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