This source file includes following definitions.
- host1x_syncpt_base_request
 
- host1x_syncpt_base_free
 
- host1x_syncpt_alloc
 
- host1x_syncpt_id
 
- host1x_syncpt_incr_max
 
- host1x_syncpt_restore
 
- host1x_syncpt_save
 
- host1x_syncpt_load
 
- host1x_syncpt_load_wait_base
 
- host1x_syncpt_incr
 
- syncpt_load_min_is_expired
 
- host1x_syncpt_wait
 
- host1x_syncpt_is_expired
 
- host1x_syncpt_init
 
- host1x_syncpt_request
 
- host1x_syncpt_free
 
- host1x_syncpt_deinit
 
- host1x_syncpt_read_max
 
- host1x_syncpt_read_min
 
- host1x_syncpt_read
 
- host1x_syncpt_nb_pts
 
- host1x_syncpt_nb_bases
 
- host1x_syncpt_nb_mlocks
 
- host1x_syncpt_get
 
- host1x_syncpt_get_base
 
- host1x_syncpt_base_id
 
   1 
   2 
   3 
   4 
   5 
   6 
   7 
   8 #include <linux/module.h>
   9 #include <linux/device.h>
  10 #include <linux/slab.h>
  11 
  12 #include <trace/events/host1x.h>
  13 
  14 #include "syncpt.h"
  15 #include "dev.h"
  16 #include "intr.h"
  17 #include "debug.h"
  18 
  19 #define SYNCPT_CHECK_PERIOD (2 * HZ)
  20 #define MAX_STUCK_CHECK_COUNT 15
  21 
  22 static struct host1x_syncpt_base *
  23 host1x_syncpt_base_request(struct host1x *host)
  24 {
  25         struct host1x_syncpt_base *bases = host->bases;
  26         unsigned int i;
  27 
  28         for (i = 0; i < host->info->nb_bases; i++)
  29                 if (!bases[i].requested)
  30                         break;
  31 
  32         if (i >= host->info->nb_bases)
  33                 return NULL;
  34 
  35         bases[i].requested = true;
  36         return &bases[i];
  37 }
  38 
  39 static void host1x_syncpt_base_free(struct host1x_syncpt_base *base)
  40 {
  41         if (base)
  42                 base->requested = false;
  43 }
  44 
  45 static struct host1x_syncpt *host1x_syncpt_alloc(struct host1x *host,
  46                                                  struct host1x_client *client,
  47                                                  unsigned long flags)
  48 {
  49         struct host1x_syncpt *sp = host->syncpt;
  50         unsigned int i;
  51         char *name;
  52 
  53         mutex_lock(&host->syncpt_mutex);
  54 
  55         for (i = 0; i < host->info->nb_pts && sp->name; i++, sp++)
  56                 ;
  57 
  58         if (i >= host->info->nb_pts)
  59                 goto unlock;
  60 
  61         if (flags & HOST1X_SYNCPT_HAS_BASE) {
  62                 sp->base = host1x_syncpt_base_request(host);
  63                 if (!sp->base)
  64                         goto unlock;
  65         }
  66 
  67         name = kasprintf(GFP_KERNEL, "%02u-%s", sp->id,
  68                          client ? dev_name(client->dev) : NULL);
  69         if (!name)
  70                 goto free_base;
  71 
  72         sp->client = client;
  73         sp->name = name;
  74 
  75         if (flags & HOST1X_SYNCPT_CLIENT_MANAGED)
  76                 sp->client_managed = true;
  77         else
  78                 sp->client_managed = false;
  79 
  80         mutex_unlock(&host->syncpt_mutex);
  81         return sp;
  82 
  83 free_base:
  84         host1x_syncpt_base_free(sp->base);
  85         sp->base = NULL;
  86 unlock:
  87         mutex_unlock(&host->syncpt_mutex);
  88         return NULL;
  89 }
  90 
  91 
  92 
  93 
  94 
  95 
  96 
  97 
  98 
  99 u32 host1x_syncpt_id(struct host1x_syncpt *sp)
 100 {
 101         return sp->id;
 102 }
 103 EXPORT_SYMBOL(host1x_syncpt_id);
 104 
 105 
 106 
 107 
 108 
 109 
 110 u32 host1x_syncpt_incr_max(struct host1x_syncpt *sp, u32 incrs)
 111 {
 112         return (u32)atomic_add_return(incrs, &sp->max_val);
 113 }
 114 EXPORT_SYMBOL(host1x_syncpt_incr_max);
 115 
 116  
 117 
 118 
 119 void host1x_syncpt_restore(struct host1x *host)
 120 {
 121         struct host1x_syncpt *sp_base = host->syncpt;
 122         unsigned int i;
 123 
 124         for (i = 0; i < host1x_syncpt_nb_pts(host); i++)
 125                 host1x_hw_syncpt_restore(host, sp_base + i);
 126 
 127         for (i = 0; i < host1x_syncpt_nb_bases(host); i++)
 128                 host1x_hw_syncpt_restore_wait_base(host, sp_base + i);
 129 
 130         wmb();
 131 }
 132 
 133 
 134 
 135 
 136 
 137 void host1x_syncpt_save(struct host1x *host)
 138 {
 139         struct host1x_syncpt *sp_base = host->syncpt;
 140         unsigned int i;
 141 
 142         for (i = 0; i < host1x_syncpt_nb_pts(host); i++) {
 143                 if (host1x_syncpt_client_managed(sp_base + i))
 144                         host1x_hw_syncpt_load(host, sp_base + i);
 145                 else
 146                         WARN_ON(!host1x_syncpt_idle(sp_base + i));
 147         }
 148 
 149         for (i = 0; i < host1x_syncpt_nb_bases(host); i++)
 150                 host1x_hw_syncpt_load_wait_base(host, sp_base + i);
 151 }
 152 
 153 
 154 
 155 
 156 
 157 u32 host1x_syncpt_load(struct host1x_syncpt *sp)
 158 {
 159         u32 val;
 160 
 161         val = host1x_hw_syncpt_load(sp->host, sp);
 162         trace_host1x_syncpt_load_min(sp->id, val);
 163 
 164         return val;
 165 }
 166 
 167 
 168 
 169 
 170 u32 host1x_syncpt_load_wait_base(struct host1x_syncpt *sp)
 171 {
 172         host1x_hw_syncpt_load_wait_base(sp->host, sp);
 173 
 174         return sp->base_val;
 175 }
 176 
 177 
 178 
 179 
 180 
 181 int host1x_syncpt_incr(struct host1x_syncpt *sp)
 182 {
 183         return host1x_hw_syncpt_cpu_incr(sp->host, sp);
 184 }
 185 EXPORT_SYMBOL(host1x_syncpt_incr);
 186 
 187 
 188 
 189 
 190 
 191 static bool syncpt_load_min_is_expired(struct host1x_syncpt *sp, u32 thresh)
 192 {
 193         host1x_hw_syncpt_load(sp->host, sp);
 194 
 195         return host1x_syncpt_is_expired(sp, thresh);
 196 }
 197 
 198 
 199 
 200 
 201 
 202 
 203 
 204 
 205 int host1x_syncpt_wait(struct host1x_syncpt *sp, u32 thresh, long timeout,
 206                        u32 *value)
 207 {
 208         DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
 209         void *ref;
 210         struct host1x_waitlist *waiter;
 211         int err = 0, check_count = 0;
 212         u32 val;
 213 
 214         if (value)
 215                 *value = 0;
 216 
 217         
 218         if (host1x_syncpt_is_expired(sp, thresh)) {
 219                 if (value)
 220                         *value = host1x_syncpt_load(sp);
 221 
 222                 return 0;
 223         }
 224 
 225         
 226         val = host1x_hw_syncpt_load(sp->host, sp);
 227         if (host1x_syncpt_is_expired(sp, thresh)) {
 228                 if (value)
 229                         *value = val;
 230 
 231                 goto done;
 232         }
 233 
 234         if (!timeout) {
 235                 err = -EAGAIN;
 236                 goto done;
 237         }
 238 
 239         
 240         waiter = kzalloc(sizeof(*waiter), GFP_KERNEL);
 241         if (!waiter) {
 242                 err = -ENOMEM;
 243                 goto done;
 244         }
 245 
 246         
 247         err = host1x_intr_add_action(sp->host, sp, thresh,
 248                                      HOST1X_INTR_ACTION_WAKEUP_INTERRUPTIBLE,
 249                                      &wq, waiter, &ref);
 250         if (err)
 251                 goto done;
 252 
 253         err = -EAGAIN;
 254         
 255         if (timeout < 0)
 256                 timeout = LONG_MAX;
 257 
 258         
 259         while (timeout) {
 260                 long check = min_t(long, SYNCPT_CHECK_PERIOD, timeout);
 261                 int remain;
 262 
 263                 remain = wait_event_interruptible_timeout(wq,
 264                                 syncpt_load_min_is_expired(sp, thresh),
 265                                 check);
 266                 if (remain > 0 || host1x_syncpt_is_expired(sp, thresh)) {
 267                         if (value)
 268                                 *value = host1x_syncpt_load(sp);
 269 
 270                         err = 0;
 271 
 272                         break;
 273                 }
 274 
 275                 if (remain < 0) {
 276                         err = remain;
 277                         break;
 278                 }
 279 
 280                 timeout -= check;
 281 
 282                 if (timeout && check_count <= MAX_STUCK_CHECK_COUNT) {
 283                         dev_warn(sp->host->dev,
 284                                 "%s: syncpoint id %u (%s) stuck waiting %d, timeout=%ld\n",
 285                                  current->comm, sp->id, sp->name,
 286                                  thresh, timeout);
 287 
 288                         host1x_debug_dump_syncpts(sp->host);
 289 
 290                         if (check_count == MAX_STUCK_CHECK_COUNT)
 291                                 host1x_debug_dump(sp->host);
 292 
 293                         check_count++;
 294                 }
 295         }
 296 
 297         host1x_intr_put_ref(sp->host, sp->id, ref);
 298 
 299 done:
 300         return err;
 301 }
 302 EXPORT_SYMBOL(host1x_syncpt_wait);
 303 
 304 
 305 
 306 
 307 bool host1x_syncpt_is_expired(struct host1x_syncpt *sp, u32 thresh)
 308 {
 309         u32 current_val;
 310         u32 future_val;
 311 
 312         smp_rmb();
 313 
 314         current_val = (u32)atomic_read(&sp->min_val);
 315         future_val = (u32)atomic_read(&sp->max_val);
 316 
 317         
 318 
 319 
 320 
 321 
 322 
 323 
 324 
 325 
 326 
 327 
 328 
 329 
 330 
 331 
 332 
 333 
 334 
 335 
 336 
 337 
 338 
 339 
 340 
 341 
 342 
 343 
 344 
 345 
 346 
 347 
 348 
 349 
 350 
 351 
 352 
 353 
 354 
 355 
 356 
 357 
 358 
 359         if (!host1x_syncpt_client_managed(sp))
 360                 return future_val - thresh >= current_val - thresh;
 361         else
 362                 return (s32)(current_val - thresh) >= 0;
 363 }
 364 
 365 int host1x_syncpt_init(struct host1x *host)
 366 {
 367         struct host1x_syncpt_base *bases;
 368         struct host1x_syncpt *syncpt;
 369         unsigned int i;
 370 
 371         syncpt = devm_kcalloc(host->dev, host->info->nb_pts, sizeof(*syncpt),
 372                               GFP_KERNEL);
 373         if (!syncpt)
 374                 return -ENOMEM;
 375 
 376         bases = devm_kcalloc(host->dev, host->info->nb_bases, sizeof(*bases),
 377                              GFP_KERNEL);
 378         if (!bases)
 379                 return -ENOMEM;
 380 
 381         for (i = 0; i < host->info->nb_pts; i++) {
 382                 syncpt[i].id = i;
 383                 syncpt[i].host = host;
 384 
 385                 
 386 
 387 
 388 
 389 
 390                 host1x_hw_syncpt_assign_to_channel(host, &syncpt[i], NULL);
 391         }
 392 
 393         for (i = 0; i < host->info->nb_bases; i++)
 394                 bases[i].id = i;
 395 
 396         mutex_init(&host->syncpt_mutex);
 397         host->syncpt = syncpt;
 398         host->bases = bases;
 399 
 400         host1x_syncpt_restore(host);
 401         host1x_hw_syncpt_enable_protection(host);
 402 
 403         
 404         host->nop_sp = host1x_syncpt_alloc(host, NULL, 0);
 405         if (!host->nop_sp)
 406                 return -ENOMEM;
 407 
 408         return 0;
 409 }
 410 
 411 
 412 
 413 
 414 
 415 
 416 
 417 
 418 
 419 
 420 
 421 struct host1x_syncpt *host1x_syncpt_request(struct host1x_client *client,
 422                                             unsigned long flags)
 423 {
 424         struct host1x *host = dev_get_drvdata(client->parent->parent);
 425 
 426         return host1x_syncpt_alloc(host, client, flags);
 427 }
 428 EXPORT_SYMBOL(host1x_syncpt_request);
 429 
 430 
 431 
 432 
 433 
 434 
 435 
 436 
 437 
 438 
 439 
 440 void host1x_syncpt_free(struct host1x_syncpt *sp)
 441 {
 442         if (!sp)
 443                 return;
 444 
 445         mutex_lock(&sp->host->syncpt_mutex);
 446 
 447         host1x_syncpt_base_free(sp->base);
 448         kfree(sp->name);
 449         sp->base = NULL;
 450         sp->client = NULL;
 451         sp->name = NULL;
 452         sp->client_managed = false;
 453 
 454         mutex_unlock(&sp->host->syncpt_mutex);
 455 }
 456 EXPORT_SYMBOL(host1x_syncpt_free);
 457 
 458 void host1x_syncpt_deinit(struct host1x *host)
 459 {
 460         struct host1x_syncpt *sp = host->syncpt;
 461         unsigned int i;
 462 
 463         for (i = 0; i < host->info->nb_pts; i++, sp++)
 464                 kfree(sp->name);
 465 }
 466 
 467 
 468 
 469 
 470 
 471 
 472 
 473 
 474 u32 host1x_syncpt_read_max(struct host1x_syncpt *sp)
 475 {
 476         smp_rmb();
 477 
 478         return (u32)atomic_read(&sp->max_val);
 479 }
 480 EXPORT_SYMBOL(host1x_syncpt_read_max);
 481 
 482 
 483 
 484 
 485 
 486 
 487 
 488 
 489 u32 host1x_syncpt_read_min(struct host1x_syncpt *sp)
 490 {
 491         smp_rmb();
 492 
 493         return (u32)atomic_read(&sp->min_val);
 494 }
 495 EXPORT_SYMBOL(host1x_syncpt_read_min);
 496 
 497 
 498 
 499 
 500 
 501 u32 host1x_syncpt_read(struct host1x_syncpt *sp)
 502 {
 503         return host1x_syncpt_load(sp);
 504 }
 505 EXPORT_SYMBOL(host1x_syncpt_read);
 506 
 507 unsigned int host1x_syncpt_nb_pts(struct host1x *host)
 508 {
 509         return host->info->nb_pts;
 510 }
 511 
 512 unsigned int host1x_syncpt_nb_bases(struct host1x *host)
 513 {
 514         return host->info->nb_bases;
 515 }
 516 
 517 unsigned int host1x_syncpt_nb_mlocks(struct host1x *host)
 518 {
 519         return host->info->nb_mlocks;
 520 }
 521 
 522 
 523 
 524 
 525 
 526 
 527 struct host1x_syncpt *host1x_syncpt_get(struct host1x *host, unsigned int id)
 528 {
 529         if (id >= host->info->nb_pts)
 530                 return NULL;
 531 
 532         return host->syncpt + id;
 533 }
 534 EXPORT_SYMBOL(host1x_syncpt_get);
 535 
 536 
 537 
 538 
 539 
 540 struct host1x_syncpt_base *host1x_syncpt_get_base(struct host1x_syncpt *sp)
 541 {
 542         return sp ? sp->base : NULL;
 543 }
 544 EXPORT_SYMBOL(host1x_syncpt_get_base);
 545 
 546 
 547 
 548 
 549 
 550 u32 host1x_syncpt_base_id(struct host1x_syncpt_base *base)
 551 {
 552         return base->id;
 553 }
 554 EXPORT_SYMBOL(host1x_syncpt_base_id);