c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu/*
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu * CDDL HEADER START
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu *
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu * The contents of this file are subject to the terms of the
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu * Common Development and Distribution License (the "License").
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu * You may not use this file except in compliance with the License.
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu *
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu * or http://www.opensolaris.org/os/licensing.
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu * See the License for the specific language governing permissions
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu * and limitations under the License.
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu *
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu * When distributing Covered Code, include this CDDL HEADER in each
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu * If applicable, add the following below this CDDL HEADER, with the
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu * fields enclosed by brackets "[]" replaced with your own identifying
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu * information: Portions Copyright [yyyy] [name of copyright owner]
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu *
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu * CDDL HEADER END
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu */
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu/*
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu */
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu#include <sys/systm.h>
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu#include <sys/pci_cfgacc.h>
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu#include <sys/pci_cfgspace.h>
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu#include <sys/pci_cfgspace_impl.h>
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu#include <sys/sunddi.h>
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu#include <sys/sysmacros.h>
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu#include <sys/x86_archext.h>
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu#include <sys/pci.h>
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu#include <sys/cmn_err.h>
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu#include <vm/hat_i86.h>
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu#include <vm/seg_kmem.h>
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu#include <vm/kboot_mmu.h>
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu#define PCIE_CFG_SPACE_SIZE (PCI_CONF_HDR_SIZE << 4)
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu#define PCI_BDF_BUS(bdf) ((((uint16_t)bdf) & 0xff00) >> 8)
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu#define PCI_BDF_DEV(bdf) ((((uint16_t)bdf) & 0xf8) >> 3)
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu#define PCI_BDF_FUNC(bdf) (((uint16_t)bdf) & 0x7)
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu/* patchable variables */
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fuvolatile boolean_t pci_cfgacc_force_io = B_FALSE;
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fuextern uintptr_t alloc_vaddr(size_t, paddr_t);
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fuvoid pci_cfgacc_acc(pci_cfgacc_req_t *);
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fuboolean_t pci_cfgacc_find_workaround(uint16_t);
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu/*
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu * IS_P2ALIGNED() is used to make sure offset is 'size'-aligned, so
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu * it's guaranteed that the access will not cross 4k page boundary.
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu * Thus only 1 page is allocated for all config space access, and the
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu * virtual address of that page is cached in pci_cfgacc_virt_base.
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu */
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fustatic caddr_t pci_cfgacc_virt_base = NULL;
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fustatic caddr_t
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fupci_cfgacc_map(paddr_t phys_addr)
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu{
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu#ifdef __xpv
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu phys_addr = pfn_to_pa(xen_assign_pfn(mmu_btop(phys_addr))) |
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu (phys_addr & MMU_PAGEOFFSET);
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu#endif
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu if (khat_running) {
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu pfn_t pfn = mmu_btop(phys_addr);
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu /*
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu * pci_cfgacc_virt_base may hold address left from early
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu * boot, which points to low mem. Realloc virtual address
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu * in kernel space since it's already late in boot now.
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu * Note: no need to unmap first, clear_boot_mappings() will
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu * do that for us.
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu */
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu if (pci_cfgacc_virt_base < (caddr_t)kernelbase)
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu pci_cfgacc_virt_base = vmem_alloc(heap_arena,
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu MMU_PAGESIZE, VM_SLEEP);
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu hat_devload(kas.a_hat, pci_cfgacc_virt_base,
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu MMU_PAGESIZE, pfn, PROT_READ | PROT_WRITE |
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu HAT_STRICTORDER, HAT_LOAD_LOCK);
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu } else {
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu paddr_t pa_base = P2ALIGN(phys_addr, MMU_PAGESIZE);
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu if (pci_cfgacc_virt_base == NULL)
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu pci_cfgacc_virt_base =
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu (caddr_t)alloc_vaddr(MMU_PAGESIZE, MMU_PAGESIZE);
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu kbm_map((uintptr_t)pci_cfgacc_virt_base, pa_base, 0, 0);
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu }
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu return (pci_cfgacc_virt_base + (phys_addr & MMU_PAGEOFFSET));
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu}
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fustatic void
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fupci_cfgacc_unmap()
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu{
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu if (khat_running)
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu hat_unload(kas.a_hat, pci_cfgacc_virt_base, MMU_PAGESIZE,
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu HAT_UNLOAD_UNLOCK);
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu}
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fustatic void
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fupci_cfgacc_io(pci_cfgacc_req_t *req)
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu{
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu uint8_t bus, dev, func;
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu uint16_t ioacc_offset; /* 4K config access with IO ECS */
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu bus = PCI_BDF_BUS(req->bdf);
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu dev = PCI_BDF_DEV(req->bdf);
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu func = PCI_BDF_FUNC(req->bdf);
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu ioacc_offset = req->offset;
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu switch (req->size) {
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu case 1:
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu if (req->write)
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu (*pci_putb_func)(bus, dev, func,
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu ioacc_offset, VAL8(req));
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu else
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu VAL8(req) = (*pci_getb_func)(bus, dev, func,
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu ioacc_offset);
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu break;
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu case 2:
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu if (req->write)
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu (*pci_putw_func)(bus, dev, func,
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu ioacc_offset, VAL16(req));
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu else
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu VAL16(req) = (*pci_getw_func)(bus, dev, func,
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu ioacc_offset);
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu break;
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu case 4:
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu if (req->write)
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu (*pci_putl_func)(bus, dev, func,
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu ioacc_offset, VAL32(req));
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu else
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu VAL32(req) = (*pci_getl_func)(bus, dev, func,
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu ioacc_offset);
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu break;
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu case 8:
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu if (req->write) {
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu (*pci_putl_func)(bus, dev, func,
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu ioacc_offset, VAL64(req) & 0xffffffff);
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu (*pci_putl_func)(bus, dev, func,
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu ioacc_offset + 4, VAL64(req) >> 32);
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu } else {
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu VAL64(req) = (*pci_getl_func)(bus, dev, func,
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu ioacc_offset);
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu VAL64(req) |= (uint64_t)(*pci_getl_func)(bus, dev, func,
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu ioacc_offset + 4) << 32;
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu }
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu break;
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu }
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu}
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fustatic void
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fupci_cfgacc_mmio(pci_cfgacc_req_t *req)
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu{
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu caddr_t vaddr;
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu paddr_t paddr;
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu paddr = (paddr_t)req->bdf << 12;
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu paddr += mcfg_mem_base + req->offset;
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu
137632774395dba0eb9b77257da1d8732bd5413dGuoli Shu mutex_enter(&pcicfg_mmio_mutex);
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu vaddr = pci_cfgacc_map(paddr);
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu switch (req->size) {
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu case 1:
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu if (req->write)
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu *((uint8_t *)vaddr) = VAL8(req);
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu else
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu VAL8(req) = *((uint8_t *)vaddr);
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu break;
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu case 2:
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu if (req->write)
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu *((uint16_t *)vaddr) = VAL16(req);
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu else
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu VAL16(req) = *((uint16_t *)vaddr);
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu break;
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu case 4:
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu if (req->write)
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu *((uint32_t *)vaddr) = VAL32(req);
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu else
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu VAL32(req) = *((uint32_t *)vaddr);
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu break;
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu case 8:
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu if (req->write)
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu *((uint64_t *)vaddr) = VAL64(req);
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu else
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu VAL64(req) = *((uint64_t *)vaddr);
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu break;
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu }
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu pci_cfgacc_unmap();
137632774395dba0eb9b77257da1d8732bd5413dGuoli Shu mutex_exit(&pcicfg_mmio_mutex);
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu}
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fustatic boolean_t
586fe2c2bfa4216c91ca1ccaf9b43738d60ede7eZhi-Jun Robin Fupci_cfgacc_valid(pci_cfgacc_req_t *req, uint16_t cfgspc_size)
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu{
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu int sz = req->size;
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu if (IS_P2ALIGNED(req->offset, sz) &&
586fe2c2bfa4216c91ca1ccaf9b43738d60ede7eZhi-Jun Robin Fu (req->offset + sz - 1 < cfgspc_size) &&
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu ((sz & 0xf) && ISP2(sz)))
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu return (B_TRUE);
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu cmn_err(CE_WARN, "illegal PCI request: offset = %x, size = %d",
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu req->offset, sz);
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu return (B_FALSE);
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu}
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fuvoid
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fupci_cfgacc_check_io(pci_cfgacc_req_t *req)
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu{
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu uint8_t bus;
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu bus = PCI_BDF_BUS(req->bdf);
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu if (pci_cfgacc_force_io || (mcfg_mem_base == NULL) ||
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu (bus < mcfg_bus_start) || (bus > mcfg_bus_end) ||
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu pci_cfgacc_find_workaround(req->bdf))
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu req->ioacc = B_TRUE;
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu}
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fuvoid
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fupci_cfgacc_acc(pci_cfgacc_req_t *req)
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu{
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu extern uint_t pci_iocfg_max_offset;
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu if (!req->write)
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu VAL64(req) = (uint64_t)-1;
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu pci_cfgacc_check_io(req);
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu if (req->ioacc) {
586fe2c2bfa4216c91ca1ccaf9b43738d60ede7eZhi-Jun Robin Fu if (pci_cfgacc_valid(req, pci_iocfg_max_offset + 1))
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu pci_cfgacc_io(req);
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu } else {
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu if (pci_cfgacc_valid(req, PCIE_CFG_SPACE_SIZE))
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu pci_cfgacc_mmio(req);
8d7fafffed373567f52062b634e61fd50858b8d9Zhi-Jun Robin Fu }
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu}
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Futypedef struct cfgacc_bus_range {
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu struct cfgacc_bus_range *next;
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu uint16_t bdf;
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu uchar_t secbus;
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu uchar_t subbus;
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu} cfgacc_bus_range_t;
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fucfgacc_bus_range_t *pci_cfgacc_bus_head = NULL;
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu#define BUS_INSERT(prev, el) \
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu el->next = *prev; \
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu *prev = el;
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu#define BUS_REMOVE(prev, el) \
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu *prev = el->next;
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu/*
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu * This function is only supposed to be called in device tree setup time,
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu * thus no lock is needed.
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu */
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fuvoid
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fupci_cfgacc_add_workaround(uint16_t bdf, uchar_t secbus, uchar_t subbus)
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu{
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu cfgacc_bus_range_t *entry;
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu entry = kmem_zalloc(sizeof (cfgacc_bus_range_t), KM_SLEEP);
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu entry->bdf = bdf;
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu entry->secbus = secbus;
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu entry->subbus = subbus;
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu BUS_INSERT(&pci_cfgacc_bus_head, entry);
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu}
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fuboolean_t
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fupci_cfgacc_find_workaround(uint16_t bdf)
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu{
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu cfgacc_bus_range_t *entry;
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu uchar_t bus;
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu for (entry = pci_cfgacc_bus_head; entry != NULL;
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu entry = entry->next) {
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu if (bdf == entry->bdf) {
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu /* found a device which is known to be broken */
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu return (B_TRUE);
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu }
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu bus = PCI_BDF_BUS(bdf);
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu if ((bus != 0) && (bus >= entry->secbus) &&
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu (bus <= entry->subbus)) {
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu /*
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu * found a device whose parent/grandparent is
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu * known to be broken.
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu */
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu return (B_TRUE);
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu }
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu }
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu return (B_FALSE);
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu}