blob: f8f84c545d3981b43e581e427daec5704db6ba5a [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0-only
/*
* Interface for the array of abstracted fences.
*
* Copyright (C) 2023 Google LLC
*/
#include <linux/kref.h>
#include <linux/slab.h>
#include <gcip/gcip-fence-array.h>
#include <gcip/gcip-fence.h>
struct gcip_fence_array *gcip_fence_array_create(int *fences, int num_fences, bool check_same_type)
{
int i, ret;
struct gcip_fence_array *fence_array;
struct gcip_fence *fence;
if (!fences && num_fences)
return ERR_PTR(-EINVAL);
fence_array = kzalloc(sizeof(*fence_array), GFP_KERNEL);
if (!fence_array)
return ERR_PTR(-ENOMEM);
fence_array->fences = kcalloc(num_fences, sizeof(*fence_array->fences), GFP_KERNEL);
if (!fence_array->fences) {
ret = -ENOMEM;
goto err_free_fence_array;
}
fence_array->same_type = true;
for (i = 0; i < num_fences; i++) {
fence = gcip_fence_fdget(fences[i]);
if (IS_ERR(fence)) {
ret = PTR_ERR(fence);
goto err_put_fences;
}
if (i && fence_array->same_type && fence->type != fence_array->fences[0]->type) {
/* Check whether all fences are the same type. */
if (check_same_type) {
ret = -EINVAL;
gcip_fence_put(fence);
goto err_put_fences;
}
fence_array->same_type = false;
}
fence_array->fences[i] = fence;
}
if (i && fence_array->same_type)
fence_array->type = fence_array->fences[0]->type;
fence_array->size = i;
kref_init(&fence_array->kref);
return fence_array;
err_put_fences:
while (i--)
gcip_fence_put(fence_array->fences[i]);
kfree(fence_array->fences);
err_free_fence_array:
kfree(fence_array);
return ERR_PTR(ret);
}
static void gcip_fence_array_release(struct kref *kref)
{
struct gcip_fence_array *fence_array = container_of(kref, struct gcip_fence_array, kref);
int i;
for (i = 0; i < fence_array->size; i++)
gcip_fence_put(fence_array->fences[i]);
kfree(fence_array->fences);
kfree(fence_array);
}
struct gcip_fence_array *gcip_fence_array_get(struct gcip_fence_array *fence_array)
{
if (!fence_array)
return NULL;
kref_get(&fence_array->kref);
return fence_array;
}
void gcip_fence_array_put(struct gcip_fence_array *fence_array)
{
if (fence_array)
kref_put(&fence_array->kref, gcip_fence_array_release);
}
void gcip_fence_array_signal(struct gcip_fence_array *fence_array, int errno)
{
int i;
if (!fence_array)
return;
for (i = 0; i < fence_array->size; i++)
gcip_fence_signal(fence_array->fences[i], errno);
}
void gcip_fence_array_waited(struct gcip_fence_array *fence_array)
{
int i;
if (!fence_array)
return;
for (i = 0; i < fence_array->size; i++)
gcip_fence_waited(fence_array->fences[i]);
}
void gcip_fence_array_submit_signaler(struct gcip_fence_array *fence_array)
{
int i;
if (!fence_array)
return;
for (i = 0; i < fence_array->size; i++)
gcip_fence_submit_signaler(fence_array->fences[i]);
}
void gcip_fence_array_submit_waiter(struct gcip_fence_array *fence_array)
{
int i;
if (!fence_array)
return;
for (i = 0; i < fence_array->size; i++)
gcip_fence_submit_waiter(fence_array->fences[i]);
}
uint16_t *gcip_fence_array_get_iif_id(struct gcip_fence_array *fence_array, int *num_iif)
{
uint16_t *iif_fences;
int i, j;
if (!fence_array)
return NULL;
*num_iif = 0;
for (i = 0; i < fence_array->size; i++) {
if (fence_array->fences[i]->type == GCIP_INTER_IP_FENCE)
(*num_iif)++;
}
if (!(*num_iif))
return NULL;
iif_fences = kcalloc(*num_iif, sizeof(*iif_fences), GFP_KERNEL);
if (!iif_fences)
return ERR_PTR(-ENOMEM);
for (i = 0, j = 0; i < fence_array->size; i++) {
if (fence_array->fences[i]->type == GCIP_INTER_IP_FENCE)
iif_fences[j++] = gcip_fence_get_iif_id(fence_array->fences[i]);
}
return iif_fences;
}
int gcip_fence_array_wait_signaler_submission(struct gcip_fence_array *fence_array,
unsigned int eventfd, int *remaining_signalers)
{
return gcip_fence_wait_signaler_submission(fence_array->fences, fence_array->size, eventfd,
remaining_signalers);
}