linux/drivers/gpu/host1x/bus.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2012 Avionic Design GmbH
   3 * Copyright (C) 2012-2013, NVIDIA Corporation
   4 *
   5 * This program is free software; you can redistribute it and/or modify it
   6 * under the terms and conditions of the GNU General Public License,
   7 * version 2, as published by the Free Software Foundation.
   8 *
   9 * This program is distributed in the hope it will be useful, but WITHOUT
  10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  12 * more details.
  13 *
  14 * You should have received a copy of the GNU General Public License
  15 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  16 */
  17
  18#include <linux/host1x.h>
  19#include <linux/of.h>
  20#include <linux/slab.h>
  21#include <linux/of_device.h>
  22
  23#include "bus.h"
  24#include "dev.h"
  25
  26static DEFINE_MUTEX(clients_lock);
  27static LIST_HEAD(clients);
  28
  29static DEFINE_MUTEX(drivers_lock);
  30static LIST_HEAD(drivers);
  31
  32static DEFINE_MUTEX(devices_lock);
  33static LIST_HEAD(devices);
  34
  35struct host1x_subdev {
  36        struct host1x_client *client;
  37        struct device_node *np;
  38        struct list_head list;
  39};
  40
  41/**
  42 * host1x_subdev_add() - add a new subdevice with an associated device node
  43 */
  44static int host1x_subdev_add(struct host1x_device *device,
  45                             struct device_node *np)
  46{
  47        struct host1x_subdev *subdev;
  48
  49        subdev = kzalloc(sizeof(*subdev), GFP_KERNEL);
  50        if (!subdev)
  51                return -ENOMEM;
  52
  53        INIT_LIST_HEAD(&subdev->list);
  54        subdev->np = of_node_get(np);
  55
  56        mutex_lock(&device->subdevs_lock);
  57        list_add_tail(&subdev->list, &device->subdevs);
  58        mutex_unlock(&device->subdevs_lock);
  59
  60        return 0;
  61}
  62
  63/**
  64 * host1x_subdev_del() - remove subdevice
  65 */
  66static void host1x_subdev_del(struct host1x_subdev *subdev)
  67{
  68        list_del(&subdev->list);
  69        of_node_put(subdev->np);
  70        kfree(subdev);
  71}
  72
  73/**
  74 * host1x_device_parse_dt() - scan device tree and add matching subdevices
  75 */
  76static int host1x_device_parse_dt(struct host1x_device *device,
  77                                  struct host1x_driver *driver)
  78{
  79        struct device_node *np;
  80        int err;
  81
  82        for_each_child_of_node(device->dev.parent->of_node, np) {
  83                if (of_match_node(driver->subdevs, np) &&
  84                    of_device_is_available(np)) {
  85                        err = host1x_subdev_add(device, np);
  86                        if (err < 0) {
  87                                of_node_put(np);
  88                                return err;
  89                        }
  90                }
  91        }
  92
  93        return 0;
  94}
  95
  96static void host1x_subdev_register(struct host1x_device *device,
  97                                   struct host1x_subdev *subdev,
  98                                   struct host1x_client *client)
  99{
 100        int err;
 101
 102        /*
 103         * Move the subdevice to the list of active (registered) subdevices
 104         * and associate it with a client. At the same time, associate the
 105         * client with its parent device.
 106         */
 107        mutex_lock(&device->subdevs_lock);
 108        mutex_lock(&device->clients_lock);
 109        list_move_tail(&client->list, &device->clients);
 110        list_move_tail(&subdev->list, &device->active);
 111        client->parent = &device->dev;
 112        subdev->client = client;
 113        mutex_unlock(&device->clients_lock);
 114        mutex_unlock(&device->subdevs_lock);
 115
 116        if (list_empty(&device->subdevs)) {
 117                err = device_add(&device->dev);
 118                if (err < 0)
 119                        dev_err(&device->dev, "failed to add: %d\n", err);
 120                else
 121                        device->registered = true;
 122        }
 123}
 124
 125static void __host1x_subdev_unregister(struct host1x_device *device,
 126                                       struct host1x_subdev *subdev)
 127{
 128        struct host1x_client *client = subdev->client;
 129
 130        /*
 131         * If all subdevices have been activated, we're about to remove the
 132         * first active subdevice, so unload the driver first.
 133         */
 134        if (list_empty(&device->subdevs)) {
 135                if (device->registered) {
 136                        device->registered = false;
 137                        device_del(&device->dev);
 138                }
 139        }
 140
 141        /*
 142         * Move the subdevice back to the list of idle subdevices and remove
 143         * it from list of clients.
 144         */
 145        mutex_lock(&device->clients_lock);
 146        subdev->client = NULL;
 147        client->parent = NULL;
 148        list_move_tail(&subdev->list, &device->subdevs);
 149        /*
 150         * XXX: Perhaps don't do this here, but rather explicitly remove it
 151         * when the device is about to be deleted.
 152         *
 153         * This is somewhat complicated by the fact that this function is
 154         * used to remove the subdevice when a client is unregistered but
 155         * also when the composite device is about to be removed.
 156         */
 157        list_del_init(&client->list);
 158        mutex_unlock(&device->clients_lock);
 159}
 160
 161static void host1x_subdev_unregister(struct host1x_device *device,
 162                                     struct host1x_subdev *subdev)
 163{
 164        mutex_lock(&device->subdevs_lock);
 165        __host1x_subdev_unregister(device, subdev);
 166        mutex_unlock(&device->subdevs_lock);
 167}
 168
 169int host1x_device_init(struct host1x_device *device)
 170{
 171        struct host1x_client *client;
 172        int err;
 173
 174        mutex_lock(&device->clients_lock);
 175
 176        list_for_each_entry(client, &device->clients, list) {
 177                if (client->ops && client->ops->init) {
 178                        err = client->ops->init(client);
 179                        if (err < 0) {
 180                                dev_err(&device->dev,
 181                                        "failed to initialize %s: %d\n",
 182                                        dev_name(client->dev), err);
 183                                mutex_unlock(&device->clients_lock);
 184                                return err;
 185                        }
 186                }
 187        }
 188
 189        mutex_unlock(&device->clients_lock);
 190
 191        return 0;
 192}
 193EXPORT_SYMBOL(host1x_device_init);
 194
 195int host1x_device_exit(struct host1x_device *device)
 196{
 197        struct host1x_client *client;
 198        int err;
 199
 200        mutex_lock(&device->clients_lock);
 201
 202        list_for_each_entry_reverse(client, &device->clients, list) {
 203                if (client->ops && client->ops->exit) {
 204                        err = client->ops->exit(client);
 205                        if (err < 0) {
 206                                dev_err(&device->dev,
 207                                        "failed to cleanup %s: %d\n",
 208                                        dev_name(client->dev), err);
 209                                mutex_unlock(&device->clients_lock);
 210                                return err;
 211                        }
 212                }
 213        }
 214
 215        mutex_unlock(&device->clients_lock);
 216
 217        return 0;
 218}
 219EXPORT_SYMBOL(host1x_device_exit);
 220
 221static int host1x_add_client(struct host1x *host1x,
 222                             struct host1x_client *client)
 223{
 224        struct host1x_device *device;
 225        struct host1x_subdev *subdev;
 226
 227        mutex_lock(&host1x->devices_lock);
 228
 229        list_for_each_entry(device, &host1x->devices, list) {
 230                list_for_each_entry(subdev, &device->subdevs, list) {
 231                        if (subdev->np == client->dev->of_node) {
 232                                host1x_subdev_register(device, subdev, client);
 233                                mutex_unlock(&host1x->devices_lock);
 234                                return 0;
 235                        }
 236                }
 237        }
 238
 239        mutex_unlock(&host1x->devices_lock);
 240        return -ENODEV;
 241}
 242
 243static int host1x_del_client(struct host1x *host1x,
 244                             struct host1x_client *client)
 245{
 246        struct host1x_device *device, *dt;
 247        struct host1x_subdev *subdev;
 248
 249        mutex_lock(&host1x->devices_lock);
 250
 251        list_for_each_entry_safe(device, dt, &host1x->devices, list) {
 252                list_for_each_entry(subdev, &device->active, list) {
 253                        if (subdev->client == client) {
 254                                host1x_subdev_unregister(device, subdev);
 255                                mutex_unlock(&host1x->devices_lock);
 256                                return 0;
 257                        }
 258                }
 259        }
 260
 261        mutex_unlock(&host1x->devices_lock);
 262        return -ENODEV;
 263}
 264
 265static int host1x_device_match(struct device *dev, struct device_driver *drv)
 266{
 267        return strcmp(dev_name(dev), drv->name) == 0;
 268}
 269
 270static int host1x_device_probe(struct device *dev)
 271{
 272        struct host1x_driver *driver = to_host1x_driver(dev->driver);
 273        struct host1x_device *device = to_host1x_device(dev);
 274
 275        if (driver->probe)
 276                return driver->probe(device);
 277
 278        return 0;
 279}
 280
 281static int host1x_device_remove(struct device *dev)
 282{
 283        struct host1x_driver *driver = to_host1x_driver(dev->driver);
 284        struct host1x_device *device = to_host1x_device(dev);
 285
 286        if (driver->remove)
 287                return driver->remove(device);
 288
 289        return 0;
 290}
 291
 292static void host1x_device_shutdown(struct device *dev)
 293{
 294        struct host1x_driver *driver = to_host1x_driver(dev->driver);
 295        struct host1x_device *device = to_host1x_device(dev);
 296
 297        if (driver->shutdown)
 298                driver->shutdown(device);
 299}
 300
 301static const struct dev_pm_ops host1x_device_pm_ops = {
 302        .suspend = pm_generic_suspend,
 303        .resume = pm_generic_resume,
 304        .freeze = pm_generic_freeze,
 305        .thaw = pm_generic_thaw,
 306        .poweroff = pm_generic_poweroff,
 307        .restore = pm_generic_restore,
 308};
 309
 310struct bus_type host1x_bus_type = {
 311        .name = "host1x",
 312        .match = host1x_device_match,
 313        .probe = host1x_device_probe,
 314        .remove = host1x_device_remove,
 315        .shutdown = host1x_device_shutdown,
 316        .pm = &host1x_device_pm_ops,
 317};
 318
 319static void __host1x_device_del(struct host1x_device *device)
 320{
 321        struct host1x_subdev *subdev, *sd;
 322        struct host1x_client *client, *cl;
 323
 324        mutex_lock(&device->subdevs_lock);
 325
 326        /* unregister subdevices */
 327        list_for_each_entry_safe(subdev, sd, &device->active, list) {
 328                /*
 329                 * host1x_subdev_unregister() will remove the client from
 330                 * any lists, so we'll need to manually add it back to the
 331                 * list of idle clients.
 332                 *
 333                 * XXX: Alternatively, perhaps don't remove the client from
 334                 * any lists in host1x_subdev_unregister() and instead do
 335                 * that explicitly from host1x_unregister_client()?
 336                 */
 337                client = subdev->client;
 338
 339                __host1x_subdev_unregister(device, subdev);
 340
 341                /* add the client to the list of idle clients */
 342                mutex_lock(&clients_lock);
 343                list_add_tail(&client->list, &clients);
 344                mutex_unlock(&clients_lock);
 345        }
 346
 347        /* remove subdevices */
 348        list_for_each_entry_safe(subdev, sd, &device->subdevs, list)
 349                host1x_subdev_del(subdev);
 350
 351        mutex_unlock(&device->subdevs_lock);
 352
 353        /* move clients to idle list */
 354        mutex_lock(&clients_lock);
 355        mutex_lock(&device->clients_lock);
 356
 357        list_for_each_entry_safe(client, cl, &device->clients, list)
 358                list_move_tail(&client->list, &clients);
 359
 360        mutex_unlock(&device->clients_lock);
 361        mutex_unlock(&clients_lock);
 362
 363        /* finally remove the device */
 364        list_del_init(&device->list);
 365}
 366
 367static void host1x_device_release(struct device *dev)
 368{
 369        struct host1x_device *device = to_host1x_device(dev);
 370
 371        __host1x_device_del(device);
 372        kfree(device);
 373}
 374
 375static int host1x_device_add(struct host1x *host1x,
 376                             struct host1x_driver *driver)
 377{
 378        struct host1x_client *client, *tmp;
 379        struct host1x_subdev *subdev;
 380        struct host1x_device *device;
 381        int err;
 382
 383        device = kzalloc(sizeof(*device), GFP_KERNEL);
 384        if (!device)
 385                return -ENOMEM;
 386
 387        device_initialize(&device->dev);
 388
 389        mutex_init(&device->subdevs_lock);
 390        INIT_LIST_HEAD(&device->subdevs);
 391        INIT_LIST_HEAD(&device->active);
 392        mutex_init(&device->clients_lock);
 393        INIT_LIST_HEAD(&device->clients);
 394        INIT_LIST_HEAD(&device->list);
 395        device->driver = driver;
 396
 397        device->dev.coherent_dma_mask = host1x->dev->coherent_dma_mask;
 398        device->dev.dma_mask = &device->dev.coherent_dma_mask;
 399        dev_set_name(&device->dev, "%s", driver->driver.name);
 400        of_dma_configure(&device->dev, host1x->dev->of_node);
 401        device->dev.release = host1x_device_release;
 402        device->dev.bus = &host1x_bus_type;
 403        device->dev.parent = host1x->dev;
 404
 405        err = host1x_device_parse_dt(device, driver);
 406        if (err < 0) {
 407                kfree(device);
 408                return err;
 409        }
 410
 411        list_add_tail(&device->list, &host1x->devices);
 412
 413        mutex_lock(&clients_lock);
 414
 415        list_for_each_entry_safe(client, tmp, &clients, list) {
 416                list_for_each_entry(subdev, &device->subdevs, list) {
 417                        if (subdev->np == client->dev->of_node) {
 418                                host1x_subdev_register(device, subdev, client);
 419                                break;
 420                        }
 421                }
 422        }
 423
 424        mutex_unlock(&clients_lock);
 425
 426        return 0;
 427}
 428
 429/*
 430 * Removes a device by first unregistering any subdevices and then removing
 431 * itself from the list of devices.
 432 *
 433 * This function must be called with the host1x->devices_lock held.
 434 */
 435static void host1x_device_del(struct host1x *host1x,
 436                              struct host1x_device *device)
 437{
 438        if (device->registered) {
 439                device->registered = false;
 440                device_del(&device->dev);
 441        }
 442
 443        put_device(&device->dev);
 444}
 445
 446static void host1x_attach_driver(struct host1x *host1x,
 447                                 struct host1x_driver *driver)
 448{
 449        struct host1x_device *device;
 450        int err;
 451
 452        mutex_lock(&host1x->devices_lock);
 453
 454        list_for_each_entry(device, &host1x->devices, list) {
 455                if (device->driver == driver) {
 456                        mutex_unlock(&host1x->devices_lock);
 457                        return;
 458                }
 459        }
 460
 461        err = host1x_device_add(host1x, driver);
 462        if (err < 0)
 463                dev_err(host1x->dev, "failed to allocate device: %d\n", err);
 464
 465        mutex_unlock(&host1x->devices_lock);
 466}
 467
 468static void host1x_detach_driver(struct host1x *host1x,
 469                                 struct host1x_driver *driver)
 470{
 471        struct host1x_device *device, *tmp;
 472
 473        mutex_lock(&host1x->devices_lock);
 474
 475        list_for_each_entry_safe(device, tmp, &host1x->devices, list)
 476                if (device->driver == driver)
 477                        host1x_device_del(host1x, device);
 478
 479        mutex_unlock(&host1x->devices_lock);
 480}
 481
 482int host1x_register(struct host1x *host1x)
 483{
 484        struct host1x_driver *driver;
 485
 486        mutex_lock(&devices_lock);
 487        list_add_tail(&host1x->list, &devices);
 488        mutex_unlock(&devices_lock);
 489
 490        mutex_lock(&drivers_lock);
 491
 492        list_for_each_entry(driver, &drivers, list)
 493                host1x_attach_driver(host1x, driver);
 494
 495        mutex_unlock(&drivers_lock);
 496
 497        return 0;
 498}
 499
 500int host1x_unregister(struct host1x *host1x)
 501{
 502        struct host1x_driver *driver;
 503
 504        mutex_lock(&drivers_lock);
 505
 506        list_for_each_entry(driver, &drivers, list)
 507                host1x_detach_driver(host1x, driver);
 508
 509        mutex_unlock(&drivers_lock);
 510
 511        mutex_lock(&devices_lock);
 512        list_del_init(&host1x->list);
 513        mutex_unlock(&devices_lock);
 514
 515        return 0;
 516}
 517
 518int host1x_driver_register_full(struct host1x_driver *driver,
 519                                struct module *owner)
 520{
 521        struct host1x *host1x;
 522
 523        INIT_LIST_HEAD(&driver->list);
 524
 525        mutex_lock(&drivers_lock);
 526        list_add_tail(&driver->list, &drivers);
 527        mutex_unlock(&drivers_lock);
 528
 529        mutex_lock(&devices_lock);
 530
 531        list_for_each_entry(host1x, &devices, list)
 532                host1x_attach_driver(host1x, driver);
 533
 534        mutex_unlock(&devices_lock);
 535
 536        driver->driver.bus = &host1x_bus_type;
 537        driver->driver.owner = owner;
 538
 539        return driver_register(&driver->driver);
 540}
 541EXPORT_SYMBOL(host1x_driver_register_full);
 542
 543void host1x_driver_unregister(struct host1x_driver *driver)
 544{
 545        driver_unregister(&driver->driver);
 546
 547        mutex_lock(&drivers_lock);
 548        list_del_init(&driver->list);
 549        mutex_unlock(&drivers_lock);
 550}
 551EXPORT_SYMBOL(host1x_driver_unregister);
 552
 553int host1x_client_register(struct host1x_client *client)
 554{
 555        struct host1x *host1x;
 556        int err;
 557
 558        mutex_lock(&devices_lock);
 559
 560        list_for_each_entry(host1x, &devices, list) {
 561                err = host1x_add_client(host1x, client);
 562                if (!err) {
 563                        mutex_unlock(&devices_lock);
 564                        return 0;
 565                }
 566        }
 567
 568        mutex_unlock(&devices_lock);
 569
 570        mutex_lock(&clients_lock);
 571        list_add_tail(&client->list, &clients);
 572        mutex_unlock(&clients_lock);
 573
 574        return 0;
 575}
 576EXPORT_SYMBOL(host1x_client_register);
 577
 578int host1x_client_unregister(struct host1x_client *client)
 579{
 580        struct host1x_client *c;
 581        struct host1x *host1x;
 582        int err;
 583
 584        mutex_lock(&devices_lock);
 585
 586        list_for_each_entry(host1x, &devices, list) {
 587                err = host1x_del_client(host1x, client);
 588                if (!err) {
 589                        mutex_unlock(&devices_lock);
 590                        return 0;
 591                }
 592        }
 593
 594        mutex_unlock(&devices_lock);
 595        mutex_lock(&clients_lock);
 596
 597        list_for_each_entry(c, &clients, list) {
 598                if (c == client) {
 599                        list_del_init(&c->list);
 600                        break;
 601                }
 602        }
 603
 604        mutex_unlock(&clients_lock);
 605
 606        return 0;
 607}
 608EXPORT_SYMBOL(host1x_client_unregister);
 609