qcomsmem.c revision 1.1 1 1.1 jmcneill /* $NetBSD: qcomsmem.c,v 1.1 2024/12/30 12:31:10 jmcneill Exp $ */
2 1.1 jmcneill /* $OpenBSD: qcsmem.c,v 1.1 2023/05/19 21:13:49 patrick Exp $ */
3 1.1 jmcneill /*
4 1.1 jmcneill * Copyright (c) 2023 Patrick Wildt <patrick (at) blueri.se>
5 1.1 jmcneill *
6 1.1 jmcneill * Permission to use, copy, modify, and distribute this software for any
7 1.1 jmcneill * purpose with or without fee is hereby granted, provided that the above
8 1.1 jmcneill * copyright notice and this permission notice appear in all copies.
9 1.1 jmcneill *
10 1.1 jmcneill * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 1.1 jmcneill * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 1.1 jmcneill * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 1.1 jmcneill * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 1.1 jmcneill * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 1.1 jmcneill * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 1.1 jmcneill * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 1.1 jmcneill */
18 1.1 jmcneill
19 1.1 jmcneill #include <sys/param.h>
20 1.1 jmcneill #include <sys/systm.h>
21 1.1 jmcneill #include <sys/device.h>
22 1.1 jmcneill #include <sys/kmem.h>
23 1.1 jmcneill
24 1.1 jmcneill #include <dev/acpi/acpivar.h>
25 1.1 jmcneill #include <dev/acpi/qcomsmem.h>
26 1.1 jmcneill
27 1.1 jmcneill #define QCSMEM_ITEM_FIXED 8
28 1.1 jmcneill #define QCSMEM_ITEM_COUNT 512
29 1.1 jmcneill #define QCSMEM_HOST_COUNT 15
30 1.1 jmcneill
31 1.1 jmcneill struct qcsmem_proc_comm {
32 1.1 jmcneill uint32_t command;
33 1.1 jmcneill uint32_t status;
34 1.1 jmcneill uint32_t params[2];
35 1.1 jmcneill };
36 1.1 jmcneill
37 1.1 jmcneill struct qcsmem_global_entry {
38 1.1 jmcneill uint32_t allocated;
39 1.1 jmcneill uint32_t offset;
40 1.1 jmcneill uint32_t size;
41 1.1 jmcneill uint32_t aux_base;
42 1.1 jmcneill #define QCSMEM_GLOBAL_ENTRY_AUX_BASE_MASK 0xfffffffc
43 1.1 jmcneill };
44 1.1 jmcneill
45 1.1 jmcneill struct qcsmem_header {
46 1.1 jmcneill struct qcsmem_proc_comm proc_comm[4];
47 1.1 jmcneill uint32_t version[32];
48 1.1 jmcneill #define QCSMEM_HEADER_VERSION_MASTER_SBL_IDX 7
49 1.1 jmcneill #define QCSMEM_HEADER_VERSION_GLOBAL_HEAP 11
50 1.1 jmcneill #define QCSMEM_HEADER_VERSION_GLOBAL_PART 12
51 1.1 jmcneill uint32_t initialized;
52 1.1 jmcneill uint32_t free_offset;
53 1.1 jmcneill uint32_t available;
54 1.1 jmcneill uint32_t reserved;
55 1.1 jmcneill struct qcsmem_global_entry toc[QCSMEM_ITEM_COUNT];
56 1.1 jmcneill };
57 1.1 jmcneill
58 1.1 jmcneill struct qcsmem_ptable_entry {
59 1.1 jmcneill uint32_t offset;
60 1.1 jmcneill uint32_t size;
61 1.1 jmcneill uint32_t flags;
62 1.1 jmcneill uint16_t host[2];
63 1.1 jmcneill #define QCSMEM_LOCAL_HOST 0
64 1.1 jmcneill #define QCSMEM_GLOBAL_HOST 0xfffe
65 1.1 jmcneill uint32_t cacheline;
66 1.1 jmcneill uint32_t reserved[7];
67 1.1 jmcneill };
68 1.1 jmcneill
69 1.1 jmcneill struct qcsmem_ptable {
70 1.1 jmcneill uint32_t magic;
71 1.1 jmcneill #define QCSMEM_PTABLE_MAGIC 0x434f5424
72 1.1 jmcneill uint32_t version;
73 1.1 jmcneill #define QCSMEM_PTABLE_VERSION 1
74 1.1 jmcneill uint32_t num_entries;
75 1.1 jmcneill uint32_t reserved[5];
76 1.1 jmcneill struct qcsmem_ptable_entry entry[];
77 1.1 jmcneill };
78 1.1 jmcneill
79 1.1 jmcneill struct qcsmem_partition_header {
80 1.1 jmcneill uint32_t magic;
81 1.1 jmcneill #define QCSMEM_PART_HDR_MAGIC 0x54525024
82 1.1 jmcneill uint16_t host[2];
83 1.1 jmcneill uint32_t size;
84 1.1 jmcneill uint32_t offset_free_uncached;
85 1.1 jmcneill uint32_t offset_free_cached;
86 1.1 jmcneill uint32_t reserved[3];
87 1.1 jmcneill };
88 1.1 jmcneill
89 1.1 jmcneill struct qcsmem_partition {
90 1.1 jmcneill struct qcsmem_partition_header *phdr;
91 1.1 jmcneill size_t cacheline;
92 1.1 jmcneill size_t size;
93 1.1 jmcneill };
94 1.1 jmcneill
95 1.1 jmcneill struct qcsmem_private_entry {
96 1.1 jmcneill uint16_t canary;
97 1.1 jmcneill #define QCSMEM_PRIV_ENTRY_CANARY 0xa5a5
98 1.1 jmcneill uint16_t item;
99 1.1 jmcneill uint32_t size;
100 1.1 jmcneill uint16_t padding_data;
101 1.1 jmcneill uint16_t padding_hdr;
102 1.1 jmcneill uint32_t reserved;
103 1.1 jmcneill };
104 1.1 jmcneill
105 1.1 jmcneill struct qcsmem_info {
106 1.1 jmcneill uint32_t magic;
107 1.1 jmcneill #define QCSMEM_INFO_MAGIC 0x49494953
108 1.1 jmcneill uint32_t size;
109 1.1 jmcneill uint32_t base_addr;
110 1.1 jmcneill uint32_t reserved;
111 1.1 jmcneill uint32_t num_items;
112 1.1 jmcneill };
113 1.1 jmcneill
114 1.1 jmcneill struct qcsmem_softc {
115 1.1 jmcneill device_t sc_dev;
116 1.1 jmcneill bus_space_tag_t sc_iot;
117 1.1 jmcneill void *sc_smem;
118 1.1 jmcneill bus_space_handle_t sc_mtx_ioh;
119 1.1 jmcneill
120 1.1 jmcneill bus_addr_t sc_aux_base;
121 1.1 jmcneill bus_size_t sc_aux_size;
122 1.1 jmcneill
123 1.1 jmcneill int sc_item_count;
124 1.1 jmcneill struct qcsmem_partition sc_global_partition;
125 1.1 jmcneill struct qcsmem_partition sc_partitions[QCSMEM_HOST_COUNT];
126 1.1 jmcneill };
127 1.1 jmcneill
128 1.1 jmcneill #define QCMTX_OFF(idx) ((idx) * 0x1000)
129 1.1 jmcneill #define QCMTX_NUM_LOCKS 32
130 1.1 jmcneill #define QCMTX_APPS_PROC_ID 1
131 1.1 jmcneill
132 1.1 jmcneill #define MTXREAD4(sc, reg) \
133 1.1 jmcneill bus_space_read_4((sc)->sc_iot, (sc)->sc_mtx_ioh, (reg))
134 1.1 jmcneill #define MTXWRITE4(sc, reg, val) \
135 1.1 jmcneill bus_space_write_4((sc)->sc_iot, (sc)->sc_mtx_ioh, (reg), (val))
136 1.1 jmcneill
137 1.1 jmcneill struct qcsmem_softc *qcsmem_sc;
138 1.1 jmcneill
139 1.1 jmcneill #define QCSMEM_X1E_BASE 0xffe00000
140 1.1 jmcneill #define QCSMEM_X1E_SIZE 0x200000
141 1.1 jmcneill
142 1.1 jmcneill #define QCMTX_X1E_BASE 0x01f40000
143 1.1 jmcneill #define QCMTX_X1E_SIZE 0x20000
144 1.1 jmcneill
145 1.1 jmcneill #define QCSMEM_X1E_LOCK_IDX 3
146 1.1 jmcneill
147 1.1 jmcneill static const struct device_compatible_entry compat_data[] = {
148 1.1 jmcneill { .compat = "QCOM0C84" },
149 1.1 jmcneill DEVICE_COMPAT_EOL
150 1.1 jmcneill };
151 1.1 jmcneill
152 1.1 jmcneill static int qcsmem_match(device_t, cfdata_t, void *);
153 1.1 jmcneill static void qcsmem_attach(device_t, device_t, void *);
154 1.1 jmcneill static int qcmtx_lock(struct qcsmem_softc *, u_int, u_int);
155 1.1 jmcneill static void qcmtx_unlock(struct qcsmem_softc *, u_int);
156 1.1 jmcneill
157 1.1 jmcneill CFATTACH_DECL_NEW(qcomsmem, sizeof(struct qcsmem_softc),
158 1.1 jmcneill qcsmem_match, qcsmem_attach, NULL, NULL);
159 1.1 jmcneill
160 1.1 jmcneill static int
161 1.1 jmcneill qcsmem_match(device_t parent, cfdata_t match, void *aux)
162 1.1 jmcneill {
163 1.1 jmcneill struct acpi_attach_args *aa = aux;
164 1.1 jmcneill
165 1.1 jmcneill return acpi_compatible_match(aa, compat_data);
166 1.1 jmcneill }
167 1.1 jmcneill
168 1.1 jmcneill static void
169 1.1 jmcneill qcsmem_attach(device_t parent, device_t self, void *aux)
170 1.1 jmcneill {
171 1.1 jmcneill struct qcsmem_softc *sc = device_private(self);
172 1.1 jmcneill struct acpi_attach_args *aa = aux;
173 1.1 jmcneill struct qcsmem_header *header;
174 1.1 jmcneill struct qcsmem_ptable *ptable;
175 1.1 jmcneill struct qcsmem_ptable_entry *pte;
176 1.1 jmcneill struct qcsmem_info *info;
177 1.1 jmcneill struct qcsmem_partition *part;
178 1.1 jmcneill struct qcsmem_partition_header *phdr;
179 1.1 jmcneill uintptr_t smem_va;
180 1.1 jmcneill uint32_t hdr_version;
181 1.1 jmcneill int i;
182 1.1 jmcneill
183 1.1 jmcneill sc->sc_dev = self;
184 1.1 jmcneill sc->sc_iot = aa->aa_memt;
185 1.1 jmcneill sc->sc_smem = AcpiOsMapMemory(QCSMEM_X1E_BASE, QCSMEM_X1E_SIZE);
186 1.1 jmcneill KASSERT(sc->sc_smem != NULL);
187 1.1 jmcneill
188 1.1 jmcneill sc->sc_aux_base = QCSMEM_X1E_BASE;
189 1.1 jmcneill sc->sc_aux_size = QCSMEM_X1E_SIZE;
190 1.1 jmcneill
191 1.1 jmcneill if (bus_space_map(sc->sc_iot, QCMTX_X1E_BASE,
192 1.1 jmcneill QCMTX_X1E_SIZE, 0, &sc->sc_mtx_ioh)) {
193 1.1 jmcneill aprint_error(": can't map mutex registers\n");
194 1.1 jmcneill return;
195 1.1 jmcneill }
196 1.1 jmcneill
197 1.1 jmcneill smem_va = (uintptr_t)sc->sc_smem;
198 1.1 jmcneill
199 1.1 jmcneill ptable = (void *)(smem_va + sc->sc_aux_size - PAGE_SIZE);
200 1.1 jmcneill if (ptable->magic != QCSMEM_PTABLE_MAGIC ||
201 1.1 jmcneill ptable->version != QCSMEM_PTABLE_VERSION) {
202 1.1 jmcneill aprint_error(": unsupported ptable 0x%x/0x%x\n",
203 1.1 jmcneill ptable->magic, ptable->version);
204 1.1 jmcneill return;
205 1.1 jmcneill }
206 1.1 jmcneill
207 1.1 jmcneill header = (void *)smem_va;
208 1.1 jmcneill hdr_version = header->version[QCSMEM_HEADER_VERSION_MASTER_SBL_IDX] >> 16;
209 1.1 jmcneill if (hdr_version != QCSMEM_HEADER_VERSION_GLOBAL_PART) {
210 1.1 jmcneill aprint_error(": unsupported header 0x%x\n", hdr_version);
211 1.1 jmcneill return;
212 1.1 jmcneill }
213 1.1 jmcneill
214 1.1 jmcneill for (i = 0; i < ptable->num_entries; i++) {
215 1.1 jmcneill pte = &ptable->entry[i];
216 1.1 jmcneill if (!pte->offset || !pte->size)
217 1.1 jmcneill continue;
218 1.1 jmcneill if (pte->host[0] == QCSMEM_GLOBAL_HOST &&
219 1.1 jmcneill pte->host[1] == QCSMEM_GLOBAL_HOST)
220 1.1 jmcneill part = &sc->sc_global_partition;
221 1.1 jmcneill else if (pte->host[0] == QCSMEM_LOCAL_HOST &&
222 1.1 jmcneill pte->host[1] < QCSMEM_HOST_COUNT)
223 1.1 jmcneill part = &sc->sc_partitions[pte->host[1]];
224 1.1 jmcneill else if (pte->host[1] == QCSMEM_LOCAL_HOST &&
225 1.1 jmcneill pte->host[0] < QCSMEM_HOST_COUNT)
226 1.1 jmcneill part = &sc->sc_partitions[pte->host[0]];
227 1.1 jmcneill else
228 1.1 jmcneill continue;
229 1.1 jmcneill if (part->phdr != NULL)
230 1.1 jmcneill continue;
231 1.1 jmcneill phdr = (void *)(smem_va + pte->offset);
232 1.1 jmcneill if (phdr->magic != QCSMEM_PART_HDR_MAGIC) {
233 1.1 jmcneill aprint_error(": unsupported partition 0x%x\n",
234 1.1 jmcneill phdr->magic);
235 1.1 jmcneill return;
236 1.1 jmcneill }
237 1.1 jmcneill if (pte->host[0] != phdr->host[0] ||
238 1.1 jmcneill pte->host[1] != phdr->host[1]) {
239 1.1 jmcneill aprint_error(": bad hosts 0x%x/0x%x+0x%x/0x%x\n",
240 1.1 jmcneill pte->host[0], phdr->host[0],
241 1.1 jmcneill pte->host[1], phdr->host[1]);
242 1.1 jmcneill return;
243 1.1 jmcneill }
244 1.1 jmcneill if (pte->size != phdr->size) {
245 1.1 jmcneill aprint_error(": bad size 0x%x/0x%x\n",
246 1.1 jmcneill pte->size, phdr->size);
247 1.1 jmcneill return;
248 1.1 jmcneill }
249 1.1 jmcneill if (phdr->offset_free_uncached > phdr->size) {
250 1.1 jmcneill aprint_error(": bad size 0x%x > 0x%x\n",
251 1.1 jmcneill phdr->offset_free_uncached, phdr->size);
252 1.1 jmcneill return;
253 1.1 jmcneill }
254 1.1 jmcneill part->phdr = phdr;
255 1.1 jmcneill part->size = pte->size;
256 1.1 jmcneill part->cacheline = pte->cacheline;
257 1.1 jmcneill }
258 1.1 jmcneill if (sc->sc_global_partition.phdr == NULL) {
259 1.1 jmcneill aprint_error(": could not find global partition\n");
260 1.1 jmcneill return;
261 1.1 jmcneill }
262 1.1 jmcneill
263 1.1 jmcneill sc->sc_item_count = QCSMEM_ITEM_COUNT;
264 1.1 jmcneill info = (struct qcsmem_info *)&ptable->entry[ptable->num_entries];
265 1.1 jmcneill if (info->magic == QCSMEM_INFO_MAGIC)
266 1.1 jmcneill sc->sc_item_count = info->num_items;
267 1.1 jmcneill
268 1.1 jmcneill aprint_naive("\n");
269 1.1 jmcneill aprint_normal("\n");
270 1.1 jmcneill
271 1.1 jmcneill qcsmem_sc = sc;
272 1.1 jmcneill }
273 1.1 jmcneill
274 1.1 jmcneill static int
275 1.1 jmcneill qcsmem_alloc_private(struct qcsmem_softc *sc, struct qcsmem_partition *part,
276 1.1 jmcneill int item, int size)
277 1.1 jmcneill {
278 1.1 jmcneill struct qcsmem_private_entry *entry, *last;
279 1.1 jmcneill struct qcsmem_partition_header *phdr = part->phdr;
280 1.1 jmcneill uintptr_t phdr_va = (uintptr_t)phdr;
281 1.1 jmcneill
282 1.1 jmcneill entry = (void *)&phdr[1];
283 1.1 jmcneill last = (void *)(phdr_va + phdr->offset_free_uncached);
284 1.1 jmcneill
285 1.1 jmcneill if ((void *)last > (void *)(phdr_va + part->size))
286 1.1 jmcneill return EINVAL;
287 1.1 jmcneill
288 1.1 jmcneill while (entry < last) {
289 1.1 jmcneill if (entry->canary != QCSMEM_PRIV_ENTRY_CANARY) {
290 1.1 jmcneill device_printf(sc->sc_dev, "invalid canary\n");
291 1.1 jmcneill return EINVAL;
292 1.1 jmcneill }
293 1.1 jmcneill
294 1.1 jmcneill if (entry->item == item)
295 1.1 jmcneill return 0;
296 1.1 jmcneill
297 1.1 jmcneill entry = (void *)((uintptr_t)&entry[1] + entry->padding_hdr +
298 1.1 jmcneill entry->size);
299 1.1 jmcneill }
300 1.1 jmcneill
301 1.1 jmcneill if ((void *)entry > (void *)(phdr_va + part->size))
302 1.1 jmcneill return EINVAL;
303 1.1 jmcneill
304 1.1 jmcneill if ((uintptr_t)&entry[1] + roundup(size, 8) >
305 1.1 jmcneill phdr_va + phdr->offset_free_cached)
306 1.1 jmcneill return EINVAL;
307 1.1 jmcneill
308 1.1 jmcneill entry->canary = QCSMEM_PRIV_ENTRY_CANARY;
309 1.1 jmcneill entry->item = item;
310 1.1 jmcneill entry->size = roundup(size, 8);
311 1.1 jmcneill entry->padding_data = entry->size - size;
312 1.1 jmcneill entry->padding_hdr = 0;
313 1.1 jmcneill membar_producer();
314 1.1 jmcneill
315 1.1 jmcneill phdr->offset_free_uncached += sizeof(*entry) + entry->size;
316 1.1 jmcneill
317 1.1 jmcneill return 0;
318 1.1 jmcneill }
319 1.1 jmcneill
320 1.1 jmcneill static int
321 1.1 jmcneill qcsmem_alloc_global(struct qcsmem_softc *sc, int item, int size)
322 1.1 jmcneill {
323 1.1 jmcneill struct qcsmem_header *header;
324 1.1 jmcneill struct qcsmem_global_entry *entry;
325 1.1 jmcneill
326 1.1 jmcneill header = (void *)sc->sc_smem;
327 1.1 jmcneill entry = &header->toc[item];
328 1.1 jmcneill if (entry->allocated)
329 1.1 jmcneill return 0;
330 1.1 jmcneill
331 1.1 jmcneill size = roundup(size, 8);
332 1.1 jmcneill if (size > header->available)
333 1.1 jmcneill return EINVAL;
334 1.1 jmcneill
335 1.1 jmcneill entry->offset = header->free_offset;
336 1.1 jmcneill entry->size = size;
337 1.1 jmcneill membar_producer();
338 1.1 jmcneill entry->allocated = 1;
339 1.1 jmcneill
340 1.1 jmcneill header->free_offset += size;
341 1.1 jmcneill header->available -= size;
342 1.1 jmcneill
343 1.1 jmcneill return 0;
344 1.1 jmcneill }
345 1.1 jmcneill
346 1.1 jmcneill int
347 1.1 jmcneill qcsmem_alloc(int host, int item, int size)
348 1.1 jmcneill {
349 1.1 jmcneill struct qcsmem_softc *sc = qcsmem_sc;
350 1.1 jmcneill struct qcsmem_partition *part;
351 1.1 jmcneill int ret;
352 1.1 jmcneill
353 1.1 jmcneill if (sc == NULL)
354 1.1 jmcneill return ENXIO;
355 1.1 jmcneill
356 1.1 jmcneill if (item < QCSMEM_ITEM_FIXED)
357 1.1 jmcneill return EPERM;
358 1.1 jmcneill
359 1.1 jmcneill if (item >= sc->sc_item_count)
360 1.1 jmcneill return ENXIO;
361 1.1 jmcneill
362 1.1 jmcneill ret = qcmtx_lock(sc, QCSMEM_X1E_LOCK_IDX, 1000);
363 1.1 jmcneill if (ret)
364 1.1 jmcneill return ret;
365 1.1 jmcneill
366 1.1 jmcneill if (host < QCSMEM_HOST_COUNT &&
367 1.1 jmcneill sc->sc_partitions[host].phdr != NULL) {
368 1.1 jmcneill part = &sc->sc_partitions[host];
369 1.1 jmcneill ret = qcsmem_alloc_private(sc, part, item, size);
370 1.1 jmcneill } else if (sc->sc_global_partition.phdr != NULL) {
371 1.1 jmcneill part = &sc->sc_global_partition;
372 1.1 jmcneill ret = qcsmem_alloc_private(sc, part, item, size);
373 1.1 jmcneill } else {
374 1.1 jmcneill ret = qcsmem_alloc_global(sc, item, size);
375 1.1 jmcneill }
376 1.1 jmcneill
377 1.1 jmcneill qcmtx_unlock(sc, QCSMEM_X1E_LOCK_IDX);
378 1.1 jmcneill
379 1.1 jmcneill return ret;
380 1.1 jmcneill }
381 1.1 jmcneill
382 1.1 jmcneill static void *
383 1.1 jmcneill qcsmem_get_private(struct qcsmem_softc *sc, struct qcsmem_partition *part,
384 1.1 jmcneill int item, int *size)
385 1.1 jmcneill {
386 1.1 jmcneill struct qcsmem_private_entry *entry, *last;
387 1.1 jmcneill struct qcsmem_partition_header *phdr = part->phdr;
388 1.1 jmcneill uintptr_t phdr_va = (uintptr_t)phdr;
389 1.1 jmcneill
390 1.1 jmcneill entry = (void *)&phdr[1];
391 1.1 jmcneill last = (void *)(phdr_va + phdr->offset_free_uncached);
392 1.1 jmcneill
393 1.1 jmcneill while (entry < last) {
394 1.1 jmcneill if (entry->canary != QCSMEM_PRIV_ENTRY_CANARY) {
395 1.1 jmcneill device_printf(sc->sc_dev, "invalid canary\n");
396 1.1 jmcneill return NULL;
397 1.1 jmcneill }
398 1.1 jmcneill
399 1.1 jmcneill if (entry->item == item) {
400 1.1 jmcneill if (size != NULL) {
401 1.1 jmcneill if (entry->size > part->size ||
402 1.1 jmcneill entry->padding_data > entry->size)
403 1.1 jmcneill return NULL;
404 1.1 jmcneill *size = entry->size - entry->padding_data;
405 1.1 jmcneill }
406 1.1 jmcneill
407 1.1 jmcneill return (void *)((uintptr_t)&entry[1] + entry->padding_hdr);
408 1.1 jmcneill }
409 1.1 jmcneill
410 1.1 jmcneill entry = (void *)((uintptr_t)&entry[1] + entry->padding_hdr +
411 1.1 jmcneill entry->size);
412 1.1 jmcneill }
413 1.1 jmcneill
414 1.1 jmcneill if ((uintptr_t)entry > phdr_va + part->size)
415 1.1 jmcneill return NULL;
416 1.1 jmcneill
417 1.1 jmcneill entry = (void *)(phdr_va + phdr->size -
418 1.1 jmcneill roundup(sizeof(*entry), part->cacheline));
419 1.1 jmcneill last = (void *)(phdr_va + phdr->offset_free_cached);
420 1.1 jmcneill
421 1.1 jmcneill if ((uintptr_t)entry < phdr_va ||
422 1.1 jmcneill (uintptr_t)last > phdr_va + part->size)
423 1.1 jmcneill return NULL;
424 1.1 jmcneill
425 1.1 jmcneill while (entry > last) {
426 1.1 jmcneill if (entry->canary != QCSMEM_PRIV_ENTRY_CANARY) {
427 1.1 jmcneill device_printf(sc->sc_dev, "invalid canary\n");
428 1.1 jmcneill return NULL;
429 1.1 jmcneill }
430 1.1 jmcneill
431 1.1 jmcneill if (entry->item == item) {
432 1.1 jmcneill if (size != NULL) {
433 1.1 jmcneill if (entry->size > part->size ||
434 1.1 jmcneill entry->padding_data > entry->size)
435 1.1 jmcneill return NULL;
436 1.1 jmcneill *size = entry->size - entry->padding_data;
437 1.1 jmcneill }
438 1.1 jmcneill
439 1.1 jmcneill return (void *)((uintptr_t)entry - entry->size);
440 1.1 jmcneill }
441 1.1 jmcneill
442 1.1 jmcneill entry = (void *)((uintptr_t)entry - entry->size -
443 1.1 jmcneill roundup(sizeof(*entry), part->cacheline));
444 1.1 jmcneill }
445 1.1 jmcneill
446 1.1 jmcneill if ((uintptr_t)entry < phdr_va)
447 1.1 jmcneill return NULL;
448 1.1 jmcneill
449 1.1 jmcneill return NULL;
450 1.1 jmcneill }
451 1.1 jmcneill
452 1.1 jmcneill static void *
453 1.1 jmcneill qcsmem_get_global(struct qcsmem_softc *sc, int item, int *size)
454 1.1 jmcneill {
455 1.1 jmcneill struct qcsmem_header *header;
456 1.1 jmcneill struct qcsmem_global_entry *entry;
457 1.1 jmcneill uint32_t aux_base;
458 1.1 jmcneill
459 1.1 jmcneill header = (void *)sc->sc_smem;
460 1.1 jmcneill entry = &header->toc[item];
461 1.1 jmcneill if (!entry->allocated)
462 1.1 jmcneill return NULL;
463 1.1 jmcneill
464 1.1 jmcneill aux_base = entry->aux_base & QCSMEM_GLOBAL_ENTRY_AUX_BASE_MASK;
465 1.1 jmcneill if (aux_base != 0 && aux_base != sc->sc_aux_base)
466 1.1 jmcneill return NULL;
467 1.1 jmcneill
468 1.1 jmcneill if (entry->size + entry->offset > sc->sc_aux_size)
469 1.1 jmcneill return NULL;
470 1.1 jmcneill
471 1.1 jmcneill if (size != NULL)
472 1.1 jmcneill *size = entry->size;
473 1.1 jmcneill
474 1.1 jmcneill return (void *)((uintptr_t)sc->sc_smem +
475 1.1 jmcneill entry->offset);
476 1.1 jmcneill }
477 1.1 jmcneill
478 1.1 jmcneill void *
479 1.1 jmcneill qcsmem_get(int host, int item, int *size)
480 1.1 jmcneill {
481 1.1 jmcneill struct qcsmem_softc *sc = qcsmem_sc;
482 1.1 jmcneill struct qcsmem_partition *part;
483 1.1 jmcneill void *p = NULL;
484 1.1 jmcneill int ret;
485 1.1 jmcneill
486 1.1 jmcneill if (sc == NULL)
487 1.1 jmcneill return NULL;
488 1.1 jmcneill
489 1.1 jmcneill if (item >= sc->sc_item_count)
490 1.1 jmcneill return NULL;
491 1.1 jmcneill
492 1.1 jmcneill ret = qcmtx_lock(sc, QCSMEM_X1E_LOCK_IDX, 1000);
493 1.1 jmcneill if (ret)
494 1.1 jmcneill return NULL;
495 1.1 jmcneill
496 1.1 jmcneill if (host >= 0 &&
497 1.1 jmcneill host < QCSMEM_HOST_COUNT &&
498 1.1 jmcneill sc->sc_partitions[host].phdr != NULL) {
499 1.1 jmcneill part = &sc->sc_partitions[host];
500 1.1 jmcneill p = qcsmem_get_private(sc, part, item, size);
501 1.1 jmcneill } else if (sc->sc_global_partition.phdr != NULL) {
502 1.1 jmcneill part = &sc->sc_global_partition;
503 1.1 jmcneill p = qcsmem_get_private(sc, part, item, size);
504 1.1 jmcneill } else {
505 1.1 jmcneill p = qcsmem_get_global(sc, item, size);
506 1.1 jmcneill }
507 1.1 jmcneill
508 1.1 jmcneill qcmtx_unlock(sc, QCSMEM_X1E_LOCK_IDX);
509 1.1 jmcneill return p;
510 1.1 jmcneill }
511 1.1 jmcneill
512 1.1 jmcneill void
513 1.1 jmcneill qcsmem_memset(void *ptr, uint8_t val, size_t len)
514 1.1 jmcneill {
515 1.1 jmcneill if (len % 8 == 0 && val == 0) {
516 1.1 jmcneill volatile uint64_t *p = ptr;
517 1.1 jmcneill size_t n;
518 1.1 jmcneill
519 1.1 jmcneill for (n = 0; n < len; n += 8) {
520 1.1 jmcneill p[n] = val;
521 1.1 jmcneill }
522 1.1 jmcneill } else {
523 1.1 jmcneill volatile uint8_t *p = ptr;
524 1.1 jmcneill size_t n;
525 1.1 jmcneill
526 1.1 jmcneill for (n = 0; n < len; n++) {
527 1.1 jmcneill p[n] = val;
528 1.1 jmcneill }
529 1.1 jmcneill }
530 1.1 jmcneill }
531 1.1 jmcneill
532 1.1 jmcneill static int
533 1.1 jmcneill qcmtx_dolockunlock(struct qcsmem_softc *sc, u_int idx, int lock)
534 1.1 jmcneill {
535 1.1 jmcneill if (idx >= QCMTX_NUM_LOCKS)
536 1.1 jmcneill return ENXIO;
537 1.1 jmcneill
538 1.1 jmcneill if (lock) {
539 1.1 jmcneill MTXWRITE4(sc, QCMTX_OFF(idx), QCMTX_APPS_PROC_ID);
540 1.1 jmcneill if (MTXREAD4(sc, QCMTX_OFF(idx)) !=
541 1.1 jmcneill QCMTX_APPS_PROC_ID)
542 1.1 jmcneill return EAGAIN;
543 1.1 jmcneill KASSERT(MTXREAD4(sc, QCMTX_OFF(idx)) == QCMTX_APPS_PROC_ID);
544 1.1 jmcneill } else {
545 1.1 jmcneill KASSERT(MTXREAD4(sc, QCMTX_OFF(idx)) == QCMTX_APPS_PROC_ID);
546 1.1 jmcneill MTXWRITE4(sc, QCMTX_OFF(idx), 0);
547 1.1 jmcneill }
548 1.1 jmcneill
549 1.1 jmcneill return 0;
550 1.1 jmcneill }
551 1.1 jmcneill
552 1.1 jmcneill static int
553 1.1 jmcneill qcmtx_lock(struct qcsmem_softc *sc, u_int idx, u_int timeout_ms)
554 1.1 jmcneill {
555 1.1 jmcneill int rv = EINVAL;
556 1.1 jmcneill u_int n;
557 1.1 jmcneill
558 1.1 jmcneill for (n = 0; n < timeout_ms; n++) {
559 1.1 jmcneill rv = qcmtx_dolockunlock(sc, idx, 1);
560 1.1 jmcneill if (rv != EAGAIN) {
561 1.1 jmcneill break;
562 1.1 jmcneill }
563 1.1 jmcneill delay(1000);
564 1.1 jmcneill }
565 1.1 jmcneill
566 1.1 jmcneill return rv;
567 1.1 jmcneill }
568 1.1 jmcneill
569 1.1 jmcneill static void
570 1.1 jmcneill qcmtx_unlock(struct qcsmem_softc *sc, u_int idx)
571 1.1 jmcneill {
572 1.1 jmcneill qcmtx_dolockunlock(sc, idx, 0);
573 1.1 jmcneill }
574