17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 500d0963fSdilpreet * Common Development and Distribution License (the "License"). 600d0963fSdilpreet * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 2219397407SSherry Moore * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 25*cd21e7c5SGarrett D'Amore /* 26*cd21e7c5SGarrett D'Amore * Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved. 27*cd21e7c5SGarrett D'Amore */ 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate /* 317c478bd9Sstevel@tonic-gate * PCI to PCI bus bridge nexus driver 327c478bd9Sstevel@tonic-gate */ 337c478bd9Sstevel@tonic-gate 347c478bd9Sstevel@tonic-gate #include <sys/conf.h> 357c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 367c478bd9Sstevel@tonic-gate #include <sys/debug.h> 377c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 387c478bd9Sstevel@tonic-gate #include <sys/autoconf.h> 397c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 407c478bd9Sstevel@tonic-gate #include <sys/ddi_subrdefs.h> 417c478bd9Sstevel@tonic-gate #include <sys/ddifm.h> 427c478bd9Sstevel@tonic-gate #include <sys/fm/util.h> 437c478bd9Sstevel@tonic-gate #include <sys/fm/protocol.h> 447c478bd9Sstevel@tonic-gate #include <sys/fm/io/pci.h> 457c478bd9Sstevel@tonic-gate #include <sys/pci.h> 467c478bd9Sstevel@tonic-gate #include <sys/pci/pci_nexus.h> 477c478bd9Sstevel@tonic-gate #include <sys/pci/pci_regs.h> 487c478bd9Sstevel@tonic-gate #include <sys/pci/pci_simba.h> 497c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 507c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 517c478bd9Sstevel@tonic-gate #include <sys/sunndi.h> 527c478bd9Sstevel@tonic-gate #include <sys/promif.h> /* prom_printf */ 537c478bd9Sstevel@tonic-gate #include <sys/open.h> 547c478bd9Sstevel@tonic-gate #include <sys/stat.h> 557c478bd9Sstevel@tonic-gate #include <sys/file.h> 567c478bd9Sstevel@tonic-gate 577c478bd9Sstevel@tonic-gate #if defined(DEBUG) && !defined(lint) 587c478bd9Sstevel@tonic-gate static uint_t simba_debug_flags = 0; 597c478bd9Sstevel@tonic-gate #define D_IDENTIFY 0x00000001 607c478bd9Sstevel@tonic-gate #define D_ATTACH 0x00000002 617c478bd9Sstevel@tonic-gate #define D_DETACH 0x00000004 627c478bd9Sstevel@tonic-gate #define D_MAP 0x00000008 637c478bd9Sstevel@tonic-gate #define D_CTLOPS 0x00000010 647c478bd9Sstevel@tonic-gate #define D_G_ISPEC 0x00000020 657c478bd9Sstevel@tonic-gate #define D_A_ISPEC 0x00000040 667c478bd9Sstevel@tonic-gate #define D_INIT_CLD 0x00400000 677c478bd9Sstevel@tonic-gate #define D_FAULT 0x00000080 687c478bd9Sstevel@tonic-gate 697c478bd9Sstevel@tonic-gate #define DEBUG0(f, s) if ((f)& simba_debug_flags) \ 707c478bd9Sstevel@tonic-gate prom_printf("simba: " s "\n") 717c478bd9Sstevel@tonic-gate 727c478bd9Sstevel@tonic-gate #define DEBUG1(f, s, a) if ((f)& simba_debug_flags) \ 737c478bd9Sstevel@tonic-gate prom_printf("simba: " s "\n", a) 747c478bd9Sstevel@tonic-gate 757c478bd9Sstevel@tonic-gate #define DEBUG2(f, s, a, b) if ((f)& simba_debug_flags) \ 767c478bd9Sstevel@tonic-gate prom_printf("simba: " s "\n", a, b) 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate #define DEBUG3(f, s, a, b, c) if ((f)& simba_debug_flags) \ 797c478bd9Sstevel@tonic-gate prom_printf("simba: " s "\n", a, b, c) 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate #define DEBUG4(f, s, a, b, c, d) if ((f)& simba_debug_flags) \ 827c478bd9Sstevel@tonic-gate prom_printf("simba: " s "\n", a, b, c, d) 837c478bd9Sstevel@tonic-gate 847c478bd9Sstevel@tonic-gate #define DEBUG5(f, s, a, b, c, d, e) if ((f)& simba_debug_flags) \ 857c478bd9Sstevel@tonic-gate prom_printf("simba: " s "\n", a, b, c, d, e) 867c478bd9Sstevel@tonic-gate 877c478bd9Sstevel@tonic-gate #define DEBUG6(f, s, a, b, c, d, e, ff) if ((f)& simba_debug_flags) \ 887c478bd9Sstevel@tonic-gate prom_printf("simba: " s "\n", a, b, c, d, e, ff) 897c478bd9Sstevel@tonic-gate 907c478bd9Sstevel@tonic-gate #else 917c478bd9Sstevel@tonic-gate 927c478bd9Sstevel@tonic-gate #define DEBUG0(f, s) 937c478bd9Sstevel@tonic-gate #define DEBUG1(f, s, a) 947c478bd9Sstevel@tonic-gate #define DEBUG2(f, s, a, b) 957c478bd9Sstevel@tonic-gate #define DEBUG3(f, s, a, b, c) 967c478bd9Sstevel@tonic-gate #define DEBUG4(f, s, a, b, c, d) 977c478bd9Sstevel@tonic-gate #define DEBUG5(f, s, a, b, c, d, e) 987c478bd9Sstevel@tonic-gate #define DEBUG6(f, s, a, b, c, d, e, ff) 997c478bd9Sstevel@tonic-gate 1007c478bd9Sstevel@tonic-gate #endif 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate /* 1037c478bd9Sstevel@tonic-gate * The variable controls the default setting of the command register 1047c478bd9Sstevel@tonic-gate * for pci devices. See simba_initchild() for details. 1057c478bd9Sstevel@tonic-gate */ 1067c478bd9Sstevel@tonic-gate static ushort_t simba_command_default = PCI_COMM_SERR_ENABLE | 1077c478bd9Sstevel@tonic-gate PCI_COMM_WAIT_CYC_ENAB | 1087c478bd9Sstevel@tonic-gate PCI_COMM_PARITY_DETECT | 1097c478bd9Sstevel@tonic-gate PCI_COMM_ME | 1107c478bd9Sstevel@tonic-gate PCI_COMM_MAE | 1117c478bd9Sstevel@tonic-gate PCI_COMM_IO; 1127c478bd9Sstevel@tonic-gate 1137c478bd9Sstevel@tonic-gate static int simba_bus_map(dev_info_t *, dev_info_t *, ddi_map_req_t *, 1147c478bd9Sstevel@tonic-gate off_t, off_t, caddr_t *); 1157c478bd9Sstevel@tonic-gate static int simba_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, 1167c478bd9Sstevel@tonic-gate void *, void *); 1177c478bd9Sstevel@tonic-gate static int simba_fm_init_child(dev_info_t *dip, dev_info_t *tdip, int cap, 1187c478bd9Sstevel@tonic-gate ddi_iblock_cookie_t *ibc); 1197c478bd9Sstevel@tonic-gate static void simba_bus_enter(dev_info_t *dip, ddi_acc_handle_t handle); 1207c478bd9Sstevel@tonic-gate static void simba_bus_exit(dev_info_t *dip, ddi_acc_handle_t handle); 1217c478bd9Sstevel@tonic-gate 1227c478bd9Sstevel@tonic-gate struct bus_ops simba_bus_ops = { 1237c478bd9Sstevel@tonic-gate BUSO_REV, 1247c478bd9Sstevel@tonic-gate simba_bus_map, 1257c478bd9Sstevel@tonic-gate 0, 1267c478bd9Sstevel@tonic-gate 0, 1277c478bd9Sstevel@tonic-gate 0, 1287c478bd9Sstevel@tonic-gate i_ddi_map_fault, 129*cd21e7c5SGarrett D'Amore 0, 1307c478bd9Sstevel@tonic-gate ddi_dma_allochdl, 1317c478bd9Sstevel@tonic-gate ddi_dma_freehdl, 1327c478bd9Sstevel@tonic-gate ddi_dma_bindhdl, 1337c478bd9Sstevel@tonic-gate ddi_dma_unbindhdl, 1347c478bd9Sstevel@tonic-gate ddi_dma_flush, 1357c478bd9Sstevel@tonic-gate ddi_dma_win, 1367c478bd9Sstevel@tonic-gate ddi_dma_mctl, 1377c478bd9Sstevel@tonic-gate simba_ctlops, 1387c478bd9Sstevel@tonic-gate ddi_bus_prop_op, 1397c478bd9Sstevel@tonic-gate ndi_busop_get_eventcookie, 1407c478bd9Sstevel@tonic-gate ndi_busop_add_eventcall, 1417c478bd9Sstevel@tonic-gate ndi_busop_remove_eventcall, 1427c478bd9Sstevel@tonic-gate ndi_post_event, 1437c478bd9Sstevel@tonic-gate 0, 1447c478bd9Sstevel@tonic-gate 0, 1457c478bd9Sstevel@tonic-gate 0, 1467c478bd9Sstevel@tonic-gate simba_fm_init_child, 1477c478bd9Sstevel@tonic-gate NULL, 1487c478bd9Sstevel@tonic-gate simba_bus_enter, 1497c478bd9Sstevel@tonic-gate simba_bus_exit, 1507c478bd9Sstevel@tonic-gate 0, 1517c478bd9Sstevel@tonic-gate i_ddi_intr_ops 1527c478bd9Sstevel@tonic-gate }; 1537c478bd9Sstevel@tonic-gate 1547c478bd9Sstevel@tonic-gate static int simba_open(dev_t *devp, int flags, int otyp, cred_t *credp); 1557c478bd9Sstevel@tonic-gate static int simba_close(dev_t dev, int flags, int otyp, cred_t *credp); 1567c478bd9Sstevel@tonic-gate static int simba_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 1577c478bd9Sstevel@tonic-gate cred_t *credp, int *rvalp); 1587c478bd9Sstevel@tonic-gate 1597c478bd9Sstevel@tonic-gate static struct cb_ops simba_cb_ops = { 1607c478bd9Sstevel@tonic-gate simba_open, /* open */ 1617c478bd9Sstevel@tonic-gate simba_close, /* close */ 1627c478bd9Sstevel@tonic-gate nulldev, /* strategy */ 1637c478bd9Sstevel@tonic-gate nulldev, /* print */ 1647c478bd9Sstevel@tonic-gate nulldev, /* dump */ 1657c478bd9Sstevel@tonic-gate nulldev, /* read */ 1667c478bd9Sstevel@tonic-gate nulldev, /* write */ 1677c478bd9Sstevel@tonic-gate simba_ioctl, /* ioctl */ 1687c478bd9Sstevel@tonic-gate nodev, /* devmap */ 1697c478bd9Sstevel@tonic-gate nodev, /* mmap */ 1707c478bd9Sstevel@tonic-gate nodev, /* segmap */ 1717c478bd9Sstevel@tonic-gate nochpoll, /* poll */ 1727c478bd9Sstevel@tonic-gate ddi_prop_op, /* cb_prop_op */ 1737c478bd9Sstevel@tonic-gate NULL, /* streamtab */ 1747c478bd9Sstevel@tonic-gate D_NEW | D_MP | D_HOTPLUG, /* Driver compatibility flag */ 1757c478bd9Sstevel@tonic-gate CB_REV, /* rev */ 1767c478bd9Sstevel@tonic-gate nodev, /* int (*cb_aread)() */ 1777c478bd9Sstevel@tonic-gate nodev /* int (*cb_awrite)() */ 1787c478bd9Sstevel@tonic-gate }; 1797c478bd9Sstevel@tonic-gate 1807c478bd9Sstevel@tonic-gate static int simba_probe(dev_info_t *); 1817c478bd9Sstevel@tonic-gate static int simba_attach(dev_info_t *devi, ddi_attach_cmd_t cmd); 1827c478bd9Sstevel@tonic-gate static int simba_detach(dev_info_t *devi, ddi_detach_cmd_t cmd); 1837c478bd9Sstevel@tonic-gate static int simba_info(dev_info_t *dip, ddi_info_cmd_t infocmd, 1847c478bd9Sstevel@tonic-gate void *arg, void **result); 1857c478bd9Sstevel@tonic-gate 1867c478bd9Sstevel@tonic-gate struct dev_ops simba_ops = { 1877c478bd9Sstevel@tonic-gate DEVO_REV, /* devo_rev */ 1887c478bd9Sstevel@tonic-gate 0, /* refcnt */ 1897c478bd9Sstevel@tonic-gate simba_info, /* info */ 1907c478bd9Sstevel@tonic-gate nulldev, /* identify */ 1917c478bd9Sstevel@tonic-gate simba_probe, /* probe */ 1927c478bd9Sstevel@tonic-gate simba_attach, /* attach */ 1937c478bd9Sstevel@tonic-gate simba_detach, /* detach */ 1947c478bd9Sstevel@tonic-gate nulldev, /* reset */ 1957c478bd9Sstevel@tonic-gate &simba_cb_ops, /* driver operations */ 19619397407SSherry Moore &simba_bus_ops, /* bus operations */ 19719397407SSherry Moore NULL, 19819397407SSherry Moore ddi_quiesce_not_supported, /* devo_quiesce */ 1997c478bd9Sstevel@tonic-gate }; 2007c478bd9Sstevel@tonic-gate 2017c478bd9Sstevel@tonic-gate /* 2027c478bd9Sstevel@tonic-gate * Module linkage information for the kernel. 2037c478bd9Sstevel@tonic-gate */ 2047c478bd9Sstevel@tonic-gate 2057c478bd9Sstevel@tonic-gate static struct modldrv modldrv = { 2067c478bd9Sstevel@tonic-gate &mod_driverops, /* Type of module */ 20719397407SSherry Moore "SIMBA PCI to PCI bridge nexus driver", 2087c478bd9Sstevel@tonic-gate &simba_ops, /* driver ops */ 2097c478bd9Sstevel@tonic-gate }; 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 2127c478bd9Sstevel@tonic-gate MODREV_1, 2137c478bd9Sstevel@tonic-gate (void *)&modldrv, 2147c478bd9Sstevel@tonic-gate NULL 2157c478bd9Sstevel@tonic-gate }; 2167c478bd9Sstevel@tonic-gate 2177c478bd9Sstevel@tonic-gate /* 2187c478bd9Sstevel@tonic-gate * Simba specific error state structure 2197c478bd9Sstevel@tonic-gate */ 220f47a9c50Smathue struct simba_errstate { 2217c478bd9Sstevel@tonic-gate char *error; 2227c478bd9Sstevel@tonic-gate ushort_t pci_cfg_stat; 2237c478bd9Sstevel@tonic-gate ushort_t pci_cfg_sec_stat; 2247c478bd9Sstevel@tonic-gate uint64_t afsr; 2257c478bd9Sstevel@tonic-gate uint64_t afar; 2267c478bd9Sstevel@tonic-gate int bridge_secondary; 2277c478bd9Sstevel@tonic-gate }; 2287c478bd9Sstevel@tonic-gate 229f47a9c50Smathue struct simba_cfg_state { 2307c478bd9Sstevel@tonic-gate dev_info_t *dip; 2317c478bd9Sstevel@tonic-gate ushort_t command; 2327c478bd9Sstevel@tonic-gate uchar_t cache_line_size; 2337c478bd9Sstevel@tonic-gate uchar_t latency_timer; 2347c478bd9Sstevel@tonic-gate uchar_t header_type; 2357c478bd9Sstevel@tonic-gate uchar_t bus_number; 2367c478bd9Sstevel@tonic-gate uchar_t sec_bus_number; 2377c478bd9Sstevel@tonic-gate uchar_t sub_bus_number; 2387c478bd9Sstevel@tonic-gate uchar_t sec_latency_timer; 2397c478bd9Sstevel@tonic-gate ushort_t bridge_control; 2407c478bd9Sstevel@tonic-gate }; 2417c478bd9Sstevel@tonic-gate 2427c478bd9Sstevel@tonic-gate /* 2437c478bd9Sstevel@tonic-gate * soft state pointer and structure template: 2447c478bd9Sstevel@tonic-gate */ 2457c478bd9Sstevel@tonic-gate static void *simba_state; 2467c478bd9Sstevel@tonic-gate 2477c478bd9Sstevel@tonic-gate typedef struct { 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate dev_info_t *dip; 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate /* 2527c478bd9Sstevel@tonic-gate * configuration register state for the bus: 2537c478bd9Sstevel@tonic-gate */ 2547c478bd9Sstevel@tonic-gate ddi_acc_handle_t config_handle; 2557c478bd9Sstevel@tonic-gate uchar_t simba_cache_line_size; 2567c478bd9Sstevel@tonic-gate uchar_t simba_latency_timer; 2577c478bd9Sstevel@tonic-gate 2587c478bd9Sstevel@tonic-gate /* 2597c478bd9Sstevel@tonic-gate * cpr support: 2607c478bd9Sstevel@tonic-gate */ 2617c478bd9Sstevel@tonic-gate uint_t config_state_index; 2627c478bd9Sstevel@tonic-gate struct simba_cfg_state *simba_config_state_p; 2637c478bd9Sstevel@tonic-gate ddi_iblock_cookie_t fm_ibc; 2647c478bd9Sstevel@tonic-gate int fm_cap; 2657c478bd9Sstevel@tonic-gate kmutex_t simba_mutex; 2667c478bd9Sstevel@tonic-gate uint_t simba_soft_state; 2677c478bd9Sstevel@tonic-gate #define SIMBA_SOFT_STATE_CLOSED 0x00 2687c478bd9Sstevel@tonic-gate #define SIMBA_SOFT_STATE_OPEN 0x01 2697c478bd9Sstevel@tonic-gate #define SIMBA_SOFT_STATE_OPEN_EXCL 0x02 2707c478bd9Sstevel@tonic-gate } simba_devstate_t; 2717c478bd9Sstevel@tonic-gate 2727c478bd9Sstevel@tonic-gate /* 2737c478bd9Sstevel@tonic-gate * The following variable enables a workaround for the following obp bug: 2747c478bd9Sstevel@tonic-gate * 2757c478bd9Sstevel@tonic-gate * 1234181 - obp should set latency timer registers in pci 2767c478bd9Sstevel@tonic-gate * configuration header 2777c478bd9Sstevel@tonic-gate * 2787c478bd9Sstevel@tonic-gate * Until this bug gets fixed in the obp, the following workaround should 2797c478bd9Sstevel@tonic-gate * be enabled. 2807c478bd9Sstevel@tonic-gate */ 2817c478bd9Sstevel@tonic-gate static uint_t simba_set_latency_timer_register = 1; 2827c478bd9Sstevel@tonic-gate 2837c478bd9Sstevel@tonic-gate /* 2847c478bd9Sstevel@tonic-gate * The following variable enables a workaround for an obp bug to be 2857c478bd9Sstevel@tonic-gate * submitted. A bug requesting a workaround fof this problem has 2867c478bd9Sstevel@tonic-gate * been filed: 2877c478bd9Sstevel@tonic-gate * 2887c478bd9Sstevel@tonic-gate * 1235094 - need workarounds on positron nexus drivers to set cache 2897c478bd9Sstevel@tonic-gate * line size registers 2907c478bd9Sstevel@tonic-gate * 2917c478bd9Sstevel@tonic-gate * Until this bug gets fixed in the obp, the following workaround should 2927c478bd9Sstevel@tonic-gate * be enabled. 2937c478bd9Sstevel@tonic-gate */ 2947c478bd9Sstevel@tonic-gate static uint_t simba_set_cache_line_size_register = 1; 2957c478bd9Sstevel@tonic-gate 2967c478bd9Sstevel@tonic-gate 2977c478bd9Sstevel@tonic-gate /* 2987c478bd9Sstevel@tonic-gate * forward function declarations: 2997c478bd9Sstevel@tonic-gate */ 3007c478bd9Sstevel@tonic-gate static void simba_uninitchild(dev_info_t *); 3017c478bd9Sstevel@tonic-gate static int simba_initchild(dev_info_t *child); 3027c478bd9Sstevel@tonic-gate static void simba_save_config_regs(simba_devstate_t *simba_p); 3037c478bd9Sstevel@tonic-gate static void simba_restore_config_regs(simba_devstate_t *simba_p); 3047c478bd9Sstevel@tonic-gate static int simba_err_callback(dev_info_t *dip, ddi_fm_error_t *derr, 3057c478bd9Sstevel@tonic-gate const void *impl_data); 3067c478bd9Sstevel@tonic-gate 3077c478bd9Sstevel@tonic-gate int 3087c478bd9Sstevel@tonic-gate _init(void) 3097c478bd9Sstevel@tonic-gate { 3107c478bd9Sstevel@tonic-gate int e; 3117c478bd9Sstevel@tonic-gate 3127c478bd9Sstevel@tonic-gate DEBUG0(D_ATTACH, "_init() installing module...\n"); 3137c478bd9Sstevel@tonic-gate if ((e = ddi_soft_state_init(&simba_state, sizeof (simba_devstate_t), 3147c478bd9Sstevel@tonic-gate 1)) == 0 && (e = mod_install(&modlinkage)) != 0) 3157c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&simba_state); 3167c478bd9Sstevel@tonic-gate 3177c478bd9Sstevel@tonic-gate DEBUG0(D_ATTACH, "_init() module installed\n"); 3187c478bd9Sstevel@tonic-gate return (e); 3197c478bd9Sstevel@tonic-gate } 3207c478bd9Sstevel@tonic-gate 3217c478bd9Sstevel@tonic-gate int 3227c478bd9Sstevel@tonic-gate _fini(void) 3237c478bd9Sstevel@tonic-gate { 3247c478bd9Sstevel@tonic-gate int e; 3257c478bd9Sstevel@tonic-gate DEBUG0(D_ATTACH, "_fini() removing module...\n"); 3267c478bd9Sstevel@tonic-gate if ((e = mod_remove(&modlinkage)) == 0) 3277c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&simba_state); 3287c478bd9Sstevel@tonic-gate return (e); 3297c478bd9Sstevel@tonic-gate } 3307c478bd9Sstevel@tonic-gate 3317c478bd9Sstevel@tonic-gate int 3327c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 3337c478bd9Sstevel@tonic-gate { 3347c478bd9Sstevel@tonic-gate DEBUG0(D_ATTACH, "_info() called.\n"); 3357c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 3367c478bd9Sstevel@tonic-gate } 3377c478bd9Sstevel@tonic-gate 3387c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3397c478bd9Sstevel@tonic-gate static int 3407c478bd9Sstevel@tonic-gate simba_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 3417c478bd9Sstevel@tonic-gate { 3427c478bd9Sstevel@tonic-gate simba_devstate_t *simba_p; /* per simba state pointer */ 3437c478bd9Sstevel@tonic-gate int instance; 3447c478bd9Sstevel@tonic-gate 3457c478bd9Sstevel@tonic-gate instance = getminor((dev_t)arg); 3467c478bd9Sstevel@tonic-gate simba_p = (simba_devstate_t *)ddi_get_soft_state(simba_state, 3477c478bd9Sstevel@tonic-gate instance); 3487c478bd9Sstevel@tonic-gate 3497c478bd9Sstevel@tonic-gate switch (infocmd) { 3507c478bd9Sstevel@tonic-gate default: 3517c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3527c478bd9Sstevel@tonic-gate 3537c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 354f47a9c50Smathue *result = (void *)(uintptr_t)instance; 3557c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 3567c478bd9Sstevel@tonic-gate 3577c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 3587c478bd9Sstevel@tonic-gate if (simba_p == NULL) 3597c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3607c478bd9Sstevel@tonic-gate *result = (void *)simba_p->dip; 3617c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 3627c478bd9Sstevel@tonic-gate } 3637c478bd9Sstevel@tonic-gate } 3647c478bd9Sstevel@tonic-gate 3657c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3667c478bd9Sstevel@tonic-gate static int 3677c478bd9Sstevel@tonic-gate simba_probe(register dev_info_t *devi) 3687c478bd9Sstevel@tonic-gate { 3697c478bd9Sstevel@tonic-gate DEBUG0(D_ATTACH, "simba_probe() called.\n"); 3707c478bd9Sstevel@tonic-gate return (DDI_PROBE_SUCCESS); 3717c478bd9Sstevel@tonic-gate } 3727c478bd9Sstevel@tonic-gate 3737c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3747c478bd9Sstevel@tonic-gate static int 3757c478bd9Sstevel@tonic-gate simba_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 3767c478bd9Sstevel@tonic-gate { 3777c478bd9Sstevel@tonic-gate int instance; 3787c478bd9Sstevel@tonic-gate simba_devstate_t *simba; 3797c478bd9Sstevel@tonic-gate 3807c478bd9Sstevel@tonic-gate switch (cmd) { 3817c478bd9Sstevel@tonic-gate case DDI_ATTACH: 3827c478bd9Sstevel@tonic-gate 383f47a9c50Smathue DEBUG1(D_ATTACH, "attach(%p) ATTACH\n", devi); 3847c478bd9Sstevel@tonic-gate 3857c478bd9Sstevel@tonic-gate /* 3867c478bd9Sstevel@tonic-gate * Make sure the "device_type" property exists. 3877c478bd9Sstevel@tonic-gate */ 3887c478bd9Sstevel@tonic-gate (void) ddi_prop_update_string(DDI_DEV_T_NONE, devi, 3897c478bd9Sstevel@tonic-gate "device_type", "pci"); 3907c478bd9Sstevel@tonic-gate 3917c478bd9Sstevel@tonic-gate /* 3927c478bd9Sstevel@tonic-gate * Allocate and get soft state structure. 3937c478bd9Sstevel@tonic-gate */ 3947c478bd9Sstevel@tonic-gate instance = ddi_get_instance(devi); 3957c478bd9Sstevel@tonic-gate if (ddi_soft_state_zalloc(simba_state, instance) != DDI_SUCCESS) 3967c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3977c478bd9Sstevel@tonic-gate simba = (simba_devstate_t *)ddi_get_soft_state(simba_state, 3987c478bd9Sstevel@tonic-gate instance); 3997c478bd9Sstevel@tonic-gate simba->dip = devi; 4007c478bd9Sstevel@tonic-gate mutex_init(&simba->simba_mutex, NULL, MUTEX_DRIVER, NULL); 4017c478bd9Sstevel@tonic-gate simba->simba_soft_state = SIMBA_SOFT_STATE_CLOSED; 4027c478bd9Sstevel@tonic-gate 4037c478bd9Sstevel@tonic-gate /* 4047c478bd9Sstevel@tonic-gate * create minor node for devctl interfaces 4057c478bd9Sstevel@tonic-gate */ 4067c478bd9Sstevel@tonic-gate if (ddi_create_minor_node(devi, "devctl", S_IFCHR, instance, 4077c478bd9Sstevel@tonic-gate DDI_NT_NEXUS, 0) != DDI_SUCCESS) { 4087c478bd9Sstevel@tonic-gate mutex_destroy(&simba->simba_mutex); 4097c478bd9Sstevel@tonic-gate ddi_soft_state_free(simba_state, instance); 4107c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 4117c478bd9Sstevel@tonic-gate } 4127c478bd9Sstevel@tonic-gate 4137c478bd9Sstevel@tonic-gate if (pci_config_setup(devi, &simba->config_handle) != 4147c478bd9Sstevel@tonic-gate DDI_SUCCESS) { 4157c478bd9Sstevel@tonic-gate ddi_remove_minor_node(devi, "devctl"); 4167c478bd9Sstevel@tonic-gate mutex_destroy(&simba->simba_mutex); 4177c478bd9Sstevel@tonic-gate ddi_soft_state_free(simba_state, instance); 4187c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 4197c478bd9Sstevel@tonic-gate } 4207c478bd9Sstevel@tonic-gate 4217c478bd9Sstevel@tonic-gate /* 4227c478bd9Sstevel@tonic-gate * Simba cache line size is 64 bytes and hardwired. 4237c478bd9Sstevel@tonic-gate */ 4247c478bd9Sstevel@tonic-gate simba->simba_cache_line_size = 4257c478bd9Sstevel@tonic-gate pci_config_get8(simba->config_handle, 4267c478bd9Sstevel@tonic-gate PCI_CONF_CACHE_LINESZ); 4277c478bd9Sstevel@tonic-gate simba->simba_latency_timer = 4287c478bd9Sstevel@tonic-gate pci_config_get8(simba->config_handle, 4297c478bd9Sstevel@tonic-gate PCI_CONF_LATENCY_TIMER); 4307c478bd9Sstevel@tonic-gate 4317c478bd9Sstevel@tonic-gate /* simba specific, clears up the pri/sec status registers */ 4327c478bd9Sstevel@tonic-gate pci_config_put16(simba->config_handle, 0x6, 0xffff); 4337c478bd9Sstevel@tonic-gate pci_config_put16(simba->config_handle, 0x1e, 0xffff); 4347c478bd9Sstevel@tonic-gate 4357c478bd9Sstevel@tonic-gate DEBUG2(D_ATTACH, "simba_attach(): clsz=%x, lt=%x\n", 4367c478bd9Sstevel@tonic-gate simba->simba_cache_line_size, 4377c478bd9Sstevel@tonic-gate simba->simba_latency_timer); 4387c478bd9Sstevel@tonic-gate 4397c478bd9Sstevel@tonic-gate /* 4407c478bd9Sstevel@tonic-gate * Initialize FMA support 4417c478bd9Sstevel@tonic-gate */ 4427c478bd9Sstevel@tonic-gate simba->fm_cap = DDI_FM_EREPORT_CAPABLE | DDI_FM_ERRCB_CAPABLE | 4437c478bd9Sstevel@tonic-gate DDI_FM_ACCCHK_CAPABLE | DDI_FM_DMACHK_CAPABLE; 4447c478bd9Sstevel@tonic-gate 4457c478bd9Sstevel@tonic-gate /* 4467c478bd9Sstevel@tonic-gate * Call parent to get it's capablity 4477c478bd9Sstevel@tonic-gate */ 4487c478bd9Sstevel@tonic-gate ddi_fm_init(devi, &simba->fm_cap, &simba->fm_ibc); 4497c478bd9Sstevel@tonic-gate 4507c478bd9Sstevel@tonic-gate ASSERT((simba->fm_cap & DDI_FM_ERRCB_CAPABLE) && 4517c478bd9Sstevel@tonic-gate (simba->fm_cap & DDI_FM_EREPORT_CAPABLE)); 4527c478bd9Sstevel@tonic-gate 4537c478bd9Sstevel@tonic-gate pci_ereport_setup(devi); 4547c478bd9Sstevel@tonic-gate 4557c478bd9Sstevel@tonic-gate ddi_fm_handler_register(devi, simba_err_callback, simba); 4567c478bd9Sstevel@tonic-gate 4577c478bd9Sstevel@tonic-gate ddi_report_dev(devi); 4587c478bd9Sstevel@tonic-gate DEBUG0(D_ATTACH, "attach(): ATTACH done\n"); 4597c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 4607c478bd9Sstevel@tonic-gate 4617c478bd9Sstevel@tonic-gate case DDI_RESUME: 4627c478bd9Sstevel@tonic-gate 4637c478bd9Sstevel@tonic-gate /* 4647c478bd9Sstevel@tonic-gate * Get the soft state structure for the bridge. 4657c478bd9Sstevel@tonic-gate */ 4667c478bd9Sstevel@tonic-gate simba = (simba_devstate_t *) 4677c478bd9Sstevel@tonic-gate ddi_get_soft_state(simba_state, ddi_get_instance(devi)); 4687c478bd9Sstevel@tonic-gate simba_restore_config_regs(simba); 4697c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 4707c478bd9Sstevel@tonic-gate } 4717c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 4727c478bd9Sstevel@tonic-gate } 4737c478bd9Sstevel@tonic-gate 4747c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4757c478bd9Sstevel@tonic-gate static int 4767c478bd9Sstevel@tonic-gate simba_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) 4777c478bd9Sstevel@tonic-gate { 4787c478bd9Sstevel@tonic-gate simba_devstate_t *simba; 4797c478bd9Sstevel@tonic-gate simba = (simba_devstate_t *) 4807c478bd9Sstevel@tonic-gate ddi_get_soft_state(simba_state, ddi_get_instance(devi)); 4817c478bd9Sstevel@tonic-gate 4827c478bd9Sstevel@tonic-gate switch (cmd) { 4837c478bd9Sstevel@tonic-gate case DDI_DETACH: 4847c478bd9Sstevel@tonic-gate DEBUG0(D_DETACH, "detach() called\n"); 4857c478bd9Sstevel@tonic-gate ddi_fm_handler_unregister(devi); 4867c478bd9Sstevel@tonic-gate pci_ereport_teardown(devi); 4877c478bd9Sstevel@tonic-gate ddi_fm_fini(devi); 4887c478bd9Sstevel@tonic-gate pci_config_teardown(&simba->config_handle); 4897c478bd9Sstevel@tonic-gate (void) ddi_prop_remove(DDI_DEV_T_NONE, devi, "device_type"); 4907c478bd9Sstevel@tonic-gate ddi_remove_minor_node(devi, "devctl"); 4917c478bd9Sstevel@tonic-gate mutex_destroy(&simba->simba_mutex); 4927c478bd9Sstevel@tonic-gate ddi_soft_state_free(simba_state, ddi_get_instance(devi)); 4937c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 4947c478bd9Sstevel@tonic-gate 4957c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 4967c478bd9Sstevel@tonic-gate simba_save_config_regs(simba); 4977c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 4987c478bd9Sstevel@tonic-gate } 4997c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 5007c478bd9Sstevel@tonic-gate } 5017c478bd9Sstevel@tonic-gate 5027c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5037c478bd9Sstevel@tonic-gate static int 5047c478bd9Sstevel@tonic-gate simba_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 5057c478bd9Sstevel@tonic-gate off_t offset, off_t len, caddr_t *vaddrp) 5067c478bd9Sstevel@tonic-gate { 5077c478bd9Sstevel@tonic-gate register dev_info_t *pdip; 5087c478bd9Sstevel@tonic-gate 509f47a9c50Smathue DEBUG3(D_MAP, "simba_bus_map(): dip=%p, rdip=%p, mp=%p", dip, rdip, mp); 510f47a9c50Smathue DEBUG3(D_MAP, "simba_bus_map(): offset=%lx, len=%lx, vaddrp=%p", 5117c478bd9Sstevel@tonic-gate offset, len, vaddrp); 5127c478bd9Sstevel@tonic-gate 5137c478bd9Sstevel@tonic-gate pdip = (dev_info_t *)DEVI(dip)->devi_parent; 5147c478bd9Sstevel@tonic-gate return ((DEVI(pdip)->devi_ops->devo_bus_ops->bus_map) 5157c478bd9Sstevel@tonic-gate (pdip, rdip, mp, offset, len, vaddrp)); 5167c478bd9Sstevel@tonic-gate } 5177c478bd9Sstevel@tonic-gate 5187c478bd9Sstevel@tonic-gate /* 5197c478bd9Sstevel@tonic-gate * Registered error handling callback with our parent 5207c478bd9Sstevel@tonic-gate */ 5217c478bd9Sstevel@tonic-gate static int 5227c478bd9Sstevel@tonic-gate simba_err_callback(dev_info_t *dip, ddi_fm_error_t *derr, const void *impl_data) 5237c478bd9Sstevel@tonic-gate { 5247c478bd9Sstevel@tonic-gate simba_devstate_t *simba = (simba_devstate_t *)impl_data; 5257c478bd9Sstevel@tonic-gate struct simba_errstate simba_err; 5267c478bd9Sstevel@tonic-gate int ret = 0; 5277c478bd9Sstevel@tonic-gate 5287c478bd9Sstevel@tonic-gate bzero(&simba_err, sizeof (struct simba_errstate)); 5297c478bd9Sstevel@tonic-gate simba_err.afsr = pci_config_get64(simba->config_handle, 0xe8); 5307c478bd9Sstevel@tonic-gate simba_err.afar = pci_config_get64(simba->config_handle, 0xf0); 5317c478bd9Sstevel@tonic-gate derr->fme_ena = fm_ena_generate(0, FM_ENA_FMT1); 5327c478bd9Sstevel@tonic-gate 53300d0963fSdilpreet pci_ereport_post(dip, derr, NULL); 53400d0963fSdilpreet ret = derr->fme_status; 5357c478bd9Sstevel@tonic-gate 5367c478bd9Sstevel@tonic-gate DEBUG6(D_FAULT, "%s-%d: cleaning up fault bits %x %x %x.%8x\n", 53700d0963fSdilpreet ddi_driver_name(simba->dip), ddi_get_instance(simba->dip), 53800d0963fSdilpreet simba_err.pci_cfg_stat, simba_err.pci_cfg_sec_stat, 53900d0963fSdilpreet (uint_t)(simba_err.afsr >> 32), (uint_t)simba_err.afsr); 5407c478bd9Sstevel@tonic-gate pci_config_put64(simba->config_handle, 0xe8, simba_err.afsr); 5417c478bd9Sstevel@tonic-gate 5427c478bd9Sstevel@tonic-gate return (ret); 5437c478bd9Sstevel@tonic-gate } 5447c478bd9Sstevel@tonic-gate 5457c478bd9Sstevel@tonic-gate #if defined(DEBUG) && !defined(lint) 5467c478bd9Sstevel@tonic-gate static char *ops[] = 5477c478bd9Sstevel@tonic-gate { 5487c478bd9Sstevel@tonic-gate "DDI_CTLOPS_DMAPMAPC", 5497c478bd9Sstevel@tonic-gate "DDI_CTLOPS_INITCHILD", 5507c478bd9Sstevel@tonic-gate "DDI_CTLOPS_UNINITCHILD", 5517c478bd9Sstevel@tonic-gate "DDI_CTLOPS_REPORTDEV", 5527c478bd9Sstevel@tonic-gate "DDI_CTLOPS_REPORTINT", 5537c478bd9Sstevel@tonic-gate "DDI_CTLOPS_REGSIZE", 5547c478bd9Sstevel@tonic-gate "DDI_CTLOPS_NREGS", 555a195726fSgovinda "DDI_CTLOPS_RESERVED0", 5567c478bd9Sstevel@tonic-gate "DDI_CTLOPS_SIDDEV", 5577c478bd9Sstevel@tonic-gate "DDI_CTLOPS_SLAVEONLY", 5587c478bd9Sstevel@tonic-gate "DDI_CTLOPS_AFFINITY", 5597c478bd9Sstevel@tonic-gate "DDI_CTLOPS_IOMIN", 5607c478bd9Sstevel@tonic-gate "DDI_CTLOPS_PTOB", 5617c478bd9Sstevel@tonic-gate "DDI_CTLOPS_BTOP", 5627c478bd9Sstevel@tonic-gate "DDI_CTLOPS_BTOPR", 5637c478bd9Sstevel@tonic-gate "DDI_CTLOPS_RESERVED1", 5647c478bd9Sstevel@tonic-gate "DDI_CTLOPS_RESERVED2", 5657c478bd9Sstevel@tonic-gate "DDI_CTLOPS_RESERVED3", 566a195726fSgovinda "DDI_CTLOPS_RESERVED4", 567a195726fSgovinda "DDI_CTLOPS_RESERVED5", 5687c478bd9Sstevel@tonic-gate "DDI_CTLOPS_DVMAPAGESIZE", 5697c478bd9Sstevel@tonic-gate "DDI_CTLOPS_POWER", 5707c478bd9Sstevel@tonic-gate "DDI_CTLOPS_ATTACH", 5717c478bd9Sstevel@tonic-gate "DDI_CTLOPS_DETACH", 5727c478bd9Sstevel@tonic-gate "DDI_CTLOPS_POKE", 5737c478bd9Sstevel@tonic-gate "DDI_CTLOPS_PEEK" 5747c478bd9Sstevel@tonic-gate }; 5757c478bd9Sstevel@tonic-gate #endif 5767c478bd9Sstevel@tonic-gate 5777c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5787c478bd9Sstevel@tonic-gate static int 5797c478bd9Sstevel@tonic-gate simba_ctlops(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop, 5807c478bd9Sstevel@tonic-gate void *arg, void *result) 5817c478bd9Sstevel@tonic-gate { 5827c478bd9Sstevel@tonic-gate int reglen; 5837c478bd9Sstevel@tonic-gate int rn; 5847c478bd9Sstevel@tonic-gate int totreg; 5857c478bd9Sstevel@tonic-gate pci_regspec_t *drv_regp; 5867c478bd9Sstevel@tonic-gate 5877c478bd9Sstevel@tonic-gate DEBUG6(D_CTLOPS, 588f47a9c50Smathue "simba_ctlops(): dip=%p rdip=%p ctlop=%x-%s arg=%p result=%p", 5897c478bd9Sstevel@tonic-gate dip, rdip, ctlop, ctlop < (sizeof (ops) / sizeof (ops[0])) ? 5907c478bd9Sstevel@tonic-gate ops[ctlop] : "Unknown", arg, result); 5917c478bd9Sstevel@tonic-gate 5927c478bd9Sstevel@tonic-gate switch (ctlop) { 5937c478bd9Sstevel@tonic-gate case DDI_CTLOPS_REPORTDEV: 5947c478bd9Sstevel@tonic-gate if (rdip == (dev_info_t *)0) 5957c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 5967c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "?PCI-device: %s@%s, %s%d\n", 5977c478bd9Sstevel@tonic-gate ddi_node_name(rdip), ddi_get_name_addr(rdip), 5987c478bd9Sstevel@tonic-gate ddi_driver_name(rdip), 5997c478bd9Sstevel@tonic-gate ddi_get_instance(rdip)); 6007c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 6017c478bd9Sstevel@tonic-gate 6027c478bd9Sstevel@tonic-gate case DDI_CTLOPS_INITCHILD: 6037c478bd9Sstevel@tonic-gate return (simba_initchild((dev_info_t *)arg)); 6047c478bd9Sstevel@tonic-gate 6057c478bd9Sstevel@tonic-gate case DDI_CTLOPS_UNINITCHILD: 6067c478bd9Sstevel@tonic-gate simba_uninitchild((dev_info_t *)arg); 6077c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 6087c478bd9Sstevel@tonic-gate 6097c478bd9Sstevel@tonic-gate case DDI_CTLOPS_SIDDEV: 6107c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 6117c478bd9Sstevel@tonic-gate 6127c478bd9Sstevel@tonic-gate case DDI_CTLOPS_REGSIZE: 6137c478bd9Sstevel@tonic-gate case DDI_CTLOPS_NREGS: 6147c478bd9Sstevel@tonic-gate if (rdip == (dev_info_t *)0) 6157c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6167c478bd9Sstevel@tonic-gate break; 6177c478bd9Sstevel@tonic-gate 6187c478bd9Sstevel@tonic-gate default: 6197c478bd9Sstevel@tonic-gate DEBUG0(D_CTLOPS, "simba_ctlops(): calling ddi_ctlops()"); 6207c478bd9Sstevel@tonic-gate return (ddi_ctlops(dip, rdip, ctlop, arg, result)); 6217c478bd9Sstevel@tonic-gate } 6227c478bd9Sstevel@tonic-gate 6237c478bd9Sstevel@tonic-gate *(int *)result = 0; 624a3282898Scth if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, 6257c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "reg", 6267c478bd9Sstevel@tonic-gate (caddr_t)&drv_regp, ®len) != DDI_SUCCESS) 6277c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6287c478bd9Sstevel@tonic-gate 6297c478bd9Sstevel@tonic-gate totreg = reglen / sizeof (pci_regspec_t); 6307c478bd9Sstevel@tonic-gate if (ctlop == DDI_CTLOPS_NREGS) 6317c478bd9Sstevel@tonic-gate *(int *)result = totreg; 6327c478bd9Sstevel@tonic-gate else if (ctlop == DDI_CTLOPS_REGSIZE) { 6337c478bd9Sstevel@tonic-gate rn = *(int *)arg; 6347c478bd9Sstevel@tonic-gate if (rn >= totreg) { 6357c478bd9Sstevel@tonic-gate kmem_free(drv_regp, reglen); 6367c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6377c478bd9Sstevel@tonic-gate } 6387c478bd9Sstevel@tonic-gate *(off_t *)result = drv_regp[rn].pci_size_low | 6397c478bd9Sstevel@tonic-gate ((uint64_t)drv_regp[rn].pci_size_hi << 32); 6407c478bd9Sstevel@tonic-gate } 6417c478bd9Sstevel@tonic-gate 6427c478bd9Sstevel@tonic-gate kmem_free(drv_regp, reglen); 643f47a9c50Smathue DEBUG1(D_CTLOPS, "simba_ctlops(): *result=%lx\n", *(off_t *)result); 6447c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 6457c478bd9Sstevel@tonic-gate } 6467c478bd9Sstevel@tonic-gate 6477c478bd9Sstevel@tonic-gate static int 6487c478bd9Sstevel@tonic-gate simba_name_child(dev_info_t *child, char *name, int namelen) 6497c478bd9Sstevel@tonic-gate { 6507c478bd9Sstevel@tonic-gate uint_t n, slot, func; 6517c478bd9Sstevel@tonic-gate pci_regspec_t *pci_rp; 6527c478bd9Sstevel@tonic-gate 6537c478bd9Sstevel@tonic-gate if (ndi_dev_is_persistent_node(child) == 0) { 6547c478bd9Sstevel@tonic-gate char **unit_addr; 6557c478bd9Sstevel@tonic-gate 6567c478bd9Sstevel@tonic-gate /* name .conf nodes by "unit-address" property" */ 6577c478bd9Sstevel@tonic-gate if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child, 6587c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) != 6597c478bd9Sstevel@tonic-gate DDI_PROP_SUCCESS) { 6607c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "cannot name node from %s.conf", 6617c478bd9Sstevel@tonic-gate ddi_driver_name(child)); 6627c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6637c478bd9Sstevel@tonic-gate } 6647c478bd9Sstevel@tonic-gate if (n != 1 || *unit_addr == NULL || **unit_addr == 0) { 6657c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "unit-address property in %s.conf" 6667c478bd9Sstevel@tonic-gate " not well-formed", ddi_driver_name(child)); 6677c478bd9Sstevel@tonic-gate ddi_prop_free(unit_addr); 6687c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6697c478bd9Sstevel@tonic-gate } 6707c478bd9Sstevel@tonic-gate 6717c478bd9Sstevel@tonic-gate (void) snprintf(name, namelen, "%s", *unit_addr); 6727c478bd9Sstevel@tonic-gate ddi_prop_free(unit_addr); 6737c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 6747c478bd9Sstevel@tonic-gate } 6757c478bd9Sstevel@tonic-gate 6767c478bd9Sstevel@tonic-gate /* name hardware nodes by "reg" property */ 6777c478bd9Sstevel@tonic-gate if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, 0, "reg", 6787c478bd9Sstevel@tonic-gate (int **)&pci_rp, &n) != DDI_SUCCESS) 6797c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6807c478bd9Sstevel@tonic-gate 6817c478bd9Sstevel@tonic-gate /* get the device identifications */ 6827c478bd9Sstevel@tonic-gate slot = PCI_REG_DEV_G(pci_rp->pci_phys_hi); 6837c478bd9Sstevel@tonic-gate func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi); 6847c478bd9Sstevel@tonic-gate 6857c478bd9Sstevel@tonic-gate if (func != 0) 6867c478bd9Sstevel@tonic-gate (void) snprintf(name, namelen, "%x,%x", slot, func); 6877c478bd9Sstevel@tonic-gate else 6887c478bd9Sstevel@tonic-gate (void) snprintf(name, namelen, "%x", slot); 6897c478bd9Sstevel@tonic-gate 6907c478bd9Sstevel@tonic-gate ddi_prop_free(pci_rp); 6917c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 6927c478bd9Sstevel@tonic-gate } 6937c478bd9Sstevel@tonic-gate 6947c478bd9Sstevel@tonic-gate static int 6957c478bd9Sstevel@tonic-gate simba_initchild(dev_info_t *child) 6967c478bd9Sstevel@tonic-gate { 6977c478bd9Sstevel@tonic-gate char name[MAXNAMELEN]; 6987c478bd9Sstevel@tonic-gate int i; 6997c478bd9Sstevel@tonic-gate ddi_acc_handle_t config_handle; 7007c478bd9Sstevel@tonic-gate ushort_t command_preserve, command; 7017c478bd9Sstevel@tonic-gate uchar_t header_type; 7027c478bd9Sstevel@tonic-gate uchar_t min_gnt, latency_timer; 7037c478bd9Sstevel@tonic-gate simba_devstate_t *simba; 7047c478bd9Sstevel@tonic-gate uint_t n; 7057c478bd9Sstevel@tonic-gate 706f47a9c50Smathue DEBUG1(D_INIT_CLD, "simba_initchild(): child=%p\n", child); 7077c478bd9Sstevel@tonic-gate 7087c478bd9Sstevel@tonic-gate /* 7097c478bd9Sstevel@tonic-gate * Pseudo nodes indicate a prototype node with per-instance 7107c478bd9Sstevel@tonic-gate * properties to be merged into the real h/w device node. 7117c478bd9Sstevel@tonic-gate * The interpretation of the unit-address is DD[,F] 7127c478bd9Sstevel@tonic-gate * where DD is the device id and F is the function. 7137c478bd9Sstevel@tonic-gate */ 7147c478bd9Sstevel@tonic-gate if (ndi_dev_is_persistent_node(child) == 0) { 7157c478bd9Sstevel@tonic-gate extern int pci_allow_pseudo_children; 7167c478bd9Sstevel@tonic-gate pci_regspec_t *pci_rp; 7177c478bd9Sstevel@tonic-gate 7187c478bd9Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, child, 7197c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "reg", (caddr_t)&pci_rp, &i) == 7207c478bd9Sstevel@tonic-gate DDI_SUCCESS) { 7217c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 7227c478bd9Sstevel@tonic-gate "cannot merge prototype from %s.conf", 7237c478bd9Sstevel@tonic-gate ddi_driver_name(child)); 7247c478bd9Sstevel@tonic-gate kmem_free(pci_rp, i); 7257c478bd9Sstevel@tonic-gate return (DDI_NOT_WELL_FORMED); 7267c478bd9Sstevel@tonic-gate } 7277c478bd9Sstevel@tonic-gate 7287c478bd9Sstevel@tonic-gate if (simba_name_child(child, name, MAXNAMELEN) != DDI_SUCCESS) 7297c478bd9Sstevel@tonic-gate return (DDI_NOT_WELL_FORMED); 7307c478bd9Sstevel@tonic-gate 7317c478bd9Sstevel@tonic-gate ddi_set_name_addr(child, name); 7327c478bd9Sstevel@tonic-gate ddi_set_parent_data(child, NULL); 7337c478bd9Sstevel@tonic-gate 7347c478bd9Sstevel@tonic-gate /* 7357c478bd9Sstevel@tonic-gate * Try to merge the properties from this prototype 7367c478bd9Sstevel@tonic-gate * node into real h/w nodes. 7377c478bd9Sstevel@tonic-gate */ 7387c478bd9Sstevel@tonic-gate if (ndi_merge_node(child, simba_name_child) == DDI_SUCCESS) { 7397c478bd9Sstevel@tonic-gate /* 7407c478bd9Sstevel@tonic-gate * Merged ok - return failure to remove the node. 7417c478bd9Sstevel@tonic-gate */ 7427c478bd9Sstevel@tonic-gate simba_uninitchild(child); 7437c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 7447c478bd9Sstevel@tonic-gate } 7457c478bd9Sstevel@tonic-gate 7467c478bd9Sstevel@tonic-gate /* workaround for ddivs to run under PCI */ 7477c478bd9Sstevel@tonic-gate if (pci_allow_pseudo_children) 7487c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 7497c478bd9Sstevel@tonic-gate 7507c478bd9Sstevel@tonic-gate /* 7517c478bd9Sstevel@tonic-gate * The child was not merged into a h/w node, 7527c478bd9Sstevel@tonic-gate * but there's not much we can do with it other 7537c478bd9Sstevel@tonic-gate * than return failure to cause the node to be removed. 7547c478bd9Sstevel@tonic-gate */ 7557c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "!%s@%s: %s.conf properties not merged", 7567c478bd9Sstevel@tonic-gate ddi_driver_name(child), ddi_get_name_addr(child), 7577c478bd9Sstevel@tonic-gate ddi_driver_name(child)); 7587c478bd9Sstevel@tonic-gate simba_uninitchild(child); 7597c478bd9Sstevel@tonic-gate return (DDI_NOT_WELL_FORMED); 7607c478bd9Sstevel@tonic-gate } 7617c478bd9Sstevel@tonic-gate 7627c478bd9Sstevel@tonic-gate /* 7637c478bd9Sstevel@tonic-gate * Initialize real h/w nodes 7647c478bd9Sstevel@tonic-gate */ 7657c478bd9Sstevel@tonic-gate if (simba_name_child(child, name, MAXNAMELEN) != DDI_SUCCESS) 7667c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 7677c478bd9Sstevel@tonic-gate 7687c478bd9Sstevel@tonic-gate ddi_set_name_addr(child, name); 7697c478bd9Sstevel@tonic-gate ddi_set_parent_data(child, NULL); 7707c478bd9Sstevel@tonic-gate 7717c478bd9Sstevel@tonic-gate if (pci_config_setup(child, &config_handle) != DDI_SUCCESS) { 7727c478bd9Sstevel@tonic-gate simba_uninitchild(child); 7737c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 7747c478bd9Sstevel@tonic-gate } 7757c478bd9Sstevel@tonic-gate 7767c478bd9Sstevel@tonic-gate DEBUG0(D_INIT_CLD, "simba_initchild(): pci_config_setup success!\n"); 7777c478bd9Sstevel@tonic-gate 7787c478bd9Sstevel@tonic-gate /* 7797c478bd9Sstevel@tonic-gate * Determine the configuration header type. 7807c478bd9Sstevel@tonic-gate */ 7817c478bd9Sstevel@tonic-gate header_type = pci_config_get8(config_handle, PCI_CONF_HEADER); 7827c478bd9Sstevel@tonic-gate 7837c478bd9Sstevel@tonic-gate /* 7847c478bd9Sstevel@tonic-gate * Support for the "command-preserve" property. 7857c478bd9Sstevel@tonic-gate */ 7867c478bd9Sstevel@tonic-gate command_preserve = ddi_prop_get_int(DDI_DEV_T_ANY, child, 7877c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "command-preserve", 0); 7887c478bd9Sstevel@tonic-gate command = pci_config_get16(config_handle, PCI_CONF_COMM); 7897c478bd9Sstevel@tonic-gate command &= (command_preserve | PCI_COMM_BACK2BACK_ENAB); 7907c478bd9Sstevel@tonic-gate command |= (simba_command_default & ~command_preserve); 7917c478bd9Sstevel@tonic-gate pci_config_put16(config_handle, PCI_CONF_COMM, command); 7927c478bd9Sstevel@tonic-gate 7937c478bd9Sstevel@tonic-gate /* clean up all PCI child devices status register */ 7947c478bd9Sstevel@tonic-gate pci_config_put16(config_handle, PCI_CONF_STAT, 0xffff); 7957c478bd9Sstevel@tonic-gate 7967c478bd9Sstevel@tonic-gate /* 7977c478bd9Sstevel@tonic-gate * If the device has a primary bus control register then program it 7987c478bd9Sstevel@tonic-gate * based on the settings in the command register. 7997c478bd9Sstevel@tonic-gate */ 8007c478bd9Sstevel@tonic-gate if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE) { 8017c478bd9Sstevel@tonic-gate ushort_t bcr = 8027c478bd9Sstevel@tonic-gate pci_config_get16(config_handle, PCI_BCNF_BCNTRL); 8037c478bd9Sstevel@tonic-gate if (simba_command_default & PCI_COMM_PARITY_DETECT) 8047c478bd9Sstevel@tonic-gate bcr |= PCI_BCNF_BCNTRL_PARITY_ENABLE; 8057c478bd9Sstevel@tonic-gate if (simba_command_default & PCI_COMM_SERR_ENABLE) 8067c478bd9Sstevel@tonic-gate bcr |= PCI_BCNF_BCNTRL_SERR_ENABLE; 8077c478bd9Sstevel@tonic-gate bcr |= PCI_BCNF_BCNTRL_MAST_AB_MODE; 8087c478bd9Sstevel@tonic-gate pci_config_put8(config_handle, PCI_BCNF_BCNTRL, bcr); 8097c478bd9Sstevel@tonic-gate } 8107c478bd9Sstevel@tonic-gate 8117c478bd9Sstevel@tonic-gate simba = (simba_devstate_t *)ddi_get_soft_state(simba_state, 8127c478bd9Sstevel@tonic-gate ddi_get_instance(ddi_get_parent(child))); 8137c478bd9Sstevel@tonic-gate /* 8147c478bd9Sstevel@tonic-gate * Initialize cache-line-size configuration register if needed. 8157c478bd9Sstevel@tonic-gate */ 8167c478bd9Sstevel@tonic-gate if (simba_set_cache_line_size_register && 8177c478bd9Sstevel@tonic-gate ddi_getprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, 8187c478bd9Sstevel@tonic-gate "cache-line-size", 0) == 0) { 8197c478bd9Sstevel@tonic-gate pci_config_put8(config_handle, PCI_CONF_CACHE_LINESZ, 8207c478bd9Sstevel@tonic-gate simba->simba_cache_line_size); 8217c478bd9Sstevel@tonic-gate n = pci_config_get8(config_handle, PCI_CONF_CACHE_LINESZ); 8227c478bd9Sstevel@tonic-gate if (n != 0) 8237c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, child, 8247c478bd9Sstevel@tonic-gate "cache-line-size", n); 8257c478bd9Sstevel@tonic-gate } 8267c478bd9Sstevel@tonic-gate 8277c478bd9Sstevel@tonic-gate /* 8287c478bd9Sstevel@tonic-gate * Initialize latency timer configuration registers if needed. 8297c478bd9Sstevel@tonic-gate */ 8307c478bd9Sstevel@tonic-gate if (simba_set_latency_timer_register && 8317c478bd9Sstevel@tonic-gate ddi_getprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, 8327c478bd9Sstevel@tonic-gate "latency-timer", 0) == 0) { 8337c478bd9Sstevel@tonic-gate 8347c478bd9Sstevel@tonic-gate if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE) { 8357c478bd9Sstevel@tonic-gate latency_timer = simba->simba_latency_timer; 8367c478bd9Sstevel@tonic-gate pci_config_put8(config_handle, PCI_BCNF_LATENCY_TIMER, 8377c478bd9Sstevel@tonic-gate simba->simba_latency_timer); 8387c478bd9Sstevel@tonic-gate } else { 8397c478bd9Sstevel@tonic-gate min_gnt = pci_config_get8(config_handle, 8407c478bd9Sstevel@tonic-gate PCI_CONF_MIN_G); 8417c478bd9Sstevel@tonic-gate latency_timer = min_gnt * 8; 8427c478bd9Sstevel@tonic-gate } 8437c478bd9Sstevel@tonic-gate pci_config_put8(config_handle, PCI_CONF_LATENCY_TIMER, 8447c478bd9Sstevel@tonic-gate latency_timer); 8457c478bd9Sstevel@tonic-gate n = pci_config_get8(config_handle, PCI_CONF_LATENCY_TIMER); 8467c478bd9Sstevel@tonic-gate if (n != 0) 8477c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, child, 8487c478bd9Sstevel@tonic-gate "latency-timer", n); 8497c478bd9Sstevel@tonic-gate } 8507c478bd9Sstevel@tonic-gate 8517c478bd9Sstevel@tonic-gate pci_config_teardown(&config_handle); 8527c478bd9Sstevel@tonic-gate DEBUG0(D_INIT_CLD, "simba_initchild(): pci_config_teardown called\n"); 8537c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 8547c478bd9Sstevel@tonic-gate } 8557c478bd9Sstevel@tonic-gate 8567c478bd9Sstevel@tonic-gate static void 8577c478bd9Sstevel@tonic-gate simba_uninitchild(dev_info_t *dip) 8587c478bd9Sstevel@tonic-gate { 8597c478bd9Sstevel@tonic-gate ddi_set_name_addr(dip, NULL); 8607c478bd9Sstevel@tonic-gate 8617c478bd9Sstevel@tonic-gate /* 8627c478bd9Sstevel@tonic-gate * Strip the node to properly convert it back to prototype form 8637c478bd9Sstevel@tonic-gate */ 8647c478bd9Sstevel@tonic-gate impl_rem_dev_props(dip); 8657c478bd9Sstevel@tonic-gate } 8667c478bd9Sstevel@tonic-gate 8677c478bd9Sstevel@tonic-gate /* 8687c478bd9Sstevel@tonic-gate * simba_save_config_regs 8697c478bd9Sstevel@tonic-gate * 8707c478bd9Sstevel@tonic-gate * This routine saves the state of the configuration registers of all 8717c478bd9Sstevel@tonic-gate * the child nodes of each PBM. 8727c478bd9Sstevel@tonic-gate * 8737c478bd9Sstevel@tonic-gate * used by: simba_detach() on suspends 8747c478bd9Sstevel@tonic-gate * 8757c478bd9Sstevel@tonic-gate * return value: none 8767c478bd9Sstevel@tonic-gate */ 8777c478bd9Sstevel@tonic-gate static void 8787c478bd9Sstevel@tonic-gate simba_save_config_regs(simba_devstate_t *simba_p) 8797c478bd9Sstevel@tonic-gate { 8807c478bd9Sstevel@tonic-gate int i; 8817c478bd9Sstevel@tonic-gate dev_info_t *dip; 8827c478bd9Sstevel@tonic-gate ddi_acc_handle_t ch; 8837c478bd9Sstevel@tonic-gate struct simba_cfg_state *statep; 8847c478bd9Sstevel@tonic-gate 8857c478bd9Sstevel@tonic-gate for (i = 0, dip = ddi_get_child(simba_p->dip); dip != NULL; 8867c478bd9Sstevel@tonic-gate dip = ddi_get_next_sibling(dip)) { 887737d277aScth if (i_ddi_devi_attached(dip)) 8887c478bd9Sstevel@tonic-gate i++; 8897c478bd9Sstevel@tonic-gate } 8907c478bd9Sstevel@tonic-gate if (!i) 8917c478bd9Sstevel@tonic-gate return; 8927c478bd9Sstevel@tonic-gate simba_p->simba_config_state_p = 8937c478bd9Sstevel@tonic-gate kmem_zalloc(i * sizeof (struct simba_cfg_state), KM_NOSLEEP); 8947c478bd9Sstevel@tonic-gate if (!simba_p->simba_config_state_p) { 8957c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "not enough memrory to save simba child\n"); 8967c478bd9Sstevel@tonic-gate return; 8977c478bd9Sstevel@tonic-gate } 8987c478bd9Sstevel@tonic-gate simba_p->config_state_index = i; 8997c478bd9Sstevel@tonic-gate 9007c478bd9Sstevel@tonic-gate for (statep = simba_p->simba_config_state_p, 9017c478bd9Sstevel@tonic-gate dip = ddi_get_child(simba_p->dip); 9027c478bd9Sstevel@tonic-gate dip != NULL; 9037c478bd9Sstevel@tonic-gate dip = ddi_get_next_sibling(dip)) { 9047c478bd9Sstevel@tonic-gate 905737d277aScth if (!i_ddi_devi_attached(dip)) { 9067c478bd9Sstevel@tonic-gate DEBUG4(D_DETACH, "%s%d: skipping unattached %s%d\n", 9077c478bd9Sstevel@tonic-gate ddi_driver_name(simba_p->dip), 9087c478bd9Sstevel@tonic-gate ddi_get_instance(simba_p->dip), 9097c478bd9Sstevel@tonic-gate ddi_driver_name(dip), 9107c478bd9Sstevel@tonic-gate ddi_get_instance(dip)); 9117c478bd9Sstevel@tonic-gate continue; 9127c478bd9Sstevel@tonic-gate } 9137c478bd9Sstevel@tonic-gate 9147c478bd9Sstevel@tonic-gate DEBUG4(D_DETACH, "%s%d: saving regs for %s%d\n", 9157c478bd9Sstevel@tonic-gate ddi_driver_name(simba_p->dip), 9167c478bd9Sstevel@tonic-gate ddi_get_instance(simba_p->dip), 9177c478bd9Sstevel@tonic-gate ddi_driver_name(dip), 9187c478bd9Sstevel@tonic-gate ddi_get_instance(dip)); 9197c478bd9Sstevel@tonic-gate 9207c478bd9Sstevel@tonic-gate if (pci_config_setup(dip, &ch) != DDI_SUCCESS) { 9217c478bd9Sstevel@tonic-gate DEBUG4(D_DETACH, "%s%d: can't config space for %s%d\n", 9227c478bd9Sstevel@tonic-gate ddi_driver_name(simba_p->dip), 9237c478bd9Sstevel@tonic-gate ddi_get_instance(simba_p->dip), 9247c478bd9Sstevel@tonic-gate ddi_driver_name(dip), 9257c478bd9Sstevel@tonic-gate ddi_get_instance(dip)); 9267c478bd9Sstevel@tonic-gate continue; 9277c478bd9Sstevel@tonic-gate } 9287c478bd9Sstevel@tonic-gate 929f47a9c50Smathue DEBUG3(D_DETACH, "%s%d: saving child dip=%p\n", 9307c478bd9Sstevel@tonic-gate ddi_driver_name(simba_p->dip), 9317c478bd9Sstevel@tonic-gate ddi_get_instance(simba_p->dip), 9327c478bd9Sstevel@tonic-gate dip); 9337c478bd9Sstevel@tonic-gate 9347c478bd9Sstevel@tonic-gate statep->dip = dip; 9357c478bd9Sstevel@tonic-gate statep->command = pci_config_get16(ch, PCI_CONF_COMM); 9367c478bd9Sstevel@tonic-gate statep->header_type = pci_config_get8(ch, PCI_CONF_HEADER); 9377c478bd9Sstevel@tonic-gate if ((statep->header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE) 9387c478bd9Sstevel@tonic-gate statep->bridge_control = 9397c478bd9Sstevel@tonic-gate pci_config_get16(ch, PCI_BCNF_BCNTRL); 9407c478bd9Sstevel@tonic-gate statep->cache_line_size = 9417c478bd9Sstevel@tonic-gate pci_config_get8(ch, PCI_CONF_CACHE_LINESZ); 9427c478bd9Sstevel@tonic-gate statep->latency_timer = 9437c478bd9Sstevel@tonic-gate pci_config_get8(ch, PCI_CONF_LATENCY_TIMER); 9447c478bd9Sstevel@tonic-gate if ((statep->header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE) 9457c478bd9Sstevel@tonic-gate statep->sec_latency_timer = 9467c478bd9Sstevel@tonic-gate pci_config_get8(ch, PCI_BCNF_LATENCY_TIMER); 9477c478bd9Sstevel@tonic-gate /* 9487c478bd9Sstevel@tonic-gate * Simba specific. 9497c478bd9Sstevel@tonic-gate */ 9507c478bd9Sstevel@tonic-gate if (pci_config_get16(ch, PCI_CONF_VENID) == PCI_SIMBA_VENID && 9517c478bd9Sstevel@tonic-gate pci_config_get16(ch, PCI_CONF_DEVID) == PCI_SIMBA_DEVID) { 9527c478bd9Sstevel@tonic-gate 9537c478bd9Sstevel@tonic-gate statep->bus_number = 9547c478bd9Sstevel@tonic-gate pci_config_get8(ch, PCI_BCNF_PRIBUS); 9557c478bd9Sstevel@tonic-gate statep->sec_bus_number = 9567c478bd9Sstevel@tonic-gate pci_config_get8(ch, PCI_BCNF_SECBUS); 9577c478bd9Sstevel@tonic-gate statep->sub_bus_number = 9587c478bd9Sstevel@tonic-gate pci_config_get8(ch, PCI_BCNF_SUBBUS); 9597c478bd9Sstevel@tonic-gate statep->bridge_control = 9607c478bd9Sstevel@tonic-gate pci_config_get16(ch, PCI_BCNF_BCNTRL); 9617c478bd9Sstevel@tonic-gate } 9627c478bd9Sstevel@tonic-gate pci_config_teardown(&ch); 9637c478bd9Sstevel@tonic-gate statep++; 9647c478bd9Sstevel@tonic-gate } 9657c478bd9Sstevel@tonic-gate } 9667c478bd9Sstevel@tonic-gate 9677c478bd9Sstevel@tonic-gate 9687c478bd9Sstevel@tonic-gate /* 9697c478bd9Sstevel@tonic-gate * simba_restore_config_regs 9707c478bd9Sstevel@tonic-gate * 9717c478bd9Sstevel@tonic-gate * This routine restores the state of the configuration registers of all 9727c478bd9Sstevel@tonic-gate * the child nodes of each PBM. 9737c478bd9Sstevel@tonic-gate * 9747c478bd9Sstevel@tonic-gate * used by: simba_attach() on resume 9757c478bd9Sstevel@tonic-gate * 9767c478bd9Sstevel@tonic-gate * return value: none 9777c478bd9Sstevel@tonic-gate */ 9787c478bd9Sstevel@tonic-gate static void 9797c478bd9Sstevel@tonic-gate simba_restore_config_regs(simba_devstate_t *simba_p) 9807c478bd9Sstevel@tonic-gate { 9817c478bd9Sstevel@tonic-gate int i; 9827c478bd9Sstevel@tonic-gate dev_info_t *dip; 9837c478bd9Sstevel@tonic-gate ddi_acc_handle_t ch; 9847c478bd9Sstevel@tonic-gate struct simba_cfg_state *statep = simba_p->simba_config_state_p; 9857c478bd9Sstevel@tonic-gate if (!simba_p->config_state_index) 9867c478bd9Sstevel@tonic-gate return; 9877c478bd9Sstevel@tonic-gate 9887c478bd9Sstevel@tonic-gate for (i = 0; i < simba_p->config_state_index; i++, statep++) { 9897c478bd9Sstevel@tonic-gate dip = statep->dip; 9907c478bd9Sstevel@tonic-gate if (!dip) { 9917c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 9927c478bd9Sstevel@tonic-gate "%s%d: skipping bad dev info (%d)\n", 9937c478bd9Sstevel@tonic-gate ddi_driver_name(simba_p->dip), 9947c478bd9Sstevel@tonic-gate ddi_get_instance(simba_p->dip), 9957c478bd9Sstevel@tonic-gate i); 9967c478bd9Sstevel@tonic-gate continue; 9977c478bd9Sstevel@tonic-gate } 9987c478bd9Sstevel@tonic-gate 999f47a9c50Smathue DEBUG5(D_ATTACH, "%s%d: restoring regs for %p-%s%d\n", 10007c478bd9Sstevel@tonic-gate ddi_driver_name(simba_p->dip), 10017c478bd9Sstevel@tonic-gate ddi_get_instance(simba_p->dip), 10027c478bd9Sstevel@tonic-gate dip, 10037c478bd9Sstevel@tonic-gate ddi_driver_name(dip), 10047c478bd9Sstevel@tonic-gate ddi_get_instance(dip)); 10057c478bd9Sstevel@tonic-gate 10067c478bd9Sstevel@tonic-gate if (pci_config_setup(dip, &ch) != DDI_SUCCESS) { 10077c478bd9Sstevel@tonic-gate DEBUG4(D_ATTACH, "%s%d: can't config space for %s%d\n", 10087c478bd9Sstevel@tonic-gate ddi_driver_name(simba_p->dip), 10097c478bd9Sstevel@tonic-gate ddi_get_instance(simba_p->dip), 10107c478bd9Sstevel@tonic-gate ddi_driver_name(dip), 10117c478bd9Sstevel@tonic-gate ddi_get_instance(dip)); 10127c478bd9Sstevel@tonic-gate continue; 10137c478bd9Sstevel@tonic-gate } 10147c478bd9Sstevel@tonic-gate pci_config_put16(ch, PCI_CONF_COMM, statep->command); 10157c478bd9Sstevel@tonic-gate if ((statep->header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE) 10167c478bd9Sstevel@tonic-gate pci_config_put16(ch, PCI_BCNF_BCNTRL, 10177c478bd9Sstevel@tonic-gate statep->bridge_control); 10187c478bd9Sstevel@tonic-gate /* 10197c478bd9Sstevel@tonic-gate * Simba specific. 10207c478bd9Sstevel@tonic-gate */ 10217c478bd9Sstevel@tonic-gate if (pci_config_get16(ch, PCI_CONF_VENID) == PCI_SIMBA_VENID && 10227c478bd9Sstevel@tonic-gate pci_config_get16(ch, PCI_CONF_DEVID) == PCI_SIMBA_DEVID) { 10237c478bd9Sstevel@tonic-gate pci_config_put8(ch, PCI_BCNF_PRIBUS, 10247c478bd9Sstevel@tonic-gate statep->bus_number); 10257c478bd9Sstevel@tonic-gate pci_config_put8(ch, PCI_BCNF_SECBUS, 10267c478bd9Sstevel@tonic-gate statep->sec_bus_number); 10277c478bd9Sstevel@tonic-gate pci_config_put8(ch, PCI_BCNF_SUBBUS, 10287c478bd9Sstevel@tonic-gate statep->sub_bus_number); 10297c478bd9Sstevel@tonic-gate pci_config_put16(ch, PCI_BCNF_BCNTRL, 10307c478bd9Sstevel@tonic-gate statep->bridge_control); 10317c478bd9Sstevel@tonic-gate } 10327c478bd9Sstevel@tonic-gate 10337c478bd9Sstevel@tonic-gate pci_config_put8(ch, PCI_CONF_CACHE_LINESZ, 10347c478bd9Sstevel@tonic-gate statep->cache_line_size); 10357c478bd9Sstevel@tonic-gate pci_config_put8(ch, PCI_CONF_LATENCY_TIMER, 10367c478bd9Sstevel@tonic-gate statep->latency_timer); 10377c478bd9Sstevel@tonic-gate if ((statep->header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE) 10387c478bd9Sstevel@tonic-gate pci_config_put8(ch, PCI_BCNF_LATENCY_TIMER, 10397c478bd9Sstevel@tonic-gate statep->sec_latency_timer); 10407c478bd9Sstevel@tonic-gate pci_config_teardown(&ch); 10417c478bd9Sstevel@tonic-gate } 10427c478bd9Sstevel@tonic-gate 10437c478bd9Sstevel@tonic-gate kmem_free(simba_p->simba_config_state_p, 10447c478bd9Sstevel@tonic-gate simba_p->config_state_index * sizeof (struct simba_cfg_state)); 10457c478bd9Sstevel@tonic-gate simba_p->simba_config_state_p = NULL; 10467c478bd9Sstevel@tonic-gate simba_p->config_state_index = 0; 10477c478bd9Sstevel@tonic-gate } 10487c478bd9Sstevel@tonic-gate 10497c478bd9Sstevel@tonic-gate /* ARGSUSED */ 10507c478bd9Sstevel@tonic-gate static int 10517c478bd9Sstevel@tonic-gate simba_open(dev_t *devp, int flags, int otyp, cred_t *credp) 10527c478bd9Sstevel@tonic-gate { 10537c478bd9Sstevel@tonic-gate simba_devstate_t *simba_p; 10547c478bd9Sstevel@tonic-gate 10557c478bd9Sstevel@tonic-gate /* 10567c478bd9Sstevel@tonic-gate * Make sure the open is for the right file type. 10577c478bd9Sstevel@tonic-gate */ 10587c478bd9Sstevel@tonic-gate if (otyp != OTYP_CHR) 10597c478bd9Sstevel@tonic-gate return (EINVAL); 10607c478bd9Sstevel@tonic-gate 10617c478bd9Sstevel@tonic-gate /* 10627c478bd9Sstevel@tonic-gate * Get the soft state structure for the device. 10637c478bd9Sstevel@tonic-gate */ 10647c478bd9Sstevel@tonic-gate simba_p = (simba_devstate_t *)ddi_get_soft_state(simba_state, 10657c478bd9Sstevel@tonic-gate getminor(*devp)); 10667c478bd9Sstevel@tonic-gate if (simba_p == NULL) 10677c478bd9Sstevel@tonic-gate return (ENXIO); 10687c478bd9Sstevel@tonic-gate 10697c478bd9Sstevel@tonic-gate /* 10707c478bd9Sstevel@tonic-gate * Handle the open by tracking the device state. 10717c478bd9Sstevel@tonic-gate */ 10727c478bd9Sstevel@tonic-gate mutex_enter(&simba_p->simba_mutex); 10737c478bd9Sstevel@tonic-gate if (flags & FEXCL) { 10747c478bd9Sstevel@tonic-gate if (simba_p->simba_soft_state != SIMBA_SOFT_STATE_CLOSED) { 10757c478bd9Sstevel@tonic-gate mutex_exit(&simba_p->simba_mutex); 10767c478bd9Sstevel@tonic-gate return (EBUSY); 10777c478bd9Sstevel@tonic-gate } 10787c478bd9Sstevel@tonic-gate simba_p->simba_soft_state = SIMBA_SOFT_STATE_OPEN_EXCL; 10797c478bd9Sstevel@tonic-gate } else { 10807c478bd9Sstevel@tonic-gate if (simba_p->simba_soft_state == SIMBA_SOFT_STATE_OPEN_EXCL) { 10817c478bd9Sstevel@tonic-gate mutex_exit(&simba_p->simba_mutex); 10827c478bd9Sstevel@tonic-gate return (EBUSY); 10837c478bd9Sstevel@tonic-gate } 10847c478bd9Sstevel@tonic-gate simba_p->simba_soft_state = SIMBA_SOFT_STATE_OPEN; 10857c478bd9Sstevel@tonic-gate } 10867c478bd9Sstevel@tonic-gate mutex_exit(&simba_p->simba_mutex); 10877c478bd9Sstevel@tonic-gate return (0); 10887c478bd9Sstevel@tonic-gate } 10897c478bd9Sstevel@tonic-gate 10907c478bd9Sstevel@tonic-gate 10917c478bd9Sstevel@tonic-gate /* ARGSUSED */ 10927c478bd9Sstevel@tonic-gate static int 10937c478bd9Sstevel@tonic-gate simba_close(dev_t dev, int flags, int otyp, cred_t *credp) 10947c478bd9Sstevel@tonic-gate { 10957c478bd9Sstevel@tonic-gate simba_devstate_t *simba_p; 10967c478bd9Sstevel@tonic-gate 10977c478bd9Sstevel@tonic-gate if (otyp != OTYP_CHR) 10987c478bd9Sstevel@tonic-gate return (EINVAL); 10997c478bd9Sstevel@tonic-gate 11007c478bd9Sstevel@tonic-gate simba_p = (simba_devstate_t *)ddi_get_soft_state(simba_state, 11017c478bd9Sstevel@tonic-gate getminor(dev)); 11027c478bd9Sstevel@tonic-gate if (simba_p == NULL) 11037c478bd9Sstevel@tonic-gate return (ENXIO); 11047c478bd9Sstevel@tonic-gate 11057c478bd9Sstevel@tonic-gate mutex_enter(&simba_p->simba_mutex); 11067c478bd9Sstevel@tonic-gate simba_p->simba_soft_state = SIMBA_SOFT_STATE_CLOSED; 11077c478bd9Sstevel@tonic-gate mutex_exit(&simba_p->simba_mutex); 11087c478bd9Sstevel@tonic-gate return (0); 11097c478bd9Sstevel@tonic-gate } 11107c478bd9Sstevel@tonic-gate 11117c478bd9Sstevel@tonic-gate 11127c478bd9Sstevel@tonic-gate /* 11137c478bd9Sstevel@tonic-gate * simba_ioctl: devctl hotplug controls 11147c478bd9Sstevel@tonic-gate */ 11157c478bd9Sstevel@tonic-gate /* ARGSUSED */ 11167c478bd9Sstevel@tonic-gate static int 11177c478bd9Sstevel@tonic-gate simba_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, 11187c478bd9Sstevel@tonic-gate int *rvalp) 11197c478bd9Sstevel@tonic-gate { 11207c478bd9Sstevel@tonic-gate simba_devstate_t *simba_p; 11217c478bd9Sstevel@tonic-gate dev_info_t *self; 11227c478bd9Sstevel@tonic-gate struct devctl_iocdata *dcp; 11237c478bd9Sstevel@tonic-gate uint_t bus_state; 11247c478bd9Sstevel@tonic-gate int rv = 0; 11257c478bd9Sstevel@tonic-gate 11267c478bd9Sstevel@tonic-gate simba_p = (simba_devstate_t *)ddi_get_soft_state(simba_state, 11277c478bd9Sstevel@tonic-gate getminor(dev)); 11287c478bd9Sstevel@tonic-gate if (simba_p == NULL) 11297c478bd9Sstevel@tonic-gate return (ENXIO); 11307c478bd9Sstevel@tonic-gate 11317c478bd9Sstevel@tonic-gate self = simba_p->dip; 11327c478bd9Sstevel@tonic-gate 11337c478bd9Sstevel@tonic-gate /* 11347c478bd9Sstevel@tonic-gate * We can use the generic implementation for these ioctls 11357c478bd9Sstevel@tonic-gate */ 11367c478bd9Sstevel@tonic-gate switch (cmd) { 11377c478bd9Sstevel@tonic-gate case DEVCTL_DEVICE_GETSTATE: 11387c478bd9Sstevel@tonic-gate case DEVCTL_DEVICE_ONLINE: 11397c478bd9Sstevel@tonic-gate case DEVCTL_DEVICE_OFFLINE: 11407c478bd9Sstevel@tonic-gate case DEVCTL_BUS_GETSTATE: 11417c478bd9Sstevel@tonic-gate return (ndi_devctl_ioctl(self, cmd, arg, mode, 0)); 11427c478bd9Sstevel@tonic-gate } 11437c478bd9Sstevel@tonic-gate 11447c478bd9Sstevel@tonic-gate /* 11457c478bd9Sstevel@tonic-gate * read devctl ioctl data 11467c478bd9Sstevel@tonic-gate */ 11477c478bd9Sstevel@tonic-gate if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS) 11487c478bd9Sstevel@tonic-gate return (EFAULT); 11497c478bd9Sstevel@tonic-gate 11507c478bd9Sstevel@tonic-gate switch (cmd) { 11517c478bd9Sstevel@tonic-gate 11527c478bd9Sstevel@tonic-gate case DEVCTL_DEVICE_RESET: 11537c478bd9Sstevel@tonic-gate rv = ENOTSUP; 11547c478bd9Sstevel@tonic-gate break; 11557c478bd9Sstevel@tonic-gate 11567c478bd9Sstevel@tonic-gate 11577c478bd9Sstevel@tonic-gate case DEVCTL_BUS_QUIESCE: 11587c478bd9Sstevel@tonic-gate if (ndi_get_bus_state(self, &bus_state) == NDI_SUCCESS) 11597c478bd9Sstevel@tonic-gate if (bus_state == BUS_QUIESCED) 11607c478bd9Sstevel@tonic-gate break; 11617c478bd9Sstevel@tonic-gate (void) ndi_set_bus_state(self, BUS_QUIESCED); 11627c478bd9Sstevel@tonic-gate break; 11637c478bd9Sstevel@tonic-gate 11647c478bd9Sstevel@tonic-gate case DEVCTL_BUS_UNQUIESCE: 11657c478bd9Sstevel@tonic-gate if (ndi_get_bus_state(self, &bus_state) == NDI_SUCCESS) 11667c478bd9Sstevel@tonic-gate if (bus_state == BUS_ACTIVE) 11677c478bd9Sstevel@tonic-gate break; 11687c478bd9Sstevel@tonic-gate (void) ndi_set_bus_state(self, BUS_ACTIVE); 11697c478bd9Sstevel@tonic-gate break; 11707c478bd9Sstevel@tonic-gate 11717c478bd9Sstevel@tonic-gate case DEVCTL_BUS_RESET: 11727c478bd9Sstevel@tonic-gate rv = ENOTSUP; 11737c478bd9Sstevel@tonic-gate break; 11747c478bd9Sstevel@tonic-gate 11757c478bd9Sstevel@tonic-gate case DEVCTL_BUS_RESETALL: 11767c478bd9Sstevel@tonic-gate rv = ENOTSUP; 11777c478bd9Sstevel@tonic-gate break; 11787c478bd9Sstevel@tonic-gate 11797c478bd9Sstevel@tonic-gate default: 11807c478bd9Sstevel@tonic-gate rv = ENOTTY; 11817c478bd9Sstevel@tonic-gate } 11827c478bd9Sstevel@tonic-gate 11837c478bd9Sstevel@tonic-gate ndi_dc_freehdl(dcp); 11847c478bd9Sstevel@tonic-gate return (rv); 11857c478bd9Sstevel@tonic-gate } 11867c478bd9Sstevel@tonic-gate 11877c478bd9Sstevel@tonic-gate /* 11887c478bd9Sstevel@tonic-gate * Initialize FMA resources for children devices. Called when 11897c478bd9Sstevel@tonic-gate * child calls ddi_fm_init(). 11907c478bd9Sstevel@tonic-gate */ 11917c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 11927c478bd9Sstevel@tonic-gate static int 11937c478bd9Sstevel@tonic-gate simba_fm_init_child(dev_info_t *dip, dev_info_t *tdip, int cap, 11947c478bd9Sstevel@tonic-gate ddi_iblock_cookie_t *ibc) 11957c478bd9Sstevel@tonic-gate { 11967c478bd9Sstevel@tonic-gate simba_devstate_t *simba_p = ddi_get_soft_state(simba_state, 11977c478bd9Sstevel@tonic-gate ddi_get_instance(dip)); 11987c478bd9Sstevel@tonic-gate 11997c478bd9Sstevel@tonic-gate *ibc = simba_p->fm_ibc; 12007c478bd9Sstevel@tonic-gate return (simba_p->fm_cap); 12017c478bd9Sstevel@tonic-gate } 12027c478bd9Sstevel@tonic-gate 12037c478bd9Sstevel@tonic-gate static void 12047c478bd9Sstevel@tonic-gate simba_bus_enter(dev_info_t *dip, ddi_acc_handle_t handle) 12057c478bd9Sstevel@tonic-gate { 12067c478bd9Sstevel@tonic-gate i_ndi_busop_access_enter(dip, handle); 12077c478bd9Sstevel@tonic-gate } 12087c478bd9Sstevel@tonic-gate 12097c478bd9Sstevel@tonic-gate /* ARGSUSED */ 12107c478bd9Sstevel@tonic-gate static void 12117c478bd9Sstevel@tonic-gate simba_bus_exit(dev_info_t *dip, ddi_acc_handle_t handle) 12127c478bd9Sstevel@tonic-gate { 12137c478bd9Sstevel@tonic-gate i_ndi_busop_access_exit(dip, handle); 12147c478bd9Sstevel@tonic-gate } 1215