xref: /linux/drivers/net/ethernet/intel/ice/ice_adapter.c (revision 18f65355e112dfc87d5e2e8a299119afd2e65e7e)
1 // SPDX-License-Identifier: GPL-2.0-only
2 // SPDX-FileCopyrightText: Copyright Red Hat
3 
4 #include <linux/cleanup.h>
5 #include <linux/mutex.h>
6 #include <linux/pci.h>
7 #include <linux/slab.h>
8 #include <linux/spinlock.h>
9 #include <linux/xarray.h>
10 #include "ice_adapter.h"
11 #include "ice.h"
12 
13 static DEFINE_XARRAY(ice_adapters);
14 static DEFINE_MUTEX(ice_adapters_mutex);
15 
16 #define ICE_ADAPTER_FIXED_INDEX	BIT_ULL(63)
17 
18 #define ICE_ADAPTER_INDEX_E825C	\
19 	(ICE_DEV_ID_E825C_BACKPLANE | ICE_ADAPTER_FIXED_INDEX)
20 
21 static u64 ice_adapter_index(struct pci_dev *pdev)
22 {
23 	switch (pdev->device) {
24 	case ICE_DEV_ID_E825C_BACKPLANE:
25 	case ICE_DEV_ID_E825C_QSFP:
26 	case ICE_DEV_ID_E825C_SFP:
27 	case ICE_DEV_ID_E825C_SGMII:
28 		/* E825C devices have multiple NACs which are connected to the
29 		 * same clock source, and which must share the same
30 		 * ice_adapter structure. We can't use the serial number since
31 		 * each NAC has its own NVM generated with its own unique
32 		 * Device Serial Number. Instead, rely on the embedded nature
33 		 * of the E825C devices, and use a fixed index. This relies on
34 		 * the fact that all E825C physical functions in a given
35 		 * system are part of the same overall device.
36 		 */
37 		return ICE_ADAPTER_INDEX_E825C;
38 	default:
39 		return pci_get_dsn(pdev) & ~ICE_ADAPTER_FIXED_INDEX;
40 	}
41 }
42 
43 static unsigned long ice_adapter_xa_index(struct pci_dev *pdev)
44 {
45 	u64 index = ice_adapter_index(pdev);
46 
47 #if BITS_PER_LONG == 64
48 	return index;
49 #else
50 	return (u32)index ^ (u32)(index >> 32);
51 #endif
52 }
53 
54 static struct ice_adapter *ice_adapter_new(struct pci_dev *pdev)
55 {
56 	struct ice_adapter *adapter;
57 
58 	adapter = kzalloc_obj(*adapter);
59 	if (!adapter)
60 		return NULL;
61 
62 	adapter->index = ice_adapter_index(pdev);
63 	spin_lock_init(&adapter->ptp_gltsyn_time_lock);
64 	spin_lock_init(&adapter->txq_ctx_lock);
65 	for (int i = 0; i < ARRAY_SIZE(adapter->cpi_phy_lock); i++)
66 		mutex_init(&adapter->cpi_phy_lock[i]);
67 	refcount_set(&adapter->refcount, 1);
68 
69 	mutex_init(&adapter->ports.lock);
70 	INIT_LIST_HEAD(&adapter->ports.ports);
71 
72 	return adapter;
73 }
74 
75 static void ice_adapter_free(struct ice_adapter *adapter)
76 {
77 	WARN_ON(!list_empty(&adapter->ports.ports));
78 	for (int i = 0; i < ARRAY_SIZE(adapter->cpi_phy_lock); i++)
79 		mutex_destroy(&adapter->cpi_phy_lock[i]);
80 	mutex_destroy(&adapter->ports.lock);
81 
82 	kfree(adapter);
83 }
84 
85 /**
86  * ice_adapter_get - Get a shared ice_adapter structure.
87  * @pdev: Pointer to the pci_dev whose driver is getting the ice_adapter.
88  *
89  * Gets a pointer to a shared ice_adapter structure. Physical functions (PFs)
90  * of the same multi-function PCI device share one ice_adapter structure.
91  * The ice_adapter is reference-counted. The PF driver must use ice_adapter_put
92  * to release its reference.
93  *
94  * Context: Process, may sleep.
95  * Return:  Pointer to ice_adapter on success.
96  *          ERR_PTR() on error. -ENOMEM is the only possible error.
97  */
98 struct ice_adapter *ice_adapter_get(struct pci_dev *pdev)
99 {
100 	struct ice_adapter *adapter;
101 	unsigned long index;
102 	int err;
103 
104 	index = ice_adapter_xa_index(pdev);
105 	scoped_guard(mutex, &ice_adapters_mutex) {
106 		adapter = xa_load(&ice_adapters, index);
107 		if (adapter) {
108 			refcount_inc(&adapter->refcount);
109 			WARN_ON_ONCE(adapter->index != ice_adapter_index(pdev));
110 			return adapter;
111 		}
112 		err = xa_reserve(&ice_adapters, index, GFP_KERNEL);
113 		if (err)
114 			return ERR_PTR(err);
115 
116 		adapter = ice_adapter_new(pdev);
117 		if (!adapter) {
118 			xa_release(&ice_adapters, index);
119 			return ERR_PTR(-ENOMEM);
120 		}
121 		xa_store(&ice_adapters, index, adapter, GFP_KERNEL);
122 	}
123 	return adapter;
124 }
125 
126 /**
127  * ice_adapter_put - Release a reference to the shared ice_adapter structure.
128  * @pdev: Pointer to the pci_dev whose driver is releasing the ice_adapter.
129  *
130  * Releases the reference to ice_adapter previously obtained with
131  * ice_adapter_get.
132  *
133  * Context: Process, may sleep.
134  */
135 void ice_adapter_put(struct pci_dev *pdev)
136 {
137 	struct ice_adapter *adapter;
138 	unsigned long index;
139 
140 	index = ice_adapter_xa_index(pdev);
141 	scoped_guard(mutex, &ice_adapters_mutex) {
142 		adapter = xa_load(&ice_adapters, index);
143 		if (WARN_ON(!adapter))
144 			return;
145 		if (!refcount_dec_and_test(&adapter->refcount))
146 			return;
147 
148 		WARN_ON(xa_erase(&ice_adapters, index) != adapter);
149 	}
150 	ice_adapter_free(adapter);
151 }
152