| From bf4e8ccd3b905cfc321b00fa297589c80e071d1c Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Fri, 1 Aug 2025 15:27:12 -0700 |
| Subject: ice: use fixed adapter index for E825C embedded devices |
| |
| From: Jacob Keller <jacob.e.keller@intel.com> |
| |
| [ Upstream commit 5c5e5b52bf05c7fe88768318c041052c5fac36b8 ] |
| |
| The ice_adapter structure is used by the ice driver to connect multiple |
| physical functions of a device in software. It was introduced by |
| commit 0e2bddf9e5f9 ("ice: add ice_adapter for shared data across PFs on |
| the same NIC") and is primarily used for PTP support, as well as for |
| handling certain cross-PF synchronization. |
| |
| The original design of ice_adapter used PCI address information to |
| determine which devices should be connected. This was extended to support |
| E825C devices by commit fdb7f54700b1 ("ice: Initial support for E825C |
| hardware in ice_adapter"), which used the device ID for E825C devices |
| instead of the PCI address. |
| |
| Later, commit 0093cb194a75 ("ice: use DSN instead of PCI BDF for |
| ice_adapter index") replaced the use of Bus/Device/Function addressing with |
| use of the device serial number. |
| |
| E825C devices may appear in "Dual NAC" configuration which has multiple |
| physical devices tied to the same clock source and which need to use the |
| same ice_adapter. Unfortunately, each "NAC" has its own NVM which has its |
| own unique Device Serial Number. Thus, use of the DSN for connecting |
| ice_adapter does not work properly. It "worked" in the pre-production |
| systems because the DSN was not initialized on the test NVMs and all the |
| NACs had the same zero'd serial number. |
| |
| Since we cannot rely on the DSN, lets fall back to the logic in the |
| original E825C support which used the device ID. This is safe for E825C |
| only because of the embedded nature of the device. It isn't a discreet |
| adapter that can be plugged into an arbitrary system. All E825C devices on |
| a given system are connected to the same clock source and need to be |
| configured through the same PTP clock. |
| |
| To make this separation clear, reserve bit 63 of the 64-bit index values as |
| a "fixed index" indicator. Always clear this bit when using the device |
| serial number as an index. |
| |
| For E825C, use a fixed value defined as the 0x579C E825C backplane device |
| ID bitwise ORed with the fixed index indicator. This is slightly different |
| than the original logic of just using the device ID directly. Doing so |
| prevents a potential issue with systems where only one of the NACs is |
| connected with an external PHY over SGMII. In that case, one NAC would |
| have the E825C_SGMII device ID, but the other would not. |
| |
| Separate the determination of the full 64-bit index from the 32-bit |
| reduction logic. Provide both ice_adapter_index() and a wrapping |
| ice_adapter_xa_index() which handles reducing the index to a long on 32-bit |
| systems. As before, cache the full index value in the adapter structure to |
| warn about collisions. |
| |
| This fixes issues with E825C not initializing PTP on both NACs, due to |
| failure to connect the appropriate devices to the same ice_adapter. |
| |
| Fixes: 0093cb194a75 ("ice: use DSN instead of PCI BDF for ice_adapter index") |
| Signed-off-by: Jacob Keller <jacob.e.keller@intel.com> |
| Reviewed-by: Grzegorz Nitka <grzegorz.nitka@intel.com> |
| Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com> |
| Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com> |
| Tested-by: Rinitha S <sx.rinitha@intel.com> (A Contingent worker at Intel) |
| Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/net/ethernet/intel/ice/ice_adapter.c | 49 +++++++++++++++----- |
| drivers/net/ethernet/intel/ice/ice_adapter.h | 4 +- |
| 2 files changed, 40 insertions(+), 13 deletions(-) |
| |
| diff --git a/drivers/net/ethernet/intel/ice/ice_adapter.c b/drivers/net/ethernet/intel/ice/ice_adapter.c |
| index 66e070095d1bb..10285995c9edd 100644 |
| --- a/drivers/net/ethernet/intel/ice/ice_adapter.c |
| +++ b/drivers/net/ethernet/intel/ice/ice_adapter.c |
| @@ -13,16 +13,45 @@ |
| static DEFINE_XARRAY(ice_adapters); |
| static DEFINE_MUTEX(ice_adapters_mutex); |
| |
| -static unsigned long ice_adapter_index(u64 dsn) |
| +#define ICE_ADAPTER_FIXED_INDEX BIT_ULL(63) |
| + |
| +#define ICE_ADAPTER_INDEX_E825C \ |
| + (ICE_DEV_ID_E825C_BACKPLANE | ICE_ADAPTER_FIXED_INDEX) |
| + |
| +static u64 ice_adapter_index(struct pci_dev *pdev) |
| { |
| + switch (pdev->device) { |
| + case ICE_DEV_ID_E825C_BACKPLANE: |
| + case ICE_DEV_ID_E825C_QSFP: |
| + case ICE_DEV_ID_E825C_SFP: |
| + case ICE_DEV_ID_E825C_SGMII: |
| + /* E825C devices have multiple NACs which are connected to the |
| + * same clock source, and which must share the same |
| + * ice_adapter structure. We can't use the serial number since |
| + * each NAC has its own NVM generated with its own unique |
| + * Device Serial Number. Instead, rely on the embedded nature |
| + * of the E825C devices, and use a fixed index. This relies on |
| + * the fact that all E825C physical functions in a given |
| + * system are part of the same overall device. |
| + */ |
| + return ICE_ADAPTER_INDEX_E825C; |
| + default: |
| + return pci_get_dsn(pdev) & ~ICE_ADAPTER_FIXED_INDEX; |
| + } |
| +} |
| + |
| +static unsigned long ice_adapter_xa_index(struct pci_dev *pdev) |
| +{ |
| + u64 index = ice_adapter_index(pdev); |
| + |
| #if BITS_PER_LONG == 64 |
| - return dsn; |
| + return index; |
| #else |
| - return (u32)dsn ^ (u32)(dsn >> 32); |
| + return (u32)index ^ (u32)(index >> 32); |
| #endif |
| } |
| |
| -static struct ice_adapter *ice_adapter_new(u64 dsn) |
| +static struct ice_adapter *ice_adapter_new(struct pci_dev *pdev) |
| { |
| struct ice_adapter *adapter; |
| |
| @@ -30,7 +59,7 @@ static struct ice_adapter *ice_adapter_new(u64 dsn) |
| if (!adapter) |
| return NULL; |
| |
| - adapter->device_serial_number = dsn; |
| + adapter->index = ice_adapter_index(pdev); |
| spin_lock_init(&adapter->ptp_gltsyn_time_lock); |
| refcount_set(&adapter->refcount, 1); |
| |
| @@ -63,24 +92,23 @@ static void ice_adapter_free(struct ice_adapter *adapter) |
| */ |
| struct ice_adapter *ice_adapter_get(struct pci_dev *pdev) |
| { |
| - u64 dsn = pci_get_dsn(pdev); |
| struct ice_adapter *adapter; |
| unsigned long index; |
| int err; |
| |
| - index = ice_adapter_index(dsn); |
| + index = ice_adapter_xa_index(pdev); |
| scoped_guard(mutex, &ice_adapters_mutex) { |
| err = xa_insert(&ice_adapters, index, NULL, GFP_KERNEL); |
| if (err == -EBUSY) { |
| adapter = xa_load(&ice_adapters, index); |
| refcount_inc(&adapter->refcount); |
| - WARN_ON_ONCE(adapter->device_serial_number != dsn); |
| + WARN_ON_ONCE(adapter->index != ice_adapter_index(pdev)); |
| return adapter; |
| } |
| if (err) |
| return ERR_PTR(err); |
| |
| - adapter = ice_adapter_new(dsn); |
| + adapter = ice_adapter_new(pdev); |
| if (!adapter) |
| return ERR_PTR(-ENOMEM); |
| xa_store(&ice_adapters, index, adapter, GFP_KERNEL); |
| @@ -99,11 +127,10 @@ struct ice_adapter *ice_adapter_get(struct pci_dev *pdev) |
| */ |
| void ice_adapter_put(struct pci_dev *pdev) |
| { |
| - u64 dsn = pci_get_dsn(pdev); |
| struct ice_adapter *adapter; |
| unsigned long index; |
| |
| - index = ice_adapter_index(dsn); |
| + index = ice_adapter_xa_index(pdev); |
| scoped_guard(mutex, &ice_adapters_mutex) { |
| adapter = xa_load(&ice_adapters, index); |
| if (WARN_ON(!adapter)) |
| diff --git a/drivers/net/ethernet/intel/ice/ice_adapter.h b/drivers/net/ethernet/intel/ice/ice_adapter.h |
| index ac15c0d2bc1a4..409467847c753 100644 |
| --- a/drivers/net/ethernet/intel/ice/ice_adapter.h |
| +++ b/drivers/net/ethernet/intel/ice/ice_adapter.h |
| @@ -32,7 +32,7 @@ struct ice_port_list { |
| * @refcount: Reference count. struct ice_pf objects hold the references. |
| * @ctrl_pf: Control PF of the adapter |
| * @ports: Ports list |
| - * @device_serial_number: DSN cached for collision detection on 32bit systems |
| + * @index: 64-bit index cached for collision detection on 32bit systems |
| */ |
| struct ice_adapter { |
| refcount_t refcount; |
| @@ -41,7 +41,7 @@ struct ice_adapter { |
| |
| struct ice_pf *ctrl_pf; |
| struct ice_port_list ports; |
| - u64 device_serial_number; |
| + u64 index; |
| }; |
| |
| struct ice_adapter *ice_adapter_get(struct pci_dev *pdev); |
| -- |
| 2.50.1 |
| |