1*26947304SEvan Yan /* 2*26947304SEvan Yan * CDDL HEADER START 3*26947304SEvan Yan * 4*26947304SEvan Yan * The contents of this file are subject to the terms of the 5*26947304SEvan Yan * Common Development and Distribution License (the "License"). 6*26947304SEvan Yan * You may not use this file except in compliance with the License. 7*26947304SEvan Yan * 8*26947304SEvan Yan * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*26947304SEvan Yan * or http://www.opensolaris.org/os/licensing. 10*26947304SEvan Yan * See the License for the specific language governing permissions 11*26947304SEvan Yan * and limitations under the License. 12*26947304SEvan Yan * 13*26947304SEvan Yan * When distributing Covered Code, include this CDDL HEADER in each 14*26947304SEvan Yan * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*26947304SEvan Yan * If applicable, add the following below this CDDL HEADER, with the 16*26947304SEvan Yan * fields enclosed by brackets "[]" replaced with your own identifying 17*26947304SEvan Yan * information: Portions Copyright [yyyy] [name of copyright owner] 18*26947304SEvan Yan * 19*26947304SEvan Yan * CDDL HEADER END 20*26947304SEvan Yan */ 21*26947304SEvan Yan /* 22*26947304SEvan Yan * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23*26947304SEvan Yan * Use is subject to license terms. 24*26947304SEvan Yan */ 25*26947304SEvan Yan 26*26947304SEvan Yan /* 27*26947304SEvan Yan * PCI configurator (pcicfg) 28*26947304SEvan Yan */ 29*26947304SEvan Yan 30*26947304SEvan Yan #include <sys/isa_defs.h> 31*26947304SEvan Yan 32*26947304SEvan Yan #include <sys/conf.h> 33*26947304SEvan Yan #include <sys/kmem.h> 34*26947304SEvan Yan #include <sys/debug.h> 35*26947304SEvan Yan #include <sys/modctl.h> 36*26947304SEvan Yan #include <sys/autoconf.h> 37*26947304SEvan Yan #include <sys/hwconf.h> 38*26947304SEvan Yan #include <sys/ddi_impldefs.h> 39*26947304SEvan Yan #include <sys/fcode.h> 40*26947304SEvan Yan #include <sys/pci.h> 41*26947304SEvan Yan #include <sys/pcie.h> 42*26947304SEvan Yan #include <sys/pcie_impl.h> 43*26947304SEvan Yan #include <sys/ddi.h> 44*26947304SEvan Yan #include <sys/sunddi.h> 45*26947304SEvan Yan #include <sys/sunndi.h> 46*26947304SEvan Yan #include <sys/pci_cap.h> 47*26947304SEvan Yan #include <sys/hotplug/pci/pcicfg.h> 48*26947304SEvan Yan #include <sys/ndi_impldefs.h> 49*26947304SEvan Yan 50*26947304SEvan Yan #define PCICFG_DEVICE_TYPE_PCI 1 51*26947304SEvan Yan #define PCICFG_DEVICE_TYPE_PCIE 2 52*26947304SEvan Yan 53*26947304SEvan Yan #define EFCODE21554 /* changes for supporting 21554 */ 54*26947304SEvan Yan 55*26947304SEvan Yan static int pcicfg_alloc_resource(dev_info_t *, pci_regspec_t); 56*26947304SEvan Yan static int pcicfg_free_resource(dev_info_t *, pci_regspec_t, pcicfg_flags_t); 57*26947304SEvan Yan static int pcicfg_remove_assigned_prop(dev_info_t *, pci_regspec_t *); 58*26947304SEvan Yan 59*26947304SEvan Yan #ifdef PCICFG_INTERPRET_FCODE 60*26947304SEvan Yan static int pcicfg_fcode_assign_bars(ddi_acc_handle_t, dev_info_t *, 61*26947304SEvan Yan uint_t, uint_t, uint_t, int32_t, pci_regspec_t *); 62*26947304SEvan Yan #endif /* PCICFG_INTERPRET_FCODE */ 63*26947304SEvan Yan 64*26947304SEvan Yan /* 65*26947304SEvan Yan * ************************************************************************ 66*26947304SEvan Yan * *** Implementation specific local data structures/definitions. *** 67*26947304SEvan Yan * ************************************************************************ 68*26947304SEvan Yan */ 69*26947304SEvan Yan 70*26947304SEvan Yan static int pcicfg_start_devno = 0; /* for Debug only */ 71*26947304SEvan Yan 72*26947304SEvan Yan #define PCICFG_MAX_DEVICE 32 73*26947304SEvan Yan #define PCICFG_MAX_FUNCTION 8 74*26947304SEvan Yan #define PCICFG_MAX_ARI_FUNCTION 256 75*26947304SEvan Yan #define PCICFG_MAX_REGISTER 64 76*26947304SEvan Yan #define PCICFG_MAX_BUS_DEPTH 255 77*26947304SEvan Yan 78*26947304SEvan Yan #define PCICFG_NODEVICE 42 79*26947304SEvan Yan #define PCICFG_NOMEMORY 43 80*26947304SEvan Yan #define PCICFG_NOMULTI 44 81*26947304SEvan Yan 82*26947304SEvan Yan #define PCICFG_HIADDR(n) ((uint32_t)(((uint64_t)(n) & 0xFFFFFFFF00000000)>> 32)) 83*26947304SEvan Yan #define PCICFG_LOADDR(n) ((uint32_t)((uint64_t)(n) & 0x00000000FFFFFFFF)) 84*26947304SEvan Yan #define PCICFG_LADDR(lo, hi) (((uint64_t)(hi) << 32) | (uint32_t)(lo)) 85*26947304SEvan Yan 86*26947304SEvan Yan #define PCICFG_HIWORD(n) ((uint16_t)(((uint32_t)(n) & 0xFFFF0000)>> 16)) 87*26947304SEvan Yan #define PCICFG_LOWORD(n) ((uint16_t)((uint32_t)(n) & 0x0000FFFF)) 88*26947304SEvan Yan #define PCICFG_HIBYTE(n) ((uint8_t)(((uint16_t)(n) & 0xFF00)>> 8)) 89*26947304SEvan Yan #define PCICFG_LOBYTE(n) ((uint8_t)((uint16_t)(n) & 0x00FF)) 90*26947304SEvan Yan 91*26947304SEvan Yan #define PCICFG_ROUND_UP(addr, gran) ((uintptr_t)((gran+addr-1)&(~(gran-1)))) 92*26947304SEvan Yan #define PCICFG_ROUND_DOWN(addr, gran) ((uintptr_t)((addr) & ~(gran-1))) 93*26947304SEvan Yan 94*26947304SEvan Yan #define PCICFG_MEMGRAN 0x100000 95*26947304SEvan Yan #define PCICFG_IOGRAN 0x1000 96*26947304SEvan Yan #define PCICFG_4GIG_LIMIT 0xFFFFFFFFUL 97*26947304SEvan Yan 98*26947304SEvan Yan #define PCICFG_MEM_MULT 4 99*26947304SEvan Yan #define PCICFG_IO_MULT 4 100*26947304SEvan Yan #define PCICFG_RANGE_LEN 2 /* Number of range entries */ 101*26947304SEvan Yan 102*26947304SEvan Yan static int pcicfg_slot_busnums = 8; 103*26947304SEvan Yan static int pcicfg_slot_memsize = 32 * PCICFG_MEMGRAN; /* 32MB per slot */ 104*26947304SEvan Yan static int pcicfg_slot_iosize = 16 * PCICFG_IOGRAN; /* 64K per slot */ 105*26947304SEvan Yan static int pcicfg_chassis_per_tree = 1; 106*26947304SEvan Yan static int pcicfg_sec_reset_delay = 1000000; 107*26947304SEvan Yan 108*26947304SEvan Yan /* 109*26947304SEvan Yan * The following typedef is used to represent a 110*26947304SEvan Yan * 1275 "bus-range" property of a PCI Bus node. 111*26947304SEvan Yan * DAF - should be in generic include file... 112*26947304SEvan Yan */ 113*26947304SEvan Yan 114*26947304SEvan Yan typedef struct pcicfg_bus_range { 115*26947304SEvan Yan uint32_t lo; 116*26947304SEvan Yan uint32_t hi; 117*26947304SEvan Yan } pcicfg_bus_range_t; 118*26947304SEvan Yan 119*26947304SEvan Yan typedef struct pcicfg_range { 120*26947304SEvan Yan 121*26947304SEvan Yan uint32_t child_hi; 122*26947304SEvan Yan uint32_t child_mid; 123*26947304SEvan Yan uint32_t child_lo; 124*26947304SEvan Yan uint32_t parent_hi; 125*26947304SEvan Yan uint32_t parent_mid; 126*26947304SEvan Yan uint32_t parent_lo; 127*26947304SEvan Yan uint32_t size_hi; 128*26947304SEvan Yan uint32_t size_lo; 129*26947304SEvan Yan 130*26947304SEvan Yan } pcicfg_range_t; 131*26947304SEvan Yan 132*26947304SEvan Yan typedef struct hole hole_t; 133*26947304SEvan Yan 134*26947304SEvan Yan struct hole { 135*26947304SEvan Yan uint64_t start; 136*26947304SEvan Yan uint64_t len; 137*26947304SEvan Yan hole_t *next; 138*26947304SEvan Yan }; 139*26947304SEvan Yan 140*26947304SEvan Yan typedef struct pcicfg_phdl pcicfg_phdl_t; 141*26947304SEvan Yan 142*26947304SEvan Yan struct pcicfg_phdl { 143*26947304SEvan Yan 144*26947304SEvan Yan dev_info_t *dip; /* Associated with the attach point */ 145*26947304SEvan Yan pcicfg_phdl_t *next; 146*26947304SEvan Yan 147*26947304SEvan Yan uint64_t memory_base; /* Memory base for this attach point */ 148*26947304SEvan Yan uint64_t memory_last; 149*26947304SEvan Yan uint64_t memory_len; 150*26947304SEvan Yan uint32_t io_base; /* I/O base for this attach point */ 151*26947304SEvan Yan uint32_t io_last; 152*26947304SEvan Yan uint32_t io_len; 153*26947304SEvan Yan 154*26947304SEvan Yan int error; 155*26947304SEvan Yan uint_t highest_bus; /* Highest bus seen on the probe */ 156*26947304SEvan Yan 157*26947304SEvan Yan hole_t mem_hole; /* Memory hole linked list. */ 158*26947304SEvan Yan hole_t io_hole; /* IO hole linked list */ 159*26947304SEvan Yan 160*26947304SEvan Yan ndi_ra_request_t mem_req; /* allocator request for memory */ 161*26947304SEvan Yan ndi_ra_request_t io_req; /* allocator request for I/O */ 162*26947304SEvan Yan }; 163*26947304SEvan Yan 164*26947304SEvan Yan struct pcicfg_standard_prop_entry { 165*26947304SEvan Yan uchar_t *name; 166*26947304SEvan Yan uint_t config_offset; 167*26947304SEvan Yan uint_t size; 168*26947304SEvan Yan }; 169*26947304SEvan Yan 170*26947304SEvan Yan 171*26947304SEvan Yan struct pcicfg_name_entry { 172*26947304SEvan Yan uint32_t class_code; 173*26947304SEvan Yan char *name; 174*26947304SEvan Yan }; 175*26947304SEvan Yan 176*26947304SEvan Yan struct pcicfg_find_ctrl { 177*26947304SEvan Yan uint_t device; 178*26947304SEvan Yan uint_t function; 179*26947304SEvan Yan dev_info_t *dip; 180*26947304SEvan Yan }; 181*26947304SEvan Yan 182*26947304SEvan Yan typedef struct pcicfg_err_regs { 183*26947304SEvan Yan uint16_t cmd; 184*26947304SEvan Yan uint16_t bcntl; 185*26947304SEvan Yan uint16_t pcie_dev; 186*26947304SEvan Yan uint16_t devctl; 187*26947304SEvan Yan uint16_t pcie_cap_off; 188*26947304SEvan Yan } pcicfg_err_regs_t; 189*26947304SEvan Yan 190*26947304SEvan Yan /* 191*26947304SEvan Yan * List of Indirect Config Map Devices. At least the intent of the 192*26947304SEvan Yan * design is to look for a device in this list during the configure 193*26947304SEvan Yan * operation, and if the device is listed here, then it is a nontransparent 194*26947304SEvan Yan * bridge, hence load the driver and avail the config map services from 195*26947304SEvan Yan * the driver. Class and Subclass should be as defined in the PCI specs 196*26947304SEvan Yan * ie. class is 0x6, and subclass is 0x9. 197*26947304SEvan Yan */ 198*26947304SEvan Yan static struct { 199*26947304SEvan Yan uint8_t mem_range_bar_offset; 200*26947304SEvan Yan uint8_t io_range_bar_offset; 201*26947304SEvan Yan uint8_t prefetch_mem_range_bar_offset; 202*26947304SEvan Yan } pcicfg_indirect_map_devs[] = { 203*26947304SEvan Yan PCI_CONF_BASE3, PCI_CONF_BASE2, PCI_CONF_BASE3, 204*26947304SEvan Yan 0, 0, 0, 205*26947304SEvan Yan }; 206*26947304SEvan Yan 207*26947304SEvan Yan #define PCICFG_MAKE_REG_HIGH(busnum, devnum, funcnum, register)\ 208*26947304SEvan Yan (\ 209*26947304SEvan Yan ((ulong_t)(busnum & 0xff) << 16) |\ 210*26947304SEvan Yan ((ulong_t)(devnum & 0x1f) << 11) |\ 211*26947304SEvan Yan ((ulong_t)(funcnum & 0x7) << 8) |\ 212*26947304SEvan Yan ((ulong_t)(register & 0x3f))) 213*26947304SEvan Yan 214*26947304SEvan Yan /* 215*26947304SEvan Yan * debug macros: 216*26947304SEvan Yan */ 217*26947304SEvan Yan #if defined(DEBUG) 218*26947304SEvan Yan extern void prom_printf(const char *, ...); 219*26947304SEvan Yan 220*26947304SEvan Yan /* 221*26947304SEvan Yan * Following values are defined for this debug flag. 222*26947304SEvan Yan * 223*26947304SEvan Yan * 1 = dump configuration header only. 224*26947304SEvan Yan * 2 = dump generic debug data only (no config header dumped) 225*26947304SEvan Yan * 3 = dump everything (both 1 and 2) 226*26947304SEvan Yan */ 227*26947304SEvan Yan int pcicfg_debug = 0; 228*26947304SEvan Yan int pcicfg_dump_fcode = 0; 229*26947304SEvan Yan 230*26947304SEvan Yan static void debug(char *, uintptr_t, uintptr_t, 231*26947304SEvan Yan uintptr_t, uintptr_t, uintptr_t); 232*26947304SEvan Yan 233*26947304SEvan Yan #define DEBUG0(fmt)\ 234*26947304SEvan Yan debug(fmt, 0, 0, 0, 0, 0); 235*26947304SEvan Yan #define DEBUG1(fmt, a1)\ 236*26947304SEvan Yan debug(fmt, (uintptr_t)(a1), 0, 0, 0, 0); 237*26947304SEvan Yan #define DEBUG2(fmt, a1, a2)\ 238*26947304SEvan Yan debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2), 0, 0, 0); 239*26947304SEvan Yan #define DEBUG3(fmt, a1, a2, a3)\ 240*26947304SEvan Yan debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2),\ 241*26947304SEvan Yan (uintptr_t)(a3), 0, 0); 242*26947304SEvan Yan #define DEBUG4(fmt, a1, a2, a3, a4)\ 243*26947304SEvan Yan debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2),\ 244*26947304SEvan Yan (uintptr_t)(a3), (uintptr_t)(a4), 0); 245*26947304SEvan Yan #else 246*26947304SEvan Yan #define DEBUG0(fmt) 247*26947304SEvan Yan #define DEBUG1(fmt, a1) 248*26947304SEvan Yan #define DEBUG2(fmt, a1, a2) 249*26947304SEvan Yan #define DEBUG3(fmt, a1, a2, a3) 250*26947304SEvan Yan #define DEBUG4(fmt, a1, a2, a3, a4) 251*26947304SEvan Yan #endif 252*26947304SEvan Yan 253*26947304SEvan Yan #ifdef PCICFG_INTERPRET_FCODE 254*26947304SEvan Yan int pcicfg_dont_interpret = 0; 255*26947304SEvan Yan #else 256*26947304SEvan Yan int pcicfg_dont_interpret = 1; 257*26947304SEvan Yan #endif 258*26947304SEvan Yan 259*26947304SEvan Yan /* 260*26947304SEvan Yan * forward declarations for routines defined in this module (called here) 261*26947304SEvan Yan */ 262*26947304SEvan Yan 263*26947304SEvan Yan static int pcicfg_add_config_reg(dev_info_t *, 264*26947304SEvan Yan uint_t, uint_t, uint_t); 265*26947304SEvan Yan static int pcicfg_probe_children(dev_info_t *, uint_t, uint_t, uint_t, 266*26947304SEvan Yan uint_t *, pcicfg_flags_t); 267*26947304SEvan Yan 268*26947304SEvan Yan #ifdef PCICFG_INTERPRET_FCODE 269*26947304SEvan Yan static int pcicfg_load_fcode(dev_info_t *, uint_t, uint_t, uint_t, 270*26947304SEvan Yan uint16_t, uint16_t, uchar_t **, int *, int, int); 271*26947304SEvan Yan #endif 272*26947304SEvan Yan 273*26947304SEvan Yan static int pcicfg_fcode_probe(dev_info_t *, uint_t, uint_t, uint_t, 274*26947304SEvan Yan uint_t *, pcicfg_flags_t); 275*26947304SEvan Yan static int pcicfg_probe_bridge(dev_info_t *, ddi_acc_handle_t, uint_t, 276*26947304SEvan Yan uint_t *); 277*26947304SEvan Yan static int pcicfg_free_all_resources(dev_info_t *); 278*26947304SEvan Yan static int pcicfg_alloc_new_resources(dev_info_t *); 279*26947304SEvan Yan static int pcicfg_match_dev(dev_info_t *, void *); 280*26947304SEvan Yan static dev_info_t *pcicfg_devi_find(dev_info_t *, uint_t, uint_t); 281*26947304SEvan Yan static pcicfg_phdl_t *pcicfg_find_phdl(dev_info_t *); 282*26947304SEvan Yan static pcicfg_phdl_t *pcicfg_create_phdl(dev_info_t *); 283*26947304SEvan Yan static int pcicfg_destroy_phdl(dev_info_t *); 284*26947304SEvan Yan static int pcicfg_sum_resources(dev_info_t *, void *); 285*26947304SEvan Yan static int pcicfg_find_resource_end(dev_info_t *, void *); 286*26947304SEvan Yan static int pcicfg_allocate_chunk(dev_info_t *); 287*26947304SEvan Yan static int pcicfg_program_ap(dev_info_t *); 288*26947304SEvan Yan static int pcicfg_device_assign(dev_info_t *); 289*26947304SEvan Yan static int pcicfg_bridge_assign(dev_info_t *, void *); 290*26947304SEvan Yan static int pcicfg_device_assign_readonly(dev_info_t *); 291*26947304SEvan Yan static int pcicfg_free_resources(dev_info_t *, pcicfg_flags_t); 292*26947304SEvan Yan static void pcicfg_setup_bridge(pcicfg_phdl_t *, ddi_acc_handle_t, 293*26947304SEvan Yan dev_info_t *); 294*26947304SEvan Yan static void pcicfg_update_bridge(pcicfg_phdl_t *, ddi_acc_handle_t); 295*26947304SEvan Yan static void pcicfg_enable_bridge_probe_err(dev_info_t *dip, 296*26947304SEvan Yan ddi_acc_handle_t h, pcicfg_err_regs_t *regs); 297*26947304SEvan Yan static void pcicfg_disable_bridge_probe_err(dev_info_t *dip, 298*26947304SEvan Yan ddi_acc_handle_t h, pcicfg_err_regs_t *regs); 299*26947304SEvan Yan static int pcicfg_update_assigned_prop(dev_info_t *, pci_regspec_t *); 300*26947304SEvan Yan static void pcicfg_device_on(ddi_acc_handle_t); 301*26947304SEvan Yan static void pcicfg_device_off(ddi_acc_handle_t); 302*26947304SEvan Yan static int pcicfg_set_busnode_props(dev_info_t *, uint8_t, int, int); 303*26947304SEvan Yan static int pcicfg_free_bridge_resources(dev_info_t *); 304*26947304SEvan Yan static int pcicfg_free_device_resources(dev_info_t *, pcicfg_flags_t); 305*26947304SEvan Yan static int pcicfg_teardown_device(dev_info_t *, pcicfg_flags_t); 306*26947304SEvan Yan static int pcicfg_config_setup(dev_info_t *, ddi_acc_handle_t *); 307*26947304SEvan Yan static void pcicfg_config_teardown(ddi_acc_handle_t *); 308*26947304SEvan Yan static void pcicfg_get_mem(pcicfg_phdl_t *, uint32_t, uint64_t *); 309*26947304SEvan Yan static void pcicfg_get_io(pcicfg_phdl_t *, uint32_t, uint32_t *); 310*26947304SEvan Yan static int pcicfg_update_ranges_prop(dev_info_t *, pcicfg_range_t *); 311*26947304SEvan Yan static int pcicfg_map_phys(dev_info_t *, pci_regspec_t *, caddr_t *, 312*26947304SEvan Yan ddi_device_acc_attr_t *, ddi_acc_handle_t *); 313*26947304SEvan Yan static void pcicfg_unmap_phys(ddi_acc_handle_t *, pci_regspec_t *); 314*26947304SEvan Yan static int pcicfg_dump_assigned(dev_info_t *); 315*26947304SEvan Yan static uint_t pcicfg_configure_ntbridge(dev_info_t *, uint_t, uint_t); 316*26947304SEvan Yan static int pcicfg_indirect_map(dev_info_t *dip); 317*26947304SEvan Yan static uint_t pcicfg_get_ntbridge_child_range(dev_info_t *, uint64_t *, 318*26947304SEvan Yan uint64_t *, uint_t); 319*26947304SEvan Yan static int pcicfg_is_ntbridge(dev_info_t *); 320*26947304SEvan Yan static int pcicfg_ntbridge_allocate_resources(dev_info_t *); 321*26947304SEvan Yan static int pcicfg_ntbridge_configure_done(dev_info_t *); 322*26947304SEvan Yan static int pcicfg_ntbridge_unconfigure(dev_info_t *); 323*26947304SEvan Yan static int pcicfg_ntbridge_unconfigure_child(dev_info_t *, uint_t); 324*26947304SEvan Yan static void pcicfg_free_hole(hole_t *); 325*26947304SEvan Yan static uint64_t pcicfg_alloc_hole(hole_t *, uint64_t *, uint32_t); 326*26947304SEvan Yan static int pcicfg_update_available_prop(dev_info_t *, pci_regspec_t *); 327*26947304SEvan Yan static int pcicfg_ari_configure(dev_info_t *); 328*26947304SEvan Yan static int pcicfg_populate_reg_props(dev_info_t *, ddi_acc_handle_t); 329*26947304SEvan Yan static int pcicfg_populate_props_from_bar(dev_info_t *, ddi_acc_handle_t); 330*26947304SEvan Yan static int pcicfg_update_assigned_prop_value(dev_info_t *, uint32_t, 331*26947304SEvan Yan uint32_t, uint32_t, uint_t); 332*26947304SEvan Yan 333*26947304SEvan Yan #ifdef DEBUG 334*26947304SEvan Yan static void pcicfg_dump_common_config(ddi_acc_handle_t config_handle); 335*26947304SEvan Yan static void pcicfg_dump_device_config(ddi_acc_handle_t); 336*26947304SEvan Yan 337*26947304SEvan Yan static void pcicfg_dump_bridge_config(ddi_acc_handle_t config_handle); 338*26947304SEvan Yan static uint64_t pcicfg_unused_space(hole_t *, uint32_t *); 339*26947304SEvan Yan 340*26947304SEvan Yan #define PCICFG_DUMP_COMMON_CONFIG(hdl) (void)pcicfg_dump_common_config(hdl) 341*26947304SEvan Yan #define PCICFG_DUMP_DEVICE_CONFIG(hdl) (void)pcicfg_dump_device_config(hdl) 342*26947304SEvan Yan #define PCICFG_DUMP_BRIDGE_CONFIG(hdl) (void)pcicfg_dump_bridge_config(hdl) 343*26947304SEvan Yan #else 344*26947304SEvan Yan #define PCICFG_DUMP_COMMON_CONFIG(handle) 345*26947304SEvan Yan #define PCICFG_DUMP_DEVICE_CONFIG(handle) 346*26947304SEvan Yan #define PCICFG_DUMP_BRIDGE_CONFIG(handle) 347*26947304SEvan Yan #endif 348*26947304SEvan Yan 349*26947304SEvan Yan static kmutex_t pcicfg_list_mutex; /* Protects the probe handle list */ 350*26947304SEvan Yan static pcicfg_phdl_t *pcicfg_phdl_list = NULL; 351*26947304SEvan Yan 352*26947304SEvan Yan #ifndef _DONT_USE_1275_GENERIC_NAMES 353*26947304SEvan Yan /* 354*26947304SEvan Yan * Class code table 355*26947304SEvan Yan */ 356*26947304SEvan Yan static struct pcicfg_name_entry pcicfg_class_lookup [] = { 357*26947304SEvan Yan 358*26947304SEvan Yan { 0x001, "display" }, 359*26947304SEvan Yan { 0x100, "scsi" }, 360*26947304SEvan Yan { 0x101, "ide" }, 361*26947304SEvan Yan { 0x102, "fdc" }, 362*26947304SEvan Yan { 0x103, "ipi" }, 363*26947304SEvan Yan { 0x104, "raid" }, 364*26947304SEvan Yan { 0x200, "ethernet" }, 365*26947304SEvan Yan { 0x201, "token-ring" }, 366*26947304SEvan Yan { 0x202, "fddi" }, 367*26947304SEvan Yan { 0x203, "atm" }, 368*26947304SEvan Yan { 0x300, "display" }, 369*26947304SEvan Yan { 0x400, "video" }, 370*26947304SEvan Yan { 0x401, "sound" }, 371*26947304SEvan Yan { 0x500, "memory" }, 372*26947304SEvan Yan { 0x501, "flash" }, 373*26947304SEvan Yan { 0x600, "host" }, 374*26947304SEvan Yan { 0x601, "isa" }, 375*26947304SEvan Yan { 0x602, "eisa" }, 376*26947304SEvan Yan { 0x603, "mca" }, 377*26947304SEvan Yan { 0x604, "pci" }, 378*26947304SEvan Yan { 0x605, "pcmcia" }, 379*26947304SEvan Yan { 0x606, "nubus" }, 380*26947304SEvan Yan { 0x607, "cardbus" }, 381*26947304SEvan Yan { 0x609, "pci" }, 382*26947304SEvan Yan { 0x700, "serial" }, 383*26947304SEvan Yan { 0x701, "parallel" }, 384*26947304SEvan Yan { 0x800, "interrupt-controller" }, 385*26947304SEvan Yan { 0x801, "dma-controller" }, 386*26947304SEvan Yan { 0x802, "timer" }, 387*26947304SEvan Yan { 0x803, "rtc" }, 388*26947304SEvan Yan { 0x900, "keyboard" }, 389*26947304SEvan Yan { 0x901, "pen" }, 390*26947304SEvan Yan { 0x902, "mouse" }, 391*26947304SEvan Yan { 0xa00, "dock" }, 392*26947304SEvan Yan { 0xb00, "cpu" }, 393*26947304SEvan Yan { 0xc00, "firewire" }, 394*26947304SEvan Yan { 0xc01, "access-bus" }, 395*26947304SEvan Yan { 0xc02, "ssa" }, 396*26947304SEvan Yan { 0xc03, "usb" }, 397*26947304SEvan Yan { 0xc04, "fibre-channel" }, 398*26947304SEvan Yan { 0, 0 } 399*26947304SEvan Yan }; 400*26947304SEvan Yan #endif /* _DONT_USE_1275_GENERIC_NAMES */ 401*26947304SEvan Yan 402*26947304SEvan Yan /* 403*26947304SEvan Yan * Module control operations 404*26947304SEvan Yan */ 405*26947304SEvan Yan 406*26947304SEvan Yan extern struct mod_ops mod_miscops; 407*26947304SEvan Yan 408*26947304SEvan Yan static struct modlmisc modlmisc = { 409*26947304SEvan Yan &mod_miscops, /* Type of module */ 410*26947304SEvan Yan "PCIe/PCI Config (EFCode Enabled)" 411*26947304SEvan Yan }; 412*26947304SEvan Yan 413*26947304SEvan Yan static struct modlinkage modlinkage = { 414*26947304SEvan Yan MODREV_1, (void *)&modlmisc, NULL 415*26947304SEvan Yan }; 416*26947304SEvan Yan 417*26947304SEvan Yan #ifdef DEBUG 418*26947304SEvan Yan 419*26947304SEvan Yan static void 420*26947304SEvan Yan pcicfg_dump_common_config(ddi_acc_handle_t config_handle) 421*26947304SEvan Yan { 422*26947304SEvan Yan if ((pcicfg_debug & 1) == 0) 423*26947304SEvan Yan return; 424*26947304SEvan Yan cmn_err(CE_CONT, " Vendor ID = [0x%x]\n", 425*26947304SEvan Yan pci_config_get16(config_handle, PCI_CONF_VENID)); 426*26947304SEvan Yan cmn_err(CE_CONT, " Device ID = [0x%x]\n", 427*26947304SEvan Yan pci_config_get16(config_handle, PCI_CONF_DEVID)); 428*26947304SEvan Yan cmn_err(CE_CONT, " Command REG = [0x%x]\n", 429*26947304SEvan Yan pci_config_get16(config_handle, PCI_CONF_COMM)); 430*26947304SEvan Yan cmn_err(CE_CONT, " Status REG = [0x%x]\n", 431*26947304SEvan Yan pci_config_get16(config_handle, PCI_CONF_STAT)); 432*26947304SEvan Yan cmn_err(CE_CONT, " Revision ID = [0x%x]\n", 433*26947304SEvan Yan pci_config_get8(config_handle, PCI_CONF_REVID)); 434*26947304SEvan Yan cmn_err(CE_CONT, " Prog Class = [0x%x]\n", 435*26947304SEvan Yan pci_config_get8(config_handle, PCI_CONF_PROGCLASS)); 436*26947304SEvan Yan cmn_err(CE_CONT, " Dev Class = [0x%x]\n", 437*26947304SEvan Yan pci_config_get8(config_handle, PCI_CONF_SUBCLASS)); 438*26947304SEvan Yan cmn_err(CE_CONT, " Base Class = [0x%x]\n", 439*26947304SEvan Yan pci_config_get8(config_handle, PCI_CONF_BASCLASS)); 440*26947304SEvan Yan cmn_err(CE_CONT, " Device ID = [0x%x]\n", 441*26947304SEvan Yan pci_config_get8(config_handle, PCI_CONF_CACHE_LINESZ)); 442*26947304SEvan Yan cmn_err(CE_CONT, " Header Type = [0x%x]\n", 443*26947304SEvan Yan pci_config_get8(config_handle, PCI_CONF_HEADER)); 444*26947304SEvan Yan cmn_err(CE_CONT, " BIST = [0x%x]\n", 445*26947304SEvan Yan pci_config_get8(config_handle, PCI_CONF_BIST)); 446*26947304SEvan Yan cmn_err(CE_CONT, " BASE 0 = [0x%x]\n", 447*26947304SEvan Yan pci_config_get32(config_handle, PCI_CONF_BASE0)); 448*26947304SEvan Yan cmn_err(CE_CONT, " BASE 1 = [0x%x]\n", 449*26947304SEvan Yan pci_config_get32(config_handle, PCI_CONF_BASE1)); 450*26947304SEvan Yan 451*26947304SEvan Yan } 452*26947304SEvan Yan 453*26947304SEvan Yan static void 454*26947304SEvan Yan pcicfg_dump_device_config(ddi_acc_handle_t config_handle) 455*26947304SEvan Yan { 456*26947304SEvan Yan if ((pcicfg_debug & 1) == 0) 457*26947304SEvan Yan return; 458*26947304SEvan Yan pcicfg_dump_common_config(config_handle); 459*26947304SEvan Yan 460*26947304SEvan Yan cmn_err(CE_CONT, " BASE 2 = [0x%x]\n", 461*26947304SEvan Yan pci_config_get32(config_handle, PCI_CONF_BASE2)); 462*26947304SEvan Yan cmn_err(CE_CONT, " BASE 3 = [0x%x]\n", 463*26947304SEvan Yan pci_config_get32(config_handle, PCI_CONF_BASE3)); 464*26947304SEvan Yan cmn_err(CE_CONT, " BASE 4 = [0x%x]\n", 465*26947304SEvan Yan pci_config_get32(config_handle, PCI_CONF_BASE4)); 466*26947304SEvan Yan cmn_err(CE_CONT, " BASE 5 = [0x%x]\n", 467*26947304SEvan Yan pci_config_get32(config_handle, PCI_CONF_BASE5)); 468*26947304SEvan Yan cmn_err(CE_CONT, " Cardbus CIS = [0x%x]\n", 469*26947304SEvan Yan pci_config_get32(config_handle, PCI_CONF_CIS)); 470*26947304SEvan Yan cmn_err(CE_CONT, " Sub VID = [0x%x]\n", 471*26947304SEvan Yan pci_config_get16(config_handle, PCI_CONF_SUBVENID)); 472*26947304SEvan Yan cmn_err(CE_CONT, " Sub SID = [0x%x]\n", 473*26947304SEvan Yan pci_config_get16(config_handle, PCI_CONF_SUBSYSID)); 474*26947304SEvan Yan cmn_err(CE_CONT, " ROM = [0x%x]\n", 475*26947304SEvan Yan pci_config_get32(config_handle, PCI_CONF_ROM)); 476*26947304SEvan Yan cmn_err(CE_CONT, " I Line = [0x%x]\n", 477*26947304SEvan Yan pci_config_get8(config_handle, PCI_CONF_ILINE)); 478*26947304SEvan Yan cmn_err(CE_CONT, " I Pin = [0x%x]\n", 479*26947304SEvan Yan pci_config_get8(config_handle, PCI_CONF_IPIN)); 480*26947304SEvan Yan cmn_err(CE_CONT, " Max Grant = [0x%x]\n", 481*26947304SEvan Yan pci_config_get8(config_handle, PCI_CONF_MIN_G)); 482*26947304SEvan Yan cmn_err(CE_CONT, " Max Latent = [0x%x]\n", 483*26947304SEvan Yan pci_config_get8(config_handle, PCI_CONF_MAX_L)); 484*26947304SEvan Yan } 485*26947304SEvan Yan 486*26947304SEvan Yan static void 487*26947304SEvan Yan pcicfg_dump_bridge_config(ddi_acc_handle_t config_handle) 488*26947304SEvan Yan { 489*26947304SEvan Yan if ((pcicfg_debug & 1) == 0) 490*26947304SEvan Yan return; 491*26947304SEvan Yan 492*26947304SEvan Yan pcicfg_dump_common_config(config_handle); 493*26947304SEvan Yan 494*26947304SEvan Yan cmn_err(CE_CONT, "........................................\n"); 495*26947304SEvan Yan 496*26947304SEvan Yan cmn_err(CE_CONT, " Pri Bus = [0x%x]\n", 497*26947304SEvan Yan pci_config_get8(config_handle, PCI_BCNF_PRIBUS)); 498*26947304SEvan Yan cmn_err(CE_CONT, " Sec Bus = [0x%x]\n", 499*26947304SEvan Yan pci_config_get8(config_handle, PCI_BCNF_SECBUS)); 500*26947304SEvan Yan cmn_err(CE_CONT, " Sub Bus = [0x%x]\n", 501*26947304SEvan Yan pci_config_get8(config_handle, PCI_BCNF_SUBBUS)); 502*26947304SEvan Yan cmn_err(CE_CONT, " Latency = [0x%x]\n", 503*26947304SEvan Yan pci_config_get8(config_handle, PCI_BCNF_LATENCY_TIMER)); 504*26947304SEvan Yan cmn_err(CE_CONT, " I/O Base LO = [0x%x]\n", 505*26947304SEvan Yan pci_config_get8(config_handle, PCI_BCNF_IO_BASE_LOW)); 506*26947304SEvan Yan cmn_err(CE_CONT, " I/O Lim LO = [0x%x]\n", 507*26947304SEvan Yan pci_config_get8(config_handle, PCI_BCNF_IO_LIMIT_LOW)); 508*26947304SEvan Yan cmn_err(CE_CONT, " Sec. Status = [0x%x]\n", 509*26947304SEvan Yan pci_config_get16(config_handle, PCI_BCNF_SEC_STATUS)); 510*26947304SEvan Yan cmn_err(CE_CONT, " Mem Base = [0x%x]\n", 511*26947304SEvan Yan pci_config_get16(config_handle, PCI_BCNF_MEM_BASE)); 512*26947304SEvan Yan cmn_err(CE_CONT, " Mem Limit = [0x%x]\n", 513*26947304SEvan Yan pci_config_get16(config_handle, PCI_BCNF_MEM_LIMIT)); 514*26947304SEvan Yan cmn_err(CE_CONT, " PF Mem Base = [0x%x]\n", 515*26947304SEvan Yan pci_config_get16(config_handle, PCI_BCNF_PF_BASE_LOW)); 516*26947304SEvan Yan cmn_err(CE_CONT, " PF Mem Lim = [0x%x]\n", 517*26947304SEvan Yan pci_config_get16(config_handle, PCI_BCNF_PF_LIMIT_LOW)); 518*26947304SEvan Yan cmn_err(CE_CONT, " PF Base HI = [0x%x]\n", 519*26947304SEvan Yan pci_config_get32(config_handle, PCI_BCNF_PF_BASE_HIGH)); 520*26947304SEvan Yan cmn_err(CE_CONT, " PF Lim HI = [0x%x]\n", 521*26947304SEvan Yan pci_config_get32(config_handle, PCI_BCNF_PF_LIMIT_HIGH)); 522*26947304SEvan Yan cmn_err(CE_CONT, " I/O Base HI = [0x%x]\n", 523*26947304SEvan Yan pci_config_get16(config_handle, PCI_BCNF_IO_BASE_HI)); 524*26947304SEvan Yan cmn_err(CE_CONT, " I/O Lim HI = [0x%x]\n", 525*26947304SEvan Yan pci_config_get16(config_handle, PCI_BCNF_IO_LIMIT_HI)); 526*26947304SEvan Yan cmn_err(CE_CONT, " ROM addr = [0x%x]\n", 527*26947304SEvan Yan pci_config_get32(config_handle, PCI_BCNF_ROM)); 528*26947304SEvan Yan cmn_err(CE_CONT, " Intr Line = [0x%x]\n", 529*26947304SEvan Yan pci_config_get8(config_handle, PCI_BCNF_ILINE)); 530*26947304SEvan Yan cmn_err(CE_CONT, " Intr Pin = [0x%x]\n", 531*26947304SEvan Yan pci_config_get8(config_handle, PCI_BCNF_IPIN)); 532*26947304SEvan Yan cmn_err(CE_CONT, " Bridge Ctrl = [0x%x]\n", 533*26947304SEvan Yan pci_config_get16(config_handle, PCI_BCNF_BCNTRL)); 534*26947304SEvan Yan } 535*26947304SEvan Yan 536*26947304SEvan Yan #endif 537*26947304SEvan Yan 538*26947304SEvan Yan 539*26947304SEvan Yan int 540*26947304SEvan Yan _init() 541*26947304SEvan Yan { 542*26947304SEvan Yan DEBUG0("PCI configurator installed - Fcode Interpretation/21554\n"); 543*26947304SEvan Yan 544*26947304SEvan Yan mutex_init(&pcicfg_list_mutex, NULL, MUTEX_DRIVER, NULL); 545*26947304SEvan Yan return (mod_install(&modlinkage)); 546*26947304SEvan Yan } 547*26947304SEvan Yan 548*26947304SEvan Yan int 549*26947304SEvan Yan _fini(void) 550*26947304SEvan Yan { 551*26947304SEvan Yan int error; 552*26947304SEvan Yan 553*26947304SEvan Yan error = mod_remove(&modlinkage); 554*26947304SEvan Yan if (error != 0) { 555*26947304SEvan Yan return (error); 556*26947304SEvan Yan } 557*26947304SEvan Yan mutex_destroy(&pcicfg_list_mutex); 558*26947304SEvan Yan return (0); 559*26947304SEvan Yan } 560*26947304SEvan Yan 561*26947304SEvan Yan int 562*26947304SEvan Yan _info(modinfop) 563*26947304SEvan Yan struct modinfo *modinfop; 564*26947304SEvan Yan { 565*26947304SEvan Yan return (mod_info(&modlinkage, modinfop)); 566*26947304SEvan Yan } 567*26947304SEvan Yan 568*26947304SEvan Yan /*ARGSUSED*/ 569*26947304SEvan Yan static uint8_t 570*26947304SEvan Yan pcicfg_get_nslots(dev_info_t *dip, ddi_acc_handle_t handle) 571*26947304SEvan Yan { 572*26947304SEvan Yan uint8_t num_slots = 0; 573*26947304SEvan Yan uint16_t cap_ptr; 574*26947304SEvan Yan 575*26947304SEvan Yan if ((PCI_CAP_LOCATE(handle, PCI_CAP_ID_PCI_HOTPLUG, 576*26947304SEvan Yan &cap_ptr)) == DDI_SUCCESS) { 577*26947304SEvan Yan uint32_t config; 578*26947304SEvan Yan 579*26947304SEvan Yan PCI_CAP_PUT8(handle, NULL, cap_ptr, PCI_HP_DWORD_SELECT_OFF, 580*26947304SEvan Yan PCI_HP_SLOT_CONFIGURATION_REG); 581*26947304SEvan Yan config = PCI_CAP_GET32(handle, NULL, cap_ptr, 582*26947304SEvan Yan PCI_HP_DWORD_DATA_OFF); 583*26947304SEvan Yan num_slots = config & 0x1F; 584*26947304SEvan Yan } else if ((PCI_CAP_LOCATE(handle, PCI_CAP_ID_SLOT_ID, &cap_ptr)) 585*26947304SEvan Yan == DDI_SUCCESS) { 586*26947304SEvan Yan uint8_t esr_reg = PCI_CAP_GET8(handle, NULL, 587*26947304SEvan Yan cap_ptr, PCI_CAP_ID_REGS_OFF); 588*26947304SEvan Yan 589*26947304SEvan Yan num_slots = PCI_CAPSLOT_NSLOTS(esr_reg); 590*26947304SEvan Yan } else if ((PCI_CAP_LOCATE(handle, PCI_CAP_ID_PCI_E, &cap_ptr)) 591*26947304SEvan Yan == DDI_SUCCESS) { 592*26947304SEvan Yan int port_type = PCI_CAP_GET16(handle, NULL, cap_ptr, 593*26947304SEvan Yan PCIE_PCIECAP) & PCIE_PCIECAP_DEV_TYPE_MASK; 594*26947304SEvan Yan 595*26947304SEvan Yan if ((port_type == PCIE_PCIECAP_DEV_TYPE_DOWN) && 596*26947304SEvan Yan (PCI_CAP_GET16(handle, NULL, cap_ptr, PCIE_PCIECAP) 597*26947304SEvan Yan & PCIE_PCIECAP_SLOT_IMPL)) 598*26947304SEvan Yan num_slots = 1; 599*26947304SEvan Yan } 600*26947304SEvan Yan 601*26947304SEvan Yan DEBUG3("%s#%d has %d slots", 602*26947304SEvan Yan ddi_get_name(dip), ddi_get_instance(dip), num_slots); 603*26947304SEvan Yan 604*26947304SEvan Yan return (num_slots); 605*26947304SEvan Yan } 606*26947304SEvan Yan 607*26947304SEvan Yan /*ARGSUSED*/ 608*26947304SEvan Yan static uint8_t 609*26947304SEvan Yan pcicfg_is_chassis(dev_info_t *dip, ddi_acc_handle_t handle) 610*26947304SEvan Yan { 611*26947304SEvan Yan uint16_t cap_ptr; 612*26947304SEvan Yan 613*26947304SEvan Yan if ((PCI_CAP_LOCATE(handle, PCI_CAP_ID_SLOT_ID, &cap_ptr)) != 614*26947304SEvan Yan DDI_FAILURE) { 615*26947304SEvan Yan 616*26947304SEvan Yan uint8_t esr_reg = PCI_CAP_GET8(handle, NULL, cap_ptr, 2); 617*26947304SEvan Yan if (PCI_CAPSLOT_FIC(esr_reg)) 618*26947304SEvan Yan return (B_TRUE); 619*26947304SEvan Yan } 620*26947304SEvan Yan return (B_FALSE); 621*26947304SEvan Yan } 622*26947304SEvan Yan 623*26947304SEvan Yan /*ARGSUSED*/ 624*26947304SEvan Yan static int 625*26947304SEvan Yan pcicfg_pcie_dev(dev_info_t *dip, int bus_type, pcicfg_err_regs_t *regs) 626*26947304SEvan Yan { 627*26947304SEvan Yan /* get parent device's device_type property */ 628*26947304SEvan Yan char *device_type; 629*26947304SEvan Yan int rc = DDI_FAILURE; 630*26947304SEvan Yan dev_info_t *pdip = ddi_get_parent(dip); 631*26947304SEvan Yan 632*26947304SEvan Yan regs->pcie_dev = 0; 633*26947304SEvan Yan if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip, 634*26947304SEvan Yan DDI_PROP_DONTPASS, "device_type", &device_type) 635*26947304SEvan Yan != DDI_PROP_SUCCESS) { 636*26947304SEvan Yan DEBUG2("device_type property missing for %s#%d", 637*26947304SEvan Yan ddi_get_name(pdip), ddi_get_instance(pdip)); 638*26947304SEvan Yan return (DDI_FAILURE); 639*26947304SEvan Yan } 640*26947304SEvan Yan switch (bus_type) { 641*26947304SEvan Yan case PCICFG_DEVICE_TYPE_PCIE: 642*26947304SEvan Yan if (strcmp(device_type, "pciex") == 0) { 643*26947304SEvan Yan rc = DDI_SUCCESS; 644*26947304SEvan Yan regs->pcie_dev = 1; 645*26947304SEvan Yan } 646*26947304SEvan Yan break; 647*26947304SEvan Yan case PCICFG_DEVICE_TYPE_PCI: 648*26947304SEvan Yan if (strcmp(device_type, "pci") == 0) 649*26947304SEvan Yan rc = DDI_SUCCESS; 650*26947304SEvan Yan break; 651*26947304SEvan Yan default: 652*26947304SEvan Yan break; 653*26947304SEvan Yan } 654*26947304SEvan Yan ddi_prop_free(device_type); 655*26947304SEvan Yan return (rc); 656*26947304SEvan Yan } 657*26947304SEvan Yan 658*26947304SEvan Yan /*ARGSUSED*/ 659*26947304SEvan Yan static int 660*26947304SEvan Yan pcicfg_pcie_port_type(dev_info_t *dip, ddi_acc_handle_t handle) 661*26947304SEvan Yan { 662*26947304SEvan Yan int port_type = -1; 663*26947304SEvan Yan uint16_t cap_ptr; 664*26947304SEvan Yan 665*26947304SEvan Yan if ((PCI_CAP_LOCATE(handle, PCI_CAP_ID_PCI_E, &cap_ptr)) != 666*26947304SEvan Yan DDI_FAILURE) 667*26947304SEvan Yan port_type = PCI_CAP_GET16(handle, NULL, 668*26947304SEvan Yan cap_ptr, PCIE_PCIECAP) & PCIE_PCIECAP_DEV_TYPE_MASK; 669*26947304SEvan Yan 670*26947304SEvan Yan return (port_type); 671*26947304SEvan Yan } 672*26947304SEvan Yan 673*26947304SEvan Yan static int 674*26947304SEvan Yan pcicfg_pcie_device_type(dev_info_t *dip, ddi_acc_handle_t handle) 675*26947304SEvan Yan { 676*26947304SEvan Yan int port_type = pcicfg_pcie_port_type(dip, handle); 677*26947304SEvan Yan 678*26947304SEvan Yan DEBUG1("device port_type = %x\n", port_type); 679*26947304SEvan Yan /* No PCIe CAP regs, we are not PCIe device_type */ 680*26947304SEvan Yan if (port_type < 0) 681*26947304SEvan Yan return (DDI_FAILURE); 682*26947304SEvan Yan 683*26947304SEvan Yan /* check for all PCIe device_types */ 684*26947304SEvan Yan if ((port_type == PCIE_PCIECAP_DEV_TYPE_UP) || 685*26947304SEvan Yan (port_type == PCIE_PCIECAP_DEV_TYPE_DOWN) || 686*26947304SEvan Yan (port_type == PCIE_PCIECAP_DEV_TYPE_ROOT) || 687*26947304SEvan Yan (port_type == PCIE_PCIECAP_DEV_TYPE_PCI2PCIE)) 688*26947304SEvan Yan return (DDI_SUCCESS); 689*26947304SEvan Yan 690*26947304SEvan Yan return (DDI_FAILURE); 691*26947304SEvan Yan 692*26947304SEvan Yan } 693*26947304SEvan Yan 694*26947304SEvan Yan /* 695*26947304SEvan Yan * In the following functions ndi_devi_enter() without holding the 696*26947304SEvan Yan * parent dip is sufficient. This is because pci dr is driven through 697*26947304SEvan Yan * opens on the nexus which is in the device tree path above the node 698*26947304SEvan Yan * being operated on, and implicitly held due to the open. 699*26947304SEvan Yan */ 700*26947304SEvan Yan 701*26947304SEvan Yan /* 702*26947304SEvan Yan * This entry point is called to configure a device (and 703*26947304SEvan Yan * all its children) on the given bus. It is called when 704*26947304SEvan Yan * a new device is added to the PCI domain. This routine 705*26947304SEvan Yan * will create the device tree and program the devices 706*26947304SEvan Yan * registers. 707*26947304SEvan Yan */ 708*26947304SEvan Yan 709*26947304SEvan Yan int 710*26947304SEvan Yan pcicfg_configure(dev_info_t *devi, uint_t device, uint_t function, 711*26947304SEvan Yan pcicfg_flags_t flags) 712*26947304SEvan Yan { 713*26947304SEvan Yan uint_t bus; 714*26947304SEvan Yan int len; 715*26947304SEvan Yan int func; 716*26947304SEvan Yan int trans_device; 717*26947304SEvan Yan dev_info_t *new_device; 718*26947304SEvan Yan pcicfg_bus_range_t pci_bus_range; 719*26947304SEvan Yan int rv; 720*26947304SEvan Yan int circ; 721*26947304SEvan Yan uint_t highest_bus = 0; 722*26947304SEvan Yan int ari_mode = B_FALSE; 723*26947304SEvan Yan int max_function = PCICFG_MAX_FUNCTION; 724*26947304SEvan Yan 725*26947304SEvan Yan if (flags == PCICFG_FLAG_ENABLE_ARI) 726*26947304SEvan Yan return (pcicfg_ari_configure(devi)); 727*26947304SEvan Yan 728*26947304SEvan Yan /* 729*26947304SEvan Yan * Start probing at the device specified in "device" on the 730*26947304SEvan Yan * "bus" specified. 731*26947304SEvan Yan */ 732*26947304SEvan Yan len = sizeof (pcicfg_bus_range_t); 733*26947304SEvan Yan if (ddi_getlongprop_buf(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS, 734*26947304SEvan Yan "bus-range", (caddr_t)&pci_bus_range, &len) != DDI_SUCCESS) { 735*26947304SEvan Yan DEBUG0("no bus-range property\n"); 736*26947304SEvan Yan return (PCICFG_FAILURE); 737*26947304SEvan Yan } 738*26947304SEvan Yan 739*26947304SEvan Yan bus = pci_bus_range.lo; /* primary bus number of this bus node */ 740*26947304SEvan Yan 741*26947304SEvan Yan ndi_devi_enter(devi, &circ); 742*26947304SEvan Yan for (func = 0; func < max_function; ) { 743*26947304SEvan Yan if ((function != PCICFG_ALL_FUNC) && (function != func)) 744*26947304SEvan Yan goto next; 745*26947304SEvan Yan 746*26947304SEvan Yan if (ari_mode) 747*26947304SEvan Yan trans_device = func >> 3; 748*26947304SEvan Yan else 749*26947304SEvan Yan trans_device = device; 750*26947304SEvan Yan 751*26947304SEvan Yan DEBUG3("Configuring [0x%x][0x%x][0x%x]\n", 752*26947304SEvan Yan bus, trans_device, func & 7); 753*26947304SEvan Yan 754*26947304SEvan Yan /* 755*26947304SEvan Yan * Try executing fcode if available. 756*26947304SEvan Yan */ 757*26947304SEvan Yan switch (rv = pcicfg_fcode_probe(devi, bus, trans_device, 758*26947304SEvan Yan func & 7, &highest_bus, flags)) { 759*26947304SEvan Yan case PCICFG_FAILURE: 760*26947304SEvan Yan DEBUG2("configure failed: " 761*26947304SEvan Yan "bus [0x%x] device [0x%x]\n", 762*26947304SEvan Yan bus, trans_device); 763*26947304SEvan Yan break; 764*26947304SEvan Yan case PCICFG_NODEVICE: 765*26947304SEvan Yan DEBUG3("no device : bus " 766*26947304SEvan Yan "[0x%x] slot [0x%x] func [0x%x]\n", 767*26947304SEvan Yan bus, trans_device, func & 7); 768*26947304SEvan Yan if (func) 769*26947304SEvan Yan goto next; 770*26947304SEvan Yan break; 771*26947304SEvan Yan default: 772*26947304SEvan Yan DEBUG3("configure: bus => [%d] " 773*26947304SEvan Yan "slot => [%d] func => [%d]\n", 774*26947304SEvan Yan bus, trans_device, func & 7); 775*26947304SEvan Yan break; 776*26947304SEvan Yan } 777*26947304SEvan Yan 778*26947304SEvan Yan if (rv != PCICFG_SUCCESS) 779*26947304SEvan Yan break; 780*26947304SEvan Yan 781*26947304SEvan Yan if ((new_device = pcicfg_devi_find(devi, 782*26947304SEvan Yan trans_device, (func & 7))) == NULL) { 783*26947304SEvan Yan DEBUG0("Did'nt find device node just created\n"); 784*26947304SEvan Yan goto cleanup; 785*26947304SEvan Yan } 786*26947304SEvan Yan 787*26947304SEvan Yan next: 788*26947304SEvan Yan /* 789*26947304SEvan Yan * Determine if ARI Forwarding should be enabled. 790*26947304SEvan Yan */ 791*26947304SEvan Yan if (func == 0) { 792*26947304SEvan Yan if ((pcie_ari_supported(devi) 793*26947304SEvan Yan == PCIE_ARI_FORW_SUPPORTED) && 794*26947304SEvan Yan (pcie_ari_device(new_device) == PCIE_ARI_DEVICE)) { 795*26947304SEvan Yan if (pcie_ari_enable(devi) == DDI_SUCCESS) { 796*26947304SEvan Yan (void) ddi_prop_create(DDI_DEV_T_NONE, 797*26947304SEvan Yan devi, DDI_PROP_CANSLEEP, 798*26947304SEvan Yan "ari-enabled", NULL, 0); 799*26947304SEvan Yan 800*26947304SEvan Yan ari_mode = B_TRUE; 801*26947304SEvan Yan max_function = PCICFG_MAX_ARI_FUNCTION; 802*26947304SEvan Yan } 803*26947304SEvan Yan } 804*26947304SEvan Yan } 805*26947304SEvan Yan 806*26947304SEvan Yan if (ari_mode == B_TRUE) { 807*26947304SEvan Yan int next_function; 808*26947304SEvan Yan 809*26947304SEvan Yan DEBUG0("Next Function - ARI Device\n"); 810*26947304SEvan Yan if (pcie_ari_get_next_function(new_device, 811*26947304SEvan Yan &next_function) != DDI_SUCCESS) 812*26947304SEvan Yan goto cleanup; 813*26947304SEvan Yan 814*26947304SEvan Yan /* 815*26947304SEvan Yan * Check if there are more fucntions to probe. 816*26947304SEvan Yan */ 817*26947304SEvan Yan if (next_function == 0) { 818*26947304SEvan Yan DEBUG0("Next Function - " 819*26947304SEvan Yan "No more ARI Functions\n"); 820*26947304SEvan Yan break; 821*26947304SEvan Yan } 822*26947304SEvan Yan func = next_function; 823*26947304SEvan Yan } else { 824*26947304SEvan Yan func++; 825*26947304SEvan Yan } 826*26947304SEvan Yan 827*26947304SEvan Yan DEBUG1("Next Function - %x\n", func); 828*26947304SEvan Yan } 829*26947304SEvan Yan 830*26947304SEvan Yan ndi_devi_exit(devi, circ); 831*26947304SEvan Yan 832*26947304SEvan Yan if (func == 0) 833*26947304SEvan Yan return (PCICFG_FAILURE); /* probe failed */ 834*26947304SEvan Yan else 835*26947304SEvan Yan return (PCICFG_SUCCESS); 836*26947304SEvan Yan 837*26947304SEvan Yan cleanup: 838*26947304SEvan Yan /* 839*26947304SEvan Yan * Clean up a partially created "probe state" tree. 840*26947304SEvan Yan * There are no resources allocated to the in the 841*26947304SEvan Yan * probe state. 842*26947304SEvan Yan */ 843*26947304SEvan Yan if (pcie_ari_is_enabled(devi) == PCIE_ARI_FORW_ENABLED) 844*26947304SEvan Yan max_function = PCICFG_MAX_ARI_FUNCTION; 845*26947304SEvan Yan else 846*26947304SEvan Yan max_function = PCICFG_MAX_FUNCTION; 847*26947304SEvan Yan 848*26947304SEvan Yan for (func = 0; func < max_function; func++) { 849*26947304SEvan Yan 850*26947304SEvan Yan if (max_function == PCICFG_MAX_ARI_FUNCTION) 851*26947304SEvan Yan trans_device = func >> 3; /* ARI Device */ 852*26947304SEvan Yan else 853*26947304SEvan Yan trans_device = device; 854*26947304SEvan Yan 855*26947304SEvan Yan if ((new_device = pcicfg_devi_find(devi, 856*26947304SEvan Yan trans_device, (func & 0x7))) == NULL) { 857*26947304SEvan Yan DEBUG0("No more devices to clean up\n"); 858*26947304SEvan Yan continue; 859*26947304SEvan Yan } 860*26947304SEvan Yan 861*26947304SEvan Yan DEBUG2("Cleaning up device [0x%x] function [0x%x]\n", 862*26947304SEvan Yan trans_device, func & 7); 863*26947304SEvan Yan /* 864*26947304SEvan Yan * If this was a bridge device it will have a 865*26947304SEvan Yan * probe handle - if not, no harm in calling this. 866*26947304SEvan Yan */ 867*26947304SEvan Yan (void) pcicfg_destroy_phdl(new_device); 868*26947304SEvan Yan /* 869*26947304SEvan Yan * This will free up the node 870*26947304SEvan Yan */ 871*26947304SEvan Yan (void) ndi_devi_offline(new_device, NDI_DEVI_REMOVE); 872*26947304SEvan Yan } 873*26947304SEvan Yan ndi_devi_exit(devi, circ); 874*26947304SEvan Yan 875*26947304SEvan Yan return (PCICFG_FAILURE); 876*26947304SEvan Yan } 877*26947304SEvan Yan 878*26947304SEvan Yan /* 879*26947304SEvan Yan * configure the child nodes of ntbridge. new_device points to ntbridge itself 880*26947304SEvan Yan */ 881*26947304SEvan Yan /*ARGSUSED*/ 882*26947304SEvan Yan static uint_t 883*26947304SEvan Yan pcicfg_configure_ntbridge(dev_info_t *new_device, uint_t bus, uint_t device) 884*26947304SEvan Yan { 885*26947304SEvan Yan int bus_range[2], rc = PCICFG_FAILURE, rc1, max_devs = 0; 886*26947304SEvan Yan int devno; 887*26947304SEvan Yan dev_info_t *new_ntbridgechild; 888*26947304SEvan Yan ddi_acc_handle_t config_handle; 889*26947304SEvan Yan uint16_t vid; 890*26947304SEvan Yan uint64_t next_bus; 891*26947304SEvan Yan uint64_t blen; 892*26947304SEvan Yan ndi_ra_request_t req; 893*26947304SEvan Yan uint8_t pcie_device_type = 0; 894*26947304SEvan Yan 895*26947304SEvan Yan /* 896*26947304SEvan Yan * If we need to do indirect config, lets create a property here 897*26947304SEvan Yan * to let the child conf map routine know that it has to 898*26947304SEvan Yan * go through the DDI calls, and not assume the devices are 899*26947304SEvan Yan * mapped directly under the host. 900*26947304SEvan Yan */ 901*26947304SEvan Yan if ((rc = ndi_prop_update_int(DDI_DEV_T_NONE, new_device, 902*26947304SEvan Yan PCI_DEV_CONF_MAP_PROP, (int)DDI_SUCCESS)) 903*26947304SEvan Yan != DDI_SUCCESS) { 904*26947304SEvan Yan 905*26947304SEvan Yan DEBUG0("Cannot create indirect conf map property.\n"); 906*26947304SEvan Yan return ((uint_t)PCICFG_FAILURE); 907*26947304SEvan Yan } 908*26947304SEvan Yan if (pci_config_setup(new_device, &config_handle) != DDI_SUCCESS) 909*26947304SEvan Yan return ((uint_t)PCICFG_FAILURE); 910*26947304SEvan Yan /* check if we are PCIe device */ 911*26947304SEvan Yan if (pcicfg_pcie_device_type(new_device, config_handle) == DDI_SUCCESS) 912*26947304SEvan Yan pcie_device_type = 1; 913*26947304SEvan Yan pci_config_teardown(&config_handle); 914*26947304SEvan Yan 915*26947304SEvan Yan /* create Bus node properties for ntbridge. */ 916*26947304SEvan Yan if (pcicfg_set_busnode_props(new_device, pcie_device_type, -1, -1) != 917*26947304SEvan Yan PCICFG_SUCCESS) { 918*26947304SEvan Yan DEBUG0("Failed to set busnode props\n"); 919*26947304SEvan Yan return (rc); 920*26947304SEvan Yan } 921*26947304SEvan Yan 922*26947304SEvan Yan /* For now: Lets only support one layer of child */ 923*26947304SEvan Yan bzero((caddr_t)&req, sizeof (ndi_ra_request_t)); 924*26947304SEvan Yan req.ra_len = 1; 925*26947304SEvan Yan if (ndi_ra_alloc(ddi_get_parent(new_device), &req, 926*26947304SEvan Yan &next_bus, &blen, NDI_RA_TYPE_PCI_BUSNUM, 927*26947304SEvan Yan NDI_RA_PASS) != NDI_SUCCESS) { 928*26947304SEvan Yan DEBUG0("ntbridge: Failed to get a bus number\n"); 929*26947304SEvan Yan return (rc); 930*26947304SEvan Yan } 931*26947304SEvan Yan 932*26947304SEvan Yan DEBUG1("ntbridge bus range start ->[%d]\n", next_bus); 933*26947304SEvan Yan 934*26947304SEvan Yan /* 935*26947304SEvan Yan * Following will change, as we detect more bridges 936*26947304SEvan Yan * on the way. 937*26947304SEvan Yan */ 938*26947304SEvan Yan bus_range[0] = (int)next_bus; 939*26947304SEvan Yan bus_range[1] = (int)next_bus; 940*26947304SEvan Yan 941*26947304SEvan Yan if (ndi_prop_update_int_array(DDI_DEV_T_NONE, new_device, 942*26947304SEvan Yan "bus-range", bus_range, 2) != DDI_SUCCESS) { 943*26947304SEvan Yan DEBUG0("Cannot set ntbridge bus-range property"); 944*26947304SEvan Yan return (rc); 945*26947304SEvan Yan } 946*26947304SEvan Yan 947*26947304SEvan Yan /* 948*26947304SEvan Yan * The other interface (away from the host) will be 949*26947304SEvan Yan * initialized by the nexus driver when it loads. 950*26947304SEvan Yan * We just have to set the registers and the nexus driver 951*26947304SEvan Yan * figures out the rest. 952*26947304SEvan Yan */ 953*26947304SEvan Yan 954*26947304SEvan Yan /* 955*26947304SEvan Yan * finally, lets load and attach the driver 956*26947304SEvan Yan * before configuring children of ntbridge. 957*26947304SEvan Yan */ 958*26947304SEvan Yan rc = ndi_devi_online(new_device, NDI_NO_EVENT|NDI_CONFIG); 959*26947304SEvan Yan if (rc != NDI_SUCCESS) { 960*26947304SEvan Yan cmn_err(CE_WARN, 961*26947304SEvan Yan "pcicfg: Fail: can\'t load non-transparent bridge \ 962*26947304SEvan Yan driver.\n"); 963*26947304SEvan Yan rc = PCICFG_FAILURE; 964*26947304SEvan Yan return (rc); 965*26947304SEvan Yan } 966*26947304SEvan Yan DEBUG0("pcicfg: Success loading nontransparent bridge nexus driver.."); 967*26947304SEvan Yan 968*26947304SEvan Yan /* Now set aside pci resources for our children. */ 969*26947304SEvan Yan if (pcicfg_ntbridge_allocate_resources(new_device) != 970*26947304SEvan Yan PCICFG_SUCCESS) { 971*26947304SEvan Yan max_devs = 0; 972*26947304SEvan Yan rc = PCICFG_FAILURE; 973*26947304SEvan Yan } else 974*26947304SEvan Yan max_devs = PCICFG_MAX_DEVICE; 975*26947304SEvan Yan 976*26947304SEvan Yan /* Probe devices on 2nd bus */ 977*26947304SEvan Yan for (devno = pcicfg_start_devno; devno < max_devs; devno++) { 978*26947304SEvan Yan 979*26947304SEvan Yan if (ndi_devi_alloc(new_device, DEVI_PSEUDO_NEXNAME, 980*26947304SEvan Yan (pnode_t)DEVI_SID_NODEID, &new_ntbridgechild) 981*26947304SEvan Yan != NDI_SUCCESS) { 982*26947304SEvan Yan 983*26947304SEvan Yan DEBUG0("pcicfg: Failed to alloc test node\n"); 984*26947304SEvan Yan rc = PCICFG_FAILURE; 985*26947304SEvan Yan break; 986*26947304SEvan Yan } 987*26947304SEvan Yan 988*26947304SEvan Yan if (pcicfg_add_config_reg(new_ntbridgechild, next_bus, devno, 0) 989*26947304SEvan Yan != DDI_PROP_SUCCESS) { 990*26947304SEvan Yan cmn_err(CE_WARN, 991*26947304SEvan Yan "Failed to add conf reg for ntbridge child.\n"); 992*26947304SEvan Yan (void) ndi_devi_free(new_ntbridgechild); 993*26947304SEvan Yan rc = PCICFG_FAILURE; 994*26947304SEvan Yan break; 995*26947304SEvan Yan } 996*26947304SEvan Yan 997*26947304SEvan Yan if ((rc = pci_config_setup(new_ntbridgechild, 998*26947304SEvan Yan &config_handle)) != PCICFG_SUCCESS) { 999*26947304SEvan Yan cmn_err(CE_WARN, 1000*26947304SEvan Yan "Cannot map ntbridge child %x\n", devno); 1001*26947304SEvan Yan (void) ndi_devi_free(new_ntbridgechild); 1002*26947304SEvan Yan rc = PCICFG_FAILURE; 1003*26947304SEvan Yan break; 1004*26947304SEvan Yan } 1005*26947304SEvan Yan 1006*26947304SEvan Yan /* 1007*26947304SEvan Yan * See if there is any PCI HW at this location 1008*26947304SEvan Yan * by reading the Vendor ID. If it returns with 0xffff 1009*26947304SEvan Yan * then there is no hardware at this location. 1010*26947304SEvan Yan */ 1011*26947304SEvan Yan vid = pci_config_get16(config_handle, PCI_CONF_VENID); 1012*26947304SEvan Yan 1013*26947304SEvan Yan pci_config_teardown(&config_handle); 1014*26947304SEvan Yan (void) ndi_devi_free(new_ntbridgechild); 1015*26947304SEvan Yan if (vid == 0xffff) 1016*26947304SEvan Yan continue; 1017*26947304SEvan Yan 1018*26947304SEvan Yan /* Lets fake attachments points for each child, */ 1019*26947304SEvan Yan if (pcicfg_configure(new_device, devno, PCICFG_ALL_FUNC, 0) 1020*26947304SEvan Yan != PCICFG_SUCCESS) { 1021*26947304SEvan Yan int old_dev = pcicfg_start_devno; 1022*26947304SEvan Yan 1023*26947304SEvan Yan cmn_err(CE_WARN, 1024*26947304SEvan Yan "Error configuring ntbridge child dev=%d\n", devno); 1025*26947304SEvan Yan 1026*26947304SEvan Yan rc = PCICFG_FAILURE; 1027*26947304SEvan Yan while (old_dev != devno) { 1028*26947304SEvan Yan if (pcicfg_ntbridge_unconfigure_child( 1029*26947304SEvan Yan new_device, old_dev) == PCICFG_FAILURE) 1030*26947304SEvan Yan 1031*26947304SEvan Yan cmn_err(CE_WARN, 1032*26947304SEvan Yan "Unconfig Error ntbridge child " 1033*26947304SEvan Yan "dev=%d\n", old_dev); 1034*26947304SEvan Yan old_dev++; 1035*26947304SEvan Yan } 1036*26947304SEvan Yan break; 1037*26947304SEvan Yan } 1038*26947304SEvan Yan } /* devno loop */ 1039*26947304SEvan Yan DEBUG1("ntbridge: finish probing 2nd bus, rc=%d\n", rc); 1040*26947304SEvan Yan 1041*26947304SEvan Yan if (rc != PCICFG_FAILURE) 1042*26947304SEvan Yan rc = pcicfg_ntbridge_configure_done(new_device); 1043*26947304SEvan Yan else { 1044*26947304SEvan Yan pcicfg_phdl_t *entry = pcicfg_find_phdl(new_device); 1045*26947304SEvan Yan uint_t *bus; 1046*26947304SEvan Yan int k; 1047*26947304SEvan Yan 1048*26947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, new_device, 1049*26947304SEvan Yan DDI_PROP_DONTPASS, "bus-range", (caddr_t)&bus, 1050*26947304SEvan Yan &k) != DDI_PROP_SUCCESS) { 1051*26947304SEvan Yan DEBUG0("Failed to read bus-range property\n"); 1052*26947304SEvan Yan rc = PCICFG_FAILURE; 1053*26947304SEvan Yan return (rc); 1054*26947304SEvan Yan } 1055*26947304SEvan Yan 1056*26947304SEvan Yan DEBUG2("Need to free bus [%d] range [%d]\n", 1057*26947304SEvan Yan bus[0], bus[1] - bus[0] + 1); 1058*26947304SEvan Yan 1059*26947304SEvan Yan if (ndi_ra_free(ddi_get_parent(new_device), 1060*26947304SEvan Yan (uint64_t)bus[0], (uint64_t)(bus[1] - bus[0] + 1), 1061*26947304SEvan Yan NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS) != NDI_SUCCESS) { 1062*26947304SEvan Yan DEBUG0("Failed to free a bus number\n"); 1063*26947304SEvan Yan rc = PCICFG_FAILURE; 1064*26947304SEvan Yan /* 1065*26947304SEvan Yan * Don't forget to free up memory from ddi_getlongprop 1066*26947304SEvan Yan */ 1067*26947304SEvan Yan kmem_free((caddr_t)bus, k); 1068*26947304SEvan Yan 1069*26947304SEvan Yan return (rc); 1070*26947304SEvan Yan } 1071*26947304SEvan Yan 1072*26947304SEvan Yan /* 1073*26947304SEvan Yan * Since no memory allocations are done for non transparent 1074*26947304SEvan Yan * bridges (but instead we just set the handle with the 1075*26947304SEvan Yan * already allocated memory, we just need to reset the 1076*26947304SEvan Yan * following values before calling the destroy_phdl() 1077*26947304SEvan Yan * function next, otherwise the it will try to free 1078*26947304SEvan Yan * memory allocated as in case of a transparent bridge. 1079*26947304SEvan Yan */ 1080*26947304SEvan Yan entry->memory_len = 0; 1081*26947304SEvan Yan entry->io_len = 0; 1082*26947304SEvan Yan /* the following will free hole data. */ 1083*26947304SEvan Yan (void) pcicfg_destroy_phdl(new_device); 1084*26947304SEvan Yan /* 1085*26947304SEvan Yan * Don't forget to free up memory from ddi_getlongprop 1086*26947304SEvan Yan */ 1087*26947304SEvan Yan kmem_free((caddr_t)bus, k); 1088*26947304SEvan Yan } 1089*26947304SEvan Yan 1090*26947304SEvan Yan /* 1091*26947304SEvan Yan * Unload driver just in case child configure failed! 1092*26947304SEvan Yan */ 1093*26947304SEvan Yan rc1 = ndi_devi_offline(new_device, NDI_NO_EVENT); 1094*26947304SEvan Yan DEBUG1("pcicfg: now unloading the ntbridge driver. rc1=%d\n", rc1); 1095*26947304SEvan Yan if (rc1 != NDI_SUCCESS) { 1096*26947304SEvan Yan cmn_err(CE_WARN, 1097*26947304SEvan Yan "pcicfg: can\'t unload ntbridge driver children.\n"); 1098*26947304SEvan Yan rc = PCICFG_FAILURE; 1099*26947304SEvan Yan } 1100*26947304SEvan Yan 1101*26947304SEvan Yan return (rc); 1102*26947304SEvan Yan } 1103*26947304SEvan Yan 1104*26947304SEvan Yan static int 1105*26947304SEvan Yan pcicfg_ntbridge_allocate_resources(dev_info_t *dip) 1106*26947304SEvan Yan { 1107*26947304SEvan Yan pcicfg_phdl_t *phdl; 1108*26947304SEvan Yan ndi_ra_request_t *mem_request; 1109*26947304SEvan Yan ndi_ra_request_t *io_request; 1110*26947304SEvan Yan uint64_t boundbase, boundlen; 1111*26947304SEvan Yan 1112*26947304SEvan Yan phdl = pcicfg_find_phdl(dip); 1113*26947304SEvan Yan ASSERT(phdl); 1114*26947304SEvan Yan 1115*26947304SEvan Yan mem_request = &phdl->mem_req; 1116*26947304SEvan Yan io_request = &phdl->io_req; 1117*26947304SEvan Yan 1118*26947304SEvan Yan phdl->error = PCICFG_SUCCESS; 1119*26947304SEvan Yan 1120*26947304SEvan Yan /* Set Memory space handle for ntbridge */ 1121*26947304SEvan Yan if (pcicfg_get_ntbridge_child_range(dip, &boundbase, &boundlen, 1122*26947304SEvan Yan PCI_BASE_SPACE_MEM) != DDI_SUCCESS) { 1123*26947304SEvan Yan cmn_err(CE_WARN, 1124*26947304SEvan Yan "ntbridge: Mem resource information failure\n"); 1125*26947304SEvan Yan phdl->memory_len = 0; 1126*26947304SEvan Yan return (PCICFG_FAILURE); 1127*26947304SEvan Yan } 1128*26947304SEvan Yan mem_request->ra_boundbase = boundbase; 1129*26947304SEvan Yan mem_request->ra_boundlen = boundbase + boundlen; 1130*26947304SEvan Yan mem_request->ra_len = boundlen; 1131*26947304SEvan Yan mem_request->ra_align_mask = 1132*26947304SEvan Yan PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */ 1133*26947304SEvan Yan mem_request->ra_flags |= NDI_RA_ALLOC_BOUNDED; 1134*26947304SEvan Yan 1135*26947304SEvan Yan /* 1136*26947304SEvan Yan * mem_request->ra_len = 1137*26947304SEvan Yan * PCICFG_ROUND_UP(mem_request->ra_len, PCICFG_MEMGRAN); 1138*26947304SEvan Yan */ 1139*26947304SEvan Yan 1140*26947304SEvan Yan phdl->memory_base = phdl->memory_last = boundbase; 1141*26947304SEvan Yan phdl->memory_len = boundlen; 1142*26947304SEvan Yan phdl->mem_hole.start = phdl->memory_base; 1143*26947304SEvan Yan phdl->mem_hole.len = mem_request->ra_len; 1144*26947304SEvan Yan phdl->mem_hole.next = (hole_t *)NULL; 1145*26947304SEvan Yan 1146*26947304SEvan Yan DEBUG2("Connector requested [0x%llx], needs [0x%llx] bytes of memory\n", 1147*26947304SEvan Yan boundlen, mem_request->ra_len); 1148*26947304SEvan Yan 1149*26947304SEvan Yan /* set up a memory resource map for NT bridge */ 1150*26947304SEvan Yan if (ndi_ra_map_setup(dip, NDI_RA_TYPE_MEM) == NDI_FAILURE) { 1151*26947304SEvan Yan DEBUG0("Can not setup ntbridge memory resource map\n"); 1152*26947304SEvan Yan return (PCICFG_FAILURE); 1153*26947304SEvan Yan } 1154*26947304SEvan Yan /* initialize the memory map */ 1155*26947304SEvan Yan if (ndi_ra_free(dip, boundbase, boundlen, NDI_RA_TYPE_MEM, 1156*26947304SEvan Yan NDI_RA_PASS) != NDI_SUCCESS) { 1157*26947304SEvan Yan DEBUG0("Can not initalize ntbridge memory resource map\n"); 1158*26947304SEvan Yan return (PCICFG_FAILURE); 1159*26947304SEvan Yan } 1160*26947304SEvan Yan /* Set IO space handle for ntbridge */ 1161*26947304SEvan Yan if (pcicfg_get_ntbridge_child_range(dip, &boundbase, &boundlen, 1162*26947304SEvan Yan PCI_BASE_SPACE_IO) != DDI_SUCCESS) { 1163*26947304SEvan Yan cmn_err(CE_WARN, "ntbridge: IO resource information failure\n"); 1164*26947304SEvan Yan phdl->io_len = 0; 1165*26947304SEvan Yan return (PCICFG_FAILURE); 1166*26947304SEvan Yan } 1167*26947304SEvan Yan io_request->ra_len = boundlen; 1168*26947304SEvan Yan io_request->ra_align_mask = 1169*26947304SEvan Yan PCICFG_IOGRAN - 1; /* 4K alignment on I/O space */ 1170*26947304SEvan Yan io_request->ra_boundbase = boundbase; 1171*26947304SEvan Yan io_request->ra_boundlen = boundbase + boundlen; 1172*26947304SEvan Yan io_request->ra_flags |= NDI_RA_ALLOC_BOUNDED; 1173*26947304SEvan Yan 1174*26947304SEvan Yan /* 1175*26947304SEvan Yan * io_request->ra_len = 1176*26947304SEvan Yan * PCICFG_ROUND_UP(io_request->ra_len, PCICFG_IOGRAN); 1177*26947304SEvan Yan */ 1178*26947304SEvan Yan 1179*26947304SEvan Yan phdl->io_base = phdl->io_last = (uint32_t)boundbase; 1180*26947304SEvan Yan phdl->io_len = (uint32_t)boundlen; 1181*26947304SEvan Yan phdl->io_hole.start = phdl->io_base; 1182*26947304SEvan Yan phdl->io_hole.len = io_request->ra_len; 1183*26947304SEvan Yan phdl->io_hole.next = (hole_t *)NULL; 1184*26947304SEvan Yan 1185*26947304SEvan Yan DEBUG2("Connector requested [0x%llx], needs [0x%llx] bytes of IO\n", 1186*26947304SEvan Yan boundlen, io_request->ra_len); 1187*26947304SEvan Yan 1188*26947304SEvan Yan DEBUG2("MEMORY BASE = [0x%x] length [0x%x]\n", 1189*26947304SEvan Yan phdl->memory_base, phdl->memory_len); 1190*26947304SEvan Yan DEBUG2("IO BASE = [0x%x] length [0x%x]\n", 1191*26947304SEvan Yan phdl->io_base, phdl->io_len); 1192*26947304SEvan Yan 1193*26947304SEvan Yan /* set up a IO resource map for NT bridge */ 1194*26947304SEvan Yan if (ndi_ra_map_setup(dip, NDI_RA_TYPE_IO) == NDI_FAILURE) { 1195*26947304SEvan Yan DEBUG0("Can not setup ntbridge memory resource map\n"); 1196*26947304SEvan Yan return (PCICFG_FAILURE); 1197*26947304SEvan Yan } 1198*26947304SEvan Yan /* initialize the IO map */ 1199*26947304SEvan Yan if (ndi_ra_free(dip, boundbase, boundlen, NDI_RA_TYPE_IO, 1200*26947304SEvan Yan NDI_RA_PASS) != NDI_SUCCESS) { 1201*26947304SEvan Yan DEBUG0("Can not initalize ntbridge memory resource map\n"); 1202*26947304SEvan Yan return (PCICFG_FAILURE); 1203*26947304SEvan Yan } 1204*26947304SEvan Yan 1205*26947304SEvan Yan return (PCICFG_SUCCESS); 1206*26947304SEvan Yan } 1207*26947304SEvan Yan 1208*26947304SEvan Yan static int 1209*26947304SEvan Yan pcicfg_ntbridge_configure_done(dev_info_t *dip) 1210*26947304SEvan Yan { 1211*26947304SEvan Yan pcicfg_range_t range[PCICFG_RANGE_LEN]; 1212*26947304SEvan Yan pcicfg_phdl_t *entry; 1213*26947304SEvan Yan uint_t len; 1214*26947304SEvan Yan pcicfg_bus_range_t bus_range; 1215*26947304SEvan Yan int new_bus_range[2]; 1216*26947304SEvan Yan 1217*26947304SEvan Yan DEBUG1("Configuring children for %llx\n", dip); 1218*26947304SEvan Yan 1219*26947304SEvan Yan entry = pcicfg_find_phdl(dip); 1220*26947304SEvan Yan ASSERT(entry); 1221*26947304SEvan Yan 1222*26947304SEvan Yan bzero((caddr_t)range, 1223*26947304SEvan Yan sizeof (pcicfg_range_t) * PCICFG_RANGE_LEN); 1224*26947304SEvan Yan range[1].child_hi = range[1].parent_hi |= 1225*26947304SEvan Yan (PCI_REG_REL_M | PCI_ADDR_MEM32); 1226*26947304SEvan Yan range[1].child_lo = range[1].parent_lo = (uint32_t)entry->memory_base; 1227*26947304SEvan Yan 1228*26947304SEvan Yan range[0].child_hi = range[0].parent_hi |= 1229*26947304SEvan Yan (PCI_REG_REL_M | PCI_ADDR_IO); 1230*26947304SEvan Yan range[0].child_lo = range[0].parent_lo = (uint32_t)entry->io_base; 1231*26947304SEvan Yan 1232*26947304SEvan Yan len = sizeof (pcicfg_bus_range_t); 1233*26947304SEvan Yan if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 1234*26947304SEvan Yan "bus-range", (caddr_t)&bus_range, (int *)&len) != DDI_SUCCESS) { 1235*26947304SEvan Yan DEBUG0("no bus-range property\n"); 1236*26947304SEvan Yan return (PCICFG_FAILURE); 1237*26947304SEvan Yan } 1238*26947304SEvan Yan 1239*26947304SEvan Yan new_bus_range[0] = bus_range.lo; /* primary bus number */ 1240*26947304SEvan Yan if (entry->highest_bus) { /* secondary bus number */ 1241*26947304SEvan Yan if (entry->highest_bus < bus_range.lo) { 1242*26947304SEvan Yan cmn_err(CE_WARN, 1243*26947304SEvan Yan "ntbridge bus range invalid !(%d,%d)\n", 1244*26947304SEvan Yan bus_range.lo, entry->highest_bus); 1245*26947304SEvan Yan new_bus_range[1] = bus_range.lo + entry->highest_bus; 1246*26947304SEvan Yan } 1247*26947304SEvan Yan else 1248*26947304SEvan Yan new_bus_range[1] = entry->highest_bus; 1249*26947304SEvan Yan } 1250*26947304SEvan Yan else 1251*26947304SEvan Yan new_bus_range[1] = bus_range.hi; 1252*26947304SEvan Yan 1253*26947304SEvan Yan DEBUG2("ntbridge: bus range lo=%x, hi=%x\n", 1254*26947304SEvan Yan new_bus_range[0], new_bus_range[1]); 1255*26947304SEvan Yan 1256*26947304SEvan Yan if (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, 1257*26947304SEvan Yan "bus-range", new_bus_range, 2) != DDI_SUCCESS) { 1258*26947304SEvan Yan DEBUG0("Failed to set bus-range property"); 1259*26947304SEvan Yan entry->error = PCICFG_FAILURE; 1260*26947304SEvan Yan return (PCICFG_FAILURE); 1261*26947304SEvan Yan } 1262*26947304SEvan Yan 1263*26947304SEvan Yan #ifdef DEBUG 1264*26947304SEvan Yan { 1265*26947304SEvan Yan uint64_t unused; 1266*26947304SEvan Yan unused = pcicfg_unused_space(&entry->io_hole, &len); 1267*26947304SEvan Yan DEBUG2("ntbridge: Unused IO space %llx bytes over %d holes\n", 1268*26947304SEvan Yan unused, len); 1269*26947304SEvan Yan } 1270*26947304SEvan Yan #endif 1271*26947304SEvan Yan 1272*26947304SEvan Yan range[0].size_lo = entry->io_len; 1273*26947304SEvan Yan if (pcicfg_update_ranges_prop(dip, &range[0])) { 1274*26947304SEvan Yan DEBUG0("Failed to update ranges (i/o)\n"); 1275*26947304SEvan Yan entry->error = PCICFG_FAILURE; 1276*26947304SEvan Yan return (PCICFG_FAILURE); 1277*26947304SEvan Yan } 1278*26947304SEvan Yan 1279*26947304SEvan Yan #ifdef DEBUG 1280*26947304SEvan Yan { 1281*26947304SEvan Yan uint64_t unused; 1282*26947304SEvan Yan unused = pcicfg_unused_space(&entry->mem_hole, &len); 1283*26947304SEvan Yan DEBUG2("ntbridge: Unused Mem space %llx bytes over %d holes\n", 1284*26947304SEvan Yan unused, len); 1285*26947304SEvan Yan } 1286*26947304SEvan Yan #endif 1287*26947304SEvan Yan 1288*26947304SEvan Yan range[1].size_lo = entry->memory_len; 1289*26947304SEvan Yan if (pcicfg_update_ranges_prop(dip, &range[1])) { 1290*26947304SEvan Yan DEBUG0("Failed to update ranges (memory)\n"); 1291*26947304SEvan Yan entry->error = PCICFG_FAILURE; 1292*26947304SEvan Yan return (PCICFG_FAILURE); 1293*26947304SEvan Yan } 1294*26947304SEvan Yan 1295*26947304SEvan Yan return (PCICFG_SUCCESS); 1296*26947304SEvan Yan } 1297*26947304SEvan Yan 1298*26947304SEvan Yan static int 1299*26947304SEvan Yan pcicfg_ntbridge_unconfigure_child(dev_info_t *new_device, uint_t devno) 1300*26947304SEvan Yan { 1301*26947304SEvan Yan 1302*26947304SEvan Yan dev_info_t *new_ntbridgechild; 1303*26947304SEvan Yan int len, bus; 1304*26947304SEvan Yan uint16_t vid; 1305*26947304SEvan Yan ddi_acc_handle_t config_handle; 1306*26947304SEvan Yan pcicfg_bus_range_t pci_bus_range; 1307*26947304SEvan Yan 1308*26947304SEvan Yan len = sizeof (pcicfg_bus_range_t); 1309*26947304SEvan Yan if (ddi_getlongprop_buf(DDI_DEV_T_ANY, new_device, DDI_PROP_DONTPASS, 1310*26947304SEvan Yan "bus-range", (caddr_t)&pci_bus_range, &len) != DDI_SUCCESS) { 1311*26947304SEvan Yan DEBUG0("no bus-range property\n"); 1312*26947304SEvan Yan return (PCICFG_FAILURE); 1313*26947304SEvan Yan } 1314*26947304SEvan Yan 1315*26947304SEvan Yan bus = pci_bus_range.lo; /* primary bus number of this bus node */ 1316*26947304SEvan Yan 1317*26947304SEvan Yan if (ndi_devi_alloc(new_device, DEVI_PSEUDO_NEXNAME, 1318*26947304SEvan Yan (pnode_t)DEVI_SID_NODEID, &new_ntbridgechild) != NDI_SUCCESS) { 1319*26947304SEvan Yan 1320*26947304SEvan Yan DEBUG0("pcicfg: Failed to alloc test node\n"); 1321*26947304SEvan Yan return (PCICFG_FAILURE); 1322*26947304SEvan Yan } 1323*26947304SEvan Yan 1324*26947304SEvan Yan if (pcicfg_add_config_reg(new_ntbridgechild, bus, devno, 0) 1325*26947304SEvan Yan != DDI_PROP_SUCCESS) { 1326*26947304SEvan Yan cmn_err(CE_WARN, 1327*26947304SEvan Yan "Unconfigure: Failed to add conf reg prop for ntbridge " 1328*26947304SEvan Yan "child.\n"); 1329*26947304SEvan Yan (void) ndi_devi_free(new_ntbridgechild); 1330*26947304SEvan Yan return (PCICFG_FAILURE); 1331*26947304SEvan Yan } 1332*26947304SEvan Yan 1333*26947304SEvan Yan if (pcicfg_config_setup(new_ntbridgechild, &config_handle) 1334*26947304SEvan Yan != DDI_SUCCESS) { 1335*26947304SEvan Yan cmn_err(CE_WARN, 1336*26947304SEvan Yan "pcicfg: Cannot map ntbridge child %x\n", devno); 1337*26947304SEvan Yan (void) ndi_devi_free(new_ntbridgechild); 1338*26947304SEvan Yan return (PCICFG_FAILURE); 1339*26947304SEvan Yan } 1340*26947304SEvan Yan 1341*26947304SEvan Yan /* 1342*26947304SEvan Yan * See if there is any PCI HW at this location 1343*26947304SEvan Yan * by reading the Vendor ID. If it returns with 0xffff 1344*26947304SEvan Yan * then there is no hardware at this location. 1345*26947304SEvan Yan */ 1346*26947304SEvan Yan vid = pci_config_get16(config_handle, PCI_CONF_VENID); 1347*26947304SEvan Yan 1348*26947304SEvan Yan pci_config_teardown(&config_handle); 1349*26947304SEvan Yan (void) ndi_devi_free(new_ntbridgechild); 1350*26947304SEvan Yan if (vid == 0xffff) 1351*26947304SEvan Yan return (PCICFG_NODEVICE); 1352*26947304SEvan Yan 1353*26947304SEvan Yan return (pcicfg_unconfigure(new_device, devno, PCICFG_ALL_FUNC, 0)); 1354*26947304SEvan Yan } 1355*26947304SEvan Yan 1356*26947304SEvan Yan static int 1357*26947304SEvan Yan pcicfg_ntbridge_unconfigure(dev_info_t *dip) 1358*26947304SEvan Yan { 1359*26947304SEvan Yan pcicfg_phdl_t *entry = pcicfg_find_phdl(dip); 1360*26947304SEvan Yan uint_t *bus; 1361*26947304SEvan Yan int k, rc = PCICFG_FAILURE; 1362*26947304SEvan Yan 1363*26947304SEvan Yan if (entry->memory_len) 1364*26947304SEvan Yan if (ndi_ra_map_destroy(dip, NDI_RA_TYPE_MEM) == NDI_FAILURE) { 1365*26947304SEvan Yan DEBUG1("cannot destroy ntbridge memory map size=%x\n", 1366*26947304SEvan Yan entry->memory_len); 1367*26947304SEvan Yan return (PCICFG_FAILURE); 1368*26947304SEvan Yan } 1369*26947304SEvan Yan if (entry->io_len) 1370*26947304SEvan Yan if (ndi_ra_map_destroy(dip, NDI_RA_TYPE_IO) == NDI_FAILURE) { 1371*26947304SEvan Yan DEBUG1("cannot destroy ntbridge io map size=%x\n", 1372*26947304SEvan Yan entry->io_len); 1373*26947304SEvan Yan return (PCICFG_FAILURE); 1374*26947304SEvan Yan } 1375*26947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 1376*26947304SEvan Yan DDI_PROP_DONTPASS, "bus-range", (caddr_t)&bus, 1377*26947304SEvan Yan &k) != DDI_PROP_SUCCESS) { 1378*26947304SEvan Yan DEBUG0("ntbridge: Failed to read bus-range property\n"); 1379*26947304SEvan Yan return (rc); 1380*26947304SEvan Yan } 1381*26947304SEvan Yan 1382*26947304SEvan Yan DEBUG2("ntbridge: Need to free bus [%d] range [%d]\n", 1383*26947304SEvan Yan bus[0], bus[1] - bus[0] + 1); 1384*26947304SEvan Yan 1385*26947304SEvan Yan if (ndi_ra_free(ddi_get_parent(dip), 1386*26947304SEvan Yan (uint64_t)bus[0], (uint64_t)(bus[1] - bus[0] + 1), 1387*26947304SEvan Yan NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS) != NDI_SUCCESS) { 1388*26947304SEvan Yan DEBUG0("ntbridge: Failed to free a bus number\n"); 1389*26947304SEvan Yan /* 1390*26947304SEvan Yan * Don't forget to free up memory from ddi_getlongprop 1391*26947304SEvan Yan */ 1392*26947304SEvan Yan kmem_free((caddr_t)bus, k); 1393*26947304SEvan Yan 1394*26947304SEvan Yan return (rc); 1395*26947304SEvan Yan } 1396*26947304SEvan Yan 1397*26947304SEvan Yan /* 1398*26947304SEvan Yan * Don't forget to free up memory from ddi_getlongprop 1399*26947304SEvan Yan */ 1400*26947304SEvan Yan kmem_free((caddr_t)bus, k); 1401*26947304SEvan Yan 1402*26947304SEvan Yan /* 1403*26947304SEvan Yan * Since our resources will be freed at the parent level, 1404*26947304SEvan Yan * just reset these values. 1405*26947304SEvan Yan */ 1406*26947304SEvan Yan entry->memory_len = 0; 1407*26947304SEvan Yan entry->io_len = 0; 1408*26947304SEvan Yan /* the following will also free hole data. */ 1409*26947304SEvan Yan return (pcicfg_destroy_phdl(dip)); 1410*26947304SEvan Yan 1411*26947304SEvan Yan } 1412*26947304SEvan Yan 1413*26947304SEvan Yan static int 1414*26947304SEvan Yan pcicfg_is_ntbridge(dev_info_t *dip) 1415*26947304SEvan Yan { 1416*26947304SEvan Yan ddi_acc_handle_t config_handle; 1417*26947304SEvan Yan uint8_t class, subclass; 1418*26947304SEvan Yan int rc = DDI_SUCCESS; 1419*26947304SEvan Yan 1420*26947304SEvan Yan if (pcicfg_config_setup(dip, &config_handle) != DDI_SUCCESS) { 1421*26947304SEvan Yan cmn_err(CE_WARN, 1422*26947304SEvan Yan "pcicfg: cannot map config space, to get map type\n"); 1423*26947304SEvan Yan return (DDI_FAILURE); 1424*26947304SEvan Yan } 1425*26947304SEvan Yan class = pci_config_get8(config_handle, PCI_CONF_BASCLASS); 1426*26947304SEvan Yan subclass = pci_config_get8(config_handle, PCI_CONF_SUBCLASS); 1427*26947304SEvan Yan 1428*26947304SEvan Yan /* check for class=6, subclass=9, for non transparent bridges. */ 1429*26947304SEvan Yan if ((class != PCI_CLASS_BRIDGE) || (subclass != PCI_BRIDGE_STBRIDGE)) 1430*26947304SEvan Yan rc = DDI_FAILURE; 1431*26947304SEvan Yan 1432*26947304SEvan Yan DEBUG3("pcicfg: checking device %x,%x for indirect map. rc=%d\n", 1433*26947304SEvan Yan pci_config_get16(config_handle, PCI_CONF_VENID), 1434*26947304SEvan Yan pci_config_get16(config_handle, PCI_CONF_DEVID), 1435*26947304SEvan Yan rc); 1436*26947304SEvan Yan pci_config_teardown(&config_handle); 1437*26947304SEvan Yan return (rc); 1438*26947304SEvan Yan } 1439*26947304SEvan Yan 1440*26947304SEvan Yan /* 1441*26947304SEvan Yan * this function is called only for SPARC platforms, where we may have 1442*26947304SEvan Yan * a mix n' match of direct vs indirectly mapped configuration space. 1443*26947304SEvan Yan * On x86, this function does not get called. We always return TRUE 1444*26947304SEvan Yan * via a macro for x86. 1445*26947304SEvan Yan */ 1446*26947304SEvan Yan /*ARGSUSED*/ 1447*26947304SEvan Yan static int 1448*26947304SEvan Yan pcicfg_indirect_map(dev_info_t *dip) 1449*26947304SEvan Yan { 1450*26947304SEvan Yan #if defined(__sparc) 1451*26947304SEvan Yan int rc = DDI_FAILURE; 1452*26947304SEvan Yan 1453*26947304SEvan Yan if (ddi_prop_get_int(DDI_DEV_T_ANY, ddi_get_parent(dip), 0, 1454*26947304SEvan Yan PCI_DEV_CONF_MAP_PROP, DDI_FAILURE) != DDI_FAILURE) 1455*26947304SEvan Yan rc = DDI_SUCCESS; 1456*26947304SEvan Yan else 1457*26947304SEvan Yan if (ddi_prop_get_int(DDI_DEV_T_ANY, ddi_get_parent(dip), 1458*26947304SEvan Yan 0, PCI_BUS_CONF_MAP_PROP, 1459*26947304SEvan Yan DDI_FAILURE) != DDI_FAILURE) 1460*26947304SEvan Yan rc = DDI_SUCCESS; 1461*26947304SEvan Yan DEBUG1("pci conf map = %d", rc); 1462*26947304SEvan Yan return (rc); 1463*26947304SEvan Yan #else 1464*26947304SEvan Yan return (DDI_SUCCESS); 1465*26947304SEvan Yan #endif 1466*26947304SEvan Yan } 1467*26947304SEvan Yan 1468*26947304SEvan Yan static uint_t 1469*26947304SEvan Yan pcicfg_get_ntbridge_child_range(dev_info_t *dip, uint64_t *boundbase, 1470*26947304SEvan Yan uint64_t *boundlen, uint_t space_type) 1471*26947304SEvan Yan { 1472*26947304SEvan Yan int length, found = DDI_FAILURE, acount, i, ibridge; 1473*26947304SEvan Yan pci_regspec_t *assigned; 1474*26947304SEvan Yan 1475*26947304SEvan Yan if ((ibridge = pcicfg_is_ntbridge(dip)) == DDI_FAILURE) 1476*26947304SEvan Yan return (found); 1477*26947304SEvan Yan 1478*26947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 1479*26947304SEvan Yan DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned, 1480*26947304SEvan Yan &length) != DDI_PROP_SUCCESS) { 1481*26947304SEvan Yan DEBUG1("Failed to get assigned-addresses property %llx\n", dip); 1482*26947304SEvan Yan return (found); 1483*26947304SEvan Yan } 1484*26947304SEvan Yan DEBUG1("pcicfg: ntbridge child range: dip = %s\n", 1485*26947304SEvan Yan ddi_driver_name(dip)); 1486*26947304SEvan Yan 1487*26947304SEvan Yan acount = length / sizeof (pci_regspec_t); 1488*26947304SEvan Yan 1489*26947304SEvan Yan for (i = 0; i < acount; i++) { 1490*26947304SEvan Yan if ((PCI_REG_REG_G(assigned[i].pci_phys_hi) == 1491*26947304SEvan Yan pcicfg_indirect_map_devs[ibridge].mem_range_bar_offset) && 1492*26947304SEvan Yan (space_type == PCI_BASE_SPACE_MEM)) { 1493*26947304SEvan Yan found = DDI_SUCCESS; 1494*26947304SEvan Yan break; 1495*26947304SEvan Yan } else { 1496*26947304SEvan Yan if ((PCI_REG_REG_G(assigned[i].pci_phys_hi) == 1497*26947304SEvan Yan pcicfg_indirect_map_devs[ibridge].\ 1498*26947304SEvan Yan io_range_bar_offset) && 1499*26947304SEvan Yan (space_type == PCI_BASE_SPACE_IO)) { 1500*26947304SEvan Yan found = DDI_SUCCESS; 1501*26947304SEvan Yan break; 1502*26947304SEvan Yan } 1503*26947304SEvan Yan } 1504*26947304SEvan Yan } 1505*26947304SEvan Yan DEBUG3("pcicfg: ntbridge child range: space=%x, base=%lx, len=%lx\n", 1506*26947304SEvan Yan space_type, assigned[i].pci_phys_low, assigned[i].pci_size_low); 1507*26947304SEvan Yan 1508*26947304SEvan Yan if (found == DDI_SUCCESS) { 1509*26947304SEvan Yan *boundbase = assigned[i].pci_phys_low; 1510*26947304SEvan Yan *boundlen = assigned[i].pci_size_low; 1511*26947304SEvan Yan } 1512*26947304SEvan Yan 1513*26947304SEvan Yan kmem_free(assigned, length); 1514*26947304SEvan Yan return (found); 1515*26947304SEvan Yan } 1516*26947304SEvan Yan 1517*26947304SEvan Yan /* 1518*26947304SEvan Yan * This will turn resources allocated by pcicfg_configure() 1519*26947304SEvan Yan * and remove the device tree from the Hotplug Connection (CN) 1520*26947304SEvan Yan * and below. The routine assumes the devices have their 1521*26947304SEvan Yan * drivers detached. 1522*26947304SEvan Yan */ 1523*26947304SEvan Yan int 1524*26947304SEvan Yan pcicfg_unconfigure(dev_info_t *devi, uint_t device, uint_t function, 1525*26947304SEvan Yan pcicfg_flags_t flags) 1526*26947304SEvan Yan { 1527*26947304SEvan Yan dev_info_t *child_dip; 1528*26947304SEvan Yan int func; 1529*26947304SEvan Yan int i; 1530*26947304SEvan Yan int max_function; 1531*26947304SEvan Yan int trans_device; 1532*26947304SEvan Yan 1533*26947304SEvan Yan if (pcie_ari_is_enabled(devi) == PCIE_ARI_FORW_ENABLED) 1534*26947304SEvan Yan max_function = PCICFG_MAX_ARI_FUNCTION; 1535*26947304SEvan Yan else 1536*26947304SEvan Yan max_function = PCICFG_MAX_FUNCTION; 1537*26947304SEvan Yan 1538*26947304SEvan Yan /* 1539*26947304SEvan Yan * Cycle through devices to make sure none are busy. 1540*26947304SEvan Yan * If a single device is busy fail the whole unconfigure. 1541*26947304SEvan Yan */ 1542*26947304SEvan Yan for (func = 0; func < max_function; func++) { 1543*26947304SEvan Yan 1544*26947304SEvan Yan if (max_function == PCICFG_MAX_ARI_FUNCTION) 1545*26947304SEvan Yan trans_device = func >> 3; /* ARI Device */ 1546*26947304SEvan Yan else 1547*26947304SEvan Yan trans_device = device; 1548*26947304SEvan Yan 1549*26947304SEvan Yan if ((child_dip = pcicfg_devi_find(devi, trans_device, 1550*26947304SEvan Yan (func & 0x7))) == NULL) 1551*26947304SEvan Yan continue; 1552*26947304SEvan Yan 1553*26947304SEvan Yan if (ndi_devi_offline(child_dip, NDI_UNCONFIG) == NDI_SUCCESS) 1554*26947304SEvan Yan continue; 1555*26947304SEvan Yan /* 1556*26947304SEvan Yan * Device function is busy. Before returning we have to 1557*26947304SEvan Yan * put all functions back online which were taken 1558*26947304SEvan Yan * offline during the process. 1559*26947304SEvan Yan */ 1560*26947304SEvan Yan DEBUG2("Device [0x%x] function [%x] is busy\n", device, func); 1561*26947304SEvan Yan /* 1562*26947304SEvan Yan * If we are only asked to offline one specific function, 1563*26947304SEvan Yan * and that fails, we just simply return. 1564*26947304SEvan Yan */ 1565*26947304SEvan Yan if (function != PCICFG_ALL_FUNC) 1566*26947304SEvan Yan return (PCICFG_FAILURE); 1567*26947304SEvan Yan 1568*26947304SEvan Yan for (i = 0; i < func; i++) { 1569*26947304SEvan Yan 1570*26947304SEvan Yan if (max_function == PCICFG_MAX_ARI_FUNCTION) 1571*26947304SEvan Yan trans_device = i >> 3; 1572*26947304SEvan Yan 1573*26947304SEvan Yan if ((child_dip = 1574*26947304SEvan Yan pcicfg_devi_find(devi, trans_device, (i & 7))) 1575*26947304SEvan Yan == NULL) { 1576*26947304SEvan Yan DEBUG0( 1577*26947304SEvan Yan "No more devices to put back on line!!\n"); 1578*26947304SEvan Yan /* 1579*26947304SEvan Yan * Made it through all functions 1580*26947304SEvan Yan */ 1581*26947304SEvan Yan continue; 1582*26947304SEvan Yan } 1583*26947304SEvan Yan if (ndi_devi_online(child_dip, NDI_CONFIG) 1584*26947304SEvan Yan != NDI_SUCCESS) { 1585*26947304SEvan Yan DEBUG0("Failed to put back devices state\n"); 1586*26947304SEvan Yan return (PCICFG_FAILURE); 1587*26947304SEvan Yan } 1588*26947304SEvan Yan } 1589*26947304SEvan Yan return (PCICFG_FAILURE); 1590*26947304SEvan Yan } 1591*26947304SEvan Yan 1592*26947304SEvan Yan /* 1593*26947304SEvan Yan * Now, tear down all devinfo nodes for this Connector. 1594*26947304SEvan Yan */ 1595*26947304SEvan Yan for (func = 0; func < max_function; func++) { 1596*26947304SEvan Yan 1597*26947304SEvan Yan if (max_function == PCICFG_MAX_ARI_FUNCTION) 1598*26947304SEvan Yan trans_device = func >> 3; /* ARI Device */ 1599*26947304SEvan Yan else 1600*26947304SEvan Yan trans_device = device; 1601*26947304SEvan Yan 1602*26947304SEvan Yan if ((child_dip = pcicfg_devi_find(devi, 1603*26947304SEvan Yan trans_device, (func & 7))) == NULL) { 1604*26947304SEvan Yan DEBUG0("No more devices to tear down!\n"); 1605*26947304SEvan Yan continue; 1606*26947304SEvan Yan } 1607*26947304SEvan Yan 1608*26947304SEvan Yan DEBUG2("Tearing down device [0x%x] function [0x%x]\n", 1609*26947304SEvan Yan trans_device, (func & 7)); 1610*26947304SEvan Yan 1611*26947304SEvan Yan if (pcicfg_is_ntbridge(child_dip) != DDI_FAILURE) 1612*26947304SEvan Yan if (pcicfg_ntbridge_unconfigure(child_dip) != 1613*26947304SEvan Yan PCICFG_SUCCESS) { 1614*26947304SEvan Yan cmn_err(CE_WARN, 1615*26947304SEvan Yan "ntbridge: unconfigure failed\n"); 1616*26947304SEvan Yan return (PCICFG_FAILURE); 1617*26947304SEvan Yan } 1618*26947304SEvan Yan 1619*26947304SEvan Yan if (pcicfg_teardown_device(child_dip, flags) 1620*26947304SEvan Yan != PCICFG_SUCCESS) { 1621*26947304SEvan Yan DEBUG2("Failed to tear down device [0x%x]" 1622*26947304SEvan Yan "function [0x%x]\n", 1623*26947304SEvan Yan trans_device, func & 7); 1624*26947304SEvan Yan return (PCICFG_FAILURE); 1625*26947304SEvan Yan } 1626*26947304SEvan Yan } 1627*26947304SEvan Yan 1628*26947304SEvan Yan if (pcie_ari_is_enabled(devi) == PCIE_ARI_FORW_ENABLED) { 1629*26947304SEvan Yan (void) ddi_prop_remove(DDI_DEV_T_NONE, devi, "ari-enabled"); 1630*26947304SEvan Yan (void) pcie_ari_disable(devi); 1631*26947304SEvan Yan } 1632*26947304SEvan Yan 1633*26947304SEvan Yan return (PCICFG_SUCCESS); 1634*26947304SEvan Yan } 1635*26947304SEvan Yan 1636*26947304SEvan Yan static int 1637*26947304SEvan Yan pcicfg_teardown_device(dev_info_t *dip, pcicfg_flags_t flags) 1638*26947304SEvan Yan { 1639*26947304SEvan Yan ddi_acc_handle_t config_handle; 1640*26947304SEvan Yan 1641*26947304SEvan Yan /* 1642*26947304SEvan Yan * Free up resources associated with 'dip' 1643*26947304SEvan Yan */ 1644*26947304SEvan Yan if (pcicfg_free_resources(dip, flags) != PCICFG_SUCCESS) { 1645*26947304SEvan Yan DEBUG0("Failed to free resources\n"); 1646*26947304SEvan Yan return (PCICFG_FAILURE); 1647*26947304SEvan Yan } 1648*26947304SEvan Yan 1649*26947304SEvan Yan /* 1650*26947304SEvan Yan * This will disable the device 1651*26947304SEvan Yan */ 1652*26947304SEvan Yan if (pci_config_setup(dip, &config_handle) != PCICFG_SUCCESS) { 1653*26947304SEvan Yan return (PCICFG_FAILURE); 1654*26947304SEvan Yan } 1655*26947304SEvan Yan 1656*26947304SEvan Yan pcicfg_device_off(config_handle); 1657*26947304SEvan Yan pci_config_teardown(&config_handle); 1658*26947304SEvan Yan 1659*26947304SEvan Yan /* 1660*26947304SEvan Yan * The framework provides this routine which can 1661*26947304SEvan Yan * tear down a sub-tree. 1662*26947304SEvan Yan */ 1663*26947304SEvan Yan if (ndi_devi_offline(dip, NDI_DEVI_REMOVE) != NDI_SUCCESS) { 1664*26947304SEvan Yan DEBUG0("Failed to offline and remove node\n"); 1665*26947304SEvan Yan return (PCICFG_FAILURE); 1666*26947304SEvan Yan } 1667*26947304SEvan Yan 1668*26947304SEvan Yan return (PCICFG_SUCCESS); 1669*26947304SEvan Yan } 1670*26947304SEvan Yan 1671*26947304SEvan Yan /* 1672*26947304SEvan Yan * BEGIN GENERIC SUPPORT ROUTINES 1673*26947304SEvan Yan */ 1674*26947304SEvan Yan static pcicfg_phdl_t * 1675*26947304SEvan Yan pcicfg_find_phdl(dev_info_t *dip) 1676*26947304SEvan Yan { 1677*26947304SEvan Yan pcicfg_phdl_t *entry; 1678*26947304SEvan Yan mutex_enter(&pcicfg_list_mutex); 1679*26947304SEvan Yan for (entry = pcicfg_phdl_list; entry != NULL; entry = entry->next) { 1680*26947304SEvan Yan if (entry->dip == dip) { 1681*26947304SEvan Yan mutex_exit(&pcicfg_list_mutex); 1682*26947304SEvan Yan return (entry); 1683*26947304SEvan Yan } 1684*26947304SEvan Yan } 1685*26947304SEvan Yan mutex_exit(&pcicfg_list_mutex); 1686*26947304SEvan Yan 1687*26947304SEvan Yan /* 1688*26947304SEvan Yan * Did'nt find entry - create one 1689*26947304SEvan Yan */ 1690*26947304SEvan Yan return (pcicfg_create_phdl(dip)); 1691*26947304SEvan Yan } 1692*26947304SEvan Yan 1693*26947304SEvan Yan static pcicfg_phdl_t * 1694*26947304SEvan Yan pcicfg_create_phdl(dev_info_t *dip) 1695*26947304SEvan Yan { 1696*26947304SEvan Yan pcicfg_phdl_t *new; 1697*26947304SEvan Yan 1698*26947304SEvan Yan new = (pcicfg_phdl_t *)kmem_zalloc(sizeof (pcicfg_phdl_t), 1699*26947304SEvan Yan KM_SLEEP); 1700*26947304SEvan Yan 1701*26947304SEvan Yan new->dip = dip; 1702*26947304SEvan Yan mutex_enter(&pcicfg_list_mutex); 1703*26947304SEvan Yan new->next = pcicfg_phdl_list; 1704*26947304SEvan Yan pcicfg_phdl_list = new; 1705*26947304SEvan Yan mutex_exit(&pcicfg_list_mutex); 1706*26947304SEvan Yan 1707*26947304SEvan Yan return (new); 1708*26947304SEvan Yan } 1709*26947304SEvan Yan 1710*26947304SEvan Yan static int 1711*26947304SEvan Yan pcicfg_destroy_phdl(dev_info_t *dip) 1712*26947304SEvan Yan { 1713*26947304SEvan Yan pcicfg_phdl_t *entry; 1714*26947304SEvan Yan pcicfg_phdl_t *follow = NULL; 1715*26947304SEvan Yan 1716*26947304SEvan Yan mutex_enter(&pcicfg_list_mutex); 1717*26947304SEvan Yan for (entry = pcicfg_phdl_list; entry != NULL; follow = entry, 1718*26947304SEvan Yan entry = entry->next) { 1719*26947304SEvan Yan if (entry->dip == dip) { 1720*26947304SEvan Yan if (entry == pcicfg_phdl_list) { 1721*26947304SEvan Yan pcicfg_phdl_list = entry->next; 1722*26947304SEvan Yan } else { 1723*26947304SEvan Yan follow->next = entry->next; 1724*26947304SEvan Yan } 1725*26947304SEvan Yan /* 1726*26947304SEvan Yan * If this entry has any allocated memory 1727*26947304SEvan Yan * or IO space associated with it, that 1728*26947304SEvan Yan * must be freed up. 1729*26947304SEvan Yan */ 1730*26947304SEvan Yan if (entry->memory_len > 0) { 1731*26947304SEvan Yan (void) ndi_ra_free(ddi_get_parent(dip), 1732*26947304SEvan Yan entry->memory_base, 1733*26947304SEvan Yan entry->memory_len, 1734*26947304SEvan Yan NDI_RA_TYPE_MEM, NDI_RA_PASS); 1735*26947304SEvan Yan } 1736*26947304SEvan Yan pcicfg_free_hole(&entry->mem_hole); 1737*26947304SEvan Yan 1738*26947304SEvan Yan if (entry->io_len > 0) { 1739*26947304SEvan Yan (void) ndi_ra_free(ddi_get_parent(dip), 1740*26947304SEvan Yan entry->io_base, 1741*26947304SEvan Yan entry->io_len, 1742*26947304SEvan Yan NDI_RA_TYPE_IO, NDI_RA_PASS); 1743*26947304SEvan Yan } 1744*26947304SEvan Yan pcicfg_free_hole(&entry->io_hole); 1745*26947304SEvan Yan 1746*26947304SEvan Yan /* 1747*26947304SEvan Yan * Destroy this entry 1748*26947304SEvan Yan */ 1749*26947304SEvan Yan kmem_free((caddr_t)entry, sizeof (pcicfg_phdl_t)); 1750*26947304SEvan Yan mutex_exit(&pcicfg_list_mutex); 1751*26947304SEvan Yan return (PCICFG_SUCCESS); 1752*26947304SEvan Yan } 1753*26947304SEvan Yan } 1754*26947304SEvan Yan mutex_exit(&pcicfg_list_mutex); 1755*26947304SEvan Yan /* 1756*26947304SEvan Yan * Did'nt find the entry 1757*26947304SEvan Yan */ 1758*26947304SEvan Yan return (PCICFG_FAILURE); 1759*26947304SEvan Yan } 1760*26947304SEvan Yan 1761*26947304SEvan Yan static int 1762*26947304SEvan Yan pcicfg_program_ap(dev_info_t *dip) 1763*26947304SEvan Yan { 1764*26947304SEvan Yan pcicfg_phdl_t *phdl; 1765*26947304SEvan Yan uint8_t header_type; 1766*26947304SEvan Yan ddi_acc_handle_t handle; 1767*26947304SEvan Yan pcicfg_phdl_t *entry; 1768*26947304SEvan Yan 1769*26947304SEvan Yan if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) { 1770*26947304SEvan Yan DEBUG0("Failed to map config space!\n"); 1771*26947304SEvan Yan return (PCICFG_FAILURE); 1772*26947304SEvan Yan 1773*26947304SEvan Yan } 1774*26947304SEvan Yan 1775*26947304SEvan Yan header_type = pci_config_get8(handle, PCI_CONF_HEADER); 1776*26947304SEvan Yan 1777*26947304SEvan Yan (void) pcicfg_config_teardown(&handle); 1778*26947304SEvan Yan 1779*26947304SEvan Yan if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) { 1780*26947304SEvan Yan 1781*26947304SEvan Yan if (pcicfg_allocate_chunk(dip) != PCICFG_SUCCESS) { 1782*26947304SEvan Yan DEBUG0("Not enough memory to hotplug\n"); 1783*26947304SEvan Yan (void) pcicfg_destroy_phdl(dip); 1784*26947304SEvan Yan return (PCICFG_FAILURE); 1785*26947304SEvan Yan } 1786*26947304SEvan Yan 1787*26947304SEvan Yan phdl = pcicfg_find_phdl(dip); 1788*26947304SEvan Yan ASSERT(phdl); 1789*26947304SEvan Yan 1790*26947304SEvan Yan (void) pcicfg_bridge_assign(dip, (void *)phdl); 1791*26947304SEvan Yan 1792*26947304SEvan Yan if (phdl->error != PCICFG_SUCCESS) { 1793*26947304SEvan Yan DEBUG0("Problem assigning bridge\n"); 1794*26947304SEvan Yan (void) pcicfg_destroy_phdl(dip); 1795*26947304SEvan Yan return (phdl->error); 1796*26947304SEvan Yan } 1797*26947304SEvan Yan 1798*26947304SEvan Yan /* 1799*26947304SEvan Yan * Successfully allocated and assigned 1800*26947304SEvan Yan * memory. Set the memory and IO length 1801*26947304SEvan Yan * to zero so when the handle is freed up 1802*26947304SEvan Yan * it will not de-allocate assigned resources. 1803*26947304SEvan Yan */ 1804*26947304SEvan Yan entry = (pcicfg_phdl_t *)phdl; 1805*26947304SEvan Yan 1806*26947304SEvan Yan entry->memory_len = entry->io_len = 0; 1807*26947304SEvan Yan 1808*26947304SEvan Yan /* 1809*26947304SEvan Yan * Free up the "entry" structure. 1810*26947304SEvan Yan */ 1811*26947304SEvan Yan (void) pcicfg_destroy_phdl(dip); 1812*26947304SEvan Yan } else { 1813*26947304SEvan Yan if (pcicfg_device_assign(dip) != PCICFG_SUCCESS) { 1814*26947304SEvan Yan return (PCICFG_FAILURE); 1815*26947304SEvan Yan } 1816*26947304SEvan Yan } 1817*26947304SEvan Yan return (PCICFG_SUCCESS); 1818*26947304SEvan Yan } 1819*26947304SEvan Yan 1820*26947304SEvan Yan static int 1821*26947304SEvan Yan pcicfg_bridge_assign(dev_info_t *dip, void *hdl) 1822*26947304SEvan Yan { 1823*26947304SEvan Yan ddi_acc_handle_t handle; 1824*26947304SEvan Yan pci_regspec_t *reg; 1825*26947304SEvan Yan int length; 1826*26947304SEvan Yan int rcount; 1827*26947304SEvan Yan int i; 1828*26947304SEvan Yan int offset; 1829*26947304SEvan Yan uint64_t mem_answer; 1830*26947304SEvan Yan uint32_t io_answer; 1831*26947304SEvan Yan int count; 1832*26947304SEvan Yan uint8_t header_type; 1833*26947304SEvan Yan pcicfg_range_t range[PCICFG_RANGE_LEN]; 1834*26947304SEvan Yan int bus_range[2]; 1835*26947304SEvan Yan 1836*26947304SEvan Yan pcicfg_phdl_t *entry = (pcicfg_phdl_t *)hdl; 1837*26947304SEvan Yan 1838*26947304SEvan Yan DEBUG1("bridge assign: assigning addresses to %s\n", ddi_get_name(dip)); 1839*26947304SEvan Yan 1840*26947304SEvan Yan if (entry == NULL) { 1841*26947304SEvan Yan DEBUG0("Failed to get entry\n"); 1842*26947304SEvan Yan return (DDI_WALK_TERMINATE); 1843*26947304SEvan Yan } 1844*26947304SEvan Yan 1845*26947304SEvan Yan entry->error = PCICFG_SUCCESS; 1846*26947304SEvan Yan 1847*26947304SEvan Yan if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) { 1848*26947304SEvan Yan DEBUG0("Failed to map config space!\n"); 1849*26947304SEvan Yan entry->error = PCICFG_FAILURE; 1850*26947304SEvan Yan return (DDI_WALK_TERMINATE); 1851*26947304SEvan Yan } 1852*26947304SEvan Yan 1853*26947304SEvan Yan header_type = pci_config_get8(handle, PCI_CONF_HEADER); 1854*26947304SEvan Yan 1855*26947304SEvan Yan if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) { 1856*26947304SEvan Yan 1857*26947304SEvan Yan bzero((caddr_t)range, 1858*26947304SEvan Yan sizeof (pcicfg_range_t) * PCICFG_RANGE_LEN); 1859*26947304SEvan Yan 1860*26947304SEvan Yan (void) pcicfg_setup_bridge(entry, handle, dip); 1861*26947304SEvan Yan 1862*26947304SEvan Yan range[0].child_hi = range[0].parent_hi |= 1863*26947304SEvan Yan (PCI_REG_REL_M | PCI_ADDR_IO); 1864*26947304SEvan Yan range[0].child_lo = range[0].parent_lo = 1865*26947304SEvan Yan entry->io_last; 1866*26947304SEvan Yan range[1].child_hi = range[1].parent_hi |= 1867*26947304SEvan Yan (PCI_REG_REL_M | PCI_ADDR_MEM32); 1868*26947304SEvan Yan range[1].child_lo = range[1].parent_lo = 1869*26947304SEvan Yan entry->memory_last; 1870*26947304SEvan Yan 1871*26947304SEvan Yan ndi_devi_enter(dip, &count); 1872*26947304SEvan Yan ddi_walk_devs(ddi_get_child(dip), 1873*26947304SEvan Yan pcicfg_bridge_assign, (void *)entry); 1874*26947304SEvan Yan ndi_devi_exit(dip, count); 1875*26947304SEvan Yan 1876*26947304SEvan Yan (void) pcicfg_update_bridge(entry, handle); 1877*26947304SEvan Yan 1878*26947304SEvan Yan bus_range[0] = pci_config_get8(handle, PCI_BCNF_SECBUS); 1879*26947304SEvan Yan bus_range[1] = pci_config_get8(handle, PCI_BCNF_SUBBUS); 1880*26947304SEvan Yan 1881*26947304SEvan Yan if (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, 1882*26947304SEvan Yan "bus-range", bus_range, 2) != DDI_SUCCESS) { 1883*26947304SEvan Yan DEBUG0("Failed to set bus-range property"); 1884*26947304SEvan Yan entry->error = PCICFG_FAILURE; 1885*26947304SEvan Yan return (DDI_WALK_TERMINATE); 1886*26947304SEvan Yan } 1887*26947304SEvan Yan 1888*26947304SEvan Yan if (entry->io_len > 0) { 1889*26947304SEvan Yan range[0].size_lo = entry->io_last - entry->io_base; 1890*26947304SEvan Yan if (pcicfg_update_ranges_prop(dip, &range[0])) { 1891*26947304SEvan Yan DEBUG0("Failed to update ranges (i/o)\n"); 1892*26947304SEvan Yan entry->error = PCICFG_FAILURE; 1893*26947304SEvan Yan return (DDI_WALK_TERMINATE); 1894*26947304SEvan Yan } 1895*26947304SEvan Yan } 1896*26947304SEvan Yan if (entry->memory_len > 0) { 1897*26947304SEvan Yan range[1].size_lo = 1898*26947304SEvan Yan entry->memory_last - entry->memory_base; 1899*26947304SEvan Yan if (pcicfg_update_ranges_prop(dip, &range[1])) { 1900*26947304SEvan Yan DEBUG0("Failed to update ranges (memory)\n"); 1901*26947304SEvan Yan entry->error = PCICFG_FAILURE; 1902*26947304SEvan Yan return (DDI_WALK_TERMINATE); 1903*26947304SEvan Yan } 1904*26947304SEvan Yan } 1905*26947304SEvan Yan 1906*26947304SEvan Yan (void) pcicfg_device_on(handle); 1907*26947304SEvan Yan 1908*26947304SEvan Yan PCICFG_DUMP_BRIDGE_CONFIG(handle); 1909*26947304SEvan Yan 1910*26947304SEvan Yan return (DDI_WALK_PRUNECHILD); 1911*26947304SEvan Yan } 1912*26947304SEvan Yan 1913*26947304SEvan Yan /* 1914*26947304SEvan Yan * If there is an interrupt pin set program 1915*26947304SEvan Yan * interrupt line with default values. 1916*26947304SEvan Yan */ 1917*26947304SEvan Yan if (pci_config_get8(handle, PCI_CONF_IPIN)) { 1918*26947304SEvan Yan pci_config_put8(handle, PCI_CONF_ILINE, 0xf); 1919*26947304SEvan Yan } 1920*26947304SEvan Yan 1921*26947304SEvan Yan /* 1922*26947304SEvan Yan * A single device (under a bridge). 1923*26947304SEvan Yan * For each "reg" property with a length, allocate memory 1924*26947304SEvan Yan * and program the base registers. 1925*26947304SEvan Yan */ 1926*26947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 1927*26947304SEvan Yan DDI_PROP_DONTPASS, "reg", (caddr_t)®, 1928*26947304SEvan Yan &length) != DDI_PROP_SUCCESS) { 1929*26947304SEvan Yan DEBUG0("Failed to read reg property\n"); 1930*26947304SEvan Yan entry->error = PCICFG_FAILURE; 1931*26947304SEvan Yan return (DDI_WALK_TERMINATE); 1932*26947304SEvan Yan } 1933*26947304SEvan Yan 1934*26947304SEvan Yan rcount = length / sizeof (pci_regspec_t); 1935*26947304SEvan Yan offset = PCI_CONF_BASE0; 1936*26947304SEvan Yan for (i = 0; i < rcount; i++) { 1937*26947304SEvan Yan if ((reg[i].pci_size_low != 0)|| 1938*26947304SEvan Yan (reg[i].pci_size_hi != 0)) { 1939*26947304SEvan Yan 1940*26947304SEvan Yan offset = PCI_REG_REG_G(reg[i].pci_phys_hi); 1941*26947304SEvan Yan 1942*26947304SEvan Yan switch (PCI_REG_ADDR_G(reg[i].pci_phys_hi)) { 1943*26947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_MEM64): 1944*26947304SEvan Yan 1945*26947304SEvan Yan (void) pcicfg_get_mem(entry, 1946*26947304SEvan Yan reg[i].pci_size_low, &mem_answer); 1947*26947304SEvan Yan pci_config_put64(handle, offset, mem_answer); 1948*26947304SEvan Yan DEBUG2("REGISTER off %x (64)LO ----> [0x%x]\n", 1949*26947304SEvan Yan offset, 1950*26947304SEvan Yan pci_config_get32(handle, offset)); 1951*26947304SEvan Yan DEBUG2("REGISTER off %x (64)HI ----> [0x%x]\n", 1952*26947304SEvan Yan offset + 4, 1953*26947304SEvan Yan pci_config_get32(handle, offset + 4)); 1954*26947304SEvan Yan 1955*26947304SEvan Yan reg[i].pci_phys_low = PCICFG_HIADDR(mem_answer); 1956*26947304SEvan Yan reg[i].pci_phys_mid = 1957*26947304SEvan Yan PCICFG_LOADDR(mem_answer); 1958*26947304SEvan Yan 1959*26947304SEvan Yan break; 1960*26947304SEvan Yan 1961*26947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_MEM32): 1962*26947304SEvan Yan /* allocate memory space from the allocator */ 1963*26947304SEvan Yan 1964*26947304SEvan Yan (void) pcicfg_get_mem(entry, 1965*26947304SEvan Yan reg[i].pci_size_low, &mem_answer); 1966*26947304SEvan Yan pci_config_put32(handle, 1967*26947304SEvan Yan offset, (uint32_t)mem_answer); 1968*26947304SEvan Yan 1969*26947304SEvan Yan DEBUG2("REGISTER off %x(32)LO ----> [0x%x]\n", 1970*26947304SEvan Yan offset, 1971*26947304SEvan Yan pci_config_get32(handle, offset)); 1972*26947304SEvan Yan 1973*26947304SEvan Yan reg[i].pci_phys_low = (uint32_t)mem_answer; 1974*26947304SEvan Yan 1975*26947304SEvan Yan break; 1976*26947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_IO): 1977*26947304SEvan Yan /* allocate I/O space from the allocator */ 1978*26947304SEvan Yan 1979*26947304SEvan Yan (void) pcicfg_get_io(entry, 1980*26947304SEvan Yan reg[i].pci_size_low, &io_answer); 1981*26947304SEvan Yan pci_config_put32(handle, offset, io_answer); 1982*26947304SEvan Yan 1983*26947304SEvan Yan DEBUG2("REGISTER off %x (I/O)LO ----> [0x%x]\n", 1984*26947304SEvan Yan offset, 1985*26947304SEvan Yan pci_config_get32(handle, offset)); 1986*26947304SEvan Yan 1987*26947304SEvan Yan reg[i].pci_phys_low = io_answer; 1988*26947304SEvan Yan 1989*26947304SEvan Yan break; 1990*26947304SEvan Yan default: 1991*26947304SEvan Yan DEBUG0("Unknown register type\n"); 1992*26947304SEvan Yan kmem_free(reg, length); 1993*26947304SEvan Yan (void) pcicfg_config_teardown(&handle); 1994*26947304SEvan Yan entry->error = PCICFG_FAILURE; 1995*26947304SEvan Yan return (DDI_WALK_TERMINATE); 1996*26947304SEvan Yan } /* switch */ 1997*26947304SEvan Yan 1998*26947304SEvan Yan /* 1999*26947304SEvan Yan * Now that memory locations are assigned, 2000*26947304SEvan Yan * update the assigned address property. 2001*26947304SEvan Yan */ 2002*26947304SEvan Yan if (pcicfg_update_assigned_prop(dip, 2003*26947304SEvan Yan ®[i]) != PCICFG_SUCCESS) { 2004*26947304SEvan Yan kmem_free(reg, length); 2005*26947304SEvan Yan (void) pcicfg_config_teardown(&handle); 2006*26947304SEvan Yan entry->error = PCICFG_FAILURE; 2007*26947304SEvan Yan return (DDI_WALK_TERMINATE); 2008*26947304SEvan Yan } 2009*26947304SEvan Yan } 2010*26947304SEvan Yan } 2011*26947304SEvan Yan (void) pcicfg_device_on(handle); 2012*26947304SEvan Yan 2013*26947304SEvan Yan PCICFG_DUMP_DEVICE_CONFIG(handle); 2014*26947304SEvan Yan 2015*26947304SEvan Yan (void) pcicfg_config_teardown(&handle); 2016*26947304SEvan Yan /* 2017*26947304SEvan Yan * Don't forget to free up memory from ddi_getlongprop 2018*26947304SEvan Yan */ 2019*26947304SEvan Yan kmem_free((caddr_t)reg, length); 2020*26947304SEvan Yan 2021*26947304SEvan Yan return (DDI_WALK_CONTINUE); 2022*26947304SEvan Yan } 2023*26947304SEvan Yan 2024*26947304SEvan Yan static int 2025*26947304SEvan Yan pcicfg_device_assign(dev_info_t *dip) 2026*26947304SEvan Yan { 2027*26947304SEvan Yan ddi_acc_handle_t handle; 2028*26947304SEvan Yan pci_regspec_t *reg; 2029*26947304SEvan Yan int length; 2030*26947304SEvan Yan int rcount; 2031*26947304SEvan Yan int i; 2032*26947304SEvan Yan int offset; 2033*26947304SEvan Yan ndi_ra_request_t request; 2034*26947304SEvan Yan uint64_t answer; 2035*26947304SEvan Yan uint64_t alen; 2036*26947304SEvan Yan 2037*26947304SEvan Yan DEBUG1("%llx now under configuration\n", dip); 2038*26947304SEvan Yan 2039*26947304SEvan Yan /* 2040*26947304SEvan Yan * XXX Failure here should be noted 2041*26947304SEvan Yan */ 2042*26947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 2043*26947304SEvan Yan DDI_PROP_DONTPASS, "reg", (caddr_t)®, 2044*26947304SEvan Yan &length) != DDI_PROP_SUCCESS) { 2045*26947304SEvan Yan DEBUG0("Failed to read reg property\n"); 2046*26947304SEvan Yan return (PCICFG_FAILURE); 2047*26947304SEvan Yan } 2048*26947304SEvan Yan 2049*26947304SEvan Yan if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) { 2050*26947304SEvan Yan DEBUG0("Failed to map config space!\n"); 2051*26947304SEvan Yan /* 2052*26947304SEvan Yan * Don't forget to free up memory from ddi_getlongprop 2053*26947304SEvan Yan */ 2054*26947304SEvan Yan kmem_free((caddr_t)reg, length); 2055*26947304SEvan Yan 2056*26947304SEvan Yan return (PCICFG_FAILURE); 2057*26947304SEvan Yan } 2058*26947304SEvan Yan 2059*26947304SEvan Yan /* 2060*26947304SEvan Yan * A single device 2061*26947304SEvan Yan * 2062*26947304SEvan Yan * For each "reg" property with a length, allocate memory 2063*26947304SEvan Yan * and program the base registers. 2064*26947304SEvan Yan */ 2065*26947304SEvan Yan 2066*26947304SEvan Yan /* 2067*26947304SEvan Yan * If there is an interrupt pin set program 2068*26947304SEvan Yan * interrupt line with default values. 2069*26947304SEvan Yan */ 2070*26947304SEvan Yan if (pci_config_get8(handle, PCI_CONF_IPIN)) { 2071*26947304SEvan Yan pci_config_put8(handle, PCI_CONF_ILINE, 0xf); 2072*26947304SEvan Yan } 2073*26947304SEvan Yan 2074*26947304SEvan Yan bzero((caddr_t)&request, sizeof (ndi_ra_request_t)); 2075*26947304SEvan Yan 2076*26947304SEvan Yan request.ra_flags |= NDI_RA_ALIGN_SIZE; 2077*26947304SEvan Yan request.ra_boundbase = 0; 2078*26947304SEvan Yan request.ra_boundlen = PCICFG_4GIG_LIMIT; 2079*26947304SEvan Yan 2080*26947304SEvan Yan rcount = length / sizeof (pci_regspec_t); 2081*26947304SEvan Yan offset = PCI_CONF_BASE0; 2082*26947304SEvan Yan for (i = 0; i < rcount; i++) { 2083*26947304SEvan Yan if ((reg[i].pci_size_low != 0)|| 2084*26947304SEvan Yan (reg[i].pci_size_hi != 0)) { 2085*26947304SEvan Yan 2086*26947304SEvan Yan offset = PCI_REG_REG_G(reg[i].pci_phys_hi); 2087*26947304SEvan Yan request.ra_len = reg[i].pci_size_low; 2088*26947304SEvan Yan 2089*26947304SEvan Yan switch (PCI_REG_ADDR_G(reg[i].pci_phys_hi)) { 2090*26947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_MEM64): 2091*26947304SEvan Yan request.ra_flags ^= NDI_RA_ALLOC_BOUNDED; 2092*26947304SEvan Yan /* allocate memory space from the allocator */ 2093*26947304SEvan Yan if (ndi_ra_alloc(ddi_get_parent(dip), 2094*26947304SEvan Yan &request, &answer, &alen, 2095*26947304SEvan Yan NDI_RA_TYPE_MEM, NDI_RA_PASS) 2096*26947304SEvan Yan != NDI_SUCCESS) { 2097*26947304SEvan Yan DEBUG0("Failed to allocate 64b mem\n"); 2098*26947304SEvan Yan kmem_free(reg, length); 2099*26947304SEvan Yan (void) pcicfg_config_teardown(&handle); 2100*26947304SEvan Yan return (PCICFG_FAILURE); 2101*26947304SEvan Yan } 2102*26947304SEvan Yan DEBUG3("64 addr = [0x%x.%x] len [0x%x]\n", 2103*26947304SEvan Yan PCICFG_HIADDR(answer), 2104*26947304SEvan Yan PCICFG_LOADDR(answer), 2105*26947304SEvan Yan alen); 2106*26947304SEvan Yan /* program the low word */ 2107*26947304SEvan Yan pci_config_put32(handle, 2108*26947304SEvan Yan offset, PCICFG_LOADDR(answer)); 2109*26947304SEvan Yan 2110*26947304SEvan Yan /* program the high word with value zero */ 2111*26947304SEvan Yan pci_config_put32(handle, offset + 4, 2112*26947304SEvan Yan PCICFG_HIADDR(answer)); 2113*26947304SEvan Yan 2114*26947304SEvan Yan reg[i].pci_phys_low = PCICFG_LOADDR(answer); 2115*26947304SEvan Yan reg[i].pci_phys_mid = PCICFG_HIADDR(answer); 2116*26947304SEvan Yan /* 2117*26947304SEvan Yan * currently support 32b address space 2118*26947304SEvan Yan * assignments only. 2119*26947304SEvan Yan */ 2120*26947304SEvan Yan reg[i].pci_phys_hi ^= PCI_ADDR_MEM64 ^ 2121*26947304SEvan Yan PCI_ADDR_MEM32; 2122*26947304SEvan Yan 2123*26947304SEvan Yan offset += 8; 2124*26947304SEvan Yan break; 2125*26947304SEvan Yan 2126*26947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_MEM32): 2127*26947304SEvan Yan request.ra_flags |= NDI_RA_ALLOC_BOUNDED; 2128*26947304SEvan Yan /* allocate memory space from the allocator */ 2129*26947304SEvan Yan if (ndi_ra_alloc(ddi_get_parent(dip), 2130*26947304SEvan Yan &request, &answer, &alen, 2131*26947304SEvan Yan NDI_RA_TYPE_MEM, NDI_RA_PASS) 2132*26947304SEvan Yan != NDI_SUCCESS) { 2133*26947304SEvan Yan DEBUG0("Failed to allocate 32b mem\n"); 2134*26947304SEvan Yan kmem_free(reg, length); 2135*26947304SEvan Yan (void) pcicfg_config_teardown(&handle); 2136*26947304SEvan Yan return (PCICFG_FAILURE); 2137*26947304SEvan Yan } 2138*26947304SEvan Yan DEBUG3("32 addr = [0x%x.%x] len [0x%x]\n", 2139*26947304SEvan Yan PCICFG_HIADDR(answer), 2140*26947304SEvan Yan PCICFG_LOADDR(answer), 2141*26947304SEvan Yan alen); 2142*26947304SEvan Yan /* program the low word */ 2143*26947304SEvan Yan pci_config_put32(handle, 2144*26947304SEvan Yan offset, PCICFG_LOADDR(answer)); 2145*26947304SEvan Yan 2146*26947304SEvan Yan reg[i].pci_phys_low = PCICFG_LOADDR(answer); 2147*26947304SEvan Yan 2148*26947304SEvan Yan offset += 4; 2149*26947304SEvan Yan break; 2150*26947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_IO): 2151*26947304SEvan Yan /* allocate I/O space from the allocator */ 2152*26947304SEvan Yan request.ra_flags |= NDI_RA_ALLOC_BOUNDED; 2153*26947304SEvan Yan if (ndi_ra_alloc(ddi_get_parent(dip), 2154*26947304SEvan Yan &request, &answer, &alen, 2155*26947304SEvan Yan NDI_RA_TYPE_IO, NDI_RA_PASS) 2156*26947304SEvan Yan != NDI_SUCCESS) { 2157*26947304SEvan Yan DEBUG0("Failed to allocate I/O\n"); 2158*26947304SEvan Yan kmem_free(reg, length); 2159*26947304SEvan Yan (void) pcicfg_config_teardown(&handle); 2160*26947304SEvan Yan return (PCICFG_FAILURE); 2161*26947304SEvan Yan } 2162*26947304SEvan Yan DEBUG3("I/O addr = [0x%x.%x] len [0x%x]\n", 2163*26947304SEvan Yan PCICFG_HIADDR(answer), 2164*26947304SEvan Yan PCICFG_LOADDR(answer), 2165*26947304SEvan Yan alen); 2166*26947304SEvan Yan pci_config_put32(handle, 2167*26947304SEvan Yan offset, PCICFG_LOADDR(answer)); 2168*26947304SEvan Yan 2169*26947304SEvan Yan reg[i].pci_phys_low = PCICFG_LOADDR(answer); 2170*26947304SEvan Yan 2171*26947304SEvan Yan offset += 4; 2172*26947304SEvan Yan break; 2173*26947304SEvan Yan default: 2174*26947304SEvan Yan DEBUG0("Unknown register type\n"); 2175*26947304SEvan Yan kmem_free(reg, length); 2176*26947304SEvan Yan (void) pcicfg_config_teardown(&handle); 2177*26947304SEvan Yan return (PCICFG_FAILURE); 2178*26947304SEvan Yan } /* switch */ 2179*26947304SEvan Yan 2180*26947304SEvan Yan /* 2181*26947304SEvan Yan * Now that memory locations are assigned, 2182*26947304SEvan Yan * update the assigned address property. 2183*26947304SEvan Yan */ 2184*26947304SEvan Yan 2185*26947304SEvan Yan if (pcicfg_update_assigned_prop(dip, 2186*26947304SEvan Yan ®[i]) != PCICFG_SUCCESS) { 2187*26947304SEvan Yan kmem_free(reg, length); 2188*26947304SEvan Yan (void) pcicfg_config_teardown(&handle); 2189*26947304SEvan Yan return (PCICFG_FAILURE); 2190*26947304SEvan Yan } 2191*26947304SEvan Yan } 2192*26947304SEvan Yan } 2193*26947304SEvan Yan 2194*26947304SEvan Yan (void) pcicfg_device_on(handle); 2195*26947304SEvan Yan kmem_free(reg, length); 2196*26947304SEvan Yan 2197*26947304SEvan Yan PCICFG_DUMP_DEVICE_CONFIG(handle); 2198*26947304SEvan Yan 2199*26947304SEvan Yan (void) pcicfg_config_teardown(&handle); 2200*26947304SEvan Yan return (PCICFG_SUCCESS); 2201*26947304SEvan Yan } 2202*26947304SEvan Yan 2203*26947304SEvan Yan static int 2204*26947304SEvan Yan pcicfg_device_assign_readonly(dev_info_t *dip) 2205*26947304SEvan Yan { 2206*26947304SEvan Yan ddi_acc_handle_t handle; 2207*26947304SEvan Yan pci_regspec_t *assigned; 2208*26947304SEvan Yan int length; 2209*26947304SEvan Yan int acount; 2210*26947304SEvan Yan int i; 2211*26947304SEvan Yan ndi_ra_request_t request; 2212*26947304SEvan Yan uint64_t answer; 2213*26947304SEvan Yan uint64_t alen; 2214*26947304SEvan Yan 2215*26947304SEvan Yan 2216*26947304SEvan Yan DEBUG1("%llx now under configuration\n", dip); 2217*26947304SEvan Yan 2218*26947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 2219*26947304SEvan Yan DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned, 2220*26947304SEvan Yan &length) != DDI_PROP_SUCCESS) { 2221*26947304SEvan Yan DEBUG0("Failed to read assigned-addresses property\n"); 2222*26947304SEvan Yan return (PCICFG_FAILURE); 2223*26947304SEvan Yan } 2224*26947304SEvan Yan 2225*26947304SEvan Yan if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) { 2226*26947304SEvan Yan DEBUG0("Failed to map config space!\n"); 2227*26947304SEvan Yan /* 2228*26947304SEvan Yan * Don't forget to free up memory from ddi_getlongprop 2229*26947304SEvan Yan */ 2230*26947304SEvan Yan kmem_free((caddr_t)assigned, length); 2231*26947304SEvan Yan 2232*26947304SEvan Yan return (PCICFG_FAILURE); 2233*26947304SEvan Yan } 2234*26947304SEvan Yan 2235*26947304SEvan Yan /* 2236*26947304SEvan Yan * For each "assigned-addresses" property entry with a length, 2237*26947304SEvan Yan * call the memory allocation routines to return the 2238*26947304SEvan Yan * resource. 2239*26947304SEvan Yan */ 2240*26947304SEvan Yan /* 2241*26947304SEvan Yan * If there is an interrupt pin set program 2242*26947304SEvan Yan * interrupt line with default values. 2243*26947304SEvan Yan */ 2244*26947304SEvan Yan if (pci_config_get8(handle, PCI_CONF_IPIN)) { 2245*26947304SEvan Yan pci_config_put8(handle, PCI_CONF_ILINE, 0xf); 2246*26947304SEvan Yan } 2247*26947304SEvan Yan 2248*26947304SEvan Yan bzero((caddr_t)&request, sizeof (ndi_ra_request_t)); 2249*26947304SEvan Yan 2250*26947304SEvan Yan request.ra_flags = NDI_RA_ALLOC_SPECIFIED; /* specified addr */ 2251*26947304SEvan Yan request.ra_boundbase = 0; 2252*26947304SEvan Yan request.ra_boundlen = PCICFG_4GIG_LIMIT; 2253*26947304SEvan Yan 2254*26947304SEvan Yan acount = length / sizeof (pci_regspec_t); 2255*26947304SEvan Yan for (i = 0; i < acount; i++) { 2256*26947304SEvan Yan if ((assigned[i].pci_size_low != 0)|| 2257*26947304SEvan Yan (assigned[i].pci_size_hi != 0)) { 2258*26947304SEvan Yan 2259*26947304SEvan Yan request.ra_len = assigned[i].pci_size_low; 2260*26947304SEvan Yan 2261*26947304SEvan Yan switch (PCI_REG_ADDR_G(assigned[i].pci_phys_hi)) { 2262*26947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_MEM64): 2263*26947304SEvan Yan request.ra_addr = (uint64_t)PCICFG_LADDR( 2264*26947304SEvan Yan assigned[i].pci_phys_low, 2265*26947304SEvan Yan assigned[i].pci_phys_mid); 2266*26947304SEvan Yan 2267*26947304SEvan Yan /* allocate memory space from the allocator */ 2268*26947304SEvan Yan if (ndi_ra_alloc(ddi_get_parent(dip), 2269*26947304SEvan Yan &request, &answer, &alen, 2270*26947304SEvan Yan NDI_RA_TYPE_MEM, NDI_RA_PASS) 2271*26947304SEvan Yan != NDI_SUCCESS) { 2272*26947304SEvan Yan DEBUG0("Failed to allocate 64b mem\n"); 2273*26947304SEvan Yan kmem_free(assigned, length); 2274*26947304SEvan Yan return (PCICFG_FAILURE); 2275*26947304SEvan Yan } 2276*26947304SEvan Yan 2277*26947304SEvan Yan break; 2278*26947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_MEM32): 2279*26947304SEvan Yan request.ra_addr = (uint64_t) 2280*26947304SEvan Yan assigned[i].pci_phys_low; 2281*26947304SEvan Yan 2282*26947304SEvan Yan /* allocate memory space from the allocator */ 2283*26947304SEvan Yan if (ndi_ra_alloc(ddi_get_parent(dip), 2284*26947304SEvan Yan &request, &answer, &alen, 2285*26947304SEvan Yan NDI_RA_TYPE_MEM, NDI_RA_PASS) 2286*26947304SEvan Yan != NDI_SUCCESS) { 2287*26947304SEvan Yan DEBUG0("Failed to allocate 32b mem\n"); 2288*26947304SEvan Yan kmem_free(assigned, length); 2289*26947304SEvan Yan return (PCICFG_FAILURE); 2290*26947304SEvan Yan } 2291*26947304SEvan Yan 2292*26947304SEvan Yan break; 2293*26947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_IO): 2294*26947304SEvan Yan request.ra_addr = (uint64_t) 2295*26947304SEvan Yan assigned[i].pci_phys_low; 2296*26947304SEvan Yan 2297*26947304SEvan Yan /* allocate I/O space from the allocator */ 2298*26947304SEvan Yan if (ndi_ra_alloc(ddi_get_parent(dip), 2299*26947304SEvan Yan &request, &answer, &alen, 2300*26947304SEvan Yan NDI_RA_TYPE_IO, NDI_RA_PASS) 2301*26947304SEvan Yan != NDI_SUCCESS) { 2302*26947304SEvan Yan DEBUG0("Failed to allocate I/O\n"); 2303*26947304SEvan Yan kmem_free(assigned, length); 2304*26947304SEvan Yan return (PCICFG_FAILURE); 2305*26947304SEvan Yan } 2306*26947304SEvan Yan 2307*26947304SEvan Yan break; 2308*26947304SEvan Yan default: 2309*26947304SEvan Yan DEBUG0("Unknown register type\n"); 2310*26947304SEvan Yan kmem_free(assigned, length); 2311*26947304SEvan Yan return (PCICFG_FAILURE); 2312*26947304SEvan Yan } /* switch */ 2313*26947304SEvan Yan } 2314*26947304SEvan Yan } 2315*26947304SEvan Yan 2316*26947304SEvan Yan (void) pcicfg_device_on(handle); 2317*26947304SEvan Yan kmem_free(assigned, length); 2318*26947304SEvan Yan 2319*26947304SEvan Yan PCICFG_DUMP_DEVICE_CONFIG(handle); 2320*26947304SEvan Yan 2321*26947304SEvan Yan (void) pcicfg_config_teardown(&handle); 2322*26947304SEvan Yan return (PCICFG_SUCCESS); 2323*26947304SEvan Yan } 2324*26947304SEvan Yan 2325*26947304SEvan Yan /* 2326*26947304SEvan Yan * The "dip" passed to this routine is assumed to be 2327*26947304SEvan Yan * the device at the Hotplug Connection (CN). Currently it is 2328*26947304SEvan Yan * assumed to be a bridge. 2329*26947304SEvan Yan */ 2330*26947304SEvan Yan static int 2331*26947304SEvan Yan pcicfg_allocate_chunk(dev_info_t *dip) 2332*26947304SEvan Yan { 2333*26947304SEvan Yan pcicfg_phdl_t *phdl; 2334*26947304SEvan Yan ndi_ra_request_t *mem_request; 2335*26947304SEvan Yan ndi_ra_request_t *io_request; 2336*26947304SEvan Yan uint64_t mem_answer; 2337*26947304SEvan Yan uint64_t io_answer; 2338*26947304SEvan Yan int count; 2339*26947304SEvan Yan uint64_t alen; 2340*26947304SEvan Yan 2341*26947304SEvan Yan /* 2342*26947304SEvan Yan * This should not find an existing entry - so 2343*26947304SEvan Yan * it will create a new one. 2344*26947304SEvan Yan */ 2345*26947304SEvan Yan phdl = pcicfg_find_phdl(dip); 2346*26947304SEvan Yan ASSERT(phdl); 2347*26947304SEvan Yan 2348*26947304SEvan Yan mem_request = &phdl->mem_req; 2349*26947304SEvan Yan io_request = &phdl->io_req; 2350*26947304SEvan Yan 2351*26947304SEvan Yan /* 2352*26947304SEvan Yan * From this point in the tree - walk the devices, 2353*26947304SEvan Yan * The function passed in will read and "sum" up 2354*26947304SEvan Yan * the memory and I/O requirements and put them in 2355*26947304SEvan Yan * structure "phdl". 2356*26947304SEvan Yan */ 2357*26947304SEvan Yan ndi_devi_enter(ddi_get_parent(dip), &count); 2358*26947304SEvan Yan ddi_walk_devs(dip, pcicfg_sum_resources, (void *)phdl); 2359*26947304SEvan Yan ndi_devi_exit(ddi_get_parent(dip), count); 2360*26947304SEvan Yan 2361*26947304SEvan Yan if (phdl->error != PCICFG_SUCCESS) { 2362*26947304SEvan Yan DEBUG0("Failure summing resources\n"); 2363*26947304SEvan Yan return (phdl->error); 2364*26947304SEvan Yan } 2365*26947304SEvan Yan 2366*26947304SEvan Yan /* 2367*26947304SEvan Yan * Call into the memory allocator with the request. 2368*26947304SEvan Yan * Record the addresses returned in the phdl 2369*26947304SEvan Yan */ 2370*26947304SEvan Yan DEBUG1("Connector requires [0x%x] bytes of memory space\n", 2371*26947304SEvan Yan mem_request->ra_len); 2372*26947304SEvan Yan DEBUG1("Connector requires [0x%x] bytes of I/O space\n", 2373*26947304SEvan Yan io_request->ra_len); 2374*26947304SEvan Yan 2375*26947304SEvan Yan mem_request->ra_align_mask = 2376*26947304SEvan Yan PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */ 2377*26947304SEvan Yan io_request->ra_align_mask = 2378*26947304SEvan Yan PCICFG_IOGRAN - 1; /* 4K alignment on I/O space */ 2379*26947304SEvan Yan io_request->ra_boundbase = 0; 2380*26947304SEvan Yan io_request->ra_boundlen = PCICFG_4GIG_LIMIT; 2381*26947304SEvan Yan io_request->ra_flags |= NDI_RA_ALLOC_BOUNDED; 2382*26947304SEvan Yan 2383*26947304SEvan Yan mem_request->ra_len = 2384*26947304SEvan Yan PCICFG_ROUND_UP(mem_request->ra_len, PCICFG_MEMGRAN); 2385*26947304SEvan Yan 2386*26947304SEvan Yan io_request->ra_len = 2387*26947304SEvan Yan PCICFG_ROUND_UP(io_request->ra_len, PCICFG_IOGRAN); 2388*26947304SEvan Yan 2389*26947304SEvan Yan if (ndi_ra_alloc(ddi_get_parent(dip), 2390*26947304SEvan Yan mem_request, &mem_answer, &alen, 2391*26947304SEvan Yan NDI_RA_TYPE_MEM, NDI_RA_PASS) != NDI_SUCCESS) { 2392*26947304SEvan Yan DEBUG0("Failed to allocate memory\n"); 2393*26947304SEvan Yan return (PCICFG_FAILURE); 2394*26947304SEvan Yan } 2395*26947304SEvan Yan 2396*26947304SEvan Yan phdl->memory_base = phdl->memory_last = mem_answer; 2397*26947304SEvan Yan phdl->memory_len = alen; 2398*26947304SEvan Yan 2399*26947304SEvan Yan phdl->mem_hole.start = phdl->memory_base; 2400*26947304SEvan Yan phdl->mem_hole.len = phdl->memory_len; 2401*26947304SEvan Yan phdl->mem_hole.next = (hole_t *)NULL; 2402*26947304SEvan Yan 2403*26947304SEvan Yan if (ndi_ra_alloc(ddi_get_parent(dip), io_request, &io_answer, 2404*26947304SEvan Yan &alen, NDI_RA_TYPE_IO, NDI_RA_PASS) != NDI_SUCCESS) { 2405*26947304SEvan Yan 2406*26947304SEvan Yan DEBUG0("Failed to allocate I/O space\n"); 2407*26947304SEvan Yan (void) ndi_ra_free(ddi_get_parent(dip), mem_answer, 2408*26947304SEvan Yan alen, NDI_RA_TYPE_MEM, NDI_RA_PASS); 2409*26947304SEvan Yan phdl->memory_len = phdl->io_len = 0; 2410*26947304SEvan Yan return (PCICFG_FAILURE); 2411*26947304SEvan Yan } 2412*26947304SEvan Yan 2413*26947304SEvan Yan phdl->io_base = phdl->io_last = (uint32_t)io_answer; 2414*26947304SEvan Yan phdl->io_len = (uint32_t)alen; 2415*26947304SEvan Yan 2416*26947304SEvan Yan phdl->io_hole.start = phdl->io_base; 2417*26947304SEvan Yan phdl->io_hole.len = phdl->io_len; 2418*26947304SEvan Yan phdl->io_hole.next = (hole_t *)NULL; 2419*26947304SEvan Yan 2420*26947304SEvan Yan DEBUG2("MEMORY BASE = [0x%x] length [0x%x]\n", 2421*26947304SEvan Yan phdl->memory_base, phdl->memory_len); 2422*26947304SEvan Yan DEBUG2("IO BASE = [0x%x] length [0x%x]\n", 2423*26947304SEvan Yan phdl->io_base, phdl->io_len); 2424*26947304SEvan Yan 2425*26947304SEvan Yan return (PCICFG_SUCCESS); 2426*26947304SEvan Yan } 2427*26947304SEvan Yan 2428*26947304SEvan Yan #ifdef DEBUG 2429*26947304SEvan Yan /* 2430*26947304SEvan Yan * This function is useful in debug mode, where we can measure how 2431*26947304SEvan Yan * much memory was wasted/unallocated in bridge device's domain. 2432*26947304SEvan Yan */ 2433*26947304SEvan Yan static uint64_t 2434*26947304SEvan Yan pcicfg_unused_space(hole_t *hole, uint32_t *hole_count) 2435*26947304SEvan Yan { 2436*26947304SEvan Yan uint64_t len = 0; 2437*26947304SEvan Yan uint32_t count = 0; 2438*26947304SEvan Yan 2439*26947304SEvan Yan do { 2440*26947304SEvan Yan len += hole->len; 2441*26947304SEvan Yan hole = hole->next; 2442*26947304SEvan Yan count++; 2443*26947304SEvan Yan } while (hole); 2444*26947304SEvan Yan *hole_count = count; 2445*26947304SEvan Yan return (len); 2446*26947304SEvan Yan } 2447*26947304SEvan Yan #endif 2448*26947304SEvan Yan 2449*26947304SEvan Yan /* 2450*26947304SEvan Yan * This function frees data structures that hold the hole information 2451*26947304SEvan Yan * which are allocated in pcicfg_alloc_hole(). This is not freeing 2452*26947304SEvan Yan * any memory allocated through NDI calls. 2453*26947304SEvan Yan */ 2454*26947304SEvan Yan static void 2455*26947304SEvan Yan pcicfg_free_hole(hole_t *addr_hole) 2456*26947304SEvan Yan { 2457*26947304SEvan Yan hole_t *nhole, *hole = addr_hole->next; 2458*26947304SEvan Yan 2459*26947304SEvan Yan while (hole) { 2460*26947304SEvan Yan nhole = hole->next; 2461*26947304SEvan Yan kmem_free(hole, sizeof (hole_t)); 2462*26947304SEvan Yan hole = nhole; 2463*26947304SEvan Yan } 2464*26947304SEvan Yan } 2465*26947304SEvan Yan 2466*26947304SEvan Yan static uint64_t 2467*26947304SEvan Yan pcicfg_alloc_hole(hole_t *addr_hole, uint64_t *alast, uint32_t length) 2468*26947304SEvan Yan { 2469*26947304SEvan Yan uint64_t actual_hole_start, ostart, olen; 2470*26947304SEvan Yan hole_t *hole = addr_hole, *thole, *nhole; 2471*26947304SEvan Yan 2472*26947304SEvan Yan do { 2473*26947304SEvan Yan actual_hole_start = PCICFG_ROUND_UP(hole->start, length); 2474*26947304SEvan Yan if (((actual_hole_start - hole->start) + length) <= hole->len) { 2475*26947304SEvan Yan DEBUG3("hole found. start %llx, len %llx, req=%x\n", 2476*26947304SEvan Yan hole->start, hole->len, length); 2477*26947304SEvan Yan ostart = hole->start; 2478*26947304SEvan Yan olen = hole->len; 2479*26947304SEvan Yan /* current hole parameters adjust */ 2480*26947304SEvan Yan if ((actual_hole_start - hole->start) == 0) { 2481*26947304SEvan Yan hole->start += length; 2482*26947304SEvan Yan hole->len -= length; 2483*26947304SEvan Yan if (hole->start > *alast) 2484*26947304SEvan Yan *alast = hole->start; 2485*26947304SEvan Yan } else { 2486*26947304SEvan Yan hole->len = actual_hole_start - hole->start; 2487*26947304SEvan Yan nhole = (hole_t *)kmem_zalloc(sizeof (hole_t), 2488*26947304SEvan Yan KM_SLEEP); 2489*26947304SEvan Yan nhole->start = actual_hole_start + length; 2490*26947304SEvan Yan nhole->len = (ostart + olen) - nhole->start; 2491*26947304SEvan Yan nhole->next = NULL; 2492*26947304SEvan Yan thole = hole->next; 2493*26947304SEvan Yan hole->next = nhole; 2494*26947304SEvan Yan nhole->next = thole; 2495*26947304SEvan Yan if (nhole->start > *alast) 2496*26947304SEvan Yan *alast = nhole->start; 2497*26947304SEvan Yan DEBUG2("put new hole to %llx, %llx\n", 2498*26947304SEvan Yan nhole->start, nhole->len); 2499*26947304SEvan Yan } 2500*26947304SEvan Yan DEBUG2("adjust current hole to %llx, %llx\n", 2501*26947304SEvan Yan hole->start, hole->len); 2502*26947304SEvan Yan break; 2503*26947304SEvan Yan } 2504*26947304SEvan Yan actual_hole_start = 0; 2505*26947304SEvan Yan hole = hole->next; 2506*26947304SEvan Yan } while (hole); 2507*26947304SEvan Yan 2508*26947304SEvan Yan DEBUG1("return hole at %llx\n", actual_hole_start); 2509*26947304SEvan Yan return (actual_hole_start); 2510*26947304SEvan Yan } 2511*26947304SEvan Yan 2512*26947304SEvan Yan static void 2513*26947304SEvan Yan pcicfg_get_mem(pcicfg_phdl_t *entry, 2514*26947304SEvan Yan uint32_t length, uint64_t *ans) 2515*26947304SEvan Yan { 2516*26947304SEvan Yan uint64_t new_mem; 2517*26947304SEvan Yan 2518*26947304SEvan Yan /* See if there is a hole, that can hold this request. */ 2519*26947304SEvan Yan new_mem = pcicfg_alloc_hole(&entry->mem_hole, &entry->memory_last, 2520*26947304SEvan Yan length); 2521*26947304SEvan Yan if (new_mem) { /* if non-zero, found a hole. */ 2522*26947304SEvan Yan if (ans != NULL) 2523*26947304SEvan Yan *ans = new_mem; 2524*26947304SEvan Yan } else 2525*26947304SEvan Yan cmn_err(CE_WARN, "No %u bytes memory window for %s\n", 2526*26947304SEvan Yan length, ddi_get_name(entry->dip)); 2527*26947304SEvan Yan } 2528*26947304SEvan Yan 2529*26947304SEvan Yan static void 2530*26947304SEvan Yan pcicfg_get_io(pcicfg_phdl_t *entry, 2531*26947304SEvan Yan uint32_t length, uint32_t *ans) 2532*26947304SEvan Yan { 2533*26947304SEvan Yan uint32_t new_io; 2534*26947304SEvan Yan uint64_t io_last; 2535*26947304SEvan Yan 2536*26947304SEvan Yan /* 2537*26947304SEvan Yan * See if there is a hole, that can hold this request. 2538*26947304SEvan Yan * Pass 64 bit parameters and then truncate to 32 bit. 2539*26947304SEvan Yan */ 2540*26947304SEvan Yan io_last = entry->io_last; 2541*26947304SEvan Yan new_io = (uint32_t)pcicfg_alloc_hole(&entry->io_hole, &io_last, length); 2542*26947304SEvan Yan if (new_io) { /* if non-zero, found a hole. */ 2543*26947304SEvan Yan entry->io_last = (uint32_t)io_last; 2544*26947304SEvan Yan if (ans != NULL) 2545*26947304SEvan Yan *ans = new_io; 2546*26947304SEvan Yan } else 2547*26947304SEvan Yan cmn_err(CE_WARN, "No %u bytes IO space window for %s\n", 2548*26947304SEvan Yan length, ddi_get_name(entry->dip)); 2549*26947304SEvan Yan } 2550*26947304SEvan Yan 2551*26947304SEvan Yan static int 2552*26947304SEvan Yan pcicfg_sum_resources(dev_info_t *dip, void *hdl) 2553*26947304SEvan Yan { 2554*26947304SEvan Yan pcicfg_phdl_t *entry = (pcicfg_phdl_t *)hdl; 2555*26947304SEvan Yan pci_regspec_t *pci_rp; 2556*26947304SEvan Yan int length; 2557*26947304SEvan Yan int rcount; 2558*26947304SEvan Yan int i; 2559*26947304SEvan Yan ndi_ra_request_t *mem_request; 2560*26947304SEvan Yan ndi_ra_request_t *io_request; 2561*26947304SEvan Yan uint8_t header_type; 2562*26947304SEvan Yan ddi_acc_handle_t handle; 2563*26947304SEvan Yan 2564*26947304SEvan Yan entry->error = PCICFG_SUCCESS; 2565*26947304SEvan Yan 2566*26947304SEvan Yan mem_request = &entry->mem_req; 2567*26947304SEvan Yan io_request = &entry->io_req; 2568*26947304SEvan Yan 2569*26947304SEvan Yan if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) { 2570*26947304SEvan Yan DEBUG0("Failed to map config space!\n"); 2571*26947304SEvan Yan entry->error = PCICFG_FAILURE; 2572*26947304SEvan Yan return (DDI_WALK_TERMINATE); 2573*26947304SEvan Yan } 2574*26947304SEvan Yan 2575*26947304SEvan Yan header_type = pci_config_get8(handle, PCI_CONF_HEADER); 2576*26947304SEvan Yan 2577*26947304SEvan Yan /* 2578*26947304SEvan Yan * If its a bridge - just record the highest bus seen 2579*26947304SEvan Yan */ 2580*26947304SEvan Yan if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) { 2581*26947304SEvan Yan 2582*26947304SEvan Yan if (entry->highest_bus < pci_config_get8(handle, 2583*26947304SEvan Yan PCI_BCNF_SECBUS)) { 2584*26947304SEvan Yan entry->highest_bus = 2585*26947304SEvan Yan pci_config_get8(handle, PCI_BCNF_SECBUS); 2586*26947304SEvan Yan } 2587*26947304SEvan Yan 2588*26947304SEvan Yan (void) pcicfg_config_teardown(&handle); 2589*26947304SEvan Yan entry->error = PCICFG_FAILURE; 2590*26947304SEvan Yan return (DDI_WALK_CONTINUE); 2591*26947304SEvan Yan } else { 2592*26947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 2593*26947304SEvan Yan DDI_PROP_DONTPASS, "reg", (caddr_t)&pci_rp, 2594*26947304SEvan Yan &length) != DDI_PROP_SUCCESS) { 2595*26947304SEvan Yan /* 2596*26947304SEvan Yan * If one node in (the subtree of nodes) 2597*26947304SEvan Yan * does'nt have a "reg" property fail the 2598*26947304SEvan Yan * allocation. 2599*26947304SEvan Yan */ 2600*26947304SEvan Yan entry->memory_len = 0; 2601*26947304SEvan Yan entry->io_len = 0; 2602*26947304SEvan Yan entry->error = PCICFG_FAILURE; 2603*26947304SEvan Yan return (DDI_WALK_TERMINATE); 2604*26947304SEvan Yan } 2605*26947304SEvan Yan /* 2606*26947304SEvan Yan * For each "reg" property with a length, add that to the 2607*26947304SEvan Yan * total memory (or I/O) to allocate. 2608*26947304SEvan Yan */ 2609*26947304SEvan Yan rcount = length / sizeof (pci_regspec_t); 2610*26947304SEvan Yan 2611*26947304SEvan Yan for (i = 0; i < rcount; i++) { 2612*26947304SEvan Yan 2613*26947304SEvan Yan switch (PCI_REG_ADDR_G(pci_rp[i].pci_phys_hi)) { 2614*26947304SEvan Yan 2615*26947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_MEM32): 2616*26947304SEvan Yan mem_request->ra_len = 2617*26947304SEvan Yan pci_rp[i].pci_size_low + 2618*26947304SEvan Yan PCICFG_ROUND_UP(mem_request->ra_len, 2619*26947304SEvan Yan pci_rp[i].pci_size_low); 2620*26947304SEvan Yan DEBUG1("ADDING 32 --->0x%x\n", 2621*26947304SEvan Yan pci_rp[i].pci_size_low); 2622*26947304SEvan Yan 2623*26947304SEvan Yan break; 2624*26947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_MEM64): 2625*26947304SEvan Yan mem_request->ra_len = 2626*26947304SEvan Yan pci_rp[i].pci_size_low + 2627*26947304SEvan Yan PCICFG_ROUND_UP(mem_request->ra_len, 2628*26947304SEvan Yan pci_rp[i].pci_size_low); 2629*26947304SEvan Yan DEBUG1("ADDING 64 --->0x%x\n", 2630*26947304SEvan Yan pci_rp[i].pci_size_low); 2631*26947304SEvan Yan 2632*26947304SEvan Yan break; 2633*26947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_IO): 2634*26947304SEvan Yan io_request->ra_len = 2635*26947304SEvan Yan pci_rp[i].pci_size_low + 2636*26947304SEvan Yan PCICFG_ROUND_UP(io_request->ra_len, 2637*26947304SEvan Yan pci_rp[i].pci_size_low); 2638*26947304SEvan Yan DEBUG1("ADDING I/O --->0x%x\n", 2639*26947304SEvan Yan pci_rp[i].pci_size_low); 2640*26947304SEvan Yan break; 2641*26947304SEvan Yan default: 2642*26947304SEvan Yan /* Config space register - not included */ 2643*26947304SEvan Yan break; 2644*26947304SEvan Yan } 2645*26947304SEvan Yan } 2646*26947304SEvan Yan 2647*26947304SEvan Yan /* 2648*26947304SEvan Yan * free the memory allocated by ddi_getlongprop 2649*26947304SEvan Yan */ 2650*26947304SEvan Yan kmem_free(pci_rp, length); 2651*26947304SEvan Yan 2652*26947304SEvan Yan /* 2653*26947304SEvan Yan * continue the walk to the next sibling to sum memory 2654*26947304SEvan Yan */ 2655*26947304SEvan Yan 2656*26947304SEvan Yan (void) pcicfg_config_teardown(&handle); 2657*26947304SEvan Yan 2658*26947304SEvan Yan return (DDI_WALK_CONTINUE); 2659*26947304SEvan Yan } 2660*26947304SEvan Yan } 2661*26947304SEvan Yan 2662*26947304SEvan Yan static int 2663*26947304SEvan Yan pcicfg_find_resource_end(dev_info_t *dip, void *hdl) 2664*26947304SEvan Yan { 2665*26947304SEvan Yan pcicfg_phdl_t *entry_p = (pcicfg_phdl_t *)hdl; 2666*26947304SEvan Yan pci_regspec_t *pci_ap; 2667*26947304SEvan Yan pcicfg_range_t *ranges; 2668*26947304SEvan Yan int length; 2669*26947304SEvan Yan int rcount; 2670*26947304SEvan Yan int i; 2671*26947304SEvan Yan 2672*26947304SEvan Yan entry_p->error = PCICFG_SUCCESS; 2673*26947304SEvan Yan 2674*26947304SEvan Yan if (dip == entry_p->dip) { 2675*26947304SEvan Yan DEBUG0("Don't include parent bridge node\n"); 2676*26947304SEvan Yan return (DDI_WALK_CONTINUE); 2677*26947304SEvan Yan } 2678*26947304SEvan Yan 2679*26947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 2680*26947304SEvan Yan DDI_PROP_DONTPASS, "ranges", 2681*26947304SEvan Yan (caddr_t)&ranges, &length) != DDI_PROP_SUCCESS) { 2682*26947304SEvan Yan DEBUG0("Node doesn't have ranges\n"); 2683*26947304SEvan Yan goto ap; 2684*26947304SEvan Yan } 2685*26947304SEvan Yan 2686*26947304SEvan Yan rcount = length / sizeof (pcicfg_range_t); 2687*26947304SEvan Yan 2688*26947304SEvan Yan for (i = 0; i < rcount; i++) { 2689*26947304SEvan Yan uint64_t base; 2690*26947304SEvan Yan uint64_t mid = ranges[i].child_mid; 2691*26947304SEvan Yan uint64_t lo = ranges[i].child_lo; 2692*26947304SEvan Yan uint64_t size = ranges[i].size_lo; 2693*26947304SEvan Yan 2694*26947304SEvan Yan switch (PCI_REG_ADDR_G(ranges[i].child_hi)) { 2695*26947304SEvan Yan 2696*26947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_MEM32): 2697*26947304SEvan Yan base = entry_p->memory_base; 2698*26947304SEvan Yan entry_p->memory_base = MAX(base, lo + size); 2699*26947304SEvan Yan break; 2700*26947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_MEM64): 2701*26947304SEvan Yan base = entry_p->memory_base; 2702*26947304SEvan Yan entry_p->memory_base = MAX(base, 2703*26947304SEvan Yan PCICFG_LADDR(lo, mid) + size); 2704*26947304SEvan Yan break; 2705*26947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_IO): 2706*26947304SEvan Yan base = entry_p->io_base; 2707*26947304SEvan Yan entry_p->io_base = MAX(base, lo + size); 2708*26947304SEvan Yan break; 2709*26947304SEvan Yan } 2710*26947304SEvan Yan } 2711*26947304SEvan Yan 2712*26947304SEvan Yan kmem_free(ranges, length); 2713*26947304SEvan Yan return (DDI_WALK_CONTINUE); 2714*26947304SEvan Yan 2715*26947304SEvan Yan ap: if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 2716*26947304SEvan Yan DDI_PROP_DONTPASS, "assigned-addresses", 2717*26947304SEvan Yan (caddr_t)&pci_ap, &length) != DDI_PROP_SUCCESS) { 2718*26947304SEvan Yan DEBUG0("Node doesn't have assigned-addresses\n"); 2719*26947304SEvan Yan return (DDI_WALK_CONTINUE); 2720*26947304SEvan Yan } 2721*26947304SEvan Yan 2722*26947304SEvan Yan rcount = length / sizeof (pci_regspec_t); 2723*26947304SEvan Yan 2724*26947304SEvan Yan for (i = 0; i < rcount; i++) { 2725*26947304SEvan Yan 2726*26947304SEvan Yan switch (PCI_REG_ADDR_G(pci_ap[i].pci_phys_hi)) { 2727*26947304SEvan Yan 2728*26947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_MEM32): 2729*26947304SEvan Yan if ((pci_ap[i].pci_phys_low + 2730*26947304SEvan Yan pci_ap[i].pci_size_low) > 2731*26947304SEvan Yan entry_p->memory_base) { 2732*26947304SEvan Yan entry_p->memory_base = 2733*26947304SEvan Yan pci_ap[i].pci_phys_low + 2734*26947304SEvan Yan pci_ap[i].pci_size_low; 2735*26947304SEvan Yan } 2736*26947304SEvan Yan break; 2737*26947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_MEM64): 2738*26947304SEvan Yan if ((PCICFG_LADDR(pci_ap[i].pci_phys_low, 2739*26947304SEvan Yan pci_ap[i].pci_phys_mid) + 2740*26947304SEvan Yan pci_ap[i].pci_size_low) > 2741*26947304SEvan Yan entry_p->memory_base) { 2742*26947304SEvan Yan entry_p->memory_base = PCICFG_LADDR( 2743*26947304SEvan Yan pci_ap[i].pci_phys_low, 2744*26947304SEvan Yan pci_ap[i].pci_phys_mid) + 2745*26947304SEvan Yan pci_ap[i].pci_size_low; 2746*26947304SEvan Yan } 2747*26947304SEvan Yan break; 2748*26947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_IO): 2749*26947304SEvan Yan if ((pci_ap[i].pci_phys_low + 2750*26947304SEvan Yan pci_ap[i].pci_size_low) > 2751*26947304SEvan Yan entry_p->io_base) { 2752*26947304SEvan Yan entry_p->io_base = 2753*26947304SEvan Yan pci_ap[i].pci_phys_low + 2754*26947304SEvan Yan pci_ap[i].pci_size_low; 2755*26947304SEvan Yan } 2756*26947304SEvan Yan break; 2757*26947304SEvan Yan } 2758*26947304SEvan Yan } 2759*26947304SEvan Yan 2760*26947304SEvan Yan /* 2761*26947304SEvan Yan * free the memory allocated by ddi_getlongprop 2762*26947304SEvan Yan */ 2763*26947304SEvan Yan kmem_free(pci_ap, length); 2764*26947304SEvan Yan 2765*26947304SEvan Yan /* 2766*26947304SEvan Yan * continue the walk to the next sibling to sum memory 2767*26947304SEvan Yan */ 2768*26947304SEvan Yan return (DDI_WALK_CONTINUE); 2769*26947304SEvan Yan } 2770*26947304SEvan Yan 2771*26947304SEvan Yan static int 2772*26947304SEvan Yan pcicfg_free_bridge_resources(dev_info_t *dip) 2773*26947304SEvan Yan { 2774*26947304SEvan Yan pcicfg_range_t *ranges; 2775*26947304SEvan Yan uint_t *bus; 2776*26947304SEvan Yan int k; 2777*26947304SEvan Yan int length; 2778*26947304SEvan Yan int i; 2779*26947304SEvan Yan 2780*26947304SEvan Yan 2781*26947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 2782*26947304SEvan Yan DDI_PROP_DONTPASS, "ranges", (caddr_t)&ranges, 2783*26947304SEvan Yan &length) != DDI_PROP_SUCCESS) { 2784*26947304SEvan Yan DEBUG0("Failed to read ranges property\n"); 2785*26947304SEvan Yan if (ddi_get_child(dip)) { 2786*26947304SEvan Yan cmn_err(CE_WARN, "No ranges property found for %s", 2787*26947304SEvan Yan ddi_get_name(dip)); 2788*26947304SEvan Yan /* 2789*26947304SEvan Yan * strictly speaking, we can check for children with 2790*26947304SEvan Yan * assigned-addresses but for now it is better to 2791*26947304SEvan Yan * be conservative and assume that if there are child 2792*26947304SEvan Yan * nodes, then they do consume PCI memory or IO 2793*26947304SEvan Yan * resources, Hence return failure. 2794*26947304SEvan Yan */ 2795*26947304SEvan Yan return (PCICFG_FAILURE); 2796*26947304SEvan Yan } 2797*26947304SEvan Yan length = 0; 2798*26947304SEvan Yan 2799*26947304SEvan Yan } 2800*26947304SEvan Yan 2801*26947304SEvan Yan for (i = 0; i < length / sizeof (pcicfg_range_t); i++) { 2802*26947304SEvan Yan if (ranges[i].size_lo != 0 || 2803*26947304SEvan Yan ranges[i].size_hi != 0) { 2804*26947304SEvan Yan switch (ranges[i].parent_hi & PCI_REG_ADDR_M) { 2805*26947304SEvan Yan case PCI_ADDR_IO: 2806*26947304SEvan Yan DEBUG2("Free I/O " 2807*26947304SEvan Yan "base/length = [0x%x]/[0x%x]\n", 2808*26947304SEvan Yan ranges[i].child_lo, 2809*26947304SEvan Yan ranges[i].size_lo); 2810*26947304SEvan Yan if (ndi_ra_free(ddi_get_parent(dip), 2811*26947304SEvan Yan (uint64_t)ranges[i].child_lo, 2812*26947304SEvan Yan (uint64_t)ranges[i].size_lo, 2813*26947304SEvan Yan NDI_RA_TYPE_IO, NDI_RA_PASS) 2814*26947304SEvan Yan != NDI_SUCCESS) { 2815*26947304SEvan Yan DEBUG0("Trouble freeing " 2816*26947304SEvan Yan "PCI i/o space\n"); 2817*26947304SEvan Yan kmem_free(ranges, length); 2818*26947304SEvan Yan return (PCICFG_FAILURE); 2819*26947304SEvan Yan } 2820*26947304SEvan Yan break; 2821*26947304SEvan Yan case PCI_ADDR_MEM32: 2822*26947304SEvan Yan case PCI_ADDR_MEM64: 2823*26947304SEvan Yan DEBUG3("Free Memory base/length = " 2824*26947304SEvan Yan "[0x%x.%x]/[0x%x]\n", 2825*26947304SEvan Yan ranges[i].child_mid, 2826*26947304SEvan Yan ranges[i].child_lo, 2827*26947304SEvan Yan ranges[i].size_lo) 2828*26947304SEvan Yan if (ndi_ra_free(ddi_get_parent(dip), 2829*26947304SEvan Yan PCICFG_LADDR(ranges[i].child_lo, 2830*26947304SEvan Yan ranges[i].child_mid), 2831*26947304SEvan Yan (uint64_t)ranges[i].size_lo, 2832*26947304SEvan Yan NDI_RA_TYPE_MEM, NDI_RA_PASS) 2833*26947304SEvan Yan != NDI_SUCCESS) { 2834*26947304SEvan Yan DEBUG0("Trouble freeing " 2835*26947304SEvan Yan "PCI memory space\n"); 2836*26947304SEvan Yan kmem_free(ranges, length); 2837*26947304SEvan Yan return (PCICFG_FAILURE); 2838*26947304SEvan Yan } 2839*26947304SEvan Yan break; 2840*26947304SEvan Yan default: 2841*26947304SEvan Yan DEBUG0("Unknown memory space\n"); 2842*26947304SEvan Yan break; 2843*26947304SEvan Yan } 2844*26947304SEvan Yan } 2845*26947304SEvan Yan } 2846*26947304SEvan Yan 2847*26947304SEvan Yan if (length) 2848*26947304SEvan Yan kmem_free(ranges, length); 2849*26947304SEvan Yan 2850*26947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 2851*26947304SEvan Yan DDI_PROP_DONTPASS, "bus-range", (caddr_t)&bus, 2852*26947304SEvan Yan &k) != DDI_PROP_SUCCESS) { 2853*26947304SEvan Yan DEBUG0("Failed to read bus-range property\n"); 2854*26947304SEvan Yan return (PCICFG_FAILURE); 2855*26947304SEvan Yan } 2856*26947304SEvan Yan 2857*26947304SEvan Yan DEBUG2("Need to free bus [%d] range [%d]\n", 2858*26947304SEvan Yan bus[0], bus[1] - bus[0] + 1); 2859*26947304SEvan Yan 2860*26947304SEvan Yan if (ndi_ra_free(ddi_get_parent(dip), 2861*26947304SEvan Yan (uint64_t)bus[0], (uint64_t)(bus[1] - bus[0] + 1), 2862*26947304SEvan Yan NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS) != NDI_SUCCESS) { 2863*26947304SEvan Yan /*EMPTY*/ 2864*26947304SEvan Yan DEBUG0("Failed to free a bus number\n"); 2865*26947304SEvan Yan } 2866*26947304SEvan Yan /* 2867*26947304SEvan Yan * Don't forget to free up memory from ddi_getlongprop 2868*26947304SEvan Yan */ 2869*26947304SEvan Yan kmem_free((caddr_t)bus, k); 2870*26947304SEvan Yan 2871*26947304SEvan Yan return (PCICFG_SUCCESS); 2872*26947304SEvan Yan } 2873*26947304SEvan Yan 2874*26947304SEvan Yan static int 2875*26947304SEvan Yan pcicfg_free_device_resources(dev_info_t *dip, pcicfg_flags_t flags) 2876*26947304SEvan Yan { 2877*26947304SEvan Yan pci_regspec_t *assigned; 2878*26947304SEvan Yan 2879*26947304SEvan Yan int length; 2880*26947304SEvan Yan int acount; 2881*26947304SEvan Yan int i; 2882*26947304SEvan Yan 2883*26947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 2884*26947304SEvan Yan DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned, 2885*26947304SEvan Yan &length) != DDI_PROP_SUCCESS) { 2886*26947304SEvan Yan DEBUG0("Failed to read assigned-addresses property\n"); 2887*26947304SEvan Yan return (PCICFG_FAILURE); 2888*26947304SEvan Yan } 2889*26947304SEvan Yan 2890*26947304SEvan Yan /* 2891*26947304SEvan Yan * For each "assigned-addresses" property entry with a length, 2892*26947304SEvan Yan * call the memory allocation routines to return the 2893*26947304SEvan Yan * resource. 2894*26947304SEvan Yan */ 2895*26947304SEvan Yan acount = length / sizeof (pci_regspec_t); 2896*26947304SEvan Yan for (i = 0; i < acount; i++) { 2897*26947304SEvan Yan /* 2898*26947304SEvan Yan * Workaround for Devconf (x86) bug to skip extra entries 2899*26947304SEvan Yan * beyond the PCI_CONF_BASE5 offset. But we want to free up 2900*26947304SEvan Yan * any memory for expansion roms if allocated. 2901*26947304SEvan Yan */ 2902*26947304SEvan Yan if ((PCI_REG_REG_G(assigned[i].pci_phys_hi) > PCI_CONF_BASE5) && 2903*26947304SEvan Yan (PCI_REG_REG_G(assigned[i].pci_phys_hi) != PCI_CONF_ROM)) 2904*26947304SEvan Yan break; 2905*26947304SEvan Yan 2906*26947304SEvan Yan if (pcicfg_free_resource(dip, assigned[i], flags)) { 2907*26947304SEvan Yan DEBUG1("pcicfg_free_device_resources - Trouble freeing " 2908*26947304SEvan Yan "%x\n", assigned[i].pci_phys_hi); 2909*26947304SEvan Yan /* 2910*26947304SEvan Yan * Don't forget to free up memory from ddi_getlongprop 2911*26947304SEvan Yan */ 2912*26947304SEvan Yan kmem_free((caddr_t)assigned, length); 2913*26947304SEvan Yan 2914*26947304SEvan Yan return (PCICFG_FAILURE); 2915*26947304SEvan Yan } 2916*26947304SEvan Yan } 2917*26947304SEvan Yan kmem_free(assigned, length); 2918*26947304SEvan Yan return (PCICFG_SUCCESS); 2919*26947304SEvan Yan } 2920*26947304SEvan Yan 2921*26947304SEvan Yan static int 2922*26947304SEvan Yan pcicfg_free_resources(dev_info_t *dip, pcicfg_flags_t flags) 2923*26947304SEvan Yan { 2924*26947304SEvan Yan ddi_acc_handle_t handle; 2925*26947304SEvan Yan uint8_t header_type; 2926*26947304SEvan Yan 2927*26947304SEvan Yan if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) { 2928*26947304SEvan Yan DEBUG0("Failed to map config space!\n"); 2929*26947304SEvan Yan return (PCICFG_FAILURE); 2930*26947304SEvan Yan } 2931*26947304SEvan Yan 2932*26947304SEvan Yan header_type = pci_config_get8(handle, PCI_CONF_HEADER); 2933*26947304SEvan Yan 2934*26947304SEvan Yan (void) pci_config_teardown(&handle); 2935*26947304SEvan Yan 2936*26947304SEvan Yan /* 2937*26947304SEvan Yan * A different algorithm is used for bridges and leaf devices. 2938*26947304SEvan Yan */ 2939*26947304SEvan Yan if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) { 2940*26947304SEvan Yan /* 2941*26947304SEvan Yan * We only support readonly probing for leaf devices. 2942*26947304SEvan Yan */ 2943*26947304SEvan Yan if (flags & PCICFG_FLAG_READ_ONLY) 2944*26947304SEvan Yan return (PCICFG_FAILURE); 2945*26947304SEvan Yan 2946*26947304SEvan Yan if (pcicfg_free_bridge_resources(dip) != PCICFG_SUCCESS) { 2947*26947304SEvan Yan DEBUG0("Failed freeing up bridge resources\n"); 2948*26947304SEvan Yan return (PCICFG_FAILURE); 2949*26947304SEvan Yan } 2950*26947304SEvan Yan } else { 2951*26947304SEvan Yan if (pcicfg_free_device_resources(dip, flags) 2952*26947304SEvan Yan != PCICFG_SUCCESS) { 2953*26947304SEvan Yan DEBUG0("Failed freeing up device resources\n"); 2954*26947304SEvan Yan return (PCICFG_FAILURE); 2955*26947304SEvan Yan } 2956*26947304SEvan Yan } 2957*26947304SEvan Yan return (PCICFG_SUCCESS); 2958*26947304SEvan Yan } 2959*26947304SEvan Yan 2960*26947304SEvan Yan #ifndef _DONT_USE_1275_GENERIC_NAMES 2961*26947304SEvan Yan static char * 2962*26947304SEvan Yan pcicfg_get_class_name(uint32_t classcode) 2963*26947304SEvan Yan { 2964*26947304SEvan Yan struct pcicfg_name_entry *ptr; 2965*26947304SEvan Yan 2966*26947304SEvan Yan for (ptr = &pcicfg_class_lookup[0]; ptr->name != NULL; ptr++) { 2967*26947304SEvan Yan if (ptr->class_code == classcode) { 2968*26947304SEvan Yan return (ptr->name); 2969*26947304SEvan Yan } 2970*26947304SEvan Yan } 2971*26947304SEvan Yan return (NULL); 2972*26947304SEvan Yan } 2973*26947304SEvan Yan #endif /* _DONT_USE_1275_GENERIC_NAMES */ 2974*26947304SEvan Yan 2975*26947304SEvan Yan static dev_info_t * 2976*26947304SEvan Yan pcicfg_devi_find(dev_info_t *dip, uint_t device, uint_t function) 2977*26947304SEvan Yan { 2978*26947304SEvan Yan struct pcicfg_find_ctrl ctrl; 2979*26947304SEvan Yan int count; 2980*26947304SEvan Yan 2981*26947304SEvan Yan ctrl.device = device; 2982*26947304SEvan Yan ctrl.function = function; 2983*26947304SEvan Yan ctrl.dip = NULL; 2984*26947304SEvan Yan 2985*26947304SEvan Yan ndi_devi_enter(dip, &count); 2986*26947304SEvan Yan ddi_walk_devs(ddi_get_child(dip), pcicfg_match_dev, (void *)&ctrl); 2987*26947304SEvan Yan ndi_devi_exit(dip, count); 2988*26947304SEvan Yan 2989*26947304SEvan Yan return (ctrl.dip); 2990*26947304SEvan Yan } 2991*26947304SEvan Yan 2992*26947304SEvan Yan static int 2993*26947304SEvan Yan pcicfg_match_dev(dev_info_t *dip, void *hdl) 2994*26947304SEvan Yan { 2995*26947304SEvan Yan struct pcicfg_find_ctrl *ctrl = (struct pcicfg_find_ctrl *)hdl; 2996*26947304SEvan Yan pci_regspec_t *pci_rp; 2997*26947304SEvan Yan int length; 2998*26947304SEvan Yan int pci_dev; 2999*26947304SEvan Yan int pci_func; 3000*26947304SEvan Yan 3001*26947304SEvan Yan if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 3002*26947304SEvan Yan DDI_PROP_DONTPASS, "reg", (int **)&pci_rp, 3003*26947304SEvan Yan (uint_t *)&length) != DDI_PROP_SUCCESS) { 3004*26947304SEvan Yan ctrl->dip = NULL; 3005*26947304SEvan Yan return (DDI_WALK_TERMINATE); 3006*26947304SEvan Yan } 3007*26947304SEvan Yan 3008*26947304SEvan Yan /* get the PCI device address info */ 3009*26947304SEvan Yan pci_dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi); 3010*26947304SEvan Yan pci_func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi); 3011*26947304SEvan Yan 3012*26947304SEvan Yan /* 3013*26947304SEvan Yan * free the memory allocated by ddi_prop_lookup_int_array 3014*26947304SEvan Yan */ 3015*26947304SEvan Yan ddi_prop_free(pci_rp); 3016*26947304SEvan Yan 3017*26947304SEvan Yan 3018*26947304SEvan Yan if ((pci_dev == ctrl->device) && (pci_func == ctrl->function)) { 3019*26947304SEvan Yan /* found the match for the specified device address */ 3020*26947304SEvan Yan ctrl->dip = dip; 3021*26947304SEvan Yan return (DDI_WALK_TERMINATE); 3022*26947304SEvan Yan } 3023*26947304SEvan Yan 3024*26947304SEvan Yan /* 3025*26947304SEvan Yan * continue the walk to the next sibling to look for a match. 3026*26947304SEvan Yan */ 3027*26947304SEvan Yan return (DDI_WALK_PRUNECHILD); 3028*26947304SEvan Yan } 3029*26947304SEvan Yan 3030*26947304SEvan Yan static int 3031*26947304SEvan Yan pcicfg_update_assigned_prop(dev_info_t *dip, pci_regspec_t *newone) 3032*26947304SEvan Yan { 3033*26947304SEvan Yan int alen; 3034*26947304SEvan Yan pci_regspec_t *assigned; 3035*26947304SEvan Yan caddr_t newreg; 3036*26947304SEvan Yan uint_t status; 3037*26947304SEvan Yan 3038*26947304SEvan Yan DEBUG0("pcicfg_update_assigned_prop()\n"); 3039*26947304SEvan Yan status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 3040*26947304SEvan Yan "assigned-addresses", (caddr_t)&assigned, &alen); 3041*26947304SEvan Yan switch (status) { 3042*26947304SEvan Yan case DDI_PROP_SUCCESS: 3043*26947304SEvan Yan break; 3044*26947304SEvan Yan case DDI_PROP_NO_MEMORY: 3045*26947304SEvan Yan DEBUG0("no memory for assigned-addresses property\n"); 3046*26947304SEvan Yan return (PCICFG_FAILURE); 3047*26947304SEvan Yan default: 3048*26947304SEvan Yan (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, 3049*26947304SEvan Yan "assigned-addresses", (int *)newone, 3050*26947304SEvan Yan sizeof (*newone)/sizeof (int)); 3051*26947304SEvan Yan 3052*26947304SEvan Yan (void) pcicfg_dump_assigned(dip); 3053*26947304SEvan Yan 3054*26947304SEvan Yan return (PCICFG_SUCCESS); 3055*26947304SEvan Yan } 3056*26947304SEvan Yan 3057*26947304SEvan Yan /* 3058*26947304SEvan Yan * Allocate memory for the existing 3059*26947304SEvan Yan * assigned-addresses(s) plus one and then 3060*26947304SEvan Yan * build it. 3061*26947304SEvan Yan */ 3062*26947304SEvan Yan 3063*26947304SEvan Yan newreg = kmem_zalloc(alen+sizeof (*newone), KM_SLEEP); 3064*26947304SEvan Yan 3065*26947304SEvan Yan bcopy(assigned, newreg, alen); 3066*26947304SEvan Yan bcopy(newone, newreg + alen, sizeof (*newone)); 3067*26947304SEvan Yan 3068*26947304SEvan Yan /* 3069*26947304SEvan Yan * Write out the new "assigned-addresses" spec 3070*26947304SEvan Yan */ 3071*26947304SEvan Yan (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, 3072*26947304SEvan Yan "assigned-addresses", (int *)newreg, 3073*26947304SEvan Yan (alen + sizeof (*newone))/sizeof (int)); 3074*26947304SEvan Yan 3075*26947304SEvan Yan kmem_free((caddr_t)newreg, alen+sizeof (*newone)); 3076*26947304SEvan Yan 3077*26947304SEvan Yan /* 3078*26947304SEvan Yan * Don't forget to free up memory from ddi_getlongprop 3079*26947304SEvan Yan */ 3080*26947304SEvan Yan kmem_free((caddr_t)assigned, alen); 3081*26947304SEvan Yan 3082*26947304SEvan Yan (void) pcicfg_dump_assigned(dip); 3083*26947304SEvan Yan 3084*26947304SEvan Yan return (PCICFG_SUCCESS); 3085*26947304SEvan Yan } 3086*26947304SEvan Yan static int 3087*26947304SEvan Yan pcicfg_update_ranges_prop(dev_info_t *dip, pcicfg_range_t *addition) 3088*26947304SEvan Yan { 3089*26947304SEvan Yan int rlen; 3090*26947304SEvan Yan pcicfg_range_t *ranges; 3091*26947304SEvan Yan caddr_t newreg; 3092*26947304SEvan Yan uint_t status; 3093*26947304SEvan Yan 3094*26947304SEvan Yan status = ddi_getlongprop(DDI_DEV_T_ANY, 3095*26947304SEvan Yan dip, DDI_PROP_DONTPASS, "ranges", (caddr_t)&ranges, &rlen); 3096*26947304SEvan Yan 3097*26947304SEvan Yan 3098*26947304SEvan Yan switch (status) { 3099*26947304SEvan Yan case DDI_PROP_SUCCESS: 3100*26947304SEvan Yan break; 3101*26947304SEvan Yan case DDI_PROP_NO_MEMORY: 3102*26947304SEvan Yan DEBUG0("ranges present, but unable to get memory\n"); 3103*26947304SEvan Yan return (PCICFG_FAILURE); 3104*26947304SEvan Yan default: 3105*26947304SEvan Yan DEBUG0("no ranges property - creating one\n"); 3106*26947304SEvan Yan if (ndi_prop_update_int_array(DDI_DEV_T_NONE, 3107*26947304SEvan Yan dip, "ranges", (int *)addition, 3108*26947304SEvan Yan sizeof (pcicfg_range_t)/sizeof (int)) 3109*26947304SEvan Yan != DDI_SUCCESS) { 3110*26947304SEvan Yan DEBUG0("Did'nt create ranges property\n"); 3111*26947304SEvan Yan return (PCICFG_FAILURE); 3112*26947304SEvan Yan } 3113*26947304SEvan Yan return (PCICFG_SUCCESS); 3114*26947304SEvan Yan } 3115*26947304SEvan Yan 3116*26947304SEvan Yan /* 3117*26947304SEvan Yan * Allocate memory for the existing reg(s) plus one and then 3118*26947304SEvan Yan * build it. 3119*26947304SEvan Yan */ 3120*26947304SEvan Yan newreg = kmem_zalloc(rlen + sizeof (pcicfg_range_t), KM_SLEEP); 3121*26947304SEvan Yan 3122*26947304SEvan Yan bcopy(ranges, newreg, rlen); 3123*26947304SEvan Yan bcopy(addition, newreg + rlen, sizeof (pcicfg_range_t)); 3124*26947304SEvan Yan 3125*26947304SEvan Yan /* 3126*26947304SEvan Yan * Write out the new "ranges" property 3127*26947304SEvan Yan */ 3128*26947304SEvan Yan (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, 3129*26947304SEvan Yan dip, "ranges", (int *)newreg, 3130*26947304SEvan Yan (rlen + sizeof (pcicfg_range_t))/sizeof (int)); 3131*26947304SEvan Yan 3132*26947304SEvan Yan kmem_free((caddr_t)newreg, rlen+sizeof (pcicfg_range_t)); 3133*26947304SEvan Yan 3134*26947304SEvan Yan kmem_free((caddr_t)ranges, rlen); 3135*26947304SEvan Yan 3136*26947304SEvan Yan return (PCICFG_SUCCESS); 3137*26947304SEvan Yan } 3138*26947304SEvan Yan 3139*26947304SEvan Yan static int 3140*26947304SEvan Yan pcicfg_update_reg_prop(dev_info_t *dip, uint32_t regvalue, uint_t reg_offset) 3141*26947304SEvan Yan { 3142*26947304SEvan Yan int rlen; 3143*26947304SEvan Yan pci_regspec_t *reg; 3144*26947304SEvan Yan caddr_t newreg; 3145*26947304SEvan Yan uint32_t hiword; 3146*26947304SEvan Yan pci_regspec_t addition; 3147*26947304SEvan Yan uint32_t size; 3148*26947304SEvan Yan uint_t status; 3149*26947304SEvan Yan 3150*26947304SEvan Yan status = ddi_getlongprop(DDI_DEV_T_ANY, 3151*26947304SEvan Yan dip, DDI_PROP_DONTPASS, "reg", (caddr_t)®, &rlen); 3152*26947304SEvan Yan 3153*26947304SEvan Yan switch (status) { 3154*26947304SEvan Yan case DDI_PROP_SUCCESS: 3155*26947304SEvan Yan break; 3156*26947304SEvan Yan case DDI_PROP_NO_MEMORY: 3157*26947304SEvan Yan DEBUG0("reg present, but unable to get memory\n"); 3158*26947304SEvan Yan return (PCICFG_FAILURE); 3159*26947304SEvan Yan default: 3160*26947304SEvan Yan DEBUG0("no reg property\n"); 3161*26947304SEvan Yan return (PCICFG_FAILURE); 3162*26947304SEvan Yan } 3163*26947304SEvan Yan 3164*26947304SEvan Yan /* 3165*26947304SEvan Yan * Allocate memory for the existing reg(s) plus one and then 3166*26947304SEvan Yan * build it. 3167*26947304SEvan Yan */ 3168*26947304SEvan Yan newreg = kmem_zalloc(rlen+sizeof (pci_regspec_t), KM_SLEEP); 3169*26947304SEvan Yan 3170*26947304SEvan Yan /* 3171*26947304SEvan Yan * Build the regspec, then add it to the existing one(s) 3172*26947304SEvan Yan */ 3173*26947304SEvan Yan 3174*26947304SEvan Yan hiword = PCICFG_MAKE_REG_HIGH(PCI_REG_BUS_G(reg->pci_phys_hi), 3175*26947304SEvan Yan PCI_REG_DEV_G(reg->pci_phys_hi), 3176*26947304SEvan Yan PCI_REG_FUNC_G(reg->pci_phys_hi), reg_offset); 3177*26947304SEvan Yan 3178*26947304SEvan Yan if (reg_offset == PCI_CONF_ROM) { 3179*26947304SEvan Yan size = (~(PCI_BASE_ROM_ADDR_M & regvalue))+1; 3180*26947304SEvan Yan hiword |= PCI_ADDR_MEM32; 3181*26947304SEvan Yan } else { 3182*26947304SEvan Yan size = (~(PCI_BASE_M_ADDR_M & regvalue))+1; 3183*26947304SEvan Yan 3184*26947304SEvan Yan if ((PCI_BASE_SPACE_M & regvalue) == PCI_BASE_SPACE_MEM) { 3185*26947304SEvan Yan if ((PCI_BASE_TYPE_M & regvalue) == PCI_BASE_TYPE_MEM) { 3186*26947304SEvan Yan hiword |= PCI_ADDR_MEM32; 3187*26947304SEvan Yan } else if ((PCI_BASE_TYPE_M & regvalue) 3188*26947304SEvan Yan == PCI_BASE_TYPE_ALL) { 3189*26947304SEvan Yan hiword |= PCI_ADDR_MEM64; 3190*26947304SEvan Yan } 3191*26947304SEvan Yan } else { 3192*26947304SEvan Yan hiword |= PCI_ADDR_IO; 3193*26947304SEvan Yan } 3194*26947304SEvan Yan } 3195*26947304SEvan Yan 3196*26947304SEvan Yan addition.pci_phys_hi = hiword; 3197*26947304SEvan Yan addition.pci_phys_mid = 0; 3198*26947304SEvan Yan addition.pci_phys_low = 0; 3199*26947304SEvan Yan addition.pci_size_hi = 0; 3200*26947304SEvan Yan addition.pci_size_low = size; 3201*26947304SEvan Yan 3202*26947304SEvan Yan bcopy(reg, newreg, rlen); 3203*26947304SEvan Yan bcopy(&addition, newreg + rlen, sizeof (pci_regspec_t)); 3204*26947304SEvan Yan 3205*26947304SEvan Yan /* 3206*26947304SEvan Yan * Write out the new "reg" property 3207*26947304SEvan Yan */ 3208*26947304SEvan Yan (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, 3209*26947304SEvan Yan dip, "reg", (int *)newreg, 3210*26947304SEvan Yan (rlen + sizeof (pci_regspec_t))/sizeof (int)); 3211*26947304SEvan Yan 3212*26947304SEvan Yan kmem_free((caddr_t)newreg, rlen+sizeof (pci_regspec_t)); 3213*26947304SEvan Yan kmem_free((caddr_t)reg, rlen); 3214*26947304SEvan Yan 3215*26947304SEvan Yan return (PCICFG_SUCCESS); 3216*26947304SEvan Yan } 3217*26947304SEvan Yan static int 3218*26947304SEvan Yan pcicfg_update_available_prop(dev_info_t *dip, pci_regspec_t *newone) 3219*26947304SEvan Yan { 3220*26947304SEvan Yan int alen; 3221*26947304SEvan Yan pci_regspec_t *avail_p; 3222*26947304SEvan Yan caddr_t new_avail; 3223*26947304SEvan Yan uint_t status; 3224*26947304SEvan Yan 3225*26947304SEvan Yan DEBUG2("pcicfg_update_available_prop() - Address %lx Size %x\n", 3226*26947304SEvan Yan newone->pci_phys_low, newone->pci_size_low); 3227*26947304SEvan Yan status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 3228*26947304SEvan Yan "available", (caddr_t)&avail_p, &alen); 3229*26947304SEvan Yan switch (status) { 3230*26947304SEvan Yan case DDI_PROP_SUCCESS: 3231*26947304SEvan Yan break; 3232*26947304SEvan Yan case DDI_PROP_NO_MEMORY: 3233*26947304SEvan Yan DEBUG0("no memory for available property\n"); 3234*26947304SEvan Yan return (PCICFG_FAILURE); 3235*26947304SEvan Yan default: 3236*26947304SEvan Yan (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, 3237*26947304SEvan Yan "available", (int *)newone, 3238*26947304SEvan Yan sizeof (*newone)/sizeof (int)); 3239*26947304SEvan Yan 3240*26947304SEvan Yan return (PCICFG_SUCCESS); 3241*26947304SEvan Yan } 3242*26947304SEvan Yan 3243*26947304SEvan Yan /* 3244*26947304SEvan Yan * Allocate memory for the existing available plus one and then 3245*26947304SEvan Yan * build it. 3246*26947304SEvan Yan */ 3247*26947304SEvan Yan new_avail = kmem_zalloc(alen+sizeof (*newone), KM_SLEEP); 3248*26947304SEvan Yan 3249*26947304SEvan Yan bcopy(avail_p, new_avail, alen); 3250*26947304SEvan Yan bcopy(newone, new_avail + alen, sizeof (*newone)); 3251*26947304SEvan Yan 3252*26947304SEvan Yan /* Write out the new "available" spec */ 3253*26947304SEvan Yan (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, 3254*26947304SEvan Yan "available", (int *)new_avail, 3255*26947304SEvan Yan (alen + sizeof (*newone))/sizeof (int)); 3256*26947304SEvan Yan 3257*26947304SEvan Yan kmem_free((caddr_t)new_avail, alen+sizeof (*newone)); 3258*26947304SEvan Yan 3259*26947304SEvan Yan /* Don't forget to free up memory from ddi_getlongprop */ 3260*26947304SEvan Yan kmem_free((caddr_t)avail_p, alen); 3261*26947304SEvan Yan 3262*26947304SEvan Yan return (PCICFG_SUCCESS); 3263*26947304SEvan Yan } 3264*26947304SEvan Yan 3265*26947304SEvan Yan static int 3266*26947304SEvan Yan pcicfg_update_assigned_prop_value(dev_info_t *dip, uint32_t size, 3267*26947304SEvan Yan uint32_t base, uint32_t base_hi, uint_t reg_offset) 3268*26947304SEvan Yan { 3269*26947304SEvan Yan int rlen; 3270*26947304SEvan Yan pci_regspec_t *reg; 3271*26947304SEvan Yan uint32_t hiword; 3272*26947304SEvan Yan pci_regspec_t addition; 3273*26947304SEvan Yan uint_t status; 3274*26947304SEvan Yan 3275*26947304SEvan Yan status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 3276*26947304SEvan Yan "reg", (caddr_t)®, &rlen); 3277*26947304SEvan Yan 3278*26947304SEvan Yan switch (status) { 3279*26947304SEvan Yan case DDI_PROP_SUCCESS: 3280*26947304SEvan Yan break; 3281*26947304SEvan Yan case DDI_PROP_NO_MEMORY: 3282*26947304SEvan Yan DEBUG0("reg present, but unable to get memory\n"); 3283*26947304SEvan Yan return (PCICFG_FAILURE); 3284*26947304SEvan Yan default: 3285*26947304SEvan Yan /* 3286*26947304SEvan Yan * Since the config space "reg" entry should have been 3287*26947304SEvan Yan * created, we expect a "reg" property already 3288*26947304SEvan Yan * present here. 3289*26947304SEvan Yan */ 3290*26947304SEvan Yan DEBUG0("no reg property\n"); 3291*26947304SEvan Yan return (PCICFG_FAILURE); 3292*26947304SEvan Yan } 3293*26947304SEvan Yan 3294*26947304SEvan Yan /* 3295*26947304SEvan Yan * Build the regspec, then add it to the existing one(s) 3296*26947304SEvan Yan */ 3297*26947304SEvan Yan 3298*26947304SEvan Yan hiword = PCICFG_MAKE_REG_HIGH(PCI_REG_BUS_G(reg->pci_phys_hi), 3299*26947304SEvan Yan PCI_REG_DEV_G(reg->pci_phys_hi), 3300*26947304SEvan Yan PCI_REG_FUNC_G(reg->pci_phys_hi), reg_offset); 3301*26947304SEvan Yan 3302*26947304SEvan Yan hiword |= PCI_REG_REL_M; 3303*26947304SEvan Yan 3304*26947304SEvan Yan if (reg_offset == PCI_CONF_ROM) { 3305*26947304SEvan Yan hiword |= PCI_ADDR_MEM32; 3306*26947304SEvan Yan 3307*26947304SEvan Yan base = PCI_BASE_ROM_ADDR_M & base; 3308*26947304SEvan Yan } else { 3309*26947304SEvan Yan if ((PCI_BASE_SPACE_M & base) == PCI_BASE_SPACE_MEM) { 3310*26947304SEvan Yan if ((PCI_BASE_TYPE_M & base) == PCI_BASE_TYPE_MEM) { 3311*26947304SEvan Yan hiword |= PCI_ADDR_MEM32; 3312*26947304SEvan Yan } else if ((PCI_BASE_TYPE_M & base) 3313*26947304SEvan Yan == PCI_BASE_TYPE_ALL) { 3314*26947304SEvan Yan hiword |= PCI_ADDR_MEM64; 3315*26947304SEvan Yan } 3316*26947304SEvan Yan 3317*26947304SEvan Yan if (base & PCI_BASE_PREF_M) 3318*26947304SEvan Yan hiword |= PCI_REG_PF_M; 3319*26947304SEvan Yan 3320*26947304SEvan Yan base = PCI_BASE_M_ADDR_M & base; 3321*26947304SEvan Yan } else { 3322*26947304SEvan Yan hiword |= PCI_ADDR_IO; 3323*26947304SEvan Yan 3324*26947304SEvan Yan base = PCI_BASE_IO_ADDR_M & base; 3325*26947304SEvan Yan base_hi = 0; 3326*26947304SEvan Yan } 3327*26947304SEvan Yan } 3328*26947304SEvan Yan 3329*26947304SEvan Yan addition.pci_phys_hi = hiword; 3330*26947304SEvan Yan addition.pci_phys_mid = base_hi; 3331*26947304SEvan Yan addition.pci_phys_low = base; 3332*26947304SEvan Yan addition.pci_size_hi = 0; 3333*26947304SEvan Yan addition.pci_size_low = size; 3334*26947304SEvan Yan 3335*26947304SEvan Yan DEBUG3("updating BAR@off %x with %x,%x\n", reg_offset, hiword, size); 3336*26947304SEvan Yan 3337*26947304SEvan Yan kmem_free((caddr_t)reg, rlen); 3338*26947304SEvan Yan 3339*26947304SEvan Yan return (pcicfg_update_assigned_prop(dip, &addition)); 3340*26947304SEvan Yan } 3341*26947304SEvan Yan 3342*26947304SEvan Yan static void 3343*26947304SEvan Yan pcicfg_device_on(ddi_acc_handle_t config_handle) 3344*26947304SEvan Yan { 3345*26947304SEvan Yan /* 3346*26947304SEvan Yan * Enable memory, IO, and bus mastership 3347*26947304SEvan Yan * XXX should we enable parity, SERR#, 3348*26947304SEvan Yan * fast back-to-back, and addr. stepping? 3349*26947304SEvan Yan */ 3350*26947304SEvan Yan pci_config_put16(config_handle, PCI_CONF_COMM, 3351*26947304SEvan Yan pci_config_get16(config_handle, PCI_CONF_COMM) | 0x7); 3352*26947304SEvan Yan } 3353*26947304SEvan Yan 3354*26947304SEvan Yan static void 3355*26947304SEvan Yan pcicfg_device_off(ddi_acc_handle_t config_handle) 3356*26947304SEvan Yan { 3357*26947304SEvan Yan /* 3358*26947304SEvan Yan * Disable I/O and memory traffic through the bridge 3359*26947304SEvan Yan */ 3360*26947304SEvan Yan pci_config_put16(config_handle, PCI_CONF_COMM, 0x0); 3361*26947304SEvan Yan } 3362*26947304SEvan Yan 3363*26947304SEvan Yan /* 3364*26947304SEvan Yan * Setup the basic 1275 properties based on information found in the config 3365*26947304SEvan Yan * header of the PCI device 3366*26947304SEvan Yan */ 3367*26947304SEvan Yan static int 3368*26947304SEvan Yan pcicfg_set_standard_props(dev_info_t *dip, ddi_acc_handle_t config_handle, 3369*26947304SEvan Yan uint8_t pcie_dev) 3370*26947304SEvan Yan { 3371*26947304SEvan Yan int ret; 3372*26947304SEvan Yan uint16_t val, cap_ptr; 3373*26947304SEvan Yan uint32_t wordval; 3374*26947304SEvan Yan uint8_t byteval; 3375*26947304SEvan Yan 3376*26947304SEvan Yan /* These two exists only for non-bridges */ 3377*26947304SEvan Yan if (((pci_config_get8(config_handle, PCI_CONF_HEADER) 3378*26947304SEvan Yan & PCI_HEADER_TYPE_M) == PCI_HEADER_ZERO) && !pcie_dev) { 3379*26947304SEvan Yan byteval = pci_config_get8(config_handle, PCI_CONF_MIN_G); 3380*26947304SEvan Yan if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, 3381*26947304SEvan Yan "min-grant", byteval)) != DDI_SUCCESS) { 3382*26947304SEvan Yan return (ret); 3383*26947304SEvan Yan } 3384*26947304SEvan Yan 3385*26947304SEvan Yan byteval = pci_config_get8(config_handle, PCI_CONF_MAX_L); 3386*26947304SEvan Yan if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, 3387*26947304SEvan Yan "max-latency", byteval)) != DDI_SUCCESS) { 3388*26947304SEvan Yan return (ret); 3389*26947304SEvan Yan } 3390*26947304SEvan Yan } 3391*26947304SEvan Yan 3392*26947304SEvan Yan /* 3393*26947304SEvan Yan * These should always exist and have the value of the 3394*26947304SEvan Yan * corresponding register value 3395*26947304SEvan Yan */ 3396*26947304SEvan Yan val = pci_config_get16(config_handle, PCI_CONF_VENID); 3397*26947304SEvan Yan 3398*26947304SEvan Yan if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, 3399*26947304SEvan Yan "vendor-id", val)) != DDI_SUCCESS) { 3400*26947304SEvan Yan return (ret); 3401*26947304SEvan Yan } 3402*26947304SEvan Yan val = pci_config_get16(config_handle, PCI_CONF_DEVID); 3403*26947304SEvan Yan if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, 3404*26947304SEvan Yan "device-id", val)) != DDI_SUCCESS) { 3405*26947304SEvan Yan return (ret); 3406*26947304SEvan Yan } 3407*26947304SEvan Yan byteval = pci_config_get8(config_handle, PCI_CONF_REVID); 3408*26947304SEvan Yan if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, 3409*26947304SEvan Yan "revision-id", byteval)) != DDI_SUCCESS) { 3410*26947304SEvan Yan return (ret); 3411*26947304SEvan Yan } 3412*26947304SEvan Yan 3413*26947304SEvan Yan wordval = (pci_config_get16(config_handle, PCI_CONF_SUBCLASS)<< 8) | 3414*26947304SEvan Yan (pci_config_get8(config_handle, PCI_CONF_PROGCLASS)); 3415*26947304SEvan Yan 3416*26947304SEvan Yan if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, 3417*26947304SEvan Yan "class-code", wordval)) != DDI_SUCCESS) { 3418*26947304SEvan Yan return (ret); 3419*26947304SEvan Yan } 3420*26947304SEvan Yan /* devsel-speed starts at the 9th bit */ 3421*26947304SEvan Yan val = (pci_config_get16(config_handle, 3422*26947304SEvan Yan PCI_CONF_STAT) & PCI_STAT_DEVSELT) >> 9; 3423*26947304SEvan Yan if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, 3424*26947304SEvan Yan "devsel-speed", val)) != DDI_SUCCESS) { 3425*26947304SEvan Yan return (ret); 3426*26947304SEvan Yan } 3427*26947304SEvan Yan 3428*26947304SEvan Yan /* 3429*26947304SEvan Yan * The next three are bits set in the status register. The property is 3430*26947304SEvan Yan * present (but with no value other than its own existence) if the bit 3431*26947304SEvan Yan * is set, non-existent otherwise 3432*26947304SEvan Yan */ 3433*26947304SEvan Yan if ((!pcie_dev) && 3434*26947304SEvan Yan (pci_config_get16(config_handle, PCI_CONF_STAT) & 3435*26947304SEvan Yan PCI_STAT_FBBC)) { 3436*26947304SEvan Yan if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, 3437*26947304SEvan Yan "fast-back-to-back", 0)) != DDI_SUCCESS) { 3438*26947304SEvan Yan return (ret); 3439*26947304SEvan Yan } 3440*26947304SEvan Yan } 3441*26947304SEvan Yan if ((!pcie_dev) && 3442*26947304SEvan Yan (pci_config_get16(config_handle, PCI_CONF_STAT) & 3443*26947304SEvan Yan PCI_STAT_66MHZ)) { 3444*26947304SEvan Yan if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, 3445*26947304SEvan Yan "66mhz-capable", 0)) != DDI_SUCCESS) { 3446*26947304SEvan Yan return (ret); 3447*26947304SEvan Yan } 3448*26947304SEvan Yan } 3449*26947304SEvan Yan if (pci_config_get16(config_handle, PCI_CONF_STAT) & PCI_STAT_UDF) { 3450*26947304SEvan Yan if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, 3451*26947304SEvan Yan "udf-supported", 0)) != DDI_SUCCESS) { 3452*26947304SEvan Yan return (ret); 3453*26947304SEvan Yan } 3454*26947304SEvan Yan } 3455*26947304SEvan Yan 3456*26947304SEvan Yan /* 3457*26947304SEvan Yan * These next three are optional and are not present 3458*26947304SEvan Yan * if the corresponding register is zero. If the value 3459*26947304SEvan Yan * is non-zero then the property exists with the value 3460*26947304SEvan Yan * of the register. 3461*26947304SEvan Yan */ 3462*26947304SEvan Yan if ((val = pci_config_get16(config_handle, 3463*26947304SEvan Yan PCI_CONF_SUBVENID)) != 0) { 3464*26947304SEvan Yan if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, 3465*26947304SEvan Yan "subsystem-vendor-id", val)) != DDI_SUCCESS) { 3466*26947304SEvan Yan return (ret); 3467*26947304SEvan Yan } 3468*26947304SEvan Yan } 3469*26947304SEvan Yan if ((val = pci_config_get16(config_handle, 3470*26947304SEvan Yan PCI_CONF_SUBSYSID)) != 0) { 3471*26947304SEvan Yan if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, 3472*26947304SEvan Yan "subsystem-id", val)) != DDI_SUCCESS) { 3473*26947304SEvan Yan return (ret); 3474*26947304SEvan Yan } 3475*26947304SEvan Yan } 3476*26947304SEvan Yan if ((val = pci_config_get16(config_handle, 3477*26947304SEvan Yan PCI_CONF_CACHE_LINESZ)) != 0) { 3478*26947304SEvan Yan if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, 3479*26947304SEvan Yan "cache-line-size", val)) != DDI_SUCCESS) { 3480*26947304SEvan Yan return (ret); 3481*26947304SEvan Yan } 3482*26947304SEvan Yan } 3483*26947304SEvan Yan 3484*26947304SEvan Yan /* 3485*26947304SEvan Yan * If the Interrupt Pin register is non-zero then the 3486*26947304SEvan Yan * interrupts property exists 3487*26947304SEvan Yan */ 3488*26947304SEvan Yan if ((byteval = pci_config_get8(config_handle, PCI_CONF_IPIN)) != 0) { 3489*26947304SEvan Yan /* 3490*26947304SEvan Yan * If interrupt pin is non-zero, 3491*26947304SEvan Yan * record the interrupt line used 3492*26947304SEvan Yan */ 3493*26947304SEvan Yan if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, 3494*26947304SEvan Yan "interrupts", byteval)) != DDI_SUCCESS) { 3495*26947304SEvan Yan return (ret); 3496*26947304SEvan Yan } 3497*26947304SEvan Yan } 3498*26947304SEvan Yan 3499*26947304SEvan Yan ret = PCI_CAP_LOCATE(config_handle, PCI_CAP_ID_PCI_E, &cap_ptr); 3500*26947304SEvan Yan 3501*26947304SEvan Yan if (pcie_dev && (ret == DDI_SUCCESS)) { 3502*26947304SEvan Yan val = PCI_CAP_GET16(config_handle, NULL, cap_ptr, 3503*26947304SEvan Yan PCIE_PCIECAP) & PCIE_PCIECAP_SLOT_IMPL; 3504*26947304SEvan Yan /* if slot implemented, get physical slot number */ 3505*26947304SEvan Yan if (val) { 3506*26947304SEvan Yan wordval = (PCI_CAP_GET32(config_handle, NULL, 3507*26947304SEvan Yan cap_ptr, PCIE_SLOTCAP) >> 3508*26947304SEvan Yan PCIE_SLOTCAP_PHY_SLOT_NUM_SHIFT) & 3509*26947304SEvan Yan PCIE_SLOTCAP_PHY_SLOT_NUM_MASK; 3510*26947304SEvan Yan if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, 3511*26947304SEvan Yan dip, "physical-slot#", wordval)) 3512*26947304SEvan Yan != DDI_SUCCESS) { 3513*26947304SEvan Yan return (ret); 3514*26947304SEvan Yan } 3515*26947304SEvan Yan } 3516*26947304SEvan Yan } 3517*26947304SEvan Yan return (PCICFG_SUCCESS); 3518*26947304SEvan Yan } 3519*26947304SEvan Yan static int 3520*26947304SEvan Yan pcicfg_set_busnode_props(dev_info_t *dip, uint8_t pcie_device_type, 3521*26947304SEvan Yan int pbus, int sbus) 3522*26947304SEvan Yan { 3523*26947304SEvan Yan int ret; 3524*26947304SEvan Yan char device_type[8]; 3525*26947304SEvan Yan 3526*26947304SEvan Yan if (pcie_device_type) 3527*26947304SEvan Yan (void) strcpy(device_type, "pciex"); 3528*26947304SEvan Yan else 3529*26947304SEvan Yan (void) strcpy(device_type, "pci"); 3530*26947304SEvan Yan 3531*26947304SEvan Yan if ((ret = ndi_prop_update_string(DDI_DEV_T_NONE, dip, 3532*26947304SEvan Yan "device_type", device_type)) != DDI_SUCCESS) { 3533*26947304SEvan Yan return (ret); 3534*26947304SEvan Yan } 3535*26947304SEvan Yan if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, 3536*26947304SEvan Yan "#address-cells", 3)) != DDI_SUCCESS) { 3537*26947304SEvan Yan return (ret); 3538*26947304SEvan Yan } 3539*26947304SEvan Yan if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, 3540*26947304SEvan Yan "#size-cells", 2)) != DDI_SUCCESS) { 3541*26947304SEvan Yan return (ret); 3542*26947304SEvan Yan } 3543*26947304SEvan Yan 3544*26947304SEvan Yan /* 3545*26947304SEvan Yan * Create primary-bus and secondary-bus properties to be used 3546*26947304SEvan Yan * to restore bus numbers in the pcicfg_setup_bridge() routine. 3547*26947304SEvan Yan */ 3548*26947304SEvan Yan if (pbus != -1 && sbus != -1) { 3549*26947304SEvan Yan if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, 3550*26947304SEvan Yan "primary-bus", pbus)) != DDI_SUCCESS) { 3551*26947304SEvan Yan return (ret); 3552*26947304SEvan Yan } 3553*26947304SEvan Yan if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, 3554*26947304SEvan Yan "secondary-bus", sbus)) != DDI_SUCCESS) { 3555*26947304SEvan Yan return (ret); 3556*26947304SEvan Yan } 3557*26947304SEvan Yan } 3558*26947304SEvan Yan return (PCICFG_SUCCESS); 3559*26947304SEvan Yan } 3560*26947304SEvan Yan 3561*26947304SEvan Yan static int 3562*26947304SEvan Yan pcicfg_set_childnode_props(dev_info_t *dip, ddi_acc_handle_t config_handle, 3563*26947304SEvan Yan uint8_t pcie_dev) 3564*26947304SEvan Yan { 3565*26947304SEvan Yan 3566*26947304SEvan Yan int ret; 3567*26947304SEvan Yan char *name; 3568*26947304SEvan Yan char buffer[64], pprefix[8]; 3569*26947304SEvan Yan uint16_t classcode; 3570*26947304SEvan Yan uint8_t revid, pif, pclass, psubclass; 3571*26947304SEvan Yan char *compat[24]; 3572*26947304SEvan Yan int i; 3573*26947304SEvan Yan int n; 3574*26947304SEvan Yan uint16_t sub_vid, sub_sid, vid, did; 3575*26947304SEvan Yan 3576*26947304SEvan Yan /* set the property prefix based on the device type */ 3577*26947304SEvan Yan if (pcie_dev) 3578*26947304SEvan Yan (void) sprintf(pprefix, "pciex"); 3579*26947304SEvan Yan else 3580*26947304SEvan Yan (void) sprintf(pprefix, "pci"); 3581*26947304SEvan Yan sub_vid = pci_config_get16(config_handle, PCI_CONF_SUBVENID); 3582*26947304SEvan Yan sub_sid = pci_config_get16(config_handle, PCI_CONF_SUBSYSID); 3583*26947304SEvan Yan vid = pci_config_get16(config_handle, PCI_CONF_VENID); 3584*26947304SEvan Yan did = pci_config_get16(config_handle, PCI_CONF_DEVID); 3585*26947304SEvan Yan revid = pci_config_get8(config_handle, PCI_CONF_REVID); 3586*26947304SEvan Yan pif = pci_config_get8(config_handle, PCI_CONF_PROGCLASS); 3587*26947304SEvan Yan classcode = pci_config_get16(config_handle, PCI_CONF_SUBCLASS); 3588*26947304SEvan Yan pclass = pci_config_get8(config_handle, PCI_CONF_BASCLASS); 3589*26947304SEvan Yan psubclass = pci_config_get8(config_handle, PCI_CONF_SUBCLASS); 3590*26947304SEvan Yan 3591*26947304SEvan Yan /* 3592*26947304SEvan Yan * NOTE: These are for both a child and PCI-PCI bridge node 3593*26947304SEvan Yan */ 3594*26947304SEvan Yan 3595*26947304SEvan Yan /* 3596*26947304SEvan Yan * "name" property rule 3597*26947304SEvan Yan * -------------------- 3598*26947304SEvan Yan * 3599*26947304SEvan Yan * 3600*26947304SEvan Yan * | \svid | 3601*26947304SEvan Yan * | \ | 3602*26947304SEvan Yan * | \ | 3603*26947304SEvan Yan * | ssid \ | =0 | != 0 | 3604*26947304SEvan Yan * |------------|-----------------------|-----------------------| 3605*26947304SEvan Yan * | | | | 3606*26947304SEvan Yan * | =0 | vid,did | svid,ssid | 3607*26947304SEvan Yan * | | | | 3608*26947304SEvan Yan * |------------|-----------------------|-----------------------| 3609*26947304SEvan Yan * | | | | 3610*26947304SEvan Yan * | !=0 | svid,ssid | svid,ssid | 3611*26947304SEvan Yan * | | | | 3612*26947304SEvan Yan * |------------|-----------------------|-----------------------| 3613*26947304SEvan Yan * 3614*26947304SEvan Yan * where: 3615*26947304SEvan Yan * vid = vendor id 3616*26947304SEvan Yan * did = device id 3617*26947304SEvan Yan * svid = subsystem vendor id 3618*26947304SEvan Yan * ssid = subsystem id 3619*26947304SEvan Yan */ 3620*26947304SEvan Yan 3621*26947304SEvan Yan if ((sub_sid != 0) || (sub_vid != 0)) { 3622*26947304SEvan Yan (void) sprintf(buffer, "%s%x,%x", pprefix, sub_vid, sub_sid); 3623*26947304SEvan Yan } else { 3624*26947304SEvan Yan (void) sprintf(buffer, "%s%x,%x", pprefix, vid, did); 3625*26947304SEvan Yan } 3626*26947304SEvan Yan 3627*26947304SEvan Yan /* 3628*26947304SEvan Yan * In some environments, trying to use "generic" 1275 names is 3629*26947304SEvan Yan * not the convention. In those cases use the name as created 3630*26947304SEvan Yan * above. In all the rest of the cases, check to see if there 3631*26947304SEvan Yan * is a generic name first. 3632*26947304SEvan Yan */ 3633*26947304SEvan Yan #ifdef _DONT_USE_1275_GENERIC_NAMES 3634*26947304SEvan Yan name = buffer; 3635*26947304SEvan Yan #else 3636*26947304SEvan Yan if ((name = pcicfg_get_class_name(classcode)) == NULL) { 3637*26947304SEvan Yan /* 3638*26947304SEvan Yan * Set name to the above fabricated name 3639*26947304SEvan Yan */ 3640*26947304SEvan Yan name = buffer; 3641*26947304SEvan Yan } 3642*26947304SEvan Yan #endif 3643*26947304SEvan Yan 3644*26947304SEvan Yan /* 3645*26947304SEvan Yan * The node name field needs to be filled in with the name 3646*26947304SEvan Yan */ 3647*26947304SEvan Yan if (ndi_devi_set_nodename(dip, name, 0) != NDI_SUCCESS) { 3648*26947304SEvan Yan DEBUG0("Failed to set nodename for node\n"); 3649*26947304SEvan Yan return (PCICFG_FAILURE); 3650*26947304SEvan Yan } 3651*26947304SEvan Yan 3652*26947304SEvan Yan /* 3653*26947304SEvan Yan * Create the compatible property as an array of pointers 3654*26947304SEvan Yan * to strings. Start with the buffer created above. 3655*26947304SEvan Yan */ 3656*26947304SEvan Yan n = 0; 3657*26947304SEvan Yan compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP); 3658*26947304SEvan Yan (void) strcpy(compat[n++], buffer); 3659*26947304SEvan Yan 3660*26947304SEvan Yan /* 3661*26947304SEvan Yan * Setup 'compatible' as per the PCI2.1 bindings document. 3662*26947304SEvan Yan * pci[ex]VVVV,DDDD.SSSS.ssss.RR 3663*26947304SEvan Yan * pci[ex]VVVV,DDDD.SSSS.ssss 3664*26947304SEvan Yan * pciSSSS.ssss -> not created for PCIe as per PCIe bindings 3665*26947304SEvan Yan * pci[ex]VVVV,DDDD.RR 3666*26947304SEvan Yan * pci[ex]VVVV,DDDD 3667*26947304SEvan Yan * pci[ex]class,CCSSPP 3668*26947304SEvan Yan * pci[ex]class,CCSS 3669*26947304SEvan Yan */ 3670*26947304SEvan Yan 3671*26947304SEvan Yan /* pci[ex]VVVV,DDDD.SSSS.ssss.RR */ 3672*26947304SEvan Yan (void) sprintf(buffer, "%s%x,%x.%x.%x.%x", pprefix, vid, did, 3673*26947304SEvan Yan sub_vid, sub_sid, revid); 3674*26947304SEvan Yan compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP); 3675*26947304SEvan Yan (void) strcpy(compat[n++], buffer); 3676*26947304SEvan Yan 3677*26947304SEvan Yan /* pci[ex]VVVV,DDDD.SSSS.ssss */ 3678*26947304SEvan Yan (void) sprintf(buffer, "%s%x,%x.%x.%x", pprefix, vid, did, 3679*26947304SEvan Yan sub_vid, sub_sid); 3680*26947304SEvan Yan compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP); 3681*26947304SEvan Yan (void) strcpy(compat[n++], buffer); 3682*26947304SEvan Yan 3683*26947304SEvan Yan /* pciSSSS.ssss -> not created for PCIe as per PCIe bindings */ 3684*26947304SEvan Yan if (!pcie_dev) { 3685*26947304SEvan Yan (void) sprintf(buffer, "pci%x,%x", sub_vid, sub_sid); 3686*26947304SEvan Yan compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP); 3687*26947304SEvan Yan (void) strcpy(compat[n++], buffer); 3688*26947304SEvan Yan } 3689*26947304SEvan Yan 3690*26947304SEvan Yan /* pci[ex]VVVV,DDDD.RR */ 3691*26947304SEvan Yan (void) sprintf(buffer, "%s%x,%x.%x", pprefix, vid, did, revid); 3692*26947304SEvan Yan compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP); 3693*26947304SEvan Yan (void) strcpy(compat[n++], buffer); 3694*26947304SEvan Yan 3695*26947304SEvan Yan /* pci[ex]VVVV,DDDD */ 3696*26947304SEvan Yan (void) sprintf(buffer, "%s%x,%x", pprefix, vid, did); 3697*26947304SEvan Yan compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP); 3698*26947304SEvan Yan (void) strcpy(compat[n++], buffer); 3699*26947304SEvan Yan 3700*26947304SEvan Yan /* pci[ex]class,CCSSPP */ 3701*26947304SEvan Yan (void) sprintf(buffer, "%sclass,%02x%02x%02x", pprefix, 3702*26947304SEvan Yan pclass, psubclass, pif); 3703*26947304SEvan Yan compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP); 3704*26947304SEvan Yan (void) strcpy(compat[n++], buffer); 3705*26947304SEvan Yan 3706*26947304SEvan Yan /* pci[ex]class,CCSS */ 3707*26947304SEvan Yan (void) sprintf(buffer, "%sclass,%04x", pprefix, classcode); 3708*26947304SEvan Yan compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP); 3709*26947304SEvan Yan (void) strcpy(compat[n++], buffer); 3710*26947304SEvan Yan 3711*26947304SEvan Yan if ((ret = ndi_prop_update_string_array(DDI_DEV_T_NONE, dip, 3712*26947304SEvan Yan "compatible", (char **)compat, n)) != DDI_SUCCESS) { 3713*26947304SEvan Yan return (ret); 3714*26947304SEvan Yan } 3715*26947304SEvan Yan 3716*26947304SEvan Yan for (i = 0; i < n; i++) { 3717*26947304SEvan Yan kmem_free(compat[i], strlen(compat[i]) + 1); 3718*26947304SEvan Yan } 3719*26947304SEvan Yan 3720*26947304SEvan Yan DEBUG1("pcicfg_set_childnode_props - creating name=%s\n", name); 3721*26947304SEvan Yan if ((ret = ndi_prop_update_string(DDI_DEV_T_NONE, dip, 3722*26947304SEvan Yan "name", name)) != DDI_SUCCESS) { 3723*26947304SEvan Yan 3724*26947304SEvan Yan DEBUG0("pcicfg_set_childnode_props - Unable to create name " 3725*26947304SEvan Yan "property\n"); 3726*26947304SEvan Yan 3727*26947304SEvan Yan return (ret); 3728*26947304SEvan Yan } 3729*26947304SEvan Yan 3730*26947304SEvan Yan return (PCICFG_SUCCESS); 3731*26947304SEvan Yan } 3732*26947304SEvan Yan 3733*26947304SEvan Yan /* 3734*26947304SEvan Yan * Program the bus numbers into the bridge 3735*26947304SEvan Yan */ 3736*26947304SEvan Yan 3737*26947304SEvan Yan static void 3738*26947304SEvan Yan pcicfg_set_bus_numbers(ddi_acc_handle_t config_handle, 3739*26947304SEvan Yan uint_t primary, uint_t secondary, uint_t subordinate) 3740*26947304SEvan Yan { 3741*26947304SEvan Yan DEBUG3("Setting bridge bus-range %d,%d,%d\n", primary, secondary, 3742*26947304SEvan Yan subordinate); 3743*26947304SEvan Yan /* 3744*26947304SEvan Yan * Primary bus# 3745*26947304SEvan Yan */ 3746*26947304SEvan Yan pci_config_put8(config_handle, PCI_BCNF_PRIBUS, primary); 3747*26947304SEvan Yan 3748*26947304SEvan Yan /* 3749*26947304SEvan Yan * Secondary bus# 3750*26947304SEvan Yan */ 3751*26947304SEvan Yan pci_config_put8(config_handle, PCI_BCNF_SECBUS, secondary); 3752*26947304SEvan Yan 3753*26947304SEvan Yan /* 3754*26947304SEvan Yan * Subordinate bus# 3755*26947304SEvan Yan */ 3756*26947304SEvan Yan pci_config_put8(config_handle, PCI_BCNF_SUBBUS, subordinate); 3757*26947304SEvan Yan } 3758*26947304SEvan Yan 3759*26947304SEvan Yan /* 3760*26947304SEvan Yan * Put bridge registers into initial state 3761*26947304SEvan Yan */ 3762*26947304SEvan Yan static void 3763*26947304SEvan Yan pcicfg_setup_bridge(pcicfg_phdl_t *entry, 3764*26947304SEvan Yan ddi_acc_handle_t handle, dev_info_t *dip) 3765*26947304SEvan Yan { 3766*26947304SEvan Yan int pbus, sbus; 3767*26947304SEvan Yan 3768*26947304SEvan Yan /* 3769*26947304SEvan Yan * The highest bus seen during probing is the max-subordinate bus 3770*26947304SEvan Yan */ 3771*26947304SEvan Yan pci_config_put8(handle, PCI_BCNF_SUBBUS, entry->highest_bus); 3772*26947304SEvan Yan 3773*26947304SEvan Yan 3774*26947304SEvan Yan /* 3775*26947304SEvan Yan * If there exists more than 1 downstream bridge, it 3776*26947304SEvan Yan * will be reset by the below secondary bus reset which 3777*26947304SEvan Yan * will clear the bus numbers assumed to be programmed in 3778*26947304SEvan Yan * the pcicfg_probe_children() routine. We therefore restore 3779*26947304SEvan Yan * them here. 3780*26947304SEvan Yan */ 3781*26947304SEvan Yan if (pci_config_get8(handle, PCI_BCNF_SECBUS) == 0) { 3782*26947304SEvan Yan pbus = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 3783*26947304SEvan Yan DDI_PROP_DONTPASS, "primary-bus", -1); 3784*26947304SEvan Yan sbus = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 3785*26947304SEvan Yan DDI_PROP_DONTPASS, "secondary-bus", -1); 3786*26947304SEvan Yan if (pbus != -1 && sbus != -1) { 3787*26947304SEvan Yan pci_config_put8(handle, PCI_BCNF_PRIBUS, (uint_t)pbus); 3788*26947304SEvan Yan pci_config_put8(handle, PCI_BCNF_SECBUS, (uint_t)sbus); 3789*26947304SEvan Yan } else { 3790*26947304SEvan Yan cmn_err(CE_WARN, "Invalid Bridge number detected: \ 3791*26947304SEvan Yan %s%d: pbus = 0x%x, sbus = 0x%x", 3792*26947304SEvan Yan ddi_get_name(dip), ddi_get_instance(dip), pbus, 3793*26947304SEvan Yan sbus); 3794*26947304SEvan Yan } 3795*26947304SEvan Yan } 3796*26947304SEvan Yan 3797*26947304SEvan Yan /* 3798*26947304SEvan Yan * Reset the secondary bus 3799*26947304SEvan Yan */ 3800*26947304SEvan Yan pci_config_put16(handle, PCI_BCNF_BCNTRL, 3801*26947304SEvan Yan pci_config_get16(handle, PCI_BCNF_BCNTRL) | 0x40); 3802*26947304SEvan Yan 3803*26947304SEvan Yan drv_usecwait(100); 3804*26947304SEvan Yan 3805*26947304SEvan Yan pci_config_put16(handle, PCI_BCNF_BCNTRL, 3806*26947304SEvan Yan pci_config_get16(handle, PCI_BCNF_BCNTRL) & ~0x40); 3807*26947304SEvan Yan 3808*26947304SEvan Yan /* 3809*26947304SEvan Yan * Program the memory base register with the 3810*26947304SEvan Yan * start of the memory range 3811*26947304SEvan Yan */ 3812*26947304SEvan Yan pci_config_put16(handle, PCI_BCNF_MEM_BASE, 3813*26947304SEvan Yan PCICFG_HIWORD(PCICFG_LOADDR(entry->memory_last))); 3814*26947304SEvan Yan 3815*26947304SEvan Yan /* 3816*26947304SEvan Yan * Program the I/O base register with the start of the I/O range 3817*26947304SEvan Yan */ 3818*26947304SEvan Yan pci_config_put8(handle, PCI_BCNF_IO_BASE_LOW, 3819*26947304SEvan Yan PCICFG_HIBYTE(PCICFG_LOWORD(PCICFG_LOADDR(entry->io_last)))); 3820*26947304SEvan Yan pci_config_put16(handle, PCI_BCNF_IO_BASE_HI, 3821*26947304SEvan Yan PCICFG_HIWORD(PCICFG_LOADDR(entry->io_last))); 3822*26947304SEvan Yan 3823*26947304SEvan Yan /* 3824*26947304SEvan Yan * Clear status bits 3825*26947304SEvan Yan */ 3826*26947304SEvan Yan pci_config_put16(handle, PCI_BCNF_SEC_STATUS, 0xffff); 3827*26947304SEvan Yan 3828*26947304SEvan Yan /* 3829*26947304SEvan Yan * Turn off prefetchable range 3830*26947304SEvan Yan */ 3831*26947304SEvan Yan pci_config_put32(handle, PCI_BCNF_PF_BASE_LOW, 0x0000ffff); 3832*26947304SEvan Yan pci_config_put32(handle, PCI_BCNF_PF_BASE_HIGH, 0xffffffff); 3833*26947304SEvan Yan pci_config_put32(handle, PCI_BCNF_PF_LIMIT_HIGH, 0x0); 3834*26947304SEvan Yan 3835*26947304SEvan Yan /* 3836*26947304SEvan Yan * Needs to be set to this value 3837*26947304SEvan Yan */ 3838*26947304SEvan Yan pci_config_put8(handle, PCI_CONF_ILINE, 0xf); 3839*26947304SEvan Yan 3840*26947304SEvan Yan /* 3841*26947304SEvan Yan * After a Reset, we need to wait 2^25 clock cycles before the 3842*26947304SEvan Yan * first Configuration access. The worst case is 33MHz, which 3843*26947304SEvan Yan * is a 1 second wait. 3844*26947304SEvan Yan */ 3845*26947304SEvan Yan drv_usecwait(pcicfg_sec_reset_delay); 3846*26947304SEvan Yan 3847*26947304SEvan Yan } 3848*26947304SEvan Yan 3849*26947304SEvan Yan static void 3850*26947304SEvan Yan pcicfg_update_bridge(pcicfg_phdl_t *entry, 3851*26947304SEvan Yan ddi_acc_handle_t handle) 3852*26947304SEvan Yan { 3853*26947304SEvan Yan uint_t length; 3854*26947304SEvan Yan 3855*26947304SEvan Yan /* 3856*26947304SEvan Yan * Program the memory limit register with the end of the memory range 3857*26947304SEvan Yan */ 3858*26947304SEvan Yan 3859*26947304SEvan Yan DEBUG1("DOWN ROUNDED ===>[0x%x]\n", 3860*26947304SEvan Yan PCICFG_ROUND_DOWN(entry->memory_last, 3861*26947304SEvan Yan PCICFG_MEMGRAN)); 3862*26947304SEvan Yan 3863*26947304SEvan Yan pci_config_put16(handle, PCI_BCNF_MEM_LIMIT, 3864*26947304SEvan Yan PCICFG_HIWORD(PCICFG_LOADDR( 3865*26947304SEvan Yan PCICFG_ROUND_DOWN(entry->memory_last, 3866*26947304SEvan Yan PCICFG_MEMGRAN)))); 3867*26947304SEvan Yan /* 3868*26947304SEvan Yan * Since this is a bridge, the rest of this range will 3869*26947304SEvan Yan * be responded to by the bridge. We have to round up 3870*26947304SEvan Yan * so no other device claims it. 3871*26947304SEvan Yan */ 3872*26947304SEvan Yan if ((length = (PCICFG_ROUND_UP(entry->memory_last, 3873*26947304SEvan Yan PCICFG_MEMGRAN) - entry->memory_last)) > 0) { 3874*26947304SEvan Yan (void) pcicfg_get_mem(entry, length, NULL); 3875*26947304SEvan Yan DEBUG1("Added [0x%x]at the top of " 3876*26947304SEvan Yan "the bridge (mem)\n", length); 3877*26947304SEvan Yan } 3878*26947304SEvan Yan 3879*26947304SEvan Yan /* 3880*26947304SEvan Yan * Program the I/O limit register with the end of the I/O range 3881*26947304SEvan Yan */ 3882*26947304SEvan Yan pci_config_put8(handle, PCI_BCNF_IO_LIMIT_LOW, 3883*26947304SEvan Yan PCICFG_HIBYTE(PCICFG_LOWORD( 3884*26947304SEvan Yan PCICFG_LOADDR(PCICFG_ROUND_DOWN(entry->io_last, 3885*26947304SEvan Yan PCICFG_IOGRAN))))); 3886*26947304SEvan Yan 3887*26947304SEvan Yan pci_config_put16(handle, PCI_BCNF_IO_LIMIT_HI, 3888*26947304SEvan Yan PCICFG_HIWORD(PCICFG_LOADDR(PCICFG_ROUND_DOWN(entry->io_last, 3889*26947304SEvan Yan PCICFG_IOGRAN)))); 3890*26947304SEvan Yan 3891*26947304SEvan Yan /* 3892*26947304SEvan Yan * Same as above for I/O space. Since this is a 3893*26947304SEvan Yan * bridge, the rest of this range will be responded 3894*26947304SEvan Yan * to by the bridge. We have to round up so no 3895*26947304SEvan Yan * other device claims it. 3896*26947304SEvan Yan */ 3897*26947304SEvan Yan if ((length = (PCICFG_ROUND_UP(entry->io_last, 3898*26947304SEvan Yan PCICFG_IOGRAN) - entry->io_last)) > 0) { 3899*26947304SEvan Yan (void) pcicfg_get_io(entry, length, NULL); 3900*26947304SEvan Yan DEBUG1("Added [0x%x]at the top of " 3901*26947304SEvan Yan "the bridge (I/O)\n", length); 3902*26947304SEvan Yan } 3903*26947304SEvan Yan } 3904*26947304SEvan Yan 3905*26947304SEvan Yan /*ARGSUSED*/ 3906*26947304SEvan Yan static void 3907*26947304SEvan Yan pcicfg_disable_bridge_probe_err(dev_info_t *dip, ddi_acc_handle_t h, 3908*26947304SEvan Yan pcicfg_err_regs_t *regs) 3909*26947304SEvan Yan { 3910*26947304SEvan Yan uint16_t val; 3911*26947304SEvan Yan 3912*26947304SEvan Yan /* disable SERR generated in the context of Master Aborts. */ 3913*26947304SEvan Yan regs->cmd = val = pci_config_get16(h, PCI_CONF_COMM); 3914*26947304SEvan Yan val &= ~PCI_COMM_SERR_ENABLE; 3915*26947304SEvan Yan pci_config_put16(h, PCI_CONF_COMM, val); 3916*26947304SEvan Yan regs->bcntl = val = pci_config_get16(h, PCI_BCNF_BCNTRL); 3917*26947304SEvan Yan val &= ~PCI_BCNF_BCNTRL_SERR_ENABLE; 3918*26947304SEvan Yan pci_config_put16(h, PCI_BCNF_BCNTRL, val); 3919*26947304SEvan Yan /* clear any current pending errors */ 3920*26947304SEvan Yan pci_config_put16(h, PCI_CONF_STAT, PCI_STAT_S_TARG_AB| 3921*26947304SEvan Yan PCI_STAT_R_TARG_AB | PCI_STAT_R_MAST_AB | PCI_STAT_S_SYSERR); 3922*26947304SEvan Yan pci_config_put16(h, PCI_BCNF_SEC_STATUS, PCI_STAT_S_TARG_AB| 3923*26947304SEvan Yan PCI_STAT_R_TARG_AB | PCI_STAT_R_MAST_AB | PCI_STAT_S_SYSERR); 3924*26947304SEvan Yan /* if we are a PCIe device, disable the generation of UR, CE and NFE */ 3925*26947304SEvan Yan if (regs->pcie_dev) { 3926*26947304SEvan Yan uint16_t devctl; 3927*26947304SEvan Yan uint16_t cap_ptr; 3928*26947304SEvan Yan 3929*26947304SEvan Yan if ((PCI_CAP_LOCATE(h, PCI_CAP_ID_PCI_E, &cap_ptr)) == 3930*26947304SEvan Yan DDI_FAILURE) 3931*26947304SEvan Yan return; 3932*26947304SEvan Yan 3933*26947304SEvan Yan regs->pcie_cap_off = cap_ptr; 3934*26947304SEvan Yan regs->devctl = devctl = PCI_CAP_GET16(h, NULL, cap_ptr, 3935*26947304SEvan Yan PCIE_DEVCTL); 3936*26947304SEvan Yan devctl &= ~(PCIE_DEVCTL_UR_REPORTING_EN | 3937*26947304SEvan Yan PCIE_DEVCTL_CE_REPORTING_EN | 3938*26947304SEvan Yan PCIE_DEVCTL_NFE_REPORTING_EN | 3939*26947304SEvan Yan PCIE_DEVCTL_FE_REPORTING_EN); 3940*26947304SEvan Yan PCI_CAP_PUT16(h, NULL, cap_ptr, PCIE_DEVCTL, devctl); 3941*26947304SEvan Yan } 3942*26947304SEvan Yan } 3943*26947304SEvan Yan 3944*26947304SEvan Yan /*ARGSUSED*/ 3945*26947304SEvan Yan static void 3946*26947304SEvan Yan pcicfg_enable_bridge_probe_err(dev_info_t *dip, ddi_acc_handle_t h, 3947*26947304SEvan Yan pcicfg_err_regs_t *regs) 3948*26947304SEvan Yan { 3949*26947304SEvan Yan /* clear any pending errors */ 3950*26947304SEvan Yan pci_config_put16(h, PCI_CONF_STAT, PCI_STAT_S_TARG_AB| 3951*26947304SEvan Yan PCI_STAT_R_TARG_AB | PCI_STAT_R_MAST_AB | PCI_STAT_S_SYSERR); 3952*26947304SEvan Yan pci_config_put16(h, PCI_BCNF_SEC_STATUS, PCI_STAT_S_TARG_AB| 3953*26947304SEvan Yan PCI_STAT_R_TARG_AB | PCI_STAT_R_MAST_AB | PCI_STAT_S_SYSERR); 3954*26947304SEvan Yan 3955*26947304SEvan Yan /* restore original settings */ 3956*26947304SEvan Yan if (regs->pcie_dev) { 3957*26947304SEvan Yan pcie_clear_errors(dip); 3958*26947304SEvan Yan pci_config_put16(h, regs->pcie_cap_off + PCIE_DEVCTL, 3959*26947304SEvan Yan regs->devctl); 3960*26947304SEvan Yan } 3961*26947304SEvan Yan 3962*26947304SEvan Yan pci_config_put16(h, PCI_BCNF_BCNTRL, regs->bcntl); 3963*26947304SEvan Yan pci_config_put16(h, PCI_CONF_COMM, regs->cmd); 3964*26947304SEvan Yan 3965*26947304SEvan Yan } 3966*26947304SEvan Yan 3967*26947304SEvan Yan static int 3968*26947304SEvan Yan pcicfg_probe_children(dev_info_t *parent, uint_t bus, uint_t device, 3969*26947304SEvan Yan uint_t func, uint_t *highest_bus, pcicfg_flags_t flags) 3970*26947304SEvan Yan { 3971*26947304SEvan Yan dev_info_t *new_child; 3972*26947304SEvan Yan ddi_acc_handle_t config_handle; 3973*26947304SEvan Yan uint8_t header_type, pcie_dev = 0; 3974*26947304SEvan Yan int ret; 3975*26947304SEvan Yan pcicfg_err_regs_t regs; 3976*26947304SEvan Yan 3977*26947304SEvan Yan /* 3978*26947304SEvan Yan * This node will be put immediately below 3979*26947304SEvan Yan * "parent". Allocate a blank device node. It will either 3980*26947304SEvan Yan * be filled in or freed up based on further probing. 3981*26947304SEvan Yan */ 3982*26947304SEvan Yan /* 3983*26947304SEvan Yan * Note: in usr/src/uts/common/io/hotplug/pcicfg/pcicfg.c 3984*26947304SEvan Yan * ndi_devi_alloc() is called as ndi_devi_alloc_sleep() 3985*26947304SEvan Yan */ 3986*26947304SEvan Yan if (ndi_devi_alloc(parent, DEVI_PSEUDO_NEXNAME, 3987*26947304SEvan Yan (pnode_t)DEVI_SID_NODEID, &new_child) 3988*26947304SEvan Yan != NDI_SUCCESS) { 3989*26947304SEvan Yan DEBUG0("pcicfg_probe_children(): Failed to alloc child node\n"); 3990*26947304SEvan Yan return (PCICFG_FAILURE); 3991*26947304SEvan Yan } 3992*26947304SEvan Yan 3993*26947304SEvan Yan if (pcicfg_add_config_reg(new_child, bus, 3994*26947304SEvan Yan device, func) != DDI_SUCCESS) { 3995*26947304SEvan Yan DEBUG0("pcicfg_probe_children():" 3996*26947304SEvan Yan "Failed to add candidate REG\n"); 3997*26947304SEvan Yan goto failedconfig; 3998*26947304SEvan Yan } 3999*26947304SEvan Yan 4000*26947304SEvan Yan if ((ret = pcicfg_config_setup(new_child, &config_handle)) 4001*26947304SEvan Yan != PCICFG_SUCCESS) { 4002*26947304SEvan Yan if (ret == PCICFG_NODEVICE) { 4003*26947304SEvan Yan (void) ndi_devi_free(new_child); 4004*26947304SEvan Yan return (ret); 4005*26947304SEvan Yan } 4006*26947304SEvan Yan DEBUG0("pcicfg_probe_children():" 4007*26947304SEvan Yan "Failed to setup config space\n"); 4008*26947304SEvan Yan goto failedconfig; 4009*26947304SEvan Yan } 4010*26947304SEvan Yan 4011*26947304SEvan Yan /* 4012*26947304SEvan Yan * As soon as we have access to config space, 4013*26947304SEvan Yan * turn off device. It will get turned on 4014*26947304SEvan Yan * later (after memory is assigned). 4015*26947304SEvan Yan */ 4016*26947304SEvan Yan (void) pcicfg_device_off(config_handle); 4017*26947304SEvan Yan 4018*26947304SEvan Yan /* check if we are PCIe device */ 4019*26947304SEvan Yan if (pcicfg_pcie_dev(new_child, PCICFG_DEVICE_TYPE_PCIE, ®s) 4020*26947304SEvan Yan == DDI_SUCCESS) { 4021*26947304SEvan Yan DEBUG0("PCIe device detected\n"); 4022*26947304SEvan Yan pcie_dev = 1; 4023*26947304SEvan Yan } 4024*26947304SEvan Yan 4025*26947304SEvan Yan /* 4026*26947304SEvan Yan * Set 1275 properties common to all devices 4027*26947304SEvan Yan */ 4028*26947304SEvan Yan if (pcicfg_set_standard_props(new_child, config_handle, 4029*26947304SEvan Yan pcie_dev) != PCICFG_SUCCESS) { 4030*26947304SEvan Yan DEBUG0("Failed to set standard properties\n"); 4031*26947304SEvan Yan goto failedchild; 4032*26947304SEvan Yan } 4033*26947304SEvan Yan 4034*26947304SEvan Yan /* 4035*26947304SEvan Yan * Child node properties NOTE: Both for PCI-PCI bridge and child node 4036*26947304SEvan Yan */ 4037*26947304SEvan Yan if (pcicfg_set_childnode_props(new_child, config_handle, 4038*26947304SEvan Yan pcie_dev) != PCICFG_SUCCESS) { 4039*26947304SEvan Yan goto failedchild; 4040*26947304SEvan Yan } 4041*26947304SEvan Yan 4042*26947304SEvan Yan header_type = pci_config_get8(config_handle, PCI_CONF_HEADER); 4043*26947304SEvan Yan 4044*26947304SEvan Yan /* 4045*26947304SEvan Yan * If this is not a multi-function card only probe function zero. 4046*26947304SEvan Yan */ 4047*26947304SEvan Yan if ((!(header_type & PCI_HEADER_MULTI)) && (func != 0)) { 4048*26947304SEvan Yan 4049*26947304SEvan Yan (void) pcicfg_config_teardown(&config_handle); 4050*26947304SEvan Yan (void) ndi_devi_free(new_child); 4051*26947304SEvan Yan return (PCICFG_NODEVICE); 4052*26947304SEvan Yan } 4053*26947304SEvan Yan 4054*26947304SEvan Yan DEBUG1("---Vendor ID = [0x%x]\n", 4055*26947304SEvan Yan pci_config_get16(config_handle, PCI_CONF_VENID)); 4056*26947304SEvan Yan DEBUG1("---Device ID = [0x%x]\n", 4057*26947304SEvan Yan pci_config_get16(config_handle, PCI_CONF_DEVID)); 4058*26947304SEvan Yan 4059*26947304SEvan Yan /* 4060*26947304SEvan Yan * Attach the child to its parent 4061*26947304SEvan Yan */ 4062*26947304SEvan Yan (void) i_ndi_config_node(new_child, DS_LINKED, 0); 4063*26947304SEvan Yan 4064*26947304SEvan Yan if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) { 4065*26947304SEvan Yan 4066*26947304SEvan Yan DEBUG3("--Bridge found bus [0x%x] device" 4067*26947304SEvan Yan "[0x%x] func [0x%x]\n", bus, device, func); 4068*26947304SEvan Yan 4069*26947304SEvan Yan /* Only support read-only probe for leaf device */ 4070*26947304SEvan Yan if (flags & PCICFG_FLAG_READ_ONLY) 4071*26947304SEvan Yan goto failedchild; 4072*26947304SEvan Yan 4073*26947304SEvan Yan if (pcicfg_probe_bridge(new_child, config_handle, 4074*26947304SEvan Yan bus, highest_bus) != PCICFG_SUCCESS) { 4075*26947304SEvan Yan (void) pcicfg_free_bridge_resources(new_child); 4076*26947304SEvan Yan goto failedchild; 4077*26947304SEvan Yan } 4078*26947304SEvan Yan 4079*26947304SEvan Yan } else { 4080*26947304SEvan Yan 4081*26947304SEvan Yan DEBUG3("--Leaf device found bus [0x%x] device" 4082*26947304SEvan Yan "[0x%x] func [0x%x]\n", 4083*26947304SEvan Yan bus, device, func); 4084*26947304SEvan Yan 4085*26947304SEvan Yan if (flags & PCICFG_FLAG_READ_ONLY) { 4086*26947304SEvan Yan /* 4087*26947304SEvan Yan * with read-only probe, don't do any resource 4088*26947304SEvan Yan * allocation, just read the BARs and update props. 4089*26947304SEvan Yan */ 4090*26947304SEvan Yan ret = pcicfg_populate_props_from_bar(new_child, 4091*26947304SEvan Yan config_handle); 4092*26947304SEvan Yan if (ret != PCICFG_SUCCESS) 4093*26947304SEvan Yan goto failedchild; 4094*26947304SEvan Yan 4095*26947304SEvan Yan /* 4096*26947304SEvan Yan * for readonly probe "assigned-addresses" property 4097*26947304SEvan Yan * has already been setup by reading the BAR, here 4098*26947304SEvan Yan * just substract the resource from its parent here. 4099*26947304SEvan Yan */ 4100*26947304SEvan Yan ret = pcicfg_device_assign_readonly(new_child); 4101*26947304SEvan Yan if (ret != PCICFG_SUCCESS) { 4102*26947304SEvan Yan (void) pcicfg_free_device_resources(new_child, 4103*26947304SEvan Yan flags); 4104*26947304SEvan Yan goto failedchild; 4105*26947304SEvan Yan } 4106*26947304SEvan Yan } else { 4107*26947304SEvan Yan /* 4108*26947304SEvan Yan * update "reg" property by sizing the BARs. 4109*26947304SEvan Yan */ 4110*26947304SEvan Yan ret = pcicfg_populate_reg_props(new_child, 4111*26947304SEvan Yan config_handle); 4112*26947304SEvan Yan if (ret != PCICFG_SUCCESS) 4113*26947304SEvan Yan goto failedchild; 4114*26947304SEvan Yan 4115*26947304SEvan Yan /* now allocate & program the resources */ 4116*26947304SEvan Yan ret = pcicfg_device_assign(new_child); 4117*26947304SEvan Yan if (ret != PCICFG_SUCCESS) { 4118*26947304SEvan Yan (void) pcicfg_free_device_resources(new_child, 4119*26947304SEvan Yan flags); 4120*26947304SEvan Yan goto failedchild; 4121*26947304SEvan Yan } 4122*26947304SEvan Yan } 4123*26947304SEvan Yan 4124*26947304SEvan Yan (void) ndi_devi_bind_driver(new_child, 0); 4125*26947304SEvan Yan } 4126*26947304SEvan Yan 4127*26947304SEvan Yan (void) pcicfg_config_teardown(&config_handle); 4128*26947304SEvan Yan return (PCICFG_SUCCESS); 4129*26947304SEvan Yan 4130*26947304SEvan Yan failedchild: 4131*26947304SEvan Yan 4132*26947304SEvan Yan (void) pcicfg_config_teardown(&config_handle); 4133*26947304SEvan Yan 4134*26947304SEvan Yan failedconfig: 4135*26947304SEvan Yan 4136*26947304SEvan Yan (void) ndi_devi_free(new_child); 4137*26947304SEvan Yan return (PCICFG_FAILURE); 4138*26947304SEvan Yan } 4139*26947304SEvan Yan 4140*26947304SEvan Yan /* 4141*26947304SEvan Yan * Sizing the BARs and update "reg" property 4142*26947304SEvan Yan */ 4143*26947304SEvan Yan static int 4144*26947304SEvan Yan pcicfg_populate_reg_props(dev_info_t *new_child, 4145*26947304SEvan Yan ddi_acc_handle_t config_handle) 4146*26947304SEvan Yan { 4147*26947304SEvan Yan int i; 4148*26947304SEvan Yan uint32_t request; 4149*26947304SEvan Yan 4150*26947304SEvan Yan i = PCI_CONF_BASE0; 4151*26947304SEvan Yan 4152*26947304SEvan Yan while (i <= PCI_CONF_BASE5) { 4153*26947304SEvan Yan 4154*26947304SEvan Yan pci_config_put32(config_handle, i, 0xffffffff); 4155*26947304SEvan Yan 4156*26947304SEvan Yan request = pci_config_get32(config_handle, i); 4157*26947304SEvan Yan /* 4158*26947304SEvan Yan * If its a zero length, don't do 4159*26947304SEvan Yan * any programming. 4160*26947304SEvan Yan */ 4161*26947304SEvan Yan if (request != 0) { 4162*26947304SEvan Yan /* 4163*26947304SEvan Yan * Add to the "reg" property 4164*26947304SEvan Yan */ 4165*26947304SEvan Yan if (pcicfg_update_reg_prop(new_child, 4166*26947304SEvan Yan request, i) != PCICFG_SUCCESS) { 4167*26947304SEvan Yan goto failedchild; 4168*26947304SEvan Yan } 4169*26947304SEvan Yan } else { 4170*26947304SEvan Yan DEBUG1("BASE register [0x%x] asks for " 4171*26947304SEvan Yan "[0x0]=[0x0](32)\n", i); 4172*26947304SEvan Yan i += 4; 4173*26947304SEvan Yan continue; 4174*26947304SEvan Yan } 4175*26947304SEvan Yan 4176*26947304SEvan Yan /* 4177*26947304SEvan Yan * Increment by eight if it is 64 bit address space 4178*26947304SEvan Yan */ 4179*26947304SEvan Yan if ((PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_ALL) { 4180*26947304SEvan Yan DEBUG3("BASE register [0x%x] asks for " 4181*26947304SEvan Yan "[0x%x]=[0x%x] (64)\n", 4182*26947304SEvan Yan i, request, 4183*26947304SEvan Yan (~(PCI_BASE_M_ADDR_M & request))+1) 4184*26947304SEvan Yan i += 8; 4185*26947304SEvan Yan } else { 4186*26947304SEvan Yan DEBUG3("BASE register [0x%x] asks for " 4187*26947304SEvan Yan "[0x%x]=[0x%x](32)\n", 4188*26947304SEvan Yan i, request, 4189*26947304SEvan Yan (~(PCI_BASE_M_ADDR_M & request))+1) 4190*26947304SEvan Yan i += 4; 4191*26947304SEvan Yan } 4192*26947304SEvan Yan } 4193*26947304SEvan Yan 4194*26947304SEvan Yan /* 4195*26947304SEvan Yan * Get the ROM size and create register for it 4196*26947304SEvan Yan */ 4197*26947304SEvan Yan pci_config_put32(config_handle, PCI_CONF_ROM, 0xfffffffe); 4198*26947304SEvan Yan 4199*26947304SEvan Yan request = pci_config_get32(config_handle, PCI_CONF_ROM); 4200*26947304SEvan Yan /* 4201*26947304SEvan Yan * If its a zero length, don't do 4202*26947304SEvan Yan * any programming. 4203*26947304SEvan Yan */ 4204*26947304SEvan Yan 4205*26947304SEvan Yan if (request != 0) { 4206*26947304SEvan Yan DEBUG3("BASE register [0x%x] asks for [0x%x]=[0x%x]\n", 4207*26947304SEvan Yan PCI_CONF_ROM, request, 4208*26947304SEvan Yan (~(PCI_BASE_ROM_ADDR_M & request))+1); 4209*26947304SEvan Yan /* 4210*26947304SEvan Yan * Add to the "reg" property 4211*26947304SEvan Yan */ 4212*26947304SEvan Yan if (pcicfg_update_reg_prop(new_child, 4213*26947304SEvan Yan request, PCI_CONF_ROM) != PCICFG_SUCCESS) { 4214*26947304SEvan Yan goto failedchild; 4215*26947304SEvan Yan } 4216*26947304SEvan Yan } 4217*26947304SEvan Yan 4218*26947304SEvan Yan 4219*26947304SEvan Yan return (PCICFG_SUCCESS); 4220*26947304SEvan Yan 4221*26947304SEvan Yan failedchild: 4222*26947304SEvan Yan return (PCICFG_FAILURE); 4223*26947304SEvan Yan } 4224*26947304SEvan Yan 4225*26947304SEvan Yan static int 4226*26947304SEvan Yan pcicfg_fcode_probe(dev_info_t *parent, uint_t bus, uint_t device, 4227*26947304SEvan Yan uint_t func, uint_t *highest_bus, pcicfg_flags_t flags) 4228*26947304SEvan Yan { 4229*26947304SEvan Yan dev_info_t *new_child; 4230*26947304SEvan Yan int8_t header_type; 4231*26947304SEvan Yan int ret; 4232*26947304SEvan Yan ddi_acc_handle_t h, ph; 4233*26947304SEvan Yan int error = 0; 4234*26947304SEvan Yan extern int pcicfg_dont_interpret; 4235*26947304SEvan Yan pcicfg_err_regs_t parent_regs, regs; 4236*26947304SEvan Yan char *status_prop = NULL; 4237*26947304SEvan Yan #ifdef PCICFG_INTERPRET_FCODE 4238*26947304SEvan Yan struct pci_ops_bus_args po; 4239*26947304SEvan Yan fco_handle_t c; 4240*26947304SEvan Yan char unit_address[64]; 4241*26947304SEvan Yan int fcode_size = 0; 4242*26947304SEvan Yan uchar_t *fcode_addr; 4243*26947304SEvan Yan uint64_t mem_answer, mem_alen; 4244*26947304SEvan Yan pci_regspec_t p; 4245*26947304SEvan Yan int32_t request; 4246*26947304SEvan Yan ndi_ra_request_t req; 4247*26947304SEvan Yan int16_t vendor_id, device_id; 4248*26947304SEvan Yan #endif 4249*26947304SEvan Yan 4250*26947304SEvan Yan /* 4251*26947304SEvan Yan * check if our parent is of type pciex. 4252*26947304SEvan Yan * if so, program config space to disable error msgs during probe. 4253*26947304SEvan Yan */ 4254*26947304SEvan Yan if (pcicfg_pcie_dev(parent, PCICFG_DEVICE_TYPE_PCIE, &parent_regs) 4255*26947304SEvan Yan == DDI_SUCCESS) { 4256*26947304SEvan Yan DEBUG0("PCI/PCIe parent detected. Disable errors.\n"); 4257*26947304SEvan Yan /* 4258*26947304SEvan Yan * disable parent generating URs or SERR#s during probing 4259*26947304SEvan Yan * alone. 4260*26947304SEvan Yan */ 4261*26947304SEvan Yan if (pci_config_setup(parent, &ph) != DDI_SUCCESS) 4262*26947304SEvan Yan return (DDI_FAILURE); 4263*26947304SEvan Yan 4264*26947304SEvan Yan if ((flags & PCICFG_FLAG_READ_ONLY) == 0) { 4265*26947304SEvan Yan pcicfg_disable_bridge_probe_err(parent, 4266*26947304SEvan Yan ph, &parent_regs); 4267*26947304SEvan Yan } 4268*26947304SEvan Yan } 4269*26947304SEvan Yan 4270*26947304SEvan Yan /* 4271*26947304SEvan Yan * This node will be put immediately below 4272*26947304SEvan Yan * "parent". Allocate a blank device node. It will either 4273*26947304SEvan Yan * be filled in or freed up based on further probing. 4274*26947304SEvan Yan */ 4275*26947304SEvan Yan 4276*26947304SEvan Yan if (ndi_devi_alloc(parent, DEVI_PSEUDO_NEXNAME, 4277*26947304SEvan Yan (pnode_t)DEVI_SID_NODEID, &new_child) 4278*26947304SEvan Yan != NDI_SUCCESS) { 4279*26947304SEvan Yan DEBUG0("pcicfg_fcode_probe(): Failed to alloc child node\n"); 4280*26947304SEvan Yan /* return (PCICFG_FAILURE); */ 4281*26947304SEvan Yan ret = PCICFG_FAILURE; 4282*26947304SEvan Yan goto failed2; 4283*26947304SEvan Yan } 4284*26947304SEvan Yan 4285*26947304SEvan Yan /* 4286*26947304SEvan Yan * Create a dummy reg property. This will be replaced with 4287*26947304SEvan Yan * a real reg property when fcode completes or if we need to 4288*26947304SEvan Yan * produce one by hand. 4289*26947304SEvan Yan */ 4290*26947304SEvan Yan if (pcicfg_add_config_reg(new_child, bus, 4291*26947304SEvan Yan device, func) != DDI_SUCCESS) { 4292*26947304SEvan Yan ret = PCICFG_FAILURE; 4293*26947304SEvan Yan goto failed3; 4294*26947304SEvan Yan } 4295*26947304SEvan Yan #ifdef EFCODE21554 4296*26947304SEvan Yan if ((ret = pcicfg_config_setup(new_child, &h)) 4297*26947304SEvan Yan != PCICFG_SUCCESS) { 4298*26947304SEvan Yan DEBUG0("pcicfg_fcode_probe():" 4299*26947304SEvan Yan "Failed to setup config space\n"); 4300*26947304SEvan Yan ret = PCICFG_NODEVICE; 4301*26947304SEvan Yan goto failed3; 4302*26947304SEvan Yan } 4303*26947304SEvan Yan 4304*26947304SEvan Yan #else 4305*26947304SEvan Yan p.pci_phys_hi = PCICFG_MAKE_REG_HIGH(bus, device, func, 0); 4306*26947304SEvan Yan p.pci_phys_mid = p.pci_phys_low = 0; 4307*26947304SEvan Yan p.pci_size_hi = p.pci_size_low = 0; 4308*26947304SEvan Yan 4309*26947304SEvan Yan /* 4310*26947304SEvan Yan * Map in configuration space (temporarily) 4311*26947304SEvan Yan */ 4312*26947304SEvan Yan acc.devacc_attr_version = DDI_DEVICE_ATTR_V0; 4313*26947304SEvan Yan acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 4314*26947304SEvan Yan acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 4315*26947304SEvan Yan 4316*26947304SEvan Yan if (pcicfg_map_phys(new_child, &p, &virt, &acc, &h)) { 4317*26947304SEvan Yan DEBUG0("pcicfg_fcode_probe():" 4318*26947304SEvan Yan "Failed to setup config space\n"); 4319*26947304SEvan Yan ret = PCICFG_NODEVICE; 4320*26947304SEvan Yan goto failed3; 4321*26947304SEvan Yan } 4322*26947304SEvan Yan 4323*26947304SEvan Yan /* 4324*26947304SEvan Yan * First use ddi_peek16 so that if there is not a device there, 4325*26947304SEvan Yan * a bus error will not cause a panic. 4326*26947304SEvan Yan */ 4327*26947304SEvan Yan v = virt + PCI_CONF_VENID; 4328*26947304SEvan Yan if (ddi_peek16(new_child, (int16_t *)v, &vendor_id)) { 4329*26947304SEvan Yan DEBUG0("Can not read Vendor ID"); 4330*26947304SEvan Yan pcicfg_unmap_phys(&h, &p); 4331*26947304SEvan Yan ret = PCICFG_NODEVICE; 4332*26947304SEvan Yan goto failed3; 4333*26947304SEvan Yan } 4334*26947304SEvan Yan #endif 4335*26947304SEvan Yan DEBUG0("fcode_probe: conf space mapped.\n"); 4336*26947304SEvan Yan /* 4337*26947304SEvan Yan * As soon as we have access to config space, 4338*26947304SEvan Yan * turn off device. It will get turned on 4339*26947304SEvan Yan * later (after memory is assigned). 4340*26947304SEvan Yan */ 4341*26947304SEvan Yan (void) pcicfg_device_off(h); 4342*26947304SEvan Yan 4343*26947304SEvan Yan /* check if we are PCIe device */ 4344*26947304SEvan Yan if (pcicfg_pcie_dev(new_child, PCICFG_DEVICE_TYPE_PCIE, ®s) 4345*26947304SEvan Yan == DDI_SUCCESS) { 4346*26947304SEvan Yan /*EMPTY*/ 4347*26947304SEvan Yan DEBUG0("PCI/PCIe device detected\n"); 4348*26947304SEvan Yan } 4349*26947304SEvan Yan 4350*26947304SEvan Yan /* 4351*26947304SEvan Yan * Set 1275 properties common to all devices 4352*26947304SEvan Yan */ 4353*26947304SEvan Yan if (pcicfg_set_standard_props(new_child, 4354*26947304SEvan Yan h, regs.pcie_dev) != PCICFG_SUCCESS) { 4355*26947304SEvan Yan DEBUG0("Failed to set standard properties\n"); 4356*26947304SEvan Yan goto failed; 4357*26947304SEvan Yan } 4358*26947304SEvan Yan 4359*26947304SEvan Yan /* 4360*26947304SEvan Yan * Child node properties NOTE: Both for PCI-PCI bridge and child node 4361*26947304SEvan Yan */ 4362*26947304SEvan Yan if (pcicfg_set_childnode_props(new_child, 4363*26947304SEvan Yan h, regs.pcie_dev) != PCICFG_SUCCESS) { 4364*26947304SEvan Yan ret = PCICFG_FAILURE; 4365*26947304SEvan Yan goto failed; 4366*26947304SEvan Yan } 4367*26947304SEvan Yan 4368*26947304SEvan Yan header_type = pci_config_get8(h, PCI_CONF_HEADER); 4369*26947304SEvan Yan 4370*26947304SEvan Yan /* 4371*26947304SEvan Yan * If this is not a multi-function card only probe function zero. 4372*26947304SEvan Yan */ 4373*26947304SEvan Yan if (!(header_type & PCI_HEADER_MULTI) && (func > 0)) { 4374*26947304SEvan Yan 4375*26947304SEvan Yan ret = PCICFG_NODEVICE; 4376*26947304SEvan Yan goto failed; 4377*26947304SEvan Yan } 4378*26947304SEvan Yan 4379*26947304SEvan Yan if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) { 4380*26947304SEvan Yan 4381*26947304SEvan Yan /* 4382*26947304SEvan Yan * XXX - Transparent bridges are handled differently 4383*26947304SEvan Yan * than other devices with regards to fcode. Since 4384*26947304SEvan Yan * no transparent bridge currently ships with fcode, 4385*26947304SEvan Yan * there is no reason to try to extract it from its rom 4386*26947304SEvan Yan * or call the fcode interpreter to try to load a drop-in. 4387*26947304SEvan Yan * If fcode is developed to handle transparent bridges, 4388*26947304SEvan Yan * this code will have to change. 4389*26947304SEvan Yan */ 4390*26947304SEvan Yan 4391*26947304SEvan Yan DEBUG3("--Bridge found bus [0x%x] device" 4392*26947304SEvan Yan "[0x%x] func [0x%x]\n", bus, device, func); 4393*26947304SEvan Yan 4394*26947304SEvan Yan /* Only support read-only probe for leaf device */ 4395*26947304SEvan Yan if (flags & PCICFG_FLAG_READ_ONLY) 4396*26947304SEvan Yan goto failed; 4397*26947304SEvan Yan 4398*26947304SEvan Yan if ((ret = pcicfg_probe_bridge(new_child, h, 4399*26947304SEvan Yan bus, highest_bus)) != PCICFG_SUCCESS) 4400*26947304SEvan Yan (void) pcicfg_free_bridge_resources(new_child); 4401*26947304SEvan Yan goto done; 4402*26947304SEvan Yan } else { 4403*26947304SEvan Yan 4404*26947304SEvan Yan DEBUG3("--Leaf device found bus [0x%x] device" 4405*26947304SEvan Yan "[0x%x] func [0x%x]\n", 4406*26947304SEvan Yan bus, device, func); 4407*26947304SEvan Yan 4408*26947304SEvan Yan /* 4409*26947304SEvan Yan * link in tree, but don't bind driver 4410*26947304SEvan Yan * We don't have compatible property yet 4411*26947304SEvan Yan */ 4412*26947304SEvan Yan (void) i_ndi_config_node(new_child, DS_LINKED, 0); 4413*26947304SEvan Yan 4414*26947304SEvan Yan /* XXX for now, don't run Fcode in read-only probe. */ 4415*26947304SEvan Yan if (flags & PCICFG_FLAG_READ_ONLY) 4416*26947304SEvan Yan goto no_fcode; 4417*26947304SEvan Yan 4418*26947304SEvan Yan if (pci_config_get8(h, PCI_CONF_IPIN)) { 4419*26947304SEvan Yan pci_config_put8(h, PCI_CONF_ILINE, 0xf); 4420*26947304SEvan Yan } 4421*26947304SEvan Yan 4422*26947304SEvan Yan #ifdef PCICFG_INTERPRET_FCODE 4423*26947304SEvan Yan /* 4424*26947304SEvan Yan * Some platforms (x86) don't run fcode, so don't interpret 4425*26947304SEvan Yan * fcode that might be in the ROM. 4426*26947304SEvan Yan */ 4427*26947304SEvan Yan if (pcicfg_dont_interpret == 0) { 4428*26947304SEvan Yan 4429*26947304SEvan Yan /* This platform supports fcode */ 4430*26947304SEvan Yan 4431*26947304SEvan Yan vendor_id = pci_config_get16(h, PCI_CONF_VENID); 4432*26947304SEvan Yan device_id = pci_config_get16(h, PCI_CONF_DEVID); 4433*26947304SEvan Yan 4434*26947304SEvan Yan /* 4435*26947304SEvan Yan * Get the ROM size and create register for it 4436*26947304SEvan Yan */ 4437*26947304SEvan Yan pci_config_put32(h, PCI_CONF_ROM, 0xfffffffe); 4438*26947304SEvan Yan 4439*26947304SEvan Yan request = pci_config_get32(h, PCI_CONF_ROM); 4440*26947304SEvan Yan 4441*26947304SEvan Yan /* 4442*26947304SEvan Yan * If its a zero length, don't do 4443*26947304SEvan Yan * any programming. 4444*26947304SEvan Yan */ 4445*26947304SEvan Yan 4446*26947304SEvan Yan if (request != 0) { 4447*26947304SEvan Yan /* 4448*26947304SEvan Yan * Add resource to assigned-addresses. 4449*26947304SEvan Yan */ 4450*26947304SEvan Yan if (pcicfg_fcode_assign_bars(h, new_child, 4451*26947304SEvan Yan bus, device, func, request, &p) 4452*26947304SEvan Yan != PCICFG_SUCCESS) { 4453*26947304SEvan Yan DEBUG0("Failed to assign addresses to " 4454*26947304SEvan Yan "implemented BARs"); 4455*26947304SEvan Yan ret = PCICFG_FAILURE; 4456*26947304SEvan Yan goto failed; 4457*26947304SEvan Yan } 4458*26947304SEvan Yan 4459*26947304SEvan Yan /* Turn device on */ 4460*26947304SEvan Yan (void) pcicfg_device_on(h); 4461*26947304SEvan Yan 4462*26947304SEvan Yan /* 4463*26947304SEvan Yan * Attempt to load fcode. 4464*26947304SEvan Yan */ 4465*26947304SEvan Yan (void) pcicfg_load_fcode(new_child, bus, device, 4466*26947304SEvan Yan func, vendor_id, device_id, &fcode_addr, 4467*26947304SEvan Yan &fcode_size, PCICFG_LOADDR(mem_answer), 4468*26947304SEvan Yan (~(PCI_BASE_ROM_ADDR_M & request)) + 1); 4469*26947304SEvan Yan 4470*26947304SEvan Yan /* Turn device off */ 4471*26947304SEvan Yan (void) pcicfg_device_off(h); 4472*26947304SEvan Yan 4473*26947304SEvan Yan /* 4474*26947304SEvan Yan * Free the ROM resources. 4475*26947304SEvan Yan */ 4476*26947304SEvan Yan (void) pcicfg_free_resource(new_child, p, 0); 4477*26947304SEvan Yan 4478*26947304SEvan Yan DEBUG2("configure: fcode addr %lx size %x\n", 4479*26947304SEvan Yan fcode_addr, fcode_size); 4480*26947304SEvan Yan 4481*26947304SEvan Yan /* 4482*26947304SEvan Yan * Create the fcode-rom-offset property. The 4483*26947304SEvan Yan * buffer containing the fcode always starts 4484*26947304SEvan Yan * with 0xF1, so the fcode offset is zero. 4485*26947304SEvan Yan */ 4486*26947304SEvan Yan if (ndi_prop_update_int(DDI_DEV_T_NONE, 4487*26947304SEvan Yan new_child, "fcode-rom-offset", 0) 4488*26947304SEvan Yan != DDI_SUCCESS) { 4489*26947304SEvan Yan DEBUG0("Failed to create " 4490*26947304SEvan Yan "fcode-rom-offset property\n"); 4491*26947304SEvan Yan ret = PCICFG_FAILURE; 4492*26947304SEvan Yan goto failed; 4493*26947304SEvan Yan } 4494*26947304SEvan Yan } else { 4495*26947304SEvan Yan DEBUG0("There is no Expansion ROM\n"); 4496*26947304SEvan Yan fcode_addr = NULL; 4497*26947304SEvan Yan fcode_size = 0; 4498*26947304SEvan Yan } 4499*26947304SEvan Yan 4500*26947304SEvan Yan /* 4501*26947304SEvan Yan * Fill in the bus specific arguments. For 4502*26947304SEvan Yan * PCI, it is the config address. 4503*26947304SEvan Yan */ 4504*26947304SEvan Yan po.config_address = 4505*26947304SEvan Yan PCICFG_MAKE_REG_HIGH(bus, device, func, 0); 4506*26947304SEvan Yan 4507*26947304SEvan Yan DEBUG1("config_address=%x\n", po.config_address); 4508*26947304SEvan Yan 4509*26947304SEvan Yan /* 4510*26947304SEvan Yan * Build unit address. 4511*26947304SEvan Yan */ 4512*26947304SEvan Yan (void) sprintf(unit_address, "%x,%x", device, func); 4513*26947304SEvan Yan 4514*26947304SEvan Yan DEBUG3("pci_fc_ops_alloc_handle ap=%lx " 4515*26947304SEvan Yan "new device=%lx unit address=%s\n", 4516*26947304SEvan Yan parent, new_child, unit_address); 4517*26947304SEvan Yan 4518*26947304SEvan Yan c = pci_fc_ops_alloc_handle(parent, new_child, 4519*26947304SEvan Yan fcode_addr, fcode_size, unit_address, &po); 4520*26947304SEvan Yan 4521*26947304SEvan Yan DEBUG0("calling fcode_interpreter()\n"); 4522*26947304SEvan Yan 4523*26947304SEvan Yan DEBUG3("Before int DIP=%lx binding name %s major %d\n", 4524*26947304SEvan Yan new_child, ddi_binding_name(new_child), 4525*26947304SEvan Yan ddi_driver_major(new_child)); 4526*26947304SEvan Yan 4527*26947304SEvan Yan error = fcode_interpreter(parent, &pci_fc_ops, c); 4528*26947304SEvan Yan 4529*26947304SEvan Yan DEBUG1("returned from fcode_interpreter() - " 4530*26947304SEvan Yan "returned %x\n", error); 4531*26947304SEvan Yan 4532*26947304SEvan Yan pci_fc_ops_free_handle(c); 4533*26947304SEvan Yan 4534*26947304SEvan Yan DEBUG1("fcode size = %x\n", fcode_size); 4535*26947304SEvan Yan /* 4536*26947304SEvan Yan * We don't need the fcode anymore. While allocating 4537*26947304SEvan Yan * we had rounded up to a page size. 4538*26947304SEvan Yan */ 4539*26947304SEvan Yan if (fcode_size) { 4540*26947304SEvan Yan kmem_free(fcode_addr, ptob(btopr(fcode_size))); 4541*26947304SEvan Yan } 4542*26947304SEvan Yan } else { 4543*26947304SEvan Yan /* This platform does not support fcode */ 4544*26947304SEvan Yan 4545*26947304SEvan Yan DEBUG0("NOT calling fcode_interpreter()\n"); 4546*26947304SEvan Yan } 4547*26947304SEvan Yan 4548*26947304SEvan Yan #endif /* PCICFG_INTERPRET_FCODE */ 4549*26947304SEvan Yan 4550*26947304SEvan Yan if ((error == 0) && (pcicfg_dont_interpret == 0)) { 4551*26947304SEvan Yan /* 4552*26947304SEvan Yan * The interpreter completed successfully. 4553*26947304SEvan Yan * We need to redo the resources based on the new reg 4554*26947304SEvan Yan * property. 4555*26947304SEvan Yan */ 4556*26947304SEvan Yan DEBUG3("DIP=%lx binding name %s major %d\n", new_child, 4557*26947304SEvan Yan ddi_binding_name(new_child), 4558*26947304SEvan Yan ddi_driver_major(new_child)); 4559*26947304SEvan Yan 4560*26947304SEvan Yan /* 4561*26947304SEvan Yan * Readjust resources specified by reg property. 4562*26947304SEvan Yan */ 4563*26947304SEvan Yan if (pcicfg_alloc_new_resources(new_child) == 4564*26947304SEvan Yan PCICFG_FAILURE) { 4565*26947304SEvan Yan ret = PCICFG_FAILURE; 4566*26947304SEvan Yan goto failed; 4567*26947304SEvan Yan } 4568*26947304SEvan Yan 4569*26947304SEvan Yan /* 4570*26947304SEvan Yan * At this stage, there should be enough info to pull 4571*26947304SEvan Yan * the status property if it exists. 4572*26947304SEvan Yan */ 4573*26947304SEvan Yan if (ddi_prop_lookup_string(DDI_DEV_T_ANY, 4574*26947304SEvan Yan new_child, NULL, "status", &status_prop) == 4575*26947304SEvan Yan DDI_PROP_SUCCESS) { 4576*26947304SEvan Yan if ((strncmp("disabled", status_prop, 8) == 4577*26947304SEvan Yan 0) || (strncmp("fail", status_prop, 4) == 4578*26947304SEvan Yan 0)) { 4579*26947304SEvan Yan ret = PCICFG_FAILURE; 4580*26947304SEvan Yan ddi_prop_free(status_prop); 4581*26947304SEvan Yan goto failed; 4582*26947304SEvan Yan } else { 4583*26947304SEvan Yan ddi_prop_free(status_prop); 4584*26947304SEvan Yan } 4585*26947304SEvan Yan } 4586*26947304SEvan Yan 4587*26947304SEvan Yan ret = PCICFG_SUCCESS; 4588*26947304SEvan Yan /* no fcode, bind driver now */ 4589*26947304SEvan Yan (void) ndi_devi_bind_driver(new_child, 0); 4590*26947304SEvan Yan 4591*26947304SEvan Yan goto done; 4592*26947304SEvan Yan } else if ((error != FC_NO_FCODE) && 4593*26947304SEvan Yan (pcicfg_dont_interpret == 0)) { 4594*26947304SEvan Yan /* 4595*26947304SEvan Yan * The interpreter located fcode, but had an error in 4596*26947304SEvan Yan * processing. Cleanup and fail the operation. 4597*26947304SEvan Yan */ 4598*26947304SEvan Yan DEBUG0("Interpreter detected fcode failure\n"); 4599*26947304SEvan Yan (void) pcicfg_free_resources(new_child, flags); 4600*26947304SEvan Yan ret = PCICFG_FAILURE; 4601*26947304SEvan Yan goto failed; 4602*26947304SEvan Yan } else { 4603*26947304SEvan Yan no_fcode: 4604*26947304SEvan Yan /* 4605*26947304SEvan Yan * Either the interpreter failed with FC_NO_FCODE or we 4606*26947304SEvan Yan * chose not to run the interpreter 4607*26947304SEvan Yan * (pcicfg_dont_interpret). 4608*26947304SEvan Yan * 4609*26947304SEvan Yan * If the interpreter failed because there was no 4610*26947304SEvan Yan * dropin, then we need to probe the device ourself. 4611*26947304SEvan Yan */ 4612*26947304SEvan Yan 4613*26947304SEvan Yan /* 4614*26947304SEvan Yan * Free any resources that may have been assigned 4615*26947304SEvan Yan * during fcode loading/execution since we need 4616*26947304SEvan Yan * to start over. 4617*26947304SEvan Yan */ 4618*26947304SEvan Yan (void) pcicfg_free_resources(new_child, flags); 4619*26947304SEvan Yan 4620*26947304SEvan Yan #ifdef EFCODE21554 4621*26947304SEvan Yan pcicfg_config_teardown(&h); 4622*26947304SEvan Yan #else 4623*26947304SEvan Yan pcicfg_unmap_phys(&h, &p); 4624*26947304SEvan Yan #endif 4625*26947304SEvan Yan (void) ndi_devi_free(new_child); 4626*26947304SEvan Yan 4627*26947304SEvan Yan DEBUG0("No Drop-in Probe device ourself\n"); 4628*26947304SEvan Yan 4629*26947304SEvan Yan ret = pcicfg_probe_children(parent, bus, device, func, 4630*26947304SEvan Yan highest_bus, flags); 4631*26947304SEvan Yan 4632*26947304SEvan Yan if (ret != PCICFG_SUCCESS) { 4633*26947304SEvan Yan DEBUG0("Could not self probe child\n"); 4634*26947304SEvan Yan goto failed2; 4635*26947304SEvan Yan } 4636*26947304SEvan Yan 4637*26947304SEvan Yan /* 4638*26947304SEvan Yan * We successfully self probed the device. 4639*26947304SEvan Yan */ 4640*26947304SEvan Yan if ((new_child = pcicfg_devi_find( 4641*26947304SEvan Yan parent, device, func)) == NULL) { 4642*26947304SEvan Yan DEBUG0("Did'nt find device node " 4643*26947304SEvan Yan "just created\n"); 4644*26947304SEvan Yan ret = PCICFG_FAILURE; 4645*26947304SEvan Yan goto failed2; 4646*26947304SEvan Yan } 4647*26947304SEvan Yan #ifdef EFCODE21554 4648*26947304SEvan Yan /* 4649*26947304SEvan Yan * Till now, we have detected a non transparent bridge 4650*26947304SEvan Yan * (ntbridge) as a part of the generic probe code and 4651*26947304SEvan Yan * configured only one configuration 4652*26947304SEvan Yan * header which is the side facing the host bus. 4653*26947304SEvan Yan * Now, configure the other side and create children. 4654*26947304SEvan Yan * 4655*26947304SEvan Yan * To make the process simpler, lets load the device 4656*26947304SEvan Yan * driver for the non transparent bridge as this is a 4657*26947304SEvan Yan * Solaris bundled driver, and use its configuration map 4658*26947304SEvan Yan * services rather than programming it here. 4659*26947304SEvan Yan * If the driver is not bundled into Solaris, it must be 4660*26947304SEvan Yan * first loaded and configured before performing any 4661*26947304SEvan Yan * hotplug operations. 4662*26947304SEvan Yan * 4663*26947304SEvan Yan * This not only makes the code simpler but also more 4664*26947304SEvan Yan * generic. 4665*26947304SEvan Yan * 4666*26947304SEvan Yan * So here we go. 4667*26947304SEvan Yan */ 4668*26947304SEvan Yan if (pcicfg_is_ntbridge(new_child) != DDI_FAILURE) { 4669*26947304SEvan Yan 4670*26947304SEvan Yan DEBUG0("Found nontransparent bridge.\n"); 4671*26947304SEvan Yan 4672*26947304SEvan Yan ret = pcicfg_configure_ntbridge(new_child, 4673*26947304SEvan Yan bus, device); 4674*26947304SEvan Yan } 4675*26947304SEvan Yan if (ret != PCICFG_SUCCESS) { 4676*26947304SEvan Yan /* 4677*26947304SEvan Yan * Bridge configure failed. Free up the self 4678*26947304SEvan Yan * probed entry. The bus resource allocation 4679*26947304SEvan Yan * maps need to be cleaned up to prevent 4680*26947304SEvan Yan * warnings on retries of the failed configure. 4681*26947304SEvan Yan */ 4682*26947304SEvan Yan (void) pcicfg_ntbridge_unconfigure(new_child); 4683*26947304SEvan Yan (void) pcicfg_teardown_device(new_child, flags); 4684*26947304SEvan Yan } 4685*26947304SEvan Yan #endif 4686*26947304SEvan Yan goto done2; 4687*26947304SEvan Yan } 4688*26947304SEvan Yan } 4689*26947304SEvan Yan done: 4690*26947304SEvan Yan failed: 4691*26947304SEvan Yan #ifdef EFCODE21554 4692*26947304SEvan Yan pcicfg_config_teardown(&h); 4693*26947304SEvan Yan #else 4694*26947304SEvan Yan pcicfg_unmap_phys(&h, &p); 4695*26947304SEvan Yan #endif 4696*26947304SEvan Yan failed3: 4697*26947304SEvan Yan if (ret != PCICFG_SUCCESS) 4698*26947304SEvan Yan (void) ndi_devi_free(new_child); 4699*26947304SEvan Yan done2: 4700*26947304SEvan Yan failed2: 4701*26947304SEvan Yan if (parent_regs.pcie_dev) { 4702*26947304SEvan Yan if ((flags & PCICFG_FLAG_READ_ONLY) == 0) { 4703*26947304SEvan Yan pcicfg_enable_bridge_probe_err(parent, 4704*26947304SEvan Yan ph, &parent_regs); 4705*26947304SEvan Yan } 4706*26947304SEvan Yan pci_config_teardown(&ph); 4707*26947304SEvan Yan } 4708*26947304SEvan Yan return (ret); 4709*26947304SEvan Yan } 4710*26947304SEvan Yan 4711*26947304SEvan Yan /* 4712*26947304SEvan Yan * Read the BARs and update properties. Used in virtual hotplug. 4713*26947304SEvan Yan */ 4714*26947304SEvan Yan static int 4715*26947304SEvan Yan pcicfg_populate_props_from_bar(dev_info_t *new_child, 4716*26947304SEvan Yan ddi_acc_handle_t config_handle) 4717*26947304SEvan Yan { 4718*26947304SEvan Yan uint32_t request, base, base_hi, size; 4719*26947304SEvan Yan int i; 4720*26947304SEvan Yan 4721*26947304SEvan Yan i = PCI_CONF_BASE0; 4722*26947304SEvan Yan 4723*26947304SEvan Yan while (i <= PCI_CONF_BASE5) { 4724*26947304SEvan Yan /* 4725*26947304SEvan Yan * determine the size of the address space 4726*26947304SEvan Yan */ 4727*26947304SEvan Yan base = pci_config_get32(config_handle, i); 4728*26947304SEvan Yan pci_config_put32(config_handle, i, 0xffffffff); 4729*26947304SEvan Yan request = pci_config_get32(config_handle, i); 4730*26947304SEvan Yan pci_config_put32(config_handle, i, base); 4731*26947304SEvan Yan 4732*26947304SEvan Yan /* 4733*26947304SEvan Yan * If its a zero length, don't do any programming. 4734*26947304SEvan Yan */ 4735*26947304SEvan Yan if (request != 0) { 4736*26947304SEvan Yan /* 4737*26947304SEvan Yan * Add to the "reg" property 4738*26947304SEvan Yan */ 4739*26947304SEvan Yan if (pcicfg_update_reg_prop(new_child, 4740*26947304SEvan Yan request, i) != PCICFG_SUCCESS) { 4741*26947304SEvan Yan goto failedchild; 4742*26947304SEvan Yan } 4743*26947304SEvan Yan 4744*26947304SEvan Yan if ((PCI_BASE_SPACE_IO & request) == 0 && 4745*26947304SEvan Yan (PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_ALL) { 4746*26947304SEvan Yan base_hi = pci_config_get32(config_handle, i+4); 4747*26947304SEvan Yan } else { 4748*26947304SEvan Yan base_hi = 0; 4749*26947304SEvan Yan } 4750*26947304SEvan Yan /* 4751*26947304SEvan Yan * Add to "assigned-addresses" property 4752*26947304SEvan Yan */ 4753*26947304SEvan Yan size = (~(PCI_BASE_M_ADDR_M & request))+1; 4754*26947304SEvan Yan if (pcicfg_update_assigned_prop_value(new_child, 4755*26947304SEvan Yan size, base, base_hi, i) != PCICFG_SUCCESS) { 4756*26947304SEvan Yan goto failedchild; 4757*26947304SEvan Yan } 4758*26947304SEvan Yan } else { 4759*26947304SEvan Yan DEBUG1("BASE register [0x%x] asks for " 4760*26947304SEvan Yan "[0x0]=[0x0](32)\n", i); 4761*26947304SEvan Yan i += 4; 4762*26947304SEvan Yan continue; 4763*26947304SEvan Yan } 4764*26947304SEvan Yan 4765*26947304SEvan Yan /* 4766*26947304SEvan Yan * Increment by eight if it is 64 bit address space 4767*26947304SEvan Yan */ 4768*26947304SEvan Yan if ((PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_ALL) { 4769*26947304SEvan Yan DEBUG3("BASE register [0x%x] asks for " 4770*26947304SEvan Yan "[0x%x]=[0x%x] (64)\n", 4771*26947304SEvan Yan i, request, 4772*26947304SEvan Yan (~(PCI_BASE_M_ADDR_M & request))+1) 4773*26947304SEvan Yan i += 8; 4774*26947304SEvan Yan } else { 4775*26947304SEvan Yan DEBUG3("BASE register [0x%x] asks for " 4776*26947304SEvan Yan "[0x%x]=[0x%x](32)\n", 4777*26947304SEvan Yan i, request, 4778*26947304SEvan Yan (~(PCI_BASE_M_ADDR_M & request))+1) 4779*26947304SEvan Yan i += 4; 4780*26947304SEvan Yan } 4781*26947304SEvan Yan } 4782*26947304SEvan Yan 4783*26947304SEvan Yan /* 4784*26947304SEvan Yan * Get the ROM size and create register for it 4785*26947304SEvan Yan */ 4786*26947304SEvan Yan base = pci_config_get32(config_handle, PCI_CONF_ROM); 4787*26947304SEvan Yan pci_config_put32(config_handle, PCI_CONF_ROM, 0xfffffffe); 4788*26947304SEvan Yan request = pci_config_get32(config_handle, PCI_CONF_ROM); 4789*26947304SEvan Yan pci_config_put32(config_handle, PCI_CONF_ROM, base); 4790*26947304SEvan Yan 4791*26947304SEvan Yan /* 4792*26947304SEvan Yan * If its a zero length, don't do 4793*26947304SEvan Yan * any programming. 4794*26947304SEvan Yan */ 4795*26947304SEvan Yan if (request != 0) { 4796*26947304SEvan Yan DEBUG3("BASE register [0x%x] asks for [0x%x]=[0x%x]\n", 4797*26947304SEvan Yan PCI_CONF_ROM, request, 4798*26947304SEvan Yan (~(PCI_BASE_ROM_ADDR_M & request))+1); 4799*26947304SEvan Yan /* 4800*26947304SEvan Yan * Add to the "reg" property 4801*26947304SEvan Yan */ 4802*26947304SEvan Yan if (pcicfg_update_reg_prop(new_child, 4803*26947304SEvan Yan request, PCI_CONF_ROM) != PCICFG_SUCCESS) { 4804*26947304SEvan Yan goto failedchild; 4805*26947304SEvan Yan } 4806*26947304SEvan Yan /* 4807*26947304SEvan Yan * Add to "assigned-addresses" property 4808*26947304SEvan Yan */ 4809*26947304SEvan Yan size = (~(PCI_BASE_ROM_ADDR_M & request))+1; 4810*26947304SEvan Yan if (pcicfg_update_assigned_prop_value(new_child, size, 4811*26947304SEvan Yan base, 0, PCI_CONF_ROM) != PCICFG_SUCCESS) { 4812*26947304SEvan Yan goto failedchild; 4813*26947304SEvan Yan } 4814*26947304SEvan Yan } 4815*26947304SEvan Yan 4816*26947304SEvan Yan return (PCICFG_SUCCESS); 4817*26947304SEvan Yan 4818*26947304SEvan Yan failedchild: 4819*26947304SEvan Yan return (PCICFG_FAILURE); 4820*26947304SEvan Yan } 4821*26947304SEvan Yan 4822*26947304SEvan Yan static int 4823*26947304SEvan Yan pcicfg_probe_bridge(dev_info_t *new_child, ddi_acc_handle_t h, uint_t bus, 4824*26947304SEvan Yan uint_t *highest_bus) 4825*26947304SEvan Yan { 4826*26947304SEvan Yan uint64_t next_bus; 4827*26947304SEvan Yan uint_t new_bus, num_slots; 4828*26947304SEvan Yan ndi_ra_request_t req; 4829*26947304SEvan Yan int rval, i, j; 4830*26947304SEvan Yan uint64_t mem_answer, mem_base, mem_alen, mem_size, mem_end; 4831*26947304SEvan Yan uint64_t io_answer, io_base, io_alen, io_size, io_end; 4832*26947304SEvan Yan uint64_t round_answer, round_len; 4833*26947304SEvan Yan pcicfg_range_t range[PCICFG_RANGE_LEN]; 4834*26947304SEvan Yan int bus_range[2]; 4835*26947304SEvan Yan pcicfg_phdl_t phdl; 4836*26947304SEvan Yan int count; 4837*26947304SEvan Yan uint64_t pcibus_base, pcibus_alen; 4838*26947304SEvan Yan uint64_t max_bus; 4839*26947304SEvan Yan uint8_t pcie_device_type = 0; 4840*26947304SEvan Yan dev_info_t *new_device; 4841*26947304SEvan Yan int trans_device; 4842*26947304SEvan Yan int ari_mode = B_FALSE; 4843*26947304SEvan Yan int max_function = PCICFG_MAX_FUNCTION; 4844*26947304SEvan Yan 4845*26947304SEvan Yan /* 4846*26947304SEvan Yan * Set "device_type" to "pci", the actual type will be set later 4847*26947304SEvan Yan * by pcicfg_set_busnode_props() below. This is needed as the 4848*26947304SEvan Yan * pcicfg_ra_free() below would update "available" property based 4849*26947304SEvan Yan * on "device_type". 4850*26947304SEvan Yan * 4851*26947304SEvan Yan * This code can be removed later after PCI configurator is changed 4852*26947304SEvan Yan * to use PCIRM, which automatically update properties upon allocation 4853*26947304SEvan Yan * and free, at that time we'll be able to remove the code inside 4854*26947304SEvan Yan * ndi_ra_alloc/free() which currently updates "available" property 4855*26947304SEvan Yan * for pci/pcie devices in pcie fabric. 4856*26947304SEvan Yan */ 4857*26947304SEvan Yan if (ndi_prop_update_string(DDI_DEV_T_NONE, new_child, 4858*26947304SEvan Yan "device_type", "pci") != DDI_SUCCESS) { 4859*26947304SEvan Yan DEBUG0("Failed to set \"device_type\" props\n"); 4860*26947304SEvan Yan return (PCICFG_FAILURE); 4861*26947304SEvan Yan } 4862*26947304SEvan Yan 4863*26947304SEvan Yan bzero((caddr_t)&req, sizeof (ndi_ra_request_t)); 4864*26947304SEvan Yan req.ra_flags = (NDI_RA_ALLOC_BOUNDED | NDI_RA_ALLOC_PARTIAL_OK); 4865*26947304SEvan Yan req.ra_boundbase = 0; 4866*26947304SEvan Yan req.ra_boundlen = PCICFG_MAX_BUS_DEPTH; 4867*26947304SEvan Yan req.ra_len = PCICFG_MAX_BUS_DEPTH; 4868*26947304SEvan Yan req.ra_align_mask = 0; /* no alignment needed */ 4869*26947304SEvan Yan 4870*26947304SEvan Yan rval = ndi_ra_alloc(ddi_get_parent(new_child), &req, 4871*26947304SEvan Yan &pcibus_base, &pcibus_alen, NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS); 4872*26947304SEvan Yan 4873*26947304SEvan Yan if (rval != NDI_SUCCESS) { 4874*26947304SEvan Yan if (rval == NDI_RA_PARTIAL_REQ) { 4875*26947304SEvan Yan /*EMPTY*/ 4876*26947304SEvan Yan DEBUG0("NDI_RA_PARTIAL_REQ returned for bus range\n"); 4877*26947304SEvan Yan } else { 4878*26947304SEvan Yan DEBUG0( 4879*26947304SEvan Yan "Failed to allocate bus range for bridge\n"); 4880*26947304SEvan Yan return (PCICFG_FAILURE); 4881*26947304SEvan Yan } 4882*26947304SEvan Yan } 4883*26947304SEvan Yan 4884*26947304SEvan Yan DEBUG2("Bus Range Allocated [base=%d] [len=%d]\n", 4885*26947304SEvan Yan pcibus_base, pcibus_alen); 4886*26947304SEvan Yan 4887*26947304SEvan Yan if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_PCI_BUSNUM) 4888*26947304SEvan Yan == NDI_FAILURE) { 4889*26947304SEvan Yan DEBUG0("Can not setup resource map - NDI_RA_TYPE_PCI_BUSNUM\n"); 4890*26947304SEvan Yan return (PCICFG_FAILURE); 4891*26947304SEvan Yan } 4892*26947304SEvan Yan 4893*26947304SEvan Yan /* 4894*26947304SEvan Yan * Put available bus range into the pool. 4895*26947304SEvan Yan * Take the first one for this bridge to use and don't give 4896*26947304SEvan Yan * to child. 4897*26947304SEvan Yan */ 4898*26947304SEvan Yan (void) ndi_ra_free(new_child, pcibus_base+1, pcibus_alen-1, 4899*26947304SEvan Yan NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS); 4900*26947304SEvan Yan 4901*26947304SEvan Yan next_bus = pcibus_base; 4902*26947304SEvan Yan max_bus = pcibus_base + pcibus_alen - 1; 4903*26947304SEvan Yan 4904*26947304SEvan Yan new_bus = next_bus; 4905*26947304SEvan Yan 4906*26947304SEvan Yan DEBUG1("NEW bus found ->[%d]\n", new_bus); 4907*26947304SEvan Yan 4908*26947304SEvan Yan /* Keep track of highest bus for subordinate bus programming */ 4909*26947304SEvan Yan *highest_bus = new_bus; 4910*26947304SEvan Yan 4911*26947304SEvan Yan /* 4912*26947304SEvan Yan * Allocate Memory Space for Bridge 4913*26947304SEvan Yan */ 4914*26947304SEvan Yan bzero((caddr_t)&req, sizeof (ndi_ra_request_t)); 4915*26947304SEvan Yan req.ra_flags = (NDI_RA_ALLOC_BOUNDED | NDI_RA_ALLOC_PARTIAL_OK); 4916*26947304SEvan Yan req.ra_boundbase = 0; 4917*26947304SEvan Yan /* 4918*26947304SEvan Yan * Note: To support a 32b system, boundlen and len need to be 4919*26947304SEvan Yan * 32b quantities 4920*26947304SEvan Yan */ 4921*26947304SEvan Yan req.ra_boundlen = PCICFG_4GIG_LIMIT + 1; 4922*26947304SEvan Yan req.ra_len = PCICFG_4GIG_LIMIT + 1; /* Get as big as possible */ 4923*26947304SEvan Yan req.ra_align_mask = 4924*26947304SEvan Yan PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */ 4925*26947304SEvan Yan 4926*26947304SEvan Yan rval = ndi_ra_alloc(ddi_get_parent(new_child), &req, 4927*26947304SEvan Yan &mem_answer, &mem_alen, NDI_RA_TYPE_MEM, NDI_RA_PASS); 4928*26947304SEvan Yan 4929*26947304SEvan Yan if (rval != NDI_SUCCESS) { 4930*26947304SEvan Yan if (rval == NDI_RA_PARTIAL_REQ) { 4931*26947304SEvan Yan /*EMPTY*/ 4932*26947304SEvan Yan DEBUG0("NDI_RA_PARTIAL_REQ returned\n"); 4933*26947304SEvan Yan } else { 4934*26947304SEvan Yan DEBUG0( 4935*26947304SEvan Yan "Failed to allocate memory for bridge\n"); 4936*26947304SEvan Yan return (PCICFG_FAILURE); 4937*26947304SEvan Yan } 4938*26947304SEvan Yan } 4939*26947304SEvan Yan 4940*26947304SEvan Yan DEBUG3("Bridge Memory Allocated [0x%x.%x] len [0x%x]\n", 4941*26947304SEvan Yan PCICFG_HIADDR(mem_answer), 4942*26947304SEvan Yan PCICFG_LOADDR(mem_answer), 4943*26947304SEvan Yan mem_alen); 4944*26947304SEvan Yan 4945*26947304SEvan Yan if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_MEM) == NDI_FAILURE) { 4946*26947304SEvan Yan DEBUG0("Can not setup resource map - NDI_RA_TYPE_MEM\n"); 4947*26947304SEvan Yan return (PCICFG_FAILURE); 4948*26947304SEvan Yan } 4949*26947304SEvan Yan 4950*26947304SEvan Yan /* 4951*26947304SEvan Yan * Put available memory into the pool. 4952*26947304SEvan Yan */ 4953*26947304SEvan Yan (void) ndi_ra_free(new_child, mem_answer, mem_alen, NDI_RA_TYPE_MEM, 4954*26947304SEvan Yan NDI_RA_PASS); 4955*26947304SEvan Yan 4956*26947304SEvan Yan mem_base = mem_answer; 4957*26947304SEvan Yan 4958*26947304SEvan Yan /* 4959*26947304SEvan Yan * Allocate I/O Space for Bridge 4960*26947304SEvan Yan */ 4961*26947304SEvan Yan bzero((caddr_t)&req, sizeof (ndi_ra_request_t)); 4962*26947304SEvan Yan req.ra_align_mask = PCICFG_IOGRAN - 1; /* 4k alignment */ 4963*26947304SEvan Yan req.ra_boundbase = 0; 4964*26947304SEvan Yan req.ra_boundlen = PCICFG_4GIG_LIMIT; 4965*26947304SEvan Yan req.ra_flags = (NDI_RA_ALLOC_BOUNDED | NDI_RA_ALLOC_PARTIAL_OK); 4966*26947304SEvan Yan req.ra_len = PCICFG_4GIG_LIMIT; /* Get as big as possible */ 4967*26947304SEvan Yan 4968*26947304SEvan Yan rval = ndi_ra_alloc(ddi_get_parent(new_child), &req, &io_answer, 4969*26947304SEvan Yan &io_alen, NDI_RA_TYPE_IO, NDI_RA_PASS); 4970*26947304SEvan Yan 4971*26947304SEvan Yan if (rval != NDI_SUCCESS) { 4972*26947304SEvan Yan if (rval == NDI_RA_PARTIAL_REQ) { 4973*26947304SEvan Yan /*EMPTY*/ 4974*26947304SEvan Yan DEBUG0("NDI_RA_PARTIAL_REQ returned\n"); 4975*26947304SEvan Yan } else { 4976*26947304SEvan Yan DEBUG0("Failed to allocate io space for bridge\n"); 4977*26947304SEvan Yan io_base = io_answer = io_alen = 0; 4978*26947304SEvan Yan /* return (PCICFG_FAILURE); */ 4979*26947304SEvan Yan } 4980*26947304SEvan Yan } 4981*26947304SEvan Yan 4982*26947304SEvan Yan if (io_alen) { 4983*26947304SEvan Yan DEBUG3("Bridge IO Space Allocated [0x%x.%x] len [0x%x]\n", 4984*26947304SEvan Yan PCICFG_HIADDR(io_answer), PCICFG_LOADDR(io_answer), 4985*26947304SEvan Yan io_alen); 4986*26947304SEvan Yan 4987*26947304SEvan Yan if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_IO) == 4988*26947304SEvan Yan NDI_FAILURE) { 4989*26947304SEvan Yan DEBUG0("Can not setup resource map - NDI_RA_TYPE_IO\n"); 4990*26947304SEvan Yan return (PCICFG_FAILURE); 4991*26947304SEvan Yan } 4992*26947304SEvan Yan 4993*26947304SEvan Yan /* 4994*26947304SEvan Yan * Put available I/O into the pool. 4995*26947304SEvan Yan */ 4996*26947304SEvan Yan (void) ndi_ra_free(new_child, io_answer, io_alen, 4997*26947304SEvan Yan NDI_RA_TYPE_IO, NDI_RA_PASS); 4998*26947304SEvan Yan io_base = io_answer; 4999*26947304SEvan Yan } 5000*26947304SEvan Yan 5001*26947304SEvan Yan pcicfg_set_bus_numbers(h, bus, new_bus, max_bus); 5002*26947304SEvan Yan 5003*26947304SEvan Yan /* 5004*26947304SEvan Yan * Setup "bus-range" property before onlining the bridge. 5005*26947304SEvan Yan */ 5006*26947304SEvan Yan bus_range[0] = new_bus; 5007*26947304SEvan Yan bus_range[1] = max_bus; 5008*26947304SEvan Yan 5009*26947304SEvan Yan if (ndi_prop_update_int_array(DDI_DEV_T_NONE, new_child, 5010*26947304SEvan Yan "bus-range", bus_range, 2) != DDI_SUCCESS) { 5011*26947304SEvan Yan DEBUG0("Failed to set bus-range property"); 5012*26947304SEvan Yan return (PCICFG_FAILURE); 5013*26947304SEvan Yan } 5014*26947304SEvan Yan 5015*26947304SEvan Yan /* 5016*26947304SEvan Yan * Reset the secondary bus 5017*26947304SEvan Yan */ 5018*26947304SEvan Yan pci_config_put16(h, PCI_BCNF_BCNTRL, 5019*26947304SEvan Yan pci_config_get16(h, PCI_BCNF_BCNTRL) | 0x40); 5020*26947304SEvan Yan 5021*26947304SEvan Yan drv_usecwait(100); 5022*26947304SEvan Yan 5023*26947304SEvan Yan pci_config_put16(h, PCI_BCNF_BCNTRL, 5024*26947304SEvan Yan pci_config_get16(h, PCI_BCNF_BCNTRL) & ~0x40); 5025*26947304SEvan Yan 5026*26947304SEvan Yan /* 5027*26947304SEvan Yan * Program the memory base register with the 5028*26947304SEvan Yan * start of the memory range 5029*26947304SEvan Yan */ 5030*26947304SEvan Yan pci_config_put16(h, PCI_BCNF_MEM_BASE, 5031*26947304SEvan Yan PCICFG_HIWORD(PCICFG_LOADDR(mem_answer))); 5032*26947304SEvan Yan 5033*26947304SEvan Yan /* 5034*26947304SEvan Yan * Program the memory limit register with the 5035*26947304SEvan Yan * end of the memory range. 5036*26947304SEvan Yan */ 5037*26947304SEvan Yan 5038*26947304SEvan Yan pci_config_put16(h, PCI_BCNF_MEM_LIMIT, 5039*26947304SEvan Yan PCICFG_HIWORD(PCICFG_LOADDR( 5040*26947304SEvan Yan PCICFG_ROUND_DOWN((mem_answer + mem_alen), PCICFG_MEMGRAN) - 1))); 5041*26947304SEvan Yan 5042*26947304SEvan Yan /* 5043*26947304SEvan Yan * Allocate the chunk of memory (if any) not programmed into the 5044*26947304SEvan Yan * bridge because of the round down. 5045*26947304SEvan Yan */ 5046*26947304SEvan Yan if (PCICFG_ROUND_DOWN((mem_answer + mem_alen), PCICFG_MEMGRAN) 5047*26947304SEvan Yan != (mem_answer + mem_alen)) { 5048*26947304SEvan Yan DEBUG0("Need to allocate Memory round off chunk\n"); 5049*26947304SEvan Yan bzero((caddr_t)&req, sizeof (ndi_ra_request_t)); 5050*26947304SEvan Yan req.ra_flags = NDI_RA_ALLOC_SPECIFIED; 5051*26947304SEvan Yan req.ra_addr = PCICFG_ROUND_DOWN((mem_answer + mem_alen), 5052*26947304SEvan Yan PCICFG_MEMGRAN); 5053*26947304SEvan Yan req.ra_len = (mem_answer + mem_alen) - 5054*26947304SEvan Yan (PCICFG_ROUND_DOWN((mem_answer + mem_alen), 5055*26947304SEvan Yan PCICFG_MEMGRAN)); 5056*26947304SEvan Yan 5057*26947304SEvan Yan (void) ndi_ra_alloc(new_child, &req, 5058*26947304SEvan Yan &round_answer, &round_len, NDI_RA_TYPE_MEM, NDI_RA_PASS); 5059*26947304SEvan Yan } 5060*26947304SEvan Yan 5061*26947304SEvan Yan /* 5062*26947304SEvan Yan * Program the I/O Space Base 5063*26947304SEvan Yan */ 5064*26947304SEvan Yan pci_config_put8(h, PCI_BCNF_IO_BASE_LOW, 5065*26947304SEvan Yan PCICFG_HIBYTE(PCICFG_LOWORD( 5066*26947304SEvan Yan PCICFG_LOADDR(io_answer)))); 5067*26947304SEvan Yan 5068*26947304SEvan Yan pci_config_put16(h, PCI_BCNF_IO_BASE_HI, 5069*26947304SEvan Yan PCICFG_HIWORD(PCICFG_LOADDR(io_answer))); 5070*26947304SEvan Yan 5071*26947304SEvan Yan /* 5072*26947304SEvan Yan * Program the I/O Space Limit 5073*26947304SEvan Yan */ 5074*26947304SEvan Yan pci_config_put8(h, PCI_BCNF_IO_LIMIT_LOW, 5075*26947304SEvan Yan PCICFG_HIBYTE(PCICFG_LOWORD( 5076*26947304SEvan Yan PCICFG_LOADDR(PCICFG_ROUND_DOWN(io_answer + io_alen, 5077*26947304SEvan Yan PCICFG_IOGRAN)))) - 1); 5078*26947304SEvan Yan 5079*26947304SEvan Yan pci_config_put16(h, PCI_BCNF_IO_LIMIT_HI, 5080*26947304SEvan Yan PCICFG_HIWORD(PCICFG_LOADDR( 5081*26947304SEvan Yan PCICFG_ROUND_DOWN(io_answer + io_alen, PCICFG_IOGRAN))) 5082*26947304SEvan Yan - 1); 5083*26947304SEvan Yan 5084*26947304SEvan Yan /* 5085*26947304SEvan Yan * Allocate the chunk of I/O (if any) not programmed into the 5086*26947304SEvan Yan * bridge because of the round down. 5087*26947304SEvan Yan */ 5088*26947304SEvan Yan if (PCICFG_ROUND_DOWN((io_answer + io_alen), PCICFG_IOGRAN) 5089*26947304SEvan Yan != (io_answer + io_alen)) { 5090*26947304SEvan Yan DEBUG0("Need to allocate I/O round off chunk\n"); 5091*26947304SEvan Yan bzero((caddr_t)&req, sizeof (ndi_ra_request_t)); 5092*26947304SEvan Yan req.ra_flags = NDI_RA_ALLOC_SPECIFIED; 5093*26947304SEvan Yan req.ra_addr = PCICFG_ROUND_DOWN((io_answer + io_alen), 5094*26947304SEvan Yan PCICFG_IOGRAN); 5095*26947304SEvan Yan req.ra_len = (io_answer + io_alen) - 5096*26947304SEvan Yan (PCICFG_ROUND_DOWN((io_answer + io_alen), 5097*26947304SEvan Yan PCICFG_IOGRAN)); 5098*26947304SEvan Yan 5099*26947304SEvan Yan (void) ndi_ra_alloc(new_child, &req, 5100*26947304SEvan Yan &round_answer, &round_len, NDI_RA_TYPE_IO, NDI_RA_PASS); 5101*26947304SEvan Yan } 5102*26947304SEvan Yan 5103*26947304SEvan Yan /* 5104*26947304SEvan Yan * Setup "ranges" property before onlining the bridge. 5105*26947304SEvan Yan */ 5106*26947304SEvan Yan bzero((caddr_t)range, sizeof (pcicfg_range_t) * PCICFG_RANGE_LEN); 5107*26947304SEvan Yan 5108*26947304SEvan Yan range[0].child_hi = range[0].parent_hi |= (PCI_REG_REL_M | PCI_ADDR_IO); 5109*26947304SEvan Yan range[0].child_lo = range[0].parent_lo = io_base; 5110*26947304SEvan Yan range[1].child_hi = range[1].parent_hi |= 5111*26947304SEvan Yan (PCI_REG_REL_M | PCI_ADDR_MEM32); 5112*26947304SEvan Yan range[1].child_lo = range[1].parent_lo = mem_base; 5113*26947304SEvan Yan 5114*26947304SEvan Yan range[0].size_lo = io_alen; 5115*26947304SEvan Yan if (pcicfg_update_ranges_prop(new_child, &range[0])) { 5116*26947304SEvan Yan DEBUG0("Failed to update ranges (io)\n"); 5117*26947304SEvan Yan return (PCICFG_FAILURE); 5118*26947304SEvan Yan } 5119*26947304SEvan Yan range[1].size_lo = mem_alen; 5120*26947304SEvan Yan if (pcicfg_update_ranges_prop(new_child, &range[1])) { 5121*26947304SEvan Yan DEBUG0("Failed to update ranges (memory)\n"); 5122*26947304SEvan Yan return (PCICFG_FAILURE); 5123*26947304SEvan Yan } 5124*26947304SEvan Yan 5125*26947304SEvan Yan /* 5126*26947304SEvan Yan * Clear status bits 5127*26947304SEvan Yan */ 5128*26947304SEvan Yan pci_config_put16(h, PCI_BCNF_SEC_STATUS, 0xffff); 5129*26947304SEvan Yan 5130*26947304SEvan Yan /* 5131*26947304SEvan Yan * Turn off prefetchable range 5132*26947304SEvan Yan */ 5133*26947304SEvan Yan pci_config_put32(h, PCI_BCNF_PF_BASE_LOW, 0x0000ffff); 5134*26947304SEvan Yan pci_config_put32(h, PCI_BCNF_PF_BASE_HIGH, 0xffffffff); 5135*26947304SEvan Yan pci_config_put32(h, PCI_BCNF_PF_LIMIT_HIGH, 0x0); 5136*26947304SEvan Yan 5137*26947304SEvan Yan /* 5138*26947304SEvan Yan * Needs to be set to this value 5139*26947304SEvan Yan */ 5140*26947304SEvan Yan pci_config_put8(h, PCI_CONF_ILINE, 0xf); 5141*26947304SEvan Yan 5142*26947304SEvan Yan /* check our device_type as defined by Open Firmware */ 5143*26947304SEvan Yan if (pcicfg_pcie_device_type(new_child, h) == DDI_SUCCESS) 5144*26947304SEvan Yan pcie_device_type = 1; 5145*26947304SEvan Yan 5146*26947304SEvan Yan /* 5147*26947304SEvan Yan * Set bus properties 5148*26947304SEvan Yan */ 5149*26947304SEvan Yan if (pcicfg_set_busnode_props(new_child, pcie_device_type, 5150*26947304SEvan Yan (int)bus, (int)new_bus) != PCICFG_SUCCESS) { 5151*26947304SEvan Yan DEBUG0("Failed to set busnode props\n"); 5152*26947304SEvan Yan return (PCICFG_FAILURE); 5153*26947304SEvan Yan } 5154*26947304SEvan Yan 5155*26947304SEvan Yan (void) pcicfg_device_on(h); 5156*26947304SEvan Yan 5157*26947304SEvan Yan if (ndi_devi_online(new_child, NDI_NO_EVENT|NDI_CONFIG) 5158*26947304SEvan Yan != NDI_SUCCESS) { 5159*26947304SEvan Yan DEBUG0("Unable to online bridge\n"); 5160*26947304SEvan Yan return (PCICFG_FAILURE); 5161*26947304SEvan Yan } 5162*26947304SEvan Yan 5163*26947304SEvan Yan DEBUG0("Bridge is ONLINE\n"); 5164*26947304SEvan Yan 5165*26947304SEvan Yan /* 5166*26947304SEvan Yan * After a Reset, we need to wait 2^25 clock cycles before the 5167*26947304SEvan Yan * first Configuration access. The worst case is 33MHz, which 5168*26947304SEvan Yan * is a 1 second wait. 5169*26947304SEvan Yan */ 5170*26947304SEvan Yan drv_usecwait(pcicfg_sec_reset_delay); 5171*26947304SEvan Yan 5172*26947304SEvan Yan /* 5173*26947304SEvan Yan * Probe all children devices 5174*26947304SEvan Yan */ 5175*26947304SEvan Yan DEBUG0("Bridge Programming Complete - probe children\n"); 5176*26947304SEvan Yan ndi_devi_enter(new_child, &count); 5177*26947304SEvan Yan for (i = 0; ((i < PCICFG_MAX_DEVICE) && (ari_mode == B_FALSE)); 5178*26947304SEvan Yan i++) { 5179*26947304SEvan Yan for (j = 0; j < max_function; ) { 5180*26947304SEvan Yan if (ari_mode) 5181*26947304SEvan Yan trans_device = j >> 3; 5182*26947304SEvan Yan else 5183*26947304SEvan Yan trans_device = i; 5184*26947304SEvan Yan 5185*26947304SEvan Yan if ((rval = pcicfg_fcode_probe(new_child, 5186*26947304SEvan Yan new_bus, trans_device, (j & 7), highest_bus, 0)) 5187*26947304SEvan Yan != PCICFG_SUCCESS) { 5188*26947304SEvan Yan if (rval == PCICFG_NODEVICE) { 5189*26947304SEvan Yan DEBUG3("No Device at bus [0x%x]" 5190*26947304SEvan Yan "device [0x%x] " 5191*26947304SEvan Yan "func [0x%x]\n", new_bus, 5192*26947304SEvan Yan trans_device, j & 7); 5193*26947304SEvan Yan 5194*26947304SEvan Yan if (j) 5195*26947304SEvan Yan goto next; 5196*26947304SEvan Yan } else { 5197*26947304SEvan Yan DEBUG3("Failed to configure bus " 5198*26947304SEvan Yan "[0x%x] device [0x%x] " 5199*26947304SEvan Yan "func [0x%x]\n", new_bus, 5200*26947304SEvan Yan trans_device, j & 7); 5201*26947304SEvan Yan 5202*26947304SEvan Yan rval = PCICFG_FAILURE; 5203*26947304SEvan Yan } 5204*26947304SEvan Yan break; 5205*26947304SEvan Yan } 5206*26947304SEvan Yan next: 5207*26947304SEvan Yan new_device = pcicfg_devi_find(new_child, 5208*26947304SEvan Yan trans_device, (j & 7)); 5209*26947304SEvan Yan 5210*26947304SEvan Yan /* 5211*26947304SEvan Yan * Determine if ARI Forwarding should be enabled. 5212*26947304SEvan Yan */ 5213*26947304SEvan Yan if (j == 0) { 5214*26947304SEvan Yan if (new_device == NULL) 5215*26947304SEvan Yan break; 5216*26947304SEvan Yan 5217*26947304SEvan Yan if ((pcie_ari_supported(new_child) == 5218*26947304SEvan Yan PCIE_ARI_FORW_ENABLED) && 5219*26947304SEvan Yan (pcie_ari_device(new_device) == 5220*26947304SEvan Yan PCIE_ARI_DEVICE)) { 5221*26947304SEvan Yan if (pcie_ari_enable(new_child) == 5222*26947304SEvan Yan DDI_SUCCESS) { 5223*26947304SEvan Yan (void) ddi_prop_create( 5224*26947304SEvan Yan DDI_DEV_T_NONE, 5225*26947304SEvan Yan new_child, 5226*26947304SEvan Yan DDI_PROP_CANSLEEP, 5227*26947304SEvan Yan "ari-enabled", NULL, 0); 5228*26947304SEvan Yan ari_mode = B_TRUE; 5229*26947304SEvan Yan max_function = 5230*26947304SEvan Yan PCICFG_MAX_ARI_FUNCTION; 5231*26947304SEvan Yan } 5232*26947304SEvan Yan } 5233*26947304SEvan Yan } 5234*26947304SEvan Yan 5235*26947304SEvan Yan if (ari_mode == B_TRUE) { 5236*26947304SEvan Yan int next_function; 5237*26947304SEvan Yan 5238*26947304SEvan Yan if (new_device == NULL) 5239*26947304SEvan Yan break; 5240*26947304SEvan Yan 5241*26947304SEvan Yan if (pcie_ari_get_next_function(new_device, 5242*26947304SEvan Yan &next_function) != DDI_SUCCESS) 5243*26947304SEvan Yan break; 5244*26947304SEvan Yan 5245*26947304SEvan Yan j = next_function; 5246*26947304SEvan Yan 5247*26947304SEvan Yan if (next_function == 0) 5248*26947304SEvan Yan break; 5249*26947304SEvan Yan } else 5250*26947304SEvan Yan j++; 5251*26947304SEvan Yan } 5252*26947304SEvan Yan } 5253*26947304SEvan Yan 5254*26947304SEvan Yan ndi_devi_exit(new_child, count); 5255*26947304SEvan Yan 5256*26947304SEvan Yan /* if empty topology underneath, it is still a success. */ 5257*26947304SEvan Yan if (rval != PCICFG_FAILURE) 5258*26947304SEvan Yan rval = PCICFG_SUCCESS; 5259*26947304SEvan Yan 5260*26947304SEvan Yan /* 5261*26947304SEvan Yan * Offline the bridge to allow reprogramming of resources. 5262*26947304SEvan Yan * 5263*26947304SEvan Yan * This should always succeed since nobody else has started to 5264*26947304SEvan Yan * use it yet, failing to detach the driver would indicate a bug. 5265*26947304SEvan Yan * Also in that case it's better just panic than allowing the 5266*26947304SEvan Yan * configurator to proceed with BAR reprogramming without bridge 5267*26947304SEvan Yan * driver detached. 5268*26947304SEvan Yan */ 5269*26947304SEvan Yan VERIFY(ndi_devi_offline(new_child, NDI_NO_EVENT|NDI_UNCONFIG) 5270*26947304SEvan Yan == NDI_SUCCESS); 5271*26947304SEvan Yan 5272*26947304SEvan Yan phdl.dip = new_child; 5273*26947304SEvan Yan phdl.memory_base = mem_answer; 5274*26947304SEvan Yan phdl.io_base = (uint32_t)io_answer; 5275*26947304SEvan Yan phdl.error = PCICFG_SUCCESS; /* in case of empty child tree */ 5276*26947304SEvan Yan 5277*26947304SEvan Yan ndi_devi_enter(ddi_get_parent(new_child), &count); 5278*26947304SEvan Yan ddi_walk_devs(new_child, pcicfg_find_resource_end, (void *)&phdl); 5279*26947304SEvan Yan ndi_devi_exit(ddi_get_parent(new_child), count); 5280*26947304SEvan Yan 5281*26947304SEvan Yan if (phdl.error != PCICFG_SUCCESS) { 5282*26947304SEvan Yan DEBUG0("Failure summing resources\n"); 5283*26947304SEvan Yan return (PCICFG_FAILURE); 5284*26947304SEvan Yan } 5285*26947304SEvan Yan 5286*26947304SEvan Yan num_slots = pcicfg_get_nslots(new_child, h); 5287*26947304SEvan Yan mem_end = PCICFG_ROUND_UP(phdl.memory_base, PCICFG_MEMGRAN); 5288*26947304SEvan Yan io_end = PCICFG_ROUND_UP(phdl.io_base, PCICFG_IOGRAN); 5289*26947304SEvan Yan 5290*26947304SEvan Yan DEBUG3("Start of Unallocated Bridge(%d slots) Resources " 5291*26947304SEvan Yan "Mem=0x%lx I/O=0x%lx\n", num_slots, mem_end, io_end); 5292*26947304SEvan Yan 5293*26947304SEvan Yan /* 5294*26947304SEvan Yan * Before probing the children we've allocated maximum MEM/IO 5295*26947304SEvan Yan * resources from parent, and updated "available" property 5296*26947304SEvan Yan * accordingly. Later we'll be giving up unused resources to 5297*26947304SEvan Yan * the parent, thus we need to destroy "available" property 5298*26947304SEvan Yan * here otherwise it will be out-of-sync with the actual free 5299*26947304SEvan Yan * resources this bridge has. This property will be rebuilt below 5300*26947304SEvan Yan * with the actual free resources reserved for hotplug slots 5301*26947304SEvan Yan * (if any). 5302*26947304SEvan Yan */ 5303*26947304SEvan Yan (void) ndi_prop_remove(DDI_DEV_T_NONE, new_child, "available"); 5304*26947304SEvan Yan /* 5305*26947304SEvan Yan * if the bridge a slots, then preallocate. If not, assume static 5306*26947304SEvan Yan * configuration. Also check for preallocation limits and spit 5307*26947304SEvan Yan * warning messages appropriately (perhaps some can be in debug mode). 5308*26947304SEvan Yan */ 5309*26947304SEvan Yan if (num_slots) { 5310*26947304SEvan Yan pci_regspec_t reg; 5311*26947304SEvan Yan uint64_t mem_assigned = mem_end; 5312*26947304SEvan Yan uint64_t io_assigned = io_end; 5313*26947304SEvan Yan uint64_t mem_reqd = mem_answer + (num_slots * 5314*26947304SEvan Yan pcicfg_slot_memsize); 5315*26947304SEvan Yan uint64_t io_reqd = io_answer + (num_slots * 5316*26947304SEvan Yan pcicfg_slot_iosize); 5317*26947304SEvan Yan uint8_t highest_bus_reqd = new_bus + (num_slots * 5318*26947304SEvan Yan pcicfg_slot_busnums); 5319*26947304SEvan Yan #ifdef DEBUG 5320*26947304SEvan Yan if (mem_end > mem_reqd) 5321*26947304SEvan Yan DEBUG3("Memory space consumed by bridge" 5322*26947304SEvan Yan " more than planned for %d slot(s)(%lx, %lx)", 5323*26947304SEvan Yan num_slots, mem_answer, mem_end); 5324*26947304SEvan Yan if (io_end > io_reqd) 5325*26947304SEvan Yan DEBUG3("IO space consumed by bridge" 5326*26947304SEvan Yan " more than planned for %d slot(s)(%lx, %lx)", 5327*26947304SEvan Yan num_slots, io_answer, io_end); 5328*26947304SEvan Yan if (*highest_bus > highest_bus_reqd) 5329*26947304SEvan Yan DEBUG3("Buses consumed by bridge" 5330*26947304SEvan Yan " more than planned for %d slot(s)(%x, %x)", 5331*26947304SEvan Yan num_slots, new_bus, *highest_bus); 5332*26947304SEvan Yan 5333*26947304SEvan Yan if (mem_reqd > (mem_answer + mem_alen)) 5334*26947304SEvan Yan DEBUG3("Memory space required by bridge" 5335*26947304SEvan Yan " more than available for %d slot(s)(%lx, %lx)", 5336*26947304SEvan Yan num_slots, mem_answer, mem_end); 5337*26947304SEvan Yan 5338*26947304SEvan Yan if (io_reqd > (io_answer + io_alen)) 5339*26947304SEvan Yan DEBUG3("IO space required by bridge" 5340*26947304SEvan Yan " more than available for %d slot(s)(%lx, %lx)", 5341*26947304SEvan Yan num_slots, io_answer, io_end); 5342*26947304SEvan Yan if (highest_bus_reqd > max_bus) 5343*26947304SEvan Yan DEBUG3("Bus numbers required by bridge" 5344*26947304SEvan Yan " more than available for %d slot(s)(%x, %x)", 5345*26947304SEvan Yan num_slots, new_bus, *highest_bus); 5346*26947304SEvan Yan #endif 5347*26947304SEvan Yan mem_end = MAX((MIN(mem_reqd, (mem_answer + mem_alen))), 5348*26947304SEvan Yan mem_end); 5349*26947304SEvan Yan io_end = MAX((MIN(io_reqd, (io_answer + io_alen))), io_end); 5350*26947304SEvan Yan *highest_bus = MAX((MIN(highest_bus_reqd, max_bus)), 5351*26947304SEvan Yan *highest_bus); 5352*26947304SEvan Yan DEBUG3("mem_end %lx, io_end %lx, highest_bus %x\n", 5353*26947304SEvan Yan mem_end, io_end, *highest_bus); 5354*26947304SEvan Yan 5355*26947304SEvan Yan mem_size = mem_end - mem_assigned; 5356*26947304SEvan Yan io_size = io_end - io_assigned; 5357*26947304SEvan Yan 5358*26947304SEvan Yan reg.pci_phys_mid = reg.pci_size_hi = 0; 5359*26947304SEvan Yan if (io_size > 0) { 5360*26947304SEvan Yan reg.pci_phys_hi = (PCI_REG_REL_M | PCI_ADDR_IO); 5361*26947304SEvan Yan reg.pci_phys_low = io_assigned; 5362*26947304SEvan Yan reg.pci_size_low = io_size; 5363*26947304SEvan Yan if (pcicfg_update_available_prop(new_child, ®)) { 5364*26947304SEvan Yan DEBUG0("Failed to update available prop " 5365*26947304SEvan Yan "(io)\n"); 5366*26947304SEvan Yan return (PCICFG_FAILURE); 5367*26947304SEvan Yan } 5368*26947304SEvan Yan } 5369*26947304SEvan Yan if (mem_size > 0) { 5370*26947304SEvan Yan reg.pci_phys_hi = (PCI_REG_REL_M | PCI_ADDR_MEM32); 5371*26947304SEvan Yan reg.pci_phys_low = mem_assigned; 5372*26947304SEvan Yan reg.pci_size_low = mem_size; 5373*26947304SEvan Yan if (pcicfg_update_available_prop(new_child, ®)) { 5374*26947304SEvan Yan DEBUG0("Failed to update available prop " 5375*26947304SEvan Yan "(memory)\n"); 5376*26947304SEvan Yan return (PCICFG_FAILURE); 5377*26947304SEvan Yan } 5378*26947304SEvan Yan } 5379*26947304SEvan Yan } 5380*26947304SEvan Yan 5381*26947304SEvan Yan /* 5382*26947304SEvan Yan * Give back unused memory space to parent. 5383*26947304SEvan Yan */ 5384*26947304SEvan Yan (void) ndi_ra_free(ddi_get_parent(new_child), 5385*26947304SEvan Yan mem_end, (mem_answer + mem_alen) - mem_end, NDI_RA_TYPE_MEM, 5386*26947304SEvan Yan NDI_RA_PASS); 5387*26947304SEvan Yan 5388*26947304SEvan Yan if (mem_end == mem_answer) { 5389*26947304SEvan Yan DEBUG0("No memory resources used\n"); 5390*26947304SEvan Yan /* 5391*26947304SEvan Yan * To prevent the bridge from forwarding any Memory 5392*26947304SEvan Yan * transactions, the Memory Limit will be programmed 5393*26947304SEvan Yan * with a smaller value than the Memory Base. 5394*26947304SEvan Yan */ 5395*26947304SEvan Yan pci_config_put16(h, PCI_BCNF_MEM_BASE, 0xffff); 5396*26947304SEvan Yan pci_config_put16(h, PCI_BCNF_MEM_LIMIT, 0); 5397*26947304SEvan Yan 5398*26947304SEvan Yan mem_size = 0; 5399*26947304SEvan Yan } else { 5400*26947304SEvan Yan /* 5401*26947304SEvan Yan * Reprogram the end of the memory. 5402*26947304SEvan Yan */ 5403*26947304SEvan Yan pci_config_put16(h, PCI_BCNF_MEM_LIMIT, 5404*26947304SEvan Yan PCICFG_HIWORD(mem_end) - 1); 5405*26947304SEvan Yan mem_size = mem_end - mem_base; 5406*26947304SEvan Yan } 5407*26947304SEvan Yan 5408*26947304SEvan Yan /* 5409*26947304SEvan Yan * Give back unused io space to parent. 5410*26947304SEvan Yan */ 5411*26947304SEvan Yan (void) ndi_ra_free(ddi_get_parent(new_child), 5412*26947304SEvan Yan io_end, (io_answer + io_alen) - io_end, 5413*26947304SEvan Yan NDI_RA_TYPE_IO, NDI_RA_PASS); 5414*26947304SEvan Yan 5415*26947304SEvan Yan if (io_end == io_answer) { 5416*26947304SEvan Yan DEBUG0("No IO Space resources used\n"); 5417*26947304SEvan Yan 5418*26947304SEvan Yan /* 5419*26947304SEvan Yan * To prevent the bridge from forwarding any I/O 5420*26947304SEvan Yan * transactions, the I/O Limit will be programmed 5421*26947304SEvan Yan * with a smaller value than the I/O Base. 5422*26947304SEvan Yan */ 5423*26947304SEvan Yan pci_config_put8(h, PCI_BCNF_IO_LIMIT_LOW, 0); 5424*26947304SEvan Yan pci_config_put16(h, PCI_BCNF_IO_LIMIT_HI, 0); 5425*26947304SEvan Yan pci_config_put8(h, PCI_BCNF_IO_BASE_LOW, 0xff); 5426*26947304SEvan Yan pci_config_put16(h, PCI_BCNF_IO_BASE_HI, 0); 5427*26947304SEvan Yan 5428*26947304SEvan Yan io_size = 0; 5429*26947304SEvan Yan } else { 5430*26947304SEvan Yan /* 5431*26947304SEvan Yan * Reprogram the end of the io space. 5432*26947304SEvan Yan */ 5433*26947304SEvan Yan pci_config_put8(h, PCI_BCNF_IO_LIMIT_LOW, 5434*26947304SEvan Yan PCICFG_HIBYTE(PCICFG_LOWORD( 5435*26947304SEvan Yan PCICFG_LOADDR(io_end) - 1))); 5436*26947304SEvan Yan 5437*26947304SEvan Yan pci_config_put16(h, PCI_BCNF_IO_LIMIT_HI, 5438*26947304SEvan Yan PCICFG_HIWORD(PCICFG_LOADDR(io_end - 1))); 5439*26947304SEvan Yan 5440*26947304SEvan Yan io_size = io_end - io_base; 5441*26947304SEvan Yan } 5442*26947304SEvan Yan 5443*26947304SEvan Yan if ((max_bus - *highest_bus) > 0) { 5444*26947304SEvan Yan /* 5445*26947304SEvan Yan * Give back unused bus numbers 5446*26947304SEvan Yan */ 5447*26947304SEvan Yan (void) ndi_ra_free(ddi_get_parent(new_child), 5448*26947304SEvan Yan *highest_bus+1, max_bus - *highest_bus, 5449*26947304SEvan Yan NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS); 5450*26947304SEvan Yan } 5451*26947304SEvan Yan 5452*26947304SEvan Yan /* 5453*26947304SEvan Yan * Set bus numbers to ranges encountered during scan 5454*26947304SEvan Yan */ 5455*26947304SEvan Yan pcicfg_set_bus_numbers(h, bus, new_bus, *highest_bus); 5456*26947304SEvan Yan 5457*26947304SEvan Yan bus_range[0] = pci_config_get8(h, PCI_BCNF_SECBUS); 5458*26947304SEvan Yan bus_range[1] = pci_config_get8(h, PCI_BCNF_SUBBUS); 5459*26947304SEvan Yan DEBUG1("End of bridge probe: bus_range[0] = %d\n", bus_range[0]); 5460*26947304SEvan Yan DEBUG1("End of bridge probe: bus_range[1] = %d\n", bus_range[1]); 5461*26947304SEvan Yan 5462*26947304SEvan Yan if (ndi_prop_update_int_array(DDI_DEV_T_NONE, new_child, 5463*26947304SEvan Yan "bus-range", bus_range, 2) != DDI_SUCCESS) { 5464*26947304SEvan Yan DEBUG0("Failed to set bus-range property"); 5465*26947304SEvan Yan return (PCICFG_FAILURE); 5466*26947304SEvan Yan } 5467*26947304SEvan Yan 5468*26947304SEvan Yan /* 5469*26947304SEvan Yan * Remove the ranges property if it exists since we will create 5470*26947304SEvan Yan * a new one. 5471*26947304SEvan Yan */ 5472*26947304SEvan Yan (void) ndi_prop_remove(DDI_DEV_T_NONE, new_child, "ranges"); 5473*26947304SEvan Yan 5474*26947304SEvan Yan DEBUG2("Creating Ranges property - Mem Address %lx Mem Size %x\n", 5475*26947304SEvan Yan mem_base, mem_size); 5476*26947304SEvan Yan DEBUG2(" - I/O Address %lx I/O Size %x\n", 5477*26947304SEvan Yan io_base, io_size); 5478*26947304SEvan Yan 5479*26947304SEvan Yan bzero((caddr_t)range, sizeof (pcicfg_range_t) * PCICFG_RANGE_LEN); 5480*26947304SEvan Yan 5481*26947304SEvan Yan range[0].child_hi = range[0].parent_hi |= (PCI_REG_REL_M | PCI_ADDR_IO); 5482*26947304SEvan Yan range[0].child_lo = range[0].parent_lo = io_base; 5483*26947304SEvan Yan range[1].child_hi = range[1].parent_hi |= 5484*26947304SEvan Yan (PCI_REG_REL_M | PCI_ADDR_MEM32); 5485*26947304SEvan Yan range[1].child_lo = range[1].parent_lo = mem_base; 5486*26947304SEvan Yan 5487*26947304SEvan Yan if (io_size > 0) { 5488*26947304SEvan Yan range[0].size_lo = io_size; 5489*26947304SEvan Yan if (pcicfg_update_ranges_prop(new_child, &range[0])) { 5490*26947304SEvan Yan DEBUG0("Failed to update ranges (io)\n"); 5491*26947304SEvan Yan return (PCICFG_FAILURE); 5492*26947304SEvan Yan } 5493*26947304SEvan Yan } 5494*26947304SEvan Yan if (mem_size > 0) { 5495*26947304SEvan Yan range[1].size_lo = mem_size; 5496*26947304SEvan Yan if (pcicfg_update_ranges_prop(new_child, &range[1])) { 5497*26947304SEvan Yan DEBUG0("Failed to update ranges (memory)\n"); 5498*26947304SEvan Yan return (PCICFG_FAILURE); 5499*26947304SEvan Yan } 5500*26947304SEvan Yan } 5501*26947304SEvan Yan 5502*26947304SEvan Yan /* 5503*26947304SEvan Yan * Remove the resource maps for the bridge since we no longer 5504*26947304SEvan Yan * need them. Note that the failure is ignored since the 5505*26947304SEvan Yan * ndi_devi_offline above may have already taken care of it via 5506*26947304SEvan Yan * driver detach. 5507*26947304SEvan Yan * It has been checked that there are no other reasons for 5508*26947304SEvan Yan * failure other than map itself being non-existent. So we are Ok. 5509*26947304SEvan Yan */ 5510*26947304SEvan Yan if (ndi_ra_map_destroy(new_child, NDI_RA_TYPE_MEM) == NDI_FAILURE) { 5511*26947304SEvan Yan /*EMPTY*/ 5512*26947304SEvan Yan DEBUG0("Can not destroy resource map - NDI_RA_TYPE_MEM\n"); 5513*26947304SEvan Yan } 5514*26947304SEvan Yan 5515*26947304SEvan Yan if (ndi_ra_map_destroy(new_child, NDI_RA_TYPE_IO) == NDI_FAILURE) { 5516*26947304SEvan Yan /*EMPTY*/ 5517*26947304SEvan Yan DEBUG0("Can not destroy resource map - NDI_RA_TYPE_IO\n"); 5518*26947304SEvan Yan } 5519*26947304SEvan Yan 5520*26947304SEvan Yan if (ndi_ra_map_destroy(new_child, NDI_RA_TYPE_PCI_BUSNUM) 5521*26947304SEvan Yan == NDI_FAILURE) { 5522*26947304SEvan Yan /*EMPTY*/ 5523*26947304SEvan Yan DEBUG0("Can't destroy resource map - NDI_RA_TYPE_PCI_BUSNUM\n"); 5524*26947304SEvan Yan } 5525*26947304SEvan Yan 5526*26947304SEvan Yan return (rval); 5527*26947304SEvan Yan } 5528*26947304SEvan Yan 5529*26947304SEvan Yan /* 5530*26947304SEvan Yan * Return PCICFG_SUCCESS if device exists at the specified address. 5531*26947304SEvan Yan * Return PCICFG_NODEVICE is no device exists at the specified address. 5532*26947304SEvan Yan * 5533*26947304SEvan Yan */ 5534*26947304SEvan Yan int 5535*26947304SEvan Yan pcicfg_config_setup(dev_info_t *dip, ddi_acc_handle_t *handle) 5536*26947304SEvan Yan { 5537*26947304SEvan Yan caddr_t virt; 5538*26947304SEvan Yan ddi_device_acc_attr_t attr; 5539*26947304SEvan Yan int status; 5540*26947304SEvan Yan int rlen; 5541*26947304SEvan Yan pci_regspec_t *reg; 5542*26947304SEvan Yan int ret = DDI_SUCCESS; 5543*26947304SEvan Yan int16_t tmp; 5544*26947304SEvan Yan /* 5545*26947304SEvan Yan * flags = PCICFG_CONF_INDIRECT_MAP if configuration space is indirectly 5546*26947304SEvan Yan * mapped, otherwise it is 0. "flags" is introduced in support of any 5547*26947304SEvan Yan * non transparent bridges, where configuration space is indirectly 5548*26947304SEvan Yan * mapped. 5549*26947304SEvan Yan * Indirect mapping is always true on sun4v systems. 5550*26947304SEvan Yan */ 5551*26947304SEvan Yan int flags = 0; 5552*26947304SEvan Yan 5553*26947304SEvan Yan 5554*26947304SEvan Yan /* 5555*26947304SEvan Yan * Get the pci register spec from the node 5556*26947304SEvan Yan */ 5557*26947304SEvan Yan status = ddi_getlongprop(DDI_DEV_T_ANY, 5558*26947304SEvan Yan dip, DDI_PROP_DONTPASS, "reg", (caddr_t)®, &rlen); 5559*26947304SEvan Yan 5560*26947304SEvan Yan switch (status) { 5561*26947304SEvan Yan case DDI_PROP_SUCCESS: 5562*26947304SEvan Yan break; 5563*26947304SEvan Yan case DDI_PROP_NO_MEMORY: 5564*26947304SEvan Yan DEBUG0("reg present, but unable to get memory\n"); 5565*26947304SEvan Yan return (PCICFG_FAILURE); 5566*26947304SEvan Yan default: 5567*26947304SEvan Yan DEBUG0("no reg property\n"); 5568*26947304SEvan Yan return (PCICFG_FAILURE); 5569*26947304SEvan Yan } 5570*26947304SEvan Yan 5571*26947304SEvan Yan if (pcicfg_indirect_map(dip) == DDI_SUCCESS) 5572*26947304SEvan Yan flags |= PCICFG_CONF_INDIRECT_MAP; 5573*26947304SEvan Yan 5574*26947304SEvan Yan /* 5575*26947304SEvan Yan * Map in configuration space (temporarily) 5576*26947304SEvan Yan */ 5577*26947304SEvan Yan attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 5578*26947304SEvan Yan attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 5579*26947304SEvan Yan attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 5580*26947304SEvan Yan attr.devacc_attr_access = DDI_CAUTIOUS_ACC; 5581*26947304SEvan Yan 5582*26947304SEvan Yan #ifdef EFCODE21554 5583*26947304SEvan Yan if (ddi_regs_map_setup(dip, 0, &virt, 5584*26947304SEvan Yan 0, 0, &attr, handle) != DDI_SUCCESS) 5585*26947304SEvan Yan #else 5586*26947304SEvan Yan if (pcicfg_map_phys(dip, reg, &virt, &attr, handle) 5587*26947304SEvan Yan != DDI_SUCCESS) 5588*26947304SEvan Yan #endif 5589*26947304SEvan Yan { 5590*26947304SEvan Yan DEBUG0("pcicfg_config_setup():" 5591*26947304SEvan Yan "Failed to setup config space\n"); 5592*26947304SEvan Yan 5593*26947304SEvan Yan kmem_free((caddr_t)reg, rlen); 5594*26947304SEvan Yan return (PCICFG_FAILURE); 5595*26947304SEvan Yan } 5596*26947304SEvan Yan 5597*26947304SEvan Yan if (flags & PCICFG_CONF_INDIRECT_MAP) { 5598*26947304SEvan Yan /* 5599*26947304SEvan Yan * need to use DDI interfaces as the conf space is 5600*26947304SEvan Yan * cannot be directly accessed by the host. 5601*26947304SEvan Yan */ 5602*26947304SEvan Yan tmp = (int16_t)ddi_get16(*handle, (uint16_t *)virt); 5603*26947304SEvan Yan } else { 5604*26947304SEvan Yan ret = ddi_peek16(dip, (int16_t *)virt, &tmp); 5605*26947304SEvan Yan } 5606*26947304SEvan Yan 5607*26947304SEvan Yan if (ret == DDI_SUCCESS) { 5608*26947304SEvan Yan if (tmp == -1) { 5609*26947304SEvan Yan DEBUG1("NO DEVICEFOUND, read %x\n", tmp); 5610*26947304SEvan Yan ret = PCICFG_NODEVICE; 5611*26947304SEvan Yan } else { 5612*26947304SEvan Yan /* XXX - Need to check why HV is returning 0 */ 5613*26947304SEvan Yan if (tmp == 0) { 5614*26947304SEvan Yan DEBUG0("Device Not Ready yet ?"); 5615*26947304SEvan Yan ret = PCICFG_NODEVICE; 5616*26947304SEvan Yan } else { 5617*26947304SEvan Yan DEBUG1("DEVICEFOUND, read %x\n", tmp); 5618*26947304SEvan Yan ret = PCICFG_SUCCESS; 5619*26947304SEvan Yan } 5620*26947304SEvan Yan } 5621*26947304SEvan Yan } else { 5622*26947304SEvan Yan DEBUG0("ddi_peek failed, must be NODEVICE\n"); 5623*26947304SEvan Yan ret = PCICFG_NODEVICE; 5624*26947304SEvan Yan } 5625*26947304SEvan Yan 5626*26947304SEvan Yan /* 5627*26947304SEvan Yan * A bug in XMITS 3.0 causes us to miss the Master Abort Split 5628*26947304SEvan Yan * Completion message. The result is the error message being 5629*26947304SEvan Yan * sent back as part of the config data. If the first two words 5630*26947304SEvan Yan * of the config space happen to be the same as the Master Abort 5631*26947304SEvan Yan * message, then report back that there is no device there. 5632*26947304SEvan Yan */ 5633*26947304SEvan Yan if ((ret == PCICFG_SUCCESS) && !(flags & PCICFG_CONF_INDIRECT_MAP)) { 5634*26947304SEvan Yan int32_t pcix_scm; 5635*26947304SEvan Yan 5636*26947304SEvan Yan #define PCICFG_PCIX_SCM 0x10000004 5637*26947304SEvan Yan 5638*26947304SEvan Yan pcix_scm = 0; 5639*26947304SEvan Yan (void) ddi_peek32(dip, (int32_t *)virt, &pcix_scm); 5640*26947304SEvan Yan if (pcix_scm == PCICFG_PCIX_SCM) { 5641*26947304SEvan Yan pcix_scm = 0; 5642*26947304SEvan Yan (void) ddi_peek32(dip, 5643*26947304SEvan Yan (int32_t *)(virt + 4), &pcix_scm); 5644*26947304SEvan Yan if (pcix_scm == PCICFG_PCIX_SCM) 5645*26947304SEvan Yan ret = PCICFG_NODEVICE; 5646*26947304SEvan Yan } 5647*26947304SEvan Yan } 5648*26947304SEvan Yan 5649*26947304SEvan Yan if (ret == PCICFG_NODEVICE) 5650*26947304SEvan Yan #ifdef EFCODE21554 5651*26947304SEvan Yan ddi_regs_map_free(handle); 5652*26947304SEvan Yan #else 5653*26947304SEvan Yan pcicfg_unmap_phys(handle, reg); 5654*26947304SEvan Yan #endif 5655*26947304SEvan Yan 5656*26947304SEvan Yan kmem_free((caddr_t)reg, rlen); 5657*26947304SEvan Yan 5658*26947304SEvan Yan return (ret); 5659*26947304SEvan Yan 5660*26947304SEvan Yan } 5661*26947304SEvan Yan 5662*26947304SEvan Yan static void 5663*26947304SEvan Yan pcicfg_config_teardown(ddi_acc_handle_t *handle) 5664*26947304SEvan Yan { 5665*26947304SEvan Yan (void) ddi_regs_map_free(handle); 5666*26947304SEvan Yan } 5667*26947304SEvan Yan 5668*26947304SEvan Yan static int 5669*26947304SEvan Yan pcicfg_add_config_reg(dev_info_t *dip, 5670*26947304SEvan Yan uint_t bus, uint_t device, uint_t func) 5671*26947304SEvan Yan { 5672*26947304SEvan Yan int reg[10] = { PCI_ADDR_CONFIG, 0, 0, 0, 0}; 5673*26947304SEvan Yan 5674*26947304SEvan Yan reg[0] = PCICFG_MAKE_REG_HIGH(bus, device, func, 0); 5675*26947304SEvan Yan 5676*26947304SEvan Yan return (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, 5677*26947304SEvan Yan "reg", reg, 5)); 5678*26947304SEvan Yan } 5679*26947304SEvan Yan 5680*26947304SEvan Yan static int 5681*26947304SEvan Yan pcicfg_dump_assigned(dev_info_t *dip) 5682*26947304SEvan Yan { 5683*26947304SEvan Yan pci_regspec_t *reg; 5684*26947304SEvan Yan int length; 5685*26947304SEvan Yan int rcount; 5686*26947304SEvan Yan int i; 5687*26947304SEvan Yan 5688*26947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 5689*26947304SEvan Yan DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)®, 5690*26947304SEvan Yan &length) != DDI_PROP_SUCCESS) { 5691*26947304SEvan Yan DEBUG0("Failed to read assigned-addresses property\n"); 5692*26947304SEvan Yan return (PCICFG_FAILURE); 5693*26947304SEvan Yan } 5694*26947304SEvan Yan 5695*26947304SEvan Yan rcount = length / sizeof (pci_regspec_t); 5696*26947304SEvan Yan for (i = 0; i < rcount; i++) { 5697*26947304SEvan Yan DEBUG4("pcicfg_dump_assigned - size=%x low=%x mid=%x high=%x\n", 5698*26947304SEvan Yan reg[i].pci_size_low, reg[i].pci_phys_low, 5699*26947304SEvan Yan reg[i].pci_phys_mid, reg[i].pci_phys_hi); 5700*26947304SEvan Yan } 5701*26947304SEvan Yan /* 5702*26947304SEvan Yan * Don't forget to free up memory from ddi_getlongprop 5703*26947304SEvan Yan */ 5704*26947304SEvan Yan kmem_free((caddr_t)reg, length); 5705*26947304SEvan Yan 5706*26947304SEvan Yan return (PCICFG_SUCCESS); 5707*26947304SEvan Yan } 5708*26947304SEvan Yan 5709*26947304SEvan Yan #ifdef PCICFG_INTERPRET_FCODE 5710*26947304SEvan Yan static int 5711*26947304SEvan Yan pcicfg_load_fcode(dev_info_t *dip, uint_t bus, uint_t device, uint_t func, 5712*26947304SEvan Yan uint16_t vendor_id, uint16_t device_id, uchar_t **fcode_addr, 5713*26947304SEvan Yan int *fcode_size, int rom_paddr, int rom_size) 5714*26947304SEvan Yan { 5715*26947304SEvan Yan pci_regspec_t p; 5716*26947304SEvan Yan int pci_data; 5717*26947304SEvan Yan int start_of_fcode; 5718*26947304SEvan Yan int image_length; 5719*26947304SEvan Yan int code_type; 5720*26947304SEvan Yan ddi_acc_handle_t h; 5721*26947304SEvan Yan ddi_device_acc_attr_t acc; 5722*26947304SEvan Yan uint8_t *addr; 5723*26947304SEvan Yan int8_t image_not_found, indicator; 5724*26947304SEvan Yan uint16_t vendor_id_img, device_id_img; 5725*26947304SEvan Yan int16_t rom_sig; 5726*26947304SEvan Yan #ifdef DEBUG 5727*26947304SEvan Yan int i; 5728*26947304SEvan Yan #endif 5729*26947304SEvan Yan 5730*26947304SEvan Yan DEBUG4("pcicfg_load_fcode() - " 5731*26947304SEvan Yan "bus %x device =%x func=%x rom_paddr=%lx\n", 5732*26947304SEvan Yan bus, device, func, rom_paddr); 5733*26947304SEvan Yan DEBUG2("pcicfg_load_fcode() - vendor_id=%x device_id=%x\n", 5734*26947304SEvan Yan vendor_id, device_id); 5735*26947304SEvan Yan 5736*26947304SEvan Yan *fcode_size = 0; 5737*26947304SEvan Yan *fcode_addr = NULL; 5738*26947304SEvan Yan 5739*26947304SEvan Yan acc.devacc_attr_version = DDI_DEVICE_ATTR_V0; 5740*26947304SEvan Yan acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 5741*26947304SEvan Yan acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 5742*26947304SEvan Yan 5743*26947304SEvan Yan p.pci_phys_hi = PCI_ADDR_MEM32 | PCICFG_MAKE_REG_HIGH(bus, device, 5744*26947304SEvan Yan func, PCI_CONF_ROM); 5745*26947304SEvan Yan 5746*26947304SEvan Yan p.pci_phys_mid = 0; 5747*26947304SEvan Yan p.pci_phys_low = 0; 5748*26947304SEvan Yan 5749*26947304SEvan Yan p.pci_size_low = rom_size; 5750*26947304SEvan Yan p.pci_size_hi = 0; 5751*26947304SEvan Yan 5752*26947304SEvan Yan if (pcicfg_map_phys(dip, &p, (caddr_t *)&addr, &acc, &h)) { 5753*26947304SEvan Yan DEBUG1("Can Not map in ROM %x\n", p.pci_phys_low); 5754*26947304SEvan Yan return (PCICFG_FAILURE); 5755*26947304SEvan Yan } 5756*26947304SEvan Yan 5757*26947304SEvan Yan /* 5758*26947304SEvan Yan * Walk the ROM to find the proper image for this device. 5759*26947304SEvan Yan */ 5760*26947304SEvan Yan image_not_found = 1; 5761*26947304SEvan Yan while (image_not_found) { 5762*26947304SEvan Yan DEBUG1("Expansion ROM maps to %lx\n", addr); 5763*26947304SEvan Yan 5764*26947304SEvan Yan #ifdef DEBUG 5765*26947304SEvan Yan if (pcicfg_dump_fcode) { 5766*26947304SEvan Yan for (i = 0; i < 100; i++) 5767*26947304SEvan Yan DEBUG2("ROM 0x%x --> 0x%x\n", i, 5768*26947304SEvan Yan ddi_get8(h, (uint8_t *)(addr + i))); 5769*26947304SEvan Yan } 5770*26947304SEvan Yan #endif 5771*26947304SEvan Yan 5772*26947304SEvan Yan /* 5773*26947304SEvan Yan * Some device say they have an Expansion ROM, but do not, so 5774*26947304SEvan Yan * for non-21554 devices use peek so we don't panic due to 5775*26947304SEvan Yan * accessing non existent memory. 5776*26947304SEvan Yan */ 5777*26947304SEvan Yan if (pcicfg_indirect_map(dip) == DDI_SUCCESS) { 5778*26947304SEvan Yan rom_sig = ddi_get16(h, 5779*26947304SEvan Yan (uint16_t *)(addr + PCI_ROM_SIGNATURE)); 5780*26947304SEvan Yan } else { 5781*26947304SEvan Yan if (ddi_peek16(dip, 5782*26947304SEvan Yan (int16_t *)(addr + PCI_ROM_SIGNATURE), &rom_sig)) { 5783*26947304SEvan Yan cmn_err(CE_WARN, 5784*26947304SEvan Yan "PCI Expansion ROM is not accessible"); 5785*26947304SEvan Yan pcicfg_unmap_phys(&h, &p); 5786*26947304SEvan Yan return (PCICFG_FAILURE); 5787*26947304SEvan Yan } 5788*26947304SEvan Yan } 5789*26947304SEvan Yan 5790*26947304SEvan Yan /* 5791*26947304SEvan Yan * Validate the ROM Signature. 5792*26947304SEvan Yan */ 5793*26947304SEvan Yan if ((uint16_t)rom_sig != 0xaa55) { 5794*26947304SEvan Yan DEBUG1("Invalid ROM Signature %x\n", (uint16_t)rom_sig); 5795*26947304SEvan Yan pcicfg_unmap_phys(&h, &p); 5796*26947304SEvan Yan return (PCICFG_FAILURE); 5797*26947304SEvan Yan } 5798*26947304SEvan Yan 5799*26947304SEvan Yan DEBUG0("Valid ROM Signature Found\n"); 5800*26947304SEvan Yan 5801*26947304SEvan Yan start_of_fcode = ddi_get16(h, (uint16_t *)(addr + 2)); 5802*26947304SEvan Yan 5803*26947304SEvan Yan pci_data = ddi_get16(h, 5804*26947304SEvan Yan (uint16_t *)(addr + PCI_ROM_PCI_DATA_STRUCT_PTR)); 5805*26947304SEvan Yan 5806*26947304SEvan Yan DEBUG2("Pointer To PCI Data Structure %x %x\n", pci_data, 5807*26947304SEvan Yan addr); 5808*26947304SEvan Yan 5809*26947304SEvan Yan /* 5810*26947304SEvan Yan * Validate the PCI Data Structure Signature. 5811*26947304SEvan Yan * 0x52494350 = "PCIR" 5812*26947304SEvan Yan */ 5813*26947304SEvan Yan 5814*26947304SEvan Yan if (ddi_get8(h, (uint8_t *)(addr + pci_data)) != 0x50) { 5815*26947304SEvan Yan DEBUG0("Invalid PCI Data Structure Signature\n"); 5816*26947304SEvan Yan pcicfg_unmap_phys(&h, &p); 5817*26947304SEvan Yan return (PCICFG_FAILURE); 5818*26947304SEvan Yan } 5819*26947304SEvan Yan 5820*26947304SEvan Yan if (ddi_get8(h, (uint8_t *)(addr + pci_data + 1)) != 0x43) { 5821*26947304SEvan Yan DEBUG0("Invalid PCI Data Structure Signature\n"); 5822*26947304SEvan Yan pcicfg_unmap_phys(&h, &p); 5823*26947304SEvan Yan return (PCICFG_FAILURE); 5824*26947304SEvan Yan } 5825*26947304SEvan Yan if (ddi_get8(h, (uint8_t *)(addr + pci_data + 2)) != 0x49) { 5826*26947304SEvan Yan DEBUG0("Invalid PCI Data Structure Signature\n"); 5827*26947304SEvan Yan pcicfg_unmap_phys(&h, &p); 5828*26947304SEvan Yan return (PCICFG_FAILURE); 5829*26947304SEvan Yan } 5830*26947304SEvan Yan if (ddi_get8(h, (uint8_t *)(addr + pci_data + 3)) != 0x52) { 5831*26947304SEvan Yan DEBUG0("Invalid PCI Data Structure Signature\n"); 5832*26947304SEvan Yan pcicfg_unmap_phys(&h, &p); 5833*26947304SEvan Yan return (PCICFG_FAILURE); 5834*26947304SEvan Yan } 5835*26947304SEvan Yan 5836*26947304SEvan Yan /* 5837*26947304SEvan Yan * Is this image for this device? 5838*26947304SEvan Yan */ 5839*26947304SEvan Yan vendor_id_img = ddi_get16(h, 5840*26947304SEvan Yan (uint16_t *)(addr + pci_data + PCI_PDS_VENDOR_ID)); 5841*26947304SEvan Yan device_id_img = ddi_get16(h, 5842*26947304SEvan Yan (uint16_t *)(addr + pci_data + PCI_PDS_DEVICE_ID)); 5843*26947304SEvan Yan 5844*26947304SEvan Yan DEBUG2("This image is for vendor_id=%x device_id=%x\n", 5845*26947304SEvan Yan vendor_id_img, device_id_img); 5846*26947304SEvan Yan 5847*26947304SEvan Yan code_type = ddi_get8(h, addr + pci_data + PCI_PDS_CODE_TYPE); 5848*26947304SEvan Yan 5849*26947304SEvan Yan switch (code_type) { 5850*26947304SEvan Yan case PCI_PDS_CODE_TYPE_PCAT: 5851*26947304SEvan Yan DEBUG0("ROM is of x86/PC-AT Type\n"); 5852*26947304SEvan Yan break; 5853*26947304SEvan Yan case PCI_PDS_CODE_TYPE_OPEN_FW: 5854*26947304SEvan Yan DEBUG0("ROM is of Open Firmware Type\n"); 5855*26947304SEvan Yan break; 5856*26947304SEvan Yan default: 5857*26947304SEvan Yan DEBUG1("ROM is of Unknown Type 0x%x\n", code_type); 5858*26947304SEvan Yan break; 5859*26947304SEvan Yan } 5860*26947304SEvan Yan 5861*26947304SEvan Yan if ((vendor_id_img != vendor_id) || 5862*26947304SEvan Yan (device_id_img != device_id) || 5863*26947304SEvan Yan (code_type != PCI_PDS_CODE_TYPE_OPEN_FW)) { 5864*26947304SEvan Yan DEBUG0("Firmware Image is not for this device..." 5865*26947304SEvan Yan "goto next image\n"); 5866*26947304SEvan Yan /* 5867*26947304SEvan Yan * Read indicator byte to see if there is another 5868*26947304SEvan Yan * image in the ROM 5869*26947304SEvan Yan */ 5870*26947304SEvan Yan indicator = ddi_get8(h, 5871*26947304SEvan Yan (uint8_t *)(addr + pci_data + PCI_PDS_INDICATOR)); 5872*26947304SEvan Yan 5873*26947304SEvan Yan if (indicator != 1) { 5874*26947304SEvan Yan /* 5875*26947304SEvan Yan * There is another image in the ROM. 5876*26947304SEvan Yan */ 5877*26947304SEvan Yan image_length = ddi_get16(h, (uint16_t *)(addr + 5878*26947304SEvan Yan pci_data + PCI_PDS_IMAGE_LENGTH)) * 512; 5879*26947304SEvan Yan 5880*26947304SEvan Yan addr += image_length; 5881*26947304SEvan Yan } else { 5882*26947304SEvan Yan /* 5883*26947304SEvan Yan * There are no more images. 5884*26947304SEvan Yan */ 5885*26947304SEvan Yan DEBUG0("There are no more images in the ROM\n"); 5886*26947304SEvan Yan pcicfg_unmap_phys(&h, &p); 5887*26947304SEvan Yan 5888*26947304SEvan Yan return (PCICFG_FAILURE); 5889*26947304SEvan Yan } 5890*26947304SEvan Yan } else { 5891*26947304SEvan Yan DEBUG0("Correct image was found\n"); 5892*26947304SEvan Yan image_not_found = 0; /* Image was found */ 5893*26947304SEvan Yan } 5894*26947304SEvan Yan } 5895*26947304SEvan Yan 5896*26947304SEvan Yan *fcode_size = (ddi_get8(h, addr + start_of_fcode + 4) << 24) | 5897*26947304SEvan Yan (ddi_get8(h, addr + start_of_fcode + 5) << 16) | 5898*26947304SEvan Yan (ddi_get8(h, addr + start_of_fcode + 6) << 8) | 5899*26947304SEvan Yan (ddi_get8(h, addr + start_of_fcode + 7)); 5900*26947304SEvan Yan 5901*26947304SEvan Yan DEBUG1("Fcode Size %x\n", *fcode_size); 5902*26947304SEvan Yan 5903*26947304SEvan Yan /* 5904*26947304SEvan Yan * Allocate page aligned buffer space 5905*26947304SEvan Yan */ 5906*26947304SEvan Yan *fcode_addr = kmem_zalloc(ptob(btopr(*fcode_size)), KM_SLEEP); 5907*26947304SEvan Yan 5908*26947304SEvan Yan if (*fcode_addr == NULL) { 5909*26947304SEvan Yan DEBUG0("kmem_zalloc returned NULL\n"); 5910*26947304SEvan Yan pcicfg_unmap_phys(&h, &p); 5911*26947304SEvan Yan return (PCICFG_FAILURE); 5912*26947304SEvan Yan } 5913*26947304SEvan Yan 5914*26947304SEvan Yan DEBUG1("Fcode Addr %lx\n", *fcode_addr); 5915*26947304SEvan Yan 5916*26947304SEvan Yan ddi_rep_get8(h, *fcode_addr, addr + start_of_fcode, *fcode_size, 5917*26947304SEvan Yan DDI_DEV_AUTOINCR); 5918*26947304SEvan Yan 5919*26947304SEvan Yan pcicfg_unmap_phys(&h, &p); 5920*26947304SEvan Yan 5921*26947304SEvan Yan return (PCICFG_SUCCESS); 5922*26947304SEvan Yan } 5923*26947304SEvan Yan 5924*26947304SEvan Yan static int 5925*26947304SEvan Yan pcicfg_fcode_assign_bars(ddi_acc_handle_t h, dev_info_t *dip, uint_t bus, 5926*26947304SEvan Yan uint_t device, uint_t func, int32_t fc_request, pci_regspec_t *rom_regspec) 5927*26947304SEvan Yan { 5928*26947304SEvan Yan /* 5929*26947304SEvan Yan * Assign values to all BARs so that it is safe to turn on the 5930*26947304SEvan Yan * device for accessing the fcode on the PROM. On successful 5931*26947304SEvan Yan * exit from this function, "assigned-addresses" are created 5932*26947304SEvan Yan * for all BARs and ROM BAR is enabled. Also, rom_regspec is 5933*26947304SEvan Yan * filled with the values that can be used to free up this 5934*26947304SEvan Yan * resource later. 5935*26947304SEvan Yan */ 5936*26947304SEvan Yan uint32_t request, hiword, size; 5937*26947304SEvan Yan pci_regspec_t phys_spec; 5938*26947304SEvan Yan ndi_ra_request_t req; 5939*26947304SEvan Yan uint64_t mem_answer, mem_alen; 5940*26947304SEvan Yan int i; 5941*26947304SEvan Yan 5942*26947304SEvan Yan DEBUG1("pcicfg_fcode_assign_bars :%s\n", DEVI(dip)->devi_name); 5943*26947304SEvan Yan 5944*26947304SEvan Yan /* 5945*26947304SEvan Yan * Process the BARs. 5946*26947304SEvan Yan */ 5947*26947304SEvan Yan for (i = PCI_CONF_BASE0; i <= PCI_CONF_BASE5; ) { 5948*26947304SEvan Yan pci_config_put32(h, i, 0xffffffff); 5949*26947304SEvan Yan request = pci_config_get32(h, i); 5950*26947304SEvan Yan /* 5951*26947304SEvan Yan * Check if implemented 5952*26947304SEvan Yan */ 5953*26947304SEvan Yan if (request == 0) { 5954*26947304SEvan Yan DEBUG1("pcicfg_fcode_assign_bars :" 5955*26947304SEvan Yan "BASE register [0x%x] asks for 0(32)\n", i); 5956*26947304SEvan Yan i += 4; 5957*26947304SEvan Yan continue; 5958*26947304SEvan Yan } 5959*26947304SEvan Yan /* 5960*26947304SEvan Yan * Build the phys_spec for this BAR 5961*26947304SEvan Yan */ 5962*26947304SEvan Yan hiword = PCICFG_MAKE_REG_HIGH(bus, device, func, i); 5963*26947304SEvan Yan size = (~(PCI_BASE_M_ADDR_M & request)) + 1; 5964*26947304SEvan Yan 5965*26947304SEvan Yan DEBUG3("pcicfg_fcode_assign_bars :" 5966*26947304SEvan Yan "BASE register [0x%x] asks for [0x%x]=[0x%x]\n", 5967*26947304SEvan Yan i, request, size); 5968*26947304SEvan Yan 5969*26947304SEvan Yan if ((PCI_BASE_SPACE_M & request) == PCI_BASE_SPACE_MEM) { 5970*26947304SEvan Yan if ((PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_MEM) { 5971*26947304SEvan Yan hiword |= PCI_ADDR_MEM32; 5972*26947304SEvan Yan } else if ((PCI_BASE_TYPE_M & request) 5973*26947304SEvan Yan == PCI_BASE_TYPE_ALL) { 5974*26947304SEvan Yan hiword |= PCI_ADDR_MEM64; 5975*26947304SEvan Yan } 5976*26947304SEvan Yan if (request & PCI_BASE_PREF_M) 5977*26947304SEvan Yan hiword |= PCI_REG_PF_M; 5978*26947304SEvan Yan } else { 5979*26947304SEvan Yan hiword |= PCI_ADDR_IO; 5980*26947304SEvan Yan } 5981*26947304SEvan Yan phys_spec.pci_phys_hi = hiword; 5982*26947304SEvan Yan phys_spec.pci_phys_mid = 0; 5983*26947304SEvan Yan phys_spec.pci_phys_low = 0; 5984*26947304SEvan Yan phys_spec.pci_size_hi = 0; 5985*26947304SEvan Yan phys_spec.pci_size_low = size; 5986*26947304SEvan Yan 5987*26947304SEvan Yan /* 5988*26947304SEvan Yan * The following function 5989*26947304SEvan Yan * - allocates address space 5990*26947304SEvan Yan * - programs the BAR 5991*26947304SEvan Yan * - adds an "assigned-addresses" property 5992*26947304SEvan Yan */ 5993*26947304SEvan Yan if (pcicfg_alloc_resource(dip, phys_spec)) { 5994*26947304SEvan Yan cmn_err(CE_WARN, "failed to allocate %d bytes" 5995*26947304SEvan Yan " for dev %s BASE register [0x%x]\n", 5996*26947304SEvan Yan size, DEVI(dip)->devi_name, i); 5997*26947304SEvan Yan goto failure; 5998*26947304SEvan Yan } 5999*26947304SEvan Yan if ((PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_ALL) { 6000*26947304SEvan Yan /* 6001*26947304SEvan Yan * 64 bit, should be in memory space. 6002*26947304SEvan Yan */ 6003*26947304SEvan Yan i += 8; 6004*26947304SEvan Yan } else { 6005*26947304SEvan Yan /* 6006*26947304SEvan Yan * 32 bit, either memory or I/O space. 6007*26947304SEvan Yan */ 6008*26947304SEvan Yan i += 4; 6009*26947304SEvan Yan } 6010*26947304SEvan Yan } 6011*26947304SEvan Yan 6012*26947304SEvan Yan /* 6013*26947304SEvan Yan * Handle ROM BAR. We do not use the common 6014*26947304SEvan Yan * resource allocator function because we need to 6015*26947304SEvan Yan * return reg spec to the caller. 6016*26947304SEvan Yan */ 6017*26947304SEvan Yan size = (~(PCI_BASE_ROM_ADDR_M & fc_request)) + 1; 6018*26947304SEvan Yan 6019*26947304SEvan Yan DEBUG3("BASE register [0x%x] asks for " 6020*26947304SEvan Yan "[0x%x]=[0x%x]\n", PCI_CONF_ROM, fc_request, size); 6021*26947304SEvan Yan 6022*26947304SEvan Yan bzero((caddr_t)&req, sizeof (ndi_ra_request_t)); 6023*26947304SEvan Yan 6024*26947304SEvan Yan req.ra_boundbase = 0; 6025*26947304SEvan Yan req.ra_boundlen = PCICFG_4GIG_LIMIT; 6026*26947304SEvan Yan req.ra_len = size; 6027*26947304SEvan Yan req.ra_flags |= NDI_RA_ALIGN_SIZE; 6028*26947304SEvan Yan req.ra_flags ^= NDI_RA_ALLOC_BOUNDED; 6029*26947304SEvan Yan 6030*26947304SEvan Yan if (ndi_ra_alloc(ddi_get_parent(dip), 6031*26947304SEvan Yan &req, &mem_answer, &mem_alen, 6032*26947304SEvan Yan NDI_RA_TYPE_MEM, NDI_RA_PASS)) { 6033*26947304SEvan Yan cmn_err(CE_WARN, "failed to allocate %d bytes" 6034*26947304SEvan Yan " for dev %s ROM BASE register\n", 6035*26947304SEvan Yan size, DEVI(dip)->devi_name); 6036*26947304SEvan Yan goto failure; 6037*26947304SEvan Yan } 6038*26947304SEvan Yan 6039*26947304SEvan Yan DEBUG3("ROM addr = [0x%x.%x] len [0x%x]\n", 6040*26947304SEvan Yan PCICFG_HIADDR(mem_answer), 6041*26947304SEvan Yan PCICFG_LOADDR(mem_answer), mem_alen); 6042*26947304SEvan Yan 6043*26947304SEvan Yan /* 6044*26947304SEvan Yan * Assign address space and enable ROM. 6045*26947304SEvan Yan */ 6046*26947304SEvan Yan pci_config_put32(h, PCI_CONF_ROM, 6047*26947304SEvan Yan PCICFG_LOADDR(mem_answer) | PCI_BASE_ROM_ENABLE); 6048*26947304SEvan Yan 6049*26947304SEvan Yan /* 6050*26947304SEvan Yan * Add resource to assigned-addresses. 6051*26947304SEvan Yan */ 6052*26947304SEvan Yan phys_spec.pci_phys_hi = PCICFG_MAKE_REG_HIGH(bus, device, func, \ 6053*26947304SEvan Yan PCI_CONF_ROM) | PCI_ADDR_MEM32; 6054*26947304SEvan Yan if (fc_request & PCI_BASE_PREF_M) 6055*26947304SEvan Yan phys_spec.pci_phys_hi |= PCI_REG_PF_M; 6056*26947304SEvan Yan phys_spec.pci_phys_mid = 0; 6057*26947304SEvan Yan phys_spec.pci_phys_low = PCICFG_LOADDR(mem_answer); 6058*26947304SEvan Yan phys_spec.pci_size_hi = 0; 6059*26947304SEvan Yan phys_spec.pci_size_low = size; 6060*26947304SEvan Yan 6061*26947304SEvan Yan if (pcicfg_update_assigned_prop(dip, &phys_spec) 6062*26947304SEvan Yan != PCICFG_SUCCESS) { 6063*26947304SEvan Yan cmn_err(CE_WARN, "failed to update" 6064*26947304SEvan Yan " assigned-address property for dev %s\n", 6065*26947304SEvan Yan DEVI(dip)->devi_name); 6066*26947304SEvan Yan goto failure; 6067*26947304SEvan Yan } 6068*26947304SEvan Yan /* 6069*26947304SEvan Yan * Copy out the reg spec. 6070*26947304SEvan Yan */ 6071*26947304SEvan Yan *rom_regspec = phys_spec; 6072*26947304SEvan Yan 6073*26947304SEvan Yan return (PCICFG_SUCCESS); 6074*26947304SEvan Yan 6075*26947304SEvan Yan failure: 6076*26947304SEvan Yan /* 6077*26947304SEvan Yan * We came in with no "assigned-addresses". 6078*26947304SEvan Yan * Free up the resources we may have allocated. 6079*26947304SEvan Yan */ 6080*26947304SEvan Yan (void) pcicfg_free_device_resources(dip, 0); 6081*26947304SEvan Yan 6082*26947304SEvan Yan return (PCICFG_FAILURE); 6083*26947304SEvan Yan } 6084*26947304SEvan Yan 6085*26947304SEvan Yan #endif /* PCICFG_INTERPRET_FCODE */ 6086*26947304SEvan Yan 6087*26947304SEvan Yan static int 6088*26947304SEvan Yan pcicfg_free_all_resources(dev_info_t *dip) 6089*26947304SEvan Yan { 6090*26947304SEvan Yan pci_regspec_t *assigned; 6091*26947304SEvan Yan int assigned_len; 6092*26947304SEvan Yan int acount; 6093*26947304SEvan Yan int i; 6094*26947304SEvan Yan 6095*26947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 6096*26947304SEvan Yan DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned, 6097*26947304SEvan Yan &assigned_len) != DDI_PROP_SUCCESS) { 6098*26947304SEvan Yan DEBUG0("Failed to read assigned-addresses property\n"); 6099*26947304SEvan Yan return (PCICFG_FAILURE); 6100*26947304SEvan Yan } 6101*26947304SEvan Yan 6102*26947304SEvan Yan acount = assigned_len / sizeof (pci_regspec_t); 6103*26947304SEvan Yan 6104*26947304SEvan Yan for (i = 0; i < acount; i++) { 6105*26947304SEvan Yan if (pcicfg_free_resource(dip, assigned[i], 0)) { 6106*26947304SEvan Yan /* 6107*26947304SEvan Yan * Dont forget to free mem from ddi_getlongprop 6108*26947304SEvan Yan */ 6109*26947304SEvan Yan kmem_free((caddr_t)assigned, assigned_len); 6110*26947304SEvan Yan return (PCICFG_FAILURE); 6111*26947304SEvan Yan } 6112*26947304SEvan Yan } 6113*26947304SEvan Yan 6114*26947304SEvan Yan /* 6115*26947304SEvan Yan * Don't forget to free up memory from ddi_getlongprop 6116*26947304SEvan Yan */ 6117*26947304SEvan Yan if (assigned_len) 6118*26947304SEvan Yan kmem_free((caddr_t)assigned, assigned_len); 6119*26947304SEvan Yan 6120*26947304SEvan Yan return (PCICFG_SUCCESS); 6121*26947304SEvan Yan } 6122*26947304SEvan Yan static int 6123*26947304SEvan Yan pcicfg_alloc_new_resources(dev_info_t *dip) 6124*26947304SEvan Yan { 6125*26947304SEvan Yan pci_regspec_t *assigned, *reg; 6126*26947304SEvan Yan int assigned_len, reg_len; 6127*26947304SEvan Yan int acount, rcount; 6128*26947304SEvan Yan int i, j, alloc_size; 6129*26947304SEvan Yan boolean_t alloc; 6130*26947304SEvan Yan 6131*26947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 6132*26947304SEvan Yan DDI_PROP_DONTPASS, "reg", (caddr_t)®, 6133*26947304SEvan Yan ®_len) != DDI_PROP_SUCCESS) { 6134*26947304SEvan Yan DEBUG0("Failed to read reg property\n"); 6135*26947304SEvan Yan return (PCICFG_FAILURE); 6136*26947304SEvan Yan } 6137*26947304SEvan Yan rcount = reg_len / sizeof (pci_regspec_t); 6138*26947304SEvan Yan 6139*26947304SEvan Yan DEBUG2("pcicfg_alloc_new_resources() reg size=%x entries=%x\n", 6140*26947304SEvan Yan reg_len, rcount); 6141*26947304SEvan Yan 6142*26947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 6143*26947304SEvan Yan DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned, 6144*26947304SEvan Yan &assigned_len) != DDI_PROP_SUCCESS) { 6145*26947304SEvan Yan acount = 0; 6146*26947304SEvan Yan } else { 6147*26947304SEvan Yan acount = assigned_len / sizeof (pci_regspec_t); 6148*26947304SEvan Yan } 6149*26947304SEvan Yan 6150*26947304SEvan Yan DEBUG1("assigned-addresses property len=%x\n", acount); 6151*26947304SEvan Yan 6152*26947304SEvan Yan /* 6153*26947304SEvan Yan * For each address described by reg, search for it in the 6154*26947304SEvan Yan * assigned-addresses property. If it does not exist, allocate 6155*26947304SEvan Yan * resources for it. If it does exist, check the size in both. 6156*26947304SEvan Yan * The size needs to be bigger of the two. 6157*26947304SEvan Yan */ 6158*26947304SEvan Yan for (i = 1; i < rcount; i++) { 6159*26947304SEvan Yan alloc = B_TRUE; 6160*26947304SEvan Yan alloc_size = reg[i].pci_size_low; 6161*26947304SEvan Yan for (j = 0; j < acount; j++) { 6162*26947304SEvan Yan if (assigned[j].pci_phys_hi == reg[i].pci_phys_hi) { 6163*26947304SEvan Yan /* 6164*26947304SEvan Yan * There is an exact match. Check size. 6165*26947304SEvan Yan */ 6166*26947304SEvan Yan DEBUG1("pcicfg_alloc_new_resources " 6167*26947304SEvan Yan "- %x - MATCH\n", 6168*26947304SEvan Yan reg[i].pci_phys_hi); 6169*26947304SEvan Yan 6170*26947304SEvan Yan if (reg[i].pci_size_low > 6171*26947304SEvan Yan assigned[j].pci_size_low) { 6172*26947304SEvan Yan /* 6173*26947304SEvan Yan * Fcode wants more. 6174*26947304SEvan Yan */ 6175*26947304SEvan Yan DEBUG3("pcicfg_alloc_new_resources" 6176*26947304SEvan Yan " - %x - RESIZE" 6177*26947304SEvan Yan " assigned 0x%x reg 0x%x\n", 6178*26947304SEvan Yan assigned[j].pci_phys_hi, 6179*26947304SEvan Yan assigned[j].pci_size_low, 6180*26947304SEvan Yan reg[i].pci_size_low); 6181*26947304SEvan Yan 6182*26947304SEvan Yan /* 6183*26947304SEvan Yan * Free the old resource. 6184*26947304SEvan Yan */ 6185*26947304SEvan Yan (void) pcicfg_free_resource(dip, 6186*26947304SEvan Yan assigned[j], 0); 6187*26947304SEvan Yan } else { 6188*26947304SEvan Yan DEBUG3("pcicfg_alloc_new_resources" 6189*26947304SEvan Yan " - %x - ENOUGH" 6190*26947304SEvan Yan " assigned 0x%x reg 0x%x\n", 6191*26947304SEvan Yan assigned[j].pci_phys_hi, 6192*26947304SEvan Yan assigned[j].pci_size_low, 6193*26947304SEvan Yan reg[i].pci_size_low); 6194*26947304SEvan Yan 6195*26947304SEvan Yan alloc = B_FALSE; 6196*26947304SEvan Yan } 6197*26947304SEvan Yan break; 6198*26947304SEvan Yan } 6199*26947304SEvan Yan /* 6200*26947304SEvan Yan * Fcode may have set one or more of the 6201*26947304SEvan Yan * NPT bits in phys.hi. 6202*26947304SEvan Yan */ 6203*26947304SEvan Yan if (PCI_REG_BDFR_G(assigned[j].pci_phys_hi) == 6204*26947304SEvan Yan PCI_REG_BDFR_G(reg[i].pci_phys_hi)) { 6205*26947304SEvan Yan 6206*26947304SEvan Yan DEBUG2("pcicfg_alloc_new_resources " 6207*26947304SEvan Yan "- PARTIAL MATCH assigned 0x%x " 6208*26947304SEvan Yan "reg 0x%x\n", assigned[j].pci_phys_hi, 6209*26947304SEvan Yan reg[i].pci_phys_hi); 6210*26947304SEvan Yan /* 6211*26947304SEvan Yan * Changing the SS bits is an error 6212*26947304SEvan Yan */ 6213*26947304SEvan Yan if (PCI_REG_ADDR_G( 6214*26947304SEvan Yan assigned[j].pci_phys_hi) != 6215*26947304SEvan Yan PCI_REG_ADDR_G(reg[i].pci_phys_hi)) { 6216*26947304SEvan Yan 6217*26947304SEvan Yan DEBUG2("Fcode changing" 6218*26947304SEvan Yan " SS bits of - 0x%x -" 6219*26947304SEvan Yan " on %s\n", reg[i].pci_phys_hi, 6220*26947304SEvan Yan DEVI(dip)->devi_name); 6221*26947304SEvan Yan 6222*26947304SEvan Yan } 6223*26947304SEvan Yan 6224*26947304SEvan Yan 6225*26947304SEvan Yan /* 6226*26947304SEvan Yan * We are going to allocate new resource. 6227*26947304SEvan Yan * Free the old resource. Again, adjust 6228*26947304SEvan Yan * the size to be safe. 6229*26947304SEvan Yan */ 6230*26947304SEvan Yan (void) pcicfg_free_resource(dip, 6231*26947304SEvan Yan assigned[j], 0); 6232*26947304SEvan Yan 6233*26947304SEvan Yan alloc_size = MAX(reg[i].pci_size_low, 6234*26947304SEvan Yan assigned[j].pci_size_low); 6235*26947304SEvan Yan 6236*26947304SEvan Yan break; 6237*26947304SEvan Yan } 6238*26947304SEvan Yan } 6239*26947304SEvan Yan /* 6240*26947304SEvan Yan * We are allocating resources for one of three reasons - 6241*26947304SEvan Yan * - Fcode wants a larger address space 6242*26947304SEvan Yan * - Fcode has set changed/set n, p, t bits. 6243*26947304SEvan Yan * - It is a new "reg", it should be only ROM bar, but 6244*26947304SEvan Yan * we don't do the checking. 6245*26947304SEvan Yan */ 6246*26947304SEvan Yan if (alloc == B_TRUE) { 6247*26947304SEvan Yan DEBUG1("pcicfg_alloc_new_resources : creating 0x%x\n", 6248*26947304SEvan Yan reg[i].pci_phys_hi); 6249*26947304SEvan Yan 6250*26947304SEvan Yan reg[i].pci_size_low = alloc_size; 6251*26947304SEvan Yan if (pcicfg_alloc_resource(dip, reg[i])) { 6252*26947304SEvan Yan /* 6253*26947304SEvan Yan * Dont forget to free mem from 6254*26947304SEvan Yan * ddi_getlongprop 6255*26947304SEvan Yan */ 6256*26947304SEvan Yan if (acount != 0) 6257*26947304SEvan Yan kmem_free((caddr_t)assigned, 6258*26947304SEvan Yan assigned_len); 6259*26947304SEvan Yan kmem_free((caddr_t)reg, reg_len); 6260*26947304SEvan Yan return (PCICFG_FAILURE); 6261*26947304SEvan Yan } 6262*26947304SEvan Yan } 6263*26947304SEvan Yan } 6264*26947304SEvan Yan 6265*26947304SEvan Yan /* 6266*26947304SEvan Yan * Don't forget to free up memory from ddi_getlongprop 6267*26947304SEvan Yan */ 6268*26947304SEvan Yan if (acount != 0) 6269*26947304SEvan Yan kmem_free((caddr_t)assigned, assigned_len); 6270*26947304SEvan Yan kmem_free((caddr_t)reg, reg_len); 6271*26947304SEvan Yan 6272*26947304SEvan Yan return (PCICFG_SUCCESS); 6273*26947304SEvan Yan } 6274*26947304SEvan Yan 6275*26947304SEvan Yan static int 6276*26947304SEvan Yan pcicfg_alloc_resource(dev_info_t *dip, pci_regspec_t phys_spec) 6277*26947304SEvan Yan { 6278*26947304SEvan Yan uint64_t answer; 6279*26947304SEvan Yan uint64_t alen; 6280*26947304SEvan Yan int offset; 6281*26947304SEvan Yan pci_regspec_t config; 6282*26947304SEvan Yan caddr_t virt, v; 6283*26947304SEvan Yan ddi_device_acc_attr_t acc; 6284*26947304SEvan Yan ddi_acc_handle_t h; 6285*26947304SEvan Yan ndi_ra_request_t request; 6286*26947304SEvan Yan pci_regspec_t *assigned; 6287*26947304SEvan Yan int assigned_len, entries, i; 6288*26947304SEvan Yan 6289*26947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 6290*26947304SEvan Yan DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned, 6291*26947304SEvan Yan &assigned_len) == DDI_PROP_SUCCESS) { 6292*26947304SEvan Yan DEBUG0("pcicfg_alloc_resource - " 6293*26947304SEvan Yan "searching assigned-addresses\n"); 6294*26947304SEvan Yan 6295*26947304SEvan Yan entries = assigned_len / (sizeof (pci_regspec_t)); 6296*26947304SEvan Yan 6297*26947304SEvan Yan /* 6298*26947304SEvan Yan * Walk through the assigned-addresses entries. If there is 6299*26947304SEvan Yan * a match, there is no need to allocate the resource. 6300*26947304SEvan Yan */ 6301*26947304SEvan Yan for (i = 0; i < entries; i++) { 6302*26947304SEvan Yan if (assigned[i].pci_phys_hi == phys_spec.pci_phys_hi) { 6303*26947304SEvan Yan DEBUG1("pcicfg_alloc_resource - MATCH %x\n", 6304*26947304SEvan Yan assigned[i].pci_phys_hi); 6305*26947304SEvan Yan kmem_free(assigned, assigned_len); 6306*26947304SEvan Yan return (0); 6307*26947304SEvan Yan } 6308*26947304SEvan Yan } 6309*26947304SEvan Yan kmem_free(assigned, assigned_len); 6310*26947304SEvan Yan } 6311*26947304SEvan Yan 6312*26947304SEvan Yan bzero((caddr_t)&request, sizeof (ndi_ra_request_t)); 6313*26947304SEvan Yan 6314*26947304SEvan Yan config.pci_phys_hi = PCI_CONF_ADDR_MASK & phys_spec.pci_phys_hi; 6315*26947304SEvan Yan config.pci_phys_hi &= ~PCI_REG_REG_M; 6316*26947304SEvan Yan config.pci_phys_mid = config.pci_phys_low = 0; 6317*26947304SEvan Yan config.pci_size_hi = config.pci_size_low = 0; 6318*26947304SEvan Yan 6319*26947304SEvan Yan /* 6320*26947304SEvan Yan * Map in configuration space (temporarily) 6321*26947304SEvan Yan */ 6322*26947304SEvan Yan acc.devacc_attr_version = DDI_DEVICE_ATTR_V0; 6323*26947304SEvan Yan acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 6324*26947304SEvan Yan acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 6325*26947304SEvan Yan 6326*26947304SEvan Yan if (pcicfg_map_phys(dip, &config, &virt, &acc, &h)) { 6327*26947304SEvan Yan DEBUG0("Can not map in config space\n"); 6328*26947304SEvan Yan return (1); 6329*26947304SEvan Yan } 6330*26947304SEvan Yan 6331*26947304SEvan Yan request.ra_flags |= NDI_RA_ALIGN_SIZE; 6332*26947304SEvan Yan request.ra_boundbase = 0; 6333*26947304SEvan Yan request.ra_boundlen = PCICFG_4GIG_LIMIT; 6334*26947304SEvan Yan /* 6335*26947304SEvan Yan * Use size stored in phys_spec parameter. 6336*26947304SEvan Yan */ 6337*26947304SEvan Yan request.ra_len = phys_spec.pci_size_low; 6338*26947304SEvan Yan 6339*26947304SEvan Yan offset = PCI_REG_REG_G(phys_spec.pci_phys_hi); 6340*26947304SEvan Yan 6341*26947304SEvan Yan v = virt + offset; 6342*26947304SEvan Yan 6343*26947304SEvan Yan if (PCI_REG_REG_G(phys_spec.pci_phys_hi) == PCI_CONF_ROM) { 6344*26947304SEvan Yan 6345*26947304SEvan Yan request.ra_flags ^= NDI_RA_ALLOC_BOUNDED; 6346*26947304SEvan Yan 6347*26947304SEvan Yan /* allocate memory space from the allocator */ 6348*26947304SEvan Yan 6349*26947304SEvan Yan if (ndi_ra_alloc(ddi_get_parent(dip), 6350*26947304SEvan Yan &request, &answer, &alen, 6351*26947304SEvan Yan NDI_RA_TYPE_MEM, NDI_RA_PASS) 6352*26947304SEvan Yan != NDI_SUCCESS) { 6353*26947304SEvan Yan DEBUG0("(ROM)Failed to allocate 32b mem"); 6354*26947304SEvan Yan pcicfg_unmap_phys(&h, &config); 6355*26947304SEvan Yan return (1); 6356*26947304SEvan Yan } 6357*26947304SEvan Yan DEBUG3("ROM addr = [0x%x.%x] len [0x%x]\n", 6358*26947304SEvan Yan PCICFG_HIADDR(answer), 6359*26947304SEvan Yan PCICFG_LOADDR(answer), 6360*26947304SEvan Yan alen); 6361*26947304SEvan Yan 6362*26947304SEvan Yan /* program the low word */ 6363*26947304SEvan Yan 6364*26947304SEvan Yan ddi_put32(h, (uint32_t *)v, (uint32_t)PCICFG_LOADDR(answer)); 6365*26947304SEvan Yan 6366*26947304SEvan Yan phys_spec.pci_phys_low = PCICFG_LOADDR(answer); 6367*26947304SEvan Yan phys_spec.pci_phys_mid = PCICFG_HIADDR(answer); 6368*26947304SEvan Yan } else { 6369*26947304SEvan Yan 6370*26947304SEvan Yan switch (PCI_REG_ADDR_G(phys_spec.pci_phys_hi)) { 6371*26947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_MEM64): 6372*26947304SEvan Yan request.ra_flags ^= NDI_RA_ALLOC_BOUNDED; 6373*26947304SEvan Yan /* allocate memory space from the allocator */ 6374*26947304SEvan Yan if (ndi_ra_alloc(ddi_get_parent(dip), 6375*26947304SEvan Yan &request, &answer, &alen, 6376*26947304SEvan Yan NDI_RA_TYPE_MEM, NDI_RA_PASS) 6377*26947304SEvan Yan != NDI_SUCCESS) { 6378*26947304SEvan Yan DEBUG0("Failed to allocate 64b mem\n"); 6379*26947304SEvan Yan pcicfg_unmap_phys(&h, &config); 6380*26947304SEvan Yan return (1); 6381*26947304SEvan Yan } 6382*26947304SEvan Yan DEBUG3("64 addr = [0x%x.%x] len [0x%x]\n", 6383*26947304SEvan Yan PCICFG_HIADDR(answer), 6384*26947304SEvan Yan PCICFG_LOADDR(answer), 6385*26947304SEvan Yan alen); 6386*26947304SEvan Yan 6387*26947304SEvan Yan /* program the low word */ 6388*26947304SEvan Yan 6389*26947304SEvan Yan ddi_put32(h, (uint32_t *)v, 6390*26947304SEvan Yan (uint32_t)PCICFG_LOADDR(answer)); 6391*26947304SEvan Yan 6392*26947304SEvan Yan /* program the high word with value zero */ 6393*26947304SEvan Yan v += 4; 6394*26947304SEvan Yan ddi_put32(h, (uint32_t *)v, 6395*26947304SEvan Yan (uint32_t)PCICFG_HIADDR(answer)); 6396*26947304SEvan Yan 6397*26947304SEvan Yan phys_spec.pci_phys_low = PCICFG_LOADDR(answer); 6398*26947304SEvan Yan phys_spec.pci_phys_mid = PCICFG_HIADDR(answer); 6399*26947304SEvan Yan /* 6400*26947304SEvan Yan * currently support 32b address space 6401*26947304SEvan Yan * assignments only. 6402*26947304SEvan Yan */ 6403*26947304SEvan Yan phys_spec.pci_phys_hi ^= PCI_ADDR_MEM64 ^ 6404*26947304SEvan Yan PCI_ADDR_MEM32; 6405*26947304SEvan Yan 6406*26947304SEvan Yan break; 6407*26947304SEvan Yan 6408*26947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_MEM32): 6409*26947304SEvan Yan request.ra_flags |= NDI_RA_ALLOC_BOUNDED; 6410*26947304SEvan Yan /* allocate memory space from the allocator */ 6411*26947304SEvan Yan if (ndi_ra_alloc(ddi_get_parent(dip), 6412*26947304SEvan Yan &request, &answer, &alen, 6413*26947304SEvan Yan NDI_RA_TYPE_MEM, NDI_RA_PASS) 6414*26947304SEvan Yan != NDI_SUCCESS) { 6415*26947304SEvan Yan DEBUG0("Failed to allocate 32b mem\n"); 6416*26947304SEvan Yan pcicfg_unmap_phys(&h, &config); 6417*26947304SEvan Yan return (1); 6418*26947304SEvan Yan } 6419*26947304SEvan Yan 6420*26947304SEvan Yan DEBUG3("32 addr = [0x%x.%x] len [0x%x]\n", 6421*26947304SEvan Yan PCICFG_HIADDR(answer), 6422*26947304SEvan Yan PCICFG_LOADDR(answer), 6423*26947304SEvan Yan alen); 6424*26947304SEvan Yan 6425*26947304SEvan Yan /* program the low word */ 6426*26947304SEvan Yan 6427*26947304SEvan Yan ddi_put32(h, (uint32_t *)v, 6428*26947304SEvan Yan (uint32_t)PCICFG_LOADDR(answer)); 6429*26947304SEvan Yan 6430*26947304SEvan Yan phys_spec.pci_phys_low = PCICFG_LOADDR(answer); 6431*26947304SEvan Yan 6432*26947304SEvan Yan break; 6433*26947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_IO): 6434*26947304SEvan Yan /* allocate I/O space from the allocator */ 6435*26947304SEvan Yan request.ra_flags |= NDI_RA_ALLOC_BOUNDED; 6436*26947304SEvan Yan if (ndi_ra_alloc(ddi_get_parent(dip), 6437*26947304SEvan Yan &request, &answer, &alen, 6438*26947304SEvan Yan NDI_RA_TYPE_IO, NDI_RA_PASS) 6439*26947304SEvan Yan != NDI_SUCCESS) { 6440*26947304SEvan Yan DEBUG0("Failed to allocate I/O\n"); 6441*26947304SEvan Yan pcicfg_unmap_phys(&h, &config); 6442*26947304SEvan Yan return (1); 6443*26947304SEvan Yan } 6444*26947304SEvan Yan DEBUG3("I/O addr = [0x%x.%x] len [0x%x]\n", 6445*26947304SEvan Yan PCICFG_HIADDR(answer), 6446*26947304SEvan Yan PCICFG_LOADDR(answer), 6447*26947304SEvan Yan alen); 6448*26947304SEvan Yan 6449*26947304SEvan Yan ddi_put32(h, (uint32_t *)v, 6450*26947304SEvan Yan (uint32_t)PCICFG_LOADDR(answer)); 6451*26947304SEvan Yan 6452*26947304SEvan Yan phys_spec.pci_phys_low = PCICFG_LOADDR(answer); 6453*26947304SEvan Yan 6454*26947304SEvan Yan break; 6455*26947304SEvan Yan default: 6456*26947304SEvan Yan DEBUG0("Unknown register type\n"); 6457*26947304SEvan Yan pcicfg_unmap_phys(&h, &config); 6458*26947304SEvan Yan return (1); 6459*26947304SEvan Yan } /* switch */ 6460*26947304SEvan Yan } 6461*26947304SEvan Yan 6462*26947304SEvan Yan /* 6463*26947304SEvan Yan * Now that memory locations are assigned, 6464*26947304SEvan Yan * update the assigned address property. 6465*26947304SEvan Yan */ 6466*26947304SEvan Yan 6467*26947304SEvan Yan DEBUG1("updating assigned-addresss for %x\n", phys_spec.pci_phys_hi); 6468*26947304SEvan Yan 6469*26947304SEvan Yan if (pcicfg_update_assigned_prop(dip, &phys_spec)) { 6470*26947304SEvan Yan pcicfg_unmap_phys(&h, &config); 6471*26947304SEvan Yan return (1); 6472*26947304SEvan Yan } 6473*26947304SEvan Yan 6474*26947304SEvan Yan pcicfg_unmap_phys(&h, &config); 6475*26947304SEvan Yan 6476*26947304SEvan Yan return (0); 6477*26947304SEvan Yan } 6478*26947304SEvan Yan 6479*26947304SEvan Yan static int 6480*26947304SEvan Yan pcicfg_free_resource(dev_info_t *dip, pci_regspec_t phys_spec, 6481*26947304SEvan Yan pcicfg_flags_t flags) 6482*26947304SEvan Yan { 6483*26947304SEvan Yan int offset; 6484*26947304SEvan Yan pci_regspec_t config; 6485*26947304SEvan Yan caddr_t virt, v; 6486*26947304SEvan Yan ddi_device_acc_attr_t acc; 6487*26947304SEvan Yan ddi_acc_handle_t h; 6488*26947304SEvan Yan ndi_ra_request_t request; 6489*26947304SEvan Yan int l; 6490*26947304SEvan Yan 6491*26947304SEvan Yan bzero((caddr_t)&request, sizeof (ndi_ra_request_t)); 6492*26947304SEvan Yan 6493*26947304SEvan Yan config.pci_phys_hi = PCI_CONF_ADDR_MASK & phys_spec.pci_phys_hi; 6494*26947304SEvan Yan config.pci_phys_hi &= ~PCI_REG_REG_M; 6495*26947304SEvan Yan config.pci_phys_mid = config.pci_phys_low = 0; 6496*26947304SEvan Yan config.pci_size_hi = config.pci_size_low = 0; 6497*26947304SEvan Yan 6498*26947304SEvan Yan /* 6499*26947304SEvan Yan * Map in configuration space (temporarily) 6500*26947304SEvan Yan */ 6501*26947304SEvan Yan acc.devacc_attr_version = DDI_DEVICE_ATTR_V0; 6502*26947304SEvan Yan acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 6503*26947304SEvan Yan acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 6504*26947304SEvan Yan 6505*26947304SEvan Yan if (pcicfg_map_phys(dip, &config, &virt, &acc, &h)) { 6506*26947304SEvan Yan DEBUG0("Can not map in config space\n"); 6507*26947304SEvan Yan return (1); 6508*26947304SEvan Yan } 6509*26947304SEvan Yan 6510*26947304SEvan Yan offset = PCI_REG_REG_G(phys_spec.pci_phys_hi); 6511*26947304SEvan Yan 6512*26947304SEvan Yan v = virt + offset; 6513*26947304SEvan Yan 6514*26947304SEvan Yan /* 6515*26947304SEvan Yan * Use size stored in phys_spec parameter. 6516*26947304SEvan Yan */ 6517*26947304SEvan Yan l = phys_spec.pci_size_low; 6518*26947304SEvan Yan 6519*26947304SEvan Yan if (PCI_REG_REG_G(phys_spec.pci_phys_hi) == PCI_CONF_ROM) { 6520*26947304SEvan Yan 6521*26947304SEvan Yan /* free memory back to the allocator */ 6522*26947304SEvan Yan if (ndi_ra_free(ddi_get_parent(dip), phys_spec.pci_phys_low, 6523*26947304SEvan Yan l, NDI_RA_TYPE_MEM, NDI_RA_PASS) != NDI_SUCCESS) { 6524*26947304SEvan Yan DEBUG0("(ROM)Can not free 32b mem"); 6525*26947304SEvan Yan pcicfg_unmap_phys(&h, &config); 6526*26947304SEvan Yan return (1); 6527*26947304SEvan Yan } 6528*26947304SEvan Yan 6529*26947304SEvan Yan /* Unmap the BAR by writing a zero */ 6530*26947304SEvan Yan 6531*26947304SEvan Yan if ((flags & PCICFG_FLAG_READ_ONLY) == 0) 6532*26947304SEvan Yan ddi_put32(h, (uint32_t *)v, (uint32_t)0); 6533*26947304SEvan Yan } else { 6534*26947304SEvan Yan 6535*26947304SEvan Yan switch (PCI_REG_ADDR_G(phys_spec.pci_phys_hi)) { 6536*26947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_MEM64): 6537*26947304SEvan Yan /* free memory back to the allocator */ 6538*26947304SEvan Yan if (ndi_ra_free(ddi_get_parent(dip), 6539*26947304SEvan Yan PCICFG_LADDR(phys_spec.pci_phys_low, 6540*26947304SEvan Yan phys_spec.pci_phys_mid), 6541*26947304SEvan Yan l, NDI_RA_TYPE_MEM, 6542*26947304SEvan Yan NDI_RA_PASS) != NDI_SUCCESS) { 6543*26947304SEvan Yan DEBUG0("Can not free 64b mem"); 6544*26947304SEvan Yan pcicfg_unmap_phys(&h, &config); 6545*26947304SEvan Yan return (1); 6546*26947304SEvan Yan } 6547*26947304SEvan Yan 6548*26947304SEvan Yan break; 6549*26947304SEvan Yan 6550*26947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_MEM32): 6551*26947304SEvan Yan /* free memory back to the allocator */ 6552*26947304SEvan Yan if (ndi_ra_free(ddi_get_parent(dip), 6553*26947304SEvan Yan phys_spec.pci_phys_low, 6554*26947304SEvan Yan l, NDI_RA_TYPE_MEM, 6555*26947304SEvan Yan NDI_RA_PASS) != NDI_SUCCESS) { 6556*26947304SEvan Yan DEBUG0("Can not free 32b mem"); 6557*26947304SEvan Yan pcicfg_unmap_phys(&h, &config); 6558*26947304SEvan Yan return (1); 6559*26947304SEvan Yan } 6560*26947304SEvan Yan 6561*26947304SEvan Yan break; 6562*26947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_IO): 6563*26947304SEvan Yan /* free I/O space back to the allocator */ 6564*26947304SEvan Yan if (ndi_ra_free(ddi_get_parent(dip), 6565*26947304SEvan Yan phys_spec.pci_phys_low, 6566*26947304SEvan Yan l, NDI_RA_TYPE_IO, 6567*26947304SEvan Yan NDI_RA_PASS) != NDI_SUCCESS) { 6568*26947304SEvan Yan DEBUG0("Can not free I/O space"); 6569*26947304SEvan Yan pcicfg_unmap_phys(&h, &config); 6570*26947304SEvan Yan return (1); 6571*26947304SEvan Yan } 6572*26947304SEvan Yan 6573*26947304SEvan Yan break; 6574*26947304SEvan Yan default: 6575*26947304SEvan Yan DEBUG0("Unknown register type\n"); 6576*26947304SEvan Yan pcicfg_unmap_phys(&h, &config); 6577*26947304SEvan Yan return (1); 6578*26947304SEvan Yan } /* switch */ 6579*26947304SEvan Yan } 6580*26947304SEvan Yan 6581*26947304SEvan Yan /* 6582*26947304SEvan Yan * Now that memory locations are assigned, 6583*26947304SEvan Yan * update the assigned address property. 6584*26947304SEvan Yan */ 6585*26947304SEvan Yan 6586*26947304SEvan Yan DEBUG1("updating assigned-addresss for %x\n", phys_spec.pci_phys_hi); 6587*26947304SEvan Yan 6588*26947304SEvan Yan if (pcicfg_remove_assigned_prop(dip, &phys_spec)) { 6589*26947304SEvan Yan pcicfg_unmap_phys(&h, &config); 6590*26947304SEvan Yan return (1); 6591*26947304SEvan Yan } 6592*26947304SEvan Yan 6593*26947304SEvan Yan pcicfg_unmap_phys(&h, &config); 6594*26947304SEvan Yan 6595*26947304SEvan Yan return (0); 6596*26947304SEvan Yan } 6597*26947304SEvan Yan 6598*26947304SEvan Yan static int 6599*26947304SEvan Yan pcicfg_remove_assigned_prop(dev_info_t *dip, pci_regspec_t *oldone) 6600*26947304SEvan Yan { 6601*26947304SEvan Yan int alen, num_entries, i; 6602*26947304SEvan Yan pci_regspec_t *assigned, *assigned_copy; 6603*26947304SEvan Yan uint_t status; 6604*26947304SEvan Yan 6605*26947304SEvan Yan status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 6606*26947304SEvan Yan "assigned-addresses", (caddr_t)&assigned, &alen); 6607*26947304SEvan Yan switch (status) { 6608*26947304SEvan Yan case DDI_PROP_SUCCESS: 6609*26947304SEvan Yan break; 6610*26947304SEvan Yan case DDI_PROP_NO_MEMORY: 6611*26947304SEvan Yan DEBUG0("no memory for assigned-addresses property\n"); 6612*26947304SEvan Yan return (1); 6613*26947304SEvan Yan default: 6614*26947304SEvan Yan DEBUG0("assigned-addresses property does not exist\n"); 6615*26947304SEvan Yan return (0); 6616*26947304SEvan Yan } 6617*26947304SEvan Yan 6618*26947304SEvan Yan /* 6619*26947304SEvan Yan * Make a copy of old assigned-addresses property. 6620*26947304SEvan Yan */ 6621*26947304SEvan Yan assigned_copy = kmem_alloc(alen, KM_SLEEP); 6622*26947304SEvan Yan bcopy(assigned, assigned_copy, alen); 6623*26947304SEvan Yan 6624*26947304SEvan Yan status = ndi_prop_remove(DDI_DEV_T_NONE, dip, "assigned-addresses"); 6625*26947304SEvan Yan 6626*26947304SEvan Yan if (status != DDI_PROP_SUCCESS) { 6627*26947304SEvan Yan /* 6628*26947304SEvan Yan * If "assigned-addresses" is retrieved from PROM, the 6629*26947304SEvan Yan * ndi_prop_remove() will fail. 6630*26947304SEvan Yan */ 6631*26947304SEvan Yan DEBUG1("pcicfg_remove_assigned_prop: 0x%x not removed\n", 6632*26947304SEvan Yan oldone->pci_phys_hi); 6633*26947304SEvan Yan 6634*26947304SEvan Yan /* 6635*26947304SEvan Yan * Free up allocated memory 6636*26947304SEvan Yan */ 6637*26947304SEvan Yan kmem_free(assigned_copy, alen); 6638*26947304SEvan Yan kmem_free((caddr_t)assigned, alen); 6639*26947304SEvan Yan 6640*26947304SEvan Yan return (0); 6641*26947304SEvan Yan } 6642*26947304SEvan Yan 6643*26947304SEvan Yan num_entries = alen / sizeof (pci_regspec_t); 6644*26947304SEvan Yan 6645*26947304SEvan Yan /* 6646*26947304SEvan Yan * Rebuild the assigned-addresses property. 6647*26947304SEvan Yan */ 6648*26947304SEvan Yan for (i = 0; i < num_entries; i++) { 6649*26947304SEvan Yan if (assigned_copy[i].pci_phys_hi != oldone->pci_phys_hi) { 6650*26947304SEvan Yan (void) pcicfg_update_assigned_prop(dip, 6651*26947304SEvan Yan &assigned_copy[i]); 6652*26947304SEvan Yan } 6653*26947304SEvan Yan } 6654*26947304SEvan Yan 6655*26947304SEvan Yan /* 6656*26947304SEvan Yan * Free the copy of the original assigned-addresses. 6657*26947304SEvan Yan */ 6658*26947304SEvan Yan kmem_free(assigned_copy, alen); 6659*26947304SEvan Yan 6660*26947304SEvan Yan /* 6661*26947304SEvan Yan * Don't forget to free up memory from ddi_getlongprop 6662*26947304SEvan Yan */ 6663*26947304SEvan Yan kmem_free((caddr_t)assigned, alen); 6664*26947304SEvan Yan 6665*26947304SEvan Yan return (0); 6666*26947304SEvan Yan } 6667*26947304SEvan Yan 6668*26947304SEvan Yan static int 6669*26947304SEvan Yan pcicfg_map_phys(dev_info_t *dip, pci_regspec_t *phys_spec, 6670*26947304SEvan Yan caddr_t *addrp, ddi_device_acc_attr_t *accattrp, 6671*26947304SEvan Yan ddi_acc_handle_t *handlep) 6672*26947304SEvan Yan { 6673*26947304SEvan Yan ddi_map_req_t mr; 6674*26947304SEvan Yan ddi_acc_hdl_t *hp; 6675*26947304SEvan Yan int result; 6676*26947304SEvan Yan 6677*26947304SEvan Yan *handlep = impl_acc_hdl_alloc(KM_SLEEP, NULL); 6678*26947304SEvan Yan hp = impl_acc_hdl_get(*handlep); 6679*26947304SEvan Yan hp->ah_vers = VERS_ACCHDL; 6680*26947304SEvan Yan hp->ah_dip = dip; 6681*26947304SEvan Yan hp->ah_rnumber = 0; 6682*26947304SEvan Yan hp->ah_offset = 0; 6683*26947304SEvan Yan hp->ah_len = 0; 6684*26947304SEvan Yan hp->ah_acc = *accattrp; 6685*26947304SEvan Yan 6686*26947304SEvan Yan mr.map_op = DDI_MO_MAP_LOCKED; 6687*26947304SEvan Yan mr.map_type = DDI_MT_REGSPEC; 6688*26947304SEvan Yan mr.map_obj.rp = (struct regspec *)phys_spec; 6689*26947304SEvan Yan mr.map_prot = PROT_READ | PROT_WRITE; 6690*26947304SEvan Yan mr.map_flags = DDI_MF_KERNEL_MAPPING; 6691*26947304SEvan Yan mr.map_handlep = hp; 6692*26947304SEvan Yan mr.map_vers = DDI_MAP_VERSION; 6693*26947304SEvan Yan 6694*26947304SEvan Yan result = ddi_map(dip, &mr, 0, 0, addrp); 6695*26947304SEvan Yan 6696*26947304SEvan Yan if (result != DDI_SUCCESS) { 6697*26947304SEvan Yan impl_acc_hdl_free(*handlep); 6698*26947304SEvan Yan *handlep = (ddi_acc_handle_t)NULL; 6699*26947304SEvan Yan } else { 6700*26947304SEvan Yan hp->ah_addr = *addrp; 6701*26947304SEvan Yan } 6702*26947304SEvan Yan 6703*26947304SEvan Yan return (result); 6704*26947304SEvan Yan } 6705*26947304SEvan Yan 6706*26947304SEvan Yan void 6707*26947304SEvan Yan pcicfg_unmap_phys(ddi_acc_handle_t *handlep, pci_regspec_t *ph) 6708*26947304SEvan Yan { 6709*26947304SEvan Yan ddi_map_req_t mr; 6710*26947304SEvan Yan ddi_acc_hdl_t *hp; 6711*26947304SEvan Yan 6712*26947304SEvan Yan hp = impl_acc_hdl_get(*handlep); 6713*26947304SEvan Yan ASSERT(hp); 6714*26947304SEvan Yan 6715*26947304SEvan Yan mr.map_op = DDI_MO_UNMAP; 6716*26947304SEvan Yan mr.map_type = DDI_MT_REGSPEC; 6717*26947304SEvan Yan mr.map_obj.rp = (struct regspec *)ph; 6718*26947304SEvan Yan mr.map_prot = PROT_READ | PROT_WRITE; 6719*26947304SEvan Yan mr.map_flags = DDI_MF_KERNEL_MAPPING; 6720*26947304SEvan Yan mr.map_handlep = hp; 6721*26947304SEvan Yan mr.map_vers = DDI_MAP_VERSION; 6722*26947304SEvan Yan 6723*26947304SEvan Yan (void) ddi_map(hp->ah_dip, &mr, hp->ah_offset, 6724*26947304SEvan Yan hp->ah_len, &hp->ah_addr); 6725*26947304SEvan Yan 6726*26947304SEvan Yan impl_acc_hdl_free(*handlep); 6727*26947304SEvan Yan *handlep = (ddi_acc_handle_t)NULL; 6728*26947304SEvan Yan } 6729*26947304SEvan Yan 6730*26947304SEvan Yan static int 6731*26947304SEvan Yan pcicfg_ari_configure(dev_info_t *dip) 6732*26947304SEvan Yan { 6733*26947304SEvan Yan if (pcie_ari_supported(dip) == PCIE_ARI_FORW_NOT_SUPPORTED) 6734*26947304SEvan Yan return (DDI_FAILURE); 6735*26947304SEvan Yan 6736*26947304SEvan Yan /* 6737*26947304SEvan Yan * Until we have resource balancing, dynamically configure 6738*26947304SEvan Yan * ARI functions without firmware assistamce. 6739*26947304SEvan Yan */ 6740*26947304SEvan Yan return (DDI_FAILURE); 6741*26947304SEvan Yan } 6742*26947304SEvan Yan 6743*26947304SEvan Yan #ifdef DEBUG 6744*26947304SEvan Yan static void 6745*26947304SEvan Yan debug(char *fmt, uintptr_t a1, uintptr_t a2, uintptr_t a3, 6746*26947304SEvan Yan uintptr_t a4, uintptr_t a5) 6747*26947304SEvan Yan { 6748*26947304SEvan Yan if (pcicfg_debug == 1) { 6749*26947304SEvan Yan prom_printf("pcicfg: "); 6750*26947304SEvan Yan prom_printf(fmt, a1, a2, a3, a4, a5); 6751*26947304SEvan Yan } else 6752*26947304SEvan Yan if (pcicfg_debug) 6753*26947304SEvan Yan cmn_err(CE_CONT, fmt, a1, a2, a3, a4, a5); 6754*26947304SEvan Yan } 6755*26947304SEvan Yan #endif 6756