xref: /linux/drivers/net/ethernet/intel/ice/ice_adapter.c (revision 24168c5e6dfbdd5b414f048f47f75d64533296ca)
1 // SPDX-License-Identifier: GPL-2.0-only
2 // SPDX-FileCopyrightText: Copyright Red Hat
3 
4 #include <linux/bitfield.h>
5 #include <linux/cleanup.h>
6 #include <linux/mutex.h>
7 #include <linux/pci.h>
8 #include <linux/slab.h>
9 #include <linux/spinlock.h>
10 #include <linux/xarray.h>
11 #include "ice_adapter.h"
12 
13 static DEFINE_XARRAY(ice_adapters);
14 
15 /* PCI bus number is 8 bits. Slot is 5 bits. Domain can have the rest. */
16 #define INDEX_FIELD_DOMAIN GENMASK(BITS_PER_LONG - 1, 13)
17 #define INDEX_FIELD_BUS    GENMASK(12, 5)
18 #define INDEX_FIELD_SLOT   GENMASK(4, 0)
19 
20 static unsigned long ice_adapter_index(const struct pci_dev *pdev)
21 {
22 	unsigned int domain = pci_domain_nr(pdev->bus);
23 
24 	WARN_ON(domain > FIELD_MAX(INDEX_FIELD_DOMAIN));
25 
26 	return FIELD_PREP(INDEX_FIELD_DOMAIN, domain) |
27 	       FIELD_PREP(INDEX_FIELD_BUS,    pdev->bus->number) |
28 	       FIELD_PREP(INDEX_FIELD_SLOT,   PCI_SLOT(pdev->devfn));
29 }
30 
31 static struct ice_adapter *ice_adapter_new(void)
32 {
33 	struct ice_adapter *adapter;
34 
35 	adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
36 	if (!adapter)
37 		return NULL;
38 
39 	spin_lock_init(&adapter->ptp_gltsyn_time_lock);
40 	refcount_set(&adapter->refcount, 1);
41 
42 	return adapter;
43 }
44 
45 static void ice_adapter_free(struct ice_adapter *adapter)
46 {
47 	kfree(adapter);
48 }
49 
50 DEFINE_FREE(ice_adapter_free, struct ice_adapter*, if (_T) ice_adapter_free(_T))
51 
52 /**
53  * ice_adapter_get - Get a shared ice_adapter structure.
54  * @pdev: Pointer to the pci_dev whose driver is getting the ice_adapter.
55  *
56  * Gets a pointer to a shared ice_adapter structure. Physical functions (PFs)
57  * of the same multi-function PCI device share one ice_adapter structure.
58  * The ice_adapter is reference-counted. The PF driver must use ice_adapter_put
59  * to release its reference.
60  *
61  * Context: Process, may sleep.
62  * Return:  Pointer to ice_adapter on success.
63  *          ERR_PTR() on error. -ENOMEM is the only possible error.
64  */
65 struct ice_adapter *ice_adapter_get(const struct pci_dev *pdev)
66 {
67 	struct ice_adapter *ret, __free(ice_adapter_free) *adapter = NULL;
68 	unsigned long index = ice_adapter_index(pdev);
69 
70 	adapter = ice_adapter_new();
71 	if (!adapter)
72 		return ERR_PTR(-ENOMEM);
73 
74 	xa_lock(&ice_adapters);
75 	ret = __xa_cmpxchg(&ice_adapters, index, NULL, adapter, GFP_KERNEL);
76 	if (xa_is_err(ret)) {
77 		ret = ERR_PTR(xa_err(ret));
78 		goto unlock;
79 	}
80 	if (ret) {
81 		refcount_inc(&ret->refcount);
82 		goto unlock;
83 	}
84 	ret = no_free_ptr(adapter);
85 unlock:
86 	xa_unlock(&ice_adapters);
87 	return ret;
88 }
89 
90 /**
91  * ice_adapter_put - Release a reference to the shared ice_adapter structure.
92  * @pdev: Pointer to the pci_dev whose driver is releasing the ice_adapter.
93  *
94  * Releases the reference to ice_adapter previously obtained with
95  * ice_adapter_get.
96  *
97  * Context: Any.
98  */
99 void ice_adapter_put(const struct pci_dev *pdev)
100 {
101 	unsigned long index = ice_adapter_index(pdev);
102 	struct ice_adapter *adapter;
103 
104 	xa_lock(&ice_adapters);
105 	adapter = xa_load(&ice_adapters, index);
106 	if (WARN_ON(!adapter))
107 		goto unlock;
108 
109 	if (!refcount_dec_and_test(&adapter->refcount))
110 		goto unlock;
111 
112 	WARN_ON(__xa_erase(&ice_adapters, index) != adapter);
113 	ice_adapter_free(adapter);
114 unlock:
115 	xa_unlock(&ice_adapters);
116 }
117