diff options
Diffstat (limited to 'arch/arm/mach-bcm/bcm_kona_smc.c')
-rw-r--r-- | arch/arm/mach-bcm/bcm_kona_smc.c | 136 |
1 files changed, 98 insertions, 38 deletions
diff --git a/arch/arm/mach-bcm/bcm_kona_smc.c b/arch/arm/mach-bcm/bcm_kona_smc.c index 5e31e918f325..a55a7ecf146a 100644 --- a/arch/arm/mach-bcm/bcm_kona_smc.c +++ b/arch/arm/mach-bcm/bcm_kona_smc.c | |||
@@ -21,11 +21,8 @@ | |||
21 | 21 | ||
22 | #include "bcm_kona_smc.h" | 22 | #include "bcm_kona_smc.h" |
23 | 23 | ||
24 | struct secure_bridge_data { | 24 | static u32 bcm_smc_buffer_phys; /* physical address */ |
25 | void __iomem *bounce; /* virtual address */ | 25 | static void __iomem *bcm_smc_buffer; /* virtual address */ |
26 | u32 __iomem buffer_addr; /* physical address */ | ||
27 | int initialized; | ||
28 | } bridge_data; | ||
29 | 26 | ||
30 | struct bcm_kona_smc_data { | 27 | struct bcm_kona_smc_data { |
31 | unsigned service_id; | 28 | unsigned service_id; |
@@ -33,6 +30,7 @@ struct bcm_kona_smc_data { | |||
33 | unsigned arg1; | 30 | unsigned arg1; |
34 | unsigned arg2; | 31 | unsigned arg2; |
35 | unsigned arg3; | 32 | unsigned arg3; |
33 | unsigned result; | ||
36 | }; | 34 | }; |
37 | 35 | ||
38 | static const struct of_device_id bcm_kona_smc_ids[] __initconst = { | 36 | static const struct of_device_id bcm_kona_smc_ids[] __initconst = { |
@@ -41,59 +39,125 @@ static const struct of_device_id bcm_kona_smc_ids[] __initconst = { | |||
41 | {}, | 39 | {}, |
42 | }; | 40 | }; |
43 | 41 | ||
44 | /* Map in the bounce area */ | 42 | /* Map in the args buffer area */ |
45 | int __init bcm_kona_smc_init(void) | 43 | int __init bcm_kona_smc_init(void) |
46 | { | 44 | { |
47 | struct device_node *node; | 45 | struct device_node *node; |
46 | const __be32 *prop_val; | ||
47 | u64 prop_size = 0; | ||
48 | unsigned long buffer_size; | ||
49 | u32 buffer_phys; | ||
48 | 50 | ||
49 | /* Read buffer addr and size from the device tree node */ | 51 | /* Read buffer addr and size from the device tree node */ |
50 | node = of_find_matching_node(NULL, bcm_kona_smc_ids); | 52 | node = of_find_matching_node(NULL, bcm_kona_smc_ids); |
51 | if (!node) | 53 | if (!node) |
52 | return -ENODEV; | 54 | return -ENODEV; |
53 | 55 | ||
54 | /* Don't care about size or flags of the DT node */ | 56 | prop_val = of_get_address(node, 0, &prop_size, NULL); |
55 | bridge_data.buffer_addr = | 57 | if (!prop_val) |
56 | be32_to_cpu(*of_get_address(node, 0, NULL, NULL)); | 58 | return -EINVAL; |
57 | BUG_ON(!bridge_data.buffer_addr); | ||
58 | 59 | ||
59 | bridge_data.bounce = of_iomap(node, 0); | 60 | /* We assume space for four 32-bit arguments */ |
60 | BUG_ON(!bridge_data.bounce); | 61 | if (prop_size < 4 * sizeof(u32) || prop_size > (u64)ULONG_MAX) |
62 | return -EINVAL; | ||
63 | buffer_size = (unsigned long)prop_size; | ||
61 | 64 | ||
62 | bridge_data.initialized = 1; | 65 | buffer_phys = be32_to_cpup(prop_val); |
66 | if (!buffer_phys) | ||
67 | return -EINVAL; | ||
68 | |||
69 | bcm_smc_buffer = ioremap(buffer_phys, buffer_size); | ||
70 | if (!bcm_smc_buffer) | ||
71 | return -ENOMEM; | ||
72 | bcm_smc_buffer_phys = buffer_phys; | ||
63 | 73 | ||
64 | pr_info("Kona Secure API initialized\n"); | 74 | pr_info("Kona Secure API initialized\n"); |
65 | 75 | ||
66 | return 0; | 76 | return 0; |
67 | } | 77 | } |
68 | 78 | ||
79 | /* | ||
80 | * int bcm_kona_do_smc(u32 service_id, u32 buffer_addr) | ||
81 | * | ||
82 | * Only core 0 can run the secure monitor code. If an "smc" request | ||
83 | * is initiated on a different core it must be redirected to core 0 | ||
84 | * for execution. We rely on the caller to handle this. | ||
85 | * | ||
86 | * Each "smc" request supplies a service id and the address of a | ||
87 | * buffer containing parameters related to the service to be | ||
88 | * performed. A flags value defines the behavior of the level 2 | ||
89 | * cache and interrupt handling while the secure monitor executes. | ||
90 | * | ||
91 | * Parameters to the "smc" request are passed in r4-r6 as follows: | ||
92 | * r4 service id | ||
93 | * r5 flags (SEC_ROM_*) | ||
94 | * r6 physical address of buffer with other parameters | ||
95 | * | ||
96 | * Execution of an "smc" request produces two distinct results. | ||
97 | * | ||
98 | * First, the secure monitor call itself (regardless of the specific | ||
99 | * service request) can succeed, or can produce an error. When an | ||
100 | * "smc" request completes this value is found in r12; it should | ||
101 | * always be SEC_EXIT_NORMAL. | ||
102 | * | ||
103 | * In addition, the particular service performed produces a result. | ||
104 | * The values that should be expected depend on the service. We | ||
105 | * therefore return this value to the caller, so it can handle the | ||
106 | * request result appropriately. This result value is found in r0 | ||
107 | * when the "smc" request completes. | ||
108 | */ | ||
109 | static int bcm_kona_do_smc(u32 service_id, u32 buffer_phys) | ||
110 | { | ||
111 | register u32 ip asm("ip"); /* Also called r12 */ | ||
112 | register u32 r0 asm("r0"); | ||
113 | register u32 r4 asm("r4"); | ||
114 | register u32 r5 asm("r5"); | ||
115 | register u32 r6 asm("r6"); | ||
116 | |||
117 | r4 = service_id; | ||
118 | r5 = 0x3; /* Keep IRQ and FIQ off in SM */ | ||
119 | r6 = buffer_phys; | ||
120 | |||
121 | asm volatile ( | ||
122 | /* Make sure we got the registers we want */ | ||
123 | __asmeq("%0", "ip") | ||
124 | __asmeq("%1", "r0") | ||
125 | __asmeq("%2", "r4") | ||
126 | __asmeq("%3", "r5") | ||
127 | __asmeq("%4", "r6") | ||
128 | #ifdef REQUIRES_SEC | ||
129 | ".arch_extension sec\n" | ||
130 | #endif | ||
131 | " smc #0\n" | ||
132 | : "=r" (ip), "=r" (r0) | ||
133 | : "r" (r4), "r" (r5), "r" (r6) | ||
134 | : "r1", "r2", "r3", "r7", "lr"); | ||
135 | |||
136 | BUG_ON(ip != SEC_EXIT_NORMAL); | ||
137 | |||
138 | return r0; | ||
139 | } | ||
140 | |||
69 | /* __bcm_kona_smc() should only run on CPU 0, with pre-emption disabled */ | 141 | /* __bcm_kona_smc() should only run on CPU 0, with pre-emption disabled */ |
70 | static void __bcm_kona_smc(void *info) | 142 | static void __bcm_kona_smc(void *info) |
71 | { | 143 | { |
72 | struct bcm_kona_smc_data *data = info; | 144 | struct bcm_kona_smc_data *data = info; |
73 | u32 *args = bridge_data.bounce; | 145 | u32 *args = bcm_smc_buffer; |
74 | int rc = 0; | ||
75 | 146 | ||
76 | /* Must run on CPU 0 */ | ||
77 | BUG_ON(smp_processor_id() != 0); | 147 | BUG_ON(smp_processor_id() != 0); |
148 | BUG_ON(!args); | ||
78 | 149 | ||
79 | /* Check map in the bounce area */ | 150 | /* Copy the four 32 bit argument values into the bounce area */ |
80 | BUG_ON(!bridge_data.initialized); | 151 | writel_relaxed(data->arg0, args++); |
81 | 152 | writel_relaxed(data->arg1, args++); | |
82 | /* Copy one 32 bit word into the bounce area */ | 153 | writel_relaxed(data->arg2, args++); |
83 | args[0] = data->arg0; | 154 | writel(data->arg3, args); |
84 | args[1] = data->arg1; | ||
85 | args[2] = data->arg2; | ||
86 | args[3] = data->arg3; | ||
87 | 155 | ||
88 | /* Flush caches for input data passed to Secure Monitor */ | 156 | /* Flush caches for input data passed to Secure Monitor */ |
89 | if (data->service_id != SSAPI_BRCM_START_VC_CORE) | 157 | flush_cache_all(); |
90 | flush_cache_all(); | ||
91 | |||
92 | /* Trap into Secure Monitor */ | ||
93 | rc = bcm_kona_smc_asm(data->service_id, bridge_data.buffer_addr); | ||
94 | 158 | ||
95 | if (rc != SEC_ROM_RET_OK) | 159 | /* Trap into Secure Monitor and record the request result */ |
96 | pr_err("Secure Monitor call failed (0x%x)!\n", rc); | 160 | data->result = bcm_kona_do_smc(data->service_id, bcm_smc_buffer_phys); |
97 | } | 161 | } |
98 | 162 | ||
99 | unsigned bcm_kona_smc(unsigned service_id, unsigned arg0, unsigned arg1, | 163 | unsigned bcm_kona_smc(unsigned service_id, unsigned arg0, unsigned arg1, |
@@ -106,17 +170,13 @@ unsigned bcm_kona_smc(unsigned service_id, unsigned arg0, unsigned arg1, | |||
106 | data.arg1 = arg1; | 170 | data.arg1 = arg1; |
107 | data.arg2 = arg2; | 171 | data.arg2 = arg2; |
108 | data.arg3 = arg3; | 172 | data.arg3 = arg3; |
173 | data.result = 0; | ||
109 | 174 | ||
110 | /* | 175 | /* |
111 | * Due to a limitation of the secure monitor, we must use the SMP | 176 | * Due to a limitation of the secure monitor, we must use the SMP |
112 | * infrastructure to forward all secure monitor calls to Core 0. | 177 | * infrastructure to forward all secure monitor calls to Core 0. |
113 | */ | 178 | */ |
114 | if (get_cpu() != 0) | 179 | smp_call_function_single(0, __bcm_kona_smc, &data, 1); |
115 | smp_call_function_single(0, __bcm_kona_smc, (void *)&data, 1); | ||
116 | else | ||
117 | __bcm_kona_smc(&data); | ||
118 | 180 | ||
119 | put_cpu(); | 181 | return data.result; |
120 | |||
121 | return 0; | ||
122 | } | 182 | } |