Import of kernel-6.12.0-124.20.1.el10_1
This commit is contained in:
parent
1dc94ec495
commit
8ac76c15e5
76
Documentation/devicetree/bindings/dpll/dpll-device.yaml
Normal file
76
Documentation/devicetree/bindings/dpll/dpll-device.yaml
Normal 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
|
||||
45
Documentation/devicetree/bindings/dpll/dpll-pin.yaml
Normal file
45
Documentation/devicetree/bindings/dpll/dpll-pin.yaml
Normal 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
|
||||
115
Documentation/devicetree/bindings/dpll/microchip,zl30731.yaml
Normal file
115
Documentation/devicetree/bindings/dpll/microchip,zl30731.yaml
Normal 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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
...
|
||||
@ -98,3 +98,4 @@ parameters, info versions, and other features it supports.
|
||||
iosm
|
||||
octeontx2
|
||||
sfc
|
||||
zl3073x
|
||||
|
||||
51
Documentation/networking/devlink/zl3073x.rst
Normal file
51
Documentation/networking/devlink/zl3073x.rst
Normal 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
|
||||
10
MAINTAINERS
10
MAINTAINERS
@ -6963,6 +6963,8 @@ M: Arkadiusz Kubalewski <arkadiusz.kubalewski@intel.com>
|
||||
M: Jiri Pirko <jiri@resnulli.us>
|
||||
L: netdev@vger.kernel.org
|
||||
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: drivers/dpll/*
|
||||
F: include/linux/dpll.h
|
||||
@ -15392,6 +15394,14 @@ L: linux-wireless@vger.kernel.org
|
||||
S: Supported
|
||||
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
|
||||
M: Alexandre Belloni <alexandre.belloni@bootlin.com>
|
||||
M: UNGLinuxDriver@microchip.com
|
||||
|
||||
@ -12,7 +12,7 @@ RHEL_MINOR = 1
|
||||
#
|
||||
# Use this spot to avoid future merge conflicts.
|
||||
# Do not trim this comment.
|
||||
RHEL_RELEASE = 124.16.1
|
||||
RHEL_RELEASE = 124.20.1
|
||||
|
||||
#
|
||||
# RHEL_REBASE_NUM
|
||||
|
||||
@ -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);
|
||||
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));
|
||||
rc = zpci_reset_load_store_blocked(zdev);
|
||||
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 pci_dev *pdev = NULL;
|
||||
pci_ers_result_t ers_res;
|
||||
u32 fh = 0;
|
||||
int rc;
|
||||
|
||||
zpci_dbg(3, "err fid:%x, fh:%x, pec:%x\n",
|
||||
ccdf->fid, ccdf->fh, ccdf->pec);
|
||||
@ -281,6 +287,15 @@ static void __zpci_event_error(struct zpci_ccdf_err *ccdf)
|
||||
|
||||
if (zdev) {
|
||||
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);
|
||||
if (zdev->zbus->bus)
|
||||
pdev = pci_get_slot(zdev->zbus->bus, zdev->devfn);
|
||||
|
||||
@ -460,6 +460,195 @@ void hv_ivm_msr_read(u64 msr, u64 *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.
|
||||
*
|
||||
@ -473,6 +662,7 @@ static int hv_mark_gpa_visibility(u16 count, const u64 pfn[],
|
||||
struct hv_gpa_range_for_visibility *input;
|
||||
u64 hv_status;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
/* no-op if partition isolation is not enabled */
|
||||
if (!hv_is_isolation_supported())
|
||||
@ -484,6 +674,13 @@ static int hv_mark_gpa_visibility(u16 count, const u64 pfn[],
|
||||
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);
|
||||
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))
|
||||
return 0;
|
||||
|
||||
if (visibility == VMBUS_PAGE_NOT_VISIBLE)
|
||||
ret = hv_list_enc_add(pfn, count);
|
||||
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_status_change_prepare = hv_vtom_clear_present;
|
||||
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. */
|
||||
mtrr_overwrite_state(NULL, 0, MTRR_TYPE_WRBACK);
|
||||
|
||||
@ -2882,6 +2882,7 @@ void __init sev_set_cpu_caps(void)
|
||||
void __init sev_hardware_setup(void)
|
||||
{
|
||||
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_es_supported = false;
|
||||
bool sev_supported = false;
|
||||
@ -2998,6 +2999,15 @@ out:
|
||||
sev_supported_vmsa_features = 0;
|
||||
if (sev_es_debug_swap_enabled)
|
||||
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)
|
||||
@ -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_ES, 0);
|
||||
|
||||
sev_platform_shutdown();
|
||||
}
|
||||
|
||||
int sev_cpu_init(struct svm_cpu_data *sd)
|
||||
|
||||
@ -4231,6 +4231,15 @@ CONFIG_PTP_1588_CLOCK_MOCK=m
|
||||
# CONFIG_PTP_1588_CLOCK_OCP is not set
|
||||
# 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_GENERIC_PINCTRL_GROUPS=y
|
||||
CONFIG_PINMUX=y
|
||||
@ -7709,7 +7718,6 @@ CONFIG_INTERCONNECT_IMX8MP=m
|
||||
# CONFIG_PECI is not set
|
||||
# CONFIG_HTE is not set
|
||||
# CONFIG_CDX_BUS is not set
|
||||
CONFIG_DPLL=y
|
||||
# end of Device Drivers
|
||||
|
||||
#
|
||||
|
||||
@ -4214,6 +4214,15 @@ CONFIG_PTP_1588_CLOCK_MOCK=m
|
||||
# CONFIG_PTP_1588_CLOCK_OCP is not set
|
||||
# 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_GENERIC_PINCTRL_GROUPS=y
|
||||
CONFIG_PINMUX=y
|
||||
@ -7686,7 +7695,6 @@ CONFIG_INTERCONNECT_IMX8MP=m
|
||||
# CONFIG_PECI is not set
|
||||
# CONFIG_HTE is not set
|
||||
# CONFIG_CDX_BUS is not set
|
||||
CONFIG_DPLL=y
|
||||
# end of Device Drivers
|
||||
|
||||
#
|
||||
|
||||
@ -4235,6 +4235,15 @@ CONFIG_PTP_1588_CLOCK_MOCK=m
|
||||
# CONFIG_PTP_1588_CLOCK_OCP is not set
|
||||
# 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_GENERIC_PINCTRL_GROUPS=y
|
||||
CONFIG_PINMUX=y
|
||||
@ -7715,7 +7724,6 @@ CONFIG_INTERCONNECT_IMX8MP=m
|
||||
# CONFIG_PECI is not set
|
||||
# CONFIG_HTE is not set
|
||||
# CONFIG_CDX_BUS is not set
|
||||
CONFIG_DPLL=y
|
||||
# end of Device Drivers
|
||||
|
||||
#
|
||||
|
||||
@ -4218,6 +4218,15 @@ CONFIG_PTP_1588_CLOCK_MOCK=m
|
||||
# CONFIG_PTP_1588_CLOCK_OCP is not set
|
||||
# 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_GENERIC_PINCTRL_GROUPS=y
|
||||
CONFIG_PINMUX=y
|
||||
@ -7692,7 +7701,6 @@ CONFIG_INTERCONNECT_IMX8MP=m
|
||||
# CONFIG_PECI is not set
|
||||
# CONFIG_HTE is not set
|
||||
# CONFIG_CDX_BUS is not set
|
||||
CONFIG_DPLL=y
|
||||
# end of Device Drivers
|
||||
|
||||
#
|
||||
|
||||
@ -4201,6 +4201,15 @@ CONFIG_PTP_1588_CLOCK_MOCK=m
|
||||
# CONFIG_PTP_1588_CLOCK_OCP is not set
|
||||
# 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_GENERIC_PINCTRL_GROUPS=y
|
||||
CONFIG_PINMUX=y
|
||||
@ -7669,7 +7678,6 @@ CONFIG_INTERCONNECT_IMX8MP=m
|
||||
# CONFIG_PECI is not set
|
||||
# CONFIG_HTE is not set
|
||||
# CONFIG_CDX_BUS is not set
|
||||
CONFIG_DPLL=y
|
||||
# end of Device Drivers
|
||||
|
||||
#
|
||||
|
||||
@ -4221,6 +4221,15 @@ CONFIG_PTP_1588_CLOCK_MOCK=m
|
||||
# CONFIG_PTP_1588_CLOCK_OCP is not set
|
||||
# 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_GENERIC_PINCTRL_GROUPS=y
|
||||
CONFIG_PINMUX=y
|
||||
@ -7697,7 +7706,6 @@ CONFIG_INTERCONNECT_IMX8MP=m
|
||||
# CONFIG_PECI is not set
|
||||
# CONFIG_HTE is not set
|
||||
# CONFIG_CDX_BUS is not set
|
||||
CONFIG_DPLL=y
|
||||
# end of Device Drivers
|
||||
|
||||
#
|
||||
|
||||
@ -4204,6 +4204,15 @@ CONFIG_PTP_1588_CLOCK_MOCK=m
|
||||
# CONFIG_PTP_1588_CLOCK_OCP is not set
|
||||
# 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_GENERIC_PINCTRL_GROUPS=y
|
||||
CONFIG_PINMUX=y
|
||||
@ -7674,7 +7683,6 @@ CONFIG_INTERCONNECT_IMX8MP=m
|
||||
# CONFIG_PECI is not set
|
||||
# CONFIG_HTE is not set
|
||||
# CONFIG_CDX_BUS is not set
|
||||
CONFIG_DPLL=y
|
||||
# end of Device Drivers
|
||||
|
||||
#
|
||||
|
||||
@ -4218,6 +4218,15 @@ CONFIG_PTP_1588_CLOCK_MOCK=m
|
||||
# CONFIG_PTP_1588_CLOCK_OCP is not set
|
||||
# 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_GENERIC_PINCTRL_GROUPS=y
|
||||
CONFIG_PINMUX=y
|
||||
@ -7692,7 +7701,6 @@ CONFIG_INTERCONNECT_IMX8MP=m
|
||||
# CONFIG_PECI is not set
|
||||
# CONFIG_HTE is not set
|
||||
# CONFIG_CDX_BUS is not set
|
||||
CONFIG_DPLL=y
|
||||
# end of Device Drivers
|
||||
|
||||
#
|
||||
|
||||
@ -3459,6 +3459,14 @@ CONFIG_PTP_1588_CLOCK_MOCK=m
|
||||
# CONFIG_PTP_1588_CLOCK_OCP is not set
|
||||
# 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_GPIOLIB=y
|
||||
CONFIG_GPIOLIB_FASTPATH_LIMIT=512
|
||||
@ -5973,7 +5981,6 @@ CONFIG_INTERCONNECT=y
|
||||
# CONFIG_MOST is not set
|
||||
# CONFIG_PECI is not set
|
||||
# CONFIG_HTE is not set
|
||||
CONFIG_DPLL=y
|
||||
# end of Device Drivers
|
||||
|
||||
#
|
||||
|
||||
@ -3461,6 +3461,14 @@ CONFIG_PTP_1588_CLOCK_MOCK=m
|
||||
# CONFIG_PTP_1588_CLOCK_OCP is not set
|
||||
# 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_GPIOLIB=y
|
||||
CONFIG_GPIOLIB_FASTPATH_LIMIT=512
|
||||
@ -5969,7 +5977,6 @@ CONFIG_INTERCONNECT=y
|
||||
# CONFIG_MOST is not set
|
||||
# CONFIG_PECI is not set
|
||||
# CONFIG_HTE is not set
|
||||
CONFIG_DPLL=y
|
||||
# end of Device Drivers
|
||||
|
||||
#
|
||||
|
||||
@ -2479,6 +2479,13 @@ CONFIG_PTP_1588_CLOCK_OPTIONAL=y
|
||||
CONFIG_PTP_1588_CLOCK_MOCK=m
|
||||
# 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_GPIOLIB=y
|
||||
CONFIG_GPIOLIB_FASTPATH_LIMIT=512
|
||||
@ -3135,7 +3142,6 @@ CONFIG_INTERCONNECT=y
|
||||
# CONFIG_MOST is not set
|
||||
# CONFIG_PECI is not set
|
||||
# CONFIG_HTE is not set
|
||||
CONFIG_DPLL=y
|
||||
# end of Device Drivers
|
||||
|
||||
#
|
||||
|
||||
@ -1048,6 +1048,11 @@ CONFIG_PTP_1588_CLOCK_OPTIONAL=y
|
||||
# CONFIG_PTP_1588_CLOCK_MOCK is not set
|
||||
# end of PTP clock support
|
||||
|
||||
#
|
||||
# DPLL device support
|
||||
#
|
||||
# end of DPLL device support
|
||||
|
||||
# CONFIG_PINCTRL is not set
|
||||
CONFIG_GPIOLIB=y
|
||||
CONFIG_GPIOLIB_FASTPATH_LIMIT=512
|
||||
|
||||
@ -2503,6 +2503,13 @@ CONFIG_PTP_1588_CLOCK_OPTIONAL=y
|
||||
CONFIG_PTP_1588_CLOCK_MOCK=m
|
||||
# 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_GPIOLIB=y
|
||||
CONFIG_GPIOLIB_FASTPATH_LIMIT=512
|
||||
@ -3159,7 +3166,6 @@ CONFIG_INTERCONNECT=y
|
||||
# CONFIG_MOST is not set
|
||||
# CONFIG_PECI is not set
|
||||
# CONFIG_HTE is not set
|
||||
CONFIG_DPLL=y
|
||||
# end of Device Drivers
|
||||
|
||||
#
|
||||
|
||||
@ -4063,7 +4063,7 @@ CONFIG_I2C_MUX=m
|
||||
# CONFIG_I2C_MUX_GPIO is not set
|
||||
# CONFIG_I2C_MUX_LTC4306 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_MLXCPLD=m
|
||||
# end of Multiplexer I2C Chip support
|
||||
@ -4229,6 +4229,15 @@ CONFIG_PTP_1588_CLOCK_VMW=m
|
||||
# CONFIG_PTP_1588_CLOCK_OCP is not set
|
||||
# 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_PINMUX=y
|
||||
CONFIG_PINCONF=y
|
||||
@ -8469,7 +8478,6 @@ CONFIG_INTEL_QEP=m
|
||||
# CONFIG_MOST is not set
|
||||
# CONFIG_PECI is not set
|
||||
# CONFIG_HTE is not set
|
||||
CONFIG_DPLL=y
|
||||
# end of Device Drivers
|
||||
|
||||
#
|
||||
|
||||
@ -4049,7 +4049,7 @@ CONFIG_I2C_MUX=m
|
||||
# CONFIG_I2C_MUX_GPIO is not set
|
||||
# CONFIG_I2C_MUX_LTC4306 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_MLXCPLD=m
|
||||
# end of Multiplexer I2C Chip support
|
||||
@ -4215,6 +4215,15 @@ CONFIG_PTP_1588_CLOCK_VMW=m
|
||||
# CONFIG_PTP_1588_CLOCK_OCP is not set
|
||||
# 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_PINMUX=y
|
||||
CONFIG_PINCONF=y
|
||||
@ -8451,7 +8460,6 @@ CONFIG_INTEL_QEP=m
|
||||
# CONFIG_MOST is not set
|
||||
# CONFIG_PECI is not set
|
||||
# CONFIG_HTE is not set
|
||||
CONFIG_DPLL=y
|
||||
# end of Device Drivers
|
||||
|
||||
#
|
||||
|
||||
@ -4031,7 +4031,7 @@ CONFIG_I2C_MUX=m
|
||||
# CONFIG_I2C_MUX_GPIO is not set
|
||||
# CONFIG_I2C_MUX_LTC4306 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_MLXCPLD=m
|
||||
# end of Multiplexer I2C Chip support
|
||||
@ -4197,6 +4197,15 @@ CONFIG_PTP_1588_CLOCK_VMW=m
|
||||
# CONFIG_PTP_1588_CLOCK_OCP is not set
|
||||
# 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_PINMUX=y
|
||||
CONFIG_PINCONF=y
|
||||
@ -8422,7 +8431,6 @@ CONFIG_INTEL_QEP=m
|
||||
# CONFIG_MOST is not set
|
||||
# CONFIG_PECI is not set
|
||||
# CONFIG_HTE is not set
|
||||
CONFIG_DPLL=y
|
||||
# end of Device Drivers
|
||||
|
||||
#
|
||||
|
||||
@ -4045,7 +4045,7 @@ CONFIG_I2C_MUX=m
|
||||
# CONFIG_I2C_MUX_GPIO is not set
|
||||
# CONFIG_I2C_MUX_LTC4306 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_MLXCPLD=m
|
||||
# end of Multiplexer I2C Chip support
|
||||
@ -4211,6 +4211,15 @@ CONFIG_PTP_1588_CLOCK_VMW=m
|
||||
# CONFIG_PTP_1588_CLOCK_OCP is not set
|
||||
# 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_PINMUX=y
|
||||
CONFIG_PINCONF=y
|
||||
@ -8440,7 +8449,6 @@ CONFIG_INTEL_QEP=m
|
||||
# CONFIG_MOST is not set
|
||||
# CONFIG_PECI is not set
|
||||
# CONFIG_HTE is not set
|
||||
CONFIG_DPLL=y
|
||||
# end of Device Drivers
|
||||
|
||||
#
|
||||
|
||||
@ -4063,7 +4063,7 @@ CONFIG_I2C_MUX=m
|
||||
# CONFIG_I2C_MUX_GPIO is not set
|
||||
# CONFIG_I2C_MUX_LTC4306 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_MLXCPLD=m
|
||||
# end of Multiplexer I2C Chip support
|
||||
@ -4229,6 +4229,15 @@ CONFIG_PTP_1588_CLOCK_VMW=m
|
||||
# CONFIG_PTP_1588_CLOCK_OCP is not set
|
||||
# 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_PINMUX=y
|
||||
CONFIG_PINCONF=y
|
||||
@ -8469,7 +8478,6 @@ CONFIG_INTEL_QEP=m
|
||||
# CONFIG_MOST is not set
|
||||
# CONFIG_PECI is not set
|
||||
# CONFIG_HTE is not set
|
||||
CONFIG_DPLL=y
|
||||
# end of Device Drivers
|
||||
|
||||
#
|
||||
|
||||
@ -4049,7 +4049,7 @@ CONFIG_I2C_MUX=m
|
||||
# CONFIG_I2C_MUX_GPIO is not set
|
||||
# CONFIG_I2C_MUX_LTC4306 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_MLXCPLD=m
|
||||
# end of Multiplexer I2C Chip support
|
||||
@ -4215,6 +4215,15 @@ CONFIG_PTP_1588_CLOCK_VMW=m
|
||||
# CONFIG_PTP_1588_CLOCK_OCP is not set
|
||||
# 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_PINMUX=y
|
||||
CONFIG_PINCONF=y
|
||||
@ -8451,7 +8460,6 @@ CONFIG_INTEL_QEP=m
|
||||
# CONFIG_MOST is not set
|
||||
# CONFIG_PECI is not set
|
||||
# CONFIG_HTE is not set
|
||||
CONFIG_DPLL=y
|
||||
# end of Device Drivers
|
||||
|
||||
#
|
||||
|
||||
@ -4031,7 +4031,7 @@ CONFIG_I2C_MUX=m
|
||||
# CONFIG_I2C_MUX_GPIO is not set
|
||||
# CONFIG_I2C_MUX_LTC4306 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_MLXCPLD=m
|
||||
# end of Multiplexer I2C Chip support
|
||||
@ -4197,6 +4197,15 @@ CONFIG_PTP_1588_CLOCK_VMW=m
|
||||
# CONFIG_PTP_1588_CLOCK_OCP is not set
|
||||
# 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_PINMUX=y
|
||||
CONFIG_PINCONF=y
|
||||
@ -8422,7 +8431,6 @@ CONFIG_INTEL_QEP=m
|
||||
# CONFIG_MOST is not set
|
||||
# CONFIG_PECI is not set
|
||||
# CONFIG_HTE is not set
|
||||
CONFIG_DPLL=y
|
||||
# end of Device Drivers
|
||||
|
||||
#
|
||||
|
||||
@ -4045,7 +4045,7 @@ CONFIG_I2C_MUX=m
|
||||
# CONFIG_I2C_MUX_GPIO is not set
|
||||
# CONFIG_I2C_MUX_LTC4306 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_MLXCPLD=m
|
||||
# end of Multiplexer I2C Chip support
|
||||
@ -4211,6 +4211,15 @@ CONFIG_PTP_1588_CLOCK_VMW=m
|
||||
# CONFIG_PTP_1588_CLOCK_OCP is not set
|
||||
# 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_PINMUX=y
|
||||
CONFIG_PINCONF=y
|
||||
@ -8440,7 +8449,6 @@ CONFIG_INTEL_QEP=m
|
||||
# CONFIG_MOST is not set
|
||||
# CONFIG_PECI is not set
|
||||
# CONFIG_HTE is not set
|
||||
CONFIG_DPLL=y
|
||||
# end of Device Drivers
|
||||
|
||||
#
|
||||
|
||||
@ -77,6 +77,8 @@ source "drivers/pps/Kconfig"
|
||||
|
||||
source "drivers/ptp/Kconfig"
|
||||
|
||||
source "drivers/dpll/Kconfig"
|
||||
|
||||
source "drivers/pinctrl/Kconfig"
|
||||
|
||||
source "drivers/gpio/Kconfig"
|
||||
@ -245,6 +247,4 @@ source "drivers/hte/Kconfig"
|
||||
|
||||
source "drivers/cdx/Kconfig"
|
||||
|
||||
source "drivers/dpll/Kconfig"
|
||||
|
||||
endmenu
|
||||
|
||||
@ -109,6 +109,15 @@ static void *sev_init_ex_buffer;
|
||||
*/
|
||||
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)
|
||||
{
|
||||
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)) {
|
||||
dev_dbg(sev->dev, "SEV-SNP support requires firmware version >= %d:%d\n",
|
||||
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. */
|
||||
@ -1176,21 +1185,34 @@ static int __sev_snp_init_locked(int *error)
|
||||
wbinvd_on_all_cpus();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* Prepare for first SNP guest launch after INIT. */
|
||||
wbinvd_on_all_cpus();
|
||||
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;
|
||||
}
|
||||
|
||||
sev->snp_initialized = true;
|
||||
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;
|
||||
|
||||
return rc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
int rc, psp_ret = SEV_RET_NO_FW_CALL;
|
||||
int rc, psp_ret, dfflush_error;
|
||||
struct sev_device *sev;
|
||||
|
||||
psp_ret = dfflush_error = SEV_RET_NO_FW_CALL;
|
||||
|
||||
if (!psp_master || !psp_master->sev_data)
|
||||
return -ENODEV;
|
||||
|
||||
@ -1287,16 +1311,22 @@ static int __sev_platform_init_locked(int *error)
|
||||
if (error)
|
||||
*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;
|
||||
}
|
||||
|
||||
sev->state = SEV_STATE_INIT;
|
||||
|
||||
/* Prepare for first SEV guest launch after INIT */
|
||||
wbinvd_on_all_cpus();
|
||||
rc = __sev_do_cmd_locked(SEV_CMD_DF_FLUSH, NULL, error);
|
||||
if (rc)
|
||||
rc = __sev_do_cmd_locked(SEV_CMD_DF_FLUSH, NULL, &dfflush_error);
|
||||
if (rc) {
|
||||
dev_err(sev->dev, "SEV: DF_FLUSH failed %#x, rc %d\n",
|
||||
dfflush_error, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
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)
|
||||
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);
|
||||
if (rc && rc != -ENODEV) {
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
if (rc && rc != -ENODEV)
|
||||
return rc;
|
||||
|
||||
/* Defer legacy SEV/SEV-ES support if allowed by caller/module. */
|
||||
if (args->probe && !psp_init_on_probe)
|
||||
@ -1367,8 +1387,11 @@ static int __sev_platform_shutdown_locked(int *error)
|
||||
return 0;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
sev->state = SEV_STATE_UNINIT;
|
||||
dev_dbg(sev->dev, "SEV firmware shutdown\n");
|
||||
@ -1389,6 +1412,37 @@ static int sev_get_platform_state(int *state, int *error)
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
struct sev_device *sev = psp_master->sev_data;
|
||||
bool shutdown_required = false;
|
||||
int rc;
|
||||
|
||||
if (!writable)
|
||||
return -EPERM;
|
||||
|
||||
if (sev->state == SEV_STATE_UNINIT) {
|
||||
rc = __sev_platform_init_locked(&argp->error);
|
||||
rc = sev_move_to_init_state(argp, &shutdown_required);
|
||||
if (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)
|
||||
{
|
||||
struct sev_device *sev = psp_master->sev_data;
|
||||
struct sev_user_data_pek_csr input;
|
||||
bool shutdown_required = false;
|
||||
struct sev_data_pek_csr data;
|
||||
void __user *input_address;
|
||||
void *blob = NULL;
|
||||
@ -1490,7 +1551,7 @@ static int sev_ioctl_do_pek_csr(struct sev_issue_cmd *argp, bool writable)
|
||||
|
||||
cmd:
|
||||
if (sev->state == SEV_STATE_UNINIT) {
|
||||
ret = __sev_platform_init_locked(&argp->error);
|
||||
ret = sev_move_to_init_state(argp, &shutdown_required);
|
||||
if (ret)
|
||||
goto e_free_blob;
|
||||
}
|
||||
@ -1511,6 +1572,9 @@ cmd:
|
||||
}
|
||||
|
||||
e_free_blob:
|
||||
if (shutdown_required)
|
||||
__sev_firmware_shutdown(sev, false);
|
||||
|
||||
kfree(blob);
|
||||
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);
|
||||
/* SHUTDOWN may require DF_FLUSH */
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
/* reissue the shutdown command */
|
||||
@ -1692,7 +1759,8 @@ static int __sev_snp_shutdown_locked(int *error, bool panic)
|
||||
error);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1718,6 +1786,18 @@ static int __sev_snp_shutdown_locked(int *error, bool panic)
|
||||
sev->snp_initialized = false;
|
||||
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;
|
||||
}
|
||||
|
||||
@ -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_user_data_pek_cert_import input;
|
||||
struct sev_data_pek_cert_import data;
|
||||
bool shutdown_required = false;
|
||||
void *pek_blob, *oca_blob;
|
||||
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 (sev->state != SEV_STATE_INIT) {
|
||||
ret = __sev_platform_init_locked(&argp->error);
|
||||
ret = sev_move_to_init_state(argp, &shutdown_required);
|
||||
if (ret)
|
||||
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);
|
||||
|
||||
e_free_oca:
|
||||
if (shutdown_required)
|
||||
__sev_firmware_shutdown(sev, false);
|
||||
|
||||
kfree(oca_blob);
|
||||
e_free_pek:
|
||||
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;
|
||||
void __user *input_cert_chain_address;
|
||||
void __user *input_pdh_cert_address;
|
||||
bool shutdown_required = false;
|
||||
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)))
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
/* If we query the length, FW responded with expected data. */
|
||||
@ -1957,6 +2043,9 @@ cmd:
|
||||
}
|
||||
|
||||
e_free_cert:
|
||||
if (shutdown_required)
|
||||
__sev_firmware_shutdown(sev, false);
|
||||
|
||||
kfree(cert_blob);
|
||||
e_free_pdh:
|
||||
kfree(pdh_blob);
|
||||
@ -1966,12 +2055,13 @@ e_free_pdh:
|
||||
static int sev_ioctl_do_snp_platform_status(struct sev_issue_cmd *argp)
|
||||
{
|
||||
struct sev_device *sev = psp_master->sev_data;
|
||||
bool shutdown_required = false;
|
||||
struct sev_data_snp_addr buf;
|
||||
struct page *status_page;
|
||||
int ret, error;
|
||||
void *data;
|
||||
int ret;
|
||||
|
||||
if (!sev->snp_initialized || !argp->data)
|
||||
if (!argp->data)
|
||||
return -EINVAL;
|
||||
|
||||
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);
|
||||
|
||||
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
|
||||
* 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;
|
||||
|
||||
cleanup:
|
||||
if (shutdown_required)
|
||||
__sev_snp_shutdown_locked(&error, false);
|
||||
|
||||
__free_pages(status_page, 0);
|
||||
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_data_snp_commit buf;
|
||||
bool shutdown_required = false;
|
||||
int ret, error;
|
||||
|
||||
if (!sev->snp_initialized)
|
||||
return -EINVAL;
|
||||
if (!sev->snp_initialized) {
|
||||
ret = snp_move_to_init_state(argp, &shutdown_required);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct sev_device *sev = psp_master->sev_data;
|
||||
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;
|
||||
|
||||
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)))
|
||||
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)
|
||||
{
|
||||
struct sev_device *sev = psp_master->sev_data;
|
||||
struct sev_user_data_snp_vlek_load input;
|
||||
bool shutdown_required = false;
|
||||
int ret, error;
|
||||
void *blob;
|
||||
int ret;
|
||||
|
||||
if (!sev->snp_initialized || !argp->data)
|
||||
if (!argp->data)
|
||||
return -EINVAL;
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
if (shutdown_required)
|
||||
__sev_snp_shutdown_locked(&error, false);
|
||||
|
||||
cleanup:
|
||||
kfree(blob);
|
||||
|
||||
return ret;
|
||||
@ -2296,7 +2429,7 @@ static void __sev_firmware_shutdown(struct sev_device *sev, bool panic)
|
||||
{
|
||||
int error;
|
||||
|
||||
__sev_platform_shutdown_locked(NULL);
|
||||
__sev_platform_shutdown_locked(&error);
|
||||
|
||||
if (sev_es_tmr) {
|
||||
/*
|
||||
@ -2339,6 +2472,15 @@ static void sev_firmware_shutdown(struct sev_device *sev)
|
||||
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)
|
||||
{
|
||||
struct sev_device *sev = psp->sev_data;
|
||||
@ -2373,10 +2515,6 @@ static int snp_shutdown_on_panic(struct notifier_block *nb,
|
||||
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,
|
||||
void *data, int *error)
|
||||
{
|
||||
@ -2390,9 +2528,7 @@ EXPORT_SYMBOL_GPL(sev_issue_cmd_external_user);
|
||||
void sev_pci_init(void)
|
||||
{
|
||||
struct sev_device *sev = psp_master->sev_data;
|
||||
struct sev_platform_init_args args = {0};
|
||||
u8 api_major, api_minor, build;
|
||||
int rc;
|
||||
|
||||
if (!sev)
|
||||
return;
|
||||
@ -2415,18 +2551,6 @@ void sev_pci_init(void)
|
||||
api_major, api_minor, 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;
|
||||
|
||||
err:
|
||||
@ -2443,7 +2567,4 @@ void sev_pci_exit(void)
|
||||
return;
|
||||
|
||||
sev_firmware_shutdown(sev);
|
||||
|
||||
atomic_notifier_chain_unregister(&panic_notifier_list,
|
||||
&snp_panic_notifier);
|
||||
}
|
||||
|
||||
@ -3,5 +3,11 @@
|
||||
# Generic DPLL drivers configuration
|
||||
#
|
||||
|
||||
menu "DPLL device support"
|
||||
|
||||
config DPLL
|
||||
bool
|
||||
|
||||
source "drivers/dpll/zl3073x/Kconfig"
|
||||
|
||||
endmenu
|
||||
|
||||
@ -7,3 +7,5 @@ obj-$(CONFIG_DPLL) += dpll.o
|
||||
dpll-y += dpll_core.o
|
||||
dpll-y += dpll_netlink.o
|
||||
dpll-y += dpll_nl.o
|
||||
|
||||
obj-$(CONFIG_ZL3073X) += zl3073x/
|
||||
|
||||
39
drivers/dpll/zl3073x/Kconfig
Normal file
39
drivers/dpll/zl3073x/Kconfig
Normal 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.
|
||||
10
drivers/dpll/zl3073x/Makefile
Normal file
10
drivers/dpll/zl3073x/Makefile
Normal 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
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
386
drivers/dpll/zl3073x/core.h
Normal 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 */
|
||||
253
drivers/dpll/zl3073x/devlink.c
Normal file
253
drivers/dpll/zl3073x/devlink.c
Normal 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);
|
||||
}
|
||||
12
drivers/dpll/zl3073x/devlink.h
Normal file
12
drivers/dpll/zl3073x/devlink.h
Normal 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
2318
drivers/dpll/zl3073x/dpll.c
Normal file
File diff suppressed because it is too large
Load Diff
46
drivers/dpll/zl3073x/dpll.h
Normal file
46
drivers/dpll/zl3073x/dpll.h
Normal 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 */
|
||||
76
drivers/dpll/zl3073x/i2c.c
Normal file
76
drivers/dpll/zl3073x/i2c.c
Normal 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
358
drivers/dpll/zl3073x/prop.c
Normal 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", ®))
|
||||
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 */
|
||||
}
|
||||
34
drivers/dpll/zl3073x/prop.h
Normal file
34
drivers/dpll/zl3073x/prop.h
Normal 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
266
drivers/dpll/zl3073x/regs.h
Normal 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 */
|
||||
76
drivers/dpll/zl3073x/spi.c
Normal file
76
drivers/dpll/zl3073x/spi.c
Normal 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");
|
||||
@ -542,7 +542,8 @@ enum {
|
||||
#define pasid_supported(iommu) (sm_supported(iommu) && \
|
||||
ecap_pasid((iommu)->ecap))
|
||||
#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) && \
|
||||
ecap_nest((iommu)->ecap))
|
||||
|
||||
|
||||
@ -98,19 +98,21 @@ struct ice_adapter *ice_adapter_get(struct pci_dev *pdev)
|
||||
|
||||
index = ice_adapter_xa_index(pdev);
|
||||
scoped_guard(mutex, &ice_adapters_mutex) {
|
||||
err = xa_insert(&ice_adapters, index, NULL, GFP_KERNEL);
|
||||
if (err == -EBUSY) {
|
||||
adapter = xa_load(&ice_adapters, index);
|
||||
adapter = xa_load(&ice_adapters, index);
|
||||
if (adapter) {
|
||||
refcount_inc(&adapter->refcount);
|
||||
WARN_ON_ONCE(adapter->index != ice_adapter_index(pdev));
|
||||
return adapter;
|
||||
}
|
||||
err = xa_reserve(&ice_adapters, index, GFP_KERNEL);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
||||
adapter = ice_adapter_new(pdev);
|
||||
if (!adapter)
|
||||
if (!adapter) {
|
||||
xa_release(&ice_adapters, index);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
xa_store(&ice_adapters, index, adapter, GFP_KERNEL);
|
||||
}
|
||||
return adapter;
|
||||
|
||||
@ -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_vport_config *vport_config;
|
||||
struct sockaddr *addr = p;
|
||||
u8 old_mac_addr[ETH_ALEN];
|
||||
struct idpf_vport *vport;
|
||||
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))
|
||||
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];
|
||||
err = idpf_add_mac_filter(vport, np, addr->sa_data, false);
|
||||
if (err) {
|
||||
__idpf_del_mac_filter(vport_config, addr->sa_data);
|
||||
ether_addr_copy(vport->default_mac_addr, netdev->dev_addr);
|
||||
goto unlock_mutex;
|
||||
}
|
||||
|
||||
if (is_valid_ether_addr(vport->default_mac_addr))
|
||||
idpf_del_mac_filter(vport, np, vport->default_mac_addr, false);
|
||||
if (is_valid_ether_addr(old_mac_addr))
|
||||
__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);
|
||||
|
||||
unlock_mutex:
|
||||
|
||||
@ -3516,6 +3516,16 @@ u32 idpf_get_vport_id(struct idpf_vport *vport)
|
||||
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
|
||||
* @adapter: private data struct
|
||||
@ -3645,6 +3655,7 @@ int idpf_add_del_mac_filters(struct idpf_vport *vport,
|
||||
list) {
|
||||
if (add && f->add) {
|
||||
ether_addr_copy(mac_addr[i].addr, f->macaddr);
|
||||
idpf_set_mac_type(vport, &mac_addr[i]);
|
||||
i++;
|
||||
f->add = false;
|
||||
if (i == total_filters)
|
||||
@ -3652,6 +3663,7 @@ int idpf_add_del_mac_filters(struct idpf_vport *vport,
|
||||
}
|
||||
if (!add && f->remove) {
|
||||
ether_addr_copy(mac_addr[i].addr, f->macaddr);
|
||||
idpf_set_mac_type(vport, &mac_addr[i]);
|
||||
i++;
|
||||
f->remove = false;
|
||||
if (i == total_filters)
|
||||
|
||||
@ -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_FLOW_COUNTERS);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@ -345,6 +345,7 @@ struct mlx5_fc {
|
||||
/* last{packets,bytes} are used for calculating deltas since last reading. */
|
||||
u64 lastpackets;
|
||||
u64 lastbytes;
|
||||
RH_KABI_EXTEND(refcount_t fc_local_refcount)
|
||||
};
|
||||
|
||||
struct mlx5_fc_bulk {
|
||||
|
||||
@ -562,17 +562,36 @@ mlx5_fc_local_create(u32 counter_id, u32 offset, u32 bulk_size)
|
||||
counter->id = counter_id;
|
||||
fc_bulk->base_id = counter_id - offset;
|
||||
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;
|
||||
refcount_set(&counter->fc_local_refcount, 1);
|
||||
return counter;
|
||||
}
|
||||
EXPORT_SYMBOL(mlx5_fc_local_create);
|
||||
|
||||
void mlx5_fc_local_destroy(struct mlx5_fc *counter)
|
||||
{
|
||||
if (!counter || counter->type != MLX5_FC_TYPE_LOCAL)
|
||||
return;
|
||||
|
||||
kfree(counter->bulk);
|
||||
kfree(counter);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
@ -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_fc_bulk *fc_bulk = counter->bulk;
|
||||
struct mlx5hws_action *hws_action;
|
||||
|
||||
create_ctx.hws_ctx = ctx;
|
||||
create_ctx.id = fc_bulk->base_id;
|
||||
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)
|
||||
{
|
||||
mlx5_fs_put_hws_action(&counter->bulk->hws_data);
|
||||
mlx5_fc_local_put(counter);
|
||||
}
|
||||
|
||||
@ -4509,7 +4509,7 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, int num_rqst,
|
||||
for (int i = 1; i < num_rqst; i++) {
|
||||
struct smb_rqst *old = &old_rq[i - 1];
|
||||
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);
|
||||
|
||||
orig_len += smb_rqst_len(server, old);
|
||||
|
||||
0
include/config/ZL3073X
Normal file
0
include/config/ZL3073X
Normal file
0
include/config/ZL3073X_I2C
Normal file
0
include/config/ZL3073X_I2C
Normal file
0
include/config/ZL3073X_SPI
Normal file
0
include/config/ZL3073X_SPI
Normal file
@ -3242,6 +3242,7 @@ CONFIG_NET_VENDOR_AQUANTIA=y
|
||||
CONFIG_HID_LENOVO=m
|
||||
CONFIG_CEPH_FS=m
|
||||
CONFIG_DRM_DISPLAY_HDMI_STATE_HELPER=y
|
||||
CONFIG_ZL3073X_I2C=m
|
||||
CONFIG_ATA_SFF=y
|
||||
CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
|
||||
CONFIG_PINCTRL=y
|
||||
@ -3992,6 +3993,7 @@ CONFIG_SUNRPC_GSS=m
|
||||
CONFIG_VIDEOMODE_HELPERS=y
|
||||
CONFIG_SQUASHFS_LZ4=y
|
||||
CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY=y
|
||||
CONFIG_ZL3073X_SPI=m
|
||||
CONFIG_EDAC_SUPPORT=y
|
||||
CONFIG_USB_PRINTER=m
|
||||
CONFIG_FW_CFG_SYSFS=y
|
||||
@ -4458,6 +4460,7 @@ CONFIG_NEED_DMA_MAP_STATE=y
|
||||
CONFIG_TCM_FC=m
|
||||
CONFIG_RCU_EXP_CPU_STALL_TIMEOUT=0
|
||||
CONFIG_OF=y
|
||||
CONFIG_ZL3073X=m
|
||||
CONFIG_MODULE_SIG_KEY=certs/signing_key.pem
|
||||
CONFIG_ARCH_MMAP_RND_BITS_MIN=14
|
||||
CONFIG_USB_SERIAL_SYMBOL=m
|
||||
|
||||
@ -578,6 +578,8 @@ deps_config := \
|
||||
drivers/pps/clients/Kconfig \
|
||||
drivers/pps/generators/Kconfig \
|
||||
drivers/ptp/Kconfig \
|
||||
drivers/dpll/Kconfig \
|
||||
drivers/dpll/zl3073x/Kconfig \
|
||||
drivers/pinctrl/Kconfig \
|
||||
drivers/pinctrl/actions/Kconfig \
|
||||
drivers/pinctrl/aspeed/Kconfig \
|
||||
@ -1458,7 +1460,6 @@ deps_config := \
|
||||
drivers/hte/Kconfig \
|
||||
drivers/cdx/Kconfig \
|
||||
drivers/cdx/controller/Kconfig \
|
||||
drivers/dpll/Kconfig \
|
||||
fs/Kconfig \
|
||||
fs/ext2/Kconfig \
|
||||
fs/ext4/Kconfig \
|
||||
|
||||
@ -3242,6 +3242,7 @@
|
||||
#define CONFIG_HID_LENOVO_MODULE 1
|
||||
#define CONFIG_CEPH_FS_MODULE 1
|
||||
#define CONFIG_DRM_DISPLAY_HDMI_STATE_HELPER 1
|
||||
#define CONFIG_ZL3073X_I2C_MODULE 1
|
||||
#define CONFIG_ATA_SFF 1
|
||||
#define CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024
|
||||
#define CONFIG_PINCTRL 1
|
||||
@ -3992,6 +3993,7 @@
|
||||
#define CONFIG_VIDEOMODE_HELPERS 1
|
||||
#define CONFIG_SQUASHFS_LZ4 1
|
||||
#define CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY 1
|
||||
#define CONFIG_ZL3073X_SPI_MODULE 1
|
||||
#define CONFIG_EDAC_SUPPORT 1
|
||||
#define CONFIG_USB_PRINTER_MODULE 1
|
||||
#define CONFIG_FW_CFG_SYSFS 1
|
||||
@ -4458,6 +4460,7 @@
|
||||
#define CONFIG_TCM_FC_MODULE 1
|
||||
#define CONFIG_RCU_EXP_CPU_STALL_TIMEOUT 0
|
||||
#define CONFIG_OF 1
|
||||
#define CONFIG_ZL3073X_MODULE 1
|
||||
#define CONFIG_MODULE_SIG_KEY "certs/signing_key.pem"
|
||||
#define CONFIG_ARCH_MMAP_RND_BITS_MIN 14
|
||||
#define CONFIG_USB_SERIAL_SYMBOL_MODULE 1
|
||||
|
||||
@ -6373,6 +6373,8 @@
|
||||
--cfg=CONFIG_CEPH_FS="m"
|
||||
--cfg=CONFIG_DRM_DISPLAY_HDMI_STATE_HELPER
|
||||
--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="y"
|
||||
--cfg=CONFIG_INPUT_MOUSEDEV_SCREEN_X="1024"
|
||||
@ -7853,6 +7855,8 @@
|
||||
--cfg=CONFIG_SQUASHFS_LZ4="y"
|
||||
--cfg=CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY
|
||||
--cfg=CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY="y"
|
||||
--cfg=CONFIG_ZL3073X_SPI
|
||||
--cfg=CONFIG_ZL3073X_SPI="m"
|
||||
--cfg=CONFIG_EDAC_SUPPORT
|
||||
--cfg=CONFIG_EDAC_SUPPORT="y"
|
||||
--cfg=CONFIG_USB_PRINTER
|
||||
@ -8770,6 +8774,8 @@
|
||||
--cfg=CONFIG_RCU_EXP_CPU_STALL_TIMEOUT="0"
|
||||
--cfg=CONFIG_OF
|
||||
--cfg=CONFIG_OF="y"
|
||||
--cfg=CONFIG_ZL3073X
|
||||
--cfg=CONFIG_ZL3073X="m"
|
||||
--cfg=CONFIG_MODULE_SIG_KEY="certs/signing_key.pem"
|
||||
--cfg=CONFIG_ARCH_MMAP_RND_BITS_MIN="14"
|
||||
--cfg=CONFIG_USB_SERIAL_SYMBOL
|
||||
|
||||
@ -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);
|
||||
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_get(struct mlx5_fc *counter);
|
||||
void mlx5_fc_local_put(struct mlx5_fc *counter);
|
||||
u64 mlx5_fc_query_lastuse(struct mlx5_fc *counter);
|
||||
void mlx5_fc_query_cached(struct mlx5_fc *counter,
|
||||
u64 *bytes, u64 *packets, u64 *lastuse);
|
||||
|
||||
@ -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 *snp_alloc_firmware_page(gfp_t mask);
|
||||
void snp_free_firmware_page(void *addr);
|
||||
void sev_platform_shutdown(void);
|
||||
|
||||
#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 sev_platform_shutdown(void) { }
|
||||
|
||||
#endif /* CONFIG_CRYPTO_DEV_SP_PSP */
|
||||
|
||||
#endif /* __PSP_SEV_H__ */
|
||||
|
||||
@ -548,6 +548,7 @@ struct hci_dev {
|
||||
struct hci_conn_hash conn_hash;
|
||||
|
||||
struct list_head mesh_pending;
|
||||
struct mutex mgmt_pending_lock;
|
||||
struct list_head mgmt_pending;
|
||||
struct list_head reject_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;
|
||||
}
|
||||
|
||||
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,
|
||||
bdaddr_t *ba,
|
||||
__u8 ba_type)
|
||||
@ -2408,7 +2430,6 @@ void mgmt_advertising_added(struct sock *sk, struct hci_dev *hdev,
|
||||
u8 instance);
|
||||
void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev,
|
||||
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);
|
||||
void mgmt_adv_monitor_device_lost(struct hci_dev *hdev, u16 handle,
|
||||
bdaddr_t *bdaddr, u8 addr_type);
|
||||
|
||||
@ -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_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_get_random_address(struct hci_dev *hdev, bool require_privacy,
|
||||
|
||||
@ -848,7 +848,7 @@ struct mgmt_cp_set_mesh {
|
||||
__le16 window;
|
||||
__le16 period;
|
||||
__u8 num_ad_types;
|
||||
__u8 ad_types[];
|
||||
__u8 ad_types[] __counted_by(num_ad_types);
|
||||
} __packed;
|
||||
#define MGMT_SET_MESH_RECEIVER_SIZE 6
|
||||
|
||||
|
||||
@ -272,13 +272,14 @@ static int io_waitid_wait(struct wait_queue_entry *wait, unsigned mode,
|
||||
if (!pid_child_should_wake(wo, p))
|
||||
return 0;
|
||||
|
||||
list_del_init(&wait->entry);
|
||||
|
||||
/* cancel is in progress */
|
||||
if (atomic_fetch_inc(&iw->refs) & IO_WAITID_REF_MASK)
|
||||
return 1;
|
||||
|
||||
req->io_task_work.func = io_waitid_cb;
|
||||
io_req_task_work_add(req);
|
||||
list_del_init(&wait->entry);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@ -1895,10 +1895,8 @@ void hci_free_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor)
|
||||
if (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--;
|
||||
mgmt_adv_monitor_removed(hdev, monitor->handle);
|
||||
}
|
||||
|
||||
kfree(monitor);
|
||||
}
|
||||
@ -2510,6 +2508,7 @@ struct hci_dev *hci_alloc_dev_priv(int sizeof_priv)
|
||||
|
||||
mutex_init(&hdev->lock);
|
||||
mutex_init(&hdev->req_lock);
|
||||
mutex_init(&hdev->mgmt_pending_lock);
|
||||
|
||||
ida_init(&hdev->unset_handle_ida);
|
||||
|
||||
|
||||
@ -3115,8 +3115,18 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, void *data,
|
||||
|
||||
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);
|
||||
if (!conn) {
|
||||
if (!conn ||
|
||||
(conn->role == HCI_ROLE_MASTER && conn->state != BT_CONNECT)) {
|
||||
/* In case of error status and there is no connection pending
|
||||
* 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);
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
for (i = 0; i < ev->num; i++) {
|
||||
struct hci_comp_pkts_info *info = &ev->handles[i];
|
||||
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);
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
|
||||
if (!conn) {
|
||||
/* Check for existing connection:
|
||||
*
|
||||
* 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
|
||||
* just unlock as there is nothing to cleanup.
|
||||
*/
|
||||
|
||||
@ -3412,13 +3412,13 @@ int hci_update_scan_sync(struct hci_dev *hdev)
|
||||
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;
|
||||
|
||||
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,
|
||||
sizeof(cp), &cp,
|
||||
@ -3471,7 +3471,7 @@ int hci_powered_update_sync(struct hci_dev *hdev)
|
||||
hci_write_fast_connectable_sync(hdev, false);
|
||||
hci_update_scan_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);
|
||||
}
|
||||
|
||||
|
||||
@ -1324,8 +1324,7 @@ static void mgmt_set_powered_complete(struct hci_dev *hdev, void *data, int err)
|
||||
struct mgmt_mode *cp;
|
||||
|
||||
/* Make sure cmd still outstanding. */
|
||||
if (err == -ECANCELED ||
|
||||
cmd != pending_find(MGMT_OP_SET_POWERED, hdev))
|
||||
if (err == -ECANCELED || !mgmt_pending_valid(hdev, cmd))
|
||||
return;
|
||||
|
||||
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_pending_remove(cmd);
|
||||
mgmt_pending_free(cmd);
|
||||
}
|
||||
|
||||
static int set_powered_sync(struct hci_dev *hdev, void *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. */
|
||||
if (cmd != pending_find(MGMT_OP_SET_POWERED, hdev))
|
||||
if (!__mgmt_pending_listed(hdev, cmd)) {
|
||||
mutex_unlock(&hdev->mgmt_pending_lock);
|
||||
return -ECANCELED;
|
||||
}
|
||||
|
||||
cp = cmd->param;
|
||||
memcpy(&cp, cmd->param, sizeof(cp));
|
||||
|
||||
mutex_unlock(&hdev->mgmt_pending_lock);
|
||||
|
||||
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,
|
||||
@ -1447,22 +1452,17 @@ static void settings_rsp(struct mgmt_pending_cmd *cmd, void *data)
|
||||
|
||||
send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
|
||||
|
||||
list_del(&cmd->list);
|
||||
|
||||
if (match->sk == NULL) {
|
||||
match->sk = cmd->sk;
|
||||
sock_hold(match->sk);
|
||||
}
|
||||
|
||||
mgmt_pending_free(cmd);
|
||||
}
|
||||
|
||||
static void cmd_status_rsp(struct mgmt_pending_cmd *cmd, void *data)
|
||||
{
|
||||
u8 *status = data;
|
||||
|
||||
mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
|
||||
mgmt_pending_remove(cmd);
|
||||
mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, *status);
|
||||
}
|
||||
|
||||
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) {
|
||||
cmd->cmd_complete(cmd, match->mgmt_status);
|
||||
mgmt_pending_remove(cmd);
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
@ -1524,15 +1522,14 @@ static void mgmt_set_discoverable_complete(struct hci_dev *hdev, void *data,
|
||||
bt_dev_dbg(hdev, "err %d", err);
|
||||
|
||||
/* Make sure cmd still outstanding. */
|
||||
if (err == -ECANCELED ||
|
||||
cmd != pending_find(MGMT_OP_SET_DISCOVERABLE, hdev))
|
||||
if (err == -ECANCELED || !mgmt_pending_valid(hdev, cmd))
|
||||
return;
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
if (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);
|
||||
goto done;
|
||||
}
|
||||
@ -1547,12 +1544,15 @@ static void mgmt_set_discoverable_complete(struct hci_dev *hdev, void *data,
|
||||
new_settings(hdev, cmd->sk);
|
||||
|
||||
done:
|
||||
mgmt_pending_remove(cmd);
|
||||
mgmt_pending_free(cmd);
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static int set_discoverable_sync(struct hci_dev *hdev, void *data)
|
||||
{
|
||||
if (!mgmt_pending_listed(hdev, data))
|
||||
return -ECANCELED;
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
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);
|
||||
|
||||
/* Make sure cmd still outstanding. */
|
||||
if (err == -ECANCELED ||
|
||||
cmd != pending_find(MGMT_OP_SET_CONNECTABLE, hdev))
|
||||
if (err == -ECANCELED || !mgmt_pending_valid(hdev, cmd))
|
||||
return;
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
if (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;
|
||||
}
|
||||
|
||||
@ -1715,7 +1714,7 @@ static void mgmt_set_connectable_complete(struct hci_dev *hdev, void *data,
|
||||
new_settings(hdev, cmd->sk);
|
||||
|
||||
done:
|
||||
mgmt_pending_remove(cmd);
|
||||
mgmt_pending_free(cmd);
|
||||
|
||||
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)
|
||||
{
|
||||
if (!mgmt_pending_listed(hdev, data))
|
||||
return -ECANCELED;
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
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 mgmt_pending_cmd *cmd = data;
|
||||
struct mgmt_mode *cp = cmd->param;
|
||||
u8 enable = cp->val;
|
||||
struct mgmt_mode *cp;
|
||||
u8 enable;
|
||||
bool changed;
|
||||
|
||||
/* 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;
|
||||
|
||||
cp = cmd->param;
|
||||
enable = cp->val;
|
||||
|
||||
if (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);
|
||||
}
|
||||
|
||||
mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
|
||||
&mgmt_err);
|
||||
mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_err);
|
||||
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);
|
||||
}
|
||||
|
||||
mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
|
||||
settings_rsp(cmd, &match);
|
||||
|
||||
if (changed)
|
||||
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)
|
||||
{
|
||||
struct mgmt_pending_cmd *cmd = data;
|
||||
struct mgmt_mode *cp = cmd->param;
|
||||
struct mgmt_mode cp;
|
||||
bool changed = false;
|
||||
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);
|
||||
|
||||
err = hci_write_ssp_mode_sync(hdev, cp->val);
|
||||
err = hci_write_ssp_mode_sync(hdev, cp.val);
|
||||
|
||||
if (!err && changed)
|
||||
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)
|
||||
{
|
||||
struct mgmt_pending_cmd *cmd = data;
|
||||
struct cmd_lookup match = { NULL, hdev };
|
||||
u8 status = mgmt_status(err);
|
||||
|
||||
bt_dev_dbg(hdev, "err %d", err);
|
||||
|
||||
if (status) {
|
||||
mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
|
||||
&status);
|
||||
if (err == -ECANCELED || !mgmt_pending_valid(hdev, data))
|
||||
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);
|
||||
|
||||
if (match.sk)
|
||||
sock_put(match.sk);
|
||||
|
||||
done:
|
||||
mgmt_pending_free(cmd);
|
||||
}
|
||||
|
||||
static int set_le_sync(struct hci_dev *hdev, void *data)
|
||||
{
|
||||
struct mgmt_pending_cmd *cmd = data;
|
||||
struct mgmt_mode *cp = cmd->param;
|
||||
u8 val = !!cp->val;
|
||||
struct mgmt_mode cp;
|
||||
u8 val;
|
||||
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) {
|
||||
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;
|
||||
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) {
|
||||
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);
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
|
||||
mgmt_pending_remove(cmd);
|
||||
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)
|
||||
{
|
||||
struct mgmt_pending_cmd *cmd = data;
|
||||
struct mgmt_cp_set_mesh *cp = cmd->param;
|
||||
size_t len = cmd->param_len;
|
||||
DEFINE_FLEX(struct mgmt_cp_set_mesh, cp, ad_types, num_ad_types,
|
||||
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));
|
||||
|
||||
@ -2160,7 +2215,10 @@ static int set_mesh_sync(struct hci_dev *hdev, void *data)
|
||||
else
|
||||
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 (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_pending_cmd *cmd;
|
||||
__u16 period, window;
|
||||
int err = 0;
|
||||
|
||||
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,
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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_pending_free(cmd);
|
||||
@ -3425,7 +3501,7 @@ static int pairing_complete(struct mgmt_pending_cmd *cmd, u8 status)
|
||||
bacpy(&rp.addr.bdaddr, &conn->dst);
|
||||
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));
|
||||
|
||||
/* 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)
|
||||
{
|
||||
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);
|
||||
|
||||
bt_dev_dbg(hdev, "err %d", err);
|
||||
|
||||
if (err == -ECANCELED ||
|
||||
cmd != pending_find(MGMT_OP_SET_LOCAL_NAME, hdev))
|
||||
if (err == -ECANCELED || !mgmt_pending_valid(hdev, cmd))
|
||||
return;
|
||||
|
||||
cp = cmd->param;
|
||||
|
||||
if (status) {
|
||||
mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
|
||||
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);
|
||||
}
|
||||
|
||||
mgmt_pending_remove(cmd);
|
||||
mgmt_pending_free(cmd);
|
||||
}
|
||||
|
||||
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)) {
|
||||
hci_update_name_sync(hdev);
|
||||
hci_update_name_sync(hdev, cp.name);
|
||||
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)
|
||||
{
|
||||
struct mgmt_pending_cmd *cmd = data;
|
||||
struct sk_buff *skb = cmd->skb;
|
||||
struct sk_buff *skb;
|
||||
u8 status = mgmt_status(err);
|
||||
|
||||
if (err == -ECANCELED ||
|
||||
cmd != pending_find(MGMT_OP_SET_PHY_CONFIGURATION, hdev))
|
||||
return;
|
||||
skb = cmd->skb;
|
||||
|
||||
if (!status) {
|
||||
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))
|
||||
kfree_skb(skb);
|
||||
|
||||
mgmt_pending_remove(cmd);
|
||||
mgmt_pending_free(cmd);
|
||||
}
|
||||
|
||||
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_cp_set_phy_configuration *cp = cmd->param;
|
||||
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));
|
||||
|
||||
@ -4209,7 +4300,7 @@ static int set_phy_configuration(struct sock *sk, struct hci_dev *hdev,
|
||||
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);
|
||||
if (!cmd)
|
||||
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);
|
||||
}
|
||||
|
||||
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_pending_cmd *cmd;
|
||||
struct sock *sk_skip = NULL;
|
||||
struct mgmt_cp_remove_adv_monitor *cp;
|
||||
|
||||
cmd = pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev);
|
||||
if (cmd) {
|
||||
cp = cmd->param;
|
||||
ev.monitor_handle = handle;
|
||||
|
||||
if (cp->monitor_handle)
|
||||
sk_skip = cmd->sk;
|
||||
}
|
||||
|
||||
ev.monitor_handle = cpu_to_le16(handle);
|
||||
|
||||
mgmt_event(MGMT_EV_ADV_MONITOR_REMOVED, hdev, &ev, sizeof(ev), sk_skip);
|
||||
mgmt_event(MGMT_EV_ADV_MONITOR_REMOVED, hdev, &ev, sizeof(ev), sk);
|
||||
}
|
||||
|
||||
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_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);
|
||||
|
||||
@ -5194,7 +5285,7 @@ static void mgmt_add_adv_patterns_monitor_complete(struct hci_dev *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_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)
|
||||
{
|
||||
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,
|
||||
@ -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) ||
|
||||
pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR, hdev) ||
|
||||
pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI, hdev) ||
|
||||
pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev)) {
|
||||
pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI, hdev)) {
|
||||
status = MGMT_STATUS_BUSY;
|
||||
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_cp_remove_adv_monitor *cp;
|
||||
|
||||
if (status == -ECANCELED ||
|
||||
cmd != pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev))
|
||||
if (status == -ECANCELED)
|
||||
return;
|
||||
|
||||
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;
|
||||
|
||||
if (!status)
|
||||
if (!status) {
|
||||
mgmt_adv_monitor_removed(cmd->sk, hdev, cp->monitor_handle);
|
||||
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_pending_remove(cmd);
|
||||
mgmt_pending_free(cmd);
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
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)
|
||||
{
|
||||
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;
|
||||
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);
|
||||
|
||||
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_RSSI, hdev)) {
|
||||
status = MGMT_STATUS_BUSY;
|
||||
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) {
|
||||
status = MGMT_STATUS_NO_RESOURCES;
|
||||
goto unlock;
|
||||
@ -5460,7 +5557,7 @@ static int remove_adv_monitor(struct sock *sk, struct hci_dev *hdev,
|
||||
mgmt_remove_adv_monitor_complete);
|
||||
|
||||
if (err) {
|
||||
mgmt_pending_remove(cmd);
|
||||
mgmt_pending_free(cmd);
|
||||
|
||||
if (err == -ENOMEM)
|
||||
status = MGMT_STATUS_NO_RESOURCES;
|
||||
@ -5480,7 +5577,8 @@ unlock:
|
||||
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;
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -5782,17 +5881,12 @@ static void start_discovery_complete(struct hci_dev *hdev, void *data, int err)
|
||||
|
||||
bt_dev_dbg(hdev, "err %d", err);
|
||||
|
||||
if (err == -ECANCELED)
|
||||
if (err == -ECANCELED || !mgmt_pending_valid(hdev, cmd))
|
||||
return;
|
||||
|
||||
if (cmd != pending_find(MGMT_OP_START_DISCOVERY, hdev) &&
|
||||
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),
|
||||
mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_status(err),
|
||||
cmd->param, 1);
|
||||
mgmt_pending_remove(cmd);
|
||||
mgmt_pending_free(cmd);
|
||||
|
||||
hci_discovery_set_state(hdev, err ? DISCOVERY_STOPPED:
|
||||
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)
|
||||
{
|
||||
if (!mgmt_pending_listed(hdev, data))
|
||||
return -ECANCELED;
|
||||
|
||||
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;
|
||||
|
||||
if (err == -ECANCELED ||
|
||||
cmd != pending_find(MGMT_OP_STOP_DISCOVERY, hdev))
|
||||
if (err == -ECANCELED || !mgmt_pending_valid(hdev, cmd))
|
||||
return;
|
||||
|
||||
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);
|
||||
mgmt_pending_remove(cmd);
|
||||
mgmt_pending_free(cmd);
|
||||
|
||||
if (!err)
|
||||
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)
|
||||
{
|
||||
if (!mgmt_pending_listed(hdev, data))
|
||||
return -ECANCELED;
|
||||
|
||||
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)
|
||||
{
|
||||
struct mgmt_pending_cmd *cmd = data;
|
||||
struct cmd_lookup match = { NULL, hdev };
|
||||
u8 instance;
|
||||
struct adv_info *adv_instance;
|
||||
u8 status = mgmt_status(err);
|
||||
|
||||
if (err == -ECANCELED || !mgmt_pending_valid(hdev, data))
|
||||
return;
|
||||
|
||||
if (status) {
|
||||
mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
|
||||
cmd_status_rsp, &status);
|
||||
mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, status);
|
||||
mgmt_pending_free(cmd);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -6246,8 +6349,7 @@ static void set_advertising_complete(struct hci_dev *hdev, void *data, int err)
|
||||
else
|
||||
hci_dev_clear_flag(hdev, HCI_ADVERTISING);
|
||||
|
||||
mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
|
||||
&match);
|
||||
settings_rsp(cmd, &match);
|
||||
|
||||
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)
|
||||
{
|
||||
struct mgmt_pending_cmd *cmd = data;
|
||||
struct mgmt_mode *cp = cmd->param;
|
||||
u8 val = !!cp->val;
|
||||
struct mgmt_mode cp;
|
||||
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);
|
||||
else
|
||||
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,
|
||||
MGMT_STATUS_NOT_SUPPORTED);
|
||||
|
||||
/* Keep allowed ranges in sync with set_mesh() */
|
||||
interval = __le16_to_cpu(cp->interval);
|
||||
|
||||
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);
|
||||
|
||||
mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
|
||||
mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_err);
|
||||
} else {
|
||||
send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
mgmt_pending_free(cmd);
|
||||
@ -7334,7 +7450,7 @@ static void get_clock_info_complete(struct hci_dev *hdev, void *data, int err)
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
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);
|
||||
u16 eir_len;
|
||||
|
||||
if (err == -ECANCELED ||
|
||||
cmd != pending_find(MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev))
|
||||
return;
|
||||
|
||||
if (!status) {
|
||||
if (!skb)
|
||||
status = MGMT_STATUS_FAILED;
|
||||
@ -8144,7 +8256,7 @@ done:
|
||||
kfree_skb(skb);
|
||||
|
||||
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,
|
||||
@ -8153,7 +8265,7 @@ static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk,
|
||||
struct mgmt_pending_cmd *cmd;
|
||||
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));
|
||||
if (!cmd)
|
||||
return -ENOMEM;
|
||||
@ -8584,10 +8696,10 @@ static void add_advertising_complete(struct hci_dev *hdev, void *data, int err)
|
||||
rp.instance = cp->instance;
|
||||
|
||||
if (err)
|
||||
mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
|
||||
mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode,
|
||||
mgmt_status(err));
|
||||
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));
|
||||
|
||||
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);
|
||||
|
||||
mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
|
||||
mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode,
|
||||
mgmt_status(err));
|
||||
} 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));
|
||||
}
|
||||
|
||||
@ -8925,10 +9037,10 @@ static void add_ext_adv_data_complete(struct hci_dev *hdev, void *data, int err)
|
||||
rp.instance = cp->instance;
|
||||
|
||||
if (err)
|
||||
mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
|
||||
mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode,
|
||||
mgmt_status(err));
|
||||
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_pending_free(cmd);
|
||||
@ -9087,10 +9199,10 @@ static void remove_advertising_complete(struct hci_dev *hdev, void *data,
|
||||
rp.instance = cp->instance;
|
||||
|
||||
if (err)
|
||||
mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
|
||||
mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode,
|
||||
mgmt_status(err));
|
||||
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_pending_free(cmd);
|
||||
@ -9362,7 +9474,7 @@ void mgmt_index_removed(struct hci_dev *hdev)
|
||||
if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
|
||||
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)) {
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@ -9415,7 +9528,8 @@ void __mgmt_power_off(struct hci_dev *hdev)
|
||||
struct cmd_lookup match = { NULL, hdev };
|
||||
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
|
||||
* use the appropriate INVALID_INDEX status. Otherwise use
|
||||
@ -9429,7 +9543,7 @@ void __mgmt_power_off(struct hci_dev *hdev)
|
||||
else
|
||||
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) {
|
||||
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);
|
||||
|
||||
cmd->cmd_complete(cmd, 0);
|
||||
mgmt_pending_remove(cmd);
|
||||
}
|
||||
|
||||
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_pending_cmd *cmd;
|
||||
|
||||
mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
|
||||
hdev);
|
||||
mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, true,
|
||||
unpair_device_rsp, hdev);
|
||||
|
||||
cmd = pending_find(MGMT_OP_DISCONNECT, hdev);
|
||||
if (!cmd)
|
||||
@ -9920,7 +10033,7 @@ void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
|
||||
|
||||
if (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);
|
||||
return;
|
||||
}
|
||||
@ -9930,8 +10043,8 @@ void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
|
||||
else
|
||||
changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY);
|
||||
|
||||
mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
|
||||
&match);
|
||||
mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, true,
|
||||
settings_rsp, &match);
|
||||
|
||||
if (changed)
|
||||
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) };
|
||||
|
||||
mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
|
||||
mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
|
||||
mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
|
||||
mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, false, 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) {
|
||||
mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
|
||||
|
||||
@ -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 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)
|
||||
continue;
|
||||
if (cmd->opcode == opcode)
|
||||
|
||||
if (cmd->opcode == opcode) {
|
||||
mutex_unlock(&hdev->mgmt_pending_lock);
|
||||
return cmd;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&hdev->mgmt_pending_lock);
|
||||
|
||||
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 *data)
|
||||
{
|
||||
struct mgmt_pending_cmd *cmd, *tmp;
|
||||
|
||||
mutex_lock(&hdev->mgmt_pending_lock);
|
||||
|
||||
list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
|
||||
if (opcode > 0 && cmd->opcode != opcode)
|
||||
continue;
|
||||
|
||||
if (remove)
|
||||
list_del(&cmd->list);
|
||||
|
||||
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,
|
||||
@ -254,7 +271,7 @@ struct mgmt_pending_cmd *mgmt_pending_new(struct sock *sk, u16 opcode,
|
||||
return NULL;
|
||||
|
||||
cmd->opcode = opcode;
|
||||
cmd->index = hdev->id;
|
||||
cmd->hdev = hdev;
|
||||
|
||||
cmd->param = kmemdup(data, len, GFP_KERNEL);
|
||||
if (!cmd->param) {
|
||||
@ -280,7 +297,9 @@ struct mgmt_pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
|
||||
if (!cmd)
|
||||
return NULL;
|
||||
|
||||
mutex_lock(&hdev->mgmt_pending_lock);
|
||||
list_add_tail(&cmd->list, &hdev->mgmt_pending);
|
||||
mutex_unlock(&hdev->mgmt_pending_lock);
|
||||
|
||||
return cmd;
|
||||
}
|
||||
@ -294,10 +313,59 @@ void mgmt_pending_free(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);
|
||||
mutex_unlock(&cmd->hdev->mgmt_pending_lock);
|
||||
|
||||
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 (*cb)(struct mgmt_mesh_tx *mesh_tx, void *data),
|
||||
void *data, struct sock *sk)
|
||||
|
||||
@ -33,7 +33,7 @@ struct mgmt_mesh_tx {
|
||||
struct mgmt_pending_cmd {
|
||||
struct list_head list;
|
||||
u16 opcode;
|
||||
int index;
|
||||
struct hci_dev *hdev;
|
||||
void *param;
|
||||
size_t param_len;
|
||||
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 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 *data);
|
||||
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 mgmt_pending_free(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 (*cb)(struct mgmt_mesh_tx *mesh_tx, void *data),
|
||||
void *data, struct sock *sk);
|
||||
|
||||
@ -212,6 +212,7 @@ void j1939_priv_get(struct j1939_priv *priv);
|
||||
|
||||
/* notify/alert all j1939 sockets bound to ifindex */
|
||||
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);
|
||||
void j1939_tp_init(struct j1939_priv *priv);
|
||||
|
||||
|
||||
@ -377,6 +377,11 @@ static int j1939_netdev_notify(struct notifier_block *nb,
|
||||
j1939_sk_netdev_event_netdown(priv);
|
||||
j1939_ecu_unmap_all(priv);
|
||||
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);
|
||||
|
||||
@ -1298,6 +1298,55 @@ void j1939_sk_netdev_event_netdown(struct j1939_priv *priv)
|
||||
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,
|
||||
unsigned long arg)
|
||||
{
|
||||
|
||||
@ -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)))
|
||||
return -EINVAL;
|
||||
|
||||
if (skb_is_gso(skb))
|
||||
skb_gso_reset(skb);
|
||||
|
||||
skb_copy_bits(skb, skb_mac_offset(skb), &eh, ETH_HLEN);
|
||||
pskb_pull(skb, ETH_HLEN);
|
||||
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)))
|
||||
return -EINVAL;
|
||||
|
||||
if (skb_is_gso(skb))
|
||||
skb_gso_reset(skb);
|
||||
|
||||
skb_copy_bits(skb, skb_mac_offset(skb), &eh, ETH_HLEN);
|
||||
pskb_pull(skb, ETH_HLEN);
|
||||
skb_reset_network_header(skb);
|
||||
|
||||
1
redhat/configs/common/generic/CONFIG_ZL3073X
Normal file
1
redhat/configs/common/generic/CONFIG_ZL3073X
Normal file
@ -0,0 +1 @@
|
||||
CONFIG_ZL3073X=m
|
||||
1
redhat/configs/common/generic/CONFIG_ZL3073X_I2C
Normal file
1
redhat/configs/common/generic/CONFIG_ZL3073X_I2C
Normal file
@ -0,0 +1 @@
|
||||
CONFIG_ZL3073X_I2C=m
|
||||
1
redhat/configs/common/generic/CONFIG_ZL3073X_SPI
Normal file
1
redhat/configs/common/generic/CONFIG_ZL3073X_SPI
Normal file
@ -0,0 +1 @@
|
||||
CONFIG_ZL3073X_SPI=m
|
||||
1
redhat/configs/common/generic/s390x/CONFIG_ZL3073X
Normal file
1
redhat/configs/common/generic/s390x/CONFIG_ZL3073X
Normal file
@ -0,0 +1 @@
|
||||
# CONFIG_ZL3073X is not set
|
||||
1
redhat/configs/common/generic/s390x/CONFIG_ZL3073X_I2C
Normal file
1
redhat/configs/common/generic/s390x/CONFIG_ZL3073X_I2C
Normal file
@ -0,0 +1 @@
|
||||
# CONFIG_ZL3073X_I2C is not set
|
||||
1
redhat/configs/common/generic/s390x/CONFIG_ZL3073X_SPI
Normal file
1
redhat/configs/common/generic/s390x/CONFIG_ZL3073X_SPI
Normal file
@ -0,0 +1 @@
|
||||
# CONFIG_ZL3073X_SPI is not set
|
||||
1
redhat/configs/common/generic/x86/CONFIG_I2C_MUX_PCA954x
Normal file
1
redhat/configs/common/generic/x86/CONFIG_I2C_MUX_PCA954x
Normal file
@ -0,0 +1 @@
|
||||
CONFIG_I2C_MUX_PCA954x=m
|
||||
@ -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]
|
||||
- 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}
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
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.almalinux,1,AlmaLinux,kernel-uki-virt-addons,6.12.0-124.16.1.el10.x86_64,mailto:security@almalinux.org
|
||||
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.20.1.el10.x86_64,mailto:security@almalinux.org
|
||||
|
||||
4
uki.sbat
4
uki.sbat
@ -1,3 +1,3 @@
|
||||
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.almalinux,1,AlmaLinux,kernel-uki-virt,6.12.0-124.16.1.el10.x86_64,mailto:security@almalinux.org
|
||||
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.20.1.el10.x86_64,mailto:security@almalinux.org
|
||||
|
||||
Loading…
Reference in New Issue
Block a user