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