• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ice_adapter_index(struct pci_dev * pdev)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 
ice_adapter_xa_index(struct pci_dev * pdev)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 
ice_adapter_new(struct pci_dev * pdev)54 static struct ice_adapter *ice_adapter_new(struct pci_dev *pdev)
55 {
56 	struct ice_adapter *adapter;
57 
58 	adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
59 	if (!adapter)
60 		return NULL;
61 
62 	adapter->index = ice_adapter_index(pdev);
63 	spin_lock_init(&adapter->ptp_gltsyn_time_lock);
64 	refcount_set(&adapter->refcount, 1);
65 
66 	mutex_init(&adapter->ports.lock);
67 	INIT_LIST_HEAD(&adapter->ports.ports);
68 
69 	return adapter;
70 }
71 
ice_adapter_free(struct ice_adapter * adapter)72 static void ice_adapter_free(struct ice_adapter *adapter)
73 {
74 	WARN_ON(!list_empty(&adapter->ports.ports));
75 	mutex_destroy(&adapter->ports.lock);
76 
77 	kfree(adapter);
78 }
79 
80 /**
81  * ice_adapter_get - Get a shared ice_adapter structure.
82  * @pdev: Pointer to the pci_dev whose driver is getting the ice_adapter.
83  *
84  * Gets a pointer to a shared ice_adapter structure. Physical functions (PFs)
85  * of the same multi-function PCI device share one ice_adapter structure.
86  * The ice_adapter is reference-counted. The PF driver must use ice_adapter_put
87  * to release its reference.
88  *
89  * Context: Process, may sleep.
90  * Return:  Pointer to ice_adapter on success.
91  *          ERR_PTR() on error. -ENOMEM is the only possible error.
92  */
ice_adapter_get(struct pci_dev * pdev)93 struct ice_adapter *ice_adapter_get(struct pci_dev *pdev)
94 {
95 	struct ice_adapter *adapter;
96 	unsigned long index;
97 	int err;
98 
99 	index = ice_adapter_xa_index(pdev);
100 	scoped_guard(mutex, &ice_adapters_mutex) {
101 		err = xa_insert(&ice_adapters, index, NULL, GFP_KERNEL);
102 		if (err == -EBUSY) {
103 			adapter = xa_load(&ice_adapters, index);
104 			refcount_inc(&adapter->refcount);
105 			WARN_ON_ONCE(adapter->index != ice_adapter_index(pdev));
106 			return adapter;
107 		}
108 		if (err)
109 			return ERR_PTR(err);
110 
111 		adapter = ice_adapter_new(pdev);
112 		if (!adapter)
113 			return ERR_PTR(-ENOMEM);
114 		xa_store(&ice_adapters, index, adapter, GFP_KERNEL);
115 	}
116 	return adapter;
117 }
118 
119 /**
120  * ice_adapter_put - Release a reference to the shared ice_adapter structure.
121  * @pdev: Pointer to the pci_dev whose driver is releasing the ice_adapter.
122  *
123  * Releases the reference to ice_adapter previously obtained with
124  * ice_adapter_get.
125  *
126  * Context: Process, may sleep.
127  */
ice_adapter_put(struct pci_dev * pdev)128 void ice_adapter_put(struct pci_dev *pdev)
129 {
130 	struct ice_adapter *adapter;
131 	unsigned long index;
132 
133 	index = ice_adapter_xa_index(pdev);
134 	scoped_guard(mutex, &ice_adapters_mutex) {
135 		adapter = xa_load(&ice_adapters, index);
136 		if (WARN_ON(!adapter))
137 			return;
138 		if (!refcount_dec_and_test(&adapter->refcount))
139 			return;
140 
141 		WARN_ON(xa_erase(&ice_adapters, index) != adapter);
142 	}
143 	ice_adapter_free(adapter);
144 }
145