110923SEvan.Yan@Sun.COM /*
210923SEvan.Yan@Sun.COM * CDDL HEADER START
310923SEvan.Yan@Sun.COM *
410923SEvan.Yan@Sun.COM * The contents of this file are subject to the terms of the
510923SEvan.Yan@Sun.COM * Common Development and Distribution License (the "License").
610923SEvan.Yan@Sun.COM * You may not use this file except in compliance with the License.
710923SEvan.Yan@Sun.COM *
810923SEvan.Yan@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
910923SEvan.Yan@Sun.COM * or http://www.opensolaris.org/os/licensing.
1010923SEvan.Yan@Sun.COM * See the License for the specific language governing permissions
1110923SEvan.Yan@Sun.COM * and limitations under the License.
1210923SEvan.Yan@Sun.COM *
1310923SEvan.Yan@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
1410923SEvan.Yan@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1510923SEvan.Yan@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
1610923SEvan.Yan@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
1710923SEvan.Yan@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
1810923SEvan.Yan@Sun.COM *
1910923SEvan.Yan@Sun.COM * CDDL HEADER END
2010923SEvan.Yan@Sun.COM */
2110923SEvan.Yan@Sun.COM /*
2212622SAlan.Adamson@Sun.COM * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
2310923SEvan.Yan@Sun.COM */
2410923SEvan.Yan@Sun.COM
2510923SEvan.Yan@Sun.COM /*
2610923SEvan.Yan@Sun.COM * PCI configurator (pcicfg)
2710923SEvan.Yan@Sun.COM */
2810923SEvan.Yan@Sun.COM
2910923SEvan.Yan@Sun.COM #include <sys/isa_defs.h>
3010923SEvan.Yan@Sun.COM
3110923SEvan.Yan@Sun.COM #include <sys/conf.h>
3210923SEvan.Yan@Sun.COM #include <sys/kmem.h>
3310923SEvan.Yan@Sun.COM #include <sys/debug.h>
3410923SEvan.Yan@Sun.COM #include <sys/modctl.h>
3510923SEvan.Yan@Sun.COM #include <sys/autoconf.h>
3610923SEvan.Yan@Sun.COM #include <sys/hwconf.h>
3710923SEvan.Yan@Sun.COM #include <sys/ddi_impldefs.h>
3810923SEvan.Yan@Sun.COM #include <sys/fcode.h>
3910923SEvan.Yan@Sun.COM #include <sys/pci.h>
4010923SEvan.Yan@Sun.COM #include <sys/pcie.h>
4110923SEvan.Yan@Sun.COM #include <sys/pcie_impl.h>
4210923SEvan.Yan@Sun.COM #include <sys/ddi.h>
4310923SEvan.Yan@Sun.COM #include <sys/sunddi.h>
4410923SEvan.Yan@Sun.COM #include <sys/sunndi.h>
4510923SEvan.Yan@Sun.COM #include <sys/pci_cap.h>
4610923SEvan.Yan@Sun.COM #include <sys/hotplug/pci/pcicfg.h>
4710923SEvan.Yan@Sun.COM #include <sys/ndi_impldefs.h>
4811245SZhijun.Fu@Sun.COM #include <sys/pci_cfgacc.h>
4910923SEvan.Yan@Sun.COM
5010923SEvan.Yan@Sun.COM #define PCICFG_DEVICE_TYPE_PCI 1
5110923SEvan.Yan@Sun.COM #define PCICFG_DEVICE_TYPE_PCIE 2
5210923SEvan.Yan@Sun.COM
5310923SEvan.Yan@Sun.COM #define EFCODE21554 /* changes for supporting 21554 */
5410923SEvan.Yan@Sun.COM
5510923SEvan.Yan@Sun.COM static int pcicfg_alloc_resource(dev_info_t *, pci_regspec_t);
5610923SEvan.Yan@Sun.COM static int pcicfg_free_resource(dev_info_t *, pci_regspec_t, pcicfg_flags_t);
5710923SEvan.Yan@Sun.COM static int pcicfg_remove_assigned_prop(dev_info_t *, pci_regspec_t *);
5810923SEvan.Yan@Sun.COM
5910923SEvan.Yan@Sun.COM #ifdef PCICFG_INTERPRET_FCODE
6010923SEvan.Yan@Sun.COM static int pcicfg_fcode_assign_bars(ddi_acc_handle_t, dev_info_t *,
6110923SEvan.Yan@Sun.COM uint_t, uint_t, uint_t, int32_t, pci_regspec_t *);
6210923SEvan.Yan@Sun.COM #endif /* PCICFG_INTERPRET_FCODE */
6310923SEvan.Yan@Sun.COM
6410923SEvan.Yan@Sun.COM /*
6510923SEvan.Yan@Sun.COM * ************************************************************************
6610923SEvan.Yan@Sun.COM * *** Implementation specific local data structures/definitions. ***
6710923SEvan.Yan@Sun.COM * ************************************************************************
6810923SEvan.Yan@Sun.COM */
6910923SEvan.Yan@Sun.COM
7010923SEvan.Yan@Sun.COM static int pcicfg_start_devno = 0; /* for Debug only */
7110923SEvan.Yan@Sun.COM
7210923SEvan.Yan@Sun.COM #define PCICFG_MAX_DEVICE 32
7310923SEvan.Yan@Sun.COM #define PCICFG_MAX_FUNCTION 8
7410923SEvan.Yan@Sun.COM #define PCICFG_MAX_ARI_FUNCTION 256
7510923SEvan.Yan@Sun.COM #define PCICFG_MAX_REGISTER 64
7610923SEvan.Yan@Sun.COM #define PCICFG_MAX_BUS_DEPTH 255
7710923SEvan.Yan@Sun.COM
7810923SEvan.Yan@Sun.COM #define PCICFG_NODEVICE 42
7910923SEvan.Yan@Sun.COM #define PCICFG_NOMEMORY 43
8010923SEvan.Yan@Sun.COM #define PCICFG_NOMULTI 44
8110923SEvan.Yan@Sun.COM
8210923SEvan.Yan@Sun.COM #define PCICFG_HIADDR(n) ((uint32_t)(((uint64_t)(n) & 0xFFFFFFFF00000000)>> 32))
8310923SEvan.Yan@Sun.COM #define PCICFG_LOADDR(n) ((uint32_t)((uint64_t)(n) & 0x00000000FFFFFFFF))
8410923SEvan.Yan@Sun.COM #define PCICFG_LADDR(lo, hi) (((uint64_t)(hi) << 32) | (uint32_t)(lo))
8510923SEvan.Yan@Sun.COM
8610923SEvan.Yan@Sun.COM #define PCICFG_HIWORD(n) ((uint16_t)(((uint32_t)(n) & 0xFFFF0000)>> 16))
8710923SEvan.Yan@Sun.COM #define PCICFG_LOWORD(n) ((uint16_t)((uint32_t)(n) & 0x0000FFFF))
8810923SEvan.Yan@Sun.COM #define PCICFG_HIBYTE(n) ((uint8_t)(((uint16_t)(n) & 0xFF00)>> 8))
8910923SEvan.Yan@Sun.COM #define PCICFG_LOBYTE(n) ((uint8_t)((uint16_t)(n) & 0x00FF))
9010923SEvan.Yan@Sun.COM
9110923SEvan.Yan@Sun.COM #define PCICFG_ROUND_UP(addr, gran) ((uintptr_t)((gran+addr-1)&(~(gran-1))))
9210923SEvan.Yan@Sun.COM #define PCICFG_ROUND_DOWN(addr, gran) ((uintptr_t)((addr) & ~(gran-1)))
9310923SEvan.Yan@Sun.COM
9410923SEvan.Yan@Sun.COM #define PCICFG_MEMGRAN 0x100000
9510923SEvan.Yan@Sun.COM #define PCICFG_IOGRAN 0x1000
9610923SEvan.Yan@Sun.COM #define PCICFG_4GIG_LIMIT 0xFFFFFFFFUL
9710923SEvan.Yan@Sun.COM
9810923SEvan.Yan@Sun.COM #define PCICFG_MEM_MULT 4
9910923SEvan.Yan@Sun.COM #define PCICFG_IO_MULT 4
10010923SEvan.Yan@Sun.COM #define PCICFG_RANGE_LEN 2 /* Number of range entries */
10110923SEvan.Yan@Sun.COM
10210923SEvan.Yan@Sun.COM static int pcicfg_slot_busnums = 8;
10310923SEvan.Yan@Sun.COM static int pcicfg_slot_memsize = 32 * PCICFG_MEMGRAN; /* 32MB per slot */
10410923SEvan.Yan@Sun.COM static int pcicfg_slot_iosize = 16 * PCICFG_IOGRAN; /* 64K per slot */
10510923SEvan.Yan@Sun.COM static int pcicfg_chassis_per_tree = 1;
10610923SEvan.Yan@Sun.COM static int pcicfg_sec_reset_delay = 1000000;
10710923SEvan.Yan@Sun.COM
10810923SEvan.Yan@Sun.COM /*
10910923SEvan.Yan@Sun.COM * The following typedef is used to represent a
11010923SEvan.Yan@Sun.COM * 1275 "bus-range" property of a PCI Bus node.
11110923SEvan.Yan@Sun.COM * DAF - should be in generic include file...
11210923SEvan.Yan@Sun.COM */
11310923SEvan.Yan@Sun.COM
11410923SEvan.Yan@Sun.COM typedef struct pcicfg_bus_range {
11510923SEvan.Yan@Sun.COM uint32_t lo;
11610923SEvan.Yan@Sun.COM uint32_t hi;
11710923SEvan.Yan@Sun.COM } pcicfg_bus_range_t;
11810923SEvan.Yan@Sun.COM
11910923SEvan.Yan@Sun.COM typedef struct pcicfg_range {
12010923SEvan.Yan@Sun.COM
12110923SEvan.Yan@Sun.COM uint32_t child_hi;
12210923SEvan.Yan@Sun.COM uint32_t child_mid;
12310923SEvan.Yan@Sun.COM uint32_t child_lo;
12410923SEvan.Yan@Sun.COM uint32_t parent_hi;
12510923SEvan.Yan@Sun.COM uint32_t parent_mid;
12610923SEvan.Yan@Sun.COM uint32_t parent_lo;
12710923SEvan.Yan@Sun.COM uint32_t size_hi;
12810923SEvan.Yan@Sun.COM uint32_t size_lo;
12910923SEvan.Yan@Sun.COM
13010923SEvan.Yan@Sun.COM } pcicfg_range_t;
13110923SEvan.Yan@Sun.COM
13210923SEvan.Yan@Sun.COM typedef struct hole hole_t;
13310923SEvan.Yan@Sun.COM
13410923SEvan.Yan@Sun.COM struct hole {
13510923SEvan.Yan@Sun.COM uint64_t start;
13610923SEvan.Yan@Sun.COM uint64_t len;
13710923SEvan.Yan@Sun.COM hole_t *next;
13810923SEvan.Yan@Sun.COM };
13910923SEvan.Yan@Sun.COM
14010923SEvan.Yan@Sun.COM typedef struct pcicfg_phdl pcicfg_phdl_t;
14110923SEvan.Yan@Sun.COM
14210923SEvan.Yan@Sun.COM struct pcicfg_phdl {
14310923SEvan.Yan@Sun.COM
14410923SEvan.Yan@Sun.COM dev_info_t *dip; /* Associated with the attach point */
14510923SEvan.Yan@Sun.COM pcicfg_phdl_t *next;
14610923SEvan.Yan@Sun.COM
14710923SEvan.Yan@Sun.COM uint64_t memory_base; /* Memory base for this attach point */
14810923SEvan.Yan@Sun.COM uint64_t memory_last;
14910923SEvan.Yan@Sun.COM uint64_t memory_len;
15010923SEvan.Yan@Sun.COM uint32_t io_base; /* I/O base for this attach point */
15110923SEvan.Yan@Sun.COM uint32_t io_last;
15210923SEvan.Yan@Sun.COM uint32_t io_len;
15310923SEvan.Yan@Sun.COM
15410923SEvan.Yan@Sun.COM int error;
15510923SEvan.Yan@Sun.COM uint_t highest_bus; /* Highest bus seen on the probe */
15610923SEvan.Yan@Sun.COM
15710923SEvan.Yan@Sun.COM hole_t mem_hole; /* Memory hole linked list. */
15810923SEvan.Yan@Sun.COM hole_t io_hole; /* IO hole linked list */
15910923SEvan.Yan@Sun.COM
16010923SEvan.Yan@Sun.COM ndi_ra_request_t mem_req; /* allocator request for memory */
16110923SEvan.Yan@Sun.COM ndi_ra_request_t io_req; /* allocator request for I/O */
16210923SEvan.Yan@Sun.COM };
16310923SEvan.Yan@Sun.COM
16410923SEvan.Yan@Sun.COM struct pcicfg_standard_prop_entry {
16510923SEvan.Yan@Sun.COM uchar_t *name;
16610923SEvan.Yan@Sun.COM uint_t config_offset;
16710923SEvan.Yan@Sun.COM uint_t size;
16810923SEvan.Yan@Sun.COM };
16910923SEvan.Yan@Sun.COM
17010923SEvan.Yan@Sun.COM
17110923SEvan.Yan@Sun.COM struct pcicfg_name_entry {
17210923SEvan.Yan@Sun.COM uint32_t class_code;
17310923SEvan.Yan@Sun.COM char *name;
17410923SEvan.Yan@Sun.COM };
17510923SEvan.Yan@Sun.COM
17610923SEvan.Yan@Sun.COM struct pcicfg_find_ctrl {
17710923SEvan.Yan@Sun.COM uint_t device;
17810923SEvan.Yan@Sun.COM uint_t function;
17910923SEvan.Yan@Sun.COM dev_info_t *dip;
18010923SEvan.Yan@Sun.COM };
18110923SEvan.Yan@Sun.COM
18210923SEvan.Yan@Sun.COM typedef struct pcicfg_err_regs {
18310923SEvan.Yan@Sun.COM uint16_t cmd;
18410923SEvan.Yan@Sun.COM uint16_t bcntl;
18510923SEvan.Yan@Sun.COM uint16_t pcie_dev;
18610923SEvan.Yan@Sun.COM uint16_t devctl;
18710923SEvan.Yan@Sun.COM uint16_t pcie_cap_off;
18810923SEvan.Yan@Sun.COM } pcicfg_err_regs_t;
18910923SEvan.Yan@Sun.COM
19010923SEvan.Yan@Sun.COM /*
19110923SEvan.Yan@Sun.COM * List of Indirect Config Map Devices. At least the intent of the
19210923SEvan.Yan@Sun.COM * design is to look for a device in this list during the configure
19310923SEvan.Yan@Sun.COM * operation, and if the device is listed here, then it is a nontransparent
19410923SEvan.Yan@Sun.COM * bridge, hence load the driver and avail the config map services from
19510923SEvan.Yan@Sun.COM * the driver. Class and Subclass should be as defined in the PCI specs
19610923SEvan.Yan@Sun.COM * ie. class is 0x6, and subclass is 0x9.
19710923SEvan.Yan@Sun.COM */
19810923SEvan.Yan@Sun.COM static struct {
19910923SEvan.Yan@Sun.COM uint8_t mem_range_bar_offset;
20010923SEvan.Yan@Sun.COM uint8_t io_range_bar_offset;
20110923SEvan.Yan@Sun.COM uint8_t prefetch_mem_range_bar_offset;
20210923SEvan.Yan@Sun.COM } pcicfg_indirect_map_devs[] = {
20310923SEvan.Yan@Sun.COM PCI_CONF_BASE3, PCI_CONF_BASE2, PCI_CONF_BASE3,
20410923SEvan.Yan@Sun.COM 0, 0, 0,
20510923SEvan.Yan@Sun.COM };
20610923SEvan.Yan@Sun.COM
20710923SEvan.Yan@Sun.COM #define PCICFG_MAKE_REG_HIGH(busnum, devnum, funcnum, register)\
20810923SEvan.Yan@Sun.COM (\
20910923SEvan.Yan@Sun.COM ((ulong_t)(busnum & 0xff) << 16) |\
21010923SEvan.Yan@Sun.COM ((ulong_t)(devnum & 0x1f) << 11) |\
21110923SEvan.Yan@Sun.COM ((ulong_t)(funcnum & 0x7) << 8) |\
21210923SEvan.Yan@Sun.COM ((ulong_t)(register & 0x3f)))
21310923SEvan.Yan@Sun.COM
21410923SEvan.Yan@Sun.COM /*
21510923SEvan.Yan@Sun.COM * debug macros:
21610923SEvan.Yan@Sun.COM */
21710923SEvan.Yan@Sun.COM #if defined(DEBUG)
21810923SEvan.Yan@Sun.COM extern void prom_printf(const char *, ...);
21910923SEvan.Yan@Sun.COM
22010923SEvan.Yan@Sun.COM /*
22110923SEvan.Yan@Sun.COM * Following values are defined for this debug flag.
22210923SEvan.Yan@Sun.COM *
22310923SEvan.Yan@Sun.COM * 1 = dump configuration header only.
22410923SEvan.Yan@Sun.COM * 2 = dump generic debug data only (no config header dumped)
22510923SEvan.Yan@Sun.COM * 3 = dump everything (both 1 and 2)
22610923SEvan.Yan@Sun.COM */
22710923SEvan.Yan@Sun.COM int pcicfg_debug = 0;
22810923SEvan.Yan@Sun.COM int pcicfg_dump_fcode = 0;
22910923SEvan.Yan@Sun.COM
23010923SEvan.Yan@Sun.COM static void debug(char *, uintptr_t, uintptr_t,
23110923SEvan.Yan@Sun.COM uintptr_t, uintptr_t, uintptr_t);
23210923SEvan.Yan@Sun.COM
23310923SEvan.Yan@Sun.COM #define DEBUG0(fmt)\
23410923SEvan.Yan@Sun.COM debug(fmt, 0, 0, 0, 0, 0);
23510923SEvan.Yan@Sun.COM #define DEBUG1(fmt, a1)\
23610923SEvan.Yan@Sun.COM debug(fmt, (uintptr_t)(a1), 0, 0, 0, 0);
23710923SEvan.Yan@Sun.COM #define DEBUG2(fmt, a1, a2)\
23810923SEvan.Yan@Sun.COM debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2), 0, 0, 0);
23910923SEvan.Yan@Sun.COM #define DEBUG3(fmt, a1, a2, a3)\
24010923SEvan.Yan@Sun.COM debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2),\
24110923SEvan.Yan@Sun.COM (uintptr_t)(a3), 0, 0);
24210923SEvan.Yan@Sun.COM #define DEBUG4(fmt, a1, a2, a3, a4)\
24310923SEvan.Yan@Sun.COM debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2),\
24410923SEvan.Yan@Sun.COM (uintptr_t)(a3), (uintptr_t)(a4), 0);
24510923SEvan.Yan@Sun.COM #else
24610923SEvan.Yan@Sun.COM #define DEBUG0(fmt)
24710923SEvan.Yan@Sun.COM #define DEBUG1(fmt, a1)
24810923SEvan.Yan@Sun.COM #define DEBUG2(fmt, a1, a2)
24910923SEvan.Yan@Sun.COM #define DEBUG3(fmt, a1, a2, a3)
25010923SEvan.Yan@Sun.COM #define DEBUG4(fmt, a1, a2, a3, a4)
25110923SEvan.Yan@Sun.COM #endif
25210923SEvan.Yan@Sun.COM
25310923SEvan.Yan@Sun.COM #ifdef PCICFG_INTERPRET_FCODE
25410923SEvan.Yan@Sun.COM int pcicfg_dont_interpret = 0;
25510923SEvan.Yan@Sun.COM #else
25610923SEvan.Yan@Sun.COM int pcicfg_dont_interpret = 1;
25710923SEvan.Yan@Sun.COM #endif
25810923SEvan.Yan@Sun.COM
25910923SEvan.Yan@Sun.COM /*
26010923SEvan.Yan@Sun.COM * forward declarations for routines defined in this module (called here)
26110923SEvan.Yan@Sun.COM */
26210923SEvan.Yan@Sun.COM
26310923SEvan.Yan@Sun.COM static int pcicfg_add_config_reg(dev_info_t *,
26410923SEvan.Yan@Sun.COM uint_t, uint_t, uint_t);
26510923SEvan.Yan@Sun.COM static int pcicfg_probe_children(dev_info_t *, uint_t, uint_t, uint_t,
26611245SZhijun.Fu@Sun.COM uint_t *, pcicfg_flags_t, boolean_t);
26710923SEvan.Yan@Sun.COM
26810923SEvan.Yan@Sun.COM #ifdef PCICFG_INTERPRET_FCODE
26910923SEvan.Yan@Sun.COM static int pcicfg_load_fcode(dev_info_t *, uint_t, uint_t, uint_t,
27010923SEvan.Yan@Sun.COM uint16_t, uint16_t, uchar_t **, int *, int, int);
27110923SEvan.Yan@Sun.COM #endif
27210923SEvan.Yan@Sun.COM
27310923SEvan.Yan@Sun.COM static int pcicfg_fcode_probe(dev_info_t *, uint_t, uint_t, uint_t,
27411245SZhijun.Fu@Sun.COM uint_t *, pcicfg_flags_t, boolean_t);
27510923SEvan.Yan@Sun.COM static int pcicfg_probe_bridge(dev_info_t *, ddi_acc_handle_t, uint_t,
27611245SZhijun.Fu@Sun.COM uint_t *, boolean_t);
27710923SEvan.Yan@Sun.COM static int pcicfg_free_all_resources(dev_info_t *);
27810923SEvan.Yan@Sun.COM static int pcicfg_alloc_new_resources(dev_info_t *);
27910923SEvan.Yan@Sun.COM static int pcicfg_match_dev(dev_info_t *, void *);
28010923SEvan.Yan@Sun.COM static dev_info_t *pcicfg_devi_find(dev_info_t *, uint_t, uint_t);
28110923SEvan.Yan@Sun.COM static pcicfg_phdl_t *pcicfg_find_phdl(dev_info_t *);
28210923SEvan.Yan@Sun.COM static pcicfg_phdl_t *pcicfg_create_phdl(dev_info_t *);
28310923SEvan.Yan@Sun.COM static int pcicfg_destroy_phdl(dev_info_t *);
28410923SEvan.Yan@Sun.COM static int pcicfg_sum_resources(dev_info_t *, void *);
28510923SEvan.Yan@Sun.COM static int pcicfg_find_resource_end(dev_info_t *, void *);
28610923SEvan.Yan@Sun.COM static int pcicfg_allocate_chunk(dev_info_t *);
28710923SEvan.Yan@Sun.COM static int pcicfg_program_ap(dev_info_t *);
28810923SEvan.Yan@Sun.COM static int pcicfg_device_assign(dev_info_t *);
28910923SEvan.Yan@Sun.COM static int pcicfg_bridge_assign(dev_info_t *, void *);
29010923SEvan.Yan@Sun.COM static int pcicfg_device_assign_readonly(dev_info_t *);
29110923SEvan.Yan@Sun.COM static int pcicfg_free_resources(dev_info_t *, pcicfg_flags_t);
29210923SEvan.Yan@Sun.COM static void pcicfg_setup_bridge(pcicfg_phdl_t *, ddi_acc_handle_t,
29310923SEvan.Yan@Sun.COM dev_info_t *);
29410923SEvan.Yan@Sun.COM static void pcicfg_update_bridge(pcicfg_phdl_t *, ddi_acc_handle_t);
29510923SEvan.Yan@Sun.COM static void pcicfg_enable_bridge_probe_err(dev_info_t *dip,
29610923SEvan.Yan@Sun.COM ddi_acc_handle_t h, pcicfg_err_regs_t *regs);
29710923SEvan.Yan@Sun.COM static void pcicfg_disable_bridge_probe_err(dev_info_t *dip,
29810923SEvan.Yan@Sun.COM ddi_acc_handle_t h, pcicfg_err_regs_t *regs);
29910923SEvan.Yan@Sun.COM static int pcicfg_update_assigned_prop(dev_info_t *, pci_regspec_t *);
30010923SEvan.Yan@Sun.COM static void pcicfg_device_on(ddi_acc_handle_t);
30110923SEvan.Yan@Sun.COM static void pcicfg_device_off(ddi_acc_handle_t);
30210923SEvan.Yan@Sun.COM static int pcicfg_set_busnode_props(dev_info_t *, uint8_t, int, int);
30310923SEvan.Yan@Sun.COM static int pcicfg_free_bridge_resources(dev_info_t *);
30410923SEvan.Yan@Sun.COM static int pcicfg_free_device_resources(dev_info_t *, pcicfg_flags_t);
30511245SZhijun.Fu@Sun.COM static int pcicfg_teardown_device(dev_info_t *, pcicfg_flags_t, boolean_t);
30610923SEvan.Yan@Sun.COM static int pcicfg_config_setup(dev_info_t *, ddi_acc_handle_t *);
30710923SEvan.Yan@Sun.COM static void pcicfg_config_teardown(ddi_acc_handle_t *);
30810923SEvan.Yan@Sun.COM static void pcicfg_get_mem(pcicfg_phdl_t *, uint32_t, uint64_t *);
30910923SEvan.Yan@Sun.COM static void pcicfg_get_io(pcicfg_phdl_t *, uint32_t, uint32_t *);
31010923SEvan.Yan@Sun.COM static int pcicfg_update_ranges_prop(dev_info_t *, pcicfg_range_t *);
31110923SEvan.Yan@Sun.COM static int pcicfg_map_phys(dev_info_t *, pci_regspec_t *, caddr_t *,
31210923SEvan.Yan@Sun.COM ddi_device_acc_attr_t *, ddi_acc_handle_t *);
31310923SEvan.Yan@Sun.COM static void pcicfg_unmap_phys(ddi_acc_handle_t *, pci_regspec_t *);
31410923SEvan.Yan@Sun.COM static int pcicfg_dump_assigned(dev_info_t *);
31510923SEvan.Yan@Sun.COM static uint_t pcicfg_configure_ntbridge(dev_info_t *, uint_t, uint_t);
31610923SEvan.Yan@Sun.COM static int pcicfg_indirect_map(dev_info_t *dip);
31710923SEvan.Yan@Sun.COM static uint_t pcicfg_get_ntbridge_child_range(dev_info_t *, uint64_t *,
31810923SEvan.Yan@Sun.COM uint64_t *, uint_t);
31910923SEvan.Yan@Sun.COM static int pcicfg_is_ntbridge(dev_info_t *);
32010923SEvan.Yan@Sun.COM static int pcicfg_ntbridge_allocate_resources(dev_info_t *);
32110923SEvan.Yan@Sun.COM static int pcicfg_ntbridge_configure_done(dev_info_t *);
32210923SEvan.Yan@Sun.COM static int pcicfg_ntbridge_unconfigure(dev_info_t *);
32310923SEvan.Yan@Sun.COM static int pcicfg_ntbridge_unconfigure_child(dev_info_t *, uint_t);
32410923SEvan.Yan@Sun.COM static void pcicfg_free_hole(hole_t *);
32510923SEvan.Yan@Sun.COM static uint64_t pcicfg_alloc_hole(hole_t *, uint64_t *, uint32_t);
32610923SEvan.Yan@Sun.COM static int pcicfg_update_available_prop(dev_info_t *, pci_regspec_t *);
32710923SEvan.Yan@Sun.COM static int pcicfg_ari_configure(dev_info_t *);
32810923SEvan.Yan@Sun.COM static int pcicfg_populate_reg_props(dev_info_t *, ddi_acc_handle_t);
32910923SEvan.Yan@Sun.COM static int pcicfg_populate_props_from_bar(dev_info_t *, ddi_acc_handle_t);
33010923SEvan.Yan@Sun.COM static int pcicfg_update_assigned_prop_value(dev_info_t *, uint32_t,
33110923SEvan.Yan@Sun.COM uint32_t, uint32_t, uint_t);
33211245SZhijun.Fu@Sun.COM static boolean_t is_pcie_fabric(dev_info_t *dip);
33310923SEvan.Yan@Sun.COM
33410923SEvan.Yan@Sun.COM #ifdef DEBUG
33510923SEvan.Yan@Sun.COM static void pcicfg_dump_common_config(ddi_acc_handle_t config_handle);
33610923SEvan.Yan@Sun.COM static void pcicfg_dump_device_config(ddi_acc_handle_t);
33710923SEvan.Yan@Sun.COM
33810923SEvan.Yan@Sun.COM static void pcicfg_dump_bridge_config(ddi_acc_handle_t config_handle);
33910923SEvan.Yan@Sun.COM static uint64_t pcicfg_unused_space(hole_t *, uint32_t *);
34010923SEvan.Yan@Sun.COM
34110923SEvan.Yan@Sun.COM #define PCICFG_DUMP_COMMON_CONFIG(hdl) (void)pcicfg_dump_common_config(hdl)
34210923SEvan.Yan@Sun.COM #define PCICFG_DUMP_DEVICE_CONFIG(hdl) (void)pcicfg_dump_device_config(hdl)
34310923SEvan.Yan@Sun.COM #define PCICFG_DUMP_BRIDGE_CONFIG(hdl) (void)pcicfg_dump_bridge_config(hdl)
34410923SEvan.Yan@Sun.COM #else
34510923SEvan.Yan@Sun.COM #define PCICFG_DUMP_COMMON_CONFIG(handle)
34610923SEvan.Yan@Sun.COM #define PCICFG_DUMP_DEVICE_CONFIG(handle)
34710923SEvan.Yan@Sun.COM #define PCICFG_DUMP_BRIDGE_CONFIG(handle)
34810923SEvan.Yan@Sun.COM #endif
34910923SEvan.Yan@Sun.COM
35010923SEvan.Yan@Sun.COM static kmutex_t pcicfg_list_mutex; /* Protects the probe handle list */
35110923SEvan.Yan@Sun.COM static pcicfg_phdl_t *pcicfg_phdl_list = NULL;
35210923SEvan.Yan@Sun.COM
35310923SEvan.Yan@Sun.COM #ifndef _DONT_USE_1275_GENERIC_NAMES
35410923SEvan.Yan@Sun.COM /*
35510923SEvan.Yan@Sun.COM * Class code table
35610923SEvan.Yan@Sun.COM */
35710923SEvan.Yan@Sun.COM static struct pcicfg_name_entry pcicfg_class_lookup [] = {
35810923SEvan.Yan@Sun.COM
35910923SEvan.Yan@Sun.COM { 0x001, "display" },
36010923SEvan.Yan@Sun.COM { 0x100, "scsi" },
36110923SEvan.Yan@Sun.COM { 0x101, "ide" },
36210923SEvan.Yan@Sun.COM { 0x102, "fdc" },
36310923SEvan.Yan@Sun.COM { 0x103, "ipi" },
36410923SEvan.Yan@Sun.COM { 0x104, "raid" },
36510923SEvan.Yan@Sun.COM { 0x200, "ethernet" },
36610923SEvan.Yan@Sun.COM { 0x201, "token-ring" },
36710923SEvan.Yan@Sun.COM { 0x202, "fddi" },
36810923SEvan.Yan@Sun.COM { 0x203, "atm" },
36910923SEvan.Yan@Sun.COM { 0x300, "display" },
37010923SEvan.Yan@Sun.COM { 0x400, "video" },
37110923SEvan.Yan@Sun.COM { 0x401, "sound" },
37210923SEvan.Yan@Sun.COM { 0x500, "memory" },
37310923SEvan.Yan@Sun.COM { 0x501, "flash" },
37410923SEvan.Yan@Sun.COM { 0x600, "host" },
37510923SEvan.Yan@Sun.COM { 0x601, "isa" },
37610923SEvan.Yan@Sun.COM { 0x602, "eisa" },
37710923SEvan.Yan@Sun.COM { 0x603, "mca" },
37810923SEvan.Yan@Sun.COM { 0x604, "pci" },
37910923SEvan.Yan@Sun.COM { 0x605, "pcmcia" },
38010923SEvan.Yan@Sun.COM { 0x606, "nubus" },
38110923SEvan.Yan@Sun.COM { 0x607, "cardbus" },
38210923SEvan.Yan@Sun.COM { 0x609, "pci" },
38310923SEvan.Yan@Sun.COM { 0x700, "serial" },
38410923SEvan.Yan@Sun.COM { 0x701, "parallel" },
38510923SEvan.Yan@Sun.COM { 0x800, "interrupt-controller" },
38610923SEvan.Yan@Sun.COM { 0x801, "dma-controller" },
38710923SEvan.Yan@Sun.COM { 0x802, "timer" },
38810923SEvan.Yan@Sun.COM { 0x803, "rtc" },
38910923SEvan.Yan@Sun.COM { 0x900, "keyboard" },
39010923SEvan.Yan@Sun.COM { 0x901, "pen" },
39110923SEvan.Yan@Sun.COM { 0x902, "mouse" },
39210923SEvan.Yan@Sun.COM { 0xa00, "dock" },
39310923SEvan.Yan@Sun.COM { 0xb00, "cpu" },
39410923SEvan.Yan@Sun.COM { 0xc00, "firewire" },
39510923SEvan.Yan@Sun.COM { 0xc01, "access-bus" },
39610923SEvan.Yan@Sun.COM { 0xc02, "ssa" },
39710923SEvan.Yan@Sun.COM { 0xc03, "usb" },
39810923SEvan.Yan@Sun.COM { 0xc04, "fibre-channel" },
39910923SEvan.Yan@Sun.COM { 0, 0 }
40010923SEvan.Yan@Sun.COM };
40110923SEvan.Yan@Sun.COM #endif /* _DONT_USE_1275_GENERIC_NAMES */
40210923SEvan.Yan@Sun.COM
40310923SEvan.Yan@Sun.COM /*
40410923SEvan.Yan@Sun.COM * Module control operations
40510923SEvan.Yan@Sun.COM */
40610923SEvan.Yan@Sun.COM
40710923SEvan.Yan@Sun.COM extern struct mod_ops mod_miscops;
40810923SEvan.Yan@Sun.COM
40910923SEvan.Yan@Sun.COM static struct modlmisc modlmisc = {
41010923SEvan.Yan@Sun.COM &mod_miscops, /* Type of module */
41110923SEvan.Yan@Sun.COM "PCIe/PCI Config (EFCode Enabled)"
41210923SEvan.Yan@Sun.COM };
41310923SEvan.Yan@Sun.COM
41410923SEvan.Yan@Sun.COM static struct modlinkage modlinkage = {
41510923SEvan.Yan@Sun.COM MODREV_1, (void *)&modlmisc, NULL
41610923SEvan.Yan@Sun.COM };
41710923SEvan.Yan@Sun.COM
41810923SEvan.Yan@Sun.COM #ifdef DEBUG
41910923SEvan.Yan@Sun.COM
42010923SEvan.Yan@Sun.COM static void
pcicfg_dump_common_config(ddi_acc_handle_t config_handle)42110923SEvan.Yan@Sun.COM pcicfg_dump_common_config(ddi_acc_handle_t config_handle)
42210923SEvan.Yan@Sun.COM {
42310923SEvan.Yan@Sun.COM if ((pcicfg_debug & 1) == 0)
42410923SEvan.Yan@Sun.COM return;
42510923SEvan.Yan@Sun.COM cmn_err(CE_CONT, " Vendor ID = [0x%x]\n",
42610923SEvan.Yan@Sun.COM pci_config_get16(config_handle, PCI_CONF_VENID));
42710923SEvan.Yan@Sun.COM cmn_err(CE_CONT, " Device ID = [0x%x]\n",
42810923SEvan.Yan@Sun.COM pci_config_get16(config_handle, PCI_CONF_DEVID));
42910923SEvan.Yan@Sun.COM cmn_err(CE_CONT, " Command REG = [0x%x]\n",
43010923SEvan.Yan@Sun.COM pci_config_get16(config_handle, PCI_CONF_COMM));
43110923SEvan.Yan@Sun.COM cmn_err(CE_CONT, " Status REG = [0x%x]\n",
43210923SEvan.Yan@Sun.COM pci_config_get16(config_handle, PCI_CONF_STAT));
43310923SEvan.Yan@Sun.COM cmn_err(CE_CONT, " Revision ID = [0x%x]\n",
43410923SEvan.Yan@Sun.COM pci_config_get8(config_handle, PCI_CONF_REVID));
43510923SEvan.Yan@Sun.COM cmn_err(CE_CONT, " Prog Class = [0x%x]\n",
43610923SEvan.Yan@Sun.COM pci_config_get8(config_handle, PCI_CONF_PROGCLASS));
43710923SEvan.Yan@Sun.COM cmn_err(CE_CONT, " Dev Class = [0x%x]\n",
43810923SEvan.Yan@Sun.COM pci_config_get8(config_handle, PCI_CONF_SUBCLASS));
43910923SEvan.Yan@Sun.COM cmn_err(CE_CONT, " Base Class = [0x%x]\n",
44010923SEvan.Yan@Sun.COM pci_config_get8(config_handle, PCI_CONF_BASCLASS));
44110923SEvan.Yan@Sun.COM cmn_err(CE_CONT, " Device ID = [0x%x]\n",
44210923SEvan.Yan@Sun.COM pci_config_get8(config_handle, PCI_CONF_CACHE_LINESZ));
44310923SEvan.Yan@Sun.COM cmn_err(CE_CONT, " Header Type = [0x%x]\n",
44410923SEvan.Yan@Sun.COM pci_config_get8(config_handle, PCI_CONF_HEADER));
44510923SEvan.Yan@Sun.COM cmn_err(CE_CONT, " BIST = [0x%x]\n",
44610923SEvan.Yan@Sun.COM pci_config_get8(config_handle, PCI_CONF_BIST));
44710923SEvan.Yan@Sun.COM cmn_err(CE_CONT, " BASE 0 = [0x%x]\n",
44810923SEvan.Yan@Sun.COM pci_config_get32(config_handle, PCI_CONF_BASE0));
44910923SEvan.Yan@Sun.COM cmn_err(CE_CONT, " BASE 1 = [0x%x]\n",
45010923SEvan.Yan@Sun.COM pci_config_get32(config_handle, PCI_CONF_BASE1));
45110923SEvan.Yan@Sun.COM
45210923SEvan.Yan@Sun.COM }
45310923SEvan.Yan@Sun.COM
45410923SEvan.Yan@Sun.COM static void
pcicfg_dump_device_config(ddi_acc_handle_t config_handle)45510923SEvan.Yan@Sun.COM pcicfg_dump_device_config(ddi_acc_handle_t config_handle)
45610923SEvan.Yan@Sun.COM {
45710923SEvan.Yan@Sun.COM if ((pcicfg_debug & 1) == 0)
45810923SEvan.Yan@Sun.COM return;
45910923SEvan.Yan@Sun.COM pcicfg_dump_common_config(config_handle);
46010923SEvan.Yan@Sun.COM
46110923SEvan.Yan@Sun.COM cmn_err(CE_CONT, " BASE 2 = [0x%x]\n",
46210923SEvan.Yan@Sun.COM pci_config_get32(config_handle, PCI_CONF_BASE2));
46310923SEvan.Yan@Sun.COM cmn_err(CE_CONT, " BASE 3 = [0x%x]\n",
46410923SEvan.Yan@Sun.COM pci_config_get32(config_handle, PCI_CONF_BASE3));
46510923SEvan.Yan@Sun.COM cmn_err(CE_CONT, " BASE 4 = [0x%x]\n",
46610923SEvan.Yan@Sun.COM pci_config_get32(config_handle, PCI_CONF_BASE4));
46710923SEvan.Yan@Sun.COM cmn_err(CE_CONT, " BASE 5 = [0x%x]\n",
46810923SEvan.Yan@Sun.COM pci_config_get32(config_handle, PCI_CONF_BASE5));
46910923SEvan.Yan@Sun.COM cmn_err(CE_CONT, " Cardbus CIS = [0x%x]\n",
47010923SEvan.Yan@Sun.COM pci_config_get32(config_handle, PCI_CONF_CIS));
47110923SEvan.Yan@Sun.COM cmn_err(CE_CONT, " Sub VID = [0x%x]\n",
47210923SEvan.Yan@Sun.COM pci_config_get16(config_handle, PCI_CONF_SUBVENID));
47310923SEvan.Yan@Sun.COM cmn_err(CE_CONT, " Sub SID = [0x%x]\n",
47410923SEvan.Yan@Sun.COM pci_config_get16(config_handle, PCI_CONF_SUBSYSID));
47510923SEvan.Yan@Sun.COM cmn_err(CE_CONT, " ROM = [0x%x]\n",
47610923SEvan.Yan@Sun.COM pci_config_get32(config_handle, PCI_CONF_ROM));
47710923SEvan.Yan@Sun.COM cmn_err(CE_CONT, " I Line = [0x%x]\n",
47810923SEvan.Yan@Sun.COM pci_config_get8(config_handle, PCI_CONF_ILINE));
47910923SEvan.Yan@Sun.COM cmn_err(CE_CONT, " I Pin = [0x%x]\n",
48010923SEvan.Yan@Sun.COM pci_config_get8(config_handle, PCI_CONF_IPIN));
48110923SEvan.Yan@Sun.COM cmn_err(CE_CONT, " Max Grant = [0x%x]\n",
48210923SEvan.Yan@Sun.COM pci_config_get8(config_handle, PCI_CONF_MIN_G));
48310923SEvan.Yan@Sun.COM cmn_err(CE_CONT, " Max Latent = [0x%x]\n",
48410923SEvan.Yan@Sun.COM pci_config_get8(config_handle, PCI_CONF_MAX_L));
48510923SEvan.Yan@Sun.COM }
48610923SEvan.Yan@Sun.COM
48710923SEvan.Yan@Sun.COM static void
pcicfg_dump_bridge_config(ddi_acc_handle_t config_handle)48810923SEvan.Yan@Sun.COM pcicfg_dump_bridge_config(ddi_acc_handle_t config_handle)
48910923SEvan.Yan@Sun.COM {
49010923SEvan.Yan@Sun.COM if ((pcicfg_debug & 1) == 0)
49110923SEvan.Yan@Sun.COM return;
49210923SEvan.Yan@Sun.COM
49310923SEvan.Yan@Sun.COM pcicfg_dump_common_config(config_handle);
49410923SEvan.Yan@Sun.COM
49510923SEvan.Yan@Sun.COM cmn_err(CE_CONT, "........................................\n");
49610923SEvan.Yan@Sun.COM
49710923SEvan.Yan@Sun.COM cmn_err(CE_CONT, " Pri Bus = [0x%x]\n",
49810923SEvan.Yan@Sun.COM pci_config_get8(config_handle, PCI_BCNF_PRIBUS));
49910923SEvan.Yan@Sun.COM cmn_err(CE_CONT, " Sec Bus = [0x%x]\n",
50010923SEvan.Yan@Sun.COM pci_config_get8(config_handle, PCI_BCNF_SECBUS));
50110923SEvan.Yan@Sun.COM cmn_err(CE_CONT, " Sub Bus = [0x%x]\n",
50210923SEvan.Yan@Sun.COM pci_config_get8(config_handle, PCI_BCNF_SUBBUS));
50310923SEvan.Yan@Sun.COM cmn_err(CE_CONT, " Latency = [0x%x]\n",
50410923SEvan.Yan@Sun.COM pci_config_get8(config_handle, PCI_BCNF_LATENCY_TIMER));
50510923SEvan.Yan@Sun.COM cmn_err(CE_CONT, " I/O Base LO = [0x%x]\n",
50610923SEvan.Yan@Sun.COM pci_config_get8(config_handle, PCI_BCNF_IO_BASE_LOW));
50710923SEvan.Yan@Sun.COM cmn_err(CE_CONT, " I/O Lim LO = [0x%x]\n",
50810923SEvan.Yan@Sun.COM pci_config_get8(config_handle, PCI_BCNF_IO_LIMIT_LOW));
50910923SEvan.Yan@Sun.COM cmn_err(CE_CONT, " Sec. Status = [0x%x]\n",
51010923SEvan.Yan@Sun.COM pci_config_get16(config_handle, PCI_BCNF_SEC_STATUS));
51110923SEvan.Yan@Sun.COM cmn_err(CE_CONT, " Mem Base = [0x%x]\n",
51210923SEvan.Yan@Sun.COM pci_config_get16(config_handle, PCI_BCNF_MEM_BASE));
51310923SEvan.Yan@Sun.COM cmn_err(CE_CONT, " Mem Limit = [0x%x]\n",
51410923SEvan.Yan@Sun.COM pci_config_get16(config_handle, PCI_BCNF_MEM_LIMIT));
51510923SEvan.Yan@Sun.COM cmn_err(CE_CONT, " PF Mem Base = [0x%x]\n",
51610923SEvan.Yan@Sun.COM pci_config_get16(config_handle, PCI_BCNF_PF_BASE_LOW));
51710923SEvan.Yan@Sun.COM cmn_err(CE_CONT, " PF Mem Lim = [0x%x]\n",
51810923SEvan.Yan@Sun.COM pci_config_get16(config_handle, PCI_BCNF_PF_LIMIT_LOW));
51910923SEvan.Yan@Sun.COM cmn_err(CE_CONT, " PF Base HI = [0x%x]\n",
52010923SEvan.Yan@Sun.COM pci_config_get32(config_handle, PCI_BCNF_PF_BASE_HIGH));
52110923SEvan.Yan@Sun.COM cmn_err(CE_CONT, " PF Lim HI = [0x%x]\n",
52210923SEvan.Yan@Sun.COM pci_config_get32(config_handle, PCI_BCNF_PF_LIMIT_HIGH));
52310923SEvan.Yan@Sun.COM cmn_err(CE_CONT, " I/O Base HI = [0x%x]\n",
52410923SEvan.Yan@Sun.COM pci_config_get16(config_handle, PCI_BCNF_IO_BASE_HI));
52510923SEvan.Yan@Sun.COM cmn_err(CE_CONT, " I/O Lim HI = [0x%x]\n",
52610923SEvan.Yan@Sun.COM pci_config_get16(config_handle, PCI_BCNF_IO_LIMIT_HI));
52710923SEvan.Yan@Sun.COM cmn_err(CE_CONT, " ROM addr = [0x%x]\n",
52810923SEvan.Yan@Sun.COM pci_config_get32(config_handle, PCI_BCNF_ROM));
52910923SEvan.Yan@Sun.COM cmn_err(CE_CONT, " Intr Line = [0x%x]\n",
53010923SEvan.Yan@Sun.COM pci_config_get8(config_handle, PCI_BCNF_ILINE));
53110923SEvan.Yan@Sun.COM cmn_err(CE_CONT, " Intr Pin = [0x%x]\n",
53210923SEvan.Yan@Sun.COM pci_config_get8(config_handle, PCI_BCNF_IPIN));
53310923SEvan.Yan@Sun.COM cmn_err(CE_CONT, " Bridge Ctrl = [0x%x]\n",
53410923SEvan.Yan@Sun.COM pci_config_get16(config_handle, PCI_BCNF_BCNTRL));
53510923SEvan.Yan@Sun.COM }
53610923SEvan.Yan@Sun.COM
53710923SEvan.Yan@Sun.COM #endif
53810923SEvan.Yan@Sun.COM
53910923SEvan.Yan@Sun.COM
54010923SEvan.Yan@Sun.COM int
_init()54110923SEvan.Yan@Sun.COM _init()
54210923SEvan.Yan@Sun.COM {
54310923SEvan.Yan@Sun.COM DEBUG0("PCI configurator installed - Fcode Interpretation/21554\n");
54410923SEvan.Yan@Sun.COM
54510923SEvan.Yan@Sun.COM mutex_init(&pcicfg_list_mutex, NULL, MUTEX_DRIVER, NULL);
54610923SEvan.Yan@Sun.COM return (mod_install(&modlinkage));
54710923SEvan.Yan@Sun.COM }
54810923SEvan.Yan@Sun.COM
54910923SEvan.Yan@Sun.COM int
_fini(void)55010923SEvan.Yan@Sun.COM _fini(void)
55110923SEvan.Yan@Sun.COM {
55210923SEvan.Yan@Sun.COM int error;
55310923SEvan.Yan@Sun.COM
55410923SEvan.Yan@Sun.COM error = mod_remove(&modlinkage);
55510923SEvan.Yan@Sun.COM if (error != 0) {
55610923SEvan.Yan@Sun.COM return (error);
55710923SEvan.Yan@Sun.COM }
55810923SEvan.Yan@Sun.COM mutex_destroy(&pcicfg_list_mutex);
55910923SEvan.Yan@Sun.COM return (0);
56010923SEvan.Yan@Sun.COM }
56110923SEvan.Yan@Sun.COM
56210923SEvan.Yan@Sun.COM int
_info(modinfop)56310923SEvan.Yan@Sun.COM _info(modinfop)
56410923SEvan.Yan@Sun.COM struct modinfo *modinfop;
56510923SEvan.Yan@Sun.COM {
56610923SEvan.Yan@Sun.COM return (mod_info(&modlinkage, modinfop));
56710923SEvan.Yan@Sun.COM }
56810923SEvan.Yan@Sun.COM
56910923SEvan.Yan@Sun.COM /*ARGSUSED*/
57010923SEvan.Yan@Sun.COM static uint8_t
pcicfg_get_nslots(dev_info_t * dip,ddi_acc_handle_t handle)57110923SEvan.Yan@Sun.COM pcicfg_get_nslots(dev_info_t *dip, ddi_acc_handle_t handle)
57210923SEvan.Yan@Sun.COM {
57310923SEvan.Yan@Sun.COM uint8_t num_slots = 0;
57410923SEvan.Yan@Sun.COM uint16_t cap_ptr;
57510923SEvan.Yan@Sun.COM
57610923SEvan.Yan@Sun.COM if ((PCI_CAP_LOCATE(handle, PCI_CAP_ID_PCI_HOTPLUG,
57710923SEvan.Yan@Sun.COM &cap_ptr)) == DDI_SUCCESS) {
57810923SEvan.Yan@Sun.COM uint32_t config;
57910923SEvan.Yan@Sun.COM
58010923SEvan.Yan@Sun.COM PCI_CAP_PUT8(handle, NULL, cap_ptr, PCI_HP_DWORD_SELECT_OFF,
58110923SEvan.Yan@Sun.COM PCI_HP_SLOT_CONFIGURATION_REG);
58210923SEvan.Yan@Sun.COM config = PCI_CAP_GET32(handle, NULL, cap_ptr,
58310923SEvan.Yan@Sun.COM PCI_HP_DWORD_DATA_OFF);
58410923SEvan.Yan@Sun.COM num_slots = config & 0x1F;
58510923SEvan.Yan@Sun.COM } else if ((PCI_CAP_LOCATE(handle, PCI_CAP_ID_SLOT_ID, &cap_ptr))
58610923SEvan.Yan@Sun.COM == DDI_SUCCESS) {
58710923SEvan.Yan@Sun.COM uint8_t esr_reg = PCI_CAP_GET8(handle, NULL,
58810923SEvan.Yan@Sun.COM cap_ptr, PCI_CAP_ID_REGS_OFF);
58910923SEvan.Yan@Sun.COM
59010923SEvan.Yan@Sun.COM num_slots = PCI_CAPSLOT_NSLOTS(esr_reg);
59110923SEvan.Yan@Sun.COM } else if ((PCI_CAP_LOCATE(handle, PCI_CAP_ID_PCI_E, &cap_ptr))
59210923SEvan.Yan@Sun.COM == DDI_SUCCESS) {
59310923SEvan.Yan@Sun.COM int port_type = PCI_CAP_GET16(handle, NULL, cap_ptr,
59410923SEvan.Yan@Sun.COM PCIE_PCIECAP) & PCIE_PCIECAP_DEV_TYPE_MASK;
59510923SEvan.Yan@Sun.COM
59610923SEvan.Yan@Sun.COM if ((port_type == PCIE_PCIECAP_DEV_TYPE_DOWN) &&
59710923SEvan.Yan@Sun.COM (PCI_CAP_GET16(handle, NULL, cap_ptr, PCIE_PCIECAP)
59810923SEvan.Yan@Sun.COM & PCIE_PCIECAP_SLOT_IMPL))
59910923SEvan.Yan@Sun.COM num_slots = 1;
60010923SEvan.Yan@Sun.COM }
60110923SEvan.Yan@Sun.COM
60210923SEvan.Yan@Sun.COM DEBUG3("%s#%d has %d slots",
60310923SEvan.Yan@Sun.COM ddi_get_name(dip), ddi_get_instance(dip), num_slots);
60410923SEvan.Yan@Sun.COM
60510923SEvan.Yan@Sun.COM return (num_slots);
60610923SEvan.Yan@Sun.COM }
60710923SEvan.Yan@Sun.COM
60810923SEvan.Yan@Sun.COM /*ARGSUSED*/
60910923SEvan.Yan@Sun.COM static uint8_t
pcicfg_is_chassis(dev_info_t * dip,ddi_acc_handle_t handle)61010923SEvan.Yan@Sun.COM pcicfg_is_chassis(dev_info_t *dip, ddi_acc_handle_t handle)
61110923SEvan.Yan@Sun.COM {
61210923SEvan.Yan@Sun.COM uint16_t cap_ptr;
61310923SEvan.Yan@Sun.COM
61410923SEvan.Yan@Sun.COM if ((PCI_CAP_LOCATE(handle, PCI_CAP_ID_SLOT_ID, &cap_ptr)) !=
61510923SEvan.Yan@Sun.COM DDI_FAILURE) {
61610923SEvan.Yan@Sun.COM
61710923SEvan.Yan@Sun.COM uint8_t esr_reg = PCI_CAP_GET8(handle, NULL, cap_ptr, 2);
61810923SEvan.Yan@Sun.COM if (PCI_CAPSLOT_FIC(esr_reg))
61910923SEvan.Yan@Sun.COM return (B_TRUE);
62010923SEvan.Yan@Sun.COM }
62110923SEvan.Yan@Sun.COM return (B_FALSE);
62210923SEvan.Yan@Sun.COM }
62310923SEvan.Yan@Sun.COM
62410923SEvan.Yan@Sun.COM /*ARGSUSED*/
62510923SEvan.Yan@Sun.COM static int
pcicfg_pcie_dev(dev_info_t * dip,int bus_type,pcicfg_err_regs_t * regs)62610923SEvan.Yan@Sun.COM pcicfg_pcie_dev(dev_info_t *dip, int bus_type, pcicfg_err_regs_t *regs)
62710923SEvan.Yan@Sun.COM {
62810923SEvan.Yan@Sun.COM /* get parent device's device_type property */
62910923SEvan.Yan@Sun.COM char *device_type;
63010923SEvan.Yan@Sun.COM int rc = DDI_FAILURE;
63110923SEvan.Yan@Sun.COM dev_info_t *pdip = ddi_get_parent(dip);
63210923SEvan.Yan@Sun.COM
63310923SEvan.Yan@Sun.COM regs->pcie_dev = 0;
63410923SEvan.Yan@Sun.COM if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip,
63510923SEvan.Yan@Sun.COM DDI_PROP_DONTPASS, "device_type", &device_type)
63610923SEvan.Yan@Sun.COM != DDI_PROP_SUCCESS) {
63710923SEvan.Yan@Sun.COM DEBUG2("device_type property missing for %s#%d",
63810923SEvan.Yan@Sun.COM ddi_get_name(pdip), ddi_get_instance(pdip));
63910923SEvan.Yan@Sun.COM return (DDI_FAILURE);
64010923SEvan.Yan@Sun.COM }
64110923SEvan.Yan@Sun.COM switch (bus_type) {
64210923SEvan.Yan@Sun.COM case PCICFG_DEVICE_TYPE_PCIE:
64310923SEvan.Yan@Sun.COM if (strcmp(device_type, "pciex") == 0) {
64410923SEvan.Yan@Sun.COM rc = DDI_SUCCESS;
64510923SEvan.Yan@Sun.COM regs->pcie_dev = 1;
64610923SEvan.Yan@Sun.COM }
64710923SEvan.Yan@Sun.COM break;
64810923SEvan.Yan@Sun.COM case PCICFG_DEVICE_TYPE_PCI:
64910923SEvan.Yan@Sun.COM if (strcmp(device_type, "pci") == 0)
65010923SEvan.Yan@Sun.COM rc = DDI_SUCCESS;
65110923SEvan.Yan@Sun.COM break;
65210923SEvan.Yan@Sun.COM default:
65310923SEvan.Yan@Sun.COM break;
65410923SEvan.Yan@Sun.COM }
65510923SEvan.Yan@Sun.COM ddi_prop_free(device_type);
65610923SEvan.Yan@Sun.COM return (rc);
65710923SEvan.Yan@Sun.COM }
65810923SEvan.Yan@Sun.COM
65910923SEvan.Yan@Sun.COM /*ARGSUSED*/
66010923SEvan.Yan@Sun.COM static int
pcicfg_pcie_port_type(dev_info_t * dip,ddi_acc_handle_t handle)66110923SEvan.Yan@Sun.COM pcicfg_pcie_port_type(dev_info_t *dip, ddi_acc_handle_t handle)
66210923SEvan.Yan@Sun.COM {
66310923SEvan.Yan@Sun.COM int port_type = -1;
66410923SEvan.Yan@Sun.COM uint16_t cap_ptr;
66510923SEvan.Yan@Sun.COM
66610923SEvan.Yan@Sun.COM if ((PCI_CAP_LOCATE(handle, PCI_CAP_ID_PCI_E, &cap_ptr)) !=
66710923SEvan.Yan@Sun.COM DDI_FAILURE)
66810923SEvan.Yan@Sun.COM port_type = PCI_CAP_GET16(handle, NULL,
66910923SEvan.Yan@Sun.COM cap_ptr, PCIE_PCIECAP) & PCIE_PCIECAP_DEV_TYPE_MASK;
67010923SEvan.Yan@Sun.COM
67110923SEvan.Yan@Sun.COM return (port_type);
67210923SEvan.Yan@Sun.COM }
67310923SEvan.Yan@Sun.COM
67410923SEvan.Yan@Sun.COM static int
pcicfg_pcie_device_type(dev_info_t * dip,ddi_acc_handle_t handle)67510923SEvan.Yan@Sun.COM pcicfg_pcie_device_type(dev_info_t *dip, ddi_acc_handle_t handle)
67610923SEvan.Yan@Sun.COM {
67710923SEvan.Yan@Sun.COM int port_type = pcicfg_pcie_port_type(dip, handle);
67810923SEvan.Yan@Sun.COM
67910923SEvan.Yan@Sun.COM DEBUG1("device port_type = %x\n", port_type);
68010923SEvan.Yan@Sun.COM /* No PCIe CAP regs, we are not PCIe device_type */
68110923SEvan.Yan@Sun.COM if (port_type < 0)
68210923SEvan.Yan@Sun.COM return (DDI_FAILURE);
68310923SEvan.Yan@Sun.COM
68410923SEvan.Yan@Sun.COM /* check for all PCIe device_types */
68510923SEvan.Yan@Sun.COM if ((port_type == PCIE_PCIECAP_DEV_TYPE_UP) ||
68610923SEvan.Yan@Sun.COM (port_type == PCIE_PCIECAP_DEV_TYPE_DOWN) ||
68710923SEvan.Yan@Sun.COM (port_type == PCIE_PCIECAP_DEV_TYPE_ROOT) ||
68810923SEvan.Yan@Sun.COM (port_type == PCIE_PCIECAP_DEV_TYPE_PCI2PCIE))
68910923SEvan.Yan@Sun.COM return (DDI_SUCCESS);
69010923SEvan.Yan@Sun.COM
69110923SEvan.Yan@Sun.COM return (DDI_FAILURE);
69210923SEvan.Yan@Sun.COM
69310923SEvan.Yan@Sun.COM }
69410923SEvan.Yan@Sun.COM
69510923SEvan.Yan@Sun.COM /*
69610923SEvan.Yan@Sun.COM * In the following functions ndi_devi_enter() without holding the
69710923SEvan.Yan@Sun.COM * parent dip is sufficient. This is because pci dr is driven through
69810923SEvan.Yan@Sun.COM * opens on the nexus which is in the device tree path above the node
69910923SEvan.Yan@Sun.COM * being operated on, and implicitly held due to the open.
70010923SEvan.Yan@Sun.COM */
70110923SEvan.Yan@Sun.COM
70210923SEvan.Yan@Sun.COM /*
70310923SEvan.Yan@Sun.COM * This entry point is called to configure a device (and
70410923SEvan.Yan@Sun.COM * all its children) on the given bus. It is called when
70510923SEvan.Yan@Sun.COM * a new device is added to the PCI domain. This routine
70610923SEvan.Yan@Sun.COM * will create the device tree and program the devices
70710923SEvan.Yan@Sun.COM * registers.
70810923SEvan.Yan@Sun.COM */
70910923SEvan.Yan@Sun.COM
71010923SEvan.Yan@Sun.COM int
pcicfg_configure(dev_info_t * devi,uint_t device,uint_t function,pcicfg_flags_t flags)71110923SEvan.Yan@Sun.COM pcicfg_configure(dev_info_t *devi, uint_t device, uint_t function,
71210923SEvan.Yan@Sun.COM pcicfg_flags_t flags)
71310923SEvan.Yan@Sun.COM {
71410923SEvan.Yan@Sun.COM uint_t bus;
71510923SEvan.Yan@Sun.COM int len;
71610923SEvan.Yan@Sun.COM int func;
71710923SEvan.Yan@Sun.COM int trans_device;
71810923SEvan.Yan@Sun.COM dev_info_t *new_device;
71910923SEvan.Yan@Sun.COM pcicfg_bus_range_t pci_bus_range;
72010923SEvan.Yan@Sun.COM int rv;
72110923SEvan.Yan@Sun.COM int circ;
72210923SEvan.Yan@Sun.COM uint_t highest_bus = 0;
72310923SEvan.Yan@Sun.COM int ari_mode = B_FALSE;
72410923SEvan.Yan@Sun.COM int max_function = PCICFG_MAX_FUNCTION;
72511245SZhijun.Fu@Sun.COM boolean_t is_pcie;
72610923SEvan.Yan@Sun.COM
72710923SEvan.Yan@Sun.COM if (flags == PCICFG_FLAG_ENABLE_ARI)
72810923SEvan.Yan@Sun.COM return (pcicfg_ari_configure(devi));
72910923SEvan.Yan@Sun.COM
73010923SEvan.Yan@Sun.COM /*
73110923SEvan.Yan@Sun.COM * Start probing at the device specified in "device" on the
73210923SEvan.Yan@Sun.COM * "bus" specified.
73310923SEvan.Yan@Sun.COM */
73410923SEvan.Yan@Sun.COM len = sizeof (pcicfg_bus_range_t);
73510923SEvan.Yan@Sun.COM if (ddi_getlongprop_buf(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS,
73610923SEvan.Yan@Sun.COM "bus-range", (caddr_t)&pci_bus_range, &len) != DDI_SUCCESS) {
73710923SEvan.Yan@Sun.COM DEBUG0("no bus-range property\n");
73810923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
73910923SEvan.Yan@Sun.COM }
74010923SEvan.Yan@Sun.COM
74110923SEvan.Yan@Sun.COM bus = pci_bus_range.lo; /* primary bus number of this bus node */
74210923SEvan.Yan@Sun.COM
74311245SZhijun.Fu@Sun.COM is_pcie = is_pcie_fabric(devi);
74411245SZhijun.Fu@Sun.COM
74510923SEvan.Yan@Sun.COM ndi_devi_enter(devi, &circ);
74610923SEvan.Yan@Sun.COM for (func = 0; func < max_function; ) {
74710923SEvan.Yan@Sun.COM if ((function != PCICFG_ALL_FUNC) && (function != func))
74810923SEvan.Yan@Sun.COM goto next;
74910923SEvan.Yan@Sun.COM
75010923SEvan.Yan@Sun.COM if (ari_mode)
75110923SEvan.Yan@Sun.COM trans_device = func >> 3;
75210923SEvan.Yan@Sun.COM else
75310923SEvan.Yan@Sun.COM trans_device = device;
75410923SEvan.Yan@Sun.COM
75510923SEvan.Yan@Sun.COM DEBUG3("Configuring [0x%x][0x%x][0x%x]\n",
75610923SEvan.Yan@Sun.COM bus, trans_device, func & 7);
75710923SEvan.Yan@Sun.COM
75810923SEvan.Yan@Sun.COM /*
75910923SEvan.Yan@Sun.COM * Try executing fcode if available.
76010923SEvan.Yan@Sun.COM */
76110923SEvan.Yan@Sun.COM switch (rv = pcicfg_fcode_probe(devi, bus, trans_device,
76211245SZhijun.Fu@Sun.COM func & 7, &highest_bus, flags, is_pcie)) {
76310923SEvan.Yan@Sun.COM case PCICFG_FAILURE:
76410923SEvan.Yan@Sun.COM DEBUG2("configure failed: "
76510923SEvan.Yan@Sun.COM "bus [0x%x] device [0x%x]\n",
76610923SEvan.Yan@Sun.COM bus, trans_device);
76710923SEvan.Yan@Sun.COM break;
76810923SEvan.Yan@Sun.COM case PCICFG_NODEVICE:
76910923SEvan.Yan@Sun.COM DEBUG3("no device : bus "
77010923SEvan.Yan@Sun.COM "[0x%x] slot [0x%x] func [0x%x]\n",
77110923SEvan.Yan@Sun.COM bus, trans_device, func & 7);
77212622SAlan.Adamson@Sun.COM
77312622SAlan.Adamson@Sun.COM /*
77412622SAlan.Adamson@Sun.COM * When walking the list of ARI functions
77512622SAlan.Adamson@Sun.COM * we don't expect to see a non-present
77612622SAlan.Adamson@Sun.COM * function, so we will stop walking
77712622SAlan.Adamson@Sun.COM * the function list.
77812622SAlan.Adamson@Sun.COM */
77912622SAlan.Adamson@Sun.COM if (ari_mode == B_TRUE)
78012622SAlan.Adamson@Sun.COM break;
78112622SAlan.Adamson@Sun.COM
78210923SEvan.Yan@Sun.COM if (func)
78310923SEvan.Yan@Sun.COM goto next;
78410923SEvan.Yan@Sun.COM break;
78510923SEvan.Yan@Sun.COM default:
78610923SEvan.Yan@Sun.COM DEBUG3("configure: bus => [%d] "
78710923SEvan.Yan@Sun.COM "slot => [%d] func => [%d]\n",
78810923SEvan.Yan@Sun.COM bus, trans_device, func & 7);
78910923SEvan.Yan@Sun.COM break;
79010923SEvan.Yan@Sun.COM }
79110923SEvan.Yan@Sun.COM
79210923SEvan.Yan@Sun.COM if (rv != PCICFG_SUCCESS)
79310923SEvan.Yan@Sun.COM break;
79410923SEvan.Yan@Sun.COM
79510923SEvan.Yan@Sun.COM if ((new_device = pcicfg_devi_find(devi,
79610923SEvan.Yan@Sun.COM trans_device, (func & 7))) == NULL) {
79710923SEvan.Yan@Sun.COM DEBUG0("Did'nt find device node just created\n");
79810923SEvan.Yan@Sun.COM goto cleanup;
79910923SEvan.Yan@Sun.COM }
80010923SEvan.Yan@Sun.COM
80110923SEvan.Yan@Sun.COM next:
80210923SEvan.Yan@Sun.COM /*
80310923SEvan.Yan@Sun.COM * Determine if ARI Forwarding should be enabled.
80410923SEvan.Yan@Sun.COM */
80510923SEvan.Yan@Sun.COM if (func == 0) {
80610923SEvan.Yan@Sun.COM if ((pcie_ari_supported(devi)
80710923SEvan.Yan@Sun.COM == PCIE_ARI_FORW_SUPPORTED) &&
80810923SEvan.Yan@Sun.COM (pcie_ari_device(new_device) == PCIE_ARI_DEVICE)) {
80910923SEvan.Yan@Sun.COM if (pcie_ari_enable(devi) == DDI_SUCCESS) {
81010923SEvan.Yan@Sun.COM (void) ddi_prop_create(DDI_DEV_T_NONE,
81110923SEvan.Yan@Sun.COM devi, DDI_PROP_CANSLEEP,
81210923SEvan.Yan@Sun.COM "ari-enabled", NULL, 0);
81310923SEvan.Yan@Sun.COM
81410923SEvan.Yan@Sun.COM ari_mode = B_TRUE;
81510923SEvan.Yan@Sun.COM max_function = PCICFG_MAX_ARI_FUNCTION;
81610923SEvan.Yan@Sun.COM }
81710923SEvan.Yan@Sun.COM }
81810923SEvan.Yan@Sun.COM }
81910923SEvan.Yan@Sun.COM
82010923SEvan.Yan@Sun.COM if (ari_mode == B_TRUE) {
82110923SEvan.Yan@Sun.COM int next_function;
82210923SEvan.Yan@Sun.COM
82310923SEvan.Yan@Sun.COM DEBUG0("Next Function - ARI Device\n");
82410923SEvan.Yan@Sun.COM if (pcie_ari_get_next_function(new_device,
82510923SEvan.Yan@Sun.COM &next_function) != DDI_SUCCESS)
82610923SEvan.Yan@Sun.COM goto cleanup;
82710923SEvan.Yan@Sun.COM
82810923SEvan.Yan@Sun.COM /*
82910923SEvan.Yan@Sun.COM * Check if there are more fucntions to probe.
83010923SEvan.Yan@Sun.COM */
83110923SEvan.Yan@Sun.COM if (next_function == 0) {
83210923SEvan.Yan@Sun.COM DEBUG0("Next Function - "
83310923SEvan.Yan@Sun.COM "No more ARI Functions\n");
83410923SEvan.Yan@Sun.COM break;
83510923SEvan.Yan@Sun.COM }
83610923SEvan.Yan@Sun.COM func = next_function;
83710923SEvan.Yan@Sun.COM } else {
83810923SEvan.Yan@Sun.COM func++;
83910923SEvan.Yan@Sun.COM }
84010923SEvan.Yan@Sun.COM
84110923SEvan.Yan@Sun.COM DEBUG1("Next Function - %x\n", func);
84210923SEvan.Yan@Sun.COM }
84310923SEvan.Yan@Sun.COM
84410923SEvan.Yan@Sun.COM ndi_devi_exit(devi, circ);
84510923SEvan.Yan@Sun.COM
84610923SEvan.Yan@Sun.COM if (func == 0)
84710923SEvan.Yan@Sun.COM return (PCICFG_FAILURE); /* probe failed */
84810923SEvan.Yan@Sun.COM else
84910923SEvan.Yan@Sun.COM return (PCICFG_SUCCESS);
85010923SEvan.Yan@Sun.COM
85110923SEvan.Yan@Sun.COM cleanup:
85210923SEvan.Yan@Sun.COM /*
85310923SEvan.Yan@Sun.COM * Clean up a partially created "probe state" tree.
85410923SEvan.Yan@Sun.COM * There are no resources allocated to the in the
85510923SEvan.Yan@Sun.COM * probe state.
85610923SEvan.Yan@Sun.COM */
85710923SEvan.Yan@Sun.COM if (pcie_ari_is_enabled(devi) == PCIE_ARI_FORW_ENABLED)
85810923SEvan.Yan@Sun.COM max_function = PCICFG_MAX_ARI_FUNCTION;
85910923SEvan.Yan@Sun.COM else
86010923SEvan.Yan@Sun.COM max_function = PCICFG_MAX_FUNCTION;
86110923SEvan.Yan@Sun.COM
86210923SEvan.Yan@Sun.COM for (func = 0; func < max_function; func++) {
86310923SEvan.Yan@Sun.COM
86410923SEvan.Yan@Sun.COM if (max_function == PCICFG_MAX_ARI_FUNCTION)
86510923SEvan.Yan@Sun.COM trans_device = func >> 3; /* ARI Device */
86610923SEvan.Yan@Sun.COM else
86710923SEvan.Yan@Sun.COM trans_device = device;
86810923SEvan.Yan@Sun.COM
86910923SEvan.Yan@Sun.COM if ((new_device = pcicfg_devi_find(devi,
87010923SEvan.Yan@Sun.COM trans_device, (func & 0x7))) == NULL) {
87110923SEvan.Yan@Sun.COM DEBUG0("No more devices to clean up\n");
87210923SEvan.Yan@Sun.COM continue;
87310923SEvan.Yan@Sun.COM }
87410923SEvan.Yan@Sun.COM
87510923SEvan.Yan@Sun.COM DEBUG2("Cleaning up device [0x%x] function [0x%x]\n",
87610923SEvan.Yan@Sun.COM trans_device, func & 7);
87710923SEvan.Yan@Sun.COM /*
87810923SEvan.Yan@Sun.COM * If this was a bridge device it will have a
87910923SEvan.Yan@Sun.COM * probe handle - if not, no harm in calling this.
88010923SEvan.Yan@Sun.COM */
88110923SEvan.Yan@Sun.COM (void) pcicfg_destroy_phdl(new_device);
88211245SZhijun.Fu@Sun.COM
88311245SZhijun.Fu@Sun.COM if (is_pcie) {
88411245SZhijun.Fu@Sun.COM /*
88511245SZhijun.Fu@Sun.COM * Free bus_t structure
88611245SZhijun.Fu@Sun.COM */
88711245SZhijun.Fu@Sun.COM if (ddi_get_child(new_device) != NULL)
88811245SZhijun.Fu@Sun.COM pcie_fab_fini_bus(new_device, PCIE_BUS_ALL);
88911245SZhijun.Fu@Sun.COM
89011245SZhijun.Fu@Sun.COM pcie_fini_bus(new_device, PCIE_BUS_ALL);
89111245SZhijun.Fu@Sun.COM }
89210923SEvan.Yan@Sun.COM /*
89310923SEvan.Yan@Sun.COM * This will free up the node
89410923SEvan.Yan@Sun.COM */
89510923SEvan.Yan@Sun.COM (void) ndi_devi_offline(new_device, NDI_DEVI_REMOVE);
89610923SEvan.Yan@Sun.COM }
89710923SEvan.Yan@Sun.COM ndi_devi_exit(devi, circ);
89810923SEvan.Yan@Sun.COM
89910923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
90010923SEvan.Yan@Sun.COM }
90110923SEvan.Yan@Sun.COM
90210923SEvan.Yan@Sun.COM /*
90310923SEvan.Yan@Sun.COM * configure the child nodes of ntbridge. new_device points to ntbridge itself
90410923SEvan.Yan@Sun.COM */
90510923SEvan.Yan@Sun.COM /*ARGSUSED*/
90610923SEvan.Yan@Sun.COM static uint_t
pcicfg_configure_ntbridge(dev_info_t * new_device,uint_t bus,uint_t device)90710923SEvan.Yan@Sun.COM pcicfg_configure_ntbridge(dev_info_t *new_device, uint_t bus, uint_t device)
90810923SEvan.Yan@Sun.COM {
90910923SEvan.Yan@Sun.COM int bus_range[2], rc = PCICFG_FAILURE, rc1, max_devs = 0;
91010923SEvan.Yan@Sun.COM int devno;
91110923SEvan.Yan@Sun.COM dev_info_t *new_ntbridgechild;
91210923SEvan.Yan@Sun.COM ddi_acc_handle_t config_handle;
91310923SEvan.Yan@Sun.COM uint16_t vid;
91410923SEvan.Yan@Sun.COM uint64_t next_bus;
91510923SEvan.Yan@Sun.COM uint64_t blen;
91610923SEvan.Yan@Sun.COM ndi_ra_request_t req;
91710923SEvan.Yan@Sun.COM uint8_t pcie_device_type = 0;
91810923SEvan.Yan@Sun.COM
91910923SEvan.Yan@Sun.COM /*
92010923SEvan.Yan@Sun.COM * If we need to do indirect config, lets create a property here
92110923SEvan.Yan@Sun.COM * to let the child conf map routine know that it has to
92210923SEvan.Yan@Sun.COM * go through the DDI calls, and not assume the devices are
92310923SEvan.Yan@Sun.COM * mapped directly under the host.
92410923SEvan.Yan@Sun.COM */
92510923SEvan.Yan@Sun.COM if ((rc = ndi_prop_update_int(DDI_DEV_T_NONE, new_device,
92610923SEvan.Yan@Sun.COM PCI_DEV_CONF_MAP_PROP, (int)DDI_SUCCESS))
92710923SEvan.Yan@Sun.COM != DDI_SUCCESS) {
92810923SEvan.Yan@Sun.COM
92910923SEvan.Yan@Sun.COM DEBUG0("Cannot create indirect conf map property.\n");
93010923SEvan.Yan@Sun.COM return ((uint_t)PCICFG_FAILURE);
93110923SEvan.Yan@Sun.COM }
93210923SEvan.Yan@Sun.COM if (pci_config_setup(new_device, &config_handle) != DDI_SUCCESS)
93310923SEvan.Yan@Sun.COM return ((uint_t)PCICFG_FAILURE);
93410923SEvan.Yan@Sun.COM /* check if we are PCIe device */
93510923SEvan.Yan@Sun.COM if (pcicfg_pcie_device_type(new_device, config_handle) == DDI_SUCCESS)
93610923SEvan.Yan@Sun.COM pcie_device_type = 1;
93710923SEvan.Yan@Sun.COM pci_config_teardown(&config_handle);
93810923SEvan.Yan@Sun.COM
93910923SEvan.Yan@Sun.COM /* create Bus node properties for ntbridge. */
94010923SEvan.Yan@Sun.COM if (pcicfg_set_busnode_props(new_device, pcie_device_type, -1, -1) !=
94110923SEvan.Yan@Sun.COM PCICFG_SUCCESS) {
94210923SEvan.Yan@Sun.COM DEBUG0("Failed to set busnode props\n");
94310923SEvan.Yan@Sun.COM return (rc);
94410923SEvan.Yan@Sun.COM }
94510923SEvan.Yan@Sun.COM
94610923SEvan.Yan@Sun.COM /* For now: Lets only support one layer of child */
94710923SEvan.Yan@Sun.COM bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
94810923SEvan.Yan@Sun.COM req.ra_len = 1;
94910923SEvan.Yan@Sun.COM if (ndi_ra_alloc(ddi_get_parent(new_device), &req,
95010923SEvan.Yan@Sun.COM &next_bus, &blen, NDI_RA_TYPE_PCI_BUSNUM,
95110923SEvan.Yan@Sun.COM NDI_RA_PASS) != NDI_SUCCESS) {
95210923SEvan.Yan@Sun.COM DEBUG0("ntbridge: Failed to get a bus number\n");
95310923SEvan.Yan@Sun.COM return (rc);
95410923SEvan.Yan@Sun.COM }
95510923SEvan.Yan@Sun.COM
95610923SEvan.Yan@Sun.COM DEBUG1("ntbridge bus range start ->[%d]\n", next_bus);
95710923SEvan.Yan@Sun.COM
95810923SEvan.Yan@Sun.COM /*
95910923SEvan.Yan@Sun.COM * Following will change, as we detect more bridges
96010923SEvan.Yan@Sun.COM * on the way.
96110923SEvan.Yan@Sun.COM */
96210923SEvan.Yan@Sun.COM bus_range[0] = (int)next_bus;
96310923SEvan.Yan@Sun.COM bus_range[1] = (int)next_bus;
96410923SEvan.Yan@Sun.COM
96510923SEvan.Yan@Sun.COM if (ndi_prop_update_int_array(DDI_DEV_T_NONE, new_device,
96610923SEvan.Yan@Sun.COM "bus-range", bus_range, 2) != DDI_SUCCESS) {
96710923SEvan.Yan@Sun.COM DEBUG0("Cannot set ntbridge bus-range property");
96810923SEvan.Yan@Sun.COM return (rc);
96910923SEvan.Yan@Sun.COM }
97010923SEvan.Yan@Sun.COM
97110923SEvan.Yan@Sun.COM /*
97210923SEvan.Yan@Sun.COM * The other interface (away from the host) will be
97310923SEvan.Yan@Sun.COM * initialized by the nexus driver when it loads.
97410923SEvan.Yan@Sun.COM * We just have to set the registers and the nexus driver
97510923SEvan.Yan@Sun.COM * figures out the rest.
97610923SEvan.Yan@Sun.COM */
97710923SEvan.Yan@Sun.COM
97810923SEvan.Yan@Sun.COM /*
97910923SEvan.Yan@Sun.COM * finally, lets load and attach the driver
98010923SEvan.Yan@Sun.COM * before configuring children of ntbridge.
98110923SEvan.Yan@Sun.COM */
98210923SEvan.Yan@Sun.COM rc = ndi_devi_online(new_device, NDI_NO_EVENT|NDI_CONFIG);
98310923SEvan.Yan@Sun.COM if (rc != NDI_SUCCESS) {
98410923SEvan.Yan@Sun.COM cmn_err(CE_WARN,
98510923SEvan.Yan@Sun.COM "pcicfg: Fail: can\'t load non-transparent bridge \
98610923SEvan.Yan@Sun.COM driver.\n");
98710923SEvan.Yan@Sun.COM rc = PCICFG_FAILURE;
98810923SEvan.Yan@Sun.COM return (rc);
98910923SEvan.Yan@Sun.COM }
99010923SEvan.Yan@Sun.COM DEBUG0("pcicfg: Success loading nontransparent bridge nexus driver..");
99110923SEvan.Yan@Sun.COM
99210923SEvan.Yan@Sun.COM /* Now set aside pci resources for our children. */
99310923SEvan.Yan@Sun.COM if (pcicfg_ntbridge_allocate_resources(new_device) !=
99410923SEvan.Yan@Sun.COM PCICFG_SUCCESS) {
99510923SEvan.Yan@Sun.COM max_devs = 0;
99610923SEvan.Yan@Sun.COM rc = PCICFG_FAILURE;
99710923SEvan.Yan@Sun.COM } else
99810923SEvan.Yan@Sun.COM max_devs = PCICFG_MAX_DEVICE;
99910923SEvan.Yan@Sun.COM
100010923SEvan.Yan@Sun.COM /* Probe devices on 2nd bus */
100110923SEvan.Yan@Sun.COM for (devno = pcicfg_start_devno; devno < max_devs; devno++) {
100210923SEvan.Yan@Sun.COM
100310923SEvan.Yan@Sun.COM if (ndi_devi_alloc(new_device, DEVI_PSEUDO_NEXNAME,
100410923SEvan.Yan@Sun.COM (pnode_t)DEVI_SID_NODEID, &new_ntbridgechild)
100510923SEvan.Yan@Sun.COM != NDI_SUCCESS) {
100610923SEvan.Yan@Sun.COM
100710923SEvan.Yan@Sun.COM DEBUG0("pcicfg: Failed to alloc test node\n");
100810923SEvan.Yan@Sun.COM rc = PCICFG_FAILURE;
100910923SEvan.Yan@Sun.COM break;
101010923SEvan.Yan@Sun.COM }
101110923SEvan.Yan@Sun.COM
101210923SEvan.Yan@Sun.COM if (pcicfg_add_config_reg(new_ntbridgechild, next_bus, devno, 0)
101310923SEvan.Yan@Sun.COM != DDI_PROP_SUCCESS) {
101410923SEvan.Yan@Sun.COM cmn_err(CE_WARN,
101510923SEvan.Yan@Sun.COM "Failed to add conf reg for ntbridge child.\n");
101610923SEvan.Yan@Sun.COM (void) ndi_devi_free(new_ntbridgechild);
101710923SEvan.Yan@Sun.COM rc = PCICFG_FAILURE;
101810923SEvan.Yan@Sun.COM break;
101910923SEvan.Yan@Sun.COM }
102010923SEvan.Yan@Sun.COM
102110923SEvan.Yan@Sun.COM if ((rc = pci_config_setup(new_ntbridgechild,
102210923SEvan.Yan@Sun.COM &config_handle)) != PCICFG_SUCCESS) {
102310923SEvan.Yan@Sun.COM cmn_err(CE_WARN,
102410923SEvan.Yan@Sun.COM "Cannot map ntbridge child %x\n", devno);
102510923SEvan.Yan@Sun.COM (void) ndi_devi_free(new_ntbridgechild);
102610923SEvan.Yan@Sun.COM rc = PCICFG_FAILURE;
102710923SEvan.Yan@Sun.COM break;
102810923SEvan.Yan@Sun.COM }
102910923SEvan.Yan@Sun.COM
103010923SEvan.Yan@Sun.COM /*
103110923SEvan.Yan@Sun.COM * See if there is any PCI HW at this location
103210923SEvan.Yan@Sun.COM * by reading the Vendor ID. If it returns with 0xffff
103310923SEvan.Yan@Sun.COM * then there is no hardware at this location.
103410923SEvan.Yan@Sun.COM */
103510923SEvan.Yan@Sun.COM vid = pci_config_get16(config_handle, PCI_CONF_VENID);
103610923SEvan.Yan@Sun.COM
103710923SEvan.Yan@Sun.COM pci_config_teardown(&config_handle);
103810923SEvan.Yan@Sun.COM (void) ndi_devi_free(new_ntbridgechild);
103910923SEvan.Yan@Sun.COM if (vid == 0xffff)
104010923SEvan.Yan@Sun.COM continue;
104110923SEvan.Yan@Sun.COM
104210923SEvan.Yan@Sun.COM /* Lets fake attachments points for each child, */
104310923SEvan.Yan@Sun.COM if (pcicfg_configure(new_device, devno, PCICFG_ALL_FUNC, 0)
104410923SEvan.Yan@Sun.COM != PCICFG_SUCCESS) {
104510923SEvan.Yan@Sun.COM int old_dev = pcicfg_start_devno;
104610923SEvan.Yan@Sun.COM
104710923SEvan.Yan@Sun.COM cmn_err(CE_WARN,
104810923SEvan.Yan@Sun.COM "Error configuring ntbridge child dev=%d\n", devno);
104910923SEvan.Yan@Sun.COM
105010923SEvan.Yan@Sun.COM rc = PCICFG_FAILURE;
105110923SEvan.Yan@Sun.COM while (old_dev != devno) {
105210923SEvan.Yan@Sun.COM if (pcicfg_ntbridge_unconfigure_child(
105310923SEvan.Yan@Sun.COM new_device, old_dev) == PCICFG_FAILURE)
105410923SEvan.Yan@Sun.COM
105510923SEvan.Yan@Sun.COM cmn_err(CE_WARN,
105610923SEvan.Yan@Sun.COM "Unconfig Error ntbridge child "
105710923SEvan.Yan@Sun.COM "dev=%d\n", old_dev);
105810923SEvan.Yan@Sun.COM old_dev++;
105910923SEvan.Yan@Sun.COM }
106010923SEvan.Yan@Sun.COM break;
106110923SEvan.Yan@Sun.COM }
106210923SEvan.Yan@Sun.COM } /* devno loop */
106310923SEvan.Yan@Sun.COM DEBUG1("ntbridge: finish probing 2nd bus, rc=%d\n", rc);
106410923SEvan.Yan@Sun.COM
106510923SEvan.Yan@Sun.COM if (rc != PCICFG_FAILURE)
106610923SEvan.Yan@Sun.COM rc = pcicfg_ntbridge_configure_done(new_device);
106710923SEvan.Yan@Sun.COM else {
106810923SEvan.Yan@Sun.COM pcicfg_phdl_t *entry = pcicfg_find_phdl(new_device);
106910923SEvan.Yan@Sun.COM uint_t *bus;
107010923SEvan.Yan@Sun.COM int k;
107110923SEvan.Yan@Sun.COM
107210923SEvan.Yan@Sun.COM if (ddi_getlongprop(DDI_DEV_T_ANY, new_device,
107310923SEvan.Yan@Sun.COM DDI_PROP_DONTPASS, "bus-range", (caddr_t)&bus,
107410923SEvan.Yan@Sun.COM &k) != DDI_PROP_SUCCESS) {
107510923SEvan.Yan@Sun.COM DEBUG0("Failed to read bus-range property\n");
107610923SEvan.Yan@Sun.COM rc = PCICFG_FAILURE;
107710923SEvan.Yan@Sun.COM return (rc);
107810923SEvan.Yan@Sun.COM }
107910923SEvan.Yan@Sun.COM
108010923SEvan.Yan@Sun.COM DEBUG2("Need to free bus [%d] range [%d]\n",
108110923SEvan.Yan@Sun.COM bus[0], bus[1] - bus[0] + 1);
108210923SEvan.Yan@Sun.COM
108310923SEvan.Yan@Sun.COM if (ndi_ra_free(ddi_get_parent(new_device),
108410923SEvan.Yan@Sun.COM (uint64_t)bus[0], (uint64_t)(bus[1] - bus[0] + 1),
108510923SEvan.Yan@Sun.COM NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS) != NDI_SUCCESS) {
108610923SEvan.Yan@Sun.COM DEBUG0("Failed to free a bus number\n");
108710923SEvan.Yan@Sun.COM rc = PCICFG_FAILURE;
108810923SEvan.Yan@Sun.COM /*
108910923SEvan.Yan@Sun.COM * Don't forget to free up memory from ddi_getlongprop
109010923SEvan.Yan@Sun.COM */
109110923SEvan.Yan@Sun.COM kmem_free((caddr_t)bus, k);
109210923SEvan.Yan@Sun.COM
109310923SEvan.Yan@Sun.COM return (rc);
109410923SEvan.Yan@Sun.COM }
109510923SEvan.Yan@Sun.COM
109610923SEvan.Yan@Sun.COM /*
109710923SEvan.Yan@Sun.COM * Since no memory allocations are done for non transparent
109810923SEvan.Yan@Sun.COM * bridges (but instead we just set the handle with the
109910923SEvan.Yan@Sun.COM * already allocated memory, we just need to reset the
110010923SEvan.Yan@Sun.COM * following values before calling the destroy_phdl()
110110923SEvan.Yan@Sun.COM * function next, otherwise the it will try to free
110210923SEvan.Yan@Sun.COM * memory allocated as in case of a transparent bridge.
110310923SEvan.Yan@Sun.COM */
110410923SEvan.Yan@Sun.COM entry->memory_len = 0;
110510923SEvan.Yan@Sun.COM entry->io_len = 0;
110610923SEvan.Yan@Sun.COM /* the following will free hole data. */
110710923SEvan.Yan@Sun.COM (void) pcicfg_destroy_phdl(new_device);
110810923SEvan.Yan@Sun.COM /*
110910923SEvan.Yan@Sun.COM * Don't forget to free up memory from ddi_getlongprop
111010923SEvan.Yan@Sun.COM */
111110923SEvan.Yan@Sun.COM kmem_free((caddr_t)bus, k);
111210923SEvan.Yan@Sun.COM }
111310923SEvan.Yan@Sun.COM
111410923SEvan.Yan@Sun.COM /*
111510923SEvan.Yan@Sun.COM * Unload driver just in case child configure failed!
111610923SEvan.Yan@Sun.COM */
111710923SEvan.Yan@Sun.COM rc1 = ndi_devi_offline(new_device, NDI_NO_EVENT);
111810923SEvan.Yan@Sun.COM DEBUG1("pcicfg: now unloading the ntbridge driver. rc1=%d\n", rc1);
111910923SEvan.Yan@Sun.COM if (rc1 != NDI_SUCCESS) {
112010923SEvan.Yan@Sun.COM cmn_err(CE_WARN,
112110923SEvan.Yan@Sun.COM "pcicfg: can\'t unload ntbridge driver children.\n");
112210923SEvan.Yan@Sun.COM rc = PCICFG_FAILURE;
112310923SEvan.Yan@Sun.COM }
112410923SEvan.Yan@Sun.COM
112510923SEvan.Yan@Sun.COM return (rc);
112610923SEvan.Yan@Sun.COM }
112710923SEvan.Yan@Sun.COM
112810923SEvan.Yan@Sun.COM static int
pcicfg_ntbridge_allocate_resources(dev_info_t * dip)112910923SEvan.Yan@Sun.COM pcicfg_ntbridge_allocate_resources(dev_info_t *dip)
113010923SEvan.Yan@Sun.COM {
113110923SEvan.Yan@Sun.COM pcicfg_phdl_t *phdl;
113210923SEvan.Yan@Sun.COM ndi_ra_request_t *mem_request;
113310923SEvan.Yan@Sun.COM ndi_ra_request_t *io_request;
113410923SEvan.Yan@Sun.COM uint64_t boundbase, boundlen;
113510923SEvan.Yan@Sun.COM
113610923SEvan.Yan@Sun.COM phdl = pcicfg_find_phdl(dip);
113710923SEvan.Yan@Sun.COM ASSERT(phdl);
113810923SEvan.Yan@Sun.COM
113910923SEvan.Yan@Sun.COM mem_request = &phdl->mem_req;
114010923SEvan.Yan@Sun.COM io_request = &phdl->io_req;
114110923SEvan.Yan@Sun.COM
114210923SEvan.Yan@Sun.COM phdl->error = PCICFG_SUCCESS;
114310923SEvan.Yan@Sun.COM
114410923SEvan.Yan@Sun.COM /* Set Memory space handle for ntbridge */
114510923SEvan.Yan@Sun.COM if (pcicfg_get_ntbridge_child_range(dip, &boundbase, &boundlen,
114610923SEvan.Yan@Sun.COM PCI_BASE_SPACE_MEM) != DDI_SUCCESS) {
114710923SEvan.Yan@Sun.COM cmn_err(CE_WARN,
114810923SEvan.Yan@Sun.COM "ntbridge: Mem resource information failure\n");
114910923SEvan.Yan@Sun.COM phdl->memory_len = 0;
115010923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
115110923SEvan.Yan@Sun.COM }
115210923SEvan.Yan@Sun.COM mem_request->ra_boundbase = boundbase;
115310923SEvan.Yan@Sun.COM mem_request->ra_boundlen = boundbase + boundlen;
115410923SEvan.Yan@Sun.COM mem_request->ra_len = boundlen;
115510923SEvan.Yan@Sun.COM mem_request->ra_align_mask =
115610923SEvan.Yan@Sun.COM PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */
115710923SEvan.Yan@Sun.COM mem_request->ra_flags |= NDI_RA_ALLOC_BOUNDED;
115810923SEvan.Yan@Sun.COM
115910923SEvan.Yan@Sun.COM /*
116010923SEvan.Yan@Sun.COM * mem_request->ra_len =
116110923SEvan.Yan@Sun.COM * PCICFG_ROUND_UP(mem_request->ra_len, PCICFG_MEMGRAN);
116210923SEvan.Yan@Sun.COM */
116310923SEvan.Yan@Sun.COM
116410923SEvan.Yan@Sun.COM phdl->memory_base = phdl->memory_last = boundbase;
116510923SEvan.Yan@Sun.COM phdl->memory_len = boundlen;
116610923SEvan.Yan@Sun.COM phdl->mem_hole.start = phdl->memory_base;
116710923SEvan.Yan@Sun.COM phdl->mem_hole.len = mem_request->ra_len;
116810923SEvan.Yan@Sun.COM phdl->mem_hole.next = (hole_t *)NULL;
116910923SEvan.Yan@Sun.COM
117010923SEvan.Yan@Sun.COM DEBUG2("Connector requested [0x%llx], needs [0x%llx] bytes of memory\n",
117110923SEvan.Yan@Sun.COM boundlen, mem_request->ra_len);
117210923SEvan.Yan@Sun.COM
117310923SEvan.Yan@Sun.COM /* set up a memory resource map for NT bridge */
117410923SEvan.Yan@Sun.COM if (ndi_ra_map_setup(dip, NDI_RA_TYPE_MEM) == NDI_FAILURE) {
117510923SEvan.Yan@Sun.COM DEBUG0("Can not setup ntbridge memory resource map\n");
117610923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
117710923SEvan.Yan@Sun.COM }
117810923SEvan.Yan@Sun.COM /* initialize the memory map */
117910923SEvan.Yan@Sun.COM if (ndi_ra_free(dip, boundbase, boundlen, NDI_RA_TYPE_MEM,
118010923SEvan.Yan@Sun.COM NDI_RA_PASS) != NDI_SUCCESS) {
118110923SEvan.Yan@Sun.COM DEBUG0("Can not initalize ntbridge memory resource map\n");
118210923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
118310923SEvan.Yan@Sun.COM }
118410923SEvan.Yan@Sun.COM /* Set IO space handle for ntbridge */
118510923SEvan.Yan@Sun.COM if (pcicfg_get_ntbridge_child_range(dip, &boundbase, &boundlen,
118610923SEvan.Yan@Sun.COM PCI_BASE_SPACE_IO) != DDI_SUCCESS) {
118710923SEvan.Yan@Sun.COM cmn_err(CE_WARN, "ntbridge: IO resource information failure\n");
118810923SEvan.Yan@Sun.COM phdl->io_len = 0;
118910923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
119010923SEvan.Yan@Sun.COM }
119110923SEvan.Yan@Sun.COM io_request->ra_len = boundlen;
119210923SEvan.Yan@Sun.COM io_request->ra_align_mask =
119310923SEvan.Yan@Sun.COM PCICFG_IOGRAN - 1; /* 4K alignment on I/O space */
119410923SEvan.Yan@Sun.COM io_request->ra_boundbase = boundbase;
119510923SEvan.Yan@Sun.COM io_request->ra_boundlen = boundbase + boundlen;
119610923SEvan.Yan@Sun.COM io_request->ra_flags |= NDI_RA_ALLOC_BOUNDED;
119710923SEvan.Yan@Sun.COM
119810923SEvan.Yan@Sun.COM /*
119910923SEvan.Yan@Sun.COM * io_request->ra_len =
120010923SEvan.Yan@Sun.COM * PCICFG_ROUND_UP(io_request->ra_len, PCICFG_IOGRAN);
120110923SEvan.Yan@Sun.COM */
120210923SEvan.Yan@Sun.COM
120310923SEvan.Yan@Sun.COM phdl->io_base = phdl->io_last = (uint32_t)boundbase;
120410923SEvan.Yan@Sun.COM phdl->io_len = (uint32_t)boundlen;
120510923SEvan.Yan@Sun.COM phdl->io_hole.start = phdl->io_base;
120610923SEvan.Yan@Sun.COM phdl->io_hole.len = io_request->ra_len;
120710923SEvan.Yan@Sun.COM phdl->io_hole.next = (hole_t *)NULL;
120810923SEvan.Yan@Sun.COM
120910923SEvan.Yan@Sun.COM DEBUG2("Connector requested [0x%llx], needs [0x%llx] bytes of IO\n",
121010923SEvan.Yan@Sun.COM boundlen, io_request->ra_len);
121110923SEvan.Yan@Sun.COM
121210923SEvan.Yan@Sun.COM DEBUG2("MEMORY BASE = [0x%x] length [0x%x]\n",
121310923SEvan.Yan@Sun.COM phdl->memory_base, phdl->memory_len);
121410923SEvan.Yan@Sun.COM DEBUG2("IO BASE = [0x%x] length [0x%x]\n",
121510923SEvan.Yan@Sun.COM phdl->io_base, phdl->io_len);
121610923SEvan.Yan@Sun.COM
121710923SEvan.Yan@Sun.COM /* set up a IO resource map for NT bridge */
121810923SEvan.Yan@Sun.COM if (ndi_ra_map_setup(dip, NDI_RA_TYPE_IO) == NDI_FAILURE) {
121910923SEvan.Yan@Sun.COM DEBUG0("Can not setup ntbridge memory resource map\n");
122010923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
122110923SEvan.Yan@Sun.COM }
122210923SEvan.Yan@Sun.COM /* initialize the IO map */
122310923SEvan.Yan@Sun.COM if (ndi_ra_free(dip, boundbase, boundlen, NDI_RA_TYPE_IO,
122410923SEvan.Yan@Sun.COM NDI_RA_PASS) != NDI_SUCCESS) {
122510923SEvan.Yan@Sun.COM DEBUG0("Can not initalize ntbridge memory resource map\n");
122610923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
122710923SEvan.Yan@Sun.COM }
122810923SEvan.Yan@Sun.COM
122910923SEvan.Yan@Sun.COM return (PCICFG_SUCCESS);
123010923SEvan.Yan@Sun.COM }
123110923SEvan.Yan@Sun.COM
123210923SEvan.Yan@Sun.COM static int
pcicfg_ntbridge_configure_done(dev_info_t * dip)123310923SEvan.Yan@Sun.COM pcicfg_ntbridge_configure_done(dev_info_t *dip)
123410923SEvan.Yan@Sun.COM {
123510923SEvan.Yan@Sun.COM pcicfg_range_t range[PCICFG_RANGE_LEN];
123610923SEvan.Yan@Sun.COM pcicfg_phdl_t *entry;
123710923SEvan.Yan@Sun.COM uint_t len;
123810923SEvan.Yan@Sun.COM pcicfg_bus_range_t bus_range;
123910923SEvan.Yan@Sun.COM int new_bus_range[2];
124010923SEvan.Yan@Sun.COM
124110923SEvan.Yan@Sun.COM DEBUG1("Configuring children for %llx\n", dip);
124210923SEvan.Yan@Sun.COM
124310923SEvan.Yan@Sun.COM entry = pcicfg_find_phdl(dip);
124410923SEvan.Yan@Sun.COM ASSERT(entry);
124510923SEvan.Yan@Sun.COM
124610923SEvan.Yan@Sun.COM bzero((caddr_t)range,
124710923SEvan.Yan@Sun.COM sizeof (pcicfg_range_t) * PCICFG_RANGE_LEN);
124810923SEvan.Yan@Sun.COM range[1].child_hi = range[1].parent_hi |=
124910923SEvan.Yan@Sun.COM (PCI_REG_REL_M | PCI_ADDR_MEM32);
125010923SEvan.Yan@Sun.COM range[1].child_lo = range[1].parent_lo = (uint32_t)entry->memory_base;
125110923SEvan.Yan@Sun.COM
125210923SEvan.Yan@Sun.COM range[0].child_hi = range[0].parent_hi |=
125310923SEvan.Yan@Sun.COM (PCI_REG_REL_M | PCI_ADDR_IO);
125410923SEvan.Yan@Sun.COM range[0].child_lo = range[0].parent_lo = (uint32_t)entry->io_base;
125510923SEvan.Yan@Sun.COM
125610923SEvan.Yan@Sun.COM len = sizeof (pcicfg_bus_range_t);
125710923SEvan.Yan@Sun.COM if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
125810923SEvan.Yan@Sun.COM "bus-range", (caddr_t)&bus_range, (int *)&len) != DDI_SUCCESS) {
125910923SEvan.Yan@Sun.COM DEBUG0("no bus-range property\n");
126010923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
126110923SEvan.Yan@Sun.COM }
126210923SEvan.Yan@Sun.COM
126310923SEvan.Yan@Sun.COM new_bus_range[0] = bus_range.lo; /* primary bus number */
126410923SEvan.Yan@Sun.COM if (entry->highest_bus) { /* secondary bus number */
126510923SEvan.Yan@Sun.COM if (entry->highest_bus < bus_range.lo) {
126610923SEvan.Yan@Sun.COM cmn_err(CE_WARN,
126710923SEvan.Yan@Sun.COM "ntbridge bus range invalid !(%d,%d)\n",
126810923SEvan.Yan@Sun.COM bus_range.lo, entry->highest_bus);
126910923SEvan.Yan@Sun.COM new_bus_range[1] = bus_range.lo + entry->highest_bus;
127010923SEvan.Yan@Sun.COM }
127110923SEvan.Yan@Sun.COM else
127210923SEvan.Yan@Sun.COM new_bus_range[1] = entry->highest_bus;
127310923SEvan.Yan@Sun.COM }
127410923SEvan.Yan@Sun.COM else
127510923SEvan.Yan@Sun.COM new_bus_range[1] = bus_range.hi;
127610923SEvan.Yan@Sun.COM
127710923SEvan.Yan@Sun.COM DEBUG2("ntbridge: bus range lo=%x, hi=%x\n",
127810923SEvan.Yan@Sun.COM new_bus_range[0], new_bus_range[1]);
127910923SEvan.Yan@Sun.COM
128010923SEvan.Yan@Sun.COM if (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
128110923SEvan.Yan@Sun.COM "bus-range", new_bus_range, 2) != DDI_SUCCESS) {
128210923SEvan.Yan@Sun.COM DEBUG0("Failed to set bus-range property");
128310923SEvan.Yan@Sun.COM entry->error = PCICFG_FAILURE;
128410923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
128510923SEvan.Yan@Sun.COM }
128610923SEvan.Yan@Sun.COM
128710923SEvan.Yan@Sun.COM #ifdef DEBUG
128810923SEvan.Yan@Sun.COM {
128910923SEvan.Yan@Sun.COM uint64_t unused;
129010923SEvan.Yan@Sun.COM unused = pcicfg_unused_space(&entry->io_hole, &len);
129110923SEvan.Yan@Sun.COM DEBUG2("ntbridge: Unused IO space %llx bytes over %d holes\n",
129210923SEvan.Yan@Sun.COM unused, len);
129310923SEvan.Yan@Sun.COM }
129410923SEvan.Yan@Sun.COM #endif
129510923SEvan.Yan@Sun.COM
129610923SEvan.Yan@Sun.COM range[0].size_lo = entry->io_len;
129710923SEvan.Yan@Sun.COM if (pcicfg_update_ranges_prop(dip, &range[0])) {
129810923SEvan.Yan@Sun.COM DEBUG0("Failed to update ranges (i/o)\n");
129910923SEvan.Yan@Sun.COM entry->error = PCICFG_FAILURE;
130010923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
130110923SEvan.Yan@Sun.COM }
130210923SEvan.Yan@Sun.COM
130310923SEvan.Yan@Sun.COM #ifdef DEBUG
130410923SEvan.Yan@Sun.COM {
130510923SEvan.Yan@Sun.COM uint64_t unused;
130610923SEvan.Yan@Sun.COM unused = pcicfg_unused_space(&entry->mem_hole, &len);
130710923SEvan.Yan@Sun.COM DEBUG2("ntbridge: Unused Mem space %llx bytes over %d holes\n",
130810923SEvan.Yan@Sun.COM unused, len);
130910923SEvan.Yan@Sun.COM }
131010923SEvan.Yan@Sun.COM #endif
131110923SEvan.Yan@Sun.COM
131210923SEvan.Yan@Sun.COM range[1].size_lo = entry->memory_len;
131310923SEvan.Yan@Sun.COM if (pcicfg_update_ranges_prop(dip, &range[1])) {
131410923SEvan.Yan@Sun.COM DEBUG0("Failed to update ranges (memory)\n");
131510923SEvan.Yan@Sun.COM entry->error = PCICFG_FAILURE;
131610923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
131710923SEvan.Yan@Sun.COM }
131810923SEvan.Yan@Sun.COM
131910923SEvan.Yan@Sun.COM return (PCICFG_SUCCESS);
132010923SEvan.Yan@Sun.COM }
132110923SEvan.Yan@Sun.COM
132210923SEvan.Yan@Sun.COM static int
pcicfg_ntbridge_unconfigure_child(dev_info_t * new_device,uint_t devno)132310923SEvan.Yan@Sun.COM pcicfg_ntbridge_unconfigure_child(dev_info_t *new_device, uint_t devno)
132410923SEvan.Yan@Sun.COM {
132510923SEvan.Yan@Sun.COM
132610923SEvan.Yan@Sun.COM dev_info_t *new_ntbridgechild;
132710923SEvan.Yan@Sun.COM int len, bus;
132810923SEvan.Yan@Sun.COM uint16_t vid;
132910923SEvan.Yan@Sun.COM ddi_acc_handle_t config_handle;
133010923SEvan.Yan@Sun.COM pcicfg_bus_range_t pci_bus_range;
133110923SEvan.Yan@Sun.COM
133210923SEvan.Yan@Sun.COM len = sizeof (pcicfg_bus_range_t);
133310923SEvan.Yan@Sun.COM if (ddi_getlongprop_buf(DDI_DEV_T_ANY, new_device, DDI_PROP_DONTPASS,
133410923SEvan.Yan@Sun.COM "bus-range", (caddr_t)&pci_bus_range, &len) != DDI_SUCCESS) {
133510923SEvan.Yan@Sun.COM DEBUG0("no bus-range property\n");
133610923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
133710923SEvan.Yan@Sun.COM }
133810923SEvan.Yan@Sun.COM
133910923SEvan.Yan@Sun.COM bus = pci_bus_range.lo; /* primary bus number of this bus node */
134010923SEvan.Yan@Sun.COM
134110923SEvan.Yan@Sun.COM if (ndi_devi_alloc(new_device, DEVI_PSEUDO_NEXNAME,
134210923SEvan.Yan@Sun.COM (pnode_t)DEVI_SID_NODEID, &new_ntbridgechild) != NDI_SUCCESS) {
134310923SEvan.Yan@Sun.COM
134410923SEvan.Yan@Sun.COM DEBUG0("pcicfg: Failed to alloc test node\n");
134510923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
134610923SEvan.Yan@Sun.COM }
134710923SEvan.Yan@Sun.COM
134810923SEvan.Yan@Sun.COM if (pcicfg_add_config_reg(new_ntbridgechild, bus, devno, 0)
134910923SEvan.Yan@Sun.COM != DDI_PROP_SUCCESS) {
135010923SEvan.Yan@Sun.COM cmn_err(CE_WARN,
135110923SEvan.Yan@Sun.COM "Unconfigure: Failed to add conf reg prop for ntbridge "
135210923SEvan.Yan@Sun.COM "child.\n");
135310923SEvan.Yan@Sun.COM (void) ndi_devi_free(new_ntbridgechild);
135410923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
135510923SEvan.Yan@Sun.COM }
135610923SEvan.Yan@Sun.COM
135710923SEvan.Yan@Sun.COM if (pcicfg_config_setup(new_ntbridgechild, &config_handle)
135810923SEvan.Yan@Sun.COM != DDI_SUCCESS) {
135910923SEvan.Yan@Sun.COM cmn_err(CE_WARN,
136010923SEvan.Yan@Sun.COM "pcicfg: Cannot map ntbridge child %x\n", devno);
136110923SEvan.Yan@Sun.COM (void) ndi_devi_free(new_ntbridgechild);
136210923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
136310923SEvan.Yan@Sun.COM }
136410923SEvan.Yan@Sun.COM
136510923SEvan.Yan@Sun.COM /*
136610923SEvan.Yan@Sun.COM * See if there is any PCI HW at this location
136710923SEvan.Yan@Sun.COM * by reading the Vendor ID. If it returns with 0xffff
136810923SEvan.Yan@Sun.COM * then there is no hardware at this location.
136910923SEvan.Yan@Sun.COM */
137010923SEvan.Yan@Sun.COM vid = pci_config_get16(config_handle, PCI_CONF_VENID);
137110923SEvan.Yan@Sun.COM
137210923SEvan.Yan@Sun.COM pci_config_teardown(&config_handle);
137310923SEvan.Yan@Sun.COM (void) ndi_devi_free(new_ntbridgechild);
137410923SEvan.Yan@Sun.COM if (vid == 0xffff)
137510923SEvan.Yan@Sun.COM return (PCICFG_NODEVICE);
137610923SEvan.Yan@Sun.COM
137710923SEvan.Yan@Sun.COM return (pcicfg_unconfigure(new_device, devno, PCICFG_ALL_FUNC, 0));
137810923SEvan.Yan@Sun.COM }
137910923SEvan.Yan@Sun.COM
138010923SEvan.Yan@Sun.COM static int
pcicfg_ntbridge_unconfigure(dev_info_t * dip)138110923SEvan.Yan@Sun.COM pcicfg_ntbridge_unconfigure(dev_info_t *dip)
138210923SEvan.Yan@Sun.COM {
138310923SEvan.Yan@Sun.COM pcicfg_phdl_t *entry = pcicfg_find_phdl(dip);
138410923SEvan.Yan@Sun.COM uint_t *bus;
138510923SEvan.Yan@Sun.COM int k, rc = PCICFG_FAILURE;
138610923SEvan.Yan@Sun.COM
138710923SEvan.Yan@Sun.COM if (entry->memory_len)
138810923SEvan.Yan@Sun.COM if (ndi_ra_map_destroy(dip, NDI_RA_TYPE_MEM) == NDI_FAILURE) {
138910923SEvan.Yan@Sun.COM DEBUG1("cannot destroy ntbridge memory map size=%x\n",
139010923SEvan.Yan@Sun.COM entry->memory_len);
139110923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
139210923SEvan.Yan@Sun.COM }
139310923SEvan.Yan@Sun.COM if (entry->io_len)
139410923SEvan.Yan@Sun.COM if (ndi_ra_map_destroy(dip, NDI_RA_TYPE_IO) == NDI_FAILURE) {
139510923SEvan.Yan@Sun.COM DEBUG1("cannot destroy ntbridge io map size=%x\n",
139610923SEvan.Yan@Sun.COM entry->io_len);
139710923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
139810923SEvan.Yan@Sun.COM }
139910923SEvan.Yan@Sun.COM if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
140010923SEvan.Yan@Sun.COM DDI_PROP_DONTPASS, "bus-range", (caddr_t)&bus,
140110923SEvan.Yan@Sun.COM &k) != DDI_PROP_SUCCESS) {
140210923SEvan.Yan@Sun.COM DEBUG0("ntbridge: Failed to read bus-range property\n");
140310923SEvan.Yan@Sun.COM return (rc);
140410923SEvan.Yan@Sun.COM }
140510923SEvan.Yan@Sun.COM
140610923SEvan.Yan@Sun.COM DEBUG2("ntbridge: Need to free bus [%d] range [%d]\n",
140710923SEvan.Yan@Sun.COM bus[0], bus[1] - bus[0] + 1);
140810923SEvan.Yan@Sun.COM
140910923SEvan.Yan@Sun.COM if (ndi_ra_free(ddi_get_parent(dip),
141010923SEvan.Yan@Sun.COM (uint64_t)bus[0], (uint64_t)(bus[1] - bus[0] + 1),
141110923SEvan.Yan@Sun.COM NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS) != NDI_SUCCESS) {
141210923SEvan.Yan@Sun.COM DEBUG0("ntbridge: Failed to free a bus number\n");
141310923SEvan.Yan@Sun.COM /*
141410923SEvan.Yan@Sun.COM * Don't forget to free up memory from ddi_getlongprop
141510923SEvan.Yan@Sun.COM */
141610923SEvan.Yan@Sun.COM kmem_free((caddr_t)bus, k);
141710923SEvan.Yan@Sun.COM
141810923SEvan.Yan@Sun.COM return (rc);
141910923SEvan.Yan@Sun.COM }
142010923SEvan.Yan@Sun.COM
142110923SEvan.Yan@Sun.COM /*
142210923SEvan.Yan@Sun.COM * Don't forget to free up memory from ddi_getlongprop
142310923SEvan.Yan@Sun.COM */
142410923SEvan.Yan@Sun.COM kmem_free((caddr_t)bus, k);
142510923SEvan.Yan@Sun.COM
142610923SEvan.Yan@Sun.COM /*
142710923SEvan.Yan@Sun.COM * Since our resources will be freed at the parent level,
142810923SEvan.Yan@Sun.COM * just reset these values.
142910923SEvan.Yan@Sun.COM */
143010923SEvan.Yan@Sun.COM entry->memory_len = 0;
143110923SEvan.Yan@Sun.COM entry->io_len = 0;
143210923SEvan.Yan@Sun.COM /* the following will also free hole data. */
143310923SEvan.Yan@Sun.COM return (pcicfg_destroy_phdl(dip));
143410923SEvan.Yan@Sun.COM
143510923SEvan.Yan@Sun.COM }
143610923SEvan.Yan@Sun.COM
143710923SEvan.Yan@Sun.COM static int
pcicfg_is_ntbridge(dev_info_t * dip)143810923SEvan.Yan@Sun.COM pcicfg_is_ntbridge(dev_info_t *dip)
143910923SEvan.Yan@Sun.COM {
144010923SEvan.Yan@Sun.COM ddi_acc_handle_t config_handle;
144110923SEvan.Yan@Sun.COM uint8_t class, subclass;
144210923SEvan.Yan@Sun.COM int rc = DDI_SUCCESS;
144310923SEvan.Yan@Sun.COM
144410923SEvan.Yan@Sun.COM if (pcicfg_config_setup(dip, &config_handle) != DDI_SUCCESS) {
144510923SEvan.Yan@Sun.COM cmn_err(CE_WARN,
144610923SEvan.Yan@Sun.COM "pcicfg: cannot map config space, to get map type\n");
144710923SEvan.Yan@Sun.COM return (DDI_FAILURE);
144810923SEvan.Yan@Sun.COM }
144910923SEvan.Yan@Sun.COM class = pci_config_get8(config_handle, PCI_CONF_BASCLASS);
145010923SEvan.Yan@Sun.COM subclass = pci_config_get8(config_handle, PCI_CONF_SUBCLASS);
145110923SEvan.Yan@Sun.COM
145210923SEvan.Yan@Sun.COM /* check for class=6, subclass=9, for non transparent bridges. */
145310923SEvan.Yan@Sun.COM if ((class != PCI_CLASS_BRIDGE) || (subclass != PCI_BRIDGE_STBRIDGE))
145410923SEvan.Yan@Sun.COM rc = DDI_FAILURE;
145510923SEvan.Yan@Sun.COM
145610923SEvan.Yan@Sun.COM DEBUG3("pcicfg: checking device %x,%x for indirect map. rc=%d\n",
145710923SEvan.Yan@Sun.COM pci_config_get16(config_handle, PCI_CONF_VENID),
145810923SEvan.Yan@Sun.COM pci_config_get16(config_handle, PCI_CONF_DEVID),
145910923SEvan.Yan@Sun.COM rc);
146010923SEvan.Yan@Sun.COM pci_config_teardown(&config_handle);
146110923SEvan.Yan@Sun.COM return (rc);
146210923SEvan.Yan@Sun.COM }
146310923SEvan.Yan@Sun.COM
146410923SEvan.Yan@Sun.COM /*
146510923SEvan.Yan@Sun.COM * this function is called only for SPARC platforms, where we may have
146610923SEvan.Yan@Sun.COM * a mix n' match of direct vs indirectly mapped configuration space.
146710923SEvan.Yan@Sun.COM * On x86, this function does not get called. We always return TRUE
146810923SEvan.Yan@Sun.COM * via a macro for x86.
146910923SEvan.Yan@Sun.COM */
147010923SEvan.Yan@Sun.COM /*ARGSUSED*/
147110923SEvan.Yan@Sun.COM static int
pcicfg_indirect_map(dev_info_t * dip)147210923SEvan.Yan@Sun.COM pcicfg_indirect_map(dev_info_t *dip)
147310923SEvan.Yan@Sun.COM {
147410923SEvan.Yan@Sun.COM #if defined(__sparc)
147510923SEvan.Yan@Sun.COM int rc = DDI_FAILURE;
147610923SEvan.Yan@Sun.COM
147710923SEvan.Yan@Sun.COM if (ddi_prop_get_int(DDI_DEV_T_ANY, ddi_get_parent(dip), 0,
147810923SEvan.Yan@Sun.COM PCI_DEV_CONF_MAP_PROP, DDI_FAILURE) != DDI_FAILURE)
147910923SEvan.Yan@Sun.COM rc = DDI_SUCCESS;
148010923SEvan.Yan@Sun.COM else
148110923SEvan.Yan@Sun.COM if (ddi_prop_get_int(DDI_DEV_T_ANY, ddi_get_parent(dip),
148210923SEvan.Yan@Sun.COM 0, PCI_BUS_CONF_MAP_PROP,
148310923SEvan.Yan@Sun.COM DDI_FAILURE) != DDI_FAILURE)
148410923SEvan.Yan@Sun.COM rc = DDI_SUCCESS;
148510923SEvan.Yan@Sun.COM DEBUG1("pci conf map = %d", rc);
148610923SEvan.Yan@Sun.COM return (rc);
148710923SEvan.Yan@Sun.COM #else
148810923SEvan.Yan@Sun.COM return (DDI_SUCCESS);
148910923SEvan.Yan@Sun.COM #endif
149010923SEvan.Yan@Sun.COM }
149110923SEvan.Yan@Sun.COM
149210923SEvan.Yan@Sun.COM static uint_t
pcicfg_get_ntbridge_child_range(dev_info_t * dip,uint64_t * boundbase,uint64_t * boundlen,uint_t space_type)149310923SEvan.Yan@Sun.COM pcicfg_get_ntbridge_child_range(dev_info_t *dip, uint64_t *boundbase,
149410923SEvan.Yan@Sun.COM uint64_t *boundlen, uint_t space_type)
149510923SEvan.Yan@Sun.COM {
149610923SEvan.Yan@Sun.COM int length, found = DDI_FAILURE, acount, i, ibridge;
149710923SEvan.Yan@Sun.COM pci_regspec_t *assigned;
149810923SEvan.Yan@Sun.COM
149910923SEvan.Yan@Sun.COM if ((ibridge = pcicfg_is_ntbridge(dip)) == DDI_FAILURE)
150010923SEvan.Yan@Sun.COM return (found);
150110923SEvan.Yan@Sun.COM
150210923SEvan.Yan@Sun.COM if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
150310923SEvan.Yan@Sun.COM DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned,
150410923SEvan.Yan@Sun.COM &length) != DDI_PROP_SUCCESS) {
150510923SEvan.Yan@Sun.COM DEBUG1("Failed to get assigned-addresses property %llx\n", dip);
150610923SEvan.Yan@Sun.COM return (found);
150710923SEvan.Yan@Sun.COM }
150810923SEvan.Yan@Sun.COM DEBUG1("pcicfg: ntbridge child range: dip = %s\n",
150910923SEvan.Yan@Sun.COM ddi_driver_name(dip));
151010923SEvan.Yan@Sun.COM
151110923SEvan.Yan@Sun.COM acount = length / sizeof (pci_regspec_t);
151210923SEvan.Yan@Sun.COM
151310923SEvan.Yan@Sun.COM for (i = 0; i < acount; i++) {
151410923SEvan.Yan@Sun.COM if ((PCI_REG_REG_G(assigned[i].pci_phys_hi) ==
151510923SEvan.Yan@Sun.COM pcicfg_indirect_map_devs[ibridge].mem_range_bar_offset) &&
151610923SEvan.Yan@Sun.COM (space_type == PCI_BASE_SPACE_MEM)) {
151710923SEvan.Yan@Sun.COM found = DDI_SUCCESS;
151810923SEvan.Yan@Sun.COM break;
151910923SEvan.Yan@Sun.COM } else {
152010923SEvan.Yan@Sun.COM if ((PCI_REG_REG_G(assigned[i].pci_phys_hi) ==
152110923SEvan.Yan@Sun.COM pcicfg_indirect_map_devs[ibridge].\
152210923SEvan.Yan@Sun.COM io_range_bar_offset) &&
152310923SEvan.Yan@Sun.COM (space_type == PCI_BASE_SPACE_IO)) {
152410923SEvan.Yan@Sun.COM found = DDI_SUCCESS;
152510923SEvan.Yan@Sun.COM break;
152610923SEvan.Yan@Sun.COM }
152710923SEvan.Yan@Sun.COM }
152810923SEvan.Yan@Sun.COM }
152910923SEvan.Yan@Sun.COM DEBUG3("pcicfg: ntbridge child range: space=%x, base=%lx, len=%lx\n",
153010923SEvan.Yan@Sun.COM space_type, assigned[i].pci_phys_low, assigned[i].pci_size_low);
153110923SEvan.Yan@Sun.COM
153210923SEvan.Yan@Sun.COM if (found == DDI_SUCCESS) {
153310923SEvan.Yan@Sun.COM *boundbase = assigned[i].pci_phys_low;
153410923SEvan.Yan@Sun.COM *boundlen = assigned[i].pci_size_low;
153510923SEvan.Yan@Sun.COM }
153610923SEvan.Yan@Sun.COM
153710923SEvan.Yan@Sun.COM kmem_free(assigned, length);
153810923SEvan.Yan@Sun.COM return (found);
153910923SEvan.Yan@Sun.COM }
154010923SEvan.Yan@Sun.COM
154110923SEvan.Yan@Sun.COM /*
154210923SEvan.Yan@Sun.COM * This will turn resources allocated by pcicfg_configure()
154310923SEvan.Yan@Sun.COM * and remove the device tree from the Hotplug Connection (CN)
154410923SEvan.Yan@Sun.COM * and below. The routine assumes the devices have their
154510923SEvan.Yan@Sun.COM * drivers detached.
154610923SEvan.Yan@Sun.COM */
154710923SEvan.Yan@Sun.COM int
pcicfg_unconfigure(dev_info_t * devi,uint_t device,uint_t function,pcicfg_flags_t flags)154810923SEvan.Yan@Sun.COM pcicfg_unconfigure(dev_info_t *devi, uint_t device, uint_t function,
154910923SEvan.Yan@Sun.COM pcicfg_flags_t flags)
155010923SEvan.Yan@Sun.COM {
155110923SEvan.Yan@Sun.COM dev_info_t *child_dip;
155210923SEvan.Yan@Sun.COM int func;
155310923SEvan.Yan@Sun.COM int i;
155410923SEvan.Yan@Sun.COM int max_function;
155510923SEvan.Yan@Sun.COM int trans_device;
155611245SZhijun.Fu@Sun.COM int circ;
155711245SZhijun.Fu@Sun.COM boolean_t is_pcie;
155810923SEvan.Yan@Sun.COM
155910923SEvan.Yan@Sun.COM if (pcie_ari_is_enabled(devi) == PCIE_ARI_FORW_ENABLED)
156010923SEvan.Yan@Sun.COM max_function = PCICFG_MAX_ARI_FUNCTION;
156110923SEvan.Yan@Sun.COM else
156210923SEvan.Yan@Sun.COM max_function = PCICFG_MAX_FUNCTION;
156310923SEvan.Yan@Sun.COM
156410923SEvan.Yan@Sun.COM /*
156510923SEvan.Yan@Sun.COM * Cycle through devices to make sure none are busy.
156610923SEvan.Yan@Sun.COM * If a single device is busy fail the whole unconfigure.
156710923SEvan.Yan@Sun.COM */
156811245SZhijun.Fu@Sun.COM is_pcie = is_pcie_fabric(devi);
156911245SZhijun.Fu@Sun.COM
157011245SZhijun.Fu@Sun.COM ndi_devi_enter(devi, &circ);
157110923SEvan.Yan@Sun.COM for (func = 0; func < max_function; func++) {
157210923SEvan.Yan@Sun.COM
157310923SEvan.Yan@Sun.COM if (max_function == PCICFG_MAX_ARI_FUNCTION)
157410923SEvan.Yan@Sun.COM trans_device = func >> 3; /* ARI Device */
157510923SEvan.Yan@Sun.COM else
157610923SEvan.Yan@Sun.COM trans_device = device;
157710923SEvan.Yan@Sun.COM
157810923SEvan.Yan@Sun.COM if ((child_dip = pcicfg_devi_find(devi, trans_device,
157910923SEvan.Yan@Sun.COM (func & 0x7))) == NULL)
158010923SEvan.Yan@Sun.COM continue;
158110923SEvan.Yan@Sun.COM
158210923SEvan.Yan@Sun.COM if (ndi_devi_offline(child_dip, NDI_UNCONFIG) == NDI_SUCCESS)
158310923SEvan.Yan@Sun.COM continue;
158410923SEvan.Yan@Sun.COM /*
158510923SEvan.Yan@Sun.COM * Device function is busy. Before returning we have to
158610923SEvan.Yan@Sun.COM * put all functions back online which were taken
158710923SEvan.Yan@Sun.COM * offline during the process.
158810923SEvan.Yan@Sun.COM */
158910923SEvan.Yan@Sun.COM DEBUG2("Device [0x%x] function [%x] is busy\n", device, func);
159010923SEvan.Yan@Sun.COM /*
159110923SEvan.Yan@Sun.COM * If we are only asked to offline one specific function,
159210923SEvan.Yan@Sun.COM * and that fails, we just simply return.
159310923SEvan.Yan@Sun.COM */
159410923SEvan.Yan@Sun.COM if (function != PCICFG_ALL_FUNC)
159510923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
159610923SEvan.Yan@Sun.COM
159710923SEvan.Yan@Sun.COM for (i = 0; i < func; i++) {
159810923SEvan.Yan@Sun.COM
159910923SEvan.Yan@Sun.COM if (max_function == PCICFG_MAX_ARI_FUNCTION)
160010923SEvan.Yan@Sun.COM trans_device = i >> 3;
160110923SEvan.Yan@Sun.COM
160210923SEvan.Yan@Sun.COM if ((child_dip =
160310923SEvan.Yan@Sun.COM pcicfg_devi_find(devi, trans_device, (i & 7)))
160410923SEvan.Yan@Sun.COM == NULL) {
160510923SEvan.Yan@Sun.COM DEBUG0(
160610923SEvan.Yan@Sun.COM "No more devices to put back on line!!\n");
160710923SEvan.Yan@Sun.COM /*
160810923SEvan.Yan@Sun.COM * Made it through all functions
160910923SEvan.Yan@Sun.COM */
161010923SEvan.Yan@Sun.COM continue;
161110923SEvan.Yan@Sun.COM }
161210923SEvan.Yan@Sun.COM if (ndi_devi_online(child_dip, NDI_CONFIG)
161310923SEvan.Yan@Sun.COM != NDI_SUCCESS) {
161410923SEvan.Yan@Sun.COM DEBUG0("Failed to put back devices state\n");
161511245SZhijun.Fu@Sun.COM goto fail;
161610923SEvan.Yan@Sun.COM }
161710923SEvan.Yan@Sun.COM }
161811245SZhijun.Fu@Sun.COM goto fail;
161910923SEvan.Yan@Sun.COM }
162010923SEvan.Yan@Sun.COM
162110923SEvan.Yan@Sun.COM /*
162210923SEvan.Yan@Sun.COM * Now, tear down all devinfo nodes for this Connector.
162310923SEvan.Yan@Sun.COM */
162410923SEvan.Yan@Sun.COM for (func = 0; func < max_function; func++) {
162510923SEvan.Yan@Sun.COM
162610923SEvan.Yan@Sun.COM if (max_function == PCICFG_MAX_ARI_FUNCTION)
162710923SEvan.Yan@Sun.COM trans_device = func >> 3; /* ARI Device */
162810923SEvan.Yan@Sun.COM else
162910923SEvan.Yan@Sun.COM trans_device = device;
163010923SEvan.Yan@Sun.COM
163110923SEvan.Yan@Sun.COM if ((child_dip = pcicfg_devi_find(devi,
163210923SEvan.Yan@Sun.COM trans_device, (func & 7))) == NULL) {
163310923SEvan.Yan@Sun.COM DEBUG0("No more devices to tear down!\n");
163410923SEvan.Yan@Sun.COM continue;
163510923SEvan.Yan@Sun.COM }
163610923SEvan.Yan@Sun.COM
163710923SEvan.Yan@Sun.COM DEBUG2("Tearing down device [0x%x] function [0x%x]\n",
163810923SEvan.Yan@Sun.COM trans_device, (func & 7));
163910923SEvan.Yan@Sun.COM
164010923SEvan.Yan@Sun.COM if (pcicfg_is_ntbridge(child_dip) != DDI_FAILURE)
164110923SEvan.Yan@Sun.COM if (pcicfg_ntbridge_unconfigure(child_dip) !=
164210923SEvan.Yan@Sun.COM PCICFG_SUCCESS) {
164310923SEvan.Yan@Sun.COM cmn_err(CE_WARN,
164410923SEvan.Yan@Sun.COM "ntbridge: unconfigure failed\n");
164511245SZhijun.Fu@Sun.COM goto fail;
164610923SEvan.Yan@Sun.COM }
164710923SEvan.Yan@Sun.COM
164811245SZhijun.Fu@Sun.COM if (pcicfg_teardown_device(child_dip, flags, is_pcie)
164910923SEvan.Yan@Sun.COM != PCICFG_SUCCESS) {
165010923SEvan.Yan@Sun.COM DEBUG2("Failed to tear down device [0x%x]"
165110923SEvan.Yan@Sun.COM "function [0x%x]\n",
165210923SEvan.Yan@Sun.COM trans_device, func & 7);
165311245SZhijun.Fu@Sun.COM goto fail;
165410923SEvan.Yan@Sun.COM }
165510923SEvan.Yan@Sun.COM }
165610923SEvan.Yan@Sun.COM
165710923SEvan.Yan@Sun.COM if (pcie_ari_is_enabled(devi) == PCIE_ARI_FORW_ENABLED) {
165810923SEvan.Yan@Sun.COM (void) ddi_prop_remove(DDI_DEV_T_NONE, devi, "ari-enabled");
165910923SEvan.Yan@Sun.COM (void) pcie_ari_disable(devi);
166010923SEvan.Yan@Sun.COM }
166110923SEvan.Yan@Sun.COM
166211245SZhijun.Fu@Sun.COM ndi_devi_exit(devi, circ);
166310923SEvan.Yan@Sun.COM return (PCICFG_SUCCESS);
166411245SZhijun.Fu@Sun.COM
166511245SZhijun.Fu@Sun.COM fail:
166611245SZhijun.Fu@Sun.COM ndi_devi_exit(devi, circ);
166711245SZhijun.Fu@Sun.COM return (PCICFG_FAILURE);
166810923SEvan.Yan@Sun.COM }
166910923SEvan.Yan@Sun.COM
167010923SEvan.Yan@Sun.COM static int
pcicfg_teardown_device(dev_info_t * dip,pcicfg_flags_t flags,boolean_t is_pcie)167111245SZhijun.Fu@Sun.COM pcicfg_teardown_device(dev_info_t *dip, pcicfg_flags_t flags, boolean_t is_pcie)
167210923SEvan.Yan@Sun.COM {
167310923SEvan.Yan@Sun.COM ddi_acc_handle_t config_handle;
167410923SEvan.Yan@Sun.COM
167510923SEvan.Yan@Sun.COM /*
167610923SEvan.Yan@Sun.COM * Free up resources associated with 'dip'
167710923SEvan.Yan@Sun.COM */
167810923SEvan.Yan@Sun.COM if (pcicfg_free_resources(dip, flags) != PCICFG_SUCCESS) {
167910923SEvan.Yan@Sun.COM DEBUG0("Failed to free resources\n");
168010923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
168110923SEvan.Yan@Sun.COM }
168210923SEvan.Yan@Sun.COM
168310923SEvan.Yan@Sun.COM /*
168410923SEvan.Yan@Sun.COM * This will disable the device
168510923SEvan.Yan@Sun.COM */
168610923SEvan.Yan@Sun.COM if (pci_config_setup(dip, &config_handle) != PCICFG_SUCCESS) {
168710923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
168810923SEvan.Yan@Sun.COM }
168910923SEvan.Yan@Sun.COM
169010923SEvan.Yan@Sun.COM pcicfg_device_off(config_handle);
169110923SEvan.Yan@Sun.COM pci_config_teardown(&config_handle);
169210923SEvan.Yan@Sun.COM
169310923SEvan.Yan@Sun.COM /*
169411245SZhijun.Fu@Sun.COM * free pcie_bus_t for the sub-tree
169511245SZhijun.Fu@Sun.COM */
169611245SZhijun.Fu@Sun.COM if (is_pcie) {
169711245SZhijun.Fu@Sun.COM if (ddi_get_child(dip) != NULL)
169811245SZhijun.Fu@Sun.COM pcie_fab_fini_bus(dip, PCIE_BUS_ALL);
169911245SZhijun.Fu@Sun.COM
170011245SZhijun.Fu@Sun.COM pcie_fini_bus(dip, PCIE_BUS_ALL);
170111245SZhijun.Fu@Sun.COM }
170211245SZhijun.Fu@Sun.COM
170311245SZhijun.Fu@Sun.COM /*
170410923SEvan.Yan@Sun.COM * The framework provides this routine which can
170510923SEvan.Yan@Sun.COM * tear down a sub-tree.
170610923SEvan.Yan@Sun.COM */
170710923SEvan.Yan@Sun.COM if (ndi_devi_offline(dip, NDI_DEVI_REMOVE) != NDI_SUCCESS) {
170810923SEvan.Yan@Sun.COM DEBUG0("Failed to offline and remove node\n");
170910923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
171010923SEvan.Yan@Sun.COM }
171110923SEvan.Yan@Sun.COM
171210923SEvan.Yan@Sun.COM return (PCICFG_SUCCESS);
171310923SEvan.Yan@Sun.COM }
171410923SEvan.Yan@Sun.COM
171510923SEvan.Yan@Sun.COM /*
171610923SEvan.Yan@Sun.COM * BEGIN GENERIC SUPPORT ROUTINES
171710923SEvan.Yan@Sun.COM */
171810923SEvan.Yan@Sun.COM static pcicfg_phdl_t *
pcicfg_find_phdl(dev_info_t * dip)171910923SEvan.Yan@Sun.COM pcicfg_find_phdl(dev_info_t *dip)
172010923SEvan.Yan@Sun.COM {
172110923SEvan.Yan@Sun.COM pcicfg_phdl_t *entry;
172210923SEvan.Yan@Sun.COM mutex_enter(&pcicfg_list_mutex);
172310923SEvan.Yan@Sun.COM for (entry = pcicfg_phdl_list; entry != NULL; entry = entry->next) {
172410923SEvan.Yan@Sun.COM if (entry->dip == dip) {
172510923SEvan.Yan@Sun.COM mutex_exit(&pcicfg_list_mutex);
172610923SEvan.Yan@Sun.COM return (entry);
172710923SEvan.Yan@Sun.COM }
172810923SEvan.Yan@Sun.COM }
172910923SEvan.Yan@Sun.COM mutex_exit(&pcicfg_list_mutex);
173010923SEvan.Yan@Sun.COM
173110923SEvan.Yan@Sun.COM /*
173210923SEvan.Yan@Sun.COM * Did'nt find entry - create one
173310923SEvan.Yan@Sun.COM */
173410923SEvan.Yan@Sun.COM return (pcicfg_create_phdl(dip));
173510923SEvan.Yan@Sun.COM }
173610923SEvan.Yan@Sun.COM
173710923SEvan.Yan@Sun.COM static pcicfg_phdl_t *
pcicfg_create_phdl(dev_info_t * dip)173810923SEvan.Yan@Sun.COM pcicfg_create_phdl(dev_info_t *dip)
173910923SEvan.Yan@Sun.COM {
174010923SEvan.Yan@Sun.COM pcicfg_phdl_t *new;
174110923SEvan.Yan@Sun.COM
174210923SEvan.Yan@Sun.COM new = (pcicfg_phdl_t *)kmem_zalloc(sizeof (pcicfg_phdl_t),
174310923SEvan.Yan@Sun.COM KM_SLEEP);
174410923SEvan.Yan@Sun.COM
174510923SEvan.Yan@Sun.COM new->dip = dip;
174610923SEvan.Yan@Sun.COM mutex_enter(&pcicfg_list_mutex);
174710923SEvan.Yan@Sun.COM new->next = pcicfg_phdl_list;
174810923SEvan.Yan@Sun.COM pcicfg_phdl_list = new;
174910923SEvan.Yan@Sun.COM mutex_exit(&pcicfg_list_mutex);
175010923SEvan.Yan@Sun.COM
175110923SEvan.Yan@Sun.COM return (new);
175210923SEvan.Yan@Sun.COM }
175310923SEvan.Yan@Sun.COM
175410923SEvan.Yan@Sun.COM static int
pcicfg_destroy_phdl(dev_info_t * dip)175510923SEvan.Yan@Sun.COM pcicfg_destroy_phdl(dev_info_t *dip)
175610923SEvan.Yan@Sun.COM {
175710923SEvan.Yan@Sun.COM pcicfg_phdl_t *entry;
175810923SEvan.Yan@Sun.COM pcicfg_phdl_t *follow = NULL;
175910923SEvan.Yan@Sun.COM
176010923SEvan.Yan@Sun.COM mutex_enter(&pcicfg_list_mutex);
176110923SEvan.Yan@Sun.COM for (entry = pcicfg_phdl_list; entry != NULL; follow = entry,
176210923SEvan.Yan@Sun.COM entry = entry->next) {
176310923SEvan.Yan@Sun.COM if (entry->dip == dip) {
176410923SEvan.Yan@Sun.COM if (entry == pcicfg_phdl_list) {
176510923SEvan.Yan@Sun.COM pcicfg_phdl_list = entry->next;
176610923SEvan.Yan@Sun.COM } else {
176710923SEvan.Yan@Sun.COM follow->next = entry->next;
176810923SEvan.Yan@Sun.COM }
176910923SEvan.Yan@Sun.COM /*
177010923SEvan.Yan@Sun.COM * If this entry has any allocated memory
177110923SEvan.Yan@Sun.COM * or IO space associated with it, that
177210923SEvan.Yan@Sun.COM * must be freed up.
177310923SEvan.Yan@Sun.COM */
177410923SEvan.Yan@Sun.COM if (entry->memory_len > 0) {
177510923SEvan.Yan@Sun.COM (void) ndi_ra_free(ddi_get_parent(dip),
177610923SEvan.Yan@Sun.COM entry->memory_base,
177710923SEvan.Yan@Sun.COM entry->memory_len,
177810923SEvan.Yan@Sun.COM NDI_RA_TYPE_MEM, NDI_RA_PASS);
177910923SEvan.Yan@Sun.COM }
178010923SEvan.Yan@Sun.COM pcicfg_free_hole(&entry->mem_hole);
178110923SEvan.Yan@Sun.COM
178210923SEvan.Yan@Sun.COM if (entry->io_len > 0) {
178310923SEvan.Yan@Sun.COM (void) ndi_ra_free(ddi_get_parent(dip),
178410923SEvan.Yan@Sun.COM entry->io_base,
178510923SEvan.Yan@Sun.COM entry->io_len,
178610923SEvan.Yan@Sun.COM NDI_RA_TYPE_IO, NDI_RA_PASS);
178710923SEvan.Yan@Sun.COM }
178810923SEvan.Yan@Sun.COM pcicfg_free_hole(&entry->io_hole);
178910923SEvan.Yan@Sun.COM
179010923SEvan.Yan@Sun.COM /*
179110923SEvan.Yan@Sun.COM * Destroy this entry
179210923SEvan.Yan@Sun.COM */
179310923SEvan.Yan@Sun.COM kmem_free((caddr_t)entry, sizeof (pcicfg_phdl_t));
179410923SEvan.Yan@Sun.COM mutex_exit(&pcicfg_list_mutex);
179510923SEvan.Yan@Sun.COM return (PCICFG_SUCCESS);
179610923SEvan.Yan@Sun.COM }
179710923SEvan.Yan@Sun.COM }
179810923SEvan.Yan@Sun.COM mutex_exit(&pcicfg_list_mutex);
179910923SEvan.Yan@Sun.COM /*
180010923SEvan.Yan@Sun.COM * Did'nt find the entry
180110923SEvan.Yan@Sun.COM */
180210923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
180310923SEvan.Yan@Sun.COM }
180410923SEvan.Yan@Sun.COM
180510923SEvan.Yan@Sun.COM static int
pcicfg_program_ap(dev_info_t * dip)180610923SEvan.Yan@Sun.COM pcicfg_program_ap(dev_info_t *dip)
180710923SEvan.Yan@Sun.COM {
180810923SEvan.Yan@Sun.COM pcicfg_phdl_t *phdl;
180910923SEvan.Yan@Sun.COM uint8_t header_type;
181010923SEvan.Yan@Sun.COM ddi_acc_handle_t handle;
181110923SEvan.Yan@Sun.COM pcicfg_phdl_t *entry;
181210923SEvan.Yan@Sun.COM
181310923SEvan.Yan@Sun.COM if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
181410923SEvan.Yan@Sun.COM DEBUG0("Failed to map config space!\n");
181510923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
181610923SEvan.Yan@Sun.COM
181710923SEvan.Yan@Sun.COM }
181810923SEvan.Yan@Sun.COM
181910923SEvan.Yan@Sun.COM header_type = pci_config_get8(handle, PCI_CONF_HEADER);
182010923SEvan.Yan@Sun.COM
182110923SEvan.Yan@Sun.COM (void) pcicfg_config_teardown(&handle);
182210923SEvan.Yan@Sun.COM
182310923SEvan.Yan@Sun.COM if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
182410923SEvan.Yan@Sun.COM
182510923SEvan.Yan@Sun.COM if (pcicfg_allocate_chunk(dip) != PCICFG_SUCCESS) {
182610923SEvan.Yan@Sun.COM DEBUG0("Not enough memory to hotplug\n");
182710923SEvan.Yan@Sun.COM (void) pcicfg_destroy_phdl(dip);
182810923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
182910923SEvan.Yan@Sun.COM }
183010923SEvan.Yan@Sun.COM
183110923SEvan.Yan@Sun.COM phdl = pcicfg_find_phdl(dip);
183210923SEvan.Yan@Sun.COM ASSERT(phdl);
183310923SEvan.Yan@Sun.COM
183410923SEvan.Yan@Sun.COM (void) pcicfg_bridge_assign(dip, (void *)phdl);
183510923SEvan.Yan@Sun.COM
183610923SEvan.Yan@Sun.COM if (phdl->error != PCICFG_SUCCESS) {
183710923SEvan.Yan@Sun.COM DEBUG0("Problem assigning bridge\n");
183810923SEvan.Yan@Sun.COM (void) pcicfg_destroy_phdl(dip);
183910923SEvan.Yan@Sun.COM return (phdl->error);
184010923SEvan.Yan@Sun.COM }
184110923SEvan.Yan@Sun.COM
184210923SEvan.Yan@Sun.COM /*
184310923SEvan.Yan@Sun.COM * Successfully allocated and assigned
184410923SEvan.Yan@Sun.COM * memory. Set the memory and IO length
184510923SEvan.Yan@Sun.COM * to zero so when the handle is freed up
184610923SEvan.Yan@Sun.COM * it will not de-allocate assigned resources.
184710923SEvan.Yan@Sun.COM */
184810923SEvan.Yan@Sun.COM entry = (pcicfg_phdl_t *)phdl;
184910923SEvan.Yan@Sun.COM
185010923SEvan.Yan@Sun.COM entry->memory_len = entry->io_len = 0;
185110923SEvan.Yan@Sun.COM
185210923SEvan.Yan@Sun.COM /*
185310923SEvan.Yan@Sun.COM * Free up the "entry" structure.
185410923SEvan.Yan@Sun.COM */
185510923SEvan.Yan@Sun.COM (void) pcicfg_destroy_phdl(dip);
185610923SEvan.Yan@Sun.COM } else {
185710923SEvan.Yan@Sun.COM if (pcicfg_device_assign(dip) != PCICFG_SUCCESS) {
185810923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
185910923SEvan.Yan@Sun.COM }
186010923SEvan.Yan@Sun.COM }
186110923SEvan.Yan@Sun.COM return (PCICFG_SUCCESS);
186210923SEvan.Yan@Sun.COM }
186310923SEvan.Yan@Sun.COM
186410923SEvan.Yan@Sun.COM static int
pcicfg_bridge_assign(dev_info_t * dip,void * hdl)186510923SEvan.Yan@Sun.COM pcicfg_bridge_assign(dev_info_t *dip, void *hdl)
186610923SEvan.Yan@Sun.COM {
186710923SEvan.Yan@Sun.COM ddi_acc_handle_t handle;
186810923SEvan.Yan@Sun.COM pci_regspec_t *reg;
186910923SEvan.Yan@Sun.COM int length;
187010923SEvan.Yan@Sun.COM int rcount;
187110923SEvan.Yan@Sun.COM int i;
187210923SEvan.Yan@Sun.COM int offset;
187310923SEvan.Yan@Sun.COM uint64_t mem_answer;
187410923SEvan.Yan@Sun.COM uint32_t io_answer;
187510923SEvan.Yan@Sun.COM int count;
187610923SEvan.Yan@Sun.COM uint8_t header_type;
187710923SEvan.Yan@Sun.COM pcicfg_range_t range[PCICFG_RANGE_LEN];
187810923SEvan.Yan@Sun.COM int bus_range[2];
187910923SEvan.Yan@Sun.COM
188010923SEvan.Yan@Sun.COM pcicfg_phdl_t *entry = (pcicfg_phdl_t *)hdl;
188110923SEvan.Yan@Sun.COM
188210923SEvan.Yan@Sun.COM DEBUG1("bridge assign: assigning addresses to %s\n", ddi_get_name(dip));
188310923SEvan.Yan@Sun.COM
188410923SEvan.Yan@Sun.COM if (entry == NULL) {
188510923SEvan.Yan@Sun.COM DEBUG0("Failed to get entry\n");
188610923SEvan.Yan@Sun.COM return (DDI_WALK_TERMINATE);
188710923SEvan.Yan@Sun.COM }
188810923SEvan.Yan@Sun.COM
188910923SEvan.Yan@Sun.COM entry->error = PCICFG_SUCCESS;
189010923SEvan.Yan@Sun.COM
189110923SEvan.Yan@Sun.COM if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
189210923SEvan.Yan@Sun.COM DEBUG0("Failed to map config space!\n");
189310923SEvan.Yan@Sun.COM entry->error = PCICFG_FAILURE;
189410923SEvan.Yan@Sun.COM return (DDI_WALK_TERMINATE);
189510923SEvan.Yan@Sun.COM }
189610923SEvan.Yan@Sun.COM
189710923SEvan.Yan@Sun.COM header_type = pci_config_get8(handle, PCI_CONF_HEADER);
189810923SEvan.Yan@Sun.COM
189910923SEvan.Yan@Sun.COM if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
190010923SEvan.Yan@Sun.COM
190110923SEvan.Yan@Sun.COM bzero((caddr_t)range,
190210923SEvan.Yan@Sun.COM sizeof (pcicfg_range_t) * PCICFG_RANGE_LEN);
190310923SEvan.Yan@Sun.COM
190410923SEvan.Yan@Sun.COM (void) pcicfg_setup_bridge(entry, handle, dip);
190510923SEvan.Yan@Sun.COM
190610923SEvan.Yan@Sun.COM range[0].child_hi = range[0].parent_hi |=
190710923SEvan.Yan@Sun.COM (PCI_REG_REL_M | PCI_ADDR_IO);
190810923SEvan.Yan@Sun.COM range[0].child_lo = range[0].parent_lo =
190910923SEvan.Yan@Sun.COM entry->io_last;
191010923SEvan.Yan@Sun.COM range[1].child_hi = range[1].parent_hi |=
191110923SEvan.Yan@Sun.COM (PCI_REG_REL_M | PCI_ADDR_MEM32);
191210923SEvan.Yan@Sun.COM range[1].child_lo = range[1].parent_lo =
191310923SEvan.Yan@Sun.COM entry->memory_last;
191410923SEvan.Yan@Sun.COM
191510923SEvan.Yan@Sun.COM ndi_devi_enter(dip, &count);
191610923SEvan.Yan@Sun.COM ddi_walk_devs(ddi_get_child(dip),
191710923SEvan.Yan@Sun.COM pcicfg_bridge_assign, (void *)entry);
191810923SEvan.Yan@Sun.COM ndi_devi_exit(dip, count);
191910923SEvan.Yan@Sun.COM
192010923SEvan.Yan@Sun.COM (void) pcicfg_update_bridge(entry, handle);
192110923SEvan.Yan@Sun.COM
192210923SEvan.Yan@Sun.COM bus_range[0] = pci_config_get8(handle, PCI_BCNF_SECBUS);
192310923SEvan.Yan@Sun.COM bus_range[1] = pci_config_get8(handle, PCI_BCNF_SUBBUS);
192410923SEvan.Yan@Sun.COM
192510923SEvan.Yan@Sun.COM if (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
192610923SEvan.Yan@Sun.COM "bus-range", bus_range, 2) != DDI_SUCCESS) {
192710923SEvan.Yan@Sun.COM DEBUG0("Failed to set bus-range property");
192810923SEvan.Yan@Sun.COM entry->error = PCICFG_FAILURE;
192910923SEvan.Yan@Sun.COM return (DDI_WALK_TERMINATE);
193010923SEvan.Yan@Sun.COM }
193110923SEvan.Yan@Sun.COM
193210923SEvan.Yan@Sun.COM if (entry->io_len > 0) {
193310923SEvan.Yan@Sun.COM range[0].size_lo = entry->io_last - entry->io_base;
193410923SEvan.Yan@Sun.COM if (pcicfg_update_ranges_prop(dip, &range[0])) {
193510923SEvan.Yan@Sun.COM DEBUG0("Failed to update ranges (i/o)\n");
193610923SEvan.Yan@Sun.COM entry->error = PCICFG_FAILURE;
193710923SEvan.Yan@Sun.COM return (DDI_WALK_TERMINATE);
193810923SEvan.Yan@Sun.COM }
193910923SEvan.Yan@Sun.COM }
194010923SEvan.Yan@Sun.COM if (entry->memory_len > 0) {
194110923SEvan.Yan@Sun.COM range[1].size_lo =
194210923SEvan.Yan@Sun.COM entry->memory_last - entry->memory_base;
194310923SEvan.Yan@Sun.COM if (pcicfg_update_ranges_prop(dip, &range[1])) {
194410923SEvan.Yan@Sun.COM DEBUG0("Failed to update ranges (memory)\n");
194510923SEvan.Yan@Sun.COM entry->error = PCICFG_FAILURE;
194610923SEvan.Yan@Sun.COM return (DDI_WALK_TERMINATE);
194710923SEvan.Yan@Sun.COM }
194810923SEvan.Yan@Sun.COM }
194910923SEvan.Yan@Sun.COM
195010923SEvan.Yan@Sun.COM (void) pcicfg_device_on(handle);
195110923SEvan.Yan@Sun.COM
195210923SEvan.Yan@Sun.COM PCICFG_DUMP_BRIDGE_CONFIG(handle);
195310923SEvan.Yan@Sun.COM
195410923SEvan.Yan@Sun.COM return (DDI_WALK_PRUNECHILD);
195510923SEvan.Yan@Sun.COM }
195610923SEvan.Yan@Sun.COM
195710923SEvan.Yan@Sun.COM /*
195810923SEvan.Yan@Sun.COM * If there is an interrupt pin set program
195910923SEvan.Yan@Sun.COM * interrupt line with default values.
196010923SEvan.Yan@Sun.COM */
196110923SEvan.Yan@Sun.COM if (pci_config_get8(handle, PCI_CONF_IPIN)) {
196210923SEvan.Yan@Sun.COM pci_config_put8(handle, PCI_CONF_ILINE, 0xf);
196310923SEvan.Yan@Sun.COM }
196410923SEvan.Yan@Sun.COM
196510923SEvan.Yan@Sun.COM /*
196610923SEvan.Yan@Sun.COM * A single device (under a bridge).
196710923SEvan.Yan@Sun.COM * For each "reg" property with a length, allocate memory
196810923SEvan.Yan@Sun.COM * and program the base registers.
196910923SEvan.Yan@Sun.COM */
197010923SEvan.Yan@Sun.COM if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
197110923SEvan.Yan@Sun.COM DDI_PROP_DONTPASS, "reg", (caddr_t)®,
197210923SEvan.Yan@Sun.COM &length) != DDI_PROP_SUCCESS) {
197310923SEvan.Yan@Sun.COM DEBUG0("Failed to read reg property\n");
197410923SEvan.Yan@Sun.COM entry->error = PCICFG_FAILURE;
197510923SEvan.Yan@Sun.COM return (DDI_WALK_TERMINATE);
197610923SEvan.Yan@Sun.COM }
197710923SEvan.Yan@Sun.COM
197810923SEvan.Yan@Sun.COM rcount = length / sizeof (pci_regspec_t);
197910923SEvan.Yan@Sun.COM offset = PCI_CONF_BASE0;
198010923SEvan.Yan@Sun.COM for (i = 0; i < rcount; i++) {
198110923SEvan.Yan@Sun.COM if ((reg[i].pci_size_low != 0)||
198210923SEvan.Yan@Sun.COM (reg[i].pci_size_hi != 0)) {
198310923SEvan.Yan@Sun.COM
198410923SEvan.Yan@Sun.COM offset = PCI_REG_REG_G(reg[i].pci_phys_hi);
198510923SEvan.Yan@Sun.COM
198610923SEvan.Yan@Sun.COM switch (PCI_REG_ADDR_G(reg[i].pci_phys_hi)) {
198710923SEvan.Yan@Sun.COM case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
198810923SEvan.Yan@Sun.COM
198910923SEvan.Yan@Sun.COM (void) pcicfg_get_mem(entry,
199010923SEvan.Yan@Sun.COM reg[i].pci_size_low, &mem_answer);
199110923SEvan.Yan@Sun.COM pci_config_put64(handle, offset, mem_answer);
199210923SEvan.Yan@Sun.COM DEBUG2("REGISTER off %x (64)LO ----> [0x%x]\n",
199310923SEvan.Yan@Sun.COM offset,
199410923SEvan.Yan@Sun.COM pci_config_get32(handle, offset));
199510923SEvan.Yan@Sun.COM DEBUG2("REGISTER off %x (64)HI ----> [0x%x]\n",
199610923SEvan.Yan@Sun.COM offset + 4,
199710923SEvan.Yan@Sun.COM pci_config_get32(handle, offset + 4));
199810923SEvan.Yan@Sun.COM
199910923SEvan.Yan@Sun.COM reg[i].pci_phys_low = PCICFG_HIADDR(mem_answer);
200010923SEvan.Yan@Sun.COM reg[i].pci_phys_mid =
200110923SEvan.Yan@Sun.COM PCICFG_LOADDR(mem_answer);
200210923SEvan.Yan@Sun.COM
200310923SEvan.Yan@Sun.COM break;
200410923SEvan.Yan@Sun.COM
200510923SEvan.Yan@Sun.COM case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
200610923SEvan.Yan@Sun.COM /* allocate memory space from the allocator */
200710923SEvan.Yan@Sun.COM
200810923SEvan.Yan@Sun.COM (void) pcicfg_get_mem(entry,
200910923SEvan.Yan@Sun.COM reg[i].pci_size_low, &mem_answer);
201010923SEvan.Yan@Sun.COM pci_config_put32(handle,
201110923SEvan.Yan@Sun.COM offset, (uint32_t)mem_answer);
201210923SEvan.Yan@Sun.COM
201310923SEvan.Yan@Sun.COM DEBUG2("REGISTER off %x(32)LO ----> [0x%x]\n",
201410923SEvan.Yan@Sun.COM offset,
201510923SEvan.Yan@Sun.COM pci_config_get32(handle, offset));
201610923SEvan.Yan@Sun.COM
201710923SEvan.Yan@Sun.COM reg[i].pci_phys_low = (uint32_t)mem_answer;
201810923SEvan.Yan@Sun.COM
201910923SEvan.Yan@Sun.COM break;
202010923SEvan.Yan@Sun.COM case PCI_REG_ADDR_G(PCI_ADDR_IO):
202110923SEvan.Yan@Sun.COM /* allocate I/O space from the allocator */
202210923SEvan.Yan@Sun.COM
202310923SEvan.Yan@Sun.COM (void) pcicfg_get_io(entry,
202410923SEvan.Yan@Sun.COM reg[i].pci_size_low, &io_answer);
202510923SEvan.Yan@Sun.COM pci_config_put32(handle, offset, io_answer);
202610923SEvan.Yan@Sun.COM
202710923SEvan.Yan@Sun.COM DEBUG2("REGISTER off %x (I/O)LO ----> [0x%x]\n",
202810923SEvan.Yan@Sun.COM offset,
202910923SEvan.Yan@Sun.COM pci_config_get32(handle, offset));
203010923SEvan.Yan@Sun.COM
203110923SEvan.Yan@Sun.COM reg[i].pci_phys_low = io_answer;
203210923SEvan.Yan@Sun.COM
203310923SEvan.Yan@Sun.COM break;
203410923SEvan.Yan@Sun.COM default:
203510923SEvan.Yan@Sun.COM DEBUG0("Unknown register type\n");
203610923SEvan.Yan@Sun.COM kmem_free(reg, length);
203710923SEvan.Yan@Sun.COM (void) pcicfg_config_teardown(&handle);
203810923SEvan.Yan@Sun.COM entry->error = PCICFG_FAILURE;
203910923SEvan.Yan@Sun.COM return (DDI_WALK_TERMINATE);
204010923SEvan.Yan@Sun.COM } /* switch */
204110923SEvan.Yan@Sun.COM
204210923SEvan.Yan@Sun.COM /*
204310923SEvan.Yan@Sun.COM * Now that memory locations are assigned,
204410923SEvan.Yan@Sun.COM * update the assigned address property.
204510923SEvan.Yan@Sun.COM */
204610923SEvan.Yan@Sun.COM if (pcicfg_update_assigned_prop(dip,
204710923SEvan.Yan@Sun.COM ®[i]) != PCICFG_SUCCESS) {
204810923SEvan.Yan@Sun.COM kmem_free(reg, length);
204910923SEvan.Yan@Sun.COM (void) pcicfg_config_teardown(&handle);
205010923SEvan.Yan@Sun.COM entry->error = PCICFG_FAILURE;
205110923SEvan.Yan@Sun.COM return (DDI_WALK_TERMINATE);
205210923SEvan.Yan@Sun.COM }
205310923SEvan.Yan@Sun.COM }
205410923SEvan.Yan@Sun.COM }
205510923SEvan.Yan@Sun.COM (void) pcicfg_device_on(handle);
205610923SEvan.Yan@Sun.COM
205710923SEvan.Yan@Sun.COM PCICFG_DUMP_DEVICE_CONFIG(handle);
205810923SEvan.Yan@Sun.COM
205910923SEvan.Yan@Sun.COM (void) pcicfg_config_teardown(&handle);
206010923SEvan.Yan@Sun.COM /*
206110923SEvan.Yan@Sun.COM * Don't forget to free up memory from ddi_getlongprop
206210923SEvan.Yan@Sun.COM */
206310923SEvan.Yan@Sun.COM kmem_free((caddr_t)reg, length);
206410923SEvan.Yan@Sun.COM
206510923SEvan.Yan@Sun.COM return (DDI_WALK_CONTINUE);
206610923SEvan.Yan@Sun.COM }
206710923SEvan.Yan@Sun.COM
206810923SEvan.Yan@Sun.COM static int
pcicfg_device_assign(dev_info_t * dip)206910923SEvan.Yan@Sun.COM pcicfg_device_assign(dev_info_t *dip)
207010923SEvan.Yan@Sun.COM {
207110923SEvan.Yan@Sun.COM ddi_acc_handle_t handle;
207210923SEvan.Yan@Sun.COM pci_regspec_t *reg;
207310923SEvan.Yan@Sun.COM int length;
207410923SEvan.Yan@Sun.COM int rcount;
207510923SEvan.Yan@Sun.COM int i;
207610923SEvan.Yan@Sun.COM int offset;
207710923SEvan.Yan@Sun.COM ndi_ra_request_t request;
207810923SEvan.Yan@Sun.COM uint64_t answer;
207910923SEvan.Yan@Sun.COM uint64_t alen;
208010923SEvan.Yan@Sun.COM
208110923SEvan.Yan@Sun.COM DEBUG1("%llx now under configuration\n", dip);
208210923SEvan.Yan@Sun.COM
208310923SEvan.Yan@Sun.COM /*
208410923SEvan.Yan@Sun.COM * XXX Failure here should be noted
208510923SEvan.Yan@Sun.COM */
208610923SEvan.Yan@Sun.COM if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
208710923SEvan.Yan@Sun.COM DDI_PROP_DONTPASS, "reg", (caddr_t)®,
208810923SEvan.Yan@Sun.COM &length) != DDI_PROP_SUCCESS) {
208910923SEvan.Yan@Sun.COM DEBUG0("Failed to read reg property\n");
209010923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
209110923SEvan.Yan@Sun.COM }
209210923SEvan.Yan@Sun.COM
209310923SEvan.Yan@Sun.COM if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
209410923SEvan.Yan@Sun.COM DEBUG0("Failed to map config space!\n");
209510923SEvan.Yan@Sun.COM /*
209610923SEvan.Yan@Sun.COM * Don't forget to free up memory from ddi_getlongprop
209710923SEvan.Yan@Sun.COM */
209810923SEvan.Yan@Sun.COM kmem_free((caddr_t)reg, length);
209910923SEvan.Yan@Sun.COM
210010923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
210110923SEvan.Yan@Sun.COM }
210210923SEvan.Yan@Sun.COM
210310923SEvan.Yan@Sun.COM /*
210410923SEvan.Yan@Sun.COM * A single device
210510923SEvan.Yan@Sun.COM *
210610923SEvan.Yan@Sun.COM * For each "reg" property with a length, allocate memory
210710923SEvan.Yan@Sun.COM * and program the base registers.
210810923SEvan.Yan@Sun.COM */
210910923SEvan.Yan@Sun.COM
211010923SEvan.Yan@Sun.COM /*
211110923SEvan.Yan@Sun.COM * If there is an interrupt pin set program
211210923SEvan.Yan@Sun.COM * interrupt line with default values.
211310923SEvan.Yan@Sun.COM */
211410923SEvan.Yan@Sun.COM if (pci_config_get8(handle, PCI_CONF_IPIN)) {
211510923SEvan.Yan@Sun.COM pci_config_put8(handle, PCI_CONF_ILINE, 0xf);
211610923SEvan.Yan@Sun.COM }
211710923SEvan.Yan@Sun.COM
211810923SEvan.Yan@Sun.COM bzero((caddr_t)&request, sizeof (ndi_ra_request_t));
211910923SEvan.Yan@Sun.COM
2120*12765SScott.Carter@Oracle.COM request.ra_flags = NDI_RA_ALIGN_SIZE;
212110923SEvan.Yan@Sun.COM request.ra_boundbase = 0;
212210923SEvan.Yan@Sun.COM request.ra_boundlen = PCICFG_4GIG_LIMIT;
212310923SEvan.Yan@Sun.COM
212410923SEvan.Yan@Sun.COM rcount = length / sizeof (pci_regspec_t);
212510923SEvan.Yan@Sun.COM for (i = 0; i < rcount; i++) {
212610923SEvan.Yan@Sun.COM if ((reg[i].pci_size_low != 0)||
212710923SEvan.Yan@Sun.COM (reg[i].pci_size_hi != 0)) {
212810923SEvan.Yan@Sun.COM
212910923SEvan.Yan@Sun.COM offset = PCI_REG_REG_G(reg[i].pci_phys_hi);
213010923SEvan.Yan@Sun.COM request.ra_len = reg[i].pci_size_low;
213110923SEvan.Yan@Sun.COM
213210923SEvan.Yan@Sun.COM switch (PCI_REG_ADDR_G(reg[i].pci_phys_hi)) {
213310923SEvan.Yan@Sun.COM case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
2134*12765SScott.Carter@Oracle.COM request.ra_flags &= ~NDI_RA_ALLOC_BOUNDED;
213510923SEvan.Yan@Sun.COM /* allocate memory space from the allocator */
213610923SEvan.Yan@Sun.COM if (ndi_ra_alloc(ddi_get_parent(dip),
213710923SEvan.Yan@Sun.COM &request, &answer, &alen,
213810923SEvan.Yan@Sun.COM NDI_RA_TYPE_MEM, NDI_RA_PASS)
213910923SEvan.Yan@Sun.COM != NDI_SUCCESS) {
214010923SEvan.Yan@Sun.COM DEBUG0("Failed to allocate 64b mem\n");
214110923SEvan.Yan@Sun.COM kmem_free(reg, length);
214210923SEvan.Yan@Sun.COM (void) pcicfg_config_teardown(&handle);
214310923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
214410923SEvan.Yan@Sun.COM }
214510923SEvan.Yan@Sun.COM DEBUG3("64 addr = [0x%x.%x] len [0x%x]\n",
214610923SEvan.Yan@Sun.COM PCICFG_HIADDR(answer),
214710923SEvan.Yan@Sun.COM PCICFG_LOADDR(answer),
214810923SEvan.Yan@Sun.COM alen);
214910923SEvan.Yan@Sun.COM /* program the low word */
215010923SEvan.Yan@Sun.COM pci_config_put32(handle,
215110923SEvan.Yan@Sun.COM offset, PCICFG_LOADDR(answer));
215210923SEvan.Yan@Sun.COM
2153*12765SScott.Carter@Oracle.COM /* program the high word */
215410923SEvan.Yan@Sun.COM pci_config_put32(handle, offset + 4,
215510923SEvan.Yan@Sun.COM PCICFG_HIADDR(answer));
215610923SEvan.Yan@Sun.COM
215710923SEvan.Yan@Sun.COM reg[i].pci_phys_low = PCICFG_LOADDR(answer);
215810923SEvan.Yan@Sun.COM reg[i].pci_phys_mid = PCICFG_HIADDR(answer);
2159*12765SScott.Carter@Oracle.COM
2160*12765SScott.Carter@Oracle.COM /* adjust to 32b address space when possible */
2161*12765SScott.Carter@Oracle.COM if ((answer + alen) <= PCICFG_4GIG_LIMIT)
2162*12765SScott.Carter@Oracle.COM reg[i].pci_phys_hi ^=
2163*12765SScott.Carter@Oracle.COM PCI_ADDR_MEM64 ^ PCI_ADDR_MEM32;
216410923SEvan.Yan@Sun.COM break;
216510923SEvan.Yan@Sun.COM
216610923SEvan.Yan@Sun.COM case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
216710923SEvan.Yan@Sun.COM request.ra_flags |= NDI_RA_ALLOC_BOUNDED;
216810923SEvan.Yan@Sun.COM /* allocate memory space from the allocator */
216910923SEvan.Yan@Sun.COM if (ndi_ra_alloc(ddi_get_parent(dip),
217010923SEvan.Yan@Sun.COM &request, &answer, &alen,
217110923SEvan.Yan@Sun.COM NDI_RA_TYPE_MEM, NDI_RA_PASS)
217210923SEvan.Yan@Sun.COM != NDI_SUCCESS) {
217310923SEvan.Yan@Sun.COM DEBUG0("Failed to allocate 32b mem\n");
217410923SEvan.Yan@Sun.COM kmem_free(reg, length);
217510923SEvan.Yan@Sun.COM (void) pcicfg_config_teardown(&handle);
217610923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
217710923SEvan.Yan@Sun.COM }
217810923SEvan.Yan@Sun.COM DEBUG3("32 addr = [0x%x.%x] len [0x%x]\n",
217910923SEvan.Yan@Sun.COM PCICFG_HIADDR(answer),
218010923SEvan.Yan@Sun.COM PCICFG_LOADDR(answer),
218110923SEvan.Yan@Sun.COM alen);
218210923SEvan.Yan@Sun.COM /* program the low word */
218310923SEvan.Yan@Sun.COM pci_config_put32(handle,
218410923SEvan.Yan@Sun.COM offset, PCICFG_LOADDR(answer));
218510923SEvan.Yan@Sun.COM
218610923SEvan.Yan@Sun.COM reg[i].pci_phys_low = PCICFG_LOADDR(answer);
218710923SEvan.Yan@Sun.COM break;
2188*12765SScott.Carter@Oracle.COM
218910923SEvan.Yan@Sun.COM case PCI_REG_ADDR_G(PCI_ADDR_IO):
219010923SEvan.Yan@Sun.COM /* allocate I/O space from the allocator */
219110923SEvan.Yan@Sun.COM request.ra_flags |= NDI_RA_ALLOC_BOUNDED;
219210923SEvan.Yan@Sun.COM if (ndi_ra_alloc(ddi_get_parent(dip),
219310923SEvan.Yan@Sun.COM &request, &answer, &alen,
219410923SEvan.Yan@Sun.COM NDI_RA_TYPE_IO, NDI_RA_PASS)
219510923SEvan.Yan@Sun.COM != NDI_SUCCESS) {
219610923SEvan.Yan@Sun.COM DEBUG0("Failed to allocate I/O\n");
219710923SEvan.Yan@Sun.COM kmem_free(reg, length);
219810923SEvan.Yan@Sun.COM (void) pcicfg_config_teardown(&handle);
219910923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
220010923SEvan.Yan@Sun.COM }
220110923SEvan.Yan@Sun.COM DEBUG3("I/O addr = [0x%x.%x] len [0x%x]\n",
220210923SEvan.Yan@Sun.COM PCICFG_HIADDR(answer),
220310923SEvan.Yan@Sun.COM PCICFG_LOADDR(answer),
220410923SEvan.Yan@Sun.COM alen);
220510923SEvan.Yan@Sun.COM pci_config_put32(handle,
220610923SEvan.Yan@Sun.COM offset, PCICFG_LOADDR(answer));
220710923SEvan.Yan@Sun.COM
220810923SEvan.Yan@Sun.COM reg[i].pci_phys_low = PCICFG_LOADDR(answer);
220910923SEvan.Yan@Sun.COM break;
2210*12765SScott.Carter@Oracle.COM
221110923SEvan.Yan@Sun.COM default:
221210923SEvan.Yan@Sun.COM DEBUG0("Unknown register type\n");
221310923SEvan.Yan@Sun.COM kmem_free(reg, length);
221410923SEvan.Yan@Sun.COM (void) pcicfg_config_teardown(&handle);
221510923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
221610923SEvan.Yan@Sun.COM } /* switch */
221710923SEvan.Yan@Sun.COM
221810923SEvan.Yan@Sun.COM /*
221910923SEvan.Yan@Sun.COM * Now that memory locations are assigned,
222010923SEvan.Yan@Sun.COM * update the assigned address property.
222110923SEvan.Yan@Sun.COM */
222210923SEvan.Yan@Sun.COM
222310923SEvan.Yan@Sun.COM if (pcicfg_update_assigned_prop(dip,
222410923SEvan.Yan@Sun.COM ®[i]) != PCICFG_SUCCESS) {
222510923SEvan.Yan@Sun.COM kmem_free(reg, length);
222610923SEvan.Yan@Sun.COM (void) pcicfg_config_teardown(&handle);
222710923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
222810923SEvan.Yan@Sun.COM }
222910923SEvan.Yan@Sun.COM }
223010923SEvan.Yan@Sun.COM }
223110923SEvan.Yan@Sun.COM
223210923SEvan.Yan@Sun.COM (void) pcicfg_device_on(handle);
223310923SEvan.Yan@Sun.COM kmem_free(reg, length);
223410923SEvan.Yan@Sun.COM
223510923SEvan.Yan@Sun.COM PCICFG_DUMP_DEVICE_CONFIG(handle);
223610923SEvan.Yan@Sun.COM
223710923SEvan.Yan@Sun.COM (void) pcicfg_config_teardown(&handle);
223810923SEvan.Yan@Sun.COM return (PCICFG_SUCCESS);
223910923SEvan.Yan@Sun.COM }
224010923SEvan.Yan@Sun.COM
224110923SEvan.Yan@Sun.COM static int
pcicfg_device_assign_readonly(dev_info_t * dip)224210923SEvan.Yan@Sun.COM pcicfg_device_assign_readonly(dev_info_t *dip)
224310923SEvan.Yan@Sun.COM {
224410923SEvan.Yan@Sun.COM ddi_acc_handle_t handle;
224510923SEvan.Yan@Sun.COM pci_regspec_t *assigned;
224610923SEvan.Yan@Sun.COM int length;
224710923SEvan.Yan@Sun.COM int acount;
224810923SEvan.Yan@Sun.COM int i;
224910923SEvan.Yan@Sun.COM ndi_ra_request_t request;
225010923SEvan.Yan@Sun.COM uint64_t answer;
225110923SEvan.Yan@Sun.COM uint64_t alen;
225210923SEvan.Yan@Sun.COM
225310923SEvan.Yan@Sun.COM
225410923SEvan.Yan@Sun.COM DEBUG1("%llx now under configuration\n", dip);
225510923SEvan.Yan@Sun.COM
225610923SEvan.Yan@Sun.COM if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
225710923SEvan.Yan@Sun.COM DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned,
225810923SEvan.Yan@Sun.COM &length) != DDI_PROP_SUCCESS) {
225910923SEvan.Yan@Sun.COM DEBUG0("Failed to read assigned-addresses property\n");
226010923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
226110923SEvan.Yan@Sun.COM }
226210923SEvan.Yan@Sun.COM
226310923SEvan.Yan@Sun.COM if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
226410923SEvan.Yan@Sun.COM DEBUG0("Failed to map config space!\n");
226510923SEvan.Yan@Sun.COM /*
226610923SEvan.Yan@Sun.COM * Don't forget to free up memory from ddi_getlongprop
226710923SEvan.Yan@Sun.COM */
226810923SEvan.Yan@Sun.COM kmem_free((caddr_t)assigned, length);
226910923SEvan.Yan@Sun.COM
227010923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
227110923SEvan.Yan@Sun.COM }
227210923SEvan.Yan@Sun.COM
227310923SEvan.Yan@Sun.COM /*
227410923SEvan.Yan@Sun.COM * For each "assigned-addresses" property entry with a length,
227510923SEvan.Yan@Sun.COM * call the memory allocation routines to return the
227610923SEvan.Yan@Sun.COM * resource.
227710923SEvan.Yan@Sun.COM */
227810923SEvan.Yan@Sun.COM /*
227910923SEvan.Yan@Sun.COM * If there is an interrupt pin set program
228010923SEvan.Yan@Sun.COM * interrupt line with default values.
228110923SEvan.Yan@Sun.COM */
228210923SEvan.Yan@Sun.COM if (pci_config_get8(handle, PCI_CONF_IPIN)) {
228310923SEvan.Yan@Sun.COM pci_config_put8(handle, PCI_CONF_ILINE, 0xf);
228410923SEvan.Yan@Sun.COM }
228510923SEvan.Yan@Sun.COM
228610923SEvan.Yan@Sun.COM bzero((caddr_t)&request, sizeof (ndi_ra_request_t));
228710923SEvan.Yan@Sun.COM
228810923SEvan.Yan@Sun.COM request.ra_flags = NDI_RA_ALLOC_SPECIFIED; /* specified addr */
228910923SEvan.Yan@Sun.COM request.ra_boundbase = 0;
229010923SEvan.Yan@Sun.COM request.ra_boundlen = PCICFG_4GIG_LIMIT;
229110923SEvan.Yan@Sun.COM
229210923SEvan.Yan@Sun.COM acount = length / sizeof (pci_regspec_t);
229310923SEvan.Yan@Sun.COM for (i = 0; i < acount; i++) {
229410923SEvan.Yan@Sun.COM if ((assigned[i].pci_size_low != 0)||
229510923SEvan.Yan@Sun.COM (assigned[i].pci_size_hi != 0)) {
229610923SEvan.Yan@Sun.COM
229710923SEvan.Yan@Sun.COM request.ra_len = assigned[i].pci_size_low;
229810923SEvan.Yan@Sun.COM
229910923SEvan.Yan@Sun.COM switch (PCI_REG_ADDR_G(assigned[i].pci_phys_hi)) {
230010923SEvan.Yan@Sun.COM case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
230110923SEvan.Yan@Sun.COM request.ra_addr = (uint64_t)PCICFG_LADDR(
230210923SEvan.Yan@Sun.COM assigned[i].pci_phys_low,
230310923SEvan.Yan@Sun.COM assigned[i].pci_phys_mid);
230410923SEvan.Yan@Sun.COM
230510923SEvan.Yan@Sun.COM /* allocate memory space from the allocator */
230610923SEvan.Yan@Sun.COM if (ndi_ra_alloc(ddi_get_parent(dip),
230710923SEvan.Yan@Sun.COM &request, &answer, &alen,
230810923SEvan.Yan@Sun.COM NDI_RA_TYPE_MEM, NDI_RA_PASS)
230910923SEvan.Yan@Sun.COM != NDI_SUCCESS) {
231010923SEvan.Yan@Sun.COM DEBUG0("Failed to allocate 64b mem\n");
231110923SEvan.Yan@Sun.COM kmem_free(assigned, length);
231210923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
231310923SEvan.Yan@Sun.COM }
231410923SEvan.Yan@Sun.COM
231510923SEvan.Yan@Sun.COM break;
231610923SEvan.Yan@Sun.COM case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
231710923SEvan.Yan@Sun.COM request.ra_addr = (uint64_t)
231810923SEvan.Yan@Sun.COM assigned[i].pci_phys_low;
231910923SEvan.Yan@Sun.COM
232010923SEvan.Yan@Sun.COM /* allocate memory space from the allocator */
232110923SEvan.Yan@Sun.COM if (ndi_ra_alloc(ddi_get_parent(dip),
232210923SEvan.Yan@Sun.COM &request, &answer, &alen,
232310923SEvan.Yan@Sun.COM NDI_RA_TYPE_MEM, NDI_RA_PASS)
232410923SEvan.Yan@Sun.COM != NDI_SUCCESS) {
232510923SEvan.Yan@Sun.COM DEBUG0("Failed to allocate 32b mem\n");
232610923SEvan.Yan@Sun.COM kmem_free(assigned, length);
232710923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
232810923SEvan.Yan@Sun.COM }
232910923SEvan.Yan@Sun.COM
233010923SEvan.Yan@Sun.COM break;
233110923SEvan.Yan@Sun.COM case PCI_REG_ADDR_G(PCI_ADDR_IO):
233210923SEvan.Yan@Sun.COM request.ra_addr = (uint64_t)
233310923SEvan.Yan@Sun.COM assigned[i].pci_phys_low;
233410923SEvan.Yan@Sun.COM
233510923SEvan.Yan@Sun.COM /* allocate I/O space from the allocator */
233610923SEvan.Yan@Sun.COM if (ndi_ra_alloc(ddi_get_parent(dip),
233710923SEvan.Yan@Sun.COM &request, &answer, &alen,
233810923SEvan.Yan@Sun.COM NDI_RA_TYPE_IO, NDI_RA_PASS)
233910923SEvan.Yan@Sun.COM != NDI_SUCCESS) {
234010923SEvan.Yan@Sun.COM DEBUG0("Failed to allocate I/O\n");
234110923SEvan.Yan@Sun.COM kmem_free(assigned, length);
234210923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
234310923SEvan.Yan@Sun.COM }
234410923SEvan.Yan@Sun.COM
234510923SEvan.Yan@Sun.COM break;
234610923SEvan.Yan@Sun.COM default:
234710923SEvan.Yan@Sun.COM DEBUG0("Unknown register type\n");
234810923SEvan.Yan@Sun.COM kmem_free(assigned, length);
234910923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
235010923SEvan.Yan@Sun.COM } /* switch */
235110923SEvan.Yan@Sun.COM }
235210923SEvan.Yan@Sun.COM }
235310923SEvan.Yan@Sun.COM
235410923SEvan.Yan@Sun.COM (void) pcicfg_device_on(handle);
235510923SEvan.Yan@Sun.COM kmem_free(assigned, length);
235610923SEvan.Yan@Sun.COM
235710923SEvan.Yan@Sun.COM PCICFG_DUMP_DEVICE_CONFIG(handle);
235810923SEvan.Yan@Sun.COM
235910923SEvan.Yan@Sun.COM (void) pcicfg_config_teardown(&handle);
236010923SEvan.Yan@Sun.COM return (PCICFG_SUCCESS);
236110923SEvan.Yan@Sun.COM }
236210923SEvan.Yan@Sun.COM
236310923SEvan.Yan@Sun.COM /*
236410923SEvan.Yan@Sun.COM * The "dip" passed to this routine is assumed to be
236510923SEvan.Yan@Sun.COM * the device at the Hotplug Connection (CN). Currently it is
236610923SEvan.Yan@Sun.COM * assumed to be a bridge.
236710923SEvan.Yan@Sun.COM */
236810923SEvan.Yan@Sun.COM static int
pcicfg_allocate_chunk(dev_info_t * dip)236910923SEvan.Yan@Sun.COM pcicfg_allocate_chunk(dev_info_t *dip)
237010923SEvan.Yan@Sun.COM {
237110923SEvan.Yan@Sun.COM pcicfg_phdl_t *phdl;
237210923SEvan.Yan@Sun.COM ndi_ra_request_t *mem_request;
237310923SEvan.Yan@Sun.COM ndi_ra_request_t *io_request;
237410923SEvan.Yan@Sun.COM uint64_t mem_answer;
237510923SEvan.Yan@Sun.COM uint64_t io_answer;
237610923SEvan.Yan@Sun.COM int count;
237710923SEvan.Yan@Sun.COM uint64_t alen;
237810923SEvan.Yan@Sun.COM
237910923SEvan.Yan@Sun.COM /*
238010923SEvan.Yan@Sun.COM * This should not find an existing entry - so
238110923SEvan.Yan@Sun.COM * it will create a new one.
238210923SEvan.Yan@Sun.COM */
238310923SEvan.Yan@Sun.COM phdl = pcicfg_find_phdl(dip);
238410923SEvan.Yan@Sun.COM ASSERT(phdl);
238510923SEvan.Yan@Sun.COM
238610923SEvan.Yan@Sun.COM mem_request = &phdl->mem_req;
238710923SEvan.Yan@Sun.COM io_request = &phdl->io_req;
238810923SEvan.Yan@Sun.COM
238910923SEvan.Yan@Sun.COM /*
239010923SEvan.Yan@Sun.COM * From this point in the tree - walk the devices,
239110923SEvan.Yan@Sun.COM * The function passed in will read and "sum" up
239210923SEvan.Yan@Sun.COM * the memory and I/O requirements and put them in
239310923SEvan.Yan@Sun.COM * structure "phdl".
239410923SEvan.Yan@Sun.COM */
239510923SEvan.Yan@Sun.COM ndi_devi_enter(ddi_get_parent(dip), &count);
239610923SEvan.Yan@Sun.COM ddi_walk_devs(dip, pcicfg_sum_resources, (void *)phdl);
239710923SEvan.Yan@Sun.COM ndi_devi_exit(ddi_get_parent(dip), count);
239810923SEvan.Yan@Sun.COM
239910923SEvan.Yan@Sun.COM if (phdl->error != PCICFG_SUCCESS) {
240010923SEvan.Yan@Sun.COM DEBUG0("Failure summing resources\n");
240110923SEvan.Yan@Sun.COM return (phdl->error);
240210923SEvan.Yan@Sun.COM }
240310923SEvan.Yan@Sun.COM
240410923SEvan.Yan@Sun.COM /*
240510923SEvan.Yan@Sun.COM * Call into the memory allocator with the request.
240610923SEvan.Yan@Sun.COM * Record the addresses returned in the phdl
240710923SEvan.Yan@Sun.COM */
240810923SEvan.Yan@Sun.COM DEBUG1("Connector requires [0x%x] bytes of memory space\n",
240910923SEvan.Yan@Sun.COM mem_request->ra_len);
241010923SEvan.Yan@Sun.COM DEBUG1("Connector requires [0x%x] bytes of I/O space\n",
241110923SEvan.Yan@Sun.COM io_request->ra_len);
241210923SEvan.Yan@Sun.COM
241310923SEvan.Yan@Sun.COM mem_request->ra_align_mask =
241410923SEvan.Yan@Sun.COM PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */
241510923SEvan.Yan@Sun.COM io_request->ra_align_mask =
241610923SEvan.Yan@Sun.COM PCICFG_IOGRAN - 1; /* 4K alignment on I/O space */
241710923SEvan.Yan@Sun.COM io_request->ra_boundbase = 0;
241810923SEvan.Yan@Sun.COM io_request->ra_boundlen = PCICFG_4GIG_LIMIT;
241910923SEvan.Yan@Sun.COM io_request->ra_flags |= NDI_RA_ALLOC_BOUNDED;
242010923SEvan.Yan@Sun.COM
242110923SEvan.Yan@Sun.COM mem_request->ra_len =
242210923SEvan.Yan@Sun.COM PCICFG_ROUND_UP(mem_request->ra_len, PCICFG_MEMGRAN);
242310923SEvan.Yan@Sun.COM
242410923SEvan.Yan@Sun.COM io_request->ra_len =
242510923SEvan.Yan@Sun.COM PCICFG_ROUND_UP(io_request->ra_len, PCICFG_IOGRAN);
242610923SEvan.Yan@Sun.COM
242710923SEvan.Yan@Sun.COM if (ndi_ra_alloc(ddi_get_parent(dip),
242810923SEvan.Yan@Sun.COM mem_request, &mem_answer, &alen,
242910923SEvan.Yan@Sun.COM NDI_RA_TYPE_MEM, NDI_RA_PASS) != NDI_SUCCESS) {
243010923SEvan.Yan@Sun.COM DEBUG0("Failed to allocate memory\n");
243110923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
243210923SEvan.Yan@Sun.COM }
243310923SEvan.Yan@Sun.COM
243410923SEvan.Yan@Sun.COM phdl->memory_base = phdl->memory_last = mem_answer;
243510923SEvan.Yan@Sun.COM phdl->memory_len = alen;
243610923SEvan.Yan@Sun.COM
243710923SEvan.Yan@Sun.COM phdl->mem_hole.start = phdl->memory_base;
243810923SEvan.Yan@Sun.COM phdl->mem_hole.len = phdl->memory_len;
243910923SEvan.Yan@Sun.COM phdl->mem_hole.next = (hole_t *)NULL;
244010923SEvan.Yan@Sun.COM
244110923SEvan.Yan@Sun.COM if (ndi_ra_alloc(ddi_get_parent(dip), io_request, &io_answer,
244210923SEvan.Yan@Sun.COM &alen, NDI_RA_TYPE_IO, NDI_RA_PASS) != NDI_SUCCESS) {
244310923SEvan.Yan@Sun.COM
244410923SEvan.Yan@Sun.COM DEBUG0("Failed to allocate I/O space\n");
244510923SEvan.Yan@Sun.COM (void) ndi_ra_free(ddi_get_parent(dip), mem_answer,
244610923SEvan.Yan@Sun.COM alen, NDI_RA_TYPE_MEM, NDI_RA_PASS);
244710923SEvan.Yan@Sun.COM phdl->memory_len = phdl->io_len = 0;
244810923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
244910923SEvan.Yan@Sun.COM }
245010923SEvan.Yan@Sun.COM
245110923SEvan.Yan@Sun.COM phdl->io_base = phdl->io_last = (uint32_t)io_answer;
245210923SEvan.Yan@Sun.COM phdl->io_len = (uint32_t)alen;
245310923SEvan.Yan@Sun.COM
245410923SEvan.Yan@Sun.COM phdl->io_hole.start = phdl->io_base;
245510923SEvan.Yan@Sun.COM phdl->io_hole.len = phdl->io_len;
245610923SEvan.Yan@Sun.COM phdl->io_hole.next = (hole_t *)NULL;
245710923SEvan.Yan@Sun.COM
245810923SEvan.Yan@Sun.COM DEBUG2("MEMORY BASE = [0x%x] length [0x%x]\n",
245910923SEvan.Yan@Sun.COM phdl->memory_base, phdl->memory_len);
246010923SEvan.Yan@Sun.COM DEBUG2("IO BASE = [0x%x] length [0x%x]\n",
246110923SEvan.Yan@Sun.COM phdl->io_base, phdl->io_len);
246210923SEvan.Yan@Sun.COM
246310923SEvan.Yan@Sun.COM return (PCICFG_SUCCESS);
246410923SEvan.Yan@Sun.COM }
246510923SEvan.Yan@Sun.COM
246610923SEvan.Yan@Sun.COM #ifdef DEBUG
246710923SEvan.Yan@Sun.COM /*
246810923SEvan.Yan@Sun.COM * This function is useful in debug mode, where we can measure how
246910923SEvan.Yan@Sun.COM * much memory was wasted/unallocated in bridge device's domain.
247010923SEvan.Yan@Sun.COM */
247110923SEvan.Yan@Sun.COM static uint64_t
pcicfg_unused_space(hole_t * hole,uint32_t * hole_count)247210923SEvan.Yan@Sun.COM pcicfg_unused_space(hole_t *hole, uint32_t *hole_count)
247310923SEvan.Yan@Sun.COM {
247410923SEvan.Yan@Sun.COM uint64_t len = 0;
247510923SEvan.Yan@Sun.COM uint32_t count = 0;
247610923SEvan.Yan@Sun.COM
247710923SEvan.Yan@Sun.COM do {
247810923SEvan.Yan@Sun.COM len += hole->len;
247910923SEvan.Yan@Sun.COM hole = hole->next;
248010923SEvan.Yan@Sun.COM count++;
248110923SEvan.Yan@Sun.COM } while (hole);
248210923SEvan.Yan@Sun.COM *hole_count = count;
248310923SEvan.Yan@Sun.COM return (len);
248410923SEvan.Yan@Sun.COM }
248510923SEvan.Yan@Sun.COM #endif
248610923SEvan.Yan@Sun.COM
248710923SEvan.Yan@Sun.COM /*
248810923SEvan.Yan@Sun.COM * This function frees data structures that hold the hole information
248910923SEvan.Yan@Sun.COM * which are allocated in pcicfg_alloc_hole(). This is not freeing
249010923SEvan.Yan@Sun.COM * any memory allocated through NDI calls.
249110923SEvan.Yan@Sun.COM */
249210923SEvan.Yan@Sun.COM static void
pcicfg_free_hole(hole_t * addr_hole)249310923SEvan.Yan@Sun.COM pcicfg_free_hole(hole_t *addr_hole)
249410923SEvan.Yan@Sun.COM {
249510923SEvan.Yan@Sun.COM hole_t *nhole, *hole = addr_hole->next;
249610923SEvan.Yan@Sun.COM
249710923SEvan.Yan@Sun.COM while (hole) {
249810923SEvan.Yan@Sun.COM nhole = hole->next;
249910923SEvan.Yan@Sun.COM kmem_free(hole, sizeof (hole_t));
250010923SEvan.Yan@Sun.COM hole = nhole;
250110923SEvan.Yan@Sun.COM }
250210923SEvan.Yan@Sun.COM }
250310923SEvan.Yan@Sun.COM
250410923SEvan.Yan@Sun.COM static uint64_t
pcicfg_alloc_hole(hole_t * addr_hole,uint64_t * alast,uint32_t length)250510923SEvan.Yan@Sun.COM pcicfg_alloc_hole(hole_t *addr_hole, uint64_t *alast, uint32_t length)
250610923SEvan.Yan@Sun.COM {
250710923SEvan.Yan@Sun.COM uint64_t actual_hole_start, ostart, olen;
250810923SEvan.Yan@Sun.COM hole_t *hole = addr_hole, *thole, *nhole;
250910923SEvan.Yan@Sun.COM
251010923SEvan.Yan@Sun.COM do {
251110923SEvan.Yan@Sun.COM actual_hole_start = PCICFG_ROUND_UP(hole->start, length);
251210923SEvan.Yan@Sun.COM if (((actual_hole_start - hole->start) + length) <= hole->len) {
251310923SEvan.Yan@Sun.COM DEBUG3("hole found. start %llx, len %llx, req=%x\n",
251410923SEvan.Yan@Sun.COM hole->start, hole->len, length);
251510923SEvan.Yan@Sun.COM ostart = hole->start;
251610923SEvan.Yan@Sun.COM olen = hole->len;
251710923SEvan.Yan@Sun.COM /* current hole parameters adjust */
251810923SEvan.Yan@Sun.COM if ((actual_hole_start - hole->start) == 0) {
251910923SEvan.Yan@Sun.COM hole->start += length;
252010923SEvan.Yan@Sun.COM hole->len -= length;
252110923SEvan.Yan@Sun.COM if (hole->start > *alast)
252210923SEvan.Yan@Sun.COM *alast = hole->start;
252310923SEvan.Yan@Sun.COM } else {
252410923SEvan.Yan@Sun.COM hole->len = actual_hole_start - hole->start;
252510923SEvan.Yan@Sun.COM nhole = (hole_t *)kmem_zalloc(sizeof (hole_t),
252610923SEvan.Yan@Sun.COM KM_SLEEP);
252710923SEvan.Yan@Sun.COM nhole->start = actual_hole_start + length;
252810923SEvan.Yan@Sun.COM nhole->len = (ostart + olen) - nhole->start;
252910923SEvan.Yan@Sun.COM nhole->next = NULL;
253010923SEvan.Yan@Sun.COM thole = hole->next;
253110923SEvan.Yan@Sun.COM hole->next = nhole;
253210923SEvan.Yan@Sun.COM nhole->next = thole;
253310923SEvan.Yan@Sun.COM if (nhole->start > *alast)
253410923SEvan.Yan@Sun.COM *alast = nhole->start;
253510923SEvan.Yan@Sun.COM DEBUG2("put new hole to %llx, %llx\n",
253610923SEvan.Yan@Sun.COM nhole->start, nhole->len);
253710923SEvan.Yan@Sun.COM }
253810923SEvan.Yan@Sun.COM DEBUG2("adjust current hole to %llx, %llx\n",
253910923SEvan.Yan@Sun.COM hole->start, hole->len);
254010923SEvan.Yan@Sun.COM break;
254110923SEvan.Yan@Sun.COM }
254210923SEvan.Yan@Sun.COM actual_hole_start = 0;
254310923SEvan.Yan@Sun.COM hole = hole->next;
254410923SEvan.Yan@Sun.COM } while (hole);
254510923SEvan.Yan@Sun.COM
254610923SEvan.Yan@Sun.COM DEBUG1("return hole at %llx\n", actual_hole_start);
254710923SEvan.Yan@Sun.COM return (actual_hole_start);
254810923SEvan.Yan@Sun.COM }
254910923SEvan.Yan@Sun.COM
255010923SEvan.Yan@Sun.COM static void
pcicfg_get_mem(pcicfg_phdl_t * entry,uint32_t length,uint64_t * ans)255110923SEvan.Yan@Sun.COM pcicfg_get_mem(pcicfg_phdl_t *entry,
255210923SEvan.Yan@Sun.COM uint32_t length, uint64_t *ans)
255310923SEvan.Yan@Sun.COM {
255410923SEvan.Yan@Sun.COM uint64_t new_mem;
255510923SEvan.Yan@Sun.COM
255610923SEvan.Yan@Sun.COM /* See if there is a hole, that can hold this request. */
255710923SEvan.Yan@Sun.COM new_mem = pcicfg_alloc_hole(&entry->mem_hole, &entry->memory_last,
255810923SEvan.Yan@Sun.COM length);
255910923SEvan.Yan@Sun.COM if (new_mem) { /* if non-zero, found a hole. */
256010923SEvan.Yan@Sun.COM if (ans != NULL)
256110923SEvan.Yan@Sun.COM *ans = new_mem;
256210923SEvan.Yan@Sun.COM } else
256310923SEvan.Yan@Sun.COM cmn_err(CE_WARN, "No %u bytes memory window for %s\n",
256410923SEvan.Yan@Sun.COM length, ddi_get_name(entry->dip));
256510923SEvan.Yan@Sun.COM }
256610923SEvan.Yan@Sun.COM
256710923SEvan.Yan@Sun.COM static void
pcicfg_get_io(pcicfg_phdl_t * entry,uint32_t length,uint32_t * ans)256810923SEvan.Yan@Sun.COM pcicfg_get_io(pcicfg_phdl_t *entry,
256910923SEvan.Yan@Sun.COM uint32_t length, uint32_t *ans)
257010923SEvan.Yan@Sun.COM {
257110923SEvan.Yan@Sun.COM uint32_t new_io;
257210923SEvan.Yan@Sun.COM uint64_t io_last;
257310923SEvan.Yan@Sun.COM
257410923SEvan.Yan@Sun.COM /*
257510923SEvan.Yan@Sun.COM * See if there is a hole, that can hold this request.
257610923SEvan.Yan@Sun.COM * Pass 64 bit parameters and then truncate to 32 bit.
257710923SEvan.Yan@Sun.COM */
257810923SEvan.Yan@Sun.COM io_last = entry->io_last;
257910923SEvan.Yan@Sun.COM new_io = (uint32_t)pcicfg_alloc_hole(&entry->io_hole, &io_last, length);
258010923SEvan.Yan@Sun.COM if (new_io) { /* if non-zero, found a hole. */
258110923SEvan.Yan@Sun.COM entry->io_last = (uint32_t)io_last;
258210923SEvan.Yan@Sun.COM if (ans != NULL)
258310923SEvan.Yan@Sun.COM *ans = new_io;
258410923SEvan.Yan@Sun.COM } else
258510923SEvan.Yan@Sun.COM cmn_err(CE_WARN, "No %u bytes IO space window for %s\n",
258610923SEvan.Yan@Sun.COM length, ddi_get_name(entry->dip));
258710923SEvan.Yan@Sun.COM }
258810923SEvan.Yan@Sun.COM
258910923SEvan.Yan@Sun.COM static int
pcicfg_sum_resources(dev_info_t * dip,void * hdl)259010923SEvan.Yan@Sun.COM pcicfg_sum_resources(dev_info_t *dip, void *hdl)
259110923SEvan.Yan@Sun.COM {
259210923SEvan.Yan@Sun.COM pcicfg_phdl_t *entry = (pcicfg_phdl_t *)hdl;
259310923SEvan.Yan@Sun.COM pci_regspec_t *pci_rp;
259410923SEvan.Yan@Sun.COM int length;
259510923SEvan.Yan@Sun.COM int rcount;
259610923SEvan.Yan@Sun.COM int i;
259710923SEvan.Yan@Sun.COM ndi_ra_request_t *mem_request;
259810923SEvan.Yan@Sun.COM ndi_ra_request_t *io_request;
259910923SEvan.Yan@Sun.COM uint8_t header_type;
260010923SEvan.Yan@Sun.COM ddi_acc_handle_t handle;
260110923SEvan.Yan@Sun.COM
260210923SEvan.Yan@Sun.COM entry->error = PCICFG_SUCCESS;
260310923SEvan.Yan@Sun.COM
260410923SEvan.Yan@Sun.COM mem_request = &entry->mem_req;
260510923SEvan.Yan@Sun.COM io_request = &entry->io_req;
260610923SEvan.Yan@Sun.COM
260710923SEvan.Yan@Sun.COM if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
260810923SEvan.Yan@Sun.COM DEBUG0("Failed to map config space!\n");
260910923SEvan.Yan@Sun.COM entry->error = PCICFG_FAILURE;
261010923SEvan.Yan@Sun.COM return (DDI_WALK_TERMINATE);
261110923SEvan.Yan@Sun.COM }
261210923SEvan.Yan@Sun.COM
261310923SEvan.Yan@Sun.COM header_type = pci_config_get8(handle, PCI_CONF_HEADER);
261410923SEvan.Yan@Sun.COM
261510923SEvan.Yan@Sun.COM /*
261610923SEvan.Yan@Sun.COM * If its a bridge - just record the highest bus seen
261710923SEvan.Yan@Sun.COM */
261810923SEvan.Yan@Sun.COM if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
261910923SEvan.Yan@Sun.COM
262010923SEvan.Yan@Sun.COM if (entry->highest_bus < pci_config_get8(handle,
262110923SEvan.Yan@Sun.COM PCI_BCNF_SECBUS)) {
262210923SEvan.Yan@Sun.COM entry->highest_bus =
262310923SEvan.Yan@Sun.COM pci_config_get8(handle, PCI_BCNF_SECBUS);
262410923SEvan.Yan@Sun.COM }
262510923SEvan.Yan@Sun.COM
262610923SEvan.Yan@Sun.COM (void) pcicfg_config_teardown(&handle);
262710923SEvan.Yan@Sun.COM entry->error = PCICFG_FAILURE;
262810923SEvan.Yan@Sun.COM return (DDI_WALK_CONTINUE);
262910923SEvan.Yan@Sun.COM } else {
263010923SEvan.Yan@Sun.COM if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
263110923SEvan.Yan@Sun.COM DDI_PROP_DONTPASS, "reg", (caddr_t)&pci_rp,
263210923SEvan.Yan@Sun.COM &length) != DDI_PROP_SUCCESS) {
263310923SEvan.Yan@Sun.COM /*
263410923SEvan.Yan@Sun.COM * If one node in (the subtree of nodes)
263510923SEvan.Yan@Sun.COM * does'nt have a "reg" property fail the
263610923SEvan.Yan@Sun.COM * allocation.
263710923SEvan.Yan@Sun.COM */
263810923SEvan.Yan@Sun.COM entry->memory_len = 0;
263910923SEvan.Yan@Sun.COM entry->io_len = 0;
264010923SEvan.Yan@Sun.COM entry->error = PCICFG_FAILURE;
264110923SEvan.Yan@Sun.COM return (DDI_WALK_TERMINATE);
264210923SEvan.Yan@Sun.COM }
264310923SEvan.Yan@Sun.COM /*
264410923SEvan.Yan@Sun.COM * For each "reg" property with a length, add that to the
264510923SEvan.Yan@Sun.COM * total memory (or I/O) to allocate.
264610923SEvan.Yan@Sun.COM */
264710923SEvan.Yan@Sun.COM rcount = length / sizeof (pci_regspec_t);
264810923SEvan.Yan@Sun.COM
264910923SEvan.Yan@Sun.COM for (i = 0; i < rcount; i++) {
265010923SEvan.Yan@Sun.COM
265110923SEvan.Yan@Sun.COM switch (PCI_REG_ADDR_G(pci_rp[i].pci_phys_hi)) {
265210923SEvan.Yan@Sun.COM
265310923SEvan.Yan@Sun.COM case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
265410923SEvan.Yan@Sun.COM mem_request->ra_len =
265510923SEvan.Yan@Sun.COM pci_rp[i].pci_size_low +
265610923SEvan.Yan@Sun.COM PCICFG_ROUND_UP(mem_request->ra_len,
265710923SEvan.Yan@Sun.COM pci_rp[i].pci_size_low);
265810923SEvan.Yan@Sun.COM DEBUG1("ADDING 32 --->0x%x\n",
265910923SEvan.Yan@Sun.COM pci_rp[i].pci_size_low);
266010923SEvan.Yan@Sun.COM
266110923SEvan.Yan@Sun.COM break;
266210923SEvan.Yan@Sun.COM case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
266310923SEvan.Yan@Sun.COM mem_request->ra_len =
266410923SEvan.Yan@Sun.COM pci_rp[i].pci_size_low +
266510923SEvan.Yan@Sun.COM PCICFG_ROUND_UP(mem_request->ra_len,
266610923SEvan.Yan@Sun.COM pci_rp[i].pci_size_low);
266710923SEvan.Yan@Sun.COM DEBUG1("ADDING 64 --->0x%x\n",
266810923SEvan.Yan@Sun.COM pci_rp[i].pci_size_low);
266910923SEvan.Yan@Sun.COM
267010923SEvan.Yan@Sun.COM break;
267110923SEvan.Yan@Sun.COM case PCI_REG_ADDR_G(PCI_ADDR_IO):
267210923SEvan.Yan@Sun.COM io_request->ra_len =
267310923SEvan.Yan@Sun.COM pci_rp[i].pci_size_low +
267410923SEvan.Yan@Sun.COM PCICFG_ROUND_UP(io_request->ra_len,
267510923SEvan.Yan@Sun.COM pci_rp[i].pci_size_low);
267610923SEvan.Yan@Sun.COM DEBUG1("ADDING I/O --->0x%x\n",
267710923SEvan.Yan@Sun.COM pci_rp[i].pci_size_low);
267810923SEvan.Yan@Sun.COM break;
267910923SEvan.Yan@Sun.COM default:
268010923SEvan.Yan@Sun.COM /* Config space register - not included */
268110923SEvan.Yan@Sun.COM break;
268210923SEvan.Yan@Sun.COM }
268310923SEvan.Yan@Sun.COM }
268410923SEvan.Yan@Sun.COM
268510923SEvan.Yan@Sun.COM /*
268610923SEvan.Yan@Sun.COM * free the memory allocated by ddi_getlongprop
268710923SEvan.Yan@Sun.COM */
268810923SEvan.Yan@Sun.COM kmem_free(pci_rp, length);
268910923SEvan.Yan@Sun.COM
269010923SEvan.Yan@Sun.COM /*
269110923SEvan.Yan@Sun.COM * continue the walk to the next sibling to sum memory
269210923SEvan.Yan@Sun.COM */
269310923SEvan.Yan@Sun.COM
269410923SEvan.Yan@Sun.COM (void) pcicfg_config_teardown(&handle);
269510923SEvan.Yan@Sun.COM
269610923SEvan.Yan@Sun.COM return (DDI_WALK_CONTINUE);
269710923SEvan.Yan@Sun.COM }
269810923SEvan.Yan@Sun.COM }
269910923SEvan.Yan@Sun.COM
270010923SEvan.Yan@Sun.COM static int
pcicfg_find_resource_end(dev_info_t * dip,void * hdl)270110923SEvan.Yan@Sun.COM pcicfg_find_resource_end(dev_info_t *dip, void *hdl)
270210923SEvan.Yan@Sun.COM {
270310923SEvan.Yan@Sun.COM pcicfg_phdl_t *entry_p = (pcicfg_phdl_t *)hdl;
270410923SEvan.Yan@Sun.COM pci_regspec_t *pci_ap;
270510923SEvan.Yan@Sun.COM pcicfg_range_t *ranges;
270610923SEvan.Yan@Sun.COM int length;
270710923SEvan.Yan@Sun.COM int rcount;
270810923SEvan.Yan@Sun.COM int i;
270910923SEvan.Yan@Sun.COM
271010923SEvan.Yan@Sun.COM entry_p->error = PCICFG_SUCCESS;
271110923SEvan.Yan@Sun.COM
271210923SEvan.Yan@Sun.COM if (dip == entry_p->dip) {
271310923SEvan.Yan@Sun.COM DEBUG0("Don't include parent bridge node\n");
271410923SEvan.Yan@Sun.COM return (DDI_WALK_CONTINUE);
271510923SEvan.Yan@Sun.COM }
271610923SEvan.Yan@Sun.COM
271710923SEvan.Yan@Sun.COM if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
271810923SEvan.Yan@Sun.COM DDI_PROP_DONTPASS, "ranges",
271910923SEvan.Yan@Sun.COM (caddr_t)&ranges, &length) != DDI_PROP_SUCCESS) {
272010923SEvan.Yan@Sun.COM DEBUG0("Node doesn't have ranges\n");
272110923SEvan.Yan@Sun.COM goto ap;
272210923SEvan.Yan@Sun.COM }
272310923SEvan.Yan@Sun.COM
272410923SEvan.Yan@Sun.COM rcount = length / sizeof (pcicfg_range_t);
272510923SEvan.Yan@Sun.COM
272610923SEvan.Yan@Sun.COM for (i = 0; i < rcount; i++) {
272710923SEvan.Yan@Sun.COM uint64_t base;
272810923SEvan.Yan@Sun.COM uint64_t mid = ranges[i].child_mid;
272910923SEvan.Yan@Sun.COM uint64_t lo = ranges[i].child_lo;
273010923SEvan.Yan@Sun.COM uint64_t size = ranges[i].size_lo;
273110923SEvan.Yan@Sun.COM
273210923SEvan.Yan@Sun.COM switch (PCI_REG_ADDR_G(ranges[i].child_hi)) {
273310923SEvan.Yan@Sun.COM
273410923SEvan.Yan@Sun.COM case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
273510923SEvan.Yan@Sun.COM base = entry_p->memory_base;
273610923SEvan.Yan@Sun.COM entry_p->memory_base = MAX(base, lo + size);
273710923SEvan.Yan@Sun.COM break;
273810923SEvan.Yan@Sun.COM case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
273910923SEvan.Yan@Sun.COM base = entry_p->memory_base;
274010923SEvan.Yan@Sun.COM entry_p->memory_base = MAX(base,
274110923SEvan.Yan@Sun.COM PCICFG_LADDR(lo, mid) + size);
274210923SEvan.Yan@Sun.COM break;
274310923SEvan.Yan@Sun.COM case PCI_REG_ADDR_G(PCI_ADDR_IO):
274410923SEvan.Yan@Sun.COM base = entry_p->io_base;
274510923SEvan.Yan@Sun.COM entry_p->io_base = MAX(base, lo + size);
274610923SEvan.Yan@Sun.COM break;
274710923SEvan.Yan@Sun.COM }
274810923SEvan.Yan@Sun.COM }
274910923SEvan.Yan@Sun.COM
275010923SEvan.Yan@Sun.COM kmem_free(ranges, length);
275110923SEvan.Yan@Sun.COM return (DDI_WALK_CONTINUE);
275210923SEvan.Yan@Sun.COM
275310923SEvan.Yan@Sun.COM ap: if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
275410923SEvan.Yan@Sun.COM DDI_PROP_DONTPASS, "assigned-addresses",
275510923SEvan.Yan@Sun.COM (caddr_t)&pci_ap, &length) != DDI_PROP_SUCCESS) {
275610923SEvan.Yan@Sun.COM DEBUG0("Node doesn't have assigned-addresses\n");
275710923SEvan.Yan@Sun.COM return (DDI_WALK_CONTINUE);
275810923SEvan.Yan@Sun.COM }
275910923SEvan.Yan@Sun.COM
276010923SEvan.Yan@Sun.COM rcount = length / sizeof (pci_regspec_t);
276110923SEvan.Yan@Sun.COM
276210923SEvan.Yan@Sun.COM for (i = 0; i < rcount; i++) {
276310923SEvan.Yan@Sun.COM
276410923SEvan.Yan@Sun.COM switch (PCI_REG_ADDR_G(pci_ap[i].pci_phys_hi)) {
276510923SEvan.Yan@Sun.COM
276610923SEvan.Yan@Sun.COM case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
276710923SEvan.Yan@Sun.COM if ((pci_ap[i].pci_phys_low +
276810923SEvan.Yan@Sun.COM pci_ap[i].pci_size_low) >
276910923SEvan.Yan@Sun.COM entry_p->memory_base) {
277010923SEvan.Yan@Sun.COM entry_p->memory_base =
277110923SEvan.Yan@Sun.COM pci_ap[i].pci_phys_low +
277210923SEvan.Yan@Sun.COM pci_ap[i].pci_size_low;
277310923SEvan.Yan@Sun.COM }
277410923SEvan.Yan@Sun.COM break;
277510923SEvan.Yan@Sun.COM case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
277610923SEvan.Yan@Sun.COM if ((PCICFG_LADDR(pci_ap[i].pci_phys_low,
277710923SEvan.Yan@Sun.COM pci_ap[i].pci_phys_mid) +
277810923SEvan.Yan@Sun.COM pci_ap[i].pci_size_low) >
277910923SEvan.Yan@Sun.COM entry_p->memory_base) {
278010923SEvan.Yan@Sun.COM entry_p->memory_base = PCICFG_LADDR(
278110923SEvan.Yan@Sun.COM pci_ap[i].pci_phys_low,
278210923SEvan.Yan@Sun.COM pci_ap[i].pci_phys_mid) +
278310923SEvan.Yan@Sun.COM pci_ap[i].pci_size_low;
278410923SEvan.Yan@Sun.COM }
278510923SEvan.Yan@Sun.COM break;
278610923SEvan.Yan@Sun.COM case PCI_REG_ADDR_G(PCI_ADDR_IO):
278710923SEvan.Yan@Sun.COM if ((pci_ap[i].pci_phys_low +
278810923SEvan.Yan@Sun.COM pci_ap[i].pci_size_low) >
278910923SEvan.Yan@Sun.COM entry_p->io_base) {
279010923SEvan.Yan@Sun.COM entry_p->io_base =
279110923SEvan.Yan@Sun.COM pci_ap[i].pci_phys_low +
279210923SEvan.Yan@Sun.COM pci_ap[i].pci_size_low;
279310923SEvan.Yan@Sun.COM }
279410923SEvan.Yan@Sun.COM break;
279510923SEvan.Yan@Sun.COM }
279610923SEvan.Yan@Sun.COM }
279710923SEvan.Yan@Sun.COM
279810923SEvan.Yan@Sun.COM /*
279910923SEvan.Yan@Sun.COM * free the memory allocated by ddi_getlongprop
280010923SEvan.Yan@Sun.COM */
280110923SEvan.Yan@Sun.COM kmem_free(pci_ap, length);
280210923SEvan.Yan@Sun.COM
280310923SEvan.Yan@Sun.COM /*
280410923SEvan.Yan@Sun.COM * continue the walk to the next sibling to sum memory
280510923SEvan.Yan@Sun.COM */
280610923SEvan.Yan@Sun.COM return (DDI_WALK_CONTINUE);
280710923SEvan.Yan@Sun.COM }
280810923SEvan.Yan@Sun.COM
280910923SEvan.Yan@Sun.COM static int
pcicfg_free_bridge_resources(dev_info_t * dip)281010923SEvan.Yan@Sun.COM pcicfg_free_bridge_resources(dev_info_t *dip)
281110923SEvan.Yan@Sun.COM {
281210923SEvan.Yan@Sun.COM pcicfg_range_t *ranges;
281310923SEvan.Yan@Sun.COM uint_t *bus;
281410923SEvan.Yan@Sun.COM int k;
281510923SEvan.Yan@Sun.COM int length;
281610923SEvan.Yan@Sun.COM int i;
281710923SEvan.Yan@Sun.COM
281810923SEvan.Yan@Sun.COM
281910923SEvan.Yan@Sun.COM if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
282010923SEvan.Yan@Sun.COM DDI_PROP_DONTPASS, "ranges", (caddr_t)&ranges,
282110923SEvan.Yan@Sun.COM &length) != DDI_PROP_SUCCESS) {
282210923SEvan.Yan@Sun.COM DEBUG0("Failed to read ranges property\n");
282310923SEvan.Yan@Sun.COM if (ddi_get_child(dip)) {
282410923SEvan.Yan@Sun.COM cmn_err(CE_WARN, "No ranges property found for %s",
282510923SEvan.Yan@Sun.COM ddi_get_name(dip));
282610923SEvan.Yan@Sun.COM /*
282710923SEvan.Yan@Sun.COM * strictly speaking, we can check for children with
282810923SEvan.Yan@Sun.COM * assigned-addresses but for now it is better to
282910923SEvan.Yan@Sun.COM * be conservative and assume that if there are child
283010923SEvan.Yan@Sun.COM * nodes, then they do consume PCI memory or IO
283110923SEvan.Yan@Sun.COM * resources, Hence return failure.
283210923SEvan.Yan@Sun.COM */
283310923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
283410923SEvan.Yan@Sun.COM }
283510923SEvan.Yan@Sun.COM length = 0;
283610923SEvan.Yan@Sun.COM
283710923SEvan.Yan@Sun.COM }
283810923SEvan.Yan@Sun.COM
283910923SEvan.Yan@Sun.COM for (i = 0; i < length / sizeof (pcicfg_range_t); i++) {
284010923SEvan.Yan@Sun.COM if (ranges[i].size_lo != 0 ||
284110923SEvan.Yan@Sun.COM ranges[i].size_hi != 0) {
284210923SEvan.Yan@Sun.COM switch (ranges[i].parent_hi & PCI_REG_ADDR_M) {
284310923SEvan.Yan@Sun.COM case PCI_ADDR_IO:
284410923SEvan.Yan@Sun.COM DEBUG2("Free I/O "
284510923SEvan.Yan@Sun.COM "base/length = [0x%x]/[0x%x]\n",
284610923SEvan.Yan@Sun.COM ranges[i].child_lo,
284710923SEvan.Yan@Sun.COM ranges[i].size_lo);
284810923SEvan.Yan@Sun.COM if (ndi_ra_free(ddi_get_parent(dip),
284910923SEvan.Yan@Sun.COM (uint64_t)ranges[i].child_lo,
285010923SEvan.Yan@Sun.COM (uint64_t)ranges[i].size_lo,
285110923SEvan.Yan@Sun.COM NDI_RA_TYPE_IO, NDI_RA_PASS)
285210923SEvan.Yan@Sun.COM != NDI_SUCCESS) {
285310923SEvan.Yan@Sun.COM DEBUG0("Trouble freeing "
285410923SEvan.Yan@Sun.COM "PCI i/o space\n");
285510923SEvan.Yan@Sun.COM kmem_free(ranges, length);
285610923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
285710923SEvan.Yan@Sun.COM }
285810923SEvan.Yan@Sun.COM break;
285910923SEvan.Yan@Sun.COM case PCI_ADDR_MEM32:
286010923SEvan.Yan@Sun.COM case PCI_ADDR_MEM64:
286110923SEvan.Yan@Sun.COM DEBUG3("Free Memory base/length = "
286210923SEvan.Yan@Sun.COM "[0x%x.%x]/[0x%x]\n",
286310923SEvan.Yan@Sun.COM ranges[i].child_mid,
286410923SEvan.Yan@Sun.COM ranges[i].child_lo,
286510923SEvan.Yan@Sun.COM ranges[i].size_lo)
286610923SEvan.Yan@Sun.COM if (ndi_ra_free(ddi_get_parent(dip),
286710923SEvan.Yan@Sun.COM PCICFG_LADDR(ranges[i].child_lo,
286810923SEvan.Yan@Sun.COM ranges[i].child_mid),
286910923SEvan.Yan@Sun.COM (uint64_t)ranges[i].size_lo,
287010923SEvan.Yan@Sun.COM NDI_RA_TYPE_MEM, NDI_RA_PASS)
287110923SEvan.Yan@Sun.COM != NDI_SUCCESS) {
287210923SEvan.Yan@Sun.COM DEBUG0("Trouble freeing "
287310923SEvan.Yan@Sun.COM "PCI memory space\n");
287410923SEvan.Yan@Sun.COM kmem_free(ranges, length);
287510923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
287610923SEvan.Yan@Sun.COM }
287710923SEvan.Yan@Sun.COM break;
287810923SEvan.Yan@Sun.COM default:
287910923SEvan.Yan@Sun.COM DEBUG0("Unknown memory space\n");
288010923SEvan.Yan@Sun.COM break;
288110923SEvan.Yan@Sun.COM }
288210923SEvan.Yan@Sun.COM }
288310923SEvan.Yan@Sun.COM }
288410923SEvan.Yan@Sun.COM
288510923SEvan.Yan@Sun.COM if (length)
288610923SEvan.Yan@Sun.COM kmem_free(ranges, length);
288710923SEvan.Yan@Sun.COM
288810923SEvan.Yan@Sun.COM if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
288910923SEvan.Yan@Sun.COM DDI_PROP_DONTPASS, "bus-range", (caddr_t)&bus,
289010923SEvan.Yan@Sun.COM &k) != DDI_PROP_SUCCESS) {
289110923SEvan.Yan@Sun.COM DEBUG0("Failed to read bus-range property\n");
289210923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
289310923SEvan.Yan@Sun.COM }
289410923SEvan.Yan@Sun.COM
289510923SEvan.Yan@Sun.COM DEBUG2("Need to free bus [%d] range [%d]\n",
289610923SEvan.Yan@Sun.COM bus[0], bus[1] - bus[0] + 1);
289710923SEvan.Yan@Sun.COM
289810923SEvan.Yan@Sun.COM if (ndi_ra_free(ddi_get_parent(dip),
289910923SEvan.Yan@Sun.COM (uint64_t)bus[0], (uint64_t)(bus[1] - bus[0] + 1),
290010923SEvan.Yan@Sun.COM NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS) != NDI_SUCCESS) {
290110923SEvan.Yan@Sun.COM /*EMPTY*/
290210923SEvan.Yan@Sun.COM DEBUG0("Failed to free a bus number\n");
290310923SEvan.Yan@Sun.COM }
290410923SEvan.Yan@Sun.COM /*
290510923SEvan.Yan@Sun.COM * Don't forget to free up memory from ddi_getlongprop
290610923SEvan.Yan@Sun.COM */
290710923SEvan.Yan@Sun.COM kmem_free((caddr_t)bus, k);
290810923SEvan.Yan@Sun.COM
290910923SEvan.Yan@Sun.COM return (PCICFG_SUCCESS);
291010923SEvan.Yan@Sun.COM }
291110923SEvan.Yan@Sun.COM
291210923SEvan.Yan@Sun.COM static int
pcicfg_free_device_resources(dev_info_t * dip,pcicfg_flags_t flags)291310923SEvan.Yan@Sun.COM pcicfg_free_device_resources(dev_info_t *dip, pcicfg_flags_t flags)
291410923SEvan.Yan@Sun.COM {
291510923SEvan.Yan@Sun.COM pci_regspec_t *assigned;
291610923SEvan.Yan@Sun.COM
291710923SEvan.Yan@Sun.COM int length;
291810923SEvan.Yan@Sun.COM int acount;
291910923SEvan.Yan@Sun.COM int i;
292010923SEvan.Yan@Sun.COM
292110923SEvan.Yan@Sun.COM if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
292210923SEvan.Yan@Sun.COM DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned,
292310923SEvan.Yan@Sun.COM &length) != DDI_PROP_SUCCESS) {
292410923SEvan.Yan@Sun.COM DEBUG0("Failed to read assigned-addresses property\n");
292510923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
292610923SEvan.Yan@Sun.COM }
292710923SEvan.Yan@Sun.COM
292810923SEvan.Yan@Sun.COM /*
292910923SEvan.Yan@Sun.COM * For each "assigned-addresses" property entry with a length,
293010923SEvan.Yan@Sun.COM * call the memory allocation routines to return the
293110923SEvan.Yan@Sun.COM * resource.
293210923SEvan.Yan@Sun.COM */
293310923SEvan.Yan@Sun.COM acount = length / sizeof (pci_regspec_t);
293410923SEvan.Yan@Sun.COM for (i = 0; i < acount; i++) {
293510923SEvan.Yan@Sun.COM /*
293610923SEvan.Yan@Sun.COM * Workaround for Devconf (x86) bug to skip extra entries
293710923SEvan.Yan@Sun.COM * beyond the PCI_CONF_BASE5 offset. But we want to free up
293810923SEvan.Yan@Sun.COM * any memory for expansion roms if allocated.
293910923SEvan.Yan@Sun.COM */
294010923SEvan.Yan@Sun.COM if ((PCI_REG_REG_G(assigned[i].pci_phys_hi) > PCI_CONF_BASE5) &&
294110923SEvan.Yan@Sun.COM (PCI_REG_REG_G(assigned[i].pci_phys_hi) != PCI_CONF_ROM))
294210923SEvan.Yan@Sun.COM break;
294310923SEvan.Yan@Sun.COM
294410923SEvan.Yan@Sun.COM if (pcicfg_free_resource(dip, assigned[i], flags)) {
294510923SEvan.Yan@Sun.COM DEBUG1("pcicfg_free_device_resources - Trouble freeing "
294610923SEvan.Yan@Sun.COM "%x\n", assigned[i].pci_phys_hi);
294710923SEvan.Yan@Sun.COM /*
294810923SEvan.Yan@Sun.COM * Don't forget to free up memory from ddi_getlongprop
294910923SEvan.Yan@Sun.COM */
295010923SEvan.Yan@Sun.COM kmem_free((caddr_t)assigned, length);
295110923SEvan.Yan@Sun.COM
295210923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
295310923SEvan.Yan@Sun.COM }
295410923SEvan.Yan@Sun.COM }
295510923SEvan.Yan@Sun.COM kmem_free(assigned, length);
295610923SEvan.Yan@Sun.COM return (PCICFG_SUCCESS);
295710923SEvan.Yan@Sun.COM }
295810923SEvan.Yan@Sun.COM
295910923SEvan.Yan@Sun.COM static int
pcicfg_free_resources(dev_info_t * dip,pcicfg_flags_t flags)296010923SEvan.Yan@Sun.COM pcicfg_free_resources(dev_info_t *dip, pcicfg_flags_t flags)
296110923SEvan.Yan@Sun.COM {
296210923SEvan.Yan@Sun.COM ddi_acc_handle_t handle;
296310923SEvan.Yan@Sun.COM uint8_t header_type;
296410923SEvan.Yan@Sun.COM
296510923SEvan.Yan@Sun.COM if (pcicfg_config_setup(dip, &handle) != DDI_SUCCESS) {
296610923SEvan.Yan@Sun.COM DEBUG0("Failed to map config space!\n");
296710923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
296810923SEvan.Yan@Sun.COM }
296910923SEvan.Yan@Sun.COM
297010923SEvan.Yan@Sun.COM header_type = pci_config_get8(handle, PCI_CONF_HEADER);
297110923SEvan.Yan@Sun.COM
297210923SEvan.Yan@Sun.COM (void) pci_config_teardown(&handle);
297310923SEvan.Yan@Sun.COM
297410923SEvan.Yan@Sun.COM /*
297510923SEvan.Yan@Sun.COM * A different algorithm is used for bridges and leaf devices.
297610923SEvan.Yan@Sun.COM */
297710923SEvan.Yan@Sun.COM if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
297810923SEvan.Yan@Sun.COM /*
297910923SEvan.Yan@Sun.COM * We only support readonly probing for leaf devices.
298010923SEvan.Yan@Sun.COM */
298110923SEvan.Yan@Sun.COM if (flags & PCICFG_FLAG_READ_ONLY)
298210923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
298310923SEvan.Yan@Sun.COM
298410923SEvan.Yan@Sun.COM if (pcicfg_free_bridge_resources(dip) != PCICFG_SUCCESS) {
298510923SEvan.Yan@Sun.COM DEBUG0("Failed freeing up bridge resources\n");
298610923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
298710923SEvan.Yan@Sun.COM }
298810923SEvan.Yan@Sun.COM } else {
298910923SEvan.Yan@Sun.COM if (pcicfg_free_device_resources(dip, flags)
299010923SEvan.Yan@Sun.COM != PCICFG_SUCCESS) {
299110923SEvan.Yan@Sun.COM DEBUG0("Failed freeing up device resources\n");
299210923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
299310923SEvan.Yan@Sun.COM }
299410923SEvan.Yan@Sun.COM }
299510923SEvan.Yan@Sun.COM return (PCICFG_SUCCESS);
299610923SEvan.Yan@Sun.COM }
299710923SEvan.Yan@Sun.COM
299810923SEvan.Yan@Sun.COM #ifndef _DONT_USE_1275_GENERIC_NAMES
299910923SEvan.Yan@Sun.COM static char *
pcicfg_get_class_name(uint32_t classcode)300010923SEvan.Yan@Sun.COM pcicfg_get_class_name(uint32_t classcode)
300110923SEvan.Yan@Sun.COM {
300210923SEvan.Yan@Sun.COM struct pcicfg_name_entry *ptr;
300310923SEvan.Yan@Sun.COM
300410923SEvan.Yan@Sun.COM for (ptr = &pcicfg_class_lookup[0]; ptr->name != NULL; ptr++) {
300510923SEvan.Yan@Sun.COM if (ptr->class_code == classcode) {
300610923SEvan.Yan@Sun.COM return (ptr->name);
300710923SEvan.Yan@Sun.COM }
300810923SEvan.Yan@Sun.COM }
300910923SEvan.Yan@Sun.COM return (NULL);
301010923SEvan.Yan@Sun.COM }
301110923SEvan.Yan@Sun.COM #endif /* _DONT_USE_1275_GENERIC_NAMES */
301210923SEvan.Yan@Sun.COM
301310923SEvan.Yan@Sun.COM static dev_info_t *
pcicfg_devi_find(dev_info_t * dip,uint_t device,uint_t function)301410923SEvan.Yan@Sun.COM pcicfg_devi_find(dev_info_t *dip, uint_t device, uint_t function)
301510923SEvan.Yan@Sun.COM {
301610923SEvan.Yan@Sun.COM struct pcicfg_find_ctrl ctrl;
301710923SEvan.Yan@Sun.COM int count;
301810923SEvan.Yan@Sun.COM
301910923SEvan.Yan@Sun.COM ctrl.device = device;
302010923SEvan.Yan@Sun.COM ctrl.function = function;
302110923SEvan.Yan@Sun.COM ctrl.dip = NULL;
302210923SEvan.Yan@Sun.COM
302310923SEvan.Yan@Sun.COM ndi_devi_enter(dip, &count);
302410923SEvan.Yan@Sun.COM ddi_walk_devs(ddi_get_child(dip), pcicfg_match_dev, (void *)&ctrl);
302510923SEvan.Yan@Sun.COM ndi_devi_exit(dip, count);
302610923SEvan.Yan@Sun.COM
302710923SEvan.Yan@Sun.COM return (ctrl.dip);
302810923SEvan.Yan@Sun.COM }
302910923SEvan.Yan@Sun.COM
303010923SEvan.Yan@Sun.COM static int
pcicfg_match_dev(dev_info_t * dip,void * hdl)303110923SEvan.Yan@Sun.COM pcicfg_match_dev(dev_info_t *dip, void *hdl)
303210923SEvan.Yan@Sun.COM {
303310923SEvan.Yan@Sun.COM struct pcicfg_find_ctrl *ctrl = (struct pcicfg_find_ctrl *)hdl;
303410923SEvan.Yan@Sun.COM pci_regspec_t *pci_rp;
303510923SEvan.Yan@Sun.COM int length;
303610923SEvan.Yan@Sun.COM int pci_dev;
303710923SEvan.Yan@Sun.COM int pci_func;
303810923SEvan.Yan@Sun.COM
303910923SEvan.Yan@Sun.COM if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
304010923SEvan.Yan@Sun.COM DDI_PROP_DONTPASS, "reg", (int **)&pci_rp,
304110923SEvan.Yan@Sun.COM (uint_t *)&length) != DDI_PROP_SUCCESS) {
304210923SEvan.Yan@Sun.COM ctrl->dip = NULL;
304310923SEvan.Yan@Sun.COM return (DDI_WALK_TERMINATE);
304410923SEvan.Yan@Sun.COM }
304510923SEvan.Yan@Sun.COM
304610923SEvan.Yan@Sun.COM /* get the PCI device address info */
304710923SEvan.Yan@Sun.COM pci_dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
304810923SEvan.Yan@Sun.COM pci_func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
304910923SEvan.Yan@Sun.COM
305010923SEvan.Yan@Sun.COM /*
305110923SEvan.Yan@Sun.COM * free the memory allocated by ddi_prop_lookup_int_array
305210923SEvan.Yan@Sun.COM */
305310923SEvan.Yan@Sun.COM ddi_prop_free(pci_rp);
305410923SEvan.Yan@Sun.COM
305510923SEvan.Yan@Sun.COM
305610923SEvan.Yan@Sun.COM if ((pci_dev == ctrl->device) && (pci_func == ctrl->function)) {
305710923SEvan.Yan@Sun.COM /* found the match for the specified device address */
305810923SEvan.Yan@Sun.COM ctrl->dip = dip;
305910923SEvan.Yan@Sun.COM return (DDI_WALK_TERMINATE);
306010923SEvan.Yan@Sun.COM }
306110923SEvan.Yan@Sun.COM
306210923SEvan.Yan@Sun.COM /*
306310923SEvan.Yan@Sun.COM * continue the walk to the next sibling to look for a match.
306410923SEvan.Yan@Sun.COM */
306510923SEvan.Yan@Sun.COM return (DDI_WALK_PRUNECHILD);
306610923SEvan.Yan@Sun.COM }
306710923SEvan.Yan@Sun.COM
306810923SEvan.Yan@Sun.COM static int
pcicfg_update_assigned_prop(dev_info_t * dip,pci_regspec_t * newone)306910923SEvan.Yan@Sun.COM pcicfg_update_assigned_prop(dev_info_t *dip, pci_regspec_t *newone)
307010923SEvan.Yan@Sun.COM {
307110923SEvan.Yan@Sun.COM int alen;
307210923SEvan.Yan@Sun.COM pci_regspec_t *assigned;
307310923SEvan.Yan@Sun.COM caddr_t newreg;
307410923SEvan.Yan@Sun.COM uint_t status;
307510923SEvan.Yan@Sun.COM
307610923SEvan.Yan@Sun.COM DEBUG0("pcicfg_update_assigned_prop()\n");
307710923SEvan.Yan@Sun.COM status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
307810923SEvan.Yan@Sun.COM "assigned-addresses", (caddr_t)&assigned, &alen);
307910923SEvan.Yan@Sun.COM switch (status) {
308010923SEvan.Yan@Sun.COM case DDI_PROP_SUCCESS:
308110923SEvan.Yan@Sun.COM break;
308210923SEvan.Yan@Sun.COM case DDI_PROP_NO_MEMORY:
308310923SEvan.Yan@Sun.COM DEBUG0("no memory for assigned-addresses property\n");
308410923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
308510923SEvan.Yan@Sun.COM default:
308610923SEvan.Yan@Sun.COM (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
308710923SEvan.Yan@Sun.COM "assigned-addresses", (int *)newone,
308810923SEvan.Yan@Sun.COM sizeof (*newone)/sizeof (int));
308910923SEvan.Yan@Sun.COM
309010923SEvan.Yan@Sun.COM (void) pcicfg_dump_assigned(dip);
309110923SEvan.Yan@Sun.COM
309210923SEvan.Yan@Sun.COM return (PCICFG_SUCCESS);
309310923SEvan.Yan@Sun.COM }
309410923SEvan.Yan@Sun.COM
309510923SEvan.Yan@Sun.COM /*
309610923SEvan.Yan@Sun.COM * Allocate memory for the existing
309710923SEvan.Yan@Sun.COM * assigned-addresses(s) plus one and then
309810923SEvan.Yan@Sun.COM * build it.
309910923SEvan.Yan@Sun.COM */
310010923SEvan.Yan@Sun.COM
310110923SEvan.Yan@Sun.COM newreg = kmem_zalloc(alen+sizeof (*newone), KM_SLEEP);
310210923SEvan.Yan@Sun.COM
310310923SEvan.Yan@Sun.COM bcopy(assigned, newreg, alen);
310410923SEvan.Yan@Sun.COM bcopy(newone, newreg + alen, sizeof (*newone));
310510923SEvan.Yan@Sun.COM
310610923SEvan.Yan@Sun.COM /*
310710923SEvan.Yan@Sun.COM * Write out the new "assigned-addresses" spec
310810923SEvan.Yan@Sun.COM */
310910923SEvan.Yan@Sun.COM (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
311010923SEvan.Yan@Sun.COM "assigned-addresses", (int *)newreg,
311110923SEvan.Yan@Sun.COM (alen + sizeof (*newone))/sizeof (int));
311210923SEvan.Yan@Sun.COM
311310923SEvan.Yan@Sun.COM kmem_free((caddr_t)newreg, alen+sizeof (*newone));
311410923SEvan.Yan@Sun.COM
311510923SEvan.Yan@Sun.COM /*
311610923SEvan.Yan@Sun.COM * Don't forget to free up memory from ddi_getlongprop
311710923SEvan.Yan@Sun.COM */
311810923SEvan.Yan@Sun.COM kmem_free((caddr_t)assigned, alen);
311910923SEvan.Yan@Sun.COM
312010923SEvan.Yan@Sun.COM (void) pcicfg_dump_assigned(dip);
312110923SEvan.Yan@Sun.COM
312210923SEvan.Yan@Sun.COM return (PCICFG_SUCCESS);
312310923SEvan.Yan@Sun.COM }
312410923SEvan.Yan@Sun.COM static int
pcicfg_update_ranges_prop(dev_info_t * dip,pcicfg_range_t * addition)312510923SEvan.Yan@Sun.COM pcicfg_update_ranges_prop(dev_info_t *dip, pcicfg_range_t *addition)
312610923SEvan.Yan@Sun.COM {
312710923SEvan.Yan@Sun.COM int rlen;
312810923SEvan.Yan@Sun.COM pcicfg_range_t *ranges;
312910923SEvan.Yan@Sun.COM caddr_t newreg;
313010923SEvan.Yan@Sun.COM uint_t status;
313110923SEvan.Yan@Sun.COM
313210923SEvan.Yan@Sun.COM status = ddi_getlongprop(DDI_DEV_T_ANY,
313310923SEvan.Yan@Sun.COM dip, DDI_PROP_DONTPASS, "ranges", (caddr_t)&ranges, &rlen);
313410923SEvan.Yan@Sun.COM
313510923SEvan.Yan@Sun.COM
313610923SEvan.Yan@Sun.COM switch (status) {
313710923SEvan.Yan@Sun.COM case DDI_PROP_SUCCESS:
313810923SEvan.Yan@Sun.COM break;
313910923SEvan.Yan@Sun.COM case DDI_PROP_NO_MEMORY:
314010923SEvan.Yan@Sun.COM DEBUG0("ranges present, but unable to get memory\n");
314110923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
314210923SEvan.Yan@Sun.COM default:
314310923SEvan.Yan@Sun.COM DEBUG0("no ranges property - creating one\n");
314410923SEvan.Yan@Sun.COM if (ndi_prop_update_int_array(DDI_DEV_T_NONE,
314510923SEvan.Yan@Sun.COM dip, "ranges", (int *)addition,
314610923SEvan.Yan@Sun.COM sizeof (pcicfg_range_t)/sizeof (int))
314710923SEvan.Yan@Sun.COM != DDI_SUCCESS) {
314810923SEvan.Yan@Sun.COM DEBUG0("Did'nt create ranges property\n");
314910923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
315010923SEvan.Yan@Sun.COM }
315110923SEvan.Yan@Sun.COM return (PCICFG_SUCCESS);
315210923SEvan.Yan@Sun.COM }
315310923SEvan.Yan@Sun.COM
315410923SEvan.Yan@Sun.COM /*
315510923SEvan.Yan@Sun.COM * Allocate memory for the existing reg(s) plus one and then
315610923SEvan.Yan@Sun.COM * build it.
315710923SEvan.Yan@Sun.COM */
315810923SEvan.Yan@Sun.COM newreg = kmem_zalloc(rlen + sizeof (pcicfg_range_t), KM_SLEEP);
315910923SEvan.Yan@Sun.COM
316010923SEvan.Yan@Sun.COM bcopy(ranges, newreg, rlen);
316110923SEvan.Yan@Sun.COM bcopy(addition, newreg + rlen, sizeof (pcicfg_range_t));
316210923SEvan.Yan@Sun.COM
316310923SEvan.Yan@Sun.COM /*
316410923SEvan.Yan@Sun.COM * Write out the new "ranges" property
316510923SEvan.Yan@Sun.COM */
316610923SEvan.Yan@Sun.COM (void) ndi_prop_update_int_array(DDI_DEV_T_NONE,
316710923SEvan.Yan@Sun.COM dip, "ranges", (int *)newreg,
316810923SEvan.Yan@Sun.COM (rlen + sizeof (pcicfg_range_t))/sizeof (int));
316910923SEvan.Yan@Sun.COM
317010923SEvan.Yan@Sun.COM kmem_free((caddr_t)newreg, rlen+sizeof (pcicfg_range_t));
317110923SEvan.Yan@Sun.COM
317210923SEvan.Yan@Sun.COM kmem_free((caddr_t)ranges, rlen);
317310923SEvan.Yan@Sun.COM
317410923SEvan.Yan@Sun.COM return (PCICFG_SUCCESS);
317510923SEvan.Yan@Sun.COM }
317610923SEvan.Yan@Sun.COM
317710923SEvan.Yan@Sun.COM static int
pcicfg_update_reg_prop(dev_info_t * dip,uint32_t regvalue,uint_t reg_offset)317810923SEvan.Yan@Sun.COM pcicfg_update_reg_prop(dev_info_t *dip, uint32_t regvalue, uint_t reg_offset)
317910923SEvan.Yan@Sun.COM {
318010923SEvan.Yan@Sun.COM int rlen;
318110923SEvan.Yan@Sun.COM pci_regspec_t *reg;
318210923SEvan.Yan@Sun.COM caddr_t newreg;
318310923SEvan.Yan@Sun.COM uint32_t hiword;
318410923SEvan.Yan@Sun.COM pci_regspec_t addition;
318510923SEvan.Yan@Sun.COM uint32_t size;
318610923SEvan.Yan@Sun.COM uint_t status;
318710923SEvan.Yan@Sun.COM
318810923SEvan.Yan@Sun.COM status = ddi_getlongprop(DDI_DEV_T_ANY,
318910923SEvan.Yan@Sun.COM dip, DDI_PROP_DONTPASS, "reg", (caddr_t)®, &rlen);
319010923SEvan.Yan@Sun.COM
319110923SEvan.Yan@Sun.COM switch (status) {
319210923SEvan.Yan@Sun.COM case DDI_PROP_SUCCESS:
319310923SEvan.Yan@Sun.COM break;
319410923SEvan.Yan@Sun.COM case DDI_PROP_NO_MEMORY:
319510923SEvan.Yan@Sun.COM DEBUG0("reg present, but unable to get memory\n");
319610923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
319710923SEvan.Yan@Sun.COM default:
319810923SEvan.Yan@Sun.COM DEBUG0("no reg property\n");
319910923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
320010923SEvan.Yan@Sun.COM }
320110923SEvan.Yan@Sun.COM
320210923SEvan.Yan@Sun.COM /*
320310923SEvan.Yan@Sun.COM * Allocate memory for the existing reg(s) plus one and then
320410923SEvan.Yan@Sun.COM * build it.
320510923SEvan.Yan@Sun.COM */
320610923SEvan.Yan@Sun.COM newreg = kmem_zalloc(rlen+sizeof (pci_regspec_t), KM_SLEEP);
320710923SEvan.Yan@Sun.COM
320810923SEvan.Yan@Sun.COM /*
320910923SEvan.Yan@Sun.COM * Build the regspec, then add it to the existing one(s)
321010923SEvan.Yan@Sun.COM */
321110923SEvan.Yan@Sun.COM
321210923SEvan.Yan@Sun.COM hiword = PCICFG_MAKE_REG_HIGH(PCI_REG_BUS_G(reg->pci_phys_hi),
321310923SEvan.Yan@Sun.COM PCI_REG_DEV_G(reg->pci_phys_hi),
321410923SEvan.Yan@Sun.COM PCI_REG_FUNC_G(reg->pci_phys_hi), reg_offset);
321510923SEvan.Yan@Sun.COM
321610923SEvan.Yan@Sun.COM if (reg_offset == PCI_CONF_ROM) {
321710923SEvan.Yan@Sun.COM size = (~(PCI_BASE_ROM_ADDR_M & regvalue))+1;
321810923SEvan.Yan@Sun.COM hiword |= PCI_ADDR_MEM32;
321910923SEvan.Yan@Sun.COM } else {
322010923SEvan.Yan@Sun.COM size = (~(PCI_BASE_M_ADDR_M & regvalue))+1;
322110923SEvan.Yan@Sun.COM
322210923SEvan.Yan@Sun.COM if ((PCI_BASE_SPACE_M & regvalue) == PCI_BASE_SPACE_MEM) {
322310923SEvan.Yan@Sun.COM if ((PCI_BASE_TYPE_M & regvalue) == PCI_BASE_TYPE_MEM) {
322410923SEvan.Yan@Sun.COM hiword |= PCI_ADDR_MEM32;
322510923SEvan.Yan@Sun.COM } else if ((PCI_BASE_TYPE_M & regvalue)
322610923SEvan.Yan@Sun.COM == PCI_BASE_TYPE_ALL) {
322710923SEvan.Yan@Sun.COM hiword |= PCI_ADDR_MEM64;
322810923SEvan.Yan@Sun.COM }
322910923SEvan.Yan@Sun.COM } else {
323010923SEvan.Yan@Sun.COM hiword |= PCI_ADDR_IO;
323110923SEvan.Yan@Sun.COM }
323210923SEvan.Yan@Sun.COM }
323310923SEvan.Yan@Sun.COM
323410923SEvan.Yan@Sun.COM addition.pci_phys_hi = hiword;
323510923SEvan.Yan@Sun.COM addition.pci_phys_mid = 0;
323610923SEvan.Yan@Sun.COM addition.pci_phys_low = 0;
323710923SEvan.Yan@Sun.COM addition.pci_size_hi = 0;
323810923SEvan.Yan@Sun.COM addition.pci_size_low = size;
323910923SEvan.Yan@Sun.COM
324010923SEvan.Yan@Sun.COM bcopy(reg, newreg, rlen);
324110923SEvan.Yan@Sun.COM bcopy(&addition, newreg + rlen, sizeof (pci_regspec_t));
324210923SEvan.Yan@Sun.COM
324310923SEvan.Yan@Sun.COM /*
324410923SEvan.Yan@Sun.COM * Write out the new "reg" property
324510923SEvan.Yan@Sun.COM */
324610923SEvan.Yan@Sun.COM (void) ndi_prop_update_int_array(DDI_DEV_T_NONE,
324710923SEvan.Yan@Sun.COM dip, "reg", (int *)newreg,
324810923SEvan.Yan@Sun.COM (rlen + sizeof (pci_regspec_t))/sizeof (int));
324910923SEvan.Yan@Sun.COM
325010923SEvan.Yan@Sun.COM kmem_free((caddr_t)newreg, rlen+sizeof (pci_regspec_t));
325110923SEvan.Yan@Sun.COM kmem_free((caddr_t)reg, rlen);
325210923SEvan.Yan@Sun.COM
325310923SEvan.Yan@Sun.COM return (PCICFG_SUCCESS);
325410923SEvan.Yan@Sun.COM }
325510923SEvan.Yan@Sun.COM static int
pcicfg_update_available_prop(dev_info_t * dip,pci_regspec_t * newone)325610923SEvan.Yan@Sun.COM pcicfg_update_available_prop(dev_info_t *dip, pci_regspec_t *newone)
325710923SEvan.Yan@Sun.COM {
325810923SEvan.Yan@Sun.COM int alen;
325910923SEvan.Yan@Sun.COM pci_regspec_t *avail_p;
326010923SEvan.Yan@Sun.COM caddr_t new_avail;
326110923SEvan.Yan@Sun.COM uint_t status;
326210923SEvan.Yan@Sun.COM
326310923SEvan.Yan@Sun.COM DEBUG2("pcicfg_update_available_prop() - Address %lx Size %x\n",
326410923SEvan.Yan@Sun.COM newone->pci_phys_low, newone->pci_size_low);
326510923SEvan.Yan@Sun.COM status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
326610923SEvan.Yan@Sun.COM "available", (caddr_t)&avail_p, &alen);
326710923SEvan.Yan@Sun.COM switch (status) {
326810923SEvan.Yan@Sun.COM case DDI_PROP_SUCCESS:
326910923SEvan.Yan@Sun.COM break;
327010923SEvan.Yan@Sun.COM case DDI_PROP_NO_MEMORY:
327110923SEvan.Yan@Sun.COM DEBUG0("no memory for available property\n");
327210923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
327310923SEvan.Yan@Sun.COM default:
327410923SEvan.Yan@Sun.COM (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
327510923SEvan.Yan@Sun.COM "available", (int *)newone,
327610923SEvan.Yan@Sun.COM sizeof (*newone)/sizeof (int));
327710923SEvan.Yan@Sun.COM
327810923SEvan.Yan@Sun.COM return (PCICFG_SUCCESS);
327910923SEvan.Yan@Sun.COM }
328010923SEvan.Yan@Sun.COM
328110923SEvan.Yan@Sun.COM /*
328210923SEvan.Yan@Sun.COM * Allocate memory for the existing available plus one and then
328310923SEvan.Yan@Sun.COM * build it.
328410923SEvan.Yan@Sun.COM */
328510923SEvan.Yan@Sun.COM new_avail = kmem_zalloc(alen+sizeof (*newone), KM_SLEEP);
328610923SEvan.Yan@Sun.COM
328710923SEvan.Yan@Sun.COM bcopy(avail_p, new_avail, alen);
328810923SEvan.Yan@Sun.COM bcopy(newone, new_avail + alen, sizeof (*newone));
328910923SEvan.Yan@Sun.COM
329010923SEvan.Yan@Sun.COM /* Write out the new "available" spec */
329110923SEvan.Yan@Sun.COM (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
329210923SEvan.Yan@Sun.COM "available", (int *)new_avail,
329310923SEvan.Yan@Sun.COM (alen + sizeof (*newone))/sizeof (int));
329410923SEvan.Yan@Sun.COM
329510923SEvan.Yan@Sun.COM kmem_free((caddr_t)new_avail, alen+sizeof (*newone));
329610923SEvan.Yan@Sun.COM
329710923SEvan.Yan@Sun.COM /* Don't forget to free up memory from ddi_getlongprop */
329810923SEvan.Yan@Sun.COM kmem_free((caddr_t)avail_p, alen);
329910923SEvan.Yan@Sun.COM
330010923SEvan.Yan@Sun.COM return (PCICFG_SUCCESS);
330110923SEvan.Yan@Sun.COM }
330210923SEvan.Yan@Sun.COM
330310923SEvan.Yan@Sun.COM 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)330410923SEvan.Yan@Sun.COM pcicfg_update_assigned_prop_value(dev_info_t *dip, uint32_t size,
330510923SEvan.Yan@Sun.COM uint32_t base, uint32_t base_hi, uint_t reg_offset)
330610923SEvan.Yan@Sun.COM {
330710923SEvan.Yan@Sun.COM int rlen;
330810923SEvan.Yan@Sun.COM pci_regspec_t *reg;
330910923SEvan.Yan@Sun.COM uint32_t hiword;
331010923SEvan.Yan@Sun.COM pci_regspec_t addition;
331110923SEvan.Yan@Sun.COM uint_t status;
331210923SEvan.Yan@Sun.COM
331310923SEvan.Yan@Sun.COM status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
331410923SEvan.Yan@Sun.COM "reg", (caddr_t)®, &rlen);
331510923SEvan.Yan@Sun.COM
331610923SEvan.Yan@Sun.COM switch (status) {
331710923SEvan.Yan@Sun.COM case DDI_PROP_SUCCESS:
331810923SEvan.Yan@Sun.COM break;
331910923SEvan.Yan@Sun.COM case DDI_PROP_NO_MEMORY:
332010923SEvan.Yan@Sun.COM DEBUG0("reg present, but unable to get memory\n");
332110923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
332210923SEvan.Yan@Sun.COM default:
332310923SEvan.Yan@Sun.COM /*
332410923SEvan.Yan@Sun.COM * Since the config space "reg" entry should have been
332510923SEvan.Yan@Sun.COM * created, we expect a "reg" property already
332610923SEvan.Yan@Sun.COM * present here.
332710923SEvan.Yan@Sun.COM */
332810923SEvan.Yan@Sun.COM DEBUG0("no reg property\n");
332910923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
333010923SEvan.Yan@Sun.COM }
333110923SEvan.Yan@Sun.COM
333210923SEvan.Yan@Sun.COM /*
333310923SEvan.Yan@Sun.COM * Build the regspec, then add it to the existing one(s)
333410923SEvan.Yan@Sun.COM */
333510923SEvan.Yan@Sun.COM
333610923SEvan.Yan@Sun.COM hiword = PCICFG_MAKE_REG_HIGH(PCI_REG_BUS_G(reg->pci_phys_hi),
333710923SEvan.Yan@Sun.COM PCI_REG_DEV_G(reg->pci_phys_hi),
333810923SEvan.Yan@Sun.COM PCI_REG_FUNC_G(reg->pci_phys_hi), reg_offset);
333910923SEvan.Yan@Sun.COM
334010923SEvan.Yan@Sun.COM hiword |= PCI_REG_REL_M;
334110923SEvan.Yan@Sun.COM
334210923SEvan.Yan@Sun.COM if (reg_offset == PCI_CONF_ROM) {
334310923SEvan.Yan@Sun.COM hiword |= PCI_ADDR_MEM32;
334410923SEvan.Yan@Sun.COM
334510923SEvan.Yan@Sun.COM base = PCI_BASE_ROM_ADDR_M & base;
334610923SEvan.Yan@Sun.COM } else {
334710923SEvan.Yan@Sun.COM if ((PCI_BASE_SPACE_M & base) == PCI_BASE_SPACE_MEM) {
334810923SEvan.Yan@Sun.COM if ((PCI_BASE_TYPE_M & base) == PCI_BASE_TYPE_MEM) {
334910923SEvan.Yan@Sun.COM hiword |= PCI_ADDR_MEM32;
335010923SEvan.Yan@Sun.COM } else if ((PCI_BASE_TYPE_M & base)
335110923SEvan.Yan@Sun.COM == PCI_BASE_TYPE_ALL) {
335210923SEvan.Yan@Sun.COM hiword |= PCI_ADDR_MEM64;
335310923SEvan.Yan@Sun.COM }
335410923SEvan.Yan@Sun.COM
335510923SEvan.Yan@Sun.COM if (base & PCI_BASE_PREF_M)
335610923SEvan.Yan@Sun.COM hiword |= PCI_REG_PF_M;
335710923SEvan.Yan@Sun.COM
335810923SEvan.Yan@Sun.COM base = PCI_BASE_M_ADDR_M & base;
335910923SEvan.Yan@Sun.COM } else {
336010923SEvan.Yan@Sun.COM hiword |= PCI_ADDR_IO;
336110923SEvan.Yan@Sun.COM
336210923SEvan.Yan@Sun.COM base = PCI_BASE_IO_ADDR_M & base;
336310923SEvan.Yan@Sun.COM base_hi = 0;
336410923SEvan.Yan@Sun.COM }
336510923SEvan.Yan@Sun.COM }
336610923SEvan.Yan@Sun.COM
336710923SEvan.Yan@Sun.COM addition.pci_phys_hi = hiword;
336810923SEvan.Yan@Sun.COM addition.pci_phys_mid = base_hi;
336910923SEvan.Yan@Sun.COM addition.pci_phys_low = base;
337010923SEvan.Yan@Sun.COM addition.pci_size_hi = 0;
337110923SEvan.Yan@Sun.COM addition.pci_size_low = size;
337210923SEvan.Yan@Sun.COM
337310923SEvan.Yan@Sun.COM DEBUG3("updating BAR@off %x with %x,%x\n", reg_offset, hiword, size);
337410923SEvan.Yan@Sun.COM
337510923SEvan.Yan@Sun.COM kmem_free((caddr_t)reg, rlen);
337610923SEvan.Yan@Sun.COM
337710923SEvan.Yan@Sun.COM return (pcicfg_update_assigned_prop(dip, &addition));
337810923SEvan.Yan@Sun.COM }
337910923SEvan.Yan@Sun.COM
338010923SEvan.Yan@Sun.COM static void
pcicfg_device_on(ddi_acc_handle_t config_handle)338110923SEvan.Yan@Sun.COM pcicfg_device_on(ddi_acc_handle_t config_handle)
338210923SEvan.Yan@Sun.COM {
338310923SEvan.Yan@Sun.COM /*
338410923SEvan.Yan@Sun.COM * Enable memory, IO, and bus mastership
338510923SEvan.Yan@Sun.COM * XXX should we enable parity, SERR#,
338610923SEvan.Yan@Sun.COM * fast back-to-back, and addr. stepping?
338710923SEvan.Yan@Sun.COM */
338810923SEvan.Yan@Sun.COM pci_config_put16(config_handle, PCI_CONF_COMM,
338910923SEvan.Yan@Sun.COM pci_config_get16(config_handle, PCI_CONF_COMM) | 0x7);
339010923SEvan.Yan@Sun.COM }
339110923SEvan.Yan@Sun.COM
339210923SEvan.Yan@Sun.COM static void
pcicfg_device_off(ddi_acc_handle_t config_handle)339310923SEvan.Yan@Sun.COM pcicfg_device_off(ddi_acc_handle_t config_handle)
339410923SEvan.Yan@Sun.COM {
339510923SEvan.Yan@Sun.COM /*
339610923SEvan.Yan@Sun.COM * Disable I/O and memory traffic through the bridge
339710923SEvan.Yan@Sun.COM */
339810923SEvan.Yan@Sun.COM pci_config_put16(config_handle, PCI_CONF_COMM, 0x0);
339910923SEvan.Yan@Sun.COM }
340010923SEvan.Yan@Sun.COM
340110923SEvan.Yan@Sun.COM /*
340210923SEvan.Yan@Sun.COM * Setup the basic 1275 properties based on information found in the config
340310923SEvan.Yan@Sun.COM * header of the PCI device
340410923SEvan.Yan@Sun.COM */
340510923SEvan.Yan@Sun.COM static int
pcicfg_set_standard_props(dev_info_t * dip,ddi_acc_handle_t config_handle,uint8_t pcie_dev)340610923SEvan.Yan@Sun.COM pcicfg_set_standard_props(dev_info_t *dip, ddi_acc_handle_t config_handle,
340710923SEvan.Yan@Sun.COM uint8_t pcie_dev)
340810923SEvan.Yan@Sun.COM {
340910923SEvan.Yan@Sun.COM int ret;
341010923SEvan.Yan@Sun.COM uint16_t val, cap_ptr;
341110923SEvan.Yan@Sun.COM uint32_t wordval;
341210923SEvan.Yan@Sun.COM uint8_t byteval;
341310923SEvan.Yan@Sun.COM
341410923SEvan.Yan@Sun.COM /* These two exists only for non-bridges */
341510923SEvan.Yan@Sun.COM if (((pci_config_get8(config_handle, PCI_CONF_HEADER)
341610923SEvan.Yan@Sun.COM & PCI_HEADER_TYPE_M) == PCI_HEADER_ZERO) && !pcie_dev) {
341710923SEvan.Yan@Sun.COM byteval = pci_config_get8(config_handle, PCI_CONF_MIN_G);
341810923SEvan.Yan@Sun.COM if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
341910923SEvan.Yan@Sun.COM "min-grant", byteval)) != DDI_SUCCESS) {
342010923SEvan.Yan@Sun.COM return (ret);
342110923SEvan.Yan@Sun.COM }
342210923SEvan.Yan@Sun.COM
342310923SEvan.Yan@Sun.COM byteval = pci_config_get8(config_handle, PCI_CONF_MAX_L);
342410923SEvan.Yan@Sun.COM if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
342510923SEvan.Yan@Sun.COM "max-latency", byteval)) != DDI_SUCCESS) {
342610923SEvan.Yan@Sun.COM return (ret);
342710923SEvan.Yan@Sun.COM }
342810923SEvan.Yan@Sun.COM }
342910923SEvan.Yan@Sun.COM
343010923SEvan.Yan@Sun.COM /*
343110923SEvan.Yan@Sun.COM * These should always exist and have the value of the
343210923SEvan.Yan@Sun.COM * corresponding register value
343310923SEvan.Yan@Sun.COM */
343410923SEvan.Yan@Sun.COM val = pci_config_get16(config_handle, PCI_CONF_VENID);
343510923SEvan.Yan@Sun.COM
343610923SEvan.Yan@Sun.COM if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
343710923SEvan.Yan@Sun.COM "vendor-id", val)) != DDI_SUCCESS) {
343810923SEvan.Yan@Sun.COM return (ret);
343910923SEvan.Yan@Sun.COM }
344010923SEvan.Yan@Sun.COM val = pci_config_get16(config_handle, PCI_CONF_DEVID);
344110923SEvan.Yan@Sun.COM if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
344210923SEvan.Yan@Sun.COM "device-id", val)) != DDI_SUCCESS) {
344310923SEvan.Yan@Sun.COM return (ret);
344410923SEvan.Yan@Sun.COM }
344510923SEvan.Yan@Sun.COM byteval = pci_config_get8(config_handle, PCI_CONF_REVID);
344610923SEvan.Yan@Sun.COM if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
344710923SEvan.Yan@Sun.COM "revision-id", byteval)) != DDI_SUCCESS) {
344810923SEvan.Yan@Sun.COM return (ret);
344910923SEvan.Yan@Sun.COM }
345010923SEvan.Yan@Sun.COM
345110923SEvan.Yan@Sun.COM wordval = (pci_config_get16(config_handle, PCI_CONF_SUBCLASS)<< 8) |
345210923SEvan.Yan@Sun.COM (pci_config_get8(config_handle, PCI_CONF_PROGCLASS));
345310923SEvan.Yan@Sun.COM
345410923SEvan.Yan@Sun.COM if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
345510923SEvan.Yan@Sun.COM "class-code", wordval)) != DDI_SUCCESS) {
345610923SEvan.Yan@Sun.COM return (ret);
345710923SEvan.Yan@Sun.COM }
345810923SEvan.Yan@Sun.COM /* devsel-speed starts at the 9th bit */
345910923SEvan.Yan@Sun.COM val = (pci_config_get16(config_handle,
346010923SEvan.Yan@Sun.COM PCI_CONF_STAT) & PCI_STAT_DEVSELT) >> 9;
346110923SEvan.Yan@Sun.COM if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
346210923SEvan.Yan@Sun.COM "devsel-speed", val)) != DDI_SUCCESS) {
346310923SEvan.Yan@Sun.COM return (ret);
346410923SEvan.Yan@Sun.COM }
346510923SEvan.Yan@Sun.COM
346610923SEvan.Yan@Sun.COM /*
346710923SEvan.Yan@Sun.COM * The next three are bits set in the status register. The property is
346810923SEvan.Yan@Sun.COM * present (but with no value other than its own existence) if the bit
346910923SEvan.Yan@Sun.COM * is set, non-existent otherwise
347010923SEvan.Yan@Sun.COM */
347110923SEvan.Yan@Sun.COM if ((!pcie_dev) &&
347210923SEvan.Yan@Sun.COM (pci_config_get16(config_handle, PCI_CONF_STAT) &
347310923SEvan.Yan@Sun.COM PCI_STAT_FBBC)) {
347410923SEvan.Yan@Sun.COM if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
347510923SEvan.Yan@Sun.COM "fast-back-to-back", 0)) != DDI_SUCCESS) {
347610923SEvan.Yan@Sun.COM return (ret);
347710923SEvan.Yan@Sun.COM }
347810923SEvan.Yan@Sun.COM }
347910923SEvan.Yan@Sun.COM if ((!pcie_dev) &&
348010923SEvan.Yan@Sun.COM (pci_config_get16(config_handle, PCI_CONF_STAT) &
348110923SEvan.Yan@Sun.COM PCI_STAT_66MHZ)) {
348210923SEvan.Yan@Sun.COM if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
348310923SEvan.Yan@Sun.COM "66mhz-capable", 0)) != DDI_SUCCESS) {
348410923SEvan.Yan@Sun.COM return (ret);
348510923SEvan.Yan@Sun.COM }
348610923SEvan.Yan@Sun.COM }
348710923SEvan.Yan@Sun.COM if (pci_config_get16(config_handle, PCI_CONF_STAT) & PCI_STAT_UDF) {
348810923SEvan.Yan@Sun.COM if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
348910923SEvan.Yan@Sun.COM "udf-supported", 0)) != DDI_SUCCESS) {
349010923SEvan.Yan@Sun.COM return (ret);
349110923SEvan.Yan@Sun.COM }
349210923SEvan.Yan@Sun.COM }
349310923SEvan.Yan@Sun.COM
349410923SEvan.Yan@Sun.COM /*
349510923SEvan.Yan@Sun.COM * These next three are optional and are not present
349610923SEvan.Yan@Sun.COM * if the corresponding register is zero. If the value
349710923SEvan.Yan@Sun.COM * is non-zero then the property exists with the value
349810923SEvan.Yan@Sun.COM * of the register.
349910923SEvan.Yan@Sun.COM */
350010923SEvan.Yan@Sun.COM if ((val = pci_config_get16(config_handle,
350110923SEvan.Yan@Sun.COM PCI_CONF_SUBVENID)) != 0) {
350210923SEvan.Yan@Sun.COM if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
350310923SEvan.Yan@Sun.COM "subsystem-vendor-id", val)) != DDI_SUCCESS) {
350410923SEvan.Yan@Sun.COM return (ret);
350510923SEvan.Yan@Sun.COM }
350610923SEvan.Yan@Sun.COM }
350710923SEvan.Yan@Sun.COM if ((val = pci_config_get16(config_handle,
350810923SEvan.Yan@Sun.COM PCI_CONF_SUBSYSID)) != 0) {
350910923SEvan.Yan@Sun.COM if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
351010923SEvan.Yan@Sun.COM "subsystem-id", val)) != DDI_SUCCESS) {
351110923SEvan.Yan@Sun.COM return (ret);
351210923SEvan.Yan@Sun.COM }
351310923SEvan.Yan@Sun.COM }
351410923SEvan.Yan@Sun.COM if ((val = pci_config_get16(config_handle,
351510923SEvan.Yan@Sun.COM PCI_CONF_CACHE_LINESZ)) != 0) {
351610923SEvan.Yan@Sun.COM if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
351710923SEvan.Yan@Sun.COM "cache-line-size", val)) != DDI_SUCCESS) {
351810923SEvan.Yan@Sun.COM return (ret);
351910923SEvan.Yan@Sun.COM }
352010923SEvan.Yan@Sun.COM }
352110923SEvan.Yan@Sun.COM
352210923SEvan.Yan@Sun.COM /*
352310923SEvan.Yan@Sun.COM * If the Interrupt Pin register is non-zero then the
352410923SEvan.Yan@Sun.COM * interrupts property exists
352510923SEvan.Yan@Sun.COM */
352610923SEvan.Yan@Sun.COM if ((byteval = pci_config_get8(config_handle, PCI_CONF_IPIN)) != 0) {
352710923SEvan.Yan@Sun.COM /*
352810923SEvan.Yan@Sun.COM * If interrupt pin is non-zero,
352910923SEvan.Yan@Sun.COM * record the interrupt line used
353010923SEvan.Yan@Sun.COM */
353110923SEvan.Yan@Sun.COM if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
353210923SEvan.Yan@Sun.COM "interrupts", byteval)) != DDI_SUCCESS) {
353310923SEvan.Yan@Sun.COM return (ret);
353410923SEvan.Yan@Sun.COM }
353510923SEvan.Yan@Sun.COM }
353610923SEvan.Yan@Sun.COM
353710923SEvan.Yan@Sun.COM ret = PCI_CAP_LOCATE(config_handle, PCI_CAP_ID_PCI_E, &cap_ptr);
353810923SEvan.Yan@Sun.COM
353910923SEvan.Yan@Sun.COM if (pcie_dev && (ret == DDI_SUCCESS)) {
354010923SEvan.Yan@Sun.COM val = PCI_CAP_GET16(config_handle, NULL, cap_ptr,
354110923SEvan.Yan@Sun.COM PCIE_PCIECAP) & PCIE_PCIECAP_SLOT_IMPL;
354210923SEvan.Yan@Sun.COM /* if slot implemented, get physical slot number */
354310923SEvan.Yan@Sun.COM if (val) {
354410923SEvan.Yan@Sun.COM wordval = (PCI_CAP_GET32(config_handle, NULL,
354510923SEvan.Yan@Sun.COM cap_ptr, PCIE_SLOTCAP) >>
354610923SEvan.Yan@Sun.COM PCIE_SLOTCAP_PHY_SLOT_NUM_SHIFT) &
354710923SEvan.Yan@Sun.COM PCIE_SLOTCAP_PHY_SLOT_NUM_MASK;
354810923SEvan.Yan@Sun.COM if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE,
354910923SEvan.Yan@Sun.COM dip, "physical-slot#", wordval))
355010923SEvan.Yan@Sun.COM != DDI_SUCCESS) {
355110923SEvan.Yan@Sun.COM return (ret);
355210923SEvan.Yan@Sun.COM }
355310923SEvan.Yan@Sun.COM }
355410923SEvan.Yan@Sun.COM }
355510923SEvan.Yan@Sun.COM return (PCICFG_SUCCESS);
355610923SEvan.Yan@Sun.COM }
355710923SEvan.Yan@Sun.COM static int
pcicfg_set_busnode_props(dev_info_t * dip,uint8_t pcie_device_type,int pbus,int sbus)355810923SEvan.Yan@Sun.COM pcicfg_set_busnode_props(dev_info_t *dip, uint8_t pcie_device_type,
355910923SEvan.Yan@Sun.COM int pbus, int sbus)
356010923SEvan.Yan@Sun.COM {
356110923SEvan.Yan@Sun.COM int ret;
356210923SEvan.Yan@Sun.COM char device_type[8];
356310923SEvan.Yan@Sun.COM
356410923SEvan.Yan@Sun.COM if (pcie_device_type)
356510923SEvan.Yan@Sun.COM (void) strcpy(device_type, "pciex");
356610923SEvan.Yan@Sun.COM else
356710923SEvan.Yan@Sun.COM (void) strcpy(device_type, "pci");
356810923SEvan.Yan@Sun.COM
356910923SEvan.Yan@Sun.COM if ((ret = ndi_prop_update_string(DDI_DEV_T_NONE, dip,
357010923SEvan.Yan@Sun.COM "device_type", device_type)) != DDI_SUCCESS) {
357110923SEvan.Yan@Sun.COM return (ret);
357210923SEvan.Yan@Sun.COM }
357310923SEvan.Yan@Sun.COM if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
357410923SEvan.Yan@Sun.COM "#address-cells", 3)) != DDI_SUCCESS) {
357510923SEvan.Yan@Sun.COM return (ret);
357610923SEvan.Yan@Sun.COM }
357710923SEvan.Yan@Sun.COM if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
357810923SEvan.Yan@Sun.COM "#size-cells", 2)) != DDI_SUCCESS) {
357910923SEvan.Yan@Sun.COM return (ret);
358010923SEvan.Yan@Sun.COM }
358110923SEvan.Yan@Sun.COM
358210923SEvan.Yan@Sun.COM /*
358310923SEvan.Yan@Sun.COM * Create primary-bus and secondary-bus properties to be used
358410923SEvan.Yan@Sun.COM * to restore bus numbers in the pcicfg_setup_bridge() routine.
358510923SEvan.Yan@Sun.COM */
358610923SEvan.Yan@Sun.COM if (pbus != -1 && sbus != -1) {
358710923SEvan.Yan@Sun.COM if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
358810923SEvan.Yan@Sun.COM "primary-bus", pbus)) != DDI_SUCCESS) {
358910923SEvan.Yan@Sun.COM return (ret);
359010923SEvan.Yan@Sun.COM }
359110923SEvan.Yan@Sun.COM if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip,
359210923SEvan.Yan@Sun.COM "secondary-bus", sbus)) != DDI_SUCCESS) {
359310923SEvan.Yan@Sun.COM return (ret);
359410923SEvan.Yan@Sun.COM }
359510923SEvan.Yan@Sun.COM }
359610923SEvan.Yan@Sun.COM return (PCICFG_SUCCESS);
359710923SEvan.Yan@Sun.COM }
359810923SEvan.Yan@Sun.COM
359910923SEvan.Yan@Sun.COM static int
pcicfg_set_childnode_props(dev_info_t * dip,ddi_acc_handle_t config_handle,uint8_t pcie_dev)360010923SEvan.Yan@Sun.COM pcicfg_set_childnode_props(dev_info_t *dip, ddi_acc_handle_t config_handle,
360110923SEvan.Yan@Sun.COM uint8_t pcie_dev)
360210923SEvan.Yan@Sun.COM {
360310923SEvan.Yan@Sun.COM
360410923SEvan.Yan@Sun.COM int ret;
360510923SEvan.Yan@Sun.COM char *name;
360610923SEvan.Yan@Sun.COM char buffer[64], pprefix[8];
360710923SEvan.Yan@Sun.COM uint16_t classcode;
360810923SEvan.Yan@Sun.COM uint8_t revid, pif, pclass, psubclass;
360910923SEvan.Yan@Sun.COM char *compat[24];
361010923SEvan.Yan@Sun.COM int i;
361110923SEvan.Yan@Sun.COM int n;
361210923SEvan.Yan@Sun.COM uint16_t sub_vid, sub_sid, vid, did;
361310923SEvan.Yan@Sun.COM
361410923SEvan.Yan@Sun.COM /* set the property prefix based on the device type */
361510923SEvan.Yan@Sun.COM if (pcie_dev)
361610923SEvan.Yan@Sun.COM (void) sprintf(pprefix, "pciex");
361710923SEvan.Yan@Sun.COM else
361810923SEvan.Yan@Sun.COM (void) sprintf(pprefix, "pci");
361910923SEvan.Yan@Sun.COM sub_vid = pci_config_get16(config_handle, PCI_CONF_SUBVENID);
362010923SEvan.Yan@Sun.COM sub_sid = pci_config_get16(config_handle, PCI_CONF_SUBSYSID);
362110923SEvan.Yan@Sun.COM vid = pci_config_get16(config_handle, PCI_CONF_VENID);
362210923SEvan.Yan@Sun.COM did = pci_config_get16(config_handle, PCI_CONF_DEVID);
362310923SEvan.Yan@Sun.COM revid = pci_config_get8(config_handle, PCI_CONF_REVID);
362410923SEvan.Yan@Sun.COM pif = pci_config_get8(config_handle, PCI_CONF_PROGCLASS);
362510923SEvan.Yan@Sun.COM classcode = pci_config_get16(config_handle, PCI_CONF_SUBCLASS);
362610923SEvan.Yan@Sun.COM pclass = pci_config_get8(config_handle, PCI_CONF_BASCLASS);
362710923SEvan.Yan@Sun.COM psubclass = pci_config_get8(config_handle, PCI_CONF_SUBCLASS);
362810923SEvan.Yan@Sun.COM
362910923SEvan.Yan@Sun.COM /*
363010923SEvan.Yan@Sun.COM * NOTE: These are for both a child and PCI-PCI bridge node
363110923SEvan.Yan@Sun.COM */
363210923SEvan.Yan@Sun.COM
363310923SEvan.Yan@Sun.COM /*
363410923SEvan.Yan@Sun.COM * "name" property rule
363510923SEvan.Yan@Sun.COM * --------------------
363610923SEvan.Yan@Sun.COM *
363710923SEvan.Yan@Sun.COM *
363810923SEvan.Yan@Sun.COM * | \svid |
363910923SEvan.Yan@Sun.COM * | \ |
364010923SEvan.Yan@Sun.COM * | \ |
364110923SEvan.Yan@Sun.COM * | ssid \ | =0 | != 0 |
364210923SEvan.Yan@Sun.COM * |------------|-----------------------|-----------------------|
364310923SEvan.Yan@Sun.COM * | | | |
364410923SEvan.Yan@Sun.COM * | =0 | vid,did | svid,ssid |
364510923SEvan.Yan@Sun.COM * | | | |
364610923SEvan.Yan@Sun.COM * |------------|-----------------------|-----------------------|
364710923SEvan.Yan@Sun.COM * | | | |
364810923SEvan.Yan@Sun.COM * | !=0 | svid,ssid | svid,ssid |
364910923SEvan.Yan@Sun.COM * | | | |
365010923SEvan.Yan@Sun.COM * |------------|-----------------------|-----------------------|
365110923SEvan.Yan@Sun.COM *
365210923SEvan.Yan@Sun.COM * where:
365310923SEvan.Yan@Sun.COM * vid = vendor id
365410923SEvan.Yan@Sun.COM * did = device id
365510923SEvan.Yan@Sun.COM * svid = subsystem vendor id
365610923SEvan.Yan@Sun.COM * ssid = subsystem id
365710923SEvan.Yan@Sun.COM */
365810923SEvan.Yan@Sun.COM
365910923SEvan.Yan@Sun.COM if ((sub_sid != 0) || (sub_vid != 0)) {
366010923SEvan.Yan@Sun.COM (void) sprintf(buffer, "%s%x,%x", pprefix, sub_vid, sub_sid);
366110923SEvan.Yan@Sun.COM } else {
366210923SEvan.Yan@Sun.COM (void) sprintf(buffer, "%s%x,%x", pprefix, vid, did);
366310923SEvan.Yan@Sun.COM }
366410923SEvan.Yan@Sun.COM
366510923SEvan.Yan@Sun.COM /*
366610923SEvan.Yan@Sun.COM * In some environments, trying to use "generic" 1275 names is
366710923SEvan.Yan@Sun.COM * not the convention. In those cases use the name as created
366810923SEvan.Yan@Sun.COM * above. In all the rest of the cases, check to see if there
366910923SEvan.Yan@Sun.COM * is a generic name first.
367010923SEvan.Yan@Sun.COM */
367110923SEvan.Yan@Sun.COM #ifdef _DONT_USE_1275_GENERIC_NAMES
367210923SEvan.Yan@Sun.COM name = buffer;
367310923SEvan.Yan@Sun.COM #else
367410923SEvan.Yan@Sun.COM if ((name = pcicfg_get_class_name(classcode)) == NULL) {
367510923SEvan.Yan@Sun.COM /*
367610923SEvan.Yan@Sun.COM * Set name to the above fabricated name
367710923SEvan.Yan@Sun.COM */
367810923SEvan.Yan@Sun.COM name = buffer;
367910923SEvan.Yan@Sun.COM }
368010923SEvan.Yan@Sun.COM #endif
368110923SEvan.Yan@Sun.COM
368210923SEvan.Yan@Sun.COM /*
368310923SEvan.Yan@Sun.COM * The node name field needs to be filled in with the name
368410923SEvan.Yan@Sun.COM */
368510923SEvan.Yan@Sun.COM if (ndi_devi_set_nodename(dip, name, 0) != NDI_SUCCESS) {
368610923SEvan.Yan@Sun.COM DEBUG0("Failed to set nodename for node\n");
368710923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
368810923SEvan.Yan@Sun.COM }
368910923SEvan.Yan@Sun.COM
369010923SEvan.Yan@Sun.COM /*
369110923SEvan.Yan@Sun.COM * Create the compatible property as an array of pointers
369210923SEvan.Yan@Sun.COM * to strings. Start with the buffer created above.
369310923SEvan.Yan@Sun.COM */
369410923SEvan.Yan@Sun.COM n = 0;
369510923SEvan.Yan@Sun.COM compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
369610923SEvan.Yan@Sun.COM (void) strcpy(compat[n++], buffer);
369710923SEvan.Yan@Sun.COM
369810923SEvan.Yan@Sun.COM /*
369910923SEvan.Yan@Sun.COM * Setup 'compatible' as per the PCI2.1 bindings document.
370010923SEvan.Yan@Sun.COM * pci[ex]VVVV,DDDD.SSSS.ssss.RR
370110923SEvan.Yan@Sun.COM * pci[ex]VVVV,DDDD.SSSS.ssss
370210923SEvan.Yan@Sun.COM * pciSSSS.ssss -> not created for PCIe as per PCIe bindings
370310923SEvan.Yan@Sun.COM * pci[ex]VVVV,DDDD.RR
370410923SEvan.Yan@Sun.COM * pci[ex]VVVV,DDDD
370510923SEvan.Yan@Sun.COM * pci[ex]class,CCSSPP
370610923SEvan.Yan@Sun.COM * pci[ex]class,CCSS
370710923SEvan.Yan@Sun.COM */
370810923SEvan.Yan@Sun.COM
370910923SEvan.Yan@Sun.COM /* pci[ex]VVVV,DDDD.SSSS.ssss.RR */
371010923SEvan.Yan@Sun.COM (void) sprintf(buffer, "%s%x,%x.%x.%x.%x", pprefix, vid, did,
371110923SEvan.Yan@Sun.COM sub_vid, sub_sid, revid);
371210923SEvan.Yan@Sun.COM compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
371310923SEvan.Yan@Sun.COM (void) strcpy(compat[n++], buffer);
371410923SEvan.Yan@Sun.COM
371510923SEvan.Yan@Sun.COM /* pci[ex]VVVV,DDDD.SSSS.ssss */
371610923SEvan.Yan@Sun.COM (void) sprintf(buffer, "%s%x,%x.%x.%x", pprefix, vid, did,
371710923SEvan.Yan@Sun.COM sub_vid, sub_sid);
371810923SEvan.Yan@Sun.COM compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
371910923SEvan.Yan@Sun.COM (void) strcpy(compat[n++], buffer);
372010923SEvan.Yan@Sun.COM
372110923SEvan.Yan@Sun.COM /* pciSSSS.ssss -> not created for PCIe as per PCIe bindings */
372210923SEvan.Yan@Sun.COM if (!pcie_dev) {
372310923SEvan.Yan@Sun.COM (void) sprintf(buffer, "pci%x,%x", sub_vid, sub_sid);
372410923SEvan.Yan@Sun.COM compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
372510923SEvan.Yan@Sun.COM (void) strcpy(compat[n++], buffer);
372610923SEvan.Yan@Sun.COM }
372710923SEvan.Yan@Sun.COM
372810923SEvan.Yan@Sun.COM /* pci[ex]VVVV,DDDD.RR */
372910923SEvan.Yan@Sun.COM (void) sprintf(buffer, "%s%x,%x.%x", pprefix, vid, did, revid);
373010923SEvan.Yan@Sun.COM compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
373110923SEvan.Yan@Sun.COM (void) strcpy(compat[n++], buffer);
373210923SEvan.Yan@Sun.COM
373310923SEvan.Yan@Sun.COM /* pci[ex]VVVV,DDDD */
373410923SEvan.Yan@Sun.COM (void) sprintf(buffer, "%s%x,%x", pprefix, vid, did);
373510923SEvan.Yan@Sun.COM compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
373610923SEvan.Yan@Sun.COM (void) strcpy(compat[n++], buffer);
373710923SEvan.Yan@Sun.COM
373810923SEvan.Yan@Sun.COM /* pci[ex]class,CCSSPP */
373910923SEvan.Yan@Sun.COM (void) sprintf(buffer, "%sclass,%02x%02x%02x", pprefix,
374010923SEvan.Yan@Sun.COM pclass, psubclass, pif);
374110923SEvan.Yan@Sun.COM compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
374210923SEvan.Yan@Sun.COM (void) strcpy(compat[n++], buffer);
374310923SEvan.Yan@Sun.COM
374410923SEvan.Yan@Sun.COM /* pci[ex]class,CCSS */
374510923SEvan.Yan@Sun.COM (void) sprintf(buffer, "%sclass,%04x", pprefix, classcode);
374610923SEvan.Yan@Sun.COM compat[n] = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
374710923SEvan.Yan@Sun.COM (void) strcpy(compat[n++], buffer);
374810923SEvan.Yan@Sun.COM
374910923SEvan.Yan@Sun.COM if ((ret = ndi_prop_update_string_array(DDI_DEV_T_NONE, dip,
375010923SEvan.Yan@Sun.COM "compatible", (char **)compat, n)) != DDI_SUCCESS) {
375110923SEvan.Yan@Sun.COM return (ret);
375210923SEvan.Yan@Sun.COM }
375310923SEvan.Yan@Sun.COM
375410923SEvan.Yan@Sun.COM for (i = 0; i < n; i++) {
375510923SEvan.Yan@Sun.COM kmem_free(compat[i], strlen(compat[i]) + 1);
375610923SEvan.Yan@Sun.COM }
375710923SEvan.Yan@Sun.COM
375810923SEvan.Yan@Sun.COM DEBUG1("pcicfg_set_childnode_props - creating name=%s\n", name);
375910923SEvan.Yan@Sun.COM if ((ret = ndi_prop_update_string(DDI_DEV_T_NONE, dip,
376010923SEvan.Yan@Sun.COM "name", name)) != DDI_SUCCESS) {
376110923SEvan.Yan@Sun.COM
376210923SEvan.Yan@Sun.COM DEBUG0("pcicfg_set_childnode_props - Unable to create name "
376310923SEvan.Yan@Sun.COM "property\n");
376410923SEvan.Yan@Sun.COM
376510923SEvan.Yan@Sun.COM return (ret);
376610923SEvan.Yan@Sun.COM }
376710923SEvan.Yan@Sun.COM
376810923SEvan.Yan@Sun.COM return (PCICFG_SUCCESS);
376910923SEvan.Yan@Sun.COM }
377010923SEvan.Yan@Sun.COM
377110923SEvan.Yan@Sun.COM /*
377210923SEvan.Yan@Sun.COM * Program the bus numbers into the bridge
377310923SEvan.Yan@Sun.COM */
377410923SEvan.Yan@Sun.COM
377510923SEvan.Yan@Sun.COM static void
pcicfg_set_bus_numbers(ddi_acc_handle_t config_handle,uint_t primary,uint_t secondary,uint_t subordinate)377610923SEvan.Yan@Sun.COM pcicfg_set_bus_numbers(ddi_acc_handle_t config_handle,
377710923SEvan.Yan@Sun.COM uint_t primary, uint_t secondary, uint_t subordinate)
377810923SEvan.Yan@Sun.COM {
377910923SEvan.Yan@Sun.COM DEBUG3("Setting bridge bus-range %d,%d,%d\n", primary, secondary,
378010923SEvan.Yan@Sun.COM subordinate);
378110923SEvan.Yan@Sun.COM /*
378210923SEvan.Yan@Sun.COM * Primary bus#
378310923SEvan.Yan@Sun.COM */
378410923SEvan.Yan@Sun.COM pci_config_put8(config_handle, PCI_BCNF_PRIBUS, primary);
378510923SEvan.Yan@Sun.COM
378610923SEvan.Yan@Sun.COM /*
378710923SEvan.Yan@Sun.COM * Secondary bus#
378810923SEvan.Yan@Sun.COM */
378910923SEvan.Yan@Sun.COM pci_config_put8(config_handle, PCI_BCNF_SECBUS, secondary);
379010923SEvan.Yan@Sun.COM
379110923SEvan.Yan@Sun.COM /*
379210923SEvan.Yan@Sun.COM * Subordinate bus#
379310923SEvan.Yan@Sun.COM */
379410923SEvan.Yan@Sun.COM pci_config_put8(config_handle, PCI_BCNF_SUBBUS, subordinate);
379510923SEvan.Yan@Sun.COM }
379610923SEvan.Yan@Sun.COM
379710923SEvan.Yan@Sun.COM /*
379810923SEvan.Yan@Sun.COM * Put bridge registers into initial state
379910923SEvan.Yan@Sun.COM */
380010923SEvan.Yan@Sun.COM static void
pcicfg_setup_bridge(pcicfg_phdl_t * entry,ddi_acc_handle_t handle,dev_info_t * dip)380110923SEvan.Yan@Sun.COM pcicfg_setup_bridge(pcicfg_phdl_t *entry,
380210923SEvan.Yan@Sun.COM ddi_acc_handle_t handle, dev_info_t *dip)
380310923SEvan.Yan@Sun.COM {
380410923SEvan.Yan@Sun.COM int pbus, sbus;
380510923SEvan.Yan@Sun.COM
380610923SEvan.Yan@Sun.COM /*
380710923SEvan.Yan@Sun.COM * The highest bus seen during probing is the max-subordinate bus
380810923SEvan.Yan@Sun.COM */
380910923SEvan.Yan@Sun.COM pci_config_put8(handle, PCI_BCNF_SUBBUS, entry->highest_bus);
381010923SEvan.Yan@Sun.COM
381110923SEvan.Yan@Sun.COM
381210923SEvan.Yan@Sun.COM /*
381310923SEvan.Yan@Sun.COM * If there exists more than 1 downstream bridge, it
381410923SEvan.Yan@Sun.COM * will be reset by the below secondary bus reset which
381510923SEvan.Yan@Sun.COM * will clear the bus numbers assumed to be programmed in
381610923SEvan.Yan@Sun.COM * the pcicfg_probe_children() routine. We therefore restore
381710923SEvan.Yan@Sun.COM * them here.
381810923SEvan.Yan@Sun.COM */
381910923SEvan.Yan@Sun.COM if (pci_config_get8(handle, PCI_BCNF_SECBUS) == 0) {
382010923SEvan.Yan@Sun.COM pbus = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
382110923SEvan.Yan@Sun.COM DDI_PROP_DONTPASS, "primary-bus", -1);
382210923SEvan.Yan@Sun.COM sbus = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
382310923SEvan.Yan@Sun.COM DDI_PROP_DONTPASS, "secondary-bus", -1);
382410923SEvan.Yan@Sun.COM if (pbus != -1 && sbus != -1) {
382510923SEvan.Yan@Sun.COM pci_config_put8(handle, PCI_BCNF_PRIBUS, (uint_t)pbus);
382610923SEvan.Yan@Sun.COM pci_config_put8(handle, PCI_BCNF_SECBUS, (uint_t)sbus);
382710923SEvan.Yan@Sun.COM } else {
382810923SEvan.Yan@Sun.COM cmn_err(CE_WARN, "Invalid Bridge number detected: \
382910923SEvan.Yan@Sun.COM %s%d: pbus = 0x%x, sbus = 0x%x",
383010923SEvan.Yan@Sun.COM ddi_get_name(dip), ddi_get_instance(dip), pbus,
383110923SEvan.Yan@Sun.COM sbus);
383210923SEvan.Yan@Sun.COM }
383310923SEvan.Yan@Sun.COM }
383410923SEvan.Yan@Sun.COM
383510923SEvan.Yan@Sun.COM /*
383610923SEvan.Yan@Sun.COM * Reset the secondary bus
383710923SEvan.Yan@Sun.COM */
383810923SEvan.Yan@Sun.COM pci_config_put16(handle, PCI_BCNF_BCNTRL,
383910923SEvan.Yan@Sun.COM pci_config_get16(handle, PCI_BCNF_BCNTRL) | 0x40);
384010923SEvan.Yan@Sun.COM
384110923SEvan.Yan@Sun.COM drv_usecwait(100);
384210923SEvan.Yan@Sun.COM
384310923SEvan.Yan@Sun.COM pci_config_put16(handle, PCI_BCNF_BCNTRL,
384410923SEvan.Yan@Sun.COM pci_config_get16(handle, PCI_BCNF_BCNTRL) & ~0x40);
384510923SEvan.Yan@Sun.COM
384610923SEvan.Yan@Sun.COM /*
384710923SEvan.Yan@Sun.COM * Program the memory base register with the
384810923SEvan.Yan@Sun.COM * start of the memory range
384910923SEvan.Yan@Sun.COM */
385010923SEvan.Yan@Sun.COM pci_config_put16(handle, PCI_BCNF_MEM_BASE,
385110923SEvan.Yan@Sun.COM PCICFG_HIWORD(PCICFG_LOADDR(entry->memory_last)));
385210923SEvan.Yan@Sun.COM
385310923SEvan.Yan@Sun.COM /*
385410923SEvan.Yan@Sun.COM * Program the I/O base register with the start of the I/O range
385510923SEvan.Yan@Sun.COM */
385610923SEvan.Yan@Sun.COM pci_config_put8(handle, PCI_BCNF_IO_BASE_LOW,
385710923SEvan.Yan@Sun.COM PCICFG_HIBYTE(PCICFG_LOWORD(PCICFG_LOADDR(entry->io_last))));
385810923SEvan.Yan@Sun.COM pci_config_put16(handle, PCI_BCNF_IO_BASE_HI,
385910923SEvan.Yan@Sun.COM PCICFG_HIWORD(PCICFG_LOADDR(entry->io_last)));
386010923SEvan.Yan@Sun.COM
386110923SEvan.Yan@Sun.COM /*
386210923SEvan.Yan@Sun.COM * Clear status bits
386310923SEvan.Yan@Sun.COM */
386410923SEvan.Yan@Sun.COM pci_config_put16(handle, PCI_BCNF_SEC_STATUS, 0xffff);
386510923SEvan.Yan@Sun.COM
386610923SEvan.Yan@Sun.COM /*
386710923SEvan.Yan@Sun.COM * Turn off prefetchable range
386810923SEvan.Yan@Sun.COM */
386910923SEvan.Yan@Sun.COM pci_config_put32(handle, PCI_BCNF_PF_BASE_LOW, 0x0000ffff);
387010923SEvan.Yan@Sun.COM pci_config_put32(handle, PCI_BCNF_PF_BASE_HIGH, 0xffffffff);
387110923SEvan.Yan@Sun.COM pci_config_put32(handle, PCI_BCNF_PF_LIMIT_HIGH, 0x0);
387210923SEvan.Yan@Sun.COM
387310923SEvan.Yan@Sun.COM /*
387410923SEvan.Yan@Sun.COM * Needs to be set to this value
387510923SEvan.Yan@Sun.COM */
387610923SEvan.Yan@Sun.COM pci_config_put8(handle, PCI_CONF_ILINE, 0xf);
387710923SEvan.Yan@Sun.COM
387810923SEvan.Yan@Sun.COM /*
387910923SEvan.Yan@Sun.COM * After a Reset, we need to wait 2^25 clock cycles before the
388010923SEvan.Yan@Sun.COM * first Configuration access. The worst case is 33MHz, which
388110923SEvan.Yan@Sun.COM * is a 1 second wait.
388210923SEvan.Yan@Sun.COM */
388310923SEvan.Yan@Sun.COM drv_usecwait(pcicfg_sec_reset_delay);
388410923SEvan.Yan@Sun.COM
388510923SEvan.Yan@Sun.COM }
388610923SEvan.Yan@Sun.COM
388710923SEvan.Yan@Sun.COM static void
pcicfg_update_bridge(pcicfg_phdl_t * entry,ddi_acc_handle_t handle)388810923SEvan.Yan@Sun.COM pcicfg_update_bridge(pcicfg_phdl_t *entry,
388910923SEvan.Yan@Sun.COM ddi_acc_handle_t handle)
389010923SEvan.Yan@Sun.COM {
389110923SEvan.Yan@Sun.COM uint_t length;
389210923SEvan.Yan@Sun.COM
389310923SEvan.Yan@Sun.COM /*
389410923SEvan.Yan@Sun.COM * Program the memory limit register with the end of the memory range
389510923SEvan.Yan@Sun.COM */
389610923SEvan.Yan@Sun.COM
389710923SEvan.Yan@Sun.COM DEBUG1("DOWN ROUNDED ===>[0x%x]\n",
389810923SEvan.Yan@Sun.COM PCICFG_ROUND_DOWN(entry->memory_last,
389910923SEvan.Yan@Sun.COM PCICFG_MEMGRAN));
390010923SEvan.Yan@Sun.COM
390110923SEvan.Yan@Sun.COM pci_config_put16(handle, PCI_BCNF_MEM_LIMIT,
390210923SEvan.Yan@Sun.COM PCICFG_HIWORD(PCICFG_LOADDR(
390310923SEvan.Yan@Sun.COM PCICFG_ROUND_DOWN(entry->memory_last,
390410923SEvan.Yan@Sun.COM PCICFG_MEMGRAN))));
390510923SEvan.Yan@Sun.COM /*
390610923SEvan.Yan@Sun.COM * Since this is a bridge, the rest of this range will
390710923SEvan.Yan@Sun.COM * be responded to by the bridge. We have to round up
390810923SEvan.Yan@Sun.COM * so no other device claims it.
390910923SEvan.Yan@Sun.COM */
391010923SEvan.Yan@Sun.COM if ((length = (PCICFG_ROUND_UP(entry->memory_last,
391110923SEvan.Yan@Sun.COM PCICFG_MEMGRAN) - entry->memory_last)) > 0) {
391210923SEvan.Yan@Sun.COM (void) pcicfg_get_mem(entry, length, NULL);
391310923SEvan.Yan@Sun.COM DEBUG1("Added [0x%x]at the top of "
391410923SEvan.Yan@Sun.COM "the bridge (mem)\n", length);
391510923SEvan.Yan@Sun.COM }
391610923SEvan.Yan@Sun.COM
391710923SEvan.Yan@Sun.COM /*
391810923SEvan.Yan@Sun.COM * Program the I/O limit register with the end of the I/O range
391910923SEvan.Yan@Sun.COM */
392010923SEvan.Yan@Sun.COM pci_config_put8(handle, PCI_BCNF_IO_LIMIT_LOW,
392110923SEvan.Yan@Sun.COM PCICFG_HIBYTE(PCICFG_LOWORD(
392210923SEvan.Yan@Sun.COM PCICFG_LOADDR(PCICFG_ROUND_DOWN(entry->io_last,
392310923SEvan.Yan@Sun.COM PCICFG_IOGRAN)))));
392410923SEvan.Yan@Sun.COM
392510923SEvan.Yan@Sun.COM pci_config_put16(handle, PCI_BCNF_IO_LIMIT_HI,
392610923SEvan.Yan@Sun.COM PCICFG_HIWORD(PCICFG_LOADDR(PCICFG_ROUND_DOWN(entry->io_last,
392710923SEvan.Yan@Sun.COM PCICFG_IOGRAN))));
392810923SEvan.Yan@Sun.COM
392910923SEvan.Yan@Sun.COM /*
393010923SEvan.Yan@Sun.COM * Same as above for I/O space. Since this is a
393110923SEvan.Yan@Sun.COM * bridge, the rest of this range will be responded
393210923SEvan.Yan@Sun.COM * to by the bridge. We have to round up so no
393310923SEvan.Yan@Sun.COM * other device claims it.
393410923SEvan.Yan@Sun.COM */
393510923SEvan.Yan@Sun.COM if ((length = (PCICFG_ROUND_UP(entry->io_last,
393610923SEvan.Yan@Sun.COM PCICFG_IOGRAN) - entry->io_last)) > 0) {
393710923SEvan.Yan@Sun.COM (void) pcicfg_get_io(entry, length, NULL);
393810923SEvan.Yan@Sun.COM DEBUG1("Added [0x%x]at the top of "
393910923SEvan.Yan@Sun.COM "the bridge (I/O)\n", length);
394010923SEvan.Yan@Sun.COM }
394110923SEvan.Yan@Sun.COM }
394210923SEvan.Yan@Sun.COM
394310923SEvan.Yan@Sun.COM /*ARGSUSED*/
394410923SEvan.Yan@Sun.COM static void
pcicfg_disable_bridge_probe_err(dev_info_t * dip,ddi_acc_handle_t h,pcicfg_err_regs_t * regs)394510923SEvan.Yan@Sun.COM pcicfg_disable_bridge_probe_err(dev_info_t *dip, ddi_acc_handle_t h,
394610923SEvan.Yan@Sun.COM pcicfg_err_regs_t *regs)
394710923SEvan.Yan@Sun.COM {
394810923SEvan.Yan@Sun.COM uint16_t val;
394910923SEvan.Yan@Sun.COM
395010923SEvan.Yan@Sun.COM /* disable SERR generated in the context of Master Aborts. */
395110923SEvan.Yan@Sun.COM regs->cmd = val = pci_config_get16(h, PCI_CONF_COMM);
395210923SEvan.Yan@Sun.COM val &= ~PCI_COMM_SERR_ENABLE;
395310923SEvan.Yan@Sun.COM pci_config_put16(h, PCI_CONF_COMM, val);
395410923SEvan.Yan@Sun.COM regs->bcntl = val = pci_config_get16(h, PCI_BCNF_BCNTRL);
395510923SEvan.Yan@Sun.COM val &= ~PCI_BCNF_BCNTRL_SERR_ENABLE;
395610923SEvan.Yan@Sun.COM pci_config_put16(h, PCI_BCNF_BCNTRL, val);
395710923SEvan.Yan@Sun.COM /* clear any current pending errors */
395810923SEvan.Yan@Sun.COM pci_config_put16(h, PCI_CONF_STAT, PCI_STAT_S_TARG_AB|
395910923SEvan.Yan@Sun.COM PCI_STAT_R_TARG_AB | PCI_STAT_R_MAST_AB | PCI_STAT_S_SYSERR);
396010923SEvan.Yan@Sun.COM pci_config_put16(h, PCI_BCNF_SEC_STATUS, PCI_STAT_S_TARG_AB|
396110923SEvan.Yan@Sun.COM PCI_STAT_R_TARG_AB | PCI_STAT_R_MAST_AB | PCI_STAT_S_SYSERR);
396210923SEvan.Yan@Sun.COM /* if we are a PCIe device, disable the generation of UR, CE and NFE */
396310923SEvan.Yan@Sun.COM if (regs->pcie_dev) {
396410923SEvan.Yan@Sun.COM uint16_t devctl;
396510923SEvan.Yan@Sun.COM uint16_t cap_ptr;
396610923SEvan.Yan@Sun.COM
396710923SEvan.Yan@Sun.COM if ((PCI_CAP_LOCATE(h, PCI_CAP_ID_PCI_E, &cap_ptr)) ==
396810923SEvan.Yan@Sun.COM DDI_FAILURE)
396910923SEvan.Yan@Sun.COM return;
397010923SEvan.Yan@Sun.COM
397110923SEvan.Yan@Sun.COM regs->pcie_cap_off = cap_ptr;
397210923SEvan.Yan@Sun.COM regs->devctl = devctl = PCI_CAP_GET16(h, NULL, cap_ptr,
397310923SEvan.Yan@Sun.COM PCIE_DEVCTL);
397410923SEvan.Yan@Sun.COM devctl &= ~(PCIE_DEVCTL_UR_REPORTING_EN |
397510923SEvan.Yan@Sun.COM PCIE_DEVCTL_CE_REPORTING_EN |
397610923SEvan.Yan@Sun.COM PCIE_DEVCTL_NFE_REPORTING_EN |
397710923SEvan.Yan@Sun.COM PCIE_DEVCTL_FE_REPORTING_EN);
397810923SEvan.Yan@Sun.COM PCI_CAP_PUT16(h, NULL, cap_ptr, PCIE_DEVCTL, devctl);
397910923SEvan.Yan@Sun.COM }
398010923SEvan.Yan@Sun.COM }
398110923SEvan.Yan@Sun.COM
398210923SEvan.Yan@Sun.COM /*ARGSUSED*/
398310923SEvan.Yan@Sun.COM static void
pcicfg_enable_bridge_probe_err(dev_info_t * dip,ddi_acc_handle_t h,pcicfg_err_regs_t * regs)398410923SEvan.Yan@Sun.COM pcicfg_enable_bridge_probe_err(dev_info_t *dip, ddi_acc_handle_t h,
398510923SEvan.Yan@Sun.COM pcicfg_err_regs_t *regs)
398610923SEvan.Yan@Sun.COM {
398710923SEvan.Yan@Sun.COM /* clear any pending errors */
398810923SEvan.Yan@Sun.COM pci_config_put16(h, PCI_CONF_STAT, PCI_STAT_S_TARG_AB|
398910923SEvan.Yan@Sun.COM PCI_STAT_R_TARG_AB | PCI_STAT_R_MAST_AB | PCI_STAT_S_SYSERR);
399010923SEvan.Yan@Sun.COM pci_config_put16(h, PCI_BCNF_SEC_STATUS, PCI_STAT_S_TARG_AB|
399110923SEvan.Yan@Sun.COM PCI_STAT_R_TARG_AB | PCI_STAT_R_MAST_AB | PCI_STAT_S_SYSERR);
399210923SEvan.Yan@Sun.COM
399310923SEvan.Yan@Sun.COM /* restore original settings */
399410923SEvan.Yan@Sun.COM if (regs->pcie_dev) {
399510923SEvan.Yan@Sun.COM pcie_clear_errors(dip);
399610923SEvan.Yan@Sun.COM pci_config_put16(h, regs->pcie_cap_off + PCIE_DEVCTL,
399710923SEvan.Yan@Sun.COM regs->devctl);
399810923SEvan.Yan@Sun.COM }
399910923SEvan.Yan@Sun.COM
400010923SEvan.Yan@Sun.COM pci_config_put16(h, PCI_BCNF_BCNTRL, regs->bcntl);
400110923SEvan.Yan@Sun.COM pci_config_put16(h, PCI_CONF_COMM, regs->cmd);
400210923SEvan.Yan@Sun.COM
400310923SEvan.Yan@Sun.COM }
400410923SEvan.Yan@Sun.COM
400510923SEvan.Yan@Sun.COM 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)400610923SEvan.Yan@Sun.COM pcicfg_probe_children(dev_info_t *parent, uint_t bus, uint_t device,
400711245SZhijun.Fu@Sun.COM uint_t func, uint_t *highest_bus, pcicfg_flags_t flags, boolean_t is_pcie)
400810923SEvan.Yan@Sun.COM {
400910923SEvan.Yan@Sun.COM dev_info_t *new_child;
401010923SEvan.Yan@Sun.COM ddi_acc_handle_t config_handle;
401110923SEvan.Yan@Sun.COM uint8_t header_type, pcie_dev = 0;
401210923SEvan.Yan@Sun.COM int ret;
401310923SEvan.Yan@Sun.COM pcicfg_err_regs_t regs;
401410923SEvan.Yan@Sun.COM
401510923SEvan.Yan@Sun.COM /*
401610923SEvan.Yan@Sun.COM * This node will be put immediately below
401710923SEvan.Yan@Sun.COM * "parent". Allocate a blank device node. It will either
401810923SEvan.Yan@Sun.COM * be filled in or freed up based on further probing.
401910923SEvan.Yan@Sun.COM */
402010923SEvan.Yan@Sun.COM /*
402110923SEvan.Yan@Sun.COM * Note: in usr/src/uts/common/io/hotplug/pcicfg/pcicfg.c
402210923SEvan.Yan@Sun.COM * ndi_devi_alloc() is called as ndi_devi_alloc_sleep()
402310923SEvan.Yan@Sun.COM */
402410923SEvan.Yan@Sun.COM if (ndi_devi_alloc(parent, DEVI_PSEUDO_NEXNAME,
402510923SEvan.Yan@Sun.COM (pnode_t)DEVI_SID_NODEID, &new_child)
402610923SEvan.Yan@Sun.COM != NDI_SUCCESS) {
402710923SEvan.Yan@Sun.COM DEBUG0("pcicfg_probe_children(): Failed to alloc child node\n");
402810923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
402910923SEvan.Yan@Sun.COM }
403010923SEvan.Yan@Sun.COM
403110923SEvan.Yan@Sun.COM if (pcicfg_add_config_reg(new_child, bus,
403210923SEvan.Yan@Sun.COM device, func) != DDI_SUCCESS) {
403310923SEvan.Yan@Sun.COM DEBUG0("pcicfg_probe_children():"
403410923SEvan.Yan@Sun.COM "Failed to add candidate REG\n");
403510923SEvan.Yan@Sun.COM goto failedconfig;
403610923SEvan.Yan@Sun.COM }
403710923SEvan.Yan@Sun.COM
403810923SEvan.Yan@Sun.COM if ((ret = pcicfg_config_setup(new_child, &config_handle))
403910923SEvan.Yan@Sun.COM != PCICFG_SUCCESS) {
404010923SEvan.Yan@Sun.COM if (ret == PCICFG_NODEVICE) {
404110923SEvan.Yan@Sun.COM (void) ndi_devi_free(new_child);
404210923SEvan.Yan@Sun.COM return (ret);
404310923SEvan.Yan@Sun.COM }
404410923SEvan.Yan@Sun.COM DEBUG0("pcicfg_probe_children():"
404510923SEvan.Yan@Sun.COM "Failed to setup config space\n");
404610923SEvan.Yan@Sun.COM goto failedconfig;
404710923SEvan.Yan@Sun.COM }
404810923SEvan.Yan@Sun.COM
404911245SZhijun.Fu@Sun.COM if (is_pcie)
405011245SZhijun.Fu@Sun.COM (void) pcie_init_bus(new_child, PCI_GETBDF(bus, device, func),
405111245SZhijun.Fu@Sun.COM PCIE_BUS_INITIAL);
405211245SZhijun.Fu@Sun.COM
405310923SEvan.Yan@Sun.COM /*
405410923SEvan.Yan@Sun.COM * As soon as we have access to config space,
405510923SEvan.Yan@Sun.COM * turn off device. It will get turned on
405610923SEvan.Yan@Sun.COM * later (after memory is assigned).
405710923SEvan.Yan@Sun.COM */
405810923SEvan.Yan@Sun.COM (void) pcicfg_device_off(config_handle);
405910923SEvan.Yan@Sun.COM
406010923SEvan.Yan@Sun.COM /* check if we are PCIe device */
406110923SEvan.Yan@Sun.COM if (pcicfg_pcie_dev(new_child, PCICFG_DEVICE_TYPE_PCIE, ®s)
406210923SEvan.Yan@Sun.COM == DDI_SUCCESS) {
406310923SEvan.Yan@Sun.COM DEBUG0("PCIe device detected\n");
406410923SEvan.Yan@Sun.COM pcie_dev = 1;
406510923SEvan.Yan@Sun.COM }
406610923SEvan.Yan@Sun.COM
406710923SEvan.Yan@Sun.COM /*
406810923SEvan.Yan@Sun.COM * Set 1275 properties common to all devices
406910923SEvan.Yan@Sun.COM */
407010923SEvan.Yan@Sun.COM if (pcicfg_set_standard_props(new_child, config_handle,
407110923SEvan.Yan@Sun.COM pcie_dev) != PCICFG_SUCCESS) {
407210923SEvan.Yan@Sun.COM DEBUG0("Failed to set standard properties\n");
407310923SEvan.Yan@Sun.COM goto failedchild;
407410923SEvan.Yan@Sun.COM }
407510923SEvan.Yan@Sun.COM
407610923SEvan.Yan@Sun.COM /*
407710923SEvan.Yan@Sun.COM * Child node properties NOTE: Both for PCI-PCI bridge and child node
407810923SEvan.Yan@Sun.COM */
407910923SEvan.Yan@Sun.COM if (pcicfg_set_childnode_props(new_child, config_handle,
408010923SEvan.Yan@Sun.COM pcie_dev) != PCICFG_SUCCESS) {
408110923SEvan.Yan@Sun.COM goto failedchild;
408210923SEvan.Yan@Sun.COM }
408310923SEvan.Yan@Sun.COM
408410923SEvan.Yan@Sun.COM header_type = pci_config_get8(config_handle, PCI_CONF_HEADER);
408510923SEvan.Yan@Sun.COM
408610923SEvan.Yan@Sun.COM /*
408710923SEvan.Yan@Sun.COM * If this is not a multi-function card only probe function zero.
408810923SEvan.Yan@Sun.COM */
408910923SEvan.Yan@Sun.COM if ((!(header_type & PCI_HEADER_MULTI)) && (func != 0)) {
409010923SEvan.Yan@Sun.COM
409110923SEvan.Yan@Sun.COM (void) pcicfg_config_teardown(&config_handle);
409210923SEvan.Yan@Sun.COM (void) ndi_devi_free(new_child);
409310923SEvan.Yan@Sun.COM return (PCICFG_NODEVICE);
409410923SEvan.Yan@Sun.COM }
409510923SEvan.Yan@Sun.COM
409610923SEvan.Yan@Sun.COM DEBUG1("---Vendor ID = [0x%x]\n",
409710923SEvan.Yan@Sun.COM pci_config_get16(config_handle, PCI_CONF_VENID));
409810923SEvan.Yan@Sun.COM DEBUG1("---Device ID = [0x%x]\n",
409910923SEvan.Yan@Sun.COM pci_config_get16(config_handle, PCI_CONF_DEVID));
410010923SEvan.Yan@Sun.COM
410110923SEvan.Yan@Sun.COM /*
410210923SEvan.Yan@Sun.COM * Attach the child to its parent
410310923SEvan.Yan@Sun.COM */
410410923SEvan.Yan@Sun.COM (void) i_ndi_config_node(new_child, DS_LINKED, 0);
410510923SEvan.Yan@Sun.COM
410610923SEvan.Yan@Sun.COM if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
410710923SEvan.Yan@Sun.COM
410810923SEvan.Yan@Sun.COM DEBUG3("--Bridge found bus [0x%x] device"
410910923SEvan.Yan@Sun.COM "[0x%x] func [0x%x]\n", bus, device, func);
411010923SEvan.Yan@Sun.COM
411110923SEvan.Yan@Sun.COM /* Only support read-only probe for leaf device */
411210923SEvan.Yan@Sun.COM if (flags & PCICFG_FLAG_READ_ONLY)
411310923SEvan.Yan@Sun.COM goto failedchild;
411410923SEvan.Yan@Sun.COM
411510923SEvan.Yan@Sun.COM if (pcicfg_probe_bridge(new_child, config_handle,
411611245SZhijun.Fu@Sun.COM bus, highest_bus, is_pcie) != PCICFG_SUCCESS) {
411710923SEvan.Yan@Sun.COM (void) pcicfg_free_bridge_resources(new_child);
411810923SEvan.Yan@Sun.COM goto failedchild;
411910923SEvan.Yan@Sun.COM }
412010923SEvan.Yan@Sun.COM
412110923SEvan.Yan@Sun.COM } else {
412210923SEvan.Yan@Sun.COM
412310923SEvan.Yan@Sun.COM DEBUG3("--Leaf device found bus [0x%x] device"
412410923SEvan.Yan@Sun.COM "[0x%x] func [0x%x]\n",
412510923SEvan.Yan@Sun.COM bus, device, func);
412610923SEvan.Yan@Sun.COM
412710923SEvan.Yan@Sun.COM if (flags & PCICFG_FLAG_READ_ONLY) {
412810923SEvan.Yan@Sun.COM /*
412910923SEvan.Yan@Sun.COM * with read-only probe, don't do any resource
413010923SEvan.Yan@Sun.COM * allocation, just read the BARs and update props.
413110923SEvan.Yan@Sun.COM */
413210923SEvan.Yan@Sun.COM ret = pcicfg_populate_props_from_bar(new_child,
413310923SEvan.Yan@Sun.COM config_handle);
413410923SEvan.Yan@Sun.COM if (ret != PCICFG_SUCCESS)
413510923SEvan.Yan@Sun.COM goto failedchild;
413610923SEvan.Yan@Sun.COM
413710923SEvan.Yan@Sun.COM /*
413810923SEvan.Yan@Sun.COM * for readonly probe "assigned-addresses" property
413910923SEvan.Yan@Sun.COM * has already been setup by reading the BAR, here
414010923SEvan.Yan@Sun.COM * just substract the resource from its parent here.
414110923SEvan.Yan@Sun.COM */
414210923SEvan.Yan@Sun.COM ret = pcicfg_device_assign_readonly(new_child);
414310923SEvan.Yan@Sun.COM if (ret != PCICFG_SUCCESS) {
414410923SEvan.Yan@Sun.COM (void) pcicfg_free_device_resources(new_child,
414510923SEvan.Yan@Sun.COM flags);
414610923SEvan.Yan@Sun.COM goto failedchild;
414710923SEvan.Yan@Sun.COM }
414810923SEvan.Yan@Sun.COM } else {
414910923SEvan.Yan@Sun.COM /*
415010923SEvan.Yan@Sun.COM * update "reg" property by sizing the BARs.
415110923SEvan.Yan@Sun.COM */
415210923SEvan.Yan@Sun.COM ret = pcicfg_populate_reg_props(new_child,
415310923SEvan.Yan@Sun.COM config_handle);
415410923SEvan.Yan@Sun.COM if (ret != PCICFG_SUCCESS)
415510923SEvan.Yan@Sun.COM goto failedchild;
415610923SEvan.Yan@Sun.COM
415710923SEvan.Yan@Sun.COM /* now allocate & program the resources */
415810923SEvan.Yan@Sun.COM ret = pcicfg_device_assign(new_child);
415910923SEvan.Yan@Sun.COM if (ret != PCICFG_SUCCESS) {
416010923SEvan.Yan@Sun.COM (void) pcicfg_free_device_resources(new_child,
416110923SEvan.Yan@Sun.COM flags);
416210923SEvan.Yan@Sun.COM goto failedchild;
416310923SEvan.Yan@Sun.COM }
416410923SEvan.Yan@Sun.COM }
416510923SEvan.Yan@Sun.COM
416610923SEvan.Yan@Sun.COM (void) ndi_devi_bind_driver(new_child, 0);
416710923SEvan.Yan@Sun.COM }
416810923SEvan.Yan@Sun.COM
416910923SEvan.Yan@Sun.COM (void) pcicfg_config_teardown(&config_handle);
417011245SZhijun.Fu@Sun.COM
417111245SZhijun.Fu@Sun.COM /*
417211245SZhijun.Fu@Sun.COM * Properties have been setted up, so initilize the rest fields
417311245SZhijun.Fu@Sun.COM * in bus_t.
417411245SZhijun.Fu@Sun.COM */
417511245SZhijun.Fu@Sun.COM if (is_pcie)
417611387SSurya.Prakki@Sun.COM (void) pcie_init_bus(new_child, 0, PCIE_BUS_FINAL);
417711245SZhijun.Fu@Sun.COM
417810923SEvan.Yan@Sun.COM return (PCICFG_SUCCESS);
417910923SEvan.Yan@Sun.COM
418010923SEvan.Yan@Sun.COM failedchild:
418110923SEvan.Yan@Sun.COM
418210923SEvan.Yan@Sun.COM (void) pcicfg_config_teardown(&config_handle);
418311245SZhijun.Fu@Sun.COM if (is_pcie)
418411245SZhijun.Fu@Sun.COM pcie_fini_bus(new_child, PCIE_BUS_FINAL);
418510923SEvan.Yan@Sun.COM
418610923SEvan.Yan@Sun.COM failedconfig:
418710923SEvan.Yan@Sun.COM
418810923SEvan.Yan@Sun.COM (void) ndi_devi_free(new_child);
418910923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
419010923SEvan.Yan@Sun.COM }
419110923SEvan.Yan@Sun.COM
419210923SEvan.Yan@Sun.COM /*
419310923SEvan.Yan@Sun.COM * Sizing the BARs and update "reg" property
419410923SEvan.Yan@Sun.COM */
419510923SEvan.Yan@Sun.COM static int
pcicfg_populate_reg_props(dev_info_t * new_child,ddi_acc_handle_t config_handle)419610923SEvan.Yan@Sun.COM pcicfg_populate_reg_props(dev_info_t *new_child,
419710923SEvan.Yan@Sun.COM ddi_acc_handle_t config_handle)
419810923SEvan.Yan@Sun.COM {
419910923SEvan.Yan@Sun.COM int i;
420010923SEvan.Yan@Sun.COM uint32_t request;
420110923SEvan.Yan@Sun.COM
420210923SEvan.Yan@Sun.COM i = PCI_CONF_BASE0;
420310923SEvan.Yan@Sun.COM
420410923SEvan.Yan@Sun.COM while (i <= PCI_CONF_BASE5) {
420510923SEvan.Yan@Sun.COM
420610923SEvan.Yan@Sun.COM pci_config_put32(config_handle, i, 0xffffffff);
420710923SEvan.Yan@Sun.COM
420810923SEvan.Yan@Sun.COM request = pci_config_get32(config_handle, i);
420910923SEvan.Yan@Sun.COM /*
421010923SEvan.Yan@Sun.COM * If its a zero length, don't do
421110923SEvan.Yan@Sun.COM * any programming.
421210923SEvan.Yan@Sun.COM */
421310923SEvan.Yan@Sun.COM if (request != 0) {
421410923SEvan.Yan@Sun.COM /*
421510923SEvan.Yan@Sun.COM * Add to the "reg" property
421610923SEvan.Yan@Sun.COM */
421710923SEvan.Yan@Sun.COM if (pcicfg_update_reg_prop(new_child,
421810923SEvan.Yan@Sun.COM request, i) != PCICFG_SUCCESS) {
421910923SEvan.Yan@Sun.COM goto failedchild;
422010923SEvan.Yan@Sun.COM }
422110923SEvan.Yan@Sun.COM } else {
422210923SEvan.Yan@Sun.COM DEBUG1("BASE register [0x%x] asks for "
422310923SEvan.Yan@Sun.COM "[0x0]=[0x0](32)\n", i);
422410923SEvan.Yan@Sun.COM i += 4;
422510923SEvan.Yan@Sun.COM continue;
422610923SEvan.Yan@Sun.COM }
422710923SEvan.Yan@Sun.COM
422810923SEvan.Yan@Sun.COM /*
422910923SEvan.Yan@Sun.COM * Increment by eight if it is 64 bit address space
423010923SEvan.Yan@Sun.COM */
423110923SEvan.Yan@Sun.COM if ((PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_ALL) {
423210923SEvan.Yan@Sun.COM DEBUG3("BASE register [0x%x] asks for "
423310923SEvan.Yan@Sun.COM "[0x%x]=[0x%x] (64)\n",
423410923SEvan.Yan@Sun.COM i, request,
423510923SEvan.Yan@Sun.COM (~(PCI_BASE_M_ADDR_M & request))+1)
423610923SEvan.Yan@Sun.COM i += 8;
423710923SEvan.Yan@Sun.COM } else {
423810923SEvan.Yan@Sun.COM DEBUG3("BASE register [0x%x] asks for "
423910923SEvan.Yan@Sun.COM "[0x%x]=[0x%x](32)\n",
424010923SEvan.Yan@Sun.COM i, request,
424110923SEvan.Yan@Sun.COM (~(PCI_BASE_M_ADDR_M & request))+1)
424210923SEvan.Yan@Sun.COM i += 4;
424310923SEvan.Yan@Sun.COM }
424410923SEvan.Yan@Sun.COM }
424510923SEvan.Yan@Sun.COM
424610923SEvan.Yan@Sun.COM /*
424710923SEvan.Yan@Sun.COM * Get the ROM size and create register for it
424810923SEvan.Yan@Sun.COM */
424910923SEvan.Yan@Sun.COM pci_config_put32(config_handle, PCI_CONF_ROM, 0xfffffffe);
425010923SEvan.Yan@Sun.COM
425110923SEvan.Yan@Sun.COM request = pci_config_get32(config_handle, PCI_CONF_ROM);
425210923SEvan.Yan@Sun.COM /*
425310923SEvan.Yan@Sun.COM * If its a zero length, don't do
425410923SEvan.Yan@Sun.COM * any programming.
425510923SEvan.Yan@Sun.COM */
425610923SEvan.Yan@Sun.COM
425710923SEvan.Yan@Sun.COM if (request != 0) {
425810923SEvan.Yan@Sun.COM DEBUG3("BASE register [0x%x] asks for [0x%x]=[0x%x]\n",
425910923SEvan.Yan@Sun.COM PCI_CONF_ROM, request,
426010923SEvan.Yan@Sun.COM (~(PCI_BASE_ROM_ADDR_M & request))+1);
426110923SEvan.Yan@Sun.COM /*
426210923SEvan.Yan@Sun.COM * Add to the "reg" property
426310923SEvan.Yan@Sun.COM */
426410923SEvan.Yan@Sun.COM if (pcicfg_update_reg_prop(new_child,
426510923SEvan.Yan@Sun.COM request, PCI_CONF_ROM) != PCICFG_SUCCESS) {
426610923SEvan.Yan@Sun.COM goto failedchild;
426710923SEvan.Yan@Sun.COM }
426810923SEvan.Yan@Sun.COM }
426910923SEvan.Yan@Sun.COM
427010923SEvan.Yan@Sun.COM return (PCICFG_SUCCESS);
427110923SEvan.Yan@Sun.COM
427210923SEvan.Yan@Sun.COM failedchild:
427310923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
427410923SEvan.Yan@Sun.COM }
427510923SEvan.Yan@Sun.COM
427610923SEvan.Yan@Sun.COM static int
pcicfg_fcode_probe(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)427710923SEvan.Yan@Sun.COM pcicfg_fcode_probe(dev_info_t *parent, uint_t bus, uint_t device,
427811245SZhijun.Fu@Sun.COM uint_t func, uint_t *highest_bus, pcicfg_flags_t flags, boolean_t is_pcie)
427910923SEvan.Yan@Sun.COM {
428010923SEvan.Yan@Sun.COM dev_info_t *new_child;
428110923SEvan.Yan@Sun.COM int8_t header_type;
428210923SEvan.Yan@Sun.COM int ret;
428310923SEvan.Yan@Sun.COM ddi_acc_handle_t h, ph;
428410923SEvan.Yan@Sun.COM int error = 0;
428510923SEvan.Yan@Sun.COM extern int pcicfg_dont_interpret;
428610923SEvan.Yan@Sun.COM pcicfg_err_regs_t parent_regs, regs;
428710923SEvan.Yan@Sun.COM char *status_prop = NULL;
428810923SEvan.Yan@Sun.COM #ifdef PCICFG_INTERPRET_FCODE
428910923SEvan.Yan@Sun.COM struct pci_ops_bus_args po;
429010923SEvan.Yan@Sun.COM fco_handle_t c;
429110923SEvan.Yan@Sun.COM char unit_address[64];
429210923SEvan.Yan@Sun.COM int fcode_size = 0;
429310923SEvan.Yan@Sun.COM uchar_t *fcode_addr;
429410923SEvan.Yan@Sun.COM uint64_t mem_answer, mem_alen;
429510923SEvan.Yan@Sun.COM pci_regspec_t p;
429610923SEvan.Yan@Sun.COM int32_t request;
429710923SEvan.Yan@Sun.COM ndi_ra_request_t req;
429810923SEvan.Yan@Sun.COM int16_t vendor_id, device_id;
429910923SEvan.Yan@Sun.COM #endif
430010923SEvan.Yan@Sun.COM
430110923SEvan.Yan@Sun.COM /*
430210923SEvan.Yan@Sun.COM * check if our parent is of type pciex.
430310923SEvan.Yan@Sun.COM * if so, program config space to disable error msgs during probe.
430410923SEvan.Yan@Sun.COM */
430510923SEvan.Yan@Sun.COM if (pcicfg_pcie_dev(parent, PCICFG_DEVICE_TYPE_PCIE, &parent_regs)
430610923SEvan.Yan@Sun.COM == DDI_SUCCESS) {
430710923SEvan.Yan@Sun.COM DEBUG0("PCI/PCIe parent detected. Disable errors.\n");
430810923SEvan.Yan@Sun.COM /*
430910923SEvan.Yan@Sun.COM * disable parent generating URs or SERR#s during probing
431010923SEvan.Yan@Sun.COM * alone.
431110923SEvan.Yan@Sun.COM */
431210923SEvan.Yan@Sun.COM if (pci_config_setup(parent, &ph) != DDI_SUCCESS)
431310923SEvan.Yan@Sun.COM return (DDI_FAILURE);
431410923SEvan.Yan@Sun.COM
431510923SEvan.Yan@Sun.COM if ((flags & PCICFG_FLAG_READ_ONLY) == 0) {
431610923SEvan.Yan@Sun.COM pcicfg_disable_bridge_probe_err(parent,
431710923SEvan.Yan@Sun.COM ph, &parent_regs);
431810923SEvan.Yan@Sun.COM }
431910923SEvan.Yan@Sun.COM }
432010923SEvan.Yan@Sun.COM
432110923SEvan.Yan@Sun.COM /*
432210923SEvan.Yan@Sun.COM * This node will be put immediately below
432310923SEvan.Yan@Sun.COM * "parent". Allocate a blank device node. It will either
432410923SEvan.Yan@Sun.COM * be filled in or freed up based on further probing.
432510923SEvan.Yan@Sun.COM */
432610923SEvan.Yan@Sun.COM
432710923SEvan.Yan@Sun.COM if (ndi_devi_alloc(parent, DEVI_PSEUDO_NEXNAME,
432810923SEvan.Yan@Sun.COM (pnode_t)DEVI_SID_NODEID, &new_child)
432910923SEvan.Yan@Sun.COM != NDI_SUCCESS) {
433010923SEvan.Yan@Sun.COM DEBUG0("pcicfg_fcode_probe(): Failed to alloc child node\n");
433110923SEvan.Yan@Sun.COM /* return (PCICFG_FAILURE); */
433210923SEvan.Yan@Sun.COM ret = PCICFG_FAILURE;
433310923SEvan.Yan@Sun.COM goto failed2;
433410923SEvan.Yan@Sun.COM }
433510923SEvan.Yan@Sun.COM
433610923SEvan.Yan@Sun.COM /*
433710923SEvan.Yan@Sun.COM * Create a dummy reg property. This will be replaced with
433810923SEvan.Yan@Sun.COM * a real reg property when fcode completes or if we need to
433910923SEvan.Yan@Sun.COM * produce one by hand.
434010923SEvan.Yan@Sun.COM */
434110923SEvan.Yan@Sun.COM if (pcicfg_add_config_reg(new_child, bus,
434210923SEvan.Yan@Sun.COM device, func) != DDI_SUCCESS) {
434310923SEvan.Yan@Sun.COM ret = PCICFG_FAILURE;
434410923SEvan.Yan@Sun.COM goto failed3;
434510923SEvan.Yan@Sun.COM }
434610923SEvan.Yan@Sun.COM #ifdef EFCODE21554
434710923SEvan.Yan@Sun.COM if ((ret = pcicfg_config_setup(new_child, &h))
434810923SEvan.Yan@Sun.COM != PCICFG_SUCCESS) {
434910923SEvan.Yan@Sun.COM DEBUG0("pcicfg_fcode_probe():"
435010923SEvan.Yan@Sun.COM "Failed to setup config space\n");
435110923SEvan.Yan@Sun.COM ret = PCICFG_NODEVICE;
435210923SEvan.Yan@Sun.COM goto failed3;
435310923SEvan.Yan@Sun.COM }
435410923SEvan.Yan@Sun.COM
435510923SEvan.Yan@Sun.COM #else
435610923SEvan.Yan@Sun.COM p.pci_phys_hi = PCICFG_MAKE_REG_HIGH(bus, device, func, 0);
435710923SEvan.Yan@Sun.COM p.pci_phys_mid = p.pci_phys_low = 0;
435810923SEvan.Yan@Sun.COM p.pci_size_hi = p.pci_size_low = 0;
435910923SEvan.Yan@Sun.COM
436010923SEvan.Yan@Sun.COM /*
436110923SEvan.Yan@Sun.COM * Map in configuration space (temporarily)
436210923SEvan.Yan@Sun.COM */
436310923SEvan.Yan@Sun.COM acc.devacc_attr_version = DDI_DEVICE_ATTR_V0;
436410923SEvan.Yan@Sun.COM acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
436510923SEvan.Yan@Sun.COM acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
436610923SEvan.Yan@Sun.COM
436710923SEvan.Yan@Sun.COM if (pcicfg_map_phys(new_child, &p, &virt, &acc, &h)) {
436810923SEvan.Yan@Sun.COM DEBUG0("pcicfg_fcode_probe():"
436910923SEvan.Yan@Sun.COM "Failed to setup config space\n");
437010923SEvan.Yan@Sun.COM ret = PCICFG_NODEVICE;
437110923SEvan.Yan@Sun.COM goto failed3;
437210923SEvan.Yan@Sun.COM }
437310923SEvan.Yan@Sun.COM
437410923SEvan.Yan@Sun.COM /*
437510923SEvan.Yan@Sun.COM * First use ddi_peek16 so that if there is not a device there,
437610923SEvan.Yan@Sun.COM * a bus error will not cause a panic.
437710923SEvan.Yan@Sun.COM */
437810923SEvan.Yan@Sun.COM v = virt + PCI_CONF_VENID;
437910923SEvan.Yan@Sun.COM if (ddi_peek16(new_child, (int16_t *)v, &vendor_id)) {
438010923SEvan.Yan@Sun.COM DEBUG0("Can not read Vendor ID");
438110923SEvan.Yan@Sun.COM pcicfg_unmap_phys(&h, &p);
438210923SEvan.Yan@Sun.COM ret = PCICFG_NODEVICE;
438310923SEvan.Yan@Sun.COM goto failed3;
438410923SEvan.Yan@Sun.COM }
438510923SEvan.Yan@Sun.COM #endif
438611245SZhijun.Fu@Sun.COM
438711245SZhijun.Fu@Sun.COM if (is_pcie)
438811245SZhijun.Fu@Sun.COM (void) pcie_init_bus(new_child, PCI_GETBDF(bus, device, func),
438911245SZhijun.Fu@Sun.COM PCIE_BUS_INITIAL);
439011245SZhijun.Fu@Sun.COM
439110923SEvan.Yan@Sun.COM DEBUG0("fcode_probe: conf space mapped.\n");
439210923SEvan.Yan@Sun.COM /*
439310923SEvan.Yan@Sun.COM * As soon as we have access to config space,
439410923SEvan.Yan@Sun.COM * turn off device. It will get turned on
439510923SEvan.Yan@Sun.COM * later (after memory is assigned).
439610923SEvan.Yan@Sun.COM */
439710923SEvan.Yan@Sun.COM (void) pcicfg_device_off(h);
439810923SEvan.Yan@Sun.COM
439910923SEvan.Yan@Sun.COM /* check if we are PCIe device */
440010923SEvan.Yan@Sun.COM if (pcicfg_pcie_dev(new_child, PCICFG_DEVICE_TYPE_PCIE, ®s)
440110923SEvan.Yan@Sun.COM == DDI_SUCCESS) {
440210923SEvan.Yan@Sun.COM /*EMPTY*/
440310923SEvan.Yan@Sun.COM DEBUG0("PCI/PCIe device detected\n");
440410923SEvan.Yan@Sun.COM }
440510923SEvan.Yan@Sun.COM
440610923SEvan.Yan@Sun.COM /*
440710923SEvan.Yan@Sun.COM * Set 1275 properties common to all devices
440810923SEvan.Yan@Sun.COM */
440910923SEvan.Yan@Sun.COM if (pcicfg_set_standard_props(new_child,
441010923SEvan.Yan@Sun.COM h, regs.pcie_dev) != PCICFG_SUCCESS) {
441110923SEvan.Yan@Sun.COM DEBUG0("Failed to set standard properties\n");
441210923SEvan.Yan@Sun.COM goto failed;
441310923SEvan.Yan@Sun.COM }
441410923SEvan.Yan@Sun.COM
441510923SEvan.Yan@Sun.COM /*
441610923SEvan.Yan@Sun.COM * Child node properties NOTE: Both for PCI-PCI bridge and child node
441710923SEvan.Yan@Sun.COM */
441810923SEvan.Yan@Sun.COM if (pcicfg_set_childnode_props(new_child,
441910923SEvan.Yan@Sun.COM h, regs.pcie_dev) != PCICFG_SUCCESS) {
442010923SEvan.Yan@Sun.COM ret = PCICFG_FAILURE;
442110923SEvan.Yan@Sun.COM goto failed;
442210923SEvan.Yan@Sun.COM }
442310923SEvan.Yan@Sun.COM
442410923SEvan.Yan@Sun.COM header_type = pci_config_get8(h, PCI_CONF_HEADER);
442510923SEvan.Yan@Sun.COM
442610923SEvan.Yan@Sun.COM /*
442710923SEvan.Yan@Sun.COM * If this is not a multi-function card only probe function zero.
442810923SEvan.Yan@Sun.COM */
442910923SEvan.Yan@Sun.COM if (!(header_type & PCI_HEADER_MULTI) && (func > 0)) {
443010923SEvan.Yan@Sun.COM
443110923SEvan.Yan@Sun.COM ret = PCICFG_NODEVICE;
443210923SEvan.Yan@Sun.COM goto failed;
443310923SEvan.Yan@Sun.COM }
443410923SEvan.Yan@Sun.COM
443510923SEvan.Yan@Sun.COM if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
443610923SEvan.Yan@Sun.COM
443710923SEvan.Yan@Sun.COM /*
443810923SEvan.Yan@Sun.COM * XXX - Transparent bridges are handled differently
443910923SEvan.Yan@Sun.COM * than other devices with regards to fcode. Since
444010923SEvan.Yan@Sun.COM * no transparent bridge currently ships with fcode,
444110923SEvan.Yan@Sun.COM * there is no reason to try to extract it from its rom
444210923SEvan.Yan@Sun.COM * or call the fcode interpreter to try to load a drop-in.
444310923SEvan.Yan@Sun.COM * If fcode is developed to handle transparent bridges,
444410923SEvan.Yan@Sun.COM * this code will have to change.
444510923SEvan.Yan@Sun.COM */
444610923SEvan.Yan@Sun.COM
444710923SEvan.Yan@Sun.COM DEBUG3("--Bridge found bus [0x%x] device"
444810923SEvan.Yan@Sun.COM "[0x%x] func [0x%x]\n", bus, device, func);
444910923SEvan.Yan@Sun.COM
445010923SEvan.Yan@Sun.COM /* Only support read-only probe for leaf device */
445110923SEvan.Yan@Sun.COM if (flags & PCICFG_FLAG_READ_ONLY)
445210923SEvan.Yan@Sun.COM goto failed;
445310923SEvan.Yan@Sun.COM
445410923SEvan.Yan@Sun.COM if ((ret = pcicfg_probe_bridge(new_child, h,
445511245SZhijun.Fu@Sun.COM bus, highest_bus, is_pcie)) != PCICFG_SUCCESS)
445610923SEvan.Yan@Sun.COM (void) pcicfg_free_bridge_resources(new_child);
445710923SEvan.Yan@Sun.COM goto done;
445810923SEvan.Yan@Sun.COM } else {
445910923SEvan.Yan@Sun.COM
446010923SEvan.Yan@Sun.COM DEBUG3("--Leaf device found bus [0x%x] device"
446110923SEvan.Yan@Sun.COM "[0x%x] func [0x%x]\n",
446210923SEvan.Yan@Sun.COM bus, device, func);
446310923SEvan.Yan@Sun.COM
446410923SEvan.Yan@Sun.COM /*
446510923SEvan.Yan@Sun.COM * link in tree, but don't bind driver
446610923SEvan.Yan@Sun.COM * We don't have compatible property yet
446710923SEvan.Yan@Sun.COM */
446810923SEvan.Yan@Sun.COM (void) i_ndi_config_node(new_child, DS_LINKED, 0);
446910923SEvan.Yan@Sun.COM
447010923SEvan.Yan@Sun.COM /* XXX for now, don't run Fcode in read-only probe. */
447110923SEvan.Yan@Sun.COM if (flags & PCICFG_FLAG_READ_ONLY)
447210923SEvan.Yan@Sun.COM goto no_fcode;
447310923SEvan.Yan@Sun.COM
447410923SEvan.Yan@Sun.COM if (pci_config_get8(h, PCI_CONF_IPIN)) {
447510923SEvan.Yan@Sun.COM pci_config_put8(h, PCI_CONF_ILINE, 0xf);
447610923SEvan.Yan@Sun.COM }
447710923SEvan.Yan@Sun.COM
447810923SEvan.Yan@Sun.COM #ifdef PCICFG_INTERPRET_FCODE
447910923SEvan.Yan@Sun.COM /*
448010923SEvan.Yan@Sun.COM * Some platforms (x86) don't run fcode, so don't interpret
448110923SEvan.Yan@Sun.COM * fcode that might be in the ROM.
448210923SEvan.Yan@Sun.COM */
448310923SEvan.Yan@Sun.COM if (pcicfg_dont_interpret == 0) {
448410923SEvan.Yan@Sun.COM
448510923SEvan.Yan@Sun.COM /* This platform supports fcode */
448610923SEvan.Yan@Sun.COM
448710923SEvan.Yan@Sun.COM vendor_id = pci_config_get16(h, PCI_CONF_VENID);
448810923SEvan.Yan@Sun.COM device_id = pci_config_get16(h, PCI_CONF_DEVID);
448910923SEvan.Yan@Sun.COM
449010923SEvan.Yan@Sun.COM /*
449110923SEvan.Yan@Sun.COM * Get the ROM size and create register for it
449210923SEvan.Yan@Sun.COM */
449310923SEvan.Yan@Sun.COM pci_config_put32(h, PCI_CONF_ROM, 0xfffffffe);
449410923SEvan.Yan@Sun.COM
449510923SEvan.Yan@Sun.COM request = pci_config_get32(h, PCI_CONF_ROM);
449610923SEvan.Yan@Sun.COM
449710923SEvan.Yan@Sun.COM /*
449810923SEvan.Yan@Sun.COM * If its a zero length, don't do
449910923SEvan.Yan@Sun.COM * any programming.
450010923SEvan.Yan@Sun.COM */
450110923SEvan.Yan@Sun.COM
450210923SEvan.Yan@Sun.COM if (request != 0) {
450310923SEvan.Yan@Sun.COM /*
450410923SEvan.Yan@Sun.COM * Add resource to assigned-addresses.
450510923SEvan.Yan@Sun.COM */
450610923SEvan.Yan@Sun.COM if (pcicfg_fcode_assign_bars(h, new_child,
450710923SEvan.Yan@Sun.COM bus, device, func, request, &p)
450810923SEvan.Yan@Sun.COM != PCICFG_SUCCESS) {
450910923SEvan.Yan@Sun.COM DEBUG0("Failed to assign addresses to "
451010923SEvan.Yan@Sun.COM "implemented BARs");
451110923SEvan.Yan@Sun.COM ret = PCICFG_FAILURE;
451210923SEvan.Yan@Sun.COM goto failed;
451310923SEvan.Yan@Sun.COM }
451410923SEvan.Yan@Sun.COM
451510923SEvan.Yan@Sun.COM /* Turn device on */
451610923SEvan.Yan@Sun.COM (void) pcicfg_device_on(h);
451710923SEvan.Yan@Sun.COM
451810923SEvan.Yan@Sun.COM /*
451910923SEvan.Yan@Sun.COM * Attempt to load fcode.
452010923SEvan.Yan@Sun.COM */
452110923SEvan.Yan@Sun.COM (void) pcicfg_load_fcode(new_child, bus, device,
452210923SEvan.Yan@Sun.COM func, vendor_id, device_id, &fcode_addr,
452310923SEvan.Yan@Sun.COM &fcode_size, PCICFG_LOADDR(mem_answer),
452410923SEvan.Yan@Sun.COM (~(PCI_BASE_ROM_ADDR_M & request)) + 1);
452510923SEvan.Yan@Sun.COM
452610923SEvan.Yan@Sun.COM /* Turn device off */
452710923SEvan.Yan@Sun.COM (void) pcicfg_device_off(h);
452810923SEvan.Yan@Sun.COM
452910923SEvan.Yan@Sun.COM /*
453010923SEvan.Yan@Sun.COM * Free the ROM resources.
453110923SEvan.Yan@Sun.COM */
453210923SEvan.Yan@Sun.COM (void) pcicfg_free_resource(new_child, p, 0);
453310923SEvan.Yan@Sun.COM
453410923SEvan.Yan@Sun.COM DEBUG2("configure: fcode addr %lx size %x\n",
453510923SEvan.Yan@Sun.COM fcode_addr, fcode_size);
453610923SEvan.Yan@Sun.COM
453710923SEvan.Yan@Sun.COM /*
453810923SEvan.Yan@Sun.COM * Create the fcode-rom-offset property. The
453910923SEvan.Yan@Sun.COM * buffer containing the fcode always starts
454010923SEvan.Yan@Sun.COM * with 0xF1, so the fcode offset is zero.
454110923SEvan.Yan@Sun.COM */
454210923SEvan.Yan@Sun.COM if (ndi_prop_update_int(DDI_DEV_T_NONE,
454310923SEvan.Yan@Sun.COM new_child, "fcode-rom-offset", 0)
454410923SEvan.Yan@Sun.COM != DDI_SUCCESS) {
454510923SEvan.Yan@Sun.COM DEBUG0("Failed to create "
454610923SEvan.Yan@Sun.COM "fcode-rom-offset property\n");
454710923SEvan.Yan@Sun.COM ret = PCICFG_FAILURE;
454810923SEvan.Yan@Sun.COM goto failed;
454910923SEvan.Yan@Sun.COM }
455010923SEvan.Yan@Sun.COM } else {
455110923SEvan.Yan@Sun.COM DEBUG0("There is no Expansion ROM\n");
455210923SEvan.Yan@Sun.COM fcode_addr = NULL;
455310923SEvan.Yan@Sun.COM fcode_size = 0;
455410923SEvan.Yan@Sun.COM }
455510923SEvan.Yan@Sun.COM
455610923SEvan.Yan@Sun.COM /*
455710923SEvan.Yan@Sun.COM * Fill in the bus specific arguments. For
455810923SEvan.Yan@Sun.COM * PCI, it is the config address.
455910923SEvan.Yan@Sun.COM */
456010923SEvan.Yan@Sun.COM po.config_address =
456110923SEvan.Yan@Sun.COM PCICFG_MAKE_REG_HIGH(bus, device, func, 0);
456210923SEvan.Yan@Sun.COM
456310923SEvan.Yan@Sun.COM DEBUG1("config_address=%x\n", po.config_address);
456410923SEvan.Yan@Sun.COM
456510923SEvan.Yan@Sun.COM /*
456610923SEvan.Yan@Sun.COM * Build unit address.
456710923SEvan.Yan@Sun.COM */
456810923SEvan.Yan@Sun.COM (void) sprintf(unit_address, "%x,%x", device, func);
456910923SEvan.Yan@Sun.COM
457010923SEvan.Yan@Sun.COM DEBUG3("pci_fc_ops_alloc_handle ap=%lx "
457110923SEvan.Yan@Sun.COM "new device=%lx unit address=%s\n",
457210923SEvan.Yan@Sun.COM parent, new_child, unit_address);
457310923SEvan.Yan@Sun.COM
457410923SEvan.Yan@Sun.COM c = pci_fc_ops_alloc_handle(parent, new_child,
457510923SEvan.Yan@Sun.COM fcode_addr, fcode_size, unit_address, &po);
457610923SEvan.Yan@Sun.COM
457710923SEvan.Yan@Sun.COM DEBUG0("calling fcode_interpreter()\n");
457810923SEvan.Yan@Sun.COM
457910923SEvan.Yan@Sun.COM DEBUG3("Before int DIP=%lx binding name %s major %d\n",
458010923SEvan.Yan@Sun.COM new_child, ddi_binding_name(new_child),
458110923SEvan.Yan@Sun.COM ddi_driver_major(new_child));
458210923SEvan.Yan@Sun.COM
458310923SEvan.Yan@Sun.COM error = fcode_interpreter(parent, &pci_fc_ops, c);
458410923SEvan.Yan@Sun.COM
458510923SEvan.Yan@Sun.COM DEBUG1("returned from fcode_interpreter() - "
458610923SEvan.Yan@Sun.COM "returned %x\n", error);
458710923SEvan.Yan@Sun.COM
458810923SEvan.Yan@Sun.COM pci_fc_ops_free_handle(c);
458910923SEvan.Yan@Sun.COM
459010923SEvan.Yan@Sun.COM DEBUG1("fcode size = %x\n", fcode_size);
459110923SEvan.Yan@Sun.COM /*
459210923SEvan.Yan@Sun.COM * We don't need the fcode anymore. While allocating
459310923SEvan.Yan@Sun.COM * we had rounded up to a page size.
459410923SEvan.Yan@Sun.COM */
459510923SEvan.Yan@Sun.COM if (fcode_size) {
459610923SEvan.Yan@Sun.COM kmem_free(fcode_addr, ptob(btopr(fcode_size)));
459710923SEvan.Yan@Sun.COM }
459810923SEvan.Yan@Sun.COM } else {
459910923SEvan.Yan@Sun.COM /* This platform does not support fcode */
460010923SEvan.Yan@Sun.COM
460110923SEvan.Yan@Sun.COM DEBUG0("NOT calling fcode_interpreter()\n");
460210923SEvan.Yan@Sun.COM }
460310923SEvan.Yan@Sun.COM
460410923SEvan.Yan@Sun.COM #endif /* PCICFG_INTERPRET_FCODE */
460510923SEvan.Yan@Sun.COM
460610923SEvan.Yan@Sun.COM if ((error == 0) && (pcicfg_dont_interpret == 0)) {
460710923SEvan.Yan@Sun.COM /*
460810923SEvan.Yan@Sun.COM * The interpreter completed successfully.
460910923SEvan.Yan@Sun.COM * We need to redo the resources based on the new reg
461010923SEvan.Yan@Sun.COM * property.
461110923SEvan.Yan@Sun.COM */
461210923SEvan.Yan@Sun.COM DEBUG3("DIP=%lx binding name %s major %d\n", new_child,
461310923SEvan.Yan@Sun.COM ddi_binding_name(new_child),
461410923SEvan.Yan@Sun.COM ddi_driver_major(new_child));
461510923SEvan.Yan@Sun.COM
461610923SEvan.Yan@Sun.COM /*
461710923SEvan.Yan@Sun.COM * Readjust resources specified by reg property.
461810923SEvan.Yan@Sun.COM */
461910923SEvan.Yan@Sun.COM if (pcicfg_alloc_new_resources(new_child) ==
462010923SEvan.Yan@Sun.COM PCICFG_FAILURE) {
462110923SEvan.Yan@Sun.COM ret = PCICFG_FAILURE;
462210923SEvan.Yan@Sun.COM goto failed;
462310923SEvan.Yan@Sun.COM }
462410923SEvan.Yan@Sun.COM
462510923SEvan.Yan@Sun.COM /*
462610923SEvan.Yan@Sun.COM * At this stage, there should be enough info to pull
462710923SEvan.Yan@Sun.COM * the status property if it exists.
462810923SEvan.Yan@Sun.COM */
462910923SEvan.Yan@Sun.COM if (ddi_prop_lookup_string(DDI_DEV_T_ANY,
463010923SEvan.Yan@Sun.COM new_child, NULL, "status", &status_prop) ==
463110923SEvan.Yan@Sun.COM DDI_PROP_SUCCESS) {
463210923SEvan.Yan@Sun.COM if ((strncmp("disabled", status_prop, 8) ==
463310923SEvan.Yan@Sun.COM 0) || (strncmp("fail", status_prop, 4) ==
463410923SEvan.Yan@Sun.COM 0)) {
463510923SEvan.Yan@Sun.COM ret = PCICFG_FAILURE;
463610923SEvan.Yan@Sun.COM ddi_prop_free(status_prop);
463710923SEvan.Yan@Sun.COM goto failed;
463810923SEvan.Yan@Sun.COM } else {
463910923SEvan.Yan@Sun.COM ddi_prop_free(status_prop);
464010923SEvan.Yan@Sun.COM }
464110923SEvan.Yan@Sun.COM }
464210923SEvan.Yan@Sun.COM
464310923SEvan.Yan@Sun.COM ret = PCICFG_SUCCESS;
464410923SEvan.Yan@Sun.COM /* no fcode, bind driver now */
464510923SEvan.Yan@Sun.COM (void) ndi_devi_bind_driver(new_child, 0);
464610923SEvan.Yan@Sun.COM
464710923SEvan.Yan@Sun.COM goto done;
464810923SEvan.Yan@Sun.COM } else if ((error != FC_NO_FCODE) &&
464910923SEvan.Yan@Sun.COM (pcicfg_dont_interpret == 0)) {
465010923SEvan.Yan@Sun.COM /*
465110923SEvan.Yan@Sun.COM * The interpreter located fcode, but had an error in
465210923SEvan.Yan@Sun.COM * processing. Cleanup and fail the operation.
465310923SEvan.Yan@Sun.COM */
465410923SEvan.Yan@Sun.COM DEBUG0("Interpreter detected fcode failure\n");
465510923SEvan.Yan@Sun.COM (void) pcicfg_free_resources(new_child, flags);
465610923SEvan.Yan@Sun.COM ret = PCICFG_FAILURE;
465710923SEvan.Yan@Sun.COM goto failed;
465810923SEvan.Yan@Sun.COM } else {
465910923SEvan.Yan@Sun.COM no_fcode:
466010923SEvan.Yan@Sun.COM /*
466110923SEvan.Yan@Sun.COM * Either the interpreter failed with FC_NO_FCODE or we
466210923SEvan.Yan@Sun.COM * chose not to run the interpreter
466310923SEvan.Yan@Sun.COM * (pcicfg_dont_interpret).
466410923SEvan.Yan@Sun.COM *
466510923SEvan.Yan@Sun.COM * If the interpreter failed because there was no
466610923SEvan.Yan@Sun.COM * dropin, then we need to probe the device ourself.
466710923SEvan.Yan@Sun.COM */
466810923SEvan.Yan@Sun.COM
466910923SEvan.Yan@Sun.COM /*
467010923SEvan.Yan@Sun.COM * Free any resources that may have been assigned
467110923SEvan.Yan@Sun.COM * during fcode loading/execution since we need
467210923SEvan.Yan@Sun.COM * to start over.
467310923SEvan.Yan@Sun.COM */
467410923SEvan.Yan@Sun.COM (void) pcicfg_free_resources(new_child, flags);
467510923SEvan.Yan@Sun.COM
467610923SEvan.Yan@Sun.COM #ifdef EFCODE21554
467710923SEvan.Yan@Sun.COM pcicfg_config_teardown(&h);
467810923SEvan.Yan@Sun.COM #else
467910923SEvan.Yan@Sun.COM pcicfg_unmap_phys(&h, &p);
468010923SEvan.Yan@Sun.COM #endif
468111245SZhijun.Fu@Sun.COM /* destroy the bus_t before the dev node is gone */
468211245SZhijun.Fu@Sun.COM if (is_pcie)
468311245SZhijun.Fu@Sun.COM pcie_fini_bus(new_child, PCIE_BUS_FINAL);
468411245SZhijun.Fu@Sun.COM
468510923SEvan.Yan@Sun.COM (void) ndi_devi_free(new_child);
468610923SEvan.Yan@Sun.COM
468710923SEvan.Yan@Sun.COM DEBUG0("No Drop-in Probe device ourself\n");
468810923SEvan.Yan@Sun.COM
468910923SEvan.Yan@Sun.COM ret = pcicfg_probe_children(parent, bus, device, func,
469011245SZhijun.Fu@Sun.COM highest_bus, flags, is_pcie);
469110923SEvan.Yan@Sun.COM
469210923SEvan.Yan@Sun.COM if (ret != PCICFG_SUCCESS) {
469310923SEvan.Yan@Sun.COM DEBUG0("Could not self probe child\n");
469410923SEvan.Yan@Sun.COM goto failed2;
469510923SEvan.Yan@Sun.COM }
469610923SEvan.Yan@Sun.COM
469710923SEvan.Yan@Sun.COM /*
469810923SEvan.Yan@Sun.COM * We successfully self probed the device.
469910923SEvan.Yan@Sun.COM */
470010923SEvan.Yan@Sun.COM if ((new_child = pcicfg_devi_find(
470110923SEvan.Yan@Sun.COM parent, device, func)) == NULL) {
470210923SEvan.Yan@Sun.COM DEBUG0("Did'nt find device node "
470310923SEvan.Yan@Sun.COM "just created\n");
470410923SEvan.Yan@Sun.COM ret = PCICFG_FAILURE;
470510923SEvan.Yan@Sun.COM goto failed2;
470610923SEvan.Yan@Sun.COM }
470710923SEvan.Yan@Sun.COM #ifdef EFCODE21554
470810923SEvan.Yan@Sun.COM /*
470910923SEvan.Yan@Sun.COM * Till now, we have detected a non transparent bridge
471010923SEvan.Yan@Sun.COM * (ntbridge) as a part of the generic probe code and
471110923SEvan.Yan@Sun.COM * configured only one configuration
471210923SEvan.Yan@Sun.COM * header which is the side facing the host bus.
471310923SEvan.Yan@Sun.COM * Now, configure the other side and create children.
471410923SEvan.Yan@Sun.COM *
471510923SEvan.Yan@Sun.COM * To make the process simpler, lets load the device
471610923SEvan.Yan@Sun.COM * driver for the non transparent bridge as this is a
471710923SEvan.Yan@Sun.COM * Solaris bundled driver, and use its configuration map
471810923SEvan.Yan@Sun.COM * services rather than programming it here.
471910923SEvan.Yan@Sun.COM * If the driver is not bundled into Solaris, it must be
472010923SEvan.Yan@Sun.COM * first loaded and configured before performing any
472110923SEvan.Yan@Sun.COM * hotplug operations.
472210923SEvan.Yan@Sun.COM *
472310923SEvan.Yan@Sun.COM * This not only makes the code simpler but also more
472410923SEvan.Yan@Sun.COM * generic.
472510923SEvan.Yan@Sun.COM *
472610923SEvan.Yan@Sun.COM * So here we go.
472710923SEvan.Yan@Sun.COM */
472810923SEvan.Yan@Sun.COM if (pcicfg_is_ntbridge(new_child) != DDI_FAILURE) {
472910923SEvan.Yan@Sun.COM
473010923SEvan.Yan@Sun.COM DEBUG0("Found nontransparent bridge.\n");
473110923SEvan.Yan@Sun.COM
473210923SEvan.Yan@Sun.COM ret = pcicfg_configure_ntbridge(new_child,
473310923SEvan.Yan@Sun.COM bus, device);
473410923SEvan.Yan@Sun.COM }
473510923SEvan.Yan@Sun.COM if (ret != PCICFG_SUCCESS) {
473610923SEvan.Yan@Sun.COM /*
473710923SEvan.Yan@Sun.COM * Bridge configure failed. Free up the self
473810923SEvan.Yan@Sun.COM * probed entry. The bus resource allocation
473910923SEvan.Yan@Sun.COM * maps need to be cleaned up to prevent
474010923SEvan.Yan@Sun.COM * warnings on retries of the failed configure.
474110923SEvan.Yan@Sun.COM */
474210923SEvan.Yan@Sun.COM (void) pcicfg_ntbridge_unconfigure(new_child);
474311245SZhijun.Fu@Sun.COM (void) pcicfg_teardown_device(new_child,
474411245SZhijun.Fu@Sun.COM flags, is_pcie);
474510923SEvan.Yan@Sun.COM }
474610923SEvan.Yan@Sun.COM #endif
474710923SEvan.Yan@Sun.COM goto done2;
474810923SEvan.Yan@Sun.COM }
474910923SEvan.Yan@Sun.COM }
475010923SEvan.Yan@Sun.COM done:
475110923SEvan.Yan@Sun.COM failed:
475211245SZhijun.Fu@Sun.COM if (is_pcie) {
475311245SZhijun.Fu@Sun.COM if (ret == PCICFG_SUCCESS)
475411387SSurya.Prakki@Sun.COM (void) pcie_init_bus(new_child, 0, PCIE_BUS_FINAL);
475511245SZhijun.Fu@Sun.COM else
475611245SZhijun.Fu@Sun.COM pcie_fini_bus(new_child, PCIE_BUS_FINAL);
475711245SZhijun.Fu@Sun.COM }
475811245SZhijun.Fu@Sun.COM
475910923SEvan.Yan@Sun.COM #ifdef EFCODE21554
476010923SEvan.Yan@Sun.COM pcicfg_config_teardown(&h);
476110923SEvan.Yan@Sun.COM #else
476210923SEvan.Yan@Sun.COM pcicfg_unmap_phys(&h, &p);
476310923SEvan.Yan@Sun.COM #endif
476410923SEvan.Yan@Sun.COM failed3:
476510923SEvan.Yan@Sun.COM if (ret != PCICFG_SUCCESS)
476610923SEvan.Yan@Sun.COM (void) ndi_devi_free(new_child);
476710923SEvan.Yan@Sun.COM done2:
476810923SEvan.Yan@Sun.COM failed2:
476910923SEvan.Yan@Sun.COM if (parent_regs.pcie_dev) {
477010923SEvan.Yan@Sun.COM if ((flags & PCICFG_FLAG_READ_ONLY) == 0) {
477110923SEvan.Yan@Sun.COM pcicfg_enable_bridge_probe_err(parent,
477210923SEvan.Yan@Sun.COM ph, &parent_regs);
477310923SEvan.Yan@Sun.COM }
477410923SEvan.Yan@Sun.COM pci_config_teardown(&ph);
477510923SEvan.Yan@Sun.COM }
477611245SZhijun.Fu@Sun.COM
477710923SEvan.Yan@Sun.COM return (ret);
477810923SEvan.Yan@Sun.COM }
477910923SEvan.Yan@Sun.COM
478010923SEvan.Yan@Sun.COM /*
478110923SEvan.Yan@Sun.COM * Read the BARs and update properties. Used in virtual hotplug.
478210923SEvan.Yan@Sun.COM */
478310923SEvan.Yan@Sun.COM static int
pcicfg_populate_props_from_bar(dev_info_t * new_child,ddi_acc_handle_t config_handle)478410923SEvan.Yan@Sun.COM pcicfg_populate_props_from_bar(dev_info_t *new_child,
478510923SEvan.Yan@Sun.COM ddi_acc_handle_t config_handle)
478610923SEvan.Yan@Sun.COM {
478710923SEvan.Yan@Sun.COM uint32_t request, base, base_hi, size;
478810923SEvan.Yan@Sun.COM int i;
478910923SEvan.Yan@Sun.COM
479010923SEvan.Yan@Sun.COM i = PCI_CONF_BASE0;
479110923SEvan.Yan@Sun.COM
479210923SEvan.Yan@Sun.COM while (i <= PCI_CONF_BASE5) {
479310923SEvan.Yan@Sun.COM /*
479410923SEvan.Yan@Sun.COM * determine the size of the address space
479510923SEvan.Yan@Sun.COM */
479610923SEvan.Yan@Sun.COM base = pci_config_get32(config_handle, i);
479710923SEvan.Yan@Sun.COM pci_config_put32(config_handle, i, 0xffffffff);
479810923SEvan.Yan@Sun.COM request = pci_config_get32(config_handle, i);
479910923SEvan.Yan@Sun.COM pci_config_put32(config_handle, i, base);
480010923SEvan.Yan@Sun.COM
480110923SEvan.Yan@Sun.COM /*
480210923SEvan.Yan@Sun.COM * If its a zero length, don't do any programming.
480310923SEvan.Yan@Sun.COM */
480410923SEvan.Yan@Sun.COM if (request != 0) {
480510923SEvan.Yan@Sun.COM /*
480610923SEvan.Yan@Sun.COM * Add to the "reg" property
480710923SEvan.Yan@Sun.COM */
480810923SEvan.Yan@Sun.COM if (pcicfg_update_reg_prop(new_child,
480910923SEvan.Yan@Sun.COM request, i) != PCICFG_SUCCESS) {
481010923SEvan.Yan@Sun.COM goto failedchild;
481110923SEvan.Yan@Sun.COM }
481210923SEvan.Yan@Sun.COM
481310923SEvan.Yan@Sun.COM if ((PCI_BASE_SPACE_IO & request) == 0 &&
481410923SEvan.Yan@Sun.COM (PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_ALL) {
481510923SEvan.Yan@Sun.COM base_hi = pci_config_get32(config_handle, i+4);
481610923SEvan.Yan@Sun.COM } else {
481710923SEvan.Yan@Sun.COM base_hi = 0;
481810923SEvan.Yan@Sun.COM }
481910923SEvan.Yan@Sun.COM /*
482010923SEvan.Yan@Sun.COM * Add to "assigned-addresses" property
482110923SEvan.Yan@Sun.COM */
482210923SEvan.Yan@Sun.COM size = (~(PCI_BASE_M_ADDR_M & request))+1;
482310923SEvan.Yan@Sun.COM if (pcicfg_update_assigned_prop_value(new_child,
482410923SEvan.Yan@Sun.COM size, base, base_hi, i) != PCICFG_SUCCESS) {
482510923SEvan.Yan@Sun.COM goto failedchild;
482610923SEvan.Yan@Sun.COM }
482710923SEvan.Yan@Sun.COM } else {
482810923SEvan.Yan@Sun.COM DEBUG1("BASE register [0x%x] asks for "
482910923SEvan.Yan@Sun.COM "[0x0]=[0x0](32)\n", i);
483010923SEvan.Yan@Sun.COM i += 4;
483110923SEvan.Yan@Sun.COM continue;
483210923SEvan.Yan@Sun.COM }
483310923SEvan.Yan@Sun.COM
483410923SEvan.Yan@Sun.COM /*
483510923SEvan.Yan@Sun.COM * Increment by eight if it is 64 bit address space
483610923SEvan.Yan@Sun.COM */
483710923SEvan.Yan@Sun.COM if ((PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_ALL) {
483810923SEvan.Yan@Sun.COM DEBUG3("BASE register [0x%x] asks for "
483910923SEvan.Yan@Sun.COM "[0x%x]=[0x%x] (64)\n",
484010923SEvan.Yan@Sun.COM i, request,
484110923SEvan.Yan@Sun.COM (~(PCI_BASE_M_ADDR_M & request))+1)
484210923SEvan.Yan@Sun.COM i += 8;
484310923SEvan.Yan@Sun.COM } else {
484410923SEvan.Yan@Sun.COM DEBUG3("BASE register [0x%x] asks for "
484510923SEvan.Yan@Sun.COM "[0x%x]=[0x%x](32)\n",
484610923SEvan.Yan@Sun.COM i, request,
484710923SEvan.Yan@Sun.COM (~(PCI_BASE_M_ADDR_M & request))+1)
484810923SEvan.Yan@Sun.COM i += 4;
484910923SEvan.Yan@Sun.COM }
485010923SEvan.Yan@Sun.COM }
485110923SEvan.Yan@Sun.COM
485210923SEvan.Yan@Sun.COM /*
485310923SEvan.Yan@Sun.COM * Get the ROM size and create register for it
485410923SEvan.Yan@Sun.COM */
485510923SEvan.Yan@Sun.COM base = pci_config_get32(config_handle, PCI_CONF_ROM);
485610923SEvan.Yan@Sun.COM pci_config_put32(config_handle, PCI_CONF_ROM, 0xfffffffe);
485710923SEvan.Yan@Sun.COM request = pci_config_get32(config_handle, PCI_CONF_ROM);
485810923SEvan.Yan@Sun.COM pci_config_put32(config_handle, PCI_CONF_ROM, base);
485910923SEvan.Yan@Sun.COM
486010923SEvan.Yan@Sun.COM /*
486110923SEvan.Yan@Sun.COM * If its a zero length, don't do
486210923SEvan.Yan@Sun.COM * any programming.
486310923SEvan.Yan@Sun.COM */
486410923SEvan.Yan@Sun.COM if (request != 0) {
486510923SEvan.Yan@Sun.COM DEBUG3("BASE register [0x%x] asks for [0x%x]=[0x%x]\n",
486610923SEvan.Yan@Sun.COM PCI_CONF_ROM, request,
486710923SEvan.Yan@Sun.COM (~(PCI_BASE_ROM_ADDR_M & request))+1);
486810923SEvan.Yan@Sun.COM /*
486910923SEvan.Yan@Sun.COM * Add to the "reg" property
487010923SEvan.Yan@Sun.COM */
487110923SEvan.Yan@Sun.COM if (pcicfg_update_reg_prop(new_child,
487210923SEvan.Yan@Sun.COM request, PCI_CONF_ROM) != PCICFG_SUCCESS) {
487310923SEvan.Yan@Sun.COM goto failedchild;
487410923SEvan.Yan@Sun.COM }
487510923SEvan.Yan@Sun.COM /*
487610923SEvan.Yan@Sun.COM * Add to "assigned-addresses" property
487710923SEvan.Yan@Sun.COM */
487810923SEvan.Yan@Sun.COM size = (~(PCI_BASE_ROM_ADDR_M & request))+1;
487910923SEvan.Yan@Sun.COM if (pcicfg_update_assigned_prop_value(new_child, size,
488010923SEvan.Yan@Sun.COM base, 0, PCI_CONF_ROM) != PCICFG_SUCCESS) {
488110923SEvan.Yan@Sun.COM goto failedchild;
488210923SEvan.Yan@Sun.COM }
488310923SEvan.Yan@Sun.COM }
488410923SEvan.Yan@Sun.COM
488510923SEvan.Yan@Sun.COM return (PCICFG_SUCCESS);
488610923SEvan.Yan@Sun.COM
488710923SEvan.Yan@Sun.COM failedchild:
488810923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
488910923SEvan.Yan@Sun.COM }
489010923SEvan.Yan@Sun.COM
489110923SEvan.Yan@Sun.COM 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)489210923SEvan.Yan@Sun.COM pcicfg_probe_bridge(dev_info_t *new_child, ddi_acc_handle_t h, uint_t bus,
489311245SZhijun.Fu@Sun.COM uint_t *highest_bus, boolean_t is_pcie)
489410923SEvan.Yan@Sun.COM {
489510923SEvan.Yan@Sun.COM uint64_t next_bus;
489610923SEvan.Yan@Sun.COM uint_t new_bus, num_slots;
489710923SEvan.Yan@Sun.COM ndi_ra_request_t req;
489810923SEvan.Yan@Sun.COM int rval, i, j;
489910923SEvan.Yan@Sun.COM uint64_t mem_answer, mem_base, mem_alen, mem_size, mem_end;
490010923SEvan.Yan@Sun.COM uint64_t io_answer, io_base, io_alen, io_size, io_end;
490110923SEvan.Yan@Sun.COM uint64_t round_answer, round_len;
490210923SEvan.Yan@Sun.COM pcicfg_range_t range[PCICFG_RANGE_LEN];
490310923SEvan.Yan@Sun.COM int bus_range[2];
490410923SEvan.Yan@Sun.COM pcicfg_phdl_t phdl;
490510923SEvan.Yan@Sun.COM int count;
490610923SEvan.Yan@Sun.COM uint64_t pcibus_base, pcibus_alen;
490710923SEvan.Yan@Sun.COM uint64_t max_bus;
490810923SEvan.Yan@Sun.COM uint8_t pcie_device_type = 0;
490910923SEvan.Yan@Sun.COM dev_info_t *new_device;
491010923SEvan.Yan@Sun.COM int trans_device;
491110923SEvan.Yan@Sun.COM int ari_mode = B_FALSE;
491210923SEvan.Yan@Sun.COM int max_function = PCICFG_MAX_FUNCTION;
491310923SEvan.Yan@Sun.COM
491410923SEvan.Yan@Sun.COM /*
491510923SEvan.Yan@Sun.COM * Set "device_type" to "pci", the actual type will be set later
491610923SEvan.Yan@Sun.COM * by pcicfg_set_busnode_props() below. This is needed as the
491710923SEvan.Yan@Sun.COM * pcicfg_ra_free() below would update "available" property based
491810923SEvan.Yan@Sun.COM * on "device_type".
491910923SEvan.Yan@Sun.COM *
492010923SEvan.Yan@Sun.COM * This code can be removed later after PCI configurator is changed
492110923SEvan.Yan@Sun.COM * to use PCIRM, which automatically update properties upon allocation
492210923SEvan.Yan@Sun.COM * and free, at that time we'll be able to remove the code inside
492310923SEvan.Yan@Sun.COM * ndi_ra_alloc/free() which currently updates "available" property
492410923SEvan.Yan@Sun.COM * for pci/pcie devices in pcie fabric.
492510923SEvan.Yan@Sun.COM */
492610923SEvan.Yan@Sun.COM if (ndi_prop_update_string(DDI_DEV_T_NONE, new_child,
492710923SEvan.Yan@Sun.COM "device_type", "pci") != DDI_SUCCESS) {
492810923SEvan.Yan@Sun.COM DEBUG0("Failed to set \"device_type\" props\n");
492910923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
493010923SEvan.Yan@Sun.COM }
493110923SEvan.Yan@Sun.COM
493210923SEvan.Yan@Sun.COM bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
493310923SEvan.Yan@Sun.COM req.ra_flags = (NDI_RA_ALLOC_BOUNDED | NDI_RA_ALLOC_PARTIAL_OK);
493410923SEvan.Yan@Sun.COM req.ra_boundbase = 0;
493510923SEvan.Yan@Sun.COM req.ra_boundlen = PCICFG_MAX_BUS_DEPTH;
493610923SEvan.Yan@Sun.COM req.ra_len = PCICFG_MAX_BUS_DEPTH;
493710923SEvan.Yan@Sun.COM req.ra_align_mask = 0; /* no alignment needed */
493810923SEvan.Yan@Sun.COM
493910923SEvan.Yan@Sun.COM rval = ndi_ra_alloc(ddi_get_parent(new_child), &req,
494010923SEvan.Yan@Sun.COM &pcibus_base, &pcibus_alen, NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS);
494110923SEvan.Yan@Sun.COM
494210923SEvan.Yan@Sun.COM if (rval != NDI_SUCCESS) {
494310923SEvan.Yan@Sun.COM if (rval == NDI_RA_PARTIAL_REQ) {
494410923SEvan.Yan@Sun.COM /*EMPTY*/
494510923SEvan.Yan@Sun.COM DEBUG0("NDI_RA_PARTIAL_REQ returned for bus range\n");
494610923SEvan.Yan@Sun.COM } else {
494710923SEvan.Yan@Sun.COM DEBUG0(
494810923SEvan.Yan@Sun.COM "Failed to allocate bus range for bridge\n");
494910923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
495010923SEvan.Yan@Sun.COM }
495110923SEvan.Yan@Sun.COM }
495210923SEvan.Yan@Sun.COM
495310923SEvan.Yan@Sun.COM DEBUG2("Bus Range Allocated [base=%d] [len=%d]\n",
495410923SEvan.Yan@Sun.COM pcibus_base, pcibus_alen);
495510923SEvan.Yan@Sun.COM
495610923SEvan.Yan@Sun.COM if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_PCI_BUSNUM)
495710923SEvan.Yan@Sun.COM == NDI_FAILURE) {
495810923SEvan.Yan@Sun.COM DEBUG0("Can not setup resource map - NDI_RA_TYPE_PCI_BUSNUM\n");
495910923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
496010923SEvan.Yan@Sun.COM }
496110923SEvan.Yan@Sun.COM
496210923SEvan.Yan@Sun.COM /*
496310923SEvan.Yan@Sun.COM * Put available bus range into the pool.
496410923SEvan.Yan@Sun.COM * Take the first one for this bridge to use and don't give
496510923SEvan.Yan@Sun.COM * to child.
496610923SEvan.Yan@Sun.COM */
496710923SEvan.Yan@Sun.COM (void) ndi_ra_free(new_child, pcibus_base+1, pcibus_alen-1,
496810923SEvan.Yan@Sun.COM NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS);
496910923SEvan.Yan@Sun.COM
497010923SEvan.Yan@Sun.COM next_bus = pcibus_base;
497110923SEvan.Yan@Sun.COM max_bus = pcibus_base + pcibus_alen - 1;
497210923SEvan.Yan@Sun.COM
497310923SEvan.Yan@Sun.COM new_bus = next_bus;
497410923SEvan.Yan@Sun.COM
497510923SEvan.Yan@Sun.COM DEBUG1("NEW bus found ->[%d]\n", new_bus);
497610923SEvan.Yan@Sun.COM
497710923SEvan.Yan@Sun.COM /* Keep track of highest bus for subordinate bus programming */
497810923SEvan.Yan@Sun.COM *highest_bus = new_bus;
497910923SEvan.Yan@Sun.COM
498010923SEvan.Yan@Sun.COM /*
498110923SEvan.Yan@Sun.COM * Allocate Memory Space for Bridge
498210923SEvan.Yan@Sun.COM */
498310923SEvan.Yan@Sun.COM bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
498410923SEvan.Yan@Sun.COM req.ra_flags = (NDI_RA_ALLOC_BOUNDED | NDI_RA_ALLOC_PARTIAL_OK);
498510923SEvan.Yan@Sun.COM req.ra_boundbase = 0;
498610923SEvan.Yan@Sun.COM /*
498710923SEvan.Yan@Sun.COM * Note: To support a 32b system, boundlen and len need to be
498810923SEvan.Yan@Sun.COM * 32b quantities
498910923SEvan.Yan@Sun.COM */
499010923SEvan.Yan@Sun.COM req.ra_boundlen = PCICFG_4GIG_LIMIT + 1;
499110923SEvan.Yan@Sun.COM req.ra_len = PCICFG_4GIG_LIMIT + 1; /* Get as big as possible */
499210923SEvan.Yan@Sun.COM req.ra_align_mask =
499310923SEvan.Yan@Sun.COM PCICFG_MEMGRAN - 1; /* 1M alignment on memory space */
499410923SEvan.Yan@Sun.COM
499510923SEvan.Yan@Sun.COM rval = ndi_ra_alloc(ddi_get_parent(new_child), &req,
499610923SEvan.Yan@Sun.COM &mem_answer, &mem_alen, NDI_RA_TYPE_MEM, NDI_RA_PASS);
499710923SEvan.Yan@Sun.COM
499810923SEvan.Yan@Sun.COM if (rval != NDI_SUCCESS) {
499910923SEvan.Yan@Sun.COM if (rval == NDI_RA_PARTIAL_REQ) {
500010923SEvan.Yan@Sun.COM /*EMPTY*/
500110923SEvan.Yan@Sun.COM DEBUG0("NDI_RA_PARTIAL_REQ returned\n");
500210923SEvan.Yan@Sun.COM } else {
500310923SEvan.Yan@Sun.COM DEBUG0(
500410923SEvan.Yan@Sun.COM "Failed to allocate memory for bridge\n");
500510923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
500610923SEvan.Yan@Sun.COM }
500710923SEvan.Yan@Sun.COM }
500810923SEvan.Yan@Sun.COM
500910923SEvan.Yan@Sun.COM DEBUG3("Bridge Memory Allocated [0x%x.%x] len [0x%x]\n",
501010923SEvan.Yan@Sun.COM PCICFG_HIADDR(mem_answer),
501110923SEvan.Yan@Sun.COM PCICFG_LOADDR(mem_answer),
501210923SEvan.Yan@Sun.COM mem_alen);
501310923SEvan.Yan@Sun.COM
501410923SEvan.Yan@Sun.COM if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_MEM) == NDI_FAILURE) {
501510923SEvan.Yan@Sun.COM DEBUG0("Can not setup resource map - NDI_RA_TYPE_MEM\n");
501610923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
501710923SEvan.Yan@Sun.COM }
501810923SEvan.Yan@Sun.COM
501910923SEvan.Yan@Sun.COM /*
502010923SEvan.Yan@Sun.COM * Put available memory into the pool.
502110923SEvan.Yan@Sun.COM */
502210923SEvan.Yan@Sun.COM (void) ndi_ra_free(new_child, mem_answer, mem_alen, NDI_RA_TYPE_MEM,
502310923SEvan.Yan@Sun.COM NDI_RA_PASS);
502410923SEvan.Yan@Sun.COM
502510923SEvan.Yan@Sun.COM mem_base = mem_answer;
502610923SEvan.Yan@Sun.COM
502710923SEvan.Yan@Sun.COM /*
502810923SEvan.Yan@Sun.COM * Allocate I/O Space for Bridge
502910923SEvan.Yan@Sun.COM */
503010923SEvan.Yan@Sun.COM bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
503110923SEvan.Yan@Sun.COM req.ra_align_mask = PCICFG_IOGRAN - 1; /* 4k alignment */
503210923SEvan.Yan@Sun.COM req.ra_boundbase = 0;
503310923SEvan.Yan@Sun.COM req.ra_boundlen = PCICFG_4GIG_LIMIT;
503410923SEvan.Yan@Sun.COM req.ra_flags = (NDI_RA_ALLOC_BOUNDED | NDI_RA_ALLOC_PARTIAL_OK);
503510923SEvan.Yan@Sun.COM req.ra_len = PCICFG_4GIG_LIMIT; /* Get as big as possible */
503610923SEvan.Yan@Sun.COM
503710923SEvan.Yan@Sun.COM rval = ndi_ra_alloc(ddi_get_parent(new_child), &req, &io_answer,
503810923SEvan.Yan@Sun.COM &io_alen, NDI_RA_TYPE_IO, NDI_RA_PASS);
503910923SEvan.Yan@Sun.COM
504010923SEvan.Yan@Sun.COM if (rval != NDI_SUCCESS) {
504110923SEvan.Yan@Sun.COM if (rval == NDI_RA_PARTIAL_REQ) {
504210923SEvan.Yan@Sun.COM /*EMPTY*/
504310923SEvan.Yan@Sun.COM DEBUG0("NDI_RA_PARTIAL_REQ returned\n");
504410923SEvan.Yan@Sun.COM } else {
504510923SEvan.Yan@Sun.COM DEBUG0("Failed to allocate io space for bridge\n");
504610923SEvan.Yan@Sun.COM io_base = io_answer = io_alen = 0;
504710923SEvan.Yan@Sun.COM /* return (PCICFG_FAILURE); */
504810923SEvan.Yan@Sun.COM }
504910923SEvan.Yan@Sun.COM }
505010923SEvan.Yan@Sun.COM
505110923SEvan.Yan@Sun.COM if (io_alen) {
505210923SEvan.Yan@Sun.COM DEBUG3("Bridge IO Space Allocated [0x%x.%x] len [0x%x]\n",
505310923SEvan.Yan@Sun.COM PCICFG_HIADDR(io_answer), PCICFG_LOADDR(io_answer),
505410923SEvan.Yan@Sun.COM io_alen);
505510923SEvan.Yan@Sun.COM
505610923SEvan.Yan@Sun.COM if (ndi_ra_map_setup(new_child, NDI_RA_TYPE_IO) ==
505710923SEvan.Yan@Sun.COM NDI_FAILURE) {
505810923SEvan.Yan@Sun.COM DEBUG0("Can not setup resource map - NDI_RA_TYPE_IO\n");
505910923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
506010923SEvan.Yan@Sun.COM }
506110923SEvan.Yan@Sun.COM
506210923SEvan.Yan@Sun.COM /*
506310923SEvan.Yan@Sun.COM * Put available I/O into the pool.
506410923SEvan.Yan@Sun.COM */
506510923SEvan.Yan@Sun.COM (void) ndi_ra_free(new_child, io_answer, io_alen,
506610923SEvan.Yan@Sun.COM NDI_RA_TYPE_IO, NDI_RA_PASS);
506710923SEvan.Yan@Sun.COM io_base = io_answer;
506810923SEvan.Yan@Sun.COM }
506910923SEvan.Yan@Sun.COM
507010923SEvan.Yan@Sun.COM pcicfg_set_bus_numbers(h, bus, new_bus, max_bus);
507110923SEvan.Yan@Sun.COM
507210923SEvan.Yan@Sun.COM /*
507310923SEvan.Yan@Sun.COM * Setup "bus-range" property before onlining the bridge.
507410923SEvan.Yan@Sun.COM */
507510923SEvan.Yan@Sun.COM bus_range[0] = new_bus;
507610923SEvan.Yan@Sun.COM bus_range[1] = max_bus;
507710923SEvan.Yan@Sun.COM
507810923SEvan.Yan@Sun.COM if (ndi_prop_update_int_array(DDI_DEV_T_NONE, new_child,
507910923SEvan.Yan@Sun.COM "bus-range", bus_range, 2) != DDI_SUCCESS) {
508010923SEvan.Yan@Sun.COM DEBUG0("Failed to set bus-range property");
508110923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
508210923SEvan.Yan@Sun.COM }
508310923SEvan.Yan@Sun.COM
508410923SEvan.Yan@Sun.COM /*
508510923SEvan.Yan@Sun.COM * Reset the secondary bus
508610923SEvan.Yan@Sun.COM */
508710923SEvan.Yan@Sun.COM pci_config_put16(h, PCI_BCNF_BCNTRL,
508810923SEvan.Yan@Sun.COM pci_config_get16(h, PCI_BCNF_BCNTRL) | 0x40);
508910923SEvan.Yan@Sun.COM
509010923SEvan.Yan@Sun.COM drv_usecwait(100);
509110923SEvan.Yan@Sun.COM
509210923SEvan.Yan@Sun.COM pci_config_put16(h, PCI_BCNF_BCNTRL,
509310923SEvan.Yan@Sun.COM pci_config_get16(h, PCI_BCNF_BCNTRL) & ~0x40);
509410923SEvan.Yan@Sun.COM
509510923SEvan.Yan@Sun.COM /*
509610923SEvan.Yan@Sun.COM * Program the memory base register with the
509710923SEvan.Yan@Sun.COM * start of the memory range
509810923SEvan.Yan@Sun.COM */
509910923SEvan.Yan@Sun.COM pci_config_put16(h, PCI_BCNF_MEM_BASE,
510010923SEvan.Yan@Sun.COM PCICFG_HIWORD(PCICFG_LOADDR(mem_answer)));
510110923SEvan.Yan@Sun.COM
510210923SEvan.Yan@Sun.COM /*
510310923SEvan.Yan@Sun.COM * Program the memory limit register with the
510410923SEvan.Yan@Sun.COM * end of the memory range.
510510923SEvan.Yan@Sun.COM */
510610923SEvan.Yan@Sun.COM
510710923SEvan.Yan@Sun.COM pci_config_put16(h, PCI_BCNF_MEM_LIMIT,
510810923SEvan.Yan@Sun.COM PCICFG_HIWORD(PCICFG_LOADDR(
510910923SEvan.Yan@Sun.COM PCICFG_ROUND_DOWN((mem_answer + mem_alen), PCICFG_MEMGRAN) - 1)));
511010923SEvan.Yan@Sun.COM
511110923SEvan.Yan@Sun.COM /*
511210923SEvan.Yan@Sun.COM * Allocate the chunk of memory (if any) not programmed into the
511310923SEvan.Yan@Sun.COM * bridge because of the round down.
511410923SEvan.Yan@Sun.COM */
511510923SEvan.Yan@Sun.COM if (PCICFG_ROUND_DOWN((mem_answer + mem_alen), PCICFG_MEMGRAN)
511610923SEvan.Yan@Sun.COM != (mem_answer + mem_alen)) {
511710923SEvan.Yan@Sun.COM DEBUG0("Need to allocate Memory round off chunk\n");
511810923SEvan.Yan@Sun.COM bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
511910923SEvan.Yan@Sun.COM req.ra_flags = NDI_RA_ALLOC_SPECIFIED;
512010923SEvan.Yan@Sun.COM req.ra_addr = PCICFG_ROUND_DOWN((mem_answer + mem_alen),
512110923SEvan.Yan@Sun.COM PCICFG_MEMGRAN);
512210923SEvan.Yan@Sun.COM req.ra_len = (mem_answer + mem_alen) -
512310923SEvan.Yan@Sun.COM (PCICFG_ROUND_DOWN((mem_answer + mem_alen),
512410923SEvan.Yan@Sun.COM PCICFG_MEMGRAN));
512510923SEvan.Yan@Sun.COM
512610923SEvan.Yan@Sun.COM (void) ndi_ra_alloc(new_child, &req,
512710923SEvan.Yan@Sun.COM &round_answer, &round_len, NDI_RA_TYPE_MEM, NDI_RA_PASS);
512810923SEvan.Yan@Sun.COM }
512910923SEvan.Yan@Sun.COM
513010923SEvan.Yan@Sun.COM /*
513110923SEvan.Yan@Sun.COM * Program the I/O Space Base
513210923SEvan.Yan@Sun.COM */
513310923SEvan.Yan@Sun.COM pci_config_put8(h, PCI_BCNF_IO_BASE_LOW,
513410923SEvan.Yan@Sun.COM PCICFG_HIBYTE(PCICFG_LOWORD(
513510923SEvan.Yan@Sun.COM PCICFG_LOADDR(io_answer))));
513610923SEvan.Yan@Sun.COM
513710923SEvan.Yan@Sun.COM pci_config_put16(h, PCI_BCNF_IO_BASE_HI,
513810923SEvan.Yan@Sun.COM PCICFG_HIWORD(PCICFG_LOADDR(io_answer)));
513910923SEvan.Yan@Sun.COM
514010923SEvan.Yan@Sun.COM /*
514110923SEvan.Yan@Sun.COM * Program the I/O Space Limit
514210923SEvan.Yan@Sun.COM */
514310923SEvan.Yan@Sun.COM pci_config_put8(h, PCI_BCNF_IO_LIMIT_LOW,
514410923SEvan.Yan@Sun.COM PCICFG_HIBYTE(PCICFG_LOWORD(
514510923SEvan.Yan@Sun.COM PCICFG_LOADDR(PCICFG_ROUND_DOWN(io_answer + io_alen,
514610923SEvan.Yan@Sun.COM PCICFG_IOGRAN)))) - 1);
514710923SEvan.Yan@Sun.COM
514810923SEvan.Yan@Sun.COM pci_config_put16(h, PCI_BCNF_IO_LIMIT_HI,
514910923SEvan.Yan@Sun.COM PCICFG_HIWORD(PCICFG_LOADDR(
515010923SEvan.Yan@Sun.COM PCICFG_ROUND_DOWN(io_answer + io_alen, PCICFG_IOGRAN)))
515110923SEvan.Yan@Sun.COM - 1);
515210923SEvan.Yan@Sun.COM
515310923SEvan.Yan@Sun.COM /*
515410923SEvan.Yan@Sun.COM * Allocate the chunk of I/O (if any) not programmed into the
515510923SEvan.Yan@Sun.COM * bridge because of the round down.
515610923SEvan.Yan@Sun.COM */
515710923SEvan.Yan@Sun.COM if (PCICFG_ROUND_DOWN((io_answer + io_alen), PCICFG_IOGRAN)
515810923SEvan.Yan@Sun.COM != (io_answer + io_alen)) {
515910923SEvan.Yan@Sun.COM DEBUG0("Need to allocate I/O round off chunk\n");
516010923SEvan.Yan@Sun.COM bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
516110923SEvan.Yan@Sun.COM req.ra_flags = NDI_RA_ALLOC_SPECIFIED;
516210923SEvan.Yan@Sun.COM req.ra_addr = PCICFG_ROUND_DOWN((io_answer + io_alen),
516310923SEvan.Yan@Sun.COM PCICFG_IOGRAN);
516410923SEvan.Yan@Sun.COM req.ra_len = (io_answer + io_alen) -
516510923SEvan.Yan@Sun.COM (PCICFG_ROUND_DOWN((io_answer + io_alen),
516610923SEvan.Yan@Sun.COM PCICFG_IOGRAN));
516710923SEvan.Yan@Sun.COM
516810923SEvan.Yan@Sun.COM (void) ndi_ra_alloc(new_child, &req,
516910923SEvan.Yan@Sun.COM &round_answer, &round_len, NDI_RA_TYPE_IO, NDI_RA_PASS);
517010923SEvan.Yan@Sun.COM }
517110923SEvan.Yan@Sun.COM
517210923SEvan.Yan@Sun.COM /*
517310923SEvan.Yan@Sun.COM * Setup "ranges" property before onlining the bridge.
517410923SEvan.Yan@Sun.COM */
517510923SEvan.Yan@Sun.COM bzero((caddr_t)range, sizeof (pcicfg_range_t) * PCICFG_RANGE_LEN);
517610923SEvan.Yan@Sun.COM
517710923SEvan.Yan@Sun.COM range[0].child_hi = range[0].parent_hi |= (PCI_REG_REL_M | PCI_ADDR_IO);
517810923SEvan.Yan@Sun.COM range[0].child_lo = range[0].parent_lo = io_base;
517910923SEvan.Yan@Sun.COM range[1].child_hi = range[1].parent_hi |=
518010923SEvan.Yan@Sun.COM (PCI_REG_REL_M | PCI_ADDR_MEM32);
518110923SEvan.Yan@Sun.COM range[1].child_lo = range[1].parent_lo = mem_base;
518210923SEvan.Yan@Sun.COM
518310923SEvan.Yan@Sun.COM range[0].size_lo = io_alen;
518410923SEvan.Yan@Sun.COM if (pcicfg_update_ranges_prop(new_child, &range[0])) {
518510923SEvan.Yan@Sun.COM DEBUG0("Failed to update ranges (io)\n");
518610923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
518710923SEvan.Yan@Sun.COM }
518810923SEvan.Yan@Sun.COM range[1].size_lo = mem_alen;
518910923SEvan.Yan@Sun.COM if (pcicfg_update_ranges_prop(new_child, &range[1])) {
519010923SEvan.Yan@Sun.COM DEBUG0("Failed to update ranges (memory)\n");
519110923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
519210923SEvan.Yan@Sun.COM }
519310923SEvan.Yan@Sun.COM
519410923SEvan.Yan@Sun.COM /*
519510923SEvan.Yan@Sun.COM * Clear status bits
519610923SEvan.Yan@Sun.COM */
519710923SEvan.Yan@Sun.COM pci_config_put16(h, PCI_BCNF_SEC_STATUS, 0xffff);
519810923SEvan.Yan@Sun.COM
519910923SEvan.Yan@Sun.COM /*
520010923SEvan.Yan@Sun.COM * Turn off prefetchable range
520110923SEvan.Yan@Sun.COM */
520210923SEvan.Yan@Sun.COM pci_config_put32(h, PCI_BCNF_PF_BASE_LOW, 0x0000ffff);
520310923SEvan.Yan@Sun.COM pci_config_put32(h, PCI_BCNF_PF_BASE_HIGH, 0xffffffff);
520410923SEvan.Yan@Sun.COM pci_config_put32(h, PCI_BCNF_PF_LIMIT_HIGH, 0x0);
520510923SEvan.Yan@Sun.COM
520610923SEvan.Yan@Sun.COM /*
520710923SEvan.Yan@Sun.COM * Needs to be set to this value
520810923SEvan.Yan@Sun.COM */
520910923SEvan.Yan@Sun.COM pci_config_put8(h, PCI_CONF_ILINE, 0xf);
521010923SEvan.Yan@Sun.COM
521110923SEvan.Yan@Sun.COM /* check our device_type as defined by Open Firmware */
521210923SEvan.Yan@Sun.COM if (pcicfg_pcie_device_type(new_child, h) == DDI_SUCCESS)
521310923SEvan.Yan@Sun.COM pcie_device_type = 1;
521410923SEvan.Yan@Sun.COM
521510923SEvan.Yan@Sun.COM /*
521610923SEvan.Yan@Sun.COM * Set bus properties
521710923SEvan.Yan@Sun.COM */
521810923SEvan.Yan@Sun.COM if (pcicfg_set_busnode_props(new_child, pcie_device_type,
521910923SEvan.Yan@Sun.COM (int)bus, (int)new_bus) != PCICFG_SUCCESS) {
522010923SEvan.Yan@Sun.COM DEBUG0("Failed to set busnode props\n");
522110923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
522210923SEvan.Yan@Sun.COM }
522310923SEvan.Yan@Sun.COM
522410923SEvan.Yan@Sun.COM (void) pcicfg_device_on(h);
522510923SEvan.Yan@Sun.COM
522611245SZhijun.Fu@Sun.COM if (is_pcie)
522711387SSurya.Prakki@Sun.COM (void) pcie_init_bus(new_child, 0, PCIE_BUS_FINAL);
522810923SEvan.Yan@Sun.COM if (ndi_devi_online(new_child, NDI_NO_EVENT|NDI_CONFIG)
522910923SEvan.Yan@Sun.COM != NDI_SUCCESS) {
523010923SEvan.Yan@Sun.COM DEBUG0("Unable to online bridge\n");
523110923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
523210923SEvan.Yan@Sun.COM }
523310923SEvan.Yan@Sun.COM
523410923SEvan.Yan@Sun.COM DEBUG0("Bridge is ONLINE\n");
523510923SEvan.Yan@Sun.COM
523610923SEvan.Yan@Sun.COM /*
523710923SEvan.Yan@Sun.COM * After a Reset, we need to wait 2^25 clock cycles before the
523810923SEvan.Yan@Sun.COM * first Configuration access. The worst case is 33MHz, which
523910923SEvan.Yan@Sun.COM * is a 1 second wait.
524010923SEvan.Yan@Sun.COM */
524110923SEvan.Yan@Sun.COM drv_usecwait(pcicfg_sec_reset_delay);
524210923SEvan.Yan@Sun.COM
524310923SEvan.Yan@Sun.COM /*
524410923SEvan.Yan@Sun.COM * Probe all children devices
524510923SEvan.Yan@Sun.COM */
524610923SEvan.Yan@Sun.COM DEBUG0("Bridge Programming Complete - probe children\n");
524710923SEvan.Yan@Sun.COM ndi_devi_enter(new_child, &count);
524810923SEvan.Yan@Sun.COM for (i = 0; ((i < PCICFG_MAX_DEVICE) && (ari_mode == B_FALSE));
524910923SEvan.Yan@Sun.COM i++) {
525010923SEvan.Yan@Sun.COM for (j = 0; j < max_function; ) {
525110923SEvan.Yan@Sun.COM if (ari_mode)
525210923SEvan.Yan@Sun.COM trans_device = j >> 3;
525310923SEvan.Yan@Sun.COM else
525410923SEvan.Yan@Sun.COM trans_device = i;
525510923SEvan.Yan@Sun.COM
525610923SEvan.Yan@Sun.COM if ((rval = pcicfg_fcode_probe(new_child,
525711245SZhijun.Fu@Sun.COM new_bus, trans_device, (j & 7), highest_bus,
525811245SZhijun.Fu@Sun.COM 0, is_pcie))
525910923SEvan.Yan@Sun.COM != PCICFG_SUCCESS) {
526010923SEvan.Yan@Sun.COM if (rval == PCICFG_NODEVICE) {
526110923SEvan.Yan@Sun.COM DEBUG3("No Device at bus [0x%x]"
526210923SEvan.Yan@Sun.COM "device [0x%x] "
526310923SEvan.Yan@Sun.COM "func [0x%x]\n", new_bus,
526410923SEvan.Yan@Sun.COM trans_device, j & 7);
526510923SEvan.Yan@Sun.COM
526610923SEvan.Yan@Sun.COM if (j)
526710923SEvan.Yan@Sun.COM goto next;
526810923SEvan.Yan@Sun.COM } else {
526910923SEvan.Yan@Sun.COM DEBUG3("Failed to configure bus "
527010923SEvan.Yan@Sun.COM "[0x%x] device [0x%x] "
527110923SEvan.Yan@Sun.COM "func [0x%x]\n", new_bus,
527210923SEvan.Yan@Sun.COM trans_device, j & 7);
527310923SEvan.Yan@Sun.COM
527410923SEvan.Yan@Sun.COM rval = PCICFG_FAILURE;
527510923SEvan.Yan@Sun.COM }
527610923SEvan.Yan@Sun.COM break;
527710923SEvan.Yan@Sun.COM }
527810923SEvan.Yan@Sun.COM next:
527910923SEvan.Yan@Sun.COM new_device = pcicfg_devi_find(new_child,
528010923SEvan.Yan@Sun.COM trans_device, (j & 7));
528110923SEvan.Yan@Sun.COM
528210923SEvan.Yan@Sun.COM /*
528310923SEvan.Yan@Sun.COM * Determine if ARI Forwarding should be enabled.
528410923SEvan.Yan@Sun.COM */
528510923SEvan.Yan@Sun.COM if (j == 0) {
528610923SEvan.Yan@Sun.COM if (new_device == NULL)
528710923SEvan.Yan@Sun.COM break;
528810923SEvan.Yan@Sun.COM
528910923SEvan.Yan@Sun.COM if ((pcie_ari_supported(new_child) ==
529010923SEvan.Yan@Sun.COM PCIE_ARI_FORW_ENABLED) &&
529110923SEvan.Yan@Sun.COM (pcie_ari_device(new_device) ==
529210923SEvan.Yan@Sun.COM PCIE_ARI_DEVICE)) {
529310923SEvan.Yan@Sun.COM if (pcie_ari_enable(new_child) ==
529410923SEvan.Yan@Sun.COM DDI_SUCCESS) {
529510923SEvan.Yan@Sun.COM (void) ddi_prop_create(
529610923SEvan.Yan@Sun.COM DDI_DEV_T_NONE,
529710923SEvan.Yan@Sun.COM new_child,
529810923SEvan.Yan@Sun.COM DDI_PROP_CANSLEEP,
529910923SEvan.Yan@Sun.COM "ari-enabled", NULL, 0);
530010923SEvan.Yan@Sun.COM ari_mode = B_TRUE;
530110923SEvan.Yan@Sun.COM max_function =
530210923SEvan.Yan@Sun.COM PCICFG_MAX_ARI_FUNCTION;
530310923SEvan.Yan@Sun.COM }
530410923SEvan.Yan@Sun.COM }
530510923SEvan.Yan@Sun.COM }
530610923SEvan.Yan@Sun.COM
530710923SEvan.Yan@Sun.COM if (ari_mode == B_TRUE) {
530810923SEvan.Yan@Sun.COM int next_function;
530910923SEvan.Yan@Sun.COM
531010923SEvan.Yan@Sun.COM if (new_device == NULL)
531110923SEvan.Yan@Sun.COM break;
531210923SEvan.Yan@Sun.COM
531310923SEvan.Yan@Sun.COM if (pcie_ari_get_next_function(new_device,
531410923SEvan.Yan@Sun.COM &next_function) != DDI_SUCCESS)
531510923SEvan.Yan@Sun.COM break;
531610923SEvan.Yan@Sun.COM
531710923SEvan.Yan@Sun.COM j = next_function;
531810923SEvan.Yan@Sun.COM
531910923SEvan.Yan@Sun.COM if (next_function == 0)
532010923SEvan.Yan@Sun.COM break;
532110923SEvan.Yan@Sun.COM } else
532210923SEvan.Yan@Sun.COM j++;
532310923SEvan.Yan@Sun.COM }
532410923SEvan.Yan@Sun.COM }
532510923SEvan.Yan@Sun.COM
532610923SEvan.Yan@Sun.COM ndi_devi_exit(new_child, count);
532710923SEvan.Yan@Sun.COM
532810923SEvan.Yan@Sun.COM /* if empty topology underneath, it is still a success. */
532910923SEvan.Yan@Sun.COM if (rval != PCICFG_FAILURE)
533010923SEvan.Yan@Sun.COM rval = PCICFG_SUCCESS;
533110923SEvan.Yan@Sun.COM
533210923SEvan.Yan@Sun.COM /*
533310923SEvan.Yan@Sun.COM * Offline the bridge to allow reprogramming of resources.
533410923SEvan.Yan@Sun.COM *
533510923SEvan.Yan@Sun.COM * This should always succeed since nobody else has started to
533610923SEvan.Yan@Sun.COM * use it yet, failing to detach the driver would indicate a bug.
533710923SEvan.Yan@Sun.COM * Also in that case it's better just panic than allowing the
533810923SEvan.Yan@Sun.COM * configurator to proceed with BAR reprogramming without bridge
533910923SEvan.Yan@Sun.COM * driver detached.
534010923SEvan.Yan@Sun.COM */
534110923SEvan.Yan@Sun.COM VERIFY(ndi_devi_offline(new_child, NDI_NO_EVENT|NDI_UNCONFIG)
534210923SEvan.Yan@Sun.COM == NDI_SUCCESS);
534311245SZhijun.Fu@Sun.COM if (is_pcie)
534411245SZhijun.Fu@Sun.COM pcie_fini_bus(new_child, PCIE_BUS_INITIAL);
534510923SEvan.Yan@Sun.COM
534610923SEvan.Yan@Sun.COM phdl.dip = new_child;
534710923SEvan.Yan@Sun.COM phdl.memory_base = mem_answer;
534810923SEvan.Yan@Sun.COM phdl.io_base = (uint32_t)io_answer;
534910923SEvan.Yan@Sun.COM phdl.error = PCICFG_SUCCESS; /* in case of empty child tree */
535010923SEvan.Yan@Sun.COM
535110923SEvan.Yan@Sun.COM ndi_devi_enter(ddi_get_parent(new_child), &count);
535210923SEvan.Yan@Sun.COM ddi_walk_devs(new_child, pcicfg_find_resource_end, (void *)&phdl);
535310923SEvan.Yan@Sun.COM ndi_devi_exit(ddi_get_parent(new_child), count);
535410923SEvan.Yan@Sun.COM
535510923SEvan.Yan@Sun.COM if (phdl.error != PCICFG_SUCCESS) {
535610923SEvan.Yan@Sun.COM DEBUG0("Failure summing resources\n");
535710923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
535810923SEvan.Yan@Sun.COM }
535910923SEvan.Yan@Sun.COM
536010923SEvan.Yan@Sun.COM num_slots = pcicfg_get_nslots(new_child, h);
536110923SEvan.Yan@Sun.COM mem_end = PCICFG_ROUND_UP(phdl.memory_base, PCICFG_MEMGRAN);
536210923SEvan.Yan@Sun.COM io_end = PCICFG_ROUND_UP(phdl.io_base, PCICFG_IOGRAN);
536310923SEvan.Yan@Sun.COM
536410923SEvan.Yan@Sun.COM DEBUG3("Start of Unallocated Bridge(%d slots) Resources "
536510923SEvan.Yan@Sun.COM "Mem=0x%lx I/O=0x%lx\n", num_slots, mem_end, io_end);
536610923SEvan.Yan@Sun.COM
536710923SEvan.Yan@Sun.COM /*
536810923SEvan.Yan@Sun.COM * Before probing the children we've allocated maximum MEM/IO
536910923SEvan.Yan@Sun.COM * resources from parent, and updated "available" property
537010923SEvan.Yan@Sun.COM * accordingly. Later we'll be giving up unused resources to
537110923SEvan.Yan@Sun.COM * the parent, thus we need to destroy "available" property
537210923SEvan.Yan@Sun.COM * here otherwise it will be out-of-sync with the actual free
537310923SEvan.Yan@Sun.COM * resources this bridge has. This property will be rebuilt below
537410923SEvan.Yan@Sun.COM * with the actual free resources reserved for hotplug slots
537510923SEvan.Yan@Sun.COM * (if any).
537610923SEvan.Yan@Sun.COM */
537710923SEvan.Yan@Sun.COM (void) ndi_prop_remove(DDI_DEV_T_NONE, new_child, "available");
537810923SEvan.Yan@Sun.COM /*
537910923SEvan.Yan@Sun.COM * if the bridge a slots, then preallocate. If not, assume static
538010923SEvan.Yan@Sun.COM * configuration. Also check for preallocation limits and spit
538110923SEvan.Yan@Sun.COM * warning messages appropriately (perhaps some can be in debug mode).
538210923SEvan.Yan@Sun.COM */
538310923SEvan.Yan@Sun.COM if (num_slots) {
538410923SEvan.Yan@Sun.COM pci_regspec_t reg;
538510923SEvan.Yan@Sun.COM uint64_t mem_assigned = mem_end;
538610923SEvan.Yan@Sun.COM uint64_t io_assigned = io_end;
538710923SEvan.Yan@Sun.COM uint64_t mem_reqd = mem_answer + (num_slots *
538810923SEvan.Yan@Sun.COM pcicfg_slot_memsize);
538910923SEvan.Yan@Sun.COM uint64_t io_reqd = io_answer + (num_slots *
539010923SEvan.Yan@Sun.COM pcicfg_slot_iosize);
539110923SEvan.Yan@Sun.COM uint8_t highest_bus_reqd = new_bus + (num_slots *
539210923SEvan.Yan@Sun.COM pcicfg_slot_busnums);
539310923SEvan.Yan@Sun.COM #ifdef DEBUG
539410923SEvan.Yan@Sun.COM if (mem_end > mem_reqd)
539510923SEvan.Yan@Sun.COM DEBUG3("Memory space consumed by bridge"
539610923SEvan.Yan@Sun.COM " more than planned for %d slot(s)(%lx, %lx)",
539710923SEvan.Yan@Sun.COM num_slots, mem_answer, mem_end);
539810923SEvan.Yan@Sun.COM if (io_end > io_reqd)
539910923SEvan.Yan@Sun.COM DEBUG3("IO space consumed by bridge"
540010923SEvan.Yan@Sun.COM " more than planned for %d slot(s)(%lx, %lx)",
540110923SEvan.Yan@Sun.COM num_slots, io_answer, io_end);
540210923SEvan.Yan@Sun.COM if (*highest_bus > highest_bus_reqd)
540310923SEvan.Yan@Sun.COM DEBUG3("Buses consumed by bridge"
540410923SEvan.Yan@Sun.COM " more than planned for %d slot(s)(%x, %x)",
540510923SEvan.Yan@Sun.COM num_slots, new_bus, *highest_bus);
540610923SEvan.Yan@Sun.COM
540710923SEvan.Yan@Sun.COM if (mem_reqd > (mem_answer + mem_alen))
540810923SEvan.Yan@Sun.COM DEBUG3("Memory space required by bridge"
540910923SEvan.Yan@Sun.COM " more than available for %d slot(s)(%lx, %lx)",
541010923SEvan.Yan@Sun.COM num_slots, mem_answer, mem_end);
541110923SEvan.Yan@Sun.COM
541210923SEvan.Yan@Sun.COM if (io_reqd > (io_answer + io_alen))
541310923SEvan.Yan@Sun.COM DEBUG3("IO space required by bridge"
541410923SEvan.Yan@Sun.COM " more than available for %d slot(s)(%lx, %lx)",
541510923SEvan.Yan@Sun.COM num_slots, io_answer, io_end);
541610923SEvan.Yan@Sun.COM if (highest_bus_reqd > max_bus)
541710923SEvan.Yan@Sun.COM DEBUG3("Bus numbers required by bridge"
541810923SEvan.Yan@Sun.COM " more than available for %d slot(s)(%x, %x)",
541910923SEvan.Yan@Sun.COM num_slots, new_bus, *highest_bus);
542010923SEvan.Yan@Sun.COM #endif
542110923SEvan.Yan@Sun.COM mem_end = MAX((MIN(mem_reqd, (mem_answer + mem_alen))),
542210923SEvan.Yan@Sun.COM mem_end);
542310923SEvan.Yan@Sun.COM io_end = MAX((MIN(io_reqd, (io_answer + io_alen))), io_end);
542410923SEvan.Yan@Sun.COM *highest_bus = MAX((MIN(highest_bus_reqd, max_bus)),
542510923SEvan.Yan@Sun.COM *highest_bus);
542610923SEvan.Yan@Sun.COM DEBUG3("mem_end %lx, io_end %lx, highest_bus %x\n",
542710923SEvan.Yan@Sun.COM mem_end, io_end, *highest_bus);
542810923SEvan.Yan@Sun.COM
542910923SEvan.Yan@Sun.COM mem_size = mem_end - mem_assigned;
543010923SEvan.Yan@Sun.COM io_size = io_end - io_assigned;
543110923SEvan.Yan@Sun.COM
543210923SEvan.Yan@Sun.COM reg.pci_phys_mid = reg.pci_size_hi = 0;
543310923SEvan.Yan@Sun.COM if (io_size > 0) {
543410923SEvan.Yan@Sun.COM reg.pci_phys_hi = (PCI_REG_REL_M | PCI_ADDR_IO);
543510923SEvan.Yan@Sun.COM reg.pci_phys_low = io_assigned;
543610923SEvan.Yan@Sun.COM reg.pci_size_low = io_size;
543710923SEvan.Yan@Sun.COM if (pcicfg_update_available_prop(new_child, ®)) {
543810923SEvan.Yan@Sun.COM DEBUG0("Failed to update available prop "
543910923SEvan.Yan@Sun.COM "(io)\n");
544010923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
544110923SEvan.Yan@Sun.COM }
544210923SEvan.Yan@Sun.COM }
544310923SEvan.Yan@Sun.COM if (mem_size > 0) {
544410923SEvan.Yan@Sun.COM reg.pci_phys_hi = (PCI_REG_REL_M | PCI_ADDR_MEM32);
544510923SEvan.Yan@Sun.COM reg.pci_phys_low = mem_assigned;
544610923SEvan.Yan@Sun.COM reg.pci_size_low = mem_size;
544710923SEvan.Yan@Sun.COM if (pcicfg_update_available_prop(new_child, ®)) {
544810923SEvan.Yan@Sun.COM DEBUG0("Failed to update available prop "
544910923SEvan.Yan@Sun.COM "(memory)\n");
545010923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
545110923SEvan.Yan@Sun.COM }
545210923SEvan.Yan@Sun.COM }
545310923SEvan.Yan@Sun.COM }
545410923SEvan.Yan@Sun.COM
545510923SEvan.Yan@Sun.COM /*
545610923SEvan.Yan@Sun.COM * Give back unused memory space to parent.
545710923SEvan.Yan@Sun.COM */
545810923SEvan.Yan@Sun.COM (void) ndi_ra_free(ddi_get_parent(new_child),
545910923SEvan.Yan@Sun.COM mem_end, (mem_answer + mem_alen) - mem_end, NDI_RA_TYPE_MEM,
546010923SEvan.Yan@Sun.COM NDI_RA_PASS);
546110923SEvan.Yan@Sun.COM
546210923SEvan.Yan@Sun.COM if (mem_end == mem_answer) {
546310923SEvan.Yan@Sun.COM DEBUG0("No memory resources used\n");
546410923SEvan.Yan@Sun.COM /*
546510923SEvan.Yan@Sun.COM * To prevent the bridge from forwarding any Memory
546610923SEvan.Yan@Sun.COM * transactions, the Memory Limit will be programmed
546710923SEvan.Yan@Sun.COM * with a smaller value than the Memory Base.
546810923SEvan.Yan@Sun.COM */
546910923SEvan.Yan@Sun.COM pci_config_put16(h, PCI_BCNF_MEM_BASE, 0xffff);
547010923SEvan.Yan@Sun.COM pci_config_put16(h, PCI_BCNF_MEM_LIMIT, 0);
547110923SEvan.Yan@Sun.COM
547210923SEvan.Yan@Sun.COM mem_size = 0;
547310923SEvan.Yan@Sun.COM } else {
547410923SEvan.Yan@Sun.COM /*
547510923SEvan.Yan@Sun.COM * Reprogram the end of the memory.
547610923SEvan.Yan@Sun.COM */
547710923SEvan.Yan@Sun.COM pci_config_put16(h, PCI_BCNF_MEM_LIMIT,
547810923SEvan.Yan@Sun.COM PCICFG_HIWORD(mem_end) - 1);
547910923SEvan.Yan@Sun.COM mem_size = mem_end - mem_base;
548010923SEvan.Yan@Sun.COM }
548110923SEvan.Yan@Sun.COM
548210923SEvan.Yan@Sun.COM /*
548310923SEvan.Yan@Sun.COM * Give back unused io space to parent.
548410923SEvan.Yan@Sun.COM */
548510923SEvan.Yan@Sun.COM (void) ndi_ra_free(ddi_get_parent(new_child),
548610923SEvan.Yan@Sun.COM io_end, (io_answer + io_alen) - io_end,
548710923SEvan.Yan@Sun.COM NDI_RA_TYPE_IO, NDI_RA_PASS);
548810923SEvan.Yan@Sun.COM
548910923SEvan.Yan@Sun.COM if (io_end == io_answer) {
549010923SEvan.Yan@Sun.COM DEBUG0("No IO Space resources used\n");
549110923SEvan.Yan@Sun.COM
549210923SEvan.Yan@Sun.COM /*
549310923SEvan.Yan@Sun.COM * To prevent the bridge from forwarding any I/O
549410923SEvan.Yan@Sun.COM * transactions, the I/O Limit will be programmed
549510923SEvan.Yan@Sun.COM * with a smaller value than the I/O Base.
549610923SEvan.Yan@Sun.COM */
549710923SEvan.Yan@Sun.COM pci_config_put8(h, PCI_BCNF_IO_LIMIT_LOW, 0);
549810923SEvan.Yan@Sun.COM pci_config_put16(h, PCI_BCNF_IO_LIMIT_HI, 0);
549910923SEvan.Yan@Sun.COM pci_config_put8(h, PCI_BCNF_IO_BASE_LOW, 0xff);
550010923SEvan.Yan@Sun.COM pci_config_put16(h, PCI_BCNF_IO_BASE_HI, 0);
550110923SEvan.Yan@Sun.COM
550210923SEvan.Yan@Sun.COM io_size = 0;
550310923SEvan.Yan@Sun.COM } else {
550410923SEvan.Yan@Sun.COM /*
550510923SEvan.Yan@Sun.COM * Reprogram the end of the io space.
550610923SEvan.Yan@Sun.COM */
550710923SEvan.Yan@Sun.COM pci_config_put8(h, PCI_BCNF_IO_LIMIT_LOW,
550810923SEvan.Yan@Sun.COM PCICFG_HIBYTE(PCICFG_LOWORD(
550910923SEvan.Yan@Sun.COM PCICFG_LOADDR(io_end) - 1)));
551010923SEvan.Yan@Sun.COM
551110923SEvan.Yan@Sun.COM pci_config_put16(h, PCI_BCNF_IO_LIMIT_HI,
551210923SEvan.Yan@Sun.COM PCICFG_HIWORD(PCICFG_LOADDR(io_end - 1)));
551310923SEvan.Yan@Sun.COM
551410923SEvan.Yan@Sun.COM io_size = io_end - io_base;
551510923SEvan.Yan@Sun.COM }
551610923SEvan.Yan@Sun.COM
551710923SEvan.Yan@Sun.COM if ((max_bus - *highest_bus) > 0) {
551810923SEvan.Yan@Sun.COM /*
551910923SEvan.Yan@Sun.COM * Give back unused bus numbers
552010923SEvan.Yan@Sun.COM */
552110923SEvan.Yan@Sun.COM (void) ndi_ra_free(ddi_get_parent(new_child),
552210923SEvan.Yan@Sun.COM *highest_bus+1, max_bus - *highest_bus,
552310923SEvan.Yan@Sun.COM NDI_RA_TYPE_PCI_BUSNUM, NDI_RA_PASS);
552410923SEvan.Yan@Sun.COM }
552510923SEvan.Yan@Sun.COM
552610923SEvan.Yan@Sun.COM /*
552710923SEvan.Yan@Sun.COM * Set bus numbers to ranges encountered during scan
552810923SEvan.Yan@Sun.COM */
552910923SEvan.Yan@Sun.COM pcicfg_set_bus_numbers(h, bus, new_bus, *highest_bus);
553010923SEvan.Yan@Sun.COM
553110923SEvan.Yan@Sun.COM bus_range[0] = pci_config_get8(h, PCI_BCNF_SECBUS);
553210923SEvan.Yan@Sun.COM bus_range[1] = pci_config_get8(h, PCI_BCNF_SUBBUS);
553310923SEvan.Yan@Sun.COM DEBUG1("End of bridge probe: bus_range[0] = %d\n", bus_range[0]);
553410923SEvan.Yan@Sun.COM DEBUG1("End of bridge probe: bus_range[1] = %d\n", bus_range[1]);
553510923SEvan.Yan@Sun.COM
553610923SEvan.Yan@Sun.COM if (ndi_prop_update_int_array(DDI_DEV_T_NONE, new_child,
553710923SEvan.Yan@Sun.COM "bus-range", bus_range, 2) != DDI_SUCCESS) {
553810923SEvan.Yan@Sun.COM DEBUG0("Failed to set bus-range property");
553910923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
554010923SEvan.Yan@Sun.COM }
554110923SEvan.Yan@Sun.COM
554210923SEvan.Yan@Sun.COM /*
554310923SEvan.Yan@Sun.COM * Remove the ranges property if it exists since we will create
554410923SEvan.Yan@Sun.COM * a new one.
554510923SEvan.Yan@Sun.COM */
554610923SEvan.Yan@Sun.COM (void) ndi_prop_remove(DDI_DEV_T_NONE, new_child, "ranges");
554710923SEvan.Yan@Sun.COM
554810923SEvan.Yan@Sun.COM DEBUG2("Creating Ranges property - Mem Address %lx Mem Size %x\n",
554910923SEvan.Yan@Sun.COM mem_base, mem_size);
555010923SEvan.Yan@Sun.COM DEBUG2(" - I/O Address %lx I/O Size %x\n",
555110923SEvan.Yan@Sun.COM io_base, io_size);
555210923SEvan.Yan@Sun.COM
555310923SEvan.Yan@Sun.COM bzero((caddr_t)range, sizeof (pcicfg_range_t) * PCICFG_RANGE_LEN);
555410923SEvan.Yan@Sun.COM
555510923SEvan.Yan@Sun.COM range[0].child_hi = range[0].parent_hi |= (PCI_REG_REL_M | PCI_ADDR_IO);
555610923SEvan.Yan@Sun.COM range[0].child_lo = range[0].parent_lo = io_base;
555710923SEvan.Yan@Sun.COM range[1].child_hi = range[1].parent_hi |=
555810923SEvan.Yan@Sun.COM (PCI_REG_REL_M | PCI_ADDR_MEM32);
555910923SEvan.Yan@Sun.COM range[1].child_lo = range[1].parent_lo = mem_base;
556010923SEvan.Yan@Sun.COM
556110923SEvan.Yan@Sun.COM if (io_size > 0) {
556210923SEvan.Yan@Sun.COM range[0].size_lo = io_size;
556310923SEvan.Yan@Sun.COM if (pcicfg_update_ranges_prop(new_child, &range[0])) {
556410923SEvan.Yan@Sun.COM DEBUG0("Failed to update ranges (io)\n");
556510923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
556610923SEvan.Yan@Sun.COM }
556710923SEvan.Yan@Sun.COM }
556810923SEvan.Yan@Sun.COM if (mem_size > 0) {
556910923SEvan.Yan@Sun.COM range[1].size_lo = mem_size;
557010923SEvan.Yan@Sun.COM if (pcicfg_update_ranges_prop(new_child, &range[1])) {
557110923SEvan.Yan@Sun.COM DEBUG0("Failed to update ranges (memory)\n");
557210923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
557310923SEvan.Yan@Sun.COM }
557410923SEvan.Yan@Sun.COM }
557510923SEvan.Yan@Sun.COM
557610923SEvan.Yan@Sun.COM /*
557710923SEvan.Yan@Sun.COM * Remove the resource maps for the bridge since we no longer
557810923SEvan.Yan@Sun.COM * need them. Note that the failure is ignored since the
557910923SEvan.Yan@Sun.COM * ndi_devi_offline above may have already taken care of it via
558010923SEvan.Yan@Sun.COM * driver detach.
558110923SEvan.Yan@Sun.COM * It has been checked that there are no other reasons for
558210923SEvan.Yan@Sun.COM * failure other than map itself being non-existent. So we are Ok.
558310923SEvan.Yan@Sun.COM */
558410923SEvan.Yan@Sun.COM if (ndi_ra_map_destroy(new_child, NDI_RA_TYPE_MEM) == NDI_FAILURE) {
558510923SEvan.Yan@Sun.COM /*EMPTY*/
558610923SEvan.Yan@Sun.COM DEBUG0("Can not destroy resource map - NDI_RA_TYPE_MEM\n");
558710923SEvan.Yan@Sun.COM }
558810923SEvan.Yan@Sun.COM
558910923SEvan.Yan@Sun.COM if (ndi_ra_map_destroy(new_child, NDI_RA_TYPE_IO) == NDI_FAILURE) {
559010923SEvan.Yan@Sun.COM /*EMPTY*/
559110923SEvan.Yan@Sun.COM DEBUG0("Can not destroy resource map - NDI_RA_TYPE_IO\n");
559210923SEvan.Yan@Sun.COM }
559310923SEvan.Yan@Sun.COM
559410923SEvan.Yan@Sun.COM if (ndi_ra_map_destroy(new_child, NDI_RA_TYPE_PCI_BUSNUM)
559510923SEvan.Yan@Sun.COM == NDI_FAILURE) {
559610923SEvan.Yan@Sun.COM /*EMPTY*/
559710923SEvan.Yan@Sun.COM DEBUG0("Can't destroy resource map - NDI_RA_TYPE_PCI_BUSNUM\n");
559810923SEvan.Yan@Sun.COM }
559910923SEvan.Yan@Sun.COM
560010923SEvan.Yan@Sun.COM return (rval);
560110923SEvan.Yan@Sun.COM }
560210923SEvan.Yan@Sun.COM
560310923SEvan.Yan@Sun.COM /*
560410923SEvan.Yan@Sun.COM * Return PCICFG_SUCCESS if device exists at the specified address.
560510923SEvan.Yan@Sun.COM * Return PCICFG_NODEVICE is no device exists at the specified address.
560610923SEvan.Yan@Sun.COM *
560710923SEvan.Yan@Sun.COM */
560810923SEvan.Yan@Sun.COM int
pcicfg_config_setup(dev_info_t * dip,ddi_acc_handle_t * handle)560910923SEvan.Yan@Sun.COM pcicfg_config_setup(dev_info_t *dip, ddi_acc_handle_t *handle)
561010923SEvan.Yan@Sun.COM {
561110923SEvan.Yan@Sun.COM caddr_t virt;
561210923SEvan.Yan@Sun.COM ddi_device_acc_attr_t attr;
561310923SEvan.Yan@Sun.COM int status;
561410923SEvan.Yan@Sun.COM int rlen;
561510923SEvan.Yan@Sun.COM pci_regspec_t *reg;
561610923SEvan.Yan@Sun.COM int ret = DDI_SUCCESS;
561710923SEvan.Yan@Sun.COM int16_t tmp;
561810923SEvan.Yan@Sun.COM /*
561910923SEvan.Yan@Sun.COM * flags = PCICFG_CONF_INDIRECT_MAP if configuration space is indirectly
562010923SEvan.Yan@Sun.COM * mapped, otherwise it is 0. "flags" is introduced in support of any
562110923SEvan.Yan@Sun.COM * non transparent bridges, where configuration space is indirectly
562210923SEvan.Yan@Sun.COM * mapped.
562310923SEvan.Yan@Sun.COM * Indirect mapping is always true on sun4v systems.
562410923SEvan.Yan@Sun.COM */
562510923SEvan.Yan@Sun.COM int flags = 0;
562610923SEvan.Yan@Sun.COM
562710923SEvan.Yan@Sun.COM
562810923SEvan.Yan@Sun.COM /*
562910923SEvan.Yan@Sun.COM * Get the pci register spec from the node
563010923SEvan.Yan@Sun.COM */
563110923SEvan.Yan@Sun.COM status = ddi_getlongprop(DDI_DEV_T_ANY,
563210923SEvan.Yan@Sun.COM dip, DDI_PROP_DONTPASS, "reg", (caddr_t)®, &rlen);
563310923SEvan.Yan@Sun.COM
563410923SEvan.Yan@Sun.COM switch (status) {
563510923SEvan.Yan@Sun.COM case DDI_PROP_SUCCESS:
563610923SEvan.Yan@Sun.COM break;
563710923SEvan.Yan@Sun.COM case DDI_PROP_NO_MEMORY:
563810923SEvan.Yan@Sun.COM DEBUG0("reg present, but unable to get memory\n");
563910923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
564010923SEvan.Yan@Sun.COM default:
564110923SEvan.Yan@Sun.COM DEBUG0("no reg property\n");
564210923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
564310923SEvan.Yan@Sun.COM }
564410923SEvan.Yan@Sun.COM
564510923SEvan.Yan@Sun.COM if (pcicfg_indirect_map(dip) == DDI_SUCCESS)
564610923SEvan.Yan@Sun.COM flags |= PCICFG_CONF_INDIRECT_MAP;
564710923SEvan.Yan@Sun.COM
564810923SEvan.Yan@Sun.COM /*
564910923SEvan.Yan@Sun.COM * Map in configuration space (temporarily)
565010923SEvan.Yan@Sun.COM */
565110923SEvan.Yan@Sun.COM attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
565210923SEvan.Yan@Sun.COM attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
565310923SEvan.Yan@Sun.COM attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
565410923SEvan.Yan@Sun.COM attr.devacc_attr_access = DDI_CAUTIOUS_ACC;
565510923SEvan.Yan@Sun.COM
565610923SEvan.Yan@Sun.COM #ifdef EFCODE21554
565710923SEvan.Yan@Sun.COM if (ddi_regs_map_setup(dip, 0, &virt,
565810923SEvan.Yan@Sun.COM 0, 0, &attr, handle) != DDI_SUCCESS)
565910923SEvan.Yan@Sun.COM #else
566010923SEvan.Yan@Sun.COM if (pcicfg_map_phys(dip, reg, &virt, &attr, handle)
566110923SEvan.Yan@Sun.COM != DDI_SUCCESS)
566210923SEvan.Yan@Sun.COM #endif
566310923SEvan.Yan@Sun.COM {
566410923SEvan.Yan@Sun.COM DEBUG0("pcicfg_config_setup():"
566510923SEvan.Yan@Sun.COM "Failed to setup config space\n");
566610923SEvan.Yan@Sun.COM
566710923SEvan.Yan@Sun.COM kmem_free((caddr_t)reg, rlen);
566810923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
566910923SEvan.Yan@Sun.COM }
567010923SEvan.Yan@Sun.COM
567110923SEvan.Yan@Sun.COM if (flags & PCICFG_CONF_INDIRECT_MAP) {
567210923SEvan.Yan@Sun.COM /*
567310923SEvan.Yan@Sun.COM * need to use DDI interfaces as the conf space is
567410923SEvan.Yan@Sun.COM * cannot be directly accessed by the host.
567510923SEvan.Yan@Sun.COM */
567610923SEvan.Yan@Sun.COM tmp = (int16_t)ddi_get16(*handle, (uint16_t *)virt);
567710923SEvan.Yan@Sun.COM } else {
567810923SEvan.Yan@Sun.COM ret = ddi_peek16(dip, (int16_t *)virt, &tmp);
567910923SEvan.Yan@Sun.COM }
568010923SEvan.Yan@Sun.COM
568110923SEvan.Yan@Sun.COM if (ret == DDI_SUCCESS) {
568210923SEvan.Yan@Sun.COM if (tmp == -1) {
568310923SEvan.Yan@Sun.COM DEBUG1("NO DEVICEFOUND, read %x\n", tmp);
568410923SEvan.Yan@Sun.COM ret = PCICFG_NODEVICE;
568510923SEvan.Yan@Sun.COM } else {
568610923SEvan.Yan@Sun.COM /* XXX - Need to check why HV is returning 0 */
568710923SEvan.Yan@Sun.COM if (tmp == 0) {
568810923SEvan.Yan@Sun.COM DEBUG0("Device Not Ready yet ?");
568910923SEvan.Yan@Sun.COM ret = PCICFG_NODEVICE;
569010923SEvan.Yan@Sun.COM } else {
569110923SEvan.Yan@Sun.COM DEBUG1("DEVICEFOUND, read %x\n", tmp);
569210923SEvan.Yan@Sun.COM ret = PCICFG_SUCCESS;
569310923SEvan.Yan@Sun.COM }
569410923SEvan.Yan@Sun.COM }
569510923SEvan.Yan@Sun.COM } else {
569610923SEvan.Yan@Sun.COM DEBUG0("ddi_peek failed, must be NODEVICE\n");
569710923SEvan.Yan@Sun.COM ret = PCICFG_NODEVICE;
569810923SEvan.Yan@Sun.COM }
569910923SEvan.Yan@Sun.COM
570010923SEvan.Yan@Sun.COM /*
570110923SEvan.Yan@Sun.COM * A bug in XMITS 3.0 causes us to miss the Master Abort Split
570210923SEvan.Yan@Sun.COM * Completion message. The result is the error message being
570310923SEvan.Yan@Sun.COM * sent back as part of the config data. If the first two words
570410923SEvan.Yan@Sun.COM * of the config space happen to be the same as the Master Abort
570510923SEvan.Yan@Sun.COM * message, then report back that there is no device there.
570610923SEvan.Yan@Sun.COM */
570710923SEvan.Yan@Sun.COM if ((ret == PCICFG_SUCCESS) && !(flags & PCICFG_CONF_INDIRECT_MAP)) {
570810923SEvan.Yan@Sun.COM int32_t pcix_scm;
570910923SEvan.Yan@Sun.COM
571010923SEvan.Yan@Sun.COM #define PCICFG_PCIX_SCM 0x10000004
571110923SEvan.Yan@Sun.COM
571210923SEvan.Yan@Sun.COM pcix_scm = 0;
571310923SEvan.Yan@Sun.COM (void) ddi_peek32(dip, (int32_t *)virt, &pcix_scm);
571410923SEvan.Yan@Sun.COM if (pcix_scm == PCICFG_PCIX_SCM) {
571510923SEvan.Yan@Sun.COM pcix_scm = 0;
571610923SEvan.Yan@Sun.COM (void) ddi_peek32(dip,
571710923SEvan.Yan@Sun.COM (int32_t *)(virt + 4), &pcix_scm);
571810923SEvan.Yan@Sun.COM if (pcix_scm == PCICFG_PCIX_SCM)
571910923SEvan.Yan@Sun.COM ret = PCICFG_NODEVICE;
572010923SEvan.Yan@Sun.COM }
572110923SEvan.Yan@Sun.COM }
572210923SEvan.Yan@Sun.COM
572310923SEvan.Yan@Sun.COM if (ret == PCICFG_NODEVICE)
572410923SEvan.Yan@Sun.COM #ifdef EFCODE21554
572510923SEvan.Yan@Sun.COM ddi_regs_map_free(handle);
572610923SEvan.Yan@Sun.COM #else
572710923SEvan.Yan@Sun.COM pcicfg_unmap_phys(handle, reg);
572810923SEvan.Yan@Sun.COM #endif
572910923SEvan.Yan@Sun.COM
573010923SEvan.Yan@Sun.COM kmem_free((caddr_t)reg, rlen);
573110923SEvan.Yan@Sun.COM
573210923SEvan.Yan@Sun.COM return (ret);
573310923SEvan.Yan@Sun.COM
573410923SEvan.Yan@Sun.COM }
573510923SEvan.Yan@Sun.COM
573610923SEvan.Yan@Sun.COM static void
pcicfg_config_teardown(ddi_acc_handle_t * handle)573710923SEvan.Yan@Sun.COM pcicfg_config_teardown(ddi_acc_handle_t *handle)
573810923SEvan.Yan@Sun.COM {
573910923SEvan.Yan@Sun.COM (void) ddi_regs_map_free(handle);
574010923SEvan.Yan@Sun.COM }
574110923SEvan.Yan@Sun.COM
574210923SEvan.Yan@Sun.COM static int
pcicfg_add_config_reg(dev_info_t * dip,uint_t bus,uint_t device,uint_t func)574310923SEvan.Yan@Sun.COM pcicfg_add_config_reg(dev_info_t *dip,
574410923SEvan.Yan@Sun.COM uint_t bus, uint_t device, uint_t func)
574510923SEvan.Yan@Sun.COM {
574610923SEvan.Yan@Sun.COM int reg[10] = { PCI_ADDR_CONFIG, 0, 0, 0, 0};
574710923SEvan.Yan@Sun.COM
574810923SEvan.Yan@Sun.COM reg[0] = PCICFG_MAKE_REG_HIGH(bus, device, func, 0);
574910923SEvan.Yan@Sun.COM
575010923SEvan.Yan@Sun.COM return (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
575110923SEvan.Yan@Sun.COM "reg", reg, 5));
575210923SEvan.Yan@Sun.COM }
575310923SEvan.Yan@Sun.COM
575410923SEvan.Yan@Sun.COM static int
pcicfg_dump_assigned(dev_info_t * dip)575510923SEvan.Yan@Sun.COM pcicfg_dump_assigned(dev_info_t *dip)
575610923SEvan.Yan@Sun.COM {
575710923SEvan.Yan@Sun.COM pci_regspec_t *reg;
575810923SEvan.Yan@Sun.COM int length;
575910923SEvan.Yan@Sun.COM int rcount;
576010923SEvan.Yan@Sun.COM int i;
576110923SEvan.Yan@Sun.COM
576210923SEvan.Yan@Sun.COM if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
576310923SEvan.Yan@Sun.COM DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)®,
576410923SEvan.Yan@Sun.COM &length) != DDI_PROP_SUCCESS) {
576510923SEvan.Yan@Sun.COM DEBUG0("Failed to read assigned-addresses property\n");
576610923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
576710923SEvan.Yan@Sun.COM }
576810923SEvan.Yan@Sun.COM
576910923SEvan.Yan@Sun.COM rcount = length / sizeof (pci_regspec_t);
577010923SEvan.Yan@Sun.COM for (i = 0; i < rcount; i++) {
577110923SEvan.Yan@Sun.COM DEBUG4("pcicfg_dump_assigned - size=%x low=%x mid=%x high=%x\n",
577210923SEvan.Yan@Sun.COM reg[i].pci_size_low, reg[i].pci_phys_low,
577310923SEvan.Yan@Sun.COM reg[i].pci_phys_mid, reg[i].pci_phys_hi);
577410923SEvan.Yan@Sun.COM }
577510923SEvan.Yan@Sun.COM /*
577610923SEvan.Yan@Sun.COM * Don't forget to free up memory from ddi_getlongprop
577710923SEvan.Yan@Sun.COM */
577810923SEvan.Yan@Sun.COM kmem_free((caddr_t)reg, length);
577910923SEvan.Yan@Sun.COM
578010923SEvan.Yan@Sun.COM return (PCICFG_SUCCESS);
578110923SEvan.Yan@Sun.COM }
578210923SEvan.Yan@Sun.COM
578310923SEvan.Yan@Sun.COM #ifdef PCICFG_INTERPRET_FCODE
578410923SEvan.Yan@Sun.COM static int
pcicfg_load_fcode(dev_info_t * dip,uint_t bus,uint_t device,uint_t func,uint16_t vendor_id,uint16_t device_id,uchar_t ** fcode_addr,int * fcode_size,int rom_paddr,int rom_size)578510923SEvan.Yan@Sun.COM pcicfg_load_fcode(dev_info_t *dip, uint_t bus, uint_t device, uint_t func,
578610923SEvan.Yan@Sun.COM uint16_t vendor_id, uint16_t device_id, uchar_t **fcode_addr,
578710923SEvan.Yan@Sun.COM int *fcode_size, int rom_paddr, int rom_size)
578810923SEvan.Yan@Sun.COM {
578910923SEvan.Yan@Sun.COM pci_regspec_t p;
579010923SEvan.Yan@Sun.COM int pci_data;
579110923SEvan.Yan@Sun.COM int start_of_fcode;
579210923SEvan.Yan@Sun.COM int image_length;
579310923SEvan.Yan@Sun.COM int code_type;
579410923SEvan.Yan@Sun.COM ddi_acc_handle_t h;
579510923SEvan.Yan@Sun.COM ddi_device_acc_attr_t acc;
579610923SEvan.Yan@Sun.COM uint8_t *addr;
579710923SEvan.Yan@Sun.COM int8_t image_not_found, indicator;
579810923SEvan.Yan@Sun.COM uint16_t vendor_id_img, device_id_img;
579910923SEvan.Yan@Sun.COM int16_t rom_sig;
580010923SEvan.Yan@Sun.COM #ifdef DEBUG
580110923SEvan.Yan@Sun.COM int i;
580210923SEvan.Yan@Sun.COM #endif
580310923SEvan.Yan@Sun.COM
580410923SEvan.Yan@Sun.COM DEBUG4("pcicfg_load_fcode() - "
580510923SEvan.Yan@Sun.COM "bus %x device =%x func=%x rom_paddr=%lx\n",
580610923SEvan.Yan@Sun.COM bus, device, func, rom_paddr);
580710923SEvan.Yan@Sun.COM DEBUG2("pcicfg_load_fcode() - vendor_id=%x device_id=%x\n",
580810923SEvan.Yan@Sun.COM vendor_id, device_id);
580910923SEvan.Yan@Sun.COM
581010923SEvan.Yan@Sun.COM *fcode_size = 0;
581110923SEvan.Yan@Sun.COM *fcode_addr = NULL;
581210923SEvan.Yan@Sun.COM
581310923SEvan.Yan@Sun.COM acc.devacc_attr_version = DDI_DEVICE_ATTR_V0;
581410923SEvan.Yan@Sun.COM acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
581510923SEvan.Yan@Sun.COM acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
581610923SEvan.Yan@Sun.COM
581710923SEvan.Yan@Sun.COM p.pci_phys_hi = PCI_ADDR_MEM32 | PCICFG_MAKE_REG_HIGH(bus, device,
581810923SEvan.Yan@Sun.COM func, PCI_CONF_ROM);
581910923SEvan.Yan@Sun.COM
582010923SEvan.Yan@Sun.COM p.pci_phys_mid = 0;
582110923SEvan.Yan@Sun.COM p.pci_phys_low = 0;
582210923SEvan.Yan@Sun.COM
582310923SEvan.Yan@Sun.COM p.pci_size_low = rom_size;
582410923SEvan.Yan@Sun.COM p.pci_size_hi = 0;
582510923SEvan.Yan@Sun.COM
582610923SEvan.Yan@Sun.COM if (pcicfg_map_phys(dip, &p, (caddr_t *)&addr, &acc, &h)) {
582710923SEvan.Yan@Sun.COM DEBUG1("Can Not map in ROM %x\n", p.pci_phys_low);
582810923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
582910923SEvan.Yan@Sun.COM }
583010923SEvan.Yan@Sun.COM
583110923SEvan.Yan@Sun.COM /*
583210923SEvan.Yan@Sun.COM * Walk the ROM to find the proper image for this device.
583310923SEvan.Yan@Sun.COM */
583410923SEvan.Yan@Sun.COM image_not_found = 1;
583510923SEvan.Yan@Sun.COM while (image_not_found) {
583610923SEvan.Yan@Sun.COM DEBUG1("Expansion ROM maps to %lx\n", addr);
583710923SEvan.Yan@Sun.COM
583810923SEvan.Yan@Sun.COM #ifdef DEBUG
583910923SEvan.Yan@Sun.COM if (pcicfg_dump_fcode) {
584010923SEvan.Yan@Sun.COM for (i = 0; i < 100; i++)
584110923SEvan.Yan@Sun.COM DEBUG2("ROM 0x%x --> 0x%x\n", i,
584210923SEvan.Yan@Sun.COM ddi_get8(h, (uint8_t *)(addr + i)));
584310923SEvan.Yan@Sun.COM }
584410923SEvan.Yan@Sun.COM #endif
584510923SEvan.Yan@Sun.COM
584610923SEvan.Yan@Sun.COM /*
584710923SEvan.Yan@Sun.COM * Some device say they have an Expansion ROM, but do not, so
584810923SEvan.Yan@Sun.COM * for non-21554 devices use peek so we don't panic due to
584910923SEvan.Yan@Sun.COM * accessing non existent memory.
585010923SEvan.Yan@Sun.COM */
585110923SEvan.Yan@Sun.COM if (pcicfg_indirect_map(dip) == DDI_SUCCESS) {
585210923SEvan.Yan@Sun.COM rom_sig = ddi_get16(h,
585310923SEvan.Yan@Sun.COM (uint16_t *)(addr + PCI_ROM_SIGNATURE));
585410923SEvan.Yan@Sun.COM } else {
585510923SEvan.Yan@Sun.COM if (ddi_peek16(dip,
585610923SEvan.Yan@Sun.COM (int16_t *)(addr + PCI_ROM_SIGNATURE), &rom_sig)) {
585710923SEvan.Yan@Sun.COM cmn_err(CE_WARN,
585810923SEvan.Yan@Sun.COM "PCI Expansion ROM is not accessible");
585910923SEvan.Yan@Sun.COM pcicfg_unmap_phys(&h, &p);
586010923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
586110923SEvan.Yan@Sun.COM }
586210923SEvan.Yan@Sun.COM }
586310923SEvan.Yan@Sun.COM
586410923SEvan.Yan@Sun.COM /*
586510923SEvan.Yan@Sun.COM * Validate the ROM Signature.
586610923SEvan.Yan@Sun.COM */
586710923SEvan.Yan@Sun.COM if ((uint16_t)rom_sig != 0xaa55) {
586810923SEvan.Yan@Sun.COM DEBUG1("Invalid ROM Signature %x\n", (uint16_t)rom_sig);
586910923SEvan.Yan@Sun.COM pcicfg_unmap_phys(&h, &p);
587010923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
587110923SEvan.Yan@Sun.COM }
587210923SEvan.Yan@Sun.COM
587310923SEvan.Yan@Sun.COM DEBUG0("Valid ROM Signature Found\n");
587410923SEvan.Yan@Sun.COM
587510923SEvan.Yan@Sun.COM start_of_fcode = ddi_get16(h, (uint16_t *)(addr + 2));
587610923SEvan.Yan@Sun.COM
587710923SEvan.Yan@Sun.COM pci_data = ddi_get16(h,
587810923SEvan.Yan@Sun.COM (uint16_t *)(addr + PCI_ROM_PCI_DATA_STRUCT_PTR));
587910923SEvan.Yan@Sun.COM
588010923SEvan.Yan@Sun.COM DEBUG2("Pointer To PCI Data Structure %x %x\n", pci_data,
588110923SEvan.Yan@Sun.COM addr);
588210923SEvan.Yan@Sun.COM
588310923SEvan.Yan@Sun.COM /*
588410923SEvan.Yan@Sun.COM * Validate the PCI Data Structure Signature.
588510923SEvan.Yan@Sun.COM * 0x52494350 = "PCIR"
588610923SEvan.Yan@Sun.COM */
588710923SEvan.Yan@Sun.COM
588810923SEvan.Yan@Sun.COM if (ddi_get8(h, (uint8_t *)(addr + pci_data)) != 0x50) {
588910923SEvan.Yan@Sun.COM DEBUG0("Invalid PCI Data Structure Signature\n");
589010923SEvan.Yan@Sun.COM pcicfg_unmap_phys(&h, &p);
589110923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
589210923SEvan.Yan@Sun.COM }
589310923SEvan.Yan@Sun.COM
589410923SEvan.Yan@Sun.COM if (ddi_get8(h, (uint8_t *)(addr + pci_data + 1)) != 0x43) {
589510923SEvan.Yan@Sun.COM DEBUG0("Invalid PCI Data Structure Signature\n");
589610923SEvan.Yan@Sun.COM pcicfg_unmap_phys(&h, &p);
589710923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
589810923SEvan.Yan@Sun.COM }
589910923SEvan.Yan@Sun.COM if (ddi_get8(h, (uint8_t *)(addr + pci_data + 2)) != 0x49) {
590010923SEvan.Yan@Sun.COM DEBUG0("Invalid PCI Data Structure Signature\n");
590110923SEvan.Yan@Sun.COM pcicfg_unmap_phys(&h, &p);
590210923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
590310923SEvan.Yan@Sun.COM }
590410923SEvan.Yan@Sun.COM if (ddi_get8(h, (uint8_t *)(addr + pci_data + 3)) != 0x52) {
590510923SEvan.Yan@Sun.COM DEBUG0("Invalid PCI Data Structure Signature\n");
590610923SEvan.Yan@Sun.COM pcicfg_unmap_phys(&h, &p);
590710923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
590810923SEvan.Yan@Sun.COM }
590910923SEvan.Yan@Sun.COM
591010923SEvan.Yan@Sun.COM /*
591110923SEvan.Yan@Sun.COM * Is this image for this device?
591210923SEvan.Yan@Sun.COM */
591310923SEvan.Yan@Sun.COM vendor_id_img = ddi_get16(h,
591410923SEvan.Yan@Sun.COM (uint16_t *)(addr + pci_data + PCI_PDS_VENDOR_ID));
591510923SEvan.Yan@Sun.COM device_id_img = ddi_get16(h,
591610923SEvan.Yan@Sun.COM (uint16_t *)(addr + pci_data + PCI_PDS_DEVICE_ID));
591710923SEvan.Yan@Sun.COM
591810923SEvan.Yan@Sun.COM DEBUG2("This image is for vendor_id=%x device_id=%x\n",
591910923SEvan.Yan@Sun.COM vendor_id_img, device_id_img);
592010923SEvan.Yan@Sun.COM
592110923SEvan.Yan@Sun.COM code_type = ddi_get8(h, addr + pci_data + PCI_PDS_CODE_TYPE);
592210923SEvan.Yan@Sun.COM
592310923SEvan.Yan@Sun.COM switch (code_type) {
592410923SEvan.Yan@Sun.COM case PCI_PDS_CODE_TYPE_PCAT:
592510923SEvan.Yan@Sun.COM DEBUG0("ROM is of x86/PC-AT Type\n");
592610923SEvan.Yan@Sun.COM break;
592710923SEvan.Yan@Sun.COM case PCI_PDS_CODE_TYPE_OPEN_FW:
592810923SEvan.Yan@Sun.COM DEBUG0("ROM is of Open Firmware Type\n");
592910923SEvan.Yan@Sun.COM break;
593010923SEvan.Yan@Sun.COM default:
593110923SEvan.Yan@Sun.COM DEBUG1("ROM is of Unknown Type 0x%x\n", code_type);
593210923SEvan.Yan@Sun.COM break;
593310923SEvan.Yan@Sun.COM }
593410923SEvan.Yan@Sun.COM
593510923SEvan.Yan@Sun.COM if ((vendor_id_img != vendor_id) ||
593610923SEvan.Yan@Sun.COM (device_id_img != device_id) ||
593710923SEvan.Yan@Sun.COM (code_type != PCI_PDS_CODE_TYPE_OPEN_FW)) {
593810923SEvan.Yan@Sun.COM DEBUG0("Firmware Image is not for this device..."
593910923SEvan.Yan@Sun.COM "goto next image\n");
594010923SEvan.Yan@Sun.COM /*
594110923SEvan.Yan@Sun.COM * Read indicator byte to see if there is another
594210923SEvan.Yan@Sun.COM * image in the ROM
594310923SEvan.Yan@Sun.COM */
594410923SEvan.Yan@Sun.COM indicator = ddi_get8(h,
594510923SEvan.Yan@Sun.COM (uint8_t *)(addr + pci_data + PCI_PDS_INDICATOR));
594610923SEvan.Yan@Sun.COM
594710923SEvan.Yan@Sun.COM if (indicator != 1) {
594810923SEvan.Yan@Sun.COM /*
594910923SEvan.Yan@Sun.COM * There is another image in the ROM.
595010923SEvan.Yan@Sun.COM */
595110923SEvan.Yan@Sun.COM image_length = ddi_get16(h, (uint16_t *)(addr +
595210923SEvan.Yan@Sun.COM pci_data + PCI_PDS_IMAGE_LENGTH)) * 512;
595310923SEvan.Yan@Sun.COM
595410923SEvan.Yan@Sun.COM addr += image_length;
595510923SEvan.Yan@Sun.COM } else {
595610923SEvan.Yan@Sun.COM /*
595710923SEvan.Yan@Sun.COM * There are no more images.
595810923SEvan.Yan@Sun.COM */
595910923SEvan.Yan@Sun.COM DEBUG0("There are no more images in the ROM\n");
596010923SEvan.Yan@Sun.COM pcicfg_unmap_phys(&h, &p);
596110923SEvan.Yan@Sun.COM
596210923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
596310923SEvan.Yan@Sun.COM }
596410923SEvan.Yan@Sun.COM } else {
596510923SEvan.Yan@Sun.COM DEBUG0("Correct image was found\n");
596610923SEvan.Yan@Sun.COM image_not_found = 0; /* Image was found */
596710923SEvan.Yan@Sun.COM }
596810923SEvan.Yan@Sun.COM }
596910923SEvan.Yan@Sun.COM
597010923SEvan.Yan@Sun.COM *fcode_size = (ddi_get8(h, addr + start_of_fcode + 4) << 24) |
597110923SEvan.Yan@Sun.COM (ddi_get8(h, addr + start_of_fcode + 5) << 16) |
597210923SEvan.Yan@Sun.COM (ddi_get8(h, addr + start_of_fcode + 6) << 8) |
597310923SEvan.Yan@Sun.COM (ddi_get8(h, addr + start_of_fcode + 7));
597410923SEvan.Yan@Sun.COM
597510923SEvan.Yan@Sun.COM DEBUG1("Fcode Size %x\n", *fcode_size);
597610923SEvan.Yan@Sun.COM
597710923SEvan.Yan@Sun.COM /*
597810923SEvan.Yan@Sun.COM * Allocate page aligned buffer space
597910923SEvan.Yan@Sun.COM */
598010923SEvan.Yan@Sun.COM *fcode_addr = kmem_zalloc(ptob(btopr(*fcode_size)), KM_SLEEP);
598110923SEvan.Yan@Sun.COM
598210923SEvan.Yan@Sun.COM if (*fcode_addr == NULL) {
598310923SEvan.Yan@Sun.COM DEBUG0("kmem_zalloc returned NULL\n");
598410923SEvan.Yan@Sun.COM pcicfg_unmap_phys(&h, &p);
598510923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
598610923SEvan.Yan@Sun.COM }
598710923SEvan.Yan@Sun.COM
598810923SEvan.Yan@Sun.COM DEBUG1("Fcode Addr %lx\n", *fcode_addr);
598910923SEvan.Yan@Sun.COM
599010923SEvan.Yan@Sun.COM ddi_rep_get8(h, *fcode_addr, addr + start_of_fcode, *fcode_size,
599110923SEvan.Yan@Sun.COM DDI_DEV_AUTOINCR);
599210923SEvan.Yan@Sun.COM
599310923SEvan.Yan@Sun.COM pcicfg_unmap_phys(&h, &p);
599410923SEvan.Yan@Sun.COM
599510923SEvan.Yan@Sun.COM return (PCICFG_SUCCESS);
599610923SEvan.Yan@Sun.COM }
599710923SEvan.Yan@Sun.COM
599810923SEvan.Yan@Sun.COM static int
pcicfg_fcode_assign_bars(ddi_acc_handle_t h,dev_info_t * dip,uint_t bus,uint_t device,uint_t func,int32_t fc_request,pci_regspec_t * rom_regspec)599910923SEvan.Yan@Sun.COM pcicfg_fcode_assign_bars(ddi_acc_handle_t h, dev_info_t *dip, uint_t bus,
600010923SEvan.Yan@Sun.COM uint_t device, uint_t func, int32_t fc_request, pci_regspec_t *rom_regspec)
600110923SEvan.Yan@Sun.COM {
600210923SEvan.Yan@Sun.COM /*
600310923SEvan.Yan@Sun.COM * Assign values to all BARs so that it is safe to turn on the
600410923SEvan.Yan@Sun.COM * device for accessing the fcode on the PROM. On successful
600510923SEvan.Yan@Sun.COM * exit from this function, "assigned-addresses" are created
600610923SEvan.Yan@Sun.COM * for all BARs and ROM BAR is enabled. Also, rom_regspec is
600710923SEvan.Yan@Sun.COM * filled with the values that can be used to free up this
600810923SEvan.Yan@Sun.COM * resource later.
600910923SEvan.Yan@Sun.COM */
601010923SEvan.Yan@Sun.COM uint32_t request, hiword, size;
601110923SEvan.Yan@Sun.COM pci_regspec_t phys_spec;
601210923SEvan.Yan@Sun.COM ndi_ra_request_t req;
601310923SEvan.Yan@Sun.COM uint64_t mem_answer, mem_alen;
601410923SEvan.Yan@Sun.COM int i;
601510923SEvan.Yan@Sun.COM
601610923SEvan.Yan@Sun.COM DEBUG1("pcicfg_fcode_assign_bars :%s\n", DEVI(dip)->devi_name);
601710923SEvan.Yan@Sun.COM
601810923SEvan.Yan@Sun.COM /*
601910923SEvan.Yan@Sun.COM * Process the BARs.
602010923SEvan.Yan@Sun.COM */
602110923SEvan.Yan@Sun.COM for (i = PCI_CONF_BASE0; i <= PCI_CONF_BASE5; ) {
602210923SEvan.Yan@Sun.COM pci_config_put32(h, i, 0xffffffff);
602310923SEvan.Yan@Sun.COM request = pci_config_get32(h, i);
602410923SEvan.Yan@Sun.COM /*
602510923SEvan.Yan@Sun.COM * Check if implemented
602610923SEvan.Yan@Sun.COM */
602710923SEvan.Yan@Sun.COM if (request == 0) {
602810923SEvan.Yan@Sun.COM DEBUG1("pcicfg_fcode_assign_bars :"
602910923SEvan.Yan@Sun.COM "BASE register [0x%x] asks for 0(32)\n", i);
603010923SEvan.Yan@Sun.COM i += 4;
603110923SEvan.Yan@Sun.COM continue;
603210923SEvan.Yan@Sun.COM }
603310923SEvan.Yan@Sun.COM /*
603410923SEvan.Yan@Sun.COM * Build the phys_spec for this BAR
603510923SEvan.Yan@Sun.COM */
603610923SEvan.Yan@Sun.COM hiword = PCICFG_MAKE_REG_HIGH(bus, device, func, i);
603710923SEvan.Yan@Sun.COM size = (~(PCI_BASE_M_ADDR_M & request)) + 1;
603810923SEvan.Yan@Sun.COM
603910923SEvan.Yan@Sun.COM DEBUG3("pcicfg_fcode_assign_bars :"
604010923SEvan.Yan@Sun.COM "BASE register [0x%x] asks for [0x%x]=[0x%x]\n",
604110923SEvan.Yan@Sun.COM i, request, size);
604210923SEvan.Yan@Sun.COM
604310923SEvan.Yan@Sun.COM if ((PCI_BASE_SPACE_M & request) == PCI_BASE_SPACE_MEM) {
604410923SEvan.Yan@Sun.COM if ((PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_MEM) {
604510923SEvan.Yan@Sun.COM hiword |= PCI_ADDR_MEM32;
604610923SEvan.Yan@Sun.COM } else if ((PCI_BASE_TYPE_M & request)
604710923SEvan.Yan@Sun.COM == PCI_BASE_TYPE_ALL) {
604810923SEvan.Yan@Sun.COM hiword |= PCI_ADDR_MEM64;
604910923SEvan.Yan@Sun.COM }
605010923SEvan.Yan@Sun.COM if (request & PCI_BASE_PREF_M)
605110923SEvan.Yan@Sun.COM hiword |= PCI_REG_PF_M;
605210923SEvan.Yan@Sun.COM } else {
605310923SEvan.Yan@Sun.COM hiword |= PCI_ADDR_IO;
605410923SEvan.Yan@Sun.COM }
605510923SEvan.Yan@Sun.COM phys_spec.pci_phys_hi = hiword;
605610923SEvan.Yan@Sun.COM phys_spec.pci_phys_mid = 0;
605710923SEvan.Yan@Sun.COM phys_spec.pci_phys_low = 0;
605810923SEvan.Yan@Sun.COM phys_spec.pci_size_hi = 0;
605910923SEvan.Yan@Sun.COM phys_spec.pci_size_low = size;
606010923SEvan.Yan@Sun.COM
606110923SEvan.Yan@Sun.COM /*
606210923SEvan.Yan@Sun.COM * The following function
606310923SEvan.Yan@Sun.COM * - allocates address space
606410923SEvan.Yan@Sun.COM * - programs the BAR
606510923SEvan.Yan@Sun.COM * - adds an "assigned-addresses" property
606610923SEvan.Yan@Sun.COM */
606710923SEvan.Yan@Sun.COM if (pcicfg_alloc_resource(dip, phys_spec)) {
606810923SEvan.Yan@Sun.COM cmn_err(CE_WARN, "failed to allocate %d bytes"
606910923SEvan.Yan@Sun.COM " for dev %s BASE register [0x%x]\n",
607010923SEvan.Yan@Sun.COM size, DEVI(dip)->devi_name, i);
607110923SEvan.Yan@Sun.COM goto failure;
607210923SEvan.Yan@Sun.COM }
607310923SEvan.Yan@Sun.COM if ((PCI_BASE_TYPE_M & request) == PCI_BASE_TYPE_ALL) {
607410923SEvan.Yan@Sun.COM /*
607510923SEvan.Yan@Sun.COM * 64 bit, should be in memory space.
607610923SEvan.Yan@Sun.COM */
607710923SEvan.Yan@Sun.COM i += 8;
607810923SEvan.Yan@Sun.COM } else {
607910923SEvan.Yan@Sun.COM /*
608010923SEvan.Yan@Sun.COM * 32 bit, either memory or I/O space.
608110923SEvan.Yan@Sun.COM */
608210923SEvan.Yan@Sun.COM i += 4;
608310923SEvan.Yan@Sun.COM }
608410923SEvan.Yan@Sun.COM }
608510923SEvan.Yan@Sun.COM
608610923SEvan.Yan@Sun.COM /*
608710923SEvan.Yan@Sun.COM * Handle ROM BAR. We do not use the common
608810923SEvan.Yan@Sun.COM * resource allocator function because we need to
608910923SEvan.Yan@Sun.COM * return reg spec to the caller.
609010923SEvan.Yan@Sun.COM */
609110923SEvan.Yan@Sun.COM size = (~(PCI_BASE_ROM_ADDR_M & fc_request)) + 1;
609210923SEvan.Yan@Sun.COM
609310923SEvan.Yan@Sun.COM DEBUG3("BASE register [0x%x] asks for "
609410923SEvan.Yan@Sun.COM "[0x%x]=[0x%x]\n", PCI_CONF_ROM, fc_request, size);
609510923SEvan.Yan@Sun.COM
609610923SEvan.Yan@Sun.COM bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
609710923SEvan.Yan@Sun.COM
609810923SEvan.Yan@Sun.COM req.ra_boundbase = 0;
609910923SEvan.Yan@Sun.COM req.ra_boundlen = PCICFG_4GIG_LIMIT;
610010923SEvan.Yan@Sun.COM req.ra_len = size;
6101*12765SScott.Carter@Oracle.COM req.ra_flags = (NDI_RA_ALIGN_SIZE | NDI_RA_ALLOC_BOUNDED);
610210923SEvan.Yan@Sun.COM
610310923SEvan.Yan@Sun.COM if (ndi_ra_alloc(ddi_get_parent(dip),
610410923SEvan.Yan@Sun.COM &req, &mem_answer, &mem_alen,
610510923SEvan.Yan@Sun.COM NDI_RA_TYPE_MEM, NDI_RA_PASS)) {
610610923SEvan.Yan@Sun.COM cmn_err(CE_WARN, "failed to allocate %d bytes"
610710923SEvan.Yan@Sun.COM " for dev %s ROM BASE register\n",
610810923SEvan.Yan@Sun.COM size, DEVI(dip)->devi_name);
610910923SEvan.Yan@Sun.COM goto failure;
611010923SEvan.Yan@Sun.COM }
611110923SEvan.Yan@Sun.COM
611210923SEvan.Yan@Sun.COM DEBUG3("ROM addr = [0x%x.%x] len [0x%x]\n",
611310923SEvan.Yan@Sun.COM PCICFG_HIADDR(mem_answer),
611410923SEvan.Yan@Sun.COM PCICFG_LOADDR(mem_answer), mem_alen);
611510923SEvan.Yan@Sun.COM
611610923SEvan.Yan@Sun.COM /*
611710923SEvan.Yan@Sun.COM * Assign address space and enable ROM.
611810923SEvan.Yan@Sun.COM */
611910923SEvan.Yan@Sun.COM pci_config_put32(h, PCI_CONF_ROM,
612010923SEvan.Yan@Sun.COM PCICFG_LOADDR(mem_answer) | PCI_BASE_ROM_ENABLE);
612110923SEvan.Yan@Sun.COM
612210923SEvan.Yan@Sun.COM /*
612310923SEvan.Yan@Sun.COM * Add resource to assigned-addresses.
612410923SEvan.Yan@Sun.COM */
612510923SEvan.Yan@Sun.COM phys_spec.pci_phys_hi = PCICFG_MAKE_REG_HIGH(bus, device, func, \
612610923SEvan.Yan@Sun.COM PCI_CONF_ROM) | PCI_ADDR_MEM32;
612710923SEvan.Yan@Sun.COM if (fc_request & PCI_BASE_PREF_M)
612810923SEvan.Yan@Sun.COM phys_spec.pci_phys_hi |= PCI_REG_PF_M;
612910923SEvan.Yan@Sun.COM phys_spec.pci_phys_mid = 0;
613010923SEvan.Yan@Sun.COM phys_spec.pci_phys_low = PCICFG_LOADDR(mem_answer);
613110923SEvan.Yan@Sun.COM phys_spec.pci_size_hi = 0;
613210923SEvan.Yan@Sun.COM phys_spec.pci_size_low = size;
613310923SEvan.Yan@Sun.COM
613410923SEvan.Yan@Sun.COM if (pcicfg_update_assigned_prop(dip, &phys_spec)
613510923SEvan.Yan@Sun.COM != PCICFG_SUCCESS) {
613610923SEvan.Yan@Sun.COM cmn_err(CE_WARN, "failed to update"
613710923SEvan.Yan@Sun.COM " assigned-address property for dev %s\n",
613810923SEvan.Yan@Sun.COM DEVI(dip)->devi_name);
613910923SEvan.Yan@Sun.COM goto failure;
614010923SEvan.Yan@Sun.COM }
614110923SEvan.Yan@Sun.COM /*
614210923SEvan.Yan@Sun.COM * Copy out the reg spec.
614310923SEvan.Yan@Sun.COM */
614410923SEvan.Yan@Sun.COM *rom_regspec = phys_spec;
614510923SEvan.Yan@Sun.COM
614610923SEvan.Yan@Sun.COM return (PCICFG_SUCCESS);
614710923SEvan.Yan@Sun.COM
614810923SEvan.Yan@Sun.COM failure:
614910923SEvan.Yan@Sun.COM /*
615010923SEvan.Yan@Sun.COM * We came in with no "assigned-addresses".
615110923SEvan.Yan@Sun.COM * Free up the resources we may have allocated.
615210923SEvan.Yan@Sun.COM */
615310923SEvan.Yan@Sun.COM (void) pcicfg_free_device_resources(dip, 0);
615410923SEvan.Yan@Sun.COM
615510923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
615610923SEvan.Yan@Sun.COM }
615710923SEvan.Yan@Sun.COM
615810923SEvan.Yan@Sun.COM #endif /* PCICFG_INTERPRET_FCODE */
615910923SEvan.Yan@Sun.COM
616010923SEvan.Yan@Sun.COM static int
pcicfg_free_all_resources(dev_info_t * dip)616110923SEvan.Yan@Sun.COM pcicfg_free_all_resources(dev_info_t *dip)
616210923SEvan.Yan@Sun.COM {
616310923SEvan.Yan@Sun.COM pci_regspec_t *assigned;
616410923SEvan.Yan@Sun.COM int assigned_len;
616510923SEvan.Yan@Sun.COM int acount;
616610923SEvan.Yan@Sun.COM int i;
616710923SEvan.Yan@Sun.COM
616810923SEvan.Yan@Sun.COM if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
616910923SEvan.Yan@Sun.COM DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned,
617010923SEvan.Yan@Sun.COM &assigned_len) != DDI_PROP_SUCCESS) {
617110923SEvan.Yan@Sun.COM DEBUG0("Failed to read assigned-addresses property\n");
617210923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
617310923SEvan.Yan@Sun.COM }
617410923SEvan.Yan@Sun.COM
617510923SEvan.Yan@Sun.COM acount = assigned_len / sizeof (pci_regspec_t);
617610923SEvan.Yan@Sun.COM
617710923SEvan.Yan@Sun.COM for (i = 0; i < acount; i++) {
617810923SEvan.Yan@Sun.COM if (pcicfg_free_resource(dip, assigned[i], 0)) {
617910923SEvan.Yan@Sun.COM /*
618010923SEvan.Yan@Sun.COM * Dont forget to free mem from ddi_getlongprop
618110923SEvan.Yan@Sun.COM */
618210923SEvan.Yan@Sun.COM kmem_free((caddr_t)assigned, assigned_len);
618310923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
618410923SEvan.Yan@Sun.COM }
618510923SEvan.Yan@Sun.COM }
618610923SEvan.Yan@Sun.COM
618710923SEvan.Yan@Sun.COM /*
618810923SEvan.Yan@Sun.COM * Don't forget to free up memory from ddi_getlongprop
618910923SEvan.Yan@Sun.COM */
619010923SEvan.Yan@Sun.COM if (assigned_len)
619110923SEvan.Yan@Sun.COM kmem_free((caddr_t)assigned, assigned_len);
619210923SEvan.Yan@Sun.COM
619310923SEvan.Yan@Sun.COM return (PCICFG_SUCCESS);
619410923SEvan.Yan@Sun.COM }
619510923SEvan.Yan@Sun.COM static int
pcicfg_alloc_new_resources(dev_info_t * dip)619610923SEvan.Yan@Sun.COM pcicfg_alloc_new_resources(dev_info_t *dip)
619710923SEvan.Yan@Sun.COM {
619810923SEvan.Yan@Sun.COM pci_regspec_t *assigned, *reg;
619910923SEvan.Yan@Sun.COM int assigned_len, reg_len;
620010923SEvan.Yan@Sun.COM int acount, rcount;
620110923SEvan.Yan@Sun.COM int i, j, alloc_size;
620210923SEvan.Yan@Sun.COM boolean_t alloc;
620310923SEvan.Yan@Sun.COM
620410923SEvan.Yan@Sun.COM if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
620510923SEvan.Yan@Sun.COM DDI_PROP_DONTPASS, "reg", (caddr_t)®,
620610923SEvan.Yan@Sun.COM ®_len) != DDI_PROP_SUCCESS) {
620710923SEvan.Yan@Sun.COM DEBUG0("Failed to read reg property\n");
620810923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
620910923SEvan.Yan@Sun.COM }
621010923SEvan.Yan@Sun.COM rcount = reg_len / sizeof (pci_regspec_t);
621110923SEvan.Yan@Sun.COM
621210923SEvan.Yan@Sun.COM DEBUG2("pcicfg_alloc_new_resources() reg size=%x entries=%x\n",
621310923SEvan.Yan@Sun.COM reg_len, rcount);
621410923SEvan.Yan@Sun.COM
621510923SEvan.Yan@Sun.COM if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
621610923SEvan.Yan@Sun.COM DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned,
621710923SEvan.Yan@Sun.COM &assigned_len) != DDI_PROP_SUCCESS) {
621810923SEvan.Yan@Sun.COM acount = 0;
621910923SEvan.Yan@Sun.COM } else {
622010923SEvan.Yan@Sun.COM acount = assigned_len / sizeof (pci_regspec_t);
622110923SEvan.Yan@Sun.COM }
622210923SEvan.Yan@Sun.COM
622310923SEvan.Yan@Sun.COM DEBUG1("assigned-addresses property len=%x\n", acount);
622410923SEvan.Yan@Sun.COM
622510923SEvan.Yan@Sun.COM /*
622610923SEvan.Yan@Sun.COM * For each address described by reg, search for it in the
622710923SEvan.Yan@Sun.COM * assigned-addresses property. If it does not exist, allocate
622810923SEvan.Yan@Sun.COM * resources for it. If it does exist, check the size in both.
622910923SEvan.Yan@Sun.COM * The size needs to be bigger of the two.
623010923SEvan.Yan@Sun.COM */
623110923SEvan.Yan@Sun.COM for (i = 1; i < rcount; i++) {
623210923SEvan.Yan@Sun.COM alloc = B_TRUE;
623310923SEvan.Yan@Sun.COM alloc_size = reg[i].pci_size_low;
623410923SEvan.Yan@Sun.COM for (j = 0; j < acount; j++) {
623510923SEvan.Yan@Sun.COM if (assigned[j].pci_phys_hi == reg[i].pci_phys_hi) {
623610923SEvan.Yan@Sun.COM /*
623710923SEvan.Yan@Sun.COM * There is an exact match. Check size.
623810923SEvan.Yan@Sun.COM */
623910923SEvan.Yan@Sun.COM DEBUG1("pcicfg_alloc_new_resources "
624010923SEvan.Yan@Sun.COM "- %x - MATCH\n",
624110923SEvan.Yan@Sun.COM reg[i].pci_phys_hi);
624210923SEvan.Yan@Sun.COM
624310923SEvan.Yan@Sun.COM if (reg[i].pci_size_low >
624410923SEvan.Yan@Sun.COM assigned[j].pci_size_low) {
624510923SEvan.Yan@Sun.COM /*
624610923SEvan.Yan@Sun.COM * Fcode wants more.
624710923SEvan.Yan@Sun.COM */
624810923SEvan.Yan@Sun.COM DEBUG3("pcicfg_alloc_new_resources"
624910923SEvan.Yan@Sun.COM " - %x - RESIZE"
625010923SEvan.Yan@Sun.COM " assigned 0x%x reg 0x%x\n",
625110923SEvan.Yan@Sun.COM assigned[j].pci_phys_hi,
625210923SEvan.Yan@Sun.COM assigned[j].pci_size_low,
625310923SEvan.Yan@Sun.COM reg[i].pci_size_low);
625410923SEvan.Yan@Sun.COM
625510923SEvan.Yan@Sun.COM /*
625610923SEvan.Yan@Sun.COM * Free the old resource.
625710923SEvan.Yan@Sun.COM */
625810923SEvan.Yan@Sun.COM (void) pcicfg_free_resource(dip,
625910923SEvan.Yan@Sun.COM assigned[j], 0);
626010923SEvan.Yan@Sun.COM } else {
626110923SEvan.Yan@Sun.COM DEBUG3("pcicfg_alloc_new_resources"
626210923SEvan.Yan@Sun.COM " - %x - ENOUGH"
626310923SEvan.Yan@Sun.COM " assigned 0x%x reg 0x%x\n",
626410923SEvan.Yan@Sun.COM assigned[j].pci_phys_hi,
626510923SEvan.Yan@Sun.COM assigned[j].pci_size_low,
626610923SEvan.Yan@Sun.COM reg[i].pci_size_low);
626710923SEvan.Yan@Sun.COM
626810923SEvan.Yan@Sun.COM alloc = B_FALSE;
626910923SEvan.Yan@Sun.COM }
627010923SEvan.Yan@Sun.COM break;
627110923SEvan.Yan@Sun.COM }
627210923SEvan.Yan@Sun.COM /*
627310923SEvan.Yan@Sun.COM * Fcode may have set one or more of the
627410923SEvan.Yan@Sun.COM * NPT bits in phys.hi.
627510923SEvan.Yan@Sun.COM */
627610923SEvan.Yan@Sun.COM if (PCI_REG_BDFR_G(assigned[j].pci_phys_hi) ==
627710923SEvan.Yan@Sun.COM PCI_REG_BDFR_G(reg[i].pci_phys_hi)) {
627810923SEvan.Yan@Sun.COM
627910923SEvan.Yan@Sun.COM DEBUG2("pcicfg_alloc_new_resources "
628010923SEvan.Yan@Sun.COM "- PARTIAL MATCH assigned 0x%x "
628110923SEvan.Yan@Sun.COM "reg 0x%x\n", assigned[j].pci_phys_hi,
628210923SEvan.Yan@Sun.COM reg[i].pci_phys_hi);
628310923SEvan.Yan@Sun.COM /*
628410923SEvan.Yan@Sun.COM * Changing the SS bits is an error
628510923SEvan.Yan@Sun.COM */
628610923SEvan.Yan@Sun.COM if (PCI_REG_ADDR_G(
628710923SEvan.Yan@Sun.COM assigned[j].pci_phys_hi) !=
628810923SEvan.Yan@Sun.COM PCI_REG_ADDR_G(reg[i].pci_phys_hi)) {
628910923SEvan.Yan@Sun.COM
629010923SEvan.Yan@Sun.COM DEBUG2("Fcode changing"
629110923SEvan.Yan@Sun.COM " SS bits of - 0x%x -"
629210923SEvan.Yan@Sun.COM " on %s\n", reg[i].pci_phys_hi,
629310923SEvan.Yan@Sun.COM DEVI(dip)->devi_name);
629410923SEvan.Yan@Sun.COM
629510923SEvan.Yan@Sun.COM }
629610923SEvan.Yan@Sun.COM
629710923SEvan.Yan@Sun.COM
629810923SEvan.Yan@Sun.COM /*
629910923SEvan.Yan@Sun.COM * We are going to allocate new resource.
630010923SEvan.Yan@Sun.COM * Free the old resource. Again, adjust
630110923SEvan.Yan@Sun.COM * the size to be safe.
630210923SEvan.Yan@Sun.COM */
630310923SEvan.Yan@Sun.COM (void) pcicfg_free_resource(dip,
630410923SEvan.Yan@Sun.COM assigned[j], 0);
630510923SEvan.Yan@Sun.COM
630610923SEvan.Yan@Sun.COM alloc_size = MAX(reg[i].pci_size_low,
630710923SEvan.Yan@Sun.COM assigned[j].pci_size_low);
630810923SEvan.Yan@Sun.COM
630910923SEvan.Yan@Sun.COM break;
631010923SEvan.Yan@Sun.COM }
631110923SEvan.Yan@Sun.COM }
631210923SEvan.Yan@Sun.COM /*
631310923SEvan.Yan@Sun.COM * We are allocating resources for one of three reasons -
631410923SEvan.Yan@Sun.COM * - Fcode wants a larger address space
631510923SEvan.Yan@Sun.COM * - Fcode has set changed/set n, p, t bits.
631610923SEvan.Yan@Sun.COM * - It is a new "reg", it should be only ROM bar, but
631710923SEvan.Yan@Sun.COM * we don't do the checking.
631810923SEvan.Yan@Sun.COM */
631910923SEvan.Yan@Sun.COM if (alloc == B_TRUE) {
632010923SEvan.Yan@Sun.COM DEBUG1("pcicfg_alloc_new_resources : creating 0x%x\n",
632110923SEvan.Yan@Sun.COM reg[i].pci_phys_hi);
632210923SEvan.Yan@Sun.COM
632310923SEvan.Yan@Sun.COM reg[i].pci_size_low = alloc_size;
632410923SEvan.Yan@Sun.COM if (pcicfg_alloc_resource(dip, reg[i])) {
632510923SEvan.Yan@Sun.COM /*
632610923SEvan.Yan@Sun.COM * Dont forget to free mem from
632710923SEvan.Yan@Sun.COM * ddi_getlongprop
632810923SEvan.Yan@Sun.COM */
632910923SEvan.Yan@Sun.COM if (acount != 0)
633010923SEvan.Yan@Sun.COM kmem_free((caddr_t)assigned,
633110923SEvan.Yan@Sun.COM assigned_len);
633210923SEvan.Yan@Sun.COM kmem_free((caddr_t)reg, reg_len);
633310923SEvan.Yan@Sun.COM return (PCICFG_FAILURE);
633410923SEvan.Yan@Sun.COM }
633510923SEvan.Yan@Sun.COM }
633610923SEvan.Yan@Sun.COM }
633710923SEvan.Yan@Sun.COM
633810923SEvan.Yan@Sun.COM /*
633910923SEvan.Yan@Sun.COM * Don't forget to free up memory from ddi_getlongprop
634010923SEvan.Yan@Sun.COM */
634110923SEvan.Yan@Sun.COM if (acount != 0)
634210923SEvan.Yan@Sun.COM kmem_free((caddr_t)assigned, assigned_len);
634310923SEvan.Yan@Sun.COM kmem_free((caddr_t)reg, reg_len);
634410923SEvan.Yan@Sun.COM
634510923SEvan.Yan@Sun.COM return (PCICFG_SUCCESS);
634610923SEvan.Yan@Sun.COM }
634710923SEvan.Yan@Sun.COM
634810923SEvan.Yan@Sun.COM static int
pcicfg_alloc_resource(dev_info_t * dip,pci_regspec_t phys_spec)634910923SEvan.Yan@Sun.COM pcicfg_alloc_resource(dev_info_t *dip, pci_regspec_t phys_spec)
635010923SEvan.Yan@Sun.COM {
635110923SEvan.Yan@Sun.COM uint64_t answer;
635210923SEvan.Yan@Sun.COM uint64_t alen;
635310923SEvan.Yan@Sun.COM int offset;
635410923SEvan.Yan@Sun.COM pci_regspec_t config;
635510923SEvan.Yan@Sun.COM caddr_t virt, v;
635610923SEvan.Yan@Sun.COM ddi_device_acc_attr_t acc;
635710923SEvan.Yan@Sun.COM ddi_acc_handle_t h;
635810923SEvan.Yan@Sun.COM ndi_ra_request_t request;
635910923SEvan.Yan@Sun.COM pci_regspec_t *assigned;
636010923SEvan.Yan@Sun.COM int assigned_len, entries, i;
636110923SEvan.Yan@Sun.COM
636210923SEvan.Yan@Sun.COM if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
636310923SEvan.Yan@Sun.COM DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned,
636410923SEvan.Yan@Sun.COM &assigned_len) == DDI_PROP_SUCCESS) {
636510923SEvan.Yan@Sun.COM DEBUG0("pcicfg_alloc_resource - "
636610923SEvan.Yan@Sun.COM "searching assigned-addresses\n");
636710923SEvan.Yan@Sun.COM
636810923SEvan.Yan@Sun.COM entries = assigned_len / (sizeof (pci_regspec_t));
636910923SEvan.Yan@Sun.COM
637010923SEvan.Yan@Sun.COM /*
637110923SEvan.Yan@Sun.COM * Walk through the assigned-addresses entries. If there is
637210923SEvan.Yan@Sun.COM * a match, there is no need to allocate the resource.
637310923SEvan.Yan@Sun.COM */
637410923SEvan.Yan@Sun.COM for (i = 0; i < entries; i++) {
637510923SEvan.Yan@Sun.COM if (assigned[i].pci_phys_hi == phys_spec.pci_phys_hi) {
637610923SEvan.Yan@Sun.COM DEBUG1("pcicfg_alloc_resource - MATCH %x\n",
637710923SEvan.Yan@Sun.COM assigned[i].pci_phys_hi);
637810923SEvan.Yan@Sun.COM kmem_free(assigned, assigned_len);
637910923SEvan.Yan@Sun.COM return (0);
638010923SEvan.Yan@Sun.COM }
638110923SEvan.Yan@Sun.COM }
638210923SEvan.Yan@Sun.COM kmem_free(assigned, assigned_len);
638310923SEvan.Yan@Sun.COM }
638410923SEvan.Yan@Sun.COM
638510923SEvan.Yan@Sun.COM bzero((caddr_t)&request, sizeof (ndi_ra_request_t));
638610923SEvan.Yan@Sun.COM
638710923SEvan.Yan@Sun.COM config.pci_phys_hi = PCI_CONF_ADDR_MASK & phys_spec.pci_phys_hi;
638810923SEvan.Yan@Sun.COM config.pci_phys_hi &= ~PCI_REG_REG_M;
638910923SEvan.Yan@Sun.COM config.pci_phys_mid = config.pci_phys_low = 0;
639010923SEvan.Yan@Sun.COM config.pci_size_hi = config.pci_size_low = 0;
639110923SEvan.Yan@Sun.COM
639210923SEvan.Yan@Sun.COM /*
639310923SEvan.Yan@Sun.COM * Map in configuration space (temporarily)
639410923SEvan.Yan@Sun.COM */
639510923SEvan.Yan@Sun.COM acc.devacc_attr_version = DDI_DEVICE_ATTR_V0;
639610923SEvan.Yan@Sun.COM acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
639710923SEvan.Yan@Sun.COM acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
639810923SEvan.Yan@Sun.COM
639910923SEvan.Yan@Sun.COM if (pcicfg_map_phys(dip, &config, &virt, &acc, &h)) {
640010923SEvan.Yan@Sun.COM DEBUG0("Can not map in config space\n");
640110923SEvan.Yan@Sun.COM return (1);
640210923SEvan.Yan@Sun.COM }
640310923SEvan.Yan@Sun.COM
6404*12765SScott.Carter@Oracle.COM request.ra_flags = NDI_RA_ALIGN_SIZE;
640510923SEvan.Yan@Sun.COM request.ra_boundbase = 0;
640610923SEvan.Yan@Sun.COM request.ra_boundlen = PCICFG_4GIG_LIMIT;
640710923SEvan.Yan@Sun.COM /*
640810923SEvan.Yan@Sun.COM * Use size stored in phys_spec parameter.
640910923SEvan.Yan@Sun.COM */
641010923SEvan.Yan@Sun.COM request.ra_len = phys_spec.pci_size_low;
641110923SEvan.Yan@Sun.COM
641210923SEvan.Yan@Sun.COM offset = PCI_REG_REG_G(phys_spec.pci_phys_hi);
641310923SEvan.Yan@Sun.COM
641410923SEvan.Yan@Sun.COM v = virt + offset;
641510923SEvan.Yan@Sun.COM
641610923SEvan.Yan@Sun.COM if (PCI_REG_REG_G(phys_spec.pci_phys_hi) == PCI_CONF_ROM) {
641710923SEvan.Yan@Sun.COM
6418*12765SScott.Carter@Oracle.COM request.ra_flags |= NDI_RA_ALLOC_BOUNDED;
641910923SEvan.Yan@Sun.COM
642010923SEvan.Yan@Sun.COM /* allocate memory space from the allocator */
642110923SEvan.Yan@Sun.COM
642210923SEvan.Yan@Sun.COM if (ndi_ra_alloc(ddi_get_parent(dip),
642310923SEvan.Yan@Sun.COM &request, &answer, &alen,
642410923SEvan.Yan@Sun.COM NDI_RA_TYPE_MEM, NDI_RA_PASS)
642510923SEvan.Yan@Sun.COM != NDI_SUCCESS) {
642610923SEvan.Yan@Sun.COM DEBUG0("(ROM)Failed to allocate 32b mem");
642710923SEvan.Yan@Sun.COM pcicfg_unmap_phys(&h, &config);
642810923SEvan.Yan@Sun.COM return (1);
642910923SEvan.Yan@Sun.COM }
643010923SEvan.Yan@Sun.COM DEBUG3("ROM addr = [0x%x.%x] len [0x%x]\n",
643110923SEvan.Yan@Sun.COM PCICFG_HIADDR(answer),
643210923SEvan.Yan@Sun.COM PCICFG_LOADDR(answer),
643310923SEvan.Yan@Sun.COM alen);
643410923SEvan.Yan@Sun.COM
643510923SEvan.Yan@Sun.COM /* program the low word */
643610923SEvan.Yan@Sun.COM
643710923SEvan.Yan@Sun.COM ddi_put32(h, (uint32_t *)v, (uint32_t)PCICFG_LOADDR(answer));
643810923SEvan.Yan@Sun.COM
643910923SEvan.Yan@Sun.COM phys_spec.pci_phys_low = PCICFG_LOADDR(answer);
644010923SEvan.Yan@Sun.COM phys_spec.pci_phys_mid = PCICFG_HIADDR(answer);
644110923SEvan.Yan@Sun.COM } else {
644210923SEvan.Yan@Sun.COM
644310923SEvan.Yan@Sun.COM switch (PCI_REG_ADDR_G(phys_spec.pci_phys_hi)) {
644410923SEvan.Yan@Sun.COM case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
6445*12765SScott.Carter@Oracle.COM request.ra_flags &= ~NDI_RA_ALLOC_BOUNDED;
644610923SEvan.Yan@Sun.COM /* allocate memory space from the allocator */
644710923SEvan.Yan@Sun.COM if (ndi_ra_alloc(ddi_get_parent(dip),
644810923SEvan.Yan@Sun.COM &request, &answer, &alen,
644910923SEvan.Yan@Sun.COM NDI_RA_TYPE_MEM, NDI_RA_PASS)
645010923SEvan.Yan@Sun.COM != NDI_SUCCESS) {
645110923SEvan.Yan@Sun.COM DEBUG0("Failed to allocate 64b mem\n");
645210923SEvan.Yan@Sun.COM pcicfg_unmap_phys(&h, &config);
645310923SEvan.Yan@Sun.COM return (1);
645410923SEvan.Yan@Sun.COM }
645510923SEvan.Yan@Sun.COM DEBUG3("64 addr = [0x%x.%x] len [0x%x]\n",
645610923SEvan.Yan@Sun.COM PCICFG_HIADDR(answer),
645710923SEvan.Yan@Sun.COM PCICFG_LOADDR(answer),
645810923SEvan.Yan@Sun.COM alen);
645910923SEvan.Yan@Sun.COM
646010923SEvan.Yan@Sun.COM /* program the low word */
646110923SEvan.Yan@Sun.COM
646210923SEvan.Yan@Sun.COM ddi_put32(h, (uint32_t *)v,
646310923SEvan.Yan@Sun.COM (uint32_t)PCICFG_LOADDR(answer));
646410923SEvan.Yan@Sun.COM
646510923SEvan.Yan@Sun.COM /* program the high word with value zero */
646610923SEvan.Yan@Sun.COM v += 4;
646710923SEvan.Yan@Sun.COM ddi_put32(h, (uint32_t *)v,
646810923SEvan.Yan@Sun.COM (uint32_t)PCICFG_HIADDR(answer));
646910923SEvan.Yan@Sun.COM
647010923SEvan.Yan@Sun.COM phys_spec.pci_phys_low = PCICFG_LOADDR(answer);
647110923SEvan.Yan@Sun.COM phys_spec.pci_phys_mid = PCICFG_HIADDR(answer);
647210923SEvan.Yan@Sun.COM /*
647310923SEvan.Yan@Sun.COM * currently support 32b address space
647410923SEvan.Yan@Sun.COM * assignments only.
647510923SEvan.Yan@Sun.COM */
647610923SEvan.Yan@Sun.COM phys_spec.pci_phys_hi ^= PCI_ADDR_MEM64 ^
647710923SEvan.Yan@Sun.COM PCI_ADDR_MEM32;
647810923SEvan.Yan@Sun.COM
647910923SEvan.Yan@Sun.COM break;
648010923SEvan.Yan@Sun.COM
648110923SEvan.Yan@Sun.COM case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
648210923SEvan.Yan@Sun.COM request.ra_flags |= NDI_RA_ALLOC_BOUNDED;
648310923SEvan.Yan@Sun.COM /* allocate memory space from the allocator */
648410923SEvan.Yan@Sun.COM if (ndi_ra_alloc(ddi_get_parent(dip),
648510923SEvan.Yan@Sun.COM &request, &answer, &alen,
648610923SEvan.Yan@Sun.COM NDI_RA_TYPE_MEM, NDI_RA_PASS)
648710923SEvan.Yan@Sun.COM != NDI_SUCCESS) {
648810923SEvan.Yan@Sun.COM DEBUG0("Failed to allocate 32b mem\n");
648910923SEvan.Yan@Sun.COM pcicfg_unmap_phys(&h, &config);
649010923SEvan.Yan@Sun.COM return (1);
649110923SEvan.Yan@Sun.COM }
649210923SEvan.Yan@Sun.COM
649310923SEvan.Yan@Sun.COM DEBUG3("32 addr = [0x%x.%x] len [0x%x]\n",
649410923SEvan.Yan@Sun.COM PCICFG_HIADDR(answer),
649510923SEvan.Yan@Sun.COM PCICFG_LOADDR(answer),
649610923SEvan.Yan@Sun.COM alen);
649710923SEvan.Yan@Sun.COM
649810923SEvan.Yan@Sun.COM /* program the low word */
649910923SEvan.Yan@Sun.COM
650010923SEvan.Yan@Sun.COM ddi_put32(h, (uint32_t *)v,
650110923SEvan.Yan@Sun.COM (uint32_t)PCICFG_LOADDR(answer));
650210923SEvan.Yan@Sun.COM
650310923SEvan.Yan@Sun.COM phys_spec.pci_phys_low = PCICFG_LOADDR(answer);
650410923SEvan.Yan@Sun.COM
650510923SEvan.Yan@Sun.COM break;
650610923SEvan.Yan@Sun.COM case PCI_REG_ADDR_G(PCI_ADDR_IO):
650710923SEvan.Yan@Sun.COM /* allocate I/O space from the allocator */
650810923SEvan.Yan@Sun.COM request.ra_flags |= NDI_RA_ALLOC_BOUNDED;
650910923SEvan.Yan@Sun.COM if (ndi_ra_alloc(ddi_get_parent(dip),
651010923SEvan.Yan@Sun.COM &request, &answer, &alen,
651110923SEvan.Yan@Sun.COM NDI_RA_TYPE_IO, NDI_RA_PASS)
651210923SEvan.Yan@Sun.COM != NDI_SUCCESS) {
651310923SEvan.Yan@Sun.COM DEBUG0("Failed to allocate I/O\n");
651410923SEvan.Yan@Sun.COM pcicfg_unmap_phys(&h, &config);
651510923SEvan.Yan@Sun.COM return (1);
651610923SEvan.Yan@Sun.COM }
651710923SEvan.Yan@Sun.COM DEBUG3("I/O addr = [0x%x.%x] len [0x%x]\n",
651810923SEvan.Yan@Sun.COM PCICFG_HIADDR(answer),
651910923SEvan.Yan@Sun.COM PCICFG_LOADDR(answer),
652010923SEvan.Yan@Sun.COM alen);
652110923SEvan.Yan@Sun.COM
652210923SEvan.Yan@Sun.COM ddi_put32(h, (uint32_t *)v,
652310923SEvan.Yan@Sun.COM (uint32_t)PCICFG_LOADDR(answer));
652410923SEvan.Yan@Sun.COM
652510923SEvan.Yan@Sun.COM phys_spec.pci_phys_low = PCICFG_LOADDR(answer);
652610923SEvan.Yan@Sun.COM
652710923SEvan.Yan@Sun.COM break;
652810923SEvan.Yan@Sun.COM default:
652910923SEvan.Yan@Sun.COM DEBUG0("Unknown register type\n");
653010923SEvan.Yan@Sun.COM pcicfg_unmap_phys(&h, &config);
653110923SEvan.Yan@Sun.COM return (1);
653210923SEvan.Yan@Sun.COM } /* switch */
653310923SEvan.Yan@Sun.COM }
653410923SEvan.Yan@Sun.COM
653510923SEvan.Yan@Sun.COM /*
653610923SEvan.Yan@Sun.COM * Now that memory locations are assigned,
653710923SEvan.Yan@Sun.COM * update the assigned address property.
653810923SEvan.Yan@Sun.COM */
653910923SEvan.Yan@Sun.COM
654010923SEvan.Yan@Sun.COM DEBUG1("updating assigned-addresss for %x\n", phys_spec.pci_phys_hi);
654110923SEvan.Yan@Sun.COM
654210923SEvan.Yan@Sun.COM if (pcicfg_update_assigned_prop(dip, &phys_spec)) {
654310923SEvan.Yan@Sun.COM pcicfg_unmap_phys(&h, &config);
654410923SEvan.Yan@Sun.COM return (1);
654510923SEvan.Yan@Sun.COM }
654610923SEvan.Yan@Sun.COM
654710923SEvan.Yan@Sun.COM pcicfg_unmap_phys(&h, &config);
654810923SEvan.Yan@Sun.COM
654910923SEvan.Yan@Sun.COM return (0);
655010923SEvan.Yan@Sun.COM }
655110923SEvan.Yan@Sun.COM
655210923SEvan.Yan@Sun.COM static int
pcicfg_free_resource(dev_info_t * dip,pci_regspec_t phys_spec,pcicfg_flags_t flags)655310923SEvan.Yan@Sun.COM pcicfg_free_resource(dev_info_t *dip, pci_regspec_t phys_spec,
655410923SEvan.Yan@Sun.COM pcicfg_flags_t flags)
655510923SEvan.Yan@Sun.COM {
655610923SEvan.Yan@Sun.COM int offset;
655710923SEvan.Yan@Sun.COM pci_regspec_t config;
655810923SEvan.Yan@Sun.COM caddr_t virt, v;
655910923SEvan.Yan@Sun.COM ddi_device_acc_attr_t acc;
656010923SEvan.Yan@Sun.COM ddi_acc_handle_t h;
656110923SEvan.Yan@Sun.COM ndi_ra_request_t request;
656210923SEvan.Yan@Sun.COM int l;
656310923SEvan.Yan@Sun.COM
656410923SEvan.Yan@Sun.COM bzero((caddr_t)&request, sizeof (ndi_ra_request_t));
656510923SEvan.Yan@Sun.COM
656610923SEvan.Yan@Sun.COM config.pci_phys_hi = PCI_CONF_ADDR_MASK & phys_spec.pci_phys_hi;
656710923SEvan.Yan@Sun.COM config.pci_phys_hi &= ~PCI_REG_REG_M;
656810923SEvan.Yan@Sun.COM config.pci_phys_mid = config.pci_phys_low = 0;
656910923SEvan.Yan@Sun.COM config.pci_size_hi = config.pci_size_low = 0;
657010923SEvan.Yan@Sun.COM
657110923SEvan.Yan@Sun.COM /*
657210923SEvan.Yan@Sun.COM * Map in configuration space (temporarily)
657310923SEvan.Yan@Sun.COM */
657410923SEvan.Yan@Sun.COM acc.devacc_attr_version = DDI_DEVICE_ATTR_V0;
657510923SEvan.Yan@Sun.COM acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
657610923SEvan.Yan@Sun.COM acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
657710923SEvan.Yan@Sun.COM
657810923SEvan.Yan@Sun.COM if (pcicfg_map_phys(dip, &config, &virt, &acc, &h)) {
657910923SEvan.Yan@Sun.COM DEBUG0("Can not map in config space\n");
658010923SEvan.Yan@Sun.COM return (1);
658110923SEvan.Yan@Sun.COM }
658210923SEvan.Yan@Sun.COM
658310923SEvan.Yan@Sun.COM offset = PCI_REG_REG_G(phys_spec.pci_phys_hi);
658410923SEvan.Yan@Sun.COM
658510923SEvan.Yan@Sun.COM v = virt + offset;
658610923SEvan.Yan@Sun.COM
658710923SEvan.Yan@Sun.COM /*
658810923SEvan.Yan@Sun.COM * Use size stored in phys_spec parameter.
658910923SEvan.Yan@Sun.COM */
659010923SEvan.Yan@Sun.COM l = phys_spec.pci_size_low;
659110923SEvan.Yan@Sun.COM
659210923SEvan.Yan@Sun.COM if (PCI_REG_REG_G(phys_spec.pci_phys_hi) == PCI_CONF_ROM) {
659310923SEvan.Yan@Sun.COM
659410923SEvan.Yan@Sun.COM /* free memory back to the allocator */
659510923SEvan.Yan@Sun.COM if (ndi_ra_free(ddi_get_parent(dip), phys_spec.pci_phys_low,
659610923SEvan.Yan@Sun.COM l, NDI_RA_TYPE_MEM, NDI_RA_PASS) != NDI_SUCCESS) {
659710923SEvan.Yan@Sun.COM DEBUG0("(ROM)Can not free 32b mem");
659810923SEvan.Yan@Sun.COM pcicfg_unmap_phys(&h, &config);
659910923SEvan.Yan@Sun.COM return (1);
660010923SEvan.Yan@Sun.COM }
660110923SEvan.Yan@Sun.COM
660210923SEvan.Yan@Sun.COM /* Unmap the BAR by writing a zero */
660310923SEvan.Yan@Sun.COM
660410923SEvan.Yan@Sun.COM if ((flags & PCICFG_FLAG_READ_ONLY) == 0)
660510923SEvan.Yan@Sun.COM ddi_put32(h, (uint32_t *)v, (uint32_t)0);
660610923SEvan.Yan@Sun.COM } else {
660710923SEvan.Yan@Sun.COM
660810923SEvan.Yan@Sun.COM switch (PCI_REG_ADDR_G(phys_spec.pci_phys_hi)) {
6609*12765SScott.Carter@Oracle.COM
661010923SEvan.Yan@Sun.COM case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
6611*12765SScott.Carter@Oracle.COM case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
661210923SEvan.Yan@Sun.COM /* free memory back to the allocator */
661310923SEvan.Yan@Sun.COM if (ndi_ra_free(ddi_get_parent(dip),
661410923SEvan.Yan@Sun.COM PCICFG_LADDR(phys_spec.pci_phys_low,
661510923SEvan.Yan@Sun.COM phys_spec.pci_phys_mid),
661610923SEvan.Yan@Sun.COM l, NDI_RA_TYPE_MEM,
661710923SEvan.Yan@Sun.COM NDI_RA_PASS) != NDI_SUCCESS) {
6618*12765SScott.Carter@Oracle.COM DEBUG0("Cannot free mem");
661910923SEvan.Yan@Sun.COM pcicfg_unmap_phys(&h, &config);
662010923SEvan.Yan@Sun.COM return (1);
662110923SEvan.Yan@Sun.COM }
662210923SEvan.Yan@Sun.COM break;
662310923SEvan.Yan@Sun.COM
662410923SEvan.Yan@Sun.COM case PCI_REG_ADDR_G(PCI_ADDR_IO):
662510923SEvan.Yan@Sun.COM /* free I/O space back to the allocator */
662610923SEvan.Yan@Sun.COM if (ndi_ra_free(ddi_get_parent(dip),
662710923SEvan.Yan@Sun.COM phys_spec.pci_phys_low,
662810923SEvan.Yan@Sun.COM l, NDI_RA_TYPE_IO,
662910923SEvan.Yan@Sun.COM NDI_RA_PASS) != NDI_SUCCESS) {
663010923SEvan.Yan@Sun.COM DEBUG0("Can not free I/O space");
663110923SEvan.Yan@Sun.COM pcicfg_unmap_phys(&h, &config);
663210923SEvan.Yan@Sun.COM return (1);
663310923SEvan.Yan@Sun.COM }
663410923SEvan.Yan@Sun.COM break;
6635*12765SScott.Carter@Oracle.COM
663610923SEvan.Yan@Sun.COM default:
663710923SEvan.Yan@Sun.COM DEBUG0("Unknown register type\n");
663810923SEvan.Yan@Sun.COM pcicfg_unmap_phys(&h, &config);
663910923SEvan.Yan@Sun.COM return (1);
664010923SEvan.Yan@Sun.COM } /* switch */
664110923SEvan.Yan@Sun.COM }
664210923SEvan.Yan@Sun.COM
664310923SEvan.Yan@Sun.COM /*
664410923SEvan.Yan@Sun.COM * Now that memory locations are assigned,
664510923SEvan.Yan@Sun.COM * update the assigned address property.
664610923SEvan.Yan@Sun.COM */
664710923SEvan.Yan@Sun.COM
664810923SEvan.Yan@Sun.COM DEBUG1("updating assigned-addresss for %x\n", phys_spec.pci_phys_hi);
664910923SEvan.Yan@Sun.COM
665010923SEvan.Yan@Sun.COM if (pcicfg_remove_assigned_prop(dip, &phys_spec)) {
665110923SEvan.Yan@Sun.COM pcicfg_unmap_phys(&h, &config);
665210923SEvan.Yan@Sun.COM return (1);
665310923SEvan.Yan@Sun.COM }
665410923SEvan.Yan@Sun.COM
665510923SEvan.Yan@Sun.COM pcicfg_unmap_phys(&h, &config);
665610923SEvan.Yan@Sun.COM
665710923SEvan.Yan@Sun.COM return (0);
665810923SEvan.Yan@Sun.COM }
665910923SEvan.Yan@Sun.COM
666010923SEvan.Yan@Sun.COM static int
pcicfg_remove_assigned_prop(dev_info_t * dip,pci_regspec_t * oldone)666110923SEvan.Yan@Sun.COM pcicfg_remove_assigned_prop(dev_info_t *dip, pci_regspec_t *oldone)
666210923SEvan.Yan@Sun.COM {
666310923SEvan.Yan@Sun.COM int alen, num_entries, i;
666410923SEvan.Yan@Sun.COM pci_regspec_t *assigned, *assigned_copy;
666510923SEvan.Yan@Sun.COM uint_t status;
666610923SEvan.Yan@Sun.COM
666710923SEvan.Yan@Sun.COM status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
666810923SEvan.Yan@Sun.COM "assigned-addresses", (caddr_t)&assigned, &alen);
666910923SEvan.Yan@Sun.COM switch (status) {
667010923SEvan.Yan@Sun.COM case DDI_PROP_SUCCESS:
667110923SEvan.Yan@Sun.COM break;
667210923SEvan.Yan@Sun.COM case DDI_PROP_NO_MEMORY:
667310923SEvan.Yan@Sun.COM DEBUG0("no memory for assigned-addresses property\n");
667410923SEvan.Yan@Sun.COM return (1);
667510923SEvan.Yan@Sun.COM default:
667610923SEvan.Yan@Sun.COM DEBUG0("assigned-addresses property does not exist\n");
667710923SEvan.Yan@Sun.COM return (0);
667810923SEvan.Yan@Sun.COM }
667910923SEvan.Yan@Sun.COM
668010923SEvan.Yan@Sun.COM /*
668110923SEvan.Yan@Sun.COM * Make a copy of old assigned-addresses property.
668210923SEvan.Yan@Sun.COM */
668310923SEvan.Yan@Sun.COM assigned_copy = kmem_alloc(alen, KM_SLEEP);
668410923SEvan.Yan@Sun.COM bcopy(assigned, assigned_copy, alen);
668510923SEvan.Yan@Sun.COM
668610923SEvan.Yan@Sun.COM status = ndi_prop_remove(DDI_DEV_T_NONE, dip, "assigned-addresses");
668710923SEvan.Yan@Sun.COM
668810923SEvan.Yan@Sun.COM if (status != DDI_PROP_SUCCESS) {
668910923SEvan.Yan@Sun.COM /*
669010923SEvan.Yan@Sun.COM * If "assigned-addresses" is retrieved from PROM, the
669110923SEvan.Yan@Sun.COM * ndi_prop_remove() will fail.
669210923SEvan.Yan@Sun.COM */
669310923SEvan.Yan@Sun.COM DEBUG1("pcicfg_remove_assigned_prop: 0x%x not removed\n",
669410923SEvan.Yan@Sun.COM oldone->pci_phys_hi);
669510923SEvan.Yan@Sun.COM
669610923SEvan.Yan@Sun.COM /*
669710923SEvan.Yan@Sun.COM * Free up allocated memory
669810923SEvan.Yan@Sun.COM */
669910923SEvan.Yan@Sun.COM kmem_free(assigned_copy, alen);
670010923SEvan.Yan@Sun.COM kmem_free((caddr_t)assigned, alen);
670110923SEvan.Yan@Sun.COM
670210923SEvan.Yan@Sun.COM return (0);
670310923SEvan.Yan@Sun.COM }
670410923SEvan.Yan@Sun.COM
670510923SEvan.Yan@Sun.COM num_entries = alen / sizeof (pci_regspec_t);
670610923SEvan.Yan@Sun.COM
670710923SEvan.Yan@Sun.COM /*
670810923SEvan.Yan@Sun.COM * Rebuild the assigned-addresses property.
670910923SEvan.Yan@Sun.COM */
671010923SEvan.Yan@Sun.COM for (i = 0; i < num_entries; i++) {
671110923SEvan.Yan@Sun.COM if (assigned_copy[i].pci_phys_hi != oldone->pci_phys_hi) {
671210923SEvan.Yan@Sun.COM (void) pcicfg_update_assigned_prop(dip,
671310923SEvan.Yan@Sun.COM &assigned_copy[i]);
671410923SEvan.Yan@Sun.COM }
671510923SEvan.Yan@Sun.COM }
671610923SEvan.Yan@Sun.COM
671710923SEvan.Yan@Sun.COM /*
671810923SEvan.Yan@Sun.COM * Free the copy of the original assigned-addresses.
671910923SEvan.Yan@Sun.COM */
672010923SEvan.Yan@Sun.COM kmem_free(assigned_copy, alen);
672110923SEvan.Yan@Sun.COM
672210923SEvan.Yan@Sun.COM /*
672310923SEvan.Yan@Sun.COM * Don't forget to free up memory from ddi_getlongprop
672410923SEvan.Yan@Sun.COM */
672510923SEvan.Yan@Sun.COM kmem_free((caddr_t)assigned, alen);
672610923SEvan.Yan@Sun.COM
672710923SEvan.Yan@Sun.COM return (0);
672810923SEvan.Yan@Sun.COM }
672910923SEvan.Yan@Sun.COM
673010923SEvan.Yan@Sun.COM static int
pcicfg_map_phys(dev_info_t * dip,pci_regspec_t * phys_spec,caddr_t * addrp,ddi_device_acc_attr_t * accattrp,ddi_acc_handle_t * handlep)673110923SEvan.Yan@Sun.COM pcicfg_map_phys(dev_info_t *dip, pci_regspec_t *phys_spec,
673210923SEvan.Yan@Sun.COM caddr_t *addrp, ddi_device_acc_attr_t *accattrp,
673310923SEvan.Yan@Sun.COM ddi_acc_handle_t *handlep)
673410923SEvan.Yan@Sun.COM {
673510923SEvan.Yan@Sun.COM ddi_map_req_t mr;
673610923SEvan.Yan@Sun.COM ddi_acc_hdl_t *hp;
673710923SEvan.Yan@Sun.COM int result;
673810923SEvan.Yan@Sun.COM
673910923SEvan.Yan@Sun.COM *handlep = impl_acc_hdl_alloc(KM_SLEEP, NULL);
674010923SEvan.Yan@Sun.COM hp = impl_acc_hdl_get(*handlep);
674110923SEvan.Yan@Sun.COM hp->ah_vers = VERS_ACCHDL;
674210923SEvan.Yan@Sun.COM hp->ah_dip = dip;
674310923SEvan.Yan@Sun.COM hp->ah_rnumber = 0;
674410923SEvan.Yan@Sun.COM hp->ah_offset = 0;
674510923SEvan.Yan@Sun.COM hp->ah_len = 0;
674610923SEvan.Yan@Sun.COM hp->ah_acc = *accattrp;
674710923SEvan.Yan@Sun.COM
674810923SEvan.Yan@Sun.COM mr.map_op = DDI_MO_MAP_LOCKED;
674910923SEvan.Yan@Sun.COM mr.map_type = DDI_MT_REGSPEC;
675010923SEvan.Yan@Sun.COM mr.map_obj.rp = (struct regspec *)phys_spec;
675110923SEvan.Yan@Sun.COM mr.map_prot = PROT_READ | PROT_WRITE;
675210923SEvan.Yan@Sun.COM mr.map_flags = DDI_MF_KERNEL_MAPPING;
675310923SEvan.Yan@Sun.COM mr.map_handlep = hp;
675410923SEvan.Yan@Sun.COM mr.map_vers = DDI_MAP_VERSION;
675510923SEvan.Yan@Sun.COM
675610923SEvan.Yan@Sun.COM result = ddi_map(dip, &mr, 0, 0, addrp);
675710923SEvan.Yan@Sun.COM
675810923SEvan.Yan@Sun.COM if (result != DDI_SUCCESS) {
675910923SEvan.Yan@Sun.COM impl_acc_hdl_free(*handlep);
676010923SEvan.Yan@Sun.COM *handlep = (ddi_acc_handle_t)NULL;
676110923SEvan.Yan@Sun.COM } else {
676210923SEvan.Yan@Sun.COM hp->ah_addr = *addrp;
676310923SEvan.Yan@Sun.COM }
676410923SEvan.Yan@Sun.COM
676510923SEvan.Yan@Sun.COM return (result);
676610923SEvan.Yan@Sun.COM }
676710923SEvan.Yan@Sun.COM
676810923SEvan.Yan@Sun.COM void
pcicfg_unmap_phys(ddi_acc_handle_t * handlep,pci_regspec_t * ph)676910923SEvan.Yan@Sun.COM pcicfg_unmap_phys(ddi_acc_handle_t *handlep, pci_regspec_t *ph)
677010923SEvan.Yan@Sun.COM {
677110923SEvan.Yan@Sun.COM ddi_map_req_t mr;
677210923SEvan.Yan@Sun.COM ddi_acc_hdl_t *hp;
677310923SEvan.Yan@Sun.COM
677410923SEvan.Yan@Sun.COM hp = impl_acc_hdl_get(*handlep);
677510923SEvan.Yan@Sun.COM ASSERT(hp);
677610923SEvan.Yan@Sun.COM
677710923SEvan.Yan@Sun.COM mr.map_op = DDI_MO_UNMAP;
677810923SEvan.Yan@Sun.COM mr.map_type = DDI_MT_REGSPEC;
677910923SEvan.Yan@Sun.COM mr.map_obj.rp = (struct regspec *)ph;
678010923SEvan.Yan@Sun.COM mr.map_prot = PROT_READ | PROT_WRITE;
678110923SEvan.Yan@Sun.COM mr.map_flags = DDI_MF_KERNEL_MAPPING;
678210923SEvan.Yan@Sun.COM mr.map_handlep = hp;
678310923SEvan.Yan@Sun.COM mr.map_vers = DDI_MAP_VERSION;
678410923SEvan.Yan@Sun.COM
678510923SEvan.Yan@Sun.COM (void) ddi_map(hp->ah_dip, &mr, hp->ah_offset,
678610923SEvan.Yan@Sun.COM hp->ah_len, &hp->ah_addr);
678710923SEvan.Yan@Sun.COM
678810923SEvan.Yan@Sun.COM impl_acc_hdl_free(*handlep);
678910923SEvan.Yan@Sun.COM *handlep = (ddi_acc_handle_t)NULL;
679010923SEvan.Yan@Sun.COM }
679110923SEvan.Yan@Sun.COM
679210923SEvan.Yan@Sun.COM static int
pcicfg_ari_configure(dev_info_t * dip)679310923SEvan.Yan@Sun.COM pcicfg_ari_configure(dev_info_t *dip)
679410923SEvan.Yan@Sun.COM {
679510923SEvan.Yan@Sun.COM if (pcie_ari_supported(dip) == PCIE_ARI_FORW_NOT_SUPPORTED)
679610923SEvan.Yan@Sun.COM return (DDI_FAILURE);
679710923SEvan.Yan@Sun.COM
679810923SEvan.Yan@Sun.COM /*
679910923SEvan.Yan@Sun.COM * Until we have resource balancing, dynamically configure
680010923SEvan.Yan@Sun.COM * ARI functions without firmware assistamce.
680110923SEvan.Yan@Sun.COM */
680210923SEvan.Yan@Sun.COM return (DDI_FAILURE);
680310923SEvan.Yan@Sun.COM }
680410923SEvan.Yan@Sun.COM
680510923SEvan.Yan@Sun.COM #ifdef DEBUG
680610923SEvan.Yan@Sun.COM static void
debug(char * fmt,uintptr_t a1,uintptr_t a2,uintptr_t a3,uintptr_t a4,uintptr_t a5)680710923SEvan.Yan@Sun.COM debug(char *fmt, uintptr_t a1, uintptr_t a2, uintptr_t a3,
680810923SEvan.Yan@Sun.COM uintptr_t a4, uintptr_t a5)
680910923SEvan.Yan@Sun.COM {
681010923SEvan.Yan@Sun.COM if (pcicfg_debug == 1) {
681110923SEvan.Yan@Sun.COM prom_printf("pcicfg: ");
681210923SEvan.Yan@Sun.COM prom_printf(fmt, a1, a2, a3, a4, a5);
681310923SEvan.Yan@Sun.COM } else
681410923SEvan.Yan@Sun.COM if (pcicfg_debug)
681510923SEvan.Yan@Sun.COM cmn_err(CE_CONT, fmt, a1, a2, a3, a4, a5);
681610923SEvan.Yan@Sun.COM }
681710923SEvan.Yan@Sun.COM #endif
681811245SZhijun.Fu@Sun.COM
681911245SZhijun.Fu@Sun.COM /*
682011245SZhijun.Fu@Sun.COM * Return true if the devinfo node is in a PCI Express hierarchy.
682111245SZhijun.Fu@Sun.COM */
682211245SZhijun.Fu@Sun.COM static boolean_t
is_pcie_fabric(dev_info_t * dip)682311245SZhijun.Fu@Sun.COM is_pcie_fabric(dev_info_t *dip)
682411245SZhijun.Fu@Sun.COM {
682511245SZhijun.Fu@Sun.COM dev_info_t *root = ddi_root_node();
682611245SZhijun.Fu@Sun.COM dev_info_t *pdip;
682711245SZhijun.Fu@Sun.COM boolean_t found = B_FALSE;
682811245SZhijun.Fu@Sun.COM char *bus;
682911245SZhijun.Fu@Sun.COM
683011245SZhijun.Fu@Sun.COM /*
683111245SZhijun.Fu@Sun.COM * Does this device reside in a pcie fabric ?
683211245SZhijun.Fu@Sun.COM */
683311245SZhijun.Fu@Sun.COM for (pdip = dip; pdip && (pdip != root) && !found;
683411245SZhijun.Fu@Sun.COM pdip = ddi_get_parent(pdip)) {
683511245SZhijun.Fu@Sun.COM if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip,
683611245SZhijun.Fu@Sun.COM DDI_PROP_DONTPASS, "device_type", &bus) !=
683711245SZhijun.Fu@Sun.COM DDI_PROP_SUCCESS)
683811245SZhijun.Fu@Sun.COM break;
683911245SZhijun.Fu@Sun.COM
684011245SZhijun.Fu@Sun.COM if (strcmp(bus, "pciex") == 0)
684111245SZhijun.Fu@Sun.COM found = B_TRUE;
684211245SZhijun.Fu@Sun.COM
684311245SZhijun.Fu@Sun.COM ddi_prop_free(bus);
684411245SZhijun.Fu@Sun.COM }
684511245SZhijun.Fu@Sun.COM
684611245SZhijun.Fu@Sun.COM return (found);
684711245SZhijun.Fu@Sun.COM }
6848