/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * 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. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. */ #include #include #include #include #include #include #include #include "list.h" extern int mdb_devinfo2driver(uintptr_t, char *, size_t); static char * irm_get_type(int type) { if (type == (DDI_INTR_TYPE_MSI | DDI_INTR_TYPE_MSIX)) return ("MSI/X"); switch (type) { case DDI_INTR_TYPE_FIXED: return ("Fixed"); case DDI_INTR_TYPE_MSI: return ("MSI"); case DDI_INTR_TYPE_MSIX: return ("MSI-X"); default: return ("Unknown"); } } static int check_irm_enabled(void) { GElf_Sym sym; uintptr_t addr; int value; if (mdb_lookup_by_name("irm_enable", &sym) == -1) { mdb_warn("couldn't find irm_enable"); return (0); } addr = (uintptr_t)sym.st_value; if (mdb_vread(&value, sizeof (value), addr) != sizeof (value)) { mdb_warn("couldn't read irm_enable at %p", addr); return (0); } return (value); } int irmpools_walk_init(mdb_walk_state_t *wsp) { GElf_Sym sym; if (mdb_lookup_by_name("irm_pools_list", &sym) == -1) { mdb_warn("couldn't find irm_pools_list"); return (WALK_ERR); } wsp->walk_addr = (uintptr_t)sym.st_value; return (list_walk_init_named(wsp, "interrupt pools", "pool")); } int irmreqs_walk_init(mdb_walk_state_t *wsp) { wsp->walk_addr = (uintptr_t)(wsp->walk_addr + offsetof(ddi_irm_pool_t, ipool_req_list)); return (list_walk_init_named(wsp, "interrupt requests", "request")); } int irmpools_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) { ddi_irm_pool_t pool; struct dev_info dev; char driver[MODMAXNAMELEN + 1] = ""; char devname[MODMAXNAMELEN + 1] = ""; if (argc != 0) return (DCMD_USAGE); if (check_irm_enabled() == 0) { mdb_warn("IRM is not enabled"); return (DCMD_ERR); } if (!(flags & DCMD_ADDRSPEC)) { if (mdb_walk_dcmd("irmpools", "irmpools", argc, argv) == -1) { mdb_warn("can't walk interrupt pools"); return (DCMD_ERR); } return (DCMD_OK); } if (DCMD_HDRSPEC(flags)) { mdb_printf("%%?s %-18s %-8s %-6s %-9s %-8s%\n", "ADDR", "OWNER", "TYPE", "SIZE", "REQUESTED", "RESERVED"); } if (mdb_vread(&pool, sizeof (pool), addr) != sizeof (pool)) { mdb_warn("couldn't read interrupt pool at %p", addr); return (DCMD_ERR); } if (mdb_vread(&dev, sizeof (dev), (uintptr_t)pool.ipool_owner) != sizeof (dev)) { mdb_warn("couldn't read dev_info at %p", pool.ipool_owner); return (DCMD_ERR); } mdb_devinfo2driver((uintptr_t)pool.ipool_owner, driver, sizeof (driver)); /* * Include driver instance number only if the node has an * instance number assigned (i.e. instance != -1) to it. * This will cover cases like rootnex driver which doesn't * have instance number assigned to it. */ if (dev.devi_instance != -1) mdb_snprintf(devname, sizeof (devname), "%s#%d", driver, dev.devi_instance); else mdb_snprintf(devname, sizeof (devname), "%s", driver); mdb_printf("%0?p %-18s %-8s %-6d %-9d %-8d\n", addr, devname, irm_get_type(pool.ipool_types), pool.ipool_totsz, pool.ipool_reqno, pool.ipool_resno); return (DCMD_OK); } int irmreqs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) { if (argc != 0) return (DCMD_USAGE); if (check_irm_enabled() == 0) { mdb_warn("IRM is not enabled"); return (DCMD_ERR); } if (!(flags & DCMD_ADDRSPEC)) { mdb_warn("can't perform global interrupt request walk"); return (DCMD_ERR); } if (mdb_pwalk_dcmd("irmreqs", "irmreq", argc, argv, addr) == -1) { mdb_warn("can't walk interrupt requests"); return (DCMD_ERR); } return (DCMD_OK); } /*ARGSUSED*/ int irmreq_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) { ddi_irm_req_t req; struct dev_info dev; struct devinfo_intr intr; char driver[MODMAXNAMELEN + 1] = ""; char devname[MODMAXNAMELEN + 1] = ""; if (argc != 0) return (DCMD_USAGE); if (!(flags & DCMD_ADDRSPEC)) { return (DCMD_ERR); } if (DCMD_HDRSPEC(flags)) { mdb_printf("%%?s %-18s %-8s %-8s %-6s %-4s " "%-6s%\n", "ADDR", "OWNER", "TYPE", "CALLBACK", "NINTRS", "NREQ", "NAVAIL"); } if (mdb_vread(&req, sizeof (req), addr) != sizeof (req)) { mdb_warn("couldn't read interrupt request at %p", addr); return (DCMD_ERR); } if (mdb_vread(&dev, sizeof (dev), (uintptr_t)req.ireq_dip) != sizeof (dev)) { mdb_warn("couldn't read dev_info at %p", req.ireq_dip); return (DCMD_ERR); } if (mdb_vread(&intr, sizeof (intr), (uintptr_t)dev.devi_intr_p) != sizeof (intr)) { mdb_warn("couldn't read devinfo_intr at %p", dev.devi_intr_p); return (DCMD_ERR); } mdb_devinfo2driver((uintptr_t)req.ireq_dip, driver, sizeof (driver)); mdb_snprintf(devname, sizeof (devname), "%s#%d", driver, dev.devi_instance); mdb_printf("%0?p %-18s %-8s %-8s %-6d %-4d %-6d\n", addr, devname, irm_get_type(req.ireq_type), (req.ireq_flags & DDI_IRM_FLAG_CALLBACK) ? "Yes" : "No", intr.devi_intr_sup_nintrs, req.ireq_nreq, req.ireq_navail); return (DCMD_OK); }