* [PATCH v4 09/36] thunderbolt: Move LC specific functionality into a separate file
From: Mika Westerberg @ 2019-04-10 13:36 UTC (permalink / raw)
To: linux-kernel
Cc: Michael Jamet, Yehezkel Bernat, Andreas Noever, Lukas Wunner,
David S . Miller, Andy Shevchenko, Christian Kellner,
Mario.Limonciello, Joe Perches, Mika Westerberg, netdev
In-Reply-To: <20190410133653.88061-1-mika.westerberg@linux.intel.com>
We will be adding more link controller functionality in subsequent
patches and it does not make sense to keep all that in switch.c, so
separate LC functionality into its own file.
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
---
drivers/thunderbolt/Makefile | 2 +-
drivers/thunderbolt/lc.c | 21 +++++++++++++++++++++
drivers/thunderbolt/switch.c | 21 ++++++++++-----------
drivers/thunderbolt/tb.h | 3 +++
drivers/thunderbolt/tb_regs.h | 2 ++
5 files changed, 37 insertions(+), 12 deletions(-)
create mode 100644 drivers/thunderbolt/lc.c
diff --git a/drivers/thunderbolt/Makefile b/drivers/thunderbolt/Makefile
index f2f0de27252b..8531f15d3b3c 100644
--- a/drivers/thunderbolt/Makefile
+++ b/drivers/thunderbolt/Makefile
@@ -1,3 +1,3 @@
obj-${CONFIG_THUNDERBOLT} := thunderbolt.o
thunderbolt-objs := nhi.o ctl.o tb.o switch.o cap.o path.o tunnel_pci.o eeprom.o
-thunderbolt-objs += domain.o dma_port.o icm.o property.o xdomain.o
+thunderbolt-objs += domain.o dma_port.o icm.o property.o xdomain.o lc.o
diff --git a/drivers/thunderbolt/lc.c b/drivers/thunderbolt/lc.c
new file mode 100644
index 000000000000..2134a55ed837
--- /dev/null
+++ b/drivers/thunderbolt/lc.c
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Thunderbolt link controller support
+ *
+ * Copyright (C) 2019, Intel Corporation
+ * Author: Mika Westerberg <mika.westerberg@linux.intel.com>
+ */
+
+#include "tb.h"
+
+/**
+ * tb_lc_read_uuid() - Read switch UUID from link controller common register
+ * @sw: Switch whose UUID is read
+ * @uuid: UUID is placed here
+ */
+int tb_lc_read_uuid(struct tb_switch *sw, u32 *uuid)
+{
+ if (!sw->cap_lc)
+ return -EINVAL;
+ return tb_sw_read(sw, uuid, TB_CFG_SWITCH, sw->cap_lc + TB_LC_FUSE, 4);
+}
diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c
index 1e29c06947af..63ff4c753d89 100644
--- a/drivers/thunderbolt/switch.c
+++ b/drivers/thunderbolt/switch.c
@@ -1182,6 +1182,10 @@ struct tb_switch *tb_switch_alloc(struct tb *tb, struct device *parent,
}
sw->cap_plug_events = cap;
+ cap = tb_switch_find_vse_cap(sw, TB_VSE_CAP_LINK_CONTROLLER);
+ if (cap > 0)
+ sw->cap_lc = cap;
+
/* Root switch is always authorized */
if (!route)
sw->authorized = true;
@@ -1278,22 +1282,17 @@ int tb_switch_configure(struct tb_switch *sw)
static int tb_switch_set_uuid(struct tb_switch *sw)
{
u32 uuid[4];
- int cap, ret;
+ int ret;
- ret = 0;
if (sw->uuid)
- return ret;
+ return 0;
/*
* The newer controllers include fused UUID as part of link
* controller specific registers
*/
- cap = tb_switch_find_vse_cap(sw, TB_VSE_CAP_LINK_CONTROLLER);
- if (cap > 0) {
- ret = tb_sw_read(sw, uuid, TB_CFG_SWITCH, cap + 3, 4);
- if (ret)
- return ret;
- } else {
+ ret = tb_lc_read_uuid(sw, uuid);
+ if (ret) {
/*
* ICM generates UUID based on UID and fills the upper
* two words with ones. This is not strictly following
@@ -1308,8 +1307,8 @@ static int tb_switch_set_uuid(struct tb_switch *sw)
sw->uuid = kmemdup(uuid, sizeof(uuid), GFP_KERNEL);
if (!sw->uuid)
- ret = -ENOMEM;
- return ret;
+ return -ENOMEM;
+ return 0;
}
static int tb_switch_add_dma_port(struct tb_switch *sw)
diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h
index a166265dfcf9..e52d39b25266 100644
--- a/drivers/thunderbolt/tb.h
+++ b/drivers/thunderbolt/tb.h
@@ -63,6 +63,7 @@ struct tb_switch_nvm {
* @device_name: Name of the device (or %NULL if not known)
* @generation: Switch Thunderbolt generation
* @cap_plug_events: Offset to the plug events capability (%0 if not found)
+ * @cap_lc: Offset to the link controller capability (%0 if not found)
* @is_unplugged: The switch is going away
* @drom: DROM of the switch (%NULL if not found)
* @nvm: Pointer to the NVM if the switch has one (%NULL otherwise)
@@ -96,6 +97,7 @@ struct tb_switch {
const char *device_name;
unsigned int generation;
int cap_plug_events;
+ int cap_lc;
bool is_unplugged;
u8 *drom;
struct tb_switch_nvm *nvm;
@@ -462,6 +464,7 @@ bool tb_path_is_invalid(struct tb_path *path);
int tb_drom_read(struct tb_switch *sw);
int tb_drom_read_uid_only(struct tb_switch *sw, u64 *uid);
+int tb_lc_read_uuid(struct tb_switch *sw, u32 *uuid);
static inline int tb_route_length(u64 route)
{
diff --git a/drivers/thunderbolt/tb_regs.h b/drivers/thunderbolt/tb_regs.h
index 6f1ff04ee195..4895ae9f0b40 100644
--- a/drivers/thunderbolt/tb_regs.h
+++ b/drivers/thunderbolt/tb_regs.h
@@ -237,5 +237,7 @@ struct tb_regs_hop {
u32 unknown3:4; /* set to zero */
} __packed;
+/* Common link controller registers */
+#define TB_LC_FUSE 0x03
#endif
--
2.20.1
^ permalink raw reply related
* [PATCH v4 08/36] thunderbolt: Add dummy read after port capability list walk on Light Ridge
From: Mika Westerberg @ 2019-04-10 13:36 UTC (permalink / raw)
To: linux-kernel
Cc: Michael Jamet, Yehezkel Bernat, Andreas Noever, Lukas Wunner,
David S . Miller, Andy Shevchenko, Christian Kellner,
Mario.Limonciello, Joe Perches, Mika Westerberg, netdev
In-Reply-To: <20190410133653.88061-1-mika.westerberg@linux.intel.com>
Light Ridge has an issue where reading the next capability pointer
location in port config space the read data is not cleared. It is fine
to read capabilities each after another so only thing we need to do is
to make sure we issue dummy read after tb_port_find_cap() is finished to
avoid the issue in next read.
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
---
drivers/thunderbolt/cap.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/drivers/thunderbolt/cap.c b/drivers/thunderbolt/cap.c
index a58585b4e6d9..8bf8e031f0bc 100644
--- a/drivers/thunderbolt/cap.c
+++ b/drivers/thunderbolt/cap.c
@@ -52,6 +52,21 @@ static int tb_port_enable_tmu(struct tb_port *port, bool enable)
return tb_sw_write(sw, &value, TB_CFG_SWITCH, offset, 1);
}
+static void tb_port_dummy_read(struct tb_port *port)
+{
+ /*
+ * When reading from next capability pointer location in port
+ * config space the read data is not cleared on LR. To avoid
+ * reading stale data on next read perform one dummy read after
+ * port capabilities are walked.
+ */
+ if (tb_switch_is_lr(port->sw)) {
+ u32 dummy;
+
+ tb_port_read(port, &dummy, TB_CFG_PORT, 0, 1);
+ }
+}
+
static int __tb_port_find_cap(struct tb_port *port, enum tb_port_cap cap)
{
u32 offset = 1;
@@ -92,6 +107,7 @@ int tb_port_find_cap(struct tb_port *port, enum tb_port_cap cap)
ret = __tb_port_find_cap(port, cap);
+ tb_port_dummy_read(port);
tb_port_enable_tmu(port, false);
return ret;
--
2.20.1
^ permalink raw reply related
* [PATCH v4 25/36] thunderbolt: Rework NFC credits handling
From: Mika Westerberg @ 2019-04-10 13:36 UTC (permalink / raw)
To: linux-kernel
Cc: Michael Jamet, Yehezkel Bernat, Andreas Noever, Lukas Wunner,
David S . Miller, Andy Shevchenko, Christian Kellner,
Mario.Limonciello, Joe Perches, Mika Westerberg, netdev
In-Reply-To: <20190410133653.88061-1-mika.westerberg@linux.intel.com>
NFC (non flow control) credits is actually 20-bit field so update
tb_port_add_nfc_credits() to handle this properly. This allows us to set
NFC credits for Display Port path in subsequent patches.
Also make sure the function does not update the hardware if the
underlying switch is already unplugged.
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
---
drivers/thunderbolt/switch.c | 20 +++++++++++++-------
drivers/thunderbolt/tb_regs.h | 3 +++
2 files changed, 16 insertions(+), 7 deletions(-)
diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c
index 028e9a293382..9462e6982061 100644
--- a/drivers/thunderbolt/switch.c
+++ b/drivers/thunderbolt/switch.c
@@ -537,14 +537,20 @@ int tb_wait_for_port(struct tb_port *port, bool wait_if_unplugged)
*/
int tb_port_add_nfc_credits(struct tb_port *port, int credits)
{
- if (credits == 0)
+ u32 nfc_credits;
+
+ if (credits == 0 || port->sw->is_unplugged)
return 0;
- tb_port_info(port,
- "adding %#x NFC credits (%#x -> %#x)",
- credits,
- port->config.nfc_credits,
- port->config.nfc_credits + credits);
- port->config.nfc_credits += credits;
+
+ nfc_credits = port->config.nfc_credits & TB_PORT_NFC_CREDITS_MASK;
+ nfc_credits += credits;
+
+ tb_port_dbg(port, "adding %d NFC credits to %lu",
+ credits, port->config.nfc_credits & TB_PORT_NFC_CREDITS_MASK);
+
+ port->config.nfc_credits &= ~TB_PORT_NFC_CREDITS_MASK;
+ port->config.nfc_credits |= nfc_credits;
+
return tb_port_write(port, &port->config.nfc_credits,
TB_CFG_PORT, 4, 1);
}
diff --git a/drivers/thunderbolt/tb_regs.h b/drivers/thunderbolt/tb_regs.h
index 75e935acade5..74c0f4a5606d 100644
--- a/drivers/thunderbolt/tb_regs.h
+++ b/drivers/thunderbolt/tb_regs.h
@@ -211,6 +211,9 @@ struct tb_regs_port_header {
} __packed;
+/* DWORD 4 */
+#define TB_PORT_NFC_CREDITS_MASK GENMASK(19, 0)
+
/* PCIe adapter registers */
#define TB_PCI_EN BIT(31)
--
2.20.1
^ permalink raw reply related
* [PATCH v4 24/36] thunderbolt: Generalize port finding routines to support all port types
From: Mika Westerberg @ 2019-04-10 13:36 UTC (permalink / raw)
To: linux-kernel
Cc: Michael Jamet, Yehezkel Bernat, Andreas Noever, Lukas Wunner,
David S . Miller, Andy Shevchenko, Christian Kellner,
Mario.Limonciello, Joe Perches, Mika Westerberg, netdev
In-Reply-To: <20190410133653.88061-1-mika.westerberg@linux.intel.com>
We will be needing these routines to find Display Port adapters as well
so modify them to take port type as the second parameter.
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
---
drivers/thunderbolt/switch.c | 16 ++++++++++++++++
drivers/thunderbolt/tb.c | 35 +++++++++++++++++------------------
drivers/thunderbolt/tb.h | 1 +
3 files changed, 34 insertions(+), 18 deletions(-)
diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c
index 00aec2124f79..028e9a293382 100644
--- a/drivers/thunderbolt/switch.c
+++ b/drivers/thunderbolt/switch.c
@@ -730,6 +730,22 @@ struct tb_port *tb_next_port_on_path(struct tb_port *start, struct tb_port *end,
return next;
}
+/**
+ * tb_port_is_enabled() - Is the adapter port enabled
+ * @port: Port to check
+ */
+bool tb_port_is_enabled(struct tb_port *port)
+{
+ switch (port->config.type) {
+ case TB_TYPE_PCIE_UP:
+ case TB_TYPE_PCIE_DOWN:
+ return tb_pci_port_is_enabled(port);
+
+ default:
+ return false;
+ }
+}
+
/**
* tb_pci_port_is_enabled() - Is the PCIe adapter port enabled
* @port: PCIe port to check
diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c
index fb01396a62a9..903922a16d64 100644
--- a/drivers/thunderbolt/tb.c
+++ b/drivers/thunderbolt/tb.c
@@ -180,40 +180,39 @@ static void tb_free_unplugged_children(struct tb_switch *sw)
}
}
-
/**
- * find_pci_up_port() - return the first PCIe up port on @sw or NULL
+ * tb_find_port() - return the first port of @type on @sw or NULL
+ * @sw: Switch to find the port from
+ * @type: Port type to look for
*/
-static struct tb_port *tb_find_pci_up_port(struct tb_switch *sw)
+static struct tb_port *tb_find_port(struct tb_switch *sw,
+ enum tb_port_type type)
{
int i;
for (i = 1; i <= sw->config.max_port_number; i++)
- if (sw->ports[i].config.type == TB_TYPE_PCIE_UP)
+ if (sw->ports[i].config.type == type)
return &sw->ports[i];
return NULL;
}
/**
- * find_unused_down_port() - return the first inactive PCIe down port on @sw
+ * tb_find_unused_port() - return the first inactive port on @sw
+ * @sw: Switch to find the port on
+ * @type: Port type to look for
*/
-static struct tb_port *tb_find_unused_down_port(struct tb_switch *sw)
+static struct tb_port *tb_find_unused_port(struct tb_switch *sw,
+ enum tb_port_type type)
{
int i;
- int cap;
- int res;
- int data;
+
for (i = 1; i <= sw->config.max_port_number; i++) {
if (tb_is_upstream_port(&sw->ports[i]))
continue;
- if (sw->ports[i].config.type != TB_TYPE_PCIE_DOWN)
- continue;
- cap = sw->ports[i].cap_adap;
- if (!cap)
+ if (sw->ports[i].config.type != type)
continue;
- res = tb_port_read(&sw->ports[i], &data, TB_CFG_PORT, cap, 1);
- if (res < 0)
+ if (!sw->ports[i].cap_adap)
continue;
- if (data & 0x80000000)
+ if (tb_port_is_enabled(&sw->ports[i]))
continue;
return &sw->ports[i];
}
@@ -255,7 +254,7 @@ static struct tb_port *tb_find_pcie_down(struct tb_switch *sw,
}
out:
- return tb_find_unused_down_port(sw);
+ return tb_find_unused_port(sw, TB_TYPE_PCIE_DOWN);
}
static int tb_tunnel_pci(struct tb *tb, struct tb_switch *sw)
@@ -265,7 +264,7 @@ static int tb_tunnel_pci(struct tb *tb, struct tb_switch *sw)
struct tb_switch *parent_sw;
struct tb_tunnel *tunnel;
- up = tb_find_pci_up_port(sw);
+ up = tb_find_port(sw, TB_TYPE_PCIE_UP);
if (!up)
return 0;
diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h
index 260360ec59a9..e6040c9f68fa 100644
--- a/drivers/thunderbolt/tb.h
+++ b/drivers/thunderbolt/tb.h
@@ -576,6 +576,7 @@ struct tb_port *tb_next_port_on_path(struct tb_port *start, struct tb_port *end,
int tb_switch_find_vse_cap(struct tb_switch *sw, enum tb_switch_vse_cap vsec);
int tb_port_find_cap(struct tb_port *port, enum tb_port_cap cap);
+bool tb_port_is_enabled(struct tb_port *port);
bool tb_pci_port_is_enabled(struct tb_port *port);
int tb_pci_port_enable(struct tb_port *port, bool enable);
--
2.20.1
^ permalink raw reply related
* Re: [PATCH 2/2] ARM: dts: stm32: Enable STM32F769 clock driver
From: Alexandre Torgue @ 2019-04-10 13:40 UTC (permalink / raw)
To: Gabriel Fernandez, michael turquette, stephen boyd, rob herring,
mark rutland, maxime coquelin
Cc: linux-clk, devicetree, linux-kernel, linux-stm32
In-Reply-To: <20190405075332.28530-3-gabriel.fernandez@st.com>
Hi Gabriel
On 4/5/19 9:53 AM, Gabriel Fernandez wrote:
> This patch enables clocks for STM32F769 boards.
>
> Signed-off-by: Gabriel Fernandez <gabriel.fernandez@st.com>
> ---
> arch/arm/boot/dts/stm32f769-disco.dts | 4 ++++
> 1 file changed, 4 insertions(+)
>
> diff --git a/arch/arm/boot/dts/stm32f769-disco.dts b/arch/arm/boot/dts/stm32f769-disco.dts
> index 3c7216844a9b..6f1d0ac8c31c 100644
> --- a/arch/arm/boot/dts/stm32f769-disco.dts
> +++ b/arch/arm/boot/dts/stm32f769-disco.dts
> @@ -102,6 +102,10 @@
> };
> };
>
> +&rcc {
> + compatible = "st,stm32f769-rcc", "st,stm32f746-rcc", "st,stm32-rcc";
> +};
> +
> &cec {
> pinctrl-0 = <&cec_pins_a>;
> pinctrl-names = "default";
>
Even if driver part is not yet merged, this DT part can be taken as we
will run with "st,stm32f746-rcc" compatible (the current one).
So:
Applied on stm32-next.
Thanks.
Alex
^ permalink raw reply
* [PATCH v4 27/36] thunderbolt: Do not tear down tunnels when driver is unloaded
From: Mika Westerberg @ 2019-04-10 13:36 UTC (permalink / raw)
To: linux-kernel
Cc: Michael Jamet, Yehezkel Bernat, Andreas Noever, Lukas Wunner,
David S . Miller, Andy Shevchenko, Christian Kellner,
Mario.Limonciello, Joe Perches, Mika Westerberg, netdev
In-Reply-To: <20190410133653.88061-1-mika.westerberg@linux.intel.com>
Now that we have capability to discover existing tunnels during driver
load there is no point tearing down tunnels when the driver gets
unloaded. Instead we can just leave them running. If user disconnects
devices while there is no Thunderbolt driver loaded, tunneled protocol
hotplug happens and is handled by the corresponding driver (pciehp in
case of PCIe tunnel, GFX driver in case of DP tunnel).
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
---
drivers/thunderbolt/path.c | 10 ++++------
drivers/thunderbolt/tb.c | 4 +---
drivers/thunderbolt/tunnel.c | 10 +---------
3 files changed, 6 insertions(+), 18 deletions(-)
diff --git a/drivers/thunderbolt/path.c b/drivers/thunderbolt/path.c
index 670a12e60d66..3fc92881a197 100644
--- a/drivers/thunderbolt/path.c
+++ b/drivers/thunderbolt/path.c
@@ -304,17 +304,15 @@ struct tb_path *tb_path_alloc(struct tb *tb, struct tb_port *src, int src_hopid,
}
/**
- * tb_path_free() - free a deactivated path
+ * tb_path_free() - free a path
+ * @path: Path to free
+ *
+ * Frees a path. The path does not need to be deactivated.
*/
void tb_path_free(struct tb_path *path)
{
int i;
- if (path->activated) {
- tb_WARN(path->tb, "trying to free an activated path\n")
- return;
- }
-
for (i = 0; i < path->path_length; i++) {
const struct tb_path_hop *hop = &path->hops[i];
diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c
index c5e96e7ac37a..8a97a4e19638 100644
--- a/drivers/thunderbolt/tb.c
+++ b/drivers/thunderbolt/tb.c
@@ -500,10 +500,8 @@ static void tb_stop(struct tb *tb)
struct tb_tunnel *n;
/* tunnels are only present after everything has been initialized */
- list_for_each_entry_safe(tunnel, n, &tcm->tunnel_list, list) {
- tb_tunnel_deactivate(tunnel);
+ list_for_each_entry_safe(tunnel, n, &tcm->tunnel_list, list)
tb_tunnel_free(tunnel);
- }
tb_switch_remove(tb->root_switch);
tcm->hotplug_active = false; /* signal tb_handle_hotplug to quit */
}
diff --git a/drivers/thunderbolt/tunnel.c b/drivers/thunderbolt/tunnel.c
index 21d3393c6e9c..0bc6639c6e74 100644
--- a/drivers/thunderbolt/tunnel.c
+++ b/drivers/thunderbolt/tunnel.c
@@ -475,7 +475,7 @@ struct tb_tunnel *tb_tunnel_alloc_dp(struct tb *tb, struct tb_port *in,
* tb_tunnel_free() - free a tunnel
* @tunnel: Tunnel to be freed
*
- * The tunnel must have been deactivated.
+ * Frees a tunnel. The tunnel does not need to be deactivated.
*/
void tb_tunnel_free(struct tb_tunnel *tunnel)
{
@@ -484,14 +484,6 @@ void tb_tunnel_free(struct tb_tunnel *tunnel)
if (!tunnel)
return;
- for (i = 0; i < tunnel->npaths; i++) {
- if (tunnel->paths[i] && tunnel->paths[i]->activated) {
- tb_tunnel_WARN(tunnel,
- "trying to free an activated tunnel\n");
- return;
- }
- }
-
for (i = 0; i < tunnel->npaths; i++) {
if (tunnel->paths[i])
tb_path_free(tunnel->paths[i]);
--
2.20.1
^ permalink raw reply related
* Re: [PATCH net 7/7] mlxsw: spectrum_buffers: Add a multicast pool for Spectrum-2
From: Jiri Pirko @ 2019-04-10 13:40 UTC (permalink / raw)
To: Ido Schimmel
Cc: netdev@vger.kernel.org, davem@davemloft.net, Jiri Pirko, mlxsw
In-Reply-To: <20190410065758.21199-8-idosch@mellanox.com>
Wed, Apr 10, 2019 at 08:58:17AM CEST, idosch@mellanox.com wrote:
>In Spectrum-1, when a multicast packet is admitted to the shared buffer
>it increases the quotas of all the ports and {port, TC} to which it is
>forwarded to.
>
>The above means that multicast packets are accounted multiple times in
>the shared buffer and can therefore cause the associated shared buffer
>pool to fill up very quickly.
>
>To work around this issue, commit e83c045e53d7 ("mlxsw:
>spectrum_buffers: Configure MC pool") added a dedicated multicast pool
>in which multicast packets are accounted.
>
>The issue is not present in Spectrum-2, but in order to be backward
>compatible with Spectrum-1, its default behavior is to allow a multicast
>packet to increase multiple egress quotas instead of one.
>
>Until the new (non-backward compatible) mode is supported, configure a
>dedicated multicast pool as in Spectrum-1.
>
>Fixes: fe099bf682ab ("mlxsw: spectrum_buffers: Add Spectrum-2 shared buffer configuration")
>Signed-off-by: Ido Schimmel <idosch@mellanox.com>
>Reviewed-by: Petr Machata <petrm@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
^ permalink raw reply
* [PATCH v4 07/36] thunderbolt: Enable TMU access when accessing port space on legacy devices
From: Mika Westerberg @ 2019-04-10 13:36 UTC (permalink / raw)
To: linux-kernel
Cc: Michael Jamet, Yehezkel Bernat, Andreas Noever, Lukas Wunner,
David S . Miller, Andy Shevchenko, Christian Kellner,
Mario.Limonciello, Joe Perches, Mika Westerberg, netdev
In-Reply-To: <20190410133653.88061-1-mika.westerberg@linux.intel.com>
Light Ridge and Eagle Ridge both need to have TMU access enabled before
port space can be fully accessed so make sure it happens on those. This
allows us to get rid of the offset quirk in tb_port_find_cap().
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
---
drivers/thunderbolt/cap.c | 69 +++++++++++++++++++++++++++++----------
drivers/thunderbolt/tb.h | 10 ++++++
2 files changed, 62 insertions(+), 17 deletions(-)
diff --git a/drivers/thunderbolt/cap.c b/drivers/thunderbolt/cap.c
index 9553305c63ea..a58585b4e6d9 100644
--- a/drivers/thunderbolt/cap.c
+++ b/drivers/thunderbolt/cap.c
@@ -13,6 +13,7 @@
#define CAP_OFFSET_MAX 0xff
#define VSE_CAP_OFFSET_MAX 0xffff
+#define TMU_ACCESS_EN BIT(20)
struct tb_cap_any {
union {
@@ -22,28 +23,38 @@ struct tb_cap_any {
};
} __packed;
-/**
- * tb_port_find_cap() - Find port capability
- * @port: Port to find the capability for
- * @cap: Capability to look
- *
- * Returns offset to start of capability or %-ENOENT if no such
- * capability was found. Negative errno is returned if there was an
- * error.
- */
-int tb_port_find_cap(struct tb_port *port, enum tb_port_cap cap)
+static int tb_port_enable_tmu(struct tb_port *port, bool enable)
{
- u32 offset;
+ struct tb_switch *sw = port->sw;
+ u32 value, offset;
+ int ret;
/*
- * DP out adapters claim to implement TMU capability but in
- * reality they do not so we hard code the adapter specific
- * capability offset here.
+ * Legacy devices need to have TMU access enabled before port
+ * space can be fully accessed.
*/
- if (port->config.type == TB_TYPE_DP_HDMI_OUT)
- offset = 0x39;
+ if (tb_switch_is_lr(sw))
+ offset = 0x26;
+ else if (tb_switch_is_er(sw))
+ offset = 0x2a;
+ else
+ return 0;
+
+ ret = tb_sw_read(sw, &value, TB_CFG_SWITCH, offset, 1);
+ if (ret)
+ return ret;
+
+ if (enable)
+ value |= TMU_ACCESS_EN;
else
- offset = 0x1;
+ value &= ~TMU_ACCESS_EN;
+
+ return tb_sw_write(sw, &value, TB_CFG_SWITCH, offset, 1);
+}
+
+static int __tb_port_find_cap(struct tb_port *port, enum tb_port_cap cap)
+{
+ u32 offset = 1;
do {
struct tb_cap_any header;
@@ -62,6 +73,30 @@ int tb_port_find_cap(struct tb_port *port, enum tb_port_cap cap)
return -ENOENT;
}
+/**
+ * tb_port_find_cap() - Find port capability
+ * @port: Port to find the capability for
+ * @cap: Capability to look
+ *
+ * Returns offset to start of capability or %-ENOENT if no such
+ * capability was found. Negative errno is returned if there was an
+ * error.
+ */
+int tb_port_find_cap(struct tb_port *port, enum tb_port_cap cap)
+{
+ int ret;
+
+ ret = tb_port_enable_tmu(port, true);
+ if (ret)
+ return ret;
+
+ ret = __tb_port_find_cap(port, cap);
+
+ tb_port_enable_tmu(port, false);
+
+ return ret;
+}
+
static int tb_switch_find_cap(struct tb_switch *sw, enum tb_switch_cap cap)
{
int offset = sw->config.first_cap_offset;
diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h
index 93c1ea21feeb..a166265dfcf9 100644
--- a/drivers/thunderbolt/tb.h
+++ b/drivers/thunderbolt/tb.h
@@ -436,6 +436,16 @@ static inline struct tb_switch *tb_to_switch(struct device *dev)
return NULL;
}
+static inline bool tb_switch_is_lr(const struct tb_switch *sw)
+{
+ return sw->config.device_id == PCI_DEVICE_ID_INTEL_LIGHT_RIDGE;
+}
+
+static inline bool tb_switch_is_er(const struct tb_switch *sw)
+{
+ return sw->config.device_id == PCI_DEVICE_ID_INTEL_EAGLE_RIDGE;
+}
+
int tb_wait_for_port(struct tb_port *port, bool wait_if_unplugged);
int tb_port_add_nfc_credits(struct tb_port *port, int credits);
int tb_port_clear_counter(struct tb_port *port, int counter);
--
2.20.1
^ permalink raw reply related
* [PATCH v4 23/36] thunderbolt: Scan only valid NULL adapter ports in hotplug
From: Mika Westerberg @ 2019-04-10 13:36 UTC (permalink / raw)
To: linux-kernel
Cc: Michael Jamet, Yehezkel Bernat, Andreas Noever, Lukas Wunner,
David S . Miller, Andy Shevchenko, Christian Kellner,
Mario.Limonciello, Joe Perches, Mika Westerberg, netdev
In-Reply-To: <20190410133653.88061-1-mika.westerberg@linux.intel.com>
The only way to expand Thunderbolt topology is through the NULL adapter
ports (typically ports 1, 2, 3 and 4). There is no point handling
Thunderbolt hotplug events on any other port.
Add a helper function (tb_port_is_null()) that can be used to determine
if the port is NULL port, and use it in software connection manager code
when hotplug event is handled.
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
---
drivers/thunderbolt/tb.c | 10 ++++++----
drivers/thunderbolt/tb.h | 5 +++++
2 files changed, 11 insertions(+), 4 deletions(-)
diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c
index cfc451c938fd..fb01396a62a9 100644
--- a/drivers/thunderbolt/tb.c
+++ b/drivers/thunderbolt/tb.c
@@ -356,10 +356,12 @@ static void tb_handle_hotplug(struct work_struct *work)
tb_port_info(port,
"got plug event for connected port, ignoring\n");
} else {
- tb_port_info(port, "hotplug: scanning\n");
- tb_scan_port(port);
- if (!port->remote)
- tb_port_info(port, "hotplug: no switch found\n");
+ if (tb_port_is_null(port)) {
+ tb_port_info(port, "hotplug: scanning\n");
+ tb_scan_port(port);
+ if (!port->remote)
+ tb_port_info(port, "hotplug: no switch found\n");
+ }
}
put_sw:
diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h
index 5b5ba8919086..260360ec59a9 100644
--- a/drivers/thunderbolt/tb.h
+++ b/drivers/thunderbolt/tb.h
@@ -350,6 +350,11 @@ static inline bool tb_port_has_remote(const struct tb_port *port)
return true;
}
+static inline bool tb_port_is_null(const struct tb_port *port)
+{
+ return port && port->port && port->config.type == TB_TYPE_PORT;
+}
+
static inline bool tb_port_is_pcie_down(const struct tb_port *port)
{
return port && port->config.type == TB_TYPE_PCIE_DOWN;
--
2.20.1
^ permalink raw reply related
* [PATCH v4 32/36] thunderbolt: Add support for XDomain connections
From: Mika Westerberg @ 2019-04-10 13:36 UTC (permalink / raw)
To: linux-kernel
Cc: Michael Jamet, Yehezkel Bernat, Andreas Noever, Lukas Wunner,
David S . Miller, Andy Shevchenko, Christian Kellner,
Mario.Limonciello, Joe Perches, Mika Westerberg, netdev
In-Reply-To: <20190410133653.88061-1-mika.westerberg@linux.intel.com>
Two domains (hosts) can be connected through a Thunderbolt cable and in
that case they can start software services such as networking over the
high-speed DMA paths. Now that we have all the basic building blocks in
place to create DMA tunnels over the Thunderbolt fabric we can add this
support to the software connection manager as well.
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
---
drivers/thunderbolt/switch.c | 29 +++++-
drivers/thunderbolt/tb.c | 167 ++++++++++++++++++++++++++++++++++-
2 files changed, 188 insertions(+), 8 deletions(-)
diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c
index 460f2bcad40a..a5345a6225bd 100644
--- a/drivers/thunderbolt/switch.c
+++ b/drivers/thunderbolt/switch.c
@@ -1845,6 +1845,8 @@ void tb_sw_set_unplugged(struct tb_switch *sw)
for (i = 0; i <= sw->config.max_port_number; i++) {
if (tb_port_has_remote(&sw->ports[i]))
tb_sw_set_unplugged(sw->ports[i].remote->sw);
+ else if (sw->ports[i].xdomain)
+ sw->ports[i].xdomain->is_unplugged = true;
}
}
@@ -1860,6 +1862,17 @@ int tb_switch_resume(struct tb_switch *sw)
if (tb_route(sw)) {
u64 uid;
+ /*
+ * Check first that we can still read the switch config
+ * space. It may be that there is now another domain
+ * connected.
+ */
+ err = tb_cfg_get_upstream_port(sw->tb->ctl, tb_route(sw));
+ if (err < 0) {
+ tb_sw_info(sw, "switch not present anymore\n");
+ return err;
+ }
+
err = tb_drom_read_uid_only(sw, &uid);
if (err) {
tb_sw_warn(sw, "uid read failed\n");
@@ -1890,14 +1903,22 @@ int tb_switch_resume(struct tb_switch *sw)
for (i = 1; i <= sw->config.max_port_number; i++) {
struct tb_port *port = &sw->ports[i];
- if (!tb_port_has_remote(port))
+ if (!tb_port_has_remote(port) && !port->xdomain)
continue;
- if (tb_wait_for_port(port, true) <= 0
- || tb_switch_resume(port->remote->sw)) {
+ if (tb_wait_for_port(port, true) <= 0) {
tb_port_warn(port,
"lost during suspend, disconnecting\n");
- tb_sw_set_unplugged(port->remote->sw);
+ if (tb_port_has_remote(port))
+ tb_sw_set_unplugged(port->remote->sw);
+ else if (port->xdomain)
+ port->xdomain->is_unplugged = true;
+ } else if (tb_port_has_remote(port)) {
+ if (tb_switch_resume(port->remote->sw)) {
+ tb_port_warn(port,
+ "lost during suspend, disconnecting\n");
+ tb_sw_set_unplugged(port->remote->sw);
+ }
}
}
return 0;
diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c
index c5e82c4dcb64..e39fc1e35e6b 100644
--- a/drivers/thunderbolt/tb.c
+++ b/drivers/thunderbolt/tb.c
@@ -101,6 +101,28 @@ static void tb_discover_tunnels(struct tb_switch *sw)
}
}
+static void tb_scan_xdomain(struct tb_port *port)
+{
+ struct tb_switch *sw = port->sw;
+ struct tb *tb = sw->tb;
+ struct tb_xdomain *xd;
+ u64 route;
+
+ route = tb_downstream_route(port);
+ xd = tb_xdomain_find_by_route(tb, route);
+ if (xd) {
+ tb_xdomain_put(xd);
+ return;
+ }
+
+ xd = tb_xdomain_alloc(tb, &sw->dev, route, tb->root_switch->uuid,
+ NULL);
+ if (xd) {
+ tb_port_at(route, sw)->xdomain = xd;
+ tb_xdomain_add(xd);
+ }
+}
+
static void tb_scan_port(struct tb_port *port);
/**
@@ -143,19 +165,36 @@ static void tb_scan_port(struct tb_port *port)
if (tb_wait_for_port(port, false) <= 0)
return;
if (port->remote) {
- tb_port_WARN(port, "port already has a remote!\n");
+ tb_port_dbg(port, "port already has a remote\n");
return;
}
sw = tb_switch_alloc(port->sw->tb, &port->sw->dev,
tb_downstream_route(port));
- if (IS_ERR(sw))
+ if (IS_ERR(sw)) {
+ /*
+ * If there is an error accessing the connected switch
+ * it may be connected to another domain. Also we allow
+ * the other domain to be connected to a max depth switch.
+ */
+ if (PTR_ERR(sw) == -EIO || PTR_ERR(sw) == -EADDRNOTAVAIL)
+ tb_scan_xdomain(port);
return;
+ }
if (tb_switch_configure(sw)) {
tb_switch_put(sw);
return;
}
+ /*
+ * If there was previously another domain connected remove it
+ * first.
+ */
+ if (port->xdomain) {
+ tb_xdomain_remove(port->xdomain);
+ port->xdomain = NULL;
+ }
+
/*
* Do not send uevents until we have discovered all existing
* tunnels and know which switches were authorized already by
@@ -393,6 +432,65 @@ static int tb_tunnel_pci(struct tb *tb, struct tb_switch *sw)
return 0;
}
+static int tb_approve_xdomain_paths(struct tb *tb, struct tb_xdomain *xd)
+{
+ struct tb_cm *tcm = tb_priv(tb);
+ struct tb_port *nhi_port, *dst_port;
+ struct tb_tunnel *tunnel;
+ struct tb_switch *sw;
+
+ sw = tb_to_switch(xd->dev.parent);
+ dst_port = tb_port_at(xd->route, sw);
+ nhi_port = tb_find_port(tb->root_switch, TB_TYPE_NHI);
+
+ mutex_lock(&tb->lock);
+ tunnel = tb_tunnel_alloc_dma(tb, nhi_port, dst_port, xd->transmit_ring,
+ xd->transmit_path, xd->receive_ring,
+ xd->receive_path);
+ if (!tunnel) {
+ mutex_unlock(&tb->lock);
+ return -ENOMEM;
+ }
+
+ if (tb_tunnel_activate(tunnel)) {
+ tb_port_info(nhi_port,
+ "DMA tunnel activation failed, aborting\n");
+ tb_tunnel_free(tunnel);
+ mutex_unlock(&tb->lock);
+ return -EIO;
+ }
+
+ list_add_tail(&tunnel->list, &tcm->tunnel_list);
+ mutex_unlock(&tb->lock);
+ return 0;
+}
+
+static void __tb_disconnect_xdomain_paths(struct tb *tb, struct tb_xdomain *xd)
+{
+ struct tb_port *dst_port;
+ struct tb_switch *sw;
+
+ sw = tb_to_switch(xd->dev.parent);
+ dst_port = tb_port_at(xd->route, sw);
+
+ /*
+ * It is possible that the tunnel was already teared down (in
+ * case of cable disconnect) so it is fine if we cannot find it
+ * here anymore.
+ */
+ tb_free_tunnel(tb, TB_TUNNEL_DMA, NULL, dst_port);
+}
+
+static int tb_disconnect_xdomain_paths(struct tb *tb, struct tb_xdomain *xd)
+{
+ if (!xd->is_unplugged) {
+ mutex_lock(&tb->lock);
+ __tb_disconnect_xdomain_paths(tb, xd);
+ mutex_unlock(&tb->lock);
+ }
+ return 0;
+}
+
/* hotplug handling */
/**
@@ -432,13 +530,29 @@ static void tb_handle_hotplug(struct work_struct *work)
}
if (ev->unplug) {
if (tb_port_has_remote(port)) {
- tb_port_info(port, "unplugged\n");
+ tb_port_dbg(port, "switch unplugged\n");
tb_sw_set_unplugged(port->remote->sw);
tb_free_invalid_tunnels(tb);
tb_switch_remove(port->remote->sw);
port->remote = NULL;
if (port->dual_link_port)
port->dual_link_port->remote = NULL;
+ } else if (port->xdomain) {
+ struct tb_xdomain *xd = tb_xdomain_get(port->xdomain);
+
+ tb_port_dbg(port, "xdomain unplugged\n");
+ /*
+ * Service drivers are unbound during
+ * tb_xdomain_remove() so setting XDomain as
+ * unplugged here prevents deadlock if they call
+ * tb_xdomain_disable_paths(). We will tear down
+ * the path below.
+ */
+ xd->is_unplugged = true;
+ tb_xdomain_remove(xd);
+ port->xdomain = NULL;
+ __tb_disconnect_xdomain_paths(tb, xd);
+ tb_xdomain_put(xd);
} else if (tb_port_is_dpout(port)) {
tb_teardown_dp(tb, port);
} else {
@@ -500,8 +614,16 @@ static void tb_stop(struct tb *tb)
struct tb_tunnel *n;
/* tunnels are only present after everything has been initialized */
- list_for_each_entry_safe(tunnel, n, &tcm->tunnel_list, list)
+ list_for_each_entry_safe(tunnel, n, &tcm->tunnel_list, list) {
+ /*
+ * DMA tunnels require the driver to be functional so we
+ * tear them down. Other protocol tunnels can be left
+ * intact.
+ */
+ if (tb_tunnel_is_dma(tunnel))
+ tb_tunnel_deactivate(tunnel);
tb_tunnel_free(tunnel);
+ }
tb_switch_remove(tb->root_switch);
tcm->hotplug_active = false; /* signal tb_handle_hotplug to quit */
}
@@ -611,13 +733,50 @@ static int tb_resume_noirq(struct tb *tb)
return 0;
}
+static int tb_free_unplugged_xdomains(struct tb_switch *sw)
+{
+ int i, ret = 0;
+
+ for (i = 1; i <= sw->config.max_port_number; i++) {
+ struct tb_port *port = &sw->ports[i];
+
+ if (tb_is_upstream_port(port))
+ continue;
+ if (port->xdomain && port->xdomain->is_unplugged) {
+ tb_xdomain_remove(port->xdomain);
+ port->xdomain = NULL;
+ ret++;
+ } else if (port->remote) {
+ ret += tb_free_unplugged_xdomains(port->remote->sw);
+ }
+ }
+
+ return ret;
+}
+
+static void tb_complete(struct tb *tb)
+{
+ /*
+ * Release any unplugged XDomains and if there is a case where
+ * another domain is swapped in place of unplugged XDomain we
+ * need to run another rescan.
+ */
+ mutex_lock(&tb->lock);
+ if (tb_free_unplugged_xdomains(tb->root_switch))
+ tb_scan_switch(tb->root_switch);
+ mutex_unlock(&tb->lock);
+}
+
static const struct tb_cm_ops tb_cm_ops = {
.start = tb_start,
.stop = tb_stop,
.suspend_noirq = tb_suspend_noirq,
.resume_noirq = tb_resume_noirq,
+ .complete = tb_complete,
.handle_event = tb_handle_event,
.approve_switch = tb_tunnel_pci,
+ .approve_xdomain_paths = tb_approve_xdomain_paths,
+ .disconnect_xdomain_paths = tb_disconnect_xdomain_paths,
};
struct tb *tb_probe(struct tb_nhi *nhi)
--
2.20.1
^ permalink raw reply related
* [PATCH v4 30/36] thunderbolt: Add support for DMA tunnels
From: Mika Westerberg @ 2019-04-10 13:36 UTC (permalink / raw)
To: linux-kernel
Cc: Michael Jamet, Yehezkel Bernat, Andreas Noever, Lukas Wunner,
David S . Miller, Andy Shevchenko, Christian Kellner,
Mario.Limonciello, Joe Perches, Mika Westerberg, netdev
In-Reply-To: <20190410133653.88061-1-mika.westerberg@linux.intel.com>
In addition to PCIe and Display Port tunnels it is also possible to
create tunnels that forward DMA traffic from the host interface adapter
(NHI) to a NULL port that is connected to another domain through a
Thunderbolt cable. These tunnels can be used to carry software messages
such as networking packets.
To support this we introduce another tunnel type (TB_TUNNEL_DMA) that
supports paths from NHI to NULL port and back.
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
---
drivers/thunderbolt/path.c | 22 +++++++--
drivers/thunderbolt/switch.c | 22 +++++++++
drivers/thunderbolt/tb.h | 4 ++
drivers/thunderbolt/tb_regs.h | 3 ++
drivers/thunderbolt/tunnel.c | 93 ++++++++++++++++++++++++++++++++++-
drivers/thunderbolt/tunnel.h | 10 ++++
6 files changed, 149 insertions(+), 5 deletions(-)
diff --git a/drivers/thunderbolt/path.c b/drivers/thunderbolt/path.c
index 3fc92881a197..e4c22f53ef4d 100644
--- a/drivers/thunderbolt/path.c
+++ b/drivers/thunderbolt/path.c
@@ -341,7 +341,8 @@ static void __tb_path_deallocate_nfc(struct tb_path *path, int first_hop)
}
}
-static int __tb_path_deactivate_hop(struct tb_port *port, int hop_index)
+static int __tb_path_deactivate_hop(struct tb_port *port, int hop_index,
+ bool clear_fc)
{
struct tb_regs_hop hop;
ktime_t timeout;
@@ -369,8 +370,20 @@ static int __tb_path_deactivate_hop(struct tb_port *port, int hop_index)
if (ret)
return ret;
- if (!hop.pending)
+ if (!hop.pending) {
+ if (clear_fc) {
+ /* Clear flow control */
+ hop.ingress_fc = 0;
+ hop.egress_fc = 0;
+ hop.ingress_shared_buffer = 0;
+ hop.egress_shared_buffer = 0;
+
+ return tb_port_write(port, &hop, TB_CFG_HOPS,
+ 2 * hop_index, 2);
+ }
+
return 0;
+ }
usleep_range(10, 20);
} while (ktime_before(ktime_get(), timeout));
@@ -384,7 +397,8 @@ static void __tb_path_deactivate_hops(struct tb_path *path, int first_hop)
for (i = first_hop; i < path->path_length; i++) {
res = __tb_path_deactivate_hop(path->hops[i].in_port,
- path->hops[i].in_hop_index);
+ path->hops[i].in_hop_index,
+ path->clear_fc);
if (res && res != -ENODEV)
tb_port_warn(path->hops[i].in_port,
"hop deactivation failed for hop %d, index %d\n",
@@ -459,7 +473,7 @@ int tb_path_activate(struct tb_path *path)
/* If it is left active deactivate it first */
__tb_path_deactivate_hop(path->hops[i].in_port,
- path->hops[i].in_hop_index);
+ path->hops[i].in_hop_index, path->clear_fc);
/* dword 0 */
hop.next_hop = path->hops[i].next_hop_index;
diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c
index 1de1afa24182..ecf53d986a5c 100644
--- a/drivers/thunderbolt/switch.c
+++ b/drivers/thunderbolt/switch.c
@@ -555,6 +555,28 @@ int tb_port_add_nfc_credits(struct tb_port *port, int credits)
TB_CFG_PORT, 4, 1);
}
+/**
+ * tb_port_set_initial_credits() - Set initial port link credits allocated
+ * @port: Port to set the initial credits
+ * @credits: Number of credits to to allocate
+ *
+ * Set initial credits value to be used for ingress shared buffering.
+ */
+int tb_port_set_initial_credits(struct tb_port *port, u32 credits)
+{
+ u32 data;
+ int ret;
+
+ ret = tb_port_read(port, &data, TB_CFG_PORT, 5, 1);
+ if (ret)
+ return ret;
+
+ data &= ~TB_PORT_LCA_MASK;
+ data |= (credits << TB_PORT_LCA_SHIFT) & TB_PORT_LCA_MASK;
+
+ return tb_port_write(port, &data, TB_CFG_PORT, 5, 1);
+}
+
/**
* tb_port_clear_counter() - clear a counter in TB_CFG_COUNTER
*
diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h
index 89b5d18f6035..119a00837992 100644
--- a/drivers/thunderbolt/tb.h
+++ b/drivers/thunderbolt/tb.h
@@ -207,6 +207,8 @@ enum tb_path_port {
* @weight: Weight of the path inside the priority group
* @drop_packages: Drop packages from queue tail or head
* @activated: Is the path active
+ * @clear_fc: Clear all flow control from the path config space entries
+ * when deactivating this path
* @hops: Path hops
* @path_length: How many hops the path uses
*
@@ -227,6 +229,7 @@ struct tb_path {
int weight:4;
bool drop_packages;
bool activated;
+ bool clear_fc;
struct tb_path_hop *hops;
int path_length;
};
@@ -583,6 +586,7 @@ static inline bool tb_switch_is_fr(const struct tb_switch *sw)
int tb_wait_for_port(struct tb_port *port, bool wait_if_unplugged);
int tb_port_add_nfc_credits(struct tb_port *port, int credits);
+int tb_port_set_initial_credits(struct tb_port *port, u32 credits);
int tb_port_clear_counter(struct tb_port *port, int counter);
int tb_port_alloc_in_hopid(struct tb_port *port, int hopid, int max_hopid);
void tb_port_release_in_hopid(struct tb_port *port, int hopid);
diff --git a/drivers/thunderbolt/tb_regs.h b/drivers/thunderbolt/tb_regs.h
index 3ce705184e2c..deb9d4a977b9 100644
--- a/drivers/thunderbolt/tb_regs.h
+++ b/drivers/thunderbolt/tb_regs.h
@@ -215,6 +215,9 @@ struct tb_regs_port_header {
#define TB_PORT_NFC_CREDITS_MASK GENMASK(19, 0)
#define TB_PORT_MAX_CREDITS_SHIFT 20
#define TB_PORT_MAX_CREDITS_MASK GENMASK(26, 20)
+/* DWORD 5 */
+#define TB_PORT_LCA_SHIFT 22
+#define TB_PORT_LCA_MASK GENMASK(28, 22)
/* Display Port adapter registers */
diff --git a/drivers/thunderbolt/tunnel.c b/drivers/thunderbolt/tunnel.c
index 0bc6639c6e74..9f9b26b12d0a 100644
--- a/drivers/thunderbolt/tunnel.c
+++ b/drivers/thunderbolt/tunnel.c
@@ -27,7 +27,10 @@
#define TB_DP_AUX_PATH_OUT 1
#define TB_DP_AUX_PATH_IN 2
-static const char * const tb_tunnel_names[] = { "PCI", "DP" };
+#define TB_DMA_PATH_OUT 0
+#define TB_DMA_PATH_IN 1
+
+static const char * const tb_tunnel_names[] = { "PCI", "DP", "DMA" };
#define __TB_TUNNEL_PRINT(level, tunnel, fmt, arg...) \
do { \
@@ -471,6 +474,94 @@ struct tb_tunnel *tb_tunnel_alloc_dp(struct tb *tb, struct tb_port *in,
return NULL;
}
+static u32 tb_dma_credits(struct tb_port *nhi)
+{
+ u32 max_credits;
+
+ max_credits = (nhi->config.nfc_credits & TB_PORT_MAX_CREDITS_MASK) >>
+ TB_PORT_MAX_CREDITS_SHIFT;
+ return min(max_credits, 13U);
+}
+
+static int tb_dma_activate(struct tb_tunnel *tunnel, bool active)
+{
+ struct tb_port *nhi = tunnel->src_port;
+ u32 credits;
+
+ credits = active ? tb_dma_credits(nhi) : 0;
+ return tb_port_set_initial_credits(nhi, credits);
+}
+
+static void tb_dma_init_path(struct tb_path *path, unsigned int isb,
+ unsigned int efc, u32 credits)
+{
+ int i;
+
+ path->egress_fc_enable = efc;
+ path->ingress_fc_enable = TB_PATH_ALL;
+ path->egress_shared_buffer = TB_PATH_NONE;
+ path->ingress_shared_buffer = isb;
+ path->priority = 5;
+ path->weight = 1;
+ path->clear_fc = true;
+
+ for (i = 0; i < path->path_length; i++)
+ path->hops[i].initial_credits = credits;
+}
+
+/**
+ * tb_tunnel_alloc_dma() - allocate a DMA tunnel
+ * @tb: Pointer to the domain structure
+ * @nhi: Host controller port
+ * @dst: Destination null port which the other domain is connected to
+ * @transmit_ring: NHI ring number used to send packets towards the
+ * other domain
+ * @transmit_path: HopID used for transmitting packets
+ * @receive_ring: NHI ring number used to receive packets from the
+ * other domain
+ * @reveive_path: HopID used for receiving packets
+ *
+ * Return: Returns a tb_tunnel on success or NULL on failure.
+ */
+struct tb_tunnel *tb_tunnel_alloc_dma(struct tb *tb, struct tb_port *nhi,
+ struct tb_port *dst, int transmit_ring,
+ int transmit_path, int receive_ring,
+ int receive_path)
+{
+ struct tb_tunnel *tunnel;
+ struct tb_path *path;
+ u32 credits;
+
+ tunnel = tb_tunnel_alloc(tb, 2, TB_TUNNEL_DMA);
+ if (!tunnel)
+ return NULL;
+
+ tunnel->activate = tb_dma_activate;
+ tunnel->src_port = nhi;
+ tunnel->dst_port = dst;
+
+ credits = tb_dma_credits(nhi);
+
+ path = tb_path_alloc(tb, dst, receive_path, nhi, receive_ring, 0, "DMA RX");
+ if (!path) {
+ tb_tunnel_free(tunnel);
+ return NULL;
+ }
+ tb_dma_init_path(path, TB_PATH_NONE, TB_PATH_SOURCE | TB_PATH_INTERNAL,
+ credits);
+ tunnel->paths[TB_DMA_PATH_IN] = path;
+
+ path = tb_path_alloc(tb, nhi, transmit_ring, dst, transmit_path, 0, "DMA TX");
+ if (!path) {
+ tb_tunnel_free(tunnel);
+ return NULL;
+ }
+ tb_dma_init_path(path, TB_PATH_SOURCE, TB_PATH_ALL, credits);
+ tunnel->paths[TB_DMA_PATH_OUT] = path;
+
+ return tunnel;
+}
+
/**
* tb_tunnel_free() - free a tunnel
* @tunnel: Tunnel to be freed
diff --git a/drivers/thunderbolt/tunnel.h b/drivers/thunderbolt/tunnel.h
index 0373779f43ba..c68bbcd3a62c 100644
--- a/drivers/thunderbolt/tunnel.h
+++ b/drivers/thunderbolt/tunnel.h
@@ -14,6 +14,7 @@
enum tb_tunnel_type {
TB_TUNNEL_PCI,
TB_TUNNEL_DP,
+ TB_TUNNEL_DMA,
};
/**
@@ -47,6 +48,10 @@ struct tb_tunnel *tb_tunnel_alloc_pci(struct tb *tb, struct tb_port *up,
struct tb_tunnel *tb_tunnel_discover_dp(struct tb *tb, struct tb_port *in);
struct tb_tunnel *tb_tunnel_alloc_dp(struct tb *tb, struct tb_port *in,
struct tb_port *out);
+struct tb_tunnel *tb_tunnel_alloc_dma(struct tb *tb, struct tb_port *nhi,
+ struct tb_port *dst, int transmit_ring,
+ int transmit_path, int receive_ring,
+ int receive_path);
void tb_tunnel_free(struct tb_tunnel *tunnel);
int tb_tunnel_activate(struct tb_tunnel *tunnel);
@@ -64,5 +69,10 @@ static inline bool tb_tunnel_is_dp(const struct tb_tunnel *tunnel)
return tunnel->type == TB_TUNNEL_DP;
}
+static inline bool tb_tunnel_is_dma(const struct tb_tunnel *tunnel)
+{
+ return tunnel->type == TB_TUNNEL_DMA;
+}
+
#endif
--
2.20.1
^ permalink raw reply related
* Re: [RFC patch 19/41] lib/stackdepot: Provide functions which operate on plain storage arrays
From: Alexander Potapenko @ 2019-04-10 13:39 UTC (permalink / raw)
To: Thomas Gleixner
Cc: LKML, Josh Poimboeuf, x86, Andy Lutomirski, Steven Rostedt,
Alexander Potapenko
In-Reply-To: <20190410103645.315084160@linutronix.de>
On Wed, Apr 10, 2019 at 1:05 PM Thomas Gleixner <tglx@linutronix.de> wrote:
>
> The struct stack_trace indirection in the stack depot functions is a truly
> pointless excercise which requires horrible code at the callsites.
>
> Provide interfaces based on plain storage arrays.
>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Alexander Potapenko <glider@google.com>
> ---
> include/linux/stackdepot.h | 4 ++
> lib/stackdepot.c | 66 ++++++++++++++++++++++++++++++++-------------
> 2 files changed, 51 insertions(+), 19 deletions(-)
>
> --- a/include/linux/stackdepot.h
> +++ b/include/linux/stackdepot.h
> @@ -26,7 +26,11 @@ typedef u32 depot_stack_handle_t;
> struct stack_trace;
>
> depot_stack_handle_t depot_save_stack(struct stack_trace *trace, gfp_t flags);
> +depot_stack_handle_t stack_depot_save(unsigned long *entries,
> + unsigned int nr_entries, gfp_t gfp_flags);
>
> void depot_fetch_stack(depot_stack_handle_t handle, struct stack_trace *trace);
> +unsigned int stack_depot_fetch(depot_stack_handle_t handle,
> + unsigned long **entries);
>
> #endif
> --- a/lib/stackdepot.c
> +++ b/lib/stackdepot.c
> @@ -194,40 +194,56 @@ static inline struct stack_record *find_
> return NULL;
> }
>
> -void depot_fetch_stack(depot_stack_handle_t handle, struct stack_trace *trace)
> +/**
> + * stack_depot_fetch - Fetch stack entries from a depot
> + *
> + * @entries: Pointer to store the entries address
> + */
> +unsigned int stack_depot_fetch(depot_stack_handle_t handle,
> + unsigned long **entries)
> {
> union handle_parts parts = { .handle = handle };
> void *slab = stack_slabs[parts.slabindex];
> size_t offset = parts.offset << STACK_ALLOC_ALIGN;
> struct stack_record *stack = slab + offset;
>
> - trace->nr_entries = trace->max_entries = stack->size;
> - trace->entries = stack->entries;
> - trace->skip = 0;
> + *entries = stack->entries;
> + return stack->size;
> +}
> +EXPORT_SYMBOL_GPL(stack_depot_fetch);
> +
> +void depot_fetch_stack(depot_stack_handle_t handle, struct stack_trace *trace)
> +{
> + unsigned int nent = stack_depot_fetch(handle, &trace->entries);
> +
> + trace->max_entries = trace->nr_entries = nent;
> }
> EXPORT_SYMBOL_GPL(depot_fetch_stack);
>
> /**
> - * depot_save_stack - save stack in a stack depot.
> - * @trace - the stacktrace to save.
> - * @alloc_flags - flags for allocating additional memory if required.
> + * stack_depot_save - Save a stack trace from an array
> *
> - * Returns the handle of the stack struct stored in depot.
> + * @entries: Pointer to storage array
> + * @nr_entries: Size of the storage array
> + * @alloc_flags: Allocation gfp flags
> + *
> + * Returns the handle of the stack struct stored in depot
> */
> -depot_stack_handle_t depot_save_stack(struct stack_trace *trace,
> - gfp_t alloc_flags)
> +depot_stack_handle_t stack_depot_save(unsigned long *entries,
> + unsigned int nr_entries,
> + gfp_t alloc_flags)
> {
> - u32 hash;
> - depot_stack_handle_t retval = 0;
> struct stack_record *found = NULL, **bucket;
> - unsigned long flags;
> + depot_stack_handle_t retval = 0;
> struct page *page = NULL;
> void *prealloc = NULL;
> + unsigned long flags;
> + u32 hash;
>
> - if (unlikely(trace->nr_entries == 0))
> + if (unlikely(nr_entries == 0))
> goto fast_exit;
>
> - hash = hash_stack(trace->entries, trace->nr_entries);
> + hash = hash_stack(entries, nr_entries);
> bucket = &stack_table[hash & STACK_HASH_MASK];
>
> /*
> @@ -235,8 +251,8 @@ depot_stack_handle_t depot_save_stack(st
> * The smp_load_acquire() here pairs with smp_store_release() to
> * |bucket| below.
> */
> - found = find_stack(smp_load_acquire(bucket), trace->entries,
> - trace->nr_entries, hash);
> + found = find_stack(smp_load_acquire(bucket), entries,
> + nr_entries, hash);
> if (found)
> goto exit;
>
> @@ -264,10 +280,10 @@ depot_stack_handle_t depot_save_stack(st
>
> spin_lock_irqsave(&depot_lock, flags);
>
> - found = find_stack(*bucket, trace->entries, trace->nr_entries, hash);
> + found = find_stack(*bucket, entries, nr_entries, hash);
> if (!found) {
> struct stack_record *new =
> - depot_alloc_stack(trace->entries, trace->nr_entries,
> + depot_alloc_stack(entries, nr_entries,
> hash, &prealloc, alloc_flags);
> if (new) {
> new->next = *bucket;
> @@ -297,4 +313,16 @@ depot_stack_handle_t depot_save_stack(st
> fast_exit:
> return retval;
> }
> +EXPORT_SYMBOL_GPL(stack_depot_save);
> +
> +/**
> + * depot_save_stack - save stack in a stack depot.
> + * @trace - the stacktrace to save.
> + * @alloc_flags - flags for allocating additional memory if required.
> + */
> +depot_stack_handle_t depot_save_stack(struct stack_trace *trace,
> + gfp_t alloc_flags)
> +{
> + return stack_depot_save(trace->entries, trace->nr_entries, alloc_flags);
> +}
> EXPORT_SYMBOL_GPL(depot_save_stack);
>
>
--
Alexander Potapenko
Software Engineer
Google Germany GmbH
Erika-Mann-Straße, 33
80636 München
Geschäftsführer: Paul Manicle, Halimah DeLaine Prado
Registergericht und -nummer: Hamburg, HRB 86891
Sitz der Gesellschaft: Hamburg
^ permalink raw reply
* [PATCH v4 28/36] thunderbolt: Run tb_xdp_handle_request() in system workqueue
From: Mika Westerberg @ 2019-04-10 13:36 UTC (permalink / raw)
To: linux-kernel
Cc: Michael Jamet, Yehezkel Bernat, Andreas Noever, Lukas Wunner,
David S . Miller, Andy Shevchenko, Christian Kellner,
Mario.Limonciello, Joe Perches, Mika Westerberg, netdev
In-Reply-To: <20190410133653.88061-1-mika.westerberg@linux.intel.com>
We run all XDomain requests during discovery in tb->wq and since it only
runs one work at the time it means that sending back reply to the other
domain may be delayed too much depending whether there is an active
XDomain discovery request running.
To make sure we can send reply to the other domain as soon as possible
run tb_xdp_handle_request() in system workqueue instead. Since the
device can be hot-removed in the middle we need to make sure the domain
structure is still around when the function is run so increase reference
count before we schedule the reply work.
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
---
drivers/thunderbolt/tb.h | 7 +++++++
drivers/thunderbolt/xdomain.c | 6 ++++--
2 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h
index 56eed0bc3c2b..89b5d18f6035 100644
--- a/drivers/thunderbolt/tb.h
+++ b/drivers/thunderbolt/tb.h
@@ -492,6 +492,13 @@ int tb_domain_approve_xdomain_paths(struct tb *tb, struct tb_xdomain *xd);
int tb_domain_disconnect_xdomain_paths(struct tb *tb, struct tb_xdomain *xd);
int tb_domain_disconnect_all_paths(struct tb *tb);
+static inline struct tb *tb_domain_get(struct tb *tb)
+{
+ if (tb)
+ get_device(&tb->dev);
+ return tb;
+}
+
static inline void tb_domain_put(struct tb *tb)
{
put_device(&tb->dev);
diff --git a/drivers/thunderbolt/xdomain.c b/drivers/thunderbolt/xdomain.c
index 7bae92bc486f..44d3b2e486cd 100644
--- a/drivers/thunderbolt/xdomain.c
+++ b/drivers/thunderbolt/xdomain.c
@@ -524,6 +524,8 @@ static void tb_xdp_handle_request(struct work_struct *work)
out:
kfree(xw->pkg);
kfree(xw);
+
+ tb_domain_put(tb);
}
static bool
@@ -542,9 +544,9 @@ tb_xdp_schedule_request(struct tb *tb, const struct tb_xdp_header *hdr,
kfree(xw);
return false;
}
- xw->tb = tb;
+ xw->tb = tb_domain_get(tb);
- queue_work(tb->wq, &xw->work);
+ schedule_work(&xw->work);
return true;
}
--
2.20.1
^ permalink raw reply related
* Re: [PATCH] mtd: nand: Fix build error while CONFIG_MTD_NAND_ECC_SW_BCH is set to module
From: Boris Brezillon @ 2019-04-10 13:39 UTC (permalink / raw)
To: Yue Haibing
Cc: miquel.raynal, richard, computersforpeace, marek.vasut,
paul.burton, bbrezillon, linux-kernel, linux-mtd
In-Reply-To: <20190410130747.35692-1-yuehaibing@huawei.com>
On Wed, 10 Apr 2019 21:07:47 +0800
Yue Haibing <yuehaibing@huawei.com> wrote:
> From: YueHaibing <yuehaibing@huawei.com>
>
> Fix gcc build error while CONFIG_MTD_NAND_ECC_SW_BCH
> is set to module:
>
> drivers/mtd/nand/raw/nand_base.o: In function `nand_cleanup':
> (.text+0xef6): undefined reference to `nand_bch_free'
> drivers/mtd/nand/raw/nand_base.o: In function `nand_scan_tail':
> nand_base.c:(.text+0xa101): undefined reference to `nand_bch_calculate_ecc'
> nand_base.c:(.text+0xa120): undefined reference to `nand_bch_correct_data'
> nand_base.c:(.text+0xa269): undefined reference to `nand_bch_init'
>
> CONFIG_MTD_NAND_ECC_SW_BCH should not be set to M,
> because MTD_RAW_NAND need it while linked.
>
> Reported-by: Hulk Robot <hulkci@huawei.com>
> Fixes: 193bd4002644 ("mtd: nand: add software BCH ECC support"
Nope, it's not this one that introduced the regression.
> Signed-off-by: YueHaibing <yuehaibing@huawei.com>
> ---
> drivers/mtd/nand/raw/Kconfig | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig
> index 615d738..0500c42 100644
> --- a/drivers/mtd/nand/raw/Kconfig
> +++ b/drivers/mtd/nand/raw/Kconfig
> @@ -22,7 +22,7 @@ menuconfig MTD_RAW_NAND
> if MTD_RAW_NAND
>
> config MTD_NAND_ECC_SW_BCH
> - tristate "Support software BCH ECC"
> + bool "Support software BCH ECC"
> select BCH
> default n
> help
Should be fixed with the following diff squashed into:
51ef1d0b2095 ("mtd: nand: Clarify Kconfig entry for software BCH ECC algorithm")
--->8---
diff --git a/include/linux/mtd/nand_bch.h b/include/linux/mtd/nand_bch.h
index b8106651f807..06ce2b655c13 100644
--- a/include/linux/mtd/nand_bch.h
+++ b/include/linux/mtd/nand_bch.h
@@ -15,7 +15,7 @@ struct mtd_info;
struct nand_chip;
struct nand_bch_control;
-#if defined(CONFIG_MTD_NAND_ECC_BCH)
+#if defined(CONFIG_MTD_NAND_ECC_SW_BCH)
static inline int mtd_nand_has_bch(void) { return 1; }
@@ -39,7 +39,7 @@ struct nand_bch_control *nand_bch_init(struct mtd_info *mtd);
*/
void nand_bch_free(struct nand_bch_control *nbc);
-#else /* !CONFIG_MTD_NAND_ECC_BCH */
+#else /* !CONFIG_MTD_NAND_ECC_SW_BCH */
static inline int mtd_nand_has_bch(void) { return 0; }
@@ -64,6 +64,6 @@ static inline struct nand_bch_control *nand_bch_init(struct mtd_info *mtd)
static inline void nand_bch_free(struct nand_bch_control *nbc) {}
-#endif /* CONFIG_MTD_NAND_ECC_BCH */
+#endif /* CONFIG_MTD_NAND_ECC_SW_BCH */
#endif /* __MTD_NAND_BCH_H__ */
^ permalink raw reply related
* Re: [PATCH net 1/7] mlxsw: spectrum_switchdev: Add MDB entries in prepare phase
From: Jiri Pirko @ 2019-04-10 13:39 UTC (permalink / raw)
To: Ido Schimmel
Cc: netdev@vger.kernel.org, davem@davemloft.net, Jiri Pirko, mlxsw
In-Reply-To: <20190410065758.21199-2-idosch@mellanox.com>
Wed, Apr 10, 2019 at 08:58:12AM CEST, idosch@mellanox.com wrote:
>The driver cannot guarantee in the prepare phase that it will be able to
>write an MDB entry to the device. In case the driver returned success
>during the prepare phase, but then failed to add the entry in the commit
>phase, a WARNING [1] will be generated by the switchdev core.
>
>Fix this by doing the work in the prepare phase instead.
>
>[1]
>[ 358.544486] swp12s0: Commit of object (id=2) failed.
>[ 358.550061] WARNING: CPU: 0 PID: 30 at net/switchdev/switchdev.c:281 switchdev_port_obj_add_now+0x9b/0xe0
>[ 358.560754] CPU: 0 PID: 30 Comm: kworker/0:1 Not tainted 5.0.0-custom-13382-gf2449babf221 #1350
>[ 358.570472] Hardware name: Mellanox Technologies Ltd. MSN2100-CB2FO/SA001017, BIOS 5.6.5 06/07/2016
>[ 358.580582] Workqueue: events switchdev_deferred_process_work
>[ 358.587001] RIP: 0010:switchdev_port_obj_add_now+0x9b/0xe0
>...
>[ 358.614109] RSP: 0018:ffffa6b900d6fe18 EFLAGS: 00010286
>[ 358.619943] RAX: 0000000000000000 RBX: ffff8b00797ff000 RCX: 0000000000000000
>[ 358.627912] RDX: ffff8b00b7a1d4c0 RSI: ffff8b00b7a152e8 RDI: ffff8b00b7a152e8
>[ 358.635881] RBP: ffff8b005c3f5bc0 R08: 000000000000022b R09: 0000000000000000
>[ 358.643850] R10: 0000000000000000 R11: ffffa6b900d6fcc8 R12: 0000000000000000
>[ 358.651819] R13: dead000000000100 R14: ffff8b00b65a23c0 R15: 0ffff8b00b7a2200
>[ 358.659790] FS: 0000000000000000(0000) GS:ffff8b00b7a00000(0000) knlGS:0000000000000000
>[ 358.668820] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
>[ 358.675228] CR2: 00007f00aad90de0 CR3: 00000001ca80d000 CR4: 00000000001006f0
>[ 358.683188] Call Trace:
>[ 358.685918] switchdev_port_obj_add_deferred+0x13/0x60
>[ 358.691655] switchdev_deferred_process+0x6b/0xf0
>[ 358.696907] switchdev_deferred_process_work+0xa/0x10
>[ 358.702548] process_one_work+0x1f5/0x3f0
>[ 358.707022] worker_thread+0x28/0x3c0
>[ 358.711099] ? process_one_work+0x3f0/0x3f0
>[ 358.715768] kthread+0x10d/0x130
>[ 358.719369] ? __kthread_create_on_node+0x180/0x180
>[ 358.724815] ret_from_fork+0x35/0x40
>
>Fixes: 3a49b4fde2a1 ("mlxsw: Adding layer 2 multicast support")
>Signed-off-by: Ido Schimmel <idosch@mellanox.com>
>Reported-by: Alex Kushnarov <alexanderk@mellanox.com>
>Tested-by: Alex Kushnarov <alexanderk@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
^ permalink raw reply
* [PATCH v4 31/36] thunderbolt: Make tb_switch_alloc() return ERR_PTR()
From: Mika Westerberg @ 2019-04-10 13:36 UTC (permalink / raw)
To: linux-kernel
Cc: Michael Jamet, Yehezkel Bernat, Andreas Noever, Lukas Wunner,
David S . Miller, Andy Shevchenko, Christian Kellner,
Mario.Limonciello, Joe Perches, Mika Westerberg, netdev
In-Reply-To: <20190410133653.88061-1-mika.westerberg@linux.intel.com>
In order to detect possible connections to other domains we need to be
able to find out why tb_switch_alloc() fails so make it return ERR_PTR()
instead. This allows the caller to differentiate between errors such as
-ENOMEM which comes from the kernel and for instance -EIO which comes
from the hardware when trying to access the possible switch.
Convert all the current call sites to handle this properly.
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
---
drivers/thunderbolt/icm.c | 6 +++---
drivers/thunderbolt/switch.c | 36 ++++++++++++++++++++----------------
drivers/thunderbolt/tb.c | 6 +++---
3 files changed, 26 insertions(+), 22 deletions(-)
diff --git a/drivers/thunderbolt/icm.c b/drivers/thunderbolt/icm.c
index 805958e53c58..d1f6ec89763c 100644
--- a/drivers/thunderbolt/icm.c
+++ b/drivers/thunderbolt/icm.c
@@ -468,7 +468,7 @@ static void add_switch(struct tb_switch *parent_sw, u64 route,
pm_runtime_get_sync(&parent_sw->dev);
sw = tb_switch_alloc(parent_sw->tb, &parent_sw->dev, route);
- if (!sw)
+ if (IS_ERR(sw))
goto out;
sw->uuid = kmemdup(uuid, sizeof(*uuid), GFP_KERNEL);
@@ -1848,8 +1848,8 @@ static int icm_start(struct tb *tb)
tb->root_switch = tb_switch_alloc_safe_mode(tb, &tb->dev, 0);
else
tb->root_switch = tb_switch_alloc(tb, &tb->dev, 0);
- if (!tb->root_switch)
- return -ENODEV;
+ if (IS_ERR(tb->root_switch))
+ return PTR_ERR(tb->root_switch);
/*
* NVM upgrade has not been tested on Apple systems and they
diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c
index ecf53d986a5c..460f2bcad40a 100644
--- a/drivers/thunderbolt/switch.c
+++ b/drivers/thunderbolt/switch.c
@@ -1450,30 +1450,32 @@ static int tb_switch_get_generation(struct tb_switch *sw)
* separately. The returned switch should be released by calling
* tb_switch_put().
*
- * Return: Pointer to the allocated switch or %NULL in case of failure
+ * Return: Pointer to the allocated switch or ERR_PTR() in case of
+ * failure.
*/
struct tb_switch *tb_switch_alloc(struct tb *tb, struct device *parent,
u64 route)
{
struct tb_switch *sw;
int upstream_port;
- int i, cap, depth;
+ int i, ret, depth;
/* Make sure we do not exceed maximum topology limit */
depth = tb_route_length(route);
if (depth > TB_SWITCH_MAX_DEPTH)
- return NULL;
+ return ERR_PTR(-EADDRNOTAVAIL);
upstream_port = tb_cfg_get_upstream_port(tb->ctl, route);
if (upstream_port < 0)
- return NULL;
+ return ERR_PTR(upstream_port);
sw = kzalloc(sizeof(*sw), GFP_KERNEL);
if (!sw)
- return NULL;
+ return ERR_PTR(-ENOMEM);
sw->tb = tb;
- if (tb_cfg_read(tb->ctl, &sw->config, route, 0, TB_CFG_SWITCH, 0, 5))
+ ret = tb_cfg_read(tb->ctl, &sw->config, route, 0, TB_CFG_SWITCH, 0, 5);
+ if (ret)
goto err_free_sw_ports;
tb_dbg(tb, "current switch config:\n");
@@ -1489,8 +1491,10 @@ struct tb_switch *tb_switch_alloc(struct tb *tb, struct device *parent,
/* initialize ports */
sw->ports = kcalloc(sw->config.max_port_number + 1, sizeof(*sw->ports),
GFP_KERNEL);
- if (!sw->ports)
+ if (!sw->ports) {
+ ret = -ENOMEM;
goto err_free_sw_ports;
+ }
for (i = 0; i <= sw->config.max_port_number; i++) {
/* minimum setup for tb_find_cap and tb_drom_read to work */
@@ -1500,16 +1504,16 @@ struct tb_switch *tb_switch_alloc(struct tb *tb, struct device *parent,
sw->generation = tb_switch_get_generation(sw);
- cap = tb_switch_find_vse_cap(sw, TB_VSE_CAP_PLUG_EVENTS);
- if (cap < 0) {
+ ret = tb_switch_find_vse_cap(sw, TB_VSE_CAP_PLUG_EVENTS);
+ if (ret < 0) {
tb_sw_warn(sw, "cannot find TB_VSE_CAP_PLUG_EVENTS aborting\n");
goto err_free_sw_ports;
}
- sw->cap_plug_events = cap;
+ sw->cap_plug_events = ret;
- cap = tb_switch_find_vse_cap(sw, TB_VSE_CAP_LINK_CONTROLLER);
- if (cap > 0)
- sw->cap_lc = cap;
+ ret = tb_switch_find_vse_cap(sw, TB_VSE_CAP_LINK_CONTROLLER);
+ if (ret > 0)
+ sw->cap_lc = ret;
/* Root switch is always authorized */
if (!route)
@@ -1528,7 +1532,7 @@ struct tb_switch *tb_switch_alloc(struct tb *tb, struct device *parent,
kfree(sw->ports);
kfree(sw);
- return NULL;
+ return ERR_PTR(ret);
}
/**
@@ -1543,7 +1547,7 @@ struct tb_switch *tb_switch_alloc(struct tb *tb, struct device *parent,
*
* The returned switch must be released by calling tb_switch_put().
*
- * Return: Pointer to the allocated switch or %NULL in case of failure
+ * Return: Pointer to the allocated switch or ERR_PTR() in case of failure
*/
struct tb_switch *
tb_switch_alloc_safe_mode(struct tb *tb, struct device *parent, u64 route)
@@ -1552,7 +1556,7 @@ tb_switch_alloc_safe_mode(struct tb *tb, struct device *parent, u64 route)
sw = kzalloc(sizeof(*sw), GFP_KERNEL);
if (!sw)
- return NULL;
+ return ERR_PTR(-ENOMEM);
sw->tb = tb;
sw->config.depth = tb_route_length(route);
diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c
index 8a97a4e19638..c5e82c4dcb64 100644
--- a/drivers/thunderbolt/tb.c
+++ b/drivers/thunderbolt/tb.c
@@ -148,7 +148,7 @@ static void tb_scan_port(struct tb_port *port)
}
sw = tb_switch_alloc(port->sw->tb, &port->sw->dev,
tb_downstream_route(port));
- if (!sw)
+ if (IS_ERR(sw))
return;
if (tb_switch_configure(sw)) {
@@ -533,8 +533,8 @@ static int tb_start(struct tb *tb)
int ret;
tb->root_switch = tb_switch_alloc(tb, &tb->dev, 0);
- if (!tb->root_switch)
- return -ENOMEM;
+ if (IS_ERR(tb->root_switch))
+ return PTR_ERR(tb->root_switch);
/*
* ICM firmware upgrade needs running firmware and in native
--
2.20.1
^ permalink raw reply related
* Re: [PATCH] mtd: nand: Fix build error while CONFIG_MTD_NAND_ECC_SW_BCH is set to module
From: Boris Brezillon @ 2019-04-10 13:39 UTC (permalink / raw)
To: Yue Haibing
Cc: bbrezillon, richard, linux-kernel, marek.vasut, paul.burton,
linux-mtd, miquel.raynal, computersforpeace
In-Reply-To: <20190410130747.35692-1-yuehaibing@huawei.com>
On Wed, 10 Apr 2019 21:07:47 +0800
Yue Haibing <yuehaibing@huawei.com> wrote:
> From: YueHaibing <yuehaibing@huawei.com>
>
> Fix gcc build error while CONFIG_MTD_NAND_ECC_SW_BCH
> is set to module:
>
> drivers/mtd/nand/raw/nand_base.o: In function `nand_cleanup':
> (.text+0xef6): undefined reference to `nand_bch_free'
> drivers/mtd/nand/raw/nand_base.o: In function `nand_scan_tail':
> nand_base.c:(.text+0xa101): undefined reference to `nand_bch_calculate_ecc'
> nand_base.c:(.text+0xa120): undefined reference to `nand_bch_correct_data'
> nand_base.c:(.text+0xa269): undefined reference to `nand_bch_init'
>
> CONFIG_MTD_NAND_ECC_SW_BCH should not be set to M,
> because MTD_RAW_NAND need it while linked.
>
> Reported-by: Hulk Robot <hulkci@huawei.com>
> Fixes: 193bd4002644 ("mtd: nand: add software BCH ECC support"
Nope, it's not this one that introduced the regression.
> Signed-off-by: YueHaibing <yuehaibing@huawei.com>
> ---
> drivers/mtd/nand/raw/Kconfig | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig
> index 615d738..0500c42 100644
> --- a/drivers/mtd/nand/raw/Kconfig
> +++ b/drivers/mtd/nand/raw/Kconfig
> @@ -22,7 +22,7 @@ menuconfig MTD_RAW_NAND
> if MTD_RAW_NAND
>
> config MTD_NAND_ECC_SW_BCH
> - tristate "Support software BCH ECC"
> + bool "Support software BCH ECC"
> select BCH
> default n
> help
Should be fixed with the following diff squashed into:
51ef1d0b2095 ("mtd: nand: Clarify Kconfig entry for software BCH ECC algorithm")
--->8---
diff --git a/include/linux/mtd/nand_bch.h b/include/linux/mtd/nand_bch.h
index b8106651f807..06ce2b655c13 100644
--- a/include/linux/mtd/nand_bch.h
+++ b/include/linux/mtd/nand_bch.h
@@ -15,7 +15,7 @@ struct mtd_info;
struct nand_chip;
struct nand_bch_control;
-#if defined(CONFIG_MTD_NAND_ECC_BCH)
+#if defined(CONFIG_MTD_NAND_ECC_SW_BCH)
static inline int mtd_nand_has_bch(void) { return 1; }
@@ -39,7 +39,7 @@ struct nand_bch_control *nand_bch_init(struct mtd_info *mtd);
*/
void nand_bch_free(struct nand_bch_control *nbc);
-#else /* !CONFIG_MTD_NAND_ECC_BCH */
+#else /* !CONFIG_MTD_NAND_ECC_SW_BCH */
static inline int mtd_nand_has_bch(void) { return 0; }
@@ -64,6 +64,6 @@ static inline struct nand_bch_control *nand_bch_init(struct mtd_info *mtd)
static inline void nand_bch_free(struct nand_bch_control *nbc) {}
-#endif /* CONFIG_MTD_NAND_ECC_BCH */
+#endif /* CONFIG_MTD_NAND_ECC_SW_BCH */
#endif /* __MTD_NAND_BCH_H__ */
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
^ permalink raw reply related
* [PATCH v4 29/36] thunderbolt: Add XDomain UUID exchange support
From: Mika Westerberg @ 2019-04-10 13:36 UTC (permalink / raw)
To: linux-kernel
Cc: Michael Jamet, Yehezkel Bernat, Andreas Noever, Lukas Wunner,
David S . Miller, Andy Shevchenko, Christian Kellner,
Mario.Limonciello, Joe Perches, Mika Westerberg, netdev
In-Reply-To: <20190410133653.88061-1-mika.westerberg@linux.intel.com>
Currently ICM has been handling XDomain UUID exchange so there was no
need to have it in the driver yet. However, since now we are going to
add the same capabilities to the software connection manager it needs to
be handled properly.
For this reason modify the driver XDomain protocol handling so that if
the remote domain UUID is not filled in the core will query it first and
only then start the normal property exchange flow.
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
---
drivers/thunderbolt/tb_msgs.h | 11 +++
drivers/thunderbolt/xdomain.c | 136 +++++++++++++++++++++++++++++++---
include/linux/thunderbolt.h | 8 ++
3 files changed, 145 insertions(+), 10 deletions(-)
diff --git a/drivers/thunderbolt/tb_msgs.h b/drivers/thunderbolt/tb_msgs.h
index 02c84aa3d018..afbe1d29bb03 100644
--- a/drivers/thunderbolt/tb_msgs.h
+++ b/drivers/thunderbolt/tb_msgs.h
@@ -492,6 +492,17 @@ struct tb_xdp_header {
u32 type;
};
+struct tb_xdp_uuid {
+ struct tb_xdp_header hdr;
+};
+
+struct tb_xdp_uuid_response {
+ struct tb_xdp_header hdr;
+ uuid_t src_uuid;
+ u32 src_route_hi;
+ u32 src_route_lo;
+};
+
struct tb_xdp_properties {
struct tb_xdp_header hdr;
uuid_t src_uuid;
diff --git a/drivers/thunderbolt/xdomain.c b/drivers/thunderbolt/xdomain.c
index 44d3b2e486cd..5118d46702d5 100644
--- a/drivers/thunderbolt/xdomain.c
+++ b/drivers/thunderbolt/xdomain.c
@@ -18,6 +18,7 @@
#include "tb.h"
#define XDOMAIN_DEFAULT_TIMEOUT 5000 /* ms */
+#define XDOMAIN_UUID_RETRIES 10
#define XDOMAIN_PROPERTIES_RETRIES 60
#define XDOMAIN_PROPERTIES_CHANGED_RETRIES 10
@@ -222,6 +223,50 @@ static int tb_xdp_handle_error(const struct tb_xdp_header *hdr)
return 0;
}
+static int tb_xdp_uuid_request(struct tb_ctl *ctl, u64 route, int retry,
+ uuid_t *uuid)
+{
+ struct tb_xdp_uuid_response res;
+ struct tb_xdp_uuid req;
+ int ret;
+
+ memset(&req, 0, sizeof(req));
+ tb_xdp_fill_header(&req.hdr, route, retry % 4, UUID_REQUEST,
+ sizeof(req));
+
+ memset(&res, 0, sizeof(res));
+ ret = __tb_xdomain_request(ctl, &req, sizeof(req),
+ TB_CFG_PKG_XDOMAIN_REQ, &res, sizeof(res),
+ TB_CFG_PKG_XDOMAIN_RESP,
+ XDOMAIN_DEFAULT_TIMEOUT);
+ if (ret)
+ return ret;
+
+ ret = tb_xdp_handle_error(&res.hdr);
+ if (ret)
+ return ret;
+
+ uuid_copy(uuid, &res.src_uuid);
+ return 0;
+}
+
+static int tb_xdp_uuid_response(struct tb_ctl *ctl, u64 route, u8 sequence,
+ const uuid_t *uuid)
+{
+ struct tb_xdp_uuid_response res;
+
+ memset(&res, 0, sizeof(res));
+ tb_xdp_fill_header(&res.hdr, route, sequence, UUID_RESPONSE,
+ sizeof(res));
+
+ uuid_copy(&res.src_uuid, uuid);
+ res.src_route_hi = upper_32_bits(route);
+ res.src_route_lo = lower_32_bits(route);
+
+ return __tb_xdomain_response(ctl, &res, sizeof(res),
+ TB_CFG_PKG_XDOMAIN_RESP);
+}
+
static int tb_xdp_error_response(struct tb_ctl *ctl, u64 route, u8 sequence,
enum tb_xdp_error error)
{
@@ -512,7 +557,14 @@ static void tb_xdp_handle_request(struct work_struct *work)
break;
}
+ case UUID_REQUEST_OLD:
+ case UUID_REQUEST:
+ ret = tb_xdp_uuid_response(ctl, route, sequence, uuid);
+ break;
+
default:
+ tb_xdp_error_response(ctl, route, sequence,
+ ERROR_NOT_SUPPORTED);
break;
}
@@ -839,6 +891,55 @@ static void tb_xdomain_restore_paths(struct tb_xdomain *xd)
}
}
+static void tb_xdomain_get_uuid(struct work_struct *work)
+{
+ struct tb_xdomain *xd = container_of(work, typeof(*xd),
+ get_uuid_work.work);
+ struct tb *tb = xd->tb;
+ uuid_t uuid;
+ int ret;
+
+ ret = tb_xdp_uuid_request(tb->ctl, xd->route, xd->uuid_retries, &uuid);
+ if (ret < 0) {
+ if (xd->uuid_retries-- > 0) {
+ queue_delayed_work(xd->tb->wq, &xd->get_uuid_work,
+ msecs_to_jiffies(100));
+ } else {
+ dev_dbg(&xd->dev, "failed to read remote UUID\n");
+ }
+ return;
+ }
+
+ if (uuid_equal(&uuid, xd->local_uuid)) {
+ dev_dbg(&xd->dev, "intra-domain loop detected\n");
+ return;
+ }
+
+ /*
+ * If the UUID is different, there is another domain connected
+ * so mark this one unplugged and wait for the connection
+ * manager to replace it.
+ */
+ if (xd->remote_uuid && !uuid_equal(&uuid, xd->remote_uuid)) {
+ dev_dbg(&xd->dev, "remote UUID is different, unplugging\n");
+ xd->is_unplugged = true;
+ return;
+ }
+
+ /* First time fill in the missing UUID */
+ if (!xd->remote_uuid) {
+ xd->remote_uuid = kmemdup(&uuid, sizeof(uuid_t), GFP_KERNEL);
+ if (!xd->remote_uuid)
+ return;
+ }
+
+ /* Now we can start the normal properties exchange */
+ queue_delayed_work(xd->tb->wq, &xd->properties_changed_work,
+ msecs_to_jiffies(100));
+ queue_delayed_work(xd->tb->wq, &xd->get_properties_work,
+ msecs_to_jiffies(1000));
+}
+
static void tb_xdomain_get_properties(struct work_struct *work)
{
struct tb_xdomain *xd = container_of(work, typeof(*xd),
@@ -1045,21 +1146,29 @@ static void tb_xdomain_release(struct device *dev)
static void start_handshake(struct tb_xdomain *xd)
{
+ xd->uuid_retries = XDOMAIN_UUID_RETRIES;
xd->properties_retries = XDOMAIN_PROPERTIES_RETRIES;
xd->properties_changed_retries = XDOMAIN_PROPERTIES_CHANGED_RETRIES;
- /* Start exchanging properties with the other host */
- queue_delayed_work(xd->tb->wq, &xd->properties_changed_work,
- msecs_to_jiffies(100));
- queue_delayed_work(xd->tb->wq, &xd->get_properties_work,
- msecs_to_jiffies(1000));
+ if (xd->needs_uuid) {
+ queue_delayed_work(xd->tb->wq, &xd->get_uuid_work,
+ msecs_to_jiffies(100));
+ } else {
+ /* Start exchanging properties with the other host */
+ queue_delayed_work(xd->tb->wq, &xd->properties_changed_work,
+ msecs_to_jiffies(100));
+ queue_delayed_work(xd->tb->wq, &xd->get_properties_work,
+ msecs_to_jiffies(1000));
+ }
}
static void stop_handshake(struct tb_xdomain *xd)
{
+ xd->uuid_retries = 0;
xd->properties_retries = 0;
xd->properties_changed_retries = 0;
+ cancel_delayed_work_sync(&xd->get_uuid_work);
cancel_delayed_work_sync(&xd->get_properties_work);
cancel_delayed_work_sync(&xd->properties_changed_work);
}
@@ -1102,7 +1211,7 @@ EXPORT_SYMBOL_GPL(tb_xdomain_type);
* other domain is reached).
* @route: Route string used to reach the other domain
* @local_uuid: Our local domain UUID
- * @remote_uuid: UUID of the other domain
+ * @remote_uuid: UUID of the other domain (optional)
*
* Allocates new XDomain structure and returns pointer to that. The
* object must be released by calling tb_xdomain_put().
@@ -1121,6 +1230,7 @@ struct tb_xdomain *tb_xdomain_alloc(struct tb *tb, struct device *parent,
xd->route = route;
ida_init(&xd->service_ids);
mutex_init(&xd->lock);
+ INIT_DELAYED_WORK(&xd->get_uuid_work, tb_xdomain_get_uuid);
INIT_DELAYED_WORK(&xd->get_properties_work, tb_xdomain_get_properties);
INIT_DELAYED_WORK(&xd->properties_changed_work,
tb_xdomain_properties_changed);
@@ -1129,9 +1239,14 @@ struct tb_xdomain *tb_xdomain_alloc(struct tb *tb, struct device *parent,
if (!xd->local_uuid)
goto err_free;
- xd->remote_uuid = kmemdup(remote_uuid, sizeof(uuid_t), GFP_KERNEL);
- if (!xd->remote_uuid)
- goto err_free_local_uuid;
+ if (remote_uuid) {
+ xd->remote_uuid = kmemdup(remote_uuid, sizeof(uuid_t),
+ GFP_KERNEL);
+ if (!xd->remote_uuid)
+ goto err_free_local_uuid;
+ } else {
+ xd->needs_uuid = true;
+ }
device_initialize(&xd->dev);
xd->dev.parent = get_device(parent);
@@ -1299,7 +1414,8 @@ static struct tb_xdomain *switch_find_xdomain(struct tb_switch *sw,
xd = port->xdomain;
if (lookup->uuid) {
- if (uuid_equal(xd->remote_uuid, lookup->uuid))
+ if (xd->remote_uuid &&
+ uuid_equal(xd->remote_uuid, lookup->uuid))
return xd;
} else if (lookup->link &&
lookup->link == xd->link &&
diff --git a/include/linux/thunderbolt.h b/include/linux/thunderbolt.h
index bf6ec83e60ee..2d7e012db03f 100644
--- a/include/linux/thunderbolt.h
+++ b/include/linux/thunderbolt.h
@@ -181,6 +181,8 @@ void tb_unregister_property_dir(const char *key, struct tb_property_dir *dir);
* @device_name: Name of the device (or %NULL if not known)
* @is_unplugged: The XDomain is unplugged
* @resume: The XDomain is being resumed
+ * @needs_uuid: If the XDomain does not have @remote_uuid it will be
+ * queried first
* @transmit_path: HopID which the remote end expects us to transmit
* @transmit_ring: Local ring (hop) where outgoing packets are pushed
* @receive_path: HopID which we expect the remote end to transmit
@@ -189,6 +191,9 @@ void tb_unregister_property_dir(const char *key, struct tb_property_dir *dir);
* @properties: Properties exported by the remote domain
* @property_block_gen: Generation of @properties
* @properties_lock: Lock protecting @properties.
+ * @get_uuid_work: Work used to retrieve @remote_uuid
+ * @uuid_retries: Number of times left @remote_uuid is requested before
+ * giving up
* @get_properties_work: Work used to get remote domain properties
* @properties_retries: Number of times left to read properties
* @properties_changed_work: Work used to notify the remote domain that
@@ -220,6 +225,7 @@ struct tb_xdomain {
const char *device_name;
bool is_unplugged;
bool resume;
+ bool needs_uuid;
u16 transmit_path;
u16 transmit_ring;
u16 receive_path;
@@ -227,6 +233,8 @@ struct tb_xdomain {
struct ida service_ids;
struct tb_property_dir *properties;
u32 property_block_gen;
+ struct delayed_work get_uuid_work;
+ int uuid_retries;
struct delayed_work get_properties_work;
int properties_retries;
struct delayed_work properties_changed_work;
--
2.20.1
^ permalink raw reply related
* [PATCH v2 5/6] dt-bindings: leds: Add LED bindings for the LM36274
From: Dan Murphy @ 2019-04-10 13:38 UTC (permalink / raw)
To: robh+dt, jacek.anaszewski, pavel, lee.jones, lgirdwood, broonie
Cc: devicetree, linux-kernel, linux-leds, Dan Murphy
In-Reply-To: <20190410133833.28859-1-dmurphy@ti.com>
Add the LM36274 LED specific bindings.
Signed-off-by: Dan Murphy <dmurphy@ti.com>
---
v2 - Changed 29-V to 29V - https://lore.kernel.org/patchwork/patch/1058779/
.../devicetree/bindings/leds/leds-lm36274.txt | 82 +++++++++++++++++++
1 file changed, 82 insertions(+)
create mode 100644 Documentation/devicetree/bindings/leds/leds-lm36274.txt
diff --git a/Documentation/devicetree/bindings/leds/leds-lm36274.txt b/Documentation/devicetree/bindings/leds/leds-lm36274.txt
new file mode 100644
index 000000000000..329393700191
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/leds-lm36274.txt
@@ -0,0 +1,82 @@
+* Texas Instruments LM36274 4-Channel LCD Backlight Driver w/Integrated Bias
+
+The LM36274 is an integrated four-channel WLED driver and LCD bias supply.
+The backlight boost provides the power to bias four parallel LED strings with
+up to 29V total output voltage. The 11-bit LED current is programmable via
+the I2C bus and/or controlled via a logic level PWM input from 60 μA to 30 mA.
+
+Parent device properties are documented in ../mfd/ti_lmu.txt
+Regulator properties are documented in ../regulator/lm363x-regulator.txt
+
+Required backlight properties:
+ - compatible:
+ "ti,lm36274-backlight"
+ - reg : 0
+ - #address-cells : 1
+ - #size-cells : 0
+ - led-sources : Indicates which LED strings will be enabled.
+ Values from 0-3, sources is 0 based so strings will be
+ source value + 1.
+
+Optional backlight properties:
+ - label : see Documentation/devicetree/bindings/leds/common.txt
+ - linux,default-trigger :
+ see Documentation/devicetree/bindings/leds/common.txt
+
+Example:
+
+HVLED string 1 and 3 are controlled by control bank A and HVLED 2 string is
+controlled by control bank B.
+
+lm36274@11 {
+ compatible = "ti,lm36274";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x11>;
+
+ enable-gpios = <&gpio1 28 GPIO_ACTIVE_HIGH>;
+
+ regulators {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "ti,lm363x-regulator";
+
+ enable-gpios = <&pioC 0 GPIO_ACTIVE_HIGH>,
+ <&pioC 1 GPIO_ACTIVE_HIGH>;
+
+ vboost {
+ regulator-name = "lcd_boost";
+ regulator-min-microvolt = <4000000>;
+ regulator-max-microvolt = <7150000>;
+ regulator-always-on;
+ };
+
+ vpos {
+ regulator-name = "lcd_vpos";
+ regulator-min-microvolt = <4000000>;
+ regulator-max-microvolt = <6500000>;
+ };
+
+ vneg {
+ regulator-name = "lcd_vneg";
+ regulator-min-microvolt = <4000000>;
+ regulator-max-microvolt = <6500000>;
+ };
+ };
+
+ backlight {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "ti,lm36274-backlight";
+
+ led@0 {
+ reg = <0>;
+ led-sources = <0 2>;
+ label = "white:backlight_cluster";
+ linux,default-trigger = "backlight";
+ };
+ };
+};
+
+For more product information please see the link below:
+http://www.ti.com/lit/ds/symlink/lm36274.pdf
--
2.21.0.5.gaeb582a983
^ permalink raw reply related
* [PATCH v2 6/6] leds: lm36274: Introduce the TI LM36274 LED driver
From: Dan Murphy @ 2019-04-10 13:38 UTC (permalink / raw)
To: robh+dt, jacek.anaszewski, pavel, lee.jones, lgirdwood, broonie
Cc: devicetree, linux-kernel, linux-leds, Dan Murphy
In-Reply-To: <20190410133833.28859-1-dmurphy@ti.com>
Introduce the LM36274 LED driver. This driver uses the ti-lmu
MFD driver to probe this LED driver. The driver configures only the
LED registers and enables the outputs according to the config file.
The driver utilizes the ti-lmu-led-common framework to set the brightness
bits.
Signed-off-by: Dan Murphy <dmurphy@ti.com>
---
v2 - No changes - https://lore.kernel.org/patchwork/patch/1058778/
drivers/leds/Kconfig | 9 +-
drivers/leds/Makefile | 1 +
drivers/leds/leds-lm36274.c | 174 ++++++++++++++++++++++++++++++++++++
3 files changed, 183 insertions(+), 1 deletion(-)
create mode 100644 drivers/leds/leds-lm36274.c
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 2d1576f4d5d6..c0bf59544886 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -783,12 +783,19 @@ config LEDS_LM3697
Say Y to enable the LM3697 LED driver for TI LMU devices.
This supports the LED device LM3697.
+config LEDS_LM36274
+ tristate "LED driver for LM36274"
+ depends on LEDS_TI_LMU_COMMON
+ help
+ Say Y to enable the LM36274 LED driver for TI LMU devices.
+ This supports the LED device LM36274.
+
config LEDS_TI_LMU_COMMON
tristate "LED driver for TI LMU"
help
Say Y to enable the LED driver for TI LMU devices.
This supports common features between the TI LM3532, LM3631, LM3632,
- LM3633, LM3695 and LM3697.
+ LM3633, LM3695, LM3697 and LM36274
comment "LED Triggers"
source "drivers/leds/trigger/Kconfig"
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 2eb0225d8dc6..7ff67215b38c 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -81,6 +81,7 @@ obj-$(CONFIG_LEDS_LM3692X) += leds-lm3692x.o
obj-$(CONFIG_LEDS_SC27XX_BLTC) += leds-sc27xx-bltc.o
obj-$(CONFIG_LEDS_LM3601X) += leds-lm3601x.o
obj-$(CONFIG_LEDS_LM3697) += leds-lm3697.o
+obj-$(CONFIG_LEDS_LM36274) += leds-lm36274.o
obj-$(CONFIG_LEDS_TI_LMU_COMMON) += ti-lmu-led-common.o
# LED SPI Drivers
diff --git a/drivers/leds/leds-lm36274.c b/drivers/leds/leds-lm36274.c
new file mode 100644
index 000000000000..6a419c47c47f
--- /dev/null
+++ b/drivers/leds/leds-lm36274.c
@@ -0,0 +1,174 @@
+// SPDX-License-Identifier: GPL-2.0
+// TI LM36274 LED chip family driver
+// Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
+
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/leds.h>
+#include <linux/ti-lmu-led-common.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+#include <linux/mfd/ti-lmu.h>
+#include <linux/mfd/ti-lmu-register.h>
+
+#include <uapi/linux/uleds.h>
+
+#define LM36274_MAX_STRINGS 4
+#define LM36274_BL_EN BIT(4)
+
+/**
+ * struct lm36274
+ * @pdev: platform device
+ * @led_dev: led class device
+ * @lmu_data: Register and setting values for common code
+ * @regmap: Devices register map
+ * @dev: Pointer to the devices device struct
+ * @led_sources - The LED strings supported in this array
+ * @num_leds - Number of LED strings are supported in this array
+ */
+struct lm36274 {
+ struct platform_device *pdev;
+ struct led_classdev led_dev;
+ struct ti_lmu_bank lmu_data;
+ struct regmap *regmap;
+ struct device *dev;
+
+ u32 led_sources[LM36274_MAX_STRINGS];
+ int num_leds;
+};
+
+static int lm36274_brightness_set(struct led_classdev *led_cdev,
+ enum led_brightness brt_val)
+{
+ struct lm36274 *led = container_of(led_cdev, struct lm36274, led_dev);
+
+ return ti_lmu_common_set_brightness(&led->lmu_data, brt_val);
+}
+
+static int lm36274_init(struct lm36274 *lm36274_data)
+{
+ int enable_val = 0;
+ int i;
+
+ for (i = 0; i < lm36274_data->num_leds; i++)
+ enable_val |= (1 << lm36274_data->led_sources[i]);
+
+ if (!enable_val) {
+ dev_err(lm36274_data->dev, "No LEDs were enabled\n");
+ return -EINVAL;
+ }
+
+ enable_val |= LM36274_BL_EN;
+
+ return regmap_write(lm36274_data->regmap, LM36274_REG_BL_EN,
+ enable_val);
+}
+
+static int lm36274_parse_dt(struct lm36274 *lm36274_data)
+{
+ struct fwnode_handle *child = NULL;
+ char label[LED_MAX_NAME_SIZE];
+ struct device *dev = &lm36274_data->pdev->dev;
+ const char *name;
+ int child_cnt;
+ int ret = -EINVAL;
+
+ /* There should only be 1 node */
+ child_cnt = device_get_child_node_count(dev);
+ if (child_cnt != 1)
+ return ret;
+
+ device_for_each_child_node(dev, child) {
+ ret = fwnode_property_read_string(child, "label", &name);
+ if (ret)
+ snprintf(label, sizeof(label),
+ "%s::", lm36274_data->pdev->name);
+ else
+ snprintf(label, sizeof(label),
+ "%s:%s", lm36274_data->pdev->name, name);
+
+ lm36274_data->num_leds = fwnode_property_read_u32_array(child,
+ "led-sources",
+ NULL, 0);
+ if (lm36274_data->num_leds <= 0)
+ return -ENODEV;
+
+ ret = fwnode_property_read_u32_array(child, "led-sources",
+ lm36274_data->led_sources,
+ lm36274_data->num_leds);
+ if (ret) {
+ dev_err(dev, "led-sources property missing\n");
+ return -EINVAL;
+ }
+
+ fwnode_property_read_string(child, "linux,default-trigger",
+ &lm36274_data->led_dev.default_trigger);
+
+ }
+
+ lm36274_data->lmu_data.regmap = lm36274_data->regmap;
+ lm36274_data->lmu_data.max_brightness = MAX_BRIGHTNESS_11BIT;
+ lm36274_data->lmu_data.msb_brightness_reg = LM36274_REG_BRT_MSB;
+ lm36274_data->lmu_data.lsb_brightness_reg = LM36274_REG_BRT_LSB;
+
+ lm36274_data->led_dev.name = label;
+ lm36274_data->led_dev.max_brightness = MAX_BRIGHTNESS_11BIT;
+ lm36274_data->led_dev.brightness_set_blocking = lm36274_brightness_set;
+
+ return ret;
+}
+
+static int lm36274_probe(struct platform_device *pdev)
+{
+ struct ti_lmu *lmu = dev_get_drvdata(pdev->dev.parent);
+ struct lm36274 *lm36274_data;
+ int ret;
+
+ lm36274_data = devm_kzalloc(&pdev->dev, sizeof(*lm36274_data),
+ GFP_KERNEL);
+ if (!lm36274_data) {
+ ret = -ENOMEM;
+ return ret;
+ }
+
+ lm36274_data->pdev = pdev;
+ lm36274_data->dev = lmu->dev;
+ lm36274_data->regmap = lmu->regmap;
+ dev_set_drvdata(&pdev->dev, lm36274_data);
+
+ ret = lm36274_parse_dt(lm36274_data);
+ if (ret) {
+ dev_err(lm36274_data->dev, "Failed to parse DT node\n");
+ return ret;
+ }
+
+ ret = lm36274_init(lm36274_data);
+ if (ret) {
+ dev_err(lm36274_data->dev, "Failed to init the device\n");
+ return ret;
+ }
+
+ return devm_led_classdev_register(lm36274_data->dev,
+ &lm36274_data->led_dev);
+}
+
+static const struct of_device_id of_lm36274_leds_match[] = {
+ { .compatible = "ti,lm36274-backlight", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, of_lm36274_leds_match);
+
+static struct platform_driver lm36274_driver = {
+ .probe = lm36274_probe,
+ .driver = {
+ .name = "lm36274-leds",
+ },
+};
+module_platform_driver(lm36274_driver)
+
+MODULE_DESCRIPTION("Texas Instruments LM36274 LED driver");
+MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
+MODULE_LICENSE("GPL v2");
--
2.21.0.5.gaeb582a983
^ permalink raw reply related
* Re: [PATCH 6/7] drm/i915: Use Engine1 instance for gen11 pm interrupts
From: Chris Wilson @ 2019-04-10 13:39 UTC (permalink / raw)
To: Mika Kuoppala, intel-gfx
In-Reply-To: <20190410105923.18546-6-mika.kuoppala@linux.intel.com>
Quoting Mika Kuoppala (2019-04-10 11:59:22)
> With gen11 the interrupt registers are shared between 2 engines,
> with Engine1 instance being upper word and Engine0 instance being
> lower. Annoyingly gen11 selected the pm interrupts to be in the
> Engine1 instance.
>
> Rectify the situation by shifting the access accordingly,
> based on gen.
>
> v2: comments, warn on overzealous rps_events
>
> Bugzilla: https://bugzilla.freedesktop.org/show_bug.cgi?id=108059
> Testcase: igt/i915_pm_rps@min-max-config-loaded
> Cc: Chris Wilson <chris@chris-wilson.co.uk>
> Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
Acked-by: Chris Wilson <chris@chris-wilson.co.uk>
-Chris
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply
* [PATCH v2 2/6] dt-bindings: mfd: Add lm36274 bindings to ti-lmu
From: Dan Murphy @ 2019-04-10 13:38 UTC (permalink / raw)
To: robh+dt, jacek.anaszewski, pavel, lee.jones, lgirdwood, broonie
Cc: devicetree, linux-kernel, linux-leds, Dan Murphy
In-Reply-To: <20190410133833.28859-1-dmurphy@ti.com>
Add the LM36274 backlight driver with regulator support.
This is a multi-function device for backlight applications.
Backlight properties will be documented in it's a supplemental
bindings document.
Regulator support is documented in the regulator/lm363x-regulator.txt
http://www.ti.com/lit/ds/symlink/lm36274.pdf
Signed-off-by: Dan Murphy <dmurphy@ti.com>
---
v2 - No changes - https://lore.kernel.org/patchwork/patch/1058776/
.../devicetree/bindings/mfd/ti-lmu.txt | 54 +++++++++++++++++++
1 file changed, 54 insertions(+)
diff --git a/Documentation/devicetree/bindings/mfd/ti-lmu.txt b/Documentation/devicetree/bindings/mfd/ti-lmu.txt
index a948a8f41b2c..6ada671c1038 100644
--- a/Documentation/devicetree/bindings/mfd/ti-lmu.txt
+++ b/Documentation/devicetree/bindings/mfd/ti-lmu.txt
@@ -8,6 +8,7 @@ TI LMU driver supports lighting devices below.
LM3632 Backlight and regulator
LM3633 Backlight, LED and fault monitor
LM3695 Backlight
+ LM36274 Backlight and regulator
Required properties:
- compatible: Should be one of:
@@ -15,11 +16,13 @@ Required properties:
"ti,lm3632"
"ti,lm3633"
"ti,lm3695"
+ "ti,lm36274"
- reg: I2C slave address.
0x11 for LM3632
0x29 for LM3631
0x36 for LM3633
0x63 for LM3695
+ 0x11 for LM36274
Optional property:
- enable-gpios: A GPIO specifier for hardware enable pin.
@@ -50,12 +53,14 @@ Optional nodes:
- compatible: Should be one of:
"ti,lm3633-fault-monitor"
- leds: LED properties for LM3633. Please refer to [2].
+ LED properties for LM36274. Please refer to [4].
- regulators: Regulator properties for LM3631 and LM3632.
Please refer to [3].
[1] ../leds/backlight/ti-lmu-backlight.txt
[2] ../leds/leds-lm3633.txt
[3] ../regulator/lm363x-regulator.txt
+[4] ../leds/leds-lm36274.txt
lm3631@29 {
compatible = "ti,lm3631";
@@ -213,3 +218,52 @@ lm3695@63 {
};
};
};
+
+lm36274@11 {
+ compatible = "ti,lm36274";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x11>;
+
+ enable-gpios = <&pioC 2 GPIO_ACTIVE_HIGH>;
+ regulators {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "ti,lm363x-regulator";
+
+ enable-gpios = <&pioC 0 GPIO_ACTIVE_HIGH>,
+ <&pioC 1 GPIO_ACTIVE_HIGH>;
+
+ vboost {
+ regulator-name = "lcd_boost";
+ regulator-min-microvolt = <4000000>;
+ regulator-max-microvolt = <7150000>;
+ regulator-always-on;
+ };
+
+ vpos {
+ regulator-name = "lcd_vpos";
+ regulator-min-microvolt = <4000000>;
+ regulator-max-microvolt = <6500000>;
+ };
+
+ vneg {
+ regulator-name = "lcd_vneg";
+ regulator-min-microvolt = <4000000>;
+ regulator-max-microvolt = <6500000>;
+ };
+ };
+
+ backlight {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "ti,lm36274-backlight";
+
+ led@0 {
+ reg = <0>;
+ led-sources = <0 2>;
+ label = "white:backlight_cluster";
+ linux,default-trigger = "backlight";
+ };
+ };
+};
--
2.21.0.5.gaeb582a983
^ permalink raw reply related
* [PATCH v2 3/6] mfd: ti-lmu: Add LM36274 support to the ti-lmu
From: Dan Murphy @ 2019-04-10 13:38 UTC (permalink / raw)
To: robh+dt, jacek.anaszewski, pavel, lee.jones, lgirdwood, broonie
Cc: devicetree, linux-kernel, linux-leds, Dan Murphy
In-Reply-To: <20190410133833.28859-1-dmurphy@ti.com>
Add the LM36274 register support to the ti-lmu MFD driver.
Signed-off-by: Dan Murphy <dmurphy@ti.com>
---
v2 - No changes - https://lore.kernel.org/patchwork/patch/1058780/
drivers/mfd/Kconfig | 5 ++---
drivers/mfd/ti-lmu.c | 14 ++++++++++++++
include/linux/mfd/ti-lmu-register.h | 23 +++++++++++++++++++++++
include/linux/mfd/ti-lmu.h | 4 ++++
4 files changed, 43 insertions(+), 3 deletions(-)
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index fcae244229b3..5606411038bb 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -1311,9 +1311,8 @@ config MFD_TI_LMU
select REGMAP_I2C
help
Say yes here to enable support for TI LMU chips.
-
- TI LMU MFD supports LM3532, LM3631, LM3632, LM3633, and LM3695.
- It consists of backlight, LED and regulator driver.
+ TI LMU MFD supports LM3532, LM3631, LM3632, LM3633, LM3695 and
+ LM36274. It consists of backlight, LED and regulator driver.
It provides consistent device controls for lighting functions.
config MFD_OMAP_USB_HOST
diff --git a/drivers/mfd/ti-lmu.c b/drivers/mfd/ti-lmu.c
index 89b1c5b584af..691ab9dd6236 100644
--- a/drivers/mfd/ti-lmu.c
+++ b/drivers/mfd/ti-lmu.c
@@ -111,6 +111,17 @@ static const struct mfd_cell lm3695_devices[] = {
},
};
+static const struct mfd_cell lm36274_devices[] = {
+ LM363X_REGULATOR(LM36274_BOOST),
+ LM363X_REGULATOR(LM36274_LDO_POS),
+ LM363X_REGULATOR(LM36274_LDO_NEG),
+ {
+ .name = "lm36274-leds",
+ .id = LM36274,
+ .of_compatible = "ti,lm36274-backlight",
+ },
+};
+
#define TI_LMU_DATA(chip, max_reg) \
static const struct ti_lmu_data chip##_data = \
{ \
@@ -123,6 +134,7 @@ TI_LMU_DATA(lm3631, LM3631_MAX_REG);
TI_LMU_DATA(lm3632, LM3632_MAX_REG);
TI_LMU_DATA(lm3633, LM3633_MAX_REG);
TI_LMU_DATA(lm3695, LM3695_MAX_REG);
+TI_LMU_DATA(lm36274, LM36274_MAX_REG);
static int ti_lmu_probe(struct i2c_client *cl, const struct i2c_device_id *id)
{
@@ -191,6 +203,7 @@ static const struct of_device_id ti_lmu_of_match[] = {
{ .compatible = "ti,lm3632", .data = &lm3632_data },
{ .compatible = "ti,lm3633", .data = &lm3633_data },
{ .compatible = "ti,lm3695", .data = &lm3695_data },
+ { .compatible = "ti,lm36274", .data = &lm36274_data },
{ }
};
MODULE_DEVICE_TABLE(of, ti_lmu_of_match);
@@ -200,6 +213,7 @@ static const struct i2c_device_id ti_lmu_ids[] = {
{ "lm3632", LM3632 },
{ "lm3633", LM3633 },
{ "lm3695", LM3695 },
+ { "lm36274", LM36274 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ti_lmu_ids);
diff --git a/include/linux/mfd/ti-lmu-register.h b/include/linux/mfd/ti-lmu-register.h
index 76998b01764b..076d8dea38fd 100644
--- a/include/linux/mfd/ti-lmu-register.h
+++ b/include/linux/mfd/ti-lmu-register.h
@@ -189,4 +189,27 @@
#define LM3695_REG_BRT_MSB 0x14
#define LM3695_MAX_REG 0x14
+
+/* LM36274 */
+#define LM36274_REG_REV 0x01
+#define LM36274_REG_BL_CFG_1 0x02
+#define LM36274_REG_BL_CFG_2 0x03
+#define LM36274_REG_BRT_LSB 0x04
+#define LM36274_REG_BRT_MSB 0x05
+#define LM36274_REG_BL_EN 0x08
+
+#define LM36274_REG_BIAS_CONFIG_1 0x09
+#define LM36274_EXT_EN_MASK BIT(0)
+#define LM36274_EN_VNEG_MASK BIT(1)
+#define LM36274_EN_VPOS_MASK BIT(2)
+
+#define LM36274_REG_BIAS_CONFIG_2 0x0a
+#define LM36274_REG_BIAS_CONFIG_3 0x0b
+#define LM36274_REG_VOUT_BOOST 0x0c
+#define LM36274_REG_VOUT_POS 0x0d
+#define LM36274_REG_VOUT_NEG 0x0e
+#define LM36274_VOUT_MASK 0x3F
+
+#define LM36274_MAX_REG 0x13
+
#endif
diff --git a/include/linux/mfd/ti-lmu.h b/include/linux/mfd/ti-lmu.h
index 54e9d272e81c..0957598c7d41 100644
--- a/include/linux/mfd/ti-lmu.h
+++ b/include/linux/mfd/ti-lmu.h
@@ -26,6 +26,7 @@ enum ti_lmu_id {
LM3632,
LM3633,
LM3695,
+ LM36274,
LMU_MAX_ID,
};
@@ -67,6 +68,9 @@ enum lm363x_regulator_id {
LM3632_BOOST, /* Boost output */
LM3632_LDO_POS, /* Positive display bias output */
LM3632_LDO_NEG, /* Negative display bias output */
+ LM36274_BOOST, /* Boost output */
+ LM36274_LDO_POS, /* Positive display bias output */
+ LM36274_LDO_NEG, /* Negative display bias output */
};
/**
--
2.21.0.5.gaeb582a983
^ permalink raw reply related
* Re: [PATCH] watchdog: wdat_wdt: fix get_timeleft call for wdat_wdt
From: Guenter Roeck @ 2019-04-10 13:38 UTC (permalink / raw)
To: Bryan Tan
Cc: Wim Van Sebroeck, linux-watchdog@vger.kernel.org,
linux-kernel@vger.kernel.org
In-Reply-To: <20190410124813.86892-1-bryantan@vmware.com>
On 4/10/19 5:49 AM, Bryan Tan wrote:
> The get_timeleft call for wdat_wdt was using ACPI_WDAT_GET_COUNTDOWN
> when running an action on the device, which would return the configured
> countdown, instead of ACPI_WDAT_GET_CURRENT_COUNTDOWN, which returns the
> time left before the watchdog will fire. This change corrects that.
>
> Signed-off-by: Bryan Tan <bryantan@vmware.com>
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
> ---
> drivers/watchdog/wdat_wdt.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/watchdog/wdat_wdt.c b/drivers/watchdog/wdat_wdt.c
> index 56ad196..387892f 100644
> --- a/drivers/watchdog/wdat_wdt.c
> +++ b/drivers/watchdog/wdat_wdt.c
> @@ -287,7 +287,7 @@ static unsigned int wdat_wdt_get_timeleft(struct watchdog_device *wdd)
> struct wdat_wdt *wdat = to_wdat_wdt(wdd);
> u32 periods = 0;
>
> - wdat_wdt_run_action(wdat, ACPI_WDAT_GET_COUNTDOWN, 0, &periods);
> + wdat_wdt_run_action(wdat, ACPI_WDAT_GET_CURRENT_COUNTDOWN, 0, &periods);
> return periods * wdat->period / 1000;
> }
>
>
^ permalink raw reply
* [PATCH v2 1/6] regulator: lm363x: Make the gpio register enable flexible
From: Dan Murphy @ 2019-04-10 13:38 UTC (permalink / raw)
To: robh+dt, jacek.anaszewski, pavel, lee.jones, lgirdwood, broonie
Cc: devicetree, linux-kernel, linux-leds, Dan Murphy
The use of and enablement of the GPIO can be used across devices.
Use the enable_reg in the regulator descriptor for the register to
write.
Signed-off-by: Dan Murphy <dmurphy@ti.com>
---
v2 - No changes - https://lore.kernel.org/patchwork/patch/1058777/
drivers/regulator/lm363x-regulator.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/regulator/lm363x-regulator.c b/drivers/regulator/lm363x-regulator.c
index c876e161052a..382b1cecdd93 100644
--- a/drivers/regulator/lm363x-regulator.c
+++ b/drivers/regulator/lm363x-regulator.c
@@ -263,8 +263,8 @@ static int lm363x_regulator_probe(struct platform_device *pdev)
if (gpiod) {
cfg.ena_gpiod = gpiod;
-
- ret = regmap_update_bits(regmap, LM3632_REG_BIAS_CONFIG,
+ ret = regmap_update_bits(regmap,
+ lm363x_regulator_desc[id].enable_reg,
LM3632_EXT_EN_MASK,
LM3632_EXT_EN_MASK);
if (ret) {
--
2.21.0.5.gaeb582a983
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.