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 /* 223354Sjl139090 * Copyright 2007 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 *); 821982Smv143129 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 871982Smv143129 static int master_interrupt_init(uint32_t, uint32_t); 881982Smv143129 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}, 1111982Smv143129 { "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 1281982Smv143129 static int master_interrupt_inited = 0; 1291982Smv143129 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 { 7243354Sjl139090 if (e_ddi_branch_destroy(node, NULL, 0) != 0) { 7253354Sjl139090 char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 7263354Sjl139090 (void) ddi_pathname(node, path); 7273354Sjl139090 cmn_err(CE_WARN, "OPL node removal failed: %s (%p)", 7283354Sjl139090 path, (void *)node); 7293354Sjl139090 kmem_free(path, MAXPATHLEN); 7301772Sjl139090 return (-1); 7313354Sjl139090 } 7321772Sjl139090 7331772Sjl139090 return (0); 7341772Sjl139090 } 7351772Sjl139090 7361772Sjl139090 /* 7371772Sjl139090 * Set the properties for a "cpu" node. 7381772Sjl139090 */ 7391772Sjl139090 /*ARGSUSED*/ 7401772Sjl139090 static int 7411772Sjl139090 opl_create_cpu(dev_info_t *node, void *arg, uint_t flags) 7421772Sjl139090 { 7431772Sjl139090 opl_probe_t *probe; 7441772Sjl139090 hwd_cpu_chip_t *chip; 7451772Sjl139090 hwd_core_t *core; 7461772Sjl139090 hwd_cpu_t *cpu; 7471772Sjl139090 int ret; 7481772Sjl139090 7491772Sjl139090 probe = arg; 7501772Sjl139090 chip = &probe->pr_sb->sb_cmu.cmu_cpu_chips[probe->pr_cpu_chip]; 7511772Sjl139090 core = &chip->chip_cores[probe->pr_core]; 7521772Sjl139090 cpu = &core->core_cpus[probe->pr_cpu]; 7531772Sjl139090 OPL_UPDATE_PROP(string, node, "name", OPL_CPU_NODE); 7541772Sjl139090 OPL_UPDATE_PROP(string, node, "device_type", OPL_CPU_NODE); 7551772Sjl139090 7561772Sjl139090 OPL_UPDATE_PROP(int, node, "cpuid", cpu->cpu_cpuid); 7571772Sjl139090 OPL_UPDATE_PROP(int, node, "reg", probe->pr_cpu); 7581772Sjl139090 7591772Sjl139090 OPL_UPDATE_PROP(string, node, "status", "okay"); 7601772Sjl139090 7611772Sjl139090 return (DDI_WALK_TERMINATE); 7621772Sjl139090 } 7631772Sjl139090 7641772Sjl139090 /* 7651772Sjl139090 * Create "cpu" nodes as child nodes of a given "core" node. 7661772Sjl139090 */ 7671772Sjl139090 static int 7681772Sjl139090 opl_probe_cpus(opl_probe_t *probe) 7691772Sjl139090 { 7701772Sjl139090 int i; 7711772Sjl139090 hwd_cpu_chip_t *chip; 7721772Sjl139090 hwd_core_t *core; 7731772Sjl139090 hwd_cpu_t *cpus; 7741772Sjl139090 7751772Sjl139090 chip = &probe->pr_sb->sb_cmu.cmu_cpu_chips[probe->pr_cpu_chip]; 7761772Sjl139090 core = &chip->chip_cores[probe->pr_core]; 7771772Sjl139090 cpus = &core->core_cpus[0]; 7781772Sjl139090 7791772Sjl139090 for (i = 0; i < HWD_CPUS_PER_CORE; i++) { 7801772Sjl139090 7811772Sjl139090 /* 7821772Sjl139090 * Olympus-C has 2 cpus per core. 7831772Sjl139090 * Jupiter has 4 cpus per core. 7841772Sjl139090 * For the Olympus-C based platform, we expect the cpu_status 7851772Sjl139090 * of the non-existent cpus to be set to missing. 7861772Sjl139090 */ 7871772Sjl139090 if (!HWD_STATUS_OK(cpus[i].cpu_status)) 7881772Sjl139090 continue; 7891772Sjl139090 7901772Sjl139090 probe->pr_create = opl_create_cpu; 7911772Sjl139090 probe->pr_cpu = i; 7921772Sjl139090 if (opl_create_node(probe) == NULL) { 7931772Sjl139090 7941772Sjl139090 cmn_err(CE_WARN, "IKP: create cpu (%d-%d-%d-%d) failed", 7951772Sjl139090 probe->pr_board, probe->pr_cpu_chip, 7961772Sjl139090 probe->pr_core, probe->pr_cpu); 7971772Sjl139090 return (-1); 7981772Sjl139090 } 7991772Sjl139090 } 8001772Sjl139090 8011772Sjl139090 return (0); 8021772Sjl139090 } 8031772Sjl139090 8041772Sjl139090 /* 8051772Sjl139090 * Set the properties for a "core" node. 8061772Sjl139090 */ 8071772Sjl139090 /*ARGSUSED*/ 8081772Sjl139090 static int 8091772Sjl139090 opl_create_core(dev_info_t *node, void *arg, uint_t flags) 8101772Sjl139090 { 8111772Sjl139090 opl_probe_t *probe; 8121772Sjl139090 hwd_cpu_chip_t *chip; 8131772Sjl139090 hwd_core_t *core; 8141772Sjl139090 int sharing[2]; 8151772Sjl139090 int ret; 8161772Sjl139090 8171772Sjl139090 probe = arg; 8181772Sjl139090 chip = &probe->pr_sb->sb_cmu.cmu_cpu_chips[probe->pr_cpu_chip]; 8191772Sjl139090 core = &chip->chip_cores[probe->pr_core]; 8201772Sjl139090 8211772Sjl139090 OPL_UPDATE_PROP(string, node, "name", OPL_CORE_NODE); 8221772Sjl139090 OPL_UPDATE_PROP(string, node, "device_type", OPL_CORE_NODE); 8231772Sjl139090 OPL_UPDATE_PROP(string, node, "compatible", chip->chip_compatible); 8241772Sjl139090 8251772Sjl139090 OPL_UPDATE_PROP(int, node, "reg", probe->pr_core); 8261772Sjl139090 OPL_UPDATE_PROP(int, node, "manufacturer#", core->core_manufacturer); 8271772Sjl139090 OPL_UPDATE_PROP(int, node, "implementation#", 8281772Sjl139090 core->core_implementation); 8291772Sjl139090 OPL_UPDATE_PROP(int, node, "mask#", core->core_mask); 8301772Sjl139090 8313659Sjimand OPL_UPDATE_PROP(int, node, "sparc-version", 9); 8321772Sjl139090 OPL_UPDATE_PROP(int, node, "clock-frequency", core->core_frequency); 8331772Sjl139090 8341772Sjl139090 OPL_UPDATE_PROP(int, node, "l1-icache-size", core->core_l1_icache_size); 8351772Sjl139090 OPL_UPDATE_PROP(int, node, "l1-icache-line-size", 8361772Sjl139090 core->core_l1_icache_line_size); 8371772Sjl139090 OPL_UPDATE_PROP(int, node, "l1-icache-associativity", 8381772Sjl139090 core->core_l1_icache_associativity); 8391772Sjl139090 OPL_UPDATE_PROP(int, node, "#itlb-entries", 8401772Sjl139090 core->core_num_itlb_entries); 8411772Sjl139090 8421772Sjl139090 OPL_UPDATE_PROP(int, node, "l1-dcache-size", core->core_l1_dcache_size); 8431772Sjl139090 OPL_UPDATE_PROP(int, node, "l1-dcache-line-size", 8441772Sjl139090 core->core_l1_dcache_line_size); 8451772Sjl139090 OPL_UPDATE_PROP(int, node, "l1-dcache-associativity", 8461772Sjl139090 core->core_l1_dcache_associativity); 8471772Sjl139090 OPL_UPDATE_PROP(int, node, "#dtlb-entries", 8481772Sjl139090 core->core_num_dtlb_entries); 8491772Sjl139090 8501772Sjl139090 OPL_UPDATE_PROP(int, node, "l2-cache-size", core->core_l2_cache_size); 8511772Sjl139090 OPL_UPDATE_PROP(int, node, "l2-cache-line-size", 8521772Sjl139090 core->core_l2_cache_line_size); 8531772Sjl139090 OPL_UPDATE_PROP(int, node, "l2-cache-associativity", 8541772Sjl139090 core->core_l2_cache_associativity); 8551772Sjl139090 sharing[0] = 0; 8561772Sjl139090 sharing[1] = core->core_l2_cache_sharing; 8571772Sjl139090 OPL_UPDATE_PROP_ARRAY(int, node, "l2-cache-sharing", sharing, 2); 8581772Sjl139090 8591772Sjl139090 OPL_UPDATE_PROP(string, node, "status", "okay"); 8601772Sjl139090 8611772Sjl139090 return (DDI_WALK_TERMINATE); 8621772Sjl139090 } 8631772Sjl139090 8641772Sjl139090 /* 8651772Sjl139090 * Create "core" nodes as child nodes of a given "cmp" node. 8661772Sjl139090 * 8671772Sjl139090 * Create the branch below each "core" node". 8681772Sjl139090 */ 8691772Sjl139090 static int 8701772Sjl139090 opl_probe_cores(opl_probe_t *probe) 8711772Sjl139090 { 8721772Sjl139090 int i; 8731772Sjl139090 hwd_cpu_chip_t *chip; 8741772Sjl139090 hwd_core_t *cores; 8751772Sjl139090 dev_info_t *parent, *node; 8761772Sjl139090 8771772Sjl139090 chip = &probe->pr_sb->sb_cmu.cmu_cpu_chips[probe->pr_cpu_chip]; 8781772Sjl139090 cores = &chip->chip_cores[0]; 8791772Sjl139090 parent = probe->pr_parent; 8801772Sjl139090 8811772Sjl139090 for (i = 0; i < HWD_CORES_PER_CPU_CHIP; i++) { 8821772Sjl139090 8831772Sjl139090 if (!HWD_STATUS_OK(cores[i].core_status)) 8841772Sjl139090 continue; 8851772Sjl139090 8861772Sjl139090 probe->pr_parent = parent; 8871772Sjl139090 probe->pr_create = opl_create_core; 8881772Sjl139090 probe->pr_core = i; 8891772Sjl139090 node = opl_create_node(probe); 8901772Sjl139090 if (node == NULL) { 8911772Sjl139090 8921772Sjl139090 cmn_err(CE_WARN, "IKP: create core (%d-%d-%d) failed", 8931772Sjl139090 probe->pr_board, probe->pr_cpu_chip, 8941772Sjl139090 probe->pr_core); 8951772Sjl139090 return (-1); 8961772Sjl139090 } 8971772Sjl139090 8981772Sjl139090 /* 8991772Sjl139090 * Create "cpu" nodes below "core". 9001772Sjl139090 */ 9011772Sjl139090 probe->pr_parent = node; 9021772Sjl139090 if (opl_probe_cpus(probe) != 0) 9031772Sjl139090 return (-1); 9041772Sjl139090 } 9051772Sjl139090 9061772Sjl139090 return (0); 9071772Sjl139090 } 9081772Sjl139090 9091772Sjl139090 /* 9101772Sjl139090 * Set the properties for a "cmp" node. 9111772Sjl139090 */ 9121772Sjl139090 /*ARGSUSED*/ 9131772Sjl139090 static int 9141772Sjl139090 opl_create_cpu_chip(dev_info_t *node, void *arg, uint_t flags) 9151772Sjl139090 { 9161772Sjl139090 opl_probe_t *probe; 9171772Sjl139090 hwd_cpu_chip_t *chip; 9181772Sjl139090 opl_range_t range; 9191772Sjl139090 uint64_t dummy_addr; 9201772Sjl139090 int ret; 9211772Sjl139090 9221772Sjl139090 probe = arg; 9231772Sjl139090 chip = &probe->pr_sb->sb_cmu.cmu_cpu_chips[probe->pr_cpu_chip]; 9241772Sjl139090 9251772Sjl139090 OPL_UPDATE_PROP(string, node, "name", OPL_CPU_CHIP_NODE); 9261772Sjl139090 9271772Sjl139090 OPL_UPDATE_PROP(int, node, "portid", chip->chip_portid); 9281772Sjl139090 OPL_UPDATE_PROP(int, node, "board#", probe->pr_board); 9291772Sjl139090 9301772Sjl139090 dummy_addr = OPL_PROC_AS(probe->pr_board, probe->pr_cpu_chip); 9311772Sjl139090 range.rg_addr_hi = OPL_HI(dummy_addr); 9321772Sjl139090 range.rg_addr_lo = OPL_LO(dummy_addr); 9331772Sjl139090 range.rg_size_hi = 0; 9341772Sjl139090 range.rg_size_lo = 0; 9351772Sjl139090 OPL_UPDATE_PROP_ARRAY(int, node, "reg", (int *)&range, 4); 9361772Sjl139090 9371772Sjl139090 OPL_UPDATE_PROP(int, node, "#address-cells", 1); 9381772Sjl139090 OPL_UPDATE_PROP(int, node, "#size-cells", 0); 9391772Sjl139090 9401772Sjl139090 OPL_UPDATE_PROP(string, node, "status", "okay"); 9411772Sjl139090 9421772Sjl139090 return (DDI_WALK_TERMINATE); 9431772Sjl139090 } 9441772Sjl139090 9451772Sjl139090 /* 9461772Sjl139090 * Create "cmp" nodes as child nodes of the root node. 9471772Sjl139090 * 9481772Sjl139090 * Create the branch below each "cmp" node. 9491772Sjl139090 */ 9501772Sjl139090 static int 9511772Sjl139090 opl_probe_cpu_chips(opl_probe_t *probe) 9521772Sjl139090 { 9531772Sjl139090 int i; 9541772Sjl139090 dev_info_t **cfg_cpu_chips; 9551772Sjl139090 hwd_cpu_chip_t *chips; 9561772Sjl139090 dev_info_t *node; 9571772Sjl139090 9581772Sjl139090 cfg_cpu_chips = opl_boards[probe->pr_board].cfg_cpu_chips; 9591772Sjl139090 chips = &probe->pr_sb->sb_cmu.cmu_cpu_chips[0]; 9601772Sjl139090 9611772Sjl139090 for (i = 0; i < HWD_CPU_CHIPS_PER_CMU; i++) { 9621772Sjl139090 9631772Sjl139090 ASSERT(cfg_cpu_chips[i] == NULL); 9641772Sjl139090 9651772Sjl139090 if (!HWD_STATUS_OK(chips[i].chip_status)) 9661772Sjl139090 continue; 9671772Sjl139090 9681772Sjl139090 probe->pr_parent = ddi_root_node(); 9691772Sjl139090 probe->pr_create = opl_create_cpu_chip; 9701772Sjl139090 probe->pr_cpu_chip = i; 9711772Sjl139090 probe->pr_hold = 1; 9721772Sjl139090 node = opl_create_node(probe); 9731772Sjl139090 if (node == NULL) { 9741772Sjl139090 9751772Sjl139090 cmn_err(CE_WARN, "IKP: create chip (%d-%d) failed", 9761772Sjl139090 probe->pr_board, probe->pr_cpu_chip); 9771772Sjl139090 return (-1); 9781772Sjl139090 } 9791772Sjl139090 9801772Sjl139090 cfg_cpu_chips[i] = node; 9811772Sjl139090 9821772Sjl139090 /* 9831772Sjl139090 * Create "core" nodes below "cmp". 9841772Sjl139090 * We hold the "cmp" node. So, there is no need to hold 9851772Sjl139090 * the "core" and "cpu" nodes below it. 9861772Sjl139090 */ 9871772Sjl139090 probe->pr_parent = node; 9881772Sjl139090 probe->pr_hold = 0; 9891772Sjl139090 if (opl_probe_cores(probe) != 0) 9901772Sjl139090 return (-1); 9911772Sjl139090 } 9921772Sjl139090 9931772Sjl139090 return (0); 9941772Sjl139090 } 9951772Sjl139090 9961772Sjl139090 /* 9971772Sjl139090 * Set the properties for a "pseudo-mc" node. 9981772Sjl139090 */ 9991772Sjl139090 /*ARGSUSED*/ 10001772Sjl139090 static int 10011772Sjl139090 opl_create_pseudo_mc(dev_info_t *node, void *arg, uint_t flags) 10021772Sjl139090 { 10031772Sjl139090 opl_probe_t *probe; 10041772Sjl139090 int board, portid; 10051772Sjl139090 hwd_bank_t *bank; 10061772Sjl139090 hwd_memory_t *mem; 10071772Sjl139090 opl_range_t range; 10081772Sjl139090 opl_mc_addr_t mc[HWD_BANKS_PER_CMU]; 10091772Sjl139090 int status[2][7]; 10101772Sjl139090 int i, j; 10111772Sjl139090 int ret; 10121772Sjl139090 10131772Sjl139090 probe = arg; 10141772Sjl139090 board = probe->pr_board; 10151772Sjl139090 10161772Sjl139090 OPL_UPDATE_PROP(string, node, "name", OPL_PSEUDO_MC_NODE); 10171772Sjl139090 OPL_UPDATE_PROP(string, node, "device_type", "memory-controller"); 10181772Sjl139090 OPL_UPDATE_PROP(string, node, "compatible", "FJSV,oplmc"); 10191772Sjl139090 10201772Sjl139090 portid = OPL_LSB_TO_PSEUDOMC_PORTID(board); 10211772Sjl139090 OPL_UPDATE_PROP(int, node, "portid", portid); 10221772Sjl139090 10231772Sjl139090 range.rg_addr_hi = OPL_HI(OPL_MC_AS(board)); 10241772Sjl139090 range.rg_addr_lo = 0x200; 10251772Sjl139090 range.rg_size_hi = 0; 10261772Sjl139090 range.rg_size_lo = 0; 10271772Sjl139090 OPL_UPDATE_PROP_ARRAY(int, node, "reg", (int *)&range, 4); 10281772Sjl139090 10291772Sjl139090 OPL_UPDATE_PROP(int, node, "board#", board); 10301772Sjl139090 OPL_UPDATE_PROP(int, node, "physical-board#", 10311772Sjl139090 probe->pr_sb->sb_psb_number); 10321772Sjl139090 10331772Sjl139090 OPL_UPDATE_PROP(int, node, "#address-cells", 1); 10341772Sjl139090 OPL_UPDATE_PROP(int, node, "#size-cells", 2); 10351772Sjl139090 10361772Sjl139090 mem = &probe->pr_sb->sb_cmu.cmu_memory; 10371772Sjl139090 10381772Sjl139090 range.rg_addr_hi = OPL_HI(mem->mem_start_address); 10391772Sjl139090 range.rg_addr_lo = OPL_LO(mem->mem_start_address); 10401772Sjl139090 range.rg_size_hi = OPL_HI(mem->mem_size); 10411772Sjl139090 range.rg_size_lo = OPL_LO(mem->mem_size); 10421772Sjl139090 OPL_UPDATE_PROP_ARRAY(int, node, "sb-mem-ranges", (int *)&range, 4); 10431772Sjl139090 10441772Sjl139090 bank = probe->pr_sb->sb_cmu.cmu_memory.mem_banks; 10451772Sjl139090 for (i = 0, j = 0; i < HWD_BANKS_PER_CMU; i++) { 10461772Sjl139090 10471772Sjl139090 if (!HWD_STATUS_OK(bank[i].bank_status)) 10481772Sjl139090 continue; 10491772Sjl139090 10501772Sjl139090 mc[j].mc_bank = i; 10511772Sjl139090 mc[j].mc_hi = OPL_HI(bank[i].bank_register_address); 10521772Sjl139090 mc[j].mc_lo = OPL_LO(bank[i].bank_register_address); 10531772Sjl139090 j++; 10541772Sjl139090 } 10553354Sjl139090 10563354Sjl139090 if (j > 0) { 10573354Sjl139090 OPL_UPDATE_PROP_ARRAY(int, node, "mc-addr", (int *)mc, j*3); 10583354Sjl139090 } else { 10593354Sjl139090 /* 10603354Sjl139090 * If there is no memory, we need the mc-addr property, but 10613354Sjl139090 * it is length 0. The only way to do this using ndi seems 10623354Sjl139090 * to be by creating a boolean property. 10633354Sjl139090 */ 10643354Sjl139090 ret = ndi_prop_create_boolean(DDI_DEV_T_NONE, node, "mc-addr"); 10653354Sjl139090 OPL_UPDATE_PROP_ERR(ret, "mc-addr"); 10663354Sjl139090 } 10671772Sjl139090 10681772Sjl139090 OPL_UPDATE_PROP_ARRAY(byte, node, "cs0-mc-pa-trans-table", 10691772Sjl139090 mem->mem_cs[0].cs_pa_mac_table, 64); 10701772Sjl139090 OPL_UPDATE_PROP_ARRAY(byte, node, "cs1-mc-pa-trans-table", 10711772Sjl139090 mem->mem_cs[1].cs_pa_mac_table, 64); 10721772Sjl139090 10731772Sjl139090 #define CS_PER_MEM 2 10741772Sjl139090 10751772Sjl139090 for (i = 0, j = 0; i < CS_PER_MEM; i++) { 10761772Sjl139090 if (HWD_STATUS_OK(mem->mem_cs[i].cs_status) || 10771772Sjl139090 HWD_STATUS_FAILED(mem->mem_cs[i].cs_status)) { 10781772Sjl139090 status[j][0] = i; 10791772Sjl139090 if (HWD_STATUS_OK(mem->mem_cs[i].cs_status)) 10801772Sjl139090 status[j][1] = 0; 10811772Sjl139090 else 10821772Sjl139090 status[j][1] = 1; 10831772Sjl139090 status[j][2] = 10841772Sjl139090 OPL_HI(mem->mem_cs[i].cs_available_capacity); 10851772Sjl139090 status[j][3] = 10861772Sjl139090 OPL_LO(mem->mem_cs[i].cs_available_capacity); 10871772Sjl139090 status[j][4] = OPL_HI(mem->mem_cs[i].cs_dimm_capacity); 10881772Sjl139090 status[j][5] = OPL_LO(mem->mem_cs[i].cs_dimm_capacity); 10891772Sjl139090 status[j][6] = mem->mem_cs[i].cs_number_of_dimms; 10901772Sjl139090 j++; 10911772Sjl139090 } 10921772Sjl139090 } 10933354Sjl139090 10943354Sjl139090 if (j > 0) { 10953354Sjl139090 OPL_UPDATE_PROP_ARRAY(int, node, "cs-status", (int *)status, 10963354Sjl139090 j*7); 10973354Sjl139090 } else { 10983354Sjl139090 /* 10993354Sjl139090 * If there is no memory, we need the cs-status property, but 11003354Sjl139090 * it is length 0. The only way to do this using ndi seems 11013354Sjl139090 * to be by creating a boolean property. 11023354Sjl139090 */ 11033354Sjl139090 ret = ndi_prop_create_boolean(DDI_DEV_T_NONE, node, 11043354Sjl139090 "cs-status"); 11053354Sjl139090 OPL_UPDATE_PROP_ERR(ret, "cs-status"); 11063354Sjl139090 } 11071772Sjl139090 11081772Sjl139090 return (DDI_WALK_TERMINATE); 11091772Sjl139090 } 11101772Sjl139090 11111772Sjl139090 /* 11121772Sjl139090 * Create "pseudo-mc" nodes 11131772Sjl139090 */ 11141772Sjl139090 static int 11151772Sjl139090 opl_probe_memory(opl_probe_t *probe) 11161772Sjl139090 { 11171772Sjl139090 int board; 11181772Sjl139090 opl_board_cfg_t *board_cfg; 11191772Sjl139090 dev_info_t *node; 11201772Sjl139090 11211772Sjl139090 board = probe->pr_board; 11221772Sjl139090 board_cfg = &opl_boards[board]; 11231772Sjl139090 11241772Sjl139090 ASSERT(board_cfg->cfg_pseudo_mc == NULL); 11251772Sjl139090 11261772Sjl139090 probe->pr_parent = ddi_root_node(); 11271772Sjl139090 probe->pr_create = opl_create_pseudo_mc; 11281772Sjl139090 probe->pr_hold = 1; 11291772Sjl139090 node = opl_create_node(probe); 11301772Sjl139090 if (node == NULL) { 11311772Sjl139090 11321772Sjl139090 cmn_err(CE_WARN, "IKP: create pseudo-mc (%d) failed", board); 11331772Sjl139090 return (-1); 11341772Sjl139090 } 11351772Sjl139090 11361772Sjl139090 board_cfg->cfg_pseudo_mc = node; 11371772Sjl139090 11381772Sjl139090 return (0); 11391772Sjl139090 } 11401772Sjl139090 11411772Sjl139090 /* 11421772Sjl139090 * Allocate the fcode ops handle. 11431772Sjl139090 */ 11441772Sjl139090 /*ARGSUSED*/ 11451772Sjl139090 static 11461772Sjl139090 fco_handle_t 11471772Sjl139090 opl_fc_ops_alloc_handle(dev_info_t *parent, dev_info_t *child, 11481772Sjl139090 void *fcode, size_t fcode_size, char *unit_address, 11491772Sjl139090 char *my_args) 11501772Sjl139090 { 11511772Sjl139090 fco_handle_t rp; 11521772Sjl139090 phandle_t h; 11531772Sjl139090 char *buf; 11541772Sjl139090 11551772Sjl139090 rp = kmem_zalloc(sizeof (struct fc_resource_list), KM_SLEEP); 11561772Sjl139090 rp->next_handle = fc_ops_alloc_handle(parent, child, fcode, fcode_size, 11571772Sjl139090 unit_address, NULL); 11581772Sjl139090 rp->ap = parent; 11591772Sjl139090 rp->child = child; 11601772Sjl139090 rp->fcode = fcode; 11611772Sjl139090 rp->fcode_size = fcode_size; 11621772Sjl139090 rp->my_args = my_args; 11631772Sjl139090 11641772Sjl139090 if (unit_address) { 11651772Sjl139090 buf = kmem_zalloc(UNIT_ADDR_SIZE, KM_SLEEP); 11661772Sjl139090 (void) strcpy(buf, unit_address); 11671772Sjl139090 rp->unit_address = buf; 11681772Sjl139090 } 11691772Sjl139090 11701772Sjl139090 /* 11711772Sjl139090 * Add the child's nodeid to our table... 11721772Sjl139090 */ 11731772Sjl139090 h = ddi_get_nodeid(rp->child); 11741772Sjl139090 fc_add_dip_to_phandle(fc_handle_to_phandle_head(rp), rp->child, h); 11751772Sjl139090 11761772Sjl139090 return (rp); 11771772Sjl139090 } 11781772Sjl139090 11791772Sjl139090 11801772Sjl139090 static void 11811772Sjl139090 opl_fc_ops_free_handle(fco_handle_t rp) 11821772Sjl139090 { 11831772Sjl139090 struct fc_resource *resp, *nresp; 11841772Sjl139090 11851772Sjl139090 ASSERT(rp); 11861772Sjl139090 11871772Sjl139090 if (rp->next_handle) 11881772Sjl139090 fc_ops_free_handle(rp->next_handle); 11891772Sjl139090 if (rp->unit_address) 11901772Sjl139090 kmem_free(rp->unit_address, UNIT_ADDR_SIZE); 11911772Sjl139090 11921772Sjl139090 /* 11931772Sjl139090 * Release all the resources from the resource list 11941772Sjl139090 */ 11951772Sjl139090 for (resp = rp->head; resp != NULL; resp = nresp) { 11961772Sjl139090 nresp = resp->next; 11971772Sjl139090 switch (resp->type) { 11981772Sjl139090 11991772Sjl139090 case RT_MAP: 12003354Sjl139090 /* 12013354Sjl139090 * If this is still mapped, we'd better unmap it now, 12023354Sjl139090 * or all our structures that are tracking it will 12033354Sjl139090 * be leaked. 12043354Sjl139090 */ 12053354Sjl139090 if (resp->fc_map_handle != NULL) 12063354Sjl139090 opl_unmap_phys(&resp->fc_map_handle); 12071772Sjl139090 break; 12081772Sjl139090 12091772Sjl139090 case RT_DMA: 12101772Sjl139090 /* 12111772Sjl139090 * DMA has to be freed up at exit time. 12121772Sjl139090 */ 12131772Sjl139090 cmn_err(CE_CONT, 12141772Sjl139090 "opl_fc_ops_free_handle: Unexpected DMA seen!"); 12151772Sjl139090 break; 12161772Sjl139090 12171772Sjl139090 case RT_CONTIGIOUS: 12181772Sjl139090 FC_DEBUG2(1, CE_CONT, "opl_fc_ops_free: " 12191772Sjl139090 "Free claim-memory resource 0x%lx size 0x%x\n", 12201772Sjl139090 resp->fc_contig_virt, resp->fc_contig_len); 12211772Sjl139090 12221772Sjl139090 (void) ndi_ra_free(ddi_root_node(), 12231772Sjl139090 (uint64_t)resp->fc_contig_virt, 12241772Sjl139090 resp->fc_contig_len, "opl-fcodemem", 12251772Sjl139090 NDI_RA_PASS); 12261772Sjl139090 12271772Sjl139090 break; 12281772Sjl139090 12291772Sjl139090 default: 12301772Sjl139090 cmn_err(CE_CONT, "opl_fc_ops_free: " 12311772Sjl139090 "unknown resource type %d", resp->type); 12321772Sjl139090 break; 12331772Sjl139090 } 12341772Sjl139090 fc_rem_resource(rp, resp); 12351772Sjl139090 kmem_free(resp, sizeof (struct fc_resource)); 12361772Sjl139090 } 12371772Sjl139090 12381772Sjl139090 kmem_free(rp, sizeof (struct fc_resource_list)); 12391772Sjl139090 } 12401772Sjl139090 12411772Sjl139090 int 12421772Sjl139090 opl_fc_do_op(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 12431772Sjl139090 { 12441772Sjl139090 opl_fc_ops_t *op; 12451772Sjl139090 char *service = fc_cell2ptr(cp->svc_name); 12461772Sjl139090 12471772Sjl139090 ASSERT(rp); 12481772Sjl139090 12491772Sjl139090 FC_DEBUG1(1, CE_CONT, "opl_fc_do_op: <%s>\n", service); 12501772Sjl139090 12511772Sjl139090 /* 12521772Sjl139090 * First try the generic fc_ops. 12531772Sjl139090 */ 12541772Sjl139090 if (fc_ops(ap, rp->next_handle, cp) == 0) 12551772Sjl139090 return (0); 12561772Sjl139090 12571772Sjl139090 /* 12581772Sjl139090 * Now try the Jupiter-specific ops. 12591772Sjl139090 */ 12601772Sjl139090 for (op = opl_fc_ops; op->fc_service != NULL; ++op) 12611772Sjl139090 if (strcmp(op->fc_service, service) == 0) 12621772Sjl139090 return (op->fc_op(ap, rp, cp)); 12631772Sjl139090 12641772Sjl139090 FC_DEBUG1(9, CE_CONT, "opl_fc_do_op: <%s> not serviced\n", service); 12651772Sjl139090 12661772Sjl139090 return (-1); 12671772Sjl139090 } 12681772Sjl139090 12691772Sjl139090 /* 12701772Sjl139090 * map-in (phys.lo phys.hi size -- virt) 12711772Sjl139090 */ 12721772Sjl139090 static int 12731772Sjl139090 opl_map_in(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 12741772Sjl139090 { 12751772Sjl139090 size_t len; 12761772Sjl139090 int error; 12771772Sjl139090 caddr_t virt; 12781772Sjl139090 struct fc_resource *resp; 12791772Sjl139090 struct regspec rspec; 12801772Sjl139090 ddi_device_acc_attr_t acc; 12811772Sjl139090 ddi_acc_handle_t h; 12821772Sjl139090 12831772Sjl139090 if (fc_cell2int(cp->nargs) != 3) 12841772Sjl139090 return (fc_syntax_error(cp, "nargs must be 3")); 12851772Sjl139090 12861772Sjl139090 if (fc_cell2int(cp->nresults) < 1) 12871772Sjl139090 return (fc_syntax_error(cp, "nresults must be >= 1")); 12881772Sjl139090 12891772Sjl139090 rspec.regspec_size = len = fc_cell2size(fc_arg(cp, 0)); 12901772Sjl139090 rspec.regspec_bustype = fc_cell2uint(fc_arg(cp, 1)); 12911772Sjl139090 rspec.regspec_addr = fc_cell2uint(fc_arg(cp, 2)); 12921772Sjl139090 12931772Sjl139090 acc.devacc_attr_version = DDI_DEVICE_ATTR_V0; 12941772Sjl139090 acc.devacc_attr_endian_flags = DDI_STRUCTURE_BE_ACC; 12951772Sjl139090 acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 12961772Sjl139090 12971772Sjl139090 FC_DEBUG3(1, CE_CONT, "opl_map_in: attempting map in " 12981772Sjl139090 "address 0x%08x.%08x length %x\n", rspec.regspec_bustype, 12991772Sjl139090 rspec.regspec_addr, rspec.regspec_size); 13001772Sjl139090 13011772Sjl139090 error = opl_map_phys(rp->child, &rspec, &virt, &acc, &h); 13021772Sjl139090 13031772Sjl139090 if (error) { 13041772Sjl139090 FC_DEBUG3(1, CE_CONT, "opl_map_in: map in failed - " 13051772Sjl139090 "address 0x%08x.%08x length %x\n", rspec.regspec_bustype, 13061772Sjl139090 rspec.regspec_addr, rspec.regspec_size); 13071772Sjl139090 13081772Sjl139090 return (fc_priv_error(cp, "opl map-in failed")); 13091772Sjl139090 } 13101772Sjl139090 13111772Sjl139090 FC_DEBUG1(3, CE_CONT, "opl_map_in: returning virt %p\n", virt); 13121772Sjl139090 13131772Sjl139090 cp->nresults = fc_int2cell(1); 13141772Sjl139090 fc_result(cp, 0) = fc_ptr2cell(virt); 13151772Sjl139090 13161772Sjl139090 /* 13171772Sjl139090 * Log this resource ... 13181772Sjl139090 */ 13191772Sjl139090 resp = kmem_zalloc(sizeof (struct fc_resource), KM_SLEEP); 13201772Sjl139090 resp->type = RT_MAP; 13211772Sjl139090 resp->fc_map_virt = virt; 13221772Sjl139090 resp->fc_map_len = len; 13231772Sjl139090 resp->fc_map_handle = h; 13241772Sjl139090 fc_add_resource(rp, resp); 13251772Sjl139090 13261772Sjl139090 return (fc_success_op(ap, rp, cp)); 13271772Sjl139090 } 13281772Sjl139090 13291772Sjl139090 /* 13301772Sjl139090 * map-out (virt size -- ) 13311772Sjl139090 */ 13321772Sjl139090 static int 13331772Sjl139090 opl_map_out(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 13341772Sjl139090 { 13351772Sjl139090 caddr_t virt; 13361772Sjl139090 size_t len; 13371772Sjl139090 struct fc_resource *resp; 13381772Sjl139090 13391772Sjl139090 if (fc_cell2int(cp->nargs) != 2) 13401772Sjl139090 return (fc_syntax_error(cp, "nargs must be 2")); 13411772Sjl139090 13421772Sjl139090 virt = fc_cell2ptr(fc_arg(cp, 1)); 13431772Sjl139090 13441772Sjl139090 len = fc_cell2size(fc_arg(cp, 0)); 13451772Sjl139090 13461772Sjl139090 FC_DEBUG2(1, CE_CONT, "opl_map_out: attempting map out %p %x\n", 13471772Sjl139090 virt, len); 13481772Sjl139090 13491772Sjl139090 /* 13501772Sjl139090 * Find if this request matches a mapping resource we set up. 13511772Sjl139090 */ 13521772Sjl139090 fc_lock_resource_list(rp); 13531772Sjl139090 for (resp = rp->head; resp != NULL; resp = resp->next) { 13541772Sjl139090 if (resp->type != RT_MAP) 13551772Sjl139090 continue; 13561772Sjl139090 if (resp->fc_map_virt != virt) 13571772Sjl139090 continue; 13581772Sjl139090 if (resp->fc_map_len == len) 13591772Sjl139090 break; 13601772Sjl139090 } 13611772Sjl139090 fc_unlock_resource_list(rp); 13621772Sjl139090 13631772Sjl139090 if (resp == NULL) 13641772Sjl139090 return (fc_priv_error(cp, "request doesn't match a " 13651772Sjl139090 "known mapping")); 13661772Sjl139090 13671772Sjl139090 opl_unmap_phys(&resp->fc_map_handle); 13681772Sjl139090 13691772Sjl139090 /* 13701772Sjl139090 * remove the resource from the list and release it. 13711772Sjl139090 */ 13721772Sjl139090 fc_rem_resource(rp, resp); 13731772Sjl139090 kmem_free(resp, sizeof (struct fc_resource)); 13741772Sjl139090 13751772Sjl139090 cp->nresults = fc_int2cell(0); 13761772Sjl139090 return (fc_success_op(ap, rp, cp)); 13771772Sjl139090 } 13781772Sjl139090 13791772Sjl139090 static int 13801772Sjl139090 opl_register_fetch(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 13811772Sjl139090 { 13821772Sjl139090 size_t len; 13831772Sjl139090 caddr_t virt; 13841772Sjl139090 int error = 0; 13851772Sjl139090 uint64_t v; 13861772Sjl139090 uint64_t x; 13871772Sjl139090 uint32_t l; 13881772Sjl139090 uint16_t w; 13891772Sjl139090 uint8_t b; 13901772Sjl139090 char *service = fc_cell2ptr(cp->svc_name); 13911772Sjl139090 struct fc_resource *resp; 13921772Sjl139090 13931772Sjl139090 if (fc_cell2int(cp->nargs) != 1) 13941772Sjl139090 return (fc_syntax_error(cp, "nargs must be 1")); 13951772Sjl139090 13961772Sjl139090 if (fc_cell2int(cp->nresults) < 1) 13971772Sjl139090 return (fc_syntax_error(cp, "nresults must be >= 1")); 13981772Sjl139090 13991772Sjl139090 virt = fc_cell2ptr(fc_arg(cp, 0)); 14001772Sjl139090 14011772Sjl139090 /* 14021772Sjl139090 * Determine the access width .. we can switch on the 2nd 14031772Sjl139090 * character of the name which is "rx@", "rl@", "rb@" or "rw@" 14041772Sjl139090 */ 14051772Sjl139090 switch (*(service + 1)) { 14061772Sjl139090 case 'x': len = sizeof (x); break; 14071772Sjl139090 case 'l': len = sizeof (l); break; 14081772Sjl139090 case 'w': len = sizeof (w); break; 14091772Sjl139090 case 'b': len = sizeof (b); break; 14101772Sjl139090 } 14111772Sjl139090 14121772Sjl139090 /* 14131772Sjl139090 * Check the alignment ... 14141772Sjl139090 */ 14151772Sjl139090 if (((intptr_t)virt & (len - 1)) != 0) 14161772Sjl139090 return (fc_priv_error(cp, "unaligned access")); 14171772Sjl139090 14181772Sjl139090 /* 14191772Sjl139090 * Find if this virt is 'within' a request we know about 14201772Sjl139090 */ 14211772Sjl139090 fc_lock_resource_list(rp); 14221772Sjl139090 for (resp = rp->head; resp != NULL; resp = resp->next) { 14231772Sjl139090 if (resp->type == RT_MAP) { 14241772Sjl139090 if ((virt >= (caddr_t)resp->fc_map_virt) && 14251772Sjl139090 ((virt + len) <= 14261772Sjl139090 ((caddr_t)resp->fc_map_virt + resp->fc_map_len))) 14271772Sjl139090 break; 14281772Sjl139090 } else if (resp->type == RT_CONTIGIOUS) { 14291772Sjl139090 if ((virt >= (caddr_t)resp->fc_contig_virt) && ((virt + len) 14301772Sjl139090 <= ((caddr_t)resp->fc_contig_virt + 14311772Sjl139090 resp->fc_contig_len))) 14321772Sjl139090 break; 14331772Sjl139090 } 14341772Sjl139090 } 14351772Sjl139090 fc_unlock_resource_list(rp); 14361772Sjl139090 14371772Sjl139090 if (resp == NULL) { 14381772Sjl139090 return (fc_priv_error(cp, "request not within " 14391772Sjl139090 "known mappings")); 14401772Sjl139090 } 14411772Sjl139090 14421772Sjl139090 switch (len) { 14431772Sjl139090 case sizeof (x): 14441772Sjl139090 if (resp->type == RT_MAP) 14451772Sjl139090 error = ddi_peek64(rp->child, 14461772Sjl139090 (int64_t *)virt, (int64_t *)&x); 14471772Sjl139090 else /* RT_CONTIGIOUS */ 14481772Sjl139090 x = *(int64_t *)virt; 14491772Sjl139090 v = x; 14501772Sjl139090 break; 14511772Sjl139090 case sizeof (l): 14521772Sjl139090 if (resp->type == RT_MAP) 14531772Sjl139090 error = ddi_peek32(rp->child, 14541772Sjl139090 (int32_t *)virt, (int32_t *)&l); 14551772Sjl139090 else /* RT_CONTIGIOUS */ 14561772Sjl139090 l = *(int32_t *)virt; 14571772Sjl139090 v = l; 14581772Sjl139090 break; 14591772Sjl139090 case sizeof (w): 14601772Sjl139090 if (resp->type == RT_MAP) 14611772Sjl139090 error = ddi_peek16(rp->child, 14621772Sjl139090 (int16_t *)virt, (int16_t *)&w); 14631772Sjl139090 else /* RT_CONTIGIOUS */ 14641772Sjl139090 w = *(int16_t *)virt; 14651772Sjl139090 v = w; 14661772Sjl139090 break; 14671772Sjl139090 case sizeof (b): 14681772Sjl139090 if (resp->type == RT_MAP) 14691772Sjl139090 error = ddi_peek8(rp->child, 14701772Sjl139090 (int8_t *)virt, (int8_t *)&b); 14711772Sjl139090 else /* RT_CONTIGIOUS */ 14721772Sjl139090 b = *(int8_t *)virt; 14731772Sjl139090 v = b; 14741772Sjl139090 break; 14751772Sjl139090 } 14761772Sjl139090 14771772Sjl139090 if (error == DDI_FAILURE) { 14781772Sjl139090 FC_DEBUG2(1, CE_CONT, "opl_register_fetch: access error " 14791772Sjl139090 "accessing virt %p len %d\n", virt, len); 14801772Sjl139090 return (fc_priv_error(cp, "access error")); 14811772Sjl139090 } 14821772Sjl139090 14831772Sjl139090 FC_DEBUG3(1, CE_CONT, "register_fetch (%s) %llx %llx\n", 14841772Sjl139090 service, virt, v); 14851772Sjl139090 14861772Sjl139090 cp->nresults = fc_int2cell(1); 14871772Sjl139090 switch (len) { 14881772Sjl139090 case sizeof (x): fc_result(cp, 0) = x; break; 14891772Sjl139090 case sizeof (l): fc_result(cp, 0) = fc_uint32_t2cell(l); break; 14901772Sjl139090 case sizeof (w): fc_result(cp, 0) = fc_uint16_t2cell(w); break; 14911772Sjl139090 case sizeof (b): fc_result(cp, 0) = fc_uint8_t2cell(b); break; 14921772Sjl139090 } 14931772Sjl139090 return (fc_success_op(ap, rp, cp)); 14941772Sjl139090 } 14951772Sjl139090 14961772Sjl139090 static int 14971772Sjl139090 opl_register_store(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 14981772Sjl139090 { 14991772Sjl139090 size_t len; 15001772Sjl139090 caddr_t virt; 15011772Sjl139090 uint64_t v; 15021772Sjl139090 uint64_t x; 15031772Sjl139090 uint32_t l; 15041772Sjl139090 uint16_t w; 15051772Sjl139090 uint8_t b; 15061772Sjl139090 char *service = fc_cell2ptr(cp->svc_name); 15071772Sjl139090 struct fc_resource *resp; 15081772Sjl139090 int error = 0; 15091772Sjl139090 15101772Sjl139090 if (fc_cell2int(cp->nargs) != 2) 15111772Sjl139090 return (fc_syntax_error(cp, "nargs must be 2")); 15121772Sjl139090 15131772Sjl139090 virt = fc_cell2ptr(fc_arg(cp, 0)); 15141772Sjl139090 15151772Sjl139090 /* 15161772Sjl139090 * Determine the access width .. we can switch on the 2nd 15171772Sjl139090 * character of the name which is "rx!", "rl!", "rb!" or "rw!" 15181772Sjl139090 */ 15191772Sjl139090 switch (*(service + 1)) { 15201772Sjl139090 case 'x': 15211772Sjl139090 len = sizeof (x); 15221772Sjl139090 x = fc_arg(cp, 1); 15231772Sjl139090 v = x; 15241772Sjl139090 break; 15251772Sjl139090 case 'l': 15261772Sjl139090 len = sizeof (l); 15271772Sjl139090 l = fc_cell2uint32_t(fc_arg(cp, 1)); 15281772Sjl139090 v = l; 15291772Sjl139090 break; 15301772Sjl139090 case 'w': 15311772Sjl139090 len = sizeof (w); 15321772Sjl139090 w = fc_cell2uint16_t(fc_arg(cp, 1)); 15331772Sjl139090 v = w; 15341772Sjl139090 break; 15351772Sjl139090 case 'b': 15361772Sjl139090 len = sizeof (b); 15371772Sjl139090 b = fc_cell2uint8_t(fc_arg(cp, 1)); 15381772Sjl139090 v = b; 15391772Sjl139090 break; 15401772Sjl139090 } 15411772Sjl139090 15421772Sjl139090 FC_DEBUG3(1, CE_CONT, "register_store (%s) %llx %llx\n", 15431772Sjl139090 service, virt, v); 15441772Sjl139090 15451772Sjl139090 /* 15461772Sjl139090 * Check the alignment ... 15471772Sjl139090 */ 15481772Sjl139090 if (((intptr_t)virt & (len - 1)) != 0) 15491772Sjl139090 return (fc_priv_error(cp, "unaligned access")); 15501772Sjl139090 15511772Sjl139090 /* 15521772Sjl139090 * Find if this virt is 'within' a request we know about 15531772Sjl139090 */ 15541772Sjl139090 fc_lock_resource_list(rp); 15551772Sjl139090 for (resp = rp->head; resp != NULL; resp = resp->next) { 15561772Sjl139090 if (resp->type == RT_MAP) { 15571772Sjl139090 if ((virt >= (caddr_t)resp->fc_map_virt) && 15581772Sjl139090 ((virt + len) <= 15591772Sjl139090 ((caddr_t)resp->fc_map_virt + resp->fc_map_len))) 15601772Sjl139090 break; 15611772Sjl139090 } else if (resp->type == RT_CONTIGIOUS) { 15621772Sjl139090 if ((virt >= (caddr_t)resp->fc_contig_virt) && ((virt + len) 15631772Sjl139090 <= ((caddr_t)resp->fc_contig_virt + 15641772Sjl139090 resp->fc_contig_len))) 15651772Sjl139090 break; 15661772Sjl139090 } 15671772Sjl139090 } 15681772Sjl139090 fc_unlock_resource_list(rp); 15691772Sjl139090 15701772Sjl139090 if (resp == NULL) 15711772Sjl139090 return (fc_priv_error(cp, "request not within" 15721772Sjl139090 "known mappings")); 15731772Sjl139090 15741772Sjl139090 switch (len) { 15751772Sjl139090 case sizeof (x): 15761772Sjl139090 if (resp->type == RT_MAP) 15771772Sjl139090 error = ddi_poke64(rp->child, (int64_t *)virt, x); 15781772Sjl139090 else if (resp->type == RT_CONTIGIOUS) 15791772Sjl139090 *(uint64_t *)virt = x; 15801772Sjl139090 break; 15811772Sjl139090 case sizeof (l): 15821772Sjl139090 if (resp->type == RT_MAP) 15831772Sjl139090 error = ddi_poke32(rp->child, (int32_t *)virt, l); 15841772Sjl139090 else if (resp->type == RT_CONTIGIOUS) 15851772Sjl139090 *(uint32_t *)virt = l; 15861772Sjl139090 break; 15871772Sjl139090 case sizeof (w): 15881772Sjl139090 if (resp->type == RT_MAP) 15891772Sjl139090 error = ddi_poke16(rp->child, (int16_t *)virt, w); 15901772Sjl139090 else if (resp->type == RT_CONTIGIOUS) 15911772Sjl139090 *(uint16_t *)virt = w; 15921772Sjl139090 break; 15931772Sjl139090 case sizeof (b): 15941772Sjl139090 if (resp->type == RT_MAP) 15951772Sjl139090 error = ddi_poke8(rp->child, (int8_t *)virt, b); 15961772Sjl139090 else if (resp->type == RT_CONTIGIOUS) 15971772Sjl139090 *(uint8_t *)virt = b; 15981772Sjl139090 break; 15991772Sjl139090 } 16001772Sjl139090 16011772Sjl139090 if (error == DDI_FAILURE) { 16021772Sjl139090 FC_DEBUG2(1, CE_CONT, "opl_register_store: access error " 16031772Sjl139090 "accessing virt %p len %d\n", virt, len); 16041772Sjl139090 return (fc_priv_error(cp, "access error")); 16051772Sjl139090 } 16061772Sjl139090 16071772Sjl139090 cp->nresults = fc_int2cell(0); 16081772Sjl139090 return (fc_success_op(ap, rp, cp)); 16091772Sjl139090 } 16101772Sjl139090 16111772Sjl139090 /* 16121772Sjl139090 * opl_claim_memory 16131772Sjl139090 * 16141772Sjl139090 * claim-memory (align size vhint -- vaddr) 16151772Sjl139090 */ 16161772Sjl139090 static int 16171772Sjl139090 opl_claim_memory(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 16181772Sjl139090 { 16191772Sjl139090 int align, size, vhint; 16201772Sjl139090 uint64_t answer, alen; 16211772Sjl139090 ndi_ra_request_t request; 16221772Sjl139090 struct fc_resource *resp; 16231772Sjl139090 16241772Sjl139090 if (fc_cell2int(cp->nargs) != 3) 16251772Sjl139090 return (fc_syntax_error(cp, "nargs must be 3")); 16261772Sjl139090 16271772Sjl139090 if (fc_cell2int(cp->nresults) < 1) 16281772Sjl139090 return (fc_syntax_error(cp, "nresults must be >= 1")); 16291772Sjl139090 16301772Sjl139090 vhint = fc_cell2int(fc_arg(cp, 2)); 16311772Sjl139090 size = fc_cell2int(fc_arg(cp, 1)); 16321772Sjl139090 align = fc_cell2int(fc_arg(cp, 0)); 16331772Sjl139090 16341772Sjl139090 FC_DEBUG3(1, CE_CONT, "opl_claim_memory: align=0x%x size=0x%x " 16351772Sjl139090 "vhint=0x%x\n", align, size, vhint); 16361772Sjl139090 16371772Sjl139090 if (size == 0) { 16381772Sjl139090 cmn_err(CE_WARN, "opl_claim_memory - unable to allocate " 16391772Sjl139090 "contiguous memory of size zero\n"); 16401772Sjl139090 return (fc_priv_error(cp, "allocation error")); 16411772Sjl139090 } 16421772Sjl139090 16431772Sjl139090 if (vhint) { 16441772Sjl139090 cmn_err(CE_WARN, "opl_claim_memory - vhint is not zero " 16451772Sjl139090 "vhint=0x%x - Ignoring Argument\n", vhint); 16461772Sjl139090 } 16471772Sjl139090 16481772Sjl139090 bzero((caddr_t)&request, sizeof (ndi_ra_request_t)); 16491772Sjl139090 request.ra_flags = NDI_RA_ALLOC_BOUNDED; 16501772Sjl139090 request.ra_boundbase = 0; 16511772Sjl139090 request.ra_boundlen = 0xffffffff; 16521772Sjl139090 request.ra_len = size; 16531772Sjl139090 request.ra_align_mask = align - 1; 16541772Sjl139090 16551772Sjl139090 if (ndi_ra_alloc(ddi_root_node(), &request, &answer, &alen, 16561772Sjl139090 "opl-fcodemem", NDI_RA_PASS) != NDI_SUCCESS) { 16571772Sjl139090 cmn_err(CE_WARN, "opl_claim_memory - unable to allocate " 16581772Sjl139090 "contiguous memory\n"); 16591772Sjl139090 return (fc_priv_error(cp, "allocation error")); 16601772Sjl139090 } 16611772Sjl139090 16621772Sjl139090 FC_DEBUG2(1, CE_CONT, "opl_claim_memory: address allocated=0x%lx " 16631772Sjl139090 "size=0x%x\n", answer, alen); 16641772Sjl139090 16651772Sjl139090 cp->nresults = fc_int2cell(1); 16661772Sjl139090 fc_result(cp, 0) = answer; 16671772Sjl139090 16681772Sjl139090 /* 16691772Sjl139090 * Log this resource ... 16701772Sjl139090 */ 16711772Sjl139090 resp = kmem_zalloc(sizeof (struct fc_resource), KM_SLEEP); 16721772Sjl139090 resp->type = RT_CONTIGIOUS; 16731772Sjl139090 resp->fc_contig_virt = (void *)answer; 16741772Sjl139090 resp->fc_contig_len = size; 16751772Sjl139090 fc_add_resource(rp, resp); 16761772Sjl139090 16771772Sjl139090 return (fc_success_op(ap, rp, cp)); 16781772Sjl139090 } 16791772Sjl139090 16801772Sjl139090 /* 16811772Sjl139090 * opl_release_memory 16821772Sjl139090 * 16831772Sjl139090 * release-memory (size vaddr -- ) 16841772Sjl139090 */ 16851772Sjl139090 static int 16861772Sjl139090 opl_release_memory(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 16871772Sjl139090 { 16881772Sjl139090 int32_t vaddr, size; 16891772Sjl139090 struct fc_resource *resp; 16901772Sjl139090 16911772Sjl139090 if (fc_cell2int(cp->nargs) != 2) 16921772Sjl139090 return (fc_syntax_error(cp, "nargs must be 2")); 16931772Sjl139090 16941772Sjl139090 if (fc_cell2int(cp->nresults) != 0) 16951772Sjl139090 return (fc_syntax_error(cp, "nresults must be 0")); 16961772Sjl139090 16971772Sjl139090 vaddr = fc_cell2int(fc_arg(cp, 1)); 16981772Sjl139090 size = fc_cell2int(fc_arg(cp, 0)); 16991772Sjl139090 17001772Sjl139090 FC_DEBUG2(1, CE_CONT, "opl_release_memory: vaddr=0x%x size=0x%x\n", 17011772Sjl139090 vaddr, size); 17021772Sjl139090 17031772Sjl139090 /* 17041772Sjl139090 * Find if this request matches a mapping resource we set up. 17051772Sjl139090 */ 17061772Sjl139090 fc_lock_resource_list(rp); 17071772Sjl139090 for (resp = rp->head; resp != NULL; resp = resp->next) { 17081772Sjl139090 if (resp->type != RT_CONTIGIOUS) 17091772Sjl139090 continue; 17101772Sjl139090 if (resp->fc_contig_virt != (void *)(uintptr_t)vaddr) 17111772Sjl139090 continue; 17121772Sjl139090 if (resp->fc_contig_len == size) 17131772Sjl139090 break; 17141772Sjl139090 } 17151772Sjl139090 fc_unlock_resource_list(rp); 17161772Sjl139090 17171772Sjl139090 if (resp == NULL) 17181772Sjl139090 return (fc_priv_error(cp, "request doesn't match a " 17191772Sjl139090 "known mapping")); 17201772Sjl139090 17211772Sjl139090 (void) ndi_ra_free(ddi_root_node(), vaddr, size, 17221772Sjl139090 "opl-fcodemem", NDI_RA_PASS); 17231772Sjl139090 17241772Sjl139090 /* 17251772Sjl139090 * remove the resource from the list and release it. 17261772Sjl139090 */ 17271772Sjl139090 fc_rem_resource(rp, resp); 17281772Sjl139090 kmem_free(resp, sizeof (struct fc_resource)); 17291772Sjl139090 17301772Sjl139090 cp->nresults = fc_int2cell(0); 17311772Sjl139090 17321772Sjl139090 return (fc_success_op(ap, rp, cp)); 17331772Sjl139090 } 17341772Sjl139090 17351772Sjl139090 /* 17361772Sjl139090 * opl_vtop 17371772Sjl139090 * 17381772Sjl139090 * vtop (vaddr -- paddr.lo paddr.hi) 17391772Sjl139090 */ 17401772Sjl139090 static int 17411772Sjl139090 opl_vtop(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 17421772Sjl139090 { 17431772Sjl139090 int vaddr; 17441772Sjl139090 uint64_t paddr; 17451772Sjl139090 struct fc_resource *resp; 17461772Sjl139090 17471772Sjl139090 if (fc_cell2int(cp->nargs) != 1) 17481772Sjl139090 return (fc_syntax_error(cp, "nargs must be 1")); 17491772Sjl139090 17501772Sjl139090 if (fc_cell2int(cp->nresults) >= 3) 17511772Sjl139090 return (fc_syntax_error(cp, "nresults must be less than 2")); 17521772Sjl139090 17531772Sjl139090 vaddr = fc_cell2int(fc_arg(cp, 0)); 17541772Sjl139090 17551772Sjl139090 /* 17561772Sjl139090 * Find if this request matches a mapping resource we set up. 17571772Sjl139090 */ 17581772Sjl139090 fc_lock_resource_list(rp); 17591772Sjl139090 for (resp = rp->head; resp != NULL; resp = resp->next) { 17601772Sjl139090 if (resp->type != RT_CONTIGIOUS) 17611772Sjl139090 continue; 1762*3965Sbm42561 if (((uint64_t)resp->fc_contig_virt <= vaddr) && 1763*3965Sbm42561 (vaddr < (uint64_t)resp->fc_contig_virt + 1764*3965Sbm42561 resp->fc_contig_len)) 17651772Sjl139090 break; 17661772Sjl139090 } 17671772Sjl139090 fc_unlock_resource_list(rp); 17681772Sjl139090 17691772Sjl139090 if (resp == NULL) 17701772Sjl139090 return (fc_priv_error(cp, "request doesn't match a " 17711772Sjl139090 "known mapping")); 17721772Sjl139090 17731772Sjl139090 paddr = va_to_pa((void *)(uintptr_t)vaddr); 17741772Sjl139090 17751772Sjl139090 FC_DEBUG2(1, CE_CONT, "opl_vtop: vaddr=0x%x paddr=0x%x\n", 17761772Sjl139090 vaddr, paddr); 17771772Sjl139090 17781772Sjl139090 cp->nresults = fc_int2cell(2); 17791772Sjl139090 17801772Sjl139090 fc_result(cp, 0) = paddr; 17811772Sjl139090 fc_result(cp, 1) = 0; 17821772Sjl139090 17831772Sjl139090 return (fc_success_op(ap, rp, cp)); 17841772Sjl139090 } 17851772Sjl139090 17861772Sjl139090 static int 17871772Sjl139090 opl_config_child(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 17881772Sjl139090 { 17891772Sjl139090 fc_phandle_t h; 17901772Sjl139090 17911772Sjl139090 if (fc_cell2int(cp->nargs) != 0) 17921772Sjl139090 return (fc_syntax_error(cp, "nargs must be 0")); 17931772Sjl139090 17941772Sjl139090 if (fc_cell2int(cp->nresults) < 1) 17951772Sjl139090 return (fc_syntax_error(cp, "nresults must be >= 1")); 17961772Sjl139090 17971772Sjl139090 h = fc_dip_to_phandle(fc_handle_to_phandle_head(rp), rp->child); 17981772Sjl139090 17991772Sjl139090 cp->nresults = fc_int2cell(1); 18001772Sjl139090 fc_result(cp, 0) = fc_phandle2cell(h); 18011772Sjl139090 18021772Sjl139090 return (fc_success_op(ap, rp, cp)); 18031772Sjl139090 } 18041772Sjl139090 18051772Sjl139090 static int 18061772Sjl139090 opl_get_fcode(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 18071772Sjl139090 { 18081772Sjl139090 caddr_t dropin_name_virt, fcode_virt; 18091772Sjl139090 char *dropin_name, *fcode; 18101772Sjl139090 int fcode_len, status; 18111772Sjl139090 18121772Sjl139090 if (fc_cell2int(cp->nargs) != 3) 18131772Sjl139090 return (fc_syntax_error(cp, "nargs must be 3")); 18141772Sjl139090 18151772Sjl139090 if (fc_cell2int(cp->nresults) < 1) 18161772Sjl139090 return (fc_syntax_error(cp, "nresults must be >= 1")); 18171772Sjl139090 18181772Sjl139090 dropin_name_virt = fc_cell2ptr(fc_arg(cp, 0)); 18191772Sjl139090 18201772Sjl139090 fcode_virt = fc_cell2ptr(fc_arg(cp, 1)); 18211772Sjl139090 18221772Sjl139090 fcode_len = fc_cell2int(fc_arg(cp, 2)); 18231772Sjl139090 18241772Sjl139090 dropin_name = kmem_zalloc(FC_SVC_NAME_LEN, KM_SLEEP); 18251772Sjl139090 18261772Sjl139090 FC_DEBUG2(1, CE_CONT, "get_fcode: %x %d\n", fcode_virt, fcode_len); 18271772Sjl139090 18281772Sjl139090 if (copyinstr(fc_cell2ptr(dropin_name_virt), dropin_name, 18291772Sjl139090 FC_SVC_NAME_LEN - 1, NULL)) { 18301772Sjl139090 FC_DEBUG1(1, CE_CONT, "opl_get_fcode: " 18311772Sjl139090 "fault copying in drop in name %p\n", dropin_name_virt); 18321772Sjl139090 status = 0; 18331772Sjl139090 } else { 18341772Sjl139090 FC_DEBUG1(1, CE_CONT, "get_fcode: %s\n", dropin_name); 18351772Sjl139090 18361772Sjl139090 fcode = kmem_zalloc(fcode_len, KM_SLEEP); 18371772Sjl139090 18381772Sjl139090 if ((status = prom_get_fcode(dropin_name, fcode)) != 0) { 18391772Sjl139090 18401772Sjl139090 if (copyout((void *)fcode, (void *)fcode_virt, 18411772Sjl139090 fcode_len)) { 18421772Sjl139090 cmn_err(CE_WARN, " opl_get_fcode: Unable " 18431772Sjl139090 "to copy out fcode image"); 18441772Sjl139090 status = 0; 18451772Sjl139090 } 18461772Sjl139090 } 18471772Sjl139090 18481772Sjl139090 kmem_free(fcode, fcode_len); 18491772Sjl139090 } 18501772Sjl139090 18511772Sjl139090 kmem_free(dropin_name, FC_SVC_NAME_LEN); 18521772Sjl139090 18531772Sjl139090 cp->nresults = fc_int2cell(1); 18541772Sjl139090 fc_result(cp, 0) = status; 18551772Sjl139090 18561772Sjl139090 return (fc_success_op(ap, rp, cp)); 18571772Sjl139090 } 18581772Sjl139090 18591772Sjl139090 static int 18601772Sjl139090 opl_get_fcode_size(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 18611772Sjl139090 { 18621772Sjl139090 caddr_t virt; 18631772Sjl139090 char *dropin_name; 18641772Sjl139090 int len; 18651772Sjl139090 18661772Sjl139090 if (fc_cell2int(cp->nargs) != 1) 18671772Sjl139090 return (fc_syntax_error(cp, "nargs must be 1")); 18681772Sjl139090 18691772Sjl139090 if (fc_cell2int(cp->nresults) < 1) 18701772Sjl139090 return (fc_syntax_error(cp, "nresults must be >= 1")); 18711772Sjl139090 18721772Sjl139090 virt = fc_cell2ptr(fc_arg(cp, 0)); 18731772Sjl139090 18741772Sjl139090 dropin_name = kmem_zalloc(FC_SVC_NAME_LEN, KM_SLEEP); 18751772Sjl139090 18761772Sjl139090 FC_DEBUG0(1, CE_CONT, "opl_get_fcode_size:\n"); 18771772Sjl139090 18781772Sjl139090 if (copyinstr(fc_cell2ptr(virt), dropin_name, 18791772Sjl139090 FC_SVC_NAME_LEN - 1, NULL)) { 18801772Sjl139090 FC_DEBUG1(1, CE_CONT, "opl_get_fcode_size: " 18811772Sjl139090 "fault copying in drop in name %p\n", virt); 18821772Sjl139090 len = 0; 18831772Sjl139090 } else { 18841772Sjl139090 FC_DEBUG1(1, CE_CONT, "opl_get_fcode_size: %s\n", dropin_name); 18851772Sjl139090 18861772Sjl139090 len = prom_get_fcode_size(dropin_name); 18871772Sjl139090 } 18881772Sjl139090 18891772Sjl139090 kmem_free(dropin_name, FC_SVC_NAME_LEN); 18901772Sjl139090 18911772Sjl139090 FC_DEBUG1(1, CE_CONT, "opl_get_fcode_size: fcode_len = %d\n", len); 18921772Sjl139090 18931772Sjl139090 cp->nresults = fc_int2cell(1); 18941772Sjl139090 fc_result(cp, 0) = len; 18951772Sjl139090 18961772Sjl139090 return (fc_success_op(ap, rp, cp)); 18971772Sjl139090 } 18981772Sjl139090 18991772Sjl139090 static int 19001772Sjl139090 opl_map_phys(dev_info_t *dip, struct regspec *phys_spec, 19011772Sjl139090 caddr_t *addrp, ddi_device_acc_attr_t *accattrp, 19021772Sjl139090 ddi_acc_handle_t *handlep) 19031772Sjl139090 { 19041772Sjl139090 ddi_map_req_t mapreq; 19051772Sjl139090 ddi_acc_hdl_t *acc_handlep; 19061772Sjl139090 int result; 19071772Sjl139090 struct regspec *rspecp; 19081772Sjl139090 19091772Sjl139090 *handlep = impl_acc_hdl_alloc(KM_SLEEP, NULL); 19101772Sjl139090 acc_handlep = impl_acc_hdl_get(*handlep); 19111772Sjl139090 acc_handlep->ah_vers = VERS_ACCHDL; 19121772Sjl139090 acc_handlep->ah_dip = dip; 19131772Sjl139090 acc_handlep->ah_rnumber = 0; 19141772Sjl139090 acc_handlep->ah_offset = 0; 19151772Sjl139090 acc_handlep->ah_len = 0; 19161772Sjl139090 acc_handlep->ah_acc = *accattrp; 19171772Sjl139090 rspecp = kmem_zalloc(sizeof (struct regspec), KM_SLEEP); 19181772Sjl139090 *rspecp = *phys_spec; 19191772Sjl139090 /* 19201772Sjl139090 * cache a copy of the reg spec 19211772Sjl139090 */ 19221772Sjl139090 acc_handlep->ah_bus_private = rspecp; 19231772Sjl139090 19241772Sjl139090 mapreq.map_op = DDI_MO_MAP_LOCKED; 19251772Sjl139090 mapreq.map_type = DDI_MT_REGSPEC; 19261772Sjl139090 mapreq.map_obj.rp = (struct regspec *)phys_spec; 19271772Sjl139090 mapreq.map_prot = PROT_READ | PROT_WRITE; 19281772Sjl139090 mapreq.map_flags = DDI_MF_KERNEL_MAPPING; 19291772Sjl139090 mapreq.map_handlep = acc_handlep; 19301772Sjl139090 mapreq.map_vers = DDI_MAP_VERSION; 19311772Sjl139090 19321772Sjl139090 result = ddi_map(dip, &mapreq, 0, 0, addrp); 19331772Sjl139090 19341772Sjl139090 if (result != DDI_SUCCESS) { 19351772Sjl139090 impl_acc_hdl_free(*handlep); 19363354Sjl139090 kmem_free(rspecp, sizeof (struct regspec)); 19371772Sjl139090 *handlep = (ddi_acc_handle_t)NULL; 19381772Sjl139090 } else { 19391772Sjl139090 acc_handlep->ah_addr = *addrp; 19401772Sjl139090 } 19411772Sjl139090 19421772Sjl139090 return (result); 19431772Sjl139090 } 19441772Sjl139090 19451772Sjl139090 static void 19461772Sjl139090 opl_unmap_phys(ddi_acc_handle_t *handlep) 19471772Sjl139090 { 19481772Sjl139090 ddi_map_req_t mapreq; 19491772Sjl139090 ddi_acc_hdl_t *acc_handlep; 19501772Sjl139090 struct regspec *rspecp; 19511772Sjl139090 19521772Sjl139090 acc_handlep = impl_acc_hdl_get(*handlep); 19531772Sjl139090 ASSERT(acc_handlep); 19541772Sjl139090 rspecp = acc_handlep->ah_bus_private; 19551772Sjl139090 19561772Sjl139090 mapreq.map_op = DDI_MO_UNMAP; 19571772Sjl139090 mapreq.map_type = DDI_MT_REGSPEC; 19581772Sjl139090 mapreq.map_obj.rp = (struct regspec *)rspecp; 19591772Sjl139090 mapreq.map_prot = PROT_READ | PROT_WRITE; 19601772Sjl139090 mapreq.map_flags = DDI_MF_KERNEL_MAPPING; 19611772Sjl139090 mapreq.map_handlep = acc_handlep; 19621772Sjl139090 mapreq.map_vers = DDI_MAP_VERSION; 19631772Sjl139090 19641772Sjl139090 (void) ddi_map(acc_handlep->ah_dip, &mapreq, acc_handlep->ah_offset, 19651772Sjl139090 acc_handlep->ah_len, &acc_handlep->ah_addr); 19661772Sjl139090 19671772Sjl139090 impl_acc_hdl_free(*handlep); 19681772Sjl139090 /* 19691772Sjl139090 * Free the cached copy 19701772Sjl139090 */ 19711772Sjl139090 kmem_free(rspecp, sizeof (struct regspec)); 19721772Sjl139090 *handlep = (ddi_acc_handle_t)NULL; 19731772Sjl139090 } 19741772Sjl139090 19751772Sjl139090 static int 19761772Sjl139090 opl_get_hwd_va(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 19771772Sjl139090 { 19781772Sjl139090 uint32_t portid; 19791772Sjl139090 void *hwd_virt; 19801772Sjl139090 hwd_header_t *hwd_h = NULL; 19811772Sjl139090 hwd_sb_t *hwd_sb = NULL; 19821772Sjl139090 int lsb, ch, leaf; 19831772Sjl139090 int status = 1; 19841772Sjl139090 19851772Sjl139090 /* Check the argument */ 19861772Sjl139090 if (fc_cell2int(cp->nargs) != 2) 19871772Sjl139090 return (fc_syntax_error(cp, "nargs must be 2")); 19881772Sjl139090 19891772Sjl139090 if (fc_cell2int(cp->nresults) < 1) 19901772Sjl139090 return (fc_syntax_error(cp, "nresults must be >= 1")); 19911772Sjl139090 19921772Sjl139090 /* Get the parameters */ 19931772Sjl139090 portid = fc_cell2uint32_t(fc_arg(cp, 0)); 19941772Sjl139090 hwd_virt = (void *)fc_cell2ptr(fc_arg(cp, 1)); 19951772Sjl139090 19961772Sjl139090 /* Get the ID numbers */ 19971772Sjl139090 lsb = OPL_IO_PORTID_TO_LSB(portid); 19981772Sjl139090 ch = OPL_PORTID_TO_CHANNEL(portid); 19991772Sjl139090 leaf = OPL_PORTID_TO_LEAF(portid); 20001772Sjl139090 ASSERT(OPL_IO_PORTID(lsb, ch, leaf) == portid); 20011772Sjl139090 20021772Sjl139090 /* Set the pointer of hwd. */ 20031772Sjl139090 if ((hwd_h = (hwd_header_t *)opl_boards[lsb].cfg_hwd) == NULL) { 20041772Sjl139090 return (fc_priv_error(cp, "null hwd header")); 20051772Sjl139090 } 20061772Sjl139090 /* Set the pointer of hwd sb. */ 20071772Sjl139090 if ((hwd_sb = (hwd_sb_t *)((char *)hwd_h + hwd_h->hdr_sb_info_offset)) 20081772Sjl139090 == NULL) { 20091772Sjl139090 return (fc_priv_error(cp, "null hwd sb")); 20101772Sjl139090 } 20111772Sjl139090 20121772Sjl139090 if (ch == OPL_CMU_CHANNEL) { 20131772Sjl139090 /* Copyout CMU-CH HW Descriptor */ 20141772Sjl139090 if (copyout((void *)&hwd_sb->sb_cmu.cmu_ch, 20151772Sjl139090 (void *)hwd_virt, sizeof (hwd_cmu_chan_t))) { 20161772Sjl139090 cmn_err(CE_WARN, "opl_get_hwd_va: " 20171772Sjl139090 "Unable to copy out cmuch descriptor for %x", 20181772Sjl139090 portid); 20191772Sjl139090 status = 0; 20201772Sjl139090 } 20211772Sjl139090 } else { 20221772Sjl139090 /* Copyout PCI-CH HW Descriptor */ 20231772Sjl139090 if (copyout((void *)&hwd_sb->sb_pci_ch[ch].pci_leaf[leaf], 20241772Sjl139090 (void *)hwd_virt, sizeof (hwd_leaf_t))) { 20251772Sjl139090 cmn_err(CE_WARN, "opl_get_hwd_va: " 20261772Sjl139090 "Unable to copy out pcich descriptor for %x", 20271772Sjl139090 portid); 20281772Sjl139090 status = 0; 20291772Sjl139090 } 20301772Sjl139090 } 20311772Sjl139090 20321772Sjl139090 cp->nresults = fc_int2cell(1); 20331772Sjl139090 fc_result(cp, 0) = status; 20341772Sjl139090 20351772Sjl139090 return (fc_success_op(ap, rp, cp)); 20361772Sjl139090 } 20371772Sjl139090 20381772Sjl139090 /* 20391982Smv143129 * After Solaris boots, a user can enter OBP using L1A, etc. While in OBP, 20401982Smv143129 * interrupts may be received from PCI devices. These interrupts 20411982Smv143129 * cannot be handled meaningfully since the system is in OBP. These 20421982Smv143129 * interrupts need to be cleared on the CPU side so that the CPU may 20431982Smv143129 * continue with whatever it is doing. Devices that have raised the 20441982Smv143129 * interrupts are expected to reraise the interrupts after sometime 20451982Smv143129 * as they have not been handled. At that time, Solaris will have a 20461982Smv143129 * chance to properly service the interrupts. 20471982Smv143129 * 20481982Smv143129 * The location of the interrupt registers depends on what is present 20491982Smv143129 * at a port. OPL currently supports the Oberon and the CMU channel. 20501982Smv143129 * The following handler handles both kinds of ports and computes 20511982Smv143129 * interrupt register addresses from the specifications and Jupiter Bus 20521982Smv143129 * device bindings. 20531982Smv143129 * 20541982Smv143129 * Fcode drivers install their interrupt handler via a "master-interrupt" 20551982Smv143129 * service. For boot time devices, this takes place within OBP. In the case 20561982Smv143129 * of DR, OPL uses IKP. The Fcode drivers that run within the efcode framework 20571982Smv143129 * attempt to install their handler via the "master-interrupt" service. 20581982Smv143129 * However, we cannot meaningfully install the Fcode driver's handler. 20591982Smv143129 * Instead, we install our own handler in OBP which does the same thing. 20601982Smv143129 * 20611982Smv143129 * Note that the only handling done for interrupts here is to clear it 20621982Smv143129 * on the CPU side. If any device in the future requires more special 20631982Smv143129 * handling, we would have to put in some kind of framework for adding 20641982Smv143129 * device-specific handlers. This is *highly* unlikely, but possible. 20651982Smv143129 * 20661982Smv143129 * Finally, OBP provides a hook called "unix-interrupt-handler" to install 20671982Smv143129 * a Solaris-defined master-interrupt handler for a port. The default 20681982Smv143129 * definition for this method does nothing. Solaris may override this 20691982Smv143129 * with its own definition. This is the way the following handler gets 20701982Smv143129 * control from OBP when interrupts happen at a port after L1A, etc. 20711982Smv143129 */ 20721982Smv143129 20731982Smv143129 static char define_master_interrupt_handler[] = 20741982Smv143129 20751982Smv143129 /* 20761982Smv143129 * This method translates an Oberon port id to the base (physical) address 20771982Smv143129 * of the interrupt clear registers for that port id. 20781982Smv143129 */ 20791982Smv143129 20801982Smv143129 ": pcich-mid>clear-int-pa ( mid -- pa ) " 20811982Smv143129 " dup 1 >> 7 and ( mid ch# ) " 20821982Smv143129 " over 4 >> h# 1f and ( mid ch# lsb# ) " 20831982Smv143129 " 1 d# 46 << ( mid ch# lsb# pa ) " 20841982Smv143129 " swap d# 40 << or ( mid ch# pa ) " 20851982Smv143129 " swap d# 37 << or ( mid pa ) " 20861982Smv143129 " swap 1 and if h# 70.0000 else h# 60.0000 then " 20871982Smv143129 " or h# 1400 or ( pa ) " 20881982Smv143129 "; " 20891982Smv143129 20901982Smv143129 /* 20911982Smv143129 * This method translates a CMU channel port id to the base (physical) address 20921982Smv143129 * of the interrupt clear registers for that port id. There are two classes of 20931982Smv143129 * interrupts that need to be handled for a CMU channel: 20941982Smv143129 * - obio interrupts 20951982Smv143129 * - pci interrupts 20961982Smv143129 * So, there are two addresses that need to be computed. 20971982Smv143129 */ 20981982Smv143129 20991982Smv143129 ": cmuch-mid>clear-int-pa ( mid -- obio-pa pci-pa ) " 21001982Smv143129 " dup 1 >> 7 and ( mid ch# ) " 21011982Smv143129 " over 4 >> h# 1f and ( mid ch# lsb# ) " 21021982Smv143129 " 1 d# 46 << ( mid ch# lsb# pa ) " 21031982Smv143129 " swap d# 40 << or ( mid ch# pa ) " 21041982Smv143129 " swap d# 37 << or ( mid pa ) " 21051982Smv143129 " nip dup h# 1800 + ( pa obio-pa ) " 21061982Smv143129 " swap h# 1400 + ( obio-pa pci-pa ) " 21071982Smv143129 "; " 21081982Smv143129 21091982Smv143129 /* 21101982Smv143129 * This method checks if a given I/O port ID is valid or not. 21111982Smv143129 * For a given LSB, 21121982Smv143129 * Oberon ports range from 0 - 3 21131982Smv143129 * CMU ch ports range from 4 - 4 21141982Smv143129 * 21151982Smv143129 * Also, the Oberon supports leaves 0 and 1. 21161982Smv143129 * The CMU ch supports only one leaf, leaf 0. 21171982Smv143129 */ 21181982Smv143129 21191982Smv143129 ": valid-io-mid? ( mid -- flag ) " 21201982Smv143129 " dup 1 >> 7 and ( mid ch# ) " 21211982Smv143129 " dup 4 > if 2drop false exit then ( mid ch# ) " 21221982Smv143129 " 4 = swap 1 and 1 = and not " 21231982Smv143129 "; " 21241982Smv143129 21251982Smv143129 /* 21261982Smv143129 * This method checks if a given port id is a CMU ch. 21271982Smv143129 */ 21281982Smv143129 21291982Smv143129 ": cmuch? ( mid -- flag ) 1 >> 7 and 4 = ; " 21301982Smv143129 21311982Smv143129 /* 21321982Smv143129 * Given the base address of the array of interrupt clear registers for 21331982Smv143129 * a port id, this method iterates over the given interrupt number bitmap 21341982Smv143129 * and resets the interrupt on the CPU side for every interrupt number 21351982Smv143129 * in the bitmap. Note that physical addresses are used to perform the 21361982Smv143129 * writes, not virtual addresses. This allows the handler to work without 21371982Smv143129 * any involvement from Solaris. 21381982Smv143129 */ 21391982Smv143129 21401982Smv143129 ": clear-ints ( pa bitmap count -- ) " 21411982Smv143129 " 0 do ( pa bitmap ) " 21421982Smv143129 " dup 0= if 2drop unloop exit then " 21431982Smv143129 " tuck ( bitmap pa bitmap ) " 21441982Smv143129 " 1 and if ( bitmap pa ) " 21451982Smv143129 " dup i 8 * + 0 swap ( bitmap pa 0 pa' ) " 21461982Smv143129 " h# 15 spacex! ( bitmap pa ) " 21471982Smv143129 " then ( bitmap pa ) " 21481982Smv143129 " swap 1 >> ( pa bitmap ) " 21491982Smv143129 " loop " 21501982Smv143129 "; " 21511982Smv143129 21521982Smv143129 /* 21531982Smv143129 * This method replaces the master-interrupt handler in OBP. Once 21541982Smv143129 * this method is plumbed into OBP, OBP transfers control to this 21551982Smv143129 * handler while returning to Solaris from OBP after L1A. This method's 21561982Smv143129 * task is to simply reset received interrupts on the CPU side. 21571982Smv143129 * When the devices reassert the interrupts later, Solaris will 21581982Smv143129 * be able to see them and handle them. 21591982Smv143129 * 21601982Smv143129 * For each port ID that has interrupts, this method is called 21611982Smv143129 * once by OBP. The input arguments are: 21621982Smv143129 * mid portid 21631982Smv143129 * bitmap bitmap of interrupts that have happened 21641982Smv143129 * 21651982Smv143129 * This method returns true, if it is able to handle the interrupts. 21661982Smv143129 * OBP does nothing further. 21671982Smv143129 * 21681982Smv143129 * This method returns false, if it encountered a problem. Currently, 21691982Smv143129 * the only problem could be an invalid port id. OBP needs to do 21701982Smv143129 * its own processing in that case. If this method returns false, 21711982Smv143129 * it preserves the mid and bitmap arguments for OBP. 21721982Smv143129 */ 21731982Smv143129 21741982Smv143129 ": unix-resend-mondos ( mid bitmap -- [ mid bitmap false ] | true ) " 21751982Smv143129 21761982Smv143129 /* 21771982Smv143129 * Uncomment the following line if you want to display the input arguments. 21781982Smv143129 * This is meant for debugging. 21791982Smv143129 * " .\" Bitmap=\" dup u. .\" MID=\" over u. cr " 21801982Smv143129 */ 21811982Smv143129 21821982Smv143129 /* 21831982Smv143129 * If the port id is not valid (according to the Oberon and CMU ch 21841982Smv143129 * specifications, then return false to OBP to continue further 21851982Smv143129 * processing. 21861982Smv143129 */ 21871982Smv143129 21881982Smv143129 " over valid-io-mid? not if ( mid bitmap ) " 21891982Smv143129 " false exit " 21901982Smv143129 " then " 21911982Smv143129 21921982Smv143129 /* 21931982Smv143129 * If the port is a CMU ch, then the 64-bit bitmap represents 21941982Smv143129 * 2 32-bit bitmaps: 21951982Smv143129 * - obio interrupt bitmap (20 bits) 21961982Smv143129 * - pci interrupt bitmap (32 bits) 21971982Smv143129 * 21981982Smv143129 * - Split the bitmap into two 21991982Smv143129 * - Compute the base addresses of the interrupt clear registers 22001982Smv143129 * for both pci interrupts and obio interrupts 22011982Smv143129 * - Clear obio interrupts 22021982Smv143129 * - Clear pci interrupts 22031982Smv143129 */ 22041982Smv143129 22051982Smv143129 " over cmuch? if ( mid bitmap ) " 22061982Smv143129 " xlsplit ( mid pci-bit obio-bit ) " 22071982Smv143129 " rot cmuch-mid>clear-int-pa ( pci-bit obio-bit obio-pa pci-pa ) " 22081982Smv143129 " >r ( pci-bit obio-bit obio-pa ) ( r: pci-pa ) " 22091982Smv143129 " swap d# 20 clear-ints ( pci-bit ) ( r: pci-pa ) " 22101982Smv143129 " r> swap d# 32 clear-ints ( ) ( r: ) " 22111982Smv143129 22121982Smv143129 /* 22131982Smv143129 * If the port is an Oberon, then the 64-bit bitmap is used fully. 22141982Smv143129 * 22151982Smv143129 * - Compute the base address of the interrupt clear registers 22161982Smv143129 * - Clear interrupts 22171982Smv143129 */ 22181982Smv143129 22191982Smv143129 " else ( mid bitmap ) " 22201982Smv143129 " swap pcich-mid>clear-int-pa ( bitmap pa ) " 22211982Smv143129 " swap d# 64 clear-ints ( ) " 22221982Smv143129 " then " 22231982Smv143129 22241982Smv143129 /* 22251982Smv143129 * Always return true from here. 22261982Smv143129 */ 22271982Smv143129 22281982Smv143129 " true ( true ) " 22291982Smv143129 "; " 22301982Smv143129 ; 22311982Smv143129 22321982Smv143129 static char install_master_interrupt_handler[] = 22331982Smv143129 "' unix-resend-mondos to unix-interrupt-handler"; 22341982Smv143129 static char handler[] = "unix-interrupt-handler"; 22351982Smv143129 static char handler_defined[] = "p\" %s\" find nip swap l! "; 22361982Smv143129 22371982Smv143129 /*ARGSUSED*/ 22381982Smv143129 static int 22391982Smv143129 master_interrupt_init(uint32_t portid, uint32_t xt) 22401982Smv143129 { 22411982Smv143129 uint_t defined; 22421982Smv143129 char buf[sizeof (handler) + sizeof (handler_defined)]; 22431982Smv143129 22441982Smv143129 if (master_interrupt_inited) 22451982Smv143129 return (1); 22461982Smv143129 22471982Smv143129 /* 22481982Smv143129 * Check if the defer word "unix-interrupt-handler" is defined. 22491982Smv143129 * This must be defined for OPL systems. So, this is only a 22501982Smv143129 * sanity check. 22511982Smv143129 */ 22521982Smv143129 (void) sprintf(buf, handler_defined, handler); 22531982Smv143129 prom_interpret(buf, (uintptr_t)&defined, 0, 0, 0, 0); 22541982Smv143129 if (!defined) { 22551982Smv143129 cmn_err(CE_WARN, "master_interrupt_init: " 22561982Smv143129 "%s is not defined\n", handler); 22571982Smv143129 return (0); 22581982Smv143129 } 22591982Smv143129 22601982Smv143129 /* 22611982Smv143129 * Install the generic master-interrupt handler. Note that 22621982Smv143129 * this is only done one time on the first DR operation. 22631982Smv143129 * This is because, for OPL, one, single generic handler 22641982Smv143129 * handles all ports (Oberon and CMU channel) and all 22651982Smv143129 * interrupt sources within each port. 22661982Smv143129 * 22671982Smv143129 * The current support is only for the Oberon and CMU-channel. 22681982Smv143129 * If any others need to be supported, the handler has to be 22691982Smv143129 * modified accordingly. 22701982Smv143129 */ 22711982Smv143129 22721982Smv143129 /* 22731982Smv143129 * Define the OPL master interrupt handler 22741982Smv143129 */ 22751982Smv143129 prom_interpret(define_master_interrupt_handler, 0, 0, 0, 0, 0); 22761982Smv143129 22771982Smv143129 /* 22781982Smv143129 * Take over the master interrupt handler from OBP. 22791982Smv143129 */ 22801982Smv143129 prom_interpret(install_master_interrupt_handler, 0, 0, 0, 0, 0); 22811982Smv143129 22821982Smv143129 master_interrupt_inited = 1; 22831982Smv143129 22841982Smv143129 /* 22851982Smv143129 * prom_interpret() does not return a status. So, we assume 22861982Smv143129 * that the calls succeeded. In reality, the calls may fail 22871982Smv143129 * if there is a syntax error, etc in the strings. 22881982Smv143129 */ 22891982Smv143129 22901982Smv143129 return (1); 22911982Smv143129 } 22921982Smv143129 22931982Smv143129 /* 22941982Smv143129 * Install the master-interrupt handler for a device. 22951982Smv143129 */ 22961982Smv143129 static int 22971982Smv143129 opl_master_interrupt(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 22981982Smv143129 { 22991982Smv143129 uint32_t portid, xt; 23001982Smv143129 int board, channel, leaf; 23011982Smv143129 int status; 23021982Smv143129 23031982Smv143129 /* Check the argument */ 23041982Smv143129 if (fc_cell2int(cp->nargs) != 2) 23051982Smv143129 return (fc_syntax_error(cp, "nargs must be 2")); 23061982Smv143129 23071982Smv143129 if (fc_cell2int(cp->nresults) < 1) 23081982Smv143129 return (fc_syntax_error(cp, "nresults must be >= 1")); 23091982Smv143129 23101982Smv143129 /* Get the parameters */ 23111982Smv143129 portid = fc_cell2uint32_t(fc_arg(cp, 0)); 23121982Smv143129 xt = fc_cell2uint32_t(fc_arg(cp, 1)); 23131982Smv143129 23141982Smv143129 board = OPL_IO_PORTID_TO_LSB(portid); 23151982Smv143129 channel = OPL_PORTID_TO_CHANNEL(portid); 23161982Smv143129 leaf = OPL_PORTID_TO_LEAF(portid); 23171982Smv143129 23181982Smv143129 if ((board >= HWD_SBS_PER_DOMAIN) || !OPL_VALID_CHANNEL(channel) || 23191982Smv143129 (OPL_OBERON_CHANNEL(channel) && !OPL_VALID_LEAF(leaf)) || 23201982Smv143129 ((channel == OPL_CMU_CHANNEL) && (leaf != 0))) { 23211982Smv143129 FC_DEBUG1(1, CE_CONT, "opl_master_interrupt: invalid port %x\n", 23221982Smv143129 portid); 23231982Smv143129 status = 0; 23241982Smv143129 } else { 23251982Smv143129 status = master_interrupt_init(portid, xt); 23261982Smv143129 } 23271982Smv143129 23281982Smv143129 cp->nresults = fc_int2cell(1); 23291982Smv143129 fc_result(cp, 0) = status; 23301982Smv143129 23311982Smv143129 return (fc_success_op(ap, rp, cp)); 23321982Smv143129 } 23331982Smv143129 23341982Smv143129 /* 23351772Sjl139090 * Set the properties for a leaf node (Oberon leaf or CMU channel leaf). 23361772Sjl139090 */ 23371772Sjl139090 /*ARGSUSED*/ 23381772Sjl139090 static int 23391772Sjl139090 opl_create_leaf(dev_info_t *node, void *arg, uint_t flags) 23401772Sjl139090 { 23411772Sjl139090 int ret; 23421772Sjl139090 23431772Sjl139090 OPL_UPDATE_PROP(string, node, "name", OPL_PCI_LEAF_NODE); 23441772Sjl139090 23451772Sjl139090 OPL_UPDATE_PROP(string, node, "status", "okay"); 23461772Sjl139090 23471772Sjl139090 return (DDI_WALK_TERMINATE); 23481772Sjl139090 } 23491772Sjl139090 23501772Sjl139090 static char * 23511772Sjl139090 opl_get_probe_string(opl_probe_t *probe, int channel, int leaf) 23521772Sjl139090 { 23531772Sjl139090 char *probe_string; 23541772Sjl139090 int portid; 23551772Sjl139090 23561772Sjl139090 probe_string = kmem_zalloc(PROBE_STR_SIZE, KM_SLEEP); 23571772Sjl139090 23581772Sjl139090 if (channel == OPL_CMU_CHANNEL) 23591772Sjl139090 portid = probe->pr_sb->sb_cmu.cmu_ch.chan_portid; 23601772Sjl139090 else 23611772Sjl139090 portid = probe-> 23621772Sjl139090 pr_sb->sb_pci_ch[channel].pci_leaf[leaf].leaf_port_id; 23631772Sjl139090 23641772Sjl139090 (void) sprintf(probe_string, "%x", portid); 23651772Sjl139090 23661772Sjl139090 return (probe_string); 23671772Sjl139090 } 23681772Sjl139090 23691772Sjl139090 static int 23701772Sjl139090 opl_probe_leaf(opl_probe_t *probe) 23711772Sjl139090 { 23721772Sjl139090 int channel, leaf, portid, error, circ; 23731772Sjl139090 int board; 23741772Sjl139090 fco_handle_t fco_handle, *cfg_handle; 23751772Sjl139090 dev_info_t *parent, *leaf_node; 23761772Sjl139090 char unit_address[UNIT_ADDR_SIZE]; 23771772Sjl139090 char *probe_string; 23781772Sjl139090 opl_board_cfg_t *board_cfg; 23791772Sjl139090 23801772Sjl139090 board = probe->pr_board; 23811772Sjl139090 channel = probe->pr_channel; 23821772Sjl139090 leaf = probe->pr_leaf; 23831772Sjl139090 parent = ddi_root_node(); 23841772Sjl139090 board_cfg = &opl_boards[board]; 23851772Sjl139090 23861772Sjl139090 ASSERT(OPL_VALID_CHANNEL(channel)); 23871772Sjl139090 ASSERT(OPL_VALID_LEAF(leaf)); 23881772Sjl139090 23891772Sjl139090 if (channel == OPL_CMU_CHANNEL) { 23901772Sjl139090 portid = probe->pr_sb->sb_cmu.cmu_ch.chan_portid; 23911772Sjl139090 cfg_handle = &board_cfg->cfg_cmuch_handle; 23921772Sjl139090 } else { 23931772Sjl139090 portid = probe-> 23941772Sjl139090 pr_sb->sb_pci_ch[channel].pci_leaf[leaf].leaf_port_id; 23951772Sjl139090 cfg_handle = &board_cfg->cfg_pcich_handle[channel][leaf]; 23961772Sjl139090 } 23971772Sjl139090 23981772Sjl139090 /* 23991772Sjl139090 * Prevent any changes to leaf_node until we have bound 24001772Sjl139090 * it to the correct driver. 24011772Sjl139090 */ 24021772Sjl139090 ndi_devi_enter(parent, &circ); 24031772Sjl139090 24041772Sjl139090 /* 24051772Sjl139090 * Ideally, fcode would be run from the "sid_branch_create" 24061772Sjl139090 * callback (that is the primary purpose of that callback). 24071772Sjl139090 * However, the fcode interpreter was written with the 24081772Sjl139090 * assumption that the "new_child" was linked into the 24091772Sjl139090 * device tree. The callback is invoked with the devinfo node 24101772Sjl139090 * in the DS_PROTO state. More investigation is needed before 24111772Sjl139090 * we can invoke the interpreter from the callback. For now, 24121772Sjl139090 * we create the "new_child" in the BOUND state, invoke the 24131772Sjl139090 * fcode interpreter and then rebind the dip to use any 24141772Sjl139090 * compatible properties created by fcode. 24151772Sjl139090 */ 24161772Sjl139090 24171772Sjl139090 probe->pr_parent = parent; 24181772Sjl139090 probe->pr_create = opl_create_leaf; 24191772Sjl139090 probe->pr_hold = 1; 24201772Sjl139090 24211772Sjl139090 leaf_node = opl_create_node(probe); 24221772Sjl139090 if (leaf_node == NULL) { 24231772Sjl139090 24241772Sjl139090 cmn_err(CE_WARN, "IKP: create leaf (%d-%d-%d) failed", 24251772Sjl139090 probe->pr_board, probe->pr_channel, probe->pr_leaf); 24261772Sjl139090 ndi_devi_exit(parent, circ); 24271772Sjl139090 return (-1); 24281772Sjl139090 } 24291772Sjl139090 24301772Sjl139090 /* 24311772Sjl139090 * The platform DR interfaces created the dip in 24321772Sjl139090 * bound state. Bring devinfo node down to linked 24331772Sjl139090 * state and hold it there until compatible 24341772Sjl139090 * properties are created. 24351772Sjl139090 */ 24361772Sjl139090 e_ddi_branch_rele(leaf_node); 24371772Sjl139090 (void) i_ndi_unconfig_node(leaf_node, DS_LINKED, 0); 24381772Sjl139090 ASSERT(i_ddi_node_state(leaf_node) == DS_LINKED); 24391772Sjl139090 e_ddi_branch_hold(leaf_node); 24401772Sjl139090 24411772Sjl139090 mutex_enter(&DEVI(leaf_node)->devi_lock); 24421772Sjl139090 DEVI(leaf_node)->devi_flags |= DEVI_NO_BIND; 24431772Sjl139090 mutex_exit(&DEVI(leaf_node)->devi_lock); 24441772Sjl139090 24451772Sjl139090 /* 24461772Sjl139090 * Drop the busy-hold on parent before calling 24471772Sjl139090 * fcode_interpreter to prevent potential deadlocks 24481772Sjl139090 */ 24491772Sjl139090 ndi_devi_exit(parent, circ); 24501772Sjl139090 24511772Sjl139090 (void) sprintf(unit_address, "%x", portid); 24521772Sjl139090 24531772Sjl139090 /* 24541772Sjl139090 * Get the probe string 24551772Sjl139090 */ 24561772Sjl139090 probe_string = opl_get_probe_string(probe, channel, leaf); 24571772Sjl139090 24581772Sjl139090 /* 24591772Sjl139090 * The fcode pointer specified here is NULL and the fcode 24601772Sjl139090 * size specified here is 0. This causes the user-level 24611772Sjl139090 * fcode interpreter to issue a request to the fcode 24621772Sjl139090 * driver to get the Oberon/cmu-ch fcode. 24631772Sjl139090 */ 24641772Sjl139090 fco_handle = opl_fc_ops_alloc_handle(parent, leaf_node, 24651772Sjl139090 NULL, 0, unit_address, probe_string); 24661772Sjl139090 24671772Sjl139090 error = fcode_interpreter(parent, &opl_fc_do_op, fco_handle); 24681772Sjl139090 24691772Sjl139090 if (error != 0) { 24701772Sjl139090 cmn_err(CE_WARN, "IKP: Unable to probe PCI leaf (%d-%d-%d)", 24711772Sjl139090 probe->pr_board, probe->pr_channel, probe->pr_leaf); 24721772Sjl139090 24731772Sjl139090 opl_fc_ops_free_handle(fco_handle); 24741772Sjl139090 24751772Sjl139090 if (probe_string != NULL) 24761772Sjl139090 kmem_free(probe_string, PROBE_STR_SIZE); 24771772Sjl139090 24781772Sjl139090 (void) opl_destroy_node(leaf_node); 24791772Sjl139090 } else { 24801772Sjl139090 *cfg_handle = fco_handle; 24811772Sjl139090 24821772Sjl139090 if (channel == OPL_CMU_CHANNEL) 24831772Sjl139090 board_cfg->cfg_cmuch_probe_str = probe_string; 24841772Sjl139090 else 24851772Sjl139090 board_cfg->cfg_pcich_probe_str[channel][leaf] 24861772Sjl139090 = probe_string; 24871772Sjl139090 24881772Sjl139090 /* 24891772Sjl139090 * Compatible properties (if any) have been created, 24901772Sjl139090 * so bind driver. 24911772Sjl139090 */ 24921772Sjl139090 ndi_devi_enter(parent, &circ); 24931772Sjl139090 ASSERT(i_ddi_node_state(leaf_node) <= DS_LINKED); 24941772Sjl139090 24951772Sjl139090 mutex_enter(&DEVI(leaf_node)->devi_lock); 24961772Sjl139090 DEVI(leaf_node)->devi_flags &= ~DEVI_NO_BIND; 24971772Sjl139090 mutex_exit(&DEVI(leaf_node)->devi_lock); 24981772Sjl139090 24991772Sjl139090 ndi_devi_exit(parent, circ); 25001772Sjl139090 25011772Sjl139090 if (ndi_devi_bind_driver(leaf_node, 0) != 25021772Sjl139090 DDI_SUCCESS) { 25031772Sjl139090 cmn_err(CE_WARN, 25041772Sjl139090 "IKP: Unable to bind PCI leaf (%d-%d-%d)", 25051772Sjl139090 probe->pr_board, probe->pr_channel, 25061772Sjl139090 probe->pr_leaf); 25071772Sjl139090 } 25081772Sjl139090 } 25091772Sjl139090 25101772Sjl139090 if ((error != 0) && (channel == OPL_CMU_CHANNEL)) 25111772Sjl139090 return (-1); 25121772Sjl139090 25131772Sjl139090 return (0); 25141772Sjl139090 } 25151772Sjl139090 25161772Sjl139090 static void 25171772Sjl139090 opl_init_leaves(int myboard) 25181772Sjl139090 { 25191772Sjl139090 dev_info_t *parent, *node; 25201772Sjl139090 char *name; 25211772Sjl139090 int circ, ret; 25221772Sjl139090 int len, portid, board, channel, leaf; 25231772Sjl139090 opl_board_cfg_t *cfg; 25241772Sjl139090 25251772Sjl139090 parent = ddi_root_node(); 25261772Sjl139090 25271772Sjl139090 /* 25281772Sjl139090 * Hold parent node busy to walk its child list 25291772Sjl139090 */ 25301772Sjl139090 ndi_devi_enter(parent, &circ); 25311772Sjl139090 25321772Sjl139090 for (node = ddi_get_child(parent); 25331772Sjl139090 (node != NULL); 25341772Sjl139090 node = ddi_get_next_sibling(node)) { 25351772Sjl139090 25361772Sjl139090 ret = OPL_GET_PROP(string, node, "name", &name, &len); 25371772Sjl139090 if (ret != DDI_PROP_SUCCESS) { 25381772Sjl139090 /* 25391772Sjl139090 * The property does not exist for this node. 25401772Sjl139090 */ 25411772Sjl139090 continue; 25421772Sjl139090 } 25431772Sjl139090 25441772Sjl139090 if (strncmp(name, OPL_PCI_LEAF_NODE, len) == 0) { 25451772Sjl139090 25461772Sjl139090 ret = OPL_GET_PROP(int, node, "portid", &portid, -1); 25471772Sjl139090 if (ret == DDI_PROP_SUCCESS) { 25481772Sjl139090 25491772Sjl139090 ret = OPL_GET_PROP(int, node, "board#", 25501772Sjl139090 &board, -1); 25511772Sjl139090 if ((ret != DDI_PROP_SUCCESS) || 25523354Sjl139090 (board != myboard)) { 25533354Sjl139090 kmem_free(name, len); 25541772Sjl139090 continue; 25553354Sjl139090 } 25561772Sjl139090 25571772Sjl139090 cfg = &opl_boards[board]; 25581772Sjl139090 channel = OPL_PORTID_TO_CHANNEL(portid); 25591772Sjl139090 if (channel == OPL_CMU_CHANNEL) { 25601772Sjl139090 25611772Sjl139090 if (cfg->cfg_cmuch_handle != NULL) 25621772Sjl139090 cfg->cfg_cmuch_leaf = node; 25631772Sjl139090 25641772Sjl139090 } else { 25651772Sjl139090 25661772Sjl139090 leaf = OPL_PORTID_TO_LEAF(portid); 25671772Sjl139090 if (cfg->cfg_pcich_handle 25681772Sjl139090 [channel][leaf] != NULL) 25691772Sjl139090 cfg->cfg_pcich_leaf 25701772Sjl139090 [channel][leaf] = node; 25711772Sjl139090 } 25721772Sjl139090 } 25731772Sjl139090 } 25741772Sjl139090 25751772Sjl139090 kmem_free(name, len); 25761772Sjl139090 if (ret != DDI_PROP_SUCCESS) 25771772Sjl139090 break; 25781772Sjl139090 } 25791772Sjl139090 25801772Sjl139090 ndi_devi_exit(parent, circ); 25811772Sjl139090 } 25821772Sjl139090 25831772Sjl139090 /* 25841772Sjl139090 * Create "pci" node and hierarchy for the Oberon channels and the 25851772Sjl139090 * CMU channel. 25861772Sjl139090 */ 25871772Sjl139090 /*ARGSUSED*/ 25881772Sjl139090 static int 25891772Sjl139090 opl_probe_io(opl_probe_t *probe) 25901772Sjl139090 { 25911772Sjl139090 25921772Sjl139090 int i, j; 25931772Sjl139090 hwd_pci_ch_t *channels; 25941772Sjl139090 25951772Sjl139090 if (HWD_STATUS_OK(probe->pr_sb->sb_cmu.cmu_ch.chan_status)) { 25961772Sjl139090 25971772Sjl139090 probe->pr_channel = HWD_CMU_CHANNEL; 25981772Sjl139090 probe->pr_channel_status = 25991772Sjl139090 probe->pr_sb->sb_cmu.cmu_ch.chan_status; 26001772Sjl139090 probe->pr_leaf = 0; 26011772Sjl139090 probe->pr_leaf_status = probe->pr_channel_status; 26021772Sjl139090 26031772Sjl139090 if (opl_probe_leaf(probe) != 0) 26041772Sjl139090 return (-1); 26051772Sjl139090 } 26061772Sjl139090 26071772Sjl139090 channels = &probe->pr_sb->sb_pci_ch[0]; 26081772Sjl139090 26091772Sjl139090 for (i = 0; i < HWD_PCI_CHANNELS_PER_SB; i++) { 26101772Sjl139090 26111772Sjl139090 if (!HWD_STATUS_OK(channels[i].pci_status)) 26121772Sjl139090 continue; 26131772Sjl139090 26141772Sjl139090 probe->pr_channel = i; 26151772Sjl139090 probe->pr_channel_status = channels[i].pci_status; 26161772Sjl139090 26171772Sjl139090 for (j = 0; j < HWD_LEAVES_PER_PCI_CHANNEL; j++) { 26181772Sjl139090 26191772Sjl139090 probe->pr_leaf = j; 26201772Sjl139090 probe->pr_leaf_status = 26211772Sjl139090 channels[i].pci_leaf[j].leaf_status; 26221772Sjl139090 26231772Sjl139090 if (!HWD_STATUS_OK(probe->pr_leaf_status)) 26241772Sjl139090 continue; 26251772Sjl139090 26261772Sjl139090 (void) opl_probe_leaf(probe); 26271772Sjl139090 } 26281772Sjl139090 } 26291772Sjl139090 opl_init_leaves(probe->pr_board); 26301772Sjl139090 return (0); 26311772Sjl139090 } 26321772Sjl139090 26331772Sjl139090 /* 26341772Sjl139090 * Perform the probe in the following order: 26351772Sjl139090 * 26361772Sjl139090 * processors 26371772Sjl139090 * memory 26381772Sjl139090 * IO 26391772Sjl139090 * 26401772Sjl139090 * Each probe function returns 0 on sucess and a non-zero value on failure. 26411772Sjl139090 * What is a failure is determined by the implementor of the probe function. 26421772Sjl139090 * For example, while probing CPUs, any error encountered during probe 26431772Sjl139090 * is considered a failure and causes the whole probe operation to fail. 26441772Sjl139090 * However, for I/O, an error encountered while probing one device 26451772Sjl139090 * should not prevent other devices from being probed. It should not cause 26461772Sjl139090 * the whole probe operation to fail. 26471772Sjl139090 */ 26481772Sjl139090 int 26491772Sjl139090 opl_probe_sb(int board) 26501772Sjl139090 { 26511772Sjl139090 opl_probe_t *probe; 26521772Sjl139090 int ret; 26531772Sjl139090 26541772Sjl139090 if ((board < 0) || (board >= HWD_SBS_PER_DOMAIN)) 26551772Sjl139090 return (-1); 26561772Sjl139090 26571772Sjl139090 ASSERT(opl_cfg_inited != 0); 26581772Sjl139090 26591772Sjl139090 /* 26601772Sjl139090 * If the previous probe failed and left a partially configured 26611772Sjl139090 * board, we need to unprobe the board and start with a clean slate. 26621772Sjl139090 */ 26631772Sjl139090 if ((opl_boards[board].cfg_hwd != NULL) && 26641772Sjl139090 (opl_unprobe_sb(board) != 0)) 26651772Sjl139090 return (-1); 26661772Sjl139090 26671772Sjl139090 ret = 0; 26681772Sjl139090 26691772Sjl139090 probe = kmem_zalloc(sizeof (opl_probe_t), KM_SLEEP); 26701772Sjl139090 probe->pr_board = board; 26711772Sjl139090 26721772Sjl139090 if ((opl_probe_init(probe) != 0) || 26731772Sjl139090 26741772Sjl139090 (opl_probe_cpu_chips(probe) != 0) || 26751772Sjl139090 26761772Sjl139090 (opl_probe_memory(probe) != 0) || 26771772Sjl139090 26781772Sjl139090 (opl_probe_io(probe) != 0)) { 26791772Sjl139090 26801772Sjl139090 /* 26811772Sjl139090 * Probe failed. Perform cleanup. 26821772Sjl139090 */ 26831772Sjl139090 (void) opl_unprobe_sb(board); 26841772Sjl139090 ret = -1; 26851772Sjl139090 } 26861772Sjl139090 26871772Sjl139090 kmem_free(probe, sizeof (opl_probe_t)); 26881772Sjl139090 26891772Sjl139090 return (ret); 26901772Sjl139090 } 26911772Sjl139090 26921772Sjl139090 /* 26931772Sjl139090 * This unprobing also includes CMU-CH. 26941772Sjl139090 */ 26951772Sjl139090 /*ARGSUSED*/ 26961772Sjl139090 static int 26971772Sjl139090 opl_unprobe_io(int board) 26981772Sjl139090 { 26991772Sjl139090 int i, j, ret; 27001772Sjl139090 opl_board_cfg_t *board_cfg; 27011772Sjl139090 dev_info_t **node; 27021772Sjl139090 fco_handle_t *hand; 27031772Sjl139090 char **probe_str; 27041772Sjl139090 27051772Sjl139090 board_cfg = &opl_boards[board]; 27061772Sjl139090 27071772Sjl139090 for (i = 0; i < HWD_PCI_CHANNELS_PER_SB; i++) { 27081772Sjl139090 27091772Sjl139090 for (j = 0; j < HWD_LEAVES_PER_PCI_CHANNEL; j++) { 27101772Sjl139090 27111772Sjl139090 node = &board_cfg->cfg_pcich_leaf[i][j]; 27121772Sjl139090 hand = &board_cfg->cfg_pcich_handle[i][j]; 27131772Sjl139090 probe_str = &board_cfg->cfg_pcich_probe_str[i][j]; 27141772Sjl139090 27151772Sjl139090 if (*node == NULL) 27161772Sjl139090 continue; 27171772Sjl139090 27181772Sjl139090 if (*hand != NULL) { 27191772Sjl139090 opl_fc_ops_free_handle(*hand); 27201772Sjl139090 *hand = NULL; 27211772Sjl139090 } 27221772Sjl139090 27231772Sjl139090 if (*probe_str != NULL) { 27241772Sjl139090 kmem_free(*probe_str, PROBE_STR_SIZE); 27251772Sjl139090 *probe_str = NULL; 27261772Sjl139090 } 27271772Sjl139090 27281772Sjl139090 ret = opl_destroy_node(*node); 27291772Sjl139090 if (ret != 0) { 27301772Sjl139090 27311772Sjl139090 cmn_err(CE_WARN, 27321772Sjl139090 "IKP: destroy pci (%d-%d-%d) failed", 27331772Sjl139090 board, i, j); 27341772Sjl139090 return (-1); 27351772Sjl139090 } 27361772Sjl139090 27371772Sjl139090 *node = NULL; 27381772Sjl139090 27391772Sjl139090 } 27401772Sjl139090 } 27411772Sjl139090 27421772Sjl139090 node = &board_cfg->cfg_cmuch_leaf; 27431772Sjl139090 hand = &board_cfg->cfg_cmuch_handle; 27441772Sjl139090 probe_str = &board_cfg->cfg_cmuch_probe_str; 27451772Sjl139090 27461772Sjl139090 if (*node == NULL) 27471772Sjl139090 return (0); 27481772Sjl139090 27491772Sjl139090 if (*hand != NULL) { 27501772Sjl139090 opl_fc_ops_free_handle(*hand); 27511772Sjl139090 *hand = NULL; 27521772Sjl139090 } 27531772Sjl139090 27541772Sjl139090 if (*probe_str != NULL) { 27551772Sjl139090 kmem_free(*probe_str, PROBE_STR_SIZE); 27561772Sjl139090 *probe_str = NULL; 27571772Sjl139090 } 27581772Sjl139090 27591772Sjl139090 if (opl_destroy_node(*node) != 0) { 27601772Sjl139090 27611772Sjl139090 cmn_err(CE_WARN, "IKP: destroy pci (%d-%d-%d) failed", 27621772Sjl139090 board, OPL_CMU_CHANNEL, 0); 27631772Sjl139090 return (-1); 27641772Sjl139090 } 27651772Sjl139090 27661772Sjl139090 *node = NULL; 27671772Sjl139090 27681772Sjl139090 return (0); 27691772Sjl139090 } 27701772Sjl139090 27711772Sjl139090 /* 27721772Sjl139090 * Destroy the "pseudo-mc" node for a board. 27731772Sjl139090 */ 27741772Sjl139090 static int 27751772Sjl139090 opl_unprobe_memory(int board) 27761772Sjl139090 { 27771772Sjl139090 opl_board_cfg_t *board_cfg; 27781772Sjl139090 27791772Sjl139090 board_cfg = &opl_boards[board]; 27801772Sjl139090 27811772Sjl139090 if (board_cfg->cfg_pseudo_mc == NULL) 27821772Sjl139090 return (0); 27831772Sjl139090 27841772Sjl139090 if (opl_destroy_node(board_cfg->cfg_pseudo_mc) != 0) { 27851772Sjl139090 27861772Sjl139090 cmn_err(CE_WARN, "IKP: destroy pseudo-mc (%d) failed", board); 27871772Sjl139090 return (-1); 27881772Sjl139090 } 27891772Sjl139090 27901772Sjl139090 board_cfg->cfg_pseudo_mc = NULL; 27911772Sjl139090 27921772Sjl139090 return (0); 27931772Sjl139090 } 27941772Sjl139090 27951772Sjl139090 /* 27961772Sjl139090 * Destroy the "cmp" nodes for a board. This also destroys the "core" 27971772Sjl139090 * and "cpu" nodes below the "cmp" nodes. 27981772Sjl139090 */ 27991772Sjl139090 static int 28001772Sjl139090 opl_unprobe_processors(int board) 28011772Sjl139090 { 28021772Sjl139090 int i; 28031772Sjl139090 dev_info_t **cfg_cpu_chips; 28041772Sjl139090 28051772Sjl139090 cfg_cpu_chips = opl_boards[board].cfg_cpu_chips; 28061772Sjl139090 28071772Sjl139090 for (i = 0; i < HWD_CPU_CHIPS_PER_CMU; i++) { 28081772Sjl139090 28091772Sjl139090 if (cfg_cpu_chips[i] == NULL) 28101772Sjl139090 continue; 28111772Sjl139090 28121772Sjl139090 if (opl_destroy_node(cfg_cpu_chips[i]) != 0) { 28131772Sjl139090 28141772Sjl139090 cmn_err(CE_WARN, 28151772Sjl139090 "IKP: destroy chip (%d-%d) failed", board, i); 28161772Sjl139090 return (-1); 28171772Sjl139090 } 28181772Sjl139090 28191772Sjl139090 cfg_cpu_chips[i] = NULL; 28201772Sjl139090 } 28211772Sjl139090 28221772Sjl139090 return (0); 28231772Sjl139090 } 28241772Sjl139090 28251772Sjl139090 /* 28261772Sjl139090 * Perform the unprobe in the following order: 28271772Sjl139090 * 28281772Sjl139090 * IO 28291772Sjl139090 * memory 28301772Sjl139090 * processors 28311772Sjl139090 */ 28321772Sjl139090 int 28331772Sjl139090 opl_unprobe_sb(int board) 28341772Sjl139090 { 28351772Sjl139090 if ((board < 0) || (board >= HWD_SBS_PER_DOMAIN)) 28361772Sjl139090 return (-1); 28371772Sjl139090 28381772Sjl139090 ASSERT(opl_cfg_inited != 0); 28391772Sjl139090 28401772Sjl139090 if ((opl_unprobe_io(board) != 0) || 28411772Sjl139090 28421772Sjl139090 (opl_unprobe_memory(board) != 0) || 28431772Sjl139090 28441772Sjl139090 (opl_unprobe_processors(board) != 0)) 28451772Sjl139090 28461772Sjl139090 return (-1); 28471772Sjl139090 28481772Sjl139090 if (opl_boards[board].cfg_hwd != NULL) { 28491772Sjl139090 #ifdef UCTEST 28501772Sjl139090 size_t size = 0xA000; 28511772Sjl139090 #endif 28521772Sjl139090 /* Release the memory for the HWD */ 28531772Sjl139090 void *hwdp = opl_boards[board].cfg_hwd; 28541772Sjl139090 opl_boards[board].cfg_hwd = NULL; 28551772Sjl139090 #ifdef UCTEST 28561772Sjl139090 hwdp = (void *)((char *)hwdp - 0x1000); 28571772Sjl139090 hat_unload(kas.a_hat, hwdp, size, HAT_UNLOAD_UNLOCK); 28581772Sjl139090 vmem_free(heap_arena, hwdp, size); 28591772Sjl139090 #else 28601772Sjl139090 kmem_free(hwdp, HWD_DATA_SIZE); 28611772Sjl139090 #endif 28621772Sjl139090 } 28631772Sjl139090 return (0); 28641772Sjl139090 } 28651772Sjl139090 28661772Sjl139090 /* 28671772Sjl139090 * For MAC patrol support, we need to update the PA-related properties 28681772Sjl139090 * when there is a copy-rename event. This should be called after the 28691772Sjl139090 * physical copy and rename has been done by DR, and before the MAC 28701772Sjl139090 * patrol is restarted. 28711772Sjl139090 */ 28721772Sjl139090 int 28731772Sjl139090 oplcfg_pa_swap(int from, int to) 28741772Sjl139090 { 28751772Sjl139090 dev_info_t *from_node = opl_boards[from].cfg_pseudo_mc; 28761772Sjl139090 dev_info_t *to_node = opl_boards[to].cfg_pseudo_mc; 28771772Sjl139090 opl_range_t *rangef, *ranget; 28781772Sjl139090 int elems; 28791772Sjl139090 int ret; 28801772Sjl139090 28811772Sjl139090 if ((OPL_GET_PROP_ARRAY(int, from_node, "sb-mem-ranges", rangef, 28821772Sjl139090 elems) != DDI_SUCCESS) || (elems != 4)) { 28831772Sjl139090 /* XXX -- bad news */ 28841772Sjl139090 return (-1); 28851772Sjl139090 } 28861772Sjl139090 if ((OPL_GET_PROP_ARRAY(int, to_node, "sb-mem-ranges", ranget, 28871772Sjl139090 elems) != DDI_SUCCESS) || (elems != 4)) { 28881772Sjl139090 /* XXX -- bad news */ 28891772Sjl139090 return (-1); 28901772Sjl139090 } 28911772Sjl139090 OPL_UPDATE_PROP_ARRAY(int, from_node, "sb-mem-ranges", (int *)ranget, 28921772Sjl139090 4); 28931772Sjl139090 OPL_UPDATE_PROP_ARRAY(int, to_node, "sb-mem-ranges", (int *)rangef, 28941772Sjl139090 4); 28951772Sjl139090 28961772Sjl139090 OPL_FREE_PROP(ranget); 28971772Sjl139090 OPL_FREE_PROP(rangef); 28981772Sjl139090 28991772Sjl139090 return (0); 29001772Sjl139090 } 2901