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 static unsigned long ice_adapter_index(u64 dsn) 17 { 18 #if BITS_PER_LONG == 64 19 return dsn; 20 #else 21 return (u32)dsn ^ (u32)(dsn >> 32); 22 #endif 23 } 24 25 static struct ice_adapter *ice_adapter_new(u64 dsn) 26 { 27 struct ice_adapter *adapter; 28 29 adapter = kzalloc(sizeof(*adapter), GFP_KERNEL); 30 if (!adapter) 31 return NULL; 32 33 adapter->device_serial_number = dsn; 34 spin_lock_init(&adapter->ptp_gltsyn_time_lock); 35 refcount_set(&adapter->refcount, 1); 36 37 mutex_init(&adapter->ports.lock); 38 INIT_LIST_HEAD(&adapter->ports.ports); 39 40 return adapter; 41 } 42 43 static void ice_adapter_free(struct ice_adapter *adapter) 44 { 45 WARN_ON(!list_empty(&adapter->ports.ports)); 46 mutex_destroy(&adapter->ports.lock); 47 48 kfree(adapter); 49 } 50 51 /** 52 * ice_adapter_get - Get a shared ice_adapter structure. 53 * @pdev: Pointer to the pci_dev whose driver is getting the ice_adapter. 54 * 55 * Gets a pointer to a shared ice_adapter structure. Physical functions (PFs) 56 * of the same multi-function PCI device share one ice_adapter structure. 57 * The ice_adapter is reference-counted. The PF driver must use ice_adapter_put 58 * to release its reference. 59 * 60 * Context: Process, may sleep. 61 * Return: Pointer to ice_adapter on success. 62 * ERR_PTR() on error. -ENOMEM is the only possible error. 63 */ 64 struct ice_adapter *ice_adapter_get(struct pci_dev *pdev) 65 { 66 u64 dsn = pci_get_dsn(pdev); 67 struct ice_adapter *adapter; 68 unsigned long index; 69 int err; 70 71 index = ice_adapter_index(dsn); 72 scoped_guard(mutex, &ice_adapters_mutex) { 73 err = xa_insert(&ice_adapters, index, NULL, GFP_KERNEL); 74 if (err == -EBUSY) { 75 adapter = xa_load(&ice_adapters, index); 76 refcount_inc(&adapter->refcount); 77 WARN_ON_ONCE(adapter->device_serial_number != dsn); 78 return adapter; 79 } 80 if (err) 81 return ERR_PTR(err); 82 83 adapter = ice_adapter_new(dsn); 84 if (!adapter) 85 return ERR_PTR(-ENOMEM); 86 xa_store(&ice_adapters, index, adapter, GFP_KERNEL); 87 } 88 return adapter; 89 } 90 91 /** 92 * ice_adapter_put - Release a reference to the shared ice_adapter structure. 93 * @pdev: Pointer to the pci_dev whose driver is releasing the ice_adapter. 94 * 95 * Releases the reference to ice_adapter previously obtained with 96 * ice_adapter_get. 97 * 98 * Context: Process, may sleep. 99 */ 100 void ice_adapter_put(struct pci_dev *pdev) 101 { 102 u64 dsn = pci_get_dsn(pdev); 103 struct ice_adapter *adapter; 104 unsigned long index; 105 106 index = ice_adapter_index(dsn); 107 scoped_guard(mutex, &ice_adapters_mutex) { 108 adapter = xa_load(&ice_adapters, index); 109 if (WARN_ON(!adapter)) 110 return; 111 if (!refcount_dec_and_test(&adapter->refcount)) 112 return; 113 114 WARN_ON(xa_erase(&ice_adapters, index) != adapter); 115 } 116 ice_adapter_free(adapter); 117 } 118