1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved. 3*91f16700Schasinglulu * 4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 5*91f16700Schasinglulu */ 6*91f16700Schasinglulu 7*91f16700Schasinglulu #include <assert.h> 8*91f16700Schasinglulu #include <stdint.h> 9*91f16700Schasinglulu 10*91f16700Schasinglulu #include <common/debug.h> 11*91f16700Schasinglulu #include <common/runtime_svc.h> 12*91f16700Schasinglulu #include <services/pci_svc.h> 13*91f16700Schasinglulu #include <services/std_svc.h> 14*91f16700Schasinglulu #include <smccc_helpers.h> 15*91f16700Schasinglulu 16*91f16700Schasinglulu static uint64_t validate_rw_addr_sz(uint32_t addr, uint64_t off, uint64_t sz) 17*91f16700Schasinglulu { 18*91f16700Schasinglulu uint32_t nseg; 19*91f16700Schasinglulu uint32_t ret; 20*91f16700Schasinglulu uint32_t start_end_bus; 21*91f16700Schasinglulu 22*91f16700Schasinglulu ret = pci_get_bus_for_seg(PCI_ADDR_SEG(addr), &start_end_bus, &nseg); 23*91f16700Schasinglulu 24*91f16700Schasinglulu if (ret != SMC_PCI_CALL_SUCCESS) { 25*91f16700Schasinglulu return SMC_PCI_CALL_INVAL_PARAM; 26*91f16700Schasinglulu } 27*91f16700Schasinglulu switch (sz) { 28*91f16700Schasinglulu case SMC_PCI_SZ_8BIT: 29*91f16700Schasinglulu case SMC_PCI_SZ_16BIT: 30*91f16700Schasinglulu case SMC_PCI_SZ_32BIT: 31*91f16700Schasinglulu break; 32*91f16700Schasinglulu default: 33*91f16700Schasinglulu return SMC_PCI_CALL_INVAL_PARAM; 34*91f16700Schasinglulu } 35*91f16700Schasinglulu if ((off + sz) > (PCI_OFFSET_MASK + 1U)) { 36*91f16700Schasinglulu return SMC_PCI_CALL_INVAL_PARAM; 37*91f16700Schasinglulu } 38*91f16700Schasinglulu return SMC_PCI_CALL_SUCCESS; 39*91f16700Schasinglulu } 40*91f16700Schasinglulu 41*91f16700Schasinglulu uint64_t pci_smc_handler(uint32_t smc_fid, 42*91f16700Schasinglulu u_register_t x1, 43*91f16700Schasinglulu u_register_t x2, 44*91f16700Schasinglulu u_register_t x3, 45*91f16700Schasinglulu u_register_t x4, 46*91f16700Schasinglulu void *cookie, 47*91f16700Schasinglulu void *handle, 48*91f16700Schasinglulu u_register_t flags) 49*91f16700Schasinglulu { 50*91f16700Schasinglulu switch (smc_fid) { 51*91f16700Schasinglulu case SMC_PCI_VERSION: { 52*91f16700Schasinglulu pcie_version ver; 53*91f16700Schasinglulu 54*91f16700Schasinglulu ver.major = 1U; 55*91f16700Schasinglulu ver.minor = 0U; 56*91f16700Schasinglulu SMC_RET4(handle, ver.val, 0U, 0U, 0U); 57*91f16700Schasinglulu } 58*91f16700Schasinglulu case SMC_PCI_FEATURES: 59*91f16700Schasinglulu switch (x1) { 60*91f16700Schasinglulu case SMC_PCI_VERSION: 61*91f16700Schasinglulu case SMC_PCI_FEATURES: 62*91f16700Schasinglulu case SMC_PCI_READ: 63*91f16700Schasinglulu case SMC_PCI_WRITE: 64*91f16700Schasinglulu case SMC_PCI_SEG_INFO: 65*91f16700Schasinglulu SMC_RET1(handle, SMC_PCI_CALL_SUCCESS); 66*91f16700Schasinglulu default: 67*91f16700Schasinglulu SMC_RET1(handle, SMC_PCI_CALL_NOT_SUPPORTED); 68*91f16700Schasinglulu } 69*91f16700Schasinglulu break; 70*91f16700Schasinglulu case SMC_PCI_READ: { 71*91f16700Schasinglulu uint32_t ret; 72*91f16700Schasinglulu 73*91f16700Schasinglulu if (validate_rw_addr_sz(x1, x2, x3) != SMC_PCI_CALL_SUCCESS) { 74*91f16700Schasinglulu SMC_RET2(handle, SMC_PCI_CALL_INVAL_PARAM, 0U); 75*91f16700Schasinglulu } 76*91f16700Schasinglulu if (x4 != 0U) { 77*91f16700Schasinglulu SMC_RET2(handle, SMC_PCI_CALL_INVAL_PARAM, 0U); 78*91f16700Schasinglulu } 79*91f16700Schasinglulu if (pci_read_config(x1, x2, x3, &ret) != 0U) { 80*91f16700Schasinglulu SMC_RET2(handle, SMC_PCI_CALL_INVAL_PARAM, 0U); 81*91f16700Schasinglulu } else { 82*91f16700Schasinglulu SMC_RET2(handle, SMC_PCI_CALL_SUCCESS, ret); 83*91f16700Schasinglulu } 84*91f16700Schasinglulu break; 85*91f16700Schasinglulu } 86*91f16700Schasinglulu case SMC_PCI_WRITE: { 87*91f16700Schasinglulu uint32_t ret; 88*91f16700Schasinglulu 89*91f16700Schasinglulu if (validate_rw_addr_sz(x1, x2, x3) != SMC_PCI_CALL_SUCCESS) { 90*91f16700Schasinglulu SMC_RET1(handle, SMC_PCI_CALL_INVAL_PARAM); 91*91f16700Schasinglulu } 92*91f16700Schasinglulu ret = pci_write_config(x1, x2, x3, x4); 93*91f16700Schasinglulu SMC_RET1(handle, ret); 94*91f16700Schasinglulu break; 95*91f16700Schasinglulu } 96*91f16700Schasinglulu case SMC_PCI_SEG_INFO: { 97*91f16700Schasinglulu uint32_t nseg; 98*91f16700Schasinglulu uint32_t ret; 99*91f16700Schasinglulu uint32_t start_end_bus; 100*91f16700Schasinglulu 101*91f16700Schasinglulu if ((x2 != 0U) || (x3 != 0U) || (x4 != 0U)) { 102*91f16700Schasinglulu SMC_RET3(handle, SMC_PCI_CALL_INVAL_PARAM, 0U, 0U); 103*91f16700Schasinglulu } 104*91f16700Schasinglulu ret = pci_get_bus_for_seg(x1, &start_end_bus, &nseg); 105*91f16700Schasinglulu SMC_RET3(handle, ret, start_end_bus, nseg); 106*91f16700Schasinglulu break; 107*91f16700Schasinglulu } 108*91f16700Schasinglulu default: 109*91f16700Schasinglulu /* should be unreachable */ 110*91f16700Schasinglulu WARN("Unimplemented PCI Service Call: 0x%x\n", smc_fid); 111*91f16700Schasinglulu SMC_RET1(handle, SMC_PCI_CALL_NOT_SUPPORTED); 112*91f16700Schasinglulu } 113*91f16700Schasinglulu } 114