/* * 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. * * 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 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include typedef struct gfxp_pci_bsf { uint16_t vendor; uint16_t device; uint8_t bus; uint8_t slot; uint8_t function; uint8_t found; dev_info_t *dip; } gfxp_pci_bsf_t; /* The use of pci_get?/put?_func() depends on misc/pci_autoconfig */ static int gfxp_pci_get_bsf(dev_info_t *dip, uint8_t *bus, uint8_t *dev, uint8_t *func) { pci_regspec_t *pci_rp; uint32_t length; int rc; /* get "reg" property */ rc = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg", (int **)&pci_rp, (uint_t *)&length); if ((rc != DDI_SUCCESS) || (length < (sizeof (pci_regspec_t) / sizeof (int)))) { return (DDI_FAILURE); } *bus = PCI_REG_BUS_G(pci_rp->pci_phys_hi); *dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi); *func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi); /* * free the memory allocated by ddi_prop_lookup_int_array(). */ ddi_prop_free(pci_rp); return (DDI_SUCCESS); } static int gfxp_pci_find_bsf(dev_info_t *dip, void *arg) { int rc; uint8_t bus, dev, func; gfxp_pci_bsf_t *pci_bsf; int vendor_id, device_id, class_code; /* * Look for vendor-id, device-id, class-code to verify * this is some type of PCI child node. */ vendor_id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "vendor-id", -1); device_id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "device-id", -1); class_code = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "class-code", -1); if ((vendor_id == -1) || (device_id == -1) || (class_code == -1)) { return (DDI_WALK_CONTINUE); } if (gfxp_pci_get_bsf(dip, &bus, &dev, &func) != DDI_SUCCESS) return (DDI_WALK_TERMINATE); pci_bsf = (gfxp_pci_bsf_t *)arg; if ((bus == pci_bsf->bus) && (dev == pci_bsf->slot) && (func == pci_bsf->function)) { pci_bsf->dip = dip; pci_bsf->vendor = vendor_id; pci_bsf->device = device_id; pci_bsf->found = 1; rc = DDI_WALK_TERMINATE; } else { rc = DDI_WALK_CONTINUE; } return (rc); } gfxp_acc_handle_t gfxp_pci_init_handle(uint8_t bus, uint8_t slot, uint8_t function, uint16_t *vendor, uint16_t *device) { dev_info_t *dip; gfxp_pci_bsf_t *pci_bsf; /* * Find a PCI device based on its address, and return a unique handle * to be used in subsequent calls to read from or write to the config * space of this device. */ if ((pci_bsf = kmem_zalloc(sizeof (gfxp_pci_bsf_t), KM_SLEEP)) == NULL) { return (NULL); } pci_bsf->bus = bus; pci_bsf->slot = slot; pci_bsf->function = function; ddi_walk_devs(ddi_root_node(), gfxp_pci_find_bsf, pci_bsf); if (pci_bsf->found) { dip = pci_bsf->dip; if (vendor) *vendor = pci_bsf->vendor; if (device) *device = pci_bsf->device; } else { dip = NULL; if (vendor) *vendor = 0x0000; if (device) *device = 0x0000; } kmem_free(pci_bsf, sizeof (gfxp_pci_bsf_t)); return ((gfxp_acc_handle_t)dip); } uint8_t gfxp_pci_read_byte(gfxp_acc_handle_t handle, uint16_t offset) { dev_info_t *dip = (dev_info_t *)handle; uint8_t val; uint8_t bus, dev, func; if (dip == NULL) return ((uint8_t)~0); if (gfxp_pci_get_bsf(dip, &bus, &dev, &func) != DDI_SUCCESS) return ((uint8_t)~0); val = (*pci_getb_func)(bus, dev, func, offset); return (val); } uint16_t gfxp_pci_read_word(gfxp_acc_handle_t handle, uint16_t offset) { dev_info_t *dip = (dev_info_t *)handle; uint16_t val; uint8_t bus, dev, func; if (dip == NULL) return ((uint16_t)~0); if (gfxp_pci_get_bsf(dip, &bus, &dev, &func) != DDI_SUCCESS) return ((uint16_t)~0); val = (*pci_getw_func)(bus, dev, func, offset); return (val); } uint32_t gfxp_pci_read_dword(gfxp_acc_handle_t handle, uint16_t offset) { dev_info_t *dip = (dev_info_t *)handle; uint32_t val; uint8_t bus, dev, func; if (dip == NULL) return ((uint32_t)~0); if (gfxp_pci_get_bsf(dip, &bus, &dev, &func) != DDI_SUCCESS) return ((uint32_t)~0); val = (*pci_getl_func)(bus, dev, func, offset); return (val); } void gfxp_pci_write_byte(gfxp_acc_handle_t handle, uint16_t offset, uint8_t value) { dev_info_t *dip = (dev_info_t *)handle; uint8_t bus, dev, func; if (dip == NULL) return; if (gfxp_pci_get_bsf(dip, &bus, &dev, &func) != DDI_SUCCESS) return; (*pci_putb_func)(bus, dev, func, offset, value); } void gfxp_pci_write_word(gfxp_acc_handle_t handle, uint16_t offset, uint16_t value) { dev_info_t *dip = (dev_info_t *)handle; uint8_t bus, dev, func; if (dip == NULL) return; if (gfxp_pci_get_bsf(dip, &bus, &dev, &func) != DDI_SUCCESS) return; (*pci_putw_func)(bus, dev, func, offset, value); } void gfxp_pci_write_dword(gfxp_acc_handle_t handle, uint16_t offset, uint32_t value) { dev_info_t *dip = (dev_info_t *)handle; uint8_t bus, dev, func; if (dip == NULL) return; if (gfxp_pci_get_bsf(dip, &bus, &dev, &func) != DDI_SUCCESS) return; (*pci_putl_func)(bus, dev, func, offset, value); } static int gfxp_pci_find_vd(dev_info_t *dip, void *arg) { int rc; gfxp_pci_bsf_t *pci_bsf; int vendor_id, device_id, class_code; /* * Look for vendor-id, device-id, class-code to verify * this is some type of PCI child node. */ vendor_id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "vendor-id", -1); device_id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "device-id", -1); class_code = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "class-code", -1); if ((vendor_id == -1) || (device_id == -1) || (class_code == -1)) { return (DDI_WALK_CONTINUE); } pci_bsf = (gfxp_pci_bsf_t *)arg; if ((vendor_id == pci_bsf->vendor) && (device_id == pci_bsf->device)) { pci_bsf->found = 1; rc = DDI_WALK_TERMINATE; } else { rc = DDI_WALK_CONTINUE; } return (rc); } int gfxp_pci_device_present(uint16_t vendor, uint16_t device) { gfxp_pci_bsf_t *pci_bsf; int rv; /* * Find a PCI device based on its device and vendor id. */ if ((pci_bsf = kmem_zalloc(sizeof (gfxp_pci_bsf_t), KM_SLEEP)) == NULL) return (0); pci_bsf->vendor = vendor; pci_bsf->device = device; ddi_walk_devs(ddi_root_node(), gfxp_pci_find_vd, pci_bsf); if (pci_bsf->found) { rv = 1; } else { rv = 0; } kmem_free(pci_bsf, sizeof (gfxp_pci_bsf_t)); return (rv); }