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