125cf1a30Sjl139090 /* 225cf1a30Sjl139090 * CDDL HEADER START 325cf1a30Sjl139090 * 425cf1a30Sjl139090 * The contents of this file are subject to the terms of the 525cf1a30Sjl139090 * Common Development and Distribution License (the "License"). 625cf1a30Sjl139090 * You may not use this file except in compliance with the License. 725cf1a30Sjl139090 * 825cf1a30Sjl139090 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 925cf1a30Sjl139090 * or http://www.opensolaris.org/os/licensing. 1025cf1a30Sjl139090 * See the License for the specific language governing permissions 1125cf1a30Sjl139090 * and limitations under the License. 1225cf1a30Sjl139090 * 1325cf1a30Sjl139090 * When distributing Covered Code, include this CDDL HEADER in each 1425cf1a30Sjl139090 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1525cf1a30Sjl139090 * If applicable, add the following below this CDDL HEADER, with the 1625cf1a30Sjl139090 * fields enclosed by brackets "[]" replaced with your own identifying 1725cf1a30Sjl139090 * information: Portions Copyright [yyyy] [name of copyright owner] 1825cf1a30Sjl139090 * 1925cf1a30Sjl139090 * CDDL HEADER END 2025cf1a30Sjl139090 */ 2125cf1a30Sjl139090 /* 2288294e09SRichard Bean * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 2325cf1a30Sjl139090 * Use is subject to license terms. 24*48bbca81SDaniel Hoffman * Copyright (c) 2016 by Delphix. All rights reserved. 2525cf1a30Sjl139090 */ 2625cf1a30Sjl139090 2725cf1a30Sjl139090 #include <sys/conf.h> 2825cf1a30Sjl139090 #include <sys/kmem.h> 2925cf1a30Sjl139090 #include <sys/debug.h> 3025cf1a30Sjl139090 #include <sys/modctl.h> 3125cf1a30Sjl139090 #include <sys/autoconf.h> 3225cf1a30Sjl139090 #include <sys/hwconf.h> 3325cf1a30Sjl139090 #include <sys/ddi_impldefs.h> 3425cf1a30Sjl139090 #include <sys/ddi.h> 3525cf1a30Sjl139090 #include <sys/sunddi.h> 3625cf1a30Sjl139090 #include <sys/sunndi.h> 3725cf1a30Sjl139090 #include <sys/ndi_impldefs.h> 3825cf1a30Sjl139090 #include <sys/machsystm.h> 3925cf1a30Sjl139090 #include <sys/fcode.h> 4025cf1a30Sjl139090 #include <sys/promif.h> 4125cf1a30Sjl139090 #include <sys/promimpl.h> 4225cf1a30Sjl139090 #include <sys/opl_cfg.h> 4325cf1a30Sjl139090 #include <sys/scfd/scfostoescf.h> 4425cf1a30Sjl139090 4525cf1a30Sjl139090 static unsigned int opl_cfg_inited; 4625cf1a30Sjl139090 static opl_board_cfg_t opl_boards[HWD_SBS_PER_DOMAIN]; 4725cf1a30Sjl139090 4825cf1a30Sjl139090 /* 4925cf1a30Sjl139090 * Module control operations 5025cf1a30Sjl139090 */ 5125cf1a30Sjl139090 5225cf1a30Sjl139090 extern struct mod_ops mod_miscops; 5325cf1a30Sjl139090 5425cf1a30Sjl139090 static struct modlmisc modlmisc = { 5525cf1a30Sjl139090 &mod_miscops, /* Type of module */ 5688294e09SRichard Bean "OPL opl_cfg" 5725cf1a30Sjl139090 }; 5825cf1a30Sjl139090 5925cf1a30Sjl139090 static struct modlinkage modlinkage = { 6025cf1a30Sjl139090 MODREV_1, (void *)&modlmisc, NULL 6125cf1a30Sjl139090 }; 6225cf1a30Sjl139090 6325cf1a30Sjl139090 static int opl_map_in(dev_info_t *, fco_handle_t, fc_ci_t *); 6425cf1a30Sjl139090 static int opl_map_out(dev_info_t *, fco_handle_t, fc_ci_t *); 6525cf1a30Sjl139090 static int opl_register_fetch(dev_info_t *, fco_handle_t, fc_ci_t *); 6625cf1a30Sjl139090 static int opl_register_store(dev_info_t *, fco_handle_t, fc_ci_t *); 6725cf1a30Sjl139090 6825cf1a30Sjl139090 static int opl_claim_memory(dev_info_t *, fco_handle_t, fc_ci_t *); 6925cf1a30Sjl139090 static int opl_release_memory(dev_info_t *, fco_handle_t, fc_ci_t *); 7025cf1a30Sjl139090 static int opl_vtop(dev_info_t *, fco_handle_t, fc_ci_t *); 7125cf1a30Sjl139090 7225cf1a30Sjl139090 static int opl_config_child(dev_info_t *, fco_handle_t, fc_ci_t *); 7325cf1a30Sjl139090 7425cf1a30Sjl139090 static int opl_get_fcode_size(dev_info_t *, fco_handle_t, fc_ci_t *); 7525cf1a30Sjl139090 static int opl_get_fcode(dev_info_t *, fco_handle_t, fc_ci_t *); 7625cf1a30Sjl139090 7725cf1a30Sjl139090 static int opl_map_phys(dev_info_t *, struct regspec *, caddr_t *, 7825cf1a30Sjl139090 ddi_device_acc_attr_t *, ddi_acc_handle_t *); 7925cf1a30Sjl139090 static void opl_unmap_phys(ddi_acc_handle_t *); 8025cf1a30Sjl139090 static int opl_get_hwd_va(dev_info_t *, fco_handle_t, fc_ci_t *); 8153123245Smv143129 static int opl_master_interrupt(dev_info_t *, fco_handle_t, fc_ci_t *); 8225cf1a30Sjl139090 8325cf1a30Sjl139090 extern int prom_get_fcode_size(char *); 8425cf1a30Sjl139090 extern int prom_get_fcode(char *, char *); 8525cf1a30Sjl139090 8653123245Smv143129 static int master_interrupt_init(uint32_t, uint32_t); 8753123245Smv143129 8825cf1a30Sjl139090 #define PROBE_STR_SIZE 64 8925cf1a30Sjl139090 #define UNIT_ADDR_SIZE 64 9025cf1a30Sjl139090 9125cf1a30Sjl139090 opl_fc_ops_t opl_fc_ops[] = { 9225cf1a30Sjl139090 9325cf1a30Sjl139090 { FC_MAP_IN, opl_map_in}, 9425cf1a30Sjl139090 { FC_MAP_OUT, opl_map_out}, 9525cf1a30Sjl139090 { "rx@", opl_register_fetch}, 9625cf1a30Sjl139090 { FC_RL_FETCH, opl_register_fetch}, 9725cf1a30Sjl139090 { FC_RW_FETCH, opl_register_fetch}, 9825cf1a30Sjl139090 { FC_RB_FETCH, opl_register_fetch}, 9925cf1a30Sjl139090 { "rx!", opl_register_store}, 10025cf1a30Sjl139090 { FC_RL_STORE, opl_register_store}, 10125cf1a30Sjl139090 { FC_RW_STORE, opl_register_store}, 10225cf1a30Sjl139090 { FC_RB_STORE, opl_register_store}, 10325cf1a30Sjl139090 { "claim-memory", opl_claim_memory}, 10425cf1a30Sjl139090 { "release-memory", opl_release_memory}, 10525cf1a30Sjl139090 { "vtop", opl_vtop}, 10625cf1a30Sjl139090 { FC_CONFIG_CHILD, opl_config_child}, 10725cf1a30Sjl139090 { FC_GET_FCODE_SIZE, opl_get_fcode_size}, 10825cf1a30Sjl139090 { FC_GET_FCODE, opl_get_fcode}, 10925cf1a30Sjl139090 { "get-hwd-va", opl_get_hwd_va}, 11053123245Smv143129 { "master-interrupt", opl_master_interrupt}, 11125cf1a30Sjl139090 { NULL, NULL} 11225cf1a30Sjl139090 11325cf1a30Sjl139090 }; 11425cf1a30Sjl139090 11525cf1a30Sjl139090 extern caddr_t efcode_vaddr; 11625cf1a30Sjl139090 extern int efcode_size; 11725cf1a30Sjl139090 11825cf1a30Sjl139090 #ifdef DEBUG 11925cf1a30Sjl139090 #define HWDDUMP_OFFSETS 1 12025cf1a30Sjl139090 #define HWDDUMP_ALL_STATUS 2 12125cf1a30Sjl139090 #define HWDDUMP_CHUNKS 3 12225cf1a30Sjl139090 #define HWDDUMP_SBP 4 12325cf1a30Sjl139090 12425cf1a30Sjl139090 int hwddump_flags = HWDDUMP_SBP | HWDDUMP_CHUNKS; 12525cf1a30Sjl139090 #endif 12625cf1a30Sjl139090 12753123245Smv143129 static int master_interrupt_inited = 0; 12853123245Smv143129 12925cf1a30Sjl139090 int 13025cf1a30Sjl139090 _init() 13125cf1a30Sjl139090 { 13225cf1a30Sjl139090 int err = 0; 13325cf1a30Sjl139090 13425cf1a30Sjl139090 /* 13525cf1a30Sjl139090 * Create a resource map for the contiguous memory allocated 13625cf1a30Sjl139090 * at start-of-day in startup.c 13725cf1a30Sjl139090 */ 13825cf1a30Sjl139090 err = ndi_ra_map_setup(ddi_root_node(), "opl-fcodemem"); 13925cf1a30Sjl139090 if (err == NDI_FAILURE) { 14025cf1a30Sjl139090 cmn_err(CE_WARN, "Cannot setup resource map opl-fcodemem\n"); 14125cf1a30Sjl139090 return (1); 14225cf1a30Sjl139090 } 14325cf1a30Sjl139090 14425cf1a30Sjl139090 /* 14525cf1a30Sjl139090 * Put the allocated memory into the pool. 14625cf1a30Sjl139090 */ 14725cf1a30Sjl139090 (void) ndi_ra_free(ddi_root_node(), (uint64_t)efcode_vaddr, 14825cf1a30Sjl139090 (uint64_t)efcode_size, "opl-fcodemem", 0); 14925cf1a30Sjl139090 15025cf1a30Sjl139090 if ((err = mod_install(&modlinkage)) != 0) { 15125cf1a30Sjl139090 cmn_err(CE_WARN, "opl_cfg failed to load, error=%d", err); 15225cf1a30Sjl139090 (void) ndi_ra_map_destroy(ddi_root_node(), "opl-fcodemem"); 15325cf1a30Sjl139090 } 15425cf1a30Sjl139090 15525cf1a30Sjl139090 return (err); 15625cf1a30Sjl139090 } 15725cf1a30Sjl139090 15825cf1a30Sjl139090 int 15925cf1a30Sjl139090 _fini(void) 16025cf1a30Sjl139090 { 16125cf1a30Sjl139090 int ret; 16225cf1a30Sjl139090 16325cf1a30Sjl139090 ret = (mod_remove(&modlinkage)); 16425cf1a30Sjl139090 if (ret != 0) 16525cf1a30Sjl139090 return (ret); 16625cf1a30Sjl139090 16725cf1a30Sjl139090 (void) ndi_ra_map_destroy(ddi_root_node(), "opl-fcodemem"); 16825cf1a30Sjl139090 16925cf1a30Sjl139090 return (ret); 17025cf1a30Sjl139090 } 17125cf1a30Sjl139090 17225cf1a30Sjl139090 int 17325cf1a30Sjl139090 _info(modinfop) 17425cf1a30Sjl139090 struct modinfo *modinfop; 17525cf1a30Sjl139090 { 17625cf1a30Sjl139090 return (mod_info(&modlinkage, modinfop)); 17725cf1a30Sjl139090 } 17825cf1a30Sjl139090 17925cf1a30Sjl139090 #ifdef DEBUG 18025cf1a30Sjl139090 static void 18125cf1a30Sjl139090 opl_dump_hwd(opl_probe_t *probe) 18225cf1a30Sjl139090 { 18325cf1a30Sjl139090 hwd_header_t *hdrp; 18425cf1a30Sjl139090 hwd_sb_status_t *statp; 18525cf1a30Sjl139090 hwd_domain_info_t *dinfop; 18625cf1a30Sjl139090 hwd_sb_t *sbp; 18725cf1a30Sjl139090 hwd_cpu_chip_t *chips; 18825cf1a30Sjl139090 hwd_pci_ch_t *channels; 18925cf1a30Sjl139090 int board, i, status; 19025cf1a30Sjl139090 19125cf1a30Sjl139090 board = probe->pr_board; 19225cf1a30Sjl139090 19325cf1a30Sjl139090 hdrp = probe->pr_hdr; 19425cf1a30Sjl139090 statp = probe->pr_sb_status; 19525cf1a30Sjl139090 dinfop = probe->pr_dinfo; 19625cf1a30Sjl139090 sbp = probe->pr_sb; 19725cf1a30Sjl139090 19825cf1a30Sjl139090 printf("HWD: board %d\n", board); 19925cf1a30Sjl139090 printf("HWD:magic = 0x%x\n", hdrp->hdr_magic); 20025cf1a30Sjl139090 printf("HWD:version = 0x%x.%x\n", hdrp->hdr_version.major, 20125cf1a30Sjl139090 hdrp->hdr_version.minor); 20225cf1a30Sjl139090 20325cf1a30Sjl139090 if (hwddump_flags & HWDDUMP_OFFSETS) { 20425cf1a30Sjl139090 printf("HWD:status offset = 0x%x\n", 20525cf1a30Sjl139090 hdrp->hdr_sb_status_offset); 20625cf1a30Sjl139090 printf("HWD:domain offset = 0x%x\n", 20725cf1a30Sjl139090 hdrp->hdr_domain_info_offset); 20825cf1a30Sjl139090 printf("HWD:board offset = 0x%x\n", hdrp->hdr_sb_info_offset); 20925cf1a30Sjl139090 } 21025cf1a30Sjl139090 21125cf1a30Sjl139090 if (hwddump_flags & HWDDUMP_SBP) 21225cf1a30Sjl139090 printf("HWD:sb_t ptr = 0x%p\n", (void *)probe->pr_sb); 21325cf1a30Sjl139090 21425cf1a30Sjl139090 if (hwddump_flags & HWDDUMP_ALL_STATUS) { 21525cf1a30Sjl139090 int bd; 21625cf1a30Sjl139090 printf("HWD:board status ="); 21725cf1a30Sjl139090 for (bd = 0; bd < HWD_SBS_PER_DOMAIN; bd++) 21825cf1a30Sjl139090 printf("%x ", statp->sb_status[bd]); 21925cf1a30Sjl139090 printf("\n"); 22025cf1a30Sjl139090 } else { 22125cf1a30Sjl139090 printf("HWD:board status = %d\n", statp->sb_status[board]); 22225cf1a30Sjl139090 } 22325cf1a30Sjl139090 22425cf1a30Sjl139090 printf("HWD:banner name = %s\n", dinfop->dinf_banner_name); 22525cf1a30Sjl139090 printf("HWD:platform = %s\n", dinfop->dinf_platform_token); 22625cf1a30Sjl139090 22725cf1a30Sjl139090 printf("HWD:chip status:\n"); 22825cf1a30Sjl139090 chips = &sbp->sb_cmu.cmu_cpu_chips[0]; 22925cf1a30Sjl139090 for (i = 0; i < HWD_CPU_CHIPS_PER_CMU; i++) { 23025cf1a30Sjl139090 23125cf1a30Sjl139090 status = chips[i].chip_status; 23225cf1a30Sjl139090 printf("chip[%d] = ", i); 23325cf1a30Sjl139090 if (HWD_STATUS_NONE(status)) 23425cf1a30Sjl139090 printf("none"); 23525cf1a30Sjl139090 else if (HWD_STATUS_FAILED(status)) 23625cf1a30Sjl139090 printf("fail"); 23725cf1a30Sjl139090 else if (HWD_STATUS_OK(status)) 23825cf1a30Sjl139090 printf("ok"); 23925cf1a30Sjl139090 printf("\n"); 24025cf1a30Sjl139090 } 24125cf1a30Sjl139090 24225cf1a30Sjl139090 if (hwddump_flags & HWDDUMP_CHUNKS) { 24325cf1a30Sjl139090 int chunk; 24425cf1a30Sjl139090 hwd_memory_t *mem = &sbp->sb_cmu.cmu_memory; 24525cf1a30Sjl139090 printf("HWD:chunks:\n"); 24625cf1a30Sjl139090 for (chunk = 0; chunk < HWD_MAX_MEM_CHUNKS; chunk++) 24725cf1a30Sjl139090 printf("\t%d 0x%lx 0x%lx\n", chunk, 24825cf1a30Sjl139090 mem->mem_chunks[chunk].chnk_start_address, 24925cf1a30Sjl139090 mem->mem_chunks[chunk].chnk_size); 25025cf1a30Sjl139090 } 25125cf1a30Sjl139090 25225cf1a30Sjl139090 printf("HWD:channel status:\n"); 25325cf1a30Sjl139090 channels = &sbp->sb_pci_ch[0]; 25425cf1a30Sjl139090 for (i = 0; i < HWD_PCI_CHANNELS_PER_SB; i++) { 25525cf1a30Sjl139090 25625cf1a30Sjl139090 status = channels[i].pci_status; 25725cf1a30Sjl139090 printf("channels[%d] = ", i); 25825cf1a30Sjl139090 if (HWD_STATUS_NONE(status)) 25925cf1a30Sjl139090 printf("none"); 26025cf1a30Sjl139090 else if (HWD_STATUS_FAILED(status)) 26125cf1a30Sjl139090 printf("fail"); 26225cf1a30Sjl139090 else if (HWD_STATUS_OK(status)) 26325cf1a30Sjl139090 printf("ok"); 26425cf1a30Sjl139090 printf("\n"); 26525cf1a30Sjl139090 } 26625cf1a30Sjl139090 printf("channels[%d] = ", i); 26725cf1a30Sjl139090 status = sbp->sb_cmu.cmu_ch.chan_status; 26825cf1a30Sjl139090 if (HWD_STATUS_NONE(status)) 26925cf1a30Sjl139090 printf("none"); 27025cf1a30Sjl139090 else if (HWD_STATUS_FAILED(status)) 27125cf1a30Sjl139090 printf("fail"); 27225cf1a30Sjl139090 else if (HWD_STATUS_OK(status)) 27325cf1a30Sjl139090 printf("ok"); 27425cf1a30Sjl139090 printf("\n"); 27525cf1a30Sjl139090 } 27625cf1a30Sjl139090 #endif /* DEBUG */ 27725cf1a30Sjl139090 27825cf1a30Sjl139090 #ifdef UCTEST 27925cf1a30Sjl139090 /* 28025cf1a30Sjl139090 * For SesamI debugging, just map the SRAM directly to a kernel 28125cf1a30Sjl139090 * VA and read it out from there 28225cf1a30Sjl139090 */ 28325cf1a30Sjl139090 28425cf1a30Sjl139090 #include <sys/vmem.h> 28525cf1a30Sjl139090 #include <vm/seg_kmem.h> 28625cf1a30Sjl139090 28725cf1a30Sjl139090 /* 28825cf1a30Sjl139090 * 0x4081F1323000LL is the HWD base address for LSB 0. But we need to map 28925cf1a30Sjl139090 * at page boundaries. So, we use a base address of 0x4081F1322000LL. 29025cf1a30Sjl139090 * Note that this has to match the HWD base pa set in .sesami-common-defs. 29125cf1a30Sjl139090 * 29225cf1a30Sjl139090 * The size specified for the HWD in the SCF spec is 36K. But since 29325cf1a30Sjl139090 * we adjusted the base address by 4K, we need to use 40K for the 29425cf1a30Sjl139090 * mapping size to cover the HWD. And 40K is also a multiple of the 29525cf1a30Sjl139090 * base page size. 29625cf1a30Sjl139090 */ 29725cf1a30Sjl139090 #define OPL_HWD_BASE(lsb) \ 29825cf1a30Sjl139090 (0x4081F1322000LL | (((uint64_t)(lsb)) << 40)) 29925cf1a30Sjl139090 30025cf1a30Sjl139090 void *opl_hwd_vaddr; 30125cf1a30Sjl139090 #endif /* UCTEST */ 30225cf1a30Sjl139090 30325cf1a30Sjl139090 /* 30425cf1a30Sjl139090 * Get the hardware descriptor from SCF. 30525cf1a30Sjl139090 */ 30625cf1a30Sjl139090 30725cf1a30Sjl139090 /*ARGSUSED*/ 30825cf1a30Sjl139090 int 30925cf1a30Sjl139090 opl_read_hwd(int board, hwd_header_t **hdrp, hwd_sb_status_t **statp, 31025cf1a30Sjl139090 hwd_domain_info_t **dinfop, hwd_sb_t **sbp) 31125cf1a30Sjl139090 { 31225cf1a30Sjl139090 static int (*getinfop)(uint32_t, uint8_t, uint32_t, uint32_t *, 31325cf1a30Sjl139090 void *) = NULL; 31425cf1a30Sjl139090 void *hwdp; 31525cf1a30Sjl139090 31625cf1a30Sjl139090 uint32_t key = KEY_ESCF; /* required value */ 31725cf1a30Sjl139090 uint8_t type = 0x40; /* SUB_OS_RECEIVE_HWD */ 31825cf1a30Sjl139090 uint32_t transid = board; 31925cf1a30Sjl139090 uint32_t datasize = HWD_DATA_SIZE; 32025cf1a30Sjl139090 32125cf1a30Sjl139090 hwd_header_t *hd; 32225cf1a30Sjl139090 hwd_sb_status_t *st; 32325cf1a30Sjl139090 hwd_domain_info_t *di; 32425cf1a30Sjl139090 hwd_sb_t *sb; 32525cf1a30Sjl139090 32625cf1a30Sjl139090 int ret; 32725cf1a30Sjl139090 32825cf1a30Sjl139090 if (opl_boards[board].cfg_hwd == NULL) { 32925cf1a30Sjl139090 #ifdef UCTEST 33025cf1a30Sjl139090 /* 33125cf1a30Sjl139090 * Just map the HWD in SRAM to a kernel VA 33225cf1a30Sjl139090 */ 33325cf1a30Sjl139090 33425cf1a30Sjl139090 size_t size; 33525cf1a30Sjl139090 pfn_t pfn; 33625cf1a30Sjl139090 33725cf1a30Sjl139090 size = 0xA000; 33825cf1a30Sjl139090 33925cf1a30Sjl139090 opl_hwd_vaddr = vmem_alloc(heap_arena, size, VM_SLEEP); 34025cf1a30Sjl139090 if (opl_hwd_vaddr == NULL) { 34125cf1a30Sjl139090 cmn_err(CE_NOTE, "No space for HWD"); 34225cf1a30Sjl139090 return (-1); 34325cf1a30Sjl139090 } 34425cf1a30Sjl139090 34525cf1a30Sjl139090 pfn = btop(OPL_HWD_BASE(board)); 34625cf1a30Sjl139090 hat_devload(kas.a_hat, opl_hwd_vaddr, size, pfn, PROT_READ, 34725cf1a30Sjl139090 HAT_LOAD_NOCONSIST | HAT_LOAD_LOCK); 34825cf1a30Sjl139090 34925cf1a30Sjl139090 hwdp = (void *)((char *)opl_hwd_vaddr + 0x1000); 35025cf1a30Sjl139090 opl_boards[board].cfg_hwd = hwdp; 35125cf1a30Sjl139090 ret = 0; 35225cf1a30Sjl139090 #else 35325cf1a30Sjl139090 35425cf1a30Sjl139090 /* find the scf_service_getinfo() function */ 35525cf1a30Sjl139090 if (getinfop == NULL) 35625cf1a30Sjl139090 getinfop = (int (*)(uint32_t, uint8_t, uint32_t, 35725cf1a30Sjl139090 uint32_t *, 35825cf1a30Sjl139090 void *))modgetsymvalue("scf_service_getinfo", 0); 35925cf1a30Sjl139090 36025cf1a30Sjl139090 if (getinfop == NULL) 36125cf1a30Sjl139090 return (-1); 36225cf1a30Sjl139090 36325cf1a30Sjl139090 /* allocate memory to receive the data */ 36425cf1a30Sjl139090 hwdp = kmem_alloc(HWD_DATA_SIZE, KM_SLEEP); 36525cf1a30Sjl139090 36625cf1a30Sjl139090 /* get the HWD */ 36725cf1a30Sjl139090 ret = (*getinfop)(key, type, transid, &datasize, hwdp); 36825cf1a30Sjl139090 if (ret == 0) 36925cf1a30Sjl139090 opl_boards[board].cfg_hwd = hwdp; 37025cf1a30Sjl139090 else 37125cf1a30Sjl139090 kmem_free(hwdp, HWD_DATA_SIZE); 37225cf1a30Sjl139090 #endif 37325cf1a30Sjl139090 } else { 37425cf1a30Sjl139090 hwdp = opl_boards[board].cfg_hwd; 37525cf1a30Sjl139090 ret = 0; 37625cf1a30Sjl139090 } 37725cf1a30Sjl139090 37825cf1a30Sjl139090 /* copy the data to the destination */ 37925cf1a30Sjl139090 if (ret == 0) { 38025cf1a30Sjl139090 hd = (hwd_header_t *)hwdp; 38125cf1a30Sjl139090 st = (hwd_sb_status_t *) 38225cf1a30Sjl139090 ((char *)hwdp + hd->hdr_sb_status_offset); 38325cf1a30Sjl139090 di = (hwd_domain_info_t *) 38425cf1a30Sjl139090 ((char *)hwdp + hd->hdr_domain_info_offset); 38525cf1a30Sjl139090 sb = (hwd_sb_t *) 38625cf1a30Sjl139090 ((char *)hwdp + hd->hdr_sb_info_offset); 38725cf1a30Sjl139090 if (hdrp != NULL) 38825cf1a30Sjl139090 *hdrp = hd; 38925cf1a30Sjl139090 if (statp != NULL) 39025cf1a30Sjl139090 *statp = st; 39125cf1a30Sjl139090 if (dinfop != NULL) 39225cf1a30Sjl139090 *dinfop = di; 39325cf1a30Sjl139090 if (sbp != NULL) 39425cf1a30Sjl139090 *sbp = sb; 39525cf1a30Sjl139090 } 39625cf1a30Sjl139090 39725cf1a30Sjl139090 return (ret); 39825cf1a30Sjl139090 } 39925cf1a30Sjl139090 40025cf1a30Sjl139090 /* 40125cf1a30Sjl139090 * The opl_probe_t probe structure is used to pass all sorts of parameters 40225cf1a30Sjl139090 * to callback functions during probing. It also contains a snapshot of 40325cf1a30Sjl139090 * the hardware descriptor that is taken at the beginning of a probe. 40425cf1a30Sjl139090 */ 40525cf1a30Sjl139090 static int 40625cf1a30Sjl139090 opl_probe_init(opl_probe_t *probe) 40725cf1a30Sjl139090 { 40825cf1a30Sjl139090 hwd_header_t **hdrp; 40925cf1a30Sjl139090 hwd_sb_status_t **statp; 41025cf1a30Sjl139090 hwd_domain_info_t **dinfop; 41125cf1a30Sjl139090 hwd_sb_t **sbp; 41225cf1a30Sjl139090 int board, ret; 41325cf1a30Sjl139090 41425cf1a30Sjl139090 board = probe->pr_board; 41525cf1a30Sjl139090 41625cf1a30Sjl139090 hdrp = &probe->pr_hdr; 41725cf1a30Sjl139090 statp = &probe->pr_sb_status; 41825cf1a30Sjl139090 dinfop = &probe->pr_dinfo; 41925cf1a30Sjl139090 sbp = &probe->pr_sb; 42025cf1a30Sjl139090 42125cf1a30Sjl139090 /* 42225cf1a30Sjl139090 * Read the hardware descriptor. 42325cf1a30Sjl139090 */ 42425cf1a30Sjl139090 ret = opl_read_hwd(board, hdrp, statp, dinfop, sbp); 42525cf1a30Sjl139090 if (ret != 0) { 42625cf1a30Sjl139090 42725cf1a30Sjl139090 cmn_err(CE_WARN, "IKP: failed to read HWD header"); 42825cf1a30Sjl139090 return (-1); 42925cf1a30Sjl139090 } 43025cf1a30Sjl139090 43125cf1a30Sjl139090 #ifdef DEBUG 43225cf1a30Sjl139090 opl_dump_hwd(probe); 43325cf1a30Sjl139090 #endif 43425cf1a30Sjl139090 return (0); 43525cf1a30Sjl139090 } 43625cf1a30Sjl139090 43725cf1a30Sjl139090 /* 43825cf1a30Sjl139090 * This function is used to obtain pointers to relevant device nodes 43925cf1a30Sjl139090 * which are created by Solaris at boot time. 44025cf1a30Sjl139090 * 44125cf1a30Sjl139090 * This function walks the child nodes of a given node, extracts 44225cf1a30Sjl139090 * the "name" property, if it exists, and passes the node to a 44325cf1a30Sjl139090 * callback init function. The callback determines if this node is 44425cf1a30Sjl139090 * interesting or not. If it is, then a pointer to the node is 44525cf1a30Sjl139090 * stored away by the callback for use during unprobe. 44625cf1a30Sjl139090 * 44725cf1a30Sjl139090 * The DDI get property function allocates storage for the name 44825cf1a30Sjl139090 * property. That needs to be freed within this function. 44925cf1a30Sjl139090 */ 45025cf1a30Sjl139090 static int 45125cf1a30Sjl139090 opl_init_nodes(dev_info_t *parent, opl_init_func_t init) 45225cf1a30Sjl139090 { 45325cf1a30Sjl139090 dev_info_t *node; 45425cf1a30Sjl139090 char *name; 45525cf1a30Sjl139090 int circ, ret; 45625cf1a30Sjl139090 int len; 45725cf1a30Sjl139090 45825cf1a30Sjl139090 ASSERT(parent != NULL); 45925cf1a30Sjl139090 46025cf1a30Sjl139090 /* 46125cf1a30Sjl139090 * Hold parent node busy to walk its child list 46225cf1a30Sjl139090 */ 46325cf1a30Sjl139090 ndi_devi_enter(parent, &circ); 46425cf1a30Sjl139090 node = ddi_get_child(parent); 46525cf1a30Sjl139090 46625cf1a30Sjl139090 while (node != NULL) { 46725cf1a30Sjl139090 46825cf1a30Sjl139090 ret = OPL_GET_PROP(string, node, "name", &name, &len); 46925cf1a30Sjl139090 if (ret != DDI_PROP_SUCCESS) { 47025cf1a30Sjl139090 /* 47125cf1a30Sjl139090 * The property does not exist for this node. 47225cf1a30Sjl139090 */ 47325cf1a30Sjl139090 node = ddi_get_next_sibling(node); 47425cf1a30Sjl139090 continue; 47525cf1a30Sjl139090 } 47625cf1a30Sjl139090 47725cf1a30Sjl139090 ret = init(node, name, len); 47825cf1a30Sjl139090 kmem_free(name, len); 47925cf1a30Sjl139090 if (ret != 0) { 48025cf1a30Sjl139090 48125cf1a30Sjl139090 ndi_devi_exit(parent, circ); 48225cf1a30Sjl139090 return (-1); 48325cf1a30Sjl139090 } 48425cf1a30Sjl139090 48525cf1a30Sjl139090 node = ddi_get_next_sibling(node); 48625cf1a30Sjl139090 } 48725cf1a30Sjl139090 48825cf1a30Sjl139090 ndi_devi_exit(parent, circ); 48925cf1a30Sjl139090 49025cf1a30Sjl139090 return (0); 49125cf1a30Sjl139090 } 49225cf1a30Sjl139090 49325cf1a30Sjl139090 /* 49425cf1a30Sjl139090 * This init function finds all the interesting nodes under the 49525cf1a30Sjl139090 * root node and stores pointers to them. The following nodes 49625cf1a30Sjl139090 * are considered interesting by this implementation: 49725cf1a30Sjl139090 * 49825cf1a30Sjl139090 * "cmp" 49925cf1a30Sjl139090 * These are nodes that represent processor chips. 50025cf1a30Sjl139090 * 50125cf1a30Sjl139090 * "pci" 50225cf1a30Sjl139090 * These are nodes that represent PCI leaves. 50325cf1a30Sjl139090 * 50425cf1a30Sjl139090 * "pseudo-mc" 50525cf1a30Sjl139090 * These are nodes that contain memory information. 50625cf1a30Sjl139090 */ 50725cf1a30Sjl139090 static int 50825cf1a30Sjl139090 opl_init_root_nodes(dev_info_t *node, char *name, int len) 50925cf1a30Sjl139090 { 51025cf1a30Sjl139090 int portid, board, chip, channel, leaf; 51125cf1a30Sjl139090 int ret; 51225cf1a30Sjl139090 51325cf1a30Sjl139090 if (strncmp(name, OPL_CPU_CHIP_NODE, len) == 0) { 51425cf1a30Sjl139090 51525cf1a30Sjl139090 ret = OPL_GET_PROP(int, node, "portid", &portid, -1); 51625cf1a30Sjl139090 if (ret != DDI_PROP_SUCCESS) 51725cf1a30Sjl139090 return (-1); 51825cf1a30Sjl139090 51925cf1a30Sjl139090 ret = OPL_GET_PROP(int, node, "board#", &board, -1); 52025cf1a30Sjl139090 if (ret != DDI_PROP_SUCCESS) 52125cf1a30Sjl139090 return (-1); 52225cf1a30Sjl139090 52325cf1a30Sjl139090 chip = OPL_CPU_CHIP(portid); 52425cf1a30Sjl139090 opl_boards[board].cfg_cpu_chips[chip] = node; 52525cf1a30Sjl139090 52625cf1a30Sjl139090 } else if (strncmp(name, OPL_PCI_LEAF_NODE, len) == 0) { 52725cf1a30Sjl139090 52825cf1a30Sjl139090 ret = OPL_GET_PROP(int, node, "portid", &portid, -1); 52925cf1a30Sjl139090 if (ret != DDI_PROP_SUCCESS) 53025cf1a30Sjl139090 return (-1); 53125cf1a30Sjl139090 53225cf1a30Sjl139090 board = OPL_IO_PORTID_TO_LSB(portid); 53325cf1a30Sjl139090 channel = OPL_PORTID_TO_CHANNEL(portid); 53425cf1a30Sjl139090 53525cf1a30Sjl139090 if (channel == OPL_CMU_CHANNEL) { 53625cf1a30Sjl139090 53725cf1a30Sjl139090 opl_boards[board].cfg_cmuch_leaf = node; 53825cf1a30Sjl139090 53925cf1a30Sjl139090 } else { 54025cf1a30Sjl139090 54125cf1a30Sjl139090 leaf = OPL_PORTID_TO_LEAF(portid); 54225cf1a30Sjl139090 opl_boards[board].cfg_pcich_leaf[channel][leaf] = node; 54325cf1a30Sjl139090 } 54425cf1a30Sjl139090 } else if (strncmp(name, OPL_PSEUDO_MC_NODE, len) == 0) { 54525cf1a30Sjl139090 54625cf1a30Sjl139090 ret = OPL_GET_PROP(int, node, "board#", &board, -1); 54725cf1a30Sjl139090 if (ret != DDI_PROP_SUCCESS) 54825cf1a30Sjl139090 return (-1); 54925cf1a30Sjl139090 55025cf1a30Sjl139090 ASSERT((board >= 0) && (board < HWD_SBS_PER_DOMAIN)); 55125cf1a30Sjl139090 55225cf1a30Sjl139090 opl_boards[board].cfg_pseudo_mc = node; 55325cf1a30Sjl139090 } 55425cf1a30Sjl139090 55525cf1a30Sjl139090 return (0); 55625cf1a30Sjl139090 } 55725cf1a30Sjl139090 55825cf1a30Sjl139090 /* 55925cf1a30Sjl139090 * This function initializes the OPL IKP feature. Currently, all it does 56025cf1a30Sjl139090 * is find the interesting nodes that Solaris has created at boot time 56125cf1a30Sjl139090 * for boards present at boot time and store pointers to them. This 56225cf1a30Sjl139090 * is useful if those boards are unprobed by DR. 56325cf1a30Sjl139090 */ 56425cf1a30Sjl139090 int 56525cf1a30Sjl139090 opl_init_cfg() 56625cf1a30Sjl139090 { 56725cf1a30Sjl139090 dev_info_t *root; 56825cf1a30Sjl139090 56925cf1a30Sjl139090 if (opl_cfg_inited == 0) { 57025cf1a30Sjl139090 57125cf1a30Sjl139090 root = ddi_root_node(); 57225cf1a30Sjl139090 if ((opl_init_nodes(root, opl_init_root_nodes) != 0)) { 57325cf1a30Sjl139090 cmn_err(CE_WARN, "IKP: init failed"); 57425cf1a30Sjl139090 return (1); 57525cf1a30Sjl139090 } 57625cf1a30Sjl139090 57725cf1a30Sjl139090 opl_cfg_inited = 1; 57825cf1a30Sjl139090 } 57925cf1a30Sjl139090 58025cf1a30Sjl139090 return (0); 58125cf1a30Sjl139090 } 58225cf1a30Sjl139090 58325cf1a30Sjl139090 /* 58425cf1a30Sjl139090 * When DR is initialized, we walk the device tree and acquire a hold on 58525cf1a30Sjl139090 * all the nodes that are interesting to IKP. This is so that the corresponding 58625cf1a30Sjl139090 * branches cannot be deleted. 58725cf1a30Sjl139090 * 58825cf1a30Sjl139090 * The following function informs the walk about which nodes are interesting 58925cf1a30Sjl139090 * so that it can hold the corresponding branches. 59025cf1a30Sjl139090 */ 59125cf1a30Sjl139090 static int 59225cf1a30Sjl139090 opl_hold_node(char *name) 59325cf1a30Sjl139090 { 59425cf1a30Sjl139090 /* 59525cf1a30Sjl139090 * We only need to hold/release the following nodes which 59625cf1a30Sjl139090 * represent separate branches that must be managed. 59725cf1a30Sjl139090 */ 59825cf1a30Sjl139090 return ((strcmp(name, OPL_CPU_CHIP_NODE) == 0) || 59925cf1a30Sjl139090 (strcmp(name, OPL_PSEUDO_MC_NODE) == 0) || 60025cf1a30Sjl139090 (strcmp(name, OPL_PCI_LEAF_NODE) == 0)); 60125cf1a30Sjl139090 } 60225cf1a30Sjl139090 60325cf1a30Sjl139090 static int 60425cf1a30Sjl139090 opl_hold_rele_devtree(dev_info_t *rdip, void *arg) 60525cf1a30Sjl139090 { 60625cf1a30Sjl139090 60725cf1a30Sjl139090 int *holdp = (int *)arg; 60825cf1a30Sjl139090 char *name = ddi_node_name(rdip); 60925cf1a30Sjl139090 61025cf1a30Sjl139090 /* 61125cf1a30Sjl139090 * We only need to hold/release the following nodes which 61225cf1a30Sjl139090 * represent separate branches that must be managed. 61325cf1a30Sjl139090 */ 61425cf1a30Sjl139090 if (opl_hold_node(name) == 0) { 61525cf1a30Sjl139090 /* Not of interest to us */ 61625cf1a30Sjl139090 return (DDI_WALK_PRUNECHILD); 61725cf1a30Sjl139090 } 61825cf1a30Sjl139090 if (*holdp) { 61925cf1a30Sjl139090 ASSERT(!e_ddi_branch_held(rdip)); 62025cf1a30Sjl139090 e_ddi_branch_hold(rdip); 62125cf1a30Sjl139090 } else { 62225cf1a30Sjl139090 ASSERT(e_ddi_branch_held(rdip)); 62325cf1a30Sjl139090 e_ddi_branch_rele(rdip); 62425cf1a30Sjl139090 } 62525cf1a30Sjl139090 62625cf1a30Sjl139090 return (DDI_WALK_PRUNECHILD); 62725cf1a30Sjl139090 } 62825cf1a30Sjl139090 62925cf1a30Sjl139090 void 63025cf1a30Sjl139090 opl_hold_devtree() 63125cf1a30Sjl139090 { 63225cf1a30Sjl139090 dev_info_t *dip; 63325cf1a30Sjl139090 int circ; 63425cf1a30Sjl139090 int hold = 1; 63525cf1a30Sjl139090 63625cf1a30Sjl139090 dip = ddi_root_node(); 63725cf1a30Sjl139090 ndi_devi_enter(dip, &circ); 63825cf1a30Sjl139090 ddi_walk_devs(ddi_get_child(dip), opl_hold_rele_devtree, &hold); 63925cf1a30Sjl139090 ndi_devi_exit(dip, circ); 64025cf1a30Sjl139090 } 64125cf1a30Sjl139090 64225cf1a30Sjl139090 void 64325cf1a30Sjl139090 opl_release_devtree() 64425cf1a30Sjl139090 { 64525cf1a30Sjl139090 dev_info_t *dip; 64625cf1a30Sjl139090 int circ; 64725cf1a30Sjl139090 int hold = 0; 64825cf1a30Sjl139090 64925cf1a30Sjl139090 dip = ddi_root_node(); 65025cf1a30Sjl139090 ndi_devi_enter(dip, &circ); 65125cf1a30Sjl139090 ddi_walk_devs(ddi_get_child(dip), opl_hold_rele_devtree, &hold); 65225cf1a30Sjl139090 ndi_devi_exit(dip, circ); 65325cf1a30Sjl139090 } 65425cf1a30Sjl139090 65525cf1a30Sjl139090 /* 65625cf1a30Sjl139090 * This is a helper function that allows opl_create_node() to return a 65725cf1a30Sjl139090 * pointer to a newly created node to its caller. 65825cf1a30Sjl139090 */ 65925cf1a30Sjl139090 /*ARGSUSED*/ 66025cf1a30Sjl139090 static void 66125cf1a30Sjl139090 opl_set_node(dev_info_t *node, void *arg, uint_t flags) 66225cf1a30Sjl139090 { 66325cf1a30Sjl139090 opl_probe_t *probe; 66425cf1a30Sjl139090 66525cf1a30Sjl139090 probe = arg; 66625cf1a30Sjl139090 probe->pr_node = node; 66725cf1a30Sjl139090 } 66825cf1a30Sjl139090 66925cf1a30Sjl139090 /* 67025cf1a30Sjl139090 * Function to create a node in the device tree under a specified parent. 67125cf1a30Sjl139090 * 67225cf1a30Sjl139090 * e_ddi_branch_create() allows the creation of a whole branch with a 67325cf1a30Sjl139090 * single call of the function. However, we only use it to create one node 67425cf1a30Sjl139090 * at a time in the case of non-I/O device nodes. In other words, we 67525cf1a30Sjl139090 * create branches by repeatedly using this function. This makes the 67625cf1a30Sjl139090 * code more readable. 67725cf1a30Sjl139090 * 67825cf1a30Sjl139090 * The branch descriptor passed to e_ddi_branch_create() takes two 67925cf1a30Sjl139090 * callbacks. The create() callback is used to set the properties of a 68025cf1a30Sjl139090 * newly created node. The other callback is used to return a pointer 68125cf1a30Sjl139090 * to the newly created node. The create() callback is passed by the 682*48bbca81SDaniel Hoffman * caller of this function based on the kind of node it wishes to 68325cf1a30Sjl139090 * create. 68425cf1a30Sjl139090 * 68525cf1a30Sjl139090 * e_ddi_branch_create() returns with the newly created node held. We 68625cf1a30Sjl139090 * only need to hold the top nodes of the branches we create. We release 68725cf1a30Sjl139090 * the hold for the others. E.g., the "cmp" node needs to be held. Since 68825cf1a30Sjl139090 * we hold the "cmp" node, there is no need to hold the "core" and "cpu" 68925cf1a30Sjl139090 * nodes below it. 69025cf1a30Sjl139090 */ 69125cf1a30Sjl139090 static dev_info_t * 69225cf1a30Sjl139090 opl_create_node(opl_probe_t *probe) 69325cf1a30Sjl139090 { 69425cf1a30Sjl139090 devi_branch_t branch; 69525cf1a30Sjl139090 69625cf1a30Sjl139090 probe->pr_node = NULL; 69725cf1a30Sjl139090 69825cf1a30Sjl139090 branch.arg = probe; 69925cf1a30Sjl139090 branch.type = DEVI_BRANCH_SID; 70025cf1a30Sjl139090 branch.create.sid_branch_create = probe->pr_create; 70125cf1a30Sjl139090 branch.devi_branch_callback = opl_set_node; 70225cf1a30Sjl139090 70325cf1a30Sjl139090 if (e_ddi_branch_create(probe->pr_parent, &branch, NULL, 0) != 0) 70425cf1a30Sjl139090 return (NULL); 70525cf1a30Sjl139090 70625cf1a30Sjl139090 ASSERT(probe->pr_node != NULL); 70725cf1a30Sjl139090 70825cf1a30Sjl139090 if (probe->pr_hold == 0) 70925cf1a30Sjl139090 e_ddi_branch_rele(probe->pr_node); 71025cf1a30Sjl139090 71125cf1a30Sjl139090 return (probe->pr_node); 71225cf1a30Sjl139090 } 71325cf1a30Sjl139090 71425cf1a30Sjl139090 /* 71525cf1a30Sjl139090 * Function to tear down a whole branch rooted at the specified node. 71625cf1a30Sjl139090 * 71725cf1a30Sjl139090 * Although we create each node of a branch individually, we destroy 71825cf1a30Sjl139090 * a whole branch in one call. This is more efficient. 71925cf1a30Sjl139090 */ 72025cf1a30Sjl139090 static int 72125cf1a30Sjl139090 opl_destroy_node(dev_info_t *node) 72225cf1a30Sjl139090 { 72368ac2337Sjl139090 if (e_ddi_branch_destroy(node, NULL, 0) != 0) { 72468ac2337Sjl139090 char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 72568ac2337Sjl139090 (void) ddi_pathname(node, path); 726e98fafb9Sjl139090 cmn_err(CE_WARN, "OPL node removal failed: %s (%p)", path, 727e98fafb9Sjl139090 (void *)node); 72868ac2337Sjl139090 kmem_free(path, MAXPATHLEN); 72925cf1a30Sjl139090 return (-1); 73068ac2337Sjl139090 } 73125cf1a30Sjl139090 73225cf1a30Sjl139090 return (0); 73325cf1a30Sjl139090 } 73425cf1a30Sjl139090 73525cf1a30Sjl139090 /* 73625cf1a30Sjl139090 * Set the properties for a "cpu" node. 73725cf1a30Sjl139090 */ 73825cf1a30Sjl139090 /*ARGSUSED*/ 73925cf1a30Sjl139090 static int 74025cf1a30Sjl139090 opl_create_cpu(dev_info_t *node, void *arg, uint_t flags) 74125cf1a30Sjl139090 { 74225cf1a30Sjl139090 opl_probe_t *probe; 74325cf1a30Sjl139090 hwd_cpu_chip_t *chip; 74425cf1a30Sjl139090 hwd_core_t *core; 74525cf1a30Sjl139090 hwd_cpu_t *cpu; 74625cf1a30Sjl139090 int ret; 74725cf1a30Sjl139090 74825cf1a30Sjl139090 probe = arg; 74925cf1a30Sjl139090 chip = &probe->pr_sb->sb_cmu.cmu_cpu_chips[probe->pr_cpu_chip]; 75025cf1a30Sjl139090 core = &chip->chip_cores[probe->pr_core]; 75125cf1a30Sjl139090 cpu = &core->core_cpus[probe->pr_cpu]; 75225cf1a30Sjl139090 OPL_UPDATE_PROP(string, node, "name", OPL_CPU_NODE); 75325cf1a30Sjl139090 OPL_UPDATE_PROP(string, node, "device_type", OPL_CPU_NODE); 75425cf1a30Sjl139090 75525cf1a30Sjl139090 OPL_UPDATE_PROP(int, node, "cpuid", cpu->cpu_cpuid); 75625cf1a30Sjl139090 OPL_UPDATE_PROP(int, node, "reg", probe->pr_cpu); 75725cf1a30Sjl139090 75825cf1a30Sjl139090 OPL_UPDATE_PROP(string, node, "status", "okay"); 75925cf1a30Sjl139090 76025cf1a30Sjl139090 return (DDI_WALK_TERMINATE); 76125cf1a30Sjl139090 } 76225cf1a30Sjl139090 76325cf1a30Sjl139090 /* 76425cf1a30Sjl139090 * Create "cpu" nodes as child nodes of a given "core" node. 76525cf1a30Sjl139090 */ 76625cf1a30Sjl139090 static int 76725cf1a30Sjl139090 opl_probe_cpus(opl_probe_t *probe) 76825cf1a30Sjl139090 { 76925cf1a30Sjl139090 int i; 77025cf1a30Sjl139090 hwd_cpu_chip_t *chip; 77125cf1a30Sjl139090 hwd_core_t *core; 77225cf1a30Sjl139090 hwd_cpu_t *cpus; 77325cf1a30Sjl139090 77425cf1a30Sjl139090 chip = &probe->pr_sb->sb_cmu.cmu_cpu_chips[probe->pr_cpu_chip]; 77525cf1a30Sjl139090 core = &chip->chip_cores[probe->pr_core]; 77625cf1a30Sjl139090 cpus = &core->core_cpus[0]; 77725cf1a30Sjl139090 77825cf1a30Sjl139090 for (i = 0; i < HWD_CPUS_PER_CORE; i++) { 77925cf1a30Sjl139090 78025cf1a30Sjl139090 /* 78125cf1a30Sjl139090 * Olympus-C has 2 cpus per core. 78225cf1a30Sjl139090 * Jupiter has 4 cpus per core. 78325cf1a30Sjl139090 * For the Olympus-C based platform, we expect the cpu_status 78425cf1a30Sjl139090 * of the non-existent cpus to be set to missing. 78525cf1a30Sjl139090 */ 78625cf1a30Sjl139090 if (!HWD_STATUS_OK(cpus[i].cpu_status)) 78725cf1a30Sjl139090 continue; 78825cf1a30Sjl139090 78925cf1a30Sjl139090 probe->pr_create = opl_create_cpu; 79025cf1a30Sjl139090 probe->pr_cpu = i; 79125cf1a30Sjl139090 if (opl_create_node(probe) == NULL) { 79225cf1a30Sjl139090 79325cf1a30Sjl139090 cmn_err(CE_WARN, "IKP: create cpu (%d-%d-%d-%d) failed", 794e98fafb9Sjl139090 probe->pr_board, probe->pr_cpu_chip, probe->pr_core, 795e98fafb9Sjl139090 probe->pr_cpu); 79625cf1a30Sjl139090 return (-1); 79725cf1a30Sjl139090 } 79825cf1a30Sjl139090 } 79925cf1a30Sjl139090 80025cf1a30Sjl139090 return (0); 80125cf1a30Sjl139090 } 80225cf1a30Sjl139090 80325cf1a30Sjl139090 /* 80425cf1a30Sjl139090 * Set the properties for a "core" node. 80525cf1a30Sjl139090 */ 80625cf1a30Sjl139090 /*ARGSUSED*/ 80725cf1a30Sjl139090 static int 80825cf1a30Sjl139090 opl_create_core(dev_info_t *node, void *arg, uint_t flags) 80925cf1a30Sjl139090 { 81025cf1a30Sjl139090 opl_probe_t *probe; 81125cf1a30Sjl139090 hwd_cpu_chip_t *chip; 81225cf1a30Sjl139090 hwd_core_t *core; 81325cf1a30Sjl139090 int sharing[2]; 81425cf1a30Sjl139090 int ret; 81525cf1a30Sjl139090 81625cf1a30Sjl139090 probe = arg; 81725cf1a30Sjl139090 chip = &probe->pr_sb->sb_cmu.cmu_cpu_chips[probe->pr_cpu_chip]; 81825cf1a30Sjl139090 core = &chip->chip_cores[probe->pr_core]; 81925cf1a30Sjl139090 82025cf1a30Sjl139090 OPL_UPDATE_PROP(string, node, "name", OPL_CORE_NODE); 82125cf1a30Sjl139090 OPL_UPDATE_PROP(string, node, "device_type", OPL_CORE_NODE); 82225cf1a30Sjl139090 OPL_UPDATE_PROP(string, node, "compatible", chip->chip_compatible); 82325cf1a30Sjl139090 82425cf1a30Sjl139090 OPL_UPDATE_PROP(int, node, "reg", probe->pr_core); 82525cf1a30Sjl139090 OPL_UPDATE_PROP(int, node, "manufacturer#", core->core_manufacturer); 82625cf1a30Sjl139090 OPL_UPDATE_PROP(int, node, "implementation#", 82725cf1a30Sjl139090 core->core_implementation); 82825cf1a30Sjl139090 OPL_UPDATE_PROP(int, node, "mask#", core->core_mask); 82925cf1a30Sjl139090 8300e9f8900Sjimand OPL_UPDATE_PROP(int, node, "sparc-version", 9); 83125cf1a30Sjl139090 OPL_UPDATE_PROP(int, node, "clock-frequency", core->core_frequency); 83225cf1a30Sjl139090 83325cf1a30Sjl139090 OPL_UPDATE_PROP(int, node, "l1-icache-size", core->core_l1_icache_size); 83425cf1a30Sjl139090 OPL_UPDATE_PROP(int, node, "l1-icache-line-size", 83525cf1a30Sjl139090 core->core_l1_icache_line_size); 83625cf1a30Sjl139090 OPL_UPDATE_PROP(int, node, "l1-icache-associativity", 83725cf1a30Sjl139090 core->core_l1_icache_associativity); 83825cf1a30Sjl139090 OPL_UPDATE_PROP(int, node, "#itlb-entries", 83925cf1a30Sjl139090 core->core_num_itlb_entries); 84025cf1a30Sjl139090 84125cf1a30Sjl139090 OPL_UPDATE_PROP(int, node, "l1-dcache-size", core->core_l1_dcache_size); 84225cf1a30Sjl139090 OPL_UPDATE_PROP(int, node, "l1-dcache-line-size", 84325cf1a30Sjl139090 core->core_l1_dcache_line_size); 84425cf1a30Sjl139090 OPL_UPDATE_PROP(int, node, "l1-dcache-associativity", 84525cf1a30Sjl139090 core->core_l1_dcache_associativity); 84625cf1a30Sjl139090 OPL_UPDATE_PROP(int, node, "#dtlb-entries", 84725cf1a30Sjl139090 core->core_num_dtlb_entries); 84825cf1a30Sjl139090 84925cf1a30Sjl139090 OPL_UPDATE_PROP(int, node, "l2-cache-size", core->core_l2_cache_size); 85025cf1a30Sjl139090 OPL_UPDATE_PROP(int, node, "l2-cache-line-size", 85125cf1a30Sjl139090 core->core_l2_cache_line_size); 85225cf1a30Sjl139090 OPL_UPDATE_PROP(int, node, "l2-cache-associativity", 85325cf1a30Sjl139090 core->core_l2_cache_associativity); 85425cf1a30Sjl139090 sharing[0] = 0; 85525cf1a30Sjl139090 sharing[1] = core->core_l2_cache_sharing; 85625cf1a30Sjl139090 OPL_UPDATE_PROP_ARRAY(int, node, "l2-cache-sharing", sharing, 2); 85725cf1a30Sjl139090 85825cf1a30Sjl139090 OPL_UPDATE_PROP(string, node, "status", "okay"); 85925cf1a30Sjl139090 86025cf1a30Sjl139090 return (DDI_WALK_TERMINATE); 86125cf1a30Sjl139090 } 86225cf1a30Sjl139090 86325cf1a30Sjl139090 /* 86425cf1a30Sjl139090 * Create "core" nodes as child nodes of a given "cmp" node. 86525cf1a30Sjl139090 * 86625cf1a30Sjl139090 * Create the branch below each "core" node". 86725cf1a30Sjl139090 */ 86825cf1a30Sjl139090 static int 86925cf1a30Sjl139090 opl_probe_cores(opl_probe_t *probe) 87025cf1a30Sjl139090 { 87125cf1a30Sjl139090 int i; 87225cf1a30Sjl139090 hwd_cpu_chip_t *chip; 87325cf1a30Sjl139090 hwd_core_t *cores; 87425cf1a30Sjl139090 dev_info_t *parent, *node; 87525cf1a30Sjl139090 87625cf1a30Sjl139090 chip = &probe->pr_sb->sb_cmu.cmu_cpu_chips[probe->pr_cpu_chip]; 87725cf1a30Sjl139090 cores = &chip->chip_cores[0]; 87825cf1a30Sjl139090 parent = probe->pr_parent; 87925cf1a30Sjl139090 88025cf1a30Sjl139090 for (i = 0; i < HWD_CORES_PER_CPU_CHIP; i++) { 88125cf1a30Sjl139090 88225cf1a30Sjl139090 if (!HWD_STATUS_OK(cores[i].core_status)) 88325cf1a30Sjl139090 continue; 88425cf1a30Sjl139090 88525cf1a30Sjl139090 probe->pr_parent = parent; 88625cf1a30Sjl139090 probe->pr_create = opl_create_core; 88725cf1a30Sjl139090 probe->pr_core = i; 88825cf1a30Sjl139090 node = opl_create_node(probe); 88925cf1a30Sjl139090 if (node == NULL) { 89025cf1a30Sjl139090 89125cf1a30Sjl139090 cmn_err(CE_WARN, "IKP: create core (%d-%d-%d) failed", 89225cf1a30Sjl139090 probe->pr_board, probe->pr_cpu_chip, 89325cf1a30Sjl139090 probe->pr_core); 89425cf1a30Sjl139090 return (-1); 89525cf1a30Sjl139090 } 89625cf1a30Sjl139090 89725cf1a30Sjl139090 /* 89825cf1a30Sjl139090 * Create "cpu" nodes below "core". 89925cf1a30Sjl139090 */ 90025cf1a30Sjl139090 probe->pr_parent = node; 90125cf1a30Sjl139090 if (opl_probe_cpus(probe) != 0) 90225cf1a30Sjl139090 return (-1); 903e98fafb9Sjl139090 probe->pr_cpu_impl |= (1 << cores[i].core_implementation); 90425cf1a30Sjl139090 } 90525cf1a30Sjl139090 90625cf1a30Sjl139090 return (0); 90725cf1a30Sjl139090 } 90825cf1a30Sjl139090 90925cf1a30Sjl139090 /* 91025cf1a30Sjl139090 * Set the properties for a "cmp" node. 91125cf1a30Sjl139090 */ 91225cf1a30Sjl139090 /*ARGSUSED*/ 91325cf1a30Sjl139090 static int 91425cf1a30Sjl139090 opl_create_cpu_chip(dev_info_t *node, void *arg, uint_t flags) 91525cf1a30Sjl139090 { 91625cf1a30Sjl139090 opl_probe_t *probe; 91725cf1a30Sjl139090 hwd_cpu_chip_t *chip; 91825cf1a30Sjl139090 opl_range_t range; 91925cf1a30Sjl139090 uint64_t dummy_addr; 92025cf1a30Sjl139090 int ret; 92125cf1a30Sjl139090 92225cf1a30Sjl139090 probe = arg; 92325cf1a30Sjl139090 chip = &probe->pr_sb->sb_cmu.cmu_cpu_chips[probe->pr_cpu_chip]; 92425cf1a30Sjl139090 92525cf1a30Sjl139090 OPL_UPDATE_PROP(string, node, "name", OPL_CPU_CHIP_NODE); 92625cf1a30Sjl139090 92725cf1a30Sjl139090 OPL_UPDATE_PROP(int, node, "portid", chip->chip_portid); 92825cf1a30Sjl139090 OPL_UPDATE_PROP(int, node, "board#", probe->pr_board); 92925cf1a30Sjl139090 93025cf1a30Sjl139090 dummy_addr = OPL_PROC_AS(probe->pr_board, probe->pr_cpu_chip); 93125cf1a30Sjl139090 range.rg_addr_hi = OPL_HI(dummy_addr); 93225cf1a30Sjl139090 range.rg_addr_lo = OPL_LO(dummy_addr); 93325cf1a30Sjl139090 range.rg_size_hi = 0; 93425cf1a30Sjl139090 range.rg_size_lo = 0; 93525cf1a30Sjl139090 OPL_UPDATE_PROP_ARRAY(int, node, "reg", (int *)&range, 4); 93625cf1a30Sjl139090 93725cf1a30Sjl139090 OPL_UPDATE_PROP(int, node, "#address-cells", 1); 93825cf1a30Sjl139090 OPL_UPDATE_PROP(int, node, "#size-cells", 0); 93925cf1a30Sjl139090 94025cf1a30Sjl139090 OPL_UPDATE_PROP(string, node, "status", "okay"); 94125cf1a30Sjl139090 94225cf1a30Sjl139090 return (DDI_WALK_TERMINATE); 94325cf1a30Sjl139090 } 94425cf1a30Sjl139090 94525cf1a30Sjl139090 /* 94625cf1a30Sjl139090 * Create "cmp" nodes as child nodes of the root node. 94725cf1a30Sjl139090 * 94825cf1a30Sjl139090 * Create the branch below each "cmp" node. 94925cf1a30Sjl139090 */ 95025cf1a30Sjl139090 static int 95125cf1a30Sjl139090 opl_probe_cpu_chips(opl_probe_t *probe) 95225cf1a30Sjl139090 { 95325cf1a30Sjl139090 int i; 95425cf1a30Sjl139090 dev_info_t **cfg_cpu_chips; 95525cf1a30Sjl139090 hwd_cpu_chip_t *chips; 95625cf1a30Sjl139090 dev_info_t *node; 95725cf1a30Sjl139090 95825cf1a30Sjl139090 cfg_cpu_chips = opl_boards[probe->pr_board].cfg_cpu_chips; 95925cf1a30Sjl139090 chips = &probe->pr_sb->sb_cmu.cmu_cpu_chips[0]; 96025cf1a30Sjl139090 96125cf1a30Sjl139090 for (i = 0; i < HWD_CPU_CHIPS_PER_CMU; i++) { 96225cf1a30Sjl139090 96325cf1a30Sjl139090 ASSERT(cfg_cpu_chips[i] == NULL); 96425cf1a30Sjl139090 96525cf1a30Sjl139090 if (!HWD_STATUS_OK(chips[i].chip_status)) 96625cf1a30Sjl139090 continue; 96725cf1a30Sjl139090 96825cf1a30Sjl139090 probe->pr_parent = ddi_root_node(); 96925cf1a30Sjl139090 probe->pr_create = opl_create_cpu_chip; 97025cf1a30Sjl139090 probe->pr_cpu_chip = i; 97125cf1a30Sjl139090 probe->pr_hold = 1; 97225cf1a30Sjl139090 node = opl_create_node(probe); 97325cf1a30Sjl139090 if (node == NULL) { 97425cf1a30Sjl139090 97525cf1a30Sjl139090 cmn_err(CE_WARN, "IKP: create chip (%d-%d) failed", 97625cf1a30Sjl139090 probe->pr_board, probe->pr_cpu_chip); 97725cf1a30Sjl139090 return (-1); 97825cf1a30Sjl139090 } 97925cf1a30Sjl139090 98025cf1a30Sjl139090 cfg_cpu_chips[i] = node; 98125cf1a30Sjl139090 98225cf1a30Sjl139090 /* 98325cf1a30Sjl139090 * Create "core" nodes below "cmp". 98425cf1a30Sjl139090 * We hold the "cmp" node. So, there is no need to hold 98525cf1a30Sjl139090 * the "core" and "cpu" nodes below it. 98625cf1a30Sjl139090 */ 98725cf1a30Sjl139090 probe->pr_parent = node; 98825cf1a30Sjl139090 probe->pr_hold = 0; 98925cf1a30Sjl139090 if (opl_probe_cores(probe) != 0) 99025cf1a30Sjl139090 return (-1); 99125cf1a30Sjl139090 } 99225cf1a30Sjl139090 99325cf1a30Sjl139090 return (0); 99425cf1a30Sjl139090 } 99525cf1a30Sjl139090 99625cf1a30Sjl139090 /* 99725cf1a30Sjl139090 * Set the properties for a "pseudo-mc" node. 99825cf1a30Sjl139090 */ 99925cf1a30Sjl139090 /*ARGSUSED*/ 100025cf1a30Sjl139090 static int 100125cf1a30Sjl139090 opl_create_pseudo_mc(dev_info_t *node, void *arg, uint_t flags) 100225cf1a30Sjl139090 { 100325cf1a30Sjl139090 opl_probe_t *probe; 100425cf1a30Sjl139090 int board, portid; 100525cf1a30Sjl139090 hwd_bank_t *bank; 100625cf1a30Sjl139090 hwd_memory_t *mem; 100725cf1a30Sjl139090 opl_range_t range; 100825cf1a30Sjl139090 opl_mc_addr_t mc[HWD_BANKS_PER_CMU]; 100925cf1a30Sjl139090 int status[2][7]; 101025cf1a30Sjl139090 int i, j; 101125cf1a30Sjl139090 int ret; 101225cf1a30Sjl139090 101325cf1a30Sjl139090 probe = arg; 101425cf1a30Sjl139090 board = probe->pr_board; 101525cf1a30Sjl139090 101625cf1a30Sjl139090 OPL_UPDATE_PROP(string, node, "name", OPL_PSEUDO_MC_NODE); 101725cf1a30Sjl139090 OPL_UPDATE_PROP(string, node, "device_type", "memory-controller"); 101825cf1a30Sjl139090 OPL_UPDATE_PROP(string, node, "compatible", "FJSV,oplmc"); 101925cf1a30Sjl139090 102025cf1a30Sjl139090 portid = OPL_LSB_TO_PSEUDOMC_PORTID(board); 102125cf1a30Sjl139090 OPL_UPDATE_PROP(int, node, "portid", portid); 102225cf1a30Sjl139090 102325cf1a30Sjl139090 range.rg_addr_hi = OPL_HI(OPL_MC_AS(board)); 102425cf1a30Sjl139090 range.rg_addr_lo = 0x200; 102525cf1a30Sjl139090 range.rg_size_hi = 0; 102625cf1a30Sjl139090 range.rg_size_lo = 0; 102725cf1a30Sjl139090 OPL_UPDATE_PROP_ARRAY(int, node, "reg", (int *)&range, 4); 102825cf1a30Sjl139090 102925cf1a30Sjl139090 OPL_UPDATE_PROP(int, node, "board#", board); 103025cf1a30Sjl139090 OPL_UPDATE_PROP(int, node, "physical-board#", 103125cf1a30Sjl139090 probe->pr_sb->sb_psb_number); 103225cf1a30Sjl139090 103325cf1a30Sjl139090 OPL_UPDATE_PROP(int, node, "#address-cells", 1); 103425cf1a30Sjl139090 OPL_UPDATE_PROP(int, node, "#size-cells", 2); 103525cf1a30Sjl139090 103625cf1a30Sjl139090 mem = &probe->pr_sb->sb_cmu.cmu_memory; 103725cf1a30Sjl139090 103825cf1a30Sjl139090 range.rg_addr_hi = OPL_HI(mem->mem_start_address); 103925cf1a30Sjl139090 range.rg_addr_lo = OPL_LO(mem->mem_start_address); 104025cf1a30Sjl139090 range.rg_size_hi = OPL_HI(mem->mem_size); 104125cf1a30Sjl139090 range.rg_size_lo = OPL_LO(mem->mem_size); 104225cf1a30Sjl139090 OPL_UPDATE_PROP_ARRAY(int, node, "sb-mem-ranges", (int *)&range, 4); 104325cf1a30Sjl139090 104425cf1a30Sjl139090 bank = probe->pr_sb->sb_cmu.cmu_memory.mem_banks; 104525cf1a30Sjl139090 for (i = 0, j = 0; i < HWD_BANKS_PER_CMU; i++) { 104625cf1a30Sjl139090 104725cf1a30Sjl139090 if (!HWD_STATUS_OK(bank[i].bank_status)) 104825cf1a30Sjl139090 continue; 104925cf1a30Sjl139090 105025cf1a30Sjl139090 mc[j].mc_bank = i; 105125cf1a30Sjl139090 mc[j].mc_hi = OPL_HI(bank[i].bank_register_address); 105225cf1a30Sjl139090 mc[j].mc_lo = OPL_LO(bank[i].bank_register_address); 105325cf1a30Sjl139090 j++; 105425cf1a30Sjl139090 } 105568ac2337Sjl139090 105668ac2337Sjl139090 if (j > 0) { 105725cf1a30Sjl139090 OPL_UPDATE_PROP_ARRAY(int, node, "mc-addr", (int *)mc, j*3); 105868ac2337Sjl139090 } else { 105968ac2337Sjl139090 /* 106068ac2337Sjl139090 * If there is no memory, we need the mc-addr property, but 106168ac2337Sjl139090 * it is length 0. The only way to do this using ndi seems 106268ac2337Sjl139090 * to be by creating a boolean property. 106368ac2337Sjl139090 */ 106468ac2337Sjl139090 ret = ndi_prop_create_boolean(DDI_DEV_T_NONE, node, "mc-addr"); 106568ac2337Sjl139090 OPL_UPDATE_PROP_ERR(ret, "mc-addr"); 106668ac2337Sjl139090 } 106725cf1a30Sjl139090 106825cf1a30Sjl139090 OPL_UPDATE_PROP_ARRAY(byte, node, "cs0-mc-pa-trans-table", 106925cf1a30Sjl139090 mem->mem_cs[0].cs_pa_mac_table, 64); 107025cf1a30Sjl139090 OPL_UPDATE_PROP_ARRAY(byte, node, "cs1-mc-pa-trans-table", 107125cf1a30Sjl139090 mem->mem_cs[1].cs_pa_mac_table, 64); 107225cf1a30Sjl139090 107325cf1a30Sjl139090 #define CS_PER_MEM 2 107425cf1a30Sjl139090 107525cf1a30Sjl139090 for (i = 0, j = 0; i < CS_PER_MEM; i++) { 107625cf1a30Sjl139090 if (HWD_STATUS_OK(mem->mem_cs[i].cs_status) || 107725cf1a30Sjl139090 HWD_STATUS_FAILED(mem->mem_cs[i].cs_status)) { 107825cf1a30Sjl139090 status[j][0] = i; 107925cf1a30Sjl139090 if (HWD_STATUS_OK(mem->mem_cs[i].cs_status)) 108025cf1a30Sjl139090 status[j][1] = 0; 108125cf1a30Sjl139090 else 108225cf1a30Sjl139090 status[j][1] = 1; 108325cf1a30Sjl139090 status[j][2] = 108425cf1a30Sjl139090 OPL_HI(mem->mem_cs[i].cs_available_capacity); 108525cf1a30Sjl139090 status[j][3] = 108625cf1a30Sjl139090 OPL_LO(mem->mem_cs[i].cs_available_capacity); 108725cf1a30Sjl139090 status[j][4] = OPL_HI(mem->mem_cs[i].cs_dimm_capacity); 108825cf1a30Sjl139090 status[j][5] = OPL_LO(mem->mem_cs[i].cs_dimm_capacity); 108925cf1a30Sjl139090 status[j][6] = mem->mem_cs[i].cs_number_of_dimms; 109025cf1a30Sjl139090 j++; 109125cf1a30Sjl139090 } 109225cf1a30Sjl139090 } 109368ac2337Sjl139090 109468ac2337Sjl139090 if (j > 0) { 109525cf1a30Sjl139090 OPL_UPDATE_PROP_ARRAY(int, node, "cs-status", (int *)status, 109625cf1a30Sjl139090 j*7); 109768ac2337Sjl139090 } else { 109868ac2337Sjl139090 /* 109968ac2337Sjl139090 * If there is no memory, we need the cs-status property, but 110068ac2337Sjl139090 * it is length 0. The only way to do this using ndi seems 110168ac2337Sjl139090 * to be by creating a boolean property. 110268ac2337Sjl139090 */ 110368ac2337Sjl139090 ret = ndi_prop_create_boolean(DDI_DEV_T_NONE, node, 110468ac2337Sjl139090 "cs-status"); 110568ac2337Sjl139090 OPL_UPDATE_PROP_ERR(ret, "cs-status"); 110668ac2337Sjl139090 } 110725cf1a30Sjl139090 110825cf1a30Sjl139090 return (DDI_WALK_TERMINATE); 110925cf1a30Sjl139090 } 111025cf1a30Sjl139090 111125cf1a30Sjl139090 /* 111225cf1a30Sjl139090 * Create "pseudo-mc" nodes 111325cf1a30Sjl139090 */ 111425cf1a30Sjl139090 static int 111525cf1a30Sjl139090 opl_probe_memory(opl_probe_t *probe) 111625cf1a30Sjl139090 { 111725cf1a30Sjl139090 int board; 111825cf1a30Sjl139090 opl_board_cfg_t *board_cfg; 111925cf1a30Sjl139090 dev_info_t *node; 112025cf1a30Sjl139090 112125cf1a30Sjl139090 board = probe->pr_board; 112225cf1a30Sjl139090 board_cfg = &opl_boards[board]; 112325cf1a30Sjl139090 112425cf1a30Sjl139090 ASSERT(board_cfg->cfg_pseudo_mc == NULL); 112525cf1a30Sjl139090 112625cf1a30Sjl139090 probe->pr_parent = ddi_root_node(); 112725cf1a30Sjl139090 probe->pr_create = opl_create_pseudo_mc; 112825cf1a30Sjl139090 probe->pr_hold = 1; 112925cf1a30Sjl139090 node = opl_create_node(probe); 113025cf1a30Sjl139090 if (node == NULL) { 113125cf1a30Sjl139090 113225cf1a30Sjl139090 cmn_err(CE_WARN, "IKP: create pseudo-mc (%d) failed", board); 113325cf1a30Sjl139090 return (-1); 113425cf1a30Sjl139090 } 113525cf1a30Sjl139090 113625cf1a30Sjl139090 board_cfg->cfg_pseudo_mc = node; 113725cf1a30Sjl139090 113825cf1a30Sjl139090 return (0); 113925cf1a30Sjl139090 } 114025cf1a30Sjl139090 114125cf1a30Sjl139090 /* 114225cf1a30Sjl139090 * Allocate the fcode ops handle. 114325cf1a30Sjl139090 */ 114425cf1a30Sjl139090 /*ARGSUSED*/ 114525cf1a30Sjl139090 static 114625cf1a30Sjl139090 fco_handle_t 114725cf1a30Sjl139090 opl_fc_ops_alloc_handle(dev_info_t *parent, dev_info_t *child, 114825cf1a30Sjl139090 void *fcode, size_t fcode_size, char *unit_address, 114925cf1a30Sjl139090 char *my_args) 115025cf1a30Sjl139090 { 115125cf1a30Sjl139090 fco_handle_t rp; 115225cf1a30Sjl139090 phandle_t h; 115325cf1a30Sjl139090 char *buf; 115425cf1a30Sjl139090 115525cf1a30Sjl139090 rp = kmem_zalloc(sizeof (struct fc_resource_list), KM_SLEEP); 115625cf1a30Sjl139090 rp->next_handle = fc_ops_alloc_handle(parent, child, fcode, fcode_size, 115725cf1a30Sjl139090 unit_address, NULL); 115825cf1a30Sjl139090 rp->ap = parent; 115925cf1a30Sjl139090 rp->child = child; 116025cf1a30Sjl139090 rp->fcode = fcode; 116125cf1a30Sjl139090 rp->fcode_size = fcode_size; 116225cf1a30Sjl139090 rp->my_args = my_args; 116325cf1a30Sjl139090 116425cf1a30Sjl139090 if (unit_address) { 116525cf1a30Sjl139090 buf = kmem_zalloc(UNIT_ADDR_SIZE, KM_SLEEP); 116625cf1a30Sjl139090 (void) strcpy(buf, unit_address); 116725cf1a30Sjl139090 rp->unit_address = buf; 116825cf1a30Sjl139090 } 116925cf1a30Sjl139090 117025cf1a30Sjl139090 /* 117125cf1a30Sjl139090 * Add the child's nodeid to our table... 117225cf1a30Sjl139090 */ 117325cf1a30Sjl139090 h = ddi_get_nodeid(rp->child); 117425cf1a30Sjl139090 fc_add_dip_to_phandle(fc_handle_to_phandle_head(rp), rp->child, h); 117525cf1a30Sjl139090 117625cf1a30Sjl139090 return (rp); 117725cf1a30Sjl139090 } 117825cf1a30Sjl139090 117925cf1a30Sjl139090 118025cf1a30Sjl139090 static void 118125cf1a30Sjl139090 opl_fc_ops_free_handle(fco_handle_t rp) 118225cf1a30Sjl139090 { 118325cf1a30Sjl139090 struct fc_resource *resp, *nresp; 118425cf1a30Sjl139090 118525cf1a30Sjl139090 ASSERT(rp); 118625cf1a30Sjl139090 118725cf1a30Sjl139090 if (rp->next_handle) 118825cf1a30Sjl139090 fc_ops_free_handle(rp->next_handle); 118925cf1a30Sjl139090 if (rp->unit_address) 119025cf1a30Sjl139090 kmem_free(rp->unit_address, UNIT_ADDR_SIZE); 119125cf1a30Sjl139090 119225cf1a30Sjl139090 /* 119325cf1a30Sjl139090 * Release all the resources from the resource list 119425cf1a30Sjl139090 */ 119525cf1a30Sjl139090 for (resp = rp->head; resp != NULL; resp = nresp) { 119625cf1a30Sjl139090 nresp = resp->next; 119725cf1a30Sjl139090 switch (resp->type) { 119825cf1a30Sjl139090 119925cf1a30Sjl139090 case RT_MAP: 120068ac2337Sjl139090 /* 120168ac2337Sjl139090 * If this is still mapped, we'd better unmap it now, 120268ac2337Sjl139090 * or all our structures that are tracking it will 120368ac2337Sjl139090 * be leaked. 120468ac2337Sjl139090 */ 120568ac2337Sjl139090 if (resp->fc_map_handle != NULL) 120668ac2337Sjl139090 opl_unmap_phys(&resp->fc_map_handle); 120725cf1a30Sjl139090 break; 120825cf1a30Sjl139090 120925cf1a30Sjl139090 case RT_DMA: 121025cf1a30Sjl139090 /* 121125cf1a30Sjl139090 * DMA has to be freed up at exit time. 121225cf1a30Sjl139090 */ 121325cf1a30Sjl139090 cmn_err(CE_CONT, 121425cf1a30Sjl139090 "opl_fc_ops_free_handle: Unexpected DMA seen!"); 121525cf1a30Sjl139090 break; 121625cf1a30Sjl139090 121725cf1a30Sjl139090 case RT_CONTIGIOUS: 121825cf1a30Sjl139090 FC_DEBUG2(1, CE_CONT, "opl_fc_ops_free: " 121925cf1a30Sjl139090 "Free claim-memory resource 0x%lx size 0x%x\n", 122025cf1a30Sjl139090 resp->fc_contig_virt, resp->fc_contig_len); 122125cf1a30Sjl139090 122225cf1a30Sjl139090 (void) ndi_ra_free(ddi_root_node(), 122325cf1a30Sjl139090 (uint64_t)resp->fc_contig_virt, 122425cf1a30Sjl139090 resp->fc_contig_len, "opl-fcodemem", 122525cf1a30Sjl139090 NDI_RA_PASS); 122625cf1a30Sjl139090 122725cf1a30Sjl139090 break; 122825cf1a30Sjl139090 122925cf1a30Sjl139090 default: 123025cf1a30Sjl139090 cmn_err(CE_CONT, "opl_fc_ops_free: " 123125cf1a30Sjl139090 "unknown resource type %d", resp->type); 123225cf1a30Sjl139090 break; 123325cf1a30Sjl139090 } 123425cf1a30Sjl139090 fc_rem_resource(rp, resp); 123525cf1a30Sjl139090 kmem_free(resp, sizeof (struct fc_resource)); 123625cf1a30Sjl139090 } 123725cf1a30Sjl139090 123825cf1a30Sjl139090 kmem_free(rp, sizeof (struct fc_resource_list)); 123925cf1a30Sjl139090 } 124025cf1a30Sjl139090 124125cf1a30Sjl139090 int 124225cf1a30Sjl139090 opl_fc_do_op(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 124325cf1a30Sjl139090 { 124425cf1a30Sjl139090 opl_fc_ops_t *op; 124525cf1a30Sjl139090 char *service = fc_cell2ptr(cp->svc_name); 124625cf1a30Sjl139090 124725cf1a30Sjl139090 ASSERT(rp); 124825cf1a30Sjl139090 124925cf1a30Sjl139090 FC_DEBUG1(1, CE_CONT, "opl_fc_do_op: <%s>\n", service); 125025cf1a30Sjl139090 125125cf1a30Sjl139090 /* 125225cf1a30Sjl139090 * First try the generic fc_ops. 125325cf1a30Sjl139090 */ 125425cf1a30Sjl139090 if (fc_ops(ap, rp->next_handle, cp) == 0) 125525cf1a30Sjl139090 return (0); 125625cf1a30Sjl139090 125725cf1a30Sjl139090 /* 125825cf1a30Sjl139090 * Now try the Jupiter-specific ops. 125925cf1a30Sjl139090 */ 126025cf1a30Sjl139090 for (op = opl_fc_ops; op->fc_service != NULL; ++op) 126125cf1a30Sjl139090 if (strcmp(op->fc_service, service) == 0) 126225cf1a30Sjl139090 return (op->fc_op(ap, rp, cp)); 126325cf1a30Sjl139090 126425cf1a30Sjl139090 FC_DEBUG1(9, CE_CONT, "opl_fc_do_op: <%s> not serviced\n", service); 126525cf1a30Sjl139090 126625cf1a30Sjl139090 return (-1); 126725cf1a30Sjl139090 } 126825cf1a30Sjl139090 126925cf1a30Sjl139090 /* 127025cf1a30Sjl139090 * map-in (phys.lo phys.hi size -- virt) 127125cf1a30Sjl139090 */ 127225cf1a30Sjl139090 static int 127325cf1a30Sjl139090 opl_map_in(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 127425cf1a30Sjl139090 { 127525cf1a30Sjl139090 size_t len; 127625cf1a30Sjl139090 int error; 127725cf1a30Sjl139090 caddr_t virt; 127825cf1a30Sjl139090 struct fc_resource *resp; 127925cf1a30Sjl139090 struct regspec rspec; 128025cf1a30Sjl139090 ddi_device_acc_attr_t acc; 128125cf1a30Sjl139090 ddi_acc_handle_t h; 128225cf1a30Sjl139090 128325cf1a30Sjl139090 if (fc_cell2int(cp->nargs) != 3) 128425cf1a30Sjl139090 return (fc_syntax_error(cp, "nargs must be 3")); 128525cf1a30Sjl139090 128625cf1a30Sjl139090 if (fc_cell2int(cp->nresults) < 1) 128725cf1a30Sjl139090 return (fc_syntax_error(cp, "nresults must be >= 1")); 128825cf1a30Sjl139090 128925cf1a30Sjl139090 rspec.regspec_size = len = fc_cell2size(fc_arg(cp, 0)); 129025cf1a30Sjl139090 rspec.regspec_bustype = fc_cell2uint(fc_arg(cp, 1)); 129125cf1a30Sjl139090 rspec.regspec_addr = fc_cell2uint(fc_arg(cp, 2)); 129225cf1a30Sjl139090 129325cf1a30Sjl139090 acc.devacc_attr_version = DDI_DEVICE_ATTR_V0; 129425cf1a30Sjl139090 acc.devacc_attr_endian_flags = DDI_STRUCTURE_BE_ACC; 129525cf1a30Sjl139090 acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 129625cf1a30Sjl139090 129725cf1a30Sjl139090 FC_DEBUG3(1, CE_CONT, "opl_map_in: attempting map in " 129825cf1a30Sjl139090 "address 0x%08x.%08x length %x\n", rspec.regspec_bustype, 129925cf1a30Sjl139090 rspec.regspec_addr, rspec.regspec_size); 130025cf1a30Sjl139090 130125cf1a30Sjl139090 error = opl_map_phys(rp->child, &rspec, &virt, &acc, &h); 130225cf1a30Sjl139090 130325cf1a30Sjl139090 if (error) { 130425cf1a30Sjl139090 FC_DEBUG3(1, CE_CONT, "opl_map_in: map in failed - " 130525cf1a30Sjl139090 "address 0x%08x.%08x length %x\n", rspec.regspec_bustype, 130625cf1a30Sjl139090 rspec.regspec_addr, rspec.regspec_size); 130725cf1a30Sjl139090 130825cf1a30Sjl139090 return (fc_priv_error(cp, "opl map-in failed")); 130925cf1a30Sjl139090 } 131025cf1a30Sjl139090 131125cf1a30Sjl139090 FC_DEBUG1(3, CE_CONT, "opl_map_in: returning virt %p\n", virt); 131225cf1a30Sjl139090 131325cf1a30Sjl139090 cp->nresults = fc_int2cell(1); 131425cf1a30Sjl139090 fc_result(cp, 0) = fc_ptr2cell(virt); 131525cf1a30Sjl139090 131625cf1a30Sjl139090 /* 131725cf1a30Sjl139090 * Log this resource ... 131825cf1a30Sjl139090 */ 131925cf1a30Sjl139090 resp = kmem_zalloc(sizeof (struct fc_resource), KM_SLEEP); 132025cf1a30Sjl139090 resp->type = RT_MAP; 132125cf1a30Sjl139090 resp->fc_map_virt = virt; 132225cf1a30Sjl139090 resp->fc_map_len = len; 132325cf1a30Sjl139090 resp->fc_map_handle = h; 132425cf1a30Sjl139090 fc_add_resource(rp, resp); 132525cf1a30Sjl139090 132625cf1a30Sjl139090 return (fc_success_op(ap, rp, cp)); 132725cf1a30Sjl139090 } 132825cf1a30Sjl139090 132925cf1a30Sjl139090 /* 133025cf1a30Sjl139090 * map-out (virt size -- ) 133125cf1a30Sjl139090 */ 133225cf1a30Sjl139090 static int 133325cf1a30Sjl139090 opl_map_out(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 133425cf1a30Sjl139090 { 133525cf1a30Sjl139090 caddr_t virt; 133625cf1a30Sjl139090 size_t len; 133725cf1a30Sjl139090 struct fc_resource *resp; 133825cf1a30Sjl139090 133925cf1a30Sjl139090 if (fc_cell2int(cp->nargs) != 2) 134025cf1a30Sjl139090 return (fc_syntax_error(cp, "nargs must be 2")); 134125cf1a30Sjl139090 134225cf1a30Sjl139090 virt = fc_cell2ptr(fc_arg(cp, 1)); 134325cf1a30Sjl139090 134425cf1a30Sjl139090 len = fc_cell2size(fc_arg(cp, 0)); 134525cf1a30Sjl139090 134625cf1a30Sjl139090 FC_DEBUG2(1, CE_CONT, "opl_map_out: attempting map out %p %x\n", 134725cf1a30Sjl139090 virt, len); 134825cf1a30Sjl139090 134925cf1a30Sjl139090 /* 135025cf1a30Sjl139090 * Find if this request matches a mapping resource we set up. 135125cf1a30Sjl139090 */ 135225cf1a30Sjl139090 fc_lock_resource_list(rp); 135325cf1a30Sjl139090 for (resp = rp->head; resp != NULL; resp = resp->next) { 135425cf1a30Sjl139090 if (resp->type != RT_MAP) 135525cf1a30Sjl139090 continue; 135625cf1a30Sjl139090 if (resp->fc_map_virt != virt) 135725cf1a30Sjl139090 continue; 135825cf1a30Sjl139090 if (resp->fc_map_len == len) 135925cf1a30Sjl139090 break; 136025cf1a30Sjl139090 } 136125cf1a30Sjl139090 fc_unlock_resource_list(rp); 136225cf1a30Sjl139090 136325cf1a30Sjl139090 if (resp == NULL) 136425cf1a30Sjl139090 return (fc_priv_error(cp, "request doesn't match a " 136525cf1a30Sjl139090 "known mapping")); 136625cf1a30Sjl139090 136725cf1a30Sjl139090 opl_unmap_phys(&resp->fc_map_handle); 136825cf1a30Sjl139090 136925cf1a30Sjl139090 /* 137025cf1a30Sjl139090 * remove the resource from the list and release it. 137125cf1a30Sjl139090 */ 137225cf1a30Sjl139090 fc_rem_resource(rp, resp); 137325cf1a30Sjl139090 kmem_free(resp, sizeof (struct fc_resource)); 137425cf1a30Sjl139090 137525cf1a30Sjl139090 cp->nresults = fc_int2cell(0); 137625cf1a30Sjl139090 return (fc_success_op(ap, rp, cp)); 137725cf1a30Sjl139090 } 137825cf1a30Sjl139090 137925cf1a30Sjl139090 static int 138025cf1a30Sjl139090 opl_register_fetch(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 138125cf1a30Sjl139090 { 138225cf1a30Sjl139090 size_t len; 138325cf1a30Sjl139090 caddr_t virt; 138425cf1a30Sjl139090 int error = 0; 138525cf1a30Sjl139090 uint64_t v; 138625cf1a30Sjl139090 uint64_t x; 138725cf1a30Sjl139090 uint32_t l; 138825cf1a30Sjl139090 uint16_t w; 138925cf1a30Sjl139090 uint8_t b; 139025cf1a30Sjl139090 char *service = fc_cell2ptr(cp->svc_name); 139125cf1a30Sjl139090 struct fc_resource *resp; 139225cf1a30Sjl139090 139325cf1a30Sjl139090 if (fc_cell2int(cp->nargs) != 1) 139425cf1a30Sjl139090 return (fc_syntax_error(cp, "nargs must be 1")); 139525cf1a30Sjl139090 139625cf1a30Sjl139090 if (fc_cell2int(cp->nresults) < 1) 139725cf1a30Sjl139090 return (fc_syntax_error(cp, "nresults must be >= 1")); 139825cf1a30Sjl139090 139925cf1a30Sjl139090 virt = fc_cell2ptr(fc_arg(cp, 0)); 140025cf1a30Sjl139090 140125cf1a30Sjl139090 /* 140225cf1a30Sjl139090 * Determine the access width .. we can switch on the 2nd 140325cf1a30Sjl139090 * character of the name which is "rx@", "rl@", "rb@" or "rw@" 140425cf1a30Sjl139090 */ 140525cf1a30Sjl139090 switch (*(service + 1)) { 140625cf1a30Sjl139090 case 'x': len = sizeof (x); break; 140725cf1a30Sjl139090 case 'l': len = sizeof (l); break; 140825cf1a30Sjl139090 case 'w': len = sizeof (w); break; 140925cf1a30Sjl139090 case 'b': len = sizeof (b); break; 141025cf1a30Sjl139090 } 141125cf1a30Sjl139090 141225cf1a30Sjl139090 /* 141325cf1a30Sjl139090 * Check the alignment ... 141425cf1a30Sjl139090 */ 141525cf1a30Sjl139090 if (((intptr_t)virt & (len - 1)) != 0) 141625cf1a30Sjl139090 return (fc_priv_error(cp, "unaligned access")); 141725cf1a30Sjl139090 141825cf1a30Sjl139090 /* 141925cf1a30Sjl139090 * Find if this virt is 'within' a request we know about 142025cf1a30Sjl139090 */ 142125cf1a30Sjl139090 fc_lock_resource_list(rp); 142225cf1a30Sjl139090 for (resp = rp->head; resp != NULL; resp = resp->next) { 142325cf1a30Sjl139090 if (resp->type == RT_MAP) { 142425cf1a30Sjl139090 if ((virt >= (caddr_t)resp->fc_map_virt) && 142525cf1a30Sjl139090 ((virt + len) <= 142625cf1a30Sjl139090 ((caddr_t)resp->fc_map_virt + resp->fc_map_len))) 142725cf1a30Sjl139090 break; 142825cf1a30Sjl139090 } else if (resp->type == RT_CONTIGIOUS) { 1429e98fafb9Sjl139090 if ((virt >= (caddr_t)resp->fc_contig_virt) && 1430e98fafb9Sjl139090 ((virt + len) <= ((caddr_t)resp->fc_contig_virt + 143125cf1a30Sjl139090 resp->fc_contig_len))) 143225cf1a30Sjl139090 break; 143325cf1a30Sjl139090 } 143425cf1a30Sjl139090 } 143525cf1a30Sjl139090 fc_unlock_resource_list(rp); 143625cf1a30Sjl139090 143725cf1a30Sjl139090 if (resp == NULL) { 143825cf1a30Sjl139090 return (fc_priv_error(cp, "request not within " 143925cf1a30Sjl139090 "known mappings")); 144025cf1a30Sjl139090 } 144125cf1a30Sjl139090 144225cf1a30Sjl139090 switch (len) { 144325cf1a30Sjl139090 case sizeof (x): 144425cf1a30Sjl139090 if (resp->type == RT_MAP) 1445e98fafb9Sjl139090 error = ddi_peek64(rp->child, (int64_t *)virt, 1446e98fafb9Sjl139090 (int64_t *)&x); 144725cf1a30Sjl139090 else /* RT_CONTIGIOUS */ 144825cf1a30Sjl139090 x = *(int64_t *)virt; 144925cf1a30Sjl139090 v = x; 145025cf1a30Sjl139090 break; 145125cf1a30Sjl139090 case sizeof (l): 145225cf1a30Sjl139090 if (resp->type == RT_MAP) 1453e98fafb9Sjl139090 error = ddi_peek32(rp->child, (int32_t *)virt, 1454e98fafb9Sjl139090 (int32_t *)&l); 145525cf1a30Sjl139090 else /* RT_CONTIGIOUS */ 145625cf1a30Sjl139090 l = *(int32_t *)virt; 145725cf1a30Sjl139090 v = l; 145825cf1a30Sjl139090 break; 145925cf1a30Sjl139090 case sizeof (w): 146025cf1a30Sjl139090 if (resp->type == RT_MAP) 1461e98fafb9Sjl139090 error = ddi_peek16(rp->child, (int16_t *)virt, 1462e98fafb9Sjl139090 (int16_t *)&w); 146325cf1a30Sjl139090 else /* RT_CONTIGIOUS */ 146425cf1a30Sjl139090 w = *(int16_t *)virt; 146525cf1a30Sjl139090 v = w; 146625cf1a30Sjl139090 break; 146725cf1a30Sjl139090 case sizeof (b): 146825cf1a30Sjl139090 if (resp->type == RT_MAP) 1469e98fafb9Sjl139090 error = ddi_peek8(rp->child, (int8_t *)virt, 1470e98fafb9Sjl139090 (int8_t *)&b); 147125cf1a30Sjl139090 else /* RT_CONTIGIOUS */ 147225cf1a30Sjl139090 b = *(int8_t *)virt; 147325cf1a30Sjl139090 v = b; 147425cf1a30Sjl139090 break; 147525cf1a30Sjl139090 } 147625cf1a30Sjl139090 147725cf1a30Sjl139090 if (error == DDI_FAILURE) { 147825cf1a30Sjl139090 FC_DEBUG2(1, CE_CONT, "opl_register_fetch: access error " 147925cf1a30Sjl139090 "accessing virt %p len %d\n", virt, len); 148025cf1a30Sjl139090 return (fc_priv_error(cp, "access error")); 148125cf1a30Sjl139090 } 148225cf1a30Sjl139090 148325cf1a30Sjl139090 FC_DEBUG3(1, CE_CONT, "register_fetch (%s) %llx %llx\n", 148425cf1a30Sjl139090 service, virt, v); 148525cf1a30Sjl139090 148625cf1a30Sjl139090 cp->nresults = fc_int2cell(1); 148725cf1a30Sjl139090 switch (len) { 148825cf1a30Sjl139090 case sizeof (x): fc_result(cp, 0) = x; break; 148925cf1a30Sjl139090 case sizeof (l): fc_result(cp, 0) = fc_uint32_t2cell(l); break; 149025cf1a30Sjl139090 case sizeof (w): fc_result(cp, 0) = fc_uint16_t2cell(w); break; 149125cf1a30Sjl139090 case sizeof (b): fc_result(cp, 0) = fc_uint8_t2cell(b); break; 149225cf1a30Sjl139090 } 149325cf1a30Sjl139090 return (fc_success_op(ap, rp, cp)); 149425cf1a30Sjl139090 } 149525cf1a30Sjl139090 149625cf1a30Sjl139090 static int 149725cf1a30Sjl139090 opl_register_store(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 149825cf1a30Sjl139090 { 149925cf1a30Sjl139090 size_t len; 150025cf1a30Sjl139090 caddr_t virt; 150125cf1a30Sjl139090 uint64_t v; 150225cf1a30Sjl139090 uint64_t x; 150325cf1a30Sjl139090 uint32_t l; 150425cf1a30Sjl139090 uint16_t w; 150525cf1a30Sjl139090 uint8_t b; 150625cf1a30Sjl139090 char *service = fc_cell2ptr(cp->svc_name); 150725cf1a30Sjl139090 struct fc_resource *resp; 150825cf1a30Sjl139090 int error = 0; 150925cf1a30Sjl139090 151025cf1a30Sjl139090 if (fc_cell2int(cp->nargs) != 2) 151125cf1a30Sjl139090 return (fc_syntax_error(cp, "nargs must be 2")); 151225cf1a30Sjl139090 151325cf1a30Sjl139090 virt = fc_cell2ptr(fc_arg(cp, 0)); 151425cf1a30Sjl139090 151525cf1a30Sjl139090 /* 151625cf1a30Sjl139090 * Determine the access width .. we can switch on the 2nd 151725cf1a30Sjl139090 * character of the name which is "rx!", "rl!", "rb!" or "rw!" 151825cf1a30Sjl139090 */ 151925cf1a30Sjl139090 switch (*(service + 1)) { 152025cf1a30Sjl139090 case 'x': 152125cf1a30Sjl139090 len = sizeof (x); 152225cf1a30Sjl139090 x = fc_arg(cp, 1); 152325cf1a30Sjl139090 v = x; 152425cf1a30Sjl139090 break; 152525cf1a30Sjl139090 case 'l': 152625cf1a30Sjl139090 len = sizeof (l); 152725cf1a30Sjl139090 l = fc_cell2uint32_t(fc_arg(cp, 1)); 152825cf1a30Sjl139090 v = l; 152925cf1a30Sjl139090 break; 153025cf1a30Sjl139090 case 'w': 153125cf1a30Sjl139090 len = sizeof (w); 153225cf1a30Sjl139090 w = fc_cell2uint16_t(fc_arg(cp, 1)); 153325cf1a30Sjl139090 v = w; 153425cf1a30Sjl139090 break; 153525cf1a30Sjl139090 case 'b': 153625cf1a30Sjl139090 len = sizeof (b); 153725cf1a30Sjl139090 b = fc_cell2uint8_t(fc_arg(cp, 1)); 153825cf1a30Sjl139090 v = b; 153925cf1a30Sjl139090 break; 154025cf1a30Sjl139090 } 154125cf1a30Sjl139090 154225cf1a30Sjl139090 FC_DEBUG3(1, CE_CONT, "register_store (%s) %llx %llx\n", 154325cf1a30Sjl139090 service, virt, v); 154425cf1a30Sjl139090 154525cf1a30Sjl139090 /* 154625cf1a30Sjl139090 * Check the alignment ... 154725cf1a30Sjl139090 */ 154825cf1a30Sjl139090 if (((intptr_t)virt & (len - 1)) != 0) 154925cf1a30Sjl139090 return (fc_priv_error(cp, "unaligned access")); 155025cf1a30Sjl139090 155125cf1a30Sjl139090 /* 155225cf1a30Sjl139090 * Find if this virt is 'within' a request we know about 155325cf1a30Sjl139090 */ 155425cf1a30Sjl139090 fc_lock_resource_list(rp); 155525cf1a30Sjl139090 for (resp = rp->head; resp != NULL; resp = resp->next) { 155625cf1a30Sjl139090 if (resp->type == RT_MAP) { 155725cf1a30Sjl139090 if ((virt >= (caddr_t)resp->fc_map_virt) && 155825cf1a30Sjl139090 ((virt + len) <= 155925cf1a30Sjl139090 ((caddr_t)resp->fc_map_virt + resp->fc_map_len))) 156025cf1a30Sjl139090 break; 156125cf1a30Sjl139090 } else if (resp->type == RT_CONTIGIOUS) { 1562e98fafb9Sjl139090 if ((virt >= (caddr_t)resp->fc_contig_virt) && 1563e98fafb9Sjl139090 ((virt + len) <= ((caddr_t)resp->fc_contig_virt + 156425cf1a30Sjl139090 resp->fc_contig_len))) 156525cf1a30Sjl139090 break; 156625cf1a30Sjl139090 } 156725cf1a30Sjl139090 } 156825cf1a30Sjl139090 fc_unlock_resource_list(rp); 156925cf1a30Sjl139090 157025cf1a30Sjl139090 if (resp == NULL) 157125cf1a30Sjl139090 return (fc_priv_error(cp, "request not within" 157225cf1a30Sjl139090 "known mappings")); 157325cf1a30Sjl139090 157425cf1a30Sjl139090 switch (len) { 157525cf1a30Sjl139090 case sizeof (x): 157625cf1a30Sjl139090 if (resp->type == RT_MAP) 157725cf1a30Sjl139090 error = ddi_poke64(rp->child, (int64_t *)virt, x); 157825cf1a30Sjl139090 else if (resp->type == RT_CONTIGIOUS) 157925cf1a30Sjl139090 *(uint64_t *)virt = x; 158025cf1a30Sjl139090 break; 158125cf1a30Sjl139090 case sizeof (l): 158225cf1a30Sjl139090 if (resp->type == RT_MAP) 158325cf1a30Sjl139090 error = ddi_poke32(rp->child, (int32_t *)virt, l); 158425cf1a30Sjl139090 else if (resp->type == RT_CONTIGIOUS) 158525cf1a30Sjl139090 *(uint32_t *)virt = l; 158625cf1a30Sjl139090 break; 158725cf1a30Sjl139090 case sizeof (w): 158825cf1a30Sjl139090 if (resp->type == RT_MAP) 158925cf1a30Sjl139090 error = ddi_poke16(rp->child, (int16_t *)virt, w); 159025cf1a30Sjl139090 else if (resp->type == RT_CONTIGIOUS) 159125cf1a30Sjl139090 *(uint16_t *)virt = w; 159225cf1a30Sjl139090 break; 159325cf1a30Sjl139090 case sizeof (b): 159425cf1a30Sjl139090 if (resp->type == RT_MAP) 159525cf1a30Sjl139090 error = ddi_poke8(rp->child, (int8_t *)virt, b); 159625cf1a30Sjl139090 else if (resp->type == RT_CONTIGIOUS) 159725cf1a30Sjl139090 *(uint8_t *)virt = b; 159825cf1a30Sjl139090 break; 159925cf1a30Sjl139090 } 160025cf1a30Sjl139090 160125cf1a30Sjl139090 if (error == DDI_FAILURE) { 160225cf1a30Sjl139090 FC_DEBUG2(1, CE_CONT, "opl_register_store: access error " 160325cf1a30Sjl139090 "accessing virt %p len %d\n", virt, len); 160425cf1a30Sjl139090 return (fc_priv_error(cp, "access error")); 160525cf1a30Sjl139090 } 160625cf1a30Sjl139090 160725cf1a30Sjl139090 cp->nresults = fc_int2cell(0); 160825cf1a30Sjl139090 return (fc_success_op(ap, rp, cp)); 160925cf1a30Sjl139090 } 161025cf1a30Sjl139090 161125cf1a30Sjl139090 /* 161225cf1a30Sjl139090 * opl_claim_memory 161325cf1a30Sjl139090 * 161425cf1a30Sjl139090 * claim-memory (align size vhint -- vaddr) 161525cf1a30Sjl139090 */ 161625cf1a30Sjl139090 static int 161725cf1a30Sjl139090 opl_claim_memory(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 161825cf1a30Sjl139090 { 161925cf1a30Sjl139090 int align, size, vhint; 162025cf1a30Sjl139090 uint64_t answer, alen; 162125cf1a30Sjl139090 ndi_ra_request_t request; 162225cf1a30Sjl139090 struct fc_resource *resp; 162325cf1a30Sjl139090 162425cf1a30Sjl139090 if (fc_cell2int(cp->nargs) != 3) 162525cf1a30Sjl139090 return (fc_syntax_error(cp, "nargs must be 3")); 162625cf1a30Sjl139090 162725cf1a30Sjl139090 if (fc_cell2int(cp->nresults) < 1) 162825cf1a30Sjl139090 return (fc_syntax_error(cp, "nresults must be >= 1")); 162925cf1a30Sjl139090 163025cf1a30Sjl139090 vhint = fc_cell2int(fc_arg(cp, 2)); 163125cf1a30Sjl139090 size = fc_cell2int(fc_arg(cp, 1)); 163225cf1a30Sjl139090 align = fc_cell2int(fc_arg(cp, 0)); 163325cf1a30Sjl139090 163425cf1a30Sjl139090 FC_DEBUG3(1, CE_CONT, "opl_claim_memory: align=0x%x size=0x%x " 163525cf1a30Sjl139090 "vhint=0x%x\n", align, size, vhint); 163625cf1a30Sjl139090 163725cf1a30Sjl139090 if (size == 0) { 163825cf1a30Sjl139090 cmn_err(CE_WARN, "opl_claim_memory - unable to allocate " 163925cf1a30Sjl139090 "contiguous memory of size zero\n"); 164025cf1a30Sjl139090 return (fc_priv_error(cp, "allocation error")); 164125cf1a30Sjl139090 } 164225cf1a30Sjl139090 164325cf1a30Sjl139090 if (vhint) { 164425cf1a30Sjl139090 cmn_err(CE_WARN, "opl_claim_memory - vhint is not zero " 164525cf1a30Sjl139090 "vhint=0x%x - Ignoring Argument\n", vhint); 164625cf1a30Sjl139090 } 164725cf1a30Sjl139090 164825cf1a30Sjl139090 bzero((caddr_t)&request, sizeof (ndi_ra_request_t)); 164925cf1a30Sjl139090 request.ra_flags = NDI_RA_ALLOC_BOUNDED; 165025cf1a30Sjl139090 request.ra_boundbase = 0; 165125cf1a30Sjl139090 request.ra_boundlen = 0xffffffff; 165225cf1a30Sjl139090 request.ra_len = size; 165325cf1a30Sjl139090 request.ra_align_mask = align - 1; 165425cf1a30Sjl139090 165525cf1a30Sjl139090 if (ndi_ra_alloc(ddi_root_node(), &request, &answer, &alen, 165625cf1a30Sjl139090 "opl-fcodemem", NDI_RA_PASS) != NDI_SUCCESS) { 165725cf1a30Sjl139090 cmn_err(CE_WARN, "opl_claim_memory - unable to allocate " 165825cf1a30Sjl139090 "contiguous memory\n"); 165925cf1a30Sjl139090 return (fc_priv_error(cp, "allocation error")); 166025cf1a30Sjl139090 } 166125cf1a30Sjl139090 166225cf1a30Sjl139090 FC_DEBUG2(1, CE_CONT, "opl_claim_memory: address allocated=0x%lx " 166325cf1a30Sjl139090 "size=0x%x\n", answer, alen); 166425cf1a30Sjl139090 166525cf1a30Sjl139090 cp->nresults = fc_int2cell(1); 166625cf1a30Sjl139090 fc_result(cp, 0) = answer; 166725cf1a30Sjl139090 166825cf1a30Sjl139090 /* 166925cf1a30Sjl139090 * Log this resource ... 167025cf1a30Sjl139090 */ 167125cf1a30Sjl139090 resp = kmem_zalloc(sizeof (struct fc_resource), KM_SLEEP); 167225cf1a30Sjl139090 resp->type = RT_CONTIGIOUS; 167325cf1a30Sjl139090 resp->fc_contig_virt = (void *)answer; 167425cf1a30Sjl139090 resp->fc_contig_len = size; 167525cf1a30Sjl139090 fc_add_resource(rp, resp); 167625cf1a30Sjl139090 167725cf1a30Sjl139090 return (fc_success_op(ap, rp, cp)); 167825cf1a30Sjl139090 } 167925cf1a30Sjl139090 168025cf1a30Sjl139090 /* 168125cf1a30Sjl139090 * opl_release_memory 168225cf1a30Sjl139090 * 168325cf1a30Sjl139090 * release-memory (size vaddr -- ) 168425cf1a30Sjl139090 */ 168525cf1a30Sjl139090 static int 168625cf1a30Sjl139090 opl_release_memory(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 168725cf1a30Sjl139090 { 168825cf1a30Sjl139090 int32_t vaddr, size; 168925cf1a30Sjl139090 struct fc_resource *resp; 169025cf1a30Sjl139090 169125cf1a30Sjl139090 if (fc_cell2int(cp->nargs) != 2) 169225cf1a30Sjl139090 return (fc_syntax_error(cp, "nargs must be 2")); 169325cf1a30Sjl139090 169425cf1a30Sjl139090 if (fc_cell2int(cp->nresults) != 0) 169525cf1a30Sjl139090 return (fc_syntax_error(cp, "nresults must be 0")); 169625cf1a30Sjl139090 169725cf1a30Sjl139090 vaddr = fc_cell2int(fc_arg(cp, 1)); 169825cf1a30Sjl139090 size = fc_cell2int(fc_arg(cp, 0)); 169925cf1a30Sjl139090 170025cf1a30Sjl139090 FC_DEBUG2(1, CE_CONT, "opl_release_memory: vaddr=0x%x size=0x%x\n", 170125cf1a30Sjl139090 vaddr, size); 170225cf1a30Sjl139090 170325cf1a30Sjl139090 /* 170425cf1a30Sjl139090 * Find if this request matches a mapping resource we set up. 170525cf1a30Sjl139090 */ 170625cf1a30Sjl139090 fc_lock_resource_list(rp); 170725cf1a30Sjl139090 for (resp = rp->head; resp != NULL; resp = resp->next) { 170825cf1a30Sjl139090 if (resp->type != RT_CONTIGIOUS) 170925cf1a30Sjl139090 continue; 171025cf1a30Sjl139090 if (resp->fc_contig_virt != (void *)(uintptr_t)vaddr) 171125cf1a30Sjl139090 continue; 171225cf1a30Sjl139090 if (resp->fc_contig_len == size) 171325cf1a30Sjl139090 break; 171425cf1a30Sjl139090 } 171525cf1a30Sjl139090 fc_unlock_resource_list(rp); 171625cf1a30Sjl139090 171725cf1a30Sjl139090 if (resp == NULL) 171825cf1a30Sjl139090 return (fc_priv_error(cp, "request doesn't match a " 171925cf1a30Sjl139090 "known mapping")); 172025cf1a30Sjl139090 172125cf1a30Sjl139090 (void) ndi_ra_free(ddi_root_node(), vaddr, size, 172225cf1a30Sjl139090 "opl-fcodemem", NDI_RA_PASS); 172325cf1a30Sjl139090 172425cf1a30Sjl139090 /* 172525cf1a30Sjl139090 * remove the resource from the list and release it. 172625cf1a30Sjl139090 */ 172725cf1a30Sjl139090 fc_rem_resource(rp, resp); 172825cf1a30Sjl139090 kmem_free(resp, sizeof (struct fc_resource)); 172925cf1a30Sjl139090 173025cf1a30Sjl139090 cp->nresults = fc_int2cell(0); 173125cf1a30Sjl139090 173225cf1a30Sjl139090 return (fc_success_op(ap, rp, cp)); 173325cf1a30Sjl139090 } 173425cf1a30Sjl139090 173525cf1a30Sjl139090 /* 173625cf1a30Sjl139090 * opl_vtop 173725cf1a30Sjl139090 * 173825cf1a30Sjl139090 * vtop (vaddr -- paddr.lo paddr.hi) 173925cf1a30Sjl139090 */ 174025cf1a30Sjl139090 static int 174125cf1a30Sjl139090 opl_vtop(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 174225cf1a30Sjl139090 { 174325cf1a30Sjl139090 int vaddr; 174425cf1a30Sjl139090 uint64_t paddr; 174525cf1a30Sjl139090 struct fc_resource *resp; 174625cf1a30Sjl139090 174725cf1a30Sjl139090 if (fc_cell2int(cp->nargs) != 1) 174825cf1a30Sjl139090 return (fc_syntax_error(cp, "nargs must be 1")); 174925cf1a30Sjl139090 175025cf1a30Sjl139090 if (fc_cell2int(cp->nresults) >= 3) 175125cf1a30Sjl139090 return (fc_syntax_error(cp, "nresults must be less than 2")); 175225cf1a30Sjl139090 175325cf1a30Sjl139090 vaddr = fc_cell2int(fc_arg(cp, 0)); 175425cf1a30Sjl139090 175525cf1a30Sjl139090 /* 175625cf1a30Sjl139090 * Find if this request matches a mapping resource we set up. 175725cf1a30Sjl139090 */ 175825cf1a30Sjl139090 fc_lock_resource_list(rp); 175925cf1a30Sjl139090 for (resp = rp->head; resp != NULL; resp = resp->next) { 176025cf1a30Sjl139090 if (resp->type != RT_CONTIGIOUS) 176125cf1a30Sjl139090 continue; 1762431161ebSbm42561 if (((uint64_t)resp->fc_contig_virt <= vaddr) && 1763431161ebSbm42561 (vaddr < (uint64_t)resp->fc_contig_virt + 1764431161ebSbm42561 resp->fc_contig_len)) 176525cf1a30Sjl139090 break; 176625cf1a30Sjl139090 } 176725cf1a30Sjl139090 fc_unlock_resource_list(rp); 176825cf1a30Sjl139090 176925cf1a30Sjl139090 if (resp == NULL) 177025cf1a30Sjl139090 return (fc_priv_error(cp, "request doesn't match a " 177125cf1a30Sjl139090 "known mapping")); 177225cf1a30Sjl139090 177325cf1a30Sjl139090 paddr = va_to_pa((void *)(uintptr_t)vaddr); 177425cf1a30Sjl139090 177525cf1a30Sjl139090 FC_DEBUG2(1, CE_CONT, "opl_vtop: vaddr=0x%x paddr=0x%x\n", 177625cf1a30Sjl139090 vaddr, paddr); 177725cf1a30Sjl139090 177825cf1a30Sjl139090 cp->nresults = fc_int2cell(2); 177925cf1a30Sjl139090 178025cf1a30Sjl139090 fc_result(cp, 0) = paddr; 178125cf1a30Sjl139090 fc_result(cp, 1) = 0; 178225cf1a30Sjl139090 178325cf1a30Sjl139090 return (fc_success_op(ap, rp, cp)); 178425cf1a30Sjl139090 } 178525cf1a30Sjl139090 178625cf1a30Sjl139090 static int 178725cf1a30Sjl139090 opl_config_child(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 178825cf1a30Sjl139090 { 178925cf1a30Sjl139090 fc_phandle_t h; 179025cf1a30Sjl139090 179125cf1a30Sjl139090 if (fc_cell2int(cp->nargs) != 0) 179225cf1a30Sjl139090 return (fc_syntax_error(cp, "nargs must be 0")); 179325cf1a30Sjl139090 179425cf1a30Sjl139090 if (fc_cell2int(cp->nresults) < 1) 179525cf1a30Sjl139090 return (fc_syntax_error(cp, "nresults must be >= 1")); 179625cf1a30Sjl139090 179725cf1a30Sjl139090 h = fc_dip_to_phandle(fc_handle_to_phandle_head(rp), rp->child); 179825cf1a30Sjl139090 179925cf1a30Sjl139090 cp->nresults = fc_int2cell(1); 180025cf1a30Sjl139090 fc_result(cp, 0) = fc_phandle2cell(h); 180125cf1a30Sjl139090 180225cf1a30Sjl139090 return (fc_success_op(ap, rp, cp)); 180325cf1a30Sjl139090 } 180425cf1a30Sjl139090 180525cf1a30Sjl139090 static int 180625cf1a30Sjl139090 opl_get_fcode(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 180725cf1a30Sjl139090 { 180825cf1a30Sjl139090 caddr_t dropin_name_virt, fcode_virt; 180925cf1a30Sjl139090 char *dropin_name, *fcode; 181025cf1a30Sjl139090 int fcode_len, status; 181125cf1a30Sjl139090 181225cf1a30Sjl139090 if (fc_cell2int(cp->nargs) != 3) 181325cf1a30Sjl139090 return (fc_syntax_error(cp, "nargs must be 3")); 181425cf1a30Sjl139090 181525cf1a30Sjl139090 if (fc_cell2int(cp->nresults) < 1) 181625cf1a30Sjl139090 return (fc_syntax_error(cp, "nresults must be >= 1")); 181725cf1a30Sjl139090 181825cf1a30Sjl139090 dropin_name_virt = fc_cell2ptr(fc_arg(cp, 0)); 181925cf1a30Sjl139090 182025cf1a30Sjl139090 fcode_virt = fc_cell2ptr(fc_arg(cp, 1)); 182125cf1a30Sjl139090 182225cf1a30Sjl139090 fcode_len = fc_cell2int(fc_arg(cp, 2)); 182325cf1a30Sjl139090 182425cf1a30Sjl139090 dropin_name = kmem_zalloc(FC_SVC_NAME_LEN, KM_SLEEP); 182525cf1a30Sjl139090 182625cf1a30Sjl139090 FC_DEBUG2(1, CE_CONT, "get_fcode: %x %d\n", fcode_virt, fcode_len); 182725cf1a30Sjl139090 182825cf1a30Sjl139090 if (copyinstr(fc_cell2ptr(dropin_name_virt), dropin_name, 182925cf1a30Sjl139090 FC_SVC_NAME_LEN - 1, NULL)) { 183025cf1a30Sjl139090 FC_DEBUG1(1, CE_CONT, "opl_get_fcode: " 183125cf1a30Sjl139090 "fault copying in drop in name %p\n", dropin_name_virt); 183225cf1a30Sjl139090 status = 0; 183325cf1a30Sjl139090 } else { 183425cf1a30Sjl139090 FC_DEBUG1(1, CE_CONT, "get_fcode: %s\n", dropin_name); 183525cf1a30Sjl139090 183625cf1a30Sjl139090 fcode = kmem_zalloc(fcode_len, KM_SLEEP); 183725cf1a30Sjl139090 183825cf1a30Sjl139090 if ((status = prom_get_fcode(dropin_name, fcode)) != 0) { 183925cf1a30Sjl139090 184025cf1a30Sjl139090 if (copyout((void *)fcode, (void *)fcode_virt, 184125cf1a30Sjl139090 fcode_len)) { 184225cf1a30Sjl139090 cmn_err(CE_WARN, " opl_get_fcode: Unable " 184325cf1a30Sjl139090 "to copy out fcode image"); 184425cf1a30Sjl139090 status = 0; 184525cf1a30Sjl139090 } 184625cf1a30Sjl139090 } 184725cf1a30Sjl139090 184825cf1a30Sjl139090 kmem_free(fcode, fcode_len); 184925cf1a30Sjl139090 } 185025cf1a30Sjl139090 185125cf1a30Sjl139090 kmem_free(dropin_name, FC_SVC_NAME_LEN); 185225cf1a30Sjl139090 185325cf1a30Sjl139090 cp->nresults = fc_int2cell(1); 185425cf1a30Sjl139090 fc_result(cp, 0) = status; 185525cf1a30Sjl139090 185625cf1a30Sjl139090 return (fc_success_op(ap, rp, cp)); 185725cf1a30Sjl139090 } 185825cf1a30Sjl139090 185925cf1a30Sjl139090 static int 186025cf1a30Sjl139090 opl_get_fcode_size(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 186125cf1a30Sjl139090 { 186225cf1a30Sjl139090 caddr_t virt; 186325cf1a30Sjl139090 char *dropin_name; 186425cf1a30Sjl139090 int len; 186525cf1a30Sjl139090 186625cf1a30Sjl139090 if (fc_cell2int(cp->nargs) != 1) 186725cf1a30Sjl139090 return (fc_syntax_error(cp, "nargs must be 1")); 186825cf1a30Sjl139090 186925cf1a30Sjl139090 if (fc_cell2int(cp->nresults) < 1) 187025cf1a30Sjl139090 return (fc_syntax_error(cp, "nresults must be >= 1")); 187125cf1a30Sjl139090 187225cf1a30Sjl139090 virt = fc_cell2ptr(fc_arg(cp, 0)); 187325cf1a30Sjl139090 187425cf1a30Sjl139090 dropin_name = kmem_zalloc(FC_SVC_NAME_LEN, KM_SLEEP); 187525cf1a30Sjl139090 187625cf1a30Sjl139090 FC_DEBUG0(1, CE_CONT, "opl_get_fcode_size:\n"); 187725cf1a30Sjl139090 187825cf1a30Sjl139090 if (copyinstr(fc_cell2ptr(virt), dropin_name, 187925cf1a30Sjl139090 FC_SVC_NAME_LEN - 1, NULL)) { 188025cf1a30Sjl139090 FC_DEBUG1(1, CE_CONT, "opl_get_fcode_size: " 188125cf1a30Sjl139090 "fault copying in drop in name %p\n", virt); 188225cf1a30Sjl139090 len = 0; 188325cf1a30Sjl139090 } else { 188425cf1a30Sjl139090 FC_DEBUG1(1, CE_CONT, "opl_get_fcode_size: %s\n", dropin_name); 188525cf1a30Sjl139090 188625cf1a30Sjl139090 len = prom_get_fcode_size(dropin_name); 188725cf1a30Sjl139090 } 188825cf1a30Sjl139090 188925cf1a30Sjl139090 kmem_free(dropin_name, FC_SVC_NAME_LEN); 189025cf1a30Sjl139090 189125cf1a30Sjl139090 FC_DEBUG1(1, CE_CONT, "opl_get_fcode_size: fcode_len = %d\n", len); 189225cf1a30Sjl139090 189325cf1a30Sjl139090 cp->nresults = fc_int2cell(1); 189425cf1a30Sjl139090 fc_result(cp, 0) = len; 189525cf1a30Sjl139090 189625cf1a30Sjl139090 return (fc_success_op(ap, rp, cp)); 189725cf1a30Sjl139090 } 189825cf1a30Sjl139090 189925cf1a30Sjl139090 static int 190025cf1a30Sjl139090 opl_map_phys(dev_info_t *dip, struct regspec *phys_spec, 190125cf1a30Sjl139090 caddr_t *addrp, ddi_device_acc_attr_t *accattrp, 190225cf1a30Sjl139090 ddi_acc_handle_t *handlep) 190325cf1a30Sjl139090 { 190425cf1a30Sjl139090 ddi_map_req_t mapreq; 190525cf1a30Sjl139090 ddi_acc_hdl_t *acc_handlep; 190625cf1a30Sjl139090 int result; 190725cf1a30Sjl139090 struct regspec *rspecp; 190825cf1a30Sjl139090 190925cf1a30Sjl139090 *handlep = impl_acc_hdl_alloc(KM_SLEEP, NULL); 191025cf1a30Sjl139090 acc_handlep = impl_acc_hdl_get(*handlep); 191125cf1a30Sjl139090 acc_handlep->ah_vers = VERS_ACCHDL; 191225cf1a30Sjl139090 acc_handlep->ah_dip = dip; 191325cf1a30Sjl139090 acc_handlep->ah_rnumber = 0; 191425cf1a30Sjl139090 acc_handlep->ah_offset = 0; 191525cf1a30Sjl139090 acc_handlep->ah_len = 0; 191625cf1a30Sjl139090 acc_handlep->ah_acc = *accattrp; 191725cf1a30Sjl139090 rspecp = kmem_zalloc(sizeof (struct regspec), KM_SLEEP); 191825cf1a30Sjl139090 *rspecp = *phys_spec; 191925cf1a30Sjl139090 /* 192025cf1a30Sjl139090 * cache a copy of the reg spec 192125cf1a30Sjl139090 */ 192225cf1a30Sjl139090 acc_handlep->ah_bus_private = rspecp; 192325cf1a30Sjl139090 192425cf1a30Sjl139090 mapreq.map_op = DDI_MO_MAP_LOCKED; 192525cf1a30Sjl139090 mapreq.map_type = DDI_MT_REGSPEC; 192625cf1a30Sjl139090 mapreq.map_obj.rp = (struct regspec *)phys_spec; 192725cf1a30Sjl139090 mapreq.map_prot = PROT_READ | PROT_WRITE; 192825cf1a30Sjl139090 mapreq.map_flags = DDI_MF_KERNEL_MAPPING; 192925cf1a30Sjl139090 mapreq.map_handlep = acc_handlep; 193025cf1a30Sjl139090 mapreq.map_vers = DDI_MAP_VERSION; 193125cf1a30Sjl139090 193225cf1a30Sjl139090 result = ddi_map(dip, &mapreq, 0, 0, addrp); 193325cf1a30Sjl139090 193425cf1a30Sjl139090 if (result != DDI_SUCCESS) { 193525cf1a30Sjl139090 impl_acc_hdl_free(*handlep); 193668ac2337Sjl139090 kmem_free(rspecp, sizeof (struct regspec)); 193725cf1a30Sjl139090 *handlep = (ddi_acc_handle_t)NULL; 193825cf1a30Sjl139090 } else { 193925cf1a30Sjl139090 acc_handlep->ah_addr = *addrp; 194025cf1a30Sjl139090 } 194125cf1a30Sjl139090 194225cf1a30Sjl139090 return (result); 194325cf1a30Sjl139090 } 194425cf1a30Sjl139090 194525cf1a30Sjl139090 static void 194625cf1a30Sjl139090 opl_unmap_phys(ddi_acc_handle_t *handlep) 194725cf1a30Sjl139090 { 194825cf1a30Sjl139090 ddi_map_req_t mapreq; 194925cf1a30Sjl139090 ddi_acc_hdl_t *acc_handlep; 195025cf1a30Sjl139090 struct regspec *rspecp; 195125cf1a30Sjl139090 195225cf1a30Sjl139090 acc_handlep = impl_acc_hdl_get(*handlep); 195325cf1a30Sjl139090 ASSERT(acc_handlep); 195425cf1a30Sjl139090 rspecp = acc_handlep->ah_bus_private; 195525cf1a30Sjl139090 195625cf1a30Sjl139090 mapreq.map_op = DDI_MO_UNMAP; 195725cf1a30Sjl139090 mapreq.map_type = DDI_MT_REGSPEC; 195825cf1a30Sjl139090 mapreq.map_obj.rp = (struct regspec *)rspecp; 195925cf1a30Sjl139090 mapreq.map_prot = PROT_READ | PROT_WRITE; 196025cf1a30Sjl139090 mapreq.map_flags = DDI_MF_KERNEL_MAPPING; 196125cf1a30Sjl139090 mapreq.map_handlep = acc_handlep; 196225cf1a30Sjl139090 mapreq.map_vers = DDI_MAP_VERSION; 196325cf1a30Sjl139090 196425cf1a30Sjl139090 (void) ddi_map(acc_handlep->ah_dip, &mapreq, acc_handlep->ah_offset, 196525cf1a30Sjl139090 acc_handlep->ah_len, &acc_handlep->ah_addr); 196625cf1a30Sjl139090 196725cf1a30Sjl139090 impl_acc_hdl_free(*handlep); 196825cf1a30Sjl139090 /* 196925cf1a30Sjl139090 * Free the cached copy 197025cf1a30Sjl139090 */ 197125cf1a30Sjl139090 kmem_free(rspecp, sizeof (struct regspec)); 197225cf1a30Sjl139090 *handlep = (ddi_acc_handle_t)NULL; 197325cf1a30Sjl139090 } 197425cf1a30Sjl139090 197525cf1a30Sjl139090 static int 197625cf1a30Sjl139090 opl_get_hwd_va(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 197725cf1a30Sjl139090 { 197825cf1a30Sjl139090 uint32_t portid; 197925cf1a30Sjl139090 void *hwd_virt; 198025cf1a30Sjl139090 hwd_header_t *hwd_h = NULL; 198125cf1a30Sjl139090 hwd_sb_t *hwd_sb = NULL; 198225cf1a30Sjl139090 int lsb, ch, leaf; 198325cf1a30Sjl139090 int status = 1; 198425cf1a30Sjl139090 198525cf1a30Sjl139090 /* Check the argument */ 198625cf1a30Sjl139090 if (fc_cell2int(cp->nargs) != 2) 198725cf1a30Sjl139090 return (fc_syntax_error(cp, "nargs must be 2")); 198825cf1a30Sjl139090 198925cf1a30Sjl139090 if (fc_cell2int(cp->nresults) < 1) 199025cf1a30Sjl139090 return (fc_syntax_error(cp, "nresults must be >= 1")); 199125cf1a30Sjl139090 199225cf1a30Sjl139090 /* Get the parameters */ 199325cf1a30Sjl139090 portid = fc_cell2uint32_t(fc_arg(cp, 0)); 199425cf1a30Sjl139090 hwd_virt = (void *)fc_cell2ptr(fc_arg(cp, 1)); 199525cf1a30Sjl139090 199625cf1a30Sjl139090 /* Get the ID numbers */ 199725cf1a30Sjl139090 lsb = OPL_IO_PORTID_TO_LSB(portid); 199825cf1a30Sjl139090 ch = OPL_PORTID_TO_CHANNEL(portid); 199925cf1a30Sjl139090 leaf = OPL_PORTID_TO_LEAF(portid); 200025cf1a30Sjl139090 ASSERT(OPL_IO_PORTID(lsb, ch, leaf) == portid); 200125cf1a30Sjl139090 200225cf1a30Sjl139090 /* Set the pointer of hwd. */ 200325cf1a30Sjl139090 if ((hwd_h = (hwd_header_t *)opl_boards[lsb].cfg_hwd) == NULL) { 200425cf1a30Sjl139090 return (fc_priv_error(cp, "null hwd header")); 200525cf1a30Sjl139090 } 200625cf1a30Sjl139090 /* Set the pointer of hwd sb. */ 200725cf1a30Sjl139090 if ((hwd_sb = (hwd_sb_t *)((char *)hwd_h + hwd_h->hdr_sb_info_offset)) 200825cf1a30Sjl139090 == NULL) { 200925cf1a30Sjl139090 return (fc_priv_error(cp, "null hwd sb")); 201025cf1a30Sjl139090 } 201125cf1a30Sjl139090 201225cf1a30Sjl139090 if (ch == OPL_CMU_CHANNEL) { 201325cf1a30Sjl139090 /* Copyout CMU-CH HW Descriptor */ 201425cf1a30Sjl139090 if (copyout((void *)&hwd_sb->sb_cmu.cmu_ch, 201525cf1a30Sjl139090 (void *)hwd_virt, sizeof (hwd_cmu_chan_t))) { 201625cf1a30Sjl139090 cmn_err(CE_WARN, "opl_get_hwd_va: " 201725cf1a30Sjl139090 "Unable to copy out cmuch descriptor for %x", 201825cf1a30Sjl139090 portid); 201925cf1a30Sjl139090 status = 0; 202025cf1a30Sjl139090 } 202125cf1a30Sjl139090 } else { 202225cf1a30Sjl139090 /* Copyout PCI-CH HW Descriptor */ 202325cf1a30Sjl139090 if (copyout((void *)&hwd_sb->sb_pci_ch[ch].pci_leaf[leaf], 202425cf1a30Sjl139090 (void *)hwd_virt, sizeof (hwd_leaf_t))) { 202525cf1a30Sjl139090 cmn_err(CE_WARN, "opl_get_hwd_va: " 202625cf1a30Sjl139090 "Unable to copy out pcich descriptor for %x", 202725cf1a30Sjl139090 portid); 202825cf1a30Sjl139090 status = 0; 202925cf1a30Sjl139090 } 203025cf1a30Sjl139090 } 203125cf1a30Sjl139090 203225cf1a30Sjl139090 cp->nresults = fc_int2cell(1); 203325cf1a30Sjl139090 fc_result(cp, 0) = status; 203425cf1a30Sjl139090 203525cf1a30Sjl139090 return (fc_success_op(ap, rp, cp)); 203625cf1a30Sjl139090 } 203725cf1a30Sjl139090 203825cf1a30Sjl139090 /* 203953123245Smv143129 * After Solaris boots, a user can enter OBP using L1A, etc. While in OBP, 204053123245Smv143129 * interrupts may be received from PCI devices. These interrupts 204153123245Smv143129 * cannot be handled meaningfully since the system is in OBP. These 204253123245Smv143129 * interrupts need to be cleared on the CPU side so that the CPU may 204353123245Smv143129 * continue with whatever it is doing. Devices that have raised the 204453123245Smv143129 * interrupts are expected to reraise the interrupts after sometime 204553123245Smv143129 * as they have not been handled. At that time, Solaris will have a 204653123245Smv143129 * chance to properly service the interrupts. 204753123245Smv143129 * 204853123245Smv143129 * The location of the interrupt registers depends on what is present 204953123245Smv143129 * at a port. OPL currently supports the Oberon and the CMU channel. 205053123245Smv143129 * The following handler handles both kinds of ports and computes 205153123245Smv143129 * interrupt register addresses from the specifications and Jupiter Bus 205253123245Smv143129 * device bindings. 205353123245Smv143129 * 205453123245Smv143129 * Fcode drivers install their interrupt handler via a "master-interrupt" 205553123245Smv143129 * service. For boot time devices, this takes place within OBP. In the case 205653123245Smv143129 * of DR, OPL uses IKP. The Fcode drivers that run within the efcode framework 205753123245Smv143129 * attempt to install their handler via the "master-interrupt" service. 205853123245Smv143129 * However, we cannot meaningfully install the Fcode driver's handler. 205953123245Smv143129 * Instead, we install our own handler in OBP which does the same thing. 206053123245Smv143129 * 206153123245Smv143129 * Note that the only handling done for interrupts here is to clear it 206253123245Smv143129 * on the CPU side. If any device in the future requires more special 206353123245Smv143129 * handling, we would have to put in some kind of framework for adding 206453123245Smv143129 * device-specific handlers. This is *highly* unlikely, but possible. 206553123245Smv143129 * 206653123245Smv143129 * Finally, OBP provides a hook called "unix-interrupt-handler" to install 206753123245Smv143129 * a Solaris-defined master-interrupt handler for a port. The default 206853123245Smv143129 * definition for this method does nothing. Solaris may override this 206953123245Smv143129 * with its own definition. This is the way the following handler gets 207053123245Smv143129 * control from OBP when interrupts happen at a port after L1A, etc. 207153123245Smv143129 */ 207253123245Smv143129 207353123245Smv143129 static char define_master_interrupt_handler[] = 207453123245Smv143129 207553123245Smv143129 /* 207653123245Smv143129 * This method translates an Oberon port id to the base (physical) address 207753123245Smv143129 * of the interrupt clear registers for that port id. 207853123245Smv143129 */ 207953123245Smv143129 208053123245Smv143129 ": pcich-mid>clear-int-pa ( mid -- pa ) " 208153123245Smv143129 " dup 1 >> 7 and ( mid ch# ) " 208253123245Smv143129 " over 4 >> h# 1f and ( mid ch# lsb# ) " 208353123245Smv143129 " 1 d# 46 << ( mid ch# lsb# pa ) " 208453123245Smv143129 " swap d# 40 << or ( mid ch# pa ) " 208553123245Smv143129 " swap d# 37 << or ( mid pa ) " 208653123245Smv143129 " swap 1 and if h# 70.0000 else h# 60.0000 then " 208753123245Smv143129 " or h# 1400 or ( pa ) " 208853123245Smv143129 "; " 208953123245Smv143129 209053123245Smv143129 /* 209153123245Smv143129 * This method translates a CMU channel port id to the base (physical) address 209253123245Smv143129 * of the interrupt clear registers for that port id. There are two classes of 209353123245Smv143129 * interrupts that need to be handled for a CMU channel: 209453123245Smv143129 * - obio interrupts 209553123245Smv143129 * - pci interrupts 209653123245Smv143129 * So, there are two addresses that need to be computed. 209753123245Smv143129 */ 209853123245Smv143129 209953123245Smv143129 ": cmuch-mid>clear-int-pa ( mid -- obio-pa pci-pa ) " 210053123245Smv143129 " dup 1 >> 7 and ( mid ch# ) " 210153123245Smv143129 " over 4 >> h# 1f and ( mid ch# lsb# ) " 210253123245Smv143129 " 1 d# 46 << ( mid ch# lsb# pa ) " 210353123245Smv143129 " swap d# 40 << or ( mid ch# pa ) " 210453123245Smv143129 " swap d# 37 << or ( mid pa ) " 210553123245Smv143129 " nip dup h# 1800 + ( pa obio-pa ) " 210653123245Smv143129 " swap h# 1400 + ( obio-pa pci-pa ) " 210753123245Smv143129 "; " 210853123245Smv143129 210953123245Smv143129 /* 211053123245Smv143129 * This method checks if a given I/O port ID is valid or not. 211153123245Smv143129 * For a given LSB, 211253123245Smv143129 * Oberon ports range from 0 - 3 211353123245Smv143129 * CMU ch ports range from 4 - 4 211453123245Smv143129 * 211553123245Smv143129 * Also, the Oberon supports leaves 0 and 1. 211653123245Smv143129 * The CMU ch supports only one leaf, leaf 0. 211753123245Smv143129 */ 211853123245Smv143129 211953123245Smv143129 ": valid-io-mid? ( mid -- flag ) " 212053123245Smv143129 " dup 1 >> 7 and ( mid ch# ) " 212153123245Smv143129 " dup 4 > if 2drop false exit then ( mid ch# ) " 212253123245Smv143129 " 4 = swap 1 and 1 = and not " 212353123245Smv143129 "; " 212453123245Smv143129 212553123245Smv143129 /* 212653123245Smv143129 * This method checks if a given port id is a CMU ch. 212753123245Smv143129 */ 212853123245Smv143129 212953123245Smv143129 ": cmuch? ( mid -- flag ) 1 >> 7 and 4 = ; " 213053123245Smv143129 213153123245Smv143129 /* 213253123245Smv143129 * Given the base address of the array of interrupt clear registers for 213353123245Smv143129 * a port id, this method iterates over the given interrupt number bitmap 213453123245Smv143129 * and resets the interrupt on the CPU side for every interrupt number 213553123245Smv143129 * in the bitmap. Note that physical addresses are used to perform the 213653123245Smv143129 * writes, not virtual addresses. This allows the handler to work without 213753123245Smv143129 * any involvement from Solaris. 213853123245Smv143129 */ 213953123245Smv143129 214053123245Smv143129 ": clear-ints ( pa bitmap count -- ) " 214153123245Smv143129 " 0 do ( pa bitmap ) " 214253123245Smv143129 " dup 0= if 2drop unloop exit then " 214353123245Smv143129 " tuck ( bitmap pa bitmap ) " 214453123245Smv143129 " 1 and if ( bitmap pa ) " 214553123245Smv143129 " dup i 8 * + 0 swap ( bitmap pa 0 pa' ) " 214653123245Smv143129 " h# 15 spacex! ( bitmap pa ) " 214753123245Smv143129 " then ( bitmap pa ) " 214853123245Smv143129 " swap 1 >> ( pa bitmap ) " 214953123245Smv143129 " loop " 215053123245Smv143129 "; " 215153123245Smv143129 215253123245Smv143129 /* 215353123245Smv143129 * This method replaces the master-interrupt handler in OBP. Once 215453123245Smv143129 * this method is plumbed into OBP, OBP transfers control to this 215553123245Smv143129 * handler while returning to Solaris from OBP after L1A. This method's 215653123245Smv143129 * task is to simply reset received interrupts on the CPU side. 215753123245Smv143129 * When the devices reassert the interrupts later, Solaris will 215853123245Smv143129 * be able to see them and handle them. 215953123245Smv143129 * 216053123245Smv143129 * For each port ID that has interrupts, this method is called 216153123245Smv143129 * once by OBP. The input arguments are: 216253123245Smv143129 * mid portid 216353123245Smv143129 * bitmap bitmap of interrupts that have happened 216453123245Smv143129 * 216553123245Smv143129 * This method returns true, if it is able to handle the interrupts. 216653123245Smv143129 * OBP does nothing further. 216753123245Smv143129 * 216853123245Smv143129 * This method returns false, if it encountered a problem. Currently, 216953123245Smv143129 * the only problem could be an invalid port id. OBP needs to do 217053123245Smv143129 * its own processing in that case. If this method returns false, 217153123245Smv143129 * it preserves the mid and bitmap arguments for OBP. 217253123245Smv143129 */ 217353123245Smv143129 217453123245Smv143129 ": unix-resend-mondos ( mid bitmap -- [ mid bitmap false ] | true ) " 217553123245Smv143129 217653123245Smv143129 /* 217753123245Smv143129 * Uncomment the following line if you want to display the input arguments. 217853123245Smv143129 * This is meant for debugging. 217953123245Smv143129 * " .\" Bitmap=\" dup u. .\" MID=\" over u. cr " 218053123245Smv143129 */ 218153123245Smv143129 218253123245Smv143129 /* 218353123245Smv143129 * If the port id is not valid (according to the Oberon and CMU ch 218453123245Smv143129 * specifications, then return false to OBP to continue further 218553123245Smv143129 * processing. 218653123245Smv143129 */ 218753123245Smv143129 218853123245Smv143129 " over valid-io-mid? not if ( mid bitmap ) " 218953123245Smv143129 " false exit " 219053123245Smv143129 " then " 219153123245Smv143129 219253123245Smv143129 /* 219353123245Smv143129 * If the port is a CMU ch, then the 64-bit bitmap represents 219453123245Smv143129 * 2 32-bit bitmaps: 219553123245Smv143129 * - obio interrupt bitmap (20 bits) 219653123245Smv143129 * - pci interrupt bitmap (32 bits) 219753123245Smv143129 * 219853123245Smv143129 * - Split the bitmap into two 219953123245Smv143129 * - Compute the base addresses of the interrupt clear registers 220053123245Smv143129 * for both pci interrupts and obio interrupts 220153123245Smv143129 * - Clear obio interrupts 220253123245Smv143129 * - Clear pci interrupts 220353123245Smv143129 */ 220453123245Smv143129 220553123245Smv143129 " over cmuch? if ( mid bitmap ) " 220653123245Smv143129 " xlsplit ( mid pci-bit obio-bit ) " 220753123245Smv143129 " rot cmuch-mid>clear-int-pa ( pci-bit obio-bit obio-pa pci-pa ) " 220853123245Smv143129 " >r ( pci-bit obio-bit obio-pa ) ( r: pci-pa ) " 220953123245Smv143129 " swap d# 20 clear-ints ( pci-bit ) ( r: pci-pa ) " 221053123245Smv143129 " r> swap d# 32 clear-ints ( ) ( r: ) " 221153123245Smv143129 221253123245Smv143129 /* 221353123245Smv143129 * If the port is an Oberon, then the 64-bit bitmap is used fully. 221453123245Smv143129 * 221553123245Smv143129 * - Compute the base address of the interrupt clear registers 221653123245Smv143129 * - Clear interrupts 221753123245Smv143129 */ 221853123245Smv143129 221953123245Smv143129 " else ( mid bitmap ) " 222053123245Smv143129 " swap pcich-mid>clear-int-pa ( bitmap pa ) " 222153123245Smv143129 " swap d# 64 clear-ints ( ) " 222253123245Smv143129 " then " 222353123245Smv143129 222453123245Smv143129 /* 222553123245Smv143129 * Always return true from here. 222653123245Smv143129 */ 222753123245Smv143129 222853123245Smv143129 " true ( true ) " 222953123245Smv143129 "; " 223053123245Smv143129 ; 223153123245Smv143129 223253123245Smv143129 static char install_master_interrupt_handler[] = 223353123245Smv143129 "' unix-resend-mondos to unix-interrupt-handler"; 223453123245Smv143129 static char handler[] = "unix-interrupt-handler"; 223553123245Smv143129 static char handler_defined[] = "p\" %s\" find nip swap l! "; 223653123245Smv143129 223753123245Smv143129 /*ARGSUSED*/ 223853123245Smv143129 static int 223953123245Smv143129 master_interrupt_init(uint32_t portid, uint32_t xt) 224053123245Smv143129 { 224153123245Smv143129 uint_t defined; 224253123245Smv143129 char buf[sizeof (handler) + sizeof (handler_defined)]; 224353123245Smv143129 224453123245Smv143129 if (master_interrupt_inited) 224553123245Smv143129 return (1); 224653123245Smv143129 224753123245Smv143129 /* 224853123245Smv143129 * Check if the defer word "unix-interrupt-handler" is defined. 224953123245Smv143129 * This must be defined for OPL systems. So, this is only a 225053123245Smv143129 * sanity check. 225153123245Smv143129 */ 225253123245Smv143129 (void) sprintf(buf, handler_defined, handler); 225353123245Smv143129 prom_interpret(buf, (uintptr_t)&defined, 0, 0, 0, 0); 225453123245Smv143129 if (!defined) { 225553123245Smv143129 cmn_err(CE_WARN, "master_interrupt_init: " 225653123245Smv143129 "%s is not defined\n", handler); 225753123245Smv143129 return (0); 225853123245Smv143129 } 225953123245Smv143129 226053123245Smv143129 /* 226153123245Smv143129 * Install the generic master-interrupt handler. Note that 226253123245Smv143129 * this is only done one time on the first DR operation. 226353123245Smv143129 * This is because, for OPL, one, single generic handler 226453123245Smv143129 * handles all ports (Oberon and CMU channel) and all 226553123245Smv143129 * interrupt sources within each port. 226653123245Smv143129 * 226753123245Smv143129 * The current support is only for the Oberon and CMU-channel. 226853123245Smv143129 * If any others need to be supported, the handler has to be 226953123245Smv143129 * modified accordingly. 227053123245Smv143129 */ 227153123245Smv143129 227253123245Smv143129 /* 227353123245Smv143129 * Define the OPL master interrupt handler 227453123245Smv143129 */ 227553123245Smv143129 prom_interpret(define_master_interrupt_handler, 0, 0, 0, 0, 0); 227653123245Smv143129 227753123245Smv143129 /* 227853123245Smv143129 * Take over the master interrupt handler from OBP. 227953123245Smv143129 */ 228053123245Smv143129 prom_interpret(install_master_interrupt_handler, 0, 0, 0, 0, 0); 228153123245Smv143129 228253123245Smv143129 master_interrupt_inited = 1; 228353123245Smv143129 228453123245Smv143129 /* 228553123245Smv143129 * prom_interpret() does not return a status. So, we assume 228653123245Smv143129 * that the calls succeeded. In reality, the calls may fail 228753123245Smv143129 * if there is a syntax error, etc in the strings. 228853123245Smv143129 */ 228953123245Smv143129 229053123245Smv143129 return (1); 229153123245Smv143129 } 229253123245Smv143129 229353123245Smv143129 /* 229453123245Smv143129 * Install the master-interrupt handler for a device. 229553123245Smv143129 */ 229653123245Smv143129 static int 229753123245Smv143129 opl_master_interrupt(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 229853123245Smv143129 { 229953123245Smv143129 uint32_t portid, xt; 230053123245Smv143129 int board, channel, leaf; 230153123245Smv143129 int status; 230253123245Smv143129 230353123245Smv143129 /* Check the argument */ 230453123245Smv143129 if (fc_cell2int(cp->nargs) != 2) 230553123245Smv143129 return (fc_syntax_error(cp, "nargs must be 2")); 230653123245Smv143129 230753123245Smv143129 if (fc_cell2int(cp->nresults) < 1) 230853123245Smv143129 return (fc_syntax_error(cp, "nresults must be >= 1")); 230953123245Smv143129 231053123245Smv143129 /* Get the parameters */ 231153123245Smv143129 portid = fc_cell2uint32_t(fc_arg(cp, 0)); 231253123245Smv143129 xt = fc_cell2uint32_t(fc_arg(cp, 1)); 231353123245Smv143129 231453123245Smv143129 board = OPL_IO_PORTID_TO_LSB(portid); 231553123245Smv143129 channel = OPL_PORTID_TO_CHANNEL(portid); 231653123245Smv143129 leaf = OPL_PORTID_TO_LEAF(portid); 231753123245Smv143129 231853123245Smv143129 if ((board >= HWD_SBS_PER_DOMAIN) || !OPL_VALID_CHANNEL(channel) || 231953123245Smv143129 (OPL_OBERON_CHANNEL(channel) && !OPL_VALID_LEAF(leaf)) || 232053123245Smv143129 ((channel == OPL_CMU_CHANNEL) && (leaf != 0))) { 232153123245Smv143129 FC_DEBUG1(1, CE_CONT, "opl_master_interrupt: invalid port %x\n", 232253123245Smv143129 portid); 232353123245Smv143129 status = 0; 232453123245Smv143129 } else { 232553123245Smv143129 status = master_interrupt_init(portid, xt); 232653123245Smv143129 } 232753123245Smv143129 232853123245Smv143129 cp->nresults = fc_int2cell(1); 232953123245Smv143129 fc_result(cp, 0) = status; 233053123245Smv143129 233153123245Smv143129 return (fc_success_op(ap, rp, cp)); 233253123245Smv143129 } 233353123245Smv143129 233453123245Smv143129 /* 233525cf1a30Sjl139090 * Set the properties for a leaf node (Oberon leaf or CMU channel leaf). 233625cf1a30Sjl139090 */ 233725cf1a30Sjl139090 /*ARGSUSED*/ 233825cf1a30Sjl139090 static int 233925cf1a30Sjl139090 opl_create_leaf(dev_info_t *node, void *arg, uint_t flags) 234025cf1a30Sjl139090 { 234125cf1a30Sjl139090 int ret; 234225cf1a30Sjl139090 234325cf1a30Sjl139090 OPL_UPDATE_PROP(string, node, "name", OPL_PCI_LEAF_NODE); 234425cf1a30Sjl139090 234525cf1a30Sjl139090 OPL_UPDATE_PROP(string, node, "status", "okay"); 234625cf1a30Sjl139090 234725cf1a30Sjl139090 return (DDI_WALK_TERMINATE); 234825cf1a30Sjl139090 } 234925cf1a30Sjl139090 235025cf1a30Sjl139090 static char * 235125cf1a30Sjl139090 opl_get_probe_string(opl_probe_t *probe, int channel, int leaf) 235225cf1a30Sjl139090 { 235325cf1a30Sjl139090 char *probe_string; 235425cf1a30Sjl139090 int portid; 235525cf1a30Sjl139090 235625cf1a30Sjl139090 probe_string = kmem_zalloc(PROBE_STR_SIZE, KM_SLEEP); 235725cf1a30Sjl139090 235825cf1a30Sjl139090 if (channel == OPL_CMU_CHANNEL) 235925cf1a30Sjl139090 portid = probe->pr_sb->sb_cmu.cmu_ch.chan_portid; 236025cf1a30Sjl139090 else 236125cf1a30Sjl139090 portid = probe-> 236225cf1a30Sjl139090 pr_sb->sb_pci_ch[channel].pci_leaf[leaf].leaf_port_id; 236325cf1a30Sjl139090 236425cf1a30Sjl139090 (void) sprintf(probe_string, "%x", portid); 236525cf1a30Sjl139090 236625cf1a30Sjl139090 return (probe_string); 236725cf1a30Sjl139090 } 236825cf1a30Sjl139090 236925cf1a30Sjl139090 static int 237025cf1a30Sjl139090 opl_probe_leaf(opl_probe_t *probe) 237125cf1a30Sjl139090 { 237225cf1a30Sjl139090 int channel, leaf, portid, error, circ; 237325cf1a30Sjl139090 int board; 237425cf1a30Sjl139090 fco_handle_t fco_handle, *cfg_handle; 237525cf1a30Sjl139090 dev_info_t *parent, *leaf_node; 237625cf1a30Sjl139090 char unit_address[UNIT_ADDR_SIZE]; 237725cf1a30Sjl139090 char *probe_string; 237825cf1a30Sjl139090 opl_board_cfg_t *board_cfg; 237925cf1a30Sjl139090 238025cf1a30Sjl139090 board = probe->pr_board; 238125cf1a30Sjl139090 channel = probe->pr_channel; 238225cf1a30Sjl139090 leaf = probe->pr_leaf; 238325cf1a30Sjl139090 parent = ddi_root_node(); 238425cf1a30Sjl139090 board_cfg = &opl_boards[board]; 238525cf1a30Sjl139090 238625cf1a30Sjl139090 ASSERT(OPL_VALID_CHANNEL(channel)); 238725cf1a30Sjl139090 ASSERT(OPL_VALID_LEAF(leaf)); 238825cf1a30Sjl139090 238925cf1a30Sjl139090 if (channel == OPL_CMU_CHANNEL) { 239025cf1a30Sjl139090 portid = probe->pr_sb->sb_cmu.cmu_ch.chan_portid; 239125cf1a30Sjl139090 cfg_handle = &board_cfg->cfg_cmuch_handle; 239225cf1a30Sjl139090 } else { 239325cf1a30Sjl139090 portid = probe-> 239425cf1a30Sjl139090 pr_sb->sb_pci_ch[channel].pci_leaf[leaf].leaf_port_id; 239525cf1a30Sjl139090 cfg_handle = &board_cfg->cfg_pcich_handle[channel][leaf]; 239625cf1a30Sjl139090 } 239725cf1a30Sjl139090 239825cf1a30Sjl139090 /* 239925cf1a30Sjl139090 * Prevent any changes to leaf_node until we have bound 240025cf1a30Sjl139090 * it to the correct driver. 240125cf1a30Sjl139090 */ 240225cf1a30Sjl139090 ndi_devi_enter(parent, &circ); 240325cf1a30Sjl139090 240425cf1a30Sjl139090 /* 240525cf1a30Sjl139090 * Ideally, fcode would be run from the "sid_branch_create" 240625cf1a30Sjl139090 * callback (that is the primary purpose of that callback). 240725cf1a30Sjl139090 * However, the fcode interpreter was written with the 240825cf1a30Sjl139090 * assumption that the "new_child" was linked into the 240925cf1a30Sjl139090 * device tree. The callback is invoked with the devinfo node 241025cf1a30Sjl139090 * in the DS_PROTO state. More investigation is needed before 241125cf1a30Sjl139090 * we can invoke the interpreter from the callback. For now, 241225cf1a30Sjl139090 * we create the "new_child" in the BOUND state, invoke the 241325cf1a30Sjl139090 * fcode interpreter and then rebind the dip to use any 241425cf1a30Sjl139090 * compatible properties created by fcode. 241525cf1a30Sjl139090 */ 241625cf1a30Sjl139090 241725cf1a30Sjl139090 probe->pr_parent = parent; 241825cf1a30Sjl139090 probe->pr_create = opl_create_leaf; 241925cf1a30Sjl139090 probe->pr_hold = 1; 242025cf1a30Sjl139090 242125cf1a30Sjl139090 leaf_node = opl_create_node(probe); 242225cf1a30Sjl139090 if (leaf_node == NULL) { 242325cf1a30Sjl139090 242425cf1a30Sjl139090 cmn_err(CE_WARN, "IKP: create leaf (%d-%d-%d) failed", 242525cf1a30Sjl139090 probe->pr_board, probe->pr_channel, probe->pr_leaf); 242625cf1a30Sjl139090 ndi_devi_exit(parent, circ); 242725cf1a30Sjl139090 return (-1); 242825cf1a30Sjl139090 } 242925cf1a30Sjl139090 243025cf1a30Sjl139090 /* 243125cf1a30Sjl139090 * The platform DR interfaces created the dip in 243225cf1a30Sjl139090 * bound state. Bring devinfo node down to linked 243325cf1a30Sjl139090 * state and hold it there until compatible 243425cf1a30Sjl139090 * properties are created. 243525cf1a30Sjl139090 */ 243625cf1a30Sjl139090 e_ddi_branch_rele(leaf_node); 243725cf1a30Sjl139090 (void) i_ndi_unconfig_node(leaf_node, DS_LINKED, 0); 243825cf1a30Sjl139090 ASSERT(i_ddi_node_state(leaf_node) == DS_LINKED); 243925cf1a30Sjl139090 e_ddi_branch_hold(leaf_node); 244025cf1a30Sjl139090 244125cf1a30Sjl139090 mutex_enter(&DEVI(leaf_node)->devi_lock); 244225cf1a30Sjl139090 DEVI(leaf_node)->devi_flags |= DEVI_NO_BIND; 244325cf1a30Sjl139090 mutex_exit(&DEVI(leaf_node)->devi_lock); 244425cf1a30Sjl139090 244525cf1a30Sjl139090 /* 244625cf1a30Sjl139090 * Drop the busy-hold on parent before calling 244725cf1a30Sjl139090 * fcode_interpreter to prevent potential deadlocks 244825cf1a30Sjl139090 */ 244925cf1a30Sjl139090 ndi_devi_exit(parent, circ); 245025cf1a30Sjl139090 245125cf1a30Sjl139090 (void) sprintf(unit_address, "%x", portid); 245225cf1a30Sjl139090 245325cf1a30Sjl139090 /* 245425cf1a30Sjl139090 * Get the probe string 245525cf1a30Sjl139090 */ 245625cf1a30Sjl139090 probe_string = opl_get_probe_string(probe, channel, leaf); 245725cf1a30Sjl139090 245825cf1a30Sjl139090 /* 245925cf1a30Sjl139090 * The fcode pointer specified here is NULL and the fcode 246025cf1a30Sjl139090 * size specified here is 0. This causes the user-level 246125cf1a30Sjl139090 * fcode interpreter to issue a request to the fcode 246225cf1a30Sjl139090 * driver to get the Oberon/cmu-ch fcode. 246325cf1a30Sjl139090 */ 246425cf1a30Sjl139090 fco_handle = opl_fc_ops_alloc_handle(parent, leaf_node, 246525cf1a30Sjl139090 NULL, 0, unit_address, probe_string); 246625cf1a30Sjl139090 246725cf1a30Sjl139090 error = fcode_interpreter(parent, &opl_fc_do_op, fco_handle); 246825cf1a30Sjl139090 246925cf1a30Sjl139090 if (error != 0) { 247025cf1a30Sjl139090 cmn_err(CE_WARN, "IKP: Unable to probe PCI leaf (%d-%d-%d)", 247125cf1a30Sjl139090 probe->pr_board, probe->pr_channel, probe->pr_leaf); 247225cf1a30Sjl139090 247325cf1a30Sjl139090 opl_fc_ops_free_handle(fco_handle); 247425cf1a30Sjl139090 247525cf1a30Sjl139090 if (probe_string != NULL) 247625cf1a30Sjl139090 kmem_free(probe_string, PROBE_STR_SIZE); 247725cf1a30Sjl139090 247825cf1a30Sjl139090 (void) opl_destroy_node(leaf_node); 247925cf1a30Sjl139090 } else { 248025cf1a30Sjl139090 *cfg_handle = fco_handle; 248125cf1a30Sjl139090 248225cf1a30Sjl139090 if (channel == OPL_CMU_CHANNEL) 248325cf1a30Sjl139090 board_cfg->cfg_cmuch_probe_str = probe_string; 248425cf1a30Sjl139090 else 248525cf1a30Sjl139090 board_cfg->cfg_pcich_probe_str[channel][leaf] 248625cf1a30Sjl139090 = probe_string; 248725cf1a30Sjl139090 248825cf1a30Sjl139090 /* 248925cf1a30Sjl139090 * Compatible properties (if any) have been created, 249025cf1a30Sjl139090 * so bind driver. 249125cf1a30Sjl139090 */ 249225cf1a30Sjl139090 ndi_devi_enter(parent, &circ); 249325cf1a30Sjl139090 ASSERT(i_ddi_node_state(leaf_node) <= DS_LINKED); 249425cf1a30Sjl139090 249525cf1a30Sjl139090 mutex_enter(&DEVI(leaf_node)->devi_lock); 249625cf1a30Sjl139090 DEVI(leaf_node)->devi_flags &= ~DEVI_NO_BIND; 249725cf1a30Sjl139090 mutex_exit(&DEVI(leaf_node)->devi_lock); 249825cf1a30Sjl139090 249925cf1a30Sjl139090 ndi_devi_exit(parent, circ); 250025cf1a30Sjl139090 2501e98fafb9Sjl139090 if (ndi_devi_bind_driver(leaf_node, 0) != DDI_SUCCESS) { 2502e98fafb9Sjl139090 cmn_err(CE_WARN, "IKP: Unable to bind PCI leaf " 2503e98fafb9Sjl139090 "(%d-%d-%d)", probe->pr_board, probe->pr_channel, 250425cf1a30Sjl139090 probe->pr_leaf); 250525cf1a30Sjl139090 } 250625cf1a30Sjl139090 } 250725cf1a30Sjl139090 250825cf1a30Sjl139090 if ((error != 0) && (channel == OPL_CMU_CHANNEL)) 250925cf1a30Sjl139090 return (-1); 251025cf1a30Sjl139090 251125cf1a30Sjl139090 return (0); 251225cf1a30Sjl139090 } 251325cf1a30Sjl139090 251425cf1a30Sjl139090 static void 251525cf1a30Sjl139090 opl_init_leaves(int myboard) 251625cf1a30Sjl139090 { 251725cf1a30Sjl139090 dev_info_t *parent, *node; 251825cf1a30Sjl139090 char *name; 251925cf1a30Sjl139090 int circ, ret; 252025cf1a30Sjl139090 int len, portid, board, channel, leaf; 252125cf1a30Sjl139090 opl_board_cfg_t *cfg; 252225cf1a30Sjl139090 252325cf1a30Sjl139090 parent = ddi_root_node(); 252425cf1a30Sjl139090 252525cf1a30Sjl139090 /* 252625cf1a30Sjl139090 * Hold parent node busy to walk its child list 252725cf1a30Sjl139090 */ 252825cf1a30Sjl139090 ndi_devi_enter(parent, &circ); 252925cf1a30Sjl139090 2530e98fafb9Sjl139090 for (node = ddi_get_child(parent); (node != NULL); node = 2531e98fafb9Sjl139090 ddi_get_next_sibling(node)) { 253225cf1a30Sjl139090 253325cf1a30Sjl139090 ret = OPL_GET_PROP(string, node, "name", &name, &len); 253425cf1a30Sjl139090 if (ret != DDI_PROP_SUCCESS) { 253525cf1a30Sjl139090 /* 253625cf1a30Sjl139090 * The property does not exist for this node. 253725cf1a30Sjl139090 */ 253825cf1a30Sjl139090 continue; 253925cf1a30Sjl139090 } 254025cf1a30Sjl139090 254125cf1a30Sjl139090 if (strncmp(name, OPL_PCI_LEAF_NODE, len) == 0) { 254225cf1a30Sjl139090 254325cf1a30Sjl139090 ret = OPL_GET_PROP(int, node, "portid", &portid, -1); 254425cf1a30Sjl139090 if (ret == DDI_PROP_SUCCESS) { 254525cf1a30Sjl139090 254625cf1a30Sjl139090 ret = OPL_GET_PROP(int, node, "board#", 254725cf1a30Sjl139090 &board, -1); 254825cf1a30Sjl139090 if ((ret != DDI_PROP_SUCCESS) || 254968ac2337Sjl139090 (board != myboard)) { 255068ac2337Sjl139090 kmem_free(name, len); 255125cf1a30Sjl139090 continue; 255268ac2337Sjl139090 } 255325cf1a30Sjl139090 255425cf1a30Sjl139090 cfg = &opl_boards[board]; 255525cf1a30Sjl139090 channel = OPL_PORTID_TO_CHANNEL(portid); 255625cf1a30Sjl139090 if (channel == OPL_CMU_CHANNEL) { 255725cf1a30Sjl139090 255825cf1a30Sjl139090 if (cfg->cfg_cmuch_handle != NULL) 255925cf1a30Sjl139090 cfg->cfg_cmuch_leaf = node; 256025cf1a30Sjl139090 256125cf1a30Sjl139090 } else { 256225cf1a30Sjl139090 256325cf1a30Sjl139090 leaf = OPL_PORTID_TO_LEAF(portid); 2564e98fafb9Sjl139090 if (cfg->cfg_pcich_handle[ 2565e98fafb9Sjl139090 channel][leaf] != NULL) 2566e98fafb9Sjl139090 cfg->cfg_pcich_leaf[ 2567e98fafb9Sjl139090 channel][leaf] = node; 256825cf1a30Sjl139090 } 256925cf1a30Sjl139090 } 257025cf1a30Sjl139090 } 257125cf1a30Sjl139090 257225cf1a30Sjl139090 kmem_free(name, len); 257325cf1a30Sjl139090 if (ret != DDI_PROP_SUCCESS) 257425cf1a30Sjl139090 break; 257525cf1a30Sjl139090 } 257625cf1a30Sjl139090 257725cf1a30Sjl139090 ndi_devi_exit(parent, circ); 257825cf1a30Sjl139090 } 257925cf1a30Sjl139090 258025cf1a30Sjl139090 /* 258125cf1a30Sjl139090 * Create "pci" node and hierarchy for the Oberon channels and the 258225cf1a30Sjl139090 * CMU channel. 258325cf1a30Sjl139090 */ 258425cf1a30Sjl139090 /*ARGSUSED*/ 258525cf1a30Sjl139090 static int 258625cf1a30Sjl139090 opl_probe_io(opl_probe_t *probe) 258725cf1a30Sjl139090 { 258825cf1a30Sjl139090 258925cf1a30Sjl139090 int i, j; 259025cf1a30Sjl139090 hwd_pci_ch_t *channels; 259125cf1a30Sjl139090 259225cf1a30Sjl139090 if (HWD_STATUS_OK(probe->pr_sb->sb_cmu.cmu_ch.chan_status)) { 259325cf1a30Sjl139090 259425cf1a30Sjl139090 probe->pr_channel = HWD_CMU_CHANNEL; 259525cf1a30Sjl139090 probe->pr_channel_status = 259625cf1a30Sjl139090 probe->pr_sb->sb_cmu.cmu_ch.chan_status; 259725cf1a30Sjl139090 probe->pr_leaf = 0; 259825cf1a30Sjl139090 probe->pr_leaf_status = probe->pr_channel_status; 259925cf1a30Sjl139090 260025cf1a30Sjl139090 if (opl_probe_leaf(probe) != 0) 260125cf1a30Sjl139090 return (-1); 260225cf1a30Sjl139090 } 260325cf1a30Sjl139090 260425cf1a30Sjl139090 channels = &probe->pr_sb->sb_pci_ch[0]; 260525cf1a30Sjl139090 260625cf1a30Sjl139090 for (i = 0; i < HWD_PCI_CHANNELS_PER_SB; i++) { 260725cf1a30Sjl139090 260825cf1a30Sjl139090 if (!HWD_STATUS_OK(channels[i].pci_status)) 260925cf1a30Sjl139090 continue; 261025cf1a30Sjl139090 261125cf1a30Sjl139090 probe->pr_channel = i; 261225cf1a30Sjl139090 probe->pr_channel_status = channels[i].pci_status; 261325cf1a30Sjl139090 261425cf1a30Sjl139090 for (j = 0; j < HWD_LEAVES_PER_PCI_CHANNEL; j++) { 261525cf1a30Sjl139090 261625cf1a30Sjl139090 probe->pr_leaf = j; 261725cf1a30Sjl139090 probe->pr_leaf_status = 261825cf1a30Sjl139090 channels[i].pci_leaf[j].leaf_status; 261925cf1a30Sjl139090 262025cf1a30Sjl139090 if (!HWD_STATUS_OK(probe->pr_leaf_status)) 262125cf1a30Sjl139090 continue; 262225cf1a30Sjl139090 262325cf1a30Sjl139090 (void) opl_probe_leaf(probe); 262425cf1a30Sjl139090 } 262525cf1a30Sjl139090 } 262625cf1a30Sjl139090 opl_init_leaves(probe->pr_board); 262725cf1a30Sjl139090 return (0); 262825cf1a30Sjl139090 } 262925cf1a30Sjl139090 263025cf1a30Sjl139090 /* 263125cf1a30Sjl139090 * Perform the probe in the following order: 263225cf1a30Sjl139090 * 263325cf1a30Sjl139090 * processors 263425cf1a30Sjl139090 * memory 263525cf1a30Sjl139090 * IO 263625cf1a30Sjl139090 * 263725cf1a30Sjl139090 * Each probe function returns 0 on sucess and a non-zero value on failure. 263825cf1a30Sjl139090 * What is a failure is determined by the implementor of the probe function. 263925cf1a30Sjl139090 * For example, while probing CPUs, any error encountered during probe 264025cf1a30Sjl139090 * is considered a failure and causes the whole probe operation to fail. 264125cf1a30Sjl139090 * However, for I/O, an error encountered while probing one device 264225cf1a30Sjl139090 * should not prevent other devices from being probed. It should not cause 264325cf1a30Sjl139090 * the whole probe operation to fail. 264425cf1a30Sjl139090 */ 264525cf1a30Sjl139090 int 2646e98fafb9Sjl139090 opl_probe_sb(int board, unsigned *cpu_impl) 264725cf1a30Sjl139090 { 264825cf1a30Sjl139090 opl_probe_t *probe; 264925cf1a30Sjl139090 int ret; 265025cf1a30Sjl139090 265125cf1a30Sjl139090 if ((board < 0) || (board >= HWD_SBS_PER_DOMAIN)) 265225cf1a30Sjl139090 return (-1); 265325cf1a30Sjl139090 265425cf1a30Sjl139090 ASSERT(opl_cfg_inited != 0); 265525cf1a30Sjl139090 265625cf1a30Sjl139090 /* 265725cf1a30Sjl139090 * If the previous probe failed and left a partially configured 265825cf1a30Sjl139090 * board, we need to unprobe the board and start with a clean slate. 265925cf1a30Sjl139090 */ 266025cf1a30Sjl139090 if ((opl_boards[board].cfg_hwd != NULL) && 266125cf1a30Sjl139090 (opl_unprobe_sb(board) != 0)) 266225cf1a30Sjl139090 return (-1); 266325cf1a30Sjl139090 266425cf1a30Sjl139090 ret = 0; 266525cf1a30Sjl139090 266625cf1a30Sjl139090 probe = kmem_zalloc(sizeof (opl_probe_t), KM_SLEEP); 266725cf1a30Sjl139090 probe->pr_board = board; 266825cf1a30Sjl139090 266925cf1a30Sjl139090 if ((opl_probe_init(probe) != 0) || 267025cf1a30Sjl139090 267125cf1a30Sjl139090 (opl_probe_cpu_chips(probe) != 0) || 267225cf1a30Sjl139090 267325cf1a30Sjl139090 (opl_probe_memory(probe) != 0) || 267425cf1a30Sjl139090 267525cf1a30Sjl139090 (opl_probe_io(probe) != 0)) { 267625cf1a30Sjl139090 267725cf1a30Sjl139090 /* 267825cf1a30Sjl139090 * Probe failed. Perform cleanup. 267925cf1a30Sjl139090 */ 268025cf1a30Sjl139090 (void) opl_unprobe_sb(board); 268125cf1a30Sjl139090 ret = -1; 268225cf1a30Sjl139090 } 268325cf1a30Sjl139090 2684e98fafb9Sjl139090 *cpu_impl = probe->pr_cpu_impl; 2685e98fafb9Sjl139090 268625cf1a30Sjl139090 kmem_free(probe, sizeof (opl_probe_t)); 268725cf1a30Sjl139090 268825cf1a30Sjl139090 return (ret); 268925cf1a30Sjl139090 } 269025cf1a30Sjl139090 269125cf1a30Sjl139090 /* 269225cf1a30Sjl139090 * This unprobing also includes CMU-CH. 269325cf1a30Sjl139090 */ 269425cf1a30Sjl139090 /*ARGSUSED*/ 269525cf1a30Sjl139090 static int 269625cf1a30Sjl139090 opl_unprobe_io(int board) 269725cf1a30Sjl139090 { 269825cf1a30Sjl139090 int i, j, ret; 269925cf1a30Sjl139090 opl_board_cfg_t *board_cfg; 270025cf1a30Sjl139090 dev_info_t **node; 270125cf1a30Sjl139090 fco_handle_t *hand; 270225cf1a30Sjl139090 char **probe_str; 270325cf1a30Sjl139090 270425cf1a30Sjl139090 board_cfg = &opl_boards[board]; 270525cf1a30Sjl139090 270625cf1a30Sjl139090 for (i = 0; i < HWD_PCI_CHANNELS_PER_SB; i++) { 270725cf1a30Sjl139090 270825cf1a30Sjl139090 for (j = 0; j < HWD_LEAVES_PER_PCI_CHANNEL; j++) { 270925cf1a30Sjl139090 271025cf1a30Sjl139090 node = &board_cfg->cfg_pcich_leaf[i][j]; 271125cf1a30Sjl139090 hand = &board_cfg->cfg_pcich_handle[i][j]; 271225cf1a30Sjl139090 probe_str = &board_cfg->cfg_pcich_probe_str[i][j]; 271325cf1a30Sjl139090 271425cf1a30Sjl139090 if (*node == NULL) 271525cf1a30Sjl139090 continue; 271625cf1a30Sjl139090 271725cf1a30Sjl139090 if (*hand != NULL) { 271825cf1a30Sjl139090 opl_fc_ops_free_handle(*hand); 271925cf1a30Sjl139090 *hand = NULL; 272025cf1a30Sjl139090 } 272125cf1a30Sjl139090 272225cf1a30Sjl139090 if (*probe_str != NULL) { 272325cf1a30Sjl139090 kmem_free(*probe_str, PROBE_STR_SIZE); 272425cf1a30Sjl139090 *probe_str = NULL; 272525cf1a30Sjl139090 } 272625cf1a30Sjl139090 272725cf1a30Sjl139090 ret = opl_destroy_node(*node); 272825cf1a30Sjl139090 if (ret != 0) { 272925cf1a30Sjl139090 2730e98fafb9Sjl139090 cmn_err(CE_WARN, "IKP: destroy pci (%d-%d-%d) " 2731e98fafb9Sjl139090 "failed", board, i, j); 273225cf1a30Sjl139090 return (-1); 273325cf1a30Sjl139090 } 273425cf1a30Sjl139090 273525cf1a30Sjl139090 *node = NULL; 273625cf1a30Sjl139090 273725cf1a30Sjl139090 } 273825cf1a30Sjl139090 } 273925cf1a30Sjl139090 274025cf1a30Sjl139090 node = &board_cfg->cfg_cmuch_leaf; 274125cf1a30Sjl139090 hand = &board_cfg->cfg_cmuch_handle; 274225cf1a30Sjl139090 probe_str = &board_cfg->cfg_cmuch_probe_str; 274325cf1a30Sjl139090 274425cf1a30Sjl139090 if (*node == NULL) 274525cf1a30Sjl139090 return (0); 274625cf1a30Sjl139090 274725cf1a30Sjl139090 if (*hand != NULL) { 274825cf1a30Sjl139090 opl_fc_ops_free_handle(*hand); 274925cf1a30Sjl139090 *hand = NULL; 275025cf1a30Sjl139090 } 275125cf1a30Sjl139090 275225cf1a30Sjl139090 if (*probe_str != NULL) { 275325cf1a30Sjl139090 kmem_free(*probe_str, PROBE_STR_SIZE); 275425cf1a30Sjl139090 *probe_str = NULL; 275525cf1a30Sjl139090 } 275625cf1a30Sjl139090 275725cf1a30Sjl139090 if (opl_destroy_node(*node) != 0) { 275825cf1a30Sjl139090 2759e98fafb9Sjl139090 cmn_err(CE_WARN, "IKP: destroy pci (%d-%d-%d) failed", board, 2760e98fafb9Sjl139090 OPL_CMU_CHANNEL, 0); 276125cf1a30Sjl139090 return (-1); 276225cf1a30Sjl139090 } 276325cf1a30Sjl139090 276425cf1a30Sjl139090 *node = NULL; 276525cf1a30Sjl139090 276625cf1a30Sjl139090 return (0); 276725cf1a30Sjl139090 } 276825cf1a30Sjl139090 276925cf1a30Sjl139090 /* 277025cf1a30Sjl139090 * Destroy the "pseudo-mc" node for a board. 277125cf1a30Sjl139090 */ 277225cf1a30Sjl139090 static int 277325cf1a30Sjl139090 opl_unprobe_memory(int board) 277425cf1a30Sjl139090 { 277525cf1a30Sjl139090 opl_board_cfg_t *board_cfg; 277625cf1a30Sjl139090 277725cf1a30Sjl139090 board_cfg = &opl_boards[board]; 277825cf1a30Sjl139090 277925cf1a30Sjl139090 if (board_cfg->cfg_pseudo_mc == NULL) 278025cf1a30Sjl139090 return (0); 278125cf1a30Sjl139090 278225cf1a30Sjl139090 if (opl_destroy_node(board_cfg->cfg_pseudo_mc) != 0) { 278325cf1a30Sjl139090 278425cf1a30Sjl139090 cmn_err(CE_WARN, "IKP: destroy pseudo-mc (%d) failed", board); 278525cf1a30Sjl139090 return (-1); 278625cf1a30Sjl139090 } 278725cf1a30Sjl139090 278825cf1a30Sjl139090 board_cfg->cfg_pseudo_mc = NULL; 278925cf1a30Sjl139090 279025cf1a30Sjl139090 return (0); 279125cf1a30Sjl139090 } 279225cf1a30Sjl139090 279325cf1a30Sjl139090 /* 279425cf1a30Sjl139090 * Destroy the "cmp" nodes for a board. This also destroys the "core" 279525cf1a30Sjl139090 * and "cpu" nodes below the "cmp" nodes. 279625cf1a30Sjl139090 */ 279725cf1a30Sjl139090 static int 279825cf1a30Sjl139090 opl_unprobe_processors(int board) 279925cf1a30Sjl139090 { 280025cf1a30Sjl139090 int i; 280125cf1a30Sjl139090 dev_info_t **cfg_cpu_chips; 280225cf1a30Sjl139090 280325cf1a30Sjl139090 cfg_cpu_chips = opl_boards[board].cfg_cpu_chips; 280425cf1a30Sjl139090 280525cf1a30Sjl139090 for (i = 0; i < HWD_CPU_CHIPS_PER_CMU; i++) { 280625cf1a30Sjl139090 280725cf1a30Sjl139090 if (cfg_cpu_chips[i] == NULL) 280825cf1a30Sjl139090 continue; 280925cf1a30Sjl139090 281025cf1a30Sjl139090 if (opl_destroy_node(cfg_cpu_chips[i]) != 0) { 281125cf1a30Sjl139090 2812e98fafb9Sjl139090 cmn_err(CE_WARN, "IKP: destroy chip (%d-%d) failed", 2813e98fafb9Sjl139090 board, i); 281425cf1a30Sjl139090 return (-1); 281525cf1a30Sjl139090 } 281625cf1a30Sjl139090 281725cf1a30Sjl139090 cfg_cpu_chips[i] = NULL; 281825cf1a30Sjl139090 } 281925cf1a30Sjl139090 282025cf1a30Sjl139090 return (0); 282125cf1a30Sjl139090 } 282225cf1a30Sjl139090 282325cf1a30Sjl139090 /* 282425cf1a30Sjl139090 * Perform the unprobe in the following order: 282525cf1a30Sjl139090 * 282625cf1a30Sjl139090 * IO 282725cf1a30Sjl139090 * memory 282825cf1a30Sjl139090 * processors 282925cf1a30Sjl139090 */ 283025cf1a30Sjl139090 int 283125cf1a30Sjl139090 opl_unprobe_sb(int board) 283225cf1a30Sjl139090 { 283325cf1a30Sjl139090 if ((board < 0) || (board >= HWD_SBS_PER_DOMAIN)) 283425cf1a30Sjl139090 return (-1); 283525cf1a30Sjl139090 283625cf1a30Sjl139090 ASSERT(opl_cfg_inited != 0); 283725cf1a30Sjl139090 283825cf1a30Sjl139090 if ((opl_unprobe_io(board) != 0) || 283925cf1a30Sjl139090 284025cf1a30Sjl139090 (opl_unprobe_memory(board) != 0) || 284125cf1a30Sjl139090 284225cf1a30Sjl139090 (opl_unprobe_processors(board) != 0)) 284325cf1a30Sjl139090 284425cf1a30Sjl139090 return (-1); 284525cf1a30Sjl139090 284625cf1a30Sjl139090 if (opl_boards[board].cfg_hwd != NULL) { 284725cf1a30Sjl139090 #ifdef UCTEST 284825cf1a30Sjl139090 size_t size = 0xA000; 284925cf1a30Sjl139090 #endif 285025cf1a30Sjl139090 /* Release the memory for the HWD */ 285125cf1a30Sjl139090 void *hwdp = opl_boards[board].cfg_hwd; 285225cf1a30Sjl139090 opl_boards[board].cfg_hwd = NULL; 285325cf1a30Sjl139090 #ifdef UCTEST 285425cf1a30Sjl139090 hwdp = (void *)((char *)hwdp - 0x1000); 285525cf1a30Sjl139090 hat_unload(kas.a_hat, hwdp, size, HAT_UNLOAD_UNLOCK); 285625cf1a30Sjl139090 vmem_free(heap_arena, hwdp, size); 285725cf1a30Sjl139090 #else 285825cf1a30Sjl139090 kmem_free(hwdp, HWD_DATA_SIZE); 285925cf1a30Sjl139090 #endif 286025cf1a30Sjl139090 } 286125cf1a30Sjl139090 return (0); 286225cf1a30Sjl139090 } 286325cf1a30Sjl139090 286425cf1a30Sjl139090 /* 286525cf1a30Sjl139090 * For MAC patrol support, we need to update the PA-related properties 286625cf1a30Sjl139090 * when there is a copy-rename event. This should be called after the 286725cf1a30Sjl139090 * physical copy and rename has been done by DR, and before the MAC 286825cf1a30Sjl139090 * patrol is restarted. 286925cf1a30Sjl139090 */ 287025cf1a30Sjl139090 int 287125cf1a30Sjl139090 oplcfg_pa_swap(int from, int to) 287225cf1a30Sjl139090 { 287325cf1a30Sjl139090 dev_info_t *from_node = opl_boards[from].cfg_pseudo_mc; 287425cf1a30Sjl139090 dev_info_t *to_node = opl_boards[to].cfg_pseudo_mc; 287525cf1a30Sjl139090 opl_range_t *rangef, *ranget; 287625cf1a30Sjl139090 int elems; 287725cf1a30Sjl139090 int ret; 287825cf1a30Sjl139090 287925cf1a30Sjl139090 if ((OPL_GET_PROP_ARRAY(int, from_node, "sb-mem-ranges", rangef, 288025cf1a30Sjl139090 elems) != DDI_SUCCESS) || (elems != 4)) { 288125cf1a30Sjl139090 /* XXX -- bad news */ 288225cf1a30Sjl139090 return (-1); 288325cf1a30Sjl139090 } 288425cf1a30Sjl139090 if ((OPL_GET_PROP_ARRAY(int, to_node, "sb-mem-ranges", ranget, 288525cf1a30Sjl139090 elems) != DDI_SUCCESS) || (elems != 4)) { 288625cf1a30Sjl139090 /* XXX -- bad news */ 288725cf1a30Sjl139090 return (-1); 288825cf1a30Sjl139090 } 288925cf1a30Sjl139090 OPL_UPDATE_PROP_ARRAY(int, from_node, "sb-mem-ranges", (int *)ranget, 289025cf1a30Sjl139090 4); 289125cf1a30Sjl139090 OPL_UPDATE_PROP_ARRAY(int, to_node, "sb-mem-ranges", (int *)rangef, 289225cf1a30Sjl139090 4); 289325cf1a30Sjl139090 289425cf1a30Sjl139090 OPL_FREE_PROP(ranget); 289525cf1a30Sjl139090 OPL_FREE_PROP(rangef); 289625cf1a30Sjl139090 289725cf1a30Sjl139090 return (0); 289825cf1a30Sjl139090 } 2899