1/* $NetBSD: acpi_pci_smccc.c,v 1.2 2022/10/15 10:45:40 jmcneill Exp $ */ 2 3/*- 4 * Copyright (c) 2021 Jared McNeill <jmcneill@invisible.ca> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29#include <sys/cdefs.h> 30__KERNEL_RCSID(0, "$NetBSD: acpi_pci_smccc.c,v 1.2 2022/10/15 10:45:40 jmcneill Exp $"); 31 32#include <sys/param.h> 33#include <sys/kernel.h> 34 35#include <dev/pci/pcireg.h> 36#include <dev/pci/pcivar.h> 37#include <dev/pci/pciconf.h> 38 39#include <dev/acpi/acpivar.h> 40#include <dev/acpi/acpi_pci.h> 41#include <dev/acpi/acpi_mcfg.h> 42 43#include <arm/acpi/acpi_pci_machdep.h> 44 45#include <arm/pci/pci_smccc.h> 46 47static int 48acpi_pci_smccc_conf_read(pci_chipset_tag_t pc, pcitag_t tag, int reg, 49 pcireg_t *data) 50{ 51 struct acpi_pci_context *ap = pc->pc_conf_v; 52 int b, d, f; 53 int status; 54 55 pci_decompose_tag(pc, tag, &b, &d, &f); 56 57 if (b < ap->ap_bus || b > ap->ap_maxbus) { 58 *data = -1; 59 return EINVAL; 60 } 61 62 status = pci_smccc_read(PCI_SMCCC_SBDF(ap->ap_seg, b, d, f), reg, 63 PCI_SMCCC_ACCESS_32BIT, data); 64 if (!PCI_SMCCC_SUCCESS(status)) { 65 *data = -1; 66 return EINVAL; 67 } 68 69 return 0; 70} 71 72static int 73acpi_pci_smccc_conf_write(pci_chipset_tag_t pc, pcitag_t tag, int reg, 74 pcireg_t data) 75{ 76 struct acpi_pci_context *ap = pc->pc_conf_v; 77 int b, d, f; 78 int status; 79 80 pci_decompose_tag(pc, tag, &b, &d, &f); 81 82 if (b < ap->ap_bus || b > ap->ap_maxbus) { 83 return EINVAL; 84 } 85 86 status = pci_smccc_write(PCI_SMCCC_SBDF(ap->ap_seg, b, d, f), reg, 87 PCI_SMCCC_ACCESS_32BIT, data); 88 if (!PCI_SMCCC_SUCCESS(status)) { 89 return EINVAL; 90 } 91 92 return 0; 93} 94 95 96void 97acpi_pci_smccc_init(struct acpi_pci_context *ap) 98{ 99 int status, ver; 100 uint8_t bus_start, bus_end; 101 uint16_t next_seg; 102 103 ver = pci_smccc_version(); 104 if (!PCI_SMCCC_SUCCESS(ver)) { 105 aprint_error_dev(ap->ap_dev, 106 "SMCCC: PCI_VERSION call failed, status %#x\n", ver); 107 return; 108 } 109 aprint_normal_dev(ap->ap_dev, "SMCCC: PCI impl. version %u.%u\n", 110 (ver >> 16) & 0x7fff, ver & 0xffff); 111 112 status = pci_smccc_get_seg_info(ap->ap_seg, &bus_start, &bus_end, 113 &next_seg); 114 if (!PCI_SMCCC_SUCCESS(status)) { 115 aprint_error_dev(ap->ap_dev, 116 "SMCCC: No info for segment %u, status %#x\n", 117 ap->ap_seg, status); 118 return; 119 } 120 aprint_normal_dev(ap->ap_dev, "SMCCC: segment %u, bus %u-%u\n", 121 ap->ap_seg, bus_start, bus_end); 122 123 ap->ap_bus = bus_start; 124 ap->ap_maxbus = bus_end; 125 ap->ap_conf_read = acpi_pci_smccc_conf_read; 126 ap->ap_conf_write = acpi_pci_smccc_conf_write; 127 ap->ap_flags |= ACPI_PCI_FLAG_NO_MCFG; 128 ap->ap_pciflags_clear = PCI_FLAGS_MSI_OKAY | PCI_FLAGS_MSIX_OKAY; 129} 130