Merge a229327733 ("Merge tag 'printk-for-5.17' of git://git.kernel.org/pub/scm/linux/kernel/git/printk/linux") into android-mainline

Steps on the way to 5.17-rc1

Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
Change-Id: I6e68b1f6037ff9acffe7352ff72921e3a9ab4aa0
This commit is contained in:
Greg Kroah-Hartman
2022-01-14 13:47:14 +01:00
34 changed files with 853 additions and 521 deletions

View File

@@ -0,0 +1,76 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/thermal/rzg2l-thermal.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Renesas RZ/G2L Thermal Sensor Unit
description:
On RZ/G2L SoCs, the thermal sensor unit (TSU) measures the
temperature(Tj) inside the LSI.
maintainers:
- Biju Das <biju.das.jz@bp.renesas.com>
properties:
compatible:
items:
- enum:
- renesas,r9a07g044-tsu # RZ/G2{L,LC}
- const: renesas,rzg2l-tsu
reg:
maxItems: 1
clocks:
maxItems: 1
power-domains:
maxItems: 1
resets:
maxItems: 1
"#thermal-sensor-cells":
const: 1
required:
- compatible
- reg
- clocks
- power-domains
- resets
- "#thermal-sensor-cells"
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/r9a07g044-cpg.h>
tsu: thermal@10059400 {
compatible = "renesas,r9a07g044-tsu",
"renesas,rzg2l-tsu";
reg = <0x10059400 0x400>;
clocks = <&cpg CPG_MOD R9A07G044_TSU_PCLK>;
resets = <&cpg R9A07G044_TSU_PRESETN>;
power-domains = <&cpg>;
#thermal-sensor-cells = <1>;
};
thermal-zones {
cpu-thermal {
polling-delay-passive = <250>;
polling-delay = <1000>;
thermal-sensors = <&tsu 0>;
trips {
sensor_crit: sensor-crit {
temperature = <125000>;
hysteresis = <1000>;
type = "critical";
};
};
};
};

View File

@@ -5,7 +5,7 @@
Referencing hierarchical data nodes
===================================
:Copyright: |copy| 2018 Intel Corporation
:Copyright: |copy| 2018, 2021 Intel Corporation
:Author: Sakari Ailus <sakari.ailus@linux.intel.com>
ACPI in general allows referring to device objects in the tree only.
@@ -13,9 +13,9 @@ Hierarchical data extension nodes may not be referred to directly, hence this
document defines a scheme to implement such references.
A reference consist of the device object name followed by one or more
hierarchical data extension [1] keys. Specifically, the hierarchical data
extension node which is referred to by the key shall lie directly under the
parent object i.e. either the device object or another hierarchical data
hierarchical data extension [dsd-guide] keys. Specifically, the hierarchical
data extension node which is referred to by the key shall lie directly under
the parent object i.e. either the device object or another hierarchical data
extension node.
The keys in the hierarchical data nodes shall consist of the name of the node,
@@ -33,7 +33,7 @@ extension key.
Example
=======
In the ASL snippet below, the "reference" _DSD property [2] contains a
In the ASL snippet below, the "reference" _DSD property contains a
device object reference to DEV0 and under that device object, a
hierarchical data extension key "node@1" referring to the NOD1 object
and lastly, a hierarchical data extension key "anothernode" referring to
@@ -52,12 +52,14 @@ the ANOD object which is also the final target node of the reference.
Name (NOD0, Package() {
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package () {
Package () { "reg", 0 },
Package () { "random-property", 3 },
}
})
Name (NOD1, Package() {
ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
Package () {
Package () { "reg", 1 },
Package () { "anothernode", "ANOD" },
}
})
@@ -74,7 +76,11 @@ the ANOD object which is also the final target node of the reference.
Name (_DSD, Package () {
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package () {
Package () { "reference", ^DEV0, "node@1", "anothernode" },
Package () {
"reference", Package () {
^DEV0, "node@1", "anothernode"
}
},
}
})
}
@@ -85,10 +91,6 @@ Documentation/firmware-guide/acpi/dsd/graph.rst.
References
==========
[1] Hierarchical Data Extension UUID For _DSD.
<https://www.uefi.org/sites/default/files/resources/_DSD-hierarchical-data-extension-UUID-v1.1.pdf>,
referenced 2018-07-17.
[2] Device Properties UUID For _DSD.
<https://www.uefi.org/sites/default/files/resources/_DSD-device-properties-UUID.pdf>,
referenced 2016-10-04.
[dsd-guide] DSD Guide.
https://github.com/UEFI/DSD-Guide/blob/main/dsd-guide.adoc, referenced
2021-11-30.

View File

@@ -7,11 +7,11 @@ Graphs
_DSD
====
_DSD (Device Specific Data) [7] is a predefined ACPI device
_DSD (Device Specific Data) [dsd-guide] is a predefined ACPI device
configuration object that can be used to convey information on
hardware features which are not specifically covered by the ACPI
specification [1][6]. There are two _DSD extensions that are relevant
for graphs: property [4] and hierarchical data extensions [5]. The
specification [acpi]. There are two _DSD extensions that are relevant
for graphs: property [dsd-guide] and hierarchical data extensions. The
property extension provides generic key-value pairs whereas the
hierarchical data extension supports nodes with references to other
nodes, forming a tree. The nodes in the tree may contain properties as
@@ -36,8 +36,9 @@ Ports and endpoints
===================
The port and endpoint concepts are very similar to those in Devicetree
[3]. A port represents an interface in a device, and an endpoint
represents a connection to that interface.
[devicetree, graph-bindings]. A port represents an interface in a device, and
an endpoint represents a connection to that interface. Also see [data-node-ref]
for generic data node references.
All port nodes are located under the device's "_DSD" node in the hierarchical
data extension tree. The data extension related to each port node must begin
@@ -153,25 +154,20 @@ the "ISP" device and vice versa.
References
==========
[1] _DSD (Device Specific Data) Implementation Guide.
https://www.uefi.org/sites/default/files/resources/_DSD-implementation-guide-toplevel-1_1.htm,
referenced 2016-10-03.
[acpi] Advanced Configuration and Power Interface Specification.
https://uefi.org/specifications/ACPI/6.4/, referenced 2021-11-30.
[2] Devicetree. https://www.devicetree.org, referenced 2016-10-03.
[data-node-ref] Documentation/firmware-guide/acpi/dsd/data-node-references.rst
[3] Documentation/devicetree/bindings/graph.txt
[devicetree] Devicetree. https://www.devicetree.org, referenced 2016-10-03.
[4] Device Properties UUID For _DSD.
https://www.uefi.org/sites/default/files/resources/_DSD-device-properties-UUID.pdf,
referenced 2016-10-04.
[dsd-guide] DSD Guide.
https://github.com/UEFI/DSD-Guide/blob/main/dsd-guide.adoc, referenced
2021-11-30.
[5] Hierarchical Data Extension UUID For _DSD.
https://www.uefi.org/sites/default/files/resources/_DSD-hierarchical-data-extension-UUID-v1.1.pdf,
referenced 2016-10-04.
[6] Advanced Configuration and Power Interface Specification.
https://www.uefi.org/sites/default/files/resources/ACPI_6_1.pdf,
referenced 2016-10-04.
[7] _DSD Device Properties Usage Rules.
[dsd-rules] _DSD Device Properties Usage Rules.
Documentation/firmware-guide/acpi/DSD-properties-rules.rst
[graph-bindings] Common bindings for device graphs (Devicetree).
https://github.com/devicetree-org/dt-schema/blob/main/schemas/graph.yaml,
referenced 2021-11-30.

View File

@@ -5,19 +5,20 @@
Describing and referring to LEDs in ACPI
========================================
Individual LEDs are described by hierarchical data extension [6] nodes under the
Individual LEDs are described by hierarchical data extension [5] nodes under the
device node, the LED driver chip. The "reg" property in the LED specific nodes
tells the numerical ID of each individual LED output to which the LEDs are
connected. [3] The hierarchical data nodes are named "led@X", where X is the
connected. [leds] The hierarchical data nodes are named "led@X", where X is the
number of the LED output.
Referring to LEDs in Device tree is documented in [4], in "flash-leds" property
documentation. In short, LEDs are directly referred to by using phandles.
Referring to LEDs in Device tree is documented in [video-interfaces], in
"flash-leds" property documentation. In short, LEDs are directly referred to by
using phandles.
While Device tree allows referring to any node in the tree[1], in ACPI
references are limited to device nodes only [2]. For this reason using the same
mechanism on ACPI is not possible. A mechanism to refer to non-device ACPI nodes
is documented in [7].
While Device tree allows referring to any node in the tree [devicetree], in
ACPI references are limited to device nodes only [acpi]. For this reason using
the same mechanism on ACPI is not possible. A mechanism to refer to non-device
ACPI nodes is documented in [data-node-ref].
ACPI allows (as does DT) using integer arguments after the reference. A
combination of the LED driver device reference and an integer argument,
@@ -90,22 +91,17 @@ where
References
==========
[1] Device tree. https://www.devicetree.org, referenced 2019-02-21.
[acpi] Advanced Configuration and Power Interface Specification.
https://uefi.org/specifications/ACPI/6.4/, referenced 2021-11-30.
[2] Advanced Configuration and Power Interface Specification.
https://uefi.org/sites/default/files/resources/ACPI_6_3_final_Jan30.pdf,
referenced 2019-02-21.
[data-node-ref] Documentation/firmware-guide/acpi/dsd/data-node-references.rst
[3] Documentation/devicetree/bindings/leds/common.txt
[devicetree] Devicetree. https://www.devicetree.org, referenced 2019-02-21.
[4] Documentation/devicetree/bindings/media/video-interfaces.txt
[dsd-guide] DSD Guide.
https://github.com/UEFI/DSD-Guide/blob/main/dsd-guide.adoc, referenced
2021-11-30.
[5] Device Properties UUID For _DSD.
https://www.uefi.org/sites/default/files/resources/_DSD-device-properties-UUID.pdf,
referenced 2019-02-21.
[leds] Documentation/devicetree/bindings/leds/common.yaml
[6] Hierarchical Data Extension UUID For _DSD.
https://www.uefi.org/sites/default/files/resources/_DSD-hierarchical-data-extension-UUID-v1.1.pdf,
referenced 2019-02-21.
[7] Documentation/firmware-guide/acpi/dsd/data-node-references.rst
[video-interfaces] Documentation/devicetree/bindings/media/video-interfaces.yaml

View File

@@ -4,17 +4,17 @@
MDIO bus and PHYs in ACPI
=========================
The PHYs on an MDIO bus [1] are probed and registered using
The PHYs on an MDIO bus [phy] are probed and registered using
fwnode_mdiobus_register_phy().
Later, for connecting these PHYs to their respective MACs, the PHYs registered
on the MDIO bus have to be referenced.
This document introduces two _DSD properties that are to be used
for connecting PHYs on the MDIO bus [3] to the MAC layer.
for connecting PHYs on the MDIO bus [dsd-properties-rules] to the MAC layer.
These properties are defined in accordance with the "Device
Properties UUID For _DSD" [2] document and the
Properties UUID For _DSD" [dsd-guide] document and the
daffd814-6eba-4d8c-8a91-bc9bbf4aa301 UUID must be used in the Device
Data Descriptors containing them.
@@ -48,22 +48,22 @@ as device object references (e.g. \_SB.MDI0.PHY1).
phy-mode
--------
The "phy-mode" _DSD property is used to describe the connection to
the PHY. The valid values for "phy-mode" are defined in [4].
the PHY. The valid values for "phy-mode" are defined in [ethernet-controller].
managed
-------
Optional property, which specifies the PHY management type.
The valid values for "managed" are defined in [4].
The valid values for "managed" are defined in [ethernet-controller].
fixed-link
----------
The "fixed-link" is described by a data-only subnode of the
MAC port, which is linked in the _DSD package via
hierarchical data extension (UUID dbb8e3e6-5886-4ba6-8795-1319f52a966b
in accordance with [5] "_DSD Implementation Guide" document).
in accordance with [dsd-guide] "_DSD Implementation Guide" document).
The subnode should comprise a required property ("speed") and
possibly the optional ones - complete list of parameters and
their values are specified in [4].
their values are specified in [ethernet-controller].
The following ASL example illustrates the usage of these properties.
@@ -188,12 +188,14 @@ MAC node example with a "fixed-link" subnode.
References
==========
[1] Documentation/networking/phy.rst
[phy] Documentation/networking/phy.rst
[2] https://www.uefi.org/sites/default/files/resources/_DSD-device-properties-UUID.pdf
[dsd-properties-rules]
Documentation/firmware-guide/acpi/DSD-properties-rules.rst
[3] Documentation/firmware-guide/acpi/DSD-properties-rules.rst
[ethernet-controller]
Documentation/devicetree/bindings/net/ethernet-controller.yaml
[4] Documentation/devicetree/bindings/net/ethernet-controller.yaml
[5] https://github.com/UEFI/DSD-Guide/blob/main/dsd-guide.pdf
[dsd-guide] DSD Guide.
https://github.com/UEFI/DSD-Guide/blob/main/dsd-guide.adoc, referenced
2021-11-30.

View File

@@ -15403,6 +15403,7 @@ M: Sergey Senozhatsky <senozhatsky@chromium.org>
R: Steven Rostedt <rostedt@goodmis.org>
R: John Ogness <john.ogness@linutronix.de>
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/printk/linux.git
F: include/linux/printk.h
F: kernel/printk/
@@ -17741,12 +17742,17 @@ F: drivers/firmware/arm_sdei.c
F: include/linux/arm_sdei.h
F: include/uapi/linux/arm_sdei.h
SOFTWARE NODES
SOFTWARE NODES AND DEVICE PROPERTIES
R: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
R: Daniel Scally <djrscally@gmail.com>
R: Heikki Krogerus <heikki.krogerus@linux.intel.com>
R: Sakari Ailus <sakari.ailus@linux.intel.com>
L: linux-acpi@vger.kernel.org
S: Maintained
F: drivers/base/property.c
F: drivers/base/swnode.c
F: include/linux/fwnode.h
F: include/linux/property.h
SOFTWARE RAID (Multiple Disks) SUPPORT
M: Song Liu <song@kernel.org>
@@ -20527,7 +20533,7 @@ M: Sergey Senozhatsky <senozhatsky@chromium.org>
R: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
R: Rasmus Villemoes <linux@rasmusvillemoes.dk>
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/pmladek/printk.git
T: git git://git.kernel.org/pub/scm/linux/kernel/git/printk/linux.git
F: Documentation/core-api/printk-formats.rst
F: lib/test_printf.c
F: lib/test_scanf.c

View File

@@ -3581,7 +3581,6 @@ void device_del(struct device *dev)
device_pm_remove(dev);
driver_deferred_probe_del(dev);
device_platform_notify_remove(dev);
device_remove_properties(dev);
device_links_purge(dev);
if (dev->bus)

View File

@@ -507,54 +507,6 @@ struct fwnode_handle *fwnode_find_reference(const struct fwnode_handle *fwnode,
}
EXPORT_SYMBOL_GPL(fwnode_find_reference);
/**
* device_remove_properties - Remove properties from a device object.
* @dev: Device whose properties to remove.
*
* The function removes properties previously associated to the device
* firmware node with device_add_properties(). Memory allocated to the
* properties will also be released.
*/
void device_remove_properties(struct device *dev)
{
struct fwnode_handle *fwnode = dev_fwnode(dev);
if (!fwnode)
return;
if (is_software_node(fwnode->secondary)) {
fwnode_remove_software_node(fwnode->secondary);
set_secondary_fwnode(dev, NULL);
}
}
EXPORT_SYMBOL_GPL(device_remove_properties);
/**
* device_add_properties - Add a collection of properties to a device object.
* @dev: Device to add properties to.
* @properties: Collection of properties to add.
*
* Associate a collection of device properties represented by @properties with
* @dev. The function takes a copy of @properties.
*
* WARNING: The callers should not use this function if it is known that there
* is no real firmware node associated with @dev! In that case the callers
* should create a software node and assign it to @dev directly.
*/
int device_add_properties(struct device *dev,
const struct property_entry *properties)
{
struct fwnode_handle *fwnode;
fwnode = fwnode_create_software_node(properties, NULL);
if (IS_ERR(fwnode))
return PTR_ERR(fwnode);
set_secondary_fwnode(dev, fwnode);
return 0;
}
EXPORT_SYMBOL_GPL(device_add_properties);
/**
* fwnode_get_name - Return the name of a node
* @fwnode: The firmware node
@@ -1059,43 +1011,17 @@ fwnode_graph_get_remote_endpoint(const struct fwnode_handle *fwnode)
}
EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_endpoint);
/**
* fwnode_graph_get_remote_node - get remote parent node for given port/endpoint
* @fwnode: pointer to parent fwnode_handle containing graph port/endpoint
* @port_id: identifier of the parent port node
* @endpoint_id: identifier of the endpoint node
*
* Return: Remote fwnode handle associated with remote endpoint node linked
* to @node. Use fwnode_node_put() on it when done.
*/
struct fwnode_handle *
fwnode_graph_get_remote_node(const struct fwnode_handle *fwnode, u32 port_id,
u32 endpoint_id)
static bool fwnode_graph_remote_available(struct fwnode_handle *ep)
{
struct fwnode_handle *endpoint = NULL;
struct fwnode_handle *dev_node;
bool available;
while ((endpoint = fwnode_graph_get_next_endpoint(fwnode, endpoint))) {
struct fwnode_endpoint fwnode_ep;
struct fwnode_handle *remote;
int ret;
dev_node = fwnode_graph_get_remote_port_parent(ep);
available = fwnode_device_is_available(dev_node);
fwnode_handle_put(dev_node);
ret = fwnode_graph_parse_endpoint(endpoint, &fwnode_ep);
if (ret < 0)
continue;
if (fwnode_ep.port != port_id || fwnode_ep.id != endpoint_id)
continue;
remote = fwnode_graph_get_remote_port_parent(endpoint);
if (!remote)
return NULL;
return fwnode_device_is_available(remote) ? remote : NULL;
}
return NULL;
return available;
}
EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_node);
/**
* fwnode_graph_get_endpoint_by_id - get endpoint by port and endpoint numbers
@@ -1111,8 +1037,8 @@ EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_node);
* has not been found, look for the closest endpoint ID greater than the
* specified one and return the endpoint that corresponds to it, if present.
*
* Do not return endpoints that belong to disabled devices, unless
* FWNODE_GRAPH_DEVICE_DISABLED is passed in @flags.
* Does not return endpoints that belong to disabled devices or endpoints that
* are unconnected, unless FWNODE_GRAPH_DEVICE_DISABLED is passed in @flags.
*
* The returned endpoint needs to be released by calling fwnode_handle_put() on
* it when it is not needed any more.
@@ -1121,25 +1047,17 @@ struct fwnode_handle *
fwnode_graph_get_endpoint_by_id(const struct fwnode_handle *fwnode,
u32 port, u32 endpoint, unsigned long flags)
{
struct fwnode_handle *ep = NULL, *best_ep = NULL;
struct fwnode_handle *ep, *best_ep = NULL;
unsigned int best_ep_id = 0;
bool endpoint_next = flags & FWNODE_GRAPH_ENDPOINT_NEXT;
bool enabled_only = !(flags & FWNODE_GRAPH_DEVICE_DISABLED);
while ((ep = fwnode_graph_get_next_endpoint(fwnode, ep))) {
fwnode_graph_for_each_endpoint(fwnode, ep) {
struct fwnode_endpoint fwnode_ep = { 0 };
int ret;
if (enabled_only) {
struct fwnode_handle *dev_node;
bool available;
dev_node = fwnode_graph_get_remote_port_parent(ep);
available = fwnode_device_is_available(dev_node);
fwnode_handle_put(dev_node);
if (!available)
continue;
}
if (enabled_only && !fwnode_graph_remote_available(ep))
continue;
ret = fwnode_graph_parse_endpoint(ep, &fwnode_ep);
if (ret < 0)
@@ -1172,6 +1090,31 @@ fwnode_graph_get_endpoint_by_id(const struct fwnode_handle *fwnode,
}
EXPORT_SYMBOL_GPL(fwnode_graph_get_endpoint_by_id);
/**
* fwnode_graph_get_endpoint_count - Count endpoints on a device node
* @fwnode: The node related to a device
* @flags: fwnode lookup flags
* Count endpoints in a device node.
*
* If FWNODE_GRAPH_DEVICE_DISABLED flag is specified, also unconnected endpoints
* and endpoints connected to disabled devices are counted.
*/
unsigned int fwnode_graph_get_endpoint_count(struct fwnode_handle *fwnode,
unsigned long flags)
{
struct fwnode_handle *ep;
unsigned int count = 0;
fwnode_graph_for_each_endpoint(fwnode, ep) {
if (flags & FWNODE_GRAPH_DEVICE_DISABLED ||
fwnode_graph_remote_available(ep))
count++;
}
return count;
}
EXPORT_SYMBOL_GPL(fwnode_graph_get_endpoint_count);
/**
* fwnode_graph_parse_endpoint - parse common endpoint node properties
* @fwnode: pointer to endpoint fwnode_handle
@@ -1206,8 +1149,10 @@ fwnode_graph_devcon_match(struct fwnode_handle *fwnode, const char *con_id,
fwnode_graph_for_each_endpoint(fwnode, ep) {
node = fwnode_graph_get_remote_port_parent(ep);
if (!fwnode_device_is_available(node))
if (!fwnode_device_is_available(node)) {
fwnode_handle_put(node);
continue;
}
ret = match(node, con_id, data);
fwnode_handle_put(node);

View File

@@ -529,7 +529,7 @@ software_node_get_reference_args(const struct fwnode_handle *fwnode,
return -ENOENT;
if (nargs_prop) {
error = property_entry_read_int_array(swnode->node->properties,
error = property_entry_read_int_array(ref->node->properties,
nargs_prop, sizeof(u32),
&nargs_prop_val, 1);
if (error)

View File

@@ -1850,7 +1850,7 @@ static void quirk_huawei_pcie_sva(struct pci_dev *pdev)
* can set it directly.
*/
if (!pdev->dev.of_node &&
device_add_properties(&pdev->dev, properties))
device_create_managed_software_node(&pdev->dev, properties, NULL))
pci_warn(pdev, "could not add stall property");
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_HUAWEI, 0xa250, quirk_huawei_pcie_sva);

View File

@@ -1845,7 +1845,6 @@ static int tegra_vi_graph_init(struct tegra_vi *vi)
struct tegra_vi_channel *chan;
struct fwnode_handle *fwnode = dev_fwnode(vi->dev);
int ret;
struct fwnode_handle *remote = NULL;
/*
* Walk the links to parse the full graph. Each channel will have
@@ -1857,11 +1856,16 @@ static int tegra_vi_graph_init(struct tegra_vi *vi)
* next channels.
*/
list_for_each_entry(chan, &vi->vi_chans, list) {
remote = fwnode_graph_get_remote_node(fwnode, chan->portnos[0],
0);
if (!remote)
struct fwnode_handle *ep, *remote;
ep = fwnode_graph_get_endpoint_by_id(fwnode,
chan->portnos[0], 0, 0);
if (!ep)
continue;
remote = fwnode_graph_get_remote_port_parent(ep);
fwnode_handle_put(ep);
ret = tegra_vi_graph_parse_one(chan, remote);
fwnode_handle_put(remote);
if (ret < 0 || list_empty(&chan->notifier.asd_list))

View File

@@ -354,6 +354,15 @@ config RCAR_GEN3_THERMAL
Enable this to plug the R-Car Gen3 or RZ/G2 thermal sensor driver into
the Linux thermal framework.
config RZG2L_THERMAL
tristate "Renesas RZ/G2L thermal driver"
depends on ARCH_RENESAS || COMPILE_TEST
depends on HAS_IOMEM
depends on OF
help
Enable this to plug the RZ/G2L thermal sensor driver into the Linux
thermal framework.
config KIRKWOOD_THERMAL
tristate "Temperature sensor on Marvell Kirkwood SoCs"
depends on MACH_KIRKWOOD || COMPILE_TEST

View File

@@ -37,6 +37,7 @@ obj-$(CONFIG_SUN8I_THERMAL) += sun8i_thermal.o
obj-$(CONFIG_ROCKCHIP_THERMAL) += rockchip_thermal.o
obj-$(CONFIG_RCAR_THERMAL) += rcar_thermal.o
obj-$(CONFIG_RCAR_GEN3_THERMAL) += rcar_gen3_thermal.o
obj-$(CONFIG_RZG2L_THERMAL) += rzg2l_thermal.o
obj-$(CONFIG_KIRKWOOD_THERMAL) += kirkwood_thermal.o
obj-y += samsung/
obj-$(CONFIG_DOVE_THERMAL) += dove_thermal.o

View File

@@ -21,6 +21,7 @@
#define TPS 0x4
#define TRITSR 0x20 /* TMU immediate temp */
#define TER_ADC_PD BIT(30)
#define TER_EN BIT(31)
#define TRITSR_TEMP0_VAL_MASK 0xff
#define TRITSR_TEMP1_VAL_MASK 0xff0000
@@ -113,6 +114,8 @@ static void imx8mm_tmu_enable(struct imx8mm_tmu *tmu, bool enable)
val = readl_relaxed(tmu->base + TER);
val = enable ? (val | TER_EN) : (val & ~TER_EN);
if (tmu->socdata->version == TMU_VER2)
val = enable ? (val & ~TER_ADC_PD) : (val | TER_ADC_PD);
writel_relaxed(val, tmu->base + TER);
}

View File

@@ -15,6 +15,7 @@
#include <linux/regmap.h>
#include <linux/thermal.h>
#include <linux/nvmem-consumer.h>
#include <linux/pm_runtime.h>
#define REG_SET 0x4
#define REG_CLR 0x8
@@ -194,6 +195,7 @@ static struct thermal_soc_data thermal_imx7d_data = {
};
struct imx_thermal_data {
struct device *dev;
struct cpufreq_policy *policy;
struct thermal_zone_device *tz;
struct thermal_cooling_device *cdev;
@@ -252,44 +254,15 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
const struct thermal_soc_data *soc_data = data->socdata;
struct regmap *map = data->tempmon;
unsigned int n_meas;
bool wait, run_measurement;
u32 val;
int ret;
run_measurement = !data->irq_enabled;
if (!run_measurement) {
/* Check if a measurement is currently in progress */
regmap_read(map, soc_data->temp_data, &val);
wait = !(val & soc_data->temp_valid_mask);
} else {
/*
* Every time we measure the temperature, we will power on the
* temperature sensor, enable measurements, take a reading,
* disable measurements, power off the temperature sensor.
*/
regmap_write(map, soc_data->sensor_ctrl + REG_CLR,
soc_data->power_down_mask);
regmap_write(map, soc_data->sensor_ctrl + REG_SET,
soc_data->measure_temp_mask);
wait = true;
}
/*
* According to the temp sensor designers, it may require up to ~17us
* to complete a measurement.
*/
if (wait)
usleep_range(20, 50);
ret = pm_runtime_resume_and_get(data->dev);
if (ret < 0)
return ret;
regmap_read(map, soc_data->temp_data, &val);
if (run_measurement) {
regmap_write(map, soc_data->sensor_ctrl + REG_CLR,
soc_data->measure_temp_mask);
regmap_write(map, soc_data->sensor_ctrl + REG_SET,
soc_data->power_down_mask);
}
if ((val & soc_data->temp_valid_mask) == 0) {
dev_dbg(&tz->device, "temp measurement never finished\n");
return -EAGAIN;
@@ -328,6 +301,8 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
enable_irq(data->irq);
}
pm_runtime_put(data->dev);
return 0;
}
@@ -335,24 +310,16 @@ static int imx_change_mode(struct thermal_zone_device *tz,
enum thermal_device_mode mode)
{
struct imx_thermal_data *data = tz->devdata;
struct regmap *map = data->tempmon;
const struct thermal_soc_data *soc_data = data->socdata;
if (mode == THERMAL_DEVICE_ENABLED) {
regmap_write(map, soc_data->sensor_ctrl + REG_CLR,
soc_data->power_down_mask);
regmap_write(map, soc_data->sensor_ctrl + REG_SET,
soc_data->measure_temp_mask);
pm_runtime_get(data->dev);
if (!data->irq_enabled) {
data->irq_enabled = true;
enable_irq(data->irq);
}
} else {
regmap_write(map, soc_data->sensor_ctrl + REG_CLR,
soc_data->measure_temp_mask);
regmap_write(map, soc_data->sensor_ctrl + REG_SET,
soc_data->power_down_mask);
pm_runtime_put(data->dev);
if (data->irq_enabled) {
disable_irq(data->irq);
@@ -393,6 +360,11 @@ static int imx_set_trip_temp(struct thermal_zone_device *tz, int trip,
int temp)
{
struct imx_thermal_data *data = tz->devdata;
int ret;
ret = pm_runtime_resume_and_get(data->dev);
if (ret < 0)
return ret;
/* do not allow changing critical threshold */
if (trip == IMX_TRIP_CRITICAL)
@@ -406,6 +378,8 @@ static int imx_set_trip_temp(struct thermal_zone_device *tz, int trip,
imx_set_alarm_temp(data, temp);
pm_runtime_put(data->dev);
return 0;
}
@@ -681,6 +655,8 @@ static int imx_thermal_probe(struct platform_device *pdev)
if (!data)
return -ENOMEM;
data->dev = &pdev->dev;
map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "fsl,tempmon");
if (IS_ERR(map)) {
ret = PTR_ERR(map);
@@ -800,6 +776,16 @@ static int imx_thermal_probe(struct platform_device *pdev)
data->socdata->power_down_mask);
regmap_write(map, data->socdata->sensor_ctrl + REG_SET,
data->socdata->measure_temp_mask);
/* After power up, we need a delay before first access can be done. */
usleep_range(20, 50);
/* the core was configured and enabled just before */
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(data->dev);
ret = pm_runtime_resume_and_get(data->dev);
if (ret < 0)
goto disable_runtime_pm;
data->irq_enabled = true;
ret = thermal_zone_device_enable(data->tz);
@@ -814,10 +800,15 @@ static int imx_thermal_probe(struct platform_device *pdev)
goto thermal_zone_unregister;
}
pm_runtime_put(data->dev);
return 0;
thermal_zone_unregister:
thermal_zone_device_unregister(data->tz);
disable_runtime_pm:
pm_runtime_put_noidle(data->dev);
pm_runtime_disable(data->dev);
clk_disable:
clk_disable_unprepare(data->thermal_clk);
legacy_cleanup:
@@ -829,13 +820,9 @@ legacy_cleanup:
static int imx_thermal_remove(struct platform_device *pdev)
{
struct imx_thermal_data *data = platform_get_drvdata(pdev);
struct regmap *map = data->tempmon;
/* Disable measurements */
regmap_write(map, data->socdata->sensor_ctrl + REG_SET,
data->socdata->power_down_mask);
if (!IS_ERR(data->thermal_clk))
clk_disable_unprepare(data->thermal_clk);
pm_runtime_put_noidle(data->dev);
pm_runtime_disable(data->dev);
thermal_zone_device_unregister(data->tz);
imx_thermal_unregister_legacy_cooling(data);
@@ -858,9 +845,8 @@ static int __maybe_unused imx_thermal_suspend(struct device *dev)
ret = thermal_zone_device_disable(data->tz);
if (ret)
return ret;
clk_disable_unprepare(data->thermal_clk);
return 0;
return pm_runtime_force_suspend(data->dev);
}
static int __maybe_unused imx_thermal_resume(struct device *dev)
@@ -868,19 +854,70 @@ static int __maybe_unused imx_thermal_resume(struct device *dev)
struct imx_thermal_data *data = dev_get_drvdata(dev);
int ret;
ret = clk_prepare_enable(data->thermal_clk);
ret = pm_runtime_force_resume(data->dev);
if (ret)
return ret;
/* Enabled thermal sensor after resume */
ret = thermal_zone_device_enable(data->tz);
return thermal_zone_device_enable(data->tz);
}
static int __maybe_unused imx_thermal_runtime_suspend(struct device *dev)
{
struct imx_thermal_data *data = dev_get_drvdata(dev);
const struct thermal_soc_data *socdata = data->socdata;
struct regmap *map = data->tempmon;
int ret;
ret = regmap_write(map, socdata->sensor_ctrl + REG_CLR,
socdata->measure_temp_mask);
if (ret)
return ret;
ret = regmap_write(map, socdata->sensor_ctrl + REG_SET,
socdata->power_down_mask);
if (ret)
return ret;
clk_disable_unprepare(data->thermal_clk);
return 0;
}
static SIMPLE_DEV_PM_OPS(imx_thermal_pm_ops,
imx_thermal_suspend, imx_thermal_resume);
static int __maybe_unused imx_thermal_runtime_resume(struct device *dev)
{
struct imx_thermal_data *data = dev_get_drvdata(dev);
const struct thermal_soc_data *socdata = data->socdata;
struct regmap *map = data->tempmon;
int ret;
ret = clk_prepare_enable(data->thermal_clk);
if (ret)
return ret;
ret = regmap_write(map, socdata->sensor_ctrl + REG_CLR,
socdata->power_down_mask);
if (ret)
return ret;
ret = regmap_write(map, socdata->sensor_ctrl + REG_SET,
socdata->measure_temp_mask);
if (ret)
return ret;
/*
* According to the temp sensor designers, it may require up to ~17us
* to complete a measurement.
*/
usleep_range(20, 50);
return 0;
}
static const struct dev_pm_ops imx_thermal_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(imx_thermal_suspend, imx_thermal_resume)
SET_RUNTIME_PM_OPS(imx_thermal_runtime_suspend,
imx_thermal_runtime_resume, NULL)
};
static struct platform_driver imx_thermal = {
.driver = {

View File

@@ -250,8 +250,9 @@ static int fill_art(char __user *ubuf)
get_single_name(arts[i].source, art_user[i].source_device);
get_single_name(arts[i].target, art_user[i].target_device);
/* copy the rest int data in addition to source and target */
memcpy(&art_user[i].weight, &arts[i].weight,
sizeof(u64) * (ACPI_NR_ART_ELEMENTS - 2));
BUILD_BUG_ON(sizeof(art_user[i].data) !=
sizeof(u64) * (ACPI_NR_ART_ELEMENTS - 2));
memcpy(&art_user[i].data, &arts[i].data, sizeof(art_user[i].data));
}
if (copy_to_user(ubuf, art_user, art_len))

View File

@@ -17,17 +17,19 @@
struct art {
acpi_handle source;
acpi_handle target;
u64 weight;
u64 ac0_max;
u64 ac1_max;
u64 ac2_max;
u64 ac3_max;
u64 ac4_max;
u64 ac5_max;
u64 ac6_max;
u64 ac7_max;
u64 ac8_max;
u64 ac9_max;
struct_group(data,
u64 weight;
u64 ac0_max;
u64 ac1_max;
u64 ac2_max;
u64 ac3_max;
u64 ac4_max;
u64 ac5_max;
u64 ac6_max;
u64 ac7_max;
u64 ac8_max;
u64 ac9_max;
);
} __packed;
struct trt {
@@ -47,17 +49,19 @@ union art_object {
struct {
char source_device[8]; /* ACPI single name */
char target_device[8]; /* ACPI single name */
u64 weight;
u64 ac0_max_level;
u64 ac1_max_level;
u64 ac2_max_level;
u64 ac3_max_level;
u64 ac4_max_level;
u64 ac5_max_level;
u64 ac6_max_level;
u64 ac7_max_level;
u64 ac8_max_level;
u64 ac9_max_level;
struct_group(data,
u64 weight;
u64 ac0_max_level;
u64 ac1_max_level;
u64 ac2_max_level;
u64 ac3_max_level;
u64 ac4_max_level;
u64 ac5_max_level;
u64 ac6_max_level;
u64 ac7_max_level;
u64 ac8_max_level;
u64 ac9_max_level;
);
};
u64 __data[ACPI_NR_ART_ELEMENTS];
};

View File

@@ -80,7 +80,8 @@ void proc_thermal_rfim_remove(struct pci_dev *pdev);
int proc_thermal_mbox_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv);
void proc_thermal_mbox_remove(struct pci_dev *pdev);
int processor_thermal_send_mbox_cmd(struct pci_dev *pdev, u16 cmd_id, u32 cmd_data, u64 *cmd_resp);
int processor_thermal_send_mbox_read_cmd(struct pci_dev *pdev, u16 id, u64 *resp);
int processor_thermal_send_mbox_write_cmd(struct pci_dev *pdev, u16 id, u32 data);
int proc_thermal_add(struct device *dev, struct proc_thermal_device *priv);
void proc_thermal_remove(struct proc_thermal_device *proc_priv);
int proc_thermal_suspend(struct device *dev);

View File

@@ -24,19 +24,15 @@
static DEFINE_MUTEX(mbox_lock);
static int send_mbox_cmd(struct pci_dev *pdev, u16 cmd_id, u32 cmd_data, u64 *cmd_resp)
static int wait_for_mbox_ready(struct proc_thermal_device *proc_priv)
{
struct proc_thermal_device *proc_priv;
u32 retries, data;
int ret;
mutex_lock(&mbox_lock);
proc_priv = pci_get_drvdata(pdev);
/* Poll for rb bit == 0 */
retries = MBOX_RETRY_COUNT;
do {
data = readl((void __iomem *) (proc_priv->mmio_base + MBOX_OFFSET_INTERFACE));
data = readl(proc_priv->mmio_base + MBOX_OFFSET_INTERFACE);
if (data & BIT_ULL(MBOX_BUSY_BIT)) {
ret = -EBUSY;
continue;
@@ -45,53 +41,78 @@ static int send_mbox_cmd(struct pci_dev *pdev, u16 cmd_id, u32 cmd_data, u64 *cm
break;
} while (--retries);
return ret;
}
static int send_mbox_write_cmd(struct pci_dev *pdev, u16 id, u32 data)
{
struct proc_thermal_device *proc_priv;
u32 reg_data;
int ret;
proc_priv = pci_get_drvdata(pdev);
mutex_lock(&mbox_lock);
ret = wait_for_mbox_ready(proc_priv);
if (ret)
goto unlock_mbox;
if (cmd_id == MBOX_CMD_WORKLOAD_TYPE_WRITE)
writel(cmd_data, (void __iomem *) ((proc_priv->mmio_base + MBOX_OFFSET_DATA)));
writel(data, (proc_priv->mmio_base + MBOX_OFFSET_DATA));
/* Write command register */
data = BIT_ULL(MBOX_BUSY_BIT) | cmd_id;
writel(data, (void __iomem *) ((proc_priv->mmio_base + MBOX_OFFSET_INTERFACE)));
reg_data = BIT_ULL(MBOX_BUSY_BIT) | id;
writel(reg_data, (proc_priv->mmio_base + MBOX_OFFSET_INTERFACE));
/* Poll for rb bit == 0 */
retries = MBOX_RETRY_COUNT;
do {
data = readl((void __iomem *) (proc_priv->mmio_base + MBOX_OFFSET_INTERFACE));
if (data & BIT_ULL(MBOX_BUSY_BIT)) {
ret = -EBUSY;
continue;
}
if (data) {
ret = -ENXIO;
goto unlock_mbox;
}
ret = 0;
if (!cmd_resp)
break;
if (cmd_id == MBOX_CMD_WORKLOAD_TYPE_READ)
*cmd_resp = readl((void __iomem *) (proc_priv->mmio_base + MBOX_OFFSET_DATA));
else
*cmd_resp = readq((void __iomem *) (proc_priv->mmio_base + MBOX_OFFSET_DATA));
break;
} while (--retries);
ret = wait_for_mbox_ready(proc_priv);
unlock_mbox:
mutex_unlock(&mbox_lock);
return ret;
}
int processor_thermal_send_mbox_cmd(struct pci_dev *pdev, u16 cmd_id, u32 cmd_data, u64 *cmd_resp)
static int send_mbox_read_cmd(struct pci_dev *pdev, u16 id, u64 *resp)
{
return send_mbox_cmd(pdev, cmd_id, cmd_data, cmd_resp);
struct proc_thermal_device *proc_priv;
u32 reg_data;
int ret;
proc_priv = pci_get_drvdata(pdev);
mutex_lock(&mbox_lock);
ret = wait_for_mbox_ready(proc_priv);
if (ret)
goto unlock_mbox;
/* Write command register */
reg_data = BIT_ULL(MBOX_BUSY_BIT) | id;
writel(reg_data, (proc_priv->mmio_base + MBOX_OFFSET_INTERFACE));
ret = wait_for_mbox_ready(proc_priv);
if (ret)
goto unlock_mbox;
if (id == MBOX_CMD_WORKLOAD_TYPE_READ)
*resp = readl(proc_priv->mmio_base + MBOX_OFFSET_DATA);
else
*resp = readq(proc_priv->mmio_base + MBOX_OFFSET_DATA);
unlock_mbox:
mutex_unlock(&mbox_lock);
return ret;
}
EXPORT_SYMBOL_GPL(processor_thermal_send_mbox_cmd);
int processor_thermal_send_mbox_read_cmd(struct pci_dev *pdev, u16 id, u64 *resp)
{
return send_mbox_read_cmd(pdev, id, resp);
}
EXPORT_SYMBOL_NS_GPL(processor_thermal_send_mbox_read_cmd, INT340X_THERMAL);
int processor_thermal_send_mbox_write_cmd(struct pci_dev *pdev, u16 id, u32 data)
{
return send_mbox_write_cmd(pdev, id, data);
}
EXPORT_SYMBOL_NS_GPL(processor_thermal_send_mbox_write_cmd, INT340X_THERMAL);
/* List of workload types */
static const char * const workload_types[] = {
@@ -104,7 +125,6 @@ static const char * const workload_types[] = {
NULL
};
static ssize_t workload_available_types_show(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -146,7 +166,7 @@ static ssize_t workload_type_store(struct device *dev,
data |= ret;
ret = send_mbox_cmd(pdev, MBOX_CMD_WORKLOAD_TYPE_WRITE, data, NULL);
ret = send_mbox_write_cmd(pdev, MBOX_CMD_WORKLOAD_TYPE_WRITE, data);
if (ret)
return false;
@@ -161,7 +181,7 @@ static ssize_t workload_type_show(struct device *dev,
u64 cmd_resp;
int ret;
ret = send_mbox_cmd(pdev, MBOX_CMD_WORKLOAD_TYPE_READ, 0, &cmd_resp);
ret = send_mbox_read_cmd(pdev, MBOX_CMD_WORKLOAD_TYPE_READ, &cmd_resp);
if (ret)
return false;
@@ -186,8 +206,6 @@ static const struct attribute_group workload_req_attribute_group = {
.name = "workload_request"
};
static bool workload_req_created;
int proc_thermal_mbox_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv)
@@ -196,7 +214,7 @@ int proc_thermal_mbox_add(struct pci_dev *pdev, struct proc_thermal_device *proc
int ret;
/* Check if there is a mailbox support, if fails return success */
ret = send_mbox_cmd(pdev, MBOX_CMD_WORKLOAD_TYPE_READ, 0, &cmd_resp);
ret = send_mbox_read_cmd(pdev, MBOX_CMD_WORKLOAD_TYPE_READ, &cmd_resp);
if (ret)
return 0;

View File

@@ -9,6 +9,8 @@
#include <linux/pci.h>
#include "processor_thermal_device.h"
MODULE_IMPORT_NS(INT340X_THERMAL);
struct mmio_reg {
int read_only;
u32 offset;
@@ -194,8 +196,7 @@ static ssize_t rfi_restriction_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
u16 cmd_id = 0x0008;
u64 cmd_resp;
u16 id = 0x0008;
u32 input;
int ret;
@@ -203,7 +204,7 @@ static ssize_t rfi_restriction_store(struct device *dev,
if (ret)
return ret;
ret = processor_thermal_send_mbox_cmd(to_pci_dev(dev), cmd_id, input, &cmd_resp);
ret = processor_thermal_send_mbox_write_cmd(to_pci_dev(dev), id, input);
if (ret)
return ret;
@@ -214,30 +215,30 @@ static ssize_t rfi_restriction_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
u16 cmd_id = 0x0007;
u64 cmd_resp;
u16 id = 0x0007;
u64 resp;
int ret;
ret = processor_thermal_send_mbox_cmd(to_pci_dev(dev), cmd_id, 0, &cmd_resp);
ret = processor_thermal_send_mbox_read_cmd(to_pci_dev(dev), id, &resp);
if (ret)
return ret;
return sprintf(buf, "%llu\n", cmd_resp);
return sprintf(buf, "%llu\n", resp);
}
static ssize_t ddr_data_rate_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
u16 cmd_id = 0x0107;
u64 cmd_resp;
u16 id = 0x0107;
u64 resp;
int ret;
ret = processor_thermal_send_mbox_cmd(to_pci_dev(dev), cmd_id, 0, &cmd_resp);
ret = processor_thermal_send_mbox_read_cmd(to_pci_dev(dev), id, &resp);
if (ret)
return ret;
return sprintf(buf, "%llu\n", cmd_resp);
return sprintf(buf, "%llu\n", resp);
}
static DEVICE_ATTR_RW(rfi_restriction);

View File

@@ -641,7 +641,7 @@ exit_set:
}
/* bind to generic thermal layer as cooling device*/
static struct thermal_cooling_device_ops powerclamp_cooling_ops = {
static const struct thermal_cooling_device_ops powerclamp_cooling_ops = {
.get_max_state = powerclamp_get_max_state,
.get_cur_state = powerclamp_get_cur_state,
.set_cur_state = powerclamp_set_cur_state,

View File

@@ -0,0 +1,242 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Renesas RZ/G2L TSU Thermal Sensor Driver
*
* Copyright (C) 2021 Renesas Electronics Corporation
*/
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/math.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
#include <linux/thermal.h>
#include <linux/units.h>
#include "thermal_hwmon.h"
#define CTEMP_MASK 0xFFF
/* default calibration values, if FUSE values are missing */
#define SW_CALIB0_VAL 3148
#define SW_CALIB1_VAL 503
/* Register offsets */
#define TSU_SM 0x00
#define TSU_ST 0x04
#define TSU_SAD 0x0C
#define TSU_SS 0x10
#define OTPTSUTRIM_REG(n) (0x18 + ((n) * 0x4))
/* Sensor Mode Register(TSU_SM) */
#define TSU_SM_EN_TS BIT(0)
#define TSU_SM_ADC_EN_TS BIT(1)
#define TSU_SM_NORMAL_MODE (TSU_SM_EN_TS | TSU_SM_ADC_EN_TS)
/* TSU_ST bits */
#define TSU_ST_START BIT(0)
#define TSU_SS_CONV_RUNNING BIT(0)
#define TS_CODE_AVE_SCALE(x) ((x) * 1000000)
#define MCELSIUS(temp) ((temp) * MILLIDEGREE_PER_DEGREE)
#define TS_CODE_CAP_TIMES 8 /* Capture times */
#define RZG2L_THERMAL_GRAN 500 /* milli Celsius */
#define RZG2L_TSU_SS_TIMEOUT_US 1000
#define CURVATURE_CORRECTION_CONST 13
struct rzg2l_thermal_priv {
struct device *dev;
void __iomem *base;
struct thermal_zone_device *zone;
struct reset_control *rstc;
u32 calib0, calib1;
};
static inline u32 rzg2l_thermal_read(struct rzg2l_thermal_priv *priv, u32 reg)
{
return ioread32(priv->base + reg);
}
static inline void rzg2l_thermal_write(struct rzg2l_thermal_priv *priv, u32 reg,
u32 data)
{
iowrite32(data, priv->base + reg);
}
static int rzg2l_thermal_get_temp(void *devdata, int *temp)
{
struct rzg2l_thermal_priv *priv = devdata;
u32 result = 0, dsensor, ts_code_ave;
int val, i;
for (i = 0; i < TS_CODE_CAP_TIMES ; i++) {
/* TSU repeats measurement at 20 microseconds intervals and
* automatically updates the results of measurement. As per
* the HW manual for measuring temperature we need to read 8
* values consecutively and then take the average.
* ts_code_ave = (ts_code[0] + + ts_code[7]) / 8
*/
result += rzg2l_thermal_read(priv, TSU_SAD) & CTEMP_MASK;
usleep_range(20, 30);
}
ts_code_ave = result / TS_CODE_CAP_TIMES;
/* Calculate actual sensor value by applying curvature correction formula
* dsensor = ts_code_ave / (1 + ts_code_ave * 0.000013). Here we are doing
* integer calculation by scaling all the values by 1000000.
*/
dsensor = TS_CODE_AVE_SCALE(ts_code_ave) /
(TS_CODE_AVE_SCALE(1) + (ts_code_ave * CURVATURE_CORRECTION_CONST));
/* The temperature Tj is calculated by the formula
* Tj = (dsensor calib1) * 165/ (calib0 calib1) 40
* where calib0 and calib1 are the caliberation values.
*/
val = ((dsensor - priv->calib1) * (MCELSIUS(165) /
(priv->calib0 - priv->calib1))) - MCELSIUS(40);
*temp = roundup(val, RZG2L_THERMAL_GRAN);
return 0;
}
static const struct thermal_zone_of_device_ops rzg2l_tz_of_ops = {
.get_temp = rzg2l_thermal_get_temp,
};
static int rzg2l_thermal_init(struct rzg2l_thermal_priv *priv)
{
u32 reg_val;
rzg2l_thermal_write(priv, TSU_SM, TSU_SM_NORMAL_MODE);
rzg2l_thermal_write(priv, TSU_ST, 0);
/* Before setting the START bit, TSU should be in normal operating
* mode. As per the HW manual, it will take 60 µs to place the TSU
* into normal operating mode.
*/
usleep_range(60, 80);
reg_val = rzg2l_thermal_read(priv, TSU_ST);
reg_val |= TSU_ST_START;
rzg2l_thermal_write(priv, TSU_ST, reg_val);
return readl_poll_timeout(priv->base + TSU_SS, reg_val,
reg_val == TSU_SS_CONV_RUNNING, 50,
RZG2L_TSU_SS_TIMEOUT_US);
}
static void rzg2l_thermal_reset_assert_pm_disable_put(struct platform_device *pdev)
{
struct rzg2l_thermal_priv *priv = dev_get_drvdata(&pdev->dev);
pm_runtime_put(&pdev->dev);
pm_runtime_disable(&pdev->dev);
reset_control_assert(priv->rstc);
}
static int rzg2l_thermal_remove(struct platform_device *pdev)
{
struct rzg2l_thermal_priv *priv = dev_get_drvdata(&pdev->dev);
thermal_remove_hwmon_sysfs(priv->zone);
rzg2l_thermal_reset_assert_pm_disable_put(pdev);
return 0;
}
static int rzg2l_thermal_probe(struct platform_device *pdev)
{
struct thermal_zone_device *zone;
struct rzg2l_thermal_priv *priv;
struct device *dev = &pdev->dev;
int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(priv->base))
return PTR_ERR(priv->base);
priv->dev = dev;
priv->rstc = devm_reset_control_get_exclusive(dev, NULL);
if (IS_ERR(priv->rstc))
return dev_err_probe(dev, PTR_ERR(priv->rstc),
"failed to get cpg reset");
ret = reset_control_deassert(priv->rstc);
if (ret)
return dev_err_probe(dev, ret, "failed to deassert");
pm_runtime_enable(dev);
pm_runtime_get_sync(dev);
priv->calib0 = rzg2l_thermal_read(priv, OTPTSUTRIM_REG(0));
if (!priv->calib0)
priv->calib0 = SW_CALIB0_VAL;
priv->calib1 = rzg2l_thermal_read(priv, OTPTSUTRIM_REG(1));
if (!priv->calib1)
priv->calib1 = SW_CALIB1_VAL;
platform_set_drvdata(pdev, priv);
ret = rzg2l_thermal_init(priv);
if (ret) {
dev_err(dev, "Failed to start TSU");
goto err;
}
zone = devm_thermal_zone_of_sensor_register(dev, 0, priv,
&rzg2l_tz_of_ops);
if (IS_ERR(zone)) {
dev_err(dev, "Can't register thermal zone");
ret = PTR_ERR(zone);
goto err;
}
priv->zone = zone;
priv->zone->tzp->no_hwmon = false;
ret = thermal_add_hwmon_sysfs(priv->zone);
if (ret)
goto err;
dev_dbg(dev, "TSU probed with %s caliberation values",
rzg2l_thermal_read(priv, OTPTSUTRIM_REG(0)) ? "hw" : "sw");
return 0;
err:
rzg2l_thermal_reset_assert_pm_disable_put(pdev);
return ret;
}
static const struct of_device_id rzg2l_thermal_dt_ids[] = {
{ .compatible = "renesas,rzg2l-tsu", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, rzg2l_thermal_dt_ids);
static struct platform_driver rzg2l_thermal_driver = {
.driver = {
.name = "rzg2l_thermal",
.of_match_table = rzg2l_thermal_dt_ids,
},
.probe = rzg2l_thermal_probe,
.remove = rzg2l_thermal_remove,
};
module_platform_driver(rzg2l_thermal_driver);
MODULE_DESCRIPTION("Renesas RZ/G2L TSU Thermal Sensor Driver");
MODULE_AUTHOR("Biju Das <biju.das.jz@bp.renesas.com>");
MODULE_LICENSE("GPL v2");

View File

@@ -459,9 +459,11 @@ get_max:
return max;
}
#define POLLIN_SET (EPOLLRDNORM | EPOLLRDBAND | EPOLLIN | EPOLLHUP | EPOLLERR)
#define POLLOUT_SET (EPOLLWRBAND | EPOLLWRNORM | EPOLLOUT | EPOLLERR)
#define POLLEX_SET (EPOLLPRI)
#define POLLIN_SET (EPOLLRDNORM | EPOLLRDBAND | EPOLLIN | EPOLLHUP | EPOLLERR |\
EPOLLNVAL)
#define POLLOUT_SET (EPOLLWRBAND | EPOLLWRNORM | EPOLLOUT | EPOLLERR |\
EPOLLNVAL)
#define POLLEX_SET (EPOLLPRI | EPOLLNVAL)
static inline void wait_key_set(poll_table *wait, unsigned long in,
unsigned long out, unsigned long bit,
@@ -528,6 +530,7 @@ static int do_select(int n, fd_set_bits *fds, struct timespec64 *end_time)
break;
if (!(bit & all_bits))
continue;
mask = EPOLLNVAL;
f = fdget(i);
if (f.file) {
wait_key_set(wait, in, out, bit,
@@ -535,34 +538,34 @@ static int do_select(int n, fd_set_bits *fds, struct timespec64 *end_time)
mask = vfs_poll(f.file, wait);
fdput(f);
if ((mask & POLLIN_SET) && (in & bit)) {
res_in |= bit;
retval++;
wait->_qproc = NULL;
}
if ((mask & POLLOUT_SET) && (out & bit)) {
res_out |= bit;
retval++;
wait->_qproc = NULL;
}
if ((mask & POLLEX_SET) && (ex & bit)) {
res_ex |= bit;
retval++;
wait->_qproc = NULL;
}
/* got something, stop busy polling */
if (retval) {
can_busy_loop = false;
busy_flag = 0;
/*
* only remember a returned
* POLL_BUSY_LOOP if we asked for it
*/
} else if (busy_flag & mask)
can_busy_loop = true;
}
if ((mask & POLLIN_SET) && (in & bit)) {
res_in |= bit;
retval++;
wait->_qproc = NULL;
}
if ((mask & POLLOUT_SET) && (out & bit)) {
res_out |= bit;
retval++;
wait->_qproc = NULL;
}
if ((mask & POLLEX_SET) && (ex & bit)) {
res_ex |= bit;
retval++;
wait->_qproc = NULL;
}
/* got something, stop busy polling */
if (retval) {
can_busy_loop = false;
busy_flag = 0;
/*
* only remember a returned
* POLL_BUSY_LOOP if we asked for it
*/
} else if (busy_flag & mask)
can_busy_loop = true;
}
if (res_in)
*rinp = res_in;

View File

@@ -413,7 +413,7 @@ struct cgroup {
/*
* The bitmask of subsystems enabled on the child cgroups.
* ->subtree_control is the one configured through
* "cgroup.subtree_control" while ->child_ss_mask is the effective
* "cgroup.subtree_control" while ->subtree_ss_mask is the effective
* one which may have more subsystems enabled. Controller knobs
* are made available iff it's enabled in ->subtree_control.
*/

View File

@@ -378,10 +378,6 @@ property_entries_dup(const struct property_entry *properties);
void property_entries_free(const struct property_entry *properties);
int device_add_properties(struct device *dev,
const struct property_entry *properties);
void device_remove_properties(struct device *dev);
bool device_dma_supported(struct device *dev);
enum dev_dma_attr device_get_dma_attr(struct device *dev);
@@ -401,9 +397,6 @@ struct fwnode_handle *fwnode_graph_get_remote_port(
const struct fwnode_handle *fwnode);
struct fwnode_handle *fwnode_graph_get_remote_endpoint(
const struct fwnode_handle *fwnode);
struct fwnode_handle *
fwnode_graph_get_remote_node(const struct fwnode_handle *fwnode, u32 port,
u32 endpoint);
static inline bool fwnode_graph_is_endpoint(struct fwnode_handle *fwnode)
{
@@ -418,7 +411,8 @@ static inline bool fwnode_graph_is_endpoint(struct fwnode_handle *fwnode)
* one.
* @FWNODE_GRAPH_DEVICE_DISABLED: That the device to which the remote
* endpoint of the given endpoint belongs to,
* may be disabled.
* may be disabled, or that the endpoint is not
* connected.
*/
#define FWNODE_GRAPH_ENDPOINT_NEXT BIT(0)
#define FWNODE_GRAPH_DEVICE_DISABLED BIT(1)
@@ -426,6 +420,8 @@ static inline bool fwnode_graph_is_endpoint(struct fwnode_handle *fwnode)
struct fwnode_handle *
fwnode_graph_get_endpoint_by_id(const struct fwnode_handle *fwnode,
u32 port, u32 endpoint, unsigned long flags);
unsigned int fwnode_graph_get_endpoint_count(struct fwnode_handle *fwnode,
unsigned long flags);
#define fwnode_graph_for_each_endpoint(fwnode, child) \
for (child = NULL; \

View File

@@ -59,8 +59,8 @@ DECLARE_EVENT_CLASS(cgroup,
TP_STRUCT__entry(
__field( int, root )
__field( int, id )
__field( int, level )
__field( u64, id )
__string( path, path )
),
@@ -71,7 +71,7 @@ DECLARE_EVENT_CLASS(cgroup,
__assign_str(path, path);
),
TP_printk("root=%d id=%d level=%d path=%s",
TP_printk("root=%d id=%llu level=%d path=%s",
__entry->root, __entry->id, __entry->level, __get_str(path))
);
@@ -126,8 +126,8 @@ DECLARE_EVENT_CLASS(cgroup_migrate,
TP_STRUCT__entry(
__field( int, dst_root )
__field( int, dst_id )
__field( int, dst_level )
__field( u64, dst_id )
__field( int, pid )
__string( dst_path, path )
__string( comm, task->comm )
@@ -142,7 +142,7 @@ DECLARE_EVENT_CLASS(cgroup_migrate,
__assign_str(comm, task->comm);
),
TP_printk("dst_root=%d dst_id=%d dst_level=%d dst_path=%s pid=%d comm=%s",
TP_printk("dst_root=%d dst_id=%llu dst_level=%d dst_path=%s pid=%d comm=%s",
__entry->dst_root, __entry->dst_id, __entry->dst_level,
__get_str(dst_path), __entry->pid, __get_str(comm))
);
@@ -171,8 +171,8 @@ DECLARE_EVENT_CLASS(cgroup_event,
TP_STRUCT__entry(
__field( int, root )
__field( int, id )
__field( int, level )
__field( u64, id )
__string( path, path )
__field( int, val )
),
@@ -185,7 +185,7 @@ DECLARE_EVENT_CLASS(cgroup_event,
__entry->val = val;
),
TP_printk("root=%d id=%d level=%d path=%s val=%d",
TP_printk("root=%d id=%llu level=%d path=%s val=%d",
__entry->root, __entry->id, __entry->level, __get_str(path),
__entry->val)
);

View File

@@ -2657,11 +2657,11 @@ void cgroup_migrate_add_src(struct css_set *src_cset,
if (src_cset->dead)
return;
src_cgrp = cset_cgroup_from_root(src_cset, dst_cgrp->root);
if (!list_empty(&src_cset->mg_preload_node))
return;
src_cgrp = cset_cgroup_from_root(src_cset, dst_cgrp->root);
WARN_ON(src_cset->mg_src_cgrp);
WARN_ON(src_cset->mg_dst_cgrp);
WARN_ON(!list_empty(&src_cset->mg_tasks));
@@ -5755,7 +5755,7 @@ static void __init cgroup_init_subsys(struct cgroup_subsys *ss, bool early)
/* Create the root cgroup state for this subsystem */
ss->root = &cgrp_dfl_root;
css = ss->css_alloc(cgroup_css(&cgrp_dfl_root.cgrp, ss));
css = ss->css_alloc(NULL);
/* We don't handle early failures gracefully */
BUG_ON(IS_ERR(css));
init_and_link_css(css, ss, &cgrp_dfl_root.cgrp);

View File

@@ -615,19 +615,11 @@ static int validate_change(struct cpuset *cur, struct cpuset *trial)
struct cpuset *c, *par;
int ret;
rcu_read_lock();
/* Each of our child cpusets must be a subset of us */
ret = -EBUSY;
cpuset_for_each_child(c, css, cur)
if (!is_cpuset_subset(c, trial))
goto out;
/* Remaining checks don't apply to root cpuset */
ret = 0;
/* The checks don't apply to root cpuset */
if (cur == &top_cpuset)
goto out;
return 0;
rcu_read_lock();
par = parent_cs(cur);
/* On legacy hierarchy, we must be a subset of our parent cpuset. */
@@ -3552,7 +3544,7 @@ static struct cpuset *nearest_hardwall_ancestor(struct cpuset *cs)
bool __cpuset_node_allowed(int node, gfp_t gfp_mask)
{
struct cpuset *cs; /* current cpuset ancestors */
int allowed; /* is allocation in zone z allowed? */
bool allowed; /* is allocation in zone z allowed? */
unsigned long flags;
if (in_interrupt())

View File

@@ -35,7 +35,7 @@ void cgroup_rstat_updated(struct cgroup *cgrp, int cpu)
* instead of NULL, we can tell whether @cgrp is on the list by
* testing the next pointer for NULL.
*/
if (cgroup_rstat_cpu(cgrp, cpu)->updated_next)
if (data_race(cgroup_rstat_cpu(cgrp, cpu)->updated_next))
return;
raw_spin_lock_irqsave(cpu_lock, flags);
@@ -88,6 +88,7 @@ static struct cgroup *cgroup_rstat_cpu_pop_updated(struct cgroup *pos,
struct cgroup *root, int cpu)
{
struct cgroup_rstat_cpu *rstatc;
struct cgroup *parent;
if (pos == root)
return NULL;
@@ -96,10 +97,14 @@ static struct cgroup *cgroup_rstat_cpu_pop_updated(struct cgroup *pos,
* We're gonna walk down to the first leaf and visit/remove it. We
* can pick whatever unvisited node as the starting point.
*/
if (!pos)
if (!pos) {
pos = root;
else
/* return NULL if this subtree is not on-list */
if (!cgroup_rstat_cpu(pos, cpu)->updated_next)
return NULL;
} else {
pos = cgroup_parent(pos);
}
/* walk down to the first leaf */
while (true) {
@@ -115,33 +120,25 @@ static struct cgroup *cgroup_rstat_cpu_pop_updated(struct cgroup *pos,
* However, due to the way we traverse, @pos will be the first
* child in most cases. The only exception is @root.
*/
if (rstatc->updated_next) {
struct cgroup *parent = cgroup_parent(pos);
parent = cgroup_parent(pos);
if (parent) {
struct cgroup_rstat_cpu *prstatc;
struct cgroup **nextp;
if (parent) {
struct cgroup_rstat_cpu *prstatc;
struct cgroup **nextp;
prstatc = cgroup_rstat_cpu(parent, cpu);
nextp = &prstatc->updated_children;
while (*nextp != pos) {
struct cgroup_rstat_cpu *nrstatc;
prstatc = cgroup_rstat_cpu(parent, cpu);
nextp = &prstatc->updated_children;
while (true) {
struct cgroup_rstat_cpu *nrstatc;
nrstatc = cgroup_rstat_cpu(*nextp, cpu);
if (*nextp == pos)
break;
WARN_ON_ONCE(*nextp == parent);
nextp = &nrstatc->updated_next;
}
*nextp = rstatc->updated_next;
nrstatc = cgroup_rstat_cpu(*nextp, cpu);
WARN_ON_ONCE(*nextp == parent);
nextp = &nrstatc->updated_next;
}
rstatc->updated_next = NULL;
return pos;
*nextp = rstatc->updated_next;
}
/* only happens for @root */
return NULL;
rstatc->updated_next = NULL;
return pos;
}
/* see cgroup_rstat_flush() */

View File

@@ -282,7 +282,6 @@ static struct console *exclusive_console;
static struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES];
static int preferred_console = -1;
static bool has_preferred_console;
int console_set_on_cmdline;
EXPORT_SYMBOL(console_set_on_cmdline);
@@ -2869,7 +2868,8 @@ early_param("keep_bootcon", keep_bootcon_setup);
* Care need to be taken with consoles that are statically
* enabled such as netconsole
*/
static int try_enable_new_console(struct console *newcon, bool user_specified)
static int try_enable_preferred_console(struct console *newcon,
bool user_specified)
{
struct console_cmdline *c;
int i, err;
@@ -2899,10 +2899,8 @@ static int try_enable_new_console(struct console *newcon, bool user_specified)
return err;
}
newcon->flags |= CON_ENABLED;
if (i == preferred_console) {
if (i == preferred_console)
newcon->flags |= CON_CONSDEV;
has_preferred_console = true;
}
return 0;
}
@@ -2917,6 +2915,21 @@ static int try_enable_new_console(struct console *newcon, bool user_specified)
return -ENOENT;
}
/* Try to enable the console unconditionally */
static void try_enable_default_console(struct console *newcon)
{
if (newcon->index < 0)
newcon->index = 0;
if (newcon->setup && newcon->setup(newcon, NULL) != 0)
return;
newcon->flags |= CON_ENABLED;
if (newcon->device)
newcon->flags |= CON_CONSDEV;
}
/*
* The console driver calls this routine during kernel initialization
* to register the console printing procedure with printk() and to
@@ -2938,59 +2951,56 @@ static int try_enable_new_console(struct console *newcon, bool user_specified)
*/
void register_console(struct console *newcon)
{
struct console *bcon = NULL;
struct console *con;
bool bootcon_enabled = false;
bool realcon_enabled = false;
int err;
for_each_console(bcon) {
if (WARN(bcon == newcon, "console '%s%d' already registered\n",
bcon->name, bcon->index))
for_each_console(con) {
if (WARN(con == newcon, "console '%s%d' already registered\n",
con->name, con->index))
return;
}
/*
* before we register a new CON_BOOT console, make sure we don't
* already have a valid console
*/
if (newcon->flags & CON_BOOT) {
for_each_console(bcon) {
if (!(bcon->flags & CON_BOOT)) {
pr_info("Too late to register bootconsole %s%d\n",
newcon->name, newcon->index);
return;
}
}
for_each_console(con) {
if (con->flags & CON_BOOT)
bootcon_enabled = true;
else
realcon_enabled = true;
}
if (console_drivers && console_drivers->flags & CON_BOOT)
bcon = console_drivers;
if (!has_preferred_console || bcon || !console_drivers)
has_preferred_console = preferred_console >= 0;
/* Do not register boot consoles when there already is a real one. */
if (newcon->flags & CON_BOOT && realcon_enabled) {
pr_info("Too late to register bootconsole %s%d\n",
newcon->name, newcon->index);
return;
}
/*
* See if we want to use this console driver. If we
* didn't select a console we take the first one
* that registers here.
* See if we want to enable this console driver by default.
*
* Nope when a console is preferred by the command line, device
* tree, or SPCR.
*
* The first real console with tty binding (driver) wins. More
* consoles might get enabled before the right one is found.
*
* Note that a console with tty binding will have CON_CONSDEV
* flag set and will be first in the list.
*/
if (!has_preferred_console) {
if (newcon->index < 0)
newcon->index = 0;
if (newcon->setup == NULL ||
newcon->setup(newcon, NULL) == 0) {
newcon->flags |= CON_ENABLED;
if (newcon->device) {
newcon->flags |= CON_CONSDEV;
has_preferred_console = true;
}
if (preferred_console < 0) {
if (!console_drivers || !console_drivers->device ||
console_drivers->flags & CON_BOOT) {
try_enable_default_console(newcon);
}
}
/* See if this console matches one we selected on the command line */
err = try_enable_new_console(newcon, true);
err = try_enable_preferred_console(newcon, true);
/* If not, try to match against the platform default(s) */
if (err == -ENOENT)
err = try_enable_new_console(newcon, false);
err = try_enable_preferred_console(newcon, false);
/* printk() messages are not printed to the Braille console. */
if (err || newcon->flags & CON_BRL)
@@ -3002,8 +3012,10 @@ void register_console(struct console *newcon)
* the real console are the same physical device, it's annoying to
* see the beginning boot messages twice
*/
if (bcon && ((newcon->flags & (CON_CONSDEV | CON_BOOT)) == CON_CONSDEV))
if (bootcon_enabled &&
((newcon->flags & (CON_CONSDEV | CON_BOOT)) == CON_CONSDEV)) {
newcon->flags &= ~CON_PRINTBUFFER;
}
/*
* Put this console in the list - keep the
@@ -3059,15 +3071,15 @@ void register_console(struct console *newcon)
pr_info("%sconsole [%s%d] enabled\n",
(newcon->flags & CON_BOOT) ? "boot" : "" ,
newcon->name, newcon->index);
if (bcon &&
if (bootcon_enabled &&
((newcon->flags & (CON_CONSDEV | CON_BOOT)) == CON_CONSDEV) &&
!keep_bootcon) {
/* We need to iterate through all boot consoles, to make
* sure we print everything out, before we unregister them.
*/
for_each_console(bcon)
if (bcon->flags & CON_BOOT)
unregister_console(bcon);
for_each_console(con)
if (con->flags & CON_BOOT)
unregister_console(con);
}
}
EXPORT_SYMBOL(register_console);

View File

@@ -158,6 +158,9 @@ struct worker_pool {
unsigned long watchdog_ts; /* L: watchdog timestamp */
/* The current concurrency level. */
atomic_t nr_running;
struct list_head worklist; /* L: list of pending works */
int nr_workers; /* L: total number of workers */
@@ -181,19 +184,12 @@ struct worker_pool {
struct hlist_node hash_node; /* PL: unbound_pool_hash node */
int refcnt; /* PL: refcnt for unbound pools */
/*
* The current concurrency level. As it's likely to be accessed
* from other CPUs during try_to_wake_up(), put it in a separate
* cacheline.
*/
atomic_t nr_running ____cacheline_aligned_in_smp;
/*
* Destruction of pool is RCU protected to allow dereferences
* from get_work_pool().
*/
struct rcu_head rcu;
} ____cacheline_aligned_in_smp;
};
/*
* The per-pool workqueue. While queued, the lower WORK_STRUCT_FLAG_BITS
@@ -872,8 +868,17 @@ void wq_worker_running(struct task_struct *task)
if (!worker->sleeping)
return;
/*
* If preempted by unbind_workers() between the WORKER_NOT_RUNNING check
* and the nr_running increment below, we may ruin the nr_running reset
* and leave with an unexpected pool->nr_running == 1 on the newly unbound
* pool. Protect against such race.
*/
preempt_disable();
if (!(worker->flags & WORKER_NOT_RUNNING))
atomic_inc(&worker->pool->nr_running);
preempt_enable();
worker->sleeping = 0;
}
@@ -882,8 +887,7 @@ void wq_worker_running(struct task_struct *task)
* @task: task going to sleep
*
* This function is called from schedule() when a busy worker is
* going to sleep. Preemption needs to be disabled to protect ->sleeping
* assignment.
* going to sleep.
*/
void wq_worker_sleeping(struct task_struct *task)
{
@@ -907,6 +911,16 @@ void wq_worker_sleeping(struct task_struct *task)
worker->sleeping = 1;
raw_spin_lock_irq(&pool->lock);
/*
* Recheck in case unbind_workers() preempted us. We don't
* want to decrement nr_running after the worker is unbound
* and nr_running has been reset.
*/
if (worker->flags & WORKER_NOT_RUNNING) {
raw_spin_unlock_irq(&pool->lock);
return;
}
/*
* The counterpart of the following dec_and_test, implied mb,
* worklist not empty test sequence is in insert_work().
@@ -1535,7 +1549,8 @@ out:
* @work: work to queue
*
* We queue the work to a specific CPU, the caller must ensure it
* can't go away.
* can't go away. Callers that fail to ensure that the specified
* CPU cannot go away will execute on a randomly chosen CPU.
*
* Return: %false if @work was already on a queue, %true otherwise.
*/
@@ -1815,14 +1830,8 @@ static void worker_enter_idle(struct worker *worker)
if (too_many_workers(pool) && !timer_pending(&pool->idle_timer))
mod_timer(&pool->idle_timer, jiffies + IDLE_WORKER_TIMEOUT);
/*
* Sanity check nr_running. Because unbind_workers() releases
* pool->lock between setting %WORKER_UNBOUND and zapping
* nr_running, the warning may trigger spuriously. Check iff
* unbind is not in progress.
*/
WARN_ON_ONCE(!(pool->flags & POOL_DISASSOCIATED) &&
pool->nr_workers == pool->nr_idle &&
/* Sanity check nr_running. */
WARN_ON_ONCE(pool->nr_workers == pool->nr_idle &&
atomic_read(&pool->nr_running));
}
@@ -4983,38 +4992,22 @@ static void unbind_workers(int cpu)
/*
* We've blocked all attach/detach operations. Make all workers
* unbound and set DISASSOCIATED. Before this, all workers
* except for the ones which are still executing works from
* before the last CPU down must be on the cpu. After
* this, they may become diasporas.
* must be on the cpu. After this, they may become diasporas.
* And the preemption disabled section in their sched callbacks
* are guaranteed to see WORKER_UNBOUND since the code here
* is on the same cpu.
*/
for_each_pool_worker(worker, pool)
worker->flags |= WORKER_UNBOUND;
pool->flags |= POOL_DISASSOCIATED;
raw_spin_unlock_irq(&pool->lock);
for_each_pool_worker(worker, pool) {
kthread_set_per_cpu(worker->task, -1);
WARN_ON_ONCE(set_cpus_allowed_ptr(worker->task, cpu_possible_mask) < 0);
}
mutex_unlock(&wq_pool_attach_mutex);
/*
* Call schedule() so that we cross rq->lock and thus can
* guarantee sched callbacks see the %WORKER_UNBOUND flag.
* This is necessary as scheduler callbacks may be invoked
* from other cpus.
*/
schedule();
/*
* Sched callbacks are disabled now. Zap nr_running.
* After this, nr_running stays zero and need_more_worker()
* and keep_working() are always true as long as the
* worklist is not empty. This pool now behaves as an
* unbound (in terms of concurrency management) pool which
* The handling of nr_running in sched callbacks are disabled
* now. Zap nr_running. After this, nr_running stays zero and
* need_more_worker() and keep_working() are always true as
* long as the worklist is not empty. This pool now behaves as
* an unbound (in terms of concurrency management) pool which
* are served by workers tied to the pool.
*/
atomic_set(&pool->nr_running, 0);
@@ -5024,9 +5017,16 @@ static void unbind_workers(int cpu)
* worker blocking could lead to lengthy stalls. Kick off
* unbound chain execution of currently pending work items.
*/
raw_spin_lock_irq(&pool->lock);
wake_up_worker(pool);
raw_spin_unlock_irq(&pool->lock);
for_each_pool_worker(worker, pool) {
kthread_set_per_cpu(worker->task, -1);
WARN_ON_ONCE(set_cpus_allowed_ptr(worker->task, cpu_possible_mask) < 0);
}
mutex_unlock(&wq_pool_attach_mutex);
}
}
@@ -5062,17 +5062,6 @@ static void rebind_workers(struct worker_pool *pool)
for_each_pool_worker(worker, pool) {
unsigned int worker_flags = worker->flags;
/*
* A bound idle worker should actually be on the runqueue
* of the associated CPU for local wake-ups targeting it to
* work. Kick all idle workers so that they migrate to the
* associated CPU. Doing this in the same loop as
* replacing UNBOUND with REBOUND is safe as no worker will
* be bound before @pool->lock is released.
*/
if (worker_flags & WORKER_IDLE)
wake_up_process(worker->task);
/*
* We want to clear UNBOUND but can't directly call
* worker_clr_flags() or adjust nr_running. Atomically

View File

@@ -3564,7 +3564,7 @@ int vsscanf(const char *buf, const char *fmt, va_list args)
++fmt;
for ( ; *fmt && *fmt != ']'; ++fmt, ++len)
set_bit((u8)*fmt, set);
__set_bit((u8)*fmt, set);
/* no ']' or no character set found */
if (!*fmt || !len)
@@ -3574,7 +3574,7 @@ int vsscanf(const char *buf, const char *fmt, va_list args)
if (negate) {
bitmap_complement(set, set, 256);
/* exclude null '\0' byte */
clear_bit(0, set);
__clear_bit(0, set);
}
/* match must be non-empty */

View File

@@ -44,19 +44,17 @@ class LxDmesg(gdb.Command):
sz = prb_desc_ring_type.get_type().sizeof
desc_ring = utils.read_memoryview(inf, addr, sz).tobytes()
# read in descriptor array
# read in descriptor count, size, and address
off = prb_desc_ring_type.get_type()['count_bits'].bitpos // 8
desc_ring_count = 1 << utils.read_u32(desc_ring, off)
desc_sz = prb_desc_type.get_type().sizeof
off = prb_desc_ring_type.get_type()['descs'].bitpos // 8
addr = utils.read_ulong(desc_ring, off)
descs = utils.read_memoryview(inf, addr, desc_sz * desc_ring_count).tobytes()
desc_addr = utils.read_ulong(desc_ring, off)
# read in info array
# read in info size and address
info_sz = printk_info_type.get_type().sizeof
off = prb_desc_ring_type.get_type()['infos'].bitpos // 8
addr = utils.read_ulong(desc_ring, off)
infos = utils.read_memoryview(inf, addr, info_sz * desc_ring_count).tobytes()
info_addr = utils.read_ulong(desc_ring, off)
# read in text data ring structure
off = printk_ringbuffer_type.get_type()['text_data_ring'].bitpos // 8
@@ -64,12 +62,11 @@ class LxDmesg(gdb.Command):
sz = prb_data_ring_type.get_type().sizeof
text_data_ring = utils.read_memoryview(inf, addr, sz).tobytes()
# read in text data
# read in text data size and address
off = prb_data_ring_type.get_type()['size_bits'].bitpos // 8
text_data_sz = 1 << utils.read_u32(text_data_ring, off)
off = prb_data_ring_type.get_type()['data'].bitpos // 8
addr = utils.read_ulong(text_data_ring, off)
text_data = utils.read_memoryview(inf, addr, text_data_sz).tobytes()
text_data_addr = utils.read_ulong(text_data_ring, off)
counter_off = atomic_long_type.get_type()['counter'].bitpos // 8
@@ -102,17 +99,20 @@ class LxDmesg(gdb.Command):
desc_off = desc_sz * ind
info_off = info_sz * ind
desc = utils.read_memoryview(inf, desc_addr + desc_off, desc_sz).tobytes()
# skip non-committed record
state = 3 & (utils.read_u64(descs, desc_off + sv_off +
counter_off) >> desc_flags_shift)
state = 3 & (utils.read_u64(desc, sv_off + counter_off) >> desc_flags_shift)
if state != desc_committed and state != desc_finalized:
if did == head_id:
break
did = (did + 1) & desc_id_mask
continue
begin = utils.read_ulong(descs, desc_off + begin_off) % text_data_sz
end = utils.read_ulong(descs, desc_off + next_off) % text_data_sz
begin = utils.read_ulong(desc, begin_off) % text_data_sz
end = utils.read_ulong(desc, next_off) % text_data_sz
info = utils.read_memoryview(inf, info_addr + info_off, info_sz).tobytes()
# handle data-less record
if begin & 1 == 1:
@@ -125,16 +125,17 @@ class LxDmesg(gdb.Command):
# skip over descriptor id
text_start = begin + utils.get_long_type().sizeof
text_len = utils.read_u16(infos, info_off + len_off)
text_len = utils.read_u16(info, len_off)
# handle truncated message
if end - text_start < text_len:
text_len = end - text_start
text = text_data[text_start:text_start + text_len].decode(
encoding='utf8', errors='replace')
text_data = utils.read_memoryview(inf, text_data_addr + text_start,
text_len).tobytes()
text = text_data[0:text_len].decode(encoding='utf8', errors='replace')
time_stamp = utils.read_u64(infos, info_off + ts_off)
time_stamp = utils.read_u64(info, ts_off)
for line in text.splitlines():
msg = u"[{time:12.6f}] {line}\n".format(

View File

@@ -54,7 +54,6 @@ static double xk_1, xk_2; /* input temperature x[k-#] */
*/
int init_thermal_controller(void)
{
int ret = 0;
/* init pid params */
p_param.ts = ticktime;
@@ -65,7 +64,7 @@ int init_thermal_controller(void)
p_param.t_target = target_temp_user;
return ret;
return 0;
}
void controller_reset(void)