diff options
author | arutz <none@none> | 2006-08-11 13:07:51 -0700 |
---|---|---|
committer | arutz <none@none> | 2006-08-11 13:07:51 -0700 |
commit | b8dc8477f9e64fb1130ab21dc1f26664309f149d (patch) | |
tree | 011fb27cbf87f62a0067064667202f3b7be01c0a /usr/src | |
parent | c793af95640863cd29868fc7c419c5d2496b207b (diff) | |
download | illumos-joyent-b8dc8477f9e64fb1130ab21dc1f26664309f149d.tar.gz |
6265742 sbbc driver maps register space like it's going out of style
Diffstat (limited to 'usr/src')
-rw-r--r-- | usr/src/uts/sun4u/io/sbbc.c | 234 | ||||
-rw-r--r-- | usr/src/uts/sun4u/sys/sbbcreg.h | 13 | ||||
-rw-r--r-- | usr/src/uts/sun4u/sys/sbbcvar.h | 9 |
3 files changed, 138 insertions, 118 deletions
diff --git a/usr/src/uts/sun4u/io/sbbc.c b/usr/src/uts/sun4u/io/sbbc.c index 10cd3b2d4b..470136550f 100644 --- a/usr/src/uts/sun4u/io/sbbc.c +++ b/usr/src/uts/sun4u/io/sbbc.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,15 +19,45 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" /* - * Starcat PCI SBBC Device Nexus Driver that provides interfaces into - * Console Bus, I2C, Error/Intr. EPLD, IOSRAM, and JTAG. + * Starcat PCI SBBC Nexus Driver. + * + * This source code's compiled binary runs on both a Starcat System + * Controller (SSC) and a Starcat Domain. One of the SBBC hardware + * registers is read during attach(9e) in order to determine which + * environment the driver is executing on. + * + * On both the SSC and the Domain, this driver provides nexus driver + * services to its Device Tree children. Note that the children in + * each environment are not necessarily the same. + * + * This driver allows one concurrent open(2) of its associated device + * (/dev/sbbc0). The client uses the file descriptor to issue + * ioctl(2)'s in order to read and write from the 2MB (PCI) space + * reserved for "SBBC Internal Registers". Among other things, + * these registers consist of command/control/status registers for + * devices such as Console Bus, I2C, EPLD, IOSRAM, and JTAG. The 2MB + * space is very sparse; EINVAL is returned if a reserved or unaligned + * address is specified in the ioctl(2). + * + * Note that the 2MB region reserved for SBBC Internal Registers is + * a subset of the 128MB of PCI address space addressable by the SBBC + * ASIC. Address space outside of the 2MB (such as the 64MB reserved + * for the Console Bus) is not accessible via this driver. + * + * Also, note that the SBBC Internal Registers are only read and + * written by the SSC; no process on the Domain accesses these + * registers. As a result, the registers are unmapped (when running + * on the Domain) near the end of attach(9e) processing. This conserves + * kernel virtual address space resources (as one instance of the driver + * is created for each Domain-side IO assembly). (To be complete, only + * one instance of the driver is created on the SSC). */ #include <sys/types.h> @@ -56,7 +85,6 @@ #include <sys/sbbcvar.h> /* driver description */ #include <sys/sbbcio.h> /* ioctl description */ - #define getprop(dip, name, addr, intp) \ ddi_getlongprop(DDI_DEV_T_ANY, (dip), DDI_PROP_DONTPASS, \ (name), (caddr_t)(addr), (intp)) @@ -115,6 +143,7 @@ static void sbbc_remove_reg_maps(struct sbbcsoft *); uint32_t sbbc_dbg_flags = 0x0; static void sbbc_dbg(uint32_t flag, dev_info_t *dip, char *fmt, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5); +static void sbbc_dump_devid(dev_info_t *, struct sbbcsoft *, int instance); #endif /* @@ -131,6 +160,8 @@ int sbbctrace_count; */ static void *sbbcsoft_statep; + +/* Determines whether driver is executing on System Controller or Domain */ int sbbc_scmode = FALSE; /* @@ -261,9 +292,7 @@ sbbc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) char name[32]; struct sbbcsoft *sbbcsoftp; struct ddi_device_acc_attr attr; - uint32_t sbbc_id_reg = 0; - uint16_t sbbc_id_reg_partid; - uint16_t sbbc_id_reg_manfid; + uint32_t sbbc_id_reg; attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; @@ -281,8 +310,8 @@ sbbc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) case DDI_RESUME: if (!(sbbcsoftp = ddi_get_soft_state(sbbcsoft_statep, instance))) { - cmn_err(CE_WARN, - "sbbc_attach:resume: unable to acquire sbbcsoftp for instance %d", + cmn_err(CE_WARN, "sbbc_attach:resume: unable " + "to acquire sbbcsoftp for instance %d", instance); return (DDI_FAILURE); } @@ -300,18 +329,16 @@ sbbc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) } if (ddi_soft_state_zalloc(sbbcsoft_statep, instance) != 0) { - cmn_err(CE_WARN, - "sbbc_attach: Unable to allocate statep for instance %d", - instance); + cmn_err(CE_WARN, "sbbc_attach: Unable to allocate statep " + "for instance %d", instance); return (DDI_FAILURE); } sbbcsoftp = ddi_get_soft_state(sbbcsoft_statep, instance); if (sbbcsoftp == NULL) { - cmn_err(CE_WARN, - "sbbc_attach: Unable to acquire sbbcsoftp for instance %d", - instance); + cmn_err(CE_WARN, "sbbc_attach: Unable to acquire " + "sbbcsoftp for instance %d", instance); ddi_soft_state_free(sbbcsoft_statep, instance); return (DDI_FAILURE); } @@ -326,105 +353,73 @@ sbbc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) * a child gets initialized. */ if (sbbc_get_ranges(sbbcsoftp)) { - cmn_err(CE_WARN, - "sbbc_attach: Unable to read sbbc ranges from OBP %d", instance); - ddi_soft_state_free(sbbcsoft_statep, instance); + cmn_err(CE_WARN, "sbbc_attach: Unable to read sbbc " + "ranges from OBP %d", instance); + ddi_soft_state_free(sbbcsoft_statep, instance); return (DDI_FAILURE); } if (sbbc_config4pci(sbbcsoftp)) { - cmn_err(CE_WARN, - "sbbc_attach: Unable to configure sbbc on PCI %d", instance); - kmem_free(sbbcsoftp->rangep, sbbcsoftp->range_len); - ddi_soft_state_free(sbbcsoft_statep, instance); + cmn_err(CE_WARN, "sbbc_attach: Unable to configure " + "sbbc on PCI %d", instance); + kmem_free(sbbcsoftp->rangep, sbbcsoftp->range_len); + ddi_soft_state_free(sbbcsoft_statep, instance); return (DDI_FAILURE); } - /* - * Map SBBC's internal registers used by hardware access daemon. - */ + mutex_init(&sbbcsoftp->umutex, NULL, MUTEX_DRIVER, (void *)NULL); + mutex_init(&sbbcsoftp->sbbc_intr_mutex, NULL, + MUTEX_DRIVER, (void *)NULL); - /* map the whole thing since OBP does not map individual devices */ + /* Map SBBC's Internal Registers */ if (ddi_regs_map_setup(dip, 1, (caddr_t *)&sbbcsoftp->pci_sbbc_map, - 0, 0, &attr, &sbbcsoftp->pci_sbbc_map_handle) != DDI_SUCCESS) { + offsetof(struct pci_sbbc, sbbc_internal_regs), + sizeof (struct sbbc_regs_map), &attr, + &sbbcsoftp->pci_sbbc_map_handle) != DDI_SUCCESS) { cmn_err(CE_WARN, "(%d):sbbc_attach failed to map sbbc_reg", - instance); + instance); goto failed; } + SBBC_DBG1(SBBC_DBG_ATTACH, dip, "Mapped sbbc at %lx\n", + sbbcsoftp->pci_sbbc_map); +#ifdef DEBUG + sbbc_dump_devid(dip, sbbcsoftp, instance); +#endif + /* + * Read a hardware register to determine if we are executing on + * a Starcat System Controller or a Starcat Domain. + */ sbbc_id_reg = ddi_get32(sbbcsoftp->pci_sbbc_map_handle, - (uint32_t *) - &sbbcsoftp->pci_sbbc_map->sbbc_internal_regs.device_conf); + &sbbcsoftp->pci_sbbc_map->device_conf); if (sbbc_id_reg & SBBC_SC_MODE) { - - SBBC_DBG5(SBBC_DBG_ATTACH, dip, - "Mapped sbbc %llx, regs %llx, eregs %llx, sram %llx, consbus %llx\n", - sbbcsoftp->pci_sbbc_map, - &sbbcsoftp->pci_sbbc_map->sbbc_internal_regs, - &sbbcsoftp->pci_sbbc_map->echip_regs, - &sbbcsoftp->pci_sbbc_map->sram[0], - &sbbcsoftp->pci_sbbc_map->consbus); - - sbbc_id_reg = ddi_get32(sbbcsoftp->pci_sbbc_map_handle, - (uint32_t *) - &sbbcsoftp->pci_sbbc_map->sbbc_internal_regs.devid); - sbbc_id_reg_partid = ((sbbc_id_reg << 4) >> 16); - sbbc_id_reg_manfid = ((sbbc_id_reg << 20) >> 21); - SBBC_DBG4(SBBC_DBG_ATTACH, dip, - "FOUND SBBC(%d) Version %x, Partid %x, Manfid %x\n", - instance, (sbbc_id_reg >> 28), sbbc_id_reg_partid, - sbbc_id_reg_manfid); - sbbc_scmode = TRUE; - SBBC_DBG1(SBBC_DBG_ATTACH, dip, - "SBBC(%d) nexus running in System Controller Mode.\n", - instance); - - /* - * There will be only one SBBC instance on SC and no - * chosen node stuff to deal with :-) - */ + SBBC_DBG1(SBBC_DBG_ATTACH, dip, "SBBC(%d) nexus running " + "in System Controller Mode.\n", instance); + /* initialize SBBC ASIC */ + if (!sbbc_init(sbbcsoftp)) { + goto failed; + } } else { - /* The code below needs to be common with SC mode above */ - - SBBC_DBG4(SBBC_DBG_ATTACH, dip, - "Mapped sbbc %llx, regs %llx, eregs %llx, sram %llx\n", - sbbcsoftp->pci_sbbc_map, - &sbbcsoftp->pci_sbbc_map->sbbc_internal_regs, - &sbbcsoftp->pci_sbbc_map->echip_regs, - &sbbcsoftp->pci_sbbc_map->sram[0]); - - sbbc_id_reg = ddi_get32(sbbcsoftp->pci_sbbc_map_handle, - (uint32_t *) - &sbbcsoftp->pci_sbbc_map->sbbc_internal_regs.devid); - sbbc_id_reg_partid = ((sbbc_id_reg << 4) >> 16); - sbbc_id_reg_manfid = ((sbbc_id_reg << 20) >> 21); - SBBC_DBG4(SBBC_DBG_ATTACH, dip, - "FOUND SBBC(%d) Version %x, Partid %x, Manfid %x\n", - instance, (sbbc_id_reg >> 28), sbbc_id_reg_partid, - sbbc_id_reg_manfid); - sbbc_scmode = FALSE; - SBBC_DBG1(SBBC_DBG_ATTACH, dip, - "SBBC(%d) nexus running in Domain Mode.\n", - instance); + SBBC_DBG1(SBBC_DBG_ATTACH, dip, "SBBC(%d) nexus " + "running in Domain Mode.\n", instance); + + /* initialize SBBC ASIC before we unmap registers */ + if (!sbbc_init(sbbcsoftp)) { + goto failed; + } /* - * There will be only one SBBC instance on SC and no - * chosen node stuff to deal with :-) + * Access to SBBC registers is no longer needed. Unmap + * the registers to conserve kernel virtual address space. */ - - } - - mutex_init(&sbbcsoftp->umutex, NULL, MUTEX_DRIVER, (void *)NULL); - mutex_init(&sbbcsoftp->sbbc_intr_mutex, NULL, - MUTEX_DRIVER, (void *)NULL); - - /* initialize sbbc */ - if (!sbbc_init(sbbcsoftp)) { - goto remlock; + SBBC_DBG1(SBBC_DBG_ATTACH, dip, "SBBC(%d): unmap " + "SBBC registers\n", instance); + sbbc_remove_reg_maps(sbbcsoftp); + sbbcsoftp->pci_sbbc_map = NULL; } (void) sprintf(name, "sbbc%d", instance); @@ -432,7 +427,7 @@ sbbc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) if (ddi_create_minor_node(dip, name, S_IFCHR, instance, NULL, NULL) == DDI_FAILURE) { ddi_remove_minor_node(dip, NULL); - goto remlock; + goto failed; } ddi_report_dev(dip); @@ -441,11 +436,10 @@ sbbc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) return (DDI_SUCCESS); -remlock: +failed: mutex_destroy(&sbbcsoftp->sbbc_intr_mutex); mutex_destroy(&sbbcsoftp->umutex); -failed: sbbc_remove_reg_maps(sbbcsoftp); kmem_free(sbbcsoftp->rangep, sbbcsoftp->range_len); ddi_soft_state_free(sbbcsoft_statep, instance); @@ -1140,6 +1134,11 @@ sbbc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, struct ssc_sbbc_regio sbbcregs; uint64_t offset; + if (sbbc_scmode == FALSE) { + /* then we're executing on Domain; Writes not allowed */ + return (EINVAL); + } + if (arg == NULL) { return (ENXIO); } @@ -1164,7 +1163,7 @@ sbbc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, return (EINVAL); } - offset = (uint64_t)&sbbcsoftp->pci_sbbc_map->sbbc_internal_regs; + offset = (uint64_t)sbbcsoftp->pci_sbbc_map; offset += sbbcregs.offset; ddi_put32(sbbcsoftp->pci_sbbc_map_handle, (uint32_t *)offset, sbbcregs.value); @@ -1175,6 +1174,11 @@ sbbc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, struct ssc_sbbc_regio sbbcregs; uint64_t offset; + if (sbbc_scmode == FALSE) { + /* then we're executing on Domain; Reads not allowed */ + return (EINVAL); + } + if (arg == NULL) { return (ENXIO); } @@ -1199,7 +1203,7 @@ sbbc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, return (EINVAL); } - offset = (uint64_t)&sbbcsoftp->pci_sbbc_map->sbbc_internal_regs; + offset = (uint64_t)sbbcsoftp->pci_sbbc_map; offset += sbbcregs.offset; sbbcregs.value = ddi_get32(sbbcsoftp->pci_sbbc_map_handle, @@ -1227,21 +1231,15 @@ sbbc_remove_reg_maps(struct sbbcsoft *sbbcsoftp) SBBCTRACE(sbbc_remove_reg_maps, 'RMAP', sbbcsoftp); if (sbbcsoftp->pci_sbbc_map_handle) ddi_regs_map_free(&sbbcsoftp->pci_sbbc_map_handle); - - /* need to unmap other registers as well */ } static int sbbc_init(struct sbbcsoft *sbbcsoftp) { - - /* - * setup the regs. and mask all the interrupts - * till we are ready. - */ + /* Mask all the interrupts until we are ready. */ ddi_put32(sbbcsoftp->pci_sbbc_map_handle, - &sbbcsoftp->pci_sbbc_map->sbbc_internal_regs.sys_intr_enable, + &sbbcsoftp->pci_sbbc_map->sys_intr_enable, 0x00000000); return (1); @@ -1470,4 +1468,26 @@ sbbc_dbg(uint32_t flag, dev_info_t *dip, char *fmt, } } +/* + * Dump the SBBC chip's Device ID Register + */ +static void sbbc_dump_devid(dev_info_t *dip, struct sbbcsoft *sbbcsoftp, + int instance) +{ + uint32_t sbbc_id_reg; + uint16_t sbbc_id_reg_partid; + uint16_t sbbc_id_reg_manfid; + + sbbc_id_reg = ddi_get32(sbbcsoftp->pci_sbbc_map_handle, + (uint32_t *)&sbbcsoftp->pci_sbbc_map->devid); + + sbbc_id_reg_partid = ((sbbc_id_reg << 4) >> 16); + sbbc_id_reg_manfid = ((sbbc_id_reg << 20) >> 21); + + SBBC_DBG4(SBBC_DBG_ATTACH, dip, + "FOUND SBBC(%d) Version %x, Partid %x, Manfid %x\n", + instance, (sbbc_id_reg >> 28), sbbc_id_reg_partid, + sbbc_id_reg_manfid); +} + #endif /* DEBUG */ diff --git a/usr/src/uts/sun4u/sys/sbbcreg.h b/usr/src/uts/sun4u/sys/sbbcreg.h index 4966d1379d..432049298b 100644 --- a/usr/src/uts/sun4u/sys/sbbcreg.h +++ b/usr/src/uts/sun4u/sys/sbbcreg.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,8 +19,8 @@ * CDDL HEADER END */ /* - * Copyright (c) 1999-2000 by Sun Microsystems, Inc. - * All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ #ifndef _SYS_SBBCREG_H @@ -129,6 +128,8 @@ struct sbbc_regs_map { uint32_t pci_to_consbus_map; /* 0x0.4000 SBBC */ pad12_t padab; uint32_t consbus_to_pci_map; /* 0x0.4010 SBBC */ + uint32_t pad14[2247]; + /* 0x0.6330 SBBC */ }; @@ -207,7 +208,7 @@ struct ssc_eild_reg_map { struct pci_sbbc { uint8_t fprom[0x800000]; /* FPROM */ struct sbbc_regs_map sbbc_internal_regs; /* sbbc registers */ - uint8_t dontcare[0x7BFEC]; /* non-sbbc registers */ + uint8_t dontcare[0x79CD0]; /* reserved sbbc registers */ struct ssc_echip_regs echip_regs; struct ssc_devpresence_regs devpres_regs; struct ssc_i2cmux_regs i2cmux_regs; diff --git a/usr/src/uts/sun4u/sys/sbbcvar.h b/usr/src/uts/sun4u/sys/sbbcvar.h index d73dd526ea..8937836885 100644 --- a/usr/src/uts/sun4u/sys/sbbcvar.h +++ b/usr/src/uts/sun4u/sys/sbbcvar.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -103,7 +102,7 @@ typedef struct sbbcsoft { sbbc_pci_rangespec_t *rangep; int range_cnt; int range_len; - struct pci_sbbc *pci_sbbc_map; /* sbbc registers and devices */ + struct sbbc_regs_map *pci_sbbc_map; /* SBBC Internal Registers */ ddi_acc_handle_t pci_sbbc_map_handle; ddi_iblock_cookie_t sbbc_iblock_cookie; /* interrupt block cookie */ kmutex_t sbbc_intr_mutex; /* lock for interrupts */ |