linux/drivers/iommu/fsl_pamu_domain.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 *
   4 * Copyright (C) 2013 Freescale Semiconductor, Inc.
   5 * Author: Varun Sethi <varun.sethi@freescale.com>
   6 */
   7
   8#define pr_fmt(fmt)    "fsl-pamu-domain: %s: " fmt, __func__
   9
  10#include "fsl_pamu_domain.h"
  11
  12#include <sysdev/fsl_pci.h>
  13
  14/*
  15 * Global spinlock that needs to be held while
  16 * configuring PAMU.
  17 */
  18static DEFINE_SPINLOCK(iommu_lock);
  19
  20static struct kmem_cache *fsl_pamu_domain_cache;
  21static struct kmem_cache *iommu_devinfo_cache;
  22static DEFINE_SPINLOCK(device_domain_lock);
  23
  24struct iommu_device pamu_iommu; /* IOMMU core code handle */
  25
  26static struct fsl_dma_domain *to_fsl_dma_domain(struct iommu_domain *dom)
  27{
  28        return container_of(dom, struct fsl_dma_domain, iommu_domain);
  29}
  30
  31static int __init iommu_init_mempool(void)
  32{
  33        fsl_pamu_domain_cache = kmem_cache_create("fsl_pamu_domain",
  34                                                  sizeof(struct fsl_dma_domain),
  35                                                  0,
  36                                                  SLAB_HWCACHE_ALIGN,
  37                                                  NULL);
  38        if (!fsl_pamu_domain_cache) {
  39                pr_debug("Couldn't create fsl iommu_domain cache\n");
  40                return -ENOMEM;
  41        }
  42
  43        iommu_devinfo_cache = kmem_cache_create("iommu_devinfo",
  44                                                sizeof(struct device_domain_info),
  45                                                0,
  46                                                SLAB_HWCACHE_ALIGN,
  47                                                NULL);
  48        if (!iommu_devinfo_cache) {
  49                pr_debug("Couldn't create devinfo cache\n");
  50                kmem_cache_destroy(fsl_pamu_domain_cache);
  51                return -ENOMEM;
  52        }
  53
  54        return 0;
  55}
  56
  57static phys_addr_t get_phys_addr(struct fsl_dma_domain *dma_domain, dma_addr_t iova)
  58{
  59        u32 win_cnt = dma_domain->win_cnt;
  60        struct dma_window *win_ptr = &dma_domain->win_arr[0];
  61        struct iommu_domain_geometry *geom;
  62
  63        geom = &dma_domain->iommu_domain.geometry;
  64
  65        if (!win_cnt || !dma_domain->geom_size) {
  66                pr_debug("Number of windows/geometry not configured for the domain\n");
  67                return 0;
  68        }
  69
  70        if (win_cnt > 1) {
  71                u64 subwin_size;
  72                dma_addr_t subwin_iova;
  73                u32 wnd;
  74
  75                subwin_size = dma_domain->geom_size >> ilog2(win_cnt);
  76                subwin_iova = iova & ~(subwin_size - 1);
  77                wnd = (subwin_iova - geom->aperture_start) >> ilog2(subwin_size);
  78                win_ptr = &dma_domain->win_arr[wnd];
  79        }
  80
  81        if (win_ptr->valid)
  82                return win_ptr->paddr + (iova & (win_ptr->size - 1));
  83
  84        return 0;
  85}
  86
  87static int map_subwins(int liodn, struct fsl_dma_domain *dma_domain)
  88{
  89        struct dma_window *sub_win_ptr = &dma_domain->win_arr[0];
  90        int i, ret;
  91        unsigned long rpn, flags;
  92
  93        for (i = 0; i < dma_domain->win_cnt; i++) {
  94                if (sub_win_ptr[i].valid) {
  95                        rpn = sub_win_ptr[i].paddr >> PAMU_PAGE_SHIFT;
  96                        spin_lock_irqsave(&iommu_lock, flags);
  97                        ret = pamu_config_spaace(liodn, dma_domain->win_cnt, i,
  98                                                 sub_win_ptr[i].size,
  99                                                 ~(u32)0,
 100                                                 rpn,
 101                                                 dma_domain->snoop_id,
 102                                                 dma_domain->stash_id,
 103                                                 (i > 0) ? 1 : 0,
 104                                                 sub_win_ptr[i].prot);
 105                        spin_unlock_irqrestore(&iommu_lock, flags);
 106                        if (ret) {
 107                                pr_debug("SPAACE configuration failed for liodn %d\n",
 108                                         liodn);
 109                                return ret;
 110                        }
 111                }
 112        }
 113
 114        return ret;
 115}
 116
 117static int map_win(int liodn, struct fsl_dma_domain *dma_domain)
 118{
 119        int ret;
 120        struct dma_window *wnd = &dma_domain->win_arr[0];
 121        phys_addr_t wnd_addr = dma_domain->iommu_domain.geometry.aperture_start;
 122        unsigned long flags;
 123
 124        spin_lock_irqsave(&iommu_lock, flags);
 125        ret = pamu_config_ppaace(liodn, wnd_addr,
 126                                 wnd->size,
 127                                 ~(u32)0,
 128                                 wnd->paddr >> PAMU_PAGE_SHIFT,
 129                                 dma_domain->snoop_id, dma_domain->stash_id,
 130                                 0, wnd->prot);
 131        spin_unlock_irqrestore(&iommu_lock, flags);
 132        if (ret)
 133                pr_debug("PAACE configuration failed for liodn %d\n", liodn);
 134
 135        return ret;
 136}
 137
 138/* Map the DMA window corresponding to the LIODN */
 139static int map_liodn(int liodn, struct fsl_dma_domain *dma_domain)
 140{
 141        if (dma_domain->win_cnt > 1)
 142                return map_subwins(liodn, dma_domain);
 143        else
 144                return map_win(liodn, dma_domain);
 145}
 146
 147/* Update window/subwindow mapping for the LIODN */
 148static int update_liodn(int liodn, struct fsl_dma_domain *dma_domain, u32 wnd_nr)
 149{
 150        int ret;
 151        struct dma_window *wnd = &dma_domain->win_arr[wnd_nr];
 152        unsigned long flags;
 153
 154        spin_lock_irqsave(&iommu_lock, flags);
 155        if (dma_domain->win_cnt > 1) {
 156                ret = pamu_config_spaace(liodn, dma_domain->win_cnt, wnd_nr,
 157                                         wnd->size,
 158                                         ~(u32)0,
 159                                         wnd->paddr >> PAMU_PAGE_SHIFT,
 160                                         dma_domain->snoop_id,
 161                                         dma_domain->stash_id,
 162                                         (wnd_nr > 0) ? 1 : 0,
 163                                         wnd->prot);
 164                if (ret)
 165                        pr_debug("Subwindow reconfiguration failed for liodn %d\n",
 166                                 liodn);
 167        } else {
 168                phys_addr_t wnd_addr;
 169
 170                wnd_addr = dma_domain->iommu_domain.geometry.aperture_start;
 171
 172                ret = pamu_config_ppaace(liodn, wnd_addr,
 173                                         wnd->size,
 174                                         ~(u32)0,
 175                                         wnd->paddr >> PAMU_PAGE_SHIFT,
 176                                         dma_domain->snoop_id, dma_domain->stash_id,
 177                                         0, wnd->prot);
 178                if (ret)
 179                        pr_debug("Window reconfiguration failed for liodn %d\n",
 180                                 liodn);
 181        }
 182
 183        spin_unlock_irqrestore(&iommu_lock, flags);
 184
 185        return ret;
 186}
 187
 188static int update_liodn_stash(int liodn, struct fsl_dma_domain *dma_domain,
 189                              u32 val)
 190{
 191        int ret = 0, i;
 192        unsigned long flags;
 193
 194        spin_lock_irqsave(&iommu_lock, flags);
 195        if (!dma_domain->win_arr) {
 196                pr_debug("Windows not configured, stash destination update failed for liodn %d\n",
 197                         liodn);
 198                spin_unlock_irqrestore(&iommu_lock, flags);
 199                return -EINVAL;
 200        }
 201
 202        for (i = 0; i < dma_domain->win_cnt; i++) {
 203                ret = pamu_update_paace_stash(liodn, i, val);
 204                if (ret) {
 205                        pr_debug("Failed to update SPAACE %d field for liodn %d\n ",
 206                                 i, liodn);
 207                        spin_unlock_irqrestore(&iommu_lock, flags);
 208                        return ret;
 209                }
 210        }
 211
 212        spin_unlock_irqrestore(&iommu_lock, flags);
 213
 214        return ret;
 215}
 216
 217/* Set the geometry parameters for a LIODN */
 218static int pamu_set_liodn(int liodn, struct device *dev,
 219                          struct fsl_dma_domain *dma_domain,
 220                          struct iommu_domain_geometry *geom_attr,
 221                          u32 win_cnt)
 222{
 223        phys_addr_t window_addr, window_size;
 224        phys_addr_t subwin_size;
 225        int ret = 0, i;
 226        u32 omi_index = ~(u32)0;
 227        unsigned long flags;
 228
 229        /*
 230         * Configure the omi_index at the geometry setup time.
 231         * This is a static value which depends on the type of
 232         * device and would not change thereafter.
 233         */
 234        get_ome_index(&omi_index, dev);
 235
 236        window_addr = geom_attr->aperture_start;
 237        window_size = dma_domain->geom_size;
 238
 239        spin_lock_irqsave(&iommu_lock, flags);
 240        ret = pamu_disable_liodn(liodn);
 241        if (!ret)
 242                ret = pamu_config_ppaace(liodn, window_addr, window_size, omi_index,
 243                                         0, dma_domain->snoop_id,
 244                                         dma_domain->stash_id, win_cnt, 0);
 245        spin_unlock_irqrestore(&iommu_lock, flags);
 246        if (ret) {
 247                pr_debug("PAACE configuration failed for liodn %d, win_cnt =%d\n",
 248                         liodn, win_cnt);
 249                return ret;
 250        }
 251
 252        if (win_cnt > 1) {
 253                subwin_size = window_size >> ilog2(win_cnt);
 254                for (i = 0; i < win_cnt; i++) {
 255                        spin_lock_irqsave(&iommu_lock, flags);
 256                        ret = pamu_disable_spaace(liodn, i);
 257                        if (!ret)
 258                                ret = pamu_config_spaace(liodn, win_cnt, i,
 259                                                         subwin_size, omi_index,
 260                                                         0, dma_domain->snoop_id,
 261                                                         dma_domain->stash_id,
 262                                                         0, 0);
 263                        spin_unlock_irqrestore(&iommu_lock, flags);
 264                        if (ret) {
 265                                pr_debug("SPAACE configuration failed for liodn %d\n",
 266                                         liodn);
 267                                return ret;
 268                        }
 269                }
 270        }
 271
 272        return ret;
 273}
 274
 275static int check_size(u64 size, dma_addr_t iova)
 276{
 277        /*
 278         * Size must be a power of two and at least be equal
 279         * to PAMU page size.
 280         */
 281        if ((size & (size - 1)) || size < PAMU_PAGE_SIZE) {
 282                pr_debug("Size too small or not a power of two\n");
 283                return -EINVAL;
 284        }
 285
 286        /* iova must be page size aligned */
 287        if (iova & (size - 1)) {
 288                pr_debug("Address is not aligned with window size\n");
 289                return -EINVAL;
 290        }
 291
 292        return 0;
 293}
 294
 295static struct fsl_dma_domain *iommu_alloc_dma_domain(void)
 296{
 297        struct fsl_dma_domain *domain;
 298
 299        domain = kmem_cache_zalloc(fsl_pamu_domain_cache, GFP_KERNEL);
 300        if (!domain)
 301                return NULL;
 302
 303        domain->stash_id = ~(u32)0;
 304        domain->snoop_id = ~(u32)0;
 305        domain->win_cnt = pamu_get_max_subwin_cnt();
 306        domain->geom_size = 0;
 307
 308        INIT_LIST_HEAD(&domain->devices);
 309
 310        spin_lock_init(&domain->domain_lock);
 311
 312        return domain;
 313}
 314
 315static void remove_device_ref(struct device_domain_info *info, u32 win_cnt)
 316{
 317        unsigned long flags;
 318
 319        list_del(&info->link);
 320        spin_lock_irqsave(&iommu_lock, flags);
 321        if (win_cnt > 1)
 322                pamu_free_subwins(info->liodn);
 323        pamu_disable_liodn(info->liodn);
 324        spin_unlock_irqrestore(&iommu_lock, flags);
 325        spin_lock_irqsave(&device_domain_lock, flags);
 326        dev_iommu_priv_set(info->dev, NULL);
 327        kmem_cache_free(iommu_devinfo_cache, info);
 328        spin_unlock_irqrestore(&device_domain_lock, flags);
 329}
 330
 331static void detach_device(struct device *dev, struct fsl_dma_domain *dma_domain)
 332{
 333        struct device_domain_info *info, *tmp;
 334        unsigned long flags;
 335
 336        spin_lock_irqsave(&dma_domain->domain_lock, flags);
 337        /* Remove the device from the domain device list */
 338        list_for_each_entry_safe(info, tmp, &dma_domain->devices, link) {
 339                if (!dev || (info->dev == dev))
 340                        remove_device_ref(info, dma_domain->win_cnt);
 341        }
 342        spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
 343}
 344
 345static void attach_device(struct fsl_dma_domain *dma_domain, int liodn, struct device *dev)
 346{
 347        struct device_domain_info *info, *old_domain_info;
 348        unsigned long flags;
 349
 350        spin_lock_irqsave(&device_domain_lock, flags);
 351        /*
 352         * Check here if the device is already attached to domain or not.
 353         * If the device is already attached to a domain detach it.
 354         */
 355        old_domain_info = dev_iommu_priv_get(dev);
 356        if (old_domain_info && old_domain_info->domain != dma_domain) {
 357                spin_unlock_irqrestore(&device_domain_lock, flags);
 358                detach_device(dev, old_domain_info->domain);
 359                spin_lock_irqsave(&device_domain_lock, flags);
 360        }
 361
 362        info = kmem_cache_zalloc(iommu_devinfo_cache, GFP_ATOMIC);
 363
 364        info->dev = dev;
 365        info->liodn = liodn;
 366        info->domain = dma_domain;
 367
 368        list_add(&info->link, &dma_domain->devices);
 369        /*
 370         * In case of devices with multiple LIODNs just store
 371         * the info for the first LIODN as all
 372         * LIODNs share the same domain
 373         */
 374        if (!dev_iommu_priv_get(dev))
 375                dev_iommu_priv_set(dev, info);
 376        spin_unlock_irqrestore(&device_domain_lock, flags);
 377}
 378
 379static phys_addr_t fsl_pamu_iova_to_phys(struct iommu_domain *domain,
 380                                         dma_addr_t iova)
 381{
 382        struct fsl_dma_domain *dma_domain = to_fsl_dma_domain(domain);
 383
 384        if (iova < domain->geometry.aperture_start ||
 385            iova > domain->geometry.aperture_end)
 386                return 0;
 387
 388        return get_phys_addr(dma_domain, iova);
 389}
 390
 391static bool fsl_pamu_capable(enum iommu_cap cap)
 392{
 393        return cap == IOMMU_CAP_CACHE_COHERENCY;
 394}
 395
 396static void fsl_pamu_domain_free(struct iommu_domain *domain)
 397{
 398        struct fsl_dma_domain *dma_domain = to_fsl_dma_domain(domain);
 399
 400        /* remove all the devices from the device list */
 401        detach_device(NULL, dma_domain);
 402
 403        dma_domain->enabled = 0;
 404        dma_domain->mapped = 0;
 405
 406        kmem_cache_free(fsl_pamu_domain_cache, dma_domain);
 407}
 408
 409static struct iommu_domain *fsl_pamu_domain_alloc(unsigned type)
 410{
 411        struct fsl_dma_domain *dma_domain;
 412
 413        if (type != IOMMU_DOMAIN_UNMANAGED)
 414                return NULL;
 415
 416        dma_domain = iommu_alloc_dma_domain();
 417        if (!dma_domain) {
 418                pr_debug("dma_domain allocation failed\n");
 419                return NULL;
 420        }
 421        /* defaul geometry 64 GB i.e. maximum system address */
 422        dma_domain->iommu_domain. geometry.aperture_start = 0;
 423        dma_domain->iommu_domain.geometry.aperture_end = (1ULL << 36) - 1;
 424        dma_domain->iommu_domain.geometry.force_aperture = true;
 425
 426        return &dma_domain->iommu_domain;
 427}
 428
 429/* Configure geometry settings for all LIODNs associated with domain */
 430static int pamu_set_domain_geometry(struct fsl_dma_domain *dma_domain,
 431                                    struct iommu_domain_geometry *geom_attr,
 432                                    u32 win_cnt)
 433{
 434        struct device_domain_info *info;
 435        int ret = 0;
 436
 437        list_for_each_entry(info, &dma_domain->devices, link) {
 438                ret = pamu_set_liodn(info->liodn, info->dev, dma_domain,
 439                                     geom_attr, win_cnt);
 440                if (ret)
 441                        break;
 442        }
 443
 444        return ret;
 445}
 446
 447/* Update stash destination for all LIODNs associated with the domain */
 448static int update_domain_stash(struct fsl_dma_domain *dma_domain, u32 val)
 449{
 450        struct device_domain_info *info;
 451        int ret = 0;
 452
 453        list_for_each_entry(info, &dma_domain->devices, link) {
 454                ret = update_liodn_stash(info->liodn, dma_domain, val);
 455                if (ret)
 456                        break;
 457        }
 458
 459        return ret;
 460}
 461
 462/* Update domain mappings for all LIODNs associated with the domain */
 463static int update_domain_mapping(struct fsl_dma_domain *dma_domain, u32 wnd_nr)
 464{
 465        struct device_domain_info *info;
 466        int ret = 0;
 467
 468        list_for_each_entry(info, &dma_domain->devices, link) {
 469                ret = update_liodn(info->liodn, dma_domain, wnd_nr);
 470                if (ret)
 471                        break;
 472        }
 473        return ret;
 474}
 475
 476static int disable_domain_win(struct fsl_dma_domain *dma_domain, u32 wnd_nr)
 477{
 478        struct device_domain_info *info;
 479        int ret = 0;
 480
 481        list_for_each_entry(info, &dma_domain->devices, link) {
 482                if (dma_domain->win_cnt == 1 && dma_domain->enabled) {
 483                        ret = pamu_disable_liodn(info->liodn);
 484                        if (!ret)
 485                                dma_domain->enabled = 0;
 486                } else {
 487                        ret = pamu_disable_spaace(info->liodn, wnd_nr);
 488                }
 489        }
 490
 491        return ret;
 492}
 493
 494static void fsl_pamu_window_disable(struct iommu_domain *domain, u32 wnd_nr)
 495{
 496        struct fsl_dma_domain *dma_domain = to_fsl_dma_domain(domain);
 497        unsigned long flags;
 498        int ret;
 499
 500        spin_lock_irqsave(&dma_domain->domain_lock, flags);
 501        if (!dma_domain->win_arr) {
 502                pr_debug("Number of windows not configured\n");
 503                spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
 504                return;
 505        }
 506
 507        if (wnd_nr >= dma_domain->win_cnt) {
 508                pr_debug("Invalid window index\n");
 509                spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
 510                return;
 511        }
 512
 513        if (dma_domain->win_arr[wnd_nr].valid) {
 514                ret = disable_domain_win(dma_domain, wnd_nr);
 515                if (!ret) {
 516                        dma_domain->win_arr[wnd_nr].valid = 0;
 517                        dma_domain->mapped--;
 518                }
 519        }
 520
 521        spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
 522}
 523
 524static int fsl_pamu_window_enable(struct iommu_domain *domain, u32 wnd_nr,
 525                                  phys_addr_t paddr, u64 size, int prot)
 526{
 527        struct fsl_dma_domain *dma_domain = to_fsl_dma_domain(domain);
 528        struct dma_window *wnd;
 529        int pamu_prot = 0;
 530        int ret;
 531        unsigned long flags;
 532        u64 win_size;
 533
 534        if (prot & IOMMU_READ)
 535                pamu_prot |= PAACE_AP_PERMS_QUERY;
 536        if (prot & IOMMU_WRITE)
 537                pamu_prot |= PAACE_AP_PERMS_UPDATE;
 538
 539        spin_lock_irqsave(&dma_domain->domain_lock, flags);
 540        if (!dma_domain->win_arr) {
 541                pr_debug("Number of windows not configured\n");
 542                spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
 543                return -ENODEV;
 544        }
 545
 546        if (wnd_nr >= dma_domain->win_cnt) {
 547                pr_debug("Invalid window index\n");
 548                spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
 549                return -EINVAL;
 550        }
 551
 552        win_size = dma_domain->geom_size >> ilog2(dma_domain->win_cnt);
 553        if (size > win_size) {
 554                pr_debug("Invalid window size\n");
 555                spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
 556                return -EINVAL;
 557        }
 558
 559        if (dma_domain->win_cnt == 1) {
 560                if (dma_domain->enabled) {
 561                        pr_debug("Disable the window before updating the mapping\n");
 562                        spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
 563                        return -EBUSY;
 564                }
 565
 566                ret = check_size(size, domain->geometry.aperture_start);
 567                if (ret) {
 568                        pr_debug("Aperture start not aligned to the size\n");
 569                        spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
 570                        return -EINVAL;
 571                }
 572        }
 573
 574        wnd = &dma_domain->win_arr[wnd_nr];
 575        if (!wnd->valid) {
 576                wnd->paddr = paddr;
 577                wnd->size = size;
 578                wnd->prot = pamu_prot;
 579
 580                ret = update_domain_mapping(dma_domain, wnd_nr);
 581                if (!ret) {
 582                        wnd->valid = 1;
 583                        dma_domain->mapped++;
 584                }
 585        } else {
 586                pr_debug("Disable the window before updating the mapping\n");
 587                ret = -EBUSY;
 588        }
 589
 590        spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
 591
 592        return ret;
 593}
 594
 595/*
 596 * Attach the LIODN to the DMA domain and configure the geometry
 597 * and window mappings.
 598 */
 599static int handle_attach_device(struct fsl_dma_domain *dma_domain,
 600                                struct device *dev, const u32 *liodn,
 601                                int num)
 602{
 603        unsigned long flags;
 604        struct iommu_domain *domain = &dma_domain->iommu_domain;
 605        int ret = 0;
 606        int i;
 607
 608        spin_lock_irqsave(&dma_domain->domain_lock, flags);
 609        for (i = 0; i < num; i++) {
 610                /* Ensure that LIODN value is valid */
 611                if (liodn[i] >= PAACE_NUMBER_ENTRIES) {
 612                        pr_debug("Invalid liodn %d, attach device failed for %pOF\n",
 613                                 liodn[i], dev->of_node);
 614                        ret = -EINVAL;
 615                        break;
 616                }
 617
 618                attach_device(dma_domain, liodn[i], dev);
 619                /*
 620                 * Check if geometry has already been configured
 621                 * for the domain. If yes, set the geometry for
 622                 * the LIODN.
 623                 */
 624                if (dma_domain->win_arr) {
 625                        u32 win_cnt = dma_domain->win_cnt > 1 ? dma_domain->win_cnt : 0;
 626
 627                        ret = pamu_set_liodn(liodn[i], dev, dma_domain,
 628                                             &domain->geometry, win_cnt);
 629                        if (ret)
 630                                break;
 631                        if (dma_domain->mapped) {
 632                                /*
 633                                 * Create window/subwindow mapping for
 634                                 * the LIODN.
 635                                 */
 636                                ret = map_liodn(liodn[i], dma_domain);
 637                                if (ret)
 638                                        break;
 639                        }
 640                }
 641        }
 642        spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
 643
 644        return ret;
 645}
 646
 647static int fsl_pamu_attach_device(struct iommu_domain *domain,
 648                                  struct device *dev)
 649{
 650        struct fsl_dma_domain *dma_domain = to_fsl_dma_domain(domain);
 651        const u32 *liodn;
 652        u32 liodn_cnt;
 653        int len, ret = 0;
 654        struct pci_dev *pdev = NULL;
 655        struct pci_controller *pci_ctl;
 656
 657        /*
 658         * Use LIODN of the PCI controller while attaching a
 659         * PCI device.
 660         */
 661        if (dev_is_pci(dev)) {
 662                pdev = to_pci_dev(dev);
 663                pci_ctl = pci_bus_to_host(pdev->bus);
 664                /*
 665                 * make dev point to pci controller device
 666                 * so we can get the LIODN programmed by
 667                 * u-boot.
 668                 */
 669                dev = pci_ctl->parent;
 670        }
 671
 672        liodn = of_get_property(dev->of_node, "fsl,liodn", &len);
 673        if (liodn) {
 674                liodn_cnt = len / sizeof(u32);
 675                ret = handle_attach_device(dma_domain, dev, liodn, liodn_cnt);
 676        } else {
 677                pr_debug("missing fsl,liodn property at %pOF\n", dev->of_node);
 678                ret = -EINVAL;
 679        }
 680
 681        return ret;
 682}
 683
 684static void fsl_pamu_detach_device(struct iommu_domain *domain,
 685                                   struct device *dev)
 686{
 687        struct fsl_dma_domain *dma_domain = to_fsl_dma_domain(domain);
 688        const u32 *prop;
 689        int len;
 690        struct pci_dev *pdev = NULL;
 691        struct pci_controller *pci_ctl;
 692
 693        /*
 694         * Use LIODN of the PCI controller while detaching a
 695         * PCI device.
 696         */
 697        if (dev_is_pci(dev)) {
 698                pdev = to_pci_dev(dev);
 699                pci_ctl = pci_bus_to_host(pdev->bus);
 700                /*
 701                 * make dev point to pci controller device
 702                 * so we can get the LIODN programmed by
 703                 * u-boot.
 704                 */
 705                dev = pci_ctl->parent;
 706        }
 707
 708        prop = of_get_property(dev->of_node, "fsl,liodn", &len);
 709        if (prop)
 710                detach_device(dev, dma_domain);
 711        else
 712                pr_debug("missing fsl,liodn property at %pOF\n", dev->of_node);
 713}
 714
 715static  int configure_domain_geometry(struct iommu_domain *domain, void *data)
 716{
 717        struct iommu_domain_geometry *geom_attr = data;
 718        struct fsl_dma_domain *dma_domain = to_fsl_dma_domain(domain);
 719        dma_addr_t geom_size;
 720        unsigned long flags;
 721
 722        geom_size = geom_attr->aperture_end - geom_attr->aperture_start + 1;
 723        /*
 724         * Sanity check the geometry size. Also, we do not support
 725         * DMA outside of the geometry.
 726         */
 727        if (check_size(geom_size, geom_attr->aperture_start) ||
 728            !geom_attr->force_aperture) {
 729                pr_debug("Invalid PAMU geometry attributes\n");
 730                return -EINVAL;
 731        }
 732
 733        spin_lock_irqsave(&dma_domain->domain_lock, flags);
 734        if (dma_domain->enabled) {
 735                pr_debug("Can't set geometry attributes as domain is active\n");
 736                spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
 737                return  -EBUSY;
 738        }
 739
 740        /* Copy the domain geometry information */
 741        memcpy(&domain->geometry, geom_attr,
 742               sizeof(struct iommu_domain_geometry));
 743        dma_domain->geom_size = geom_size;
 744
 745        spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
 746
 747        return 0;
 748}
 749
 750/* Set the domain stash attribute */
 751static int configure_domain_stash(struct fsl_dma_domain *dma_domain, void *data)
 752{
 753        struct pamu_stash_attribute *stash_attr = data;
 754        unsigned long flags;
 755        int ret;
 756
 757        spin_lock_irqsave(&dma_domain->domain_lock, flags);
 758
 759        memcpy(&dma_domain->dma_stash, stash_attr,
 760               sizeof(struct pamu_stash_attribute));
 761
 762        dma_domain->stash_id = get_stash_id(stash_attr->cache,
 763                                            stash_attr->cpu);
 764        if (dma_domain->stash_id == ~(u32)0) {
 765                pr_debug("Invalid stash attributes\n");
 766                spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
 767                return -EINVAL;
 768        }
 769
 770        ret = update_domain_stash(dma_domain, dma_domain->stash_id);
 771
 772        spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
 773
 774        return ret;
 775}
 776
 777/* Configure domain dma state i.e. enable/disable DMA */
 778static int configure_domain_dma_state(struct fsl_dma_domain *dma_domain, bool enable)
 779{
 780        struct device_domain_info *info;
 781        unsigned long flags;
 782        int ret;
 783
 784        spin_lock_irqsave(&dma_domain->domain_lock, flags);
 785
 786        if (enable && !dma_domain->mapped) {
 787                pr_debug("Can't enable DMA domain without valid mapping\n");
 788                spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
 789                return -ENODEV;
 790        }
 791
 792        dma_domain->enabled = enable;
 793        list_for_each_entry(info, &dma_domain->devices, link) {
 794                ret = (enable) ? pamu_enable_liodn(info->liodn) :
 795                        pamu_disable_liodn(info->liodn);
 796                if (ret)
 797                        pr_debug("Unable to set dma state for liodn %d",
 798                                 info->liodn);
 799        }
 800        spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
 801
 802        return 0;
 803}
 804
 805static int fsl_pamu_set_windows(struct iommu_domain *domain, u32 w_count)
 806{
 807        struct fsl_dma_domain *dma_domain = to_fsl_dma_domain(domain);
 808        unsigned long flags;
 809        int ret;
 810
 811        spin_lock_irqsave(&dma_domain->domain_lock, flags);
 812        /* Ensure domain is inactive i.e. DMA should be disabled for the domain */
 813        if (dma_domain->enabled) {
 814                pr_debug("Can't set geometry attributes as domain is active\n");
 815                spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
 816                return  -EBUSY;
 817        }
 818
 819        /* Ensure that the geometry has been set for the domain */
 820        if (!dma_domain->geom_size) {
 821                pr_debug("Please configure geometry before setting the number of windows\n");
 822                spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
 823                return -EINVAL;
 824        }
 825
 826        /*
 827         * Ensure we have valid window count i.e. it should be less than
 828         * maximum permissible limit and should be a power of two.
 829         */
 830        if (w_count > pamu_get_max_subwin_cnt() || !is_power_of_2(w_count)) {
 831                pr_debug("Invalid window count\n");
 832                spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
 833                return -EINVAL;
 834        }
 835
 836        ret = pamu_set_domain_geometry(dma_domain, &domain->geometry,
 837                                       w_count > 1 ? w_count : 0);
 838        if (!ret) {
 839                kfree(dma_domain->win_arr);
 840                dma_domain->win_arr = kcalloc(w_count,
 841                                              sizeof(*dma_domain->win_arr),
 842                                              GFP_ATOMIC);
 843                if (!dma_domain->win_arr) {
 844                        spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
 845                        return -ENOMEM;
 846                }
 847                dma_domain->win_cnt = w_count;
 848        }
 849        spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
 850
 851        return ret;
 852}
 853
 854static int fsl_pamu_set_domain_attr(struct iommu_domain *domain,
 855                                    enum iommu_attr attr_type, void *data)
 856{
 857        struct fsl_dma_domain *dma_domain = to_fsl_dma_domain(domain);
 858        int ret = 0;
 859
 860        switch (attr_type) {
 861        case DOMAIN_ATTR_GEOMETRY:
 862                ret = configure_domain_geometry(domain, data);
 863                break;
 864        case DOMAIN_ATTR_FSL_PAMU_STASH:
 865                ret = configure_domain_stash(dma_domain, data);
 866                break;
 867        case DOMAIN_ATTR_FSL_PAMU_ENABLE:
 868                ret = configure_domain_dma_state(dma_domain, *(int *)data);
 869                break;
 870        case DOMAIN_ATTR_WINDOWS:
 871                ret = fsl_pamu_set_windows(domain, *(u32 *)data);
 872                break;
 873        default:
 874                pr_debug("Unsupported attribute type\n");
 875                ret = -EINVAL;
 876                break;
 877        }
 878
 879        return ret;
 880}
 881
 882static int fsl_pamu_get_domain_attr(struct iommu_domain *domain,
 883                                    enum iommu_attr attr_type, void *data)
 884{
 885        struct fsl_dma_domain *dma_domain = to_fsl_dma_domain(domain);
 886        int ret = 0;
 887
 888        switch (attr_type) {
 889        case DOMAIN_ATTR_FSL_PAMU_STASH:
 890                memcpy(data, &dma_domain->dma_stash,
 891                       sizeof(struct pamu_stash_attribute));
 892                break;
 893        case DOMAIN_ATTR_FSL_PAMU_ENABLE:
 894                *(int *)data = dma_domain->enabled;
 895                break;
 896        case DOMAIN_ATTR_FSL_PAMUV1:
 897                *(int *)data = DOMAIN_ATTR_FSL_PAMUV1;
 898                break;
 899        case DOMAIN_ATTR_WINDOWS:
 900                *(u32 *)data = dma_domain->win_cnt;
 901                break;
 902        default:
 903                pr_debug("Unsupported attribute type\n");
 904                ret = -EINVAL;
 905                break;
 906        }
 907
 908        return ret;
 909}
 910
 911static struct iommu_group *get_device_iommu_group(struct device *dev)
 912{
 913        struct iommu_group *group;
 914
 915        group = iommu_group_get(dev);
 916        if (!group)
 917                group = iommu_group_alloc();
 918
 919        return group;
 920}
 921
 922static  bool check_pci_ctl_endpt_part(struct pci_controller *pci_ctl)
 923{
 924        u32 version;
 925
 926        /* Check the PCI controller version number by readding BRR1 register */
 927        version = in_be32(pci_ctl->cfg_addr + (PCI_FSL_BRR1 >> 2));
 928        version &= PCI_FSL_BRR1_VER;
 929        /* If PCI controller version is >= 0x204 we can partition endpoints */
 930        return version >= 0x204;
 931}
 932
 933/* Get iommu group information from peer devices or devices on the parent bus */
 934static struct iommu_group *get_shared_pci_device_group(struct pci_dev *pdev)
 935{
 936        struct pci_dev *tmp;
 937        struct iommu_group *group;
 938        struct pci_bus *bus = pdev->bus;
 939
 940        /*
 941         * Traverese the pci bus device list to get
 942         * the shared iommu group.
 943         */
 944        while (bus) {
 945                list_for_each_entry(tmp, &bus->devices, bus_list) {
 946                        if (tmp == pdev)
 947                                continue;
 948                        group = iommu_group_get(&tmp->dev);
 949                        if (group)
 950                                return group;
 951                }
 952
 953                bus = bus->parent;
 954        }
 955
 956        return NULL;
 957}
 958
 959static struct iommu_group *get_pci_device_group(struct pci_dev *pdev)
 960{
 961        struct pci_controller *pci_ctl;
 962        bool pci_endpt_partitioning;
 963        struct iommu_group *group = NULL;
 964
 965        pci_ctl = pci_bus_to_host(pdev->bus);
 966        pci_endpt_partitioning = check_pci_ctl_endpt_part(pci_ctl);
 967        /* We can partition PCIe devices so assign device group to the device */
 968        if (pci_endpt_partitioning) {
 969                group = pci_device_group(&pdev->dev);
 970
 971                /*
 972                 * PCIe controller is not a paritionable entity
 973                 * free the controller device iommu_group.
 974                 */
 975                if (pci_ctl->parent->iommu_group)
 976                        iommu_group_remove_device(pci_ctl->parent);
 977        } else {
 978                /*
 979                 * All devices connected to the controller will share the
 980                 * PCI controllers device group. If this is the first
 981                 * device to be probed for the pci controller, copy the
 982                 * device group information from the PCI controller device
 983                 * node and remove the PCI controller iommu group.
 984                 * For subsequent devices, the iommu group information can
 985                 * be obtained from sibling devices (i.e. from the bus_devices
 986                 * link list).
 987                 */
 988                if (pci_ctl->parent->iommu_group) {
 989                        group = get_device_iommu_group(pci_ctl->parent);
 990                        iommu_group_remove_device(pci_ctl->parent);
 991                } else {
 992                        group = get_shared_pci_device_group(pdev);
 993                }
 994        }
 995
 996        if (!group)
 997                group = ERR_PTR(-ENODEV);
 998
 999        return group;
1000}
1001
1002static struct iommu_group *fsl_pamu_device_group(struct device *dev)
1003{
1004        struct iommu_group *group = ERR_PTR(-ENODEV);
1005        int len;
1006
1007        /*
1008         * For platform devices we allocate a separate group for
1009         * each of the devices.
1010         */
1011        if (dev_is_pci(dev))
1012                group = get_pci_device_group(to_pci_dev(dev));
1013        else if (of_get_property(dev->of_node, "fsl,liodn", &len))
1014                group = get_device_iommu_group(dev);
1015
1016        return group;
1017}
1018
1019static struct iommu_device *fsl_pamu_probe_device(struct device *dev)
1020{
1021        return &pamu_iommu;
1022}
1023
1024static void fsl_pamu_release_device(struct device *dev)
1025{
1026}
1027
1028static const struct iommu_ops fsl_pamu_ops = {
1029        .capable        = fsl_pamu_capable,
1030        .domain_alloc   = fsl_pamu_domain_alloc,
1031        .domain_free    = fsl_pamu_domain_free,
1032        .attach_dev     = fsl_pamu_attach_device,
1033        .detach_dev     = fsl_pamu_detach_device,
1034        .domain_window_enable = fsl_pamu_window_enable,
1035        .domain_window_disable = fsl_pamu_window_disable,
1036        .iova_to_phys   = fsl_pamu_iova_to_phys,
1037        .domain_set_attr = fsl_pamu_set_domain_attr,
1038        .domain_get_attr = fsl_pamu_get_domain_attr,
1039        .probe_device   = fsl_pamu_probe_device,
1040        .release_device = fsl_pamu_release_device,
1041        .device_group   = fsl_pamu_device_group,
1042};
1043
1044int __init pamu_domain_init(void)
1045{
1046        int ret = 0;
1047
1048        ret = iommu_init_mempool();
1049        if (ret)
1050                return ret;
1051
1052        ret = iommu_device_sysfs_add(&pamu_iommu, NULL, NULL, "iommu0");
1053        if (ret)
1054                return ret;
1055
1056        iommu_device_set_ops(&pamu_iommu, &fsl_pamu_ops);
1057
1058        ret = iommu_device_register(&pamu_iommu);
1059        if (ret) {
1060                iommu_device_sysfs_remove(&pamu_iommu);
1061                pr_err("Can't register iommu device\n");
1062                return ret;
1063        }
1064
1065        bus_set_iommu(&platform_bus_type, &fsl_pamu_ops);
1066        bus_set_iommu(&pci_bus_type, &fsl_pamu_ops);
1067
1068        return ret;
1069}
1070