Home | History | Annotate | Line # | Download | only in acpi
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