summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorarutz <none@none>2006-08-11 13:07:51 -0700
committerarutz <none@none>2006-08-11 13:07:51 -0700
commitb8dc8477f9e64fb1130ab21dc1f26664309f149d (patch)
tree011fb27cbf87f62a0067064667202f3b7be01c0a /usr/src
parentc793af95640863cd29868fc7c419c5d2496b207b (diff)
downloadillumos-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.c234
-rw-r--r--usr/src/uts/sun4u/sys/sbbcreg.h13
-rw-r--r--usr/src/uts/sun4u/sys/sbbcvar.h9
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 */