Import of kernel-6.12.0-124.20.1.el10_1

This commit is contained in:
almalinux-bot-kernel 2025-12-11 04:15:58 +00:00
parent 1dc94ec495
commit 8ac76c15e5
91 changed files with 6521 additions and 285 deletions

View File

@ -0,0 +1,76 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/dpll/dpll-device.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Digital Phase-Locked Loop (DPLL) Device
maintainers:
- Ivan Vecera <ivecera@redhat.com>
description:
Digital Phase-Locked Loop (DPLL) device is used for precise clock
synchronization in networking and telecom hardware. The device can
have one or more channels (DPLLs) and one or more physical input and
output pins. Each DPLL channel can either produce pulse-per-clock signal
or drive ethernet equipment clock. The type of each channel can be
indicated by dpll-types property.
properties:
$nodename:
pattern: "^dpll(@.*)?$"
"#address-cells":
const: 0
"#size-cells":
const: 0
dpll-types:
description: List of DPLL channel types, one per DPLL instance.
$ref: /schemas/types.yaml#/definitions/non-unique-string-array
items:
enum: [pps, eec]
input-pins:
type: object
description: DPLL input pins
unevaluatedProperties: false
properties:
"#address-cells":
const: 1
"#size-cells":
const: 0
patternProperties:
"^pin@[0-9a-f]+$":
$ref: /schemas/dpll/dpll-pin.yaml
unevaluatedProperties: false
required:
- "#address-cells"
- "#size-cells"
output-pins:
type: object
description: DPLL output pins
unevaluatedProperties: false
properties:
"#address-cells":
const: 1
"#size-cells":
const: 0
patternProperties:
"^pin@[0-9]+$":
$ref: /schemas/dpll/dpll-pin.yaml
unevaluatedProperties: false
required:
- "#address-cells"
- "#size-cells"
additionalProperties: true

View File

@ -0,0 +1,45 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/dpll/dpll-pin.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: DPLL Pin
maintainers:
- Ivan Vecera <ivecera@redhat.com>
description: |
The DPLL pin is either a physical input or output pin that is provided
by a DPLL( Digital Phase-Locked Loop) device. The pin is identified by
its physical order number that is stored in reg property and can have
an additional set of properties like supported (allowed) frequencies,
label, type and may support embedded sync.
Note that the pin in this context has nothing to do with pinctrl.
properties:
reg:
description: Hardware index of the DPLL pin.
maxItems: 1
connection-type:
description: Connection type of the pin
$ref: /schemas/types.yaml#/definitions/string
enum: [ext, gnss, int, mux, synce]
esync-control:
description: Indicates whether the pin supports embedded sync functionality.
type: boolean
label:
description: String exposed as the pin board label
$ref: /schemas/types.yaml#/definitions/string
supported-frequencies-hz:
description: List of supported frequencies for this pin, expressed in Hz.
required:
- reg
additionalProperties: false

View File

@ -0,0 +1,115 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/dpll/microchip,zl30731.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Microchip Azurite DPLL device
maintainers:
- Ivan Vecera <ivecera@redhat.com>
description:
Microchip Azurite DPLL (ZL3073x) is a family of DPLL devices that
provides up to 5 independent DPLL channels, up to 10 differential or
single-ended inputs and 10 differential or 20 single-ended outputs.
These devices support both I2C and SPI interfaces.
properties:
compatible:
enum:
- microchip,zl30731
- microchip,zl30732
- microchip,zl30733
- microchip,zl30734
- microchip,zl30735
reg:
maxItems: 1
required:
- compatible
- reg
allOf:
- $ref: /schemas/dpll/dpll-device.yaml#
- $ref: /schemas/spi/spi-peripheral-props.yaml#
unevaluatedProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
dpll@70 {
compatible = "microchip,zl30732";
reg = <0x70>;
dpll-types = "pps", "eec";
input-pins {
#address-cells = <1>;
#size-cells = <0>;
pin@0 { /* REF0P */
reg = <0>;
connection-type = "ext";
label = "Input 0";
supported-frequencies-hz = /bits/ 64 <1 1000>;
};
};
output-pins {
#address-cells = <1>;
#size-cells = <0>;
pin@3 { /* OUT1N */
reg = <3>;
connection-type = "gnss";
esync-control;
label = "Output 1";
supported-frequencies-hz = /bits/ 64 <1 10000>;
};
};
};
};
- |
spi {
#address-cells = <1>;
#size-cells = <0>;
dpll@70 {
compatible = "microchip,zl30731";
reg = <0x70>;
spi-max-frequency = <12500000>;
dpll-types = "pps";
input-pins {
#address-cells = <1>;
#size-cells = <0>;
pin@0 { /* REF0P */
reg = <0>;
connection-type = "ext";
label = "Input 0";
supported-frequencies-hz = /bits/ 64 <1 1000>;
};
};
output-pins {
#address-cells = <1>;
#size-cells = <0>;
pin@3 { /* OUT1N */
reg = <3>;
connection-type = "gnss";
esync-control;
label = "Output 1";
supported-frequencies-hz = /bits/ 64 <1 10000>;
};
};
};
};
...

View File

@ -98,3 +98,4 @@ parameters, info versions, and other features it supports.
iosm iosm
octeontx2 octeontx2
sfc sfc
zl3073x

View File

@ -0,0 +1,51 @@
.. SPDX-License-Identifier: GPL-2.0
=======================
zl3073x devlink support
=======================
This document describes the devlink features implemented by the ``zl3073x``
device driver.
Parameters
==========
.. list-table:: Generic parameters implemented
:widths: 5 5 90
* - Name
- Mode
- Notes
* - ``clock_id``
- driverinit
- Set the clock ID that is used by the driver for registering DPLL devices
and pins.
Info versions
=============
The ``zl3073x`` driver reports the following versions
.. list-table:: devlink info versions implemented
:widths: 5 5 5 90
* - Name
- Type
- Example
- Description
* - ``asic.id``
- fixed
- 1E94
- Chip identification number
* - ``asic.rev``
- fixed
- 300
- Chip revision number
* - ``fw``
- running
- 7006
- Firmware version number
* - ``custom_cfg``
- running
- 1.3.0.1
- Device configuration version customized by OEM

View File

@ -6963,6 +6963,8 @@ M: Arkadiusz Kubalewski <arkadiusz.kubalewski@intel.com>
M: Jiri Pirko <jiri@resnulli.us> M: Jiri Pirko <jiri@resnulli.us>
L: netdev@vger.kernel.org L: netdev@vger.kernel.org
S: Supported S: Supported
F: Documentation/devicetree/bindings/dpll/dpll-device.yaml
F: Documentation/devicetree/bindings/dpll/dpll-pin.yaml
F: Documentation/driver-api/dpll.rst F: Documentation/driver-api/dpll.rst
F: drivers/dpll/* F: drivers/dpll/*
F: include/linux/dpll.h F: include/linux/dpll.h
@ -15392,6 +15394,14 @@ L: linux-wireless@vger.kernel.org
S: Supported S: Supported
F: drivers/net/wireless/microchip/wilc1000/ F: drivers/net/wireless/microchip/wilc1000/
MICROCHIP ZL3073X DRIVER
M: Ivan Vecera <ivecera@redhat.com>
M: Prathosh Satish <Prathosh.Satish@microchip.com>
L: netdev@vger.kernel.org
S: Supported
F: Documentation/devicetree/bindings/dpll/microchip,zl30731.yaml
F: drivers/dpll/zl3073x/
MICROSEMI MIPS SOCS MICROSEMI MIPS SOCS
M: Alexandre Belloni <alexandre.belloni@bootlin.com> M: Alexandre Belloni <alexandre.belloni@bootlin.com>
M: UNGLinuxDriver@microchip.com M: UNGLinuxDriver@microchip.com

View File

@ -12,7 +12,7 @@ RHEL_MINOR = 1
# #
# Use this spot to avoid future merge conflicts. # Use this spot to avoid future merge conflicts.
# Do not trim this comment. # Do not trim this comment.
RHEL_RELEASE = 124.16.1 RHEL_RELEASE = 124.20.1
# #
# RHEL_REBASE_NUM # RHEL_REBASE_NUM

View File

@ -106,6 +106,10 @@ static pci_ers_result_t zpci_event_do_error_state_clear(struct pci_dev *pdev,
struct zpci_dev *zdev = to_zpci(pdev); struct zpci_dev *zdev = to_zpci(pdev);
int rc; int rc;
/* The underlying device may have been disabled by the event */
if (!zdev_enabled(zdev))
return PCI_ERS_RESULT_NEED_RESET;
pr_info("%s: Unblocking device access for examination\n", pci_name(pdev)); pr_info("%s: Unblocking device access for examination\n", pci_name(pdev));
rc = zpci_reset_load_store_blocked(zdev); rc = zpci_reset_load_store_blocked(zdev);
if (rc) { if (rc) {
@ -273,6 +277,8 @@ static void __zpci_event_error(struct zpci_ccdf_err *ccdf)
struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid); struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid);
struct pci_dev *pdev = NULL; struct pci_dev *pdev = NULL;
pci_ers_result_t ers_res; pci_ers_result_t ers_res;
u32 fh = 0;
int rc;
zpci_dbg(3, "err fid:%x, fh:%x, pec:%x\n", zpci_dbg(3, "err fid:%x, fh:%x, pec:%x\n",
ccdf->fid, ccdf->fh, ccdf->pec); ccdf->fid, ccdf->fh, ccdf->pec);
@ -281,6 +287,15 @@ static void __zpci_event_error(struct zpci_ccdf_err *ccdf)
if (zdev) { if (zdev) {
mutex_lock(&zdev->state_lock); mutex_lock(&zdev->state_lock);
rc = clp_refresh_fh(zdev->fid, &fh);
if (rc)
goto no_pdev;
if (!fh || ccdf->fh != fh) {
/* Ignore events with stale handles */
zpci_dbg(3, "err fid:%x, fh:%x (stale %x)\n",
ccdf->fid, fh, ccdf->fh);
goto no_pdev;
}
zpci_update_fh(zdev, ccdf->fh); zpci_update_fh(zdev, ccdf->fh);
if (zdev->zbus->bus) if (zdev->zbus->bus)
pdev = pci_get_slot(zdev->zbus->bus, zdev->devfn); pdev = pci_get_slot(zdev->zbus->bus, zdev->devfn);

View File

@ -460,6 +460,195 @@ void hv_ivm_msr_read(u64 msr, u64 *value)
hv_ghcb_msr_read(msr, value); hv_ghcb_msr_read(msr, value);
} }
/*
* Keep track of the PFN regions which were shared with the host. The access
* must be revoked upon kexec/kdump (see hv_ivm_clear_host_access()).
*/
struct hv_enc_pfn_region {
struct list_head list;
u64 pfn;
int count;
};
static LIST_HEAD(hv_list_enc);
static DEFINE_RAW_SPINLOCK(hv_list_enc_lock);
static int hv_list_enc_add(const u64 *pfn_list, int count)
{
struct hv_enc_pfn_region *ent;
unsigned long flags;
u64 pfn;
int i;
for (i = 0; i < count; i++) {
pfn = pfn_list[i];
raw_spin_lock_irqsave(&hv_list_enc_lock, flags);
/* Check if the PFN already exists in some region first */
list_for_each_entry(ent, &hv_list_enc, list) {
if ((ent->pfn <= pfn) && (ent->pfn + ent->count - 1 >= pfn))
/* Nothing to do - pfn is already in the list */
goto unlock_done;
}
/*
* Check if the PFN is adjacent to an existing region. Growing
* a region can make it adjacent to another one but merging is
* not (yet) implemented for simplicity. A PFN cannot be added
* to two regions to keep the logic in hv_list_enc_remove()
* correct.
*/
list_for_each_entry(ent, &hv_list_enc, list) {
if (ent->pfn + ent->count == pfn) {
/* Grow existing region up */
ent->count++;
goto unlock_done;
} else if (pfn + 1 == ent->pfn) {
/* Grow existing region down */
ent->pfn--;
ent->count++;
goto unlock_done;
}
}
raw_spin_unlock_irqrestore(&hv_list_enc_lock, flags);
/* No adjacent region found -- create a new one */
ent = kzalloc(sizeof(struct hv_enc_pfn_region), GFP_KERNEL);
if (!ent)
return -ENOMEM;
ent->pfn = pfn;
ent->count = 1;
raw_spin_lock_irqsave(&hv_list_enc_lock, flags);
list_add(&ent->list, &hv_list_enc);
unlock_done:
raw_spin_unlock_irqrestore(&hv_list_enc_lock, flags);
}
return 0;
}
static int hv_list_enc_remove(const u64 *pfn_list, int count)
{
struct hv_enc_pfn_region *ent, *t;
struct hv_enc_pfn_region new_region;
unsigned long flags;
u64 pfn;
int i;
for (i = 0; i < count; i++) {
pfn = pfn_list[i];
raw_spin_lock_irqsave(&hv_list_enc_lock, flags);
list_for_each_entry_safe(ent, t, &hv_list_enc, list) {
if (pfn == ent->pfn + ent->count - 1) {
/* Removing tail pfn */
ent->count--;
if (!ent->count) {
list_del(&ent->list);
kfree(ent);
}
goto unlock_done;
} else if (pfn == ent->pfn) {
/* Removing head pfn */
ent->count--;
ent->pfn++;
if (!ent->count) {
list_del(&ent->list);
kfree(ent);
}
goto unlock_done;
} else if (pfn > ent->pfn && pfn < ent->pfn + ent->count - 1) {
/*
* Removing a pfn in the middle. Cut off the tail
* of the existing region and create a template for
* the new one.
*/
new_region.pfn = pfn + 1;
new_region.count = ent->count - (pfn - ent->pfn + 1);
ent->count = pfn - ent->pfn;
goto unlock_split;
}
}
unlock_done:
raw_spin_unlock_irqrestore(&hv_list_enc_lock, flags);
continue;
unlock_split:
raw_spin_unlock_irqrestore(&hv_list_enc_lock, flags);
ent = kzalloc(sizeof(struct hv_enc_pfn_region), GFP_KERNEL);
if (!ent)
return -ENOMEM;
ent->pfn = new_region.pfn;
ent->count = new_region.count;
raw_spin_lock_irqsave(&hv_list_enc_lock, flags);
list_add(&ent->list, &hv_list_enc);
raw_spin_unlock_irqrestore(&hv_list_enc_lock, flags);
}
return 0;
}
/* Stop new private<->shared conversions */
static void hv_vtom_kexec_begin(void)
{
if (!IS_ENABLED(CONFIG_KEXEC_CORE))
return;
/*
* Crash kernel reaches here with interrupts disabled: can't wait for
* conversions to finish.
*
* If race happened, just report and proceed.
*/
if (!set_memory_enc_stop_conversion())
pr_warn("Failed to stop shared<->private conversions\n");
}
static void hv_vtom_kexec_finish(void)
{
struct hv_gpa_range_for_visibility *input;
struct hv_enc_pfn_region *ent;
unsigned long flags;
u64 hv_status;
int cur, i;
local_irq_save(flags);
input = *this_cpu_ptr(hyperv_pcpu_input_arg);
if (unlikely(!input))
goto out;
list_for_each_entry(ent, &hv_list_enc, list) {
for (i = 0, cur = 0; i < ent->count; i++) {
input->gpa_page_list[cur] = ent->pfn + i;
cur++;
if (cur == HV_MAX_MODIFY_GPA_REP_COUNT || i == ent->count - 1) {
input->partition_id = HV_PARTITION_ID_SELF;
input->host_visibility = VMBUS_PAGE_NOT_VISIBLE;
input->reserved0 = 0;
input->reserved1 = 0;
hv_status = hv_do_rep_hypercall(
HVCALL_MODIFY_SPARSE_GPA_PAGE_HOST_VISIBILITY,
cur, 0, input, NULL);
WARN_ON_ONCE(!hv_result_success(hv_status));
cur = 0;
}
}
}
out:
local_irq_restore(flags);
}
/* /*
* hv_mark_gpa_visibility - Set pages visible to host via hvcall. * hv_mark_gpa_visibility - Set pages visible to host via hvcall.
* *
@ -473,6 +662,7 @@ static int hv_mark_gpa_visibility(u16 count, const u64 pfn[],
struct hv_gpa_range_for_visibility *input; struct hv_gpa_range_for_visibility *input;
u64 hv_status; u64 hv_status;
unsigned long flags; unsigned long flags;
int ret;
/* no-op if partition isolation is not enabled */ /* no-op if partition isolation is not enabled */
if (!hv_is_isolation_supported()) if (!hv_is_isolation_supported())
@ -484,6 +674,13 @@ static int hv_mark_gpa_visibility(u16 count, const u64 pfn[],
return -EINVAL; return -EINVAL;
} }
if (visibility == VMBUS_PAGE_NOT_VISIBLE)
ret = hv_list_enc_remove(pfn, count);
else
ret = hv_list_enc_add(pfn, count);
if (ret)
return ret;
local_irq_save(flags); local_irq_save(flags);
input = *this_cpu_ptr(hyperv_pcpu_input_arg); input = *this_cpu_ptr(hyperv_pcpu_input_arg);
@ -504,8 +701,18 @@ static int hv_mark_gpa_visibility(u16 count, const u64 pfn[],
if (hv_result_success(hv_status)) if (hv_result_success(hv_status))
return 0; return 0;
if (visibility == VMBUS_PAGE_NOT_VISIBLE)
ret = hv_list_enc_add(pfn, count);
else else
return -EFAULT; ret = hv_list_enc_remove(pfn, count);
/*
* There's no good way to recover from -ENOMEM here, the accounting is
* wrong either way.
*/
WARN_ON_ONCE(ret);
return -EFAULT;
} }
/* /*
@ -667,6 +874,8 @@ void __init hv_vtom_init(void)
x86_platform.guest.enc_tlb_flush_required = hv_vtom_tlb_flush_required; x86_platform.guest.enc_tlb_flush_required = hv_vtom_tlb_flush_required;
x86_platform.guest.enc_status_change_prepare = hv_vtom_clear_present; x86_platform.guest.enc_status_change_prepare = hv_vtom_clear_present;
x86_platform.guest.enc_status_change_finish = hv_vtom_set_host_visibility; x86_platform.guest.enc_status_change_finish = hv_vtom_set_host_visibility;
x86_platform.guest.enc_kexec_begin = hv_vtom_kexec_begin;
x86_platform.guest.enc_kexec_finish = hv_vtom_kexec_finish;
/* Set WB as the default cache mode. */ /* Set WB as the default cache mode. */
mtrr_overwrite_state(NULL, 0, MTRR_TYPE_WRBACK); mtrr_overwrite_state(NULL, 0, MTRR_TYPE_WRBACK);

View File

@ -2882,6 +2882,7 @@ void __init sev_set_cpu_caps(void)
void __init sev_hardware_setup(void) void __init sev_hardware_setup(void)
{ {
unsigned int eax, ebx, ecx, edx, sev_asid_count, sev_es_asid_count; unsigned int eax, ebx, ecx, edx, sev_asid_count, sev_es_asid_count;
struct sev_platform_init_args init_args = {0};
bool sev_snp_supported = false; bool sev_snp_supported = false;
bool sev_es_supported = false; bool sev_es_supported = false;
bool sev_supported = false; bool sev_supported = false;
@ -2998,6 +2999,15 @@ out:
sev_supported_vmsa_features = 0; sev_supported_vmsa_features = 0;
if (sev_es_debug_swap_enabled) if (sev_es_debug_swap_enabled)
sev_supported_vmsa_features |= SVM_SEV_FEAT_DEBUG_SWAP; sev_supported_vmsa_features |= SVM_SEV_FEAT_DEBUG_SWAP;
if (!sev_enabled)
return;
/*
* Do both SNP and SEV initialization at KVM module load.
*/
init_args.probe = true;
sev_platform_init(&init_args);
} }
void sev_hardware_unsetup(void) void sev_hardware_unsetup(void)
@ -3013,6 +3023,8 @@ void sev_hardware_unsetup(void)
misc_cg_set_capacity(MISC_CG_RES_SEV, 0); misc_cg_set_capacity(MISC_CG_RES_SEV, 0);
misc_cg_set_capacity(MISC_CG_RES_SEV_ES, 0); misc_cg_set_capacity(MISC_CG_RES_SEV_ES, 0);
sev_platform_shutdown();
} }
int sev_cpu_init(struct svm_cpu_data *sd) int sev_cpu_init(struct svm_cpu_data *sd)

View File

@ -4231,6 +4231,15 @@ CONFIG_PTP_1588_CLOCK_MOCK=m
# CONFIG_PTP_1588_CLOCK_OCP is not set # CONFIG_PTP_1588_CLOCK_OCP is not set
# end of PTP clock support # end of PTP clock support
#
# DPLL device support
#
CONFIG_DPLL=y
CONFIG_ZL3073X=m
CONFIG_ZL3073X_I2C=m
CONFIG_ZL3073X_SPI=m
# end of DPLL device support
CONFIG_PINCTRL=y CONFIG_PINCTRL=y
CONFIG_GENERIC_PINCTRL_GROUPS=y CONFIG_GENERIC_PINCTRL_GROUPS=y
CONFIG_PINMUX=y CONFIG_PINMUX=y
@ -7709,7 +7718,6 @@ CONFIG_INTERCONNECT_IMX8MP=m
# CONFIG_PECI is not set # CONFIG_PECI is not set
# CONFIG_HTE is not set # CONFIG_HTE is not set
# CONFIG_CDX_BUS is not set # CONFIG_CDX_BUS is not set
CONFIG_DPLL=y
# end of Device Drivers # end of Device Drivers
# #

View File

@ -4214,6 +4214,15 @@ CONFIG_PTP_1588_CLOCK_MOCK=m
# CONFIG_PTP_1588_CLOCK_OCP is not set # CONFIG_PTP_1588_CLOCK_OCP is not set
# end of PTP clock support # end of PTP clock support
#
# DPLL device support
#
CONFIG_DPLL=y
CONFIG_ZL3073X=m
CONFIG_ZL3073X_I2C=m
CONFIG_ZL3073X_SPI=m
# end of DPLL device support
CONFIG_PINCTRL=y CONFIG_PINCTRL=y
CONFIG_GENERIC_PINCTRL_GROUPS=y CONFIG_GENERIC_PINCTRL_GROUPS=y
CONFIG_PINMUX=y CONFIG_PINMUX=y
@ -7686,7 +7695,6 @@ CONFIG_INTERCONNECT_IMX8MP=m
# CONFIG_PECI is not set # CONFIG_PECI is not set
# CONFIG_HTE is not set # CONFIG_HTE is not set
# CONFIG_CDX_BUS is not set # CONFIG_CDX_BUS is not set
CONFIG_DPLL=y
# end of Device Drivers # end of Device Drivers
# #

View File

@ -4235,6 +4235,15 @@ CONFIG_PTP_1588_CLOCK_MOCK=m
# CONFIG_PTP_1588_CLOCK_OCP is not set # CONFIG_PTP_1588_CLOCK_OCP is not set
# end of PTP clock support # end of PTP clock support
#
# DPLL device support
#
CONFIG_DPLL=y
CONFIG_ZL3073X=m
CONFIG_ZL3073X_I2C=m
CONFIG_ZL3073X_SPI=m
# end of DPLL device support
CONFIG_PINCTRL=y CONFIG_PINCTRL=y
CONFIG_GENERIC_PINCTRL_GROUPS=y CONFIG_GENERIC_PINCTRL_GROUPS=y
CONFIG_PINMUX=y CONFIG_PINMUX=y
@ -7715,7 +7724,6 @@ CONFIG_INTERCONNECT_IMX8MP=m
# CONFIG_PECI is not set # CONFIG_PECI is not set
# CONFIG_HTE is not set # CONFIG_HTE is not set
# CONFIG_CDX_BUS is not set # CONFIG_CDX_BUS is not set
CONFIG_DPLL=y
# end of Device Drivers # end of Device Drivers
# #

View File

@ -4218,6 +4218,15 @@ CONFIG_PTP_1588_CLOCK_MOCK=m
# CONFIG_PTP_1588_CLOCK_OCP is not set # CONFIG_PTP_1588_CLOCK_OCP is not set
# end of PTP clock support # end of PTP clock support
#
# DPLL device support
#
CONFIG_DPLL=y
CONFIG_ZL3073X=m
CONFIG_ZL3073X_I2C=m
CONFIG_ZL3073X_SPI=m
# end of DPLL device support
CONFIG_PINCTRL=y CONFIG_PINCTRL=y
CONFIG_GENERIC_PINCTRL_GROUPS=y CONFIG_GENERIC_PINCTRL_GROUPS=y
CONFIG_PINMUX=y CONFIG_PINMUX=y
@ -7692,7 +7701,6 @@ CONFIG_INTERCONNECT_IMX8MP=m
# CONFIG_PECI is not set # CONFIG_PECI is not set
# CONFIG_HTE is not set # CONFIG_HTE is not set
# CONFIG_CDX_BUS is not set # CONFIG_CDX_BUS is not set
CONFIG_DPLL=y
# end of Device Drivers # end of Device Drivers
# #

View File

@ -4201,6 +4201,15 @@ CONFIG_PTP_1588_CLOCK_MOCK=m
# CONFIG_PTP_1588_CLOCK_OCP is not set # CONFIG_PTP_1588_CLOCK_OCP is not set
# end of PTP clock support # end of PTP clock support
#
# DPLL device support
#
CONFIG_DPLL=y
CONFIG_ZL3073X=m
CONFIG_ZL3073X_I2C=m
CONFIG_ZL3073X_SPI=m
# end of DPLL device support
CONFIG_PINCTRL=y CONFIG_PINCTRL=y
CONFIG_GENERIC_PINCTRL_GROUPS=y CONFIG_GENERIC_PINCTRL_GROUPS=y
CONFIG_PINMUX=y CONFIG_PINMUX=y
@ -7669,7 +7678,6 @@ CONFIG_INTERCONNECT_IMX8MP=m
# CONFIG_PECI is not set # CONFIG_PECI is not set
# CONFIG_HTE is not set # CONFIG_HTE is not set
# CONFIG_CDX_BUS is not set # CONFIG_CDX_BUS is not set
CONFIG_DPLL=y
# end of Device Drivers # end of Device Drivers
# #

View File

@ -4221,6 +4221,15 @@ CONFIG_PTP_1588_CLOCK_MOCK=m
# CONFIG_PTP_1588_CLOCK_OCP is not set # CONFIG_PTP_1588_CLOCK_OCP is not set
# end of PTP clock support # end of PTP clock support
#
# DPLL device support
#
CONFIG_DPLL=y
CONFIG_ZL3073X=m
CONFIG_ZL3073X_I2C=m
CONFIG_ZL3073X_SPI=m
# end of DPLL device support
CONFIG_PINCTRL=y CONFIG_PINCTRL=y
CONFIG_GENERIC_PINCTRL_GROUPS=y CONFIG_GENERIC_PINCTRL_GROUPS=y
CONFIG_PINMUX=y CONFIG_PINMUX=y
@ -7697,7 +7706,6 @@ CONFIG_INTERCONNECT_IMX8MP=m
# CONFIG_PECI is not set # CONFIG_PECI is not set
# CONFIG_HTE is not set # CONFIG_HTE is not set
# CONFIG_CDX_BUS is not set # CONFIG_CDX_BUS is not set
CONFIG_DPLL=y
# end of Device Drivers # end of Device Drivers
# #

View File

@ -4204,6 +4204,15 @@ CONFIG_PTP_1588_CLOCK_MOCK=m
# CONFIG_PTP_1588_CLOCK_OCP is not set # CONFIG_PTP_1588_CLOCK_OCP is not set
# end of PTP clock support # end of PTP clock support
#
# DPLL device support
#
CONFIG_DPLL=y
CONFIG_ZL3073X=m
CONFIG_ZL3073X_I2C=m
CONFIG_ZL3073X_SPI=m
# end of DPLL device support
CONFIG_PINCTRL=y CONFIG_PINCTRL=y
CONFIG_GENERIC_PINCTRL_GROUPS=y CONFIG_GENERIC_PINCTRL_GROUPS=y
CONFIG_PINMUX=y CONFIG_PINMUX=y
@ -7674,7 +7683,6 @@ CONFIG_INTERCONNECT_IMX8MP=m
# CONFIG_PECI is not set # CONFIG_PECI is not set
# CONFIG_HTE is not set # CONFIG_HTE is not set
# CONFIG_CDX_BUS is not set # CONFIG_CDX_BUS is not set
CONFIG_DPLL=y
# end of Device Drivers # end of Device Drivers
# #

View File

@ -4218,6 +4218,15 @@ CONFIG_PTP_1588_CLOCK_MOCK=m
# CONFIG_PTP_1588_CLOCK_OCP is not set # CONFIG_PTP_1588_CLOCK_OCP is not set
# end of PTP clock support # end of PTP clock support
#
# DPLL device support
#
CONFIG_DPLL=y
CONFIG_ZL3073X=m
CONFIG_ZL3073X_I2C=m
CONFIG_ZL3073X_SPI=m
# end of DPLL device support
CONFIG_PINCTRL=y CONFIG_PINCTRL=y
CONFIG_GENERIC_PINCTRL_GROUPS=y CONFIG_GENERIC_PINCTRL_GROUPS=y
CONFIG_PINMUX=y CONFIG_PINMUX=y
@ -7692,7 +7701,6 @@ CONFIG_INTERCONNECT_IMX8MP=m
# CONFIG_PECI is not set # CONFIG_PECI is not set
# CONFIG_HTE is not set # CONFIG_HTE is not set
# CONFIG_CDX_BUS is not set # CONFIG_CDX_BUS is not set
CONFIG_DPLL=y
# end of Device Drivers # end of Device Drivers
# #

View File

@ -3459,6 +3459,14 @@ CONFIG_PTP_1588_CLOCK_MOCK=m
# CONFIG_PTP_1588_CLOCK_OCP is not set # CONFIG_PTP_1588_CLOCK_OCP is not set
# end of PTP clock support # end of PTP clock support
#
# DPLL device support
#
CONFIG_DPLL=y
CONFIG_ZL3073X=m
CONFIG_ZL3073X_I2C=m
# end of DPLL device support
# CONFIG_PINCTRL is not set # CONFIG_PINCTRL is not set
CONFIG_GPIOLIB=y CONFIG_GPIOLIB=y
CONFIG_GPIOLIB_FASTPATH_LIMIT=512 CONFIG_GPIOLIB_FASTPATH_LIMIT=512
@ -5973,7 +5981,6 @@ CONFIG_INTERCONNECT=y
# CONFIG_MOST is not set # CONFIG_MOST is not set
# CONFIG_PECI is not set # CONFIG_PECI is not set
# CONFIG_HTE is not set # CONFIG_HTE is not set
CONFIG_DPLL=y
# end of Device Drivers # end of Device Drivers
# #

View File

@ -3461,6 +3461,14 @@ CONFIG_PTP_1588_CLOCK_MOCK=m
# CONFIG_PTP_1588_CLOCK_OCP is not set # CONFIG_PTP_1588_CLOCK_OCP is not set
# end of PTP clock support # end of PTP clock support
#
# DPLL device support
#
CONFIG_DPLL=y
CONFIG_ZL3073X=m
CONFIG_ZL3073X_I2C=m
# end of DPLL device support
# CONFIG_PINCTRL is not set # CONFIG_PINCTRL is not set
CONFIG_GPIOLIB=y CONFIG_GPIOLIB=y
CONFIG_GPIOLIB_FASTPATH_LIMIT=512 CONFIG_GPIOLIB_FASTPATH_LIMIT=512
@ -5969,7 +5977,6 @@ CONFIG_INTERCONNECT=y
# CONFIG_MOST is not set # CONFIG_MOST is not set
# CONFIG_PECI is not set # CONFIG_PECI is not set
# CONFIG_HTE is not set # CONFIG_HTE is not set
CONFIG_DPLL=y
# end of Device Drivers # end of Device Drivers
# #

View File

@ -2479,6 +2479,13 @@ CONFIG_PTP_1588_CLOCK_OPTIONAL=y
CONFIG_PTP_1588_CLOCK_MOCK=m CONFIG_PTP_1588_CLOCK_MOCK=m
# end of PTP clock support # end of PTP clock support
#
# DPLL device support
#
CONFIG_DPLL=y
# CONFIG_ZL3073X_I2C is not set
# end of DPLL device support
# CONFIG_PINCTRL is not set # CONFIG_PINCTRL is not set
CONFIG_GPIOLIB=y CONFIG_GPIOLIB=y
CONFIG_GPIOLIB_FASTPATH_LIMIT=512 CONFIG_GPIOLIB_FASTPATH_LIMIT=512
@ -3135,7 +3142,6 @@ CONFIG_INTERCONNECT=y
# CONFIG_MOST is not set # CONFIG_MOST is not set
# CONFIG_PECI is not set # CONFIG_PECI is not set
# CONFIG_HTE is not set # CONFIG_HTE is not set
CONFIG_DPLL=y
# end of Device Drivers # end of Device Drivers
# #

View File

@ -1048,6 +1048,11 @@ CONFIG_PTP_1588_CLOCK_OPTIONAL=y
# CONFIG_PTP_1588_CLOCK_MOCK is not set # CONFIG_PTP_1588_CLOCK_MOCK is not set
# end of PTP clock support # end of PTP clock support
#
# DPLL device support
#
# end of DPLL device support
# CONFIG_PINCTRL is not set # CONFIG_PINCTRL is not set
CONFIG_GPIOLIB=y CONFIG_GPIOLIB=y
CONFIG_GPIOLIB_FASTPATH_LIMIT=512 CONFIG_GPIOLIB_FASTPATH_LIMIT=512

View File

@ -2503,6 +2503,13 @@ CONFIG_PTP_1588_CLOCK_OPTIONAL=y
CONFIG_PTP_1588_CLOCK_MOCK=m CONFIG_PTP_1588_CLOCK_MOCK=m
# end of PTP clock support # end of PTP clock support
#
# DPLL device support
#
CONFIG_DPLL=y
# CONFIG_ZL3073X_I2C is not set
# end of DPLL device support
# CONFIG_PINCTRL is not set # CONFIG_PINCTRL is not set
CONFIG_GPIOLIB=y CONFIG_GPIOLIB=y
CONFIG_GPIOLIB_FASTPATH_LIMIT=512 CONFIG_GPIOLIB_FASTPATH_LIMIT=512
@ -3159,7 +3166,6 @@ CONFIG_INTERCONNECT=y
# CONFIG_MOST is not set # CONFIG_MOST is not set
# CONFIG_PECI is not set # CONFIG_PECI is not set
# CONFIG_HTE is not set # CONFIG_HTE is not set
CONFIG_DPLL=y
# end of Device Drivers # end of Device Drivers
# #

View File

@ -4063,7 +4063,7 @@ CONFIG_I2C_MUX=m
# CONFIG_I2C_MUX_GPIO is not set # CONFIG_I2C_MUX_GPIO is not set
# CONFIG_I2C_MUX_LTC4306 is not set # CONFIG_I2C_MUX_LTC4306 is not set
# CONFIG_I2C_MUX_PCA9541 is not set # CONFIG_I2C_MUX_PCA9541 is not set
# CONFIG_I2C_MUX_PCA954x is not set CONFIG_I2C_MUX_PCA954x=m
# CONFIG_I2C_MUX_REG is not set # CONFIG_I2C_MUX_REG is not set
CONFIG_I2C_MUX_MLXCPLD=m CONFIG_I2C_MUX_MLXCPLD=m
# end of Multiplexer I2C Chip support # end of Multiplexer I2C Chip support
@ -4229,6 +4229,15 @@ CONFIG_PTP_1588_CLOCK_VMW=m
# CONFIG_PTP_1588_CLOCK_OCP is not set # CONFIG_PTP_1588_CLOCK_OCP is not set
# end of PTP clock support # end of PTP clock support
#
# DPLL device support
#
CONFIG_DPLL=y
CONFIG_ZL3073X=m
CONFIG_ZL3073X_I2C=m
CONFIG_ZL3073X_SPI=m
# end of DPLL device support
CONFIG_PINCTRL=y CONFIG_PINCTRL=y
CONFIG_PINMUX=y CONFIG_PINMUX=y
CONFIG_PINCONF=y CONFIG_PINCONF=y
@ -8469,7 +8478,6 @@ CONFIG_INTEL_QEP=m
# CONFIG_MOST is not set # CONFIG_MOST is not set
# CONFIG_PECI is not set # CONFIG_PECI is not set
# CONFIG_HTE is not set # CONFIG_HTE is not set
CONFIG_DPLL=y
# end of Device Drivers # end of Device Drivers
# #

View File

@ -4049,7 +4049,7 @@ CONFIG_I2C_MUX=m
# CONFIG_I2C_MUX_GPIO is not set # CONFIG_I2C_MUX_GPIO is not set
# CONFIG_I2C_MUX_LTC4306 is not set # CONFIG_I2C_MUX_LTC4306 is not set
# CONFIG_I2C_MUX_PCA9541 is not set # CONFIG_I2C_MUX_PCA9541 is not set
# CONFIG_I2C_MUX_PCA954x is not set CONFIG_I2C_MUX_PCA954x=m
# CONFIG_I2C_MUX_REG is not set # CONFIG_I2C_MUX_REG is not set
CONFIG_I2C_MUX_MLXCPLD=m CONFIG_I2C_MUX_MLXCPLD=m
# end of Multiplexer I2C Chip support # end of Multiplexer I2C Chip support
@ -4215,6 +4215,15 @@ CONFIG_PTP_1588_CLOCK_VMW=m
# CONFIG_PTP_1588_CLOCK_OCP is not set # CONFIG_PTP_1588_CLOCK_OCP is not set
# end of PTP clock support # end of PTP clock support
#
# DPLL device support
#
CONFIG_DPLL=y
CONFIG_ZL3073X=m
CONFIG_ZL3073X_I2C=m
CONFIG_ZL3073X_SPI=m
# end of DPLL device support
CONFIG_PINCTRL=y CONFIG_PINCTRL=y
CONFIG_PINMUX=y CONFIG_PINMUX=y
CONFIG_PINCONF=y CONFIG_PINCONF=y
@ -8451,7 +8460,6 @@ CONFIG_INTEL_QEP=m
# CONFIG_MOST is not set # CONFIG_MOST is not set
# CONFIG_PECI is not set # CONFIG_PECI is not set
# CONFIG_HTE is not set # CONFIG_HTE is not set
CONFIG_DPLL=y
# end of Device Drivers # end of Device Drivers
# #

View File

@ -4031,7 +4031,7 @@ CONFIG_I2C_MUX=m
# CONFIG_I2C_MUX_GPIO is not set # CONFIG_I2C_MUX_GPIO is not set
# CONFIG_I2C_MUX_LTC4306 is not set # CONFIG_I2C_MUX_LTC4306 is not set
# CONFIG_I2C_MUX_PCA9541 is not set # CONFIG_I2C_MUX_PCA9541 is not set
# CONFIG_I2C_MUX_PCA954x is not set CONFIG_I2C_MUX_PCA954x=m
# CONFIG_I2C_MUX_REG is not set # CONFIG_I2C_MUX_REG is not set
CONFIG_I2C_MUX_MLXCPLD=m CONFIG_I2C_MUX_MLXCPLD=m
# end of Multiplexer I2C Chip support # end of Multiplexer I2C Chip support
@ -4197,6 +4197,15 @@ CONFIG_PTP_1588_CLOCK_VMW=m
# CONFIG_PTP_1588_CLOCK_OCP is not set # CONFIG_PTP_1588_CLOCK_OCP is not set
# end of PTP clock support # end of PTP clock support
#
# DPLL device support
#
CONFIG_DPLL=y
CONFIG_ZL3073X=m
CONFIG_ZL3073X_I2C=m
CONFIG_ZL3073X_SPI=m
# end of DPLL device support
CONFIG_PINCTRL=y CONFIG_PINCTRL=y
CONFIG_PINMUX=y CONFIG_PINMUX=y
CONFIG_PINCONF=y CONFIG_PINCONF=y
@ -8422,7 +8431,6 @@ CONFIG_INTEL_QEP=m
# CONFIG_MOST is not set # CONFIG_MOST is not set
# CONFIG_PECI is not set # CONFIG_PECI is not set
# CONFIG_HTE is not set # CONFIG_HTE is not set
CONFIG_DPLL=y
# end of Device Drivers # end of Device Drivers
# #

View File

@ -4045,7 +4045,7 @@ CONFIG_I2C_MUX=m
# CONFIG_I2C_MUX_GPIO is not set # CONFIG_I2C_MUX_GPIO is not set
# CONFIG_I2C_MUX_LTC4306 is not set # CONFIG_I2C_MUX_LTC4306 is not set
# CONFIG_I2C_MUX_PCA9541 is not set # CONFIG_I2C_MUX_PCA9541 is not set
# CONFIG_I2C_MUX_PCA954x is not set CONFIG_I2C_MUX_PCA954x=m
# CONFIG_I2C_MUX_REG is not set # CONFIG_I2C_MUX_REG is not set
CONFIG_I2C_MUX_MLXCPLD=m CONFIG_I2C_MUX_MLXCPLD=m
# end of Multiplexer I2C Chip support # end of Multiplexer I2C Chip support
@ -4211,6 +4211,15 @@ CONFIG_PTP_1588_CLOCK_VMW=m
# CONFIG_PTP_1588_CLOCK_OCP is not set # CONFIG_PTP_1588_CLOCK_OCP is not set
# end of PTP clock support # end of PTP clock support
#
# DPLL device support
#
CONFIG_DPLL=y
CONFIG_ZL3073X=m
CONFIG_ZL3073X_I2C=m
CONFIG_ZL3073X_SPI=m
# end of DPLL device support
CONFIG_PINCTRL=y CONFIG_PINCTRL=y
CONFIG_PINMUX=y CONFIG_PINMUX=y
CONFIG_PINCONF=y CONFIG_PINCONF=y
@ -8440,7 +8449,6 @@ CONFIG_INTEL_QEP=m
# CONFIG_MOST is not set # CONFIG_MOST is not set
# CONFIG_PECI is not set # CONFIG_PECI is not set
# CONFIG_HTE is not set # CONFIG_HTE is not set
CONFIG_DPLL=y
# end of Device Drivers # end of Device Drivers
# #

View File

@ -4063,7 +4063,7 @@ CONFIG_I2C_MUX=m
# CONFIG_I2C_MUX_GPIO is not set # CONFIG_I2C_MUX_GPIO is not set
# CONFIG_I2C_MUX_LTC4306 is not set # CONFIG_I2C_MUX_LTC4306 is not set
# CONFIG_I2C_MUX_PCA9541 is not set # CONFIG_I2C_MUX_PCA9541 is not set
# CONFIG_I2C_MUX_PCA954x is not set CONFIG_I2C_MUX_PCA954x=m
# CONFIG_I2C_MUX_REG is not set # CONFIG_I2C_MUX_REG is not set
CONFIG_I2C_MUX_MLXCPLD=m CONFIG_I2C_MUX_MLXCPLD=m
# end of Multiplexer I2C Chip support # end of Multiplexer I2C Chip support
@ -4229,6 +4229,15 @@ CONFIG_PTP_1588_CLOCK_VMW=m
# CONFIG_PTP_1588_CLOCK_OCP is not set # CONFIG_PTP_1588_CLOCK_OCP is not set
# end of PTP clock support # end of PTP clock support
#
# DPLL device support
#
CONFIG_DPLL=y
CONFIG_ZL3073X=m
CONFIG_ZL3073X_I2C=m
CONFIG_ZL3073X_SPI=m
# end of DPLL device support
CONFIG_PINCTRL=y CONFIG_PINCTRL=y
CONFIG_PINMUX=y CONFIG_PINMUX=y
CONFIG_PINCONF=y CONFIG_PINCONF=y
@ -8469,7 +8478,6 @@ CONFIG_INTEL_QEP=m
# CONFIG_MOST is not set # CONFIG_MOST is not set
# CONFIG_PECI is not set # CONFIG_PECI is not set
# CONFIG_HTE is not set # CONFIG_HTE is not set
CONFIG_DPLL=y
# end of Device Drivers # end of Device Drivers
# #

View File

@ -4049,7 +4049,7 @@ CONFIG_I2C_MUX=m
# CONFIG_I2C_MUX_GPIO is not set # CONFIG_I2C_MUX_GPIO is not set
# CONFIG_I2C_MUX_LTC4306 is not set # CONFIG_I2C_MUX_LTC4306 is not set
# CONFIG_I2C_MUX_PCA9541 is not set # CONFIG_I2C_MUX_PCA9541 is not set
# CONFIG_I2C_MUX_PCA954x is not set CONFIG_I2C_MUX_PCA954x=m
# CONFIG_I2C_MUX_REG is not set # CONFIG_I2C_MUX_REG is not set
CONFIG_I2C_MUX_MLXCPLD=m CONFIG_I2C_MUX_MLXCPLD=m
# end of Multiplexer I2C Chip support # end of Multiplexer I2C Chip support
@ -4215,6 +4215,15 @@ CONFIG_PTP_1588_CLOCK_VMW=m
# CONFIG_PTP_1588_CLOCK_OCP is not set # CONFIG_PTP_1588_CLOCK_OCP is not set
# end of PTP clock support # end of PTP clock support
#
# DPLL device support
#
CONFIG_DPLL=y
CONFIG_ZL3073X=m
CONFIG_ZL3073X_I2C=m
CONFIG_ZL3073X_SPI=m
# end of DPLL device support
CONFIG_PINCTRL=y CONFIG_PINCTRL=y
CONFIG_PINMUX=y CONFIG_PINMUX=y
CONFIG_PINCONF=y CONFIG_PINCONF=y
@ -8451,7 +8460,6 @@ CONFIG_INTEL_QEP=m
# CONFIG_MOST is not set # CONFIG_MOST is not set
# CONFIG_PECI is not set # CONFIG_PECI is not set
# CONFIG_HTE is not set # CONFIG_HTE is not set
CONFIG_DPLL=y
# end of Device Drivers # end of Device Drivers
# #

View File

@ -4031,7 +4031,7 @@ CONFIG_I2C_MUX=m
# CONFIG_I2C_MUX_GPIO is not set # CONFIG_I2C_MUX_GPIO is not set
# CONFIG_I2C_MUX_LTC4306 is not set # CONFIG_I2C_MUX_LTC4306 is not set
# CONFIG_I2C_MUX_PCA9541 is not set # CONFIG_I2C_MUX_PCA9541 is not set
# CONFIG_I2C_MUX_PCA954x is not set CONFIG_I2C_MUX_PCA954x=m
# CONFIG_I2C_MUX_REG is not set # CONFIG_I2C_MUX_REG is not set
CONFIG_I2C_MUX_MLXCPLD=m CONFIG_I2C_MUX_MLXCPLD=m
# end of Multiplexer I2C Chip support # end of Multiplexer I2C Chip support
@ -4197,6 +4197,15 @@ CONFIG_PTP_1588_CLOCK_VMW=m
# CONFIG_PTP_1588_CLOCK_OCP is not set # CONFIG_PTP_1588_CLOCK_OCP is not set
# end of PTP clock support # end of PTP clock support
#
# DPLL device support
#
CONFIG_DPLL=y
CONFIG_ZL3073X=m
CONFIG_ZL3073X_I2C=m
CONFIG_ZL3073X_SPI=m
# end of DPLL device support
CONFIG_PINCTRL=y CONFIG_PINCTRL=y
CONFIG_PINMUX=y CONFIG_PINMUX=y
CONFIG_PINCONF=y CONFIG_PINCONF=y
@ -8422,7 +8431,6 @@ CONFIG_INTEL_QEP=m
# CONFIG_MOST is not set # CONFIG_MOST is not set
# CONFIG_PECI is not set # CONFIG_PECI is not set
# CONFIG_HTE is not set # CONFIG_HTE is not set
CONFIG_DPLL=y
# end of Device Drivers # end of Device Drivers
# #

View File

@ -4045,7 +4045,7 @@ CONFIG_I2C_MUX=m
# CONFIG_I2C_MUX_GPIO is not set # CONFIG_I2C_MUX_GPIO is not set
# CONFIG_I2C_MUX_LTC4306 is not set # CONFIG_I2C_MUX_LTC4306 is not set
# CONFIG_I2C_MUX_PCA9541 is not set # CONFIG_I2C_MUX_PCA9541 is not set
# CONFIG_I2C_MUX_PCA954x is not set CONFIG_I2C_MUX_PCA954x=m
# CONFIG_I2C_MUX_REG is not set # CONFIG_I2C_MUX_REG is not set
CONFIG_I2C_MUX_MLXCPLD=m CONFIG_I2C_MUX_MLXCPLD=m
# end of Multiplexer I2C Chip support # end of Multiplexer I2C Chip support
@ -4211,6 +4211,15 @@ CONFIG_PTP_1588_CLOCK_VMW=m
# CONFIG_PTP_1588_CLOCK_OCP is not set # CONFIG_PTP_1588_CLOCK_OCP is not set
# end of PTP clock support # end of PTP clock support
#
# DPLL device support
#
CONFIG_DPLL=y
CONFIG_ZL3073X=m
CONFIG_ZL3073X_I2C=m
CONFIG_ZL3073X_SPI=m
# end of DPLL device support
CONFIG_PINCTRL=y CONFIG_PINCTRL=y
CONFIG_PINMUX=y CONFIG_PINMUX=y
CONFIG_PINCONF=y CONFIG_PINCONF=y
@ -8440,7 +8449,6 @@ CONFIG_INTEL_QEP=m
# CONFIG_MOST is not set # CONFIG_MOST is not set
# CONFIG_PECI is not set # CONFIG_PECI is not set
# CONFIG_HTE is not set # CONFIG_HTE is not set
CONFIG_DPLL=y
# end of Device Drivers # end of Device Drivers
# #

View File

@ -77,6 +77,8 @@ source "drivers/pps/Kconfig"
source "drivers/ptp/Kconfig" source "drivers/ptp/Kconfig"
source "drivers/dpll/Kconfig"
source "drivers/pinctrl/Kconfig" source "drivers/pinctrl/Kconfig"
source "drivers/gpio/Kconfig" source "drivers/gpio/Kconfig"
@ -245,6 +247,4 @@ source "drivers/hte/Kconfig"
source "drivers/cdx/Kconfig" source "drivers/cdx/Kconfig"
source "drivers/dpll/Kconfig"
endmenu endmenu

View File

@ -109,6 +109,15 @@ static void *sev_init_ex_buffer;
*/ */
static struct sev_data_range_list *snp_range_list; static struct sev_data_range_list *snp_range_list;
static void __sev_firmware_shutdown(struct sev_device *sev, bool panic);
static int snp_shutdown_on_panic(struct notifier_block *nb,
unsigned long reason, void *arg);
static struct notifier_block snp_panic_notifier = {
.notifier_call = snp_shutdown_on_panic,
};
static inline bool sev_version_greater_or_equal(u8 maj, u8 min) static inline bool sev_version_greater_or_equal(u8 maj, u8 min)
{ {
struct sev_device *sev = psp_master->sev_data; struct sev_device *sev = psp_master->sev_data;
@ -1112,7 +1121,7 @@ static int __sev_snp_init_locked(int *error)
if (!sev_version_greater_or_equal(SNP_MIN_API_MAJOR, SNP_MIN_API_MINOR)) { if (!sev_version_greater_or_equal(SNP_MIN_API_MAJOR, SNP_MIN_API_MINOR)) {
dev_dbg(sev->dev, "SEV-SNP support requires firmware version >= %d:%d\n", dev_dbg(sev->dev, "SEV-SNP support requires firmware version >= %d:%d\n",
SNP_MIN_API_MAJOR, SNP_MIN_API_MINOR); SNP_MIN_API_MAJOR, SNP_MIN_API_MINOR);
return 0; return -EOPNOTSUPP;
} }
/* SNP_INIT requires MSR_VM_HSAVE_PA to be cleared on all CPUs. */ /* SNP_INIT requires MSR_VM_HSAVE_PA to be cleared on all CPUs. */
@ -1176,21 +1185,34 @@ static int __sev_snp_init_locked(int *error)
wbinvd_on_all_cpus(); wbinvd_on_all_cpus();
rc = __sev_do_cmd_locked(cmd, arg, error); rc = __sev_do_cmd_locked(cmd, arg, error);
if (rc) if (rc) {
dev_err(sev->dev, "SEV-SNP: %s failed rc %d, error %#x\n",
cmd == SEV_CMD_SNP_INIT_EX ? "SNP_INIT_EX" : "SNP_INIT",
rc, *error);
return rc; return rc;
}
/* Prepare for first SNP guest launch after INIT. */ /* Prepare for first SNP guest launch after INIT. */
wbinvd_on_all_cpus(); wbinvd_on_all_cpus();
rc = __sev_do_cmd_locked(SEV_CMD_SNP_DF_FLUSH, NULL, error); rc = __sev_do_cmd_locked(SEV_CMD_SNP_DF_FLUSH, NULL, error);
if (rc) if (rc) {
dev_err(sev->dev, "SEV-SNP: SNP_DF_FLUSH failed rc %d, error %#x\n",
rc, *error);
return rc; return rc;
}
sev->snp_initialized = true; sev->snp_initialized = true;
dev_dbg(sev->dev, "SEV-SNP firmware initialized\n"); dev_dbg(sev->dev, "SEV-SNP firmware initialized\n");
dev_info(sev->dev, "SEV-SNP API:%d.%d build:%d\n", sev->api_major,
sev->api_minor, sev->build);
atomic_notifier_chain_register(&panic_notifier_list,
&snp_panic_notifier);
sev_es_tmr_size = SNP_TMR_SIZE; sev_es_tmr_size = SNP_TMR_SIZE;
return rc; return 0;
} }
static void __sev_platform_init_handle_tmr(struct sev_device *sev) static void __sev_platform_init_handle_tmr(struct sev_device *sev)
@ -1253,9 +1275,11 @@ static int __sev_platform_init_handle_init_ex_path(struct sev_device *sev)
static int __sev_platform_init_locked(int *error) static int __sev_platform_init_locked(int *error)
{ {
int rc, psp_ret = SEV_RET_NO_FW_CALL; int rc, psp_ret, dfflush_error;
struct sev_device *sev; struct sev_device *sev;
psp_ret = dfflush_error = SEV_RET_NO_FW_CALL;
if (!psp_master || !psp_master->sev_data) if (!psp_master || !psp_master->sev_data)
return -ENODEV; return -ENODEV;
@ -1287,16 +1311,22 @@ static int __sev_platform_init_locked(int *error)
if (error) if (error)
*error = psp_ret; *error = psp_ret;
if (rc) if (rc) {
dev_err(sev->dev, "SEV: %s failed %#x, rc %d\n",
sev_init_ex_buffer ? "INIT_EX" : "INIT", psp_ret, rc);
return rc; return rc;
}
sev->state = SEV_STATE_INIT; sev->state = SEV_STATE_INIT;
/* Prepare for first SEV guest launch after INIT */ /* Prepare for first SEV guest launch after INIT */
wbinvd_on_all_cpus(); wbinvd_on_all_cpus();
rc = __sev_do_cmd_locked(SEV_CMD_DF_FLUSH, NULL, error); rc = __sev_do_cmd_locked(SEV_CMD_DF_FLUSH, NULL, &dfflush_error);
if (rc) if (rc) {
dev_err(sev->dev, "SEV: DF_FLUSH failed %#x, rc %d\n",
dfflush_error, rc);
return rc; return rc;
}
dev_dbg(sev->dev, "SEV firmware initialized\n"); dev_dbg(sev->dev, "SEV firmware initialized\n");
@ -1319,19 +1349,9 @@ static int _sev_platform_init_locked(struct sev_platform_init_args *args)
if (sev->state == SEV_STATE_INIT) if (sev->state == SEV_STATE_INIT)
return 0; return 0;
/*
* Legacy guests cannot be running while SNP_INIT(_EX) is executing,
* so perform SEV-SNP initialization at probe time.
*/
rc = __sev_snp_init_locked(&args->error); rc = __sev_snp_init_locked(&args->error);
if (rc && rc != -ENODEV) { if (rc && rc != -ENODEV)
/* return rc;
* Don't abort the probe if SNP INIT failed,
* continue to initialize the legacy SEV firmware.
*/
dev_err(sev->dev, "SEV-SNP: failed to INIT rc %d, error %#x\n",
rc, args->error);
}
/* Defer legacy SEV/SEV-ES support if allowed by caller/module. */ /* Defer legacy SEV/SEV-ES support if allowed by caller/module. */
if (args->probe && !psp_init_on_probe) if (args->probe && !psp_init_on_probe)
@ -1367,8 +1387,11 @@ static int __sev_platform_shutdown_locked(int *error)
return 0; return 0;
ret = __sev_do_cmd_locked(SEV_CMD_SHUTDOWN, NULL, error); ret = __sev_do_cmd_locked(SEV_CMD_SHUTDOWN, NULL, error);
if (ret) if (ret) {
dev_err(sev->dev, "SEV: failed to SHUTDOWN error %#x, rc %d\n",
*error, ret);
return ret; return ret;
}
sev->state = SEV_STATE_UNINIT; sev->state = SEV_STATE_UNINIT;
dev_dbg(sev->dev, "SEV firmware shutdown\n"); dev_dbg(sev->dev, "SEV firmware shutdown\n");
@ -1389,6 +1412,37 @@ static int sev_get_platform_state(int *state, int *error)
return rc; return rc;
} }
static int sev_move_to_init_state(struct sev_issue_cmd *argp, bool *shutdown_required)
{
struct sev_platform_init_args init_args = {0};
int rc;
rc = _sev_platform_init_locked(&init_args);
if (rc) {
argp->error = SEV_RET_INVALID_PLATFORM_STATE;
return rc;
}
*shutdown_required = true;
return 0;
}
static int snp_move_to_init_state(struct sev_issue_cmd *argp, bool *shutdown_required)
{
int error, rc;
rc = __sev_snp_init_locked(&error);
if (rc) {
argp->error = SEV_RET_INVALID_PLATFORM_STATE;
return rc;
}
*shutdown_required = true;
return 0;
}
static int sev_ioctl_do_reset(struct sev_issue_cmd *argp, bool writable) static int sev_ioctl_do_reset(struct sev_issue_cmd *argp, bool writable)
{ {
int state, rc; int state, rc;
@ -1441,24 +1495,31 @@ static int sev_ioctl_do_platform_status(struct sev_issue_cmd *argp)
static int sev_ioctl_do_pek_pdh_gen(int cmd, struct sev_issue_cmd *argp, bool writable) static int sev_ioctl_do_pek_pdh_gen(int cmd, struct sev_issue_cmd *argp, bool writable)
{ {
struct sev_device *sev = psp_master->sev_data; struct sev_device *sev = psp_master->sev_data;
bool shutdown_required = false;
int rc; int rc;
if (!writable) if (!writable)
return -EPERM; return -EPERM;
if (sev->state == SEV_STATE_UNINIT) { if (sev->state == SEV_STATE_UNINIT) {
rc = __sev_platform_init_locked(&argp->error); rc = sev_move_to_init_state(argp, &shutdown_required);
if (rc) if (rc)
return rc; return rc;
} }
return __sev_do_cmd_locked(cmd, NULL, &argp->error); rc = __sev_do_cmd_locked(cmd, NULL, &argp->error);
if (shutdown_required)
__sev_firmware_shutdown(sev, false);
return rc;
} }
static int sev_ioctl_do_pek_csr(struct sev_issue_cmd *argp, bool writable) static int sev_ioctl_do_pek_csr(struct sev_issue_cmd *argp, bool writable)
{ {
struct sev_device *sev = psp_master->sev_data; struct sev_device *sev = psp_master->sev_data;
struct sev_user_data_pek_csr input; struct sev_user_data_pek_csr input;
bool shutdown_required = false;
struct sev_data_pek_csr data; struct sev_data_pek_csr data;
void __user *input_address; void __user *input_address;
void *blob = NULL; void *blob = NULL;
@ -1490,7 +1551,7 @@ static int sev_ioctl_do_pek_csr(struct sev_issue_cmd *argp, bool writable)
cmd: cmd:
if (sev->state == SEV_STATE_UNINIT) { if (sev->state == SEV_STATE_UNINIT) {
ret = __sev_platform_init_locked(&argp->error); ret = sev_move_to_init_state(argp, &shutdown_required);
if (ret) if (ret)
goto e_free_blob; goto e_free_blob;
} }
@ -1511,6 +1572,9 @@ cmd:
} }
e_free_blob: e_free_blob:
if (shutdown_required)
__sev_firmware_shutdown(sev, false);
kfree(blob); kfree(blob);
return ret; return ret;
} }
@ -1682,9 +1746,12 @@ static int __sev_snp_shutdown_locked(int *error, bool panic)
ret = __sev_do_cmd_locked(SEV_CMD_SNP_SHUTDOWN_EX, &data, error); ret = __sev_do_cmd_locked(SEV_CMD_SNP_SHUTDOWN_EX, &data, error);
/* SHUTDOWN may require DF_FLUSH */ /* SHUTDOWN may require DF_FLUSH */
if (*error == SEV_RET_DFFLUSH_REQUIRED) { if (*error == SEV_RET_DFFLUSH_REQUIRED) {
ret = __sev_do_cmd_locked(SEV_CMD_SNP_DF_FLUSH, NULL, NULL); int dfflush_error = SEV_RET_NO_FW_CALL;
ret = __sev_do_cmd_locked(SEV_CMD_SNP_DF_FLUSH, NULL, &dfflush_error);
if (ret) { if (ret) {
dev_err(sev->dev, "SEV-SNP DF_FLUSH failed\n"); dev_err(sev->dev, "SEV-SNP DF_FLUSH failed, ret = %d, error = %#x\n",
ret, dfflush_error);
return ret; return ret;
} }
/* reissue the shutdown command */ /* reissue the shutdown command */
@ -1692,7 +1759,8 @@ static int __sev_snp_shutdown_locked(int *error, bool panic)
error); error);
} }
if (ret) { if (ret) {
dev_err(sev->dev, "SEV-SNP firmware shutdown failed\n"); dev_err(sev->dev, "SEV-SNP firmware shutdown failed, rc %d, error %#x\n",
ret, *error);
return ret; return ret;
} }
@ -1718,6 +1786,18 @@ static int __sev_snp_shutdown_locked(int *error, bool panic)
sev->snp_initialized = false; sev->snp_initialized = false;
dev_dbg(sev->dev, "SEV-SNP firmware shutdown\n"); dev_dbg(sev->dev, "SEV-SNP firmware shutdown\n");
/*
* __sev_snp_shutdown_locked() deadlocks when it tries to unregister
* itself during panic as the panic notifier is called with RCU read
* lock held and notifier unregistration does RCU synchronization.
*/
if (!panic)
atomic_notifier_chain_unregister(&panic_notifier_list,
&snp_panic_notifier);
/* Reset TMR size back to default */
sev_es_tmr_size = SEV_TMR_SIZE;
return ret; return ret;
} }
@ -1726,6 +1806,7 @@ static int sev_ioctl_do_pek_import(struct sev_issue_cmd *argp, bool writable)
struct sev_device *sev = psp_master->sev_data; struct sev_device *sev = psp_master->sev_data;
struct sev_user_data_pek_cert_import input; struct sev_user_data_pek_cert_import input;
struct sev_data_pek_cert_import data; struct sev_data_pek_cert_import data;
bool shutdown_required = false;
void *pek_blob, *oca_blob; void *pek_blob, *oca_blob;
int ret; int ret;
@ -1756,7 +1837,7 @@ static int sev_ioctl_do_pek_import(struct sev_issue_cmd *argp, bool writable)
/* If platform is not in INIT state then transition it to INIT */ /* If platform is not in INIT state then transition it to INIT */
if (sev->state != SEV_STATE_INIT) { if (sev->state != SEV_STATE_INIT) {
ret = __sev_platform_init_locked(&argp->error); ret = sev_move_to_init_state(argp, &shutdown_required);
if (ret) if (ret)
goto e_free_oca; goto e_free_oca;
} }
@ -1764,6 +1845,9 @@ static int sev_ioctl_do_pek_import(struct sev_issue_cmd *argp, bool writable)
ret = __sev_do_cmd_locked(SEV_CMD_PEK_CERT_IMPORT, &data, &argp->error); ret = __sev_do_cmd_locked(SEV_CMD_PEK_CERT_IMPORT, &data, &argp->error);
e_free_oca: e_free_oca:
if (shutdown_required)
__sev_firmware_shutdown(sev, false);
kfree(oca_blob); kfree(oca_blob);
e_free_pek: e_free_pek:
kfree(pek_blob); kfree(pek_blob);
@ -1880,18 +1964,9 @@ static int sev_ioctl_do_pdh_export(struct sev_issue_cmd *argp, bool writable)
struct sev_data_pdh_cert_export data; struct sev_data_pdh_cert_export data;
void __user *input_cert_chain_address; void __user *input_cert_chain_address;
void __user *input_pdh_cert_address; void __user *input_pdh_cert_address;
bool shutdown_required = false;
int ret; int ret;
/* If platform is not in INIT state then transition it to INIT. */
if (sev->state != SEV_STATE_INIT) {
if (!writable)
return -EPERM;
ret = __sev_platform_init_locked(&argp->error);
if (ret)
return ret;
}
if (copy_from_user(&input, (void __user *)argp->data, sizeof(input))) if (copy_from_user(&input, (void __user *)argp->data, sizeof(input)))
return -EFAULT; return -EFAULT;
@ -1931,6 +2006,17 @@ static int sev_ioctl_do_pdh_export(struct sev_issue_cmd *argp, bool writable)
data.cert_chain_len = input.cert_chain_len; data.cert_chain_len = input.cert_chain_len;
cmd: cmd:
/* If platform is not in INIT state then transition it to INIT. */
if (sev->state != SEV_STATE_INIT) {
if (!writable) {
ret = -EPERM;
goto e_free_cert;
}
ret = sev_move_to_init_state(argp, &shutdown_required);
if (ret)
goto e_free_cert;
}
ret = __sev_do_cmd_locked(SEV_CMD_PDH_CERT_EXPORT, &data, &argp->error); ret = __sev_do_cmd_locked(SEV_CMD_PDH_CERT_EXPORT, &data, &argp->error);
/* If we query the length, FW responded with expected data. */ /* If we query the length, FW responded with expected data. */
@ -1957,6 +2043,9 @@ cmd:
} }
e_free_cert: e_free_cert:
if (shutdown_required)
__sev_firmware_shutdown(sev, false);
kfree(cert_blob); kfree(cert_blob);
e_free_pdh: e_free_pdh:
kfree(pdh_blob); kfree(pdh_blob);
@ -1966,12 +2055,13 @@ e_free_pdh:
static int sev_ioctl_do_snp_platform_status(struct sev_issue_cmd *argp) static int sev_ioctl_do_snp_platform_status(struct sev_issue_cmd *argp)
{ {
struct sev_device *sev = psp_master->sev_data; struct sev_device *sev = psp_master->sev_data;
bool shutdown_required = false;
struct sev_data_snp_addr buf; struct sev_data_snp_addr buf;
struct page *status_page; struct page *status_page;
int ret, error;
void *data; void *data;
int ret;
if (!sev->snp_initialized || !argp->data) if (!argp->data)
return -EINVAL; return -EINVAL;
status_page = alloc_page(GFP_KERNEL_ACCOUNT); status_page = alloc_page(GFP_KERNEL_ACCOUNT);
@ -1980,6 +2070,12 @@ static int sev_ioctl_do_snp_platform_status(struct sev_issue_cmd *argp)
data = page_address(status_page); data = page_address(status_page);
if (!sev->snp_initialized) {
ret = snp_move_to_init_state(argp, &shutdown_required);
if (ret)
goto cleanup;
}
/* /*
* Firmware expects status page to be in firmware-owned state, otherwise * Firmware expects status page to be in firmware-owned state, otherwise
* it will report firmware error code INVALID_PAGE_STATE (0x1A). * it will report firmware error code INVALID_PAGE_STATE (0x1A).
@ -2008,6 +2104,9 @@ static int sev_ioctl_do_snp_platform_status(struct sev_issue_cmd *argp)
ret = -EFAULT; ret = -EFAULT;
cleanup: cleanup:
if (shutdown_required)
__sev_snp_shutdown_locked(&error, false);
__free_pages(status_page, 0); __free_pages(status_page, 0);
return ret; return ret;
} }
@ -2016,21 +2115,33 @@ static int sev_ioctl_do_snp_commit(struct sev_issue_cmd *argp)
{ {
struct sev_device *sev = psp_master->sev_data; struct sev_device *sev = psp_master->sev_data;
struct sev_data_snp_commit buf; struct sev_data_snp_commit buf;
bool shutdown_required = false;
int ret, error;
if (!sev->snp_initialized) if (!sev->snp_initialized) {
return -EINVAL; ret = snp_move_to_init_state(argp, &shutdown_required);
if (ret)
return ret;
}
buf.len = sizeof(buf); buf.len = sizeof(buf);
return __sev_do_cmd_locked(SEV_CMD_SNP_COMMIT, &buf, &argp->error); ret = __sev_do_cmd_locked(SEV_CMD_SNP_COMMIT, &buf, &argp->error);
if (shutdown_required)
__sev_snp_shutdown_locked(&error, false);
return ret;
} }
static int sev_ioctl_do_snp_set_config(struct sev_issue_cmd *argp, bool writable) static int sev_ioctl_do_snp_set_config(struct sev_issue_cmd *argp, bool writable)
{ {
struct sev_device *sev = psp_master->sev_data; struct sev_device *sev = psp_master->sev_data;
struct sev_user_data_snp_config config; struct sev_user_data_snp_config config;
bool shutdown_required = false;
int ret, error;
if (!sev->snp_initialized || !argp->data) if (!argp->data)
return -EINVAL; return -EINVAL;
if (!writable) if (!writable)
@ -2039,17 +2150,29 @@ static int sev_ioctl_do_snp_set_config(struct sev_issue_cmd *argp, bool writable
if (copy_from_user(&config, (void __user *)argp->data, sizeof(config))) if (copy_from_user(&config, (void __user *)argp->data, sizeof(config)))
return -EFAULT; return -EFAULT;
return __sev_do_cmd_locked(SEV_CMD_SNP_CONFIG, &config, &argp->error); if (!sev->snp_initialized) {
ret = snp_move_to_init_state(argp, &shutdown_required);
if (ret)
return ret;
}
ret = __sev_do_cmd_locked(SEV_CMD_SNP_CONFIG, &config, &argp->error);
if (shutdown_required)
__sev_snp_shutdown_locked(&error, false);
return ret;
} }
static int sev_ioctl_do_snp_vlek_load(struct sev_issue_cmd *argp, bool writable) static int sev_ioctl_do_snp_vlek_load(struct sev_issue_cmd *argp, bool writable)
{ {
struct sev_device *sev = psp_master->sev_data; struct sev_device *sev = psp_master->sev_data;
struct sev_user_data_snp_vlek_load input; struct sev_user_data_snp_vlek_load input;
bool shutdown_required = false;
int ret, error;
void *blob; void *blob;
int ret;
if (!sev->snp_initialized || !argp->data) if (!argp->data)
return -EINVAL; return -EINVAL;
if (!writable) if (!writable)
@ -2068,8 +2191,18 @@ static int sev_ioctl_do_snp_vlek_load(struct sev_issue_cmd *argp, bool writable)
input.vlek_wrapped_address = __psp_pa(blob); input.vlek_wrapped_address = __psp_pa(blob);
if (!sev->snp_initialized) {
ret = snp_move_to_init_state(argp, &shutdown_required);
if (ret)
goto cleanup;
}
ret = __sev_do_cmd_locked(SEV_CMD_SNP_VLEK_LOAD, &input, &argp->error); ret = __sev_do_cmd_locked(SEV_CMD_SNP_VLEK_LOAD, &input, &argp->error);
if (shutdown_required)
__sev_snp_shutdown_locked(&error, false);
cleanup:
kfree(blob); kfree(blob);
return ret; return ret;
@ -2296,7 +2429,7 @@ static void __sev_firmware_shutdown(struct sev_device *sev, bool panic)
{ {
int error; int error;
__sev_platform_shutdown_locked(NULL); __sev_platform_shutdown_locked(&error);
if (sev_es_tmr) { if (sev_es_tmr) {
/* /*
@ -2339,6 +2472,15 @@ static void sev_firmware_shutdown(struct sev_device *sev)
mutex_unlock(&sev_cmd_mutex); mutex_unlock(&sev_cmd_mutex);
} }
void sev_platform_shutdown(void)
{
if (!psp_master || !psp_master->sev_data)
return;
sev_firmware_shutdown(psp_master->sev_data);
}
EXPORT_SYMBOL_GPL(sev_platform_shutdown);
void sev_dev_destroy(struct psp_device *psp) void sev_dev_destroy(struct psp_device *psp)
{ {
struct sev_device *sev = psp->sev_data; struct sev_device *sev = psp->sev_data;
@ -2373,10 +2515,6 @@ static int snp_shutdown_on_panic(struct notifier_block *nb,
return NOTIFY_DONE; return NOTIFY_DONE;
} }
static struct notifier_block snp_panic_notifier = {
.notifier_call = snp_shutdown_on_panic,
};
int sev_issue_cmd_external_user(struct file *filep, unsigned int cmd, int sev_issue_cmd_external_user(struct file *filep, unsigned int cmd,
void *data, int *error) void *data, int *error)
{ {
@ -2390,9 +2528,7 @@ EXPORT_SYMBOL_GPL(sev_issue_cmd_external_user);
void sev_pci_init(void) void sev_pci_init(void)
{ {
struct sev_device *sev = psp_master->sev_data; struct sev_device *sev = psp_master->sev_data;
struct sev_platform_init_args args = {0};
u8 api_major, api_minor, build; u8 api_major, api_minor, build;
int rc;
if (!sev) if (!sev)
return; return;
@ -2415,18 +2551,6 @@ void sev_pci_init(void)
api_major, api_minor, build, api_major, api_minor, build,
sev->api_major, sev->api_minor, sev->build); sev->api_major, sev->api_minor, sev->build);
/* Initialize the platform */
args.probe = true;
rc = sev_platform_init(&args);
if (rc)
dev_err(sev->dev, "SEV: failed to INIT error %#x, rc %d\n",
args.error, rc);
dev_info(sev->dev, "SEV%s API:%d.%d build:%d\n", sev->snp_initialized ?
"-SNP" : "", sev->api_major, sev->api_minor, sev->build);
atomic_notifier_chain_register(&panic_notifier_list,
&snp_panic_notifier);
return; return;
err: err:
@ -2443,7 +2567,4 @@ void sev_pci_exit(void)
return; return;
sev_firmware_shutdown(sev); sev_firmware_shutdown(sev);
atomic_notifier_chain_unregister(&panic_notifier_list,
&snp_panic_notifier);
} }

View File

@ -3,5 +3,11 @@
# Generic DPLL drivers configuration # Generic DPLL drivers configuration
# #
menu "DPLL device support"
config DPLL config DPLL
bool bool
source "drivers/dpll/zl3073x/Kconfig"
endmenu

View File

@ -7,3 +7,5 @@ obj-$(CONFIG_DPLL) += dpll.o
dpll-y += dpll_core.o dpll-y += dpll_core.o
dpll-y += dpll_netlink.o dpll-y += dpll_netlink.o
dpll-y += dpll_nl.o dpll-y += dpll_nl.o
obj-$(CONFIG_ZL3073X) += zl3073x/

View File

@ -0,0 +1,39 @@
# SPDX-License-Identifier: GPL-2.0-only
config ZL3073X
tristate "Microchip Azurite DPLL/PTP/SyncE devices" if COMPILE_TEST
depends on NET
select DPLL
select NET_DEVLINK
select REGMAP
help
This driver supports Microchip Azurite family DPLL/PTP/SyncE
devices that support up to 5 independent DPLL channels,
10 input pins and up to 20 output pins.
To compile this driver as a module, choose M here. The module
will be called zl3073x.
config ZL3073X_I2C
tristate "I2C bus implementation for Microchip Azurite devices"
depends on I2C && NET
select REGMAP_I2C
select ZL3073X
help
This is I2C bus implementation for Microchip Azurite DPLL/PTP/SyncE
devices.
To compile this driver as a module, choose M here: the module will
be called zl3073x_i2c.
config ZL3073X_SPI
tristate "SPI bus implementation for Microchip Azurite devices"
depends on NET && SPI
select REGMAP_SPI
select ZL3073X
help
This is SPI bus implementation for Microchip Azurite DPLL/PTP/SyncE
devices.
To compile this driver as a module, choose M here: the module will
be called zl3073x_spi.

View File

@ -0,0 +1,10 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_ZL3073X) += zl3073x.o
zl3073x-objs := core.o devlink.o dpll.o prop.o
obj-$(CONFIG_ZL3073X_I2C) += zl3073x_i2c.o
zl3073x_i2c-objs := i2c.o
obj-$(CONFIG_ZL3073X_SPI) += zl3073x_spi.o
zl3073x_spi-objs := spi.o

1110
drivers/dpll/zl3073x/core.c Normal file

File diff suppressed because it is too large Load Diff

386
drivers/dpll/zl3073x/core.h Normal file
View File

@ -0,0 +1,386 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef _ZL3073X_CORE_H
#define _ZL3073X_CORE_H
#include <linux/kthread.h>
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/types.h>
#include "regs.h"
struct device;
struct regmap;
struct zl3073x_dpll;
/*
* 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)
/**
* struct zl3073x_ref - input reference invariant info
* @enabled: input reference is enabled or disabled
* @diff: true if input reference is differential
* @ffo: current fractional frequency offset
*/
struct zl3073x_ref {
bool enabled;
bool diff;
s64 ffo;
};
/**
* struct zl3073x_out - output invariant info
* @enabled: out is enabled or disabled
* @synth: synthesizer the out is connected to
* @signal_format: out signal format
*/
struct zl3073x_out {
bool enabled;
u8 synth;
u8 signal_format;
};
/**
* struct zl3073x_synth - synthesizer invariant info
* @freq: synthesizer frequency
* @dpll: ID of DPLL the synthesizer is driven by
* @enabled: synth is enabled or disabled
*/
struct zl3073x_synth {
u32 freq;
u8 dpll;
bool enabled;
};
/**
* struct zl3073x_dev - zl3073x device
* @dev: pointer to device
* @regmap: regmap to access device registers
* @multiop_lock: to serialize multiple register operations
* @clock_id: clock id of the device
* @ref: array of input references' invariants
* @out: array of outs' invariants
* @synth: array of synths' invariants
* @dplls: list of DPLLs
* @kworker: thread for periodic work
* @work: periodic work
*/
struct zl3073x_dev {
struct device *dev;
struct regmap *regmap;
struct mutex multiop_lock;
u64 clock_id;
/* Invariants */
struct zl3073x_ref ref[ZL3073X_NUM_REFS];
struct zl3073x_out out[ZL3073X_NUM_OUTS];
struct zl3073x_synth synth[ZL3073X_NUM_SYNTHS];
/* DPLL channels */
struct list_head dplls;
/* Monitor */
struct kthread_worker *kworker;
struct kthread_delayed_work work;
};
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_start(struct zl3073x_dev *zldev, bool full);
void zl3073x_dev_stop(struct zl3073x_dev *zldev);
/**********************
* Registers operations
**********************/
int zl3073x_mb_op(struct zl3073x_dev *zldev, unsigned int op_reg, u8 op_val,
unsigned int mask_reg, u16 mask_val);
int zl3073x_poll_zero_u8(struct zl3073x_dev *zldev, unsigned int reg, u8 mask);
int zl3073x_read_u8(struct zl3073x_dev *zldev, unsigned int reg, u8 *val);
int zl3073x_read_u16(struct zl3073x_dev *zldev, unsigned int reg, u16 *val);
int zl3073x_read_u32(struct zl3073x_dev *zldev, unsigned int reg, u32 *val);
int zl3073x_read_u48(struct zl3073x_dev *zldev, unsigned int reg, u64 *val);
int zl3073x_write_u8(struct zl3073x_dev *zldev, unsigned int reg, u8 val);
int zl3073x_write_u16(struct zl3073x_dev *zldev, unsigned int reg, u16 val);
int zl3073x_write_u32(struct zl3073x_dev *zldev, unsigned int reg, u32 val);
int zl3073x_write_u48(struct zl3073x_dev *zldev, unsigned int reg, u64 val);
/*****************
* Misc operations
*****************/
int zl3073x_ref_freq_factorize(u32 freq, u16 *base, u16 *mult);
int zl3073x_ref_phase_offsets_update(struct zl3073x_dev *zldev, int channel);
static inline bool
zl3073x_is_n_pin(u8 id)
{
/* P-pins ids are even while N-pins are odd */
return id & 1;
}
static inline bool
zl3073x_is_p_pin(u8 id)
{
return !zl3073x_is_n_pin(id);
}
/**
* zl3073x_input_pin_ref_get - get reference for given input pin
* @id: input pin id
*
* Return: reference id for the given input pin
*/
static inline u8
zl3073x_input_pin_ref_get(u8 id)
{
return id;
}
/**
* zl3073x_output_pin_out_get - get output for the given output pin
* @id: output pin id
*
* Return: output id for the given output pin
*/
static inline u8
zl3073x_output_pin_out_get(u8 id)
{
/* Output pin pair shares the single output */
return id / 2;
}
/**
* zl3073x_ref_ffo_get - get current fractional frequency offset
* @zldev: pointer to zl3073x device
* @index: input reference index
*
* Return: the latest measured fractional frequency offset
*/
static inline s64
zl3073x_ref_ffo_get(struct zl3073x_dev *zldev, u8 index)
{
return zldev->ref[index].ffo;
}
/**
* zl3073x_ref_is_diff - check if the given input reference is differential
* @zldev: pointer to zl3073x device
* @index: input reference index
*
* Return: true if reference is differential, false if reference is single-ended
*/
static inline bool
zl3073x_ref_is_diff(struct zl3073x_dev *zldev, u8 index)
{
return zldev->ref[index].diff;
}
/**
* zl3073x_ref_is_enabled - check if the given input reference is enabled
* @zldev: pointer to zl3073x device
* @index: input reference index
*
* Return: true if input refernce is enabled, false otherwise
*/
static inline bool
zl3073x_ref_is_enabled(struct zl3073x_dev *zldev, u8 index)
{
return zldev->ref[index].enabled;
}
/**
* zl3073x_synth_dpll_get - get DPLL ID the synth is driven by
* @zldev: pointer to zl3073x device
* @index: synth index
*
* Return: ID of DPLL the given synthetizer is driven by
*/
static inline u8
zl3073x_synth_dpll_get(struct zl3073x_dev *zldev, u8 index)
{
return zldev->synth[index].dpll;
}
/**
* zl3073x_synth_freq_get - get synth current freq
* @zldev: pointer to zl3073x device
* @index: synth index
*
* Return: frequency of given synthetizer
*/
static inline u32
zl3073x_synth_freq_get(struct zl3073x_dev *zldev, u8 index)
{
return zldev->synth[index].freq;
}
/**
* zl3073x_synth_is_enabled - check if the given synth is enabled
* @zldev: pointer to zl3073x device
* @index: synth index
*
* Return: true if synth is enabled, false otherwise
*/
static inline bool
zl3073x_synth_is_enabled(struct zl3073x_dev *zldev, u8 index)
{
return zldev->synth[index].enabled;
}
/**
* zl3073x_out_synth_get - get synth connected to given output
* @zldev: pointer to zl3073x device
* @index: output index
*
* Return: index of synth connected to given output.
*/
static inline u8
zl3073x_out_synth_get(struct zl3073x_dev *zldev, u8 index)
{
return zldev->out[index].synth;
}
/**
* zl3073x_out_is_enabled - check if the given output is enabled
* @zldev: pointer to zl3073x device
* @index: output index
*
* Return: true if the output is enabled, false otherwise
*/
static inline bool
zl3073x_out_is_enabled(struct zl3073x_dev *zldev, u8 index)
{
u8 synth;
/* Output is enabled only if associated synth is enabled */
synth = zl3073x_out_synth_get(zldev, index);
if (zl3073x_synth_is_enabled(zldev, synth))
return zldev->out[index].enabled;
return false;
}
/**
* zl3073x_out_signal_format_get - get output signal format
* @zldev: pointer to zl3073x device
* @index: output index
*
* Return: signal format of given output
*/
static inline u8
zl3073x_out_signal_format_get(struct zl3073x_dev *zldev, u8 index)
{
return zldev->out[index].signal_format;
}
/**
* zl3073x_out_dpll_get - get DPLL ID the output is driven by
* @zldev: pointer to zl3073x device
* @index: output index
*
* Return: ID of DPLL the given output is driven by
*/
static inline
u8 zl3073x_out_dpll_get(struct zl3073x_dev *zldev, u8 index)
{
u8 synth;
/* Get synthesizer connected to given output */
synth = zl3073x_out_synth_get(zldev, index);
/* Return DPLL that drives the synth */
return zl3073x_synth_dpll_get(zldev, synth);
}
/**
* zl3073x_out_is_diff - check if the given output is differential
* @zldev: pointer to zl3073x device
* @index: output index
*
* Return: true if output is differential, false if output is single-ended
*/
static inline bool
zl3073x_out_is_diff(struct zl3073x_dev *zldev, u8 index)
{
switch (zl3073x_out_signal_format_get(zldev, index)) {
case ZL_OUTPUT_MODE_SIGNAL_FORMAT_LVDS:
case ZL_OUTPUT_MODE_SIGNAL_FORMAT_DIFF:
case ZL_OUTPUT_MODE_SIGNAL_FORMAT_LOWVCM:
return true;
default:
break;
}
return false;
}
/**
* zl3073x_output_pin_is_enabled - check if the given output pin is enabled
* @zldev: pointer to zl3073x device
* @id: output pin id
*
* Checks if the output of the given output pin is enabled and also that
* its signal format also enables the given pin.
*
* Return: true if output pin is enabled, false if output pin is disabled
*/
static inline bool
zl3073x_output_pin_is_enabled(struct zl3073x_dev *zldev, u8 id)
{
u8 output = zl3073x_output_pin_out_get(id);
/* Check if the whole output is enabled */
if (!zl3073x_out_is_enabled(zldev, output))
return false;
/* Check signal format */
switch (zl3073x_out_signal_format_get(zldev, output)) {
case ZL_OUTPUT_MODE_SIGNAL_FORMAT_DISABLED:
/* Both output pins are disabled by signal format */
return false;
case ZL_OUTPUT_MODE_SIGNAL_FORMAT_1P:
/* Output is one single ended P-pin output */
if (zl3073x_is_n_pin(id))
return false;
break;
case ZL_OUTPUT_MODE_SIGNAL_FORMAT_1N:
/* Output is one single ended N-pin output */
if (zl3073x_is_p_pin(id))
return false;
break;
default:
/* For other format both pins are enabled */
break;
}
return true;
}
#endif /* _ZL3073X_CORE_H */

View File

@ -0,0 +1,253 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/device/devres.h>
#include <linux/netlink.h>
#include <linux/sprintf.h>
#include <linux/types.h>
#include <net/devlink.h>
#include "core.h"
#include "devlink.h"
#include "dpll.h"
#include "regs.h"
/**
* zl3073x_devlink_info_get - Devlink device info callback
* @devlink: devlink structure pointer
* @req: devlink request pointer to store information
* @extack: netlink extack pointer to report errors
*
* Return: 0 on success, <0 on error
*/
static int
zl3073x_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req,
struct netlink_ext_ack *extack)
{
struct zl3073x_dev *zldev = devlink_priv(devlink);
u16 id, revision, fw_ver;
char buf[16];
u32 cfg_ver;
int rc;
rc = zl3073x_read_u16(zldev, ZL_REG_ID, &id);
if (rc)
return rc;
snprintf(buf, sizeof(buf), "%X", id);
rc = devlink_info_version_fixed_put(req,
DEVLINK_INFO_VERSION_GENERIC_ASIC_ID,
buf);
if (rc)
return rc;
rc = zl3073x_read_u16(zldev, ZL_REG_REVISION, &revision);
if (rc)
return rc;
snprintf(buf, sizeof(buf), "%X", revision);
rc = devlink_info_version_fixed_put(req,
DEVLINK_INFO_VERSION_GENERIC_ASIC_REV,
buf);
if (rc)
return rc;
rc = zl3073x_read_u16(zldev, ZL_REG_FW_VER, &fw_ver);
if (rc)
return rc;
snprintf(buf, sizeof(buf), "%u", fw_ver);
rc = devlink_info_version_running_put(req,
DEVLINK_INFO_VERSION_GENERIC_FW,
buf);
if (rc)
return rc;
rc = zl3073x_read_u32(zldev, ZL_REG_CUSTOM_CONFIG_VER, &cfg_ver);
if (rc)
return rc;
/* No custom config version */
if (cfg_ver == U32_MAX)
return 0;
snprintf(buf, sizeof(buf), "%lu.%lu.%lu.%lu",
FIELD_GET(GENMASK(31, 24), cfg_ver),
FIELD_GET(GENMASK(23, 16), cfg_ver),
FIELD_GET(GENMASK(15, 8), cfg_ver),
FIELD_GET(GENMASK(7, 0), cfg_ver));
return devlink_info_version_running_put(req, "custom_cfg", buf);
}
static int
zl3073x_devlink_reload_down(struct devlink *devlink, bool netns_change,
enum devlink_reload_action action,
enum devlink_reload_limit limit,
struct netlink_ext_ack *extack)
{
struct zl3073x_dev *zldev = devlink_priv(devlink);
if (action != DEVLINK_RELOAD_ACTION_DRIVER_REINIT)
return -EOPNOTSUPP;
/* Stop normal operation */
zl3073x_dev_stop(zldev);
return 0;
}
static int
zl3073x_devlink_reload_up(struct devlink *devlink,
enum devlink_reload_action action,
enum devlink_reload_limit limit,
u32 *actions_performed,
struct netlink_ext_ack *extack)
{
struct zl3073x_dev *zldev = devlink_priv(devlink);
union devlink_param_value val;
int rc;
if (action != DEVLINK_RELOAD_ACTION_DRIVER_REINIT)
return -EOPNOTSUPP;
rc = devl_param_driverinit_value_get(devlink,
DEVLINK_PARAM_GENERIC_ID_CLOCK_ID,
&val);
if (rc)
return rc;
if (zldev->clock_id != val.vu64) {
dev_dbg(zldev->dev,
"'clock_id' changed to %016llx\n", val.vu64);
zldev->clock_id = val.vu64;
}
/* Restart normal operation */
rc = zl3073x_dev_start(zldev, false);
if (rc)
dev_warn(zldev->dev, "Failed to re-start normal operation\n");
*actions_performed = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT);
return 0;
}
static const struct devlink_ops zl3073x_devlink_ops = {
.info_get = zl3073x_devlink_info_get,
.reload_actions = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT),
.reload_down = zl3073x_devlink_reload_down,
.reload_up = zl3073x_devlink_reload_up,
};
static void
zl3073x_devlink_free(void *ptr)
{
devlink_free(ptr);
}
/**
* zl3073x_devm_alloc - allocates zl3073x device structure
* @dev: pointer to device structure
*
* Allocates zl3073x device structure as device resource.
*
* Return: pointer to zl3073x device on success, error pointer on error
*/
struct zl3073x_dev *zl3073x_devm_alloc(struct device *dev)
{
struct zl3073x_dev *zldev;
struct devlink *devlink;
int rc;
devlink = devlink_alloc(&zl3073x_devlink_ops, sizeof(*zldev), dev);
if (!devlink)
return ERR_PTR(-ENOMEM);
/* Add devres action to free devlink device */
rc = devm_add_action_or_reset(dev, zl3073x_devlink_free, devlink);
if (rc)
return ERR_PTR(rc);
zldev = devlink_priv(devlink);
zldev->dev = dev;
dev_set_drvdata(zldev->dev, zldev);
return zldev;
}
EXPORT_SYMBOL_NS_GPL(zl3073x_devm_alloc, "ZL3073X");
static int
zl3073x_devlink_param_clock_id_validate(struct devlink *devlink, u32 id,
union devlink_param_value val,
struct netlink_ext_ack *extack)
{
if (!val.vu64) {
NL_SET_ERR_MSG_MOD(extack, "'clock_id' must be non-zero");
return -EINVAL;
}
return 0;
}
static const struct devlink_param zl3073x_devlink_params[] = {
DEVLINK_PARAM_GENERIC(CLOCK_ID, BIT(DEVLINK_PARAM_CMODE_DRIVERINIT),
NULL, NULL,
zl3073x_devlink_param_clock_id_validate),
};
static void
zl3073x_devlink_unregister(void *ptr)
{
struct devlink *devlink = priv_to_devlink(ptr);
devl_lock(devlink);
/* Unregister devlink params */
devl_params_unregister(devlink, zl3073x_devlink_params,
ARRAY_SIZE(zl3073x_devlink_params));
/* Unregister devlink instance */
devl_unregister(devlink);
devl_unlock(devlink);
}
/**
* zl3073x_devlink_register - register devlink instance and params
* @zldev: zl3073x device to register the devlink for
*
* Register the devlink instance and parameters associated with the device.
*
* Return: 0 on success, <0 on error
*/
int zl3073x_devlink_register(struct zl3073x_dev *zldev)
{
struct devlink *devlink = priv_to_devlink(zldev);
union devlink_param_value value;
int rc;
devl_lock(devlink);
/* Register devlink params */
rc = devl_params_register(devlink, zl3073x_devlink_params,
ARRAY_SIZE(zl3073x_devlink_params));
if (rc) {
devl_unlock(devlink);
return rc;
}
value.vu64 = zldev->clock_id;
devl_param_driverinit_value_set(devlink,
DEVLINK_PARAM_GENERIC_ID_CLOCK_ID,
value);
/* Register devlink instance */
devl_register(devlink);
devl_unlock(devlink);
/* Add devres action to unregister devlink device */
return devm_add_action_or_reset(zldev->dev, zl3073x_devlink_unregister,
zldev);
}

View File

@ -0,0 +1,12 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef _ZL3073X_DEVLINK_H
#define _ZL3073X_DEVLINK_H
struct zl3073x_dev;
struct zl3073x_dev *zl3073x_devm_alloc(struct device *dev);
int zl3073x_devlink_register(struct zl3073x_dev *zldev);
#endif /* _ZL3073X_DEVLINK_H */

2318
drivers/dpll/zl3073x/dpll.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,46 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef _ZL3073X_DPLL_H
#define _ZL3073X_DPLL_H
#include <linux/dpll.h>
#include <linux/list.h>
#include "core.h"
/**
* struct zl3073x_dpll - ZL3073x DPLL sub-device structure
* @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
* @dpll_dev: pointer to registered DPLL device
* @lock_status: last saved DPLL lock status
* @pins: list of pins
*/
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;
struct dpll_device *dpll_dev;
enum dpll_lock_status lock_status;
struct list_head pins;
};
struct zl3073x_dpll *zl3073x_dpll_alloc(struct zl3073x_dev *zldev, u8 ch);
void zl3073x_dpll_free(struct zl3073x_dpll *zldpll);
int zl3073x_dpll_register(struct zl3073x_dpll *zldpll);
void zl3073x_dpll_unregister(struct zl3073x_dpll *zldpll);
int zl3073x_dpll_init_fine_phase_adjust(struct zl3073x_dev *zldev);
void zl3073x_dpll_changes_check(struct zl3073x_dpll *zldpll);
#endif /* _ZL3073X_DPLL_H */

View File

@ -0,0 +1,76 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/dev_printk.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include "core.h"
static int zl3073x_i2c_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct zl3073x_dev *zldev;
zldev = zl3073x_devm_alloc(dev);
if (IS_ERR(zldev))
return PTR_ERR(zldev);
zldev->regmap = devm_regmap_init_i2c(client, &zl3073x_regmap_config);
if (IS_ERR(zldev->regmap))
return dev_err_probe(dev, PTR_ERR(zldev->regmap),
"Failed to initialize regmap\n");
return zl3073x_dev_probe(zldev, i2c_get_match_data(client));
}
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,
},
{ /* 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 },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, zl3073x_i2c_of_match);
static struct i2c_driver zl3073x_i2c_driver = {
.driver = {
.name = "zl3073x-i2c",
.of_match_table = zl3073x_i2c_of_match,
},
.probe = zl3073x_i2c_probe,
.id_table = zl3073x_i2c_id,
};
module_i2c_driver(zl3073x_i2c_driver);
MODULE_AUTHOR("Ivan Vecera <ivecera@redhat.com>");
MODULE_DESCRIPTION("Microchip ZL3073x I2C driver");
MODULE_IMPORT_NS("ZL3073X");
MODULE_LICENSE("GPL");

358
drivers/dpll/zl3073x/prop.c Normal file
View File

@ -0,0 +1,358 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/array_size.h>
#include <linux/dev_printk.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/fwnode.h>
#include <linux/property.h>
#include <linux/slab.h>
#include <linux/string.h>
#include "core.h"
#include "prop.h"
/**
* zl3073x_pin_check_freq - verify frequency for given pin
* @zldev: pointer to zl3073x device
* @dir: pin direction
* @id: pin index
* @freq: frequency to check
*
* The function checks the given frequency is valid for the device. For input
* pins it checks that the frequency can be factorized using supported base
* frequencies. For output pins it checks that the frequency divides connected
* synth frequency without remainder.
*
* Return: true if the frequency is valid, false if not.
*/
static bool
zl3073x_pin_check_freq(struct zl3073x_dev *zldev, enum dpll_pin_direction dir,
u8 id, u64 freq)
{
if (freq > U32_MAX)
goto err_inv_freq;
if (dir == DPLL_PIN_DIRECTION_INPUT) {
int rc;
/* Check if the frequency can be factorized */
rc = zl3073x_ref_freq_factorize(freq, NULL, NULL);
if (rc)
goto err_inv_freq;
} else {
u32 synth_freq;
u8 out, synth;
/* Get output pin synthesizer */
out = zl3073x_output_pin_out_get(id);
synth = zl3073x_out_synth_get(zldev, out);
/* Get synth frequency */
synth_freq = zl3073x_synth_freq_get(zldev, synth);
/* Check the frequency divides synth frequency */
if (synth_freq % (u32)freq)
goto err_inv_freq;
}
return true;
err_inv_freq:
dev_warn(zldev->dev,
"Unsupported frequency %llu Hz in firmware node\n", freq);
return false;
}
/**
* zl3073x_prop_pin_package_label_set - get package label for the pin
* @zldev: pointer to zl3073x device
* @props: pointer to pin properties
* @dir: pin direction
* @id: pin index
*
* Generates package label string and stores it into pin properties structure.
*
* Possible formats:
* REF<n> - differential input reference
* REF<n>P & REF<n>N - single-ended input reference (P or N pin)
* OUT<n> - differential output
* OUT<n>P & OUT<n>N - single-ended output (P or N pin)
*/
static void
zl3073x_prop_pin_package_label_set(struct zl3073x_dev *zldev,
struct zl3073x_pin_props *props,
enum dpll_pin_direction dir, u8 id)
{
const char *prefix, *suffix;
bool is_diff;
if (dir == DPLL_PIN_DIRECTION_INPUT) {
u8 ref;
prefix = "REF";
ref = zl3073x_input_pin_ref_get(id);
is_diff = zl3073x_ref_is_diff(zldev, ref);
} else {
u8 out;
prefix = "OUT";
out = zl3073x_output_pin_out_get(id);
is_diff = zl3073x_out_is_diff(zldev, out);
}
if (!is_diff)
suffix = zl3073x_is_p_pin(id) ? "P" : "N";
else
suffix = ""; /* No suffix for differential one */
snprintf(props->package_label, sizeof(props->package_label), "%s%u%s",
prefix, id / 2, suffix);
/* Set package_label pointer in DPLL core properties to generated
* string.
*/
props->dpll_props.package_label = props->package_label;
}
/**
* zl3073x_prop_pin_fwnode_get - get fwnode for given pin
* @zldev: pointer to zl3073x device
* @props: pointer to pin properties
* @dir: pin direction
* @id: pin index
*
* Return: 0 on success, -ENOENT if the firmware node does not exist
*/
static int
zl3073x_prop_pin_fwnode_get(struct zl3073x_dev *zldev,
struct zl3073x_pin_props *props,
enum dpll_pin_direction dir, u8 id)
{
struct fwnode_handle *pins_node, *pin_node;
const char *node_name;
if (dir == DPLL_PIN_DIRECTION_INPUT)
node_name = "input-pins";
else
node_name = "output-pins";
/* Get node containing input or output pins */
pins_node = device_get_named_child_node(zldev->dev, node_name);
if (!pins_node) {
dev_dbg(zldev->dev, "'%s' sub-node is missing\n", node_name);
return -ENOENT;
}
/* Enumerate child pin nodes and find the requested one */
fwnode_for_each_child_node(pins_node, pin_node) {
u32 reg;
if (fwnode_property_read_u32(pin_node, "reg", &reg))
continue;
if (id == reg)
break;
}
/* Release pin parent node */
fwnode_handle_put(pins_node);
/* Save found node */
props->fwnode = pin_node;
dev_dbg(zldev->dev, "Firmware node for %s %sfound\n",
props->package_label, pin_node ? "" : "NOT ");
return pin_node ? 0 : -ENOENT;
}
/**
* zl3073x_pin_props_get - get pin properties
* @zldev: pointer to zl3073x device
* @dir: pin direction
* @index: pin index
*
* The function looks for firmware node for the given pin if it is provided
* by the system firmware (DT or ACPI), allocates pin properties structure,
* generates package label string according pin type and optionally fetches
* board label, connection type, supported frequencies and esync capability
* from the firmware node if it does exist.
*
* Pointer that is returned by this function should be freed using
* @zl3073x_pin_props_put().
*
* Return:
* * pointer to allocated pin properties structure on success
* * error pointer in case of error
*/
struct zl3073x_pin_props *zl3073x_pin_props_get(struct zl3073x_dev *zldev,
enum dpll_pin_direction dir,
u8 index)
{
struct dpll_pin_frequency *ranges;
struct zl3073x_pin_props *props;
int i, j, num_freqs, rc;
const char *type;
u64 *freqs;
props = kzalloc(sizeof(*props), GFP_KERNEL);
if (!props)
return ERR_PTR(-ENOMEM);
/* Set default pin type and capabilities */
if (dir == DPLL_PIN_DIRECTION_INPUT) {
props->dpll_props.type = DPLL_PIN_TYPE_EXT;
props->dpll_props.capabilities =
DPLL_PIN_CAPABILITIES_PRIORITY_CAN_CHANGE |
DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE;
} else {
props->dpll_props.type = DPLL_PIN_TYPE_GNSS;
}
props->dpll_props.phase_range.min = S32_MIN;
props->dpll_props.phase_range.max = S32_MAX;
zl3073x_prop_pin_package_label_set(zldev, props, dir, index);
/* 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 */
/* Look for label property and store the value as board label */
fwnode_property_read_string(props->fwnode, "label",
&props->dpll_props.board_label);
/* Look for pin type property and translate its value to DPLL
* pin type enum if it is present.
*/
if (!fwnode_property_read_string(props->fwnode, "connection-type",
&type)) {
if (!strcmp(type, "ext"))
props->dpll_props.type = DPLL_PIN_TYPE_EXT;
else if (!strcmp(type, "gnss"))
props->dpll_props.type = DPLL_PIN_TYPE_GNSS;
else if (!strcmp(type, "int"))
props->dpll_props.type = DPLL_PIN_TYPE_INT_OSCILLATOR;
else if (!strcmp(type, "synce"))
props->dpll_props.type = DPLL_PIN_TYPE_SYNCE_ETH_PORT;
else
dev_warn(zldev->dev,
"Unknown or unsupported pin type '%s'\n",
type);
}
/* Check if the pin supports embedded sync control */
props->esync_control = fwnode_property_read_bool(props->fwnode,
"esync-control");
/* 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;
/* The firmware node specifies list of supported frequencies while
* DPLL core pin properties requires list of frequency ranges.
* So read the frequency list into temporary array.
*/
freqs = kcalloc(num_freqs, sizeof(*freqs), GFP_KERNEL);
if (!freqs) {
rc = -ENOMEM;
goto err_alloc_freqs;
}
/* Read frequencies list from firmware node */
fwnode_property_read_u64_array(props->fwnode,
"supported-frequencies-hz", freqs,
num_freqs);
/* Allocate frequency ranges list and fill it */
ranges = kcalloc(num_freqs, 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
*/
for (i = 0, j = 0; i < num_freqs; i++) {
struct dpll_pin_frequency freq = DPLL_PIN_FREQUENCY(freqs[i]);
if (zl3073x_pin_check_freq(zldev, dir, index, freqs[i])) {
ranges[j] = freq;
j++;
}
}
/* Save number of freq ranges and pointer to them into pin properties */
props->dpll_props.freq_supported = ranges;
props->dpll_props.freq_supported_num = j;
/* Free temporary array */
kfree(freqs);
return props;
err_alloc_ranges:
kfree(freqs);
err_alloc_freqs:
fwnode_handle_put(props->fwnode);
kfree(props);
return ERR_PTR(rc);
}
/**
* zl3073x_pin_props_put - release pin properties
* @props: pin properties to free
*
* The function deallocates given pin properties structure.
*/
void zl3073x_pin_props_put(struct zl3073x_pin_props *props)
{
/* Free supported frequency ranges list if it is present */
kfree(props->dpll_props.freq_supported);
/* Put firmware handle if it is present */
if (props->fwnode)
fwnode_handle_put(props->fwnode);
kfree(props);
}
/**
* zl3073x_prop_dpll_type_get - get DPLL channel type
* @zldev: pointer to zl3073x device
* @index: DPLL channel index
*
* Return: DPLL type for given DPLL channel
*/
enum dpll_type
zl3073x_prop_dpll_type_get(struct zl3073x_dev *zldev, u8 index)
{
const char *types[ZL3073X_MAX_CHANNELS];
int count;
/* Read dpll types property from firmware */
count = device_property_read_string_array(zldev->dev, "dpll-types",
types, ARRAY_SIZE(types));
/* Return default if property or entry for given channel is missing */
if (index >= count)
return DPLL_TYPE_PPS;
if (!strcmp(types[index], "pps"))
return DPLL_TYPE_PPS;
else if (!strcmp(types[index], "eec"))
return DPLL_TYPE_EEC;
dev_info(zldev->dev, "Unknown DPLL type '%s', using default\n",
types[index]);
return DPLL_TYPE_PPS; /* Default */
}

View File

@ -0,0 +1,34 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef _ZL3073X_PROP_H
#define _ZL3073X_PROP_H
#include <linux/dpll.h>
#include "core.h"
struct fwnode_handle;
/**
* struct zl3073x_pin_props - pin properties
* @fwnode: pin firmware node
* @dpll_props: DPLL core pin properties
* @package_label: pin package label
* @esync_control: embedded sync support
*/
struct zl3073x_pin_props {
struct fwnode_handle *fwnode;
struct dpll_pin_properties dpll_props;
char package_label[8];
bool esync_control;
};
enum dpll_type zl3073x_prop_dpll_type_get(struct zl3073x_dev *zldev, u8 index);
struct zl3073x_pin_props *zl3073x_pin_props_get(struct zl3073x_dev *zldev,
enum dpll_pin_direction dir,
u8 index);
void zl3073x_pin_props_put(struct zl3073x_pin_props *props);
#endif /* _ZL3073X_PROP_H */

266
drivers/dpll/zl3073x/regs.h Normal file
View File

@ -0,0 +1,266 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef _ZL3073X_REGS_H
#define _ZL3073X_REGS_H
#include <linux/bitfield.h>
#include <linux/bits.h>
/*
* Register address structure:
* ===========================
* 25 19 18 16 15 7 6 0
* +------------------------------------------+
* | max_offset | size | page | page_offset |
* +------------------------------------------+
*
* page_offset ... <0x00..0x7F>
* page .......... HW page number
* size .......... register byte size (1, 2, 4 or 6)
* max_offset .... maximal offset for indexed registers
* (for non-indexed regs max_offset == page_offset)
*/
#define ZL_REG_OFFSET_MASK GENMASK(6, 0)
#define ZL_REG_PAGE_MASK GENMASK(15, 7)
#define ZL_REG_SIZE_MASK GENMASK(18, 16)
#define ZL_REG_MAX_OFFSET_MASK GENMASK(25, 19)
#define ZL_REG_ADDR_MASK GENMASK(15, 0)
#define ZL_REG_OFFSET(_reg) FIELD_GET(ZL_REG_OFFSET_MASK, _reg)
#define ZL_REG_PAGE(_reg) FIELD_GET(ZL_REG_PAGE_MASK, _reg)
#define ZL_REG_MAX_OFFSET(_reg) FIELD_GET(ZL_REG_MAX_OFFSET_MASK, _reg)
#define ZL_REG_SIZE(_reg) FIELD_GET(ZL_REG_SIZE_MASK, _reg)
#define ZL_REG_ADDR(_reg) FIELD_GET(ZL_REG_ADDR_MASK, _reg)
/**
* ZL_REG_IDX - define indexed register
* @_idx: index of register to access
* @_page: register page
* @_offset: register offset in page
* @_size: register byte size (1, 2, 4 or 6)
* @_items: number of register indices
* @_stride: stride between items in bytes
*
* All parameters except @_idx should be constant.
*/
#define ZL_REG_IDX(_idx, _page, _offset, _size, _items, _stride) \
(FIELD_PREP(ZL_REG_OFFSET_MASK, \
(_offset) + (_idx) * (_stride)) | \
FIELD_PREP_CONST(ZL_REG_PAGE_MASK, _page) | \
FIELD_PREP_CONST(ZL_REG_SIZE_MASK, _size) | \
FIELD_PREP_CONST(ZL_REG_MAX_OFFSET_MASK, \
(_offset) + ((_items) - 1) * (_stride)))
/**
* ZL_REG - define simple (non-indexed) register
* @_page: register page
* @_offset: register offset in page
* @_size: register byte size (1, 2, 4 or 6)
*
* All parameters should be constant.
*/
#define ZL_REG(_page, _offset, _size) \
ZL_REG_IDX(0, _page, _offset, _size, 1, 0)
/**************************
* Register Page 0, General
**************************/
#define ZL_REG_INFO ZL_REG(0, 0x00, 1)
#define ZL_INFO_READY BIT(7)
#define ZL_REG_ID ZL_REG(0, 0x01, 2)
#define ZL_REG_REVISION ZL_REG(0, 0x03, 2)
#define ZL_REG_FW_VER ZL_REG(0, 0x05, 2)
#define ZL_REG_CUSTOM_CONFIG_VER ZL_REG(0, 0x07, 4)
/*************************
* 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_REG_DPLL_MON_STATUS(_idx) \
ZL_REG_IDX(_idx, 2, 0x10, 1, ZL3073X_MAX_CHANNELS, 1)
#define ZL_DPLL_MON_STATUS_STATE GENMASK(1, 0)
#define ZL_DPLL_MON_STATUS_STATE_ACQUIRING 0
#define ZL_DPLL_MON_STATUS_STATE_LOCK 1
#define ZL_DPLL_MON_STATUS_STATE_HOLDOVER 2
#define ZL_DPLL_MON_STATUS_HO_READY BIT(2)
#define ZL_REG_DPLL_REFSEL_STATUS(_idx) \
ZL_REG_IDX(_idx, 2, 0x30, 1, ZL3073X_MAX_CHANNELS, 1)
#define ZL_DPLL_REFSEL_STATUS_REFSEL GENMASK(3, 0)
#define ZL_DPLL_REFSEL_STATUS_STATE GENMASK(6, 4)
#define ZL_DPLL_REFSEL_STATUS_STATE_LOCK 4
#define ZL_REG_REF_FREQ(_idx) \
ZL_REG_IDX(_idx, 2, 0x44, 4, ZL3073X_NUM_REFS, 4)
/**********************
* Register Page 4, Ref
**********************/
#define ZL_REG_REF_PHASE_ERR_READ_RQST ZL_REG(4, 0x0f, 1)
#define ZL_REF_PHASE_ERR_READ_RQST_RD BIT(0)
#define ZL_REG_REF_FREQ_MEAS_CTRL ZL_REG(4, 0x1c, 1)
#define ZL_REF_FREQ_MEAS_CTRL GENMASK(1, 0)
#define ZL_REF_FREQ_MEAS_CTRL_REF_FREQ 1
#define ZL_REF_FREQ_MEAS_CTRL_REF_FREQ_OFF 2
#define ZL_REF_FREQ_MEAS_CTRL_DPLL_FREQ_OFF 3
#define ZL_REG_REF_FREQ_MEAS_MASK_3_0 ZL_REG(4, 0x1d, 1)
#define ZL_REF_FREQ_MEAS_MASK_3_0(_ref) BIT(_ref)
#define ZL_REG_REF_FREQ_MEAS_MASK_4 ZL_REG(4, 0x1e, 1)
#define ZL_REF_FREQ_MEAS_MASK_4(_ref) BIT((_ref) - 8)
#define ZL_REG_DPLL_MEAS_REF_FREQ_CTRL ZL_REG(4, 0x1f, 1)
#define ZL_DPLL_MEAS_REF_FREQ_CTRL_EN BIT(0)
#define ZL_DPLL_MEAS_REF_FREQ_CTRL_IDX GENMASK(6, 4)
#define ZL_REG_REF_PHASE(_idx) \
ZL_REG_IDX(_idx, 4, 0x20, 6, ZL3073X_NUM_REFS, 6)
/***********************
* Register Page 5, DPLL
***********************/
#define ZL_REG_DPLL_MODE_REFSEL(_idx) \
ZL_REG_IDX(_idx, 5, 0x04, 1, ZL3073X_MAX_CHANNELS, 4)
#define ZL_DPLL_MODE_REFSEL_MODE GENMASK(2, 0)
#define ZL_DPLL_MODE_REFSEL_MODE_FREERUN 0
#define ZL_DPLL_MODE_REFSEL_MODE_HOLDOVER 1
#define ZL_DPLL_MODE_REFSEL_MODE_REFLOCK 2
#define ZL_DPLL_MODE_REFSEL_MODE_AUTO 3
#define ZL_DPLL_MODE_REFSEL_MODE_NCO 4
#define ZL_DPLL_MODE_REFSEL_REF GENMASK(7, 4)
#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)
#define ZL_REG_DPLL_MEAS_IDX ZL_REG(5, 0x51, 1)
#define ZL_DPLL_MEAS_IDX GENMASK(2, 0)
#define ZL_REG_DPLL_PHASE_ERR_READ_MASK ZL_REG(5, 0x54, 1)
#define ZL_REG_DPLL_PHASE_ERR_DATA(_idx) \
ZL_REG_IDX(_idx, 5, 0x55, 6, ZL3073X_MAX_CHANNELS, 6)
/***********************************
* Register Page 9, Synth and Output
***********************************/
#define ZL_REG_SYNTH_CTRL(_idx) \
ZL_REG_IDX(_idx, 9, 0x00, 1, ZL3073X_NUM_SYNTHS, 1)
#define ZL_SYNTH_CTRL_EN BIT(0)
#define ZL_SYNTH_CTRL_DPLL_SEL GENMASK(6, 4)
#define ZL_REG_SYNTH_PHASE_SHIFT_CTRL ZL_REG(9, 0x1e, 1)
#define ZL_REG_SYNTH_PHASE_SHIFT_MASK ZL_REG(9, 0x1f, 1)
#define ZL_REG_SYNTH_PHASE_SHIFT_INTVL ZL_REG(9, 0x20, 1)
#define ZL_REG_SYNTH_PHASE_SHIFT_DATA ZL_REG(9, 0x21, 2)
#define ZL_REG_OUTPUT_CTRL(_idx) \
ZL_REG_IDX(_idx, 9, 0x28, 1, ZL3073X_NUM_OUTS, 1)
#define ZL_OUTPUT_CTRL_EN BIT(0)
#define ZL_OUTPUT_CTRL_SYNTH_SEL GENMASK(6, 4)
/*******************************
* Register Page 10, Ref Mailbox
*******************************/
#define ZL_REG_REF_MB_MASK ZL_REG(10, 0x02, 2)
#define ZL_REG_REF_MB_SEM ZL_REG(10, 0x04, 1)
#define ZL_REF_MB_SEM_WR BIT(0)
#define ZL_REF_MB_SEM_RD BIT(1)
#define ZL_REG_REF_FREQ_BASE ZL_REG(10, 0x05, 2)
#define ZL_REG_REF_FREQ_MULT ZL_REG(10, 0x07, 2)
#define ZL_REG_REF_RATIO_M ZL_REG(10, 0x09, 2)
#define ZL_REG_REF_RATIO_N ZL_REG(10, 0x0b, 2)
#define ZL_REG_REF_CONFIG ZL_REG(10, 0x0d, 1)
#define ZL_REF_CONFIG_ENABLE BIT(0)
#define ZL_REF_CONFIG_DIFF_EN BIT(2)
#define ZL_REG_REF_PHASE_OFFSET_COMP ZL_REG(10, 0x28, 6)
#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_50_50_ESYNC_25_75 2
#define ZL_REG_REF_ESYNC_DIV ZL_REG(10, 0x30, 4)
#define ZL_REF_ESYNC_DIV_1HZ 0
/********************************
* Register Page 12, DPLL Mailbox
********************************/
#define ZL_REG_DPLL_MB_MASK ZL_REG(12, 0x02, 2)
#define ZL_REG_DPLL_MB_SEM ZL_REG(12, 0x04, 1)
#define ZL_DPLL_MB_SEM_WR BIT(0)
#define ZL_DPLL_MB_SEM_RD BIT(1)
#define ZL_REG_DPLL_REF_PRIO(_idx) \
ZL_REG_IDX(_idx, 12, 0x52, 1, ZL3073X_NUM_REFS / 2, 1)
#define ZL_DPLL_REF_PRIO_REF_P GENMASK(3, 0)
#define ZL_DPLL_REF_PRIO_REF_N GENMASK(7, 4)
#define ZL_DPLL_REF_PRIO_MAX 14
#define ZL_DPLL_REF_PRIO_NONE 15
/*********************************
* Register Page 13, Synth Mailbox
*********************************/
#define ZL_REG_SYNTH_MB_MASK ZL_REG(13, 0x02, 2)
#define ZL_REG_SYNTH_MB_SEM ZL_REG(13, 0x04, 1)
#define ZL_SYNTH_MB_SEM_WR BIT(0)
#define ZL_SYNTH_MB_SEM_RD BIT(1)
#define ZL_REG_SYNTH_FREQ_BASE ZL_REG(13, 0x06, 2)
#define ZL_REG_SYNTH_FREQ_MULT ZL_REG(13, 0x08, 4)
#define ZL_REG_SYNTH_FREQ_M ZL_REG(13, 0x0c, 2)
#define ZL_REG_SYNTH_FREQ_N ZL_REG(13, 0x0e, 2)
/**********************************
* Register Page 14, Output Mailbox
**********************************/
#define ZL_REG_OUTPUT_MB_MASK ZL_REG(14, 0x02, 2)
#define ZL_REG_OUTPUT_MB_SEM ZL_REG(14, 0x04, 1)
#define ZL_OUTPUT_MB_SEM_WR BIT(0)
#define ZL_OUTPUT_MB_SEM_RD BIT(1)
#define ZL_REG_OUTPUT_MODE ZL_REG(14, 0x05, 1)
#define ZL_OUTPUT_MODE_CLOCK_TYPE GENMASK(2, 0)
#define ZL_OUTPUT_MODE_CLOCK_TYPE_NORMAL 0
#define ZL_OUTPUT_MODE_CLOCK_TYPE_ESYNC 1
#define ZL_OUTPUT_MODE_SIGNAL_FORMAT GENMASK(7, 4)
#define ZL_OUTPUT_MODE_SIGNAL_FORMAT_DISABLED 0
#define ZL_OUTPUT_MODE_SIGNAL_FORMAT_LVDS 1
#define ZL_OUTPUT_MODE_SIGNAL_FORMAT_DIFF 2
#define ZL_OUTPUT_MODE_SIGNAL_FORMAT_LOWVCM 3
#define ZL_OUTPUT_MODE_SIGNAL_FORMAT_2 4
#define ZL_OUTPUT_MODE_SIGNAL_FORMAT_1P 5
#define ZL_OUTPUT_MODE_SIGNAL_FORMAT_1N 6
#define ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_INV 7
#define ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV 12
#define ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV_INV 15
#define ZL_REG_OUTPUT_DIV ZL_REG(14, 0x0c, 4)
#define ZL_REG_OUTPUT_WIDTH ZL_REG(14, 0x10, 4)
#define ZL_REG_OUTPUT_ESYNC_PERIOD ZL_REG(14, 0x14, 4)
#define ZL_REG_OUTPUT_ESYNC_WIDTH ZL_REG(14, 0x18, 4)
#define ZL_REG_OUTPUT_PHASE_COMP ZL_REG(14, 0x20, 4)
#endif /* _ZL3073X_REGS_H */

View File

@ -0,0 +1,76 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/dev_printk.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
#include "core.h"
static int zl3073x_spi_probe(struct spi_device *spi)
{
struct device *dev = &spi->dev;
struct zl3073x_dev *zldev;
zldev = zl3073x_devm_alloc(dev);
if (IS_ERR(zldev))
return PTR_ERR(zldev);
zldev->regmap = devm_regmap_init_spi(spi, &zl3073x_regmap_config);
if (IS_ERR(zldev->regmap))
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));
}
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,
},
{ /* 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 },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, zl3073x_spi_of_match);
static struct spi_driver zl3073x_spi_driver = {
.driver = {
.name = "zl3073x-spi",
.of_match_table = zl3073x_spi_of_match,
},
.probe = zl3073x_spi_probe,
.id_table = zl3073x_spi_id,
};
module_spi_driver(zl3073x_spi_driver);
MODULE_AUTHOR("Ivan Vecera <ivecera@redhat.com>");
MODULE_DESCRIPTION("Microchip ZL3073x SPI driver");
MODULE_IMPORT_NS("ZL3073X");
MODULE_LICENSE("GPL");

View File

@ -542,7 +542,8 @@ enum {
#define pasid_supported(iommu) (sm_supported(iommu) && \ #define pasid_supported(iommu) (sm_supported(iommu) && \
ecap_pasid((iommu)->ecap)) ecap_pasid((iommu)->ecap))
#define ssads_supported(iommu) (sm_supported(iommu) && \ #define ssads_supported(iommu) (sm_supported(iommu) && \
ecap_slads((iommu)->ecap)) ecap_slads((iommu)->ecap) && \
ecap_smpwc(iommu->ecap))
#define nested_supported(iommu) (sm_supported(iommu) && \ #define nested_supported(iommu) (sm_supported(iommu) && \
ecap_nest((iommu)->ecap)) ecap_nest((iommu)->ecap))

View File

@ -98,19 +98,21 @@ struct ice_adapter *ice_adapter_get(struct pci_dev *pdev)
index = ice_adapter_xa_index(pdev); index = ice_adapter_xa_index(pdev);
scoped_guard(mutex, &ice_adapters_mutex) { scoped_guard(mutex, &ice_adapters_mutex) {
err = xa_insert(&ice_adapters, index, NULL, GFP_KERNEL); adapter = xa_load(&ice_adapters, index);
if (err == -EBUSY) { if (adapter) {
adapter = xa_load(&ice_adapters, index);
refcount_inc(&adapter->refcount); refcount_inc(&adapter->refcount);
WARN_ON_ONCE(adapter->index != ice_adapter_index(pdev)); WARN_ON_ONCE(adapter->index != ice_adapter_index(pdev));
return adapter; return adapter;
} }
err = xa_reserve(&ice_adapters, index, GFP_KERNEL);
if (err) if (err)
return ERR_PTR(err); return ERR_PTR(err);
adapter = ice_adapter_new(pdev); adapter = ice_adapter_new(pdev);
if (!adapter) if (!adapter) {
xa_release(&ice_adapters, index);
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
}
xa_store(&ice_adapters, index, adapter, GFP_KERNEL); xa_store(&ice_adapters, index, adapter, GFP_KERNEL);
} }
return adapter; return adapter;

View File

@ -2267,6 +2267,7 @@ static int idpf_set_mac(struct net_device *netdev, void *p)
struct idpf_netdev_priv *np = netdev_priv(netdev); struct idpf_netdev_priv *np = netdev_priv(netdev);
struct idpf_vport_config *vport_config; struct idpf_vport_config *vport_config;
struct sockaddr *addr = p; struct sockaddr *addr = p;
u8 old_mac_addr[ETH_ALEN];
struct idpf_vport *vport; struct idpf_vport *vport;
int err = 0; int err = 0;
@ -2290,17 +2291,19 @@ static int idpf_set_mac(struct net_device *netdev, void *p)
if (ether_addr_equal(netdev->dev_addr, addr->sa_data)) if (ether_addr_equal(netdev->dev_addr, addr->sa_data))
goto unlock_mutex; goto unlock_mutex;
ether_addr_copy(old_mac_addr, vport->default_mac_addr);
ether_addr_copy(vport->default_mac_addr, addr->sa_data);
vport_config = vport->adapter->vport_config[vport->idx]; vport_config = vport->adapter->vport_config[vport->idx];
err = idpf_add_mac_filter(vport, np, addr->sa_data, false); err = idpf_add_mac_filter(vport, np, addr->sa_data, false);
if (err) { if (err) {
__idpf_del_mac_filter(vport_config, addr->sa_data); __idpf_del_mac_filter(vport_config, addr->sa_data);
ether_addr_copy(vport->default_mac_addr, netdev->dev_addr);
goto unlock_mutex; goto unlock_mutex;
} }
if (is_valid_ether_addr(vport->default_mac_addr)) if (is_valid_ether_addr(old_mac_addr))
idpf_del_mac_filter(vport, np, vport->default_mac_addr, false); __idpf_del_mac_filter(vport_config, old_mac_addr);
ether_addr_copy(vport->default_mac_addr, addr->sa_data);
eth_hw_addr_set(netdev, addr->sa_data); eth_hw_addr_set(netdev, addr->sa_data);
unlock_mutex: unlock_mutex:

View File

@ -3516,6 +3516,16 @@ u32 idpf_get_vport_id(struct idpf_vport *vport)
return le32_to_cpu(vport_msg->vport_id); return le32_to_cpu(vport_msg->vport_id);
} }
static void idpf_set_mac_type(struct idpf_vport *vport,
struct virtchnl2_mac_addr *mac_addr)
{
bool is_primary;
is_primary = ether_addr_equal(vport->default_mac_addr, mac_addr->addr);
mac_addr->type = is_primary ? VIRTCHNL2_MAC_ADDR_PRIMARY :
VIRTCHNL2_MAC_ADDR_EXTRA;
}
/** /**
* idpf_mac_filter_async_handler - Async callback for mac filters * idpf_mac_filter_async_handler - Async callback for mac filters
* @adapter: private data struct * @adapter: private data struct
@ -3645,6 +3655,7 @@ int idpf_add_del_mac_filters(struct idpf_vport *vport,
list) { list) {
if (add && f->add) { if (add && f->add) {
ether_addr_copy(mac_addr[i].addr, f->macaddr); ether_addr_copy(mac_addr[i].addr, f->macaddr);
idpf_set_mac_type(vport, &mac_addr[i]);
i++; i++;
f->add = false; f->add = false;
if (i == total_filters) if (i == total_filters)
@ -3652,6 +3663,7 @@ int idpf_add_del_mac_filters(struct idpf_vport *vport,
} }
if (!add && f->remove) { if (!add && f->remove) {
ether_addr_copy(mac_addr[i].addr, f->macaddr); ether_addr_copy(mac_addr[i].addr, f->macaddr);
idpf_set_mac_type(vport, &mac_addr[i]);
i++; i++;
f->remove = false; f->remove = false;
if (i == total_filters) if (i == total_filters)

View File

@ -658,7 +658,7 @@ static void del_sw_hw_rule(struct fs_node *node)
BIT(MLX5_SET_FTE_MODIFY_ENABLE_MASK_ACTION) | BIT(MLX5_SET_FTE_MODIFY_ENABLE_MASK_ACTION) |
BIT(MLX5_SET_FTE_MODIFY_ENABLE_MASK_FLOW_COUNTERS); BIT(MLX5_SET_FTE_MODIFY_ENABLE_MASK_FLOW_COUNTERS);
fte->act_dests.action.action &= ~MLX5_FLOW_CONTEXT_ACTION_COUNT; fte->act_dests.action.action &= ~MLX5_FLOW_CONTEXT_ACTION_COUNT;
mlx5_fc_local_destroy(rule->dest_attr.counter); mlx5_fc_local_put(rule->dest_attr.counter);
goto out; goto out;
} }

View File

@ -345,6 +345,7 @@ struct mlx5_fc {
/* last{packets,bytes} are used for calculating deltas since last reading. */ /* last{packets,bytes} are used for calculating deltas since last reading. */
u64 lastpackets; u64 lastpackets;
u64 lastbytes; u64 lastbytes;
RH_KABI_EXTEND(refcount_t fc_local_refcount)
}; };
struct mlx5_fc_bulk { struct mlx5_fc_bulk {

View File

@ -562,17 +562,36 @@ mlx5_fc_local_create(u32 counter_id, u32 offset, u32 bulk_size)
counter->id = counter_id; counter->id = counter_id;
fc_bulk->base_id = counter_id - offset; fc_bulk->base_id = counter_id - offset;
fc_bulk->fs_bulk.bulk_len = bulk_size; fc_bulk->fs_bulk.bulk_len = bulk_size;
refcount_set(&fc_bulk->hws_data.hws_action_refcount, 0);
mutex_init(&fc_bulk->hws_data.lock);
counter->bulk = fc_bulk; counter->bulk = fc_bulk;
refcount_set(&counter->fc_local_refcount, 1);
return counter; return counter;
} }
EXPORT_SYMBOL(mlx5_fc_local_create); EXPORT_SYMBOL(mlx5_fc_local_create);
void mlx5_fc_local_destroy(struct mlx5_fc *counter) void mlx5_fc_local_destroy(struct mlx5_fc *counter)
{ {
if (!counter || counter->type != MLX5_FC_TYPE_LOCAL)
return;
kfree(counter->bulk); kfree(counter->bulk);
kfree(counter); kfree(counter);
} }
EXPORT_SYMBOL(mlx5_fc_local_destroy); EXPORT_SYMBOL(mlx5_fc_local_destroy);
void mlx5_fc_local_get(struct mlx5_fc *counter)
{
if (!counter || counter->type != MLX5_FC_TYPE_LOCAL)
return;
refcount_inc(&counter->fc_local_refcount);
}
void mlx5_fc_local_put(struct mlx5_fc *counter)
{
if (!counter || counter->type != MLX5_FC_TYPE_LOCAL)
return;
if (!refcount_dec_and_test(&counter->fc_local_refcount))
return;
mlx5_fc_local_destroy(counter);
}

View File

@ -407,15 +407,21 @@ struct mlx5hws_action *mlx5_fc_get_hws_action(struct mlx5hws_context *ctx,
{ {
struct mlx5_fs_hws_create_action_ctx create_ctx; struct mlx5_fs_hws_create_action_ctx create_ctx;
struct mlx5_fc_bulk *fc_bulk = counter->bulk; struct mlx5_fc_bulk *fc_bulk = counter->bulk;
struct mlx5hws_action *hws_action;
create_ctx.hws_ctx = ctx; create_ctx.hws_ctx = ctx;
create_ctx.id = fc_bulk->base_id; create_ctx.id = fc_bulk->base_id;
create_ctx.actions_type = MLX5HWS_ACTION_TYP_CTR; create_ctx.actions_type = MLX5HWS_ACTION_TYP_CTR;
return mlx5_fs_get_hws_action(&fc_bulk->hws_data, &create_ctx); mlx5_fc_local_get(counter);
hws_action = mlx5_fs_get_hws_action(&fc_bulk->hws_data, &create_ctx);
if (!hws_action)
mlx5_fc_local_put(counter);
return hws_action;
} }
void mlx5_fc_put_hws_action(struct mlx5_fc *counter) void mlx5_fc_put_hws_action(struct mlx5_fc *counter)
{ {
mlx5_fs_put_hws_action(&counter->bulk->hws_data); mlx5_fs_put_hws_action(&counter->bulk->hws_data);
mlx5_fc_local_put(counter);
} }

View File

@ -4509,7 +4509,7 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, int num_rqst,
for (int i = 1; i < num_rqst; i++) { for (int i = 1; i < num_rqst; i++) {
struct smb_rqst *old = &old_rq[i - 1]; struct smb_rqst *old = &old_rq[i - 1];
struct smb_rqst *new = &new_rq[i]; struct smb_rqst *new = &new_rq[i];
struct folio_queue *buffer; struct folio_queue *buffer = NULL;
size_t size = iov_iter_count(&old->rq_iter); size_t size = iov_iter_count(&old->rq_iter);
orig_len += smb_rqst_len(server, old); orig_len += smb_rqst_len(server, old);

0
include/config/ZL3073X Normal file
View File

View File

View File

View File

@ -3242,6 +3242,7 @@ CONFIG_NET_VENDOR_AQUANTIA=y
CONFIG_HID_LENOVO=m CONFIG_HID_LENOVO=m
CONFIG_CEPH_FS=m CONFIG_CEPH_FS=m
CONFIG_DRM_DISPLAY_HDMI_STATE_HELPER=y CONFIG_DRM_DISPLAY_HDMI_STATE_HELPER=y
CONFIG_ZL3073X_I2C=m
CONFIG_ATA_SFF=y CONFIG_ATA_SFF=y
CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
CONFIG_PINCTRL=y CONFIG_PINCTRL=y
@ -3992,6 +3993,7 @@ CONFIG_SUNRPC_GSS=m
CONFIG_VIDEOMODE_HELPERS=y CONFIG_VIDEOMODE_HELPERS=y
CONFIG_SQUASHFS_LZ4=y CONFIG_SQUASHFS_LZ4=y
CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY=y CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY=y
CONFIG_ZL3073X_SPI=m
CONFIG_EDAC_SUPPORT=y CONFIG_EDAC_SUPPORT=y
CONFIG_USB_PRINTER=m CONFIG_USB_PRINTER=m
CONFIG_FW_CFG_SYSFS=y CONFIG_FW_CFG_SYSFS=y
@ -4458,6 +4460,7 @@ CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_TCM_FC=m CONFIG_TCM_FC=m
CONFIG_RCU_EXP_CPU_STALL_TIMEOUT=0 CONFIG_RCU_EXP_CPU_STALL_TIMEOUT=0
CONFIG_OF=y CONFIG_OF=y
CONFIG_ZL3073X=m
CONFIG_MODULE_SIG_KEY=certs/signing_key.pem CONFIG_MODULE_SIG_KEY=certs/signing_key.pem
CONFIG_ARCH_MMAP_RND_BITS_MIN=14 CONFIG_ARCH_MMAP_RND_BITS_MIN=14
CONFIG_USB_SERIAL_SYMBOL=m CONFIG_USB_SERIAL_SYMBOL=m

View File

@ -578,6 +578,8 @@ deps_config := \
drivers/pps/clients/Kconfig \ drivers/pps/clients/Kconfig \
drivers/pps/generators/Kconfig \ drivers/pps/generators/Kconfig \
drivers/ptp/Kconfig \ drivers/ptp/Kconfig \
drivers/dpll/Kconfig \
drivers/dpll/zl3073x/Kconfig \
drivers/pinctrl/Kconfig \ drivers/pinctrl/Kconfig \
drivers/pinctrl/actions/Kconfig \ drivers/pinctrl/actions/Kconfig \
drivers/pinctrl/aspeed/Kconfig \ drivers/pinctrl/aspeed/Kconfig \
@ -1458,7 +1460,6 @@ deps_config := \
drivers/hte/Kconfig \ drivers/hte/Kconfig \
drivers/cdx/Kconfig \ drivers/cdx/Kconfig \
drivers/cdx/controller/Kconfig \ drivers/cdx/controller/Kconfig \
drivers/dpll/Kconfig \
fs/Kconfig \ fs/Kconfig \
fs/ext2/Kconfig \ fs/ext2/Kconfig \
fs/ext4/Kconfig \ fs/ext4/Kconfig \

View File

@ -3242,6 +3242,7 @@
#define CONFIG_HID_LENOVO_MODULE 1 #define CONFIG_HID_LENOVO_MODULE 1
#define CONFIG_CEPH_FS_MODULE 1 #define CONFIG_CEPH_FS_MODULE 1
#define CONFIG_DRM_DISPLAY_HDMI_STATE_HELPER 1 #define CONFIG_DRM_DISPLAY_HDMI_STATE_HELPER 1
#define CONFIG_ZL3073X_I2C_MODULE 1
#define CONFIG_ATA_SFF 1 #define CONFIG_ATA_SFF 1
#define CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024 #define CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024
#define CONFIG_PINCTRL 1 #define CONFIG_PINCTRL 1
@ -3992,6 +3993,7 @@
#define CONFIG_VIDEOMODE_HELPERS 1 #define CONFIG_VIDEOMODE_HELPERS 1
#define CONFIG_SQUASHFS_LZ4 1 #define CONFIG_SQUASHFS_LZ4 1
#define CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY 1 #define CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY 1
#define CONFIG_ZL3073X_SPI_MODULE 1
#define CONFIG_EDAC_SUPPORT 1 #define CONFIG_EDAC_SUPPORT 1
#define CONFIG_USB_PRINTER_MODULE 1 #define CONFIG_USB_PRINTER_MODULE 1
#define CONFIG_FW_CFG_SYSFS 1 #define CONFIG_FW_CFG_SYSFS 1
@ -4458,6 +4460,7 @@
#define CONFIG_TCM_FC_MODULE 1 #define CONFIG_TCM_FC_MODULE 1
#define CONFIG_RCU_EXP_CPU_STALL_TIMEOUT 0 #define CONFIG_RCU_EXP_CPU_STALL_TIMEOUT 0
#define CONFIG_OF 1 #define CONFIG_OF 1
#define CONFIG_ZL3073X_MODULE 1
#define CONFIG_MODULE_SIG_KEY "certs/signing_key.pem" #define CONFIG_MODULE_SIG_KEY "certs/signing_key.pem"
#define CONFIG_ARCH_MMAP_RND_BITS_MIN 14 #define CONFIG_ARCH_MMAP_RND_BITS_MIN 14
#define CONFIG_USB_SERIAL_SYMBOL_MODULE 1 #define CONFIG_USB_SERIAL_SYMBOL_MODULE 1

View File

@ -6373,6 +6373,8 @@
--cfg=CONFIG_CEPH_FS="m" --cfg=CONFIG_CEPH_FS="m"
--cfg=CONFIG_DRM_DISPLAY_HDMI_STATE_HELPER --cfg=CONFIG_DRM_DISPLAY_HDMI_STATE_HELPER
--cfg=CONFIG_DRM_DISPLAY_HDMI_STATE_HELPER="y" --cfg=CONFIG_DRM_DISPLAY_HDMI_STATE_HELPER="y"
--cfg=CONFIG_ZL3073X_I2C
--cfg=CONFIG_ZL3073X_I2C="m"
--cfg=CONFIG_ATA_SFF --cfg=CONFIG_ATA_SFF
--cfg=CONFIG_ATA_SFF="y" --cfg=CONFIG_ATA_SFF="y"
--cfg=CONFIG_INPUT_MOUSEDEV_SCREEN_X="1024" --cfg=CONFIG_INPUT_MOUSEDEV_SCREEN_X="1024"
@ -7853,6 +7855,8 @@
--cfg=CONFIG_SQUASHFS_LZ4="y" --cfg=CONFIG_SQUASHFS_LZ4="y"
--cfg=CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY --cfg=CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY
--cfg=CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY="y" --cfg=CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY="y"
--cfg=CONFIG_ZL3073X_SPI
--cfg=CONFIG_ZL3073X_SPI="m"
--cfg=CONFIG_EDAC_SUPPORT --cfg=CONFIG_EDAC_SUPPORT
--cfg=CONFIG_EDAC_SUPPORT="y" --cfg=CONFIG_EDAC_SUPPORT="y"
--cfg=CONFIG_USB_PRINTER --cfg=CONFIG_USB_PRINTER
@ -8770,6 +8774,8 @@
--cfg=CONFIG_RCU_EXP_CPU_STALL_TIMEOUT="0" --cfg=CONFIG_RCU_EXP_CPU_STALL_TIMEOUT="0"
--cfg=CONFIG_OF --cfg=CONFIG_OF
--cfg=CONFIG_OF="y" --cfg=CONFIG_OF="y"
--cfg=CONFIG_ZL3073X
--cfg=CONFIG_ZL3073X="m"
--cfg=CONFIG_MODULE_SIG_KEY="certs/signing_key.pem" --cfg=CONFIG_MODULE_SIG_KEY="certs/signing_key.pem"
--cfg=CONFIG_ARCH_MMAP_RND_BITS_MIN="14" --cfg=CONFIG_ARCH_MMAP_RND_BITS_MIN="14"
--cfg=CONFIG_USB_SERIAL_SYMBOL --cfg=CONFIG_USB_SERIAL_SYMBOL

View File

@ -308,6 +308,8 @@ struct mlx5_fc *mlx5_fc_create(struct mlx5_core_dev *dev, bool aging);
void mlx5_fc_destroy(struct mlx5_core_dev *dev, struct mlx5_fc *counter); void mlx5_fc_destroy(struct mlx5_core_dev *dev, struct mlx5_fc *counter);
struct mlx5_fc *mlx5_fc_local_create(u32 counter_id, u32 offset, u32 bulk_size); struct mlx5_fc *mlx5_fc_local_create(u32 counter_id, u32 offset, u32 bulk_size);
void mlx5_fc_local_destroy(struct mlx5_fc *counter); void mlx5_fc_local_destroy(struct mlx5_fc *counter);
void mlx5_fc_local_get(struct mlx5_fc *counter);
void mlx5_fc_local_put(struct mlx5_fc *counter);
u64 mlx5_fc_query_lastuse(struct mlx5_fc *counter); u64 mlx5_fc_query_lastuse(struct mlx5_fc *counter);
void mlx5_fc_query_cached(struct mlx5_fc *counter, void mlx5_fc_query_cached(struct mlx5_fc *counter,
u64 *bytes, u64 *packets, u64 *lastuse); u64 *bytes, u64 *packets, u64 *lastuse);

View File

@ -954,6 +954,7 @@ int sev_do_cmd(int cmd, void *data, int *psp_ret);
void *psp_copy_user_blob(u64 uaddr, u32 len); void *psp_copy_user_blob(u64 uaddr, u32 len);
void *snp_alloc_firmware_page(gfp_t mask); void *snp_alloc_firmware_page(gfp_t mask);
void snp_free_firmware_page(void *addr); void snp_free_firmware_page(void *addr);
void sev_platform_shutdown(void);
#else /* !CONFIG_CRYPTO_DEV_SP_PSP */ #else /* !CONFIG_CRYPTO_DEV_SP_PSP */
@ -988,6 +989,8 @@ static inline void *snp_alloc_firmware_page(gfp_t mask)
static inline void snp_free_firmware_page(void *addr) { } static inline void snp_free_firmware_page(void *addr) { }
static inline void sev_platform_shutdown(void) { }
#endif /* CONFIG_CRYPTO_DEV_SP_PSP */ #endif /* CONFIG_CRYPTO_DEV_SP_PSP */
#endif /* __PSP_SEV_H__ */ #endif /* __PSP_SEV_H__ */

View File

@ -548,6 +548,7 @@ struct hci_dev {
struct hci_conn_hash conn_hash; struct hci_conn_hash conn_hash;
struct list_head mesh_pending; struct list_head mesh_pending;
struct mutex mgmt_pending_lock;
struct list_head mgmt_pending; struct list_head mgmt_pending;
struct list_head reject_list; struct list_head reject_list;
struct list_head accept_list; struct list_head accept_list;
@ -1207,6 +1208,27 @@ static inline struct hci_conn *hci_conn_hash_lookup_ba(struct hci_dev *hdev,
return NULL; return NULL;
} }
static inline struct hci_conn *hci_conn_hash_lookup_role(struct hci_dev *hdev,
__u8 type, __u8 role,
bdaddr_t *ba)
{
struct hci_conn_hash *h = &hdev->conn_hash;
struct hci_conn *c;
rcu_read_lock();
list_for_each_entry_rcu(c, &h->list, list) {
if (c->type == type && c->role == role && !bacmp(&c->dst, ba)) {
rcu_read_unlock();
return c;
}
}
rcu_read_unlock();
return NULL;
}
static inline struct hci_conn *hci_conn_hash_lookup_le(struct hci_dev *hdev, static inline struct hci_conn *hci_conn_hash_lookup_le(struct hci_dev *hdev,
bdaddr_t *ba, bdaddr_t *ba,
__u8 ba_type) __u8 ba_type)
@ -2408,7 +2430,6 @@ void mgmt_advertising_added(struct sock *sk, struct hci_dev *hdev,
u8 instance); u8 instance);
void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev, void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev,
u8 instance); u8 instance);
void mgmt_adv_monitor_removed(struct hci_dev *hdev, u16 handle);
int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip); int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip);
void mgmt_adv_monitor_device_lost(struct hci_dev *hdev, u16 handle, void mgmt_adv_monitor_device_lost(struct hci_dev *hdev, u16 handle,
bdaddr_t *bdaddr, u8 addr_type); bdaddr_t *bdaddr, u8 addr_type);

View File

@ -93,7 +93,7 @@ int hci_update_class_sync(struct hci_dev *hdev);
int hci_update_eir_sync(struct hci_dev *hdev); int hci_update_eir_sync(struct hci_dev *hdev);
int hci_update_class_sync(struct hci_dev *hdev); int hci_update_class_sync(struct hci_dev *hdev);
int hci_update_name_sync(struct hci_dev *hdev); int hci_update_name_sync(struct hci_dev *hdev, const u8 *name);
int hci_write_ssp_mode_sync(struct hci_dev *hdev, u8 mode); int hci_write_ssp_mode_sync(struct hci_dev *hdev, u8 mode);
int hci_get_random_address(struct hci_dev *hdev, bool require_privacy, int hci_get_random_address(struct hci_dev *hdev, bool require_privacy,

View File

@ -848,7 +848,7 @@ struct mgmt_cp_set_mesh {
__le16 window; __le16 window;
__le16 period; __le16 period;
__u8 num_ad_types; __u8 num_ad_types;
__u8 ad_types[]; __u8 ad_types[] __counted_by(num_ad_types);
} __packed; } __packed;
#define MGMT_SET_MESH_RECEIVER_SIZE 6 #define MGMT_SET_MESH_RECEIVER_SIZE 6

View File

@ -272,13 +272,14 @@ static int io_waitid_wait(struct wait_queue_entry *wait, unsigned mode,
if (!pid_child_should_wake(wo, p)) if (!pid_child_should_wake(wo, p))
return 0; return 0;
list_del_init(&wait->entry);
/* cancel is in progress */ /* cancel is in progress */
if (atomic_fetch_inc(&iw->refs) & IO_WAITID_REF_MASK) if (atomic_fetch_inc(&iw->refs) & IO_WAITID_REF_MASK)
return 1; return 1;
req->io_task_work.func = io_waitid_cb; req->io_task_work.func = io_waitid_cb;
io_req_task_work_add(req); io_req_task_work_add(req);
list_del_init(&wait->entry);
return 1; return 1;
} }

View File

@ -1895,10 +1895,8 @@ void hci_free_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor)
if (monitor->handle) if (monitor->handle)
idr_remove(&hdev->adv_monitors_idr, monitor->handle); idr_remove(&hdev->adv_monitors_idr, monitor->handle);
if (monitor->state != ADV_MONITOR_STATE_NOT_REGISTERED) { if (monitor->state != ADV_MONITOR_STATE_NOT_REGISTERED)
hdev->adv_monitors_cnt--; hdev->adv_monitors_cnt--;
mgmt_adv_monitor_removed(hdev, monitor->handle);
}
kfree(monitor); kfree(monitor);
} }
@ -2510,6 +2508,7 @@ struct hci_dev *hci_alloc_dev_priv(int sizeof_priv)
mutex_init(&hdev->lock); mutex_init(&hdev->lock);
mutex_init(&hdev->req_lock); mutex_init(&hdev->req_lock);
mutex_init(&hdev->mgmt_pending_lock);
ida_init(&hdev->unset_handle_ida); ida_init(&hdev->unset_handle_ida);

View File

@ -3115,8 +3115,18 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, void *data,
hci_dev_lock(hdev); hci_dev_lock(hdev);
/* Check for existing connection:
*
* 1. If it doesn't exist then it must be receiver/slave role.
* 2. If it does exist confirm that it is connecting/BT_CONNECT in case
* of initiator/master role since there could be a collision where
* either side is attempting to connect or something like a fuzzing
* testing is trying to play tricks to destroy the hcon object before
* it even attempts to connect (e.g. hcon->state == BT_OPEN).
*/
conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr); conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr);
if (!conn) { if (!conn ||
(conn->role == HCI_ROLE_MASTER && conn->state != BT_CONNECT)) {
/* In case of error status and there is no connection pending /* In case of error status and there is no connection pending
* just unlock as there is nothing to cleanup. * just unlock as there is nothing to cleanup.
*/ */
@ -4422,6 +4432,8 @@ static void hci_num_comp_pkts_evt(struct hci_dev *hdev, void *data,
bt_dev_dbg(hdev, "num %d", ev->num); bt_dev_dbg(hdev, "num %d", ev->num);
hci_dev_lock(hdev);
for (i = 0; i < ev->num; i++) { for (i = 0; i < ev->num; i++) {
struct hci_comp_pkts_info *info = &ev->handles[i]; struct hci_comp_pkts_info *info = &ev->handles[i];
struct hci_conn *conn; struct hci_conn *conn;
@ -4491,6 +4503,8 @@ static void hci_num_comp_pkts_evt(struct hci_dev *hdev, void *data,
} }
queue_work(hdev->workqueue, &hdev->tx_work); queue_work(hdev->workqueue, &hdev->tx_work);
hci_dev_unlock(hdev);
} }
static void hci_mode_change_evt(struct hci_dev *hdev, void *data, static void hci_mode_change_evt(struct hci_dev *hdev, void *data,
@ -5653,8 +5667,18 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,
*/ */
hci_dev_clear_flag(hdev, HCI_LE_ADV); hci_dev_clear_flag(hdev, HCI_LE_ADV);
conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr); /* Check for existing connection:
if (!conn) { *
* 1. If it doesn't exist then use the role to create a new object.
* 2. If it does exist confirm that it is connecting/BT_CONNECT in case
* of initiator/master role since there could be a collision where
* either side is attempting to connect or something like a fuzzing
* testing is trying to play tricks to destroy the hcon object before
* it even attempts to connect (e.g. hcon->state == BT_OPEN).
*/
conn = hci_conn_hash_lookup_role(hdev, LE_LINK, role, bdaddr);
if (!conn ||
(conn->role == HCI_ROLE_MASTER && conn->state != BT_CONNECT)) {
/* In case of error status and there is no connection pending /* In case of error status and there is no connection pending
* just unlock as there is nothing to cleanup. * just unlock as there is nothing to cleanup.
*/ */

View File

@ -3412,13 +3412,13 @@ int hci_update_scan_sync(struct hci_dev *hdev)
return hci_write_scan_enable_sync(hdev, scan); return hci_write_scan_enable_sync(hdev, scan);
} }
int hci_update_name_sync(struct hci_dev *hdev) int hci_update_name_sync(struct hci_dev *hdev, const u8 *name)
{ {
struct hci_cp_write_local_name cp; struct hci_cp_write_local_name cp;
memset(&cp, 0, sizeof(cp)); memset(&cp, 0, sizeof(cp));
memcpy(cp.name, hdev->dev_name, sizeof(cp.name)); memcpy(cp.name, name, sizeof(cp.name));
return __hci_cmd_sync_status(hdev, HCI_OP_WRITE_LOCAL_NAME, return __hci_cmd_sync_status(hdev, HCI_OP_WRITE_LOCAL_NAME,
sizeof(cp), &cp, sizeof(cp), &cp,
@ -3471,7 +3471,7 @@ int hci_powered_update_sync(struct hci_dev *hdev)
hci_write_fast_connectable_sync(hdev, false); hci_write_fast_connectable_sync(hdev, false);
hci_update_scan_sync(hdev); hci_update_scan_sync(hdev);
hci_update_class_sync(hdev); hci_update_class_sync(hdev);
hci_update_name_sync(hdev); hci_update_name_sync(hdev, hdev->dev_name);
hci_update_eir_sync(hdev); hci_update_eir_sync(hdev);
} }

View File

@ -1324,8 +1324,7 @@ static void mgmt_set_powered_complete(struct hci_dev *hdev, void *data, int err)
struct mgmt_mode *cp; struct mgmt_mode *cp;
/* Make sure cmd still outstanding. */ /* Make sure cmd still outstanding. */
if (err == -ECANCELED || if (err == -ECANCELED || !mgmt_pending_valid(hdev, cmd))
cmd != pending_find(MGMT_OP_SET_POWERED, hdev))
return; return;
cp = cmd->param; cp = cmd->param;
@ -1352,23 +1351,29 @@ static void mgmt_set_powered_complete(struct hci_dev *hdev, void *data, int err)
mgmt_status(err)); mgmt_status(err));
} }
mgmt_pending_remove(cmd); mgmt_pending_free(cmd);
} }
static int set_powered_sync(struct hci_dev *hdev, void *data) static int set_powered_sync(struct hci_dev *hdev, void *data)
{ {
struct mgmt_pending_cmd *cmd = data; struct mgmt_pending_cmd *cmd = data;
struct mgmt_mode *cp; struct mgmt_mode cp;
mutex_lock(&hdev->mgmt_pending_lock);
/* Make sure cmd still outstanding. */ /* Make sure cmd still outstanding. */
if (cmd != pending_find(MGMT_OP_SET_POWERED, hdev)) if (!__mgmt_pending_listed(hdev, cmd)) {
mutex_unlock(&hdev->mgmt_pending_lock);
return -ECANCELED; return -ECANCELED;
}
cp = cmd->param; memcpy(&cp, cmd->param, sizeof(cp));
mutex_unlock(&hdev->mgmt_pending_lock);
BT_DBG("%s", hdev->name); BT_DBG("%s", hdev->name);
return hci_set_powered_sync(hdev, cp->val); return hci_set_powered_sync(hdev, cp.val);
} }
static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data, static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
@ -1447,22 +1452,17 @@ static void settings_rsp(struct mgmt_pending_cmd *cmd, void *data)
send_settings_rsp(cmd->sk, cmd->opcode, match->hdev); send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
list_del(&cmd->list);
if (match->sk == NULL) { if (match->sk == NULL) {
match->sk = cmd->sk; match->sk = cmd->sk;
sock_hold(match->sk); sock_hold(match->sk);
} }
mgmt_pending_free(cmd);
} }
static void cmd_status_rsp(struct mgmt_pending_cmd *cmd, void *data) static void cmd_status_rsp(struct mgmt_pending_cmd *cmd, void *data)
{ {
u8 *status = data; u8 *status = data;
mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, *status); mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, *status);
mgmt_pending_remove(cmd);
} }
static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data) static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
@ -1476,8 +1476,6 @@ static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
if (cmd->cmd_complete) { if (cmd->cmd_complete) {
cmd->cmd_complete(cmd, match->mgmt_status); cmd->cmd_complete(cmd, match->mgmt_status);
mgmt_pending_remove(cmd);
return; return;
} }
@ -1486,13 +1484,13 @@ static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
static int generic_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status) static int generic_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
{ {
return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, return mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, status,
cmd->param, cmd->param_len); cmd->param, cmd->param_len);
} }
static int addr_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status) static int addr_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
{ {
return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, return mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, status,
cmd->param, sizeof(struct mgmt_addr_info)); cmd->param, sizeof(struct mgmt_addr_info));
} }
@ -1524,15 +1522,14 @@ static void mgmt_set_discoverable_complete(struct hci_dev *hdev, void *data,
bt_dev_dbg(hdev, "err %d", err); bt_dev_dbg(hdev, "err %d", err);
/* Make sure cmd still outstanding. */ /* Make sure cmd still outstanding. */
if (err == -ECANCELED || if (err == -ECANCELED || !mgmt_pending_valid(hdev, cmd))
cmd != pending_find(MGMT_OP_SET_DISCOVERABLE, hdev))
return; return;
hci_dev_lock(hdev); hci_dev_lock(hdev);
if (err) { if (err) {
u8 mgmt_err = mgmt_status(err); u8 mgmt_err = mgmt_status(err);
mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err); mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_err);
hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE); hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
goto done; goto done;
} }
@ -1547,12 +1544,15 @@ static void mgmt_set_discoverable_complete(struct hci_dev *hdev, void *data,
new_settings(hdev, cmd->sk); new_settings(hdev, cmd->sk);
done: done:
mgmt_pending_remove(cmd); mgmt_pending_free(cmd);
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
} }
static int set_discoverable_sync(struct hci_dev *hdev, void *data) static int set_discoverable_sync(struct hci_dev *hdev, void *data)
{ {
if (!mgmt_pending_listed(hdev, data))
return -ECANCELED;
BT_DBG("%s", hdev->name); BT_DBG("%s", hdev->name);
return hci_update_discoverable_sync(hdev); return hci_update_discoverable_sync(hdev);
@ -1699,15 +1699,14 @@ static void mgmt_set_connectable_complete(struct hci_dev *hdev, void *data,
bt_dev_dbg(hdev, "err %d", err); bt_dev_dbg(hdev, "err %d", err);
/* Make sure cmd still outstanding. */ /* Make sure cmd still outstanding. */
if (err == -ECANCELED || if (err == -ECANCELED || !mgmt_pending_valid(hdev, cmd))
cmd != pending_find(MGMT_OP_SET_CONNECTABLE, hdev))
return; return;
hci_dev_lock(hdev); hci_dev_lock(hdev);
if (err) { if (err) {
u8 mgmt_err = mgmt_status(err); u8 mgmt_err = mgmt_status(err);
mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err); mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_err);
goto done; goto done;
} }
@ -1715,7 +1714,7 @@ static void mgmt_set_connectable_complete(struct hci_dev *hdev, void *data,
new_settings(hdev, cmd->sk); new_settings(hdev, cmd->sk);
done: done:
mgmt_pending_remove(cmd); mgmt_pending_free(cmd);
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
} }
@ -1751,6 +1750,9 @@ static int set_connectable_update_settings(struct hci_dev *hdev,
static int set_connectable_sync(struct hci_dev *hdev, void *data) static int set_connectable_sync(struct hci_dev *hdev, void *data)
{ {
if (!mgmt_pending_listed(hdev, data))
return -ECANCELED;
BT_DBG("%s", hdev->name); BT_DBG("%s", hdev->name);
return hci_update_connectable_sync(hdev); return hci_update_connectable_sync(hdev);
@ -1927,14 +1929,17 @@ static void set_ssp_complete(struct hci_dev *hdev, void *data, int err)
{ {
struct cmd_lookup match = { NULL, hdev }; struct cmd_lookup match = { NULL, hdev };
struct mgmt_pending_cmd *cmd = data; struct mgmt_pending_cmd *cmd = data;
struct mgmt_mode *cp = cmd->param; struct mgmt_mode *cp;
u8 enable = cp->val; u8 enable;
bool changed; bool changed;
/* Make sure cmd still outstanding. */ /* Make sure cmd still outstanding. */
if (err == -ECANCELED || cmd != pending_find(MGMT_OP_SET_SSP, hdev)) if (err == -ECANCELED || !mgmt_pending_valid(hdev, cmd))
return; return;
cp = cmd->param;
enable = cp->val;
if (err) { if (err) {
u8 mgmt_err = mgmt_status(err); u8 mgmt_err = mgmt_status(err);
@ -1943,8 +1948,7 @@ static void set_ssp_complete(struct hci_dev *hdev, void *data, int err)
new_settings(hdev, NULL); new_settings(hdev, NULL);
} }
mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp, mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_err);
&mgmt_err);
return; return;
} }
@ -1954,7 +1958,7 @@ static void set_ssp_complete(struct hci_dev *hdev, void *data, int err)
changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED); changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED);
} }
mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match); settings_rsp(cmd, &match);
if (changed) if (changed)
new_settings(hdev, match.sk); new_settings(hdev, match.sk);
@ -1968,14 +1972,25 @@ static void set_ssp_complete(struct hci_dev *hdev, void *data, int err)
static int set_ssp_sync(struct hci_dev *hdev, void *data) static int set_ssp_sync(struct hci_dev *hdev, void *data)
{ {
struct mgmt_pending_cmd *cmd = data; struct mgmt_pending_cmd *cmd = data;
struct mgmt_mode *cp = cmd->param; struct mgmt_mode cp;
bool changed = false; bool changed = false;
int err; int err;
if (cp->val) mutex_lock(&hdev->mgmt_pending_lock);
if (!__mgmt_pending_listed(hdev, cmd)) {
mutex_unlock(&hdev->mgmt_pending_lock);
return -ECANCELED;
}
memcpy(&cp, cmd->param, sizeof(cp));
mutex_unlock(&hdev->mgmt_pending_lock);
if (cp.val)
changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED); changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED);
err = hci_write_ssp_mode_sync(hdev, cp->val); err = hci_write_ssp_mode_sync(hdev, cp.val);
if (!err && changed) if (!err && changed)
hci_dev_clear_flag(hdev, HCI_SSP_ENABLED); hci_dev_clear_flag(hdev, HCI_SSP_ENABLED);
@ -2068,32 +2083,50 @@ static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
static void set_le_complete(struct hci_dev *hdev, void *data, int err) static void set_le_complete(struct hci_dev *hdev, void *data, int err)
{ {
struct mgmt_pending_cmd *cmd = data;
struct cmd_lookup match = { NULL, hdev }; struct cmd_lookup match = { NULL, hdev };
u8 status = mgmt_status(err); u8 status = mgmt_status(err);
bt_dev_dbg(hdev, "err %d", err); bt_dev_dbg(hdev, "err %d", err);
if (status) { if (err == -ECANCELED || !mgmt_pending_valid(hdev, data))
mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
&status);
return; return;
if (status) {
mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, status);
goto done;
} }
mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match); settings_rsp(cmd, &match);
new_settings(hdev, match.sk); new_settings(hdev, match.sk);
if (match.sk) if (match.sk)
sock_put(match.sk); sock_put(match.sk);
done:
mgmt_pending_free(cmd);
} }
static int set_le_sync(struct hci_dev *hdev, void *data) static int set_le_sync(struct hci_dev *hdev, void *data)
{ {
struct mgmt_pending_cmd *cmd = data; struct mgmt_pending_cmd *cmd = data;
struct mgmt_mode *cp = cmd->param; struct mgmt_mode cp;
u8 val = !!cp->val; u8 val;
int err; int err;
mutex_lock(&hdev->mgmt_pending_lock);
if (!__mgmt_pending_listed(hdev, cmd)) {
mutex_unlock(&hdev->mgmt_pending_lock);
return -ECANCELED;
}
memcpy(&cp, cmd->param, sizeof(cp));
val = !!cp.val;
mutex_unlock(&hdev->mgmt_pending_lock);
if (!val) { if (!val) {
hci_clear_adv_instance_sync(hdev, NULL, 0x00, true); hci_clear_adv_instance_sync(hdev, NULL, 0x00, true);
@ -2135,23 +2168,45 @@ static void set_mesh_complete(struct hci_dev *hdev, void *data, int err)
{ {
struct mgmt_pending_cmd *cmd = data; struct mgmt_pending_cmd *cmd = data;
u8 status = mgmt_status(err); u8 status = mgmt_status(err);
struct sock *sk = cmd->sk; struct sock *sk;
if (err == -ECANCELED || !mgmt_pending_valid(hdev, cmd))
return;
sk = cmd->sk;
if (status) { if (status) {
mgmt_pending_foreach(MGMT_OP_SET_MESH_RECEIVER, hdev, mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_MESH_RECEIVER,
status);
mgmt_pending_foreach(MGMT_OP_SET_MESH_RECEIVER, hdev, true,
cmd_status_rsp, &status); cmd_status_rsp, &status);
return; goto done;
} }
mgmt_pending_remove(cmd);
mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_MESH_RECEIVER, 0, NULL, 0); mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_MESH_RECEIVER, 0, NULL, 0);
done:
mgmt_pending_free(cmd);
} }
static int set_mesh_sync(struct hci_dev *hdev, void *data) static int set_mesh_sync(struct hci_dev *hdev, void *data)
{ {
struct mgmt_pending_cmd *cmd = data; struct mgmt_pending_cmd *cmd = data;
struct mgmt_cp_set_mesh *cp = cmd->param; DEFINE_FLEX(struct mgmt_cp_set_mesh, cp, ad_types, num_ad_types,
size_t len = cmd->param_len; sizeof(hdev->mesh_ad_types));
size_t len;
mutex_lock(&hdev->mgmt_pending_lock);
if (!__mgmt_pending_listed(hdev, cmd)) {
mutex_unlock(&hdev->mgmt_pending_lock);
return -ECANCELED;
}
len = cmd->param_len;
memcpy(cp, cmd->param, min(__struct_size(cp), len));
mutex_unlock(&hdev->mgmt_pending_lock);
memset(hdev->mesh_ad_types, 0, sizeof(hdev->mesh_ad_types)); memset(hdev->mesh_ad_types, 0, sizeof(hdev->mesh_ad_types));
@ -2160,7 +2215,10 @@ static int set_mesh_sync(struct hci_dev *hdev, void *data)
else else
hci_dev_clear_flag(hdev, HCI_MESH); hci_dev_clear_flag(hdev, HCI_MESH);
len -= sizeof(*cp); hdev->le_scan_interval = __le16_to_cpu(cp->period);
hdev->le_scan_window = __le16_to_cpu(cp->window);
len -= sizeof(struct mgmt_cp_set_mesh);
/* If filters don't fit, forward all adv pkts */ /* If filters don't fit, forward all adv pkts */
if (len <= sizeof(hdev->mesh_ad_types)) if (len <= sizeof(hdev->mesh_ad_types))
@ -2174,6 +2232,7 @@ static int set_mesh(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
{ {
struct mgmt_cp_set_mesh *cp = data; struct mgmt_cp_set_mesh *cp = data;
struct mgmt_pending_cmd *cmd; struct mgmt_pending_cmd *cmd;
__u16 period, window;
int err = 0; int err = 0;
bt_dev_dbg(hdev, "sock %p", sk); bt_dev_dbg(hdev, "sock %p", sk);
@ -2187,6 +2246,23 @@ static int set_mesh(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_MESH_RECEIVER, return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_MESH_RECEIVER,
MGMT_STATUS_INVALID_PARAMS); MGMT_STATUS_INVALID_PARAMS);
/* Keep allowed ranges in sync with set_scan_params() */
period = __le16_to_cpu(cp->period);
if (period < 0x0004 || period > 0x4000)
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_MESH_RECEIVER,
MGMT_STATUS_INVALID_PARAMS);
window = __le16_to_cpu(cp->window);
if (window < 0x0004 || window > 0x4000)
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_MESH_RECEIVER,
MGMT_STATUS_INVALID_PARAMS);
if (window > period)
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_MESH_RECEIVER,
MGMT_STATUS_INVALID_PARAMS);
hci_dev_lock(hdev); hci_dev_lock(hdev);
cmd = mgmt_pending_add(sk, MGMT_OP_SET_MESH_RECEIVER, hdev, data, len); cmd = mgmt_pending_add(sk, MGMT_OP_SET_MESH_RECEIVER, hdev, data, len);
@ -2637,7 +2713,7 @@ static void mgmt_class_complete(struct hci_dev *hdev, void *data, int err)
bt_dev_dbg(hdev, "err %d", err); bt_dev_dbg(hdev, "err %d", err);
mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode,
mgmt_status(err), hdev->dev_class, 3); mgmt_status(err), hdev->dev_class, 3);
mgmt_pending_free(cmd); mgmt_pending_free(cmd);
@ -3425,7 +3501,7 @@ static int pairing_complete(struct mgmt_pending_cmd *cmd, u8 status)
bacpy(&rp.addr.bdaddr, &conn->dst); bacpy(&rp.addr.bdaddr, &conn->dst);
rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type); rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, err = mgmt_cmd_complete(cmd->sk, cmd->hdev->id, MGMT_OP_PAIR_DEVICE,
status, &rp, sizeof(rp)); status, &rp, sizeof(rp));
/* So we don't get further callbacks for this connection */ /* So we don't get further callbacks for this connection */
@ -3851,15 +3927,16 @@ static int name_changed_sync(struct hci_dev *hdev, void *data)
static void set_name_complete(struct hci_dev *hdev, void *data, int err) static void set_name_complete(struct hci_dev *hdev, void *data, int err)
{ {
struct mgmt_pending_cmd *cmd = data; struct mgmt_pending_cmd *cmd = data;
struct mgmt_cp_set_local_name *cp = cmd->param; struct mgmt_cp_set_local_name *cp;
u8 status = mgmt_status(err); u8 status = mgmt_status(err);
bt_dev_dbg(hdev, "err %d", err); bt_dev_dbg(hdev, "err %d", err);
if (err == -ECANCELED || if (err == -ECANCELED || !mgmt_pending_valid(hdev, cmd))
cmd != pending_find(MGMT_OP_SET_LOCAL_NAME, hdev))
return; return;
cp = cmd->param;
if (status) { if (status) {
mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
status); status);
@ -3871,13 +3948,27 @@ static void set_name_complete(struct hci_dev *hdev, void *data, int err)
hci_cmd_sync_queue(hdev, name_changed_sync, NULL, NULL); hci_cmd_sync_queue(hdev, name_changed_sync, NULL, NULL);
} }
mgmt_pending_remove(cmd); mgmt_pending_free(cmd);
} }
static int set_name_sync(struct hci_dev *hdev, void *data) static int set_name_sync(struct hci_dev *hdev, void *data)
{ {
struct mgmt_pending_cmd *cmd = data;
struct mgmt_cp_set_local_name cp;
mutex_lock(&hdev->mgmt_pending_lock);
if (!__mgmt_pending_listed(hdev, cmd)) {
mutex_unlock(&hdev->mgmt_pending_lock);
return -ECANCELED;
}
memcpy(&cp, cmd->param, sizeof(cp));
mutex_unlock(&hdev->mgmt_pending_lock);
if (lmp_bredr_capable(hdev)) { if (lmp_bredr_capable(hdev)) {
hci_update_name_sync(hdev); hci_update_name_sync(hdev, cp.name);
hci_update_eir_sync(hdev); hci_update_eir_sync(hdev);
} }
@ -4029,12 +4120,10 @@ int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip)
static void set_default_phy_complete(struct hci_dev *hdev, void *data, int err) static void set_default_phy_complete(struct hci_dev *hdev, void *data, int err)
{ {
struct mgmt_pending_cmd *cmd = data; struct mgmt_pending_cmd *cmd = data;
struct sk_buff *skb = cmd->skb; struct sk_buff *skb;
u8 status = mgmt_status(err); u8 status = mgmt_status(err);
if (err == -ECANCELED || skb = cmd->skb;
cmd != pending_find(MGMT_OP_SET_PHY_CONFIGURATION, hdev))
return;
if (!status) { if (!status) {
if (!skb) if (!skb)
@ -4061,7 +4150,7 @@ static void set_default_phy_complete(struct hci_dev *hdev, void *data, int err)
if (skb && !IS_ERR(skb)) if (skb && !IS_ERR(skb))
kfree_skb(skb); kfree_skb(skb);
mgmt_pending_remove(cmd); mgmt_pending_free(cmd);
} }
static int set_default_phy_sync(struct hci_dev *hdev, void *data) static int set_default_phy_sync(struct hci_dev *hdev, void *data)
@ -4069,7 +4158,9 @@ static int set_default_phy_sync(struct hci_dev *hdev, void *data)
struct mgmt_pending_cmd *cmd = data; struct mgmt_pending_cmd *cmd = data;
struct mgmt_cp_set_phy_configuration *cp = cmd->param; struct mgmt_cp_set_phy_configuration *cp = cmd->param;
struct hci_cp_le_set_default_phy cp_phy; struct hci_cp_le_set_default_phy cp_phy;
u32 selected_phys = __le32_to_cpu(cp->selected_phys); u32 selected_phys;
selected_phys = __le32_to_cpu(cp->selected_phys);
memset(&cp_phy, 0, sizeof(cp_phy)); memset(&cp_phy, 0, sizeof(cp_phy));
@ -4209,7 +4300,7 @@ static int set_phy_configuration(struct sock *sk, struct hci_dev *hdev,
goto unlock; goto unlock;
} }
cmd = mgmt_pending_add(sk, MGMT_OP_SET_PHY_CONFIGURATION, hdev, data, cmd = mgmt_pending_new(sk, MGMT_OP_SET_PHY_CONFIGURATION, hdev, data,
len); len);
if (!cmd) if (!cmd)
err = -ENOMEM; err = -ENOMEM;
@ -5106,24 +5197,14 @@ static void mgmt_adv_monitor_added(struct sock *sk, struct hci_dev *hdev,
mgmt_event(MGMT_EV_ADV_MONITOR_ADDED, hdev, &ev, sizeof(ev), sk); mgmt_event(MGMT_EV_ADV_MONITOR_ADDED, hdev, &ev, sizeof(ev), sk);
} }
void mgmt_adv_monitor_removed(struct hci_dev *hdev, u16 handle) static void mgmt_adv_monitor_removed(struct sock *sk, struct hci_dev *hdev,
__le16 handle)
{ {
struct mgmt_ev_adv_monitor_removed ev; struct mgmt_ev_adv_monitor_removed ev;
struct mgmt_pending_cmd *cmd;
struct sock *sk_skip = NULL;
struct mgmt_cp_remove_adv_monitor *cp;
cmd = pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev); ev.monitor_handle = handle;
if (cmd) {
cp = cmd->param;
if (cp->monitor_handle) mgmt_event(MGMT_EV_ADV_MONITOR_REMOVED, hdev, &ev, sizeof(ev), sk);
sk_skip = cmd->sk;
}
ev.monitor_handle = cpu_to_le16(handle);
mgmt_event(MGMT_EV_ADV_MONITOR_REMOVED, hdev, &ev, sizeof(ev), sk_skip);
} }
static int read_adv_mon_features(struct sock *sk, struct hci_dev *hdev, static int read_adv_mon_features(struct sock *sk, struct hci_dev *hdev,
@ -5180,7 +5261,17 @@ static void mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev,
{ {
struct mgmt_rp_add_adv_patterns_monitor rp; struct mgmt_rp_add_adv_patterns_monitor rp;
struct mgmt_pending_cmd *cmd = data; struct mgmt_pending_cmd *cmd = data;
struct adv_monitor *monitor = cmd->user_data; struct adv_monitor *monitor;
/* This is likely the result of hdev being closed and mgmt_index_removed
* is attempting to clean up any pending command so
* hci_adv_monitors_clear is about to be called which will take care of
* freeing the adv_monitor instances.
*/
if (status == -ECANCELED && !mgmt_pending_valid(hdev, cmd))
return;
monitor = cmd->user_data;
hci_dev_lock(hdev); hci_dev_lock(hdev);
@ -5194,7 +5285,7 @@ static void mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev,
hci_update_passive_scan(hdev); hci_update_passive_scan(hdev);
} }
mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode,
mgmt_status(status), &rp, sizeof(rp)); mgmt_status(status), &rp, sizeof(rp));
mgmt_pending_remove(cmd); mgmt_pending_remove(cmd);
@ -5206,9 +5297,20 @@ static void mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev,
static int mgmt_add_adv_patterns_monitor_sync(struct hci_dev *hdev, void *data) static int mgmt_add_adv_patterns_monitor_sync(struct hci_dev *hdev, void *data)
{ {
struct mgmt_pending_cmd *cmd = data; struct mgmt_pending_cmd *cmd = data;
struct adv_monitor *monitor = cmd->user_data; struct adv_monitor *mon;
return hci_add_adv_monitor(hdev, monitor); mutex_lock(&hdev->mgmt_pending_lock);
if (!__mgmt_pending_listed(hdev, cmd)) {
mutex_unlock(&hdev->mgmt_pending_lock);
return -ECANCELED;
}
mon = cmd->user_data;
mutex_unlock(&hdev->mgmt_pending_lock);
return hci_add_adv_monitor(hdev, mon);
} }
static int __add_adv_patterns_monitor(struct sock *sk, struct hci_dev *hdev, static int __add_adv_patterns_monitor(struct sock *sk, struct hci_dev *hdev,
@ -5225,8 +5327,7 @@ static int __add_adv_patterns_monitor(struct sock *sk, struct hci_dev *hdev,
if (pending_find(MGMT_OP_SET_LE, hdev) || if (pending_find(MGMT_OP_SET_LE, hdev) ||
pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR, hdev) || pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR, hdev) ||
pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI, hdev) || pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI, hdev)) {
pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev)) {
status = MGMT_STATUS_BUSY; status = MGMT_STATUS_BUSY;
goto unlock; goto unlock;
} }
@ -5396,8 +5497,7 @@ static void mgmt_remove_adv_monitor_complete(struct hci_dev *hdev,
struct mgmt_pending_cmd *cmd = data; struct mgmt_pending_cmd *cmd = data;
struct mgmt_cp_remove_adv_monitor *cp; struct mgmt_cp_remove_adv_monitor *cp;
if (status == -ECANCELED || if (status == -ECANCELED)
cmd != pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev))
return; return;
hci_dev_lock(hdev); hci_dev_lock(hdev);
@ -5406,12 +5506,14 @@ static void mgmt_remove_adv_monitor_complete(struct hci_dev *hdev,
rp.monitor_handle = cp->monitor_handle; rp.monitor_handle = cp->monitor_handle;
if (!status) if (!status) {
mgmt_adv_monitor_removed(cmd->sk, hdev, cp->monitor_handle);
hci_update_passive_scan(hdev); hci_update_passive_scan(hdev);
}
mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode,
mgmt_status(status), &rp, sizeof(rp)); mgmt_status(status), &rp, sizeof(rp));
mgmt_pending_remove(cmd); mgmt_pending_free(cmd);
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
bt_dev_dbg(hdev, "remove monitor %d complete, status %d", bt_dev_dbg(hdev, "remove monitor %d complete, status %d",
@ -5421,10 +5523,6 @@ static void mgmt_remove_adv_monitor_complete(struct hci_dev *hdev,
static int mgmt_remove_adv_monitor_sync(struct hci_dev *hdev, void *data) static int mgmt_remove_adv_monitor_sync(struct hci_dev *hdev, void *data)
{ {
struct mgmt_pending_cmd *cmd = data; struct mgmt_pending_cmd *cmd = data;
if (cmd != pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev))
return -ECANCELED;
struct mgmt_cp_remove_adv_monitor *cp = cmd->param; struct mgmt_cp_remove_adv_monitor *cp = cmd->param;
u16 handle = __le16_to_cpu(cp->monitor_handle); u16 handle = __le16_to_cpu(cp->monitor_handle);
@ -5443,14 +5541,13 @@ static int remove_adv_monitor(struct sock *sk, struct hci_dev *hdev,
hci_dev_lock(hdev); hci_dev_lock(hdev);
if (pending_find(MGMT_OP_SET_LE, hdev) || if (pending_find(MGMT_OP_SET_LE, hdev) ||
pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev) ||
pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR, hdev) || pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR, hdev) ||
pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI, hdev)) { pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI, hdev)) {
status = MGMT_STATUS_BUSY; status = MGMT_STATUS_BUSY;
goto unlock; goto unlock;
} }
cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_ADV_MONITOR, hdev, data, len); cmd = mgmt_pending_new(sk, MGMT_OP_REMOVE_ADV_MONITOR, hdev, data, len);
if (!cmd) { if (!cmd) {
status = MGMT_STATUS_NO_RESOURCES; status = MGMT_STATUS_NO_RESOURCES;
goto unlock; goto unlock;
@ -5460,7 +5557,7 @@ static int remove_adv_monitor(struct sock *sk, struct hci_dev *hdev,
mgmt_remove_adv_monitor_complete); mgmt_remove_adv_monitor_complete);
if (err) { if (err) {
mgmt_pending_remove(cmd); mgmt_pending_free(cmd);
if (err == -ENOMEM) if (err == -ENOMEM)
status = MGMT_STATUS_NO_RESOURCES; status = MGMT_STATUS_NO_RESOURCES;
@ -5480,7 +5577,8 @@ unlock:
status); status);
} }
static void read_local_oob_data_complete(struct hci_dev *hdev, void *data, int err) static void read_local_oob_data_complete(struct hci_dev *hdev, void *data,
int err)
{ {
struct mgmt_rp_read_local_oob_data mgmt_rp; struct mgmt_rp_read_local_oob_data mgmt_rp;
size_t rp_size = sizeof(mgmt_rp); size_t rp_size = sizeof(mgmt_rp);
@ -5500,7 +5598,8 @@ static void read_local_oob_data_complete(struct hci_dev *hdev, void *data, int e
bt_dev_dbg(hdev, "status %d", status); bt_dev_dbg(hdev, "status %d", status);
if (status) { if (status) {
mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA, status); mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
status);
goto remove; goto remove;
} }
@ -5782,17 +5881,12 @@ static void start_discovery_complete(struct hci_dev *hdev, void *data, int err)
bt_dev_dbg(hdev, "err %d", err); bt_dev_dbg(hdev, "err %d", err);
if (err == -ECANCELED) if (err == -ECANCELED || !mgmt_pending_valid(hdev, cmd))
return; return;
if (cmd != pending_find(MGMT_OP_START_DISCOVERY, hdev) && mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_status(err),
cmd != pending_find(MGMT_OP_START_LIMITED_DISCOVERY, hdev) &&
cmd != pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev))
return;
mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(err),
cmd->param, 1); cmd->param, 1);
mgmt_pending_remove(cmd); mgmt_pending_free(cmd);
hci_discovery_set_state(hdev, err ? DISCOVERY_STOPPED: hci_discovery_set_state(hdev, err ? DISCOVERY_STOPPED:
DISCOVERY_FINDING); DISCOVERY_FINDING);
@ -5800,6 +5894,9 @@ static void start_discovery_complete(struct hci_dev *hdev, void *data, int err)
static int start_discovery_sync(struct hci_dev *hdev, void *data) static int start_discovery_sync(struct hci_dev *hdev, void *data)
{ {
if (!mgmt_pending_listed(hdev, data))
return -ECANCELED;
return hci_start_discovery_sync(hdev); return hci_start_discovery_sync(hdev);
} }
@ -6005,15 +6102,14 @@ static void stop_discovery_complete(struct hci_dev *hdev, void *data, int err)
{ {
struct mgmt_pending_cmd *cmd = data; struct mgmt_pending_cmd *cmd = data;
if (err == -ECANCELED || if (err == -ECANCELED || !mgmt_pending_valid(hdev, cmd))
cmd != pending_find(MGMT_OP_STOP_DISCOVERY, hdev))
return; return;
bt_dev_dbg(hdev, "err %d", err); bt_dev_dbg(hdev, "err %d", err);
mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(err), mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_status(err),
cmd->param, 1); cmd->param, 1);
mgmt_pending_remove(cmd); mgmt_pending_free(cmd);
if (!err) if (!err)
hci_discovery_set_state(hdev, DISCOVERY_STOPPED); hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
@ -6021,6 +6117,9 @@ static void stop_discovery_complete(struct hci_dev *hdev, void *data, int err)
static int stop_discovery_sync(struct hci_dev *hdev, void *data) static int stop_discovery_sync(struct hci_dev *hdev, void *data)
{ {
if (!mgmt_pending_listed(hdev, data))
return -ECANCELED;
return hci_stop_discovery_sync(hdev); return hci_stop_discovery_sync(hdev);
} }
@ -6230,14 +6329,18 @@ static void enable_advertising_instance(struct hci_dev *hdev, int err)
static void set_advertising_complete(struct hci_dev *hdev, void *data, int err) static void set_advertising_complete(struct hci_dev *hdev, void *data, int err)
{ {
struct mgmt_pending_cmd *cmd = data;
struct cmd_lookup match = { NULL, hdev }; struct cmd_lookup match = { NULL, hdev };
u8 instance; u8 instance;
struct adv_info *adv_instance; struct adv_info *adv_instance;
u8 status = mgmt_status(err); u8 status = mgmt_status(err);
if (err == -ECANCELED || !mgmt_pending_valid(hdev, data))
return;
if (status) { if (status) {
mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, status);
cmd_status_rsp, &status); mgmt_pending_free(cmd);
return; return;
} }
@ -6246,8 +6349,7 @@ static void set_advertising_complete(struct hci_dev *hdev, void *data, int err)
else else
hci_dev_clear_flag(hdev, HCI_ADVERTISING); hci_dev_clear_flag(hdev, HCI_ADVERTISING);
mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp, settings_rsp(cmd, &match);
&match);
new_settings(hdev, match.sk); new_settings(hdev, match.sk);
@ -6279,10 +6381,23 @@ static void set_advertising_complete(struct hci_dev *hdev, void *data, int err)
static int set_adv_sync(struct hci_dev *hdev, void *data) static int set_adv_sync(struct hci_dev *hdev, void *data)
{ {
struct mgmt_pending_cmd *cmd = data; struct mgmt_pending_cmd *cmd = data;
struct mgmt_mode *cp = cmd->param; struct mgmt_mode cp;
u8 val = !!cp->val; u8 val;
if (cp->val == 0x02) mutex_lock(&hdev->mgmt_pending_lock);
if (!__mgmt_pending_listed(hdev, cmd)) {
mutex_unlock(&hdev->mgmt_pending_lock);
return -ECANCELED;
}
memcpy(&cp, cmd->param, sizeof(cp));
mutex_unlock(&hdev->mgmt_pending_lock);
val = !!cp.val;
if (cp.val == 0x02)
hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE); hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
else else
hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE); hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
@ -6452,6 +6567,7 @@ static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
MGMT_STATUS_NOT_SUPPORTED); MGMT_STATUS_NOT_SUPPORTED);
/* Keep allowed ranges in sync with set_mesh() */
interval = __le16_to_cpu(cp->interval); interval = __le16_to_cpu(cp->interval);
if (interval < 0x0004 || interval > 0x4000) if (interval < 0x0004 || interval > 0x4000)
@ -6590,7 +6706,7 @@ static void set_bredr_complete(struct hci_dev *hdev, void *data, int err)
*/ */
hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED); hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED);
mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err); mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_err);
} else { } else {
send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev); send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
new_settings(hdev, cmd->sk); new_settings(hdev, cmd->sk);
@ -6727,7 +6843,7 @@ static void set_secure_conn_complete(struct hci_dev *hdev, void *data, int err)
if (err) { if (err) {
u8 mgmt_err = mgmt_status(err); u8 mgmt_err = mgmt_status(err);
mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err); mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_err);
goto done; goto done;
} }
@ -7174,7 +7290,7 @@ static void get_conn_info_complete(struct hci_dev *hdev, void *data, int err)
rp.max_tx_power = HCI_TX_POWER_INVALID; rp.max_tx_power = HCI_TX_POWER_INVALID;
} }
mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO, status, mgmt_cmd_complete(cmd->sk, cmd->hdev->id, MGMT_OP_GET_CONN_INFO, status,
&rp, sizeof(rp)); &rp, sizeof(rp));
mgmt_pending_free(cmd); mgmt_pending_free(cmd);
@ -7334,7 +7450,7 @@ static void get_clock_info_complete(struct hci_dev *hdev, void *data, int err)
} }
complete: complete:
mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp, mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, status, &rp,
sizeof(rp)); sizeof(rp));
mgmt_pending_free(cmd); mgmt_pending_free(cmd);
@ -8034,10 +8150,6 @@ static void read_local_oob_ext_data_complete(struct hci_dev *hdev, void *data,
u8 status = mgmt_status(err); u8 status = mgmt_status(err);
u16 eir_len; u16 eir_len;
if (err == -ECANCELED ||
cmd != pending_find(MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev))
return;
if (!status) { if (!status) {
if (!skb) if (!skb)
status = MGMT_STATUS_FAILED; status = MGMT_STATUS_FAILED;
@ -8144,7 +8256,7 @@ done:
kfree_skb(skb); kfree_skb(skb);
kfree(mgmt_rp); kfree(mgmt_rp);
mgmt_pending_remove(cmd); mgmt_pending_free(cmd);
} }
static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk, static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk,
@ -8153,7 +8265,7 @@ static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk,
struct mgmt_pending_cmd *cmd; struct mgmt_pending_cmd *cmd;
int err; int err;
cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev, cmd = mgmt_pending_new(sk, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev,
cp, sizeof(*cp)); cp, sizeof(*cp));
if (!cmd) if (!cmd)
return -ENOMEM; return -ENOMEM;
@ -8584,10 +8696,10 @@ static void add_advertising_complete(struct hci_dev *hdev, void *data, int err)
rp.instance = cp->instance; rp.instance = cp->instance;
if (err) if (err)
mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode,
mgmt_status(err)); mgmt_status(err));
else else
mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode,
mgmt_status(err), &rp, sizeof(rp)); mgmt_status(err), &rp, sizeof(rp));
add_adv_complete(hdev, cmd->sk, cp->instance, err); add_adv_complete(hdev, cmd->sk, cp->instance, err);
@ -8775,10 +8887,10 @@ static void add_ext_adv_params_complete(struct hci_dev *hdev, void *data,
hci_remove_adv_instance(hdev, cp->instance); hci_remove_adv_instance(hdev, cp->instance);
mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode,
mgmt_status(err)); mgmt_status(err));
} else { } else {
mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode,
mgmt_status(err), &rp, sizeof(rp)); mgmt_status(err), &rp, sizeof(rp));
} }
@ -8925,10 +9037,10 @@ static void add_ext_adv_data_complete(struct hci_dev *hdev, void *data, int err)
rp.instance = cp->instance; rp.instance = cp->instance;
if (err) if (err)
mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode,
mgmt_status(err)); mgmt_status(err));
else else
mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode,
mgmt_status(err), &rp, sizeof(rp)); mgmt_status(err), &rp, sizeof(rp));
mgmt_pending_free(cmd); mgmt_pending_free(cmd);
@ -9087,10 +9199,10 @@ static void remove_advertising_complete(struct hci_dev *hdev, void *data,
rp.instance = cp->instance; rp.instance = cp->instance;
if (err) if (err)
mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode,
mgmt_status(err)); mgmt_status(err));
else else
mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode,
MGMT_STATUS_SUCCESS, &rp, sizeof(rp)); MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
mgmt_pending_free(cmd); mgmt_pending_free(cmd);
@ -9362,7 +9474,7 @@ void mgmt_index_removed(struct hci_dev *hdev)
if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
return; return;
mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &match); mgmt_pending_foreach(0, hdev, true, cmd_complete_rsp, &match);
if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) { if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev, NULL, 0, mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev, NULL, 0,
@ -9400,7 +9512,8 @@ void mgmt_power_on(struct hci_dev *hdev, int err)
hci_update_passive_scan(hdev); hci_update_passive_scan(hdev);
} }
mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match); mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, true, settings_rsp,
&match);
new_settings(hdev, match.sk); new_settings(hdev, match.sk);
@ -9415,7 +9528,8 @@ void __mgmt_power_off(struct hci_dev *hdev)
struct cmd_lookup match = { NULL, hdev }; struct cmd_lookup match = { NULL, hdev };
u8 zero_cod[] = { 0, 0, 0 }; u8 zero_cod[] = { 0, 0, 0 };
mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match); mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, true, settings_rsp,
&match);
/* If the power off is because of hdev unregistration let /* If the power off is because of hdev unregistration let
* use the appropriate INVALID_INDEX status. Otherwise use * use the appropriate INVALID_INDEX status. Otherwise use
@ -9429,7 +9543,7 @@ void __mgmt_power_off(struct hci_dev *hdev)
else else
match.mgmt_status = MGMT_STATUS_NOT_POWERED; match.mgmt_status = MGMT_STATUS_NOT_POWERED;
mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &match); mgmt_pending_foreach(0, hdev, true, cmd_complete_rsp, &match);
if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0) { if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0) {
mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
@ -9670,7 +9784,6 @@ static void unpair_device_rsp(struct mgmt_pending_cmd *cmd, void *data)
device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk); device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
cmd->cmd_complete(cmd, 0); cmd->cmd_complete(cmd, 0);
mgmt_pending_remove(cmd);
} }
bool mgmt_powering_down(struct hci_dev *hdev) bool mgmt_powering_down(struct hci_dev *hdev)
@ -9726,8 +9839,8 @@ void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
struct mgmt_cp_disconnect *cp; struct mgmt_cp_disconnect *cp;
struct mgmt_pending_cmd *cmd; struct mgmt_pending_cmd *cmd;
mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp, mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, true,
hdev); unpair_device_rsp, hdev);
cmd = pending_find(MGMT_OP_DISCONNECT, hdev); cmd = pending_find(MGMT_OP_DISCONNECT, hdev);
if (!cmd) if (!cmd)
@ -9920,7 +10033,7 @@ void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
if (status) { if (status) {
u8 mgmt_err = mgmt_status(status); u8 mgmt_err = mgmt_status(status);
mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, true,
cmd_status_rsp, &mgmt_err); cmd_status_rsp, &mgmt_err);
return; return;
} }
@ -9930,8 +10043,8 @@ void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
else else
changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY); changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY);
mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp, mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, true,
&match); settings_rsp, &match);
if (changed) if (changed)
new_settings(hdev, match.sk); new_settings(hdev, match.sk);
@ -9955,9 +10068,12 @@ void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
{ {
struct cmd_lookup match = { NULL, hdev, mgmt_status(status) }; struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match); mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, false, sk_lookup,
mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match); &match);
mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match); mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, false, sk_lookup,
&match);
mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, false, sk_lookup,
&match);
if (!status) { if (!status) {
mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class, mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,

View File

@ -217,30 +217,47 @@ int mgmt_cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
struct mgmt_pending_cmd *mgmt_pending_find(unsigned short channel, u16 opcode, struct mgmt_pending_cmd *mgmt_pending_find(unsigned short channel, u16 opcode,
struct hci_dev *hdev) struct hci_dev *hdev)
{ {
struct mgmt_pending_cmd *cmd; struct mgmt_pending_cmd *cmd, *tmp;
list_for_each_entry(cmd, &hdev->mgmt_pending, list) { mutex_lock(&hdev->mgmt_pending_lock);
list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
if (hci_sock_get_channel(cmd->sk) != channel) if (hci_sock_get_channel(cmd->sk) != channel)
continue; continue;
if (cmd->opcode == opcode)
if (cmd->opcode == opcode) {
mutex_unlock(&hdev->mgmt_pending_lock);
return cmd; return cmd;
}
} }
mutex_unlock(&hdev->mgmt_pending_lock);
return NULL; return NULL;
} }
void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev, void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev, bool remove,
void (*cb)(struct mgmt_pending_cmd *cmd, void *data), void (*cb)(struct mgmt_pending_cmd *cmd, void *data),
void *data) void *data)
{ {
struct mgmt_pending_cmd *cmd, *tmp; struct mgmt_pending_cmd *cmd, *tmp;
mutex_lock(&hdev->mgmt_pending_lock);
list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) { list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
if (opcode > 0 && cmd->opcode != opcode) if (opcode > 0 && cmd->opcode != opcode)
continue; continue;
if (remove)
list_del(&cmd->list);
cb(cmd, data); cb(cmd, data);
if (remove)
mgmt_pending_free(cmd);
} }
mutex_unlock(&hdev->mgmt_pending_lock);
} }
struct mgmt_pending_cmd *mgmt_pending_new(struct sock *sk, u16 opcode, struct mgmt_pending_cmd *mgmt_pending_new(struct sock *sk, u16 opcode,
@ -254,7 +271,7 @@ struct mgmt_pending_cmd *mgmt_pending_new(struct sock *sk, u16 opcode,
return NULL; return NULL;
cmd->opcode = opcode; cmd->opcode = opcode;
cmd->index = hdev->id; cmd->hdev = hdev;
cmd->param = kmemdup(data, len, GFP_KERNEL); cmd->param = kmemdup(data, len, GFP_KERNEL);
if (!cmd->param) { if (!cmd->param) {
@ -280,7 +297,9 @@ struct mgmt_pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
if (!cmd) if (!cmd)
return NULL; return NULL;
mutex_lock(&hdev->mgmt_pending_lock);
list_add_tail(&cmd->list, &hdev->mgmt_pending); list_add_tail(&cmd->list, &hdev->mgmt_pending);
mutex_unlock(&hdev->mgmt_pending_lock);
return cmd; return cmd;
} }
@ -294,10 +313,59 @@ void mgmt_pending_free(struct mgmt_pending_cmd *cmd)
void mgmt_pending_remove(struct mgmt_pending_cmd *cmd) void mgmt_pending_remove(struct mgmt_pending_cmd *cmd)
{ {
mutex_lock(&cmd->hdev->mgmt_pending_lock);
list_del(&cmd->list); list_del(&cmd->list);
mutex_unlock(&cmd->hdev->mgmt_pending_lock);
mgmt_pending_free(cmd); mgmt_pending_free(cmd);
} }
bool __mgmt_pending_listed(struct hci_dev *hdev, struct mgmt_pending_cmd *cmd)
{
struct mgmt_pending_cmd *tmp;
lockdep_assert_held(&hdev->mgmt_pending_lock);
if (!cmd)
return false;
list_for_each_entry(tmp, &hdev->mgmt_pending, list) {
if (cmd == tmp)
return true;
}
return false;
}
bool mgmt_pending_listed(struct hci_dev *hdev, struct mgmt_pending_cmd *cmd)
{
bool listed;
mutex_lock(&hdev->mgmt_pending_lock);
listed = __mgmt_pending_listed(hdev, cmd);
mutex_unlock(&hdev->mgmt_pending_lock);
return listed;
}
bool mgmt_pending_valid(struct hci_dev *hdev, struct mgmt_pending_cmd *cmd)
{
bool listed;
if (!cmd)
return false;
mutex_lock(&hdev->mgmt_pending_lock);
listed = __mgmt_pending_listed(hdev, cmd);
if (listed)
list_del(&cmd->list);
mutex_unlock(&hdev->mgmt_pending_lock);
return listed;
}
void mgmt_mesh_foreach(struct hci_dev *hdev, void mgmt_mesh_foreach(struct hci_dev *hdev,
void (*cb)(struct mgmt_mesh_tx *mesh_tx, void *data), void (*cb)(struct mgmt_mesh_tx *mesh_tx, void *data),
void *data, struct sock *sk) void *data, struct sock *sk)

View File

@ -33,7 +33,7 @@ struct mgmt_mesh_tx {
struct mgmt_pending_cmd { struct mgmt_pending_cmd {
struct list_head list; struct list_head list;
u16 opcode; u16 opcode;
int index; struct hci_dev *hdev;
void *param; void *param;
size_t param_len; size_t param_len;
struct sock *sk; struct sock *sk;
@ -54,7 +54,7 @@ int mgmt_cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
struct mgmt_pending_cmd *mgmt_pending_find(unsigned short channel, u16 opcode, struct mgmt_pending_cmd *mgmt_pending_find(unsigned short channel, u16 opcode,
struct hci_dev *hdev); struct hci_dev *hdev);
void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev, void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev, bool remove,
void (*cb)(struct mgmt_pending_cmd *cmd, void *data), void (*cb)(struct mgmt_pending_cmd *cmd, void *data),
void *data); void *data);
struct mgmt_pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode, struct mgmt_pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
@ -65,6 +65,9 @@ struct mgmt_pending_cmd *mgmt_pending_new(struct sock *sk, u16 opcode,
void *data, u16 len); void *data, u16 len);
void mgmt_pending_free(struct mgmt_pending_cmd *cmd); void mgmt_pending_free(struct mgmt_pending_cmd *cmd);
void mgmt_pending_remove(struct mgmt_pending_cmd *cmd); void mgmt_pending_remove(struct mgmt_pending_cmd *cmd);
bool __mgmt_pending_listed(struct hci_dev *hdev, struct mgmt_pending_cmd *cmd);
bool mgmt_pending_listed(struct hci_dev *hdev, struct mgmt_pending_cmd *cmd);
bool mgmt_pending_valid(struct hci_dev *hdev, struct mgmt_pending_cmd *cmd);
void mgmt_mesh_foreach(struct hci_dev *hdev, void mgmt_mesh_foreach(struct hci_dev *hdev,
void (*cb)(struct mgmt_mesh_tx *mesh_tx, void *data), void (*cb)(struct mgmt_mesh_tx *mesh_tx, void *data),
void *data, struct sock *sk); void *data, struct sock *sk);

View File

@ -212,6 +212,7 @@ void j1939_priv_get(struct j1939_priv *priv);
/* notify/alert all j1939 sockets bound to ifindex */ /* notify/alert all j1939 sockets bound to ifindex */
void j1939_sk_netdev_event_netdown(struct j1939_priv *priv); void j1939_sk_netdev_event_netdown(struct j1939_priv *priv);
void j1939_sk_netdev_event_unregister(struct j1939_priv *priv);
int j1939_cancel_active_session(struct j1939_priv *priv, struct sock *sk); int j1939_cancel_active_session(struct j1939_priv *priv, struct sock *sk);
void j1939_tp_init(struct j1939_priv *priv); void j1939_tp_init(struct j1939_priv *priv);

View File

@ -377,6 +377,11 @@ static int j1939_netdev_notify(struct notifier_block *nb,
j1939_sk_netdev_event_netdown(priv); j1939_sk_netdev_event_netdown(priv);
j1939_ecu_unmap_all(priv); j1939_ecu_unmap_all(priv);
break; break;
case NETDEV_UNREGISTER:
j1939_cancel_active_session(priv, NULL);
j1939_sk_netdev_event_netdown(priv);
j1939_sk_netdev_event_unregister(priv);
break;
} }
j1939_priv_put(priv); j1939_priv_put(priv);

View File

@ -1298,6 +1298,55 @@ void j1939_sk_netdev_event_netdown(struct j1939_priv *priv)
read_unlock_bh(&priv->j1939_socks_lock); read_unlock_bh(&priv->j1939_socks_lock);
} }
void j1939_sk_netdev_event_unregister(struct j1939_priv *priv)
{
struct sock *sk;
struct j1939_sock *jsk;
bool wait_rcu = false;
rescan: /* The caller is holding a ref on this "priv" via j1939_priv_get_by_ndev(). */
read_lock_bh(&priv->j1939_socks_lock);
list_for_each_entry(jsk, &priv->j1939_socks, list) {
/* Skip if j1939_jsk_add() is not called on this socket. */
if (!(jsk->state & J1939_SOCK_BOUND))
continue;
sk = &jsk->sk;
sock_hold(sk);
read_unlock_bh(&priv->j1939_socks_lock);
/* Check if j1939_jsk_del() is not yet called on this socket after holding
* socket's lock, for both j1939_sk_bind() and j1939_sk_release() call
* j1939_jsk_del() with socket's lock held.
*/
lock_sock(sk);
if (jsk->state & J1939_SOCK_BOUND) {
/* Neither j1939_sk_bind() nor j1939_sk_release() called j1939_jsk_del().
* Make this socket no longer bound, by pretending as if j1939_sk_bind()
* dropped old references but did not get new references.
*/
j1939_jsk_del(priv, jsk);
j1939_local_ecu_put(priv, jsk->addr.src_name, jsk->addr.sa);
j1939_netdev_stop(priv);
/* Call j1939_priv_put() now and prevent j1939_sk_sock_destruct() from
* calling the corresponding j1939_priv_put().
*
* j1939_sk_sock_destruct() is supposed to call j1939_priv_put() after
* an RCU grace period. But since the caller is holding a ref on this
* "priv", we can defer synchronize_rcu() until immediately before
* the caller calls j1939_priv_put().
*/
j1939_priv_put(priv);
jsk->priv = NULL;
wait_rcu = true;
}
release_sock(sk);
sock_put(sk);
goto rescan;
}
read_unlock_bh(&priv->j1939_socks_lock);
if (wait_rcu)
synchronize_rcu();
}
static int j1939_sk_no_ioctlcmd(struct socket *sock, unsigned int cmd, static int j1939_sk_no_ioctlcmd(struct socket *sock, unsigned int cmd,
unsigned long arg) unsigned long arg)
{ {

View File

@ -204,6 +204,9 @@ static int iptunnel_pmtud_build_icmp(struct sk_buff *skb, int mtu)
if (!pskb_may_pull(skb, ETH_HLEN + sizeof(struct iphdr))) if (!pskb_may_pull(skb, ETH_HLEN + sizeof(struct iphdr)))
return -EINVAL; return -EINVAL;
if (skb_is_gso(skb))
skb_gso_reset(skb);
skb_copy_bits(skb, skb_mac_offset(skb), &eh, ETH_HLEN); skb_copy_bits(skb, skb_mac_offset(skb), &eh, ETH_HLEN);
pskb_pull(skb, ETH_HLEN); pskb_pull(skb, ETH_HLEN);
skb_reset_network_header(skb); skb_reset_network_header(skb);
@ -298,6 +301,9 @@ static int iptunnel_pmtud_build_icmpv6(struct sk_buff *skb, int mtu)
if (!pskb_may_pull(skb, ETH_HLEN + sizeof(struct ipv6hdr))) if (!pskb_may_pull(skb, ETH_HLEN + sizeof(struct ipv6hdr)))
return -EINVAL; return -EINVAL;
if (skb_is_gso(skb))
skb_gso_reset(skb);
skb_copy_bits(skb, skb_mac_offset(skb), &eh, ETH_HLEN); skb_copy_bits(skb, skb_mac_offset(skb), &eh, ETH_HLEN);
pskb_pull(skb, ETH_HLEN); pskb_pull(skb, ETH_HLEN);
skb_reset_network_header(skb); skb_reset_network_header(skb);

View File

@ -0,0 +1 @@
CONFIG_ZL3073X=m

View File

@ -0,0 +1 @@
CONFIG_ZL3073X_I2C=m

View File

@ -0,0 +1 @@
CONFIG_ZL3073X_SPI=m

View File

@ -0,0 +1 @@
# CONFIG_ZL3073X is not set

View File

@ -0,0 +1 @@
# CONFIG_ZL3073X_I2C is not set

View File

@ -0,0 +1 @@
# CONFIG_ZL3073X_SPI is not set

View File

@ -0,0 +1 @@
CONFIG_I2C_MUX_PCA954x=m

View File

@ -1,3 +1,71 @@
* Tue Dec 02 2025 CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> [6.12.0-124.20.1.el10_1]
- iommu/vt-d: Disallow dirty tracking if incoherent page walk (CKI Backport Bot) [RHEL-125482] {CVE-2025-40058}
- net/mlx5: fs, fix UAF in flow counter release (Michal Schmidt) [RHEL-124432] {CVE-2025-39979}
- dpll: zl3073x: Fix output pin registration (Ivan Vecera) [RHEL-114795]
- dpll: zl3073x: Handle missing or corrupted flash configuration (Ivan Vecera) [RHEL-114795]
- dpll: zl3073x: Refactor DPLL initialization (Ivan Vecera) [RHEL-114795]
- dpll: zl3073x: ZL3073X_I2C and ZL3073X_SPI should depend on NET (Ivan Vecera) [RHEL-114795]
- dpll: Make ZL3073X invisible (Ivan Vecera) [RHEL-114795]
- dpll: zl3073x: Fix build failure (Ivan Vecera) [RHEL-114795]
- redhat/configs: enable CONFIG_ZL3073X* (Ivan Vecera) [RHEL-114795]
- redhat/configs: enable CONFIG_I2C_MUX_PCA954x on x86 (Ivan Vecera) [RHEL-114795]
- dpll: zl3073x: Add support to get fractional frequency offset (Ivan Vecera) [RHEL-114795]
- dpll: zl3073x: Add support to adjust phase (Ivan Vecera) [RHEL-114795]
- dpll: zl3073x: Implement phase offset monitor feature (Ivan Vecera) [RHEL-114795]
- dpll: zl3073x: Add support to get phase offset on connected input pin (Ivan Vecera) [RHEL-114795]
- dpll: zl3073x: Add support to get/set esync on pins (Ivan Vecera) [RHEL-114795]
- dpll: zl3073x: Add support to get/set frequency on pins (Ivan Vecera) [RHEL-114795]
- dpll: zl3073x: Implement input pin state setting in automatic mode (Ivan Vecera) [RHEL-114795]
- dpll: zl3073x: Add support to get/set priority on input pins (Ivan Vecera) [RHEL-114795]
- dpll: zl3073x: Implement input pin selection in manual mode (Ivan Vecera) [RHEL-114795]
- dpll: zl3073x: Register DPLL devices and pins (Ivan Vecera) [RHEL-114795]
- dpll: zl3073x: Read DPLL types and pin properties from system firmware (Ivan Vecera) [RHEL-114795]
- dpll: zl3073x: Fetch invariants during probe (Ivan Vecera) [RHEL-114795]
- dpll: Add basic Microchip ZL3073x support (Ivan Vecera) [RHEL-114795]
- dt-bindings: dpll: Add support for Microchip Azurite chip family (Ivan Vecera) [RHEL-114795]
- dt-bindings: dpll: Add DPLL device and pin (Ivan Vecera) [RHEL-114795]
- idpf: set mac type when adding and removing MAC filters (CKI Backport Bot) [RHEL-123372]
- crypto: ccp - Always pass in an error pointer to __sev_platform_shutdown_locked() (Lenny Szubowicz) [RHEL-76557]
- crypto: ccp - Fix SNP panic notifier unregistration (Lenny Szubowicz) [RHEL-76557]
- crypto: ccp - Fix dereferencing uninitialized error pointer (Lenny Szubowicz) [RHEL-76557]
- crypto: ccp - Fix __sev_snp_shutdown_locked (Lenny Szubowicz) [RHEL-76557]
- crypto: ccp - Move SEV/SNP Platform initialization to KVM (Lenny Szubowicz) [RHEL-76557]
- KVM: SVM: Add support to initialize SEV/SNP functionality in KVM (Lenny Szubowicz) [RHEL-76557]
- crypto: ccp - Add new SEV/SNP platform shutdown API (Lenny Szubowicz) [RHEL-76557]
- crypto: ccp - Register SNP panic notifier only if SNP is enabled (Lenny Szubowicz) [RHEL-76557]
- crypto: ccp - Reset TMR size at SNP Shutdown (Lenny Szubowicz) [RHEL-76557]
- crypto: ccp - Ensure implicit SEV/SNP init and shutdown in ioctls (Lenny Szubowicz) [RHEL-76557]
- crypto: ccp - Move dev_info/err messages for SEV/SNP init and shutdown (Lenny Szubowicz) [RHEL-76557]
- crypto: ccp - Abort doing SEV INIT if SNP INIT fails (Lenny Szubowicz) [RHEL-76557]
- s390/pci: Do not try re-enabling load/store if device is disabled (CKI Backport Bot) [RHEL-114448]
- s390/pci: Fix stale function handles in error handling (CKI Backport Bot) [RHEL-114448]
Resolves: RHEL-114448, RHEL-114795, RHEL-123372, RHEL-124432, RHEL-125482, RHEL-76557
* Sat Nov 29 2025 CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> [6.12.0-124.19.1.el10_1]
- Bluetooth: MGMT: fix crash in set_mesh_sync and set_mesh_complete (CKI Backport Bot) [RHEL-122901] {CVE-2025-39981}
- Bluetooth: MGMT: Fix sparse errors (CKI Backport Bot) [RHEL-122901] {CVE-2025-39981}
- Bluetooth: MGMT: Fix possible UAFs (CKI Backport Bot) [RHEL-122901] {CVE-2025-39981}
- Bluetooth: hci_sync: fix set_local_name race condition (CKI Backport Bot) [RHEL-122901] {CVE-2025-39981}
- Bluetooth: MGMT: set_mesh: update LE scan interval and window (CKI Backport Bot) [RHEL-122901] {CVE-2025-39981}
- Bluetooth: MGMT: Protect mgmt_pending list with its own lock (CKI Backport Bot) [RHEL-122901] {CVE-2025-39981}
- Bluetooth: MGMT: Fix UAF on mgmt_remove_adv_monitor_complete (CKI Backport Bot) [RHEL-122901] {CVE-2025-39981}
- Bluetooth: hci_event: Fix UAF in hci_conn_tx_dequeue (CKI Backport Bot) [RHEL-124134] {CVE-2025-39983}
- can: j1939: add missing calls in NETDEV_UNREGISTER notification handler (CKI Backport Bot) [RHEL-124110] {CVE-2025-39925}
- can: j1939: implement NETDEV_UNREGISTER notification handler (CKI Backport Bot) [RHEL-124110] {CVE-2025-39925}
- Bluetooth: hci_event: Fix UAF in hci_acl_create_conn_sync (CKI Backport Bot) [RHEL-123824] {CVE-2025-39982}
Resolves: RHEL-122901, RHEL-123824, RHEL-124110, RHEL-124134
* Thu Nov 27 2025 CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> [6.12.0-124.18.1.el10_1]
- ice: ice_adapter: release xa entry on adapter allocation failure (CKI Backport Bot) [RHEL-128472] {CVE-2025-40185}
- cifs: Fix oops due to uninitialised variable (CKI Backport Bot) [RHEL-120562] {CVE-2025-38737}
Resolves: RHEL-120562, RHEL-128472
* Tue Nov 25 2025 CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> [6.12.0-124.17.1.el10_1]
- x86/hyperv: Fix kdump on Azure CVMs (Li Tian) [RHEL-129777]
- tunnels: reset the GSO metadata before reusing the skb (Antoine Tenart) [RHEL-113919]
- io_uring/waitid: always prune wait queue entry in io_waitid_wait() (CKI Backport Bot) [RHEL-124974] {CVE-2025-40047}
Resolves: RHEL-113919, RHEL-124974, RHEL-129777
* Sat Nov 22 2025 CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> [6.12.0-124.16.1.el10_1] * Sat Nov 22 2025 CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> [6.12.0-124.16.1.el10_1]
- bpf: Fix metadata_dst leak __bpf_redirect_neigh_v{4,6} (Xin Long) [RHEL-125759] - bpf: Fix metadata_dst leak __bpf_redirect_neigh_v{4,6} (Xin Long) [RHEL-125759]
- mm/memory-failure: fix VM_BUG_ON_PAGE(PagePoisoned(page)) when unpoison memory (CKI Backport Bot) [RHEL-119161] {CVE-2025-39883} - mm/memory-failure: fix VM_BUG_ON_PAGE(PagePoisoned(page)) when unpoison memory (CKI Backport Bot) [RHEL-119161] {CVE-2025-39883}

View File

@ -1,3 +1,3 @@
sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md
kernel-uki-virt-addons.centos,1,Red Hat,kernel-uki-virt-addons,6.12.0-124.16.1.el10.x86_64,mailto:secalert@redhat.com kernel-uki-virt-addons.centos,1,Red Hat,kernel-uki-virt-addons,6.12.0-124.20.1.el10.x86_64,mailto:secalert@redhat.com
kernel-uki-virt-addons.almalinux,1,AlmaLinux,kernel-uki-virt-addons,6.12.0-124.16.1.el10.x86_64,mailto:security@almalinux.org kernel-uki-virt-addons.almalinux,1,AlmaLinux,kernel-uki-virt-addons,6.12.0-124.20.1.el10.x86_64,mailto:security@almalinux.org

View File

@ -1,3 +1,3 @@
sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md
kernel-uki-virt.centos,1,Red Hat,kernel-uki-virt,6.12.0-124.16.1.el10.x86_64,mailto:secalert@redhat.com kernel-uki-virt.centos,1,Red Hat,kernel-uki-virt,6.12.0-124.20.1.el10.x86_64,mailto:secalert@redhat.com
kernel-uki-virt.almalinux,1,AlmaLinux,kernel-uki-virt,6.12.0-124.16.1.el10.x86_64,mailto:security@almalinux.org kernel-uki-virt.almalinux,1,AlmaLinux,kernel-uki-virt,6.12.0-124.20.1.el10.x86_64,mailto:security@almalinux.org