123c35297Sanish /*
223c35297Sanish * CDDL HEADER START
323c35297Sanish *
423c35297Sanish * The contents of this file are subject to the terms of the
523c35297Sanish * Common Development and Distribution License (the "License").
623c35297Sanish * You may not use this file except in compliance with the License.
723c35297Sanish *
823c35297Sanish * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
923c35297Sanish * or http://www.opensolaris.org/os/licensing.
1023c35297Sanish * See the License for the specific language governing permissions
1123c35297Sanish * and limitations under the License.
1223c35297Sanish *
1323c35297Sanish * When distributing Covered Code, include this CDDL HEADER in each
1423c35297Sanish * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1523c35297Sanish * If applicable, add the following below this CDDL HEADER, with the
1623c35297Sanish * fields enclosed by brackets "[]" replaced with your own identifying
1723c35297Sanish * information: Portions Copyright [yyyy] [name of copyright owner]
1823c35297Sanish *
1923c35297Sanish * CDDL HEADER END
2023c35297Sanish */
2123c35297Sanish /*
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
2523c35297Sanish */
2623c35297Sanish
2723c35297Sanish /*
2823c35297Sanish * PCI configurator (pcicfg)
2923c35297Sanish */
3023c35297Sanish
3123c35297Sanish #include <sys/sysmacros.h>
3223c35297Sanish #include <sys/conf.h>
3323c35297Sanish #include <sys/kmem.h>
3423c35297Sanish #include <sys/debug.h>
3523c35297Sanish #include <sys/modctl.h>
3623c35297Sanish #include <sys/autoconf.h>
3723c35297Sanish #include <sys/hwconf.h>
3823c35297Sanish #include <sys/pcie.h>
3926947304SEvan Yan #include <sys/pcie_impl.h>
4049fbdd30SErwin T Tsaur #include <sys/pci_cap.h>
4123c35297Sanish #include <sys/ddi.h>
4223c35297Sanish #include <sys/sunndi.h>
4323c35297Sanish #include <sys/hotplug/pci/pcicfg.h>
4423c35297Sanish #include <sys/ndi_impldefs.h>
45c0da6274SZhi-Jun Robin Fu #include <sys/pci_cfgacc.h>
46*bd97c7ceSRobert Mustacchi #include <sys/pci_props.h>
4723c35297Sanish
4823c35297Sanish /*
4923c35297Sanish * ************************************************************************
5023c35297Sanish * *** Implementation specific local data structures/definitions. ***
5123c35297Sanish * ************************************************************************
5223c35297Sanish */
5323c35297Sanish
5423c35297Sanish static int pcicfg_start_devno = 0; /* for Debug only */
5523c35297Sanish
5626947304SEvan Yan #define PCICFG_MAX_ARI_FUNCTION 256
5726947304SEvan Yan
5823c35297Sanish #define PCICFG_NODEVICE 42
5923c35297Sanish #define PCICFG_NOMEMORY 43
6023c35297Sanish #define PCICFG_NOMULTI 44
615af4ae46Sjveta #define PCICFG_NORESRC 45
6223c35297Sanish
6323c35297Sanish #define PCICFG_HIADDR(n) ((uint32_t)(((uint64_t)(n) & \
6423c35297Sanish 0xFFFFFFFF00000000ULL)>> 32))
6523c35297Sanish #define PCICFG_LOADDR(n) ((uint32_t)((uint64_t)(n) & 0x00000000FFFFFFFF))
6623c35297Sanish #define PCICFG_LADDR(lo, hi) (((uint64_t)(hi) << 32) | (uint32_t)(lo))
6723c35297Sanish
6823c35297Sanish #define PCICFG_HIWORD(n) ((uint16_t)(((uint32_t)(n) & 0xFFFF0000)>> 16))
6923c35297Sanish #define PCICFG_LOWORD(n) ((uint16_t)((uint32_t)(n) & 0x0000FFFF))
7023c35297Sanish #define PCICFG_HIBYTE(n) ((uint8_t)(((uint16_t)(n) & 0xFF00)>> 8))
7123c35297Sanish #define PCICFG_LOBYTE(n) ((uint8_t)((uint16_t)(n) & 0x00FF))
7223c35297Sanish
7323c35297Sanish #define PCICFG_ROUND_UP(addr, gran) ((uintptr_t)((gran+addr-1)&(~(gran-1))))
7423c35297Sanish #define PCICFG_ROUND_DOWN(addr, gran) ((uintptr_t)((addr) & ~(gran-1)))
7523c35297Sanish
7623c35297Sanish #define PCICFG_MEMGRAN 0x100000
7723c35297Sanish #define PCICFG_IOGRAN 0x1000
7823c35297Sanish #define PCICFG_4GIG_LIMIT 0xFFFFFFFFUL
7923c35297Sanish
8023c35297Sanish #define PCICFG_MEM_MULT 4
8123c35297Sanish #define PCICFG_IO_MULT 4
8223c35297Sanish #define PCICFG_RANGE_LEN 3 /* Number of range entries */
8323c35297Sanish
8423c35297Sanish static int pcicfg_slot_busnums = 8;
8523c35297Sanish static int pcicfg_slot_memsize = 32 * PCICFG_MEMGRAN; /* 32MB per slot */
8623c35297Sanish static int pcicfg_slot_pf_memsize = 32 * PCICFG_MEMGRAN; /* 32MB per slot */
8723c35297Sanish static int pcicfg_slot_iosize = 64 * PCICFG_IOGRAN; /* 64K per slot */
8823c35297Sanish static int pcicfg_sec_reset_delay = 3000000;
8923c35297Sanish
9023c35297Sanish typedef struct hole hole_t;
9123c35297Sanish
9223c35297Sanish struct hole {
9323c35297Sanish uint64_t start;
9423c35297Sanish uint64_t len;
9523c35297Sanish hole_t *next;
9623c35297Sanish };
9723c35297Sanish
9823c35297Sanish typedef struct pcicfg_phdl pcicfg_phdl_t;
9923c35297Sanish
10023c35297Sanish struct pcicfg_phdl {
10123c35297Sanish
10223c35297Sanish dev_info_t *dip; /* Associated with the bridge */
10323c35297Sanish dev_info_t *top_dip; /* top node of the attach point */
10423c35297Sanish pcicfg_phdl_t *next;
10523c35297Sanish
10623c35297Sanish /* non-prefetchable memory space */
10723c35297Sanish uint64_t memory_base; /* Memory base for this attach point */
10823c35297Sanish uint64_t memory_last;
10923c35297Sanish uint64_t memory_len;
11023c35297Sanish
11123c35297Sanish /* prefetchable memory space */
11226947304SEvan Yan uint64_t pf_memory_base; /* PF Memory base for this Connection */
11323c35297Sanish uint64_t pf_memory_last;
11423c35297Sanish uint64_t pf_memory_len;
11523c35297Sanish
11623c35297Sanish /* io space */
11723c35297Sanish uint32_t io_base; /* I/O base for this attach point */
11823c35297Sanish uint32_t io_last;
11923c35297Sanish uint32_t io_len;
12023c35297Sanish
12123c35297Sanish int error;
12223c35297Sanish uint_t highest_bus; /* Highest bus seen on the probe */
12323c35297Sanish
12423c35297Sanish hole_t mem_hole; /* Memory hole linked list. */
12523c35297Sanish hole_t pf_mem_hole; /* PF Memory hole linked list. */
12623c35297Sanish hole_t io_hole; /* IO hole linked list */
12723c35297Sanish
12823c35297Sanish ndi_ra_request_t mem_req; /* allocator request for memory */
12923c35297Sanish ndi_ra_request_t pf_mem_req; /* allocator request for PF memory */
13023c35297Sanish ndi_ra_request_t io_req; /* allocator request for I/O */
13123c35297Sanish };
13223c35297Sanish
13323c35297Sanish struct pcicfg_standard_prop_entry {
13423c35297Sanish uchar_t *name;
13523c35297Sanish uint_t config_offset;
13623c35297Sanish uint_t size;
13723c35297Sanish };
13823c35297Sanish
13923c35297Sanish
14023c35297Sanish struct pcicfg_name_entry {
14123c35297Sanish uint32_t class_code;
14223c35297Sanish char *name;
14323c35297Sanish };
14423c35297Sanish
14523c35297Sanish struct pcicfg_find_ctrl {
14623c35297Sanish uint_t device;
14723c35297Sanish uint_t function;
14823c35297Sanish dev_info_t *dip;
14923c35297Sanish };
15023c35297Sanish
15123c35297Sanish /*
15223c35297Sanish * List of Indirect Config Map Devices. At least the intent of the
15323c35297Sanish * design is to look for a device in this list during the configure
15423c35297Sanish * operation, and if the device is listed here, then it is a nontransparent
15523c35297Sanish * bridge, hence load the driver and avail the config map services from
15623c35297Sanish * the driver. Class and Subclass should be as defined in the PCI specs
15723c35297Sanish * ie. class is 0x6, and subclass is 0x9.
15823c35297Sanish */
15923c35297Sanish static struct {
16023c35297Sanish uint8_t mem_range_bar_offset;
16123c35297Sanish uint8_t io_range_bar_offset;
16223c35297Sanish uint8_t prefetch_mem_range_bar_offset;
16323c35297Sanish } pcicfg_indirect_map_devs[] = {
16423c35297Sanish PCI_CONF_BASE3, PCI_CONF_BASE2, PCI_CONF_BASE3,
16523c35297Sanish 0, 0, 0,
16623c35297Sanish };
16723c35297Sanish
16823c35297Sanish #define PCICFG_MAKE_REG_HIGH(busnum, devnum, funcnum, register)\
16923c35297Sanish (\
17023c35297Sanish ((ulong_t)(busnum & 0xff) << 16) |\
17123c35297Sanish ((ulong_t)(devnum & 0x1f) << 11) |\
17223c35297Sanish ((ulong_t)(funcnum & 0x7) << 8) |\
17323c35297Sanish ((ulong_t)(register & 0x3f)))
17423c35297Sanish
17523c35297Sanish /*
17623c35297Sanish * debug macros:
17723c35297Sanish */
17823c35297Sanish #if defined(DEBUG)
17923c35297Sanish extern void prom_printf(const char *, ...);
18023c35297Sanish
18123c35297Sanish /*
18223c35297Sanish * Following values are defined for this debug flag.
18323c35297Sanish *
18423c35297Sanish * 1 = dump configuration header only.
18523c35297Sanish * 2 = dump generic debug data only (no config header dumped)
18623c35297Sanish * 3 = dump everything (both 1 and 2)
18723c35297Sanish */
18823c35297Sanish int pcicfg_debug = 0;
18923c35297Sanish
19023c35297Sanish static void debug(char *, uintptr_t, uintptr_t,
19123c35297Sanish uintptr_t, uintptr_t, uintptr_t);
19223c35297Sanish
19323c35297Sanish #define DEBUG0(fmt)\
19423c35297Sanish debug(fmt, 0, 0, 0, 0, 0);
19523c35297Sanish #define DEBUG1(fmt, a1)\
19623c35297Sanish debug(fmt, (uintptr_t)(a1), 0, 0, 0, 0);
19723c35297Sanish #define DEBUG2(fmt, a1, a2)\
19823c35297Sanish debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2), 0, 0, 0);
19923c35297Sanish #define DEBUG3(fmt, a1, a2, a3)\
20023c35297Sanish debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2),\
20123c35297Sanish (uintptr_t)(a3), 0, 0);
20223c35297Sanish #define DEBUG4(fmt, a1, a2, a3, a4)\
20323c35297Sanish debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2),\
20423c35297Sanish (uintptr_t)(a3), (uintptr_t)(a4), 0);
20523c35297Sanish #define DEBUG5(fmt, a1, a2, a3, a4, a5)\
20623c35297Sanish debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2),\
20723c35297Sanish (uintptr_t)(a3), (uintptr_t)(a4), (uintptr_t)(a5));
20823c35297Sanish #else
20923c35297Sanish #define DEBUG0(fmt)
21023c35297Sanish #define DEBUG1(fmt, a1)
21123c35297Sanish #define DEBUG2(fmt, a1, a2)
21223c35297Sanish #define DEBUG3(fmt, a1, a2, a3)
21323c35297Sanish #define DEBUG4(fmt, a1, a2, a3, a4)
21423c35297Sanish #define DEBUG5(fmt, a1, a2, a3, a4, a5)
21523c35297Sanish #endif
21623c35297Sanish
21723c35297Sanish /*
21823c35297Sanish * forward declarations for routines defined in this module (called here)
21923c35297Sanish */
22023c35297Sanish
22123c35297Sanish static int pcicfg_add_config_reg(dev_info_t *,
22223c35297Sanish uint_t, uint_t, uint_t);
22323c35297Sanish 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);
22523c35297Sanish static int pcicfg_match_dev(dev_info_t *, void *);
22623c35297Sanish static dev_info_t *pcicfg_devi_find(dev_info_t *, uint_t, uint_t);
22723c35297Sanish static pcicfg_phdl_t *pcicfg_find_phdl(dev_info_t *);
22823c35297Sanish static pcicfg_phdl_t *pcicfg_create_phdl(dev_info_t *);
22923c35297Sanish static int pcicfg_destroy_phdl(dev_info_t *);
23023c35297Sanish static int pcicfg_sum_resources(dev_info_t *, void *);
23123c35297Sanish static int pcicfg_device_assign(dev_info_t *);
23223c35297Sanish 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);
23523c35297Sanish static void pcicfg_setup_bridge(pcicfg_phdl_t *, ddi_acc_handle_t);
23623c35297Sanish static void pcicfg_update_bridge(pcicfg_phdl_t *, ddi_acc_handle_t);
23723c35297Sanish static int pcicfg_update_assigned_prop(dev_info_t *, pci_regspec_t *);
23823c35297Sanish static void pcicfg_device_on(ddi_acc_handle_t);
23923c35297Sanish static void pcicfg_device_off(ddi_acc_handle_t);
24023c35297Sanish static int pcicfg_set_busnode_props(dev_info_t *, uint8_t);
24123c35297Sanish static int pcicfg_free_bridge_resources(dev_info_t *);
24223c35297Sanish 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);
24423c35297Sanish static void pcicfg_reparent_node(dev_info_t *, dev_info_t *);
24523c35297Sanish static int pcicfg_config_setup(dev_info_t *, ddi_acc_handle_t *);
24623c35297Sanish static void pcicfg_config_teardown(ddi_acc_handle_t *);
24723c35297Sanish static void pcicfg_get_mem(pcicfg_phdl_t *, uint32_t, uint64_t *);
24823c35297Sanish static void pcicfg_get_pf_mem(pcicfg_phdl_t *, uint32_t, uint64_t *);
24923c35297Sanish static void pcicfg_get_io(pcicfg_phdl_t *, uint32_t, uint32_t *);
25023c35297Sanish static int pcicfg_update_ranges_prop(dev_info_t *, ppb_ranges_t *);
25123c35297Sanish static int pcicfg_configure_ntbridge(dev_info_t *, uint_t, uint_t);
25223c35297Sanish static uint_t pcicfg_ntbridge_child(dev_info_t *);
25323c35297Sanish static uint_t pcicfg_get_ntbridge_child_range(dev_info_t *, uint64_t *,
25423c35297Sanish uint64_t *, uint_t);
25523c35297Sanish static int pcicfg_is_ntbridge(dev_info_t *);
25623c35297Sanish static int pcicfg_ntbridge_allocate_resources(dev_info_t *);
25723c35297Sanish static int pcicfg_ntbridge_configure_done(dev_info_t *);
25823c35297Sanish static int pcicfg_ntbridge_program_child(dev_info_t *);
25923c35297Sanish static uint_t pcicfg_ntbridge_unconfigure(dev_info_t *);
26023c35297Sanish static int pcicfg_ntbridge_unconfigure_child(dev_info_t *, uint_t);
26123c35297Sanish static void pcicfg_free_hole(hole_t *);
26223c35297Sanish static uint64_t pcicfg_alloc_hole(hole_t *, uint64_t *, uint32_t);
26323c35297Sanish static int pcicfg_device_type(dev_info_t *, ddi_acc_handle_t *);
26423c35297Sanish static void pcicfg_update_phdl(dev_info_t *, uint8_t, uint8_t);
26523c35297Sanish static int pcicfg_get_cap(ddi_acc_handle_t, uint8_t);
26623c35297Sanish static uint8_t pcicfg_get_nslots(dev_info_t *, ddi_acc_handle_t);
26723c35297Sanish static int pcicfg_pcie_device_type(dev_info_t *, ddi_acc_handle_t);
26823c35297Sanish static int pcicfg_pcie_port_type(dev_info_t *, ddi_acc_handle_t);
26923c35297Sanish static int pcicfg_probe_bridge(dev_info_t *, ddi_acc_handle_t, uint_t,
270c0da6274SZhi-Jun Robin Fu uint_t *, boolean_t);
27123c35297Sanish static int pcicfg_find_resource_end(dev_info_t *, void *);
272c0da6274SZhi-Jun Robin Fu static boolean_t is_pcie_fabric(dev_info_t *);
27323c35297Sanish
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
28023c35297Sanish #ifdef DEBUG
28123c35297Sanish static void pcicfg_dump_common_config(ddi_acc_handle_t config_handle);
28223c35297Sanish static void pcicfg_dump_device_config(ddi_acc_handle_t);
28323c35297Sanish static void pcicfg_dump_bridge_config(ddi_acc_handle_t config_handle);
28423c35297Sanish static uint64_t pcicfg_unused_space(hole_t *, uint32_t *);
28523c35297Sanish
28623c35297Sanish #define PCICFG_DUMP_COMMON_CONFIG(hdl) (void)pcicfg_dump_common_config(hdl)
28723c35297Sanish #define PCICFG_DUMP_DEVICE_CONFIG(hdl) (void)pcicfg_dump_device_config(hdl)
28823c35297Sanish #define PCICFG_DUMP_BRIDGE_CONFIG(hdl) (void)pcicfg_dump_bridge_config(hdl)
28923c35297Sanish #else
29023c35297Sanish #define PCICFG_DUMP_COMMON_CONFIG(handle)
29123c35297Sanish #define PCICFG_DUMP_DEVICE_CONFIG(handle)
29223c35297Sanish #define PCICFG_DUMP_BRIDGE_CONFIG(handle)
29323c35297Sanish #endif
29423c35297Sanish
29523c35297Sanish static kmutex_t pcicfg_list_mutex; /* Protects the probe handle list */
29623c35297Sanish static pcicfg_phdl_t *pcicfg_phdl_list = NULL;
29723c35297Sanish
29823c35297Sanish #ifndef _DONT_USE_1275_GENERIC_NAMES
29923c35297Sanish /*
30023c35297Sanish * Class code table
30123c35297Sanish */
30223c35297Sanish static struct pcicfg_name_entry pcicfg_class_lookup [] = {
30323c35297Sanish
30423c35297Sanish { 0x001, "display" },
30523c35297Sanish { 0x100, "scsi" },
30623c35297Sanish { 0x101, "ide" },
30723c35297Sanish { 0x102, "fdc" },
30823c35297Sanish { 0x103, "ipi" },
30923c35297Sanish { 0x104, "raid" },
31023c35297Sanish { 0x105, "ata" },
31123c35297Sanish { 0x106, "sata" },
31223c35297Sanish { 0x200, "ethernet" },
31323c35297Sanish { 0x201, "token-ring" },
31423c35297Sanish { 0x202, "fddi" },
31523c35297Sanish { 0x203, "atm" },
31623c35297Sanish { 0x204, "isdn" },
31723c35297Sanish { 0x206, "mcd" },
31823c35297Sanish { 0x300, "display" },
31923c35297Sanish { 0x400, "video" },
32023c35297Sanish { 0x401, "sound" },
32123c35297Sanish { 0x500, "memory" },
32223c35297Sanish { 0x501, "flash" },
32323c35297Sanish { 0x600, "host" },
32423c35297Sanish { 0x601, "isa" },
32523c35297Sanish { 0x602, "eisa" },
32623c35297Sanish { 0x603, "mca" },
32723c35297Sanish { 0x604, "pci" },
32823c35297Sanish { 0x605, "pcmcia" },
32923c35297Sanish { 0x606, "nubus" },
33023c35297Sanish { 0x607, "cardbus" },
33123c35297Sanish { 0x609, "pci" },
33223c35297Sanish { 0x60a, "ib-pci" },
33323c35297Sanish { 0x700, "serial" },
33423c35297Sanish { 0x701, "parallel" },
33523c35297Sanish { 0x800, "interrupt-controller" },
33623c35297Sanish { 0x801, "dma-controller" },
33723c35297Sanish { 0x802, "timer" },
33823c35297Sanish { 0x803, "rtc" },
33923c35297Sanish { 0x900, "keyboard" },
34023c35297Sanish { 0x901, "pen" },
34123c35297Sanish { 0x902, "mouse" },
34223c35297Sanish { 0xa00, "dock" },
34323c35297Sanish { 0xb00, "cpu" },
34423c35297Sanish { 0xb01, "cpu" },
34523c35297Sanish { 0xb02, "cpu" },
34623c35297Sanish { 0xb10, "cpu" },
34723c35297Sanish { 0xb20, "cpu" },
34823c35297Sanish { 0xb30, "cpu" },
34923c35297Sanish { 0xb40, "coproc" },
35023c35297Sanish { 0xc00, "firewire" },
35123c35297Sanish { 0xc01, "access-bus" },
35223c35297Sanish { 0xc02, "ssa" },
35323c35297Sanish { 0xc03, "usb" },
35423c35297Sanish { 0xc04, "fibre-channel" },
35523c35297Sanish { 0xc05, "smbus" },
35623c35297Sanish { 0xc06, "ib" },
35723c35297Sanish { 0xd00, "irda" },
35823c35297Sanish { 0xd01, "ir" },
35923c35297Sanish { 0xd10, "rf" },
36023c35297Sanish { 0xd11, "btooth" },
36123c35297Sanish { 0xd12, "brdband" },
36223c35297Sanish { 0xd20, "802.11a" },
36323c35297Sanish { 0xd21, "802.11b" },
36423c35297Sanish { 0xe00, "i2o" },
36523c35297Sanish { 0xf01, "tv" },
36623c35297Sanish { 0xf02, "audio" },
36723c35297Sanish { 0xf03, "voice" },
36823c35297Sanish { 0xf04, "data" },
36923c35297Sanish { 0, 0 }
37023c35297Sanish };
37123c35297Sanish #endif /* _DONT_USE_1275_GENERIC_NAMES */
37223c35297Sanish
37323c35297Sanish /*
37423c35297Sanish * Module control operations
37523c35297Sanish */
37623c35297Sanish
37723c35297Sanish extern struct mod_ops mod_miscops;
37823c35297Sanish
37923c35297Sanish static struct modlmisc modlmisc = {
38023c35297Sanish &mod_miscops, /* Type of module */
381613b2871SRichard Bean "PCI configurator"
38223c35297Sanish };
38323c35297Sanish
38423c35297Sanish static struct modlinkage modlinkage = {
38523c35297Sanish MODREV_1, (void *)&modlmisc, NULL
38623c35297Sanish };
38723c35297Sanish
38823c35297Sanish
38923c35297Sanish #ifdef DEBUG
39023c35297Sanish
39123c35297Sanish static void
pcicfg_dump_common_config(ddi_acc_handle_t config_handle)39223c35297Sanish pcicfg_dump_common_config(ddi_acc_handle_t config_handle)
39323c35297Sanish {
39423c35297Sanish if ((pcicfg_debug & 1) == 0)
39523c35297Sanish return;
39623c35297Sanish prom_printf(" Vendor ID = [0x%x]\n",
39723c35297Sanish pci_config_get16(config_handle, PCI_CONF_VENID));
39823c35297Sanish prom_printf(" Device ID = [0x%x]\n",
39923c35297Sanish pci_config_get16(config_handle, PCI_CONF_DEVID));
40023c35297Sanish prom_printf(" Command REG = [0x%x]\n",
40123c35297Sanish pci_config_get16(config_handle, PCI_CONF_COMM));
40223c35297Sanish prom_printf(" Status REG = [0x%x]\n",
40323c35297Sanish pci_config_get16(config_handle, PCI_CONF_STAT));
40423c35297Sanish prom_printf(" Revision ID = [0x%x]\n",
40523c35297Sanish pci_config_get8(config_handle, PCI_CONF_REVID));
40623c35297Sanish prom_printf(" Prog Class = [0x%x]\n",
40723c35297Sanish pci_config_get8(config_handle, PCI_CONF_PROGCLASS));
40823c35297Sanish prom_printf(" Dev Class = [0x%x]\n",
40923c35297Sanish pci_config_get8(config_handle, PCI_CONF_SUBCLASS));
41023c35297Sanish prom_printf(" Base Class = [0x%x]\n",
41123c35297Sanish pci_config_get8(config_handle, PCI_CONF_BASCLASS));
41223c35297Sanish prom_printf(" Device ID = [0x%x]\n",
41323c35297Sanish pci_config_get8(config_handle, PCI_CONF_CACHE_LINESZ));
41423c35297Sanish prom_printf(" Header Type = [0x%x]\n",
41523c35297Sanish pci_config_get8(config_handle, PCI_CONF_HEADER));
41623c35297Sanish prom_printf(" BIST = [0x%x]\n",
41723c35297Sanish pci_config_get8(config_handle, PCI_CONF_BIST));
41823c35297Sanish prom_printf(" BASE 0 = [0x%x]\n",
41923c35297Sanish pci_config_get32(config_handle, PCI_CONF_BASE0));
42023c35297Sanish prom_printf(" BASE 1 = [0x%x]\n",
42123c35297Sanish pci_config_get32(config_handle, PCI_CONF_BASE1));
42223c35297Sanish
42323c35297Sanish }
42423c35297Sanish
42523c35297Sanish static void
pcicfg_dump_device_config(ddi_acc_handle_t config_handle)42623c35297Sanish pcicfg_dump_device_config(ddi_acc_handle_t config_handle)
42723c35297Sanish {
42823c35297Sanish if ((pcicfg_debug & 1) == 0)
42923c35297Sanish return;
43023c35297Sanish pcicfg_dump_common_config(config_handle);
43123c35297Sanish
43223c35297Sanish prom_printf(" BASE 2 = [0x%x]\n",
43323c35297Sanish pci_config_get32(config_handle, PCI_CONF_BASE2));
43423c35297Sanish prom_printf(" BASE 3 = [0x%x]\n",
43523c35297Sanish pci_config_get32(config_handle, PCI_CONF_BASE3));
43623c35297Sanish prom_printf(" BASE 4 = [0x%x]\n",
43723c35297Sanish pci_config_get32(config_handle, PCI_CONF_BASE4));
43823c35297Sanish prom_printf(" BASE 5 = [0x%x]\n",
43923c35297Sanish pci_config_get32(config_handle, PCI_CONF_BASE5));
44023c35297Sanish prom_printf(" Cardbus CIS = [0x%x]\n",
44123c35297Sanish pci_config_get32(config_handle, PCI_CONF_CIS));
44223c35297Sanish prom_printf(" Sub VID = [0x%x]\n",
44323c35297Sanish pci_config_get16(config_handle, PCI_CONF_SUBVENID));
44423c35297Sanish prom_printf(" Sub SID = [0x%x]\n",
44523c35297Sanish pci_config_get16(config_handle, PCI_CONF_SUBSYSID));
44623c35297Sanish prom_printf(" ROM = [0x%x]\n",
44723c35297Sanish pci_config_get32(config_handle, PCI_CONF_ROM));
44823c35297Sanish prom_printf(" I Line = [0x%x]\n",
44923c35297Sanish pci_config_get8(config_handle, PCI_CONF_ILINE));
45023c35297Sanish prom_printf(" I Pin = [0x%x]\n",
45123c35297Sanish pci_config_get8(config_handle, PCI_CONF_IPIN));
45223c35297Sanish prom_printf(" Max Grant = [0x%x]\n",
45323c35297Sanish pci_config_get8(config_handle, PCI_CONF_MIN_G));
45423c35297Sanish prom_printf(" Max Latent = [0x%x]\n",
45523c35297Sanish pci_config_get8(config_handle, PCI_CONF_MAX_L));
45623c35297Sanish }
45723c35297Sanish
45823c35297Sanish static void
pcicfg_dump_bridge_config(ddi_acc_handle_t config_handle)45923c35297Sanish pcicfg_dump_bridge_config(ddi_acc_handle_t config_handle)
46023c35297Sanish {
46123c35297Sanish if ((pcicfg_debug & 1) == 0)
46223c35297Sanish return;
46323c35297Sanish pcicfg_dump_common_config(config_handle);
46423c35297Sanish
46523c35297Sanish prom_printf("........................................\n");
46623c35297Sanish
46723c35297Sanish prom_printf(" Pri Bus = [0x%x]\n",
46823c35297Sanish pci_config_get8(config_handle, PCI_BCNF_PRIBUS));
46923c35297Sanish prom_printf(" Sec Bus = [0x%x]\n",
47023c35297Sanish pci_config_get8(config_handle, PCI_BCNF_SECBUS));
47123c35297Sanish prom_printf(" Sub Bus = [0x%x]\n",
47223c35297Sanish pci_config_get8(config_handle, PCI_BCNF_SUBBUS));
47323c35297Sanish prom_printf(" Latency = [0x%x]\n",
47423c35297Sanish pci_config_get8(config_handle, PCI_BCNF_LATENCY_TIMER));
47523c35297Sanish prom_printf(" I/O Base LO = [0x%x]\n",
47623c35297Sanish pci_config_get8(config_handle, PCI_BCNF_IO_BASE_LOW));
47723c35297Sanish prom_printf(" I/O Lim LO = [0x%x]\n",
47823c35297Sanish pci_config_get8(config_handle, PCI_BCNF_IO_LIMIT_LOW));
47923c35297Sanish prom_printf(" Sec. Status = [0x%x]\n",
48023c35297Sanish pci_config_get16(config_handle, PCI_BCNF_SEC_STATUS));
48123c35297Sanish prom_printf(" Mem Base = [0x%x]\n",
48223c35297Sanish pci_config_get16(config_handle, PCI_BCNF_MEM_BASE));
48323c35297Sanish prom_printf(" Mem Limit = [0x%x]\n",
48423c35297Sanish pci_config_get16(config_handle, PCI_BCNF_MEM_LIMIT));
48523c35297Sanish prom_printf(" PF Mem Base = [0x%x]\n",
48623c35297Sanish pci_config_get16(config_handle, PCI_BCNF_PF_BASE_LOW));
48723c35297Sanish prom_printf(" PF Mem Lim = [0x%x]\n",
48823c35297Sanish pci_config_get16(config_handle, PCI_BCNF_PF_LIMIT_LOW));
48923c35297Sanish prom_printf(" PF Base HI = [0x%x]\n",
49023c35297Sanish pci_config_get32(config_handle, PCI_BCNF_PF_BASE_HIGH));
49123c35297Sanish prom_printf(" PF Lim HI = [0x%x]\n",
49223c35297Sanish pci_config_get32(config_handle, PCI_BCNF_PF_LIMIT_HIGH));
49323c35297Sanish prom_printf(" I/O Base HI = [0x%x]\n",
49423c35297Sanish pci_config_get16(config_handle, PCI_BCNF_IO_BASE_HI));
49523c35297Sanish prom_printf(" I/O Lim HI = [0x%x]\n",
49623c35297Sanish pci_config_get16(config_handle, PCI_BCNF_IO_LIMIT_HI));
49723c35297Sanish prom_printf(" ROM addr = [0x%x]\n",
49823c35297Sanish pci_config_get32(config_handle, PCI_BCNF_ROM));
49923c35297Sanish prom_printf(" Intr Line = [0x%x]\n",
50023c35297Sanish pci_config_get8(config_handle, PCI_BCNF_ILINE));
50123c35297Sanish prom_printf(" Intr Pin = [0x%x]\n",
50223c35297Sanish pci_config_get8(config_handle, PCI_BCNF_IPIN));
50323c35297Sanish prom_printf(" Bridge Ctrl = [0x%x]\n",
50423c35297Sanish pci_config_get16(config_handle, PCI_BCNF_BCNTRL));
50523c35297Sanish }
50623c35297Sanish #endif
50723c35297Sanish
50823c35297Sanish int
_init()50923c35297Sanish _init()
51023c35297Sanish {
51123c35297Sanish DEBUG0(" PCI configurator installed\n");
51223c35297Sanish mutex_init(&pcicfg_list_mutex, NULL, MUTEX_DRIVER, NULL);
51323c35297Sanish return (mod_install(&modlinkage));
51423c35297Sanish }
51523c35297Sanish
51623c35297Sanish int
_fini(void)51723c35297Sanish _fini(void)
51823c35297Sanish {
51923c35297Sanish int error;
52023c35297Sanish
52123c35297Sanish error = mod_remove(&modlinkage);
52223c35297Sanish if (error != 0) {
52323c35297Sanish return (error);
52423c35297Sanish }
52523c35297Sanish mutex_destroy(&pcicfg_list_mutex);
52623c35297Sanish return (0);
52723c35297Sanish }
52823c35297Sanish
52923c35297Sanish int
_info(struct modinfo * modinfop)53023c35297Sanish _info(struct modinfo *modinfop)
53123c35297Sanish {
53223c35297Sanish return (mod_info(&modlinkage, modinfop));
53323c35297Sanish }
53423c35297Sanish
53523c35297Sanish /*
53623c35297Sanish * In the following functions ndi_devi_enter() without holding the
53723c35297Sanish * parent dip is sufficient. This is because pci dr is driven through
53823c35297Sanish * opens on the nexus which is in the device tree path above the node
53923c35297Sanish * being operated on, and implicitly held due to the open.
54023c35297Sanish */
54123c35297Sanish
54223c35297Sanish /*
54323c35297Sanish * This entry point is called to configure a device (and
54423c35297Sanish * all its children) on the given bus. It is called when
54523c35297Sanish * a new device is added to the PCI domain. This routine
54623c35297Sanish * will create the device tree and program the devices
54723c35297Sanish * registers.
54823c35297Sanish */
54923c35297Sanish 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)
55223c35297Sanish {
55323c35297Sanish uint_t bus;
55423c35297Sanish int len;
55523c35297Sanish int func;
55623c35297Sanish dev_info_t *attach_point;
55723c35297Sanish pci_bus_range_t pci_bus_range;
55823c35297Sanish 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));
56823c35297Sanish
56923c35297Sanish /*
57023c35297Sanish * Start probing at the device specified in "device" on the
57123c35297Sanish * "bus" specified.
57223c35297Sanish */
57323c35297Sanish len = sizeof (pci_bus_range_t);
57423c35297Sanish if (ddi_getlongprop_buf(DDI_DEV_T_ANY, devi, 0, "bus-range",
57523c35297Sanish (caddr_t)&pci_bus_range, &len) != DDI_SUCCESS) {
57623c35297Sanish DEBUG0("no bus-range property\n");
57723c35297Sanish return (PCICFG_FAILURE);
57823c35297Sanish }
57923c35297Sanish
58023c35297Sanish bus = pci_bus_range.lo; /* primary bus number of this bus node */
58123c35297Sanish
58223c35297Sanish attach_point = devi;
58323c35297Sanish
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; ) {
59823c35297Sanish
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;
60623c35297Sanish
60723c35297Sanish 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:
61123c35297Sanish case PCICFG_FAILURE:
61226947304SEvan Yan DEBUG2("configure failed: bus [0x%x] device "
61326947304SEvan Yan "[0x%x]\n", bus, trans_device);
61423c35297Sanish goto cleanup;
61523c35297Sanish case PCICFG_NODEVICE:
61623c35297Sanish DEBUG3("no device : bus "
61723c35297Sanish "[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;
63223c35297Sanish default:
63323c35297Sanish DEBUG3("configure: bus => [%d] "
63423c35297Sanish "slot => [%d] func => [%d]\n",
63526947304SEvan Yan bus, trans_device, func & 7);
63623c35297Sanish break;
63723c35297Sanish }
63823c35297Sanish
63923c35297Sanish if (rv != PCICFG_SUCCESS)
64023c35297Sanish break;
64123c35297Sanish
64223c35297Sanish if ((new_device = pcicfg_devi_find(attach_point,
64326947304SEvan Yan trans_device, func & 7)) == NULL) {
64423c35297Sanish DEBUG0("Did'nt find device node just created\n");
64523c35297Sanish goto cleanup;
64623c35297Sanish }
64723c35297Sanish
64823c35297Sanish /*
64923c35297Sanish * Up until now, we have detected a non transparent bridge
65023c35297Sanish * (ntbridge) as a part of the generic probe code and
65123c35297Sanish * configured only one configuration
65223c35297Sanish * header which is the side facing the host bus.
65323c35297Sanish * Now, configure the other side and create children.
65423c35297Sanish *
65523c35297Sanish * In order to make the process simpler, lets load the device
65623c35297Sanish * driver for the non transparent bridge as this is a
65723c35297Sanish * Solaris bundled driver, and use its configuration map
65823c35297Sanish * services rather than programming it here.
65923c35297Sanish * If the driver is not bundled into Solaris, it must be
66023c35297Sanish * first loaded and configured before performing any
66123c35297Sanish * hotplug operations.
66223c35297Sanish *
66323c35297Sanish * This not only makes the code here simpler but also more
66423c35297Sanish * generic.
66523c35297Sanish *
66623c35297Sanish * So here we go.
66723c35297Sanish */
66823c35297Sanish
66923c35297Sanish /*
67023c35297Sanish * check if this is a bridge in nontransparent mode
67123c35297Sanish */
67223c35297Sanish if (pcicfg_is_ntbridge(new_device) != DDI_FAILURE) {
67323c35297Sanish DEBUG0("pcicfg: Found nontransparent bridge.\n");
67423c35297Sanish
67526947304SEvan Yan rv = pcicfg_configure_ntbridge(new_device, bus,
67626947304SEvan Yan trans_device);
6775af4ae46Sjveta if (rv != PCICFG_SUCCESS)
67823c35297Sanish goto cleanup;
67923c35297Sanish }
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);
72523c35297Sanish }
72623c35297Sanish
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));
74123c35297Sanish
7425c734816SRobert Mustacchi if (visited == 0)
74323c35297Sanish return (PCICFG_FAILURE); /* probe failed */
74423c35297Sanish else
74523c35297Sanish return (PCICFG_SUCCESS);
74623c35297Sanish
74723c35297Sanish cleanup:
74823c35297Sanish /*
74923c35297Sanish * Clean up a partially created "probe state" tree.
75023c35297Sanish * There are no resources allocated to the in the
75123c35297Sanish * probe state.
75223c35297Sanish */
75323c35297Sanish
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) {
76023c35297Sanish continue;
76123c35297Sanish }
76223c35297Sanish
76323c35297Sanish DEBUG2("Cleaning up device [0x%x] function [0x%x]\n",
76423c35297Sanish device, func);
76523c35297Sanish /*
76623c35297Sanish * If this was a bridge device it will have a
76723c35297Sanish * probe handle - if not, no harm in calling this.
76823c35297Sanish */
76923c35297Sanish (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 }
77923c35297Sanish /*
78023c35297Sanish * This will free up the node
78123c35297Sanish */
78223c35297Sanish (void) ndi_devi_offline(new_device, NDI_DEVI_REMOVE);
78323c35297Sanish }
7843fe80ca4SDan Cross ndi_devi_exit(devi);
7853fe80ca4SDan Cross ndi_devi_exit(ddi_get_parent(devi));
78623c35297Sanish
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);
80723c35297Sanish }
80823c35297Sanish
80923c35297Sanish /*
81023c35297Sanish * configure the child nodes of ntbridge. new_device points to ntbridge itself
81123c35297Sanish */
81223c35297Sanish /*ARGSUSED*/
81323c35297Sanish static int
pcicfg_configure_ntbridge(dev_info_t * new_device,uint_t bus,uint_t device)81423c35297Sanish pcicfg_configure_ntbridge(dev_info_t *new_device, uint_t bus, uint_t device)
81523c35297Sanish {
81623c35297Sanish int bus_range[2], rc = PCICFG_FAILURE, rc1, max_devs = 0;
81723c35297Sanish int devno;
81823c35297Sanish dev_info_t *new_ntbridgechild;
81923c35297Sanish ddi_acc_handle_t config_handle;
82023c35297Sanish uint16_t vid;
82123c35297Sanish uint64_t next_bus;
82223c35297Sanish uint64_t blen;
82323c35297Sanish ndi_ra_request_t req;
82423c35297Sanish uint8_t pcie_device_type = 0;
82523c35297Sanish
82623c35297Sanish /*
82723c35297Sanish * If we need to do indirect config, lets create a property here
82823c35297Sanish * to let the child conf map routine know that it has to
82923c35297Sanish * go through the DDI calls, and not assume the devices are
83023c35297Sanish * mapped directly under the host.
83123c35297Sanish */
83223c35297Sanish if ((rc = ndi_prop_update_int(DDI_DEV_T_NONE, new_device,
83326947304SEvan Yan PCI_DEV_CONF_MAP_PROP, (int)DDI_SUCCESS)) != DDI_SUCCESS) {
83423c35297Sanish DEBUG0("Cannot create indirect conf map property.\n");
83523c35297Sanish return ((int)PCICFG_FAILURE);
83623c35297Sanish }
83723c35297Sanish
83823c35297Sanish if (pci_config_setup(new_device, &config_handle) != DDI_SUCCESS)
83923c35297Sanish return (PCICFG_FAILURE);
84023c35297Sanish /* check if we are PCIe device */
84123c35297Sanish if (pcicfg_pcie_device_type(new_device, config_handle) == DDI_SUCCESS) {
84223c35297Sanish DEBUG0("PCIe device detected\n");
84323c35297Sanish pcie_device_type = 1;
84423c35297Sanish }
84523c35297Sanish pci_config_teardown(&config_handle);
84623c35297Sanish /* create Bus node properties for ntbridge. */
84723c35297Sanish if (pcicfg_set_busnode_props(new_device, pcie_device_type)
84823c35297Sanish != PCICFG_SUCCESS) {
84923c35297Sanish DEBUG0("Failed to set busnode props\n");
85023c35297Sanish return (rc);
85123c35297Sanish }
85223c35297Sanish
85323c35297Sanish /* For now: Lets only support one layer of child */
85423c35297Sanish bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
85523c35297Sanish 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) {
85823c35297Sanish DEBUG0("ntbridge: Failed to get a bus number\n");
8595af4ae46Sjveta return (PCICFG_NORESRC);
86023c35297Sanish }
86123c35297Sanish
86223c35297Sanish DEBUG1("ntbridge bus range start ->[%d]\n", next_bus);
86323c35297Sanish
86423c35297Sanish /*
86523c35297Sanish * Following will change, as we detect more bridges
86623c35297Sanish * on the way.
86723c35297Sanish */
86823c35297Sanish bus_range[0] = (int)next_bus;
86923c35297Sanish bus_range[1] = (int)next_bus;
87023c35297Sanish
87126947304SEvan Yan if (ndi_prop_update_int_array(DDI_DEV_T_NONE, new_device, "bus-range",
87226947304SEvan Yan bus_range, 2) != DDI_SUCCESS) {
87323c35297Sanish DEBUG0("Cannot set ntbridge bus-range property");
87423c35297Sanish return (rc);
87523c35297Sanish }
87623c35297Sanish
87723c35297Sanish /*
87823c35297Sanish * The other interface (away from the host) will be
87923c35297Sanish * initialized by the nexus driver when it loads.
88023c35297Sanish * We just have to set the registers and the nexus driver
88123c35297Sanish * figures out the rest.
88223c35297Sanish */
88323c35297Sanish
88423c35297Sanish /*
88523c35297Sanish * finally, lets load and attach the driver
88623c35297Sanish * before configuring children of ntbridge.
88723c35297Sanish */
88823c35297Sanish rc = ndi_devi_online(new_device, NDI_ONLINE_ATTACH|NDI_CONFIG);
88923c35297Sanish if (rc != NDI_SUCCESS) {
89023c35297Sanish cmn_err(CE_WARN,
89123c35297Sanish "pcicfg: Fail:cant load nontransparent bridgd driver..\n");
89223c35297Sanish rc = PCICFG_FAILURE;
89323c35297Sanish return (rc);
89423c35297Sanish }
89523c35297Sanish DEBUG0("pcicfg: Success loading nontransparent bridge nexus driver..");
89623c35297Sanish
8975af4ae46Sjveta /* Now set aside pci resource allocation requests for our children */
89826947304SEvan Yan if (pcicfg_ntbridge_allocate_resources(new_device) != PCICFG_SUCCESS) {
89923c35297Sanish max_devs = 0;
90023c35297Sanish rc = PCICFG_FAILURE;
90123c35297Sanish } else
90223c35297Sanish max_devs = PCI_MAX_DEVICES;
90323c35297Sanish
90423c35297Sanish /* Probe devices on 2nd bus */
9055af4ae46Sjveta rc = PCICFG_SUCCESS;
90623c35297Sanish for (devno = pcicfg_start_devno; devno < max_devs; devno++) {
90723c35297Sanish
90823c35297Sanish ndi_devi_alloc_sleep(new_device, DEVI_PSEUDO_NEXNAME,
90923c35297Sanish (pnode_t)DEVI_SID_NODEID, &new_ntbridgechild);
91023c35297Sanish
91123c35297Sanish if (pcicfg_add_config_reg(new_ntbridgechild, next_bus, devno, 0)
91223c35297Sanish != DDI_PROP_SUCCESS) {
91323c35297Sanish cmn_err(CE_WARN,
91423c35297Sanish "Failed to add conf reg for ntbridge child.\n");
91523c35297Sanish (void) ndi_devi_free(new_ntbridgechild);
91623c35297Sanish rc = PCICFG_FAILURE;
91723c35297Sanish break;
91823c35297Sanish }
91923c35297Sanish
92023c35297Sanish if (pci_config_setup(new_ntbridgechild, &config_handle)
92123c35297Sanish != DDI_SUCCESS) {
92223c35297Sanish cmn_err(CE_WARN,
92323c35297Sanish "Cannot map ntbridge child %x\n", devno);
92423c35297Sanish (void) ndi_devi_free(new_ntbridgechild);
92523c35297Sanish rc = PCICFG_FAILURE;
92623c35297Sanish break;
92723c35297Sanish }
92823c35297Sanish
92923c35297Sanish /*
93023c35297Sanish * See if there is any PCI HW at this location
93123c35297Sanish * by reading the Vendor ID. If it returns with 0xffff
93223c35297Sanish * then there is no hardware at this location.
93323c35297Sanish */
93423c35297Sanish vid = pci_config_get16(config_handle, PCI_CONF_VENID);
93523c35297Sanish
93623c35297Sanish pci_config_teardown(&config_handle);
93723c35297Sanish (void) ndi_devi_free(new_ntbridgechild);
93823c35297Sanish if (vid == 0xffff)
93923c35297Sanish continue;
94023c35297Sanish
94123c35297Sanish /* Lets fake attachments points for each child, */
94226947304SEvan Yan rc = pcicfg_configure(new_device, devno, PCICFG_ALL_FUNC, 0);
9435af4ae46Sjveta if (rc != PCICFG_SUCCESS) {
94423c35297Sanish int old_dev = pcicfg_start_devno;
94523c35297Sanish
94623c35297Sanish cmn_err(CE_WARN,
94723c35297Sanish "Error configuring ntbridge child dev=%d\n", devno);
94823c35297Sanish
94923c35297Sanish while (old_dev != devno) {
95023c35297Sanish if (pcicfg_ntbridge_unconfigure_child(
95123c35297Sanish new_device, old_dev) == PCICFG_FAILURE)
95226947304SEvan Yan cmn_err(CE_WARN, "Unconfig Error "
95326947304SEvan Yan "ntbridge child dev=%d\n", old_dev);
95423c35297Sanish old_dev++;
95523c35297Sanish }
95623c35297Sanish break;
95723c35297Sanish }
95823c35297Sanish } /* devno loop */
95923c35297Sanish DEBUG1("ntbridge: finish probing 2nd bus, rc=%d\n", rc);
96023c35297Sanish
9615af4ae46Sjveta if (rc == PCICFG_SUCCESS)
96223c35297Sanish rc = pcicfg_ntbridge_configure_done(new_device);
96323c35297Sanish else {
96423c35297Sanish pcicfg_phdl_t *entry = pcicfg_find_phdl(new_device);
96523c35297Sanish uint_t *bus;
96623c35297Sanish int k;
96723c35297Sanish
96823c35297Sanish 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) {
97123c35297Sanish DEBUG0("Failed to read bus-range property\n");
97223c35297Sanish rc = PCICFG_FAILURE;
97323c35297Sanish return (rc);
97423c35297Sanish }
97523c35297Sanish
97623c35297Sanish DEBUG2("Need to free bus [%d] range [%d]\n",
97723c35297Sanish bus[0], bus[1] - bus[0] + 1);
97823c35297Sanish
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) {
98223c35297Sanish DEBUG0("Failed to free a bus number\n");
98323c35297Sanish rc = PCICFG_FAILURE;
9841fb5b786Sprasad kmem_free(bus, k);
98523c35297Sanish return (rc);
98623c35297Sanish }
98723c35297Sanish
98823c35297Sanish /*
98923c35297Sanish * Since no memory allocations are done for non transparent
99023c35297Sanish * bridges (but instead we just set the handle with the
99123c35297Sanish * already allocated memory, we just need to reset the
99223c35297Sanish * following values before calling the destroy_phdl()
99323c35297Sanish * function next, otherwise the it will try to free
99423c35297Sanish * memory allocated as in case of a transparent bridge.
99523c35297Sanish */
99623c35297Sanish entry->memory_len = 0;
99723c35297Sanish entry->pf_memory_len = 0;
99823c35297Sanish entry->io_len = 0;
9991fb5b786Sprasad kmem_free(bus, k);
100023c35297Sanish /* the following will free hole data. */
100123c35297Sanish (void) pcicfg_destroy_phdl(new_device);
100223c35297Sanish }
100323c35297Sanish
100423c35297Sanish /*
100523c35297Sanish * Unload driver just in case child configure failed!
100623c35297Sanish */
100723c35297Sanish rc1 = ndi_devi_offline(new_device, 0);
100823c35297Sanish DEBUG1("pcicfg: now unloading the ntbridge driver. rc1=%d\n", rc1);
100923c35297Sanish if (rc1 != NDI_SUCCESS) {
101023c35297Sanish cmn_err(CE_WARN,
101123c35297Sanish "pcicfg: cant unload ntbridge driver..children.\n");
101223c35297Sanish rc = PCICFG_FAILURE;
101323c35297Sanish }
101423c35297Sanish
101523c35297Sanish return (rc);
101623c35297Sanish }
101723c35297Sanish
101823c35297Sanish static int
pcicfg_ntbridge_allocate_resources(dev_info_t * dip)101923c35297Sanish pcicfg_ntbridge_allocate_resources(dev_info_t *dip)
102023c35297Sanish {
102123c35297Sanish pcicfg_phdl_t *phdl;
102223c35297Sanish ndi_ra_request_t *mem_request;
102323c35297Sanish ndi_ra_request_t *pf_mem_request;
102423c35297Sanish ndi_ra_request_t *io_request;
102523c35297Sanish uint64_t boundbase, boundlen;
102623c35297Sanish
102723c35297Sanish phdl = pcicfg_find_phdl(dip);
102823c35297Sanish ASSERT(phdl);
102923c35297Sanish
103023c35297Sanish mem_request = &phdl->mem_req;
103123c35297Sanish pf_mem_request = &phdl->pf_mem_req;
103223c35297Sanish io_request = &phdl->io_req;
103323c35297Sanish
103423c35297Sanish phdl->error = PCICFG_SUCCESS;
103523c35297Sanish
103623c35297Sanish /* Set Memory space handle for ntbridge */
103723c35297Sanish if (pcicfg_get_ntbridge_child_range(dip, &boundbase, &boundlen,
103823c35297Sanish PCI_BASE_SPACE_MEM) != DDI_SUCCESS) {
103923c35297Sanish cmn_err(CE_WARN,
104023c35297Sanish "ntbridge: Mem resource information failure\n");
104123c35297Sanish phdl->memory_len = 0;
104223c35297Sanish return (PCICFG_FAILURE);
104323c35297Sanish }
104423c35297Sanish mem_request->ra_boundbase = boundbase;
104523c35297Sanish mem_request->ra_boundlen = boundbase + boundlen;
104623c35297Sanish mem_request->ra_len = boundlen;
104723c35297Sanish mem_request->ra_align_mask =
104823c35297Sanish PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */
104923c35297Sanish mem_request->ra_flags |= NDI_RA_ALLOC_BOUNDED;
105023c35297Sanish
105123c35297Sanish /*
105223c35297Sanish * mem_request->ra_len =
105323c35297Sanish * PCICFG_ROUND_UP(mem_request->ra_len, PCICFG_MEMGRAN);
105423c35297Sanish */
105523c35297Sanish
105623c35297Sanish phdl->memory_base = phdl->memory_last = boundbase;
105723c35297Sanish phdl->memory_len = boundlen;
105823c35297Sanish phdl->mem_hole.start = phdl->memory_base;
105923c35297Sanish phdl->mem_hole.len = mem_request->ra_len;
106023c35297Sanish phdl->mem_hole.next = (hole_t *)NULL;
106123c35297Sanish
106226947304SEvan Yan DEBUG2("Connector requested [0x%llx], needs [0x%llx] bytes of memory\n",
106323c35297Sanish boundlen, mem_request->ra_len);
106423c35297Sanish
106523c35297Sanish /* Set IO space handle for ntbridge */
106623c35297Sanish if (pcicfg_get_ntbridge_child_range(dip, &boundbase, &boundlen,
106723c35297Sanish PCI_BASE_SPACE_IO) != DDI_SUCCESS) {
106823c35297Sanish cmn_err(CE_WARN, "ntbridge: IO resource information failure\n");
106923c35297Sanish phdl->io_len = 0;
107023c35297Sanish return (PCICFG_FAILURE);
107123c35297Sanish }
107223c35297Sanish io_request->ra_len = boundlen;
107323c35297Sanish io_request->ra_align_mask =
107423c35297Sanish PCICFG_IOGRAN - 1; /* 4K alignment on I/O space */
107523c35297Sanish io_request->ra_boundbase = boundbase;
107623c35297Sanish io_request->ra_boundlen = boundbase + boundlen;
107723c35297Sanish io_request->ra_flags |= NDI_RA_ALLOC_BOUNDED;
107823c35297Sanish
107923c35297Sanish /*
108023c35297Sanish * io_request->ra_len =
108123c35297Sanish * PCICFG_ROUND_UP(io_request->ra_len, PCICFG_IOGRAN);
108223c35297Sanish */
108323c35297Sanish
108423c35297Sanish phdl->io_base = phdl->io_last = (uint32_t)boundbase;
108523c35297Sanish phdl->io_len = (uint32_t)boundlen;
108623c35297Sanish phdl->io_hole.start = phdl->io_base;
108723c35297Sanish phdl->io_hole.len = io_request->ra_len;
108823c35297Sanish phdl->io_hole.next = (hole_t *)NULL;
108923c35297Sanish
109026947304SEvan Yan DEBUG2("Connector requested [0x%llx], needs [0x%llx] bytes of IO\n",
109123c35297Sanish boundlen, io_request->ra_len);
109223c35297Sanish
109323c35297Sanish /* Set Prefetchable Memory space handle for ntbridge */
109423c35297Sanish if (pcicfg_get_ntbridge_child_range(dip, &boundbase, &boundlen,
109523c35297Sanish PCI_BASE_SPACE_MEM | PCI_BASE_PREF_M) != DDI_SUCCESS) {
109623c35297Sanish cmn_err(CE_WARN,
109723c35297Sanish "ntbridge: PF Mem resource information failure\n");
109823c35297Sanish phdl->pf_memory_len = 0;
109923c35297Sanish return (PCICFG_FAILURE);
110023c35297Sanish }
110123c35297Sanish pf_mem_request->ra_boundbase = boundbase;
110223c35297Sanish pf_mem_request->ra_boundlen = boundbase + boundlen;
110323c35297Sanish pf_mem_request->ra_len = boundlen;
110423c35297Sanish pf_mem_request->ra_align_mask =
110523c35297Sanish PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */
110623c35297Sanish pf_mem_request->ra_flags |= NDI_RA_ALLOC_BOUNDED;
110723c35297Sanish
110823c35297Sanish /*
110923c35297Sanish * pf_mem_request->ra_len =
111023c35297Sanish * PCICFG_ROUND_UP(pf_mem_request->ra_len, PCICFG_MEMGRAN);
111123c35297Sanish */
111223c35297Sanish
111323c35297Sanish phdl->pf_memory_base = phdl->pf_memory_last = boundbase;
111423c35297Sanish phdl->pf_memory_len = boundlen;
111523c35297Sanish phdl->pf_mem_hole.start = phdl->pf_memory_base;
111623c35297Sanish phdl->pf_mem_hole.len = pf_mem_request->ra_len;
111723c35297Sanish phdl->pf_mem_hole.next = (hole_t *)NULL;
111823c35297Sanish
111926947304SEvan Yan DEBUG2("Connector requested [0x%llx], needs [0x%llx] bytes of PF "
112026947304SEvan Yan "memory\n", boundlen, pf_mem_request->ra_len);
112123c35297Sanish
112223c35297Sanish DEBUG2("MEMORY BASE = [0x%lx] length [0x%lx]\n",
112323c35297Sanish phdl->memory_base, phdl->memory_len);
112423c35297Sanish DEBUG2("IO BASE = [0x%x] length [0x%x]\n",
112523c35297Sanish phdl->io_base, phdl->io_len);
112623c35297Sanish DEBUG2("PF MEMORY BASE = [0x%lx] length [0x%lx]\n",
112723c35297Sanish phdl->pf_memory_base, phdl->pf_memory_len);
112823c35297Sanish
112923c35297Sanish return (PCICFG_SUCCESS);
113023c35297Sanish }
113123c35297Sanish
113223c35297Sanish static int
pcicfg_ntbridge_configure_done(dev_info_t * dip)113323c35297Sanish pcicfg_ntbridge_configure_done(dev_info_t *dip)
113423c35297Sanish {
113523c35297Sanish ppb_ranges_t range[PCICFG_RANGE_LEN];
113623c35297Sanish pcicfg_phdl_t *entry;
113723c35297Sanish uint_t len;
113823c35297Sanish pci_bus_range_t bus_range;
113923c35297Sanish int new_bus_range[2];
114023c35297Sanish
114123c35297Sanish DEBUG1("Configuring children for %p\n", dip);
114223c35297Sanish
114323c35297Sanish entry = pcicfg_find_phdl(dip);
114423c35297Sanish ASSERT(entry);
114523c35297Sanish
114626947304SEvan Yan bzero((caddr_t)range, sizeof (ppb_ranges_t) * PCICFG_RANGE_LEN);
114723c35297Sanish range[1].child_high = range[1].parent_high |=
114823c35297Sanish (PCI_REG_REL_M | PCI_ADDR_MEM32);
114923c35297Sanish range[1].child_low = range[1].parent_low = (uint32_t)entry->memory_base;
115023c35297Sanish
115123c35297Sanish range[0].child_high = range[0].parent_high |=
115223c35297Sanish (PCI_REG_REL_M | PCI_ADDR_IO);
115323c35297Sanish range[0].child_low = range[0].parent_low = (uint32_t)entry->io_base;
115423c35297Sanish
115523c35297Sanish range[2].child_high = range[2].parent_high |=
115623c35297Sanish (PCI_REG_REL_M | PCI_ADDR_MEM32 | PCI_REG_PF_M);
115723c35297Sanish range[2].child_low = range[2].parent_low =
115823c35297Sanish (uint32_t)entry->pf_memory_base;
115923c35297Sanish
116023c35297Sanish len = sizeof (pci_bus_range_t);
116123c35297Sanish if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
116223c35297Sanish "bus-range", (caddr_t)&bus_range, (int *)&len) != DDI_SUCCESS) {
116323c35297Sanish DEBUG0("no bus-range property\n");
116423c35297Sanish return (PCICFG_FAILURE);
116523c35297Sanish }
116623c35297Sanish
116723c35297Sanish new_bus_range[0] = bus_range.lo; /* primary bus number */
116823c35297Sanish if (entry->highest_bus) { /* secondary bus number */
116923c35297Sanish if (entry->highest_bus < bus_range.lo) {
117023c35297Sanish cmn_err(CE_WARN,
117123c35297Sanish "ntbridge bus range invalid !(%d,%d)\n",
117223c35297Sanish bus_range.lo, entry->highest_bus);
117323c35297Sanish new_bus_range[1] = bus_range.lo + entry->highest_bus;
117423c35297Sanish }
117523c35297Sanish else
117623c35297Sanish new_bus_range[1] = entry->highest_bus;
117723c35297Sanish }
117823c35297Sanish else
117923c35297Sanish new_bus_range[1] = bus_range.hi;
118023c35297Sanish
118126947304SEvan Yan DEBUG2("ntbridge: bus range lo=%x, hi=%x\n", new_bus_range[0],
118226947304SEvan Yan new_bus_range[1]);
118323c35297Sanish
118426947304SEvan Yan if (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "bus-range",
118526947304SEvan Yan new_bus_range, 2) != DDI_SUCCESS) {
118623c35297Sanish DEBUG0("Failed to set bus-range property");
118723c35297Sanish entry->error = PCICFG_FAILURE;
118823c35297Sanish return (PCICFG_FAILURE);
118923c35297Sanish }
119023c35297Sanish
119123c35297Sanish #ifdef DEBUG
119223c35297Sanish {
119323c35297Sanish uint64_t unused;
119423c35297Sanish unused = pcicfg_unused_space(&entry->io_hole, &len);
119523c35297Sanish DEBUG2("ntbridge: Unused IO space %llx bytes over %d holes\n",
119623c35297Sanish unused, len);
119723c35297Sanish }
119823c35297Sanish #endif
119923c35297Sanish
120023c35297Sanish range[0].size_low = entry->io_len;
120123c35297Sanish if (pcicfg_update_ranges_prop(dip, &range[0])) {
120223c35297Sanish DEBUG0("Failed to update ranges (i/o)\n");
120323c35297Sanish entry->error = PCICFG_FAILURE;
120423c35297Sanish return (PCICFG_FAILURE);
120523c35297Sanish }
120623c35297Sanish
120723c35297Sanish #ifdef DEBUG
120823c35297Sanish {
120923c35297Sanish uint64_t unused;
121023c35297Sanish unused = pcicfg_unused_space(&entry->mem_hole, &len);
121123c35297Sanish DEBUG2("ntbridge: Unused Mem space %llx bytes over %d holes\n",
121223c35297Sanish unused, len);
121323c35297Sanish }
121423c35297Sanish #endif
121523c35297Sanish
121623c35297Sanish range[1].size_low = entry->memory_len;
121723c35297Sanish if (pcicfg_update_ranges_prop(dip, &range[1])) {
121823c35297Sanish DEBUG0("Failed to update ranges (memory)\n");
121923c35297Sanish entry->error = PCICFG_FAILURE;
122023c35297Sanish return (PCICFG_FAILURE);
122123c35297Sanish }
122223c35297Sanish
122323c35297Sanish #ifdef DEBUG
122423c35297Sanish {
122523c35297Sanish uint64_t unused;
122623c35297Sanish unused = pcicfg_unused_space(&entry->pf_mem_hole, &len);
122723c35297Sanish DEBUG2("ntbridge: Unused PF Mem space %llx bytes over"
122823c35297Sanish " %d holes\n", unused, len);
122923c35297Sanish }
123023c35297Sanish #endif
123123c35297Sanish
123223c35297Sanish range[2].size_low = entry->pf_memory_len;
123323c35297Sanish if (pcicfg_update_ranges_prop(dip, &range[2])) {
123423c35297Sanish DEBUG0("Failed to update ranges (PF memory)\n");
123523c35297Sanish entry->error = PCICFG_FAILURE;
123623c35297Sanish return (PCICFG_FAILURE);
123723c35297Sanish }
123823c35297Sanish
123923c35297Sanish return (PCICFG_SUCCESS);
124023c35297Sanish }
124123c35297Sanish
124223c35297Sanish static int
pcicfg_ntbridge_program_child(dev_info_t * dip)124323c35297Sanish pcicfg_ntbridge_program_child(dev_info_t *dip)
124423c35297Sanish {
124523c35297Sanish pcicfg_phdl_t *entry;
124623c35297Sanish int rc = PCICFG_SUCCESS;
124723c35297Sanish dev_info_t *anode = dip;
124823c35297Sanish
124926947304SEvan Yan /* Find the Hotplug Connection (CN) node */
125026947304SEvan Yan while ((anode != NULL) &&
125126947304SEvan Yan (strcmp(ddi_binding_name(anode), "hp_attachment") != 0)) {
125223c35297Sanish anode = ddi_get_parent(anode);
125323c35297Sanish }
125423c35297Sanish
125523c35297Sanish if (anode == NULL) {
125623c35297Sanish DEBUG0("ntbridge child tree not in PROBE state\n");
125723c35297Sanish return (PCICFG_FAILURE);
125823c35297Sanish }
125923c35297Sanish entry = pcicfg_find_phdl(ddi_get_parent(anode));
126023c35297Sanish ASSERT(entry);
126123c35297Sanish
126223c35297Sanish if (pcicfg_bridge_assign(dip, entry) == DDI_WALK_TERMINATE) {
126323c35297Sanish cmn_err(CE_WARN,
126423c35297Sanish "ntbridge: Error assigning range for child %s\n",
126523c35297Sanish ddi_get_name(dip));
126623c35297Sanish rc = PCICFG_FAILURE;
126723c35297Sanish }
126823c35297Sanish return (rc);
126923c35297Sanish }
127023c35297Sanish
127123c35297Sanish static int
pcicfg_ntbridge_unconfigure_child(dev_info_t * new_device,uint_t devno)127223c35297Sanish pcicfg_ntbridge_unconfigure_child(dev_info_t *new_device, uint_t devno)
127323c35297Sanish {
127423c35297Sanish
127523c35297Sanish dev_info_t *new_ntbridgechild;
127623c35297Sanish int len, bus;
127723c35297Sanish uint16_t vid;
127823c35297Sanish ddi_acc_handle_t config_handle;
127923c35297Sanish pci_bus_range_t pci_bus_range;
128023c35297Sanish
128123c35297Sanish len = sizeof (pci_bus_range_t);
128223c35297Sanish if (ddi_getlongprop_buf(DDI_DEV_T_ANY, new_device, DDI_PROP_DONTPASS,
128323c35297Sanish "bus-range", (caddr_t)&pci_bus_range, &len) != DDI_SUCCESS) {
128423c35297Sanish DEBUG0("no bus-range property\n");
128523c35297Sanish return (PCICFG_FAILURE);
128623c35297Sanish }
128723c35297Sanish
128823c35297Sanish bus = pci_bus_range.lo; /* primary bus number of this bus node */
128923c35297Sanish
129023c35297Sanish ndi_devi_alloc_sleep(new_device, DEVI_PSEUDO_NEXNAME,
129123c35297Sanish (pnode_t)DEVI_SID_NODEID, &new_ntbridgechild);
129223c35297Sanish
129323c35297Sanish if (pcicfg_add_config_reg(new_ntbridgechild, bus, devno, 0)
129423c35297Sanish != DDI_PROP_SUCCESS) {
129526947304SEvan Yan cmn_err(CE_WARN, "Unconfigure: Failed to add conf reg prop for "
129626947304SEvan Yan "ntbridge child.\n");
129723c35297Sanish (void) ndi_devi_free(new_ntbridgechild);
129823c35297Sanish return (PCICFG_FAILURE);
129923c35297Sanish }
130023c35297Sanish
130123c35297Sanish if (pci_config_setup(new_ntbridgechild, &config_handle)
130223c35297Sanish != DDI_SUCCESS) {
130326947304SEvan Yan cmn_err(CE_WARN, "pcicfg: Cannot map ntbridge child %x\n",
130426947304SEvan Yan devno);
130523c35297Sanish (void) ndi_devi_free(new_ntbridgechild);
130623c35297Sanish return (PCICFG_FAILURE);
130723c35297Sanish }
130823c35297Sanish
130923c35297Sanish /*
131023c35297Sanish * See if there is any PCI HW at this location
131123c35297Sanish * by reading the Vendor ID. If it returns with 0xffff
131223c35297Sanish * then there is no hardware at this location.
131323c35297Sanish */
131423c35297Sanish vid = pci_config_get16(config_handle, PCI_CONF_VENID);
131523c35297Sanish
131623c35297Sanish pci_config_teardown(&config_handle);
131723c35297Sanish (void) ndi_devi_free(new_ntbridgechild);
131823c35297Sanish if (vid == 0xffff)
131923c35297Sanish return (PCICFG_NODEVICE);
132023c35297Sanish
132126947304SEvan Yan return (pcicfg_unconfigure(new_device, devno, PCICFG_ALL_FUNC, 0));
132223c35297Sanish }
132323c35297Sanish
132423c35297Sanish static uint_t
pcicfg_ntbridge_unconfigure(dev_info_t * dip)132523c35297Sanish pcicfg_ntbridge_unconfigure(dev_info_t *dip)
132623c35297Sanish {
132723c35297Sanish pcicfg_phdl_t *entry = pcicfg_find_phdl(dip);
132823c35297Sanish uint_t *bus;
132923c35297Sanish int k, rc = DDI_FAILURE;
133023c35297Sanish
133126947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "bus-range",
133226947304SEvan Yan (caddr_t)&bus, &k) != DDI_PROP_SUCCESS) {
133323c35297Sanish DEBUG0("ntbridge: Failed to read bus-range property\n");
133423c35297Sanish return (rc);
133523c35297Sanish }
133623c35297Sanish
133723c35297Sanish DEBUG2("ntbridge: Need to free bus [%d] range [%d]\n",
133823c35297Sanish bus[0], bus[1] - bus[0] + 1);
133923c35297Sanish
134026947304SEvan Yan if (ndi_ra_free(ddi_get_parent(dip), (uint64_t)bus[0],
134126947304SEvan Yan (uint64_t)(bus[1] - bus[0] + 1),
134223c35297Sanish NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS) != NDI_SUCCESS) {
134323c35297Sanish DEBUG0("ntbridge: Failed to free a bus number\n");
134423c35297Sanish kmem_free(bus, k);
134523c35297Sanish return (rc);
134623c35297Sanish }
134723c35297Sanish
134823c35297Sanish /*
134923c35297Sanish * Since our resources will be freed at the parent level,
135023c35297Sanish * just reset these values.
135123c35297Sanish */
135223c35297Sanish entry->memory_len = 0;
135323c35297Sanish entry->io_len = 0;
135423c35297Sanish entry->pf_memory_len = 0;
135523c35297Sanish
135623c35297Sanish kmem_free(bus, k);
135723c35297Sanish
135823c35297Sanish /* the following will also free hole data. */
135923c35297Sanish return (pcicfg_destroy_phdl(dip));
136023c35297Sanish
136123c35297Sanish }
136223c35297Sanish
136323c35297Sanish static int
pcicfg_is_ntbridge(dev_info_t * dip)136423c35297Sanish pcicfg_is_ntbridge(dev_info_t *dip)
136523c35297Sanish {
136623c35297Sanish ddi_acc_handle_t config_handle;
136723c35297Sanish uint8_t class, subclass;
136823c35297Sanish int rc = DDI_SUCCESS;
136923c35297Sanish
137023c35297Sanish if (pci_config_setup(dip, &config_handle) != DDI_SUCCESS) {
137123c35297Sanish cmn_err(CE_WARN,
137223c35297Sanish "pcicfg: cannot map config space, to get map type\n");
137323c35297Sanish return (DDI_FAILURE);
137423c35297Sanish }
137523c35297Sanish class = pci_config_get8(config_handle, PCI_CONF_BASCLASS);
137623c35297Sanish subclass = pci_config_get8(config_handle, PCI_CONF_SUBCLASS);
137723c35297Sanish
137823c35297Sanish /* check for class=6, subclass=9, for non transparent bridges. */
137923c35297Sanish if ((class != PCI_CLASS_BRIDGE) || (subclass != PCI_BRIDGE_STBRIDGE))
138023c35297Sanish rc = DDI_FAILURE;
138123c35297Sanish
138223c35297Sanish DEBUG3("pcicfg: checking device %x,%x for indirect map. rc=%d\n",
138323c35297Sanish pci_config_get16(config_handle, PCI_CONF_VENID),
138423c35297Sanish pci_config_get16(config_handle, PCI_CONF_DEVID),
138523c35297Sanish rc);
138623c35297Sanish pci_config_teardown(&config_handle);
138723c35297Sanish return (rc);
138823c35297Sanish }
138923c35297Sanish
139023c35297Sanish static uint_t
pcicfg_ntbridge_child(dev_info_t * dip)139123c35297Sanish pcicfg_ntbridge_child(dev_info_t *dip)
139223c35297Sanish {
139323c35297Sanish int len, val, rc = DDI_FAILURE;
139423c35297Sanish dev_info_t *anode = dip;
139523c35297Sanish
139623c35297Sanish /*
139726947304SEvan Yan * Find the Hotplug Connection (CN) node
139823c35297Sanish */
139923c35297Sanish while ((anode != NULL) && (strcmp(ddi_binding_name(anode),
140023c35297Sanish "hp_attachment") != 0)) {
140123c35297Sanish anode = ddi_get_parent(anode);
140223c35297Sanish }
140323c35297Sanish
140423c35297Sanish if (anode == NULL) {
140523c35297Sanish DEBUG0("ntbridge child tree not in PROBE state\n");
140623c35297Sanish return (rc);
140723c35297Sanish }
140823c35297Sanish len = sizeof (int);
140923c35297Sanish 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) {
141223c35297Sanish
141323c35297Sanish DEBUG1("ntbridge child: no \"%s\" property\n",
141423c35297Sanish PCI_DEV_CONF_MAP_PROP);
141523c35297Sanish return (rc);
141623c35297Sanish }
141723c35297Sanish DEBUG0("ntbridge child: success\n");
141823c35297Sanish return (DDI_SUCCESS);
141923c35297Sanish }
142023c35297Sanish
142123c35297Sanish static uint_t
pcicfg_get_ntbridge_child_range(dev_info_t * dip,uint64_t * boundbase,uint64_t * boundlen,uint_t space_type)142223c35297Sanish pcicfg_get_ntbridge_child_range(dev_info_t *dip, uint64_t *boundbase,
142323c35297Sanish uint64_t *boundlen, uint_t space_type)
142423c35297Sanish {
142523c35297Sanish int length, found = DDI_FAILURE, acount, i, ibridge;
142623c35297Sanish pci_regspec_t *assigned;
142723c35297Sanish
142823c35297Sanish if ((ibridge = pcicfg_is_ntbridge(dip)) == DDI_FAILURE)
142923c35297Sanish return (found);
143023c35297Sanish
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) {
143423c35297Sanish DEBUG1("Failed to get assigned-addresses property %llx\n", dip);
143523c35297Sanish return (found);
143623c35297Sanish }
143723c35297Sanish DEBUG1("pcicfg: ntbridge child range: dip = %s\n",
143823c35297Sanish ddi_driver_name(dip));
143923c35297Sanish
144023c35297Sanish acount = length / sizeof (pci_regspec_t);
144123c35297Sanish
144223c35297Sanish 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) &&
144523c35297Sanish (space_type == PCI_BASE_SPACE_MEM)) {
144623c35297Sanish found = DDI_SUCCESS;
144723c35297Sanish 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) &&
145023c35297Sanish (space_type == PCI_BASE_SPACE_IO)) {
145123c35297Sanish found = DDI_SUCCESS;
145223c35297Sanish break;
145326947304SEvan Yan } else if ((PCI_REG_REG_G(assigned[i].pci_phys_hi) ==
145423c35297Sanish pcicfg_indirect_map_devs[ibridge].
145523c35297Sanish prefetch_mem_range_bar_offset) &&
145623c35297Sanish (space_type == (PCI_BASE_SPACE_MEM |
145723c35297Sanish PCI_BASE_PREF_M))) {
145823c35297Sanish found = DDI_SUCCESS;
145923c35297Sanish break;
146023c35297Sanish }
146123c35297Sanish }
146223c35297Sanish DEBUG3("pcicfg: ntbridge child range: space=%x, base=%lx, len=%lx\n",
146323c35297Sanish space_type, assigned[i].pci_phys_low, assigned[i].pci_size_low);
146423c35297Sanish
146523c35297Sanish if (found == DDI_SUCCESS) {
146623c35297Sanish *boundbase = assigned[i].pci_phys_low;
146723c35297Sanish *boundlen = assigned[i].pci_size_low;
146823c35297Sanish }
146923c35297Sanish
147023c35297Sanish kmem_free(assigned, length);
147123c35297Sanish return (found);
147223c35297Sanish }
147323c35297Sanish
147423c35297Sanish /*
147523c35297Sanish * This will turn resources allocated by pcicfg_configure()
147626947304SEvan Yan * and remove the device tree from the Hotplug Connection (CN)
147723c35297Sanish * and below. The routine assumes the devices have their
147823c35297Sanish * drivers detached.
147923c35297Sanish */
148023c35297Sanish 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)
148323c35297Sanish {
148423c35297Sanish dev_info_t *child_dip;
148523c35297Sanish int func;
148623c35297Sanish 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;
149423c35297Sanish
149523c35297Sanish /*
149623c35297Sanish * Cycle through devices to make sure none are busy.
149723c35297Sanish * If a single device is busy fail the whole unconfigure.
149823c35297Sanish */
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)
151323c35297Sanish continue;
151423c35297Sanish
151523c35297Sanish if (ndi_devi_offline(child_dip, NDI_UNCONFIG) == NDI_SUCCESS)
151623c35297Sanish continue;
151726947304SEvan Yan
151823c35297Sanish /*
151923c35297Sanish * Device function is busy. Before returning we have to
152023c35297Sanish * put all functions back online which were taken
152123c35297Sanish * offline during the process.
152223c35297Sanish */
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)
153026947304SEvan Yan return (PCICFG_FAILURE);
153126947304SEvan Yan
153223c35297Sanish 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");
154023c35297Sanish /*
154123c35297Sanish * Made it through all functions
154223c35297Sanish */
154323c35297Sanish continue;
154423c35297Sanish }
154526947304SEvan Yan if (ndi_devi_online(child_dip, NDI_CONFIG)
154626947304SEvan Yan != NDI_SUCCESS) {
154723c35297Sanish DEBUG0("Failed to put back devices state\n");
1548c0da6274SZhi-Jun Robin Fu goto fail;
154923c35297Sanish }
155023c35297Sanish }
1551c0da6274SZhi-Jun Robin Fu goto fail;
155223c35297Sanish }
155323c35297Sanish
155423c35297Sanish /*
155526947304SEvan Yan * Now, tear down all devinfo nodes for this Connector.
155623c35297Sanish */
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);
156923c35297Sanish continue;
157023c35297Sanish }
157123c35297Sanish
157223c35297Sanish DEBUG2("Tearing down device [0x%x] function [0x%x]\n",
157326947304SEvan Yan trans_device, func & 7);
157423c35297Sanish
157523c35297Sanish if (pcicfg_is_ntbridge(child_dip) != DDI_FAILURE)
157623c35297Sanish if (pcicfg_ntbridge_unconfigure(child_dip) !=
157723c35297Sanish PCICFG_SUCCESS) {
157823c35297Sanish cmn_err(CE_WARN,
157923c35297Sanish "ntbridge: unconfigure failed\n");
1580c0da6274SZhi-Jun Robin Fu goto fail;
158123c35297Sanish }
158223c35297Sanish
1583c0da6274SZhi-Jun Robin Fu if (pcicfg_teardown_device(child_dip, flags, is_pcie)
158426947304SEvan Yan != PCICFG_SUCCESS) {
158523c35297Sanish DEBUG2("Failed to tear down device [0x%x]"
158626947304SEvan Yan "function [0x%x]\n", trans_device, func & 7);
1587c0da6274SZhi-Jun Robin Fu goto fail;
158823c35297Sanish }
158923c35297Sanish }
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);
159723c35297Sanish 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);
160223c35297Sanish }
160323c35297Sanish
160423c35297Sanish 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)
160623c35297Sanish {
160723c35297Sanish ddi_acc_handle_t handle;
1608ffb64830SJordan Paige Hendricks int ret;
160923c35297Sanish
161023c35297Sanish /*
161123c35297Sanish * Free up resources associated with 'dip'
161223c35297Sanish */
161326947304SEvan Yan if (pcicfg_free_resources(dip, flags) != PCICFG_SUCCESS) {
161423c35297Sanish DEBUG0("Failed to free resources\n");
161523c35297Sanish return (PCICFG_FAILURE);
161623c35297Sanish }
161723c35297Sanish
161823c35297Sanish /*
161923c35297Sanish * disable the device
162023c35297Sanish */
1621ffb64830SJordan Paige Hendricks
1622ffb64830SJordan Paige Hendricks ret = pcicfg_config_setup(dip, &handle);
1623ffb64830SJordan Paige Hendricks if (ret == PCICFG_SUCCESS) {
162423c35297Sanish pcicfg_device_off(handle);
162523c35297Sanish 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 */
1633ffb64830SJordan Paige Hendricks return (PCICFG_FAILURE);
1634ffb64830SJordan Paige Hendricks }
163523c35297Sanish
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
164623c35297Sanish /*
164723c35297Sanish * The framework provides this routine which can
164823c35297Sanish * tear down a sub-tree.
164923c35297Sanish */
165023c35297Sanish if (ndi_devi_offline(dip, NDI_DEVI_REMOVE) != NDI_SUCCESS) {
165123c35297Sanish DEBUG0("Failed to offline and remove node\n");
165223c35297Sanish return (PCICFG_FAILURE);
165323c35297Sanish }
165423c35297Sanish
165523c35297Sanish return (PCICFG_SUCCESS);
165623c35297Sanish }
165723c35297Sanish
165823c35297Sanish /*
165923c35297Sanish * BEGIN GENERIC SUPPORT ROUTINES
166023c35297Sanish */
166123c35297Sanish static pcicfg_phdl_t *
pcicfg_find_phdl(dev_info_t * dip)166223c35297Sanish pcicfg_find_phdl(dev_info_t *dip)
166323c35297Sanish {
166423c35297Sanish pcicfg_phdl_t *entry;
166523c35297Sanish mutex_enter(&pcicfg_list_mutex);
166623c35297Sanish for (entry = pcicfg_phdl_list; entry != NULL; entry = entry->next) {
166723c35297Sanish if (entry->dip == dip) {
166823c35297Sanish mutex_exit(&pcicfg_list_mutex);
166923c35297Sanish return (entry);
167023c35297Sanish }
167123c35297Sanish }
167223c35297Sanish mutex_exit(&pcicfg_list_mutex);
167323c35297Sanish
167423c35297Sanish /*
167523c35297Sanish * Did'nt find entry - create one
167623c35297Sanish */
167723c35297Sanish return (pcicfg_create_phdl(dip));
167823c35297Sanish }
167923c35297Sanish
168023c35297Sanish static pcicfg_phdl_t *
pcicfg_create_phdl(dev_info_t * dip)168123c35297Sanish pcicfg_create_phdl(dev_info_t *dip)
168223c35297Sanish {
168323c35297Sanish pcicfg_phdl_t *new;
168423c35297Sanish
168526947304SEvan Yan new = (pcicfg_phdl_t *)kmem_zalloc(sizeof (pcicfg_phdl_t), KM_SLEEP);
168623c35297Sanish
168723c35297Sanish new->dip = dip;
168823c35297Sanish mutex_enter(&pcicfg_list_mutex);
168923c35297Sanish new->next = pcicfg_phdl_list;
169023c35297Sanish pcicfg_phdl_list = new;
169123c35297Sanish mutex_exit(&pcicfg_list_mutex);
169223c35297Sanish
169323c35297Sanish return (new);
169423c35297Sanish }
169523c35297Sanish
169623c35297Sanish static int
pcicfg_destroy_phdl(dev_info_t * dip)169723c35297Sanish pcicfg_destroy_phdl(dev_info_t *dip)
169823c35297Sanish {
169923c35297Sanish pcicfg_phdl_t *entry;
170023c35297Sanish pcicfg_phdl_t *follow = NULL;
170123c35297Sanish
170223c35297Sanish mutex_enter(&pcicfg_list_mutex);
170323c35297Sanish for (entry = pcicfg_phdl_list; entry != NULL; follow = entry,
170423c35297Sanish entry = entry->next) {
170523c35297Sanish if (entry->dip == dip) {
170623c35297Sanish if (entry == pcicfg_phdl_list) {
170723c35297Sanish pcicfg_phdl_list = entry->next;
170823c35297Sanish } else {
170923c35297Sanish follow->next = entry->next;
171023c35297Sanish }
171123c35297Sanish /*
171223c35297Sanish * If this entry has any allocated memory
171323c35297Sanish * or IO space associated with it, that
171423c35297Sanish * must be freed up.
171523c35297Sanish */
171623c35297Sanish if (entry->memory_len > 0) {
171723c35297Sanish (void) ndi_ra_free(ddi_get_parent(dip),
171826947304SEvan Yan entry->memory_base, entry->memory_len,
171923c35297Sanish NDI_RA_TYPE_MEM, NDI_RA_PASS);
172023c35297Sanish }
172123c35297Sanish pcicfg_free_hole(&entry->mem_hole);
172223c35297Sanish
172323c35297Sanish if (entry->io_len > 0) {
172423c35297Sanish (void) ndi_ra_free(ddi_get_parent(dip),
172526947304SEvan Yan entry->io_base, entry->io_len,
172623c35297Sanish NDI_RA_TYPE_IO, NDI_RA_PASS);
172723c35297Sanish }
172823c35297Sanish pcicfg_free_hole(&entry->io_hole);
172923c35297Sanish
173023c35297Sanish if (entry->pf_memory_len > 0) {
173123c35297Sanish (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);
173423c35297Sanish }
173523c35297Sanish pcicfg_free_hole(&entry->pf_mem_hole);
173623c35297Sanish
173723c35297Sanish /*
173823c35297Sanish * Destroy this entry
173923c35297Sanish */
174023c35297Sanish kmem_free((caddr_t)entry, sizeof (pcicfg_phdl_t));
174123c35297Sanish mutex_exit(&pcicfg_list_mutex);
174223c35297Sanish return (PCICFG_SUCCESS);
174323c35297Sanish }
174423c35297Sanish }
174523c35297Sanish mutex_exit(&pcicfg_list_mutex);
174623c35297Sanish /*
174723c35297Sanish * Did'nt find the entry
174823c35297Sanish */
174923c35297Sanish return (PCICFG_FAILURE);
175023c35297Sanish }
175123c35297Sanish
175223c35297Sanish static int
pcicfg_bridge_assign(dev_info_t * dip,void * hdl)175323c35297Sanish pcicfg_bridge_assign(dev_info_t *dip, void *hdl)
175423c35297Sanish {
175523c35297Sanish ddi_acc_handle_t handle;
175623c35297Sanish pci_regspec_t *reg;
175723c35297Sanish int length;
175823c35297Sanish int rcount;
175923c35297Sanish int i;
176023c35297Sanish int offset;
176123c35297Sanish uint64_t mem_answer;
176223c35297Sanish uint32_t io_answer;
176323c35297Sanish uint8_t header_type;
176423c35297Sanish ppb_ranges_t range[PCICFG_RANGE_LEN];
176523c35297Sanish int bus_range[2];
176623c35297Sanish uint64_t mem_residual;
176723c35297Sanish uint64_t pf_mem_residual;
176823c35297Sanish uint64_t io_residual;
176923c35297Sanish
177023c35297Sanish pcicfg_phdl_t *entry = (pcicfg_phdl_t *)hdl;
177123c35297Sanish
177226947304SEvan Yan DEBUG1("bridge assign: assigning addresses to %s\n", ddi_get_name(dip));
177323c35297Sanish
177423c35297Sanish entry->error = PCICFG_SUCCESS;
177523c35297Sanish
177623c35297Sanish if (entry == NULL) {
177723c35297Sanish DEBUG0("Failed to get entry\n");
177823c35297Sanish entry->error = PCICFG_FAILURE;
177923c35297Sanish return (DDI_WALK_TERMINATE);
178023c35297Sanish }
178123c35297Sanish
178226947304SEvan Yan if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
178323c35297Sanish DEBUG0("Failed to map config space!\n");
178423c35297Sanish entry->error = PCICFG_FAILURE;
178523c35297Sanish return (DDI_WALK_TERMINATE);
178623c35297Sanish }
178723c35297Sanish
178823c35297Sanish header_type = pci_config_get8(handle, PCI_CONF_HEADER);
178923c35297Sanish
179023c35297Sanish if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
179123c35297Sanish
179226947304SEvan Yan bzero((caddr_t)range, sizeof (ppb_ranges_t) * PCICFG_RANGE_LEN);
179323c35297Sanish
179423c35297Sanish (void) pcicfg_setup_bridge(entry, handle);
179523c35297Sanish
179623c35297Sanish range[0].child_high = range[0].parent_high |=
179723c35297Sanish (PCI_REG_REL_M | PCI_ADDR_IO);
179826947304SEvan Yan range[0].child_low = range[0].parent_low = entry->io_last;
179923c35297Sanish range[1].child_high = range[1].parent_high |=
180023c35297Sanish (PCI_REG_REL_M | PCI_ADDR_MEM32);
180123c35297Sanish range[1].child_low = range[1].parent_low =
180223c35297Sanish entry->memory_last;
180323c35297Sanish range[2].child_high = range[2].parent_high |=
180423c35297Sanish (PCI_REG_REL_M | PCI_ADDR_MEM32 | PCI_REG_PF_M);
180523c35297Sanish range[2].child_low = range[2].parent_low =
180623c35297Sanish entry->pf_memory_last;
180723c35297Sanish
18083fe80ca4SDan Cross ndi_devi_enter(dip);
180923c35297Sanish ddi_walk_devs(ddi_get_child(dip),
181023c35297Sanish pcicfg_bridge_assign, (void *)entry);
18113fe80ca4SDan Cross ndi_devi_exit(dip);
181223c35297Sanish
181323c35297Sanish (void) pcicfg_update_bridge(entry, handle);
181423c35297Sanish
181523c35297Sanish bus_range[0] = pci_config_get8(handle, PCI_BCNF_SECBUS);
181623c35297Sanish bus_range[1] = pci_config_get8(handle, PCI_BCNF_SUBBUS);
181723c35297Sanish
181823c35297Sanish if (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
181923c35297Sanish "bus-range", bus_range, 2) != DDI_SUCCESS) {
182023c35297Sanish DEBUG0("Failed to set bus-range property");
182123c35297Sanish entry->error = PCICFG_FAILURE;
18221fb5b786Sprasad (void) pcicfg_config_teardown(&handle);
182323c35297Sanish return (DDI_WALK_TERMINATE);
182423c35297Sanish }
182523c35297Sanish
182623c35297Sanish /*
182723c35297Sanish * Put back memory and I/O space not allocated
182823c35297Sanish * under the bridge.
182923c35297Sanish */
183023c35297Sanish mem_residual = entry->memory_len -
183123c35297Sanish (entry->memory_last - entry->memory_base);
183223c35297Sanish if (mem_residual > 0) {
183323c35297Sanish (void) ndi_ra_free(ddi_get_parent(dip),
183426947304SEvan Yan entry->memory_last, mem_residual,
183523c35297Sanish NDI_RA_TYPE_MEM, NDI_RA_PASS);
183623c35297Sanish }
183723c35297Sanish
183826947304SEvan Yan io_residual = entry->io_len - (entry->io_last - entry->io_base);
183923c35297Sanish 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);
184223c35297Sanish }
184323c35297Sanish
184423c35297Sanish pf_mem_residual = entry->pf_memory_len -
184523c35297Sanish (entry->pf_memory_last - entry->pf_memory_base);
184623c35297Sanish if (pf_mem_residual > 0) {
184723c35297Sanish (void) ndi_ra_free(ddi_get_parent(dip),
184826947304SEvan Yan entry->pf_memory_last, pf_mem_residual,
184923c35297Sanish NDI_RA_TYPE_PCI_PREFETCH_MEM, NDI_RA_PASS);
185023c35297Sanish }
185123c35297Sanish
185223c35297Sanish if (entry->io_len > 0) {
185323c35297Sanish range[0].size_low = entry->io_last - entry->io_base;
185423c35297Sanish if (pcicfg_update_ranges_prop(dip, &range[0])) {
185523c35297Sanish DEBUG0("Failed to update ranges (i/o)\n");
185623c35297Sanish entry->error = PCICFG_FAILURE;
18571fb5b786Sprasad (void) pcicfg_config_teardown(&handle);
185823c35297Sanish return (DDI_WALK_TERMINATE);
185923c35297Sanish }
186023c35297Sanish }
186123c35297Sanish if (entry->memory_len > 0) {
186223c35297Sanish range[1].size_low =
186323c35297Sanish entry->memory_last - entry->memory_base;
186423c35297Sanish if (pcicfg_update_ranges_prop(dip, &range[1])) {
186523c35297Sanish DEBUG0("Failed to update ranges (memory)\n");
186623c35297Sanish entry->error = PCICFG_FAILURE;
18671fb5b786Sprasad (void) pcicfg_config_teardown(&handle);
186823c35297Sanish return (DDI_WALK_TERMINATE);
186923c35297Sanish }
187023c35297Sanish }
187123c35297Sanish if (entry->pf_memory_len > 0) {
187223c35297Sanish range[2].size_low =
187323c35297Sanish entry->pf_memory_last - entry->pf_memory_base;
187423c35297Sanish if (pcicfg_update_ranges_prop(dip, &range[2])) {
187523c35297Sanish DEBUG0("Failed to update ranges (PF memory)\n");
187623c35297Sanish entry->error = PCICFG_FAILURE;
18771fb5b786Sprasad (void) pcicfg_config_teardown(&handle);
187823c35297Sanish return (DDI_WALK_TERMINATE);
187923c35297Sanish }
188023c35297Sanish }
188123c35297Sanish
188223c35297Sanish (void) pcicfg_device_on(handle);
188323c35297Sanish
188423c35297Sanish PCICFG_DUMP_BRIDGE_CONFIG(handle);
188523c35297Sanish
18861fb5b786Sprasad (void) pcicfg_config_teardown(&handle);
18871fb5b786Sprasad
188823c35297Sanish return (DDI_WALK_PRUNECHILD);
188923c35297Sanish }
189023c35297Sanish
189123c35297Sanish /*
189223c35297Sanish * If there is an interrupt pin set program
189323c35297Sanish * interrupt line with default values.
189423c35297Sanish */
189523c35297Sanish if (pci_config_get8(handle, PCI_CONF_IPIN)) {
189623c35297Sanish pci_config_put8(handle, PCI_CONF_ILINE, 0xf);
189723c35297Sanish }
189823c35297Sanish
189923c35297Sanish /*
190023c35297Sanish * A single device (under a bridge).
190123c35297Sanish * For each "reg" property with a length, allocate memory
190223c35297Sanish * and program the base registers.
190323c35297Sanish */
190426947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg",
190526947304SEvan Yan (caddr_t)®, &length) != DDI_PROP_SUCCESS) {
190623c35297Sanish DEBUG0("Failed to read reg property\n");
190723c35297Sanish entry->error = PCICFG_FAILURE;
19081fb5b786Sprasad (void) pcicfg_config_teardown(&handle);
190923c35297Sanish return (DDI_WALK_TERMINATE);
191023c35297Sanish }
191123c35297Sanish
191223c35297Sanish rcount = length / sizeof (pci_regspec_t);
191323c35297Sanish offset = PCI_CONF_BASE0;
191423c35297Sanish for (i = 0; i < rcount; i++) {
191526947304SEvan Yan if ((reg[i].pci_size_low != 0) || (reg[i].pci_size_hi != 0)) {
191623c35297Sanish
191723c35297Sanish offset = PCI_REG_REG_G(reg[i].pci_phys_hi);
191823c35297Sanish
191923c35297Sanish switch (PCI_REG_ADDR_G(reg[i].pci_phys_hi)) {
192023c35297Sanish case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
192123c35297Sanish
192223c35297Sanish if (reg[i].pci_phys_hi & PCI_REG_PF_M) {
192323c35297Sanish /* allocate prefetchable memory */
192423c35297Sanish pcicfg_get_pf_mem(entry,
192523c35297Sanish reg[i].pci_size_low, &mem_answer);
192623c35297Sanish } else { /* get non prefetchable memory */
192723c35297Sanish pcicfg_get_mem(entry,
192823c35297Sanish reg[i].pci_size_low, &mem_answer);
192923c35297Sanish }
193023c35297Sanish pci_config_put64(handle, offset, mem_answer);
193123c35297Sanish DEBUG2("REGISTER off %x (64)LO ----> [0x%x]\n",
193226947304SEvan Yan offset, pci_config_get32(handle, offset));
193323c35297Sanish DEBUG2("REGISTER off %x (64)HI ----> [0x%x]\n",
193423c35297Sanish offset + 4,
193523c35297Sanish pci_config_get32(handle, offset + 4));
193623c35297Sanish
193723c35297Sanish reg[i].pci_phys_hi |= PCI_REG_REL_M;
193823c35297Sanish reg[i].pci_phys_low = PCICFG_LOADDR(mem_answer);
193926947304SEvan Yan reg[i].pci_phys_mid = PCICFG_HIADDR(mem_answer);
194023c35297Sanish break;
194123c35297Sanish
194223c35297Sanish case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
194323c35297Sanish if (reg[i].pci_phys_hi & PCI_REG_PF_M) {
194423c35297Sanish /* allocate prefetchable memory */
194523c35297Sanish pcicfg_get_pf_mem(entry,
194623c35297Sanish reg[i].pci_size_low, &mem_answer);
194723c35297Sanish } else {
194823c35297Sanish /* get non prefetchable memory */
194923c35297Sanish pcicfg_get_mem(entry,
195023c35297Sanish reg[i].pci_size_low, &mem_answer);
195123c35297Sanish }
195223c35297Sanish
195326947304SEvan Yan pci_config_put32(handle, offset,
195426947304SEvan Yan (uint32_t)mem_answer);
195523c35297Sanish
195623c35297Sanish DEBUG2("REGISTER off %x(32)LO ----> [0x%x]\n",
195726947304SEvan Yan offset, pci_config_get32(handle, offset));
195823c35297Sanish
195923c35297Sanish reg[i].pci_phys_hi |= PCI_REG_REL_M;
196023c35297Sanish reg[i].pci_phys_low = (uint32_t)mem_answer;
196123c35297Sanish
196223c35297Sanish break;
196323c35297Sanish case PCI_REG_ADDR_G(PCI_ADDR_IO):
196423c35297Sanish /* allocate I/O space from the allocator */
196523c35297Sanish
196626947304SEvan Yan (void) pcicfg_get_io(entry, reg[i].pci_size_low,
196726947304SEvan Yan &io_answer);
196823c35297Sanish pci_config_put32(handle, offset, io_answer);
196923c35297Sanish
197023c35297Sanish DEBUG2("REGISTER off %x (I/O)LO ----> [0x%x]\n",
197126947304SEvan Yan offset, pci_config_get32(handle, offset));
197223c35297Sanish
197323c35297Sanish reg[i].pci_phys_hi |= PCI_REG_REL_M;
197423c35297Sanish reg[i].pci_phys_low = io_answer;
197523c35297Sanish
197623c35297Sanish break;
197723c35297Sanish default:
197823c35297Sanish DEBUG0("Unknown register type\n");
197923c35297Sanish kmem_free(reg, length);
198023c35297Sanish (void) pcicfg_config_teardown(&handle);
198123c35297Sanish entry->error = PCICFG_FAILURE;
198223c35297Sanish return (DDI_WALK_TERMINATE);
198323c35297Sanish } /* switch */
198423c35297Sanish
198523c35297Sanish /*
198623c35297Sanish * Now that memory locations are assigned,
198723c35297Sanish * update the assigned address property.
198823c35297Sanish */
198926947304SEvan Yan if (pcicfg_update_assigned_prop(dip, ®[i])
199026947304SEvan Yan != PCICFG_SUCCESS) {
199123c35297Sanish kmem_free(reg, length);
199223c35297Sanish (void) pcicfg_config_teardown(&handle);
199323c35297Sanish entry->error = PCICFG_FAILURE;
199423c35297Sanish return (DDI_WALK_TERMINATE);
199523c35297Sanish }
199623c35297Sanish }
199723c35297Sanish }
199823c35297Sanish (void) pcicfg_device_on(handle);
199923c35297Sanish
200023c35297Sanish PCICFG_DUMP_DEVICE_CONFIG(handle);
200123c35297Sanish
200223c35297Sanish (void) pcicfg_config_teardown(&handle);
200323c35297Sanish kmem_free((caddr_t)reg, length);
200423c35297Sanish return (DDI_WALK_CONTINUE);
200523c35297Sanish }
200623c35297Sanish
200723c35297Sanish static int
pcicfg_device_assign(dev_info_t * dip)200823c35297Sanish pcicfg_device_assign(dev_info_t *dip)
200923c35297Sanish {
201023c35297Sanish ddi_acc_handle_t handle;
201123c35297Sanish pci_regspec_t *reg;
201223c35297Sanish int length;
201323c35297Sanish int rcount;
201423c35297Sanish int i;
201523c35297Sanish int offset;
201623c35297Sanish ndi_ra_request_t request;
201723c35297Sanish uint64_t answer;
201823c35297Sanish uint64_t alen;
201923c35297Sanish
202023c35297Sanish DEBUG1("%llx now under configuration\n", dip);
202123c35297Sanish
202223c35297Sanish /* request.ra_len = PCICFG_ROUND_UP(request.ra_len, PCICFG_IOGRAN); */
202323c35297Sanish if (pcicfg_ntbridge_child(dip) == DDI_SUCCESS) {
202423c35297Sanish
202523c35297Sanish return (pcicfg_ntbridge_program_child(dip));
202623c35297Sanish }
202723c35297Sanish /*
202823c35297Sanish * XXX Failure here should be noted
202923c35297Sanish */
203026947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg",
203126947304SEvan Yan (caddr_t)®, &length) != DDI_PROP_SUCCESS) {
203223c35297Sanish DEBUG0("Failed to read reg property\n");
203323c35297Sanish return (PCICFG_FAILURE);
203423c35297Sanish }
203523c35297Sanish
203623c35297Sanish if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
203723c35297Sanish DEBUG0("Failed to map config space!\n");
20381fb5b786Sprasad kmem_free(reg, length);
203923c35297Sanish return (PCICFG_FAILURE);
204023c35297Sanish }
204123c35297Sanish
204223c35297Sanish /*
204323c35297Sanish * A single device
204423c35297Sanish *
204523c35297Sanish * For each "reg" property with a length, allocate memory
204623c35297Sanish * and program the base registers.
204723c35297Sanish */
204823c35297Sanish
204923c35297Sanish /*
205023c35297Sanish * If there is an interrupt pin set program
205123c35297Sanish * interrupt line with default values.
205223c35297Sanish */
205323c35297Sanish if (pci_config_get8(handle, PCI_CONF_IPIN)) {
205423c35297Sanish pci_config_put8(handle, PCI_CONF_ILINE, 0xf);
205523c35297Sanish }
205623c35297Sanish
205723c35297Sanish bzero((caddr_t)&request, sizeof (ndi_ra_request_t));
205823c35297Sanish
205923c35297Sanish /*
206023c35297Sanish * Note: Both non-prefetchable and prefetchable memory space
206123c35297Sanish * allocations are made within 32bit space. Currently, BIOSs
206223c35297Sanish * allocate device memory for PCI devices within the 32bit space
206323c35297Sanish * so this will not be a problem.
206423c35297Sanish */
206523c35297Sanish request.ra_flags |= NDI_RA_ALIGN_SIZE | NDI_RA_ALLOC_BOUNDED;
206623c35297Sanish request.ra_boundbase = 0;
206723c35297Sanish request.ra_boundlen = PCICFG_4GIG_LIMIT;
206823c35297Sanish
206923c35297Sanish rcount = length / sizeof (pci_regspec_t);
207023c35297Sanish offset = PCI_CONF_BASE0;
207123c35297Sanish for (i = 0; i < rcount; i++) {
207223c35297Sanish char *mem_type;
207323c35297Sanish
207426947304SEvan Yan if ((reg[i].pci_size_low != 0)|| (reg[i].pci_size_hi != 0)) {
207523c35297Sanish
207623c35297Sanish offset = PCI_REG_REG_G(reg[i].pci_phys_hi);
207723c35297Sanish request.ra_len = reg[i].pci_size_low;
207823c35297Sanish
207923c35297Sanish switch (PCI_REG_ADDR_G(reg[i].pci_phys_hi)) {
208023c35297Sanish case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
208123c35297Sanish if (reg[i].pci_phys_hi & PCI_REG_PF_M) {
208223c35297Sanish mem_type = NDI_RA_TYPE_PCI_PREFETCH_MEM;
208323c35297Sanish } else {
208423c35297Sanish mem_type = NDI_RA_TYPE_MEM;
208523c35297Sanish }
208623c35297Sanish /* 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) {
209023c35297Sanish DEBUG0("Failed to allocate 64b mem\n");
209123c35297Sanish kmem_free(reg, length);
209223c35297Sanish (void) pcicfg_config_teardown(&handle);
20935af4ae46Sjveta return (PCICFG_NORESRC);
209423c35297Sanish }
209523c35297Sanish DEBUG3("64 addr = [0x%x.0x%x] len [0x%x]\n",
209623c35297Sanish PCICFG_HIADDR(answer),
209726947304SEvan Yan PCICFG_LOADDR(answer), alen);
209823c35297Sanish /* program the low word */
209926947304SEvan Yan pci_config_put32(handle, offset,
210026947304SEvan Yan PCICFG_LOADDR(answer));
210123c35297Sanish /* program the high word */
210223c35297Sanish pci_config_put32(handle, offset + 4,
210323c35297Sanish PCICFG_HIADDR(answer));
210423c35297Sanish
210523c35297Sanish reg[i].pci_phys_hi |= PCI_REG_REL_M;
210623c35297Sanish reg[i].pci_phys_low = PCICFG_LOADDR(answer);
210723c35297Sanish reg[i].pci_phys_mid = PCICFG_HIADDR(answer);
210823c35297Sanish /*
210923c35297Sanish * currently support 32b address space
211023c35297Sanish * assignments only.
211123c35297Sanish */
211226947304SEvan Yan reg[i].pci_phys_hi ^=
211326947304SEvan Yan PCI_ADDR_MEM64 ^ PCI_ADDR_MEM32;
211423c35297Sanish
211523c35297Sanish offset += 8;
211623c35297Sanish break;
211723c35297Sanish
211823c35297Sanish case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
211923c35297Sanish if (reg[i].pci_phys_hi & PCI_REG_PF_M)
212023c35297Sanish mem_type = NDI_RA_TYPE_PCI_PREFETCH_MEM;
212123c35297Sanish else
212223c35297Sanish mem_type = NDI_RA_TYPE_MEM;
212323c35297Sanish /* 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) {
212723c35297Sanish DEBUG0("Failed to allocate 32b mem\n");
212823c35297Sanish kmem_free(reg, length);
212923c35297Sanish (void) pcicfg_config_teardown(&handle);
21305af4ae46Sjveta return (PCICFG_NORESRC);
213123c35297Sanish }
213223c35297Sanish DEBUG3("32 addr = [0x%x.0x%x] len [0x%x]\n",
213323c35297Sanish PCICFG_HIADDR(answer),
213423c35297Sanish PCICFG_LOADDR(answer),
213523c35297Sanish alen);
213623c35297Sanish /* program the low word */
213726947304SEvan Yan pci_config_put32(handle, offset,
213826947304SEvan Yan PCICFG_LOADDR(answer));
213923c35297Sanish
214023c35297Sanish reg[i].pci_phys_hi |= PCI_REG_REL_M;
214123c35297Sanish reg[i].pci_phys_low = PCICFG_LOADDR(answer);
214223c35297Sanish reg[i].pci_phys_mid = 0;
214323c35297Sanish
214423c35297Sanish offset += 4;
214523c35297Sanish break;
214623c35297Sanish 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)
215723c35297Sanish != NDI_SUCCESS) {
215823c35297Sanish DEBUG0("Failed to allocate I/O\n");
2159b9abf428Slipeng sang - Sun Microsystems - Beijing China continue;
216023c35297Sanish }
216123c35297Sanish DEBUG3("I/O addr = [0x%x.0x%x] len [0x%x]\n",
216223c35297Sanish PCICFG_HIADDR(answer),
216326947304SEvan Yan PCICFG_LOADDR(answer), alen);
216426947304SEvan Yan pci_config_put32(handle, offset,
216526947304SEvan Yan PCICFG_LOADDR(answer));
216623c35297Sanish
216723c35297Sanish reg[i].pci_phys_hi |= PCI_REG_REL_M;
216823c35297Sanish reg[i].pci_phys_low = PCICFG_LOADDR(answer);
216923c35297Sanish
217023c35297Sanish offset += 4;
217123c35297Sanish break;
217223c35297Sanish default:
217323c35297Sanish DEBUG0("Unknown register type\n");
217423c35297Sanish kmem_free(reg, length);
217523c35297Sanish (void) pcicfg_config_teardown(&handle);
217623c35297Sanish return (PCICFG_FAILURE);
217723c35297Sanish } /* switch */
217823c35297Sanish
217923c35297Sanish /*
218023c35297Sanish * Now that memory locations are assigned,
218123c35297Sanish * update the assigned address property.
218223c35297Sanish */
218323c35297Sanish
218426947304SEvan Yan if (pcicfg_update_assigned_prop(dip, ®[i])
218526947304SEvan Yan != PCICFG_SUCCESS) {
218623c35297Sanish kmem_free(reg, length);
218723c35297Sanish (void) pcicfg_config_teardown(&handle);
218823c35297Sanish return (PCICFG_FAILURE);
218923c35297Sanish }
219023c35297Sanish }
219123c35297Sanish }
219223c35297Sanish
219323c35297Sanish (void) pcicfg_device_on(handle);
219423c35297Sanish kmem_free(reg, length);
219523c35297Sanish
219623c35297Sanish PCICFG_DUMP_DEVICE_CONFIG(handle);
219723c35297Sanish
219823c35297Sanish (void) pcicfg_config_teardown(&handle);
219923c35297Sanish return (PCICFG_SUCCESS);
220023c35297Sanish }
220123c35297Sanish
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
233423c35297Sanish #ifdef DEBUG
233523c35297Sanish /*
233623c35297Sanish * This function is useful in debug mode, where we can measure how
233723c35297Sanish * much memory was wasted/unallocated in bridge device's domain.
233823c35297Sanish */
233923c35297Sanish static uint64_t
pcicfg_unused_space(hole_t * hole,uint32_t * hole_count)234023c35297Sanish pcicfg_unused_space(hole_t *hole, uint32_t *hole_count)
234123c35297Sanish {
234223c35297Sanish uint64_t len = 0;
234323c35297Sanish uint32_t count = 0;
234423c35297Sanish
234523c35297Sanish do {
234623c35297Sanish len += hole->len;
234723c35297Sanish hole = hole->next;
234823c35297Sanish count++;
234923c35297Sanish } while (hole);
235023c35297Sanish *hole_count = count;
235123c35297Sanish return (len);
235223c35297Sanish }
235323c35297Sanish #endif
235423c35297Sanish
235523c35297Sanish /*
235623c35297Sanish * This function frees data structures that hold the hole information
235723c35297Sanish * which are allocated in pcicfg_alloc_hole(). This is not freeing
235823c35297Sanish * any memory allocated through NDI calls.
235923c35297Sanish */
236023c35297Sanish static void
pcicfg_free_hole(hole_t * addr_hole)236123c35297Sanish pcicfg_free_hole(hole_t *addr_hole)
236223c35297Sanish {
236323c35297Sanish hole_t *nhole, *hole = addr_hole->next;
236423c35297Sanish
236523c35297Sanish while (hole) {
236623c35297Sanish nhole = hole->next;
236723c35297Sanish kmem_free(hole, sizeof (hole_t));
236823c35297Sanish hole = nhole;
236923c35297Sanish }
237023c35297Sanish }
237123c35297Sanish
237223c35297Sanish static uint64_t
pcicfg_alloc_hole(hole_t * addr_hole,uint64_t * alast,uint32_t length)237323c35297Sanish pcicfg_alloc_hole(hole_t *addr_hole, uint64_t *alast, uint32_t length)
237423c35297Sanish {
237523c35297Sanish uint64_t actual_hole_start, ostart, olen;
237623c35297Sanish hole_t *hole = addr_hole, *thole, *nhole;
237723c35297Sanish
237823c35297Sanish do {
237923c35297Sanish actual_hole_start = PCICFG_ROUND_UP(hole->start, length);
238023c35297Sanish if (((actual_hole_start - hole->start) + length) <= hole->len) {
238123c35297Sanish DEBUG3("hole found. start %llx, len %llx, req=0x%x\n",
238223c35297Sanish hole->start, hole->len, length);
238323c35297Sanish ostart = hole->start;
238423c35297Sanish olen = hole->len;
238523c35297Sanish /* current hole parameters adjust */
238623c35297Sanish if ((actual_hole_start - hole->start) == 0) {
238723c35297Sanish hole->start += length;
238823c35297Sanish hole->len -= length;
238923c35297Sanish if (hole->start > *alast)
239023c35297Sanish *alast = hole->start;
239123c35297Sanish } else {
239223c35297Sanish hole->len = actual_hole_start - hole->start;
239323c35297Sanish nhole = (hole_t *)kmem_zalloc(sizeof (hole_t),
239423c35297Sanish KM_SLEEP);
239523c35297Sanish nhole->start = actual_hole_start + length;
239623c35297Sanish nhole->len = (ostart + olen) - nhole->start;
239723c35297Sanish nhole->next = NULL;
239823c35297Sanish thole = hole->next;
239923c35297Sanish hole->next = nhole;
240023c35297Sanish nhole->next = thole;
240123c35297Sanish if (nhole->start > *alast)
240223c35297Sanish *alast = nhole->start;
240323c35297Sanish DEBUG2("put new hole to %llx, %llx\n",
240423c35297Sanish nhole->start, nhole->len);
240523c35297Sanish }
240623c35297Sanish DEBUG2("adjust current hole to %llx, %llx\n",
240723c35297Sanish hole->start, hole->len);
240823c35297Sanish break;
240923c35297Sanish }
241023c35297Sanish actual_hole_start = 0;
241123c35297Sanish hole = hole->next;
241223c35297Sanish } while (hole);
241323c35297Sanish
241423c35297Sanish DEBUG1("return hole at %llx\n", actual_hole_start);
241523c35297Sanish return (actual_hole_start);
241623c35297Sanish }
241723c35297Sanish
241823c35297Sanish 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)
242023c35297Sanish {
242123c35297Sanish uint64_t new_mem;
242223c35297Sanish
242323c35297Sanish /* See if there is a hole, that can hold this request. */
242423c35297Sanish new_mem = pcicfg_alloc_hole(&entry->mem_hole, &entry->memory_last,
242523c35297Sanish length);
242623c35297Sanish if (new_mem) { /* if non-zero, found a hole. */
242723c35297Sanish if (ans != NULL)
242823c35297Sanish *ans = new_mem;
242923c35297Sanish } else
243023c35297Sanish cmn_err(CE_WARN, "No %u bytes memory window for %s\n",
243123c35297Sanish length, ddi_get_name(entry->dip));
243223c35297Sanish }
243323c35297Sanish
243423c35297Sanish 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)
243623c35297Sanish {
243723c35297Sanish uint32_t new_io;
243823c35297Sanish uint64_t io_last;
243923c35297Sanish
244023c35297Sanish /*
244123c35297Sanish * See if there is a hole, that can hold this request.
244223c35297Sanish * Pass 64 bit parameters and then truncate to 32 bit.
244323c35297Sanish */
244423c35297Sanish io_last = entry->io_last;
244523c35297Sanish new_io = (uint32_t)pcicfg_alloc_hole(&entry->io_hole, &io_last, length);
244623c35297Sanish if (new_io) { /* if non-zero, found a hole. */
244723c35297Sanish entry->io_last = (uint32_t)io_last;
244823c35297Sanish if (ans != NULL)
244923c35297Sanish *ans = new_io;
245023c35297Sanish } else
245123c35297Sanish cmn_err(CE_WARN, "No %u bytes IO space window for %s\n",
245223c35297Sanish length, ddi_get_name(entry->dip));
245323c35297Sanish }
245423c35297Sanish
245523c35297Sanish 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)
245723c35297Sanish {
245823c35297Sanish uint64_t new_mem;
245923c35297Sanish
246023c35297Sanish /* See if there is a hole, that can hold this request. */
246123c35297Sanish new_mem = pcicfg_alloc_hole(&entry->pf_mem_hole, &entry->pf_memory_last,
246223c35297Sanish length);
246323c35297Sanish if (new_mem) { /* if non-zero, found a hole. */
246423c35297Sanish if (ans != NULL)
246523c35297Sanish *ans = new_mem;
246623c35297Sanish } else
246723c35297Sanish cmn_err(CE_WARN, "No %u bytes PF memory window for %s\n",
246823c35297Sanish length, ddi_get_name(entry->dip));
246923c35297Sanish }
247023c35297Sanish
2471ae5a8bedSAndy Fiddaman #ifdef __sparc
247223c35297Sanish static int
pcicfg_sum_resources(dev_info_t * dip,void * hdl)247323c35297Sanish pcicfg_sum_resources(dev_info_t *dip, void *hdl)
247423c35297Sanish {
247523c35297Sanish pcicfg_phdl_t *entry = (pcicfg_phdl_t *)hdl;
247623c35297Sanish pci_regspec_t *pci_rp;
247723c35297Sanish int length;
247823c35297Sanish int rcount;
247923c35297Sanish int i;
248023c35297Sanish ndi_ra_request_t *pf_mem_request;
248123c35297Sanish ndi_ra_request_t *mem_request;
248223c35297Sanish ndi_ra_request_t *io_request;
248323c35297Sanish uint8_t header_type;
248423c35297Sanish ddi_acc_handle_t handle;
248523c35297Sanish
248623c35297Sanish entry->error = PCICFG_SUCCESS;
248723c35297Sanish
248823c35297Sanish pf_mem_request = &entry->pf_mem_req;
248923c35297Sanish mem_request = &entry->mem_req;
249023c35297Sanish io_request = &entry->io_req;
249123c35297Sanish
249223c35297Sanish if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
249323c35297Sanish DEBUG0("Failed to map config space!\n");
249423c35297Sanish entry->error = PCICFG_FAILURE;
249523c35297Sanish return (DDI_WALK_TERMINATE);
249623c35297Sanish }
249723c35297Sanish
249823c35297Sanish header_type = pci_config_get8(handle, PCI_CONF_HEADER);
249923c35297Sanish
250023c35297Sanish /*
250123c35297Sanish * If its a bridge - just record the highest bus seen
250223c35297Sanish */
250323c35297Sanish if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
250423c35297Sanish
250523c35297Sanish if (entry->highest_bus < pci_config_get8(handle,
250623c35297Sanish PCI_BCNF_SECBUS)) {
250723c35297Sanish entry->highest_bus =
250823c35297Sanish pci_config_get8(handle, PCI_BCNF_SECBUS);
250923c35297Sanish }
251023c35297Sanish (void) pcicfg_config_teardown(&handle);
251123c35297Sanish entry->error = PCICFG_FAILURE;
251223c35297Sanish return (DDI_WALK_CONTINUE);
251323c35297Sanish } 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) {
251623c35297Sanish /*
251723c35297Sanish * If one node in (the subtree of nodes)
251823c35297Sanish * doesn't have a "reg" property fail the
251923c35297Sanish * allocation.
252023c35297Sanish */
252123c35297Sanish entry->memory_len = 0;
252223c35297Sanish entry->io_len = 0;
252323c35297Sanish entry->pf_memory_len = 0;
252423c35297Sanish entry->error = PCICFG_FAILURE;
25251fb5b786Sprasad (void) pcicfg_config_teardown(&handle);
252623c35297Sanish return (DDI_WALK_TERMINATE);
252723c35297Sanish }
252823c35297Sanish /*
252923c35297Sanish * For each "reg" property with a length, add that to the
253023c35297Sanish * total memory (or I/O) to allocate.
253123c35297Sanish */
253223c35297Sanish rcount = length / sizeof (pci_regspec_t);
253323c35297Sanish
253423c35297Sanish for (i = 0; i < rcount; i++) {
253523c35297Sanish
253623c35297Sanish switch (PCI_REG_ADDR_G(pci_rp[i].pci_phys_hi)) {
253723c35297Sanish
253823c35297Sanish case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
253923c35297Sanish if (pci_rp[i].pci_phys_hi & PCI_REG_PF_M) {
254023c35297Sanish pf_mem_request->ra_len =
254123c35297Sanish pci_rp[i].pci_size_low +
254226947304SEvan Yan PCICFG_ROUND_UP(
254326947304SEvan Yan pf_mem_request->ra_len,
254423c35297Sanish pci_rp[i].pci_size_low);
254523c35297Sanish DEBUG1("ADDING 32 --->0x%x\n",
254623c35297Sanish pci_rp[i].pci_size_low);
254723c35297Sanish } else {
254823c35297Sanish mem_request->ra_len =
254923c35297Sanish pci_rp[i].pci_size_low +
255023c35297Sanish PCICFG_ROUND_UP(mem_request->ra_len,
255123c35297Sanish pci_rp[i].pci_size_low);
255223c35297Sanish DEBUG1("ADDING 32 --->0x%x\n",
255323c35297Sanish pci_rp[i].pci_size_low);
255423c35297Sanish }
255523c35297Sanish
255623c35297Sanish break;
255723c35297Sanish case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
255823c35297Sanish if (pci_rp[i].pci_phys_hi & PCI_REG_PF_M) {
255923c35297Sanish pf_mem_request->ra_len =
256023c35297Sanish pci_rp[i].pci_size_low +
256126947304SEvan Yan PCICFG_ROUND_UP(
256226947304SEvan Yan pf_mem_request->ra_len,
256323c35297Sanish pci_rp[i].pci_size_low);
256423c35297Sanish DEBUG1("ADDING 64 --->0x%x\n",
256523c35297Sanish pci_rp[i].pci_size_low);
256623c35297Sanish } else {
256723c35297Sanish mem_request->ra_len =
256823c35297Sanish pci_rp[i].pci_size_low +
256923c35297Sanish PCICFG_ROUND_UP(mem_request->ra_len,
257023c35297Sanish pci_rp[i].pci_size_low);
257123c35297Sanish DEBUG1("ADDING 64 --->0x%x\n",
257223c35297Sanish pci_rp[i].pci_size_low);
257323c35297Sanish }
257423c35297Sanish
257523c35297Sanish break;
257623c35297Sanish case PCI_REG_ADDR_G(PCI_ADDR_IO):
257723c35297Sanish io_request->ra_len =
257823c35297Sanish pci_rp[i].pci_size_low +
257923c35297Sanish PCICFG_ROUND_UP(io_request->ra_len,
258023c35297Sanish pci_rp[i].pci_size_low);
258123c35297Sanish DEBUG1("ADDING I/O --->0x%x\n",
258223c35297Sanish pci_rp[i].pci_size_low);
258323c35297Sanish break;
258423c35297Sanish default:
258523c35297Sanish /* Config space register - not included */
258623c35297Sanish break;
258723c35297Sanish }
258823c35297Sanish }
258923c35297Sanish
259023c35297Sanish /*
259123c35297Sanish * free the memory allocated by ddi_getlongprop
259223c35297Sanish */
259323c35297Sanish kmem_free(pci_rp, length);
259423c35297Sanish
259523c35297Sanish /*
259623c35297Sanish * continue the walk to the next sibling to sum memory
259723c35297Sanish */
259823c35297Sanish
259923c35297Sanish (void) pcicfg_config_teardown(&handle);
260023c35297Sanish
260123c35297Sanish return (DDI_WALK_CONTINUE);
260223c35297Sanish }
260323c35297Sanish }
2604ae5a8bedSAndy Fiddaman #endif /* __sparc */
260523c35297Sanish
260623c35297Sanish static int
pcicfg_free_bridge_resources(dev_info_t * dip)260723c35297Sanish pcicfg_free_bridge_resources(dev_info_t *dip)
260823c35297Sanish {
260923c35297Sanish ppb_ranges_t *ranges;
261023c35297Sanish uint_t *bus;
261123c35297Sanish int k;
26121fb5b786Sprasad int length = 0;
261323c35297Sanish int i;
261423c35297Sanish
261523c35297Sanish
261626947304SEvan Yan if ((i = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
261726947304SEvan Yan "ranges", (caddr_t)&ranges, &length)) != DDI_PROP_SUCCESS) {
261823c35297Sanish DEBUG0("Failed to read ranges property\n");
261923c35297Sanish if (ddi_get_child(dip)) {
262023c35297Sanish cmn_err(CE_WARN, "No ranges property found for %s",
262123c35297Sanish ddi_get_name(dip));
262223c35297Sanish /*
262323c35297Sanish * strictly speaking, we can check for children with
262423c35297Sanish * assigned-addresses but for now it is better to
262523c35297Sanish * be conservative and assume that if there are child
262623c35297Sanish * nodes, then they do consume PCI memory or IO
262723c35297Sanish * resources, Hence return failure.
262823c35297Sanish */
262923c35297Sanish return (PCICFG_FAILURE);
263023c35297Sanish }
263123c35297Sanish length = 0;
263223c35297Sanish }
263323c35297Sanish
263423c35297Sanish for (i = 0; i < length / sizeof (ppb_ranges_t); i++) {
263523c35297Sanish char *mem_type;
263623c35297Sanish
263726947304SEvan Yan if (ranges[i].size_low != 0 || ranges[i].size_high != 0) {
263823c35297Sanish switch (ranges[i].parent_high & PCI_REG_ADDR_M) {
263923c35297Sanish case PCI_ADDR_IO:
264026947304SEvan Yan DEBUG2("Free I/O base/length = "
264126947304SEvan Yan "[0x%x]/[0x%x]\n", ranges[i].child_low,
264223c35297Sanish ranges[i].size_low);
264323c35297Sanish if (ndi_ra_free(ddi_get_parent(dip),
264423c35297Sanish (uint64_t)ranges[i].child_low,
264523c35297Sanish (uint64_t)ranges[i].size_low,
264623c35297Sanish NDI_RA_TYPE_IO, NDI_RA_PASS)
264723c35297Sanish != NDI_SUCCESS) {
264823c35297Sanish DEBUG0("Trouble freeing "
264923c35297Sanish "PCI i/o space\n");
265023c35297Sanish kmem_free(ranges, length);
265123c35297Sanish return (PCICFG_FAILURE);
265223c35297Sanish }
265323c35297Sanish break;
265423c35297Sanish case PCI_ADDR_MEM32:
265523c35297Sanish case PCI_ADDR_MEM64:
265623c35297Sanish 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",
265923c35297Sanish ranges[i].child_mid,
266023c35297Sanish ranges[i].child_low,
266126947304SEvan Yan ranges[i].size_low);
266223c35297Sanish mem_type = NDI_RA_TYPE_PCI_PREFETCH_MEM;
266323c35297Sanish } else {
266423c35297Sanish DEBUG3("Free Memory base/length"
266523c35297Sanish " = [0x%x.0x%x]/[0x%x]\n",
266623c35297Sanish ranges[i].child_mid,
266723c35297Sanish ranges[i].child_low,
266823c35297Sanish ranges[i].size_low)
266923c35297Sanish mem_type = NDI_RA_TYPE_MEM;
267023c35297Sanish }
267123c35297Sanish if (ndi_ra_free(ddi_get_parent(dip),
267226947304SEvan Yan PCICFG_LADDR(ranges[i].child_low,
267323c35297Sanish ranges[i].child_mid),
267423c35297Sanish (uint64_t)ranges[i].size_low,
267526947304SEvan Yan mem_type, NDI_RA_PASS) != NDI_SUCCESS) {
267623c35297Sanish DEBUG0("Trouble freeing "
267723c35297Sanish "PCI memory space\n");
267823c35297Sanish kmem_free(ranges, length);
267923c35297Sanish return (PCICFG_FAILURE);
268023c35297Sanish }
268123c35297Sanish break;
268223c35297Sanish default:
268323c35297Sanish DEBUG0("Unknown memory space\n");
268423c35297Sanish break;
268523c35297Sanish }
268623c35297Sanish }
268723c35297Sanish }
268823c35297Sanish
268923c35297Sanish if (length)
269023c35297Sanish kmem_free(ranges, length);
269123c35297Sanish
269226947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
269326947304SEvan Yan "bus-range", (caddr_t)&bus, &k) != DDI_PROP_SUCCESS) {
269423c35297Sanish DEBUG0("Failed to read bus-range property\n");
269523c35297Sanish return (PCICFG_FAILURE);
269623c35297Sanish }
269723c35297Sanish
269823c35297Sanish DEBUG2("Need to free bus [%d] range [%d]\n",
269923c35297Sanish bus[0], bus[1] - bus[0] + 1);
270023c35297Sanish
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) {
270423c35297Sanish DEBUG0("Failed to free a bus number\n");
27051fb5b786Sprasad kmem_free(bus, k);
270623c35297Sanish return (PCICFG_FAILURE);
270723c35297Sanish }
27081fb5b786Sprasad
27091fb5b786Sprasad kmem_free(bus, k);
271023c35297Sanish return (PCICFG_SUCCESS);
271123c35297Sanish }
271223c35297Sanish
271323c35297Sanish static int
pcicfg_free_device_resources(dev_info_t * dip)271423c35297Sanish pcicfg_free_device_resources(dev_info_t *dip)
271523c35297Sanish {
271623c35297Sanish pci_regspec_t *assigned;
271723c35297Sanish
271823c35297Sanish int length;
271923c35297Sanish int acount;
272023c35297Sanish int i;
272123c35297Sanish
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) {
272523c35297Sanish DEBUG0("Failed to read assigned-addresses property\n");
272623c35297Sanish return (PCICFG_FAILURE);
272723c35297Sanish }
272823c35297Sanish
272923c35297Sanish /*
273023c35297Sanish * For each "assigned-addresses" property entry with a length,
273123c35297Sanish * call the memory allocation routines to return the
273223c35297Sanish * resource.
273323c35297Sanish */
273423c35297Sanish acount = length / sizeof (pci_regspec_t);
273523c35297Sanish for (i = 0; i < acount; i++) {
273623c35297Sanish char *mem_type;
273723c35297Sanish
273823c35297Sanish /*
273923c35297Sanish * Free the resource if the size of it is not zero.
274023c35297Sanish */
274123c35297Sanish if ((assigned[i].pci_size_low != 0)||
274223c35297Sanish (assigned[i].pci_size_hi != 0)) {
274323c35297Sanish switch (PCI_REG_ADDR_G(assigned[i].pci_phys_hi)) {
274423c35297Sanish case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
274523c35297Sanish /*
274623c35297Sanish * Check the assigned address for zero.
274723c35297Sanish * (Workaround for Devconf (x86) bug to
274823c35297Sanish * skip bogus entry for ROM base address
274923c35297Sanish * register. If the assigned address is
275023c35297Sanish * zero then ignore the entry
275123c35297Sanish * (see bugid 4281306)).
275223c35297Sanish */
275323c35297Sanish if (assigned[i].pci_phys_low == 0)
275423c35297Sanish break; /* ignore the entry */
275523c35297Sanish
275623c35297Sanish if (assigned[i].pci_phys_hi & PCI_REG_PF_M)
275723c35297Sanish mem_type = NDI_RA_TYPE_PCI_PREFETCH_MEM;
275823c35297Sanish else
275923c35297Sanish mem_type = NDI_RA_TYPE_MEM;
276023c35297Sanish
276123c35297Sanish if (ndi_ra_free(ddi_get_parent(dip),
276223c35297Sanish (uint64_t)assigned[i].pci_phys_low,
276323c35297Sanish (uint64_t)assigned[i].pci_size_low,
276423c35297Sanish mem_type, NDI_RA_PASS) != NDI_SUCCESS) {
276523c35297Sanish DEBUG0("Trouble freeing "
276623c35297Sanish "PCI memory space\n");
27671fb5b786Sprasad kmem_free(assigned, length);
276823c35297Sanish return (PCICFG_FAILURE);
276923c35297Sanish }
277023c35297Sanish
277123c35297Sanish DEBUG4("Returned 0x%x of 32 bit %s space"
277223c35297Sanish " @ 0x%x from register 0x%x\n",
277326947304SEvan Yan assigned[i].pci_size_low, mem_type,
277423c35297Sanish assigned[i].pci_phys_low,
277523c35297Sanish PCI_REG_REG_G(assigned[i].pci_phys_hi));
277623c35297Sanish
277723c35297Sanish break;
277823c35297Sanish case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
277923c35297Sanish if (assigned[i].pci_phys_hi & PCI_REG_PF_M)
278023c35297Sanish mem_type = NDI_RA_TYPE_PCI_PREFETCH_MEM;
278123c35297Sanish else
278223c35297Sanish mem_type = NDI_RA_TYPE_MEM;
278323c35297Sanish
278423c35297Sanish if (ndi_ra_free(ddi_get_parent(dip),
278523c35297Sanish PCICFG_LADDR(assigned[i].pci_phys_low,
278623c35297Sanish assigned[i].pci_phys_mid),
278723c35297Sanish (uint64_t)assigned[i].pci_size_low,
278823c35297Sanish mem_type, NDI_RA_PASS) != NDI_SUCCESS) {
278923c35297Sanish DEBUG0("Trouble freeing "
279023c35297Sanish "PCI memory space\n");
27911fb5b786Sprasad kmem_free(assigned, length);
279223c35297Sanish return (PCICFG_FAILURE);
279323c35297Sanish }
279423c35297Sanish
279523c35297Sanish DEBUG5("Returned 0x%x of 64 bit %s space"
279623c35297Sanish " @ 0x%x.0x%x from register 0x%x\n",
279723c35297Sanish assigned[i].pci_size_low,
279826947304SEvan Yan mem_type, assigned[i].pci_phys_mid,
279923c35297Sanish assigned[i].pci_phys_low,
280023c35297Sanish PCI_REG_REG_G(assigned[i].pci_phys_hi));
280123c35297Sanish
280223c35297Sanish break;
280323c35297Sanish case PCI_REG_ADDR_G(PCI_ADDR_IO):
280423c35297Sanish if (ndi_ra_free(ddi_get_parent(dip),
280523c35297Sanish (uint64_t)assigned[i].pci_phys_low,
280623c35297Sanish (uint64_t)assigned[i].pci_size_low,
28071fb5b786Sprasad NDI_RA_TYPE_IO, NDI_RA_PASS) !=
28081fb5b786Sprasad NDI_SUCCESS) {
280923c35297Sanish DEBUG0("Trouble freeing "
281023c35297Sanish "PCI IO space\n");
28111fb5b786Sprasad kmem_free(assigned, length);
281223c35297Sanish return (PCICFG_FAILURE);
281323c35297Sanish }
281426947304SEvan Yan DEBUG3("Returned 0x%x of IO space @ 0x%x from "
281526947304SEvan Yan "register 0x%x\n", assigned[i].pci_size_low,
281623c35297Sanish assigned[i].pci_phys_low,
281723c35297Sanish PCI_REG_REG_G(assigned[i].pci_phys_hi));
281823c35297Sanish break;
281923c35297Sanish default:
282023c35297Sanish DEBUG0("Unknown register type\n");
282123c35297Sanish kmem_free(assigned, length);
282223c35297Sanish return (PCICFG_FAILURE);
282323c35297Sanish } /* switch */
282423c35297Sanish }
282523c35297Sanish }
282623c35297Sanish kmem_free(assigned, length);
282723c35297Sanish return (PCICFG_SUCCESS);
282823c35297Sanish }
282923c35297Sanish
283023c35297Sanish 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)
283223c35297Sanish {
283323c35297Sanish ddi_acc_handle_t handle;
283423c35297Sanish uint8_t header_type;
283523c35297Sanish
283623c35297Sanish if (pci_config_setup(dip, &handle) != DDI_SUCCESS) {
283723c35297Sanish DEBUG0("Failed to map config space!\n");
283823c35297Sanish return (PCICFG_FAILURE);
283923c35297Sanish }
284023c35297Sanish
284123c35297Sanish header_type = pci_config_get8(handle, PCI_CONF_HEADER);
284223c35297Sanish
284323c35297Sanish (void) pci_config_teardown(&handle);
284423c35297Sanish
284523c35297Sanish /*
284623c35297Sanish * A different algorithm is used for bridges and leaf devices.
284723c35297Sanish */
284823c35297Sanish 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
285523c35297Sanish if (pcicfg_free_bridge_resources(dip) != PCICFG_SUCCESS) {
285623c35297Sanish DEBUG0("Failed freeing up bridge resources\n");
285723c35297Sanish return (PCICFG_FAILURE);
285823c35297Sanish }
285923c35297Sanish } else {
286023c35297Sanish if (pcicfg_free_device_resources(dip) != PCICFG_SUCCESS) {
286123c35297Sanish DEBUG0("Failed freeing up device resources\n");
286223c35297Sanish return (PCICFG_FAILURE);
286323c35297Sanish }
286423c35297Sanish }
286523c35297Sanish
286623c35297Sanish return (PCICFG_SUCCESS);
286723c35297Sanish }
286823c35297Sanish
286923c35297Sanish #ifndef _DONT_USE_1275_GENERIC_NAMES
287023c35297Sanish static char *
pcicfg_get_class_name(uint32_t classcode)287123c35297Sanish pcicfg_get_class_name(uint32_t classcode)
287223c35297Sanish {
287323c35297Sanish struct pcicfg_name_entry *ptr;
287423c35297Sanish
287523c35297Sanish for (ptr = &pcicfg_class_lookup[0]; ptr->name != NULL; ptr++) {
287623c35297Sanish if (ptr->class_code == classcode) {
287723c35297Sanish return (ptr->name);
287823c35297Sanish }
287923c35297Sanish }
288023c35297Sanish return (NULL);
288123c35297Sanish }
288223c35297Sanish #endif /* _DONT_USE_1275_GENERIC_NAMES */
288323c35297Sanish
288423c35297Sanish static dev_info_t *
pcicfg_devi_find(dev_info_t * dip,uint_t device,uint_t function)288523c35297Sanish pcicfg_devi_find(dev_info_t *dip, uint_t device, uint_t function)
288623c35297Sanish {
288723c35297Sanish struct pcicfg_find_ctrl ctrl;
288823c35297Sanish
288923c35297Sanish ctrl.device = device;
289023c35297Sanish ctrl.function = function;
289123c35297Sanish ctrl.dip = NULL;
289223c35297Sanish
28933fe80ca4SDan Cross ndi_devi_enter(dip);
289423c35297Sanish ddi_walk_devs(ddi_get_child(dip), pcicfg_match_dev, (void *)&ctrl);
28953fe80ca4SDan Cross ndi_devi_exit(dip);
289623c35297Sanish
289723c35297Sanish return (ctrl.dip);
289823c35297Sanish }
289923c35297Sanish
290023c35297Sanish static int
pcicfg_match_dev(dev_info_t * dip,void * hdl)290123c35297Sanish pcicfg_match_dev(dev_info_t *dip, void *hdl)
290223c35297Sanish {
290323c35297Sanish struct pcicfg_find_ctrl *ctrl = (struct pcicfg_find_ctrl *)hdl;
290423c35297Sanish pci_regspec_t *pci_rp;
290523c35297Sanish int length;
290623c35297Sanish int pci_dev;
290723c35297Sanish int pci_func;
290823c35297Sanish
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) {
291123c35297Sanish ctrl->dip = NULL;
291223c35297Sanish return (DDI_WALK_TERMINATE);
291323c35297Sanish }
291423c35297Sanish
291523c35297Sanish /* get the PCI device address info */
291623c35297Sanish pci_dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
291723c35297Sanish pci_func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
291823c35297Sanish
291923c35297Sanish /*
292023c35297Sanish * free the memory allocated by ddi_prop_lookup_int_array
292123c35297Sanish */
292223c35297Sanish ddi_prop_free(pci_rp);
292323c35297Sanish
292423c35297Sanish
292523c35297Sanish if ((pci_dev == ctrl->device) && (pci_func == ctrl->function)) {
292623c35297Sanish /* found the match for the specified device address */
292723c35297Sanish ctrl->dip = dip;
292823c35297Sanish return (DDI_WALK_TERMINATE);
292923c35297Sanish }
293023c35297Sanish
293123c35297Sanish /*
293223c35297Sanish * continue the walk to the next sibling to look for a match.
293323c35297Sanish */
293423c35297Sanish return (DDI_WALK_PRUNECHILD);
293523c35297Sanish }
293623c35297Sanish
293723c35297Sanish static int
pcicfg_update_assigned_prop(dev_info_t * dip,pci_regspec_t * newone)293823c35297Sanish pcicfg_update_assigned_prop(dev_info_t *dip, pci_regspec_t *newone)
293923c35297Sanish {
294023c35297Sanish int alen;
294123c35297Sanish pci_regspec_t *assigned;
294223c35297Sanish caddr_t newreg;
294323c35297Sanish uint_t status;
294423c35297Sanish
294523c35297Sanish status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
294623c35297Sanish "assigned-addresses", (caddr_t)&assigned, &alen);
294723c35297Sanish switch (status) {
294823c35297Sanish case DDI_PROP_SUCCESS:
294923c35297Sanish break;
295023c35297Sanish case DDI_PROP_NO_MEMORY:
295123c35297Sanish DEBUG0("no memory for assigned-addresses property\n");
295223c35297Sanish return (PCICFG_FAILURE);
295323c35297Sanish default:
295423c35297Sanish (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
295523c35297Sanish "assigned-addresses", (int *)newone,
295623c35297Sanish sizeof (*newone)/sizeof (int));
295723c35297Sanish return (PCICFG_SUCCESS);
295823c35297Sanish }
295923c35297Sanish
296023c35297Sanish /*
296123c35297Sanish * Allocate memory for the existing
296223c35297Sanish * assigned-addresses(s) plus one and then
296323c35297Sanish * build it.
296423c35297Sanish */
296523c35297Sanish
296623c35297Sanish newreg = kmem_zalloc(alen+sizeof (*newone), KM_SLEEP);
296723c35297Sanish
296823c35297Sanish bcopy(assigned, newreg, alen);
296923c35297Sanish bcopy(newone, newreg + alen, sizeof (*newone));
297023c35297Sanish
297123c35297Sanish /*
297223c35297Sanish * Write out the new "assigned-addresses" spec
297323c35297Sanish */
297423c35297Sanish (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
297523c35297Sanish "assigned-addresses", (int *)newreg,
297623c35297Sanish (alen + sizeof (*newone))/sizeof (int));
297723c35297Sanish
297823c35297Sanish kmem_free((caddr_t)newreg, alen+sizeof (*newone));
297923c35297Sanish kmem_free(assigned, alen);
298023c35297Sanish
298123c35297Sanish return (PCICFG_SUCCESS);
298223c35297Sanish }
298323c35297Sanish
298423c35297Sanish static int
pcicfg_update_ranges_prop(dev_info_t * dip,ppb_ranges_t * addition)298523c35297Sanish pcicfg_update_ranges_prop(dev_info_t *dip, ppb_ranges_t *addition)
298623c35297Sanish {
298723c35297Sanish int rlen;
298823c35297Sanish ppb_ranges_t *ranges;
298923c35297Sanish caddr_t newreg;
299023c35297Sanish uint_t status;
299123c35297Sanish
299226947304SEvan Yan status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
299326947304SEvan Yan "ranges", (caddr_t)&ranges, &rlen);
299423c35297Sanish
299523c35297Sanish
299623c35297Sanish switch (status) {
299723c35297Sanish case DDI_PROP_SUCCESS:
299823c35297Sanish break;
299923c35297Sanish case DDI_PROP_NO_MEMORY:
300023c35297Sanish DEBUG0("ranges present, but unable to get memory\n");
300123c35297Sanish return (PCICFG_FAILURE);
300223c35297Sanish default:
300323c35297Sanish DEBUG0("no ranges property - creating one\n");
300423c35297Sanish if (ndi_prop_update_int_array(DDI_DEV_T_NONE,
300523c35297Sanish dip, "ranges", (int *)addition,
300623c35297Sanish sizeof (ppb_ranges_t)/sizeof (int))
300723c35297Sanish != DDI_SUCCESS) {
300823c35297Sanish DEBUG0("Did'nt create ranges property\n");
300923c35297Sanish return (PCICFG_FAILURE);
301023c35297Sanish }
301123c35297Sanish return (PCICFG_SUCCESS);
301223c35297Sanish }
301323c35297Sanish
301423c35297Sanish /*
301523c35297Sanish * Allocate memory for the existing ranges plus one and then
301623c35297Sanish * build it.
301723c35297Sanish */
301823c35297Sanish newreg = kmem_zalloc(rlen+sizeof (ppb_ranges_t), KM_SLEEP);
301923c35297Sanish
302023c35297Sanish bcopy(ranges, newreg, rlen);
302123c35297Sanish bcopy(addition, newreg + rlen, sizeof (ppb_ranges_t));
302223c35297Sanish
302323c35297Sanish /*
302423c35297Sanish * Write out the new "ranges" property
302523c35297Sanish */
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));
302823c35297Sanish
302923c35297Sanish DEBUG1("Updating ranges property for %d entries",
303023c35297Sanish rlen / sizeof (ppb_ranges_t) + 1);
303123c35297Sanish
303223c35297Sanish kmem_free((caddr_t)newreg, rlen+sizeof (ppb_ranges_t));
303323c35297Sanish
303423c35297Sanish kmem_free((caddr_t)ranges, rlen);
303523c35297Sanish
303623c35297Sanish return (PCICFG_SUCCESS);
303723c35297Sanish }
303823c35297Sanish
303923c35297Sanish static int
pcicfg_update_reg_prop(dev_info_t * dip,uint32_t regvalue,uint_t reg_offset)304023c35297Sanish pcicfg_update_reg_prop(dev_info_t *dip, uint32_t regvalue, uint_t reg_offset)
304123c35297Sanish {
304223c35297Sanish int rlen;
304323c35297Sanish pci_regspec_t *reg;
304423c35297Sanish caddr_t newreg;
304523c35297Sanish uint32_t hiword;
304623c35297Sanish pci_regspec_t addition;
304723c35297Sanish uint32_t size;
304823c35297Sanish uint_t status;
304923c35297Sanish
305023c35297Sanish status = ddi_getlongprop(DDI_DEV_T_ANY,
305123c35297Sanish dip, DDI_PROP_DONTPASS, "reg", (caddr_t)®, &rlen);
305223c35297Sanish
305323c35297Sanish switch (status) {
305423c35297Sanish case DDI_PROP_SUCCESS:
305523c35297Sanish break;
305623c35297Sanish case DDI_PROP_NO_MEMORY:
305723c35297Sanish DEBUG0("reg present, but unable to get memory\n");
305823c35297Sanish return (PCICFG_FAILURE);
305923c35297Sanish default:
306023c35297Sanish DEBUG0("no reg property\n");
306123c35297Sanish return (PCICFG_FAILURE);
306223c35297Sanish }
306323c35297Sanish
306423c35297Sanish /*
306523c35297Sanish * Allocate memory for the existing reg(s) plus one and then
306623c35297Sanish * build it.
306723c35297Sanish */
306823c35297Sanish newreg = kmem_zalloc(rlen+sizeof (pci_regspec_t), KM_SLEEP);
306923c35297Sanish
307023c35297Sanish /*
307123c35297Sanish * Build the regspec, then add it to the existing one(s)
307223c35297Sanish */
307323c35297Sanish
307423c35297Sanish hiword = PCICFG_MAKE_REG_HIGH(PCI_REG_BUS_G(reg->pci_phys_hi),
307523c35297Sanish PCI_REG_DEV_G(reg->pci_phys_hi),
307623c35297Sanish PCI_REG_FUNC_G(reg->pci_phys_hi), reg_offset);
307723c35297Sanish
307823c35297Sanish if (reg_offset == PCI_CONF_ROM) {
307923c35297Sanish size = (~(PCI_BASE_ROM_ADDR_M & regvalue))+1;
308023c35297Sanish hiword |= PCI_ADDR_MEM32;
308123c35297Sanish } else {
308223c35297Sanish size = (~(PCI_BASE_M_ADDR_M & regvalue))+1;
308323c35297Sanish
308423c35297Sanish if ((PCI_BASE_SPACE_M & regvalue) == PCI_BASE_SPACE_MEM) {
308523c35297Sanish if ((PCI_BASE_TYPE_M & regvalue) == PCI_BASE_TYPE_MEM) {
308623c35297Sanish hiword |= PCI_ADDR_MEM32;
308723c35297Sanish } else if ((PCI_BASE_TYPE_M & regvalue)
308823c35297Sanish == PCI_BASE_TYPE_ALL) {
308923c35297Sanish hiword |= PCI_ADDR_MEM64;
309023c35297Sanish }
309123c35297Sanish if (regvalue & PCI_BASE_PREF_M)
309223c35297Sanish hiword |= PCI_REG_PF_M;
309323c35297Sanish } else {
309423c35297Sanish hiword |= PCI_ADDR_IO;
309523c35297Sanish }
309623c35297Sanish }
309723c35297Sanish
309823c35297Sanish addition.pci_phys_hi = hiword;
309923c35297Sanish addition.pci_phys_mid = 0;
310023c35297Sanish addition.pci_phys_low = 0;
310123c35297Sanish addition.pci_size_hi = 0;
310223c35297Sanish addition.pci_size_low = size;
310323c35297Sanish
310423c35297Sanish bcopy(reg, newreg, rlen);
310523c35297Sanish bcopy(&addition, newreg + rlen, sizeof (pci_regspec_t));
310623c35297Sanish
310723c35297Sanish DEBUG3("updating BAR@off %x with %x,%x\n", reg_offset, hiword, size);
310823c35297Sanish /*
310923c35297Sanish * Write out the new "reg" property
311023c35297Sanish */
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));
311323c35297Sanish
311423c35297Sanish kmem_free((caddr_t)newreg, rlen+sizeof (pci_regspec_t));
311523c35297Sanish kmem_free((caddr_t)reg, rlen);
311623c35297Sanish
311723c35297Sanish return (PCICFG_SUCCESS);
311823c35297Sanish }
311923c35297Sanish
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
319623c35297Sanish static void
pcicfg_device_on(ddi_acc_handle_t config_handle)319723c35297Sanish pcicfg_device_on(ddi_acc_handle_t config_handle)
319823c35297Sanish {
319923c35297Sanish /*
320023c35297Sanish * Enable memory, IO, and bus mastership
320123c35297Sanish * XXX should we enable parity, SERR#,
320223c35297Sanish * fast back-to-back, and addr. stepping?
320323c35297Sanish */
320423c35297Sanish pci_config_put16(config_handle, PCI_CONF_COMM,
320523c35297Sanish pci_config_get16(config_handle, PCI_CONF_COMM) | 0x7);
320623c35297Sanish }
320723c35297Sanish
320823c35297Sanish static void
pcicfg_device_off(ddi_acc_handle_t config_handle)320923c35297Sanish pcicfg_device_off(ddi_acc_handle_t config_handle)
321023c35297Sanish {
321123c35297Sanish /*
321223c35297Sanish * Disable I/O and memory traffic through the bridge
321323c35297Sanish */
321423c35297Sanish pci_config_put16(config_handle, PCI_CONF_COMM, 0x0);
321523c35297Sanish }
321623c35297Sanish
321723c35297Sanish static int
pcicfg_set_busnode_props(dev_info_t * dip,uint8_t pcie_device_type)321823c35297Sanish pcicfg_set_busnode_props(dev_info_t *dip, uint8_t pcie_device_type)
321923c35297Sanish {
322023c35297Sanish int ret;
322123c35297Sanish char device_type[8];
322223c35297Sanish
322323c35297Sanish if (pcie_device_type)
322423c35297Sanish (void) strcpy(device_type, "pciex");
322523c35297Sanish else
322623c35297Sanish (void) strcpy(device_type, "pci");
322723c35297Sanish
322823c35297Sanish if ((ret = ndi_prop_update_string(DDI_DEV_T_NONE, dip,
322923c35297Sanish "device_type", device_type)) != DDI_SUCCESS) {
323023c35297Sanish return (ret);
323123c35297Sanish }
323223c35297Sanish if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
323323c35297Sanish "#address-cells", 3)) != DDI_SUCCESS) {
323423c35297Sanish return (ret);
323523c35297Sanish }
323626947304SEvan Yan if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, "#size-cells", 2))
323726947304SEvan Yan != DDI_SUCCESS) {
323823c35297Sanish return (ret);
323923c35297Sanish }
324023c35297Sanish return (PCICFG_SUCCESS);
324123c35297Sanish }
324223c35297Sanish
324323c35297Sanish /*
324423c35297Sanish * Program the bus numbers into the bridge
324523c35297Sanish */
324623c35297Sanish 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)
324923c35297Sanish {
325023c35297Sanish DEBUG3("Setting bridge bus-range %d,%d,%d\n", primary, secondary,
325123c35297Sanish subordinate);
325223c35297Sanish /*
325323c35297Sanish * Primary bus#
325423c35297Sanish */
325523c35297Sanish pci_config_put8(config_handle, PCI_BCNF_PRIBUS, primary);
325623c35297Sanish
325723c35297Sanish /*
325823c35297Sanish * Secondary bus#
325923c35297Sanish */
326023c35297Sanish pci_config_put8(config_handle, PCI_BCNF_SECBUS, secondary);
326123c35297Sanish
326223c35297Sanish /*
326323c35297Sanish * Set the subordinate bus number to ff in order to pass through any
326423c35297Sanish * type 1 cycle with a bus number higher than the secondary bus#
326523c35297Sanish */
326623c35297Sanish pci_config_put8(config_handle, PCI_BCNF_SUBBUS, subordinate);
326723c35297Sanish }
326823c35297Sanish
326923c35297Sanish /*
327023c35297Sanish * Put bridge registers into initial state
327123c35297Sanish */
327223c35297Sanish 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)
327423c35297Sanish {
327523c35297Sanish /*
327623c35297Sanish * The highest bus seen during probing is the max-subordinate bus
327723c35297Sanish */
327823c35297Sanish pci_config_put8(handle, PCI_BCNF_SUBBUS, entry->highest_bus);
327923c35297Sanish
328023c35297Sanish /*
328123c35297Sanish * Reset the secondary bus
328223c35297Sanish */
328323c35297Sanish pci_config_put16(handle, PCI_BCNF_BCNTRL,
328423c35297Sanish pci_config_get16(handle, PCI_BCNF_BCNTRL) | 0x40);
328523c35297Sanish drv_usecwait(1000);
328623c35297Sanish pci_config_put16(handle, PCI_BCNF_BCNTRL,
328723c35297Sanish pci_config_get16(handle, PCI_BCNF_BCNTRL) & ~0x40);
328823c35297Sanish drv_usecwait(1000);
328923c35297Sanish
329023c35297Sanish /*
329123c35297Sanish * Program the memory base register with the
329223c35297Sanish * start of the memory range
329323c35297Sanish */
329423c35297Sanish pci_config_put16(handle, PCI_BCNF_MEM_BASE,
329523c35297Sanish PCICFG_HIWORD(PCICFG_LOADDR(entry->memory_last)));
329623c35297Sanish
329723c35297Sanish /*
329823c35297Sanish * Program the I/O base register with the start of the I/O range
329923c35297Sanish */
330023c35297Sanish pci_config_put8(handle, PCI_BCNF_IO_BASE_LOW,
330123c35297Sanish PCICFG_HIBYTE(PCICFG_LOWORD(PCICFG_LOADDR(entry->io_last))));
330223c35297Sanish pci_config_put16(handle, PCI_BCNF_IO_BASE_HI,
330323c35297Sanish PCICFG_HIWORD(PCICFG_LOADDR(entry->io_last)));
330423c35297Sanish
330523c35297Sanish /*
330623c35297Sanish * Program the PF memory base register with the start of
330723c35297Sanish * PF memory range
330823c35297Sanish */
330923c35297Sanish pci_config_put16(handle, PCI_BCNF_PF_BASE_LOW,
331023c35297Sanish PCICFG_HIWORD(PCICFG_LOADDR(entry->pf_memory_last)));
331123c35297Sanish pci_config_put32(handle, PCI_BCNF_PF_BASE_HIGH,
331223c35297Sanish PCICFG_HIADDR(entry->pf_memory_last));
331323c35297Sanish
331423c35297Sanish /*
331523c35297Sanish * Clear status bits
331623c35297Sanish */
331723c35297Sanish pci_config_put16(handle, PCI_BCNF_SEC_STATUS, 0xffff);
331823c35297Sanish
331923c35297Sanish /*
332023c35297Sanish * Needs to be set to this value
332123c35297Sanish */
332223c35297Sanish pci_config_put8(handle, PCI_CONF_ILINE, 0xf);
332323c35297Sanish
332423c35297Sanish /*
332523c35297Sanish * XXX - may be delay should be used since noone configures
332623c35297Sanish * devices in the interrupt context
332723c35297Sanish */
332823c35297Sanish drv_usecwait(pcicfg_sec_reset_delay); /* 1 sec wait */
332923c35297Sanish }
333023c35297Sanish
333123c35297Sanish 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)
333323c35297Sanish {
333423c35297Sanish uint_t length;
333523c35297Sanish
333623c35297Sanish /*
333723c35297Sanish * Program the memory limit register with the end of the memory range
333823c35297Sanish */
333923c35297Sanish
334023c35297Sanish DEBUG1("DOWN ROUNDED ===>[0x%x]\n",
334126947304SEvan Yan PCICFG_ROUND_DOWN(entry->memory_last, PCICFG_MEMGRAN));
334223c35297Sanish
334323c35297Sanish pci_config_put16(handle, PCI_BCNF_MEM_LIMIT,
334423c35297Sanish PCICFG_HIWORD(PCICFG_LOADDR(
334526947304SEvan Yan PCICFG_ROUND_DOWN(entry->memory_last, PCICFG_MEMGRAN))));
334623c35297Sanish /*
334723c35297Sanish * Since this is a bridge, the rest of this range will
334823c35297Sanish * be responded to by the bridge. We have to round up
334923c35297Sanish * so no other device claims it.
335023c35297Sanish */
335126947304SEvan Yan if ((length = (PCICFG_ROUND_UP(entry->memory_last, PCICFG_MEMGRAN)
335226947304SEvan Yan - entry->memory_last)) > 0) {
335323c35297Sanish (void) pcicfg_get_mem(entry, length, NULL);
335426947304SEvan Yan DEBUG1("Added [0x%x]at the top of the bridge (mem)\n", length);
335523c35297Sanish }
335623c35297Sanish
335723c35297Sanish /*
335823c35297Sanish * Program the PF memory limit register with the end of the memory range
335923c35297Sanish */
336023c35297Sanish
336123c35297Sanish DEBUG1("DOWN ROUNDED ===>[0x%x]\n",
336226947304SEvan Yan PCICFG_ROUND_DOWN(entry->pf_memory_last, PCICFG_MEMGRAN));
336323c35297Sanish
336423c35297Sanish 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) {
337123c35297Sanish (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);
337423c35297Sanish }
337523c35297Sanish
337623c35297Sanish /*
337723c35297Sanish * Program the I/O limit register with the end of the I/O range
337823c35297Sanish */
337923c35297Sanish pci_config_put8(handle, PCI_BCNF_IO_LIMIT_LOW,
338023c35297Sanish PCICFG_HIBYTE(PCICFG_LOWORD(
338126947304SEvan Yan PCICFG_LOADDR(PCICFG_ROUND_DOWN(entry->io_last, PCICFG_IOGRAN)))));
338223c35297Sanish
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))));
338523c35297Sanish
338623c35297Sanish /*
338723c35297Sanish * Same as above for I/O space. Since this is a
338823c35297Sanish * bridge, the rest of this range will be responded
338923c35297Sanish * to by the bridge. We have to round up so no
339023c35297Sanish * other device claims it.
339123c35297Sanish */
339226947304SEvan Yan if ((length = (PCICFG_ROUND_UP(entry->io_last, PCICFG_IOGRAN)
339326947304SEvan Yan - entry->io_last)) > 0) {
339423c35297Sanish (void) pcicfg_get_io(entry, length, NULL);
339526947304SEvan Yan DEBUG1("Added [0x%x]at the top of the bridge (I/O)\n", length);
339623c35297Sanish }
339723c35297Sanish }
339823c35297Sanish
339923c35297Sanish 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)
340223c35297Sanish {
340323c35297Sanish dev_info_t *new_child;
340423c35297Sanish 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;
340823c35297Sanish
340923c35297Sanish /*
341023c35297Sanish * This node will be put immediately below
341123c35297Sanish * "parent". Allocate a blank device node. It will either
341223c35297Sanish * be filled in or freed up based on further probing.
341323c35297Sanish */
341423c35297Sanish
341523c35297Sanish ndi_devi_alloc_sleep(parent, DEVI_PSEUDO_NEXNAME,
341623c35297Sanish (pnode_t)DEVI_SID_NODEID, &new_child);
341723c35297Sanish
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");
342123c35297Sanish goto failedconfig;
342223c35297Sanish }
342323c35297Sanish
342423c35297Sanish if ((ret = pcicfg_config_setup(new_child, &config_handle))
342523c35297Sanish != PCICFG_SUCCESS) {
342623c35297Sanish if (ret == PCICFG_NODEVICE) {
342723c35297Sanish (void) ndi_devi_free(new_child);
342823c35297Sanish return (ret);
342923c35297Sanish }
343023c35297Sanish DEBUG0("pcicfg_probe_children():"
343123c35297Sanish "Failed to setup config space\n");
343223c35297Sanish goto failedconfig;
343323c35297Sanish }
343423c35297Sanish
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
343923c35297Sanish /*
344023c35297Sanish * As soon as we have access to config space,
344123c35297Sanish * turn off device. It will get turned on
344223c35297Sanish * later (after memory is assigned).
344323c35297Sanish */
344423c35297Sanish (void) pcicfg_device_off(config_handle);
344523c35297Sanish
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);
345123c35297Sanish goto failedchild;
345223c35297Sanish }
345323c35297Sanish
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);
345923c35297Sanish goto failedchild;
346023c35297Sanish }
346123c35297Sanish
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);
3467*bd97c7ceSRobert Mustacchi goto failedchild;
3468*bd97c7ceSRobert Mustacchi }
3469*bd97c7ceSRobert Mustacchi
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 }
347723c35297Sanish
347823c35297Sanish /*
347923c35297Sanish * If this is not a multi-function card only probe function zero.
348023c35297Sanish */
3481*bd97c7ceSRobert Mustacchi if ((prop_data.ppd_flags & PCI_PROP_F_MULT_FUNC) == 0 && func != 0) {
348223c35297Sanish
3483c0da6274SZhi-Jun Robin Fu ret = PCICFG_NODEVICE;
3484c0da6274SZhi-Jun Robin Fu goto failedchild;
348523c35297Sanish }
348623c35297Sanish
348723c35297Sanish /*
348823c35297Sanish * Attach the child to its parent
348923c35297Sanish */
349023c35297Sanish (void) i_ndi_config_node(new_child, DS_LINKED, 0);
349123c35297Sanish
34923a634bfcSVikram Hegde DEVI_SET_PCI(new_child);
34933a634bfcSVikram Hegde
3494*bd97c7ceSRobert Mustacchi if (prop_data.ppd_header == PCI_HEADER_PPB) {
349523c35297Sanish
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;
350223c35297Sanish
35035af4ae46Sjveta ret = pcicfg_probe_bridge(new_child, config_handle, bus,
3504c0da6274SZhi-Jun Robin Fu highest_bus, is_pcie);
35055af4ae46Sjveta if (ret != PCICFG_SUCCESS) {
350623c35297Sanish (void) pcicfg_free_bridge_resources(new_child);
350723c35297Sanish goto failedchild;
350823c35297Sanish }
350923c35297Sanish
351023c35297Sanish } else {
351123c35297Sanish
351223c35297Sanish DEBUG3("--Leaf device found bus [0x%x] device"
351326947304SEvan Yan "[0x%x] func [0x%x]\n", bus, device, func);
351426947304SEvan Yan
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;
352426947304SEvan Yan
352526947304SEvan Yan /*
352626947304SEvan Yan * now allocate the resources, just remove the
352726947304SEvan Yan * resources from the parent busra pool.
352826947304SEvan Yan */
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;
353326947304SEvan Yan }
353426947304SEvan Yan
353526947304SEvan Yan } else {
353626947304SEvan Yan /*
353726947304SEvan Yan * update "reg" property by sizing the BARs.
353826947304SEvan Yan */
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;
354926947304SEvan Yan }
355026947304SEvan Yan }
355126947304SEvan Yan
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;
358826947304SEvan Yan uint32_t request;
358923c35297Sanish
359023c35297Sanish i = PCI_CONF_BASE0;
359123c35297Sanish
359223c35297Sanish while (i <= PCI_CONF_BASE5) {
359323c35297Sanish
359423c35297Sanish pci_config_put32(config_handle, i, 0xffffffff);
359523c35297Sanish
359623c35297Sanish request = pci_config_get32(config_handle, i);
359723c35297Sanish /*
359823c35297Sanish * If its a zero length, don't do
359923c35297Sanish * any programming.
360023c35297Sanish */
360123c35297Sanish if (request != 0) {
360223c35297Sanish /*
360323c35297Sanish * Add to the "reg" property
360423c35297Sanish */
360523c35297Sanish if (pcicfg_update_reg_prop(new_child,
360623c35297Sanish request, i) != PCICFG_SUCCESS) {
360723c35297Sanish goto failedchild;
360823c35297Sanish }
360923c35297Sanish } else {
361023c35297Sanish DEBUG1("BASE register [0x%x] asks for "
361123c35297Sanish "[0x0]=[0x0](32)\n", i);
361223c35297Sanish i += 4;
361323c35297Sanish continue;
361423c35297Sanish }
361523c35297Sanish
361623c35297Sanish /*
361723c35297Sanish * Increment by eight if it is 64 bit address space
361823c35297Sanish */
361923c35297Sanish if ((PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_ALL) {
362023c35297Sanish DEBUG3("BASE register [0x%x] asks for "
362123c35297Sanish "[0x%x]=[0x%x] (64)\n",
362226947304SEvan Yan i, request, (~(PCI_BASE_M_ADDR_M & request))+1);
362323c35297Sanish i += 8;
362423c35297Sanish } else {
362523c35297Sanish DEBUG3("BASE register [0x%x] asks for "
362623c35297Sanish "[0x%x]=[0x%x](32)\n",
362726947304SEvan Yan i, request, (~(PCI_BASE_M_ADDR_M & request))+1);
362823c35297Sanish i += 4;
362923c35297Sanish }
363023c35297Sanish }
363123c35297Sanish
363223c35297Sanish /*
363323c35297Sanish * Get the ROM size and create register for it
363423c35297Sanish */
363523c35297Sanish pci_config_put32(config_handle, PCI_CONF_ROM, 0xfffffffe);
363623c35297Sanish
363723c35297Sanish request = pci_config_get32(config_handle, PCI_CONF_ROM);
363823c35297Sanish /*
363923c35297Sanish * If its a zero length, don't do
364023c35297Sanish * any programming.
364123c35297Sanish */
364223c35297Sanish
364323c35297Sanish if (request != 0) {
364423c35297Sanish DEBUG3("BASE register [0x%x] asks for [0x%x]=[0x%x]\n",
364523c35297Sanish PCI_CONF_ROM, request,
364623c35297Sanish (~(PCI_BASE_ROM_ADDR_M & request)) + 1);
364723c35297Sanish /*
364823c35297Sanish * Add to the "reg" property
364923c35297Sanish */
365026947304SEvan Yan if (pcicfg_update_reg_prop(new_child, request, PCI_CONF_ROM)
365126947304SEvan Yan != PCICFG_SUCCESS) {
365223c35297Sanish goto failedchild;
365323c35297Sanish }
365423c35297Sanish }
365523c35297Sanish
365623c35297Sanish return (PCICFG_SUCCESS);
365723c35297Sanish
365823c35297Sanish failedchild:
365926947304SEvan Yan return (PCICFG_FAILURE);
366026947304SEvan Yan }
366126947304SEvan Yan
366223c35297Sanish /*
366326947304SEvan Yan * Read the BARs and update properties. Used in virtual hotplug.
366423c35297Sanish */
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;
367123c35297Sanish
367226947304SEvan Yan i = PCI_CONF_BASE0;
367323c35297Sanish
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
373226947304SEvan Yan /*
373326947304SEvan Yan * Get the ROM size and create register for it
373426947304SEvan Yan */
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);
373926947304SEvan Yan
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 }
376426947304SEvan Yan
376526947304SEvan Yan return (PCICFG_SUCCESS);
376626947304SEvan Yan
376726947304SEvan Yan failedchild:
376826947304SEvan Yan return (PCICFG_FAILURE);
376923c35297Sanish }
377023c35297Sanish
377123c35297Sanish 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)377223c35297Sanish 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)
377423c35297Sanish {
377523c35297Sanish uint64_t next_bus;
377623c35297Sanish uint_t new_bus, num_slots;
377723c35297Sanish ndi_ra_request_t req;
377823c35297Sanish int rval, i, j;
377923c35297Sanish uint64_t mem_answer, io_answer, mem_base, io_base, mem_alen, io_alen;
378023c35297Sanish uint64_t pf_mem_answer, pf_mem_base, pf_mem_alen;
378123c35297Sanish uint64_t mem_size, io_size, pf_mem_size;
378223c35297Sanish uint64_t mem_end, pf_mem_end, io_end;
378323c35297Sanish uint64_t round_answer, round_len;
378423c35297Sanish ppb_ranges_t range[PCICFG_RANGE_LEN];
378523c35297Sanish int bus_range[2];
378623c35297Sanish pcicfg_phdl_t phdl;
378723c35297Sanish uint64_t pcibus_base, pcibus_alen;
378823c35297Sanish uint64_t max_bus;
378923c35297Sanish uint8_t pcie_device_type = 0;
379023c35297Sanish 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;
379523c35297Sanish
379623c35297Sanish io_answer = io_base = io_alen = io_size = 0;
379723c35297Sanish pf_mem_answer = pf_mem_base = pf_mem_size = pf_mem_alen = 0;
379823c35297Sanish
379923c35297Sanish /*
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
381726947304SEvan Yan /*
381823c35297Sanish * setup resource maps for the bridge node
381923c35297Sanish */
382023c35297Sanish if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_PCI_BUSNUM)
382123c35297Sanish == NDI_FAILURE) {
382223c35297Sanish DEBUG0("Can not setup resource map - NDI_RA_TYPE_PCI_BUSNUM\n");
382323c35297Sanish rval = PCICFG_FAILURE;
382423c35297Sanish goto cleanup;
382523c35297Sanish }
382623c35297Sanish if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_MEM) == NDI_FAILURE) {
382723c35297Sanish DEBUG0("Can not setup resource map - NDI_RA_TYPE_MEM\n");
382823c35297Sanish rval = PCICFG_FAILURE;
382923c35297Sanish goto cleanup;
383023c35297Sanish }
383123c35297Sanish if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_IO) == NDI_FAILURE) {
383223c35297Sanish DEBUG0("Can not setup resource map - NDI_RA_TYPE_IO\n");
383323c35297Sanish rval = PCICFG_FAILURE;
383423c35297Sanish goto cleanup;
383523c35297Sanish }
383623c35297Sanish if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_PCI_PREFETCH_MEM) ==
383723c35297Sanish NDI_FAILURE) {
383823c35297Sanish DEBUG0("Can not setup resource map -"
383923c35297Sanish " NDI_RA_TYPE_PCI_PREFETCH_MEM\n");
384023c35297Sanish rval = PCICFG_FAILURE;
384123c35297Sanish goto cleanup;
384223c35297Sanish }
384323c35297Sanish
384423c35297Sanish /*
384523c35297Sanish * Allocate bus range pool for the bridge.
384623c35297Sanish */
384723c35297Sanish bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
384823c35297Sanish req.ra_flags = (NDI_RA_ALLOC_BOUNDED | NDI_RA_ALLOC_PARTIAL_OK);
384923c35297Sanish req.ra_boundbase = 0;
385023c35297Sanish req.ra_boundlen = req.ra_len = (PCI_MAX_BUS_NUM -1);
385123c35297Sanish req.ra_align_mask = 0; /* no alignment needed */
385223c35297Sanish
385323c35297Sanish rval = ndi_ra_alloc(ddi_get_parent(new_child), &req,
385423c35297Sanish &pcibus_base, &pcibus_alen, NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS);
385523c35297Sanish
385623c35297Sanish if (rval != NDI_SUCCESS) {
385723c35297Sanish if (rval == NDI_RA_PARTIAL_REQ) {
385823c35297Sanish /*EMPTY*/
385923c35297Sanish DEBUG0("NDI_RA_PARTIAL_REQ returned for bus range\n");
386023c35297Sanish } else {
386123c35297Sanish DEBUG0(
386223c35297Sanish "Failed to allocate bus range for bridge\n");
38635af4ae46Sjveta rval = PCICFG_NORESRC;
386423c35297Sanish goto cleanup;
386523c35297Sanish }
386623c35297Sanish }
386723c35297Sanish
386823c35297Sanish DEBUG2("Bus Range Allocated [base=%d] [len=%d]\n",
386923c35297Sanish pcibus_base, pcibus_alen);
387023c35297Sanish
387123c35297Sanish /*
387223c35297Sanish * Put available bus range into the pool.
387323c35297Sanish * Take the first one for this bridge to use and don't give
387423c35297Sanish * to child.
387523c35297Sanish */
387623c35297Sanish (void) ndi_ra_free(new_child, pcibus_base+1, pcibus_alen-1,
387723c35297Sanish NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS);
387823c35297Sanish
387923c35297Sanish next_bus = pcibus_base;
388023c35297Sanish max_bus = pcibus_base + pcibus_alen - 1;
388123c35297Sanish
388223c35297Sanish new_bus = next_bus;
388323c35297Sanish
388423c35297Sanish DEBUG1("NEW bus found ->[%d]\n", new_bus);
388523c35297Sanish
388623c35297Sanish /* Keep track of highest bus for subordinate bus programming */
388723c35297Sanish *highest_bus = new_bus;
388823c35297Sanish
388923c35297Sanish /*
389023c35297Sanish * Allocate (non-prefetchable) Memory Space for Bridge
389123c35297Sanish */
389223c35297Sanish bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
389323c35297Sanish req.ra_flags = (NDI_RA_ALLOC_BOUNDED | NDI_RA_ALLOC_PARTIAL_OK);
389423c35297Sanish req.ra_boundbase = 0;
389523c35297Sanish /*
389623c35297Sanish * limit the boundlen,len to a 32b quantity. It should be Ok to
389723c35297Sanish * lose alignment-based-size of resource due to this.
389823c35297Sanish */
389923c35297Sanish req.ra_boundlen = PCICFG_4GIG_LIMIT;
390023c35297Sanish req.ra_len = PCICFG_4GIG_LIMIT; /* Get as big as possible */
390123c35297Sanish req.ra_align_mask =
390223c35297Sanish PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */
390323c35297Sanish
390423c35297Sanish rval = ndi_ra_alloc(ddi_get_parent(new_child), &req,
390523c35297Sanish &mem_answer, &mem_alen, NDI_RA_TYPE_MEM, NDI_RA_PASS);
390623c35297Sanish
390723c35297Sanish if (rval != NDI_SUCCESS) {
390823c35297Sanish if (rval == NDI_RA_PARTIAL_REQ) {
390923c35297Sanish /*EMPTY*/
391023c35297Sanish DEBUG0("NDI_RA_PARTIAL_REQ returned\n");
391123c35297Sanish } else {
391223c35297Sanish DEBUG0(
391323c35297Sanish "Failed to allocate memory for bridge\n");
39145af4ae46Sjveta rval = PCICFG_NORESRC;
391523c35297Sanish goto cleanup;
391623c35297Sanish }
391723c35297Sanish }
391823c35297Sanish
391923c35297Sanish DEBUG3("Bridge Memory Allocated [0x%x.%x] len [0x%x]\n",
392023c35297Sanish PCICFG_HIADDR(mem_answer),
392123c35297Sanish PCICFG_LOADDR(mem_answer),
392223c35297Sanish mem_alen);
392323c35297Sanish
392423c35297Sanish /*
392523c35297Sanish * Put available memory into the pool.
392623c35297Sanish */
392723c35297Sanish (void) ndi_ra_free(new_child, mem_answer, mem_alen, NDI_RA_TYPE_MEM,
392823c35297Sanish NDI_RA_PASS);
392923c35297Sanish
393023c35297Sanish mem_base = mem_answer;
393123c35297Sanish
393223c35297Sanish /*
393323c35297Sanish * Allocate I/O Space for Bridge
393423c35297Sanish */
393523c35297Sanish bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
393623c35297Sanish req.ra_align_mask = PCICFG_IOGRAN - 1; /* 4k alignment */
393723c35297Sanish req.ra_boundbase = 0;
393823c35297Sanish req.ra_boundlen = PCICFG_4GIG_LIMIT;
393923c35297Sanish req.ra_flags = (NDI_RA_ALLOC_BOUNDED | NDI_RA_ALLOC_PARTIAL_OK);
394023c35297Sanish req.ra_len = PCICFG_4GIG_LIMIT; /* Get as big as possible */
394123c35297Sanish
394223c35297Sanish rval = ndi_ra_alloc(ddi_get_parent(new_child), &req, &io_answer,
394323c35297Sanish &io_alen, NDI_RA_TYPE_IO, NDI_RA_PASS);
394423c35297Sanish
394523c35297Sanish if (rval != NDI_SUCCESS) {
394623c35297Sanish if (rval == NDI_RA_PARTIAL_REQ) {
394723c35297Sanish /*EMPTY*/
394823c35297Sanish DEBUG0("NDI_RA_PARTIAL_REQ returned\n");
394923c35297Sanish } else {
395023c35297Sanish DEBUG0("Failed to allocate io space for bridge\n");
395123c35297Sanish /* i/o space is an optional requirement so continue */
395223c35297Sanish }
395323c35297Sanish }
395423c35297Sanish
395523c35297Sanish DEBUG3("Bridge IO Space Allocated [0x%x.%x] len [0x%x]\n",
395623c35297Sanish PCICFG_HIADDR(io_answer), PCICFG_LOADDR(io_answer), io_alen);
395723c35297Sanish
395823c35297Sanish /*
395923c35297Sanish * Put available I/O into the pool.
396023c35297Sanish */
396123c35297Sanish (void) ndi_ra_free(new_child, io_answer, io_alen, NDI_RA_TYPE_IO,
396223c35297Sanish NDI_RA_PASS);
396323c35297Sanish
396423c35297Sanish io_base = io_answer;
396523c35297Sanish
396623c35297Sanish /*
396723c35297Sanish * Check if the bridge supports Prefetchable memory range.
396823c35297Sanish * If it does, then we setup PF memory range for the bridge.
396923c35297Sanish * Otherwise, we skip the step of setting up PF memory
397023c35297Sanish * range for it. This could cause config operation to
397123c35297Sanish * fail if any devices under the bridge need PF memory.
397223c35297Sanish */
397323c35297Sanish /* write a non zero value to the PF BASE register */
397423c35297Sanish pci_config_put16(h, PCI_BCNF_PF_BASE_LOW, 0xfff0);
397523c35297Sanish /* if the read returns zero then PF range is not supported */
397623c35297Sanish if (pci_config_get16(h, PCI_BCNF_PF_BASE_LOW) == 0) {
397723c35297Sanish /* bridge doesn't support PF memory range */
397823c35297Sanish goto pf_setup_end;
397923c35297Sanish } else {
398023c35297Sanish pf_mem_supported = 1;
398123c35297Sanish /* reset the PF BASE register */
398223c35297Sanish pci_config_put16(h, PCI_BCNF_PF_BASE_LOW, 0);
398323c35297Sanish }
398423c35297Sanish
398523c35297Sanish /*
398623c35297Sanish * Bridge supports PF mem range; Allocate PF Memory Space for it.
398723c35297Sanish *
398823c35297Sanish * Note: Both non-prefetchable and prefetchable memory space
398923c35297Sanish * allocations are made within 32bit space. Currently, BIOSs
399023c35297Sanish * allocate device memory for PCI devices within the 32bit space
399123c35297Sanish * so this will not be a problem.
399223c35297Sanish */
399323c35297Sanish bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
399423c35297Sanish req.ra_flags = NDI_RA_ALLOC_PARTIAL_OK | NDI_RA_ALLOC_BOUNDED;
399523c35297Sanish req.ra_boundbase = 0;
399623c35297Sanish req.ra_len = PCICFG_4GIG_LIMIT; /* Get as big as possible */
399723c35297Sanish req.ra_align_mask =
399823c35297Sanish PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */
399923c35297Sanish
400023c35297Sanish rval = ndi_ra_alloc(ddi_get_parent(new_child), &req,
400123c35297Sanish &pf_mem_answer, &pf_mem_alen, NDI_RA_TYPE_PCI_PREFETCH_MEM,
400223c35297Sanish NDI_RA_PASS);
400323c35297Sanish
400423c35297Sanish if (rval != NDI_SUCCESS) {
400523c35297Sanish if (rval == NDI_RA_PARTIAL_REQ) {
400623c35297Sanish /*EMPTY*/
400723c35297Sanish DEBUG0("NDI_RA_PARTIAL_REQ returned\n");
400823c35297Sanish } else {
400923c35297Sanish DEBUG0(
401023c35297Sanish "Failed to allocate PF memory for bridge\n");
401123c35297Sanish /* PF mem is an optional requirement so continue */
401223c35297Sanish }
401323c35297Sanish }
401423c35297Sanish
401523c35297Sanish DEBUG3("Bridge PF Memory Allocated [0x%x.%x] len [0x%x]\n",
401623c35297Sanish PCICFG_HIADDR(pf_mem_answer),
401723c35297Sanish PCICFG_LOADDR(pf_mem_answer),
401823c35297Sanish pf_mem_alen);
401923c35297Sanish
402023c35297Sanish /*
402123c35297Sanish * Put available PF memory into the pool.
402223c35297Sanish */
402323c35297Sanish (void) ndi_ra_free(new_child, pf_mem_answer, pf_mem_alen,
402423c35297Sanish NDI_RA_TYPE_PCI_PREFETCH_MEM, NDI_RA_PASS);
402523c35297Sanish
402623c35297Sanish pf_mem_base = pf_mem_answer;
402723c35297Sanish
402823c35297Sanish /*
402923c35297Sanish * Program the PF memory base register with the
403023c35297Sanish * start of the memory range
403123c35297Sanish */
403223c35297Sanish pci_config_put16(h, PCI_BCNF_PF_BASE_LOW,
403323c35297Sanish PCICFG_HIWORD(PCICFG_LOADDR(pf_mem_answer)));
403423c35297Sanish pci_config_put32(h, PCI_BCNF_PF_BASE_HIGH,
403523c35297Sanish PCICFG_HIADDR(pf_mem_answer));
403623c35297Sanish
403723c35297Sanish /*
403823c35297Sanish * Program the PF memory limit register with the
403923c35297Sanish * end of the memory range.
404023c35297Sanish */
404123c35297Sanish pci_config_put16(h, PCI_BCNF_PF_LIMIT_LOW,
404223c35297Sanish PCICFG_HIWORD(PCICFG_LOADDR(
404323c35297Sanish PCICFG_ROUND_DOWN((pf_mem_answer + pf_mem_alen),
404423c35297Sanish PCICFG_MEMGRAN) - 1)));
404523c35297Sanish pci_config_put32(h, PCI_BCNF_PF_LIMIT_HIGH,
404623c35297Sanish PCICFG_HIADDR(PCICFG_ROUND_DOWN((pf_mem_answer + pf_mem_alen),
404723c35297Sanish PCICFG_MEMGRAN) - 1));
404823c35297Sanish
404923c35297Sanish /*
405023c35297Sanish * Allocate the chunk of PF memory (if any) not programmed into the
405123c35297Sanish * bridge because of the round down.
405223c35297Sanish */
405323c35297Sanish if (PCICFG_ROUND_DOWN((pf_mem_answer + pf_mem_alen), PCICFG_MEMGRAN)
405423c35297Sanish != (pf_mem_answer + pf_mem_alen)) {
405523c35297Sanish DEBUG0("Need to allocate Memory round off chunk\n");
405623c35297Sanish bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
405723c35297Sanish req.ra_flags = NDI_RA_ALLOC_SPECIFIED;
405823c35297Sanish req.ra_addr = PCICFG_ROUND_DOWN((pf_mem_answer + pf_mem_alen),
405923c35297Sanish PCICFG_MEMGRAN);
406023c35297Sanish req.ra_len = (pf_mem_answer + pf_mem_alen) -
406123c35297Sanish (PCICFG_ROUND_DOWN((pf_mem_answer + pf_mem_alen),
406223c35297Sanish PCICFG_MEMGRAN));
406323c35297Sanish
406423c35297Sanish (void) ndi_ra_alloc(new_child, &req,
406523c35297Sanish &round_answer, &round_len, NDI_RA_TYPE_PCI_PREFETCH_MEM,
406623c35297Sanish NDI_RA_PASS);
406723c35297Sanish }
406823c35297Sanish
406923c35297Sanish pf_setup_end:
407023c35297Sanish
407123c35297Sanish /*
407223c35297Sanish * Program the memory base register with the
407323c35297Sanish * start of the memory range
407423c35297Sanish */
407523c35297Sanish pci_config_put16(h, PCI_BCNF_MEM_BASE,
407623c35297Sanish PCICFG_HIWORD(PCICFG_LOADDR(mem_answer)));
407723c35297Sanish
407823c35297Sanish /*
407923c35297Sanish * Program the memory limit register with the
408023c35297Sanish * end of the memory range.
408123c35297Sanish */
408223c35297Sanish
408323c35297Sanish pci_config_put16(h, PCI_BCNF_MEM_LIMIT,
408423c35297Sanish PCICFG_HIWORD(PCICFG_LOADDR(
408523c35297Sanish PCICFG_ROUND_DOWN((mem_answer + mem_alen), PCICFG_MEMGRAN) - 1)));
408623c35297Sanish
408723c35297Sanish /*
408823c35297Sanish * Allocate the chunk of memory (if any) not programmed into the
408923c35297Sanish * bridge because of the round down.
409023c35297Sanish */
409123c35297Sanish if (PCICFG_ROUND_DOWN((mem_answer + mem_alen), PCICFG_MEMGRAN)
409223c35297Sanish != (mem_answer + mem_alen)) {
409323c35297Sanish DEBUG0("Need to allocate Memory round off chunk\n");
409423c35297Sanish bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
409523c35297Sanish req.ra_flags = NDI_RA_ALLOC_SPECIFIED;
409623c35297Sanish req.ra_addr = PCICFG_ROUND_DOWN((mem_answer + mem_alen),
409723c35297Sanish PCICFG_MEMGRAN);
409823c35297Sanish req.ra_len = (mem_answer + mem_alen) -
409923c35297Sanish (PCICFG_ROUND_DOWN((mem_answer + mem_alen),
410023c35297Sanish PCICFG_MEMGRAN));
410123c35297Sanish
410223c35297Sanish (void) ndi_ra_alloc(new_child, &req,
410323c35297Sanish &round_answer, &round_len, NDI_RA_TYPE_MEM, NDI_RA_PASS);
410423c35297Sanish }
410523c35297Sanish
410623c35297Sanish /*
410723c35297Sanish * Program the I/O Space Base
410823c35297Sanish */
410923c35297Sanish pci_config_put8(h, PCI_BCNF_IO_BASE_LOW,
411023c35297Sanish PCICFG_HIBYTE(PCICFG_LOWORD(
411123c35297Sanish PCICFG_LOADDR(io_answer))));
411223c35297Sanish
411323c35297Sanish pci_config_put16(h, PCI_BCNF_IO_BASE_HI,
411423c35297Sanish PCICFG_HIWORD(PCICFG_LOADDR(io_answer)));
411523c35297Sanish
411623c35297Sanish /*
411723c35297Sanish * Program the I/O Space Limit
411823c35297Sanish */
411923c35297Sanish pci_config_put8(h, PCI_BCNF_IO_LIMIT_LOW,
412023c35297Sanish PCICFG_HIBYTE(PCICFG_LOWORD(
412123c35297Sanish PCICFG_LOADDR(PCICFG_ROUND_DOWN(io_answer + io_alen,
412223c35297Sanish PCICFG_IOGRAN)))) - 1);
412323c35297Sanish
412423c35297Sanish pci_config_put16(h, PCI_BCNF_IO_LIMIT_HI,
412523c35297Sanish PCICFG_HIWORD(PCICFG_LOADDR(
412623c35297Sanish PCICFG_ROUND_DOWN(io_answer + io_alen, PCICFG_IOGRAN)))
412723c35297Sanish - 1);
412823c35297Sanish
412923c35297Sanish /*
413023c35297Sanish * Allocate the chunk of I/O (if any) not programmed into the
413123c35297Sanish * bridge because of the round down.
413223c35297Sanish */
413323c35297Sanish if (PCICFG_ROUND_DOWN((io_answer + io_alen), PCICFG_IOGRAN)
413423c35297Sanish != (io_answer + io_alen)) {
413523c35297Sanish DEBUG0("Need to allocate I/O round off chunk\n");
413623c35297Sanish bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
413723c35297Sanish req.ra_flags = NDI_RA_ALLOC_SPECIFIED;
413823c35297Sanish req.ra_addr = PCICFG_ROUND_DOWN((io_answer + io_alen),
413923c35297Sanish PCICFG_IOGRAN);
414023c35297Sanish req.ra_len = (io_answer + io_alen) -
414123c35297Sanish (PCICFG_ROUND_DOWN((io_answer + io_alen),
414223c35297Sanish PCICFG_IOGRAN));
414323c35297Sanish
414423c35297Sanish (void) ndi_ra_alloc(new_child, &req,
414523c35297Sanish &round_answer, &round_len, NDI_RA_TYPE_IO, NDI_RA_PASS);
414623c35297Sanish }
414723c35297Sanish
414823c35297Sanish (void) pcicfg_set_bus_numbers(h, bus, new_bus, max_bus);
414923c35297Sanish
415023c35297Sanish /*
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
41783f9ec228SZhi-Jun Robin Fu /*
417923c35297Sanish * Reset the secondary bus
418023c35297Sanish */
418123c35297Sanish pci_config_put16(h, PCI_BCNF_BCNTRL,
418223c35297Sanish pci_config_get16(h, PCI_BCNF_BCNTRL) | 0x40);
418323c35297Sanish
418423c35297Sanish drv_usecwait(100);
418523c35297Sanish
418623c35297Sanish pci_config_put16(h, PCI_BCNF_BCNTRL,
418723c35297Sanish pci_config_get16(h, PCI_BCNF_BCNTRL) & ~0x40);
418823c35297Sanish
418923c35297Sanish /*
419023c35297Sanish * Clear status bits
419123c35297Sanish */
419223c35297Sanish pci_config_put16(h, PCI_BCNF_SEC_STATUS, 0xffff);
419323c35297Sanish
419423c35297Sanish /*
419523c35297Sanish * Needs to be set to this value
419623c35297Sanish */
419723c35297Sanish pci_config_put8(h, PCI_CONF_ILINE, 0xf);
419823c35297Sanish
419923c35297Sanish /* check our device_type as defined by Open Firmware */
420023c35297Sanish if (pcicfg_pcie_device_type(new_child, h) == DDI_SUCCESS)
420123c35297Sanish pcie_device_type = 1;
420223c35297Sanish
420323c35297Sanish /*
420423c35297Sanish * Set bus properties
420523c35297Sanish */
420623c35297Sanish if (pcicfg_set_busnode_props(new_child, pcie_device_type)
420723c35297Sanish != PCICFG_SUCCESS) {
420823c35297Sanish DEBUG0("Failed to set busnode props\n");
420923c35297Sanish rval = PCICFG_FAILURE;
421023c35297Sanish goto cleanup;
421123c35297Sanish }
421223c35297Sanish
421323c35297Sanish (void) pcicfg_device_on(h);
421423c35297Sanish
4215c0da6274SZhi-Jun Robin Fu if (is_pcie)
4216c1374a13SSurya Prakki (void) pcie_init_bus(new_child, 0, PCIE_BUS_FINAL);
421723c35297Sanish if (ndi_devi_online(new_child, NDI_NO_EVENT|NDI_CONFIG)
421823c35297Sanish != NDI_SUCCESS) {
421923c35297Sanish DEBUG0("Unable to online bridge\n");
422023c35297Sanish rval = PCICFG_FAILURE;
422123c35297Sanish goto cleanup;
422223c35297Sanish }
422323c35297Sanish
422423c35297Sanish DEBUG0("Bridge is ONLINE\n");
422523c35297Sanish
422623c35297Sanish /*
422723c35297Sanish * After a Reset, we need to wait 2^25 clock cycles before the
422823c35297Sanish * first Configuration access. The worst case is 33MHz, which
422923c35297Sanish * is a 1 second wait.
423023c35297Sanish */
423123c35297Sanish drv_usecwait(pcicfg_sec_reset_delay);
423223c35297Sanish
423323c35297Sanish /*
423423c35297Sanish * Probe all children devices
423523c35297Sanish */
423623c35297Sanish 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
424623c35297Sanish 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) {
424923c35297Sanish if (rval == PCICFG_NODEVICE) {
425023c35297Sanish DEBUG3("No Device at bus [0x%x]"
425123c35297Sanish "device [0x%x] "
425226947304SEvan Yan "func [0x%x]\n", new_bus,
425326947304SEvan Yan trans_device, j & 7);
425426947304SEvan Yan
425523c35297Sanish if (j)
425626947304SEvan Yan goto next;
425723c35297Sanish } else
425823c35297Sanish /*EMPTY*/
425923c35297Sanish DEBUG3("Failed to configure bus "
426023c35297Sanish "[0x%x] device [0x%x] "
426126947304SEvan Yan "func [0x%x]\n", new_bus,
426226947304SEvan Yan trans_device, j & 7);
426323c35297Sanish break;
426423c35297Sanish }
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
431023c35297Sanish }
431123c35297Sanish /* if any function fails to be configured, no need to proceed */
431223c35297Sanish if (rval != PCICFG_NODEVICE)
431323c35297Sanish break;
431423c35297Sanish }
43153fe80ca4SDan Cross ndi_devi_exit(new_child);
431623c35297Sanish
431723c35297Sanish /*
431823c35297Sanish * 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.
432523c35297Sanish */
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);
433023c35297Sanish
433123c35297Sanish phdl.dip = new_child;
433223c35297Sanish phdl.memory_base = mem_answer;
433323c35297Sanish phdl.io_base = io_answer;
433423c35297Sanish phdl.pf_memory_base = pf_mem_answer;
433523c35297Sanish phdl.error = PCICFG_SUCCESS; /* in case of empty child tree */
433623c35297Sanish
43373fe80ca4SDan Cross ndi_devi_enter(ddi_get_parent(new_child));
433823c35297Sanish ddi_walk_devs(new_child, pcicfg_find_resource_end, (void *)&phdl);
43393fe80ca4SDan Cross ndi_devi_exit(ddi_get_parent(new_child));
434023c35297Sanish
434123c35297Sanish num_slots = pcicfg_get_nslots(new_child, h);
434223c35297Sanish mem_end = PCICFG_ROUND_UP(phdl.memory_base, PCICFG_MEMGRAN);
434323c35297Sanish io_end = PCICFG_ROUND_UP(phdl.io_base, PCICFG_IOGRAN);
434423c35297Sanish pf_mem_end = PCICFG_ROUND_UP(phdl.pf_memory_base, PCICFG_MEMGRAN);
434523c35297Sanish
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);
434823c35297Sanish
434923c35297Sanish /*
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");
436026947304SEvan Yan /*
436123c35297Sanish * if the bridge a slots, then preallocate. If not, assume static
436223c35297Sanish * configuration. Also check for preallocation limits and spit
436323c35297Sanish * warning messages appropriately (perhaps some can be in debug mode).
436423c35297Sanish */
436523c35297Sanish 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
437523c35297Sanish if (mem_end > mem_reqd)
4376949b8557Sarutz DEBUG3("Memory space consumed by bridge more "
437723c35297Sanish "than planned for %d slot(s)(%" PRIx64 ",%"
437823c35297Sanish PRIx64 ")", num_slots, mem_answer, mem_end);
437923c35297Sanish if (io_end > io_reqd)
4380949b8557Sarutz DEBUG3("IO space consumed by bridge more than"
438123c35297Sanish " planned for %d slot(s)(%" PRIx64 ",%" PRIx64 ")",
438223c35297Sanish num_slots, io_answer, io_end);
438323c35297Sanish if (pf_mem_end > pf_mem_reqd)
4384949b8557Sarutz DEBUG3("PF Memory space consumed by bridge"
438523c35297Sanish " more than planned for %d slot(s)(%" PRIx64 ",%"
438623c35297Sanish PRIx64 ")", num_slots, pf_mem_answer, pf_mem_end);
438723c35297Sanish if (*highest_bus > highest_bus_reqd)
4388949b8557Sarutz DEBUG3("Buses consumed by bridge more "
438923c35297Sanish "than planned for %d slot(s)(%x, %x)",
439023c35297Sanish num_slots, new_bus, *highest_bus);
439123c35297Sanish
439223c35297Sanish if (mem_reqd > (mem_answer + mem_alen))
4393949b8557Sarutz DEBUG3("Memory space required by bridge more "
439423c35297Sanish "than available for %d slot(s)(%" PRIx64 ",%"
439523c35297Sanish PRIx64 ")", num_slots, mem_answer, mem_end);
439623c35297Sanish if (io_reqd > (io_answer + io_alen))
4397949b8557Sarutz DEBUG3("IO space required by bridge more than"
439823c35297Sanish "available for %d slot(s)(%" PRIx64 ",%" PRIx64 ")",
439923c35297Sanish num_slots, io_answer, io_end);
440023c35297Sanish if (pf_mem_reqd > (pf_mem_answer + pf_mem_alen))
4401949b8557Sarutz DEBUG3("PF Memory space required by bridge"
440223c35297Sanish " more than available for %d slot(s)(%" PRIx64 ",%"
440323c35297Sanish PRIx64 ")", num_slots, pf_mem_answer, pf_mem_end);
440423c35297Sanish if (highest_bus_reqd > max_bus)
4405949b8557Sarutz DEBUG3("Bus numbers required by bridge more "
440623c35297Sanish "than available for %d slot(s)(%x, %x)",
440723c35297Sanish num_slots, new_bus, *highest_bus);
4408949b8557Sarutz #endif
440923c35297Sanish mem_end = MAX((MIN(mem_reqd, (mem_answer + mem_alen))),
441023c35297Sanish mem_end);
441123c35297Sanish io_end = MAX((MIN(io_reqd, (io_answer + io_alen))), io_end);
441223c35297Sanish pf_mem_end = MAX((MIN(pf_mem_reqd, (pf_mem_answer +
441323c35297Sanish pf_mem_alen))), pf_mem_end);
441423c35297Sanish *highest_bus = MAX((MIN(highest_bus_reqd, max_bus)),
441523c35297Sanish *highest_bus);
441623c35297Sanish 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);
441923c35297Sanish }
442023c35297Sanish
442123c35297Sanish /*
442223c35297Sanish * Give back unused memory space to parent.
442323c35297Sanish */
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);
442623c35297Sanish
442723c35297Sanish if (mem_end == mem_answer) {
442823c35297Sanish DEBUG0("No memory resources used\n");
442923c35297Sanish /*
443023c35297Sanish * To prevent the bridge from forwarding any Memory
443123c35297Sanish * transactions, the Memory Limit will be programmed
443223c35297Sanish * with a smaller value than the Memory Base.
443323c35297Sanish */
443423c35297Sanish pci_config_put16(h, PCI_BCNF_MEM_BASE, 0xffff);
443523c35297Sanish pci_config_put16(h, PCI_BCNF_MEM_LIMIT, 0);
443623c35297Sanish
443723c35297Sanish mem_size = 0;
443823c35297Sanish } else {
443923c35297Sanish /*
444023c35297Sanish * Reprogram the end of the memory.
444123c35297Sanish */
444223c35297Sanish pci_config_put16(h, PCI_BCNF_MEM_LIMIT,
444323c35297Sanish PCICFG_HIWORD(mem_end) - 1);
444423c35297Sanish mem_size = mem_end - mem_base;
444523c35297Sanish }
444623c35297Sanish
444723c35297Sanish /*
444823c35297Sanish * Give back unused io space to parent.
444923c35297Sanish */
445023c35297Sanish (void) ndi_ra_free(ddi_get_parent(new_child),
445123c35297Sanish io_end, (io_answer + io_alen) - io_end,
445223c35297Sanish NDI_RA_TYPE_IO, NDI_RA_PASS);
445323c35297Sanish
445423c35297Sanish if (io_end == io_answer) {
445523c35297Sanish DEBUG0("No IO Space resources used\n");
445623c35297Sanish
445723c35297Sanish /*
445823c35297Sanish * To prevent the bridge from forwarding any I/O
445923c35297Sanish * transactions, the I/O Limit will be programmed
446023c35297Sanish * with a smaller value than the I/O Base.
446123c35297Sanish */
446223c35297Sanish pci_config_put8(h, PCI_BCNF_IO_LIMIT_LOW, 0);
446323c35297Sanish pci_config_put16(h, PCI_BCNF_IO_LIMIT_HI, 0);
446423c35297Sanish pci_config_put8(h, PCI_BCNF_IO_BASE_LOW, 0xff);
446523c35297Sanish pci_config_put16(h, PCI_BCNF_IO_BASE_HI, 0);
446623c35297Sanish
446723c35297Sanish io_size = 0;
446823c35297Sanish } else {
446923c35297Sanish /*
447023c35297Sanish * Reprogram the end of the io space.
447123c35297Sanish */
447223c35297Sanish pci_config_put8(h, PCI_BCNF_IO_LIMIT_LOW,
447323c35297Sanish PCICFG_HIBYTE(PCICFG_LOWORD(
447423c35297Sanish PCICFG_LOADDR(io_end) - 1)));
447523c35297Sanish
447623c35297Sanish pci_config_put16(h, PCI_BCNF_IO_LIMIT_HI,
447723c35297Sanish PCICFG_HIWORD(PCICFG_LOADDR(io_end - 1)));
447823c35297Sanish
447923c35297Sanish io_size = io_end - io_base;
448023c35297Sanish }
448123c35297Sanish
448223c35297Sanish /*
448323c35297Sanish * Give back unused PF memory space to parent.
448423c35297Sanish */
448523c35297Sanish if (pf_mem_supported) {
448623c35297Sanish (void) ndi_ra_free(ddi_get_parent(new_child),
448723c35297Sanish pf_mem_end, (pf_mem_answer + pf_mem_alen) - pf_mem_end,
448823c35297Sanish NDI_RA_TYPE_PCI_PREFETCH_MEM, NDI_RA_PASS);
448923c35297Sanish
449023c35297Sanish if (pf_mem_end == pf_mem_answer) {
449123c35297Sanish DEBUG0("No PF memory resources used\n");
449223c35297Sanish /*
449323c35297Sanish * To prevent the bridge from forwarding any PF Memory
449423c35297Sanish * transactions, the PF Memory Limit will be programmed
449523c35297Sanish * with a smaller value than the Memory Base.
449623c35297Sanish */
449723c35297Sanish pci_config_put16(h, PCI_BCNF_PF_BASE_LOW, 0xfff0);
449823c35297Sanish pci_config_put32(h, PCI_BCNF_PF_BASE_HIGH, 0xffffffff);
449923c35297Sanish pci_config_put16(h, PCI_BCNF_PF_LIMIT_LOW, 0);
450023c35297Sanish pci_config_put32(h, PCI_BCNF_PF_LIMIT_HIGH, 0);
450123c35297Sanish
450223c35297Sanish pf_mem_size = 0;
450323c35297Sanish } else {
450423c35297Sanish /*
450523c35297Sanish * Reprogram the end of the PF memory range.
450623c35297Sanish */
450723c35297Sanish pci_config_put16(h, PCI_BCNF_PF_LIMIT_LOW,
450823c35297Sanish PCICFG_HIWORD(PCICFG_LOADDR(pf_mem_end - 1)));
450923c35297Sanish pci_config_put32(h, PCI_BCNF_PF_LIMIT_HIGH,
451023c35297Sanish PCICFG_HIADDR(pf_mem_end - 1));
451123c35297Sanish pf_mem_size = pf_mem_end - pf_mem_base;
451223c35297Sanish }
451323c35297Sanish }
451423c35297Sanish
451523c35297Sanish if ((max_bus - *highest_bus) > 0) {
451623c35297Sanish /*
451723c35297Sanish * Give back unused bus numbers
451823c35297Sanish */
451923c35297Sanish (void) ndi_ra_free(ddi_get_parent(new_child),
452023c35297Sanish *highest_bus+1, max_bus - *highest_bus,
452123c35297Sanish NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS);
452223c35297Sanish }
452323c35297Sanish
452423c35297Sanish /*
452523c35297Sanish * Set bus numbers to ranges encountered during scan
452623c35297Sanish */
452723c35297Sanish (void) pcicfg_set_bus_numbers(h, bus, new_bus, *highest_bus);
452823c35297Sanish
452923c35297Sanish /*
453023c35297Sanish * Remove the ranges property if it exists since we will create
453123c35297Sanish * a new one.
453223c35297Sanish */
453323c35297Sanish (void) ndi_prop_remove(DDI_DEV_T_NONE, new_child, "ranges");
453423c35297Sanish
453523c35297Sanish DEBUG2("Creating Ranges property - Mem Address %lx Mem Size %x\n",
453623c35297Sanish mem_base, mem_size);
453723c35297Sanish DEBUG2(" - I/O Address %lx I/O Size %x\n",
453823c35297Sanish io_base, io_size);
453923c35297Sanish DEBUG2(" - PF Mem address %lx PF Mem Size %x\n",
454023c35297Sanish pf_mem_base, pf_mem_size);
454123c35297Sanish
454223c35297Sanish bzero((caddr_t)range, sizeof (ppb_ranges_t) * PCICFG_RANGE_LEN);
454323c35297Sanish
454423c35297Sanish range[0].child_high = range[0].parent_high |= (PCI_REG_REL_M |
454523c35297Sanish PCI_ADDR_IO);
454623c35297Sanish range[0].child_low = range[0].parent_low = io_base;
454723c35297Sanish range[1].child_high = range[1].parent_high |=
454823c35297Sanish (PCI_REG_REL_M | PCI_ADDR_MEM32);
454923c35297Sanish range[1].child_low = range[1].parent_low = mem_base;
455023c35297Sanish range[2].child_high = range[2].parent_high |=
455123c35297Sanish (PCI_REG_REL_M | PCI_ADDR_MEM64 | PCI_REG_PF_M);
455223c35297Sanish range[2].child_low = range[2].parent_low = pf_mem_base;
455323c35297Sanish
455423c35297Sanish if (io_size > 0) {
455523c35297Sanish range[0].size_low = io_size;
455623c35297Sanish (void) pcicfg_update_ranges_prop(new_child, &range[0]);
455723c35297Sanish }
455823c35297Sanish if (mem_size > 0) {
455923c35297Sanish range[1].size_low = mem_size;
456023c35297Sanish (void) pcicfg_update_ranges_prop(new_child, &range[1]);
456123c35297Sanish }
456223c35297Sanish if (pf_mem_size > 0) {
456323c35297Sanish range[2].size_low = pf_mem_size;
456423c35297Sanish (void) pcicfg_update_ranges_prop(new_child, &range[2]);
456523c35297Sanish }
456623c35297Sanish
456723c35297Sanish bus_range[0] = pci_config_get8(h, PCI_BCNF_SECBUS);
456823c35297Sanish bus_range[1] = pci_config_get8(h, PCI_BCNF_SUBBUS);
456923c35297Sanish DEBUG1("End of bridge probe: bus_range[0] = %d\n", bus_range[0]);
457023c35297Sanish DEBUG1("End of bridge probe: bus_range[1] = %d\n", bus_range[1]);
457123c35297Sanish
457223c35297Sanish (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, new_child,
457323c35297Sanish "bus-range", bus_range, 2);
457423c35297Sanish
457523c35297Sanish rval = PCICFG_SUCCESS;
457623c35297Sanish
457723c35297Sanish PCICFG_DUMP_BRIDGE_CONFIG(h);
457823c35297Sanish
457923c35297Sanish cleanup:
458023c35297Sanish /* free up resources (for error return case only) */
458123c35297Sanish if (rval != PCICFG_SUCCESS) {
458223c35297Sanish if (mem_alen)
458323c35297Sanish (void) ndi_ra_free(ddi_get_parent(new_child), mem_base,
458423c35297Sanish mem_alen, NDI_RA_TYPE_MEM, NDI_RA_PASS);
458523c35297Sanish if (io_alen)
458623c35297Sanish (void) ndi_ra_free(ddi_get_parent(new_child), io_base,
458723c35297Sanish io_alen, NDI_RA_TYPE_IO, NDI_RA_PASS);
458823c35297Sanish 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);
459223c35297Sanish 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);
459623c35297Sanish }
459723c35297Sanish
459823c35297Sanish /* free up any resource maps setup for the bridge node */
459923c35297Sanish (void) ndi_ra_map_destroy(new_child, NDI_RA_TYPE_PCI_BUSNUM);
460023c35297Sanish (void) ndi_ra_map_destroy(new_child, NDI_RA_TYPE_IO);
460123c35297Sanish (void) ndi_ra_map_destroy(new_child, NDI_RA_TYPE_MEM);
460223c35297Sanish (void) ndi_ra_map_destroy(new_child, NDI_RA_TYPE_PCI_PREFETCH_MEM);
460323c35297Sanish
460423c35297Sanish return (rval);
460523c35297Sanish }
460623c35297Sanish
460723c35297Sanish static int
pcicfg_find_resource_end(dev_info_t * dip,void * hdl)460823c35297Sanish pcicfg_find_resource_end(dev_info_t *dip, void *hdl)
460923c35297Sanish {
461023c35297Sanish pcicfg_phdl_t *entry = (pcicfg_phdl_t *)hdl;
461123c35297Sanish pci_regspec_t *pci_ap;
461223c35297Sanish int length;
461323c35297Sanish int rcount;
461423c35297Sanish int i;
461523c35297Sanish
461623c35297Sanish entry->error = PCICFG_SUCCESS;
461723c35297Sanish
461823c35297Sanish if (dip == entry->dip) {
461923c35297Sanish DEBUG0("Don't include parent bridge node\n");
462023c35297Sanish return (DDI_WALK_CONTINUE);
462123c35297Sanish } else {
462223c35297Sanish if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
462323c35297Sanish DDI_PROP_DONTPASS, "assigned-addresses",
462423c35297Sanish (caddr_t)&pci_ap, &length) != DDI_PROP_SUCCESS) {
462523c35297Sanish DEBUG0("Node doesn't have assigned-addresses\n");
462623c35297Sanish return (DDI_WALK_CONTINUE);
462723c35297Sanish }
462823c35297Sanish
462923c35297Sanish rcount = length / sizeof (pci_regspec_t);
463023c35297Sanish
463123c35297Sanish for (i = 0; i < rcount; i++) {
463223c35297Sanish
463323c35297Sanish switch (PCI_REG_ADDR_G(pci_ap[i].pci_phys_hi)) {
463423c35297Sanish
463523c35297Sanish case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
463623c35297Sanish if (pci_ap[i].pci_phys_hi & PCI_REG_PF_M) {
463723c35297Sanish if ((pci_ap[i].pci_phys_low +
463823c35297Sanish pci_ap[i].pci_size_low) >
463923c35297Sanish entry->pf_memory_base) {
464023c35297Sanish entry->pf_memory_base =
464123c35297Sanish pci_ap[i].pci_phys_low +
464223c35297Sanish pci_ap[i].pci_size_low;
464323c35297Sanish }
464423c35297Sanish } else {
464523c35297Sanish if ((pci_ap[i].pci_phys_low +
464623c35297Sanish pci_ap[i].pci_size_low) >
464723c35297Sanish entry->memory_base) {
464823c35297Sanish entry->memory_base =
464923c35297Sanish pci_ap[i].pci_phys_low +
465023c35297Sanish pci_ap[i].pci_size_low;
465123c35297Sanish }
465223c35297Sanish }
465323c35297Sanish break;
465423c35297Sanish case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
465523c35297Sanish if (pci_ap[i].pci_phys_hi & PCI_REG_PF_M) {
465626947304SEvan Yan if ((PCICFG_LADDR(
465726947304SEvan Yan pci_ap[i].pci_phys_low,
465823c35297Sanish pci_ap[i].pci_phys_mid) +
465923c35297Sanish pci_ap[i].pci_size_low) >
466023c35297Sanish entry->pf_memory_base) {
466126947304SEvan Yan entry->pf_memory_base =
466226947304SEvan Yan PCICFG_LADDR(
466323c35297Sanish pci_ap[i].pci_phys_low,
466423c35297Sanish pci_ap[i].pci_phys_mid) +
466523c35297Sanish pci_ap[i].pci_size_low;
466623c35297Sanish }
466723c35297Sanish } else {
466826947304SEvan Yan if ((PCICFG_LADDR(
466926947304SEvan Yan pci_ap[i].pci_phys_low,
467023c35297Sanish pci_ap[i].pci_phys_mid) +
467123c35297Sanish pci_ap[i].pci_size_low) >
467223c35297Sanish entry->memory_base) {
467326947304SEvan Yan entry->memory_base =
467426947304SEvan Yan PCICFG_LADDR(
467523c35297Sanish pci_ap[i].pci_phys_low,
467623c35297Sanish pci_ap[i].pci_phys_mid) +
467723c35297Sanish pci_ap[i].pci_size_low;
467823c35297Sanish }
467923c35297Sanish }
468023c35297Sanish break;
468123c35297Sanish case PCI_REG_ADDR_G(PCI_ADDR_IO):
468223c35297Sanish if ((pci_ap[i].pci_phys_low +
468323c35297Sanish pci_ap[i].pci_size_low) >
468423c35297Sanish entry->io_base) {
468523c35297Sanish entry->io_base =
468623c35297Sanish pci_ap[i].pci_phys_low +
468723c35297Sanish pci_ap[i].pci_size_low;
468823c35297Sanish }
468923c35297Sanish break;
469023c35297Sanish }
469123c35297Sanish }
469223c35297Sanish
469323c35297Sanish /*
469423c35297Sanish * free the memory allocated by ddi_getlongprop
469523c35297Sanish */
469623c35297Sanish kmem_free(pci_ap, length);
469723c35297Sanish
469823c35297Sanish /*
469923c35297Sanish * continue the walk to the next sibling to sum memory
470023c35297Sanish */
470123c35297Sanish return (DDI_WALK_CONTINUE);
470223c35297Sanish }
470323c35297Sanish }
470423c35297Sanish
470523c35297Sanish /*
470623c35297Sanish * Make "parent" be the parent of the "child" dip
470723c35297Sanish */
470823c35297Sanish static void
pcicfg_reparent_node(dev_info_t * child,dev_info_t * parent)470923c35297Sanish pcicfg_reparent_node(dev_info_t *child, dev_info_t *parent)
471023c35297Sanish {
471123c35297Sanish dev_info_t *opdip;
471223c35297Sanish
471323c35297Sanish ASSERT(i_ddi_node_state(child) <= DS_LINKED);
471423c35297Sanish /*
471523c35297Sanish * Unlink node from tree before reparenting
471623c35297Sanish */
471723c35297Sanish opdip = ddi_get_parent(child);
47183fe80ca4SDan Cross ndi_devi_enter(opdip);
471923c35297Sanish (void) i_ndi_unconfig_node(child, DS_PROTO, 0);
47203fe80ca4SDan Cross ndi_devi_exit(opdip);
472123c35297Sanish
472223c35297Sanish DEVI(child)->devi_parent = DEVI(parent);
472323c35297Sanish DEVI(child)->devi_bus_ctl = DEVI(parent);
472423c35297Sanish (void) ndi_devi_bind_driver(child, 0);
472523c35297Sanish }
472623c35297Sanish
472723c35297Sanish /*
472823c35297Sanish * Return PCICFG_SUCCESS if device exists at the specified address.
472923c35297Sanish * Return PCICFG_NODEVICE is no device exists at the specified address.
473023c35297Sanish */
473123c35297Sanish int
pcicfg_config_setup(dev_info_t * dip,ddi_acc_handle_t * handle)473223c35297Sanish pcicfg_config_setup(dev_info_t *dip, ddi_acc_handle_t *handle)
473323c35297Sanish {
473423c35297Sanish caddr_t cfgaddr;
473523c35297Sanish ddi_device_acc_attr_t attr;
473623c35297Sanish dev_info_t *anode;
473723c35297Sanish int status;
473823c35297Sanish int rlen;
473923c35297Sanish pci_regspec_t *reg;
474023c35297Sanish int ret = DDI_SUCCESS;
474123c35297Sanish int16_t tmp;
474223c35297Sanish
474323c35297Sanish /*
474423c35297Sanish * Get the pci register spec from the node
474523c35297Sanish */
474626947304SEvan Yan status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg",
474726947304SEvan Yan (caddr_t)®, &rlen);
474823c35297Sanish
474923c35297Sanish switch (status) {
475023c35297Sanish case DDI_PROP_SUCCESS:
475123c35297Sanish break;
475223c35297Sanish case DDI_PROP_NO_MEMORY:
475323c35297Sanish DEBUG0("reg present, but unable to get memory\n");
475423c35297Sanish return (PCICFG_FAILURE);
475523c35297Sanish default:
475623c35297Sanish DEBUG0("no reg property\n");
475723c35297Sanish return (PCICFG_FAILURE);
475823c35297Sanish }
475923c35297Sanish
476023c35297Sanish anode = dip;
476123c35297Sanish DEBUG2("conf_map: dip=%p, anode=%p\n", dip, anode);
476223c35297Sanish
476323c35297Sanish attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
476423c35297Sanish attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
476523c35297Sanish attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
476623c35297Sanish
476726947304SEvan Yan if (ddi_regs_map_setup(anode, 0, &cfgaddr, 0, 0, &attr, handle)
476826947304SEvan Yan != DDI_SUCCESS) {
476923c35297Sanish DEBUG0("Failed to setup registers\n");
477023c35297Sanish kmem_free((caddr_t)reg, rlen);
477123c35297Sanish return (PCICFG_FAILURE);
477223c35297Sanish }
477323c35297Sanish
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;
478223c35297Sanish } else {
478323c35297Sanish if (tmp == 0) {
478423c35297Sanish DEBUG0("Device Not Ready yet ?");
478523c35297Sanish ret = PCICFG_NODEVICE;
478623c35297Sanish } else {
478723c35297Sanish DEBUG1("DEVICEFOUND, read %x\n", tmp);
478823c35297Sanish ret = PCICFG_SUCCESS;
478923c35297Sanish }
479023c35297Sanish }
479123c35297Sanish
479223c35297Sanish if (ret == PCICFG_NODEVICE)
479323c35297Sanish ddi_regs_map_free(handle);
479423c35297Sanish kmem_free((caddr_t)reg, rlen);
479523c35297Sanish
479623c35297Sanish return (ret);
479723c35297Sanish
479823c35297Sanish }
479923c35297Sanish
480023c35297Sanish static void
pcicfg_config_teardown(ddi_acc_handle_t * handle)480123c35297Sanish pcicfg_config_teardown(ddi_acc_handle_t *handle)
480223c35297Sanish {
480323c35297Sanish (void) ddi_regs_map_free(handle);
480423c35297Sanish }
480523c35297Sanish
480623c35297Sanish static int
pcicfg_add_config_reg(dev_info_t * dip,uint_t bus,uint_t device,uint_t func)480723c35297Sanish pcicfg_add_config_reg(dev_info_t *dip,
480823c35297Sanish uint_t bus, uint_t device, uint_t func)
480923c35297Sanish {
481023c35297Sanish int reg[10] = { PCI_ADDR_CONFIG, 0, 0, 0, 0};
481123c35297Sanish
481223c35297Sanish reg[0] = PCICFG_MAKE_REG_HIGH(bus, device, func, 0);
481323c35297Sanish
481426947304SEvan Yan return (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "reg", reg, 5));
481523c35297Sanish }
481623c35297Sanish
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
483123c35297Sanish #ifdef DEBUG
483223c35297Sanish 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)
483523c35297Sanish {
483623c35297Sanish if (pcicfg_debug > 1) {
483723c35297Sanish prom_printf("pcicfg: ");
483823c35297Sanish prom_printf(fmt, a1, a2, a3, a4, a5);
483923c35297Sanish }
484023c35297Sanish }
484123c35297Sanish #endif
484223c35297Sanish
484323c35297Sanish /*ARGSUSED*/
484423c35297Sanish static uint8_t
pcicfg_get_nslots(dev_info_t * dip,ddi_acc_handle_t handle)484523c35297Sanish pcicfg_get_nslots(dev_info_t *dip, ddi_acc_handle_t handle)
484623c35297Sanish {
484749fbdd30SErwin T Tsaur uint16_t cap_id_loc, slot_id_loc;
484823c35297Sanish uint8_t num_slots = 0;
484923c35297Sanish
485023c35297Sanish /* 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) &
485523c35297Sanish PCIE_PCIECAP_SLOT_IMPL)
485623c35297Sanish num_slots = 1;
485723c35297Sanish } 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);
486023c35297Sanish num_slots = PCI_CAPSLOT_NSLOTS(esr_reg);
486123c35297Sanish }
486223c35297Sanish /* XXX - need to cover PCI-PCIe bridge with n slots */
486323c35297Sanish return (num_slots);
486423c35297Sanish }
486523c35297Sanish
486623c35297Sanish static int
pcicfg_pcie_device_type(dev_info_t * dip,ddi_acc_handle_t handle)486723c35297Sanish pcicfg_pcie_device_type(dev_info_t *dip, ddi_acc_handle_t handle)
486823c35297Sanish {
486923c35297Sanish int port_type = pcicfg_pcie_port_type(dip, handle);
487023c35297Sanish
487123c35297Sanish DEBUG1("device port_type = %x\n", port_type);
487223c35297Sanish /* No PCIe CAP regs, we are not PCIe device_type */
487323c35297Sanish if (port_type < 0)
487423c35297Sanish return (DDI_FAILURE);
487523c35297Sanish
487623c35297Sanish /* check for all PCIe device_types */
487723c35297Sanish if ((port_type == PCIE_PCIECAP_DEV_TYPE_UP) ||
487823c35297Sanish (port_type == PCIE_PCIECAP_DEV_TYPE_DOWN) ||
487923c35297Sanish (port_type == PCIE_PCIECAP_DEV_TYPE_ROOT) ||
488023c35297Sanish (port_type == PCIE_PCIECAP_DEV_TYPE_PCI2PCIE))
488123c35297Sanish return (DDI_SUCCESS);
488223c35297Sanish
488323c35297Sanish return (DDI_FAILURE);
488423c35297Sanish
488523c35297Sanish }
488623c35297Sanish
488723c35297Sanish /*ARGSUSED*/
488823c35297Sanish static int
pcicfg_pcie_port_type(dev_info_t * dip,ddi_acc_handle_t handle)488923c35297Sanish pcicfg_pcie_port_type(dev_info_t *dip, ddi_acc_handle_t handle)
489023c35297Sanish {
489123c35297Sanish int port_type = -1;
489249fbdd30SErwin T Tsaur uint16_t cap_loc;
489323c35297Sanish
489423c35297Sanish /* 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)
489723c35297Sanish port_type = pci_config_get16(handle,
489823c35297Sanish cap_loc + PCIE_PCIECAP) & PCIE_PCIECAP_DEV_TYPE_MASK;
489923c35297Sanish
490023c35297Sanish return (port_type);
490123c35297Sanish }
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