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_pri_enabled - Checks if PRI capability is enabled
 239 * @pdev: PCI device structure
 240 *
 241 * Returns true if PRI is enabled on the device, false otherwise
 242 */
 243bool pci_pri_enabled(struct pci_dev *pdev)
 244{
 245        u16 control;
 246        int pos;
 247
 248        pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
 249        if (!pos)
 250                return false;
 251
 252        pci_read_config_word(pdev, pos + PCI_PRI_CTRL, &control);
 253
 254        return (control & PCI_PRI_CTRL_ENABLE) ? true : false;
 255}
 256EXPORT_SYMBOL_GPL(pci_pri_enabled);
 257
 258/**
 259 * pci_reset_pri - Resets device's PRI state
 260 * @pdev: PCI device structure
 261 *
 262 * The PRI capability must be disabled before this function is called.
 263 * Returns 0 on success, negative value on error.
 264 */
 265int pci_reset_pri(struct pci_dev *pdev)
 266{
 267        u16 control;
 268        int pos;
 269
 270        pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
 271        if (!pos)
 272                return -EINVAL;
 273
 274        pci_read_config_word(pdev, pos + PCI_PRI_CTRL, &control);
 275        if (control & PCI_PRI_CTRL_ENABLE)
 276                return -EBUSY;
 277
 278        control |= PCI_PRI_CTRL_RESET;
 279
 280        pci_write_config_word(pdev, pos + PCI_PRI_CTRL, control);
 281
 282        return 0;
 283}
 284EXPORT_SYMBOL_GPL(pci_reset_pri);
 285
 286/**
 287 * pci_pri_stopped - Checks whether the PRI capability is stopped
 288 * @pdev: PCI device structure
 289 *
 290 * Returns true if the PRI capability on the device is disabled and the
 291 * device has no outstanding PRI requests, false otherwise. The device
 292 * indicates this via the STOPPED bit in the status register of the
 293 * capability.
 294 * The device internal state can be cleared by resetting the PRI state
 295 * with pci_reset_pri(). This can force the capability into the STOPPED
 296 * state.
 297 */
 298bool pci_pri_stopped(struct pci_dev *pdev)
 299{
 300        u16 control, status;
 301        int pos;
 302
 303        pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
 304        if (!pos)
 305                return true;
 306
 307        pci_read_config_word(pdev, pos + PCI_PRI_CTRL, &control);
 308        pci_read_config_word(pdev, pos + PCI_PRI_STATUS, &status);
 309
 310        if (control & PCI_PRI_CTRL_ENABLE)
 311                return false;
 312
 313        return (status & PCI_PRI_STATUS_STOPPED) ? true : false;
 314}
 315EXPORT_SYMBOL_GPL(pci_pri_stopped);
 316
 317/**
 318 * pci_pri_status - Request PRI status of a device
 319 * @pdev: PCI device structure
 320 *
 321 * Returns negative value on failure, status on success. The status can
 322 * be checked against status-bits. Supported bits are currently:
 323 * PCI_PRI_STATUS_RF:      Response failure
 324 * PCI_PRI_STATUS_UPRGI:   Unexpected Page Request Group Index
 325 * PCI_PRI_STATUS_STOPPED: PRI has stopped
 326 */
 327int pci_pri_status(struct pci_dev *pdev)
 328{
 329        u16 status, control;
 330        int pos;
 331
 332        pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
 333        if (!pos)
 334                return -EINVAL;
 335
 336        pci_read_config_word(pdev, pos + PCI_PRI_CTRL, &control);
 337        pci_read_config_word(pdev, pos + PCI_PRI_STATUS, &status);
 338
 339        /* Stopped bit is undefined when enable == 1, so clear it */
 340        if (control & PCI_PRI_CTRL_ENABLE)
 341                status &= ~PCI_PRI_STATUS_STOPPED;
 342
 343        return status;
 344}
 345EXPORT_SYMBOL_GPL(pci_pri_status);
 346#endif /* CONFIG_PCI_PRI */
 347
 348#ifdef CONFIG_PCI_PASID
 349/**
 350 * pci_enable_pasid - Enable the PASID capability
 351 * @pdev: PCI device structure
 352 * @features: Features to enable
 353 *
 354 * Returns 0 on success, negative value on error. This function checks
 355 * whether the features are actually supported by the device and returns
 356 * an error if not.
 357 */
 358int pci_enable_pasid(struct pci_dev *pdev, int features)
 359{
 360        u16 control, supported;
 361        int pos;
 362
 363        pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID);
 364        if (!pos)
 365                return -EINVAL;
 366
 367        pci_read_config_word(pdev, pos + PCI_PASID_CTRL, &control);
 368        pci_read_config_word(pdev, pos + PCI_PASID_CAP, &supported);
 369
 370        if (control & PCI_PASID_CTRL_ENABLE)
 371                return -EINVAL;
 372
 373        supported &= PCI_PASID_CAP_EXEC | PCI_PASID_CAP_PRIV;
 374
 375        /* User wants to enable anything unsupported? */
 376        if ((supported & features) != features)
 377                return -EINVAL;
 378
 379        control = PCI_PASID_CTRL_ENABLE | features;
 380
 381        pci_write_config_word(pdev, pos + PCI_PASID_CTRL, control);
 382
 383        return 0;
 384}
 385EXPORT_SYMBOL_GPL(pci_enable_pasid);
 386
 387/**
 388 * pci_disable_pasid - Disable the PASID capability
 389 * @pdev: PCI device structure
 390 *
 391 */
 392void pci_disable_pasid(struct pci_dev *pdev)
 393{
 394        u16 control = 0;
 395        int pos;
 396
 397        pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID);
 398        if (!pos)
 399                return;
 400
 401        pci_write_config_word(pdev, pos + PCI_PASID_CTRL, control);
 402}
 403EXPORT_SYMBOL_GPL(pci_disable_pasid);
 404
 405/**
 406 * pci_pasid_features - Check which PASID features are supported
 407 * @pdev: PCI device structure
 408 *
 409 * Returns a negative value when no PASI capability is present.
 410 * Otherwise is returns a bitmask with supported features. Current
 411 * features reported are:
 412 * PCI_PASID_CAP_EXEC - Execute permission supported
 413 * PCI_PASID_CAP_PRIV - Priviledged mode supported
 414 */
 415int pci_pasid_features(struct pci_dev *pdev)
 416{
 417        u16 supported;
 418        int pos;
 419
 420        pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID);
 421        if (!pos)
 422                return -EINVAL;
 423
 424        pci_read_config_word(pdev, pos + PCI_PASID_CAP, &supported);
 425
 426        supported &= PCI_PASID_CAP_EXEC | PCI_PASID_CAP_PRIV;
 427
 428        return supported;
 429}
 430EXPORT_SYMBOL_GPL(pci_pasid_features);
 431
 432#define PASID_NUMBER_SHIFT      8
 433#define PASID_NUMBER_MASK       (0x1f << PASID_NUMBER_SHIFT)
 434/**
 435 * pci_max_pasid - Get maximum number of PASIDs supported by device
 436 * @pdev: PCI device structure
 437 *
 438 * Returns negative value when PASID capability is not present.
 439 * Otherwise it returns the numer of supported PASIDs.
 440 */
 441int pci_max_pasids(struct pci_dev *pdev)
 442{
 443        u16 supported;
 444        int pos;
 445
 446        pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID);
 447        if (!pos)
 448                return -EINVAL;
 449
 450        pci_read_config_word(pdev, pos + PCI_PASID_CAP, &supported);
 451
 452        supported = (supported & PASID_NUMBER_MASK) >> PASID_NUMBER_SHIFT;
 453
 454        return (1 << supported);
 455}
 456EXPORT_SYMBOL_GPL(pci_max_pasids);
 457#endif /* CONFIG_PCI_PASID */
 458
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.