/* * Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ /* * Copyright (c) 2012 Intel Corporation. All rights reserved. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "drmP.h" #include #include #include #define PCI_BUS(x) (((x) & 0xff0000) >> 16) #define PCI_SLOT(x) (((x)>>11) & 0x1f) #define PCI_FUNC(x) (((x) & 0x700) >> 8) struct pci_dev * pci_dev_create(struct drm_device *dev) { dev_info_t *dip = dev->devinfo; pci_regspec_t *regspec; struct pci_dev *pdev; int *regs, ret, len, i; uint_t nregs = 0; pdev = kmem_zalloc(sizeof(struct pci_dev), KM_NOSLEEP); if (!pdev) return (NULL); /* access handle */ ret = pci_config_setup(dip, &pdev->pci_cfg_acc_handle); if (ret != DDI_SUCCESS) { DRM_ERROR("pci_config_setup() failed"); goto err_setup; } /* XXX Fix domain number (alpha hoses) */ pdev->domain = 0; /* bus, slot, func */ ret = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg", (int **)®s, &nregs); if (ret != DDI_PROP_SUCCESS) { DRM_ERROR("ddi_prop_lookup_int_array() failed"); goto err_info; } pdev->bus = (int)PCI_BUS(regs[0]); pdev->slot = (int)PCI_SLOT(regs[0]); pdev->func = (int)PCI_FUNC(regs[0]); ddi_prop_free(regs); /* irq */ ret = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "interrupts", -1); if (ret == -1) { DRM_ERROR("ddi_prop_get_int() failed"); goto err_irq; } if (ret > 0) pdev->irq = pci_config_get8(pdev->pci_cfg_acc_handle, PCI_CONF_ILINE); if (ddi_intr_hilevel(dip, 0) != 0) { DRM_ERROR("high-level interrupts are not supported"); goto err_irq; } if (ddi_get_iblock_cookie(dip, (uint_t)0, &pdev->intr_block) != DDI_SUCCESS) { DRM_ERROR("cannot get iblock cookie"); goto err_irq; } /* regions */ ret = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)®spec, &len); if (ret != DDI_PROP_SUCCESS) { DRM_ERROR("ddi_getlongprop() failed"); goto err_regions; } for (i = 0; i < PCI_CONFIG_REGION_NUMS; i++) { pdev->regions[i].start = (unsigned long)regspec[i].pci_phys_low; pdev->regions[i].size = (unsigned long)regspec[i].pci_size_low; } kmem_free(regspec, (size_t)len); /* vendor, device */ pdev->vendor = ddi_prop_get_int(DDI_DEV_T_ANY, dev->devinfo, DDI_PROP_DONTPASS, "vendor-id", 0); pdev->device = ddi_prop_get_int(DDI_DEV_T_ANY, dev->devinfo, DDI_PROP_DONTPASS, "device-id", 0); pdev->dev = dev; return pdev; err_regions: err_irq: err_info: pci_config_teardown(&pdev->pci_cfg_acc_handle); err_setup: kmem_free(pdev, sizeof(struct pci_dev)); return (NULL); } void pci_dev_destroy(struct pci_dev *pdev) { pci_config_teardown(&pdev->pci_cfg_acc_handle); kmem_free(pdev, sizeof(struct pci_dev)); } void pci_read_config_byte(struct pci_dev *pdev, int where, u8 *val) { *val = pci_config_get8(pdev->pci_cfg_acc_handle, where); } void pci_read_config_word(struct pci_dev *pdev, int where, u16 *val) { *val = pci_config_get16(pdev->pci_cfg_acc_handle, where); } void pci_read_config_dword(struct pci_dev *pdev, int where, u32 *val) { *val = pci_config_get32(pdev->pci_cfg_acc_handle, where); } void pci_write_config_byte(struct pci_dev *pdev, int where, u8 val) { pci_config_put8(pdev->pci_cfg_acc_handle, where, val); } void pci_write_config_word(struct pci_dev *pdev, int where, u16 val) { pci_config_put16(pdev->pci_cfg_acc_handle, where, val); } void pci_write_config_dword(struct pci_dev *pdev, int where, u32 val) { pci_config_put32(pdev->pci_cfg_acc_handle, where, val); } /* LINTED */ u8* pci_map_rom(struct pci_dev *pdev, size_t *size) { u32 base; base = 0xC0000; *size = 0x20000; return (u8*)drm_sun_ioremap(base, *size, DRM_MEM_UNCACHED); } /* LINTED */ void pci_unmap_rom(struct pci_dev *pdev, u8 *base) { iounmap(base); } int pci_find_capability(struct pci_dev *pdev, int capid) { uint8_t cap = 0; uint16_t caps_ptr; /* has capabilities list ? */ if ((pci_config_get16(pdev->pci_cfg_acc_handle, PCI_CONF_STAT) & PCI_CONF_CAP_MASK) == 0) return (0); caps_ptr = pci_config_get8( pdev->pci_cfg_acc_handle, PCI_CONF_CAP_PTR); while (caps_ptr != PCI_CAP_NEXT_PTR_NULL) { cap = pci_config_get32( pdev->pci_cfg_acc_handle, caps_ptr); if ((cap & PCI_CONF_CAPID_MASK) == capid) return (cap); caps_ptr = pci_config_get8( pdev->pci_cfg_acc_handle, caps_ptr + PCI_CAP_NEXT_PTR); } return (0); }