123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916 |
- // SPDX-License-Identifier: GPL-2.0-only
- /*
- * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
- */
- #include <linux/hwspinlock.h>
- #include <linux/string.h>
- #include "synx_debugfs.h"
- #include "synx_global.h"
- static struct synx_shared_mem synx_gmem;
- static struct hwspinlock *synx_hwlock;
- static u32 synx_gmem_lock_owner(u32 idx)
- {
- /*
- * subscribers field of global table index 0 is used to
- * maintain synx gmem lock owner data.
- * core updates the field after acquiring the lock and
- * before releasing the lock appropriately.
- */
- return synx_gmem.table[0].subscribers;
- }
- static void synx_gmem_lock_owner_set(u32 idx)
- {
- synx_gmem.table[0].subscribers = SYNX_CORE_APSS;
- }
- static void synx_gmem_lock_owner_clear(u32 idx)
- {
- if (synx_gmem.table[0].subscribers != SYNX_CORE_APSS)
- dprintk(SYNX_WARN, "reset lock owned by core %u\n",
- synx_gmem.table[0].subscribers);
- synx_gmem.table[0].subscribers = SYNX_CORE_MAX;
- }
- static int synx_gmem_lock(u32 idx, unsigned long *flags)
- {
- int rc;
- if (!synx_hwlock)
- return -SYNX_INVALID;
- rc = hwspin_lock_timeout_irqsave(
- synx_hwlock, SYNX_HWSPIN_TIMEOUT, flags);
- if (!rc)
- synx_gmem_lock_owner_set(idx);
- return rc;
- }
- static void synx_gmem_unlock(u32 idx, unsigned long *flags)
- {
- synx_gmem_lock_owner_clear(idx);
- hwspin_unlock_irqrestore(synx_hwlock, flags);
- }
- static void synx_global_print_data(
- struct synx_global_coredata *synx_g_obj,
- const char *func)
- {
- int i = 0;
- dprintk(SYNX_VERB, "%s: status %u, handle %u, refcount %u",
- func, synx_g_obj->status,
- synx_g_obj->handle, synx_g_obj->refcount);
- dprintk(SYNX_VERB, "%s: subscribers %u, waiters %u, pending %u",
- func, synx_g_obj->subscribers, synx_g_obj->waiters,
- synx_g_obj->num_child);
- for (i = 0; i < SYNX_GLOBAL_MAX_PARENTS; i++)
- if (synx_g_obj->parents[i])
- dprintk(SYNX_VERB, "%s: parents %u:%u",
- func, i, synx_g_obj->parents[i]);
- }
- bool synx_fetch_global_shared_memory_handle_details(u32 synx_handle,
- struct synx_global_coredata *synx_global_entry)
- {
- int rc = SYNX_SUCCESS;
- u32 idx;
- unsigned long flags;
- struct synx_global_coredata *entry;
- if (!synx_gmem.table) {
- dprintk(SYNX_VERB, "synx_gmem is NULL\n");
- return false;
- }
- idx = synx_handle & SYNX_HANDLE_INDEX_MASK;
- if (!synx_is_valid_idx(idx))
- return false;
- rc = synx_gmem_lock(idx, &flags);
- if (rc) {
- dprintk(SYNX_VERB, "Failed to lock entry %d\n", idx);
- return false;
- }
- entry = &synx_gmem.table[idx];
- memcpy(synx_global_entry, entry, sizeof(struct synx_global_coredata));
- synx_gmem_unlock(idx, &flags);
- return true;
- }
- int synx_global_dump_shared_memory(void)
- {
- int rc = SYNX_SUCCESS, idx;
- unsigned long flags;
- struct synx_global_coredata *synx_g_obj;
- if (!synx_gmem.table)
- return -SYNX_INVALID;
- /* Print bitmap memory*/
- for (idx = 0; idx < SHRD_MEM_DUMP_NUM_BMAP_WORDS; idx++) {
- rc = synx_gmem_lock(idx, &flags);
- if (rc)
- return rc;
- dprintk(SYNX_VERB, "%s: idx %d, bitmap value %d",
- __func__, idx, synx_gmem.bitmap[idx]);
- synx_gmem_unlock(idx, &flags);
- }
- /* Print table memory*/
- for (idx = 0;
- idx < SHRD_MEM_DUMP_NUM_BMAP_WORDS * sizeof(u32) * NUM_CHAR_BIT;
- idx++) {
- rc = synx_gmem_lock(idx, &flags);
- if (rc)
- return rc;
- dprintk(SYNX_VERB, "%s: idx %d\n", __func__, idx);
- synx_g_obj = &synx_gmem.table[idx];
- synx_global_print_data(synx_g_obj, __func__);
- synx_gmem_unlock(idx, &flags);
- }
- return rc;
- }
- static int synx_gmem_init(void)
- {
- if (!synx_gmem.table)
- return -SYNX_NOMEM;
- synx_hwlock = hwspin_lock_request_specific(SYNX_HWSPIN_ID);
- if (!synx_hwlock) {
- dprintk(SYNX_ERR, "hwspinlock request failed\n");
- return -SYNX_NOMEM;
- }
- /* zero idx not allocated for clients */
- ipclite_global_test_and_set_bit(0,
- (ipclite_atomic_uint32_t *)synx_gmem.bitmap);
- memset(&synx_gmem.table[0], 0, sizeof(struct synx_global_coredata));
- return SYNX_SUCCESS;
- }
- u32 synx_global_map_core_id(enum synx_core_id id)
- {
- u32 host_id;
- switch (id) {
- case SYNX_CORE_APSS:
- host_id = IPCMEM_APPS; break;
- case SYNX_CORE_NSP:
- host_id = IPCMEM_CDSP; break;
- case SYNX_CORE_IRIS:
- host_id = IPCMEM_VPU; break;
- case SYNX_CORE_EVA:
- host_id = IPCMEM_CVP; break;
- case SYNX_CORE_ICP:
- host_id = IPCMEM_CAM; break;
- default:
- host_id = IPCMEM_NUM_HOSTS;
- dprintk(SYNX_ERR, "invalid core id\n");
- }
- return host_id;
- }
- int synx_global_alloc_index(u32 *idx)
- {
- int rc = SYNX_SUCCESS;
- u32 prev, index;
- const u32 size = SYNX_GLOBAL_MAX_OBJS;
- if (!synx_gmem.table)
- return -SYNX_NOMEM;
- if (IS_ERR_OR_NULL(idx))
- return -SYNX_INVALID;
- do {
- index = find_first_zero_bit((unsigned long *)synx_gmem.bitmap, size);
- if (index >= size) {
- rc = -SYNX_NOMEM;
- break;
- }
- prev = ipclite_global_test_and_set_bit(index % 32,
- (ipclite_atomic_uint32_t *)(synx_gmem.bitmap + index/32));
- if ((prev & (1UL << (index % 32))) == 0) {
- *idx = index;
- dprintk(SYNX_MEM, "allocated global idx %u\n", *idx);
- break;
- }
- } while (true);
- return rc;
- }
- int synx_global_init_coredata(u32 h_synx)
- {
- int rc;
- unsigned long flags;
- struct synx_global_coredata *synx_g_obj;
- u32 idx = h_synx & SYNX_HANDLE_INDEX_MASK;
- if (!synx_gmem.table)
- return -SYNX_NOMEM;
- if (!synx_is_valid_idx(idx))
- return -SYNX_INVALID;
- rc = synx_gmem_lock(idx, &flags);
- if (rc)
- return rc;
- synx_g_obj = &synx_gmem.table[idx];
- if (synx_g_obj->status != 0 || synx_g_obj->refcount != 0 ||
- synx_g_obj->subscribers != 0 || synx_g_obj->handle != 0 ||
- synx_g_obj->parents[0] != 0) {
- dprintk(SYNX_ERR,
- "entry not cleared for idx %u,\n"
- "synx_g_obj->status %d,\n"
- "synx_g_obj->refcount %d,\n"
- "synx_g_obj->subscribers %d,\n"
- "synx_g_obj->handle %u,\n"
- "synx_g_obj->parents[0] %d\n",
- idx, synx_g_obj->status,
- synx_g_obj->refcount,
- synx_g_obj->subscribers,
- synx_g_obj->handle,
- synx_g_obj->parents[0]);
- synx_gmem_unlock(idx, &flags);
- return -SYNX_INVALID;
- }
- memset(synx_g_obj, 0, sizeof(*synx_g_obj));
- /* set status to active */
- synx_g_obj->status = SYNX_STATE_ACTIVE;
- synx_g_obj->refcount = 1;
- synx_g_obj->subscribers = (1UL << SYNX_CORE_APSS);
- synx_g_obj->handle = h_synx;
- synx_gmem_unlock(idx, &flags);
- return SYNX_SUCCESS;
- }
- static int synx_global_get_waiting_cores_locked(
- struct synx_global_coredata *synx_g_obj,
- bool *cores)
- {
- int i;
- synx_global_print_data(synx_g_obj, __func__);
- for (i = 0; i < SYNX_CORE_MAX; i++) {
- if (synx_g_obj->waiters & (1UL << i)) {
- cores[i] = true;
- dprintk(SYNX_VERB,
- "waiting for handle %u/n",
- synx_g_obj->handle);
- }
- }
- /* clear waiter list so signals are not repeated */
- synx_g_obj->waiters = 0;
- return SYNX_SUCCESS;
- }
- int synx_global_get_waiting_cores(u32 idx, bool *cores)
- {
- int rc;
- unsigned long flags;
- struct synx_global_coredata *synx_g_obj;
- if (!synx_gmem.table)
- return -SYNX_NOMEM;
- if (IS_ERR_OR_NULL(cores) || !synx_is_valid_idx(idx))
- return -SYNX_INVALID;
- rc = synx_gmem_lock(idx, &flags);
- if (rc)
- return rc;
- synx_g_obj = &synx_gmem.table[idx];
- synx_global_get_waiting_cores_locked(synx_g_obj, cores);
- synx_gmem_unlock(idx, &flags);
- return SYNX_SUCCESS;
- }
- int synx_global_set_waiting_core(u32 idx, enum synx_core_id id)
- {
- int rc;
- unsigned long flags;
- struct synx_global_coredata *synx_g_obj;
- if (!synx_gmem.table)
- return -SYNX_NOMEM;
- if (id >= SYNX_CORE_MAX || !synx_is_valid_idx(idx))
- return -SYNX_INVALID;
- rc = synx_gmem_lock(idx, &flags);
- if (rc)
- return rc;
- synx_g_obj = &synx_gmem.table[idx];
- synx_g_obj->waiters |= (1UL << id);
- synx_gmem_unlock(idx, &flags);
- return SYNX_SUCCESS;
- }
- int synx_global_get_subscribed_cores(u32 idx, bool *cores)
- {
- int i;
- int rc;
- unsigned long flags;
- struct synx_global_coredata *synx_g_obj;
- if (!synx_gmem.table)
- return -SYNX_NOMEM;
- if (IS_ERR_OR_NULL(cores) || !synx_is_valid_idx(idx))
- return -SYNX_INVALID;
- rc = synx_gmem_lock(idx, &flags);
- if (rc)
- return rc;
- synx_g_obj = &synx_gmem.table[idx];
- for (i = 0; i < SYNX_CORE_MAX; i++)
- if (synx_g_obj->subscribers & (1UL << i))
- cores[i] = true;
- synx_gmem_unlock(idx, &flags);
- return SYNX_SUCCESS;
- }
- int synx_global_fetch_handle_details(u32 idx, u32 *h_synx)
- {
- int rc;
- unsigned long flags;
- struct synx_global_coredata *synx_g_obj;
- if (!synx_gmem.table)
- return -SYNX_NOMEM;
- if (IS_ERR_OR_NULL(h_synx) || !synx_is_valid_idx(idx))
- return -SYNX_INVALID;
- rc = synx_gmem_lock(idx, &flags);
- if (rc)
- return rc;
- synx_g_obj = &synx_gmem.table[idx];
- *h_synx = synx_g_obj->handle;
- synx_gmem_unlock(idx, &flags);
- return SYNX_SUCCESS;
- }
- int synx_global_set_subscribed_core(u32 idx, enum synx_core_id id)
- {
- int rc;
- unsigned long flags;
- struct synx_global_coredata *synx_g_obj;
- if (!synx_gmem.table)
- return -SYNX_NOMEM;
- if (id >= SYNX_CORE_MAX || !synx_is_valid_idx(idx))
- return -SYNX_INVALID;
- rc = synx_gmem_lock(idx, &flags);
- if (rc)
- return rc;
- synx_g_obj = &synx_gmem.table[idx];
- synx_g_obj->subscribers |= (1UL << id);
- synx_gmem_unlock(idx, &flags);
- return SYNX_SUCCESS;
- }
- int synx_global_clear_subscribed_core(u32 idx, enum synx_core_id id)
- {
- int rc;
- unsigned long flags;
- struct synx_global_coredata *synx_g_obj;
- if (!synx_gmem.table)
- return -SYNX_NOMEM;
- if (id >= SYNX_CORE_MAX || !synx_is_valid_idx(idx))
- return -SYNX_INVALID;
- rc = synx_gmem_lock(idx, &flags);
- if (rc)
- return rc;
- synx_g_obj = &synx_gmem.table[idx];
- synx_g_obj->subscribers &= ~(1UL << id);
- synx_gmem_unlock(idx, &flags);
- return SYNX_SUCCESS;
- }
- u32 synx_global_get_parents_num(u32 idx)
- {
- int rc;
- unsigned long flags;
- struct synx_global_coredata *synx_g_obj;
- u32 i, count = 0;
- if (!synx_gmem.table)
- return 0;
- if (!synx_is_valid_idx(idx))
- return 0;
- rc = synx_gmem_lock(idx, &flags);
- if (rc)
- return rc;
- synx_g_obj = &synx_gmem.table[idx];
- for (i = 0; i < SYNX_GLOBAL_MAX_PARENTS; i++) {
- if (synx_g_obj->parents[i] != 0)
- count++;
- }
- synx_gmem_unlock(idx, &flags);
- return count;
- }
- static int synx_global_get_parents_locked(
- struct synx_global_coredata *synx_g_obj, u32 *parents)
- {
- u32 i;
- if (!synx_g_obj || !parents)
- return -SYNX_NOMEM;
- for (i = 0; i < SYNX_GLOBAL_MAX_PARENTS; i++)
- parents[i] = synx_g_obj->parents[i];
- return SYNX_SUCCESS;
- }
- int synx_global_get_parents(u32 idx, u32 *parents)
- {
- int rc;
- unsigned long flags;
- struct synx_global_coredata *synx_g_obj;
- if (!synx_gmem.table || !parents)
- return -SYNX_NOMEM;
- if (!synx_is_valid_idx(idx))
- return -SYNX_INVALID;
- rc = synx_gmem_lock(idx, &flags);
- if (rc)
- return rc;
- synx_g_obj = &synx_gmem.table[idx];
- rc = synx_global_get_parents_locked(synx_g_obj, parents);
- synx_gmem_unlock(idx, &flags);
- return rc;
- }
- u32 synx_global_get_status(u32 idx)
- {
- int rc;
- unsigned long flags;
- u32 status = SYNX_STATE_ACTIVE;
- struct synx_global_coredata *synx_g_obj;
- if (!synx_gmem.table)
- return 0;
- if (!synx_is_valid_idx(idx))
- return 0;
- rc = synx_gmem_lock(idx, &flags);
- if (rc)
- return rc;
- synx_g_obj = &synx_gmem.table[idx];
- if (synx_g_obj->status != SYNX_STATE_ACTIVE && synx_g_obj->num_child == 0)
- status = synx_g_obj->status;
- synx_gmem_unlock(idx, &flags);
- return status;
- }
- u32 synx_global_test_status_set_wait(u32 idx,
- enum synx_core_id id)
- {
- int rc;
- unsigned long flags;
- u32 status;
- struct synx_global_coredata *synx_g_obj;
- if (!synx_gmem.table)
- return 0;
- if (id >= SYNX_CORE_MAX || !synx_is_valid_idx(idx))
- return 0;
- rc = synx_gmem_lock(idx, &flags);
- if (rc)
- return 0;
- synx_g_obj = &synx_gmem.table[idx];
- synx_global_print_data(synx_g_obj, __func__);
- status = synx_g_obj->status;
- /* if handle is still ACTIVE */
- if (status == SYNX_STATE_ACTIVE || synx_g_obj->num_child != 0) {
- synx_g_obj->waiters |= (1UL << id);
- status = SYNX_STATE_ACTIVE;
- }
- else
- dprintk(SYNX_DBG, "handle %u already signaled %u",
- synx_g_obj->handle, synx_g_obj->status);
- synx_gmem_unlock(idx, &flags);
- return status;
- }
- static int synx_global_update_status_core(u32 idx,
- u32 status)
- {
- u32 i, p_idx;
- int rc;
- bool clear = false;
- unsigned long flags;
- uint64_t data;
- struct synx_global_coredata *synx_g_obj;
- u32 h_parents[SYNX_GLOBAL_MAX_PARENTS] = {0};
- bool wait_cores[SYNX_CORE_MAX] = {false};
- rc = synx_gmem_lock(idx, &flags);
- if (rc)
- return rc;
- synx_g_obj = &synx_gmem.table[idx];
- synx_global_print_data(synx_g_obj, __func__);
- /* prepare for cross core signaling */
- data = synx_g_obj->handle;
- data <<= 32;
- if (synx_g_obj->num_child != 0) {
- /* composite handle */
- synx_g_obj->num_child--;
- if (synx_g_obj->status == SYNX_STATE_ACTIVE ||
- (status > SYNX_STATE_SIGNALED_SUCCESS &&
- status <= SYNX_STATE_SIGNALED_MAX))
- synx_g_obj->status = status;
- if (synx_g_obj->num_child == 0) {
- data |= synx_g_obj->status;
- synx_global_get_waiting_cores_locked(synx_g_obj,
- wait_cores);
- synx_global_get_parents_locked(synx_g_obj, h_parents);
- /* release ref held by constituting handles */
- synx_g_obj->refcount--;
- if (synx_g_obj->refcount == 0) {
- memset(synx_g_obj, 0,
- sizeof(*synx_g_obj));
- clear = true;
- }
- } else {
- /* pending notification from handles */
- data = 0;
- dprintk(SYNX_DBG,
- "Child notified parent handle %u, pending %u\n",
- synx_g_obj->handle, synx_g_obj->num_child);
- }
- } else {
- synx_g_obj->status = status;
- data |= synx_g_obj->status;
- synx_global_get_waiting_cores_locked(synx_g_obj,
- wait_cores);
- synx_global_get_parents_locked(synx_g_obj, h_parents);
- }
- synx_gmem_unlock(idx, &flags);
- if (clear) {
- ipclite_global_test_and_clear_bit(idx%32,
- (ipclite_atomic_uint32_t *)(synx_gmem.bitmap + idx/32));
- dprintk(SYNX_MEM,
- "cleared global idx %u\n", idx);
- }
- /* notify waiting clients on signal */
- if (data) {
- /* notify wait client */
- /* In case of SSR, someone might be waiting on same core
- * However, in other cases, synx_signal API will take care
- * of signaling handles on same core and thus we don't need
- * to send interrupt
- */
- if (status == SYNX_STATE_SIGNALED_SSR)
- i = 0;
- else
- i = 1;
- for (; i < SYNX_CORE_MAX ; i++) {
- if (!wait_cores[i])
- continue;
- dprintk(SYNX_DBG,
- "invoking ipc signal handle %u, status %u\n",
- synx_g_obj->handle, synx_g_obj->status);
- if (ipclite_msg_send(
- synx_global_map_core_id(i),
- data))
- dprintk(SYNX_ERR,
- "ipc signaling %llu to core %u failed\n",
- data, i);
- }
- }
- /* handle parent notifications */
- for (i = 0; i < SYNX_GLOBAL_MAX_PARENTS; i++) {
- p_idx = h_parents[i];
- if (p_idx == 0)
- continue;
- synx_global_update_status_core(p_idx, status);
- }
- return SYNX_SUCCESS;
- }
- int synx_global_update_status(u32 idx, u32 status)
- {
- int rc = -SYNX_INVALID;
- unsigned long flags;
- struct synx_global_coredata *synx_g_obj;
- if (!synx_gmem.table)
- return -SYNX_NOMEM;
- if (!synx_is_valid_idx(idx) || status <= SYNX_STATE_ACTIVE)
- return -SYNX_INVALID;
- rc = synx_gmem_lock(idx, &flags);
- if (rc)
- return rc;
- synx_g_obj = &synx_gmem.table[idx];
- if (synx_g_obj->num_child != 0) {
- /* composite handle cannot be signaled */
- goto fail;
- } else if (synx_g_obj->status != SYNX_STATE_ACTIVE) {
- rc = -SYNX_ALREADY;
- goto fail;
- }
- synx_gmem_unlock(idx, &flags);
- return synx_global_update_status_core(idx, status);
- fail:
- synx_gmem_unlock(idx, &flags);
- return rc;
- }
- int synx_global_get_ref(u32 idx)
- {
- int rc;
- unsigned long flags;
- struct synx_global_coredata *synx_g_obj;
- if (!synx_gmem.table)
- return -SYNX_NOMEM;
- if (!synx_is_valid_idx(idx))
- return -SYNX_INVALID;
- rc = synx_gmem_lock(idx, &flags);
- if (rc)
- return rc;
- synx_g_obj = &synx_gmem.table[idx];
- synx_global_print_data(synx_g_obj, __func__);
- if (synx_g_obj->handle && synx_g_obj->refcount)
- synx_g_obj->refcount++;
- else
- rc = -SYNX_NOENT;
- synx_gmem_unlock(idx, &flags);
- return rc;
- }
- void synx_global_put_ref(u32 idx)
- {
- int rc;
- bool clear = false;
- unsigned long flags;
- struct synx_global_coredata *synx_g_obj;
- if (!synx_gmem.table)
- return;
- if (!synx_is_valid_idx(idx))
- return;
- rc = synx_gmem_lock(idx, &flags);
- if (rc)
- return;
- synx_g_obj = &synx_gmem.table[idx];
- synx_g_obj->refcount--;
- if (synx_g_obj->refcount == 0) {
- memset(synx_g_obj, 0, sizeof(*synx_g_obj));
- clear = true;
- }
- synx_gmem_unlock(idx, &flags);
- if (clear) {
- ipclite_global_test_and_clear_bit(idx%32,
- (ipclite_atomic_uint32_t *)(synx_gmem.bitmap + idx/32));
- dprintk(SYNX_MEM, "cleared global idx %u\n", idx);
- }
- }
- int synx_global_merge(u32 *idx_list, u32 num_list, u32 p_idx)
- {
- int rc = -SYNX_INVALID;
- unsigned long flags;
- struct synx_global_coredata *synx_g_obj;
- u32 i, j = 0;
- u32 idx;
- u32 num_child = 0;
- u32 parent_status = SYNX_STATE_ACTIVE;
- if (!synx_gmem.table)
- return -SYNX_NOMEM;
- if (!synx_is_valid_idx(p_idx))
- return -SYNX_INVALID;
- if (num_list == 0)
- return SYNX_SUCCESS;
- while (j < num_list) {
- idx = idx_list[j];
- if (!synx_is_valid_idx(idx))
- goto fail;
- rc = synx_gmem_lock(idx, &flags);
- if (rc)
- goto fail;
- synx_g_obj = &synx_gmem.table[idx];
- for (i = 0; i < SYNX_GLOBAL_MAX_PARENTS; i++) {
- if (synx_g_obj->parents[i] == 0) {
- synx_g_obj->parents[i] = p_idx;
- break;
- }
- }
- if (synx_g_obj->status == SYNX_STATE_ACTIVE)
- num_child++;
- else if (synx_g_obj->status >
- SYNX_STATE_SIGNALED_SUCCESS &&
- synx_g_obj->status <= SYNX_STATE_SIGNALED_MAX)
- parent_status = synx_g_obj->status;
- else if (parent_status == SYNX_STATE_ACTIVE)
- parent_status = synx_g_obj->status;
- if (synx_g_obj->status != SYNX_STATE_ACTIVE && synx_g_obj->num_child != 0)
- num_child++;
- dprintk(SYNX_MEM, "synx_obj->status %d parent status %d\n",
- synx_g_obj->status, parent_status);
- synx_gmem_unlock(idx, &flags);
- if (i >= SYNX_GLOBAL_MAX_PARENTS) {
- rc = -SYNX_NOMEM;
- goto fail;
- }
- j++;
- }
- rc = synx_gmem_lock(p_idx, &flags);
- if (rc)
- goto fail;
- synx_g_obj = &synx_gmem.table[p_idx];
- synx_g_obj->num_child += num_child;
- if (synx_g_obj->num_child != 0)
- synx_g_obj->refcount++;
- synx_g_obj->status = parent_status;
- synx_global_print_data(synx_g_obj, __func__);
- synx_gmem_unlock(p_idx, &flags);
- return SYNX_SUCCESS;
- fail:
- while (num_child--) {
- idx = idx_list[num_child];
- if (synx_gmem_lock(idx, &flags))
- continue;
- synx_g_obj = &synx_gmem.table[idx];
- for (i = 0; i < SYNX_GLOBAL_MAX_PARENTS; i++) {
- if (synx_g_obj->parents[i] == p_idx) {
- synx_g_obj->parents[i] = 0;
- break;
- }
- }
- synx_gmem_unlock(idx, &flags);
- }
- return rc;
- }
- int synx_global_recover(enum synx_core_id core_id)
- {
- int rc = SYNX_SUCCESS;
- u32 idx = 0;
- const u32 size = SYNX_GLOBAL_MAX_OBJS;
- unsigned long flags;
- struct synx_global_coredata *synx_g_obj;
- bool update;
- int *clear_idx = NULL;
- if (!synx_gmem.table)
- return -SYNX_NOMEM;
- clear_idx = kzalloc(sizeof(int)*SYNX_GLOBAL_MAX_OBJS, GFP_KERNEL);
- if (!clear_idx)
- return -SYNX_NOMEM;
- ipclite_recover(synx_global_map_core_id(core_id));
- /* recover synx gmem lock if it was owned by core in ssr */
- if (synx_gmem_lock_owner(0) == core_id) {
- synx_gmem_lock_owner_clear(0);
- hwspin_unlock_raw(synx_hwlock);
- }
- idx = find_next_bit((unsigned long *)synx_gmem.bitmap,
- size, idx + 1);
- while (idx < size) {
- update = false;
- rc = synx_gmem_lock(idx, &flags);
- if (rc)
- goto free;
- synx_g_obj = &synx_gmem.table[idx];
- if (synx_g_obj->refcount &&
- synx_g_obj->subscribers & (1UL << core_id)) {
- synx_g_obj->subscribers &= ~(1UL << core_id);
- synx_g_obj->refcount--;
- if (synx_g_obj->refcount == 0) {
- memset(synx_g_obj, 0, sizeof(*synx_g_obj));
- clear_idx[idx] = 1;
- } else if (synx_g_obj->status == SYNX_STATE_ACTIVE) {
- update = true;
- }
- }
- synx_gmem_unlock(idx, &flags);
- if (update)
- synx_global_update_status(idx,
- SYNX_STATE_SIGNALED_SSR);
- idx = find_next_bit((unsigned long *)synx_gmem.bitmap,
- size, idx + 1);
- }
- for (idx = 1; idx < size; idx++) {
- if (clear_idx[idx]) {
- ipclite_global_test_and_clear_bit(idx % 32,
- (ipclite_atomic_uint32_t *)(synx_gmem.bitmap + idx/32));
- dprintk(SYNX_MEM, "released global idx %u\n", idx);
- }
- }
- free:
- kfree(clear_idx);
- return rc;
- }
- int synx_global_mem_init(void)
- {
- int rc;
- int bitmap_size = SYNX_GLOBAL_MAX_OBJS/32;
- struct global_region_info mem_info;
- rc = get_global_partition_info(&mem_info);
- if (rc) {
- dprintk(SYNX_ERR, "error setting up global shared memory\n");
- return rc;
- }
- memset(mem_info.virt_base, 0, mem_info.size);
- dprintk(SYNX_DBG, "global shared memory %pK size %u\n",
- mem_info.virt_base, mem_info.size);
- synx_gmem.bitmap = (u32 *)mem_info.virt_base;
- synx_gmem.locks = synx_gmem.bitmap + bitmap_size;
- synx_gmem.table =
- (struct synx_global_coredata *)(synx_gmem.locks + 2);
- dprintk(SYNX_DBG, "global memory bitmap %pK, table %pK\n",
- synx_gmem.bitmap, synx_gmem.table);
- return synx_gmem_init();
- }
|