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 /*
22*7f59ab1cSAlan Adamson, SD OSSD * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
2323c35297Sanish */
2423c35297Sanish
2523c35297Sanish /*
2623c35297Sanish * PCI configurator (pcicfg)
2723c35297Sanish */
2823c35297Sanish
2923c35297Sanish #include <sys/sysmacros.h>
3023c35297Sanish #include <sys/conf.h>
3123c35297Sanish #include <sys/kmem.h>
3223c35297Sanish #include <sys/debug.h>
3323c35297Sanish #include <sys/modctl.h>
3423c35297Sanish #include <sys/autoconf.h>
3523c35297Sanish #include <sys/hwconf.h>
3623c35297Sanish #include <sys/pcie.h>
3726947304SEvan Yan #include <sys/pcie_impl.h>
3849fbdd30SErwin T Tsaur #include <sys/pci_cap.h>
3923c35297Sanish #include <sys/ddi.h>
4023c35297Sanish #include <sys/sunndi.h>
4123c35297Sanish #include <sys/hotplug/pci/pcicfg.h>
4223c35297Sanish #include <sys/ndi_impldefs.h>
43c0da6274SZhi-Jun Robin Fu #include <sys/pci_cfgacc.h>
44c0da6274SZhi-Jun Robin Fu #include <sys/pcie_impl.h>
4523c35297Sanish
4623c35297Sanish /*
4723c35297Sanish * ************************************************************************
4823c35297Sanish * *** Implementation specific local data structures/definitions. ***
4923c35297Sanish * ************************************************************************
5023c35297Sanish */
5123c35297Sanish
5223c35297Sanish static int pcicfg_start_devno = 0; /* for Debug only */
5323c35297Sanish
5426947304SEvan Yan #define PCICFG_MAX_ARI_FUNCTION 256
5526947304SEvan Yan
5623c35297Sanish #define PCICFG_NODEVICE 42
5723c35297Sanish #define PCICFG_NOMEMORY 43
5823c35297Sanish #define PCICFG_NOMULTI 44
595af4ae46Sjveta #define PCICFG_NORESRC 45
6023c35297Sanish
6123c35297Sanish #define PCICFG_HIADDR(n) ((uint32_t)(((uint64_t)(n) & \
6223c35297Sanish 0xFFFFFFFF00000000ULL)>> 32))
6323c35297Sanish #define PCICFG_LOADDR(n) ((uint32_t)((uint64_t)(n) & 0x00000000FFFFFFFF))
6423c35297Sanish #define PCICFG_LADDR(lo, hi) (((uint64_t)(hi) << 32) | (uint32_t)(lo))
6523c35297Sanish
6623c35297Sanish #define PCICFG_HIWORD(n) ((uint16_t)(((uint32_t)(n) & 0xFFFF0000)>> 16))
6723c35297Sanish #define PCICFG_LOWORD(n) ((uint16_t)((uint32_t)(n) & 0x0000FFFF))
6823c35297Sanish #define PCICFG_HIBYTE(n) ((uint8_t)(((uint16_t)(n) & 0xFF00)>> 8))
6923c35297Sanish #define PCICFG_LOBYTE(n) ((uint8_t)((uint16_t)(n) & 0x00FF))
7023c35297Sanish
7123c35297Sanish #define PCICFG_ROUND_UP(addr, gran) ((uintptr_t)((gran+addr-1)&(~(gran-1))))
7223c35297Sanish #define PCICFG_ROUND_DOWN(addr, gran) ((uintptr_t)((addr) & ~(gran-1)))
7323c35297Sanish
7423c35297Sanish #define PCICFG_MEMGRAN 0x100000
7523c35297Sanish #define PCICFG_IOGRAN 0x1000
7623c35297Sanish #define PCICFG_4GIG_LIMIT 0xFFFFFFFFUL
7723c35297Sanish
7823c35297Sanish #define PCICFG_MEM_MULT 4
7923c35297Sanish #define PCICFG_IO_MULT 4
8023c35297Sanish #define PCICFG_RANGE_LEN 3 /* Number of range entries */
8123c35297Sanish
8223c35297Sanish static int pcicfg_slot_busnums = 8;
8323c35297Sanish static int pcicfg_slot_memsize = 32 * PCICFG_MEMGRAN; /* 32MB per slot */
8423c35297Sanish static int pcicfg_slot_pf_memsize = 32 * PCICFG_MEMGRAN; /* 32MB per slot */
8523c35297Sanish static int pcicfg_slot_iosize = 64 * PCICFG_IOGRAN; /* 64K per slot */
8623c35297Sanish static int pcicfg_sec_reset_delay = 3000000;
8723c35297Sanish static int pcicfg_do_legacy_props = 1; /* create legacy compatible prop */
8823c35297Sanish
8923c35297Sanish typedef struct hole hole_t;
9023c35297Sanish
9123c35297Sanish struct hole {
9223c35297Sanish uint64_t start;
9323c35297Sanish uint64_t len;
9423c35297Sanish hole_t *next;
9523c35297Sanish };
9623c35297Sanish
9723c35297Sanish typedef struct pcicfg_phdl pcicfg_phdl_t;
9823c35297Sanish
9923c35297Sanish struct pcicfg_phdl {
10023c35297Sanish
10123c35297Sanish dev_info_t *dip; /* Associated with the bridge */
10223c35297Sanish dev_info_t *top_dip; /* top node of the attach point */
10323c35297Sanish pcicfg_phdl_t *next;
10423c35297Sanish
10523c35297Sanish /* non-prefetchable memory space */
10623c35297Sanish uint64_t memory_base; /* Memory base for this attach point */
10723c35297Sanish uint64_t memory_last;
10823c35297Sanish uint64_t memory_len;
10923c35297Sanish
11023c35297Sanish /* prefetchable memory space */
11126947304SEvan Yan uint64_t pf_memory_base; /* PF Memory base for this Connection */
11223c35297Sanish uint64_t pf_memory_last;
11323c35297Sanish uint64_t pf_memory_len;
11423c35297Sanish
11523c35297Sanish /* io space */
11623c35297Sanish uint32_t io_base; /* I/O base for this attach point */
11723c35297Sanish uint32_t io_last;
11823c35297Sanish uint32_t io_len;
11923c35297Sanish
12023c35297Sanish int error;
12123c35297Sanish uint_t highest_bus; /* Highest bus seen on the probe */
12223c35297Sanish
12323c35297Sanish hole_t mem_hole; /* Memory hole linked list. */
12423c35297Sanish hole_t pf_mem_hole; /* PF Memory hole linked list. */
12523c35297Sanish hole_t io_hole; /* IO hole linked list */
12623c35297Sanish
12723c35297Sanish ndi_ra_request_t mem_req; /* allocator request for memory */
12823c35297Sanish ndi_ra_request_t pf_mem_req; /* allocator request for PF memory */
12923c35297Sanish ndi_ra_request_t io_req; /* allocator request for I/O */
13023c35297Sanish };
13123c35297Sanish
13223c35297Sanish struct pcicfg_standard_prop_entry {
13323c35297Sanish uchar_t *name;
13423c35297Sanish uint_t config_offset;
13523c35297Sanish uint_t size;
13623c35297Sanish };
13723c35297Sanish
13823c35297Sanish
13923c35297Sanish struct pcicfg_name_entry {
14023c35297Sanish uint32_t class_code;
14123c35297Sanish char *name;
14223c35297Sanish };
14323c35297Sanish
14423c35297Sanish struct pcicfg_find_ctrl {
14523c35297Sanish uint_t device;
14623c35297Sanish uint_t function;
14723c35297Sanish dev_info_t *dip;
14823c35297Sanish };
14923c35297Sanish
15023c35297Sanish /*
15123c35297Sanish * List of Indirect Config Map Devices. At least the intent of the
15223c35297Sanish * design is to look for a device in this list during the configure
15323c35297Sanish * operation, and if the device is listed here, then it is a nontransparent
15423c35297Sanish * bridge, hence load the driver and avail the config map services from
15523c35297Sanish * the driver. Class and Subclass should be as defined in the PCI specs
15623c35297Sanish * ie. class is 0x6, and subclass is 0x9.
15723c35297Sanish */
15823c35297Sanish static struct {
15923c35297Sanish uint8_t mem_range_bar_offset;
16023c35297Sanish uint8_t io_range_bar_offset;
16123c35297Sanish uint8_t prefetch_mem_range_bar_offset;
16223c35297Sanish } pcicfg_indirect_map_devs[] = {
16323c35297Sanish PCI_CONF_BASE3, PCI_CONF_BASE2, PCI_CONF_BASE3,
16423c35297Sanish 0, 0, 0,
16523c35297Sanish };
16623c35297Sanish
16723c35297Sanish #define PCICFG_MAKE_REG_HIGH(busnum, devnum, funcnum, register)\
16823c35297Sanish (\
16923c35297Sanish ((ulong_t)(busnum & 0xff) << 16) |\
17023c35297Sanish ((ulong_t)(devnum & 0x1f) << 11) |\
17123c35297Sanish ((ulong_t)(funcnum & 0x7) << 8) |\
17223c35297Sanish ((ulong_t)(register & 0x3f)))
17323c35297Sanish
17423c35297Sanish /*
17523c35297Sanish * debug macros:
17623c35297Sanish */
17723c35297Sanish #if defined(DEBUG)
17823c35297Sanish extern void prom_printf(const char *, ...);
17923c35297Sanish
18023c35297Sanish /*
18123c35297Sanish * Following values are defined for this debug flag.
18223c35297Sanish *
18323c35297Sanish * 1 = dump configuration header only.
18423c35297Sanish * 2 = dump generic debug data only (no config header dumped)
18523c35297Sanish * 3 = dump everything (both 1 and 2)
18623c35297Sanish */
18723c35297Sanish int pcicfg_debug = 0;
18823c35297Sanish
18923c35297Sanish static void debug(char *, uintptr_t, uintptr_t,
19023c35297Sanish uintptr_t, uintptr_t, uintptr_t);
19123c35297Sanish
19223c35297Sanish #define DEBUG0(fmt)\
19323c35297Sanish debug(fmt, 0, 0, 0, 0, 0);
19423c35297Sanish #define DEBUG1(fmt, a1)\
19523c35297Sanish debug(fmt, (uintptr_t)(a1), 0, 0, 0, 0);
19623c35297Sanish #define DEBUG2(fmt, a1, a2)\
19723c35297Sanish debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2), 0, 0, 0);
19823c35297Sanish #define DEBUG3(fmt, a1, a2, a3)\
19923c35297Sanish debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2),\
20023c35297Sanish (uintptr_t)(a3), 0, 0);
20123c35297Sanish #define DEBUG4(fmt, a1, a2, a3, a4)\
20223c35297Sanish debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2),\
20323c35297Sanish (uintptr_t)(a3), (uintptr_t)(a4), 0);
20423c35297Sanish #define DEBUG5(fmt, a1, a2, a3, a4, a5)\
20523c35297Sanish debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2),\
20623c35297Sanish (uintptr_t)(a3), (uintptr_t)(a4), (uintptr_t)(a5));
20723c35297Sanish #else
20823c35297Sanish #define DEBUG0(fmt)
20923c35297Sanish #define DEBUG1(fmt, a1)
21023c35297Sanish #define DEBUG2(fmt, a1, a2)
21123c35297Sanish #define DEBUG3(fmt, a1, a2, a3)
21223c35297Sanish #define DEBUG4(fmt, a1, a2, a3, a4)
21323c35297Sanish #define DEBUG5(fmt, a1, a2, a3, a4, a5)
21423c35297Sanish #endif
21523c35297Sanish
21623c35297Sanish /*
21723c35297Sanish * forward declarations for routines defined in this module (called here)
21823c35297Sanish */
21923c35297Sanish
22023c35297Sanish static int pcicfg_add_config_reg(dev_info_t *,
22123c35297Sanish uint_t, uint_t, uint_t);
22223c35297Sanish static int pcicfg_probe_children(dev_info_t *, uint_t, uint_t, uint_t,
223c0da6274SZhi-Jun Robin Fu uint_t *, pcicfg_flags_t, boolean_t);
22423c35297Sanish static int pcicfg_match_dev(dev_info_t *, void *);
22523c35297Sanish static dev_info_t *pcicfg_devi_find(dev_info_t *, uint_t, uint_t);
22623c35297Sanish static pcicfg_phdl_t *pcicfg_find_phdl(dev_info_t *);
22723c35297Sanish static pcicfg_phdl_t *pcicfg_create_phdl(dev_info_t *);
22823c35297Sanish static int pcicfg_destroy_phdl(dev_info_t *);
22923c35297Sanish static int pcicfg_sum_resources(dev_info_t *, void *);
23023c35297Sanish static int pcicfg_device_assign(dev_info_t *);
23123c35297Sanish static int pcicfg_bridge_assign(dev_info_t *, void *);
23226947304SEvan Yan static int pcicfg_device_assign_readonly(dev_info_t *);
23326947304SEvan Yan static int pcicfg_free_resources(dev_info_t *, pcicfg_flags_t);
23423c35297Sanish static void pcicfg_setup_bridge(pcicfg_phdl_t *, ddi_acc_handle_t);
23523c35297Sanish static void pcicfg_update_bridge(pcicfg_phdl_t *, ddi_acc_handle_t);
23623c35297Sanish static int pcicfg_update_assigned_prop(dev_info_t *, pci_regspec_t *);
23723c35297Sanish static void pcicfg_device_on(ddi_acc_handle_t);
23823c35297Sanish static void pcicfg_device_off(ddi_acc_handle_t);
23923c35297Sanish static int pcicfg_set_busnode_props(dev_info_t *, uint8_t);
24023c35297Sanish static int pcicfg_free_bridge_resources(dev_info_t *);
24123c35297Sanish static int pcicfg_free_device_resources(dev_info_t *);
242c0da6274SZhi-Jun Robin Fu static int pcicfg_teardown_device(dev_info_t *, pcicfg_flags_t, boolean_t);
24323c35297Sanish static void pcicfg_reparent_node(dev_info_t *, dev_info_t *);
24423c35297Sanish static int pcicfg_config_setup(dev_info_t *, ddi_acc_handle_t *);
24523c35297Sanish static void pcicfg_config_teardown(ddi_acc_handle_t *);
24623c35297Sanish static void pcicfg_get_mem(pcicfg_phdl_t *, uint32_t, uint64_t *);
24723c35297Sanish static void pcicfg_get_pf_mem(pcicfg_phdl_t *, uint32_t, uint64_t *);
24823c35297Sanish static void pcicfg_get_io(pcicfg_phdl_t *, uint32_t, uint32_t *);
24923c35297Sanish static int pcicfg_update_ranges_prop(dev_info_t *, ppb_ranges_t *);
25023c35297Sanish static int pcicfg_configure_ntbridge(dev_info_t *, uint_t, uint_t);
25123c35297Sanish static uint_t pcicfg_ntbridge_child(dev_info_t *);
25223c35297Sanish static uint_t pcicfg_get_ntbridge_child_range(dev_info_t *, uint64_t *,
25323c35297Sanish uint64_t *, uint_t);
25423c35297Sanish static int pcicfg_is_ntbridge(dev_info_t *);
25523c35297Sanish static int pcicfg_ntbridge_allocate_resources(dev_info_t *);
25623c35297Sanish static int pcicfg_ntbridge_configure_done(dev_info_t *);
25723c35297Sanish static int pcicfg_ntbridge_program_child(dev_info_t *);
25823c35297Sanish static uint_t pcicfg_ntbridge_unconfigure(dev_info_t *);
25923c35297Sanish static int pcicfg_ntbridge_unconfigure_child(dev_info_t *, uint_t);
26023c35297Sanish static void pcicfg_free_hole(hole_t *);
26123c35297Sanish static uint64_t pcicfg_alloc_hole(hole_t *, uint64_t *, uint32_t);
26223c35297Sanish static int pcicfg_device_type(dev_info_t *, ddi_acc_handle_t *);
26323c35297Sanish static void pcicfg_update_phdl(dev_info_t *, uint8_t, uint8_t);
26423c35297Sanish static int pcicfg_get_cap(ddi_acc_handle_t, uint8_t);
26523c35297Sanish static uint8_t pcicfg_get_nslots(dev_info_t *, ddi_acc_handle_t);
26623c35297Sanish static int pcicfg_pcie_dev(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;
55923c35297Sanish int circ;
56023c35297Sanish uint_t highest_bus;
56126947304SEvan Yan int ari_mode = B_FALSE;
56226947304SEvan Yan int max_function = PCI_MAX_FUNCTIONS;
56326947304SEvan Yan int trans_device;
56426947304SEvan Yan dev_info_t *new_device;
565c0da6274SZhi-Jun Robin Fu boolean_t is_pcie;
56626947304SEvan Yan
56726947304SEvan Yan if (flags == PCICFG_FLAG_ENABLE_ARI)
56826947304SEvan Yan return (pcicfg_ari_configure(devi));
56923c35297Sanish
57023c35297Sanish /*
57123c35297Sanish * Start probing at the device specified in "device" on the
57223c35297Sanish * "bus" specified.
57323c35297Sanish */
57423c35297Sanish len = sizeof (pci_bus_range_t);
57523c35297Sanish if (ddi_getlongprop_buf(DDI_DEV_T_ANY, devi, 0, "bus-range",
57623c35297Sanish (caddr_t)&pci_bus_range, &len) != DDI_SUCCESS) {
57723c35297Sanish DEBUG0("no bus-range property\n");
57823c35297Sanish return (PCICFG_FAILURE);
57923c35297Sanish }
58023c35297Sanish
58123c35297Sanish bus = pci_bus_range.lo; /* primary bus number of this bus node */
58223c35297Sanish
58323c35297Sanish attach_point = devi;
58423c35297Sanish
585c0da6274SZhi-Jun Robin Fu is_pcie = is_pcie_fabric(devi);
586c0da6274SZhi-Jun Robin Fu
58723c35297Sanish ndi_devi_enter(devi, &circ);
58826947304SEvan Yan for (func = 0; func < max_function; ) {
58923c35297Sanish
59026947304SEvan Yan if ((function != PCICFG_ALL_FUNC) && (function != func))
59126947304SEvan Yan goto next;
59226947304SEvan Yan
59326947304SEvan Yan if (ari_mode)
59426947304SEvan Yan trans_device = func >> 3;
59526947304SEvan Yan else
59626947304SEvan Yan trans_device = device;
59723c35297Sanish
59823c35297Sanish switch (rv = pcicfg_probe_children(attach_point,
599c0da6274SZhi-Jun Robin Fu bus, trans_device, func & 7, &highest_bus,
600c0da6274SZhi-Jun Robin Fu flags, is_pcie)) {
6015af4ae46Sjveta case PCICFG_NORESRC:
60223c35297Sanish case PCICFG_FAILURE:
60326947304SEvan Yan DEBUG2("configure failed: bus [0x%x] device "
60426947304SEvan Yan "[0x%x]\n", bus, trans_device);
60523c35297Sanish goto cleanup;
60623c35297Sanish case PCICFG_NODEVICE:
60723c35297Sanish DEBUG3("no device : bus "
60823c35297Sanish "[0x%x] slot [0x%x] func [0x%x]\n",
60926947304SEvan Yan bus, trans_device, func &7);
61026947304SEvan Yan
611*7f59ab1cSAlan Adamson, SD OSSD /*
612*7f59ab1cSAlan Adamson, SD OSSD * When walking the list of ARI functions
613*7f59ab1cSAlan Adamson, SD OSSD * we don't expect to see a non-present
614*7f59ab1cSAlan Adamson, SD OSSD * function, so we will stop walking
615*7f59ab1cSAlan Adamson, SD OSSD * the function list.
616*7f59ab1cSAlan Adamson, SD OSSD */
617*7f59ab1cSAlan Adamson, SD OSSD if (ari_mode == B_TRUE)
618*7f59ab1cSAlan Adamson, SD OSSD break;
619*7f59ab1cSAlan Adamson, SD OSSD
62026947304SEvan Yan if (func)
62126947304SEvan Yan goto next;
62226947304SEvan Yan break;
62323c35297Sanish default:
62423c35297Sanish DEBUG3("configure: bus => [%d] "
62523c35297Sanish "slot => [%d] func => [%d]\n",
62626947304SEvan Yan bus, trans_device, func & 7);
62723c35297Sanish break;
62823c35297Sanish }
62923c35297Sanish
63023c35297Sanish if (rv != PCICFG_SUCCESS)
63123c35297Sanish break;
63223c35297Sanish
63323c35297Sanish if ((new_device = pcicfg_devi_find(attach_point,
63426947304SEvan Yan trans_device, func & 7)) == NULL) {
63523c35297Sanish DEBUG0("Did'nt find device node just created\n");
63623c35297Sanish goto cleanup;
63723c35297Sanish }
63823c35297Sanish
63923c35297Sanish /*
64023c35297Sanish * Up until now, we have detected a non transparent bridge
64123c35297Sanish * (ntbridge) as a part of the generic probe code and
64223c35297Sanish * configured only one configuration
64323c35297Sanish * header which is the side facing the host bus.
64423c35297Sanish * Now, configure the other side and create children.
64523c35297Sanish *
64623c35297Sanish * In order to make the process simpler, lets load the device
64723c35297Sanish * driver for the non transparent bridge as this is a
64823c35297Sanish * Solaris bundled driver, and use its configuration map
64923c35297Sanish * services rather than programming it here.
65023c35297Sanish * If the driver is not bundled into Solaris, it must be
65123c35297Sanish * first loaded and configured before performing any
65223c35297Sanish * hotplug operations.
65323c35297Sanish *
65423c35297Sanish * This not only makes the code here simpler but also more
65523c35297Sanish * generic.
65623c35297Sanish *
65723c35297Sanish * So here we go.
65823c35297Sanish */
65923c35297Sanish
66023c35297Sanish /*
66123c35297Sanish * check if this is a bridge in nontransparent mode
66223c35297Sanish */
66323c35297Sanish if (pcicfg_is_ntbridge(new_device) != DDI_FAILURE) {
66423c35297Sanish DEBUG0("pcicfg: Found nontransparent bridge.\n");
66523c35297Sanish
66626947304SEvan Yan rv = pcicfg_configure_ntbridge(new_device, bus,
66726947304SEvan Yan trans_device);
6685af4ae46Sjveta if (rv != PCICFG_SUCCESS)
66923c35297Sanish goto cleanup;
67023c35297Sanish }
67126947304SEvan Yan
67226947304SEvan Yan next:
67326947304SEvan Yan /*
67426947304SEvan Yan * Determine if ARI Forwarding should be enabled.
67526947304SEvan Yan */
67626947304SEvan Yan if (func == 0) {
67726947304SEvan Yan if ((pcie_ari_supported(devi)
67826947304SEvan Yan == PCIE_ARI_FORW_SUPPORTED) &&
67926947304SEvan Yan (pcie_ari_device(new_device) == PCIE_ARI_DEVICE)) {
68026947304SEvan Yan if (pcie_ari_enable(devi) == DDI_SUCCESS) {
68126947304SEvan Yan (void) ddi_prop_create(DDI_DEV_T_NONE,
68226947304SEvan Yan devi, DDI_PROP_CANSLEEP,
68326947304SEvan Yan "ari-enabled", NULL, 0);
68426947304SEvan Yan
68526947304SEvan Yan ari_mode = B_TRUE;
68626947304SEvan Yan max_function = PCICFG_MAX_ARI_FUNCTION;
68726947304SEvan Yan }
68826947304SEvan Yan }
68926947304SEvan Yan }
69026947304SEvan Yan if (ari_mode == B_TRUE) {
69126947304SEvan Yan int next_function;
69226947304SEvan Yan
69326947304SEvan Yan DEBUG0("Next Function - ARI Device\n");
69426947304SEvan Yan if (pcie_ari_get_next_function(new_device,
69526947304SEvan Yan &next_function) != DDI_SUCCESS)
69626947304SEvan Yan goto cleanup;
69726947304SEvan Yan
69826947304SEvan Yan /*
69926947304SEvan Yan * Check if there are more fucntions to probe.
70026947304SEvan Yan */
70126947304SEvan Yan if (next_function == 0) {
70226947304SEvan Yan DEBUG0("Next Function - "
70326947304SEvan Yan "No more ARI Functions\n");
70426947304SEvan Yan break;
70526947304SEvan Yan }
70626947304SEvan Yan func = next_function;
70726947304SEvan Yan } else {
70826947304SEvan Yan func++;
70926947304SEvan Yan }
71026947304SEvan Yan DEBUG1("Next Function - %x\n", func);
71123c35297Sanish }
71223c35297Sanish
71323c35297Sanish ndi_devi_exit(devi, circ);
71423c35297Sanish
71523c35297Sanish if (func == 0)
71623c35297Sanish return (PCICFG_FAILURE); /* probe failed */
71723c35297Sanish else
71823c35297Sanish return (PCICFG_SUCCESS);
71923c35297Sanish
72023c35297Sanish cleanup:
72123c35297Sanish /*
72223c35297Sanish * Clean up a partially created "probe state" tree.
72323c35297Sanish * There are no resources allocated to the in the
72423c35297Sanish * probe state.
72523c35297Sanish */
72623c35297Sanish
72723c35297Sanish for (func = 0; func < PCI_MAX_FUNCTIONS; func++) {
72826947304SEvan Yan if ((function != PCICFG_ALL_FUNC) && (function != func))
72926947304SEvan Yan continue;
73026947304SEvan Yan
73126947304SEvan Yan if ((new_device = pcicfg_devi_find(devi, device, func))
73226947304SEvan Yan == NULL) {
73323c35297Sanish continue;
73423c35297Sanish }
73523c35297Sanish
73623c35297Sanish DEBUG2("Cleaning up device [0x%x] function [0x%x]\n",
73723c35297Sanish device, func);
73823c35297Sanish /*
73923c35297Sanish * If this was a bridge device it will have a
74023c35297Sanish * probe handle - if not, no harm in calling this.
74123c35297Sanish */
74223c35297Sanish (void) pcicfg_destroy_phdl(new_device);
743c0da6274SZhi-Jun Robin Fu if (is_pcie) {
744c0da6274SZhi-Jun Robin Fu /*
745c0da6274SZhi-Jun Robin Fu * free pcie_bus_t for the sub-tree
746c0da6274SZhi-Jun Robin Fu */
747c0da6274SZhi-Jun Robin Fu if (ddi_get_child(new_device) != NULL)
748c0da6274SZhi-Jun Robin Fu pcie_fab_fini_bus(new_device, PCIE_BUS_ALL);
749c0da6274SZhi-Jun Robin Fu
750c0da6274SZhi-Jun Robin Fu pcie_fini_bus(new_device, PCIE_BUS_ALL);
751c0da6274SZhi-Jun Robin Fu }
75223c35297Sanish /*
75323c35297Sanish * This will free up the node
75423c35297Sanish */
75523c35297Sanish (void) ndi_devi_offline(new_device, NDI_DEVI_REMOVE);
75623c35297Sanish }
75723c35297Sanish ndi_devi_exit(devi, circ);
75823c35297Sanish
7595af4ae46Sjveta /*
7605af4ae46Sjveta * Use private return codes to help identify issues without debugging
7615af4ae46Sjveta * enabled. Resource limitations and mis-configurations are
7625af4ae46Sjveta * probably the most likely caue of configuration failures on x86.
7635af4ae46Sjveta * Convert return code back to values expected by the external
7645af4ae46Sjveta * consumer before returning so we will warn only once on the first
7655af4ae46Sjveta * encountered failure.
7665af4ae46Sjveta */
7675af4ae46Sjveta if (rv == PCICFG_NORESRC) {
7685af4ae46Sjveta char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
7695af4ae46Sjveta
7705af4ae46Sjveta (void) ddi_pathname(devi, path);
7715af4ae46Sjveta cmn_err(CE_CONT, "?Not enough PCI resources to "
7725af4ae46Sjveta "configure: %s\n", path);
7735af4ae46Sjveta
7745af4ae46Sjveta kmem_free(path, MAXPATHLEN);
7755af4ae46Sjveta rv = PCICFG_FAILURE;
7765af4ae46Sjveta }
7775af4ae46Sjveta
7785af4ae46Sjveta return (rv);
77923c35297Sanish }
78023c35297Sanish
78123c35297Sanish /*
78223c35297Sanish * configure the child nodes of ntbridge. new_device points to ntbridge itself
78323c35297Sanish */
78423c35297Sanish /*ARGSUSED*/
78523c35297Sanish static int
pcicfg_configure_ntbridge(dev_info_t * new_device,uint_t bus,uint_t device)78623c35297Sanish pcicfg_configure_ntbridge(dev_info_t *new_device, uint_t bus, uint_t device)
78723c35297Sanish {
78823c35297Sanish int bus_range[2], rc = PCICFG_FAILURE, rc1, max_devs = 0;
78923c35297Sanish int devno;
79023c35297Sanish dev_info_t *new_ntbridgechild;
79123c35297Sanish ddi_acc_handle_t config_handle;
79223c35297Sanish uint16_t vid;
79323c35297Sanish uint64_t next_bus;
79423c35297Sanish uint64_t blen;
79523c35297Sanish ndi_ra_request_t req;
79623c35297Sanish uint8_t pcie_device_type = 0;
79723c35297Sanish
79823c35297Sanish /*
79923c35297Sanish * If we need to do indirect config, lets create a property here
80023c35297Sanish * to let the child conf map routine know that it has to
80123c35297Sanish * go through the DDI calls, and not assume the devices are
80223c35297Sanish * mapped directly under the host.
80323c35297Sanish */
80423c35297Sanish if ((rc = ndi_prop_update_int(DDI_DEV_T_NONE, new_device,
80526947304SEvan Yan PCI_DEV_CONF_MAP_PROP, (int)DDI_SUCCESS)) != DDI_SUCCESS) {
80623c35297Sanish DEBUG0("Cannot create indirect conf map property.\n");
80723c35297Sanish return ((int)PCICFG_FAILURE);
80823c35297Sanish }
80923c35297Sanish
81023c35297Sanish if (pci_config_setup(new_device, &config_handle) != DDI_SUCCESS)
81123c35297Sanish return (PCICFG_FAILURE);
81223c35297Sanish /* check if we are PCIe device */
81323c35297Sanish if (pcicfg_pcie_device_type(new_device, config_handle) == DDI_SUCCESS) {
81423c35297Sanish DEBUG0("PCIe device detected\n");
81523c35297Sanish pcie_device_type = 1;
81623c35297Sanish }
81723c35297Sanish pci_config_teardown(&config_handle);
81823c35297Sanish /* create Bus node properties for ntbridge. */
81923c35297Sanish if (pcicfg_set_busnode_props(new_device, pcie_device_type)
82023c35297Sanish != PCICFG_SUCCESS) {
82123c35297Sanish DEBUG0("Failed to set busnode props\n");
82223c35297Sanish return (rc);
82323c35297Sanish }
82423c35297Sanish
82523c35297Sanish /* For now: Lets only support one layer of child */
82623c35297Sanish bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
82723c35297Sanish req.ra_len = 1;
82826947304SEvan Yan if (ndi_ra_alloc(ddi_get_parent(new_device), &req, &next_bus, &blen,
82926947304SEvan Yan NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS) != NDI_SUCCESS) {
83023c35297Sanish DEBUG0("ntbridge: Failed to get a bus number\n");
8315af4ae46Sjveta return (PCICFG_NORESRC);
83223c35297Sanish }
83323c35297Sanish
83423c35297Sanish DEBUG1("ntbridge bus range start ->[%d]\n", next_bus);
83523c35297Sanish
83623c35297Sanish /*
83723c35297Sanish * Following will change, as we detect more bridges
83823c35297Sanish * on the way.
83923c35297Sanish */
84023c35297Sanish bus_range[0] = (int)next_bus;
84123c35297Sanish bus_range[1] = (int)next_bus;
84223c35297Sanish
84326947304SEvan Yan if (ndi_prop_update_int_array(DDI_DEV_T_NONE, new_device, "bus-range",
84426947304SEvan Yan bus_range, 2) != DDI_SUCCESS) {
84523c35297Sanish DEBUG0("Cannot set ntbridge bus-range property");
84623c35297Sanish return (rc);
84723c35297Sanish }
84823c35297Sanish
84923c35297Sanish /*
85023c35297Sanish * The other interface (away from the host) will be
85123c35297Sanish * initialized by the nexus driver when it loads.
85223c35297Sanish * We just have to set the registers and the nexus driver
85323c35297Sanish * figures out the rest.
85423c35297Sanish */
85523c35297Sanish
85623c35297Sanish /*
85723c35297Sanish * finally, lets load and attach the driver
85823c35297Sanish * before configuring children of ntbridge.
85923c35297Sanish */
86023c35297Sanish rc = ndi_devi_online(new_device, NDI_ONLINE_ATTACH|NDI_CONFIG);
86123c35297Sanish if (rc != NDI_SUCCESS) {
86223c35297Sanish cmn_err(CE_WARN,
86323c35297Sanish "pcicfg: Fail:cant load nontransparent bridgd driver..\n");
86423c35297Sanish rc = PCICFG_FAILURE;
86523c35297Sanish return (rc);
86623c35297Sanish }
86723c35297Sanish DEBUG0("pcicfg: Success loading nontransparent bridge nexus driver..");
86823c35297Sanish
8695af4ae46Sjveta /* Now set aside pci resource allocation requests for our children */
87026947304SEvan Yan if (pcicfg_ntbridge_allocate_resources(new_device) != PCICFG_SUCCESS) {
87123c35297Sanish max_devs = 0;
87223c35297Sanish rc = PCICFG_FAILURE;
87323c35297Sanish } else
87423c35297Sanish max_devs = PCI_MAX_DEVICES;
87523c35297Sanish
87623c35297Sanish /* Probe devices on 2nd bus */
8775af4ae46Sjveta rc = PCICFG_SUCCESS;
87823c35297Sanish for (devno = pcicfg_start_devno; devno < max_devs; devno++) {
87923c35297Sanish
88023c35297Sanish ndi_devi_alloc_sleep(new_device, DEVI_PSEUDO_NEXNAME,
88123c35297Sanish (pnode_t)DEVI_SID_NODEID, &new_ntbridgechild);
88223c35297Sanish
88323c35297Sanish if (pcicfg_add_config_reg(new_ntbridgechild, next_bus, devno, 0)
88423c35297Sanish != DDI_PROP_SUCCESS) {
88523c35297Sanish cmn_err(CE_WARN,
88623c35297Sanish "Failed to add conf reg for ntbridge child.\n");
88723c35297Sanish (void) ndi_devi_free(new_ntbridgechild);
88823c35297Sanish rc = PCICFG_FAILURE;
88923c35297Sanish break;
89023c35297Sanish }
89123c35297Sanish
89223c35297Sanish if (pci_config_setup(new_ntbridgechild, &config_handle)
89323c35297Sanish != DDI_SUCCESS) {
89423c35297Sanish cmn_err(CE_WARN,
89523c35297Sanish "Cannot map ntbridge child %x\n", devno);
89623c35297Sanish (void) ndi_devi_free(new_ntbridgechild);
89723c35297Sanish rc = PCICFG_FAILURE;
89823c35297Sanish break;
89923c35297Sanish }
90023c35297Sanish
90123c35297Sanish /*
90223c35297Sanish * See if there is any PCI HW at this location
90323c35297Sanish * by reading the Vendor ID. If it returns with 0xffff
90423c35297Sanish * then there is no hardware at this location.
90523c35297Sanish */
90623c35297Sanish vid = pci_config_get16(config_handle, PCI_CONF_VENID);
90723c35297Sanish
90823c35297Sanish pci_config_teardown(&config_handle);
90923c35297Sanish (void) ndi_devi_free(new_ntbridgechild);
91023c35297Sanish if (vid == 0xffff)
91123c35297Sanish continue;
91223c35297Sanish
91323c35297Sanish /* Lets fake attachments points for each child, */
91426947304SEvan Yan rc = pcicfg_configure(new_device, devno, PCICFG_ALL_FUNC, 0);
9155af4ae46Sjveta if (rc != PCICFG_SUCCESS) {
91623c35297Sanish int old_dev = pcicfg_start_devno;
91723c35297Sanish
91823c35297Sanish cmn_err(CE_WARN,
91923c35297Sanish "Error configuring ntbridge child dev=%d\n", devno);
92023c35297Sanish
92123c35297Sanish while (old_dev != devno) {
92223c35297Sanish if (pcicfg_ntbridge_unconfigure_child(
92323c35297Sanish new_device, old_dev) == PCICFG_FAILURE)
92426947304SEvan Yan cmn_err(CE_WARN, "Unconfig Error "
92526947304SEvan Yan "ntbridge child dev=%d\n", old_dev);
92623c35297Sanish old_dev++;
92723c35297Sanish }
92823c35297Sanish break;
92923c35297Sanish }
93023c35297Sanish } /* devno loop */
93123c35297Sanish DEBUG1("ntbridge: finish probing 2nd bus, rc=%d\n", rc);
93223c35297Sanish
9335af4ae46Sjveta if (rc == PCICFG_SUCCESS)
93423c35297Sanish rc = pcicfg_ntbridge_configure_done(new_device);
93523c35297Sanish else {
93623c35297Sanish pcicfg_phdl_t *entry = pcicfg_find_phdl(new_device);
93723c35297Sanish uint_t *bus;
93823c35297Sanish int k;
93923c35297Sanish
94023c35297Sanish if (ddi_getlongprop(DDI_DEV_T_ANY, new_device,
94126947304SEvan Yan DDI_PROP_DONTPASS, "bus-range", (caddr_t)&bus, &k)
94226947304SEvan Yan != DDI_PROP_SUCCESS) {
94323c35297Sanish DEBUG0("Failed to read bus-range property\n");
94423c35297Sanish rc = PCICFG_FAILURE;
94523c35297Sanish return (rc);
94623c35297Sanish }
94723c35297Sanish
94823c35297Sanish DEBUG2("Need to free bus [%d] range [%d]\n",
94923c35297Sanish bus[0], bus[1] - bus[0] + 1);
95023c35297Sanish
95126947304SEvan Yan if (ndi_ra_free(ddi_get_parent(new_device), (uint64_t)bus[0],
95226947304SEvan Yan (uint64_t)(bus[1] - bus[0] + 1), NDI_RA_TYPE_PCI_BUSNUM,
95326947304SEvan Yan NDI_RA_PASS) != NDI_SUCCESS) {
95423c35297Sanish DEBUG0("Failed to free a bus number\n");
95523c35297Sanish rc = PCICFG_FAILURE;
9561fb5b786Sprasad kmem_free(bus, k);
95723c35297Sanish return (rc);
95823c35297Sanish }
95923c35297Sanish
96023c35297Sanish /*
96123c35297Sanish * Since no memory allocations are done for non transparent
96223c35297Sanish * bridges (but instead we just set the handle with the
96323c35297Sanish * already allocated memory, we just need to reset the
96423c35297Sanish * following values before calling the destroy_phdl()
96523c35297Sanish * function next, otherwise the it will try to free
96623c35297Sanish * memory allocated as in case of a transparent bridge.
96723c35297Sanish */
96823c35297Sanish entry->memory_len = 0;
96923c35297Sanish entry->pf_memory_len = 0;
97023c35297Sanish entry->io_len = 0;
9711fb5b786Sprasad kmem_free(bus, k);
97223c35297Sanish /* the following will free hole data. */
97323c35297Sanish (void) pcicfg_destroy_phdl(new_device);
97423c35297Sanish }
97523c35297Sanish
97623c35297Sanish /*
97723c35297Sanish * Unload driver just in case child configure failed!
97823c35297Sanish */
97923c35297Sanish rc1 = ndi_devi_offline(new_device, 0);
98023c35297Sanish DEBUG1("pcicfg: now unloading the ntbridge driver. rc1=%d\n", rc1);
98123c35297Sanish if (rc1 != NDI_SUCCESS) {
98223c35297Sanish cmn_err(CE_WARN,
98323c35297Sanish "pcicfg: cant unload ntbridge driver..children.\n");
98423c35297Sanish rc = PCICFG_FAILURE;
98523c35297Sanish }
98623c35297Sanish
98723c35297Sanish return (rc);
98823c35297Sanish }
98923c35297Sanish
99023c35297Sanish static int
pcicfg_ntbridge_allocate_resources(dev_info_t * dip)99123c35297Sanish pcicfg_ntbridge_allocate_resources(dev_info_t *dip)
99223c35297Sanish {
99323c35297Sanish pcicfg_phdl_t *phdl;
99423c35297Sanish ndi_ra_request_t *mem_request;
99523c35297Sanish ndi_ra_request_t *pf_mem_request;
99623c35297Sanish ndi_ra_request_t *io_request;
99723c35297Sanish uint64_t boundbase, boundlen;
99823c35297Sanish
99923c35297Sanish phdl = pcicfg_find_phdl(dip);
100023c35297Sanish ASSERT(phdl);
100123c35297Sanish
100223c35297Sanish mem_request = &phdl->mem_req;
100323c35297Sanish pf_mem_request = &phdl->pf_mem_req;
100423c35297Sanish io_request = &phdl->io_req;
100523c35297Sanish
100623c35297Sanish phdl->error = PCICFG_SUCCESS;
100723c35297Sanish
100823c35297Sanish /* Set Memory space handle for ntbridge */
100923c35297Sanish if (pcicfg_get_ntbridge_child_range(dip, &boundbase, &boundlen,
101023c35297Sanish PCI_BASE_SPACE_MEM) != DDI_SUCCESS) {
101123c35297Sanish cmn_err(CE_WARN,
101223c35297Sanish "ntbridge: Mem resource information failure\n");
101323c35297Sanish phdl->memory_len = 0;
101423c35297Sanish return (PCICFG_FAILURE);
101523c35297Sanish }
101623c35297Sanish mem_request->ra_boundbase = boundbase;
101723c35297Sanish mem_request->ra_boundlen = boundbase + boundlen;
101823c35297Sanish mem_request->ra_len = boundlen;
101923c35297Sanish mem_request->ra_align_mask =
102023c35297Sanish PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */
102123c35297Sanish mem_request->ra_flags |= NDI_RA_ALLOC_BOUNDED;
102223c35297Sanish
102323c35297Sanish /*
102423c35297Sanish * mem_request->ra_len =
102523c35297Sanish * PCICFG_ROUND_UP(mem_request->ra_len, PCICFG_MEMGRAN);
102623c35297Sanish */
102723c35297Sanish
102823c35297Sanish phdl->memory_base = phdl->memory_last = boundbase;
102923c35297Sanish phdl->memory_len = boundlen;
103023c35297Sanish phdl->mem_hole.start = phdl->memory_base;
103123c35297Sanish phdl->mem_hole.len = mem_request->ra_len;
103223c35297Sanish phdl->mem_hole.next = (hole_t *)NULL;
103323c35297Sanish
103426947304SEvan Yan DEBUG2("Connector requested [0x%llx], needs [0x%llx] bytes of memory\n",
103523c35297Sanish boundlen, mem_request->ra_len);
103623c35297Sanish
103723c35297Sanish /* Set IO space handle for ntbridge */
103823c35297Sanish if (pcicfg_get_ntbridge_child_range(dip, &boundbase, &boundlen,
103923c35297Sanish PCI_BASE_SPACE_IO) != DDI_SUCCESS) {
104023c35297Sanish cmn_err(CE_WARN, "ntbridge: IO resource information failure\n");
104123c35297Sanish phdl->io_len = 0;
104223c35297Sanish return (PCICFG_FAILURE);
104323c35297Sanish }
104423c35297Sanish io_request->ra_len = boundlen;
104523c35297Sanish io_request->ra_align_mask =
104623c35297Sanish PCICFG_IOGRAN - 1; /* 4K alignment on I/O space */
104723c35297Sanish io_request->ra_boundbase = boundbase;
104823c35297Sanish io_request->ra_boundlen = boundbase + boundlen;
104923c35297Sanish io_request->ra_flags |= NDI_RA_ALLOC_BOUNDED;
105023c35297Sanish
105123c35297Sanish /*
105223c35297Sanish * io_request->ra_len =
105323c35297Sanish * PCICFG_ROUND_UP(io_request->ra_len, PCICFG_IOGRAN);
105423c35297Sanish */
105523c35297Sanish
105623c35297Sanish phdl->io_base = phdl->io_last = (uint32_t)boundbase;
105723c35297Sanish phdl->io_len = (uint32_t)boundlen;
105823c35297Sanish phdl->io_hole.start = phdl->io_base;
105923c35297Sanish phdl->io_hole.len = io_request->ra_len;
106023c35297Sanish phdl->io_hole.next = (hole_t *)NULL;
106123c35297Sanish
106226947304SEvan Yan DEBUG2("Connector requested [0x%llx], needs [0x%llx] bytes of IO\n",
106323c35297Sanish boundlen, io_request->ra_len);
106423c35297Sanish
106523c35297Sanish /* Set Prefetchable Memory space handle for ntbridge */
106623c35297Sanish if (pcicfg_get_ntbridge_child_range(dip, &boundbase, &boundlen,
106723c35297Sanish PCI_BASE_SPACE_MEM | PCI_BASE_PREF_M) != DDI_SUCCESS) {
106823c35297Sanish cmn_err(CE_WARN,
106923c35297Sanish "ntbridge: PF Mem resource information failure\n");
107023c35297Sanish phdl->pf_memory_len = 0;
107123c35297Sanish return (PCICFG_FAILURE);
107223c35297Sanish }
107323c35297Sanish pf_mem_request->ra_boundbase = boundbase;
107423c35297Sanish pf_mem_request->ra_boundlen = boundbase + boundlen;
107523c35297Sanish pf_mem_request->ra_len = boundlen;
107623c35297Sanish pf_mem_request->ra_align_mask =
107723c35297Sanish PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */
107823c35297Sanish pf_mem_request->ra_flags |= NDI_RA_ALLOC_BOUNDED;
107923c35297Sanish
108023c35297Sanish /*
108123c35297Sanish * pf_mem_request->ra_len =
108223c35297Sanish * PCICFG_ROUND_UP(pf_mem_request->ra_len, PCICFG_MEMGRAN);
108323c35297Sanish */
108423c35297Sanish
108523c35297Sanish phdl->pf_memory_base = phdl->pf_memory_last = boundbase;
108623c35297Sanish phdl->pf_memory_len = boundlen;
108723c35297Sanish phdl->pf_mem_hole.start = phdl->pf_memory_base;
108823c35297Sanish phdl->pf_mem_hole.len = pf_mem_request->ra_len;
108923c35297Sanish phdl->pf_mem_hole.next = (hole_t *)NULL;
109023c35297Sanish
109126947304SEvan Yan DEBUG2("Connector requested [0x%llx], needs [0x%llx] bytes of PF "
109226947304SEvan Yan "memory\n", boundlen, pf_mem_request->ra_len);
109323c35297Sanish
109423c35297Sanish DEBUG2("MEMORY BASE = [0x%lx] length [0x%lx]\n",
109523c35297Sanish phdl->memory_base, phdl->memory_len);
109623c35297Sanish DEBUG2("IO BASE = [0x%x] length [0x%x]\n",
109723c35297Sanish phdl->io_base, phdl->io_len);
109823c35297Sanish DEBUG2("PF MEMORY BASE = [0x%lx] length [0x%lx]\n",
109923c35297Sanish phdl->pf_memory_base, phdl->pf_memory_len);
110023c35297Sanish
110123c35297Sanish return (PCICFG_SUCCESS);
110223c35297Sanish }
110323c35297Sanish
110423c35297Sanish static int
pcicfg_ntbridge_configure_done(dev_info_t * dip)110523c35297Sanish pcicfg_ntbridge_configure_done(dev_info_t *dip)
110623c35297Sanish {
110723c35297Sanish ppb_ranges_t range[PCICFG_RANGE_LEN];
110823c35297Sanish pcicfg_phdl_t *entry;
110923c35297Sanish uint_t len;
111023c35297Sanish pci_bus_range_t bus_range;
111123c35297Sanish int new_bus_range[2];
111223c35297Sanish
111323c35297Sanish DEBUG1("Configuring children for %p\n", dip);
111423c35297Sanish
111523c35297Sanish entry = pcicfg_find_phdl(dip);
111623c35297Sanish ASSERT(entry);
111723c35297Sanish
111826947304SEvan Yan bzero((caddr_t)range, sizeof (ppb_ranges_t) * PCICFG_RANGE_LEN);
111923c35297Sanish range[1].child_high = range[1].parent_high |=
112023c35297Sanish (PCI_REG_REL_M | PCI_ADDR_MEM32);
112123c35297Sanish range[1].child_low = range[1].parent_low = (uint32_t)entry->memory_base;
112223c35297Sanish
112323c35297Sanish range[0].child_high = range[0].parent_high |=
112423c35297Sanish (PCI_REG_REL_M | PCI_ADDR_IO);
112523c35297Sanish range[0].child_low = range[0].parent_low = (uint32_t)entry->io_base;
112623c35297Sanish
112723c35297Sanish range[2].child_high = range[2].parent_high |=
112823c35297Sanish (PCI_REG_REL_M | PCI_ADDR_MEM32 | PCI_REG_PF_M);
112923c35297Sanish range[2].child_low = range[2].parent_low =
113023c35297Sanish (uint32_t)entry->pf_memory_base;
113123c35297Sanish
113223c35297Sanish len = sizeof (pci_bus_range_t);
113323c35297Sanish if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
113423c35297Sanish "bus-range", (caddr_t)&bus_range, (int *)&len) != DDI_SUCCESS) {
113523c35297Sanish DEBUG0("no bus-range property\n");
113623c35297Sanish return (PCICFG_FAILURE);
113723c35297Sanish }
113823c35297Sanish
113923c35297Sanish new_bus_range[0] = bus_range.lo; /* primary bus number */
114023c35297Sanish if (entry->highest_bus) { /* secondary bus number */
114123c35297Sanish if (entry->highest_bus < bus_range.lo) {
114223c35297Sanish cmn_err(CE_WARN,
114323c35297Sanish "ntbridge bus range invalid !(%d,%d)\n",
114423c35297Sanish bus_range.lo, entry->highest_bus);
114523c35297Sanish new_bus_range[1] = bus_range.lo + entry->highest_bus;
114623c35297Sanish }
114723c35297Sanish else
114823c35297Sanish new_bus_range[1] = entry->highest_bus;
114923c35297Sanish }
115023c35297Sanish else
115123c35297Sanish new_bus_range[1] = bus_range.hi;
115223c35297Sanish
115326947304SEvan Yan DEBUG2("ntbridge: bus range lo=%x, hi=%x\n", new_bus_range[0],
115426947304SEvan Yan new_bus_range[1]);
115523c35297Sanish
115626947304SEvan Yan if (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "bus-range",
115726947304SEvan Yan new_bus_range, 2) != DDI_SUCCESS) {
115823c35297Sanish DEBUG0("Failed to set bus-range property");
115923c35297Sanish entry->error = PCICFG_FAILURE;
116023c35297Sanish return (PCICFG_FAILURE);
116123c35297Sanish }
116223c35297Sanish
116323c35297Sanish #ifdef DEBUG
116423c35297Sanish {
116523c35297Sanish uint64_t unused;
116623c35297Sanish unused = pcicfg_unused_space(&entry->io_hole, &len);
116723c35297Sanish DEBUG2("ntbridge: Unused IO space %llx bytes over %d holes\n",
116823c35297Sanish unused, len);
116923c35297Sanish }
117023c35297Sanish #endif
117123c35297Sanish
117223c35297Sanish range[0].size_low = entry->io_len;
117323c35297Sanish if (pcicfg_update_ranges_prop(dip, &range[0])) {
117423c35297Sanish DEBUG0("Failed to update ranges (i/o)\n");
117523c35297Sanish entry->error = PCICFG_FAILURE;
117623c35297Sanish return (PCICFG_FAILURE);
117723c35297Sanish }
117823c35297Sanish
117923c35297Sanish #ifdef DEBUG
118023c35297Sanish {
118123c35297Sanish uint64_t unused;
118223c35297Sanish unused = pcicfg_unused_space(&entry->mem_hole, &len);
118323c35297Sanish DEBUG2("ntbridge: Unused Mem space %llx bytes over %d holes\n",
118423c35297Sanish unused, len);
118523c35297Sanish }
118623c35297Sanish #endif
118723c35297Sanish
118823c35297Sanish range[1].size_low = entry->memory_len;
118923c35297Sanish if (pcicfg_update_ranges_prop(dip, &range[1])) {
119023c35297Sanish DEBUG0("Failed to update ranges (memory)\n");
119123c35297Sanish entry->error = PCICFG_FAILURE;
119223c35297Sanish return (PCICFG_FAILURE);
119323c35297Sanish }
119423c35297Sanish
119523c35297Sanish #ifdef DEBUG
119623c35297Sanish {
119723c35297Sanish uint64_t unused;
119823c35297Sanish unused = pcicfg_unused_space(&entry->pf_mem_hole, &len);
119923c35297Sanish DEBUG2("ntbridge: Unused PF Mem space %llx bytes over"
120023c35297Sanish " %d holes\n", unused, len);
120123c35297Sanish }
120223c35297Sanish #endif
120323c35297Sanish
120423c35297Sanish range[2].size_low = entry->pf_memory_len;
120523c35297Sanish if (pcicfg_update_ranges_prop(dip, &range[2])) {
120623c35297Sanish DEBUG0("Failed to update ranges (PF memory)\n");
120723c35297Sanish entry->error = PCICFG_FAILURE;
120823c35297Sanish return (PCICFG_FAILURE);
120923c35297Sanish }
121023c35297Sanish
121123c35297Sanish return (PCICFG_SUCCESS);
121223c35297Sanish }
121323c35297Sanish
121423c35297Sanish static int
pcicfg_ntbridge_program_child(dev_info_t * dip)121523c35297Sanish pcicfg_ntbridge_program_child(dev_info_t *dip)
121623c35297Sanish {
121723c35297Sanish pcicfg_phdl_t *entry;
121823c35297Sanish int rc = PCICFG_SUCCESS;
121923c35297Sanish dev_info_t *anode = dip;
122023c35297Sanish
122126947304SEvan Yan /* Find the Hotplug Connection (CN) node */
122226947304SEvan Yan while ((anode != NULL) &&
122326947304SEvan Yan (strcmp(ddi_binding_name(anode), "hp_attachment") != 0)) {
122423c35297Sanish anode = ddi_get_parent(anode);
122523c35297Sanish }
122623c35297Sanish
122723c35297Sanish if (anode == NULL) {
122823c35297Sanish DEBUG0("ntbridge child tree not in PROBE state\n");
122923c35297Sanish return (PCICFG_FAILURE);
123023c35297Sanish }
123123c35297Sanish entry = pcicfg_find_phdl(ddi_get_parent(anode));
123223c35297Sanish ASSERT(entry);
123323c35297Sanish
123423c35297Sanish if (pcicfg_bridge_assign(dip, entry) == DDI_WALK_TERMINATE) {
123523c35297Sanish cmn_err(CE_WARN,
123623c35297Sanish "ntbridge: Error assigning range for child %s\n",
123723c35297Sanish ddi_get_name(dip));
123823c35297Sanish rc = PCICFG_FAILURE;
123923c35297Sanish }
124023c35297Sanish return (rc);
124123c35297Sanish }
124223c35297Sanish
124323c35297Sanish static int
pcicfg_ntbridge_unconfigure_child(dev_info_t * new_device,uint_t devno)124423c35297Sanish pcicfg_ntbridge_unconfigure_child(dev_info_t *new_device, uint_t devno)
124523c35297Sanish {
124623c35297Sanish
124723c35297Sanish dev_info_t *new_ntbridgechild;
124823c35297Sanish int len, bus;
124923c35297Sanish uint16_t vid;
125023c35297Sanish ddi_acc_handle_t config_handle;
125123c35297Sanish pci_bus_range_t pci_bus_range;
125223c35297Sanish
125323c35297Sanish len = sizeof (pci_bus_range_t);
125423c35297Sanish if (ddi_getlongprop_buf(DDI_DEV_T_ANY, new_device, DDI_PROP_DONTPASS,
125523c35297Sanish "bus-range", (caddr_t)&pci_bus_range, &len) != DDI_SUCCESS) {
125623c35297Sanish DEBUG0("no bus-range property\n");
125723c35297Sanish return (PCICFG_FAILURE);
125823c35297Sanish }
125923c35297Sanish
126023c35297Sanish bus = pci_bus_range.lo; /* primary bus number of this bus node */
126123c35297Sanish
126223c35297Sanish ndi_devi_alloc_sleep(new_device, DEVI_PSEUDO_NEXNAME,
126323c35297Sanish (pnode_t)DEVI_SID_NODEID, &new_ntbridgechild);
126423c35297Sanish
126523c35297Sanish if (pcicfg_add_config_reg(new_ntbridgechild, bus, devno, 0)
126623c35297Sanish != DDI_PROP_SUCCESS) {
126726947304SEvan Yan cmn_err(CE_WARN, "Unconfigure: Failed to add conf reg prop for "
126826947304SEvan Yan "ntbridge child.\n");
126923c35297Sanish (void) ndi_devi_free(new_ntbridgechild);
127023c35297Sanish return (PCICFG_FAILURE);
127123c35297Sanish }
127223c35297Sanish
127323c35297Sanish if (pci_config_setup(new_ntbridgechild, &config_handle)
127423c35297Sanish != DDI_SUCCESS) {
127526947304SEvan Yan cmn_err(CE_WARN, "pcicfg: Cannot map ntbridge child %x\n",
127626947304SEvan Yan devno);
127723c35297Sanish (void) ndi_devi_free(new_ntbridgechild);
127823c35297Sanish return (PCICFG_FAILURE);
127923c35297Sanish }
128023c35297Sanish
128123c35297Sanish /*
128223c35297Sanish * See if there is any PCI HW at this location
128323c35297Sanish * by reading the Vendor ID. If it returns with 0xffff
128423c35297Sanish * then there is no hardware at this location.
128523c35297Sanish */
128623c35297Sanish vid = pci_config_get16(config_handle, PCI_CONF_VENID);
128723c35297Sanish
128823c35297Sanish pci_config_teardown(&config_handle);
128923c35297Sanish (void) ndi_devi_free(new_ntbridgechild);
129023c35297Sanish if (vid == 0xffff)
129123c35297Sanish return (PCICFG_NODEVICE);
129223c35297Sanish
129326947304SEvan Yan return (pcicfg_unconfigure(new_device, devno, PCICFG_ALL_FUNC, 0));
129423c35297Sanish }
129523c35297Sanish
129623c35297Sanish static uint_t
pcicfg_ntbridge_unconfigure(dev_info_t * dip)129723c35297Sanish pcicfg_ntbridge_unconfigure(dev_info_t *dip)
129823c35297Sanish {
129923c35297Sanish pcicfg_phdl_t *entry = pcicfg_find_phdl(dip);
130023c35297Sanish uint_t *bus;
130123c35297Sanish int k, rc = DDI_FAILURE;
130223c35297Sanish
130326947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "bus-range",
130426947304SEvan Yan (caddr_t)&bus, &k) != DDI_PROP_SUCCESS) {
130523c35297Sanish DEBUG0("ntbridge: Failed to read bus-range property\n");
130623c35297Sanish return (rc);
130723c35297Sanish }
130823c35297Sanish
130923c35297Sanish DEBUG2("ntbridge: Need to free bus [%d] range [%d]\n",
131023c35297Sanish bus[0], bus[1] - bus[0] + 1);
131123c35297Sanish
131226947304SEvan Yan if (ndi_ra_free(ddi_get_parent(dip), (uint64_t)bus[0],
131326947304SEvan Yan (uint64_t)(bus[1] - bus[0] + 1),
131423c35297Sanish NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS) != NDI_SUCCESS) {
131523c35297Sanish DEBUG0("ntbridge: Failed to free a bus number\n");
131623c35297Sanish kmem_free(bus, k);
131723c35297Sanish return (rc);
131823c35297Sanish }
131923c35297Sanish
132023c35297Sanish /*
132123c35297Sanish * Since our resources will be freed at the parent level,
132223c35297Sanish * just reset these values.
132323c35297Sanish */
132423c35297Sanish entry->memory_len = 0;
132523c35297Sanish entry->io_len = 0;
132623c35297Sanish entry->pf_memory_len = 0;
132723c35297Sanish
132823c35297Sanish kmem_free(bus, k);
132923c35297Sanish
133023c35297Sanish /* the following will also free hole data. */
133123c35297Sanish return (pcicfg_destroy_phdl(dip));
133223c35297Sanish
133323c35297Sanish }
133423c35297Sanish
133523c35297Sanish static int
pcicfg_is_ntbridge(dev_info_t * dip)133623c35297Sanish pcicfg_is_ntbridge(dev_info_t *dip)
133723c35297Sanish {
133823c35297Sanish ddi_acc_handle_t config_handle;
133923c35297Sanish uint8_t class, subclass;
134023c35297Sanish int rc = DDI_SUCCESS;
134123c35297Sanish
134223c35297Sanish if (pci_config_setup(dip, &config_handle) != DDI_SUCCESS) {
134323c35297Sanish cmn_err(CE_WARN,
134423c35297Sanish "pcicfg: cannot map config space, to get map type\n");
134523c35297Sanish return (DDI_FAILURE);
134623c35297Sanish }
134723c35297Sanish class = pci_config_get8(config_handle, PCI_CONF_BASCLASS);
134823c35297Sanish subclass = pci_config_get8(config_handle, PCI_CONF_SUBCLASS);
134923c35297Sanish
135023c35297Sanish /* check for class=6, subclass=9, for non transparent bridges. */
135123c35297Sanish if ((class != PCI_CLASS_BRIDGE) || (subclass != PCI_BRIDGE_STBRIDGE))
135223c35297Sanish rc = DDI_FAILURE;
135323c35297Sanish
135423c35297Sanish DEBUG3("pcicfg: checking device %x,%x for indirect map. rc=%d\n",
135523c35297Sanish pci_config_get16(config_handle, PCI_CONF_VENID),
135623c35297Sanish pci_config_get16(config_handle, PCI_CONF_DEVID),
135723c35297Sanish rc);
135823c35297Sanish pci_config_teardown(&config_handle);
135923c35297Sanish return (rc);
136023c35297Sanish }
136123c35297Sanish
136223c35297Sanish static uint_t
pcicfg_ntbridge_child(dev_info_t * dip)136323c35297Sanish pcicfg_ntbridge_child(dev_info_t *dip)
136423c35297Sanish {
136523c35297Sanish int len, val, rc = DDI_FAILURE;
136623c35297Sanish dev_info_t *anode = dip;
136723c35297Sanish
136823c35297Sanish /*
136926947304SEvan Yan * Find the Hotplug Connection (CN) node
137023c35297Sanish */
137123c35297Sanish while ((anode != NULL) && (strcmp(ddi_binding_name(anode),
137223c35297Sanish "hp_attachment") != 0)) {
137323c35297Sanish anode = ddi_get_parent(anode);
137423c35297Sanish }
137523c35297Sanish
137623c35297Sanish if (anode == NULL) {
137723c35297Sanish DEBUG0("ntbridge child tree not in PROBE state\n");
137823c35297Sanish return (rc);
137923c35297Sanish }
138023c35297Sanish len = sizeof (int);
138123c35297Sanish if (ddi_getlongprop_buf(DDI_DEV_T_ANY, ddi_get_parent(anode),
138226947304SEvan Yan DDI_PROP_DONTPASS, PCI_DEV_CONF_MAP_PROP, (caddr_t)&val, &len)
138326947304SEvan Yan != DDI_SUCCESS) {
138423c35297Sanish
138523c35297Sanish DEBUG1("ntbridge child: no \"%s\" property\n",
138623c35297Sanish PCI_DEV_CONF_MAP_PROP);
138723c35297Sanish return (rc);
138823c35297Sanish }
138923c35297Sanish DEBUG0("ntbridge child: success\n");
139023c35297Sanish return (DDI_SUCCESS);
139123c35297Sanish }
139223c35297Sanish
139323c35297Sanish static uint_t
pcicfg_get_ntbridge_child_range(dev_info_t * dip,uint64_t * boundbase,uint64_t * boundlen,uint_t space_type)139423c35297Sanish pcicfg_get_ntbridge_child_range(dev_info_t *dip, uint64_t *boundbase,
139523c35297Sanish uint64_t *boundlen, uint_t space_type)
139623c35297Sanish {
139723c35297Sanish int length, found = DDI_FAILURE, acount, i, ibridge;
139823c35297Sanish pci_regspec_t *assigned;
139923c35297Sanish
140023c35297Sanish if ((ibridge = pcicfg_is_ntbridge(dip)) == DDI_FAILURE)
140123c35297Sanish return (found);
140223c35297Sanish
140326947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
140426947304SEvan Yan "assigned-addresses", (caddr_t)&assigned, &length)
140526947304SEvan Yan != DDI_PROP_SUCCESS) {
140623c35297Sanish DEBUG1("Failed to get assigned-addresses property %llx\n", dip);
140723c35297Sanish return (found);
140823c35297Sanish }
140923c35297Sanish DEBUG1("pcicfg: ntbridge child range: dip = %s\n",
141023c35297Sanish ddi_driver_name(dip));
141123c35297Sanish
141223c35297Sanish acount = length / sizeof (pci_regspec_t);
141323c35297Sanish
141423c35297Sanish for (i = 0; i < acount; i++) {
141526947304SEvan Yan if ((PCI_REG_REG_G(assigned[i].pci_phys_hi) ==
141626947304SEvan Yan pcicfg_indirect_map_devs[ibridge].mem_range_bar_offset) &&
141723c35297Sanish (space_type == PCI_BASE_SPACE_MEM)) {
141823c35297Sanish found = DDI_SUCCESS;
141923c35297Sanish break;
142026947304SEvan Yan } else if ((PCI_REG_REG_G(assigned[i].pci_phys_hi) ==
142126947304SEvan Yan pcicfg_indirect_map_devs[ibridge].io_range_bar_offset) &&
142223c35297Sanish (space_type == PCI_BASE_SPACE_IO)) {
142323c35297Sanish found = DDI_SUCCESS;
142423c35297Sanish break;
142526947304SEvan Yan } else if ((PCI_REG_REG_G(assigned[i].pci_phys_hi) ==
142623c35297Sanish pcicfg_indirect_map_devs[ibridge].
142723c35297Sanish prefetch_mem_range_bar_offset) &&
142823c35297Sanish (space_type == (PCI_BASE_SPACE_MEM |
142923c35297Sanish PCI_BASE_PREF_M))) {
143023c35297Sanish found = DDI_SUCCESS;
143123c35297Sanish break;
143223c35297Sanish }
143323c35297Sanish }
143423c35297Sanish DEBUG3("pcicfg: ntbridge child range: space=%x, base=%lx, len=%lx\n",
143523c35297Sanish space_type, assigned[i].pci_phys_low, assigned[i].pci_size_low);
143623c35297Sanish
143723c35297Sanish if (found == DDI_SUCCESS) {
143823c35297Sanish *boundbase = assigned[i].pci_phys_low;
143923c35297Sanish *boundlen = assigned[i].pci_size_low;
144023c35297Sanish }
144123c35297Sanish
144223c35297Sanish kmem_free(assigned, length);
144323c35297Sanish return (found);
144423c35297Sanish }
144523c35297Sanish
144623c35297Sanish /*
144723c35297Sanish * This will turn resources allocated by pcicfg_configure()
144826947304SEvan Yan * and remove the device tree from the Hotplug Connection (CN)
144923c35297Sanish * and below. The routine assumes the devices have their
145023c35297Sanish * drivers detached.
145123c35297Sanish */
145223c35297Sanish int
pcicfg_unconfigure(dev_info_t * devi,uint_t device,uint_t function,pcicfg_flags_t flags)145326947304SEvan Yan pcicfg_unconfigure(dev_info_t *devi, uint_t device, uint_t function,
145426947304SEvan Yan pcicfg_flags_t flags)
145523c35297Sanish {
145623c35297Sanish dev_info_t *child_dip;
145723c35297Sanish int func;
145823c35297Sanish int i;
145926947304SEvan Yan int max_function, trans_device;
1460c0da6274SZhi-Jun Robin Fu int circ;
1461c0da6274SZhi-Jun Robin Fu boolean_t is_pcie;
146226947304SEvan Yan
146326947304SEvan Yan if (pcie_ari_is_enabled(devi) == PCIE_ARI_FORW_ENABLED)
146426947304SEvan Yan max_function = PCICFG_MAX_ARI_FUNCTION;
146526947304SEvan Yan else
146626947304SEvan Yan max_function = PCI_MAX_FUNCTIONS;
146723c35297Sanish
146823c35297Sanish /*
146923c35297Sanish * Cycle through devices to make sure none are busy.
147023c35297Sanish * If a single device is busy fail the whole unconfigure.
147123c35297Sanish */
1472c0da6274SZhi-Jun Robin Fu is_pcie = is_pcie_fabric(devi);
1473c0da6274SZhi-Jun Robin Fu
1474c0da6274SZhi-Jun Robin Fu ndi_devi_enter(devi, &circ);
147526947304SEvan Yan for (func = 0; func < max_function; func++) {
147626947304SEvan Yan if ((function != PCICFG_ALL_FUNC) && (function != func))
147726947304SEvan Yan continue;
147826947304SEvan Yan
147926947304SEvan Yan if (max_function == PCICFG_MAX_ARI_FUNCTION)
148026947304SEvan Yan trans_device = func >> 3; /* ARI Device */
148126947304SEvan Yan else
148226947304SEvan Yan trans_device = device;
148326947304SEvan Yan
148426947304SEvan Yan if ((child_dip = pcicfg_devi_find(devi, trans_device,
148526947304SEvan Yan func & 7)) == NULL)
148623c35297Sanish continue;
148723c35297Sanish
148823c35297Sanish if (ndi_devi_offline(child_dip, NDI_UNCONFIG) == NDI_SUCCESS)
148923c35297Sanish continue;
149026947304SEvan Yan
149123c35297Sanish /*
149223c35297Sanish * Device function is busy. Before returning we have to
149323c35297Sanish * put all functions back online which were taken
149423c35297Sanish * offline during the process.
149523c35297Sanish */
149626947304SEvan Yan DEBUG2("Device [0x%x] function [0x%x] is busy\n",
149726947304SEvan Yan trans_device, func & 7);
149826947304SEvan Yan /*
149926947304SEvan Yan * If we are only asked to offline one specific function,
150026947304SEvan Yan * and that fails, we just simply return.
150126947304SEvan Yan */
150226947304SEvan Yan if (function != PCICFG_ALL_FUNC)
150326947304SEvan Yan return (PCICFG_FAILURE);
150426947304SEvan Yan
150523c35297Sanish for (i = 0; i < func; i++) {
150626947304SEvan Yan if (max_function == PCICFG_MAX_ARI_FUNCTION)
150726947304SEvan Yan trans_device = i >> 3;
150826947304SEvan Yan
150926947304SEvan Yan if ((child_dip = pcicfg_devi_find(devi, trans_device,
151026947304SEvan Yan i & 7)) == NULL) {
151126947304SEvan Yan DEBUG0("No more devices to put back "
151226947304SEvan Yan "on line!!\n");
151323c35297Sanish /*
151423c35297Sanish * Made it through all functions
151523c35297Sanish */
151623c35297Sanish continue;
151723c35297Sanish }
151826947304SEvan Yan if (ndi_devi_online(child_dip, NDI_CONFIG)
151926947304SEvan Yan != NDI_SUCCESS) {
152023c35297Sanish DEBUG0("Failed to put back devices state\n");
1521c0da6274SZhi-Jun Robin Fu goto fail;
152223c35297Sanish }
152323c35297Sanish }
1524c0da6274SZhi-Jun Robin Fu goto fail;
152523c35297Sanish }
152623c35297Sanish
152723c35297Sanish /*
152826947304SEvan Yan * Now, tear down all devinfo nodes for this Connector.
152923c35297Sanish */
153026947304SEvan Yan for (func = 0; func < max_function; func++) {
153126947304SEvan Yan if ((function != PCICFG_ALL_FUNC) && (function != func))
153226947304SEvan Yan continue;
153326947304SEvan Yan
153426947304SEvan Yan if (max_function == PCICFG_MAX_ARI_FUNCTION)
153526947304SEvan Yan trans_device = func >> 3; /* ARI Device */
153626947304SEvan Yan else
153726947304SEvan Yan trans_device = device;
153826947304SEvan Yan
153926947304SEvan Yan if ((child_dip = pcicfg_devi_find(devi, trans_device, func & 7))
154026947304SEvan Yan == NULL) {
154126947304SEvan Yan DEBUG2("No device at %x,%x\n", trans_device, func & 7);
154223c35297Sanish continue;
154323c35297Sanish }
154423c35297Sanish
154523c35297Sanish DEBUG2("Tearing down device [0x%x] function [0x%x]\n",
154626947304SEvan Yan trans_device, func & 7);
154723c35297Sanish
154823c35297Sanish if (pcicfg_is_ntbridge(child_dip) != DDI_FAILURE)
154923c35297Sanish if (pcicfg_ntbridge_unconfigure(child_dip) !=
155023c35297Sanish PCICFG_SUCCESS) {
155123c35297Sanish cmn_err(CE_WARN,
155223c35297Sanish "ntbridge: unconfigure failed\n");
1553c0da6274SZhi-Jun Robin Fu goto fail;
155423c35297Sanish }
155523c35297Sanish
1556c0da6274SZhi-Jun Robin Fu if (pcicfg_teardown_device(child_dip, flags, is_pcie)
155726947304SEvan Yan != PCICFG_SUCCESS) {
155823c35297Sanish DEBUG2("Failed to tear down device [0x%x]"
155926947304SEvan Yan "function [0x%x]\n", trans_device, func & 7);
1560c0da6274SZhi-Jun Robin Fu goto fail;
156123c35297Sanish }
156223c35297Sanish }
156326947304SEvan Yan
156426947304SEvan Yan if (pcie_ari_is_enabled(devi) == PCIE_ARI_FORW_ENABLED) {
156526947304SEvan Yan (void) ddi_prop_remove(DDI_DEV_T_NONE, devi, "ari-enabled");
156626947304SEvan Yan (void) pcie_ari_disable(devi);
156726947304SEvan Yan }
156826947304SEvan Yan
1569c0da6274SZhi-Jun Robin Fu ndi_devi_exit(devi, circ);
157023c35297Sanish return (PCICFG_SUCCESS);
1571c0da6274SZhi-Jun Robin Fu
1572c0da6274SZhi-Jun Robin Fu fail:
1573c0da6274SZhi-Jun Robin Fu ndi_devi_exit(devi, circ);
1574c0da6274SZhi-Jun Robin Fu return (PCICFG_FAILURE);
157523c35297Sanish }
157623c35297Sanish
157723c35297Sanish static int
pcicfg_teardown_device(dev_info_t * dip,pcicfg_flags_t flags,boolean_t is_pcie)1578c0da6274SZhi-Jun Robin Fu pcicfg_teardown_device(dev_info_t *dip, pcicfg_flags_t flags, boolean_t is_pcie)
157923c35297Sanish {
158023c35297Sanish ddi_acc_handle_t handle;
158123c35297Sanish
158223c35297Sanish /*
158323c35297Sanish * Free up resources associated with 'dip'
158423c35297Sanish */
158526947304SEvan Yan if (pcicfg_free_resources(dip, flags) != PCICFG_SUCCESS) {
158623c35297Sanish DEBUG0("Failed to free resources\n");
158723c35297Sanish return (PCICFG_FAILURE);
158823c35297Sanish }
158923c35297Sanish
159023c35297Sanish /*
159123c35297Sanish * disable the device
159223c35297Sanish */
159323c35297Sanish if (pcicfg_config_setup(dip, &handle) != PCICFG_SUCCESS)
159423c35297Sanish return (PCICFG_FAILURE);
159523c35297Sanish pcicfg_device_off(handle);
159623c35297Sanish pcicfg_config_teardown(&handle);
159723c35297Sanish
1598c0da6274SZhi-Jun Robin Fu if (is_pcie) {
1599c0da6274SZhi-Jun Robin Fu /*
1600c0da6274SZhi-Jun Robin Fu * free pcie_bus_t for the sub-tree
1601c0da6274SZhi-Jun Robin Fu */
1602c0da6274SZhi-Jun Robin Fu if (ddi_get_child(dip) != NULL)
1603c0da6274SZhi-Jun Robin Fu pcie_fab_fini_bus(dip, PCIE_BUS_ALL);
1604c0da6274SZhi-Jun Robin Fu
1605c0da6274SZhi-Jun Robin Fu pcie_fini_bus(dip, PCIE_BUS_ALL);
1606c0da6274SZhi-Jun Robin Fu }
1607c0da6274SZhi-Jun Robin Fu
160823c35297Sanish /*
160923c35297Sanish * The framework provides this routine which can
161023c35297Sanish * tear down a sub-tree.
161123c35297Sanish */
161223c35297Sanish if (ndi_devi_offline(dip, NDI_DEVI_REMOVE) != NDI_SUCCESS) {
161323c35297Sanish DEBUG0("Failed to offline and remove node\n");
161423c35297Sanish return (PCICFG_FAILURE);
161523c35297Sanish }
161623c35297Sanish
161723c35297Sanish return (PCICFG_SUCCESS);
161823c35297Sanish }
161923c35297Sanish
162023c35297Sanish /*
162123c35297Sanish * BEGIN GENERIC SUPPORT ROUTINES
162223c35297Sanish */
162323c35297Sanish static pcicfg_phdl_t *
pcicfg_find_phdl(dev_info_t * dip)162423c35297Sanish pcicfg_find_phdl(dev_info_t *dip)
162523c35297Sanish {
162623c35297Sanish pcicfg_phdl_t *entry;
162723c35297Sanish mutex_enter(&pcicfg_list_mutex);
162823c35297Sanish for (entry = pcicfg_phdl_list; entry != NULL; entry = entry->next) {
162923c35297Sanish if (entry->dip == dip) {
163023c35297Sanish mutex_exit(&pcicfg_list_mutex);
163123c35297Sanish return (entry);
163223c35297Sanish }
163323c35297Sanish }
163423c35297Sanish mutex_exit(&pcicfg_list_mutex);
163523c35297Sanish
163623c35297Sanish /*
163723c35297Sanish * Did'nt find entry - create one
163823c35297Sanish */
163923c35297Sanish return (pcicfg_create_phdl(dip));
164023c35297Sanish }
164123c35297Sanish
164223c35297Sanish static pcicfg_phdl_t *
pcicfg_create_phdl(dev_info_t * dip)164323c35297Sanish pcicfg_create_phdl(dev_info_t *dip)
164423c35297Sanish {
164523c35297Sanish pcicfg_phdl_t *new;
164623c35297Sanish
164726947304SEvan Yan new = (pcicfg_phdl_t *)kmem_zalloc(sizeof (pcicfg_phdl_t), KM_SLEEP);
164823c35297Sanish
164923c35297Sanish new->dip = dip;
165023c35297Sanish mutex_enter(&pcicfg_list_mutex);
165123c35297Sanish new->next = pcicfg_phdl_list;
165223c35297Sanish pcicfg_phdl_list = new;
165323c35297Sanish mutex_exit(&pcicfg_list_mutex);
165423c35297Sanish
165523c35297Sanish return (new);
165623c35297Sanish }
165723c35297Sanish
165823c35297Sanish static int
pcicfg_destroy_phdl(dev_info_t * dip)165923c35297Sanish pcicfg_destroy_phdl(dev_info_t *dip)
166023c35297Sanish {
166123c35297Sanish pcicfg_phdl_t *entry;
166223c35297Sanish pcicfg_phdl_t *follow = NULL;
166323c35297Sanish
166423c35297Sanish mutex_enter(&pcicfg_list_mutex);
166523c35297Sanish for (entry = pcicfg_phdl_list; entry != NULL; follow = entry,
166623c35297Sanish entry = entry->next) {
166723c35297Sanish if (entry->dip == dip) {
166823c35297Sanish if (entry == pcicfg_phdl_list) {
166923c35297Sanish pcicfg_phdl_list = entry->next;
167023c35297Sanish } else {
167123c35297Sanish follow->next = entry->next;
167223c35297Sanish }
167323c35297Sanish /*
167423c35297Sanish * If this entry has any allocated memory
167523c35297Sanish * or IO space associated with it, that
167623c35297Sanish * must be freed up.
167723c35297Sanish */
167823c35297Sanish if (entry->memory_len > 0) {
167923c35297Sanish (void) ndi_ra_free(ddi_get_parent(dip),
168026947304SEvan Yan entry->memory_base, entry->memory_len,
168123c35297Sanish NDI_RA_TYPE_MEM, NDI_RA_PASS);
168223c35297Sanish }
168323c35297Sanish pcicfg_free_hole(&entry->mem_hole);
168423c35297Sanish
168523c35297Sanish if (entry->io_len > 0) {
168623c35297Sanish (void) ndi_ra_free(ddi_get_parent(dip),
168726947304SEvan Yan entry->io_base, entry->io_len,
168823c35297Sanish NDI_RA_TYPE_IO, NDI_RA_PASS);
168923c35297Sanish }
169023c35297Sanish pcicfg_free_hole(&entry->io_hole);
169123c35297Sanish
169223c35297Sanish if (entry->pf_memory_len > 0) {
169323c35297Sanish (void) ndi_ra_free(ddi_get_parent(dip),
169426947304SEvan Yan entry->pf_memory_base, entry->pf_memory_len,
169526947304SEvan Yan NDI_RA_TYPE_PCI_PREFETCH_MEM, NDI_RA_PASS);
169623c35297Sanish }
169723c35297Sanish pcicfg_free_hole(&entry->pf_mem_hole);
169823c35297Sanish
169923c35297Sanish /*
170023c35297Sanish * Destroy this entry
170123c35297Sanish */
170223c35297Sanish kmem_free((caddr_t)entry, sizeof (pcicfg_phdl_t));
170323c35297Sanish mutex_exit(&pcicfg_list_mutex);
170423c35297Sanish return (PCICFG_SUCCESS);
170523c35297Sanish }
170623c35297Sanish }
170723c35297Sanish mutex_exit(&pcicfg_list_mutex);
170823c35297Sanish /*
170923c35297Sanish * Did'nt find the entry
171023c35297Sanish */
171123c35297Sanish return (PCICFG_FAILURE);
171223c35297Sanish }
171323c35297Sanish
171423c35297Sanish static int
pcicfg_bridge_assign(dev_info_t * dip,void * hdl)171523c35297Sanish pcicfg_bridge_assign(dev_info_t *dip, void *hdl)
171623c35297Sanish {
171723c35297Sanish ddi_acc_handle_t handle;
171823c35297Sanish pci_regspec_t *reg;
171923c35297Sanish int length;
172023c35297Sanish int rcount;
172123c35297Sanish int i;
172223c35297Sanish int offset;
172323c35297Sanish uint64_t mem_answer;
172423c35297Sanish uint32_t io_answer;
172523c35297Sanish int count;
172623c35297Sanish uint8_t header_type;
172723c35297Sanish ppb_ranges_t range[PCICFG_RANGE_LEN];
172823c35297Sanish int bus_range[2];
172923c35297Sanish uint64_t mem_residual;
173023c35297Sanish uint64_t pf_mem_residual;
173123c35297Sanish uint64_t io_residual;
173223c35297Sanish
173323c35297Sanish pcicfg_phdl_t *entry = (pcicfg_phdl_t *)hdl;
173423c35297Sanish
173526947304SEvan Yan DEBUG1("bridge assign: assigning addresses to %s\n", ddi_get_name(dip));
173623c35297Sanish
173723c35297Sanish entry->error = PCICFG_SUCCESS;
173823c35297Sanish
173923c35297Sanish if (entry == NULL) {
174023c35297Sanish DEBUG0("Failed to get entry\n");
174123c35297Sanish entry->error = PCICFG_FAILURE;
174223c35297Sanish return (DDI_WALK_TERMINATE);
174323c35297Sanish }
174423c35297Sanish
174526947304SEvan Yan if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
174623c35297Sanish DEBUG0("Failed to map config space!\n");
174723c35297Sanish entry->error = PCICFG_FAILURE;
174823c35297Sanish return (DDI_WALK_TERMINATE);
174923c35297Sanish }
175023c35297Sanish
175123c35297Sanish header_type = pci_config_get8(handle, PCI_CONF_HEADER);
175223c35297Sanish
175323c35297Sanish if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
175423c35297Sanish
175526947304SEvan Yan bzero((caddr_t)range, sizeof (ppb_ranges_t) * PCICFG_RANGE_LEN);
175623c35297Sanish
175723c35297Sanish (void) pcicfg_setup_bridge(entry, handle);
175823c35297Sanish
175923c35297Sanish range[0].child_high = range[0].parent_high |=
176023c35297Sanish (PCI_REG_REL_M | PCI_ADDR_IO);
176126947304SEvan Yan range[0].child_low = range[0].parent_low = entry->io_last;
176223c35297Sanish range[1].child_high = range[1].parent_high |=
176323c35297Sanish (PCI_REG_REL_M | PCI_ADDR_MEM32);
176423c35297Sanish range[1].child_low = range[1].parent_low =
176523c35297Sanish entry->memory_last;
176623c35297Sanish range[2].child_high = range[2].parent_high |=
176723c35297Sanish (PCI_REG_REL_M | PCI_ADDR_MEM32 | PCI_REG_PF_M);
176823c35297Sanish range[2].child_low = range[2].parent_low =
176923c35297Sanish entry->pf_memory_last;
177023c35297Sanish
177123c35297Sanish ndi_devi_enter(dip, &count);
177223c35297Sanish ddi_walk_devs(ddi_get_child(dip),
177323c35297Sanish pcicfg_bridge_assign, (void *)entry);
177423c35297Sanish ndi_devi_exit(dip, count);
177523c35297Sanish
177623c35297Sanish (void) pcicfg_update_bridge(entry, handle);
177723c35297Sanish
177823c35297Sanish bus_range[0] = pci_config_get8(handle, PCI_BCNF_SECBUS);
177923c35297Sanish bus_range[1] = pci_config_get8(handle, PCI_BCNF_SUBBUS);
178023c35297Sanish
178123c35297Sanish if (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
178223c35297Sanish "bus-range", bus_range, 2) != DDI_SUCCESS) {
178323c35297Sanish DEBUG0("Failed to set bus-range property");
178423c35297Sanish entry->error = PCICFG_FAILURE;
17851fb5b786Sprasad (void) pcicfg_config_teardown(&handle);
178623c35297Sanish return (DDI_WALK_TERMINATE);
178723c35297Sanish }
178823c35297Sanish
178923c35297Sanish /*
179023c35297Sanish * Put back memory and I/O space not allocated
179123c35297Sanish * under the bridge.
179223c35297Sanish */
179323c35297Sanish mem_residual = entry->memory_len -
179423c35297Sanish (entry->memory_last - entry->memory_base);
179523c35297Sanish if (mem_residual > 0) {
179623c35297Sanish (void) ndi_ra_free(ddi_get_parent(dip),
179726947304SEvan Yan entry->memory_last, mem_residual,
179823c35297Sanish NDI_RA_TYPE_MEM, NDI_RA_PASS);
179923c35297Sanish }
180023c35297Sanish
180126947304SEvan Yan io_residual = entry->io_len - (entry->io_last - entry->io_base);
180223c35297Sanish if (io_residual > 0) {
180326947304SEvan Yan (void) ndi_ra_free(ddi_get_parent(dip), entry->io_last,
180426947304SEvan Yan io_residual, NDI_RA_TYPE_IO, NDI_RA_PASS);
180523c35297Sanish }
180623c35297Sanish
180723c35297Sanish pf_mem_residual = entry->pf_memory_len -
180823c35297Sanish (entry->pf_memory_last - entry->pf_memory_base);
180923c35297Sanish if (pf_mem_residual > 0) {
181023c35297Sanish (void) ndi_ra_free(ddi_get_parent(dip),
181126947304SEvan Yan entry->pf_memory_last, pf_mem_residual,
181223c35297Sanish NDI_RA_TYPE_PCI_PREFETCH_MEM, NDI_RA_PASS);
181323c35297Sanish }
181423c35297Sanish
181523c35297Sanish if (entry->io_len > 0) {
181623c35297Sanish range[0].size_low = entry->io_last - entry->io_base;
181723c35297Sanish if (pcicfg_update_ranges_prop(dip, &range[0])) {
181823c35297Sanish DEBUG0("Failed to update ranges (i/o)\n");
181923c35297Sanish entry->error = PCICFG_FAILURE;
18201fb5b786Sprasad (void) pcicfg_config_teardown(&handle);
182123c35297Sanish return (DDI_WALK_TERMINATE);
182223c35297Sanish }
182323c35297Sanish }
182423c35297Sanish if (entry->memory_len > 0) {
182523c35297Sanish range[1].size_low =
182623c35297Sanish entry->memory_last - entry->memory_base;
182723c35297Sanish if (pcicfg_update_ranges_prop(dip, &range[1])) {
182823c35297Sanish DEBUG0("Failed to update ranges (memory)\n");
182923c35297Sanish entry->error = PCICFG_FAILURE;
18301fb5b786Sprasad (void) pcicfg_config_teardown(&handle);
183123c35297Sanish return (DDI_WALK_TERMINATE);
183223c35297Sanish }
183323c35297Sanish }
183423c35297Sanish if (entry->pf_memory_len > 0) {
183523c35297Sanish range[2].size_low =
183623c35297Sanish entry->pf_memory_last - entry->pf_memory_base;
183723c35297Sanish if (pcicfg_update_ranges_prop(dip, &range[2])) {
183823c35297Sanish DEBUG0("Failed to update ranges (PF memory)\n");
183923c35297Sanish entry->error = PCICFG_FAILURE;
18401fb5b786Sprasad (void) pcicfg_config_teardown(&handle);
184123c35297Sanish return (DDI_WALK_TERMINATE);
184223c35297Sanish }
184323c35297Sanish }
184423c35297Sanish
184523c35297Sanish (void) pcicfg_device_on(handle);
184623c35297Sanish
184723c35297Sanish PCICFG_DUMP_BRIDGE_CONFIG(handle);
184823c35297Sanish
18491fb5b786Sprasad (void) pcicfg_config_teardown(&handle);
18501fb5b786Sprasad
185123c35297Sanish return (DDI_WALK_PRUNECHILD);
185223c35297Sanish }
185323c35297Sanish
185423c35297Sanish /*
185523c35297Sanish * If there is an interrupt pin set program
185623c35297Sanish * interrupt line with default values.
185723c35297Sanish */
185823c35297Sanish if (pci_config_get8(handle, PCI_CONF_IPIN)) {
185923c35297Sanish pci_config_put8(handle, PCI_CONF_ILINE, 0xf);
186023c35297Sanish }
186123c35297Sanish
186223c35297Sanish /*
186323c35297Sanish * A single device (under a bridge).
186423c35297Sanish * For each "reg" property with a length, allocate memory
186523c35297Sanish * and program the base registers.
186623c35297Sanish */
186726947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg",
186826947304SEvan Yan (caddr_t)®, &length) != DDI_PROP_SUCCESS) {
186923c35297Sanish DEBUG0("Failed to read reg property\n");
187023c35297Sanish entry->error = PCICFG_FAILURE;
18711fb5b786Sprasad (void) pcicfg_config_teardown(&handle);
187223c35297Sanish return (DDI_WALK_TERMINATE);
187323c35297Sanish }
187423c35297Sanish
187523c35297Sanish rcount = length / sizeof (pci_regspec_t);
187623c35297Sanish offset = PCI_CONF_BASE0;
187723c35297Sanish for (i = 0; i < rcount; i++) {
187826947304SEvan Yan if ((reg[i].pci_size_low != 0) || (reg[i].pci_size_hi != 0)) {
187923c35297Sanish
188023c35297Sanish offset = PCI_REG_REG_G(reg[i].pci_phys_hi);
188123c35297Sanish
188223c35297Sanish switch (PCI_REG_ADDR_G(reg[i].pci_phys_hi)) {
188323c35297Sanish case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
188423c35297Sanish
188523c35297Sanish if (reg[i].pci_phys_hi & PCI_REG_PF_M) {
188623c35297Sanish /* allocate prefetchable memory */
188723c35297Sanish pcicfg_get_pf_mem(entry,
188823c35297Sanish reg[i].pci_size_low, &mem_answer);
188923c35297Sanish } else { /* get non prefetchable memory */
189023c35297Sanish pcicfg_get_mem(entry,
189123c35297Sanish reg[i].pci_size_low, &mem_answer);
189223c35297Sanish }
189323c35297Sanish pci_config_put64(handle, offset, mem_answer);
189423c35297Sanish DEBUG2("REGISTER off %x (64)LO ----> [0x%x]\n",
189526947304SEvan Yan offset, pci_config_get32(handle, offset));
189623c35297Sanish DEBUG2("REGISTER off %x (64)HI ----> [0x%x]\n",
189723c35297Sanish offset + 4,
189823c35297Sanish pci_config_get32(handle, offset + 4));
189923c35297Sanish
190023c35297Sanish reg[i].pci_phys_hi |= PCI_REG_REL_M;
190123c35297Sanish reg[i].pci_phys_low = PCICFG_LOADDR(mem_answer);
190226947304SEvan Yan reg[i].pci_phys_mid = PCICFG_HIADDR(mem_answer);
190323c35297Sanish break;
190423c35297Sanish
190523c35297Sanish case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
190623c35297Sanish if (reg[i].pci_phys_hi & PCI_REG_PF_M) {
190723c35297Sanish /* allocate prefetchable memory */
190823c35297Sanish pcicfg_get_pf_mem(entry,
190923c35297Sanish reg[i].pci_size_low, &mem_answer);
191023c35297Sanish } else {
191123c35297Sanish /* get non prefetchable memory */
191223c35297Sanish pcicfg_get_mem(entry,
191323c35297Sanish reg[i].pci_size_low, &mem_answer);
191423c35297Sanish }
191523c35297Sanish
191626947304SEvan Yan pci_config_put32(handle, offset,
191726947304SEvan Yan (uint32_t)mem_answer);
191823c35297Sanish
191923c35297Sanish DEBUG2("REGISTER off %x(32)LO ----> [0x%x]\n",
192026947304SEvan Yan offset, pci_config_get32(handle, offset));
192123c35297Sanish
192223c35297Sanish reg[i].pci_phys_hi |= PCI_REG_REL_M;
192323c35297Sanish reg[i].pci_phys_low = (uint32_t)mem_answer;
192423c35297Sanish
192523c35297Sanish break;
192623c35297Sanish case PCI_REG_ADDR_G(PCI_ADDR_IO):
192723c35297Sanish /* allocate I/O space from the allocator */
192823c35297Sanish
192926947304SEvan Yan (void) pcicfg_get_io(entry, reg[i].pci_size_low,
193026947304SEvan Yan &io_answer);
193123c35297Sanish pci_config_put32(handle, offset, io_answer);
193223c35297Sanish
193323c35297Sanish DEBUG2("REGISTER off %x (I/O)LO ----> [0x%x]\n",
193426947304SEvan Yan offset, pci_config_get32(handle, offset));
193523c35297Sanish
193623c35297Sanish reg[i].pci_phys_hi |= PCI_REG_REL_M;
193723c35297Sanish reg[i].pci_phys_low = io_answer;
193823c35297Sanish
193923c35297Sanish break;
194023c35297Sanish default:
194123c35297Sanish DEBUG0("Unknown register type\n");
194223c35297Sanish kmem_free(reg, length);
194323c35297Sanish (void) pcicfg_config_teardown(&handle);
194423c35297Sanish entry->error = PCICFG_FAILURE;
194523c35297Sanish return (DDI_WALK_TERMINATE);
194623c35297Sanish } /* switch */
194723c35297Sanish
194823c35297Sanish /*
194923c35297Sanish * Now that memory locations are assigned,
195023c35297Sanish * update the assigned address property.
195123c35297Sanish */
195226947304SEvan Yan if (pcicfg_update_assigned_prop(dip, ®[i])
195326947304SEvan Yan != PCICFG_SUCCESS) {
195423c35297Sanish kmem_free(reg, length);
195523c35297Sanish (void) pcicfg_config_teardown(&handle);
195623c35297Sanish entry->error = PCICFG_FAILURE;
195723c35297Sanish return (DDI_WALK_TERMINATE);
195823c35297Sanish }
195923c35297Sanish }
196023c35297Sanish }
196123c35297Sanish (void) pcicfg_device_on(handle);
196223c35297Sanish
196323c35297Sanish PCICFG_DUMP_DEVICE_CONFIG(handle);
196423c35297Sanish
196523c35297Sanish (void) pcicfg_config_teardown(&handle);
196623c35297Sanish kmem_free((caddr_t)reg, length);
196723c35297Sanish return (DDI_WALK_CONTINUE);
196823c35297Sanish }
196923c35297Sanish
197023c35297Sanish static int
pcicfg_device_assign(dev_info_t * dip)197123c35297Sanish pcicfg_device_assign(dev_info_t *dip)
197223c35297Sanish {
197323c35297Sanish ddi_acc_handle_t handle;
197423c35297Sanish pci_regspec_t *reg;
197523c35297Sanish int length;
197623c35297Sanish int rcount;
197723c35297Sanish int i;
197823c35297Sanish int offset;
197923c35297Sanish ndi_ra_request_t request;
198023c35297Sanish uint64_t answer;
198123c35297Sanish uint64_t alen;
198223c35297Sanish
198323c35297Sanish DEBUG1("%llx now under configuration\n", dip);
198423c35297Sanish
198523c35297Sanish /* request.ra_len = PCICFG_ROUND_UP(request.ra_len, PCICFG_IOGRAN); */
198623c35297Sanish if (pcicfg_ntbridge_child(dip) == DDI_SUCCESS) {
198723c35297Sanish
198823c35297Sanish return (pcicfg_ntbridge_program_child(dip));
198923c35297Sanish }
199023c35297Sanish /*
199123c35297Sanish * XXX Failure here should be noted
199223c35297Sanish */
199326947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg",
199426947304SEvan Yan (caddr_t)®, &length) != DDI_PROP_SUCCESS) {
199523c35297Sanish DEBUG0("Failed to read reg property\n");
199623c35297Sanish return (PCICFG_FAILURE);
199723c35297Sanish }
199823c35297Sanish
199923c35297Sanish if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
200023c35297Sanish DEBUG0("Failed to map config space!\n");
20011fb5b786Sprasad kmem_free(reg, length);
200223c35297Sanish return (PCICFG_FAILURE);
200323c35297Sanish }
200423c35297Sanish
200523c35297Sanish /*
200623c35297Sanish * A single device
200723c35297Sanish *
200823c35297Sanish * For each "reg" property with a length, allocate memory
200923c35297Sanish * and program the base registers.
201023c35297Sanish */
201123c35297Sanish
201223c35297Sanish /*
201323c35297Sanish * If there is an interrupt pin set program
201423c35297Sanish * interrupt line with default values.
201523c35297Sanish */
201623c35297Sanish if (pci_config_get8(handle, PCI_CONF_IPIN)) {
201723c35297Sanish pci_config_put8(handle, PCI_CONF_ILINE, 0xf);
201823c35297Sanish }
201923c35297Sanish
202023c35297Sanish bzero((caddr_t)&request, sizeof (ndi_ra_request_t));
202123c35297Sanish
202223c35297Sanish /*
202323c35297Sanish * Note: Both non-prefetchable and prefetchable memory space
202423c35297Sanish * allocations are made within 32bit space. Currently, BIOSs
202523c35297Sanish * allocate device memory for PCI devices within the 32bit space
202623c35297Sanish * so this will not be a problem.
202723c35297Sanish */
202823c35297Sanish request.ra_flags |= NDI_RA_ALIGN_SIZE | NDI_RA_ALLOC_BOUNDED;
202923c35297Sanish request.ra_boundbase = 0;
203023c35297Sanish request.ra_boundlen = PCICFG_4GIG_LIMIT;
203123c35297Sanish
203223c35297Sanish rcount = length / sizeof (pci_regspec_t);
203323c35297Sanish offset = PCI_CONF_BASE0;
203423c35297Sanish for (i = 0; i < rcount; i++) {
203523c35297Sanish char *mem_type;
203623c35297Sanish
203726947304SEvan Yan if ((reg[i].pci_size_low != 0)|| (reg[i].pci_size_hi != 0)) {
203823c35297Sanish
203923c35297Sanish offset = PCI_REG_REG_G(reg[i].pci_phys_hi);
204023c35297Sanish request.ra_len = reg[i].pci_size_low;
204123c35297Sanish
204223c35297Sanish switch (PCI_REG_ADDR_G(reg[i].pci_phys_hi)) {
204323c35297Sanish case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
204423c35297Sanish if (reg[i].pci_phys_hi & PCI_REG_PF_M) {
204523c35297Sanish mem_type = NDI_RA_TYPE_PCI_PREFETCH_MEM;
204623c35297Sanish } else {
204723c35297Sanish mem_type = NDI_RA_TYPE_MEM;
204823c35297Sanish }
204923c35297Sanish /* allocate memory space from the allocator */
205026947304SEvan Yan if (ndi_ra_alloc(ddi_get_parent(dip), &request,
205126947304SEvan Yan &answer, &alen, mem_type, NDI_RA_PASS)
205226947304SEvan Yan != NDI_SUCCESS) {
205323c35297Sanish DEBUG0("Failed to allocate 64b mem\n");
205423c35297Sanish kmem_free(reg, length);
205523c35297Sanish (void) pcicfg_config_teardown(&handle);
20565af4ae46Sjveta return (PCICFG_NORESRC);
205723c35297Sanish }
205823c35297Sanish DEBUG3("64 addr = [0x%x.0x%x] len [0x%x]\n",
205923c35297Sanish PCICFG_HIADDR(answer),
206026947304SEvan Yan PCICFG_LOADDR(answer), alen);
206123c35297Sanish /* program the low word */
206226947304SEvan Yan pci_config_put32(handle, offset,
206326947304SEvan Yan PCICFG_LOADDR(answer));
206423c35297Sanish /* program the high word */
206523c35297Sanish pci_config_put32(handle, offset + 4,
206623c35297Sanish PCICFG_HIADDR(answer));
206723c35297Sanish
206823c35297Sanish reg[i].pci_phys_hi |= PCI_REG_REL_M;
206923c35297Sanish reg[i].pci_phys_low = PCICFG_LOADDR(answer);
207023c35297Sanish reg[i].pci_phys_mid = PCICFG_HIADDR(answer);
207123c35297Sanish /*
207223c35297Sanish * currently support 32b address space
207323c35297Sanish * assignments only.
207423c35297Sanish */
207526947304SEvan Yan reg[i].pci_phys_hi ^=
207626947304SEvan Yan PCI_ADDR_MEM64 ^ PCI_ADDR_MEM32;
207723c35297Sanish
207823c35297Sanish offset += 8;
207923c35297Sanish break;
208023c35297Sanish
208123c35297Sanish case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
208223c35297Sanish if (reg[i].pci_phys_hi & PCI_REG_PF_M)
208323c35297Sanish mem_type = NDI_RA_TYPE_PCI_PREFETCH_MEM;
208423c35297Sanish else
208523c35297Sanish mem_type = NDI_RA_TYPE_MEM;
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 32b mem\n");
209123c35297Sanish kmem_free(reg, length);
209223c35297Sanish (void) pcicfg_config_teardown(&handle);
20935af4ae46Sjveta return (PCICFG_NORESRC);
209423c35297Sanish }
209523c35297Sanish DEBUG3("32 addr = [0x%x.0x%x] len [0x%x]\n",
209623c35297Sanish PCICFG_HIADDR(answer),
209723c35297Sanish PCICFG_LOADDR(answer),
209823c35297Sanish alen);
209923c35297Sanish /* program the low word */
210026947304SEvan Yan pci_config_put32(handle, offset,
210126947304SEvan Yan PCICFG_LOADDR(answer));
210223c35297Sanish
210323c35297Sanish reg[i].pci_phys_hi |= PCI_REG_REL_M;
210423c35297Sanish reg[i].pci_phys_low = PCICFG_LOADDR(answer);
210523c35297Sanish reg[i].pci_phys_mid = 0;
210623c35297Sanish
210723c35297Sanish offset += 4;
210823c35297Sanish break;
210923c35297Sanish case PCI_REG_ADDR_G(PCI_ADDR_IO):
2110b9abf428Slipeng sang - Sun Microsystems - Beijing China /*
2111b9abf428Slipeng sang - Sun Microsystems - Beijing China * Try to allocate I/O space. If it fails,
2112b9abf428Slipeng sang - Sun Microsystems - Beijing China * continue here instead of returning failure
2113b9abf428Slipeng sang - Sun Microsystems - Beijing China * so that the hotplug for drivers that don't
2114b9abf428Slipeng sang - Sun Microsystems - Beijing China * use I/O space can succeed, For drivers
2115b9abf428Slipeng sang - Sun Microsystems - Beijing China * that need to use I/O space, the hotplug
2116b9abf428Slipeng sang - Sun Microsystems - Beijing China * will still fail later during driver attach.
2117b9abf428Slipeng sang - Sun Microsystems - Beijing China */
211826947304SEvan Yan if (ndi_ra_alloc(ddi_get_parent(dip), &request,
211926947304SEvan Yan &answer, &alen, NDI_RA_TYPE_IO, NDI_RA_PASS)
212023c35297Sanish != NDI_SUCCESS) {
212123c35297Sanish DEBUG0("Failed to allocate I/O\n");
2122b9abf428Slipeng sang - Sun Microsystems - Beijing China continue;
212323c35297Sanish }
212423c35297Sanish DEBUG3("I/O addr = [0x%x.0x%x] len [0x%x]\n",
212523c35297Sanish PCICFG_HIADDR(answer),
212626947304SEvan Yan PCICFG_LOADDR(answer), alen);
212726947304SEvan Yan pci_config_put32(handle, offset,
212826947304SEvan Yan PCICFG_LOADDR(answer));
212923c35297Sanish
213023c35297Sanish reg[i].pci_phys_hi |= PCI_REG_REL_M;
213123c35297Sanish reg[i].pci_phys_low = PCICFG_LOADDR(answer);
213223c35297Sanish
213323c35297Sanish offset += 4;
213423c35297Sanish break;
213523c35297Sanish default:
213623c35297Sanish DEBUG0("Unknown register type\n");
213723c35297Sanish kmem_free(reg, length);
213823c35297Sanish (void) pcicfg_config_teardown(&handle);
213923c35297Sanish return (PCICFG_FAILURE);
214023c35297Sanish } /* switch */
214123c35297Sanish
214223c35297Sanish /*
214323c35297Sanish * Now that memory locations are assigned,
214423c35297Sanish * update the assigned address property.
214523c35297Sanish */
214623c35297Sanish
214726947304SEvan Yan if (pcicfg_update_assigned_prop(dip, ®[i])
214826947304SEvan Yan != PCICFG_SUCCESS) {
214923c35297Sanish kmem_free(reg, length);
215023c35297Sanish (void) pcicfg_config_teardown(&handle);
215123c35297Sanish return (PCICFG_FAILURE);
215223c35297Sanish }
215323c35297Sanish }
215423c35297Sanish }
215523c35297Sanish
215623c35297Sanish (void) pcicfg_device_on(handle);
215723c35297Sanish kmem_free(reg, length);
215823c35297Sanish
215923c35297Sanish PCICFG_DUMP_DEVICE_CONFIG(handle);
216023c35297Sanish
216123c35297Sanish (void) pcicfg_config_teardown(&handle);
216223c35297Sanish return (PCICFG_SUCCESS);
216323c35297Sanish }
216423c35297Sanish
216526947304SEvan Yan static int
pcicfg_device_assign_readonly(dev_info_t * dip)216626947304SEvan Yan pcicfg_device_assign_readonly(dev_info_t *dip)
216726947304SEvan Yan {
216826947304SEvan Yan ddi_acc_handle_t handle;
216926947304SEvan Yan pci_regspec_t *assigned;
217026947304SEvan Yan int length;
217126947304SEvan Yan int acount;
217226947304SEvan Yan int i;
217326947304SEvan Yan ndi_ra_request_t request;
217426947304SEvan Yan uint64_t answer;
217526947304SEvan Yan uint64_t alen;
217626947304SEvan Yan
217726947304SEvan Yan DEBUG1("%llx now under configuration\n", dip);
217826947304SEvan Yan
217926947304SEvan Yan /*
218026947304SEvan Yan * we don't support ntbridges for readonly probe.
218126947304SEvan Yan */
218226947304SEvan Yan if (pcicfg_ntbridge_child(dip) == DDI_SUCCESS) {
218326947304SEvan Yan return (PCICFG_FAILURE);
218426947304SEvan Yan }
218526947304SEvan Yan
218626947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
218726947304SEvan Yan DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned,
218826947304SEvan Yan &length) != DDI_PROP_SUCCESS) {
218926947304SEvan Yan DEBUG0("Failed to read assigned-addresses property\n");
219026947304SEvan Yan return (PCICFG_FAILURE);
219126947304SEvan Yan }
219226947304SEvan Yan
219326947304SEvan Yan if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
219426947304SEvan Yan DEBUG0("Failed to map config space!\n");
219526947304SEvan Yan kmem_free(assigned, length);
219626947304SEvan Yan return (PCICFG_FAILURE);
219726947304SEvan Yan }
219826947304SEvan Yan
219926947304SEvan Yan /*
220026947304SEvan Yan * If there is an interrupt pin set program
220126947304SEvan Yan * interrupt line with default values.
220226947304SEvan Yan */
220326947304SEvan Yan if (pci_config_get8(handle, PCI_CONF_IPIN)) {
220426947304SEvan Yan pci_config_put8(handle, PCI_CONF_ILINE, 0xf);
220526947304SEvan Yan }
220626947304SEvan Yan /*
220726947304SEvan Yan * Note: Both non-prefetchable and prefetchable memory space
220826947304SEvan Yan * allocations are made within 32bit space. Currently, BIOSs
220926947304SEvan Yan * allocate device memory for PCI devices within the 32bit space
221026947304SEvan Yan * so this will not be a problem.
221126947304SEvan Yan */
221226947304SEvan Yan bzero((caddr_t)&request, sizeof (ndi_ra_request_t));
221326947304SEvan Yan
221426947304SEvan Yan request.ra_flags = NDI_RA_ALLOC_SPECIFIED; /* specified addr */
221526947304SEvan Yan request.ra_boundbase = 0;
221626947304SEvan Yan request.ra_boundlen = PCICFG_4GIG_LIMIT;
221726947304SEvan Yan
221826947304SEvan Yan acount = length / sizeof (pci_regspec_t);
221926947304SEvan Yan for (i = 0; i < acount; i++) {
222026947304SEvan Yan char *mem_type;
222126947304SEvan Yan
222226947304SEvan Yan if ((assigned[i].pci_size_low != 0)||
222326947304SEvan Yan (assigned[i].pci_size_hi != 0)) {
222426947304SEvan Yan
222526947304SEvan Yan request.ra_len = assigned[i].pci_size_low;
222626947304SEvan Yan
222726947304SEvan Yan switch (PCI_REG_ADDR_G(assigned[i].pci_phys_hi)) {
222826947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
222926947304SEvan Yan request.ra_addr = (uint64_t)PCICFG_LADDR(
223026947304SEvan Yan assigned[i].pci_phys_low,
223126947304SEvan Yan assigned[i].pci_phys_mid);
223226947304SEvan Yan
223326947304SEvan Yan if (assigned[i].pci_phys_hi & PCI_REG_PF_M) {
223426947304SEvan Yan mem_type = NDI_RA_TYPE_PCI_PREFETCH_MEM;
223526947304SEvan Yan } else {
223626947304SEvan Yan mem_type = NDI_RA_TYPE_MEM;
223726947304SEvan Yan }
223826947304SEvan Yan /* allocate memory space from the allocator */
223926947304SEvan Yan if (ndi_ra_alloc(ddi_get_parent(dip), &request,
224026947304SEvan Yan &answer, &alen, mem_type, NDI_RA_PASS)
224126947304SEvan Yan != NDI_SUCCESS) {
224226947304SEvan Yan DEBUG0("Failed to allocate 64b mem\n");
224326947304SEvan Yan kmem_free(assigned, length);
224426947304SEvan Yan return (PCICFG_NORESRC);
224526947304SEvan Yan }
224626947304SEvan Yan
224726947304SEvan Yan break;
224826947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
224926947304SEvan Yan request.ra_addr = (uint64_t)
225026947304SEvan Yan assigned[i].pci_phys_low;
225126947304SEvan Yan
225226947304SEvan Yan if (assigned[i].pci_phys_hi & PCI_REG_PF_M)
225326947304SEvan Yan mem_type = NDI_RA_TYPE_PCI_PREFETCH_MEM;
225426947304SEvan Yan else
225526947304SEvan Yan mem_type = NDI_RA_TYPE_MEM;
225626947304SEvan Yan /* allocate memory space from the allocator */
225726947304SEvan Yan if (ndi_ra_alloc(ddi_get_parent(dip), &request,
225826947304SEvan Yan &answer, &alen, mem_type, NDI_RA_PASS)
225926947304SEvan Yan != NDI_SUCCESS) {
226026947304SEvan Yan DEBUG0("Failed to allocate 32b mem\n");
226126947304SEvan Yan kmem_free(assigned, length);
226226947304SEvan Yan return (PCICFG_NORESRC);
226326947304SEvan Yan }
226426947304SEvan Yan
226526947304SEvan Yan break;
226626947304SEvan Yan case PCI_REG_ADDR_G(PCI_ADDR_IO):
226726947304SEvan Yan request.ra_addr = (uint64_t)
226826947304SEvan Yan assigned[i].pci_phys_low;
226926947304SEvan Yan
227026947304SEvan Yan /* allocate I/O space from the allocator */
227126947304SEvan Yan if (ndi_ra_alloc(ddi_get_parent(dip), &request,
227226947304SEvan Yan &answer, &alen, NDI_RA_TYPE_IO, NDI_RA_PASS)
227326947304SEvan Yan != NDI_SUCCESS) {
227426947304SEvan Yan DEBUG0("Failed to allocate I/O\n");
227526947304SEvan Yan kmem_free(assigned, length);
227626947304SEvan Yan return (PCICFG_NORESRC);
227726947304SEvan Yan }
227826947304SEvan Yan
227926947304SEvan Yan break;
228026947304SEvan Yan default:
228126947304SEvan Yan DEBUG0("Unknown register type\n");
228226947304SEvan Yan kmem_free(assigned, length);
228326947304SEvan Yan return (PCICFG_FAILURE);
228426947304SEvan Yan } /* switch */
228526947304SEvan Yan }
228626947304SEvan Yan }
228726947304SEvan Yan
228826947304SEvan Yan (void) pcicfg_device_on(handle);
228926947304SEvan Yan kmem_free(assigned, length);
229026947304SEvan Yan
229126947304SEvan Yan PCICFG_DUMP_DEVICE_CONFIG(handle);
229226947304SEvan Yan
229326947304SEvan Yan (void) pcicfg_config_teardown(&handle);
229426947304SEvan Yan return (PCICFG_SUCCESS);
229526947304SEvan Yan }
229626947304SEvan Yan
229723c35297Sanish #ifdef DEBUG
229823c35297Sanish /*
229923c35297Sanish * This function is useful in debug mode, where we can measure how
230023c35297Sanish * much memory was wasted/unallocated in bridge device's domain.
230123c35297Sanish */
230223c35297Sanish static uint64_t
pcicfg_unused_space(hole_t * hole,uint32_t * hole_count)230323c35297Sanish pcicfg_unused_space(hole_t *hole, uint32_t *hole_count)
230423c35297Sanish {
230523c35297Sanish uint64_t len = 0;
230623c35297Sanish uint32_t count = 0;
230723c35297Sanish
230823c35297Sanish do {
230923c35297Sanish len += hole->len;
231023c35297Sanish hole = hole->next;
231123c35297Sanish count++;
231223c35297Sanish } while (hole);
231323c35297Sanish *hole_count = count;
231423c35297Sanish return (len);
231523c35297Sanish }
231623c35297Sanish #endif
231723c35297Sanish
231823c35297Sanish /*
231923c35297Sanish * This function frees data structures that hold the hole information
232023c35297Sanish * which are allocated in pcicfg_alloc_hole(). This is not freeing
232123c35297Sanish * any memory allocated through NDI calls.
232223c35297Sanish */
232323c35297Sanish static void
pcicfg_free_hole(hole_t * addr_hole)232423c35297Sanish pcicfg_free_hole(hole_t *addr_hole)
232523c35297Sanish {
232623c35297Sanish hole_t *nhole, *hole = addr_hole->next;
232723c35297Sanish
232823c35297Sanish while (hole) {
232923c35297Sanish nhole = hole->next;
233023c35297Sanish kmem_free(hole, sizeof (hole_t));
233123c35297Sanish hole = nhole;
233223c35297Sanish }
233323c35297Sanish }
233423c35297Sanish
233523c35297Sanish static uint64_t
pcicfg_alloc_hole(hole_t * addr_hole,uint64_t * alast,uint32_t length)233623c35297Sanish pcicfg_alloc_hole(hole_t *addr_hole, uint64_t *alast, uint32_t length)
233723c35297Sanish {
233823c35297Sanish uint64_t actual_hole_start, ostart, olen;
233923c35297Sanish hole_t *hole = addr_hole, *thole, *nhole;
234023c35297Sanish
234123c35297Sanish do {
234223c35297Sanish actual_hole_start = PCICFG_ROUND_UP(hole->start, length);
234323c35297Sanish if (((actual_hole_start - hole->start) + length) <= hole->len) {
234423c35297Sanish DEBUG3("hole found. start %llx, len %llx, req=0x%x\n",
234523c35297Sanish hole->start, hole->len, length);
234623c35297Sanish ostart = hole->start;
234723c35297Sanish olen = hole->len;
234823c35297Sanish /* current hole parameters adjust */
234923c35297Sanish if ((actual_hole_start - hole->start) == 0) {
235023c35297Sanish hole->start += length;
235123c35297Sanish hole->len -= length;
235223c35297Sanish if (hole->start > *alast)
235323c35297Sanish *alast = hole->start;
235423c35297Sanish } else {
235523c35297Sanish hole->len = actual_hole_start - hole->start;
235623c35297Sanish nhole = (hole_t *)kmem_zalloc(sizeof (hole_t),
235723c35297Sanish KM_SLEEP);
235823c35297Sanish nhole->start = actual_hole_start + length;
235923c35297Sanish nhole->len = (ostart + olen) - nhole->start;
236023c35297Sanish nhole->next = NULL;
236123c35297Sanish thole = hole->next;
236223c35297Sanish hole->next = nhole;
236323c35297Sanish nhole->next = thole;
236423c35297Sanish if (nhole->start > *alast)
236523c35297Sanish *alast = nhole->start;
236623c35297Sanish DEBUG2("put new hole to %llx, %llx\n",
236723c35297Sanish nhole->start, nhole->len);
236823c35297Sanish }
236923c35297Sanish DEBUG2("adjust current hole to %llx, %llx\n",
237023c35297Sanish hole->start, hole->len);
237123c35297Sanish break;
237223c35297Sanish }
237323c35297Sanish actual_hole_start = 0;
237423c35297Sanish hole = hole->next;
237523c35297Sanish } while (hole);
237623c35297Sanish
237723c35297Sanish DEBUG1("return hole at %llx\n", actual_hole_start);
237823c35297Sanish return (actual_hole_start);
237923c35297Sanish }
238023c35297Sanish
238123c35297Sanish static void
pcicfg_get_mem(pcicfg_phdl_t * entry,uint32_t length,uint64_t * ans)238226947304SEvan Yan pcicfg_get_mem(pcicfg_phdl_t *entry, uint32_t length, uint64_t *ans)
238323c35297Sanish {
238423c35297Sanish uint64_t new_mem;
238523c35297Sanish
238623c35297Sanish /* See if there is a hole, that can hold this request. */
238723c35297Sanish new_mem = pcicfg_alloc_hole(&entry->mem_hole, &entry->memory_last,
238823c35297Sanish length);
238923c35297Sanish if (new_mem) { /* if non-zero, found a hole. */
239023c35297Sanish if (ans != NULL)
239123c35297Sanish *ans = new_mem;
239223c35297Sanish } else
239323c35297Sanish cmn_err(CE_WARN, "No %u bytes memory window for %s\n",
239423c35297Sanish length, ddi_get_name(entry->dip));
239523c35297Sanish }
239623c35297Sanish
239723c35297Sanish static void
pcicfg_get_io(pcicfg_phdl_t * entry,uint32_t length,uint32_t * ans)239823c35297Sanish pcicfg_get_io(pcicfg_phdl_t *entry,
239923c35297Sanish uint32_t length, uint32_t *ans)
240023c35297Sanish {
240123c35297Sanish uint32_t new_io;
240223c35297Sanish uint64_t io_last;
240323c35297Sanish
240423c35297Sanish /*
240523c35297Sanish * See if there is a hole, that can hold this request.
240623c35297Sanish * Pass 64 bit parameters and then truncate to 32 bit.
240723c35297Sanish */
240823c35297Sanish io_last = entry->io_last;
240923c35297Sanish new_io = (uint32_t)pcicfg_alloc_hole(&entry->io_hole, &io_last, length);
241023c35297Sanish if (new_io) { /* if non-zero, found a hole. */
241123c35297Sanish entry->io_last = (uint32_t)io_last;
241223c35297Sanish if (ans != NULL)
241323c35297Sanish *ans = new_io;
241423c35297Sanish } else
241523c35297Sanish cmn_err(CE_WARN, "No %u bytes IO space window for %s\n",
241623c35297Sanish length, ddi_get_name(entry->dip));
241723c35297Sanish }
241823c35297Sanish
241923c35297Sanish static void
pcicfg_get_pf_mem(pcicfg_phdl_t * entry,uint32_t length,uint64_t * ans)242026947304SEvan Yan pcicfg_get_pf_mem(pcicfg_phdl_t *entry, uint32_t length, uint64_t *ans)
242123c35297Sanish {
242223c35297Sanish uint64_t new_mem;
242323c35297Sanish
242423c35297Sanish /* See if there is a hole, that can hold this request. */
242523c35297Sanish new_mem = pcicfg_alloc_hole(&entry->pf_mem_hole, &entry->pf_memory_last,
242623c35297Sanish length);
242723c35297Sanish if (new_mem) { /* if non-zero, found a hole. */
242823c35297Sanish if (ans != NULL)
242923c35297Sanish *ans = new_mem;
243023c35297Sanish } else
243123c35297Sanish cmn_err(CE_WARN, "No %u bytes PF memory window for %s\n",
243223c35297Sanish length, ddi_get_name(entry->dip));
243323c35297Sanish }
243423c35297Sanish
243523c35297Sanish static int
pcicfg_sum_resources(dev_info_t * dip,void * hdl)243623c35297Sanish pcicfg_sum_resources(dev_info_t *dip, void *hdl)
243723c35297Sanish {
243823c35297Sanish pcicfg_phdl_t *entry = (pcicfg_phdl_t *)hdl;
243923c35297Sanish pci_regspec_t *pci_rp;
244023c35297Sanish int length;
244123c35297Sanish int rcount;
244223c35297Sanish int i;
244323c35297Sanish ndi_ra_request_t *pf_mem_request;
244423c35297Sanish ndi_ra_request_t *mem_request;
244523c35297Sanish ndi_ra_request_t *io_request;
244623c35297Sanish uint8_t header_type;
244723c35297Sanish ddi_acc_handle_t handle;
244823c35297Sanish
244923c35297Sanish entry->error = PCICFG_SUCCESS;
245023c35297Sanish
245123c35297Sanish pf_mem_request = &entry->pf_mem_req;
245223c35297Sanish mem_request = &entry->mem_req;
245323c35297Sanish io_request = &entry->io_req;
245423c35297Sanish
245523c35297Sanish if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
245623c35297Sanish DEBUG0("Failed to map config space!\n");
245723c35297Sanish entry->error = PCICFG_FAILURE;
245823c35297Sanish return (DDI_WALK_TERMINATE);
245923c35297Sanish }
246023c35297Sanish
246123c35297Sanish header_type = pci_config_get8(handle, PCI_CONF_HEADER);
246223c35297Sanish
246323c35297Sanish /*
246423c35297Sanish * If its a bridge - just record the highest bus seen
246523c35297Sanish */
246623c35297Sanish if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
246723c35297Sanish
246823c35297Sanish if (entry->highest_bus < pci_config_get8(handle,
246923c35297Sanish PCI_BCNF_SECBUS)) {
247023c35297Sanish entry->highest_bus =
247123c35297Sanish pci_config_get8(handle, PCI_BCNF_SECBUS);
247223c35297Sanish }
247323c35297Sanish (void) pcicfg_config_teardown(&handle);
247423c35297Sanish entry->error = PCICFG_FAILURE;
247523c35297Sanish return (DDI_WALK_CONTINUE);
247623c35297Sanish } else {
247726947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
247826947304SEvan Yan "reg", (caddr_t)&pci_rp, &length) != DDI_PROP_SUCCESS) {
247923c35297Sanish /*
248023c35297Sanish * If one node in (the subtree of nodes)
248123c35297Sanish * doesn't have a "reg" property fail the
248223c35297Sanish * allocation.
248323c35297Sanish */
248423c35297Sanish entry->memory_len = 0;
248523c35297Sanish entry->io_len = 0;
248623c35297Sanish entry->pf_memory_len = 0;
248723c35297Sanish entry->error = PCICFG_FAILURE;
24881fb5b786Sprasad (void) pcicfg_config_teardown(&handle);
248923c35297Sanish return (DDI_WALK_TERMINATE);
249023c35297Sanish }
249123c35297Sanish /*
249223c35297Sanish * For each "reg" property with a length, add that to the
249323c35297Sanish * total memory (or I/O) to allocate.
249423c35297Sanish */
249523c35297Sanish rcount = length / sizeof (pci_regspec_t);
249623c35297Sanish
249723c35297Sanish for (i = 0; i < rcount; i++) {
249823c35297Sanish
249923c35297Sanish switch (PCI_REG_ADDR_G(pci_rp[i].pci_phys_hi)) {
250023c35297Sanish
250123c35297Sanish case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
250223c35297Sanish if (pci_rp[i].pci_phys_hi & PCI_REG_PF_M) {
250323c35297Sanish pf_mem_request->ra_len =
250423c35297Sanish pci_rp[i].pci_size_low +
250526947304SEvan Yan PCICFG_ROUND_UP(
250626947304SEvan Yan pf_mem_request->ra_len,
250723c35297Sanish pci_rp[i].pci_size_low);
250823c35297Sanish DEBUG1("ADDING 32 --->0x%x\n",
250923c35297Sanish pci_rp[i].pci_size_low);
251023c35297Sanish } else {
251123c35297Sanish mem_request->ra_len =
251223c35297Sanish pci_rp[i].pci_size_low +
251323c35297Sanish PCICFG_ROUND_UP(mem_request->ra_len,
251423c35297Sanish pci_rp[i].pci_size_low);
251523c35297Sanish DEBUG1("ADDING 32 --->0x%x\n",
251623c35297Sanish pci_rp[i].pci_size_low);
251723c35297Sanish }
251823c35297Sanish
251923c35297Sanish break;
252023c35297Sanish case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
252123c35297Sanish if (pci_rp[i].pci_phys_hi & PCI_REG_PF_M) {
252223c35297Sanish pf_mem_request->ra_len =
252323c35297Sanish pci_rp[i].pci_size_low +
252426947304SEvan Yan PCICFG_ROUND_UP(
252526947304SEvan Yan pf_mem_request->ra_len,
252623c35297Sanish pci_rp[i].pci_size_low);
252723c35297Sanish DEBUG1("ADDING 64 --->0x%x\n",
252823c35297Sanish pci_rp[i].pci_size_low);
252923c35297Sanish } else {
253023c35297Sanish mem_request->ra_len =
253123c35297Sanish pci_rp[i].pci_size_low +
253223c35297Sanish PCICFG_ROUND_UP(mem_request->ra_len,
253323c35297Sanish pci_rp[i].pci_size_low);
253423c35297Sanish DEBUG1("ADDING 64 --->0x%x\n",
253523c35297Sanish pci_rp[i].pci_size_low);
253623c35297Sanish }
253723c35297Sanish
253823c35297Sanish break;
253923c35297Sanish case PCI_REG_ADDR_G(PCI_ADDR_IO):
254023c35297Sanish io_request->ra_len =
254123c35297Sanish pci_rp[i].pci_size_low +
254223c35297Sanish PCICFG_ROUND_UP(io_request->ra_len,
254323c35297Sanish pci_rp[i].pci_size_low);
254423c35297Sanish DEBUG1("ADDING I/O --->0x%x\n",
254523c35297Sanish pci_rp[i].pci_size_low);
254623c35297Sanish break;
254723c35297Sanish default:
254823c35297Sanish /* Config space register - not included */
254923c35297Sanish break;
255023c35297Sanish }
255123c35297Sanish }
255223c35297Sanish
255323c35297Sanish /*
255423c35297Sanish * free the memory allocated by ddi_getlongprop
255523c35297Sanish */
255623c35297Sanish kmem_free(pci_rp, length);
255723c35297Sanish
255823c35297Sanish /*
255923c35297Sanish * continue the walk to the next sibling to sum memory
256023c35297Sanish */
256123c35297Sanish
256223c35297Sanish (void) pcicfg_config_teardown(&handle);
256323c35297Sanish
256423c35297Sanish return (DDI_WALK_CONTINUE);
256523c35297Sanish }
256623c35297Sanish }
256723c35297Sanish
256823c35297Sanish static int
pcicfg_free_bridge_resources(dev_info_t * dip)256923c35297Sanish pcicfg_free_bridge_resources(dev_info_t *dip)
257023c35297Sanish {
257123c35297Sanish ppb_ranges_t *ranges;
257223c35297Sanish uint_t *bus;
257323c35297Sanish int k;
25741fb5b786Sprasad int length = 0;
257523c35297Sanish int i;
257623c35297Sanish
257723c35297Sanish
257826947304SEvan Yan if ((i = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
257926947304SEvan Yan "ranges", (caddr_t)&ranges, &length)) != DDI_PROP_SUCCESS) {
258023c35297Sanish DEBUG0("Failed to read ranges property\n");
258123c35297Sanish if (ddi_get_child(dip)) {
258223c35297Sanish cmn_err(CE_WARN, "No ranges property found for %s",
258323c35297Sanish ddi_get_name(dip));
258423c35297Sanish /*
258523c35297Sanish * strictly speaking, we can check for children with
258623c35297Sanish * assigned-addresses but for now it is better to
258723c35297Sanish * be conservative and assume that if there are child
258823c35297Sanish * nodes, then they do consume PCI memory or IO
258923c35297Sanish * resources, Hence return failure.
259023c35297Sanish */
259123c35297Sanish return (PCICFG_FAILURE);
259223c35297Sanish }
259323c35297Sanish length = 0;
259423c35297Sanish }
259523c35297Sanish
259623c35297Sanish for (i = 0; i < length / sizeof (ppb_ranges_t); i++) {
259723c35297Sanish char *mem_type;
259823c35297Sanish
259926947304SEvan Yan if (ranges[i].size_low != 0 || ranges[i].size_high != 0) {
260023c35297Sanish switch (ranges[i].parent_high & PCI_REG_ADDR_M) {
260123c35297Sanish case PCI_ADDR_IO:
260226947304SEvan Yan DEBUG2("Free I/O base/length = "
260326947304SEvan Yan "[0x%x]/[0x%x]\n", ranges[i].child_low,
260423c35297Sanish ranges[i].size_low);
260523c35297Sanish if (ndi_ra_free(ddi_get_parent(dip),
260623c35297Sanish (uint64_t)ranges[i].child_low,
260723c35297Sanish (uint64_t)ranges[i].size_low,
260823c35297Sanish NDI_RA_TYPE_IO, NDI_RA_PASS)
260923c35297Sanish != NDI_SUCCESS) {
261023c35297Sanish DEBUG0("Trouble freeing "
261123c35297Sanish "PCI i/o space\n");
261223c35297Sanish kmem_free(ranges, length);
261323c35297Sanish return (PCICFG_FAILURE);
261423c35297Sanish }
261523c35297Sanish break;
261623c35297Sanish case PCI_ADDR_MEM32:
261723c35297Sanish case PCI_ADDR_MEM64:
261823c35297Sanish if (ranges[i].parent_high & PCI_REG_PF_M) {
261926947304SEvan Yan DEBUG3("Free PF Memory base/length = "
262026947304SEvan Yan "[0x%x.0x%x]/[0x%x]\n",
262123c35297Sanish ranges[i].child_mid,
262223c35297Sanish ranges[i].child_low,
262326947304SEvan Yan ranges[i].size_low);
262423c35297Sanish mem_type = NDI_RA_TYPE_PCI_PREFETCH_MEM;
262523c35297Sanish } else {
262623c35297Sanish DEBUG3("Free Memory base/length"
262723c35297Sanish " = [0x%x.0x%x]/[0x%x]\n",
262823c35297Sanish ranges[i].child_mid,
262923c35297Sanish ranges[i].child_low,
263023c35297Sanish ranges[i].size_low)
263123c35297Sanish mem_type = NDI_RA_TYPE_MEM;
263223c35297Sanish }
263323c35297Sanish if (ndi_ra_free(ddi_get_parent(dip),
263426947304SEvan Yan PCICFG_LADDR(ranges[i].child_low,
263523c35297Sanish ranges[i].child_mid),
263623c35297Sanish (uint64_t)ranges[i].size_low,
263726947304SEvan Yan mem_type, NDI_RA_PASS) != NDI_SUCCESS) {
263823c35297Sanish DEBUG0("Trouble freeing "
263923c35297Sanish "PCI memory space\n");
264023c35297Sanish kmem_free(ranges, length);
264123c35297Sanish return (PCICFG_FAILURE);
264223c35297Sanish }
264323c35297Sanish break;
264423c35297Sanish default:
264523c35297Sanish DEBUG0("Unknown memory space\n");
264623c35297Sanish break;
264723c35297Sanish }
264823c35297Sanish }
264923c35297Sanish }
265023c35297Sanish
265123c35297Sanish if (length)
265223c35297Sanish kmem_free(ranges, length);
265323c35297Sanish
265426947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
265526947304SEvan Yan "bus-range", (caddr_t)&bus, &k) != DDI_PROP_SUCCESS) {
265623c35297Sanish DEBUG0("Failed to read bus-range property\n");
265723c35297Sanish return (PCICFG_FAILURE);
265823c35297Sanish }
265923c35297Sanish
266023c35297Sanish DEBUG2("Need to free bus [%d] range [%d]\n",
266123c35297Sanish bus[0], bus[1] - bus[0] + 1);
266223c35297Sanish
266326947304SEvan Yan if (ndi_ra_free(ddi_get_parent(dip), (uint64_t)bus[0],
266426947304SEvan Yan (uint64_t)(bus[1] - bus[0] + 1), NDI_RA_TYPE_PCI_BUSNUM,
266526947304SEvan Yan NDI_RA_PASS) != NDI_SUCCESS) {
266623c35297Sanish DEBUG0("Failed to free a bus number\n");
26671fb5b786Sprasad kmem_free(bus, k);
266823c35297Sanish return (PCICFG_FAILURE);
266923c35297Sanish }
26701fb5b786Sprasad
26711fb5b786Sprasad kmem_free(bus, k);
267223c35297Sanish return (PCICFG_SUCCESS);
267323c35297Sanish }
267423c35297Sanish
267523c35297Sanish static int
pcicfg_free_device_resources(dev_info_t * dip)267623c35297Sanish pcicfg_free_device_resources(dev_info_t *dip)
267723c35297Sanish {
267823c35297Sanish pci_regspec_t *assigned;
267923c35297Sanish
268023c35297Sanish int length;
268123c35297Sanish int acount;
268223c35297Sanish int i;
268323c35297Sanish
268426947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
268526947304SEvan Yan "assigned-addresses", (caddr_t)&assigned, &length)
268626947304SEvan Yan != DDI_PROP_SUCCESS) {
268723c35297Sanish DEBUG0("Failed to read assigned-addresses property\n");
268823c35297Sanish return (PCICFG_FAILURE);
268923c35297Sanish }
269023c35297Sanish
269123c35297Sanish /*
269223c35297Sanish * For each "assigned-addresses" property entry with a length,
269323c35297Sanish * call the memory allocation routines to return the
269423c35297Sanish * resource.
269523c35297Sanish */
269623c35297Sanish acount = length / sizeof (pci_regspec_t);
269723c35297Sanish for (i = 0; i < acount; i++) {
269823c35297Sanish char *mem_type;
269923c35297Sanish
270023c35297Sanish /*
270123c35297Sanish * Free the resource if the size of it is not zero.
270223c35297Sanish */
270323c35297Sanish if ((assigned[i].pci_size_low != 0)||
270423c35297Sanish (assigned[i].pci_size_hi != 0)) {
270523c35297Sanish switch (PCI_REG_ADDR_G(assigned[i].pci_phys_hi)) {
270623c35297Sanish case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
270723c35297Sanish /*
270823c35297Sanish * Check the assigned address for zero.
270923c35297Sanish * (Workaround for Devconf (x86) bug to
271023c35297Sanish * skip bogus entry for ROM base address
271123c35297Sanish * register. If the assigned address is
271223c35297Sanish * zero then ignore the entry
271323c35297Sanish * (see bugid 4281306)).
271423c35297Sanish */
271523c35297Sanish if (assigned[i].pci_phys_low == 0)
271623c35297Sanish break; /* ignore the entry */
271723c35297Sanish
271823c35297Sanish if (assigned[i].pci_phys_hi & PCI_REG_PF_M)
271923c35297Sanish mem_type = NDI_RA_TYPE_PCI_PREFETCH_MEM;
272023c35297Sanish else
272123c35297Sanish mem_type = NDI_RA_TYPE_MEM;
272223c35297Sanish
272323c35297Sanish if (ndi_ra_free(ddi_get_parent(dip),
272423c35297Sanish (uint64_t)assigned[i].pci_phys_low,
272523c35297Sanish (uint64_t)assigned[i].pci_size_low,
272623c35297Sanish mem_type, NDI_RA_PASS) != NDI_SUCCESS) {
272723c35297Sanish DEBUG0("Trouble freeing "
272823c35297Sanish "PCI memory space\n");
27291fb5b786Sprasad kmem_free(assigned, length);
273023c35297Sanish return (PCICFG_FAILURE);
273123c35297Sanish }
273223c35297Sanish
273323c35297Sanish DEBUG4("Returned 0x%x of 32 bit %s space"
273423c35297Sanish " @ 0x%x from register 0x%x\n",
273526947304SEvan Yan assigned[i].pci_size_low, mem_type,
273623c35297Sanish assigned[i].pci_phys_low,
273723c35297Sanish PCI_REG_REG_G(assigned[i].pci_phys_hi));
273823c35297Sanish
273923c35297Sanish break;
274023c35297Sanish case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
274123c35297Sanish if (assigned[i].pci_phys_hi & PCI_REG_PF_M)
274223c35297Sanish mem_type = NDI_RA_TYPE_PCI_PREFETCH_MEM;
274323c35297Sanish else
274423c35297Sanish mem_type = NDI_RA_TYPE_MEM;
274523c35297Sanish
274623c35297Sanish if (ndi_ra_free(ddi_get_parent(dip),
274723c35297Sanish PCICFG_LADDR(assigned[i].pci_phys_low,
274823c35297Sanish assigned[i].pci_phys_mid),
274923c35297Sanish (uint64_t)assigned[i].pci_size_low,
275023c35297Sanish mem_type, NDI_RA_PASS) != NDI_SUCCESS) {
275123c35297Sanish DEBUG0("Trouble freeing "
275223c35297Sanish "PCI memory space\n");
27531fb5b786Sprasad kmem_free(assigned, length);
275423c35297Sanish return (PCICFG_FAILURE);
275523c35297Sanish }
275623c35297Sanish
275723c35297Sanish DEBUG5("Returned 0x%x of 64 bit %s space"
275823c35297Sanish " @ 0x%x.0x%x from register 0x%x\n",
275923c35297Sanish assigned[i].pci_size_low,
276026947304SEvan Yan mem_type, assigned[i].pci_phys_mid,
276123c35297Sanish assigned[i].pci_phys_low,
276223c35297Sanish PCI_REG_REG_G(assigned[i].pci_phys_hi));
276323c35297Sanish
276423c35297Sanish break;
276523c35297Sanish case PCI_REG_ADDR_G(PCI_ADDR_IO):
276623c35297Sanish if (ndi_ra_free(ddi_get_parent(dip),
276723c35297Sanish (uint64_t)assigned[i].pci_phys_low,
276823c35297Sanish (uint64_t)assigned[i].pci_size_low,
27691fb5b786Sprasad NDI_RA_TYPE_IO, NDI_RA_PASS) !=
27701fb5b786Sprasad NDI_SUCCESS) {
277123c35297Sanish DEBUG0("Trouble freeing "
277223c35297Sanish "PCI IO space\n");
27731fb5b786Sprasad kmem_free(assigned, length);
277423c35297Sanish return (PCICFG_FAILURE);
277523c35297Sanish }
277626947304SEvan Yan DEBUG3("Returned 0x%x of IO space @ 0x%x from "
277726947304SEvan Yan "register 0x%x\n", assigned[i].pci_size_low,
277823c35297Sanish assigned[i].pci_phys_low,
277923c35297Sanish PCI_REG_REG_G(assigned[i].pci_phys_hi));
278023c35297Sanish break;
278123c35297Sanish default:
278223c35297Sanish DEBUG0("Unknown register type\n");
278323c35297Sanish kmem_free(assigned, length);
278423c35297Sanish return (PCICFG_FAILURE);
278523c35297Sanish } /* switch */
278623c35297Sanish }
278723c35297Sanish }
278823c35297Sanish kmem_free(assigned, length);
278923c35297Sanish return (PCICFG_SUCCESS);
279023c35297Sanish }
279123c35297Sanish
279223c35297Sanish static int
pcicfg_free_resources(dev_info_t * dip,pcicfg_flags_t flags)279326947304SEvan Yan pcicfg_free_resources(dev_info_t *dip, pcicfg_flags_t flags)
279423c35297Sanish {
279523c35297Sanish ddi_acc_handle_t handle;
279623c35297Sanish uint8_t header_type;
279723c35297Sanish
279823c35297Sanish if (pci_config_setup(dip, &handle) != DDI_SUCCESS) {
279923c35297Sanish DEBUG0("Failed to map config space!\n");
280023c35297Sanish return (PCICFG_FAILURE);
280123c35297Sanish }
280223c35297Sanish
280323c35297Sanish header_type = pci_config_get8(handle, PCI_CONF_HEADER);
280423c35297Sanish
280523c35297Sanish (void) pci_config_teardown(&handle);
280623c35297Sanish
280723c35297Sanish /*
280823c35297Sanish * A different algorithm is used for bridges and leaf devices.
280923c35297Sanish */
281023c35297Sanish if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
281126947304SEvan Yan /*
281226947304SEvan Yan * We only support readonly probing for leaf devices.
281326947304SEvan Yan */
281426947304SEvan Yan if (flags & PCICFG_FLAG_READ_ONLY)
281526947304SEvan Yan return (PCICFG_FAILURE);
281626947304SEvan Yan
281723c35297Sanish if (pcicfg_free_bridge_resources(dip) != PCICFG_SUCCESS) {
281823c35297Sanish DEBUG0("Failed freeing up bridge resources\n");
281923c35297Sanish return (PCICFG_FAILURE);
282023c35297Sanish }
282123c35297Sanish } else {
282223c35297Sanish if (pcicfg_free_device_resources(dip) != PCICFG_SUCCESS) {
282323c35297Sanish DEBUG0("Failed freeing up device resources\n");
282423c35297Sanish return (PCICFG_FAILURE);
282523c35297Sanish }
282623c35297Sanish }
282723c35297Sanish
282823c35297Sanish return (PCICFG_SUCCESS);
282923c35297Sanish }
283023c35297Sanish
283123c35297Sanish #ifndef _DONT_USE_1275_GENERIC_NAMES
283223c35297Sanish static char *
pcicfg_get_class_name(uint32_t classcode)283323c35297Sanish pcicfg_get_class_name(uint32_t classcode)
283423c35297Sanish {
283523c35297Sanish struct pcicfg_name_entry *ptr;
283623c35297Sanish
283723c35297Sanish for (ptr = &pcicfg_class_lookup[0]; ptr->name != NULL; ptr++) {
283823c35297Sanish if (ptr->class_code == classcode) {
283923c35297Sanish return (ptr->name);
284023c35297Sanish }
284123c35297Sanish }
284223c35297Sanish return (NULL);
284323c35297Sanish }
284423c35297Sanish #endif /* _DONT_USE_1275_GENERIC_NAMES */
284523c35297Sanish
284623c35297Sanish static dev_info_t *
pcicfg_devi_find(dev_info_t * dip,uint_t device,uint_t function)284723c35297Sanish pcicfg_devi_find(dev_info_t *dip, uint_t device, uint_t function)
284823c35297Sanish {
284923c35297Sanish struct pcicfg_find_ctrl ctrl;
285023c35297Sanish int count;
285123c35297Sanish
285223c35297Sanish ctrl.device = device;
285323c35297Sanish ctrl.function = function;
285423c35297Sanish ctrl.dip = NULL;
285523c35297Sanish
285623c35297Sanish ndi_devi_enter(dip, &count);
285723c35297Sanish ddi_walk_devs(ddi_get_child(dip), pcicfg_match_dev, (void *)&ctrl);
285823c35297Sanish ndi_devi_exit(dip, count);
285923c35297Sanish
286023c35297Sanish return (ctrl.dip);
286123c35297Sanish }
286223c35297Sanish
286323c35297Sanish static int
pcicfg_match_dev(dev_info_t * dip,void * hdl)286423c35297Sanish pcicfg_match_dev(dev_info_t *dip, void *hdl)
286523c35297Sanish {
286623c35297Sanish struct pcicfg_find_ctrl *ctrl = (struct pcicfg_find_ctrl *)hdl;
286723c35297Sanish pci_regspec_t *pci_rp;
286823c35297Sanish int length;
286923c35297Sanish int pci_dev;
287023c35297Sanish int pci_func;
287123c35297Sanish
287226947304SEvan Yan if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
287326947304SEvan Yan "reg", (int **)&pci_rp, (uint_t *)&length) != DDI_PROP_SUCCESS) {
287423c35297Sanish ctrl->dip = NULL;
287523c35297Sanish return (DDI_WALK_TERMINATE);
287623c35297Sanish }
287723c35297Sanish
287823c35297Sanish /* get the PCI device address info */
287923c35297Sanish pci_dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
288023c35297Sanish pci_func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
288123c35297Sanish
288223c35297Sanish /*
288323c35297Sanish * free the memory allocated by ddi_prop_lookup_int_array
288423c35297Sanish */
288523c35297Sanish ddi_prop_free(pci_rp);
288623c35297Sanish
288723c35297Sanish
288823c35297Sanish if ((pci_dev == ctrl->device) && (pci_func == ctrl->function)) {
288923c35297Sanish /* found the match for the specified device address */
289023c35297Sanish ctrl->dip = dip;
289123c35297Sanish return (DDI_WALK_TERMINATE);
289223c35297Sanish }
289323c35297Sanish
289423c35297Sanish /*
289523c35297Sanish * continue the walk to the next sibling to look for a match.
289623c35297Sanish */
289723c35297Sanish return (DDI_WALK_PRUNECHILD);
289823c35297Sanish }
289923c35297Sanish
290023c35297Sanish static int
pcicfg_update_assigned_prop(dev_info_t * dip,pci_regspec_t * newone)290123c35297Sanish pcicfg_update_assigned_prop(dev_info_t *dip, pci_regspec_t *newone)
290223c35297Sanish {
290323c35297Sanish int alen;
290423c35297Sanish pci_regspec_t *assigned;
290523c35297Sanish caddr_t newreg;
290623c35297Sanish uint_t status;
290723c35297Sanish
290823c35297Sanish status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
290923c35297Sanish "assigned-addresses", (caddr_t)&assigned, &alen);
291023c35297Sanish switch (status) {
291123c35297Sanish case DDI_PROP_SUCCESS:
291223c35297Sanish break;
291323c35297Sanish case DDI_PROP_NO_MEMORY:
291423c35297Sanish DEBUG0("no memory for assigned-addresses property\n");
291523c35297Sanish return (PCICFG_FAILURE);
291623c35297Sanish default:
291723c35297Sanish (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
291823c35297Sanish "assigned-addresses", (int *)newone,
291923c35297Sanish sizeof (*newone)/sizeof (int));
292023c35297Sanish return (PCICFG_SUCCESS);
292123c35297Sanish }
292223c35297Sanish
292323c35297Sanish /*
292423c35297Sanish * Allocate memory for the existing
292523c35297Sanish * assigned-addresses(s) plus one and then
292623c35297Sanish * build it.
292723c35297Sanish */
292823c35297Sanish
292923c35297Sanish newreg = kmem_zalloc(alen+sizeof (*newone), KM_SLEEP);
293023c35297Sanish
293123c35297Sanish bcopy(assigned, newreg, alen);
293223c35297Sanish bcopy(newone, newreg + alen, sizeof (*newone));
293323c35297Sanish
293423c35297Sanish /*
293523c35297Sanish * Write out the new "assigned-addresses" spec
293623c35297Sanish */
293723c35297Sanish (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
293823c35297Sanish "assigned-addresses", (int *)newreg,
293923c35297Sanish (alen + sizeof (*newone))/sizeof (int));
294023c35297Sanish
294123c35297Sanish kmem_free((caddr_t)newreg, alen+sizeof (*newone));
294223c35297Sanish kmem_free(assigned, alen);
294323c35297Sanish
294423c35297Sanish return (PCICFG_SUCCESS);
294523c35297Sanish }
294623c35297Sanish
294723c35297Sanish static int
pcicfg_update_ranges_prop(dev_info_t * dip,ppb_ranges_t * addition)294823c35297Sanish pcicfg_update_ranges_prop(dev_info_t *dip, ppb_ranges_t *addition)
294923c35297Sanish {
295023c35297Sanish int rlen;
295123c35297Sanish ppb_ranges_t *ranges;
295223c35297Sanish caddr_t newreg;
295323c35297Sanish uint_t status;
295423c35297Sanish
295526947304SEvan Yan status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
295626947304SEvan Yan "ranges", (caddr_t)&ranges, &rlen);
295723c35297Sanish
295823c35297Sanish
295923c35297Sanish switch (status) {
296023c35297Sanish case DDI_PROP_SUCCESS:
296123c35297Sanish break;
296223c35297Sanish case DDI_PROP_NO_MEMORY:
296323c35297Sanish DEBUG0("ranges present, but unable to get memory\n");
296423c35297Sanish return (PCICFG_FAILURE);
296523c35297Sanish default:
296623c35297Sanish DEBUG0("no ranges property - creating one\n");
296723c35297Sanish if (ndi_prop_update_int_array(DDI_DEV_T_NONE,
296823c35297Sanish dip, "ranges", (int *)addition,
296923c35297Sanish sizeof (ppb_ranges_t)/sizeof (int))
297023c35297Sanish != DDI_SUCCESS) {
297123c35297Sanish DEBUG0("Did'nt create ranges property\n");
297223c35297Sanish return (PCICFG_FAILURE);
297323c35297Sanish }
297423c35297Sanish return (PCICFG_SUCCESS);
297523c35297Sanish }
297623c35297Sanish
297723c35297Sanish /*
297823c35297Sanish * Allocate memory for the existing ranges plus one and then
297923c35297Sanish * build it.
298023c35297Sanish */
298123c35297Sanish newreg = kmem_zalloc(rlen+sizeof (ppb_ranges_t), KM_SLEEP);
298223c35297Sanish
298323c35297Sanish bcopy(ranges, newreg, rlen);
298423c35297Sanish bcopy(addition, newreg + rlen, sizeof (ppb_ranges_t));
298523c35297Sanish
298623c35297Sanish /*
298723c35297Sanish * Write out the new "ranges" property
298823c35297Sanish */
298926947304SEvan Yan (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "ranges",
299026947304SEvan Yan (int *)newreg, (rlen + sizeof (ppb_ranges_t))/sizeof (int));
299123c35297Sanish
299223c35297Sanish DEBUG1("Updating ranges property for %d entries",
299323c35297Sanish rlen / sizeof (ppb_ranges_t) + 1);
299423c35297Sanish
299523c35297Sanish kmem_free((caddr_t)newreg, rlen+sizeof (ppb_ranges_t));
299623c35297Sanish
299723c35297Sanish kmem_free((caddr_t)ranges, rlen);
299823c35297Sanish
299923c35297Sanish return (PCICFG_SUCCESS);
300023c35297Sanish }
300123c35297Sanish
300223c35297Sanish static int
pcicfg_update_reg_prop(dev_info_t * dip,uint32_t regvalue,uint_t reg_offset)300323c35297Sanish pcicfg_update_reg_prop(dev_info_t *dip, uint32_t regvalue, uint_t reg_offset)
300423c35297Sanish {
300523c35297Sanish int rlen;
300623c35297Sanish pci_regspec_t *reg;
300723c35297Sanish caddr_t newreg;
300823c35297Sanish uint32_t hiword;
300923c35297Sanish pci_regspec_t addition;
301023c35297Sanish uint32_t size;
301123c35297Sanish uint_t status;
301223c35297Sanish
301323c35297Sanish status = ddi_getlongprop(DDI_DEV_T_ANY,
301423c35297Sanish dip, DDI_PROP_DONTPASS, "reg", (caddr_t)®, &rlen);
301523c35297Sanish
301623c35297Sanish switch (status) {
301723c35297Sanish case DDI_PROP_SUCCESS:
301823c35297Sanish break;
301923c35297Sanish case DDI_PROP_NO_MEMORY:
302023c35297Sanish DEBUG0("reg present, but unable to get memory\n");
302123c35297Sanish return (PCICFG_FAILURE);
302223c35297Sanish default:
302323c35297Sanish DEBUG0("no reg property\n");
302423c35297Sanish return (PCICFG_FAILURE);
302523c35297Sanish }
302623c35297Sanish
302723c35297Sanish /*
302823c35297Sanish * Allocate memory for the existing reg(s) plus one and then
302923c35297Sanish * build it.
303023c35297Sanish */
303123c35297Sanish newreg = kmem_zalloc(rlen+sizeof (pci_regspec_t), KM_SLEEP);
303223c35297Sanish
303323c35297Sanish /*
303423c35297Sanish * Build the regspec, then add it to the existing one(s)
303523c35297Sanish */
303623c35297Sanish
303723c35297Sanish hiword = PCICFG_MAKE_REG_HIGH(PCI_REG_BUS_G(reg->pci_phys_hi),
303823c35297Sanish PCI_REG_DEV_G(reg->pci_phys_hi),
303923c35297Sanish PCI_REG_FUNC_G(reg->pci_phys_hi), reg_offset);
304023c35297Sanish
304123c35297Sanish if (reg_offset == PCI_CONF_ROM) {
304223c35297Sanish size = (~(PCI_BASE_ROM_ADDR_M & regvalue))+1;
304323c35297Sanish hiword |= PCI_ADDR_MEM32;
304423c35297Sanish } else {
304523c35297Sanish size = (~(PCI_BASE_M_ADDR_M & regvalue))+1;
304623c35297Sanish
304723c35297Sanish if ((PCI_BASE_SPACE_M & regvalue) == PCI_BASE_SPACE_MEM) {
304823c35297Sanish if ((PCI_BASE_TYPE_M & regvalue) == PCI_BASE_TYPE_MEM) {
304923c35297Sanish hiword |= PCI_ADDR_MEM32;
305023c35297Sanish } else if ((PCI_BASE_TYPE_M & regvalue)
305123c35297Sanish == PCI_BASE_TYPE_ALL) {
305223c35297Sanish hiword |= PCI_ADDR_MEM64;
305323c35297Sanish }
305423c35297Sanish if (regvalue & PCI_BASE_PREF_M)
305523c35297Sanish hiword |= PCI_REG_PF_M;
305623c35297Sanish } else {
305723c35297Sanish hiword |= PCI_ADDR_IO;
305823c35297Sanish }
305923c35297Sanish }
306023c35297Sanish
306123c35297Sanish addition.pci_phys_hi = hiword;
306223c35297Sanish addition.pci_phys_mid = 0;
306323c35297Sanish addition.pci_phys_low = 0;
306423c35297Sanish addition.pci_size_hi = 0;
306523c35297Sanish addition.pci_size_low = size;
306623c35297Sanish
306723c35297Sanish bcopy(reg, newreg, rlen);
306823c35297Sanish bcopy(&addition, newreg + rlen, sizeof (pci_regspec_t));
306923c35297Sanish
307023c35297Sanish DEBUG3("updating BAR@off %x with %x,%x\n", reg_offset, hiword, size);
307123c35297Sanish /*
307223c35297Sanish * Write out the new "reg" property
307323c35297Sanish */
307426947304SEvan Yan (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "reg",
307526947304SEvan Yan (int *)newreg, (rlen + sizeof (pci_regspec_t))/sizeof (int));
307623c35297Sanish
307723c35297Sanish kmem_free((caddr_t)newreg, rlen+sizeof (pci_regspec_t));
307823c35297Sanish kmem_free((caddr_t)reg, rlen);
307923c35297Sanish
308023c35297Sanish return (PCICFG_SUCCESS);
308123c35297Sanish }
308223c35297Sanish
308326947304SEvan 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)308426947304SEvan Yan pcicfg_update_assigned_prop_value(dev_info_t *dip, uint32_t size,
308526947304SEvan Yan uint32_t base, uint32_t base_hi, uint_t reg_offset)
308626947304SEvan Yan {
308726947304SEvan Yan int rlen;
308826947304SEvan Yan pci_regspec_t *reg;
308926947304SEvan Yan uint32_t hiword;
309026947304SEvan Yan pci_regspec_t addition;
309126947304SEvan Yan uint_t status;
309226947304SEvan Yan
309326947304SEvan Yan status = ddi_getlongprop(DDI_DEV_T_ANY,
309426947304SEvan Yan dip, DDI_PROP_DONTPASS, "reg", (caddr_t)®, &rlen);
309526947304SEvan Yan
309626947304SEvan Yan switch (status) {
309726947304SEvan Yan case DDI_PROP_SUCCESS:
309826947304SEvan Yan break;
309926947304SEvan Yan case DDI_PROP_NO_MEMORY:
310026947304SEvan Yan DEBUG0("reg present, but unable to get memory\n");
310126947304SEvan Yan return (PCICFG_FAILURE);
310226947304SEvan Yan default:
310326947304SEvan Yan /*
310426947304SEvan Yan * Since the config space "reg" entry should have been
310526947304SEvan Yan * created, we expect a "reg" property already
310626947304SEvan Yan * present here.
310726947304SEvan Yan */
310826947304SEvan Yan DEBUG0("no reg property\n");
310926947304SEvan Yan return (PCICFG_FAILURE);
311026947304SEvan Yan }
311126947304SEvan Yan
311226947304SEvan Yan /*
311326947304SEvan Yan * Build the regspec, then add it to the existing one(s)
311426947304SEvan Yan */
311526947304SEvan Yan
311626947304SEvan Yan hiword = PCICFG_MAKE_REG_HIGH(PCI_REG_BUS_G(reg->pci_phys_hi),
311726947304SEvan Yan PCI_REG_DEV_G(reg->pci_phys_hi),
311826947304SEvan Yan PCI_REG_FUNC_G(reg->pci_phys_hi), reg_offset);
311926947304SEvan Yan
312026947304SEvan Yan hiword |= PCI_REG_REL_M;
312126947304SEvan Yan
312226947304SEvan Yan if (reg_offset == PCI_CONF_ROM) {
312326947304SEvan Yan hiword |= PCI_ADDR_MEM32;
312426947304SEvan Yan
312526947304SEvan Yan base = PCI_BASE_ROM_ADDR_M & base;
312626947304SEvan Yan } else {
312726947304SEvan Yan if ((PCI_BASE_SPACE_M & base) == PCI_BASE_SPACE_MEM) {
312826947304SEvan Yan if ((PCI_BASE_TYPE_M & base) == PCI_BASE_TYPE_MEM) {
312926947304SEvan Yan hiword |= PCI_ADDR_MEM32;
313026947304SEvan Yan } else if ((PCI_BASE_TYPE_M & base)
313126947304SEvan Yan == PCI_BASE_TYPE_ALL) {
313226947304SEvan Yan hiword |= PCI_ADDR_MEM64;
313326947304SEvan Yan }
313426947304SEvan Yan if (base & PCI_BASE_PREF_M)
313526947304SEvan Yan hiword |= PCI_REG_PF_M;
313626947304SEvan Yan
313726947304SEvan Yan base = PCI_BASE_M_ADDR_M & base;
313826947304SEvan Yan } else {
313926947304SEvan Yan hiword |= PCI_ADDR_IO;
314026947304SEvan Yan
314126947304SEvan Yan base = PCI_BASE_IO_ADDR_M & base;
314226947304SEvan Yan base_hi = 0;
314326947304SEvan Yan }
314426947304SEvan Yan }
314526947304SEvan Yan
314626947304SEvan Yan addition.pci_phys_hi = hiword;
314726947304SEvan Yan addition.pci_phys_mid = base_hi;
314826947304SEvan Yan addition.pci_phys_low = base;
314926947304SEvan Yan addition.pci_size_hi = 0;
315026947304SEvan Yan addition.pci_size_low = size;
315126947304SEvan Yan
315226947304SEvan Yan DEBUG3("updating BAR@off %x with %x,%x\n", reg_offset, hiword, size);
315326947304SEvan Yan
315426947304SEvan Yan kmem_free((caddr_t)reg, rlen);
315526947304SEvan Yan
315626947304SEvan Yan return (pcicfg_update_assigned_prop(dip, &addition));
315726947304SEvan Yan }
315826947304SEvan Yan
315923c35297Sanish static void
pcicfg_device_on(ddi_acc_handle_t config_handle)316023c35297Sanish pcicfg_device_on(ddi_acc_handle_t config_handle)
316123c35297Sanish {
316223c35297Sanish /*
316323c35297Sanish * Enable memory, IO, and bus mastership
316423c35297Sanish * XXX should we enable parity, SERR#,
316523c35297Sanish * fast back-to-back, and addr. stepping?
316623c35297Sanish */
316723c35297Sanish pci_config_put16(config_handle, PCI_CONF_COMM,
316823c35297Sanish pci_config_get16(config_handle, PCI_CONF_COMM) | 0x7);
316923c35297Sanish }
317023c35297Sanish
317123c35297Sanish static void
pcicfg_device_off(ddi_acc_handle_t config_handle)317223c35297Sanish pcicfg_device_off(ddi_acc_handle_t config_handle)
317323c35297Sanish {
317423c35297Sanish /*
317523c35297Sanish * Disable I/O and memory traffic through the bridge
317623c35297Sanish */
317723c35297Sanish pci_config_put16(config_handle, PCI_CONF_COMM, 0x0);
317823c35297Sanish }
317923c35297Sanish
318023c35297Sanish /*
318123c35297Sanish * Setup the basic 1275 properties based on information found in the config
318223c35297Sanish * header of the PCI device
318323c35297Sanish */
318423c35297Sanish static int
pcicfg_set_standard_props(dev_info_t * dip,ddi_acc_handle_t config_handle,uint8_t pcie_dev)318523c35297Sanish pcicfg_set_standard_props(dev_info_t *dip, ddi_acc_handle_t config_handle,
318623c35297Sanish uint8_t pcie_dev)
318723c35297Sanish {
318849fbdd30SErwin T Tsaur int ret;
318949fbdd30SErwin T Tsaur uint16_t cap_id_loc, val;
319023c35297Sanish uint32_t wordval;
319123c35297Sanish uint8_t byteval;
319223c35297Sanish
319323c35297Sanish /* These two exists only for non-bridges */
319426947304SEvan Yan if (((pci_config_get8(config_handle, PCI_CONF_HEADER) &
319526947304SEvan Yan PCI_HEADER_TYPE_M) == PCI_HEADER_ZERO) && !pcie_dev) {
319623c35297Sanish byteval = pci_config_get8(config_handle, PCI_CONF_MIN_G);
319723c35297Sanish if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
319823c35297Sanish "min-grant", byteval)) != DDI_SUCCESS) {
319923c35297Sanish return (ret);
320023c35297Sanish }
320123c35297Sanish
320223c35297Sanish byteval = pci_config_get8(config_handle, PCI_CONF_MAX_L);
320323c35297Sanish if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
320423c35297Sanish "max-latency", byteval)) != DDI_SUCCESS) {
320523c35297Sanish return (ret);
320623c35297Sanish }
320723c35297Sanish }
320823c35297Sanish
320923c35297Sanish /*
321023c35297Sanish * These should always exist and have the value of the
321123c35297Sanish * corresponding register value
321223c35297Sanish */
321323c35297Sanish val = pci_config_get16(config_handle, PCI_CONF_VENID);
321423c35297Sanish
321526947304SEvan Yan if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, "vendor-id", val))
321626947304SEvan Yan != DDI_SUCCESS) {
321723c35297Sanish return (ret);
321823c35297Sanish }
321923c35297Sanish val = pci_config_get16(config_handle, PCI_CONF_DEVID);
322026947304SEvan Yan if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, "device-id", val))
322126947304SEvan Yan != DDI_SUCCESS) {
322223c35297Sanish return (ret);
322323c35297Sanish }
322423c35297Sanish byteval = pci_config_get8(config_handle, PCI_CONF_REVID);
322523c35297Sanish if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
322623c35297Sanish "revision-id", byteval)) != DDI_SUCCESS) {
322723c35297Sanish return (ret);
322823c35297Sanish }
322923c35297Sanish
323023c35297Sanish wordval = (pci_config_get16(config_handle, PCI_CONF_SUBCLASS)<< 8) |
323123c35297Sanish (pci_config_get8(config_handle, PCI_CONF_PROGCLASS));
323223c35297Sanish
323323c35297Sanish if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
323423c35297Sanish "class-code", wordval)) != DDI_SUCCESS) {
323523c35297Sanish return (ret);
323623c35297Sanish }
323726947304SEvan Yan val = (pci_config_get16(config_handle, PCI_CONF_STAT) &
323826947304SEvan Yan PCI_STAT_DEVSELT);
323923c35297Sanish if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
324023c35297Sanish "devsel-speed", val)) != DDI_SUCCESS) {
324123c35297Sanish return (ret);
324223c35297Sanish }
324323c35297Sanish
324423c35297Sanish /*
324523c35297Sanish * The next three are bits set in the status register. The property is
324623c35297Sanish * present (but with no value other than its own existence) if the bit
324723c35297Sanish * is set, non-existent otherwise
324823c35297Sanish */
324923c35297Sanish if ((!pcie_dev) &&
325026947304SEvan Yan (pci_config_get16(config_handle, PCI_CONF_STAT) & PCI_STAT_FBBC)) {
325123c35297Sanish if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
325223c35297Sanish "fast-back-to-back", 0)) != DDI_SUCCESS) {
325323c35297Sanish return (ret);
325423c35297Sanish }
325523c35297Sanish }
325623c35297Sanish if ((!pcie_dev) &&
325726947304SEvan Yan (pci_config_get16(config_handle, PCI_CONF_STAT) & PCI_STAT_66MHZ)) {
325823c35297Sanish if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
325923c35297Sanish "66mhz-capable", 0)) != DDI_SUCCESS) {
326023c35297Sanish return (ret);
326123c35297Sanish }
326223c35297Sanish }
326323c35297Sanish if (pci_config_get16(config_handle, PCI_CONF_STAT) & PCI_STAT_UDF) {
326423c35297Sanish if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
326523c35297Sanish "udf-supported", 0)) != DDI_SUCCESS) {
326623c35297Sanish return (ret);
326723c35297Sanish }
326823c35297Sanish }
326923c35297Sanish
327023c35297Sanish /*
327123c35297Sanish * These next three are optional and are not present
327223c35297Sanish * if the corresponding register is zero. If the value
327323c35297Sanish * is non-zero then the property exists with the value
327423c35297Sanish * of the register.
327523c35297Sanish */
327626947304SEvan Yan if ((val = pci_config_get16(config_handle, PCI_CONF_SUBVENID)) != 0) {
327723c35297Sanish if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
327823c35297Sanish "subsystem-vendor-id", val)) != DDI_SUCCESS) {
327923c35297Sanish return (ret);
328023c35297Sanish }
328123c35297Sanish }
328226947304SEvan Yan if ((val = pci_config_get16(config_handle, PCI_CONF_SUBSYSID)) != 0) {
328323c35297Sanish if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
328423c35297Sanish "subsystem-id", val)) != DDI_SUCCESS) {
328523c35297Sanish return (ret);
328623c35297Sanish }
328723c35297Sanish }
328826947304SEvan Yan if ((val = pci_config_get16(config_handle, PCI_CONF_CACHE_LINESZ))
328926947304SEvan Yan != 0) {
329023c35297Sanish if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
329123c35297Sanish "cache-line-size", val)) != DDI_SUCCESS) {
329223c35297Sanish return (ret);
329323c35297Sanish }
329423c35297Sanish }
329523c35297Sanish
329623c35297Sanish /*
329723c35297Sanish * If the Interrupt Pin register is non-zero then the
329823c35297Sanish * interrupts property exists
329923c35297Sanish */
330023c35297Sanish if ((byteval = pci_config_get8(config_handle, PCI_CONF_IPIN)) != 0) {
330123c35297Sanish /*
330223c35297Sanish * If interrupt pin is non-zero,
330323c35297Sanish * record the interrupt line used
330423c35297Sanish */
330523c35297Sanish if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
330623c35297Sanish "interrupts", byteval)) != DDI_SUCCESS) {
330723c35297Sanish return (ret);
330823c35297Sanish }
330923c35297Sanish }
331049fbdd30SErwin T Tsaur (void) PCI_CAP_LOCATE(config_handle, PCI_CAP_ID_PCI_E, &cap_id_loc);
331149fbdd30SErwin T Tsaur if (pcie_dev && cap_id_loc != PCI_CAP_NEXT_PTR_NULL) {
331226947304SEvan Yan val = pci_config_get16(config_handle, cap_id_loc + PCIE_PCIECAP)
331326947304SEvan Yan & PCIE_PCIECAP_SLOT_IMPL;
331423c35297Sanish /* if slot implemented, get physical slot number */
331523c35297Sanish if (val) {
331623c35297Sanish wordval = pci_config_get32(config_handle, cap_id_loc +
331723c35297Sanish PCIE_SLOTCAP);
331823c35297Sanish /* create the property only if slotnum set correctly? */
331923c35297Sanish if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
332023c35297Sanish "physical-slot#", PCIE_SLOTCAP_PHY_SLOT_NUM(
332123c35297Sanish wordval))) != DDI_SUCCESS) {
332223c35297Sanish return (ret);
332323c35297Sanish }
332423c35297Sanish }
332523c35297Sanish }
332623c35297Sanish
332723c35297Sanish return (PCICFG_SUCCESS);
332823c35297Sanish }
332923c35297Sanish
333023c35297Sanish static int
pcicfg_set_busnode_props(dev_info_t * dip,uint8_t pcie_device_type)333123c35297Sanish pcicfg_set_busnode_props(dev_info_t *dip, uint8_t pcie_device_type)
333223c35297Sanish {
333323c35297Sanish int ret;
333423c35297Sanish char device_type[8];
333523c35297Sanish
333623c35297Sanish if (pcie_device_type)
333723c35297Sanish (void) strcpy(device_type, "pciex");
333823c35297Sanish else
333923c35297Sanish (void) strcpy(device_type, "pci");
334023c35297Sanish
334123c35297Sanish if ((ret = ndi_prop_update_string(DDI_DEV_T_NONE, dip,
334223c35297Sanish "device_type", device_type)) != DDI_SUCCESS) {
334323c35297Sanish return (ret);
334423c35297Sanish }
334523c35297Sanish if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
334623c35297Sanish "#address-cells", 3)) != DDI_SUCCESS) {
334723c35297Sanish return (ret);
334823c35297Sanish }
334926947304SEvan Yan if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, "#size-cells", 2))
335026947304SEvan Yan != DDI_SUCCESS) {
335123c35297Sanish return (ret);
335223c35297Sanish }
335323c35297Sanish return (PCICFG_SUCCESS);
335423c35297Sanish }
335523c35297Sanish
335623c35297Sanish static int
pcicfg_set_childnode_props(dev_info_t * dip,ddi_acc_handle_t config_handle,uint8_t pcie_dev)335723c35297Sanish pcicfg_set_childnode_props(dev_info_t *dip, ddi_acc_handle_t config_handle,
335823c35297Sanish uint8_t pcie_dev)
335923c35297Sanish {
336023c35297Sanish
336123c35297Sanish int ret;
336223c35297Sanish char *name;
336323c35297Sanish char buffer[64], pprefix[8], nprefix[8];
336423c35297Sanish uint16_t classcode;
336523c35297Sanish uint8_t revid, pif, pclass, psubclass;
336623c35297Sanish char *compat[24];
336723c35297Sanish int i;
336823c35297Sanish int n;
336923c35297Sanish uint16_t sub_vid, sub_sid, vid, did;
337023c35297Sanish /* set the property prefix based on the device type */
337123c35297Sanish if (pcie_dev) {
337223c35297Sanish (void) sprintf(pprefix, "pciex");
337323c35297Sanish } else
337423c35297Sanish (void) sprintf(pprefix, "pci");
337523c35297Sanish
337623c35297Sanish /* set the prefix right for name property */
337723c35297Sanish /* x86 platforms need to go with pci for upgrade purposes */
337823c35297Sanish (void) sprintf(nprefix, "pci");
337923c35297Sanish
338023c35297Sanish /*
338123c35297Sanish * NOTE: These are for both a child and PCI-PCI bridge node
338223c35297Sanish */
338326947304SEvan Yan sub_vid = pci_config_get16(config_handle, PCI_CONF_SUBVENID);
338423c35297Sanish sub_sid = pci_config_get16(config_handle, PCI_CONF_SUBSYSID);
338526947304SEvan Yan vid = pci_config_get16(config_handle, PCI_CONF_VENID);
338623c35297Sanish did = pci_config_get16(config_handle, PCI_CONF_DEVID);
338723c35297Sanish revid = pci_config_get8(config_handle, PCI_CONF_REVID);
338823c35297Sanish pif = pci_config_get8(config_handle, PCI_CONF_PROGCLASS);
338923c35297Sanish classcode = pci_config_get16(config_handle, PCI_CONF_SUBCLASS);
339023c35297Sanish pclass = pci_config_get8(config_handle, PCI_CONF_BASCLASS);
339123c35297Sanish psubclass = pci_config_get8(config_handle, PCI_CONF_SUBCLASS);
339223c35297Sanish
3393b2e8ece4Sprasad if (!sub_vid)
339423c35297Sanish (void) sprintf(buffer, "%s%x,%x", nprefix, vid, did);
339523c35297Sanish else
339623c35297Sanish (void) sprintf(buffer, "%s%x,%x", nprefix, sub_vid, sub_sid);
339723c35297Sanish
339823c35297Sanish /*
339923c35297Sanish * In some environments, trying to use "generic" 1275 names is
340023c35297Sanish * not the convention. In those cases use the name as created
340123c35297Sanish * above. In all the rest of the cases, check to see if there
340223c35297Sanish * is a generic name first.
340323c35297Sanish */
340423c35297Sanish #ifdef _DONT_USE_1275_GENERIC_NAMES
340523c35297Sanish name = buffer;
340623c35297Sanish #else
340723c35297Sanish if ((name = pcicfg_get_class_name(classcode)) == NULL) {
340823c35297Sanish /*
340923c35297Sanish * Set name to the above fabricated name
341023c35297Sanish */
341123c35297Sanish name = buffer;
341223c35297Sanish }
341323c35297Sanish #endif
341423c35297Sanish
341523c35297Sanish /*
341623c35297Sanish * The node name field needs to be filled in with the name
341723c35297Sanish */
341823c35297Sanish if (ndi_devi_set_nodename(dip, name, 0) != NDI_SUCCESS) {
341923c35297Sanish DEBUG0("Failed to set nodename for node\n");
342023c35297Sanish return (PCICFG_FAILURE);
342123c35297Sanish }
342223c35297Sanish
342323c35297Sanish /*
342423c35297Sanish * Create the compatible property as an array of pointers
342523c35297Sanish * to strings. Start with the buffer created above.
342623c35297Sanish */
342723c35297Sanish n = 0;
342823c35297Sanish
342923c35297Sanish /*
343023c35297Sanish * Setup 'compatible' as per the PCI2.1 bindings document.
343123c35297Sanish * pci[ex]VVVV,DDDD.SSSS.ssss.RR
343223c35297Sanish * pci[ex]VVVV,DDDD.SSSS.ssss
343323c35297Sanish * pciSSSS.ssss -> not created for PCIe as per PCIe bindings
343423c35297Sanish * pci[ex]VVVV,DDDD.RR
343523c35297Sanish * pci[ex]VVVV,DDDD
343623c35297Sanish * pci[ex]class,CCSSPP
343723c35297Sanish * pci[ex]class,CCSS
343823c35297Sanish * Add legacy entries for compatibility with legacy devices and OS
343923c35297Sanish * for x86.
344023c35297Sanish * pciVVVV,DDDD.SSSS.ssss.RR
344123c35297Sanish * pciVVVV,DDDD.SSSS.ssss
344223c35297Sanish * pciSSSS.ssss
344323c35297Sanish * pciVVVV,DDDD.RR
344423c35297Sanish * pciVVVV,DDDD
344523c35297Sanish * pciclass,CCSSPP
344623c35297Sanish * pciclass,CCSS
344723c35297Sanish */
344823c35297Sanish
344923c35297Sanish do {
3450b2e8ece4Sprasad if (sub_vid) {
345123c35297Sanish /* pci[ex]VVVV,DDDD.SSSS.ssss.RR */
345226947304SEvan Yan (void) sprintf(buffer, "%s%x,%x.%x.%x.%x", pprefix, vid,
345326947304SEvan Yan did, sub_vid, sub_sid, revid);
345423c35297Sanish compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
345523c35297Sanish (void) strcpy(compat[n++], buffer);
345623c35297Sanish
345723c35297Sanish /* pci[ex]VVVV,DDDD.SSSS.ssss */
345826947304SEvan Yan (void) sprintf(buffer, "%s%x,%x.%x.%x", pprefix, vid,
345926947304SEvan Yan did, sub_vid, sub_sid);
346023c35297Sanish compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
346123c35297Sanish (void) strcpy(compat[n++], buffer);
346223c35297Sanish
3463b2e8ece4Sprasad /* pciSSSS.ssss -> not created for PCIe as per PCIe */
3464b2e8ece4Sprasad /* binding to IEEE 1275 spec. */
346523c35297Sanish if (!pcie_dev && pcicfg_do_legacy_props) {
346626947304SEvan Yan (void) sprintf(buffer, "pci%x,%x", sub_vid,
346726947304SEvan Yan sub_sid);
346826947304SEvan Yan compat[n] = kmem_alloc(strlen(buffer) + 1,
346926947304SEvan Yan KM_SLEEP);
347023c35297Sanish (void) strcpy(compat[n++], buffer);
347123c35297Sanish }
3472b2e8ece4Sprasad }
347323c35297Sanish
347423c35297Sanish /* pci[ex]VVVV,DDDD.RR */
347523c35297Sanish (void) sprintf(buffer, "%s%x,%x.%x", pprefix, vid, did, revid);
347623c35297Sanish compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
347723c35297Sanish (void) strcpy(compat[n++], buffer);
347823c35297Sanish
347923c35297Sanish /* pci[ex]VVVV,DDDD */
348023c35297Sanish (void) sprintf(buffer, "%s%x,%x", pprefix, vid, did);
348123c35297Sanish compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
348223c35297Sanish (void) strcpy(compat[n++], buffer);
348323c35297Sanish
348423c35297Sanish /* pci[ex]class,CCSSPP */
348526947304SEvan Yan (void) sprintf(buffer, "%sclass,%02x%02x%02x", pprefix, pclass,
348626947304SEvan Yan psubclass, pif);
348723c35297Sanish compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
348823c35297Sanish (void) strcpy(compat[n++], buffer);
348923c35297Sanish
349023c35297Sanish /* pci[ex]class,CCSS */
349123c35297Sanish (void) sprintf(buffer, "%sclass,%04x", pprefix, classcode);
349223c35297Sanish compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
349323c35297Sanish (void) strcpy(compat[n++], buffer);
349423c35297Sanish
349523c35297Sanish if (!pcie_dev)
349623c35297Sanish break;
349723c35297Sanish
349823c35297Sanish /* also add compatible names using "pci" prefix */
349923c35297Sanish (void) sprintf(pprefix, "pci");
350023c35297Sanish pcie_dev = 0;
350123c35297Sanish
350223c35297Sanish } while (pcicfg_do_legacy_props);
350323c35297Sanish
350426947304SEvan Yan ret = ndi_prop_update_string_array(DDI_DEV_T_NONE, dip, "compatible",
350526947304SEvan Yan (char **)compat, n);
350623c35297Sanish
350723c35297Sanish for (i = 0; i < n; i++) {
350823c35297Sanish kmem_free(compat[i], strlen(compat[i]) + 1);
350923c35297Sanish }
351023c35297Sanish
35111fb5b786Sprasad return (ret);
351223c35297Sanish }
351323c35297Sanish
351423c35297Sanish /*
351523c35297Sanish * Program the bus numbers into the bridge
351623c35297Sanish */
351723c35297Sanish static void
pcicfg_set_bus_numbers(ddi_acc_handle_t config_handle,uint_t primary,uint_t secondary,uint_t subordinate)351823c35297Sanish pcicfg_set_bus_numbers(ddi_acc_handle_t config_handle,
351923c35297Sanish uint_t primary, uint_t secondary, uint_t subordinate)
352023c35297Sanish {
352123c35297Sanish DEBUG3("Setting bridge bus-range %d,%d,%d\n", primary, secondary,
352223c35297Sanish subordinate);
352323c35297Sanish /*
352423c35297Sanish * Primary bus#
352523c35297Sanish */
352623c35297Sanish pci_config_put8(config_handle, PCI_BCNF_PRIBUS, primary);
352723c35297Sanish
352823c35297Sanish /*
352923c35297Sanish * Secondary bus#
353023c35297Sanish */
353123c35297Sanish pci_config_put8(config_handle, PCI_BCNF_SECBUS, secondary);
353223c35297Sanish
353323c35297Sanish /*
353423c35297Sanish * Set the subordinate bus number to ff in order to pass through any
353523c35297Sanish * type 1 cycle with a bus number higher than the secondary bus#
353623c35297Sanish */
353723c35297Sanish pci_config_put8(config_handle, PCI_BCNF_SUBBUS, subordinate);
353823c35297Sanish }
353923c35297Sanish
354023c35297Sanish /*
354123c35297Sanish * Put bridge registers into initial state
354223c35297Sanish */
354323c35297Sanish static void
pcicfg_setup_bridge(pcicfg_phdl_t * entry,ddi_acc_handle_t handle)354423c35297Sanish pcicfg_setup_bridge(pcicfg_phdl_t *entry,
354523c35297Sanish ddi_acc_handle_t handle)
354623c35297Sanish {
354723c35297Sanish /*
354823c35297Sanish * The highest bus seen during probing is the max-subordinate bus
354923c35297Sanish */
355023c35297Sanish pci_config_put8(handle, PCI_BCNF_SUBBUS, entry->highest_bus);
355123c35297Sanish
355223c35297Sanish /*
355323c35297Sanish * Reset the secondary bus
355423c35297Sanish */
355523c35297Sanish pci_config_put16(handle, PCI_BCNF_BCNTRL,
355623c35297Sanish pci_config_get16(handle, PCI_BCNF_BCNTRL) | 0x40);
355723c35297Sanish drv_usecwait(1000);
355823c35297Sanish pci_config_put16(handle, PCI_BCNF_BCNTRL,
355923c35297Sanish pci_config_get16(handle, PCI_BCNF_BCNTRL) & ~0x40);
356023c35297Sanish drv_usecwait(1000);
356123c35297Sanish
356223c35297Sanish /*
356323c35297Sanish * Program the memory base register with the
356423c35297Sanish * start of the memory range
356523c35297Sanish */
356623c35297Sanish pci_config_put16(handle, PCI_BCNF_MEM_BASE,
356723c35297Sanish PCICFG_HIWORD(PCICFG_LOADDR(entry->memory_last)));
356823c35297Sanish
356923c35297Sanish /*
357023c35297Sanish * Program the I/O base register with the start of the I/O range
357123c35297Sanish */
357223c35297Sanish pci_config_put8(handle, PCI_BCNF_IO_BASE_LOW,
357323c35297Sanish PCICFG_HIBYTE(PCICFG_LOWORD(PCICFG_LOADDR(entry->io_last))));
357423c35297Sanish pci_config_put16(handle, PCI_BCNF_IO_BASE_HI,
357523c35297Sanish PCICFG_HIWORD(PCICFG_LOADDR(entry->io_last)));
357623c35297Sanish
357723c35297Sanish /*
357823c35297Sanish * Program the PF memory base register with the start of
357923c35297Sanish * PF memory range
358023c35297Sanish */
358123c35297Sanish pci_config_put16(handle, PCI_BCNF_PF_BASE_LOW,
358223c35297Sanish PCICFG_HIWORD(PCICFG_LOADDR(entry->pf_memory_last)));
358323c35297Sanish pci_config_put32(handle, PCI_BCNF_PF_BASE_HIGH,
358423c35297Sanish PCICFG_HIADDR(entry->pf_memory_last));
358523c35297Sanish
358623c35297Sanish /*
358723c35297Sanish * Clear status bits
358823c35297Sanish */
358923c35297Sanish pci_config_put16(handle, PCI_BCNF_SEC_STATUS, 0xffff);
359023c35297Sanish
359123c35297Sanish /*
359223c35297Sanish * Needs to be set to this value
359323c35297Sanish */
359423c35297Sanish pci_config_put8(handle, PCI_CONF_ILINE, 0xf);
359523c35297Sanish
359623c35297Sanish /*
359723c35297Sanish * XXX - may be delay should be used since noone configures
359823c35297Sanish * devices in the interrupt context
359923c35297Sanish */
360023c35297Sanish drv_usecwait(pcicfg_sec_reset_delay); /* 1 sec wait */
360123c35297Sanish }
360223c35297Sanish
360323c35297Sanish static void
pcicfg_update_bridge(pcicfg_phdl_t * entry,ddi_acc_handle_t handle)360423c35297Sanish pcicfg_update_bridge(pcicfg_phdl_t *entry,
360523c35297Sanish ddi_acc_handle_t handle)
360623c35297Sanish {
360723c35297Sanish uint_t length;
360823c35297Sanish
360923c35297Sanish /*
361023c35297Sanish * Program the memory limit register with the end of the memory range
361123c35297Sanish */
361223c35297Sanish
361323c35297Sanish DEBUG1("DOWN ROUNDED ===>[0x%x]\n",
361426947304SEvan Yan PCICFG_ROUND_DOWN(entry->memory_last, PCICFG_MEMGRAN));
361523c35297Sanish
361623c35297Sanish pci_config_put16(handle, PCI_BCNF_MEM_LIMIT,
361723c35297Sanish PCICFG_HIWORD(PCICFG_LOADDR(
361826947304SEvan Yan PCICFG_ROUND_DOWN(entry->memory_last, PCICFG_MEMGRAN))));
361923c35297Sanish /*
362023c35297Sanish * Since this is a bridge, the rest of this range will
362123c35297Sanish * be responded to by the bridge. We have to round up
362223c35297Sanish * so no other device claims it.
362323c35297Sanish */
362426947304SEvan Yan if ((length = (PCICFG_ROUND_UP(entry->memory_last, PCICFG_MEMGRAN)
362526947304SEvan Yan - entry->memory_last)) > 0) {
362623c35297Sanish (void) pcicfg_get_mem(entry, length, NULL);
362726947304SEvan Yan DEBUG1("Added [0x%x]at the top of the bridge (mem)\n", length);
362823c35297Sanish }
362923c35297Sanish
363023c35297Sanish /*
363123c35297Sanish * Program the PF memory limit register with the end of the memory range
363223c35297Sanish */
363323c35297Sanish
363423c35297Sanish DEBUG1("DOWN ROUNDED ===>[0x%x]\n",
363526947304SEvan Yan PCICFG_ROUND_DOWN(entry->pf_memory_last, PCICFG_MEMGRAN));
363623c35297Sanish
363723c35297Sanish pci_config_put16(handle, PCI_BCNF_PF_LIMIT_LOW,
363826947304SEvan Yan PCICFG_HIWORD(PCICFG_LOADDR(PCICFG_ROUND_DOWN(
363926947304SEvan Yan entry->pf_memory_last, PCICFG_MEMGRAN))));
364026947304SEvan Yan pci_config_put32(handle, PCI_BCNF_PF_LIMIT_HIGH, PCICFG_HIADDR(
364126947304SEvan Yan PCICFG_ROUND_DOWN(entry->pf_memory_last, PCICFG_MEMGRAN)));
364226947304SEvan Yan if ((length = (PCICFG_ROUND_UP(entry->pf_memory_last, PCICFG_MEMGRAN)
364326947304SEvan Yan - entry->pf_memory_last)) > 0) {
364423c35297Sanish (void) pcicfg_get_pf_mem(entry, length, NULL);
364526947304SEvan Yan DEBUG1("Added [0x%x]at the top of the bridge (PF mem)\n",
364626947304SEvan Yan length);
364723c35297Sanish }
364823c35297Sanish
364923c35297Sanish /*
365023c35297Sanish * Program the I/O limit register with the end of the I/O range
365123c35297Sanish */
365223c35297Sanish pci_config_put8(handle, PCI_BCNF_IO_LIMIT_LOW,
365323c35297Sanish PCICFG_HIBYTE(PCICFG_LOWORD(
365426947304SEvan Yan PCICFG_LOADDR(PCICFG_ROUND_DOWN(entry->io_last, PCICFG_IOGRAN)))));
365523c35297Sanish
365626947304SEvan Yan pci_config_put16(handle, PCI_BCNF_IO_LIMIT_HI, PCICFG_HIWORD(
365726947304SEvan Yan PCICFG_LOADDR(PCICFG_ROUND_DOWN(entry->io_last, PCICFG_IOGRAN))));
365823c35297Sanish
365923c35297Sanish /*
366023c35297Sanish * Same as above for I/O space. Since this is a
366123c35297Sanish * bridge, the rest of this range will be responded
366223c35297Sanish * to by the bridge. We have to round up so no
366323c35297Sanish * other device claims it.
366423c35297Sanish */
366526947304SEvan Yan if ((length = (PCICFG_ROUND_UP(entry->io_last, PCICFG_IOGRAN)
366626947304SEvan Yan - entry->io_last)) > 0) {
366723c35297Sanish (void) pcicfg_get_io(entry, length, NULL);
366826947304SEvan Yan DEBUG1("Added [0x%x]at the top of the bridge (I/O)\n", length);
366923c35297Sanish }
367023c35297Sanish }
367123c35297Sanish
367223c35297Sanish 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)367326947304SEvan Yan pcicfg_probe_children(dev_info_t *parent, uint_t bus, uint_t device,
3674c0da6274SZhi-Jun Robin Fu uint_t func, uint_t *highest_bus, pcicfg_flags_t flags, boolean_t is_pcie)
367523c35297Sanish {
367623c35297Sanish dev_info_t *new_child;
367723c35297Sanish ddi_acc_handle_t config_handle;
367823c35297Sanish uint8_t header_type, pcie_dev = 0;
36795af4ae46Sjveta int ret = PCICFG_FAILURE;
368023c35297Sanish
368123c35297Sanish /*
368223c35297Sanish * This node will be put immediately below
368323c35297Sanish * "parent". Allocate a blank device node. It will either
368423c35297Sanish * be filled in or freed up based on further probing.
368523c35297Sanish */
368623c35297Sanish
368723c35297Sanish ndi_devi_alloc_sleep(parent, DEVI_PSEUDO_NEXNAME,
368823c35297Sanish (pnode_t)DEVI_SID_NODEID, &new_child);
368923c35297Sanish
369026947304SEvan Yan if (pcicfg_add_config_reg(new_child, bus, device, func)
369126947304SEvan Yan != DDI_SUCCESS) {
369226947304SEvan Yan DEBUG0("pcicfg_probe_children():Failed to add candidate REG\n");
369323c35297Sanish goto failedconfig;
369423c35297Sanish }
369523c35297Sanish
369623c35297Sanish if ((ret = pcicfg_config_setup(new_child, &config_handle))
369723c35297Sanish != PCICFG_SUCCESS) {
369823c35297Sanish if (ret == PCICFG_NODEVICE) {
369923c35297Sanish (void) ndi_devi_free(new_child);
370023c35297Sanish return (ret);
370123c35297Sanish }
370223c35297Sanish DEBUG0("pcicfg_probe_children():"
370323c35297Sanish "Failed to setup config space\n");
370423c35297Sanish goto failedconfig;
370523c35297Sanish }
370623c35297Sanish
3707c0da6274SZhi-Jun Robin Fu if (is_pcie)
3708c0da6274SZhi-Jun Robin Fu (void) pcie_init_bus(new_child, PCI_GETBDF(bus, device, func),
3709c0da6274SZhi-Jun Robin Fu PCIE_BUS_INITIAL);
3710c0da6274SZhi-Jun Robin Fu
371123c35297Sanish /*
371223c35297Sanish * As soon as we have access to config space,
371323c35297Sanish * turn off device. It will get turned on
371423c35297Sanish * later (after memory is assigned).
371523c35297Sanish */
371623c35297Sanish (void) pcicfg_device_off(config_handle);
371723c35297Sanish
371823c35297Sanish /* check if we are PCIe device */
371923c35297Sanish if (pcicfg_pcie_dev(new_child, config_handle) == DDI_SUCCESS) {
372023c35297Sanish DEBUG0("PCIe device detected\n");
372123c35297Sanish pcie_dev = 1;
372223c35297Sanish }
372323c35297Sanish
372423c35297Sanish /*
372523c35297Sanish * Set 1275 properties common to all devices
372623c35297Sanish */
372726947304SEvan Yan if (pcicfg_set_standard_props(new_child, config_handle, pcie_dev)
372826947304SEvan Yan != PCICFG_SUCCESS) {
372923c35297Sanish DEBUG0("Failed to set standard properties\n");
373023c35297Sanish goto failedchild;
373123c35297Sanish }
373223c35297Sanish
373323c35297Sanish /*
373423c35297Sanish * Child node properties NOTE: Both for PCI-PCI bridge and child node
373523c35297Sanish */
373626947304SEvan Yan if (pcicfg_set_childnode_props(new_child, config_handle, pcie_dev)
373726947304SEvan Yan != PCICFG_SUCCESS) {
373823c35297Sanish goto failedchild;
373923c35297Sanish }
374023c35297Sanish
374123c35297Sanish header_type = pci_config_get8(config_handle, PCI_CONF_HEADER);
374223c35297Sanish
374323c35297Sanish /*
374423c35297Sanish * If this is not a multi-function card only probe function zero.
374523c35297Sanish */
374623c35297Sanish if ((!(header_type & PCI_HEADER_MULTI)) && (func != 0)) {
374723c35297Sanish
3748c0da6274SZhi-Jun Robin Fu ret = PCICFG_NODEVICE;
3749c0da6274SZhi-Jun Robin Fu goto failedchild;
375023c35297Sanish }
375123c35297Sanish
375223c35297Sanish /*
375323c35297Sanish * Attach the child to its parent
375423c35297Sanish */
375523c35297Sanish (void) i_ndi_config_node(new_child, DS_LINKED, 0);
375623c35297Sanish
37573a634bfcSVikram Hegde DEVI_SET_PCI(new_child);
37583a634bfcSVikram Hegde
375923c35297Sanish if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
376023c35297Sanish
376126947304SEvan Yan DEBUG3("--Bridge found bus [0x%x] device[0x%x] func [0x%x]\n",
376226947304SEvan Yan bus, device, func);
376326947304SEvan Yan
376426947304SEvan Yan /* Only support read-only probe for leaf device */
376526947304SEvan Yan if (flags & PCICFG_FLAG_READ_ONLY)
376626947304SEvan Yan goto failedchild;
376723c35297Sanish
37685af4ae46Sjveta ret = pcicfg_probe_bridge(new_child, config_handle, bus,
3769c0da6274SZhi-Jun Robin Fu highest_bus, is_pcie);
37705af4ae46Sjveta if (ret != PCICFG_SUCCESS) {
377123c35297Sanish (void) pcicfg_free_bridge_resources(new_child);
377223c35297Sanish goto failedchild;
377323c35297Sanish }
377423c35297Sanish
377523c35297Sanish } else {
377623c35297Sanish
377723c35297Sanish DEBUG3("--Leaf device found bus [0x%x] device"
377826947304SEvan Yan "[0x%x] func [0x%x]\n", bus, device, func);
377926947304SEvan Yan
378026947304SEvan Yan if (flags & PCICFG_FLAG_READ_ONLY) {
378126947304SEvan Yan /*
378226947304SEvan Yan * with read-only probe, don't do any resource
378326947304SEvan Yan * allocation, just read the BARs and update props.
378426947304SEvan Yan */
378526947304SEvan Yan ret = pcicfg_populate_props_from_bar(new_child,
378626947304SEvan Yan config_handle);
378726947304SEvan Yan if (ret != PCICFG_SUCCESS)
378826947304SEvan Yan goto failedchild;
378926947304SEvan Yan
379026947304SEvan Yan /*
379126947304SEvan Yan * now allocate the resources, just remove the
379226947304SEvan Yan * resources from the parent busra pool.
379326947304SEvan Yan */
379426947304SEvan Yan ret = pcicfg_device_assign_readonly(new_child);
379526947304SEvan Yan if (ret != PCICFG_SUCCESS) {
379626947304SEvan Yan (void) pcicfg_free_device_resources(new_child);
379726947304SEvan Yan goto failedchild;
379826947304SEvan Yan }
379926947304SEvan Yan
380026947304SEvan Yan } else {
380126947304SEvan Yan /*
380226947304SEvan Yan * update "reg" property by sizing the BARs.
380326947304SEvan Yan */
380426947304SEvan Yan ret = pcicfg_populate_reg_props(new_child,
380526947304SEvan Yan config_handle);
380626947304SEvan Yan if (ret != PCICFG_SUCCESS)
380726947304SEvan Yan goto failedchild;
380826947304SEvan Yan
380926947304SEvan Yan /* now allocate & program the resources */
381026947304SEvan Yan ret = pcicfg_device_assign(new_child);
381126947304SEvan Yan if (ret != PCICFG_SUCCESS) {
381226947304SEvan Yan (void) pcicfg_free_device_resources(new_child);
381326947304SEvan Yan goto failedchild;
381426947304SEvan Yan }
381526947304SEvan Yan }
381626947304SEvan Yan
381726947304SEvan Yan (void) ndi_devi_bind_driver(new_child, 0);
381826947304SEvan Yan }
381926947304SEvan Yan
382026947304SEvan Yan (void) pcicfg_config_teardown(&config_handle);
382126947304SEvan Yan
3822c0da6274SZhi-Jun Robin Fu /*
3823c0da6274SZhi-Jun Robin Fu * Properties have been setted up, so initialize the remaining
3824c0da6274SZhi-Jun Robin Fu * bus_t fields
3825c0da6274SZhi-Jun Robin Fu */
3826c0da6274SZhi-Jun Robin Fu if (is_pcie)
3827c1374a13SSurya Prakki (void) pcie_init_bus(new_child, 0, PCIE_BUS_FINAL);
3828c0da6274SZhi-Jun Robin Fu
382926947304SEvan Yan return (PCICFG_SUCCESS);
383026947304SEvan Yan
383126947304SEvan Yan failedchild:
383226947304SEvan Yan /*
383326947304SEvan Yan * XXX check if it should be taken offline (if online)
383426947304SEvan Yan */
383526947304SEvan Yan (void) pcicfg_config_teardown(&config_handle);
383626947304SEvan Yan
3837c0da6274SZhi-Jun Robin Fu if (is_pcie)
3838c0da6274SZhi-Jun Robin Fu pcie_fini_bus(new_child, PCIE_BUS_FINAL);
3839c0da6274SZhi-Jun Robin Fu
384026947304SEvan Yan failedconfig:
384126947304SEvan Yan
384226947304SEvan Yan (void) ndi_devi_free(new_child);
384326947304SEvan Yan return (ret);
384426947304SEvan Yan }
384526947304SEvan Yan
384626947304SEvan Yan /*
384726947304SEvan Yan * Sizing the BARs and update "reg" property
384826947304SEvan Yan */
384926947304SEvan Yan static int
pcicfg_populate_reg_props(dev_info_t * new_child,ddi_acc_handle_t config_handle)385026947304SEvan Yan pcicfg_populate_reg_props(dev_info_t *new_child,
385126947304SEvan Yan ddi_acc_handle_t config_handle)
385226947304SEvan Yan {
385326947304SEvan Yan int i;
385426947304SEvan Yan uint32_t request;
385523c35297Sanish
385623c35297Sanish i = PCI_CONF_BASE0;
385723c35297Sanish
385823c35297Sanish while (i <= PCI_CONF_BASE5) {
385923c35297Sanish
386023c35297Sanish pci_config_put32(config_handle, i, 0xffffffff);
386123c35297Sanish
386223c35297Sanish request = pci_config_get32(config_handle, i);
386323c35297Sanish /*
386423c35297Sanish * If its a zero length, don't do
386523c35297Sanish * any programming.
386623c35297Sanish */
386723c35297Sanish if (request != 0) {
386823c35297Sanish /*
386923c35297Sanish * Add to the "reg" property
387023c35297Sanish */
387123c35297Sanish if (pcicfg_update_reg_prop(new_child,
387223c35297Sanish request, i) != PCICFG_SUCCESS) {
387323c35297Sanish goto failedchild;
387423c35297Sanish }
387523c35297Sanish } else {
387623c35297Sanish DEBUG1("BASE register [0x%x] asks for "
387723c35297Sanish "[0x0]=[0x0](32)\n", i);
387823c35297Sanish i += 4;
387923c35297Sanish continue;
388023c35297Sanish }
388123c35297Sanish
388223c35297Sanish /*
388323c35297Sanish * Increment by eight if it is 64 bit address space
388423c35297Sanish */
388523c35297Sanish if ((PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_ALL) {
388623c35297Sanish DEBUG3("BASE register [0x%x] asks for "
388723c35297Sanish "[0x%x]=[0x%x] (64)\n",
388826947304SEvan Yan i, request, (~(PCI_BASE_M_ADDR_M & request))+1);
388923c35297Sanish i += 8;
389023c35297Sanish } else {
389123c35297Sanish DEBUG3("BASE register [0x%x] asks for "
389223c35297Sanish "[0x%x]=[0x%x](32)\n",
389326947304SEvan Yan i, request, (~(PCI_BASE_M_ADDR_M & request))+1);
389423c35297Sanish i += 4;
389523c35297Sanish }
389623c35297Sanish }
389723c35297Sanish
389823c35297Sanish /*
389923c35297Sanish * Get the ROM size and create register for it
390023c35297Sanish */
390123c35297Sanish pci_config_put32(config_handle, PCI_CONF_ROM, 0xfffffffe);
390223c35297Sanish
390323c35297Sanish request = pci_config_get32(config_handle, PCI_CONF_ROM);
390423c35297Sanish /*
390523c35297Sanish * If its a zero length, don't do
390623c35297Sanish * any programming.
390723c35297Sanish */
390823c35297Sanish
390923c35297Sanish if (request != 0) {
391023c35297Sanish DEBUG3("BASE register [0x%x] asks for [0x%x]=[0x%x]\n",
391123c35297Sanish PCI_CONF_ROM, request,
391223c35297Sanish (~(PCI_BASE_ROM_ADDR_M & request)) + 1);
391323c35297Sanish /*
391423c35297Sanish * Add to the "reg" property
391523c35297Sanish */
391626947304SEvan Yan if (pcicfg_update_reg_prop(new_child, request, PCI_CONF_ROM)
391726947304SEvan Yan != PCICFG_SUCCESS) {
391823c35297Sanish goto failedchild;
391923c35297Sanish }
392023c35297Sanish }
392123c35297Sanish
392223c35297Sanish return (PCICFG_SUCCESS);
392323c35297Sanish
392423c35297Sanish failedchild:
392526947304SEvan Yan return (PCICFG_FAILURE);
392626947304SEvan Yan }
392726947304SEvan Yan
392823c35297Sanish /*
392926947304SEvan Yan * Read the BARs and update properties. Used in virtual hotplug.
393023c35297Sanish */
393126947304SEvan Yan static int
pcicfg_populate_props_from_bar(dev_info_t * new_child,ddi_acc_handle_t config_handle)393226947304SEvan Yan pcicfg_populate_props_from_bar(dev_info_t *new_child,
393326947304SEvan Yan ddi_acc_handle_t config_handle)
393426947304SEvan Yan {
393526947304SEvan Yan uint32_t request, base, base_hi, size;
393626947304SEvan Yan int i;
393723c35297Sanish
393826947304SEvan Yan i = PCI_CONF_BASE0;
393923c35297Sanish
394026947304SEvan Yan while (i <= PCI_CONF_BASE5) {
394126947304SEvan Yan /*
394226947304SEvan Yan * determine the size of the address space
394326947304SEvan Yan */
394426947304SEvan Yan base = pci_config_get32(config_handle, i);
394526947304SEvan Yan pci_config_put32(config_handle, i, 0xffffffff);
394626947304SEvan Yan request = pci_config_get32(config_handle, i);
394726947304SEvan Yan pci_config_put32(config_handle, i, base);
394826947304SEvan Yan
394926947304SEvan Yan /*
395026947304SEvan Yan * If its a zero length, don't do any programming.
395126947304SEvan Yan */
395226947304SEvan Yan if (request != 0) {
395326947304SEvan Yan /*
395426947304SEvan Yan * Add to the "reg" property
395526947304SEvan Yan */
395626947304SEvan Yan if (pcicfg_update_reg_prop(new_child,
395726947304SEvan Yan request, i) != PCICFG_SUCCESS) {
395826947304SEvan Yan goto failedchild;
395926947304SEvan Yan }
396026947304SEvan Yan
396126947304SEvan Yan if ((PCI_BASE_SPACE_IO & request) == 0 &&
396226947304SEvan Yan (PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_ALL) {
396326947304SEvan Yan base_hi = pci_config_get32(config_handle, i+4);
396426947304SEvan Yan } else {
396526947304SEvan Yan base_hi = 0;
396626947304SEvan Yan }
396726947304SEvan Yan /*
396826947304SEvan Yan * Add to "assigned-addresses" property
396926947304SEvan Yan */
397026947304SEvan Yan size = (~(PCI_BASE_M_ADDR_M & request))+1;
397126947304SEvan Yan if (pcicfg_update_assigned_prop_value(new_child,
397226947304SEvan Yan size, base, base_hi, i) != PCICFG_SUCCESS) {
397326947304SEvan Yan goto failedchild;
397426947304SEvan Yan }
397526947304SEvan Yan } else {
397626947304SEvan Yan DEBUG1("BASE register [0x%x] asks for [0x0]=[0x0]"
397726947304SEvan Yan "(32)\n", i);
397826947304SEvan Yan i += 4;
397926947304SEvan Yan continue;
398026947304SEvan Yan }
398126947304SEvan Yan
398226947304SEvan Yan /*
398326947304SEvan Yan * Increment by eight if it is 64 bit address space
398426947304SEvan Yan */
398526947304SEvan Yan if ((PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_ALL) {
398626947304SEvan Yan DEBUG3("BASE register [0x%x] asks for [0x%x]=[0x%x]"
398726947304SEvan Yan "(64)\n", i, request,
398826947304SEvan Yan (~(PCI_BASE_M_ADDR_M & request)) + 1);
398926947304SEvan Yan i += 8;
399026947304SEvan Yan } else {
399126947304SEvan Yan DEBUG3("BASE register [0x%x] asks for [0x%x]=[0x%x]"
399226947304SEvan Yan "(32)\n", i, request,
399326947304SEvan Yan (~(PCI_BASE_M_ADDR_M & request)) + 1);
399426947304SEvan Yan i += 4;
399526947304SEvan Yan }
399626947304SEvan Yan }
399726947304SEvan Yan
399826947304SEvan Yan /*
399926947304SEvan Yan * Get the ROM size and create register for it
400026947304SEvan Yan */
400126947304SEvan Yan base = pci_config_get32(config_handle, PCI_CONF_ROM);
400226947304SEvan Yan pci_config_put32(config_handle, PCI_CONF_ROM, 0xfffffffe);
400326947304SEvan Yan request = pci_config_get32(config_handle, PCI_CONF_ROM);
400426947304SEvan Yan pci_config_put32(config_handle, PCI_CONF_ROM, base);
400526947304SEvan Yan
400626947304SEvan Yan /*
400726947304SEvan Yan * If its a zero length, don't do
400826947304SEvan Yan * any programming.
400926947304SEvan Yan */
401026947304SEvan Yan if (request != 0) {
401126947304SEvan Yan DEBUG3("BASE register [0x%x] asks for [0x%x]=[0x%x]\n",
401226947304SEvan Yan PCI_CONF_ROM, request,
401326947304SEvan Yan (~(PCI_BASE_ROM_ADDR_M & request)) + 1);
401426947304SEvan Yan /*
401526947304SEvan Yan * Add to the "reg" property
401626947304SEvan Yan */
401726947304SEvan Yan if (pcicfg_update_reg_prop(new_child, request, PCI_CONF_ROM)
401826947304SEvan Yan != PCICFG_SUCCESS) {
401926947304SEvan Yan goto failedchild;
402026947304SEvan Yan }
402126947304SEvan Yan /*
402226947304SEvan Yan * Add to "assigned-addresses" property
402326947304SEvan Yan */
402426947304SEvan Yan size = (~(PCI_BASE_ROM_ADDR_M & request))+1;
402526947304SEvan Yan if (pcicfg_update_assigned_prop_value(new_child, size,
402626947304SEvan Yan base, 0, PCI_CONF_ROM) != PCICFG_SUCCESS) {
402726947304SEvan Yan goto failedchild;
402826947304SEvan Yan }
402926947304SEvan Yan }
403026947304SEvan Yan
403126947304SEvan Yan return (PCICFG_SUCCESS);
403226947304SEvan Yan
403326947304SEvan Yan failedchild:
403426947304SEvan Yan return (PCICFG_FAILURE);
403523c35297Sanish }
403623c35297Sanish
403723c35297Sanish 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)403823c35297Sanish pcicfg_probe_bridge(dev_info_t *new_child, ddi_acc_handle_t h, uint_t bus,
4039c0da6274SZhi-Jun Robin Fu uint_t *highest_bus, boolean_t is_pcie)
404023c35297Sanish {
404123c35297Sanish uint64_t next_bus;
404223c35297Sanish uint_t new_bus, num_slots;
404323c35297Sanish ndi_ra_request_t req;
404423c35297Sanish int rval, i, j;
404523c35297Sanish uint64_t mem_answer, io_answer, mem_base, io_base, mem_alen, io_alen;
404623c35297Sanish uint64_t pf_mem_answer, pf_mem_base, pf_mem_alen;
404723c35297Sanish uint64_t mem_size, io_size, pf_mem_size;
404823c35297Sanish uint64_t mem_end, pf_mem_end, io_end;
404923c35297Sanish uint64_t round_answer, round_len;
405023c35297Sanish ppb_ranges_t range[PCICFG_RANGE_LEN];
405123c35297Sanish int bus_range[2];
405223c35297Sanish pcicfg_phdl_t phdl;
405323c35297Sanish int count;
405423c35297Sanish uint64_t pcibus_base, pcibus_alen;
405523c35297Sanish uint64_t max_bus;
405623c35297Sanish uint8_t pcie_device_type = 0;
405723c35297Sanish uint_t pf_mem_supported = 0;
405826947304SEvan Yan dev_info_t *new_device;
405926947304SEvan Yan int trans_device;
406026947304SEvan Yan int ari_mode = B_FALSE;
406126947304SEvan Yan int max_function = PCI_MAX_FUNCTIONS;
406223c35297Sanish
406323c35297Sanish io_answer = io_base = io_alen = io_size = 0;
406423c35297Sanish pf_mem_answer = pf_mem_base = pf_mem_size = pf_mem_alen = 0;
406523c35297Sanish
406623c35297Sanish /*
406726947304SEvan Yan * Set "device_type" to "pci", the actual type will be set later
406826947304SEvan Yan * by pcicfg_set_busnode_props() below. This is needed as the
406926947304SEvan Yan * pcicfg_ra_free() below would update "available" property based
407026947304SEvan Yan * on "device_type".
407126947304SEvan Yan *
407226947304SEvan Yan * This code can be removed later after PCI configurator is changed
407326947304SEvan Yan * to use PCIRM, which automatically update properties upon allocation
407426947304SEvan Yan * and free, at that time we'll be able to remove the code inside
407526947304SEvan Yan * ndi_ra_alloc/free() which currently updates "available" property
407626947304SEvan Yan * for pci/pcie devices in pcie fabric.
407726947304SEvan Yan */
407826947304SEvan Yan if (ndi_prop_update_string(DDI_DEV_T_NONE, new_child,
407926947304SEvan Yan "device_type", "pci") != DDI_SUCCESS) {
408026947304SEvan Yan DEBUG0("Failed to set \"device_type\" props\n");
408126947304SEvan Yan return (PCICFG_FAILURE);
408226947304SEvan Yan }
408326947304SEvan Yan
408426947304SEvan Yan /*
408523c35297Sanish * setup resource maps for the bridge node
408623c35297Sanish */
408723c35297Sanish if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_PCI_BUSNUM)
408823c35297Sanish == NDI_FAILURE) {
408923c35297Sanish DEBUG0("Can not setup resource map - NDI_RA_TYPE_PCI_BUSNUM\n");
409023c35297Sanish rval = PCICFG_FAILURE;
409123c35297Sanish goto cleanup;
409223c35297Sanish }
409323c35297Sanish if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_MEM) == NDI_FAILURE) {
409423c35297Sanish DEBUG0("Can not setup resource map - NDI_RA_TYPE_MEM\n");
409523c35297Sanish rval = PCICFG_FAILURE;
409623c35297Sanish goto cleanup;
409723c35297Sanish }
409823c35297Sanish if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_IO) == NDI_FAILURE) {
409923c35297Sanish DEBUG0("Can not setup resource map - NDI_RA_TYPE_IO\n");
410023c35297Sanish rval = PCICFG_FAILURE;
410123c35297Sanish goto cleanup;
410223c35297Sanish }
410323c35297Sanish if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_PCI_PREFETCH_MEM) ==
410423c35297Sanish NDI_FAILURE) {
410523c35297Sanish DEBUG0("Can not setup resource map -"
410623c35297Sanish " NDI_RA_TYPE_PCI_PREFETCH_MEM\n");
410723c35297Sanish rval = PCICFG_FAILURE;
410823c35297Sanish goto cleanup;
410923c35297Sanish }
411023c35297Sanish
411123c35297Sanish /*
411223c35297Sanish * Allocate bus range pool for the bridge.
411323c35297Sanish */
411423c35297Sanish bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
411523c35297Sanish req.ra_flags = (NDI_RA_ALLOC_BOUNDED | NDI_RA_ALLOC_PARTIAL_OK);
411623c35297Sanish req.ra_boundbase = 0;
411723c35297Sanish req.ra_boundlen = req.ra_len = (PCI_MAX_BUS_NUM -1);
411823c35297Sanish req.ra_align_mask = 0; /* no alignment needed */
411923c35297Sanish
412023c35297Sanish rval = ndi_ra_alloc(ddi_get_parent(new_child), &req,
412123c35297Sanish &pcibus_base, &pcibus_alen, NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS);
412223c35297Sanish
412323c35297Sanish if (rval != NDI_SUCCESS) {
412423c35297Sanish if (rval == NDI_RA_PARTIAL_REQ) {
412523c35297Sanish /*EMPTY*/
412623c35297Sanish DEBUG0("NDI_RA_PARTIAL_REQ returned for bus range\n");
412723c35297Sanish } else {
412823c35297Sanish DEBUG0(
412923c35297Sanish "Failed to allocate bus range for bridge\n");
41305af4ae46Sjveta rval = PCICFG_NORESRC;
413123c35297Sanish goto cleanup;
413223c35297Sanish }
413323c35297Sanish }
413423c35297Sanish
413523c35297Sanish DEBUG2("Bus Range Allocated [base=%d] [len=%d]\n",
413623c35297Sanish pcibus_base, pcibus_alen);
413723c35297Sanish
413823c35297Sanish /*
413923c35297Sanish * Put available bus range into the pool.
414023c35297Sanish * Take the first one for this bridge to use and don't give
414123c35297Sanish * to child.
414223c35297Sanish */
414323c35297Sanish (void) ndi_ra_free(new_child, pcibus_base+1, pcibus_alen-1,
414423c35297Sanish NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS);
414523c35297Sanish
414623c35297Sanish next_bus = pcibus_base;
414723c35297Sanish max_bus = pcibus_base + pcibus_alen - 1;
414823c35297Sanish
414923c35297Sanish new_bus = next_bus;
415023c35297Sanish
415123c35297Sanish DEBUG1("NEW bus found ->[%d]\n", new_bus);
415223c35297Sanish
415323c35297Sanish /* Keep track of highest bus for subordinate bus programming */
415423c35297Sanish *highest_bus = new_bus;
415523c35297Sanish
415623c35297Sanish /*
415723c35297Sanish * Allocate (non-prefetchable) Memory Space for Bridge
415823c35297Sanish */
415923c35297Sanish bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
416023c35297Sanish req.ra_flags = (NDI_RA_ALLOC_BOUNDED | NDI_RA_ALLOC_PARTIAL_OK);
416123c35297Sanish req.ra_boundbase = 0;
416223c35297Sanish /*
416323c35297Sanish * limit the boundlen,len to a 32b quantity. It should be Ok to
416423c35297Sanish * lose alignment-based-size of resource due to this.
416523c35297Sanish */
416623c35297Sanish req.ra_boundlen = PCICFG_4GIG_LIMIT;
416723c35297Sanish req.ra_len = PCICFG_4GIG_LIMIT; /* Get as big as possible */
416823c35297Sanish req.ra_align_mask =
416923c35297Sanish PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */
417023c35297Sanish
417123c35297Sanish rval = ndi_ra_alloc(ddi_get_parent(new_child), &req,
417223c35297Sanish &mem_answer, &mem_alen, NDI_RA_TYPE_MEM, NDI_RA_PASS);
417323c35297Sanish
417423c35297Sanish if (rval != NDI_SUCCESS) {
417523c35297Sanish if (rval == NDI_RA_PARTIAL_REQ) {
417623c35297Sanish /*EMPTY*/
417723c35297Sanish DEBUG0("NDI_RA_PARTIAL_REQ returned\n");
417823c35297Sanish } else {
417923c35297Sanish DEBUG0(
418023c35297Sanish "Failed to allocate memory for bridge\n");
41815af4ae46Sjveta rval = PCICFG_NORESRC;
418223c35297Sanish goto cleanup;
418323c35297Sanish }
418423c35297Sanish }
418523c35297Sanish
418623c35297Sanish DEBUG3("Bridge Memory Allocated [0x%x.%x] len [0x%x]\n",
418723c35297Sanish PCICFG_HIADDR(mem_answer),
418823c35297Sanish PCICFG_LOADDR(mem_answer),
418923c35297Sanish mem_alen);
419023c35297Sanish
419123c35297Sanish /*
419223c35297Sanish * Put available memory into the pool.
419323c35297Sanish */
419423c35297Sanish (void) ndi_ra_free(new_child, mem_answer, mem_alen, NDI_RA_TYPE_MEM,
419523c35297Sanish NDI_RA_PASS);
419623c35297Sanish
419723c35297Sanish mem_base = mem_answer;
419823c35297Sanish
419923c35297Sanish /*
420023c35297Sanish * Allocate I/O Space for Bridge
420123c35297Sanish */
420223c35297Sanish bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
420323c35297Sanish req.ra_align_mask = PCICFG_IOGRAN - 1; /* 4k alignment */
420423c35297Sanish req.ra_boundbase = 0;
420523c35297Sanish req.ra_boundlen = PCICFG_4GIG_LIMIT;
420623c35297Sanish req.ra_flags = (NDI_RA_ALLOC_BOUNDED | NDI_RA_ALLOC_PARTIAL_OK);
420723c35297Sanish req.ra_len = PCICFG_4GIG_LIMIT; /* Get as big as possible */
420823c35297Sanish
420923c35297Sanish rval = ndi_ra_alloc(ddi_get_parent(new_child), &req, &io_answer,
421023c35297Sanish &io_alen, NDI_RA_TYPE_IO, NDI_RA_PASS);
421123c35297Sanish
421223c35297Sanish if (rval != NDI_SUCCESS) {
421323c35297Sanish if (rval == NDI_RA_PARTIAL_REQ) {
421423c35297Sanish /*EMPTY*/
421523c35297Sanish DEBUG0("NDI_RA_PARTIAL_REQ returned\n");
421623c35297Sanish } else {
421723c35297Sanish DEBUG0("Failed to allocate io space for bridge\n");
421823c35297Sanish /* i/o space is an optional requirement so continue */
421923c35297Sanish }
422023c35297Sanish }
422123c35297Sanish
422223c35297Sanish DEBUG3("Bridge IO Space Allocated [0x%x.%x] len [0x%x]\n",
422323c35297Sanish PCICFG_HIADDR(io_answer), PCICFG_LOADDR(io_answer), io_alen);
422423c35297Sanish
422523c35297Sanish /*
422623c35297Sanish * Put available I/O into the pool.
422723c35297Sanish */
422823c35297Sanish (void) ndi_ra_free(new_child, io_answer, io_alen, NDI_RA_TYPE_IO,
422923c35297Sanish NDI_RA_PASS);
423023c35297Sanish
423123c35297Sanish io_base = io_answer;
423223c35297Sanish
423323c35297Sanish /*
423423c35297Sanish * Check if the bridge supports Prefetchable memory range.
423523c35297Sanish * If it does, then we setup PF memory range for the bridge.
423623c35297Sanish * Otherwise, we skip the step of setting up PF memory
423723c35297Sanish * range for it. This could cause config operation to
423823c35297Sanish * fail if any devices under the bridge need PF memory.
423923c35297Sanish */
424023c35297Sanish /* write a non zero value to the PF BASE register */
424123c35297Sanish pci_config_put16(h, PCI_BCNF_PF_BASE_LOW, 0xfff0);
424223c35297Sanish /* if the read returns zero then PF range is not supported */
424323c35297Sanish if (pci_config_get16(h, PCI_BCNF_PF_BASE_LOW) == 0) {
424423c35297Sanish /* bridge doesn't support PF memory range */
424523c35297Sanish goto pf_setup_end;
424623c35297Sanish } else {
424723c35297Sanish pf_mem_supported = 1;
424823c35297Sanish /* reset the PF BASE register */
424923c35297Sanish pci_config_put16(h, PCI_BCNF_PF_BASE_LOW, 0);
425023c35297Sanish }
425123c35297Sanish
425223c35297Sanish /*
425323c35297Sanish * Bridge supports PF mem range; Allocate PF Memory Space for it.
425423c35297Sanish *
425523c35297Sanish * Note: Both non-prefetchable and prefetchable memory space
425623c35297Sanish * allocations are made within 32bit space. Currently, BIOSs
425723c35297Sanish * allocate device memory for PCI devices within the 32bit space
425823c35297Sanish * so this will not be a problem.
425923c35297Sanish */
426023c35297Sanish bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
426123c35297Sanish req.ra_flags = NDI_RA_ALLOC_PARTIAL_OK | NDI_RA_ALLOC_BOUNDED;
426223c35297Sanish req.ra_boundbase = 0;
426323c35297Sanish req.ra_len = PCICFG_4GIG_LIMIT; /* Get as big as possible */
426423c35297Sanish req.ra_align_mask =
426523c35297Sanish PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */
426623c35297Sanish
426723c35297Sanish rval = ndi_ra_alloc(ddi_get_parent(new_child), &req,
426823c35297Sanish &pf_mem_answer, &pf_mem_alen, NDI_RA_TYPE_PCI_PREFETCH_MEM,
426923c35297Sanish NDI_RA_PASS);
427023c35297Sanish
427123c35297Sanish if (rval != NDI_SUCCESS) {
427223c35297Sanish if (rval == NDI_RA_PARTIAL_REQ) {
427323c35297Sanish /*EMPTY*/
427423c35297Sanish DEBUG0("NDI_RA_PARTIAL_REQ returned\n");
427523c35297Sanish } else {
427623c35297Sanish DEBUG0(
427723c35297Sanish "Failed to allocate PF memory for bridge\n");
427823c35297Sanish /* PF mem is an optional requirement so continue */
427923c35297Sanish }
428023c35297Sanish }
428123c35297Sanish
428223c35297Sanish DEBUG3("Bridge PF Memory Allocated [0x%x.%x] len [0x%x]\n",
428323c35297Sanish PCICFG_HIADDR(pf_mem_answer),
428423c35297Sanish PCICFG_LOADDR(pf_mem_answer),
428523c35297Sanish pf_mem_alen);
428623c35297Sanish
428723c35297Sanish /*
428823c35297Sanish * Put available PF memory into the pool.
428923c35297Sanish */
429023c35297Sanish (void) ndi_ra_free(new_child, pf_mem_answer, pf_mem_alen,
429123c35297Sanish NDI_RA_TYPE_PCI_PREFETCH_MEM, NDI_RA_PASS);
429223c35297Sanish
429323c35297Sanish pf_mem_base = pf_mem_answer;
429423c35297Sanish
429523c35297Sanish /*
429623c35297Sanish * Program the PF memory base register with the
429723c35297Sanish * start of the memory range
429823c35297Sanish */
429923c35297Sanish pci_config_put16(h, PCI_BCNF_PF_BASE_LOW,
430023c35297Sanish PCICFG_HIWORD(PCICFG_LOADDR(pf_mem_answer)));
430123c35297Sanish pci_config_put32(h, PCI_BCNF_PF_BASE_HIGH,
430223c35297Sanish PCICFG_HIADDR(pf_mem_answer));
430323c35297Sanish
430423c35297Sanish /*
430523c35297Sanish * Program the PF memory limit register with the
430623c35297Sanish * end of the memory range.
430723c35297Sanish */
430823c35297Sanish pci_config_put16(h, PCI_BCNF_PF_LIMIT_LOW,
430923c35297Sanish PCICFG_HIWORD(PCICFG_LOADDR(
431023c35297Sanish PCICFG_ROUND_DOWN((pf_mem_answer + pf_mem_alen),
431123c35297Sanish PCICFG_MEMGRAN) - 1)));
431223c35297Sanish pci_config_put32(h, PCI_BCNF_PF_LIMIT_HIGH,
431323c35297Sanish PCICFG_HIADDR(PCICFG_ROUND_DOWN((pf_mem_answer + pf_mem_alen),
431423c35297Sanish PCICFG_MEMGRAN) - 1));
431523c35297Sanish
431623c35297Sanish /*
431723c35297Sanish * Allocate the chunk of PF memory (if any) not programmed into the
431823c35297Sanish * bridge because of the round down.
431923c35297Sanish */
432023c35297Sanish if (PCICFG_ROUND_DOWN((pf_mem_answer + pf_mem_alen), PCICFG_MEMGRAN)
432123c35297Sanish != (pf_mem_answer + pf_mem_alen)) {
432223c35297Sanish DEBUG0("Need to allocate Memory round off chunk\n");
432323c35297Sanish bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
432423c35297Sanish req.ra_flags = NDI_RA_ALLOC_SPECIFIED;
432523c35297Sanish req.ra_addr = PCICFG_ROUND_DOWN((pf_mem_answer + pf_mem_alen),
432623c35297Sanish PCICFG_MEMGRAN);
432723c35297Sanish req.ra_len = (pf_mem_answer + pf_mem_alen) -
432823c35297Sanish (PCICFG_ROUND_DOWN((pf_mem_answer + pf_mem_alen),
432923c35297Sanish PCICFG_MEMGRAN));
433023c35297Sanish
433123c35297Sanish (void) ndi_ra_alloc(new_child, &req,
433223c35297Sanish &round_answer, &round_len, NDI_RA_TYPE_PCI_PREFETCH_MEM,
433323c35297Sanish NDI_RA_PASS);
433423c35297Sanish }
433523c35297Sanish
433623c35297Sanish pf_setup_end:
433723c35297Sanish
433823c35297Sanish /*
433923c35297Sanish * Program the memory base register with the
434023c35297Sanish * start of the memory range
434123c35297Sanish */
434223c35297Sanish pci_config_put16(h, PCI_BCNF_MEM_BASE,
434323c35297Sanish PCICFG_HIWORD(PCICFG_LOADDR(mem_answer)));
434423c35297Sanish
434523c35297Sanish /*
434623c35297Sanish * Program the memory limit register with the
434723c35297Sanish * end of the memory range.
434823c35297Sanish */
434923c35297Sanish
435023c35297Sanish pci_config_put16(h, PCI_BCNF_MEM_LIMIT,
435123c35297Sanish PCICFG_HIWORD(PCICFG_LOADDR(
435223c35297Sanish PCICFG_ROUND_DOWN((mem_answer + mem_alen), PCICFG_MEMGRAN) - 1)));
435323c35297Sanish
435423c35297Sanish /*
435523c35297Sanish * Allocate the chunk of memory (if any) not programmed into the
435623c35297Sanish * bridge because of the round down.
435723c35297Sanish */
435823c35297Sanish if (PCICFG_ROUND_DOWN((mem_answer + mem_alen), PCICFG_MEMGRAN)
435923c35297Sanish != (mem_answer + mem_alen)) {
436023c35297Sanish DEBUG0("Need to allocate Memory round off chunk\n");
436123c35297Sanish bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
436223c35297Sanish req.ra_flags = NDI_RA_ALLOC_SPECIFIED;
436323c35297Sanish req.ra_addr = PCICFG_ROUND_DOWN((mem_answer + mem_alen),
436423c35297Sanish PCICFG_MEMGRAN);
436523c35297Sanish req.ra_len = (mem_answer + mem_alen) -
436623c35297Sanish (PCICFG_ROUND_DOWN((mem_answer + mem_alen),
436723c35297Sanish PCICFG_MEMGRAN));
436823c35297Sanish
436923c35297Sanish (void) ndi_ra_alloc(new_child, &req,
437023c35297Sanish &round_answer, &round_len, NDI_RA_TYPE_MEM, NDI_RA_PASS);
437123c35297Sanish }
437223c35297Sanish
437323c35297Sanish /*
437423c35297Sanish * Program the I/O Space Base
437523c35297Sanish */
437623c35297Sanish pci_config_put8(h, PCI_BCNF_IO_BASE_LOW,
437723c35297Sanish PCICFG_HIBYTE(PCICFG_LOWORD(
437823c35297Sanish PCICFG_LOADDR(io_answer))));
437923c35297Sanish
438023c35297Sanish pci_config_put16(h, PCI_BCNF_IO_BASE_HI,
438123c35297Sanish PCICFG_HIWORD(PCICFG_LOADDR(io_answer)));
438223c35297Sanish
438323c35297Sanish /*
438423c35297Sanish * Program the I/O Space Limit
438523c35297Sanish */
438623c35297Sanish pci_config_put8(h, PCI_BCNF_IO_LIMIT_LOW,
438723c35297Sanish PCICFG_HIBYTE(PCICFG_LOWORD(
438823c35297Sanish PCICFG_LOADDR(PCICFG_ROUND_DOWN(io_answer + io_alen,
438923c35297Sanish PCICFG_IOGRAN)))) - 1);
439023c35297Sanish
439123c35297Sanish pci_config_put16(h, PCI_BCNF_IO_LIMIT_HI,
439223c35297Sanish PCICFG_HIWORD(PCICFG_LOADDR(
439323c35297Sanish PCICFG_ROUND_DOWN(io_answer + io_alen, PCICFG_IOGRAN)))
439423c35297Sanish - 1);
439523c35297Sanish
439623c35297Sanish /*
439723c35297Sanish * Allocate the chunk of I/O (if any) not programmed into the
439823c35297Sanish * bridge because of the round down.
439923c35297Sanish */
440023c35297Sanish if (PCICFG_ROUND_DOWN((io_answer + io_alen), PCICFG_IOGRAN)
440123c35297Sanish != (io_answer + io_alen)) {
440223c35297Sanish DEBUG0("Need to allocate I/O round off chunk\n");
440323c35297Sanish bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
440423c35297Sanish req.ra_flags = NDI_RA_ALLOC_SPECIFIED;
440523c35297Sanish req.ra_addr = PCICFG_ROUND_DOWN((io_answer + io_alen),
440623c35297Sanish PCICFG_IOGRAN);
440723c35297Sanish req.ra_len = (io_answer + io_alen) -
440823c35297Sanish (PCICFG_ROUND_DOWN((io_answer + io_alen),
440923c35297Sanish PCICFG_IOGRAN));
441023c35297Sanish
441123c35297Sanish (void) ndi_ra_alloc(new_child, &req,
441223c35297Sanish &round_answer, &round_len, NDI_RA_TYPE_IO, NDI_RA_PASS);
441323c35297Sanish }
441423c35297Sanish
441523c35297Sanish (void) pcicfg_set_bus_numbers(h, bus, new_bus, max_bus);
441623c35297Sanish
441723c35297Sanish /*
44183f9ec228SZhi-Jun Robin Fu * Setup "ranges" and "bus-range" properties before onlining
44193f9ec228SZhi-Jun Robin Fu * the bridge.
44203f9ec228SZhi-Jun Robin Fu */
44213f9ec228SZhi-Jun Robin Fu bzero((caddr_t)range, sizeof (ppb_ranges_t) * PCICFG_RANGE_LEN);
44223f9ec228SZhi-Jun Robin Fu
44233f9ec228SZhi-Jun Robin Fu range[0].child_high = range[0].parent_high |= (PCI_REG_REL_M |
44243f9ec228SZhi-Jun Robin Fu PCI_ADDR_IO);
44253f9ec228SZhi-Jun Robin Fu range[0].child_low = range[0].parent_low = io_base;
44263f9ec228SZhi-Jun Robin Fu range[1].child_high = range[1].parent_high |=
44273f9ec228SZhi-Jun Robin Fu (PCI_REG_REL_M | PCI_ADDR_MEM32);
44283f9ec228SZhi-Jun Robin Fu range[1].child_low = range[1].parent_low = mem_base;
44293f9ec228SZhi-Jun Robin Fu range[2].child_high = range[2].parent_high |=
44303f9ec228SZhi-Jun Robin Fu (PCI_REG_REL_M | PCI_ADDR_MEM64 | PCI_REG_PF_M);
44313f9ec228SZhi-Jun Robin Fu range[2].child_low = range[2].parent_low = pf_mem_base;
44323f9ec228SZhi-Jun Robin Fu
44333f9ec228SZhi-Jun Robin Fu range[0].size_low = io_alen;
44343f9ec228SZhi-Jun Robin Fu (void) pcicfg_update_ranges_prop(new_child, &range[0]);
44353f9ec228SZhi-Jun Robin Fu range[1].size_low = mem_alen;
44363f9ec228SZhi-Jun Robin Fu (void) pcicfg_update_ranges_prop(new_child, &range[1]);
44373f9ec228SZhi-Jun Robin Fu range[2].size_low = pf_mem_alen;
44383f9ec228SZhi-Jun Robin Fu (void) pcicfg_update_ranges_prop(new_child, &range[2]);
44393f9ec228SZhi-Jun Robin Fu
44403f9ec228SZhi-Jun Robin Fu bus_range[0] = new_bus;
44413f9ec228SZhi-Jun Robin Fu bus_range[1] = max_bus;
44423f9ec228SZhi-Jun Robin Fu (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, new_child,
44433f9ec228SZhi-Jun Robin Fu "bus-range", bus_range, 2);
44443f9ec228SZhi-Jun Robin Fu
44453f9ec228SZhi-Jun Robin Fu /*
444623c35297Sanish * Reset the secondary bus
444723c35297Sanish */
444823c35297Sanish pci_config_put16(h, PCI_BCNF_BCNTRL,
444923c35297Sanish pci_config_get16(h, PCI_BCNF_BCNTRL) | 0x40);
445023c35297Sanish
445123c35297Sanish drv_usecwait(100);
445223c35297Sanish
445323c35297Sanish pci_config_put16(h, PCI_BCNF_BCNTRL,
445423c35297Sanish pci_config_get16(h, PCI_BCNF_BCNTRL) & ~0x40);
445523c35297Sanish
445623c35297Sanish /*
445723c35297Sanish * Clear status bits
445823c35297Sanish */
445923c35297Sanish pci_config_put16(h, PCI_BCNF_SEC_STATUS, 0xffff);
446023c35297Sanish
446123c35297Sanish /*
446223c35297Sanish * Needs to be set to this value
446323c35297Sanish */
446423c35297Sanish pci_config_put8(h, PCI_CONF_ILINE, 0xf);
446523c35297Sanish
446623c35297Sanish /* check our device_type as defined by Open Firmware */
446723c35297Sanish if (pcicfg_pcie_device_type(new_child, h) == DDI_SUCCESS)
446823c35297Sanish pcie_device_type = 1;
446923c35297Sanish
447023c35297Sanish /*
447123c35297Sanish * Set bus properties
447223c35297Sanish */
447323c35297Sanish if (pcicfg_set_busnode_props(new_child, pcie_device_type)
447423c35297Sanish != PCICFG_SUCCESS) {
447523c35297Sanish DEBUG0("Failed to set busnode props\n");
447623c35297Sanish rval = PCICFG_FAILURE;
447723c35297Sanish goto cleanup;
447823c35297Sanish }
447923c35297Sanish
448023c35297Sanish (void) pcicfg_device_on(h);
448123c35297Sanish
4482c0da6274SZhi-Jun Robin Fu if (is_pcie)
4483c1374a13SSurya Prakki (void) pcie_init_bus(new_child, 0, PCIE_BUS_FINAL);
448423c35297Sanish if (ndi_devi_online(new_child, NDI_NO_EVENT|NDI_CONFIG)
448523c35297Sanish != NDI_SUCCESS) {
448623c35297Sanish DEBUG0("Unable to online bridge\n");
448723c35297Sanish rval = PCICFG_FAILURE;
448823c35297Sanish goto cleanup;
448923c35297Sanish }
449023c35297Sanish
449123c35297Sanish DEBUG0("Bridge is ONLINE\n");
449223c35297Sanish
449323c35297Sanish /*
449423c35297Sanish * After a Reset, we need to wait 2^25 clock cycles before the
449523c35297Sanish * first Configuration access. The worst case is 33MHz, which
449623c35297Sanish * is a 1 second wait.
449723c35297Sanish */
449823c35297Sanish drv_usecwait(pcicfg_sec_reset_delay);
449923c35297Sanish
450023c35297Sanish /*
450123c35297Sanish * Probe all children devices
450223c35297Sanish */
450323c35297Sanish DEBUG0("Bridge Programming Complete - probe children\n");
450423c35297Sanish ndi_devi_enter(new_child, &count);
450526947304SEvan Yan for (i = 0; ((i < PCI_MAX_DEVICES) && (ari_mode == B_FALSE));
450626947304SEvan Yan i++) {
450726947304SEvan Yan for (j = 0; j < max_function; ) {
450826947304SEvan Yan if (ari_mode)
450926947304SEvan Yan trans_device = j >> 3;
451026947304SEvan Yan else
451126947304SEvan Yan trans_device = i;
451226947304SEvan Yan
451323c35297Sanish if ((rval = pcicfg_probe_children(new_child,
4514c0da6274SZhi-Jun Robin Fu new_bus, trans_device, j & 7, highest_bus,
4515c0da6274SZhi-Jun Robin Fu 0, is_pcie)) != PCICFG_SUCCESS) {
451623c35297Sanish if (rval == PCICFG_NODEVICE) {
451723c35297Sanish DEBUG3("No Device at bus [0x%x]"
451823c35297Sanish "device [0x%x] "
451926947304SEvan Yan "func [0x%x]\n", new_bus,
452026947304SEvan Yan trans_device, j & 7);
452126947304SEvan Yan
452223c35297Sanish if (j)
452326947304SEvan Yan goto next;
452423c35297Sanish } else
452523c35297Sanish /*EMPTY*/
452623c35297Sanish DEBUG3("Failed to configure bus "
452723c35297Sanish "[0x%x] device [0x%x] "
452826947304SEvan Yan "func [0x%x]\n", new_bus,
452926947304SEvan Yan trans_device, j & 7);
453023c35297Sanish break;
453123c35297Sanish }
453226947304SEvan Yan next:
453326947304SEvan Yan new_device = pcicfg_devi_find(new_child, trans_device,
453426947304SEvan Yan (j & 7));
453526947304SEvan Yan
453626947304SEvan Yan /*
453726947304SEvan Yan * Determine if ARI Forwarding should be enabled.
453826947304SEvan Yan */
453926947304SEvan Yan if (j == 0) {
454026947304SEvan Yan if (new_device == NULL)
454126947304SEvan Yan break;
454226947304SEvan Yan
454326947304SEvan Yan if ((pcie_ari_supported(new_child) ==
454426947304SEvan Yan PCIE_ARI_FORW_SUPPORTED) &&
454526947304SEvan Yan (pcie_ari_device(new_device) ==
454626947304SEvan Yan PCIE_ARI_DEVICE)) {
454726947304SEvan Yan if (pcie_ari_enable(new_child) ==
454826947304SEvan Yan DDI_SUCCESS) {
454926947304SEvan Yan (void) ddi_prop_create(
455026947304SEvan Yan DDI_DEV_T_NONE,
455126947304SEvan Yan new_child,
455226947304SEvan Yan DDI_PROP_CANSLEEP,
455326947304SEvan Yan "ari-enabled", NULL, 0);
455426947304SEvan Yan ari_mode = B_TRUE;
455526947304SEvan Yan max_function =
455626947304SEvan Yan PCICFG_MAX_ARI_FUNCTION;
455726947304SEvan Yan }
455826947304SEvan Yan }
455926947304SEvan Yan }
456026947304SEvan Yan if (ari_mode == B_TRUE) {
456126947304SEvan Yan int next_function;
456226947304SEvan Yan
456326947304SEvan Yan if (new_device == NULL)
456426947304SEvan Yan break;
456526947304SEvan Yan
456626947304SEvan Yan if (pcie_ari_get_next_function(new_device,
456726947304SEvan Yan &next_function) != DDI_SUCCESS)
456826947304SEvan Yan break;
456926947304SEvan Yan
457026947304SEvan Yan j = next_function;
457126947304SEvan Yan
457226947304SEvan Yan if (next_function == 0)
457326947304SEvan Yan break;
457426947304SEvan Yan } else
457526947304SEvan Yan j++;
457626947304SEvan Yan
457723c35297Sanish }
457823c35297Sanish /* if any function fails to be configured, no need to proceed */
457923c35297Sanish if (rval != PCICFG_NODEVICE)
458023c35297Sanish break;
458123c35297Sanish }
458223c35297Sanish ndi_devi_exit(new_child, count);
458323c35297Sanish
458423c35297Sanish /*
458523c35297Sanish * Offline the bridge to allow reprogramming of resources.
458626947304SEvan Yan *
458726947304SEvan Yan * This should always succeed since nobody else has started to
458826947304SEvan Yan * use it yet, failing to detach the driver would indicate a bug.
458926947304SEvan Yan * Also in that case it's better just panic than allowing the
459026947304SEvan Yan * configurator to proceed with BAR reprogramming without bridge
459126947304SEvan Yan * driver detached.
459223c35297Sanish */
459326947304SEvan Yan VERIFY(ndi_devi_offline(new_child, NDI_NO_EVENT|NDI_UNCONFIG)
459426947304SEvan Yan == NDI_SUCCESS);
4595c0da6274SZhi-Jun Robin Fu if (is_pcie)
4596c0da6274SZhi-Jun Robin Fu pcie_fini_bus(new_child, PCIE_BUS_INITIAL);
459723c35297Sanish
459823c35297Sanish phdl.dip = new_child;
459923c35297Sanish phdl.memory_base = mem_answer;
460023c35297Sanish phdl.io_base = io_answer;
460123c35297Sanish phdl.pf_memory_base = pf_mem_answer;
460223c35297Sanish phdl.error = PCICFG_SUCCESS; /* in case of empty child tree */
460323c35297Sanish
460423c35297Sanish ndi_devi_enter(ddi_get_parent(new_child), &count);
460523c35297Sanish ddi_walk_devs(new_child, pcicfg_find_resource_end, (void *)&phdl);
460623c35297Sanish ndi_devi_exit(ddi_get_parent(new_child), count);
460723c35297Sanish
460823c35297Sanish num_slots = pcicfg_get_nslots(new_child, h);
460923c35297Sanish mem_end = PCICFG_ROUND_UP(phdl.memory_base, PCICFG_MEMGRAN);
461023c35297Sanish io_end = PCICFG_ROUND_UP(phdl.io_base, PCICFG_IOGRAN);
461123c35297Sanish pf_mem_end = PCICFG_ROUND_UP(phdl.pf_memory_base, PCICFG_MEMGRAN);
461223c35297Sanish
461326947304SEvan Yan DEBUG4("Start of Unallocated Bridge(%d slots) Resources Mem=0x%lx "
461426947304SEvan Yan "I/O=0x%lx PF_mem=%x%lx\n", num_slots, mem_end, io_end, pf_mem_end);
461523c35297Sanish
461623c35297Sanish /*
461726947304SEvan Yan * Before probing the children we've allocated maximum MEM/IO
461826947304SEvan Yan * resources from parent, and updated "available" property
461926947304SEvan Yan * accordingly. Later we'll be giving up unused resources to
462026947304SEvan Yan * the parent, thus we need to destroy "available" property
462126947304SEvan Yan * here otherwise it will be out-of-sync with the actual free
462226947304SEvan Yan * resources this bridge has. This property will be rebuilt below
462326947304SEvan Yan * with the actual free resources reserved for hotplug slots
462426947304SEvan Yan * (if any).
462526947304SEvan Yan */
462626947304SEvan Yan (void) ndi_prop_remove(DDI_DEV_T_NONE, new_child, "available");
462726947304SEvan Yan /*
462823c35297Sanish * if the bridge a slots, then preallocate. If not, assume static
462923c35297Sanish * configuration. Also check for preallocation limits and spit
463023c35297Sanish * warning messages appropriately (perhaps some can be in debug mode).
463123c35297Sanish */
463223c35297Sanish if (num_slots) {
463326947304SEvan Yan uint64_t mem_reqd = mem_answer +
463426947304SEvan Yan (num_slots * pcicfg_slot_memsize);
463526947304SEvan Yan uint64_t io_reqd = io_answer +
463626947304SEvan Yan (num_slots * pcicfg_slot_iosize);
463726947304SEvan Yan uint64_t pf_mem_reqd = pf_mem_answer +
463826947304SEvan Yan (num_slots * pcicfg_slot_pf_memsize);
463926947304SEvan Yan uint8_t highest_bus_reqd = new_bus +
464026947304SEvan Yan (num_slots * pcicfg_slot_busnums);
4641949b8557Sarutz #ifdef DEBUG
464223c35297Sanish if (mem_end > mem_reqd)
4643949b8557Sarutz DEBUG3("Memory space consumed by bridge more "
464423c35297Sanish "than planned for %d slot(s)(%" PRIx64 ",%"
464523c35297Sanish PRIx64 ")", num_slots, mem_answer, mem_end);
464623c35297Sanish if (io_end > io_reqd)
4647949b8557Sarutz DEBUG3("IO space consumed by bridge more than"
464823c35297Sanish " planned for %d slot(s)(%" PRIx64 ",%" PRIx64 ")",
464923c35297Sanish num_slots, io_answer, io_end);
465023c35297Sanish if (pf_mem_end > pf_mem_reqd)
4651949b8557Sarutz DEBUG3("PF Memory space consumed by bridge"
465223c35297Sanish " more than planned for %d slot(s)(%" PRIx64 ",%"
465323c35297Sanish PRIx64 ")", num_slots, pf_mem_answer, pf_mem_end);
465423c35297Sanish if (*highest_bus > highest_bus_reqd)
4655949b8557Sarutz DEBUG3("Buses consumed by bridge more "
465623c35297Sanish "than planned for %d slot(s)(%x, %x)",
465723c35297Sanish num_slots, new_bus, *highest_bus);
465823c35297Sanish
465923c35297Sanish if (mem_reqd > (mem_answer + mem_alen))
4660949b8557Sarutz DEBUG3("Memory space required by bridge more "
466123c35297Sanish "than available for %d slot(s)(%" PRIx64 ",%"
466223c35297Sanish PRIx64 ")", num_slots, mem_answer, mem_end);
466323c35297Sanish if (io_reqd > (io_answer + io_alen))
4664949b8557Sarutz DEBUG3("IO space required by bridge more than"
466523c35297Sanish "available for %d slot(s)(%" PRIx64 ",%" PRIx64 ")",
466623c35297Sanish num_slots, io_answer, io_end);
466723c35297Sanish if (pf_mem_reqd > (pf_mem_answer + pf_mem_alen))
4668949b8557Sarutz DEBUG3("PF Memory space required by bridge"
466923c35297Sanish " more than available for %d slot(s)(%" PRIx64 ",%"
467023c35297Sanish PRIx64 ")", num_slots, pf_mem_answer, pf_mem_end);
467123c35297Sanish if (highest_bus_reqd > max_bus)
4672949b8557Sarutz DEBUG3("Bus numbers required by bridge more "
467323c35297Sanish "than available for %d slot(s)(%x, %x)",
467423c35297Sanish num_slots, new_bus, *highest_bus);
4675949b8557Sarutz #endif
467623c35297Sanish mem_end = MAX((MIN(mem_reqd, (mem_answer + mem_alen))),
467723c35297Sanish mem_end);
467823c35297Sanish io_end = MAX((MIN(io_reqd, (io_answer + io_alen))), io_end);
467923c35297Sanish pf_mem_end = MAX((MIN(pf_mem_reqd, (pf_mem_answer +
468023c35297Sanish pf_mem_alen))), pf_mem_end);
468123c35297Sanish *highest_bus = MAX((MIN(highest_bus_reqd, max_bus)),
468223c35297Sanish *highest_bus);
468323c35297Sanish DEBUG4("mem_end %lx, io_end %lx, pf_mem_end %lx"
468426947304SEvan Yan " highest_bus %x\n", mem_end, io_end, pf_mem_end,
468526947304SEvan Yan *highest_bus);
468623c35297Sanish }
468723c35297Sanish
468823c35297Sanish /*
468923c35297Sanish * Give back unused memory space to parent.
469023c35297Sanish */
469126947304SEvan Yan (void) ndi_ra_free(ddi_get_parent(new_child), mem_end,
469226947304SEvan Yan (mem_answer + mem_alen) - mem_end, NDI_RA_TYPE_MEM, NDI_RA_PASS);
469323c35297Sanish
469423c35297Sanish if (mem_end == mem_answer) {
469523c35297Sanish DEBUG0("No memory resources used\n");
469623c35297Sanish /*
469723c35297Sanish * To prevent the bridge from forwarding any Memory
469823c35297Sanish * transactions, the Memory Limit will be programmed
469923c35297Sanish * with a smaller value than the Memory Base.
470023c35297Sanish */
470123c35297Sanish pci_config_put16(h, PCI_BCNF_MEM_BASE, 0xffff);
470223c35297Sanish pci_config_put16(h, PCI_BCNF_MEM_LIMIT, 0);
470323c35297Sanish
470423c35297Sanish mem_size = 0;
470523c35297Sanish } else {
470623c35297Sanish /*
470723c35297Sanish * Reprogram the end of the memory.
470823c35297Sanish */
470923c35297Sanish pci_config_put16(h, PCI_BCNF_MEM_LIMIT,
471023c35297Sanish PCICFG_HIWORD(mem_end) - 1);
471123c35297Sanish mem_size = mem_end - mem_base;
471223c35297Sanish }
471323c35297Sanish
471423c35297Sanish /*
471523c35297Sanish * Give back unused io space to parent.
471623c35297Sanish */
471723c35297Sanish (void) ndi_ra_free(ddi_get_parent(new_child),
471823c35297Sanish io_end, (io_answer + io_alen) - io_end,
471923c35297Sanish NDI_RA_TYPE_IO, NDI_RA_PASS);
472023c35297Sanish
472123c35297Sanish if (io_end == io_answer) {
472223c35297Sanish DEBUG0("No IO Space resources used\n");
472323c35297Sanish
472423c35297Sanish /*
472523c35297Sanish * To prevent the bridge from forwarding any I/O
472623c35297Sanish * transactions, the I/O Limit will be programmed
472723c35297Sanish * with a smaller value than the I/O Base.
472823c35297Sanish */
472923c35297Sanish pci_config_put8(h, PCI_BCNF_IO_LIMIT_LOW, 0);
473023c35297Sanish pci_config_put16(h, PCI_BCNF_IO_LIMIT_HI, 0);
473123c35297Sanish pci_config_put8(h, PCI_BCNF_IO_BASE_LOW, 0xff);
473223c35297Sanish pci_config_put16(h, PCI_BCNF_IO_BASE_HI, 0);
473323c35297Sanish
473423c35297Sanish io_size = 0;
473523c35297Sanish } else {
473623c35297Sanish /*
473723c35297Sanish * Reprogram the end of the io space.
473823c35297Sanish */
473923c35297Sanish pci_config_put8(h, PCI_BCNF_IO_LIMIT_LOW,
474023c35297Sanish PCICFG_HIBYTE(PCICFG_LOWORD(
474123c35297Sanish PCICFG_LOADDR(io_end) - 1)));
474223c35297Sanish
474323c35297Sanish pci_config_put16(h, PCI_BCNF_IO_LIMIT_HI,
474423c35297Sanish PCICFG_HIWORD(PCICFG_LOADDR(io_end - 1)));
474523c35297Sanish
474623c35297Sanish io_size = io_end - io_base;
474723c35297Sanish }
474823c35297Sanish
474923c35297Sanish /*
475023c35297Sanish * Give back unused PF memory space to parent.
475123c35297Sanish */
475223c35297Sanish if (pf_mem_supported) {
475323c35297Sanish (void) ndi_ra_free(ddi_get_parent(new_child),
475423c35297Sanish pf_mem_end, (pf_mem_answer + pf_mem_alen) - pf_mem_end,
475523c35297Sanish NDI_RA_TYPE_PCI_PREFETCH_MEM, NDI_RA_PASS);
475623c35297Sanish
475723c35297Sanish if (pf_mem_end == pf_mem_answer) {
475823c35297Sanish DEBUG0("No PF memory resources used\n");
475923c35297Sanish /*
476023c35297Sanish * To prevent the bridge from forwarding any PF Memory
476123c35297Sanish * transactions, the PF Memory Limit will be programmed
476223c35297Sanish * with a smaller value than the Memory Base.
476323c35297Sanish */
476423c35297Sanish pci_config_put16(h, PCI_BCNF_PF_BASE_LOW, 0xfff0);
476523c35297Sanish pci_config_put32(h, PCI_BCNF_PF_BASE_HIGH, 0xffffffff);
476623c35297Sanish pci_config_put16(h, PCI_BCNF_PF_LIMIT_LOW, 0);
476723c35297Sanish pci_config_put32(h, PCI_BCNF_PF_LIMIT_HIGH, 0);
476823c35297Sanish
476923c35297Sanish pf_mem_size = 0;
477023c35297Sanish } else {
477123c35297Sanish /*
477223c35297Sanish * Reprogram the end of the PF memory range.
477323c35297Sanish */
477423c35297Sanish pci_config_put16(h, PCI_BCNF_PF_LIMIT_LOW,
477523c35297Sanish PCICFG_HIWORD(PCICFG_LOADDR(pf_mem_end - 1)));
477623c35297Sanish pci_config_put32(h, PCI_BCNF_PF_LIMIT_HIGH,
477723c35297Sanish PCICFG_HIADDR(pf_mem_end - 1));
477823c35297Sanish pf_mem_size = pf_mem_end - pf_mem_base;
477923c35297Sanish }
478023c35297Sanish }
478123c35297Sanish
478223c35297Sanish if ((max_bus - *highest_bus) > 0) {
478323c35297Sanish /*
478423c35297Sanish * Give back unused bus numbers
478523c35297Sanish */
478623c35297Sanish (void) ndi_ra_free(ddi_get_parent(new_child),
478723c35297Sanish *highest_bus+1, max_bus - *highest_bus,
478823c35297Sanish NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS);
478923c35297Sanish }
479023c35297Sanish
479123c35297Sanish /*
479223c35297Sanish * Set bus numbers to ranges encountered during scan
479323c35297Sanish */
479423c35297Sanish (void) pcicfg_set_bus_numbers(h, bus, new_bus, *highest_bus);
479523c35297Sanish
479623c35297Sanish /*
479723c35297Sanish * Remove the ranges property if it exists since we will create
479823c35297Sanish * a new one.
479923c35297Sanish */
480023c35297Sanish (void) ndi_prop_remove(DDI_DEV_T_NONE, new_child, "ranges");
480123c35297Sanish
480223c35297Sanish DEBUG2("Creating Ranges property - Mem Address %lx Mem Size %x\n",
480323c35297Sanish mem_base, mem_size);
480423c35297Sanish DEBUG2(" - I/O Address %lx I/O Size %x\n",
480523c35297Sanish io_base, io_size);
480623c35297Sanish DEBUG2(" - PF Mem address %lx PF Mem Size %x\n",
480723c35297Sanish pf_mem_base, pf_mem_size);
480823c35297Sanish
480923c35297Sanish bzero((caddr_t)range, sizeof (ppb_ranges_t) * PCICFG_RANGE_LEN);
481023c35297Sanish
481123c35297Sanish range[0].child_high = range[0].parent_high |= (PCI_REG_REL_M |
481223c35297Sanish PCI_ADDR_IO);
481323c35297Sanish range[0].child_low = range[0].parent_low = io_base;
481423c35297Sanish range[1].child_high = range[1].parent_high |=
481523c35297Sanish (PCI_REG_REL_M | PCI_ADDR_MEM32);
481623c35297Sanish range[1].child_low = range[1].parent_low = mem_base;
481723c35297Sanish range[2].child_high = range[2].parent_high |=
481823c35297Sanish (PCI_REG_REL_M | PCI_ADDR_MEM64 | PCI_REG_PF_M);
481923c35297Sanish range[2].child_low = range[2].parent_low = pf_mem_base;
482023c35297Sanish
482123c35297Sanish if (io_size > 0) {
482223c35297Sanish range[0].size_low = io_size;
482323c35297Sanish (void) pcicfg_update_ranges_prop(new_child, &range[0]);
482423c35297Sanish }
482523c35297Sanish if (mem_size > 0) {
482623c35297Sanish range[1].size_low = mem_size;
482723c35297Sanish (void) pcicfg_update_ranges_prop(new_child, &range[1]);
482823c35297Sanish }
482923c35297Sanish if (pf_mem_size > 0) {
483023c35297Sanish range[2].size_low = pf_mem_size;
483123c35297Sanish (void) pcicfg_update_ranges_prop(new_child, &range[2]);
483223c35297Sanish }
483323c35297Sanish
483423c35297Sanish bus_range[0] = pci_config_get8(h, PCI_BCNF_SECBUS);
483523c35297Sanish bus_range[1] = pci_config_get8(h, PCI_BCNF_SUBBUS);
483623c35297Sanish DEBUG1("End of bridge probe: bus_range[0] = %d\n", bus_range[0]);
483723c35297Sanish DEBUG1("End of bridge probe: bus_range[1] = %d\n", bus_range[1]);
483823c35297Sanish
483923c35297Sanish (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, new_child,
484023c35297Sanish "bus-range", bus_range, 2);
484123c35297Sanish
484223c35297Sanish rval = PCICFG_SUCCESS;
484323c35297Sanish
484423c35297Sanish PCICFG_DUMP_BRIDGE_CONFIG(h);
484523c35297Sanish
484623c35297Sanish cleanup:
484723c35297Sanish /* free up resources (for error return case only) */
484823c35297Sanish if (rval != PCICFG_SUCCESS) {
484923c35297Sanish if (mem_alen)
485023c35297Sanish (void) ndi_ra_free(ddi_get_parent(new_child), mem_base,
485123c35297Sanish mem_alen, NDI_RA_TYPE_MEM, NDI_RA_PASS);
485223c35297Sanish if (io_alen)
485323c35297Sanish (void) ndi_ra_free(ddi_get_parent(new_child), io_base,
485423c35297Sanish io_alen, NDI_RA_TYPE_IO, NDI_RA_PASS);
485523c35297Sanish if (pf_mem_alen)
485626947304SEvan Yan (void) ndi_ra_free(ddi_get_parent(new_child),
485726947304SEvan Yan pf_mem_base, pf_mem_alen,
485826947304SEvan Yan NDI_RA_TYPE_PCI_PREFETCH_MEM, NDI_RA_PASS);
485923c35297Sanish if (pcibus_alen)
486026947304SEvan Yan (void) ndi_ra_free(ddi_get_parent(new_child),
486126947304SEvan Yan pcibus_base, pcibus_alen, NDI_RA_TYPE_PCI_BUSNUM,
486226947304SEvan Yan NDI_RA_PASS);
486323c35297Sanish }
486423c35297Sanish
486523c35297Sanish /* free up any resource maps setup for the bridge node */
486623c35297Sanish (void) ndi_ra_map_destroy(new_child, NDI_RA_TYPE_PCI_BUSNUM);
486723c35297Sanish (void) ndi_ra_map_destroy(new_child, NDI_RA_TYPE_IO);
486823c35297Sanish (void) ndi_ra_map_destroy(new_child, NDI_RA_TYPE_MEM);
486923c35297Sanish (void) ndi_ra_map_destroy(new_child, NDI_RA_TYPE_PCI_PREFETCH_MEM);
487023c35297Sanish
487123c35297Sanish return (rval);
487223c35297Sanish }
487323c35297Sanish
487423c35297Sanish static int
pcicfg_find_resource_end(dev_info_t * dip,void * hdl)487523c35297Sanish pcicfg_find_resource_end(dev_info_t *dip, void *hdl)
487623c35297Sanish {
487723c35297Sanish pcicfg_phdl_t *entry = (pcicfg_phdl_t *)hdl;
487823c35297Sanish pci_regspec_t *pci_ap;
487923c35297Sanish int length;
488023c35297Sanish int rcount;
488123c35297Sanish int i;
488223c35297Sanish
488323c35297Sanish entry->error = PCICFG_SUCCESS;
488423c35297Sanish
488523c35297Sanish if (dip == entry->dip) {
488623c35297Sanish DEBUG0("Don't include parent bridge node\n");
488723c35297Sanish return (DDI_WALK_CONTINUE);
488823c35297Sanish } else {
488923c35297Sanish if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
489023c35297Sanish DDI_PROP_DONTPASS, "assigned-addresses",
489123c35297Sanish (caddr_t)&pci_ap, &length) != DDI_PROP_SUCCESS) {
489223c35297Sanish DEBUG0("Node doesn't have assigned-addresses\n");
489323c35297Sanish return (DDI_WALK_CONTINUE);
489423c35297Sanish }
489523c35297Sanish
489623c35297Sanish rcount = length / sizeof (pci_regspec_t);
489723c35297Sanish
489823c35297Sanish for (i = 0; i < rcount; i++) {
489923c35297Sanish
490023c35297Sanish switch (PCI_REG_ADDR_G(pci_ap[i].pci_phys_hi)) {
490123c35297Sanish
490223c35297Sanish case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
490323c35297Sanish if (pci_ap[i].pci_phys_hi & PCI_REG_PF_M) {
490423c35297Sanish if ((pci_ap[i].pci_phys_low +
490523c35297Sanish pci_ap[i].pci_size_low) >
490623c35297Sanish entry->pf_memory_base) {
490723c35297Sanish entry->pf_memory_base =
490823c35297Sanish pci_ap[i].pci_phys_low +
490923c35297Sanish pci_ap[i].pci_size_low;
491023c35297Sanish }
491123c35297Sanish } else {
491223c35297Sanish if ((pci_ap[i].pci_phys_low +
491323c35297Sanish pci_ap[i].pci_size_low) >
491423c35297Sanish entry->memory_base) {
491523c35297Sanish entry->memory_base =
491623c35297Sanish pci_ap[i].pci_phys_low +
491723c35297Sanish pci_ap[i].pci_size_low;
491823c35297Sanish }
491923c35297Sanish }
492023c35297Sanish break;
492123c35297Sanish case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
492223c35297Sanish if (pci_ap[i].pci_phys_hi & PCI_REG_PF_M) {
492326947304SEvan Yan if ((PCICFG_LADDR(
492426947304SEvan Yan pci_ap[i].pci_phys_low,
492523c35297Sanish pci_ap[i].pci_phys_mid) +
492623c35297Sanish pci_ap[i].pci_size_low) >
492723c35297Sanish entry->pf_memory_base) {
492826947304SEvan Yan entry->pf_memory_base =
492926947304SEvan Yan PCICFG_LADDR(
493023c35297Sanish pci_ap[i].pci_phys_low,
493123c35297Sanish pci_ap[i].pci_phys_mid) +
493223c35297Sanish pci_ap[i].pci_size_low;
493323c35297Sanish }
493423c35297Sanish } else {
493526947304SEvan Yan if ((PCICFG_LADDR(
493626947304SEvan Yan pci_ap[i].pci_phys_low,
493723c35297Sanish pci_ap[i].pci_phys_mid) +
493823c35297Sanish pci_ap[i].pci_size_low) >
493923c35297Sanish entry->memory_base) {
494026947304SEvan Yan entry->memory_base =
494126947304SEvan Yan PCICFG_LADDR(
494223c35297Sanish pci_ap[i].pci_phys_low,
494323c35297Sanish pci_ap[i].pci_phys_mid) +
494423c35297Sanish pci_ap[i].pci_size_low;
494523c35297Sanish }
494623c35297Sanish }
494723c35297Sanish break;
494823c35297Sanish case PCI_REG_ADDR_G(PCI_ADDR_IO):
494923c35297Sanish if ((pci_ap[i].pci_phys_low +
495023c35297Sanish pci_ap[i].pci_size_low) >
495123c35297Sanish entry->io_base) {
495223c35297Sanish entry->io_base =
495323c35297Sanish pci_ap[i].pci_phys_low +
495423c35297Sanish pci_ap[i].pci_size_low;
495523c35297Sanish }
495623c35297Sanish break;
495723c35297Sanish }
495823c35297Sanish }
495923c35297Sanish
496023c35297Sanish /*
496123c35297Sanish * free the memory allocated by ddi_getlongprop
496223c35297Sanish */
496323c35297Sanish kmem_free(pci_ap, length);
496423c35297Sanish
496523c35297Sanish /*
496623c35297Sanish * continue the walk to the next sibling to sum memory
496723c35297Sanish */
496823c35297Sanish return (DDI_WALK_CONTINUE);
496923c35297Sanish }
497023c35297Sanish }
497123c35297Sanish
497223c35297Sanish /*
497323c35297Sanish * Make "parent" be the parent of the "child" dip
497423c35297Sanish */
497523c35297Sanish static void
pcicfg_reparent_node(dev_info_t * child,dev_info_t * parent)497623c35297Sanish pcicfg_reparent_node(dev_info_t *child, dev_info_t *parent)
497723c35297Sanish {
497823c35297Sanish int circ;
497923c35297Sanish dev_info_t *opdip;
498023c35297Sanish
498123c35297Sanish ASSERT(i_ddi_node_state(child) <= DS_LINKED);
498223c35297Sanish /*
498323c35297Sanish * Unlink node from tree before reparenting
498423c35297Sanish */
498523c35297Sanish opdip = ddi_get_parent(child);
498623c35297Sanish ndi_devi_enter(opdip, &circ);
498723c35297Sanish (void) i_ndi_unconfig_node(child, DS_PROTO, 0);
498823c35297Sanish ndi_devi_exit(opdip, circ);
498923c35297Sanish
499023c35297Sanish DEVI(child)->devi_parent = DEVI(parent);
499123c35297Sanish DEVI(child)->devi_bus_ctl = DEVI(parent);
499223c35297Sanish (void) ndi_devi_bind_driver(child, 0);
499323c35297Sanish }
499423c35297Sanish
499523c35297Sanish /*
499623c35297Sanish * Return PCICFG_SUCCESS if device exists at the specified address.
499723c35297Sanish * Return PCICFG_NODEVICE is no device exists at the specified address.
499823c35297Sanish */
499923c35297Sanish int
pcicfg_config_setup(dev_info_t * dip,ddi_acc_handle_t * handle)500023c35297Sanish pcicfg_config_setup(dev_info_t *dip, ddi_acc_handle_t *handle)
500123c35297Sanish {
500223c35297Sanish caddr_t cfgaddr;
500323c35297Sanish ddi_device_acc_attr_t attr;
500423c35297Sanish dev_info_t *anode;
500523c35297Sanish int status;
500623c35297Sanish int rlen;
500723c35297Sanish pci_regspec_t *reg;
500823c35297Sanish int ret = DDI_SUCCESS;
500923c35297Sanish int16_t tmp;
501023c35297Sanish
501123c35297Sanish /*
501223c35297Sanish * Get the pci register spec from the node
501323c35297Sanish */
501426947304SEvan Yan status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg",
501526947304SEvan Yan (caddr_t)®, &rlen);
501623c35297Sanish
501723c35297Sanish switch (status) {
501823c35297Sanish case DDI_PROP_SUCCESS:
501923c35297Sanish break;
502023c35297Sanish case DDI_PROP_NO_MEMORY:
502123c35297Sanish DEBUG0("reg present, but unable to get memory\n");
502223c35297Sanish return (PCICFG_FAILURE);
502323c35297Sanish default:
502423c35297Sanish DEBUG0("no reg property\n");
502523c35297Sanish return (PCICFG_FAILURE);
502623c35297Sanish }
502723c35297Sanish
502823c35297Sanish anode = dip;
502923c35297Sanish DEBUG2("conf_map: dip=%p, anode=%p\n", dip, anode);
503023c35297Sanish
503123c35297Sanish attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
503223c35297Sanish attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
503323c35297Sanish attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
503423c35297Sanish
503526947304SEvan Yan if (ddi_regs_map_setup(anode, 0, &cfgaddr, 0, 0, &attr, handle)
503626947304SEvan Yan != DDI_SUCCESS) {
503723c35297Sanish DEBUG0("Failed to setup registers\n");
503823c35297Sanish kmem_free((caddr_t)reg, rlen);
503923c35297Sanish return (PCICFG_FAILURE);
504023c35297Sanish }
504123c35297Sanish
504223c35297Sanish /*
504323c35297Sanish * need to use DDI interfaces as the conf space is
504423c35297Sanish * cannot be directly accessed by the host.
504523c35297Sanish */
504623c35297Sanish tmp = (int16_t)ddi_get16(*handle, (uint16_t *)cfgaddr);
504723c35297Sanish if ((tmp == (int16_t)0xffff) || (tmp == -1)) {
504823c35297Sanish DEBUG1("NO DEVICEFOUND, read %x\n", tmp);
504923c35297Sanish ret = PCICFG_NODEVICE;
505023c35297Sanish } else {
505123c35297Sanish if (tmp == 0) {
505223c35297Sanish DEBUG0("Device Not Ready yet ?");
505323c35297Sanish ret = PCICFG_NODEVICE;
505423c35297Sanish } else {
505523c35297Sanish DEBUG1("DEVICEFOUND, read %x\n", tmp);
505623c35297Sanish ret = PCICFG_SUCCESS;
505723c35297Sanish }
505823c35297Sanish }
505923c35297Sanish
506023c35297Sanish if (ret == PCICFG_NODEVICE)
506123c35297Sanish ddi_regs_map_free(handle);
506223c35297Sanish kmem_free((caddr_t)reg, rlen);
506323c35297Sanish
506423c35297Sanish return (ret);
506523c35297Sanish
506623c35297Sanish }
506723c35297Sanish
506823c35297Sanish static void
pcicfg_config_teardown(ddi_acc_handle_t * handle)506923c35297Sanish pcicfg_config_teardown(ddi_acc_handle_t *handle)
507023c35297Sanish {
507123c35297Sanish (void) ddi_regs_map_free(handle);
507223c35297Sanish }
507323c35297Sanish
507423c35297Sanish static int
pcicfg_add_config_reg(dev_info_t * dip,uint_t bus,uint_t device,uint_t func)507523c35297Sanish pcicfg_add_config_reg(dev_info_t *dip,
507623c35297Sanish uint_t bus, uint_t device, uint_t func)
507723c35297Sanish {
507823c35297Sanish int reg[10] = { PCI_ADDR_CONFIG, 0, 0, 0, 0};
507923c35297Sanish
508023c35297Sanish reg[0] = PCICFG_MAKE_REG_HIGH(bus, device, func, 0);
508123c35297Sanish
508226947304SEvan Yan return (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "reg", reg, 5));
508323c35297Sanish }
508423c35297Sanish
508526947304SEvan Yan static int
pcicfg_ari_configure(dev_info_t * dip)508626947304SEvan Yan pcicfg_ari_configure(dev_info_t *dip)
508726947304SEvan Yan {
508826947304SEvan Yan if (pcie_ari_supported(dip) == PCIE_ARI_FORW_NOT_SUPPORTED)
508926947304SEvan Yan return (DDI_FAILURE);
509026947304SEvan Yan
509126947304SEvan Yan /*
509226947304SEvan Yan * Until we have resource balancing, dynamically configure
509326947304SEvan Yan * ARI functions without firmware assistamce.
509426947304SEvan Yan */
509526947304SEvan Yan return (DDI_FAILURE);
509626947304SEvan Yan }
509726947304SEvan Yan
509826947304SEvan Yan
509923c35297Sanish #ifdef DEBUG
510023c35297Sanish static void
debug(char * fmt,uintptr_t a1,uintptr_t a2,uintptr_t a3,uintptr_t a4,uintptr_t a5)510123c35297Sanish debug(char *fmt, uintptr_t a1, uintptr_t a2, uintptr_t a3,
510223c35297Sanish uintptr_t a4, uintptr_t a5)
510323c35297Sanish {
510423c35297Sanish if (pcicfg_debug > 1) {
510523c35297Sanish prom_printf("pcicfg: ");
510623c35297Sanish prom_printf(fmt, a1, a2, a3, a4, a5);
510723c35297Sanish }
510823c35297Sanish }
510923c35297Sanish #endif
511023c35297Sanish
511123c35297Sanish /*ARGSUSED*/
511223c35297Sanish static uint8_t
pcicfg_get_nslots(dev_info_t * dip,ddi_acc_handle_t handle)511323c35297Sanish pcicfg_get_nslots(dev_info_t *dip, ddi_acc_handle_t handle)
511423c35297Sanish {
511549fbdd30SErwin T Tsaur uint16_t cap_id_loc, slot_id_loc;
511623c35297Sanish uint8_t num_slots = 0;
511723c35297Sanish
511823c35297Sanish /* just depend on the pcie_cap for now. */
511949fbdd30SErwin T Tsaur (void) PCI_CAP_LOCATE(handle, PCI_CAP_ID_PCI_E, &cap_id_loc);
512049fbdd30SErwin T Tsaur (void) PCI_CAP_LOCATE(handle, PCI_CAP_ID_SLOT_ID, &slot_id_loc);
512149fbdd30SErwin T Tsaur if (cap_id_loc != PCI_CAP_NEXT_PTR_NULL) {
512226947304SEvan Yan if (pci_config_get8(handle, cap_id_loc + PCI_CAP_ID_REGS_OFF) &
512323c35297Sanish PCIE_PCIECAP_SLOT_IMPL)
512423c35297Sanish num_slots = 1;
512523c35297Sanish } else /* not a PCIe switch/bridge. Must be a PCI-PCI[-X] bridge */
512649fbdd30SErwin T Tsaur if (slot_id_loc != PCI_CAP_NEXT_PTR_NULL) {
512749fbdd30SErwin T Tsaur uint8_t esr_reg = pci_config_get8(handle, slot_id_loc + 2);
512823c35297Sanish num_slots = PCI_CAPSLOT_NSLOTS(esr_reg);
512923c35297Sanish }
513023c35297Sanish /* XXX - need to cover PCI-PCIe bridge with n slots */
513123c35297Sanish return (num_slots);
513223c35297Sanish }
513323c35297Sanish
513423c35297Sanish /*ARGSUSED*/
513523c35297Sanish static int
pcicfg_pcie_dev(dev_info_t * dip,ddi_acc_handle_t handle)513623c35297Sanish pcicfg_pcie_dev(dev_info_t *dip, ddi_acc_handle_t handle)
513723c35297Sanish {
513823c35297Sanish /* get parent device's device_type property */
513923c35297Sanish char *device_type;
514023c35297Sanish int val;
514123c35297Sanish dev_info_t *pdip = ddi_get_parent(dip);
514223c35297Sanish
514326947304SEvan Yan if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS,
514426947304SEvan Yan "device_type", &device_type) != DDI_PROP_SUCCESS) {
514523c35297Sanish DEBUG2("device_type property missing for %s#%d",
514623c35297Sanish ddi_get_name(pdip), ddi_get_instance(pdip));
514723c35297Sanish return (DDI_FAILURE);
514823c35297Sanish }
514923c35297Sanish DEBUG1("device_type=<%s>\n", device_type);
515023c35297Sanish
515123c35297Sanish val = DDI_FAILURE;
515223c35297Sanish if (strcmp(device_type, "pciex") == 0)
515323c35297Sanish val = DDI_SUCCESS;
515423c35297Sanish ddi_prop_free(device_type);
515523c35297Sanish return (val);
515623c35297Sanish }
515723c35297Sanish
515823c35297Sanish static int
pcicfg_pcie_device_type(dev_info_t * dip,ddi_acc_handle_t handle)515923c35297Sanish pcicfg_pcie_device_type(dev_info_t *dip, ddi_acc_handle_t handle)
516023c35297Sanish {
516123c35297Sanish int port_type = pcicfg_pcie_port_type(dip, handle);
516223c35297Sanish
516323c35297Sanish DEBUG1("device port_type = %x\n", port_type);
516423c35297Sanish /* No PCIe CAP regs, we are not PCIe device_type */
516523c35297Sanish if (port_type < 0)
516623c35297Sanish return (DDI_FAILURE);
516723c35297Sanish
516823c35297Sanish /* check for all PCIe device_types */
516923c35297Sanish if ((port_type == PCIE_PCIECAP_DEV_TYPE_UP) ||
517023c35297Sanish (port_type == PCIE_PCIECAP_DEV_TYPE_DOWN) ||
517123c35297Sanish (port_type == PCIE_PCIECAP_DEV_TYPE_ROOT) ||
517223c35297Sanish (port_type == PCIE_PCIECAP_DEV_TYPE_PCI2PCIE))
517323c35297Sanish return (DDI_SUCCESS);
517423c35297Sanish
517523c35297Sanish return (DDI_FAILURE);
517623c35297Sanish
517723c35297Sanish }
517823c35297Sanish
517923c35297Sanish /*ARGSUSED*/
518023c35297Sanish static int
pcicfg_pcie_port_type(dev_info_t * dip,ddi_acc_handle_t handle)518123c35297Sanish pcicfg_pcie_port_type(dev_info_t *dip, ddi_acc_handle_t handle)
518223c35297Sanish {
518323c35297Sanish int port_type = -1;
518449fbdd30SErwin T Tsaur uint16_t cap_loc;
518523c35297Sanish
518623c35297Sanish /* Note: need to look at the port type information here */
518749fbdd30SErwin T Tsaur (void) PCI_CAP_LOCATE(handle, PCI_CAP_ID_PCI_E, &cap_loc);
518849fbdd30SErwin T Tsaur if (cap_loc != PCI_CAP_NEXT_PTR_NULL)
518923c35297Sanish port_type = pci_config_get16(handle,
519023c35297Sanish cap_loc + PCIE_PCIECAP) & PCIE_PCIECAP_DEV_TYPE_MASK;
519123c35297Sanish
519223c35297Sanish return (port_type);
519323c35297Sanish }
5194c0da6274SZhi-Jun Robin Fu
5195c0da6274SZhi-Jun Robin Fu /*
5196c0da6274SZhi-Jun Robin Fu * Return true if the devinfo node is in a PCI Express hierarchy.
5197c0da6274SZhi-Jun Robin Fu */
5198c0da6274SZhi-Jun Robin Fu static boolean_t
is_pcie_fabric(dev_info_t * dip)5199c0da6274SZhi-Jun Robin Fu is_pcie_fabric(dev_info_t *dip)
5200c0da6274SZhi-Jun Robin Fu {
5201c0da6274SZhi-Jun Robin Fu dev_info_t *root = ddi_root_node();
5202c0da6274SZhi-Jun Robin Fu dev_info_t *pdip;
5203c0da6274SZhi-Jun Robin Fu boolean_t found = B_FALSE;
5204c0da6274SZhi-Jun Robin Fu char *bus;
5205c0da6274SZhi-Jun Robin Fu
5206c0da6274SZhi-Jun Robin Fu /*
5207c0da6274SZhi-Jun Robin Fu * Does this device reside in a pcie fabric ?
5208c0da6274SZhi-Jun Robin Fu */
5209c0da6274SZhi-Jun Robin Fu for (pdip = dip; pdip && (pdip != root) && !found;
5210c0da6274SZhi-Jun Robin Fu pdip = ddi_get_parent(pdip)) {
5211c0da6274SZhi-Jun Robin Fu if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip,
5212c0da6274SZhi-Jun Robin Fu DDI_PROP_DONTPASS, "device_type", &bus) !=
5213c0da6274SZhi-Jun Robin Fu DDI_PROP_SUCCESS)
5214c0da6274SZhi-Jun Robin Fu break;
5215c0da6274SZhi-Jun Robin Fu
5216c0da6274SZhi-Jun Robin Fu if (strcmp(bus, "pciex") == 0)
5217c0da6274SZhi-Jun Robin Fu found = B_TRUE;
5218c0da6274SZhi-Jun Robin Fu
5219c0da6274SZhi-Jun Robin Fu ddi_prop_free(bus);
5220c0da6274SZhi-Jun Robin Fu }
5221c0da6274SZhi-Jun Robin Fu
5222c0da6274SZhi-Jun Robin Fu return (found);
5223c0da6274SZhi-Jun Robin Fu }
5224