126947304SEvan Yan /* 226947304SEvan Yan * CDDL HEADER START 326947304SEvan Yan * 426947304SEvan Yan * The contents of this file are subject to the terms of the 526947304SEvan Yan * Common Development and Distribution License (the "License"). 626947304SEvan Yan * You may not use this file except in compliance with the License. 726947304SEvan Yan * 826947304SEvan Yan * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 926947304SEvan Yan * or http://www.opensolaris.org/os/licensing. 1026947304SEvan Yan * See the License for the specific language governing permissions 1126947304SEvan Yan * and limitations under the License. 1226947304SEvan Yan * 1326947304SEvan Yan * When distributing Covered Code, include this CDDL HEADER in each 1426947304SEvan Yan * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1526947304SEvan Yan * If applicable, add the following below this CDDL HEADER, with the 1626947304SEvan Yan * fields enclosed by brackets "[]" replaced with your own identifying 1726947304SEvan Yan * information: Portions Copyright [yyyy] [name of copyright owner] 1826947304SEvan Yan * 1926947304SEvan Yan * CDDL HEADER END 2026947304SEvan Yan */ 2126947304SEvan Yan /* 22*7f59ab1cSAlan Adamson, SD OSSD * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 2326947304SEvan Yan */ 2426947304SEvan Yan 2526947304SEvan Yan /* 2626947304SEvan Yan * PCI configurator (pcicfg) 2726947304SEvan Yan */ 2826947304SEvan Yan 2926947304SEvan Yan #include <sys/isa_defs.h> 3026947304SEvan Yan 3126947304SEvan Yan #include <sys/conf.h> 3226947304SEvan Yan #include <sys/kmem.h> 3326947304SEvan Yan #include <sys/debug.h> 3426947304SEvan Yan #include <sys/modctl.h> 3526947304SEvan Yan #include <sys/autoconf.h> 3626947304SEvan Yan #include <sys/hwconf.h> 3726947304SEvan Yan #include <sys/ddi_impldefs.h> 3826947304SEvan Yan #include <sys/fcode.h> 3926947304SEvan Yan #include <sys/pci.h> 4026947304SEvan Yan #include <sys/pcie.h> 4126947304SEvan Yan #include <sys/pcie_impl.h> 4226947304SEvan Yan #include <sys/ddi.h> 4326947304SEvan Yan #include <sys/sunddi.h> 4426947304SEvan Yan #include <sys/sunndi.h> 4526947304SEvan Yan #include <sys/pci_cap.h> 4626947304SEvan Yan #include <sys/hotplug/pci/pcicfg.h> 4726947304SEvan Yan #include <sys/ndi_impldefs.h> 48c0da6274SZhi-Jun Robin Fu #include <sys/pci_cfgacc.h> 4926947304SEvan Yan 5026947304SEvan Yan #define PCICFG_DEVICE_TYPE_PCI 1 5126947304SEvan Yan #define PCICFG_DEVICE_TYPE_PCIE 2 5226947304SEvan Yan 5326947304SEvan Yan #define EFCODE21554 /* changes for supporting 21554 */ 5426947304SEvan Yan 5526947304SEvan Yan static int pcicfg_alloc_resource(dev_info_t *, pci_regspec_t); 5626947304SEvan Yan static int pcicfg_free_resource(dev_info_t *, pci_regspec_t, pcicfg_flags_t); 5726947304SEvan Yan static int pcicfg_remove_assigned_prop(dev_info_t *, pci_regspec_t *); 5826947304SEvan Yan 5926947304SEvan Yan #ifdef PCICFG_INTERPRET_FCODE 6026947304SEvan Yan static int pcicfg_fcode_assign_bars(ddi_acc_handle_t, dev_info_t *, 6126947304SEvan Yan uint_t, uint_t, uint_t, int32_t, pci_regspec_t *); 6226947304SEvan Yan #endif /* PCICFG_INTERPRET_FCODE */ 6326947304SEvan Yan 6426947304SEvan Yan /* 6526947304SEvan Yan * ************************************************************************ 6626947304SEvan Yan * *** Implementation specific local data structures/definitions. *** 6726947304SEvan Yan * ************************************************************************ 6826947304SEvan Yan */ 6926947304SEvan Yan 7026947304SEvan Yan static int pcicfg_start_devno = 0; /* for Debug only */ 7126947304SEvan Yan 7226947304SEvan Yan #define PCICFG_MAX_DEVICE 32 7326947304SEvan Yan #define PCICFG_MAX_FUNCTION 8 7426947304SEvan Yan #define PCICFG_MAX_ARI_FUNCTION 256 7526947304SEvan Yan #define PCICFG_MAX_REGISTER 64 7626947304SEvan Yan #define PCICFG_MAX_BUS_DEPTH 255 7726947304SEvan Yan 7826947304SEvan Yan #define PCICFG_NODEVICE 42 7926947304SEvan Yan #define PCICFG_NOMEMORY 43 8026947304SEvan Yan #define PCICFG_NOMULTI 44 8126947304SEvan Yan 8226947304SEvan Yan #define PCICFG_HIADDR(n) ((uint32_t)(((uint64_t)(n) & 0xFFFFFFFF00000000)>> 32)) 8326947304SEvan Yan #define PCICFG_LOADDR(n) ((uint32_t)((uint64_t)(n) & 0x00000000FFFFFFFF)) 8426947304SEvan Yan #define PCICFG_LADDR(lo, hi) (((uint64_t)(hi) << 32) | (uint32_t)(lo)) 8526947304SEvan Yan 8626947304SEvan Yan #define PCICFG_HIWORD(n) ((uint16_t)(((uint32_t)(n) & 0xFFFF0000)>> 16)) 8726947304SEvan Yan #define PCICFG_LOWORD(n) ((uint16_t)((uint32_t)(n) & 0x0000FFFF)) 8826947304SEvan Yan #define PCICFG_HIBYTE(n) ((uint8_t)(((uint16_t)(n) & 0xFF00)>> 8)) 8926947304SEvan Yan #define PCICFG_LOBYTE(n) ((uint8_t)((uint16_t)(n) & 0x00FF)) 9026947304SEvan Yan 9126947304SEvan Yan #define PCICFG_ROUND_UP(addr, gran) ((uintptr_t)((gran+addr-1)&(~(gran-1)))) 9226947304SEvan Yan #define PCICFG_ROUND_DOWN(addr, gran) ((uintptr_t)((addr) & ~(gran-1))) 9326947304SEvan Yan 9426947304SEvan Yan #define PCICFG_MEMGRAN 0x100000 9526947304SEvan Yan #define PCICFG_IOGRAN 0x1000 9626947304SEvan Yan #define PCICFG_4GIG_LIMIT 0xFFFFFFFFUL 9726947304SEvan Yan 9826947304SEvan Yan #define PCICFG_MEM_MULT 4 9926947304SEvan Yan #define PCICFG_IO_MULT 4 10026947304SEvan Yan #define PCICFG_RANGE_LEN 2 /* Number of range entries */ 10126947304SEvan Yan 10226947304SEvan Yan static int pcicfg_slot_busnums = 8; 10326947304SEvan Yan static int pcicfg_slot_memsize = 32 * PCICFG_MEMGRAN; /* 32MB per slot */ 10426947304SEvan Yan static int pcicfg_slot_iosize = 16 * PCICFG_IOGRAN; /* 64K per slot */ 10526947304SEvan Yan static int pcicfg_chassis_per_tree = 1; 10626947304SEvan Yan static int pcicfg_sec_reset_delay = 1000000; 10726947304SEvan Yan 10826947304SEvan Yan /* 10926947304SEvan Yan * The following typedef is used to represent a 11026947304SEvan Yan * 1275 "bus-range" property of a PCI Bus node. 11126947304SEvan Yan * DAF - should be in generic include file... 11226947304SEvan Yan */ 11326947304SEvan Yan 11426947304SEvan Yan typedef struct pcicfg_bus_range { 11526947304SEvan Yan uint32_t lo; 11626947304SEvan Yan uint32_t hi; 11726947304SEvan Yan } pcicfg_bus_range_t; 11826947304SEvan Yan 11926947304SEvan Yan typedef struct pcicfg_range { 12026947304SEvan Yan 12126947304SEvan Yan uint32_t child_hi; 12226947304SEvan Yan uint32_t child_mid; 12326947304SEvan Yan uint32_t child_lo; 12426947304SEvan Yan uint32_t parent_hi; 12526947304SEvan Yan uint32_t parent_mid; 12626947304SEvan Yan uint32_t parent_lo; 12726947304SEvan Yan uint32_t size_hi; 12826947304SEvan Yan uint32_t size_lo; 12926947304SEvan Yan 13026947304SEvan Yan } pcicfg_range_t; 13126947304SEvan Yan 13226947304SEvan Yan typedef struct hole hole_t; 13326947304SEvan Yan 13426947304SEvan Yan struct hole { 13526947304SEvan Yan uint64_t start; 13626947304SEvan Yan uint64_t len; 13726947304SEvan Yan hole_t *next; 13826947304SEvan Yan }; 13926947304SEvan Yan 14026947304SEvan Yan typedef struct pcicfg_phdl pcicfg_phdl_t; 14126947304SEvan Yan 14226947304SEvan Yan struct pcicfg_phdl { 14326947304SEvan Yan 14426947304SEvan Yan dev_info_t *dip; /* Associated with the attach point */ 14526947304SEvan Yan pcicfg_phdl_t *next; 14626947304SEvan Yan 14726947304SEvan Yan uint64_t memory_base; /* Memory base for this attach point */ 14826947304SEvan Yan uint64_t memory_last; 14926947304SEvan Yan uint64_t memory_len; 15026947304SEvan Yan uint32_t io_base; /* I/O base for this attach point */ 15126947304SEvan Yan uint32_t io_last; 15226947304SEvan Yan uint32_t io_len; 15326947304SEvan Yan 15426947304SEvan Yan int error; 15526947304SEvan Yan uint_t highest_bus; /* Highest bus seen on the probe */ 15626947304SEvan Yan 15726947304SEvan Yan hole_t mem_hole; /* Memory hole linked list. */ 15826947304SEvan Yan hole_t io_hole; /* IO hole linked list */ 15926947304SEvan Yan 16026947304SEvan Yan ndi_ra_request_t mem_req; /* allocator request for memory */ 16126947304SEvan Yan ndi_ra_request_t io_req; /* allocator request for I/O */ 16226947304SEvan Yan }; 16326947304SEvan Yan 16426947304SEvan Yan struct pcicfg_standard_prop_entry { 16526947304SEvan Yan uchar_t *name; 16626947304SEvan Yan uint_t config_offset; 16726947304SEvan Yan uint_t size; 16826947304SEvan Yan }; 16926947304SEvan Yan 17026947304SEvan Yan 17126947304SEvan Yan struct pcicfg_name_entry { 17226947304SEvan Yan uint32_t class_code; 17326947304SEvan Yan char *name; 17426947304SEvan Yan }; 17526947304SEvan Yan 17626947304SEvan Yan struct pcicfg_find_ctrl { 17726947304SEvan Yan uint_t device; 17826947304SEvan Yan uint_t function; 17926947304SEvan Yan dev_info_t *dip; 18026947304SEvan Yan }; 18126947304SEvan Yan 18226947304SEvan Yan typedef struct pcicfg_err_regs { 18326947304SEvan Yan uint16_t cmd; 18426947304SEvan Yan uint16_t bcntl; 18526947304SEvan Yan uint16_t pcie_dev; 18626947304SEvan Yan uint16_t devctl; 18726947304SEvan Yan uint16_t pcie_cap_off; 18826947304SEvan Yan } pcicfg_err_regs_t; 18926947304SEvan Yan 19026947304SEvan Yan /* 19126947304SEvan Yan * List of Indirect Config Map Devices. At least the intent of the 19226947304SEvan Yan * design is to look for a device in this list during the configure 19326947304SEvan Yan * operation, and if the device is listed here, then it is a nontransparent 19426947304SEvan Yan * bridge, hence load the driver and avail the config map services from 19526947304SEvan Yan * the driver. Class and Subclass should be as defined in the PCI specs 19626947304SEvan Yan * ie. class is 0x6, and subclass is 0x9. 19726947304SEvan Yan */ 19826947304SEvan Yan static struct { 19926947304SEvan Yan uint8_t mem_range_bar_offset; 20026947304SEvan Yan uint8_t io_range_bar_offset; 20126947304SEvan Yan uint8_t prefetch_mem_range_bar_offset; 20226947304SEvan Yan } pcicfg_indirect_map_devs[] = { 20326947304SEvan Yan PCI_CONF_BASE3, PCI_CONF_BASE2, PCI_CONF_BASE3, 20426947304SEvan Yan 0, 0, 0, 20526947304SEvan Yan }; 20626947304SEvan Yan 20726947304SEvan Yan #define PCICFG_MAKE_REG_HIGH(busnum, devnum, funcnum, register)\ 20826947304SEvan Yan (\ 20926947304SEvan Yan ((ulong_t)(busnum & 0xff) << 16) |\ 21026947304SEvan Yan ((ulong_t)(devnum & 0x1f) << 11) |\ 21126947304SEvan Yan ((ulong_t)(funcnum & 0x7) << 8) |\ 21226947304SEvan Yan ((ulong_t)(register & 0x3f))) 21326947304SEvan Yan 21426947304SEvan Yan /* 21526947304SEvan Yan * debug macros: 21626947304SEvan Yan */ 21726947304SEvan Yan #if defined(DEBUG) 21826947304SEvan Yan extern void prom_printf(const char *, ...); 21926947304SEvan Yan 22026947304SEvan Yan /* 22126947304SEvan Yan * Following values are defined for this debug flag. 22226947304SEvan Yan * 22326947304SEvan Yan * 1 = dump configuration header only. 22426947304SEvan Yan * 2 = dump generic debug data only (no config header dumped) 22526947304SEvan Yan * 3 = dump everything (both 1 and 2) 22626947304SEvan Yan */ 22726947304SEvan Yan int pcicfg_debug = 0; 22826947304SEvan Yan int pcicfg_dump_fcode = 0; 22926947304SEvan Yan 23026947304SEvan Yan static void debug(char *, uintptr_t, uintptr_t, 23126947304SEvan Yan uintptr_t, uintptr_t, uintptr_t); 23226947304SEvan Yan 23326947304SEvan Yan #define DEBUG0(fmt)\ 23426947304SEvan Yan debug(fmt, 0, 0, 0, 0, 0); 23526947304SEvan Yan #define DEBUG1(fmt, a1)\ 23626947304SEvan Yan debug(fmt, (uintptr_t)(a1), 0, 0, 0, 0); 23726947304SEvan Yan #define DEBUG2(fmt, a1, a2)\ 23826947304SEvan Yan debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2), 0, 0, 0); 23926947304SEvan Yan #define DEBUG3(fmt, a1, a2, a3)\ 24026947304SEvan Yan debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2),\ 24126947304SEvan Yan (uintptr_t)(a3), 0, 0); 24226947304SEvan Yan #define DEBUG4(fmt, a1, a2, a3, a4)\ 24326947304SEvan Yan debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2),\ 24426947304SEvan Yan (uintptr_t)(a3), (uintptr_t)(a4), 0); 24526947304SEvan Yan #else 24626947304SEvan Yan #define DEBUG0(fmt) 24726947304SEvan Yan #define DEBUG1(fmt, a1) 24826947304SEvan Yan #define DEBUG2(fmt, a1, a2) 24926947304SEvan Yan #define DEBUG3(fmt, a1, a2, a3) 25026947304SEvan Yan #define DEBUG4(fmt, a1, a2, a3, a4) 25126947304SEvan Yan #endif 25226947304SEvan Yan 25326947304SEvan Yan #ifdef PCICFG_INTERPRET_FCODE 25426947304SEvan Yan int pcicfg_dont_interpret = 0; 25526947304SEvan Yan #else 25626947304SEvan Yan int pcicfg_dont_interpret = 1; 25726947304SEvan Yan #endif 25826947304SEvan Yan 25926947304SEvan Yan /* 26026947304SEvan Yan * forward declarations for routines defined in this module (called here) 26126947304SEvan Yan */ 26226947304SEvan Yan 26326947304SEvan Yan static int pcicfg_add_config_reg(dev_info_t *, 26426947304SEvan Yan uint_t, uint_t, uint_t); 26526947304SEvan Yan static int pcicfg_probe_children(dev_info_t *, uint_t, uint_t, uint_t, 266c0da6274SZhi-Jun Robin Fu uint_t *, pcicfg_flags_t, boolean_t); 26726947304SEvan Yan 26826947304SEvan Yan #ifdef PCICFG_INTERPRET_FCODE 26926947304SEvan Yan static int pcicfg_load_fcode(dev_info_t *, uint_t, uint_t, uint_t, 27026947304SEvan Yan uint16_t, uint16_t, uchar_t **, int *, int, int); 27126947304SEvan Yan #endif 27226947304SEvan Yan 27326947304SEvan Yan static int pcicfg_fcode_probe(dev_info_t *, uint_t, uint_t, uint_t, 274c0da6274SZhi-Jun Robin Fu uint_t *, pcicfg_flags_t, boolean_t); 27526947304SEvan Yan static int pcicfg_probe_bridge(dev_info_t *, ddi_acc_handle_t, uint_t, 276c0da6274SZhi-Jun Robin Fu uint_t *, boolean_t); 27726947304SEvan Yan static int pcicfg_free_all_resources(dev_info_t *); 27826947304SEvan Yan static int pcicfg_alloc_new_resources(dev_info_t *); 27926947304SEvan Yan static int pcicfg_match_dev(dev_info_t *, void *); 28026947304SEvan Yan static dev_info_t *pcicfg_devi_find(dev_info_t *, uint_t, uint_t); 28126947304SEvan Yan static pcicfg_phdl_t *pcicfg_find_phdl(dev_info_t *); 28226947304SEvan Yan static pcicfg_phdl_t *pcicfg_create_phdl(dev_info_t *); 28326947304SEvan Yan static int pcicfg_destroy_phdl(dev_info_t *); 28426947304SEvan Yan static int pcicfg_sum_resources(dev_info_t *, void *); 28526947304SEvan Yan static int pcicfg_find_resource_end(dev_info_t *, void *); 28626947304SEvan Yan static int pcicfg_allocate_chunk(dev_info_t *); 28726947304SEvan Yan static int pcicfg_program_ap(dev_info_t *); 28826947304SEvan Yan static int pcicfg_device_assign(dev_info_t *); 28926947304SEvan Yan static int pcicfg_bridge_assign(dev_info_t *, void *); 29026947304SEvan Yan static int pcicfg_device_assign_readonly(dev_info_t *); 29126947304SEvan Yan static int pcicfg_free_resources(dev_info_t *, pcicfg_flags_t); 29226947304SEvan Yan static void pcicfg_setup_bridge(pcicfg_phdl_t *, ddi_acc_handle_t, 29326947304SEvan Yan dev_info_t *); 29426947304SEvan Yan static void pcicfg_update_bridge(pcicfg_phdl_t *, ddi_acc_handle_t); 29526947304SEvan Yan static void pcicfg_enable_bridge_probe_err(dev_info_t *dip, 29626947304SEvan Yan ddi_acc_handle_t h, pcicfg_err_regs_t *regs); 29726947304SEvan Yan static void pcicfg_disable_bridge_probe_err(dev_info_t *dip, 29826947304SEvan Yan ddi_acc_handle_t h, pcicfg_err_regs_t *regs); 29926947304SEvan Yan static int pcicfg_update_assigned_prop(dev_info_t *, pci_regspec_t *); 30026947304SEvan Yan static void pcicfg_device_on(ddi_acc_handle_t); 30126947304SEvan Yan static void pcicfg_device_off(ddi_acc_handle_t); 30226947304SEvan Yan static int pcicfg_set_busnode_props(dev_info_t *, uint8_t, int, int); 30326947304SEvan Yan static int pcicfg_free_bridge_resources(dev_info_t *); 30426947304SEvan Yan static int pcicfg_free_device_resources(dev_info_t *, pcicfg_flags_t); 305c0da6274SZhi-Jun Robin Fu static int pcicfg_teardown_device(dev_info_t *, pcicfg_flags_t, boolean_t); 30626947304SEvan Yan static int pcicfg_config_setup(dev_info_t *, ddi_acc_handle_t *); 30726947304SEvan Yan static void pcicfg_config_teardown(ddi_acc_handle_t *); 30826947304SEvan Yan static void pcicfg_get_mem(pcicfg_phdl_t *, uint32_t, uint64_t *); 30926947304SEvan Yan static void pcicfg_get_io(pcicfg_phdl_t *, uint32_t, uint32_t *); 31026947304SEvan Yan static int pcicfg_update_ranges_prop(dev_info_t *, pcicfg_range_t *); 31126947304SEvan Yan static int pcicfg_map_phys(dev_info_t *, pci_regspec_t *, caddr_t *, 31226947304SEvan Yan ddi_device_acc_attr_t *, ddi_acc_handle_t *); 31326947304SEvan Yan static void pcicfg_unmap_phys(ddi_acc_handle_t *, pci_regspec_t *); 31426947304SEvan Yan static int pcicfg_dump_assigned(dev_info_t *); 31526947304SEvan Yan static uint_t pcicfg_configure_ntbridge(dev_info_t *, uint_t, uint_t); 31626947304SEvan Yan static int pcicfg_indirect_map(dev_info_t *dip); 31726947304SEvan Yan static uint_t pcicfg_get_ntbridge_child_range(dev_info_t *, uint64_t *, 31826947304SEvan Yan uint64_t *, uint_t); 31926947304SEvan Yan static int pcicfg_is_ntbridge(dev_info_t *); 32026947304SEvan Yan static int pcicfg_ntbridge_allocate_resources(dev_info_t *); 32126947304SEvan Yan static int pcicfg_ntbridge_configure_done(dev_info_t *); 32226947304SEvan Yan static int pcicfg_ntbridge_unconfigure(dev_info_t *); 32326947304SEvan Yan static int pcicfg_ntbridge_unconfigure_child(dev_info_t *, uint_t); 32426947304SEvan Yan static void pcicfg_free_hole(hole_t *); 32526947304SEvan Yan static uint64_t pcicfg_alloc_hole(hole_t *, uint64_t *, uint32_t); 32626947304SEvan Yan static int pcicfg_update_available_prop(dev_info_t *, pci_regspec_t *); 32726947304SEvan Yan static int pcicfg_ari_configure(dev_info_t *); 32826947304SEvan Yan static int pcicfg_populate_reg_props(dev_info_t *, ddi_acc_handle_t); 32926947304SEvan Yan static int pcicfg_populate_props_from_bar(dev_info_t *, ddi_acc_handle_t); 33026947304SEvan Yan static int pcicfg_update_assigned_prop_value(dev_info_t *, uint32_t, 33126947304SEvan Yan uint32_t, uint32_t, uint_t); 332c0da6274SZhi-Jun Robin Fu static boolean_t is_pcie_fabric(dev_info_t *dip); 33326947304SEvan Yan 33426947304SEvan Yan #ifdef DEBUG 33526947304SEvan Yan static void pcicfg_dump_common_config(ddi_acc_handle_t config_handle); 33626947304SEvan Yan static void pcicfg_dump_device_config(ddi_acc_handle_t); 33726947304SEvan Yan 33826947304SEvan Yan static void pcicfg_dump_bridge_config(ddi_acc_handle_t config_handle); 33926947304SEvan Yan static uint64_t pcicfg_unused_space(hole_t *, uint32_t *); 34026947304SEvan Yan 34126947304SEvan Yan #define PCICFG_DUMP_COMMON_CONFIG(hdl) (void)pcicfg_dump_common_config(hdl) 34226947304SEvan Yan #define PCICFG_DUMP_DEVICE_CONFIG(hdl) (void)pcicfg_dump_device_config(hdl) 34326947304SEvan Yan #define PCICFG_DUMP_BRIDGE_CONFIG(hdl) (void)pcicfg_dump_bridge_config(hdl) 34426947304SEvan Yan #else 34526947304SEvan Yan #define PCICFG_DUMP_COMMON_CONFIG(handle) 34626947304SEvan Yan #define PCICFG_DUMP_DEVICE_CONFIG(handle) 34726947304SEvan Yan #define PCICFG_DUMP_BRIDGE_CONFIG(handle) 34826947304SEvan Yan #endif 34926947304SEvan Yan 35026947304SEvan Yan static kmutex_t pcicfg_list_mutex; /* Protects the probe handle list */ 35126947304SEvan Yan static pcicfg_phdl_t *pcicfg_phdl_list = NULL; 35226947304SEvan Yan 35326947304SEvan Yan #ifndef _DONT_USE_1275_GENERIC_NAMES 35426947304SEvan Yan /* 35526947304SEvan Yan * Class code table 35626947304SEvan Yan */ 35726947304SEvan Yan static struct pcicfg_name_entry pcicfg_class_lookup [] = { 35826947304SEvan Yan 35926947304SEvan Yan { 0x001, "display" }, 36026947304SEvan Yan { 0x100, "scsi" }, 36126947304SEvan Yan { 0x101, "ide" }, 36226947304SEvan Yan { 0x102, "fdc" }, 36326947304SEvan Yan { 0x103, "ipi" }, 36426947304SEvan Yan { 0x104, "raid" }, 36526947304SEvan Yan { 0x200, "ethernet" }, 36626947304SEvan Yan { 0x201, "token-ring" }, 36726947304SEvan Yan { 0x202, "fddi" }, 36826947304SEvan Yan { 0x203, "atm" }, 36926947304SEvan Yan { 0x300, "display" }, 37026947304SEvan Yan { 0x400, "video" }, 37126947304SEvan Yan { 0x401, "sound" }, 37226947304SEvan Yan { 0x500, "memory" }, 37326947304SEvan Yan { 0x501, "flash" }, 37426947304SEvan Yan { 0x600, "host" }, 37526947304SEvan Yan { 0x601, "isa" }, 37626947304SEvan Yan { 0x602, "eisa" }, 37726947304SEvan Yan { 0x603, "mca" }, 37826947304SEvan Yan { 0x604, "pci" }, 37926947304SEvan Yan { 0x605, "pcmcia" }, 38026947304SEvan Yan { 0x606, "nubus" }, 38126947304SEvan Yan { 0x607, "cardbus" }, 38226947304SEvan Yan { 0x609, "pci" }, 38326947304SEvan Yan { 0x700, "serial" }, 38426947304SEvan Yan { 0x701, "parallel" }, 38526947304SEvan Yan { 0x800, "interrupt-controller" }, 38626947304SEvan Yan { 0x801, "dma-controller" }, 38726947304SEvan Yan { 0x802, "timer" }, 38826947304SEvan Yan { 0x803, "rtc" }, 38926947304SEvan Yan { 0x900, "keyboard" }, 39026947304SEvan Yan { 0x901, "pen" }, 39126947304SEvan Yan { 0x902, "mouse" }, 39226947304SEvan Yan { 0xa00, "dock" }, 39326947304SEvan Yan { 0xb00, "cpu" }, 39426947304SEvan Yan { 0xc00, "firewire" }, 39526947304SEvan Yan { 0xc01, "access-bus" }, 39626947304SEvan Yan { 0xc02, "ssa" }, 39726947304SEvan Yan { 0xc03, "usb" }, 39826947304SEvan Yan { 0xc04, "fibre-channel" }, 39926947304SEvan Yan { 0, 0 } 40026947304SEvan Yan }; 40126947304SEvan Yan #endif /* _DONT_USE_1275_GENERIC_NAMES */ 40226947304SEvan Yan 40326947304SEvan Yan /* 40426947304SEvan Yan * Module control operations 40526947304SEvan Yan */ 40626947304SEvan Yan 40726947304SEvan Yan extern struct mod_ops mod_miscops; 40826947304SEvan Yan 40926947304SEvan Yan static struct modlmisc modlmisc = { 41026947304SEvan Yan &mod_miscops, /* Type of module */ 41126947304SEvan Yan "PCIe/PCI Config (EFCode Enabled)" 41226947304SEvan Yan }; 41326947304SEvan Yan 41426947304SEvan Yan static struct modlinkage modlinkage = { 41526947304SEvan Yan MODREV_1, (void *)&modlmisc, NULL 41626947304SEvan Yan }; 41726947304SEvan Yan 41826947304SEvan Yan #ifdef DEBUG 41926947304SEvan Yan 42026947304SEvan Yan static void 42126947304SEvan Yan pcicfg_dump_common_config(ddi_acc_handle_t config_handle) 42226947304SEvan Yan { 42326947304SEvan Yan if ((pcicfg_debug & 1) == 0) 42426947304SEvan Yan return; 42526947304SEvan Yan cmn_err(CE_CONT, " Vendor ID = [0x%x]\n", 42626947304SEvan Yan pci_config_get16(config_handle, PCI_CONF_VENID)); 42726947304SEvan Yan cmn_err(CE_CONT, " Device ID = [0x%x]\n", 42826947304SEvan Yan pci_config_get16(config_handle, PCI_CONF_DEVID)); 42926947304SEvan Yan cmn_err(CE_CONT, " Command REG = [0x%x]\n", 43026947304SEvan Yan pci_config_get16(config_handle, PCI_CONF_COMM)); 43126947304SEvan Yan cmn_err(CE_CONT, " Status REG = [0x%x]\n", 43226947304SEvan Yan pci_config_get16(config_handle, PCI_CONF_STAT)); 43326947304SEvan Yan cmn_err(CE_CONT, " Revision ID = [0x%x]\n", 43426947304SEvan Yan pci_config_get8(config_handle, PCI_CONF_REVID)); 43526947304SEvan Yan cmn_err(CE_CONT, " Prog Class = [0x%x]\n", 43626947304SEvan Yan pci_config_get8(config_handle, PCI_CONF_PROGCLASS)); 43726947304SEvan Yan cmn_err(CE_CONT, " Dev Class = [0x%x]\n", 43826947304SEvan Yan pci_config_get8(config_handle, PCI_CONF_SUBCLASS)); 43926947304SEvan Yan cmn_err(CE_CONT, " Base Class = [0x%x]\n", 44026947304SEvan Yan pci_config_get8(config_handle, PCI_CONF_BASCLASS)); 44126947304SEvan Yan cmn_err(CE_CONT, " Device ID = [0x%x]\n", 44226947304SEvan Yan pci_config_get8(config_handle, PCI_CONF_CACHE_LINESZ)); 44326947304SEvan Yan cmn_err(CE_CONT, " Header Type = [0x%x]\n", 44426947304SEvan Yan pci_config_get8(config_handle, PCI_CONF_HEADER)); 44526947304SEvan Yan cmn_err(CE_CONT, " BIST = [0x%x]\n", 44626947304SEvan Yan pci_config_get8(config_handle, PCI_CONF_BIST)); 44726947304SEvan Yan cmn_err(CE_CONT, " BASE 0 = [0x%x]\n", 44826947304SEvan Yan pci_config_get32(config_handle, PCI_CONF_BASE0)); 44926947304SEvan Yan cmn_err(CE_CONT, " BASE 1 = [0x%x]\n", 45026947304SEvan Yan pci_config_get32(config_handle, PCI_CONF_BASE1)); 45126947304SEvan Yan 45226947304SEvan Yan } 45326947304SEvan Yan 45426947304SEvan Yan static void 45526947304SEvan Yan pcicfg_dump_device_config(ddi_acc_handle_t config_handle) 45626947304SEvan Yan { 45726947304SEvan Yan if ((pcicfg_debug & 1) == 0) 45826947304SEvan Yan return; 45926947304SEvan Yan pcicfg_dump_common_config(config_handle); 46026947304SEvan Yan 46126947304SEvan Yan cmn_err(CE_CONT, " BASE 2 = [0x%x]\n", 46226947304SEvan Yan pci_config_get32(config_handle, PCI_CONF_BASE2)); 46326947304SEvan Yan cmn_err(CE_CONT, " BASE 3 = [0x%x]\n", 46426947304SEvan Yan pci_config_get32(config_handle, PCI_CONF_BASE3)); 46526947304SEvan Yan cmn_err(CE_CONT, " BASE 4 = [0x%x]\n", 46626947304SEvan Yan pci_config_get32(config_handle, PCI_CONF_BASE4)); 46726947304SEvan Yan cmn_err(CE_CONT, " BASE 5 = [0x%x]\n", 46826947304SEvan Yan pci_config_get32(config_handle, PCI_CONF_BASE5)); 46926947304SEvan Yan cmn_err(CE_CONT, " Cardbus CIS = [0x%x]\n", 47026947304SEvan Yan pci_config_get32(config_handle, PCI_CONF_CIS)); 47126947304SEvan Yan cmn_err(CE_CONT, " Sub VID = [0x%x]\n", 47226947304SEvan Yan pci_config_get16(config_handle, PCI_CONF_SUBVENID)); 47326947304SEvan Yan cmn_err(CE_CONT, " Sub SID = [0x%x]\n", 47426947304SEvan Yan pci_config_get16(config_handle, PCI_CONF_SUBSYSID)); 47526947304SEvan Yan cmn_err(CE_CONT, " ROM = [0x%x]\n", 47626947304SEvan Yan pci_config_get32(config_handle, PCI_CONF_ROM)); 47726947304SEvan Yan cmn_err(CE_CONT, " I Line = [0x%x]\n", 47826947304SEvan Yan pci_config_get8(config_handle, PCI_CONF_ILINE)); 47926947304SEvan Yan cmn_err(CE_CONT, " I Pin = [0x%x]\n", 48026947304SEvan Yan pci_config_get8(config_handle, PCI_CONF_IPIN)); 48126947304SEvan Yan cmn_err(CE_CONT, " Max Grant = [0x%x]\n", 48226947304SEvan Yan pci_config_get8(config_handle, PCI_CONF_MIN_G)); 48326947304SEvan Yan cmn_err(CE_CONT, " Max Latent = [0x%x]\n", 48426947304SEvan Yan pci_config_get8(config_handle, PCI_CONF_MAX_L)); 48526947304SEvan Yan } 48626947304SEvan Yan 48726947304SEvan Yan static void 48826947304SEvan Yan pcicfg_dump_bridge_config(ddi_acc_handle_t config_handle) 48926947304SEvan Yan { 49026947304SEvan Yan if ((pcicfg_debug & 1) == 0) 49126947304SEvan Yan return; 49226947304SEvan Yan 49326947304SEvan Yan pcicfg_dump_common_config(config_handle); 49426947304SEvan Yan 49526947304SEvan Yan cmn_err(CE_CONT, "........................................\n"); 49626947304SEvan Yan 49726947304SEvan Yan cmn_err(CE_CONT, " Pri Bus = [0x%x]\n", 49826947304SEvan Yan pci_config_get8(config_handle, PCI_BCNF_PRIBUS)); 49926947304SEvan Yan cmn_err(CE_CONT, " Sec Bus = [0x%x]\n", 50026947304SEvan Yan pci_config_get8(config_handle, PCI_BCNF_SECBUS)); 50126947304SEvan Yan cmn_err(CE_CONT, " Sub Bus = [0x%x]\n", 50226947304SEvan Yan pci_config_get8(config_handle, PCI_BCNF_SUBBUS)); 50326947304SEvan Yan cmn_err(CE_CONT, " Latency = [0x%x]\n", 50426947304SEvan Yan pci_config_get8(config_handle, PCI_BCNF_LATENCY_TIMER)); 50526947304SEvan Yan cmn_err(CE_CONT, " I/O Base LO = [0x%x]\n", 50626947304SEvan Yan pci_config_get8(config_handle, PCI_BCNF_IO_BASE_LOW)); 50726947304SEvan Yan cmn_err(CE_CONT, " I/O Lim LO = [0x%x]\n", 50826947304SEvan Yan pci_config_get8(config_handle, PCI_BCNF_IO_LIMIT_LOW)); 50926947304SEvan Yan cmn_err(CE_CONT, " Sec. Status = [0x%x]\n", 51026947304SEvan Yan pci_config_get16(config_handle, PCI_BCNF_SEC_STATUS)); 51126947304SEvan Yan cmn_err(CE_CONT, " Mem Base = [0x%x]\n", 51226947304SEvan Yan pci_config_get16(config_handle, PCI_BCNF_MEM_BASE)); 51326947304SEvan Yan cmn_err(CE_CONT, " Mem Limit = [0x%x]\n", 51426947304SEvan Yan pci_config_get16(config_handle, PCI_BCNF_MEM_LIMIT)); 51526947304SEvan Yan cmn_err(CE_CONT, " PF Mem Base = [0x%x]\n", 51626947304SEvan Yan pci_config_get16(config_handle, PCI_BCNF_PF_BASE_LOW)); 51726947304SEvan Yan cmn_err(CE_CONT, " PF Mem Lim = [0x%x]\n", 51826947304SEvan Yan pci_config_get16(config_handle, PCI_BCNF_PF_LIMIT_LOW)); 51926947304SEvan Yan cmn_err(CE_CONT, " PF Base HI = [0x%x]\n", 52026947304SEvan Yan pci_config_get32(config_handle, PCI_BCNF_PF_BASE_HIGH)); 52126947304SEvan Yan cmn_err(CE_CONT, " PF Lim HI = [0x%x]\n", 52226947304SEvan Yan pci_config_get32(config_handle, PCI_BCNF_PF_LIMIT_HIGH)); 52326947304SEvan Yan cmn_err(CE_CONT, " I/O Base HI = [0x%x]\n", 52426947304SEvan Yan pci_config_get16(config_handle, PCI_BCNF_IO_BASE_HI)); 52526947304SEvan Yan cmn_err(CE_CONT, " I/O Lim HI = [0x%x]\n", 52626947304SEvan Yan pci_config_get16(config_handle, PCI_BCNF_IO_LIMIT_HI)); 52726947304SEvan Yan cmn_err(CE_CONT, " ROM addr = [0x%x]\n", 52826947304SEvan Yan pci_config_get32(config_handle, PCI_BCNF_ROM)); 52926947304SEvan Yan cmn_err(CE_CONT, " Intr Line = [0x%x]\n", 53026947304SEvan Yan pci_config_get8(config_handle, PCI_BCNF_ILINE)); 53126947304SEvan Yan cmn_err(CE_CONT, " Intr Pin = [0x%x]\n", 53226947304SEvan Yan pci_config_get8(config_handle, PCI_BCNF_IPIN)); 53326947304SEvan Yan cmn_err(CE_CONT, " Bridge Ctrl = [0x%x]\n", 53426947304SEvan Yan pci_config_get16(config_handle, PCI_BCNF_BCNTRL)); 53526947304SEvan Yan } 53626947304SEvan Yan 53726947304SEvan Yan #endif 53826947304SEvan Yan 53926947304SEvan Yan 54026947304SEvan Yan int 54126947304SEvan Yan _init() 54226947304SEvan Yan { 54326947304SEvan Yan DEBUG0("PCI configurator installed - Fcode Interpretation/21554\n"); 54426947304SEvan Yan 54526947304SEvan Yan mutex_init(&pcicfg_list_mutex, NULL, MUTEX_DRIVER, NULL); 54626947304SEvan Yan return (mod_install(&modlinkage)); 54726947304SEvan Yan } 54826947304SEvan Yan 54926947304SEvan Yan int 55026947304SEvan Yan _fini(void) 55126947304SEvan Yan { 55226947304SEvan Yan int error; 55326947304SEvan Yan 55426947304SEvan Yan error = mod_remove(&modlinkage); 55526947304SEvan Yan if (error != 0) { 55626947304SEvan Yan return (error); 55726947304SEvan Yan } 55826947304SEvan Yan mutex_destroy(&pcicfg_list_mutex); 55926947304SEvan Yan return (0); 56026947304SEvan Yan } 56126947304SEvan Yan 56226947304SEvan Yan int 56326947304SEvan Yan _info(modinfop) 56426947304SEvan Yan struct modinfo *modinfop; 56526947304SEvan Yan { 56626947304SEvan Yan return (mod_info(&modlinkage, modinfop)); 56726947304SEvan Yan } 56826947304SEvan Yan 56926947304SEvan Yan /*ARGSUSED*/ 57026947304SEvan Yan static uint8_t 57126947304SEvan Yan pcicfg_get_nslots(dev_info_t *dip, ddi_acc_handle_t handle) 57226947304SEvan Yan { 57326947304SEvan Yan uint8_t num_slots = 0; 57426947304SEvan Yan uint16_t cap_ptr; 57526947304SEvan Yan 57626947304SEvan Yan if ((PCI_CAP_LOCATE(handle, PCI_CAP_ID_PCI_HOTPLUG, 57726947304SEvan Yan &cap_ptr)) == DDI_SUCCESS) { 57826947304SEvan Yan uint32_t config; 57926947304SEvan Yan 58026947304SEvan Yan PCI_CAP_PUT8(handle, NULL, cap_ptr, PCI_HP_DWORD_SELECT_OFF, 58126947304SEvan Yan PCI_HP_SLOT_CONFIGURATION_REG); 58226947304SEvan Yan config = PCI_CAP_GET32(handle, NULL, cap_ptr, 58326947304SEvan Yan PCI_HP_DWORD_DATA_OFF); 58426947304SEvan Yan num_slots = config & 0x1F; 58526947304SEvan Yan } else if ((PCI_CAP_LOCATE(handle, PCI_CAP_ID_SLOT_ID, &cap_ptr)) 58626947304SEvan Yan == DDI_SUCCESS) { 58726947304SEvan Yan uint8_t esr_reg = PCI_CAP_GET8(handle, NULL, 58826947304SEvan Yan cap_ptr, PCI_CAP_ID_REGS_OFF); 58926947304SEvan Yan 59026947304SEvan Yan num_slots = PCI_CAPSLOT_NSLOTS(esr_reg); 59126947304SEvan Yan } else if ((PCI_CAP_LOCATE(handle, PCI_CAP_ID_PCI_E, &cap_ptr)) 59226947304SEvan Yan == DDI_SUCCESS) { 59326947304SEvan Yan int port_type = PCI_CAP_GET16(handle, NULL, cap_ptr, 59426947304SEvan Yan PCIE_PCIECAP) & PCIE_PCIECAP_DEV_TYPE_MASK; 59526947304SEvan Yan 59626947304SEvan Yan if ((port_type == PCIE_PCIECAP_DEV_TYPE_DOWN) && 59726947304SEvan Yan (PCI_CAP_GET16(handle, NULL, cap_ptr, PCIE_PCIECAP) 59826947304SEvan Yan & PCIE_PCIECAP_SLOT_IMPL)) 59926947304SEvan Yan num_slots = 1; 60026947304SEvan Yan } 60126947304SEvan Yan 60226947304SEvan Yan DEBUG3("%s#%d has %d slots", 60326947304SEvan Yan ddi_get_name(dip), ddi_get_instance(dip), num_slots); 60426947304SEvan Yan 60526947304SEvan Yan return (num_slots); 60626947304SEvan Yan } 60726947304SEvan Yan 60826947304SEvan Yan /*ARGSUSED*/ 60926947304SEvan Yan static uint8_t 61026947304SEvan Yan pcicfg_is_chassis(dev_info_t *dip, ddi_acc_handle_t handle) 61126947304SEvan Yan { 61226947304SEvan Yan uint16_t cap_ptr; 61326947304SEvan Yan 61426947304SEvan Yan if ((PCI_CAP_LOCATE(handle, PCI_CAP_ID_SLOT_ID, &cap_ptr)) != 61526947304SEvan Yan DDI_FAILURE) { 61626947304SEvan Yan 61726947304SEvan Yan uint8_t esr_reg = PCI_CAP_GET8(handle, NULL, cap_ptr, 2); 61826947304SEvan Yan if (PCI_CAPSLOT_FIC(esr_reg)) 61926947304SEvan Yan return (B_TRUE); 62026947304SEvan Yan } 62126947304SEvan Yan return (B_FALSE); 62226947304SEvan Yan } 62326947304SEvan Yan 62426947304SEvan Yan /*ARGSUSED*/ 62526947304SEvan Yan static int 62626947304SEvan Yan pcicfg_pcie_dev(dev_info_t *dip, int bus_type, pcicfg_err_regs_t *regs) 62726947304SEvan Yan { 62826947304SEvan Yan /* get parent device's device_type property */ 62926947304SEvan Yan char *device_type; 63026947304SEvan Yan int rc = DDI_FAILURE; 63126947304SEvan Yan dev_info_t *pdip = ddi_get_parent(dip); 63226947304SEvan Yan 63326947304SEvan Yan regs->pcie_dev = 0; 63426947304SEvan Yan if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip, 63526947304SEvan Yan DDI_PROP_DONTPASS, "device_type", &device_type) 63626947304SEvan Yan != DDI_PROP_SUCCESS) { 63726947304SEvan Yan DEBUG2("device_type property missing for %s#%d", 63826947304SEvan Yan ddi_get_name(pdip), ddi_get_instance(pdip)); 63926947304SEvan Yan return (DDI_FAILURE); 64026947304SEvan Yan } 64126947304SEvan Yan switch (bus_type) { 64226947304SEvan Yan case PCICFG_DEVICE_TYPE_PCIE: 64326947304SEvan Yan if (strcmp(device_type, "pciex") == 0) { 64426947304SEvan Yan rc = DDI_SUCCESS; 64526947304SEvan Yan regs->pcie_dev = 1; 64626947304SEvan Yan } 64726947304SEvan Yan break; 64826947304SEvan Yan case PCICFG_DEVICE_TYPE_PCI: 64926947304SEvan Yan if (strcmp(device_type, "pci") == 0) 65026947304SEvan Yan rc = DDI_SUCCESS; 65126947304SEvan Yan break; 65226947304SEvan Yan default: 65326947304SEvan Yan break; 65426947304SEvan Yan } 65526947304SEvan Yan ddi_prop_free(device_type); 65626947304SEvan Yan return (rc); 65726947304SEvan Yan } 65826947304SEvan Yan 65926947304SEvan Yan /*ARGSUSED*/ 66026947304SEvan Yan static int 66126947304SEvan Yan pcicfg_pcie_port_type(dev_info_t *dip, ddi_acc_handle_t handle) 66226947304SEvan Yan { 66326947304SEvan Yan int port_type = -1; 66426947304SEvan Yan uint16_t cap_ptr; 66526947304SEvan Yan 66626947304SEvan Yan if ((PCI_CAP_LOCATE(handle, PCI_CAP_ID_PCI_E, &cap_ptr)) != 66726947304SEvan Yan DDI_FAILURE) 66826947304SEvan Yan port_type = PCI_CAP_GET16(handle, NULL, 66926947304SEvan Yan cap_ptr, PCIE_PCIECAP) & PCIE_PCIECAP_DEV_TYPE_MASK; 67026947304SEvan Yan 67126947304SEvan Yan return (port_type); 67226947304SEvan Yan } 67326947304SEvan Yan 67426947304SEvan Yan static int 67526947304SEvan Yan pcicfg_pcie_device_type(dev_info_t *dip, ddi_acc_handle_t handle) 67626947304SEvan Yan { 67726947304SEvan Yan int port_type = pcicfg_pcie_port_type(dip, handle); 67826947304SEvan Yan 67926947304SEvan Yan DEBUG1("device port_type = %x\n", port_type); 68026947304SEvan Yan /* No PCIe CAP regs, we are not PCIe device_type */ 68126947304SEvan Yan if (port_type < 0) 68226947304SEvan Yan return (DDI_FAILURE); 68326947304SEvan Yan 68426947304SEvan Yan /* check for all PCIe device_types */ 68526947304SEvan Yan if ((port_type == PCIE_PCIECAP_DEV_TYPE_UP) || 68626947304SEvan Yan (port_type == PCIE_PCIECAP_DEV_TYPE_DOWN) || 68726947304SEvan Yan (port_type == PCIE_PCIECAP_DEV_TYPE_ROOT) || 68826947304SEvan Yan (port_type == PCIE_PCIECAP_DEV_TYPE_PCI2PCIE)) 68926947304SEvan Yan return (DDI_SUCCESS); 69026947304SEvan Yan 69126947304SEvan Yan return (DDI_FAILURE); 69226947304SEvan Yan 69326947304SEvan Yan } 69426947304SEvan Yan 69526947304SEvan Yan /* 69626947304SEvan Yan * In the following functions ndi_devi_enter() without holding the 69726947304SEvan Yan * parent dip is sufficient. This is because pci dr is driven through 69826947304SEvan Yan * opens on the nexus which is in the device tree path above the node 69926947304SEvan Yan * being operated on, and implicitly held due to the open. 70026947304SEvan Yan */ 70126947304SEvan Yan 70226947304SEvan Yan /* 70326947304SEvan Yan * This entry point is called to configure a device (and 70426947304SEvan Yan * all its children) on the given bus. It is called when 70526947304SEvan Yan * a new device is added to the PCI domain. This routine 70626947304SEvan Yan * will create the device tree and program the devices 70726947304SEvan Yan * registers. 70826947304SEvan Yan */ 70926947304SEvan Yan 71026947304SEvan Yan int 71126947304SEvan Yan pcicfg_configure(dev_info_t *devi, uint_t device, uint_t function, 71226947304SEvan Yan pcicfg_flags_t flags) 71326947304SEvan Yan { 71426947304SEvan Yan uint_t bus; 71526947304SEvan Yan int len; 71626947304SEvan Yan int func; 71726947304SEvan Yan int trans_device; 71826947304SEvan Yan dev_info_t *new_device; 71926947304SEvan Yan pcicfg_bus_range_t pci_bus_range; 72026947304SEvan Yan int rv; 72126947304SEvan Yan int circ; 72226947304SEvan Yan uint_t highest_bus = 0; 72326947304SEvan Yan int ari_mode = B_FALSE; 72426947304SEvan Yan int max_function = PCICFG_MAX_FUNCTION; 725c0da6274SZhi-Jun Robin Fu boolean_t is_pcie; 72626947304SEvan Yan 72726947304SEvan Yan if (flags == PCICFG_FLAG_ENABLE_ARI) 72826947304SEvan Yan return (pcicfg_ari_configure(devi)); 72926947304SEvan Yan 73026947304SEvan Yan /* 73126947304SEvan Yan * Start probing at the device specified in "device" on the 73226947304SEvan Yan * "bus" specified. 73326947304SEvan Yan */ 73426947304SEvan Yan len = sizeof (pcicfg_bus_range_t); 73526947304SEvan Yan if (ddi_getlongprop_buf(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS, 73626947304SEvan Yan "bus-range", (caddr_t)&pci_bus_range, &len) != DDI_SUCCESS) { 73726947304SEvan Yan DEBUG0("no bus-range property\n"); 73826947304SEvan Yan return (PCICFG_FAILURE); 73926947304SEvan Yan } 74026947304SEvan Yan 74126947304SEvan Yan bus = pci_bus_range.lo; /* primary bus number of this bus node */ 74226947304SEvan Yan 743c0da6274SZhi-Jun Robin Fu is_pcie = is_pcie_fabric(devi); 744c0da6274SZhi-Jun Robin Fu 74526947304SEvan Yan ndi_devi_enter(devi, &circ); 74626947304SEvan Yan for (func = 0; func < max_function; ) { 74726947304SEvan Yan if ((function != PCICFG_ALL_FUNC) && (function != func)) 74826947304SEvan Yan goto next; 74926947304SEvan Yan 75026947304SEvan Yan if (ari_mode) 75126947304SEvan Yan trans_device = func >> 3; 75226947304SEvan Yan else 75326947304SEvan Yan trans_device = device; 75426947304SEvan Yan 75526947304SEvan Yan DEBUG3("Configuring [0x%x][0x%x][0x%x]\n", 75626947304SEvan Yan bus, trans_device, func & 7); 75726947304SEvan Yan 75826947304SEvan Yan /* 75926947304SEvan Yan * Try executing fcode if available. 76026947304SEvan Yan */ 76126947304SEvan Yan switch (rv = pcicfg_fcode_probe(devi, bus, trans_device, 762c0da6274SZhi-Jun Robin Fu func & 7, &highest_bus, flags, is_pcie)) { 76326947304SEvan Yan case PCICFG_FAILURE: 76426947304SEvan Yan DEBUG2("configure failed: " 76526947304SEvan Yan "bus [0x%x] device [0x%x]\n", 76626947304SEvan Yan bus, trans_device); 76726947304SEvan Yan break; 76826947304SEvan Yan case PCICFG_NODEVICE: 76926947304SEvan Yan DEBUG3("no device : bus " 77026947304SEvan Yan "[0x%x] slot [0x%x] func [0x%x]\n", 77126947304SEvan Yan bus, trans_device, func & 7); 772*7f59ab1cSAlan Adamson, SD OSSD 773*7f59ab1cSAlan Adamson, SD OSSD /* 774*7f59ab1cSAlan Adamson, SD OSSD * When walking the list of ARI functions 775*7f59ab1cSAlan Adamson, SD OSSD * we don't expect to see a non-present 776*7f59ab1cSAlan Adamson, SD OSSD * function, so we will stop walking 777*7f59ab1cSAlan Adamson, SD OSSD * the function list. 778*7f59ab1cSAlan Adamson, SD OSSD */ 779*7f59ab1cSAlan Adamson, SD OSSD if (ari_mode == B_TRUE) 780*7f59ab1cSAlan Adamson, SD OSSD break; 781*7f59ab1cSAlan Adamson, SD OSSD 78226947304SEvan Yan if (func) 78326947304SEvan Yan goto next; 78426947304SEvan Yan break; 78526947304SEvan Yan default: 78626947304SEvan Yan DEBUG3("configure: bus => [%d] " 78726947304SEvan Yan "slot => [%d] func => [%d]\n", 78826947304SEvan Yan bus, trans_device, func & 7); 78926947304SEvan Yan break; 79026947304SEvan Yan } 79126947304SEvan Yan 79226947304SEvan Yan if (rv != PCICFG_SUCCESS) 79326947304SEvan Yan break; 79426947304SEvan Yan 79526947304SEvan Yan if ((new_device = pcicfg_devi_find(devi, 79626947304SEvan Yan trans_device, (func & 7))) == NULL) { 79726947304SEvan Yan DEBUG0("Did'nt find device node just created\n"); 79826947304SEvan Yan goto cleanup; 79926947304SEvan Yan } 80026947304SEvan Yan 80126947304SEvan Yan next: 80226947304SEvan Yan /* 80326947304SEvan Yan * Determine if ARI Forwarding should be enabled. 80426947304SEvan Yan */ 80526947304SEvan Yan if (func == 0) { 80626947304SEvan Yan if ((pcie_ari_supported(devi) 80726947304SEvan Yan == PCIE_ARI_FORW_SUPPORTED) && 80826947304SEvan Yan (pcie_ari_device(new_device) == PCIE_ARI_DEVICE)) { 80926947304SEvan Yan if (pcie_ari_enable(devi) == DDI_SUCCESS) { 81026947304SEvan Yan (void) ddi_prop_create(DDI_DEV_T_NONE, 81126947304SEvan Yan devi, DDI_PROP_CANSLEEP, 81226947304SEvan Yan "ari-enabled", NULL, 0); 81326947304SEvan Yan 81426947304SEvan Yan ari_mode = B_TRUE; 81526947304SEvan Yan max_function = PCICFG_MAX_ARI_FUNCTION; 81626947304SEvan Yan } 81726947304SEvan Yan } 81826947304SEvan Yan } 81926947304SEvan Yan 82026947304SEvan Yan if (ari_mode == B_TRUE) { 82126947304SEvan Yan int next_function; 82226947304SEvan Yan 82326947304SEvan Yan DEBUG0("Next Function - ARI Device\n"); 82426947304SEvan Yan if (pcie_ari_get_next_function(new_device, 82526947304SEvan Yan &next_function) != DDI_SUCCESS) 82626947304SEvan Yan goto cleanup; 82726947304SEvan Yan 82826947304SEvan Yan /* 82926947304SEvan Yan * Check if there are more fucntions to probe. 83026947304SEvan Yan */ 83126947304SEvan Yan if (next_function == 0) { 83226947304SEvan Yan DEBUG0("Next Function - " 83326947304SEvan Yan "No more ARI Functions\n"); 83426947304SEvan Yan break; 83526947304SEvan Yan } 83626947304SEvan Yan func = next_function; 83726947304SEvan Yan } else { 83826947304SEvan Yan func++; 83926947304SEvan Yan } 84026947304SEvan Yan 84126947304SEvan Yan DEBUG1("Next Function - %x\n", func); 84226947304SEvan Yan } 84326947304SEvan Yan 84426947304SEvan Yan ndi_devi_exit(devi, circ); 84526947304SEvan Yan 84626947304SEvan Yan if (func == 0) 84726947304SEvan Yan return (PCICFG_FAILURE); /* probe failed */ 84826947304SEvan Yan else 84926947304SEvan Yan return (PCICFG_SUCCESS); 85026947304SEvan Yan 85126947304SEvan Yan cleanup: 85226947304SEvan Yan /* 85326947304SEvan Yan * Clean up a partially created "probe state" tree. 85426947304SEvan Yan * There are no resources allocated to the in the 85526947304SEvan Yan * probe state. 85626947304SEvan Yan */ 85726947304SEvan Yan if (pcie_ari_is_enabled(devi) == PCIE_ARI_FORW_ENABLED) 85826947304SEvan Yan max_function = PCICFG_MAX_ARI_FUNCTION; 85926947304SEvan Yan else 86026947304SEvan Yan max_function = PCICFG_MAX_FUNCTION; 86126947304SEvan Yan 86226947304SEvan Yan for (func = 0; func < max_function; func++) { 86326947304SEvan Yan 86426947304SEvan Yan if (max_function == PCICFG_MAX_ARI_FUNCTION) 86526947304SEvan Yan trans_device = func >> 3; /* ARI Device */ 86626947304SEvan Yan else 86726947304SEvan Yan trans_device = device; 86826947304SEvan Yan 86926947304SEvan Yan if ((new_device = pcicfg_devi_find(devi, 87026947304SEvan Yan trans_device, (func & 0x7))) == NULL) { 87126947304SEvan Yan DEBUG0("No more devices to clean up\n"); 87226947304SEvan Yan continue; 87326947304SEvan Yan } 87426947304SEvan Yan 87526947304SEvan Yan DEBUG2("Cleaning up device [0x%x] function [0x%x]\n", 87626947304SEvan Yan trans_device, func & 7); 87726947304SEvan Yan /* 87826947304SEvan Yan * If this was a bridge device it will have a 87926947304SEvan Yan * probe handle - if not, no harm in calling this. 88026947304SEvan Yan */ 88126947304SEvan Yan (void) pcicfg_destroy_phdl(new_device); 882c0da6274SZhi-Jun Robin Fu 883c0da6274SZhi-Jun Robin Fu if (is_pcie) { 884c0da6274SZhi-Jun Robin Fu /* 885c0da6274SZhi-Jun Robin Fu * Free bus_t structure 886c0da6274SZhi-Jun Robin Fu */ 887c0da6274SZhi-Jun Robin Fu if (ddi_get_child(new_device) != NULL) 888c0da6274SZhi-Jun Robin Fu pcie_fab_fini_bus(new_device, PCIE_BUS_ALL); 889c0da6274SZhi-Jun Robin Fu 890c0da6274SZhi-Jun Robin Fu pcie_fini_bus(new_device, PCIE_BUS_ALL); 891c0da6274SZhi-Jun Robin Fu } 89226947304SEvan Yan /* 89326947304SEvan Yan * This will free up the node 89426947304SEvan Yan */ 89526947304SEvan Yan (void) ndi_devi_offline(new_device, NDI_DEVI_REMOVE); 89626947304SEvan Yan } 89726947304SEvan Yan ndi_devi_exit(devi, circ); 89826947304SEvan Yan 89926947304SEvan Yan return (PCICFG_FAILURE); 90026947304SEvan Yan } 90126947304SEvan Yan 90226947304SEvan Yan /* 90326947304SEvan Yan * configure the child nodes of ntbridge. new_device points to ntbridge itself 90426947304SEvan Yan */ 90526947304SEvan Yan /*ARGSUSED*/ 90626947304SEvan Yan static uint_t 90726947304SEvan Yan pcicfg_configure_ntbridge(dev_info_t *new_device, uint_t bus, uint_t device) 90826947304SEvan Yan { 90926947304SEvan Yan int bus_range[2], rc = PCICFG_FAILURE, rc1, max_devs = 0; 91026947304SEvan Yan int devno; 91126947304SEvan Yan dev_info_t *new_ntbridgechild; 91226947304SEvan Yan ddi_acc_handle_t config_handle; 91326947304SEvan Yan uint16_t vid; 91426947304SEvan Yan uint64_t next_bus; 91526947304SEvan Yan uint64_t blen; 91626947304SEvan Yan ndi_ra_request_t req; 91726947304SEvan Yan uint8_t pcie_device_type = 0; 91826947304SEvan Yan 91926947304SEvan Yan /* 92026947304SEvan Yan * If we need to do indirect config, lets create a property here 92126947304SEvan Yan * to let the child conf map routine know that it has to 92226947304SEvan Yan * go through the DDI calls, and not assume the devices are 92326947304SEvan Yan * mapped directly under the host. 92426947304SEvan Yan */ 92526947304SEvan Yan if ((rc = ndi_prop_update_int(DDI_DEV_T_NONE, new_device, 92626947304SEvan Yan PCI_DEV_CONF_MAP_PROP, (int)DDI_SUCCESS)) 92726947304SEvan Yan != DDI_SUCCESS) { 92826947304SEvan Yan 92926947304SEvan Yan DEBUG0("Cannot create indirect conf map property.\n"); 93026947304SEvan Yan return ((uint_t)PCICFG_FAILURE); 93126947304SEvan Yan } 93226947304SEvan Yan if (pci_config_setup(new_device, &config_handle) != DDI_SUCCESS) 93326947304SEvan Yan return ((uint_t)PCICFG_FAILURE); 93426947304SEvan Yan /* check if we are PCIe device */ 93526947304SEvan Yan if (pcicfg_pcie_device_type(new_device, config_handle) == DDI_SUCCESS) 93626947304SEvan Yan pcie_device_type = 1; 93726947304SEvan Yan pci_config_teardown(&config_handle); 93826947304SEvan Yan 93926947304SEvan Yan /* create Bus node properties for ntbridge. */ 94026947304SEvan Yan if (pcicfg_set_busnode_props(new_device, pcie_device_type, -1, -1) != 94126947304SEvan Yan PCICFG_SUCCESS) { 94226947304SEvan Yan DEBUG0("Failed to set busnode props\n"); 94326947304SEvan Yan return (rc); 94426947304SEvan Yan } 94526947304SEvan Yan 94626947304SEvan Yan /* For now: Lets only support one layer of child */ 94726947304SEvan Yan bzero((caddr_t)&req, sizeof (ndi_ra_request_t)); 94826947304SEvan Yan req.ra_len = 1; 94926947304SEvan Yan if (ndi_ra_alloc(ddi_get_parent(new_device), &req, 95026947304SEvan Yan &next_bus, &blen, NDI_RA_TYPE_PCI_BUSNUM, 95126947304SEvan Yan NDI_RA_PASS) != NDI_SUCCESS) { 95226947304SEvan Yan DEBUG0("ntbridge: Failed to get a bus number\n"); 95326947304SEvan Yan return (rc); 95426947304SEvan Yan } 95526947304SEvan Yan 95626947304SEvan Yan DEBUG1("ntbridge bus range start ->[%d]\n", next_bus); 95726947304SEvan Yan 95826947304SEvan Yan /* 95926947304SEvan Yan * Following will change, as we detect more bridges 96026947304SEvan Yan * on the way. 96126947304SEvan Yan */ 96226947304SEvan Yan bus_range[0] = (int)next_bus; 96326947304SEvan Yan bus_range[1] = (int)next_bus; 96426947304SEvan Yan 96526947304SEvan Yan if (ndi_prop_update_int_array(DDI_DEV_T_NONE, new_device, 96626947304SEvan Yan "bus-range", bus_range, 2) != DDI_SUCCESS) { 96726947304SEvan Yan DEBUG0("Cannot set ntbridge bus-range property"); 96826947304SEvan Yan return (rc); 96926947304SEvan Yan } 97026947304SEvan Yan 97126947304SEvan Yan /* 97226947304SEvan Yan * The other interface (away from the host) will be 97326947304SEvan Yan * initialized by the nexus driver when it loads. 97426947304SEvan Yan * We just have to set the registers and the nexus driver 97526947304SEvan Yan * figures out the rest. 97626947304SEvan Yan */ 97726947304SEvan Yan 97826947304SEvan Yan /* 97926947304SEvan Yan * finally, lets load and attach the driver 98026947304SEvan Yan * before configuring children of ntbridge. 98126947304SEvan Yan */ 98226947304SEvan Yan rc = ndi_devi_online(new_device, NDI_NO_EVENT|NDI_CONFIG); 98326947304SEvan Yan if (rc != NDI_SUCCESS) { 98426947304SEvan Yan cmn_err(CE_WARN, 98526947304SEvan Yan "pcicfg: Fail: can\'t load non-transparent bridge \ 98626947304SEvan Yan driver.\n"); 98726947304SEvan Yan rc = PCICFG_FAILURE; 98826947304SEvan Yan return (rc); 98926947304SEvan Yan } 99026947304SEvan Yan DEBUG0("pcicfg: Success loading nontransparent bridge nexus driver.."); 99126947304SEvan Yan 99226947304SEvan Yan /* Now set aside pci resources for our children. */ 99326947304SEvan Yan if (pcicfg_ntbridge_allocate_resources(new_device) != 99426947304SEvan Yan PCICFG_SUCCESS) { 99526947304SEvan Yan max_devs = 0; 99626947304SEvan Yan rc = PCICFG_FAILURE; 99726947304SEvan Yan } else 99826947304SEvan Yan max_devs = PCICFG_MAX_DEVICE; 99926947304SEvan Yan 100026947304SEvan Yan /* Probe devices on 2nd bus */ 100126947304SEvan Yan for (devno = pcicfg_start_devno; devno < max_devs; devno++) { 100226947304SEvan Yan 100326947304SEvan Yan if (ndi_devi_alloc(new_device, DEVI_PSEUDO_NEXNAME, 100426947304SEvan Yan (pnode_t)DEVI_SID_NODEID, &new_ntbridgechild) 100526947304SEvan Yan != NDI_SUCCESS) { 100626947304SEvan Yan 100726947304SEvan Yan DEBUG0("pcicfg: Failed to alloc test node\n"); 100826947304SEvan Yan rc = PCICFG_FAILURE; 100926947304SEvan Yan break; 101026947304SEvan Yan } 101126947304SEvan Yan 101226947304SEvan Yan if (pcicfg_add_config_reg(new_ntbridgechild, next_bus, devno, 0) 101326947304SEvan Yan != DDI_PROP_SUCCESS) { 101426947304SEvan Yan cmn_err(CE_WARN, 101526947304SEvan Yan "Failed to add conf reg for ntbridge child.\n"); 101626947304SEvan Yan (void) ndi_devi_free(new_ntbridgechild); 101726947304SEvan Yan rc = PCICFG_FAILURE; 101826947304SEvan Yan break; 101926947304SEvan Yan } 102026947304SEvan Yan 102126947304SEvan Yan if ((rc = pci_config_setup(new_ntbridgechild, 102226947304SEvan Yan &config_handle)) != PCICFG_SUCCESS) { 102326947304SEvan Yan cmn_err(CE_WARN, 102426947304SEvan Yan "Cannot map ntbridge child %x\n", devno); 102526947304SEvan Yan (void) ndi_devi_free(new_ntbridgechild); 102626947304SEvan Yan rc = PCICFG_FAILURE; 102726947304SEvan Yan break; 102826947304SEvan Yan } 102926947304SEvan Yan 103026947304SEvan Yan /* 103126947304SEvan Yan * See if there is any PCI HW at this location 103226947304SEvan Yan * by reading the Vendor ID. If it returns with 0xffff 103326947304SEvan Yan * then there is no hardware at this location. 103426947304SEvan Yan */ 103526947304SEvan Yan vid = pci_config_get16(config_handle, PCI_CONF_VENID); 103626947304SEvan Yan 103726947304SEvan Yan pci_config_teardown(&config_handle); 103826947304SEvan Yan (void) ndi_devi_free(new_ntbridgechild); 103926947304SEvan Yan if (vid == 0xffff) 104026947304SEvan Yan continue; 104126947304SEvan Yan 104226947304SEvan Yan /* Lets fake attachments points for each child, */ 104326947304SEvan Yan if (pcicfg_configure(new_device, devno, PCICFG_ALL_FUNC, 0) 104426947304SEvan Yan != PCICFG_SUCCESS) { 104526947304SEvan Yan int old_dev = pcicfg_start_devno; 104626947304SEvan Yan 104726947304SEvan Yan cmn_err(CE_WARN, 104826947304SEvan Yan "Error configuring ntbridge child dev=%d\n", devno); 104926947304SEvan Yan 105026947304SEvan Yan rc = PCICFG_FAILURE; 105126947304SEvan Yan while (old_dev != devno) { 105226947304SEvan Yan if (pcicfg_ntbridge_unconfigure_child( 105326947304SEvan Yan new_device, old_dev) == PCICFG_FAILURE) 105426947304SEvan Yan 105526947304SEvan Yan cmn_err(CE_WARN, 105626947304SEvan Yan "Unconfig Error ntbridge child " 105726947304SEvan Yan "dev=%d\n", old_dev); 105826947304SEvan Yan old_dev++; 105926947304SEvan Yan } 106026947304SEvan Yan break; 106126947304SEvan Yan } 106226947304SEvan Yan } /* devno loop */ 106326947304SEvan Yan DEBUG1("ntbridge: finish probing 2nd bus, rc=%d\n", rc); 106426947304SEvan Yan 106526947304SEvan Yan if (rc != PCICFG_FAILURE) 106626947304SEvan Yan rc = pcicfg_ntbridge_configure_done(new_device); 106726947304SEvan Yan else { 106826947304SEvan Yan pcicfg_phdl_t *entry = pcicfg_find_phdl(new_device); 106926947304SEvan Yan uint_t *bus; 107026947304SEvan Yan int k; 107126947304SEvan Yan 107226947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, new_device, 107326947304SEvan Yan DDI_PROP_DONTPASS, "bus-range", (caddr_t)&bus, 107426947304SEvan Yan &k) != DDI_PROP_SUCCESS) { 107526947304SEvan Yan DEBUG0("Failed to read bus-range property\n"); 107626947304SEvan Yan rc = PCICFG_FAILURE; 107726947304SEvan Yan return (rc); 107826947304SEvan Yan } 107926947304SEvan Yan 108026947304SEvan Yan DEBUG2("Need to free bus [%d] range [%d]\n", 108126947304SEvan Yan bus[0], bus[1] - bus[0] + 1); 108226947304SEvan Yan 108326947304SEvan Yan if (ndi_ra_free(ddi_get_parent(new_device), 108426947304SEvan Yan (uint64_t)bus[0], (uint64_t)(bus[1] - bus[0] + 1), 108526947304SEvan Yan NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS) != NDI_SUCCESS) { 108626947304SEvan Yan DEBUG0("Failed to free a bus number\n"); 108726947304SEvan Yan rc = PCICFG_FAILURE; 108826947304SEvan Yan /* 108926947304SEvan Yan * Don't forget to free up memory from ddi_getlongprop 109026947304SEvan Yan */ 109126947304SEvan Yan kmem_free((caddr_t)bus, k); 109226947304SEvan Yan 109326947304SEvan Yan return (rc); 109426947304SEvan Yan } 109526947304SEvan Yan 109626947304SEvan Yan /* 109726947304SEvan Yan * Since no memory allocations are done for non transparent 109826947304SEvan Yan * bridges (but instead we just set the handle with the 109926947304SEvan Yan * already allocated memory, we just need to reset the 110026947304SEvan Yan * following values before calling the destroy_phdl() 110126947304SEvan Yan * function next, otherwise the it will try to free 110226947304SEvan Yan * memory allocated as in case of a transparent bridge. 110326947304SEvan Yan */ 110426947304SEvan Yan entry->memory_len = 0; 110526947304SEvan Yan entry->io_len = 0; 110626947304SEvan Yan /* the following will free hole data. */ 110726947304SEvan Yan (void) pcicfg_destroy_phdl(new_device); 110826947304SEvan Yan /* 110926947304SEvan Yan * Don't forget to free up memory from ddi_getlongprop 111026947304SEvan Yan */ 111126947304SEvan Yan kmem_free((caddr_t)bus, k); 111226947304SEvan Yan } 111326947304SEvan Yan 111426947304SEvan Yan /* 111526947304SEvan Yan * Unload driver just in case child configure failed! 111626947304SEvan Yan */ 111726947304SEvan Yan rc1 = ndi_devi_offline(new_device, NDI_NO_EVENT); 111826947304SEvan Yan DEBUG1("pcicfg: now unloading the ntbridge driver. rc1=%d\n", rc1); 111926947304SEvan Yan if (rc1 != NDI_SUCCESS) { 112026947304SEvan Yan cmn_err(CE_WARN, 112126947304SEvan Yan "pcicfg: can\'t unload ntbridge driver children.\n"); 112226947304SEvan Yan rc = PCICFG_FAILURE; 112326947304SEvan Yan } 112426947304SEvan Yan 112526947304SEvan Yan return (rc); 112626947304SEvan Yan } 112726947304SEvan Yan 112826947304SEvan Yan static int 112926947304SEvan Yan pcicfg_ntbridge_allocate_resources(dev_info_t *dip) 113026947304SEvan Yan { 113126947304SEvan Yan pcicfg_phdl_t *phdl; 113226947304SEvan Yan ndi_ra_request_t *mem_request; 113326947304SEvan Yan ndi_ra_request_t *io_request; 113426947304SEvan Yan uint64_t boundbase, boundlen; 113526947304SEvan Yan 113626947304SEvan Yan phdl = pcicfg_find_phdl(dip); 113726947304SEvan Yan ASSERT(phdl); 113826947304SEvan Yan 113926947304SEvan Yan mem_request = &phdl->mem_req; 114026947304SEvan Yan io_request = &phdl->io_req; 114126947304SEvan Yan 114226947304SEvan Yan phdl->error = PCICFG_SUCCESS; 114326947304SEvan Yan 114426947304SEvan Yan /* Set Memory space handle for ntbridge */ 114526947304SEvan Yan if (pcicfg_get_ntbridge_child_range(dip, &boundbase, &boundlen, 114626947304SEvan Yan PCI_BASE_SPACE_MEM) != DDI_SUCCESS) { 114726947304SEvan Yan cmn_err(CE_WARN, 114826947304SEvan Yan "ntbridge: Mem resource information failure\n"); 114926947304SEvan Yan phdl->memory_len = 0; 115026947304SEvan Yan return (PCICFG_FAILURE); 115126947304SEvan Yan } 115226947304SEvan Yan mem_request->ra_boundbase = boundbase; 115326947304SEvan Yan mem_request->ra_boundlen = boundbase + boundlen; 115426947304SEvan Yan mem_request->ra_len = boundlen; 115526947304SEvan Yan mem_request->ra_align_mask = 115626947304SEvan Yan PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */ 115726947304SEvan Yan mem_request->ra_flags |= NDI_RA_ALLOC_BOUNDED; 115826947304SEvan Yan 115926947304SEvan Yan /* 116026947304SEvan Yan * mem_request->ra_len = 116126947304SEvan Yan * PCICFG_ROUND_UP(mem_request->ra_len, PCICFG_MEMGRAN); 116226947304SEvan Yan */ 116326947304SEvan Yan 116426947304SEvan Yan phdl->memory_base = phdl->memory_last = boundbase; 116526947304SEvan Yan phdl->memory_len = boundlen; 116626947304SEvan Yan phdl->mem_hole.start = phdl->memory_base; 116726947304SEvan Yan phdl->mem_hole.len = mem_request->ra_len; 116826947304SEvan Yan phdl->mem_hole.next = (hole_t *)NULL; 116926947304SEvan Yan 117026947304SEvan Yan DEBUG2("Connector requested [0x%llx], needs [0x%llx] bytes of memory\n", 117126947304SEvan Yan boundlen, mem_request->ra_len); 117226947304SEvan Yan 117326947304SEvan Yan /* set up a memory resource map for NT bridge */ 117426947304SEvan Yan if (ndi_ra_map_setup(dip, NDI_RA_TYPE_MEM) == NDI_FAILURE) { 117526947304SEvan Yan DEBUG0("Can not setup ntbridge memory resource map\n"); 117626947304SEvan Yan return (PCICFG_FAILURE); 117726947304SEvan Yan } 117826947304SEvan Yan /* initialize the memory map */ 117926947304SEvan Yan if (ndi_ra_free(dip, boundbase, boundlen, NDI_RA_TYPE_MEM, 118026947304SEvan Yan NDI_RA_PASS) != NDI_SUCCESS) { 118126947304SEvan Yan DEBUG0("Can not initalize ntbridge memory resource map\n"); 118226947304SEvan Yan return (PCICFG_FAILURE); 118326947304SEvan Yan } 118426947304SEvan Yan /* Set IO space handle for ntbridge */ 118526947304SEvan Yan if (pcicfg_get_ntbridge_child_range(dip, &boundbase, &boundlen, 118626947304SEvan Yan PCI_BASE_SPACE_IO) != DDI_SUCCESS) { 118726947304SEvan Yan cmn_err(CE_WARN, "ntbridge: IO resource information failure\n"); 118826947304SEvan Yan phdl->io_len = 0; 118926947304SEvan Yan return (PCICFG_FAILURE); 119026947304SEvan Yan } 119126947304SEvan Yan io_request->ra_len = boundlen; 119226947304SEvan Yan io_request->ra_align_mask = 119326947304SEvan Yan PCICFG_IOGRAN - 1; /* 4K alignment on I/O space */ 119426947304SEvan Yan io_request->ra_boundbase = boundbase; 119526947304SEvan Yan io_request->ra_boundlen = boundbase + boundlen; 119626947304SEvan Yan io_request->ra_flags |= NDI_RA_ALLOC_BOUNDED; 119726947304SEvan Yan 119826947304SEvan Yan /* 119926947304SEvan Yan * io_request->ra_len = 120026947304SEvan Yan * PCICFG_ROUND_UP(io_request->ra_len, PCICFG_IOGRAN); 120126947304SEvan Yan */ 120226947304SEvan Yan 120326947304SEvan Yan phdl->io_base = phdl->io_last = (uint32_t)boundbase; 120426947304SEvan Yan phdl->io_len = (uint32_t)boundlen; 120526947304SEvan Yan phdl->io_hole.start = phdl->io_base; 120626947304SEvan Yan phdl->io_hole.len = io_request->ra_len; 120726947304SEvan Yan phdl->io_hole.next = (hole_t *)NULL; 120826947304SEvan Yan 120926947304SEvan Yan DEBUG2("Connector requested [0x%llx], needs [0x%llx] bytes of IO\n", 121026947304SEvan Yan boundlen, io_request->ra_len); 121126947304SEvan Yan 121226947304SEvan Yan DEBUG2("MEMORY BASE = [0x%x] length [0x%x]\n", 121326947304SEvan Yan phdl->memory_base, phdl->memory_len); 121426947304SEvan Yan DEBUG2("IO BASE = [0x%x] length [0x%x]\n", 121526947304SEvan Yan phdl->io_base, phdl->io_len); 121626947304SEvan Yan 121726947304SEvan Yan /* set up a IO resource map for NT bridge */ 121826947304SEvan Yan if (ndi_ra_map_setup(dip, NDI_RA_TYPE_IO) == NDI_FAILURE) { 121926947304SEvan Yan DEBUG0("Can not setup ntbridge memory resource map\n"); 122026947304SEvan Yan return (PCICFG_FAILURE); 122126947304SEvan Yan } 122226947304SEvan Yan /* initialize the IO map */ 122326947304SEvan Yan if (ndi_ra_free(dip, boundbase, boundlen, NDI_RA_TYPE_IO, 122426947304SEvan Yan NDI_RA_PASS) != NDI_SUCCESS) { 122526947304SEvan Yan DEBUG0("Can not initalize ntbridge memory resource map\n"); 122626947304SEvan Yan return (PCICFG_FAILURE); 122726947304SEvan Yan } 122826947304SEvan Yan 122926947304SEvan Yan return (PCICFG_SUCCESS); 123026947304SEvan Yan } 123126947304SEvan Yan 123226947304SEvan Yan static int 123326947304SEvan Yan pcicfg_ntbridge_configure_done(dev_info_t *dip) 123426947304SEvan Yan { 123526947304SEvan Yan pcicfg_range_t range[PCICFG_RANGE_LEN]; 123626947304SEvan Yan pcicfg_phdl_t *entry; 123726947304SEvan Yan uint_t len; 123826947304SEvan Yan pcicfg_bus_range_t bus_range; 123926947304SEvan Yan int new_bus_range[2]; 124026947304SEvan Yan 124126947304SEvan Yan DEBUG1("Configuring children for %llx\n", dip); 124226947304SEvan Yan 124326947304SEvan Yan entry = pcicfg_find_phdl(dip); 124426947304SEvan Yan ASSERT(entry); 124526947304SEvan Yan 124626947304SEvan Yan bzero((caddr_t)range, 124726947304SEvan Yan sizeof (pcicfg_range_t) * PCICFG_RANGE_LEN); 124826947304SEvan Yan range[1].child_hi = range[1].parent_hi |= 124926947304SEvan Yan (PCI_REG_REL_M | PCI_ADDR_MEM32); 125026947304SEvan Yan range[1].child_lo = range[1].parent_lo = (uint32_t)entry->memory_base; 125126947304SEvan Yan 125226947304SEvan Yan range[0].child_hi = range[0].parent_hi |= 125326947304SEvan Yan (PCI_REG_REL_M | PCI_ADDR_IO); 125426947304SEvan Yan range[0].child_lo = range[0].parent_lo = (uint32_t)entry->io_base; 125526947304SEvan Yan 125626947304SEvan Yan len = sizeof (pcicfg_bus_range_t); 125726947304SEvan Yan if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 125826947304SEvan Yan "bus-range", (caddr_t)&bus_range, (int *)&len) != DDI_SUCCESS) { 125926947304SEvan Yan DEBUG0("no bus-range property\n"); 126026947304SEvan Yan return (PCICFG_FAILURE); 126126947304SEvan Yan } 126226947304SEvan Yan 126326947304SEvan Yan new_bus_range[0] = bus_range.lo; /* primary bus number */ 126426947304SEvan Yan if (entry->highest_bus) { /* secondary bus number */ 126526947304SEvan Yan if (entry->highest_bus < bus_range.lo) { 126626947304SEvan Yan cmn_err(CE_WARN, 126726947304SEvan Yan "ntbridge bus range invalid !(%d,%d)\n", 126826947304SEvan Yan bus_range.lo, entry->highest_bus); 126926947304SEvan Yan new_bus_range[1] = bus_range.lo + entry->highest_bus; 127026947304SEvan Yan } 127126947304SEvan Yan else 127226947304SEvan Yan new_bus_range[1] = entry->highest_bus; 127326947304SEvan Yan } 127426947304SEvan Yan else 127526947304SEvan Yan new_bus_range[1] = bus_range.hi; 127626947304SEvan Yan 127726947304SEvan Yan DEBUG2("ntbridge: bus range lo=%x, hi=%x\n", 127826947304SEvan Yan new_bus_range[0], new_bus_range[1]); 127926947304SEvan Yan 128026947304SEvan Yan if (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, 128126947304SEvan Yan "bus-range", new_bus_range, 2) != DDI_SUCCESS) { 128226947304SEvan Yan DEBUG0("Failed to set bus-range property"); 128326947304SEvan Yan entry->error = PCICFG_FAILURE; 128426947304SEvan Yan return (PCICFG_FAILURE); 128526947304SEvan Yan } 128626947304SEvan Yan 128726947304SEvan Yan #ifdef DEBUG 128826947304SEvan Yan { 128926947304SEvan Yan uint64_t unused; 129026947304SEvan Yan unused = pcicfg_unused_space(&entry->io_hole, &len); 129126947304SEvan Yan DEBUG2("ntbridge: Unused IO space %llx bytes over %d holes\n", 129226947304SEvan Yan unused, len); 129326947304SEvan Yan } 129426947304SEvan Yan #endif 129526947304SEvan Yan 129626947304SEvan Yan range[0].size_lo = entry->io_len; 129726947304SEvan Yan if (pcicfg_update_ranges_prop(dip, &range[0])) { 129826947304SEvan Yan DEBUG0("Failed to update ranges (i/o)\n"); 129926947304SEvan Yan entry->error = PCICFG_FAILURE; 130026947304SEvan Yan return (PCICFG_FAILURE); 130126947304SEvan Yan } 130226947304SEvan Yan 130326947304SEvan Yan #ifdef DEBUG 130426947304SEvan Yan { 130526947304SEvan Yan uint64_t unused; 130626947304SEvan Yan unused = pcicfg_unused_space(&entry->mem_hole, &len); 130726947304SEvan Yan DEBUG2("ntbridge: Unused Mem space %llx bytes over %d holes\n", 130826947304SEvan Yan unused, len); 130926947304SEvan Yan } 131026947304SEvan Yan #endif 131126947304SEvan Yan 131226947304SEvan Yan range[1].size_lo = entry->memory_len; 131326947304SEvan Yan if (pcicfg_update_ranges_prop(dip, &range[1])) { 131426947304SEvan Yan DEBUG0("Failed to update ranges (memory)\n"); 131526947304SEvan Yan entry->error = PCICFG_FAILURE; 131626947304SEvan Yan return (PCICFG_FAILURE); 131726947304SEvan Yan } 131826947304SEvan Yan 131926947304SEvan Yan return (PCICFG_SUCCESS); 132026947304SEvan Yan } 132126947304SEvan Yan 132226947304SEvan Yan static int 132326947304SEvan Yan pcicfg_ntbridge_unconfigure_child(dev_info_t *new_device, uint_t devno) 132426947304SEvan Yan { 132526947304SEvan Yan 132626947304SEvan Yan dev_info_t *new_ntbridgechild; 132726947304SEvan Yan int len, bus; 132826947304SEvan Yan uint16_t vid; 132926947304SEvan Yan ddi_acc_handle_t config_handle; 133026947304SEvan Yan pcicfg_bus_range_t pci_bus_range; 133126947304SEvan Yan 133226947304SEvan Yan len = sizeof (pcicfg_bus_range_t); 133326947304SEvan Yan if (ddi_getlongprop_buf(DDI_DEV_T_ANY, new_device, DDI_PROP_DONTPASS, 133426947304SEvan Yan "bus-range", (caddr_t)&pci_bus_range, &len) != DDI_SUCCESS) { 133526947304SEvan Yan DEBUG0("no bus-range property\n"); 133626947304SEvan Yan return (PCICFG_FAILURE); 133726947304SEvan Yan } 133826947304SEvan Yan 133926947304SEvan Yan bus = pci_bus_range.lo; /* primary bus number of this bus node */ 134026947304SEvan Yan 134126947304SEvan Yan if (ndi_devi_alloc(new_device, DEVI_PSEUDO_NEXNAME, 134226947304SEvan Yan (pnode_t)DEVI_SID_NODEID, &new_ntbridgechild) != NDI_SUCCESS) { 134326947304SEvan Yan 134426947304SEvan Yan DEBUG0("pcicfg: Failed to alloc test node\n"); 134526947304SEvan Yan return (PCICFG_FAILURE); 134626947304SEvan Yan } 134726947304SEvan Yan 134826947304SEvan Yan if (pcicfg_add_config_reg(new_ntbridgechild, bus, devno, 0) 134926947304SEvan Yan != DDI_PROP_SUCCESS) { 135026947304SEvan Yan cmn_err(CE_WARN, 135126947304SEvan Yan "Unconfigure: Failed to add conf reg prop for ntbridge " 135226947304SEvan Yan "child.\n"); 135326947304SEvan Yan (void) ndi_devi_free(new_ntbridgechild); 135426947304SEvan Yan return (PCICFG_FAILURE); 135526947304SEvan Yan } 135626947304SEvan Yan 135726947304SEvan Yan if (pcicfg_config_setup(new_ntbridgechild, &config_handle) 135826947304SEvan Yan != DDI_SUCCESS) { 135926947304SEvan Yan cmn_err(CE_WARN, 136026947304SEvan Yan "pcicfg: Cannot map ntbridge child %x\n", devno); 136126947304SEvan Yan (void) ndi_devi_free(new_ntbridgechild); 136226947304SEvan Yan return (PCICFG_FAILURE); 136326947304SEvan Yan } 136426947304SEvan Yan 136526947304SEvan Yan /* 136626947304SEvan Yan * See if there is any PCI HW at this location 136726947304SEvan Yan * by reading the Vendor ID. If it returns with 0xffff 136826947304SEvan Yan * then there is no hardware at this location. 136926947304SEvan Yan */ 137026947304SEvan Yan vid = pci_config_get16(config_handle, PCI_CONF_VENID); 137126947304SEvan Yan 137226947304SEvan Yan pci_config_teardown(&config_handle); 137326947304SEvan Yan (void) ndi_devi_free(new_ntbridgechild); 137426947304SEvan Yan if (vid == 0xffff) 137526947304SEvan Yan return (PCICFG_NODEVICE); 137626947304SEvan Yan 137726947304SEvan Yan return (pcicfg_unconfigure(new_device, devno, PCICFG_ALL_FUNC, 0)); 137826947304SEvan Yan } 137926947304SEvan Yan 138026947304SEvan Yan static int 138126947304SEvan Yan pcicfg_ntbridge_unconfigure(dev_info_t *dip) 138226947304SEvan Yan { 138326947304SEvan Yan pcicfg_phdl_t *entry = pcicfg_find_phdl(dip); 138426947304SEvan Yan uint_t *bus; 138526947304SEvan Yan int k, rc = PCICFG_FAILURE; 138626947304SEvan Yan 138726947304SEvan Yan if (entry->memory_len) 138826947304SEvan Yan if (ndi_ra_map_destroy(dip, NDI_RA_TYPE_MEM) == NDI_FAILURE) { 138926947304SEvan Yan DEBUG1("cannot destroy ntbridge memory map size=%x\n", 139026947304SEvan Yan entry->memory_len); 139126947304SEvan Yan return (PCICFG_FAILURE); 139226947304SEvan Yan } 139326947304SEvan Yan if (entry->io_len) 139426947304SEvan Yan if (ndi_ra_map_destroy(dip, NDI_RA_TYPE_IO) == NDI_FAILURE) { 139526947304SEvan Yan DEBUG1("cannot destroy ntbridge io map size=%x\n", 139626947304SEvan Yan entry->io_len); 139726947304SEvan Yan return (PCICFG_FAILURE); 139826947304SEvan Yan } 139926947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 140026947304SEvan Yan DDI_PROP_DONTPASS, "bus-range", (caddr_t)&bus, 140126947304SEvan Yan &k) != DDI_PROP_SUCCESS) { 140226947304SEvan Yan DEBUG0("ntbridge: Failed to read bus-range property\n"); 140326947304SEvan Yan return (rc); 140426947304SEvan Yan } 140526947304SEvan Yan 140626947304SEvan Yan DEBUG2("ntbridge: Need to free bus [%d] range [%d]\n", 140726947304SEvan Yan bus[0], bus[1] - bus[0] + 1); 140826947304SEvan Yan 140926947304SEvan Yan if (ndi_ra_free(ddi_get_parent(dip), 141026947304SEvan Yan (uint64_t)bus[0], (uint64_t)(bus[1] - bus[0] + 1), 141126947304SEvan Yan NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS) != NDI_SUCCESS) { 141226947304SEvan Yan DEBUG0("ntbridge: Failed to free a bus number\n"); 141326947304SEvan Yan /* 141426947304SEvan Yan * Don't forget to free up memory from ddi_getlongprop 141526947304SEvan Yan */ 141626947304SEvan Yan kmem_free((caddr_t)bus, k); 141726947304SEvan Yan 141826947304SEvan Yan return (rc); 141926947304SEvan Yan } 142026947304SEvan Yan 142126947304SEvan Yan /* 142226947304SEvan Yan * Don't forget to free up memory from ddi_getlongprop 142326947304SEvan Yan */ 142426947304SEvan Yan kmem_free((caddr_t)bus, k); 142526947304SEvan Yan 142626947304SEvan Yan /* 142726947304SEvan Yan * Since our resources will be freed at the parent level, 142826947304SEvan Yan * just reset these values. 142926947304SEvan Yan */ 143026947304SEvan Yan entry->memory_len = 0; 143126947304SEvan Yan entry->io_len = 0; 143226947304SEvan Yan /* the following will also free hole data. */ 143326947304SEvan Yan return (pcicfg_destroy_phdl(dip)); 143426947304SEvan Yan 143526947304SEvan Yan } 143626947304SEvan Yan 143726947304SEvan Yan static int 143826947304SEvan Yan pcicfg_is_ntbridge(dev_info_t *dip) 143926947304SEvan Yan { 144026947304SEvan Yan ddi_acc_handle_t config_handle; 144126947304SEvan Yan uint8_t class, subclass; 144226947304SEvan Yan int rc = DDI_SUCCESS; 144326947304SEvan Yan 144426947304SEvan Yan if (pcicfg_config_setup(dip, &config_handle) != DDI_SUCCESS) { 144526947304SEvan Yan cmn_err(CE_WARN, 144626947304SEvan Yan "pcicfg: cannot map config space, to get map type\n"); 144726947304SEvan Yan return (DDI_FAILURE); 144826947304SEvan Yan } 144926947304SEvan Yan class = pci_config_get8(config_handle, PCI_CONF_BASCLASS); 145026947304SEvan Yan subclass = pci_config_get8(config_handle, PCI_CONF_SUBCLASS); 145126947304SEvan Yan 145226947304SEvan Yan /* check for class=6, subclass=9, for non transparent bridges. */ 145326947304SEvan Yan if ((class != PCI_CLASS_BRIDGE) || (subclass != PCI_BRIDGE_STBRIDGE)) 145426947304SEvan Yan rc = DDI_FAILURE; 145526947304SEvan Yan 145626947304SEvan Yan DEBUG3("pcicfg: checking device %x,%x for indirect map. rc=%d\n", 145726947304SEvan Yan pci_config_get16(config_handle, PCI_CONF_VENID), 145826947304SEvan Yan pci_config_get16(config_handle, PCI_CONF_DEVID), 145926947304SEvan Yan rc); 146026947304SEvan Yan pci_config_teardown(&config_handle); 146126947304SEvan Yan return (rc); 146226947304SEvan Yan } 146326947304SEvan Yan 146426947304SEvan Yan /* 146526947304SEvan Yan * this function is called only for SPARC platforms, where we may have 146626947304SEvan Yan * a mix n' match of direct vs indirectly mapped configuration space. 146726947304SEvan Yan * On x86, this function does not get called. We always return TRUE 146826947304SEvan Yan * via a macro for x86. 146926947304SEvan Yan */ 147026947304SEvan Yan /*ARGSUSED*/ 147126947304SEvan Yan static int 147226947304SEvan Yan pcicfg_indirect_map(dev_info_t *dip) 147326947304SEvan Yan { 147426947304SEvan Yan #if defined(__sparc) 147526947304SEvan Yan int rc = DDI_FAILURE; 147626947304SEvan Yan 147726947304SEvan Yan if (ddi_prop_get_int(DDI_DEV_T_ANY, ddi_get_parent(dip), 0, 147826947304SEvan Yan PCI_DEV_CONF_MAP_PROP, DDI_FAILURE) != DDI_FAILURE) 147926947304SEvan Yan rc = DDI_SUCCESS; 148026947304SEvan Yan else 148126947304SEvan Yan if (ddi_prop_get_int(DDI_DEV_T_ANY, ddi_get_parent(dip), 148226947304SEvan Yan 0, PCI_BUS_CONF_MAP_PROP, 148326947304SEvan Yan DDI_FAILURE) != DDI_FAILURE) 148426947304SEvan Yan rc = DDI_SUCCESS; 148526947304SEvan Yan DEBUG1("pci conf map = %d", rc); 148626947304SEvan Yan return (rc); 148726947304SEvan Yan #else 148826947304SEvan Yan return (DDI_SUCCESS); 148926947304SEvan Yan #endif 149026947304SEvan Yan } 149126947304SEvan Yan 149226947304SEvan Yan static uint_t 149326947304SEvan Yan pcicfg_get_ntbridge_child_range(dev_info_t *dip, uint64_t *boundbase, 149426947304SEvan Yan uint64_t *boundlen, uint_t space_type) 149526947304SEvan Yan { 149626947304SEvan Yan int length, found = DDI_FAILURE, acount, i, ibridge; 149726947304SEvan Yan pci_regspec_t *assigned; 149826947304SEvan Yan 149926947304SEvan Yan if ((ibridge = pcicfg_is_ntbridge(dip)) == DDI_FAILURE) 150026947304SEvan Yan return (found); 150126947304SEvan Yan 150226947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 150326947304SEvan Yan DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned, 150426947304SEvan Yan &length) != DDI_PROP_SUCCESS) { 150526947304SEvan Yan DEBUG1("Failed to get assigned-addresses property %llx\n", dip); 150626947304SEvan Yan return (found); 150726947304SEvan Yan } 150826947304SEvan Yan DEBUG1("pcicfg: ntbridge child range: dip = %s\n", 150926947304SEvan Yan ddi_driver_name(dip)); 151026947304SEvan Yan 151126947304SEvan Yan acount = length / sizeof (pci_regspec_t); 151226947304SEvan Yan 151326947304SEvan Yan for (i = 0; i < acount; i++) { 151426947304SEvan Yan if ((PCI_REG_REG_G(assigned[i].pci_phys_hi) == 151526947304SEvan Yan pcicfg_indirect_map_devs[ibridge].mem_range_bar_offset) && 151626947304SEvan Yan (space_type == PCI_BASE_SPACE_MEM)) { 151726947304SEvan Yan found = DDI_SUCCESS; 151826947304SEvan Yan break; 151926947304SEvan Yan } else { 152026947304SEvan Yan if ((PCI_REG_REG_G(assigned[i].pci_phys_hi) == 152126947304SEvan Yan pcicfg_indirect_map_devs[ibridge].\ 152226947304SEvan Yan io_range_bar_offset) && 152326947304SEvan Yan (space_type == PCI_BASE_SPACE_IO)) { 152426947304SEvan Yan found = DDI_SUCCESS; 152526947304SEvan Yan break; 152626947304SEvan Yan } 152726947304SEvan Yan } 152826947304SEvan Yan } 152926947304SEvan Yan DEBUG3("pcicfg: ntbridge child range: space=%x, base=%lx, len=%lx\n", 153026947304SEvan Yan space_type, assigned[i].pci_phys_low, assigned[i].pci_size_low); 153126947304SEvan Yan 153226947304SEvan Yan if (found == DDI_SUCCESS) { 153326947304SEvan Yan *boundbase = assigned[i].pci_phys_low; 153426947304SEvan Yan *boundlen = assigned[i].pci_size_low; 153526947304SEvan Yan } 153626947304SEvan Yan 153726947304SEvan Yan kmem_free(assigned, length); 153826947304SEvan Yan return (found); 153926947304SEvan Yan } 154026947304SEvan Yan 154126947304SEvan Yan /* 154226947304SEvan Yan * This will turn resources allocated by pcicfg_configure() 154326947304SEvan Yan * and remove the device tree from the Hotplug Connection (CN) 154426947304SEvan Yan * and below. The routine assumes the devices have their 154526947304SEvan Yan * drivers detached. 154626947304SEvan Yan */ 154726947304SEvan Yan int 154826947304SEvan Yan pcicfg_unconfigure(dev_info_t *devi, uint_t device, uint_t function, 154926947304SEvan Yan pcicfg_flags_t flags) 155026947304SEvan Yan { 155126947304SEvan Yan dev_info_t *child_dip; 155226947304SEvan Yan int func; 155326947304SEvan Yan int i; 155426947304SEvan Yan int max_function; 155526947304SEvan Yan int trans_device; 1556c0da6274SZhi-Jun Robin Fu int circ; 1557c0da6274SZhi-Jun Robin Fu boolean_t is_pcie; 155826947304SEvan Yan 155926947304SEvan Yan if (pcie_ari_is_enabled(devi) == PCIE_ARI_FORW_ENABLED) 156026947304SEvan Yan max_function = PCICFG_MAX_ARI_FUNCTION; 156126947304SEvan Yan else 156226947304SEvan Yan max_function = PCICFG_MAX_FUNCTION; 156326947304SEvan Yan 156426947304SEvan Yan /* 156526947304SEvan Yan * Cycle through devices to make sure none are busy. 156626947304SEvan Yan * If a single device is busy fail the whole unconfigure. 156726947304SEvan Yan */ 1568c0da6274SZhi-Jun Robin Fu is_pcie = is_pcie_fabric(devi); 1569c0da6274SZhi-Jun Robin Fu 1570c0da6274SZhi-Jun Robin Fu ndi_devi_enter(devi, &circ); 157126947304SEvan Yan for (func = 0; func < max_function; func++) { 157226947304SEvan Yan 157326947304SEvan Yan if (max_function == PCICFG_MAX_ARI_FUNCTION) 157426947304SEvan Yan trans_device = func >> 3; /* ARI Device */ 157526947304SEvan Yan else 157626947304SEvan Yan trans_device = device; 157726947304SEvan Yan 157826947304SEvan Yan if ((child_dip = pcicfg_devi_find(devi, trans_device, 157926947304SEvan Yan (func & 0x7))) == NULL) 158026947304SEvan Yan continue; 158126947304SEvan Yan 158226947304SEvan Yan if (ndi_devi_offline(child_dip, NDI_UNCONFIG) == NDI_SUCCESS) 158326947304SEvan Yan continue; 158426947304SEvan Yan /* 158526947304SEvan Yan * Device function is busy. Before returning we have to 158626947304SEvan Yan * put all functions back online which were taken 158726947304SEvan Yan * offline during the process. 158826947304SEvan Yan */ 158926947304SEvan Yan DEBUG2("Device [0x%x] function [%x] is busy\n", device, func); 159026947304SEvan Yan /* 159126947304SEvan Yan * If we are only asked to offline one specific function, 159226947304SEvan Yan * and that fails, we just simply return. 159326947304SEvan Yan */ 159426947304SEvan Yan if (function != PCICFG_ALL_FUNC) 159526947304SEvan Yan return (PCICFG_FAILURE); 159626947304SEvan Yan 159726947304SEvan Yan for (i = 0; i < func; i++) { 159826947304SEvan Yan 159926947304SEvan Yan if (max_function == PCICFG_MAX_ARI_FUNCTION) 160026947304SEvan Yan trans_device = i >> 3; 160126947304SEvan Yan 160226947304SEvan Yan if ((child_dip = 160326947304SEvan Yan pcicfg_devi_find(devi, trans_device, (i & 7))) 160426947304SEvan Yan == NULL) { 160526947304SEvan Yan DEBUG0( 160626947304SEvan Yan "No more devices to put back on line!!\n"); 160726947304SEvan Yan /* 160826947304SEvan Yan * Made it through all functions 160926947304SEvan Yan */ 161026947304SEvan Yan continue; 161126947304SEvan Yan } 161226947304SEvan Yan if (ndi_devi_online(child_dip, NDI_CONFIG) 161326947304SEvan Yan != NDI_SUCCESS) { 161426947304SEvan Yan DEBUG0("Failed to put back devices state\n"); 1615c0da6274SZhi-Jun Robin Fu goto fail; 161626947304SEvan Yan } 161726947304SEvan Yan } 1618c0da6274SZhi-Jun Robin Fu goto fail; 161926947304SEvan Yan } 162026947304SEvan Yan 162126947304SEvan Yan /* 162226947304SEvan Yan * Now, tear down all devinfo nodes for this Connector. 162326947304SEvan Yan */ 162426947304SEvan Yan for (func = 0; func < max_function; func++) { 162526947304SEvan Yan 162626947304SEvan Yan if (max_function == PCICFG_MAX_ARI_FUNCTION) 162726947304SEvan Yan trans_device = func >> 3; /* ARI Device */ 162826947304SEvan Yan else 162926947304SEvan Yan trans_device = device; 163026947304SEvan Yan 163126947304SEvan Yan if ((child_dip = pcicfg_devi_find(devi, 163226947304SEvan Yan trans_device, (func & 7))) == NULL) { 163326947304SEvan Yan DEBUG0("No more devices to tear down!\n"); 163426947304SEvan Yan continue; 163526947304SEvan Yan } 163626947304SEvan Yan 163726947304SEvan Yan DEBUG2("Tearing down device [0x%x] function [0x%x]\n", 163826947304SEvan Yan trans_device, (func & 7)); 163926947304SEvan Yan 164026947304SEvan Yan if (pcicfg_is_ntbridge(child_dip) != DDI_FAILURE) 164126947304SEvan Yan if (pcicfg_ntbridge_unconfigure(child_dip) != 164226947304SEvan Yan PCICFG_SUCCESS) { 164326947304SEvan Yan cmn_err(CE_WARN, 164426947304SEvan Yan "ntbridge: unconfigure failed\n"); 1645c0da6274SZhi-Jun Robin Fu goto fail; 164626947304SEvan Yan } 164726947304SEvan Yan 1648c0da6274SZhi-Jun Robin Fu if (pcicfg_teardown_device(child_dip, flags, is_pcie) 164926947304SEvan Yan != PCICFG_SUCCESS) { 165026947304SEvan Yan DEBUG2("Failed to tear down device [0x%x]" 165126947304SEvan Yan "function [0x%x]\n", 165226947304SEvan Yan trans_device, func & 7); 1653c0da6274SZhi-Jun Robin Fu goto fail; 165426947304SEvan Yan } 165526947304SEvan Yan } 165626947304SEvan Yan 165726947304SEvan Yan if (pcie_ari_is_enabled(devi) == PCIE_ARI_FORW_ENABLED) { 165826947304SEvan Yan (void) ddi_prop_remove(DDI_DEV_T_NONE, devi, "ari-enabled"); 165926947304SEvan Yan (void) pcie_ari_disable(devi); 166026947304SEvan Yan } 166126947304SEvan Yan 1662c0da6274SZhi-Jun Robin Fu ndi_devi_exit(devi, circ); 166326947304SEvan Yan return (PCICFG_SUCCESS); 1664c0da6274SZhi-Jun Robin Fu 1665c0da6274SZhi-Jun Robin Fu fail: 1666c0da6274SZhi-Jun Robin Fu ndi_devi_exit(devi, circ); 1667c0da6274SZhi-Jun Robin Fu return (PCICFG_FAILURE); 166826947304SEvan Yan } 166926947304SEvan Yan 167026947304SEvan Yan static int 1671c0da6274SZhi-Jun Robin Fu pcicfg_teardown_device(dev_info_t *dip, pcicfg_flags_t flags, boolean_t is_pcie) 167226947304SEvan Yan { 167326947304SEvan Yan ddi_acc_handle_t config_handle; 167426947304SEvan Yan 167526947304SEvan Yan /* 167626947304SEvan Yan * Free up resources associated with 'dip' 167726947304SEvan Yan */ 167826947304SEvan Yan if (pcicfg_free_resources(dip, flags) != PCICFG_SUCCESS) { 167926947304SEvan Yan DEBUG0("Failed to free resources\n"); 168026947304SEvan Yan return (PCICFG_FAILURE); 168126947304SEvan Yan } 168226947304SEvan Yan 168326947304SEvan Yan /* 168426947304SEvan Yan * This will disable the device 168526947304SEvan Yan */ 168626947304SEvan Yan if (pci_config_setup(dip, &config_handle) != PCICFG_SUCCESS) { 168726947304SEvan Yan return (PCICFG_FAILURE); 168826947304SEvan Yan } 168926947304SEvan Yan 169026947304SEvan Yan pcicfg_device_off(config_handle); 169126947304SEvan Yan pci_config_teardown(&config_handle); 169226947304SEvan Yan 169326947304SEvan Yan /* 1694c0da6274SZhi-Jun Robin Fu * free pcie_bus_t for the sub-tree 1695c0da6274SZhi-Jun Robin Fu */ 1696c0da6274SZhi-Jun Robin Fu if (is_pcie) { 1697c0da6274SZhi-Jun Robin Fu if (ddi_get_child(dip) != NULL) 1698c0da6274SZhi-Jun Robin Fu pcie_fab_fini_bus(dip, PCIE_BUS_ALL); 1699c0da6274SZhi-Jun Robin Fu 1700c0da6274SZhi-Jun Robin Fu pcie_fini_bus(dip, PCIE_BUS_ALL); 1701c0da6274SZhi-Jun Robin Fu } 1702c0da6274SZhi-Jun Robin Fu 1703c0da6274SZhi-Jun Robin Fu /* 170426947304SEvan Yan * The framework provides this routine which can 170526947304SEvan Yan * tear down a sub-tree. 170626947304SEvan Yan */ 170726947304SEvan Yan if (ndi_devi_offline(dip, NDI_DEVI_REMOVE) != NDI_SUCCESS) { 170826947304SEvan Yan DEBUG0("Failed to offline and remove node\n"); 170926947304SEvan Yan return (PCICFG_FAILURE); 171026947304SEvan Yan } 171126947304SEvan Yan 171226947304SEvan Yan return (PCICFG_SUCCESS); 171326947304SEvan Yan } 171426947304SEvan Yan 171526947304SEvan Yan /* 171626947304SEvan Yan * BEGIN GENERIC SUPPORT ROUTINES 171726947304SEvan Yan */ 171826947304SEvan Yan static pcicfg_phdl_t * 171926947304SEvan Yan pcicfg_find_phdl(dev_info_t *dip) 172026947304SEvan Yan { 172126947304SEvan Yan pcicfg_phdl_t *entry; 172226947304SEvan Yan mutex_enter(&pcicfg_list_mutex); 172326947304SEvan Yan for (entry = pcicfg_phdl_list; entry != NULL; entry = entry->next) { 172426947304SEvan Yan if (entry->dip == dip) { 172526947304SEvan Yan mutex_exit(&pcicfg_list_mutex); 172626947304SEvan Yan return (entry); 172726947304SEvan Yan } 172826947304SEvan Yan } 172926947304SEvan Yan mutex_exit(&pcicfg_list_mutex); 173026947304SEvan Yan 173126947304SEvan Yan /* 173226947304SEvan Yan * Did'nt find entry - create one 173326947304SEvan Yan */ 173426947304SEvan Yan return (pcicfg_create_phdl(dip)); 173526947304SEvan Yan } 173626947304SEvan Yan 173726947304SEvan Yan static pcicfg_phdl_t * 173826947304SEvan Yan pcicfg_create_phdl(dev_info_t *dip) 173926947304SEvan Yan { 174026947304SEvan Yan pcicfg_phdl_t *new; 174126947304SEvan Yan 174226947304SEvan Yan new = (pcicfg_phdl_t *)kmem_zalloc(sizeof (pcicfg_phdl_t), 174326947304SEvan Yan KM_SLEEP); 174426947304SEvan Yan 174526947304SEvan Yan new->dip = dip; 174626947304SEvan Yan mutex_enter(&pcicfg_list_mutex); 174726947304SEvan Yan new->next = pcicfg_phdl_list; 174826947304SEvan Yan pcicfg_phdl_list = new; 174926947304SEvan Yan mutex_exit(&pcicfg_list_mutex); 175026947304SEvan Yan 175126947304SEvan Yan return (new); 175226947304SEvan Yan } 175326947304SEvan Yan 175426947304SEvan Yan static int 175526947304SEvan Yan pcicfg_destroy_phdl(dev_info_t *dip) 175626947304SEvan Yan { 175726947304SEvan Yan pcicfg_phdl_t *entry; 175826947304SEvan Yan pcicfg_phdl_t *follow = NULL; 175926947304SEvan Yan 176026947304SEvan Yan mutex_enter(&pcicfg_list_mutex); 176126947304SEvan Yan for (entry = pcicfg_phdl_list; entry != NULL; follow = entry, 176226947304SEvan Yan entry = entry->next) { 176326947304SEvan Yan if (entry->dip == dip) { 176426947304SEvan Yan if (entry == pcicfg_phdl_list) { 176526947304SEvan Yan pcicfg_phdl_list = entry->next; 176626947304SEvan Yan } else { 176726947304SEvan Yan follow->next = entry->next; 176826947304SEvan Yan } 176926947304SEvan Yan /* 177026947304SEvan Yan * If this entry has any allocated memory 177126947304SEvan Yan * or IO space associated with it, that 177226947304SEvan Yan * must be freed up. 177326947304SEvan Yan */ 177426947304SEvan Yan if (entry->memory_len > 0) { 177526947304SEvan Yan (void) ndi_ra_free(ddi_get_parent(dip), 177626947304SEvan Yan entry->memory_base, 177726947304SEvan Yan entry->memory_len, 177826947304SEvan Yan NDI_RA_TYPE_MEM, NDI_RA_PASS); 177926947304SEvan Yan } 178026947304SEvan Yan pcicfg_free_hole(&entry->mem_hole); 178126947304SEvan Yan 178226947304SEvan Yan if (entry->io_len > 0) { 178326947304SEvan Yan (void) ndi_ra_free(ddi_get_parent(dip), 178426947304SEvan Yan entry->io_base, 178526947304SEvan Yan entry->io_len, 178626947304SEvan Yan NDI_RA_TYPE_IO, NDI_RA_PASS); 178726947304SEvan Yan } 178826947304SEvan Yan pcicfg_free_hole(&entry->io_hole); 178926947304SEvan Yan 179026947304SEvan Yan /* 179126947304SEvan Yan * Destroy this entry 179226947304SEvan Yan */ 179326947304SEvan Yan kmem_free((caddr_t)entry, sizeof (pcicfg_phdl_t)); 179426947304SEvan Yan mutex_exit(&pcicfg_list_mutex); 179526947304SEvan Yan return (PCICFG_SUCCESS); 179626947304SEvan Yan } 179726947304SEvan Yan } 179826947304SEvan Yan mutex_exit(&pcicfg_list_mutex); 179926947304SEvan Yan /* 180026947304SEvan Yan * Did'nt find the entry 180126947304SEvan Yan */ 180226947304SEvan Yan return (PCICFG_FAILURE); 180326947304SEvan Yan } 180426947304SEvan Yan 180526947304SEvan Yan static int 180626947304SEvan Yan pcicfg_program_ap(dev_info_t *dip) 180726947304SEvan Yan { 180826947304SEvan Yan pcicfg_phdl_t *phdl; 180926947304SEvan Yan uint8_t header_type; 181026947304SEvan Yan ddi_acc_handle_t handle; 181126947304SEvan Yan pcicfg_phdl_t *entry; 181226947304SEvan Yan 181326947304SEvan Yan if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) { 181426947304SEvan Yan DEBUG0("Failed to map config space!\n"); 181526947304SEvan Yan return (PCICFG_FAILURE); 181626947304SEvan Yan 181726947304SEvan Yan } 181826947304SEvan Yan 181926947304SEvan Yan header_type = pci_config_get8(handle, PCI_CONF_HEADER); 182026947304SEvan Yan 182126947304SEvan Yan (void) pcicfg_config_teardown(&handle); 182226947304SEvan Yan 182326947304SEvan Yan if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) { 182426947304SEvan Yan 182526947304SEvan Yan if (pcicfg_allocate_chunk(dip) != PCICFG_SUCCESS) { 182626947304SEvan Yan DEBUG0("Not enough memory to hotplug\n"); 182726947304SEvan Yan (void) pcicfg_destroy_phdl(dip); 182826947304SEvan Yan return (PCICFG_FAILURE); 182926947304SEvan Yan } 183026947304SEvan Yan 183126947304SEvan Yan phdl = pcicfg_find_phdl(dip); 183226947304SEvan Yan ASSERT(phdl); 183326947304SEvan Yan 183426947304SEvan Yan (void) pcicfg_bridge_assign(dip, (void *)phdl); 183526947304SEvan Yan 183626947304SEvan Yan if (phdl->error != PCICFG_SUCCESS) { 183726947304SEvan Yan DEBUG0("Problem assigning bridge\n"); 183826947304SEvan Yan (void) pcicfg_destroy_phdl(dip); 183926947304SEvan Yan return (phdl->error); 184026947304SEvan Yan } 184126947304SEvan Yan 184226947304SEvan Yan /* 184326947304SEvan Yan * Successfully allocated and assigned 184426947304SEvan Yan * memory. Set the memory and IO length 184526947304SEvan Yan * to zero so when the handle is freed up 184626947304SEvan Yan * it will not de-allocate assigned resources. 184726947304SEvan Yan */ 184826947304SEvan Yan entry = (pcicfg_phdl_t *)phdl; 184926947304SEvan Yan 185026947304SEvan Yan entry->memory_len = entry->io_len = 0; 185126947304SEvan Yan 185226947304SEvan Yan /* 185326947304SEvan Yan * Free up the "entry" structure. 185426947304SEvan Yan */ 185526947304SEvan Yan (void) pcicfg_destroy_phdl(dip); 185626947304SEvan Yan } else { 185726947304SEvan Yan if (pcicfg_device_assign(dip) != PCICFG_SUCCESS) { 185826947304SEvan Yan return (PCICFG_FAILURE); 185926947304SEvan Yan } 186026947304SEvan Yan } 186126947304SEvan Yan return (PCICFG_SUCCESS); 186226947304SEvan Yan } 186326947304SEvan Yan 186426947304SEvan Yan static int 186526947304SEvan Yan pcicfg_bridge_assign(dev_info_t *dip, void *hdl) 186626947304SEvan Yan { 186726947304SEvan Yan ddi_acc_handle_t handle; 186826947304SEvan Yan pci_regspec_t *reg; 186926947304SEvan Yan int length; 187026947304SEvan Yan int rcount; 187126947304SEvan Yan int i; 187226947304SEvan Yan int offset; 187326947304SEvan Yan uint64_t mem_answer; 187426947304SEvan Yan uint32_t io_answer; 187526947304SEvan Yan int count; 187626947304SEvan Yan uint8_t header_type; 187726947304SEvan Yan pcicfg_range_t range[PCICFG_RANGE_LEN]; 187826947304SEvan Yan int bus_range[2]; 187926947304SEvan Yan 188026947304SEvan Yan pcicfg_phdl_t *entry = (pcicfg_phdl_t *)hdl; 188126947304SEvan Yan 188226947304SEvan Yan DEBUG1("bridge assign: assigning addresses to %s\n", ddi_get_name(dip)); 188326947304SEvan Yan 188426947304SEvan Yan if (entry == NULL) { 188526947304SEvan Yan DEBUG0("Failed to get entry\n"); 188626947304SEvan Yan return (DDI_WALK_TERMINATE); 188726947304SEvan Yan } 188826947304SEvan Yan 188926947304SEvan Yan entry->error = PCICFG_SUCCESS; 189026947304SEvan Yan 189126947304SEvan Yan if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) { 189226947304SEvan Yan DEBUG0("Failed to map config space!\n"); 189326947304SEvan Yan entry->error = PCICFG_FAILURE; 189426947304SEvan Yan return (DDI_WALK_TERMINATE); 189526947304SEvan Yan } 189626947304SEvan Yan 189726947304SEvan Yan header_type = pci_config_get8(handle, PCI_CONF_HEADER); 189826947304SEvan Yan 189926947304SEvan Yan if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) { 190026947304SEvan Yan 190126947304SEvan Yan bzero((caddr_t)range, 190226947304SEvan Yan sizeof (pcicfg_range_t) * PCICFG_RANGE_LEN); 190326947304SEvan Yan 190426947304SEvan Yan (void) pcicfg_setup_bridge(entry, handle, dip); 190526947304SEvan Yan 190626947304SEvan Yan range[0].child_hi = range[0].parent_hi |= 190726947304SEvan Yan (PCI_REG_REL_M | PCI_ADDR_IO); 190826947304SEvan Yan range[0].child_lo = range[0].parent_lo = 190926947304SEvan Yan entry->io_last; 191026947304SEvan Yan range[1].child_hi = range[1].parent_hi |= 191126947304SEvan Yan (PCI_REG_REL_M | PCI_ADDR_MEM32); 191226947304SEvan Yan range[1].child_lo = range[1].parent_lo = 191326947304SEvan Yan entry->memory_last; 191426947304SEvan Yan 191526947304SEvan Yan ndi_devi_enter(dip, &count); 191626947304SEvan Yan ddi_walk_devs(ddi_get_child(dip), 191726947304SEvan Yan pcicfg_bridge_assign, (void *)entry); 191826947304SEvan Yan ndi_devi_exit(dip, count); 191926947304SEvan Yan 192026947304SEvan Yan (void) pcicfg_update_bridge(entry, handle); 192126947304SEvan Yan 192226947304SEvan Yan bus_range[0] = pci_config_get8(handle, PCI_BCNF_SECBUS); 192326947304SEvan Yan bus_range[1] = pci_config_get8(handle, PCI_BCNF_SUBBUS); 192426947304SEvan Yan 192526947304SEvan Yan if (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, 192626947304SEvan Yan "bus-range", bus_range, 2) != DDI_SUCCESS) { 192726947304SEvan Yan DEBUG0("Failed to set bus-range property"); 192826947304SEvan Yan entry->error = PCICFG_FAILURE; 192926947304SEvan Yan return (DDI_WALK_TERMINATE); 193026947304SEvan Yan } 193126947304SEvan Yan 193226947304SEvan Yan if (entry->io_len > 0) { 193326947304SEvan Yan range[0].size_lo = entry->io_last - entry->io_base; 193426947304SEvan Yan if (pcicfg_update_ranges_prop(dip, &range[0])) { 193526947304SEvan Yan DEBUG0("Failed to update ranges (i/o)\n"); 193626947304SEvan Yan entry->error = PCICFG_FAILURE; 193726947304SEvan Yan return (DDI_WALK_TERMINATE); 193826947304SEvan Yan } 193926947304SEvan Yan } 194026947304SEvan Yan if (entry->memory_len > 0) { 194126947304SEvan Yan range[1].size_lo = 194226947304SEvan Yan entry->memory_last - entry->memory_base; 194326947304SEvan Yan if (pcicfg_update_ranges_prop(dip, &range[1])) { 194426947304SEvan Yan DEBUG0("Failed to update ranges (memory)\n"); 194526947304SEvan Yan entry->error = PCICFG_FAILURE; 194626947304SEvan Yan return (DDI_WALK_TERMINATE); 194726947304SEvan Yan } 194826947304SEvan Yan } 194926947304SEvan Yan 195026947304SEvan Yan (void) pcicfg_device_on(handle); 195126947304SEvan Yan 195226947304SEvan Yan PCICFG_DUMP_BRIDGE_CONFIG(handle); 195326947304SEvan Yan 195426947304SEvan Yan return (DDI_WALK_PRUNECHILD); 195526947304SEvan Yan } 195626947304SEvan Yan 195726947304SEvan Yan /* 195826947304SEvan Yan * If there is an interrupt pin set program 195926947304SEvan Yan * interrupt line with default values. 196026947304SEvan Yan */ 196126947304SEvan Yan if (pci_config_get8(handle, PCI_CONF_IPIN)) { 196226947304SEvan Yan pci_config_put8(handle, PCI_CONF_ILINE, 0xf); 196326947304SEvan Yan } 196426947304SEvan Yan 196526947304SEvan Yan /* 196626947304SEvan Yan * A single device (under a bridge). 196726947304SEvan Yan * For each "reg" property with a length, allocate memory 196826947304SEvan Yan * and program the base registers. 196926947304SEvan Yan */ 197026947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 197126947304SEvan Yan DDI_PROP_DONTPASS, "reg", (caddr_t)®, 197226947304SEvan Yan &length) != DDI_PROP_SUCCESS) { 197326947304SEvan Yan DEBUG0("Failed to read reg property\n"); 197426947304SEvan Yan entry->error = PCICFG_FAILURE; 197526947304SEvan Yan return (DDI_WALK_TERMINATE); 197626947304SEvan Yan } 197726947304SEvan Yan 197826947304SEvan Yan rcount = length / sizeof (pci_regspec_t); 197926947304SEvan Yan offset = PCI_CONF_BASE0; 198026947304SEvan Yan for (i = 0; i < rcount; i++) { 198126947304SEvan Yan if ((reg[i].pci_size_low != 0)|| 198226947304SEvan Yan (reg[i].pci_size_hi != 0)) { 198326947304SEvan Yan 198426947304SEvan Yan offset = PCI_REG_REG_G(reg[i].pci_phys_hi); 198526947304SEvan Yan 198626947304SEvan Yan switch (PCI_REG_ADDR_G(reg[i].pci_phys_hi)) { 198726947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_MEM64): 198826947304SEvan Yan 198926947304SEvan Yan (void) pcicfg_get_mem(entry, 199026947304SEvan Yan reg[i].pci_size_low, &mem_answer); 199126947304SEvan Yan pci_config_put64(handle, offset, mem_answer); 199226947304SEvan Yan DEBUG2("REGISTER off %x (64)LO ----> [0x%x]\n", 199326947304SEvan Yan offset, 199426947304SEvan Yan pci_config_get32(handle, offset)); 199526947304SEvan Yan DEBUG2("REGISTER off %x (64)HI ----> [0x%x]\n", 199626947304SEvan Yan offset + 4, 199726947304SEvan Yan pci_config_get32(handle, offset + 4)); 199826947304SEvan Yan 199926947304SEvan Yan reg[i].pci_phys_low = PCICFG_HIADDR(mem_answer); 200026947304SEvan Yan reg[i].pci_phys_mid = 200126947304SEvan Yan PCICFG_LOADDR(mem_answer); 200226947304SEvan Yan 200326947304SEvan Yan break; 200426947304SEvan Yan 200526947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_MEM32): 200626947304SEvan Yan /* allocate memory space from the allocator */ 200726947304SEvan Yan 200826947304SEvan Yan (void) pcicfg_get_mem(entry, 200926947304SEvan Yan reg[i].pci_size_low, &mem_answer); 201026947304SEvan Yan pci_config_put32(handle, 201126947304SEvan Yan offset, (uint32_t)mem_answer); 201226947304SEvan Yan 201326947304SEvan Yan DEBUG2("REGISTER off %x(32)LO ----> [0x%x]\n", 201426947304SEvan Yan offset, 201526947304SEvan Yan pci_config_get32(handle, offset)); 201626947304SEvan Yan 201726947304SEvan Yan reg[i].pci_phys_low = (uint32_t)mem_answer; 201826947304SEvan Yan 201926947304SEvan Yan break; 202026947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_IO): 202126947304SEvan Yan /* allocate I/O space from the allocator */ 202226947304SEvan Yan 202326947304SEvan Yan (void) pcicfg_get_io(entry, 202426947304SEvan Yan reg[i].pci_size_low, &io_answer); 202526947304SEvan Yan pci_config_put32(handle, offset, io_answer); 202626947304SEvan Yan 202726947304SEvan Yan DEBUG2("REGISTER off %x (I/O)LO ----> [0x%x]\n", 202826947304SEvan Yan offset, 202926947304SEvan Yan pci_config_get32(handle, offset)); 203026947304SEvan Yan 203126947304SEvan Yan reg[i].pci_phys_low = io_answer; 203226947304SEvan Yan 203326947304SEvan Yan break; 203426947304SEvan Yan default: 203526947304SEvan Yan DEBUG0("Unknown register type\n"); 203626947304SEvan Yan kmem_free(reg, length); 203726947304SEvan Yan (void) pcicfg_config_teardown(&handle); 203826947304SEvan Yan entry->error = PCICFG_FAILURE; 203926947304SEvan Yan return (DDI_WALK_TERMINATE); 204026947304SEvan Yan } /* switch */ 204126947304SEvan Yan 204226947304SEvan Yan /* 204326947304SEvan Yan * Now that memory locations are assigned, 204426947304SEvan Yan * update the assigned address property. 204526947304SEvan Yan */ 204626947304SEvan Yan if (pcicfg_update_assigned_prop(dip, 204726947304SEvan Yan ®[i]) != PCICFG_SUCCESS) { 204826947304SEvan Yan kmem_free(reg, length); 204926947304SEvan Yan (void) pcicfg_config_teardown(&handle); 205026947304SEvan Yan entry->error = PCICFG_FAILURE; 205126947304SEvan Yan return (DDI_WALK_TERMINATE); 205226947304SEvan Yan } 205326947304SEvan Yan } 205426947304SEvan Yan } 205526947304SEvan Yan (void) pcicfg_device_on(handle); 205626947304SEvan Yan 205726947304SEvan Yan PCICFG_DUMP_DEVICE_CONFIG(handle); 205826947304SEvan Yan 205926947304SEvan Yan (void) pcicfg_config_teardown(&handle); 206026947304SEvan Yan /* 206126947304SEvan Yan * Don't forget to free up memory from ddi_getlongprop 206226947304SEvan Yan */ 206326947304SEvan Yan kmem_free((caddr_t)reg, length); 206426947304SEvan Yan 206526947304SEvan Yan return (DDI_WALK_CONTINUE); 206626947304SEvan Yan } 206726947304SEvan Yan 206826947304SEvan Yan static int 206926947304SEvan Yan pcicfg_device_assign(dev_info_t *dip) 207026947304SEvan Yan { 207126947304SEvan Yan ddi_acc_handle_t handle; 207226947304SEvan Yan pci_regspec_t *reg; 207326947304SEvan Yan int length; 207426947304SEvan Yan int rcount; 207526947304SEvan Yan int i; 207626947304SEvan Yan int offset; 207726947304SEvan Yan ndi_ra_request_t request; 207826947304SEvan Yan uint64_t answer; 207926947304SEvan Yan uint64_t alen; 208026947304SEvan Yan 208126947304SEvan Yan DEBUG1("%llx now under configuration\n", dip); 208226947304SEvan Yan 208326947304SEvan Yan /* 208426947304SEvan Yan * XXX Failure here should be noted 208526947304SEvan Yan */ 208626947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 208726947304SEvan Yan DDI_PROP_DONTPASS, "reg", (caddr_t)®, 208826947304SEvan Yan &length) != DDI_PROP_SUCCESS) { 208926947304SEvan Yan DEBUG0("Failed to read reg property\n"); 209026947304SEvan Yan return (PCICFG_FAILURE); 209126947304SEvan Yan } 209226947304SEvan Yan 209326947304SEvan Yan if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) { 209426947304SEvan Yan DEBUG0("Failed to map config space!\n"); 209526947304SEvan Yan /* 209626947304SEvan Yan * Don't forget to free up memory from ddi_getlongprop 209726947304SEvan Yan */ 209826947304SEvan Yan kmem_free((caddr_t)reg, length); 209926947304SEvan Yan 210026947304SEvan Yan return (PCICFG_FAILURE); 210126947304SEvan Yan } 210226947304SEvan Yan 210326947304SEvan Yan /* 210426947304SEvan Yan * A single device 210526947304SEvan Yan * 210626947304SEvan Yan * For each "reg" property with a length, allocate memory 210726947304SEvan Yan * and program the base registers. 210826947304SEvan Yan */ 210926947304SEvan Yan 211026947304SEvan Yan /* 211126947304SEvan Yan * If there is an interrupt pin set program 211226947304SEvan Yan * interrupt line with default values. 211326947304SEvan Yan */ 211426947304SEvan Yan if (pci_config_get8(handle, PCI_CONF_IPIN)) { 211526947304SEvan Yan pci_config_put8(handle, PCI_CONF_ILINE, 0xf); 211626947304SEvan Yan } 211726947304SEvan Yan 211826947304SEvan Yan bzero((caddr_t)&request, sizeof (ndi_ra_request_t)); 211926947304SEvan Yan 212026947304SEvan Yan request.ra_flags |= NDI_RA_ALIGN_SIZE; 212126947304SEvan Yan request.ra_boundbase = 0; 212226947304SEvan Yan request.ra_boundlen = PCICFG_4GIG_LIMIT; 212326947304SEvan Yan 212426947304SEvan Yan rcount = length / sizeof (pci_regspec_t); 212526947304SEvan Yan offset = PCI_CONF_BASE0; 212626947304SEvan Yan for (i = 0; i < rcount; i++) { 212726947304SEvan Yan if ((reg[i].pci_size_low != 0)|| 212826947304SEvan Yan (reg[i].pci_size_hi != 0)) { 212926947304SEvan Yan 213026947304SEvan Yan offset = PCI_REG_REG_G(reg[i].pci_phys_hi); 213126947304SEvan Yan request.ra_len = reg[i].pci_size_low; 213226947304SEvan Yan 213326947304SEvan Yan switch (PCI_REG_ADDR_G(reg[i].pci_phys_hi)) { 213426947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_MEM64): 213526947304SEvan Yan request.ra_flags ^= NDI_RA_ALLOC_BOUNDED; 213626947304SEvan Yan /* allocate memory space from the allocator */ 213726947304SEvan Yan if (ndi_ra_alloc(ddi_get_parent(dip), 213826947304SEvan Yan &request, &answer, &alen, 213926947304SEvan Yan NDI_RA_TYPE_MEM, NDI_RA_PASS) 214026947304SEvan Yan != NDI_SUCCESS) { 214126947304SEvan Yan DEBUG0("Failed to allocate 64b mem\n"); 214226947304SEvan Yan kmem_free(reg, length); 214326947304SEvan Yan (void) pcicfg_config_teardown(&handle); 214426947304SEvan Yan return (PCICFG_FAILURE); 214526947304SEvan Yan } 214626947304SEvan Yan DEBUG3("64 addr = [0x%x.%x] len [0x%x]\n", 214726947304SEvan Yan PCICFG_HIADDR(answer), 214826947304SEvan Yan PCICFG_LOADDR(answer), 214926947304SEvan Yan alen); 215026947304SEvan Yan /* program the low word */ 215126947304SEvan Yan pci_config_put32(handle, 215226947304SEvan Yan offset, PCICFG_LOADDR(answer)); 215326947304SEvan Yan 215426947304SEvan Yan /* program the high word with value zero */ 215526947304SEvan Yan pci_config_put32(handle, offset + 4, 215626947304SEvan Yan PCICFG_HIADDR(answer)); 215726947304SEvan Yan 215826947304SEvan Yan reg[i].pci_phys_low = PCICFG_LOADDR(answer); 215926947304SEvan Yan reg[i].pci_phys_mid = PCICFG_HIADDR(answer); 216026947304SEvan Yan /* 216126947304SEvan Yan * currently support 32b address space 216226947304SEvan Yan * assignments only. 216326947304SEvan Yan */ 216426947304SEvan Yan reg[i].pci_phys_hi ^= PCI_ADDR_MEM64 ^ 216526947304SEvan Yan PCI_ADDR_MEM32; 216626947304SEvan Yan 216726947304SEvan Yan offset += 8; 216826947304SEvan Yan break; 216926947304SEvan Yan 217026947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_MEM32): 217126947304SEvan Yan request.ra_flags |= NDI_RA_ALLOC_BOUNDED; 217226947304SEvan Yan /* allocate memory space from the allocator */ 217326947304SEvan Yan if (ndi_ra_alloc(ddi_get_parent(dip), 217426947304SEvan Yan &request, &answer, &alen, 217526947304SEvan Yan NDI_RA_TYPE_MEM, NDI_RA_PASS) 217626947304SEvan Yan != NDI_SUCCESS) { 217726947304SEvan Yan DEBUG0("Failed to allocate 32b mem\n"); 217826947304SEvan Yan kmem_free(reg, length); 217926947304SEvan Yan (void) pcicfg_config_teardown(&handle); 218026947304SEvan Yan return (PCICFG_FAILURE); 218126947304SEvan Yan } 218226947304SEvan Yan DEBUG3("32 addr = [0x%x.%x] len [0x%x]\n", 218326947304SEvan Yan PCICFG_HIADDR(answer), 218426947304SEvan Yan PCICFG_LOADDR(answer), 218526947304SEvan Yan alen); 218626947304SEvan Yan /* program the low word */ 218726947304SEvan Yan pci_config_put32(handle, 218826947304SEvan Yan offset, PCICFG_LOADDR(answer)); 218926947304SEvan Yan 219026947304SEvan Yan reg[i].pci_phys_low = PCICFG_LOADDR(answer); 219126947304SEvan Yan 219226947304SEvan Yan offset += 4; 219326947304SEvan Yan break; 219426947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_IO): 219526947304SEvan Yan /* allocate I/O space from the allocator */ 219626947304SEvan Yan request.ra_flags |= NDI_RA_ALLOC_BOUNDED; 219726947304SEvan Yan if (ndi_ra_alloc(ddi_get_parent(dip), 219826947304SEvan Yan &request, &answer, &alen, 219926947304SEvan Yan NDI_RA_TYPE_IO, NDI_RA_PASS) 220026947304SEvan Yan != NDI_SUCCESS) { 220126947304SEvan Yan DEBUG0("Failed to allocate I/O\n"); 220226947304SEvan Yan kmem_free(reg, length); 220326947304SEvan Yan (void) pcicfg_config_teardown(&handle); 220426947304SEvan Yan return (PCICFG_FAILURE); 220526947304SEvan Yan } 220626947304SEvan Yan DEBUG3("I/O addr = [0x%x.%x] len [0x%x]\n", 220726947304SEvan Yan PCICFG_HIADDR(answer), 220826947304SEvan Yan PCICFG_LOADDR(answer), 220926947304SEvan Yan alen); 221026947304SEvan Yan pci_config_put32(handle, 221126947304SEvan Yan offset, PCICFG_LOADDR(answer)); 221226947304SEvan Yan 221326947304SEvan Yan reg[i].pci_phys_low = PCICFG_LOADDR(answer); 221426947304SEvan Yan 221526947304SEvan Yan offset += 4; 221626947304SEvan Yan break; 221726947304SEvan Yan default: 221826947304SEvan Yan DEBUG0("Unknown register type\n"); 221926947304SEvan Yan kmem_free(reg, length); 222026947304SEvan Yan (void) pcicfg_config_teardown(&handle); 222126947304SEvan Yan return (PCICFG_FAILURE); 222226947304SEvan Yan } /* switch */ 222326947304SEvan Yan 222426947304SEvan Yan /* 222526947304SEvan Yan * Now that memory locations are assigned, 222626947304SEvan Yan * update the assigned address property. 222726947304SEvan Yan */ 222826947304SEvan Yan 222926947304SEvan Yan if (pcicfg_update_assigned_prop(dip, 223026947304SEvan Yan ®[i]) != PCICFG_SUCCESS) { 223126947304SEvan Yan kmem_free(reg, length); 223226947304SEvan Yan (void) pcicfg_config_teardown(&handle); 223326947304SEvan Yan return (PCICFG_FAILURE); 223426947304SEvan Yan } 223526947304SEvan Yan } 223626947304SEvan Yan } 223726947304SEvan Yan 223826947304SEvan Yan (void) pcicfg_device_on(handle); 223926947304SEvan Yan kmem_free(reg, length); 224026947304SEvan Yan 224126947304SEvan Yan PCICFG_DUMP_DEVICE_CONFIG(handle); 224226947304SEvan Yan 224326947304SEvan Yan (void) pcicfg_config_teardown(&handle); 224426947304SEvan Yan return (PCICFG_SUCCESS); 224526947304SEvan Yan } 224626947304SEvan Yan 224726947304SEvan Yan static int 224826947304SEvan Yan pcicfg_device_assign_readonly(dev_info_t *dip) 224926947304SEvan Yan { 225026947304SEvan Yan ddi_acc_handle_t handle; 225126947304SEvan Yan pci_regspec_t *assigned; 225226947304SEvan Yan int length; 225326947304SEvan Yan int acount; 225426947304SEvan Yan int i; 225526947304SEvan Yan ndi_ra_request_t request; 225626947304SEvan Yan uint64_t answer; 225726947304SEvan Yan uint64_t alen; 225826947304SEvan Yan 225926947304SEvan Yan 226026947304SEvan Yan DEBUG1("%llx now under configuration\n", dip); 226126947304SEvan Yan 226226947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 226326947304SEvan Yan DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned, 226426947304SEvan Yan &length) != DDI_PROP_SUCCESS) { 226526947304SEvan Yan DEBUG0("Failed to read assigned-addresses property\n"); 226626947304SEvan Yan return (PCICFG_FAILURE); 226726947304SEvan Yan } 226826947304SEvan Yan 226926947304SEvan Yan if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) { 227026947304SEvan Yan DEBUG0("Failed to map config space!\n"); 227126947304SEvan Yan /* 227226947304SEvan Yan * Don't forget to free up memory from ddi_getlongprop 227326947304SEvan Yan */ 227426947304SEvan Yan kmem_free((caddr_t)assigned, length); 227526947304SEvan Yan 227626947304SEvan Yan return (PCICFG_FAILURE); 227726947304SEvan Yan } 227826947304SEvan Yan 227926947304SEvan Yan /* 228026947304SEvan Yan * For each "assigned-addresses" property entry with a length, 228126947304SEvan Yan * call the memory allocation routines to return the 228226947304SEvan Yan * resource. 228326947304SEvan Yan */ 228426947304SEvan Yan /* 228526947304SEvan Yan * If there is an interrupt pin set program 228626947304SEvan Yan * interrupt line with default values. 228726947304SEvan Yan */ 228826947304SEvan Yan if (pci_config_get8(handle, PCI_CONF_IPIN)) { 228926947304SEvan Yan pci_config_put8(handle, PCI_CONF_ILINE, 0xf); 229026947304SEvan Yan } 229126947304SEvan Yan 229226947304SEvan Yan bzero((caddr_t)&request, sizeof (ndi_ra_request_t)); 229326947304SEvan Yan 229426947304SEvan Yan request.ra_flags = NDI_RA_ALLOC_SPECIFIED; /* specified addr */ 229526947304SEvan Yan request.ra_boundbase = 0; 229626947304SEvan Yan request.ra_boundlen = PCICFG_4GIG_LIMIT; 229726947304SEvan Yan 229826947304SEvan Yan acount = length / sizeof (pci_regspec_t); 229926947304SEvan Yan for (i = 0; i < acount; i++) { 230026947304SEvan Yan if ((assigned[i].pci_size_low != 0)|| 230126947304SEvan Yan (assigned[i].pci_size_hi != 0)) { 230226947304SEvan Yan 230326947304SEvan Yan request.ra_len = assigned[i].pci_size_low; 230426947304SEvan Yan 230526947304SEvan Yan switch (PCI_REG_ADDR_G(assigned[i].pci_phys_hi)) { 230626947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_MEM64): 230726947304SEvan Yan request.ra_addr = (uint64_t)PCICFG_LADDR( 230826947304SEvan Yan assigned[i].pci_phys_low, 230926947304SEvan Yan assigned[i].pci_phys_mid); 231026947304SEvan Yan 231126947304SEvan Yan /* allocate memory space from the allocator */ 231226947304SEvan Yan if (ndi_ra_alloc(ddi_get_parent(dip), 231326947304SEvan Yan &request, &answer, &alen, 231426947304SEvan Yan NDI_RA_TYPE_MEM, NDI_RA_PASS) 231526947304SEvan Yan != NDI_SUCCESS) { 231626947304SEvan Yan DEBUG0("Failed to allocate 64b mem\n"); 231726947304SEvan Yan kmem_free(assigned, length); 231826947304SEvan Yan return (PCICFG_FAILURE); 231926947304SEvan Yan } 232026947304SEvan Yan 232126947304SEvan Yan break; 232226947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_MEM32): 232326947304SEvan Yan request.ra_addr = (uint64_t) 232426947304SEvan Yan assigned[i].pci_phys_low; 232526947304SEvan Yan 232626947304SEvan Yan /* allocate memory space from the allocator */ 232726947304SEvan Yan if (ndi_ra_alloc(ddi_get_parent(dip), 232826947304SEvan Yan &request, &answer, &alen, 232926947304SEvan Yan NDI_RA_TYPE_MEM, NDI_RA_PASS) 233026947304SEvan Yan != NDI_SUCCESS) { 233126947304SEvan Yan DEBUG0("Failed to allocate 32b mem\n"); 233226947304SEvan Yan kmem_free(assigned, length); 233326947304SEvan Yan return (PCICFG_FAILURE); 233426947304SEvan Yan } 233526947304SEvan Yan 233626947304SEvan Yan break; 233726947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_IO): 233826947304SEvan Yan request.ra_addr = (uint64_t) 233926947304SEvan Yan assigned[i].pci_phys_low; 234026947304SEvan Yan 234126947304SEvan Yan /* allocate I/O space from the allocator */ 234226947304SEvan Yan if (ndi_ra_alloc(ddi_get_parent(dip), 234326947304SEvan Yan &request, &answer, &alen, 234426947304SEvan Yan NDI_RA_TYPE_IO, NDI_RA_PASS) 234526947304SEvan Yan != NDI_SUCCESS) { 234626947304SEvan Yan DEBUG0("Failed to allocate I/O\n"); 234726947304SEvan Yan kmem_free(assigned, length); 234826947304SEvan Yan return (PCICFG_FAILURE); 234926947304SEvan Yan } 235026947304SEvan Yan 235126947304SEvan Yan break; 235226947304SEvan Yan default: 235326947304SEvan Yan DEBUG0("Unknown register type\n"); 235426947304SEvan Yan kmem_free(assigned, length); 235526947304SEvan Yan return (PCICFG_FAILURE); 235626947304SEvan Yan } /* switch */ 235726947304SEvan Yan } 235826947304SEvan Yan } 235926947304SEvan Yan 236026947304SEvan Yan (void) pcicfg_device_on(handle); 236126947304SEvan Yan kmem_free(assigned, length); 236226947304SEvan Yan 236326947304SEvan Yan PCICFG_DUMP_DEVICE_CONFIG(handle); 236426947304SEvan Yan 236526947304SEvan Yan (void) pcicfg_config_teardown(&handle); 236626947304SEvan Yan return (PCICFG_SUCCESS); 236726947304SEvan Yan } 236826947304SEvan Yan 236926947304SEvan Yan /* 237026947304SEvan Yan * The "dip" passed to this routine is assumed to be 237126947304SEvan Yan * the device at the Hotplug Connection (CN). Currently it is 237226947304SEvan Yan * assumed to be a bridge. 237326947304SEvan Yan */ 237426947304SEvan Yan static int 237526947304SEvan Yan pcicfg_allocate_chunk(dev_info_t *dip) 237626947304SEvan Yan { 237726947304SEvan Yan pcicfg_phdl_t *phdl; 237826947304SEvan Yan ndi_ra_request_t *mem_request; 237926947304SEvan Yan ndi_ra_request_t *io_request; 238026947304SEvan Yan uint64_t mem_answer; 238126947304SEvan Yan uint64_t io_answer; 238226947304SEvan Yan int count; 238326947304SEvan Yan uint64_t alen; 238426947304SEvan Yan 238526947304SEvan Yan /* 238626947304SEvan Yan * This should not find an existing entry - so 238726947304SEvan Yan * it will create a new one. 238826947304SEvan Yan */ 238926947304SEvan Yan phdl = pcicfg_find_phdl(dip); 239026947304SEvan Yan ASSERT(phdl); 239126947304SEvan Yan 239226947304SEvan Yan mem_request = &phdl->mem_req; 239326947304SEvan Yan io_request = &phdl->io_req; 239426947304SEvan Yan 239526947304SEvan Yan /* 239626947304SEvan Yan * From this point in the tree - walk the devices, 239726947304SEvan Yan * The function passed in will read and "sum" up 239826947304SEvan Yan * the memory and I/O requirements and put them in 239926947304SEvan Yan * structure "phdl". 240026947304SEvan Yan */ 240126947304SEvan Yan ndi_devi_enter(ddi_get_parent(dip), &count); 240226947304SEvan Yan ddi_walk_devs(dip, pcicfg_sum_resources, (void *)phdl); 240326947304SEvan Yan ndi_devi_exit(ddi_get_parent(dip), count); 240426947304SEvan Yan 240526947304SEvan Yan if (phdl->error != PCICFG_SUCCESS) { 240626947304SEvan Yan DEBUG0("Failure summing resources\n"); 240726947304SEvan Yan return (phdl->error); 240826947304SEvan Yan } 240926947304SEvan Yan 241026947304SEvan Yan /* 241126947304SEvan Yan * Call into the memory allocator with the request. 241226947304SEvan Yan * Record the addresses returned in the phdl 241326947304SEvan Yan */ 241426947304SEvan Yan DEBUG1("Connector requires [0x%x] bytes of memory space\n", 241526947304SEvan Yan mem_request->ra_len); 241626947304SEvan Yan DEBUG1("Connector requires [0x%x] bytes of I/O space\n", 241726947304SEvan Yan io_request->ra_len); 241826947304SEvan Yan 241926947304SEvan Yan mem_request->ra_align_mask = 242026947304SEvan Yan PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */ 242126947304SEvan Yan io_request->ra_align_mask = 242226947304SEvan Yan PCICFG_IOGRAN - 1; /* 4K alignment on I/O space */ 242326947304SEvan Yan io_request->ra_boundbase = 0; 242426947304SEvan Yan io_request->ra_boundlen = PCICFG_4GIG_LIMIT; 242526947304SEvan Yan io_request->ra_flags |= NDI_RA_ALLOC_BOUNDED; 242626947304SEvan Yan 242726947304SEvan Yan mem_request->ra_len = 242826947304SEvan Yan PCICFG_ROUND_UP(mem_request->ra_len, PCICFG_MEMGRAN); 242926947304SEvan Yan 243026947304SEvan Yan io_request->ra_len = 243126947304SEvan Yan PCICFG_ROUND_UP(io_request->ra_len, PCICFG_IOGRAN); 243226947304SEvan Yan 243326947304SEvan Yan if (ndi_ra_alloc(ddi_get_parent(dip), 243426947304SEvan Yan mem_request, &mem_answer, &alen, 243526947304SEvan Yan NDI_RA_TYPE_MEM, NDI_RA_PASS) != NDI_SUCCESS) { 243626947304SEvan Yan DEBUG0("Failed to allocate memory\n"); 243726947304SEvan Yan return (PCICFG_FAILURE); 243826947304SEvan Yan } 243926947304SEvan Yan 244026947304SEvan Yan phdl->memory_base = phdl->memory_last = mem_answer; 244126947304SEvan Yan phdl->memory_len = alen; 244226947304SEvan Yan 244326947304SEvan Yan phdl->mem_hole.start = phdl->memory_base; 244426947304SEvan Yan phdl->mem_hole.len = phdl->memory_len; 244526947304SEvan Yan phdl->mem_hole.next = (hole_t *)NULL; 244626947304SEvan Yan 244726947304SEvan Yan if (ndi_ra_alloc(ddi_get_parent(dip), io_request, &io_answer, 244826947304SEvan Yan &alen, NDI_RA_TYPE_IO, NDI_RA_PASS) != NDI_SUCCESS) { 244926947304SEvan Yan 245026947304SEvan Yan DEBUG0("Failed to allocate I/O space\n"); 245126947304SEvan Yan (void) ndi_ra_free(ddi_get_parent(dip), mem_answer, 245226947304SEvan Yan alen, NDI_RA_TYPE_MEM, NDI_RA_PASS); 245326947304SEvan Yan phdl->memory_len = phdl->io_len = 0; 245426947304SEvan Yan return (PCICFG_FAILURE); 245526947304SEvan Yan } 245626947304SEvan Yan 245726947304SEvan Yan phdl->io_base = phdl->io_last = (uint32_t)io_answer; 245826947304SEvan Yan phdl->io_len = (uint32_t)alen; 245926947304SEvan Yan 246026947304SEvan Yan phdl->io_hole.start = phdl->io_base; 246126947304SEvan Yan phdl->io_hole.len = phdl->io_len; 246226947304SEvan Yan phdl->io_hole.next = (hole_t *)NULL; 246326947304SEvan Yan 246426947304SEvan Yan DEBUG2("MEMORY BASE = [0x%x] length [0x%x]\n", 246526947304SEvan Yan phdl->memory_base, phdl->memory_len); 246626947304SEvan Yan DEBUG2("IO BASE = [0x%x] length [0x%x]\n", 246726947304SEvan Yan phdl->io_base, phdl->io_len); 246826947304SEvan Yan 246926947304SEvan Yan return (PCICFG_SUCCESS); 247026947304SEvan Yan } 247126947304SEvan Yan 247226947304SEvan Yan #ifdef DEBUG 247326947304SEvan Yan /* 247426947304SEvan Yan * This function is useful in debug mode, where we can measure how 247526947304SEvan Yan * much memory was wasted/unallocated in bridge device's domain. 247626947304SEvan Yan */ 247726947304SEvan Yan static uint64_t 247826947304SEvan Yan pcicfg_unused_space(hole_t *hole, uint32_t *hole_count) 247926947304SEvan Yan { 248026947304SEvan Yan uint64_t len = 0; 248126947304SEvan Yan uint32_t count = 0; 248226947304SEvan Yan 248326947304SEvan Yan do { 248426947304SEvan Yan len += hole->len; 248526947304SEvan Yan hole = hole->next; 248626947304SEvan Yan count++; 248726947304SEvan Yan } while (hole); 248826947304SEvan Yan *hole_count = count; 248926947304SEvan Yan return (len); 249026947304SEvan Yan } 249126947304SEvan Yan #endif 249226947304SEvan Yan 249326947304SEvan Yan /* 249426947304SEvan Yan * This function frees data structures that hold the hole information 249526947304SEvan Yan * which are allocated in pcicfg_alloc_hole(). This is not freeing 249626947304SEvan Yan * any memory allocated through NDI calls. 249726947304SEvan Yan */ 249826947304SEvan Yan static void 249926947304SEvan Yan pcicfg_free_hole(hole_t *addr_hole) 250026947304SEvan Yan { 250126947304SEvan Yan hole_t *nhole, *hole = addr_hole->next; 250226947304SEvan Yan 250326947304SEvan Yan while (hole) { 250426947304SEvan Yan nhole = hole->next; 250526947304SEvan Yan kmem_free(hole, sizeof (hole_t)); 250626947304SEvan Yan hole = nhole; 250726947304SEvan Yan } 250826947304SEvan Yan } 250926947304SEvan Yan 251026947304SEvan Yan static uint64_t 251126947304SEvan Yan pcicfg_alloc_hole(hole_t *addr_hole, uint64_t *alast, uint32_t length) 251226947304SEvan Yan { 251326947304SEvan Yan uint64_t actual_hole_start, ostart, olen; 251426947304SEvan Yan hole_t *hole = addr_hole, *thole, *nhole; 251526947304SEvan Yan 251626947304SEvan Yan do { 251726947304SEvan Yan actual_hole_start = PCICFG_ROUND_UP(hole->start, length); 251826947304SEvan Yan if (((actual_hole_start - hole->start) + length) <= hole->len) { 251926947304SEvan Yan DEBUG3("hole found. start %llx, len %llx, req=%x\n", 252026947304SEvan Yan hole->start, hole->len, length); 252126947304SEvan Yan ostart = hole->start; 252226947304SEvan Yan olen = hole->len; 252326947304SEvan Yan /* current hole parameters adjust */ 252426947304SEvan Yan if ((actual_hole_start - hole->start) == 0) { 252526947304SEvan Yan hole->start += length; 252626947304SEvan Yan hole->len -= length; 252726947304SEvan Yan if (hole->start > *alast) 252826947304SEvan Yan *alast = hole->start; 252926947304SEvan Yan } else { 253026947304SEvan Yan hole->len = actual_hole_start - hole->start; 253126947304SEvan Yan nhole = (hole_t *)kmem_zalloc(sizeof (hole_t), 253226947304SEvan Yan KM_SLEEP); 253326947304SEvan Yan nhole->start = actual_hole_start + length; 253426947304SEvan Yan nhole->len = (ostart + olen) - nhole->start; 253526947304SEvan Yan nhole->next = NULL; 253626947304SEvan Yan thole = hole->next; 253726947304SEvan Yan hole->next = nhole; 253826947304SEvan Yan nhole->next = thole; 253926947304SEvan Yan if (nhole->start > *alast) 254026947304SEvan Yan *alast = nhole->start; 254126947304SEvan Yan DEBUG2("put new hole to %llx, %llx\n", 254226947304SEvan Yan nhole->start, nhole->len); 254326947304SEvan Yan } 254426947304SEvan Yan DEBUG2("adjust current hole to %llx, %llx\n", 254526947304SEvan Yan hole->start, hole->len); 254626947304SEvan Yan break; 254726947304SEvan Yan } 254826947304SEvan Yan actual_hole_start = 0; 254926947304SEvan Yan hole = hole->next; 255026947304SEvan Yan } while (hole); 255126947304SEvan Yan 255226947304SEvan Yan DEBUG1("return hole at %llx\n", actual_hole_start); 255326947304SEvan Yan return (actual_hole_start); 255426947304SEvan Yan } 255526947304SEvan Yan 255626947304SEvan Yan static void 255726947304SEvan Yan pcicfg_get_mem(pcicfg_phdl_t *entry, 255826947304SEvan Yan uint32_t length, uint64_t *ans) 255926947304SEvan Yan { 256026947304SEvan Yan uint64_t new_mem; 256126947304SEvan Yan 256226947304SEvan Yan /* See if there is a hole, that can hold this request. */ 256326947304SEvan Yan new_mem = pcicfg_alloc_hole(&entry->mem_hole, &entry->memory_last, 256426947304SEvan Yan length); 256526947304SEvan Yan if (new_mem) { /* if non-zero, found a hole. */ 256626947304SEvan Yan if (ans != NULL) 256726947304SEvan Yan *ans = new_mem; 256826947304SEvan Yan } else 256926947304SEvan Yan cmn_err(CE_WARN, "No %u bytes memory window for %s\n", 257026947304SEvan Yan length, ddi_get_name(entry->dip)); 257126947304SEvan Yan } 257226947304SEvan Yan 257326947304SEvan Yan static void 257426947304SEvan Yan pcicfg_get_io(pcicfg_phdl_t *entry, 257526947304SEvan Yan uint32_t length, uint32_t *ans) 257626947304SEvan Yan { 257726947304SEvan Yan uint32_t new_io; 257826947304SEvan Yan uint64_t io_last; 257926947304SEvan Yan 258026947304SEvan Yan /* 258126947304SEvan Yan * See if there is a hole, that can hold this request. 258226947304SEvan Yan * Pass 64 bit parameters and then truncate to 32 bit. 258326947304SEvan Yan */ 258426947304SEvan Yan io_last = entry->io_last; 258526947304SEvan Yan new_io = (uint32_t)pcicfg_alloc_hole(&entry->io_hole, &io_last, length); 258626947304SEvan Yan if (new_io) { /* if non-zero, found a hole. */ 258726947304SEvan Yan entry->io_last = (uint32_t)io_last; 258826947304SEvan Yan if (ans != NULL) 258926947304SEvan Yan *ans = new_io; 259026947304SEvan Yan } else 259126947304SEvan Yan cmn_err(CE_WARN, "No %u bytes IO space window for %s\n", 259226947304SEvan Yan length, ddi_get_name(entry->dip)); 259326947304SEvan Yan } 259426947304SEvan Yan 259526947304SEvan Yan static int 259626947304SEvan Yan pcicfg_sum_resources(dev_info_t *dip, void *hdl) 259726947304SEvan Yan { 259826947304SEvan Yan pcicfg_phdl_t *entry = (pcicfg_phdl_t *)hdl; 259926947304SEvan Yan pci_regspec_t *pci_rp; 260026947304SEvan Yan int length; 260126947304SEvan Yan int rcount; 260226947304SEvan Yan int i; 260326947304SEvan Yan ndi_ra_request_t *mem_request; 260426947304SEvan Yan ndi_ra_request_t *io_request; 260526947304SEvan Yan uint8_t header_type; 260626947304SEvan Yan ddi_acc_handle_t handle; 260726947304SEvan Yan 260826947304SEvan Yan entry->error = PCICFG_SUCCESS; 260926947304SEvan Yan 261026947304SEvan Yan mem_request = &entry->mem_req; 261126947304SEvan Yan io_request = &entry->io_req; 261226947304SEvan Yan 261326947304SEvan Yan if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) { 261426947304SEvan Yan DEBUG0("Failed to map config space!\n"); 261526947304SEvan Yan entry->error = PCICFG_FAILURE; 261626947304SEvan Yan return (DDI_WALK_TERMINATE); 261726947304SEvan Yan } 261826947304SEvan Yan 261926947304SEvan Yan header_type = pci_config_get8(handle, PCI_CONF_HEADER); 262026947304SEvan Yan 262126947304SEvan Yan /* 262226947304SEvan Yan * If its a bridge - just record the highest bus seen 262326947304SEvan Yan */ 262426947304SEvan Yan if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) { 262526947304SEvan Yan 262626947304SEvan Yan if (entry->highest_bus < pci_config_get8(handle, 262726947304SEvan Yan PCI_BCNF_SECBUS)) { 262826947304SEvan Yan entry->highest_bus = 262926947304SEvan Yan pci_config_get8(handle, PCI_BCNF_SECBUS); 263026947304SEvan Yan } 263126947304SEvan Yan 263226947304SEvan Yan (void) pcicfg_config_teardown(&handle); 263326947304SEvan Yan entry->error = PCICFG_FAILURE; 263426947304SEvan Yan return (DDI_WALK_CONTINUE); 263526947304SEvan Yan } else { 263626947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 263726947304SEvan Yan DDI_PROP_DONTPASS, "reg", (caddr_t)&pci_rp, 263826947304SEvan Yan &length) != DDI_PROP_SUCCESS) { 263926947304SEvan Yan /* 264026947304SEvan Yan * If one node in (the subtree of nodes) 264126947304SEvan Yan * does'nt have a "reg" property fail the 264226947304SEvan Yan * allocation. 264326947304SEvan Yan */ 264426947304SEvan Yan entry->memory_len = 0; 264526947304SEvan Yan entry->io_len = 0; 264626947304SEvan Yan entry->error = PCICFG_FAILURE; 264726947304SEvan Yan return (DDI_WALK_TERMINATE); 264826947304SEvan Yan } 264926947304SEvan Yan /* 265026947304SEvan Yan * For each "reg" property with a length, add that to the 265126947304SEvan Yan * total memory (or I/O) to allocate. 265226947304SEvan Yan */ 265326947304SEvan Yan rcount = length / sizeof (pci_regspec_t); 265426947304SEvan Yan 265526947304SEvan Yan for (i = 0; i < rcount; i++) { 265626947304SEvan Yan 265726947304SEvan Yan switch (PCI_REG_ADDR_G(pci_rp[i].pci_phys_hi)) { 265826947304SEvan Yan 265926947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_MEM32): 266026947304SEvan Yan mem_request->ra_len = 266126947304SEvan Yan pci_rp[i].pci_size_low + 266226947304SEvan Yan PCICFG_ROUND_UP(mem_request->ra_len, 266326947304SEvan Yan pci_rp[i].pci_size_low); 266426947304SEvan Yan DEBUG1("ADDING 32 --->0x%x\n", 266526947304SEvan Yan pci_rp[i].pci_size_low); 266626947304SEvan Yan 266726947304SEvan Yan break; 266826947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_MEM64): 266926947304SEvan Yan mem_request->ra_len = 267026947304SEvan Yan pci_rp[i].pci_size_low + 267126947304SEvan Yan PCICFG_ROUND_UP(mem_request->ra_len, 267226947304SEvan Yan pci_rp[i].pci_size_low); 267326947304SEvan Yan DEBUG1("ADDING 64 --->0x%x\n", 267426947304SEvan Yan pci_rp[i].pci_size_low); 267526947304SEvan Yan 267626947304SEvan Yan break; 267726947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_IO): 267826947304SEvan Yan io_request->ra_len = 267926947304SEvan Yan pci_rp[i].pci_size_low + 268026947304SEvan Yan PCICFG_ROUND_UP(io_request->ra_len, 268126947304SEvan Yan pci_rp[i].pci_size_low); 268226947304SEvan Yan DEBUG1("ADDING I/O --->0x%x\n", 268326947304SEvan Yan pci_rp[i].pci_size_low); 268426947304SEvan Yan break; 268526947304SEvan Yan default: 268626947304SEvan Yan /* Config space register - not included */ 268726947304SEvan Yan break; 268826947304SEvan Yan } 268926947304SEvan Yan } 269026947304SEvan Yan 269126947304SEvan Yan /* 269226947304SEvan Yan * free the memory allocated by ddi_getlongprop 269326947304SEvan Yan */ 269426947304SEvan Yan kmem_free(pci_rp, length); 269526947304SEvan Yan 269626947304SEvan Yan /* 269726947304SEvan Yan * continue the walk to the next sibling to sum memory 269826947304SEvan Yan */ 269926947304SEvan Yan 270026947304SEvan Yan (void) pcicfg_config_teardown(&handle); 270126947304SEvan Yan 270226947304SEvan Yan return (DDI_WALK_CONTINUE); 270326947304SEvan Yan } 270426947304SEvan Yan } 270526947304SEvan Yan 270626947304SEvan Yan static int 270726947304SEvan Yan pcicfg_find_resource_end(dev_info_t *dip, void *hdl) 270826947304SEvan Yan { 270926947304SEvan Yan pcicfg_phdl_t *entry_p = (pcicfg_phdl_t *)hdl; 271026947304SEvan Yan pci_regspec_t *pci_ap; 271126947304SEvan Yan pcicfg_range_t *ranges; 271226947304SEvan Yan int length; 271326947304SEvan Yan int rcount; 271426947304SEvan Yan int i; 271526947304SEvan Yan 271626947304SEvan Yan entry_p->error = PCICFG_SUCCESS; 271726947304SEvan Yan 271826947304SEvan Yan if (dip == entry_p->dip) { 271926947304SEvan Yan DEBUG0("Don't include parent bridge node\n"); 272026947304SEvan Yan return (DDI_WALK_CONTINUE); 272126947304SEvan Yan } 272226947304SEvan Yan 272326947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 272426947304SEvan Yan DDI_PROP_DONTPASS, "ranges", 272526947304SEvan Yan (caddr_t)&ranges, &length) != DDI_PROP_SUCCESS) { 272626947304SEvan Yan DEBUG0("Node doesn't have ranges\n"); 272726947304SEvan Yan goto ap; 272826947304SEvan Yan } 272926947304SEvan Yan 273026947304SEvan Yan rcount = length / sizeof (pcicfg_range_t); 273126947304SEvan Yan 273226947304SEvan Yan for (i = 0; i < rcount; i++) { 273326947304SEvan Yan uint64_t base; 273426947304SEvan Yan uint64_t mid = ranges[i].child_mid; 273526947304SEvan Yan uint64_t lo = ranges[i].child_lo; 273626947304SEvan Yan uint64_t size = ranges[i].size_lo; 273726947304SEvan Yan 273826947304SEvan Yan switch (PCI_REG_ADDR_G(ranges[i].child_hi)) { 273926947304SEvan Yan 274026947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_MEM32): 274126947304SEvan Yan base = entry_p->memory_base; 274226947304SEvan Yan entry_p->memory_base = MAX(base, lo + size); 274326947304SEvan Yan break; 274426947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_MEM64): 274526947304SEvan Yan base = entry_p->memory_base; 274626947304SEvan Yan entry_p->memory_base = MAX(base, 274726947304SEvan Yan PCICFG_LADDR(lo, mid) + size); 274826947304SEvan Yan break; 274926947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_IO): 275026947304SEvan Yan base = entry_p->io_base; 275126947304SEvan Yan entry_p->io_base = MAX(base, lo + size); 275226947304SEvan Yan break; 275326947304SEvan Yan } 275426947304SEvan Yan } 275526947304SEvan Yan 275626947304SEvan Yan kmem_free(ranges, length); 275726947304SEvan Yan return (DDI_WALK_CONTINUE); 275826947304SEvan Yan 275926947304SEvan Yan ap: if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 276026947304SEvan Yan DDI_PROP_DONTPASS, "assigned-addresses", 276126947304SEvan Yan (caddr_t)&pci_ap, &length) != DDI_PROP_SUCCESS) { 276226947304SEvan Yan DEBUG0("Node doesn't have assigned-addresses\n"); 276326947304SEvan Yan return (DDI_WALK_CONTINUE); 276426947304SEvan Yan } 276526947304SEvan Yan 276626947304SEvan Yan rcount = length / sizeof (pci_regspec_t); 276726947304SEvan Yan 276826947304SEvan Yan for (i = 0; i < rcount; i++) { 276926947304SEvan Yan 277026947304SEvan Yan switch (PCI_REG_ADDR_G(pci_ap[i].pci_phys_hi)) { 277126947304SEvan Yan 277226947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_MEM32): 277326947304SEvan Yan if ((pci_ap[i].pci_phys_low + 277426947304SEvan Yan pci_ap[i].pci_size_low) > 277526947304SEvan Yan entry_p->memory_base) { 277626947304SEvan Yan entry_p->memory_base = 277726947304SEvan Yan pci_ap[i].pci_phys_low + 277826947304SEvan Yan pci_ap[i].pci_size_low; 277926947304SEvan Yan } 278026947304SEvan Yan break; 278126947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_MEM64): 278226947304SEvan Yan if ((PCICFG_LADDR(pci_ap[i].pci_phys_low, 278326947304SEvan Yan pci_ap[i].pci_phys_mid) + 278426947304SEvan Yan pci_ap[i].pci_size_low) > 278526947304SEvan Yan entry_p->memory_base) { 278626947304SEvan Yan entry_p->memory_base = PCICFG_LADDR( 278726947304SEvan Yan pci_ap[i].pci_phys_low, 278826947304SEvan Yan pci_ap[i].pci_phys_mid) + 278926947304SEvan Yan pci_ap[i].pci_size_low; 279026947304SEvan Yan } 279126947304SEvan Yan break; 279226947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_IO): 279326947304SEvan Yan if ((pci_ap[i].pci_phys_low + 279426947304SEvan Yan pci_ap[i].pci_size_low) > 279526947304SEvan Yan entry_p->io_base) { 279626947304SEvan Yan entry_p->io_base = 279726947304SEvan Yan pci_ap[i].pci_phys_low + 279826947304SEvan Yan pci_ap[i].pci_size_low; 279926947304SEvan Yan } 280026947304SEvan Yan break; 280126947304SEvan Yan } 280226947304SEvan Yan } 280326947304SEvan Yan 280426947304SEvan Yan /* 280526947304SEvan Yan * free the memory allocated by ddi_getlongprop 280626947304SEvan Yan */ 280726947304SEvan Yan kmem_free(pci_ap, length); 280826947304SEvan Yan 280926947304SEvan Yan /* 281026947304SEvan Yan * continue the walk to the next sibling to sum memory 281126947304SEvan Yan */ 281226947304SEvan Yan return (DDI_WALK_CONTINUE); 281326947304SEvan Yan } 281426947304SEvan Yan 281526947304SEvan Yan static int 281626947304SEvan Yan pcicfg_free_bridge_resources(dev_info_t *dip) 281726947304SEvan Yan { 281826947304SEvan Yan pcicfg_range_t *ranges; 281926947304SEvan Yan uint_t *bus; 282026947304SEvan Yan int k; 282126947304SEvan Yan int length; 282226947304SEvan Yan int i; 282326947304SEvan Yan 282426947304SEvan Yan 282526947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 282626947304SEvan Yan DDI_PROP_DONTPASS, "ranges", (caddr_t)&ranges, 282726947304SEvan Yan &length) != DDI_PROP_SUCCESS) { 282826947304SEvan Yan DEBUG0("Failed to read ranges property\n"); 282926947304SEvan Yan if (ddi_get_child(dip)) { 283026947304SEvan Yan cmn_err(CE_WARN, "No ranges property found for %s", 283126947304SEvan Yan ddi_get_name(dip)); 283226947304SEvan Yan /* 283326947304SEvan Yan * strictly speaking, we can check for children with 283426947304SEvan Yan * assigned-addresses but for now it is better to 283526947304SEvan Yan * be conservative and assume that if there are child 283626947304SEvan Yan * nodes, then they do consume PCI memory or IO 283726947304SEvan Yan * resources, Hence return failure. 283826947304SEvan Yan */ 283926947304SEvan Yan return (PCICFG_FAILURE); 284026947304SEvan Yan } 284126947304SEvan Yan length = 0; 284226947304SEvan Yan 284326947304SEvan Yan } 284426947304SEvan Yan 284526947304SEvan Yan for (i = 0; i < length / sizeof (pcicfg_range_t); i++) { 284626947304SEvan Yan if (ranges[i].size_lo != 0 || 284726947304SEvan Yan ranges[i].size_hi != 0) { 284826947304SEvan Yan switch (ranges[i].parent_hi & PCI_REG_ADDR_M) { 284926947304SEvan Yan case PCI_ADDR_IO: 285026947304SEvan Yan DEBUG2("Free I/O " 285126947304SEvan Yan "base/length = [0x%x]/[0x%x]\n", 285226947304SEvan Yan ranges[i].child_lo, 285326947304SEvan Yan ranges[i].size_lo); 285426947304SEvan Yan if (ndi_ra_free(ddi_get_parent(dip), 285526947304SEvan Yan (uint64_t)ranges[i].child_lo, 285626947304SEvan Yan (uint64_t)ranges[i].size_lo, 285726947304SEvan Yan NDI_RA_TYPE_IO, NDI_RA_PASS) 285826947304SEvan Yan != NDI_SUCCESS) { 285926947304SEvan Yan DEBUG0("Trouble freeing " 286026947304SEvan Yan "PCI i/o space\n"); 286126947304SEvan Yan kmem_free(ranges, length); 286226947304SEvan Yan return (PCICFG_FAILURE); 286326947304SEvan Yan } 286426947304SEvan Yan break; 286526947304SEvan Yan case PCI_ADDR_MEM32: 286626947304SEvan Yan case PCI_ADDR_MEM64: 286726947304SEvan Yan DEBUG3("Free Memory base/length = " 286826947304SEvan Yan "[0x%x.%x]/[0x%x]\n", 286926947304SEvan Yan ranges[i].child_mid, 287026947304SEvan Yan ranges[i].child_lo, 287126947304SEvan Yan ranges[i].size_lo) 287226947304SEvan Yan if (ndi_ra_free(ddi_get_parent(dip), 287326947304SEvan Yan PCICFG_LADDR(ranges[i].child_lo, 287426947304SEvan Yan ranges[i].child_mid), 287526947304SEvan Yan (uint64_t)ranges[i].size_lo, 287626947304SEvan Yan NDI_RA_TYPE_MEM, NDI_RA_PASS) 287726947304SEvan Yan != NDI_SUCCESS) { 287826947304SEvan Yan DEBUG0("Trouble freeing " 287926947304SEvan Yan "PCI memory space\n"); 288026947304SEvan Yan kmem_free(ranges, length); 288126947304SEvan Yan return (PCICFG_FAILURE); 288226947304SEvan Yan } 288326947304SEvan Yan break; 288426947304SEvan Yan default: 288526947304SEvan Yan DEBUG0("Unknown memory space\n"); 288626947304SEvan Yan break; 288726947304SEvan Yan } 288826947304SEvan Yan } 288926947304SEvan Yan } 289026947304SEvan Yan 289126947304SEvan Yan if (length) 289226947304SEvan Yan kmem_free(ranges, length); 289326947304SEvan Yan 289426947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 289526947304SEvan Yan DDI_PROP_DONTPASS, "bus-range", (caddr_t)&bus, 289626947304SEvan Yan &k) != DDI_PROP_SUCCESS) { 289726947304SEvan Yan DEBUG0("Failed to read bus-range property\n"); 289826947304SEvan Yan return (PCICFG_FAILURE); 289926947304SEvan Yan } 290026947304SEvan Yan 290126947304SEvan Yan DEBUG2("Need to free bus [%d] range [%d]\n", 290226947304SEvan Yan bus[0], bus[1] - bus[0] + 1); 290326947304SEvan Yan 290426947304SEvan Yan if (ndi_ra_free(ddi_get_parent(dip), 290526947304SEvan Yan (uint64_t)bus[0], (uint64_t)(bus[1] - bus[0] + 1), 290626947304SEvan Yan NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS) != NDI_SUCCESS) { 290726947304SEvan Yan /*EMPTY*/ 290826947304SEvan Yan DEBUG0("Failed to free a bus number\n"); 290926947304SEvan Yan } 291026947304SEvan Yan /* 291126947304SEvan Yan * Don't forget to free up memory from ddi_getlongprop 291226947304SEvan Yan */ 291326947304SEvan Yan kmem_free((caddr_t)bus, k); 291426947304SEvan Yan 291526947304SEvan Yan return (PCICFG_SUCCESS); 291626947304SEvan Yan } 291726947304SEvan Yan 291826947304SEvan Yan static int 291926947304SEvan Yan pcicfg_free_device_resources(dev_info_t *dip, pcicfg_flags_t flags) 292026947304SEvan Yan { 292126947304SEvan Yan pci_regspec_t *assigned; 292226947304SEvan Yan 292326947304SEvan Yan int length; 292426947304SEvan Yan int acount; 292526947304SEvan Yan int i; 292626947304SEvan Yan 292726947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 292826947304SEvan Yan DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned, 292926947304SEvan Yan &length) != DDI_PROP_SUCCESS) { 293026947304SEvan Yan DEBUG0("Failed to read assigned-addresses property\n"); 293126947304SEvan Yan return (PCICFG_FAILURE); 293226947304SEvan Yan } 293326947304SEvan Yan 293426947304SEvan Yan /* 293526947304SEvan Yan * For each "assigned-addresses" property entry with a length, 293626947304SEvan Yan * call the memory allocation routines to return the 293726947304SEvan Yan * resource. 293826947304SEvan Yan */ 293926947304SEvan Yan acount = length / sizeof (pci_regspec_t); 294026947304SEvan Yan for (i = 0; i < acount; i++) { 294126947304SEvan Yan /* 294226947304SEvan Yan * Workaround for Devconf (x86) bug to skip extra entries 294326947304SEvan Yan * beyond the PCI_CONF_BASE5 offset. But we want to free up 294426947304SEvan Yan * any memory for expansion roms if allocated. 294526947304SEvan Yan */ 294626947304SEvan Yan if ((PCI_REG_REG_G(assigned[i].pci_phys_hi) > PCI_CONF_BASE5) && 294726947304SEvan Yan (PCI_REG_REG_G(assigned[i].pci_phys_hi) != PCI_CONF_ROM)) 294826947304SEvan Yan break; 294926947304SEvan Yan 295026947304SEvan Yan if (pcicfg_free_resource(dip, assigned[i], flags)) { 295126947304SEvan Yan DEBUG1("pcicfg_free_device_resources - Trouble freeing " 295226947304SEvan Yan "%x\n", assigned[i].pci_phys_hi); 295326947304SEvan Yan /* 295426947304SEvan Yan * Don't forget to free up memory from ddi_getlongprop 295526947304SEvan Yan */ 295626947304SEvan Yan kmem_free((caddr_t)assigned, length); 295726947304SEvan Yan 295826947304SEvan Yan return (PCICFG_FAILURE); 295926947304SEvan Yan } 296026947304SEvan Yan } 296126947304SEvan Yan kmem_free(assigned, length); 296226947304SEvan Yan return (PCICFG_SUCCESS); 296326947304SEvan Yan } 296426947304SEvan Yan 296526947304SEvan Yan static int 296626947304SEvan Yan pcicfg_free_resources(dev_info_t *dip, pcicfg_flags_t flags) 296726947304SEvan Yan { 296826947304SEvan Yan ddi_acc_handle_t handle; 296926947304SEvan Yan uint8_t header_type; 297026947304SEvan Yan 297126947304SEvan Yan if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) { 297226947304SEvan Yan DEBUG0("Failed to map config space!\n"); 297326947304SEvan Yan return (PCICFG_FAILURE); 297426947304SEvan Yan } 297526947304SEvan Yan 297626947304SEvan Yan header_type = pci_config_get8(handle, PCI_CONF_HEADER); 297726947304SEvan Yan 297826947304SEvan Yan (void) pci_config_teardown(&handle); 297926947304SEvan Yan 298026947304SEvan Yan /* 298126947304SEvan Yan * A different algorithm is used for bridges and leaf devices. 298226947304SEvan Yan */ 298326947304SEvan Yan if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) { 298426947304SEvan Yan /* 298526947304SEvan Yan * We only support readonly probing for leaf devices. 298626947304SEvan Yan */ 298726947304SEvan Yan if (flags & PCICFG_FLAG_READ_ONLY) 298826947304SEvan Yan return (PCICFG_FAILURE); 298926947304SEvan Yan 299026947304SEvan Yan if (pcicfg_free_bridge_resources(dip) != PCICFG_SUCCESS) { 299126947304SEvan Yan DEBUG0("Failed freeing up bridge resources\n"); 299226947304SEvan Yan return (PCICFG_FAILURE); 299326947304SEvan Yan } 299426947304SEvan Yan } else { 299526947304SEvan Yan if (pcicfg_free_device_resources(dip, flags) 299626947304SEvan Yan != PCICFG_SUCCESS) { 299726947304SEvan Yan DEBUG0("Failed freeing up device resources\n"); 299826947304SEvan Yan return (PCICFG_FAILURE); 299926947304SEvan Yan } 300026947304SEvan Yan } 300126947304SEvan Yan return (PCICFG_SUCCESS); 300226947304SEvan Yan } 300326947304SEvan Yan 300426947304SEvan Yan #ifndef _DONT_USE_1275_GENERIC_NAMES 300526947304SEvan Yan static char * 300626947304SEvan Yan pcicfg_get_class_name(uint32_t classcode) 300726947304SEvan Yan { 300826947304SEvan Yan struct pcicfg_name_entry *ptr; 300926947304SEvan Yan 301026947304SEvan Yan for (ptr = &pcicfg_class_lookup[0]; ptr->name != NULL; ptr++) { 301126947304SEvan Yan if (ptr->class_code == classcode) { 301226947304SEvan Yan return (ptr->name); 301326947304SEvan Yan } 301426947304SEvan Yan } 301526947304SEvan Yan return (NULL); 301626947304SEvan Yan } 301726947304SEvan Yan #endif /* _DONT_USE_1275_GENERIC_NAMES */ 301826947304SEvan Yan 301926947304SEvan Yan static dev_info_t * 302026947304SEvan Yan pcicfg_devi_find(dev_info_t *dip, uint_t device, uint_t function) 302126947304SEvan Yan { 302226947304SEvan Yan struct pcicfg_find_ctrl ctrl; 302326947304SEvan Yan int count; 302426947304SEvan Yan 302526947304SEvan Yan ctrl.device = device; 302626947304SEvan Yan ctrl.function = function; 302726947304SEvan Yan ctrl.dip = NULL; 302826947304SEvan Yan 302926947304SEvan Yan ndi_devi_enter(dip, &count); 303026947304SEvan Yan ddi_walk_devs(ddi_get_child(dip), pcicfg_match_dev, (void *)&ctrl); 303126947304SEvan Yan ndi_devi_exit(dip, count); 303226947304SEvan Yan 303326947304SEvan Yan return (ctrl.dip); 303426947304SEvan Yan } 303526947304SEvan Yan 303626947304SEvan Yan static int 303726947304SEvan Yan pcicfg_match_dev(dev_info_t *dip, void *hdl) 303826947304SEvan Yan { 303926947304SEvan Yan struct pcicfg_find_ctrl *ctrl = (struct pcicfg_find_ctrl *)hdl; 304026947304SEvan Yan pci_regspec_t *pci_rp; 304126947304SEvan Yan int length; 304226947304SEvan Yan int pci_dev; 304326947304SEvan Yan int pci_func; 304426947304SEvan Yan 304526947304SEvan Yan if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 304626947304SEvan Yan DDI_PROP_DONTPASS, "reg", (int **)&pci_rp, 304726947304SEvan Yan (uint_t *)&length) != DDI_PROP_SUCCESS) { 304826947304SEvan Yan ctrl->dip = NULL; 304926947304SEvan Yan return (DDI_WALK_TERMINATE); 305026947304SEvan Yan } 305126947304SEvan Yan 305226947304SEvan Yan /* get the PCI device address info */ 305326947304SEvan Yan pci_dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi); 305426947304SEvan Yan pci_func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi); 305526947304SEvan Yan 305626947304SEvan Yan /* 305726947304SEvan Yan * free the memory allocated by ddi_prop_lookup_int_array 305826947304SEvan Yan */ 305926947304SEvan Yan ddi_prop_free(pci_rp); 306026947304SEvan Yan 306126947304SEvan Yan 306226947304SEvan Yan if ((pci_dev == ctrl->device) && (pci_func == ctrl->function)) { 306326947304SEvan Yan /* found the match for the specified device address */ 306426947304SEvan Yan ctrl->dip = dip; 306526947304SEvan Yan return (DDI_WALK_TERMINATE); 306626947304SEvan Yan } 306726947304SEvan Yan 306826947304SEvan Yan /* 306926947304SEvan Yan * continue the walk to the next sibling to look for a match. 307026947304SEvan Yan */ 307126947304SEvan Yan return (DDI_WALK_PRUNECHILD); 307226947304SEvan Yan } 307326947304SEvan Yan 307426947304SEvan Yan static int 307526947304SEvan Yan pcicfg_update_assigned_prop(dev_info_t *dip, pci_regspec_t *newone) 307626947304SEvan Yan { 307726947304SEvan Yan int alen; 307826947304SEvan Yan pci_regspec_t *assigned; 307926947304SEvan Yan caddr_t newreg; 308026947304SEvan Yan uint_t status; 308126947304SEvan Yan 308226947304SEvan Yan DEBUG0("pcicfg_update_assigned_prop()\n"); 308326947304SEvan Yan status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 308426947304SEvan Yan "assigned-addresses", (caddr_t)&assigned, &alen); 308526947304SEvan Yan switch (status) { 308626947304SEvan Yan case DDI_PROP_SUCCESS: 308726947304SEvan Yan break; 308826947304SEvan Yan case DDI_PROP_NO_MEMORY: 308926947304SEvan Yan DEBUG0("no memory for assigned-addresses property\n"); 309026947304SEvan Yan return (PCICFG_FAILURE); 309126947304SEvan Yan default: 309226947304SEvan Yan (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, 309326947304SEvan Yan "assigned-addresses", (int *)newone, 309426947304SEvan Yan sizeof (*newone)/sizeof (int)); 309526947304SEvan Yan 309626947304SEvan Yan (void) pcicfg_dump_assigned(dip); 309726947304SEvan Yan 309826947304SEvan Yan return (PCICFG_SUCCESS); 309926947304SEvan Yan } 310026947304SEvan Yan 310126947304SEvan Yan /* 310226947304SEvan Yan * Allocate memory for the existing 310326947304SEvan Yan * assigned-addresses(s) plus one and then 310426947304SEvan Yan * build it. 310526947304SEvan Yan */ 310626947304SEvan Yan 310726947304SEvan Yan newreg = kmem_zalloc(alen+sizeof (*newone), KM_SLEEP); 310826947304SEvan Yan 310926947304SEvan Yan bcopy(assigned, newreg, alen); 311026947304SEvan Yan bcopy(newone, newreg + alen, sizeof (*newone)); 311126947304SEvan Yan 311226947304SEvan Yan /* 311326947304SEvan Yan * Write out the new "assigned-addresses" spec 311426947304SEvan Yan */ 311526947304SEvan Yan (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, 311626947304SEvan Yan "assigned-addresses", (int *)newreg, 311726947304SEvan Yan (alen + sizeof (*newone))/sizeof (int)); 311826947304SEvan Yan 311926947304SEvan Yan kmem_free((caddr_t)newreg, alen+sizeof (*newone)); 312026947304SEvan Yan 312126947304SEvan Yan /* 312226947304SEvan Yan * Don't forget to free up memory from ddi_getlongprop 312326947304SEvan Yan */ 312426947304SEvan Yan kmem_free((caddr_t)assigned, alen); 312526947304SEvan Yan 312626947304SEvan Yan (void) pcicfg_dump_assigned(dip); 312726947304SEvan Yan 312826947304SEvan Yan return (PCICFG_SUCCESS); 312926947304SEvan Yan } 313026947304SEvan Yan static int 313126947304SEvan Yan pcicfg_update_ranges_prop(dev_info_t *dip, pcicfg_range_t *addition) 313226947304SEvan Yan { 313326947304SEvan Yan int rlen; 313426947304SEvan Yan pcicfg_range_t *ranges; 313526947304SEvan Yan caddr_t newreg; 313626947304SEvan Yan uint_t status; 313726947304SEvan Yan 313826947304SEvan Yan status = ddi_getlongprop(DDI_DEV_T_ANY, 313926947304SEvan Yan dip, DDI_PROP_DONTPASS, "ranges", (caddr_t)&ranges, &rlen); 314026947304SEvan Yan 314126947304SEvan Yan 314226947304SEvan Yan switch (status) { 314326947304SEvan Yan case DDI_PROP_SUCCESS: 314426947304SEvan Yan break; 314526947304SEvan Yan case DDI_PROP_NO_MEMORY: 314626947304SEvan Yan DEBUG0("ranges present, but unable to get memory\n"); 314726947304SEvan Yan return (PCICFG_FAILURE); 314826947304SEvan Yan default: 314926947304SEvan Yan DEBUG0("no ranges property - creating one\n"); 315026947304SEvan Yan if (ndi_prop_update_int_array(DDI_DEV_T_NONE, 315126947304SEvan Yan dip, "ranges", (int *)addition, 315226947304SEvan Yan sizeof (pcicfg_range_t)/sizeof (int)) 315326947304SEvan Yan != DDI_SUCCESS) { 315426947304SEvan Yan DEBUG0("Did'nt create ranges property\n"); 315526947304SEvan Yan return (PCICFG_FAILURE); 315626947304SEvan Yan } 315726947304SEvan Yan return (PCICFG_SUCCESS); 315826947304SEvan Yan } 315926947304SEvan Yan 316026947304SEvan Yan /* 316126947304SEvan Yan * Allocate memory for the existing reg(s) plus one and then 316226947304SEvan Yan * build it. 316326947304SEvan Yan */ 316426947304SEvan Yan newreg = kmem_zalloc(rlen + sizeof (pcicfg_range_t), KM_SLEEP); 316526947304SEvan Yan 316626947304SEvan Yan bcopy(ranges, newreg, rlen); 316726947304SEvan Yan bcopy(addition, newreg + rlen, sizeof (pcicfg_range_t)); 316826947304SEvan Yan 316926947304SEvan Yan /* 317026947304SEvan Yan * Write out the new "ranges" property 317126947304SEvan Yan */ 317226947304SEvan Yan (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, 317326947304SEvan Yan dip, "ranges", (int *)newreg, 317426947304SEvan Yan (rlen + sizeof (pcicfg_range_t))/sizeof (int)); 317526947304SEvan Yan 317626947304SEvan Yan kmem_free((caddr_t)newreg, rlen+sizeof (pcicfg_range_t)); 317726947304SEvan Yan 317826947304SEvan Yan kmem_free((caddr_t)ranges, rlen); 317926947304SEvan Yan 318026947304SEvan Yan return (PCICFG_SUCCESS); 318126947304SEvan Yan } 318226947304SEvan Yan 318326947304SEvan Yan static int 318426947304SEvan Yan pcicfg_update_reg_prop(dev_info_t *dip, uint32_t regvalue, uint_t reg_offset) 318526947304SEvan Yan { 318626947304SEvan Yan int rlen; 318726947304SEvan Yan pci_regspec_t *reg; 318826947304SEvan Yan caddr_t newreg; 318926947304SEvan Yan uint32_t hiword; 319026947304SEvan Yan pci_regspec_t addition; 319126947304SEvan Yan uint32_t size; 319226947304SEvan Yan uint_t status; 319326947304SEvan Yan 319426947304SEvan Yan status = ddi_getlongprop(DDI_DEV_T_ANY, 319526947304SEvan Yan dip, DDI_PROP_DONTPASS, "reg", (caddr_t)®, &rlen); 319626947304SEvan Yan 319726947304SEvan Yan switch (status) { 319826947304SEvan Yan case DDI_PROP_SUCCESS: 319926947304SEvan Yan break; 320026947304SEvan Yan case DDI_PROP_NO_MEMORY: 320126947304SEvan Yan DEBUG0("reg present, but unable to get memory\n"); 320226947304SEvan Yan return (PCICFG_FAILURE); 320326947304SEvan Yan default: 320426947304SEvan Yan DEBUG0("no reg property\n"); 320526947304SEvan Yan return (PCICFG_FAILURE); 320626947304SEvan Yan } 320726947304SEvan Yan 320826947304SEvan Yan /* 320926947304SEvan Yan * Allocate memory for the existing reg(s) plus one and then 321026947304SEvan Yan * build it. 321126947304SEvan Yan */ 321226947304SEvan Yan newreg = kmem_zalloc(rlen+sizeof (pci_regspec_t), KM_SLEEP); 321326947304SEvan Yan 321426947304SEvan Yan /* 321526947304SEvan Yan * Build the regspec, then add it to the existing one(s) 321626947304SEvan Yan */ 321726947304SEvan Yan 321826947304SEvan Yan hiword = PCICFG_MAKE_REG_HIGH(PCI_REG_BUS_G(reg->pci_phys_hi), 321926947304SEvan Yan PCI_REG_DEV_G(reg->pci_phys_hi), 322026947304SEvan Yan PCI_REG_FUNC_G(reg->pci_phys_hi), reg_offset); 322126947304SEvan Yan 322226947304SEvan Yan if (reg_offset == PCI_CONF_ROM) { 322326947304SEvan Yan size = (~(PCI_BASE_ROM_ADDR_M & regvalue))+1; 322426947304SEvan Yan hiword |= PCI_ADDR_MEM32; 322526947304SEvan Yan } else { 322626947304SEvan Yan size = (~(PCI_BASE_M_ADDR_M & regvalue))+1; 322726947304SEvan Yan 322826947304SEvan Yan if ((PCI_BASE_SPACE_M & regvalue) == PCI_BASE_SPACE_MEM) { 322926947304SEvan Yan if ((PCI_BASE_TYPE_M & regvalue) == PCI_BASE_TYPE_MEM) { 323026947304SEvan Yan hiword |= PCI_ADDR_MEM32; 323126947304SEvan Yan } else if ((PCI_BASE_TYPE_M & regvalue) 323226947304SEvan Yan == PCI_BASE_TYPE_ALL) { 323326947304SEvan Yan hiword |= PCI_ADDR_MEM64; 323426947304SEvan Yan } 323526947304SEvan Yan } else { 323626947304SEvan Yan hiword |= PCI_ADDR_IO; 323726947304SEvan Yan } 323826947304SEvan Yan } 323926947304SEvan Yan 324026947304SEvan Yan addition.pci_phys_hi = hiword; 324126947304SEvan Yan addition.pci_phys_mid = 0; 324226947304SEvan Yan addition.pci_phys_low = 0; 324326947304SEvan Yan addition.pci_size_hi = 0; 324426947304SEvan Yan addition.pci_size_low = size; 324526947304SEvan Yan 324626947304SEvan Yan bcopy(reg, newreg, rlen); 324726947304SEvan Yan bcopy(&addition, newreg + rlen, sizeof (pci_regspec_t)); 324826947304SEvan Yan 324926947304SEvan Yan /* 325026947304SEvan Yan * Write out the new "reg" property 325126947304SEvan Yan */ 325226947304SEvan Yan (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, 325326947304SEvan Yan dip, "reg", (int *)newreg, 325426947304SEvan Yan (rlen + sizeof (pci_regspec_t))/sizeof (int)); 325526947304SEvan Yan 325626947304SEvan Yan kmem_free((caddr_t)newreg, rlen+sizeof (pci_regspec_t)); 325726947304SEvan Yan kmem_free((caddr_t)reg, rlen); 325826947304SEvan Yan 325926947304SEvan Yan return (PCICFG_SUCCESS); 326026947304SEvan Yan } 326126947304SEvan Yan static int 326226947304SEvan Yan pcicfg_update_available_prop(dev_info_t *dip, pci_regspec_t *newone) 326326947304SEvan Yan { 326426947304SEvan Yan int alen; 326526947304SEvan Yan pci_regspec_t *avail_p; 326626947304SEvan Yan caddr_t new_avail; 326726947304SEvan Yan uint_t status; 326826947304SEvan Yan 326926947304SEvan Yan DEBUG2("pcicfg_update_available_prop() - Address %lx Size %x\n", 327026947304SEvan Yan newone->pci_phys_low, newone->pci_size_low); 327126947304SEvan Yan status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 327226947304SEvan Yan "available", (caddr_t)&avail_p, &alen); 327326947304SEvan Yan switch (status) { 327426947304SEvan Yan case DDI_PROP_SUCCESS: 327526947304SEvan Yan break; 327626947304SEvan Yan case DDI_PROP_NO_MEMORY: 327726947304SEvan Yan DEBUG0("no memory for available property\n"); 327826947304SEvan Yan return (PCICFG_FAILURE); 327926947304SEvan Yan default: 328026947304SEvan Yan (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, 328126947304SEvan Yan "available", (int *)newone, 328226947304SEvan Yan sizeof (*newone)/sizeof (int)); 328326947304SEvan Yan 328426947304SEvan Yan return (PCICFG_SUCCESS); 328526947304SEvan Yan } 328626947304SEvan Yan 328726947304SEvan Yan /* 328826947304SEvan Yan * Allocate memory for the existing available plus one and then 328926947304SEvan Yan * build it. 329026947304SEvan Yan */ 329126947304SEvan Yan new_avail = kmem_zalloc(alen+sizeof (*newone), KM_SLEEP); 329226947304SEvan Yan 329326947304SEvan Yan bcopy(avail_p, new_avail, alen); 329426947304SEvan Yan bcopy(newone, new_avail + alen, sizeof (*newone)); 329526947304SEvan Yan 329626947304SEvan Yan /* Write out the new "available" spec */ 329726947304SEvan Yan (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, 329826947304SEvan Yan "available", (int *)new_avail, 329926947304SEvan Yan (alen + sizeof (*newone))/sizeof (int)); 330026947304SEvan Yan 330126947304SEvan Yan kmem_free((caddr_t)new_avail, alen+sizeof (*newone)); 330226947304SEvan Yan 330326947304SEvan Yan /* Don't forget to free up memory from ddi_getlongprop */ 330426947304SEvan Yan kmem_free((caddr_t)avail_p, alen); 330526947304SEvan Yan 330626947304SEvan Yan return (PCICFG_SUCCESS); 330726947304SEvan Yan } 330826947304SEvan Yan 330926947304SEvan Yan static int 331026947304SEvan Yan pcicfg_update_assigned_prop_value(dev_info_t *dip, uint32_t size, 331126947304SEvan Yan uint32_t base, uint32_t base_hi, uint_t reg_offset) 331226947304SEvan Yan { 331326947304SEvan Yan int rlen; 331426947304SEvan Yan pci_regspec_t *reg; 331526947304SEvan Yan uint32_t hiword; 331626947304SEvan Yan pci_regspec_t addition; 331726947304SEvan Yan uint_t status; 331826947304SEvan Yan 331926947304SEvan Yan status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 332026947304SEvan Yan "reg", (caddr_t)®, &rlen); 332126947304SEvan Yan 332226947304SEvan Yan switch (status) { 332326947304SEvan Yan case DDI_PROP_SUCCESS: 332426947304SEvan Yan break; 332526947304SEvan Yan case DDI_PROP_NO_MEMORY: 332626947304SEvan Yan DEBUG0("reg present, but unable to get memory\n"); 332726947304SEvan Yan return (PCICFG_FAILURE); 332826947304SEvan Yan default: 332926947304SEvan Yan /* 333026947304SEvan Yan * Since the config space "reg" entry should have been 333126947304SEvan Yan * created, we expect a "reg" property already 333226947304SEvan Yan * present here. 333326947304SEvan Yan */ 333426947304SEvan Yan DEBUG0("no reg property\n"); 333526947304SEvan Yan return (PCICFG_FAILURE); 333626947304SEvan Yan } 333726947304SEvan Yan 333826947304SEvan Yan /* 333926947304SEvan Yan * Build the regspec, then add it to the existing one(s) 334026947304SEvan Yan */ 334126947304SEvan Yan 334226947304SEvan Yan hiword = PCICFG_MAKE_REG_HIGH(PCI_REG_BUS_G(reg->pci_phys_hi), 334326947304SEvan Yan PCI_REG_DEV_G(reg->pci_phys_hi), 334426947304SEvan Yan PCI_REG_FUNC_G(reg->pci_phys_hi), reg_offset); 334526947304SEvan Yan 334626947304SEvan Yan hiword |= PCI_REG_REL_M; 334726947304SEvan Yan 334826947304SEvan Yan if (reg_offset == PCI_CONF_ROM) { 334926947304SEvan Yan hiword |= PCI_ADDR_MEM32; 335026947304SEvan Yan 335126947304SEvan Yan base = PCI_BASE_ROM_ADDR_M & base; 335226947304SEvan Yan } else { 335326947304SEvan Yan if ((PCI_BASE_SPACE_M & base) == PCI_BASE_SPACE_MEM) { 335426947304SEvan Yan if ((PCI_BASE_TYPE_M & base) == PCI_BASE_TYPE_MEM) { 335526947304SEvan Yan hiword |= PCI_ADDR_MEM32; 335626947304SEvan Yan } else if ((PCI_BASE_TYPE_M & base) 335726947304SEvan Yan == PCI_BASE_TYPE_ALL) { 335826947304SEvan Yan hiword |= PCI_ADDR_MEM64; 335926947304SEvan Yan } 336026947304SEvan Yan 336126947304SEvan Yan if (base & PCI_BASE_PREF_M) 336226947304SEvan Yan hiword |= PCI_REG_PF_M; 336326947304SEvan Yan 336426947304SEvan Yan base = PCI_BASE_M_ADDR_M & base; 336526947304SEvan Yan } else { 336626947304SEvan Yan hiword |= PCI_ADDR_IO; 336726947304SEvan Yan 336826947304SEvan Yan base = PCI_BASE_IO_ADDR_M & base; 336926947304SEvan Yan base_hi = 0; 337026947304SEvan Yan } 337126947304SEvan Yan } 337226947304SEvan Yan 337326947304SEvan Yan addition.pci_phys_hi = hiword; 337426947304SEvan Yan addition.pci_phys_mid = base_hi; 337526947304SEvan Yan addition.pci_phys_low = base; 337626947304SEvan Yan addition.pci_size_hi = 0; 337726947304SEvan Yan addition.pci_size_low = size; 337826947304SEvan Yan 337926947304SEvan Yan DEBUG3("updating BAR@off %x with %x,%x\n", reg_offset, hiword, size); 338026947304SEvan Yan 338126947304SEvan Yan kmem_free((caddr_t)reg, rlen); 338226947304SEvan Yan 338326947304SEvan Yan return (pcicfg_update_assigned_prop(dip, &addition)); 338426947304SEvan Yan } 338526947304SEvan Yan 338626947304SEvan Yan static void 338726947304SEvan Yan pcicfg_device_on(ddi_acc_handle_t config_handle) 338826947304SEvan Yan { 338926947304SEvan Yan /* 339026947304SEvan Yan * Enable memory, IO, and bus mastership 339126947304SEvan Yan * XXX should we enable parity, SERR#, 339226947304SEvan Yan * fast back-to-back, and addr. stepping? 339326947304SEvan Yan */ 339426947304SEvan Yan pci_config_put16(config_handle, PCI_CONF_COMM, 339526947304SEvan Yan pci_config_get16(config_handle, PCI_CONF_COMM) | 0x7); 339626947304SEvan Yan } 339726947304SEvan Yan 339826947304SEvan Yan static void 339926947304SEvan Yan pcicfg_device_off(ddi_acc_handle_t config_handle) 340026947304SEvan Yan { 340126947304SEvan Yan /* 340226947304SEvan Yan * Disable I/O and memory traffic through the bridge 340326947304SEvan Yan */ 340426947304SEvan Yan pci_config_put16(config_handle, PCI_CONF_COMM, 0x0); 340526947304SEvan Yan } 340626947304SEvan Yan 340726947304SEvan Yan /* 340826947304SEvan Yan * Setup the basic 1275 properties based on information found in the config 340926947304SEvan Yan * header of the PCI device 341026947304SEvan Yan */ 341126947304SEvan Yan static int 341226947304SEvan Yan pcicfg_set_standard_props(dev_info_t *dip, ddi_acc_handle_t config_handle, 341326947304SEvan Yan uint8_t pcie_dev) 341426947304SEvan Yan { 341526947304SEvan Yan int ret; 341626947304SEvan Yan uint16_t val, cap_ptr; 341726947304SEvan Yan uint32_t wordval; 341826947304SEvan Yan uint8_t byteval; 341926947304SEvan Yan 342026947304SEvan Yan /* These two exists only for non-bridges */ 342126947304SEvan Yan if (((pci_config_get8(config_handle, PCI_CONF_HEADER) 342226947304SEvan Yan & PCI_HEADER_TYPE_M) == PCI_HEADER_ZERO) && !pcie_dev) { 342326947304SEvan Yan byteval = pci_config_get8(config_handle, PCI_CONF_MIN_G); 342426947304SEvan Yan if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, 342526947304SEvan Yan "min-grant", byteval)) != DDI_SUCCESS) { 342626947304SEvan Yan return (ret); 342726947304SEvan Yan } 342826947304SEvan Yan 342926947304SEvan Yan byteval = pci_config_get8(config_handle, PCI_CONF_MAX_L); 343026947304SEvan Yan if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, 343126947304SEvan Yan "max-latency", byteval)) != DDI_SUCCESS) { 343226947304SEvan Yan return (ret); 343326947304SEvan Yan } 343426947304SEvan Yan } 343526947304SEvan Yan 343626947304SEvan Yan /* 343726947304SEvan Yan * These should always exist and have the value of the 343826947304SEvan Yan * corresponding register value 343926947304SEvan Yan */ 344026947304SEvan Yan val = pci_config_get16(config_handle, PCI_CONF_VENID); 344126947304SEvan Yan 344226947304SEvan Yan if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, 344326947304SEvan Yan "vendor-id", val)) != DDI_SUCCESS) { 344426947304SEvan Yan return (ret); 344526947304SEvan Yan } 344626947304SEvan Yan val = pci_config_get16(config_handle, PCI_CONF_DEVID); 344726947304SEvan Yan if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, 344826947304SEvan Yan "device-id", val)) != DDI_SUCCESS) { 344926947304SEvan Yan return (ret); 345026947304SEvan Yan } 345126947304SEvan Yan byteval = pci_config_get8(config_handle, PCI_CONF_REVID); 345226947304SEvan Yan if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, 345326947304SEvan Yan "revision-id", byteval)) != DDI_SUCCESS) { 345426947304SEvan Yan return (ret); 345526947304SEvan Yan } 345626947304SEvan Yan 345726947304SEvan Yan wordval = (pci_config_get16(config_handle, PCI_CONF_SUBCLASS)<< 8) | 345826947304SEvan Yan (pci_config_get8(config_handle, PCI_CONF_PROGCLASS)); 345926947304SEvan Yan 346026947304SEvan Yan if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, 346126947304SEvan Yan "class-code", wordval)) != DDI_SUCCESS) { 346226947304SEvan Yan return (ret); 346326947304SEvan Yan } 346426947304SEvan Yan /* devsel-speed starts at the 9th bit */ 346526947304SEvan Yan val = (pci_config_get16(config_handle, 346626947304SEvan Yan PCI_CONF_STAT) & PCI_STAT_DEVSELT) >> 9; 346726947304SEvan Yan if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, 346826947304SEvan Yan "devsel-speed", val)) != DDI_SUCCESS) { 346926947304SEvan Yan return (ret); 347026947304SEvan Yan } 347126947304SEvan Yan 347226947304SEvan Yan /* 347326947304SEvan Yan * The next three are bits set in the status register. The property is 347426947304SEvan Yan * present (but with no value other than its own existence) if the bit 347526947304SEvan Yan * is set, non-existent otherwise 347626947304SEvan Yan */ 347726947304SEvan Yan if ((!pcie_dev) && 347826947304SEvan Yan (pci_config_get16(config_handle, PCI_CONF_STAT) & 347926947304SEvan Yan PCI_STAT_FBBC)) { 348026947304SEvan Yan if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, 348126947304SEvan Yan "fast-back-to-back", 0)) != DDI_SUCCESS) { 348226947304SEvan Yan return (ret); 348326947304SEvan Yan } 348426947304SEvan Yan } 348526947304SEvan Yan if ((!pcie_dev) && 348626947304SEvan Yan (pci_config_get16(config_handle, PCI_CONF_STAT) & 348726947304SEvan Yan PCI_STAT_66MHZ)) { 348826947304SEvan Yan if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, 348926947304SEvan Yan "66mhz-capable", 0)) != DDI_SUCCESS) { 349026947304SEvan Yan return (ret); 349126947304SEvan Yan } 349226947304SEvan Yan } 349326947304SEvan Yan if (pci_config_get16(config_handle, PCI_CONF_STAT) & PCI_STAT_UDF) { 349426947304SEvan Yan if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, 349526947304SEvan Yan "udf-supported", 0)) != DDI_SUCCESS) { 349626947304SEvan Yan return (ret); 349726947304SEvan Yan } 349826947304SEvan Yan } 349926947304SEvan Yan 350026947304SEvan Yan /* 350126947304SEvan Yan * These next three are optional and are not present 350226947304SEvan Yan * if the corresponding register is zero. If the value 350326947304SEvan Yan * is non-zero then the property exists with the value 350426947304SEvan Yan * of the register. 350526947304SEvan Yan */ 350626947304SEvan Yan if ((val = pci_config_get16(config_handle, 350726947304SEvan Yan PCI_CONF_SUBVENID)) != 0) { 350826947304SEvan Yan if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, 350926947304SEvan Yan "subsystem-vendor-id", val)) != DDI_SUCCESS) { 351026947304SEvan Yan return (ret); 351126947304SEvan Yan } 351226947304SEvan Yan } 351326947304SEvan Yan if ((val = pci_config_get16(config_handle, 351426947304SEvan Yan PCI_CONF_SUBSYSID)) != 0) { 351526947304SEvan Yan if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, 351626947304SEvan Yan "subsystem-id", val)) != DDI_SUCCESS) { 351726947304SEvan Yan return (ret); 351826947304SEvan Yan } 351926947304SEvan Yan } 352026947304SEvan Yan if ((val = pci_config_get16(config_handle, 352126947304SEvan Yan PCI_CONF_CACHE_LINESZ)) != 0) { 352226947304SEvan Yan if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, 352326947304SEvan Yan "cache-line-size", val)) != DDI_SUCCESS) { 352426947304SEvan Yan return (ret); 352526947304SEvan Yan } 352626947304SEvan Yan } 352726947304SEvan Yan 352826947304SEvan Yan /* 352926947304SEvan Yan * If the Interrupt Pin register is non-zero then the 353026947304SEvan Yan * interrupts property exists 353126947304SEvan Yan */ 353226947304SEvan Yan if ((byteval = pci_config_get8(config_handle, PCI_CONF_IPIN)) != 0) { 353326947304SEvan Yan /* 353426947304SEvan Yan * If interrupt pin is non-zero, 353526947304SEvan Yan * record the interrupt line used 353626947304SEvan Yan */ 353726947304SEvan Yan if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, 353826947304SEvan Yan "interrupts", byteval)) != DDI_SUCCESS) { 353926947304SEvan Yan return (ret); 354026947304SEvan Yan } 354126947304SEvan Yan } 354226947304SEvan Yan 354326947304SEvan Yan ret = PCI_CAP_LOCATE(config_handle, PCI_CAP_ID_PCI_E, &cap_ptr); 354426947304SEvan Yan 354526947304SEvan Yan if (pcie_dev && (ret == DDI_SUCCESS)) { 354626947304SEvan Yan val = PCI_CAP_GET16(config_handle, NULL, cap_ptr, 354726947304SEvan Yan PCIE_PCIECAP) & PCIE_PCIECAP_SLOT_IMPL; 354826947304SEvan Yan /* if slot implemented, get physical slot number */ 354926947304SEvan Yan if (val) { 355026947304SEvan Yan wordval = (PCI_CAP_GET32(config_handle, NULL, 355126947304SEvan Yan cap_ptr, PCIE_SLOTCAP) >> 355226947304SEvan Yan PCIE_SLOTCAP_PHY_SLOT_NUM_SHIFT) & 355326947304SEvan Yan PCIE_SLOTCAP_PHY_SLOT_NUM_MASK; 355426947304SEvan Yan if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, 355526947304SEvan Yan dip, "physical-slot#", wordval)) 355626947304SEvan Yan != DDI_SUCCESS) { 355726947304SEvan Yan return (ret); 355826947304SEvan Yan } 355926947304SEvan Yan } 356026947304SEvan Yan } 356126947304SEvan Yan return (PCICFG_SUCCESS); 356226947304SEvan Yan } 356326947304SEvan Yan static int 356426947304SEvan Yan pcicfg_set_busnode_props(dev_info_t *dip, uint8_t pcie_device_type, 356526947304SEvan Yan int pbus, int sbus) 356626947304SEvan Yan { 356726947304SEvan Yan int ret; 356826947304SEvan Yan char device_type[8]; 356926947304SEvan Yan 357026947304SEvan Yan if (pcie_device_type) 357126947304SEvan Yan (void) strcpy(device_type, "pciex"); 357226947304SEvan Yan else 357326947304SEvan Yan (void) strcpy(device_type, "pci"); 357426947304SEvan Yan 357526947304SEvan Yan if ((ret = ndi_prop_update_string(DDI_DEV_T_NONE, dip, 357626947304SEvan Yan "device_type", device_type)) != DDI_SUCCESS) { 357726947304SEvan Yan return (ret); 357826947304SEvan Yan } 357926947304SEvan Yan if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, 358026947304SEvan Yan "#address-cells", 3)) != DDI_SUCCESS) { 358126947304SEvan Yan return (ret); 358226947304SEvan Yan } 358326947304SEvan Yan if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, 358426947304SEvan Yan "#size-cells", 2)) != DDI_SUCCESS) { 358526947304SEvan Yan return (ret); 358626947304SEvan Yan } 358726947304SEvan Yan 358826947304SEvan Yan /* 358926947304SEvan Yan * Create primary-bus and secondary-bus properties to be used 359026947304SEvan Yan * to restore bus numbers in the pcicfg_setup_bridge() routine. 359126947304SEvan Yan */ 359226947304SEvan Yan if (pbus != -1 && sbus != -1) { 359326947304SEvan Yan if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, 359426947304SEvan Yan "primary-bus", pbus)) != DDI_SUCCESS) { 359526947304SEvan Yan return (ret); 359626947304SEvan Yan } 359726947304SEvan Yan if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, 359826947304SEvan Yan "secondary-bus", sbus)) != DDI_SUCCESS) { 359926947304SEvan Yan return (ret); 360026947304SEvan Yan } 360126947304SEvan Yan } 360226947304SEvan Yan return (PCICFG_SUCCESS); 360326947304SEvan Yan } 360426947304SEvan Yan 360526947304SEvan Yan static int 360626947304SEvan Yan pcicfg_set_childnode_props(dev_info_t *dip, ddi_acc_handle_t config_handle, 360726947304SEvan Yan uint8_t pcie_dev) 360826947304SEvan Yan { 360926947304SEvan Yan 361026947304SEvan Yan int ret; 361126947304SEvan Yan char *name; 361226947304SEvan Yan char buffer[64], pprefix[8]; 361326947304SEvan Yan uint16_t classcode; 361426947304SEvan Yan uint8_t revid, pif, pclass, psubclass; 361526947304SEvan Yan char *compat[24]; 361626947304SEvan Yan int i; 361726947304SEvan Yan int n; 361826947304SEvan Yan uint16_t sub_vid, sub_sid, vid, did; 361926947304SEvan Yan 362026947304SEvan Yan /* set the property prefix based on the device type */ 362126947304SEvan Yan if (pcie_dev) 362226947304SEvan Yan (void) sprintf(pprefix, "pciex"); 362326947304SEvan Yan else 362426947304SEvan Yan (void) sprintf(pprefix, "pci"); 362526947304SEvan Yan sub_vid = pci_config_get16(config_handle, PCI_CONF_SUBVENID); 362626947304SEvan Yan sub_sid = pci_config_get16(config_handle, PCI_CONF_SUBSYSID); 362726947304SEvan Yan vid = pci_config_get16(config_handle, PCI_CONF_VENID); 362826947304SEvan Yan did = pci_config_get16(config_handle, PCI_CONF_DEVID); 362926947304SEvan Yan revid = pci_config_get8(config_handle, PCI_CONF_REVID); 363026947304SEvan Yan pif = pci_config_get8(config_handle, PCI_CONF_PROGCLASS); 363126947304SEvan Yan classcode = pci_config_get16(config_handle, PCI_CONF_SUBCLASS); 363226947304SEvan Yan pclass = pci_config_get8(config_handle, PCI_CONF_BASCLASS); 363326947304SEvan Yan psubclass = pci_config_get8(config_handle, PCI_CONF_SUBCLASS); 363426947304SEvan Yan 363526947304SEvan Yan /* 363626947304SEvan Yan * NOTE: These are for both a child and PCI-PCI bridge node 363726947304SEvan Yan */ 363826947304SEvan Yan 363926947304SEvan Yan /* 364026947304SEvan Yan * "name" property rule 364126947304SEvan Yan * -------------------- 364226947304SEvan Yan * 364326947304SEvan Yan * 364426947304SEvan Yan * | \svid | 364526947304SEvan Yan * | \ | 364626947304SEvan Yan * | \ | 364726947304SEvan Yan * | ssid \ | =0 | != 0 | 364826947304SEvan Yan * |------------|-----------------------|-----------------------| 364926947304SEvan Yan * | | | | 365026947304SEvan Yan * | =0 | vid,did | svid,ssid | 365126947304SEvan Yan * | | | | 365226947304SEvan Yan * |------------|-----------------------|-----------------------| 365326947304SEvan Yan * | | | | 365426947304SEvan Yan * | !=0 | svid,ssid | svid,ssid | 365526947304SEvan Yan * | | | | 365626947304SEvan Yan * |------------|-----------------------|-----------------------| 365726947304SEvan Yan * 365826947304SEvan Yan * where: 365926947304SEvan Yan * vid = vendor id 366026947304SEvan Yan * did = device id 366126947304SEvan Yan * svid = subsystem vendor id 366226947304SEvan Yan * ssid = subsystem id 366326947304SEvan Yan */ 366426947304SEvan Yan 366526947304SEvan Yan if ((sub_sid != 0) || (sub_vid != 0)) { 366626947304SEvan Yan (void) sprintf(buffer, "%s%x,%x", pprefix, sub_vid, sub_sid); 366726947304SEvan Yan } else { 366826947304SEvan Yan (void) sprintf(buffer, "%s%x,%x", pprefix, vid, did); 366926947304SEvan Yan } 367026947304SEvan Yan 367126947304SEvan Yan /* 367226947304SEvan Yan * In some environments, trying to use "generic" 1275 names is 367326947304SEvan Yan * not the convention. In those cases use the name as created 367426947304SEvan Yan * above. In all the rest of the cases, check to see if there 367526947304SEvan Yan * is a generic name first. 367626947304SEvan Yan */ 367726947304SEvan Yan #ifdef _DONT_USE_1275_GENERIC_NAMES 367826947304SEvan Yan name = buffer; 367926947304SEvan Yan #else 368026947304SEvan Yan if ((name = pcicfg_get_class_name(classcode)) == NULL) { 368126947304SEvan Yan /* 368226947304SEvan Yan * Set name to the above fabricated name 368326947304SEvan Yan */ 368426947304SEvan Yan name = buffer; 368526947304SEvan Yan } 368626947304SEvan Yan #endif 368726947304SEvan Yan 368826947304SEvan Yan /* 368926947304SEvan Yan * The node name field needs to be filled in with the name 369026947304SEvan Yan */ 369126947304SEvan Yan if (ndi_devi_set_nodename(dip, name, 0) != NDI_SUCCESS) { 369226947304SEvan Yan DEBUG0("Failed to set nodename for node\n"); 369326947304SEvan Yan return (PCICFG_FAILURE); 369426947304SEvan Yan } 369526947304SEvan Yan 369626947304SEvan Yan /* 369726947304SEvan Yan * Create the compatible property as an array of pointers 369826947304SEvan Yan * to strings. Start with the buffer created above. 369926947304SEvan Yan */ 370026947304SEvan Yan n = 0; 370126947304SEvan Yan compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP); 370226947304SEvan Yan (void) strcpy(compat[n++], buffer); 370326947304SEvan Yan 370426947304SEvan Yan /* 370526947304SEvan Yan * Setup 'compatible' as per the PCI2.1 bindings document. 370626947304SEvan Yan * pci[ex]VVVV,DDDD.SSSS.ssss.RR 370726947304SEvan Yan * pci[ex]VVVV,DDDD.SSSS.ssss 370826947304SEvan Yan * pciSSSS.ssss -> not created for PCIe as per PCIe bindings 370926947304SEvan Yan * pci[ex]VVVV,DDDD.RR 371026947304SEvan Yan * pci[ex]VVVV,DDDD 371126947304SEvan Yan * pci[ex]class,CCSSPP 371226947304SEvan Yan * pci[ex]class,CCSS 371326947304SEvan Yan */ 371426947304SEvan Yan 371526947304SEvan Yan /* pci[ex]VVVV,DDDD.SSSS.ssss.RR */ 371626947304SEvan Yan (void) sprintf(buffer, "%s%x,%x.%x.%x.%x", pprefix, vid, did, 371726947304SEvan Yan sub_vid, sub_sid, revid); 371826947304SEvan Yan compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP); 371926947304SEvan Yan (void) strcpy(compat[n++], buffer); 372026947304SEvan Yan 372126947304SEvan Yan /* pci[ex]VVVV,DDDD.SSSS.ssss */ 372226947304SEvan Yan (void) sprintf(buffer, "%s%x,%x.%x.%x", pprefix, vid, did, 372326947304SEvan Yan sub_vid, sub_sid); 372426947304SEvan Yan compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP); 372526947304SEvan Yan (void) strcpy(compat[n++], buffer); 372626947304SEvan Yan 372726947304SEvan Yan /* pciSSSS.ssss -> not created for PCIe as per PCIe bindings */ 372826947304SEvan Yan if (!pcie_dev) { 372926947304SEvan Yan (void) sprintf(buffer, "pci%x,%x", sub_vid, sub_sid); 373026947304SEvan Yan compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP); 373126947304SEvan Yan (void) strcpy(compat[n++], buffer); 373226947304SEvan Yan } 373326947304SEvan Yan 373426947304SEvan Yan /* pci[ex]VVVV,DDDD.RR */ 373526947304SEvan Yan (void) sprintf(buffer, "%s%x,%x.%x", pprefix, vid, did, revid); 373626947304SEvan Yan compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP); 373726947304SEvan Yan (void) strcpy(compat[n++], buffer); 373826947304SEvan Yan 373926947304SEvan Yan /* pci[ex]VVVV,DDDD */ 374026947304SEvan Yan (void) sprintf(buffer, "%s%x,%x", pprefix, vid, did); 374126947304SEvan Yan compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP); 374226947304SEvan Yan (void) strcpy(compat[n++], buffer); 374326947304SEvan Yan 374426947304SEvan Yan /* pci[ex]class,CCSSPP */ 374526947304SEvan Yan (void) sprintf(buffer, "%sclass,%02x%02x%02x", pprefix, 374626947304SEvan Yan pclass, psubclass, pif); 374726947304SEvan Yan compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP); 374826947304SEvan Yan (void) strcpy(compat[n++], buffer); 374926947304SEvan Yan 375026947304SEvan Yan /* pci[ex]class,CCSS */ 375126947304SEvan Yan (void) sprintf(buffer, "%sclass,%04x", pprefix, classcode); 375226947304SEvan Yan compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP); 375326947304SEvan Yan (void) strcpy(compat[n++], buffer); 375426947304SEvan Yan 375526947304SEvan Yan if ((ret = ndi_prop_update_string_array(DDI_DEV_T_NONE, dip, 375626947304SEvan Yan "compatible", (char **)compat, n)) != DDI_SUCCESS) { 375726947304SEvan Yan return (ret); 375826947304SEvan Yan } 375926947304SEvan Yan 376026947304SEvan Yan for (i = 0; i < n; i++) { 376126947304SEvan Yan kmem_free(compat[i], strlen(compat[i]) + 1); 376226947304SEvan Yan } 376326947304SEvan Yan 376426947304SEvan Yan DEBUG1("pcicfg_set_childnode_props - creating name=%s\n", name); 376526947304SEvan Yan if ((ret = ndi_prop_update_string(DDI_DEV_T_NONE, dip, 376626947304SEvan Yan "name", name)) != DDI_SUCCESS) { 376726947304SEvan Yan 376826947304SEvan Yan DEBUG0("pcicfg_set_childnode_props - Unable to create name " 376926947304SEvan Yan "property\n"); 377026947304SEvan Yan 377126947304SEvan Yan return (ret); 377226947304SEvan Yan } 377326947304SEvan Yan 377426947304SEvan Yan return (PCICFG_SUCCESS); 377526947304SEvan Yan } 377626947304SEvan Yan 377726947304SEvan Yan /* 377826947304SEvan Yan * Program the bus numbers into the bridge 377926947304SEvan Yan */ 378026947304SEvan Yan 378126947304SEvan Yan static void 378226947304SEvan Yan pcicfg_set_bus_numbers(ddi_acc_handle_t config_handle, 378326947304SEvan Yan uint_t primary, uint_t secondary, uint_t subordinate) 378426947304SEvan Yan { 378526947304SEvan Yan DEBUG3("Setting bridge bus-range %d,%d,%d\n", primary, secondary, 378626947304SEvan Yan subordinate); 378726947304SEvan Yan /* 378826947304SEvan Yan * Primary bus# 378926947304SEvan Yan */ 379026947304SEvan Yan pci_config_put8(config_handle, PCI_BCNF_PRIBUS, primary); 379126947304SEvan Yan 379226947304SEvan Yan /* 379326947304SEvan Yan * Secondary bus# 379426947304SEvan Yan */ 379526947304SEvan Yan pci_config_put8(config_handle, PCI_BCNF_SECBUS, secondary); 379626947304SEvan Yan 379726947304SEvan Yan /* 379826947304SEvan Yan * Subordinate bus# 379926947304SEvan Yan */ 380026947304SEvan Yan pci_config_put8(config_handle, PCI_BCNF_SUBBUS, subordinate); 380126947304SEvan Yan } 380226947304SEvan Yan 380326947304SEvan Yan /* 380426947304SEvan Yan * Put bridge registers into initial state 380526947304SEvan Yan */ 380626947304SEvan Yan static void 380726947304SEvan Yan pcicfg_setup_bridge(pcicfg_phdl_t *entry, 380826947304SEvan Yan ddi_acc_handle_t handle, dev_info_t *dip) 380926947304SEvan Yan { 381026947304SEvan Yan int pbus, sbus; 381126947304SEvan Yan 381226947304SEvan Yan /* 381326947304SEvan Yan * The highest bus seen during probing is the max-subordinate bus 381426947304SEvan Yan */ 381526947304SEvan Yan pci_config_put8(handle, PCI_BCNF_SUBBUS, entry->highest_bus); 381626947304SEvan Yan 381726947304SEvan Yan 381826947304SEvan Yan /* 381926947304SEvan Yan * If there exists more than 1 downstream bridge, it 382026947304SEvan Yan * will be reset by the below secondary bus reset which 382126947304SEvan Yan * will clear the bus numbers assumed to be programmed in 382226947304SEvan Yan * the pcicfg_probe_children() routine. We therefore restore 382326947304SEvan Yan * them here. 382426947304SEvan Yan */ 382526947304SEvan Yan if (pci_config_get8(handle, PCI_BCNF_SECBUS) == 0) { 382626947304SEvan Yan pbus = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 382726947304SEvan Yan DDI_PROP_DONTPASS, "primary-bus", -1); 382826947304SEvan Yan sbus = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 382926947304SEvan Yan DDI_PROP_DONTPASS, "secondary-bus", -1); 383026947304SEvan Yan if (pbus != -1 && sbus != -1) { 383126947304SEvan Yan pci_config_put8(handle, PCI_BCNF_PRIBUS, (uint_t)pbus); 383226947304SEvan Yan pci_config_put8(handle, PCI_BCNF_SECBUS, (uint_t)sbus); 383326947304SEvan Yan } else { 383426947304SEvan Yan cmn_err(CE_WARN, "Invalid Bridge number detected: \ 383526947304SEvan Yan %s%d: pbus = 0x%x, sbus = 0x%x", 383626947304SEvan Yan ddi_get_name(dip), ddi_get_instance(dip), pbus, 383726947304SEvan Yan sbus); 383826947304SEvan Yan } 383926947304SEvan Yan } 384026947304SEvan Yan 384126947304SEvan Yan /* 384226947304SEvan Yan * Reset the secondary bus 384326947304SEvan Yan */ 384426947304SEvan Yan pci_config_put16(handle, PCI_BCNF_BCNTRL, 384526947304SEvan Yan pci_config_get16(handle, PCI_BCNF_BCNTRL) | 0x40); 384626947304SEvan Yan 384726947304SEvan Yan drv_usecwait(100); 384826947304SEvan Yan 384926947304SEvan Yan pci_config_put16(handle, PCI_BCNF_BCNTRL, 385026947304SEvan Yan pci_config_get16(handle, PCI_BCNF_BCNTRL) & ~0x40); 385126947304SEvan Yan 385226947304SEvan Yan /* 385326947304SEvan Yan * Program the memory base register with the 385426947304SEvan Yan * start of the memory range 385526947304SEvan Yan */ 385626947304SEvan Yan pci_config_put16(handle, PCI_BCNF_MEM_BASE, 385726947304SEvan Yan PCICFG_HIWORD(PCICFG_LOADDR(entry->memory_last))); 385826947304SEvan Yan 385926947304SEvan Yan /* 386026947304SEvan Yan * Program the I/O base register with the start of the I/O range 386126947304SEvan Yan */ 386226947304SEvan Yan pci_config_put8(handle, PCI_BCNF_IO_BASE_LOW, 386326947304SEvan Yan PCICFG_HIBYTE(PCICFG_LOWORD(PCICFG_LOADDR(entry->io_last)))); 386426947304SEvan Yan pci_config_put16(handle, PCI_BCNF_IO_BASE_HI, 386526947304SEvan Yan PCICFG_HIWORD(PCICFG_LOADDR(entry->io_last))); 386626947304SEvan Yan 386726947304SEvan Yan /* 386826947304SEvan Yan * Clear status bits 386926947304SEvan Yan */ 387026947304SEvan Yan pci_config_put16(handle, PCI_BCNF_SEC_STATUS, 0xffff); 387126947304SEvan Yan 387226947304SEvan Yan /* 387326947304SEvan Yan * Turn off prefetchable range 387426947304SEvan Yan */ 387526947304SEvan Yan pci_config_put32(handle, PCI_BCNF_PF_BASE_LOW, 0x0000ffff); 387626947304SEvan Yan pci_config_put32(handle, PCI_BCNF_PF_BASE_HIGH, 0xffffffff); 387726947304SEvan Yan pci_config_put32(handle, PCI_BCNF_PF_LIMIT_HIGH, 0x0); 387826947304SEvan Yan 387926947304SEvan Yan /* 388026947304SEvan Yan * Needs to be set to this value 388126947304SEvan Yan */ 388226947304SEvan Yan pci_config_put8(handle, PCI_CONF_ILINE, 0xf); 388326947304SEvan Yan 388426947304SEvan Yan /* 388526947304SEvan Yan * After a Reset, we need to wait 2^25 clock cycles before the 388626947304SEvan Yan * first Configuration access. The worst case is 33MHz, which 388726947304SEvan Yan * is a 1 second wait. 388826947304SEvan Yan */ 388926947304SEvan Yan drv_usecwait(pcicfg_sec_reset_delay); 389026947304SEvan Yan 389126947304SEvan Yan } 389226947304SEvan Yan 389326947304SEvan Yan static void 389426947304SEvan Yan pcicfg_update_bridge(pcicfg_phdl_t *entry, 389526947304SEvan Yan ddi_acc_handle_t handle) 389626947304SEvan Yan { 389726947304SEvan Yan uint_t length; 389826947304SEvan Yan 389926947304SEvan Yan /* 390026947304SEvan Yan * Program the memory limit register with the end of the memory range 390126947304SEvan Yan */ 390226947304SEvan Yan 390326947304SEvan Yan DEBUG1("DOWN ROUNDED ===>[0x%x]\n", 390426947304SEvan Yan PCICFG_ROUND_DOWN(entry->memory_last, 390526947304SEvan Yan PCICFG_MEMGRAN)); 390626947304SEvan Yan 390726947304SEvan Yan pci_config_put16(handle, PCI_BCNF_MEM_LIMIT, 390826947304SEvan Yan PCICFG_HIWORD(PCICFG_LOADDR( 390926947304SEvan Yan PCICFG_ROUND_DOWN(entry->memory_last, 391026947304SEvan Yan PCICFG_MEMGRAN)))); 391126947304SEvan Yan /* 391226947304SEvan Yan * Since this is a bridge, the rest of this range will 391326947304SEvan Yan * be responded to by the bridge. We have to round up 391426947304SEvan Yan * so no other device claims it. 391526947304SEvan Yan */ 391626947304SEvan Yan if ((length = (PCICFG_ROUND_UP(entry->memory_last, 391726947304SEvan Yan PCICFG_MEMGRAN) - entry->memory_last)) > 0) { 391826947304SEvan Yan (void) pcicfg_get_mem(entry, length, NULL); 391926947304SEvan Yan DEBUG1("Added [0x%x]at the top of " 392026947304SEvan Yan "the bridge (mem)\n", length); 392126947304SEvan Yan } 392226947304SEvan Yan 392326947304SEvan Yan /* 392426947304SEvan Yan * Program the I/O limit register with the end of the I/O range 392526947304SEvan Yan */ 392626947304SEvan Yan pci_config_put8(handle, PCI_BCNF_IO_LIMIT_LOW, 392726947304SEvan Yan PCICFG_HIBYTE(PCICFG_LOWORD( 392826947304SEvan Yan PCICFG_LOADDR(PCICFG_ROUND_DOWN(entry->io_last, 392926947304SEvan Yan PCICFG_IOGRAN))))); 393026947304SEvan Yan 393126947304SEvan Yan pci_config_put16(handle, PCI_BCNF_IO_LIMIT_HI, 393226947304SEvan Yan PCICFG_HIWORD(PCICFG_LOADDR(PCICFG_ROUND_DOWN(entry->io_last, 393326947304SEvan Yan PCICFG_IOGRAN)))); 393426947304SEvan Yan 393526947304SEvan Yan /* 393626947304SEvan Yan * Same as above for I/O space. Since this is a 393726947304SEvan Yan * bridge, the rest of this range will be responded 393826947304SEvan Yan * to by the bridge. We have to round up so no 393926947304SEvan Yan * other device claims it. 394026947304SEvan Yan */ 394126947304SEvan Yan if ((length = (PCICFG_ROUND_UP(entry->io_last, 394226947304SEvan Yan PCICFG_IOGRAN) - entry->io_last)) > 0) { 394326947304SEvan Yan (void) pcicfg_get_io(entry, length, NULL); 394426947304SEvan Yan DEBUG1("Added [0x%x]at the top of " 394526947304SEvan Yan "the bridge (I/O)\n", length); 394626947304SEvan Yan } 394726947304SEvan Yan } 394826947304SEvan Yan 394926947304SEvan Yan /*ARGSUSED*/ 395026947304SEvan Yan static void 395126947304SEvan Yan pcicfg_disable_bridge_probe_err(dev_info_t *dip, ddi_acc_handle_t h, 395226947304SEvan Yan pcicfg_err_regs_t *regs) 395326947304SEvan Yan { 395426947304SEvan Yan uint16_t val; 395526947304SEvan Yan 395626947304SEvan Yan /* disable SERR generated in the context of Master Aborts. */ 395726947304SEvan Yan regs->cmd = val = pci_config_get16(h, PCI_CONF_COMM); 395826947304SEvan Yan val &= ~PCI_COMM_SERR_ENABLE; 395926947304SEvan Yan pci_config_put16(h, PCI_CONF_COMM, val); 396026947304SEvan Yan regs->bcntl = val = pci_config_get16(h, PCI_BCNF_BCNTRL); 396126947304SEvan Yan val &= ~PCI_BCNF_BCNTRL_SERR_ENABLE; 396226947304SEvan Yan pci_config_put16(h, PCI_BCNF_BCNTRL, val); 396326947304SEvan Yan /* clear any current pending errors */ 396426947304SEvan Yan pci_config_put16(h, PCI_CONF_STAT, PCI_STAT_S_TARG_AB| 396526947304SEvan Yan PCI_STAT_R_TARG_AB | PCI_STAT_R_MAST_AB | PCI_STAT_S_SYSERR); 396626947304SEvan Yan pci_config_put16(h, PCI_BCNF_SEC_STATUS, PCI_STAT_S_TARG_AB| 396726947304SEvan Yan PCI_STAT_R_TARG_AB | PCI_STAT_R_MAST_AB | PCI_STAT_S_SYSERR); 396826947304SEvan Yan /* if we are a PCIe device, disable the generation of UR, CE and NFE */ 396926947304SEvan Yan if (regs->pcie_dev) { 397026947304SEvan Yan uint16_t devctl; 397126947304SEvan Yan uint16_t cap_ptr; 397226947304SEvan Yan 397326947304SEvan Yan if ((PCI_CAP_LOCATE(h, PCI_CAP_ID_PCI_E, &cap_ptr)) == 397426947304SEvan Yan DDI_FAILURE) 397526947304SEvan Yan return; 397626947304SEvan Yan 397726947304SEvan Yan regs->pcie_cap_off = cap_ptr; 397826947304SEvan Yan regs->devctl = devctl = PCI_CAP_GET16(h, NULL, cap_ptr, 397926947304SEvan Yan PCIE_DEVCTL); 398026947304SEvan Yan devctl &= ~(PCIE_DEVCTL_UR_REPORTING_EN | 398126947304SEvan Yan PCIE_DEVCTL_CE_REPORTING_EN | 398226947304SEvan Yan PCIE_DEVCTL_NFE_REPORTING_EN | 398326947304SEvan Yan PCIE_DEVCTL_FE_REPORTING_EN); 398426947304SEvan Yan PCI_CAP_PUT16(h, NULL, cap_ptr, PCIE_DEVCTL, devctl); 398526947304SEvan Yan } 398626947304SEvan Yan } 398726947304SEvan Yan 398826947304SEvan Yan /*ARGSUSED*/ 398926947304SEvan Yan static void 399026947304SEvan Yan pcicfg_enable_bridge_probe_err(dev_info_t *dip, ddi_acc_handle_t h, 399126947304SEvan Yan pcicfg_err_regs_t *regs) 399226947304SEvan Yan { 399326947304SEvan Yan /* clear any pending errors */ 399426947304SEvan Yan pci_config_put16(h, PCI_CONF_STAT, PCI_STAT_S_TARG_AB| 399526947304SEvan Yan PCI_STAT_R_TARG_AB | PCI_STAT_R_MAST_AB | PCI_STAT_S_SYSERR); 399626947304SEvan Yan pci_config_put16(h, PCI_BCNF_SEC_STATUS, PCI_STAT_S_TARG_AB| 399726947304SEvan Yan PCI_STAT_R_TARG_AB | PCI_STAT_R_MAST_AB | PCI_STAT_S_SYSERR); 399826947304SEvan Yan 399926947304SEvan Yan /* restore original settings */ 400026947304SEvan Yan if (regs->pcie_dev) { 400126947304SEvan Yan pcie_clear_errors(dip); 400226947304SEvan Yan pci_config_put16(h, regs->pcie_cap_off + PCIE_DEVCTL, 400326947304SEvan Yan regs->devctl); 400426947304SEvan Yan } 400526947304SEvan Yan 400626947304SEvan Yan pci_config_put16(h, PCI_BCNF_BCNTRL, regs->bcntl); 400726947304SEvan Yan pci_config_put16(h, PCI_CONF_COMM, regs->cmd); 400826947304SEvan Yan 400926947304SEvan Yan } 401026947304SEvan Yan 401126947304SEvan Yan static int 401226947304SEvan Yan pcicfg_probe_children(dev_info_t *parent, uint_t bus, uint_t device, 4013c0da6274SZhi-Jun Robin Fu uint_t func, uint_t *highest_bus, pcicfg_flags_t flags, boolean_t is_pcie) 401426947304SEvan Yan { 401526947304SEvan Yan dev_info_t *new_child; 401626947304SEvan Yan ddi_acc_handle_t config_handle; 401726947304SEvan Yan uint8_t header_type, pcie_dev = 0; 401826947304SEvan Yan int ret; 401926947304SEvan Yan pcicfg_err_regs_t regs; 402026947304SEvan Yan 402126947304SEvan Yan /* 402226947304SEvan Yan * This node will be put immediately below 402326947304SEvan Yan * "parent". Allocate a blank device node. It will either 402426947304SEvan Yan * be filled in or freed up based on further probing. 402526947304SEvan Yan */ 402626947304SEvan Yan /* 402726947304SEvan Yan * Note: in usr/src/uts/common/io/hotplug/pcicfg/pcicfg.c 402826947304SEvan Yan * ndi_devi_alloc() is called as ndi_devi_alloc_sleep() 402926947304SEvan Yan */ 403026947304SEvan Yan if (ndi_devi_alloc(parent, DEVI_PSEUDO_NEXNAME, 403126947304SEvan Yan (pnode_t)DEVI_SID_NODEID, &new_child) 403226947304SEvan Yan != NDI_SUCCESS) { 403326947304SEvan Yan DEBUG0("pcicfg_probe_children(): Failed to alloc child node\n"); 403426947304SEvan Yan return (PCICFG_FAILURE); 403526947304SEvan Yan } 403626947304SEvan Yan 403726947304SEvan Yan if (pcicfg_add_config_reg(new_child, bus, 403826947304SEvan Yan device, func) != DDI_SUCCESS) { 403926947304SEvan Yan DEBUG0("pcicfg_probe_children():" 404026947304SEvan Yan "Failed to add candidate REG\n"); 404126947304SEvan Yan goto failedconfig; 404226947304SEvan Yan } 404326947304SEvan Yan 404426947304SEvan Yan if ((ret = pcicfg_config_setup(new_child, &config_handle)) 404526947304SEvan Yan != PCICFG_SUCCESS) { 404626947304SEvan Yan if (ret == PCICFG_NODEVICE) { 404726947304SEvan Yan (void) ndi_devi_free(new_child); 404826947304SEvan Yan return (ret); 404926947304SEvan Yan } 405026947304SEvan Yan DEBUG0("pcicfg_probe_children():" 405126947304SEvan Yan "Failed to setup config space\n"); 405226947304SEvan Yan goto failedconfig; 405326947304SEvan Yan } 405426947304SEvan Yan 4055c0da6274SZhi-Jun Robin Fu if (is_pcie) 4056c0da6274SZhi-Jun Robin Fu (void) pcie_init_bus(new_child, PCI_GETBDF(bus, device, func), 4057c0da6274SZhi-Jun Robin Fu PCIE_BUS_INITIAL); 4058c0da6274SZhi-Jun Robin Fu 405926947304SEvan Yan /* 406026947304SEvan Yan * As soon as we have access to config space, 406126947304SEvan Yan * turn off device. It will get turned on 406226947304SEvan Yan * later (after memory is assigned). 406326947304SEvan Yan */ 406426947304SEvan Yan (void) pcicfg_device_off(config_handle); 406526947304SEvan Yan 406626947304SEvan Yan /* check if we are PCIe device */ 406726947304SEvan Yan if (pcicfg_pcie_dev(new_child, PCICFG_DEVICE_TYPE_PCIE, ®s) 406826947304SEvan Yan == DDI_SUCCESS) { 406926947304SEvan Yan DEBUG0("PCIe device detected\n"); 407026947304SEvan Yan pcie_dev = 1; 407126947304SEvan Yan } 407226947304SEvan Yan 407326947304SEvan Yan /* 407426947304SEvan Yan * Set 1275 properties common to all devices 407526947304SEvan Yan */ 407626947304SEvan Yan if (pcicfg_set_standard_props(new_child, config_handle, 407726947304SEvan Yan pcie_dev) != PCICFG_SUCCESS) { 407826947304SEvan Yan DEBUG0("Failed to set standard properties\n"); 407926947304SEvan Yan goto failedchild; 408026947304SEvan Yan } 408126947304SEvan Yan 408226947304SEvan Yan /* 408326947304SEvan Yan * Child node properties NOTE: Both for PCI-PCI bridge and child node 408426947304SEvan Yan */ 408526947304SEvan Yan if (pcicfg_set_childnode_props(new_child, config_handle, 408626947304SEvan Yan pcie_dev) != PCICFG_SUCCESS) { 408726947304SEvan Yan goto failedchild; 408826947304SEvan Yan } 408926947304SEvan Yan 409026947304SEvan Yan header_type = pci_config_get8(config_handle, PCI_CONF_HEADER); 409126947304SEvan Yan 409226947304SEvan Yan /* 409326947304SEvan Yan * If this is not a multi-function card only probe function zero. 409426947304SEvan Yan */ 409526947304SEvan Yan if ((!(header_type & PCI_HEADER_MULTI)) && (func != 0)) { 409626947304SEvan Yan 409726947304SEvan Yan (void) pcicfg_config_teardown(&config_handle); 409826947304SEvan Yan (void) ndi_devi_free(new_child); 409926947304SEvan Yan return (PCICFG_NODEVICE); 410026947304SEvan Yan } 410126947304SEvan Yan 410226947304SEvan Yan DEBUG1("---Vendor ID = [0x%x]\n", 410326947304SEvan Yan pci_config_get16(config_handle, PCI_CONF_VENID)); 410426947304SEvan Yan DEBUG1("---Device ID = [0x%x]\n", 410526947304SEvan Yan pci_config_get16(config_handle, PCI_CONF_DEVID)); 410626947304SEvan Yan 410726947304SEvan Yan /* 410826947304SEvan Yan * Attach the child to its parent 410926947304SEvan Yan */ 411026947304SEvan Yan (void) i_ndi_config_node(new_child, DS_LINKED, 0); 411126947304SEvan Yan 411226947304SEvan Yan if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) { 411326947304SEvan Yan 411426947304SEvan Yan DEBUG3("--Bridge found bus [0x%x] device" 411526947304SEvan Yan "[0x%x] func [0x%x]\n", bus, device, func); 411626947304SEvan Yan 411726947304SEvan Yan /* Only support read-only probe for leaf device */ 411826947304SEvan Yan if (flags & PCICFG_FLAG_READ_ONLY) 411926947304SEvan Yan goto failedchild; 412026947304SEvan Yan 412126947304SEvan Yan if (pcicfg_probe_bridge(new_child, config_handle, 4122c0da6274SZhi-Jun Robin Fu bus, highest_bus, is_pcie) != PCICFG_SUCCESS) { 412326947304SEvan Yan (void) pcicfg_free_bridge_resources(new_child); 412426947304SEvan Yan goto failedchild; 412526947304SEvan Yan } 412626947304SEvan Yan 412726947304SEvan Yan } else { 412826947304SEvan Yan 412926947304SEvan Yan DEBUG3("--Leaf device found bus [0x%x] device" 413026947304SEvan Yan "[0x%x] func [0x%x]\n", 413126947304SEvan Yan bus, device, func); 413226947304SEvan Yan 413326947304SEvan Yan if (flags & PCICFG_FLAG_READ_ONLY) { 413426947304SEvan Yan /* 413526947304SEvan Yan * with read-only probe, don't do any resource 413626947304SEvan Yan * allocation, just read the BARs and update props. 413726947304SEvan Yan */ 413826947304SEvan Yan ret = pcicfg_populate_props_from_bar(new_child, 413926947304SEvan Yan config_handle); 414026947304SEvan Yan if (ret != PCICFG_SUCCESS) 414126947304SEvan Yan goto failedchild; 414226947304SEvan Yan 414326947304SEvan Yan /* 414426947304SEvan Yan * for readonly probe "assigned-addresses" property 414526947304SEvan Yan * has already been setup by reading the BAR, here 414626947304SEvan Yan * just substract the resource from its parent here. 414726947304SEvan Yan */ 414826947304SEvan Yan ret = pcicfg_device_assign_readonly(new_child); 414926947304SEvan Yan if (ret != PCICFG_SUCCESS) { 415026947304SEvan Yan (void) pcicfg_free_device_resources(new_child, 415126947304SEvan Yan flags); 415226947304SEvan Yan goto failedchild; 415326947304SEvan Yan } 415426947304SEvan Yan } else { 415526947304SEvan Yan /* 415626947304SEvan Yan * update "reg" property by sizing the BARs. 415726947304SEvan Yan */ 415826947304SEvan Yan ret = pcicfg_populate_reg_props(new_child, 415926947304SEvan Yan config_handle); 416026947304SEvan Yan if (ret != PCICFG_SUCCESS) 416126947304SEvan Yan goto failedchild; 416226947304SEvan Yan 416326947304SEvan Yan /* now allocate & program the resources */ 416426947304SEvan Yan ret = pcicfg_device_assign(new_child); 416526947304SEvan Yan if (ret != PCICFG_SUCCESS) { 416626947304SEvan Yan (void) pcicfg_free_device_resources(new_child, 416726947304SEvan Yan flags); 416826947304SEvan Yan goto failedchild; 416926947304SEvan Yan } 417026947304SEvan Yan } 417126947304SEvan Yan 417226947304SEvan Yan (void) ndi_devi_bind_driver(new_child, 0); 417326947304SEvan Yan } 417426947304SEvan Yan 417526947304SEvan Yan (void) pcicfg_config_teardown(&config_handle); 4176c0da6274SZhi-Jun Robin Fu 4177c0da6274SZhi-Jun Robin Fu /* 4178c0da6274SZhi-Jun Robin Fu * Properties have been setted up, so initilize the rest fields 4179c0da6274SZhi-Jun Robin Fu * in bus_t. 4180c0da6274SZhi-Jun Robin Fu */ 4181c0da6274SZhi-Jun Robin Fu if (is_pcie) 4182c1374a13SSurya Prakki (void) pcie_init_bus(new_child, 0, PCIE_BUS_FINAL); 4183c0da6274SZhi-Jun Robin Fu 418426947304SEvan Yan return (PCICFG_SUCCESS); 418526947304SEvan Yan 418626947304SEvan Yan failedchild: 418726947304SEvan Yan 418826947304SEvan Yan (void) pcicfg_config_teardown(&config_handle); 4189c0da6274SZhi-Jun Robin Fu if (is_pcie) 4190c0da6274SZhi-Jun Robin Fu pcie_fini_bus(new_child, PCIE_BUS_FINAL); 419126947304SEvan Yan 419226947304SEvan Yan failedconfig: 419326947304SEvan Yan 419426947304SEvan Yan (void) ndi_devi_free(new_child); 419526947304SEvan Yan return (PCICFG_FAILURE); 419626947304SEvan Yan } 419726947304SEvan Yan 419826947304SEvan Yan /* 419926947304SEvan Yan * Sizing the BARs and update "reg" property 420026947304SEvan Yan */ 420126947304SEvan Yan static int 420226947304SEvan Yan pcicfg_populate_reg_props(dev_info_t *new_child, 420326947304SEvan Yan ddi_acc_handle_t config_handle) 420426947304SEvan Yan { 420526947304SEvan Yan int i; 420626947304SEvan Yan uint32_t request; 420726947304SEvan Yan 420826947304SEvan Yan i = PCI_CONF_BASE0; 420926947304SEvan Yan 421026947304SEvan Yan while (i <= PCI_CONF_BASE5) { 421126947304SEvan Yan 421226947304SEvan Yan pci_config_put32(config_handle, i, 0xffffffff); 421326947304SEvan Yan 421426947304SEvan Yan request = pci_config_get32(config_handle, i); 421526947304SEvan Yan /* 421626947304SEvan Yan * If its a zero length, don't do 421726947304SEvan Yan * any programming. 421826947304SEvan Yan */ 421926947304SEvan Yan if (request != 0) { 422026947304SEvan Yan /* 422126947304SEvan Yan * Add to the "reg" property 422226947304SEvan Yan */ 422326947304SEvan Yan if (pcicfg_update_reg_prop(new_child, 422426947304SEvan Yan request, i) != PCICFG_SUCCESS) { 422526947304SEvan Yan goto failedchild; 422626947304SEvan Yan } 422726947304SEvan Yan } else { 422826947304SEvan Yan DEBUG1("BASE register [0x%x] asks for " 422926947304SEvan Yan "[0x0]=[0x0](32)\n", i); 423026947304SEvan Yan i += 4; 423126947304SEvan Yan continue; 423226947304SEvan Yan } 423326947304SEvan Yan 423426947304SEvan Yan /* 423526947304SEvan Yan * Increment by eight if it is 64 bit address space 423626947304SEvan Yan */ 423726947304SEvan Yan if ((PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_ALL) { 423826947304SEvan Yan DEBUG3("BASE register [0x%x] asks for " 423926947304SEvan Yan "[0x%x]=[0x%x] (64)\n", 424026947304SEvan Yan i, request, 424126947304SEvan Yan (~(PCI_BASE_M_ADDR_M & request))+1) 424226947304SEvan Yan i += 8; 424326947304SEvan Yan } else { 424426947304SEvan Yan DEBUG3("BASE register [0x%x] asks for " 424526947304SEvan Yan "[0x%x]=[0x%x](32)\n", 424626947304SEvan Yan i, request, 424726947304SEvan Yan (~(PCI_BASE_M_ADDR_M & request))+1) 424826947304SEvan Yan i += 4; 424926947304SEvan Yan } 425026947304SEvan Yan } 425126947304SEvan Yan 425226947304SEvan Yan /* 425326947304SEvan Yan * Get the ROM size and create register for it 425426947304SEvan Yan */ 425526947304SEvan Yan pci_config_put32(config_handle, PCI_CONF_ROM, 0xfffffffe); 425626947304SEvan Yan 425726947304SEvan Yan request = pci_config_get32(config_handle, PCI_CONF_ROM); 425826947304SEvan Yan /* 425926947304SEvan Yan * If its a zero length, don't do 426026947304SEvan Yan * any programming. 426126947304SEvan Yan */ 426226947304SEvan Yan 426326947304SEvan Yan if (request != 0) { 426426947304SEvan Yan DEBUG3("BASE register [0x%x] asks for [0x%x]=[0x%x]\n", 426526947304SEvan Yan PCI_CONF_ROM, request, 426626947304SEvan Yan (~(PCI_BASE_ROM_ADDR_M & request))+1); 426726947304SEvan Yan /* 426826947304SEvan Yan * Add to the "reg" property 426926947304SEvan Yan */ 427026947304SEvan Yan if (pcicfg_update_reg_prop(new_child, 427126947304SEvan Yan request, PCI_CONF_ROM) != PCICFG_SUCCESS) { 427226947304SEvan Yan goto failedchild; 427326947304SEvan Yan } 427426947304SEvan Yan } 427526947304SEvan Yan 427626947304SEvan Yan return (PCICFG_SUCCESS); 427726947304SEvan Yan 427826947304SEvan Yan failedchild: 427926947304SEvan Yan return (PCICFG_FAILURE); 428026947304SEvan Yan } 428126947304SEvan Yan 428226947304SEvan Yan static int 428326947304SEvan Yan pcicfg_fcode_probe(dev_info_t *parent, uint_t bus, uint_t device, 4284c0da6274SZhi-Jun Robin Fu uint_t func, uint_t *highest_bus, pcicfg_flags_t flags, boolean_t is_pcie) 428526947304SEvan Yan { 428626947304SEvan Yan dev_info_t *new_child; 428726947304SEvan Yan int8_t header_type; 428826947304SEvan Yan int ret; 428926947304SEvan Yan ddi_acc_handle_t h, ph; 429026947304SEvan Yan int error = 0; 429126947304SEvan Yan extern int pcicfg_dont_interpret; 429226947304SEvan Yan pcicfg_err_regs_t parent_regs, regs; 429326947304SEvan Yan char *status_prop = NULL; 429426947304SEvan Yan #ifdef PCICFG_INTERPRET_FCODE 429526947304SEvan Yan struct pci_ops_bus_args po; 429626947304SEvan Yan fco_handle_t c; 429726947304SEvan Yan char unit_address[64]; 429826947304SEvan Yan int fcode_size = 0; 429926947304SEvan Yan uchar_t *fcode_addr; 430026947304SEvan Yan uint64_t mem_answer, mem_alen; 430126947304SEvan Yan pci_regspec_t p; 430226947304SEvan Yan int32_t request; 430326947304SEvan Yan ndi_ra_request_t req; 430426947304SEvan Yan int16_t vendor_id, device_id; 430526947304SEvan Yan #endif 430626947304SEvan Yan 430726947304SEvan Yan /* 430826947304SEvan Yan * check if our parent is of type pciex. 430926947304SEvan Yan * if so, program config space to disable error msgs during probe. 431026947304SEvan Yan */ 431126947304SEvan Yan if (pcicfg_pcie_dev(parent, PCICFG_DEVICE_TYPE_PCIE, &parent_regs) 431226947304SEvan Yan == DDI_SUCCESS) { 431326947304SEvan Yan DEBUG0("PCI/PCIe parent detected. Disable errors.\n"); 431426947304SEvan Yan /* 431526947304SEvan Yan * disable parent generating URs or SERR#s during probing 431626947304SEvan Yan * alone. 431726947304SEvan Yan */ 431826947304SEvan Yan if (pci_config_setup(parent, &ph) != DDI_SUCCESS) 431926947304SEvan Yan return (DDI_FAILURE); 432026947304SEvan Yan 432126947304SEvan Yan if ((flags & PCICFG_FLAG_READ_ONLY) == 0) { 432226947304SEvan Yan pcicfg_disable_bridge_probe_err(parent, 432326947304SEvan Yan ph, &parent_regs); 432426947304SEvan Yan } 432526947304SEvan Yan } 432626947304SEvan Yan 432726947304SEvan Yan /* 432826947304SEvan Yan * This node will be put immediately below 432926947304SEvan Yan * "parent". Allocate a blank device node. It will either 433026947304SEvan Yan * be filled in or freed up based on further probing. 433126947304SEvan Yan */ 433226947304SEvan Yan 433326947304SEvan Yan if (ndi_devi_alloc(parent, DEVI_PSEUDO_NEXNAME, 433426947304SEvan Yan (pnode_t)DEVI_SID_NODEID, &new_child) 433526947304SEvan Yan != NDI_SUCCESS) { 433626947304SEvan Yan DEBUG0("pcicfg_fcode_probe(): Failed to alloc child node\n"); 433726947304SEvan Yan /* return (PCICFG_FAILURE); */ 433826947304SEvan Yan ret = PCICFG_FAILURE; 433926947304SEvan Yan goto failed2; 434026947304SEvan Yan } 434126947304SEvan Yan 434226947304SEvan Yan /* 434326947304SEvan Yan * Create a dummy reg property. This will be replaced with 434426947304SEvan Yan * a real reg property when fcode completes or if we need to 434526947304SEvan Yan * produce one by hand. 434626947304SEvan Yan */ 434726947304SEvan Yan if (pcicfg_add_config_reg(new_child, bus, 434826947304SEvan Yan device, func) != DDI_SUCCESS) { 434926947304SEvan Yan ret = PCICFG_FAILURE; 435026947304SEvan Yan goto failed3; 435126947304SEvan Yan } 435226947304SEvan Yan #ifdef EFCODE21554 435326947304SEvan Yan if ((ret = pcicfg_config_setup(new_child, &h)) 435426947304SEvan Yan != PCICFG_SUCCESS) { 435526947304SEvan Yan DEBUG0("pcicfg_fcode_probe():" 435626947304SEvan Yan "Failed to setup config space\n"); 435726947304SEvan Yan ret = PCICFG_NODEVICE; 435826947304SEvan Yan goto failed3; 435926947304SEvan Yan } 436026947304SEvan Yan 436126947304SEvan Yan #else 436226947304SEvan Yan p.pci_phys_hi = PCICFG_MAKE_REG_HIGH(bus, device, func, 0); 436326947304SEvan Yan p.pci_phys_mid = p.pci_phys_low = 0; 436426947304SEvan Yan p.pci_size_hi = p.pci_size_low = 0; 436526947304SEvan Yan 436626947304SEvan Yan /* 436726947304SEvan Yan * Map in configuration space (temporarily) 436826947304SEvan Yan */ 436926947304SEvan Yan acc.devacc_attr_version = DDI_DEVICE_ATTR_V0; 437026947304SEvan Yan acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 437126947304SEvan Yan acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 437226947304SEvan Yan 437326947304SEvan Yan if (pcicfg_map_phys(new_child, &p, &virt, &acc, &h)) { 437426947304SEvan Yan DEBUG0("pcicfg_fcode_probe():" 437526947304SEvan Yan "Failed to setup config space\n"); 437626947304SEvan Yan ret = PCICFG_NODEVICE; 437726947304SEvan Yan goto failed3; 437826947304SEvan Yan } 437926947304SEvan Yan 438026947304SEvan Yan /* 438126947304SEvan Yan * First use ddi_peek16 so that if there is not a device there, 438226947304SEvan Yan * a bus error will not cause a panic. 438326947304SEvan Yan */ 438426947304SEvan Yan v = virt + PCI_CONF_VENID; 438526947304SEvan Yan if (ddi_peek16(new_child, (int16_t *)v, &vendor_id)) { 438626947304SEvan Yan DEBUG0("Can not read Vendor ID"); 438726947304SEvan Yan pcicfg_unmap_phys(&h, &p); 438826947304SEvan Yan ret = PCICFG_NODEVICE; 438926947304SEvan Yan goto failed3; 439026947304SEvan Yan } 439126947304SEvan Yan #endif 4392c0da6274SZhi-Jun Robin Fu 4393c0da6274SZhi-Jun Robin Fu if (is_pcie) 4394c0da6274SZhi-Jun Robin Fu (void) pcie_init_bus(new_child, PCI_GETBDF(bus, device, func), 4395c0da6274SZhi-Jun Robin Fu PCIE_BUS_INITIAL); 4396c0da6274SZhi-Jun Robin Fu 439726947304SEvan Yan DEBUG0("fcode_probe: conf space mapped.\n"); 439826947304SEvan Yan /* 439926947304SEvan Yan * As soon as we have access to config space, 440026947304SEvan Yan * turn off device. It will get turned on 440126947304SEvan Yan * later (after memory is assigned). 440226947304SEvan Yan */ 440326947304SEvan Yan (void) pcicfg_device_off(h); 440426947304SEvan Yan 440526947304SEvan Yan /* check if we are PCIe device */ 440626947304SEvan Yan if (pcicfg_pcie_dev(new_child, PCICFG_DEVICE_TYPE_PCIE, ®s) 440726947304SEvan Yan == DDI_SUCCESS) { 440826947304SEvan Yan /*EMPTY*/ 440926947304SEvan Yan DEBUG0("PCI/PCIe device detected\n"); 441026947304SEvan Yan } 441126947304SEvan Yan 441226947304SEvan Yan /* 441326947304SEvan Yan * Set 1275 properties common to all devices 441426947304SEvan Yan */ 441526947304SEvan Yan if (pcicfg_set_standard_props(new_child, 441626947304SEvan Yan h, regs.pcie_dev) != PCICFG_SUCCESS) { 441726947304SEvan Yan DEBUG0("Failed to set standard properties\n"); 441826947304SEvan Yan goto failed; 441926947304SEvan Yan } 442026947304SEvan Yan 442126947304SEvan Yan /* 442226947304SEvan Yan * Child node properties NOTE: Both for PCI-PCI bridge and child node 442326947304SEvan Yan */ 442426947304SEvan Yan if (pcicfg_set_childnode_props(new_child, 442526947304SEvan Yan h, regs.pcie_dev) != PCICFG_SUCCESS) { 442626947304SEvan Yan ret = PCICFG_FAILURE; 442726947304SEvan Yan goto failed; 442826947304SEvan Yan } 442926947304SEvan Yan 443026947304SEvan Yan header_type = pci_config_get8(h, PCI_CONF_HEADER); 443126947304SEvan Yan 443226947304SEvan Yan /* 443326947304SEvan Yan * If this is not a multi-function card only probe function zero. 443426947304SEvan Yan */ 443526947304SEvan Yan if (!(header_type & PCI_HEADER_MULTI) && (func > 0)) { 443626947304SEvan Yan 443726947304SEvan Yan ret = PCICFG_NODEVICE; 443826947304SEvan Yan goto failed; 443926947304SEvan Yan } 444026947304SEvan Yan 444126947304SEvan Yan if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) { 444226947304SEvan Yan 444326947304SEvan Yan /* 444426947304SEvan Yan * XXX - Transparent bridges are handled differently 444526947304SEvan Yan * than other devices with regards to fcode. Since 444626947304SEvan Yan * no transparent bridge currently ships with fcode, 444726947304SEvan Yan * there is no reason to try to extract it from its rom 444826947304SEvan Yan * or call the fcode interpreter to try to load a drop-in. 444926947304SEvan Yan * If fcode is developed to handle transparent bridges, 445026947304SEvan Yan * this code will have to change. 445126947304SEvan Yan */ 445226947304SEvan Yan 445326947304SEvan Yan DEBUG3("--Bridge found bus [0x%x] device" 445426947304SEvan Yan "[0x%x] func [0x%x]\n", bus, device, func); 445526947304SEvan Yan 445626947304SEvan Yan /* Only support read-only probe for leaf device */ 445726947304SEvan Yan if (flags & PCICFG_FLAG_READ_ONLY) 445826947304SEvan Yan goto failed; 445926947304SEvan Yan 446026947304SEvan Yan if ((ret = pcicfg_probe_bridge(new_child, h, 4461c0da6274SZhi-Jun Robin Fu bus, highest_bus, is_pcie)) != PCICFG_SUCCESS) 446226947304SEvan Yan (void) pcicfg_free_bridge_resources(new_child); 446326947304SEvan Yan goto done; 446426947304SEvan Yan } else { 446526947304SEvan Yan 446626947304SEvan Yan DEBUG3("--Leaf device found bus [0x%x] device" 446726947304SEvan Yan "[0x%x] func [0x%x]\n", 446826947304SEvan Yan bus, device, func); 446926947304SEvan Yan 447026947304SEvan Yan /* 447126947304SEvan Yan * link in tree, but don't bind driver 447226947304SEvan Yan * We don't have compatible property yet 447326947304SEvan Yan */ 447426947304SEvan Yan (void) i_ndi_config_node(new_child, DS_LINKED, 0); 447526947304SEvan Yan 447626947304SEvan Yan /* XXX for now, don't run Fcode in read-only probe. */ 447726947304SEvan Yan if (flags & PCICFG_FLAG_READ_ONLY) 447826947304SEvan Yan goto no_fcode; 447926947304SEvan Yan 448026947304SEvan Yan if (pci_config_get8(h, PCI_CONF_IPIN)) { 448126947304SEvan Yan pci_config_put8(h, PCI_CONF_ILINE, 0xf); 448226947304SEvan Yan } 448326947304SEvan Yan 448426947304SEvan Yan #ifdef PCICFG_INTERPRET_FCODE 448526947304SEvan Yan /* 448626947304SEvan Yan * Some platforms (x86) don't run fcode, so don't interpret 448726947304SEvan Yan * fcode that might be in the ROM. 448826947304SEvan Yan */ 448926947304SEvan Yan if (pcicfg_dont_interpret == 0) { 449026947304SEvan Yan 449126947304SEvan Yan /* This platform supports fcode */ 449226947304SEvan Yan 449326947304SEvan Yan vendor_id = pci_config_get16(h, PCI_CONF_VENID); 449426947304SEvan Yan device_id = pci_config_get16(h, PCI_CONF_DEVID); 449526947304SEvan Yan 449626947304SEvan Yan /* 449726947304SEvan Yan * Get the ROM size and create register for it 449826947304SEvan Yan */ 449926947304SEvan Yan pci_config_put32(h, PCI_CONF_ROM, 0xfffffffe); 450026947304SEvan Yan 450126947304SEvan Yan request = pci_config_get32(h, PCI_CONF_ROM); 450226947304SEvan Yan 450326947304SEvan Yan /* 450426947304SEvan Yan * If its a zero length, don't do 450526947304SEvan Yan * any programming. 450626947304SEvan Yan */ 450726947304SEvan Yan 450826947304SEvan Yan if (request != 0) { 450926947304SEvan Yan /* 451026947304SEvan Yan * Add resource to assigned-addresses. 451126947304SEvan Yan */ 451226947304SEvan Yan if (pcicfg_fcode_assign_bars(h, new_child, 451326947304SEvan Yan bus, device, func, request, &p) 451426947304SEvan Yan != PCICFG_SUCCESS) { 451526947304SEvan Yan DEBUG0("Failed to assign addresses to " 451626947304SEvan Yan "implemented BARs"); 451726947304SEvan Yan ret = PCICFG_FAILURE; 451826947304SEvan Yan goto failed; 451926947304SEvan Yan } 452026947304SEvan Yan 452126947304SEvan Yan /* Turn device on */ 452226947304SEvan Yan (void) pcicfg_device_on(h); 452326947304SEvan Yan 452426947304SEvan Yan /* 452526947304SEvan Yan * Attempt to load fcode. 452626947304SEvan Yan */ 452726947304SEvan Yan (void) pcicfg_load_fcode(new_child, bus, device, 452826947304SEvan Yan func, vendor_id, device_id, &fcode_addr, 452926947304SEvan Yan &fcode_size, PCICFG_LOADDR(mem_answer), 453026947304SEvan Yan (~(PCI_BASE_ROM_ADDR_M & request)) + 1); 453126947304SEvan Yan 453226947304SEvan Yan /* Turn device off */ 453326947304SEvan Yan (void) pcicfg_device_off(h); 453426947304SEvan Yan 453526947304SEvan Yan /* 453626947304SEvan Yan * Free the ROM resources. 453726947304SEvan Yan */ 453826947304SEvan Yan (void) pcicfg_free_resource(new_child, p, 0); 453926947304SEvan Yan 454026947304SEvan Yan DEBUG2("configure: fcode addr %lx size %x\n", 454126947304SEvan Yan fcode_addr, fcode_size); 454226947304SEvan Yan 454326947304SEvan Yan /* 454426947304SEvan Yan * Create the fcode-rom-offset property. The 454526947304SEvan Yan * buffer containing the fcode always starts 454626947304SEvan Yan * with 0xF1, so the fcode offset is zero. 454726947304SEvan Yan */ 454826947304SEvan Yan if (ndi_prop_update_int(DDI_DEV_T_NONE, 454926947304SEvan Yan new_child, "fcode-rom-offset", 0) 455026947304SEvan Yan != DDI_SUCCESS) { 455126947304SEvan Yan DEBUG0("Failed to create " 455226947304SEvan Yan "fcode-rom-offset property\n"); 455326947304SEvan Yan ret = PCICFG_FAILURE; 455426947304SEvan Yan goto failed; 455526947304SEvan Yan } 455626947304SEvan Yan } else { 455726947304SEvan Yan DEBUG0("There is no Expansion ROM\n"); 455826947304SEvan Yan fcode_addr = NULL; 455926947304SEvan Yan fcode_size = 0; 456026947304SEvan Yan } 456126947304SEvan Yan 456226947304SEvan Yan /* 456326947304SEvan Yan * Fill in the bus specific arguments. For 456426947304SEvan Yan * PCI, it is the config address. 456526947304SEvan Yan */ 456626947304SEvan Yan po.config_address = 456726947304SEvan Yan PCICFG_MAKE_REG_HIGH(bus, device, func, 0); 456826947304SEvan Yan 456926947304SEvan Yan DEBUG1("config_address=%x\n", po.config_address); 457026947304SEvan Yan 457126947304SEvan Yan /* 457226947304SEvan Yan * Build unit address. 457326947304SEvan Yan */ 457426947304SEvan Yan (void) sprintf(unit_address, "%x,%x", device, func); 457526947304SEvan Yan 457626947304SEvan Yan DEBUG3("pci_fc_ops_alloc_handle ap=%lx " 457726947304SEvan Yan "new device=%lx unit address=%s\n", 457826947304SEvan Yan parent, new_child, unit_address); 457926947304SEvan Yan 458026947304SEvan Yan c = pci_fc_ops_alloc_handle(parent, new_child, 458126947304SEvan Yan fcode_addr, fcode_size, unit_address, &po); 458226947304SEvan Yan 458326947304SEvan Yan DEBUG0("calling fcode_interpreter()\n"); 458426947304SEvan Yan 458526947304SEvan Yan DEBUG3("Before int DIP=%lx binding name %s major %d\n", 458626947304SEvan Yan new_child, ddi_binding_name(new_child), 458726947304SEvan Yan ddi_driver_major(new_child)); 458826947304SEvan Yan 458926947304SEvan Yan error = fcode_interpreter(parent, &pci_fc_ops, c); 459026947304SEvan Yan 459126947304SEvan Yan DEBUG1("returned from fcode_interpreter() - " 459226947304SEvan Yan "returned %x\n", error); 459326947304SEvan Yan 459426947304SEvan Yan pci_fc_ops_free_handle(c); 459526947304SEvan Yan 459626947304SEvan Yan DEBUG1("fcode size = %x\n", fcode_size); 459726947304SEvan Yan /* 459826947304SEvan Yan * We don't need the fcode anymore. While allocating 459926947304SEvan Yan * we had rounded up to a page size. 460026947304SEvan Yan */ 460126947304SEvan Yan if (fcode_size) { 460226947304SEvan Yan kmem_free(fcode_addr, ptob(btopr(fcode_size))); 460326947304SEvan Yan } 460426947304SEvan Yan } else { 460526947304SEvan Yan /* This platform does not support fcode */ 460626947304SEvan Yan 460726947304SEvan Yan DEBUG0("NOT calling fcode_interpreter()\n"); 460826947304SEvan Yan } 460926947304SEvan Yan 461026947304SEvan Yan #endif /* PCICFG_INTERPRET_FCODE */ 461126947304SEvan Yan 461226947304SEvan Yan if ((error == 0) && (pcicfg_dont_interpret == 0)) { 461326947304SEvan Yan /* 461426947304SEvan Yan * The interpreter completed successfully. 461526947304SEvan Yan * We need to redo the resources based on the new reg 461626947304SEvan Yan * property. 461726947304SEvan Yan */ 461826947304SEvan Yan DEBUG3("DIP=%lx binding name %s major %d\n", new_child, 461926947304SEvan Yan ddi_binding_name(new_child), 462026947304SEvan Yan ddi_driver_major(new_child)); 462126947304SEvan Yan 462226947304SEvan Yan /* 462326947304SEvan Yan * Readjust resources specified by reg property. 462426947304SEvan Yan */ 462526947304SEvan Yan if (pcicfg_alloc_new_resources(new_child) == 462626947304SEvan Yan PCICFG_FAILURE) { 462726947304SEvan Yan ret = PCICFG_FAILURE; 462826947304SEvan Yan goto failed; 462926947304SEvan Yan } 463026947304SEvan Yan 463126947304SEvan Yan /* 463226947304SEvan Yan * At this stage, there should be enough info to pull 463326947304SEvan Yan * the status property if it exists. 463426947304SEvan Yan */ 463526947304SEvan Yan if (ddi_prop_lookup_string(DDI_DEV_T_ANY, 463626947304SEvan Yan new_child, NULL, "status", &status_prop) == 463726947304SEvan Yan DDI_PROP_SUCCESS) { 463826947304SEvan Yan if ((strncmp("disabled", status_prop, 8) == 463926947304SEvan Yan 0) || (strncmp("fail", status_prop, 4) == 464026947304SEvan Yan 0)) { 464126947304SEvan Yan ret = PCICFG_FAILURE; 464226947304SEvan Yan ddi_prop_free(status_prop); 464326947304SEvan Yan goto failed; 464426947304SEvan Yan } else { 464526947304SEvan Yan ddi_prop_free(status_prop); 464626947304SEvan Yan } 464726947304SEvan Yan } 464826947304SEvan Yan 464926947304SEvan Yan ret = PCICFG_SUCCESS; 465026947304SEvan Yan /* no fcode, bind driver now */ 465126947304SEvan Yan (void) ndi_devi_bind_driver(new_child, 0); 465226947304SEvan Yan 465326947304SEvan Yan goto done; 465426947304SEvan Yan } else if ((error != FC_NO_FCODE) && 465526947304SEvan Yan (pcicfg_dont_interpret == 0)) { 465626947304SEvan Yan /* 465726947304SEvan Yan * The interpreter located fcode, but had an error in 465826947304SEvan Yan * processing. Cleanup and fail the operation. 465926947304SEvan Yan */ 466026947304SEvan Yan DEBUG0("Interpreter detected fcode failure\n"); 466126947304SEvan Yan (void) pcicfg_free_resources(new_child, flags); 466226947304SEvan Yan ret = PCICFG_FAILURE; 466326947304SEvan Yan goto failed; 466426947304SEvan Yan } else { 466526947304SEvan Yan no_fcode: 466626947304SEvan Yan /* 466726947304SEvan Yan * Either the interpreter failed with FC_NO_FCODE or we 466826947304SEvan Yan * chose not to run the interpreter 466926947304SEvan Yan * (pcicfg_dont_interpret). 467026947304SEvan Yan * 467126947304SEvan Yan * If the interpreter failed because there was no 467226947304SEvan Yan * dropin, then we need to probe the device ourself. 467326947304SEvan Yan */ 467426947304SEvan Yan 467526947304SEvan Yan /* 467626947304SEvan Yan * Free any resources that may have been assigned 467726947304SEvan Yan * during fcode loading/execution since we need 467826947304SEvan Yan * to start over. 467926947304SEvan Yan */ 468026947304SEvan Yan (void) pcicfg_free_resources(new_child, flags); 468126947304SEvan Yan 468226947304SEvan Yan #ifdef EFCODE21554 468326947304SEvan Yan pcicfg_config_teardown(&h); 468426947304SEvan Yan #else 468526947304SEvan Yan pcicfg_unmap_phys(&h, &p); 468626947304SEvan Yan #endif 4687c0da6274SZhi-Jun Robin Fu /* destroy the bus_t before the dev node is gone */ 4688c0da6274SZhi-Jun Robin Fu if (is_pcie) 4689c0da6274SZhi-Jun Robin Fu pcie_fini_bus(new_child, PCIE_BUS_FINAL); 4690c0da6274SZhi-Jun Robin Fu 469126947304SEvan Yan (void) ndi_devi_free(new_child); 469226947304SEvan Yan 469326947304SEvan Yan DEBUG0("No Drop-in Probe device ourself\n"); 469426947304SEvan Yan 469526947304SEvan Yan ret = pcicfg_probe_children(parent, bus, device, func, 4696c0da6274SZhi-Jun Robin Fu highest_bus, flags, is_pcie); 469726947304SEvan Yan 469826947304SEvan Yan if (ret != PCICFG_SUCCESS) { 469926947304SEvan Yan DEBUG0("Could not self probe child\n"); 470026947304SEvan Yan goto failed2; 470126947304SEvan Yan } 470226947304SEvan Yan 470326947304SEvan Yan /* 470426947304SEvan Yan * We successfully self probed the device. 470526947304SEvan Yan */ 470626947304SEvan Yan if ((new_child = pcicfg_devi_find( 470726947304SEvan Yan parent, device, func)) == NULL) { 470826947304SEvan Yan DEBUG0("Did'nt find device node " 470926947304SEvan Yan "just created\n"); 471026947304SEvan Yan ret = PCICFG_FAILURE; 471126947304SEvan Yan goto failed2; 471226947304SEvan Yan } 471326947304SEvan Yan #ifdef EFCODE21554 471426947304SEvan Yan /* 471526947304SEvan Yan * Till now, we have detected a non transparent bridge 471626947304SEvan Yan * (ntbridge) as a part of the generic probe code and 471726947304SEvan Yan * configured only one configuration 471826947304SEvan Yan * header which is the side facing the host bus. 471926947304SEvan Yan * Now, configure the other side and create children. 472026947304SEvan Yan * 472126947304SEvan Yan * To make the process simpler, lets load the device 472226947304SEvan Yan * driver for the non transparent bridge as this is a 472326947304SEvan Yan * Solaris bundled driver, and use its configuration map 472426947304SEvan Yan * services rather than programming it here. 472526947304SEvan Yan * If the driver is not bundled into Solaris, it must be 472626947304SEvan Yan * first loaded and configured before performing any 472726947304SEvan Yan * hotplug operations. 472826947304SEvan Yan * 472926947304SEvan Yan * This not only makes the code simpler but also more 473026947304SEvan Yan * generic. 473126947304SEvan Yan * 473226947304SEvan Yan * So here we go. 473326947304SEvan Yan */ 473426947304SEvan Yan if (pcicfg_is_ntbridge(new_child) != DDI_FAILURE) { 473526947304SEvan Yan 473626947304SEvan Yan DEBUG0("Found nontransparent bridge.\n"); 473726947304SEvan Yan 473826947304SEvan Yan ret = pcicfg_configure_ntbridge(new_child, 473926947304SEvan Yan bus, device); 474026947304SEvan Yan } 474126947304SEvan Yan if (ret != PCICFG_SUCCESS) { 474226947304SEvan Yan /* 474326947304SEvan Yan * Bridge configure failed. Free up the self 474426947304SEvan Yan * probed entry. The bus resource allocation 474526947304SEvan Yan * maps need to be cleaned up to prevent 474626947304SEvan Yan * warnings on retries of the failed configure. 474726947304SEvan Yan */ 474826947304SEvan Yan (void) pcicfg_ntbridge_unconfigure(new_child); 4749c0da6274SZhi-Jun Robin Fu (void) pcicfg_teardown_device(new_child, 4750c0da6274SZhi-Jun Robin Fu flags, is_pcie); 475126947304SEvan Yan } 475226947304SEvan Yan #endif 475326947304SEvan Yan goto done2; 475426947304SEvan Yan } 475526947304SEvan Yan } 475626947304SEvan Yan done: 475726947304SEvan Yan failed: 4758c0da6274SZhi-Jun Robin Fu if (is_pcie) { 4759c0da6274SZhi-Jun Robin Fu if (ret == PCICFG_SUCCESS) 4760c1374a13SSurya Prakki (void) pcie_init_bus(new_child, 0, PCIE_BUS_FINAL); 4761c0da6274SZhi-Jun Robin Fu else 4762c0da6274SZhi-Jun Robin Fu pcie_fini_bus(new_child, PCIE_BUS_FINAL); 4763c0da6274SZhi-Jun Robin Fu } 4764c0da6274SZhi-Jun Robin Fu 476526947304SEvan Yan #ifdef EFCODE21554 476626947304SEvan Yan pcicfg_config_teardown(&h); 476726947304SEvan Yan #else 476826947304SEvan Yan pcicfg_unmap_phys(&h, &p); 476926947304SEvan Yan #endif 477026947304SEvan Yan failed3: 477126947304SEvan Yan if (ret != PCICFG_SUCCESS) 477226947304SEvan Yan (void) ndi_devi_free(new_child); 477326947304SEvan Yan done2: 477426947304SEvan Yan failed2: 477526947304SEvan Yan if (parent_regs.pcie_dev) { 477626947304SEvan Yan if ((flags & PCICFG_FLAG_READ_ONLY) == 0) { 477726947304SEvan Yan pcicfg_enable_bridge_probe_err(parent, 477826947304SEvan Yan ph, &parent_regs); 477926947304SEvan Yan } 478026947304SEvan Yan pci_config_teardown(&ph); 478126947304SEvan Yan } 4782c0da6274SZhi-Jun Robin Fu 478326947304SEvan Yan return (ret); 478426947304SEvan Yan } 478526947304SEvan Yan 478626947304SEvan Yan /* 478726947304SEvan Yan * Read the BARs and update properties. Used in virtual hotplug. 478826947304SEvan Yan */ 478926947304SEvan Yan static int 479026947304SEvan Yan pcicfg_populate_props_from_bar(dev_info_t *new_child, 479126947304SEvan Yan ddi_acc_handle_t config_handle) 479226947304SEvan Yan { 479326947304SEvan Yan uint32_t request, base, base_hi, size; 479426947304SEvan Yan int i; 479526947304SEvan Yan 479626947304SEvan Yan i = PCI_CONF_BASE0; 479726947304SEvan Yan 479826947304SEvan Yan while (i <= PCI_CONF_BASE5) { 479926947304SEvan Yan /* 480026947304SEvan Yan * determine the size of the address space 480126947304SEvan Yan */ 480226947304SEvan Yan base = pci_config_get32(config_handle, i); 480326947304SEvan Yan pci_config_put32(config_handle, i, 0xffffffff); 480426947304SEvan Yan request = pci_config_get32(config_handle, i); 480526947304SEvan Yan pci_config_put32(config_handle, i, base); 480626947304SEvan Yan 480726947304SEvan Yan /* 480826947304SEvan Yan * If its a zero length, don't do any programming. 480926947304SEvan Yan */ 481026947304SEvan Yan if (request != 0) { 481126947304SEvan Yan /* 481226947304SEvan Yan * Add to the "reg" property 481326947304SEvan Yan */ 481426947304SEvan Yan if (pcicfg_update_reg_prop(new_child, 481526947304SEvan Yan request, i) != PCICFG_SUCCESS) { 481626947304SEvan Yan goto failedchild; 481726947304SEvan Yan } 481826947304SEvan Yan 481926947304SEvan Yan if ((PCI_BASE_SPACE_IO & request) == 0 && 482026947304SEvan Yan (PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_ALL) { 482126947304SEvan Yan base_hi = pci_config_get32(config_handle, i+4); 482226947304SEvan Yan } else { 482326947304SEvan Yan base_hi = 0; 482426947304SEvan Yan } 482526947304SEvan Yan /* 482626947304SEvan Yan * Add to "assigned-addresses" property 482726947304SEvan Yan */ 482826947304SEvan Yan size = (~(PCI_BASE_M_ADDR_M & request))+1; 482926947304SEvan Yan if (pcicfg_update_assigned_prop_value(new_child, 483026947304SEvan Yan size, base, base_hi, i) != PCICFG_SUCCESS) { 483126947304SEvan Yan goto failedchild; 483226947304SEvan Yan } 483326947304SEvan Yan } else { 483426947304SEvan Yan DEBUG1("BASE register [0x%x] asks for " 483526947304SEvan Yan "[0x0]=[0x0](32)\n", i); 483626947304SEvan Yan i += 4; 483726947304SEvan Yan continue; 483826947304SEvan Yan } 483926947304SEvan Yan 484026947304SEvan Yan /* 484126947304SEvan Yan * Increment by eight if it is 64 bit address space 484226947304SEvan Yan */ 484326947304SEvan Yan if ((PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_ALL) { 484426947304SEvan Yan DEBUG3("BASE register [0x%x] asks for " 484526947304SEvan Yan "[0x%x]=[0x%x] (64)\n", 484626947304SEvan Yan i, request, 484726947304SEvan Yan (~(PCI_BASE_M_ADDR_M & request))+1) 484826947304SEvan Yan i += 8; 484926947304SEvan Yan } else { 485026947304SEvan Yan DEBUG3("BASE register [0x%x] asks for " 485126947304SEvan Yan "[0x%x]=[0x%x](32)\n", 485226947304SEvan Yan i, request, 485326947304SEvan Yan (~(PCI_BASE_M_ADDR_M & request))+1) 485426947304SEvan Yan i += 4; 485526947304SEvan Yan } 485626947304SEvan Yan } 485726947304SEvan Yan 485826947304SEvan Yan /* 485926947304SEvan Yan * Get the ROM size and create register for it 486026947304SEvan Yan */ 486126947304SEvan Yan base = pci_config_get32(config_handle, PCI_CONF_ROM); 486226947304SEvan Yan pci_config_put32(config_handle, PCI_CONF_ROM, 0xfffffffe); 486326947304SEvan Yan request = pci_config_get32(config_handle, PCI_CONF_ROM); 486426947304SEvan Yan pci_config_put32(config_handle, PCI_CONF_ROM, base); 486526947304SEvan Yan 486626947304SEvan Yan /* 486726947304SEvan Yan * If its a zero length, don't do 486826947304SEvan Yan * any programming. 486926947304SEvan Yan */ 487026947304SEvan Yan if (request != 0) { 487126947304SEvan Yan DEBUG3("BASE register [0x%x] asks for [0x%x]=[0x%x]\n", 487226947304SEvan Yan PCI_CONF_ROM, request, 487326947304SEvan Yan (~(PCI_BASE_ROM_ADDR_M & request))+1); 487426947304SEvan Yan /* 487526947304SEvan Yan * Add to the "reg" property 487626947304SEvan Yan */ 487726947304SEvan Yan if (pcicfg_update_reg_prop(new_child, 487826947304SEvan Yan request, PCI_CONF_ROM) != PCICFG_SUCCESS) { 487926947304SEvan Yan goto failedchild; 488026947304SEvan Yan } 488126947304SEvan Yan /* 488226947304SEvan Yan * Add to "assigned-addresses" property 488326947304SEvan Yan */ 488426947304SEvan Yan size = (~(PCI_BASE_ROM_ADDR_M & request))+1; 488526947304SEvan Yan if (pcicfg_update_assigned_prop_value(new_child, size, 488626947304SEvan Yan base, 0, PCI_CONF_ROM) != PCICFG_SUCCESS) { 488726947304SEvan Yan goto failedchild; 488826947304SEvan Yan } 488926947304SEvan Yan } 489026947304SEvan Yan 489126947304SEvan Yan return (PCICFG_SUCCESS); 489226947304SEvan Yan 489326947304SEvan Yan failedchild: 489426947304SEvan Yan return (PCICFG_FAILURE); 489526947304SEvan Yan } 489626947304SEvan Yan 489726947304SEvan Yan static int 489826947304SEvan Yan pcicfg_probe_bridge(dev_info_t *new_child, ddi_acc_handle_t h, uint_t bus, 4899c0da6274SZhi-Jun Robin Fu uint_t *highest_bus, boolean_t is_pcie) 490026947304SEvan Yan { 490126947304SEvan Yan uint64_t next_bus; 490226947304SEvan Yan uint_t new_bus, num_slots; 490326947304SEvan Yan ndi_ra_request_t req; 490426947304SEvan Yan int rval, i, j; 490526947304SEvan Yan uint64_t mem_answer, mem_base, mem_alen, mem_size, mem_end; 490626947304SEvan Yan uint64_t io_answer, io_base, io_alen, io_size, io_end; 490726947304SEvan Yan uint64_t round_answer, round_len; 490826947304SEvan Yan pcicfg_range_t range[PCICFG_RANGE_LEN]; 490926947304SEvan Yan int bus_range[2]; 491026947304SEvan Yan pcicfg_phdl_t phdl; 491126947304SEvan Yan int count; 491226947304SEvan Yan uint64_t pcibus_base, pcibus_alen; 491326947304SEvan Yan uint64_t max_bus; 491426947304SEvan Yan uint8_t pcie_device_type = 0; 491526947304SEvan Yan dev_info_t *new_device; 491626947304SEvan Yan int trans_device; 491726947304SEvan Yan int ari_mode = B_FALSE; 491826947304SEvan Yan int max_function = PCICFG_MAX_FUNCTION; 491926947304SEvan Yan 492026947304SEvan Yan /* 492126947304SEvan Yan * Set "device_type" to "pci", the actual type will be set later 492226947304SEvan Yan * by pcicfg_set_busnode_props() below. This is needed as the 492326947304SEvan Yan * pcicfg_ra_free() below would update "available" property based 492426947304SEvan Yan * on "device_type". 492526947304SEvan Yan * 492626947304SEvan Yan * This code can be removed later after PCI configurator is changed 492726947304SEvan Yan * to use PCIRM, which automatically update properties upon allocation 492826947304SEvan Yan * and free, at that time we'll be able to remove the code inside 492926947304SEvan Yan * ndi_ra_alloc/free() which currently updates "available" property 493026947304SEvan Yan * for pci/pcie devices in pcie fabric. 493126947304SEvan Yan */ 493226947304SEvan Yan if (ndi_prop_update_string(DDI_DEV_T_NONE, new_child, 493326947304SEvan Yan "device_type", "pci") != DDI_SUCCESS) { 493426947304SEvan Yan DEBUG0("Failed to set \"device_type\" props\n"); 493526947304SEvan Yan return (PCICFG_FAILURE); 493626947304SEvan Yan } 493726947304SEvan Yan 493826947304SEvan Yan bzero((caddr_t)&req, sizeof (ndi_ra_request_t)); 493926947304SEvan Yan req.ra_flags = (NDI_RA_ALLOC_BOUNDED | NDI_RA_ALLOC_PARTIAL_OK); 494026947304SEvan Yan req.ra_boundbase = 0; 494126947304SEvan Yan req.ra_boundlen = PCICFG_MAX_BUS_DEPTH; 494226947304SEvan Yan req.ra_len = PCICFG_MAX_BUS_DEPTH; 494326947304SEvan Yan req.ra_align_mask = 0; /* no alignment needed */ 494426947304SEvan Yan 494526947304SEvan Yan rval = ndi_ra_alloc(ddi_get_parent(new_child), &req, 494626947304SEvan Yan &pcibus_base, &pcibus_alen, NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS); 494726947304SEvan Yan 494826947304SEvan Yan if (rval != NDI_SUCCESS) { 494926947304SEvan Yan if (rval == NDI_RA_PARTIAL_REQ) { 495026947304SEvan Yan /*EMPTY*/ 495126947304SEvan Yan DEBUG0("NDI_RA_PARTIAL_REQ returned for bus range\n"); 495226947304SEvan Yan } else { 495326947304SEvan Yan DEBUG0( 495426947304SEvan Yan "Failed to allocate bus range for bridge\n"); 495526947304SEvan Yan return (PCICFG_FAILURE); 495626947304SEvan Yan } 495726947304SEvan Yan } 495826947304SEvan Yan 495926947304SEvan Yan DEBUG2("Bus Range Allocated [base=%d] [len=%d]\n", 496026947304SEvan Yan pcibus_base, pcibus_alen); 496126947304SEvan Yan 496226947304SEvan Yan if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_PCI_BUSNUM) 496326947304SEvan Yan == NDI_FAILURE) { 496426947304SEvan Yan DEBUG0("Can not setup resource map - NDI_RA_TYPE_PCI_BUSNUM\n"); 496526947304SEvan Yan return (PCICFG_FAILURE); 496626947304SEvan Yan } 496726947304SEvan Yan 496826947304SEvan Yan /* 496926947304SEvan Yan * Put available bus range into the pool. 497026947304SEvan Yan * Take the first one for this bridge to use and don't give 497126947304SEvan Yan * to child. 497226947304SEvan Yan */ 497326947304SEvan Yan (void) ndi_ra_free(new_child, pcibus_base+1, pcibus_alen-1, 497426947304SEvan Yan NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS); 497526947304SEvan Yan 497626947304SEvan Yan next_bus = pcibus_base; 497726947304SEvan Yan max_bus = pcibus_base + pcibus_alen - 1; 497826947304SEvan Yan 497926947304SEvan Yan new_bus = next_bus; 498026947304SEvan Yan 498126947304SEvan Yan DEBUG1("NEW bus found ->[%d]\n", new_bus); 498226947304SEvan Yan 498326947304SEvan Yan /* Keep track of highest bus for subordinate bus programming */ 498426947304SEvan Yan *highest_bus = new_bus; 498526947304SEvan Yan 498626947304SEvan Yan /* 498726947304SEvan Yan * Allocate Memory Space for Bridge 498826947304SEvan Yan */ 498926947304SEvan Yan bzero((caddr_t)&req, sizeof (ndi_ra_request_t)); 499026947304SEvan Yan req.ra_flags = (NDI_RA_ALLOC_BOUNDED | NDI_RA_ALLOC_PARTIAL_OK); 499126947304SEvan Yan req.ra_boundbase = 0; 499226947304SEvan Yan /* 499326947304SEvan Yan * Note: To support a 32b system, boundlen and len need to be 499426947304SEvan Yan * 32b quantities 499526947304SEvan Yan */ 499626947304SEvan Yan req.ra_boundlen = PCICFG_4GIG_LIMIT + 1; 499726947304SEvan Yan req.ra_len = PCICFG_4GIG_LIMIT + 1; /* Get as big as possible */ 499826947304SEvan Yan req.ra_align_mask = 499926947304SEvan Yan PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */ 500026947304SEvan Yan 500126947304SEvan Yan rval = ndi_ra_alloc(ddi_get_parent(new_child), &req, 500226947304SEvan Yan &mem_answer, &mem_alen, NDI_RA_TYPE_MEM, NDI_RA_PASS); 500326947304SEvan Yan 500426947304SEvan Yan if (rval != NDI_SUCCESS) { 500526947304SEvan Yan if (rval == NDI_RA_PARTIAL_REQ) { 500626947304SEvan Yan /*EMPTY*/ 500726947304SEvan Yan DEBUG0("NDI_RA_PARTIAL_REQ returned\n"); 500826947304SEvan Yan } else { 500926947304SEvan Yan DEBUG0( 501026947304SEvan Yan "Failed to allocate memory for bridge\n"); 501126947304SEvan Yan return (PCICFG_FAILURE); 501226947304SEvan Yan } 501326947304SEvan Yan } 501426947304SEvan Yan 501526947304SEvan Yan DEBUG3("Bridge Memory Allocated [0x%x.%x] len [0x%x]\n", 501626947304SEvan Yan PCICFG_HIADDR(mem_answer), 501726947304SEvan Yan PCICFG_LOADDR(mem_answer), 501826947304SEvan Yan mem_alen); 501926947304SEvan Yan 502026947304SEvan Yan if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_MEM) == NDI_FAILURE) { 502126947304SEvan Yan DEBUG0("Can not setup resource map - NDI_RA_TYPE_MEM\n"); 502226947304SEvan Yan return (PCICFG_FAILURE); 502326947304SEvan Yan } 502426947304SEvan Yan 502526947304SEvan Yan /* 502626947304SEvan Yan * Put available memory into the pool. 502726947304SEvan Yan */ 502826947304SEvan Yan (void) ndi_ra_free(new_child, mem_answer, mem_alen, NDI_RA_TYPE_MEM, 502926947304SEvan Yan NDI_RA_PASS); 503026947304SEvan Yan 503126947304SEvan Yan mem_base = mem_answer; 503226947304SEvan Yan 503326947304SEvan Yan /* 503426947304SEvan Yan * Allocate I/O Space for Bridge 503526947304SEvan Yan */ 503626947304SEvan Yan bzero((caddr_t)&req, sizeof (ndi_ra_request_t)); 503726947304SEvan Yan req.ra_align_mask = PCICFG_IOGRAN - 1; /* 4k alignment */ 503826947304SEvan Yan req.ra_boundbase = 0; 503926947304SEvan Yan req.ra_boundlen = PCICFG_4GIG_LIMIT; 504026947304SEvan Yan req.ra_flags = (NDI_RA_ALLOC_BOUNDED | NDI_RA_ALLOC_PARTIAL_OK); 504126947304SEvan Yan req.ra_len = PCICFG_4GIG_LIMIT; /* Get as big as possible */ 504226947304SEvan Yan 504326947304SEvan Yan rval = ndi_ra_alloc(ddi_get_parent(new_child), &req, &io_answer, 504426947304SEvan Yan &io_alen, NDI_RA_TYPE_IO, NDI_RA_PASS); 504526947304SEvan Yan 504626947304SEvan Yan if (rval != NDI_SUCCESS) { 504726947304SEvan Yan if (rval == NDI_RA_PARTIAL_REQ) { 504826947304SEvan Yan /*EMPTY*/ 504926947304SEvan Yan DEBUG0("NDI_RA_PARTIAL_REQ returned\n"); 505026947304SEvan Yan } else { 505126947304SEvan Yan DEBUG0("Failed to allocate io space for bridge\n"); 505226947304SEvan Yan io_base = io_answer = io_alen = 0; 505326947304SEvan Yan /* return (PCICFG_FAILURE); */ 505426947304SEvan Yan } 505526947304SEvan Yan } 505626947304SEvan Yan 505726947304SEvan Yan if (io_alen) { 505826947304SEvan Yan DEBUG3("Bridge IO Space Allocated [0x%x.%x] len [0x%x]\n", 505926947304SEvan Yan PCICFG_HIADDR(io_answer), PCICFG_LOADDR(io_answer), 506026947304SEvan Yan io_alen); 506126947304SEvan Yan 506226947304SEvan Yan if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_IO) == 506326947304SEvan Yan NDI_FAILURE) { 506426947304SEvan Yan DEBUG0("Can not setup resource map - NDI_RA_TYPE_IO\n"); 506526947304SEvan Yan return (PCICFG_FAILURE); 506626947304SEvan Yan } 506726947304SEvan Yan 506826947304SEvan Yan /* 506926947304SEvan Yan * Put available I/O into the pool. 507026947304SEvan Yan */ 507126947304SEvan Yan (void) ndi_ra_free(new_child, io_answer, io_alen, 507226947304SEvan Yan NDI_RA_TYPE_IO, NDI_RA_PASS); 507326947304SEvan Yan io_base = io_answer; 507426947304SEvan Yan } 507526947304SEvan Yan 507626947304SEvan Yan pcicfg_set_bus_numbers(h, bus, new_bus, max_bus); 507726947304SEvan Yan 507826947304SEvan Yan /* 507926947304SEvan Yan * Setup "bus-range" property before onlining the bridge. 508026947304SEvan Yan */ 508126947304SEvan Yan bus_range[0] = new_bus; 508226947304SEvan Yan bus_range[1] = max_bus; 508326947304SEvan Yan 508426947304SEvan Yan if (ndi_prop_update_int_array(DDI_DEV_T_NONE, new_child, 508526947304SEvan Yan "bus-range", bus_range, 2) != DDI_SUCCESS) { 508626947304SEvan Yan DEBUG0("Failed to set bus-range property"); 508726947304SEvan Yan return (PCICFG_FAILURE); 508826947304SEvan Yan } 508926947304SEvan Yan 509026947304SEvan Yan /* 509126947304SEvan Yan * Reset the secondary bus 509226947304SEvan Yan */ 509326947304SEvan Yan pci_config_put16(h, PCI_BCNF_BCNTRL, 509426947304SEvan Yan pci_config_get16(h, PCI_BCNF_BCNTRL) | 0x40); 509526947304SEvan Yan 509626947304SEvan Yan drv_usecwait(100); 509726947304SEvan Yan 509826947304SEvan Yan pci_config_put16(h, PCI_BCNF_BCNTRL, 509926947304SEvan Yan pci_config_get16(h, PCI_BCNF_BCNTRL) & ~0x40); 510026947304SEvan Yan 510126947304SEvan Yan /* 510226947304SEvan Yan * Program the memory base register with the 510326947304SEvan Yan * start of the memory range 510426947304SEvan Yan */ 510526947304SEvan Yan pci_config_put16(h, PCI_BCNF_MEM_BASE, 510626947304SEvan Yan PCICFG_HIWORD(PCICFG_LOADDR(mem_answer))); 510726947304SEvan Yan 510826947304SEvan Yan /* 510926947304SEvan Yan * Program the memory limit register with the 511026947304SEvan Yan * end of the memory range. 511126947304SEvan Yan */ 511226947304SEvan Yan 511326947304SEvan Yan pci_config_put16(h, PCI_BCNF_MEM_LIMIT, 511426947304SEvan Yan PCICFG_HIWORD(PCICFG_LOADDR( 511526947304SEvan Yan PCICFG_ROUND_DOWN((mem_answer + mem_alen), PCICFG_MEMGRAN) - 1))); 511626947304SEvan Yan 511726947304SEvan Yan /* 511826947304SEvan Yan * Allocate the chunk of memory (if any) not programmed into the 511926947304SEvan Yan * bridge because of the round down. 512026947304SEvan Yan */ 512126947304SEvan Yan if (PCICFG_ROUND_DOWN((mem_answer + mem_alen), PCICFG_MEMGRAN) 512226947304SEvan Yan != (mem_answer + mem_alen)) { 512326947304SEvan Yan DEBUG0("Need to allocate Memory round off chunk\n"); 512426947304SEvan Yan bzero((caddr_t)&req, sizeof (ndi_ra_request_t)); 512526947304SEvan Yan req.ra_flags = NDI_RA_ALLOC_SPECIFIED; 512626947304SEvan Yan req.ra_addr = PCICFG_ROUND_DOWN((mem_answer + mem_alen), 512726947304SEvan Yan PCICFG_MEMGRAN); 512826947304SEvan Yan req.ra_len = (mem_answer + mem_alen) - 512926947304SEvan Yan (PCICFG_ROUND_DOWN((mem_answer + mem_alen), 513026947304SEvan Yan PCICFG_MEMGRAN)); 513126947304SEvan Yan 513226947304SEvan Yan (void) ndi_ra_alloc(new_child, &req, 513326947304SEvan Yan &round_answer, &round_len, NDI_RA_TYPE_MEM, NDI_RA_PASS); 513426947304SEvan Yan } 513526947304SEvan Yan 513626947304SEvan Yan /* 513726947304SEvan Yan * Program the I/O Space Base 513826947304SEvan Yan */ 513926947304SEvan Yan pci_config_put8(h, PCI_BCNF_IO_BASE_LOW, 514026947304SEvan Yan PCICFG_HIBYTE(PCICFG_LOWORD( 514126947304SEvan Yan PCICFG_LOADDR(io_answer)))); 514226947304SEvan Yan 514326947304SEvan Yan pci_config_put16(h, PCI_BCNF_IO_BASE_HI, 514426947304SEvan Yan PCICFG_HIWORD(PCICFG_LOADDR(io_answer))); 514526947304SEvan Yan 514626947304SEvan Yan /* 514726947304SEvan Yan * Program the I/O Space Limit 514826947304SEvan Yan */ 514926947304SEvan Yan pci_config_put8(h, PCI_BCNF_IO_LIMIT_LOW, 515026947304SEvan Yan PCICFG_HIBYTE(PCICFG_LOWORD( 515126947304SEvan Yan PCICFG_LOADDR(PCICFG_ROUND_DOWN(io_answer + io_alen, 515226947304SEvan Yan PCICFG_IOGRAN)))) - 1); 515326947304SEvan Yan 515426947304SEvan Yan pci_config_put16(h, PCI_BCNF_IO_LIMIT_HI, 515526947304SEvan Yan PCICFG_HIWORD(PCICFG_LOADDR( 515626947304SEvan Yan PCICFG_ROUND_DOWN(io_answer + io_alen, PCICFG_IOGRAN))) 515726947304SEvan Yan - 1); 515826947304SEvan Yan 515926947304SEvan Yan /* 516026947304SEvan Yan * Allocate the chunk of I/O (if any) not programmed into the 516126947304SEvan Yan * bridge because of the round down. 516226947304SEvan Yan */ 516326947304SEvan Yan if (PCICFG_ROUND_DOWN((io_answer + io_alen), PCICFG_IOGRAN) 516426947304SEvan Yan != (io_answer + io_alen)) { 516526947304SEvan Yan DEBUG0("Need to allocate I/O round off chunk\n"); 516626947304SEvan Yan bzero((caddr_t)&req, sizeof (ndi_ra_request_t)); 516726947304SEvan Yan req.ra_flags = NDI_RA_ALLOC_SPECIFIED; 516826947304SEvan Yan req.ra_addr = PCICFG_ROUND_DOWN((io_answer + io_alen), 516926947304SEvan Yan PCICFG_IOGRAN); 517026947304SEvan Yan req.ra_len = (io_answer + io_alen) - 517126947304SEvan Yan (PCICFG_ROUND_DOWN((io_answer + io_alen), 517226947304SEvan Yan PCICFG_IOGRAN)); 517326947304SEvan Yan 517426947304SEvan Yan (void) ndi_ra_alloc(new_child, &req, 517526947304SEvan Yan &round_answer, &round_len, NDI_RA_TYPE_IO, NDI_RA_PASS); 517626947304SEvan Yan } 517726947304SEvan Yan 517826947304SEvan Yan /* 517926947304SEvan Yan * Setup "ranges" property before onlining the bridge. 518026947304SEvan Yan */ 518126947304SEvan Yan bzero((caddr_t)range, sizeof (pcicfg_range_t) * PCICFG_RANGE_LEN); 518226947304SEvan Yan 518326947304SEvan Yan range[0].child_hi = range[0].parent_hi |= (PCI_REG_REL_M | PCI_ADDR_IO); 518426947304SEvan Yan range[0].child_lo = range[0].parent_lo = io_base; 518526947304SEvan Yan range[1].child_hi = range[1].parent_hi |= 518626947304SEvan Yan (PCI_REG_REL_M | PCI_ADDR_MEM32); 518726947304SEvan Yan range[1].child_lo = range[1].parent_lo = mem_base; 518826947304SEvan Yan 518926947304SEvan Yan range[0].size_lo = io_alen; 519026947304SEvan Yan if (pcicfg_update_ranges_prop(new_child, &range[0])) { 519126947304SEvan Yan DEBUG0("Failed to update ranges (io)\n"); 519226947304SEvan Yan return (PCICFG_FAILURE); 519326947304SEvan Yan } 519426947304SEvan Yan range[1].size_lo = mem_alen; 519526947304SEvan Yan if (pcicfg_update_ranges_prop(new_child, &range[1])) { 519626947304SEvan Yan DEBUG0("Failed to update ranges (memory)\n"); 519726947304SEvan Yan return (PCICFG_FAILURE); 519826947304SEvan Yan } 519926947304SEvan Yan 520026947304SEvan Yan /* 520126947304SEvan Yan * Clear status bits 520226947304SEvan Yan */ 520326947304SEvan Yan pci_config_put16(h, PCI_BCNF_SEC_STATUS, 0xffff); 520426947304SEvan Yan 520526947304SEvan Yan /* 520626947304SEvan Yan * Turn off prefetchable range 520726947304SEvan Yan */ 520826947304SEvan Yan pci_config_put32(h, PCI_BCNF_PF_BASE_LOW, 0x0000ffff); 520926947304SEvan Yan pci_config_put32(h, PCI_BCNF_PF_BASE_HIGH, 0xffffffff); 521026947304SEvan Yan pci_config_put32(h, PCI_BCNF_PF_LIMIT_HIGH, 0x0); 521126947304SEvan Yan 521226947304SEvan Yan /* 521326947304SEvan Yan * Needs to be set to this value 521426947304SEvan Yan */ 521526947304SEvan Yan pci_config_put8(h, PCI_CONF_ILINE, 0xf); 521626947304SEvan Yan 521726947304SEvan Yan /* check our device_type as defined by Open Firmware */ 521826947304SEvan Yan if (pcicfg_pcie_device_type(new_child, h) == DDI_SUCCESS) 521926947304SEvan Yan pcie_device_type = 1; 522026947304SEvan Yan 522126947304SEvan Yan /* 522226947304SEvan Yan * Set bus properties 522326947304SEvan Yan */ 522426947304SEvan Yan if (pcicfg_set_busnode_props(new_child, pcie_device_type, 522526947304SEvan Yan (int)bus, (int)new_bus) != PCICFG_SUCCESS) { 522626947304SEvan Yan DEBUG0("Failed to set busnode props\n"); 522726947304SEvan Yan return (PCICFG_FAILURE); 522826947304SEvan Yan } 522926947304SEvan Yan 523026947304SEvan Yan (void) pcicfg_device_on(h); 523126947304SEvan Yan 5232c0da6274SZhi-Jun Robin Fu if (is_pcie) 5233c1374a13SSurya Prakki (void) pcie_init_bus(new_child, 0, PCIE_BUS_FINAL); 523426947304SEvan Yan if (ndi_devi_online(new_child, NDI_NO_EVENT|NDI_CONFIG) 523526947304SEvan Yan != NDI_SUCCESS) { 523626947304SEvan Yan DEBUG0("Unable to online bridge\n"); 523726947304SEvan Yan return (PCICFG_FAILURE); 523826947304SEvan Yan } 523926947304SEvan Yan 524026947304SEvan Yan DEBUG0("Bridge is ONLINE\n"); 524126947304SEvan Yan 524226947304SEvan Yan /* 524326947304SEvan Yan * After a Reset, we need to wait 2^25 clock cycles before the 524426947304SEvan Yan * first Configuration access. The worst case is 33MHz, which 524526947304SEvan Yan * is a 1 second wait. 524626947304SEvan Yan */ 524726947304SEvan Yan drv_usecwait(pcicfg_sec_reset_delay); 524826947304SEvan Yan 524926947304SEvan Yan /* 525026947304SEvan Yan * Probe all children devices 525126947304SEvan Yan */ 525226947304SEvan Yan DEBUG0("Bridge Programming Complete - probe children\n"); 525326947304SEvan Yan ndi_devi_enter(new_child, &count); 525426947304SEvan Yan for (i = 0; ((i < PCICFG_MAX_DEVICE) && (ari_mode == B_FALSE)); 525526947304SEvan Yan i++) { 525626947304SEvan Yan for (j = 0; j < max_function; ) { 525726947304SEvan Yan if (ari_mode) 525826947304SEvan Yan trans_device = j >> 3; 525926947304SEvan Yan else 526026947304SEvan Yan trans_device = i; 526126947304SEvan Yan 526226947304SEvan Yan if ((rval = pcicfg_fcode_probe(new_child, 5263c0da6274SZhi-Jun Robin Fu new_bus, trans_device, (j & 7), highest_bus, 5264c0da6274SZhi-Jun Robin Fu 0, is_pcie)) 526526947304SEvan Yan != PCICFG_SUCCESS) { 526626947304SEvan Yan if (rval == PCICFG_NODEVICE) { 526726947304SEvan Yan DEBUG3("No Device at bus [0x%x]" 526826947304SEvan Yan "device [0x%x] " 526926947304SEvan Yan "func [0x%x]\n", new_bus, 527026947304SEvan Yan trans_device, j & 7); 527126947304SEvan Yan 527226947304SEvan Yan if (j) 527326947304SEvan Yan goto next; 527426947304SEvan Yan } else { 527526947304SEvan Yan DEBUG3("Failed to configure bus " 527626947304SEvan Yan "[0x%x] device [0x%x] " 527726947304SEvan Yan "func [0x%x]\n", new_bus, 527826947304SEvan Yan trans_device, j & 7); 527926947304SEvan Yan 528026947304SEvan Yan rval = PCICFG_FAILURE; 528126947304SEvan Yan } 528226947304SEvan Yan break; 528326947304SEvan Yan } 528426947304SEvan Yan next: 528526947304SEvan Yan new_device = pcicfg_devi_find(new_child, 528626947304SEvan Yan trans_device, (j & 7)); 528726947304SEvan Yan 528826947304SEvan Yan /* 528926947304SEvan Yan * Determine if ARI Forwarding should be enabled. 529026947304SEvan Yan */ 529126947304SEvan Yan if (j == 0) { 529226947304SEvan Yan if (new_device == NULL) 529326947304SEvan Yan break; 529426947304SEvan Yan 529526947304SEvan Yan if ((pcie_ari_supported(new_child) == 529626947304SEvan Yan PCIE_ARI_FORW_ENABLED) && 529726947304SEvan Yan (pcie_ari_device(new_device) == 529826947304SEvan Yan PCIE_ARI_DEVICE)) { 529926947304SEvan Yan if (pcie_ari_enable(new_child) == 530026947304SEvan Yan DDI_SUCCESS) { 530126947304SEvan Yan (void) ddi_prop_create( 530226947304SEvan Yan DDI_DEV_T_NONE, 530326947304SEvan Yan new_child, 530426947304SEvan Yan DDI_PROP_CANSLEEP, 530526947304SEvan Yan "ari-enabled", NULL, 0); 530626947304SEvan Yan ari_mode = B_TRUE; 530726947304SEvan Yan max_function = 530826947304SEvan Yan PCICFG_MAX_ARI_FUNCTION; 530926947304SEvan Yan } 531026947304SEvan Yan } 531126947304SEvan Yan } 531226947304SEvan Yan 531326947304SEvan Yan if (ari_mode == B_TRUE) { 531426947304SEvan Yan int next_function; 531526947304SEvan Yan 531626947304SEvan Yan if (new_device == NULL) 531726947304SEvan Yan break; 531826947304SEvan Yan 531926947304SEvan Yan if (pcie_ari_get_next_function(new_device, 532026947304SEvan Yan &next_function) != DDI_SUCCESS) 532126947304SEvan Yan break; 532226947304SEvan Yan 532326947304SEvan Yan j = next_function; 532426947304SEvan Yan 532526947304SEvan Yan if (next_function == 0) 532626947304SEvan Yan break; 532726947304SEvan Yan } else 532826947304SEvan Yan j++; 532926947304SEvan Yan } 533026947304SEvan Yan } 533126947304SEvan Yan 533226947304SEvan Yan ndi_devi_exit(new_child, count); 533326947304SEvan Yan 533426947304SEvan Yan /* if empty topology underneath, it is still a success. */ 533526947304SEvan Yan if (rval != PCICFG_FAILURE) 533626947304SEvan Yan rval = PCICFG_SUCCESS; 533726947304SEvan Yan 533826947304SEvan Yan /* 533926947304SEvan Yan * Offline the bridge to allow reprogramming of resources. 534026947304SEvan Yan * 534126947304SEvan Yan * This should always succeed since nobody else has started to 534226947304SEvan Yan * use it yet, failing to detach the driver would indicate a bug. 534326947304SEvan Yan * Also in that case it's better just panic than allowing the 534426947304SEvan Yan * configurator to proceed with BAR reprogramming without bridge 534526947304SEvan Yan * driver detached. 534626947304SEvan Yan */ 534726947304SEvan Yan VERIFY(ndi_devi_offline(new_child, NDI_NO_EVENT|NDI_UNCONFIG) 534826947304SEvan Yan == NDI_SUCCESS); 5349c0da6274SZhi-Jun Robin Fu if (is_pcie) 5350c0da6274SZhi-Jun Robin Fu pcie_fini_bus(new_child, PCIE_BUS_INITIAL); 535126947304SEvan Yan 535226947304SEvan Yan phdl.dip = new_child; 535326947304SEvan Yan phdl.memory_base = mem_answer; 535426947304SEvan Yan phdl.io_base = (uint32_t)io_answer; 535526947304SEvan Yan phdl.error = PCICFG_SUCCESS; /* in case of empty child tree */ 535626947304SEvan Yan 535726947304SEvan Yan ndi_devi_enter(ddi_get_parent(new_child), &count); 535826947304SEvan Yan ddi_walk_devs(new_child, pcicfg_find_resource_end, (void *)&phdl); 535926947304SEvan Yan ndi_devi_exit(ddi_get_parent(new_child), count); 536026947304SEvan Yan 536126947304SEvan Yan if (phdl.error != PCICFG_SUCCESS) { 536226947304SEvan Yan DEBUG0("Failure summing resources\n"); 536326947304SEvan Yan return (PCICFG_FAILURE); 536426947304SEvan Yan } 536526947304SEvan Yan 536626947304SEvan Yan num_slots = pcicfg_get_nslots(new_child, h); 536726947304SEvan Yan mem_end = PCICFG_ROUND_UP(phdl.memory_base, PCICFG_MEMGRAN); 536826947304SEvan Yan io_end = PCICFG_ROUND_UP(phdl.io_base, PCICFG_IOGRAN); 536926947304SEvan Yan 537026947304SEvan Yan DEBUG3("Start of Unallocated Bridge(%d slots) Resources " 537126947304SEvan Yan "Mem=0x%lx I/O=0x%lx\n", num_slots, mem_end, io_end); 537226947304SEvan Yan 537326947304SEvan Yan /* 537426947304SEvan Yan * Before probing the children we've allocated maximum MEM/IO 537526947304SEvan Yan * resources from parent, and updated "available" property 537626947304SEvan Yan * accordingly. Later we'll be giving up unused resources to 537726947304SEvan Yan * the parent, thus we need to destroy "available" property 537826947304SEvan Yan * here otherwise it will be out-of-sync with the actual free 537926947304SEvan Yan * resources this bridge has. This property will be rebuilt below 538026947304SEvan Yan * with the actual free resources reserved for hotplug slots 538126947304SEvan Yan * (if any). 538226947304SEvan Yan */ 538326947304SEvan Yan (void) ndi_prop_remove(DDI_DEV_T_NONE, new_child, "available"); 538426947304SEvan Yan /* 538526947304SEvan Yan * if the bridge a slots, then preallocate. If not, assume static 538626947304SEvan Yan * configuration. Also check for preallocation limits and spit 538726947304SEvan Yan * warning messages appropriately (perhaps some can be in debug mode). 538826947304SEvan Yan */ 538926947304SEvan Yan if (num_slots) { 539026947304SEvan Yan pci_regspec_t reg; 539126947304SEvan Yan uint64_t mem_assigned = mem_end; 539226947304SEvan Yan uint64_t io_assigned = io_end; 539326947304SEvan Yan uint64_t mem_reqd = mem_answer + (num_slots * 539426947304SEvan Yan pcicfg_slot_memsize); 539526947304SEvan Yan uint64_t io_reqd = io_answer + (num_slots * 539626947304SEvan Yan pcicfg_slot_iosize); 539726947304SEvan Yan uint8_t highest_bus_reqd = new_bus + (num_slots * 539826947304SEvan Yan pcicfg_slot_busnums); 539926947304SEvan Yan #ifdef DEBUG 540026947304SEvan Yan if (mem_end > mem_reqd) 540126947304SEvan Yan DEBUG3("Memory space consumed by bridge" 540226947304SEvan Yan " more than planned for %d slot(s)(%lx, %lx)", 540326947304SEvan Yan num_slots, mem_answer, mem_end); 540426947304SEvan Yan if (io_end > io_reqd) 540526947304SEvan Yan DEBUG3("IO space consumed by bridge" 540626947304SEvan Yan " more than planned for %d slot(s)(%lx, %lx)", 540726947304SEvan Yan num_slots, io_answer, io_end); 540826947304SEvan Yan if (*highest_bus > highest_bus_reqd) 540926947304SEvan Yan DEBUG3("Buses consumed by bridge" 541026947304SEvan Yan " more than planned for %d slot(s)(%x, %x)", 541126947304SEvan Yan num_slots, new_bus, *highest_bus); 541226947304SEvan Yan 541326947304SEvan Yan if (mem_reqd > (mem_answer + mem_alen)) 541426947304SEvan Yan DEBUG3("Memory space required by bridge" 541526947304SEvan Yan " more than available for %d slot(s)(%lx, %lx)", 541626947304SEvan Yan num_slots, mem_answer, mem_end); 541726947304SEvan Yan 541826947304SEvan Yan if (io_reqd > (io_answer + io_alen)) 541926947304SEvan Yan DEBUG3("IO space required by bridge" 542026947304SEvan Yan " more than available for %d slot(s)(%lx, %lx)", 542126947304SEvan Yan num_slots, io_answer, io_end); 542226947304SEvan Yan if (highest_bus_reqd > max_bus) 542326947304SEvan Yan DEBUG3("Bus numbers required by bridge" 542426947304SEvan Yan " more than available for %d slot(s)(%x, %x)", 542526947304SEvan Yan num_slots, new_bus, *highest_bus); 542626947304SEvan Yan #endif 542726947304SEvan Yan mem_end = MAX((MIN(mem_reqd, (mem_answer + mem_alen))), 542826947304SEvan Yan mem_end); 542926947304SEvan Yan io_end = MAX((MIN(io_reqd, (io_answer + io_alen))), io_end); 543026947304SEvan Yan *highest_bus = MAX((MIN(highest_bus_reqd, max_bus)), 543126947304SEvan Yan *highest_bus); 543226947304SEvan Yan DEBUG3("mem_end %lx, io_end %lx, highest_bus %x\n", 543326947304SEvan Yan mem_end, io_end, *highest_bus); 543426947304SEvan Yan 543526947304SEvan Yan mem_size = mem_end - mem_assigned; 543626947304SEvan Yan io_size = io_end - io_assigned; 543726947304SEvan Yan 543826947304SEvan Yan reg.pci_phys_mid = reg.pci_size_hi = 0; 543926947304SEvan Yan if (io_size > 0) { 544026947304SEvan Yan reg.pci_phys_hi = (PCI_REG_REL_M | PCI_ADDR_IO); 544126947304SEvan Yan reg.pci_phys_low = io_assigned; 544226947304SEvan Yan reg.pci_size_low = io_size; 544326947304SEvan Yan if (pcicfg_update_available_prop(new_child, ®)) { 544426947304SEvan Yan DEBUG0("Failed to update available prop " 544526947304SEvan Yan "(io)\n"); 544626947304SEvan Yan return (PCICFG_FAILURE); 544726947304SEvan Yan } 544826947304SEvan Yan } 544926947304SEvan Yan if (mem_size > 0) { 545026947304SEvan Yan reg.pci_phys_hi = (PCI_REG_REL_M | PCI_ADDR_MEM32); 545126947304SEvan Yan reg.pci_phys_low = mem_assigned; 545226947304SEvan Yan reg.pci_size_low = mem_size; 545326947304SEvan Yan if (pcicfg_update_available_prop(new_child, ®)) { 545426947304SEvan Yan DEBUG0("Failed to update available prop " 545526947304SEvan Yan "(memory)\n"); 545626947304SEvan Yan return (PCICFG_FAILURE); 545726947304SEvan Yan } 545826947304SEvan Yan } 545926947304SEvan Yan } 546026947304SEvan Yan 546126947304SEvan Yan /* 546226947304SEvan Yan * Give back unused memory space to parent. 546326947304SEvan Yan */ 546426947304SEvan Yan (void) ndi_ra_free(ddi_get_parent(new_child), 546526947304SEvan Yan mem_end, (mem_answer + mem_alen) - mem_end, NDI_RA_TYPE_MEM, 546626947304SEvan Yan NDI_RA_PASS); 546726947304SEvan Yan 546826947304SEvan Yan if (mem_end == mem_answer) { 546926947304SEvan Yan DEBUG0("No memory resources used\n"); 547026947304SEvan Yan /* 547126947304SEvan Yan * To prevent the bridge from forwarding any Memory 547226947304SEvan Yan * transactions, the Memory Limit will be programmed 547326947304SEvan Yan * with a smaller value than the Memory Base. 547426947304SEvan Yan */ 547526947304SEvan Yan pci_config_put16(h, PCI_BCNF_MEM_BASE, 0xffff); 547626947304SEvan Yan pci_config_put16(h, PCI_BCNF_MEM_LIMIT, 0); 547726947304SEvan Yan 547826947304SEvan Yan mem_size = 0; 547926947304SEvan Yan } else { 548026947304SEvan Yan /* 548126947304SEvan Yan * Reprogram the end of the memory. 548226947304SEvan Yan */ 548326947304SEvan Yan pci_config_put16(h, PCI_BCNF_MEM_LIMIT, 548426947304SEvan Yan PCICFG_HIWORD(mem_end) - 1); 548526947304SEvan Yan mem_size = mem_end - mem_base; 548626947304SEvan Yan } 548726947304SEvan Yan 548826947304SEvan Yan /* 548926947304SEvan Yan * Give back unused io space to parent. 549026947304SEvan Yan */ 549126947304SEvan Yan (void) ndi_ra_free(ddi_get_parent(new_child), 549226947304SEvan Yan io_end, (io_answer + io_alen) - io_end, 549326947304SEvan Yan NDI_RA_TYPE_IO, NDI_RA_PASS); 549426947304SEvan Yan 549526947304SEvan Yan if (io_end == io_answer) { 549626947304SEvan Yan DEBUG0("No IO Space resources used\n"); 549726947304SEvan Yan 549826947304SEvan Yan /* 549926947304SEvan Yan * To prevent the bridge from forwarding any I/O 550026947304SEvan Yan * transactions, the I/O Limit will be programmed 550126947304SEvan Yan * with a smaller value than the I/O Base. 550226947304SEvan Yan */ 550326947304SEvan Yan pci_config_put8(h, PCI_BCNF_IO_LIMIT_LOW, 0); 550426947304SEvan Yan pci_config_put16(h, PCI_BCNF_IO_LIMIT_HI, 0); 550526947304SEvan Yan pci_config_put8(h, PCI_BCNF_IO_BASE_LOW, 0xff); 550626947304SEvan Yan pci_config_put16(h, PCI_BCNF_IO_BASE_HI, 0); 550726947304SEvan Yan 550826947304SEvan Yan io_size = 0; 550926947304SEvan Yan } else { 551026947304SEvan Yan /* 551126947304SEvan Yan * Reprogram the end of the io space. 551226947304SEvan Yan */ 551326947304SEvan Yan pci_config_put8(h, PCI_BCNF_IO_LIMIT_LOW, 551426947304SEvan Yan PCICFG_HIBYTE(PCICFG_LOWORD( 551526947304SEvan Yan PCICFG_LOADDR(io_end) - 1))); 551626947304SEvan Yan 551726947304SEvan Yan pci_config_put16(h, PCI_BCNF_IO_LIMIT_HI, 551826947304SEvan Yan PCICFG_HIWORD(PCICFG_LOADDR(io_end - 1))); 551926947304SEvan Yan 552026947304SEvan Yan io_size = io_end - io_base; 552126947304SEvan Yan } 552226947304SEvan Yan 552326947304SEvan Yan if ((max_bus - *highest_bus) > 0) { 552426947304SEvan Yan /* 552526947304SEvan Yan * Give back unused bus numbers 552626947304SEvan Yan */ 552726947304SEvan Yan (void) ndi_ra_free(ddi_get_parent(new_child), 552826947304SEvan Yan *highest_bus+1, max_bus - *highest_bus, 552926947304SEvan Yan NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS); 553026947304SEvan Yan } 553126947304SEvan Yan 553226947304SEvan Yan /* 553326947304SEvan Yan * Set bus numbers to ranges encountered during scan 553426947304SEvan Yan */ 553526947304SEvan Yan pcicfg_set_bus_numbers(h, bus, new_bus, *highest_bus); 553626947304SEvan Yan 553726947304SEvan Yan bus_range[0] = pci_config_get8(h, PCI_BCNF_SECBUS); 553826947304SEvan Yan bus_range[1] = pci_config_get8(h, PCI_BCNF_SUBBUS); 553926947304SEvan Yan DEBUG1("End of bridge probe: bus_range[0] = %d\n", bus_range[0]); 554026947304SEvan Yan DEBUG1("End of bridge probe: bus_range[1] = %d\n", bus_range[1]); 554126947304SEvan Yan 554226947304SEvan Yan if (ndi_prop_update_int_array(DDI_DEV_T_NONE, new_child, 554326947304SEvan Yan "bus-range", bus_range, 2) != DDI_SUCCESS) { 554426947304SEvan Yan DEBUG0("Failed to set bus-range property"); 554526947304SEvan Yan return (PCICFG_FAILURE); 554626947304SEvan Yan } 554726947304SEvan Yan 554826947304SEvan Yan /* 554926947304SEvan Yan * Remove the ranges property if it exists since we will create 555026947304SEvan Yan * a new one. 555126947304SEvan Yan */ 555226947304SEvan Yan (void) ndi_prop_remove(DDI_DEV_T_NONE, new_child, "ranges"); 555326947304SEvan Yan 555426947304SEvan Yan DEBUG2("Creating Ranges property - Mem Address %lx Mem Size %x\n", 555526947304SEvan Yan mem_base, mem_size); 555626947304SEvan Yan DEBUG2(" - I/O Address %lx I/O Size %x\n", 555726947304SEvan Yan io_base, io_size); 555826947304SEvan Yan 555926947304SEvan Yan bzero((caddr_t)range, sizeof (pcicfg_range_t) * PCICFG_RANGE_LEN); 556026947304SEvan Yan 556126947304SEvan Yan range[0].child_hi = range[0].parent_hi |= (PCI_REG_REL_M | PCI_ADDR_IO); 556226947304SEvan Yan range[0].child_lo = range[0].parent_lo = io_base; 556326947304SEvan Yan range[1].child_hi = range[1].parent_hi |= 556426947304SEvan Yan (PCI_REG_REL_M | PCI_ADDR_MEM32); 556526947304SEvan Yan range[1].child_lo = range[1].parent_lo = mem_base; 556626947304SEvan Yan 556726947304SEvan Yan if (io_size > 0) { 556826947304SEvan Yan range[0].size_lo = io_size; 556926947304SEvan Yan if (pcicfg_update_ranges_prop(new_child, &range[0])) { 557026947304SEvan Yan DEBUG0("Failed to update ranges (io)\n"); 557126947304SEvan Yan return (PCICFG_FAILURE); 557226947304SEvan Yan } 557326947304SEvan Yan } 557426947304SEvan Yan if (mem_size > 0) { 557526947304SEvan Yan range[1].size_lo = mem_size; 557626947304SEvan Yan if (pcicfg_update_ranges_prop(new_child, &range[1])) { 557726947304SEvan Yan DEBUG0("Failed to update ranges (memory)\n"); 557826947304SEvan Yan return (PCICFG_FAILURE); 557926947304SEvan Yan } 558026947304SEvan Yan } 558126947304SEvan Yan 558226947304SEvan Yan /* 558326947304SEvan Yan * Remove the resource maps for the bridge since we no longer 558426947304SEvan Yan * need them. Note that the failure is ignored since the 558526947304SEvan Yan * ndi_devi_offline above may have already taken care of it via 558626947304SEvan Yan * driver detach. 558726947304SEvan Yan * It has been checked that there are no other reasons for 558826947304SEvan Yan * failure other than map itself being non-existent. So we are Ok. 558926947304SEvan Yan */ 559026947304SEvan Yan if (ndi_ra_map_destroy(new_child, NDI_RA_TYPE_MEM) == NDI_FAILURE) { 559126947304SEvan Yan /*EMPTY*/ 559226947304SEvan Yan DEBUG0("Can not destroy resource map - NDI_RA_TYPE_MEM\n"); 559326947304SEvan Yan } 559426947304SEvan Yan 559526947304SEvan Yan if (ndi_ra_map_destroy(new_child, NDI_RA_TYPE_IO) == NDI_FAILURE) { 559626947304SEvan Yan /*EMPTY*/ 559726947304SEvan Yan DEBUG0("Can not destroy resource map - NDI_RA_TYPE_IO\n"); 559826947304SEvan Yan } 559926947304SEvan Yan 560026947304SEvan Yan if (ndi_ra_map_destroy(new_child, NDI_RA_TYPE_PCI_BUSNUM) 560126947304SEvan Yan == NDI_FAILURE) { 560226947304SEvan Yan /*EMPTY*/ 560326947304SEvan Yan DEBUG0("Can't destroy resource map - NDI_RA_TYPE_PCI_BUSNUM\n"); 560426947304SEvan Yan } 560526947304SEvan Yan 560626947304SEvan Yan return (rval); 560726947304SEvan Yan } 560826947304SEvan Yan 560926947304SEvan Yan /* 561026947304SEvan Yan * Return PCICFG_SUCCESS if device exists at the specified address. 561126947304SEvan Yan * Return PCICFG_NODEVICE is no device exists at the specified address. 561226947304SEvan Yan * 561326947304SEvan Yan */ 561426947304SEvan Yan int 561526947304SEvan Yan pcicfg_config_setup(dev_info_t *dip, ddi_acc_handle_t *handle) 561626947304SEvan Yan { 561726947304SEvan Yan caddr_t virt; 561826947304SEvan Yan ddi_device_acc_attr_t attr; 561926947304SEvan Yan int status; 562026947304SEvan Yan int rlen; 562126947304SEvan Yan pci_regspec_t *reg; 562226947304SEvan Yan int ret = DDI_SUCCESS; 562326947304SEvan Yan int16_t tmp; 562426947304SEvan Yan /* 562526947304SEvan Yan * flags = PCICFG_CONF_INDIRECT_MAP if configuration space is indirectly 562626947304SEvan Yan * mapped, otherwise it is 0. "flags" is introduced in support of any 562726947304SEvan Yan * non transparent bridges, where configuration space is indirectly 562826947304SEvan Yan * mapped. 562926947304SEvan Yan * Indirect mapping is always true on sun4v systems. 563026947304SEvan Yan */ 563126947304SEvan Yan int flags = 0; 563226947304SEvan Yan 563326947304SEvan Yan 563426947304SEvan Yan /* 563526947304SEvan Yan * Get the pci register spec from the node 563626947304SEvan Yan */ 563726947304SEvan Yan status = ddi_getlongprop(DDI_DEV_T_ANY, 563826947304SEvan Yan dip, DDI_PROP_DONTPASS, "reg", (caddr_t)®, &rlen); 563926947304SEvan Yan 564026947304SEvan Yan switch (status) { 564126947304SEvan Yan case DDI_PROP_SUCCESS: 564226947304SEvan Yan break; 564326947304SEvan Yan case DDI_PROP_NO_MEMORY: 564426947304SEvan Yan DEBUG0("reg present, but unable to get memory\n"); 564526947304SEvan Yan return (PCICFG_FAILURE); 564626947304SEvan Yan default: 564726947304SEvan Yan DEBUG0("no reg property\n"); 564826947304SEvan Yan return (PCICFG_FAILURE); 564926947304SEvan Yan } 565026947304SEvan Yan 565126947304SEvan Yan if (pcicfg_indirect_map(dip) == DDI_SUCCESS) 565226947304SEvan Yan flags |= PCICFG_CONF_INDIRECT_MAP; 565326947304SEvan Yan 565426947304SEvan Yan /* 565526947304SEvan Yan * Map in configuration space (temporarily) 565626947304SEvan Yan */ 565726947304SEvan Yan attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 565826947304SEvan Yan attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 565926947304SEvan Yan attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 566026947304SEvan Yan attr.devacc_attr_access = DDI_CAUTIOUS_ACC; 566126947304SEvan Yan 566226947304SEvan Yan #ifdef EFCODE21554 566326947304SEvan Yan if (ddi_regs_map_setup(dip, 0, &virt, 566426947304SEvan Yan 0, 0, &attr, handle) != DDI_SUCCESS) 566526947304SEvan Yan #else 566626947304SEvan Yan if (pcicfg_map_phys(dip, reg, &virt, &attr, handle) 566726947304SEvan Yan != DDI_SUCCESS) 566826947304SEvan Yan #endif 566926947304SEvan Yan { 567026947304SEvan Yan DEBUG0("pcicfg_config_setup():" 567126947304SEvan Yan "Failed to setup config space\n"); 567226947304SEvan Yan 567326947304SEvan Yan kmem_free((caddr_t)reg, rlen); 567426947304SEvan Yan return (PCICFG_FAILURE); 567526947304SEvan Yan } 567626947304SEvan Yan 567726947304SEvan Yan if (flags & PCICFG_CONF_INDIRECT_MAP) { 567826947304SEvan Yan /* 567926947304SEvan Yan * need to use DDI interfaces as the conf space is 568026947304SEvan Yan * cannot be directly accessed by the host. 568126947304SEvan Yan */ 568226947304SEvan Yan tmp = (int16_t)ddi_get16(*handle, (uint16_t *)virt); 568326947304SEvan Yan } else { 568426947304SEvan Yan ret = ddi_peek16(dip, (int16_t *)virt, &tmp); 568526947304SEvan Yan } 568626947304SEvan Yan 568726947304SEvan Yan if (ret == DDI_SUCCESS) { 568826947304SEvan Yan if (tmp == -1) { 568926947304SEvan Yan DEBUG1("NO DEVICEFOUND, read %x\n", tmp); 569026947304SEvan Yan ret = PCICFG_NODEVICE; 569126947304SEvan Yan } else { 569226947304SEvan Yan /* XXX - Need to check why HV is returning 0 */ 569326947304SEvan Yan if (tmp == 0) { 569426947304SEvan Yan DEBUG0("Device Not Ready yet ?"); 569526947304SEvan Yan ret = PCICFG_NODEVICE; 569626947304SEvan Yan } else { 569726947304SEvan Yan DEBUG1("DEVICEFOUND, read %x\n", tmp); 569826947304SEvan Yan ret = PCICFG_SUCCESS; 569926947304SEvan Yan } 570026947304SEvan Yan } 570126947304SEvan Yan } else { 570226947304SEvan Yan DEBUG0("ddi_peek failed, must be NODEVICE\n"); 570326947304SEvan Yan ret = PCICFG_NODEVICE; 570426947304SEvan Yan } 570526947304SEvan Yan 570626947304SEvan Yan /* 570726947304SEvan Yan * A bug in XMITS 3.0 causes us to miss the Master Abort Split 570826947304SEvan Yan * Completion message. The result is the error message being 570926947304SEvan Yan * sent back as part of the config data. If the first two words 571026947304SEvan Yan * of the config space happen to be the same as the Master Abort 571126947304SEvan Yan * message, then report back that there is no device there. 571226947304SEvan Yan */ 571326947304SEvan Yan if ((ret == PCICFG_SUCCESS) && !(flags & PCICFG_CONF_INDIRECT_MAP)) { 571426947304SEvan Yan int32_t pcix_scm; 571526947304SEvan Yan 571626947304SEvan Yan #define PCICFG_PCIX_SCM 0x10000004 571726947304SEvan Yan 571826947304SEvan Yan pcix_scm = 0; 571926947304SEvan Yan (void) ddi_peek32(dip, (int32_t *)virt, &pcix_scm); 572026947304SEvan Yan if (pcix_scm == PCICFG_PCIX_SCM) { 572126947304SEvan Yan pcix_scm = 0; 572226947304SEvan Yan (void) ddi_peek32(dip, 572326947304SEvan Yan (int32_t *)(virt + 4), &pcix_scm); 572426947304SEvan Yan if (pcix_scm == PCICFG_PCIX_SCM) 572526947304SEvan Yan ret = PCICFG_NODEVICE; 572626947304SEvan Yan } 572726947304SEvan Yan } 572826947304SEvan Yan 572926947304SEvan Yan if (ret == PCICFG_NODEVICE) 573026947304SEvan Yan #ifdef EFCODE21554 573126947304SEvan Yan ddi_regs_map_free(handle); 573226947304SEvan Yan #else 573326947304SEvan Yan pcicfg_unmap_phys(handle, reg); 573426947304SEvan Yan #endif 573526947304SEvan Yan 573626947304SEvan Yan kmem_free((caddr_t)reg, rlen); 573726947304SEvan Yan 573826947304SEvan Yan return (ret); 573926947304SEvan Yan 574026947304SEvan Yan } 574126947304SEvan Yan 574226947304SEvan Yan static void 574326947304SEvan Yan pcicfg_config_teardown(ddi_acc_handle_t *handle) 574426947304SEvan Yan { 574526947304SEvan Yan (void) ddi_regs_map_free(handle); 574626947304SEvan Yan } 574726947304SEvan Yan 574826947304SEvan Yan static int 574926947304SEvan Yan pcicfg_add_config_reg(dev_info_t *dip, 575026947304SEvan Yan uint_t bus, uint_t device, uint_t func) 575126947304SEvan Yan { 575226947304SEvan Yan int reg[10] = { PCI_ADDR_CONFIG, 0, 0, 0, 0}; 575326947304SEvan Yan 575426947304SEvan Yan reg[0] = PCICFG_MAKE_REG_HIGH(bus, device, func, 0); 575526947304SEvan Yan 575626947304SEvan Yan return (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, 575726947304SEvan Yan "reg", reg, 5)); 575826947304SEvan Yan } 575926947304SEvan Yan 576026947304SEvan Yan static int 576126947304SEvan Yan pcicfg_dump_assigned(dev_info_t *dip) 576226947304SEvan Yan { 576326947304SEvan Yan pci_regspec_t *reg; 576426947304SEvan Yan int length; 576526947304SEvan Yan int rcount; 576626947304SEvan Yan int i; 576726947304SEvan Yan 576826947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 576926947304SEvan Yan DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)®, 577026947304SEvan Yan &length) != DDI_PROP_SUCCESS) { 577126947304SEvan Yan DEBUG0("Failed to read assigned-addresses property\n"); 577226947304SEvan Yan return (PCICFG_FAILURE); 577326947304SEvan Yan } 577426947304SEvan Yan 577526947304SEvan Yan rcount = length / sizeof (pci_regspec_t); 577626947304SEvan Yan for (i = 0; i < rcount; i++) { 577726947304SEvan Yan DEBUG4("pcicfg_dump_assigned - size=%x low=%x mid=%x high=%x\n", 577826947304SEvan Yan reg[i].pci_size_low, reg[i].pci_phys_low, 577926947304SEvan Yan reg[i].pci_phys_mid, reg[i].pci_phys_hi); 578026947304SEvan Yan } 578126947304SEvan Yan /* 578226947304SEvan Yan * Don't forget to free up memory from ddi_getlongprop 578326947304SEvan Yan */ 578426947304SEvan Yan kmem_free((caddr_t)reg, length); 578526947304SEvan Yan 578626947304SEvan Yan return (PCICFG_SUCCESS); 578726947304SEvan Yan } 578826947304SEvan Yan 578926947304SEvan Yan #ifdef PCICFG_INTERPRET_FCODE 579026947304SEvan Yan static int 579126947304SEvan Yan pcicfg_load_fcode(dev_info_t *dip, uint_t bus, uint_t device, uint_t func, 579226947304SEvan Yan uint16_t vendor_id, uint16_t device_id, uchar_t **fcode_addr, 579326947304SEvan Yan int *fcode_size, int rom_paddr, int rom_size) 579426947304SEvan Yan { 579526947304SEvan Yan pci_regspec_t p; 579626947304SEvan Yan int pci_data; 579726947304SEvan Yan int start_of_fcode; 579826947304SEvan Yan int image_length; 579926947304SEvan Yan int code_type; 580026947304SEvan Yan ddi_acc_handle_t h; 580126947304SEvan Yan ddi_device_acc_attr_t acc; 580226947304SEvan Yan uint8_t *addr; 580326947304SEvan Yan int8_t image_not_found, indicator; 580426947304SEvan Yan uint16_t vendor_id_img, device_id_img; 580526947304SEvan Yan int16_t rom_sig; 580626947304SEvan Yan #ifdef DEBUG 580726947304SEvan Yan int i; 580826947304SEvan Yan #endif 580926947304SEvan Yan 581026947304SEvan Yan DEBUG4("pcicfg_load_fcode() - " 581126947304SEvan Yan "bus %x device =%x func=%x rom_paddr=%lx\n", 581226947304SEvan Yan bus, device, func, rom_paddr); 581326947304SEvan Yan DEBUG2("pcicfg_load_fcode() - vendor_id=%x device_id=%x\n", 581426947304SEvan Yan vendor_id, device_id); 581526947304SEvan Yan 581626947304SEvan Yan *fcode_size = 0; 581726947304SEvan Yan *fcode_addr = NULL; 581826947304SEvan Yan 581926947304SEvan Yan acc.devacc_attr_version = DDI_DEVICE_ATTR_V0; 582026947304SEvan Yan acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 582126947304SEvan Yan acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 582226947304SEvan Yan 582326947304SEvan Yan p.pci_phys_hi = PCI_ADDR_MEM32 | PCICFG_MAKE_REG_HIGH(bus, device, 582426947304SEvan Yan func, PCI_CONF_ROM); 582526947304SEvan Yan 582626947304SEvan Yan p.pci_phys_mid = 0; 582726947304SEvan Yan p.pci_phys_low = 0; 582826947304SEvan Yan 582926947304SEvan Yan p.pci_size_low = rom_size; 583026947304SEvan Yan p.pci_size_hi = 0; 583126947304SEvan Yan 583226947304SEvan Yan if (pcicfg_map_phys(dip, &p, (caddr_t *)&addr, &acc, &h)) { 583326947304SEvan Yan DEBUG1("Can Not map in ROM %x\n", p.pci_phys_low); 583426947304SEvan Yan return (PCICFG_FAILURE); 583526947304SEvan Yan } 583626947304SEvan Yan 583726947304SEvan Yan /* 583826947304SEvan Yan * Walk the ROM to find the proper image for this device. 583926947304SEvan Yan */ 584026947304SEvan Yan image_not_found = 1; 584126947304SEvan Yan while (image_not_found) { 584226947304SEvan Yan DEBUG1("Expansion ROM maps to %lx\n", addr); 584326947304SEvan Yan 584426947304SEvan Yan #ifdef DEBUG 584526947304SEvan Yan if (pcicfg_dump_fcode) { 584626947304SEvan Yan for (i = 0; i < 100; i++) 584726947304SEvan Yan DEBUG2("ROM 0x%x --> 0x%x\n", i, 584826947304SEvan Yan ddi_get8(h, (uint8_t *)(addr + i))); 584926947304SEvan Yan } 585026947304SEvan Yan #endif 585126947304SEvan Yan 585226947304SEvan Yan /* 585326947304SEvan Yan * Some device say they have an Expansion ROM, but do not, so 585426947304SEvan Yan * for non-21554 devices use peek so we don't panic due to 585526947304SEvan Yan * accessing non existent memory. 585626947304SEvan Yan */ 585726947304SEvan Yan if (pcicfg_indirect_map(dip) == DDI_SUCCESS) { 585826947304SEvan Yan rom_sig = ddi_get16(h, 585926947304SEvan Yan (uint16_t *)(addr + PCI_ROM_SIGNATURE)); 586026947304SEvan Yan } else { 586126947304SEvan Yan if (ddi_peek16(dip, 586226947304SEvan Yan (int16_t *)(addr + PCI_ROM_SIGNATURE), &rom_sig)) { 586326947304SEvan Yan cmn_err(CE_WARN, 586426947304SEvan Yan "PCI Expansion ROM is not accessible"); 586526947304SEvan Yan pcicfg_unmap_phys(&h, &p); 586626947304SEvan Yan return (PCICFG_FAILURE); 586726947304SEvan Yan } 586826947304SEvan Yan } 586926947304SEvan Yan 587026947304SEvan Yan /* 587126947304SEvan Yan * Validate the ROM Signature. 587226947304SEvan Yan */ 587326947304SEvan Yan if ((uint16_t)rom_sig != 0xaa55) { 587426947304SEvan Yan DEBUG1("Invalid ROM Signature %x\n", (uint16_t)rom_sig); 587526947304SEvan Yan pcicfg_unmap_phys(&h, &p); 587626947304SEvan Yan return (PCICFG_FAILURE); 587726947304SEvan Yan } 587826947304SEvan Yan 587926947304SEvan Yan DEBUG0("Valid ROM Signature Found\n"); 588026947304SEvan Yan 588126947304SEvan Yan start_of_fcode = ddi_get16(h, (uint16_t *)(addr + 2)); 588226947304SEvan Yan 588326947304SEvan Yan pci_data = ddi_get16(h, 588426947304SEvan Yan (uint16_t *)(addr + PCI_ROM_PCI_DATA_STRUCT_PTR)); 588526947304SEvan Yan 588626947304SEvan Yan DEBUG2("Pointer To PCI Data Structure %x %x\n", pci_data, 588726947304SEvan Yan addr); 588826947304SEvan Yan 588926947304SEvan Yan /* 589026947304SEvan Yan * Validate the PCI Data Structure Signature. 589126947304SEvan Yan * 0x52494350 = "PCIR" 589226947304SEvan Yan */ 589326947304SEvan Yan 589426947304SEvan Yan if (ddi_get8(h, (uint8_t *)(addr + pci_data)) != 0x50) { 589526947304SEvan Yan DEBUG0("Invalid PCI Data Structure Signature\n"); 589626947304SEvan Yan pcicfg_unmap_phys(&h, &p); 589726947304SEvan Yan return (PCICFG_FAILURE); 589826947304SEvan Yan } 589926947304SEvan Yan 590026947304SEvan Yan if (ddi_get8(h, (uint8_t *)(addr + pci_data + 1)) != 0x43) { 590126947304SEvan Yan DEBUG0("Invalid PCI Data Structure Signature\n"); 590226947304SEvan Yan pcicfg_unmap_phys(&h, &p); 590326947304SEvan Yan return (PCICFG_FAILURE); 590426947304SEvan Yan } 590526947304SEvan Yan if (ddi_get8(h, (uint8_t *)(addr + pci_data + 2)) != 0x49) { 590626947304SEvan Yan DEBUG0("Invalid PCI Data Structure Signature\n"); 590726947304SEvan Yan pcicfg_unmap_phys(&h, &p); 590826947304SEvan Yan return (PCICFG_FAILURE); 590926947304SEvan Yan } 591026947304SEvan Yan if (ddi_get8(h, (uint8_t *)(addr + pci_data + 3)) != 0x52) { 591126947304SEvan Yan DEBUG0("Invalid PCI Data Structure Signature\n"); 591226947304SEvan Yan pcicfg_unmap_phys(&h, &p); 591326947304SEvan Yan return (PCICFG_FAILURE); 591426947304SEvan Yan } 591526947304SEvan Yan 591626947304SEvan Yan /* 591726947304SEvan Yan * Is this image for this device? 591826947304SEvan Yan */ 591926947304SEvan Yan vendor_id_img = ddi_get16(h, 592026947304SEvan Yan (uint16_t *)(addr + pci_data + PCI_PDS_VENDOR_ID)); 592126947304SEvan Yan device_id_img = ddi_get16(h, 592226947304SEvan Yan (uint16_t *)(addr + pci_data + PCI_PDS_DEVICE_ID)); 592326947304SEvan Yan 592426947304SEvan Yan DEBUG2("This image is for vendor_id=%x device_id=%x\n", 592526947304SEvan Yan vendor_id_img, device_id_img); 592626947304SEvan Yan 592726947304SEvan Yan code_type = ddi_get8(h, addr + pci_data + PCI_PDS_CODE_TYPE); 592826947304SEvan Yan 592926947304SEvan Yan switch (code_type) { 593026947304SEvan Yan case PCI_PDS_CODE_TYPE_PCAT: 593126947304SEvan Yan DEBUG0("ROM is of x86/PC-AT Type\n"); 593226947304SEvan Yan break; 593326947304SEvan Yan case PCI_PDS_CODE_TYPE_OPEN_FW: 593426947304SEvan Yan DEBUG0("ROM is of Open Firmware Type\n"); 593526947304SEvan Yan break; 593626947304SEvan Yan default: 593726947304SEvan Yan DEBUG1("ROM is of Unknown Type 0x%x\n", code_type); 593826947304SEvan Yan break; 593926947304SEvan Yan } 594026947304SEvan Yan 594126947304SEvan Yan if ((vendor_id_img != vendor_id) || 594226947304SEvan Yan (device_id_img != device_id) || 594326947304SEvan Yan (code_type != PCI_PDS_CODE_TYPE_OPEN_FW)) { 594426947304SEvan Yan DEBUG0("Firmware Image is not for this device..." 594526947304SEvan Yan "goto next image\n"); 594626947304SEvan Yan /* 594726947304SEvan Yan * Read indicator byte to see if there is another 594826947304SEvan Yan * image in the ROM 594926947304SEvan Yan */ 595026947304SEvan Yan indicator = ddi_get8(h, 595126947304SEvan Yan (uint8_t *)(addr + pci_data + PCI_PDS_INDICATOR)); 595226947304SEvan Yan 595326947304SEvan Yan if (indicator != 1) { 595426947304SEvan Yan /* 595526947304SEvan Yan * There is another image in the ROM. 595626947304SEvan Yan */ 595726947304SEvan Yan image_length = ddi_get16(h, (uint16_t *)(addr + 595826947304SEvan Yan pci_data + PCI_PDS_IMAGE_LENGTH)) * 512; 595926947304SEvan Yan 596026947304SEvan Yan addr += image_length; 596126947304SEvan Yan } else { 596226947304SEvan Yan /* 596326947304SEvan Yan * There are no more images. 596426947304SEvan Yan */ 596526947304SEvan Yan DEBUG0("There are no more images in the ROM\n"); 596626947304SEvan Yan pcicfg_unmap_phys(&h, &p); 596726947304SEvan Yan 596826947304SEvan Yan return (PCICFG_FAILURE); 596926947304SEvan Yan } 597026947304SEvan Yan } else { 597126947304SEvan Yan DEBUG0("Correct image was found\n"); 597226947304SEvan Yan image_not_found = 0; /* Image was found */ 597326947304SEvan Yan } 597426947304SEvan Yan } 597526947304SEvan Yan 597626947304SEvan Yan *fcode_size = (ddi_get8(h, addr + start_of_fcode + 4) << 24) | 597726947304SEvan Yan (ddi_get8(h, addr + start_of_fcode + 5) << 16) | 597826947304SEvan Yan (ddi_get8(h, addr + start_of_fcode + 6) << 8) | 597926947304SEvan Yan (ddi_get8(h, addr + start_of_fcode + 7)); 598026947304SEvan Yan 598126947304SEvan Yan DEBUG1("Fcode Size %x\n", *fcode_size); 598226947304SEvan Yan 598326947304SEvan Yan /* 598426947304SEvan Yan * Allocate page aligned buffer space 598526947304SEvan Yan */ 598626947304SEvan Yan *fcode_addr = kmem_zalloc(ptob(btopr(*fcode_size)), KM_SLEEP); 598726947304SEvan Yan 598826947304SEvan Yan if (*fcode_addr == NULL) { 598926947304SEvan Yan DEBUG0("kmem_zalloc returned NULL\n"); 599026947304SEvan Yan pcicfg_unmap_phys(&h, &p); 599126947304SEvan Yan return (PCICFG_FAILURE); 599226947304SEvan Yan } 599326947304SEvan Yan 599426947304SEvan Yan DEBUG1("Fcode Addr %lx\n", *fcode_addr); 599526947304SEvan Yan 599626947304SEvan Yan ddi_rep_get8(h, *fcode_addr, addr + start_of_fcode, *fcode_size, 599726947304SEvan Yan DDI_DEV_AUTOINCR); 599826947304SEvan Yan 599926947304SEvan Yan pcicfg_unmap_phys(&h, &p); 600026947304SEvan Yan 600126947304SEvan Yan return (PCICFG_SUCCESS); 600226947304SEvan Yan } 600326947304SEvan Yan 600426947304SEvan Yan static int 600526947304SEvan Yan pcicfg_fcode_assign_bars(ddi_acc_handle_t h, dev_info_t *dip, uint_t bus, 600626947304SEvan Yan uint_t device, uint_t func, int32_t fc_request, pci_regspec_t *rom_regspec) 600726947304SEvan Yan { 600826947304SEvan Yan /* 600926947304SEvan Yan * Assign values to all BARs so that it is safe to turn on the 601026947304SEvan Yan * device for accessing the fcode on the PROM. On successful 601126947304SEvan Yan * exit from this function, "assigned-addresses" are created 601226947304SEvan Yan * for all BARs and ROM BAR is enabled. Also, rom_regspec is 601326947304SEvan Yan * filled with the values that can be used to free up this 601426947304SEvan Yan * resource later. 601526947304SEvan Yan */ 601626947304SEvan Yan uint32_t request, hiword, size; 601726947304SEvan Yan pci_regspec_t phys_spec; 601826947304SEvan Yan ndi_ra_request_t req; 601926947304SEvan Yan uint64_t mem_answer, mem_alen; 602026947304SEvan Yan int i; 602126947304SEvan Yan 602226947304SEvan Yan DEBUG1("pcicfg_fcode_assign_bars :%s\n", DEVI(dip)->devi_name); 602326947304SEvan Yan 602426947304SEvan Yan /* 602526947304SEvan Yan * Process the BARs. 602626947304SEvan Yan */ 602726947304SEvan Yan for (i = PCI_CONF_BASE0; i <= PCI_CONF_BASE5; ) { 602826947304SEvan Yan pci_config_put32(h, i, 0xffffffff); 602926947304SEvan Yan request = pci_config_get32(h, i); 603026947304SEvan Yan /* 603126947304SEvan Yan * Check if implemented 603226947304SEvan Yan */ 603326947304SEvan Yan if (request == 0) { 603426947304SEvan Yan DEBUG1("pcicfg_fcode_assign_bars :" 603526947304SEvan Yan "BASE register [0x%x] asks for 0(32)\n", i); 603626947304SEvan Yan i += 4; 603726947304SEvan Yan continue; 603826947304SEvan Yan } 603926947304SEvan Yan /* 604026947304SEvan Yan * Build the phys_spec for this BAR 604126947304SEvan Yan */ 604226947304SEvan Yan hiword = PCICFG_MAKE_REG_HIGH(bus, device, func, i); 604326947304SEvan Yan size = (~(PCI_BASE_M_ADDR_M & request)) + 1; 604426947304SEvan Yan 604526947304SEvan Yan DEBUG3("pcicfg_fcode_assign_bars :" 604626947304SEvan Yan "BASE register [0x%x] asks for [0x%x]=[0x%x]\n", 604726947304SEvan Yan i, request, size); 604826947304SEvan Yan 604926947304SEvan Yan if ((PCI_BASE_SPACE_M & request) == PCI_BASE_SPACE_MEM) { 605026947304SEvan Yan if ((PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_MEM) { 605126947304SEvan Yan hiword |= PCI_ADDR_MEM32; 605226947304SEvan Yan } else if ((PCI_BASE_TYPE_M & request) 605326947304SEvan Yan == PCI_BASE_TYPE_ALL) { 605426947304SEvan Yan hiword |= PCI_ADDR_MEM64; 605526947304SEvan Yan } 605626947304SEvan Yan if (request & PCI_BASE_PREF_M) 605726947304SEvan Yan hiword |= PCI_REG_PF_M; 605826947304SEvan Yan } else { 605926947304SEvan Yan hiword |= PCI_ADDR_IO; 606026947304SEvan Yan } 606126947304SEvan Yan phys_spec.pci_phys_hi = hiword; 606226947304SEvan Yan phys_spec.pci_phys_mid = 0; 606326947304SEvan Yan phys_spec.pci_phys_low = 0; 606426947304SEvan Yan phys_spec.pci_size_hi = 0; 606526947304SEvan Yan phys_spec.pci_size_low = size; 606626947304SEvan Yan 606726947304SEvan Yan /* 606826947304SEvan Yan * The following function 606926947304SEvan Yan * - allocates address space 607026947304SEvan Yan * - programs the BAR 607126947304SEvan Yan * - adds an "assigned-addresses" property 607226947304SEvan Yan */ 607326947304SEvan Yan if (pcicfg_alloc_resource(dip, phys_spec)) { 607426947304SEvan Yan cmn_err(CE_WARN, "failed to allocate %d bytes" 607526947304SEvan Yan " for dev %s BASE register [0x%x]\n", 607626947304SEvan Yan size, DEVI(dip)->devi_name, i); 607726947304SEvan Yan goto failure; 607826947304SEvan Yan } 607926947304SEvan Yan if ((PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_ALL) { 608026947304SEvan Yan /* 608126947304SEvan Yan * 64 bit, should be in memory space. 608226947304SEvan Yan */ 608326947304SEvan Yan i += 8; 608426947304SEvan Yan } else { 608526947304SEvan Yan /* 608626947304SEvan Yan * 32 bit, either memory or I/O space. 608726947304SEvan Yan */ 608826947304SEvan Yan i += 4; 608926947304SEvan Yan } 609026947304SEvan Yan } 609126947304SEvan Yan 609226947304SEvan Yan /* 609326947304SEvan Yan * Handle ROM BAR. We do not use the common 609426947304SEvan Yan * resource allocator function because we need to 609526947304SEvan Yan * return reg spec to the caller. 609626947304SEvan Yan */ 609726947304SEvan Yan size = (~(PCI_BASE_ROM_ADDR_M & fc_request)) + 1; 609826947304SEvan Yan 609926947304SEvan Yan DEBUG3("BASE register [0x%x] asks for " 610026947304SEvan Yan "[0x%x]=[0x%x]\n", PCI_CONF_ROM, fc_request, size); 610126947304SEvan Yan 610226947304SEvan Yan bzero((caddr_t)&req, sizeof (ndi_ra_request_t)); 610326947304SEvan Yan 610426947304SEvan Yan req.ra_boundbase = 0; 610526947304SEvan Yan req.ra_boundlen = PCICFG_4GIG_LIMIT; 610626947304SEvan Yan req.ra_len = size; 610726947304SEvan Yan req.ra_flags |= NDI_RA_ALIGN_SIZE; 610826947304SEvan Yan req.ra_flags ^= NDI_RA_ALLOC_BOUNDED; 610926947304SEvan Yan 611026947304SEvan Yan if (ndi_ra_alloc(ddi_get_parent(dip), 611126947304SEvan Yan &req, &mem_answer, &mem_alen, 611226947304SEvan Yan NDI_RA_TYPE_MEM, NDI_RA_PASS)) { 611326947304SEvan Yan cmn_err(CE_WARN, "failed to allocate %d bytes" 611426947304SEvan Yan " for dev %s ROM BASE register\n", 611526947304SEvan Yan size, DEVI(dip)->devi_name); 611626947304SEvan Yan goto failure; 611726947304SEvan Yan } 611826947304SEvan Yan 611926947304SEvan Yan DEBUG3("ROM addr = [0x%x.%x] len [0x%x]\n", 612026947304SEvan Yan PCICFG_HIADDR(mem_answer), 612126947304SEvan Yan PCICFG_LOADDR(mem_answer), mem_alen); 612226947304SEvan Yan 612326947304SEvan Yan /* 612426947304SEvan Yan * Assign address space and enable ROM. 612526947304SEvan Yan */ 612626947304SEvan Yan pci_config_put32(h, PCI_CONF_ROM, 612726947304SEvan Yan PCICFG_LOADDR(mem_answer) | PCI_BASE_ROM_ENABLE); 612826947304SEvan Yan 612926947304SEvan Yan /* 613026947304SEvan Yan * Add resource to assigned-addresses. 613126947304SEvan Yan */ 613226947304SEvan Yan phys_spec.pci_phys_hi = PCICFG_MAKE_REG_HIGH(bus, device, func, \ 613326947304SEvan Yan PCI_CONF_ROM) | PCI_ADDR_MEM32; 613426947304SEvan Yan if (fc_request & PCI_BASE_PREF_M) 613526947304SEvan Yan phys_spec.pci_phys_hi |= PCI_REG_PF_M; 613626947304SEvan Yan phys_spec.pci_phys_mid = 0; 613726947304SEvan Yan phys_spec.pci_phys_low = PCICFG_LOADDR(mem_answer); 613826947304SEvan Yan phys_spec.pci_size_hi = 0; 613926947304SEvan Yan phys_spec.pci_size_low = size; 614026947304SEvan Yan 614126947304SEvan Yan if (pcicfg_update_assigned_prop(dip, &phys_spec) 614226947304SEvan Yan != PCICFG_SUCCESS) { 614326947304SEvan Yan cmn_err(CE_WARN, "failed to update" 614426947304SEvan Yan " assigned-address property for dev %s\n", 614526947304SEvan Yan DEVI(dip)->devi_name); 614626947304SEvan Yan goto failure; 614726947304SEvan Yan } 614826947304SEvan Yan /* 614926947304SEvan Yan * Copy out the reg spec. 615026947304SEvan Yan */ 615126947304SEvan Yan *rom_regspec = phys_spec; 615226947304SEvan Yan 615326947304SEvan Yan return (PCICFG_SUCCESS); 615426947304SEvan Yan 615526947304SEvan Yan failure: 615626947304SEvan Yan /* 615726947304SEvan Yan * We came in with no "assigned-addresses". 615826947304SEvan Yan * Free up the resources we may have allocated. 615926947304SEvan Yan */ 616026947304SEvan Yan (void) pcicfg_free_device_resources(dip, 0); 616126947304SEvan Yan 616226947304SEvan Yan return (PCICFG_FAILURE); 616326947304SEvan Yan } 616426947304SEvan Yan 616526947304SEvan Yan #endif /* PCICFG_INTERPRET_FCODE */ 616626947304SEvan Yan 616726947304SEvan Yan static int 616826947304SEvan Yan pcicfg_free_all_resources(dev_info_t *dip) 616926947304SEvan Yan { 617026947304SEvan Yan pci_regspec_t *assigned; 617126947304SEvan Yan int assigned_len; 617226947304SEvan Yan int acount; 617326947304SEvan Yan int i; 617426947304SEvan Yan 617526947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 617626947304SEvan Yan DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned, 617726947304SEvan Yan &assigned_len) != DDI_PROP_SUCCESS) { 617826947304SEvan Yan DEBUG0("Failed to read assigned-addresses property\n"); 617926947304SEvan Yan return (PCICFG_FAILURE); 618026947304SEvan Yan } 618126947304SEvan Yan 618226947304SEvan Yan acount = assigned_len / sizeof (pci_regspec_t); 618326947304SEvan Yan 618426947304SEvan Yan for (i = 0; i < acount; i++) { 618526947304SEvan Yan if (pcicfg_free_resource(dip, assigned[i], 0)) { 618626947304SEvan Yan /* 618726947304SEvan Yan * Dont forget to free mem from ddi_getlongprop 618826947304SEvan Yan */ 618926947304SEvan Yan kmem_free((caddr_t)assigned, assigned_len); 619026947304SEvan Yan return (PCICFG_FAILURE); 619126947304SEvan Yan } 619226947304SEvan Yan } 619326947304SEvan Yan 619426947304SEvan Yan /* 619526947304SEvan Yan * Don't forget to free up memory from ddi_getlongprop 619626947304SEvan Yan */ 619726947304SEvan Yan if (assigned_len) 619826947304SEvan Yan kmem_free((caddr_t)assigned, assigned_len); 619926947304SEvan Yan 620026947304SEvan Yan return (PCICFG_SUCCESS); 620126947304SEvan Yan } 620226947304SEvan Yan static int 620326947304SEvan Yan pcicfg_alloc_new_resources(dev_info_t *dip) 620426947304SEvan Yan { 620526947304SEvan Yan pci_regspec_t *assigned, *reg; 620626947304SEvan Yan int assigned_len, reg_len; 620726947304SEvan Yan int acount, rcount; 620826947304SEvan Yan int i, j, alloc_size; 620926947304SEvan Yan boolean_t alloc; 621026947304SEvan Yan 621126947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 621226947304SEvan Yan DDI_PROP_DONTPASS, "reg", (caddr_t)®, 621326947304SEvan Yan ®_len) != DDI_PROP_SUCCESS) { 621426947304SEvan Yan DEBUG0("Failed to read reg property\n"); 621526947304SEvan Yan return (PCICFG_FAILURE); 621626947304SEvan Yan } 621726947304SEvan Yan rcount = reg_len / sizeof (pci_regspec_t); 621826947304SEvan Yan 621926947304SEvan Yan DEBUG2("pcicfg_alloc_new_resources() reg size=%x entries=%x\n", 622026947304SEvan Yan reg_len, rcount); 622126947304SEvan Yan 622226947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 622326947304SEvan Yan DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned, 622426947304SEvan Yan &assigned_len) != DDI_PROP_SUCCESS) { 622526947304SEvan Yan acount = 0; 622626947304SEvan Yan } else { 622726947304SEvan Yan acount = assigned_len / sizeof (pci_regspec_t); 622826947304SEvan Yan } 622926947304SEvan Yan 623026947304SEvan Yan DEBUG1("assigned-addresses property len=%x\n", acount); 623126947304SEvan Yan 623226947304SEvan Yan /* 623326947304SEvan Yan * For each address described by reg, search for it in the 623426947304SEvan Yan * assigned-addresses property. If it does not exist, allocate 623526947304SEvan Yan * resources for it. If it does exist, check the size in both. 623626947304SEvan Yan * The size needs to be bigger of the two. 623726947304SEvan Yan */ 623826947304SEvan Yan for (i = 1; i < rcount; i++) { 623926947304SEvan Yan alloc = B_TRUE; 624026947304SEvan Yan alloc_size = reg[i].pci_size_low; 624126947304SEvan Yan for (j = 0; j < acount; j++) { 624226947304SEvan Yan if (assigned[j].pci_phys_hi == reg[i].pci_phys_hi) { 624326947304SEvan Yan /* 624426947304SEvan Yan * There is an exact match. Check size. 624526947304SEvan Yan */ 624626947304SEvan Yan DEBUG1("pcicfg_alloc_new_resources " 624726947304SEvan Yan "- %x - MATCH\n", 624826947304SEvan Yan reg[i].pci_phys_hi); 624926947304SEvan Yan 625026947304SEvan Yan if (reg[i].pci_size_low > 625126947304SEvan Yan assigned[j].pci_size_low) { 625226947304SEvan Yan /* 625326947304SEvan Yan * Fcode wants more. 625426947304SEvan Yan */ 625526947304SEvan Yan DEBUG3("pcicfg_alloc_new_resources" 625626947304SEvan Yan " - %x - RESIZE" 625726947304SEvan Yan " assigned 0x%x reg 0x%x\n", 625826947304SEvan Yan assigned[j].pci_phys_hi, 625926947304SEvan Yan assigned[j].pci_size_low, 626026947304SEvan Yan reg[i].pci_size_low); 626126947304SEvan Yan 626226947304SEvan Yan /* 626326947304SEvan Yan * Free the old resource. 626426947304SEvan Yan */ 626526947304SEvan Yan (void) pcicfg_free_resource(dip, 626626947304SEvan Yan assigned[j], 0); 626726947304SEvan Yan } else { 626826947304SEvan Yan DEBUG3("pcicfg_alloc_new_resources" 626926947304SEvan Yan " - %x - ENOUGH" 627026947304SEvan Yan " assigned 0x%x reg 0x%x\n", 627126947304SEvan Yan assigned[j].pci_phys_hi, 627226947304SEvan Yan assigned[j].pci_size_low, 627326947304SEvan Yan reg[i].pci_size_low); 627426947304SEvan Yan 627526947304SEvan Yan alloc = B_FALSE; 627626947304SEvan Yan } 627726947304SEvan Yan break; 627826947304SEvan Yan } 627926947304SEvan Yan /* 628026947304SEvan Yan * Fcode may have set one or more of the 628126947304SEvan Yan * NPT bits in phys.hi. 628226947304SEvan Yan */ 628326947304SEvan Yan if (PCI_REG_BDFR_G(assigned[j].pci_phys_hi) == 628426947304SEvan Yan PCI_REG_BDFR_G(reg[i].pci_phys_hi)) { 628526947304SEvan Yan 628626947304SEvan Yan DEBUG2("pcicfg_alloc_new_resources " 628726947304SEvan Yan "- PARTIAL MATCH assigned 0x%x " 628826947304SEvan Yan "reg 0x%x\n", assigned[j].pci_phys_hi, 628926947304SEvan Yan reg[i].pci_phys_hi); 629026947304SEvan Yan /* 629126947304SEvan Yan * Changing the SS bits is an error 629226947304SEvan Yan */ 629326947304SEvan Yan if (PCI_REG_ADDR_G( 629426947304SEvan Yan assigned[j].pci_phys_hi) != 629526947304SEvan Yan PCI_REG_ADDR_G(reg[i].pci_phys_hi)) { 629626947304SEvan Yan 629726947304SEvan Yan DEBUG2("Fcode changing" 629826947304SEvan Yan " SS bits of - 0x%x -" 629926947304SEvan Yan " on %s\n", reg[i].pci_phys_hi, 630026947304SEvan Yan DEVI(dip)->devi_name); 630126947304SEvan Yan 630226947304SEvan Yan } 630326947304SEvan Yan 630426947304SEvan Yan 630526947304SEvan Yan /* 630626947304SEvan Yan * We are going to allocate new resource. 630726947304SEvan Yan * Free the old resource. Again, adjust 630826947304SEvan Yan * the size to be safe. 630926947304SEvan Yan */ 631026947304SEvan Yan (void) pcicfg_free_resource(dip, 631126947304SEvan Yan assigned[j], 0); 631226947304SEvan Yan 631326947304SEvan Yan alloc_size = MAX(reg[i].pci_size_low, 631426947304SEvan Yan assigned[j].pci_size_low); 631526947304SEvan Yan 631626947304SEvan Yan break; 631726947304SEvan Yan } 631826947304SEvan Yan } 631926947304SEvan Yan /* 632026947304SEvan Yan * We are allocating resources for one of three reasons - 632126947304SEvan Yan * - Fcode wants a larger address space 632226947304SEvan Yan * - Fcode has set changed/set n, p, t bits. 632326947304SEvan Yan * - It is a new "reg", it should be only ROM bar, but 632426947304SEvan Yan * we don't do the checking. 632526947304SEvan Yan */ 632626947304SEvan Yan if (alloc == B_TRUE) { 632726947304SEvan Yan DEBUG1("pcicfg_alloc_new_resources : creating 0x%x\n", 632826947304SEvan Yan reg[i].pci_phys_hi); 632926947304SEvan Yan 633026947304SEvan Yan reg[i].pci_size_low = alloc_size; 633126947304SEvan Yan if (pcicfg_alloc_resource(dip, reg[i])) { 633226947304SEvan Yan /* 633326947304SEvan Yan * Dont forget to free mem from 633426947304SEvan Yan * ddi_getlongprop 633526947304SEvan Yan */ 633626947304SEvan Yan if (acount != 0) 633726947304SEvan Yan kmem_free((caddr_t)assigned, 633826947304SEvan Yan assigned_len); 633926947304SEvan Yan kmem_free((caddr_t)reg, reg_len); 634026947304SEvan Yan return (PCICFG_FAILURE); 634126947304SEvan Yan } 634226947304SEvan Yan } 634326947304SEvan Yan } 634426947304SEvan Yan 634526947304SEvan Yan /* 634626947304SEvan Yan * Don't forget to free up memory from ddi_getlongprop 634726947304SEvan Yan */ 634826947304SEvan Yan if (acount != 0) 634926947304SEvan Yan kmem_free((caddr_t)assigned, assigned_len); 635026947304SEvan Yan kmem_free((caddr_t)reg, reg_len); 635126947304SEvan Yan 635226947304SEvan Yan return (PCICFG_SUCCESS); 635326947304SEvan Yan } 635426947304SEvan Yan 635526947304SEvan Yan static int 635626947304SEvan Yan pcicfg_alloc_resource(dev_info_t *dip, pci_regspec_t phys_spec) 635726947304SEvan Yan { 635826947304SEvan Yan uint64_t answer; 635926947304SEvan Yan uint64_t alen; 636026947304SEvan Yan int offset; 636126947304SEvan Yan pci_regspec_t config; 636226947304SEvan Yan caddr_t virt, v; 636326947304SEvan Yan ddi_device_acc_attr_t acc; 636426947304SEvan Yan ddi_acc_handle_t h; 636526947304SEvan Yan ndi_ra_request_t request; 636626947304SEvan Yan pci_regspec_t *assigned; 636726947304SEvan Yan int assigned_len, entries, i; 636826947304SEvan Yan 636926947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 637026947304SEvan Yan DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned, 637126947304SEvan Yan &assigned_len) == DDI_PROP_SUCCESS) { 637226947304SEvan Yan DEBUG0("pcicfg_alloc_resource - " 637326947304SEvan Yan "searching assigned-addresses\n"); 637426947304SEvan Yan 637526947304SEvan Yan entries = assigned_len / (sizeof (pci_regspec_t)); 637626947304SEvan Yan 637726947304SEvan Yan /* 637826947304SEvan Yan * Walk through the assigned-addresses entries. If there is 637926947304SEvan Yan * a match, there is no need to allocate the resource. 638026947304SEvan Yan */ 638126947304SEvan Yan for (i = 0; i < entries; i++) { 638226947304SEvan Yan if (assigned[i].pci_phys_hi == phys_spec.pci_phys_hi) { 638326947304SEvan Yan DEBUG1("pcicfg_alloc_resource - MATCH %x\n", 638426947304SEvan Yan assigned[i].pci_phys_hi); 638526947304SEvan Yan kmem_free(assigned, assigned_len); 638626947304SEvan Yan return (0); 638726947304SEvan Yan } 638826947304SEvan Yan } 638926947304SEvan Yan kmem_free(assigned, assigned_len); 639026947304SEvan Yan } 639126947304SEvan Yan 639226947304SEvan Yan bzero((caddr_t)&request, sizeof (ndi_ra_request_t)); 639326947304SEvan Yan 639426947304SEvan Yan config.pci_phys_hi = PCI_CONF_ADDR_MASK & phys_spec.pci_phys_hi; 639526947304SEvan Yan config.pci_phys_hi &= ~PCI_REG_REG_M; 639626947304SEvan Yan config.pci_phys_mid = config.pci_phys_low = 0; 639726947304SEvan Yan config.pci_size_hi = config.pci_size_low = 0; 639826947304SEvan Yan 639926947304SEvan Yan /* 640026947304SEvan Yan * Map in configuration space (temporarily) 640126947304SEvan Yan */ 640226947304SEvan Yan acc.devacc_attr_version = DDI_DEVICE_ATTR_V0; 640326947304SEvan Yan acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 640426947304SEvan Yan acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 640526947304SEvan Yan 640626947304SEvan Yan if (pcicfg_map_phys(dip, &config, &virt, &acc, &h)) { 640726947304SEvan Yan DEBUG0("Can not map in config space\n"); 640826947304SEvan Yan return (1); 640926947304SEvan Yan } 641026947304SEvan Yan 641126947304SEvan Yan request.ra_flags |= NDI_RA_ALIGN_SIZE; 641226947304SEvan Yan request.ra_boundbase = 0; 641326947304SEvan Yan request.ra_boundlen = PCICFG_4GIG_LIMIT; 641426947304SEvan Yan /* 641526947304SEvan Yan * Use size stored in phys_spec parameter. 641626947304SEvan Yan */ 641726947304SEvan Yan request.ra_len = phys_spec.pci_size_low; 641826947304SEvan Yan 641926947304SEvan Yan offset = PCI_REG_REG_G(phys_spec.pci_phys_hi); 642026947304SEvan Yan 642126947304SEvan Yan v = virt + offset; 642226947304SEvan Yan 642326947304SEvan Yan if (PCI_REG_REG_G(phys_spec.pci_phys_hi) == PCI_CONF_ROM) { 642426947304SEvan Yan 642526947304SEvan Yan request.ra_flags ^= NDI_RA_ALLOC_BOUNDED; 642626947304SEvan Yan 642726947304SEvan Yan /* allocate memory space from the allocator */ 642826947304SEvan Yan 642926947304SEvan Yan if (ndi_ra_alloc(ddi_get_parent(dip), 643026947304SEvan Yan &request, &answer, &alen, 643126947304SEvan Yan NDI_RA_TYPE_MEM, NDI_RA_PASS) 643226947304SEvan Yan != NDI_SUCCESS) { 643326947304SEvan Yan DEBUG0("(ROM)Failed to allocate 32b mem"); 643426947304SEvan Yan pcicfg_unmap_phys(&h, &config); 643526947304SEvan Yan return (1); 643626947304SEvan Yan } 643726947304SEvan Yan DEBUG3("ROM addr = [0x%x.%x] len [0x%x]\n", 643826947304SEvan Yan PCICFG_HIADDR(answer), 643926947304SEvan Yan PCICFG_LOADDR(answer), 644026947304SEvan Yan alen); 644126947304SEvan Yan 644226947304SEvan Yan /* program the low word */ 644326947304SEvan Yan 644426947304SEvan Yan ddi_put32(h, (uint32_t *)v, (uint32_t)PCICFG_LOADDR(answer)); 644526947304SEvan Yan 644626947304SEvan Yan phys_spec.pci_phys_low = PCICFG_LOADDR(answer); 644726947304SEvan Yan phys_spec.pci_phys_mid = PCICFG_HIADDR(answer); 644826947304SEvan Yan } else { 644926947304SEvan Yan 645026947304SEvan Yan switch (PCI_REG_ADDR_G(phys_spec.pci_phys_hi)) { 645126947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_MEM64): 645226947304SEvan Yan request.ra_flags ^= NDI_RA_ALLOC_BOUNDED; 645326947304SEvan Yan /* allocate memory space from the allocator */ 645426947304SEvan Yan if (ndi_ra_alloc(ddi_get_parent(dip), 645526947304SEvan Yan &request, &answer, &alen, 645626947304SEvan Yan NDI_RA_TYPE_MEM, NDI_RA_PASS) 645726947304SEvan Yan != NDI_SUCCESS) { 645826947304SEvan Yan DEBUG0("Failed to allocate 64b mem\n"); 645926947304SEvan Yan pcicfg_unmap_phys(&h, &config); 646026947304SEvan Yan return (1); 646126947304SEvan Yan } 646226947304SEvan Yan DEBUG3("64 addr = [0x%x.%x] len [0x%x]\n", 646326947304SEvan Yan PCICFG_HIADDR(answer), 646426947304SEvan Yan PCICFG_LOADDR(answer), 646526947304SEvan Yan alen); 646626947304SEvan Yan 646726947304SEvan Yan /* program the low word */ 646826947304SEvan Yan 646926947304SEvan Yan ddi_put32(h, (uint32_t *)v, 647026947304SEvan Yan (uint32_t)PCICFG_LOADDR(answer)); 647126947304SEvan Yan 647226947304SEvan Yan /* program the high word with value zero */ 647326947304SEvan Yan v += 4; 647426947304SEvan Yan ddi_put32(h, (uint32_t *)v, 647526947304SEvan Yan (uint32_t)PCICFG_HIADDR(answer)); 647626947304SEvan Yan 647726947304SEvan Yan phys_spec.pci_phys_low = PCICFG_LOADDR(answer); 647826947304SEvan Yan phys_spec.pci_phys_mid = PCICFG_HIADDR(answer); 647926947304SEvan Yan /* 648026947304SEvan Yan * currently support 32b address space 648126947304SEvan Yan * assignments only. 648226947304SEvan Yan */ 648326947304SEvan Yan phys_spec.pci_phys_hi ^= PCI_ADDR_MEM64 ^ 648426947304SEvan Yan PCI_ADDR_MEM32; 648526947304SEvan Yan 648626947304SEvan Yan break; 648726947304SEvan Yan 648826947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_MEM32): 648926947304SEvan Yan request.ra_flags |= NDI_RA_ALLOC_BOUNDED; 649026947304SEvan Yan /* allocate memory space from the allocator */ 649126947304SEvan Yan if (ndi_ra_alloc(ddi_get_parent(dip), 649226947304SEvan Yan &request, &answer, &alen, 649326947304SEvan Yan NDI_RA_TYPE_MEM, NDI_RA_PASS) 649426947304SEvan Yan != NDI_SUCCESS) { 649526947304SEvan Yan DEBUG0("Failed to allocate 32b mem\n"); 649626947304SEvan Yan pcicfg_unmap_phys(&h, &config); 649726947304SEvan Yan return (1); 649826947304SEvan Yan } 649926947304SEvan Yan 650026947304SEvan Yan DEBUG3("32 addr = [0x%x.%x] len [0x%x]\n", 650126947304SEvan Yan PCICFG_HIADDR(answer), 650226947304SEvan Yan PCICFG_LOADDR(answer), 650326947304SEvan Yan alen); 650426947304SEvan Yan 650526947304SEvan Yan /* program the low word */ 650626947304SEvan Yan 650726947304SEvan Yan ddi_put32(h, (uint32_t *)v, 650826947304SEvan Yan (uint32_t)PCICFG_LOADDR(answer)); 650926947304SEvan Yan 651026947304SEvan Yan phys_spec.pci_phys_low = PCICFG_LOADDR(answer); 651126947304SEvan Yan 651226947304SEvan Yan break; 651326947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_IO): 651426947304SEvan Yan /* allocate I/O space from the allocator */ 651526947304SEvan Yan request.ra_flags |= NDI_RA_ALLOC_BOUNDED; 651626947304SEvan Yan if (ndi_ra_alloc(ddi_get_parent(dip), 651726947304SEvan Yan &request, &answer, &alen, 651826947304SEvan Yan NDI_RA_TYPE_IO, NDI_RA_PASS) 651926947304SEvan Yan != NDI_SUCCESS) { 652026947304SEvan Yan DEBUG0("Failed to allocate I/O\n"); 652126947304SEvan Yan pcicfg_unmap_phys(&h, &config); 652226947304SEvan Yan return (1); 652326947304SEvan Yan } 652426947304SEvan Yan DEBUG3("I/O addr = [0x%x.%x] len [0x%x]\n", 652526947304SEvan Yan PCICFG_HIADDR(answer), 652626947304SEvan Yan PCICFG_LOADDR(answer), 652726947304SEvan Yan alen); 652826947304SEvan Yan 652926947304SEvan Yan ddi_put32(h, (uint32_t *)v, 653026947304SEvan Yan (uint32_t)PCICFG_LOADDR(answer)); 653126947304SEvan Yan 653226947304SEvan Yan phys_spec.pci_phys_low = PCICFG_LOADDR(answer); 653326947304SEvan Yan 653426947304SEvan Yan break; 653526947304SEvan Yan default: 653626947304SEvan Yan DEBUG0("Unknown register type\n"); 653726947304SEvan Yan pcicfg_unmap_phys(&h, &config); 653826947304SEvan Yan return (1); 653926947304SEvan Yan } /* switch */ 654026947304SEvan Yan } 654126947304SEvan Yan 654226947304SEvan Yan /* 654326947304SEvan Yan * Now that memory locations are assigned, 654426947304SEvan Yan * update the assigned address property. 654526947304SEvan Yan */ 654626947304SEvan Yan 654726947304SEvan Yan DEBUG1("updating assigned-addresss for %x\n", phys_spec.pci_phys_hi); 654826947304SEvan Yan 654926947304SEvan Yan if (pcicfg_update_assigned_prop(dip, &phys_spec)) { 655026947304SEvan Yan pcicfg_unmap_phys(&h, &config); 655126947304SEvan Yan return (1); 655226947304SEvan Yan } 655326947304SEvan Yan 655426947304SEvan Yan pcicfg_unmap_phys(&h, &config); 655526947304SEvan Yan 655626947304SEvan Yan return (0); 655726947304SEvan Yan } 655826947304SEvan Yan 655926947304SEvan Yan static int 656026947304SEvan Yan pcicfg_free_resource(dev_info_t *dip, pci_regspec_t phys_spec, 656126947304SEvan Yan pcicfg_flags_t flags) 656226947304SEvan Yan { 656326947304SEvan Yan int offset; 656426947304SEvan Yan pci_regspec_t config; 656526947304SEvan Yan caddr_t virt, v; 656626947304SEvan Yan ddi_device_acc_attr_t acc; 656726947304SEvan Yan ddi_acc_handle_t h; 656826947304SEvan Yan ndi_ra_request_t request; 656926947304SEvan Yan int l; 657026947304SEvan Yan 657126947304SEvan Yan bzero((caddr_t)&request, sizeof (ndi_ra_request_t)); 657226947304SEvan Yan 657326947304SEvan Yan config.pci_phys_hi = PCI_CONF_ADDR_MASK & phys_spec.pci_phys_hi; 657426947304SEvan Yan config.pci_phys_hi &= ~PCI_REG_REG_M; 657526947304SEvan Yan config.pci_phys_mid = config.pci_phys_low = 0; 657626947304SEvan Yan config.pci_size_hi = config.pci_size_low = 0; 657726947304SEvan Yan 657826947304SEvan Yan /* 657926947304SEvan Yan * Map in configuration space (temporarily) 658026947304SEvan Yan */ 658126947304SEvan Yan acc.devacc_attr_version = DDI_DEVICE_ATTR_V0; 658226947304SEvan Yan acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 658326947304SEvan Yan acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 658426947304SEvan Yan 658526947304SEvan Yan if (pcicfg_map_phys(dip, &config, &virt, &acc, &h)) { 658626947304SEvan Yan DEBUG0("Can not map in config space\n"); 658726947304SEvan Yan return (1); 658826947304SEvan Yan } 658926947304SEvan Yan 659026947304SEvan Yan offset = PCI_REG_REG_G(phys_spec.pci_phys_hi); 659126947304SEvan Yan 659226947304SEvan Yan v = virt + offset; 659326947304SEvan Yan 659426947304SEvan Yan /* 659526947304SEvan Yan * Use size stored in phys_spec parameter. 659626947304SEvan Yan */ 659726947304SEvan Yan l = phys_spec.pci_size_low; 659826947304SEvan Yan 659926947304SEvan Yan if (PCI_REG_REG_G(phys_spec.pci_phys_hi) == PCI_CONF_ROM) { 660026947304SEvan Yan 660126947304SEvan Yan /* free memory back to the allocator */ 660226947304SEvan Yan if (ndi_ra_free(ddi_get_parent(dip), phys_spec.pci_phys_low, 660326947304SEvan Yan l, NDI_RA_TYPE_MEM, NDI_RA_PASS) != NDI_SUCCESS) { 660426947304SEvan Yan DEBUG0("(ROM)Can not free 32b mem"); 660526947304SEvan Yan pcicfg_unmap_phys(&h, &config); 660626947304SEvan Yan return (1); 660726947304SEvan Yan } 660826947304SEvan Yan 660926947304SEvan Yan /* Unmap the BAR by writing a zero */ 661026947304SEvan Yan 661126947304SEvan Yan if ((flags & PCICFG_FLAG_READ_ONLY) == 0) 661226947304SEvan Yan ddi_put32(h, (uint32_t *)v, (uint32_t)0); 661326947304SEvan Yan } else { 661426947304SEvan Yan 661526947304SEvan Yan switch (PCI_REG_ADDR_G(phys_spec.pci_phys_hi)) { 661626947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_MEM64): 661726947304SEvan Yan /* free memory back to the allocator */ 661826947304SEvan Yan if (ndi_ra_free(ddi_get_parent(dip), 661926947304SEvan Yan PCICFG_LADDR(phys_spec.pci_phys_low, 662026947304SEvan Yan phys_spec.pci_phys_mid), 662126947304SEvan Yan l, NDI_RA_TYPE_MEM, 662226947304SEvan Yan NDI_RA_PASS) != NDI_SUCCESS) { 662326947304SEvan Yan DEBUG0("Can not free 64b mem"); 662426947304SEvan Yan pcicfg_unmap_phys(&h, &config); 662526947304SEvan Yan return (1); 662626947304SEvan Yan } 662726947304SEvan Yan 662826947304SEvan Yan break; 662926947304SEvan Yan 663026947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_MEM32): 663126947304SEvan Yan /* free memory back to the allocator */ 663226947304SEvan Yan if (ndi_ra_free(ddi_get_parent(dip), 663326947304SEvan Yan phys_spec.pci_phys_low, 663426947304SEvan Yan l, NDI_RA_TYPE_MEM, 663526947304SEvan Yan NDI_RA_PASS) != NDI_SUCCESS) { 663626947304SEvan Yan DEBUG0("Can not free 32b mem"); 663726947304SEvan Yan pcicfg_unmap_phys(&h, &config); 663826947304SEvan Yan return (1); 663926947304SEvan Yan } 664026947304SEvan Yan 664126947304SEvan Yan break; 664226947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_IO): 664326947304SEvan Yan /* free I/O space back to the allocator */ 664426947304SEvan Yan if (ndi_ra_free(ddi_get_parent(dip), 664526947304SEvan Yan phys_spec.pci_phys_low, 664626947304SEvan Yan l, NDI_RA_TYPE_IO, 664726947304SEvan Yan NDI_RA_PASS) != NDI_SUCCESS) { 664826947304SEvan Yan DEBUG0("Can not free I/O space"); 664926947304SEvan Yan pcicfg_unmap_phys(&h, &config); 665026947304SEvan Yan return (1); 665126947304SEvan Yan } 665226947304SEvan Yan 665326947304SEvan Yan break; 665426947304SEvan Yan default: 665526947304SEvan Yan DEBUG0("Unknown register type\n"); 665626947304SEvan Yan pcicfg_unmap_phys(&h, &config); 665726947304SEvan Yan return (1); 665826947304SEvan Yan } /* switch */ 665926947304SEvan Yan } 666026947304SEvan Yan 666126947304SEvan Yan /* 666226947304SEvan Yan * Now that memory locations are assigned, 666326947304SEvan Yan * update the assigned address property. 666426947304SEvan Yan */ 666526947304SEvan Yan 666626947304SEvan Yan DEBUG1("updating assigned-addresss for %x\n", phys_spec.pci_phys_hi); 666726947304SEvan Yan 666826947304SEvan Yan if (pcicfg_remove_assigned_prop(dip, &phys_spec)) { 666926947304SEvan Yan pcicfg_unmap_phys(&h, &config); 667026947304SEvan Yan return (1); 667126947304SEvan Yan } 667226947304SEvan Yan 667326947304SEvan Yan pcicfg_unmap_phys(&h, &config); 667426947304SEvan Yan 667526947304SEvan Yan return (0); 667626947304SEvan Yan } 667726947304SEvan Yan 667826947304SEvan Yan static int 667926947304SEvan Yan pcicfg_remove_assigned_prop(dev_info_t *dip, pci_regspec_t *oldone) 668026947304SEvan Yan { 668126947304SEvan Yan int alen, num_entries, i; 668226947304SEvan Yan pci_regspec_t *assigned, *assigned_copy; 668326947304SEvan Yan uint_t status; 668426947304SEvan Yan 668526947304SEvan Yan status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 668626947304SEvan Yan "assigned-addresses", (caddr_t)&assigned, &alen); 668726947304SEvan Yan switch (status) { 668826947304SEvan Yan case DDI_PROP_SUCCESS: 668926947304SEvan Yan break; 669026947304SEvan Yan case DDI_PROP_NO_MEMORY: 669126947304SEvan Yan DEBUG0("no memory for assigned-addresses property\n"); 669226947304SEvan Yan return (1); 669326947304SEvan Yan default: 669426947304SEvan Yan DEBUG0("assigned-addresses property does not exist\n"); 669526947304SEvan Yan return (0); 669626947304SEvan Yan } 669726947304SEvan Yan 669826947304SEvan Yan /* 669926947304SEvan Yan * Make a copy of old assigned-addresses property. 670026947304SEvan Yan */ 670126947304SEvan Yan assigned_copy = kmem_alloc(alen, KM_SLEEP); 670226947304SEvan Yan bcopy(assigned, assigned_copy, alen); 670326947304SEvan Yan 670426947304SEvan Yan status = ndi_prop_remove(DDI_DEV_T_NONE, dip, "assigned-addresses"); 670526947304SEvan Yan 670626947304SEvan Yan if (status != DDI_PROP_SUCCESS) { 670726947304SEvan Yan /* 670826947304SEvan Yan * If "assigned-addresses" is retrieved from PROM, the 670926947304SEvan Yan * ndi_prop_remove() will fail. 671026947304SEvan Yan */ 671126947304SEvan Yan DEBUG1("pcicfg_remove_assigned_prop: 0x%x not removed\n", 671226947304SEvan Yan oldone->pci_phys_hi); 671326947304SEvan Yan 671426947304SEvan Yan /* 671526947304SEvan Yan * Free up allocated memory 671626947304SEvan Yan */ 671726947304SEvan Yan kmem_free(assigned_copy, alen); 671826947304SEvan Yan kmem_free((caddr_t)assigned, alen); 671926947304SEvan Yan 672026947304SEvan Yan return (0); 672126947304SEvan Yan } 672226947304SEvan Yan 672326947304SEvan Yan num_entries = alen / sizeof (pci_regspec_t); 672426947304SEvan Yan 672526947304SEvan Yan /* 672626947304SEvan Yan * Rebuild the assigned-addresses property. 672726947304SEvan Yan */ 672826947304SEvan Yan for (i = 0; i < num_entries; i++) { 672926947304SEvan Yan if (assigned_copy[i].pci_phys_hi != oldone->pci_phys_hi) { 673026947304SEvan Yan (void) pcicfg_update_assigned_prop(dip, 673126947304SEvan Yan &assigned_copy[i]); 673226947304SEvan Yan } 673326947304SEvan Yan } 673426947304SEvan Yan 673526947304SEvan Yan /* 673626947304SEvan Yan * Free the copy of the original assigned-addresses. 673726947304SEvan Yan */ 673826947304SEvan Yan kmem_free(assigned_copy, alen); 673926947304SEvan Yan 674026947304SEvan Yan /* 674126947304SEvan Yan * Don't forget to free up memory from ddi_getlongprop 674226947304SEvan Yan */ 674326947304SEvan Yan kmem_free((caddr_t)assigned, alen); 674426947304SEvan Yan 674526947304SEvan Yan return (0); 674626947304SEvan Yan } 674726947304SEvan Yan 674826947304SEvan Yan static int 674926947304SEvan Yan pcicfg_map_phys(dev_info_t *dip, pci_regspec_t *phys_spec, 675026947304SEvan Yan caddr_t *addrp, ddi_device_acc_attr_t *accattrp, 675126947304SEvan Yan ddi_acc_handle_t *handlep) 675226947304SEvan Yan { 675326947304SEvan Yan ddi_map_req_t mr; 675426947304SEvan Yan ddi_acc_hdl_t *hp; 675526947304SEvan Yan int result; 675626947304SEvan Yan 675726947304SEvan Yan *handlep = impl_acc_hdl_alloc(KM_SLEEP, NULL); 675826947304SEvan Yan hp = impl_acc_hdl_get(*handlep); 675926947304SEvan Yan hp->ah_vers = VERS_ACCHDL; 676026947304SEvan Yan hp->ah_dip = dip; 676126947304SEvan Yan hp->ah_rnumber = 0; 676226947304SEvan Yan hp->ah_offset = 0; 676326947304SEvan Yan hp->ah_len = 0; 676426947304SEvan Yan hp->ah_acc = *accattrp; 676526947304SEvan Yan 676626947304SEvan Yan mr.map_op = DDI_MO_MAP_LOCKED; 676726947304SEvan Yan mr.map_type = DDI_MT_REGSPEC; 676826947304SEvan Yan mr.map_obj.rp = (struct regspec *)phys_spec; 676926947304SEvan Yan mr.map_prot = PROT_READ | PROT_WRITE; 677026947304SEvan Yan mr.map_flags = DDI_MF_KERNEL_MAPPING; 677126947304SEvan Yan mr.map_handlep = hp; 677226947304SEvan Yan mr.map_vers = DDI_MAP_VERSION; 677326947304SEvan Yan 677426947304SEvan Yan result = ddi_map(dip, &mr, 0, 0, addrp); 677526947304SEvan Yan 677626947304SEvan Yan if (result != DDI_SUCCESS) { 677726947304SEvan Yan impl_acc_hdl_free(*handlep); 677826947304SEvan Yan *handlep = (ddi_acc_handle_t)NULL; 677926947304SEvan Yan } else { 678026947304SEvan Yan hp->ah_addr = *addrp; 678126947304SEvan Yan } 678226947304SEvan Yan 678326947304SEvan Yan return (result); 678426947304SEvan Yan } 678526947304SEvan Yan 678626947304SEvan Yan void 678726947304SEvan Yan pcicfg_unmap_phys(ddi_acc_handle_t *handlep, pci_regspec_t *ph) 678826947304SEvan Yan { 678926947304SEvan Yan ddi_map_req_t mr; 679026947304SEvan Yan ddi_acc_hdl_t *hp; 679126947304SEvan Yan 679226947304SEvan Yan hp = impl_acc_hdl_get(*handlep); 679326947304SEvan Yan ASSERT(hp); 679426947304SEvan Yan 679526947304SEvan Yan mr.map_op = DDI_MO_UNMAP; 679626947304SEvan Yan mr.map_type = DDI_MT_REGSPEC; 679726947304SEvan Yan mr.map_obj.rp = (struct regspec *)ph; 679826947304SEvan Yan mr.map_prot = PROT_READ | PROT_WRITE; 679926947304SEvan Yan mr.map_flags = DDI_MF_KERNEL_MAPPING; 680026947304SEvan Yan mr.map_handlep = hp; 680126947304SEvan Yan mr.map_vers = DDI_MAP_VERSION; 680226947304SEvan Yan 680326947304SEvan Yan (void) ddi_map(hp->ah_dip, &mr, hp->ah_offset, 680426947304SEvan Yan hp->ah_len, &hp->ah_addr); 680526947304SEvan Yan 680626947304SEvan Yan impl_acc_hdl_free(*handlep); 680726947304SEvan Yan *handlep = (ddi_acc_handle_t)NULL; 680826947304SEvan Yan } 680926947304SEvan Yan 681026947304SEvan Yan static int 681126947304SEvan Yan pcicfg_ari_configure(dev_info_t *dip) 681226947304SEvan Yan { 681326947304SEvan Yan if (pcie_ari_supported(dip) == PCIE_ARI_FORW_NOT_SUPPORTED) 681426947304SEvan Yan return (DDI_FAILURE); 681526947304SEvan Yan 681626947304SEvan Yan /* 681726947304SEvan Yan * Until we have resource balancing, dynamically configure 681826947304SEvan Yan * ARI functions without firmware assistamce. 681926947304SEvan Yan */ 682026947304SEvan Yan return (DDI_FAILURE); 682126947304SEvan Yan } 682226947304SEvan Yan 682326947304SEvan Yan #ifdef DEBUG 682426947304SEvan Yan static void 682526947304SEvan Yan debug(char *fmt, uintptr_t a1, uintptr_t a2, uintptr_t a3, 682626947304SEvan Yan uintptr_t a4, uintptr_t a5) 682726947304SEvan Yan { 682826947304SEvan Yan if (pcicfg_debug == 1) { 682926947304SEvan Yan prom_printf("pcicfg: "); 683026947304SEvan Yan prom_printf(fmt, a1, a2, a3, a4, a5); 683126947304SEvan Yan } else 683226947304SEvan Yan if (pcicfg_debug) 683326947304SEvan Yan cmn_err(CE_CONT, fmt, a1, a2, a3, a4, a5); 683426947304SEvan Yan } 683526947304SEvan Yan #endif 6836c0da6274SZhi-Jun Robin Fu 6837c0da6274SZhi-Jun Robin Fu /* 6838c0da6274SZhi-Jun Robin Fu * Return true if the devinfo node is in a PCI Express hierarchy. 6839c0da6274SZhi-Jun Robin Fu */ 6840c0da6274SZhi-Jun Robin Fu static boolean_t 6841c0da6274SZhi-Jun Robin Fu is_pcie_fabric(dev_info_t *dip) 6842c0da6274SZhi-Jun Robin Fu { 6843c0da6274SZhi-Jun Robin Fu dev_info_t *root = ddi_root_node(); 6844c0da6274SZhi-Jun Robin Fu dev_info_t *pdip; 6845c0da6274SZhi-Jun Robin Fu boolean_t found = B_FALSE; 6846c0da6274SZhi-Jun Robin Fu char *bus; 6847c0da6274SZhi-Jun Robin Fu 6848c0da6274SZhi-Jun Robin Fu /* 6849c0da6274SZhi-Jun Robin Fu * Does this device reside in a pcie fabric ? 6850c0da6274SZhi-Jun Robin Fu */ 6851c0da6274SZhi-Jun Robin Fu for (pdip = dip; pdip && (pdip != root) && !found; 6852c0da6274SZhi-Jun Robin Fu pdip = ddi_get_parent(pdip)) { 6853c0da6274SZhi-Jun Robin Fu if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip, 6854c0da6274SZhi-Jun Robin Fu DDI_PROP_DONTPASS, "device_type", &bus) != 6855c0da6274SZhi-Jun Robin Fu DDI_PROP_SUCCESS) 6856c0da6274SZhi-Jun Robin Fu break; 6857c0da6274SZhi-Jun Robin Fu 6858c0da6274SZhi-Jun Robin Fu if (strcmp(bus, "pciex") == 0) 6859c0da6274SZhi-Jun Robin Fu found = B_TRUE; 6860c0da6274SZhi-Jun Robin Fu 6861c0da6274SZhi-Jun Robin Fu ddi_prop_free(bus); 6862c0da6274SZhi-Jun Robin Fu } 6863c0da6274SZhi-Jun Robin Fu 6864c0da6274SZhi-Jun Robin Fu return (found); 6865c0da6274SZhi-Jun Robin Fu } 6866