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