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 a8099d4d0c9d..eeb9fb2b47aa 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);  |