px_tools.c revision d4476ccb08e9498c2013971c4212dc6362fcec46
69cd775ffd53de411433f1f43de2b4f644793528schwartz * CDDL HEADER START
69cd775ffd53de411433f1f43de2b4f644793528schwartz * The contents of this file are subject to the terms of the
69cd775ffd53de411433f1f43de2b4f644793528schwartz * Common Development and Distribution License, Version 1.0 only
69cd775ffd53de411433f1f43de2b4f644793528schwartz * (the "License"). You may not use this file except in compliance
69cd775ffd53de411433f1f43de2b4f644793528schwartz * with the License.
69cd775ffd53de411433f1f43de2b4f644793528schwartz * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
69cd775ffd53de411433f1f43de2b4f644793528schwartz * See the License for the specific language governing permissions
69cd775ffd53de411433f1f43de2b4f644793528schwartz * and limitations under the License.
69cd775ffd53de411433f1f43de2b4f644793528schwartz * When distributing Covered Code, include this CDDL HEADER in each
69cd775ffd53de411433f1f43de2b4f644793528schwartz * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
69cd775ffd53de411433f1f43de2b4f644793528schwartz * If applicable, add the following below this CDDL HEADER, with the
69cd775ffd53de411433f1f43de2b4f644793528schwartz * fields enclosed by brackets "[]" replaced with your own identifying
69cd775ffd53de411433f1f43de2b4f644793528schwartz * information: Portions Copyright [yyyy] [name of copyright owner]
69cd775ffd53de411433f1f43de2b4f644793528schwartz * CDDL HEADER END
69cd775ffd53de411433f1f43de2b4f644793528schwartz * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
69cd775ffd53de411433f1f43de2b4f644793528schwartz * Use is subject to license terms.
69cd775ffd53de411433f1f43de2b4f644793528schwartz#pragma ident "%Z%%M% %I% %E% SMI"
69cd775ffd53de411433f1f43de2b4f644793528schwartz * PCI Space definitions.
69cd775ffd53de411433f1f43de2b4f644793528schwartz#define PCI_CONFIG_SPACE (PCI_REG_ADDR_G(PCI_ADDR_CONFIG))
69cd775ffd53de411433f1f43de2b4f644793528schwartz#define PCI_MEM32_SPACE (PCI_REG_ADDR_G(PCI_ADDR_MEM32))
69cd775ffd53de411433f1f43de2b4f644793528schwartz#define PCI_MEM64_SPACE (PCI_REG_ADDR_G(PCI_ADDR_MEM64))
69cd775ffd53de411433f1f43de2b4f644793528schwartz * Config space range for a device. IEEE 1275 spec defines for PCI.
69cd775ffd53de411433f1f43de2b4f644793528schwartz * Space for PCI-express is multiplied by PX_PCI_BDF_OFFSET_DELTA
69cd775ffd53de411433f1f43de2b4f644793528schwartz (1 << (PCI_REG_FUNC_SHIFT + PX_PCI_BDF_OFFSET_DELTA))
69cd775ffd53de411433f1f43de2b4f644793528schwartz * Offsets of BARS in config space. First entry of 0 means config space.
69cd775ffd53de411433f1f43de2b4f644793528schwartz * Entries here correlate to pcitool_bars_t enumerated type.
69cd775ffd53de411433f1f43de2b4f644793528schwartzint pci_num_bars = sizeof (pci_bars) / sizeof (pci_bars[0]);
69cd775ffd53de411433f1f43de2b4f644793528schwartz * Validate the cpu_id passed in.
69cd775ffd53de411433f1f43de2b4f644793528schwartz * A value of 1 will be returned for success and zero for failure.
69cd775ffd53de411433f1f43de2b4f644793528schwartz extern const int _ncpu;
69cd775ffd53de411433f1f43de2b4f644793528schwartz return ((cpuid < _ncpu) && (cpu[cpuid] && cpu_is_online(cpu[cpuid])));
69cd775ffd53de411433f1f43de2b4f644793528schwartz if (ddi_copyout(&pxtool_num_inos, arg, sizeof (uint32_t), mode) !=
69cd775ffd53de411433f1f43de2b4f644793528schwartz * Get interrupt information for a given ino.
69cd775ffd53de411433f1f43de2b4f644793528schwartz * Returns info only for inos mapped to devices.
69cd775ffd53de411433f1f43de2b4f644793528schwartz * Returned info is valid only when iget.num_devs is returned > 0.
69cd775ffd53de411433f1f43de2b4f644793528schwartz * If ino is not enabled or is not mapped to a device,
69cd775ffd53de411433f1f43de2b4f644793528schwartz * iget.num_devs will be returned as = 0.
69cd775ffd53de411433f1f43de2b4f644793528schwartz/*ARGSUSED*/
69cd775ffd53de411433f1f43de2b4f644793528schwartzpxtool_get_intr(dev_info_t *dip, void *arg, int mode)
69cd775ffd53de411433f1f43de2b4f644793528schwartz /* Array part isn't used here, but oh well... */
69cd775ffd53de411433f1f43de2b4f644793528schwartz /* Read in just the header part, no array section. */
69cd775ffd53de411433f1f43de2b4f644793528schwartz if (ddi_copyin(arg, &partial_iget, PCITOOL_IGET_SIZE(0), mode) !=
69cd775ffd53de411433f1f43de2b4f644793528schwartz partial_iget.num_devs_ret = 0; /* Assume error for now. */
69cd775ffd53de411433f1f43de2b4f644793528schwartz /* Validate argument. */
69cd775ffd53de411433f1f43de2b4f644793528schwartz /* Caller wants device information returned. */
69cd775ffd53de411433f1f43de2b4f644793528schwartz * Allocate room.
69cd775ffd53de411433f1f43de2b4f644793528schwartz * Note if num_devs == 0 iget remains pointing to
69cd775ffd53de411433f1f43de2b4f644793528schwartz * partial_iget.
69cd775ffd53de411433f1f43de2b4f644793528schwartz iget_kmem_alloc_size = PCITOOL_IGET_SIZE(num_devs_ret);
69cd775ffd53de411433f1f43de2b4f644793528schwartz /* Read in whole structure to verify there's room. */
69cd775ffd53de411433f1f43de2b4f644793528schwartz if (ddi_copyin(arg, iget, iget_kmem_alloc_size, mode) !=
69cd775ffd53de411433f1f43de2b4f644793528schwartz /* Be consistent and just return EFAULT here. */
69cd775ffd53de411433f1f43de2b4f644793528schwartz /* Convert leaf-wide intr to system-wide intr */
69cd775ffd53de411433f1f43de2b4f644793528schwartz if (px_lib_intr_devino_to_sysino(dip, iget->ino, &sysino) ==
69cd775ffd53de411433f1f43de2b4f644793528schwartz /* Operate only on inos which are already enabled. */
69cd775ffd53de411433f1f43de2b4f644793528schwartz if (px_lib_intr_getvalid(dip, sysino, &intr_valid_state) ==
69cd775ffd53de411433f1f43de2b4f644793528schwartz * Consider all valid inos: those mapped to the root complex itself
69cd775ffd53de411433f1f43de2b4f644793528schwartz * as well as those mapped to devices.
69cd775ffd53de411433f1f43de2b4f644793528schwartz * The following looks up the px_ib_ino_info and returns
69cd775ffd53de411433f1f43de2b4f644793528schwartz * info of devices mapped to this ino.
69cd775ffd53de411433f1f43de2b4f644793528schwartz if (px_lib_intr_gettarget(dip, sysino, &old_cpu_id) ==
69cd775ffd53de411433f1f43de2b4f644793528schwartz ddi_copyout(iget, arg, PCITOOL_IGET_SIZE(num_devs_ret), mode);
69cd775ffd53de411433f1f43de2b4f644793528schwartz * Associate a new CPU with a given ino.
69cd775ffd53de411433f1f43de2b4f644793528schwartz * Operate only on inos which are already mapped to devices.
69cd775ffd53de411433f1f43de2b4f644793528schwartzpxtool_set_intr(dev_info_t *dip, void *arg, int mode)
69cd775ffd53de411433f1f43de2b4f644793528schwartz if (ddi_copyin(arg, &iset, sizeof (pcitool_intr_set_t), mode) !=
69cd775ffd53de411433f1f43de2b4f644793528schwartz /* Validate input argument. */
69cd775ffd53de411433f1f43de2b4f644793528schwartz /* Validate that ino given belongs to a device. */
69cd775ffd53de411433f1f43de2b4f644793528schwartz if (pxtool_ib_get_ino_devs(px_p, iset.ino, &zero, NULL) == 0)
69cd775ffd53de411433f1f43de2b4f644793528schwartz * Get lock, validate cpu and write new mapreg value.
69cd775ffd53de411433f1f43de2b4f644793528schwartz * Return original cpu value to caller via iset.cpu.
69cd775ffd53de411433f1f43de2b4f644793528schwartz DBG(DBG_TOOLS, dip, "Enabling CPU %d\n", iset.cpu_id);
69cd775ffd53de411433f1f43de2b4f644793528schwartz if (px_lib_intr_devino_to_sysino(dip, iset.ino, &sysino) ==
69cd775ffd53de411433f1f43de2b4f644793528schwartz if (px_lib_intr_gettarget(dip, sysino, &old_cpu_id) ==
69cd775ffd53de411433f1f43de2b4f644793528schwartz px_ib_intr_dist_en(dip, iset.cpu_id, iset.ino, B_TRUE);
69cd775ffd53de411433f1f43de2b4f644793528schwartz px_ib_log_new_cpu(ib_p, old_cpu_id, iset.cpu_id, iset.ino);
69cd775ffd53de411433f1f43de2b4f644793528schwartz } else { /* Invalid cpu. Restore original register image. */
69cd775ffd53de411433f1f43de2b4f644793528schwartz "Invalid cpuid: writing orig mapreg value\n");
69cd775ffd53de411433f1f43de2b4f644793528schwartz if (ddi_copyout(&iset, arg, sizeof (pcitool_intr_set_t), mode) !=
69cd775ffd53de411433f1f43de2b4f644793528schwartz/* Main function for handling interrupt CPU binding requests and queries. */
69cd775ffd53de411433f1f43de2b4f644793528schwartzpxtool_intr(dev_info_t *dip, void *arg, int cmd, int mode)
69cd775ffd53de411433f1f43de2b4f644793528schwartz /* Return the number of interrupts supported by a PCI bus. */
69cd775ffd53de411433f1f43de2b4f644793528schwartz /* Get interrupt information for a given ino. */
69cd775ffd53de411433f1f43de2b4f644793528schwartz /* Associate a new CPU with a given ino. */
69cd775ffd53de411433f1f43de2b4f644793528schwartz if (prg->barnum >= (sizeof (pci_bars) / sizeof (pci_bars[0]))) {
69cd775ffd53de411433f1f43de2b4f644793528schwartz /* Validate address arguments of bus / dev / func */
69cd775ffd53de411433f1f43de2b4f644793528schwartz (PCI_REG_BUS_M >> PCI_REG_BUS_SHIFT)) != prg->bus_no) ||
69cd775ffd53de411433f1f43de2b4f644793528schwartz (PCI_REG_DEV_M >> PCI_REG_DEV_SHIFT)) != prg->dev_no) ||
69cd775ffd53de411433f1f43de2b4f644793528schwartz (PCI_REG_FUNC_M >> PCI_REG_FUNC_SHIFT)) != prg->func_no)) {
69cd775ffd53de411433f1f43de2b4f644793528schwartzpxtool_get_bar(px_t *px_p, pcitool_reg_t *prg_p, uint64_t max_addr,
69cd775ffd53de411433f1f43de2b4f644793528schwartz pcitool_reg_t cfg_prg = *prg_p; /* Make local copy. */
69cd775ffd53de411433f1f43de2b4f644793528schwartz * Translate BAR number into offset of the BAR in
69cd775ffd53de411433f1f43de2b4f644793528schwartz * the device's config space.
69cd775ffd53de411433f1f43de2b4f644793528schwartz cfg_prg.phys_addr = prg_p->phys_addr + cfg_prg.offset;
69cd775ffd53de411433f1f43de2b4f644793528schwartz PCITOOL_ACC_ATTR_SIZE_4 | PCITOOL_ACC_ATTR_ENDN_LTL;
69cd775ffd53de411433f1f43de2b4f644793528schwartz DBG(DBG_TOOLS, dip, "barnum:%d, phys_addr:0x%" PRIx64 "\n",
69cd775ffd53de411433f1f43de2b4f644793528schwartz * Get Bus Address Register (BAR) from config space.
69cd775ffd53de411433f1f43de2b4f644793528schwartz * cfg_prg.offset is the offset into config space of the
69cd775ffd53de411433f1f43de2b4f644793528schwartz * BAR desired. prg_p->status is modified on error.
69cd775ffd53de411433f1f43de2b4f644793528schwartz rval = pxtool_pcicfg_access(px_p, &cfg_prg, max_addr, bar_p, PX_ISREAD);
69cd775ffd53de411433f1f43de2b4f644793528schwartz DBG(DBG_TOOLS, dip, "bar returned is 0x%" PRIx64 "\n", *bar_p);
69cd775ffd53de411433f1f43de2b4f644793528schwartz * BAR has bits saying this space is IO space, unless
69cd775ffd53de411433f1f43de2b4f644793528schwartz * this is the ROM address register.
69cd775ffd53de411433f1f43de2b4f644793528schwartz if (((PCI_BASE_SPACE_M & *bar_p) == PCI_BASE_SPACE_IO) &&
69cd775ffd53de411433f1f43de2b4f644793528schwartz * BAR has bits saying this space is 64 bit memory
69cd775ffd53de411433f1f43de2b4f644793528schwartz * space, unless this is the ROM address register.
69cd775ffd53de411433f1f43de2b4f644793528schwartz * The 64 bit address stored in two BAR cells is not
69cd775ffd53de411433f1f43de2b4f644793528schwartz * necessarily aligned on an 8-byte boundary.
69cd775ffd53de411433f1f43de2b4f644793528schwartz * Need to keep the first 4 bytes read,
69cd775ffd53de411433f1f43de2b4f644793528schwartz * and do a separate read of the high 4 bytes.
69cd775ffd53de411433f1f43de2b4f644793528schwartz uint32_t low_bytes = (uint32_t)(*bar_p & ~PCI_BASE_TYPE_ALL);
69cd775ffd53de411433f1f43de2b4f644793528schwartz /* Don't try to read the next 4 bytes past the end of BARs. */
69cd775ffd53de411433f1f43de2b4f644793528schwartz /* Access device. prg_p->status is modified on error. */
69cd775ffd53de411433f1f43de2b4f644793528schwartz rval = pxtool_pcicfg_access(px_p, &cfg_prg, max_addr, bar_p,
69cd775ffd53de411433f1f43de2b4f644793528schwartz * Honor the 64 bit BAR as such, only when the upper 32 bits
69cd775ffd53de411433f1f43de2b4f644793528schwartz * store a non-zero value.
69cd775ffd53de411433f1f43de2b4f644793528schwartz } else if (cfg_prg.offset == PCI_CONF_ROM) { /* ROM requested */
69cd775ffd53de411433f1f43de2b4f644793528schwartz * ROM enabled. Filter ROM enable bit from the BAR.
69cd775ffd53de411433f1f43de2b4f644793528schwartz * Treat as Mem32 henceforth.
69cd775ffd53de411433f1f43de2b4f644793528schwartz else { /* ROM disabled. */
69cd775ffd53de411433f1f43de2b4f644793528schwartz /* Accept a bar of 0 only for IO space. */
69cd775ffd53de411433f1f43de2b4f644793528schwartz/* Perform register accesses on PCI leaf devices. */
69cd775ffd53de411433f1f43de2b4f644793528schwartzpxtool_dev_reg_ops(dev_info_t *dip, void *arg, int cmd, int mode)
69cd775ffd53de411433f1f43de2b4f644793528schwartz DBG(DBG_TOOLS, dip, "pxtool_dev_reg_ops set/get reg\n");
69cd775ffd53de411433f1f43de2b4f644793528schwartz if ((rval = pxtool_dev_reg_ops_platchk(dip, &prg)) != SUCCESS) {
69cd775ffd53de411433f1f43de2b4f644793528schwartz DBG(DBG_TOOLS, dip, "raw bus:0x%x, dev:0x%x, func:0x%x\n",
69cd775ffd53de411433f1f43de2b4f644793528schwartz DBG(DBG_TOOLS, dip, "barnum:0x%x, offset:0x%" PRIx64 ", acc:0x%x\n",
69cd775ffd53de411433f1f43de2b4f644793528schwartz if ((rval = pxtool_validate_barnum_bdf(&prg)) != SUCCESS)
69cd775ffd53de411433f1f43de2b4f644793528schwartz range_base = PX_GET_RANGE_PROP(rp, PCI_CONFIG_SPACE);
69cd775ffd53de411433f1f43de2b4f644793528schwartz range_base_size = PX_GET_RANGE_PROP_SIZE(rp, PCI_CONFIG_SPACE);
69cd775ffd53de411433f1f43de2b4f644793528schwartz base_addr = range_base + (PX_GET_BDF(&prg) << PX_PCI_BDF_OFFSET_DELTA);
69cd775ffd53de411433f1f43de2b4f644793528schwartz if (prg.barnum == 0) { /* Proper config space desired. */
69cd775ffd53de411433f1f43de2b4f644793528schwartz /* Access config space and we're done. */
69cd775ffd53de411433f1f43de2b4f644793528schwartz "config access: base:0x%" PRIx64 ", offset:0x%" PRIx64 ", "
69cd775ffd53de411433f1f43de2b4f644793528schwartz PCITOOL_ACC_IS_BIG_ENDIAN(prg.acc_attr) ? "big":"ltl");
69cd775ffd53de411433f1f43de2b4f644793528schwartz * Access device. pr.status is modified.
69cd775ffd53de411433f1f43de2b4f644793528schwartz * BDF is assumed valid at this point.
69cd775ffd53de411433f1f43de2b4f644793528schwartz rval = pxtool_pcicfg_access(px_p, &prg, max_addr, &prg.data,
69cd775ffd53de411433f1f43de2b4f644793528schwartz /* IO/ MEM/ MEM64 space. */
69cd775ffd53de411433f1f43de2b4f644793528schwartz if ((rval = pxtool_get_bar(px_p, &prg, max_addr, &bar, &space)) !=
69cd775ffd53de411433f1f43de2b4f644793528schwartz /* Focus on IO space. */
69cd775ffd53de411433f1f43de2b4f644793528schwartz range_base_size = PX_GET_RANGE_PROP_SIZE(rp, PCI_IO_SPACE);
69cd775ffd53de411433f1f43de2b4f644793528schwartz } else if (space == PCI_MEM64_SPACE) { /* 64 bit memory space. */
69cd775ffd53de411433f1f43de2b4f644793528schwartz "64 bit mem space. 64-bit bar is 0x%" PRIx64 "\n", bar);
69cd775ffd53de411433f1f43de2b4f644793528schwartz /* Set focus to MEM64 range space. */
69cd775ffd53de411433f1f43de2b4f644793528schwartz range_base = PX_GET_RANGE_PROP(rp, PCI_MEM64_SPACE);
69cd775ffd53de411433f1f43de2b4f644793528schwartz range_base_size = PX_GET_RANGE_PROP_SIZE(rp, PCI_MEM64_SPACE);
69cd775ffd53de411433f1f43de2b4f644793528schwartz } else { /* Mem32 space, including ROM */
69cd775ffd53de411433f1f43de2b4f644793528schwartz /* Can't write to ROM */
69cd775ffd53de411433f1f43de2b4f644793528schwartz if ((PCI_BAR_OFFSET(prg) == PCI_CONF_ROM) && (write_flag)) {
69cd775ffd53de411433f1f43de2b4f644793528schwartz range_base = PX_GET_RANGE_PROP(rp, PCI_MEM32_SPACE);
69cd775ffd53de411433f1f43de2b4f644793528schwartz range_base_size = PX_GET_RANGE_PROP_SIZE(rp, PCI_MEM32_SPACE);
69cd775ffd53de411433f1f43de2b4f644793528schwartz /* Common code for all IO/MEM range spaces. */
69cd775ffd53de411433f1f43de2b4f644793528schwartz DBG(DBG_TOOLS, dip, "Range from 0x%" PRIx64 " to 0x%" PRIx64 "\n",
69cd775ffd53de411433f1f43de2b4f644793528schwartz "addr portion of bar is 0x%" PRIx64 ", base=0x%" PRIx64 ", "
69cd775ffd53de411433f1f43de2b4f644793528schwartz "offset:0x%" PRIx64 "\n", bar, base_addr, prg.offset);
69cd775ffd53de411433f1f43de2b4f644793528schwartz * Use offset provided by caller to index into desired space.
69cd775ffd53de411433f1f43de2b4f644793528schwartz * Note that prg.status is modified on error.
69cd775ffd53de411433f1f43de2b4f644793528schwartz rval = pxtool_pciiomem_access(px_p, &prg, max_addr, &prg.data,
69cd775ffd53de411433f1f43de2b4f644793528schwartz DBG(DBG_TOOLS, dip, "Error returning arguments.\n");
69cd775ffd53de411433f1f43de2b4f644793528schwartz if (ddi_create_minor_node(dip, PCI_MINOR_REG, S_IFCHR,
69cd775ffd53de411433f1f43de2b4f644793528schwartz PCIHP_AP_MINOR_NUM(instance, PCI_TOOL_REG_MINOR_NUM),
69cd775ffd53de411433f1f43de2b4f644793528schwartz if (ddi_create_minor_node(dip, PCI_MINOR_INTR, S_IFCHR,