11772Sjl139090 /* 21772Sjl139090 * CDDL HEADER START 31772Sjl139090 * 41772Sjl139090 * The contents of this file are subject to the terms of the 51772Sjl139090 * Common Development and Distribution License (the "License"). 61772Sjl139090 * You may not use this file except in compliance with the License. 71772Sjl139090 * 81772Sjl139090 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 91772Sjl139090 * or http://www.opensolaris.org/os/licensing. 101772Sjl139090 * See the License for the specific language governing permissions 111772Sjl139090 * and limitations under the License. 121772Sjl139090 * 131772Sjl139090 * When distributing Covered Code, include this CDDL HEADER in each 141772Sjl139090 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 151772Sjl139090 * If applicable, add the following below this CDDL HEADER, with the 161772Sjl139090 * fields enclosed by brackets "[]" replaced with your own identifying 171772Sjl139090 * information: Portions Copyright [yyyy] [name of copyright owner] 181772Sjl139090 * 191772Sjl139090 * CDDL HEADER END 201772Sjl139090 */ 211772Sjl139090 /* 221772Sjl139090 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 231772Sjl139090 * Use is subject to license terms. 241772Sjl139090 */ 251772Sjl139090 261772Sjl139090 #pragma ident "%Z%%M% %I% %E% SMI" 271772Sjl139090 281772Sjl139090 #include <sys/conf.h> 291772Sjl139090 #include <sys/kmem.h> 301772Sjl139090 #include <sys/debug.h> 311772Sjl139090 #include <sys/modctl.h> 321772Sjl139090 #include <sys/autoconf.h> 331772Sjl139090 #include <sys/hwconf.h> 341772Sjl139090 #include <sys/ddi_impldefs.h> 351772Sjl139090 #include <sys/ddi.h> 361772Sjl139090 #include <sys/sunddi.h> 371772Sjl139090 #include <sys/sunndi.h> 381772Sjl139090 #include <sys/ndi_impldefs.h> 391772Sjl139090 #include <sys/machsystm.h> 401772Sjl139090 #include <sys/fcode.h> 411772Sjl139090 #include <sys/promif.h> 421772Sjl139090 #include <sys/promimpl.h> 431772Sjl139090 #include <sys/opl_cfg.h> 441772Sjl139090 #include <sys/scfd/scfostoescf.h> 451772Sjl139090 461772Sjl139090 static unsigned int opl_cfg_inited; 471772Sjl139090 static opl_board_cfg_t opl_boards[HWD_SBS_PER_DOMAIN]; 481772Sjl139090 491772Sjl139090 /* 501772Sjl139090 * Module control operations 511772Sjl139090 */ 521772Sjl139090 531772Sjl139090 extern struct mod_ops mod_miscops; 541772Sjl139090 551772Sjl139090 static struct modlmisc modlmisc = { 561772Sjl139090 &mod_miscops, /* Type of module */ 571772Sjl139090 "OPL opl_cfg %I%" 581772Sjl139090 }; 591772Sjl139090 601772Sjl139090 static struct modlinkage modlinkage = { 611772Sjl139090 MODREV_1, (void *)&modlmisc, NULL 621772Sjl139090 }; 631772Sjl139090 641772Sjl139090 static int opl_map_in(dev_info_t *, fco_handle_t, fc_ci_t *); 651772Sjl139090 static int opl_map_out(dev_info_t *, fco_handle_t, fc_ci_t *); 661772Sjl139090 static int opl_register_fetch(dev_info_t *, fco_handle_t, fc_ci_t *); 671772Sjl139090 static int opl_register_store(dev_info_t *, fco_handle_t, fc_ci_t *); 681772Sjl139090 691772Sjl139090 static int opl_claim_memory(dev_info_t *, fco_handle_t, fc_ci_t *); 701772Sjl139090 static int opl_release_memory(dev_info_t *, fco_handle_t, fc_ci_t *); 711772Sjl139090 static int opl_vtop(dev_info_t *, fco_handle_t, fc_ci_t *); 721772Sjl139090 731772Sjl139090 static int opl_config_child(dev_info_t *, fco_handle_t, fc_ci_t *); 741772Sjl139090 751772Sjl139090 static int opl_get_fcode_size(dev_info_t *, fco_handle_t, fc_ci_t *); 761772Sjl139090 static int opl_get_fcode(dev_info_t *, fco_handle_t, fc_ci_t *); 771772Sjl139090 781772Sjl139090 static int opl_map_phys(dev_info_t *, struct regspec *, caddr_t *, 791772Sjl139090 ddi_device_acc_attr_t *, ddi_acc_handle_t *); 801772Sjl139090 static void opl_unmap_phys(ddi_acc_handle_t *); 811772Sjl139090 static int opl_get_hwd_va(dev_info_t *, fco_handle_t, fc_ci_t *); 82*1982Smv143129 static int opl_master_interrupt(dev_info_t *, fco_handle_t, fc_ci_t *); 831772Sjl139090 841772Sjl139090 extern int prom_get_fcode_size(char *); 851772Sjl139090 extern int prom_get_fcode(char *, char *); 861772Sjl139090 87*1982Smv143129 static int master_interrupt_init(uint32_t, uint32_t); 88*1982Smv143129 891772Sjl139090 #define PROBE_STR_SIZE 64 901772Sjl139090 #define UNIT_ADDR_SIZE 64 911772Sjl139090 921772Sjl139090 opl_fc_ops_t opl_fc_ops[] = { 931772Sjl139090 941772Sjl139090 { FC_MAP_IN, opl_map_in}, 951772Sjl139090 { FC_MAP_OUT, opl_map_out}, 961772Sjl139090 { "rx@", opl_register_fetch}, 971772Sjl139090 { FC_RL_FETCH, opl_register_fetch}, 981772Sjl139090 { FC_RW_FETCH, opl_register_fetch}, 991772Sjl139090 { FC_RB_FETCH, opl_register_fetch}, 1001772Sjl139090 { "rx!", opl_register_store}, 1011772Sjl139090 { FC_RL_STORE, opl_register_store}, 1021772Sjl139090 { FC_RW_STORE, opl_register_store}, 1031772Sjl139090 { FC_RB_STORE, opl_register_store}, 1041772Sjl139090 { "claim-memory", opl_claim_memory}, 1051772Sjl139090 { "release-memory", opl_release_memory}, 1061772Sjl139090 { "vtop", opl_vtop}, 1071772Sjl139090 { FC_CONFIG_CHILD, opl_config_child}, 1081772Sjl139090 { FC_GET_FCODE_SIZE, opl_get_fcode_size}, 1091772Sjl139090 { FC_GET_FCODE, opl_get_fcode}, 1101772Sjl139090 { "get-hwd-va", opl_get_hwd_va}, 111*1982Smv143129 { "master-interrupt", opl_master_interrupt}, 1121772Sjl139090 { NULL, NULL} 1131772Sjl139090 1141772Sjl139090 }; 1151772Sjl139090 1161772Sjl139090 extern caddr_t efcode_vaddr; 1171772Sjl139090 extern int efcode_size; 1181772Sjl139090 1191772Sjl139090 #ifdef DEBUG 1201772Sjl139090 #define HWDDUMP_OFFSETS 1 1211772Sjl139090 #define HWDDUMP_ALL_STATUS 2 1221772Sjl139090 #define HWDDUMP_CHUNKS 3 1231772Sjl139090 #define HWDDUMP_SBP 4 1241772Sjl139090 1251772Sjl139090 int hwddump_flags = HWDDUMP_SBP | HWDDUMP_CHUNKS; 1261772Sjl139090 #endif 1271772Sjl139090 128*1982Smv143129 static int master_interrupt_inited = 0; 129*1982Smv143129 1301772Sjl139090 int 1311772Sjl139090 _init() 1321772Sjl139090 { 1331772Sjl139090 int err = 0; 1341772Sjl139090 1351772Sjl139090 /* 1361772Sjl139090 * Create a resource map for the contiguous memory allocated 1371772Sjl139090 * at start-of-day in startup.c 1381772Sjl139090 */ 1391772Sjl139090 err = ndi_ra_map_setup(ddi_root_node(), "opl-fcodemem"); 1401772Sjl139090 if (err == NDI_FAILURE) { 1411772Sjl139090 cmn_err(CE_WARN, "Cannot setup resource map opl-fcodemem\n"); 1421772Sjl139090 return (1); 1431772Sjl139090 } 1441772Sjl139090 1451772Sjl139090 /* 1461772Sjl139090 * Put the allocated memory into the pool. 1471772Sjl139090 */ 1481772Sjl139090 (void) ndi_ra_free(ddi_root_node(), (uint64_t)efcode_vaddr, 1491772Sjl139090 (uint64_t)efcode_size, "opl-fcodemem", 0); 1501772Sjl139090 1511772Sjl139090 if ((err = mod_install(&modlinkage)) != 0) { 1521772Sjl139090 cmn_err(CE_WARN, "opl_cfg failed to load, error=%d", err); 1531772Sjl139090 (void) ndi_ra_map_destroy(ddi_root_node(), "opl-fcodemem"); 1541772Sjl139090 } 1551772Sjl139090 1561772Sjl139090 return (err); 1571772Sjl139090 } 1581772Sjl139090 1591772Sjl139090 int 1601772Sjl139090 _fini(void) 1611772Sjl139090 { 1621772Sjl139090 int ret; 1631772Sjl139090 1641772Sjl139090 ret = (mod_remove(&modlinkage)); 1651772Sjl139090 if (ret != 0) 1661772Sjl139090 return (ret); 1671772Sjl139090 1681772Sjl139090 (void) ndi_ra_map_destroy(ddi_root_node(), "opl-fcodemem"); 1691772Sjl139090 1701772Sjl139090 return (ret); 1711772Sjl139090 } 1721772Sjl139090 1731772Sjl139090 int 1741772Sjl139090 _info(modinfop) 1751772Sjl139090 struct modinfo *modinfop; 1761772Sjl139090 { 1771772Sjl139090 return (mod_info(&modlinkage, modinfop)); 1781772Sjl139090 } 1791772Sjl139090 1801772Sjl139090 #ifdef DEBUG 1811772Sjl139090 static void 1821772Sjl139090 opl_dump_hwd(opl_probe_t *probe) 1831772Sjl139090 { 1841772Sjl139090 hwd_header_t *hdrp; 1851772Sjl139090 hwd_sb_status_t *statp; 1861772Sjl139090 hwd_domain_info_t *dinfop; 1871772Sjl139090 hwd_sb_t *sbp; 1881772Sjl139090 hwd_cpu_chip_t *chips; 1891772Sjl139090 hwd_pci_ch_t *channels; 1901772Sjl139090 int board, i, status; 1911772Sjl139090 1921772Sjl139090 board = probe->pr_board; 1931772Sjl139090 1941772Sjl139090 hdrp = probe->pr_hdr; 1951772Sjl139090 statp = probe->pr_sb_status; 1961772Sjl139090 dinfop = probe->pr_dinfo; 1971772Sjl139090 sbp = probe->pr_sb; 1981772Sjl139090 1991772Sjl139090 printf("HWD: board %d\n", board); 2001772Sjl139090 printf("HWD:magic = 0x%x\n", hdrp->hdr_magic); 2011772Sjl139090 printf("HWD:version = 0x%x.%x\n", hdrp->hdr_version.major, 2021772Sjl139090 hdrp->hdr_version.minor); 2031772Sjl139090 2041772Sjl139090 if (hwddump_flags & HWDDUMP_OFFSETS) { 2051772Sjl139090 printf("HWD:status offset = 0x%x\n", 2061772Sjl139090 hdrp->hdr_sb_status_offset); 2071772Sjl139090 printf("HWD:domain offset = 0x%x\n", 2081772Sjl139090 hdrp->hdr_domain_info_offset); 2091772Sjl139090 printf("HWD:board offset = 0x%x\n", hdrp->hdr_sb_info_offset); 2101772Sjl139090 } 2111772Sjl139090 2121772Sjl139090 if (hwddump_flags & HWDDUMP_SBP) 2131772Sjl139090 printf("HWD:sb_t ptr = 0x%p\n", (void *)probe->pr_sb); 2141772Sjl139090 2151772Sjl139090 if (hwddump_flags & HWDDUMP_ALL_STATUS) { 2161772Sjl139090 int bd; 2171772Sjl139090 printf("HWD:board status ="); 2181772Sjl139090 for (bd = 0; bd < HWD_SBS_PER_DOMAIN; bd++) 2191772Sjl139090 printf("%x ", statp->sb_status[bd]); 2201772Sjl139090 printf("\n"); 2211772Sjl139090 } else { 2221772Sjl139090 printf("HWD:board status = %d\n", statp->sb_status[board]); 2231772Sjl139090 } 2241772Sjl139090 2251772Sjl139090 printf("HWD:banner name = %s\n", dinfop->dinf_banner_name); 2261772Sjl139090 printf("HWD:platform = %s\n", dinfop->dinf_platform_token); 2271772Sjl139090 2281772Sjl139090 printf("HWD:chip status:\n"); 2291772Sjl139090 chips = &sbp->sb_cmu.cmu_cpu_chips[0]; 2301772Sjl139090 for (i = 0; i < HWD_CPU_CHIPS_PER_CMU; i++) { 2311772Sjl139090 2321772Sjl139090 status = chips[i].chip_status; 2331772Sjl139090 printf("chip[%d] = ", i); 2341772Sjl139090 if (HWD_STATUS_NONE(status)) 2351772Sjl139090 printf("none"); 2361772Sjl139090 else if (HWD_STATUS_FAILED(status)) 2371772Sjl139090 printf("fail"); 2381772Sjl139090 else if (HWD_STATUS_OK(status)) 2391772Sjl139090 printf("ok"); 2401772Sjl139090 printf("\n"); 2411772Sjl139090 } 2421772Sjl139090 2431772Sjl139090 if (hwddump_flags & HWDDUMP_CHUNKS) { 2441772Sjl139090 int chunk; 2451772Sjl139090 hwd_memory_t *mem = &sbp->sb_cmu.cmu_memory; 2461772Sjl139090 printf("HWD:chunks:\n"); 2471772Sjl139090 for (chunk = 0; chunk < HWD_MAX_MEM_CHUNKS; chunk++) 2481772Sjl139090 printf("\t%d 0x%lx 0x%lx\n", chunk, 2491772Sjl139090 mem->mem_chunks[chunk].chnk_start_address, 2501772Sjl139090 mem->mem_chunks[chunk].chnk_size); 2511772Sjl139090 } 2521772Sjl139090 2531772Sjl139090 printf("HWD:channel status:\n"); 2541772Sjl139090 channels = &sbp->sb_pci_ch[0]; 2551772Sjl139090 for (i = 0; i < HWD_PCI_CHANNELS_PER_SB; i++) { 2561772Sjl139090 2571772Sjl139090 status = channels[i].pci_status; 2581772Sjl139090 printf("channels[%d] = ", i); 2591772Sjl139090 if (HWD_STATUS_NONE(status)) 2601772Sjl139090 printf("none"); 2611772Sjl139090 else if (HWD_STATUS_FAILED(status)) 2621772Sjl139090 printf("fail"); 2631772Sjl139090 else if (HWD_STATUS_OK(status)) 2641772Sjl139090 printf("ok"); 2651772Sjl139090 printf("\n"); 2661772Sjl139090 } 2671772Sjl139090 printf("channels[%d] = ", i); 2681772Sjl139090 status = sbp->sb_cmu.cmu_ch.chan_status; 2691772Sjl139090 if (HWD_STATUS_NONE(status)) 2701772Sjl139090 printf("none"); 2711772Sjl139090 else if (HWD_STATUS_FAILED(status)) 2721772Sjl139090 printf("fail"); 2731772Sjl139090 else if (HWD_STATUS_OK(status)) 2741772Sjl139090 printf("ok"); 2751772Sjl139090 printf("\n"); 2761772Sjl139090 } 2771772Sjl139090 #endif /* DEBUG */ 2781772Sjl139090 2791772Sjl139090 #ifdef UCTEST 2801772Sjl139090 /* 2811772Sjl139090 * For SesamI debugging, just map the SRAM directly to a kernel 2821772Sjl139090 * VA and read it out from there 2831772Sjl139090 */ 2841772Sjl139090 2851772Sjl139090 #include <sys/vmem.h> 2861772Sjl139090 #include <vm/seg_kmem.h> 2871772Sjl139090 2881772Sjl139090 /* 2891772Sjl139090 * 0x4081F1323000LL is the HWD base address for LSB 0. But we need to map 2901772Sjl139090 * at page boundaries. So, we use a base address of 0x4081F1322000LL. 2911772Sjl139090 * Note that this has to match the HWD base pa set in .sesami-common-defs. 2921772Sjl139090 * 2931772Sjl139090 * The size specified for the HWD in the SCF spec is 36K. But since 2941772Sjl139090 * we adjusted the base address by 4K, we need to use 40K for the 2951772Sjl139090 * mapping size to cover the HWD. And 40K is also a multiple of the 2961772Sjl139090 * base page size. 2971772Sjl139090 */ 2981772Sjl139090 #define OPL_HWD_BASE(lsb) \ 2991772Sjl139090 (0x4081F1322000LL | (((uint64_t)(lsb)) << 40)) 3001772Sjl139090 3011772Sjl139090 void *opl_hwd_vaddr; 3021772Sjl139090 #endif /* UCTEST */ 3031772Sjl139090 3041772Sjl139090 /* 3051772Sjl139090 * Get the hardware descriptor from SCF. 3061772Sjl139090 */ 3071772Sjl139090 3081772Sjl139090 /*ARGSUSED*/ 3091772Sjl139090 int 3101772Sjl139090 opl_read_hwd(int board, hwd_header_t **hdrp, hwd_sb_status_t **statp, 3111772Sjl139090 hwd_domain_info_t **dinfop, hwd_sb_t **sbp) 3121772Sjl139090 { 3131772Sjl139090 static int (*getinfop)(uint32_t, uint8_t, uint32_t, uint32_t *, 3141772Sjl139090 void *) = NULL; 3151772Sjl139090 void *hwdp; 3161772Sjl139090 3171772Sjl139090 uint32_t key = KEY_ESCF; /* required value */ 3181772Sjl139090 uint8_t type = 0x40; /* SUB_OS_RECEIVE_HWD */ 3191772Sjl139090 uint32_t transid = board; 3201772Sjl139090 uint32_t datasize = HWD_DATA_SIZE; 3211772Sjl139090 3221772Sjl139090 hwd_header_t *hd; 3231772Sjl139090 hwd_sb_status_t *st; 3241772Sjl139090 hwd_domain_info_t *di; 3251772Sjl139090 hwd_sb_t *sb; 3261772Sjl139090 3271772Sjl139090 int ret; 3281772Sjl139090 3291772Sjl139090 if (opl_boards[board].cfg_hwd == NULL) { 3301772Sjl139090 #ifdef UCTEST 3311772Sjl139090 /* 3321772Sjl139090 * Just map the HWD in SRAM to a kernel VA 3331772Sjl139090 */ 3341772Sjl139090 3351772Sjl139090 size_t size; 3361772Sjl139090 pfn_t pfn; 3371772Sjl139090 3381772Sjl139090 size = 0xA000; 3391772Sjl139090 3401772Sjl139090 opl_hwd_vaddr = vmem_alloc(heap_arena, size, VM_SLEEP); 3411772Sjl139090 if (opl_hwd_vaddr == NULL) { 3421772Sjl139090 cmn_err(CE_NOTE, "No space for HWD"); 3431772Sjl139090 return (-1); 3441772Sjl139090 } 3451772Sjl139090 3461772Sjl139090 pfn = btop(OPL_HWD_BASE(board)); 3471772Sjl139090 hat_devload(kas.a_hat, opl_hwd_vaddr, size, pfn, PROT_READ, 3481772Sjl139090 HAT_LOAD_NOCONSIST | HAT_LOAD_LOCK); 3491772Sjl139090 3501772Sjl139090 hwdp = (void *)((char *)opl_hwd_vaddr + 0x1000); 3511772Sjl139090 opl_boards[board].cfg_hwd = hwdp; 3521772Sjl139090 ret = 0; 3531772Sjl139090 #else 3541772Sjl139090 3551772Sjl139090 /* find the scf_service_getinfo() function */ 3561772Sjl139090 if (getinfop == NULL) 3571772Sjl139090 getinfop = (int (*)(uint32_t, uint8_t, uint32_t, 3581772Sjl139090 uint32_t *, 3591772Sjl139090 void *))modgetsymvalue("scf_service_getinfo", 0); 3601772Sjl139090 3611772Sjl139090 if (getinfop == NULL) 3621772Sjl139090 return (-1); 3631772Sjl139090 3641772Sjl139090 /* allocate memory to receive the data */ 3651772Sjl139090 hwdp = kmem_alloc(HWD_DATA_SIZE, KM_SLEEP); 3661772Sjl139090 3671772Sjl139090 /* get the HWD */ 3681772Sjl139090 ret = (*getinfop)(key, type, transid, &datasize, hwdp); 3691772Sjl139090 if (ret == 0) 3701772Sjl139090 opl_boards[board].cfg_hwd = hwdp; 3711772Sjl139090 else 3721772Sjl139090 kmem_free(hwdp, HWD_DATA_SIZE); 3731772Sjl139090 #endif 3741772Sjl139090 } else { 3751772Sjl139090 hwdp = opl_boards[board].cfg_hwd; 3761772Sjl139090 ret = 0; 3771772Sjl139090 } 3781772Sjl139090 3791772Sjl139090 /* copy the data to the destination */ 3801772Sjl139090 if (ret == 0) { 3811772Sjl139090 hd = (hwd_header_t *)hwdp; 3821772Sjl139090 st = (hwd_sb_status_t *) 3831772Sjl139090 ((char *)hwdp + hd->hdr_sb_status_offset); 3841772Sjl139090 di = (hwd_domain_info_t *) 3851772Sjl139090 ((char *)hwdp + hd->hdr_domain_info_offset); 3861772Sjl139090 sb = (hwd_sb_t *) 3871772Sjl139090 ((char *)hwdp + hd->hdr_sb_info_offset); 3881772Sjl139090 if (hdrp != NULL) 3891772Sjl139090 *hdrp = hd; 3901772Sjl139090 if (statp != NULL) 3911772Sjl139090 *statp = st; 3921772Sjl139090 if (dinfop != NULL) 3931772Sjl139090 *dinfop = di; 3941772Sjl139090 if (sbp != NULL) 3951772Sjl139090 *sbp = sb; 3961772Sjl139090 } 3971772Sjl139090 3981772Sjl139090 return (ret); 3991772Sjl139090 } 4001772Sjl139090 4011772Sjl139090 /* 4021772Sjl139090 * The opl_probe_t probe structure is used to pass all sorts of parameters 4031772Sjl139090 * to callback functions during probing. It also contains a snapshot of 4041772Sjl139090 * the hardware descriptor that is taken at the beginning of a probe. 4051772Sjl139090 */ 4061772Sjl139090 static int 4071772Sjl139090 opl_probe_init(opl_probe_t *probe) 4081772Sjl139090 { 4091772Sjl139090 hwd_header_t **hdrp; 4101772Sjl139090 hwd_sb_status_t **statp; 4111772Sjl139090 hwd_domain_info_t **dinfop; 4121772Sjl139090 hwd_sb_t **sbp; 4131772Sjl139090 int board, ret; 4141772Sjl139090 4151772Sjl139090 board = probe->pr_board; 4161772Sjl139090 4171772Sjl139090 hdrp = &probe->pr_hdr; 4181772Sjl139090 statp = &probe->pr_sb_status; 4191772Sjl139090 dinfop = &probe->pr_dinfo; 4201772Sjl139090 sbp = &probe->pr_sb; 4211772Sjl139090 4221772Sjl139090 /* 4231772Sjl139090 * Read the hardware descriptor. 4241772Sjl139090 */ 4251772Sjl139090 ret = opl_read_hwd(board, hdrp, statp, dinfop, sbp); 4261772Sjl139090 if (ret != 0) { 4271772Sjl139090 4281772Sjl139090 cmn_err(CE_WARN, "IKP: failed to read HWD header"); 4291772Sjl139090 return (-1); 4301772Sjl139090 } 4311772Sjl139090 4321772Sjl139090 #ifdef DEBUG 4331772Sjl139090 opl_dump_hwd(probe); 4341772Sjl139090 #endif 4351772Sjl139090 return (0); 4361772Sjl139090 } 4371772Sjl139090 4381772Sjl139090 /* 4391772Sjl139090 * This function is used to obtain pointers to relevant device nodes 4401772Sjl139090 * which are created by Solaris at boot time. 4411772Sjl139090 * 4421772Sjl139090 * This function walks the child nodes of a given node, extracts 4431772Sjl139090 * the "name" property, if it exists, and passes the node to a 4441772Sjl139090 * callback init function. The callback determines if this node is 4451772Sjl139090 * interesting or not. If it is, then a pointer to the node is 4461772Sjl139090 * stored away by the callback for use during unprobe. 4471772Sjl139090 * 4481772Sjl139090 * The DDI get property function allocates storage for the name 4491772Sjl139090 * property. That needs to be freed within this function. 4501772Sjl139090 */ 4511772Sjl139090 static int 4521772Sjl139090 opl_init_nodes(dev_info_t *parent, opl_init_func_t init) 4531772Sjl139090 { 4541772Sjl139090 dev_info_t *node; 4551772Sjl139090 char *name; 4561772Sjl139090 int circ, ret; 4571772Sjl139090 int len; 4581772Sjl139090 4591772Sjl139090 ASSERT(parent != NULL); 4601772Sjl139090 4611772Sjl139090 /* 4621772Sjl139090 * Hold parent node busy to walk its child list 4631772Sjl139090 */ 4641772Sjl139090 ndi_devi_enter(parent, &circ); 4651772Sjl139090 node = ddi_get_child(parent); 4661772Sjl139090 4671772Sjl139090 while (node != NULL) { 4681772Sjl139090 4691772Sjl139090 ret = OPL_GET_PROP(string, node, "name", &name, &len); 4701772Sjl139090 if (ret != DDI_PROP_SUCCESS) { 4711772Sjl139090 /* 4721772Sjl139090 * The property does not exist for this node. 4731772Sjl139090 */ 4741772Sjl139090 node = ddi_get_next_sibling(node); 4751772Sjl139090 continue; 4761772Sjl139090 } 4771772Sjl139090 4781772Sjl139090 ret = init(node, name, len); 4791772Sjl139090 kmem_free(name, len); 4801772Sjl139090 if (ret != 0) { 4811772Sjl139090 4821772Sjl139090 ndi_devi_exit(parent, circ); 4831772Sjl139090 return (-1); 4841772Sjl139090 } 4851772Sjl139090 4861772Sjl139090 node = ddi_get_next_sibling(node); 4871772Sjl139090 } 4881772Sjl139090 4891772Sjl139090 ndi_devi_exit(parent, circ); 4901772Sjl139090 4911772Sjl139090 return (0); 4921772Sjl139090 } 4931772Sjl139090 4941772Sjl139090 /* 4951772Sjl139090 * This init function finds all the interesting nodes under the 4961772Sjl139090 * root node and stores pointers to them. The following nodes 4971772Sjl139090 * are considered interesting by this implementation: 4981772Sjl139090 * 4991772Sjl139090 * "cmp" 5001772Sjl139090 * These are nodes that represent processor chips. 5011772Sjl139090 * 5021772Sjl139090 * "pci" 5031772Sjl139090 * These are nodes that represent PCI leaves. 5041772Sjl139090 * 5051772Sjl139090 * "pseudo-mc" 5061772Sjl139090 * These are nodes that contain memory information. 5071772Sjl139090 */ 5081772Sjl139090 static int 5091772Sjl139090 opl_init_root_nodes(dev_info_t *node, char *name, int len) 5101772Sjl139090 { 5111772Sjl139090 int portid, board, chip, channel, leaf; 5121772Sjl139090 int ret; 5131772Sjl139090 5141772Sjl139090 if (strncmp(name, OPL_CPU_CHIP_NODE, len) == 0) { 5151772Sjl139090 5161772Sjl139090 ret = OPL_GET_PROP(int, node, "portid", &portid, -1); 5171772Sjl139090 if (ret != DDI_PROP_SUCCESS) 5181772Sjl139090 return (-1); 5191772Sjl139090 5201772Sjl139090 ret = OPL_GET_PROP(int, node, "board#", &board, -1); 5211772Sjl139090 if (ret != DDI_PROP_SUCCESS) 5221772Sjl139090 return (-1); 5231772Sjl139090 5241772Sjl139090 chip = OPL_CPU_CHIP(portid); 5251772Sjl139090 opl_boards[board].cfg_cpu_chips[chip] = node; 5261772Sjl139090 5271772Sjl139090 } else if (strncmp(name, OPL_PCI_LEAF_NODE, len) == 0) { 5281772Sjl139090 5291772Sjl139090 ret = OPL_GET_PROP(int, node, "portid", &portid, -1); 5301772Sjl139090 if (ret != DDI_PROP_SUCCESS) 5311772Sjl139090 return (-1); 5321772Sjl139090 5331772Sjl139090 board = OPL_IO_PORTID_TO_LSB(portid); 5341772Sjl139090 channel = OPL_PORTID_TO_CHANNEL(portid); 5351772Sjl139090 5361772Sjl139090 if (channel == OPL_CMU_CHANNEL) { 5371772Sjl139090 5381772Sjl139090 opl_boards[board].cfg_cmuch_leaf = node; 5391772Sjl139090 5401772Sjl139090 } else { 5411772Sjl139090 5421772Sjl139090 leaf = OPL_PORTID_TO_LEAF(portid); 5431772Sjl139090 opl_boards[board].cfg_pcich_leaf[channel][leaf] = node; 5441772Sjl139090 } 5451772Sjl139090 } else if (strncmp(name, OPL_PSEUDO_MC_NODE, len) == 0) { 5461772Sjl139090 5471772Sjl139090 ret = OPL_GET_PROP(int, node, "board#", &board, -1); 5481772Sjl139090 if (ret != DDI_PROP_SUCCESS) 5491772Sjl139090 return (-1); 5501772Sjl139090 5511772Sjl139090 ASSERT((board >= 0) && (board < HWD_SBS_PER_DOMAIN)); 5521772Sjl139090 5531772Sjl139090 opl_boards[board].cfg_pseudo_mc = node; 5541772Sjl139090 } 5551772Sjl139090 5561772Sjl139090 return (0); 5571772Sjl139090 } 5581772Sjl139090 5591772Sjl139090 /* 5601772Sjl139090 * This function initializes the OPL IKP feature. Currently, all it does 5611772Sjl139090 * is find the interesting nodes that Solaris has created at boot time 5621772Sjl139090 * for boards present at boot time and store pointers to them. This 5631772Sjl139090 * is useful if those boards are unprobed by DR. 5641772Sjl139090 */ 5651772Sjl139090 int 5661772Sjl139090 opl_init_cfg() 5671772Sjl139090 { 5681772Sjl139090 dev_info_t *root; 5691772Sjl139090 5701772Sjl139090 if (opl_cfg_inited == 0) { 5711772Sjl139090 5721772Sjl139090 root = ddi_root_node(); 5731772Sjl139090 if ((opl_init_nodes(root, opl_init_root_nodes) != 0)) { 5741772Sjl139090 cmn_err(CE_WARN, "IKP: init failed"); 5751772Sjl139090 return (1); 5761772Sjl139090 } 5771772Sjl139090 5781772Sjl139090 opl_cfg_inited = 1; 5791772Sjl139090 } 5801772Sjl139090 5811772Sjl139090 return (0); 5821772Sjl139090 } 5831772Sjl139090 5841772Sjl139090 /* 5851772Sjl139090 * When DR is initialized, we walk the device tree and acquire a hold on 5861772Sjl139090 * all the nodes that are interesting to IKP. This is so that the corresponding 5871772Sjl139090 * branches cannot be deleted. 5881772Sjl139090 * 5891772Sjl139090 * The following function informs the walk about which nodes are interesting 5901772Sjl139090 * so that it can hold the corresponding branches. 5911772Sjl139090 */ 5921772Sjl139090 static int 5931772Sjl139090 opl_hold_node(char *name) 5941772Sjl139090 { 5951772Sjl139090 /* 5961772Sjl139090 * We only need to hold/release the following nodes which 5971772Sjl139090 * represent separate branches that must be managed. 5981772Sjl139090 */ 5991772Sjl139090 return ((strcmp(name, OPL_CPU_CHIP_NODE) == 0) || 6001772Sjl139090 (strcmp(name, OPL_PSEUDO_MC_NODE) == 0) || 6011772Sjl139090 (strcmp(name, OPL_PCI_LEAF_NODE) == 0)); 6021772Sjl139090 } 6031772Sjl139090 6041772Sjl139090 static int 6051772Sjl139090 opl_hold_rele_devtree(dev_info_t *rdip, void *arg) 6061772Sjl139090 { 6071772Sjl139090 6081772Sjl139090 int *holdp = (int *)arg; 6091772Sjl139090 char *name = ddi_node_name(rdip); 6101772Sjl139090 6111772Sjl139090 /* 6121772Sjl139090 * We only need to hold/release the following nodes which 6131772Sjl139090 * represent separate branches that must be managed. 6141772Sjl139090 */ 6151772Sjl139090 if (opl_hold_node(name) == 0) { 6161772Sjl139090 /* Not of interest to us */ 6171772Sjl139090 return (DDI_WALK_PRUNECHILD); 6181772Sjl139090 } 6191772Sjl139090 if (*holdp) { 6201772Sjl139090 ASSERT(!e_ddi_branch_held(rdip)); 6211772Sjl139090 e_ddi_branch_hold(rdip); 6221772Sjl139090 } else { 6231772Sjl139090 ASSERT(e_ddi_branch_held(rdip)); 6241772Sjl139090 e_ddi_branch_rele(rdip); 6251772Sjl139090 } 6261772Sjl139090 6271772Sjl139090 return (DDI_WALK_PRUNECHILD); 6281772Sjl139090 } 6291772Sjl139090 6301772Sjl139090 void 6311772Sjl139090 opl_hold_devtree() 6321772Sjl139090 { 6331772Sjl139090 dev_info_t *dip; 6341772Sjl139090 int circ; 6351772Sjl139090 int hold = 1; 6361772Sjl139090 6371772Sjl139090 dip = ddi_root_node(); 6381772Sjl139090 ndi_devi_enter(dip, &circ); 6391772Sjl139090 ddi_walk_devs(ddi_get_child(dip), opl_hold_rele_devtree, &hold); 6401772Sjl139090 ndi_devi_exit(dip, circ); 6411772Sjl139090 } 6421772Sjl139090 6431772Sjl139090 void 6441772Sjl139090 opl_release_devtree() 6451772Sjl139090 { 6461772Sjl139090 dev_info_t *dip; 6471772Sjl139090 int circ; 6481772Sjl139090 int hold = 0; 6491772Sjl139090 6501772Sjl139090 dip = ddi_root_node(); 6511772Sjl139090 ndi_devi_enter(dip, &circ); 6521772Sjl139090 ddi_walk_devs(ddi_get_child(dip), opl_hold_rele_devtree, &hold); 6531772Sjl139090 ndi_devi_exit(dip, circ); 6541772Sjl139090 } 6551772Sjl139090 6561772Sjl139090 /* 6571772Sjl139090 * This is a helper function that allows opl_create_node() to return a 6581772Sjl139090 * pointer to a newly created node to its caller. 6591772Sjl139090 */ 6601772Sjl139090 /*ARGSUSED*/ 6611772Sjl139090 static void 6621772Sjl139090 opl_set_node(dev_info_t *node, void *arg, uint_t flags) 6631772Sjl139090 { 6641772Sjl139090 opl_probe_t *probe; 6651772Sjl139090 6661772Sjl139090 probe = arg; 6671772Sjl139090 probe->pr_node = node; 6681772Sjl139090 } 6691772Sjl139090 6701772Sjl139090 /* 6711772Sjl139090 * Function to create a node in the device tree under a specified parent. 6721772Sjl139090 * 6731772Sjl139090 * e_ddi_branch_create() allows the creation of a whole branch with a 6741772Sjl139090 * single call of the function. However, we only use it to create one node 6751772Sjl139090 * at a time in the case of non-I/O device nodes. In other words, we 6761772Sjl139090 * create branches by repeatedly using this function. This makes the 6771772Sjl139090 * code more readable. 6781772Sjl139090 * 6791772Sjl139090 * The branch descriptor passed to e_ddi_branch_create() takes two 6801772Sjl139090 * callbacks. The create() callback is used to set the properties of a 6811772Sjl139090 * newly created node. The other callback is used to return a pointer 6821772Sjl139090 * to the newly created node. The create() callback is passed by the 6831772Sjl139090 * caller of this function based on the kind of node he wishes to 6841772Sjl139090 * create. 6851772Sjl139090 * 6861772Sjl139090 * e_ddi_branch_create() returns with the newly created node held. We 6871772Sjl139090 * only need to hold the top nodes of the branches we create. We release 6881772Sjl139090 * the hold for the others. E.g., the "cmp" node needs to be held. Since 6891772Sjl139090 * we hold the "cmp" node, there is no need to hold the "core" and "cpu" 6901772Sjl139090 * nodes below it. 6911772Sjl139090 */ 6921772Sjl139090 static dev_info_t * 6931772Sjl139090 opl_create_node(opl_probe_t *probe) 6941772Sjl139090 { 6951772Sjl139090 devi_branch_t branch; 6961772Sjl139090 6971772Sjl139090 probe->pr_node = NULL; 6981772Sjl139090 6991772Sjl139090 branch.arg = probe; 7001772Sjl139090 branch.type = DEVI_BRANCH_SID; 7011772Sjl139090 branch.create.sid_branch_create = probe->pr_create; 7021772Sjl139090 branch.devi_branch_callback = opl_set_node; 7031772Sjl139090 7041772Sjl139090 if (e_ddi_branch_create(probe->pr_parent, &branch, NULL, 0) != 0) 7051772Sjl139090 return (NULL); 7061772Sjl139090 7071772Sjl139090 ASSERT(probe->pr_node != NULL); 7081772Sjl139090 7091772Sjl139090 if (probe->pr_hold == 0) 7101772Sjl139090 e_ddi_branch_rele(probe->pr_node); 7111772Sjl139090 7121772Sjl139090 return (probe->pr_node); 7131772Sjl139090 } 7141772Sjl139090 7151772Sjl139090 /* 7161772Sjl139090 * Function to tear down a whole branch rooted at the specified node. 7171772Sjl139090 * 7181772Sjl139090 * Although we create each node of a branch individually, we destroy 7191772Sjl139090 * a whole branch in one call. This is more efficient. 7201772Sjl139090 */ 7211772Sjl139090 static int 7221772Sjl139090 opl_destroy_node(dev_info_t *node) 7231772Sjl139090 { 7241772Sjl139090 if (e_ddi_branch_destroy(node, NULL, 0) != 0) 7251772Sjl139090 return (-1); 7261772Sjl139090 7271772Sjl139090 return (0); 7281772Sjl139090 } 7291772Sjl139090 7301772Sjl139090 /* 7311772Sjl139090 * Set the properties for a "cpu" node. 7321772Sjl139090 */ 7331772Sjl139090 /*ARGSUSED*/ 7341772Sjl139090 static int 7351772Sjl139090 opl_create_cpu(dev_info_t *node, void *arg, uint_t flags) 7361772Sjl139090 { 7371772Sjl139090 opl_probe_t *probe; 7381772Sjl139090 hwd_cpu_chip_t *chip; 7391772Sjl139090 hwd_core_t *core; 7401772Sjl139090 hwd_cpu_t *cpu; 7411772Sjl139090 int ret; 7421772Sjl139090 7431772Sjl139090 probe = arg; 7441772Sjl139090 chip = &probe->pr_sb->sb_cmu.cmu_cpu_chips[probe->pr_cpu_chip]; 7451772Sjl139090 core = &chip->chip_cores[probe->pr_core]; 7461772Sjl139090 cpu = &core->core_cpus[probe->pr_cpu]; 7471772Sjl139090 OPL_UPDATE_PROP(string, node, "name", OPL_CPU_NODE); 7481772Sjl139090 OPL_UPDATE_PROP(string, node, "device_type", OPL_CPU_NODE); 7491772Sjl139090 7501772Sjl139090 OPL_UPDATE_PROP(int, node, "cpuid", cpu->cpu_cpuid); 7511772Sjl139090 OPL_UPDATE_PROP(int, node, "reg", probe->pr_cpu); 7521772Sjl139090 7531772Sjl139090 OPL_UPDATE_PROP(string, node, "status", "okay"); 7541772Sjl139090 7551772Sjl139090 return (DDI_WALK_TERMINATE); 7561772Sjl139090 } 7571772Sjl139090 7581772Sjl139090 /* 7591772Sjl139090 * Create "cpu" nodes as child nodes of a given "core" node. 7601772Sjl139090 */ 7611772Sjl139090 static int 7621772Sjl139090 opl_probe_cpus(opl_probe_t *probe) 7631772Sjl139090 { 7641772Sjl139090 int i; 7651772Sjl139090 hwd_cpu_chip_t *chip; 7661772Sjl139090 hwd_core_t *core; 7671772Sjl139090 hwd_cpu_t *cpus; 7681772Sjl139090 7691772Sjl139090 chip = &probe->pr_sb->sb_cmu.cmu_cpu_chips[probe->pr_cpu_chip]; 7701772Sjl139090 core = &chip->chip_cores[probe->pr_core]; 7711772Sjl139090 cpus = &core->core_cpus[0]; 7721772Sjl139090 7731772Sjl139090 for (i = 0; i < HWD_CPUS_PER_CORE; i++) { 7741772Sjl139090 7751772Sjl139090 /* 7761772Sjl139090 * Olympus-C has 2 cpus per core. 7771772Sjl139090 * Jupiter has 4 cpus per core. 7781772Sjl139090 * For the Olympus-C based platform, we expect the cpu_status 7791772Sjl139090 * of the non-existent cpus to be set to missing. 7801772Sjl139090 */ 7811772Sjl139090 if (!HWD_STATUS_OK(cpus[i].cpu_status)) 7821772Sjl139090 continue; 7831772Sjl139090 7841772Sjl139090 probe->pr_create = opl_create_cpu; 7851772Sjl139090 probe->pr_cpu = i; 7861772Sjl139090 if (opl_create_node(probe) == NULL) { 7871772Sjl139090 7881772Sjl139090 cmn_err(CE_WARN, "IKP: create cpu (%d-%d-%d-%d) failed", 7891772Sjl139090 probe->pr_board, probe->pr_cpu_chip, 7901772Sjl139090 probe->pr_core, probe->pr_cpu); 7911772Sjl139090 return (-1); 7921772Sjl139090 } 7931772Sjl139090 } 7941772Sjl139090 7951772Sjl139090 return (0); 7961772Sjl139090 } 7971772Sjl139090 7981772Sjl139090 /* 7991772Sjl139090 * Set the properties for a "core" node. 8001772Sjl139090 */ 8011772Sjl139090 /*ARGSUSED*/ 8021772Sjl139090 static int 8031772Sjl139090 opl_create_core(dev_info_t *node, void *arg, uint_t flags) 8041772Sjl139090 { 8051772Sjl139090 opl_probe_t *probe; 8061772Sjl139090 hwd_cpu_chip_t *chip; 8071772Sjl139090 hwd_core_t *core; 8081772Sjl139090 int sharing[2]; 8091772Sjl139090 int ret; 8101772Sjl139090 8111772Sjl139090 probe = arg; 8121772Sjl139090 chip = &probe->pr_sb->sb_cmu.cmu_cpu_chips[probe->pr_cpu_chip]; 8131772Sjl139090 core = &chip->chip_cores[probe->pr_core]; 8141772Sjl139090 8151772Sjl139090 OPL_UPDATE_PROP(string, node, "name", OPL_CORE_NODE); 8161772Sjl139090 OPL_UPDATE_PROP(string, node, "device_type", OPL_CORE_NODE); 8171772Sjl139090 OPL_UPDATE_PROP(string, node, "compatible", chip->chip_compatible); 8181772Sjl139090 8191772Sjl139090 OPL_UPDATE_PROP(int, node, "reg", probe->pr_core); 8201772Sjl139090 OPL_UPDATE_PROP(int, node, "manufacturer#", core->core_manufacturer); 8211772Sjl139090 OPL_UPDATE_PROP(int, node, "implementation#", 8221772Sjl139090 core->core_implementation); 8231772Sjl139090 OPL_UPDATE_PROP(int, node, "mask#", core->core_mask); 8241772Sjl139090 8251772Sjl139090 OPL_UPDATE_PROP(int, node, "sparc-version", core->core_version); 8261772Sjl139090 OPL_UPDATE_PROP(int, node, "clock-frequency", core->core_frequency); 8271772Sjl139090 8281772Sjl139090 OPL_UPDATE_PROP(int, node, "l1-icache-size", core->core_l1_icache_size); 8291772Sjl139090 OPL_UPDATE_PROP(int, node, "l1-icache-line-size", 8301772Sjl139090 core->core_l1_icache_line_size); 8311772Sjl139090 OPL_UPDATE_PROP(int, node, "l1-icache-associativity", 8321772Sjl139090 core->core_l1_icache_associativity); 8331772Sjl139090 OPL_UPDATE_PROP(int, node, "#itlb-entries", 8341772Sjl139090 core->core_num_itlb_entries); 8351772Sjl139090 8361772Sjl139090 OPL_UPDATE_PROP(int, node, "l1-dcache-size", core->core_l1_dcache_size); 8371772Sjl139090 OPL_UPDATE_PROP(int, node, "l1-dcache-line-size", 8381772Sjl139090 core->core_l1_dcache_line_size); 8391772Sjl139090 OPL_UPDATE_PROP(int, node, "l1-dcache-associativity", 8401772Sjl139090 core->core_l1_dcache_associativity); 8411772Sjl139090 OPL_UPDATE_PROP(int, node, "#dtlb-entries", 8421772Sjl139090 core->core_num_dtlb_entries); 8431772Sjl139090 8441772Sjl139090 OPL_UPDATE_PROP(int, node, "l2-cache-size", core->core_l2_cache_size); 8451772Sjl139090 OPL_UPDATE_PROP(int, node, "l2-cache-line-size", 8461772Sjl139090 core->core_l2_cache_line_size); 8471772Sjl139090 OPL_UPDATE_PROP(int, node, "l2-cache-associativity", 8481772Sjl139090 core->core_l2_cache_associativity); 8491772Sjl139090 sharing[0] = 0; 8501772Sjl139090 sharing[1] = core->core_l2_cache_sharing; 8511772Sjl139090 OPL_UPDATE_PROP_ARRAY(int, node, "l2-cache-sharing", sharing, 2); 8521772Sjl139090 8531772Sjl139090 OPL_UPDATE_PROP(string, node, "status", "okay"); 8541772Sjl139090 8551772Sjl139090 return (DDI_WALK_TERMINATE); 8561772Sjl139090 } 8571772Sjl139090 8581772Sjl139090 /* 8591772Sjl139090 * Create "core" nodes as child nodes of a given "cmp" node. 8601772Sjl139090 * 8611772Sjl139090 * Create the branch below each "core" node". 8621772Sjl139090 */ 8631772Sjl139090 static int 8641772Sjl139090 opl_probe_cores(opl_probe_t *probe) 8651772Sjl139090 { 8661772Sjl139090 int i; 8671772Sjl139090 hwd_cpu_chip_t *chip; 8681772Sjl139090 hwd_core_t *cores; 8691772Sjl139090 dev_info_t *parent, *node; 8701772Sjl139090 8711772Sjl139090 chip = &probe->pr_sb->sb_cmu.cmu_cpu_chips[probe->pr_cpu_chip]; 8721772Sjl139090 cores = &chip->chip_cores[0]; 8731772Sjl139090 parent = probe->pr_parent; 8741772Sjl139090 8751772Sjl139090 for (i = 0; i < HWD_CORES_PER_CPU_CHIP; i++) { 8761772Sjl139090 8771772Sjl139090 if (!HWD_STATUS_OK(cores[i].core_status)) 8781772Sjl139090 continue; 8791772Sjl139090 8801772Sjl139090 probe->pr_parent = parent; 8811772Sjl139090 probe->pr_create = opl_create_core; 8821772Sjl139090 probe->pr_core = i; 8831772Sjl139090 node = opl_create_node(probe); 8841772Sjl139090 if (node == NULL) { 8851772Sjl139090 8861772Sjl139090 cmn_err(CE_WARN, "IKP: create core (%d-%d-%d) failed", 8871772Sjl139090 probe->pr_board, probe->pr_cpu_chip, 8881772Sjl139090 probe->pr_core); 8891772Sjl139090 return (-1); 8901772Sjl139090 } 8911772Sjl139090 8921772Sjl139090 /* 8931772Sjl139090 * Create "cpu" nodes below "core". 8941772Sjl139090 */ 8951772Sjl139090 probe->pr_parent = node; 8961772Sjl139090 if (opl_probe_cpus(probe) != 0) 8971772Sjl139090 return (-1); 8981772Sjl139090 } 8991772Sjl139090 9001772Sjl139090 return (0); 9011772Sjl139090 } 9021772Sjl139090 9031772Sjl139090 /* 9041772Sjl139090 * Set the properties for a "cmp" node. 9051772Sjl139090 */ 9061772Sjl139090 /*ARGSUSED*/ 9071772Sjl139090 static int 9081772Sjl139090 opl_create_cpu_chip(dev_info_t *node, void *arg, uint_t flags) 9091772Sjl139090 { 9101772Sjl139090 opl_probe_t *probe; 9111772Sjl139090 hwd_cpu_chip_t *chip; 9121772Sjl139090 opl_range_t range; 9131772Sjl139090 uint64_t dummy_addr; 9141772Sjl139090 int ret; 9151772Sjl139090 9161772Sjl139090 probe = arg; 9171772Sjl139090 chip = &probe->pr_sb->sb_cmu.cmu_cpu_chips[probe->pr_cpu_chip]; 9181772Sjl139090 9191772Sjl139090 OPL_UPDATE_PROP(string, node, "name", OPL_CPU_CHIP_NODE); 9201772Sjl139090 9211772Sjl139090 OPL_UPDATE_PROP(int, node, "portid", chip->chip_portid); 9221772Sjl139090 OPL_UPDATE_PROP(int, node, "board#", probe->pr_board); 9231772Sjl139090 9241772Sjl139090 dummy_addr = OPL_PROC_AS(probe->pr_board, probe->pr_cpu_chip); 9251772Sjl139090 range.rg_addr_hi = OPL_HI(dummy_addr); 9261772Sjl139090 range.rg_addr_lo = OPL_LO(dummy_addr); 9271772Sjl139090 range.rg_size_hi = 0; 9281772Sjl139090 range.rg_size_lo = 0; 9291772Sjl139090 OPL_UPDATE_PROP_ARRAY(int, node, "reg", (int *)&range, 4); 9301772Sjl139090 9311772Sjl139090 OPL_UPDATE_PROP(int, node, "#address-cells", 1); 9321772Sjl139090 OPL_UPDATE_PROP(int, node, "#size-cells", 0); 9331772Sjl139090 9341772Sjl139090 OPL_UPDATE_PROP(string, node, "status", "okay"); 9351772Sjl139090 9361772Sjl139090 return (DDI_WALK_TERMINATE); 9371772Sjl139090 } 9381772Sjl139090 9391772Sjl139090 /* 9401772Sjl139090 * Create "cmp" nodes as child nodes of the root node. 9411772Sjl139090 * 9421772Sjl139090 * Create the branch below each "cmp" node. 9431772Sjl139090 */ 9441772Sjl139090 static int 9451772Sjl139090 opl_probe_cpu_chips(opl_probe_t *probe) 9461772Sjl139090 { 9471772Sjl139090 int i; 9481772Sjl139090 dev_info_t **cfg_cpu_chips; 9491772Sjl139090 hwd_cpu_chip_t *chips; 9501772Sjl139090 dev_info_t *node; 9511772Sjl139090 9521772Sjl139090 cfg_cpu_chips = opl_boards[probe->pr_board].cfg_cpu_chips; 9531772Sjl139090 chips = &probe->pr_sb->sb_cmu.cmu_cpu_chips[0]; 9541772Sjl139090 9551772Sjl139090 for (i = 0; i < HWD_CPU_CHIPS_PER_CMU; i++) { 9561772Sjl139090 9571772Sjl139090 ASSERT(cfg_cpu_chips[i] == NULL); 9581772Sjl139090 9591772Sjl139090 if (!HWD_STATUS_OK(chips[i].chip_status)) 9601772Sjl139090 continue; 9611772Sjl139090 9621772Sjl139090 probe->pr_parent = ddi_root_node(); 9631772Sjl139090 probe->pr_create = opl_create_cpu_chip; 9641772Sjl139090 probe->pr_cpu_chip = i; 9651772Sjl139090 probe->pr_hold = 1; 9661772Sjl139090 node = opl_create_node(probe); 9671772Sjl139090 if (node == NULL) { 9681772Sjl139090 9691772Sjl139090 cmn_err(CE_WARN, "IKP: create chip (%d-%d) failed", 9701772Sjl139090 probe->pr_board, probe->pr_cpu_chip); 9711772Sjl139090 return (-1); 9721772Sjl139090 } 9731772Sjl139090 9741772Sjl139090 cfg_cpu_chips[i] = node; 9751772Sjl139090 9761772Sjl139090 /* 9771772Sjl139090 * Create "core" nodes below "cmp". 9781772Sjl139090 * We hold the "cmp" node. So, there is no need to hold 9791772Sjl139090 * the "core" and "cpu" nodes below it. 9801772Sjl139090 */ 9811772Sjl139090 probe->pr_parent = node; 9821772Sjl139090 probe->pr_hold = 0; 9831772Sjl139090 if (opl_probe_cores(probe) != 0) 9841772Sjl139090 return (-1); 9851772Sjl139090 } 9861772Sjl139090 9871772Sjl139090 return (0); 9881772Sjl139090 } 9891772Sjl139090 9901772Sjl139090 /* 9911772Sjl139090 * Set the properties for a "pseudo-mc" node. 9921772Sjl139090 */ 9931772Sjl139090 /*ARGSUSED*/ 9941772Sjl139090 static int 9951772Sjl139090 opl_create_pseudo_mc(dev_info_t *node, void *arg, uint_t flags) 9961772Sjl139090 { 9971772Sjl139090 opl_probe_t *probe; 9981772Sjl139090 int board, portid; 9991772Sjl139090 hwd_bank_t *bank; 10001772Sjl139090 hwd_memory_t *mem; 10011772Sjl139090 opl_range_t range; 10021772Sjl139090 opl_mc_addr_t mc[HWD_BANKS_PER_CMU]; 10031772Sjl139090 int status[2][7]; 10041772Sjl139090 int i, j; 10051772Sjl139090 int ret; 10061772Sjl139090 10071772Sjl139090 probe = arg; 10081772Sjl139090 board = probe->pr_board; 10091772Sjl139090 10101772Sjl139090 OPL_UPDATE_PROP(string, node, "name", OPL_PSEUDO_MC_NODE); 10111772Sjl139090 OPL_UPDATE_PROP(string, node, "device_type", "memory-controller"); 10121772Sjl139090 OPL_UPDATE_PROP(string, node, "compatible", "FJSV,oplmc"); 10131772Sjl139090 10141772Sjl139090 portid = OPL_LSB_TO_PSEUDOMC_PORTID(board); 10151772Sjl139090 OPL_UPDATE_PROP(int, node, "portid", portid); 10161772Sjl139090 10171772Sjl139090 range.rg_addr_hi = OPL_HI(OPL_MC_AS(board)); 10181772Sjl139090 range.rg_addr_lo = 0x200; 10191772Sjl139090 range.rg_size_hi = 0; 10201772Sjl139090 range.rg_size_lo = 0; 10211772Sjl139090 OPL_UPDATE_PROP_ARRAY(int, node, "reg", (int *)&range, 4); 10221772Sjl139090 10231772Sjl139090 OPL_UPDATE_PROP(int, node, "board#", board); 10241772Sjl139090 OPL_UPDATE_PROP(int, node, "physical-board#", 10251772Sjl139090 probe->pr_sb->sb_psb_number); 10261772Sjl139090 10271772Sjl139090 OPL_UPDATE_PROP(int, node, "#address-cells", 1); 10281772Sjl139090 OPL_UPDATE_PROP(int, node, "#size-cells", 2); 10291772Sjl139090 10301772Sjl139090 mem = &probe->pr_sb->sb_cmu.cmu_memory; 10311772Sjl139090 10321772Sjl139090 range.rg_addr_hi = OPL_HI(mem->mem_start_address); 10331772Sjl139090 range.rg_addr_lo = OPL_LO(mem->mem_start_address); 10341772Sjl139090 range.rg_size_hi = OPL_HI(mem->mem_size); 10351772Sjl139090 range.rg_size_lo = OPL_LO(mem->mem_size); 10361772Sjl139090 OPL_UPDATE_PROP_ARRAY(int, node, "sb-mem-ranges", (int *)&range, 4); 10371772Sjl139090 10381772Sjl139090 bank = probe->pr_sb->sb_cmu.cmu_memory.mem_banks; 10391772Sjl139090 for (i = 0, j = 0; i < HWD_BANKS_PER_CMU; i++) { 10401772Sjl139090 10411772Sjl139090 if (!HWD_STATUS_OK(bank[i].bank_status)) 10421772Sjl139090 continue; 10431772Sjl139090 10441772Sjl139090 mc[j].mc_bank = i; 10451772Sjl139090 mc[j].mc_hi = OPL_HI(bank[i].bank_register_address); 10461772Sjl139090 mc[j].mc_lo = OPL_LO(bank[i].bank_register_address); 10471772Sjl139090 j++; 10481772Sjl139090 } 10491772Sjl139090 ASSERT(j > 0); 10501772Sjl139090 OPL_UPDATE_PROP_ARRAY(int, node, "mc-addr", (int *)mc, j*3); 10511772Sjl139090 10521772Sjl139090 OPL_UPDATE_PROP_ARRAY(byte, node, "cs0-mc-pa-trans-table", 10531772Sjl139090 mem->mem_cs[0].cs_pa_mac_table, 64); 10541772Sjl139090 OPL_UPDATE_PROP_ARRAY(byte, node, "cs1-mc-pa-trans-table", 10551772Sjl139090 mem->mem_cs[1].cs_pa_mac_table, 64); 10561772Sjl139090 10571772Sjl139090 #define CS_PER_MEM 2 10581772Sjl139090 10591772Sjl139090 for (i = 0, j = 0; i < CS_PER_MEM; i++) { 10601772Sjl139090 if (HWD_STATUS_OK(mem->mem_cs[i].cs_status) || 10611772Sjl139090 HWD_STATUS_FAILED(mem->mem_cs[i].cs_status)) { 10621772Sjl139090 status[j][0] = i; 10631772Sjl139090 if (HWD_STATUS_OK(mem->mem_cs[i].cs_status)) 10641772Sjl139090 status[j][1] = 0; 10651772Sjl139090 else 10661772Sjl139090 status[j][1] = 1; 10671772Sjl139090 status[j][2] = 10681772Sjl139090 OPL_HI(mem->mem_cs[i].cs_available_capacity); 10691772Sjl139090 status[j][3] = 10701772Sjl139090 OPL_LO(mem->mem_cs[i].cs_available_capacity); 10711772Sjl139090 status[j][4] = OPL_HI(mem->mem_cs[i].cs_dimm_capacity); 10721772Sjl139090 status[j][5] = OPL_LO(mem->mem_cs[i].cs_dimm_capacity); 10731772Sjl139090 status[j][6] = mem->mem_cs[i].cs_number_of_dimms; 10741772Sjl139090 j++; 10751772Sjl139090 } 10761772Sjl139090 } 10771772Sjl139090 ASSERT(j > 0); 10781772Sjl139090 OPL_UPDATE_PROP_ARRAY(int, node, "cs-status", (int *)status, 10791772Sjl139090 j*7); 10801772Sjl139090 10811772Sjl139090 return (DDI_WALK_TERMINATE); 10821772Sjl139090 } 10831772Sjl139090 10841772Sjl139090 /* 10851772Sjl139090 * Create "pseudo-mc" nodes 10861772Sjl139090 */ 10871772Sjl139090 static int 10881772Sjl139090 opl_probe_memory(opl_probe_t *probe) 10891772Sjl139090 { 10901772Sjl139090 int board; 10911772Sjl139090 opl_board_cfg_t *board_cfg; 10921772Sjl139090 dev_info_t *node; 10931772Sjl139090 10941772Sjl139090 board = probe->pr_board; 10951772Sjl139090 board_cfg = &opl_boards[board]; 10961772Sjl139090 10971772Sjl139090 ASSERT(board_cfg->cfg_pseudo_mc == NULL); 10981772Sjl139090 10991772Sjl139090 probe->pr_parent = ddi_root_node(); 11001772Sjl139090 probe->pr_create = opl_create_pseudo_mc; 11011772Sjl139090 probe->pr_hold = 1; 11021772Sjl139090 node = opl_create_node(probe); 11031772Sjl139090 if (node == NULL) { 11041772Sjl139090 11051772Sjl139090 cmn_err(CE_WARN, "IKP: create pseudo-mc (%d) failed", board); 11061772Sjl139090 return (-1); 11071772Sjl139090 } 11081772Sjl139090 11091772Sjl139090 board_cfg->cfg_pseudo_mc = node; 11101772Sjl139090 11111772Sjl139090 return (0); 11121772Sjl139090 } 11131772Sjl139090 11141772Sjl139090 /* 11151772Sjl139090 * Allocate the fcode ops handle. 11161772Sjl139090 */ 11171772Sjl139090 /*ARGSUSED*/ 11181772Sjl139090 static 11191772Sjl139090 fco_handle_t 11201772Sjl139090 opl_fc_ops_alloc_handle(dev_info_t *parent, dev_info_t *child, 11211772Sjl139090 void *fcode, size_t fcode_size, char *unit_address, 11221772Sjl139090 char *my_args) 11231772Sjl139090 { 11241772Sjl139090 fco_handle_t rp; 11251772Sjl139090 phandle_t h; 11261772Sjl139090 char *buf; 11271772Sjl139090 11281772Sjl139090 rp = kmem_zalloc(sizeof (struct fc_resource_list), KM_SLEEP); 11291772Sjl139090 rp->next_handle = fc_ops_alloc_handle(parent, child, fcode, fcode_size, 11301772Sjl139090 unit_address, NULL); 11311772Sjl139090 rp->ap = parent; 11321772Sjl139090 rp->child = child; 11331772Sjl139090 rp->fcode = fcode; 11341772Sjl139090 rp->fcode_size = fcode_size; 11351772Sjl139090 rp->my_args = my_args; 11361772Sjl139090 11371772Sjl139090 if (unit_address) { 11381772Sjl139090 buf = kmem_zalloc(UNIT_ADDR_SIZE, KM_SLEEP); 11391772Sjl139090 (void) strcpy(buf, unit_address); 11401772Sjl139090 rp->unit_address = buf; 11411772Sjl139090 } 11421772Sjl139090 11431772Sjl139090 /* 11441772Sjl139090 * Add the child's nodeid to our table... 11451772Sjl139090 */ 11461772Sjl139090 h = ddi_get_nodeid(rp->child); 11471772Sjl139090 fc_add_dip_to_phandle(fc_handle_to_phandle_head(rp), rp->child, h); 11481772Sjl139090 11491772Sjl139090 return (rp); 11501772Sjl139090 } 11511772Sjl139090 11521772Sjl139090 11531772Sjl139090 static void 11541772Sjl139090 opl_fc_ops_free_handle(fco_handle_t rp) 11551772Sjl139090 { 11561772Sjl139090 struct fc_resource *resp, *nresp; 11571772Sjl139090 11581772Sjl139090 ASSERT(rp); 11591772Sjl139090 11601772Sjl139090 if (rp->next_handle) 11611772Sjl139090 fc_ops_free_handle(rp->next_handle); 11621772Sjl139090 if (rp->unit_address) 11631772Sjl139090 kmem_free(rp->unit_address, UNIT_ADDR_SIZE); 11641772Sjl139090 11651772Sjl139090 /* 11661772Sjl139090 * Release all the resources from the resource list 11671772Sjl139090 */ 11681772Sjl139090 for (resp = rp->head; resp != NULL; resp = nresp) { 11691772Sjl139090 nresp = resp->next; 11701772Sjl139090 switch (resp->type) { 11711772Sjl139090 11721772Sjl139090 case RT_MAP: 11731772Sjl139090 break; 11741772Sjl139090 11751772Sjl139090 case RT_DMA: 11761772Sjl139090 /* 11771772Sjl139090 * DMA has to be freed up at exit time. 11781772Sjl139090 */ 11791772Sjl139090 cmn_err(CE_CONT, 11801772Sjl139090 "opl_fc_ops_free_handle: Unexpected DMA seen!"); 11811772Sjl139090 break; 11821772Sjl139090 11831772Sjl139090 case RT_CONTIGIOUS: 11841772Sjl139090 FC_DEBUG2(1, CE_CONT, "opl_fc_ops_free: " 11851772Sjl139090 "Free claim-memory resource 0x%lx size 0x%x\n", 11861772Sjl139090 resp->fc_contig_virt, resp->fc_contig_len); 11871772Sjl139090 11881772Sjl139090 (void) ndi_ra_free(ddi_root_node(), 11891772Sjl139090 (uint64_t)resp->fc_contig_virt, 11901772Sjl139090 resp->fc_contig_len, "opl-fcodemem", 11911772Sjl139090 NDI_RA_PASS); 11921772Sjl139090 11931772Sjl139090 break; 11941772Sjl139090 11951772Sjl139090 default: 11961772Sjl139090 cmn_err(CE_CONT, "opl_fc_ops_free: " 11971772Sjl139090 "unknown resource type %d", resp->type); 11981772Sjl139090 break; 11991772Sjl139090 } 12001772Sjl139090 fc_rem_resource(rp, resp); 12011772Sjl139090 kmem_free(resp, sizeof (struct fc_resource)); 12021772Sjl139090 } 12031772Sjl139090 12041772Sjl139090 kmem_free(rp, sizeof (struct fc_resource_list)); 12051772Sjl139090 } 12061772Sjl139090 12071772Sjl139090 int 12081772Sjl139090 opl_fc_do_op(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 12091772Sjl139090 { 12101772Sjl139090 opl_fc_ops_t *op; 12111772Sjl139090 char *service = fc_cell2ptr(cp->svc_name); 12121772Sjl139090 12131772Sjl139090 ASSERT(rp); 12141772Sjl139090 12151772Sjl139090 FC_DEBUG1(1, CE_CONT, "opl_fc_do_op: <%s>\n", service); 12161772Sjl139090 12171772Sjl139090 /* 12181772Sjl139090 * First try the generic fc_ops. 12191772Sjl139090 */ 12201772Sjl139090 if (fc_ops(ap, rp->next_handle, cp) == 0) 12211772Sjl139090 return (0); 12221772Sjl139090 12231772Sjl139090 /* 12241772Sjl139090 * Now try the Jupiter-specific ops. 12251772Sjl139090 */ 12261772Sjl139090 for (op = opl_fc_ops; op->fc_service != NULL; ++op) 12271772Sjl139090 if (strcmp(op->fc_service, service) == 0) 12281772Sjl139090 return (op->fc_op(ap, rp, cp)); 12291772Sjl139090 12301772Sjl139090 FC_DEBUG1(9, CE_CONT, "opl_fc_do_op: <%s> not serviced\n", service); 12311772Sjl139090 12321772Sjl139090 return (-1); 12331772Sjl139090 } 12341772Sjl139090 12351772Sjl139090 /* 12361772Sjl139090 * map-in (phys.lo phys.hi size -- virt) 12371772Sjl139090 */ 12381772Sjl139090 static int 12391772Sjl139090 opl_map_in(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 12401772Sjl139090 { 12411772Sjl139090 size_t len; 12421772Sjl139090 int error; 12431772Sjl139090 caddr_t virt; 12441772Sjl139090 struct fc_resource *resp; 12451772Sjl139090 struct regspec rspec; 12461772Sjl139090 ddi_device_acc_attr_t acc; 12471772Sjl139090 ddi_acc_handle_t h; 12481772Sjl139090 12491772Sjl139090 if (fc_cell2int(cp->nargs) != 3) 12501772Sjl139090 return (fc_syntax_error(cp, "nargs must be 3")); 12511772Sjl139090 12521772Sjl139090 if (fc_cell2int(cp->nresults) < 1) 12531772Sjl139090 return (fc_syntax_error(cp, "nresults must be >= 1")); 12541772Sjl139090 12551772Sjl139090 rspec.regspec_size = len = fc_cell2size(fc_arg(cp, 0)); 12561772Sjl139090 rspec.regspec_bustype = fc_cell2uint(fc_arg(cp, 1)); 12571772Sjl139090 rspec.regspec_addr = fc_cell2uint(fc_arg(cp, 2)); 12581772Sjl139090 12591772Sjl139090 acc.devacc_attr_version = DDI_DEVICE_ATTR_V0; 12601772Sjl139090 acc.devacc_attr_endian_flags = DDI_STRUCTURE_BE_ACC; 12611772Sjl139090 acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 12621772Sjl139090 12631772Sjl139090 FC_DEBUG3(1, CE_CONT, "opl_map_in: attempting map in " 12641772Sjl139090 "address 0x%08x.%08x length %x\n", rspec.regspec_bustype, 12651772Sjl139090 rspec.regspec_addr, rspec.regspec_size); 12661772Sjl139090 12671772Sjl139090 error = opl_map_phys(rp->child, &rspec, &virt, &acc, &h); 12681772Sjl139090 12691772Sjl139090 if (error) { 12701772Sjl139090 FC_DEBUG3(1, CE_CONT, "opl_map_in: map in failed - " 12711772Sjl139090 "address 0x%08x.%08x length %x\n", rspec.regspec_bustype, 12721772Sjl139090 rspec.regspec_addr, rspec.regspec_size); 12731772Sjl139090 12741772Sjl139090 return (fc_priv_error(cp, "opl map-in failed")); 12751772Sjl139090 } 12761772Sjl139090 12771772Sjl139090 FC_DEBUG1(3, CE_CONT, "opl_map_in: returning virt %p\n", virt); 12781772Sjl139090 12791772Sjl139090 cp->nresults = fc_int2cell(1); 12801772Sjl139090 fc_result(cp, 0) = fc_ptr2cell(virt); 12811772Sjl139090 12821772Sjl139090 /* 12831772Sjl139090 * Log this resource ... 12841772Sjl139090 */ 12851772Sjl139090 resp = kmem_zalloc(sizeof (struct fc_resource), KM_SLEEP); 12861772Sjl139090 resp->type = RT_MAP; 12871772Sjl139090 resp->fc_map_virt = virt; 12881772Sjl139090 resp->fc_map_len = len; 12891772Sjl139090 resp->fc_map_handle = h; 12901772Sjl139090 fc_add_resource(rp, resp); 12911772Sjl139090 12921772Sjl139090 return (fc_success_op(ap, rp, cp)); 12931772Sjl139090 } 12941772Sjl139090 12951772Sjl139090 /* 12961772Sjl139090 * map-out (virt size -- ) 12971772Sjl139090 */ 12981772Sjl139090 static int 12991772Sjl139090 opl_map_out(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 13001772Sjl139090 { 13011772Sjl139090 caddr_t virt; 13021772Sjl139090 size_t len; 13031772Sjl139090 struct fc_resource *resp; 13041772Sjl139090 13051772Sjl139090 if (fc_cell2int(cp->nargs) != 2) 13061772Sjl139090 return (fc_syntax_error(cp, "nargs must be 2")); 13071772Sjl139090 13081772Sjl139090 virt = fc_cell2ptr(fc_arg(cp, 1)); 13091772Sjl139090 13101772Sjl139090 len = fc_cell2size(fc_arg(cp, 0)); 13111772Sjl139090 13121772Sjl139090 FC_DEBUG2(1, CE_CONT, "opl_map_out: attempting map out %p %x\n", 13131772Sjl139090 virt, len); 13141772Sjl139090 13151772Sjl139090 /* 13161772Sjl139090 * Find if this request matches a mapping resource we set up. 13171772Sjl139090 */ 13181772Sjl139090 fc_lock_resource_list(rp); 13191772Sjl139090 for (resp = rp->head; resp != NULL; resp = resp->next) { 13201772Sjl139090 if (resp->type != RT_MAP) 13211772Sjl139090 continue; 13221772Sjl139090 if (resp->fc_map_virt != virt) 13231772Sjl139090 continue; 13241772Sjl139090 if (resp->fc_map_len == len) 13251772Sjl139090 break; 13261772Sjl139090 } 13271772Sjl139090 fc_unlock_resource_list(rp); 13281772Sjl139090 13291772Sjl139090 if (resp == NULL) 13301772Sjl139090 return (fc_priv_error(cp, "request doesn't match a " 13311772Sjl139090 "known mapping")); 13321772Sjl139090 13331772Sjl139090 opl_unmap_phys(&resp->fc_map_handle); 13341772Sjl139090 13351772Sjl139090 /* 13361772Sjl139090 * remove the resource from the list and release it. 13371772Sjl139090 */ 13381772Sjl139090 fc_rem_resource(rp, resp); 13391772Sjl139090 kmem_free(resp, sizeof (struct fc_resource)); 13401772Sjl139090 13411772Sjl139090 cp->nresults = fc_int2cell(0); 13421772Sjl139090 return (fc_success_op(ap, rp, cp)); 13431772Sjl139090 } 13441772Sjl139090 13451772Sjl139090 static int 13461772Sjl139090 opl_register_fetch(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 13471772Sjl139090 { 13481772Sjl139090 size_t len; 13491772Sjl139090 caddr_t virt; 13501772Sjl139090 int error = 0; 13511772Sjl139090 uint64_t v; 13521772Sjl139090 uint64_t x; 13531772Sjl139090 uint32_t l; 13541772Sjl139090 uint16_t w; 13551772Sjl139090 uint8_t b; 13561772Sjl139090 char *service = fc_cell2ptr(cp->svc_name); 13571772Sjl139090 struct fc_resource *resp; 13581772Sjl139090 13591772Sjl139090 if (fc_cell2int(cp->nargs) != 1) 13601772Sjl139090 return (fc_syntax_error(cp, "nargs must be 1")); 13611772Sjl139090 13621772Sjl139090 if (fc_cell2int(cp->nresults) < 1) 13631772Sjl139090 return (fc_syntax_error(cp, "nresults must be >= 1")); 13641772Sjl139090 13651772Sjl139090 virt = fc_cell2ptr(fc_arg(cp, 0)); 13661772Sjl139090 13671772Sjl139090 /* 13681772Sjl139090 * Determine the access width .. we can switch on the 2nd 13691772Sjl139090 * character of the name which is "rx@", "rl@", "rb@" or "rw@" 13701772Sjl139090 */ 13711772Sjl139090 switch (*(service + 1)) { 13721772Sjl139090 case 'x': len = sizeof (x); break; 13731772Sjl139090 case 'l': len = sizeof (l); break; 13741772Sjl139090 case 'w': len = sizeof (w); break; 13751772Sjl139090 case 'b': len = sizeof (b); break; 13761772Sjl139090 } 13771772Sjl139090 13781772Sjl139090 /* 13791772Sjl139090 * Check the alignment ... 13801772Sjl139090 */ 13811772Sjl139090 if (((intptr_t)virt & (len - 1)) != 0) 13821772Sjl139090 return (fc_priv_error(cp, "unaligned access")); 13831772Sjl139090 13841772Sjl139090 /* 13851772Sjl139090 * Find if this virt is 'within' a request we know about 13861772Sjl139090 */ 13871772Sjl139090 fc_lock_resource_list(rp); 13881772Sjl139090 for (resp = rp->head; resp != NULL; resp = resp->next) { 13891772Sjl139090 if (resp->type == RT_MAP) { 13901772Sjl139090 if ((virt >= (caddr_t)resp->fc_map_virt) && 13911772Sjl139090 ((virt + len) <= 13921772Sjl139090 ((caddr_t)resp->fc_map_virt + resp->fc_map_len))) 13931772Sjl139090 break; 13941772Sjl139090 } else if (resp->type == RT_CONTIGIOUS) { 13951772Sjl139090 if ((virt >= (caddr_t)resp->fc_contig_virt) && ((virt + len) 13961772Sjl139090 <= ((caddr_t)resp->fc_contig_virt + 13971772Sjl139090 resp->fc_contig_len))) 13981772Sjl139090 break; 13991772Sjl139090 } 14001772Sjl139090 } 14011772Sjl139090 fc_unlock_resource_list(rp); 14021772Sjl139090 14031772Sjl139090 if (resp == NULL) { 14041772Sjl139090 return (fc_priv_error(cp, "request not within " 14051772Sjl139090 "known mappings")); 14061772Sjl139090 } 14071772Sjl139090 14081772Sjl139090 switch (len) { 14091772Sjl139090 case sizeof (x): 14101772Sjl139090 if (resp->type == RT_MAP) 14111772Sjl139090 error = ddi_peek64(rp->child, 14121772Sjl139090 (int64_t *)virt, (int64_t *)&x); 14131772Sjl139090 else /* RT_CONTIGIOUS */ 14141772Sjl139090 x = *(int64_t *)virt; 14151772Sjl139090 v = x; 14161772Sjl139090 break; 14171772Sjl139090 case sizeof (l): 14181772Sjl139090 if (resp->type == RT_MAP) 14191772Sjl139090 error = ddi_peek32(rp->child, 14201772Sjl139090 (int32_t *)virt, (int32_t *)&l); 14211772Sjl139090 else /* RT_CONTIGIOUS */ 14221772Sjl139090 l = *(int32_t *)virt; 14231772Sjl139090 v = l; 14241772Sjl139090 break; 14251772Sjl139090 case sizeof (w): 14261772Sjl139090 if (resp->type == RT_MAP) 14271772Sjl139090 error = ddi_peek16(rp->child, 14281772Sjl139090 (int16_t *)virt, (int16_t *)&w); 14291772Sjl139090 else /* RT_CONTIGIOUS */ 14301772Sjl139090 w = *(int16_t *)virt; 14311772Sjl139090 v = w; 14321772Sjl139090 break; 14331772Sjl139090 case sizeof (b): 14341772Sjl139090 if (resp->type == RT_MAP) 14351772Sjl139090 error = ddi_peek8(rp->child, 14361772Sjl139090 (int8_t *)virt, (int8_t *)&b); 14371772Sjl139090 else /* RT_CONTIGIOUS */ 14381772Sjl139090 b = *(int8_t *)virt; 14391772Sjl139090 v = b; 14401772Sjl139090 break; 14411772Sjl139090 } 14421772Sjl139090 14431772Sjl139090 if (error == DDI_FAILURE) { 14441772Sjl139090 FC_DEBUG2(1, CE_CONT, "opl_register_fetch: access error " 14451772Sjl139090 "accessing virt %p len %d\n", virt, len); 14461772Sjl139090 return (fc_priv_error(cp, "access error")); 14471772Sjl139090 } 14481772Sjl139090 14491772Sjl139090 FC_DEBUG3(1, CE_CONT, "register_fetch (%s) %llx %llx\n", 14501772Sjl139090 service, virt, v); 14511772Sjl139090 14521772Sjl139090 cp->nresults = fc_int2cell(1); 14531772Sjl139090 switch (len) { 14541772Sjl139090 case sizeof (x): fc_result(cp, 0) = x; break; 14551772Sjl139090 case sizeof (l): fc_result(cp, 0) = fc_uint32_t2cell(l); break; 14561772Sjl139090 case sizeof (w): fc_result(cp, 0) = fc_uint16_t2cell(w); break; 14571772Sjl139090 case sizeof (b): fc_result(cp, 0) = fc_uint8_t2cell(b); break; 14581772Sjl139090 } 14591772Sjl139090 return (fc_success_op(ap, rp, cp)); 14601772Sjl139090 } 14611772Sjl139090 14621772Sjl139090 static int 14631772Sjl139090 opl_register_store(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 14641772Sjl139090 { 14651772Sjl139090 size_t len; 14661772Sjl139090 caddr_t virt; 14671772Sjl139090 uint64_t v; 14681772Sjl139090 uint64_t x; 14691772Sjl139090 uint32_t l; 14701772Sjl139090 uint16_t w; 14711772Sjl139090 uint8_t b; 14721772Sjl139090 char *service = fc_cell2ptr(cp->svc_name); 14731772Sjl139090 struct fc_resource *resp; 14741772Sjl139090 int error = 0; 14751772Sjl139090 14761772Sjl139090 if (fc_cell2int(cp->nargs) != 2) 14771772Sjl139090 return (fc_syntax_error(cp, "nargs must be 2")); 14781772Sjl139090 14791772Sjl139090 virt = fc_cell2ptr(fc_arg(cp, 0)); 14801772Sjl139090 14811772Sjl139090 /* 14821772Sjl139090 * Determine the access width .. we can switch on the 2nd 14831772Sjl139090 * character of the name which is "rx!", "rl!", "rb!" or "rw!" 14841772Sjl139090 */ 14851772Sjl139090 switch (*(service + 1)) { 14861772Sjl139090 case 'x': 14871772Sjl139090 len = sizeof (x); 14881772Sjl139090 x = fc_arg(cp, 1); 14891772Sjl139090 v = x; 14901772Sjl139090 break; 14911772Sjl139090 case 'l': 14921772Sjl139090 len = sizeof (l); 14931772Sjl139090 l = fc_cell2uint32_t(fc_arg(cp, 1)); 14941772Sjl139090 v = l; 14951772Sjl139090 break; 14961772Sjl139090 case 'w': 14971772Sjl139090 len = sizeof (w); 14981772Sjl139090 w = fc_cell2uint16_t(fc_arg(cp, 1)); 14991772Sjl139090 v = w; 15001772Sjl139090 break; 15011772Sjl139090 case 'b': 15021772Sjl139090 len = sizeof (b); 15031772Sjl139090 b = fc_cell2uint8_t(fc_arg(cp, 1)); 15041772Sjl139090 v = b; 15051772Sjl139090 break; 15061772Sjl139090 } 15071772Sjl139090 15081772Sjl139090 FC_DEBUG3(1, CE_CONT, "register_store (%s) %llx %llx\n", 15091772Sjl139090 service, virt, v); 15101772Sjl139090 15111772Sjl139090 /* 15121772Sjl139090 * Check the alignment ... 15131772Sjl139090 */ 15141772Sjl139090 if (((intptr_t)virt & (len - 1)) != 0) 15151772Sjl139090 return (fc_priv_error(cp, "unaligned access")); 15161772Sjl139090 15171772Sjl139090 /* 15181772Sjl139090 * Find if this virt is 'within' a request we know about 15191772Sjl139090 */ 15201772Sjl139090 fc_lock_resource_list(rp); 15211772Sjl139090 for (resp = rp->head; resp != NULL; resp = resp->next) { 15221772Sjl139090 if (resp->type == RT_MAP) { 15231772Sjl139090 if ((virt >= (caddr_t)resp->fc_map_virt) && 15241772Sjl139090 ((virt + len) <= 15251772Sjl139090 ((caddr_t)resp->fc_map_virt + resp->fc_map_len))) 15261772Sjl139090 break; 15271772Sjl139090 } else if (resp->type == RT_CONTIGIOUS) { 15281772Sjl139090 if ((virt >= (caddr_t)resp->fc_contig_virt) && ((virt + len) 15291772Sjl139090 <= ((caddr_t)resp->fc_contig_virt + 15301772Sjl139090 resp->fc_contig_len))) 15311772Sjl139090 break; 15321772Sjl139090 } 15331772Sjl139090 } 15341772Sjl139090 fc_unlock_resource_list(rp); 15351772Sjl139090 15361772Sjl139090 if (resp == NULL) 15371772Sjl139090 return (fc_priv_error(cp, "request not within" 15381772Sjl139090 "known mappings")); 15391772Sjl139090 15401772Sjl139090 switch (len) { 15411772Sjl139090 case sizeof (x): 15421772Sjl139090 if (resp->type == RT_MAP) 15431772Sjl139090 error = ddi_poke64(rp->child, (int64_t *)virt, x); 15441772Sjl139090 else if (resp->type == RT_CONTIGIOUS) 15451772Sjl139090 *(uint64_t *)virt = x; 15461772Sjl139090 break; 15471772Sjl139090 case sizeof (l): 15481772Sjl139090 if (resp->type == RT_MAP) 15491772Sjl139090 error = ddi_poke32(rp->child, (int32_t *)virt, l); 15501772Sjl139090 else if (resp->type == RT_CONTIGIOUS) 15511772Sjl139090 *(uint32_t *)virt = l; 15521772Sjl139090 break; 15531772Sjl139090 case sizeof (w): 15541772Sjl139090 if (resp->type == RT_MAP) 15551772Sjl139090 error = ddi_poke16(rp->child, (int16_t *)virt, w); 15561772Sjl139090 else if (resp->type == RT_CONTIGIOUS) 15571772Sjl139090 *(uint16_t *)virt = w; 15581772Sjl139090 break; 15591772Sjl139090 case sizeof (b): 15601772Sjl139090 if (resp->type == RT_MAP) 15611772Sjl139090 error = ddi_poke8(rp->child, (int8_t *)virt, b); 15621772Sjl139090 else if (resp->type == RT_CONTIGIOUS) 15631772Sjl139090 *(uint8_t *)virt = b; 15641772Sjl139090 break; 15651772Sjl139090 } 15661772Sjl139090 15671772Sjl139090 if (error == DDI_FAILURE) { 15681772Sjl139090 FC_DEBUG2(1, CE_CONT, "opl_register_store: access error " 15691772Sjl139090 "accessing virt %p len %d\n", virt, len); 15701772Sjl139090 return (fc_priv_error(cp, "access error")); 15711772Sjl139090 } 15721772Sjl139090 15731772Sjl139090 cp->nresults = fc_int2cell(0); 15741772Sjl139090 return (fc_success_op(ap, rp, cp)); 15751772Sjl139090 } 15761772Sjl139090 15771772Sjl139090 /* 15781772Sjl139090 * opl_claim_memory 15791772Sjl139090 * 15801772Sjl139090 * claim-memory (align size vhint -- vaddr) 15811772Sjl139090 */ 15821772Sjl139090 static int 15831772Sjl139090 opl_claim_memory(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 15841772Sjl139090 { 15851772Sjl139090 int align, size, vhint; 15861772Sjl139090 uint64_t answer, alen; 15871772Sjl139090 ndi_ra_request_t request; 15881772Sjl139090 struct fc_resource *resp; 15891772Sjl139090 15901772Sjl139090 if (fc_cell2int(cp->nargs) != 3) 15911772Sjl139090 return (fc_syntax_error(cp, "nargs must be 3")); 15921772Sjl139090 15931772Sjl139090 if (fc_cell2int(cp->nresults) < 1) 15941772Sjl139090 return (fc_syntax_error(cp, "nresults must be >= 1")); 15951772Sjl139090 15961772Sjl139090 vhint = fc_cell2int(fc_arg(cp, 2)); 15971772Sjl139090 size = fc_cell2int(fc_arg(cp, 1)); 15981772Sjl139090 align = fc_cell2int(fc_arg(cp, 0)); 15991772Sjl139090 16001772Sjl139090 FC_DEBUG3(1, CE_CONT, "opl_claim_memory: align=0x%x size=0x%x " 16011772Sjl139090 "vhint=0x%x\n", align, size, vhint); 16021772Sjl139090 16031772Sjl139090 if (size == 0) { 16041772Sjl139090 cmn_err(CE_WARN, "opl_claim_memory - unable to allocate " 16051772Sjl139090 "contiguous memory of size zero\n"); 16061772Sjl139090 return (fc_priv_error(cp, "allocation error")); 16071772Sjl139090 } 16081772Sjl139090 16091772Sjl139090 if (vhint) { 16101772Sjl139090 cmn_err(CE_WARN, "opl_claim_memory - vhint is not zero " 16111772Sjl139090 "vhint=0x%x - Ignoring Argument\n", vhint); 16121772Sjl139090 } 16131772Sjl139090 16141772Sjl139090 bzero((caddr_t)&request, sizeof (ndi_ra_request_t)); 16151772Sjl139090 request.ra_flags = NDI_RA_ALLOC_BOUNDED; 16161772Sjl139090 request.ra_boundbase = 0; 16171772Sjl139090 request.ra_boundlen = 0xffffffff; 16181772Sjl139090 request.ra_len = size; 16191772Sjl139090 request.ra_align_mask = align - 1; 16201772Sjl139090 16211772Sjl139090 if (ndi_ra_alloc(ddi_root_node(), &request, &answer, &alen, 16221772Sjl139090 "opl-fcodemem", NDI_RA_PASS) != NDI_SUCCESS) { 16231772Sjl139090 cmn_err(CE_WARN, "opl_claim_memory - unable to allocate " 16241772Sjl139090 "contiguous memory\n"); 16251772Sjl139090 return (fc_priv_error(cp, "allocation error")); 16261772Sjl139090 } 16271772Sjl139090 16281772Sjl139090 FC_DEBUG2(1, CE_CONT, "opl_claim_memory: address allocated=0x%lx " 16291772Sjl139090 "size=0x%x\n", answer, alen); 16301772Sjl139090 16311772Sjl139090 cp->nresults = fc_int2cell(1); 16321772Sjl139090 fc_result(cp, 0) = answer; 16331772Sjl139090 16341772Sjl139090 /* 16351772Sjl139090 * Log this resource ... 16361772Sjl139090 */ 16371772Sjl139090 resp = kmem_zalloc(sizeof (struct fc_resource), KM_SLEEP); 16381772Sjl139090 resp->type = RT_CONTIGIOUS; 16391772Sjl139090 resp->fc_contig_virt = (void *)answer; 16401772Sjl139090 resp->fc_contig_len = size; 16411772Sjl139090 fc_add_resource(rp, resp); 16421772Sjl139090 16431772Sjl139090 return (fc_success_op(ap, rp, cp)); 16441772Sjl139090 } 16451772Sjl139090 16461772Sjl139090 /* 16471772Sjl139090 * opl_release_memory 16481772Sjl139090 * 16491772Sjl139090 * release-memory (size vaddr -- ) 16501772Sjl139090 */ 16511772Sjl139090 static int 16521772Sjl139090 opl_release_memory(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 16531772Sjl139090 { 16541772Sjl139090 int32_t vaddr, size; 16551772Sjl139090 struct fc_resource *resp; 16561772Sjl139090 16571772Sjl139090 if (fc_cell2int(cp->nargs) != 2) 16581772Sjl139090 return (fc_syntax_error(cp, "nargs must be 2")); 16591772Sjl139090 16601772Sjl139090 if (fc_cell2int(cp->nresults) != 0) 16611772Sjl139090 return (fc_syntax_error(cp, "nresults must be 0")); 16621772Sjl139090 16631772Sjl139090 vaddr = fc_cell2int(fc_arg(cp, 1)); 16641772Sjl139090 size = fc_cell2int(fc_arg(cp, 0)); 16651772Sjl139090 16661772Sjl139090 FC_DEBUG2(1, CE_CONT, "opl_release_memory: vaddr=0x%x size=0x%x\n", 16671772Sjl139090 vaddr, size); 16681772Sjl139090 16691772Sjl139090 /* 16701772Sjl139090 * Find if this request matches a mapping resource we set up. 16711772Sjl139090 */ 16721772Sjl139090 fc_lock_resource_list(rp); 16731772Sjl139090 for (resp = rp->head; resp != NULL; resp = resp->next) { 16741772Sjl139090 if (resp->type != RT_CONTIGIOUS) 16751772Sjl139090 continue; 16761772Sjl139090 if (resp->fc_contig_virt != (void *)(uintptr_t)vaddr) 16771772Sjl139090 continue; 16781772Sjl139090 if (resp->fc_contig_len == size) 16791772Sjl139090 break; 16801772Sjl139090 } 16811772Sjl139090 fc_unlock_resource_list(rp); 16821772Sjl139090 16831772Sjl139090 if (resp == NULL) 16841772Sjl139090 return (fc_priv_error(cp, "request doesn't match a " 16851772Sjl139090 "known mapping")); 16861772Sjl139090 16871772Sjl139090 (void) ndi_ra_free(ddi_root_node(), vaddr, size, 16881772Sjl139090 "opl-fcodemem", NDI_RA_PASS); 16891772Sjl139090 16901772Sjl139090 /* 16911772Sjl139090 * remove the resource from the list and release it. 16921772Sjl139090 */ 16931772Sjl139090 fc_rem_resource(rp, resp); 16941772Sjl139090 kmem_free(resp, sizeof (struct fc_resource)); 16951772Sjl139090 16961772Sjl139090 cp->nresults = fc_int2cell(0); 16971772Sjl139090 16981772Sjl139090 return (fc_success_op(ap, rp, cp)); 16991772Sjl139090 } 17001772Sjl139090 17011772Sjl139090 /* 17021772Sjl139090 * opl_vtop 17031772Sjl139090 * 17041772Sjl139090 * vtop (vaddr -- paddr.lo paddr.hi) 17051772Sjl139090 */ 17061772Sjl139090 static int 17071772Sjl139090 opl_vtop(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 17081772Sjl139090 { 17091772Sjl139090 int vaddr; 17101772Sjl139090 uint64_t paddr; 17111772Sjl139090 struct fc_resource *resp; 17121772Sjl139090 17131772Sjl139090 if (fc_cell2int(cp->nargs) != 1) 17141772Sjl139090 return (fc_syntax_error(cp, "nargs must be 1")); 17151772Sjl139090 17161772Sjl139090 if (fc_cell2int(cp->nresults) >= 3) 17171772Sjl139090 return (fc_syntax_error(cp, "nresults must be less than 2")); 17181772Sjl139090 17191772Sjl139090 vaddr = fc_cell2int(fc_arg(cp, 0)); 17201772Sjl139090 17211772Sjl139090 /* 17221772Sjl139090 * Find if this request matches a mapping resource we set up. 17231772Sjl139090 */ 17241772Sjl139090 fc_lock_resource_list(rp); 17251772Sjl139090 for (resp = rp->head; resp != NULL; resp = resp->next) { 17261772Sjl139090 if (resp->type != RT_CONTIGIOUS) 17271772Sjl139090 continue; 17281772Sjl139090 if (resp->fc_contig_virt == (void *)(uintptr_t)vaddr) 17291772Sjl139090 break; 17301772Sjl139090 } 17311772Sjl139090 fc_unlock_resource_list(rp); 17321772Sjl139090 17331772Sjl139090 if (resp == NULL) 17341772Sjl139090 return (fc_priv_error(cp, "request doesn't match a " 17351772Sjl139090 "known mapping")); 17361772Sjl139090 17371772Sjl139090 paddr = va_to_pa((void *)(uintptr_t)vaddr); 17381772Sjl139090 17391772Sjl139090 FC_DEBUG2(1, CE_CONT, "opl_vtop: vaddr=0x%x paddr=0x%x\n", 17401772Sjl139090 vaddr, paddr); 17411772Sjl139090 17421772Sjl139090 cp->nresults = fc_int2cell(2); 17431772Sjl139090 17441772Sjl139090 fc_result(cp, 0) = paddr; 17451772Sjl139090 fc_result(cp, 1) = 0; 17461772Sjl139090 17471772Sjl139090 return (fc_success_op(ap, rp, cp)); 17481772Sjl139090 } 17491772Sjl139090 17501772Sjl139090 static int 17511772Sjl139090 opl_config_child(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 17521772Sjl139090 { 17531772Sjl139090 fc_phandle_t h; 17541772Sjl139090 17551772Sjl139090 if (fc_cell2int(cp->nargs) != 0) 17561772Sjl139090 return (fc_syntax_error(cp, "nargs must be 0")); 17571772Sjl139090 17581772Sjl139090 if (fc_cell2int(cp->nresults) < 1) 17591772Sjl139090 return (fc_syntax_error(cp, "nresults must be >= 1")); 17601772Sjl139090 17611772Sjl139090 h = fc_dip_to_phandle(fc_handle_to_phandle_head(rp), rp->child); 17621772Sjl139090 17631772Sjl139090 cp->nresults = fc_int2cell(1); 17641772Sjl139090 fc_result(cp, 0) = fc_phandle2cell(h); 17651772Sjl139090 17661772Sjl139090 return (fc_success_op(ap, rp, cp)); 17671772Sjl139090 } 17681772Sjl139090 17691772Sjl139090 static int 17701772Sjl139090 opl_get_fcode(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 17711772Sjl139090 { 17721772Sjl139090 caddr_t dropin_name_virt, fcode_virt; 17731772Sjl139090 char *dropin_name, *fcode; 17741772Sjl139090 int fcode_len, status; 17751772Sjl139090 17761772Sjl139090 if (fc_cell2int(cp->nargs) != 3) 17771772Sjl139090 return (fc_syntax_error(cp, "nargs must be 3")); 17781772Sjl139090 17791772Sjl139090 if (fc_cell2int(cp->nresults) < 1) 17801772Sjl139090 return (fc_syntax_error(cp, "nresults must be >= 1")); 17811772Sjl139090 17821772Sjl139090 dropin_name_virt = fc_cell2ptr(fc_arg(cp, 0)); 17831772Sjl139090 17841772Sjl139090 fcode_virt = fc_cell2ptr(fc_arg(cp, 1)); 17851772Sjl139090 17861772Sjl139090 fcode_len = fc_cell2int(fc_arg(cp, 2)); 17871772Sjl139090 17881772Sjl139090 dropin_name = kmem_zalloc(FC_SVC_NAME_LEN, KM_SLEEP); 17891772Sjl139090 17901772Sjl139090 FC_DEBUG2(1, CE_CONT, "get_fcode: %x %d\n", fcode_virt, fcode_len); 17911772Sjl139090 17921772Sjl139090 if (copyinstr(fc_cell2ptr(dropin_name_virt), dropin_name, 17931772Sjl139090 FC_SVC_NAME_LEN - 1, NULL)) { 17941772Sjl139090 FC_DEBUG1(1, CE_CONT, "opl_get_fcode: " 17951772Sjl139090 "fault copying in drop in name %p\n", dropin_name_virt); 17961772Sjl139090 status = 0; 17971772Sjl139090 } else { 17981772Sjl139090 FC_DEBUG1(1, CE_CONT, "get_fcode: %s\n", dropin_name); 17991772Sjl139090 18001772Sjl139090 fcode = kmem_zalloc(fcode_len, KM_SLEEP); 18011772Sjl139090 18021772Sjl139090 if ((status = prom_get_fcode(dropin_name, fcode)) != 0) { 18031772Sjl139090 18041772Sjl139090 if (copyout((void *)fcode, (void *)fcode_virt, 18051772Sjl139090 fcode_len)) { 18061772Sjl139090 cmn_err(CE_WARN, " opl_get_fcode: Unable " 18071772Sjl139090 "to copy out fcode image"); 18081772Sjl139090 status = 0; 18091772Sjl139090 } 18101772Sjl139090 } 18111772Sjl139090 18121772Sjl139090 kmem_free(fcode, fcode_len); 18131772Sjl139090 } 18141772Sjl139090 18151772Sjl139090 kmem_free(dropin_name, FC_SVC_NAME_LEN); 18161772Sjl139090 18171772Sjl139090 cp->nresults = fc_int2cell(1); 18181772Sjl139090 fc_result(cp, 0) = status; 18191772Sjl139090 18201772Sjl139090 return (fc_success_op(ap, rp, cp)); 18211772Sjl139090 } 18221772Sjl139090 18231772Sjl139090 static int 18241772Sjl139090 opl_get_fcode_size(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 18251772Sjl139090 { 18261772Sjl139090 caddr_t virt; 18271772Sjl139090 char *dropin_name; 18281772Sjl139090 int len; 18291772Sjl139090 18301772Sjl139090 if (fc_cell2int(cp->nargs) != 1) 18311772Sjl139090 return (fc_syntax_error(cp, "nargs must be 1")); 18321772Sjl139090 18331772Sjl139090 if (fc_cell2int(cp->nresults) < 1) 18341772Sjl139090 return (fc_syntax_error(cp, "nresults must be >= 1")); 18351772Sjl139090 18361772Sjl139090 virt = fc_cell2ptr(fc_arg(cp, 0)); 18371772Sjl139090 18381772Sjl139090 dropin_name = kmem_zalloc(FC_SVC_NAME_LEN, KM_SLEEP); 18391772Sjl139090 18401772Sjl139090 FC_DEBUG0(1, CE_CONT, "opl_get_fcode_size:\n"); 18411772Sjl139090 18421772Sjl139090 if (copyinstr(fc_cell2ptr(virt), dropin_name, 18431772Sjl139090 FC_SVC_NAME_LEN - 1, NULL)) { 18441772Sjl139090 FC_DEBUG1(1, CE_CONT, "opl_get_fcode_size: " 18451772Sjl139090 "fault copying in drop in name %p\n", virt); 18461772Sjl139090 len = 0; 18471772Sjl139090 } else { 18481772Sjl139090 FC_DEBUG1(1, CE_CONT, "opl_get_fcode_size: %s\n", dropin_name); 18491772Sjl139090 18501772Sjl139090 len = prom_get_fcode_size(dropin_name); 18511772Sjl139090 } 18521772Sjl139090 18531772Sjl139090 kmem_free(dropin_name, FC_SVC_NAME_LEN); 18541772Sjl139090 18551772Sjl139090 FC_DEBUG1(1, CE_CONT, "opl_get_fcode_size: fcode_len = %d\n", len); 18561772Sjl139090 18571772Sjl139090 cp->nresults = fc_int2cell(1); 18581772Sjl139090 fc_result(cp, 0) = len; 18591772Sjl139090 18601772Sjl139090 return (fc_success_op(ap, rp, cp)); 18611772Sjl139090 } 18621772Sjl139090 18631772Sjl139090 static int 18641772Sjl139090 opl_map_phys(dev_info_t *dip, struct regspec *phys_spec, 18651772Sjl139090 caddr_t *addrp, ddi_device_acc_attr_t *accattrp, 18661772Sjl139090 ddi_acc_handle_t *handlep) 18671772Sjl139090 { 18681772Sjl139090 ddi_map_req_t mapreq; 18691772Sjl139090 ddi_acc_hdl_t *acc_handlep; 18701772Sjl139090 int result; 18711772Sjl139090 struct regspec *rspecp; 18721772Sjl139090 18731772Sjl139090 *handlep = impl_acc_hdl_alloc(KM_SLEEP, NULL); 18741772Sjl139090 acc_handlep = impl_acc_hdl_get(*handlep); 18751772Sjl139090 acc_handlep->ah_vers = VERS_ACCHDL; 18761772Sjl139090 acc_handlep->ah_dip = dip; 18771772Sjl139090 acc_handlep->ah_rnumber = 0; 18781772Sjl139090 acc_handlep->ah_offset = 0; 18791772Sjl139090 acc_handlep->ah_len = 0; 18801772Sjl139090 acc_handlep->ah_acc = *accattrp; 18811772Sjl139090 rspecp = kmem_zalloc(sizeof (struct regspec), KM_SLEEP); 18821772Sjl139090 *rspecp = *phys_spec; 18831772Sjl139090 /* 18841772Sjl139090 * cache a copy of the reg spec 18851772Sjl139090 */ 18861772Sjl139090 acc_handlep->ah_bus_private = rspecp; 18871772Sjl139090 18881772Sjl139090 mapreq.map_op = DDI_MO_MAP_LOCKED; 18891772Sjl139090 mapreq.map_type = DDI_MT_REGSPEC; 18901772Sjl139090 mapreq.map_obj.rp = (struct regspec *)phys_spec; 18911772Sjl139090 mapreq.map_prot = PROT_READ | PROT_WRITE; 18921772Sjl139090 mapreq.map_flags = DDI_MF_KERNEL_MAPPING; 18931772Sjl139090 mapreq.map_handlep = acc_handlep; 18941772Sjl139090 mapreq.map_vers = DDI_MAP_VERSION; 18951772Sjl139090 18961772Sjl139090 result = ddi_map(dip, &mapreq, 0, 0, addrp); 18971772Sjl139090 18981772Sjl139090 if (result != DDI_SUCCESS) { 18991772Sjl139090 impl_acc_hdl_free(*handlep); 19001772Sjl139090 *handlep = (ddi_acc_handle_t)NULL; 19011772Sjl139090 } else { 19021772Sjl139090 acc_handlep->ah_addr = *addrp; 19031772Sjl139090 } 19041772Sjl139090 19051772Sjl139090 return (result); 19061772Sjl139090 } 19071772Sjl139090 19081772Sjl139090 static void 19091772Sjl139090 opl_unmap_phys(ddi_acc_handle_t *handlep) 19101772Sjl139090 { 19111772Sjl139090 ddi_map_req_t mapreq; 19121772Sjl139090 ddi_acc_hdl_t *acc_handlep; 19131772Sjl139090 struct regspec *rspecp; 19141772Sjl139090 19151772Sjl139090 acc_handlep = impl_acc_hdl_get(*handlep); 19161772Sjl139090 ASSERT(acc_handlep); 19171772Sjl139090 rspecp = acc_handlep->ah_bus_private; 19181772Sjl139090 19191772Sjl139090 mapreq.map_op = DDI_MO_UNMAP; 19201772Sjl139090 mapreq.map_type = DDI_MT_REGSPEC; 19211772Sjl139090 mapreq.map_obj.rp = (struct regspec *)rspecp; 19221772Sjl139090 mapreq.map_prot = PROT_READ | PROT_WRITE; 19231772Sjl139090 mapreq.map_flags = DDI_MF_KERNEL_MAPPING; 19241772Sjl139090 mapreq.map_handlep = acc_handlep; 19251772Sjl139090 mapreq.map_vers = DDI_MAP_VERSION; 19261772Sjl139090 19271772Sjl139090 (void) ddi_map(acc_handlep->ah_dip, &mapreq, acc_handlep->ah_offset, 19281772Sjl139090 acc_handlep->ah_len, &acc_handlep->ah_addr); 19291772Sjl139090 19301772Sjl139090 impl_acc_hdl_free(*handlep); 19311772Sjl139090 /* 19321772Sjl139090 * Free the cached copy 19331772Sjl139090 */ 19341772Sjl139090 kmem_free(rspecp, sizeof (struct regspec)); 19351772Sjl139090 *handlep = (ddi_acc_handle_t)NULL; 19361772Sjl139090 } 19371772Sjl139090 19381772Sjl139090 static int 19391772Sjl139090 opl_get_hwd_va(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 19401772Sjl139090 { 19411772Sjl139090 uint32_t portid; 19421772Sjl139090 void *hwd_virt; 19431772Sjl139090 hwd_header_t *hwd_h = NULL; 19441772Sjl139090 hwd_sb_t *hwd_sb = NULL; 19451772Sjl139090 int lsb, ch, leaf; 19461772Sjl139090 int status = 1; 19471772Sjl139090 19481772Sjl139090 /* Check the argument */ 19491772Sjl139090 if (fc_cell2int(cp->nargs) != 2) 19501772Sjl139090 return (fc_syntax_error(cp, "nargs must be 2")); 19511772Sjl139090 19521772Sjl139090 if (fc_cell2int(cp->nresults) < 1) 19531772Sjl139090 return (fc_syntax_error(cp, "nresults must be >= 1")); 19541772Sjl139090 19551772Sjl139090 /* Get the parameters */ 19561772Sjl139090 portid = fc_cell2uint32_t(fc_arg(cp, 0)); 19571772Sjl139090 hwd_virt = (void *)fc_cell2ptr(fc_arg(cp, 1)); 19581772Sjl139090 19591772Sjl139090 /* Get the ID numbers */ 19601772Sjl139090 lsb = OPL_IO_PORTID_TO_LSB(portid); 19611772Sjl139090 ch = OPL_PORTID_TO_CHANNEL(portid); 19621772Sjl139090 leaf = OPL_PORTID_TO_LEAF(portid); 19631772Sjl139090 ASSERT(OPL_IO_PORTID(lsb, ch, leaf) == portid); 19641772Sjl139090 19651772Sjl139090 /* Set the pointer of hwd. */ 19661772Sjl139090 if ((hwd_h = (hwd_header_t *)opl_boards[lsb].cfg_hwd) == NULL) { 19671772Sjl139090 return (fc_priv_error(cp, "null hwd header")); 19681772Sjl139090 } 19691772Sjl139090 /* Set the pointer of hwd sb. */ 19701772Sjl139090 if ((hwd_sb = (hwd_sb_t *)((char *)hwd_h + hwd_h->hdr_sb_info_offset)) 19711772Sjl139090 == NULL) { 19721772Sjl139090 return (fc_priv_error(cp, "null hwd sb")); 19731772Sjl139090 } 19741772Sjl139090 19751772Sjl139090 if (ch == OPL_CMU_CHANNEL) { 19761772Sjl139090 /* Copyout CMU-CH HW Descriptor */ 19771772Sjl139090 if (copyout((void *)&hwd_sb->sb_cmu.cmu_ch, 19781772Sjl139090 (void *)hwd_virt, sizeof (hwd_cmu_chan_t))) { 19791772Sjl139090 cmn_err(CE_WARN, "opl_get_hwd_va: " 19801772Sjl139090 "Unable to copy out cmuch descriptor for %x", 19811772Sjl139090 portid); 19821772Sjl139090 status = 0; 19831772Sjl139090 } 19841772Sjl139090 } else { 19851772Sjl139090 /* Copyout PCI-CH HW Descriptor */ 19861772Sjl139090 if (copyout((void *)&hwd_sb->sb_pci_ch[ch].pci_leaf[leaf], 19871772Sjl139090 (void *)hwd_virt, sizeof (hwd_leaf_t))) { 19881772Sjl139090 cmn_err(CE_WARN, "opl_get_hwd_va: " 19891772Sjl139090 "Unable to copy out pcich descriptor for %x", 19901772Sjl139090 portid); 19911772Sjl139090 status = 0; 19921772Sjl139090 } 19931772Sjl139090 } 19941772Sjl139090 19951772Sjl139090 cp->nresults = fc_int2cell(1); 19961772Sjl139090 fc_result(cp, 0) = status; 19971772Sjl139090 19981772Sjl139090 return (fc_success_op(ap, rp, cp)); 19991772Sjl139090 } 20001772Sjl139090 20011772Sjl139090 /* 2002*1982Smv143129 * After Solaris boots, a user can enter OBP using L1A, etc. While in OBP, 2003*1982Smv143129 * interrupts may be received from PCI devices. These interrupts 2004*1982Smv143129 * cannot be handled meaningfully since the system is in OBP. These 2005*1982Smv143129 * interrupts need to be cleared on the CPU side so that the CPU may 2006*1982Smv143129 * continue with whatever it is doing. Devices that have raised the 2007*1982Smv143129 * interrupts are expected to reraise the interrupts after sometime 2008*1982Smv143129 * as they have not been handled. At that time, Solaris will have a 2009*1982Smv143129 * chance to properly service the interrupts. 2010*1982Smv143129 * 2011*1982Smv143129 * The location of the interrupt registers depends on what is present 2012*1982Smv143129 * at a port. OPL currently supports the Oberon and the CMU channel. 2013*1982Smv143129 * The following handler handles both kinds of ports and computes 2014*1982Smv143129 * interrupt register addresses from the specifications and Jupiter Bus 2015*1982Smv143129 * device bindings. 2016*1982Smv143129 * 2017*1982Smv143129 * Fcode drivers install their interrupt handler via a "master-interrupt" 2018*1982Smv143129 * service. For boot time devices, this takes place within OBP. In the case 2019*1982Smv143129 * of DR, OPL uses IKP. The Fcode drivers that run within the efcode framework 2020*1982Smv143129 * attempt to install their handler via the "master-interrupt" service. 2021*1982Smv143129 * However, we cannot meaningfully install the Fcode driver's handler. 2022*1982Smv143129 * Instead, we install our own handler in OBP which does the same thing. 2023*1982Smv143129 * 2024*1982Smv143129 * Note that the only handling done for interrupts here is to clear it 2025*1982Smv143129 * on the CPU side. If any device in the future requires more special 2026*1982Smv143129 * handling, we would have to put in some kind of framework for adding 2027*1982Smv143129 * device-specific handlers. This is *highly* unlikely, but possible. 2028*1982Smv143129 * 2029*1982Smv143129 * Finally, OBP provides a hook called "unix-interrupt-handler" to install 2030*1982Smv143129 * a Solaris-defined master-interrupt handler for a port. The default 2031*1982Smv143129 * definition for this method does nothing. Solaris may override this 2032*1982Smv143129 * with its own definition. This is the way the following handler gets 2033*1982Smv143129 * control from OBP when interrupts happen at a port after L1A, etc. 2034*1982Smv143129 */ 2035*1982Smv143129 2036*1982Smv143129 static char define_master_interrupt_handler[] = 2037*1982Smv143129 2038*1982Smv143129 /* 2039*1982Smv143129 * This method translates an Oberon port id to the base (physical) address 2040*1982Smv143129 * of the interrupt clear registers for that port id. 2041*1982Smv143129 */ 2042*1982Smv143129 2043*1982Smv143129 ": pcich-mid>clear-int-pa ( mid -- pa ) " 2044*1982Smv143129 " dup 1 >> 7 and ( mid ch# ) " 2045*1982Smv143129 " over 4 >> h# 1f and ( mid ch# lsb# ) " 2046*1982Smv143129 " 1 d# 46 << ( mid ch# lsb# pa ) " 2047*1982Smv143129 " swap d# 40 << or ( mid ch# pa ) " 2048*1982Smv143129 " swap d# 37 << or ( mid pa ) " 2049*1982Smv143129 " swap 1 and if h# 70.0000 else h# 60.0000 then " 2050*1982Smv143129 " or h# 1400 or ( pa ) " 2051*1982Smv143129 "; " 2052*1982Smv143129 2053*1982Smv143129 /* 2054*1982Smv143129 * This method translates a CMU channel port id to the base (physical) address 2055*1982Smv143129 * of the interrupt clear registers for that port id. There are two classes of 2056*1982Smv143129 * interrupts that need to be handled for a CMU channel: 2057*1982Smv143129 * - obio interrupts 2058*1982Smv143129 * - pci interrupts 2059*1982Smv143129 * So, there are two addresses that need to be computed. 2060*1982Smv143129 */ 2061*1982Smv143129 2062*1982Smv143129 ": cmuch-mid>clear-int-pa ( mid -- obio-pa pci-pa ) " 2063*1982Smv143129 " dup 1 >> 7 and ( mid ch# ) " 2064*1982Smv143129 " over 4 >> h# 1f and ( mid ch# lsb# ) " 2065*1982Smv143129 " 1 d# 46 << ( mid ch# lsb# pa ) " 2066*1982Smv143129 " swap d# 40 << or ( mid ch# pa ) " 2067*1982Smv143129 " swap d# 37 << or ( mid pa ) " 2068*1982Smv143129 " nip dup h# 1800 + ( pa obio-pa ) " 2069*1982Smv143129 " swap h# 1400 + ( obio-pa pci-pa ) " 2070*1982Smv143129 "; " 2071*1982Smv143129 2072*1982Smv143129 /* 2073*1982Smv143129 * This method checks if a given I/O port ID is valid or not. 2074*1982Smv143129 * For a given LSB, 2075*1982Smv143129 * Oberon ports range from 0 - 3 2076*1982Smv143129 * CMU ch ports range from 4 - 4 2077*1982Smv143129 * 2078*1982Smv143129 * Also, the Oberon supports leaves 0 and 1. 2079*1982Smv143129 * The CMU ch supports only one leaf, leaf 0. 2080*1982Smv143129 */ 2081*1982Smv143129 2082*1982Smv143129 ": valid-io-mid? ( mid -- flag ) " 2083*1982Smv143129 " dup 1 >> 7 and ( mid ch# ) " 2084*1982Smv143129 " dup 4 > if 2drop false exit then ( mid ch# ) " 2085*1982Smv143129 " 4 = swap 1 and 1 = and not " 2086*1982Smv143129 "; " 2087*1982Smv143129 2088*1982Smv143129 /* 2089*1982Smv143129 * This method checks if a given port id is a CMU ch. 2090*1982Smv143129 */ 2091*1982Smv143129 2092*1982Smv143129 ": cmuch? ( mid -- flag ) 1 >> 7 and 4 = ; " 2093*1982Smv143129 2094*1982Smv143129 /* 2095*1982Smv143129 * Given the base address of the array of interrupt clear registers for 2096*1982Smv143129 * a port id, this method iterates over the given interrupt number bitmap 2097*1982Smv143129 * and resets the interrupt on the CPU side for every interrupt number 2098*1982Smv143129 * in the bitmap. Note that physical addresses are used to perform the 2099*1982Smv143129 * writes, not virtual addresses. This allows the handler to work without 2100*1982Smv143129 * any involvement from Solaris. 2101*1982Smv143129 */ 2102*1982Smv143129 2103*1982Smv143129 ": clear-ints ( pa bitmap count -- ) " 2104*1982Smv143129 " 0 do ( pa bitmap ) " 2105*1982Smv143129 " dup 0= if 2drop unloop exit then " 2106*1982Smv143129 " tuck ( bitmap pa bitmap ) " 2107*1982Smv143129 " 1 and if ( bitmap pa ) " 2108*1982Smv143129 " dup i 8 * + 0 swap ( bitmap pa 0 pa' ) " 2109*1982Smv143129 " h# 15 spacex! ( bitmap pa ) " 2110*1982Smv143129 " then ( bitmap pa ) " 2111*1982Smv143129 " swap 1 >> ( pa bitmap ) " 2112*1982Smv143129 " loop " 2113*1982Smv143129 "; " 2114*1982Smv143129 2115*1982Smv143129 /* 2116*1982Smv143129 * This method replaces the master-interrupt handler in OBP. Once 2117*1982Smv143129 * this method is plumbed into OBP, OBP transfers control to this 2118*1982Smv143129 * handler while returning to Solaris from OBP after L1A. This method's 2119*1982Smv143129 * task is to simply reset received interrupts on the CPU side. 2120*1982Smv143129 * When the devices reassert the interrupts later, Solaris will 2121*1982Smv143129 * be able to see them and handle them. 2122*1982Smv143129 * 2123*1982Smv143129 * For each port ID that has interrupts, this method is called 2124*1982Smv143129 * once by OBP. The input arguments are: 2125*1982Smv143129 * mid portid 2126*1982Smv143129 * bitmap bitmap of interrupts that have happened 2127*1982Smv143129 * 2128*1982Smv143129 * This method returns true, if it is able to handle the interrupts. 2129*1982Smv143129 * OBP does nothing further. 2130*1982Smv143129 * 2131*1982Smv143129 * This method returns false, if it encountered a problem. Currently, 2132*1982Smv143129 * the only problem could be an invalid port id. OBP needs to do 2133*1982Smv143129 * its own processing in that case. If this method returns false, 2134*1982Smv143129 * it preserves the mid and bitmap arguments for OBP. 2135*1982Smv143129 */ 2136*1982Smv143129 2137*1982Smv143129 ": unix-resend-mondos ( mid bitmap -- [ mid bitmap false ] | true ) " 2138*1982Smv143129 2139*1982Smv143129 /* 2140*1982Smv143129 * Uncomment the following line if you want to display the input arguments. 2141*1982Smv143129 * This is meant for debugging. 2142*1982Smv143129 * " .\" Bitmap=\" dup u. .\" MID=\" over u. cr " 2143*1982Smv143129 */ 2144*1982Smv143129 2145*1982Smv143129 /* 2146*1982Smv143129 * If the port id is not valid (according to the Oberon and CMU ch 2147*1982Smv143129 * specifications, then return false to OBP to continue further 2148*1982Smv143129 * processing. 2149*1982Smv143129 */ 2150*1982Smv143129 2151*1982Smv143129 " over valid-io-mid? not if ( mid bitmap ) " 2152*1982Smv143129 " false exit " 2153*1982Smv143129 " then " 2154*1982Smv143129 2155*1982Smv143129 /* 2156*1982Smv143129 * If the port is a CMU ch, then the 64-bit bitmap represents 2157*1982Smv143129 * 2 32-bit bitmaps: 2158*1982Smv143129 * - obio interrupt bitmap (20 bits) 2159*1982Smv143129 * - pci interrupt bitmap (32 bits) 2160*1982Smv143129 * 2161*1982Smv143129 * - Split the bitmap into two 2162*1982Smv143129 * - Compute the base addresses of the interrupt clear registers 2163*1982Smv143129 * for both pci interrupts and obio interrupts 2164*1982Smv143129 * - Clear obio interrupts 2165*1982Smv143129 * - Clear pci interrupts 2166*1982Smv143129 */ 2167*1982Smv143129 2168*1982Smv143129 " over cmuch? if ( mid bitmap ) " 2169*1982Smv143129 " xlsplit ( mid pci-bit obio-bit ) " 2170*1982Smv143129 " rot cmuch-mid>clear-int-pa ( pci-bit obio-bit obio-pa pci-pa ) " 2171*1982Smv143129 " >r ( pci-bit obio-bit obio-pa ) ( r: pci-pa ) " 2172*1982Smv143129 " swap d# 20 clear-ints ( pci-bit ) ( r: pci-pa ) " 2173*1982Smv143129 " r> swap d# 32 clear-ints ( ) ( r: ) " 2174*1982Smv143129 2175*1982Smv143129 /* 2176*1982Smv143129 * If the port is an Oberon, then the 64-bit bitmap is used fully. 2177*1982Smv143129 * 2178*1982Smv143129 * - Compute the base address of the interrupt clear registers 2179*1982Smv143129 * - Clear interrupts 2180*1982Smv143129 */ 2181*1982Smv143129 2182*1982Smv143129 " else ( mid bitmap ) " 2183*1982Smv143129 " swap pcich-mid>clear-int-pa ( bitmap pa ) " 2184*1982Smv143129 " swap d# 64 clear-ints ( ) " 2185*1982Smv143129 " then " 2186*1982Smv143129 2187*1982Smv143129 /* 2188*1982Smv143129 * Always return true from here. 2189*1982Smv143129 */ 2190*1982Smv143129 2191*1982Smv143129 " true ( true ) " 2192*1982Smv143129 "; " 2193*1982Smv143129 ; 2194*1982Smv143129 2195*1982Smv143129 static char install_master_interrupt_handler[] = 2196*1982Smv143129 "' unix-resend-mondos to unix-interrupt-handler"; 2197*1982Smv143129 static char handler[] = "unix-interrupt-handler"; 2198*1982Smv143129 static char handler_defined[] = "p\" %s\" find nip swap l! "; 2199*1982Smv143129 2200*1982Smv143129 /*ARGSUSED*/ 2201*1982Smv143129 static int 2202*1982Smv143129 master_interrupt_init(uint32_t portid, uint32_t xt) 2203*1982Smv143129 { 2204*1982Smv143129 uint_t defined; 2205*1982Smv143129 char buf[sizeof (handler) + sizeof (handler_defined)]; 2206*1982Smv143129 2207*1982Smv143129 if (master_interrupt_inited) 2208*1982Smv143129 return (1); 2209*1982Smv143129 2210*1982Smv143129 /* 2211*1982Smv143129 * Check if the defer word "unix-interrupt-handler" is defined. 2212*1982Smv143129 * This must be defined for OPL systems. So, this is only a 2213*1982Smv143129 * sanity check. 2214*1982Smv143129 */ 2215*1982Smv143129 (void) sprintf(buf, handler_defined, handler); 2216*1982Smv143129 prom_interpret(buf, (uintptr_t)&defined, 0, 0, 0, 0); 2217*1982Smv143129 if (!defined) { 2218*1982Smv143129 cmn_err(CE_WARN, "master_interrupt_init: " 2219*1982Smv143129 "%s is not defined\n", handler); 2220*1982Smv143129 return (0); 2221*1982Smv143129 } 2222*1982Smv143129 2223*1982Smv143129 /* 2224*1982Smv143129 * Install the generic master-interrupt handler. Note that 2225*1982Smv143129 * this is only done one time on the first DR operation. 2226*1982Smv143129 * This is because, for OPL, one, single generic handler 2227*1982Smv143129 * handles all ports (Oberon and CMU channel) and all 2228*1982Smv143129 * interrupt sources within each port. 2229*1982Smv143129 * 2230*1982Smv143129 * The current support is only for the Oberon and CMU-channel. 2231*1982Smv143129 * If any others need to be supported, the handler has to be 2232*1982Smv143129 * modified accordingly. 2233*1982Smv143129 */ 2234*1982Smv143129 2235*1982Smv143129 /* 2236*1982Smv143129 * Define the OPL master interrupt handler 2237*1982Smv143129 */ 2238*1982Smv143129 prom_interpret(define_master_interrupt_handler, 0, 0, 0, 0, 0); 2239*1982Smv143129 2240*1982Smv143129 /* 2241*1982Smv143129 * Take over the master interrupt handler from OBP. 2242*1982Smv143129 */ 2243*1982Smv143129 prom_interpret(install_master_interrupt_handler, 0, 0, 0, 0, 0); 2244*1982Smv143129 2245*1982Smv143129 master_interrupt_inited = 1; 2246*1982Smv143129 2247*1982Smv143129 /* 2248*1982Smv143129 * prom_interpret() does not return a status. So, we assume 2249*1982Smv143129 * that the calls succeeded. In reality, the calls may fail 2250*1982Smv143129 * if there is a syntax error, etc in the strings. 2251*1982Smv143129 */ 2252*1982Smv143129 2253*1982Smv143129 return (1); 2254*1982Smv143129 } 2255*1982Smv143129 2256*1982Smv143129 /* 2257*1982Smv143129 * Install the master-interrupt handler for a device. 2258*1982Smv143129 */ 2259*1982Smv143129 static int 2260*1982Smv143129 opl_master_interrupt(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 2261*1982Smv143129 { 2262*1982Smv143129 uint32_t portid, xt; 2263*1982Smv143129 int board, channel, leaf; 2264*1982Smv143129 int status; 2265*1982Smv143129 2266*1982Smv143129 /* Check the argument */ 2267*1982Smv143129 if (fc_cell2int(cp->nargs) != 2) 2268*1982Smv143129 return (fc_syntax_error(cp, "nargs must be 2")); 2269*1982Smv143129 2270*1982Smv143129 if (fc_cell2int(cp->nresults) < 1) 2271*1982Smv143129 return (fc_syntax_error(cp, "nresults must be >= 1")); 2272*1982Smv143129 2273*1982Smv143129 /* Get the parameters */ 2274*1982Smv143129 portid = fc_cell2uint32_t(fc_arg(cp, 0)); 2275*1982Smv143129 xt = fc_cell2uint32_t(fc_arg(cp, 1)); 2276*1982Smv143129 2277*1982Smv143129 board = OPL_IO_PORTID_TO_LSB(portid); 2278*1982Smv143129 channel = OPL_PORTID_TO_CHANNEL(portid); 2279*1982Smv143129 leaf = OPL_PORTID_TO_LEAF(portid); 2280*1982Smv143129 2281*1982Smv143129 if ((board >= HWD_SBS_PER_DOMAIN) || !OPL_VALID_CHANNEL(channel) || 2282*1982Smv143129 (OPL_OBERON_CHANNEL(channel) && !OPL_VALID_LEAF(leaf)) || 2283*1982Smv143129 ((channel == OPL_CMU_CHANNEL) && (leaf != 0))) { 2284*1982Smv143129 FC_DEBUG1(1, CE_CONT, "opl_master_interrupt: invalid port %x\n", 2285*1982Smv143129 portid); 2286*1982Smv143129 status = 0; 2287*1982Smv143129 } else { 2288*1982Smv143129 status = master_interrupt_init(portid, xt); 2289*1982Smv143129 } 2290*1982Smv143129 2291*1982Smv143129 cp->nresults = fc_int2cell(1); 2292*1982Smv143129 fc_result(cp, 0) = status; 2293*1982Smv143129 2294*1982Smv143129 return (fc_success_op(ap, rp, cp)); 2295*1982Smv143129 } 2296*1982Smv143129 2297*1982Smv143129 /* 22981772Sjl139090 * Set the properties for a leaf node (Oberon leaf or CMU channel leaf). 22991772Sjl139090 */ 23001772Sjl139090 /*ARGSUSED*/ 23011772Sjl139090 static int 23021772Sjl139090 opl_create_leaf(dev_info_t *node, void *arg, uint_t flags) 23031772Sjl139090 { 23041772Sjl139090 int ret; 23051772Sjl139090 23061772Sjl139090 OPL_UPDATE_PROP(string, node, "name", OPL_PCI_LEAF_NODE); 23071772Sjl139090 23081772Sjl139090 OPL_UPDATE_PROP(string, node, "status", "okay"); 23091772Sjl139090 23101772Sjl139090 return (DDI_WALK_TERMINATE); 23111772Sjl139090 } 23121772Sjl139090 23131772Sjl139090 static char * 23141772Sjl139090 opl_get_probe_string(opl_probe_t *probe, int channel, int leaf) 23151772Sjl139090 { 23161772Sjl139090 char *probe_string; 23171772Sjl139090 int portid; 23181772Sjl139090 23191772Sjl139090 probe_string = kmem_zalloc(PROBE_STR_SIZE, KM_SLEEP); 23201772Sjl139090 23211772Sjl139090 if (channel == OPL_CMU_CHANNEL) 23221772Sjl139090 portid = probe->pr_sb->sb_cmu.cmu_ch.chan_portid; 23231772Sjl139090 else 23241772Sjl139090 portid = probe-> 23251772Sjl139090 pr_sb->sb_pci_ch[channel].pci_leaf[leaf].leaf_port_id; 23261772Sjl139090 23271772Sjl139090 (void) sprintf(probe_string, "%x", portid); 23281772Sjl139090 23291772Sjl139090 return (probe_string); 23301772Sjl139090 } 23311772Sjl139090 23321772Sjl139090 static int 23331772Sjl139090 opl_probe_leaf(opl_probe_t *probe) 23341772Sjl139090 { 23351772Sjl139090 int channel, leaf, portid, error, circ; 23361772Sjl139090 int board; 23371772Sjl139090 fco_handle_t fco_handle, *cfg_handle; 23381772Sjl139090 dev_info_t *parent, *leaf_node; 23391772Sjl139090 char unit_address[UNIT_ADDR_SIZE]; 23401772Sjl139090 char *probe_string; 23411772Sjl139090 opl_board_cfg_t *board_cfg; 23421772Sjl139090 23431772Sjl139090 board = probe->pr_board; 23441772Sjl139090 channel = probe->pr_channel; 23451772Sjl139090 leaf = probe->pr_leaf; 23461772Sjl139090 parent = ddi_root_node(); 23471772Sjl139090 board_cfg = &opl_boards[board]; 23481772Sjl139090 23491772Sjl139090 ASSERT(OPL_VALID_CHANNEL(channel)); 23501772Sjl139090 ASSERT(OPL_VALID_LEAF(leaf)); 23511772Sjl139090 23521772Sjl139090 if (channel == OPL_CMU_CHANNEL) { 23531772Sjl139090 portid = probe->pr_sb->sb_cmu.cmu_ch.chan_portid; 23541772Sjl139090 cfg_handle = &board_cfg->cfg_cmuch_handle; 23551772Sjl139090 } else { 23561772Sjl139090 portid = probe-> 23571772Sjl139090 pr_sb->sb_pci_ch[channel].pci_leaf[leaf].leaf_port_id; 23581772Sjl139090 cfg_handle = &board_cfg->cfg_pcich_handle[channel][leaf]; 23591772Sjl139090 } 23601772Sjl139090 23611772Sjl139090 /* 23621772Sjl139090 * Prevent any changes to leaf_node until we have bound 23631772Sjl139090 * it to the correct driver. 23641772Sjl139090 */ 23651772Sjl139090 ndi_devi_enter(parent, &circ); 23661772Sjl139090 23671772Sjl139090 /* 23681772Sjl139090 * Ideally, fcode would be run from the "sid_branch_create" 23691772Sjl139090 * callback (that is the primary purpose of that callback). 23701772Sjl139090 * However, the fcode interpreter was written with the 23711772Sjl139090 * assumption that the "new_child" was linked into the 23721772Sjl139090 * device tree. The callback is invoked with the devinfo node 23731772Sjl139090 * in the DS_PROTO state. More investigation is needed before 23741772Sjl139090 * we can invoke the interpreter from the callback. For now, 23751772Sjl139090 * we create the "new_child" in the BOUND state, invoke the 23761772Sjl139090 * fcode interpreter and then rebind the dip to use any 23771772Sjl139090 * compatible properties created by fcode. 23781772Sjl139090 */ 23791772Sjl139090 23801772Sjl139090 probe->pr_parent = parent; 23811772Sjl139090 probe->pr_create = opl_create_leaf; 23821772Sjl139090 probe->pr_hold = 1; 23831772Sjl139090 23841772Sjl139090 leaf_node = opl_create_node(probe); 23851772Sjl139090 if (leaf_node == NULL) { 23861772Sjl139090 23871772Sjl139090 cmn_err(CE_WARN, "IKP: create leaf (%d-%d-%d) failed", 23881772Sjl139090 probe->pr_board, probe->pr_channel, probe->pr_leaf); 23891772Sjl139090 ndi_devi_exit(parent, circ); 23901772Sjl139090 return (-1); 23911772Sjl139090 } 23921772Sjl139090 23931772Sjl139090 /* 23941772Sjl139090 * The platform DR interfaces created the dip in 23951772Sjl139090 * bound state. Bring devinfo node down to linked 23961772Sjl139090 * state and hold it there until compatible 23971772Sjl139090 * properties are created. 23981772Sjl139090 */ 23991772Sjl139090 e_ddi_branch_rele(leaf_node); 24001772Sjl139090 (void) i_ndi_unconfig_node(leaf_node, DS_LINKED, 0); 24011772Sjl139090 ASSERT(i_ddi_node_state(leaf_node) == DS_LINKED); 24021772Sjl139090 e_ddi_branch_hold(leaf_node); 24031772Sjl139090 24041772Sjl139090 mutex_enter(&DEVI(leaf_node)->devi_lock); 24051772Sjl139090 DEVI(leaf_node)->devi_flags |= DEVI_NO_BIND; 24061772Sjl139090 mutex_exit(&DEVI(leaf_node)->devi_lock); 24071772Sjl139090 24081772Sjl139090 /* 24091772Sjl139090 * Drop the busy-hold on parent before calling 24101772Sjl139090 * fcode_interpreter to prevent potential deadlocks 24111772Sjl139090 */ 24121772Sjl139090 ndi_devi_exit(parent, circ); 24131772Sjl139090 24141772Sjl139090 (void) sprintf(unit_address, "%x", portid); 24151772Sjl139090 24161772Sjl139090 /* 24171772Sjl139090 * Get the probe string 24181772Sjl139090 */ 24191772Sjl139090 probe_string = opl_get_probe_string(probe, channel, leaf); 24201772Sjl139090 24211772Sjl139090 /* 24221772Sjl139090 * The fcode pointer specified here is NULL and the fcode 24231772Sjl139090 * size specified here is 0. This causes the user-level 24241772Sjl139090 * fcode interpreter to issue a request to the fcode 24251772Sjl139090 * driver to get the Oberon/cmu-ch fcode. 24261772Sjl139090 */ 24271772Sjl139090 fco_handle = opl_fc_ops_alloc_handle(parent, leaf_node, 24281772Sjl139090 NULL, 0, unit_address, probe_string); 24291772Sjl139090 24301772Sjl139090 error = fcode_interpreter(parent, &opl_fc_do_op, fco_handle); 24311772Sjl139090 24321772Sjl139090 if (error != 0) { 24331772Sjl139090 cmn_err(CE_WARN, "IKP: Unable to probe PCI leaf (%d-%d-%d)", 24341772Sjl139090 probe->pr_board, probe->pr_channel, probe->pr_leaf); 24351772Sjl139090 24361772Sjl139090 opl_fc_ops_free_handle(fco_handle); 24371772Sjl139090 24381772Sjl139090 if (probe_string != NULL) 24391772Sjl139090 kmem_free(probe_string, PROBE_STR_SIZE); 24401772Sjl139090 24411772Sjl139090 (void) opl_destroy_node(leaf_node); 24421772Sjl139090 } else { 24431772Sjl139090 *cfg_handle = fco_handle; 24441772Sjl139090 24451772Sjl139090 if (channel == OPL_CMU_CHANNEL) 24461772Sjl139090 board_cfg->cfg_cmuch_probe_str = probe_string; 24471772Sjl139090 else 24481772Sjl139090 board_cfg->cfg_pcich_probe_str[channel][leaf] 24491772Sjl139090 = probe_string; 24501772Sjl139090 24511772Sjl139090 /* 24521772Sjl139090 * Compatible properties (if any) have been created, 24531772Sjl139090 * so bind driver. 24541772Sjl139090 */ 24551772Sjl139090 ndi_devi_enter(parent, &circ); 24561772Sjl139090 ASSERT(i_ddi_node_state(leaf_node) <= DS_LINKED); 24571772Sjl139090 24581772Sjl139090 mutex_enter(&DEVI(leaf_node)->devi_lock); 24591772Sjl139090 DEVI(leaf_node)->devi_flags &= ~DEVI_NO_BIND; 24601772Sjl139090 mutex_exit(&DEVI(leaf_node)->devi_lock); 24611772Sjl139090 24621772Sjl139090 ndi_devi_exit(parent, circ); 24631772Sjl139090 24641772Sjl139090 if (ndi_devi_bind_driver(leaf_node, 0) != 24651772Sjl139090 DDI_SUCCESS) { 24661772Sjl139090 cmn_err(CE_WARN, 24671772Sjl139090 "IKP: Unable to bind PCI leaf (%d-%d-%d)", 24681772Sjl139090 probe->pr_board, probe->pr_channel, 24691772Sjl139090 probe->pr_leaf); 24701772Sjl139090 } 24711772Sjl139090 } 24721772Sjl139090 24731772Sjl139090 if ((error != 0) && (channel == OPL_CMU_CHANNEL)) 24741772Sjl139090 return (-1); 24751772Sjl139090 24761772Sjl139090 return (0); 24771772Sjl139090 } 24781772Sjl139090 24791772Sjl139090 static void 24801772Sjl139090 opl_init_leaves(int myboard) 24811772Sjl139090 { 24821772Sjl139090 dev_info_t *parent, *node; 24831772Sjl139090 char *name; 24841772Sjl139090 int circ, ret; 24851772Sjl139090 int len, portid, board, channel, leaf; 24861772Sjl139090 opl_board_cfg_t *cfg; 24871772Sjl139090 24881772Sjl139090 parent = ddi_root_node(); 24891772Sjl139090 24901772Sjl139090 /* 24911772Sjl139090 * Hold parent node busy to walk its child list 24921772Sjl139090 */ 24931772Sjl139090 ndi_devi_enter(parent, &circ); 24941772Sjl139090 24951772Sjl139090 for (node = ddi_get_child(parent); 24961772Sjl139090 (node != NULL); 24971772Sjl139090 node = ddi_get_next_sibling(node)) { 24981772Sjl139090 24991772Sjl139090 ret = OPL_GET_PROP(string, node, "name", &name, &len); 25001772Sjl139090 if (ret != DDI_PROP_SUCCESS) { 25011772Sjl139090 /* 25021772Sjl139090 * The property does not exist for this node. 25031772Sjl139090 */ 25041772Sjl139090 continue; 25051772Sjl139090 } 25061772Sjl139090 25071772Sjl139090 if (strncmp(name, OPL_PCI_LEAF_NODE, len) == 0) { 25081772Sjl139090 25091772Sjl139090 ret = OPL_GET_PROP(int, node, "portid", &portid, -1); 25101772Sjl139090 if (ret == DDI_PROP_SUCCESS) { 25111772Sjl139090 25121772Sjl139090 ret = OPL_GET_PROP(int, node, "board#", 25131772Sjl139090 &board, -1); 25141772Sjl139090 if ((ret != DDI_PROP_SUCCESS) || 25151772Sjl139090 (board != myboard)) 25161772Sjl139090 continue; 25171772Sjl139090 25181772Sjl139090 cfg = &opl_boards[board]; 25191772Sjl139090 channel = OPL_PORTID_TO_CHANNEL(portid); 25201772Sjl139090 if (channel == OPL_CMU_CHANNEL) { 25211772Sjl139090 25221772Sjl139090 if (cfg->cfg_cmuch_handle != NULL) 25231772Sjl139090 cfg->cfg_cmuch_leaf = node; 25241772Sjl139090 25251772Sjl139090 } else { 25261772Sjl139090 25271772Sjl139090 leaf = OPL_PORTID_TO_LEAF(portid); 25281772Sjl139090 if (cfg->cfg_pcich_handle 25291772Sjl139090 [channel][leaf] != NULL) 25301772Sjl139090 cfg->cfg_pcich_leaf 25311772Sjl139090 [channel][leaf] = node; 25321772Sjl139090 } 25331772Sjl139090 } 25341772Sjl139090 } 25351772Sjl139090 25361772Sjl139090 kmem_free(name, len); 25371772Sjl139090 if (ret != DDI_PROP_SUCCESS) 25381772Sjl139090 break; 25391772Sjl139090 } 25401772Sjl139090 25411772Sjl139090 ndi_devi_exit(parent, circ); 25421772Sjl139090 } 25431772Sjl139090 25441772Sjl139090 /* 25451772Sjl139090 * Create "pci" node and hierarchy for the Oberon channels and the 25461772Sjl139090 * CMU channel. 25471772Sjl139090 */ 25481772Sjl139090 /*ARGSUSED*/ 25491772Sjl139090 static int 25501772Sjl139090 opl_probe_io(opl_probe_t *probe) 25511772Sjl139090 { 25521772Sjl139090 25531772Sjl139090 int i, j; 25541772Sjl139090 hwd_pci_ch_t *channels; 25551772Sjl139090 25561772Sjl139090 if (HWD_STATUS_OK(probe->pr_sb->sb_cmu.cmu_ch.chan_status)) { 25571772Sjl139090 25581772Sjl139090 probe->pr_channel = HWD_CMU_CHANNEL; 25591772Sjl139090 probe->pr_channel_status = 25601772Sjl139090 probe->pr_sb->sb_cmu.cmu_ch.chan_status; 25611772Sjl139090 probe->pr_leaf = 0; 25621772Sjl139090 probe->pr_leaf_status = probe->pr_channel_status; 25631772Sjl139090 25641772Sjl139090 if (opl_probe_leaf(probe) != 0) 25651772Sjl139090 return (-1); 25661772Sjl139090 } 25671772Sjl139090 25681772Sjl139090 channels = &probe->pr_sb->sb_pci_ch[0]; 25691772Sjl139090 25701772Sjl139090 for (i = 0; i < HWD_PCI_CHANNELS_PER_SB; i++) { 25711772Sjl139090 25721772Sjl139090 if (!HWD_STATUS_OK(channels[i].pci_status)) 25731772Sjl139090 continue; 25741772Sjl139090 25751772Sjl139090 probe->pr_channel = i; 25761772Sjl139090 probe->pr_channel_status = channels[i].pci_status; 25771772Sjl139090 25781772Sjl139090 for (j = 0; j < HWD_LEAVES_PER_PCI_CHANNEL; j++) { 25791772Sjl139090 25801772Sjl139090 probe->pr_leaf = j; 25811772Sjl139090 probe->pr_leaf_status = 25821772Sjl139090 channels[i].pci_leaf[j].leaf_status; 25831772Sjl139090 25841772Sjl139090 if (!HWD_STATUS_OK(probe->pr_leaf_status)) 25851772Sjl139090 continue; 25861772Sjl139090 25871772Sjl139090 (void) opl_probe_leaf(probe); 25881772Sjl139090 } 25891772Sjl139090 } 25901772Sjl139090 opl_init_leaves(probe->pr_board); 25911772Sjl139090 return (0); 25921772Sjl139090 } 25931772Sjl139090 25941772Sjl139090 /* 25951772Sjl139090 * Perform the probe in the following order: 25961772Sjl139090 * 25971772Sjl139090 * processors 25981772Sjl139090 * memory 25991772Sjl139090 * IO 26001772Sjl139090 * 26011772Sjl139090 * Each probe function returns 0 on sucess and a non-zero value on failure. 26021772Sjl139090 * What is a failure is determined by the implementor of the probe function. 26031772Sjl139090 * For example, while probing CPUs, any error encountered during probe 26041772Sjl139090 * is considered a failure and causes the whole probe operation to fail. 26051772Sjl139090 * However, for I/O, an error encountered while probing one device 26061772Sjl139090 * should not prevent other devices from being probed. It should not cause 26071772Sjl139090 * the whole probe operation to fail. 26081772Sjl139090 */ 26091772Sjl139090 int 26101772Sjl139090 opl_probe_sb(int board) 26111772Sjl139090 { 26121772Sjl139090 opl_probe_t *probe; 26131772Sjl139090 int ret; 26141772Sjl139090 26151772Sjl139090 if ((board < 0) || (board >= HWD_SBS_PER_DOMAIN)) 26161772Sjl139090 return (-1); 26171772Sjl139090 26181772Sjl139090 ASSERT(opl_cfg_inited != 0); 26191772Sjl139090 26201772Sjl139090 /* 26211772Sjl139090 * If the previous probe failed and left a partially configured 26221772Sjl139090 * board, we need to unprobe the board and start with a clean slate. 26231772Sjl139090 */ 26241772Sjl139090 if ((opl_boards[board].cfg_hwd != NULL) && 26251772Sjl139090 (opl_unprobe_sb(board) != 0)) 26261772Sjl139090 return (-1); 26271772Sjl139090 26281772Sjl139090 ret = 0; 26291772Sjl139090 26301772Sjl139090 probe = kmem_zalloc(sizeof (opl_probe_t), KM_SLEEP); 26311772Sjl139090 probe->pr_board = board; 26321772Sjl139090 26331772Sjl139090 if ((opl_probe_init(probe) != 0) || 26341772Sjl139090 26351772Sjl139090 (opl_probe_cpu_chips(probe) != 0) || 26361772Sjl139090 26371772Sjl139090 (opl_probe_memory(probe) != 0) || 26381772Sjl139090 26391772Sjl139090 (opl_probe_io(probe) != 0)) { 26401772Sjl139090 26411772Sjl139090 /* 26421772Sjl139090 * Probe failed. Perform cleanup. 26431772Sjl139090 */ 26441772Sjl139090 (void) opl_unprobe_sb(board); 26451772Sjl139090 ret = -1; 26461772Sjl139090 } 26471772Sjl139090 26481772Sjl139090 kmem_free(probe, sizeof (opl_probe_t)); 26491772Sjl139090 26501772Sjl139090 return (ret); 26511772Sjl139090 } 26521772Sjl139090 26531772Sjl139090 /* 26541772Sjl139090 * This unprobing also includes CMU-CH. 26551772Sjl139090 */ 26561772Sjl139090 /*ARGSUSED*/ 26571772Sjl139090 static int 26581772Sjl139090 opl_unprobe_io(int board) 26591772Sjl139090 { 26601772Sjl139090 int i, j, ret; 26611772Sjl139090 opl_board_cfg_t *board_cfg; 26621772Sjl139090 dev_info_t **node; 26631772Sjl139090 fco_handle_t *hand; 26641772Sjl139090 char **probe_str; 26651772Sjl139090 26661772Sjl139090 board_cfg = &opl_boards[board]; 26671772Sjl139090 26681772Sjl139090 for (i = 0; i < HWD_PCI_CHANNELS_PER_SB; i++) { 26691772Sjl139090 26701772Sjl139090 for (j = 0; j < HWD_LEAVES_PER_PCI_CHANNEL; j++) { 26711772Sjl139090 26721772Sjl139090 node = &board_cfg->cfg_pcich_leaf[i][j]; 26731772Sjl139090 hand = &board_cfg->cfg_pcich_handle[i][j]; 26741772Sjl139090 probe_str = &board_cfg->cfg_pcich_probe_str[i][j]; 26751772Sjl139090 26761772Sjl139090 if (*node == NULL) 26771772Sjl139090 continue; 26781772Sjl139090 26791772Sjl139090 if (*hand != NULL) { 26801772Sjl139090 opl_fc_ops_free_handle(*hand); 26811772Sjl139090 *hand = NULL; 26821772Sjl139090 } 26831772Sjl139090 26841772Sjl139090 if (*probe_str != NULL) { 26851772Sjl139090 kmem_free(*probe_str, PROBE_STR_SIZE); 26861772Sjl139090 *probe_str = NULL; 26871772Sjl139090 } 26881772Sjl139090 26891772Sjl139090 ret = opl_destroy_node(*node); 26901772Sjl139090 if (ret != 0) { 26911772Sjl139090 26921772Sjl139090 cmn_err(CE_WARN, 26931772Sjl139090 "IKP: destroy pci (%d-%d-%d) failed", 26941772Sjl139090 board, i, j); 26951772Sjl139090 return (-1); 26961772Sjl139090 } 26971772Sjl139090 26981772Sjl139090 *node = NULL; 26991772Sjl139090 27001772Sjl139090 } 27011772Sjl139090 } 27021772Sjl139090 27031772Sjl139090 node = &board_cfg->cfg_cmuch_leaf; 27041772Sjl139090 hand = &board_cfg->cfg_cmuch_handle; 27051772Sjl139090 probe_str = &board_cfg->cfg_cmuch_probe_str; 27061772Sjl139090 27071772Sjl139090 if (*node == NULL) 27081772Sjl139090 return (0); 27091772Sjl139090 27101772Sjl139090 if (*hand != NULL) { 27111772Sjl139090 opl_fc_ops_free_handle(*hand); 27121772Sjl139090 *hand = NULL; 27131772Sjl139090 } 27141772Sjl139090 27151772Sjl139090 if (*probe_str != NULL) { 27161772Sjl139090 kmem_free(*probe_str, PROBE_STR_SIZE); 27171772Sjl139090 *probe_str = NULL; 27181772Sjl139090 } 27191772Sjl139090 27201772Sjl139090 if (opl_destroy_node(*node) != 0) { 27211772Sjl139090 27221772Sjl139090 cmn_err(CE_WARN, "IKP: destroy pci (%d-%d-%d) failed", 27231772Sjl139090 board, OPL_CMU_CHANNEL, 0); 27241772Sjl139090 return (-1); 27251772Sjl139090 } 27261772Sjl139090 27271772Sjl139090 *node = NULL; 27281772Sjl139090 27291772Sjl139090 return (0); 27301772Sjl139090 } 27311772Sjl139090 27321772Sjl139090 /* 27331772Sjl139090 * Destroy the "pseudo-mc" node for a board. 27341772Sjl139090 */ 27351772Sjl139090 static int 27361772Sjl139090 opl_unprobe_memory(int board) 27371772Sjl139090 { 27381772Sjl139090 opl_board_cfg_t *board_cfg; 27391772Sjl139090 27401772Sjl139090 board_cfg = &opl_boards[board]; 27411772Sjl139090 27421772Sjl139090 if (board_cfg->cfg_pseudo_mc == NULL) 27431772Sjl139090 return (0); 27441772Sjl139090 27451772Sjl139090 if (opl_destroy_node(board_cfg->cfg_pseudo_mc) != 0) { 27461772Sjl139090 27471772Sjl139090 cmn_err(CE_WARN, "IKP: destroy pseudo-mc (%d) failed", board); 27481772Sjl139090 return (-1); 27491772Sjl139090 } 27501772Sjl139090 27511772Sjl139090 board_cfg->cfg_pseudo_mc = NULL; 27521772Sjl139090 27531772Sjl139090 return (0); 27541772Sjl139090 } 27551772Sjl139090 27561772Sjl139090 /* 27571772Sjl139090 * Destroy the "cmp" nodes for a board. This also destroys the "core" 27581772Sjl139090 * and "cpu" nodes below the "cmp" nodes. 27591772Sjl139090 */ 27601772Sjl139090 static int 27611772Sjl139090 opl_unprobe_processors(int board) 27621772Sjl139090 { 27631772Sjl139090 int i; 27641772Sjl139090 dev_info_t **cfg_cpu_chips; 27651772Sjl139090 27661772Sjl139090 cfg_cpu_chips = opl_boards[board].cfg_cpu_chips; 27671772Sjl139090 27681772Sjl139090 for (i = 0; i < HWD_CPU_CHIPS_PER_CMU; i++) { 27691772Sjl139090 27701772Sjl139090 if (cfg_cpu_chips[i] == NULL) 27711772Sjl139090 continue; 27721772Sjl139090 27731772Sjl139090 if (opl_destroy_node(cfg_cpu_chips[i]) != 0) { 27741772Sjl139090 27751772Sjl139090 cmn_err(CE_WARN, 27761772Sjl139090 "IKP: destroy chip (%d-%d) failed", board, i); 27771772Sjl139090 return (-1); 27781772Sjl139090 } 27791772Sjl139090 27801772Sjl139090 cfg_cpu_chips[i] = NULL; 27811772Sjl139090 } 27821772Sjl139090 27831772Sjl139090 return (0); 27841772Sjl139090 } 27851772Sjl139090 27861772Sjl139090 /* 27871772Sjl139090 * Perform the unprobe in the following order: 27881772Sjl139090 * 27891772Sjl139090 * IO 27901772Sjl139090 * memory 27911772Sjl139090 * processors 27921772Sjl139090 */ 27931772Sjl139090 int 27941772Sjl139090 opl_unprobe_sb(int board) 27951772Sjl139090 { 27961772Sjl139090 if ((board < 0) || (board >= HWD_SBS_PER_DOMAIN)) 27971772Sjl139090 return (-1); 27981772Sjl139090 27991772Sjl139090 ASSERT(opl_cfg_inited != 0); 28001772Sjl139090 28011772Sjl139090 if ((opl_unprobe_io(board) != 0) || 28021772Sjl139090 28031772Sjl139090 (opl_unprobe_memory(board) != 0) || 28041772Sjl139090 28051772Sjl139090 (opl_unprobe_processors(board) != 0)) 28061772Sjl139090 28071772Sjl139090 return (-1); 28081772Sjl139090 28091772Sjl139090 if (opl_boards[board].cfg_hwd != NULL) { 28101772Sjl139090 #ifdef UCTEST 28111772Sjl139090 size_t size = 0xA000; 28121772Sjl139090 #endif 28131772Sjl139090 /* Release the memory for the HWD */ 28141772Sjl139090 void *hwdp = opl_boards[board].cfg_hwd; 28151772Sjl139090 opl_boards[board].cfg_hwd = NULL; 28161772Sjl139090 #ifdef UCTEST 28171772Sjl139090 hwdp = (void *)((char *)hwdp - 0x1000); 28181772Sjl139090 hat_unload(kas.a_hat, hwdp, size, HAT_UNLOAD_UNLOCK); 28191772Sjl139090 vmem_free(heap_arena, hwdp, size); 28201772Sjl139090 #else 28211772Sjl139090 kmem_free(hwdp, HWD_DATA_SIZE); 28221772Sjl139090 #endif 28231772Sjl139090 } 28241772Sjl139090 return (0); 28251772Sjl139090 } 28261772Sjl139090 28271772Sjl139090 /* 28281772Sjl139090 * For MAC patrol support, we need to update the PA-related properties 28291772Sjl139090 * when there is a copy-rename event. This should be called after the 28301772Sjl139090 * physical copy and rename has been done by DR, and before the MAC 28311772Sjl139090 * patrol is restarted. 28321772Sjl139090 */ 28331772Sjl139090 int 28341772Sjl139090 oplcfg_pa_swap(int from, int to) 28351772Sjl139090 { 28361772Sjl139090 dev_info_t *from_node = opl_boards[from].cfg_pseudo_mc; 28371772Sjl139090 dev_info_t *to_node = opl_boards[to].cfg_pseudo_mc; 28381772Sjl139090 opl_range_t *rangef, *ranget; 28391772Sjl139090 int elems; 28401772Sjl139090 int ret; 28411772Sjl139090 28421772Sjl139090 if ((OPL_GET_PROP_ARRAY(int, from_node, "sb-mem-ranges", rangef, 28431772Sjl139090 elems) != DDI_SUCCESS) || (elems != 4)) { 28441772Sjl139090 /* XXX -- bad news */ 28451772Sjl139090 return (-1); 28461772Sjl139090 } 28471772Sjl139090 if ((OPL_GET_PROP_ARRAY(int, to_node, "sb-mem-ranges", ranget, 28481772Sjl139090 elems) != DDI_SUCCESS) || (elems != 4)) { 28491772Sjl139090 /* XXX -- bad news */ 28501772Sjl139090 return (-1); 28511772Sjl139090 } 28521772Sjl139090 OPL_UPDATE_PROP_ARRAY(int, from_node, "sb-mem-ranges", (int *)ranget, 28531772Sjl139090 4); 28541772Sjl139090 OPL_UPDATE_PROP_ARRAY(int, to_node, "sb-mem-ranges", (int *)rangef, 28551772Sjl139090 4); 28561772Sjl139090 28571772Sjl139090 OPL_FREE_PROP(ranget); 28581772Sjl139090 OPL_FREE_PROP(rangef); 28591772Sjl139090 28601772Sjl139090 return (0); 28611772Sjl139090 } 2862