linux/drivers/pci/ats.c
<<
>>
Prefs
   1/*
   2 * drivers/pci/ats.c
   3 *
   4 * Copyright (C) 2009 Intel Corporation, Yu Zhao <yu.zhao@intel.com>
   5 * Copyright (C) 2011 Advanced Micro Devices,
   6 *
   7 * PCI Express I/O Virtualization (IOV) support.
   8 *   Address Translation Service 1.0
   9 *   Page Request Interface added by Joerg Roedel <joerg.roedel@amd.com>
  10 *   PASID support added by Joerg Roedel <joerg.roedel@amd.com>
  11 */
  12
  13#include <linux/export.h>
  14#include <linux/pci-ats.h>
  15#include <linux/pci.h>
  16#include <linux/slab.h>
  17
  18#include "pci.h"
  19
  20static int ats_alloc_one(struct pci_dev *dev, int ps)
  21{
  22        int pos;
  23        u16 cap;
  24        struct pci_ats *ats;
  25
  26        pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ATS);
  27        if (!pos)
  28                return -ENODEV;
  29
  30        ats = kzalloc(sizeof(*ats), GFP_KERNEL);
  31        if (!ats)
  32                return -ENOMEM;
  33
  34        ats->pos = pos;
  35        ats->stu = ps;
  36        pci_read_config_word(dev, pos + PCI_ATS_CAP, &cap);
  37        ats->qdep = PCI_ATS_CAP_QDEP(cap) ? PCI_ATS_CAP_QDEP(cap) :
  38                                            PCI_ATS_MAX_QDEP;
  39        dev->ats = ats;
  40
  41        return 0;
  42}
  43
  44static void ats_free_one(struct pci_dev *dev)
  45{
  46        kfree(dev->ats);
  47        dev->ats = NULL;
  48}
  49
  50/**
  51 * pci_enable_ats - enable the ATS capability
  52 * @dev: the PCI device
  53 * @ps: the IOMMU page shift
  54 *
  55 * Returns 0 on success, or negative on failure.
  56 */
  57int pci_enable_ats(struct pci_dev *dev, int ps)
  58{
  59        int rc;
  60        u16 ctrl;
  61
  62        BUG_ON(dev->ats && dev->ats->is_enabled);
  63
  64        if (ps < PCI_ATS_MIN_STU)
  65                return -EINVAL;
  66
  67        if (dev->is_physfn || dev->is_virtfn) {
  68                struct pci_dev *pdev = dev->is_physfn ? dev : dev->physfn;
  69
  70                mutex_lock(&pdev->sriov->lock);
  71                if (pdev->ats)
  72                        rc = pdev->ats->stu == ps ? 0 : -EINVAL;
  73                else
  74                        rc = ats_alloc_one(pdev, ps);
  75
  76                if (!rc)
  77                        pdev->ats->ref_cnt++;
  78                mutex_unlock(&pdev->sriov->lock);
  79                if (rc)
  80                        return rc;
  81        }
  82
  83        if (!dev->is_physfn) {
  84                rc = ats_alloc_one(dev, ps);
  85                if (rc)
  86                        return rc;
  87        }
  88
  89        ctrl = PCI_ATS_CTRL_ENABLE;
  90        if (!dev->is_virtfn)
  91                ctrl |= PCI_ATS_CTRL_STU(ps - PCI_ATS_MIN_STU);
  92        pci_write_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, ctrl);
  93
  94        dev->ats->is_enabled = 1;
  95
  96        return 0;
  97}
  98EXPORT_SYMBOL_GPL(pci_enable_ats);
  99
 100/**
 101 * pci_disable_ats - disable the ATS capability
 102 * @dev: the PCI device
 103 */
 104void pci_disable_ats(struct pci_dev *dev)
 105{
 106        u16 ctrl;
 107
 108        BUG_ON(!dev->ats || !dev->ats->is_enabled);
 109
 110        pci_read_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, &ctrl);
 111        ctrl &= ~PCI_ATS_CTRL_ENABLE;
 112        pci_write_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, ctrl);
 113
 114        dev->ats->is_enabled = 0;
 115
 116        if (dev->is_physfn || dev->is_virtfn) {
 117                struct pci_dev *pdev = dev->is_physfn ? dev : dev->physfn;
 118
 119                mutex_lock(&pdev->sriov->lock);
 120                pdev->ats->ref_cnt--;
 121                if (!pdev->ats->ref_cnt)
 122                        ats_free_one(pdev);
 123                mutex_unlock(&pdev->sriov->lock);
 124        }
 125
 126        if (!dev->is_physfn)
 127                ats_free_one(dev);
 128}
 129EXPORT_SYMBOL_GPL(pci_disable_ats);
 130
 131void pci_restore_ats_state(struct pci_dev *dev)
 132{
 133        u16 ctrl;
 134
 135        if (!pci_ats_enabled(dev))
 136                return;
 137        if (!pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ATS))
 138                BUG();
 139
 140        ctrl = PCI_ATS_CTRL_ENABLE;
 141        if (!dev->is_virtfn)
 142                ctrl |= PCI_ATS_CTRL_STU(dev->ats->stu - PCI_ATS_MIN_STU);
 143
 144        pci_write_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, ctrl);
 145}
 146EXPORT_SYMBOL_GPL(pci_restore_ats_state);
 147
 148/**
 149 * pci_ats_queue_depth - query the ATS Invalidate Queue Depth
 150 * @dev: the PCI device
 151 *
 152 * Returns the queue depth on success, or negative on failure.
 153 *
 154 * The ATS spec uses 0 in the Invalidate Queue Depth field to
 155 * indicate that the function can accept 32 Invalidate Request.
 156 * But here we use the `real' values (i.e. 1~32) for the Queue
 157 * Depth; and 0 indicates the function shares the Queue with
 158 * other functions (doesn't exclusively own a Queue).
 159 */
 160int pci_ats_queue_depth(struct pci_dev *dev)
 161{
 162        int pos;
 163        u16 cap;
 164
 165        if (dev->is_virtfn)
 166                return 0;
 167
 168        if (dev->ats)
 169                return dev->ats->qdep;
 170
 171        pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ATS);
 172        if (!pos)
 173                return -ENODEV;
 174
 175        pci_read_config_word(dev, pos + PCI_ATS_CAP, &cap);
 176
 177        return PCI_ATS_CAP_QDEP(cap) ? PCI_ATS_CAP_QDEP(cap) :
 178                                       PCI_ATS_MAX_QDEP;
 179}
 180EXPORT_SYMBOL_GPL(pci_ats_queue_depth);
 181
 182#ifdef CONFIG_PCI_PRI
 183/**
 184 * pci_enable_pri - Enable PRI capability
 185 * @ pdev: PCI device structure
 186 *
 187 * Returns 0 on success, negative value on error
 188 */
 189int pci_enable_pri(struct pci_dev *pdev, u32 reqs)
 190{
 191        u16 control, status;
 192        u32 max_requests;
 193        int pos;
 194
 195        pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
 196        if (!pos)
 197                return -EINVAL;
 198
 199        pci_read_config_word(pdev, pos + PCI_PRI_CTRL, &control);
 200        pci_read_config_word(pdev, pos + PCI_PRI_STATUS, &status);
 201        if ((control & PCI_PRI_CTRL_ENABLE) ||
 202            !(status & PCI_PRI_STATUS_STOPPED))
 203                return -EBUSY;
 204
 205        pci_read_config_dword(pdev, pos + PCI_PRI_MAX_REQ, &max_requests);
 206        reqs = min(max_requests, reqs);
 207        pci_write_config_dword(pdev, pos + PCI_PRI_ALLOC_REQ, reqs);
 208
 209        control |= PCI_PRI_CTRL_ENABLE;
 210        pci_write_config_word(pdev, pos + PCI_PRI_CTRL, control);
 211
 212        return 0;
 213}
 214EXPORT_SYMBOL_GPL(pci_enable_pri);
 215
 216/**
 217 * pci_disable_pri - Disable PRI capability
 218 * @pdev: PCI device structure
 219 *
 220 * Only clears the enabled-bit, regardless of its former value
 221 */
 222void pci_disable_pri(struct pci_dev *pdev)
 223{
 224        u16 control;
 225        int pos;
 226
 227        pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
 228        if (!pos)
 229                return;
 230
 231        pci_read_config_word(pdev, pos + PCI_PRI_CTRL, &control);
 232        control &= ~PCI_PRI_CTRL_ENABLE;
 233        pci_write_config_word(pdev, pos + PCI_PRI_CTRL, control);
 234}
 235EXPORT_SYMBOL_GPL(pci_disable_pri);
 236
 237/**
 238 * pci_reset_pri - Resets device's PRI state
 239 * @pdev: PCI device structure
 240 *
 241 * The PRI capability must be disabled before this function is called.
 242 * Returns 0 on success, negative value on error.
 243 */
 244int pci_reset_pri(struct pci_dev *pdev)
 245{
 246        u16 control;
 247        int pos;
 248
 249        pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
 250        if (!pos)
 251                return -EINVAL;
 252
 253        pci_read_config_word(pdev, pos + PCI_PRI_CTRL, &control);
 254        if (control & PCI_PRI_CTRL_ENABLE)
 255                return -EBUSY;
 256
 257        control |= PCI_PRI_CTRL_RESET;
 258
 259        pci_write_config_word(pdev, pos + PCI_PRI_CTRL, control);
 260
 261        return 0;
 262}
 263EXPORT_SYMBOL_GPL(pci_reset_pri);
 264#endif /* CONFIG_PCI_PRI */
 265
 266#ifdef CONFIG_PCI_PASID
 267/**
 268 * pci_enable_pasid - Enable the PASID capability
 269 * @pdev: PCI device structure
 270 * @features: Features to enable
 271 *
 272 * Returns 0 on success, negative value on error. This function checks
 273 * whether the features are actually supported by the device and returns
 274 * an error if not.
 275 */
 276int pci_enable_pasid(struct pci_dev *pdev, int features)
 277{
 278        u16 control, supported;
 279        int pos;
 280
 281        pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID);
 282        if (!pos)
 283                return -EINVAL;
 284
 285        pci_read_config_word(pdev, pos + PCI_PASID_CTRL, &control);
 286        pci_read_config_word(pdev, pos + PCI_PASID_CAP, &supported);
 287
 288        if (control & PCI_PASID_CTRL_ENABLE)
 289                return -EINVAL;
 290
 291        supported &= PCI_PASID_CAP_EXEC | PCI_PASID_CAP_PRIV;
 292
 293        /* User wants to enable anything unsupported? */
 294        if ((supported & features) != features)
 295                return -EINVAL;
 296
 297        control = PCI_PASID_CTRL_ENABLE | features;
 298
 299        pci_write_config_word(pdev, pos + PCI_PASID_CTRL, control);
 300
 301        return 0;
 302}
 303EXPORT_SYMBOL_GPL(pci_enable_pasid);
 304
 305/**
 306 * pci_disable_pasid - Disable the PASID capability
 307 * @pdev: PCI device structure
 308 *
 309 */
 310void pci_disable_pasid(struct pci_dev *pdev)
 311{
 312        u16 control = 0;
 313        int pos;
 314
 315        pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID);
 316        if (!pos)
 317                return;
 318
 319        pci_write_config_word(pdev, pos + PCI_PASID_CTRL, control);
 320}
 321EXPORT_SYMBOL_GPL(pci_disable_pasid);
 322
 323/**
 324 * pci_pasid_features - Check which PASID features are supported
 325 * @pdev: PCI device structure
 326 *
 327 * Returns a negative value when no PASI capability is present.
 328 * Otherwise is returns a bitmask with supported features. Current
 329 * features reported are:
 330 * PCI_PASID_CAP_EXEC - Execute permission supported
 331 * PCI_PASID_CAP_PRIV - Privileged mode supported
 332 */
 333int pci_pasid_features(struct pci_dev *pdev)
 334{
 335        u16 supported;
 336        int pos;
 337
 338        pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID);
 339        if (!pos)
 340                return -EINVAL;
 341
 342        pci_read_config_word(pdev, pos + PCI_PASID_CAP, &supported);
 343
 344        supported &= PCI_PASID_CAP_EXEC | PCI_PASID_CAP_PRIV;
 345
 346        return supported;
 347}
 348EXPORT_SYMBOL_GPL(pci_pasid_features);
 349
 350#define PASID_NUMBER_SHIFT      8
 351#define PASID_NUMBER_MASK       (0x1f << PASID_NUMBER_SHIFT)
 352/**
 353 * pci_max_pasid - Get maximum number of PASIDs supported by device
 354 * @pdev: PCI device structure
 355 *
 356 * Returns negative value when PASID capability is not present.
 357 * Otherwise it returns the numer of supported PASIDs.
 358 */
 359int pci_max_pasids(struct pci_dev *pdev)
 360{
 361        u16 supported;
 362        int pos;
 363
 364        pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID);
 365        if (!pos)
 366                return -EINVAL;
 367
 368        pci_read_config_word(pdev, pos + PCI_PASID_CAP, &supported);
 369
 370        supported = (supported & PASID_NUMBER_MASK) >> PASID_NUMBER_SHIFT;
 371
 372        return (1 << supported);
 373}
 374EXPORT_SYMBOL_GPL(pci_max_pasids);
 375#endif /* CONFIG_PCI_PASID */
 376