diff options
Diffstat (limited to 'drivers/pci/ats.c')
-rw-r--r-- | drivers/pci/ats.c | 131 |
1 files changed, 46 insertions, 85 deletions
diff --git a/drivers/pci/ats.c b/drivers/pci/ats.c index a8099d4d0..eeb9fb2b4 100644 --- a/drivers/pci/ats.c +++ b/drivers/pci/ats.c @@ -17,34 +17,15 @@ #include "pci.h" -static int ats_alloc_one(struct pci_dev *dev, int ps) +void pci_ats_init(struct pci_dev *dev) { int pos; - u16 cap; - struct pci_ats *ats; pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ATS); if (!pos) - return -ENODEV; - - ats = kzalloc(sizeof(*ats), GFP_KERNEL); - if (!ats) - return -ENOMEM; - - ats->pos = pos; - ats->stu = ps; - pci_read_config_word(dev, pos + PCI_ATS_CAP, &cap); - ats->qdep = PCI_ATS_CAP_QDEP(cap) ? PCI_ATS_CAP_QDEP(cap) : - PCI_ATS_MAX_QDEP; - dev->ats = ats; - - return 0; -} + return; -static void ats_free_one(struct pci_dev *dev) -{ - kfree(dev->ats); - dev->ats = NULL; + dev->ats_cap = pos; } /** @@ -56,43 +37,36 @@ static void ats_free_one(struct pci_dev *dev) */ int pci_enable_ats(struct pci_dev *dev, int ps) { - int rc; u16 ctrl; + struct pci_dev *pdev; - BUG_ON(dev->ats && dev->ats->is_enabled); - - if (ps < PCI_ATS_MIN_STU) + if (!dev->ats_cap) return -EINVAL; - if (dev->is_physfn || dev->is_virtfn) { - struct pci_dev *pdev = dev->is_physfn ? dev : dev->physfn; - - mutex_lock(&pdev->sriov->lock); - if (pdev->ats) - rc = pdev->ats->stu == ps ? 0 : -EINVAL; - else - rc = ats_alloc_one(pdev, ps); - - if (!rc) - pdev->ats->ref_cnt++; - mutex_unlock(&pdev->sriov->lock); - if (rc) - return rc; - } + if (WARN_ON(dev->ats_enabled)) + return -EBUSY; - if (!dev->is_physfn) { - rc = ats_alloc_one(dev, ps); - if (rc) - return rc; - } + if (ps < PCI_ATS_MIN_STU) + return -EINVAL; + /* + * Note that enabling ATS on a VF fails unless it's already enabled + * with the same STU on the PF. + */ ctrl = PCI_ATS_CTRL_ENABLE; - if (!dev->is_virtfn) - ctrl |= PCI_ATS_CTRL_STU(ps - PCI_ATS_MIN_STU); - pci_write_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, ctrl); - - dev->ats->is_enabled = 1; + if (dev->is_virtfn) { + pdev = pci_physfn(dev); + if (pdev->ats_stu != ps) + return -EINVAL; + + atomic_inc(&pdev->ats_ref_cnt); /* count enabled VFs */ + } else { + dev->ats_stu = ps; + ctrl |= PCI_ATS_CTRL_STU(dev->ats_stu - PCI_ATS_MIN_STU); + } + pci_write_config_word(dev, dev->ats_cap + PCI_ATS_CTRL, ctrl); + dev->ats_enabled = 1; return 0; } EXPORT_SYMBOL_GPL(pci_enable_ats); @@ -103,28 +77,25 @@ EXPORT_SYMBOL_GPL(pci_enable_ats); */ void pci_disable_ats(struct pci_dev *dev) { + struct pci_dev *pdev; u16 ctrl; - BUG_ON(!dev->ats || !dev->ats->is_enabled); - - pci_read_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, &ctrl); - ctrl &= ~PCI_ATS_CTRL_ENABLE; - pci_write_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, ctrl); - - dev->ats->is_enabled = 0; + if (WARN_ON(!dev->ats_enabled)) + return; - if (dev->is_physfn || dev->is_virtfn) { - struct pci_dev *pdev = dev->is_physfn ? dev : dev->physfn; + if (atomic_read(&dev->ats_ref_cnt)) + return; /* VFs still enabled */ - mutex_lock(&pdev->sriov->lock); - pdev->ats->ref_cnt--; - if (!pdev->ats->ref_cnt) - ats_free_one(pdev); - mutex_unlock(&pdev->sriov->lock); + if (dev->is_virtfn) { + pdev = pci_physfn(dev); + atomic_dec(&pdev->ats_ref_cnt); } - if (!dev->is_physfn) - ats_free_one(dev); + pci_read_config_word(dev, dev->ats_cap + PCI_ATS_CTRL, &ctrl); + ctrl &= ~PCI_ATS_CTRL_ENABLE; + pci_write_config_word(dev, dev->ats_cap + PCI_ATS_CTRL, ctrl); + + dev->ats_enabled = 0; } EXPORT_SYMBOL_GPL(pci_disable_ats); @@ -132,16 +103,13 @@ void pci_restore_ats_state(struct pci_dev *dev) { u16 ctrl; - if (!pci_ats_enabled(dev)) + if (!dev->ats_enabled) return; - if (!pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ATS)) - BUG(); ctrl = PCI_ATS_CTRL_ENABLE; if (!dev->is_virtfn) - ctrl |= PCI_ATS_CTRL_STU(dev->ats->stu - PCI_ATS_MIN_STU); - - pci_write_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, ctrl); + ctrl |= PCI_ATS_CTRL_STU(dev->ats_stu - PCI_ATS_MIN_STU); + pci_write_config_word(dev, dev->ats_cap + PCI_ATS_CTRL, ctrl); } EXPORT_SYMBOL_GPL(pci_restore_ats_state); @@ -159,23 +127,16 @@ EXPORT_SYMBOL_GPL(pci_restore_ats_state); */ int pci_ats_queue_depth(struct pci_dev *dev) { - int pos; u16 cap; + if (!dev->ats_cap) + return -EINVAL; + if (dev->is_virtfn) return 0; - if (dev->ats) - return dev->ats->qdep; - - pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ATS); - if (!pos) - return -ENODEV; - - pci_read_config_word(dev, pos + PCI_ATS_CAP, &cap); - - return PCI_ATS_CAP_QDEP(cap) ? PCI_ATS_CAP_QDEP(cap) : - PCI_ATS_MAX_QDEP; + pci_read_config_word(dev, dev->ats_cap + PCI_ATS_CAP, &cap); + return PCI_ATS_CAP_QDEP(cap) ? PCI_ATS_CAP_QDEP(cap) : PCI_ATS_MAX_QDEP; } EXPORT_SYMBOL_GPL(pci_ats_queue_depth); |