17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5a6469d9bSprasad * Common Development and Distribution License (the "License").
6a6469d9bSprasad * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
227f59ab1cSAlan Adamson, SD OSSD * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
23ffb64830SJordan Paige Hendricks * Copyright 2019 Joyent, Inc.
24b31f5cf7SDan Cross * Copyright 2023 Oxide Computer Company
257c478bd9Sstevel@tonic-gate */
267c478bd9Sstevel@tonic-gate
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate * PCI configurator (pcicfg)
297c478bd9Sstevel@tonic-gate */
307c478bd9Sstevel@tonic-gate
3170025d76Sjohnny #include <sys/sysmacros.h>
327c478bd9Sstevel@tonic-gate #include <sys/conf.h>
337c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
347c478bd9Sstevel@tonic-gate #include <sys/debug.h>
357c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
367c478bd9Sstevel@tonic-gate #include <sys/autoconf.h>
377c478bd9Sstevel@tonic-gate #include <sys/hwconf.h>
3870025d76Sjohnny #include <sys/pcie.h>
3926947304SEvan Yan #include <sys/pcie_impl.h>
4049fbdd30SErwin T Tsaur #include <sys/pci_cap.h>
417c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
427c478bd9Sstevel@tonic-gate #include <sys/sunndi.h>
437c478bd9Sstevel@tonic-gate #include <sys/hotplug/pci/pcicfg.h>
447c478bd9Sstevel@tonic-gate #include <sys/ndi_impldefs.h>
45c0da6274SZhi-Jun Robin Fu #include <sys/pci_cfgacc.h>
46*bd97c7ceSRobert Mustacchi #include <sys/pci_props.h>
477c478bd9Sstevel@tonic-gate
487c478bd9Sstevel@tonic-gate /*
497c478bd9Sstevel@tonic-gate * ************************************************************************
507c478bd9Sstevel@tonic-gate * *** Implementation specific local data structures/definitions. ***
517c478bd9Sstevel@tonic-gate * ************************************************************************
527c478bd9Sstevel@tonic-gate */
537c478bd9Sstevel@tonic-gate
547c478bd9Sstevel@tonic-gate static int pcicfg_start_devno = 0; /* for Debug only */
557c478bd9Sstevel@tonic-gate
5626947304SEvan Yan #define PCICFG_MAX_ARI_FUNCTION 256
5726947304SEvan Yan
587c478bd9Sstevel@tonic-gate #define PCICFG_NODEVICE 42
597c478bd9Sstevel@tonic-gate #define PCICFG_NOMEMORY 43
607c478bd9Sstevel@tonic-gate #define PCICFG_NOMULTI 44
615af4ae46Sjveta #define PCICFG_NORESRC 45
627c478bd9Sstevel@tonic-gate
63a6469d9bSprasad #define PCICFG_HIADDR(n) ((uint32_t)(((uint64_t)(n) & \
64a6469d9bSprasad 0xFFFFFFFF00000000ULL)>> 32))
657c478bd9Sstevel@tonic-gate #define PCICFG_LOADDR(n) ((uint32_t)((uint64_t)(n) & 0x00000000FFFFFFFF))
667c478bd9Sstevel@tonic-gate #define PCICFG_LADDR(lo, hi) (((uint64_t)(hi) << 32) | (uint32_t)(lo))
677c478bd9Sstevel@tonic-gate
687c478bd9Sstevel@tonic-gate #define PCICFG_HIWORD(n) ((uint16_t)(((uint32_t)(n) & 0xFFFF0000)>> 16))
697c478bd9Sstevel@tonic-gate #define PCICFG_LOWORD(n) ((uint16_t)((uint32_t)(n) & 0x0000FFFF))
707c478bd9Sstevel@tonic-gate #define PCICFG_HIBYTE(n) ((uint8_t)(((uint16_t)(n) & 0xFF00)>> 8))
717c478bd9Sstevel@tonic-gate #define PCICFG_LOBYTE(n) ((uint8_t)((uint16_t)(n) & 0x00FF))
727c478bd9Sstevel@tonic-gate
737c478bd9Sstevel@tonic-gate #define PCICFG_ROUND_UP(addr, gran) ((uintptr_t)((gran+addr-1)&(~(gran-1))))
747c478bd9Sstevel@tonic-gate #define PCICFG_ROUND_DOWN(addr, gran) ((uintptr_t)((addr) & ~(gran-1)))
757c478bd9Sstevel@tonic-gate
767c478bd9Sstevel@tonic-gate #define PCICFG_MEMGRAN 0x100000
777c478bd9Sstevel@tonic-gate #define PCICFG_IOGRAN 0x1000
787c478bd9Sstevel@tonic-gate #define PCICFG_4GIG_LIMIT 0xFFFFFFFFUL
797c478bd9Sstevel@tonic-gate
807c478bd9Sstevel@tonic-gate #define PCICFG_MEM_MULT 4
817c478bd9Sstevel@tonic-gate #define PCICFG_IO_MULT 4
82a6469d9bSprasad #define PCICFG_RANGE_LEN 3 /* Number of range entries */
837c478bd9Sstevel@tonic-gate
8470025d76Sjohnny static int pcicfg_slot_busnums = 8;
8570025d76Sjohnny static int pcicfg_slot_memsize = 32 * PCICFG_MEMGRAN; /* 32MB per slot */
86a6469d9bSprasad static int pcicfg_slot_pf_memsize = 32 * PCICFG_MEMGRAN; /* 32MB per slot */
8770025d76Sjohnny static int pcicfg_slot_iosize = 64 * PCICFG_IOGRAN; /* 64K per slot */
8870025d76Sjohnny static int pcicfg_sec_reset_delay = 3000000;
8970025d76Sjohnny
907c478bd9Sstevel@tonic-gate typedef struct hole hole_t;
917c478bd9Sstevel@tonic-gate
927c478bd9Sstevel@tonic-gate struct hole {
937c478bd9Sstevel@tonic-gate uint64_t start;
947c478bd9Sstevel@tonic-gate uint64_t len;
957c478bd9Sstevel@tonic-gate hole_t *next;
967c478bd9Sstevel@tonic-gate };
977c478bd9Sstevel@tonic-gate
987c478bd9Sstevel@tonic-gate typedef struct pcicfg_phdl pcicfg_phdl_t;
997c478bd9Sstevel@tonic-gate
1007c478bd9Sstevel@tonic-gate struct pcicfg_phdl {
1017c478bd9Sstevel@tonic-gate
10270025d76Sjohnny dev_info_t *dip; /* Associated with the bridge */
10370025d76Sjohnny dev_info_t *top_dip; /* top node of the attach point */
1047c478bd9Sstevel@tonic-gate pcicfg_phdl_t *next;
1057c478bd9Sstevel@tonic-gate
106a6469d9bSprasad /* non-prefetchable memory space */
1077c478bd9Sstevel@tonic-gate uint64_t memory_base; /* Memory base for this attach point */
1087c478bd9Sstevel@tonic-gate uint64_t memory_last;
1097c478bd9Sstevel@tonic-gate uint64_t memory_len;
110a6469d9bSprasad
111a6469d9bSprasad /* prefetchable memory space */
11226947304SEvan Yan uint64_t pf_memory_base; /* PF Memory base for this Connection */
113a6469d9bSprasad uint64_t pf_memory_last;
114a6469d9bSprasad uint64_t pf_memory_len;
115a6469d9bSprasad
116a6469d9bSprasad /* io space */
1177c478bd9Sstevel@tonic-gate uint32_t io_base; /* I/O base for this attach point */
1187c478bd9Sstevel@tonic-gate uint32_t io_last;
1197c478bd9Sstevel@tonic-gate uint32_t io_len;
1207c478bd9Sstevel@tonic-gate
1217c478bd9Sstevel@tonic-gate int error;
1227c478bd9Sstevel@tonic-gate uint_t highest_bus; /* Highest bus seen on the probe */
1237c478bd9Sstevel@tonic-gate
1247c478bd9Sstevel@tonic-gate hole_t mem_hole; /* Memory hole linked list. */
125a6469d9bSprasad hole_t pf_mem_hole; /* PF Memory hole linked list. */
1267c478bd9Sstevel@tonic-gate hole_t io_hole; /* IO hole linked list */
1277c478bd9Sstevel@tonic-gate
1287c478bd9Sstevel@tonic-gate ndi_ra_request_t mem_req; /* allocator request for memory */
129a6469d9bSprasad ndi_ra_request_t pf_mem_req; /* allocator request for PF memory */
1307c478bd9Sstevel@tonic-gate ndi_ra_request_t io_req; /* allocator request for I/O */
1317c478bd9Sstevel@tonic-gate };
1327c478bd9Sstevel@tonic-gate
1337c478bd9Sstevel@tonic-gate struct pcicfg_standard_prop_entry {
1347c478bd9Sstevel@tonic-gate uchar_t *name;
1357c478bd9Sstevel@tonic-gate uint_t config_offset;
1367c478bd9Sstevel@tonic-gate uint_t size;
1377c478bd9Sstevel@tonic-gate };
1387c478bd9Sstevel@tonic-gate
1397c478bd9Sstevel@tonic-gate
1407c478bd9Sstevel@tonic-gate struct pcicfg_name_entry {
1417c478bd9Sstevel@tonic-gate uint32_t class_code;
1427c478bd9Sstevel@tonic-gate char *name;
1437c478bd9Sstevel@tonic-gate };
1447c478bd9Sstevel@tonic-gate
1457c478bd9Sstevel@tonic-gate struct pcicfg_find_ctrl {
1467c478bd9Sstevel@tonic-gate uint_t device;
1477c478bd9Sstevel@tonic-gate uint_t function;
1487c478bd9Sstevel@tonic-gate dev_info_t *dip;
1497c478bd9Sstevel@tonic-gate };
1507c478bd9Sstevel@tonic-gate
1517c478bd9Sstevel@tonic-gate /*
1527c478bd9Sstevel@tonic-gate * List of Indirect Config Map Devices. At least the intent of the
1537c478bd9Sstevel@tonic-gate * design is to look for a device in this list during the configure
1547c478bd9Sstevel@tonic-gate * operation, and if the device is listed here, then it is a nontransparent
1557c478bd9Sstevel@tonic-gate * bridge, hence load the driver and avail the config map services from
1567c478bd9Sstevel@tonic-gate * the driver. Class and Subclass should be as defined in the PCI specs
1577c478bd9Sstevel@tonic-gate * ie. class is 0x6, and subclass is 0x9.
1587c478bd9Sstevel@tonic-gate */
1597c478bd9Sstevel@tonic-gate static struct {
1607c478bd9Sstevel@tonic-gate uint8_t mem_range_bar_offset;
1617c478bd9Sstevel@tonic-gate uint8_t io_range_bar_offset;
1627c478bd9Sstevel@tonic-gate uint8_t prefetch_mem_range_bar_offset;
1637c478bd9Sstevel@tonic-gate } pcicfg_indirect_map_devs[] = {
1647c478bd9Sstevel@tonic-gate PCI_CONF_BASE3, PCI_CONF_BASE2, PCI_CONF_BASE3,
1657c478bd9Sstevel@tonic-gate 0, 0, 0,
1667c478bd9Sstevel@tonic-gate };
1677c478bd9Sstevel@tonic-gate
1687c478bd9Sstevel@tonic-gate #define PCICFG_MAKE_REG_HIGH(busnum, devnum, funcnum, register)\
1697c478bd9Sstevel@tonic-gate (\
1707c478bd9Sstevel@tonic-gate ((ulong_t)(busnum & 0xff) << 16) |\
1717c478bd9Sstevel@tonic-gate ((ulong_t)(devnum & 0x1f) << 11) |\
1727c478bd9Sstevel@tonic-gate ((ulong_t)(funcnum & 0x7) << 8) |\
1737c478bd9Sstevel@tonic-gate ((ulong_t)(register & 0x3f)))
1747c478bd9Sstevel@tonic-gate
1757c478bd9Sstevel@tonic-gate /*
1767c478bd9Sstevel@tonic-gate * debug macros:
1777c478bd9Sstevel@tonic-gate */
1787c478bd9Sstevel@tonic-gate #if defined(DEBUG)
1797c478bd9Sstevel@tonic-gate extern void prom_printf(const char *, ...);
1807c478bd9Sstevel@tonic-gate
1817c478bd9Sstevel@tonic-gate /*
1827c478bd9Sstevel@tonic-gate * Following values are defined for this debug flag.
1837c478bd9Sstevel@tonic-gate *
1847c478bd9Sstevel@tonic-gate * 1 = dump configuration header only.
1857c478bd9Sstevel@tonic-gate * 2 = dump generic debug data only (no config header dumped)
1867c478bd9Sstevel@tonic-gate * 3 = dump everything (both 1 and 2)
1877c478bd9Sstevel@tonic-gate */
1887c478bd9Sstevel@tonic-gate int pcicfg_debug = 0;
1897c478bd9Sstevel@tonic-gate
1907c478bd9Sstevel@tonic-gate static void debug(char *, uintptr_t, uintptr_t,
1917c478bd9Sstevel@tonic-gate uintptr_t, uintptr_t, uintptr_t);
1927c478bd9Sstevel@tonic-gate
1937c478bd9Sstevel@tonic-gate #define DEBUG0(fmt)\
1947c478bd9Sstevel@tonic-gate debug(fmt, 0, 0, 0, 0, 0);
1957c478bd9Sstevel@tonic-gate #define DEBUG1(fmt, a1)\
1967c478bd9Sstevel@tonic-gate debug(fmt, (uintptr_t)(a1), 0, 0, 0, 0);
1977c478bd9Sstevel@tonic-gate #define DEBUG2(fmt, a1, a2)\
1987c478bd9Sstevel@tonic-gate debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2), 0, 0, 0);
1997c478bd9Sstevel@tonic-gate #define DEBUG3(fmt, a1, a2, a3)\
2007c478bd9Sstevel@tonic-gate debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2),\
2017c478bd9Sstevel@tonic-gate (uintptr_t)(a3), 0, 0);
2027c478bd9Sstevel@tonic-gate #define DEBUG4(fmt, a1, a2, a3, a4)\
2037c478bd9Sstevel@tonic-gate debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2),\
2047c478bd9Sstevel@tonic-gate (uintptr_t)(a3), (uintptr_t)(a4), 0);
205a6469d9bSprasad #define DEBUG5(fmt, a1, a2, a3, a4, a5)\
206a6469d9bSprasad debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2),\
207a6469d9bSprasad (uintptr_t)(a3), (uintptr_t)(a4), (uintptr_t)(a5));
2087c478bd9Sstevel@tonic-gate #else
2097c478bd9Sstevel@tonic-gate #define DEBUG0(fmt)
2107c478bd9Sstevel@tonic-gate #define DEBUG1(fmt, a1)
2117c478bd9Sstevel@tonic-gate #define DEBUG2(fmt, a1, a2)
2127c478bd9Sstevel@tonic-gate #define DEBUG3(fmt, a1, a2, a3)
2137c478bd9Sstevel@tonic-gate #define DEBUG4(fmt, a1, a2, a3, a4)
214a6469d9bSprasad #define DEBUG5(fmt, a1, a2, a3, a4, a5)
2157c478bd9Sstevel@tonic-gate #endif
2167c478bd9Sstevel@tonic-gate
2177c478bd9Sstevel@tonic-gate /*
2187c478bd9Sstevel@tonic-gate * forward declarations for routines defined in this module (called here)
2197c478bd9Sstevel@tonic-gate */
2207c478bd9Sstevel@tonic-gate
2217c478bd9Sstevel@tonic-gate static int pcicfg_add_config_reg(dev_info_t *,
22226947304SEvan Yan uint_t, uint_t, uint_t);
22370025d76Sjohnny static int pcicfg_probe_children(dev_info_t *, uint_t, uint_t, uint_t,
224c0da6274SZhi-Jun Robin Fu uint_t *, pcicfg_flags_t, boolean_t);
2257c478bd9Sstevel@tonic-gate static int pcicfg_match_dev(dev_info_t *, void *);
2267c478bd9Sstevel@tonic-gate static dev_info_t *pcicfg_devi_find(dev_info_t *, uint_t, uint_t);
2277c478bd9Sstevel@tonic-gate static pcicfg_phdl_t *pcicfg_find_phdl(dev_info_t *);
2287c478bd9Sstevel@tonic-gate static pcicfg_phdl_t *pcicfg_create_phdl(dev_info_t *);
2297c478bd9Sstevel@tonic-gate static int pcicfg_destroy_phdl(dev_info_t *);
2307c478bd9Sstevel@tonic-gate static int pcicfg_sum_resources(dev_info_t *, void *);
2317c478bd9Sstevel@tonic-gate static int pcicfg_device_assign(dev_info_t *);
2327c478bd9Sstevel@tonic-gate static int pcicfg_bridge_assign(dev_info_t *, void *);
23326947304SEvan Yan static int pcicfg_device_assign_readonly(dev_info_t *);
23426947304SEvan Yan static int pcicfg_free_resources(dev_info_t *, pcicfg_flags_t);
2357c478bd9Sstevel@tonic-gate static void pcicfg_setup_bridge(pcicfg_phdl_t *, ddi_acc_handle_t);
2367c478bd9Sstevel@tonic-gate static void pcicfg_update_bridge(pcicfg_phdl_t *, ddi_acc_handle_t);
2377c478bd9Sstevel@tonic-gate static int pcicfg_update_assigned_prop(dev_info_t *, pci_regspec_t *);
2387c478bd9Sstevel@tonic-gate static void pcicfg_device_on(ddi_acc_handle_t);
2397c478bd9Sstevel@tonic-gate static void pcicfg_device_off(ddi_acc_handle_t);
24070025d76Sjohnny static int pcicfg_set_busnode_props(dev_info_t *, uint8_t);
2417c478bd9Sstevel@tonic-gate static int pcicfg_free_bridge_resources(dev_info_t *);
2427c478bd9Sstevel@tonic-gate static int pcicfg_free_device_resources(dev_info_t *);
243c0da6274SZhi-Jun Robin Fu static int pcicfg_teardown_device(dev_info_t *, pcicfg_flags_t, boolean_t);
2447c478bd9Sstevel@tonic-gate static void pcicfg_reparent_node(dev_info_t *, dev_info_t *);
2457c478bd9Sstevel@tonic-gate static int pcicfg_config_setup(dev_info_t *, ddi_acc_handle_t *);
2467c478bd9Sstevel@tonic-gate static void pcicfg_config_teardown(ddi_acc_handle_t *);
2477c478bd9Sstevel@tonic-gate static void pcicfg_get_mem(pcicfg_phdl_t *, uint32_t, uint64_t *);
248a6469d9bSprasad static void pcicfg_get_pf_mem(pcicfg_phdl_t *, uint32_t, uint64_t *);
2497c478bd9Sstevel@tonic-gate static void pcicfg_get_io(pcicfg_phdl_t *, uint32_t, uint32_t *);
25000d0963fSdilpreet static int pcicfg_update_ranges_prop(dev_info_t *, ppb_ranges_t *);
25170025d76Sjohnny static int pcicfg_configure_ntbridge(dev_info_t *, uint_t, uint_t);
2527c478bd9Sstevel@tonic-gate static uint_t pcicfg_ntbridge_child(dev_info_t *);
2537c478bd9Sstevel@tonic-gate static uint_t pcicfg_get_ntbridge_child_range(dev_info_t *, uint64_t *,
25426947304SEvan Yan uint64_t *, uint_t);
2557c478bd9Sstevel@tonic-gate static int pcicfg_is_ntbridge(dev_info_t *);
2567c478bd9Sstevel@tonic-gate static int pcicfg_ntbridge_allocate_resources(dev_info_t *);
2577c478bd9Sstevel@tonic-gate static int pcicfg_ntbridge_configure_done(dev_info_t *);
2587c478bd9Sstevel@tonic-gate static int pcicfg_ntbridge_program_child(dev_info_t *);
2597c478bd9Sstevel@tonic-gate static uint_t pcicfg_ntbridge_unconfigure(dev_info_t *);
2607c478bd9Sstevel@tonic-gate static int pcicfg_ntbridge_unconfigure_child(dev_info_t *, uint_t);
2617c478bd9Sstevel@tonic-gate static void pcicfg_free_hole(hole_t *);
2627c478bd9Sstevel@tonic-gate static uint64_t pcicfg_alloc_hole(hole_t *, uint64_t *, uint32_t);
26370025d76Sjohnny static int pcicfg_device_type(dev_info_t *, ddi_acc_handle_t *);
26470025d76Sjohnny static void pcicfg_update_phdl(dev_info_t *, uint8_t, uint8_t);
26570025d76Sjohnny static int pcicfg_get_cap(ddi_acc_handle_t, uint8_t);
26670025d76Sjohnny static uint8_t pcicfg_get_nslots(dev_info_t *, ddi_acc_handle_t);
26770025d76Sjohnny static int pcicfg_pcie_device_type(dev_info_t *, ddi_acc_handle_t);
26870025d76Sjohnny static int pcicfg_pcie_port_type(dev_info_t *, ddi_acc_handle_t);
26970025d76Sjohnny static int pcicfg_probe_bridge(dev_info_t *, ddi_acc_handle_t, uint_t,
270c0da6274SZhi-Jun Robin Fu uint_t *, boolean_t);
27170025d76Sjohnny static int pcicfg_find_resource_end(dev_info_t *, void *);
272c0da6274SZhi-Jun Robin Fu static boolean_t is_pcie_fabric(dev_info_t *);
2737c478bd9Sstevel@tonic-gate
27426947304SEvan Yan static int pcicfg_populate_reg_props(dev_info_t *, ddi_acc_handle_t);
27526947304SEvan Yan static int pcicfg_populate_props_from_bar(dev_info_t *, ddi_acc_handle_t);
27626947304SEvan Yan static int pcicfg_update_assigned_prop_value(dev_info_t *, uint32_t,
27726947304SEvan Yan uint32_t, uint32_t, uint_t);
27826947304SEvan Yan static int pcicfg_ari_configure(dev_info_t *);
27926947304SEvan Yan
2807c478bd9Sstevel@tonic-gate #ifdef DEBUG
2817c478bd9Sstevel@tonic-gate static void pcicfg_dump_common_config(ddi_acc_handle_t config_handle);
2827c478bd9Sstevel@tonic-gate static void pcicfg_dump_device_config(ddi_acc_handle_t);
2837c478bd9Sstevel@tonic-gate static void pcicfg_dump_bridge_config(ddi_acc_handle_t config_handle);
2847c478bd9Sstevel@tonic-gate static uint64_t pcicfg_unused_space(hole_t *, uint32_t *);
2857c478bd9Sstevel@tonic-gate
2867c478bd9Sstevel@tonic-gate #define PCICFG_DUMP_COMMON_CONFIG(hdl) (void)pcicfg_dump_common_config(hdl)
2877c478bd9Sstevel@tonic-gate #define PCICFG_DUMP_DEVICE_CONFIG(hdl) (void)pcicfg_dump_device_config(hdl)
2887c478bd9Sstevel@tonic-gate #define PCICFG_DUMP_BRIDGE_CONFIG(hdl) (void)pcicfg_dump_bridge_config(hdl)
2897c478bd9Sstevel@tonic-gate #else
2907c478bd9Sstevel@tonic-gate #define PCICFG_DUMP_COMMON_CONFIG(handle)
2917c478bd9Sstevel@tonic-gate #define PCICFG_DUMP_DEVICE_CONFIG(handle)
2927c478bd9Sstevel@tonic-gate #define PCICFG_DUMP_BRIDGE_CONFIG(handle)
2937c478bd9Sstevel@tonic-gate #endif
2947c478bd9Sstevel@tonic-gate
2957c478bd9Sstevel@tonic-gate static kmutex_t pcicfg_list_mutex; /* Protects the probe handle list */
2967c478bd9Sstevel@tonic-gate static pcicfg_phdl_t *pcicfg_phdl_list = NULL;
2977c478bd9Sstevel@tonic-gate
2987c478bd9Sstevel@tonic-gate #ifndef _DONT_USE_1275_GENERIC_NAMES
2997c478bd9Sstevel@tonic-gate /*
3007c478bd9Sstevel@tonic-gate * Class code table
3017c478bd9Sstevel@tonic-gate */
3027c478bd9Sstevel@tonic-gate static struct pcicfg_name_entry pcicfg_class_lookup [] = {
3037c478bd9Sstevel@tonic-gate
3047c478bd9Sstevel@tonic-gate { 0x001, "display" },
3057c478bd9Sstevel@tonic-gate { 0x100, "scsi" },
3067c478bd9Sstevel@tonic-gate { 0x101, "ide" },
3077c478bd9Sstevel@tonic-gate { 0x102, "fdc" },
3087c478bd9Sstevel@tonic-gate { 0x103, "ipi" },
3097c478bd9Sstevel@tonic-gate { 0x104, "raid" },
31070025d76Sjohnny { 0x105, "ata" },
31170025d76Sjohnny { 0x106, "sata" },
3127c478bd9Sstevel@tonic-gate { 0x200, "ethernet" },
3137c478bd9Sstevel@tonic-gate { 0x201, "token-ring" },
3147c478bd9Sstevel@tonic-gate { 0x202, "fddi" },
3157c478bd9Sstevel@tonic-gate { 0x203, "atm" },
31670025d76Sjohnny { 0x204, "isdn" },
31770025d76Sjohnny { 0x206, "mcd" },
3187c478bd9Sstevel@tonic-gate { 0x300, "display" },
3197c478bd9Sstevel@tonic-gate { 0x400, "video" },
3207c478bd9Sstevel@tonic-gate { 0x401, "sound" },
3217c478bd9Sstevel@tonic-gate { 0x500, "memory" },
3227c478bd9Sstevel@tonic-gate { 0x501, "flash" },
3237c478bd9Sstevel@tonic-gate { 0x600, "host" },
3247c478bd9Sstevel@tonic-gate { 0x601, "isa" },
3257c478bd9Sstevel@tonic-gate { 0x602, "eisa" },
3267c478bd9Sstevel@tonic-gate { 0x603, "mca" },
3277c478bd9Sstevel@tonic-gate { 0x604, "pci" },
3287c478bd9Sstevel@tonic-gate { 0x605, "pcmcia" },
3297c478bd9Sstevel@tonic-gate { 0x606, "nubus" },
3307c478bd9Sstevel@tonic-gate { 0x607, "cardbus" },
3317c478bd9Sstevel@tonic-gate { 0x609, "pci" },
33270025d76Sjohnny { 0x60a, "ib-pci" },
3337c478bd9Sstevel@tonic-gate { 0x700, "serial" },
3347c478bd9Sstevel@tonic-gate { 0x701, "parallel" },
3357c478bd9Sstevel@tonic-gate { 0x800, "interrupt-controller" },
3367c478bd9Sstevel@tonic-gate { 0x801, "dma-controller" },
3377c478bd9Sstevel@tonic-gate { 0x802, "timer" },
3387c478bd9Sstevel@tonic-gate { 0x803, "rtc" },
3397c478bd9Sstevel@tonic-gate { 0x900, "keyboard" },
3407c478bd9Sstevel@tonic-gate { 0x901, "pen" },
3417c478bd9Sstevel@tonic-gate { 0x902, "mouse" },
3427c478bd9Sstevel@tonic-gate { 0xa00, "dock" },
3437c478bd9Sstevel@tonic-gate { 0xb00, "cpu" },
34470025d76Sjohnny { 0xb01, "cpu" },
34570025d76Sjohnny { 0xb02, "cpu" },
34670025d76Sjohnny { 0xb10, "cpu" },
34770025d76Sjohnny { 0xb20, "cpu" },
34870025d76Sjohnny { 0xb30, "cpu" },
34970025d76Sjohnny { 0xb40, "coproc" },
3507c478bd9Sstevel@tonic-gate { 0xc00, "firewire" },
3517c478bd9Sstevel@tonic-gate { 0xc01, "access-bus" },
3527c478bd9Sstevel@tonic-gate { 0xc02, "ssa" },
3537c478bd9Sstevel@tonic-gate { 0xc03, "usb" },
3547c478bd9Sstevel@tonic-gate { 0xc04, "fibre-channel" },
35570025d76Sjohnny { 0xc05, "smbus" },
35670025d76Sjohnny { 0xc06, "ib" },
35770025d76Sjohnny { 0xd00, "irda" },
35870025d76Sjohnny { 0xd01, "ir" },
35970025d76Sjohnny { 0xd10, "rf" },
36070025d76Sjohnny { 0xd11, "btooth" },
36170025d76Sjohnny { 0xd12, "brdband" },
36270025d76Sjohnny { 0xd20, "802.11a" },
36370025d76Sjohnny { 0xd21, "802.11b" },
36470025d76Sjohnny { 0xe00, "i2o" },
36570025d76Sjohnny { 0xf01, "tv" },
36670025d76Sjohnny { 0xf02, "audio" },
36770025d76Sjohnny { 0xf03, "voice" },
36870025d76Sjohnny { 0xf04, "data" },
3697c478bd9Sstevel@tonic-gate { 0, 0 }
3707c478bd9Sstevel@tonic-gate };
3717c478bd9Sstevel@tonic-gate #endif /* _DONT_USE_1275_GENERIC_NAMES */
3727c478bd9Sstevel@tonic-gate
3737c478bd9Sstevel@tonic-gate /*
3747c478bd9Sstevel@tonic-gate * Module control operations
3757c478bd9Sstevel@tonic-gate */
3767c478bd9Sstevel@tonic-gate
3777c478bd9Sstevel@tonic-gate extern struct mod_ops mod_miscops;
3787c478bd9Sstevel@tonic-gate
3797c478bd9Sstevel@tonic-gate static struct modlmisc modlmisc = {
3807c478bd9Sstevel@tonic-gate &mod_miscops, /* Type of module */
381613b2871SRichard Bean "PCI configurator"
3827c478bd9Sstevel@tonic-gate };
3837c478bd9Sstevel@tonic-gate
3847c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
3857c478bd9Sstevel@tonic-gate MODREV_1, (void *)&modlmisc, NULL
3867c478bd9Sstevel@tonic-gate };
3877c478bd9Sstevel@tonic-gate
3887c478bd9Sstevel@tonic-gate
3897c478bd9Sstevel@tonic-gate #ifdef DEBUG
3907c478bd9Sstevel@tonic-gate
3917c478bd9Sstevel@tonic-gate static void
pcicfg_dump_common_config(ddi_acc_handle_t config_handle)3927c478bd9Sstevel@tonic-gate pcicfg_dump_common_config(ddi_acc_handle_t config_handle)
3937c478bd9Sstevel@tonic-gate {
3947c478bd9Sstevel@tonic-gate if ((pcicfg_debug & 1) == 0)
3957c478bd9Sstevel@tonic-gate return;
3967c478bd9Sstevel@tonic-gate prom_printf(" Vendor ID = [0x%x]\n",
39726947304SEvan Yan pci_config_get16(config_handle, PCI_CONF_VENID));
3987c478bd9Sstevel@tonic-gate prom_printf(" Device ID = [0x%x]\n",
39926947304SEvan Yan pci_config_get16(config_handle, PCI_CONF_DEVID));
4007c478bd9Sstevel@tonic-gate prom_printf(" Command REG = [0x%x]\n",
40126947304SEvan Yan pci_config_get16(config_handle, PCI_CONF_COMM));
4027c478bd9Sstevel@tonic-gate prom_printf(" Status REG = [0x%x]\n",
40326947304SEvan Yan pci_config_get16(config_handle, PCI_CONF_STAT));
4047c478bd9Sstevel@tonic-gate prom_printf(" Revision ID = [0x%x]\n",
40526947304SEvan Yan pci_config_get8(config_handle, PCI_CONF_REVID));
4067c478bd9Sstevel@tonic-gate prom_printf(" Prog Class = [0x%x]\n",
40726947304SEvan Yan pci_config_get8(config_handle, PCI_CONF_PROGCLASS));
4087c478bd9Sstevel@tonic-gate prom_printf(" Dev Class = [0x%x]\n",
40926947304SEvan Yan pci_config_get8(config_handle, PCI_CONF_SUBCLASS));
4107c478bd9Sstevel@tonic-gate prom_printf(" Base Class = [0x%x]\n",
41126947304SEvan Yan pci_config_get8(config_handle, PCI_CONF_BASCLASS));
4127c478bd9Sstevel@tonic-gate prom_printf(" Device ID = [0x%x]\n",
41326947304SEvan Yan pci_config_get8(config_handle, PCI_CONF_CACHE_LINESZ));
4147c478bd9Sstevel@tonic-gate prom_printf(" Header Type = [0x%x]\n",
41526947304SEvan Yan pci_config_get8(config_handle, PCI_CONF_HEADER));
4167c478bd9Sstevel@tonic-gate prom_printf(" BIST = [0x%x]\n",
41726947304SEvan Yan pci_config_get8(config_handle, PCI_CONF_BIST));
4187c478bd9Sstevel@tonic-gate prom_printf(" BASE 0 = [0x%x]\n",
41926947304SEvan Yan pci_config_get32(config_handle, PCI_CONF_BASE0));
4207c478bd9Sstevel@tonic-gate prom_printf(" BASE 1 = [0x%x]\n",
42126947304SEvan Yan pci_config_get32(config_handle, PCI_CONF_BASE1));
4227c478bd9Sstevel@tonic-gate
4237c478bd9Sstevel@tonic-gate }
4247c478bd9Sstevel@tonic-gate
4257c478bd9Sstevel@tonic-gate static void
pcicfg_dump_device_config(ddi_acc_handle_t config_handle)4267c478bd9Sstevel@tonic-gate pcicfg_dump_device_config(ddi_acc_handle_t config_handle)
4277c478bd9Sstevel@tonic-gate {
4287c478bd9Sstevel@tonic-gate if ((pcicfg_debug & 1) == 0)
4297c478bd9Sstevel@tonic-gate return;
4307c478bd9Sstevel@tonic-gate pcicfg_dump_common_config(config_handle);
4317c478bd9Sstevel@tonic-gate
4327c478bd9Sstevel@tonic-gate prom_printf(" BASE 2 = [0x%x]\n",
43326947304SEvan Yan pci_config_get32(config_handle, PCI_CONF_BASE2));
4347c478bd9Sstevel@tonic-gate prom_printf(" BASE 3 = [0x%x]\n",
43526947304SEvan Yan pci_config_get32(config_handle, PCI_CONF_BASE3));
4367c478bd9Sstevel@tonic-gate prom_printf(" BASE 4 = [0x%x]\n",
43726947304SEvan Yan pci_config_get32(config_handle, PCI_CONF_BASE4));
4387c478bd9Sstevel@tonic-gate prom_printf(" BASE 5 = [0x%x]\n",
43926947304SEvan Yan pci_config_get32(config_handle, PCI_CONF_BASE5));
4407c478bd9Sstevel@tonic-gate prom_printf(" Cardbus CIS = [0x%x]\n",
44126947304SEvan Yan pci_config_get32(config_handle, PCI_CONF_CIS));
4427c478bd9Sstevel@tonic-gate prom_printf(" Sub VID = [0x%x]\n",
44326947304SEvan Yan pci_config_get16(config_handle, PCI_CONF_SUBVENID));
4447c478bd9Sstevel@tonic-gate prom_printf(" Sub SID = [0x%x]\n",
44526947304SEvan Yan pci_config_get16(config_handle, PCI_CONF_SUBSYSID));
4467c478bd9Sstevel@tonic-gate prom_printf(" ROM = [0x%x]\n",
44726947304SEvan Yan pci_config_get32(config_handle, PCI_CONF_ROM));
4487c478bd9Sstevel@tonic-gate prom_printf(" I Line = [0x%x]\n",
44926947304SEvan Yan pci_config_get8(config_handle, PCI_CONF_ILINE));
4507c478bd9Sstevel@tonic-gate prom_printf(" I Pin = [0x%x]\n",
45126947304SEvan Yan pci_config_get8(config_handle, PCI_CONF_IPIN));
4527c478bd9Sstevel@tonic-gate prom_printf(" Max Grant = [0x%x]\n",
45326947304SEvan Yan pci_config_get8(config_handle, PCI_CONF_MIN_G));
4547c478bd9Sstevel@tonic-gate prom_printf(" Max Latent = [0x%x]\n",
45526947304SEvan Yan pci_config_get8(config_handle, PCI_CONF_MAX_L));
4567c478bd9Sstevel@tonic-gate }
4577c478bd9Sstevel@tonic-gate
4587c478bd9Sstevel@tonic-gate static void
pcicfg_dump_bridge_config(ddi_acc_handle_t config_handle)4597c478bd9Sstevel@tonic-gate pcicfg_dump_bridge_config(ddi_acc_handle_t config_handle)
4607c478bd9Sstevel@tonic-gate {
4617c478bd9Sstevel@tonic-gate if ((pcicfg_debug & 1) == 0)
4627c478bd9Sstevel@tonic-gate return;
4637c478bd9Sstevel@tonic-gate pcicfg_dump_common_config(config_handle);
4647c478bd9Sstevel@tonic-gate
4657c478bd9Sstevel@tonic-gate prom_printf("........................................\n");
4667c478bd9Sstevel@tonic-gate
4677c478bd9Sstevel@tonic-gate prom_printf(" Pri Bus = [0x%x]\n",
46826947304SEvan Yan pci_config_get8(config_handle, PCI_BCNF_PRIBUS));
4697c478bd9Sstevel@tonic-gate prom_printf(" Sec Bus = [0x%x]\n",
47026947304SEvan Yan pci_config_get8(config_handle, PCI_BCNF_SECBUS));
4717c478bd9Sstevel@tonic-gate prom_printf(" Sub Bus = [0x%x]\n",
47226947304SEvan Yan pci_config_get8(config_handle, PCI_BCNF_SUBBUS));
4737c478bd9Sstevel@tonic-gate prom_printf(" Latency = [0x%x]\n",
47426947304SEvan Yan pci_config_get8(config_handle, PCI_BCNF_LATENCY_TIMER));
4757c478bd9Sstevel@tonic-gate prom_printf(" I/O Base LO = [0x%x]\n",
47626947304SEvan Yan pci_config_get8(config_handle, PCI_BCNF_IO_BASE_LOW));
4777c478bd9Sstevel@tonic-gate prom_printf(" I/O Lim LO = [0x%x]\n",
47826947304SEvan Yan pci_config_get8(config_handle, PCI_BCNF_IO_LIMIT_LOW));
4797c478bd9Sstevel@tonic-gate prom_printf(" Sec. Status = [0x%x]\n",
48026947304SEvan Yan pci_config_get16(config_handle, PCI_BCNF_SEC_STATUS));
4817c478bd9Sstevel@tonic-gate prom_printf(" Mem Base = [0x%x]\n",
48226947304SEvan Yan pci_config_get16(config_handle, PCI_BCNF_MEM_BASE));
4837c478bd9Sstevel@tonic-gate prom_printf(" Mem Limit = [0x%x]\n",
48426947304SEvan Yan pci_config_get16(config_handle, PCI_BCNF_MEM_LIMIT));
4857c478bd9Sstevel@tonic-gate prom_printf(" PF Mem Base = [0x%x]\n",
48626947304SEvan Yan pci_config_get16(config_handle, PCI_BCNF_PF_BASE_LOW));
4877c478bd9Sstevel@tonic-gate prom_printf(" PF Mem Lim = [0x%x]\n",
48826947304SEvan Yan pci_config_get16(config_handle, PCI_BCNF_PF_LIMIT_LOW));
4897c478bd9Sstevel@tonic-gate prom_printf(" PF Base HI = [0x%x]\n",
49026947304SEvan Yan pci_config_get32(config_handle, PCI_BCNF_PF_BASE_HIGH));
4917c478bd9Sstevel@tonic-gate prom_printf(" PF Lim HI = [0x%x]\n",
49226947304SEvan Yan pci_config_get32(config_handle, PCI_BCNF_PF_LIMIT_HIGH));
4937c478bd9Sstevel@tonic-gate prom_printf(" I/O Base HI = [0x%x]\n",
49426947304SEvan Yan pci_config_get16(config_handle, PCI_BCNF_IO_BASE_HI));
4957c478bd9Sstevel@tonic-gate prom_printf(" I/O Lim HI = [0x%x]\n",
49626947304SEvan Yan pci_config_get16(config_handle, PCI_BCNF_IO_LIMIT_HI));
4977c478bd9Sstevel@tonic-gate prom_printf(" ROM addr = [0x%x]\n",
49826947304SEvan Yan pci_config_get32(config_handle, PCI_BCNF_ROM));
4997c478bd9Sstevel@tonic-gate prom_printf(" Intr Line = [0x%x]\n",
50026947304SEvan Yan pci_config_get8(config_handle, PCI_BCNF_ILINE));
5017c478bd9Sstevel@tonic-gate prom_printf(" Intr Pin = [0x%x]\n",
50226947304SEvan Yan pci_config_get8(config_handle, PCI_BCNF_IPIN));
5037c478bd9Sstevel@tonic-gate prom_printf(" Bridge Ctrl = [0x%x]\n",
50426947304SEvan Yan pci_config_get16(config_handle, PCI_BCNF_BCNTRL));
5057c478bd9Sstevel@tonic-gate }
5067c478bd9Sstevel@tonic-gate #endif
5077c478bd9Sstevel@tonic-gate
5087c478bd9Sstevel@tonic-gate int
_init()5097c478bd9Sstevel@tonic-gate _init()
5107c478bd9Sstevel@tonic-gate {
5117c478bd9Sstevel@tonic-gate DEBUG0(" PCI configurator installed\n");
5127c478bd9Sstevel@tonic-gate mutex_init(&pcicfg_list_mutex, NULL, MUTEX_DRIVER, NULL);
5137c478bd9Sstevel@tonic-gate return (mod_install(&modlinkage));
5147c478bd9Sstevel@tonic-gate }
5157c478bd9Sstevel@tonic-gate
5167c478bd9Sstevel@tonic-gate int
_fini(void)5177c478bd9Sstevel@tonic-gate _fini(void)
5187c478bd9Sstevel@tonic-gate {
5197c478bd9Sstevel@tonic-gate int error;
5207c478bd9Sstevel@tonic-gate
5217c478bd9Sstevel@tonic-gate error = mod_remove(&modlinkage);
5227c478bd9Sstevel@tonic-gate if (error != 0) {
5237c478bd9Sstevel@tonic-gate return (error);
5247c478bd9Sstevel@tonic-gate }
5257c478bd9Sstevel@tonic-gate mutex_destroy(&pcicfg_list_mutex);
5267c478bd9Sstevel@tonic-gate return (0);
5277c478bd9Sstevel@tonic-gate }
5287c478bd9Sstevel@tonic-gate
5297c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)5307c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
5317c478bd9Sstevel@tonic-gate {
5327c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop));
5337c478bd9Sstevel@tonic-gate }
5347c478bd9Sstevel@tonic-gate
5357c478bd9Sstevel@tonic-gate /*
5367c478bd9Sstevel@tonic-gate * In the following functions ndi_devi_enter() without holding the
5377c478bd9Sstevel@tonic-gate * parent dip is sufficient. This is because pci dr is driven through
5387c478bd9Sstevel@tonic-gate * opens on the nexus which is in the device tree path above the node
5397c478bd9Sstevel@tonic-gate * being operated on, and implicitly held due to the open.
5407c478bd9Sstevel@tonic-gate */
5417c478bd9Sstevel@tonic-gate
5427c478bd9Sstevel@tonic-gate /*
5437c478bd9Sstevel@tonic-gate * This entry point is called to configure a device (and
5447c478bd9Sstevel@tonic-gate * all its children) on the given bus. It is called when
5457c478bd9Sstevel@tonic-gate * a new device is added to the PCI domain. This routine
5467c478bd9Sstevel@tonic-gate * will create the device tree and program the devices
5477c478bd9Sstevel@tonic-gate * registers.
5487c478bd9Sstevel@tonic-gate */
5497c478bd9Sstevel@tonic-gate int
pcicfg_configure(dev_info_t * devi,uint_t device,uint_t function,pcicfg_flags_t flags)55026947304SEvan Yan pcicfg_configure(dev_info_t *devi, uint_t device, uint_t function,
55126947304SEvan Yan pcicfg_flags_t flags)
5527c478bd9Sstevel@tonic-gate {
5537c478bd9Sstevel@tonic-gate uint_t bus;
5547c478bd9Sstevel@tonic-gate int len;
5557c478bd9Sstevel@tonic-gate int func;
5567c478bd9Sstevel@tonic-gate dev_info_t *attach_point;
55700d0963fSdilpreet pci_bus_range_t pci_bus_range;
5587c478bd9Sstevel@tonic-gate int rv;
5595c734816SRobert Mustacchi uint_t highest_bus, visited = 0;
56026947304SEvan Yan int ari_mode = B_FALSE;
56126947304SEvan Yan int max_function = PCI_MAX_FUNCTIONS;
56226947304SEvan Yan int trans_device;
56326947304SEvan Yan dev_info_t *new_device;
564c0da6274SZhi-Jun Robin Fu boolean_t is_pcie;
56526947304SEvan Yan
56626947304SEvan Yan if (flags == PCICFG_FLAG_ENABLE_ARI)
56726947304SEvan Yan return (pcicfg_ari_configure(devi));
5687c478bd9Sstevel@tonic-gate
5697c478bd9Sstevel@tonic-gate /*
5707c478bd9Sstevel@tonic-gate * Start probing at the device specified in "device" on the
5717c478bd9Sstevel@tonic-gate * "bus" specified.
5727c478bd9Sstevel@tonic-gate */
57300d0963fSdilpreet len = sizeof (pci_bus_range_t);
574a3282898Scth if (ddi_getlongprop_buf(DDI_DEV_T_ANY, devi, 0, "bus-range",
5757c478bd9Sstevel@tonic-gate (caddr_t)&pci_bus_range, &len) != DDI_SUCCESS) {
5767c478bd9Sstevel@tonic-gate DEBUG0("no bus-range property\n");
5777c478bd9Sstevel@tonic-gate return (PCICFG_FAILURE);
5787c478bd9Sstevel@tonic-gate }
5797c478bd9Sstevel@tonic-gate
5807c478bd9Sstevel@tonic-gate bus = pci_bus_range.lo; /* primary bus number of this bus node */
5817c478bd9Sstevel@tonic-gate
58270025d76Sjohnny attach_point = devi;
5837c478bd9Sstevel@tonic-gate
584c0da6274SZhi-Jun Robin Fu is_pcie = is_pcie_fabric(devi);
585c0da6274SZhi-Jun Robin Fu
586b31f5cf7SDan Cross /*
587b31f5cf7SDan Cross * This code may be racing against other code walking the device info
588b31f5cf7SDan Cross * tree, such as `di_copytree` et al. To avoid deadlock, we must ensure
589b31f5cf7SDan Cross * a strict hierarchical ordering of `ndi_devi_enter` calls that mirrors
590b31f5cf7SDan Cross * the structure of the tree, working from the root towards leaves.
591b31f5cf7SDan Cross * `pcie_fabric_setup`, if called, will call `ddi_walk_devs` which
592b31f5cf7SDan Cross * requires that the parent is locked; therefore, to obey the lock
593b31f5cf7SDan Cross * ordering, we must lock the parent here.
594b31f5cf7SDan Cross */
5953fe80ca4SDan Cross ndi_devi_enter(ddi_get_parent(devi));
5963fe80ca4SDan Cross ndi_devi_enter(devi);
59726947304SEvan Yan for (func = 0; func < max_function; ) {
5987c478bd9Sstevel@tonic-gate
59926947304SEvan Yan if ((function != PCICFG_ALL_FUNC) && (function != func))
60026947304SEvan Yan goto next;
60126947304SEvan Yan
60226947304SEvan Yan if (ari_mode)
60326947304SEvan Yan trans_device = func >> 3;
60426947304SEvan Yan else
60526947304SEvan Yan trans_device = device;
6067c478bd9Sstevel@tonic-gate
6077c478bd9Sstevel@tonic-gate switch (rv = pcicfg_probe_children(attach_point,
608c0da6274SZhi-Jun Robin Fu bus, trans_device, func & 7, &highest_bus,
609c0da6274SZhi-Jun Robin Fu flags, is_pcie)) {
6105af4ae46Sjveta case PCICFG_NORESRC:
6117c478bd9Sstevel@tonic-gate case PCICFG_FAILURE:
61226947304SEvan Yan DEBUG2("configure failed: bus [0x%x] device "
61326947304SEvan Yan "[0x%x]\n", bus, trans_device);
6147c478bd9Sstevel@tonic-gate goto cleanup;
6157c478bd9Sstevel@tonic-gate case PCICFG_NODEVICE:
6167c478bd9Sstevel@tonic-gate DEBUG3("no device : bus "
61726947304SEvan Yan "[0x%x] slot [0x%x] func [0x%x]\n",
61826947304SEvan Yan bus, trans_device, func &7);
61926947304SEvan Yan
6207f59ab1cSAlan Adamson, SD OSSD /*
6217f59ab1cSAlan Adamson, SD OSSD * When walking the list of ARI functions
6227f59ab1cSAlan Adamson, SD OSSD * we don't expect to see a non-present
6237f59ab1cSAlan Adamson, SD OSSD * function, so we will stop walking
6247f59ab1cSAlan Adamson, SD OSSD * the function list.
6257f59ab1cSAlan Adamson, SD OSSD */
6267f59ab1cSAlan Adamson, SD OSSD if (ari_mode == B_TRUE)
6277f59ab1cSAlan Adamson, SD OSSD break;
6287f59ab1cSAlan Adamson, SD OSSD
62926947304SEvan Yan if (func)
63026947304SEvan Yan goto next;
63126947304SEvan Yan break;
6327c478bd9Sstevel@tonic-gate default:
6337c478bd9Sstevel@tonic-gate DEBUG3("configure: bus => [%d] "
63426947304SEvan Yan "slot => [%d] func => [%d]\n",
63526947304SEvan Yan bus, trans_device, func & 7);
6367c478bd9Sstevel@tonic-gate break;
6377c478bd9Sstevel@tonic-gate }
6387c478bd9Sstevel@tonic-gate
6397c478bd9Sstevel@tonic-gate if (rv != PCICFG_SUCCESS)
6407c478bd9Sstevel@tonic-gate break;
6417c478bd9Sstevel@tonic-gate
6427c478bd9Sstevel@tonic-gate if ((new_device = pcicfg_devi_find(attach_point,
64326947304SEvan Yan trans_device, func & 7)) == NULL) {
6447c478bd9Sstevel@tonic-gate DEBUG0("Did'nt find device node just created\n");
6457c478bd9Sstevel@tonic-gate goto cleanup;
6467c478bd9Sstevel@tonic-gate }
6477c478bd9Sstevel@tonic-gate
6487c478bd9Sstevel@tonic-gate /*
6497c478bd9Sstevel@tonic-gate * Up until now, we have detected a non transparent bridge
6507c478bd9Sstevel@tonic-gate * (ntbridge) as a part of the generic probe code and
6517c478bd9Sstevel@tonic-gate * configured only one configuration
6527c478bd9Sstevel@tonic-gate * header which is the side facing the host bus.
6537c478bd9Sstevel@tonic-gate * Now, configure the other side and create children.
6547c478bd9Sstevel@tonic-gate *
6557c478bd9Sstevel@tonic-gate * In order to make the process simpler, lets load the device
6567c478bd9Sstevel@tonic-gate * driver for the non transparent bridge as this is a
6577c478bd9Sstevel@tonic-gate * Solaris bundled driver, and use its configuration map
6587c478bd9Sstevel@tonic-gate * services rather than programming it here.
6597c478bd9Sstevel@tonic-gate * If the driver is not bundled into Solaris, it must be
6607c478bd9Sstevel@tonic-gate * first loaded and configured before performing any
6617c478bd9Sstevel@tonic-gate * hotplug operations.
6627c478bd9Sstevel@tonic-gate *
6637c478bd9Sstevel@tonic-gate * This not only makes the code here simpler but also more
6647c478bd9Sstevel@tonic-gate * generic.
6657c478bd9Sstevel@tonic-gate *
6667c478bd9Sstevel@tonic-gate * So here we go.
6677c478bd9Sstevel@tonic-gate */
6687c478bd9Sstevel@tonic-gate
6697c478bd9Sstevel@tonic-gate /*
6707c478bd9Sstevel@tonic-gate * check if this is a bridge in nontransparent mode
6717c478bd9Sstevel@tonic-gate */
6727c478bd9Sstevel@tonic-gate if (pcicfg_is_ntbridge(new_device) != DDI_FAILURE) {
6737c478bd9Sstevel@tonic-gate DEBUG0("pcicfg: Found nontransparent bridge.\n");
6747c478bd9Sstevel@tonic-gate
67526947304SEvan Yan rv = pcicfg_configure_ntbridge(new_device, bus,
67626947304SEvan Yan trans_device);
6775af4ae46Sjveta if (rv != PCICFG_SUCCESS)
6787c478bd9Sstevel@tonic-gate goto cleanup;
6797c478bd9Sstevel@tonic-gate }
68026947304SEvan Yan
6815c734816SRobert Mustacchi /*
6825c734816SRobert Mustacchi * Note that we've successfully gone through and visited at
6835c734816SRobert Mustacchi * least one node.
6845c734816SRobert Mustacchi */
6855c734816SRobert Mustacchi visited++;
68626947304SEvan Yan next:
68726947304SEvan Yan /*
68826947304SEvan Yan * Determine if ARI Forwarding should be enabled.
68926947304SEvan Yan */
69026947304SEvan Yan if (func == 0) {
69126947304SEvan Yan if ((pcie_ari_supported(devi)
69226947304SEvan Yan == PCIE_ARI_FORW_SUPPORTED) &&
69326947304SEvan Yan (pcie_ari_device(new_device) == PCIE_ARI_DEVICE)) {
69426947304SEvan Yan if (pcie_ari_enable(devi) == DDI_SUCCESS) {
69526947304SEvan Yan (void) ddi_prop_create(DDI_DEV_T_NONE,
69626947304SEvan Yan devi, DDI_PROP_CANSLEEP,
69726947304SEvan Yan "ari-enabled", NULL, 0);
69826947304SEvan Yan
69926947304SEvan Yan ari_mode = B_TRUE;
70026947304SEvan Yan max_function = PCICFG_MAX_ARI_FUNCTION;
70126947304SEvan Yan }
70226947304SEvan Yan }
70326947304SEvan Yan }
70426947304SEvan Yan if (ari_mode == B_TRUE) {
70526947304SEvan Yan int next_function;
70626947304SEvan Yan
70726947304SEvan Yan DEBUG0("Next Function - ARI Device\n");
70826947304SEvan Yan if (pcie_ari_get_next_function(new_device,
70926947304SEvan Yan &next_function) != DDI_SUCCESS)
71026947304SEvan Yan goto cleanup;
71126947304SEvan Yan
71226947304SEvan Yan /*
7135c734816SRobert Mustacchi * Check if there are more functions to probe.
71426947304SEvan Yan */
71526947304SEvan Yan if (next_function == 0) {
71626947304SEvan Yan DEBUG0("Next Function - "
71726947304SEvan Yan "No more ARI Functions\n");
71826947304SEvan Yan break;
71926947304SEvan Yan }
72026947304SEvan Yan func = next_function;
72126947304SEvan Yan } else {
72226947304SEvan Yan func++;
72326947304SEvan Yan }
72426947304SEvan Yan DEBUG1("Next Function - %x\n", func);
7257c478bd9Sstevel@tonic-gate }
7267c478bd9Sstevel@tonic-gate
7275b2c4190SRobert Mustacchi /*
7285b2c4190SRobert Mustacchi * At this point we have set up the various dev_info nodes that we
7295b2c4190SRobert Mustacchi * expect to see in the tree and we must re-evaluate the general fabric
7305b2c4190SRobert Mustacchi * settings such as the overall max payload size or the tagging that is
7315b2c4190SRobert Mustacchi * enabled. However, as part the big theory statement in pcie.c, this
7325b2c4190SRobert Mustacchi * can only be performed on a root port; however, that determination
7335b2c4190SRobert Mustacchi * will be made by the fabric scanning logic.
7345b2c4190SRobert Mustacchi */
7355b2c4190SRobert Mustacchi if (visited > 0 && is_pcie) {
7365b2c4190SRobert Mustacchi pcie_fabric_setup(devi);
7375b2c4190SRobert Mustacchi }
7385b2c4190SRobert Mustacchi
7393fe80ca4SDan Cross ndi_devi_exit(devi);
7403fe80ca4SDan Cross ndi_devi_exit(ddi_get_parent(devi));
7417c478bd9Sstevel@tonic-gate
7425c734816SRobert Mustacchi if (visited == 0)
7437c478bd9Sstevel@tonic-gate return (PCICFG_FAILURE); /* probe failed */
7447c478bd9Sstevel@tonic-gate else
7457c478bd9Sstevel@tonic-gate return (PCICFG_SUCCESS);
7467c478bd9Sstevel@tonic-gate
7477c478bd9Sstevel@tonic-gate cleanup:
7487c478bd9Sstevel@tonic-gate /*
7497c478bd9Sstevel@tonic-gate * Clean up a partially created "probe state" tree.
7507c478bd9Sstevel@tonic-gate * There are no resources allocated to the in the
7517c478bd9Sstevel@tonic-gate * probe state.
7527c478bd9Sstevel@tonic-gate */
7537c478bd9Sstevel@tonic-gate
75423c35297Sanish for (func = 0; func < PCI_MAX_FUNCTIONS; func++) {
75526947304SEvan Yan if ((function != PCICFG_ALL_FUNC) && (function != func))
75626947304SEvan Yan continue;
75726947304SEvan Yan
75826947304SEvan Yan if ((new_device = pcicfg_devi_find(devi, device, func))
75926947304SEvan Yan == NULL) {
76070025d76Sjohnny continue;
7617c478bd9Sstevel@tonic-gate }
7627c478bd9Sstevel@tonic-gate
7637c478bd9Sstevel@tonic-gate DEBUG2("Cleaning up device [0x%x] function [0x%x]\n",
76426947304SEvan Yan device, func);
7657c478bd9Sstevel@tonic-gate /*
7667c478bd9Sstevel@tonic-gate * If this was a bridge device it will have a
7677c478bd9Sstevel@tonic-gate * probe handle - if not, no harm in calling this.
7687c478bd9Sstevel@tonic-gate */
7697c478bd9Sstevel@tonic-gate (void) pcicfg_destroy_phdl(new_device);
770c0da6274SZhi-Jun Robin Fu if (is_pcie) {
771c0da6274SZhi-Jun Robin Fu /*
772c0da6274SZhi-Jun Robin Fu * free pcie_bus_t for the sub-tree
773c0da6274SZhi-Jun Robin Fu */
774c0da6274SZhi-Jun Robin Fu if (ddi_get_child(new_device) != NULL)
775c0da6274SZhi-Jun Robin Fu pcie_fab_fini_bus(new_device, PCIE_BUS_ALL);
776c0da6274SZhi-Jun Robin Fu
777c0da6274SZhi-Jun Robin Fu pcie_fini_bus(new_device, PCIE_BUS_ALL);
778c0da6274SZhi-Jun Robin Fu }
7797c478bd9Sstevel@tonic-gate /*
7807c478bd9Sstevel@tonic-gate * This will free up the node
7817c478bd9Sstevel@tonic-gate */
7827c478bd9Sstevel@tonic-gate (void) ndi_devi_offline(new_device, NDI_DEVI_REMOVE);
7837c478bd9Sstevel@tonic-gate }
7843fe80ca4SDan Cross ndi_devi_exit(devi);
7853fe80ca4SDan Cross ndi_devi_exit(ddi_get_parent(devi));
7867c478bd9Sstevel@tonic-gate
7875af4ae46Sjveta /*
7885af4ae46Sjveta * Use private return codes to help identify issues without debugging
7895af4ae46Sjveta * enabled. Resource limitations and mis-configurations are
7905af4ae46Sjveta * probably the most likely caue of configuration failures on x86.
7915af4ae46Sjveta * Convert return code back to values expected by the external
7925af4ae46Sjveta * consumer before returning so we will warn only once on the first
7935af4ae46Sjveta * encountered failure.
7945af4ae46Sjveta */
7955af4ae46Sjveta if (rv == PCICFG_NORESRC) {
7965af4ae46Sjveta char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
7975af4ae46Sjveta
7985af4ae46Sjveta (void) ddi_pathname(devi, path);
7995af4ae46Sjveta cmn_err(CE_CONT, "?Not enough PCI resources to "
8005af4ae46Sjveta "configure: %s\n", path);
8015af4ae46Sjveta
8025af4ae46Sjveta kmem_free(path, MAXPATHLEN);
8035af4ae46Sjveta rv = PCICFG_FAILURE;
8045af4ae46Sjveta }
8055af4ae46Sjveta
8065af4ae46Sjveta return (rv);
8077c478bd9Sstevel@tonic-gate }
8087c478bd9Sstevel@tonic-gate
8097c478bd9Sstevel@tonic-gate /*
8107c478bd9Sstevel@tonic-gate * configure the child nodes of ntbridge. new_device points to ntbridge itself
8117c478bd9Sstevel@tonic-gate */
8127c478bd9Sstevel@tonic-gate /*ARGSUSED*/
81370025d76Sjohnny static int
pcicfg_configure_ntbridge(dev_info_t * new_device,uint_t bus,uint_t device)8147c478bd9Sstevel@tonic-gate pcicfg_configure_ntbridge(dev_info_t *new_device, uint_t bus, uint_t device)
8157c478bd9Sstevel@tonic-gate {
8167c478bd9Sstevel@tonic-gate int bus_range[2], rc = PCICFG_FAILURE, rc1, max_devs = 0;
8177c478bd9Sstevel@tonic-gate int devno;
8187c478bd9Sstevel@tonic-gate dev_info_t *new_ntbridgechild;
8197c478bd9Sstevel@tonic-gate ddi_acc_handle_t config_handle;
8207c478bd9Sstevel@tonic-gate uint16_t vid;
8217c478bd9Sstevel@tonic-gate uint64_t next_bus;
8227c478bd9Sstevel@tonic-gate uint64_t blen;
8237c478bd9Sstevel@tonic-gate ndi_ra_request_t req;
82470025d76Sjohnny uint8_t pcie_device_type = 0;
8257c478bd9Sstevel@tonic-gate
8267c478bd9Sstevel@tonic-gate /*
8277c478bd9Sstevel@tonic-gate * If we need to do indirect config, lets create a property here
8287c478bd9Sstevel@tonic-gate * to let the child conf map routine know that it has to
8297c478bd9Sstevel@tonic-gate * go through the DDI calls, and not assume the devices are
8307c478bd9Sstevel@tonic-gate * mapped directly under the host.
8317c478bd9Sstevel@tonic-gate */
8327c478bd9Sstevel@tonic-gate if ((rc = ndi_prop_update_int(DDI_DEV_T_NONE, new_device,
83326947304SEvan Yan PCI_DEV_CONF_MAP_PROP, (int)DDI_SUCCESS)) != DDI_SUCCESS) {
8347c478bd9Sstevel@tonic-gate DEBUG0("Cannot create indirect conf map property.\n");
8357c478bd9Sstevel@tonic-gate return ((int)PCICFG_FAILURE);
8367c478bd9Sstevel@tonic-gate }
8377c478bd9Sstevel@tonic-gate
83870025d76Sjohnny if (pci_config_setup(new_device, &config_handle) != DDI_SUCCESS)
83970025d76Sjohnny return (PCICFG_FAILURE);
84070025d76Sjohnny /* check if we are PCIe device */
84170025d76Sjohnny if (pcicfg_pcie_device_type(new_device, config_handle) == DDI_SUCCESS) {
84270025d76Sjohnny DEBUG0("PCIe device detected\n");
84370025d76Sjohnny pcie_device_type = 1;
84470025d76Sjohnny }
84570025d76Sjohnny pci_config_teardown(&config_handle);
8467c478bd9Sstevel@tonic-gate /* create Bus node properties for ntbridge. */
84770025d76Sjohnny if (pcicfg_set_busnode_props(new_device, pcie_device_type)
84826947304SEvan Yan != PCICFG_SUCCESS) {
8497c478bd9Sstevel@tonic-gate DEBUG0("Failed to set busnode props\n");
8507c478bd9Sstevel@tonic-gate return (rc);
8517c478bd9Sstevel@tonic-gate }
8527c478bd9Sstevel@tonic-gate
8537c478bd9Sstevel@tonic-gate /* For now: Lets only support one layer of child */
8547c478bd9Sstevel@tonic-gate bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
8557c478bd9Sstevel@tonic-gate req.ra_len = 1;
85626947304SEvan Yan if (ndi_ra_alloc(ddi_get_parent(new_device), &req, &next_bus, &blen,
85726947304SEvan Yan NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS) != NDI_SUCCESS) {
8587c478bd9Sstevel@tonic-gate DEBUG0("ntbridge: Failed to get a bus number\n");
8595af4ae46Sjveta return (PCICFG_NORESRC);
8607c478bd9Sstevel@tonic-gate }
8617c478bd9Sstevel@tonic-gate
8627c478bd9Sstevel@tonic-gate DEBUG1("ntbridge bus range start ->[%d]\n", next_bus);
8637c478bd9Sstevel@tonic-gate
8647c478bd9Sstevel@tonic-gate /*
8657c478bd9Sstevel@tonic-gate * Following will change, as we detect more bridges
8667c478bd9Sstevel@tonic-gate * on the way.
8677c478bd9Sstevel@tonic-gate */
8687c478bd9Sstevel@tonic-gate bus_range[0] = (int)next_bus;
8697c478bd9Sstevel@tonic-gate bus_range[1] = (int)next_bus;
8707c478bd9Sstevel@tonic-gate
87126947304SEvan Yan if (ndi_prop_update_int_array(DDI_DEV_T_NONE, new_device, "bus-range",
87226947304SEvan Yan bus_range, 2) != DDI_SUCCESS) {
8737c478bd9Sstevel@tonic-gate DEBUG0("Cannot set ntbridge bus-range property");
8747c478bd9Sstevel@tonic-gate return (rc);
8757c478bd9Sstevel@tonic-gate }
8767c478bd9Sstevel@tonic-gate
8777c478bd9Sstevel@tonic-gate /*
8787c478bd9Sstevel@tonic-gate * The other interface (away from the host) will be
8797c478bd9Sstevel@tonic-gate * initialized by the nexus driver when it loads.
8807c478bd9Sstevel@tonic-gate * We just have to set the registers and the nexus driver
8817c478bd9Sstevel@tonic-gate * figures out the rest.
8827c478bd9Sstevel@tonic-gate */
8837c478bd9Sstevel@tonic-gate
8847c478bd9Sstevel@tonic-gate /*
8857c478bd9Sstevel@tonic-gate * finally, lets load and attach the driver
8867c478bd9Sstevel@tonic-gate * before configuring children of ntbridge.
8877c478bd9Sstevel@tonic-gate */
8887c478bd9Sstevel@tonic-gate rc = ndi_devi_online(new_device, NDI_ONLINE_ATTACH|NDI_CONFIG);
8897c478bd9Sstevel@tonic-gate if (rc != NDI_SUCCESS) {
8907c478bd9Sstevel@tonic-gate cmn_err(CE_WARN,
8917c478bd9Sstevel@tonic-gate "pcicfg: Fail:cant load nontransparent bridgd driver..\n");
8927c478bd9Sstevel@tonic-gate rc = PCICFG_FAILURE;
8937c478bd9Sstevel@tonic-gate return (rc);
8947c478bd9Sstevel@tonic-gate }
8957c478bd9Sstevel@tonic-gate DEBUG0("pcicfg: Success loading nontransparent bridge nexus driver..");
8967c478bd9Sstevel@tonic-gate
8975af4ae46Sjveta /* Now set aside pci resource allocation requests for our children */
89826947304SEvan Yan if (pcicfg_ntbridge_allocate_resources(new_device) != PCICFG_SUCCESS) {
8997c478bd9Sstevel@tonic-gate max_devs = 0;
9007c478bd9Sstevel@tonic-gate rc = PCICFG_FAILURE;
9017c478bd9Sstevel@tonic-gate } else
90223c35297Sanish max_devs = PCI_MAX_DEVICES;
9037c478bd9Sstevel@tonic-gate
9047c478bd9Sstevel@tonic-gate /* Probe devices on 2nd bus */
9055af4ae46Sjveta rc = PCICFG_SUCCESS;
9067c478bd9Sstevel@tonic-gate for (devno = pcicfg_start_devno; devno < max_devs; devno++) {
9077c478bd9Sstevel@tonic-gate
9087c478bd9Sstevel@tonic-gate ndi_devi_alloc_sleep(new_device, DEVI_PSEUDO_NEXNAME,
909fa9e4066Sahrens (pnode_t)DEVI_SID_NODEID, &new_ntbridgechild);
9107c478bd9Sstevel@tonic-gate
9117c478bd9Sstevel@tonic-gate if (pcicfg_add_config_reg(new_ntbridgechild, next_bus, devno, 0)
91226947304SEvan Yan != DDI_PROP_SUCCESS) {
9137c478bd9Sstevel@tonic-gate cmn_err(CE_WARN,
91426947304SEvan Yan "Failed to add conf reg for ntbridge child.\n");
9157c478bd9Sstevel@tonic-gate (void) ndi_devi_free(new_ntbridgechild);
9167c478bd9Sstevel@tonic-gate rc = PCICFG_FAILURE;
9177c478bd9Sstevel@tonic-gate break;
9187c478bd9Sstevel@tonic-gate }
9197c478bd9Sstevel@tonic-gate
9207c478bd9Sstevel@tonic-gate if (pci_config_setup(new_ntbridgechild, &config_handle)
92126947304SEvan Yan != DDI_SUCCESS) {
9227c478bd9Sstevel@tonic-gate cmn_err(CE_WARN,
92326947304SEvan Yan "Cannot map ntbridge child %x\n", devno);
9247c478bd9Sstevel@tonic-gate (void) ndi_devi_free(new_ntbridgechild);
9257c478bd9Sstevel@tonic-gate rc = PCICFG_FAILURE;
9267c478bd9Sstevel@tonic-gate break;
9277c478bd9Sstevel@tonic-gate }
9287c478bd9Sstevel@tonic-gate
9297c478bd9Sstevel@tonic-gate /*
9307c478bd9Sstevel@tonic-gate * See if there is any PCI HW at this location
9317c478bd9Sstevel@tonic-gate * by reading the Vendor ID. If it returns with 0xffff
9327c478bd9Sstevel@tonic-gate * then there is no hardware at this location.
9337c478bd9Sstevel@tonic-gate */
9347c478bd9Sstevel@tonic-gate vid = pci_config_get16(config_handle, PCI_CONF_VENID);
9357c478bd9Sstevel@tonic-gate
9367c478bd9Sstevel@tonic-gate pci_config_teardown(&config_handle);
9377c478bd9Sstevel@tonic-gate (void) ndi_devi_free(new_ntbridgechild);
9387c478bd9Sstevel@tonic-gate if (vid == 0xffff)
9397c478bd9Sstevel@tonic-gate continue;
9407c478bd9Sstevel@tonic-gate
9417c478bd9Sstevel@tonic-gate /* Lets fake attachments points for each child, */
94226947304SEvan Yan rc = pcicfg_configure(new_device, devno, PCICFG_ALL_FUNC, 0);
9435af4ae46Sjveta if (rc != PCICFG_SUCCESS) {
9447c478bd9Sstevel@tonic-gate int old_dev = pcicfg_start_devno;
9457c478bd9Sstevel@tonic-gate
9467c478bd9Sstevel@tonic-gate cmn_err(CE_WARN,
94726947304SEvan Yan "Error configuring ntbridge child dev=%d\n", devno);
9487c478bd9Sstevel@tonic-gate
9497c478bd9Sstevel@tonic-gate while (old_dev != devno) {
9507c478bd9Sstevel@tonic-gate if (pcicfg_ntbridge_unconfigure_child(
95126947304SEvan Yan new_device, old_dev) == PCICFG_FAILURE)
95226947304SEvan Yan cmn_err(CE_WARN, "Unconfig Error "
95326947304SEvan Yan "ntbridge child dev=%d\n", old_dev);
9547c478bd9Sstevel@tonic-gate old_dev++;
9557c478bd9Sstevel@tonic-gate }
9567c478bd9Sstevel@tonic-gate break;
9577c478bd9Sstevel@tonic-gate }
9587c478bd9Sstevel@tonic-gate } /* devno loop */
9597c478bd9Sstevel@tonic-gate DEBUG1("ntbridge: finish probing 2nd bus, rc=%d\n", rc);
9607c478bd9Sstevel@tonic-gate
9615af4ae46Sjveta if (rc == PCICFG_SUCCESS)
9627c478bd9Sstevel@tonic-gate rc = pcicfg_ntbridge_configure_done(new_device);
9637c478bd9Sstevel@tonic-gate else {
9647c478bd9Sstevel@tonic-gate pcicfg_phdl_t *entry = pcicfg_find_phdl(new_device);
9657c478bd9Sstevel@tonic-gate uint_t *bus;
9667c478bd9Sstevel@tonic-gate int k;
9677c478bd9Sstevel@tonic-gate
9687c478bd9Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, new_device,
96926947304SEvan Yan DDI_PROP_DONTPASS, "bus-range", (caddr_t)&bus, &k)
97026947304SEvan Yan != DDI_PROP_SUCCESS) {
9717c478bd9Sstevel@tonic-gate DEBUG0("Failed to read bus-range property\n");
9727c478bd9Sstevel@tonic-gate rc = PCICFG_FAILURE;
9737c478bd9Sstevel@tonic-gate return (rc);
9747c478bd9Sstevel@tonic-gate }
9757c478bd9Sstevel@tonic-gate
9767c478bd9Sstevel@tonic-gate DEBUG2("Need to free bus [%d] range [%d]\n",
97726947304SEvan Yan bus[0], bus[1] - bus[0] + 1);
9787c478bd9Sstevel@tonic-gate
97926947304SEvan Yan if (ndi_ra_free(ddi_get_parent(new_device), (uint64_t)bus[0],
98026947304SEvan Yan (uint64_t)(bus[1] - bus[0] + 1), NDI_RA_TYPE_PCI_BUSNUM,
98126947304SEvan Yan NDI_RA_PASS) != NDI_SUCCESS) {
9827c478bd9Sstevel@tonic-gate DEBUG0("Failed to free a bus number\n");
9837c478bd9Sstevel@tonic-gate rc = PCICFG_FAILURE;
9841fb5b786Sprasad kmem_free(bus, k);
9857c478bd9Sstevel@tonic-gate return (rc);
9867c478bd9Sstevel@tonic-gate }
9877c478bd9Sstevel@tonic-gate
9887c478bd9Sstevel@tonic-gate /*
9897c478bd9Sstevel@tonic-gate * Since no memory allocations are done for non transparent
9907c478bd9Sstevel@tonic-gate * bridges (but instead we just set the handle with the
9917c478bd9Sstevel@tonic-gate * already allocated memory, we just need to reset the
9927c478bd9Sstevel@tonic-gate * following values before calling the destroy_phdl()
9937c478bd9Sstevel@tonic-gate * function next, otherwise the it will try to free
9947c478bd9Sstevel@tonic-gate * memory allocated as in case of a transparent bridge.
9957c478bd9Sstevel@tonic-gate */
9967c478bd9Sstevel@tonic-gate entry->memory_len = 0;
997a6469d9bSprasad entry->pf_memory_len = 0;
9987c478bd9Sstevel@tonic-gate entry->io_len = 0;
9991fb5b786Sprasad kmem_free(bus, k);
10007c478bd9Sstevel@tonic-gate /* the following will free hole data. */
10017c478bd9Sstevel@tonic-gate (void) pcicfg_destroy_phdl(new_device);
10027c478bd9Sstevel@tonic-gate }
10037c478bd9Sstevel@tonic-gate
10047c478bd9Sstevel@tonic-gate /*
10057c478bd9Sstevel@tonic-gate * Unload driver just in case child configure failed!
10067c478bd9Sstevel@tonic-gate */
10077c478bd9Sstevel@tonic-gate rc1 = ndi_devi_offline(new_device, 0);
10087c478bd9Sstevel@tonic-gate DEBUG1("pcicfg: now unloading the ntbridge driver. rc1=%d\n", rc1);
10097c478bd9Sstevel@tonic-gate if (rc1 != NDI_SUCCESS) {
10107c478bd9Sstevel@tonic-gate cmn_err(CE_WARN,
10117c478bd9Sstevel@tonic-gate "pcicfg: cant unload ntbridge driver..children.\n");
10127c478bd9Sstevel@tonic-gate rc = PCICFG_FAILURE;
10137c478bd9Sstevel@tonic-gate }
10147c478bd9Sstevel@tonic-gate
10157c478bd9Sstevel@tonic-gate return (rc);
10167c478bd9Sstevel@tonic-gate }
10177c478bd9Sstevel@tonic-gate
10187c478bd9Sstevel@tonic-gate static int
pcicfg_ntbridge_allocate_resources(dev_info_t * dip)10197c478bd9Sstevel@tonic-gate pcicfg_ntbridge_allocate_resources(dev_info_t *dip)
10207c478bd9Sstevel@tonic-gate {
10217c478bd9Sstevel@tonic-gate pcicfg_phdl_t *phdl;
10227c478bd9Sstevel@tonic-gate ndi_ra_request_t *mem_request;
1023a6469d9bSprasad ndi_ra_request_t *pf_mem_request;
10247c478bd9Sstevel@tonic-gate ndi_ra_request_t *io_request;
10257c478bd9Sstevel@tonic-gate uint64_t boundbase, boundlen;
10267c478bd9Sstevel@tonic-gate
10277c478bd9Sstevel@tonic-gate phdl = pcicfg_find_phdl(dip);
10287c478bd9Sstevel@tonic-gate ASSERT(phdl);
10297c478bd9Sstevel@tonic-gate
10307c478bd9Sstevel@tonic-gate mem_request = &phdl->mem_req;
1031a6469d9bSprasad pf_mem_request = &phdl->pf_mem_req;
10327c478bd9Sstevel@tonic-gate io_request = &phdl->io_req;
10337c478bd9Sstevel@tonic-gate
10347c478bd9Sstevel@tonic-gate phdl->error = PCICFG_SUCCESS;
10357c478bd9Sstevel@tonic-gate
10367c478bd9Sstevel@tonic-gate /* Set Memory space handle for ntbridge */
10377c478bd9Sstevel@tonic-gate if (pcicfg_get_ntbridge_child_range(dip, &boundbase, &boundlen,
103826947304SEvan Yan PCI_BASE_SPACE_MEM) != DDI_SUCCESS) {
10397c478bd9Sstevel@tonic-gate cmn_err(CE_WARN,
104026947304SEvan Yan "ntbridge: Mem resource information failure\n");
10417c478bd9Sstevel@tonic-gate phdl->memory_len = 0;
10427c478bd9Sstevel@tonic-gate return (PCICFG_FAILURE);
10437c478bd9Sstevel@tonic-gate }
10447c478bd9Sstevel@tonic-gate mem_request->ra_boundbase = boundbase;
10457c478bd9Sstevel@tonic-gate mem_request->ra_boundlen = boundbase + boundlen;
10467c478bd9Sstevel@tonic-gate mem_request->ra_len = boundlen;
10477c478bd9Sstevel@tonic-gate mem_request->ra_align_mask =
104826947304SEvan Yan PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */
10497c478bd9Sstevel@tonic-gate mem_request->ra_flags |= NDI_RA_ALLOC_BOUNDED;
10507c478bd9Sstevel@tonic-gate
10517c478bd9Sstevel@tonic-gate /*
10527c478bd9Sstevel@tonic-gate * mem_request->ra_len =
10537c478bd9Sstevel@tonic-gate * PCICFG_ROUND_UP(mem_request->ra_len, PCICFG_MEMGRAN);
10547c478bd9Sstevel@tonic-gate */
10557c478bd9Sstevel@tonic-gate
10567c478bd9Sstevel@tonic-gate phdl->memory_base = phdl->memory_last = boundbase;
10577c478bd9Sstevel@tonic-gate phdl->memory_len = boundlen;
10587c478bd9Sstevel@tonic-gate phdl->mem_hole.start = phdl->memory_base;
10597c478bd9Sstevel@tonic-gate phdl->mem_hole.len = mem_request->ra_len;
10607c478bd9Sstevel@tonic-gate phdl->mem_hole.next = (hole_t *)NULL;
10617c478bd9Sstevel@tonic-gate
106226947304SEvan Yan DEBUG2("Connector requested [0x%llx], needs [0x%llx] bytes of memory\n",
106326947304SEvan Yan boundlen, mem_request->ra_len);
10647c478bd9Sstevel@tonic-gate
10657c478bd9Sstevel@tonic-gate /* Set IO space handle for ntbridge */
10667c478bd9Sstevel@tonic-gate if (pcicfg_get_ntbridge_child_range(dip, &boundbase, &boundlen,
106726947304SEvan Yan PCI_BASE_SPACE_IO) != DDI_SUCCESS) {
10687c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "ntbridge: IO resource information failure\n");
10697c478bd9Sstevel@tonic-gate phdl->io_len = 0;
10707c478bd9Sstevel@tonic-gate return (PCICFG_FAILURE);
10717c478bd9Sstevel@tonic-gate }
10727c478bd9Sstevel@tonic-gate io_request->ra_len = boundlen;
10737c478bd9Sstevel@tonic-gate io_request->ra_align_mask =
107426947304SEvan Yan PCICFG_IOGRAN - 1; /* 4K alignment on I/O space */
10757c478bd9Sstevel@tonic-gate io_request->ra_boundbase = boundbase;
10767c478bd9Sstevel@tonic-gate io_request->ra_boundlen = boundbase + boundlen;
10777c478bd9Sstevel@tonic-gate io_request->ra_flags |= NDI_RA_ALLOC_BOUNDED;
10787c478bd9Sstevel@tonic-gate
10797c478bd9Sstevel@tonic-gate /*
10807c478bd9Sstevel@tonic-gate * io_request->ra_len =
10817c478bd9Sstevel@tonic-gate * PCICFG_ROUND_UP(io_request->ra_len, PCICFG_IOGRAN);
10827c478bd9Sstevel@tonic-gate */
10837c478bd9Sstevel@tonic-gate
10847c478bd9Sstevel@tonic-gate phdl->io_base = phdl->io_last = (uint32_t)boundbase;
10857c478bd9Sstevel@tonic-gate phdl->io_len = (uint32_t)boundlen;
10867c478bd9Sstevel@tonic-gate phdl->io_hole.start = phdl->io_base;
10877c478bd9Sstevel@tonic-gate phdl->io_hole.len = io_request->ra_len;
10887c478bd9Sstevel@tonic-gate phdl->io_hole.next = (hole_t *)NULL;
10897c478bd9Sstevel@tonic-gate
109026947304SEvan Yan DEBUG2("Connector requested [0x%llx], needs [0x%llx] bytes of IO\n",
109126947304SEvan Yan boundlen, io_request->ra_len);
10927c478bd9Sstevel@tonic-gate
1093a6469d9bSprasad /* Set Prefetchable Memory space handle for ntbridge */
1094a6469d9bSprasad if (pcicfg_get_ntbridge_child_range(dip, &boundbase, &boundlen,
109526947304SEvan Yan PCI_BASE_SPACE_MEM | PCI_BASE_PREF_M) != DDI_SUCCESS) {
1096a6469d9bSprasad cmn_err(CE_WARN,
109726947304SEvan Yan "ntbridge: PF Mem resource information failure\n");
1098a6469d9bSprasad phdl->pf_memory_len = 0;
1099a6469d9bSprasad return (PCICFG_FAILURE);
1100a6469d9bSprasad }
1101a6469d9bSprasad pf_mem_request->ra_boundbase = boundbase;
1102a6469d9bSprasad pf_mem_request->ra_boundlen = boundbase + boundlen;
1103a6469d9bSprasad pf_mem_request->ra_len = boundlen;
1104a6469d9bSprasad pf_mem_request->ra_align_mask =
110526947304SEvan Yan PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */
1106a6469d9bSprasad pf_mem_request->ra_flags |= NDI_RA_ALLOC_BOUNDED;
1107a6469d9bSprasad
1108a6469d9bSprasad /*
1109a6469d9bSprasad * pf_mem_request->ra_len =
1110a6469d9bSprasad * PCICFG_ROUND_UP(pf_mem_request->ra_len, PCICFG_MEMGRAN);
1111a6469d9bSprasad */
1112a6469d9bSprasad
1113a6469d9bSprasad phdl->pf_memory_base = phdl->pf_memory_last = boundbase;
1114a6469d9bSprasad phdl->pf_memory_len = boundlen;
1115a6469d9bSprasad phdl->pf_mem_hole.start = phdl->pf_memory_base;
1116a6469d9bSprasad phdl->pf_mem_hole.len = pf_mem_request->ra_len;
1117a6469d9bSprasad phdl->pf_mem_hole.next = (hole_t *)NULL;
1118a6469d9bSprasad
111926947304SEvan Yan DEBUG2("Connector requested [0x%llx], needs [0x%llx] bytes of PF "
112026947304SEvan Yan "memory\n", boundlen, pf_mem_request->ra_len);
1121a6469d9bSprasad
1122a6469d9bSprasad DEBUG2("MEMORY BASE = [0x%lx] length [0x%lx]\n",
112326947304SEvan Yan phdl->memory_base, phdl->memory_len);
11247c478bd9Sstevel@tonic-gate DEBUG2("IO BASE = [0x%x] length [0x%x]\n",
112526947304SEvan Yan phdl->io_base, phdl->io_len);
1126a6469d9bSprasad DEBUG2("PF MEMORY BASE = [0x%lx] length [0x%lx]\n",
112726947304SEvan Yan phdl->pf_memory_base, phdl->pf_memory_len);
11287c478bd9Sstevel@tonic-gate
11297c478bd9Sstevel@tonic-gate return (PCICFG_SUCCESS);
11307c478bd9Sstevel@tonic-gate }
11317c478bd9Sstevel@tonic-gate
11327c478bd9Sstevel@tonic-gate static int
pcicfg_ntbridge_configure_done(dev_info_t * dip)11337c478bd9Sstevel@tonic-gate pcicfg_ntbridge_configure_done(dev_info_t *dip)
11347c478bd9Sstevel@tonic-gate {
113500d0963fSdilpreet ppb_ranges_t range[PCICFG_RANGE_LEN];
11367c478bd9Sstevel@tonic-gate pcicfg_phdl_t *entry;
11377c478bd9Sstevel@tonic-gate uint_t len;
113800d0963fSdilpreet pci_bus_range_t bus_range;
11397c478bd9Sstevel@tonic-gate int new_bus_range[2];
11407c478bd9Sstevel@tonic-gate
1141a6469d9bSprasad DEBUG1("Configuring children for %p\n", dip);
11427c478bd9Sstevel@tonic-gate
11437c478bd9Sstevel@tonic-gate entry = pcicfg_find_phdl(dip);
11447c478bd9Sstevel@tonic-gate ASSERT(entry);
11457c478bd9Sstevel@tonic-gate
114626947304SEvan Yan bzero((caddr_t)range, sizeof (ppb_ranges_t) * PCICFG_RANGE_LEN);
114700d0963fSdilpreet range[1].child_high = range[1].parent_high |=
114826947304SEvan Yan (PCI_REG_REL_M | PCI_ADDR_MEM32);
114900d0963fSdilpreet range[1].child_low = range[1].parent_low = (uint32_t)entry->memory_base;
11507c478bd9Sstevel@tonic-gate
115100d0963fSdilpreet range[0].child_high = range[0].parent_high |=
115226947304SEvan Yan (PCI_REG_REL_M | PCI_ADDR_IO);
115300d0963fSdilpreet range[0].child_low = range[0].parent_low = (uint32_t)entry->io_base;
11547c478bd9Sstevel@tonic-gate
115500d0963fSdilpreet range[2].child_high = range[2].parent_high |=
115626947304SEvan Yan (PCI_REG_REL_M | PCI_ADDR_MEM32 | PCI_REG_PF_M);
115700d0963fSdilpreet range[2].child_low = range[2].parent_low =
115826947304SEvan Yan (uint32_t)entry->pf_memory_base;
1159a6469d9bSprasad
116000d0963fSdilpreet len = sizeof (pci_bus_range_t);
1161a3282898Scth if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
116226947304SEvan Yan "bus-range", (caddr_t)&bus_range, (int *)&len) != DDI_SUCCESS) {
11637c478bd9Sstevel@tonic-gate DEBUG0("no bus-range property\n");
11647c478bd9Sstevel@tonic-gate return (PCICFG_FAILURE);
11657c478bd9Sstevel@tonic-gate }
11667c478bd9Sstevel@tonic-gate
11677c478bd9Sstevel@tonic-gate new_bus_range[0] = bus_range.lo; /* primary bus number */
11687c478bd9Sstevel@tonic-gate if (entry->highest_bus) { /* secondary bus number */
11697c478bd9Sstevel@tonic-gate if (entry->highest_bus < bus_range.lo) {
11707c478bd9Sstevel@tonic-gate cmn_err(CE_WARN,
117126947304SEvan Yan "ntbridge bus range invalid !(%d,%d)\n",
117226947304SEvan Yan bus_range.lo, entry->highest_bus);
11737c478bd9Sstevel@tonic-gate new_bus_range[1] = bus_range.lo + entry->highest_bus;
11747c478bd9Sstevel@tonic-gate }
11757c478bd9Sstevel@tonic-gate else
11767c478bd9Sstevel@tonic-gate new_bus_range[1] = entry->highest_bus;
11777c478bd9Sstevel@tonic-gate }
11787c478bd9Sstevel@tonic-gate else
11797c478bd9Sstevel@tonic-gate new_bus_range[1] = bus_range.hi;
11807c478bd9Sstevel@tonic-gate
118126947304SEvan Yan DEBUG2("ntbridge: bus range lo=%x, hi=%x\n", new_bus_range[0],
118226947304SEvan Yan new_bus_range[1]);
11837c478bd9Sstevel@tonic-gate
118426947304SEvan Yan if (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "bus-range",
118526947304SEvan Yan new_bus_range, 2) != DDI_SUCCESS) {
11867c478bd9Sstevel@tonic-gate DEBUG0("Failed to set bus-range property");
11877c478bd9Sstevel@tonic-gate entry->error = PCICFG_FAILURE;
11887c478bd9Sstevel@tonic-gate return (PCICFG_FAILURE);
11897c478bd9Sstevel@tonic-gate }
11907c478bd9Sstevel@tonic-gate
11917c478bd9Sstevel@tonic-gate #ifdef DEBUG
11927c478bd9Sstevel@tonic-gate {
11937c478bd9Sstevel@tonic-gate uint64_t unused;
11947c478bd9Sstevel@tonic-gate unused = pcicfg_unused_space(&entry->io_hole, &len);
11957c478bd9Sstevel@tonic-gate DEBUG2("ntbridge: Unused IO space %llx bytes over %d holes\n",
119626947304SEvan Yan unused, len);
11977c478bd9Sstevel@tonic-gate }
11987c478bd9Sstevel@tonic-gate #endif
11997c478bd9Sstevel@tonic-gate
120000d0963fSdilpreet range[0].size_low = entry->io_len;
12017c478bd9Sstevel@tonic-gate if (pcicfg_update_ranges_prop(dip, &range[0])) {
12027c478bd9Sstevel@tonic-gate DEBUG0("Failed to update ranges (i/o)\n");
12037c478bd9Sstevel@tonic-gate entry->error = PCICFG_FAILURE;
12047c478bd9Sstevel@tonic-gate return (PCICFG_FAILURE);
12057c478bd9Sstevel@tonic-gate }
12067c478bd9Sstevel@tonic-gate
12077c478bd9Sstevel@tonic-gate #ifdef DEBUG
12087c478bd9Sstevel@tonic-gate {
12097c478bd9Sstevel@tonic-gate uint64_t unused;
12107c478bd9Sstevel@tonic-gate unused = pcicfg_unused_space(&entry->mem_hole, &len);
12117c478bd9Sstevel@tonic-gate DEBUG2("ntbridge: Unused Mem space %llx bytes over %d holes\n",
121226947304SEvan Yan unused, len);
12137c478bd9Sstevel@tonic-gate }
12147c478bd9Sstevel@tonic-gate #endif
12157c478bd9Sstevel@tonic-gate
121600d0963fSdilpreet range[1].size_low = entry->memory_len;
12177c478bd9Sstevel@tonic-gate if (pcicfg_update_ranges_prop(dip, &range[1])) {
12187c478bd9Sstevel@tonic-gate DEBUG0("Failed to update ranges (memory)\n");
12197c478bd9Sstevel@tonic-gate entry->error = PCICFG_FAILURE;
12207c478bd9Sstevel@tonic-gate return (PCICFG_FAILURE);
12217c478bd9Sstevel@tonic-gate }
12227c478bd9Sstevel@tonic-gate
1223a6469d9bSprasad #ifdef DEBUG
1224a6469d9bSprasad {
1225a6469d9bSprasad uint64_t unused;
1226a6469d9bSprasad unused = pcicfg_unused_space(&entry->pf_mem_hole, &len);
1227a6469d9bSprasad DEBUG2("ntbridge: Unused PF Mem space %llx bytes over"
122826947304SEvan Yan " %d holes\n", unused, len);
1229a6469d9bSprasad }
1230a6469d9bSprasad #endif
1231a6469d9bSprasad
123200d0963fSdilpreet range[2].size_low = entry->pf_memory_len;
1233a6469d9bSprasad if (pcicfg_update_ranges_prop(dip, &range[2])) {
1234a6469d9bSprasad DEBUG0("Failed to update ranges (PF memory)\n");
1235a6469d9bSprasad entry->error = PCICFG_FAILURE;
1236a6469d9bSprasad return (PCICFG_FAILURE);
1237a6469d9bSprasad }
1238a6469d9bSprasad
12397c478bd9Sstevel@tonic-gate return (PCICFG_SUCCESS);
12407c478bd9Sstevel@tonic-gate }
12417c478bd9Sstevel@tonic-gate
12427c478bd9Sstevel@tonic-gate static int
pcicfg_ntbridge_program_child(dev_info_t * dip)12437c478bd9Sstevel@tonic-gate pcicfg_ntbridge_program_child(dev_info_t *dip)
12447c478bd9Sstevel@tonic-gate {
124526947304SEvan Yan pcicfg_phdl_t *entry;
124626947304SEvan Yan int rc = PCICFG_SUCCESS;
12477c478bd9Sstevel@tonic-gate dev_info_t *anode = dip;
12487c478bd9Sstevel@tonic-gate
124926947304SEvan Yan /* Find the Hotplug Connection (CN) node */
125026947304SEvan Yan while ((anode != NULL) &&
125126947304SEvan Yan (strcmp(ddi_binding_name(anode), "hp_attachment") != 0)) {
12527c478bd9Sstevel@tonic-gate anode = ddi_get_parent(anode);
12537c478bd9Sstevel@tonic-gate }
12547c478bd9Sstevel@tonic-gate
12557c478bd9Sstevel@tonic-gate if (anode == NULL) {
12567c478bd9Sstevel@tonic-gate DEBUG0("ntbridge child tree not in PROBE state\n");
12577c478bd9Sstevel@tonic-gate return (PCICFG_FAILURE);
12587c478bd9Sstevel@tonic-gate }
12597c478bd9Sstevel@tonic-gate entry = pcicfg_find_phdl(ddi_get_parent(anode));
12607c478bd9Sstevel@tonic-gate ASSERT(entry);
12617c478bd9Sstevel@tonic-gate
12627c478bd9Sstevel@tonic-gate if (pcicfg_bridge_assign(dip, entry) == DDI_WALK_TERMINATE) {
12637c478bd9Sstevel@tonic-gate cmn_err(CE_WARN,
126426947304SEvan Yan "ntbridge: Error assigning range for child %s\n",
126526947304SEvan Yan ddi_get_name(dip));
12667c478bd9Sstevel@tonic-gate rc = PCICFG_FAILURE;
12677c478bd9Sstevel@tonic-gate }
12687c478bd9Sstevel@tonic-gate return (rc);
12697c478bd9Sstevel@tonic-gate }
12707c478bd9Sstevel@tonic-gate
12717c478bd9Sstevel@tonic-gate static int
pcicfg_ntbridge_unconfigure_child(dev_info_t * new_device,uint_t devno)12727c478bd9Sstevel@tonic-gate pcicfg_ntbridge_unconfigure_child(dev_info_t *new_device, uint_t devno)
12737c478bd9Sstevel@tonic-gate {
12747c478bd9Sstevel@tonic-gate
12757c478bd9Sstevel@tonic-gate dev_info_t *new_ntbridgechild;
1276ffb64830SJordan Paige Hendricks int len, bus;
12777c478bd9Sstevel@tonic-gate uint16_t vid;
12787c478bd9Sstevel@tonic-gate ddi_acc_handle_t config_handle;
127900d0963fSdilpreet pci_bus_range_t pci_bus_range;
12807c478bd9Sstevel@tonic-gate
128100d0963fSdilpreet len = sizeof (pci_bus_range_t);
1282a3282898Scth if (ddi_getlongprop_buf(DDI_DEV_T_ANY, new_device, DDI_PROP_DONTPASS,
128326947304SEvan Yan "bus-range", (caddr_t)&pci_bus_range, &len) != DDI_SUCCESS) {
12847c478bd9Sstevel@tonic-gate DEBUG0("no bus-range property\n");
12857c478bd9Sstevel@tonic-gate return (PCICFG_FAILURE);
12867c478bd9Sstevel@tonic-gate }
12877c478bd9Sstevel@tonic-gate
12887c478bd9Sstevel@tonic-gate bus = pci_bus_range.lo; /* primary bus number of this bus node */
12897c478bd9Sstevel@tonic-gate
12907c478bd9Sstevel@tonic-gate ndi_devi_alloc_sleep(new_device, DEVI_PSEUDO_NEXNAME,
1291fa9e4066Sahrens (pnode_t)DEVI_SID_NODEID, &new_ntbridgechild);
12927c478bd9Sstevel@tonic-gate
12937c478bd9Sstevel@tonic-gate if (pcicfg_add_config_reg(new_ntbridgechild, bus, devno, 0)
129426947304SEvan Yan != DDI_PROP_SUCCESS) {
129526947304SEvan Yan cmn_err(CE_WARN, "Unconfigure: Failed to add conf reg prop for "
129626947304SEvan Yan "ntbridge child.\n");
12977c478bd9Sstevel@tonic-gate (void) ndi_devi_free(new_ntbridgechild);
12987c478bd9Sstevel@tonic-gate return (PCICFG_FAILURE);
12997c478bd9Sstevel@tonic-gate }
13007c478bd9Sstevel@tonic-gate
13017c478bd9Sstevel@tonic-gate if (pci_config_setup(new_ntbridgechild, &config_handle)
130226947304SEvan Yan != DDI_SUCCESS) {
130326947304SEvan Yan cmn_err(CE_WARN, "pcicfg: Cannot map ntbridge child %x\n",
130426947304SEvan Yan devno);
13057c478bd9Sstevel@tonic-gate (void) ndi_devi_free(new_ntbridgechild);
13067c478bd9Sstevel@tonic-gate return (PCICFG_FAILURE);
13077c478bd9Sstevel@tonic-gate }
13087c478bd9Sstevel@tonic-gate
13097c478bd9Sstevel@tonic-gate /*
13107c478bd9Sstevel@tonic-gate * See if there is any PCI HW at this location
13117c478bd9Sstevel@tonic-gate * by reading the Vendor ID. If it returns with 0xffff
13127c478bd9Sstevel@tonic-gate * then there is no hardware at this location.
13137c478bd9Sstevel@tonic-gate */
13147c478bd9Sstevel@tonic-gate vid = pci_config_get16(config_handle, PCI_CONF_VENID);
13157c478bd9Sstevel@tonic-gate
13167c478bd9Sstevel@tonic-gate pci_config_teardown(&config_handle);
13177c478bd9Sstevel@tonic-gate (void) ndi_devi_free(new_ntbridgechild);
13187c478bd9Sstevel@tonic-gate if (vid == 0xffff)
13197c478bd9Sstevel@tonic-gate return (PCICFG_NODEVICE);
13207c478bd9Sstevel@tonic-gate
132126947304SEvan Yan return (pcicfg_unconfigure(new_device, devno, PCICFG_ALL_FUNC, 0));
13227c478bd9Sstevel@tonic-gate }
13237c478bd9Sstevel@tonic-gate
13247c478bd9Sstevel@tonic-gate static uint_t
pcicfg_ntbridge_unconfigure(dev_info_t * dip)13257c478bd9Sstevel@tonic-gate pcicfg_ntbridge_unconfigure(dev_info_t *dip)
13267c478bd9Sstevel@tonic-gate {
13277c478bd9Sstevel@tonic-gate pcicfg_phdl_t *entry = pcicfg_find_phdl(dip);
13287c478bd9Sstevel@tonic-gate uint_t *bus;
13297c478bd9Sstevel@tonic-gate int k, rc = DDI_FAILURE;
13307c478bd9Sstevel@tonic-gate
133126947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "bus-range",
133226947304SEvan Yan (caddr_t)&bus, &k) != DDI_PROP_SUCCESS) {
13337c478bd9Sstevel@tonic-gate DEBUG0("ntbridge: Failed to read bus-range property\n");
13347c478bd9Sstevel@tonic-gate return (rc);
13357c478bd9Sstevel@tonic-gate }
13367c478bd9Sstevel@tonic-gate
13377c478bd9Sstevel@tonic-gate DEBUG2("ntbridge: Need to free bus [%d] range [%d]\n",
133826947304SEvan Yan bus[0], bus[1] - bus[0] + 1);
13397c478bd9Sstevel@tonic-gate
134026947304SEvan Yan if (ndi_ra_free(ddi_get_parent(dip), (uint64_t)bus[0],
134126947304SEvan Yan (uint64_t)(bus[1] - bus[0] + 1),
134226947304SEvan Yan NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS) != NDI_SUCCESS) {
13437c478bd9Sstevel@tonic-gate DEBUG0("ntbridge: Failed to free a bus number\n");
13447c478bd9Sstevel@tonic-gate kmem_free(bus, k);
13457c478bd9Sstevel@tonic-gate return (rc);
13467c478bd9Sstevel@tonic-gate }
13477c478bd9Sstevel@tonic-gate
13487c478bd9Sstevel@tonic-gate /*
13497c478bd9Sstevel@tonic-gate * Since our resources will be freed at the parent level,
13507c478bd9Sstevel@tonic-gate * just reset these values.
13517c478bd9Sstevel@tonic-gate */
13527c478bd9Sstevel@tonic-gate entry->memory_len = 0;
13537c478bd9Sstevel@tonic-gate entry->io_len = 0;
1354a6469d9bSprasad entry->pf_memory_len = 0;
13557c478bd9Sstevel@tonic-gate
13567c478bd9Sstevel@tonic-gate kmem_free(bus, k);
13577c478bd9Sstevel@tonic-gate
13587c478bd9Sstevel@tonic-gate /* the following will also free hole data. */
13597c478bd9Sstevel@tonic-gate return (pcicfg_destroy_phdl(dip));
13607c478bd9Sstevel@tonic-gate
13617c478bd9Sstevel@tonic-gate }
13627c478bd9Sstevel@tonic-gate
13637c478bd9Sstevel@tonic-gate static int
pcicfg_is_ntbridge(dev_info_t * dip)13647c478bd9Sstevel@tonic-gate pcicfg_is_ntbridge(dev_info_t *dip)
13657c478bd9Sstevel@tonic-gate {
13667c478bd9Sstevel@tonic-gate ddi_acc_handle_t config_handle;
13677c478bd9Sstevel@tonic-gate uint8_t class, subclass;
13687c478bd9Sstevel@tonic-gate int rc = DDI_SUCCESS;
13697c478bd9Sstevel@tonic-gate
13707c478bd9Sstevel@tonic-gate if (pci_config_setup(dip, &config_handle) != DDI_SUCCESS) {
13717c478bd9Sstevel@tonic-gate cmn_err(CE_WARN,
137226947304SEvan Yan "pcicfg: cannot map config space, to get map type\n");
13737c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
13747c478bd9Sstevel@tonic-gate }
13757c478bd9Sstevel@tonic-gate class = pci_config_get8(config_handle, PCI_CONF_BASCLASS);
13767c478bd9Sstevel@tonic-gate subclass = pci_config_get8(config_handle, PCI_CONF_SUBCLASS);
13777c478bd9Sstevel@tonic-gate
13787c478bd9Sstevel@tonic-gate /* check for class=6, subclass=9, for non transparent bridges. */
13797c478bd9Sstevel@tonic-gate if ((class != PCI_CLASS_BRIDGE) || (subclass != PCI_BRIDGE_STBRIDGE))
13807c478bd9Sstevel@tonic-gate rc = DDI_FAILURE;
13817c478bd9Sstevel@tonic-gate
13827c478bd9Sstevel@tonic-gate DEBUG3("pcicfg: checking device %x,%x for indirect map. rc=%d\n",
138326947304SEvan Yan pci_config_get16(config_handle, PCI_CONF_VENID),
138426947304SEvan Yan pci_config_get16(config_handle, PCI_CONF_DEVID),
138526947304SEvan Yan rc);
13867c478bd9Sstevel@tonic-gate pci_config_teardown(&config_handle);
13877c478bd9Sstevel@tonic-gate return (rc);
13887c478bd9Sstevel@tonic-gate }
13897c478bd9Sstevel@tonic-gate
13907c478bd9Sstevel@tonic-gate static uint_t
pcicfg_ntbridge_child(dev_info_t * dip)13917c478bd9Sstevel@tonic-gate pcicfg_ntbridge_child(dev_info_t *dip)
13927c478bd9Sstevel@tonic-gate {
1393ffb64830SJordan Paige Hendricks int len, val, rc = DDI_FAILURE;
13947c478bd9Sstevel@tonic-gate dev_info_t *anode = dip;
13957c478bd9Sstevel@tonic-gate
13967c478bd9Sstevel@tonic-gate /*
139726947304SEvan Yan * Find the Hotplug Connection (CN) node
13987c478bd9Sstevel@tonic-gate */
13997c478bd9Sstevel@tonic-gate while ((anode != NULL) && (strcmp(ddi_binding_name(anode),
140026947304SEvan Yan "hp_attachment") != 0)) {
14017c478bd9Sstevel@tonic-gate anode = ddi_get_parent(anode);
14027c478bd9Sstevel@tonic-gate }
14037c478bd9Sstevel@tonic-gate
14047c478bd9Sstevel@tonic-gate if (anode == NULL) {
14057c478bd9Sstevel@tonic-gate DEBUG0("ntbridge child tree not in PROBE state\n");
14067c478bd9Sstevel@tonic-gate return (rc);
14077c478bd9Sstevel@tonic-gate }
14087c478bd9Sstevel@tonic-gate len = sizeof (int);
1409a3282898Scth if (ddi_getlongprop_buf(DDI_DEV_T_ANY, ddi_get_parent(anode),
141026947304SEvan Yan DDI_PROP_DONTPASS, PCI_DEV_CONF_MAP_PROP, (caddr_t)&val, &len)
141126947304SEvan Yan != DDI_SUCCESS) {
14127c478bd9Sstevel@tonic-gate
14137c478bd9Sstevel@tonic-gate DEBUG1("ntbridge child: no \"%s\" property\n",
141426947304SEvan Yan PCI_DEV_CONF_MAP_PROP);
14157c478bd9Sstevel@tonic-gate return (rc);
14167c478bd9Sstevel@tonic-gate }
14177c478bd9Sstevel@tonic-gate DEBUG0("ntbridge child: success\n");
14187c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
14197c478bd9Sstevel@tonic-gate }
14207c478bd9Sstevel@tonic-gate
14217c478bd9Sstevel@tonic-gate static uint_t
pcicfg_get_ntbridge_child_range(dev_info_t * dip,uint64_t * boundbase,uint64_t * boundlen,uint_t space_type)14227c478bd9Sstevel@tonic-gate pcicfg_get_ntbridge_child_range(dev_info_t *dip, uint64_t *boundbase,
1423ffb64830SJordan Paige Hendricks uint64_t *boundlen, uint_t space_type)
14247c478bd9Sstevel@tonic-gate {
14257c478bd9Sstevel@tonic-gate int length, found = DDI_FAILURE, acount, i, ibridge;
14267c478bd9Sstevel@tonic-gate pci_regspec_t *assigned;
14277c478bd9Sstevel@tonic-gate
14287c478bd9Sstevel@tonic-gate if ((ibridge = pcicfg_is_ntbridge(dip)) == DDI_FAILURE)
14297c478bd9Sstevel@tonic-gate return (found);
14307c478bd9Sstevel@tonic-gate
143126947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
143226947304SEvan Yan "assigned-addresses", (caddr_t)&assigned, &length)
143326947304SEvan Yan != DDI_PROP_SUCCESS) {
14347c478bd9Sstevel@tonic-gate DEBUG1("Failed to get assigned-addresses property %llx\n", dip);
14357c478bd9Sstevel@tonic-gate return (found);
14367c478bd9Sstevel@tonic-gate }
14377c478bd9Sstevel@tonic-gate DEBUG1("pcicfg: ntbridge child range: dip = %s\n",
143826947304SEvan Yan ddi_driver_name(dip));
14397c478bd9Sstevel@tonic-gate
14407c478bd9Sstevel@tonic-gate acount = length / sizeof (pci_regspec_t);
14417c478bd9Sstevel@tonic-gate
14427c478bd9Sstevel@tonic-gate for (i = 0; i < acount; i++) {
144326947304SEvan Yan if ((PCI_REG_REG_G(assigned[i].pci_phys_hi) ==
144426947304SEvan Yan pcicfg_indirect_map_devs[ibridge].mem_range_bar_offset) &&
144526947304SEvan Yan (space_type == PCI_BASE_SPACE_MEM)) {
144626947304SEvan Yan found = DDI_SUCCESS;
144726947304SEvan Yan break;
144826947304SEvan Yan } else if ((PCI_REG_REG_G(assigned[i].pci_phys_hi) ==
144926947304SEvan Yan pcicfg_indirect_map_devs[ibridge].io_range_bar_offset) &&
145026947304SEvan Yan (space_type == PCI_BASE_SPACE_IO)) {
145126947304SEvan Yan found = DDI_SUCCESS;
145226947304SEvan Yan break;
145326947304SEvan Yan } else if ((PCI_REG_REG_G(assigned[i].pci_phys_hi) ==
145426947304SEvan Yan pcicfg_indirect_map_devs[ibridge].
145526947304SEvan Yan prefetch_mem_range_bar_offset) &&
145626947304SEvan Yan (space_type == (PCI_BASE_SPACE_MEM |
145726947304SEvan Yan PCI_BASE_PREF_M))) {
14587c478bd9Sstevel@tonic-gate found = DDI_SUCCESS;
14597c478bd9Sstevel@tonic-gate break;
14607c478bd9Sstevel@tonic-gate }
14617c478bd9Sstevel@tonic-gate }
14627c478bd9Sstevel@tonic-gate DEBUG3("pcicfg: ntbridge child range: space=%x, base=%lx, len=%lx\n",
146326947304SEvan Yan space_type, assigned[i].pci_phys_low, assigned[i].pci_size_low);
14647c478bd9Sstevel@tonic-gate
14657c478bd9Sstevel@tonic-gate if (found == DDI_SUCCESS) {
14667c478bd9Sstevel@tonic-gate *boundbase = assigned[i].pci_phys_low;
14677c478bd9Sstevel@tonic-gate *boundlen = assigned[i].pci_size_low;
14687c478bd9Sstevel@tonic-gate }
14697c478bd9Sstevel@tonic-gate
14707c478bd9Sstevel@tonic-gate kmem_free(assigned, length);
14717c478bd9Sstevel@tonic-gate return (found);
14727c478bd9Sstevel@tonic-gate }
14737c478bd9Sstevel@tonic-gate
14747c478bd9Sstevel@tonic-gate /*
14757c478bd9Sstevel@tonic-gate * This will turn resources allocated by pcicfg_configure()
147626947304SEvan Yan * and remove the device tree from the Hotplug Connection (CN)
14777c478bd9Sstevel@tonic-gate * and below. The routine assumes the devices have their
14787c478bd9Sstevel@tonic-gate * drivers detached.
14797c478bd9Sstevel@tonic-gate */
14807c478bd9Sstevel@tonic-gate int
pcicfg_unconfigure(dev_info_t * devi,uint_t device,uint_t function,pcicfg_flags_t flags)148126947304SEvan Yan pcicfg_unconfigure(dev_info_t *devi, uint_t device, uint_t function,
148226947304SEvan Yan pcicfg_flags_t flags)
14837c478bd9Sstevel@tonic-gate {
14847c478bd9Sstevel@tonic-gate dev_info_t *child_dip;
14857c478bd9Sstevel@tonic-gate int func;
14867c478bd9Sstevel@tonic-gate int i;
148726947304SEvan Yan int max_function, trans_device;
1488c0da6274SZhi-Jun Robin Fu boolean_t is_pcie;
148926947304SEvan Yan
149026947304SEvan Yan if (pcie_ari_is_enabled(devi) == PCIE_ARI_FORW_ENABLED)
149126947304SEvan Yan max_function = PCICFG_MAX_ARI_FUNCTION;
149226947304SEvan Yan else
149326947304SEvan Yan max_function = PCI_MAX_FUNCTIONS;
14947c478bd9Sstevel@tonic-gate
14957c478bd9Sstevel@tonic-gate /*
14967c478bd9Sstevel@tonic-gate * Cycle through devices to make sure none are busy.
14977c478bd9Sstevel@tonic-gate * If a single device is busy fail the whole unconfigure.
14987c478bd9Sstevel@tonic-gate */
1499c0da6274SZhi-Jun Robin Fu is_pcie = is_pcie_fabric(devi);
1500c0da6274SZhi-Jun Robin Fu
15013fe80ca4SDan Cross ndi_devi_enter(devi);
150226947304SEvan Yan for (func = 0; func < max_function; func++) {
150326947304SEvan Yan if ((function != PCICFG_ALL_FUNC) && (function != func))
150426947304SEvan Yan continue;
150526947304SEvan Yan
150626947304SEvan Yan if (max_function == PCICFG_MAX_ARI_FUNCTION)
150726947304SEvan Yan trans_device = func >> 3; /* ARI Device */
150826947304SEvan Yan else
150926947304SEvan Yan trans_device = device;
151026947304SEvan Yan
151126947304SEvan Yan if ((child_dip = pcicfg_devi_find(devi, trans_device,
151226947304SEvan Yan func & 7)) == NULL)
151370025d76Sjohnny continue;
15147c478bd9Sstevel@tonic-gate
15157c478bd9Sstevel@tonic-gate if (ndi_devi_offline(child_dip, NDI_UNCONFIG) == NDI_SUCCESS)
151626947304SEvan Yan continue;
151726947304SEvan Yan
15187c478bd9Sstevel@tonic-gate /*
15197c478bd9Sstevel@tonic-gate * Device function is busy. Before returning we have to
15207c478bd9Sstevel@tonic-gate * put all functions back online which were taken
15217c478bd9Sstevel@tonic-gate * offline during the process.
15227c478bd9Sstevel@tonic-gate */
152326947304SEvan Yan DEBUG2("Device [0x%x] function [0x%x] is busy\n",
152426947304SEvan Yan trans_device, func & 7);
152526947304SEvan Yan /*
152626947304SEvan Yan * If we are only asked to offline one specific function,
152726947304SEvan Yan * and that fails, we just simply return.
152826947304SEvan Yan */
152926947304SEvan Yan if (function != PCICFG_ALL_FUNC)
15307c478bd9Sstevel@tonic-gate return (PCICFG_FAILURE);
153126947304SEvan Yan
153226947304SEvan Yan for (i = 0; i < func; i++) {
153326947304SEvan Yan if (max_function == PCICFG_MAX_ARI_FUNCTION)
153426947304SEvan Yan trans_device = i >> 3;
153526947304SEvan Yan
153626947304SEvan Yan if ((child_dip = pcicfg_devi_find(devi, trans_device,
153726947304SEvan Yan i & 7)) == NULL) {
153826947304SEvan Yan DEBUG0("No more devices to put back "
153926947304SEvan Yan "on line!!\n");
154026947304SEvan Yan /*
154126947304SEvan Yan * Made it through all functions
154226947304SEvan Yan */
154326947304SEvan Yan continue;
154426947304SEvan Yan }
154526947304SEvan Yan if (ndi_devi_online(child_dip, NDI_CONFIG)
154626947304SEvan Yan != NDI_SUCCESS) {
154726947304SEvan Yan DEBUG0("Failed to put back devices state\n");
1548c0da6274SZhi-Jun Robin Fu goto fail;
154926947304SEvan Yan }
15507c478bd9Sstevel@tonic-gate }
1551c0da6274SZhi-Jun Robin Fu goto fail;
15527c478bd9Sstevel@tonic-gate }
15537c478bd9Sstevel@tonic-gate
15547c478bd9Sstevel@tonic-gate /*
155526947304SEvan Yan * Now, tear down all devinfo nodes for this Connector.
15567c478bd9Sstevel@tonic-gate */
155726947304SEvan Yan for (func = 0; func < max_function; func++) {
155826947304SEvan Yan if ((function != PCICFG_ALL_FUNC) && (function != func))
155926947304SEvan Yan continue;
156026947304SEvan Yan
156126947304SEvan Yan if (max_function == PCICFG_MAX_ARI_FUNCTION)
156226947304SEvan Yan trans_device = func >> 3; /* ARI Device */
156326947304SEvan Yan else
156426947304SEvan Yan trans_device = device;
156526947304SEvan Yan
156626947304SEvan Yan if ((child_dip = pcicfg_devi_find(devi, trans_device, func & 7))
156726947304SEvan Yan == NULL) {
156826947304SEvan Yan DEBUG2("No device at %x,%x\n", trans_device, func & 7);
156970025d76Sjohnny continue;
15707c478bd9Sstevel@tonic-gate }
15717c478bd9Sstevel@tonic-gate
15727c478bd9Sstevel@tonic-gate DEBUG2("Tearing down device [0x%x] function [0x%x]\n",
157326947304SEvan Yan trans_device, func & 7);
15747c478bd9Sstevel@tonic-gate
15757c478bd9Sstevel@tonic-gate if (pcicfg_is_ntbridge(child_dip) != DDI_FAILURE)
15767c478bd9Sstevel@tonic-gate if (pcicfg_ntbridge_unconfigure(child_dip) !=
157726947304SEvan Yan PCICFG_SUCCESS) {
15787c478bd9Sstevel@tonic-gate cmn_err(CE_WARN,
157926947304SEvan Yan "ntbridge: unconfigure failed\n");
1580c0da6274SZhi-Jun Robin Fu goto fail;
15817c478bd9Sstevel@tonic-gate }
15827c478bd9Sstevel@tonic-gate
1583c0da6274SZhi-Jun Robin Fu if (pcicfg_teardown_device(child_dip, flags, is_pcie)
158426947304SEvan Yan != PCICFG_SUCCESS) {
15857c478bd9Sstevel@tonic-gate DEBUG2("Failed to tear down device [0x%x]"
158626947304SEvan Yan "function [0x%x]\n", trans_device, func & 7);
1587c0da6274SZhi-Jun Robin Fu goto fail;
15887c478bd9Sstevel@tonic-gate }
15897c478bd9Sstevel@tonic-gate }
159026947304SEvan Yan
159126947304SEvan Yan if (pcie_ari_is_enabled(devi) == PCIE_ARI_FORW_ENABLED) {
159226947304SEvan Yan (void) ddi_prop_remove(DDI_DEV_T_NONE, devi, "ari-enabled");
159326947304SEvan Yan (void) pcie_ari_disable(devi);
159426947304SEvan Yan }
159526947304SEvan Yan
15963fe80ca4SDan Cross ndi_devi_exit(devi);
15977c478bd9Sstevel@tonic-gate return (PCICFG_SUCCESS);
1598c0da6274SZhi-Jun Robin Fu
1599c0da6274SZhi-Jun Robin Fu fail:
16003fe80ca4SDan Cross ndi_devi_exit(devi);
1601c0da6274SZhi-Jun Robin Fu return (PCICFG_FAILURE);
16027c478bd9Sstevel@tonic-gate }
16037c478bd9Sstevel@tonic-gate
16047c478bd9Sstevel@tonic-gate static int
pcicfg_teardown_device(dev_info_t * dip,pcicfg_flags_t flags,boolean_t is_pcie)1605c0da6274SZhi-Jun Robin Fu pcicfg_teardown_device(dev_info_t *dip, pcicfg_flags_t flags, boolean_t is_pcie)
16067c478bd9Sstevel@tonic-gate {
1607a6469d9bSprasad ddi_acc_handle_t handle;
1608ffb64830SJordan Paige Hendricks int ret;
1609a6469d9bSprasad
16107c478bd9Sstevel@tonic-gate /*
16117c478bd9Sstevel@tonic-gate * Free up resources associated with 'dip'
16127c478bd9Sstevel@tonic-gate */
161326947304SEvan Yan if (pcicfg_free_resources(dip, flags) != PCICFG_SUCCESS) {
16147c478bd9Sstevel@tonic-gate DEBUG0("Failed to free resources\n");
16157c478bd9Sstevel@tonic-gate return (PCICFG_FAILURE);
16167c478bd9Sstevel@tonic-gate }
16177c478bd9Sstevel@tonic-gate
1618a6469d9bSprasad /*
1619a6469d9bSprasad * disable the device
1620a6469d9bSprasad */
1621ffb64830SJordan Paige Hendricks
1622ffb64830SJordan Paige Hendricks ret = pcicfg_config_setup(dip, &handle);
1623ffb64830SJordan Paige Hendricks if (ret == PCICFG_SUCCESS) {
1624ffb64830SJordan Paige Hendricks pcicfg_device_off(handle);
1625ffb64830SJordan Paige Hendricks pcicfg_config_teardown(&handle);
1626ffb64830SJordan Paige Hendricks } else if (ret != PCICFG_NODEVICE) {
1627ffb64830SJordan Paige Hendricks /*
1628ffb64830SJordan Paige Hendricks * It is possible the device no longer exists -- for instance,
1629ffb64830SJordan Paige Hendricks * if the device has been pulled from a hotpluggable slot on the
1630ffb64830SJordan Paige Hendricks * system. In this case, do not fail the teardown, though there
1631ffb64830SJordan Paige Hendricks * is less to clean up.
1632ffb64830SJordan Paige Hendricks */
1633a6469d9bSprasad return (PCICFG_FAILURE);
1634ffb64830SJordan Paige Hendricks }
1635a6469d9bSprasad
1636c0da6274SZhi-Jun Robin Fu if (is_pcie) {
1637c0da6274SZhi-Jun Robin Fu /*
1638c0da6274SZhi-Jun Robin Fu * free pcie_bus_t for the sub-tree
1639c0da6274SZhi-Jun Robin Fu */
1640c0da6274SZhi-Jun Robin Fu if (ddi_get_child(dip) != NULL)
1641c0da6274SZhi-Jun Robin Fu pcie_fab_fini_bus(dip, PCIE_BUS_ALL);
1642c0da6274SZhi-Jun Robin Fu
1643c0da6274SZhi-Jun Robin Fu pcie_fini_bus(dip, PCIE_BUS_ALL);
1644c0da6274SZhi-Jun Robin Fu }
1645c0da6274SZhi-Jun Robin Fu
16467c478bd9Sstevel@tonic-gate /*
16477c478bd9Sstevel@tonic-gate * The framework provides this routine which can
16487c478bd9Sstevel@tonic-gate * tear down a sub-tree.
16497c478bd9Sstevel@tonic-gate */
16507c478bd9Sstevel@tonic-gate if (ndi_devi_offline(dip, NDI_DEVI_REMOVE) != NDI_SUCCESS) {
16517c478bd9Sstevel@tonic-gate DEBUG0("Failed to offline and remove node\n");
16527c478bd9Sstevel@tonic-gate return (PCICFG_FAILURE);
16537c478bd9Sstevel@tonic-gate }
16547c478bd9Sstevel@tonic-gate
16557c478bd9Sstevel@tonic-gate return (PCICFG_SUCCESS);
16567c478bd9Sstevel@tonic-gate }
16577c478bd9Sstevel@tonic-gate
16587c478bd9Sstevel@tonic-gate /*
16597c478bd9Sstevel@tonic-gate * BEGIN GENERIC SUPPORT ROUTINES
16607c478bd9Sstevel@tonic-gate */
16617c478bd9Sstevel@tonic-gate static pcicfg_phdl_t *
pcicfg_find_phdl(dev_info_t * dip)16627c478bd9Sstevel@tonic-gate pcicfg_find_phdl(dev_info_t *dip)
16637c478bd9Sstevel@tonic-gate {
16647c478bd9Sstevel@tonic-gate pcicfg_phdl_t *entry;
16657c478bd9Sstevel@tonic-gate mutex_enter(&pcicfg_list_mutex);
16667c478bd9Sstevel@tonic-gate for (entry = pcicfg_phdl_list; entry != NULL; entry = entry->next) {
16677c478bd9Sstevel@tonic-gate if (entry->dip == dip) {
16687c478bd9Sstevel@tonic-gate mutex_exit(&pcicfg_list_mutex);
16697c478bd9Sstevel@tonic-gate return (entry);
16707c478bd9Sstevel@tonic-gate }
16717c478bd9Sstevel@tonic-gate }
16727c478bd9Sstevel@tonic-gate mutex_exit(&pcicfg_list_mutex);
16737c478bd9Sstevel@tonic-gate
16747c478bd9Sstevel@tonic-gate /*
16757c478bd9Sstevel@tonic-gate * Did'nt find entry - create one
16767c478bd9Sstevel@tonic-gate */
16777c478bd9Sstevel@tonic-gate return (pcicfg_create_phdl(dip));
16787c478bd9Sstevel@tonic-gate }
16797c478bd9Sstevel@tonic-gate
16807c478bd9Sstevel@tonic-gate static pcicfg_phdl_t *
pcicfg_create_phdl(dev_info_t * dip)16817c478bd9Sstevel@tonic-gate pcicfg_create_phdl(dev_info_t *dip)
16827c478bd9Sstevel@tonic-gate {
16837c478bd9Sstevel@tonic-gate pcicfg_phdl_t *new;
16847c478bd9Sstevel@tonic-gate
168526947304SEvan Yan new = (pcicfg_phdl_t *)kmem_zalloc(sizeof (pcicfg_phdl_t), KM_SLEEP);
16867c478bd9Sstevel@tonic-gate
16877c478bd9Sstevel@tonic-gate new->dip = dip;
16887c478bd9Sstevel@tonic-gate mutex_enter(&pcicfg_list_mutex);
16897c478bd9Sstevel@tonic-gate new->next = pcicfg_phdl_list;
16907c478bd9Sstevel@tonic-gate pcicfg_phdl_list = new;
16917c478bd9Sstevel@tonic-gate mutex_exit(&pcicfg_list_mutex);
16927c478bd9Sstevel@tonic-gate
16937c478bd9Sstevel@tonic-gate return (new);
16947c478bd9Sstevel@tonic-gate }
16957c478bd9Sstevel@tonic-gate
16967c478bd9Sstevel@tonic-gate static int
pcicfg_destroy_phdl(dev_info_t * dip)16977c478bd9Sstevel@tonic-gate pcicfg_destroy_phdl(dev_info_t *dip)
16987c478bd9Sstevel@tonic-gate {
16997c478bd9Sstevel@tonic-gate pcicfg_phdl_t *entry;
17007c478bd9Sstevel@tonic-gate pcicfg_phdl_t *follow = NULL;
17017c478bd9Sstevel@tonic-gate
17027c478bd9Sstevel@tonic-gate mutex_enter(&pcicfg_list_mutex);
17037c478bd9Sstevel@tonic-gate for (entry = pcicfg_phdl_list; entry != NULL; follow = entry,
170426947304SEvan Yan entry = entry->next) {
17057c478bd9Sstevel@tonic-gate if (entry->dip == dip) {
17067c478bd9Sstevel@tonic-gate if (entry == pcicfg_phdl_list) {
17077c478bd9Sstevel@tonic-gate pcicfg_phdl_list = entry->next;
17087c478bd9Sstevel@tonic-gate } else {
17097c478bd9Sstevel@tonic-gate follow->next = entry->next;
17107c478bd9Sstevel@tonic-gate }
17117c478bd9Sstevel@tonic-gate /*
17127c478bd9Sstevel@tonic-gate * If this entry has any allocated memory
17137c478bd9Sstevel@tonic-gate * or IO space associated with it, that
17147c478bd9Sstevel@tonic-gate * must be freed up.
17157c478bd9Sstevel@tonic-gate */
17167c478bd9Sstevel@tonic-gate if (entry->memory_len > 0) {
17177c478bd9Sstevel@tonic-gate (void) ndi_ra_free(ddi_get_parent(dip),
171826947304SEvan Yan entry->memory_base, entry->memory_len,
171926947304SEvan Yan NDI_RA_TYPE_MEM, NDI_RA_PASS);
17207c478bd9Sstevel@tonic-gate }
17217c478bd9Sstevel@tonic-gate pcicfg_free_hole(&entry->mem_hole);
17227c478bd9Sstevel@tonic-gate
17237c478bd9Sstevel@tonic-gate if (entry->io_len > 0) {
17247c478bd9Sstevel@tonic-gate (void) ndi_ra_free(ddi_get_parent(dip),
172526947304SEvan Yan entry->io_base, entry->io_len,
172626947304SEvan Yan NDI_RA_TYPE_IO, NDI_RA_PASS);
17277c478bd9Sstevel@tonic-gate }
17287c478bd9Sstevel@tonic-gate pcicfg_free_hole(&entry->io_hole);
17297c478bd9Sstevel@tonic-gate
1730a6469d9bSprasad if (entry->pf_memory_len > 0) {
1731a6469d9bSprasad (void) ndi_ra_free(ddi_get_parent(dip),
173226947304SEvan Yan entry->pf_memory_base, entry->pf_memory_len,
173326947304SEvan Yan NDI_RA_TYPE_PCI_PREFETCH_MEM, NDI_RA_PASS);
1734a6469d9bSprasad }
1735a6469d9bSprasad pcicfg_free_hole(&entry->pf_mem_hole);
1736a6469d9bSprasad
17377c478bd9Sstevel@tonic-gate /*
17387c478bd9Sstevel@tonic-gate * Destroy this entry
17397c478bd9Sstevel@tonic-gate */
17407c478bd9Sstevel@tonic-gate kmem_free((caddr_t)entry, sizeof (pcicfg_phdl_t));
17417c478bd9Sstevel@tonic-gate mutex_exit(&pcicfg_list_mutex);
17427c478bd9Sstevel@tonic-gate return (PCICFG_SUCCESS);
17437c478bd9Sstevel@tonic-gate }
17447c478bd9Sstevel@tonic-gate }
17457c478bd9Sstevel@tonic-gate mutex_exit(&pcicfg_list_mutex);
17467c478bd9Sstevel@tonic-gate /*
17477c478bd9Sstevel@tonic-gate * Did'nt find the entry
17487c478bd9Sstevel@tonic-gate */
17497c478bd9Sstevel@tonic-gate return (PCICFG_FAILURE);
17507c478bd9Sstevel@tonic-gate }
17517c478bd9Sstevel@tonic-gate
17527c478bd9Sstevel@tonic-gate static int
pcicfg_bridge_assign(dev_info_t * dip,void * hdl)17537c478bd9Sstevel@tonic-gate pcicfg_bridge_assign(dev_info_t *dip, void *hdl)
17547c478bd9Sstevel@tonic-gate {
17557c478bd9Sstevel@tonic-gate ddi_acc_handle_t handle;
17567c478bd9Sstevel@tonic-gate pci_regspec_t *reg;
17577c478bd9Sstevel@tonic-gate int length;
17587c478bd9Sstevel@tonic-gate int rcount;
17597c478bd9Sstevel@tonic-gate int i;
17607c478bd9Sstevel@tonic-gate int offset;
17617c478bd9Sstevel@tonic-gate uint64_t mem_answer;
17627c478bd9Sstevel@tonic-gate uint32_t io_answer;
17637c478bd9Sstevel@tonic-gate uint8_t header_type;
176400d0963fSdilpreet ppb_ranges_t range[PCICFG_RANGE_LEN];
17657c478bd9Sstevel@tonic-gate int bus_range[2];
17667c478bd9Sstevel@tonic-gate uint64_t mem_residual;
1767a6469d9bSprasad uint64_t pf_mem_residual;
17687c478bd9Sstevel@tonic-gate uint64_t io_residual;
17697c478bd9Sstevel@tonic-gate
17707c478bd9Sstevel@tonic-gate pcicfg_phdl_t *entry = (pcicfg_phdl_t *)hdl;
17717c478bd9Sstevel@tonic-gate
177226947304SEvan Yan DEBUG1("bridge assign: assigning addresses to %s\n", ddi_get_name(dip));
17737c478bd9Sstevel@tonic-gate
17747c478bd9Sstevel@tonic-gate entry->error = PCICFG_SUCCESS;
17757c478bd9Sstevel@tonic-gate
17767c478bd9Sstevel@tonic-gate if (entry == NULL) {
17777c478bd9Sstevel@tonic-gate DEBUG0("Failed to get entry\n");
17787c478bd9Sstevel@tonic-gate entry->error = PCICFG_FAILURE;
17797c478bd9Sstevel@tonic-gate return (DDI_WALK_TERMINATE);
17807c478bd9Sstevel@tonic-gate }
17817c478bd9Sstevel@tonic-gate
178226947304SEvan Yan if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
17837c478bd9Sstevel@tonic-gate DEBUG0("Failed to map config space!\n");
17847c478bd9Sstevel@tonic-gate entry->error = PCICFG_FAILURE;
17857c478bd9Sstevel@tonic-gate return (DDI_WALK_TERMINATE);
17867c478bd9Sstevel@tonic-gate }
17877c478bd9Sstevel@tonic-gate
17887c478bd9Sstevel@tonic-gate header_type = pci_config_get8(handle, PCI_CONF_HEADER);
17897c478bd9Sstevel@tonic-gate
17907c478bd9Sstevel@tonic-gate if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
17917c478bd9Sstevel@tonic-gate
179226947304SEvan Yan bzero((caddr_t)range, sizeof (ppb_ranges_t) * PCICFG_RANGE_LEN);
17937c478bd9Sstevel@tonic-gate
17947c478bd9Sstevel@tonic-gate (void) pcicfg_setup_bridge(entry, handle);
17957c478bd9Sstevel@tonic-gate
179600d0963fSdilpreet range[0].child_high = range[0].parent_high |=
179726947304SEvan Yan (PCI_REG_REL_M | PCI_ADDR_IO);
179826947304SEvan Yan range[0].child_low = range[0].parent_low = entry->io_last;
179900d0963fSdilpreet range[1].child_high = range[1].parent_high |=
180026947304SEvan Yan (PCI_REG_REL_M | PCI_ADDR_MEM32);
180100d0963fSdilpreet range[1].child_low = range[1].parent_low =
180226947304SEvan Yan entry->memory_last;
180300d0963fSdilpreet range[2].child_high = range[2].parent_high |=
180426947304SEvan Yan (PCI_REG_REL_M | PCI_ADDR_MEM32 | PCI_REG_PF_M);
180500d0963fSdilpreet range[2].child_low = range[2].parent_low =
180626947304SEvan Yan entry->pf_memory_last;
18077c478bd9Sstevel@tonic-gate
18083fe80ca4SDan Cross ndi_devi_enter(dip);
18097c478bd9Sstevel@tonic-gate ddi_walk_devs(ddi_get_child(dip),
181026947304SEvan Yan pcicfg_bridge_assign, (void *)entry);
18113fe80ca4SDan Cross ndi_devi_exit(dip);
18127c478bd9Sstevel@tonic-gate
18137c478bd9Sstevel@tonic-gate (void) pcicfg_update_bridge(entry, handle);
18147c478bd9Sstevel@tonic-gate
18157c478bd9Sstevel@tonic-gate bus_range[0] = pci_config_get8(handle, PCI_BCNF_SECBUS);
18167c478bd9Sstevel@tonic-gate bus_range[1] = pci_config_get8(handle, PCI_BCNF_SUBBUS);
18177c478bd9Sstevel@tonic-gate
18187c478bd9Sstevel@tonic-gate if (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
181926947304SEvan Yan "bus-range", bus_range, 2) != DDI_SUCCESS) {
18207c478bd9Sstevel@tonic-gate DEBUG0("Failed to set bus-range property");
18217c478bd9Sstevel@tonic-gate entry->error = PCICFG_FAILURE;
18221fb5b786Sprasad (void) pcicfg_config_teardown(&handle);
18237c478bd9Sstevel@tonic-gate return (DDI_WALK_TERMINATE);
18247c478bd9Sstevel@tonic-gate }
18257c478bd9Sstevel@tonic-gate
18267c478bd9Sstevel@tonic-gate /*
18277c478bd9Sstevel@tonic-gate * Put back memory and I/O space not allocated
18287c478bd9Sstevel@tonic-gate * under the bridge.
18297c478bd9Sstevel@tonic-gate */
18307c478bd9Sstevel@tonic-gate mem_residual = entry->memory_len -
183126947304SEvan Yan (entry->memory_last - entry->memory_base);
18327c478bd9Sstevel@tonic-gate if (mem_residual > 0) {
18337c478bd9Sstevel@tonic-gate (void) ndi_ra_free(ddi_get_parent(dip),
183426947304SEvan Yan entry->memory_last, mem_residual,
183526947304SEvan Yan NDI_RA_TYPE_MEM, NDI_RA_PASS);
18367c478bd9Sstevel@tonic-gate }
18377c478bd9Sstevel@tonic-gate
183826947304SEvan Yan io_residual = entry->io_len - (entry->io_last - entry->io_base);
18397c478bd9Sstevel@tonic-gate if (io_residual > 0) {
184026947304SEvan Yan (void) ndi_ra_free(ddi_get_parent(dip), entry->io_last,
184126947304SEvan Yan io_residual, NDI_RA_TYPE_IO, NDI_RA_PASS);
18427c478bd9Sstevel@tonic-gate }
18437c478bd9Sstevel@tonic-gate
1844a6469d9bSprasad pf_mem_residual = entry->pf_memory_len -
184526947304SEvan Yan (entry->pf_memory_last - entry->pf_memory_base);
1846a6469d9bSprasad if (pf_mem_residual > 0) {
1847a6469d9bSprasad (void) ndi_ra_free(ddi_get_parent(dip),
184826947304SEvan Yan entry->pf_memory_last, pf_mem_residual,
184926947304SEvan Yan NDI_RA_TYPE_PCI_PREFETCH_MEM, NDI_RA_PASS);
1850a6469d9bSprasad }
1851a6469d9bSprasad
18527c478bd9Sstevel@tonic-gate if (entry->io_len > 0) {
185300d0963fSdilpreet range[0].size_low = entry->io_last - entry->io_base;
18547c478bd9Sstevel@tonic-gate if (pcicfg_update_ranges_prop(dip, &range[0])) {
18557c478bd9Sstevel@tonic-gate DEBUG0("Failed to update ranges (i/o)\n");
18567c478bd9Sstevel@tonic-gate entry->error = PCICFG_FAILURE;
18571fb5b786Sprasad (void) pcicfg_config_teardown(&handle);
18587c478bd9Sstevel@tonic-gate return (DDI_WALK_TERMINATE);
18597c478bd9Sstevel@tonic-gate }
18607c478bd9Sstevel@tonic-gate }
18617c478bd9Sstevel@tonic-gate if (entry->memory_len > 0) {
186200d0963fSdilpreet range[1].size_low =
186326947304SEvan Yan entry->memory_last - entry->memory_base;
18647c478bd9Sstevel@tonic-gate if (pcicfg_update_ranges_prop(dip, &range[1])) {
18657c478bd9Sstevel@tonic-gate DEBUG0("Failed to update ranges (memory)\n");
18667c478bd9Sstevel@tonic-gate entry->error = PCICFG_FAILURE;
18671fb5b786Sprasad (void) pcicfg_config_teardown(&handle);
18687c478bd9Sstevel@tonic-gate return (DDI_WALK_TERMINATE);
18697c478bd9Sstevel@tonic-gate }
18707c478bd9Sstevel@tonic-gate }
1871a6469d9bSprasad if (entry->pf_memory_len > 0) {
187200d0963fSdilpreet range[2].size_low =
187326947304SEvan Yan entry->pf_memory_last - entry->pf_memory_base;
1874a6469d9bSprasad if (pcicfg_update_ranges_prop(dip, &range[2])) {
1875a6469d9bSprasad DEBUG0("Failed to update ranges (PF memory)\n");
1876a6469d9bSprasad entry->error = PCICFG_FAILURE;
18771fb5b786Sprasad (void) pcicfg_config_teardown(&handle);
1878a6469d9bSprasad return (DDI_WALK_TERMINATE);
1879a6469d9bSprasad }
1880a6469d9bSprasad }
18817c478bd9Sstevel@tonic-gate
18827c478bd9Sstevel@tonic-gate (void) pcicfg_device_on(handle);
18837c478bd9Sstevel@tonic-gate
18847c478bd9Sstevel@tonic-gate PCICFG_DUMP_BRIDGE_CONFIG(handle);
18857c478bd9Sstevel@tonic-gate
18861fb5b786Sprasad (void) pcicfg_config_teardown(&handle);
18871fb5b786Sprasad
18887c478bd9Sstevel@tonic-gate return (DDI_WALK_PRUNECHILD);
18897c478bd9Sstevel@tonic-gate }
18907c478bd9Sstevel@tonic-gate
18917c478bd9Sstevel@tonic-gate /*
18927c478bd9Sstevel@tonic-gate * If there is an interrupt pin set program
18937c478bd9Sstevel@tonic-gate * interrupt line with default values.
18947c478bd9Sstevel@tonic-gate */
18957c478bd9Sstevel@tonic-gate if (pci_config_get8(handle, PCI_CONF_IPIN)) {
18967c478bd9Sstevel@tonic-gate pci_config_put8(handle, PCI_CONF_ILINE, 0xf);
18977c478bd9Sstevel@tonic-gate }
18987c478bd9Sstevel@tonic-gate
18997c478bd9Sstevel@tonic-gate /*
19007c478bd9Sstevel@tonic-gate * A single device (under a bridge).
19017c478bd9Sstevel@tonic-gate * For each "reg" property with a length, allocate memory
19027c478bd9Sstevel@tonic-gate * and program the base registers.
19037c478bd9Sstevel@tonic-gate */
190426947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg",
190526947304SEvan Yan (caddr_t)®, &length) != DDI_PROP_SUCCESS) {
19067c478bd9Sstevel@tonic-gate DEBUG0("Failed to read reg property\n");
19077c478bd9Sstevel@tonic-gate entry->error = PCICFG_FAILURE;
19081fb5b786Sprasad (void) pcicfg_config_teardown(&handle);
19097c478bd9Sstevel@tonic-gate return (DDI_WALK_TERMINATE);
19107c478bd9Sstevel@tonic-gate }
19117c478bd9Sstevel@tonic-gate
19127c478bd9Sstevel@tonic-gate rcount = length / sizeof (pci_regspec_t);
19137c478bd9Sstevel@tonic-gate offset = PCI_CONF_BASE0;
19147c478bd9Sstevel@tonic-gate for (i = 0; i < rcount; i++) {
191526947304SEvan Yan if ((reg[i].pci_size_low != 0) || (reg[i].pci_size_hi != 0)) {
19167c478bd9Sstevel@tonic-gate
19177c478bd9Sstevel@tonic-gate offset = PCI_REG_REG_G(reg[i].pci_phys_hi);
19187c478bd9Sstevel@tonic-gate
19197c478bd9Sstevel@tonic-gate switch (PCI_REG_ADDR_G(reg[i].pci_phys_hi)) {
19207c478bd9Sstevel@tonic-gate case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
19217c478bd9Sstevel@tonic-gate
1922a6469d9bSprasad if (reg[i].pci_phys_hi & PCI_REG_PF_M) {
1923a6469d9bSprasad /* allocate prefetchable memory */
1924a6469d9bSprasad pcicfg_get_pf_mem(entry,
1925a6469d9bSprasad reg[i].pci_size_low, &mem_answer);
1926a6469d9bSprasad } else { /* get non prefetchable memory */
1927a6469d9bSprasad pcicfg_get_mem(entry,
192826947304SEvan Yan reg[i].pci_size_low, &mem_answer);
1929a6469d9bSprasad }
19307c478bd9Sstevel@tonic-gate pci_config_put64(handle, offset, mem_answer);
19317c478bd9Sstevel@tonic-gate DEBUG2("REGISTER off %x (64)LO ----> [0x%x]\n",
193226947304SEvan Yan offset, pci_config_get32(handle, offset));
19337c478bd9Sstevel@tonic-gate DEBUG2("REGISTER off %x (64)HI ----> [0x%x]\n",
193426947304SEvan Yan offset + 4,
193526947304SEvan Yan pci_config_get32(handle, offset + 4));
19367c478bd9Sstevel@tonic-gate
1937a6469d9bSprasad reg[i].pci_phys_hi |= PCI_REG_REL_M;
1938a6469d9bSprasad reg[i].pci_phys_low = PCICFG_LOADDR(mem_answer);
193926947304SEvan Yan reg[i].pci_phys_mid = PCICFG_HIADDR(mem_answer);
19407c478bd9Sstevel@tonic-gate break;
19417c478bd9Sstevel@tonic-gate
19427c478bd9Sstevel@tonic-gate case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
1943a6469d9bSprasad if (reg[i].pci_phys_hi & PCI_REG_PF_M) {
1944a6469d9bSprasad /* allocate prefetchable memory */
1945a6469d9bSprasad pcicfg_get_pf_mem(entry,
1946a6469d9bSprasad reg[i].pci_size_low, &mem_answer);
1947a6469d9bSprasad } else {
1948a6469d9bSprasad /* get non prefetchable memory */
1949a6469d9bSprasad pcicfg_get_mem(entry,
195026947304SEvan Yan reg[i].pci_size_low, &mem_answer);
1951a6469d9bSprasad }
1952a6469d9bSprasad
195326947304SEvan Yan pci_config_put32(handle, offset,
195426947304SEvan Yan (uint32_t)mem_answer);
19557c478bd9Sstevel@tonic-gate
19567c478bd9Sstevel@tonic-gate DEBUG2("REGISTER off %x(32)LO ----> [0x%x]\n",
195726947304SEvan Yan offset, pci_config_get32(handle, offset));
19587c478bd9Sstevel@tonic-gate
1959a6469d9bSprasad reg[i].pci_phys_hi |= PCI_REG_REL_M;
19607c478bd9Sstevel@tonic-gate reg[i].pci_phys_low = (uint32_t)mem_answer;
19617c478bd9Sstevel@tonic-gate
19627c478bd9Sstevel@tonic-gate break;
19637c478bd9Sstevel@tonic-gate case PCI_REG_ADDR_G(PCI_ADDR_IO):
19647c478bd9Sstevel@tonic-gate /* allocate I/O space from the allocator */
19657c478bd9Sstevel@tonic-gate
196626947304SEvan Yan (void) pcicfg_get_io(entry, reg[i].pci_size_low,
196726947304SEvan Yan &io_answer);
19687c478bd9Sstevel@tonic-gate pci_config_put32(handle, offset, io_answer);
19697c478bd9Sstevel@tonic-gate
19707c478bd9Sstevel@tonic-gate DEBUG2("REGISTER off %x (I/O)LO ----> [0x%x]\n",
197126947304SEvan Yan offset, pci_config_get32(handle, offset));
19727c478bd9Sstevel@tonic-gate
1973a6469d9bSprasad reg[i].pci_phys_hi |= PCI_REG_REL_M;
19747c478bd9Sstevel@tonic-gate reg[i].pci_phys_low = io_answer;
19757c478bd9Sstevel@tonic-gate
19767c478bd9Sstevel@tonic-gate break;
19777c478bd9Sstevel@tonic-gate default:
19787c478bd9Sstevel@tonic-gate DEBUG0("Unknown register type\n");
19797c478bd9Sstevel@tonic-gate kmem_free(reg, length);
19807c478bd9Sstevel@tonic-gate (void) pcicfg_config_teardown(&handle);
19817c478bd9Sstevel@tonic-gate entry->error = PCICFG_FAILURE;
19827c478bd9Sstevel@tonic-gate return (DDI_WALK_TERMINATE);
19837c478bd9Sstevel@tonic-gate } /* switch */
19847c478bd9Sstevel@tonic-gate
19857c478bd9Sstevel@tonic-gate /*
19867c478bd9Sstevel@tonic-gate * Now that memory locations are assigned,
19877c478bd9Sstevel@tonic-gate * update the assigned address property.
19887c478bd9Sstevel@tonic-gate */
198926947304SEvan Yan if (pcicfg_update_assigned_prop(dip, ®[i])
199026947304SEvan Yan != PCICFG_SUCCESS) {
19917c478bd9Sstevel@tonic-gate kmem_free(reg, length);
19927c478bd9Sstevel@tonic-gate (void) pcicfg_config_teardown(&handle);
19937c478bd9Sstevel@tonic-gate entry->error = PCICFG_FAILURE;
19947c478bd9Sstevel@tonic-gate return (DDI_WALK_TERMINATE);
19957c478bd9Sstevel@tonic-gate }
19967c478bd9Sstevel@tonic-gate }
19977c478bd9Sstevel@tonic-gate }
19987c478bd9Sstevel@tonic-gate (void) pcicfg_device_on(handle);
19997c478bd9Sstevel@tonic-gate
20007c478bd9Sstevel@tonic-gate PCICFG_DUMP_DEVICE_CONFIG(handle);
20017c478bd9Sstevel@tonic-gate
20027c478bd9Sstevel@tonic-gate (void) pcicfg_config_teardown(&handle);
20037c478bd9Sstevel@tonic-gate kmem_free((caddr_t)reg, length);
20047c478bd9Sstevel@tonic-gate return (DDI_WALK_CONTINUE);
20057c478bd9Sstevel@tonic-gate }
20067c478bd9Sstevel@tonic-gate
20077c478bd9Sstevel@tonic-gate static int
pcicfg_device_assign(dev_info_t * dip)20087c478bd9Sstevel@tonic-gate pcicfg_device_assign(dev_info_t *dip)
20097c478bd9Sstevel@tonic-gate {
20107c478bd9Sstevel@tonic-gate ddi_acc_handle_t handle;
20117c478bd9Sstevel@tonic-gate pci_regspec_t *reg;
20127c478bd9Sstevel@tonic-gate int length;
20137c478bd9Sstevel@tonic-gate int rcount;
20147c478bd9Sstevel@tonic-gate int i;
20157c478bd9Sstevel@tonic-gate int offset;
20167c478bd9Sstevel@tonic-gate ndi_ra_request_t request;
20177c478bd9Sstevel@tonic-gate uint64_t answer;
20187c478bd9Sstevel@tonic-gate uint64_t alen;
20197c478bd9Sstevel@tonic-gate
20207c478bd9Sstevel@tonic-gate DEBUG1("%llx now under configuration\n", dip);
20217c478bd9Sstevel@tonic-gate
20227c478bd9Sstevel@tonic-gate /* request.ra_len = PCICFG_ROUND_UP(request.ra_len, PCICFG_IOGRAN); */
20237c478bd9Sstevel@tonic-gate if (pcicfg_ntbridge_child(dip) == DDI_SUCCESS) {
20247c478bd9Sstevel@tonic-gate
20257c478bd9Sstevel@tonic-gate return (pcicfg_ntbridge_program_child(dip));
20267c478bd9Sstevel@tonic-gate }
20277c478bd9Sstevel@tonic-gate /*
20287c478bd9Sstevel@tonic-gate * XXX Failure here should be noted
20297c478bd9Sstevel@tonic-gate */
203026947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg",
203126947304SEvan Yan (caddr_t)®, &length) != DDI_PROP_SUCCESS) {
20327c478bd9Sstevel@tonic-gate DEBUG0("Failed to read reg property\n");
20337c478bd9Sstevel@tonic-gate return (PCICFG_FAILURE);
20347c478bd9Sstevel@tonic-gate }
20357c478bd9Sstevel@tonic-gate
20367c478bd9Sstevel@tonic-gate if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
20377c478bd9Sstevel@tonic-gate DEBUG0("Failed to map config space!\n");
20381fb5b786Sprasad kmem_free(reg, length);
20397c478bd9Sstevel@tonic-gate return (PCICFG_FAILURE);
20407c478bd9Sstevel@tonic-gate }
20417c478bd9Sstevel@tonic-gate
20427c478bd9Sstevel@tonic-gate /*
20437c478bd9Sstevel@tonic-gate * A single device
20447c478bd9Sstevel@tonic-gate *
20457c478bd9Sstevel@tonic-gate * For each "reg" property with a length, allocate memory
20467c478bd9Sstevel@tonic-gate * and program the base registers.
20477c478bd9Sstevel@tonic-gate */
20487c478bd9Sstevel@tonic-gate
20497c478bd9Sstevel@tonic-gate /*
20507c478bd9Sstevel@tonic-gate * If there is an interrupt pin set program
20517c478bd9Sstevel@tonic-gate * interrupt line with default values.
20527c478bd9Sstevel@tonic-gate */
20537c478bd9Sstevel@tonic-gate if (pci_config_get8(handle, PCI_CONF_IPIN)) {
20547c478bd9Sstevel@tonic-gate pci_config_put8(handle, PCI_CONF_ILINE, 0xf);
20557c478bd9Sstevel@tonic-gate }
20567c478bd9Sstevel@tonic-gate
20577c478bd9Sstevel@tonic-gate bzero((caddr_t)&request, sizeof (ndi_ra_request_t));
20587c478bd9Sstevel@tonic-gate
2059a6469d9bSprasad /*
2060a6469d9bSprasad * Note: Both non-prefetchable and prefetchable memory space
2061a6469d9bSprasad * allocations are made within 32bit space. Currently, BIOSs
2062a6469d9bSprasad * allocate device memory for PCI devices within the 32bit space
2063a6469d9bSprasad * so this will not be a problem.
2064a6469d9bSprasad */
2065a6469d9bSprasad request.ra_flags |= NDI_RA_ALIGN_SIZE | NDI_RA_ALLOC_BOUNDED;
20667c478bd9Sstevel@tonic-gate request.ra_boundbase = 0;
20677c478bd9Sstevel@tonic-gate request.ra_boundlen = PCICFG_4GIG_LIMIT;
20687c478bd9Sstevel@tonic-gate
20697c478bd9Sstevel@tonic-gate rcount = length / sizeof (pci_regspec_t);
20707c478bd9Sstevel@tonic-gate offset = PCI_CONF_BASE0;
20717c478bd9Sstevel@tonic-gate for (i = 0; i < rcount; i++) {
2072a6469d9bSprasad char *mem_type;
2073a6469d9bSprasad
207426947304SEvan Yan if ((reg[i].pci_size_low != 0)|| (reg[i].pci_size_hi != 0)) {
20757c478bd9Sstevel@tonic-gate
20767c478bd9Sstevel@tonic-gate offset = PCI_REG_REG_G(reg[i].pci_phys_hi);
20777c478bd9Sstevel@tonic-gate request.ra_len = reg[i].pci_size_low;
20787c478bd9Sstevel@tonic-gate
20797c478bd9Sstevel@tonic-gate switch (PCI_REG_ADDR_G(reg[i].pci_phys_hi)) {
20807c478bd9Sstevel@tonic-gate case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
2081a6469d9bSprasad if (reg[i].pci_phys_hi & PCI_REG_PF_M) {
208226947304SEvan Yan mem_type = NDI_RA_TYPE_PCI_PREFETCH_MEM;
2083a6469d9bSprasad } else {
208426947304SEvan Yan mem_type = NDI_RA_TYPE_MEM;
2085a6469d9bSprasad }
20867c478bd9Sstevel@tonic-gate /* allocate memory space from the allocator */
208726947304SEvan Yan if (ndi_ra_alloc(ddi_get_parent(dip), &request,
208826947304SEvan Yan &answer, &alen, mem_type, NDI_RA_PASS)
208926947304SEvan Yan != NDI_SUCCESS) {
20907c478bd9Sstevel@tonic-gate DEBUG0("Failed to allocate 64b mem\n");
20917c478bd9Sstevel@tonic-gate kmem_free(reg, length);
20927c478bd9Sstevel@tonic-gate (void) pcicfg_config_teardown(&handle);
20935af4ae46Sjveta return (PCICFG_NORESRC);
20947c478bd9Sstevel@tonic-gate }
2095a6469d9bSprasad DEBUG3("64 addr = [0x%x.0x%x] len [0x%x]\n",
209626947304SEvan Yan PCICFG_HIADDR(answer),
209726947304SEvan Yan PCICFG_LOADDR(answer), alen);
20987c478bd9Sstevel@tonic-gate /* program the low word */
209926947304SEvan Yan pci_config_put32(handle, offset,
210026947304SEvan Yan PCICFG_LOADDR(answer));
2101a6469d9bSprasad /* program the high word */
21027c478bd9Sstevel@tonic-gate pci_config_put32(handle, offset + 4,
210326947304SEvan Yan PCICFG_HIADDR(answer));
21047c478bd9Sstevel@tonic-gate
2105a6469d9bSprasad reg[i].pci_phys_hi |= PCI_REG_REL_M;
21067c478bd9Sstevel@tonic-gate reg[i].pci_phys_low = PCICFG_LOADDR(answer);
21077c478bd9Sstevel@tonic-gate reg[i].pci_phys_mid = PCICFG_HIADDR(answer);
210870025d76Sjohnny /*
210970025d76Sjohnny * currently support 32b address space
211070025d76Sjohnny * assignments only.
211170025d76Sjohnny */
211226947304SEvan Yan reg[i].pci_phys_hi ^=
211326947304SEvan Yan PCI_ADDR_MEM64 ^ PCI_ADDR_MEM32;
21147c478bd9Sstevel@tonic-gate
21157c478bd9Sstevel@tonic-gate offset += 8;
21167c478bd9Sstevel@tonic-gate break;
21177c478bd9Sstevel@tonic-gate
21187c478bd9Sstevel@tonic-gate case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
2119a6469d9bSprasad if (reg[i].pci_phys_hi & PCI_REG_PF_M)
2120a6469d9bSprasad mem_type = NDI_RA_TYPE_PCI_PREFETCH_MEM;
2121a6469d9bSprasad else
2122a6469d9bSprasad mem_type = NDI_RA_TYPE_MEM;
21237c478bd9Sstevel@tonic-gate /* allocate memory space from the allocator */
212426947304SEvan Yan if (ndi_ra_alloc(ddi_get_parent(dip), &request,
212526947304SEvan Yan &answer, &alen, mem_type, NDI_RA_PASS)
212626947304SEvan Yan != NDI_SUCCESS) {
21277c478bd9Sstevel@tonic-gate DEBUG0("Failed to allocate 32b mem\n");
21287c478bd9Sstevel@tonic-gate kmem_free(reg, length);
21297c478bd9Sstevel@tonic-gate (void) pcicfg_config_teardown(&handle);
21305af4ae46Sjveta return (PCICFG_NORESRC);
21317c478bd9Sstevel@tonic-gate }
2132a6469d9bSprasad DEBUG3("32 addr = [0x%x.0x%x] len [0x%x]\n",
213326947304SEvan Yan PCICFG_HIADDR(answer),
213426947304SEvan Yan PCICFG_LOADDR(answer),
213526947304SEvan Yan alen);
21367c478bd9Sstevel@tonic-gate /* program the low word */
213726947304SEvan Yan pci_config_put32(handle, offset,
213826947304SEvan Yan PCICFG_LOADDR(answer));
21397c478bd9Sstevel@tonic-gate
2140a6469d9bSprasad reg[i].pci_phys_hi |= PCI_REG_REL_M;
21417c478bd9Sstevel@tonic-gate reg[i].pci_phys_low = PCICFG_LOADDR(answer);
2142a6469d9bSprasad reg[i].pci_phys_mid = 0;
21437c478bd9Sstevel@tonic-gate
21447c478bd9Sstevel@tonic-gate offset += 4;
21457c478bd9Sstevel@tonic-gate break;
21467c478bd9Sstevel@tonic-gate case PCI_REG_ADDR_G(PCI_ADDR_IO):
2147b9abf428Slipeng sang - Sun Microsystems - Beijing China /*
2148b9abf428Slipeng sang - Sun Microsystems - Beijing China * Try to allocate I/O space. If it fails,
2149b9abf428Slipeng sang - Sun Microsystems - Beijing China * continue here instead of returning failure
2150b9abf428Slipeng sang - Sun Microsystems - Beijing China * so that the hotplug for drivers that don't
2151b9abf428Slipeng sang - Sun Microsystems - Beijing China * use I/O space can succeed, For drivers
2152b9abf428Slipeng sang - Sun Microsystems - Beijing China * that need to use I/O space, the hotplug
2153b9abf428Slipeng sang - Sun Microsystems - Beijing China * will still fail later during driver attach.
2154b9abf428Slipeng sang - Sun Microsystems - Beijing China */
215526947304SEvan Yan if (ndi_ra_alloc(ddi_get_parent(dip), &request,
215626947304SEvan Yan &answer, &alen, NDI_RA_TYPE_IO, NDI_RA_PASS)
215726947304SEvan Yan != NDI_SUCCESS) {
21587c478bd9Sstevel@tonic-gate DEBUG0("Failed to allocate I/O\n");
2159b9abf428Slipeng sang - Sun Microsystems - Beijing China continue;
21607c478bd9Sstevel@tonic-gate }
2161a6469d9bSprasad DEBUG3("I/O addr = [0x%x.0x%x] len [0x%x]\n",
216226947304SEvan Yan PCICFG_HIADDR(answer),
216326947304SEvan Yan PCICFG_LOADDR(answer), alen);
216426947304SEvan Yan pci_config_put32(handle, offset,
216526947304SEvan Yan PCICFG_LOADDR(answer));
21667c478bd9Sstevel@tonic-gate
2167a6469d9bSprasad reg[i].pci_phys_hi |= PCI_REG_REL_M;
21687c478bd9Sstevel@tonic-gate reg[i].pci_phys_low = PCICFG_LOADDR(answer);
21697c478bd9Sstevel@tonic-gate
21707c478bd9Sstevel@tonic-gate offset += 4;
21717c478bd9Sstevel@tonic-gate break;
21727c478bd9Sstevel@tonic-gate default:
21737c478bd9Sstevel@tonic-gate DEBUG0("Unknown register type\n");
21747c478bd9Sstevel@tonic-gate kmem_free(reg, length);
21757c478bd9Sstevel@tonic-gate (void) pcicfg_config_teardown(&handle);
21767c478bd9Sstevel@tonic-gate return (PCICFG_FAILURE);
21777c478bd9Sstevel@tonic-gate } /* switch */
21787c478bd9Sstevel@tonic-gate
21797c478bd9Sstevel@tonic-gate /*
21807c478bd9Sstevel@tonic-gate * Now that memory locations are assigned,
21817c478bd9Sstevel@tonic-gate * update the assigned address property.
21827c478bd9Sstevel@tonic-gate */
21837c478bd9Sstevel@tonic-gate
218426947304SEvan Yan if (pcicfg_update_assigned_prop(dip, ®[i])
218526947304SEvan Yan != PCICFG_SUCCESS) {
21867c478bd9Sstevel@tonic-gate kmem_free(reg, length);
21877c478bd9Sstevel@tonic-gate (void) pcicfg_config_teardown(&handle);
21887c478bd9Sstevel@tonic-gate return (PCICFG_FAILURE);
21897c478bd9Sstevel@tonic-gate }
21907c478bd9Sstevel@tonic-gate }
21917c478bd9Sstevel@tonic-gate }
21927c478bd9Sstevel@tonic-gate
21937c478bd9Sstevel@tonic-gate (void) pcicfg_device_on(handle);
21947c478bd9Sstevel@tonic-gate kmem_free(reg, length);
21957c478bd9Sstevel@tonic-gate
21967c478bd9Sstevel@tonic-gate PCICFG_DUMP_DEVICE_CONFIG(handle);
21977c478bd9Sstevel@tonic-gate
21987c478bd9Sstevel@tonic-gate (void) pcicfg_config_teardown(&handle);
21997c478bd9Sstevel@tonic-gate return (PCICFG_SUCCESS);
22007c478bd9Sstevel@tonic-gate }
22017c478bd9Sstevel@tonic-gate
220226947304SEvan Yan static int
pcicfg_device_assign_readonly(dev_info_t * dip)220326947304SEvan Yan pcicfg_device_assign_readonly(dev_info_t *dip)
220426947304SEvan Yan {
220526947304SEvan Yan ddi_acc_handle_t handle;
220626947304SEvan Yan pci_regspec_t *assigned;
220726947304SEvan Yan int length;
220826947304SEvan Yan int acount;
220926947304SEvan Yan int i;
221026947304SEvan Yan ndi_ra_request_t request;
221126947304SEvan Yan uint64_t answer;
221226947304SEvan Yan uint64_t alen;
221326947304SEvan Yan
221426947304SEvan Yan DEBUG1("%llx now under configuration\n", dip);
221526947304SEvan Yan
221626947304SEvan Yan /*
221726947304SEvan Yan * we don't support ntbridges for readonly probe.
221826947304SEvan Yan */
221926947304SEvan Yan if (pcicfg_ntbridge_child(dip) == DDI_SUCCESS) {
222026947304SEvan Yan return (PCICFG_FAILURE);
222126947304SEvan Yan }
222226947304SEvan Yan
222326947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
222426947304SEvan Yan DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned,
222526947304SEvan Yan &length) != DDI_PROP_SUCCESS) {
222626947304SEvan Yan DEBUG0("Failed to read assigned-addresses property\n");
222726947304SEvan Yan return (PCICFG_FAILURE);
222826947304SEvan Yan }
222926947304SEvan Yan
223026947304SEvan Yan if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
223126947304SEvan Yan DEBUG0("Failed to map config space!\n");
223226947304SEvan Yan kmem_free(assigned, length);
223326947304SEvan Yan return (PCICFG_FAILURE);
223426947304SEvan Yan }
223526947304SEvan Yan
223626947304SEvan Yan /*
223726947304SEvan Yan * If there is an interrupt pin set program
223826947304SEvan Yan * interrupt line with default values.
223926947304SEvan Yan */
224026947304SEvan Yan if (pci_config_get8(handle, PCI_CONF_IPIN)) {
224126947304SEvan Yan pci_config_put8(handle, PCI_CONF_ILINE, 0xf);
224226947304SEvan Yan }
224326947304SEvan Yan /*
224426947304SEvan Yan * Note: Both non-prefetchable and prefetchable memory space
224526947304SEvan Yan * allocations are made within 32bit space. Currently, BIOSs
224626947304SEvan Yan * allocate device memory for PCI devices within the 32bit space
224726947304SEvan Yan * so this will not be a problem.
224826947304SEvan Yan */
224926947304SEvan Yan bzero((caddr_t)&request, sizeof (ndi_ra_request_t));
225026947304SEvan Yan
225126947304SEvan Yan request.ra_flags = NDI_RA_ALLOC_SPECIFIED; /* specified addr */
225226947304SEvan Yan request.ra_boundbase = 0;
225326947304SEvan Yan request.ra_boundlen = PCICFG_4GIG_LIMIT;
225426947304SEvan Yan
225526947304SEvan Yan acount = length / sizeof (pci_regspec_t);
225626947304SEvan Yan for (i = 0; i < acount; i++) {
225726947304SEvan Yan char *mem_type;
225826947304SEvan Yan
225926947304SEvan Yan if ((assigned[i].pci_size_low != 0)||
226026947304SEvan Yan (assigned[i].pci_size_hi != 0)) {
226126947304SEvan Yan
226226947304SEvan Yan request.ra_len = assigned[i].pci_size_low;
226326947304SEvan Yan
226426947304SEvan Yan switch (PCI_REG_ADDR_G(assigned[i].pci_phys_hi)) {
226526947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
226626947304SEvan Yan request.ra_addr = (uint64_t)PCICFG_LADDR(
226726947304SEvan Yan assigned[i].pci_phys_low,
226826947304SEvan Yan assigned[i].pci_phys_mid);
226926947304SEvan Yan
227026947304SEvan Yan if (assigned[i].pci_phys_hi & PCI_REG_PF_M) {
227126947304SEvan Yan mem_type = NDI_RA_TYPE_PCI_PREFETCH_MEM;
227226947304SEvan Yan } else {
227326947304SEvan Yan mem_type = NDI_RA_TYPE_MEM;
227426947304SEvan Yan }
227526947304SEvan Yan /* allocate memory space from the allocator */
227626947304SEvan Yan if (ndi_ra_alloc(ddi_get_parent(dip), &request,
227726947304SEvan Yan &answer, &alen, mem_type, NDI_RA_PASS)
227826947304SEvan Yan != NDI_SUCCESS) {
227926947304SEvan Yan DEBUG0("Failed to allocate 64b mem\n");
228026947304SEvan Yan kmem_free(assigned, length);
228126947304SEvan Yan return (PCICFG_NORESRC);
228226947304SEvan Yan }
228326947304SEvan Yan
228426947304SEvan Yan break;
228526947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
228626947304SEvan Yan request.ra_addr = (uint64_t)
228726947304SEvan Yan assigned[i].pci_phys_low;
228826947304SEvan Yan
228926947304SEvan Yan if (assigned[i].pci_phys_hi & PCI_REG_PF_M)
229026947304SEvan Yan mem_type = NDI_RA_TYPE_PCI_PREFETCH_MEM;
229126947304SEvan Yan else
229226947304SEvan Yan mem_type = NDI_RA_TYPE_MEM;
229326947304SEvan Yan /* allocate memory space from the allocator */
229426947304SEvan Yan if (ndi_ra_alloc(ddi_get_parent(dip), &request,
229526947304SEvan Yan &answer, &alen, mem_type, NDI_RA_PASS)
229626947304SEvan Yan != NDI_SUCCESS) {
229726947304SEvan Yan DEBUG0("Failed to allocate 32b mem\n");
229826947304SEvan Yan kmem_free(assigned, length);
229926947304SEvan Yan return (PCICFG_NORESRC);
230026947304SEvan Yan }
230126947304SEvan Yan
230226947304SEvan Yan break;
230326947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_IO):
230426947304SEvan Yan request.ra_addr = (uint64_t)
230526947304SEvan Yan assigned[i].pci_phys_low;
230626947304SEvan Yan
230726947304SEvan Yan /* allocate I/O space from the allocator */
230826947304SEvan Yan if (ndi_ra_alloc(ddi_get_parent(dip), &request,
230926947304SEvan Yan &answer, &alen, NDI_RA_TYPE_IO, NDI_RA_PASS)
231026947304SEvan Yan != NDI_SUCCESS) {
231126947304SEvan Yan DEBUG0("Failed to allocate I/O\n");
231226947304SEvan Yan kmem_free(assigned, length);
231326947304SEvan Yan return (PCICFG_NORESRC);
231426947304SEvan Yan }
231526947304SEvan Yan
231626947304SEvan Yan break;
231726947304SEvan Yan default:
231826947304SEvan Yan DEBUG0("Unknown register type\n");
231926947304SEvan Yan kmem_free(assigned, length);
232026947304SEvan Yan return (PCICFG_FAILURE);
232126947304SEvan Yan } /* switch */
232226947304SEvan Yan }
232326947304SEvan Yan }
232426947304SEvan Yan
232526947304SEvan Yan (void) pcicfg_device_on(handle);
232626947304SEvan Yan kmem_free(assigned, length);
232726947304SEvan Yan
232826947304SEvan Yan PCICFG_DUMP_DEVICE_CONFIG(handle);
232926947304SEvan Yan
233026947304SEvan Yan (void) pcicfg_config_teardown(&handle);
233126947304SEvan Yan return (PCICFG_SUCCESS);
233226947304SEvan Yan }
233326947304SEvan Yan
23347c478bd9Sstevel@tonic-gate #ifdef DEBUG
23357c478bd9Sstevel@tonic-gate /*
23367c478bd9Sstevel@tonic-gate * This function is useful in debug mode, where we can measure how
23377c478bd9Sstevel@tonic-gate * much memory was wasted/unallocated in bridge device's domain.
23387c478bd9Sstevel@tonic-gate */
23397c478bd9Sstevel@tonic-gate static uint64_t
pcicfg_unused_space(hole_t * hole,uint32_t * hole_count)23407c478bd9Sstevel@tonic-gate pcicfg_unused_space(hole_t *hole, uint32_t *hole_count)
23417c478bd9Sstevel@tonic-gate {
23427c478bd9Sstevel@tonic-gate uint64_t len = 0;
23437c478bd9Sstevel@tonic-gate uint32_t count = 0;
23447c478bd9Sstevel@tonic-gate
23457c478bd9Sstevel@tonic-gate do {
23467c478bd9Sstevel@tonic-gate len += hole->len;
23477c478bd9Sstevel@tonic-gate hole = hole->next;
23487c478bd9Sstevel@tonic-gate count++;
23497c478bd9Sstevel@tonic-gate } while (hole);
23507c478bd9Sstevel@tonic-gate *hole_count = count;
23517c478bd9Sstevel@tonic-gate return (len);
23527c478bd9Sstevel@tonic-gate }
23537c478bd9Sstevel@tonic-gate #endif
23547c478bd9Sstevel@tonic-gate
23557c478bd9Sstevel@tonic-gate /*
23567c478bd9Sstevel@tonic-gate * This function frees data structures that hold the hole information
23577c478bd9Sstevel@tonic-gate * which are allocated in pcicfg_alloc_hole(). This is not freeing
23587c478bd9Sstevel@tonic-gate * any memory allocated through NDI calls.
23597c478bd9Sstevel@tonic-gate */
23607c478bd9Sstevel@tonic-gate static void
pcicfg_free_hole(hole_t * addr_hole)23617c478bd9Sstevel@tonic-gate pcicfg_free_hole(hole_t *addr_hole)
23627c478bd9Sstevel@tonic-gate {
23637c478bd9Sstevel@tonic-gate hole_t *nhole, *hole = addr_hole->next;
23647c478bd9Sstevel@tonic-gate
23657c478bd9Sstevel@tonic-gate while (hole) {
23667c478bd9Sstevel@tonic-gate nhole = hole->next;
23677c478bd9Sstevel@tonic-gate kmem_free(hole, sizeof (hole_t));
23687c478bd9Sstevel@tonic-gate hole = nhole;
23697c478bd9Sstevel@tonic-gate }
23707c478bd9Sstevel@tonic-gate }
23717c478bd9Sstevel@tonic-gate
23727c478bd9Sstevel@tonic-gate static uint64_t
pcicfg_alloc_hole(hole_t * addr_hole,uint64_t * alast,uint32_t length)23737c478bd9Sstevel@tonic-gate pcicfg_alloc_hole(hole_t *addr_hole, uint64_t *alast, uint32_t length)
23747c478bd9Sstevel@tonic-gate {
23757c478bd9Sstevel@tonic-gate uint64_t actual_hole_start, ostart, olen;
23767c478bd9Sstevel@tonic-gate hole_t *hole = addr_hole, *thole, *nhole;
23777c478bd9Sstevel@tonic-gate
23787c478bd9Sstevel@tonic-gate do {
23797c478bd9Sstevel@tonic-gate actual_hole_start = PCICFG_ROUND_UP(hole->start, length);
23807c478bd9Sstevel@tonic-gate if (((actual_hole_start - hole->start) + length) <= hole->len) {
2381a6469d9bSprasad DEBUG3("hole found. start %llx, len %llx, req=0x%x\n",
238226947304SEvan Yan hole->start, hole->len, length);
23837c478bd9Sstevel@tonic-gate ostart = hole->start;
23847c478bd9Sstevel@tonic-gate olen = hole->len;
23857c478bd9Sstevel@tonic-gate /* current hole parameters adjust */
23867c478bd9Sstevel@tonic-gate if ((actual_hole_start - hole->start) == 0) {
23877c478bd9Sstevel@tonic-gate hole->start += length;
23887c478bd9Sstevel@tonic-gate hole->len -= length;
23897c478bd9Sstevel@tonic-gate if (hole->start > *alast)
23907c478bd9Sstevel@tonic-gate *alast = hole->start;
23917c478bd9Sstevel@tonic-gate } else {
23927c478bd9Sstevel@tonic-gate hole->len = actual_hole_start - hole->start;
23937c478bd9Sstevel@tonic-gate nhole = (hole_t *)kmem_zalloc(sizeof (hole_t),
239426947304SEvan Yan KM_SLEEP);
23957c478bd9Sstevel@tonic-gate nhole->start = actual_hole_start + length;
23967c478bd9Sstevel@tonic-gate nhole->len = (ostart + olen) - nhole->start;
23977c478bd9Sstevel@tonic-gate nhole->next = NULL;
23987c478bd9Sstevel@tonic-gate thole = hole->next;
23997c478bd9Sstevel@tonic-gate hole->next = nhole;
24007c478bd9Sstevel@tonic-gate nhole->next = thole;
24017c478bd9Sstevel@tonic-gate if (nhole->start > *alast)
24027c478bd9Sstevel@tonic-gate *alast = nhole->start;
24037c478bd9Sstevel@tonic-gate DEBUG2("put new hole to %llx, %llx\n",
240426947304SEvan Yan nhole->start, nhole->len);
24057c478bd9Sstevel@tonic-gate }
24067c478bd9Sstevel@tonic-gate DEBUG2("adjust current hole to %llx, %llx\n",
240726947304SEvan Yan hole->start, hole->len);
24087c478bd9Sstevel@tonic-gate break;
24097c478bd9Sstevel@tonic-gate }
24107c478bd9Sstevel@tonic-gate actual_hole_start = 0;
24117c478bd9Sstevel@tonic-gate hole = hole->next;
24127c478bd9Sstevel@tonic-gate } while (hole);
24137c478bd9Sstevel@tonic-gate
24147c478bd9Sstevel@tonic-gate DEBUG1("return hole at %llx\n", actual_hole_start);
24157c478bd9Sstevel@tonic-gate return (actual_hole_start);
24167c478bd9Sstevel@tonic-gate }
24177c478bd9Sstevel@tonic-gate
24187c478bd9Sstevel@tonic-gate static void
pcicfg_get_mem(pcicfg_phdl_t * entry,uint32_t length,uint64_t * ans)241926947304SEvan Yan pcicfg_get_mem(pcicfg_phdl_t *entry, uint32_t length, uint64_t *ans)
24207c478bd9Sstevel@tonic-gate {
24217c478bd9Sstevel@tonic-gate uint64_t new_mem;
24227c478bd9Sstevel@tonic-gate
24237c478bd9Sstevel@tonic-gate /* See if there is a hole, that can hold this request. */
24247c478bd9Sstevel@tonic-gate new_mem = pcicfg_alloc_hole(&entry->mem_hole, &entry->memory_last,
242526947304SEvan Yan length);
24267c478bd9Sstevel@tonic-gate if (new_mem) { /* if non-zero, found a hole. */
24277c478bd9Sstevel@tonic-gate if (ans != NULL)
24287c478bd9Sstevel@tonic-gate *ans = new_mem;
24297c478bd9Sstevel@tonic-gate } else
24307c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "No %u bytes memory window for %s\n",
243126947304SEvan Yan length, ddi_get_name(entry->dip));
24327c478bd9Sstevel@tonic-gate }
24337c478bd9Sstevel@tonic-gate
24347c478bd9Sstevel@tonic-gate static void
pcicfg_get_io(pcicfg_phdl_t * entry,uint32_t length,uint32_t * ans)2435ffb64830SJordan Paige Hendricks pcicfg_get_io(pcicfg_phdl_t *entry, uint32_t length, uint32_t *ans)
24367c478bd9Sstevel@tonic-gate {
24377c478bd9Sstevel@tonic-gate uint32_t new_io;
24387c478bd9Sstevel@tonic-gate uint64_t io_last;
24397c478bd9Sstevel@tonic-gate
24407c478bd9Sstevel@tonic-gate /*
24417c478bd9Sstevel@tonic-gate * See if there is a hole, that can hold this request.
24427c478bd9Sstevel@tonic-gate * Pass 64 bit parameters and then truncate to 32 bit.
24437c478bd9Sstevel@tonic-gate */
24447c478bd9Sstevel@tonic-gate io_last = entry->io_last;
24457c478bd9Sstevel@tonic-gate new_io = (uint32_t)pcicfg_alloc_hole(&entry->io_hole, &io_last, length);
24467c478bd9Sstevel@tonic-gate if (new_io) { /* if non-zero, found a hole. */
24477c478bd9Sstevel@tonic-gate entry->io_last = (uint32_t)io_last;
24487c478bd9Sstevel@tonic-gate if (ans != NULL)
24497c478bd9Sstevel@tonic-gate *ans = new_io;
24507c478bd9Sstevel@tonic-gate } else
24517c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "No %u bytes IO space window for %s\n",
245226947304SEvan Yan length, ddi_get_name(entry->dip));
24537c478bd9Sstevel@tonic-gate }
24547c478bd9Sstevel@tonic-gate
2455a6469d9bSprasad static void
pcicfg_get_pf_mem(pcicfg_phdl_t * entry,uint32_t length,uint64_t * ans)245626947304SEvan Yan pcicfg_get_pf_mem(pcicfg_phdl_t *entry, uint32_t length, uint64_t *ans)
2457a6469d9bSprasad {
2458a6469d9bSprasad uint64_t new_mem;
2459a6469d9bSprasad
2460a6469d9bSprasad /* See if there is a hole, that can hold this request. */
2461a6469d9bSprasad new_mem = pcicfg_alloc_hole(&entry->pf_mem_hole, &entry->pf_memory_last,
246226947304SEvan Yan length);
2463a6469d9bSprasad if (new_mem) { /* if non-zero, found a hole. */
2464a6469d9bSprasad if (ans != NULL)
2465a6469d9bSprasad *ans = new_mem;
2466a6469d9bSprasad } else
2467a6469d9bSprasad cmn_err(CE_WARN, "No %u bytes PF memory window for %s\n",
246826947304SEvan Yan length, ddi_get_name(entry->dip));
2469a6469d9bSprasad }
2470a6469d9bSprasad
2471ae5a8bedSAndy Fiddaman #ifdef __sparc
24727c478bd9Sstevel@tonic-gate static int
pcicfg_sum_resources(dev_info_t * dip,void * hdl)24737c478bd9Sstevel@tonic-gate pcicfg_sum_resources(dev_info_t *dip, void *hdl)
24747c478bd9Sstevel@tonic-gate {
24757c478bd9Sstevel@tonic-gate pcicfg_phdl_t *entry = (pcicfg_phdl_t *)hdl;
24767c478bd9Sstevel@tonic-gate pci_regspec_t *pci_rp;
24777c478bd9Sstevel@tonic-gate int length;
24787c478bd9Sstevel@tonic-gate int rcount;
24797c478bd9Sstevel@tonic-gate int i;
2480a6469d9bSprasad ndi_ra_request_t *pf_mem_request;
24817c478bd9Sstevel@tonic-gate ndi_ra_request_t *mem_request;
24827c478bd9Sstevel@tonic-gate ndi_ra_request_t *io_request;
24837c478bd9Sstevel@tonic-gate uint8_t header_type;
24847c478bd9Sstevel@tonic-gate ddi_acc_handle_t handle;
24857c478bd9Sstevel@tonic-gate
24867c478bd9Sstevel@tonic-gate entry->error = PCICFG_SUCCESS;
24877c478bd9Sstevel@tonic-gate
2488a6469d9bSprasad pf_mem_request = &entry->pf_mem_req;
24897c478bd9Sstevel@tonic-gate mem_request = &entry->mem_req;
24907c478bd9Sstevel@tonic-gate io_request = &entry->io_req;
24917c478bd9Sstevel@tonic-gate
24927c478bd9Sstevel@tonic-gate if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
24937c478bd9Sstevel@tonic-gate DEBUG0("Failed to map config space!\n");
24947c478bd9Sstevel@tonic-gate entry->error = PCICFG_FAILURE;
24957c478bd9Sstevel@tonic-gate return (DDI_WALK_TERMINATE);
24967c478bd9Sstevel@tonic-gate }
24977c478bd9Sstevel@tonic-gate
24987c478bd9Sstevel@tonic-gate header_type = pci_config_get8(handle, PCI_CONF_HEADER);
24997c478bd9Sstevel@tonic-gate
25007c478bd9Sstevel@tonic-gate /*
25017c478bd9Sstevel@tonic-gate * If its a bridge - just record the highest bus seen
25027c478bd9Sstevel@tonic-gate */
25037c478bd9Sstevel@tonic-gate if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
25047c478bd9Sstevel@tonic-gate
25057c478bd9Sstevel@tonic-gate if (entry->highest_bus < pci_config_get8(handle,
250626947304SEvan Yan PCI_BCNF_SECBUS)) {
25077c478bd9Sstevel@tonic-gate entry->highest_bus =
250826947304SEvan Yan pci_config_get8(handle, PCI_BCNF_SECBUS);
25097c478bd9Sstevel@tonic-gate }
25107c478bd9Sstevel@tonic-gate (void) pcicfg_config_teardown(&handle);
25117c478bd9Sstevel@tonic-gate entry->error = PCICFG_FAILURE;
25127c478bd9Sstevel@tonic-gate return (DDI_WALK_CONTINUE);
25137c478bd9Sstevel@tonic-gate } else {
251426947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
251526947304SEvan Yan "reg", (caddr_t)&pci_rp, &length) != DDI_PROP_SUCCESS) {
25167c478bd9Sstevel@tonic-gate /*
25177c478bd9Sstevel@tonic-gate * If one node in (the subtree of nodes)
25187c478bd9Sstevel@tonic-gate * doesn't have a "reg" property fail the
25197c478bd9Sstevel@tonic-gate * allocation.
25207c478bd9Sstevel@tonic-gate */
25217c478bd9Sstevel@tonic-gate entry->memory_len = 0;
25227c478bd9Sstevel@tonic-gate entry->io_len = 0;
2523a6469d9bSprasad entry->pf_memory_len = 0;
25247c478bd9Sstevel@tonic-gate entry->error = PCICFG_FAILURE;
25251fb5b786Sprasad (void) pcicfg_config_teardown(&handle);
25267c478bd9Sstevel@tonic-gate return (DDI_WALK_TERMINATE);
25277c478bd9Sstevel@tonic-gate }
25287c478bd9Sstevel@tonic-gate /*
25297c478bd9Sstevel@tonic-gate * For each "reg" property with a length, add that to the
25307c478bd9Sstevel@tonic-gate * total memory (or I/O) to allocate.
25317c478bd9Sstevel@tonic-gate */
25327c478bd9Sstevel@tonic-gate rcount = length / sizeof (pci_regspec_t);
25337c478bd9Sstevel@tonic-gate
25347c478bd9Sstevel@tonic-gate for (i = 0; i < rcount; i++) {
25357c478bd9Sstevel@tonic-gate
25367c478bd9Sstevel@tonic-gate switch (PCI_REG_ADDR_G(pci_rp[i].pci_phys_hi)) {
25377c478bd9Sstevel@tonic-gate
25387c478bd9Sstevel@tonic-gate case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
2539a6469d9bSprasad if (pci_rp[i].pci_phys_hi & PCI_REG_PF_M) {
254026947304SEvan Yan pf_mem_request->ra_len =
254126947304SEvan Yan pci_rp[i].pci_size_low +
254226947304SEvan Yan PCICFG_ROUND_UP(
254326947304SEvan Yan pf_mem_request->ra_len,
254426947304SEvan Yan pci_rp[i].pci_size_low);
254526947304SEvan Yan DEBUG1("ADDING 32 --->0x%x\n",
254626947304SEvan Yan pci_rp[i].pci_size_low);
2547a6469d9bSprasad } else {
254826947304SEvan Yan mem_request->ra_len =
254926947304SEvan Yan pci_rp[i].pci_size_low +
255026947304SEvan Yan PCICFG_ROUND_UP(mem_request->ra_len,
255126947304SEvan Yan pci_rp[i].pci_size_low);
255226947304SEvan Yan DEBUG1("ADDING 32 --->0x%x\n",
255326947304SEvan Yan pci_rp[i].pci_size_low);
2554a6469d9bSprasad }
25557c478bd9Sstevel@tonic-gate
255626947304SEvan Yan break;
25577c478bd9Sstevel@tonic-gate case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
2558a6469d9bSprasad if (pci_rp[i].pci_phys_hi & PCI_REG_PF_M) {
255926947304SEvan Yan pf_mem_request->ra_len =
256026947304SEvan Yan pci_rp[i].pci_size_low +
256126947304SEvan Yan PCICFG_ROUND_UP(
256226947304SEvan Yan pf_mem_request->ra_len,
256326947304SEvan Yan pci_rp[i].pci_size_low);
256426947304SEvan Yan DEBUG1("ADDING 64 --->0x%x\n",
256526947304SEvan Yan pci_rp[i].pci_size_low);
2566a6469d9bSprasad } else {
256726947304SEvan Yan mem_request->ra_len =
256826947304SEvan Yan pci_rp[i].pci_size_low +
256926947304SEvan Yan PCICFG_ROUND_UP(mem_request->ra_len,
257026947304SEvan Yan pci_rp[i].pci_size_low);
257126947304SEvan Yan DEBUG1("ADDING 64 --->0x%x\n",
257226947304SEvan Yan pci_rp[i].pci_size_low);
2573a6469d9bSprasad }
25747c478bd9Sstevel@tonic-gate
257526947304SEvan Yan break;
25767c478bd9Sstevel@tonic-gate case PCI_REG_ADDR_G(PCI_ADDR_IO):
25777c478bd9Sstevel@tonic-gate io_request->ra_len =
257826947304SEvan Yan pci_rp[i].pci_size_low +
257926947304SEvan Yan PCICFG_ROUND_UP(io_request->ra_len,
258026947304SEvan Yan pci_rp[i].pci_size_low);
25817c478bd9Sstevel@tonic-gate DEBUG1("ADDING I/O --->0x%x\n",
258226947304SEvan Yan pci_rp[i].pci_size_low);
258326947304SEvan Yan break;
25847c478bd9Sstevel@tonic-gate default:
258526947304SEvan Yan /* Config space register - not included */
258626947304SEvan Yan break;
25877c478bd9Sstevel@tonic-gate }
25887c478bd9Sstevel@tonic-gate }
25897c478bd9Sstevel@tonic-gate
25907c478bd9Sstevel@tonic-gate /*
25917c478bd9Sstevel@tonic-gate * free the memory allocated by ddi_getlongprop
25927c478bd9Sstevel@tonic-gate */
25937c478bd9Sstevel@tonic-gate kmem_free(pci_rp, length);
25947c478bd9Sstevel@tonic-gate
25957c478bd9Sstevel@tonic-gate /*
25967c478bd9Sstevel@tonic-gate * continue the walk to the next sibling to sum memory
25977c478bd9Sstevel@tonic-gate */
25987c478bd9Sstevel@tonic-gate
25997c478bd9Sstevel@tonic-gate (void) pcicfg_config_teardown(&handle);
26007c478bd9Sstevel@tonic-gate
26017c478bd9Sstevel@tonic-gate return (DDI_WALK_CONTINUE);
26027c478bd9Sstevel@tonic-gate }
26037c478bd9Sstevel@tonic-gate }
2604ae5a8bedSAndy Fiddaman #endif /* __sparc */
26057c478bd9Sstevel@tonic-gate
26067c478bd9Sstevel@tonic-gate static int
pcicfg_free_bridge_resources(dev_info_t * dip)26077c478bd9Sstevel@tonic-gate pcicfg_free_bridge_resources(dev_info_t *dip)
26087c478bd9Sstevel@tonic-gate {
260900d0963fSdilpreet ppb_ranges_t *ranges;
26107c478bd9Sstevel@tonic-gate uint_t *bus;
26117c478bd9Sstevel@tonic-gate int k;
26121fb5b786Sprasad int length = 0;
26137c478bd9Sstevel@tonic-gate int i;
26147c478bd9Sstevel@tonic-gate
26157c478bd9Sstevel@tonic-gate
261626947304SEvan Yan if ((i = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
261726947304SEvan Yan "ranges", (caddr_t)&ranges, &length)) != DDI_PROP_SUCCESS) {
26187c478bd9Sstevel@tonic-gate DEBUG0("Failed to read ranges property\n");
261970025d76Sjohnny if (ddi_get_child(dip)) {
262070025d76Sjohnny cmn_err(CE_WARN, "No ranges property found for %s",
262126947304SEvan Yan ddi_get_name(dip));
262270025d76Sjohnny /*
262370025d76Sjohnny * strictly speaking, we can check for children with
262470025d76Sjohnny * assigned-addresses but for now it is better to
262570025d76Sjohnny * be conservative and assume that if there are child
262670025d76Sjohnny * nodes, then they do consume PCI memory or IO
262770025d76Sjohnny * resources, Hence return failure.
262870025d76Sjohnny */
262970025d76Sjohnny return (PCICFG_FAILURE);
263070025d76Sjohnny }
263170025d76Sjohnny length = 0;
26327c478bd9Sstevel@tonic-gate }
26337c478bd9Sstevel@tonic-gate
263400d0963fSdilpreet for (i = 0; i < length / sizeof (ppb_ranges_t); i++) {
2635a6469d9bSprasad char *mem_type;
2636a6469d9bSprasad
263726947304SEvan Yan if (ranges[i].size_low != 0 || ranges[i].size_high != 0) {
263800d0963fSdilpreet switch (ranges[i].parent_high & PCI_REG_ADDR_M) {
263926947304SEvan Yan case PCI_ADDR_IO:
264026947304SEvan Yan DEBUG2("Free I/O base/length = "
264126947304SEvan Yan "[0x%x]/[0x%x]\n", ranges[i].child_low,
264226947304SEvan Yan ranges[i].size_low);
264326947304SEvan Yan if (ndi_ra_free(ddi_get_parent(dip),
264426947304SEvan Yan (uint64_t)ranges[i].child_low,
264526947304SEvan Yan (uint64_t)ranges[i].size_low,
264626947304SEvan Yan NDI_RA_TYPE_IO, NDI_RA_PASS)
264726947304SEvan Yan != NDI_SUCCESS) {
264826947304SEvan Yan DEBUG0("Trouble freeing "
264926947304SEvan Yan "PCI i/o space\n");
265026947304SEvan Yan kmem_free(ranges, length);
265126947304SEvan Yan return (PCICFG_FAILURE);
265226947304SEvan Yan }
26537c478bd9Sstevel@tonic-gate break;
265426947304SEvan Yan case PCI_ADDR_MEM32:
265526947304SEvan Yan case PCI_ADDR_MEM64:
265626947304SEvan Yan if (ranges[i].parent_high & PCI_REG_PF_M) {
265726947304SEvan Yan DEBUG3("Free PF Memory base/length = "
265826947304SEvan Yan "[0x%x.0x%x]/[0x%x]\n",
265926947304SEvan Yan ranges[i].child_mid,
266026947304SEvan Yan ranges[i].child_low,
266126947304SEvan Yan ranges[i].size_low);
2662a6469d9bSprasad mem_type = NDI_RA_TYPE_PCI_PREFETCH_MEM;
266326947304SEvan Yan } else {
2664a6469d9bSprasad DEBUG3("Free Memory base/length"
266526947304SEvan Yan " = [0x%x.0x%x]/[0x%x]\n",
266626947304SEvan Yan ranges[i].child_mid,
266726947304SEvan Yan ranges[i].child_low,
266826947304SEvan Yan ranges[i].size_low)
2669a6469d9bSprasad mem_type = NDI_RA_TYPE_MEM;
267026947304SEvan Yan }
267126947304SEvan Yan if (ndi_ra_free(ddi_get_parent(dip),
267226947304SEvan Yan PCICFG_LADDR(ranges[i].child_low,
267326947304SEvan Yan ranges[i].child_mid),
267426947304SEvan Yan (uint64_t)ranges[i].size_low,
267526947304SEvan Yan mem_type, NDI_RA_PASS) != NDI_SUCCESS) {
267626947304SEvan Yan DEBUG0("Trouble freeing "
267726947304SEvan Yan "PCI memory space\n");
267826947304SEvan Yan kmem_free(ranges, length);
267926947304SEvan Yan return (PCICFG_FAILURE);
268026947304SEvan Yan }
26817c478bd9Sstevel@tonic-gate break;
268226947304SEvan Yan default:
268326947304SEvan Yan DEBUG0("Unknown memory space\n");
26847c478bd9Sstevel@tonic-gate break;
26857c478bd9Sstevel@tonic-gate }
26867c478bd9Sstevel@tonic-gate }
26877c478bd9Sstevel@tonic-gate }
26887c478bd9Sstevel@tonic-gate
268970025d76Sjohnny if (length)
269070025d76Sjohnny kmem_free(ranges, length);
26917c478bd9Sstevel@tonic-gate
269226947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
269326947304SEvan Yan "bus-range", (caddr_t)&bus, &k) != DDI_PROP_SUCCESS) {
26947c478bd9Sstevel@tonic-gate DEBUG0("Failed to read bus-range property\n");
26957c478bd9Sstevel@tonic-gate return (PCICFG_FAILURE);
26967c478bd9Sstevel@tonic-gate }
26977c478bd9Sstevel@tonic-gate
26987c478bd9Sstevel@tonic-gate DEBUG2("Need to free bus [%d] range [%d]\n",
269926947304SEvan Yan bus[0], bus[1] - bus[0] + 1);
27007c478bd9Sstevel@tonic-gate
270126947304SEvan Yan if (ndi_ra_free(ddi_get_parent(dip), (uint64_t)bus[0],
270226947304SEvan Yan (uint64_t)(bus[1] - bus[0] + 1), NDI_RA_TYPE_PCI_BUSNUM,
270326947304SEvan Yan NDI_RA_PASS) != NDI_SUCCESS) {
27047c478bd9Sstevel@tonic-gate DEBUG0("Failed to free a bus number\n");
27051fb5b786Sprasad kmem_free(bus, k);
27067c478bd9Sstevel@tonic-gate return (PCICFG_FAILURE);
27077c478bd9Sstevel@tonic-gate }
27081fb5b786Sprasad
27091fb5b786Sprasad kmem_free(bus, k);
27107c478bd9Sstevel@tonic-gate return (PCICFG_SUCCESS);
27117c478bd9Sstevel@tonic-gate }
27127c478bd9Sstevel@tonic-gate
27137c478bd9Sstevel@tonic-gate static int
pcicfg_free_device_resources(dev_info_t * dip)27147c478bd9Sstevel@tonic-gate pcicfg_free_device_resources(dev_info_t *dip)
27157c478bd9Sstevel@tonic-gate {
27167c478bd9Sstevel@tonic-gate pci_regspec_t *assigned;
27177c478bd9Sstevel@tonic-gate
27187c478bd9Sstevel@tonic-gate int length;
27197c478bd9Sstevel@tonic-gate int acount;
27207c478bd9Sstevel@tonic-gate int i;
27217c478bd9Sstevel@tonic-gate
272226947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
272326947304SEvan Yan "assigned-addresses", (caddr_t)&assigned, &length)
272426947304SEvan Yan != DDI_PROP_SUCCESS) {
27257c478bd9Sstevel@tonic-gate DEBUG0("Failed to read assigned-addresses property\n");
27267c478bd9Sstevel@tonic-gate return (PCICFG_FAILURE);
27277c478bd9Sstevel@tonic-gate }
27287c478bd9Sstevel@tonic-gate
27297c478bd9Sstevel@tonic-gate /*
27307c478bd9Sstevel@tonic-gate * For each "assigned-addresses" property entry with a length,
27317c478bd9Sstevel@tonic-gate * call the memory allocation routines to return the
27327c478bd9Sstevel@tonic-gate * resource.
27337c478bd9Sstevel@tonic-gate */
27347c478bd9Sstevel@tonic-gate acount = length / sizeof (pci_regspec_t);
27357c478bd9Sstevel@tonic-gate for (i = 0; i < acount; i++) {
2736a6469d9bSprasad char *mem_type;
2737a6469d9bSprasad
27387c478bd9Sstevel@tonic-gate /*
27397c478bd9Sstevel@tonic-gate * Free the resource if the size of it is not zero.
27407c478bd9Sstevel@tonic-gate */
27417c478bd9Sstevel@tonic-gate if ((assigned[i].pci_size_low != 0)||
274226947304SEvan Yan (assigned[i].pci_size_hi != 0)) {
27437c478bd9Sstevel@tonic-gate switch (PCI_REG_ADDR_G(assigned[i].pci_phys_hi)) {
27447c478bd9Sstevel@tonic-gate case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
27457c478bd9Sstevel@tonic-gate /*
27467c478bd9Sstevel@tonic-gate * Check the assigned address for zero.
27477c478bd9Sstevel@tonic-gate * (Workaround for Devconf (x86) bug to
27487c478bd9Sstevel@tonic-gate * skip bogus entry for ROM base address
27497c478bd9Sstevel@tonic-gate * register. If the assigned address is
27507c478bd9Sstevel@tonic-gate * zero then ignore the entry
27517c478bd9Sstevel@tonic-gate * (see bugid 4281306)).
27527c478bd9Sstevel@tonic-gate */
27537c478bd9Sstevel@tonic-gate if (assigned[i].pci_phys_low == 0)
27547c478bd9Sstevel@tonic-gate break; /* ignore the entry */
27557c478bd9Sstevel@tonic-gate
2756a6469d9bSprasad if (assigned[i].pci_phys_hi & PCI_REG_PF_M)
2757a6469d9bSprasad mem_type = NDI_RA_TYPE_PCI_PREFETCH_MEM;
2758a6469d9bSprasad else
2759a6469d9bSprasad mem_type = NDI_RA_TYPE_MEM;
2760a6469d9bSprasad
27617c478bd9Sstevel@tonic-gate if (ndi_ra_free(ddi_get_parent(dip),
27621fb5b786Sprasad (uint64_t)assigned[i].pci_phys_low,
27631fb5b786Sprasad (uint64_t)assigned[i].pci_size_low,
27641fb5b786Sprasad mem_type, NDI_RA_PASS) != NDI_SUCCESS) {
27651fb5b786Sprasad DEBUG0("Trouble freeing "
276626947304SEvan Yan "PCI memory space\n");
27671fb5b786Sprasad kmem_free(assigned, length);
27681fb5b786Sprasad return (PCICFG_FAILURE);
27697c478bd9Sstevel@tonic-gate }
27707c478bd9Sstevel@tonic-gate
2771a6469d9bSprasad DEBUG4("Returned 0x%x of 32 bit %s space"
277226947304SEvan Yan " @ 0x%x from register 0x%x\n",
277326947304SEvan Yan assigned[i].pci_size_low, mem_type,
277426947304SEvan Yan assigned[i].pci_phys_low,
277526947304SEvan Yan PCI_REG_REG_G(assigned[i].pci_phys_hi));
27767c478bd9Sstevel@tonic-gate
27777c478bd9Sstevel@tonic-gate break;
27787c478bd9Sstevel@tonic-gate case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
2779a6469d9bSprasad if (assigned[i].pci_phys_hi & PCI_REG_PF_M)
2780a6469d9bSprasad mem_type = NDI_RA_TYPE_PCI_PREFETCH_MEM;
2781a6469d9bSprasad else
2782a6469d9bSprasad mem_type = NDI_RA_TYPE_MEM;
2783a6469d9bSprasad
27847c478bd9Sstevel@tonic-gate if (ndi_ra_free(ddi_get_parent(dip),
27851fb5b786Sprasad PCICFG_LADDR(assigned[i].pci_phys_low,
27861fb5b786Sprasad assigned[i].pci_phys_mid),
27871fb5b786Sprasad (uint64_t)assigned[i].pci_size_low,
27881fb5b786Sprasad mem_type, NDI_RA_PASS) != NDI_SUCCESS) {
27891fb5b786Sprasad DEBUG0("Trouble freeing "
279026947304SEvan Yan "PCI memory space\n");
27911fb5b786Sprasad kmem_free(assigned, length);
27921fb5b786Sprasad return (PCICFG_FAILURE);
27937c478bd9Sstevel@tonic-gate }
27947c478bd9Sstevel@tonic-gate
2795a6469d9bSprasad DEBUG5("Returned 0x%x of 64 bit %s space"
279626947304SEvan Yan " @ 0x%x.0x%x from register 0x%x\n",
279726947304SEvan Yan assigned[i].pci_size_low,
279826947304SEvan Yan mem_type, assigned[i].pci_phys_mid,
279926947304SEvan Yan assigned[i].pci_phys_low,
280026947304SEvan Yan PCI_REG_REG_G(assigned[i].pci_phys_hi));
28017c478bd9Sstevel@tonic-gate
28027c478bd9Sstevel@tonic-gate break;
28037c478bd9Sstevel@tonic-gate case PCI_REG_ADDR_G(PCI_ADDR_IO):
28047c478bd9Sstevel@tonic-gate if (ndi_ra_free(ddi_get_parent(dip),
28051fb5b786Sprasad (uint64_t)assigned[i].pci_phys_low,
28061fb5b786Sprasad (uint64_t)assigned[i].pci_size_low,
28071fb5b786Sprasad NDI_RA_TYPE_IO, NDI_RA_PASS) !=
28081fb5b786Sprasad NDI_SUCCESS) {
28091fb5b786Sprasad DEBUG0("Trouble freeing "
281026947304SEvan Yan "PCI IO space\n");
28111fb5b786Sprasad kmem_free(assigned, length);
28121fb5b786Sprasad return (PCICFG_FAILURE);
28137c478bd9Sstevel@tonic-gate }
281426947304SEvan Yan DEBUG3("Returned 0x%x of IO space @ 0x%x from "
281526947304SEvan Yan "register 0x%x\n", assigned[i].pci_size_low,
281626947304SEvan Yan assigned[i].pci_phys_low,
281726947304SEvan Yan PCI_REG_REG_G(assigned[i].pci_phys_hi));
28187c478bd9Sstevel@tonic-gate break;
28197c478bd9Sstevel@tonic-gate default:
28207c478bd9Sstevel@tonic-gate DEBUG0("Unknown register type\n");
28217c478bd9Sstevel@tonic-gate kmem_free(assigned, length);
28227c478bd9Sstevel@tonic-gate return (PCICFG_FAILURE);
28237c478bd9Sstevel@tonic-gate } /* switch */
28247c478bd9Sstevel@tonic-gate }
28257c478bd9Sstevel@tonic-gate }
28267c478bd9Sstevel@tonic-gate kmem_free(assigned, length);
28277c478bd9Sstevel@tonic-gate return (PCICFG_SUCCESS);
28287c478bd9Sstevel@tonic-gate }
28297c478bd9Sstevel@tonic-gate
28307c478bd9Sstevel@tonic-gate static int
pcicfg_free_resources(dev_info_t * dip,pcicfg_flags_t flags)283126947304SEvan Yan pcicfg_free_resources(dev_info_t *dip, pcicfg_flags_t flags)
28327c478bd9Sstevel@tonic-gate {
28337c478bd9Sstevel@tonic-gate ddi_acc_handle_t handle;
28347c478bd9Sstevel@tonic-gate uint8_t header_type;
28357c478bd9Sstevel@tonic-gate
28367c478bd9Sstevel@tonic-gate if (pci_config_setup(dip, &handle) != DDI_SUCCESS) {
28377c478bd9Sstevel@tonic-gate DEBUG0("Failed to map config space!\n");
28387c478bd9Sstevel@tonic-gate return (PCICFG_FAILURE);
28397c478bd9Sstevel@tonic-gate }
28407c478bd9Sstevel@tonic-gate
28417c478bd9Sstevel@tonic-gate header_type = pci_config_get8(handle, PCI_CONF_HEADER);
28427c478bd9Sstevel@tonic-gate
28437c478bd9Sstevel@tonic-gate (void) pci_config_teardown(&handle);
28447c478bd9Sstevel@tonic-gate
28457c478bd9Sstevel@tonic-gate /*
28467c478bd9Sstevel@tonic-gate * A different algorithm is used for bridges and leaf devices.
28477c478bd9Sstevel@tonic-gate */
28487c478bd9Sstevel@tonic-gate if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
284926947304SEvan Yan /*
285026947304SEvan Yan * We only support readonly probing for leaf devices.
285126947304SEvan Yan */
285226947304SEvan Yan if (flags & PCICFG_FLAG_READ_ONLY)
285326947304SEvan Yan return (PCICFG_FAILURE);
285426947304SEvan Yan
28557c478bd9Sstevel@tonic-gate if (pcicfg_free_bridge_resources(dip) != PCICFG_SUCCESS) {
28567c478bd9Sstevel@tonic-gate DEBUG0("Failed freeing up bridge resources\n");
28577c478bd9Sstevel@tonic-gate return (PCICFG_FAILURE);
28587c478bd9Sstevel@tonic-gate }
28597c478bd9Sstevel@tonic-gate } else {
28607c478bd9Sstevel@tonic-gate if (pcicfg_free_device_resources(dip) != PCICFG_SUCCESS) {
28617c478bd9Sstevel@tonic-gate DEBUG0("Failed freeing up device resources\n");
28627c478bd9Sstevel@tonic-gate return (PCICFG_FAILURE);
28637c478bd9Sstevel@tonic-gate }
28647c478bd9Sstevel@tonic-gate }
28657c478bd9Sstevel@tonic-gate
28667c478bd9Sstevel@tonic-gate return (PCICFG_SUCCESS);
28677c478bd9Sstevel@tonic-gate }
28687c478bd9Sstevel@tonic-gate
28697c478bd9Sstevel@tonic-gate #ifndef _DONT_USE_1275_GENERIC_NAMES
28707c478bd9Sstevel@tonic-gate static char *
pcicfg_get_class_name(uint32_t classcode)28717c478bd9Sstevel@tonic-gate pcicfg_get_class_name(uint32_t classcode)
28727c478bd9Sstevel@tonic-gate {
28737c478bd9Sstevel@tonic-gate struct pcicfg_name_entry *ptr;
28747c478bd9Sstevel@tonic-gate
28757c478bd9Sstevel@tonic-gate for (ptr = &pcicfg_class_lookup[0]; ptr->name != NULL; ptr++) {
28767c478bd9Sstevel@tonic-gate if (ptr->class_code == classcode) {
28777c478bd9Sstevel@tonic-gate return (ptr->name);
28787c478bd9Sstevel@tonic-gate }
28797c478bd9Sstevel@tonic-gate }
28807c478bd9Sstevel@tonic-gate return (NULL);
28817c478bd9Sstevel@tonic-gate }
28827c478bd9Sstevel@tonic-gate #endif /* _DONT_USE_1275_GENERIC_NAMES */
28837c478bd9Sstevel@tonic-gate
28847c478bd9Sstevel@tonic-gate static dev_info_t *
pcicfg_devi_find(dev_info_t * dip,uint_t device,uint_t function)28857c478bd9Sstevel@tonic-gate pcicfg_devi_find(dev_info_t *dip, uint_t device, uint_t function)
28867c478bd9Sstevel@tonic-gate {
28877c478bd9Sstevel@tonic-gate struct pcicfg_find_ctrl ctrl;
28887c478bd9Sstevel@tonic-gate
28897c478bd9Sstevel@tonic-gate ctrl.device = device;
28907c478bd9Sstevel@tonic-gate ctrl.function = function;
28917c478bd9Sstevel@tonic-gate ctrl.dip = NULL;
28927c478bd9Sstevel@tonic-gate
28933fe80ca4SDan Cross ndi_devi_enter(dip);
28947c478bd9Sstevel@tonic-gate ddi_walk_devs(ddi_get_child(dip), pcicfg_match_dev, (void *)&ctrl);
28953fe80ca4SDan Cross ndi_devi_exit(dip);
28967c478bd9Sstevel@tonic-gate
28977c478bd9Sstevel@tonic-gate return (ctrl.dip);
28987c478bd9Sstevel@tonic-gate }
28997c478bd9Sstevel@tonic-gate
29007c478bd9Sstevel@tonic-gate static int
pcicfg_match_dev(dev_info_t * dip,void * hdl)29017c478bd9Sstevel@tonic-gate pcicfg_match_dev(dev_info_t *dip, void *hdl)
29027c478bd9Sstevel@tonic-gate {
29037c478bd9Sstevel@tonic-gate struct pcicfg_find_ctrl *ctrl = (struct pcicfg_find_ctrl *)hdl;
29047c478bd9Sstevel@tonic-gate pci_regspec_t *pci_rp;
29057c478bd9Sstevel@tonic-gate int length;
29067c478bd9Sstevel@tonic-gate int pci_dev;
29077c478bd9Sstevel@tonic-gate int pci_func;
29087c478bd9Sstevel@tonic-gate
290926947304SEvan Yan if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
291026947304SEvan Yan "reg", (int **)&pci_rp, (uint_t *)&length) != DDI_PROP_SUCCESS) {
29117c478bd9Sstevel@tonic-gate ctrl->dip = NULL;
29127c478bd9Sstevel@tonic-gate return (DDI_WALK_TERMINATE);
29137c478bd9Sstevel@tonic-gate }
29147c478bd9Sstevel@tonic-gate
29157c478bd9Sstevel@tonic-gate /* get the PCI device address info */
29167c478bd9Sstevel@tonic-gate pci_dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
29177c478bd9Sstevel@tonic-gate pci_func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
29187c478bd9Sstevel@tonic-gate
29197c478bd9Sstevel@tonic-gate /*
29207c478bd9Sstevel@tonic-gate * free the memory allocated by ddi_prop_lookup_int_array
29217c478bd9Sstevel@tonic-gate */
29227c478bd9Sstevel@tonic-gate ddi_prop_free(pci_rp);
29237c478bd9Sstevel@tonic-gate
29247c478bd9Sstevel@tonic-gate
29257c478bd9Sstevel@tonic-gate if ((pci_dev == ctrl->device) && (pci_func == ctrl->function)) {
29267c478bd9Sstevel@tonic-gate /* found the match for the specified device address */
29277c478bd9Sstevel@tonic-gate ctrl->dip = dip;
29287c478bd9Sstevel@tonic-gate return (DDI_WALK_TERMINATE);
29297c478bd9Sstevel@tonic-gate }
29307c478bd9Sstevel@tonic-gate
29317c478bd9Sstevel@tonic-gate /*
29327c478bd9Sstevel@tonic-gate * continue the walk to the next sibling to look for a match.
29337c478bd9Sstevel@tonic-gate */
29347c478bd9Sstevel@tonic-gate return (DDI_WALK_PRUNECHILD);
29357c478bd9Sstevel@tonic-gate }
29367c478bd9Sstevel@tonic-gate
29377c478bd9Sstevel@tonic-gate static int
pcicfg_update_assigned_prop(dev_info_t * dip,pci_regspec_t * newone)29387c478bd9Sstevel@tonic-gate pcicfg_update_assigned_prop(dev_info_t *dip, pci_regspec_t *newone)
29397c478bd9Sstevel@tonic-gate {
29407c478bd9Sstevel@tonic-gate int alen;
29417c478bd9Sstevel@tonic-gate pci_regspec_t *assigned;
29427c478bd9Sstevel@tonic-gate caddr_t newreg;
29437c478bd9Sstevel@tonic-gate uint_t status;
29447c478bd9Sstevel@tonic-gate
2945a3282898Scth status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
294626947304SEvan Yan "assigned-addresses", (caddr_t)&assigned, &alen);
29477c478bd9Sstevel@tonic-gate switch (status) {
29487c478bd9Sstevel@tonic-gate case DDI_PROP_SUCCESS:
29497c478bd9Sstevel@tonic-gate break;
29507c478bd9Sstevel@tonic-gate case DDI_PROP_NO_MEMORY:
29517c478bd9Sstevel@tonic-gate DEBUG0("no memory for assigned-addresses property\n");
29527c478bd9Sstevel@tonic-gate return (PCICFG_FAILURE);
29537c478bd9Sstevel@tonic-gate default:
29547c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
295526947304SEvan Yan "assigned-addresses", (int *)newone,
295626947304SEvan Yan sizeof (*newone)/sizeof (int));
29577c478bd9Sstevel@tonic-gate return (PCICFG_SUCCESS);
29587c478bd9Sstevel@tonic-gate }
29597c478bd9Sstevel@tonic-gate
29607c478bd9Sstevel@tonic-gate /*
29617c478bd9Sstevel@tonic-gate * Allocate memory for the existing
29627c478bd9Sstevel@tonic-gate * assigned-addresses(s) plus one and then
29637c478bd9Sstevel@tonic-gate * build it.
29647c478bd9Sstevel@tonic-gate */
29657c478bd9Sstevel@tonic-gate
29667c478bd9Sstevel@tonic-gate newreg = kmem_zalloc(alen+sizeof (*newone), KM_SLEEP);
29677c478bd9Sstevel@tonic-gate
29687c478bd9Sstevel@tonic-gate bcopy(assigned, newreg, alen);
29697c478bd9Sstevel@tonic-gate bcopy(newone, newreg + alen, sizeof (*newone));
29707c478bd9Sstevel@tonic-gate
29717c478bd9Sstevel@tonic-gate /*
29727c478bd9Sstevel@tonic-gate * Write out the new "assigned-addresses" spec
29737c478bd9Sstevel@tonic-gate */
29747c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
297526947304SEvan Yan "assigned-addresses", (int *)newreg,
297626947304SEvan Yan (alen + sizeof (*newone))/sizeof (int));
29777c478bd9Sstevel@tonic-gate
29787c478bd9Sstevel@tonic-gate kmem_free((caddr_t)newreg, alen+sizeof (*newone));
29797c478bd9Sstevel@tonic-gate kmem_free(assigned, alen);
29807c478bd9Sstevel@tonic-gate
29817c478bd9Sstevel@tonic-gate return (PCICFG_SUCCESS);
29827c478bd9Sstevel@tonic-gate }
29837c478bd9Sstevel@tonic-gate
29847c478bd9Sstevel@tonic-gate static int
pcicfg_update_ranges_prop(dev_info_t * dip,ppb_ranges_t * addition)298500d0963fSdilpreet pcicfg_update_ranges_prop(dev_info_t *dip, ppb_ranges_t *addition)
29867c478bd9Sstevel@tonic-gate {
29877c478bd9Sstevel@tonic-gate int rlen;
298800d0963fSdilpreet ppb_ranges_t *ranges;
29897c478bd9Sstevel@tonic-gate caddr_t newreg;
29907c478bd9Sstevel@tonic-gate uint_t status;
29917c478bd9Sstevel@tonic-gate
299226947304SEvan Yan status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
299326947304SEvan Yan "ranges", (caddr_t)&ranges, &rlen);
29947c478bd9Sstevel@tonic-gate
29957c478bd9Sstevel@tonic-gate
29967c478bd9Sstevel@tonic-gate switch (status) {
29977c478bd9Sstevel@tonic-gate case DDI_PROP_SUCCESS:
2998a6469d9bSprasad break;
29997c478bd9Sstevel@tonic-gate case DDI_PROP_NO_MEMORY:
30007c478bd9Sstevel@tonic-gate DEBUG0("ranges present, but unable to get memory\n");
30017c478bd9Sstevel@tonic-gate return (PCICFG_FAILURE);
30027c478bd9Sstevel@tonic-gate default:
30037c478bd9Sstevel@tonic-gate DEBUG0("no ranges property - creating one\n");
30047c478bd9Sstevel@tonic-gate if (ndi_prop_update_int_array(DDI_DEV_T_NONE,
300526947304SEvan Yan dip, "ranges", (int *)addition,
300626947304SEvan Yan sizeof (ppb_ranges_t)/sizeof (int))
300726947304SEvan Yan != DDI_SUCCESS) {
30087c478bd9Sstevel@tonic-gate DEBUG0("Did'nt create ranges property\n");
30097c478bd9Sstevel@tonic-gate return (PCICFG_FAILURE);
30107c478bd9Sstevel@tonic-gate }
30117c478bd9Sstevel@tonic-gate return (PCICFG_SUCCESS);
30127c478bd9Sstevel@tonic-gate }
30137c478bd9Sstevel@tonic-gate
30147c478bd9Sstevel@tonic-gate /*
3015a6469d9bSprasad * Allocate memory for the existing ranges plus one and then
30167c478bd9Sstevel@tonic-gate * build it.
30177c478bd9Sstevel@tonic-gate */
301800d0963fSdilpreet newreg = kmem_zalloc(rlen+sizeof (ppb_ranges_t), KM_SLEEP);
30197c478bd9Sstevel@tonic-gate
30207c478bd9Sstevel@tonic-gate bcopy(ranges, newreg, rlen);
302100d0963fSdilpreet bcopy(addition, newreg + rlen, sizeof (ppb_ranges_t));
30227c478bd9Sstevel@tonic-gate
30237c478bd9Sstevel@tonic-gate /*
30247c478bd9Sstevel@tonic-gate * Write out the new "ranges" property
30257c478bd9Sstevel@tonic-gate */
302626947304SEvan Yan (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "ranges",
302726947304SEvan Yan (int *)newreg, (rlen + sizeof (ppb_ranges_t))/sizeof (int));
30287c478bd9Sstevel@tonic-gate
3029a6469d9bSprasad DEBUG1("Updating ranges property for %d entries",
303026947304SEvan Yan rlen / sizeof (ppb_ranges_t) + 1);
3031a6469d9bSprasad
303200d0963fSdilpreet kmem_free((caddr_t)newreg, rlen+sizeof (ppb_ranges_t));
30337c478bd9Sstevel@tonic-gate
30347c478bd9Sstevel@tonic-gate kmem_free((caddr_t)ranges, rlen);
30357c478bd9Sstevel@tonic-gate
30367c478bd9Sstevel@tonic-gate return (PCICFG_SUCCESS);
30377c478bd9Sstevel@tonic-gate }
30387c478bd9Sstevel@tonic-gate
30397c478bd9Sstevel@tonic-gate static int
pcicfg_update_reg_prop(dev_info_t * dip,uint32_t regvalue,uint_t reg_offset)30407c478bd9Sstevel@tonic-gate pcicfg_update_reg_prop(dev_info_t *dip, uint32_t regvalue, uint_t reg_offset)
30417c478bd9Sstevel@tonic-gate {
30427c478bd9Sstevel@tonic-gate int rlen;
30437c478bd9Sstevel@tonic-gate pci_regspec_t *reg;
30447c478bd9Sstevel@tonic-gate caddr_t newreg;
30457c478bd9Sstevel@tonic-gate uint32_t hiword;
30467c478bd9Sstevel@tonic-gate pci_regspec_t addition;
30477c478bd9Sstevel@tonic-gate uint32_t size;
30487c478bd9Sstevel@tonic-gate uint_t status;
30497c478bd9Sstevel@tonic-gate
3050a3282898Scth status = ddi_getlongprop(DDI_DEV_T_ANY,
305126947304SEvan Yan dip, DDI_PROP_DONTPASS, "reg", (caddr_t)®, &rlen);
30527c478bd9Sstevel@tonic-gate
30537c478bd9Sstevel@tonic-gate switch (status) {
30547c478bd9Sstevel@tonic-gate case DDI_PROP_SUCCESS:
30557c478bd9Sstevel@tonic-gate break;
30567c478bd9Sstevel@tonic-gate case DDI_PROP_NO_MEMORY:
30577c478bd9Sstevel@tonic-gate DEBUG0("reg present, but unable to get memory\n");
30587c478bd9Sstevel@tonic-gate return (PCICFG_FAILURE);
30597c478bd9Sstevel@tonic-gate default:
30607c478bd9Sstevel@tonic-gate DEBUG0("no reg property\n");
30617c478bd9Sstevel@tonic-gate return (PCICFG_FAILURE);
30627c478bd9Sstevel@tonic-gate }
30637c478bd9Sstevel@tonic-gate
30647c478bd9Sstevel@tonic-gate /*
30657c478bd9Sstevel@tonic-gate * Allocate memory for the existing reg(s) plus one and then
30667c478bd9Sstevel@tonic-gate * build it.
30677c478bd9Sstevel@tonic-gate */
30687c478bd9Sstevel@tonic-gate newreg = kmem_zalloc(rlen+sizeof (pci_regspec_t), KM_SLEEP);
30697c478bd9Sstevel@tonic-gate
30707c478bd9Sstevel@tonic-gate /*
30717c478bd9Sstevel@tonic-gate * Build the regspec, then add it to the existing one(s)
30727c478bd9Sstevel@tonic-gate */
30737c478bd9Sstevel@tonic-gate
30747c478bd9Sstevel@tonic-gate hiword = PCICFG_MAKE_REG_HIGH(PCI_REG_BUS_G(reg->pci_phys_hi),
30757c478bd9Sstevel@tonic-gate PCI_REG_DEV_G(reg->pci_phys_hi),
30767c478bd9Sstevel@tonic-gate PCI_REG_FUNC_G(reg->pci_phys_hi), reg_offset);
30777c478bd9Sstevel@tonic-gate
30787c478bd9Sstevel@tonic-gate if (reg_offset == PCI_CONF_ROM) {
30797c478bd9Sstevel@tonic-gate size = (~(PCI_BASE_ROM_ADDR_M & regvalue))+1;
30807c478bd9Sstevel@tonic-gate hiword |= PCI_ADDR_MEM32;
30817c478bd9Sstevel@tonic-gate } else {
30827c478bd9Sstevel@tonic-gate size = (~(PCI_BASE_M_ADDR_M & regvalue))+1;
30837c478bd9Sstevel@tonic-gate
30847c478bd9Sstevel@tonic-gate if ((PCI_BASE_SPACE_M & regvalue) == PCI_BASE_SPACE_MEM) {
30857c478bd9Sstevel@tonic-gate if ((PCI_BASE_TYPE_M & regvalue) == PCI_BASE_TYPE_MEM) {
30867c478bd9Sstevel@tonic-gate hiword |= PCI_ADDR_MEM32;
30877c478bd9Sstevel@tonic-gate } else if ((PCI_BASE_TYPE_M & regvalue)
308826947304SEvan Yan == PCI_BASE_TYPE_ALL) {
30897c478bd9Sstevel@tonic-gate hiword |= PCI_ADDR_MEM64;
30907c478bd9Sstevel@tonic-gate }
3091a6469d9bSprasad if (regvalue & PCI_BASE_PREF_M)
3092a6469d9bSprasad hiword |= PCI_REG_PF_M;
30937c478bd9Sstevel@tonic-gate } else {
30947c478bd9Sstevel@tonic-gate hiword |= PCI_ADDR_IO;
30957c478bd9Sstevel@tonic-gate }
30967c478bd9Sstevel@tonic-gate }
30977c478bd9Sstevel@tonic-gate
30987c478bd9Sstevel@tonic-gate addition.pci_phys_hi = hiword;
30997c478bd9Sstevel@tonic-gate addition.pci_phys_mid = 0;
31007c478bd9Sstevel@tonic-gate addition.pci_phys_low = 0;
31017c478bd9Sstevel@tonic-gate addition.pci_size_hi = 0;
31027c478bd9Sstevel@tonic-gate addition.pci_size_low = size;
31037c478bd9Sstevel@tonic-gate
31047c478bd9Sstevel@tonic-gate bcopy(reg, newreg, rlen);
31057c478bd9Sstevel@tonic-gate bcopy(&addition, newreg + rlen, sizeof (pci_regspec_t));
31067c478bd9Sstevel@tonic-gate
310770025d76Sjohnny DEBUG3("updating BAR@off %x with %x,%x\n", reg_offset, hiword, size);
31087c478bd9Sstevel@tonic-gate /*
31097c478bd9Sstevel@tonic-gate * Write out the new "reg" property
31107c478bd9Sstevel@tonic-gate */
311126947304SEvan Yan (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "reg",
311226947304SEvan Yan (int *)newreg, (rlen + sizeof (pci_regspec_t))/sizeof (int));
31137c478bd9Sstevel@tonic-gate
31147c478bd9Sstevel@tonic-gate kmem_free((caddr_t)newreg, rlen+sizeof (pci_regspec_t));
31157c478bd9Sstevel@tonic-gate kmem_free((caddr_t)reg, rlen);
31167c478bd9Sstevel@tonic-gate
31177c478bd9Sstevel@tonic-gate return (PCICFG_SUCCESS);
31187c478bd9Sstevel@tonic-gate }
31197c478bd9Sstevel@tonic-gate
312026947304SEvan Yan static int
pcicfg_update_assigned_prop_value(dev_info_t * dip,uint32_t size,uint32_t base,uint32_t base_hi,uint_t reg_offset)312126947304SEvan Yan pcicfg_update_assigned_prop_value(dev_info_t *dip, uint32_t size,
312226947304SEvan Yan uint32_t base, uint32_t base_hi, uint_t reg_offset)
312326947304SEvan Yan {
312426947304SEvan Yan int rlen;
312526947304SEvan Yan pci_regspec_t *reg;
312626947304SEvan Yan uint32_t hiword;
312726947304SEvan Yan pci_regspec_t addition;
312826947304SEvan Yan uint_t status;
312926947304SEvan Yan
313026947304SEvan Yan status = ddi_getlongprop(DDI_DEV_T_ANY,
313126947304SEvan Yan dip, DDI_PROP_DONTPASS, "reg", (caddr_t)®, &rlen);
313226947304SEvan Yan
313326947304SEvan Yan switch (status) {
313426947304SEvan Yan case DDI_PROP_SUCCESS:
313526947304SEvan Yan break;
313626947304SEvan Yan case DDI_PROP_NO_MEMORY:
313726947304SEvan Yan DEBUG0("reg present, but unable to get memory\n");
313826947304SEvan Yan return (PCICFG_FAILURE);
313926947304SEvan Yan default:
314026947304SEvan Yan /*
314126947304SEvan Yan * Since the config space "reg" entry should have been
314226947304SEvan Yan * created, we expect a "reg" property already
314326947304SEvan Yan * present here.
314426947304SEvan Yan */
314526947304SEvan Yan DEBUG0("no reg property\n");
314626947304SEvan Yan return (PCICFG_FAILURE);
314726947304SEvan Yan }
314826947304SEvan Yan
314926947304SEvan Yan /*
315026947304SEvan Yan * Build the regspec, then add it to the existing one(s)
315126947304SEvan Yan */
315226947304SEvan Yan
315326947304SEvan Yan hiword = PCICFG_MAKE_REG_HIGH(PCI_REG_BUS_G(reg->pci_phys_hi),
315426947304SEvan Yan PCI_REG_DEV_G(reg->pci_phys_hi),
315526947304SEvan Yan PCI_REG_FUNC_G(reg->pci_phys_hi), reg_offset);
315626947304SEvan Yan
315726947304SEvan Yan hiword |= PCI_REG_REL_M;
315826947304SEvan Yan
315926947304SEvan Yan if (reg_offset == PCI_CONF_ROM) {
316026947304SEvan Yan hiword |= PCI_ADDR_MEM32;
316126947304SEvan Yan
316226947304SEvan Yan base = PCI_BASE_ROM_ADDR_M & base;
316326947304SEvan Yan } else {
316426947304SEvan Yan if ((PCI_BASE_SPACE_M & base) == PCI_BASE_SPACE_MEM) {
316526947304SEvan Yan if ((PCI_BASE_TYPE_M & base) == PCI_BASE_TYPE_MEM) {
316626947304SEvan Yan hiword |= PCI_ADDR_MEM32;
316726947304SEvan Yan } else if ((PCI_BASE_TYPE_M & base)
316826947304SEvan Yan == PCI_BASE_TYPE_ALL) {
316926947304SEvan Yan hiword |= PCI_ADDR_MEM64;
317026947304SEvan Yan }
317126947304SEvan Yan if (base & PCI_BASE_PREF_M)
317226947304SEvan Yan hiword |= PCI_REG_PF_M;
317326947304SEvan Yan
317426947304SEvan Yan base = PCI_BASE_M_ADDR_M & base;
317526947304SEvan Yan } else {
317626947304SEvan Yan hiword |= PCI_ADDR_IO;
317726947304SEvan Yan
317826947304SEvan Yan base = PCI_BASE_IO_ADDR_M & base;
317926947304SEvan Yan base_hi = 0;
318026947304SEvan Yan }
318126947304SEvan Yan }
318226947304SEvan Yan
318326947304SEvan Yan addition.pci_phys_hi = hiword;
318426947304SEvan Yan addition.pci_phys_mid = base_hi;
318526947304SEvan Yan addition.pci_phys_low = base;
318626947304SEvan Yan addition.pci_size_hi = 0;
318726947304SEvan Yan addition.pci_size_low = size;
318826947304SEvan Yan
318926947304SEvan Yan DEBUG3("updating BAR@off %x with %x,%x\n", reg_offset, hiword, size);
319026947304SEvan Yan
319126947304SEvan Yan kmem_free((caddr_t)reg, rlen);
319226947304SEvan Yan
319326947304SEvan Yan return (pcicfg_update_assigned_prop(dip, &addition));
319426947304SEvan Yan }
319526947304SEvan Yan
31967c478bd9Sstevel@tonic-gate static void
pcicfg_device_on(ddi_acc_handle_t config_handle)31977c478bd9Sstevel@tonic-gate pcicfg_device_on(ddi_acc_handle_t config_handle)
31987c478bd9Sstevel@tonic-gate {
31997c478bd9Sstevel@tonic-gate /*
32007c478bd9Sstevel@tonic-gate * Enable memory, IO, and bus mastership
32017c478bd9Sstevel@tonic-gate * XXX should we enable parity, SERR#,
32027c478bd9Sstevel@tonic-gate * fast back-to-back, and addr. stepping?
32037c478bd9Sstevel@tonic-gate */
32047c478bd9Sstevel@tonic-gate pci_config_put16(config_handle, PCI_CONF_COMM,
320526947304SEvan Yan pci_config_get16(config_handle, PCI_CONF_COMM) | 0x7);
32067c478bd9Sstevel@tonic-gate }
32077c478bd9Sstevel@tonic-gate
32087c478bd9Sstevel@tonic-gate static void
pcicfg_device_off(ddi_acc_handle_t config_handle)32097c478bd9Sstevel@tonic-gate pcicfg_device_off(ddi_acc_handle_t config_handle)
32107c478bd9Sstevel@tonic-gate {
32117c478bd9Sstevel@tonic-gate /*
32127c478bd9Sstevel@tonic-gate * Disable I/O and memory traffic through the bridge
32137c478bd9Sstevel@tonic-gate */
32147c478bd9Sstevel@tonic-gate pci_config_put16(config_handle, PCI_CONF_COMM, 0x0);
32157c478bd9Sstevel@tonic-gate }
32167c478bd9Sstevel@tonic-gate
32177c478bd9Sstevel@tonic-gate static int
pcicfg_set_busnode_props(dev_info_t * dip,uint8_t pcie_device_type)321870025d76Sjohnny pcicfg_set_busnode_props(dev_info_t *dip, uint8_t pcie_device_type)
32197c478bd9Sstevel@tonic-gate {
32207c478bd9Sstevel@tonic-gate int ret;
322170025d76Sjohnny char device_type[8];
322270025d76Sjohnny
322370025d76Sjohnny if (pcie_device_type)
322470025d76Sjohnny (void) strcpy(device_type, "pciex");
322570025d76Sjohnny else
322670025d76Sjohnny (void) strcpy(device_type, "pci");
32277c478bd9Sstevel@tonic-gate
32287c478bd9Sstevel@tonic-gate if ((ret = ndi_prop_update_string(DDI_DEV_T_NONE, dip,
322926947304SEvan Yan "device_type", device_type)) != DDI_SUCCESS) {
32307c478bd9Sstevel@tonic-gate return (ret);
32317c478bd9Sstevel@tonic-gate }
32327c478bd9Sstevel@tonic-gate if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
323326947304SEvan Yan "#address-cells", 3)) != DDI_SUCCESS) {
32347c478bd9Sstevel@tonic-gate return (ret);
32357c478bd9Sstevel@tonic-gate }
323626947304SEvan Yan if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, "#size-cells", 2))
323726947304SEvan Yan != DDI_SUCCESS) {
32387c478bd9Sstevel@tonic-gate return (ret);
32397c478bd9Sstevel@tonic-gate }
32407c478bd9Sstevel@tonic-gate return (PCICFG_SUCCESS);
32417c478bd9Sstevel@tonic-gate }
32427c478bd9Sstevel@tonic-gate
32437c478bd9Sstevel@tonic-gate /*
32447c478bd9Sstevel@tonic-gate * Program the bus numbers into the bridge
32457c478bd9Sstevel@tonic-gate */
32467c478bd9Sstevel@tonic-gate static void
pcicfg_set_bus_numbers(ddi_acc_handle_t config_handle,uint_t primary,uint_t secondary,uint_t subordinate)3247ffb64830SJordan Paige Hendricks pcicfg_set_bus_numbers(ddi_acc_handle_t config_handle, uint_t primary,
3248ffb64830SJordan Paige Hendricks uint_t secondary, uint_t subordinate)
32497c478bd9Sstevel@tonic-gate {
325070025d76Sjohnny DEBUG3("Setting bridge bus-range %d,%d,%d\n", primary, secondary,
325126947304SEvan Yan subordinate);
32527c478bd9Sstevel@tonic-gate /*
32537c478bd9Sstevel@tonic-gate * Primary bus#
32547c478bd9Sstevel@tonic-gate */
32557c478bd9Sstevel@tonic-gate pci_config_put8(config_handle, PCI_BCNF_PRIBUS, primary);
32567c478bd9Sstevel@tonic-gate
32577c478bd9Sstevel@tonic-gate /*
32587c478bd9Sstevel@tonic-gate * Secondary bus#
32597c478bd9Sstevel@tonic-gate */
32607c478bd9Sstevel@tonic-gate pci_config_put8(config_handle, PCI_BCNF_SECBUS, secondary);
32617c478bd9Sstevel@tonic-gate
32627c478bd9Sstevel@tonic-gate /*
32637c478bd9Sstevel@tonic-gate * Set the subordinate bus number to ff in order to pass through any
32647c478bd9Sstevel@tonic-gate * type 1 cycle with a bus number higher than the secondary bus#
32657c478bd9Sstevel@tonic-gate */
326670025d76Sjohnny pci_config_put8(config_handle, PCI_BCNF_SUBBUS, subordinate);
32677c478bd9Sstevel@tonic-gate }
32687c478bd9Sstevel@tonic-gate
32697c478bd9Sstevel@tonic-gate /*
32707c478bd9Sstevel@tonic-gate * Put bridge registers into initial state
32717c478bd9Sstevel@tonic-gate */
32727c478bd9Sstevel@tonic-gate static void
pcicfg_setup_bridge(pcicfg_phdl_t * entry,ddi_acc_handle_t handle)3273ffb64830SJordan Paige Hendricks pcicfg_setup_bridge(pcicfg_phdl_t *entry, ddi_acc_handle_t handle)
32747c478bd9Sstevel@tonic-gate {
32757c478bd9Sstevel@tonic-gate /*
32767c478bd9Sstevel@tonic-gate * The highest bus seen during probing is the max-subordinate bus
32777c478bd9Sstevel@tonic-gate */
32787c478bd9Sstevel@tonic-gate pci_config_put8(handle, PCI_BCNF_SUBBUS, entry->highest_bus);
32797c478bd9Sstevel@tonic-gate
32807c478bd9Sstevel@tonic-gate /*
32817c478bd9Sstevel@tonic-gate * Reset the secondary bus
32827c478bd9Sstevel@tonic-gate */
32837c478bd9Sstevel@tonic-gate pci_config_put16(handle, PCI_BCNF_BCNTRL,
328426947304SEvan Yan pci_config_get16(handle, PCI_BCNF_BCNTRL) | 0x40);
328570025d76Sjohnny drv_usecwait(1000);
32867c478bd9Sstevel@tonic-gate pci_config_put16(handle, PCI_BCNF_BCNTRL,
328726947304SEvan Yan pci_config_get16(handle, PCI_BCNF_BCNTRL) & ~0x40);
328870025d76Sjohnny drv_usecwait(1000);
32897c478bd9Sstevel@tonic-gate
32907c478bd9Sstevel@tonic-gate /*
32917c478bd9Sstevel@tonic-gate * Program the memory base register with the
32927c478bd9Sstevel@tonic-gate * start of the memory range
32937c478bd9Sstevel@tonic-gate */
32947c478bd9Sstevel@tonic-gate pci_config_put16(handle, PCI_BCNF_MEM_BASE,
329526947304SEvan Yan PCICFG_HIWORD(PCICFG_LOADDR(entry->memory_last)));
32967c478bd9Sstevel@tonic-gate
32977c478bd9Sstevel@tonic-gate /*
32987c478bd9Sstevel@tonic-gate * Program the I/O base register with the start of the I/O range
32997c478bd9Sstevel@tonic-gate */
33007c478bd9Sstevel@tonic-gate pci_config_put8(handle, PCI_BCNF_IO_BASE_LOW,
330126947304SEvan Yan PCICFG_HIBYTE(PCICFG_LOWORD(PCICFG_LOADDR(entry->io_last))));
33027c478bd9Sstevel@tonic-gate pci_config_put16(handle, PCI_BCNF_IO_BASE_HI,
330326947304SEvan Yan PCICFG_HIWORD(PCICFG_LOADDR(entry->io_last)));
33047c478bd9Sstevel@tonic-gate
33057c478bd9Sstevel@tonic-gate /*
3306a6469d9bSprasad * Program the PF memory base register with the start of
3307a6469d9bSprasad * PF memory range
33087c478bd9Sstevel@tonic-gate */
3309a6469d9bSprasad pci_config_put16(handle, PCI_BCNF_PF_BASE_LOW,
331026947304SEvan Yan PCICFG_HIWORD(PCICFG_LOADDR(entry->pf_memory_last)));
3311a6469d9bSprasad pci_config_put32(handle, PCI_BCNF_PF_BASE_HIGH,
331226947304SEvan Yan PCICFG_HIADDR(entry->pf_memory_last));
33137c478bd9Sstevel@tonic-gate
33147c478bd9Sstevel@tonic-gate /*
3315a6469d9bSprasad * Clear status bits
33167c478bd9Sstevel@tonic-gate */
3317a6469d9bSprasad pci_config_put16(handle, PCI_BCNF_SEC_STATUS, 0xffff);
33187c478bd9Sstevel@tonic-gate
33197c478bd9Sstevel@tonic-gate /*
33207c478bd9Sstevel@tonic-gate * Needs to be set to this value
33217c478bd9Sstevel@tonic-gate */
33227c478bd9Sstevel@tonic-gate pci_config_put8(handle, PCI_CONF_ILINE, 0xf);
332370025d76Sjohnny
332470025d76Sjohnny /*
332570025d76Sjohnny * XXX - may be delay should be used since noone configures
332670025d76Sjohnny * devices in the interrupt context
332770025d76Sjohnny */
332870025d76Sjohnny drv_usecwait(pcicfg_sec_reset_delay); /* 1 sec wait */
33297c478bd9Sstevel@tonic-gate }
33307c478bd9Sstevel@tonic-gate
33317c478bd9Sstevel@tonic-gate static void
pcicfg_update_bridge(pcicfg_phdl_t * entry,ddi_acc_handle_t handle)3332ffb64830SJordan Paige Hendricks pcicfg_update_bridge(pcicfg_phdl_t *entry, ddi_acc_handle_t handle)
33337c478bd9Sstevel@tonic-gate {
33347c478bd9Sstevel@tonic-gate uint_t length;
33357c478bd9Sstevel@tonic-gate
33367c478bd9Sstevel@tonic-gate /*
33377c478bd9Sstevel@tonic-gate * Program the memory limit register with the end of the memory range
33387c478bd9Sstevel@tonic-gate */
33397c478bd9Sstevel@tonic-gate
33407c478bd9Sstevel@tonic-gate DEBUG1("DOWN ROUNDED ===>[0x%x]\n",
334126947304SEvan Yan PCICFG_ROUND_DOWN(entry->memory_last, PCICFG_MEMGRAN));
33427c478bd9Sstevel@tonic-gate
33437c478bd9Sstevel@tonic-gate pci_config_put16(handle, PCI_BCNF_MEM_LIMIT,
334426947304SEvan Yan PCICFG_HIWORD(PCICFG_LOADDR(
334526947304SEvan Yan PCICFG_ROUND_DOWN(entry->memory_last, PCICFG_MEMGRAN))));
33467c478bd9Sstevel@tonic-gate /*
33477c478bd9Sstevel@tonic-gate * Since this is a bridge, the rest of this range will
33487c478bd9Sstevel@tonic-gate * be responded to by the bridge. We have to round up
33497c478bd9Sstevel@tonic-gate * so no other device claims it.
33507c478bd9Sstevel@tonic-gate */
335126947304SEvan Yan if ((length = (PCICFG_ROUND_UP(entry->memory_last, PCICFG_MEMGRAN)
335226947304SEvan Yan - entry->memory_last)) > 0) {
33537c478bd9Sstevel@tonic-gate (void) pcicfg_get_mem(entry, length, NULL);
335426947304SEvan Yan DEBUG1("Added [0x%x]at the top of the bridge (mem)\n", length);
33557c478bd9Sstevel@tonic-gate }
33567c478bd9Sstevel@tonic-gate
3357a6469d9bSprasad /*
3358a6469d9bSprasad * Program the PF memory limit register with the end of the memory range
3359a6469d9bSprasad */
3360a6469d9bSprasad
3361a6469d9bSprasad DEBUG1("DOWN ROUNDED ===>[0x%x]\n",
336226947304SEvan Yan PCICFG_ROUND_DOWN(entry->pf_memory_last, PCICFG_MEMGRAN));
3363a6469d9bSprasad
3364a6469d9bSprasad pci_config_put16(handle, PCI_BCNF_PF_LIMIT_LOW,
336526947304SEvan Yan PCICFG_HIWORD(PCICFG_LOADDR(PCICFG_ROUND_DOWN(
336626947304SEvan Yan entry->pf_memory_last, PCICFG_MEMGRAN))));
336726947304SEvan Yan pci_config_put32(handle, PCI_BCNF_PF_LIMIT_HIGH, PCICFG_HIADDR(
336826947304SEvan Yan PCICFG_ROUND_DOWN(entry->pf_memory_last, PCICFG_MEMGRAN)));
336926947304SEvan Yan if ((length = (PCICFG_ROUND_UP(entry->pf_memory_last, PCICFG_MEMGRAN)
337026947304SEvan Yan - entry->pf_memory_last)) > 0) {
3371a6469d9bSprasad (void) pcicfg_get_pf_mem(entry, length, NULL);
337226947304SEvan Yan DEBUG1("Added [0x%x]at the top of the bridge (PF mem)\n",
337326947304SEvan Yan length);
3374a6469d9bSprasad }
3375a6469d9bSprasad
33767c478bd9Sstevel@tonic-gate /*
33777c478bd9Sstevel@tonic-gate * Program the I/O limit register with the end of the I/O range
33787c478bd9Sstevel@tonic-gate */
33797c478bd9Sstevel@tonic-gate pci_config_put8(handle, PCI_BCNF_IO_LIMIT_LOW,
338026947304SEvan Yan PCICFG_HIBYTE(PCICFG_LOWORD(
338126947304SEvan Yan PCICFG_LOADDR(PCICFG_ROUND_DOWN(entry->io_last, PCICFG_IOGRAN)))));
33827c478bd9Sstevel@tonic-gate
338326947304SEvan Yan pci_config_put16(handle, PCI_BCNF_IO_LIMIT_HI, PCICFG_HIWORD(
338426947304SEvan Yan PCICFG_LOADDR(PCICFG_ROUND_DOWN(entry->io_last, PCICFG_IOGRAN))));
33857c478bd9Sstevel@tonic-gate
33867c478bd9Sstevel@tonic-gate /*
33877c478bd9Sstevel@tonic-gate * Same as above for I/O space. Since this is a
33887c478bd9Sstevel@tonic-gate * bridge, the rest of this range will be responded
33897c478bd9Sstevel@tonic-gate * to by the bridge. We have to round up so no
33907c478bd9Sstevel@tonic-gate * other device claims it.
33917c478bd9Sstevel@tonic-gate */
339226947304SEvan Yan if ((length = (PCICFG_ROUND_UP(entry->io_last, PCICFG_IOGRAN)
339326947304SEvan Yan - entry->io_last)) > 0) {
33947c478bd9Sstevel@tonic-gate (void) pcicfg_get_io(entry, length, NULL);
339526947304SEvan Yan DEBUG1("Added [0x%x]at the top of the bridge (I/O)\n", length);
33967c478bd9Sstevel@tonic-gate }
33977c478bd9Sstevel@tonic-gate }
33987c478bd9Sstevel@tonic-gate
33997c478bd9Sstevel@tonic-gate static int
pcicfg_probe_children(dev_info_t * parent,uint_t bus,uint_t device,uint_t func,uint_t * highest_bus,pcicfg_flags_t flags,boolean_t is_pcie)340026947304SEvan Yan pcicfg_probe_children(dev_info_t *parent, uint_t bus, uint_t device,
3401c0da6274SZhi-Jun Robin Fu uint_t func, uint_t *highest_bus, pcicfg_flags_t flags, boolean_t is_pcie)
34027c478bd9Sstevel@tonic-gate {
34037c478bd9Sstevel@tonic-gate dev_info_t *new_child;
34047c478bd9Sstevel@tonic-gate ddi_acc_handle_t config_handle;
34055af4ae46Sjveta int ret = PCICFG_FAILURE;
3406*bd97c7ceSRobert Mustacchi pci_prop_data_t prop_data;
3407*bd97c7ceSRobert Mustacchi pci_prop_failure_t prop_ret;
34087c478bd9Sstevel@tonic-gate
34097c478bd9Sstevel@tonic-gate /*
34107c478bd9Sstevel@tonic-gate * This node will be put immediately below
34117c478bd9Sstevel@tonic-gate * "parent". Allocate a blank device node. It will either
34127c478bd9Sstevel@tonic-gate * be filled in or freed up based on further probing.
34137c478bd9Sstevel@tonic-gate */
34147c478bd9Sstevel@tonic-gate
34157c478bd9Sstevel@tonic-gate ndi_devi_alloc_sleep(parent, DEVI_PSEUDO_NEXNAME,
341626947304SEvan Yan (pnode_t)DEVI_SID_NODEID, &new_child);
34177c478bd9Sstevel@tonic-gate
341826947304SEvan Yan if (pcicfg_add_config_reg(new_child, bus, device, func)
341926947304SEvan Yan != DDI_SUCCESS) {
342026947304SEvan Yan DEBUG0("pcicfg_probe_children():Failed to add candidate REG\n");
342170025d76Sjohnny goto failedconfig;
34227c478bd9Sstevel@tonic-gate }
34237c478bd9Sstevel@tonic-gate
34247c478bd9Sstevel@tonic-gate if ((ret = pcicfg_config_setup(new_child, &config_handle))
342526947304SEvan Yan != PCICFG_SUCCESS) {
34267c478bd9Sstevel@tonic-gate if (ret == PCICFG_NODEVICE) {
34277c478bd9Sstevel@tonic-gate (void) ndi_devi_free(new_child);
34287c478bd9Sstevel@tonic-gate return (ret);
34297c478bd9Sstevel@tonic-gate }
34307c478bd9Sstevel@tonic-gate DEBUG0("pcicfg_probe_children():"
34317c478bd9Sstevel@tonic-gate "Failed to setup config space\n");
34327c478bd9Sstevel@tonic-gate goto failedconfig;
34337c478bd9Sstevel@tonic-gate }
34347c478bd9Sstevel@tonic-gate
3435c0da6274SZhi-Jun Robin Fu if (is_pcie)
3436c0da6274SZhi-Jun Robin Fu (void) pcie_init_bus(new_child, PCI_GETBDF(bus, device, func),
3437c0da6274SZhi-Jun Robin Fu PCIE_BUS_INITIAL);
3438c0da6274SZhi-Jun Robin Fu
34397c478bd9Sstevel@tonic-gate /*
34407c478bd9Sstevel@tonic-gate * As soon as we have access to config space,
34417c478bd9Sstevel@tonic-gate * turn off device. It will get turned on
34427c478bd9Sstevel@tonic-gate * later (after memory is assigned).
34437c478bd9Sstevel@tonic-gate */
34447c478bd9Sstevel@tonic-gate (void) pcicfg_device_off(config_handle);
34457c478bd9Sstevel@tonic-gate
3446*bd97c7ceSRobert Mustacchi prop_ret = pci_prop_data_fill(config_handle, bus, device, func,
3447*bd97c7ceSRobert Mustacchi &prop_data);
3448*bd97c7ceSRobert Mustacchi if (prop_ret != PCI_PROP_OK) {
3449*bd97c7ceSRobert Mustacchi cmn_err(CE_WARN, "hotplug: failed to get basic PCI data for "
3450*bd97c7ceSRobert Mustacchi "b/d/f 0x%x/0x%x/0x%x: 0x%x", bus, device, func, prop_ret);
3451*bd97c7ceSRobert Mustacchi goto failedchild;
345270025d76Sjohnny }
345370025d76Sjohnny
3454*bd97c7ceSRobert Mustacchi prop_ret = pci_prop_name_node(new_child, &prop_data);
3455*bd97c7ceSRobert Mustacchi if (prop_ret != PCI_PROP_OK) {
3456*bd97c7ceSRobert Mustacchi cmn_err(CE_WARN, "hotplug: failed to set node name for b/d/f "
3457*bd97c7ceSRobert Mustacchi "0x%x/0x%x/0x%x: 0x%x", bus,
3458*bd97c7ceSRobert Mustacchi device, func, prop_ret);
34597c478bd9Sstevel@tonic-gate goto failedchild;
34607c478bd9Sstevel@tonic-gate }
34617c478bd9Sstevel@tonic-gate
3462*bd97c7ceSRobert Mustacchi prop_ret = pci_prop_set_common_props(new_child, &prop_data);
3463*bd97c7ceSRobert Mustacchi if (prop_ret != PCI_PROP_OK) {
3464*bd97c7ceSRobert Mustacchi cmn_err(CE_WARN, "hotplug: failed to set properties for b/d/f "
3465*bd97c7ceSRobert Mustacchi "0x%x/0x%x/0x%x: 0x%x", bus,
3466*bd97c7ceSRobert Mustacchi device, func, prop_ret);
34677c478bd9Sstevel@tonic-gate goto failedchild;
34687c478bd9Sstevel@tonic-gate }
34697c478bd9Sstevel@tonic-gate
3470*bd97c7ceSRobert Mustacchi prop_ret = pci_prop_set_compatible(new_child, &prop_data);
3471*bd97c7ceSRobert Mustacchi if (prop_ret != PCI_PROP_OK) {
3472*bd97c7ceSRobert Mustacchi cmn_err(CE_WARN, "hotplug: failed to set compatible property "
3473*bd97c7ceSRobert Mustacchi "for b/d/f 0x%x/0x%x/0x%x: 0x%x",
3474*bd97c7ceSRobert Mustacchi bus, device, func, prop_ret);
3475*bd97c7ceSRobert Mustacchi goto failedchild;
3476*bd97c7ceSRobert Mustacchi }
34777c478bd9Sstevel@tonic-gate
34787c478bd9Sstevel@tonic-gate /*
34797c478bd9Sstevel@tonic-gate * If this is not a multi-function card only probe function zero.
34807c478bd9Sstevel@tonic-gate */
3481*bd97c7ceSRobert Mustacchi if ((prop_data.ppd_flags & PCI_PROP_F_MULT_FUNC) == 0 && func != 0) {
34827c478bd9Sstevel@tonic-gate
3483c0da6274SZhi-Jun Robin Fu ret = PCICFG_NODEVICE;
3484c0da6274SZhi-Jun Robin Fu goto failedchild;
34857c478bd9Sstevel@tonic-gate }
34867c478bd9Sstevel@tonic-gate
348770025d76Sjohnny /*
348870025d76Sjohnny * Attach the child to its parent
348970025d76Sjohnny */
349070025d76Sjohnny (void) i_ndi_config_node(new_child, DS_LINKED, 0);
349170025d76Sjohnny
34923a634bfcSVikram Hegde DEVI_SET_PCI(new_child);
34933a634bfcSVikram Hegde
3494*bd97c7ceSRobert Mustacchi if (prop_data.ppd_header == PCI_HEADER_PPB) {
34957c478bd9Sstevel@tonic-gate
349626947304SEvan Yan DEBUG3("--Bridge found bus [0x%x] device[0x%x] func [0x%x]\n",
349726947304SEvan Yan bus, device, func);
349826947304SEvan Yan
349926947304SEvan Yan /* Only support read-only probe for leaf device */
350026947304SEvan Yan if (flags & PCICFG_FLAG_READ_ONLY)
350126947304SEvan Yan goto failedchild;
35027c478bd9Sstevel@tonic-gate
35035af4ae46Sjveta ret = pcicfg_probe_bridge(new_child, config_handle, bus,
3504c0da6274SZhi-Jun Robin Fu highest_bus, is_pcie);
35055af4ae46Sjveta if (ret != PCICFG_SUCCESS) {
350670025d76Sjohnny (void) pcicfg_free_bridge_resources(new_child);
35077c478bd9Sstevel@tonic-gate goto failedchild;
35087c478bd9Sstevel@tonic-gate }
35097c478bd9Sstevel@tonic-gate
35107c478bd9Sstevel@tonic-gate } else {
35117c478bd9Sstevel@tonic-gate
35127c478bd9Sstevel@tonic-gate DEBUG3("--Leaf device found bus [0x%x] device"
351326947304SEvan Yan "[0x%x] func [0x%x]\n", bus, device, func);
35147c478bd9Sstevel@tonic-gate
351526947304SEvan Yan if (flags & PCICFG_FLAG_READ_ONLY) {
351626947304SEvan Yan /*
351726947304SEvan Yan * with read-only probe, don't do any resource
351826947304SEvan Yan * allocation, just read the BARs and update props.
351926947304SEvan Yan */
352026947304SEvan Yan ret = pcicfg_populate_props_from_bar(new_child,
352126947304SEvan Yan config_handle);
352226947304SEvan Yan if (ret != PCICFG_SUCCESS)
352326947304SEvan Yan goto failedchild;
35247c478bd9Sstevel@tonic-gate
35257c478bd9Sstevel@tonic-gate /*
352626947304SEvan Yan * now allocate the resources, just remove the
352726947304SEvan Yan * resources from the parent busra pool.
35287c478bd9Sstevel@tonic-gate */
352926947304SEvan Yan ret = pcicfg_device_assign_readonly(new_child);
353026947304SEvan Yan if (ret != PCICFG_SUCCESS) {
353126947304SEvan Yan (void) pcicfg_free_device_resources(new_child);
353226947304SEvan Yan goto failedchild;
35337c478bd9Sstevel@tonic-gate }
35347c478bd9Sstevel@tonic-gate
353526947304SEvan Yan } else {
35367c478bd9Sstevel@tonic-gate /*
353726947304SEvan Yan * update "reg" property by sizing the BARs.
35387c478bd9Sstevel@tonic-gate */
353926947304SEvan Yan ret = pcicfg_populate_reg_props(new_child,
354026947304SEvan Yan config_handle);
354126947304SEvan Yan if (ret != PCICFG_SUCCESS)
354226947304SEvan Yan goto failedchild;
354326947304SEvan Yan
354426947304SEvan Yan /* now allocate & program the resources */
354526947304SEvan Yan ret = pcicfg_device_assign(new_child);
354626947304SEvan Yan if (ret != PCICFG_SUCCESS) {
354726947304SEvan Yan (void) pcicfg_free_device_resources(new_child);
354826947304SEvan Yan goto failedchild;
35497c478bd9Sstevel@tonic-gate }
35507c478bd9Sstevel@tonic-gate }
35517c478bd9Sstevel@tonic-gate
355226947304SEvan Yan (void) ndi_devi_bind_driver(new_child, 0);
355326947304SEvan Yan }
355426947304SEvan Yan
355526947304SEvan Yan (void) pcicfg_config_teardown(&config_handle);
355626947304SEvan Yan
3557c0da6274SZhi-Jun Robin Fu /*
3558c0da6274SZhi-Jun Robin Fu * Properties have been setted up, so initialize the remaining
3559c0da6274SZhi-Jun Robin Fu * bus_t fields
3560c0da6274SZhi-Jun Robin Fu */
3561c0da6274SZhi-Jun Robin Fu if (is_pcie)
3562c1374a13SSurya Prakki (void) pcie_init_bus(new_child, 0, PCIE_BUS_FINAL);
3563c0da6274SZhi-Jun Robin Fu
356426947304SEvan Yan return (PCICFG_SUCCESS);
356526947304SEvan Yan
356626947304SEvan Yan failedchild:
356726947304SEvan Yan /*
356826947304SEvan Yan * XXX check if it should be taken offline (if online)
356926947304SEvan Yan */
357026947304SEvan Yan (void) pcicfg_config_teardown(&config_handle);
357126947304SEvan Yan
3572c0da6274SZhi-Jun Robin Fu if (is_pcie)
3573c0da6274SZhi-Jun Robin Fu pcie_fini_bus(new_child, PCIE_BUS_FINAL);
3574c0da6274SZhi-Jun Robin Fu
357526947304SEvan Yan failedconfig:
357626947304SEvan Yan
357726947304SEvan Yan (void) ndi_devi_free(new_child);
357826947304SEvan Yan return (ret);
357926947304SEvan Yan }
358026947304SEvan Yan
358126947304SEvan Yan /*
358226947304SEvan Yan * Sizing the BARs and update "reg" property
358326947304SEvan Yan */
358426947304SEvan Yan static int
pcicfg_populate_reg_props(dev_info_t * new_child,ddi_acc_handle_t config_handle)3585ffb64830SJordan Paige Hendricks pcicfg_populate_reg_props(dev_info_t *new_child, ddi_acc_handle_t config_handle)
358626947304SEvan Yan {
358726947304SEvan Yan int i;
3588ffb64830SJordan Paige Hendricks uint32_t request;
35897c478bd9Sstevel@tonic-gate
359026947304SEvan Yan i = PCI_CONF_BASE0;
359126947304SEvan Yan
359226947304SEvan Yan while (i <= PCI_CONF_BASE5) {
359326947304SEvan Yan
359426947304SEvan Yan pci_config_put32(config_handle, i, 0xffffffff);
359526947304SEvan Yan
359626947304SEvan Yan request = pci_config_get32(config_handle, i);
35977c478bd9Sstevel@tonic-gate /*
35987c478bd9Sstevel@tonic-gate * If its a zero length, don't do
35997c478bd9Sstevel@tonic-gate * any programming.
36007c478bd9Sstevel@tonic-gate */
36017c478bd9Sstevel@tonic-gate if (request != 0) {
36027c478bd9Sstevel@tonic-gate /*
36037c478bd9Sstevel@tonic-gate * Add to the "reg" property
36047c478bd9Sstevel@tonic-gate */
36057c478bd9Sstevel@tonic-gate if (pcicfg_update_reg_prop(new_child,
360626947304SEvan Yan request, i) != PCICFG_SUCCESS) {
36077c478bd9Sstevel@tonic-gate goto failedchild;
36087c478bd9Sstevel@tonic-gate }
360926947304SEvan Yan } else {
361026947304SEvan Yan DEBUG1("BASE register [0x%x] asks for "
361126947304SEvan Yan "[0x0]=[0x0](32)\n", i);
361226947304SEvan Yan i += 4;
361326947304SEvan Yan continue;
36147c478bd9Sstevel@tonic-gate }
361570025d76Sjohnny
361626947304SEvan Yan /*
361726947304SEvan Yan * Increment by eight if it is 64 bit address space
361826947304SEvan Yan */
361926947304SEvan Yan if ((PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_ALL) {
362026947304SEvan Yan DEBUG3("BASE register [0x%x] asks for "
362126947304SEvan Yan "[0x%x]=[0x%x] (64)\n",
362226947304SEvan Yan i, request, (~(PCI_BASE_M_ADDR_M & request))+1);
362326947304SEvan Yan i += 8;
362426947304SEvan Yan } else {
362526947304SEvan Yan DEBUG3("BASE register [0x%x] asks for "
362626947304SEvan Yan "[0x%x]=[0x%x](32)\n",
362726947304SEvan Yan i, request, (~(PCI_BASE_M_ADDR_M & request))+1);
362826947304SEvan Yan i += 4;
362970025d76Sjohnny }
36307c478bd9Sstevel@tonic-gate }
36317c478bd9Sstevel@tonic-gate
363226947304SEvan Yan /*
363326947304SEvan Yan * Get the ROM size and create register for it
363426947304SEvan Yan */
363526947304SEvan Yan pci_config_put32(config_handle, PCI_CONF_ROM, 0xfffffffe);
363626947304SEvan Yan
363726947304SEvan Yan request = pci_config_get32(config_handle, PCI_CONF_ROM);
363826947304SEvan Yan /*
363926947304SEvan Yan * If its a zero length, don't do
364026947304SEvan Yan * any programming.
364126947304SEvan Yan */
364226947304SEvan Yan
364326947304SEvan Yan if (request != 0) {
364426947304SEvan Yan DEBUG3("BASE register [0x%x] asks for [0x%x]=[0x%x]\n",
364526947304SEvan Yan PCI_CONF_ROM, request,
364626947304SEvan Yan (~(PCI_BASE_ROM_ADDR_M & request)) + 1);
364726947304SEvan Yan /*
364826947304SEvan Yan * Add to the "reg" property
364926947304SEvan Yan */
365026947304SEvan Yan if (pcicfg_update_reg_prop(new_child, request, PCI_CONF_ROM)
365126947304SEvan Yan != PCICFG_SUCCESS) {
365226947304SEvan Yan goto failedchild;
365326947304SEvan Yan }
365426947304SEvan Yan }
36557c478bd9Sstevel@tonic-gate
36567c478bd9Sstevel@tonic-gate return (PCICFG_SUCCESS);
36577c478bd9Sstevel@tonic-gate
36587c478bd9Sstevel@tonic-gate failedchild:
365926947304SEvan Yan return (PCICFG_FAILURE);
366026947304SEvan Yan }
366126947304SEvan Yan
366226947304SEvan Yan /*
366326947304SEvan Yan * Read the BARs and update properties. Used in virtual hotplug.
366426947304SEvan Yan */
366526947304SEvan Yan static int
pcicfg_populate_props_from_bar(dev_info_t * new_child,ddi_acc_handle_t config_handle)366626947304SEvan Yan pcicfg_populate_props_from_bar(dev_info_t *new_child,
366726947304SEvan Yan ddi_acc_handle_t config_handle)
366826947304SEvan Yan {
366926947304SEvan Yan uint32_t request, base, base_hi, size;
367026947304SEvan Yan int i;
367126947304SEvan Yan
367226947304SEvan Yan i = PCI_CONF_BASE0;
367326947304SEvan Yan
367426947304SEvan Yan while (i <= PCI_CONF_BASE5) {
367526947304SEvan Yan /*
367626947304SEvan Yan * determine the size of the address space
367726947304SEvan Yan */
367826947304SEvan Yan base = pci_config_get32(config_handle, i);
367926947304SEvan Yan pci_config_put32(config_handle, i, 0xffffffff);
368026947304SEvan Yan request = pci_config_get32(config_handle, i);
368126947304SEvan Yan pci_config_put32(config_handle, i, base);
368226947304SEvan Yan
368326947304SEvan Yan /*
368426947304SEvan Yan * If its a zero length, don't do any programming.
368526947304SEvan Yan */
368626947304SEvan Yan if (request != 0) {
368726947304SEvan Yan /*
368826947304SEvan Yan * Add to the "reg" property
368926947304SEvan Yan */
369026947304SEvan Yan if (pcicfg_update_reg_prop(new_child,
369126947304SEvan Yan request, i) != PCICFG_SUCCESS) {
369226947304SEvan Yan goto failedchild;
369326947304SEvan Yan }
369426947304SEvan Yan
369526947304SEvan Yan if ((PCI_BASE_SPACE_IO & request) == 0 &&
369626947304SEvan Yan (PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_ALL) {
369726947304SEvan Yan base_hi = pci_config_get32(config_handle, i+4);
369826947304SEvan Yan } else {
369926947304SEvan Yan base_hi = 0;
370026947304SEvan Yan }
370126947304SEvan Yan /*
370226947304SEvan Yan * Add to "assigned-addresses" property
370326947304SEvan Yan */
370426947304SEvan Yan size = (~(PCI_BASE_M_ADDR_M & request))+1;
370526947304SEvan Yan if (pcicfg_update_assigned_prop_value(new_child,
370626947304SEvan Yan size, base, base_hi, i) != PCICFG_SUCCESS) {
370726947304SEvan Yan goto failedchild;
370826947304SEvan Yan }
370926947304SEvan Yan } else {
371026947304SEvan Yan DEBUG1("BASE register [0x%x] asks for [0x0]=[0x0]"
371126947304SEvan Yan "(32)\n", i);
371226947304SEvan Yan i += 4;
371326947304SEvan Yan continue;
371426947304SEvan Yan }
371526947304SEvan Yan
371626947304SEvan Yan /*
371726947304SEvan Yan * Increment by eight if it is 64 bit address space
371826947304SEvan Yan */
371926947304SEvan Yan if ((PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_ALL) {
372026947304SEvan Yan DEBUG3("BASE register [0x%x] asks for [0x%x]=[0x%x]"
372126947304SEvan Yan "(64)\n", i, request,
372226947304SEvan Yan (~(PCI_BASE_M_ADDR_M & request)) + 1);
372326947304SEvan Yan i += 8;
372426947304SEvan Yan } else {
372526947304SEvan Yan DEBUG3("BASE register [0x%x] asks for [0x%x]=[0x%x]"
372626947304SEvan Yan "(32)\n", i, request,
372726947304SEvan Yan (~(PCI_BASE_M_ADDR_M & request)) + 1);
372826947304SEvan Yan i += 4;
372926947304SEvan Yan }
373026947304SEvan Yan }
373126947304SEvan Yan
37327c478bd9Sstevel@tonic-gate /*
373326947304SEvan Yan * Get the ROM size and create register for it
37347c478bd9Sstevel@tonic-gate */
373526947304SEvan Yan base = pci_config_get32(config_handle, PCI_CONF_ROM);
373626947304SEvan Yan pci_config_put32(config_handle, PCI_CONF_ROM, 0xfffffffe);
373726947304SEvan Yan request = pci_config_get32(config_handle, PCI_CONF_ROM);
373826947304SEvan Yan pci_config_put32(config_handle, PCI_CONF_ROM, base);
37397c478bd9Sstevel@tonic-gate
374026947304SEvan Yan /*
374126947304SEvan Yan * If its a zero length, don't do
374226947304SEvan Yan * any programming.
374326947304SEvan Yan */
374426947304SEvan Yan if (request != 0) {
374526947304SEvan Yan DEBUG3("BASE register [0x%x] asks for [0x%x]=[0x%x]\n",
374626947304SEvan Yan PCI_CONF_ROM, request,
374726947304SEvan Yan (~(PCI_BASE_ROM_ADDR_M & request)) + 1);
374826947304SEvan Yan /*
374926947304SEvan Yan * Add to the "reg" property
375026947304SEvan Yan */
375126947304SEvan Yan if (pcicfg_update_reg_prop(new_child, request, PCI_CONF_ROM)
375226947304SEvan Yan != PCICFG_SUCCESS) {
375326947304SEvan Yan goto failedchild;
375426947304SEvan Yan }
375526947304SEvan Yan /*
375626947304SEvan Yan * Add to "assigned-addresses" property
375726947304SEvan Yan */
375826947304SEvan Yan size = (~(PCI_BASE_ROM_ADDR_M & request))+1;
375926947304SEvan Yan if (pcicfg_update_assigned_prop_value(new_child, size,
376026947304SEvan Yan base, 0, PCI_CONF_ROM) != PCICFG_SUCCESS) {
376126947304SEvan Yan goto failedchild;
376226947304SEvan Yan }
376326947304SEvan Yan }
37647c478bd9Sstevel@tonic-gate
376526947304SEvan Yan return (PCICFG_SUCCESS);
376626947304SEvan Yan
376726947304SEvan Yan failedchild:
376826947304SEvan Yan return (PCICFG_FAILURE);
37697c478bd9Sstevel@tonic-gate }
37707c478bd9Sstevel@tonic-gate
377170025d76Sjohnny static int
pcicfg_probe_bridge(dev_info_t * new_child,ddi_acc_handle_t h,uint_t bus,uint_t * highest_bus,boolean_t is_pcie)377270025d76Sjohnny pcicfg_probe_bridge(dev_info_t *new_child, ddi_acc_handle_t h, uint_t bus,
3773c0da6274SZhi-Jun Robin Fu uint_t *highest_bus, boolean_t is_pcie)
377470025d76Sjohnny {
377570025d76Sjohnny uint64_t next_bus;
377670025d76Sjohnny uint_t new_bus, num_slots;
377770025d76Sjohnny ndi_ra_request_t req;
377870025d76Sjohnny int rval, i, j;
377970025d76Sjohnny uint64_t mem_answer, io_answer, mem_base, io_base, mem_alen, io_alen;
3780a6469d9bSprasad uint64_t pf_mem_answer, pf_mem_base, pf_mem_alen;
3781a6469d9bSprasad uint64_t mem_size, io_size, pf_mem_size;
3782a6469d9bSprasad uint64_t mem_end, pf_mem_end, io_end;
378370025d76Sjohnny uint64_t round_answer, round_len;
378400d0963fSdilpreet ppb_ranges_t range[PCICFG_RANGE_LEN];
378570025d76Sjohnny int bus_range[2];
378670025d76Sjohnny pcicfg_phdl_t phdl;
378770025d76Sjohnny uint64_t pcibus_base, pcibus_alen;
378870025d76Sjohnny uint64_t max_bus;
378970025d76Sjohnny uint8_t pcie_device_type = 0;
3790a6469d9bSprasad uint_t pf_mem_supported = 0;
379126947304SEvan Yan dev_info_t *new_device;
379226947304SEvan Yan int trans_device;
379326947304SEvan Yan int ari_mode = B_FALSE;
379426947304SEvan Yan int max_function = PCI_MAX_FUNCTIONS;
3795a6469d9bSprasad
3796a6469d9bSprasad io_answer = io_base = io_alen = io_size = 0;
3797a6469d9bSprasad pf_mem_answer = pf_mem_base = pf_mem_size = pf_mem_alen = 0;
379870025d76Sjohnny
379926947304SEvan Yan /*
380026947304SEvan Yan * Set "device_type" to "pci", the actual type will be set later
380126947304SEvan Yan * by pcicfg_set_busnode_props() below. This is needed as the
380226947304SEvan Yan * pcicfg_ra_free() below would update "available" property based
380326947304SEvan Yan * on "device_type".
380426947304SEvan Yan *
380526947304SEvan Yan * This code can be removed later after PCI configurator is changed
380626947304SEvan Yan * to use PCIRM, which automatically update properties upon allocation
380726947304SEvan Yan * and free, at that time we'll be able to remove the code inside
380826947304SEvan Yan * ndi_ra_alloc/free() which currently updates "available" property
380926947304SEvan Yan * for pci/pcie devices in pcie fabric.
381026947304SEvan Yan */
381126947304SEvan Yan if (ndi_prop_update_string(DDI_DEV_T_NONE, new_child,
381226947304SEvan Yan "device_type", "pci") != DDI_SUCCESS) {
381326947304SEvan Yan DEBUG0("Failed to set \"device_type\" props\n");
381426947304SEvan Yan return (PCICFG_FAILURE);
381526947304SEvan Yan }
381626947304SEvan Yan
3817a6469d9bSprasad /*
3818a6469d9bSprasad * setup resource maps for the bridge node
3819a6469d9bSprasad */
3820a6469d9bSprasad if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_PCI_BUSNUM)
382126947304SEvan Yan == NDI_FAILURE) {
3822a6469d9bSprasad DEBUG0("Can not setup resource map - NDI_RA_TYPE_PCI_BUSNUM\n");
3823a6469d9bSprasad rval = PCICFG_FAILURE;
3824a6469d9bSprasad goto cleanup;
3825a6469d9bSprasad }
3826a6469d9bSprasad if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_MEM) == NDI_FAILURE) {
3827a6469d9bSprasad DEBUG0("Can not setup resource map - NDI_RA_TYPE_MEM\n");
3828a6469d9bSprasad rval = PCICFG_FAILURE;
3829a6469d9bSprasad goto cleanup;
3830a6469d9bSprasad }
3831a6469d9bSprasad if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_IO) == NDI_FAILURE) {
3832a6469d9bSprasad DEBUG0("Can not setup resource map - NDI_RA_TYPE_IO\n");
3833a6469d9bSprasad rval = PCICFG_FAILURE;
3834a6469d9bSprasad goto cleanup;
3835a6469d9bSprasad }
3836a6469d9bSprasad if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_PCI_PREFETCH_MEM) ==
383726947304SEvan Yan NDI_FAILURE) {
3838a6469d9bSprasad DEBUG0("Can not setup resource map -"
383926947304SEvan Yan " NDI_RA_TYPE_PCI_PREFETCH_MEM\n");
3840a6469d9bSprasad rval = PCICFG_FAILURE;
3841a6469d9bSprasad goto cleanup;
3842a6469d9bSprasad }
3843a6469d9bSprasad
3844a6469d9bSprasad /*
3845a6469d9bSprasad * Allocate bus range pool for the bridge.
3846a6469d9bSprasad */
384770025d76Sjohnny bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
384870025d76Sjohnny req.ra_flags = (NDI_RA_ALLOC_BOUNDED | NDI_RA_ALLOC_PARTIAL_OK);
384970025d76Sjohnny req.ra_boundbase = 0;
385023c35297Sanish req.ra_boundlen = req.ra_len = (PCI_MAX_BUS_NUM -1);
385170025d76Sjohnny req.ra_align_mask = 0; /* no alignment needed */
385270025d76Sjohnny
385370025d76Sjohnny rval = ndi_ra_alloc(ddi_get_parent(new_child), &req,
385470025d76Sjohnny &pcibus_base, &pcibus_alen, NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS);
385570025d76Sjohnny
385670025d76Sjohnny if (rval != NDI_SUCCESS) {
385770025d76Sjohnny if (rval == NDI_RA_PARTIAL_REQ) {
385870025d76Sjohnny /*EMPTY*/
385970025d76Sjohnny DEBUG0("NDI_RA_PARTIAL_REQ returned for bus range\n");
386070025d76Sjohnny } else {
386170025d76Sjohnny DEBUG0(
386270025d76Sjohnny "Failed to allocate bus range for bridge\n");
38635af4ae46Sjveta rval = PCICFG_NORESRC;
3864a6469d9bSprasad goto cleanup;
386570025d76Sjohnny }
386670025d76Sjohnny }
386770025d76Sjohnny
386870025d76Sjohnny DEBUG2("Bus Range Allocated [base=%d] [len=%d]\n",
386926947304SEvan Yan pcibus_base, pcibus_alen);
387070025d76Sjohnny
387170025d76Sjohnny /*
387270025d76Sjohnny * Put available bus range into the pool.
387370025d76Sjohnny * Take the first one for this bridge to use and don't give
387470025d76Sjohnny * to child.
387570025d76Sjohnny */
387670025d76Sjohnny (void) ndi_ra_free(new_child, pcibus_base+1, pcibus_alen-1,
387726947304SEvan Yan NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS);
387870025d76Sjohnny
387970025d76Sjohnny next_bus = pcibus_base;
388070025d76Sjohnny max_bus = pcibus_base + pcibus_alen - 1;
388170025d76Sjohnny
388270025d76Sjohnny new_bus = next_bus;
388370025d76Sjohnny
388470025d76Sjohnny DEBUG1("NEW bus found ->[%d]\n", new_bus);
388570025d76Sjohnny
388670025d76Sjohnny /* Keep track of highest bus for subordinate bus programming */
388770025d76Sjohnny *highest_bus = new_bus;
388870025d76Sjohnny
388970025d76Sjohnny /*
3890a6469d9bSprasad * Allocate (non-prefetchable) Memory Space for Bridge
389170025d76Sjohnny */
389270025d76Sjohnny bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
389370025d76Sjohnny req.ra_flags = (NDI_RA_ALLOC_BOUNDED | NDI_RA_ALLOC_PARTIAL_OK);
389470025d76Sjohnny req.ra_boundbase = 0;
389570025d76Sjohnny /*
389670025d76Sjohnny * limit the boundlen,len to a 32b quantity. It should be Ok to
389770025d76Sjohnny * lose alignment-based-size of resource due to this.
389870025d76Sjohnny */
389970025d76Sjohnny req.ra_boundlen = PCICFG_4GIG_LIMIT;
390070025d76Sjohnny req.ra_len = PCICFG_4GIG_LIMIT; /* Get as big as possible */
390170025d76Sjohnny req.ra_align_mask =
390270025d76Sjohnny PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */
390370025d76Sjohnny
390470025d76Sjohnny rval = ndi_ra_alloc(ddi_get_parent(new_child), &req,
390570025d76Sjohnny &mem_answer, &mem_alen, NDI_RA_TYPE_MEM, NDI_RA_PASS);
390670025d76Sjohnny
390770025d76Sjohnny if (rval != NDI_SUCCESS) {
390870025d76Sjohnny if (rval == NDI_RA_PARTIAL_REQ) {
390970025d76Sjohnny /*EMPTY*/
391070025d76Sjohnny DEBUG0("NDI_RA_PARTIAL_REQ returned\n");
391170025d76Sjohnny } else {
391270025d76Sjohnny DEBUG0(
391370025d76Sjohnny "Failed to allocate memory for bridge\n");
39145af4ae46Sjveta rval = PCICFG_NORESRC;
3915a6469d9bSprasad goto cleanup;
391670025d76Sjohnny }
391770025d76Sjohnny }
391870025d76Sjohnny
391970025d76Sjohnny DEBUG3("Bridge Memory Allocated [0x%x.%x] len [0x%x]\n",
392070025d76Sjohnny PCICFG_HIADDR(mem_answer),
392170025d76Sjohnny PCICFG_LOADDR(mem_answer),
392270025d76Sjohnny mem_alen);
392370025d76Sjohnny
392470025d76Sjohnny /*
392570025d76Sjohnny * Put available memory into the pool.
392670025d76Sjohnny */
392770025d76Sjohnny (void) ndi_ra_free(new_child, mem_answer, mem_alen, NDI_RA_TYPE_MEM,
392870025d76Sjohnny NDI_RA_PASS);
392970025d76Sjohnny
393070025d76Sjohnny mem_base = mem_answer;
393170025d76Sjohnny
393270025d76Sjohnny /*
393370025d76Sjohnny * Allocate I/O Space for Bridge
393470025d76Sjohnny */
393570025d76Sjohnny bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
393670025d76Sjohnny req.ra_align_mask = PCICFG_IOGRAN - 1; /* 4k alignment */
393770025d76Sjohnny req.ra_boundbase = 0;
393870025d76Sjohnny req.ra_boundlen = PCICFG_4GIG_LIMIT;
393970025d76Sjohnny req.ra_flags = (NDI_RA_ALLOC_BOUNDED | NDI_RA_ALLOC_PARTIAL_OK);
394070025d76Sjohnny req.ra_len = PCICFG_4GIG_LIMIT; /* Get as big as possible */
394170025d76Sjohnny
394270025d76Sjohnny rval = ndi_ra_alloc(ddi_get_parent(new_child), &req, &io_answer,
394370025d76Sjohnny &io_alen, NDI_RA_TYPE_IO, NDI_RA_PASS);
394470025d76Sjohnny
394570025d76Sjohnny if (rval != NDI_SUCCESS) {
394670025d76Sjohnny if (rval == NDI_RA_PARTIAL_REQ) {
394770025d76Sjohnny /*EMPTY*/
394870025d76Sjohnny DEBUG0("NDI_RA_PARTIAL_REQ returned\n");
394970025d76Sjohnny } else {
395070025d76Sjohnny DEBUG0("Failed to allocate io space for bridge\n");
3951a6469d9bSprasad /* i/o space is an optional requirement so continue */
395270025d76Sjohnny }
395370025d76Sjohnny }
395470025d76Sjohnny
395570025d76Sjohnny DEBUG3("Bridge IO Space Allocated [0x%x.%x] len [0x%x]\n",
395670025d76Sjohnny PCICFG_HIADDR(io_answer), PCICFG_LOADDR(io_answer), io_alen);
395770025d76Sjohnny
395870025d76Sjohnny /*
395970025d76Sjohnny * Put available I/O into the pool.
396070025d76Sjohnny */
396170025d76Sjohnny (void) ndi_ra_free(new_child, io_answer, io_alen, NDI_RA_TYPE_IO,
396270025d76Sjohnny NDI_RA_PASS);
396370025d76Sjohnny
396470025d76Sjohnny io_base = io_answer;
396570025d76Sjohnny
3966a6469d9bSprasad /*
3967a6469d9bSprasad * Check if the bridge supports Prefetchable memory range.
3968a6469d9bSprasad * If it does, then we setup PF memory range for the bridge.
3969a6469d9bSprasad * Otherwise, we skip the step of setting up PF memory
3970a6469d9bSprasad * range for it. This could cause config operation to
3971a6469d9bSprasad * fail if any devices under the bridge need PF memory.
3972a6469d9bSprasad */
3973a6469d9bSprasad /* write a non zero value to the PF BASE register */
3974a6469d9bSprasad pci_config_put16(h, PCI_BCNF_PF_BASE_LOW, 0xfff0);
3975a6469d9bSprasad /* if the read returns zero then PF range is not supported */
3976a6469d9bSprasad if (pci_config_get16(h, PCI_BCNF_PF_BASE_LOW) == 0) {
3977a6469d9bSprasad /* bridge doesn't support PF memory range */
3978a6469d9bSprasad goto pf_setup_end;
3979a6469d9bSprasad } else {
3980a6469d9bSprasad pf_mem_supported = 1;
3981a6469d9bSprasad /* reset the PF BASE register */
3982a6469d9bSprasad pci_config_put16(h, PCI_BCNF_PF_BASE_LOW, 0);
3983a6469d9bSprasad }
398470025d76Sjohnny
398570025d76Sjohnny /*
3986a6469d9bSprasad * Bridge supports PF mem range; Allocate PF Memory Space for it.
3987a6469d9bSprasad *
3988a6469d9bSprasad * Note: Both non-prefetchable and prefetchable memory space
3989a6469d9bSprasad * allocations are made within 32bit space. Currently, BIOSs
3990a6469d9bSprasad * allocate device memory for PCI devices within the 32bit space
3991a6469d9bSprasad * so this will not be a problem.
399270025d76Sjohnny */
3993a6469d9bSprasad bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
3994a6469d9bSprasad req.ra_flags = NDI_RA_ALLOC_PARTIAL_OK | NDI_RA_ALLOC_BOUNDED;
3995a6469d9bSprasad req.ra_boundbase = 0;
3996a6469d9bSprasad req.ra_len = PCICFG_4GIG_LIMIT; /* Get as big as possible */
3997a6469d9bSprasad req.ra_align_mask =
3998a6469d9bSprasad PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */
399970025d76Sjohnny
4000a6469d9bSprasad rval = ndi_ra_alloc(ddi_get_parent(new_child), &req,
4001a6469d9bSprasad &pf_mem_answer, &pf_mem_alen, NDI_RA_TYPE_PCI_PREFETCH_MEM,
4002a6469d9bSprasad NDI_RA_PASS);
400370025d76Sjohnny
4004a6469d9bSprasad if (rval != NDI_SUCCESS) {
4005a6469d9bSprasad if (rval == NDI_RA_PARTIAL_REQ) {
4006a6469d9bSprasad /*EMPTY*/
4007a6469d9bSprasad DEBUG0("NDI_RA_PARTIAL_REQ returned\n");
4008a6469d9bSprasad } else {
4009a6469d9bSprasad DEBUG0(
4010a6469d9bSprasad "Failed to allocate PF memory for bridge\n");
4011a6469d9bSprasad /* PF mem is an optional requirement so continue */
4012a6469d9bSprasad }
4013a6469d9bSprasad }
4014a6469d9bSprasad
4015a6469d9bSprasad DEBUG3("Bridge PF Memory Allocated [0x%x.%x] len [0x%x]\n",
4016a6469d9bSprasad PCICFG_HIADDR(pf_mem_answer),
4017a6469d9bSprasad PCICFG_LOADDR(pf_mem_answer),
4018a6469d9bSprasad pf_mem_alen);
4019a6469d9bSprasad
4020a6469d9bSprasad /*
4021a6469d9bSprasad * Put available PF memory into the pool.
4022a6469d9bSprasad */
4023a6469d9bSprasad (void) ndi_ra_free(new_child, pf_mem_answer, pf_mem_alen,
4024a6469d9bSprasad NDI_RA_TYPE_PCI_PREFETCH_MEM, NDI_RA_PASS);
4025a6469d9bSprasad
4026a6469d9bSprasad pf_mem_base = pf_mem_answer;
4027a6469d9bSprasad
4028a6469d9bSprasad /*
4029a6469d9bSprasad * Program the PF memory base register with the
4030a6469d9bSprasad * start of the memory range
4031a6469d9bSprasad */
4032a6469d9bSprasad pci_config_put16(h, PCI_BCNF_PF_BASE_LOW,
4033a6469d9bSprasad PCICFG_HIWORD(PCICFG_LOADDR(pf_mem_answer)));
4034a6469d9bSprasad pci_config_put32(h, PCI_BCNF_PF_BASE_HIGH,
4035a6469d9bSprasad PCICFG_HIADDR(pf_mem_answer));
4036a6469d9bSprasad
4037a6469d9bSprasad /*
4038a6469d9bSprasad * Program the PF memory limit register with the
4039a6469d9bSprasad * end of the memory range.
4040a6469d9bSprasad */
4041a6469d9bSprasad pci_config_put16(h, PCI_BCNF_PF_LIMIT_LOW,
4042a6469d9bSprasad PCICFG_HIWORD(PCICFG_LOADDR(
4043a6469d9bSprasad PCICFG_ROUND_DOWN((pf_mem_answer + pf_mem_alen),
4044a6469d9bSprasad PCICFG_MEMGRAN) - 1)));
4045a6469d9bSprasad pci_config_put32(h, PCI_BCNF_PF_LIMIT_HIGH,
4046a6469d9bSprasad PCICFG_HIADDR(PCICFG_ROUND_DOWN((pf_mem_answer + pf_mem_alen),
4047a6469d9bSprasad PCICFG_MEMGRAN) - 1));
4048a6469d9bSprasad
4049a6469d9bSprasad /*
4050a6469d9bSprasad * Allocate the chunk of PF memory (if any) not programmed into the
4051a6469d9bSprasad * bridge because of the round down.
4052a6469d9bSprasad */
4053a6469d9bSprasad if (PCICFG_ROUND_DOWN((pf_mem_answer + pf_mem_alen), PCICFG_MEMGRAN)
4054a6469d9bSprasad != (pf_mem_answer + pf_mem_alen)) {
4055a6469d9bSprasad DEBUG0("Need to allocate Memory round off chunk\n");
4056a6469d9bSprasad bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
4057a6469d9bSprasad req.ra_flags = NDI_RA_ALLOC_SPECIFIED;
4058a6469d9bSprasad req.ra_addr = PCICFG_ROUND_DOWN((pf_mem_answer + pf_mem_alen),
4059a6469d9bSprasad PCICFG_MEMGRAN);
4060a6469d9bSprasad req.ra_len = (pf_mem_answer + pf_mem_alen) -
4061a6469d9bSprasad (PCICFG_ROUND_DOWN((pf_mem_answer + pf_mem_alen),
4062a6469d9bSprasad PCICFG_MEMGRAN));
4063a6469d9bSprasad
4064a6469d9bSprasad (void) ndi_ra_alloc(new_child, &req,
4065a6469d9bSprasad &round_answer, &round_len, NDI_RA_TYPE_PCI_PREFETCH_MEM,
4066a6469d9bSprasad NDI_RA_PASS);
4067a6469d9bSprasad }
4068a6469d9bSprasad
4069a6469d9bSprasad pf_setup_end:
407070025d76Sjohnny
407170025d76Sjohnny /*
407270025d76Sjohnny * Program the memory base register with the
407370025d76Sjohnny * start of the memory range
407470025d76Sjohnny */
407570025d76Sjohnny pci_config_put16(h, PCI_BCNF_MEM_BASE,
407670025d76Sjohnny PCICFG_HIWORD(PCICFG_LOADDR(mem_answer)));
407770025d76Sjohnny
407870025d76Sjohnny /*
407970025d76Sjohnny * Program the memory limit register with the
408070025d76Sjohnny * end of the memory range.
408170025d76Sjohnny */
408270025d76Sjohnny
408370025d76Sjohnny pci_config_put16(h, PCI_BCNF_MEM_LIMIT,
408470025d76Sjohnny PCICFG_HIWORD(PCICFG_LOADDR(
408570025d76Sjohnny PCICFG_ROUND_DOWN((mem_answer + mem_alen), PCICFG_MEMGRAN) - 1)));
408670025d76Sjohnny
408770025d76Sjohnny /*
408870025d76Sjohnny * Allocate the chunk of memory (if any) not programmed into the
408970025d76Sjohnny * bridge because of the round down.
409070025d76Sjohnny */
409170025d76Sjohnny if (PCICFG_ROUND_DOWN((mem_answer + mem_alen), PCICFG_MEMGRAN)
409270025d76Sjohnny != (mem_answer + mem_alen)) {
409370025d76Sjohnny DEBUG0("Need to allocate Memory round off chunk\n");
409470025d76Sjohnny bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
409570025d76Sjohnny req.ra_flags = NDI_RA_ALLOC_SPECIFIED;
409670025d76Sjohnny req.ra_addr = PCICFG_ROUND_DOWN((mem_answer + mem_alen),
409770025d76Sjohnny PCICFG_MEMGRAN);
409870025d76Sjohnny req.ra_len = (mem_answer + mem_alen) -
409970025d76Sjohnny (PCICFG_ROUND_DOWN((mem_answer + mem_alen),
410070025d76Sjohnny PCICFG_MEMGRAN));
410170025d76Sjohnny
410270025d76Sjohnny (void) ndi_ra_alloc(new_child, &req,
410370025d76Sjohnny &round_answer, &round_len, NDI_RA_TYPE_MEM, NDI_RA_PASS);
410470025d76Sjohnny }
410570025d76Sjohnny
410670025d76Sjohnny /*
410770025d76Sjohnny * Program the I/O Space Base
410870025d76Sjohnny */
410970025d76Sjohnny pci_config_put8(h, PCI_BCNF_IO_BASE_LOW,
411070025d76Sjohnny PCICFG_HIBYTE(PCICFG_LOWORD(
411170025d76Sjohnny PCICFG_LOADDR(io_answer))));
411270025d76Sjohnny
411370025d76Sjohnny pci_config_put16(h, PCI_BCNF_IO_BASE_HI,
411470025d76Sjohnny PCICFG_HIWORD(PCICFG_LOADDR(io_answer)));
411570025d76Sjohnny
411670025d76Sjohnny /*
411770025d76Sjohnny * Program the I/O Space Limit
411870025d76Sjohnny */
411970025d76Sjohnny pci_config_put8(h, PCI_BCNF_IO_LIMIT_LOW,
412070025d76Sjohnny PCICFG_HIBYTE(PCICFG_LOWORD(
412170025d76Sjohnny PCICFG_LOADDR(PCICFG_ROUND_DOWN(io_answer + io_alen,
412270025d76Sjohnny PCICFG_IOGRAN)))) - 1);
412370025d76Sjohnny
412470025d76Sjohnny pci_config_put16(h, PCI_BCNF_IO_LIMIT_HI,
412570025d76Sjohnny PCICFG_HIWORD(PCICFG_LOADDR(
412670025d76Sjohnny PCICFG_ROUND_DOWN(io_answer + io_alen, PCICFG_IOGRAN)))
412770025d76Sjohnny - 1);
412870025d76Sjohnny
412970025d76Sjohnny /*
413070025d76Sjohnny * Allocate the chunk of I/O (if any) not programmed into the
413170025d76Sjohnny * bridge because of the round down.
413270025d76Sjohnny */
413370025d76Sjohnny if (PCICFG_ROUND_DOWN((io_answer + io_alen), PCICFG_IOGRAN)
413470025d76Sjohnny != (io_answer + io_alen)) {
413570025d76Sjohnny DEBUG0("Need to allocate I/O round off chunk\n");
413670025d76Sjohnny bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
413770025d76Sjohnny req.ra_flags = NDI_RA_ALLOC_SPECIFIED;
413870025d76Sjohnny req.ra_addr = PCICFG_ROUND_DOWN((io_answer + io_alen),
413970025d76Sjohnny PCICFG_IOGRAN);
414070025d76Sjohnny req.ra_len = (io_answer + io_alen) -
414170025d76Sjohnny (PCICFG_ROUND_DOWN((io_answer + io_alen),
414270025d76Sjohnny PCICFG_IOGRAN));
414370025d76Sjohnny
414470025d76Sjohnny (void) ndi_ra_alloc(new_child, &req,
414570025d76Sjohnny &round_answer, &round_len, NDI_RA_TYPE_IO, NDI_RA_PASS);
414670025d76Sjohnny }
414770025d76Sjohnny
4148a6469d9bSprasad (void) pcicfg_set_bus_numbers(h, bus, new_bus, max_bus);
4149a6469d9bSprasad
41503f9ec228SZhi-Jun Robin Fu /*
41513f9ec228SZhi-Jun Robin Fu * Setup "ranges" and "bus-range" properties before onlining
41523f9ec228SZhi-Jun Robin Fu * the bridge.
41533f9ec228SZhi-Jun Robin Fu */
41543f9ec228SZhi-Jun Robin Fu bzero((caddr_t)range, sizeof (ppb_ranges_t) * PCICFG_RANGE_LEN);
41553f9ec228SZhi-Jun Robin Fu
41563f9ec228SZhi-Jun Robin Fu range[0].child_high = range[0].parent_high |= (PCI_REG_REL_M |
41573f9ec228SZhi-Jun Robin Fu PCI_ADDR_IO);
41583f9ec228SZhi-Jun Robin Fu range[0].child_low = range[0].parent_low = io_base;
41593f9ec228SZhi-Jun Robin Fu range[1].child_high = range[1].parent_high |=
41603f9ec228SZhi-Jun Robin Fu (PCI_REG_REL_M | PCI_ADDR_MEM32);
41613f9ec228SZhi-Jun Robin Fu range[1].child_low = range[1].parent_low = mem_base;
41623f9ec228SZhi-Jun Robin Fu range[2].child_high = range[2].parent_high |=
41633f9ec228SZhi-Jun Robin Fu (PCI_REG_REL_M | PCI_ADDR_MEM64 | PCI_REG_PF_M);
41643f9ec228SZhi-Jun Robin Fu range[2].child_low = range[2].parent_low = pf_mem_base;
41653f9ec228SZhi-Jun Robin Fu
41663f9ec228SZhi-Jun Robin Fu range[0].size_low = io_alen;
41673f9ec228SZhi-Jun Robin Fu (void) pcicfg_update_ranges_prop(new_child, &range[0]);
41683f9ec228SZhi-Jun Robin Fu range[1].size_low = mem_alen;
41693f9ec228SZhi-Jun Robin Fu (void) pcicfg_update_ranges_prop(new_child, &range[1]);
41703f9ec228SZhi-Jun Robin Fu range[2].size_low = pf_mem_alen;
41713f9ec228SZhi-Jun Robin Fu (void) pcicfg_update_ranges_prop(new_child, &range[2]);
41723f9ec228SZhi-Jun Robin Fu
41733f9ec228SZhi-Jun Robin Fu bus_range[0] = new_bus;
41743f9ec228SZhi-Jun Robin Fu bus_range[1] = max_bus;
41753f9ec228SZhi-Jun Robin Fu (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, new_child,
41763f9ec228SZhi-Jun Robin Fu "bus-range", bus_range, 2);
41773f9ec228SZhi-Jun Robin Fu
417870025d76Sjohnny /*
4179a6469d9bSprasad * Reset the secondary bus
418070025d76Sjohnny */
4181a6469d9bSprasad pci_config_put16(h, PCI_BCNF_BCNTRL,
4182a6469d9bSprasad pci_config_get16(h, PCI_BCNF_BCNTRL) | 0x40);
4183a6469d9bSprasad
4184a6469d9bSprasad drv_usecwait(100);
4185a6469d9bSprasad
4186a6469d9bSprasad pci_config_put16(h, PCI_BCNF_BCNTRL,
4187a6469d9bSprasad pci_config_get16(h, PCI_BCNF_BCNTRL) & ~0x40);
418870025d76Sjohnny
418970025d76Sjohnny /*
4190a6469d9bSprasad * Clear status bits
419170025d76Sjohnny */
4192a6469d9bSprasad pci_config_put16(h, PCI_BCNF_SEC_STATUS, 0xffff);
419370025d76Sjohnny
419470025d76Sjohnny /*
419570025d76Sjohnny * Needs to be set to this value
419670025d76Sjohnny */
419770025d76Sjohnny pci_config_put8(h, PCI_CONF_ILINE, 0xf);
419870025d76Sjohnny
419970025d76Sjohnny /* check our device_type as defined by Open Firmware */
420070025d76Sjohnny if (pcicfg_pcie_device_type(new_child, h) == DDI_SUCCESS)
420170025d76Sjohnny pcie_device_type = 1;
420270025d76Sjohnny
420370025d76Sjohnny /*
420470025d76Sjohnny * Set bus properties
420570025d76Sjohnny */
420670025d76Sjohnny if (pcicfg_set_busnode_props(new_child, pcie_device_type)
420726947304SEvan Yan != PCICFG_SUCCESS) {
420870025d76Sjohnny DEBUG0("Failed to set busnode props\n");
4209a6469d9bSprasad rval = PCICFG_FAILURE;
4210a6469d9bSprasad goto cleanup;
421170025d76Sjohnny }
421270025d76Sjohnny
421370025d76Sjohnny (void) pcicfg_device_on(h);
421470025d76Sjohnny
4215c0da6274SZhi-Jun Robin Fu if (is_pcie)
4216c1374a13SSurya Prakki (void) pcie_init_bus(new_child, 0, PCIE_BUS_FINAL);
421770025d76Sjohnny if (ndi_devi_online(new_child, NDI_NO_EVENT|NDI_CONFIG)
421870025d76Sjohnny != NDI_SUCCESS) {
421970025d76Sjohnny DEBUG0("Unable to online bridge\n");
4220a6469d9bSprasad rval = PCICFG_FAILURE;
4221a6469d9bSprasad goto cleanup;
422270025d76Sjohnny }
422370025d76Sjohnny
422470025d76Sjohnny DEBUG0("Bridge is ONLINE\n");
422570025d76Sjohnny
422670025d76Sjohnny /*
422770025d76Sjohnny * After a Reset, we need to wait 2^25 clock cycles before the
422870025d76Sjohnny * first Configuration access. The worst case is 33MHz, which
422970025d76Sjohnny * is a 1 second wait.
423070025d76Sjohnny */
423170025d76Sjohnny drv_usecwait(pcicfg_sec_reset_delay);
423270025d76Sjohnny
423370025d76Sjohnny /*
423470025d76Sjohnny * Probe all children devices
423570025d76Sjohnny */
423670025d76Sjohnny DEBUG0("Bridge Programming Complete - probe children\n");
42373fe80ca4SDan Cross ndi_devi_enter(new_child);
423826947304SEvan Yan for (i = 0; ((i < PCI_MAX_DEVICES) && (ari_mode == B_FALSE));
423926947304SEvan Yan i++) {
424026947304SEvan Yan for (j = 0; j < max_function; ) {
424126947304SEvan Yan if (ari_mode)
424226947304SEvan Yan trans_device = j >> 3;
424326947304SEvan Yan else
424426947304SEvan Yan trans_device = i;
424526947304SEvan Yan
424670025d76Sjohnny if ((rval = pcicfg_probe_children(new_child,
4247c0da6274SZhi-Jun Robin Fu new_bus, trans_device, j & 7, highest_bus,
4248c0da6274SZhi-Jun Robin Fu 0, is_pcie)) != PCICFG_SUCCESS) {
424970025d76Sjohnny if (rval == PCICFG_NODEVICE) {
425070025d76Sjohnny DEBUG3("No Device at bus [0x%x]"
425126947304SEvan Yan "device [0x%x] "
425226947304SEvan Yan "func [0x%x]\n", new_bus,
425326947304SEvan Yan trans_device, j & 7);
425426947304SEvan Yan
425570025d76Sjohnny if (j)
425626947304SEvan Yan goto next;
425770025d76Sjohnny } else
425870025d76Sjohnny /*EMPTY*/
425970025d76Sjohnny DEBUG3("Failed to configure bus "
426026947304SEvan Yan "[0x%x] device [0x%x] "
426126947304SEvan Yan "func [0x%x]\n", new_bus,
426226947304SEvan Yan trans_device, j & 7);
426370025d76Sjohnny break;
426470025d76Sjohnny }
426526947304SEvan Yan next:
426626947304SEvan Yan new_device = pcicfg_devi_find(new_child, trans_device,
426726947304SEvan Yan (j & 7));
426826947304SEvan Yan
426926947304SEvan Yan /*
427026947304SEvan Yan * Determine if ARI Forwarding should be enabled.
427126947304SEvan Yan */
427226947304SEvan Yan if (j == 0) {
427326947304SEvan Yan if (new_device == NULL)
427426947304SEvan Yan break;
427526947304SEvan Yan
427626947304SEvan Yan if ((pcie_ari_supported(new_child) ==
427726947304SEvan Yan PCIE_ARI_FORW_SUPPORTED) &&
427826947304SEvan Yan (pcie_ari_device(new_device) ==
427926947304SEvan Yan PCIE_ARI_DEVICE)) {
428026947304SEvan Yan if (pcie_ari_enable(new_child) ==
428126947304SEvan Yan DDI_SUCCESS) {
428226947304SEvan Yan (void) ddi_prop_create(
428326947304SEvan Yan DDI_DEV_T_NONE,
428426947304SEvan Yan new_child,
428526947304SEvan Yan DDI_PROP_CANSLEEP,
428626947304SEvan Yan "ari-enabled", NULL, 0);
428726947304SEvan Yan ari_mode = B_TRUE;
428826947304SEvan Yan max_function =
428926947304SEvan Yan PCICFG_MAX_ARI_FUNCTION;
429026947304SEvan Yan }
429126947304SEvan Yan }
429226947304SEvan Yan }
429326947304SEvan Yan if (ari_mode == B_TRUE) {
429426947304SEvan Yan int next_function;
429526947304SEvan Yan
429626947304SEvan Yan if (new_device == NULL)
429726947304SEvan Yan break;
429826947304SEvan Yan
429926947304SEvan Yan if (pcie_ari_get_next_function(new_device,
430026947304SEvan Yan &next_function) != DDI_SUCCESS)
430126947304SEvan Yan break;
430226947304SEvan Yan
430326947304SEvan Yan j = next_function;
430426947304SEvan Yan
430526947304SEvan Yan if (next_function == 0)
430626947304SEvan Yan break;
430726947304SEvan Yan } else
430826947304SEvan Yan j++;
430926947304SEvan Yan
431070025d76Sjohnny }
431170025d76Sjohnny /* if any function fails to be configured, no need to proceed */
431270025d76Sjohnny if (rval != PCICFG_NODEVICE)
431370025d76Sjohnny break;
431470025d76Sjohnny }
43153fe80ca4SDan Cross ndi_devi_exit(new_child);
431670025d76Sjohnny
431770025d76Sjohnny /*
431870025d76Sjohnny * Offline the bridge to allow reprogramming of resources.
431926947304SEvan Yan *
432026947304SEvan Yan * This should always succeed since nobody else has started to
432126947304SEvan Yan * use it yet, failing to detach the driver would indicate a bug.
432226947304SEvan Yan * Also in that case it's better just panic than allowing the
432326947304SEvan Yan * configurator to proceed with BAR reprogramming without bridge
432426947304SEvan Yan * driver detached.
432570025d76Sjohnny */
432626947304SEvan Yan VERIFY(ndi_devi_offline(new_child, NDI_NO_EVENT|NDI_UNCONFIG)
432726947304SEvan Yan == NDI_SUCCESS);
4328c0da6274SZhi-Jun Robin Fu if (is_pcie)
4329c0da6274SZhi-Jun Robin Fu pcie_fini_bus(new_child, PCIE_BUS_INITIAL);
433070025d76Sjohnny
433170025d76Sjohnny phdl.dip = new_child;
433270025d76Sjohnny phdl.memory_base = mem_answer;
433370025d76Sjohnny phdl.io_base = io_answer;
4334a6469d9bSprasad phdl.pf_memory_base = pf_mem_answer;
433570025d76Sjohnny phdl.error = PCICFG_SUCCESS; /* in case of empty child tree */
433670025d76Sjohnny
43373fe80ca4SDan Cross ndi_devi_enter(ddi_get_parent(new_child));
433870025d76Sjohnny ddi_walk_devs(new_child, pcicfg_find_resource_end, (void *)&phdl);
43393fe80ca4SDan Cross ndi_devi_exit(ddi_get_parent(new_child));
434070025d76Sjohnny
434170025d76Sjohnny num_slots = pcicfg_get_nslots(new_child, h);
434270025d76Sjohnny mem_end = PCICFG_ROUND_UP(phdl.memory_base, PCICFG_MEMGRAN);
434370025d76Sjohnny io_end = PCICFG_ROUND_UP(phdl.io_base, PCICFG_IOGRAN);
4344a6469d9bSprasad pf_mem_end = PCICFG_ROUND_UP(phdl.pf_memory_base, PCICFG_MEMGRAN);
434570025d76Sjohnny
434626947304SEvan Yan DEBUG4("Start of Unallocated Bridge(%d slots) Resources Mem=0x%lx "
434726947304SEvan Yan "I/O=0x%lx PF_mem=%x%lx\n", num_slots, mem_end, io_end, pf_mem_end);
434870025d76Sjohnny
434926947304SEvan Yan /*
435026947304SEvan Yan * Before probing the children we've allocated maximum MEM/IO
435126947304SEvan Yan * resources from parent, and updated "available" property
435226947304SEvan Yan * accordingly. Later we'll be giving up unused resources to
435326947304SEvan Yan * the parent, thus we need to destroy "available" property
435426947304SEvan Yan * here otherwise it will be out-of-sync with the actual free
435526947304SEvan Yan * resources this bridge has. This property will be rebuilt below
435626947304SEvan Yan * with the actual free resources reserved for hotplug slots
435726947304SEvan Yan * (if any).
435826947304SEvan Yan */
435926947304SEvan Yan (void) ndi_prop_remove(DDI_DEV_T_NONE, new_child, "available");
436070025d76Sjohnny /*
436170025d76Sjohnny * if the bridge a slots, then preallocate. If not, assume static
436270025d76Sjohnny * configuration. Also check for preallocation limits and spit
436370025d76Sjohnny * warning messages appropriately (perhaps some can be in debug mode).
436470025d76Sjohnny */
436570025d76Sjohnny if (num_slots) {
436626947304SEvan Yan uint64_t mem_reqd = mem_answer +
436726947304SEvan Yan (num_slots * pcicfg_slot_memsize);
436826947304SEvan Yan uint64_t io_reqd = io_answer +
436926947304SEvan Yan (num_slots * pcicfg_slot_iosize);
437026947304SEvan Yan uint64_t pf_mem_reqd = pf_mem_answer +
437126947304SEvan Yan (num_slots * pcicfg_slot_pf_memsize);
437226947304SEvan Yan uint8_t highest_bus_reqd = new_bus +
437326947304SEvan Yan (num_slots * pcicfg_slot_busnums);
4374949b8557Sarutz #ifdef DEBUG
437570025d76Sjohnny if (mem_end > mem_reqd)
4376949b8557Sarutz DEBUG3("Memory space consumed by bridge more "
437770025d76Sjohnny "than planned for %d slot(s)(%" PRIx64 ",%"
437870025d76Sjohnny PRIx64 ")", num_slots, mem_answer, mem_end);
437970025d76Sjohnny if (io_end > io_reqd)
4380949b8557Sarutz DEBUG3("IO space consumed by bridge more than"
438170025d76Sjohnny " planned for %d slot(s)(%" PRIx64 ",%" PRIx64 ")",
438270025d76Sjohnny num_slots, io_answer, io_end);
4383a6469d9bSprasad if (pf_mem_end > pf_mem_reqd)
4384949b8557Sarutz DEBUG3("PF Memory space consumed by bridge"
4385a6469d9bSprasad " more than planned for %d slot(s)(%" PRIx64 ",%"
4386a6469d9bSprasad PRIx64 ")", num_slots, pf_mem_answer, pf_mem_end);
438770025d76Sjohnny if (*highest_bus > highest_bus_reqd)
4388949b8557Sarutz DEBUG3("Buses consumed by bridge more "
438970025d76Sjohnny "than planned for %d slot(s)(%x, %x)",
439070025d76Sjohnny num_slots, new_bus, *highest_bus);
439170025d76Sjohnny
439270025d76Sjohnny if (mem_reqd > (mem_answer + mem_alen))
4393949b8557Sarutz DEBUG3("Memory space required by bridge more "
439470025d76Sjohnny "than available for %d slot(s)(%" PRIx64 ",%"
439570025d76Sjohnny PRIx64 ")", num_slots, mem_answer, mem_end);
439670025d76Sjohnny if (io_reqd > (io_answer + io_alen))
4397949b8557Sarutz DEBUG3("IO space required by bridge more than"
439870025d76Sjohnny "available for %d slot(s)(%" PRIx64 ",%" PRIx64 ")",
439970025d76Sjohnny num_slots, io_answer, io_end);
4400a6469d9bSprasad if (pf_mem_reqd > (pf_mem_answer + pf_mem_alen))
4401949b8557Sarutz DEBUG3("PF Memory space required by bridge"
4402a6469d9bSprasad " more than available for %d slot(s)(%" PRIx64 ",%"
4403a6469d9bSprasad PRIx64 ")", num_slots, pf_mem_answer, pf_mem_end);
440470025d76Sjohnny if (highest_bus_reqd > max_bus)
4405949b8557Sarutz DEBUG3("Bus numbers required by bridge more "
440670025d76Sjohnny "than available for %d slot(s)(%x, %x)",
440770025d76Sjohnny num_slots, new_bus, *highest_bus);
4408949b8557Sarutz #endif
440970025d76Sjohnny mem_end = MAX((MIN(mem_reqd, (mem_answer + mem_alen))),
441026947304SEvan Yan mem_end);
441170025d76Sjohnny io_end = MAX((MIN(io_reqd, (io_answer + io_alen))), io_end);
4412a6469d9bSprasad pf_mem_end = MAX((MIN(pf_mem_reqd, (pf_mem_answer +
441326947304SEvan Yan pf_mem_alen))), pf_mem_end);
441470025d76Sjohnny *highest_bus = MAX((MIN(highest_bus_reqd, max_bus)),
441526947304SEvan Yan *highest_bus);
4416a6469d9bSprasad DEBUG4("mem_end %lx, io_end %lx, pf_mem_end %lx"
441726947304SEvan Yan " highest_bus %x\n", mem_end, io_end, pf_mem_end,
441826947304SEvan Yan *highest_bus);
441970025d76Sjohnny }
442070025d76Sjohnny
442170025d76Sjohnny /*
442270025d76Sjohnny * Give back unused memory space to parent.
442370025d76Sjohnny */
442426947304SEvan Yan (void) ndi_ra_free(ddi_get_parent(new_child), mem_end,
442526947304SEvan Yan (mem_answer + mem_alen) - mem_end, NDI_RA_TYPE_MEM, NDI_RA_PASS);
442670025d76Sjohnny
442770025d76Sjohnny if (mem_end == mem_answer) {
442870025d76Sjohnny DEBUG0("No memory resources used\n");
442970025d76Sjohnny /*
443070025d76Sjohnny * To prevent the bridge from forwarding any Memory
443170025d76Sjohnny * transactions, the Memory Limit will be programmed
443270025d76Sjohnny * with a smaller value than the Memory Base.
443370025d76Sjohnny */
443470025d76Sjohnny pci_config_put16(h, PCI_BCNF_MEM_BASE, 0xffff);
443570025d76Sjohnny pci_config_put16(h, PCI_BCNF_MEM_LIMIT, 0);
443670025d76Sjohnny
443770025d76Sjohnny mem_size = 0;
443870025d76Sjohnny } else {
443970025d76Sjohnny /*
444070025d76Sjohnny * Reprogram the end of the memory.
444170025d76Sjohnny */
444270025d76Sjohnny pci_config_put16(h, PCI_BCNF_MEM_LIMIT,
444370025d76Sjohnny PCICFG_HIWORD(mem_end) - 1);
444470025d76Sjohnny mem_size = mem_end - mem_base;
444570025d76Sjohnny }
444670025d76Sjohnny
444770025d76Sjohnny /*
444870025d76Sjohnny * Give back unused io space to parent.
444970025d76Sjohnny */
445070025d76Sjohnny (void) ndi_ra_free(ddi_get_parent(new_child),
445170025d76Sjohnny io_end, (io_answer + io_alen) - io_end,
445270025d76Sjohnny NDI_RA_TYPE_IO, NDI_RA_PASS);
445370025d76Sjohnny
445470025d76Sjohnny if (io_end == io_answer) {
445570025d76Sjohnny DEBUG0("No IO Space resources used\n");
445670025d76Sjohnny
445770025d76Sjohnny /*
445870025d76Sjohnny * To prevent the bridge from forwarding any I/O
445970025d76Sjohnny * transactions, the I/O Limit will be programmed
446070025d76Sjohnny * with a smaller value than the I/O Base.
446170025d76Sjohnny */
446270025d76Sjohnny pci_config_put8(h, PCI_BCNF_IO_LIMIT_LOW, 0);
446370025d76Sjohnny pci_config_put16(h, PCI_BCNF_IO_LIMIT_HI, 0);
446470025d76Sjohnny pci_config_put8(h, PCI_BCNF_IO_BASE_LOW, 0xff);
446570025d76Sjohnny pci_config_put16(h, PCI_BCNF_IO_BASE_HI, 0);
446670025d76Sjohnny
446770025d76Sjohnny io_size = 0;
446870025d76Sjohnny } else {
446970025d76Sjohnny /*
447070025d76Sjohnny * Reprogram the end of the io space.
447170025d76Sjohnny */
447270025d76Sjohnny pci_config_put8(h, PCI_BCNF_IO_LIMIT_LOW,
447370025d76Sjohnny PCICFG_HIBYTE(PCICFG_LOWORD(
447470025d76Sjohnny PCICFG_LOADDR(io_end) - 1)));
447570025d76Sjohnny
447670025d76Sjohnny pci_config_put16(h, PCI_BCNF_IO_LIMIT_HI,
447770025d76Sjohnny PCICFG_HIWORD(PCICFG_LOADDR(io_end - 1)));
447870025d76Sjohnny
447970025d76Sjohnny io_size = io_end - io_base;
448070025d76Sjohnny }
448170025d76Sjohnny
4482a6469d9bSprasad /*
4483a6469d9bSprasad * Give back unused PF memory space to parent.
4484a6469d9bSprasad */
4485a6469d9bSprasad if (pf_mem_supported) {
448626947304SEvan Yan (void) ndi_ra_free(ddi_get_parent(new_child),
448726947304SEvan Yan pf_mem_end, (pf_mem_answer + pf_mem_alen) - pf_mem_end,
448826947304SEvan Yan NDI_RA_TYPE_PCI_PREFETCH_MEM, NDI_RA_PASS);
4489a6469d9bSprasad
449026947304SEvan Yan if (pf_mem_end == pf_mem_answer) {
449126947304SEvan Yan DEBUG0("No PF memory resources used\n");
449226947304SEvan Yan /*
449326947304SEvan Yan * To prevent the bridge from forwarding any PF Memory
449426947304SEvan Yan * transactions, the PF Memory Limit will be programmed
449526947304SEvan Yan * with a smaller value than the Memory Base.
449626947304SEvan Yan */
449726947304SEvan Yan pci_config_put16(h, PCI_BCNF_PF_BASE_LOW, 0xfff0);
449826947304SEvan Yan pci_config_put32(h, PCI_BCNF_PF_BASE_HIGH, 0xffffffff);
449926947304SEvan Yan pci_config_put16(h, PCI_BCNF_PF_LIMIT_LOW, 0);
450026947304SEvan Yan pci_config_put32(h, PCI_BCNF_PF_LIMIT_HIGH, 0);
4501a6469d9bSprasad
450226947304SEvan Yan pf_mem_size = 0;
450326947304SEvan Yan } else {
450426947304SEvan Yan /*
450526947304SEvan Yan * Reprogram the end of the PF memory range.
450626947304SEvan Yan */
450726947304SEvan Yan pci_config_put16(h, PCI_BCNF_PF_LIMIT_LOW,
450826947304SEvan Yan PCICFG_HIWORD(PCICFG_LOADDR(pf_mem_end - 1)));
450926947304SEvan Yan pci_config_put32(h, PCI_BCNF_PF_LIMIT_HIGH,
451026947304SEvan Yan PCICFG_HIADDR(pf_mem_end - 1));
451126947304SEvan Yan pf_mem_size = pf_mem_end - pf_mem_base;
451226947304SEvan Yan }
4513a6469d9bSprasad }
4514a6469d9bSprasad
451570025d76Sjohnny if ((max_bus - *highest_bus) > 0) {
451670025d76Sjohnny /*
451770025d76Sjohnny * Give back unused bus numbers
451870025d76Sjohnny */
451970025d76Sjohnny (void) ndi_ra_free(ddi_get_parent(new_child),
452026947304SEvan Yan *highest_bus+1, max_bus - *highest_bus,
452126947304SEvan Yan NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS);
452270025d76Sjohnny }
452370025d76Sjohnny
452470025d76Sjohnny /*
452570025d76Sjohnny * Set bus numbers to ranges encountered during scan
452670025d76Sjohnny */
452770025d76Sjohnny (void) pcicfg_set_bus_numbers(h, bus, new_bus, *highest_bus);
452870025d76Sjohnny
452970025d76Sjohnny /*
453070025d76Sjohnny * Remove the ranges property if it exists since we will create
453170025d76Sjohnny * a new one.
453270025d76Sjohnny */
453370025d76Sjohnny (void) ndi_prop_remove(DDI_DEV_T_NONE, new_child, "ranges");
453470025d76Sjohnny
453570025d76Sjohnny DEBUG2("Creating Ranges property - Mem Address %lx Mem Size %x\n",
453670025d76Sjohnny mem_base, mem_size);
453770025d76Sjohnny DEBUG2(" - I/O Address %lx I/O Size %x\n",
453870025d76Sjohnny io_base, io_size);
4539a6469d9bSprasad DEBUG2(" - PF Mem address %lx PF Mem Size %x\n",
4540a6469d9bSprasad pf_mem_base, pf_mem_size);
454170025d76Sjohnny
454200d0963fSdilpreet bzero((caddr_t)range, sizeof (ppb_ranges_t) * PCICFG_RANGE_LEN);
454370025d76Sjohnny
454400d0963fSdilpreet range[0].child_high = range[0].parent_high |= (PCI_REG_REL_M |
454500d0963fSdilpreet PCI_ADDR_IO);
454600d0963fSdilpreet range[0].child_low = range[0].parent_low = io_base;
454700d0963fSdilpreet range[1].child_high = range[1].parent_high |=
454870025d76Sjohnny (PCI_REG_REL_M | PCI_ADDR_MEM32);
454900d0963fSdilpreet range[1].child_low = range[1].parent_low = mem_base;
455000d0963fSdilpreet range[2].child_high = range[2].parent_high |=
4551a6469d9bSprasad (PCI_REG_REL_M | PCI_ADDR_MEM64 | PCI_REG_PF_M);
455200d0963fSdilpreet range[2].child_low = range[2].parent_low = pf_mem_base;
455370025d76Sjohnny
455470025d76Sjohnny if (io_size > 0) {
455500d0963fSdilpreet range[0].size_low = io_size;
4556a6469d9bSprasad (void) pcicfg_update_ranges_prop(new_child, &range[0]);
455770025d76Sjohnny }
455870025d76Sjohnny if (mem_size > 0) {
455900d0963fSdilpreet range[1].size_low = mem_size;
4560a6469d9bSprasad (void) pcicfg_update_ranges_prop(new_child, &range[1]);
4561a6469d9bSprasad }
4562a6469d9bSprasad if (pf_mem_size > 0) {
456300d0963fSdilpreet range[2].size_low = pf_mem_size;
4564a6469d9bSprasad (void) pcicfg_update_ranges_prop(new_child, &range[2]);
456570025d76Sjohnny }
456670025d76Sjohnny
456770025d76Sjohnny bus_range[0] = pci_config_get8(h, PCI_BCNF_SECBUS);
456870025d76Sjohnny bus_range[1] = pci_config_get8(h, PCI_BCNF_SUBBUS);
456970025d76Sjohnny DEBUG1("End of bridge probe: bus_range[0] = %d\n", bus_range[0]);
457070025d76Sjohnny DEBUG1("End of bridge probe: bus_range[1] = %d\n", bus_range[1]);
457170025d76Sjohnny
4572a6469d9bSprasad (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, new_child,
4573a6469d9bSprasad "bus-range", bus_range, 2);
457470025d76Sjohnny
4575a6469d9bSprasad rval = PCICFG_SUCCESS;
457670025d76Sjohnny
4577a6469d9bSprasad PCICFG_DUMP_BRIDGE_CONFIG(h);
457870025d76Sjohnny
4579a6469d9bSprasad cleanup:
4580a6469d9bSprasad /* free up resources (for error return case only) */
4581a6469d9bSprasad if (rval != PCICFG_SUCCESS) {
458226947304SEvan Yan if (mem_alen)
458326947304SEvan Yan (void) ndi_ra_free(ddi_get_parent(new_child), mem_base,
458426947304SEvan Yan mem_alen, NDI_RA_TYPE_MEM, NDI_RA_PASS);
458526947304SEvan Yan if (io_alen)
458626947304SEvan Yan (void) ndi_ra_free(ddi_get_parent(new_child), io_base,
458726947304SEvan Yan io_alen, NDI_RA_TYPE_IO, NDI_RA_PASS);
458826947304SEvan Yan if (pf_mem_alen)
458926947304SEvan Yan (void) ndi_ra_free(ddi_get_parent(new_child),
459026947304SEvan Yan pf_mem_base, pf_mem_alen,
459126947304SEvan Yan NDI_RA_TYPE_PCI_PREFETCH_MEM, NDI_RA_PASS);
459226947304SEvan Yan if (pcibus_alen)
459326947304SEvan Yan (void) ndi_ra_free(ddi_get_parent(new_child),
459426947304SEvan Yan pcibus_base, pcibus_alen, NDI_RA_TYPE_PCI_BUSNUM,
459526947304SEvan Yan NDI_RA_PASS);
4596a6469d9bSprasad }
4597a6469d9bSprasad
4598a6469d9bSprasad /* free up any resource maps setup for the bridge node */
4599a6469d9bSprasad (void) ndi_ra_map_destroy(new_child, NDI_RA_TYPE_PCI_BUSNUM);
4600a6469d9bSprasad (void) ndi_ra_map_destroy(new_child, NDI_RA_TYPE_IO);
4601a6469d9bSprasad (void) ndi_ra_map_destroy(new_child, NDI_RA_TYPE_MEM);
4602a6469d9bSprasad (void) ndi_ra_map_destroy(new_child, NDI_RA_TYPE_PCI_PREFETCH_MEM);
4603a6469d9bSprasad
4604a6469d9bSprasad return (rval);
460570025d76Sjohnny }
460670025d76Sjohnny
460770025d76Sjohnny static int
pcicfg_find_resource_end(dev_info_t * dip,void * hdl)460870025d76Sjohnny pcicfg_find_resource_end(dev_info_t *dip, void *hdl)
460970025d76Sjohnny {
461070025d76Sjohnny pcicfg_phdl_t *entry = (pcicfg_phdl_t *)hdl;
461170025d76Sjohnny pci_regspec_t *pci_ap;
461270025d76Sjohnny int length;
461370025d76Sjohnny int rcount;
461470025d76Sjohnny int i;
461570025d76Sjohnny
461670025d76Sjohnny entry->error = PCICFG_SUCCESS;
461770025d76Sjohnny
461870025d76Sjohnny if (dip == entry->dip) {
461970025d76Sjohnny DEBUG0("Don't include parent bridge node\n");
462070025d76Sjohnny return (DDI_WALK_CONTINUE);
462170025d76Sjohnny } else {
462270025d76Sjohnny if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
462370025d76Sjohnny DDI_PROP_DONTPASS, "assigned-addresses",
462470025d76Sjohnny (caddr_t)&pci_ap, &length) != DDI_PROP_SUCCESS) {
462570025d76Sjohnny DEBUG0("Node doesn't have assigned-addresses\n");
462670025d76Sjohnny return (DDI_WALK_CONTINUE);
462770025d76Sjohnny }
462870025d76Sjohnny
462970025d76Sjohnny rcount = length / sizeof (pci_regspec_t);
463070025d76Sjohnny
463170025d76Sjohnny for (i = 0; i < rcount; i++) {
463270025d76Sjohnny
463370025d76Sjohnny switch (PCI_REG_ADDR_G(pci_ap[i].pci_phys_hi)) {
463470025d76Sjohnny
463570025d76Sjohnny case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
463626947304SEvan Yan if (pci_ap[i].pci_phys_hi & PCI_REG_PF_M) {
463726947304SEvan Yan if ((pci_ap[i].pci_phys_low +
463826947304SEvan Yan pci_ap[i].pci_size_low) >
463926947304SEvan Yan entry->pf_memory_base) {
464026947304SEvan Yan entry->pf_memory_base =
464126947304SEvan Yan pci_ap[i].pci_phys_low +
464226947304SEvan Yan pci_ap[i].pci_size_low;
464326947304SEvan Yan }
464426947304SEvan Yan } else {
464526947304SEvan Yan if ((pci_ap[i].pci_phys_low +
464626947304SEvan Yan pci_ap[i].pci_size_low) >
464726947304SEvan Yan entry->memory_base) {
464826947304SEvan Yan entry->memory_base =
464926947304SEvan Yan pci_ap[i].pci_phys_low +
465026947304SEvan Yan pci_ap[i].pci_size_low;
465126947304SEvan Yan }
465270025d76Sjohnny }
465326947304SEvan Yan break;
465470025d76Sjohnny case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
465526947304SEvan Yan if (pci_ap[i].pci_phys_hi & PCI_REG_PF_M) {
465626947304SEvan Yan if ((PCICFG_LADDR(
4657a6469d9bSprasad pci_ap[i].pci_phys_low,
4658a6469d9bSprasad pci_ap[i].pci_phys_mid) +
465926947304SEvan Yan pci_ap[i].pci_size_low) >
466026947304SEvan Yan entry->pf_memory_base) {
466126947304SEvan Yan entry->pf_memory_base =
466226947304SEvan Yan PCICFG_LADDR(
466326947304SEvan Yan pci_ap[i].pci_phys_low,
466426947304SEvan Yan pci_ap[i].pci_phys_mid) +
466526947304SEvan Yan pci_ap[i].pci_size_low;
466626947304SEvan Yan }
466726947304SEvan Yan } else {
466826947304SEvan Yan if ((PCICFG_LADDR(
466970025d76Sjohnny pci_ap[i].pci_phys_low,
467070025d76Sjohnny pci_ap[i].pci_phys_mid) +
467126947304SEvan Yan pci_ap[i].pci_size_low) >
467226947304SEvan Yan entry->memory_base) {
467326947304SEvan Yan entry->memory_base =
467426947304SEvan Yan PCICFG_LADDR(
467526947304SEvan Yan pci_ap[i].pci_phys_low,
467626947304SEvan Yan pci_ap[i].pci_phys_mid) +
467726947304SEvan Yan pci_ap[i].pci_size_low;
467826947304SEvan Yan }
467970025d76Sjohnny }
468026947304SEvan Yan break;
468170025d76Sjohnny case PCI_REG_ADDR_G(PCI_ADDR_IO):
468270025d76Sjohnny if ((pci_ap[i].pci_phys_low +
468370025d76Sjohnny pci_ap[i].pci_size_low) >
468470025d76Sjohnny entry->io_base) {
468570025d76Sjohnny entry->io_base =
468670025d76Sjohnny pci_ap[i].pci_phys_low +
468770025d76Sjohnny pci_ap[i].pci_size_low;
468870025d76Sjohnny }
468926947304SEvan Yan break;
469070025d76Sjohnny }
469170025d76Sjohnny }
469270025d76Sjohnny
469370025d76Sjohnny /*
469470025d76Sjohnny * free the memory allocated by ddi_getlongprop
469570025d76Sjohnny */
469670025d76Sjohnny kmem_free(pci_ap, length);
469770025d76Sjohnny
469870025d76Sjohnny /*
469970025d76Sjohnny * continue the walk to the next sibling to sum memory
470070025d76Sjohnny */
470170025d76Sjohnny return (DDI_WALK_CONTINUE);
470270025d76Sjohnny }
470370025d76Sjohnny }
470470025d76Sjohnny
47057c478bd9Sstevel@tonic-gate /*
47067c478bd9Sstevel@tonic-gate * Make "parent" be the parent of the "child" dip
47077c478bd9Sstevel@tonic-gate */
47087c478bd9Sstevel@tonic-gate static void
pcicfg_reparent_node(dev_info_t * child,dev_info_t * parent)47097c478bd9Sstevel@tonic-gate pcicfg_reparent_node(dev_info_t *child, dev_info_t *parent)
47107c478bd9Sstevel@tonic-gate {
47117c478bd9Sstevel@tonic-gate dev_info_t *opdip;
47127c478bd9Sstevel@tonic-gate
47137c478bd9Sstevel@tonic-gate ASSERT(i_ddi_node_state(child) <= DS_LINKED);
47147c478bd9Sstevel@tonic-gate /*
47157c478bd9Sstevel@tonic-gate * Unlink node from tree before reparenting
47167c478bd9Sstevel@tonic-gate */
47177c478bd9Sstevel@tonic-gate opdip = ddi_get_parent(child);
47183fe80ca4SDan Cross ndi_devi_enter(opdip);
47197c478bd9Sstevel@tonic-gate (void) i_ndi_unconfig_node(child, DS_PROTO, 0);
47203fe80ca4SDan Cross ndi_devi_exit(opdip);
47217c478bd9Sstevel@tonic-gate
47227c478bd9Sstevel@tonic-gate DEVI(child)->devi_parent = DEVI(parent);
47237c478bd9Sstevel@tonic-gate DEVI(child)->devi_bus_ctl = DEVI(parent);
47247c478bd9Sstevel@tonic-gate (void) ndi_devi_bind_driver(child, 0);
47257c478bd9Sstevel@tonic-gate }
47267c478bd9Sstevel@tonic-gate
47277c478bd9Sstevel@tonic-gate /*
47287c478bd9Sstevel@tonic-gate * Return PCICFG_SUCCESS if device exists at the specified address.
47297c478bd9Sstevel@tonic-gate * Return PCICFG_NODEVICE is no device exists at the specified address.
47307c478bd9Sstevel@tonic-gate */
47317c478bd9Sstevel@tonic-gate int
pcicfg_config_setup(dev_info_t * dip,ddi_acc_handle_t * handle)47327c478bd9Sstevel@tonic-gate pcicfg_config_setup(dev_info_t *dip, ddi_acc_handle_t *handle)
47337c478bd9Sstevel@tonic-gate {
47347c478bd9Sstevel@tonic-gate caddr_t cfgaddr;
47357c478bd9Sstevel@tonic-gate ddi_device_acc_attr_t attr;
47367c478bd9Sstevel@tonic-gate dev_info_t *anode;
47377c478bd9Sstevel@tonic-gate int status;
47387c478bd9Sstevel@tonic-gate int rlen;
47397c478bd9Sstevel@tonic-gate pci_regspec_t *reg;
47407c478bd9Sstevel@tonic-gate int ret = DDI_SUCCESS;
47417c478bd9Sstevel@tonic-gate int16_t tmp;
47427c478bd9Sstevel@tonic-gate
47437c478bd9Sstevel@tonic-gate /*
47447c478bd9Sstevel@tonic-gate * Get the pci register spec from the node
47457c478bd9Sstevel@tonic-gate */
474626947304SEvan Yan status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg",
474726947304SEvan Yan (caddr_t)®, &rlen);
47487c478bd9Sstevel@tonic-gate
47497c478bd9Sstevel@tonic-gate switch (status) {
47507c478bd9Sstevel@tonic-gate case DDI_PROP_SUCCESS:
475126947304SEvan Yan break;
47527c478bd9Sstevel@tonic-gate case DDI_PROP_NO_MEMORY:
47537c478bd9Sstevel@tonic-gate DEBUG0("reg present, but unable to get memory\n");
47547c478bd9Sstevel@tonic-gate return (PCICFG_FAILURE);
47557c478bd9Sstevel@tonic-gate default:
47567c478bd9Sstevel@tonic-gate DEBUG0("no reg property\n");
47577c478bd9Sstevel@tonic-gate return (PCICFG_FAILURE);
47587c478bd9Sstevel@tonic-gate }
47597c478bd9Sstevel@tonic-gate
47607c478bd9Sstevel@tonic-gate anode = dip;
476123c35297Sanish DEBUG2("conf_map: dip=%p, anode=%p\n", dip, anode);
47627c478bd9Sstevel@tonic-gate
47637c478bd9Sstevel@tonic-gate attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
47647c478bd9Sstevel@tonic-gate attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
47657c478bd9Sstevel@tonic-gate attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
47667c478bd9Sstevel@tonic-gate
476726947304SEvan Yan if (ddi_regs_map_setup(anode, 0, &cfgaddr, 0, 0, &attr, handle)
476826947304SEvan Yan != DDI_SUCCESS) {
47697c478bd9Sstevel@tonic-gate DEBUG0("Failed to setup registers\n");
47707c478bd9Sstevel@tonic-gate kmem_free((caddr_t)reg, rlen);
47717c478bd9Sstevel@tonic-gate return (PCICFG_FAILURE);
47727c478bd9Sstevel@tonic-gate }
47737c478bd9Sstevel@tonic-gate
477423c35297Sanish /*
477523c35297Sanish * need to use DDI interfaces as the conf space is
477623c35297Sanish * cannot be directly accessed by the host.
477723c35297Sanish */
477823c35297Sanish tmp = (int16_t)ddi_get16(*handle, (uint16_t *)cfgaddr);
477923c35297Sanish if ((tmp == (int16_t)0xffff) || (tmp == -1)) {
478023c35297Sanish DEBUG1("NO DEVICEFOUND, read %x\n", tmp);
478123c35297Sanish ret = PCICFG_NODEVICE;
47827c478bd9Sstevel@tonic-gate } else {
478323c35297Sanish if (tmp == 0) {
478423c35297Sanish DEBUG0("Device Not Ready yet ?");
47857c478bd9Sstevel@tonic-gate ret = PCICFG_NODEVICE;
47867c478bd9Sstevel@tonic-gate } else {
478723c35297Sanish DEBUG1("DEVICEFOUND, read %x\n", tmp);
478823c35297Sanish ret = PCICFG_SUCCESS;
47897c478bd9Sstevel@tonic-gate }
47907c478bd9Sstevel@tonic-gate }
47917c478bd9Sstevel@tonic-gate
47927c478bd9Sstevel@tonic-gate if (ret == PCICFG_NODEVICE)
47937c478bd9Sstevel@tonic-gate ddi_regs_map_free(handle);
47947c478bd9Sstevel@tonic-gate kmem_free((caddr_t)reg, rlen);
47957c478bd9Sstevel@tonic-gate
47967c478bd9Sstevel@tonic-gate return (ret);
47977c478bd9Sstevel@tonic-gate
47987c478bd9Sstevel@tonic-gate }
47997c478bd9Sstevel@tonic-gate
48007c478bd9Sstevel@tonic-gate static void
pcicfg_config_teardown(ddi_acc_handle_t * handle)48017c478bd9Sstevel@tonic-gate pcicfg_config_teardown(ddi_acc_handle_t *handle)
48027c478bd9Sstevel@tonic-gate {
48037c478bd9Sstevel@tonic-gate (void) ddi_regs_map_free(handle);
48047c478bd9Sstevel@tonic-gate }
48057c478bd9Sstevel@tonic-gate
48067c478bd9Sstevel@tonic-gate static int
pcicfg_add_config_reg(dev_info_t * dip,uint_t bus,uint_t device,uint_t func)48077c478bd9Sstevel@tonic-gate pcicfg_add_config_reg(dev_info_t *dip,
4808ffb64830SJordan Paige Hendricks uint_t bus, uint_t device, uint_t func)
48097c478bd9Sstevel@tonic-gate {
48107c478bd9Sstevel@tonic-gate int reg[10] = { PCI_ADDR_CONFIG, 0, 0, 0, 0};
48117c478bd9Sstevel@tonic-gate
48127c478bd9Sstevel@tonic-gate reg[0] = PCICFG_MAKE_REG_HIGH(bus, device, func, 0);
48137c478bd9Sstevel@tonic-gate
481426947304SEvan Yan return (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "reg", reg, 5));
48157c478bd9Sstevel@tonic-gate }
48167c478bd9Sstevel@tonic-gate
481726947304SEvan Yan static int
pcicfg_ari_configure(dev_info_t * dip)481826947304SEvan Yan pcicfg_ari_configure(dev_info_t *dip)
481926947304SEvan Yan {
482026947304SEvan Yan if (pcie_ari_supported(dip) == PCIE_ARI_FORW_NOT_SUPPORTED)
482126947304SEvan Yan return (DDI_FAILURE);
482226947304SEvan Yan
482326947304SEvan Yan /*
482426947304SEvan Yan * Until we have resource balancing, dynamically configure
482526947304SEvan Yan * ARI functions without firmware assistamce.
482626947304SEvan Yan */
482726947304SEvan Yan return (DDI_FAILURE);
482826947304SEvan Yan }
482926947304SEvan Yan
483026947304SEvan Yan
48317c478bd9Sstevel@tonic-gate #ifdef DEBUG
48327c478bd9Sstevel@tonic-gate static void
debug(char * fmt,uintptr_t a1,uintptr_t a2,uintptr_t a3,uintptr_t a4,uintptr_t a5)4833ffb64830SJordan Paige Hendricks debug(char *fmt, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4,
4834ffb64830SJordan Paige Hendricks uintptr_t a5)
48357c478bd9Sstevel@tonic-gate {
48367c478bd9Sstevel@tonic-gate if (pcicfg_debug > 1) {
48377c478bd9Sstevel@tonic-gate prom_printf("pcicfg: ");
48387c478bd9Sstevel@tonic-gate prom_printf(fmt, a1, a2, a3, a4, a5);
48397c478bd9Sstevel@tonic-gate }
48407c478bd9Sstevel@tonic-gate }
48417c478bd9Sstevel@tonic-gate #endif
48427c478bd9Sstevel@tonic-gate
484370025d76Sjohnny /*ARGSUSED*/
484470025d76Sjohnny static uint8_t
pcicfg_get_nslots(dev_info_t * dip,ddi_acc_handle_t handle)484570025d76Sjohnny pcicfg_get_nslots(dev_info_t *dip, ddi_acc_handle_t handle)
484670025d76Sjohnny {
484749fbdd30SErwin T Tsaur uint16_t cap_id_loc, slot_id_loc;
484870025d76Sjohnny uint8_t num_slots = 0;
484970025d76Sjohnny
485070025d76Sjohnny /* just depend on the pcie_cap for now. */
485149fbdd30SErwin T Tsaur (void) PCI_CAP_LOCATE(handle, PCI_CAP_ID_PCI_E, &cap_id_loc);
485249fbdd30SErwin T Tsaur (void) PCI_CAP_LOCATE(handle, PCI_CAP_ID_SLOT_ID, &slot_id_loc);
485349fbdd30SErwin T Tsaur if (cap_id_loc != PCI_CAP_NEXT_PTR_NULL) {
485426947304SEvan Yan if (pci_config_get8(handle, cap_id_loc + PCI_CAP_ID_REGS_OFF) &
485526947304SEvan Yan PCIE_PCIECAP_SLOT_IMPL)
485670025d76Sjohnny num_slots = 1;
485770025d76Sjohnny } else /* not a PCIe switch/bridge. Must be a PCI-PCI[-X] bridge */
485849fbdd30SErwin T Tsaur if (slot_id_loc != PCI_CAP_NEXT_PTR_NULL) {
485949fbdd30SErwin T Tsaur uint8_t esr_reg = pci_config_get8(handle, slot_id_loc + 2);
486070025d76Sjohnny num_slots = PCI_CAPSLOT_NSLOTS(esr_reg);
486170025d76Sjohnny }
486270025d76Sjohnny /* XXX - need to cover PCI-PCIe bridge with n slots */
486370025d76Sjohnny return (num_slots);
486470025d76Sjohnny }
486570025d76Sjohnny
486670025d76Sjohnny static int
pcicfg_pcie_device_type(dev_info_t * dip,ddi_acc_handle_t handle)486770025d76Sjohnny pcicfg_pcie_device_type(dev_info_t *dip, ddi_acc_handle_t handle)
486870025d76Sjohnny {
486970025d76Sjohnny int port_type = pcicfg_pcie_port_type(dip, handle);
487070025d76Sjohnny
487170025d76Sjohnny DEBUG1("device port_type = %x\n", port_type);
487270025d76Sjohnny /* No PCIe CAP regs, we are not PCIe device_type */
487370025d76Sjohnny if (port_type < 0)
487470025d76Sjohnny return (DDI_FAILURE);
487570025d76Sjohnny
487670025d76Sjohnny /* check for all PCIe device_types */
487770025d76Sjohnny if ((port_type == PCIE_PCIECAP_DEV_TYPE_UP) ||
487826947304SEvan Yan (port_type == PCIE_PCIECAP_DEV_TYPE_DOWN) ||
487926947304SEvan Yan (port_type == PCIE_PCIECAP_DEV_TYPE_ROOT) ||
488026947304SEvan Yan (port_type == PCIE_PCIECAP_DEV_TYPE_PCI2PCIE))
488170025d76Sjohnny return (DDI_SUCCESS);
488270025d76Sjohnny
488370025d76Sjohnny return (DDI_FAILURE);
488470025d76Sjohnny
488570025d76Sjohnny }
488670025d76Sjohnny
488770025d76Sjohnny /*ARGSUSED*/
488870025d76Sjohnny static int
pcicfg_pcie_port_type(dev_info_t * dip,ddi_acc_handle_t handle)488970025d76Sjohnny pcicfg_pcie_port_type(dev_info_t *dip, ddi_acc_handle_t handle)
489070025d76Sjohnny {
489170025d76Sjohnny int port_type = -1;
489249fbdd30SErwin T Tsaur uint16_t cap_loc;
489370025d76Sjohnny
489470025d76Sjohnny /* Note: need to look at the port type information here */
489549fbdd30SErwin T Tsaur (void) PCI_CAP_LOCATE(handle, PCI_CAP_ID_PCI_E, &cap_loc);
489649fbdd30SErwin T Tsaur if (cap_loc != PCI_CAP_NEXT_PTR_NULL)
489770025d76Sjohnny port_type = pci_config_get16(handle,
489826947304SEvan Yan cap_loc + PCIE_PCIECAP) & PCIE_PCIECAP_DEV_TYPE_MASK;
489970025d76Sjohnny
490070025d76Sjohnny return (port_type);
490170025d76Sjohnny }
4902c0da6274SZhi-Jun Robin Fu
4903c0da6274SZhi-Jun Robin Fu /*
4904c0da6274SZhi-Jun Robin Fu * Return true if the devinfo node is in a PCI Express hierarchy.
4905c0da6274SZhi-Jun Robin Fu */
4906c0da6274SZhi-Jun Robin Fu static boolean_t
is_pcie_fabric(dev_info_t * dip)4907c0da6274SZhi-Jun Robin Fu is_pcie_fabric(dev_info_t *dip)
4908c0da6274SZhi-Jun Robin Fu {
4909c0da6274SZhi-Jun Robin Fu dev_info_t *root = ddi_root_node();
4910c0da6274SZhi-Jun Robin Fu dev_info_t *pdip;
4911c0da6274SZhi-Jun Robin Fu boolean_t found = B_FALSE;
4912c0da6274SZhi-Jun Robin Fu char *bus;
4913c0da6274SZhi-Jun Robin Fu
4914c0da6274SZhi-Jun Robin Fu /*
4915c0da6274SZhi-Jun Robin Fu * Does this device reside in a pcie fabric ?
4916c0da6274SZhi-Jun Robin Fu */
4917c0da6274SZhi-Jun Robin Fu for (pdip = dip; pdip && (pdip != root) && !found;
4918c0da6274SZhi-Jun Robin Fu pdip = ddi_get_parent(pdip)) {
4919c0da6274SZhi-Jun Robin Fu if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip,
4920c0da6274SZhi-Jun Robin Fu DDI_PROP_DONTPASS, "device_type", &bus) !=
4921c0da6274SZhi-Jun Robin Fu DDI_PROP_SUCCESS)
4922c0da6274SZhi-Jun Robin Fu break;
4923c0da6274SZhi-Jun Robin Fu
4924c0da6274SZhi-Jun Robin Fu if (strcmp(bus, "pciex") == 0)
4925c0da6274SZhi-Jun Robin Fu found = B_TRUE;
4926c0da6274SZhi-Jun Robin Fu
4927c0da6274SZhi-Jun Robin Fu ddi_prop_free(bus);
4928c0da6274SZhi-Jun Robin Fu }
4929c0da6274SZhi-Jun Robin Fu
4930c0da6274SZhi-Jun Robin Fu return (found);
4931c0da6274SZhi-Jun Robin Fu }
4932