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