Import of kernel-6.12.0-211.20.1.el10_2

This commit is contained in:
almalinux-bot-kernel 2026-06-09 05:29:02 +00:00
parent f33fa76b71
commit c23a26575f
194 changed files with 4881 additions and 2325 deletions

View File

@ -65,35 +65,43 @@ request, where user provides attributes that result in single pin match.
Pin selection
=============
In general, selected pin (the one which signal is driving the dpll
device) can be obtained from ``DPLL_A_PIN_STATE`` attribute, and only
one pin shall be in ``DPLL_PIN_STATE_CONNECTED`` state for any dpll
device.
Pin state (``DPLL_A_PIN_STATE``) reflects the administrative intent set
by the user. Pin operational state (``DPLL_A_PIN_OPERSTATE``) reflects
what the hardware is actually doing with the pin.
Pin selection can be done either manually or automatically, depending
on hardware capabilities and active dpll device work mode
(``DPLL_A_MODE`` attribute). The consequence is that there are
differences for each mode in terms of available pin states, as well as
for the states the user can request for a dpll device.
differences for each mode in terms of available pin states the user can
request for a dpll device.
In manual mode (``DPLL_MODE_MANUAL``) the user can request or receive
one of following pin states:
In manual mode (``DPLL_MODE_MANUAL``) the user can request one of
following pin states:
- ``DPLL_PIN_STATE_CONNECTED`` - the pin is used to drive dpll device
- ``DPLL_PIN_STATE_DISCONNECTED`` - the pin is not used to drive dpll
- ``DPLL_PIN_STATE_CONNECTED`` - the pin is selected to drive dpll
device
- ``DPLL_PIN_STATE_DISCONNECTED`` - the pin is not selected to drive
dpll device
In automatic mode (``DPLL_MODE_AUTOMATIC``) the user can request or
receive one of following pin states:
In automatic mode (``DPLL_MODE_AUTOMATIC``) the user can request one of
following pin states:
- ``DPLL_PIN_STATE_SELECTABLE`` - the pin shall be considered as valid
input for automatic selection algorithm
- ``DPLL_PIN_STATE_DISCONNECTED`` - the pin shall be not considered as
a valid input for automatic selection algorithm
In automatic mode (``DPLL_MODE_AUTOMATIC``) the user can only receive
pin state ``DPLL_PIN_STATE_CONNECTED`` once automatic selection
algorithm locks a dpll device with one of the inputs.
The actual hardware status of a pin is reported via the operational
state (``DPLL_A_PIN_OPERSTATE``) attribute nested under the parent
device:
- ``DPLL_PIN_OPERSTATE_ACTIVE`` - pin is qualified and actively used
by the DPLL
- ``DPLL_PIN_OPERSTATE_STANDBY`` - pin is qualified but not actively
used by the DPLL
- ``DPLL_PIN_OPERSTATE_NO_SIGNAL`` - pin does not have a valid signal
- ``DPLL_PIN_OPERSTATE_QUAL_FAILED`` - pin signal failed qualification
checks
Shared pins
===========
@ -250,6 +258,44 @@ in the ``DPLL_A_PIN_PHASE_OFFSET`` attribute.
``DPLL_A_PHASE_OFFSET_MONITOR`` attr state of a feature
=============================== ========================
Fractional frequency offset
===========================
The fractional frequency offset (FFO) is reported through two attributes
that carry the same measurement at different precisions:
- ``DPLL_A_PIN_FRACTIONAL_FREQUENCY_OFFSET`` in PPM (parts per million)
- ``DPLL_A_PIN_FRACTIONAL_FREQUENCY_OFFSET_PPT`` in PPT (parts per trillion)
Both attributes appear at the top level of a pin and inside each
``pin-parent-device`` nest. Two FFO types are defined:
- ``DPLL_FFO_PORT_RXTX_RATE`` - RX vs TX symbol rate offset (top-level)
- ``DPLL_FFO_PIN_DEVICE`` - pin vs parent DPLL offset (per-parent)
The driver declares which types it supports via the ``supported_ffo``
bitmask in ``struct dpll_pin_ops``. The core only calls the ``ffo_get``
callback for types the driver has opted into. The requested type is
passed to the driver in the ``struct dpll_ffo_param``.
Frequency monitor
=================
Some DPLL devices may offer the capability to measure the actual
frequency of all available input pins. The attribute and current feature state
shall be included in the response message of the ``DPLL_CMD_DEVICE_GET``
command for supported DPLL devices. In such cases, users can also control
the feature using the ``DPLL_CMD_DEVICE_SET`` command by setting the
``enum dpll_feature_state`` values for the attribute.
Once enabled the measured input frequency for each input pin shall be
returned in the ``DPLL_A_PIN_MEASURED_FREQUENCY`` attribute. The value
is in millihertz (mHz), using ``DPLL_PIN_MEASURED_FREQUENCY_DIVIDER``
as the divider.
=============================== ========================
``DPLL_A_FREQUENCY_MONITOR`` attr state of a feature
=============================== ========================
Embedded SYNC
=============
@ -411,6 +457,8 @@ according to attribute purpose.
``DPLL_A_PIN_STATE`` attr state of pin on the parent
pin
``DPLL_A_PIN_CAPABILITIES`` attr bitmask of pin capabilities
``DPLL_A_PIN_MEASURED_FREQUENCY`` attr measured frequency of
an input pin in mHz
==================================== ==================================
==================================== =================================

View File

@ -212,6 +212,27 @@ definitions:
name: selectable
doc: pin enabled for automatic input selection
render-max: true
-
type: enum
name: pin-operstate
doc: |
defines possible operational states of a pin with respect to its
parent DPLL device, valid values for DPLL_A_PIN_OPERSTATE attribute
entries:
-
name: active
doc: pin is qualified and actively used by the DPLL
value: 1
-
name: standby
doc: pin is qualified but not actively used by the DPLL
-
name: no-signal
doc: pin does not have a valid signal
-
name: qual-failed
doc: pin signal failed qualification (e.g. frequency or phase monitor)
render-max: true
-
type: flags
name: pin-capabilities
@ -240,6 +261,20 @@ definitions:
integer part of a measured phase offset value.
Value of (DPLL_A_PHASE_OFFSET % DPLL_PHASE_OFFSET_DIVIDER) is a
fractional part of a measured phase offset value.
-
type: const
name: pin-measured-frequency-divider
value: 1000
doc: |
pin measured frequency divider allows userspace to calculate
a value of measured input frequency as a fractional value with
three digit decimal precision (millihertz).
Value of (DPLL_A_PIN_MEASURED_FREQUENCY /
DPLL_PIN_MEASURED_FREQUENCY_DIVIDER) is an integer part of
a measured frequency value.
Value of (DPLL_A_PIN_MEASURED_FREQUENCY %
DPLL_PIN_MEASURED_FREQUENCY_DIVIDER) is a fractional part of
a measured frequency value.
-
type: enum
name: feature-state
@ -319,6 +354,13 @@ attribute-sets:
name: phase-offset-avg-factor
type: u32
doc: Averaging factor applied to calculation of reported phase offset.
-
name: frequency-monitor
type: u32
enum: feature-state
doc: Current or desired state of the frequency monitor feature.
If enabled, dpll device shall measure all currently available
inputs for their actual input frequency.
-
name: pin
enum-name: dpll_a_pin
@ -406,12 +448,14 @@ attribute-sets:
name: fractional-frequency-offset
type: sint
doc: |
The FFO (Fractional Frequency Offset) between the RX and TX
symbol rate on the media associated with the pin:
(rx_frequency-tx_frequency)/rx_frequency
The FFO (Fractional Frequency Offset) of the pin.
At top level this represents the RX vs TX symbol rate
offset on the media associated with the pin. Inside
the pin-parent-device nest it represents the frequency
offset between the pin and its parent DPLL device.
Value is in PPM (parts per million).
This may be implemented for example for pin of type
PIN_TYPE_SYNCE_ETH_PORT.
This is a lower-precision version of
fractional-frequency-offset-ppt.
-
name: esync-frequency
type: u64
@ -450,12 +494,33 @@ attribute-sets:
name: fractional-frequency-offset-ppt
type: sint
doc: |
The FFO (Fractional Frequency Offset) of the pin with respect to
the nominal frequency.
Value = (frequency_measured - frequency_nominal) / frequency_nominal
The FFO (Fractional Frequency Offset) of the pin.
At top level this represents the RX vs TX symbol rate
offset on the media associated with the pin. Inside
the pin-parent-device nest it represents the frequency
offset between the pin and its parent DPLL device.
Value is in PPT (parts per trillion, 10^-12).
Note: This attribute provides higher resolution than the standard
fractional-frequency-offset (which is in PPM).
This is a higher-precision version of
fractional-frequency-offset.
-
name: measured-frequency
type: u64
doc: |
The measured frequency of the input pin in millihertz (mHz).
Value of (DPLL_A_PIN_MEASURED_FREQUENCY /
DPLL_PIN_MEASURED_FREQUENCY_DIVIDER) is an integer part (Hz)
of a measured frequency value.
Value of (DPLL_A_PIN_MEASURED_FREQUENCY %
DPLL_PIN_MEASURED_FREQUENCY_DIVIDER) is a fractional part
of a measured frequency value.
-
name: operstate
type: u32
enum: pin-operstate
doc: |
Operational state of the pin with respect to its parent DPLL
device. Unlike state (which reflects the administrative intent),
operstate reflects the actual hardware status.
-
name: pin-parent-device
@ -469,8 +534,14 @@ attribute-sets:
name: prio
-
name: state
-
name: operstate
-
name: phase-offset
-
name: fractional-frequency-offset
-
name: fractional-frequency-offset-ppt
-
name: pin-parent-pin
subset-of: pin
@ -544,6 +615,7 @@ operations:
- type
- phase-offset-monitor
- phase-offset-avg-factor
- frequency-monitor
dump:
reply: *dev-attrs
@ -563,6 +635,7 @@ operations:
- mode
- phase-offset-monitor
- phase-offset-avg-factor
- frequency-monitor
-
name: device-create-ntf
doc: Notification about device appearing
@ -643,6 +716,7 @@ operations:
- esync-frequency-supported
- esync-pulse
- reference-sync
- measured-frequency
dump:
request:

View File

@ -111,6 +111,7 @@ vmlinux-objs-$(CONFIG_EFI_SBAT) += $(obj)/sbat.o
ifdef CONFIG_EFI_SBAT
$(obj)/sbat.o: $(CONFIG_EFI_SBAT_FILE)
AFLAGS_sbat.o += -I $(srctree)
endif
$(obj)/vmlinux: $(vmlinux-objs-y) $(vmlinux-libs-y) FORCE

View File

@ -3040,12 +3040,6 @@ static int mmu_set_spte(struct kvm_vcpu *vcpu, struct kvm_memory_slot *slot,
bool prefetch = !fault || fault->prefetch;
bool write_fault = fault && fault->write;
if (unlikely(is_noslot_pfn(pfn))) {
vcpu->stat.pf_mmio_spte_created++;
mark_mmio_spte(vcpu, sptep, gfn, pte_access);
return RET_PF_EMULATE;
}
if (is_shadow_present_pte(*sptep)) {
if (prefetch && is_last_spte(*sptep, level) &&
pfn == spte_to_pfn(*sptep))
@ -3062,13 +3056,22 @@ static int mmu_set_spte(struct kvm_vcpu *vcpu, struct kvm_memory_slot *slot,
child = spte_to_child_sp(pte);
drop_parent_pte(vcpu->kvm, child, sptep);
flush = true;
} else if (WARN_ON_ONCE(pfn != spte_to_pfn(*sptep))) {
} else if (pfn != spte_to_pfn(*sptep)) {
WARN_ON_ONCE(vcpu->arch.mmu->root_role.direct);
drop_spte(vcpu->kvm, sptep);
flush = true;
} else
was_rmapped = 1;
}
if (unlikely(is_noslot_pfn(pfn))) {
vcpu->stat.pf_mmio_spte_created++;
mark_mmio_spte(vcpu, sptep, gfn, pte_access);
if (flush)
kvm_flush_remote_tlbs_gfn(vcpu->kvm, gfn, level);
return RET_PF_EMULATE;
}
wrprot = make_spte(vcpu, sp, slot, pte_access, gfn, pfn, *sptep, prefetch,
false, host_writable, &spte);

View File

@ -2970,7 +2970,7 @@ CONFIG_AMD_XGBE=m
CONFIG_NET_XGENE=m
CONFIG_NET_XGENE_V2=m
CONFIG_NET_VENDOR_AQUANTIA=y
# CONFIG_AQTION is not set
CONFIG_AQTION=m
# CONFIG_NET_VENDOR_ARC is not set
CONFIG_NET_VENDOR_ASIX=y
# CONFIG_SPI_AX88796C is not set

View File

@ -2965,7 +2965,7 @@ CONFIG_AMD_XGBE=m
CONFIG_NET_XGENE=m
CONFIG_NET_XGENE_V2=m
CONFIG_NET_VENDOR_AQUANTIA=y
# CONFIG_AQTION is not set
CONFIG_AQTION=m
# CONFIG_NET_VENDOR_ARC is not set
CONFIG_NET_VENDOR_ASIX=y
# CONFIG_SPI_AX88796C is not set

View File

@ -2973,7 +2973,7 @@ CONFIG_AMD_XGBE=m
CONFIG_NET_XGENE=m
CONFIG_NET_XGENE_V2=m
CONFIG_NET_VENDOR_AQUANTIA=y
# CONFIG_AQTION is not set
CONFIG_AQTION=m
# CONFIG_NET_VENDOR_ARC is not set
CONFIG_NET_VENDOR_ASIX=y
# CONFIG_SPI_AX88796C is not set

View File

@ -2957,7 +2957,7 @@ CONFIG_AMD_XGBE=m
CONFIG_NET_XGENE=m
CONFIG_NET_XGENE_V2=m
CONFIG_NET_VENDOR_AQUANTIA=y
# CONFIG_AQTION is not set
CONFIG_AQTION=m
# CONFIG_NET_VENDOR_ARC is not set
CONFIG_NET_VENDOR_ASIX=y
# CONFIG_SPI_AX88796C is not set

View File

@ -2952,7 +2952,7 @@ CONFIG_AMD_XGBE=m
CONFIG_NET_XGENE=m
CONFIG_NET_XGENE_V2=m
CONFIG_NET_VENDOR_AQUANTIA=y
# CONFIG_AQTION is not set
CONFIG_AQTION=m
# CONFIG_NET_VENDOR_ARC is not set
CONFIG_NET_VENDOR_ASIX=y
# CONFIG_SPI_AX88796C is not set

View File

@ -2959,7 +2959,7 @@ CONFIG_AMD_XGBE=m
CONFIG_NET_XGENE=m
CONFIG_NET_XGENE_V2=m
CONFIG_NET_VENDOR_AQUANTIA=y
# CONFIG_AQTION is not set
CONFIG_AQTION=m
# CONFIG_NET_VENDOR_ARC is not set
CONFIG_NET_VENDOR_ASIX=y
# CONFIG_SPI_AX88796C is not set

View File

@ -2954,7 +2954,7 @@ CONFIG_AMD_XGBE=m
CONFIG_NET_XGENE=m
CONFIG_NET_XGENE_V2=m
CONFIG_NET_VENDOR_AQUANTIA=y
# CONFIG_AQTION is not set
CONFIG_AQTION=m
# CONFIG_NET_VENDOR_ARC is not set
CONFIG_NET_VENDOR_ASIX=y
# CONFIG_SPI_AX88796C is not set

View File

@ -2968,7 +2968,7 @@ CONFIG_AMD_XGBE=m
CONFIG_NET_XGENE=m
CONFIG_NET_XGENE_V2=m
CONFIG_NET_VENDOR_AQUANTIA=y
# CONFIG_AQTION is not set
CONFIG_AQTION=m
# CONFIG_NET_VENDOR_ARC is not set
CONFIG_NET_VENDOR_ASIX=y
# CONFIG_SPI_AX88796C is not set

View File

@ -2559,7 +2559,7 @@ CONFIG_NET_VENDOR_AMAZON=y
# CONFIG_ENA_ETHERNET is not set
# CONFIG_NET_VENDOR_AMD is not set
CONFIG_NET_VENDOR_AQUANTIA=y
# CONFIG_AQTION is not set
CONFIG_AQTION=m
# CONFIG_NET_VENDOR_ARC is not set
CONFIG_NET_VENDOR_ASIX=y
CONFIG_NET_VENDOR_ATHEROS=y

View File

@ -2561,7 +2561,7 @@ CONFIG_NET_VENDOR_AMAZON=y
# CONFIG_ENA_ETHERNET is not set
# CONFIG_NET_VENDOR_AMD is not set
CONFIG_NET_VENDOR_AQUANTIA=y
# CONFIG_AQTION is not set
CONFIG_AQTION=m
# CONFIG_NET_VENDOR_ARC is not set
CONFIG_NET_VENDOR_ASIX=y
CONFIG_NET_VENDOR_ATHEROS=y

View File

@ -2599,7 +2599,7 @@ CONFIG_NET_VENDOR_AMAZON=y
# CONFIG_ENA_ETHERNET is not set
# CONFIG_NET_VENDOR_AMD is not set
CONFIG_NET_VENDOR_AQUANTIA=y
# CONFIG_AQTION is not set
CONFIG_AQTION=m
# CONFIG_NET_VENDOR_ARC is not set
CONFIG_NET_VENDOR_ASIX=y
CONFIG_NET_VENDOR_ATHEROS=y

View File

@ -2595,7 +2595,7 @@ CONFIG_NET_VENDOR_AMAZON=y
# CONFIG_ENA_ETHERNET is not set
# CONFIG_NET_VENDOR_AMD is not set
CONFIG_NET_VENDOR_AQUANTIA=y
# CONFIG_AQTION is not set
CONFIG_AQTION=m
# CONFIG_NET_VENDOR_ARC is not set
CONFIG_NET_VENDOR_ASIX=y
CONFIG_NET_VENDOR_ATHEROS=y

View File

@ -2022,7 +2022,7 @@ CONFIG_ETHERNET=y
CONFIG_NET_VENDOR_AMAZON=y
# CONFIG_NET_VENDOR_AMD is not set
CONFIG_NET_VENDOR_AQUANTIA=y
# CONFIG_AQTION is not set
CONFIG_AQTION=m
# CONFIG_NET_VENDOR_ARC is not set
CONFIG_NET_VENDOR_ASIX=y
# CONFIG_NET_VENDOR_ATHEROS is not set

View File

@ -2046,7 +2046,7 @@ CONFIG_ETHERNET=y
CONFIG_NET_VENDOR_AMAZON=y
# CONFIG_NET_VENDOR_AMD is not set
CONFIG_NET_VENDOR_AQUANTIA=y
# CONFIG_AQTION is not set
CONFIG_AQTION=m
# CONFIG_NET_VENDOR_ARC is not set
CONFIG_NET_VENDOR_ASIX=y
# CONFIG_NET_VENDOR_ATHEROS is not set

View File

@ -228,6 +228,7 @@ config CRYPTO_AUTHENC
select CRYPTO_SKCIPHER
select CRYPTO_MANAGER
select CRYPTO_HASH
select CRYPTO_NULL
help
Authenc: Combined mode wrapper for IPsec.
@ -1438,6 +1439,7 @@ config CRYPTO_USER_API_AEAD
depends on NET
select CRYPTO_AEAD
select CRYPTO_SKCIPHER
select CRYPTO_NULL
select CRYPTO_USER_API
help
Enable the userspace interface for AEAD cipher algorithms.

View File

@ -623,8 +623,10 @@ static int af_alg_alloc_tsgl(struct sock *sk)
sg_init_table(sgl->sg, MAX_SGL_ENTS + 1);
sgl->cur = 0;
if (sg)
if (sg) {
sg_unmark_end(sg + MAX_SGL_ENTS - 1);
sg_chain(sg, MAX_SGL_ENTS + 1, sgl->sg);
}
list_add_tail(&sgl->list, &ctx->tsgl_list);
}
@ -1220,6 +1222,8 @@ int af_alg_get_rsgl(struct sock *sk, struct msghdr *msg, int flags,
seglen = min_t(size_t, (maxsize - len),
msg_data_left(msg));
/* Never pin more pages than the remaining RX accounting budget. */
seglen = min_t(size_t, seglen, af_alg_rcvbuf(sk));
if (list_empty(&areq->rsgl_list)) {
rsgl = &areq->first_rsgl;

View File

@ -26,6 +26,8 @@
#include <crypto/internal/aead.h>
#include <crypto/scatterwalk.h>
#include <crypto/if_alg.h>
#include <crypto/skcipher.h>
#include <crypto/null.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/kernel.h>
@ -34,13 +36,19 @@
#include <linux/net.h>
#include <net/sock.h>
struct aead_tfm {
struct crypto_aead *aead;
struct crypto_sync_skcipher *null_tfm;
};
static inline bool aead_sufficient_data(struct sock *sk)
{
struct alg_sock *ask = alg_sk(sk);
struct sock *psk = ask->parent;
struct alg_sock *pask = alg_sk(psk);
struct af_alg_ctx *ctx = ask->private;
struct crypto_aead *tfm = pask->private;
struct aead_tfm *aeadc = pask->private;
struct crypto_aead *tfm = aeadc->aead;
unsigned int as = crypto_aead_authsize(tfm);
/*
@ -56,12 +64,27 @@ static int aead_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
struct alg_sock *ask = alg_sk(sk);
struct sock *psk = ask->parent;
struct alg_sock *pask = alg_sk(psk);
struct crypto_aead *tfm = pask->private;
struct aead_tfm *aeadc = pask->private;
struct crypto_aead *tfm = aeadc->aead;
unsigned int ivsize = crypto_aead_ivsize(tfm);
return af_alg_sendmsg(sock, msg, size, ivsize);
}
static int crypto_aead_copy_sgl(struct crypto_sync_skcipher *null_tfm,
struct scatterlist *src,
struct scatterlist *dst, unsigned int len)
{
SYNC_SKCIPHER_REQUEST_ON_STACK(skreq, null_tfm);
skcipher_request_set_sync_tfm(skreq, null_tfm);
skcipher_request_set_callback(skreq, CRYPTO_TFM_REQ_MAY_SLEEP,
NULL, NULL);
skcipher_request_set_crypt(skreq, src, dst, len, NULL);
return crypto_skcipher_encrypt(skreq);
}
static int _aead_recvmsg(struct socket *sock, struct msghdr *msg,
size_t ignored, int flags)
{
@ -70,7 +93,9 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg,
struct sock *psk = ask->parent;
struct alg_sock *pask = alg_sk(psk);
struct af_alg_ctx *ctx = ask->private;
struct crypto_aead *tfm = pask->private;
struct aead_tfm *aeadc = pask->private;
struct crypto_aead *tfm = aeadc->aead;
struct crypto_sync_skcipher *null_tfm = aeadc->null_tfm;
unsigned int as = crypto_aead_authsize(tfm);
unsigned int ivsize = crypto_aead_ivsize(tfm);
struct af_alg_async_req *areq;
@ -150,7 +175,7 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg,
if (usedpages < outlen) {
size_t less = outlen - usedpages;
if (used < less) {
if (used < less + (ctx->enc ? 0 : as)) {
err = -EINVAL;
goto free;
}
@ -189,7 +214,10 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg,
/* Use the RX SGL as source (and destination) for crypto op. */
rsgl_src = areq->first_rsgl.sgl.sgt.sgl;
memcpy_sglist(rsgl_src, tsgl_src, ctx->aead_assoclen);
err = crypto_aead_copy_sgl(null_tfm, tsgl_src, rsgl_src,
ctx->aead_assoclen);
if (err)
goto free;
/* Initialize the crypto operation */
aead_request_set_crypt(&areq->cra_u.aead_req, tsgl_src,
@ -292,7 +320,7 @@ static int aead_check_key(struct socket *sock)
int err = 0;
struct sock *psk;
struct alg_sock *pask;
struct crypto_aead *tfm;
struct aead_tfm *tfm;
struct sock *sk = sock->sk;
struct alg_sock *ask = alg_sk(sk);
@ -306,7 +334,7 @@ static int aead_check_key(struct socket *sock)
err = -ENOKEY;
lock_sock_nested(psk, SINGLE_DEPTH_NESTING);
if (crypto_aead_get_flags(tfm) & CRYPTO_TFM_NEED_KEY)
if (crypto_aead_get_flags(tfm->aead) & CRYPTO_TFM_NEED_KEY)
goto unlock;
atomic_dec(&pask->nokey_refcnt);
@ -367,22 +395,54 @@ static struct proto_ops algif_aead_ops_nokey = {
static void *aead_bind(const char *name, u32 type, u32 mask)
{
return crypto_alloc_aead(name, type, mask);
struct aead_tfm *tfm;
struct crypto_aead *aead;
struct crypto_sync_skcipher *null_tfm;
tfm = kzalloc(sizeof(*tfm), GFP_KERNEL);
if (!tfm)
return ERR_PTR(-ENOMEM);
aead = crypto_alloc_aead(name, type, mask);
if (IS_ERR(aead)) {
kfree(tfm);
return ERR_CAST(aead);
}
null_tfm = crypto_get_default_null_skcipher();
if (IS_ERR(null_tfm)) {
crypto_free_aead(aead);
kfree(tfm);
return ERR_CAST(null_tfm);
}
tfm->aead = aead;
tfm->null_tfm = null_tfm;
return tfm;
}
static void aead_release(void *private)
{
crypto_free_aead(private);
struct aead_tfm *tfm = private;
crypto_free_aead(tfm->aead);
crypto_put_default_null_skcipher();
kfree(tfm);
}
static int aead_setauthsize(void *private, unsigned int authsize)
{
return crypto_aead_setauthsize(private, authsize);
struct aead_tfm *tfm = private;
return crypto_aead_setauthsize(tfm->aead, authsize);
}
static int aead_setkey(void *private, const u8 *key, unsigned int keylen)
{
return crypto_aead_setkey(private, key, keylen);
struct aead_tfm *tfm = private;
return crypto_aead_setkey(tfm->aead, key, keylen);
}
static void aead_sock_destruct(struct sock *sk)
@ -391,7 +451,8 @@ static void aead_sock_destruct(struct sock *sk)
struct af_alg_ctx *ctx = ask->private;
struct sock *psk = ask->parent;
struct alg_sock *pask = alg_sk(psk);
struct crypto_aead *tfm = pask->private;
struct aead_tfm *aeadc = pask->private;
struct crypto_aead *tfm = aeadc->aead;
unsigned int ivlen = crypto_aead_ivsize(tfm);
af_alg_pull_tsgl(sk, ctx->used, NULL);
@ -404,9 +465,10 @@ static int aead_accept_parent_nokey(void *private, struct sock *sk)
{
struct af_alg_ctx *ctx;
struct alg_sock *ask = alg_sk(sk);
struct crypto_aead *tfm = private;
struct aead_tfm *tfm = private;
struct crypto_aead *aead = tfm->aead;
unsigned int len = sizeof(*ctx);
unsigned int ivlen = crypto_aead_ivsize(tfm);
unsigned int ivlen = crypto_aead_ivsize(aead);
ctx = sock_kmalloc(sk, len, GFP_KERNEL);
if (!ctx)
@ -433,9 +495,9 @@ static int aead_accept_parent_nokey(void *private, struct sock *sk)
static int aead_accept_parent(void *private, struct sock *sk)
{
struct crypto_aead *tfm = private;
struct aead_tfm *tfm = private;
if (crypto_aead_get_flags(tfm) & CRYPTO_TFM_NEED_KEY)
if (crypto_aead_get_flags(tfm->aead) & CRYPTO_TFM_NEED_KEY)
return -ENOKEY;
return aead_accept_parent_nokey(private, sk);

View File

@ -130,6 +130,11 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg,
* full block size buffers.
*/
if (ctx->more || len < ctx->used) {
if (len < bs) {
err = -EINVAL;
goto free;
}
len -= len % bs;
cflags |= CRYPTO_SKCIPHER_REQ_NOTFINAL;
}

View File

@ -11,6 +11,7 @@
#include <crypto/public_key.h>
#include <linux/seq_file.h>
#include <linux/module.h>
#include <linux/overflow.h>
#include <linux/slab.h>
#include <linux/ctype.h>
#include <keys/system_keyring.h>
@ -151,12 +152,17 @@ struct asymmetric_key_id *asymmetric_key_generate_id(const void *val_1,
size_t len_2)
{
struct asymmetric_key_id *kid;
size_t kid_sz;
size_t len;
kid = kmalloc(sizeof(struct asymmetric_key_id) + len_1 + len_2,
GFP_KERNEL);
if (check_add_overflow(len_1, len_2, &len))
return ERR_PTR(-EOVERFLOW);
if (check_add_overflow(sizeof(struct asymmetric_key_id), len, &kid_sz))
return ERR_PTR(-EOVERFLOW);
kid = kmalloc(kid_sz, GFP_KERNEL);
if (!kid)
return ERR_PTR(-ENOMEM);
kid->len = len_1 + len_2;
kid->len = len;
memcpy(kid->data, val_1, len_1);
memcpy(kid->data + len_1, val_2, len_2);
return kid;

View File

@ -9,6 +9,7 @@
#include <crypto/internal/hash.h>
#include <crypto/internal/skcipher.h>
#include <crypto/authenc.h>
#include <crypto/null.h>
#include <crypto/scatterwalk.h>
#include <linux/err.h>
#include <linux/init.h>
@ -27,6 +28,7 @@ struct authenc_instance_ctx {
struct crypto_authenc_ctx {
struct crypto_ahash *auth;
struct crypto_skcipher *enc;
struct crypto_sync_skcipher *null;
};
struct authenc_request_ctx {
@ -37,7 +39,7 @@ struct authenc_request_ctx {
static void authenc_request_complete(struct aead_request *req, int err)
{
if (err != -EINPROGRESS)
if (err != -EINPROGRESS && err != -EBUSY)
aead_request_complete(req, err);
}
@ -107,27 +109,42 @@ out:
return err;
}
static void authenc_geniv_ahash_done(void *data, int err)
static void authenc_geniv_ahash_finish(struct aead_request *req)
{
struct aead_request *req = data;
struct crypto_aead *authenc = crypto_aead_reqtfm(req);
struct aead_instance *inst = aead_alg_instance(authenc);
struct authenc_instance_ctx *ictx = aead_instance_ctx(inst);
struct authenc_request_ctx *areq_ctx = aead_request_ctx(req);
struct ahash_request *ahreq = (void *)(areq_ctx->tail + ictx->reqoff);
if (err)
goto out;
scatterwalk_map_and_copy(ahreq->result, req->dst,
req->assoclen + req->cryptlen,
crypto_aead_authsize(authenc), 1);
}
out:
static void authenc_geniv_ahash_done(void *data, int err)
{
struct aead_request *req = data;
if (!err)
authenc_geniv_ahash_finish(req);
aead_request_complete(req, err);
}
static int crypto_authenc_genicv(struct aead_request *req, unsigned int flags)
/*
* Used when the ahash request was invoked in the async callback context
* of the previous skcipher request. Eat any EINPROGRESS notifications.
*/
static void authenc_geniv_ahash_done2(void *data, int err)
{
struct aead_request *req = data;
if (!err)
authenc_geniv_ahash_finish(req);
authenc_request_complete(req, err);
}
static int crypto_authenc_genicv(struct aead_request *req, unsigned int mask)
{
struct crypto_aead *authenc = crypto_aead_reqtfm(req);
struct aead_instance *inst = aead_alg_instance(authenc);
@ -136,6 +153,7 @@ static int crypto_authenc_genicv(struct aead_request *req, unsigned int flags)
struct crypto_ahash *auth = ctx->auth;
struct authenc_request_ctx *areq_ctx = aead_request_ctx(req);
struct ahash_request *ahreq = (void *)(areq_ctx->tail + ictx->reqoff);
unsigned int flags = aead_request_flags(req) & ~mask;
u8 *hash = areq_ctx->tail;
int err;
@ -143,7 +161,8 @@ static int crypto_authenc_genicv(struct aead_request *req, unsigned int flags)
ahash_request_set_crypt(ahreq, req->dst, hash,
req->assoclen + req->cryptlen);
ahash_request_set_callback(ahreq, flags,
authenc_geniv_ahash_done, req);
mask ? authenc_geniv_ahash_done2 :
authenc_geniv_ahash_done, req);
err = crypto_ahash_digest(ahreq);
if (err)
@ -159,15 +178,29 @@ static void crypto_authenc_encrypt_done(void *data, int err)
{
struct aead_request *areq = data;
if (err)
goto out;
err = crypto_authenc_genicv(areq, 0);
out:
if (err) {
aead_request_complete(areq, err);
return;
}
err = crypto_authenc_genicv(areq, CRYPTO_TFM_REQ_MAY_SLEEP);
authenc_request_complete(areq, err);
}
static int crypto_authenc_copy_assoc(struct aead_request *req)
{
struct crypto_aead *authenc = crypto_aead_reqtfm(req);
struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc);
SYNC_SKCIPHER_REQUEST_ON_STACK(skreq, ctx->null);
skcipher_request_set_sync_tfm(skreq, ctx->null);
skcipher_request_set_callback(skreq, aead_request_flags(req),
NULL, NULL);
skcipher_request_set_crypt(skreq, req->src, req->dst, req->assoclen,
NULL);
return crypto_skcipher_encrypt(skreq);
}
static int crypto_authenc_encrypt(struct aead_request *req)
{
struct crypto_aead *authenc = crypto_aead_reqtfm(req);
@ -186,7 +219,10 @@ static int crypto_authenc_encrypt(struct aead_request *req)
dst = src;
if (req->src != req->dst) {
memcpy_sglist(req->dst, req->src, req->assoclen);
err = crypto_authenc_copy_assoc(req);
if (err)
return err;
dst = scatterwalk_ffwd(areq_ctx->dst, req->dst, req->assoclen);
}
@ -199,11 +235,18 @@ static int crypto_authenc_encrypt(struct aead_request *req)
if (err)
return err;
return crypto_authenc_genicv(req, aead_request_flags(req));
return crypto_authenc_genicv(req, 0);
}
static void authenc_decrypt_tail_done(void *data, int err)
{
struct aead_request *req = data;
authenc_request_complete(req, err);
}
static int crypto_authenc_decrypt_tail(struct aead_request *req,
unsigned int flags)
unsigned int mask)
{
struct crypto_aead *authenc = crypto_aead_reqtfm(req);
struct aead_instance *inst = aead_alg_instance(authenc);
@ -214,6 +257,7 @@ static int crypto_authenc_decrypt_tail(struct aead_request *req,
struct skcipher_request *skreq = (void *)(areq_ctx->tail +
ictx->reqoff);
unsigned int authsize = crypto_aead_authsize(authenc);
unsigned int flags = aead_request_flags(req) & ~mask;
u8 *ihash = ahreq->result + authsize;
struct scatterlist *src, *dst;
@ -230,7 +274,9 @@ static int crypto_authenc_decrypt_tail(struct aead_request *req,
skcipher_request_set_tfm(skreq, ctx->enc);
skcipher_request_set_callback(skreq, flags,
req->base.complete, req->base.data);
mask ? authenc_decrypt_tail_done :
req->base.complete,
mask ? req : req->base.data);
skcipher_request_set_crypt(skreq, src, dst,
req->cryptlen - authsize, req->iv);
@ -241,12 +287,11 @@ static void authenc_verify_ahash_done(void *data, int err)
{
struct aead_request *req = data;
if (err)
goto out;
err = crypto_authenc_decrypt_tail(req, 0);
out:
if (err) {
aead_request_complete(req, err);
return;
}
err = crypto_authenc_decrypt_tail(req, CRYPTO_TFM_REQ_MAY_SLEEP);
authenc_request_complete(req, err);
}
@ -273,7 +318,7 @@ static int crypto_authenc_decrypt(struct aead_request *req)
if (err)
return err;
return crypto_authenc_decrypt_tail(req, aead_request_flags(req));
return crypto_authenc_decrypt_tail(req, 0);
}
static int crypto_authenc_init_tfm(struct crypto_aead *tfm)
@ -283,6 +328,7 @@ static int crypto_authenc_init_tfm(struct crypto_aead *tfm)
struct crypto_authenc_ctx *ctx = crypto_aead_ctx(tfm);
struct crypto_ahash *auth;
struct crypto_skcipher *enc;
struct crypto_sync_skcipher *null;
int err;
auth = crypto_spawn_ahash(&ictx->auth);
@ -294,8 +340,14 @@ static int crypto_authenc_init_tfm(struct crypto_aead *tfm)
if (IS_ERR(enc))
goto err_free_ahash;
null = crypto_get_default_null_skcipher();
err = PTR_ERR(null);
if (IS_ERR(null))
goto err_free_skcipher;
ctx->auth = auth;
ctx->enc = enc;
ctx->null = null;
crypto_aead_set_reqsize(
tfm,
@ -309,6 +361,8 @@ static int crypto_authenc_init_tfm(struct crypto_aead *tfm)
return 0;
err_free_skcipher:
crypto_free_skcipher(enc);
err_free_ahash:
crypto_free_ahash(auth);
return err;
@ -320,6 +374,7 @@ static void crypto_authenc_exit_tfm(struct crypto_aead *tfm)
crypto_free_ahash(ctx->auth);
crypto_free_skcipher(ctx->enc);
crypto_put_default_null_skcipher();
}
static void crypto_authenc_free(struct aead_instance *inst)

View File

@ -12,6 +12,7 @@
#include <crypto/internal/hash.h>
#include <crypto/internal/skcipher.h>
#include <crypto/authenc.h>
#include <crypto/null.h>
#include <crypto/scatterwalk.h>
#include <linux/err.h>
#include <linux/init.h>
@ -30,6 +31,7 @@ struct crypto_authenc_esn_ctx {
unsigned int reqoff;
struct crypto_ahash *auth;
struct crypto_skcipher *enc;
struct crypto_sync_skcipher *null;
};
struct authenc_esn_request_ctx {
@ -156,6 +158,28 @@ static void crypto_authenc_esn_encrypt_done(void *data, int err)
authenc_esn_request_complete(areq, err);
}
static int crypto_authenc_esn_copy_sg(struct aead_request *req,
struct scatterlist *src,
struct scatterlist *dst,
unsigned int len)
{
struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req);
struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn);
SYNC_SKCIPHER_REQUEST_ON_STACK(skreq, ctx->null);
skcipher_request_set_sync_tfm(skreq, ctx->null);
skcipher_request_set_callback(skreq, aead_request_flags(req),
NULL, NULL);
skcipher_request_set_crypt(skreq, src, dst, len, NULL);
return crypto_skcipher_encrypt(skreq);
}
static int crypto_authenc_esn_copy(struct aead_request *req, unsigned int len)
{
return crypto_authenc_esn_copy_sg(req, req->src, req->dst, len);
}
static int crypto_authenc_esn_encrypt(struct aead_request *req)
{
struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req);
@ -177,7 +201,10 @@ static int crypto_authenc_esn_encrypt(struct aead_request *req)
dst = src;
if (req->src != req->dst) {
memcpy_sglist(req->dst, req->src, assoclen);
err = crypto_authenc_esn_copy(req, assoclen);
if (err)
return err;
sg_init_table(areq_ctx->dst, 2);
dst = scatterwalk_ffwd(areq_ctx->dst, req->dst, assoclen);
}
@ -211,6 +238,7 @@ static int crypto_authenc_esn_decrypt_tail(struct aead_request *req,
struct scatterlist *dst = req->dst;
u8 *ihash = ohash + crypto_ahash_digestsize(auth);
u32 tmp[2];
int err;
if (!authsize)
goto decrypt;
@ -220,8 +248,11 @@ static int crypto_authenc_esn_decrypt_tail(struct aead_request *req,
scatterwalk_map_and_copy(tmp, dst, 4, 4, 0);
scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 0);
scatterwalk_map_and_copy(tmp, dst, 0, 8, 1);
} else
memcpy_sglist(dst, src, assoclen);
} else {
err = crypto_authenc_esn_copy(req, assoclen);
if (err)
return err;
}
if (crypto_memneq(ihash, ohash, authsize))
return -EBADMSG;
@ -289,7 +320,10 @@ static int crypto_authenc_esn_decrypt(struct aead_request *req)
src = scatterwalk_ffwd(areq_ctx->src, src, 8);
dst = scatterwalk_ffwd(areq_ctx->dst, dst, 4);
memcpy_sglist(dst, src, assoclen + cryptlen - 8);
err = crypto_authenc_esn_copy_sg(req, src, dst,
assoclen + cryptlen - 8);
if (err)
return err;
dst = req->dst;
}
@ -313,6 +347,7 @@ static int crypto_authenc_esn_init_tfm(struct crypto_aead *tfm)
struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(tfm);
struct crypto_ahash *auth;
struct crypto_skcipher *enc;
struct crypto_sync_skcipher *null;
int err;
auth = crypto_spawn_ahash(&ictx->auth);
@ -324,8 +359,14 @@ static int crypto_authenc_esn_init_tfm(struct crypto_aead *tfm)
if (IS_ERR(enc))
goto err_free_ahash;
null = crypto_get_default_null_skcipher();
err = PTR_ERR(null);
if (IS_ERR(null))
goto err_free_skcipher;
ctx->auth = auth;
ctx->enc = enc;
ctx->null = null;
ctx->reqoff = 2 * crypto_ahash_digestsize(auth);
@ -341,6 +382,8 @@ static int crypto_authenc_esn_init_tfm(struct crypto_aead *tfm)
return 0;
err_free_skcipher:
crypto_free_skcipher(enc);
err_free_ahash:
crypto_free_ahash(auth);
return err;
@ -352,6 +395,7 @@ static void crypto_authenc_esn_exit_tfm(struct crypto_aead *tfm)
crypto_free_ahash(ctx->auth);
crypto_free_skcipher(ctx->enc);
crypto_put_default_null_skcipher();
}
static void crypto_authenc_esn_free(struct aead_instance *inst)
@ -390,6 +434,11 @@ static int crypto_authenc_esn_create(struct crypto_template *tmpl,
auth = crypto_spawn_ahash_alg(&ctx->auth);
auth_base = &auth->base;
if (auth->digestsize > 0 && auth->digestsize < 4) {
err = -EINVAL;
goto err_free_inst;
}
err = crypto_grab_skcipher(&ctx->enc, aead_crypto_instance(inst),
crypto_attr_alg_name(tb[2]), 0, mask);
if (err)

View File

@ -69,100 +69,6 @@ void scatterwalk_map_and_copy(void *buf, struct scatterlist *sg,
}
EXPORT_SYMBOL_GPL(scatterwalk_map_and_copy);
/**
* memcpy_sglist() - Copy data from one scatterlist to another
* @dst: The destination scatterlist. Can be NULL if @nbytes == 0.
* @src: The source scatterlist. Can be NULL if @nbytes == 0.
* @nbytes: Number of bytes to copy
*
* The scatterlists can describe exactly the same memory, in which case this
* function is a no-op. No other overlaps are supported.
*
* Context: Any context
*/
void memcpy_sglist(struct scatterlist *dst, struct scatterlist *src,
unsigned int nbytes)
{
unsigned int src_offset, dst_offset;
if (unlikely(nbytes == 0)) /* in case src and/or dst is NULL */
return;
src_offset = src->offset;
dst_offset = dst->offset;
for (;;) {
/* Compute the length to copy this step. */
unsigned int len = min3(src->offset + src->length - src_offset,
dst->offset + dst->length - dst_offset,
nbytes);
struct page *src_page = sg_page(src);
struct page *dst_page = sg_page(dst);
const void *src_virt;
void *dst_virt;
if (IS_ENABLED(CONFIG_HIGHMEM)) {
/* HIGHMEM: we may have to actually map the pages. */
const unsigned int src_oip = offset_in_page(src_offset);
const unsigned int dst_oip = offset_in_page(dst_offset);
const unsigned int limit = PAGE_SIZE;
/* Further limit len to not cross a page boundary. */
len = min3(len, limit - src_oip, limit - dst_oip);
/* Compute the source and destination pages. */
src_page += src_offset / PAGE_SIZE;
dst_page += dst_offset / PAGE_SIZE;
if (src_page != dst_page) {
/* Copy between different pages. */
memcpy_page(dst_page, dst_oip,
src_page, src_oip, len);
flush_dcache_page(dst_page);
} else if (src_oip != dst_oip) {
/* Copy between different parts of same page. */
dst_virt = kmap_local_page(dst_page);
memcpy(dst_virt + dst_oip, dst_virt + src_oip,
len);
kunmap_local(dst_virt);
flush_dcache_page(dst_page);
} /* Else, it's the same memory. No action needed. */
} else {
/*
* !HIGHMEM: no mapping needed. Just work in the linear
* buffer of each sg entry. Note that we can cross page
* boundaries, as they are not significant in this case.
*/
src_virt = page_address(src_page) + src_offset;
dst_virt = page_address(dst_page) + dst_offset;
if (src_virt != dst_virt) {
memcpy(dst_virt, src_virt, len);
if (ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE)
__scatterwalk_flush_dcache_pages(
dst_page, dst_offset, len);
} /* Else, it's the same memory. No action needed. */
}
nbytes -= len;
if (nbytes == 0) /* No more to copy? */
break;
/*
* There's more to copy. Advance the offsets by the length
* copied this step, and advance the sg entries as needed.
*/
src_offset += len;
if (src_offset >= src->offset + src->length) {
src = sg_next(src);
src_offset = src->offset;
}
dst_offset += len;
if (dst_offset >= dst->offset + dst->length) {
dst = sg_next(dst);
dst_offset = dst->offset;
}
}
}
EXPORT_SYMBOL_GPL(memcpy_sglist);
struct scatterlist *scatterwalk_ffwd(struct scatterlist dst[2],
struct scatterlist *src,
unsigned int len)

View File

@ -2241,12 +2241,13 @@ again:
ret = nbd_start_device(nbd);
out:
mutex_unlock(&nbd->config_lock);
if (!ret) {
set_bit(NBD_RT_HAS_CONFIG_REF, &config->runtime_flags);
refcount_inc(&nbd->config_refs);
nbd_connect_reply(info, nbd->index);
}
mutex_unlock(&nbd->config_lock);
nbd_config_put(nbd);
if (put_dev)
nbd_put(nbd);

View File

@ -4,6 +4,7 @@
* Crypto driver to handle block cipher algorithms using NVIDIA Security Engine.
*/
#include <linux/bottom_half.h>
#include <linux/clk.h>
#include <linux/dma-mapping.h>
#include <linux/module.h>
@ -333,7 +334,9 @@ out:
tegra_key_invalidate_reserved(ctx->se, key2_id, ctx->alg);
out_finalize:
local_bh_disable();
crypto_finalize_skcipher_request(se->engine, req, ret);
local_bh_enable();
return 0;
}
@ -1261,7 +1264,9 @@ out_free_inbuf:
tegra_key_invalidate_reserved(ctx->se, rctx->key_id, ctx->alg);
out_finalize:
local_bh_disable();
crypto_finalize_aead_request(ctx->se->engine, req, ret);
local_bh_enable();
return 0;
}
@ -1347,7 +1352,9 @@ out_free_inbuf:
tegra_key_invalidate_reserved(ctx->se, rctx->key_id, ctx->alg);
out_finalize:
local_bh_disable();
crypto_finalize_aead_request(ctx->se->engine, req, ret);
local_bh_enable();
return 0;
}
@ -1745,7 +1752,9 @@ out:
if (tegra_key_is_reserved(rctx->key_id))
tegra_key_invalidate_reserved(ctx->se, rctx->key_id, ctx->alg);
local_bh_disable();
crypto_finalize_hash_request(se->engine, req, ret);
local_bh_enable();
return 0;
}

View File

@ -4,6 +4,7 @@
* Crypto driver to handle HASH algorithms using NVIDIA Security Engine.
*/
#include <linux/bottom_half.h>
#include <linux/clk.h>
#include <linux/dma-mapping.h>
#include <linux/module.h>
@ -543,7 +544,9 @@ static int tegra_sha_do_one_req(struct crypto_engine *engine, void *areq)
}
out:
local_bh_disable();
crypto_finalize_hash_request(se->engine, req, ret);
local_bh_enable();
return 0;
}

View File

@ -880,7 +880,11 @@ dpll_pin_register(struct dpll_device *dpll, struct dpll_pin *pin,
if (WARN_ON(!ops) ||
WARN_ON(!ops->state_on_dpll_get) ||
WARN_ON(!ops->direction_get))
WARN_ON(!ops->direction_get) ||
WARN_ON(ops->measured_freq_get &&
(!dpll_device_ops(dpll)->freq_monitor_get ||
!dpll_device_ops(dpll)->freq_monitor_set)) ||
WARN_ON(ops->supported_ffo && !ops->ffo_get))
return -EINVAL;
mutex_lock(&dpll_lock);

View File

@ -175,6 +175,26 @@ dpll_msg_add_phase_offset_monitor(struct sk_buff *msg, struct dpll_device *dpll,
return 0;
}
static int
dpll_msg_add_freq_monitor(struct sk_buff *msg, struct dpll_device *dpll,
struct netlink_ext_ack *extack)
{
const struct dpll_device_ops *ops = dpll_device_ops(dpll);
enum dpll_feature_state state;
int ret;
if (ops->freq_monitor_set && ops->freq_monitor_get) {
ret = ops->freq_monitor_get(dpll, dpll_priv(dpll),
&state, extack);
if (ret)
return ret;
if (nla_put_u32(msg, DPLL_A_FREQUENCY_MONITOR, state))
return -EMSGSIZE;
}
return 0;
}
static int
dpll_msg_add_phase_offset_avg_factor(struct sk_buff *msg,
struct dpll_device *dpll,
@ -304,6 +324,30 @@ dpll_msg_add_pin_on_dpll_state(struct sk_buff *msg, struct dpll_pin *pin,
return 0;
}
static int
dpll_msg_add_pin_operstate(struct sk_buff *msg, struct dpll_pin *pin,
struct dpll_pin_ref *ref,
struct netlink_ext_ack *extack)
{
const struct dpll_pin_ops *ops = dpll_pin_ops(ref);
struct dpll_device *dpll = ref->dpll;
enum dpll_pin_operstate operstate;
int ret;
if (!ops->operstate_on_dpll_get)
return 0;
ret = ops->operstate_on_dpll_get(pin,
dpll_pin_on_dpll_priv(dpll, pin),
dpll, dpll_priv(dpll),
&operstate, extack);
if (ret)
return ret;
if (nla_put_u32(msg, DPLL_A_PIN_OPERSTATE, operstate))
return -EMSGSIZE;
return 0;
}
static int
dpll_msg_add_pin_direction(struct sk_buff *msg, struct dpll_pin *pin,
struct dpll_pin_ref *ref,
@ -373,31 +417,66 @@ dpll_msg_add_phase_offset(struct sk_buff *msg, struct dpll_pin *pin,
static int dpll_msg_add_ffo(struct sk_buff *msg, struct dpll_pin *pin,
struct dpll_pin_ref *ref,
enum dpll_ffo_type type,
struct netlink_ext_ack *extack)
{
const struct dpll_pin_ops *ops = dpll_pin_ops(ref);
struct dpll_device *dpll = ref->dpll;
s64 ffo;
struct dpll_ffo_param ffo = { .type = type };
int ret;
if (!ops->ffo_get)
/* RHEL: To maintain backward compatibility with older binary modules,
* we must accept a value of zero for .supported_ffo when the type is
* DPLL_FFO_PORT_RXTX_RATE.
*/
if (!ops->ffo_get ||
!((ops->supported_ffo & BIT(type)) ||
(!ops->supported_ffo && type == DPLL_FFO_PORT_RXTX_RATE)))
return 0;
ret = ops->ffo_get(pin, dpll_pin_on_dpll_priv(dpll, pin),
dpll, dpll_priv(dpll), &ffo, extack);
ret = ops->ffo_get(pin, dpll_pin_on_dpll_priv(ref->dpll, pin),
ref->dpll, dpll_priv(ref->dpll), &ffo, extack);
if (ret) {
if (ret == -ENODATA)
return 0;
return ret;
}
/* Put the FFO value in PPM to preserve compatibility with older
* programs.
*/
ret = nla_put_sint(msg, DPLL_A_PIN_FRACTIONAL_FREQUENCY_OFFSET,
div_s64(ffo, 1000000));
if (ret)
if (nla_put_sint(msg, DPLL_A_PIN_FRACTIONAL_FREQUENCY_OFFSET,
div_s64(ffo.ffo, 1000000)))
return -EMSGSIZE;
return nla_put_sint(msg, DPLL_A_PIN_FRACTIONAL_FREQUENCY_OFFSET_PPT,
ffo);
return nla_put_sint(msg,
DPLL_A_PIN_FRACTIONAL_FREQUENCY_OFFSET_PPT,
ffo.ffo);
}
static int dpll_msg_add_measured_freq(struct sk_buff *msg, struct dpll_pin *pin,
struct dpll_pin_ref *ref,
struct netlink_ext_ack *extack)
{
const struct dpll_device_ops *dev_ops = dpll_device_ops(ref->dpll);
const struct dpll_pin_ops *ops = dpll_pin_ops(ref);
struct dpll_device *dpll = ref->dpll;
enum dpll_feature_state state;
u64 measured_freq;
int ret;
if (!ops->measured_freq_get)
return 0;
ret = dev_ops->freq_monitor_get(dpll, dpll_priv(dpll),
&state, extack);
if (ret)
return ret;
if (state == DPLL_FEATURE_STATE_DISABLE)
return 0;
ret = ops->measured_freq_get(pin, dpll_pin_on_dpll_priv(dpll, pin),
dpll, dpll_priv(dpll), &measured_freq,
extack);
if (ret)
return ret;
if (nla_put_64bit(msg, DPLL_A_PIN_MEASURED_FREQUENCY,
sizeof(measured_freq), &measured_freq,
DPLL_A_PIN_PAD))
return -EMSGSIZE;
return 0;
}
static int
@ -598,6 +677,9 @@ dpll_msg_add_pin_dplls(struct sk_buff *msg, struct dpll_pin *pin,
if (ret)
goto nest_cancel;
ret = dpll_msg_add_pin_on_dpll_state(msg, pin, ref, extack);
if (ret)
goto nest_cancel;
ret = dpll_msg_add_pin_operstate(msg, pin, ref, extack);
if (ret)
goto nest_cancel;
ret = dpll_msg_add_pin_prio(msg, pin, ref, extack);
@ -607,6 +689,10 @@ dpll_msg_add_pin_dplls(struct sk_buff *msg, struct dpll_pin *pin,
if (ret)
goto nest_cancel;
ret = dpll_msg_add_phase_offset(msg, pin, ref, extack);
if (ret)
goto nest_cancel;
ret = dpll_msg_add_ffo(msg, pin, ref,
DPLL_FFO_PIN_DEVICE, extack);
if (ret)
goto nest_cancel;
nla_nest_end(msg, attr);
@ -669,7 +755,11 @@ dpll_cmd_pin_get_one(struct sk_buff *msg, struct dpll_pin *pin,
ret = dpll_msg_add_pin_phase_adjust(msg, pin, ref, extack);
if (ret)
return ret;
ret = dpll_msg_add_ffo(msg, pin, ref, extack);
ret = dpll_msg_add_ffo(msg, pin, ref,
DPLL_FFO_PORT_RXTX_RATE, extack);
if (ret)
return ret;
ret = dpll_msg_add_measured_freq(msg, pin, ref, extack);
if (ret)
return ret;
ret = dpll_msg_add_pin_esync(msg, pin, ref, extack);
@ -722,6 +812,9 @@ dpll_device_get_one(struct dpll_device *dpll, struct sk_buff *msg,
if (ret)
return ret;
ret = dpll_msg_add_phase_offset_avg_factor(msg, dpll, extack);
if (ret)
return ret;
ret = dpll_msg_add_freq_monitor(msg, dpll, extack);
if (ret)
return ret;
@ -948,6 +1041,32 @@ dpll_phase_offset_avg_factor_set(struct dpll_device *dpll, struct nlattr *a,
extack);
}
static int
dpll_freq_monitor_set(struct dpll_device *dpll, struct nlattr *a,
struct netlink_ext_ack *extack)
{
const struct dpll_device_ops *ops = dpll_device_ops(dpll);
enum dpll_feature_state state = nla_get_u32(a), old_state;
int ret;
if (!(ops->freq_monitor_set && ops->freq_monitor_get)) {
NL_SET_ERR_MSG_ATTR(extack, a,
"dpll device not capable of frequency monitor");
return -EOPNOTSUPP;
}
ret = ops->freq_monitor_get(dpll, dpll_priv(dpll), &old_state,
extack);
if (ret) {
NL_SET_ERR_MSG(extack,
"unable to get current state of frequency monitor");
return ret;
}
if (state == old_state)
return 0;
return ops->freq_monitor_set(dpll, dpll_priv(dpll), state, extack);
}
static int
dpll_pin_freq_set(struct dpll_pin *pin, struct nlattr *a,
struct netlink_ext_ack *extack)
@ -1878,6 +1997,12 @@ dpll_set_from_nlattr(struct dpll_device *dpll, struct genl_info *info)
if (ret)
return ret;
break;
case DPLL_A_FREQUENCY_MONITOR:
ret = dpll_freq_monitor_set(dpll, a,
info->extack);
if (ret)
return ret;
break;
}
}

View File

@ -11,12 +11,15 @@
#include <uapi/linux/dpll.h>
/* Common nested types */
const struct nla_policy dpll_pin_parent_device_nl_policy[DPLL_A_PIN_PHASE_OFFSET + 1] = {
const struct nla_policy dpll_pin_parent_device_nl_policy[DPLL_A_PIN_OPERSTATE + 1] = {
[DPLL_A_PIN_PARENT_ID] = { .type = NLA_U32, },
[DPLL_A_PIN_DIRECTION] = NLA_POLICY_RANGE(NLA_U32, 1, 2),
[DPLL_A_PIN_PRIO] = { .type = NLA_U32, },
[DPLL_A_PIN_STATE] = NLA_POLICY_RANGE(NLA_U32, 1, 3),
[DPLL_A_PIN_OPERSTATE] = NLA_POLICY_RANGE(NLA_U32, 1, 4),
[DPLL_A_PIN_PHASE_OFFSET] = { .type = NLA_S64, },
[DPLL_A_PIN_FRACTIONAL_FREQUENCY_OFFSET] = { .type = NLA_SINT, },
[DPLL_A_PIN_FRACTIONAL_FREQUENCY_OFFSET_PPT] = { .type = NLA_SINT, },
};
const struct nla_policy dpll_pin_parent_pin_nl_policy[DPLL_A_PIN_STATE + 1] = {
@ -42,11 +45,12 @@ static const struct nla_policy dpll_device_get_nl_policy[DPLL_A_ID + 1] = {
};
/* DPLL_CMD_DEVICE_SET - do */
static const struct nla_policy dpll_device_set_nl_policy[DPLL_A_PHASE_OFFSET_AVG_FACTOR + 1] = {
static const struct nla_policy dpll_device_set_nl_policy[DPLL_A_FREQUENCY_MONITOR + 1] = {
[DPLL_A_ID] = { .type = NLA_U32, },
[DPLL_A_MODE] = NLA_POLICY_RANGE(NLA_U32, 1, 2),
[DPLL_A_PHASE_OFFSET_MONITOR] = NLA_POLICY_MAX(NLA_U32, 1),
[DPLL_A_PHASE_OFFSET_AVG_FACTOR] = { .type = NLA_U32, },
[DPLL_A_FREQUENCY_MONITOR] = NLA_POLICY_MAX(NLA_U32, 1),
};
/* DPLL_CMD_PIN_ID_GET - do */
@ -114,7 +118,7 @@ static const struct genl_split_ops dpll_nl_ops[] = {
.doit = dpll_nl_device_set_doit,
.post_doit = dpll_post_doit,
.policy = dpll_device_set_nl_policy,
.maxattr = DPLL_A_PHASE_OFFSET_AVG_FACTOR,
.maxattr = DPLL_A_FREQUENCY_MONITOR,
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
},
{

View File

@ -12,7 +12,7 @@
#include <uapi/linux/dpll.h>
/* Common nested types */
extern const struct nla_policy dpll_pin_parent_device_nl_policy[DPLL_A_PIN_PHASE_OFFSET + 1];
extern const struct nla_policy dpll_pin_parent_device_nl_policy[DPLL_A_PIN_OPERSTATE + 1];
extern const struct nla_policy dpll_pin_parent_pin_nl_policy[DPLL_A_PIN_STATE + 1];
extern const struct nla_policy dpll_reference_sync_nl_policy[DPLL_A_PIN_STATE + 1];

View File

@ -1,8 +1,8 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_ZL3073X) += zl3073x.o
zl3073x-objs := core.o devlink.o dpll.o flash.o fw.o \
out.o prop.o ref.o synth.o
zl3073x-objs := chan.o core.o devlink.o dpll.o \
flash.o fw.o out.o prop.o ref.o synth.o
obj-$(CONFIG_ZL3073X_I2C) += zl3073x_i2c.o
zl3073x_i2c-objs := i2c.o

192
drivers/dpll/zl3073x/chan.c Normal file
View File

@ -0,0 +1,192 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/cleanup.h>
#include <linux/dev_printk.h>
#include <linux/string.h>
#include <linux/types.h>
#include "chan.h"
#include "core.h"
/**
* zl3073x_chan_state_update - update DPLL channel status from HW
* @zldev: pointer to zl3073x_dev structure
* @index: DPLL channel index
*
* Return: 0 on success, <0 on error
*/
int zl3073x_chan_state_update(struct zl3073x_dev *zldev, u8 index)
{
struct zl3073x_chan *chan = &zldev->chan[index];
u64 val;
int rc;
rc = zl3073x_read_u8(zldev, ZL_REG_DPLL_MON_STATUS(index),
&chan->mon_status);
if (rc)
return rc;
rc = zl3073x_read_u8(zldev, ZL_REG_DPLL_REFSEL_STATUS(index),
&chan->refsel_status);
if (rc)
return rc;
/* Read df_offset vs tracked reference */
rc = zl3073x_poll_zero_u8(zldev, ZL_REG_DPLL_DF_READ(index),
ZL_DPLL_DF_READ_SEM);
if (rc)
return rc;
rc = zl3073x_write_u8(zldev, ZL_REG_DPLL_DF_READ(index),
ZL_DPLL_DF_READ_SEM | ZL_DPLL_DF_READ_REF_OFST);
if (rc)
return rc;
rc = zl3073x_poll_zero_u8(zldev, ZL_REG_DPLL_DF_READ(index),
ZL_DPLL_DF_READ_SEM);
if (rc)
return rc;
rc = zl3073x_read_u48(zldev, ZL_REG_DPLL_DF_OFFSET(index), &val);
if (rc)
return rc;
chan->df_offset = sign_extend64(val, 47);
return 0;
}
/**
* zl3073x_chan_state_fetch - fetch DPLL channel state from hardware
* @zldev: pointer to zl3073x_dev structure
* @index: DPLL channel index to fetch state for
*
* Reads the mode_refsel register and reference priority registers for
* the given DPLL channel and stores the raw values for later use.
*
* Return: 0 on success, <0 on error
*/
int zl3073x_chan_state_fetch(struct zl3073x_dev *zldev, u8 index)
{
struct zl3073x_chan *chan = &zldev->chan[index];
int rc, i;
rc = zl3073x_read_u8(zldev, ZL_REG_DPLL_MODE_REFSEL(index),
&chan->mode_refsel);
if (rc)
return rc;
dev_dbg(zldev->dev, "DPLL%u mode: %u, ref: %u\n", index,
zl3073x_chan_mode_get(chan), zl3073x_chan_ref_get(chan));
rc = zl3073x_chan_state_update(zldev, index);
if (rc)
return rc;
dev_dbg(zldev->dev,
"DPLL%u lock_state: %u, ho: %u, sel_state: %u, sel_ref: %u\n",
index, zl3073x_chan_lock_state_get(chan),
zl3073x_chan_is_ho_ready(chan) ? 1 : 0,
zl3073x_chan_refsel_state_get(chan),
zl3073x_chan_refsel_ref_get(chan));
guard(mutex)(&zldev->multiop_lock);
/* Read DPLL configuration from mailbox */
rc = zl3073x_mb_op(zldev, ZL_REG_DPLL_MB_SEM, ZL_DPLL_MB_SEM_RD,
ZL_REG_DPLL_MB_MASK, BIT(index));
if (rc)
return rc;
/* Read reference priority registers */
for (i = 0; i < ARRAY_SIZE(chan->ref_prio); i++) {
rc = zl3073x_read_u8(zldev, ZL_REG_DPLL_REF_PRIO(i),
&chan->ref_prio[i]);
if (rc)
return rc;
}
return 0;
}
/**
* zl3073x_chan_state_get - get current DPLL channel state
* @zldev: pointer to zl3073x_dev structure
* @index: DPLL channel index to get state for
*
* Return: pointer to given DPLL channel state
*/
const struct zl3073x_chan *zl3073x_chan_state_get(struct zl3073x_dev *zldev,
u8 index)
{
return &zldev->chan[index];
}
/**
* zl3073x_chan_state_set - commit DPLL channel state changes to hardware
* @zldev: pointer to zl3073x_dev structure
* @index: DPLL channel index to set state for
* @chan: desired channel state
*
* Skips the HW write if the configuration is unchanged, and otherwise
* writes only the changed registers to hardware. The mode_refsel register
* is written directly, while the reference priority registers are written
* via the DPLL mailbox interface.
*
* Return: 0 on success, <0 on HW error
*/
int zl3073x_chan_state_set(struct zl3073x_dev *zldev, u8 index,
const struct zl3073x_chan *chan)
{
struct zl3073x_chan *dchan = &zldev->chan[index];
int rc, i;
/* Skip HW write if configuration hasn't changed */
if (!memcmp(&dchan->cfg, &chan->cfg, sizeof(chan->cfg)))
return 0;
/* Direct register write for mode_refsel */
if (dchan->mode_refsel != chan->mode_refsel) {
rc = zl3073x_write_u8(zldev, ZL_REG_DPLL_MODE_REFSEL(index),
chan->mode_refsel);
if (rc)
return rc;
dchan->mode_refsel = chan->mode_refsel;
}
/* Mailbox write for ref_prio if changed */
if (!memcmp(dchan->ref_prio, chan->ref_prio, sizeof(chan->ref_prio))) {
dchan->cfg = chan->cfg;
return 0;
}
guard(mutex)(&zldev->multiop_lock);
/* Read DPLL configuration into mailbox */
rc = zl3073x_mb_op(zldev, ZL_REG_DPLL_MB_SEM, ZL_DPLL_MB_SEM_RD,
ZL_REG_DPLL_MB_MASK, BIT(index));
if (rc)
return rc;
/* Update changed ref_prio registers */
for (i = 0; i < ARRAY_SIZE(chan->ref_prio); i++) {
if (dchan->ref_prio[i] != chan->ref_prio[i]) {
rc = zl3073x_write_u8(zldev,
ZL_REG_DPLL_REF_PRIO(i),
chan->ref_prio[i]);
if (rc)
return rc;
}
}
/* Commit DPLL configuration */
rc = zl3073x_mb_op(zldev, ZL_REG_DPLL_MB_SEM, ZL_DPLL_MB_SEM_WR,
ZL_REG_DPLL_MB_MASK, BIT(index));
if (rc)
return rc;
/* After successful write store new state */
dchan->cfg = chan->cfg;
return 0;
}

188
drivers/dpll/zl3073x/chan.h Normal file
View File

@ -0,0 +1,188 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef _ZL3073X_CHAN_H
#define _ZL3073X_CHAN_H
#include <linux/bitfield.h>
#include <linux/stddef.h>
#include <linux/types.h>
#include "regs.h"
struct zl3073x_dev;
/**
* struct zl3073x_chan - DPLL channel state
* @mode_refsel: mode and reference selection register value
* @ref_prio: reference priority registers (4 bits per ref, P/N packed)
* @mon_status: monitor status register value
* @refsel_status: reference selection status register value
* @df_offset: frequency offset vs tracked reference in 2^-48 steps
*/
struct zl3073x_chan {
struct_group(cfg,
u8 mode_refsel;
u8 ref_prio[ZL3073X_NUM_REFS / 2];
);
struct_group(stat,
u8 mon_status;
u8 refsel_status;
s64 df_offset;
);
};
int zl3073x_chan_state_fetch(struct zl3073x_dev *zldev, u8 index);
const struct zl3073x_chan *zl3073x_chan_state_get(struct zl3073x_dev *zldev,
u8 index);
int zl3073x_chan_state_set(struct zl3073x_dev *zldev, u8 index,
const struct zl3073x_chan *chan);
int zl3073x_chan_state_update(struct zl3073x_dev *zldev, u8 index);
/**
* zl3073x_chan_df_offset_get - get cached df_offset vs tracked reference
* @chan: pointer to channel state
*
* Return: frequency offset in 2^-48 steps
*/
static inline s64
zl3073x_chan_df_offset_get(const struct zl3073x_chan *chan)
{
return chan->df_offset;
}
/**
* zl3073x_chan_mode_get - get DPLL channel operating mode
* @chan: pointer to channel state
*
* Return: reference selection mode of the given DPLL channel
*/
static inline u8 zl3073x_chan_mode_get(const struct zl3073x_chan *chan)
{
return FIELD_GET(ZL_DPLL_MODE_REFSEL_MODE, chan->mode_refsel);
}
/**
* zl3073x_chan_ref_get - get manually selected reference
* @chan: pointer to channel state
*
* Return: reference selected in forced reference lock mode
*/
static inline u8 zl3073x_chan_ref_get(const struct zl3073x_chan *chan)
{
return FIELD_GET(ZL_DPLL_MODE_REFSEL_REF, chan->mode_refsel);
}
/**
* zl3073x_chan_mode_set - set DPLL channel operating mode
* @chan: pointer to channel state
* @mode: mode to set
*/
static inline void zl3073x_chan_mode_set(struct zl3073x_chan *chan, u8 mode)
{
FIELD_MODIFY(ZL_DPLL_MODE_REFSEL_MODE, &chan->mode_refsel, mode);
}
/**
* zl3073x_chan_ref_set - set manually selected reference
* @chan: pointer to channel state
* @ref: reference to set
*/
static inline void zl3073x_chan_ref_set(struct zl3073x_chan *chan, u8 ref)
{
FIELD_MODIFY(ZL_DPLL_MODE_REFSEL_REF, &chan->mode_refsel, ref);
}
/**
* zl3073x_chan_ref_prio_get - get reference priority
* @chan: pointer to channel state
* @ref: input reference index
*
* Return: priority of the given reference <0, 15>
*/
static inline u8
zl3073x_chan_ref_prio_get(const struct zl3073x_chan *chan, u8 ref)
{
u8 val = chan->ref_prio[ref / 2];
if (!(ref & 1))
return FIELD_GET(ZL_DPLL_REF_PRIO_REF_P, val);
else
return FIELD_GET(ZL_DPLL_REF_PRIO_REF_N, val);
}
/**
* zl3073x_chan_ref_prio_set - set reference priority
* @chan: pointer to channel state
* @ref: input reference index
* @prio: priority to set
*/
static inline void
zl3073x_chan_ref_prio_set(struct zl3073x_chan *chan, u8 ref, u8 prio)
{
u8 *val = &chan->ref_prio[ref / 2];
if (!(ref & 1))
FIELD_MODIFY(ZL_DPLL_REF_PRIO_REF_P, val, prio);
else
FIELD_MODIFY(ZL_DPLL_REF_PRIO_REF_N, val, prio);
}
/**
* zl3073x_chan_ref_is_selectable - check if reference is selectable
* @chan: pointer to channel state
* @ref: input reference index
*
* Return: true if the reference priority is not NONE, false otherwise
*/
static inline bool
zl3073x_chan_ref_is_selectable(const struct zl3073x_chan *chan, u8 ref)
{
return zl3073x_chan_ref_prio_get(chan, ref) != ZL_DPLL_REF_PRIO_NONE;
}
/**
* zl3073x_chan_lock_state_get - get DPLL channel lock state
* @chan: pointer to channel state
*
* Return: lock state of the given DPLL channel
*/
static inline u8 zl3073x_chan_lock_state_get(const struct zl3073x_chan *chan)
{
return FIELD_GET(ZL_DPLL_MON_STATUS_STATE, chan->mon_status);
}
/**
* zl3073x_chan_is_ho_ready - check if holdover is ready
* @chan: pointer to channel state
*
* Return: true if holdover is ready, false otherwise
*/
static inline bool zl3073x_chan_is_ho_ready(const struct zl3073x_chan *chan)
{
return !!FIELD_GET(ZL_DPLL_MON_STATUS_HO_READY, chan->mon_status);
}
/**
* zl3073x_chan_refsel_state_get - get reference selection state
* @chan: pointer to channel state
*
* Return: reference selection state of the given DPLL channel
*/
static inline u8 zl3073x_chan_refsel_state_get(const struct zl3073x_chan *chan)
{
return FIELD_GET(ZL_DPLL_REFSEL_STATUS_STATE, chan->refsel_status);
}
/**
* zl3073x_chan_refsel_ref_get - get currently selected reference in auto mode
* @chan: pointer to channel state
*
* Return: reference selected by the DPLL in automatic mode
*/
static inline u8 zl3073x_chan_refsel_ref_get(const struct zl3073x_chan *chan)
{
return FIELD_GET(ZL_DPLL_REFSEL_STATUS_REFSEL, chan->refsel_status);
}
#endif /* _ZL3073X_CHAN_H */

View File

@ -20,78 +20,29 @@
#include "dpll.h"
#include "regs.h"
/* Chip IDs for zl30731 */
static const u16 zl30731_ids[] = {
0x0E93,
0x1E93,
0x2E93,
};
#define ZL_CHIP_INFO(_id, _nchannels, _flags) \
{ .id = (_id), .num_channels = (_nchannels), .flags = (_flags) }
const struct zl3073x_chip_info zl30731_chip_info = {
.ids = zl30731_ids,
.num_ids = ARRAY_SIZE(zl30731_ids),
.num_channels = 1,
static const struct zl3073x_chip_info zl3073x_chip_ids[] = {
ZL_CHIP_INFO(0x0E30, 2, ZL3073X_FLAG_REF_PHASE_COMP_32),
ZL_CHIP_INFO(0x0E93, 1, ZL3073X_FLAG_REF_PHASE_COMP_32),
ZL_CHIP_INFO(0x0E94, 2, ZL3073X_FLAG_REF_PHASE_COMP_32),
ZL_CHIP_INFO(0x0E95, 3, ZL3073X_FLAG_REF_PHASE_COMP_32),
ZL_CHIP_INFO(0x0E96, 4, ZL3073X_FLAG_REF_PHASE_COMP_32),
ZL_CHIP_INFO(0x0E97, 5, ZL3073X_FLAG_REF_PHASE_COMP_32),
ZL_CHIP_INFO(0x1E93, 1, ZL3073X_FLAG_DIE_TEMP),
ZL_CHIP_INFO(0x1E94, 2, ZL3073X_FLAG_DIE_TEMP),
ZL_CHIP_INFO(0x1E95, 3, ZL3073X_FLAG_DIE_TEMP),
ZL_CHIP_INFO(0x1E96, 4, ZL3073X_FLAG_DIE_TEMP),
ZL_CHIP_INFO(0x1E97, 5, ZL3073X_FLAG_DIE_TEMP),
ZL_CHIP_INFO(0x1F60, 2, ZL3073X_FLAG_REF_PHASE_COMP_32),
ZL_CHIP_INFO(0x2E93, 1, ZL3073X_FLAG_DIE_TEMP),
ZL_CHIP_INFO(0x2E94, 2, ZL3073X_FLAG_DIE_TEMP),
ZL_CHIP_INFO(0x2E95, 3, ZL3073X_FLAG_DIE_TEMP),
ZL_CHIP_INFO(0x2E96, 4, ZL3073X_FLAG_DIE_TEMP),
ZL_CHIP_INFO(0x2E97, 5, ZL3073X_FLAG_DIE_TEMP),
ZL_CHIP_INFO(0x3FC4, 2, ZL3073X_FLAG_DIE_TEMP),
};
EXPORT_SYMBOL_NS_GPL(zl30731_chip_info, "ZL3073X");
/* Chip IDs for zl30732 */
static const u16 zl30732_ids[] = {
0x0E30,
0x0E94,
0x1E94,
0x1F60,
0x2E94,
0x3FC4,
};
const struct zl3073x_chip_info zl30732_chip_info = {
.ids = zl30732_ids,
.num_ids = ARRAY_SIZE(zl30732_ids),
.num_channels = 2,
};
EXPORT_SYMBOL_NS_GPL(zl30732_chip_info, "ZL3073X");
/* Chip IDs for zl30733 */
static const u16 zl30733_ids[] = {
0x0E95,
0x1E95,
0x2E95,
};
const struct zl3073x_chip_info zl30733_chip_info = {
.ids = zl30733_ids,
.num_ids = ARRAY_SIZE(zl30733_ids),
.num_channels = 3,
};
EXPORT_SYMBOL_NS_GPL(zl30733_chip_info, "ZL3073X");
/* Chip IDs for zl30734 */
static const u16 zl30734_ids[] = {
0x0E96,
0x1E96,
0x2E96,
};
const struct zl3073x_chip_info zl30734_chip_info = {
.ids = zl30734_ids,
.num_ids = ARRAY_SIZE(zl30734_ids),
.num_channels = 4,
};
EXPORT_SYMBOL_NS_GPL(zl30734_chip_info, "ZL3073X");
/* Chip IDs for zl30735 */
static const u16 zl30735_ids[] = {
0x0E97,
0x1E97,
0x2E97,
};
const struct zl3073x_chip_info zl30735_chip_info = {
.ids = zl30735_ids,
.num_ids = ARRAY_SIZE(zl30735_ids),
.num_channels = 5,
};
EXPORT_SYMBOL_NS_GPL(zl30735_chip_info, "ZL3073X");
#define ZL_RANGE_OFFSET 0x80
#define ZL_PAGE_SIZE 0x80
@ -588,17 +539,26 @@ zl3073x_dev_state_fetch(struct zl3073x_dev *zldev)
}
}
for (i = 0; i < zldev->info->num_channels; i++) {
rc = zl3073x_chan_state_fetch(zldev, i);
if (rc) {
dev_err(zldev->dev,
"Failed to fetch channel state: %pe\n",
ERR_PTR(rc));
return rc;
}
}
return rc;
}
static void
zl3073x_dev_ref_status_update(struct zl3073x_dev *zldev)
zl3073x_dev_ref_states_update(struct zl3073x_dev *zldev)
{
int i, rc;
for (i = 0; i < ZL3073X_NUM_REFS; i++) {
rc = zl3073x_read_u8(zldev, ZL_REG_REF_MON_STATUS(i),
&zldev->ref[i].mon_status);
rc = zl3073x_ref_state_update(zldev, i);
if (rc)
dev_warn(zldev->dev,
"Failed to get REF%u status: %pe\n", i,
@ -606,6 +566,20 @@ zl3073x_dev_ref_status_update(struct zl3073x_dev *zldev)
}
}
static void
zl3073x_dev_chan_states_update(struct zl3073x_dev *zldev)
{
int i, rc;
for (i = 0; i < zldev->info->num_channels; i++) {
rc = zl3073x_chan_state_update(zldev, i);
if (rc)
dev_warn(zldev->dev,
"Failed to get DPLL%u state: %pe\n", i,
ERR_PTR(rc));
}
}
/**
* zl3073x_ref_phase_offsets_update - update reference phase offsets
* @zldev: pointer to zl3073x_dev structure
@ -658,22 +632,21 @@ int zl3073x_ref_phase_offsets_update(struct zl3073x_dev *zldev, int channel)
}
/**
* zl3073x_ref_ffo_update - update reference fractional frequency offsets
* zl3073x_ref_freq_meas_latch - latch reference frequency measurements
* @zldev: pointer to zl3073x_dev structure
* @type: measurement type (ZL_REF_FREQ_MEAS_CTRL_*)
*
* The function asks device to update fractional frequency offsets latch
* registers the latest measured values, reads and stores them into
* The function waits for the previous measurement to finish, selects all
* references and requests a new measurement of the given type.
*
* Return: 0 on success, <0 on error
*/
static int
zl3073x_ref_ffo_update(struct zl3073x_dev *zldev)
zl3073x_ref_freq_meas_latch(struct zl3073x_dev *zldev, u8 type)
{
int i, rc;
int rc;
/* Per datasheet we have to wait for 'ref_freq_meas_ctrl' to be zero
* to ensure that the measured data are coherent.
*/
/* Wait for previous measurement to finish */
rc = zl3073x_poll_zero_u8(zldev, ZL_REG_REF_FREQ_MEAS_CTRL,
ZL_REF_FREQ_MEAS_CTRL);
if (rc)
@ -689,32 +662,43 @@ zl3073x_ref_ffo_update(struct zl3073x_dev *zldev)
if (rc)
return rc;
/* Request frequency offset measurement */
rc = zl3073x_write_u8(zldev, ZL_REG_REF_FREQ_MEAS_CTRL,
ZL_REF_FREQ_MEAS_CTRL_REF_FREQ_OFF);
/* Request measurement */
rc = zl3073x_write_u8(zldev, ZL_REG_REF_FREQ_MEAS_CTRL, type);
if (rc)
return rc;
/* Wait for finish */
rc = zl3073x_poll_zero_u8(zldev, ZL_REG_REF_FREQ_MEAS_CTRL,
ZL_REF_FREQ_MEAS_CTRL);
return zl3073x_poll_zero_u8(zldev, ZL_REG_REF_FREQ_MEAS_CTRL,
ZL_REF_FREQ_MEAS_CTRL);
}
/**
* zl3073x_ref_freq_meas_update - update measured input reference frequencies
* @zldev: pointer to zl3073x_dev structure
*
* The function asks device to latch measured input reference frequencies
* and stores the results in the ref state.
*
* Return: 0 on success, <0 on error
*/
static int
zl3073x_ref_freq_meas_update(struct zl3073x_dev *zldev)
{
int i, rc;
rc = zl3073x_ref_freq_meas_latch(zldev, ZL_REF_FREQ_MEAS_CTRL_REF_FREQ);
if (rc)
return rc;
/* Read DPLL-to-REFx frequency offset measurements */
/* Read measured frequencies in Hz (unsigned 32-bit, LSB = 1 Hz) */
for (i = 0; i < ZL3073X_NUM_REFS; i++) {
s32 value;
u32 value;
/* Read value stored in units of 2^-32 signed */
rc = zl3073x_read_u32(zldev, ZL_REG_REF_FREQ(i), &value);
if (rc)
return rc;
/* Convert to ppt
* ffo = (10^12 * value) / 2^32
* ffo = ( 5^12 * value) / 2^20
*/
zldev->ref[i].ffo = mul_s64_u64_shr(value, 244140625, 20);
zldev->ref[i].meas_freq = value;
}
return 0;
@ -728,8 +712,11 @@ zl3073x_dev_periodic_work(struct kthread_work *work)
struct zl3073x_dpll *zldpll;
int rc;
/* Update input references status */
zl3073x_dev_ref_status_update(zldev);
/* Update input references' states */
zl3073x_dev_ref_states_update(zldev);
/* Update DPLL channels' states */
zl3073x_dev_chan_states_update(zldev);
/* Update DPLL-to-connected-ref phase offsets registers */
rc = zl3073x_ref_phase_offsets_update(zldev, -1);
@ -737,12 +724,19 @@ zl3073x_dev_periodic_work(struct kthread_work *work)
dev_warn(zldev->dev, "Failed to update phase offsets: %pe\n",
ERR_PTR(rc));
/* Update references' fractional frequency offsets */
rc = zl3073x_ref_ffo_update(zldev);
if (rc)
dev_warn(zldev->dev,
"Failed to update fractional frequency offsets: %pe\n",
ERR_PTR(rc));
/* Update measured input reference frequencies if any DPLL has
* frequency monitoring enabled.
*/
list_for_each_entry(zldpll, &zldev->dplls, list) {
if (zldpll->freq_monitor) {
rc = zl3073x_ref_freq_meas_update(zldev);
if (rc)
dev_warn(zldev->dev,
"Failed to update measured frequencies: %pe\n",
ERR_PTR(rc));
break;
}
}
list_for_each_entry(zldpll, &zldev->dplls, list)
zl3073x_dpll_changes_check(zldpll);
@ -766,8 +760,7 @@ int zl3073x_dev_phase_avg_factor_set(struct zl3073x_dev *zldev, u8 factor)
value = (factor + 1) & 0x0f;
/* Update phase measurement control register */
dpll_meas_ctrl &= ~ZL_DPLL_MEAS_CTRL_AVG_FACTOR;
dpll_meas_ctrl |= FIELD_PREP(ZL_DPLL_MEAS_CTRL_AVG_FACTOR, value);
FIELD_MODIFY(ZL_DPLL_MEAS_CTRL_AVG_FACTOR, &dpll_meas_ctrl, value);
rc = zl3073x_write_u8(zldev, ZL_REG_DPLL_MEAS_CTRL, dpll_meas_ctrl);
if (rc)
return rc;
@ -942,7 +935,7 @@ static void zl3073x_dev_dpll_fini(void *ptr)
}
static int
zl3073x_devm_dpll_init(struct zl3073x_dev *zldev, u8 num_dplls)
zl3073x_devm_dpll_init(struct zl3073x_dev *zldev)
{
struct kthread_worker *kworker;
struct zl3073x_dpll *zldpll;
@ -952,7 +945,7 @@ zl3073x_devm_dpll_init(struct zl3073x_dev *zldev, u8 num_dplls)
INIT_LIST_HEAD(&zldev->dplls);
/* Allocate all DPLLs */
for (i = 0; i < num_dplls; i++) {
for (i = 0; i < zldev->info->num_channels; i++) {
zldpll = zl3073x_dpll_alloc(zldev, i);
if (IS_ERR(zldpll)) {
dev_err_probe(zldev->dev, PTR_ERR(zldpll),
@ -981,11 +974,7 @@ zl3073x_devm_dpll_init(struct zl3073x_dev *zldev, u8 num_dplls)
}
/* Add devres action to release DPLL related resources */
rc = devm_add_action_or_reset(zldev->dev, zl3073x_dev_dpll_fini, zldev);
if (rc)
goto error;
return 0;
return devm_add_action_or_reset(zldev->dev, zl3073x_dev_dpll_fini, zldev);
error:
zl3073x_dev_dpll_fini(zldev);
@ -996,14 +985,12 @@ error:
/**
* zl3073x_dev_probe - initialize zl3073x device
* @zldev: pointer to zl3073x device
* @chip_info: chip info based on compatible
*
* Common initialization of zl3073x device structure.
*
* Returns: 0 on success, <0 on error
*/
int zl3073x_dev_probe(struct zl3073x_dev *zldev,
const struct zl3073x_chip_info *chip_info)
int zl3073x_dev_probe(struct zl3073x_dev *zldev)
{
u16 id, revision, fw_ver;
unsigned int i;
@ -1015,17 +1002,17 @@ int zl3073x_dev_probe(struct zl3073x_dev *zldev,
if (rc)
return rc;
/* Check it matches */
for (i = 0; i < chip_info->num_ids; i++) {
if (id == chip_info->ids[i])
/* Detect chip variant */
for (i = 0; i < ARRAY_SIZE(zl3073x_chip_ids); i++) {
if (zl3073x_chip_ids[i].id == id)
break;
}
if (i == chip_info->num_ids) {
if (i == ARRAY_SIZE(zl3073x_chip_ids))
return dev_err_probe(zldev->dev, -ENODEV,
"Unknown or non-match chip ID: 0x%0x\n",
id);
}
"Unknown chip ID: 0x%04x\n", id);
zldev->info = &zl3073x_chip_ids[i];
/* Read revision, firmware version and custom config version */
rc = zl3073x_read_u16(zldev, ZL_REG_REVISION, &revision);
@ -1064,7 +1051,7 @@ int zl3073x_dev_probe(struct zl3073x_dev *zldev,
"Failed to initialize mutex\n");
/* Register DPLL channels */
rc = zl3073x_devm_dpll_init(zldev, chip_info->num_channels);
rc = zl3073x_devm_dpll_init(zldev);
if (rc)
return rc;

View File

@ -9,6 +9,7 @@
#include <linux/mutex.h>
#include <linux/types.h>
#include "chan.h"
#include "out.h"
#include "ref.h"
#include "regs.h"
@ -18,26 +19,39 @@ struct device;
struct regmap;
struct zl3073x_dpll;
/*
* Hardware limits for ZL3073x chip family
enum zl3073x_flags {
ZL3073X_FLAG_REF_PHASE_COMP_32_BIT,
ZL3073X_FLAG_DIE_TEMP_BIT,
ZL3073X_FLAGS_NBITS /* must be last */
};
#define __ZL3073X_FLAG(name) BIT(ZL3073X_FLAG_ ## name ## _BIT)
#define ZL3073X_FLAG_REF_PHASE_COMP_32 __ZL3073X_FLAG(REF_PHASE_COMP_32)
#define ZL3073X_FLAG_DIE_TEMP __ZL3073X_FLAG(DIE_TEMP)
/**
* struct zl3073x_chip_info - chip variant identification
* @id: chip ID
* @num_channels: number of DPLL channels supported by this variant
* @flags: chip variant flags
*/
#define ZL3073X_MAX_CHANNELS 5
#define ZL3073X_NUM_REFS 10
#define ZL3073X_NUM_OUTS 10
#define ZL3073X_NUM_SYNTHS 5
#define ZL3073X_NUM_INPUT_PINS ZL3073X_NUM_REFS
#define ZL3073X_NUM_OUTPUT_PINS (ZL3073X_NUM_OUTS * 2)
#define ZL3073X_NUM_PINS (ZL3073X_NUM_INPUT_PINS + \
ZL3073X_NUM_OUTPUT_PINS)
struct zl3073x_chip_info {
u16 id;
u8 num_channels;
unsigned long flags;
};
/**
* struct zl3073x_dev - zl3073x device
* @dev: pointer to device
* @regmap: regmap to access device registers
* @info: detected chip info
* @multiop_lock: to serialize multiple register operations
* @ref: array of input references' invariants
* @out: array of outs' invariants
* @synth: array of synths' invariants
* @chan: array of DPLL channels' state
* @dplls: list of DPLLs
* @kworker: thread for periodic work
* @work: periodic work
@ -45,14 +59,16 @@ struct zl3073x_dpll;
* @phase_avg_factor: phase offset measurement averaging factor
*/
struct zl3073x_dev {
struct device *dev;
struct regmap *regmap;
struct mutex multiop_lock;
struct device *dev;
struct regmap *regmap;
const struct zl3073x_chip_info *info;
struct mutex multiop_lock;
/* Invariants */
struct zl3073x_ref ref[ZL3073X_NUM_REFS];
struct zl3073x_out out[ZL3073X_NUM_OUTS];
struct zl3073x_synth synth[ZL3073X_NUM_SYNTHS];
struct zl3073x_chan chan[ZL3073X_MAX_CHANNELS];
/* DPLL channels */
struct list_head dplls;
@ -66,22 +82,10 @@ struct zl3073x_dev {
u8 phase_avg_factor;
};
struct zl3073x_chip_info {
const u16 *ids;
size_t num_ids;
int num_channels;
};
extern const struct zl3073x_chip_info zl30731_chip_info;
extern const struct zl3073x_chip_info zl30732_chip_info;
extern const struct zl3073x_chip_info zl30733_chip_info;
extern const struct zl3073x_chip_info zl30734_chip_info;
extern const struct zl3073x_chip_info zl30735_chip_info;
extern const struct regmap_config zl3073x_regmap_config;
struct zl3073x_dev *zl3073x_devm_alloc(struct device *dev);
int zl3073x_dev_probe(struct zl3073x_dev *zldev,
const struct zl3073x_chip_info *chip_info);
int zl3073x_dev_probe(struct zl3073x_dev *zldev);
int zl3073x_dev_start(struct zl3073x_dev *zldev, bool full);
void zl3073x_dev_stop(struct zl3073x_dev *zldev);
@ -144,6 +148,21 @@ int zl3073x_write_hwreg_seq(struct zl3073x_dev *zldev,
int zl3073x_ref_phase_offsets_update(struct zl3073x_dev *zldev, int channel);
/**
* zl3073x_dev_is_ref_phase_comp_32bit - check ref phase comp register size
* @zldev: pointer to zl3073x device
*
* Some chip IDs have a 32-bit wide ref_phase_offset_comp register instead
* of the default 48-bit.
*
* Return: true if the register is 32-bit, false if 48-bit
*/
static inline bool
zl3073x_dev_is_ref_phase_comp_32bit(struct zl3073x_dev *zldev)
{
return zldev->info->flags & ZL3073X_FLAG_REF_PHASE_COMP_32;
}
static inline bool
zl3073x_is_n_pin(u8 id)
{
@ -301,6 +320,36 @@ u8 zl3073x_dev_out_dpll_get(struct zl3073x_dev *zldev, u8 index)
return zl3073x_synth_dpll_get(synth);
}
/**
* zl3073x_dev_output_pin_freq_get - get output pin frequency
* @zldev: pointer to zl3073x device
* @id: output pin id
*
* Computes the output pin frequency based on the synth frequency, output
* divisor, and signal format. For N-div formats, N-pin frequency is
* additionally divided by esync_n_period.
*
* Return: frequency of the given output pin in Hz
*/
static inline u32
zl3073x_dev_output_pin_freq_get(struct zl3073x_dev *zldev, u8 id)
{
const struct zl3073x_synth *synth;
const struct zl3073x_out *out;
u8 out_id;
u32 freq;
out_id = zl3073x_output_pin_out_get(id);
out = zl3073x_out_state_get(zldev, out_id);
synth = zl3073x_synth_state_get(zldev, zl3073x_out_synth_get(out));
freq = zl3073x_synth_freq_get(synth) / out->div;
if (zl3073x_out_is_ndiv(out) && zl3073x_is_n_pin(id))
freq /= out->esync_n_period;
return freq;
}
/**
* zl3073x_dev_out_is_diff - check if the given output is differential
* @zldev: pointer to zl3073x device

File diff suppressed because it is too large Load Diff

View File

@ -13,10 +13,10 @@
* @list: this DPLL list entry
* @dev: pointer to multi-function parent device
* @id: DPLL index
* @refsel_mode: reference selection mode
* @forced_ref: selected reference in forced reference lock mode
* @check_count: periodic check counter
* @phase_monitor: is phase offset monitor enabled
* @freq_monitor: is frequency monitor enabled
* @ops: DPLL device operations for this instance
* @dpll_dev: pointer to registered DPLL device
* @tracker: tracking object for the acquired reference
* @lock_status: last saved DPLL lock status
@ -27,10 +27,10 @@ struct zl3073x_dpll {
struct list_head list;
struct zl3073x_dev *dev;
u8 id;
u8 refsel_mode;
u8 forced_ref;
u8 check_count;
bool phase_monitor;
bool freq_monitor;
struct dpll_device_ops ops;
struct dpll_device *dpll_dev;
dpll_tracker tracker;
enum dpll_lock_status lock_status;

View File

@ -194,8 +194,7 @@ zl3073x_flash_cmd_wait(struct zl3073x_dev *zldev, u32 operation,
if (rc)
return rc;
value &= ~ZL_WRITE_FLASH_OP;
value |= FIELD_PREP(ZL_WRITE_FLASH_OP, operation);
FIELD_MODIFY(ZL_WRITE_FLASH_OP, &value, operation);
rc = zl3073x_write_u8(zldev, ZL_REG_WRITE_FLASH, value);
if (rc)

View File

@ -22,40 +22,25 @@ static int zl3073x_i2c_probe(struct i2c_client *client)
return dev_err_probe(dev, PTR_ERR(zldev->regmap),
"Failed to initialize regmap\n");
return zl3073x_dev_probe(zldev, i2c_get_match_data(client));
return zl3073x_dev_probe(zldev);
}
static const struct i2c_device_id zl3073x_i2c_id[] = {
{
.name = "zl30731",
.driver_data = (kernel_ulong_t)&zl30731_chip_info,
},
{
.name = "zl30732",
.driver_data = (kernel_ulong_t)&zl30732_chip_info,
},
{
.name = "zl30733",
.driver_data = (kernel_ulong_t)&zl30733_chip_info,
},
{
.name = "zl30734",
.driver_data = (kernel_ulong_t)&zl30734_chip_info,
},
{
.name = "zl30735",
.driver_data = (kernel_ulong_t)&zl30735_chip_info,
},
{ "zl30731" },
{ "zl30732" },
{ "zl30733" },
{ "zl30734" },
{ "zl30735" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, zl3073x_i2c_id);
static const struct of_device_id zl3073x_i2c_of_match[] = {
{ .compatible = "microchip,zl30731", .data = &zl30731_chip_info },
{ .compatible = "microchip,zl30732", .data = &zl30732_chip_info },
{ .compatible = "microchip,zl30733", .data = &zl30733_chip_info },
{ .compatible = "microchip,zl30734", .data = &zl30734_chip_info },
{ .compatible = "microchip,zl30735", .data = &zl30735_chip_info },
{ .compatible = "microchip,zl30731" },
{ .compatible = "microchip,zl30732" },
{ .compatible = "microchip,zl30733" },
{ .compatible = "microchip,zl30734" },
{ .compatible = "microchip,zl30735" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, zl3073x_i2c_of_match);

View File

@ -106,12 +106,32 @@ const struct zl3073x_out *zl3073x_out_state_get(struct zl3073x_dev *zldev,
return &zldev->out[index];
}
/**
* zl3073x_out_state_set - commit output state changes to hardware
* @zldev: pointer to zl3073x_dev structure
* @index: output index to set state for
* @out: desired output state
*
* Validates that invariant fields have not been modified, skips the HW
* write if the mutable configuration is unchanged, and otherwise writes
* only the changed cfg fields to hardware via the mailbox interface.
*
* Return: 0 on success, -EINVAL if invariants changed, <0 on HW error
*/
int zl3073x_out_state_set(struct zl3073x_dev *zldev, u8 index,
const struct zl3073x_out *out)
{
struct zl3073x_out *dout = &zldev->out[index];
int rc;
/* Reject attempts to change invariant fields (set at fetch only) */
if (WARN_ON(memcmp(&dout->inv, &out->inv, sizeof(out->inv))))
return -EINVAL;
/* Skip HW write if configuration hasn't changed */
if (!memcmp(&dout->cfg, &out->cfg, sizeof(out->cfg)))
return 0;
guard(mutex)(&zldev->multiop_lock);
/* Read output configuration into mailbox */
@ -146,12 +166,7 @@ int zl3073x_out_state_set(struct zl3073x_dev *zldev, u8 index,
return rc;
/* After successful commit store new state */
dout->div = out->div;
dout->width = out->width;
dout->esync_n_period = out->esync_n_period;
dout->esync_n_width = out->esync_n_width;
dout->mode = out->mode;
dout->phase_comp = out->phase_comp;
dout->cfg = out->cfg;
return 0;
}

View File

@ -4,6 +4,7 @@
#define _ZL3073X_OUT_H
#include <linux/bitfield.h>
#include <linux/stddef.h>
#include <linux/types.h>
#include "regs.h"
@ -17,17 +18,21 @@ struct zl3073x_dev;
* @esync_n_period: embedded sync or n-pin period (for n-div formats)
* @esync_n_width: embedded sync or n-pin pulse width
* @phase_comp: phase compensation
* @ctrl: output control
* @mode: output mode
* @ctrl: output control
*/
struct zl3073x_out {
u32 div;
u32 width;
u32 esync_n_period;
u32 esync_n_width;
s32 phase_comp;
u8 ctrl;
u8 mode;
struct_group(cfg, /* Config */
u32 div;
u32 width;
u32 esync_n_period;
u32 esync_n_width;
s32 phase_comp;
u8 mode;
);
struct_group(inv, /* Invariants */
u8 ctrl;
);
};
int zl3073x_out_state_fetch(struct zl3073x_dev *zldev, u8 index);
@ -37,6 +42,28 @@ const struct zl3073x_out *zl3073x_out_state_get(struct zl3073x_dev *zldev,
int zl3073x_out_state_set(struct zl3073x_dev *zldev, u8 index,
const struct zl3073x_out *out);
/**
* zl3073x_out_clock_type_get - get output clock type
* @out: pointer to out state
*
* Return: clock type of given output (ZL_OUTPUT_MODE_CLOCK_TYPE_*)
*/
static inline u8 zl3073x_out_clock_type_get(const struct zl3073x_out *out)
{
return FIELD_GET(ZL_OUTPUT_MODE_CLOCK_TYPE, out->mode);
}
/**
* zl3073x_out_clock_type_set - set output clock type
* @out: pointer to out state
* @type: clock type (ZL_OUTPUT_MODE_CLOCK_TYPE_*)
*/
static inline void
zl3073x_out_clock_type_set(struct zl3073x_out *out, u8 type)
{
FIELD_MODIFY(ZL_OUTPUT_MODE_CLOCK_TYPE, &out->mode, type);
}
/**
* zl3073x_out_signal_format_get - get output signal format
* @out: pointer to out state
@ -79,6 +106,23 @@ static inline bool zl3073x_out_is_enabled(const struct zl3073x_out *out)
return !!FIELD_GET(ZL_OUTPUT_CTRL_EN, out->ctrl);
}
/**
* zl3073x_out_is_ndiv - check if the given output is in N-div mode
* @out: pointer to out state
*
* Return: true if output is in N-div mode, false otherwise
*/
static inline bool zl3073x_out_is_ndiv(const struct zl3073x_out *out)
{
switch (zl3073x_out_signal_format_get(out)) {
case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV:
case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV_INV:
return true;
default:
return false;
}
}
/**
* zl3073x_out_synth_get - get synth connected to given output
* @out: pointer to out state

View File

@ -193,9 +193,10 @@ struct zl3073x_pin_props *zl3073x_pin_props_get(struct zl3073x_dev *zldev,
{
struct dpll_pin_frequency *ranges;
struct zl3073x_pin_props *props;
int i, j, num_freqs, rc;
int i, j, num_freqs = 0, rc;
u64 *freqs = NULL;
const char *type;
u64 *freqs;
u32 curr_freq;
props = kzalloc(sizeof(*props), GFP_KERNEL);
if (!props)
@ -207,6 +208,7 @@ struct zl3073x_pin_props *zl3073x_pin_props_get(struct zl3073x_dev *zldev,
props->dpll_props.capabilities =
DPLL_PIN_CAPABILITIES_PRIORITY_CAN_CHANGE |
DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE;
curr_freq = zl3073x_dev_ref_freq_get(zldev, index);
} else {
u8 out, synth;
u32 f;
@ -220,6 +222,7 @@ struct zl3073x_pin_props *zl3073x_pin_props_get(struct zl3073x_dev *zldev,
synth = zl3073x_dev_out_synth_get(zldev, out);
f = 2 * zl3073x_dev_synth_freq_get(zldev, synth);
props->dpll_props.phase_gran = f ? div_u64(PSEC_PER_SEC, f) : 1;
curr_freq = zl3073x_dev_output_pin_freq_get(zldev, index);
}
props->dpll_props.phase_range.min = S32_MIN;
@ -230,7 +233,7 @@ struct zl3073x_pin_props *zl3073x_pin_props_get(struct zl3073x_dev *zldev,
/* Get firmware node for the given pin */
rc = zl3073x_prop_pin_fwnode_get(zldev, props, dir, index);
if (rc)
return props; /* Return if it does not exist */
goto skip_fwnode_props;
/* Look for label property and store the value as board label */
fwnode_property_read_string(props->fwnode, "label",
@ -264,9 +267,10 @@ struct zl3073x_pin_props *zl3073x_pin_props_get(struct zl3073x_dev *zldev,
/* Read supported frequencies property if it is specified */
num_freqs = fwnode_property_count_u64(props->fwnode,
"supported-frequencies-hz");
if (num_freqs <= 0)
/* Return if the property does not exist or number is 0 */
return props;
if (num_freqs <= 0) {
num_freqs = 0;
goto skip_fwnode_props;
}
/* The firmware node specifies list of supported frequencies while
* DPLL core pin properties requires list of frequency ranges.
@ -283,19 +287,25 @@ struct zl3073x_pin_props *zl3073x_pin_props_get(struct zl3073x_dev *zldev,
"supported-frequencies-hz", freqs,
num_freqs);
/* Allocate frequency ranges list and fill it */
ranges = kcalloc(num_freqs, sizeof(*ranges), GFP_KERNEL);
skip_fwnode_props:
/* Allocate frequency ranges list - extra slot for current frequency */
ranges = kcalloc(num_freqs + 1, sizeof(*ranges), GFP_KERNEL);
if (!ranges) {
rc = -ENOMEM;
goto err_alloc_ranges;
}
/* Convert list of frequencies to list of frequency ranges but
* filter-out frequencies that are not representable by device
/* Start with current frequency at index 0 */
ranges[0] = (struct dpll_pin_frequency)DPLL_PIN_FREQUENCY(curr_freq);
/* Add frequencies from firmware node, skipping current frequency
* and filtering out frequencies not representable by device
*/
for (i = 0, j = 0; i < num_freqs; i++) {
for (i = 0, j = 1; i < num_freqs; i++) {
struct dpll_pin_frequency freq = DPLL_PIN_FREQUENCY(freqs[i]);
if (freqs[i] == curr_freq)
continue;
if (zl3073x_pin_check_freq(zldev, dir, index, freqs[i])) {
ranges[j] = freq;
j++;

View File

@ -51,6 +51,21 @@ zl3073x_ref_freq_factorize(u32 freq, u16 *base, u16 *mult)
return -EINVAL;
}
/**
* zl3073x_ref_state_update - update input reference status from HW
* @zldev: pointer to zl3073x_dev structure
* @index: input reference index
*
* Return: 0 on success, <0 on error
*/
int zl3073x_ref_state_update(struct zl3073x_dev *zldev, u8 index)
{
struct zl3073x_ref *ref = &zldev->ref[index];
return zl3073x_read_u8(zldev, ZL_REG_REF_MON_STATUS(index),
&ref->mon_status);
}
/**
* zl3073x_ref_state_fetch - fetch input reference state from hardware
* @zldev: pointer to zl3073x_dev structure
@ -73,18 +88,17 @@ int zl3073x_ref_state_fetch(struct zl3073x_dev *zldev, u8 index)
struct zl3073x_ref *p_ref = ref - 1; /* P-pin counterpart*/
/* Copy the shared items from the P-pin */
ref->config = p_ref->config;
ref->esync_n_div = p_ref->esync_n_div;
ref->freq_base = p_ref->freq_base;
ref->freq_mult = p_ref->freq_mult;
ref->freq_ratio_m = p_ref->freq_ratio_m;
ref->freq_ratio_n = p_ref->freq_ratio_n;
ref->phase_comp = p_ref->phase_comp;
ref->sync_ctrl = p_ref->sync_ctrl;
ref->cfg = p_ref->cfg;
ref->inv = p_ref->inv;
return 0; /* Finish - no non-shared items for now */
}
/* Read reference status */
rc = zl3073x_ref_state_update(zldev, index);
if (rc)
return rc;
guard(mutex)(&zldev->multiop_lock);
/* Read reference configuration */
@ -121,8 +135,16 @@ int zl3073x_ref_state_fetch(struct zl3073x_dev *zldev, u8 index)
return rc;
/* Read phase compensation register */
rc = zl3073x_read_u48(zldev, ZL_REG_REF_PHASE_OFFSET_COMP,
&ref->phase_comp);
if (zl3073x_dev_is_ref_phase_comp_32bit(zldev)) {
u32 val;
rc = zl3073x_read_u32(zldev, ZL_REG_REF_PHASE_OFFSET_COMP_32,
&val);
ref->phase_comp = val;
} else {
rc = zl3073x_read_u48(zldev, ZL_REG_REF_PHASE_OFFSET_COMP,
&ref->phase_comp);
}
if (rc)
return rc;
@ -146,12 +168,32 @@ zl3073x_ref_state_get(struct zl3073x_dev *zldev, u8 index)
return &zldev->ref[index];
}
/**
* zl3073x_ref_state_set - commit input reference state changes to hardware
* @zldev: pointer to zl3073x_dev structure
* @index: input reference index to set state for
* @ref: desired reference state
*
* Validates that invariant fields have not been modified, skips the HW
* write if the mutable configuration is unchanged, and otherwise writes
* only the changed cfg fields to hardware via the mailbox interface.
*
* Return: 0 on success, -EINVAL if invariants changed, <0 on HW error
*/
int zl3073x_ref_state_set(struct zl3073x_dev *zldev, u8 index,
const struct zl3073x_ref *ref)
{
struct zl3073x_ref *dref = &zldev->ref[index];
int rc;
/* Reject attempts to change invariant fields (set at init only) */
if (WARN_ON(memcmp(&dref->inv, &ref->inv, sizeof(ref->inv))))
return -EINVAL;
/* Skip HW write if configuration hasn't changed */
if (!memcmp(&dref->cfg, &ref->cfg, sizeof(ref->cfg)))
return 0;
guard(mutex)(&zldev->multiop_lock);
/* Read reference configuration into mailbox */
@ -179,9 +221,16 @@ int zl3073x_ref_state_set(struct zl3073x_dev *zldev, u8 index,
if (!rc && dref->sync_ctrl != ref->sync_ctrl)
rc = zl3073x_write_u8(zldev, ZL_REG_REF_SYNC_CTRL,
ref->sync_ctrl);
if (!rc && dref->phase_comp != ref->phase_comp)
rc = zl3073x_write_u48(zldev, ZL_REG_REF_PHASE_OFFSET_COMP,
ref->phase_comp);
if (!rc && dref->phase_comp != ref->phase_comp) {
if (zl3073x_dev_is_ref_phase_comp_32bit(zldev))
rc = zl3073x_write_u32(zldev,
ZL_REG_REF_PHASE_OFFSET_COMP_32,
ref->phase_comp);
else
rc = zl3073x_write_u48(zldev,
ZL_REG_REF_PHASE_OFFSET_COMP,
ref->phase_comp);
}
if (rc)
return rc;
@ -192,13 +241,7 @@ int zl3073x_ref_state_set(struct zl3073x_dev *zldev, u8 index,
return rc;
/* After successful commit store new state */
dref->freq_base = ref->freq_base;
dref->freq_mult = ref->freq_mult;
dref->freq_ratio_m = ref->freq_ratio_m;
dref->freq_ratio_n = ref->freq_ratio_n;
dref->esync_n_div = ref->esync_n_div;
dref->sync_ctrl = ref->sync_ctrl;
dref->phase_comp = ref->phase_comp;
dref->cfg = ref->cfg;
return 0;
}

View File

@ -5,6 +5,7 @@
#include <linux/bitfield.h>
#include <linux/math64.h>
#include <linux/stddef.h>
#include <linux/types.h>
#include "regs.h"
@ -13,28 +14,34 @@ struct zl3073x_dev;
/**
* struct zl3073x_ref - input reference state
* @ffo: current fractional frequency offset
* @phase_comp: phase compensation
* @esync_n_div: divisor for embedded sync or n-divided signal formats
* @freq_base: frequency base
* @freq_mult: frequnecy multiplier
* @freq_ratio_m: FEC mode multiplier
* @freq_ratio_n: FEC mode divisor
* @config: reference config
* @sync_ctrl: reference sync control
* @config: reference config
* @meas_freq: measured input frequency in Hz
* @mon_status: reference monitor status
*/
struct zl3073x_ref {
s64 ffo;
u64 phase_comp;
u32 esync_n_div;
u16 freq_base;
u16 freq_mult;
u16 freq_ratio_m;
u16 freq_ratio_n;
u8 config;
u8 sync_ctrl;
u8 mon_status;
struct_group(cfg, /* Configuration */
u64 phase_comp;
u32 esync_n_div;
u16 freq_base;
u16 freq_mult;
u16 freq_ratio_m;
u16 freq_ratio_n;
u8 sync_ctrl;
);
struct_group(inv, /* Invariants */
u8 config;
);
struct_group(stat, /* Status */
u32 meas_freq;
u8 mon_status;
);
};
int zl3073x_ref_state_fetch(struct zl3073x_dev *zldev, u8 index);
@ -45,18 +52,20 @@ const struct zl3073x_ref *zl3073x_ref_state_get(struct zl3073x_dev *zldev,
int zl3073x_ref_state_set(struct zl3073x_dev *zldev, u8 index,
const struct zl3073x_ref *ref);
int zl3073x_ref_state_update(struct zl3073x_dev *zldev, u8 index);
int zl3073x_ref_freq_factorize(u32 freq, u16 *base, u16 *mult);
/**
* zl3073x_ref_ffo_get - get current fractional frequency offset
* zl3073x_ref_meas_freq_get - get measured input frequency
* @ref: pointer to ref state
*
* Return: the latest measured fractional frequency offset
* Return: measured input frequency in Hz
*/
static inline s64
zl3073x_ref_ffo_get(const struct zl3073x_ref *ref)
static inline u32
zl3073x_ref_meas_freq_get(const struct zl3073x_ref *ref)
{
return ref->ffo;
return ref->meas_freq;
}
/**
@ -91,10 +100,58 @@ zl3073x_ref_freq_set(struct zl3073x_ref *ref, u32 freq)
ref->freq_base = base;
ref->freq_mult = mult;
ref->freq_ratio_m = 1;
ref->freq_ratio_n = 1;
return 0;
}
/**
* zl3073x_ref_sync_mode_get - get sync control mode
* @ref: pointer to ref state
*
* Return: sync control mode (ZL_REF_SYNC_CTRL_MODE_*)
*/
static inline u8
zl3073x_ref_sync_mode_get(const struct zl3073x_ref *ref)
{
return FIELD_GET(ZL_REF_SYNC_CTRL_MODE, ref->sync_ctrl);
}
/**
* zl3073x_ref_sync_mode_set - set sync control mode
* @ref: pointer to ref state
* @mode: sync control mode (ZL_REF_SYNC_CTRL_MODE_*)
*/
static inline void
zl3073x_ref_sync_mode_set(struct zl3073x_ref *ref, u8 mode)
{
FIELD_MODIFY(ZL_REF_SYNC_CTRL_MODE, &ref->sync_ctrl, mode);
}
/**
* zl3073x_ref_sync_pair_get - get sync pair reference index
* @ref: pointer to ref state
*
* Return: paired reference index
*/
static inline u8
zl3073x_ref_sync_pair_get(const struct zl3073x_ref *ref)
{
return FIELD_GET(ZL_REF_SYNC_CTRL_PAIR, ref->sync_ctrl);
}
/**
* zl3073x_ref_sync_pair_set - set sync pair reference index
* @ref: pointer to ref state
* @pair: paired reference index
*/
static inline void
zl3073x_ref_sync_pair_set(struct zl3073x_ref *ref, u8 pair)
{
FIELD_MODIFY(ZL_REF_SYNC_CTRL_PAIR, &ref->sync_ctrl, pair);
}
/**
* zl3073x_ref_is_diff - check if the given input reference is differential
* @ref: pointer to ref state

View File

@ -6,6 +6,18 @@
#include <linux/bitfield.h>
#include <linux/bits.h>
/*
* Hardware limits for ZL3073x chip family
*/
#define ZL3073X_MAX_CHANNELS 5
#define ZL3073X_NUM_REFS 10
#define ZL3073X_NUM_OUTS 10
#define ZL3073X_NUM_SYNTHS 5
#define ZL3073X_NUM_INPUT_PINS ZL3073X_NUM_REFS
#define ZL3073X_NUM_OUTPUT_PINS (ZL3073X_NUM_OUTS * 2)
#define ZL3073X_NUM_PINS (ZL3073X_NUM_INPUT_PINS + \
ZL3073X_NUM_OUTPUT_PINS)
/*
* Register address structure:
* ===========================
@ -78,13 +90,22 @@
#define ZL_REG_RESET_STATUS ZL_REG(0, 0x18, 1)
#define ZL_REG_RESET_STATUS_RESET BIT(0)
#define ZL_REG_DIE_TEMP_STATUS ZL_REG(0, 0x44, 2)
/*************************
* Register Page 2, Status
*************************/
#define ZL_REG_REF_MON_STATUS(_idx) \
ZL_REG_IDX(_idx, 2, 0x02, 1, ZL3073X_NUM_REFS, 1)
#define ZL_REF_MON_STATUS_OK 0 /* all bits zeroed */
#define ZL_REF_MON_STATUS_OK 0
#define ZL_REF_MON_STATUS_LOS BIT(0)
#define ZL_REF_MON_STATUS_SCM BIT(1)
#define ZL_REF_MON_STATUS_CFM BIT(2)
#define ZL_REF_MON_STATUS_GST BIT(3)
#define ZL_REF_MON_STATUS_PFM BIT(4)
#define ZL_REF_MON_STATUS_ESYNC BIT(6)
#define ZL_REF_MON_STATUS_SPLIT_XO BIT(7)
#define ZL_REG_DPLL_MON_STATUS(_idx) \
ZL_REG_IDX(_idx, 2, 0x10, 1, ZL3073X_MAX_CHANNELS, 1)
@ -143,6 +164,11 @@
#define ZL_DPLL_MODE_REFSEL_MODE_NCO 4
#define ZL_DPLL_MODE_REFSEL_REF GENMASK(7, 4)
#define ZL_REG_DPLL_DF_READ(_idx) \
ZL_REG_IDX(_idx, 5, 0x28, 1, ZL3073X_MAX_CHANNELS, 1)
#define ZL_DPLL_DF_READ_SEM BIT(4)
#define ZL_DPLL_DF_READ_REF_OFST BIT(3)
#define ZL_REG_DPLL_MEAS_CTRL ZL_REG(5, 0x50, 1)
#define ZL_DPLL_MEAS_CTRL_EN BIT(0)
#define ZL_DPLL_MEAS_CTRL_AVG_FACTOR GENMASK(7, 4)
@ -155,6 +181,16 @@
#define ZL_REG_DPLL_PHASE_ERR_DATA(_idx) \
ZL_REG_IDX(_idx, 5, 0x55, 6, ZL3073X_MAX_CHANNELS, 6)
/*******************************
* Register Pages 6-7, DPLL Data
*******************************/
#define ZL_REG_DPLL_DF_OFFSET_03(_idx) \
ZL_REG_IDX(_idx, 6, 0x00, 6, 4, 0x20)
#define ZL_REG_DPLL_DF_OFFSET_4 ZL_REG(7, 0x00, 6)
#define ZL_REG_DPLL_DF_OFFSET(_idx) \
((_idx) < 4 ? ZL_REG_DPLL_DF_OFFSET_03(_idx) : ZL_REG_DPLL_DF_OFFSET_4)
/***********************************
* Register Page 9, Synth and Output
***********************************/
@ -194,11 +230,14 @@
#define ZL_REF_CONFIG_DIFF_EN BIT(2)
#define ZL_REG_REF_PHASE_OFFSET_COMP ZL_REG(10, 0x28, 6)
#define ZL_REG_REF_PHASE_OFFSET_COMP_32 ZL_REG(10, 0x28, 4)
#define ZL_REG_REF_SYNC_CTRL ZL_REG(10, 0x2e, 1)
#define ZL_REF_SYNC_CTRL_MODE GENMASK(2, 0)
#define ZL_REF_SYNC_CTRL_MODE_REFSYNC_PAIR_OFF 0
#define ZL_REF_SYNC_CTRL_MODE_REFSYNC_PAIR 1
#define ZL_REF_SYNC_CTRL_MODE_50_50_ESYNC_25_75 2
#define ZL_REF_SYNC_CTRL_PAIR GENMASK(7, 4)
#define ZL_REG_REF_ESYNC_DIV ZL_REG(10, 0x30, 4)
#define ZL_REF_ESYNC_DIV_1HZ 0

View File

@ -22,40 +22,25 @@ static int zl3073x_spi_probe(struct spi_device *spi)
return dev_err_probe(dev, PTR_ERR(zldev->regmap),
"Failed to initialize regmap\n");
return zl3073x_dev_probe(zldev, spi_get_device_match_data(spi));
return zl3073x_dev_probe(zldev);
}
static const struct spi_device_id zl3073x_spi_id[] = {
{
.name = "zl30731",
.driver_data = (kernel_ulong_t)&zl30731_chip_info
},
{
.name = "zl30732",
.driver_data = (kernel_ulong_t)&zl30732_chip_info,
},
{
.name = "zl30733",
.driver_data = (kernel_ulong_t)&zl30733_chip_info,
},
{
.name = "zl30734",
.driver_data = (kernel_ulong_t)&zl30734_chip_info,
},
{
.name = "zl30735",
.driver_data = (kernel_ulong_t)&zl30735_chip_info,
},
{ "zl30731" },
{ "zl30732" },
{ "zl30733" },
{ "zl30734" },
{ "zl30735" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(spi, zl3073x_spi_id);
static const struct of_device_id zl3073x_spi_of_match[] = {
{ .compatible = "microchip,zl30731", .data = &zl30731_chip_info },
{ .compatible = "microchip,zl30732", .data = &zl30732_chip_info },
{ .compatible = "microchip,zl30733", .data = &zl30733_chip_info },
{ .compatible = "microchip,zl30734", .data = &zl30734_chip_info },
{ .compatible = "microchip,zl30735", .data = &zl30735_chip_info },
{ .compatible = "microchip,zl30731" },
{ .compatible = "microchip,zl30732" },
{ .compatible = "microchip,zl30733" },
{ .compatible = "microchip,zl30734" },
{ .compatible = "microchip,zl30735" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, zl3073x_spi_of_match);

View File

@ -5,6 +5,7 @@
#include <linux/bitfield.h>
#include <linux/math64.h>
#include <linux/stddef.h>
#include <linux/types.h>
#include "regs.h"
@ -20,11 +21,13 @@ struct zl3073x_dev;
* @ctrl: synth control
*/
struct zl3073x_synth {
u32 freq_mult;
u16 freq_base;
u16 freq_m;
u16 freq_n;
u8 ctrl;
struct_group(inv, /* Invariants */
u32 freq_mult;
u16 freq_base;
u16 freq_m;
u16 freq_n;
u8 ctrl;
);
};
int zl3073x_synth_state_fetch(struct zl3073x_dev *zldev, u8 synth_id);
@ -32,9 +35,6 @@ int zl3073x_synth_state_fetch(struct zl3073x_dev *zldev, u8 synth_id);
const struct zl3073x_synth *zl3073x_synth_state_get(struct zl3073x_dev *zldev,
u8 synth_id);
int zl3073x_synth_state_set(struct zl3073x_dev *zldev, u8 synth_id,
const struct zl3073x_synth *synth);
/**
* zl3073x_synth_dpll_get - get DPLL ID the synth is driven by
* @synth: pointer to synth state

View File

@ -1655,7 +1655,7 @@ static int gen11_dsi_dsc_compute_config(struct intel_encoder *encoder,
if (ret)
return ret;
crtc_state->dsc.compression_enable = true;
intel_dsc_enable_on_crtc(crtc_state);
return 0;
}

View File

@ -4639,7 +4639,7 @@ intel_modeset_pipe_config(struct intel_atomic_state *state,
if (ret)
return ret;
crtc_state->fec_enable = limits->force_fec_pipes & BIT(crtc->pipe);
crtc_state->dsc.compression_enabled_on_link = limits->link_dsc_pipes & BIT(crtc->pipe);
crtc_state->max_link_bpp_x16 = limits->max_bpp_x16[crtc->pipe];
if (crtc_state->pipe_bpp > fxp_q4_to_int(crtc_state->max_link_bpp_x16)) {

View File

@ -946,6 +946,12 @@ struct intel_csc_matrix {
u16 postoff[3];
};
enum intel_panel_replay_dsc_support {
INTEL_DP_PANEL_REPLAY_DSC_NOT_SUPPORTED,
INTEL_DP_PANEL_REPLAY_DSC_FULL_FRAME_ONLY,
INTEL_DP_PANEL_REPLAY_DSC_SELECTIVE_UPDATE,
};
struct intel_crtc_state {
/*
* uapi (drm) state. This is the software state shown to userspace.
@ -1124,6 +1130,8 @@ struct intel_crtc_state {
bool has_panel_replay;
bool wm_level_disabled;
bool pkg_c_latency_used;
/* Only used for state verification. */
enum intel_panel_replay_dsc_support panel_replay_dsc_support;
u32 dc3co_exitline;
u16 su_y_granularity;
u8 active_non_psr_pipes;
@ -1268,6 +1276,8 @@ struct intel_crtc_state {
/* Display Stream compression state */
struct {
/* Only used for state computation, not read out from the HW. */
bool compression_enabled_on_link;
bool compression_enable;
int num_streams;
/* Compressed Bpp in U6.4 format (first 4 bits for fractional part) */
@ -1679,6 +1689,7 @@ struct intel_psr {
bool source_panel_replay_support;
bool sink_panel_replay_support;
bool sink_panel_replay_su_support;
enum intel_panel_replay_dsc_support sink_panel_replay_dsc_support;
bool panel_replay_enabled;
u32 dc3co_exitline;
u32 dc3co_exit_delay;

View File

@ -2340,24 +2340,29 @@ static int intel_edp_dsc_compute_pipe_bpp(struct intel_dp *intel_dp,
return 0;
}
static void intel_dp_fec_compute_config(struct intel_dp *intel_dp,
struct intel_crtc_state *crtc_state)
/*
* Return whether FEC must be enabled for 8b10b SST or MST links. On 128b132b
* links FEC is always enabled implicitly by the HW, so this function returns
* false for that case.
*/
bool intel_dp_needs_8b10b_fec(const struct intel_crtc_state *crtc_state,
bool dsc_enabled_on_crtc)
{
if (intel_dp_is_uhbr(crtc_state))
return false;
if (crtc_state->fec_enable)
return;
return true;
/*
* Though eDP v1.5 supports FEC with DSC, unlike DP, it is optional.
* Since, FEC is a bandwidth overhead, continue to not enable it for
* eDP. Until, there is a good reason to do so.
*/
if (intel_dp_is_edp(intel_dp))
return;
if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP))
return false;
if (intel_dp_is_uhbr(crtc_state))
return;
crtc_state->fec_enable = true;
return dsc_enabled_on_crtc || intel_dsc_enabled_on_link(crtc_state);
}
int intel_dp_dsc_compute_config(struct intel_dp *intel_dp,
@ -2375,7 +2380,11 @@ int intel_dp_dsc_compute_config(struct intel_dp *intel_dp,
bool is_mst = intel_crtc_has_type(pipe_config, INTEL_OUTPUT_DP_MST);
int ret;
intel_dp_fec_compute_config(intel_dp, pipe_config);
/*
* FIXME: set the FEC enabled state once pipe_config->port_clock is
* already known, so the UHBR/non-UHBR mode can be determined.
*/
pipe_config->fec_enable = intel_dp_needs_8b10b_fec(pipe_config, true);
if (!intel_dp_dsc_supports_format(connector, pipe_config->output_format))
return -EINVAL;
@ -2450,7 +2459,8 @@ int intel_dp_dsc_compute_config(struct intel_dp *intel_dp,
return ret;
}
pipe_config->dsc.compression_enable = true;
intel_dsc_enable_on_crtc(pipe_config);
drm_dbg_kms(display->drm, "DP DSC computed with Input Bpp = %d "
"Compressed Bpp = " FXP_Q4_FMT " Slice Count = %d\n",
pipe_config->pipe_bpp,
@ -5921,6 +5931,8 @@ intel_dp_detect(struct drm_connector *_connector,
memset(connector->dp.dsc_dpcd, 0, sizeof(connector->dp.dsc_dpcd));
intel_dp->psr.sink_panel_replay_support = false;
intel_dp->psr.sink_panel_replay_su_support = false;
intel_dp->psr.sink_panel_replay_dsc_support =
INTEL_DP_PANEL_REPLAY_DSC_NOT_SUPPORTED;
intel_dp_mst_disconnect(intel_dp);

View File

@ -72,6 +72,8 @@ void intel_dp_encoder_flush_work(struct drm_encoder *encoder);
int intel_dp_compute_config(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config,
struct drm_connector_state *conn_state);
bool intel_dp_needs_8b10b_fec(const struct intel_crtc_state *crtc_state,
bool dsc_enabled_on_crtc);
int intel_dp_dsc_compute_config(struct intel_dp *intel_dp,
struct intel_crtc_state *pipe_config,
struct drm_connector_state *conn_state,

View File

@ -293,12 +293,15 @@ int intel_dp_mtp_tu_compute_config(struct intel_dp *intel_dp,
mst_stream_update_slots(crtc_state, mst_state);
}
if (dsc) {
if (!intel_dp_supports_fec(intel_dp, connector, crtc_state))
return -EINVAL;
crtc_state->fec_enable = !intel_dp_is_uhbr(crtc_state);
}
/*
* NOTE: The following must reset crtc_state->fec_enable for UHBR/DSC
* after it was set by intel_dp_dsc_compute_config() ->
* intel_dp_needs_8b10b_fec().
*/
crtc_state->fec_enable = intel_dp_needs_8b10b_fec(crtc_state, dsc);
if (crtc_state->fec_enable &&
!intel_dp_supports_fec(intel_dp, connector, crtc_state))
return -EINVAL;
max_dpt_bpp_x16 = fxp_q4_from_int(intel_dp_mst_max_dpt_bpp(crtc_state, dsc));
if (max_dpt_bpp_x16 && max_bpp_x16 > max_dpt_bpp_x16) {
@ -811,14 +814,14 @@ static u8 get_pipes_downstream_of_mst_port(struct intel_atomic_state *state,
return mask;
}
static int intel_dp_mst_check_fec_change(struct intel_atomic_state *state,
static int intel_dp_mst_check_dsc_change(struct intel_atomic_state *state,
struct drm_dp_mst_topology_mgr *mst_mgr,
struct intel_link_bw_limits *limits)
{
struct intel_display *display = to_intel_display(state);
struct intel_crtc *crtc;
u8 mst_pipe_mask;
u8 fec_pipe_mask = 0;
u8 dsc_pipe_mask = 0;
int ret;
mst_pipe_mask = get_pipes_downstream_of_mst_port(state, mst_mgr, NULL);
@ -831,16 +834,16 @@ static int intel_dp_mst_check_fec_change(struct intel_atomic_state *state,
if (drm_WARN_ON(display->drm, !crtc_state))
return -EINVAL;
if (crtc_state->fec_enable)
fec_pipe_mask |= BIT(crtc->pipe);
if (intel_dsc_enabled_on_link(crtc_state))
dsc_pipe_mask |= BIT(crtc->pipe);
}
if (!fec_pipe_mask || mst_pipe_mask == fec_pipe_mask)
if (!dsc_pipe_mask || mst_pipe_mask == dsc_pipe_mask)
return 0;
limits->force_fec_pipes |= mst_pipe_mask;
limits->link_dsc_pipes |= mst_pipe_mask;
ret = intel_modeset_pipes_in_mask_early(state, "MST FEC",
ret = intel_modeset_pipes_in_mask_early(state, "MST DSC",
mst_pipe_mask);
return ret ? : -EAGAIN;
@ -894,7 +897,7 @@ int intel_dp_mst_atomic_check_link(struct intel_atomic_state *state,
int i;
for_each_new_mst_mgr_in_state(&state->base, mgr, mst_state, i) {
ret = intel_dp_mst_check_fec_change(state, mgr, limits);
ret = intel_dp_mst_check_dsc_change(state, mgr, limits);
if (ret)
return ret;

View File

@ -20,6 +20,7 @@
#include "intel_dp_tunnel.h"
#include "intel_fdi.h"
#include "intel_link_bw.h"
#include "intel_vdsc.h"
static int get_forced_link_bpp_x16(struct intel_atomic_state *state,
const struct intel_crtc *crtc)
@ -55,7 +56,7 @@ void intel_link_bw_init_limits(struct intel_atomic_state *state,
struct intel_display *display = to_intel_display(state);
enum pipe pipe;
limits->force_fec_pipes = 0;
limits->link_dsc_pipes = 0;
limits->bpp_limit_reached_pipes = 0;
for_each_pipe(display, pipe) {
struct intel_crtc *crtc = intel_crtc_for_pipe(display, pipe);
@ -65,8 +66,8 @@ void intel_link_bw_init_limits(struct intel_atomic_state *state,
if (state->base.duplicated && crtc_state) {
limits->max_bpp_x16[pipe] = crtc_state->max_link_bpp_x16;
if (crtc_state->fec_enable)
limits->force_fec_pipes |= BIT(pipe);
if (intel_dsc_enabled_on_link(crtc_state))
limits->link_dsc_pipes |= BIT(pipe);
} else {
limits->max_bpp_x16[pipe] = INT_MAX;
}
@ -265,10 +266,10 @@ assert_link_limit_change_valid(struct intel_display *display,
bool bpps_changed = false;
enum pipe pipe;
/* FEC can't be forced off after it was forced on. */
/* DSC can't be disabled after it was enabled. */
if (drm_WARN_ON(display->drm,
(old_limits->force_fec_pipes & new_limits->force_fec_pipes) !=
old_limits->force_fec_pipes))
(old_limits->link_dsc_pipes & new_limits->link_dsc_pipes) !=
old_limits->link_dsc_pipes))
return false;
for_each_pipe(display, pipe) {
@ -286,8 +287,8 @@ assert_link_limit_change_valid(struct intel_display *display,
/* At least one limit must change. */
if (drm_WARN_ON(display->drm,
!bpps_changed &&
new_limits->force_fec_pipes ==
old_limits->force_fec_pipes))
new_limits->link_dsc_pipes ==
old_limits->link_dsc_pipes))
return false;
return true;

View File

@ -15,7 +15,7 @@ struct intel_connector;
struct intel_crtc_state;
struct intel_link_bw_limits {
u8 force_fec_pipes;
u8 link_dsc_pipes;
u8 bpp_limit_reached_pipes;
/* in 1/16 bpp units */
int max_bpp_x16[I915_MAX_PIPES];

View File

@ -29,6 +29,7 @@
#include <drm/drm_vblank.h>
#include "i915_reg.h"
#include "i915_utils.h"
#include "intel_alpm.h"
#include "intel_atomic.h"
#include "intel_crtc.h"
@ -50,6 +51,7 @@
#include "intel_snps_phy.h"
#include "intel_step.h"
#include "intel_vblank.h"
#include "intel_vdsc.h"
#include "intel_vrr.h"
#include "skl_universal_plane.h"
@ -580,6 +582,44 @@ exit:
intel_dp->psr.su_y_granularity = y;
}
static enum intel_panel_replay_dsc_support
compute_pr_dsc_support(struct intel_dp *intel_dp)
{
u8 pr_dsc_mode;
u8 val;
val = intel_dp->pr_dpcd[INTEL_PR_DPCD_INDEX(DP_PANEL_REPLAY_CAP_CAPABILITY)];
pr_dsc_mode = REG_FIELD_GET8(DP_PANEL_REPLAY_DSC_DECODE_CAPABILITY_IN_PR_MASK, val);
switch (pr_dsc_mode) {
case DP_DSC_DECODE_CAPABILITY_IN_PR_FULL_FRAME_ONLY:
return INTEL_DP_PANEL_REPLAY_DSC_FULL_FRAME_ONLY;
case DP_DSC_DECODE_CAPABILITY_IN_PR_SUPPORTED:
return INTEL_DP_PANEL_REPLAY_DSC_SELECTIVE_UPDATE;
default:
MISSING_CASE(pr_dsc_mode);
fallthrough;
case DP_DSC_DECODE_CAPABILITY_IN_PR_NOT_SUPPORTED:
case DP_DSC_DECODE_CAPABILITY_IN_PR_RESERVED:
return INTEL_DP_PANEL_REPLAY_DSC_NOT_SUPPORTED;
}
}
static const char *panel_replay_dsc_support_str(enum intel_panel_replay_dsc_support dsc_support)
{
switch (dsc_support) {
case INTEL_DP_PANEL_REPLAY_DSC_NOT_SUPPORTED:
return "not supported";
case INTEL_DP_PANEL_REPLAY_DSC_FULL_FRAME_ONLY:
return "full frame only";
case INTEL_DP_PANEL_REPLAY_DSC_SELECTIVE_UPDATE:
return "selective update";
default:
MISSING_CASE(dsc_support);
return "n/a";
};
}
static void _panel_replay_init_dpcd(struct intel_dp *intel_dp)
{
struct intel_display *display = to_intel_display(intel_dp);
@ -619,10 +659,13 @@ static void _panel_replay_init_dpcd(struct intel_dp *intel_dp)
DP_PANEL_REPLAY_SU_SUPPORT)
intel_dp->psr.sink_panel_replay_su_support = true;
intel_dp->psr.sink_panel_replay_dsc_support = compute_pr_dsc_support(intel_dp);
drm_dbg_kms(display->drm,
"Panel replay %sis supported by panel\n",
"Panel replay %sis supported by panel (in DSC mode: %s)\n",
intel_dp->psr.sink_panel_replay_su_support ?
"selective_update " : "");
"selective_update " : "",
panel_replay_dsc_support_str(intel_dp->psr.sink_panel_replay_dsc_support));
}
static void _psr_init_dpcd(struct intel_dp *intel_dp)
@ -1534,9 +1577,21 @@ static bool intel_sel_update_config_valid(struct intel_dp *intel_dp,
goto unsupported;
}
if (crtc_state->has_panel_replay && (DISPLAY_VER(display) < 14 ||
!intel_dp->psr.sink_panel_replay_su_support))
goto unsupported;
if (crtc_state->has_panel_replay) {
if (DISPLAY_VER(display) < 14)
goto unsupported;
if (!intel_dp->psr.sink_panel_replay_su_support)
goto unsupported;
if (intel_dsc_enabled_on_link(crtc_state) &&
intel_dp->psr.sink_panel_replay_dsc_support !=
INTEL_DP_PANEL_REPLAY_DSC_SELECTIVE_UPDATE) {
drm_dbg_kms(display->drm,
"Selective update with Panel Replay not enabled because it's not supported with DSC\n");
goto unsupported;
}
}
if (crtc_state->crc_enabled) {
drm_dbg_kms(display->drm,
@ -1613,6 +1668,14 @@ _panel_replay_compute_config(struct intel_dp *intel_dp,
return false;
}
if (intel_dsc_enabled_on_link(crtc_state) &&
intel_dp->psr.sink_panel_replay_dsc_support ==
INTEL_DP_PANEL_REPLAY_DSC_NOT_SUPPORTED) {
drm_dbg_kms(display->drm,
"Panel Replay not enabled because it's not supported with DSC\n");
return false;
}
if (!intel_dp_is_edp(intel_dp))
return true;
@ -1693,6 +1756,8 @@ void intel_psr_compute_config(struct intel_dp *intel_dp,
return;
}
/* Only used for state verification. */
crtc_state->panel_replay_dsc_support = intel_dp->psr.sink_panel_replay_dsc_support;
crtc_state->has_panel_replay = _panel_replay_compute_config(intel_dp,
crtc_state,
conn_state);
@ -2950,6 +3015,20 @@ void intel_psr_pre_plane_update(struct intel_atomic_state *state,
}
}
static void
verify_panel_replay_dsc_state(const struct intel_crtc_state *crtc_state)
{
struct intel_display *display = to_intel_display(crtc_state);
if (!crtc_state->has_panel_replay)
return;
drm_WARN_ON(display->drm,
intel_dsc_enabled_on_link(crtc_state) &&
crtc_state->panel_replay_dsc_support ==
INTEL_DP_PANEL_REPLAY_DSC_NOT_SUPPORTED);
}
void intel_psr_post_plane_update(struct intel_atomic_state *state,
struct intel_crtc *crtc)
{
@ -2961,6 +3040,8 @@ void intel_psr_post_plane_update(struct intel_atomic_state *state,
if (!crtc_state->has_psr)
return;
verify_panel_replay_dsc_state(crtc_state);
for_each_intel_encoder_mask_with_psr(state->base.dev, encoder,
crtc_state->uapi.encoder_mask) {
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
@ -3990,6 +4071,8 @@ static void intel_psr_sink_capability(struct intel_dp *intel_dp,
seq_printf(m, ", Panel Replay = %s", str_yes_no(psr->sink_panel_replay_support));
seq_printf(m, ", Panel Replay Selective Update = %s",
str_yes_no(psr->sink_panel_replay_su_support));
seq_printf(m, ", Panel Replay DSC support = %s",
panel_replay_dsc_support_str(psr->sink_panel_replay_dsc_support));
if (intel_dp->pr_dpcd[INTEL_PR_DPCD_INDEX(DP_PANEL_REPLAY_CAP_SUPPORT)] &
DP_PANEL_REPLAY_EARLY_TRANSPORT_SUPPORT)
seq_printf(m, " (Early Transport)");

View File

@ -372,6 +372,22 @@ int intel_dsc_compute_params(struct intel_crtc_state *pipe_config)
return 0;
}
void intel_dsc_enable_on_crtc(struct intel_crtc_state *crtc_state)
{
crtc_state->dsc.compression_enabled_on_link = true;
crtc_state->dsc.compression_enable = true;
}
bool intel_dsc_enabled_on_link(const struct intel_crtc_state *crtc_state)
{
struct intel_display *display = to_intel_display(crtc_state);
drm_WARN_ON(display->drm, crtc_state->dsc.compression_enable &&
!crtc_state->dsc.compression_enabled_on_link);
return crtc_state->dsc.compression_enabled_on_link;
}
enum intel_display_power_domain
intel_dsc_power_domain(struct intel_crtc *crtc, enum transcoder cpu_transcoder)
{

View File

@ -20,6 +20,8 @@ void intel_uncompressed_joiner_enable(const struct intel_crtc_state *crtc_state)
void intel_dsc_enable(const struct intel_crtc_state *crtc_state);
void intel_dsc_disable(const struct intel_crtc_state *crtc_state);
int intel_dsc_compute_params(struct intel_crtc_state *pipe_config);
void intel_dsc_enable_on_crtc(struct intel_crtc_state *crtc_state);
bool intel_dsc_enabled_on_link(const struct intel_crtc_state *crtc_state);
void intel_dsc_get_config(struct intel_crtc_state *crtc_state);
enum intel_display_power_domain
intel_dsc_power_domain(struct intel_crtc *crtc, enum transcoder cpu_transcoder);

View File

@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/delay.h>
#include <linux/iopoll.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_edid.h>
@ -12,7 +13,7 @@
void mgag200_bmc_stop_scanout(struct mga_device *mdev)
{
u8 tmp;
int iter_max;
int ret;
/*
* 1 - The first step is to inform the BMC of an upcoming mode
@ -42,30 +43,22 @@ void mgag200_bmc_stop_scanout(struct mga_device *mdev)
/*
* 3a- The third step is to verify if there is an active scan.
* We are waiting for a 0 on remhsyncsts <XSPAREREG<0>).
* We are waiting for a 0 on remhsyncsts (<XSPAREREG<0>).
*/
iter_max = 300;
while (!(tmp & 0x1) && iter_max) {
WREG8(DAC_INDEX, MGA1064_SPAREREG);
tmp = RREG8(DAC_DATA);
udelay(1000);
iter_max--;
}
ret = read_poll_timeout(RREG_DAC, tmp, !(tmp & 0x1),
1000, 300000, false,
MGA1064_SPAREREG);
if (ret == -ETIMEDOUT)
return;
/*
* 3b- This step occurs only if the remove is actually
* 3b- This step occurs only if the remote BMC is actually
* scanning. We are waiting for the end of the frame which is
* a 1 on remvsyncsts (XSPAREREG<1>)
*/
if (iter_max) {
iter_max = 300;
while ((tmp & 0x2) && iter_max) {
WREG8(DAC_INDEX, MGA1064_SPAREREG);
tmp = RREG8(DAC_DATA);
udelay(1000);
iter_max--;
}
}
(void)read_poll_timeout(RREG_DAC, tmp, (tmp & 0x2),
1000, 300000, false,
MGA1064_SPAREREG);
}
void mgag200_bmc_start_scanout(struct mga_device *mdev)

View File

@ -111,6 +111,12 @@
#define DAC_INDEX 0x3c00
#define DAC_DATA 0x3c0a
#define RREG_DAC(reg) \
({ \
WREG8(DAC_INDEX, reg); \
RREG8(DAC_DATA); \
}) \
#define WREG_DAC(reg, v) \
do { \
WREG8(DAC_INDEX, reg); \

View File

@ -1208,10 +1208,20 @@ static int wacom_intuos_bt_irq(struct wacom_wac *wacom, size_t len)
switch (data[0]) {
case 0x04:
if (len < 32) {
dev_warn(wacom->pen_input->dev.parent,
"Report 0x04 too short: %zu bytes\n", len);
break;
}
wacom_intuos_bt_process_data(wacom, data + i);
i += 10;
fallthrough;
case 0x03:
if (i == 1 && len < 22) {
dev_warn(wacom->pen_input->dev.parent,
"Report 0x03 too short: %zu bytes\n", len);
break;
}
wacom_intuos_bt_process_data(wacom, data + i);
i += 10;
wacom_intuos_bt_process_data(wacom, data + i);

View File

@ -221,13 +221,11 @@ ib_umem_dmabuf_get_pinned_with_dma_device(struct ib_device *device,
err = ib_umem_dmabuf_map_pages(umem_dmabuf);
if (err)
goto err_unpin;
goto err_release;
dma_resv_unlock(umem_dmabuf->attach->dmabuf->resv);
return umem_dmabuf;
err_unpin:
dma_buf_unpin(umem_dmabuf->attach);
err_release:
dma_resv_unlock(umem_dmabuf->attach->dmabuf->resv);
ib_umem_release(&umem_dmabuf->umem);

View File

@ -170,6 +170,9 @@ static int map_cc_config_offset_gen0_ext0(u32 offset, struct bnxt_qplib_cc_param
case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_TCP_CP:
*val = ccparam->tcp_cp;
break;
case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_INACTIVITY_CP:
*val = ccparam->inact_th;
break;
default:
return -EINVAL;
}
@ -203,7 +206,7 @@ static ssize_t bnxt_re_cc_config_get(struct file *filp, char __user *buffer,
return simple_read_from_buffer(buffer, usr_buf_len, ppos, (u8 *)(buf), rc);
}
static void bnxt_re_fill_gen0_ext0(struct bnxt_qplib_cc_param *ccparam, u32 offset, u32 val)
static int bnxt_re_fill_gen0_ext0(struct bnxt_qplib_cc_param *ccparam, u32 offset, u32 val)
{
u32 modify_mask;
@ -247,7 +250,9 @@ static void bnxt_re_fill_gen0_ext0(struct bnxt_qplib_cc_param *ccparam, u32 offs
ccparam->tcp_cp = val;
break;
case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_TX_QUEUE:
return -EOPNOTSUPP;
case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_INACTIVITY_CP:
ccparam->inact_th = val;
break;
case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_TIME_PER_PHASE:
ccparam->time_pph = val;
@ -258,17 +263,20 @@ static void bnxt_re_fill_gen0_ext0(struct bnxt_qplib_cc_param *ccparam, u32 offs
}
ccparam->mask = modify_mask;
return 0;
}
static int bnxt_re_configure_cc(struct bnxt_re_dev *rdev, u32 gen_ext, u32 offset, u32 val)
{
struct bnxt_qplib_cc_param ccparam = { };
int rc;
/* Supporting only Gen 0 now */
if (gen_ext == CC_CONFIG_GEN0_EXT0)
bnxt_re_fill_gen0_ext0(&ccparam, offset, val);
else
return -EINVAL;
if (gen_ext != CC_CONFIG_GEN0_EXT0)
return -EOPNOTSUPP;
rc = bnxt_re_fill_gen0_ext0(&ccparam, offset, val);
if (rc)
return rc;
bnxt_qplib_modify_cc(&rdev->qplib_res, &ccparam);
return 0;

View File

@ -4746,7 +4746,7 @@ static int UVERBS_HANDLER(BNXT_RE_METHOD_GET_TOGGLE_MEM)(struct uverbs_attr_bund
return err;
err = uverbs_copy_to(attrs, BNXT_RE_TOGGLE_MEM_MMAP_OFFSET,
&offset, sizeof(length));
&offset, sizeof(offset));
if (err)
return err;

View File

@ -1113,7 +1113,7 @@ int bnxt_qplib_create_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp)
qp_flags |= CMDQ_CREATE_QP_QP_FLAGS_FORCE_COMPLETION;
if (qp->wqe_mode == BNXT_QPLIB_WQE_MODE_VARIABLE)
qp_flags |= CMDQ_CREATE_QP_QP_FLAGS_VARIABLE_SIZED_WQE_ENABLED;
if (_is_ext_stats_supported(res->dattr->dev_cap_flags) && !res->is_vf)
if (bnxt_ext_stats_supported(res->cctx, res->dattr->dev_cap_flags, res->is_vf))
qp_flags |= CMDQ_CREATE_QP_QP_FLAGS_EXT_STATS_ENABLED;
req.qp_flags = cpu_to_le32(qp_flags);
@ -1750,9 +1750,9 @@ static void bnxt_qplib_fill_psn_search(struct bnxt_qplib_qp *qp,
}
}
static int bnxt_qplib_put_inline(struct bnxt_qplib_qp *qp,
struct bnxt_qplib_swqe *wqe,
u16 *idx)
static unsigned int bnxt_qplib_put_inline(struct bnxt_qplib_qp *qp,
struct bnxt_qplib_swqe *wqe,
u32 *idx)
{
struct bnxt_qplib_hwq *hwq;
int len, t_len, offt;
@ -1769,7 +1769,7 @@ static int bnxt_qplib_put_inline(struct bnxt_qplib_qp *qp,
il_src = (void *)wqe->sg_list[indx].addr;
t_len += len;
if (t_len > qp->max_inline_data)
return -ENOMEM;
return BNXT_RE_INVAL_MSG_SIZE;
while (len) {
if (pull_dst) {
pull_dst = false;
@ -1795,9 +1795,9 @@ static int bnxt_qplib_put_inline(struct bnxt_qplib_qp *qp,
return t_len;
}
static u32 bnxt_qplib_put_sges(struct bnxt_qplib_hwq *hwq,
struct bnxt_qplib_sge *ssge,
u16 nsge, u16 *idx)
static unsigned int bnxt_qplib_put_sges(struct bnxt_qplib_hwq *hwq,
struct bnxt_qplib_sge *ssge,
u32 nsge, u32 *idx)
{
struct sq_sge *dsge;
int indx, len = 0;
@ -1878,14 +1878,12 @@ int bnxt_qplib_post_send(struct bnxt_qplib_qp *qp,
struct bnxt_qplib_hwq *hwq;
struct bnxt_qplib_swq *swq;
bool sch_handler = false;
u32 wqe_idx, slots, idx;
u16 wqe_sz, qdf = 0;
bool msn_update;
void *base_hdr;
void *ext_hdr;
__le32 temp32;
u32 wqe_idx;
u32 slots;
u16 idx;
hwq = &sq->hwq;
if (qp->state != CMDQ_MODIFY_QP_NEW_STATE_RTS &&
@ -1937,8 +1935,10 @@ int bnxt_qplib_post_send(struct bnxt_qplib_qp *qp,
else
data_len = bnxt_qplib_put_sges(hwq, wqe->sg_list, wqe->num_sge,
&idx);
if (data_len < 0)
goto queue_err;
if (data_len > BNXT_RE_MAX_MSG_SIZE) {
rc = -EINVAL;
goto done;
}
/* Make sure we update MSN table only for wired wqes */
msn_update = true;
/* Specifics */
@ -2139,8 +2139,8 @@ int bnxt_qplib_post_recv(struct bnxt_qplib_qp *qp,
struct bnxt_qplib_hwq *hwq;
struct bnxt_qplib_swq *swq;
bool sch_handler = false;
u16 wqe_sz, idx;
u32 wqe_idx;
u32 wqe_idx, idx;
u16 wqe_sz;
int rc = 0;
hwq = &rq->hwq;

View File

@ -346,6 +346,9 @@ struct bnxt_qplib_qp {
u8 tos_dscp;
};
#define BNXT_RE_MAX_MSG_SIZE 0x80000000
#define BNXT_RE_INVAL_MSG_SIZE 0xFFFFFFFF
#define BNXT_QPLIB_MAX_CQE_ENTRY_SIZE sizeof(struct cq_base)
#define CQE_CNT_PER_PG (PAGE_SIZE / BNXT_QPLIB_MAX_CQE_ENTRY_SIZE)

View File

@ -160,7 +160,7 @@ static int __wait_for_resp(struct bnxt_qplib_rcfw *rcfw, u16 cookie)
wait_event_timeout(cmdq->waitq,
!crsqe->is_in_used ||
test_bit(ERR_DEVICE_DETACHED, &cmdq->flags),
msecs_to_jiffies(rcfw->max_timeout * 1000));
secs_to_jiffies(rcfw->max_timeout));
if (!crsqe->is_in_used)
return 0;

View File

@ -674,7 +674,7 @@ int bnxt_qplib_reg_mr(struct bnxt_qplib_res *res, struct bnxt_qplib_mrw *mr,
req.log2_pbl_pg_size = cpu_to_le16(((ilog2(PAGE_SIZE) <<
CMDQ_REGISTER_MR_LOG2_PBL_PG_SIZE_SFT) &
CMDQ_REGISTER_MR_LOG2_PBL_PG_SIZE_MASK));
req.access = (mr->access_flags & 0xFFFF);
req.access = (mr->access_flags & BNXT_QPLIB_MR_ACCESS_MASK);
req.va = cpu_to_le64(mr->va);
req.key = cpu_to_le32(mr->lkey);
if (_is_alloc_mr_unified(res->dattr->dev_cap_flags))
@ -846,7 +846,12 @@ int bnxt_qplib_qext_stat(struct bnxt_qplib_rcfw *rcfw, u32 fid,
req.resp_size = sbuf.size / BNXT_QPLIB_CMDQE_UNITS;
req.resp_addr = cpu_to_le64(sbuf.dma_addr);
req.function_id = cpu_to_le32(fid);
if (bnxt_qplib_is_chip_gen_p7(rcfw->res->cctx) && rcfw->res->is_vf)
req.function_id =
cpu_to_le32(CMDQ_QUERY_ROCE_STATS_EXT_VF_VALID |
(fid << CMDQ_QUERY_ROCE_STATS_EXT_VF_NUM_SFT));
else
req.function_id = cpu_to_le32(fid);
req.flags = cpu_to_le16(CMDQ_QUERY_ROCE_STATS_EXT_FLAGS_FUNCTION_ID);
bnxt_qplib_fill_cmdqmsg(&msg, &req, &resp, &sbuf, sizeof(req),

View File

@ -111,6 +111,7 @@ struct bnxt_qplib_mrw {
struct bnxt_qplib_pd *pd;
int type;
u32 access_flags;
#define BNXT_QPLIB_MR_ACCESS_MASK 0xFF
#define BNXT_QPLIB_FR_PMR 0x80000000
u32 lkey;
u32 rkey;

View File

@ -490,12 +490,20 @@ static int rebalance_children(struct shadow_spine *s,
if (le32_to_cpu(n->header.nr_entries) == 1) {
struct dm_block *child;
int is_shared;
dm_block_t b = value64(n, 0);
r = dm_tm_block_is_shared(info->tm, b, &is_shared);
if (r)
return r;
r = dm_tm_read_lock(info->tm, b, &btree_node_validator, &child);
if (r)
return r;
if (is_shared)
inc_children(info->tm, dm_block_data(child), vt);
memcpy(n, dm_block_data(child),
dm_bm_block_size(dm_tm_get_bm(info->tm)));

View File

@ -3014,6 +3014,19 @@ static int dpaa2_switch_init(struct fsl_mc_device *sw_dev)
goto err_close;
}
if (!ethsw->sw_attr.num_ifs) {
dev_err(dev, "DPSW device has no interfaces\n");
err = -ENODEV;
goto err_close;
}
if (ethsw->sw_attr.num_ifs >= DPSW_MAX_IF) {
dev_err(dev, "DPSW num_ifs %u exceeds max %u\n",
ethsw->sw_attr.num_ifs, DPSW_MAX_IF);
err = -EINVAL;
goto err_close;
}
err = dpsw_get_api_version(ethsw->mc_io, 0,
&ethsw->major,
&ethsw->minor);

View File

@ -9030,7 +9030,6 @@ int i40e_open(struct net_device *netdev)
TCP_FLAG_FIN |
TCP_FLAG_CWR) >> 16);
wr32(&pf->hw, I40E_GLLAN_TSOMSK_L, be32_to_cpu(TCP_FLAG_CWR) >> 16);
udp_tunnel_get_rx_info(netdev);
return 0;
}

View File

@ -839,6 +839,28 @@ static inline void ice_tx_xsk_pool(struct ice_vsi *vsi, u16 qid)
WRITE_ONCE(ring->xsk_pool, ice_get_xp_from_qid(vsi, qid));
}
/**
* ice_get_max_txq - return the maximum number of Tx queues for in a PF
* @pf: PF structure
*
* Return: maximum number of Tx queues
*/
static inline int ice_get_max_txq(struct ice_pf *pf)
{
return min(num_online_cpus(), pf->hw.func_caps.common_cap.num_txq);
}
/**
* ice_get_max_rxq - return the maximum number of Rx queues for in a PF
* @pf: PF structure
*
* Return: maximum number of Rx queues
*/
static inline int ice_get_max_rxq(struct ice_pf *pf)
{
return min(num_online_cpus(), pf->hw.func_caps.common_cap.num_rxq);
}
/**
* ice_get_main_vsi - Get the PF VSI
* @pf: PF instance

View File

@ -3756,24 +3756,6 @@ ice_get_ts_info(struct net_device *dev, struct kernel_ethtool_ts_info *info)
return 0;
}
/**
* ice_get_max_txq - return the maximum number of Tx queues for in a PF
* @pf: PF structure
*/
static int ice_get_max_txq(struct ice_pf *pf)
{
return min(num_online_cpus(), pf->hw.func_caps.common_cap.num_txq);
}
/**
* ice_get_max_rxq - return the maximum number of Rx queues for in a PF
* @pf: PF structure
*/
static int ice_get_max_rxq(struct ice_pf *pf)
{
return min(num_online_cpus(), pf->hw.func_caps.common_cap.num_rxq);
}
/**
* ice_get_combined_cnt - return the current number of combined channels
* @vsi: PF VSI pointer

View File

@ -106,9 +106,10 @@ static struct ice_irq_entry *ice_get_irq_res(struct ice_pf *pf,
#define ICE_RDMA_AEQ_MSIX 1
static int ice_get_default_msix_amount(struct ice_pf *pf)
{
return ICE_MIN_LAN_OICR_MSIX + num_online_cpus() +
return ICE_MIN_LAN_OICR_MSIX + netif_get_num_default_rss_queues() +
(test_bit(ICE_FLAG_FD_ENA, pf->flags) ? ICE_FDIR_MSIX : 0) +
(ice_is_rdma_ena(pf) ? num_online_cpus() + ICE_RDMA_AEQ_MSIX : 0);
(ice_is_rdma_ena(pf) ? netif_get_num_default_rss_queues() +
ICE_RDMA_AEQ_MSIX : 0);
}
/**

View File

@ -155,12 +155,14 @@ static void ice_vsi_set_num_desc(struct ice_vsi *vsi)
static u16 ice_get_rxq_count(struct ice_pf *pf)
{
return min(ice_get_avail_rxq_count(pf), num_online_cpus());
return min(ice_get_avail_rxq_count(pf),
netif_get_num_default_rss_queues());
}
static u16 ice_get_txq_count(struct ice_pf *pf)
{
return min(ice_get_avail_txq_count(pf), num_online_cpus());
return min(ice_get_avail_txq_count(pf),
netif_get_num_default_rss_queues());
}
/**
@ -909,13 +911,15 @@ static void ice_vsi_set_rss_params(struct ice_vsi *vsi)
if (vsi->type == ICE_VSI_CHNL)
vsi->rss_size = min_t(u16, vsi->num_rxq, max_rss_size);
else
vsi->rss_size = min_t(u16, num_online_cpus(),
vsi->rss_size = min_t(u16,
netif_get_num_default_rss_queues(),
max_rss_size);
vsi->rss_lut_type = ICE_LUT_PF;
break;
case ICE_VSI_SF:
vsi->rss_table_size = ICE_LUT_VSI_SIZE;
vsi->rss_size = min_t(u16, num_online_cpus(), max_rss_size);
vsi->rss_size = min_t(u16, netif_get_num_default_rss_queues(),
max_rss_size);
vsi->rss_lut_type = ICE_LUT_VSI;
break;
case ICE_VSI_VF:

View File

@ -4699,8 +4699,8 @@ static int ice_cfg_netdev(struct ice_vsi *vsi)
struct net_device *netdev;
u8 mac_addr[ETH_ALEN];
netdev = alloc_etherdev_mqs(sizeof(*np), vsi->alloc_txq,
vsi->alloc_rxq);
netdev = alloc_etherdev_mqs(sizeof(*np), ice_get_max_txq(vsi->back),
ice_get_max_rxq(vsi->back));
if (!netdev)
return -ENOMEM;
@ -9665,9 +9665,6 @@ int ice_open_internal(struct net_device *netdev)
netdev_err(netdev, "Failed to open VSI 0x%04X on switch 0x%04X\n",
vsi->vsi_num, vsi->vsw->sw_id);
/* Update existing tunnels information */
udp_tunnel_get_rx_info(netdev);
return err;
}

View File

@ -300,7 +300,8 @@ static int mlx5_dpll_state_on_dpll_set(const struct dpll_pin *pin,
static int mlx5_dpll_ffo_get(const struct dpll_pin *pin, void *pin_priv,
const struct dpll_device *dpll, void *dpll_priv,
s64 *ffo, struct netlink_ext_ack *extack)
struct dpll_ffo_param *ffo,
struct netlink_ext_ack *extack)
{
struct mlx5_dpll_synce_status synce_status;
struct mlx5_dpll *mdpll = pin_priv;
@ -309,10 +310,11 @@ static int mlx5_dpll_ffo_get(const struct dpll_pin *pin, void *pin_priv,
err = mlx5_dpll_synce_status_get(mdpll->mdev, &synce_status);
if (err)
return err;
return mlx5_dpll_pin_ffo_get(&synce_status, ffo);
return mlx5_dpll_pin_ffo_get(&synce_status, &ffo->ffo);
}
static const struct dpll_pin_ops mlx5_dpll_pins_ops = {
.supported_ffo = BIT(DPLL_FFO_PORT_RXTX_RATE),
.direction_get = mlx5_dpll_pin_direction_get,
.state_on_dpll_get = mlx5_dpll_state_on_dpll_get,
.state_on_dpll_set = mlx5_dpll_state_on_dpll_set,

View File

@ -1719,13 +1719,18 @@ static int ionic_set_mac_address(struct net_device *netdev, void *sa)
if (ether_addr_equal(netdev->dev_addr, mac))
return 0;
err = ionic_program_mac(lif, mac);
if (err < 0)
return err;
/* Only program macs for virtual functions to avoid losing the permanent
* Mac across warm reset/reboot.
*/
if (lif->ionic->pdev->is_virtfn) {
err = ionic_program_mac(lif, mac);
if (err < 0)
return err;
if (err > 0)
netdev_dbg(netdev, "%s: SET and GET ATTR Mac are not equal-due to old FW running\n",
__func__);
if (err > 0)
netdev_dbg(netdev, "%s: SET and GET ATTR Mac are not equal-due to old FW running\n",
__func__);
}
err = eth_prepare_mac_addr_change(netdev, addr);
if (err)

View File

@ -1757,6 +1757,9 @@ static int netvsc_set_rxfh(struct net_device *dev,
rxfh->hfunc != ETH_RSS_HASH_TOP)
return -EOPNOTSUPP;
if (!ndc->rx_table_sz)
return -EOPNOTSUPP;
rndis_dev = ndev->extension;
if (rxfh->indir) {
for (i = 0; i < ndc->rx_table_sz; i++)

View File

@ -153,6 +153,11 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr,
bphy_err(drvr, "invalid interface index: %u\n", ifevent->ifidx);
return;
}
if (ifevent->bsscfgidx >= BRCMF_MAX_IFS) {
bphy_err(drvr, "invalid bsscfg index: %u\n",
ifevent->bsscfgidx);
return;
}
ifp = drvr->iflist[ifevent->bsscfgidx];

View File

@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
* Copyright (C) 2017-2025 Broadcom. All Rights Reserved. The term *
* Copyright (C) 2017-2024 Broadcom. All Rights Reserved. The term *
* Broadcom refers to Broadcom Inc. and/or its subsidiaries. *
* Copyright (C) 2004-2016 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@ -312,6 +312,7 @@ struct lpfc_defer_flogi_acc {
u16 rx_id;
u16 ox_id;
struct lpfc_nodelist *ndlp;
};
#define LPFC_VMID_TIMER 300 /* timer interval in seconds */
@ -634,7 +635,6 @@ struct lpfc_vport {
#define FC_CT_RSPN_ID 0x8 /* RSPN_ID accepted by switch */
#define FC_CT_RFT_ID 0x10 /* RFT_ID accepted by switch */
#define FC_CT_RPRT_DEFER 0x20 /* Defer issuing FDMI RPRT */
#define FC_CT_RSPNI_PNI 0x40 /* RSPNI_PNI accepted by switch */
struct list_head fc_nodes;
spinlock_t fc_nodes_list_lock; /* spinlock for fc_nodes list */
@ -662,12 +662,15 @@ struct lpfc_vport {
uint32_t num_disc_nodes; /* in addition to hba_state */
uint32_t gidft_inp; /* cnt of outstanding GID_FTs */
uint32_t fc_nlp_cnt; /* outstanding NODELIST requests */
uint32_t fc_rscn_id_cnt; /* count of RSCNs payloads in list */
uint32_t fc_rscn_flush; /* flag use of fc_rscn_id_list */
struct lpfc_dmabuf *fc_rscn_id_list[FC_MAX_HOLD_RSCN];
struct lpfc_name fc_nodename; /* fc nodename */
struct lpfc_name fc_portname; /* fc portname */
struct lpfc_work_evt disc_timeout_evt;
struct timer_list fc_disctmo; /* Discovery rescue timer */
uint8_t fc_ns_retry; /* retries for fabric nameserver */
uint32_t fc_prli_sent; /* cntr for outstanding PRLIs */
@ -742,6 +745,12 @@ struct lpfc_vport {
struct lpfc_vmid_priority_info vmid_priority;
#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
struct dentry *debug_disc_trc;
struct dentry *debug_nodelist;
struct dentry *debug_nvmestat;
struct dentry *debug_scsistat;
struct dentry *debug_ioktime;
struct dentry *debug_hdwqstat;
struct dentry *vport_debugfs_root;
struct lpfc_debugfs_trc *disc_trc;
atomic_t disc_trc_cnt;
@ -759,6 +768,7 @@ struct lpfc_vport {
/* There is a single nvme instance per vport. */
struct nvme_fc_local_port *localport;
uint8_t nvmei_support; /* driver supports NVME Initiator */
uint32_t last_fcp_wqidx;
uint32_t rcv_flogi_cnt; /* How many unsol FLOGIs ACK'd. */
};
@ -1051,6 +1061,8 @@ struct lpfc_hba {
struct lpfc_dmabuf hbqslimp;
uint16_t pci_cfg_value;
uint8_t fc_linkspeed; /* Link speed after last READ_LA */
uint32_t fc_eventTag; /* event tag for link attention */
@ -1077,10 +1089,9 @@ struct lpfc_hba {
struct lpfc_stats fc_stat;
struct lpfc_nodelist fc_fcpnodev; /* nodelist entry for no device */
uint32_t nport_event_cnt; /* timestamp for nlplist entry */
unsigned long pni; /* 64-bit Platform Name Identifier */
uint8_t wwnn[8];
uint8_t wwpn[8];
uint32_t RandomData[7];
@ -1219,6 +1230,9 @@ struct lpfc_hba {
uint32_t hbq_count; /* Count of configured HBQs */
struct hbq_s hbqs[LPFC_MAX_HBQS]; /* local copy of hbq indicies */
atomic_t fcp_qidx; /* next FCP WQ (RR Policy) */
atomic_t nvme_qidx; /* next NVME WQ (RR Policy) */
phys_addr_t pci_bar0_map; /* Physical address for PCI BAR0 */
phys_addr_t pci_bar1_map; /* Physical address for PCI BAR1 */
phys_addr_t pci_bar2_map; /* Physical address for PCI BAR2 */
@ -1335,9 +1349,30 @@ struct lpfc_hba {
unsigned long last_ramp_down_time;
#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
struct dentry *hba_debugfs_root;
unsigned int debugfs_vport_count;
atomic_t debugfs_vport_count;
struct dentry *debug_multixri_pools;
struct dentry *debug_hbqinfo;
struct dentry *debug_dumpHostSlim;
struct dentry *debug_dumpHBASlim;
struct dentry *debug_InjErrLBA; /* LBA to inject errors at */
struct dentry *debug_InjErrNPortID; /* NPortID to inject errors at */
struct dentry *debug_InjErrWWPN; /* WWPN to inject errors at */
struct dentry *debug_writeGuard; /* inject write guard_tag errors */
struct dentry *debug_writeApp; /* inject write app_tag errors */
struct dentry *debug_writeRef; /* inject write ref_tag errors */
struct dentry *debug_readGuard; /* inject read guard_tag errors */
struct dentry *debug_readApp; /* inject read app_tag errors */
struct dentry *debug_readRef; /* inject read ref_tag errors */
struct dentry *debug_nvmeio_trc;
struct lpfc_debugfs_nvmeio_trc *nvmeio_trc;
struct dentry *debug_hdwqinfo;
#ifdef LPFC_HDWQ_LOCK_STAT
struct dentry *debug_lockstat;
#endif
struct dentry *debug_cgn_buffer;
struct dentry *debug_rx_monitor;
struct dentry *debug_ras_log;
atomic_t nvmeio_trc_cnt;
uint32_t nvmeio_trc_size;
uint32_t nvmeio_trc_output_idx;
@ -1354,10 +1389,19 @@ struct lpfc_hba {
sector_t lpfc_injerr_lba;
#define LPFC_INJERR_LBA_OFF (sector_t)(-1)
struct dentry *debug_slow_ring_trc;
struct lpfc_debugfs_trc *slow_ring_trc;
atomic_t slow_ring_trc_cnt;
/* iDiag debugfs sub-directory */
struct dentry *idiag_root;
struct dentry *idiag_pci_cfg;
struct dentry *idiag_bar_acc;
struct dentry *idiag_que_info;
struct dentry *idiag_que_acc;
struct dentry *idiag_drb_acc;
struct dentry *idiag_ctl_acc;
struct dentry *idiag_mbx_acc;
struct dentry *idiag_ext_acc;
uint8_t lpfc_idiag_last_eq;
#endif
uint16_t nvmeio_trc_on;

View File

@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
* Copyright (C) 2017-2025 Broadcom. All Rights Reserved. The term *
* Copyright (C) 2017-2024 Broadcom. All Rights Reserved. The term *
* Broadcom refers to Broadcom Inc. and/or its subsidiaries. *
* Copyright (C) 2004-2016 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@ -264,9 +264,9 @@ ct_free_mpvirt:
ct_free_mp:
kfree(mp);
ct_exit:
lpfc_vlog_msg(vport, KERN_WARNING, LOG_ELS,
"6440 Unsol CT: Rsp err %d Data: x%lx\n",
rc, vport->fc_flag);
lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
"6440 Unsol CT: Rsp err %d Data: x%lx\n",
rc, vport->fc_flag);
}
/**
@ -313,7 +313,7 @@ lpfc_ct_handle_mibreq(struct lpfc_hba *phba, struct lpfc_iocbq *ctiocbq)
mi_cmd = be16_to_cpu(ct_req->CommandResponse.bits.CmdRsp);
lpfc_vlog_msg(vport, KERN_WARNING, LOG_ELS,
"6442 MI Cmd: x%x Not Supported\n", mi_cmd);
"6442 MI Cmd : x%x Not Supported\n", mi_cmd);
lpfc_ct_reject_event(ndlp, ct_req,
bf_get(wqe_ctxt_tag,
&ctiocbq->wqe.xmit_els_rsp.wqe_com),
@ -1742,28 +1742,6 @@ lpfc_cmpl_ct_cmd_rsnn_nn(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
return;
}
static void
lpfc_cmpl_ct_cmd_rspni_pni(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
struct lpfc_iocbq *rspiocb)
{
struct lpfc_vport *vport;
struct lpfc_dmabuf *outp;
struct lpfc_sli_ct_request *ctrsp;
u32 ulp_status;
vport = cmdiocb->vport;
ulp_status = get_job_ulpstatus(phba, rspiocb);
if (ulp_status == IOSTAT_SUCCESS) {
outp = cmdiocb->rsp_dmabuf;
ctrsp = (struct lpfc_sli_ct_request *)outp->virt;
if (be16_to_cpu(ctrsp->CommandResponse.bits.CmdRsp) ==
SLI_CT_RESPONSE_FS_ACC)
vport->ct_flags |= FC_CT_RSPNI_PNI;
}
lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
}
static void
lpfc_cmpl_ct_cmd_da_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
struct lpfc_iocbq *rspiocb)
@ -1978,8 +1956,6 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
bpl->tus.f.bdeSize = RSPN_REQUEST_SZ;
else if (cmdcode == SLI_CTNS_RSNN_NN)
bpl->tus.f.bdeSize = RSNN_REQUEST_SZ;
else if (cmdcode == SLI_CTNS_RSPNI_PNI)
bpl->tus.f.bdeSize = RSPNI_REQUEST_SZ;
else if (cmdcode == SLI_CTNS_DA_ID)
bpl->tus.f.bdeSize = DA_ID_REQUEST_SZ;
else if (cmdcode == SLI_CTNS_RFF_ID)
@ -2101,18 +2077,6 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
CtReq->un.rsnn.symbname, size);
cmpl = lpfc_cmpl_ct_cmd_rsnn_nn;
break;
case SLI_CTNS_RSPNI_PNI:
vport->ct_flags &= ~FC_CT_RSPNI_PNI;
CtReq->CommandResponse.bits.CmdRsp =
cpu_to_be16(SLI_CTNS_RSPNI_PNI);
CtReq->un.rspni.pni = cpu_to_be64(phba->pni);
scnprintf(CtReq->un.rspni.symbname,
sizeof(CtReq->un.rspni.symbname), "OS Host Name::%s",
phba->os_host_name);
CtReq->un.rspni.len = strnlen(CtReq->un.rspni.symbname,
sizeof(CtReq->un.rspni.symbname));
cmpl = lpfc_cmpl_ct_cmd_rspni_pni;
break;
case SLI_CTNS_DA_ID:
/* Implement DA_ID Nameserver request */
CtReq->CommandResponse.bits.CmdRsp =
@ -2265,6 +2229,21 @@ lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
/* Look for a retryable error */
if (ulp_status == IOSTAT_LOCAL_REJECT) {
switch ((ulp_word4 & IOERR_PARAM_MASK)) {
case IOERR_SLI_ABORTED:
case IOERR_SLI_DOWN:
/* Driver aborted this IO. No retry as error
* is likely Offline->Online or some adapter
* error. Recovery will try again, but if port
* is not active there's no point to continue
* issuing follow up FDMI commands.
*/
if (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE)) {
free_ndlp = cmdiocb->ndlp;
lpfc_ct_free_iocb(phba, cmdiocb);
lpfc_nlp_put(free_ndlp);
return;
}
break;
case IOERR_ABORT_IN_PROGRESS:
case IOERR_SEQUENCE_TIMEOUT:
case IOERR_ILLEGAL_FRAME:
@ -2290,9 +2269,6 @@ lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
lpfc_ct_free_iocb(phba, cmdiocb);
lpfc_nlp_put(free_ndlp);
if (ulp_status != IOSTAT_SUCCESS)
return;
ndlp = lpfc_findnode_did(vport, FDMI_DID);
if (!ndlp)
return;

View File

@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
* Copyright (C) 2017-2025 Broadcom. All Rights Reserved. The term *
* Copyright (C) 2017-2024 Broadcom. All Rights Reserved. The term *
* Broadcom refers to Broadcom Inc. and/or its subsidiaries. *
* Copyright (C) 2007-2015 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@ -2373,117 +2373,93 @@ out:
static ssize_t
lpfc_debugfs_dif_err_read(struct file *file, char __user *buf,
size_t nbytes, loff_t *ppos)
size_t nbytes, loff_t *ppos)
{
struct dentry *dent = file->f_path.dentry;
struct lpfc_hba *phba = file->private_data;
int kind = debugfs_get_aux_num(file);
char cbuf[32] = {0};
char cbuf[32];
uint64_t tmp = 0;
int cnt = 0;
switch (kind) {
case writeGuard:
cnt = scnprintf(cbuf, sizeof(cbuf), "%u\n",
phba->lpfc_injerr_wgrd_cnt);
break;
case writeApp:
cnt = scnprintf(cbuf, sizeof(cbuf), "%u\n",
phba->lpfc_injerr_wapp_cnt);
break;
case writeRef:
cnt = scnprintf(cbuf, sizeof(cbuf), "%u\n",
phba->lpfc_injerr_wref_cnt);
break;
case readGuard:
cnt = scnprintf(cbuf, sizeof(cbuf), "%u\n",
phba->lpfc_injerr_rgrd_cnt);
break;
case readApp:
cnt = scnprintf(cbuf, sizeof(cbuf), "%u\n",
phba->lpfc_injerr_rapp_cnt);
break;
case readRef:
cnt = scnprintf(cbuf, sizeof(cbuf), "%u\n",
phba->lpfc_injerr_rref_cnt);
break;
case InjErrNPortID:
cnt = scnprintf(cbuf, sizeof(cbuf), "0x%06x\n",
if (dent == phba->debug_writeGuard)
cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_wgrd_cnt);
else if (dent == phba->debug_writeApp)
cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_wapp_cnt);
else if (dent == phba->debug_writeRef)
cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_wref_cnt);
else if (dent == phba->debug_readGuard)
cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_rgrd_cnt);
else if (dent == phba->debug_readApp)
cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_rapp_cnt);
else if (dent == phba->debug_readRef)
cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_rref_cnt);
else if (dent == phba->debug_InjErrNPortID)
cnt = scnprintf(cbuf, 32, "0x%06x\n",
phba->lpfc_injerr_nportid);
break;
case InjErrWWPN:
cnt = scnprintf(cbuf, sizeof(cbuf), "0x%016llx\n",
be64_to_cpu(phba->lpfc_injerr_wwpn.u.wwn_be));
break;
case InjErrLBA:
if (phba->lpfc_injerr_lba == LPFC_INJERR_LBA_OFF)
cnt = scnprintf(cbuf, sizeof(cbuf), "off\n");
else if (dent == phba->debug_InjErrWWPN) {
memcpy(&tmp, &phba->lpfc_injerr_wwpn, sizeof(struct lpfc_name));
tmp = cpu_to_be64(tmp);
cnt = scnprintf(cbuf, 32, "0x%016llx\n", tmp);
} else if (dent == phba->debug_InjErrLBA) {
if (phba->lpfc_injerr_lba == (sector_t)(-1))
cnt = scnprintf(cbuf, 32, "off\n");
else
cnt = scnprintf(cbuf, sizeof(cbuf), "0x%llx\n",
(uint64_t)phba->lpfc_injerr_lba);
break;
default:
lpfc_log_msg(phba, KERN_WARNING, LOG_INIT,
"0547 Unknown debugfs error injection entry\n");
break;
}
cnt = scnprintf(cbuf, 32, "0x%llx\n",
(uint64_t) phba->lpfc_injerr_lba);
} else
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"0547 Unknown debugfs error injection entry\n");
return simple_read_from_buffer(buf, nbytes, ppos, &cbuf, cnt);
}
static ssize_t
lpfc_debugfs_dif_err_write(struct file *file, const char __user *buf,
size_t nbytes, loff_t *ppos)
size_t nbytes, loff_t *ppos)
{
struct dentry *dent = file->f_path.dentry;
struct lpfc_hba *phba = file->private_data;
int kind = debugfs_get_aux_num(file);
char dstbuf[33] = {0};
unsigned long long tmp;
unsigned long size;
char dstbuf[33];
uint64_t tmp = 0;
int size;
size = (nbytes < (sizeof(dstbuf) - 1)) ? nbytes : (sizeof(dstbuf) - 1);
memset(dstbuf, 0, 33);
size = (nbytes < 32) ? nbytes : 32;
if (copy_from_user(dstbuf, buf, size))
return -EFAULT;
if (kstrtoull(dstbuf, 0, &tmp)) {
if (kind != InjErrLBA || !strstr(dstbuf, "off"))
return -EINVAL;
if (dent == phba->debug_InjErrLBA) {
if ((dstbuf[0] == 'o') && (dstbuf[1] == 'f') &&
(dstbuf[2] == 'f'))
tmp = (uint64_t)(-1);
}
switch (kind) {
case writeGuard:
if ((tmp == 0) && (kstrtoull(dstbuf, 0, &tmp)))
return -EINVAL;
if (dent == phba->debug_writeGuard)
phba->lpfc_injerr_wgrd_cnt = (uint32_t)tmp;
break;
case writeApp:
else if (dent == phba->debug_writeApp)
phba->lpfc_injerr_wapp_cnt = (uint32_t)tmp;
break;
case writeRef:
else if (dent == phba->debug_writeRef)
phba->lpfc_injerr_wref_cnt = (uint32_t)tmp;
break;
case readGuard:
else if (dent == phba->debug_readGuard)
phba->lpfc_injerr_rgrd_cnt = (uint32_t)tmp;
break;
case readApp:
else if (dent == phba->debug_readApp)
phba->lpfc_injerr_rapp_cnt = (uint32_t)tmp;
break;
case readRef:
else if (dent == phba->debug_readRef)
phba->lpfc_injerr_rref_cnt = (uint32_t)tmp;
break;
case InjErrLBA:
if (strstr(dstbuf, "off"))
phba->lpfc_injerr_lba = LPFC_INJERR_LBA_OFF;
else
phba->lpfc_injerr_lba = (sector_t)tmp;
break;
case InjErrNPortID:
else if (dent == phba->debug_InjErrLBA)
phba->lpfc_injerr_lba = (sector_t)tmp;
else if (dent == phba->debug_InjErrNPortID)
phba->lpfc_injerr_nportid = (uint32_t)(tmp & Mask_DID);
break;
case InjErrWWPN:
phba->lpfc_injerr_wwpn.u.wwn_be = cpu_to_be64(tmp);
break;
default:
lpfc_log_msg(phba, KERN_WARNING, LOG_INIT,
"0548 Unknown debugfs error injection entry\n");
break;
}
else if (dent == phba->debug_InjErrWWPN) {
tmp = cpu_to_be64(tmp);
memcpy(&phba->lpfc_injerr_wwpn, &tmp, sizeof(struct lpfc_name));
} else
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"0548 Unknown debugfs error injection entry\n");
return nbytes;
}
@ -5752,7 +5728,7 @@ static const struct file_operations lpfc_debugfs_op_slow_ring_trc = {
};
static struct dentry *lpfc_debugfs_root = NULL;
static unsigned int lpfc_debugfs_hba_count;
static atomic_t lpfc_debugfs_hba_count;
/*
* File operations for the iDiag debugfs
@ -6074,12 +6050,7 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)
/* Setup lpfc root directory */
if (!lpfc_debugfs_root) {
lpfc_debugfs_root = debugfs_create_dir("lpfc", NULL);
lpfc_debugfs_hba_count = 0;
if (IS_ERR(lpfc_debugfs_root)) {
lpfc_vlog_msg(vport, KERN_WARNING, LOG_INIT,
"0527 Cannot create debugfs lpfc\n");
return;
}
atomic_set(&lpfc_debugfs_hba_count, 0);
}
if (!lpfc_debugfs_start_time)
lpfc_debugfs_start_time = jiffies;
@ -6090,96 +6061,159 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)
pport_setup = true;
phba->hba_debugfs_root =
debugfs_create_dir(name, lpfc_debugfs_root);
phba->debugfs_vport_count = 0;
if (IS_ERR(phba->hba_debugfs_root)) {
lpfc_vlog_msg(vport, KERN_WARNING, LOG_INIT,
"0528 Cannot create debugfs %s\n", name);
return;
}
lpfc_debugfs_hba_count++;
atomic_inc(&lpfc_debugfs_hba_count);
atomic_set(&phba->debugfs_vport_count, 0);
/* Multi-XRI pools */
debugfs_create_file("multixripools", 0644,
phba->hba_debugfs_root, phba,
&lpfc_debugfs_op_multixripools);
snprintf(name, sizeof(name), "multixripools");
phba->debug_multixri_pools =
debugfs_create_file(name, S_IFREG | 0644,
phba->hba_debugfs_root,
phba,
&lpfc_debugfs_op_multixripools);
if (IS_ERR(phba->debug_multixri_pools)) {
lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
"0527 Cannot create debugfs multixripools\n");
goto debug_failed;
}
/* Congestion Info Buffer */
debugfs_create_file("cgn_buffer", 0644, phba->hba_debugfs_root,
phba, &lpfc_cgn_buffer_op);
scnprintf(name, sizeof(name), "cgn_buffer");
phba->debug_cgn_buffer =
debugfs_create_file(name, S_IFREG | 0644,
phba->hba_debugfs_root,
phba, &lpfc_cgn_buffer_op);
if (IS_ERR(phba->debug_cgn_buffer)) {
lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
"6527 Cannot create debugfs "
"cgn_buffer\n");
goto debug_failed;
}
/* RX Monitor */
debugfs_create_file("rx_monitor", 0644, phba->hba_debugfs_root,
phba, &lpfc_rx_monitor_op);
scnprintf(name, sizeof(name), "rx_monitor");
phba->debug_rx_monitor =
debugfs_create_file(name, S_IFREG | 0644,
phba->hba_debugfs_root,
phba, &lpfc_rx_monitor_op);
if (IS_ERR(phba->debug_rx_monitor)) {
lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
"6528 Cannot create debugfs "
"rx_monitor\n");
goto debug_failed;
}
/* RAS log */
debugfs_create_file("ras_log", 0644, phba->hba_debugfs_root,
phba, &lpfc_debugfs_ras_log);
snprintf(name, sizeof(name), "ras_log");
phba->debug_ras_log =
debugfs_create_file(name, 0644,
phba->hba_debugfs_root,
phba, &lpfc_debugfs_ras_log);
if (IS_ERR(phba->debug_ras_log)) {
lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
"6148 Cannot create debugfs"
" ras_log\n");
goto debug_failed;
}
/* Setup hbqinfo */
debugfs_create_file("hbqinfo", 0644, phba->hba_debugfs_root,
phba, &lpfc_debugfs_op_hbqinfo);
snprintf(name, sizeof(name), "hbqinfo");
phba->debug_hbqinfo =
debugfs_create_file(name, S_IFREG | 0644,
phba->hba_debugfs_root,
phba, &lpfc_debugfs_op_hbqinfo);
#ifdef LPFC_HDWQ_LOCK_STAT
/* Setup lockstat */
debugfs_create_file("lockstat", 0644, phba->hba_debugfs_root,
phba, &lpfc_debugfs_op_lockstat);
snprintf(name, sizeof(name), "lockstat");
phba->debug_lockstat =
debugfs_create_file(name, S_IFREG | 0644,
phba->hba_debugfs_root,
phba, &lpfc_debugfs_op_lockstat);
if (IS_ERR(phba->debug_lockstat)) {
lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
"4610 Can't create debugfs lockstat\n");
goto debug_failed;
}
#endif
if (phba->sli_rev < LPFC_SLI_REV4) {
/* Setup dumpHBASlim */
debugfs_create_file("dumpHBASlim", 0644,
phba->hba_debugfs_root, phba,
&lpfc_debugfs_op_dumpHBASlim);
}
/* Setup dumpHBASlim */
if (phba->sli_rev < LPFC_SLI_REV4) {
/* Setup dumpHostSlim */
debugfs_create_file("dumpHostSlim", 0644,
phba->hba_debugfs_root, phba,
&lpfc_debugfs_op_dumpHostSlim);
}
snprintf(name, sizeof(name), "dumpHBASlim");
phba->debug_dumpHBASlim =
debugfs_create_file(name,
S_IFREG|S_IRUGO|S_IWUSR,
phba->hba_debugfs_root,
phba, &lpfc_debugfs_op_dumpHBASlim);
} else
phba->debug_dumpHBASlim = NULL;
/* Setup dumpHostSlim */
if (phba->sli_rev < LPFC_SLI_REV4) {
snprintf(name, sizeof(name), "dumpHostSlim");
phba->debug_dumpHostSlim =
debugfs_create_file(name,
S_IFREG|S_IRUGO|S_IWUSR,
phba->hba_debugfs_root,
phba, &lpfc_debugfs_op_dumpHostSlim);
} else
phba->debug_dumpHostSlim = NULL;
/* Setup DIF Error Injections */
debugfs_create_file_aux_num("InjErrLBA", 0644,
phba->hba_debugfs_root, phba,
InjErrLBA,
&lpfc_debugfs_op_dif_err);
snprintf(name, sizeof(name), "InjErrLBA");
phba->debug_InjErrLBA =
debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
phba->hba_debugfs_root,
phba, &lpfc_debugfs_op_dif_err);
phba->lpfc_injerr_lba = LPFC_INJERR_LBA_OFF;
debugfs_create_file_aux_num("InjErrNPortID", 0644,
phba->hba_debugfs_root, phba,
InjErrNPortID,
&lpfc_debugfs_op_dif_err);
snprintf(name, sizeof(name), "InjErrNPortID");
phba->debug_InjErrNPortID =
debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
phba->hba_debugfs_root,
phba, &lpfc_debugfs_op_dif_err);
debugfs_create_file_aux_num("InjErrWWPN", 0644,
phba->hba_debugfs_root, phba,
InjErrWWPN,
&lpfc_debugfs_op_dif_err);
snprintf(name, sizeof(name), "InjErrWWPN");
phba->debug_InjErrWWPN =
debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
phba->hba_debugfs_root,
phba, &lpfc_debugfs_op_dif_err);
debugfs_create_file_aux_num("writeGuardInjErr", 0644,
phba->hba_debugfs_root, phba,
writeGuard,
&lpfc_debugfs_op_dif_err);
snprintf(name, sizeof(name), "writeGuardInjErr");
phba->debug_writeGuard =
debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
phba->hba_debugfs_root,
phba, &lpfc_debugfs_op_dif_err);
debugfs_create_file_aux_num("writeAppInjErr", 0644,
phba->hba_debugfs_root, phba,
writeApp, &lpfc_debugfs_op_dif_err);
snprintf(name, sizeof(name), "writeAppInjErr");
phba->debug_writeApp =
debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
phba->hba_debugfs_root,
phba, &lpfc_debugfs_op_dif_err);
debugfs_create_file_aux_num("writeRefInjErr", 0644,
phba->hba_debugfs_root, phba,
writeRef, &lpfc_debugfs_op_dif_err);
snprintf(name, sizeof(name), "writeRefInjErr");
phba->debug_writeRef =
debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
phba->hba_debugfs_root,
phba, &lpfc_debugfs_op_dif_err);
debugfs_create_file_aux_num("readGuardInjErr", 0644,
phba->hba_debugfs_root, phba,
readGuard,
&lpfc_debugfs_op_dif_err);
snprintf(name, sizeof(name), "readGuardInjErr");
phba->debug_readGuard =
debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
phba->hba_debugfs_root,
phba, &lpfc_debugfs_op_dif_err);
debugfs_create_file_aux_num("readAppInjErr", 0644,
phba->hba_debugfs_root, phba,
readApp, &lpfc_debugfs_op_dif_err);
snprintf(name, sizeof(name), "readAppInjErr");
phba->debug_readApp =
debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
phba->hba_debugfs_root,
phba, &lpfc_debugfs_op_dif_err);
debugfs_create_file_aux_num("readRefInjErr", 0644,
phba->hba_debugfs_root, phba,
readRef, &lpfc_debugfs_op_dif_err);
snprintf(name, sizeof(name), "readRefInjErr");
phba->debug_readRef =
debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
phba->hba_debugfs_root,
phba, &lpfc_debugfs_op_dif_err);
/* Setup slow ring trace */
if (lpfc_debugfs_max_slow_ring_trc) {
@ -6193,15 +6227,16 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)
i++;
}
lpfc_debugfs_max_slow_ring_trc = (1 << i);
pr_info("lpfc_debugfs_max_slow_ring_trc "
"changed to %d\n",
lpfc_debugfs_max_slow_ring_trc);
pr_err("lpfc_debugfs_max_disc_trc changed to "
"%d\n", lpfc_debugfs_max_disc_trc);
}
}
debugfs_create_file("slow_ring_trace", 0644,
phba->hba_debugfs_root, phba,
&lpfc_debugfs_op_slow_ring_trc);
snprintf(name, sizeof(name), "slow_ring_trace");
phba->debug_slow_ring_trc =
debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
phba->hba_debugfs_root,
phba, &lpfc_debugfs_op_slow_ring_trc);
if (!phba->slow_ring_trc) {
phba->slow_ring_trc = kcalloc(
lpfc_debugfs_max_slow_ring_trc,
@ -6211,18 +6246,21 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)
lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
"0416 Cannot create debugfs "
"slow_ring buffer\n");
goto out;
goto debug_failed;
}
atomic_set(&phba->slow_ring_trc_cnt, 0);
}
debugfs_create_file("nvmeio_trc", 0644, phba->hba_debugfs_root,
phba, &lpfc_debugfs_op_nvmeio_trc);
snprintf(name, sizeof(name), "nvmeio_trc");
phba->debug_nvmeio_trc =
debugfs_create_file(name, 0644,
phba->hba_debugfs_root,
phba, &lpfc_debugfs_op_nvmeio_trc);
atomic_set(&phba->nvmeio_trc_cnt, 0);
if (lpfc_debugfs_max_nvmeio_trc) {
num = lpfc_debugfs_max_nvmeio_trc - 1;
if (num & lpfc_debugfs_max_nvmeio_trc) {
if (num & lpfc_debugfs_max_disc_trc) {
/* Change to be a power of 2 */
num = lpfc_debugfs_max_nvmeio_trc;
i = 0;
@ -6231,9 +6269,10 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)
i++;
}
lpfc_debugfs_max_nvmeio_trc = (1 << i);
pr_info("lpfc_debugfs_max_nvmeio_trc changed "
"to %d\n",
lpfc_debugfs_max_nvmeio_trc);
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"0575 lpfc_debugfs_max_nvmeio_trc "
"changed to %d\n",
lpfc_debugfs_max_nvmeio_trc);
}
phba->nvmeio_trc_size = lpfc_debugfs_max_nvmeio_trc;
@ -6250,6 +6289,7 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)
}
phba->nvmeio_trc_on = 1;
phba->nvmeio_trc_output_idx = 0;
phba->nvmeio_trc = NULL;
} else {
nvmeio_off:
phba->nvmeio_trc_size = 0;
@ -6263,12 +6303,7 @@ nvmeio_off:
if (!vport->vport_debugfs_root) {
vport->vport_debugfs_root =
debugfs_create_dir(name, phba->hba_debugfs_root);
if (IS_ERR(vport->vport_debugfs_root)) {
lpfc_vlog_msg(vport, KERN_WARNING, LOG_INIT,
"0529 Cannot create debugfs %s\n", name);
return;
}
phba->debugfs_vport_count++;
atomic_inc(&phba->debugfs_vport_count);
}
if (lpfc_debugfs_max_disc_trc) {
@ -6282,8 +6317,8 @@ nvmeio_off:
i++;
}
lpfc_debugfs_max_disc_trc = (1 << i);
pr_info("lpfc_debugfs_max_disc_trc changed to %d\n",
lpfc_debugfs_max_disc_trc);
pr_err("lpfc_debugfs_max_disc_trc changed to %d\n",
lpfc_debugfs_max_disc_trc);
}
}
@ -6295,27 +6330,54 @@ nvmeio_off:
lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
"0418 Cannot create debugfs disc trace "
"buffer\n");
goto out;
goto debug_failed;
}
atomic_set(&vport->disc_trc_cnt, 0);
debugfs_create_file("discovery_trace", 0644, vport->vport_debugfs_root,
vport, &lpfc_debugfs_op_disc_trc);
snprintf(name, sizeof(name), "discovery_trace");
vport->debug_disc_trc =
debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
vport->vport_debugfs_root,
vport, &lpfc_debugfs_op_disc_trc);
snprintf(name, sizeof(name), "nodelist");
vport->debug_nodelist =
debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
vport->vport_debugfs_root,
vport, &lpfc_debugfs_op_nodelist);
debugfs_create_file("nodelist", 0644, vport->vport_debugfs_root, vport,
&lpfc_debugfs_op_nodelist);
snprintf(name, sizeof(name), "nvmestat");
vport->debug_nvmestat =
debugfs_create_file(name, 0644,
vport->vport_debugfs_root,
vport, &lpfc_debugfs_op_nvmestat);
debugfs_create_file("nvmestat", 0644, vport->vport_debugfs_root, vport,
&lpfc_debugfs_op_nvmestat);
snprintf(name, sizeof(name), "scsistat");
vport->debug_scsistat =
debugfs_create_file(name, 0644,
vport->vport_debugfs_root,
vport, &lpfc_debugfs_op_scsistat);
if (IS_ERR(vport->debug_scsistat)) {
lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
"4611 Cannot create debugfs scsistat\n");
goto debug_failed;
}
debugfs_create_file("scsistat", 0644, vport->vport_debugfs_root, vport,
&lpfc_debugfs_op_scsistat);
snprintf(name, sizeof(name), "ioktime");
vport->debug_ioktime =
debugfs_create_file(name, 0644,
vport->vport_debugfs_root,
vport, &lpfc_debugfs_op_ioktime);
if (IS_ERR(vport->debug_ioktime)) {
lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
"0815 Cannot create debugfs ioktime\n");
goto debug_failed;
}
debugfs_create_file("ioktime", 0644, vport->vport_debugfs_root, vport,
&lpfc_debugfs_op_ioktime);
debugfs_create_file("hdwqstat", 0644, vport->vport_debugfs_root, vport,
&lpfc_debugfs_op_hdwqstat);
snprintf(name, sizeof(name), "hdwqstat");
vport->debug_hdwqstat =
debugfs_create_file(name, 0644,
vport->vport_debugfs_root,
vport, &lpfc_debugfs_op_hdwqstat);
/*
* The following section is for additional directories/files for the
@ -6323,58 +6385,93 @@ nvmeio_off:
*/
if (!pport_setup)
return;
goto debug_failed;
/*
* iDiag debugfs root entry points for SLI4 device only
*/
if (phba->sli_rev < LPFC_SLI_REV4)
return;
goto debug_failed;
snprintf(name, sizeof(name), "iDiag");
if (!phba->idiag_root) {
phba->idiag_root =
debugfs_create_dir("iDiag", phba->hba_debugfs_root);
debugfs_create_dir(name, phba->hba_debugfs_root);
/* Initialize iDiag data structure */
memset(&idiag, 0, sizeof(idiag));
}
/* iDiag read PCI config space */
debugfs_create_file("pciCfg", 0644, phba->idiag_root, phba,
&lpfc_idiag_op_pciCfg);
idiag.offset.last_rd = 0;
snprintf(name, sizeof(name), "pciCfg");
if (!phba->idiag_pci_cfg) {
phba->idiag_pci_cfg =
debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
phba->idiag_root, phba, &lpfc_idiag_op_pciCfg);
idiag.offset.last_rd = 0;
}
/* iDiag PCI BAR access */
debugfs_create_file("barAcc", 0644, phba->idiag_root, phba,
&lpfc_idiag_op_barAcc);
idiag.offset.last_rd = 0;
snprintf(name, sizeof(name), "barAcc");
if (!phba->idiag_bar_acc) {
phba->idiag_bar_acc =
debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
phba->idiag_root, phba, &lpfc_idiag_op_barAcc);
idiag.offset.last_rd = 0;
}
/* iDiag get PCI function queue information */
debugfs_create_file("queInfo", 0444, phba->idiag_root, phba,
&lpfc_idiag_op_queInfo);
snprintf(name, sizeof(name), "queInfo");
if (!phba->idiag_que_info) {
phba->idiag_que_info =
debugfs_create_file(name, S_IFREG|S_IRUGO,
phba->idiag_root, phba, &lpfc_idiag_op_queInfo);
}
/* iDiag access PCI function queue */
debugfs_create_file("queAcc", 0644, phba->idiag_root, phba,
&lpfc_idiag_op_queAcc);
snprintf(name, sizeof(name), "queAcc");
if (!phba->idiag_que_acc) {
phba->idiag_que_acc =
debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
phba->idiag_root, phba, &lpfc_idiag_op_queAcc);
}
/* iDiag access PCI function doorbell registers */
debugfs_create_file("drbAcc", 0644, phba->idiag_root, phba,
&lpfc_idiag_op_drbAcc);
snprintf(name, sizeof(name), "drbAcc");
if (!phba->idiag_drb_acc) {
phba->idiag_drb_acc =
debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
phba->idiag_root, phba, &lpfc_idiag_op_drbAcc);
}
/* iDiag access PCI function control registers */
debugfs_create_file("ctlAcc", 0644, phba->idiag_root, phba,
&lpfc_idiag_op_ctlAcc);
snprintf(name, sizeof(name), "ctlAcc");
if (!phba->idiag_ctl_acc) {
phba->idiag_ctl_acc =
debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
phba->idiag_root, phba, &lpfc_idiag_op_ctlAcc);
}
/* iDiag access mbox commands */
debugfs_create_file("mbxAcc", 0644, phba->idiag_root, phba,
&lpfc_idiag_op_mbxAcc);
snprintf(name, sizeof(name), "mbxAcc");
if (!phba->idiag_mbx_acc) {
phba->idiag_mbx_acc =
debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
phba->idiag_root, phba, &lpfc_idiag_op_mbxAcc);
}
/* iDiag extents access commands */
if (phba->sli4_hba.extents_in_use) {
debugfs_create_file("extAcc", 0644, phba->idiag_root, phba,
&lpfc_idiag_op_extAcc);
snprintf(name, sizeof(name), "extAcc");
if (!phba->idiag_ext_acc) {
phba->idiag_ext_acc =
debugfs_create_file(name,
S_IFREG|S_IRUGO|S_IWUSR,
phba->idiag_root, phba,
&lpfc_idiag_op_extAcc);
}
}
out:
/* alloc'ed items are kfree'd in lpfc_debugfs_terminate */
debug_failed:
return;
#endif
}
@ -6399,26 +6496,145 @@ lpfc_debugfs_terminate(struct lpfc_vport *vport)
kfree(vport->disc_trc);
vport->disc_trc = NULL;
debugfs_remove(vport->debug_disc_trc); /* discovery_trace */
vport->debug_disc_trc = NULL;
debugfs_remove(vport->debug_nodelist); /* nodelist */
vport->debug_nodelist = NULL;
debugfs_remove(vport->debug_nvmestat); /* nvmestat */
vport->debug_nvmestat = NULL;
debugfs_remove(vport->debug_scsistat); /* scsistat */
vport->debug_scsistat = NULL;
debugfs_remove(vport->debug_ioktime); /* ioktime */
vport->debug_ioktime = NULL;
debugfs_remove(vport->debug_hdwqstat); /* hdwqstat */
vport->debug_hdwqstat = NULL;
if (vport->vport_debugfs_root) {
debugfs_remove(vport->vport_debugfs_root); /* vportX */
vport->vport_debugfs_root = NULL;
phba->debugfs_vport_count--;
atomic_dec(&phba->debugfs_vport_count);
}
if (!phba->debugfs_vport_count) {
if (atomic_read(&phba->debugfs_vport_count) == 0) {
debugfs_remove(phba->debug_multixri_pools); /* multixripools*/
phba->debug_multixri_pools = NULL;
debugfs_remove(phba->debug_hbqinfo); /* hbqinfo */
phba->debug_hbqinfo = NULL;
debugfs_remove(phba->debug_cgn_buffer);
phba->debug_cgn_buffer = NULL;
debugfs_remove(phba->debug_rx_monitor);
phba->debug_rx_monitor = NULL;
debugfs_remove(phba->debug_ras_log);
phba->debug_ras_log = NULL;
#ifdef LPFC_HDWQ_LOCK_STAT
debugfs_remove(phba->debug_lockstat); /* lockstat */
phba->debug_lockstat = NULL;
#endif
debugfs_remove(phba->debug_dumpHBASlim); /* HBASlim */
phba->debug_dumpHBASlim = NULL;
debugfs_remove(phba->debug_dumpHostSlim); /* HostSlim */
phba->debug_dumpHostSlim = NULL;
debugfs_remove(phba->debug_InjErrLBA); /* InjErrLBA */
phba->debug_InjErrLBA = NULL;
debugfs_remove(phba->debug_InjErrNPortID);
phba->debug_InjErrNPortID = NULL;
debugfs_remove(phba->debug_InjErrWWPN); /* InjErrWWPN */
phba->debug_InjErrWWPN = NULL;
debugfs_remove(phba->debug_writeGuard); /* writeGuard */
phba->debug_writeGuard = NULL;
debugfs_remove(phba->debug_writeApp); /* writeApp */
phba->debug_writeApp = NULL;
debugfs_remove(phba->debug_writeRef); /* writeRef */
phba->debug_writeRef = NULL;
debugfs_remove(phba->debug_readGuard); /* readGuard */
phba->debug_readGuard = NULL;
debugfs_remove(phba->debug_readApp); /* readApp */
phba->debug_readApp = NULL;
debugfs_remove(phba->debug_readRef); /* readRef */
phba->debug_readRef = NULL;
kfree(phba->slow_ring_trc);
phba->slow_ring_trc = NULL;
/* slow_ring_trace */
debugfs_remove(phba->debug_slow_ring_trc);
phba->debug_slow_ring_trc = NULL;
debugfs_remove(phba->debug_nvmeio_trc);
phba->debug_nvmeio_trc = NULL;
kfree(phba->nvmeio_trc);
phba->nvmeio_trc = NULL;
/*
* iDiag release
*/
if (phba->sli_rev == LPFC_SLI_REV4) {
/* iDiag extAcc */
debugfs_remove(phba->idiag_ext_acc);
phba->idiag_ext_acc = NULL;
/* iDiag mbxAcc */
debugfs_remove(phba->idiag_mbx_acc);
phba->idiag_mbx_acc = NULL;
/* iDiag ctlAcc */
debugfs_remove(phba->idiag_ctl_acc);
phba->idiag_ctl_acc = NULL;
/* iDiag drbAcc */
debugfs_remove(phba->idiag_drb_acc);
phba->idiag_drb_acc = NULL;
/* iDiag queAcc */
debugfs_remove(phba->idiag_que_acc);
phba->idiag_que_acc = NULL;
/* iDiag queInfo */
debugfs_remove(phba->idiag_que_info);
phba->idiag_que_info = NULL;
/* iDiag barAcc */
debugfs_remove(phba->idiag_bar_acc);
phba->idiag_bar_acc = NULL;
/* iDiag pciCfg */
debugfs_remove(phba->idiag_pci_cfg);
phba->idiag_pci_cfg = NULL;
/* Finally remove the iDiag debugfs root */
debugfs_remove(phba->idiag_root);
phba->idiag_root = NULL;
}
if (phba->hba_debugfs_root) {
debugfs_remove(phba->hba_debugfs_root); /* fnX */
phba->hba_debugfs_root = NULL;
lpfc_debugfs_hba_count--;
atomic_dec(&lpfc_debugfs_hba_count);
}
if (!lpfc_debugfs_hba_count) {
if (atomic_read(&lpfc_debugfs_hba_count) == 0) {
debugfs_remove(lpfc_debugfs_root); /* lpfc */
lpfc_debugfs_root = NULL;
}

View File

@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
* Copyright (C) 2017-2025 Broadcom. All Rights Reserved. The term *
* Copyright (C) 2017-2022 Broadcom. All Rights Reserved. The term *
* Broadcom refers to Broadcom Inc. and/or its subsidiaries. *
* Copyright (C) 2007-2011 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@ -44,9 +44,6 @@
/* hbqinfo output buffer size */
#define LPFC_HBQINFO_SIZE 8192
/* hdwqinfo output buffer size */
#define LPFC_HDWQINFO_SIZE 8192
/* nvmestat output buffer size */
#define LPFC_NVMESTAT_SIZE 8192
#define LPFC_IOKTIME_SIZE 8192
@ -325,17 +322,6 @@ enum {
* discovery */
#endif /* H_LPFC_DEBUG_FS */
enum {
writeGuard = 1,
writeApp,
writeRef,
readGuard,
readApp,
readRef,
InjErrLBA,
InjErrNPortID,
InjErrWWPN,
};
/*
* Driver debug utility routines outside of debugfs. The debug utility

View File

@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
* Copyright (C) 2017-2025 Broadcom. All Rights Reserved. The term *
* Copyright (C) 2017-2024 Broadcom. All Rights Reserved. The term *
* Broadcom refers to Broadcom Inc. and/or its subsidiaries. *
* Copyright (C) 2004-2013 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@ -208,7 +208,6 @@ enum lpfc_nlp_flag {
NPR list */
NLP_RM_DFLT_RPI = 26, /* need to remove leftover dflt RPI */
NLP_NODEV_REMOVE = 27, /* Defer removal till discovery ends */
NLP_FLOGI_DFR_ACC = 28, /* FLOGI LS_ACC was Deferred */
NLP_SC_REQ = 29, /* Target requires authentication */
NLP_FIRSTBURST = 30, /* Target supports FirstBurst */
NLP_RPI_REGISTERED = 31 /* nlp_rpi is valid */

View File

@ -650,6 +650,8 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
ndlp->nlp_class_sup |= FC_COS_CLASS2;
if (sp->cls3.classValid)
ndlp->nlp_class_sup |= FC_COS_CLASS3;
if (sp->cls4.classValid)
ndlp->nlp_class_sup |= FC_COS_CLASS4;
ndlp->nlp_maxframe = ((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) |
sp->cmn.bbRcvSizeLsb;
@ -932,15 +934,10 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
/* Check to see if link went down during discovery */
if (lpfc_els_chk_latt(vport)) {
/* One additional decrement on node reference count to
* trigger the release of the node. Make sure the ndlp
* is marked NLP_DROPPED.
* trigger the release of the node
*/
if (!test_bit(NLP_IN_DEV_LOSS, &ndlp->nlp_flag) &&
!test_bit(NLP_DROPPED, &ndlp->nlp_flag) &&
!(ndlp->fc4_xpt_flags & SCSI_XPT_REGD)) {
set_bit(NLP_DROPPED, &ndlp->nlp_flag);
if (!(ndlp->fc4_xpt_flags & SCSI_XPT_REGD))
lpfc_nlp_put(ndlp);
}
goto out;
}
@ -998,10 +995,9 @@ stop_rr_fcf_flogi:
IOERR_LOOP_OPEN_FAILURE)))
lpfc_vlog_msg(vport, KERN_WARNING, LOG_ELS,
"2858 FLOGI Status:x%x/x%x TMO"
":x%x Data x%lx x%x x%lx x%x\n",
":x%x Data x%lx x%x\n",
ulp_status, ulp_word4, tmo,
phba->hba_flag, phba->fcf.fcf_flag,
ndlp->nlp_flag, ndlp->fc4_xpt_flags);
phba->hba_flag, phba->fcf.fcf_flag);
/* Check for retry */
if (lpfc_els_retry(phba, cmdiocb, rspiocb)) {
@ -1019,17 +1015,14 @@ stop_rr_fcf_flogi:
* reference to trigger node release.
*/
if (!test_bit(NLP_IN_DEV_LOSS, &ndlp->nlp_flag) &&
!test_bit(NLP_DROPPED, &ndlp->nlp_flag) &&
!(ndlp->fc4_xpt_flags & SCSI_XPT_REGD)) {
set_bit(NLP_DROPPED, &ndlp->nlp_flag);
!(ndlp->fc4_xpt_flags & SCSI_XPT_REGD))
lpfc_nlp_put(ndlp);
}
lpfc_printf_vlog(vport, KERN_WARNING, LOG_ELS,
"0150 FLOGI Status:x%x/x%x "
"xri x%x iotag x%x TMO:x%x refcnt %d\n",
"xri x%x TMO:x%x refcnt %d\n",
ulp_status, ulp_word4, cmdiocb->sli4_xritag,
cmdiocb->iotag, tmo, kref_read(&ndlp->kref));
tmo, kref_read(&ndlp->kref));
/* If this is not a loop open failure, bail out */
if (!(ulp_status == IOSTAT_LOCAL_REJECT &&
@ -1286,19 +1279,6 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
uint32_t tmo, did;
int rc;
/* It's possible for lpfc to reissue a FLOGI on an ndlp that is marked
* NLP_DROPPED. This happens when the FLOGI completed with the XB bit
* set causing lpfc to reference the ndlp until the XRI_ABORTED CQE is
* issued. The time window for the XRI_ABORTED CQE can be as much as
* 2*2*RA_TOV allowing for ndlp reuse of this type when the link is
* cycling quickly. When true, restore the initial reference and remove
* the NLP_DROPPED flag as lpfc is retrying.
*/
if (test_and_clear_bit(NLP_DROPPED, &ndlp->nlp_flag)) {
if (!lpfc_nlp_get(ndlp))
return 1;
}
cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm));
elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
ndlp->nlp_DID, ELS_CMD_FLOGI);
@ -1354,14 +1334,6 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
/* Can't do SLI4 class2 without support sequence coalescing */
sp->cls2.classValid = 0;
sp->cls2.seqDelivery = 0;
/* Fill out Auxiliary Parameter Data */
if (phba->pni) {
sp->aux.flags =
AUX_PARM_DATA_VALID | AUX_PARM_PNI_VALID;
sp->aux.pni = cpu_to_be64(phba->pni);
sp->aux.npiv_cnt = cpu_to_be16(phba->max_vpi - 1);
}
} else {
/* Historical, setting sequential-delivery bit for SLI3 */
sp->cls2.seqDelivery = (sp->cls2.classValid) ? 1 : 0;
@ -1441,12 +1413,11 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
phba->defer_flogi_acc.ox_id;
}
/* The LS_ACC completion needs to drop the initial reference.
* This is a special case for Pt2Pt because both FLOGIs need
* to complete and lpfc defers the LS_ACC when the remote
* FLOGI arrives before the driver's FLOGI.
*/
set_bit(NLP_FLOGI_DFR_ACC, &ndlp->nlp_flag);
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
"3354 Xmit deferred FLOGI ACC: rx_id: x%x,"
" ox_id: x%x, hba_flag x%lx\n",
phba->defer_flogi_acc.rx_id,
phba->defer_flogi_acc.ox_id, phba->hba_flag);
/* Send deferred FLOGI ACC */
lpfc_els_rsp_acc(vport, ELS_CMD_FLOGI, &defer_flogi_acc,
@ -1462,14 +1433,6 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
phba->defer_flogi_acc.ndlp = NULL;
}
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
"3354 Xmit deferred FLOGI ACC: rx_id: x%x,"
" ox_id: x%x, ndlp x%px hba_flag x%lx\n",
phba->defer_flogi_acc.rx_id,
phba->defer_flogi_acc.ox_id,
phba->defer_flogi_acc.ndlp,
phba->hba_flag);
vport->fc_myDID = did;
}
@ -2285,8 +2248,7 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry)
sp->cmn.valid_vendor_ver_level = 0;
memset(sp->un.vendorVersion, 0, sizeof(sp->un.vendorVersion));
if (!test_bit(FC_PT2PT, &vport->fc_flag))
sp->cmn.bbRcvSizeMsb &= 0xF;
sp->cmn.bbRcvSizeMsb &= 0xF;
/* Check if the destination port supports VMID */
ndlp->vmid_support = 0;
@ -2405,7 +2367,7 @@ lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
mode = KERN_INFO;
/* Warn PRLI status */
lpfc_vlog_msg(vport, mode, LOG_ELS,
lpfc_printf_vlog(vport, mode, LOG_ELS,
"2754 PRLI DID:%06X Status:x%x/x%x, "
"data: x%x x%x x%lx\n",
ndlp->nlp_DID, ulp_status,
@ -3062,7 +3024,6 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
ndlp->nlp_DID, ulp_status,
ulp_word4);
/* Call NLP_EVT_DEVICE_RM if link is down or LOGO is aborted */
if (lpfc_error_lost_link(vport, ulp_status, ulp_word4))
skip_recovery = 1;
}
@ -3301,7 +3262,7 @@ lpfc_reg_fab_ctrl_node(struct lpfc_vport *vport, struct lpfc_nodelist *fc_ndlp)
return -ENOMEM;
}
rc = lpfc_reg_rpi(phba, vport->vpi, fc_ndlp->nlp_DID,
(u8 *)&ns_ndlp->fc_sparam, mbox, fc_ndlp->nlp_rpi);
(u8 *)&vport->fc_sparam, mbox, fc_ndlp->nlp_rpi);
if (rc) {
rc = -EACCES;
goto out;
@ -3345,8 +3306,7 @@ lpfc_reg_fab_ctrl_node(struct lpfc_vport *vport, struct lpfc_nodelist *fc_ndlp)
*
* This routine is a generic completion callback function for Discovery ELS cmd.
* Currently used by the ELS command issuing routines for the ELS State Change
* Request (SCR), lpfc_issue_els_scr(), Exchange Diagnostic Capabilities (EDC),
* lpfc_issue_els_edc() and the ELS RDF, lpfc_issue_els_rdf().
* Request (SCR), lpfc_issue_els_scr() and the ELS RDF, lpfc_issue_els_rdf().
* These commands will be retried once only for ELS timeout errors.
**/
static void
@ -3419,21 +3379,11 @@ lpfc_cmpl_els_disc_cmd(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
lpfc_cmpl_els_edc(phba, cmdiocb, rspiocb);
return;
}
if (ulp_status) {
/* ELS discovery cmd completes with error */
lpfc_printf_vlog(vport, KERN_WARNING, LOG_ELS | LOG_CGN_MGMT,
"4203 ELS cmd x%x error: x%x x%X\n", cmd,
ulp_status, ulp_word4);
/* In the case where the ELS cmd completes with an error and
* the node does not have RPI registered, the node is
* outstanding and should put its initial reference.
*/
if ((cmd == ELS_CMD_SCR || cmd == ELS_CMD_RDF) &&
!(ndlp->fc4_xpt_flags & SCSI_XPT_REGD) &&
!test_and_set_bit(NLP_DROPPED, &ndlp->nlp_flag))
lpfc_nlp_put(ndlp);
goto out;
}
@ -3502,7 +3452,6 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint8_t retry)
uint8_t *pcmd;
uint16_t cmdsize;
struct lpfc_nodelist *ndlp;
bool node_created = false;
cmdsize = (sizeof(uint32_t) + sizeof(SCR));
@ -3512,21 +3461,21 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint8_t retry)
if (!ndlp)
return 1;
lpfc_enqueue_node(vport, ndlp);
node_created = true;
}
elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
ndlp->nlp_DID, ELS_CMD_SCR);
if (!elsiocb)
goto out_node_created;
return 1;
if (phba->sli_rev == LPFC_SLI_REV4) {
rc = lpfc_reg_fab_ctrl_node(vport, ndlp);
if (rc) {
lpfc_els_free_iocb(phba, elsiocb);
lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE,
"0937 %s: Failed to reg fc node, rc %d\n",
__func__, rc);
goto out_free_iocb;
return 1;
}
}
pcmd = (uint8_t *)elsiocb->cmd_dmabuf->virt;
@ -3545,27 +3494,23 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint8_t retry)
phba->fc_stat.elsXmitSCR++;
elsiocb->cmd_cmpl = lpfc_cmpl_els_disc_cmd;
elsiocb->ndlp = lpfc_nlp_get(ndlp);
if (!elsiocb->ndlp)
goto out_free_iocb;
if (!elsiocb->ndlp) {
lpfc_els_free_iocb(phba, elsiocb);
return 1;
}
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
"Issue SCR: did:x%x refcnt %d",
ndlp->nlp_DID, kref_read(&ndlp->kref), 0);
rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
if (rc == IOCB_ERROR)
goto out_iocb_error;
if (rc == IOCB_ERROR) {
lpfc_els_free_iocb(phba, elsiocb);
lpfc_nlp_put(ndlp);
return 1;
}
return 0;
out_iocb_error:
lpfc_nlp_put(ndlp);
out_free_iocb:
lpfc_els_free_iocb(phba, elsiocb);
out_node_created:
if (node_created)
lpfc_nlp_put(ndlp);
return 1;
}
/**
@ -3652,8 +3597,8 @@ lpfc_issue_els_rscn(struct lpfc_vport *vport, uint8_t retry)
}
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
"Issue RSCN: did:x%x refcnt %d",
ndlp->nlp_DID, kref_read(&ndlp->kref), 0);
"Issue RSCN: did:x%x",
ndlp->nlp_DID, 0, 0);
rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
if (rc == IOCB_ERROR) {
@ -3760,7 +3705,10 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
lpfc_nlp_put(ndlp);
return 1;
}
/* This will cause the callback-function lpfc_cmpl_els_cmd to
* trigger the release of the node.
*/
/* Don't release reference count as RDF is likely outstanding */
return 0;
}
@ -3778,12 +3726,7 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
*
* Return code
* 0 - Successfully issued rdf command
* < 0 - Failed to issue rdf command
* -EACCES - RDF not required for NPIV_PORT
* -ENODEV - No fabric controller device available
* -ENOMEM - No available memory
* -EIO - The mailbox failed to complete successfully.
*
* 1 - Failed to issue rdf command
**/
int
lpfc_issue_els_rdf(struct lpfc_vport *vport, uint8_t retry)
@ -3794,30 +3737,25 @@ lpfc_issue_els_rdf(struct lpfc_vport *vport, uint8_t retry)
struct lpfc_nodelist *ndlp;
uint16_t cmdsize;
int rc;
bool node_created = false;
int err;
cmdsize = sizeof(*prdf);
/* RDF ELS is not required on an NPIV VN_Port. */
if (vport->port_type == LPFC_NPIV_PORT)
return -EACCES;
ndlp = lpfc_findnode_did(vport, Fabric_Cntl_DID);
if (!ndlp) {
ndlp = lpfc_nlp_init(vport, Fabric_Cntl_DID);
if (!ndlp)
return -ENODEV;
lpfc_enqueue_node(vport, ndlp);
node_created = true;
}
/* RDF ELS is not required on an NPIV VN_Port. */
if (vport->port_type == LPFC_NPIV_PORT)
return -EACCES;
elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
ndlp->nlp_DID, ELS_CMD_RDF);
if (!elsiocb) {
err = -ENOMEM;
goto out_node_created;
}
if (!elsiocb)
return -ENOMEM;
/* Configure the payload for the supported FPIN events. */
prdf = (struct lpfc_els_rdf_req *)elsiocb->cmd_dmabuf->virt;
@ -3843,8 +3781,8 @@ lpfc_issue_els_rdf(struct lpfc_vport *vport, uint8_t retry)
elsiocb->cmd_cmpl = lpfc_cmpl_els_disc_cmd;
elsiocb->ndlp = lpfc_nlp_get(ndlp);
if (!elsiocb->ndlp) {
err = -EIO;
goto out_free_iocb;
lpfc_els_free_iocb(phba, elsiocb);
return -EIO;
}
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
@ -3853,19 +3791,11 @@ lpfc_issue_els_rdf(struct lpfc_vport *vport, uint8_t retry)
rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
if (rc == IOCB_ERROR) {
err = -EIO;
goto out_iocb_error;
lpfc_els_free_iocb(phba, elsiocb);
lpfc_nlp_put(ndlp);
return -EIO;
}
return 0;
out_iocb_error:
lpfc_nlp_put(ndlp);
out_free_iocb:
lpfc_els_free_iocb(phba, elsiocb);
out_node_created:
if (node_created)
lpfc_nlp_put(ndlp);
return err;
}
/**
@ -3886,23 +3816,19 @@ static int
lpfc_els_rcv_rdf(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
struct lpfc_nodelist *ndlp)
{
int rc;
rc = lpfc_els_rsp_acc(vport, ELS_CMD_RDF, cmdiocb, ndlp, NULL);
/* Send LS_ACC */
if (rc) {
if (lpfc_els_rsp_acc(vport, ELS_CMD_RDF, cmdiocb, ndlp, NULL)) {
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS | LOG_CGN_MGMT,
"1623 Failed to RDF_ACC from x%x for x%x Data: %d\n",
ndlp->nlp_DID, vport->fc_myDID, rc);
"1623 Failed to RDF_ACC from x%x for x%x\n",
ndlp->nlp_DID, vport->fc_myDID);
return -EIO;
}
rc = lpfc_issue_els_rdf(vport, 0);
/* Issue new RDF for reregistering */
if (rc) {
if (lpfc_issue_els_rdf(vport, 0)) {
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS | LOG_CGN_MGMT,
"2623 Failed to re register RDF for x%x Data: %d\n",
vport->fc_myDID, rc);
"2623 Failed to re register RDF for x%x\n",
vport->fc_myDID);
return -EIO;
}
@ -4373,7 +4299,7 @@ lpfc_issue_els_edc(struct lpfc_vport *vport, uint8_t retry)
rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
if (rc == IOCB_ERROR) {
/* The additional lpfc_nlp_put will cause the following
* lpfc_els_free_iocb routine to trigger the release of
* lpfc_els_free_iocb routine to trigger the rlease of
* the node.
*/
lpfc_els_free_iocb(phba, elsiocb);
@ -5201,7 +5127,7 @@ lpfc_els_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *elsiocb)
{
struct lpfc_dmabuf *buf_ptr, *buf_ptr1;
/* The I/O iocb is complete. Clear the node and first dmabuf */
/* The I/O iocb is complete. Clear the node and first dmbuf */
elsiocb->ndlp = NULL;
/* cmd_dmabuf = cmd, cmd_dmabuf->next = rsp, bpl_dmabuf = bpl */
@ -5234,12 +5160,14 @@ lpfc_els_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *elsiocb)
} else {
buf_ptr1 = elsiocb->cmd_dmabuf;
lpfc_els_free_data(phba, buf_ptr1);
elsiocb->cmd_dmabuf = NULL;
}
}
if (elsiocb->bpl_dmabuf) {
buf_ptr = elsiocb->bpl_dmabuf;
lpfc_els_free_bpl(phba, buf_ptr);
elsiocb->bpl_dmabuf = NULL;
}
lpfc_sli_release_iocbq(phba, elsiocb);
return 0;
@ -5377,12 +5305,11 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
IOCB_t *irsp;
LPFC_MBOXQ_t *mbox = NULL;
u32 ulp_status, ulp_word4, tmo, did, iotag;
u32 cmd;
if (!vport) {
lpfc_printf_log(phba, KERN_WARNING, LOG_ELS,
"3177 null vport in ELS rsp\n");
goto release;
goto out;
}
if (cmdiocb->context_un.mbox)
mbox = cmdiocb->context_un.mbox;
@ -5412,12 +5339,12 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
ulp_status, ulp_word4, did);
/* ELS response tag <ulpIoTag> completes */
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
"0110 ELS response tag x%x completes fc_flag x%lx"
"0110 ELS response tag x%x completes "
"Data: x%x x%x x%x x%x x%lx x%x x%x x%x %p %p\n",
iotag, vport->fc_flag, ulp_status, ulp_word4, tmo,
iotag, ulp_status, ulp_word4, tmo,
ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
ndlp->nlp_rpi, kref_read(&ndlp->kref), mbox, ndlp);
if (mbox && !test_bit(FC_PT2PT, &vport->fc_flag)) {
if (mbox) {
if (ulp_status == 0 &&
test_bit(NLP_ACC_REGLOGIN, &ndlp->nlp_flag)) {
if (!lpfc_unreg_rpi(vport, ndlp) &&
@ -5476,10 +5403,6 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
}
out_free_mbox:
lpfc_mbox_rsrc_cleanup(phba, mbox, MBOX_THD_UNLOCKED);
} else if (mbox && test_bit(FC_PT2PT, &vport->fc_flag) &&
test_bit(NLP_ACC_REGLOGIN, &ndlp->nlp_flag)) {
lpfc_mbx_cmpl_reg_login(phba, mbox);
clear_bit(NLP_ACC_REGLOGIN, &ndlp->nlp_flag);
}
out:
if (ndlp && shost) {
@ -5492,7 +5415,7 @@ out:
* these conditions because it doesn't need the login.
*/
if (phba->sli_rev == LPFC_SLI_REV4 &&
vport->port_type == LPFC_NPIV_PORT &&
vport && vport->port_type == LPFC_NPIV_PORT &&
!(ndlp->fc4_xpt_flags & SCSI_XPT_REGD)) {
if (ndlp->nlp_state != NLP_STE_PLOGI_ISSUE &&
ndlp->nlp_state != NLP_STE_REG_LOGIN_ISSUE &&
@ -5508,27 +5431,6 @@ out:
}
}
/* The driver's unsolicited deferred FLOGI ACC in Pt2Pt needs to
* release the initial reference because the put after the free_iocb
* call removes only the reference from the defer logic. This FLOGI
* is never registered with the SCSI transport.
*/
if (test_bit(FC_PT2PT, &vport->fc_flag) &&
test_and_clear_bit(NLP_FLOGI_DFR_ACC, &ndlp->nlp_flag)) {
lpfc_printf_vlog(vport, KERN_INFO,
LOG_ELS | LOG_NODE | LOG_DISCOVERY,
"3357 Pt2Pt Defer FLOGI ACC ndlp x%px, "
"nflags x%lx, fc_flag x%lx\n",
ndlp, ndlp->nlp_flag,
vport->fc_flag);
cmd = *((u32 *)cmdiocb->cmd_dmabuf->virt);
if (cmd == ELS_CMD_ACC) {
if (!test_and_set_bit(NLP_DROPPED, &ndlp->nlp_flag))
lpfc_nlp_put(ndlp);
}
}
release:
/* Release the originating I/O reference. */
lpfc_els_free_iocb(phba, cmdiocb);
lpfc_nlp_put(ndlp);
@ -5663,6 +5565,7 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
sp->cls1.classValid = 0;
sp->cls2.classValid = 0;
sp->cls3.classValid = 0;
sp->cls4.classValid = 0;
/* Copy our worldwide names */
memcpy(&sp->portName, &vport->fc_sparam.portName,
@ -5676,8 +5579,7 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
sp->cmn.valid_vendor_ver_level = 0;
memset(sp->un.vendorVersion, 0,
sizeof(sp->un.vendorVersion));
if (!test_bit(FC_PT2PT, &vport->fc_flag))
sp->cmn.bbRcvSizeMsb &= 0xF;
sp->cmn.bbRcvSizeMsb &= 0xF;
/* If our firmware supports this feature, convey that
* info to the target using the vendor specific field.
@ -7959,13 +7861,6 @@ lpfc_rscn_recovery_check(struct lpfc_vport *vport)
/* Move all affected nodes by pending RSCNs to NPR state. */
list_for_each_entry_safe(ndlp, n, &vport->fc_nodes, nlp_listp) {
if (test_bit(FC_UNLOADING, &vport->load_flag)) {
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
"1000 %s Unloading set\n",
__func__);
return 0;
}
if ((ndlp->nlp_state == NLP_STE_UNUSED_NODE) ||
!lpfc_rscn_payload_check(vport, ndlp->nlp_DID))
continue;
@ -8475,9 +8370,9 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
clear_bit(FC_PUBLIC_LOOP, &vport->fc_flag);
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
"3311 Rcv Flogi PS x%x new PS x%x "
"fc_flag x%lx new fc_flag x%lx, hba_flag x%lx\n",
"fc_flag x%lx new fc_flag x%lx\n",
port_state, vport->port_state,
fc_flag, vport->fc_flag, phba->hba_flag);
fc_flag, vport->fc_flag);
/*
* We temporarily set fc_myDID to make it look like we are
@ -8497,6 +8392,13 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
&wqe->xmit_els_rsp.wqe_com);
vport->fc_myDID = did;
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
"3344 Deferring FLOGI ACC: rx_id: x%x,"
" ox_id: x%x, hba_flag x%lx\n",
phba->defer_flogi_acc.rx_id,
phba->defer_flogi_acc.ox_id, phba->hba_flag);
phba->defer_flogi_acc.flag = true;
/* This nlp_get is paired with nlp_puts that reset the
@ -8505,14 +8407,6 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
* processed or cancelled.
*/
phba->defer_flogi_acc.ndlp = lpfc_nlp_get(ndlp);
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
"3344 Deferring FLOGI ACC: rx_id: x%x,"
" ox_id: x%x, ndlp x%px, hba_flag x%lx\n",
phba->defer_flogi_acc.rx_id,
phba->defer_flogi_acc.ox_id,
phba->defer_flogi_acc.ndlp,
phba->hba_flag);
return 0;
}
@ -8830,7 +8724,7 @@ reject_out:
* @cmdiocb: pointer to lpfc command iocb data structure.
* @ndlp: pointer to a node-list data structure.
*
* This routine processes Read Timeout Value (RTV) IOCB received as an
* This routine processes Read Timout Value (RTV) IOCB received as an
* ELS unsolicited event. It first checks the remote port state. If the
* remote port is not in NLP_STE_UNMAPPED_NODE state or NLP_STE_MAPPED_NODE
* state, it invokes the lpfc_els_rsl_reject() routine to send the reject
@ -10453,8 +10347,11 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
* Do not process any unsolicited ELS commands
* if the ndlp is in DEV_LOSS
*/
if (test_bit(NLP_IN_DEV_LOSS, &ndlp->nlp_flag))
if (test_bit(NLP_IN_DEV_LOSS, &ndlp->nlp_flag)) {
if (newnode)
lpfc_nlp_put(ndlp);
goto dropit;
}
elsiocb->ndlp = lpfc_nlp_get(ndlp);
if (!elsiocb->ndlp)
@ -10936,7 +10833,7 @@ lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
lpfc_els_unsol_buffer(phba, pring, vport, elsiocb);
/*
* The different unsolicited event handlers would tell us
* if they are done with "mp" by setting cmd_dmabuf/bpl_dmabuf to NULL.
* if they are done with "mp" by setting cmd_dmabuf to NULL.
*/
if (elsiocb->cmd_dmabuf) {
lpfc_in_buf_free(phba, elsiocb->cmd_dmabuf);
@ -11356,11 +11253,6 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
lpfc_vlog_msg(vport, KERN_WARNING, LOG_ELS,
"0126 FDISC cmpl status: x%x/x%x)\n",
ulp_status, ulp_word4);
/* drop initial reference */
if (!test_and_set_bit(NLP_DROPPED, &ndlp->nlp_flag))
lpfc_nlp_put(ndlp);
goto fdisc_failed;
}
@ -11516,13 +11408,6 @@ lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
sp->cls2.seqDelivery = 1;
sp->cls3.seqDelivery = 1;
/* Fill out Auxiliary Parameter Data */
if (phba->pni) {
sp->aux.flags =
AUX_PARM_DATA_VALID | AUX_PARM_PNI_VALID;
sp->aux.pni = cpu_to_be64(phba->pni);
}
pcmd += sizeof(uint32_t); /* CSP Word 2 */
pcmd += sizeof(uint32_t); /* CSP Word 3 */
pcmd += sizeof(uint32_t); /* CSP Word 4 */
@ -12117,11 +12002,7 @@ lpfc_sli4_els_xri_aborted(struct lpfc_hba *phba,
sglq_entry->state = SGL_FREED;
spin_unlock_irqrestore(&phba->sli4_hba.sgl_list_lock,
iflag);
lpfc_printf_log(phba, KERN_INFO, LOG_ELS | LOG_SLI |
LOG_DISCOVERY | LOG_NODE,
"0732 ELS XRI ABORT on Node: ndlp=x%px "
"xri=x%x\n",
ndlp, xri);
if (ndlp) {
lpfc_set_rrq_active(phba, ndlp,
sglq_entry->sli4_lxritag,

View File

@ -183,8 +183,7 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
/* Don't schedule a worker thread event if the vport is going down. */
if (test_bit(FC_UNLOADING, &vport->load_flag) ||
(phba->sli_rev == LPFC_SLI_REV4 &&
!test_bit(HBA_SETUP, &phba->hba_flag))) {
!test_bit(HBA_SETUP, &phba->hba_flag)) {
spin_lock_irqsave(&ndlp->lock, iflags);
ndlp->rport = NULL;
@ -424,7 +423,6 @@ lpfc_check_nlp_post_devloss(struct lpfc_vport *vport,
struct lpfc_nodelist *ndlp)
{
if (test_and_clear_bit(NLP_IN_RECOV_POST_DEV_LOSS, &ndlp->save_flags)) {
clear_bit(NLP_DROPPED, &ndlp->nlp_flag);
lpfc_nlp_get(ndlp);
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY | LOG_NODE,
"8438 Devloss timeout reversed on DID x%x "
@ -567,8 +565,7 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
return fcf_inuse;
}
if (!test_and_set_bit(NLP_DROPPED, &ndlp->nlp_flag))
lpfc_nlp_put(ndlp);
lpfc_nlp_put(ndlp);
return fcf_inuse;
}
@ -1269,10 +1266,6 @@ lpfc_linkdown(struct lpfc_hba *phba)
}
phba->defer_flogi_acc.flag = false;
/* reinitialize initial HBA flag */
clear_bit(HBA_FLOGI_ISSUED, &phba->hba_flag);
clear_bit(HBA_RHBA_CMPL, &phba->hba_flag);
/* Clear external loopback plug detected flag */
phba->link_flag &= ~LS_EXTERNAL_LOOPBACK;
@ -1443,6 +1436,10 @@ lpfc_linkup(struct lpfc_hba *phba)
phba->pport->rcv_flogi_cnt = 0;
spin_unlock_irq(shost->host_lock);
/* reinitialize initial HBA flag */
clear_bit(HBA_FLOGI_ISSUED, &phba->hba_flag);
clear_bit(HBA_RHBA_CMPL, &phba->hba_flag);
return 0;
}
@ -4373,8 +4370,6 @@ out:
lpfc_ns_cmd(vport, SLI_CTNS_RNN_ID, 0, 0);
lpfc_ns_cmd(vport, SLI_CTNS_RSNN_NN, 0, 0);
lpfc_ns_cmd(vport, SLI_CTNS_RSPN_ID, 0, 0);
if (phba->pni)
lpfc_ns_cmd(vport, SLI_CTNS_RSPNI_PNI, 0, 0);
lpfc_ns_cmd(vport, SLI_CTNS_RFT_ID, 0, 0);
if ((vport->cfg_enable_fc4_type == LPFC_ENABLE_BOTH) ||
@ -6600,11 +6595,6 @@ lpfc_nlp_get(struct lpfc_nodelist *ndlp)
unsigned long flags;
if (ndlp) {
lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE,
"node get: did:x%x flg:x%lx refcnt:x%x",
ndlp->nlp_DID, ndlp->nlp_flag,
kref_read(&ndlp->kref));
/* The check of ndlp usage to prevent incrementing the
* ndlp reference count that is in the process of being
* released.
@ -6612,9 +6602,8 @@ lpfc_nlp_get(struct lpfc_nodelist *ndlp)
spin_lock_irqsave(&ndlp->lock, flags);
if (!kref_get_unless_zero(&ndlp->kref)) {
spin_unlock_irqrestore(&ndlp->lock, flags);
lpfc_printf_vlog(ndlp->vport, KERN_WARNING, LOG_NODE,
"0276 %s: ndlp:x%px refcnt:%d\n",
__func__, (void *)ndlp, kref_read(&ndlp->kref));
pr_info("0276 %s: NDLP has zero reference count. "
"Exiting\n", __func__);
return NULL;
}
spin_unlock_irqrestore(&ndlp->lock, flags);

View File

@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
* Copyright (C) 2017-2025 Broadcom. All Rights Reserved. The term *
* Copyright (C) 2017-2024 Broadcom. All Rights Reserved. The term *
* Broadcom refers to Broadcom Inc. and/or its subsidiaries. *
* Copyright (C) 2004-2016 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@ -168,11 +168,6 @@ struct lpfc_sli_ct_request {
uint8_t len;
uint8_t symbname[255];
} rspn;
struct rspni { /* For RSPNI_PNI requests */
__be64 pni;
u8 len;
u8 symbname[255];
} rspni;
struct gff {
uint32_t PortId;
} gff;
@ -218,8 +213,6 @@ struct lpfc_sli_ct_request {
sizeof(struct da_id))
#define RSPN_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \
sizeof(struct rspn))
#define RSPNI_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \
sizeof(struct rspni))
/*
* FsType Definitions
@ -316,7 +309,6 @@ struct lpfc_sli_ct_request {
#define SLI_CTNS_RIP_NN 0x0235
#define SLI_CTNS_RIPA_NN 0x0236
#define SLI_CTNS_RSNN_NN 0x0239
#define SLI_CTNS_RSPNI_PNI 0x0240
#define SLI_CTNS_DA_ID 0x0300
/*
@ -374,7 +366,6 @@ struct lpfc_name {
} s;
uint8_t wwn[8];
uint64_t name __packed __aligned(4);
__be64 wwn_be __packed __aligned(4);
} u;
};
@ -520,21 +511,6 @@ struct class_parms {
uint8_t word3Reserved2; /* Fc Word 3, bit 0: 7 */
};
enum aux_parm_flags {
AUX_PARM_PNI_VALID = 0x20, /* FC Word 0, bit 29 */
AUX_PARM_DATA_VALID = 0x40, /* FC Word 0, bit 30 */
};
struct aux_parm {
u8 flags; /* FC Word 0, bit 31:24 */
u8 ext_feat[3]; /* FC Word 0, bit 23:0 */
__be64 pni; /* FC Word 1 and 2, platform name identifier */
__be16 rsvd; /* FC Word 3, bit 31:16 */
__be16 npiv_cnt; /* FC Word 3, bit 15:0 */
} __packed;
struct serv_parm { /* Structure is in Big Endian format */
struct csp cmn;
struct lpfc_name portName;
@ -542,7 +518,7 @@ struct serv_parm { /* Structure is in Big Endian format */
struct class_parms cls1;
struct class_parms cls2;
struct class_parms cls3;
struct aux_parm aux;
struct class_parms cls4;
union {
uint8_t vendorVersion[16];
struct {

View File

@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
* Copyright (C) 2017-2025 Broadcom. All Rights Reserved. The term *
* Copyright (C) 2017-2024 Broadcom. All Rights Reserved. The term *
* Broadcom refers to Broadcom Inc. and/or its subsidiaries. *
* Copyright (C) 2009-2016 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@ -1328,9 +1328,6 @@ struct cq_context {
#define LPFC_CQ_CNT_512 0x1
#define LPFC_CQ_CNT_1024 0x2
#define LPFC_CQ_CNT_WORD7 0x3
#define lpfc_cq_context_cqe_sz_SHIFT 25
#define lpfc_cq_context_cqe_sz_MASK 0x00000003
#define lpfc_cq_context_cqe_sz_WORD word0
#define lpfc_cq_context_autovalid_SHIFT 15
#define lpfc_cq_context_autovalid_MASK 0x00000001
#define lpfc_cq_context_autovalid_WORD word0
@ -1386,9 +1383,9 @@ struct lpfc_mbx_cq_create_set {
#define lpfc_mbx_cq_create_set_valid_SHIFT 29
#define lpfc_mbx_cq_create_set_valid_MASK 0x00000001
#define lpfc_mbx_cq_create_set_valid_WORD word1
#define lpfc_mbx_cq_create_set_cqecnt_SHIFT 27
#define lpfc_mbx_cq_create_set_cqecnt_MASK 0x00000003
#define lpfc_mbx_cq_create_set_cqecnt_WORD word1
#define lpfc_mbx_cq_create_set_cqe_cnt_SHIFT 27
#define lpfc_mbx_cq_create_set_cqe_cnt_MASK 0x00000003
#define lpfc_mbx_cq_create_set_cqe_cnt_WORD word1
#define lpfc_mbx_cq_create_set_cqe_size_SHIFT 25
#define lpfc_mbx_cq_create_set_cqe_size_MASK 0x00000003
#define lpfc_mbx_cq_create_set_cqe_size_WORD word1
@ -1401,16 +1398,13 @@ struct lpfc_mbx_cq_create_set {
#define lpfc_mbx_cq_create_set_clswm_SHIFT 12
#define lpfc_mbx_cq_create_set_clswm_MASK 0x00000003
#define lpfc_mbx_cq_create_set_clswm_WORD word1
#define lpfc_mbx_cq_create_set_cqe_cnt_hi_SHIFT 0
#define lpfc_mbx_cq_create_set_cqe_cnt_hi_MASK 0x0000001F
#define lpfc_mbx_cq_create_set_cqe_cnt_hi_WORD word1
uint32_t word2;
#define lpfc_mbx_cq_create_set_arm_SHIFT 31
#define lpfc_mbx_cq_create_set_arm_MASK 0x00000001
#define lpfc_mbx_cq_create_set_arm_WORD word2
#define lpfc_mbx_cq_create_set_cqe_cnt_lo_SHIFT 16
#define lpfc_mbx_cq_create_set_cqe_cnt_lo_MASK 0x00007FFF
#define lpfc_mbx_cq_create_set_cqe_cnt_lo_WORD word2
#define lpfc_mbx_cq_create_set_cq_cnt_SHIFT 16
#define lpfc_mbx_cq_create_set_cq_cnt_MASK 0x00007FFF
#define lpfc_mbx_cq_create_set_cq_cnt_WORD word2
#define lpfc_mbx_cq_create_set_num_cq_SHIFT 0
#define lpfc_mbx_cq_create_set_num_cq_MASK 0x0000FFFF
#define lpfc_mbx_cq_create_set_num_cq_WORD word2

View File

@ -2627,33 +2627,27 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp)
"Obsolete, Unsupported Fibre Channel Adapter"};
break;
case PCI_DEVICE_ID_BMID:
m = (typeof(m)){"LP1150", "PCI-X2",
"Obsolete, Unsupported Fibre Channel Adapter"};
m = (typeof(m)){"LP1150", "PCI-X2", "Fibre Channel Adapter"};
break;
case PCI_DEVICE_ID_BSMB:
m = (typeof(m)){"LP111", "PCI-X2",
"Obsolete, Unsupported Fibre Channel Adapter"};
break;
case PCI_DEVICE_ID_ZEPHYR:
m = (typeof(m)){"LPe11000", "PCIe",
"Obsolete, Unsupported Fibre Channel Adapter"};
m = (typeof(m)){"LPe11000", "PCIe", "Fibre Channel Adapter"};
break;
case PCI_DEVICE_ID_ZEPHYR_SCSP:
m = (typeof(m)){"LPe11000", "PCIe",
"Obsolete, Unsupported Fibre Channel Adapter"};
m = (typeof(m)){"LPe11000", "PCIe", "Fibre Channel Adapter"};
break;
case PCI_DEVICE_ID_ZEPHYR_DCSP:
m = (typeof(m)){"LP2105", "PCIe",
"Obsolete, Unsupported FCoE Adapter"};
m = (typeof(m)){"LP2105", "PCIe", "FCoE Adapter"};
GE = 1;
break;
case PCI_DEVICE_ID_ZMID:
m = (typeof(m)){"LPe1150", "PCIe",
"Obsolete, Unsupported Fibre Channel Adapter"};
m = (typeof(m)){"LPe1150", "PCIe", "Fibre Channel Adapter"};
break;
case PCI_DEVICE_ID_ZSMB:
m = (typeof(m)){"LPe111", "PCIe",
"Obsolete, Unsupported Fibre Channel Adapter"};
m = (typeof(m)){"LPe111", "PCIe", "Fibre Channel Adapter"};
break;
case PCI_DEVICE_ID_LP101:
m = (typeof(m)){"LP101", "PCI-X",
@ -2672,28 +2666,22 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp)
"Obsolete, Unsupported Fibre Channel Adapter"};
break;
case PCI_DEVICE_ID_SAT:
m = (typeof(m)){"LPe12000", "PCIe",
"Obsolete, Unsupported Fibre Channel Adapter"};
m = (typeof(m)){"LPe12000", "PCIe", "Fibre Channel Adapter"};
break;
case PCI_DEVICE_ID_SAT_MID:
m = (typeof(m)){"LPe1250", "PCIe",
"Obsolete, Unsupported Fibre Channel Adapter"};
m = (typeof(m)){"LPe1250", "PCIe", "Fibre Channel Adapter"};
break;
case PCI_DEVICE_ID_SAT_SMB:
m = (typeof(m)){"LPe121", "PCIe",
"Obsolete, Unsupported Fibre Channel Adapter"};
m = (typeof(m)){"LPe121", "PCIe", "Fibre Channel Adapter"};
break;
case PCI_DEVICE_ID_SAT_DCSP:
m = (typeof(m)){"LPe12002-SP", "PCIe",
"Obsolete, Unsupported Fibre Channel Adapter"};
m = (typeof(m)){"LPe12002-SP", "PCIe", "Fibre Channel Adapter"};
break;
case PCI_DEVICE_ID_SAT_SCSP:
m = (typeof(m)){"LPe12000-SP", "PCIe",
"Obsolete, Unsupported Fibre Channel Adapter"};
m = (typeof(m)){"LPe12000-SP", "PCIe", "Fibre Channel Adapter"};
break;
case PCI_DEVICE_ID_SAT_S:
m = (typeof(m)){"LPe12000-S", "PCIe",
"Obsolete, Unsupported Fibre Channel Adapter"};
m = (typeof(m)){"LPe12000-S", "PCIe", "Fibre Channel Adapter"};
break;
case PCI_DEVICE_ID_PROTEUS_VF:
m = (typeof(m)){"LPev12000", "PCIe IOV",
@ -2709,25 +2697,22 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp)
break;
case PCI_DEVICE_ID_TIGERSHARK:
oneConnect = 1;
m = (typeof(m)){"OCe10100", "PCIe",
"Obsolete, Unsupported FCoE Adapter"};
m = (typeof(m)){"OCe10100", "PCIe", "FCoE"};
break;
case PCI_DEVICE_ID_TOMCAT:
oneConnect = 1;
m = (typeof(m)){"OCe11100", "PCIe",
"Obsolete, Unsupported FCoE Adapter"};
m = (typeof(m)){"OCe11100", "PCIe", "FCoE"};
break;
case PCI_DEVICE_ID_FALCON:
m = (typeof(m)){"LPSe12002-ML1-E", "PCIe",
"Obsolete, Unsupported Fibre Channel Adapter"};
"EmulexSecure Fibre"};
break;
case PCI_DEVICE_ID_BALIUS:
m = (typeof(m)){"LPVe12002", "PCIe Shared I/O",
"Obsolete, Unsupported Fibre Channel Adapter"};
break;
case PCI_DEVICE_ID_LANCER_FC:
m = (typeof(m)){"LPe16000", "PCIe",
"Obsolete, Unsupported Fibre Channel Adapter"};
m = (typeof(m)){"LPe16000", "PCIe", "Fibre Channel Adapter"};
break;
case PCI_DEVICE_ID_LANCER_FC_VF:
m = (typeof(m)){"LPe16000", "PCIe",
@ -2735,13 +2720,12 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp)
break;
case PCI_DEVICE_ID_LANCER_FCOE:
oneConnect = 1;
m = (typeof(m)){"OCe15100", "PCIe",
"Obsolete, Unsupported FCoE Adapter"};
m = (typeof(m)){"OCe15100", "PCIe", "FCoE"};
break;
case PCI_DEVICE_ID_LANCER_FCOE_VF:
oneConnect = 1;
m = (typeof(m)){"OCe15100", "PCIe",
"Obsolete, Unsupported FCoE Adapter"};
"Obsolete, Unsupported FCoE"};
break;
case PCI_DEVICE_ID_LANCER_G6_FC:
m = (typeof(m)){"LPe32000", "PCIe", "Fibre Channel Adapter"};
@ -2755,8 +2739,7 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp)
case PCI_DEVICE_ID_SKYHAWK:
case PCI_DEVICE_ID_SKYHAWK_VF:
oneConnect = 1;
m = (typeof(m)){"OCe14000", "PCIe",
"Obsolete, Unsupported FCoE Adapter"};
m = (typeof(m)){"OCe14000", "PCIe", "FCoE"};
break;
default:
m = (typeof(m)){"Unknown", "", ""};
@ -3057,6 +3040,19 @@ lpfc_cleanup(struct lpfc_vport *vport)
lpfc_vmid_vport_cleanup(vport);
list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
if (vport->port_type != LPFC_PHYSICAL_PORT &&
ndlp->nlp_DID == Fabric_DID) {
/* Just free up ndlp with Fabric_DID for vports */
lpfc_nlp_put(ndlp);
continue;
}
if (ndlp->nlp_DID == Fabric_Cntl_DID &&
ndlp->nlp_state == NLP_STE_UNUSED_NODE) {
lpfc_nlp_put(ndlp);
continue;
}
/* Fabric Ports not in UNMAPPED state are cleaned up in the
* DEVICE_RM event.
*/
@ -7923,6 +7919,8 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
int longs;
int extra;
uint64_t wwn;
u32 if_type;
u32 if_fam;
phba->sli4_hba.num_present_cpu = lpfc_present_cpu;
phba->sli4_hba.num_possible_cpu = cpumask_last(cpu_possible_mask) + 1;
@ -8182,11 +8180,28 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
*/
rc = lpfc_get_sli4_parameters(phba, mboxq);
if (rc) {
lpfc_log_msg(phba, KERN_WARNING, LOG_INIT,
"2999 Could not get SLI4 parameters\n");
rc = -EIO;
mempool_free(mboxq, phba->mbox_mem_pool);
goto out_free_bsmbx;
if_type = bf_get(lpfc_sli_intf_if_type,
&phba->sli4_hba.sli_intf);
if_fam = bf_get(lpfc_sli_intf_sli_family,
&phba->sli4_hba.sli_intf);
if (phba->sli4_hba.extents_in_use &&
phba->sli4_hba.rpi_hdrs_in_use) {
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
"2999 Unsupported SLI4 Parameters "
"Extents and RPI headers enabled.\n");
if (if_type == LPFC_SLI_INTF_IF_TYPE_0 &&
if_fam == LPFC_SLI_INTF_FAMILY_BE2) {
mempool_free(mboxq, phba->mbox_mem_pool);
rc = -EIO;
goto out_free_bsmbx;
}
}
if (!(if_type == LPFC_SLI_INTF_IF_TYPE_0 &&
if_fam == LPFC_SLI_INTF_FAMILY_BE2)) {
mempool_free(mboxq, phba->mbox_mem_pool);
rc = -EIO;
goto out_free_bsmbx;
}
}
/*
@ -8287,7 +8302,10 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
phba->cfg_total_seg_cnt, phba->cfg_scsi_seg_cnt,
phba->cfg_nvme_seg_cnt);
i = min(phba->cfg_sg_dma_buf_size, SLI4_PAGE_SIZE);
if (phba->cfg_sg_dma_buf_size < SLI4_PAGE_SIZE)
i = phba->cfg_sg_dma_buf_size;
else
i = SLI4_PAGE_SIZE;
phba->lpfc_sg_dma_buf_pool =
dma_pool_create("lpfc_sg_dma_buf_pool",
@ -9076,9 +9094,9 @@ lpfc_setup_fdmi_mask(struct lpfc_vport *vport)
vport->fdmi_port_mask = LPFC_FDMI2_PORT_ATTR;
}
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
"6077 Setup FDMI mask: hba x%x port x%x\n",
vport->fdmi_hba_mask, vport->fdmi_port_mask);
lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
"6077 Setup FDMI mask: hba x%x port x%x\n",
vport->fdmi_hba_mask, vport->fdmi_port_mask);
}
/**

View File

@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
* Copyright (C) 2017-2025 Broadcom. All Rights Reserved. The term *
* Copyright (C) 2017-2024 Broadcom. All Rights Reserved. The term *
* Broadcom refers to Broadcom Inc. and/or its subsidiaries. *
* Copyright (C) 2004-2016 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@ -326,14 +326,8 @@ lpfc_defer_plogi_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *login_mbox)
/* Now that REG_RPI completed successfully,
* we can now proceed with sending the PLOGI ACC.
*/
if (test_bit(FC_PT2PT, &ndlp->vport->fc_flag)) {
rc = lpfc_els_rsp_acc(login_mbox->vport, ELS_CMD_PLOGI,
save_iocb, ndlp, login_mbox);
} else {
rc = lpfc_els_rsp_acc(login_mbox->vport, ELS_CMD_PLOGI,
save_iocb, ndlp, NULL);
}
rc = lpfc_els_rsp_acc(login_mbox->vport, ELS_CMD_PLOGI,
save_iocb, ndlp, NULL);
if (rc) {
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
"4576 PLOGI ACC fails pt2pt discovery: "
@ -341,16 +335,9 @@ lpfc_defer_plogi_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *login_mbox)
}
}
/* If this is a fabric topology, complete the reg_rpi and prli now.
* For Pt2Pt, the reg_rpi and PRLI are deferred until after the LS_ACC
* completes. This ensures, in Pt2Pt, that the PLOGI LS_ACC is sent
* before the PRLI.
*/
if (!test_bit(FC_PT2PT, &ndlp->vport->fc_flag)) {
/* Now process the REG_RPI cmpl */
lpfc_mbx_cmpl_reg_login(phba, login_mbox);
clear_bit(NLP_ACC_REGLOGIN, &ndlp->nlp_flag);
}
/* Now process the REG_RPI cmpl */
lpfc_mbx_cmpl_reg_login(phba, login_mbox);
clear_bit(NLP_ACC_REGLOGIN, &ndlp->nlp_flag);
kfree(save_iocb);
}
@ -432,6 +419,8 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
ndlp->nlp_class_sup |= FC_COS_CLASS2;
if (sp->cls3.classValid)
ndlp->nlp_class_sup |= FC_COS_CLASS3;
if (sp->cls4.classValid)
ndlp->nlp_class_sup |= FC_COS_CLASS4;
ndlp->nlp_maxframe =
((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) | sp->cmn.bbRcvSizeLsb;
/* if already logged in, do implicit logout */
@ -450,7 +439,18 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
*/
if (!(ndlp->nlp_type & NLP_FABRIC) &&
!(phba->nvmet_support)) {
break;
/* Clear ndlp info, since follow up PRLI may have
* updated ndlp information
*/
ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR);
ndlp->nlp_type &= ~(NLP_NVME_TARGET | NLP_NVME_INITIATOR);
ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE;
ndlp->nlp_nvme_info &= ~NLP_NVME_NSLER;
clear_bit(NLP_FIRSTBURST, &ndlp->nlp_flag);
lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb,
ndlp, NULL);
return 1;
}
if (nlp_portwwn != 0 &&
nlp_portwwn != wwn_to_u64(sp->portName.u.wwn))
@ -472,9 +472,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
break;
}
/* Clear ndlp info, since follow up processes may have
* updated ndlp information
*/
ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR);
ndlp->nlp_type &= ~(NLP_NVME_TARGET | NLP_NVME_INITIATOR);
ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE;
@ -1415,6 +1413,8 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
ndlp->nlp_class_sup |= FC_COS_CLASS2;
if (sp->cls3.classValid)
ndlp->nlp_class_sup |= FC_COS_CLASS3;
if (sp->cls4.classValid)
ndlp->nlp_class_sup |= FC_COS_CLASS4;
ndlp->nlp_maxframe =
((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) | sp->cmn.bbRcvSizeLsb;

View File

@ -1234,8 +1234,12 @@ lpfc_nvme_prep_io_cmd(struct lpfc_vport *vport,
if ((phba->cfg_nvme_enable_fb) &&
test_bit(NLP_FIRSTBURST, &pnode->nlp_flag)) {
req_len = lpfc_ncmd->nvmeCmd->payload_length;
wqe->fcp_iwrite.initial_xfer_len = min(req_len,
pnode->nvme_fb_size);
if (req_len < pnode->nvme_fb_size)
wqe->fcp_iwrite.initial_xfer_len =
req_len;
else
wqe->fcp_iwrite.initial_xfer_len =
pnode->nvme_fb_size;
} else {
wqe->fcp_iwrite.initial_xfer_len = 0;
}

View File

@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
* Copyright (C) 2017-2025 Broadcom. All Rights Reserved. The term *
* Copyright (C) 2017-2024 Broadcom. All Rights Reserved. The term *
* Broadcom refers to Broadcom Inc. and/or its subsidiaries. *
* Copyright (C) 2004-2016 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@ -390,10 +390,6 @@ lpfc_sli4_vport_delete_fcp_xri_aborted(struct lpfc_vport *vport)
if (!(vport->cfg_enable_fc4_type & LPFC_ENABLE_FCP))
return;
/* may be called before queues established if hba_setup fails */
if (!phba->sli4_hba.hdwq)
return;
spin_lock_irqsave(&phba->hbalock, iflag);
for (idx = 0; idx < phba->cfg_hdw_queue; idx++) {
qp = &phba->sli4_hba.hdwq[idx];
@ -536,8 +532,7 @@ lpfc_sli4_io_xri_aborted(struct lpfc_hba *phba,
psb = container_of(iocbq, struct lpfc_io_buf, cur_iocbq);
psb->flags &= ~LPFC_SBUF_XBUSY;
spin_unlock_irqrestore(&phba->hbalock, iflag);
if (test_bit(HBA_SETUP, &phba->hba_flag) &&
!list_empty(&pring->txq))
if (!list_empty(&pring->txq))
lpfc_worker_wake_up(phba);
return;
}
@ -5936,7 +5931,7 @@ lpfc_chk_tgt_mapped(struct lpfc_vport *vport, struct fc_rport *rport)
/**
* lpfc_reset_flush_io_context -
* @vport: The virtual port (scsi_host) for the flush context
* @tgt_id: If aborting by Target context - specifies the target id
* @tgt_id: If aborting by Target contect - specifies the target id
* @lun_id: If aborting by Lun context - specifies the lun id
* @context: specifies the context level to flush at.
*
@ -6110,14 +6105,8 @@ lpfc_target_reset_handler(struct scsi_cmnd *cmnd)
pnode->nlp_fcp_info &= ~NLP_FCP_2_DEVICE;
spin_unlock_irqrestore(&pnode->lock, flags);
}
status = lpfc_reset_flush_io_context(vport, tgt_id, lun_id,
LPFC_CTX_TGT);
if (status != SUCCESS) {
lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
"0726 Target Reset flush status x%x\n",
status);
return status;
}
lpfc_reset_flush_io_context(vport, tgt_id, lun_id,
LPFC_CTX_TGT);
return FAST_IO_FAIL;
}
@ -6210,7 +6199,7 @@ lpfc_host_reset_handler(struct scsi_cmnd *cmnd)
int rc, ret = SUCCESS;
lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
"3172 SCSI layer issued Host Reset\n");
"3172 SCSI layer issued Host Reset Data:\n");
lpfc_offline_prep(phba, LPFC_MBX_WAIT);
lpfc_offline(phba);

View File

@ -27,8 +27,6 @@
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/lockdep.h>
#include <linux/dmi.h>
#include <linux/of.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
@ -5162,6 +5160,7 @@ lpfc_sli4_brdreset(struct lpfc_hba *phba)
phba->link_events = 0;
phba->pport->fc_myDID = 0;
phba->pport->fc_prevDID = 0;
clear_bit(HBA_SETUP, &phba->hba_flag);
spin_lock_irq(&phba->hbalock);
psli->sli_flag &= ~(LPFC_PROCESS_LA);
@ -5278,7 +5277,6 @@ lpfc_sli_brdrestart_s4(struct lpfc_hba *phba)
"0296 Restart HBA Data: x%x x%x\n",
phba->pport->port_state, psli->sli_flag);
clear_bit(HBA_SETUP, &phba->hba_flag);
lpfc_sli4_queue_unset(phba);
rc = lpfc_sli4_brdreset(phba);
@ -8441,70 +8439,6 @@ lpfc_set_host_tm(struct lpfc_hba *phba)
return rc;
}
/**
* lpfc_get_platform_uuid - Attempts to extract a platform uuid
* @phba: pointer to lpfc hba data structure.
*
* This routine attempts to first read SMBIOS DMI data for the System
* Information structure offset 08h called System UUID. Else, no platform
* UUID will be advertised.
**/
static void
lpfc_get_platform_uuid(struct lpfc_hba *phba)
{
int rc;
const char *uuid;
char pni[17] = {0}; /* 16 characters + '\0' */
bool is_ff = true, is_00 = true;
u8 i;
/* First attempt SMBIOS DMI */
uuid = dmi_get_system_info(DMI_PRODUCT_UUID);
if (uuid) {
lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
"2088 SMBIOS UUID %s\n",
uuid);
} else {
lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
"2099 Could not extract UUID\n");
}
if (uuid && uuid_is_valid(uuid)) {
/* Generate PNI from UUID format.
*
* 1.) Extract lower 64 bits from UUID format.
* 2.) Set 3h for NAA Locally Assigned Name Identifier format.
*
* e.g. xxxxxxxx-xxxx-xxxx-yyyy-yyyyyyyyyyyy
*
* extract the yyyy-yyyyyyyyyyyy portion
* final PNI 3yyyyyyyyyyyyyyy
*/
scnprintf(pni, sizeof(pni), "3%c%c%c%s",
uuid[20], uuid[21], uuid[22], &uuid[24]);
/* Sanitize the converted PNI */
for (i = 1; i < 16 && (is_ff || is_00); i++) {
if (pni[i] != '0')
is_00 = false;
if (pni[i] != 'f' && pni[i] != 'F')
is_ff = false;
}
/* Convert from char* to unsigned long */
rc = kstrtoul(pni, 16, &phba->pni);
if (!rc && !is_ff && !is_00) {
lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
"2100 PNI 0x%016lx\n", phba->pni);
} else {
lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
"2101 PNI %s generation status %d\n",
pni, rc);
phba->pni = 0;
}
}
}
/**
* lpfc_sli4_hba_setup - SLI4 device initialization PCI function
* @phba: Pointer to HBA context object.
@ -8588,10 +8522,6 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
clear_bit(HBA_FCOE_MODE, &phba->hba_flag);
}
/* Obtain platform UUID, only for SLI4 FC adapters */
if (!test_bit(HBA_FCOE_MODE, &phba->hba_flag))
lpfc_get_platform_uuid(phba);
if (bf_get(lpfc_mbx_rd_rev_cee_ver, &mqe->un.read_rev) ==
LPFC_DCBX_CEE_MODE)
set_bit(HBA_FIP_SUPPORT, &phba->hba_flag);
@ -8883,7 +8813,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
if (unlikely(rc)) {
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
"0381 Error %d during queue setup.\n", rc);
goto out_destroy_queue;
goto out_stop_timers;
}
/* Initialize the driver internal SLI layer lists. */
lpfc_sli4_setup(phba);
@ -9166,6 +9096,7 @@ out_free_iocblist:
lpfc_free_iocb_list(phba);
out_destroy_queue:
lpfc_sli4_queue_destroy(phba);
out_stop_timers:
lpfc_stop_hba_timers(phba);
out_free_mbox:
mempool_free(mboxq, phba->mbox_mem_pool);
@ -12505,11 +12436,19 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
}
/*
* Always abort the outstanding WQE and set the IA bit correctly
* for the context. This is necessary for correctly removing
* outstanding ndlp reference counts when the CQE completes with
* the XB bit set.
* If we're unloading, don't abort iocb on the ELS ring, but change
* the callback so that nothing happens when it finishes.
*/
if (test_bit(FC_UNLOADING, &vport->load_flag) &&
pring->ringno == LPFC_ELS_RING) {
if (cmdiocb->cmd_flag & LPFC_IO_FABRIC)
cmdiocb->fabric_cmd_cmpl = lpfc_ignore_els_cmpl;
else
cmdiocb->cmd_cmpl = lpfc_ignore_els_cmpl;
return retval;
}
/* issue ABTS for this IOCB based on iotag */
abtsiocbp = __lpfc_sli_get_iocbq(phba);
if (abtsiocbp == NULL)
return IOCB_NORESOURCE;
@ -16537,10 +16476,10 @@ lpfc_cq_create_set(struct lpfc_hba *phba, struct lpfc_queue **cqp,
case 4096:
if (phba->sli4_hba.pc_sli4_params.cqv ==
LPFC_Q_CREATE_VERSION_2) {
bf_set(lpfc_mbx_cq_create_set_cqe_cnt_lo,
bf_set(lpfc_mbx_cq_create_set_cqe_cnt,
&cq_set->u.request,
cq->entry_count);
bf_set(lpfc_mbx_cq_create_set_cqecnt,
cq->entry_count);
bf_set(lpfc_mbx_cq_create_set_cqe_cnt,
&cq_set->u.request,
LPFC_CQ_CNT_WORD7);
break;
@ -16556,15 +16495,15 @@ lpfc_cq_create_set(struct lpfc_hba *phba, struct lpfc_queue **cqp,
}
fallthrough; /* otherwise default to smallest */
case 256:
bf_set(lpfc_mbx_cq_create_set_cqecnt,
bf_set(lpfc_mbx_cq_create_set_cqe_cnt,
&cq_set->u.request, LPFC_CQ_CNT_256);
break;
case 512:
bf_set(lpfc_mbx_cq_create_set_cqecnt,
bf_set(lpfc_mbx_cq_create_set_cqe_cnt,
&cq_set->u.request, LPFC_CQ_CNT_512);
break;
case 1024:
bf_set(lpfc_mbx_cq_create_set_cqecnt,
bf_set(lpfc_mbx_cq_create_set_cqe_cnt,
&cq_set->u.request, LPFC_CQ_CNT_1024);
break;
}
@ -19927,15 +19866,13 @@ lpfc_sli4_remove_rpis(struct lpfc_hba *phba)
}
/**
* lpfc_sli4_resume_rpi - Resume traffic relative to an RPI
* lpfc_sli4_resume_rpi - Remove the rpi bitmask region
* @ndlp: pointer to lpfc nodelist data structure.
* @cmpl: completion call-back.
* @iocbq: data to load as mbox ctx_u information
*
* Return codes
* 0 - successful
* -ENOMEM - No available memory
* -EIO - The mailbox failed to complete successfully.
* This routine is invoked to remove the memory region that
* provided rpi via a bitmask.
**/
int
lpfc_sli4_resume_rpi(struct lpfc_nodelist *ndlp,
@ -19965,6 +19902,7 @@ lpfc_sli4_resume_rpi(struct lpfc_nodelist *ndlp,
return -EIO;
}
/* Post all rpi memory regions to the port. */
lpfc_resume_rpi(mboxq, ndlp);
if (cmpl) {
mboxq->mbox_cmpl = cmpl;
@ -21434,7 +21372,7 @@ lpfc_sli4_issue_wqe(struct lpfc_hba *phba, struct lpfc_sli4_hdw_queue *qp,
struct lpfc_sglq *sglq;
struct lpfc_sli_ring *pring;
unsigned long iflags;
int ret = 0;
uint32_t ret = 0;
/* NVME_LS and NVME_LS ABTS requests. */
if (pwqe->cmd_flag & LPFC_IO_NVME_LS) {

View File

@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
* Copyright (C) 2017-2025 Broadcom. All Rights Reserved. The term *
* Copyright (C) 2017-2024 Broadcom. All Rights Reserved. The term *
* Broadcom refers to Broadcom Inc. and/or its subsidiaries. *
* Copyright (C) 2009-2016 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@ -575,10 +575,8 @@ struct lpfc_pc_sli4_params {
#define LPFC_CQ_4K_PAGE_SZ 0x1
#define LPFC_CQ_16K_PAGE_SZ 0x4
#define LPFC_CQ_32K_PAGE_SZ 0x8
#define LPFC_WQ_4K_PAGE_SZ 0x1
#define LPFC_WQ_16K_PAGE_SZ 0x4
#define LPFC_WQ_32K_PAGE_SZ 0x8
struct lpfc_iov {
uint32_t pf_number;

Some files were not shown because too many files have changed in this diff Show More