linux/drivers/misc/xilinx-ai-engine/ai-engine-res.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Xilinx AI Engine device driver
   4 *
   5 * Copyright (C) 2020 Xilinx, Inc.
   6 */
   7
   8#include <linux/bitmap.h>
   9
  10#include "ai-engine-internal.h"
  11
  12/**
  13 * aie_resource_initialize() - initialize AI engine resource
  14 * @res: pointer to AI engine resource
  15 * @count: total number of element of this resource
  16 * @return: 0 for success, negative value for failure.
  17 *
  18 * This function will initialize the data structure for the
  19 * resource.
  20 */
  21int aie_resource_initialize(struct aie_resource *res, int count)
  22{
  23        if (!res || !count)
  24                return -EINVAL;
  25        res->bitmap = bitmap_zalloc(count, GFP_KERNEL);
  26        if (!res->bitmap)
  27                return -ENOMEM;
  28        res->total = count;
  29
  30        return 0;
  31}
  32
  33/**
  34 * aie_resource_uninitialize() - uninitialize AI engine resource
  35 * @res: pointer to AI engine resource
  36 *
  37 * This function will release the AI engine resource data members.
  38 */
  39void aie_resource_uninitialize(struct aie_resource *res)
  40{
  41        res->total = 0;
  42        if (res->bitmap)
  43                bitmap_free(res->bitmap);
  44}
  45
  46/**
  47 * aie_resource_check_region() - check availability of requested resource
  48 * @res: pointer to AI engine resource to check
  49 * @start: start index of the required resource, it will only be used if
  50 *         @continuous is 1. It will check the available resource starting from
  51 *         @start
  52 * @count: number of requested element
  53 * @return: start resource id if the requested number of resources are available
  54 *          It will return negative value of errors.
  55 *
  56 * This function will check the availability. It will return start resource id
  57 * if the requested number of resources are available.
  58 */
  59int aie_resource_check_region(struct aie_resource *res,
  60                              u32 start, u32 count)
  61{
  62        unsigned long id;
  63
  64        if (!res || !res->bitmap || !count)
  65                return -EINVAL;
  66        id = bitmap_find_next_zero_area(res->bitmap, res->total, start,
  67                                        count, 0);
  68        if (id >= res->total)
  69                return -ERANGE;
  70
  71        return (int)id;
  72}
  73
  74/**
  75 * aie_resource_get_region() - get requested AI engine resource
  76 * @res: pointer to AI engine resource to check
  77 * @count: number of requested element
  78 * @start: start index of the required resource
  79 * @return: start resource id for success, and negative value for failure.
  80 *
  81 * This function check if the requested AI engine resource is available.
  82 * If it is available, mark it used and return the start resource id.
  83 */
  84int aie_resource_get_region(struct aie_resource *res, u32 start, u32 count)
  85{
  86        unsigned long off;
  87
  88        if (!res || !res->bitmap || !count)
  89                return -EINVAL;
  90        off = bitmap_find_next_zero_area(res->bitmap, res->total, start,
  91                                         count, 0);
  92        if (off >= res->total) {
  93                pr_err("Failed to get available AI engine resource.\n");
  94                return -ERANGE;
  95        }
  96        bitmap_set(res->bitmap, off, count);
  97
  98        return (int)off;
  99}
 100
 101/**
 102 * aie_resource_put_region() - release requested AI engine resource
 103 * @res: pointer to AI engine resource to check
 104 * @start: start index of the resource to release
 105 * @count: number of elements to release
 106 *
 107 * This function release the requested AI engine resource.
 108 */
 109void aie_resource_put_region(struct aie_resource *res, int start, u32 count)
 110{
 111        if (!res || !count)
 112                return;
 113        bitmap_clear(res->bitmap, start, count);
 114}
 115
 116/**
 117 * aie_resource_set() - set the AI engine resource bits
 118 * @res: pointer to AI engine resource
 119 * @start: start bit to set
 120 * @count: number of bits to set
 121 * @return: 0 for success and negative value for failure
 122 *
 123 * This function sets the specified number bits in the resource.
 124 */
 125int aie_resource_set(struct aie_resource *res, u32 start, u32 count)
 126{
 127        if (!res || !res->bitmap || !count || start + count > res->total)
 128                return -EINVAL;
 129
 130        bitmap_set(res->bitmap, start, count);
 131        return 0;
 132}
 133
 134/**
 135 * aie_resource_cpy_from_arr32() - copies nbits from u32[] to bitmap.
 136 * @res: pointer to AI engine resource
 137 * @start: start bit in bitmap
 138 * @src: source buffer
 139 * @nbits: number of bits to copy from u32[]
 140 * @return: 0 for success and negative value for failure
 141 */
 142int aie_resource_cpy_from_arr32(struct aie_resource *res, u32 start,
 143                                const u32 *src, u32 nbits)
 144{
 145        if (!res || !res->bitmap || !nbits || start + nbits  > res->total ||
 146            !src)
 147                return -EINVAL;
 148
 149        bitmap_from_arr32(res->bitmap + BIT_WORD(start), src, nbits);
 150        return 0;
 151}
 152
 153/**
 154 * aie_resource_cpy_to_arr32() - copies nbits to u32[] from bitmap.
 155 * @res: pointer to AI engine resource
 156 * @start: start bit in bitmap
 157 * @dst: destination buffer
 158 * @nbits: number of bits to copy to u32[]
 159 * @return: 0 for success and negative value for failure
 160 */
 161int aie_resource_cpy_to_arr32(struct aie_resource *res, u32 start, u32 *dst,
 162                              u32 nbits)
 163{
 164        if (!res || !res->bitmap || !nbits || start + nbits  > res->total ||
 165            !dst)
 166                return -EINVAL;
 167
 168        bitmap_to_arr32(dst, res->bitmap + BIT_WORD(start), nbits);
 169        return 0;
 170}
 171
 172/**
 173 * aie_resource_clear() - clear the AI engine resource bits
 174 * @res: pointer to AI engine resource
 175 * @start: start bit to set
 176 * @count: number of bits to clear
 177 * @return: 0 for success and negative value for failure
 178 *
 179 * This function clears the specified number bits in the resource.
 180 */
 181int aie_resource_clear(struct aie_resource *res, u32 start, u32 count)
 182{
 183        if (!res || !res->bitmap || !count || start + count > res->total)
 184                return -EINVAL;
 185
 186        bitmap_clear(res->bitmap, start, count);
 187        return 0;
 188}
 189
 190/**
 191 * aie_resource_clear_all() - clear all the AI engine resource bits
 192 * @res: pointer to AI engine resource
 193 * @return: 0 for success and negative value for failure
 194 *
 195 * This function clears all the bits in the resource.
 196 */
 197int aie_resource_clear_all(struct aie_resource *res)
 198{
 199        if (!res || !res->bitmap)
 200                return -EINVAL;
 201
 202        bitmap_clear(res->bitmap, 0, res->total);
 203        return 0;
 204}
 205
 206/**
 207 * aie_resource_testbit() - test if a bit is set in a AI engine resource
 208 * @res: pointer to AI engine resource
 209 * @bit: bit to check
 210 * @return: true for set, false for not set
 211 */
 212bool aie_resource_testbit(struct aie_resource *res, u32 bit)
 213{
 214        if (!res || !res->bitmap || bit >= res->total)
 215                return false;
 216
 217        /* Locate the unsigned long the required bit belongs to */
 218        return test_bit(bit, res->bitmap);
 219}
 220
 221/**
 222 * aie_resource_check_common_avail() - check common available bits
 223 *                                     of two resources table
 224 * @res0: pointer to AI engine resource0
 225 * @res1: pointer to AI engine resource1
 226 * @sbit: start bit to check
 227 * @nbits: number of bits to check
 228 * @return: number of common bits, or negative value for failure
 229 */
 230int aie_resource_check_common_avail(struct aie_resource *res0,
 231                                    struct aie_resource *res1,
 232                                    u32 sbit, u32 nbits)
 233{
 234        u32 ebit, avails;
 235
 236        if (!nbits || !res0 || !res1 || !res0->bitmap || !res1->bitmap ||
 237            (sbit + nbits) > res0->total || (sbit + nbits) > res1->total)
 238                return -EINVAL;
 239
 240        ebit = sbit + nbits - 1;
 241        avails = 0;
 242        while (sbit <= ebit) {
 243                unsigned long  *bitmap0, *bitmap1, tbits;
 244                u32 tlbit, lbit = sbit % BITS_PER_LONG;
 245                u32 lnbits = ebit - sbit + 1;
 246
 247                if (lnbits + lbit > BITS_PER_LONG)
 248                        lnbits = BITS_PER_LONG - lbit;
 249
 250                bitmap0 = &res0->bitmap[sbit / BITS_PER_LONG];
 251                bitmap1 = &res1->bitmap[sbit / BITS_PER_LONG];
 252                bitmap_or(&tbits, bitmap0, bitmap1, BITS_PER_LONG);
 253                tlbit = lbit;
 254                while (tlbit < lbit + lnbits) {
 255                        u32 b = bitmap_find_next_zero_area(&tbits,
 256                                                           BITS_PER_LONG, tlbit,
 257                                                           1, 0);
 258                        if (b >= lbit + lnbits)
 259                                break;
 260                        avails++;
 261                        tlbit = b + 1;
 262                }
 263                sbit += lnbits;
 264        };
 265
 266        return avails;
 267}
 268
 269/**
 270 * aie_resource_get_common_avail() - get common available bits
 271 *                                   of two resources table
 272 * @res0: pointer to AI engine resource0
 273 * @res1: pointer to AI engine resource1
 274 * @sbit: start bit to check
 275 * @nbits: number of bits to get
 276 * @total: total number of bits to check
 277 * @rscs: resources array to return for resources ids
 278 * @return: number of allocated bits for success, negative value for failure
 279 */
 280int aie_resource_get_common_avail(struct aie_resource *res0,
 281                                  struct aie_resource *res1,
 282                                  u32 sbit, u32 nbits, u32 total,
 283                                  struct aie_rsc *rscs)
 284{
 285        u32 ebit, tsbit, tnbits;
 286
 287        if (!nbits || !res0 || !res1 || !res0->bitmap || !res1->bitmap ||
 288            nbits > total || (sbit + total) > res0->total ||
 289            (sbit + total) > res1->total)
 290                return -EINVAL;
 291
 292        ebit = sbit + total - 1;
 293        tsbit = sbit;
 294        tnbits = 0;
 295        while (tsbit <= ebit && tnbits != nbits) {
 296                unsigned long *bitmap0, *bitmap1, tbits;
 297                u32 tlbit, lbit = tsbit % BITS_PER_LONG;
 298                u32 lnbits = ebit - tsbit + 1;
 299
 300                if (lnbits + lbit > BITS_PER_LONG)
 301                        lnbits = BITS_PER_LONG - lbit;
 302
 303                bitmap0 = &res0->bitmap[sbit / BITS_PER_LONG];
 304                bitmap1 = &res1->bitmap[sbit / BITS_PER_LONG];
 305                bitmap_or(&tbits, bitmap0, bitmap1, BITS_PER_LONG);
 306                tlbit = lbit;
 307                while (tlbit < lbit + lnbits && tnbits != nbits) {
 308                        u32 b = bitmap_find_next_zero_area(&tbits,
 309                                                           BITS_PER_LONG, tlbit,
 310                                                           1, 0);
 311                        if (b >= lbit + lnbits)
 312                                break;
 313                        rscs[tnbits].id = tsbit - sbit + b - lbit;
 314                        tnbits++;
 315                        tlbit = b + 1;
 316                }
 317                tsbit += lnbits;
 318        };
 319
 320        if (tnbits != nbits)
 321                return -EINVAL;
 322
 323        while (tnbits--) {
 324                aie_resource_set(res0, sbit + rscs[tnbits].id, 1);
 325                aie_resource_set(res1, sbit + rscs[tnbits].id, 1);
 326        }
 327
 328        return nbits;
 329}
 330
 331/**
 332 * aie_resource_check_pattern_region() - check availability of requested
 333 *                                       contiguous resources of a pattern
 334 * @res: pointer to AI engine resource to check
 335 * @start: start index of the required resource
 336 *         It will check a continuous block of available resource starting from
 337 *         @start.
 338 * @end: end index to check
 339 * @count: number of requested element
 340 * @return: start resource id if the requested number of resources are available
 341 *          It will return negative value of errors.
 342 *
 343 * This function will check the availability. It will return start resource id
 344 * if the requested number of resources are available.
 345 * The contiguous resources of a pattern is e.g.
 346 * @count is 0, the resources starting from @start needs to be 0,1; or 2,3 and
 347 * beyond
 348 */
 349int aie_resource_check_pattern_region(struct aie_resource *res,
 350                                      u32 start, u32 end, u32 count)
 351{
 352        unsigned long id;
 353        u32 lstart;
 354
 355        if (!res || !res->bitmap || !count)
 356                return -EINVAL;
 357        lstart = start;
 358        while (lstart < end) {
 359                id = bitmap_find_next_zero_area(res->bitmap, res->total, lstart,
 360                                                count, 0);
 361                if (id + count > end + 1)
 362                        return -ERANGE;
 363                else if (!((id - lstart) % count))
 364                        return (int)id;
 365
 366                lstart += count;
 367        }
 368
 369        return -ERANGE;
 370}
 371
 372/**
 373 * aie_resource_check_common_pattern_region() - check common available region
 374 *                                              of two resources table
 375 * @res0: pointer to AI engine resource0
 376 * @res1: pointer to AI engine resource1
 377 * @sbit: start bit to check
 378 * @nbits: number of bits to check
 379 * @total: total number of bits to check
 380 * @return: start bit of common region if it is found, negative value for
 381 *          failure
 382 */
 383int aie_resource_check_common_pattern_region(struct aie_resource *res0,
 384                                             struct aie_resource *res1,
 385                                             u32 sbit, u32 nbits, u32 total)
 386{
 387        int sbit0, sbit1;
 388
 389        if (!nbits || !res0 || !res1 || !res0->bitmap || !res1->bitmap ||
 390            nbits > total || (sbit + total) > res0->total ||
 391            (sbit + total) > res1->total)
 392                return -EINVAL;
 393
 394        sbit0 = aie_resource_check_pattern_region(res0, sbit,
 395                                                  sbit + total - 1, nbits);
 396        if (sbit0 < 0)
 397                return sbit0;
 398
 399        if ((u32)sbit0 + nbits > sbit + total)
 400                return -EINVAL;
 401
 402        sbit1 = aie_resource_check_pattern_region(res1, sbit0,
 403                                                  sbit0 + nbits - 1, nbits);
 404        if (sbit1 != sbit0)
 405                return -EINVAL;
 406
 407        return sbit1;
 408}
 409
 410/**
 411 * aie_resource_get_common_pattern_region() - get common available region
 412 *                                            of two resources table
 413 * @res0: pointer to AI engine resource0
 414 * @res1: pointer to AI engine resource1
 415 * @sbit: start bit to check
 416 * @nbits: number of bits to get
 417 * @total: total number of bits to check
 418 * @rscs: resources array to return for resources ids
 419 * @return: start bit of the common region if it is found, negative value for
 420 *          failure
 421 *
 422 * The common pattern region is a contiguous block of resources which needs
 423 * to be very number of @nbits.
 424 * e.g. if nbits is 2, the offset to the start bit @sbit of returned resources
 425 * needs to be: 0,1; 2,3 ...
 426 */
 427int aie_resource_get_common_pattern_region(struct aie_resource *res0,
 428                                           struct aie_resource *res1,
 429                                           u32 sbit, u32 nbits, u32 total,
 430                                           struct aie_rsc *rscs)
 431{
 432        int rsbit, ret;
 433
 434        rsbit = aie_resource_check_common_pattern_region(res0, res1, sbit,
 435                                                         nbits, total);
 436        if (rsbit < 0)
 437                return rsbit;
 438
 439        ret = aie_resource_get_region(res0, rsbit, nbits);
 440        if (ret < 0)
 441                return ret;
 442
 443        if (ret != rsbit) {
 444                aie_resource_put_region(res0, ret, nbits);
 445                return -EINVAL;
 446        }
 447
 448        ret = aie_resource_get_region(res1, rsbit, nbits);
 449        if (ret < 0)
 450                return ret;
 451
 452        if (ret != rsbit) {
 453                aie_resource_put_region(res0, rsbit, nbits);
 454                aie_resource_put_region(res1, ret, nbits);
 455                return -EINVAL;
 456        }
 457
 458        if (rscs) {
 459                u32 i;
 460
 461                for (i = 0; i < nbits; i++, rscs++)
 462                        rscs->id = rsbit - sbit + i;
 463        }
 464
 465        return rsbit;
 466}
 467