mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson
synced 2025-09-06 13:09:58 +00:00
ice: add ice_adapter for shared data across PFs on the same NIC
There is a need for synchronization between ice PFs on the same physical adapter. Add a "struct ice_adapter" for holding data shared between PFs of the same multifunction PCI device. The struct is refcounted - each ice_pf holds a reference to it. Its first use will be for PTP. I expect it will be useful also to improve the ugliness that is ice_prot_id_tbl. Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com> Signed-off-by: Michal Schmidt <mschmidt@redhat.com> Tested-by: Pucha Himasekhar Reddy <himasekharx.reddy.pucha@intel.com> (A Contingent worker at Intel) Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
This commit is contained in:
parent
3b4cf29bda
commit
0e2bddf9e5
@ -36,7 +36,8 @@ ice-y := ice_main.o \
|
||||
ice_repr.o \
|
||||
ice_tc_lib.o \
|
||||
ice_fwlog.o \
|
||||
ice_debugfs.o
|
||||
ice_debugfs.o \
|
||||
ice_adapter.o
|
||||
ice-$(CONFIG_PCI_IOV) += \
|
||||
ice_sriov.o \
|
||||
ice_virtchnl.o \
|
||||
|
@ -77,6 +77,7 @@
|
||||
#include "ice_gnss.h"
|
||||
#include "ice_irq.h"
|
||||
#include "ice_dpll.h"
|
||||
#include "ice_adapter.h"
|
||||
|
||||
#define ICE_BAR0 0
|
||||
#define ICE_REQ_DESC_MULTIPLE 32
|
||||
@ -537,6 +538,7 @@ struct ice_agg_node {
|
||||
|
||||
struct ice_pf {
|
||||
struct pci_dev *pdev;
|
||||
struct ice_adapter *adapter;
|
||||
|
||||
struct devlink_region *nvm_region;
|
||||
struct devlink_region *sram_region;
|
||||
|
114
drivers/net/ethernet/intel/ice/ice_adapter.c
Normal file
114
drivers/net/ethernet/intel/ice/ice_adapter.c
Normal file
@ -0,0 +1,114 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright Red Hat
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/xarray.h>
|
||||
#include "ice_adapter.h"
|
||||
|
||||
static DEFINE_XARRAY(ice_adapters);
|
||||
|
||||
/* PCI bus number is 8 bits. Slot is 5 bits. Domain can have the rest. */
|
||||
#define INDEX_FIELD_DOMAIN GENMASK(BITS_PER_LONG - 1, 13)
|
||||
#define INDEX_FIELD_BUS GENMASK(12, 5)
|
||||
#define INDEX_FIELD_SLOT GENMASK(4, 0)
|
||||
|
||||
static unsigned long ice_adapter_index(const struct pci_dev *pdev)
|
||||
{
|
||||
unsigned int domain = pci_domain_nr(pdev->bus);
|
||||
|
||||
WARN_ON(domain > FIELD_MAX(INDEX_FIELD_DOMAIN));
|
||||
|
||||
return FIELD_PREP(INDEX_FIELD_DOMAIN, domain) |
|
||||
FIELD_PREP(INDEX_FIELD_BUS, pdev->bus->number) |
|
||||
FIELD_PREP(INDEX_FIELD_SLOT, PCI_SLOT(pdev->devfn));
|
||||
}
|
||||
|
||||
static struct ice_adapter *ice_adapter_new(void)
|
||||
{
|
||||
struct ice_adapter *adapter;
|
||||
|
||||
adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
|
||||
if (!adapter)
|
||||
return NULL;
|
||||
|
||||
refcount_set(&adapter->refcount, 1);
|
||||
|
||||
return adapter;
|
||||
}
|
||||
|
||||
static void ice_adapter_free(struct ice_adapter *adapter)
|
||||
{
|
||||
kfree(adapter);
|
||||
}
|
||||
|
||||
DEFINE_FREE(ice_adapter_free, struct ice_adapter*, if (_T) ice_adapter_free(_T))
|
||||
|
||||
/**
|
||||
* ice_adapter_get - Get a shared ice_adapter structure.
|
||||
* @pdev: Pointer to the pci_dev whose driver is getting the ice_adapter.
|
||||
*
|
||||
* Gets a pointer to a shared ice_adapter structure. Physical functions (PFs)
|
||||
* of the same multi-function PCI device share one ice_adapter structure.
|
||||
* The ice_adapter is reference-counted. The PF driver must use ice_adapter_put
|
||||
* to release its reference.
|
||||
*
|
||||
* Context: Process, may sleep.
|
||||
* Return: Pointer to ice_adapter on success.
|
||||
* ERR_PTR() on error. -ENOMEM is the only possible error.
|
||||
*/
|
||||
struct ice_adapter *ice_adapter_get(const struct pci_dev *pdev)
|
||||
{
|
||||
struct ice_adapter *ret, __free(ice_adapter_free) *adapter = NULL;
|
||||
unsigned long index = ice_adapter_index(pdev);
|
||||
|
||||
adapter = ice_adapter_new();
|
||||
if (!adapter)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
xa_lock(&ice_adapters);
|
||||
ret = __xa_cmpxchg(&ice_adapters, index, NULL, adapter, GFP_KERNEL);
|
||||
if (xa_is_err(ret)) {
|
||||
ret = ERR_PTR(xa_err(ret));
|
||||
goto unlock;
|
||||
}
|
||||
if (ret) {
|
||||
refcount_inc(&ret->refcount);
|
||||
goto unlock;
|
||||
}
|
||||
ret = no_free_ptr(adapter);
|
||||
unlock:
|
||||
xa_unlock(&ice_adapters);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_adapter_put - Release a reference to the shared ice_adapter structure.
|
||||
* @pdev: Pointer to the pci_dev whose driver is releasing the ice_adapter.
|
||||
*
|
||||
* Releases the reference to ice_adapter previously obtained with
|
||||
* ice_adapter_get.
|
||||
*
|
||||
* Context: Any.
|
||||
*/
|
||||
void ice_adapter_put(const struct pci_dev *pdev)
|
||||
{
|
||||
unsigned long index = ice_adapter_index(pdev);
|
||||
struct ice_adapter *adapter;
|
||||
|
||||
xa_lock(&ice_adapters);
|
||||
adapter = xa_load(&ice_adapters, index);
|
||||
if (WARN_ON(!adapter))
|
||||
goto unlock;
|
||||
|
||||
if (!refcount_dec_and_test(&adapter->refcount))
|
||||
goto unlock;
|
||||
|
||||
WARN_ON(__xa_erase(&ice_adapters, index) != adapter);
|
||||
ice_adapter_free(adapter);
|
||||
unlock:
|
||||
xa_unlock(&ice_adapters);
|
||||
}
|
22
drivers/net/ethernet/intel/ice/ice_adapter.h
Normal file
22
drivers/net/ethernet/intel/ice/ice_adapter.h
Normal file
@ -0,0 +1,22 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* SPDX-FileCopyrightText: Copyright Red Hat */
|
||||
|
||||
#ifndef _ICE_ADAPTER_H_
|
||||
#define _ICE_ADAPTER_H_
|
||||
|
||||
#include <linux/refcount_types.h>
|
||||
|
||||
struct pci_dev;
|
||||
|
||||
/**
|
||||
* struct ice_adapter - PCI adapter resources shared across PFs
|
||||
* @refcount: Reference count. struct ice_pf objects hold the references.
|
||||
*/
|
||||
struct ice_adapter {
|
||||
refcount_t refcount;
|
||||
};
|
||||
|
||||
struct ice_adapter *ice_adapter_get(const struct pci_dev *pdev);
|
||||
void ice_adapter_put(const struct pci_dev *pdev);
|
||||
|
||||
#endif /* _ICE_ADAPTER_H */
|
@ -5093,6 +5093,7 @@ static int
|
||||
ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct ice_adapter *adapter;
|
||||
struct ice_pf *pf;
|
||||
struct ice_hw *hw;
|
||||
int err;
|
||||
@ -5145,7 +5146,12 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
|
||||
|
||||
pci_set_master(pdev);
|
||||
|
||||
adapter = ice_adapter_get(pdev);
|
||||
if (IS_ERR(adapter))
|
||||
return PTR_ERR(adapter);
|
||||
|
||||
pf->pdev = pdev;
|
||||
pf->adapter = adapter;
|
||||
pci_set_drvdata(pdev, pf);
|
||||
set_bit(ICE_DOWN, pf->state);
|
||||
/* Disable service task until DOWN bit is cleared */
|
||||
@ -5196,6 +5202,7 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
|
||||
err_load:
|
||||
ice_deinit(pf);
|
||||
err_init:
|
||||
ice_adapter_put(pdev);
|
||||
pci_disable_device(pdev);
|
||||
return err;
|
||||
}
|
||||
@ -5302,6 +5309,7 @@ static void ice_remove(struct pci_dev *pdev)
|
||||
ice_setup_mc_magic_wake(pf);
|
||||
ice_set_wake(pf);
|
||||
|
||||
ice_adapter_put(pdev);
|
||||
pci_disable_device(pdev);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user