* Re: [PATCH v2 2/2] drm/bridge: anx7688: Add anx7688 bridge driver support
From: Vasily Khoruzhick @ 2020-02-14 22:22 UTC (permalink / raw)
To: Enric Balletbo Serra
Cc: Icenowy Zheng, Enric Balletbo i Serra, Jernej Skrabec,
Nicolas Boichat, Laurent Pinchart, Neil Armstrong, David Airlie,
Torsten Duwe, Jonas Karlman, linux-kernel, dri-devel,
Andrzej Hajda, Maxime Ripard, Hsin-Yi Wang, Matthias Brugger,
Thomas Gleixner, Collabora Kernel ML
In-Reply-To: <CAFqH_505eWt9UU7Wj6tCQpQCMZFMfy9e1ETSkiqi7i5Zx6KULQ@mail.gmail.com>
On Fri, Feb 14, 2020 at 2:20 PM Enric Balletbo Serra
<eballetbo@gmail.com> wrote:
>
> Hi Vasily,
>
> Missatge de Vasily Khoruzhick <anarsoul@gmail.com> del dia dv., 14 de
> febr. 2020 a les 23:17:
> >
> > On Fri, Feb 14, 2020 at 1:53 PM Enric Balletbo Serra
> > <eballetbo@gmail.com> wrote:
> > >
> > > Hi Vasily,
> > >
> > > Missatge de Vasily Khoruzhick <anarsoul@gmail.com> del dia dv., 14 de
> > > febr. 2020 a les 22:36:
> > > >
> > > > On Thu, Feb 13, 2020 at 6:54 AM Enric Balletbo i Serra
> > > > <enric.balletbo@collabora.com> wrote:
> > > > >
> > > > > From: Nicolas Boichat <drinkcat@chromium.org>
> > > > >
> > > > > ANX7688 is a HDMI to DP converter (as well as USB-C port controller),
> > > > > that has an internal microcontroller.
> > > > >
> > > > > The only reason a Linux kernel driver is necessary is to reject
> > > > > resolutions that require more bandwidth than what is available on
> > > > > the DP side. DP bandwidth and lane count are reported by the bridge
> > > > > via 2 registers on I2C.
> > > >
> > > > It is true only for your particular platform where usb-c part is
> > > > managed by firmware. Pinephone has the same anx7688 but linux will
> > > > need a driver that manages usb-c in addition to DP.
> > > >
> > > > I'd suggest making it MFD driver from the beginning, or at least make
> > > > proper bindings so we don't have to rework it and introduce binding
> > > > incompatibilities in future.
> > > >
> > >
> > > Do you have example code on how the ANX7866 is used in pinephone?
> > > There is a repo somewhere?
> >
> > I don't think it's implemented yet. I've CCed Icenowy in case if she
> > has anything.
> >
>
> It would be good to join the effort. Just because I am curious, there
> are public schematics for the pinephone that is using that bridge?
Schematics is available here:
https://wiki.pine64.org/index.php/PinePhone_v1.1_-_Braveheart#Schematic
> > > Thanks,
> > > Enric
> > >
> > > > > Signed-off-by: Nicolas Boichat <drinkcat@chromium.org>
> > > > > Signed-off-by: Hsin-Yi Wang <hsinyi@chromium.org>
> > > > > Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> > > > > ---
> > > > >
> > > > > Changes in v2:
> > > > > - Move driver to drivers/gpu/drm/bridge/analogix.
> > > > > - Make the driver OF only so we can reduce the ifdefs.
> > > > > - Update the Copyright to 2020.
> > > > > - Use probe_new so we can get rid of the i2c_device_id table.
> > > > >
> > > > > drivers/gpu/drm/bridge/analogix/Kconfig | 12 ++
> > > > > drivers/gpu/drm/bridge/analogix/Makefile | 1 +
> > > > > .../drm/bridge/analogix/analogix-anx7688.c | 188 ++++++++++++++++++
> > > > > 3 files changed, 201 insertions(+)
> > > > > create mode 100644 drivers/gpu/drm/bridge/analogix/analogix-anx7688.c
> > > > >
> > > > > diff --git a/drivers/gpu/drm/bridge/analogix/Kconfig b/drivers/gpu/drm/bridge/analogix/Kconfig
> > > > > index e1fa7d820373..af7c2939403c 100644
> > > > > --- a/drivers/gpu/drm/bridge/analogix/Kconfig
> > > > > +++ b/drivers/gpu/drm/bridge/analogix/Kconfig
> > > > > @@ -11,6 +11,18 @@ config DRM_ANALOGIX_ANX6345
> > > > > ANX6345 transforms the LVTTL RGB output of an
> > > > > application processor to eDP or DisplayPort.
> > > > >
> > > > > +config DRM_ANALOGIX_ANX7688
> > > > > + tristate "Analogix ANX7688 bridge"
> > > > > + depends on OF
> > > > > + select DRM_KMS_HELPER
> > > > > + select REGMAP_I2C
> > > > > + help
> > > > > + ANX7688 is an ultra-low power 4k Ultra-HD (4096x2160p60)
> > > > > + mobile HD transmitter designed for portable devices. The
> > > > > + ANX7688 converts HDMI 2.0 to DisplayPort 1.3 Ultra-HD
> > > > > + including an intelligent crosspoint switch to support
> > > > > + USB Type-C.
> > > > > +
> > > > > config DRM_ANALOGIX_ANX78XX
> > > > > tristate "Analogix ANX78XX bridge"
> > > > > select DRM_ANALOGIX_DP
> > > > > diff --git a/drivers/gpu/drm/bridge/analogix/Makefile b/drivers/gpu/drm/bridge/analogix/Makefile
> > > > > index 97669b374098..27cd73635c8c 100644
> > > > > --- a/drivers/gpu/drm/bridge/analogix/Makefile
> > > > > +++ b/drivers/gpu/drm/bridge/analogix/Makefile
> > > > > @@ -1,5 +1,6 @@
> > > > > # SPDX-License-Identifier: GPL-2.0-only
> > > > > analogix_dp-objs := analogix_dp_core.o analogix_dp_reg.o analogix-i2c-dptx.o
> > > > > obj-$(CONFIG_DRM_ANALOGIX_ANX6345) += analogix-anx6345.o
> > > > > +obj-$(CONFIG_DRM_ANALOGIX_ANX7688) += analogix-anx7688.o
> > > > > obj-$(CONFIG_DRM_ANALOGIX_ANX78XX) += analogix-anx78xx.o
> > > > > obj-$(CONFIG_DRM_ANALOGIX_DP) += analogix_dp.o
> > > > > diff --git a/drivers/gpu/drm/bridge/analogix/analogix-anx7688.c b/drivers/gpu/drm/bridge/analogix/analogix-anx7688.c
> > > > > new file mode 100644
> > > > > index 000000000000..10a7cd0f9126
> > > > > --- /dev/null
> > > > > +++ b/drivers/gpu/drm/bridge/analogix/analogix-anx7688.c
> > > > > @@ -0,0 +1,188 @@
> > > > > +// SPDX-License-Identifier: GPL-2.0-only
> > > > > +/*
> > > > > + * ANX7688 HDMI->DP bridge driver
> > > > > + *
> > > > > + * Copyright 2020 Google LLC
> > > > > + */
> > > > > +
> > > > > +#include <linux/i2c.h>
> > > > > +#include <linux/module.h>
> > > > > +#include <linux/regmap.h>
> > > > > +#include <drm/drm_bridge.h>
> > > > > +
> > > > > +/* Register addresses */
> > > > > +#define VENDOR_ID_REG 0x00
> > > > > +#define DEVICE_ID_REG 0x02
> > > > > +
> > > > > +#define FW_VERSION_REG 0x80
> > > > > +
> > > > > +#define DP_BANDWIDTH_REG 0x85
> > > > > +#define DP_LANE_COUNT_REG 0x86
> > > > > +
> > > > > +#define VENDOR_ID 0x1f29
> > > > > +#define DEVICE_ID 0x7688
> > > > > +
> > > > > +/* First supported firmware version (0.85) */
> > > > > +#define MINIMUM_FW_VERSION 0x0085
> > > > > +
> > > > > +struct anx7688 {
> > > > > + struct drm_bridge bridge;
> > > > > + struct i2c_client *client;
> > > > > + struct regmap *regmap;
> > > > > +
> > > > > + bool filter;
> > > > > +};
> > > > > +
> > > > > +static inline struct anx7688 *bridge_to_anx7688(struct drm_bridge *bridge)
> > > > > +{
> > > > > + return container_of(bridge, struct anx7688, bridge);
> > > > > +}
> > > > > +
> > > > > +static bool anx7688_bridge_mode_fixup(struct drm_bridge *bridge,
> > > > > + const struct drm_display_mode *mode,
> > > > > + struct drm_display_mode *adjusted_mode)
> > > > > +{
> > > > > + struct anx7688 *anx7688 = bridge_to_anx7688(bridge);
> > > > > + int totalbw, requiredbw;
> > > > > + u8 dpbw, lanecount;
> > > > > + u8 regs[2];
> > > > > + int ret;
> > > > > +
> > > > > + if (!anx7688->filter)
> > > > > + return true;
> > > > > +
> > > > > + /* Read both regs 0x85 (bandwidth) and 0x86 (lane count). */
> > > > > + ret = regmap_bulk_read(anx7688->regmap, DP_BANDWIDTH_REG, regs, 2);
> > > > > + if (ret < 0) {
> > > > > + dev_err(&anx7688->client->dev,
> > > > > + "Failed to read bandwidth/lane count\n");
> > > > > + return false;
> > > > > + }
> > > > > + dpbw = regs[0];
> > > > > + lanecount = regs[1];
> > > > > +
> > > > > + /* Maximum 0x19 bandwidth (6.75 Gbps Turbo mode), 2 lanes */
> > > > > + if (dpbw > 0x19 || lanecount > 2) {
> > > > > + dev_err(&anx7688->client->dev,
> > > > > + "Invalid bandwidth/lane count (%02x/%d)\n",
> > > > > + dpbw, lanecount);
> > > > > + return false;
> > > > > + }
> > > > > +
> > > > > + /* Compute available bandwidth (kHz) */
> > > > > + totalbw = dpbw * lanecount * 270000 * 8 / 10;
> > > > > +
> > > > > + /* Required bandwidth (8 bpc, kHz) */
> > > > > + requiredbw = mode->clock * 8 * 3;
> > > > > +
> > > > > + dev_dbg(&anx7688->client->dev,
> > > > > + "DP bandwidth: %d kHz (%02x/%d); mode requires %d Khz\n",
> > > > > + totalbw, dpbw, lanecount, requiredbw);
> > > > > +
> > > > > + if (totalbw == 0) {
> > > > > + dev_warn(&anx7688->client->dev,
> > > > > + "Bandwidth/lane count are 0, not rejecting modes\n");
> > > > > + return true;
> > > > > + }
> > > > > +
> > > > > + return totalbw >= requiredbw;
> > > > > +}
> > > > > +
> > > > > +static const struct drm_bridge_funcs anx7688_bridge_funcs = {
> > > > > + .mode_fixup = anx7688_bridge_mode_fixup,
> > > > > +};
> > > > > +
> > > > > +static const struct regmap_config anx7688_regmap_config = {
> > > > > + .reg_bits = 8,
> > > > > + .val_bits = 8,
> > > > > +};
> > > > > +
> > > > > +static int anx7688_i2c_probe(struct i2c_client *client)
> > > > > +{
> > > > > + struct device *dev = &client->dev;
> > > > > + struct anx7688 *anx7688;
> > > > > + u16 vendor, device;
> > > > > + u16 fwversion;
> > > > > + u8 buffer[4];
> > > > > + int ret;
> > > > > +
> > > > > + anx7688 = devm_kzalloc(dev, sizeof(*anx7688), GFP_KERNEL);
> > > > > + if (!anx7688)
> > > > > + return -ENOMEM;
> > > > > +
> > > > > + anx7688->bridge.of_node = dev->of_node;
> > > > > + anx7688->client = client;
> > > > > + i2c_set_clientdata(client, anx7688);
> > > > > +
> > > > > + anx7688->regmap = devm_regmap_init_i2c(client, &anx7688_regmap_config);
> > > > > +
> > > > > + /* Read both vendor and device id (4 bytes). */
> > > > > + ret = regmap_bulk_read(anx7688->regmap, VENDOR_ID_REG, buffer, 4);
> > > > > + if (ret) {
> > > > > + dev_err(dev, "Failed to read chip vendor/device id\n");
> > > > > + return ret;
> > > > > + }
> > > > > +
> > > > > + vendor = (u16)buffer[1] << 8 | buffer[0];
> > > > > + device = (u16)buffer[3] << 8 | buffer[2];
> > > > > + if (vendor != VENDOR_ID || device != DEVICE_ID) {
> > > > > + dev_err(dev, "Invalid vendor/device id %04x/%04x\n",
> > > > > + vendor, device);
> > > > > + return -ENODEV;
> > > > > + }
> > > > > +
> > > > > + ret = regmap_bulk_read(anx7688->regmap, FW_VERSION_REG, buffer, 2);
> > > > > + if (ret) {
> > > > > + dev_err(&client->dev, "Failed to read firmware version\n");
> > > > > + return ret;
> > > > > + }
> > > > > +
> > > > > + fwversion = (u16)buffer[0] << 8 | buffer[1];
> > > > > + dev_info(dev, "ANX7688 firwmare version %02x.%02x\n",
> > > > > + buffer[0], buffer[1]);
> > > > > +
> > > > > + /* FW version >= 0.85 supports bandwidth/lane count registers */
> > > > > + if (fwversion >= MINIMUM_FW_VERSION) {
> > > > > + anx7688->filter = true;
> > > > > + } else {
> > > > > + /* Warn, but not fail, for backwards compatibility. */
> > > > > + dev_warn(dev,
> > > > > + "Old ANX7688 FW version (%02x.%02x), not filtering\n",
> > > > > + buffer[0], buffer[1]);
> > > > > + }
> > > > > +
> > > > > + anx7688->bridge.funcs = &anx7688_bridge_funcs;
> > > > > + drm_bridge_add(&anx7688->bridge);
> > > > > +
> > > > > + return 0;
> > > > > +}
> > > > > +
> > > > > +static int anx7688_i2c_remove(struct i2c_client *client)
> > > > > +{
> > > > > + struct anx7688 *anx7688 = i2c_get_clientdata(client);
> > > > > +
> > > > > + drm_bridge_remove(&anx7688->bridge);
> > > > > +
> > > > > + return 0;
> > > > > +}
> > > > > +
> > > > > +static const struct of_device_id anx7688_match_table[] = {
> > > > > + { .compatible = "analogix,anx7688", },
> > > > > + { }
> > > > > +};
> > > > > +MODULE_DEVICE_TABLE(of, anx7688_match_table);
> > > > > +
> > > > > +static struct i2c_driver anx7688_driver = {
> > > > > + .probe_new = anx7688_i2c_probe,
> > > > > + .remove = anx7688_i2c_remove,
> > > > > + .driver = {
> > > > > + .name = "anx7688",
> > > > > + .of_match_table = anx7688_match_table,
> > > > > + },
> > > > > +};
> > > > > +
> > > > > +module_i2c_driver(anx7688_driver);
> > > > > +
> > > > > +MODULE_DESCRIPTION("ANX7688 HDMI->DP bridge driver");
> > > > > +MODULE_AUTHOR("Nicolas Boichat <drinkcat@chromium.org>");
> > > > > +MODULE_LICENSE("GPL");
> > > > > --
> > > > > 2.25.0
> > > > >
> > > > _______________________________________________
> > > > dri-devel mailing list
> > > > dri-devel@lists.freedesktop.org
> > > > https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply
* Re: [PATCH v2 2/2] drm/bridge: anx7688: Add anx7688 bridge driver support
From: Vasily Khoruzhick @ 2020-02-14 22:22 UTC (permalink / raw)
To: Enric Balletbo Serra
Cc: Jernej Skrabec, Nicolas Boichat, Maxime Ripard, Neil Armstrong,
David Airlie, Torsten Duwe, Jonas Karlman, linux-kernel,
dri-devel, Andrzej Hajda, Matthias Brugger, Laurent Pinchart,
Hsin-Yi Wang, Enric Balletbo i Serra, Thomas Gleixner,
Collabora Kernel ML, Icenowy Zheng
In-Reply-To: <CAFqH_505eWt9UU7Wj6tCQpQCMZFMfy9e1ETSkiqi7i5Zx6KULQ@mail.gmail.com>
On Fri, Feb 14, 2020 at 2:20 PM Enric Balletbo Serra
<eballetbo@gmail.com> wrote:
>
> Hi Vasily,
>
> Missatge de Vasily Khoruzhick <anarsoul@gmail.com> del dia dv., 14 de
> febr. 2020 a les 23:17:
> >
> > On Fri, Feb 14, 2020 at 1:53 PM Enric Balletbo Serra
> > <eballetbo@gmail.com> wrote:
> > >
> > > Hi Vasily,
> > >
> > > Missatge de Vasily Khoruzhick <anarsoul@gmail.com> del dia dv., 14 de
> > > febr. 2020 a les 22:36:
> > > >
> > > > On Thu, Feb 13, 2020 at 6:54 AM Enric Balletbo i Serra
> > > > <enric.balletbo@collabora.com> wrote:
> > > > >
> > > > > From: Nicolas Boichat <drinkcat@chromium.org>
> > > > >
> > > > > ANX7688 is a HDMI to DP converter (as well as USB-C port controller),
> > > > > that has an internal microcontroller.
> > > > >
> > > > > The only reason a Linux kernel driver is necessary is to reject
> > > > > resolutions that require more bandwidth than what is available on
> > > > > the DP side. DP bandwidth and lane count are reported by the bridge
> > > > > via 2 registers on I2C.
> > > >
> > > > It is true only for your particular platform where usb-c part is
> > > > managed by firmware. Pinephone has the same anx7688 but linux will
> > > > need a driver that manages usb-c in addition to DP.
> > > >
> > > > I'd suggest making it MFD driver from the beginning, or at least make
> > > > proper bindings so we don't have to rework it and introduce binding
> > > > incompatibilities in future.
> > > >
> > >
> > > Do you have example code on how the ANX7866 is used in pinephone?
> > > There is a repo somewhere?
> >
> > I don't think it's implemented yet. I've CCed Icenowy in case if she
> > has anything.
> >
>
> It would be good to join the effort. Just because I am curious, there
> are public schematics for the pinephone that is using that bridge?
Schematics is available here:
https://wiki.pine64.org/index.php/PinePhone_v1.1_-_Braveheart#Schematic
> > > Thanks,
> > > Enric
> > >
> > > > > Signed-off-by: Nicolas Boichat <drinkcat@chromium.org>
> > > > > Signed-off-by: Hsin-Yi Wang <hsinyi@chromium.org>
> > > > > Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> > > > > ---
> > > > >
> > > > > Changes in v2:
> > > > > - Move driver to drivers/gpu/drm/bridge/analogix.
> > > > > - Make the driver OF only so we can reduce the ifdefs.
> > > > > - Update the Copyright to 2020.
> > > > > - Use probe_new so we can get rid of the i2c_device_id table.
> > > > >
> > > > > drivers/gpu/drm/bridge/analogix/Kconfig | 12 ++
> > > > > drivers/gpu/drm/bridge/analogix/Makefile | 1 +
> > > > > .../drm/bridge/analogix/analogix-anx7688.c | 188 ++++++++++++++++++
> > > > > 3 files changed, 201 insertions(+)
> > > > > create mode 100644 drivers/gpu/drm/bridge/analogix/analogix-anx7688.c
> > > > >
> > > > > diff --git a/drivers/gpu/drm/bridge/analogix/Kconfig b/drivers/gpu/drm/bridge/analogix/Kconfig
> > > > > index e1fa7d820373..af7c2939403c 100644
> > > > > --- a/drivers/gpu/drm/bridge/analogix/Kconfig
> > > > > +++ b/drivers/gpu/drm/bridge/analogix/Kconfig
> > > > > @@ -11,6 +11,18 @@ config DRM_ANALOGIX_ANX6345
> > > > > ANX6345 transforms the LVTTL RGB output of an
> > > > > application processor to eDP or DisplayPort.
> > > > >
> > > > > +config DRM_ANALOGIX_ANX7688
> > > > > + tristate "Analogix ANX7688 bridge"
> > > > > + depends on OF
> > > > > + select DRM_KMS_HELPER
> > > > > + select REGMAP_I2C
> > > > > + help
> > > > > + ANX7688 is an ultra-low power 4k Ultra-HD (4096x2160p60)
> > > > > + mobile HD transmitter designed for portable devices. The
> > > > > + ANX7688 converts HDMI 2.0 to DisplayPort 1.3 Ultra-HD
> > > > > + including an intelligent crosspoint switch to support
> > > > > + USB Type-C.
> > > > > +
> > > > > config DRM_ANALOGIX_ANX78XX
> > > > > tristate "Analogix ANX78XX bridge"
> > > > > select DRM_ANALOGIX_DP
> > > > > diff --git a/drivers/gpu/drm/bridge/analogix/Makefile b/drivers/gpu/drm/bridge/analogix/Makefile
> > > > > index 97669b374098..27cd73635c8c 100644
> > > > > --- a/drivers/gpu/drm/bridge/analogix/Makefile
> > > > > +++ b/drivers/gpu/drm/bridge/analogix/Makefile
> > > > > @@ -1,5 +1,6 @@
> > > > > # SPDX-License-Identifier: GPL-2.0-only
> > > > > analogix_dp-objs := analogix_dp_core.o analogix_dp_reg.o analogix-i2c-dptx.o
> > > > > obj-$(CONFIG_DRM_ANALOGIX_ANX6345) += analogix-anx6345.o
> > > > > +obj-$(CONFIG_DRM_ANALOGIX_ANX7688) += analogix-anx7688.o
> > > > > obj-$(CONFIG_DRM_ANALOGIX_ANX78XX) += analogix-anx78xx.o
> > > > > obj-$(CONFIG_DRM_ANALOGIX_DP) += analogix_dp.o
> > > > > diff --git a/drivers/gpu/drm/bridge/analogix/analogix-anx7688.c b/drivers/gpu/drm/bridge/analogix/analogix-anx7688.c
> > > > > new file mode 100644
> > > > > index 000000000000..10a7cd0f9126
> > > > > --- /dev/null
> > > > > +++ b/drivers/gpu/drm/bridge/analogix/analogix-anx7688.c
> > > > > @@ -0,0 +1,188 @@
> > > > > +// SPDX-License-Identifier: GPL-2.0-only
> > > > > +/*
> > > > > + * ANX7688 HDMI->DP bridge driver
> > > > > + *
> > > > > + * Copyright 2020 Google LLC
> > > > > + */
> > > > > +
> > > > > +#include <linux/i2c.h>
> > > > > +#include <linux/module.h>
> > > > > +#include <linux/regmap.h>
> > > > > +#include <drm/drm_bridge.h>
> > > > > +
> > > > > +/* Register addresses */
> > > > > +#define VENDOR_ID_REG 0x00
> > > > > +#define DEVICE_ID_REG 0x02
> > > > > +
> > > > > +#define FW_VERSION_REG 0x80
> > > > > +
> > > > > +#define DP_BANDWIDTH_REG 0x85
> > > > > +#define DP_LANE_COUNT_REG 0x86
> > > > > +
> > > > > +#define VENDOR_ID 0x1f29
> > > > > +#define DEVICE_ID 0x7688
> > > > > +
> > > > > +/* First supported firmware version (0.85) */
> > > > > +#define MINIMUM_FW_VERSION 0x0085
> > > > > +
> > > > > +struct anx7688 {
> > > > > + struct drm_bridge bridge;
> > > > > + struct i2c_client *client;
> > > > > + struct regmap *regmap;
> > > > > +
> > > > > + bool filter;
> > > > > +};
> > > > > +
> > > > > +static inline struct anx7688 *bridge_to_anx7688(struct drm_bridge *bridge)
> > > > > +{
> > > > > + return container_of(bridge, struct anx7688, bridge);
> > > > > +}
> > > > > +
> > > > > +static bool anx7688_bridge_mode_fixup(struct drm_bridge *bridge,
> > > > > + const struct drm_display_mode *mode,
> > > > > + struct drm_display_mode *adjusted_mode)
> > > > > +{
> > > > > + struct anx7688 *anx7688 = bridge_to_anx7688(bridge);
> > > > > + int totalbw, requiredbw;
> > > > > + u8 dpbw, lanecount;
> > > > > + u8 regs[2];
> > > > > + int ret;
> > > > > +
> > > > > + if (!anx7688->filter)
> > > > > + return true;
> > > > > +
> > > > > + /* Read both regs 0x85 (bandwidth) and 0x86 (lane count). */
> > > > > + ret = regmap_bulk_read(anx7688->regmap, DP_BANDWIDTH_REG, regs, 2);
> > > > > + if (ret < 0) {
> > > > > + dev_err(&anx7688->client->dev,
> > > > > + "Failed to read bandwidth/lane count\n");
> > > > > + return false;
> > > > > + }
> > > > > + dpbw = regs[0];
> > > > > + lanecount = regs[1];
> > > > > +
> > > > > + /* Maximum 0x19 bandwidth (6.75 Gbps Turbo mode), 2 lanes */
> > > > > + if (dpbw > 0x19 || lanecount > 2) {
> > > > > + dev_err(&anx7688->client->dev,
> > > > > + "Invalid bandwidth/lane count (%02x/%d)\n",
> > > > > + dpbw, lanecount);
> > > > > + return false;
> > > > > + }
> > > > > +
> > > > > + /* Compute available bandwidth (kHz) */
> > > > > + totalbw = dpbw * lanecount * 270000 * 8 / 10;
> > > > > +
> > > > > + /* Required bandwidth (8 bpc, kHz) */
> > > > > + requiredbw = mode->clock * 8 * 3;
> > > > > +
> > > > > + dev_dbg(&anx7688->client->dev,
> > > > > + "DP bandwidth: %d kHz (%02x/%d); mode requires %d Khz\n",
> > > > > + totalbw, dpbw, lanecount, requiredbw);
> > > > > +
> > > > > + if (totalbw == 0) {
> > > > > + dev_warn(&anx7688->client->dev,
> > > > > + "Bandwidth/lane count are 0, not rejecting modes\n");
> > > > > + return true;
> > > > > + }
> > > > > +
> > > > > + return totalbw >= requiredbw;
> > > > > +}
> > > > > +
> > > > > +static const struct drm_bridge_funcs anx7688_bridge_funcs = {
> > > > > + .mode_fixup = anx7688_bridge_mode_fixup,
> > > > > +};
> > > > > +
> > > > > +static const struct regmap_config anx7688_regmap_config = {
> > > > > + .reg_bits = 8,
> > > > > + .val_bits = 8,
> > > > > +};
> > > > > +
> > > > > +static int anx7688_i2c_probe(struct i2c_client *client)
> > > > > +{
> > > > > + struct device *dev = &client->dev;
> > > > > + struct anx7688 *anx7688;
> > > > > + u16 vendor, device;
> > > > > + u16 fwversion;
> > > > > + u8 buffer[4];
> > > > > + int ret;
> > > > > +
> > > > > + anx7688 = devm_kzalloc(dev, sizeof(*anx7688), GFP_KERNEL);
> > > > > + if (!anx7688)
> > > > > + return -ENOMEM;
> > > > > +
> > > > > + anx7688->bridge.of_node = dev->of_node;
> > > > > + anx7688->client = client;
> > > > > + i2c_set_clientdata(client, anx7688);
> > > > > +
> > > > > + anx7688->regmap = devm_regmap_init_i2c(client, &anx7688_regmap_config);
> > > > > +
> > > > > + /* Read both vendor and device id (4 bytes). */
> > > > > + ret = regmap_bulk_read(anx7688->regmap, VENDOR_ID_REG, buffer, 4);
> > > > > + if (ret) {
> > > > > + dev_err(dev, "Failed to read chip vendor/device id\n");
> > > > > + return ret;
> > > > > + }
> > > > > +
> > > > > + vendor = (u16)buffer[1] << 8 | buffer[0];
> > > > > + device = (u16)buffer[3] << 8 | buffer[2];
> > > > > + if (vendor != VENDOR_ID || device != DEVICE_ID) {
> > > > > + dev_err(dev, "Invalid vendor/device id %04x/%04x\n",
> > > > > + vendor, device);
> > > > > + return -ENODEV;
> > > > > + }
> > > > > +
> > > > > + ret = regmap_bulk_read(anx7688->regmap, FW_VERSION_REG, buffer, 2);
> > > > > + if (ret) {
> > > > > + dev_err(&client->dev, "Failed to read firmware version\n");
> > > > > + return ret;
> > > > > + }
> > > > > +
> > > > > + fwversion = (u16)buffer[0] << 8 | buffer[1];
> > > > > + dev_info(dev, "ANX7688 firwmare version %02x.%02x\n",
> > > > > + buffer[0], buffer[1]);
> > > > > +
> > > > > + /* FW version >= 0.85 supports bandwidth/lane count registers */
> > > > > + if (fwversion >= MINIMUM_FW_VERSION) {
> > > > > + anx7688->filter = true;
> > > > > + } else {
> > > > > + /* Warn, but not fail, for backwards compatibility. */
> > > > > + dev_warn(dev,
> > > > > + "Old ANX7688 FW version (%02x.%02x), not filtering\n",
> > > > > + buffer[0], buffer[1]);
> > > > > + }
> > > > > +
> > > > > + anx7688->bridge.funcs = &anx7688_bridge_funcs;
> > > > > + drm_bridge_add(&anx7688->bridge);
> > > > > +
> > > > > + return 0;
> > > > > +}
> > > > > +
> > > > > +static int anx7688_i2c_remove(struct i2c_client *client)
> > > > > +{
> > > > > + struct anx7688 *anx7688 = i2c_get_clientdata(client);
> > > > > +
> > > > > + drm_bridge_remove(&anx7688->bridge);
> > > > > +
> > > > > + return 0;
> > > > > +}
> > > > > +
> > > > > +static const struct of_device_id anx7688_match_table[] = {
> > > > > + { .compatible = "analogix,anx7688", },
> > > > > + { }
> > > > > +};
> > > > > +MODULE_DEVICE_TABLE(of, anx7688_match_table);
> > > > > +
> > > > > +static struct i2c_driver anx7688_driver = {
> > > > > + .probe_new = anx7688_i2c_probe,
> > > > > + .remove = anx7688_i2c_remove,
> > > > > + .driver = {
> > > > > + .name = "anx7688",
> > > > > + .of_match_table = anx7688_match_table,
> > > > > + },
> > > > > +};
> > > > > +
> > > > > +module_i2c_driver(anx7688_driver);
> > > > > +
> > > > > +MODULE_DESCRIPTION("ANX7688 HDMI->DP bridge driver");
> > > > > +MODULE_AUTHOR("Nicolas Boichat <drinkcat@chromium.org>");
> > > > > +MODULE_LICENSE("GPL");
> > > > > --
> > > > > 2.25.0
> > > > >
> > > > _______________________________________________
> > > > dri-devel mailing list
> > > > dri-devel@lists.freedesktop.org
> > > > https://lists.freedesktop.org/mailman/listinfo/dri-devel
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply
* Performance issue with psusensor / dbus-sensors
From: Peter Lundgren @ 2020-02-14 22:14 UTC (permalink / raw)
To: openbmc, james.feist, vernon.mauery, jae.hyun.yoo, Josh Lehan,
Alex Qiu, Xiang Liu, Sui Chen
[-- Attachment #1: Type: text/plain, Size: 990 bytes --]
We're running into some occasional and hard to reproduce performance issues
with sensors on the entity-manager/dbus-sensors/intel-ipmi-oem software
stack. I don't have much concrete to say on the subject, but I want to put
a feeler out to see if anyone else has seen similar issues. Here's what we
think so far:
Complaints range from IPMI sensor reads being slower than normal to sensors
"never" updating.
Josh got access to one machine in a bad state and observed this:
1. All the I2C buses were working normally. i2cdetect ran successfully
on each bus.
2. hwmon was working fine. He wrote a shell script to read all of the
*_input sysfs files and could read every sensor in the system in 3 seconds.
3. psusensor was running.
4. busctl --no-pager monitor | grep -i PropertiesChanged shows no
traffic. On a healthy system, it shows many updates per second. No obvious
error messages in journalctl --no-pager -f.
5. Restarting psusensor alleviates the problem.
[-- Attachment #2: Type: text/html, Size: 1167 bytes --]
^ permalink raw reply
* Re: [PATCH] objtool: ignore .L prefixed local symbols
From: Fangrui Song @ 2020-02-14 22:20 UTC (permalink / raw)
To: Arvind Sankar
Cc: Nick Desaulniers, jpoimboe, peterz, clang-built-linux,
Nathan Chancellor, linux-kernel
In-Reply-To: <20200214204249.GA3624438@rani.riverdale.lan>
On 2020-02-14, Arvind Sankar wrote:
>On Fri, Feb 14, 2020 at 10:05:27AM -0800, Fangrui Song wrote:
>> I know little about objtool, but if it may be used by other
>> architectures, hope the following explanations don't appear to be too
>> off-topic:)
>>
>> On 2020-02-14, Arvind Sankar wrote:
>> >Can you describe what case the clang change is supposed to optimize?
>> >AFAICT, it kicks in when the symbol is known by the compiler to be local
>> >to the DSO and defined in the same translation unit.
>> >
>> >But then there are two cases:
>> >(a) we have call foo, where foo is defined in the same section as the
>> >call instruction. In this case the assembler should be able to fully
>> >resolve foo and not generate any relocation, regardless of whether foo
>> >is global or local.
>>
>> If foo is STB_GLOBAL or STB_WEAK, the assembler cannot fully resolve a
>> reference to foo in the same section, unless the assembler can assume
>> (the codegen tells it) the call to foo cannot be interposed by another
>> foo definition at runtime.
>
>I was testing with hidden/protected visibility, I see you want this for
>the no-semantic-interposition case. Actually a bit more testing shows
>some peculiarities even with hidden visibility. With the below, the call
>and lea create relocations in the object file, but the jmp doesn't. ld
>does avoid creating a plt for this though.
>
> .text
> .globl foo, bar
> .hidden foo
> bar:
> call foo
> leaq foo(%rip), %rax
> jmp foo
>
> foo: ret
Yes, GNU as is inconsistent here. While fixing
https://sourceware.org/ml/binutils/2020-02/msg00243.html , I noticed
that the rule is quite complex. There are definitely lots of places to
improve. clang 10 emits relocations consistently.
call foo # R_X86_64_PLT32
leaq foo(%rip), %rax # R_X86_64_PC32
jmp foo # R_X86_64_PLT32
We can teach the assembler to not emit relocations referencing STV_HIDDEN or
STV_INTERNAL symbols, but I favor the simpler rule that only relocations
referencing STB_LOCAL non-STT_GNU_IFUNC symbols defined in the same section are resolved.
Leave the visibility jobs to the linker.
If we ever teach GNU objcopy or llvm-objcopt an option to set
visibility, resolving relocations may disallow such use cases.
Unfortunately gcc>=5 x86 and GNU ld>=2.26 x86 are in a bad status
regarding STV_PROTECTED (https://reviews.llvm.org/D72197#1866384).
(Now I retest it, I think I may add a special -no-integrated-as rule to
clang just to work around GNU ld x86>=2.26.)
>> >(b) we have call foo, where foo is defined in a different section from
>> >the call instruction. In this case the assembler must generate a
>> >relocation regardless of whether foo is global or local, and the linker
>> >should eliminate it.
>> >In what case does does replacing call foo with call .Lfoo$local help?
>>
>> For -fPIC -fno-semantic-interposition, the assembly emitter can perform
>> the following optimization:
>>
>> void foo() {}
>> void bar() { foo(); }
>>
>> .globl foo, bar
>> foo:
>> .Lfoo$local:
>> ret
>> bar:
>> call foo --> call .Lfoo$local
>> ret
>>
>> call foo generates an R_X86_64_PLT32. In a -shared link, it creates an
>> unneeded PLT entry for foo.
>>
>> call .Lfoo$local generates an R_X86_64_PLT32. In a -shared link, .Lfoo$local is
>> non-preemptible => no PLT entry is created.
>>
>> For -fno-PIC and -fPIE, the final link is expected to be -no-pie or
>> -pie. This optimization does not save anything, because PLT entries will
>> not be generated. With clang's integrated assembler, it may increase the
>> number of STT_SECTION symbols (because .Lfoo$local will be turned to a
>> STT_SECTION relative relocation), but the size increase is very small.
>>
>>
>> I want to teach clang -fPIC to use -fno-semantic-interposition by
>> default. (It is currently an LLVM optimization, not realized in clang.)
>> clang traditionally makes various -fno-semantic-interposition
>> assumptions and can perform interprocedural optimizations even if the
>> strict ELF rule disallows them.
>
>FWIW, gcc with no-semantic-interposition also uses local aliases, but
>rather than using .L labels, it creates a local alias by
> .set foo.localalias, foo
>This makes the type of foo.localalias the same as foo, which I gather
>should placate objtool as it'll still see an STT_FUNC no matter whether
>it picks up foo.localalias or foo.
The GCC approach costs more bytes. foo.localalias is not prefixed by .L,
thus it wastes sizeof(Elf*_Sym) bytes for each such function.
5: 0000000000401000 7 FUNC LOCAL DEFAULT 1 foo.localalias
Call/jump relocations on ARM and MIPS treat STT_FUNC differently.
If eventually we use the clang optimization for ARM and MIPS, we
probably should consider changing `.Lfoo$local:` to `.set .Lfoo$local, foo`
The assembler is quite complex. I need to investigate more into LLVM MC.
R_ARM_CALL/R_ARM_THM_CALL can be used against STT_NOTYPE symbols.
That disables interwork thunks (https://reviews.llvm.org/D73542).
If objtool is used by ARM and such disabling semantic is ever needed,
the rule should be loosened to allow STT_NOTYPE.
^ permalink raw reply
* Re: [PATCH v2 3/5] common/rc: introduce new helper function _fs_type_dev_dir()
From: Amir Goldstein @ 2020-02-14 22:20 UTC (permalink / raw)
To: Mauricio Faria de Oliveira; +Cc: fstests, overlayfs
In-Reply-To: <20200214151848.8328-4-mfo@canonical.com>
On Fri, Feb 14, 2020 at 5:18 PM Mauricio Faria de Oliveira
<mfo@canonical.com> wrote:
>
> In order to determine the fs type on fuse-overlayfs (coming)
> we need to search for the mount point/directory; the device
> is not enough. (details in the next patch.)
>
> Thus the _fs_type() function is insufficient to determine
> the filesystem type, as it only searches for mount device.
>
> So, introduce the _fs_type_dev_dir() function, which also
> searches for the mountpoint/dir in addition to the device.
>
> The fs type fix-up sed script goes into a common function.
>
> P.S.: there might be other sites that need similar changes,
> since the mount device is also checked elsewhere, but just
> with this bit tests can run, so it is good enough for now.)
>
> Signed-off-by: Mauricio Faria de Oliveira <mfo@canonical.com>
Looks ok.
You may add:
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
> ---
> common/rc | 36 ++++++++++++++++++++++++++++--------
> 1 file changed, 28 insertions(+), 8 deletions(-)
>
> diff --git a/common/rc b/common/rc
> index 1feae1a94f9e..5711eca2a1d2 100644
> --- a/common/rc
> +++ b/common/rc
> @@ -1262,6 +1262,19 @@ _used()
> _df_device $1 | $AWK_PROG '{ sub("%", "") ; print $6 }'
> }
>
> +# fix filesystem type up
> +#
> +_fix_fs_type()
> +{
> + #
> + # The Linux kernel shows NFSv4 filesystems in df output as
> + # filesystem type nfs4, although we mounted it as nfs earlier.
> + # Fix the filesystem type up here so that the callers don't
> + # have to bother with this quirk.
> + #
> + sed -e 's/nfs4/nfs/' -e 's/fuse.glusterfs/glusterfs/'
> +}
> +
> # return the FS type of a mounted device
> #
> _fs_type()
> @@ -1272,14 +1285,21 @@ _fs_type()
> exit 1
> fi
>
> - #
> - # The Linux kernel shows NFSv4 filesystems in df output as
> - # filesystem type nfs4, although we mounted it as nfs earlier.
> - # Fix the filesystem type up here so that the callers don't
> - # have to bother with this quirk.
> - #
> - _df_device $1 | $AWK_PROG '{ print $2 }' | \
> - sed -e 's/nfs4/nfs/' -e 's/fuse.glusterfs/glusterfs/'
> + _df_device $1 | $AWK_PROG '{ print $2 }' | _fix_fs_type
> +}
> +
> +# return the FS type of a mounted device
> +# on a mount point directory (check both)
> +#
> +_fs_type_dev_dir()
> +{
> + if [ $# -ne 2 ]
> + then
> + echo "Usage: _fs_type_dev_dir device directory" 1>&2
> + exit 1
> + fi
> +
> + _df_dir $2 | $AWK_PROG -v what=$1 '($1==what) { print $2 }' | _fix_fs_type
> }
>
> # return the FS mount options of a mounted device
> --
> 2.20.1
>
^ permalink raw reply
* Re: [PATCH v2 1/4] NFSD: Return eof and maxcount to nfsd4_encode_read()
From: Chuck Lever @ 2020-02-14 22:20 UTC (permalink / raw)
To: Anna Schumaker, Bruce Fields; +Cc: Linux NFS Mailing List, Anna Schumaker
In-Reply-To: <20200214211206.407725-2-Anna.Schumaker@Netapp.com>
> On Feb 14, 2020, at 4:12 PM, schumaker.anna@gmail.com wrote:
>
> From: Anna Schumaker <Anna.Schumaker@Netapp.com>
>
> I want to reuse nfsd4_encode_readv() and nfsd4_encode_splice_read() in
> READ_PLUS rather than reimplementing them. READ_PLUS returns a single
> eof flag for the entire call and a separate maxcount for each data
> segment, so we need to have the READ call encode these values in a
> different place.
This probably collides pretty nastily with the fix I posted today for
https://bugzilla.kernel.org/show_bug.cgi?id=198053 .
Can my fix go in first so that there is still opportunity to backport it?
> Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
> ---
> fs/nfsd/nfs4xdr.c | 60 ++++++++++++++++++++---------------------------
> 1 file changed, 26 insertions(+), 34 deletions(-)
>
> diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
> index 9761512674a0..45f0623f6488 100644
> --- a/fs/nfsd/nfs4xdr.c
> +++ b/fs/nfsd/nfs4xdr.c
> @@ -3521,23 +3521,22 @@ nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, __be32 nfserr, struc
>
> static __be32 nfsd4_encode_splice_read(
> struct nfsd4_compoundres *resp,
> - struct nfsd4_read *read,
> - struct file *file, unsigned long maxcount)
> + struct nfsd4_read *read, struct file *file,
> + unsigned long *maxcount, u32 *eof)
> {
> struct xdr_stream *xdr = &resp->xdr;
> struct xdr_buf *buf = xdr->buf;
> - u32 eof;
> + long len;
> int space_left;
> __be32 nfserr;
> - __be32 *p = xdr->p - 2;
>
> /* Make sure there will be room for padding if needed */
> if (xdr->end - xdr->p < 1)
> return nfserr_resource;
>
> + len = *maxcount;
> nfserr = nfsd_splice_read(read->rd_rqstp, read->rd_fhp,
> - file, read->rd_offset, &maxcount, &eof);
> - read->rd_length = maxcount;
> + file, read->rd_offset, maxcount, eof);
> if (nfserr) {
> /*
> * nfsd_splice_actor may have already messed with the
> @@ -3548,24 +3547,21 @@ static __be32 nfsd4_encode_splice_read(
> return nfserr;
> }
>
> - *(p++) = htonl(eof);
> - *(p++) = htonl(maxcount);
> -
> - buf->page_len = maxcount;
> - buf->len += maxcount;
> - xdr->page_ptr += (buf->page_base + maxcount + PAGE_SIZE - 1)
> + buf->page_len = *maxcount;
> + buf->len += *maxcount;
> + xdr->page_ptr += (buf->page_base + *maxcount + PAGE_SIZE - 1)
> / PAGE_SIZE;
>
> /* Use rest of head for padding and remaining ops: */
> buf->tail[0].iov_base = xdr->p;
> buf->tail[0].iov_len = 0;
> xdr->iov = buf->tail;
> - if (maxcount&3) {
> - int pad = 4 - (maxcount&3);
> + if (*maxcount&3) {
> + int pad = 4 - (*maxcount&3);
>
> *(xdr->p++) = 0;
>
> - buf->tail[0].iov_base += maxcount&3;
> + buf->tail[0].iov_base += *maxcount&3;
> buf->tail[0].iov_len = pad;
> buf->len += pad;
> }
> @@ -3579,22 +3575,20 @@ static __be32 nfsd4_encode_splice_read(
> }
>
> static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp,
> - struct nfsd4_read *read,
> - struct file *file, unsigned long maxcount)
> + struct nfsd4_read *read, struct file *file,
> + unsigned long *maxcount, u32 *eof)
> {
> struct xdr_stream *xdr = &resp->xdr;
> - u32 eof;
> int v;
> int starting_len = xdr->buf->len - 8;
> long len;
> int thislen;
> __be32 nfserr;
> - __be32 tmp;
> __be32 *p;
> u32 zzz = 0;
> int pad;
>
> - len = maxcount;
> + len = *maxcount;
> v = 0;
>
> thislen = min_t(long, len, ((void *)xdr->end - (void *)xdr->p));
> @@ -3616,22 +3610,15 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp,
> }
> read->rd_vlen = v;
>
> - len = maxcount;
> + len = *maxcount;
> nfserr = nfsd_readv(resp->rqstp, read->rd_fhp, file, read->rd_offset,
> - resp->rqstp->rq_vec, read->rd_vlen, &maxcount,
> - &eof);
> - read->rd_length = maxcount;
> + resp->rqstp->rq_vec, read->rd_vlen, maxcount, eof);
> if (nfserr)
> return nfserr;
> - xdr_truncate_encode(xdr, starting_len + 8 + ((maxcount+3)&~3));
> + xdr_truncate_encode(xdr, starting_len + 8 + ((*maxcount+3)&~3));
>
> - tmp = htonl(eof);
> - write_bytes_to_xdr_buf(xdr->buf, starting_len , &tmp, 4);
> - tmp = htonl(maxcount);
> - write_bytes_to_xdr_buf(xdr->buf, starting_len + 4, &tmp, 4);
> -
> - pad = (maxcount&3) ? 4 - (maxcount&3) : 0;
> - write_bytes_to_xdr_buf(xdr->buf, starting_len + 8 + maxcount,
> + pad = (*maxcount&3) ? 4 - (*maxcount&3) : 0;
> + write_bytes_to_xdr_buf(xdr->buf, starting_len + 8 + *maxcount,
> &zzz, pad);
> return 0;
>
> @@ -3642,6 +3629,7 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
> struct nfsd4_read *read)
> {
> unsigned long maxcount;
> + u32 eof;
> struct xdr_stream *xdr = &resp->xdr;
> struct file *file;
> int starting_len = xdr->buf->len;
> @@ -3670,13 +3658,17 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
>
> if (file->f_op->splice_read &&
> test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags))
> - nfserr = nfsd4_encode_splice_read(resp, read, file, maxcount);
> + nfserr = nfsd4_encode_splice_read(resp, read, file, &maxcount, &eof);
> else
> - nfserr = nfsd4_encode_readv(resp, read, file, maxcount);
> + nfserr = nfsd4_encode_readv(resp, read, file, &maxcount, &eof);
>
> if (nfserr)
> xdr_truncate_encode(xdr, starting_len);
>
> + read->rd_length = maxcount;
> + *p++ = htonl(eof);
> + *p++ = htonl(maxcount);
> +
> return nfserr;
> }
>
> --
> 2.25.0
>
--
Chuck Lever
^ permalink raw reply
* Re: [PATCH v2 2/2] drm/bridge: anx7688: Add anx7688 bridge driver support
From: Enric Balletbo Serra @ 2020-02-14 22:20 UTC (permalink / raw)
To: Vasily Khoruzhick
Cc: Icenowy Zheng, Enric Balletbo i Serra, Jernej Skrabec,
Nicolas Boichat, Laurent Pinchart, Neil Armstrong, David Airlie,
Torsten Duwe, Jonas Karlman, linux-kernel, dri-devel,
Andrzej Hajda, Maxime Ripard, Hsin-Yi Wang, Matthias Brugger,
Thomas Gleixner, Collabora Kernel ML
In-Reply-To: <CA+E=qVfGiQseZZVBvmmK6u2Mu=-91ViwLuhNegu96KRZNAHr_w@mail.gmail.com>
Hi Vasily,
Missatge de Vasily Khoruzhick <anarsoul@gmail.com> del dia dv., 14 de
febr. 2020 a les 23:17:
>
> On Fri, Feb 14, 2020 at 1:53 PM Enric Balletbo Serra
> <eballetbo@gmail.com> wrote:
> >
> > Hi Vasily,
> >
> > Missatge de Vasily Khoruzhick <anarsoul@gmail.com> del dia dv., 14 de
> > febr. 2020 a les 22:36:
> > >
> > > On Thu, Feb 13, 2020 at 6:54 AM Enric Balletbo i Serra
> > > <enric.balletbo@collabora.com> wrote:
> > > >
> > > > From: Nicolas Boichat <drinkcat@chromium.org>
> > > >
> > > > ANX7688 is a HDMI to DP converter (as well as USB-C port controller),
> > > > that has an internal microcontroller.
> > > >
> > > > The only reason a Linux kernel driver is necessary is to reject
> > > > resolutions that require more bandwidth than what is available on
> > > > the DP side. DP bandwidth and lane count are reported by the bridge
> > > > via 2 registers on I2C.
> > >
> > > It is true only for your particular platform where usb-c part is
> > > managed by firmware. Pinephone has the same anx7688 but linux will
> > > need a driver that manages usb-c in addition to DP.
> > >
> > > I'd suggest making it MFD driver from the beginning, or at least make
> > > proper bindings so we don't have to rework it and introduce binding
> > > incompatibilities in future.
> > >
> >
> > Do you have example code on how the ANX7866 is used in pinephone?
> > There is a repo somewhere?
>
> I don't think it's implemented yet. I've CCed Icenowy in case if she
> has anything.
>
It would be good to join the effort. Just because I am curious, there
are public schematics for the pinephone that is using that bridge?
> > Thanks,
> > Enric
> >
> > > > Signed-off-by: Nicolas Boichat <drinkcat@chromium.org>
> > > > Signed-off-by: Hsin-Yi Wang <hsinyi@chromium.org>
> > > > Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> > > > ---
> > > >
> > > > Changes in v2:
> > > > - Move driver to drivers/gpu/drm/bridge/analogix.
> > > > - Make the driver OF only so we can reduce the ifdefs.
> > > > - Update the Copyright to 2020.
> > > > - Use probe_new so we can get rid of the i2c_device_id table.
> > > >
> > > > drivers/gpu/drm/bridge/analogix/Kconfig | 12 ++
> > > > drivers/gpu/drm/bridge/analogix/Makefile | 1 +
> > > > .../drm/bridge/analogix/analogix-anx7688.c | 188 ++++++++++++++++++
> > > > 3 files changed, 201 insertions(+)
> > > > create mode 100644 drivers/gpu/drm/bridge/analogix/analogix-anx7688.c
> > > >
> > > > diff --git a/drivers/gpu/drm/bridge/analogix/Kconfig b/drivers/gpu/drm/bridge/analogix/Kconfig
> > > > index e1fa7d820373..af7c2939403c 100644
> > > > --- a/drivers/gpu/drm/bridge/analogix/Kconfig
> > > > +++ b/drivers/gpu/drm/bridge/analogix/Kconfig
> > > > @@ -11,6 +11,18 @@ config DRM_ANALOGIX_ANX6345
> > > > ANX6345 transforms the LVTTL RGB output of an
> > > > application processor to eDP or DisplayPort.
> > > >
> > > > +config DRM_ANALOGIX_ANX7688
> > > > + tristate "Analogix ANX7688 bridge"
> > > > + depends on OF
> > > > + select DRM_KMS_HELPER
> > > > + select REGMAP_I2C
> > > > + help
> > > > + ANX7688 is an ultra-low power 4k Ultra-HD (4096x2160p60)
> > > > + mobile HD transmitter designed for portable devices. The
> > > > + ANX7688 converts HDMI 2.0 to DisplayPort 1.3 Ultra-HD
> > > > + including an intelligent crosspoint switch to support
> > > > + USB Type-C.
> > > > +
> > > > config DRM_ANALOGIX_ANX78XX
> > > > tristate "Analogix ANX78XX bridge"
> > > > select DRM_ANALOGIX_DP
> > > > diff --git a/drivers/gpu/drm/bridge/analogix/Makefile b/drivers/gpu/drm/bridge/analogix/Makefile
> > > > index 97669b374098..27cd73635c8c 100644
> > > > --- a/drivers/gpu/drm/bridge/analogix/Makefile
> > > > +++ b/drivers/gpu/drm/bridge/analogix/Makefile
> > > > @@ -1,5 +1,6 @@
> > > > # SPDX-License-Identifier: GPL-2.0-only
> > > > analogix_dp-objs := analogix_dp_core.o analogix_dp_reg.o analogix-i2c-dptx.o
> > > > obj-$(CONFIG_DRM_ANALOGIX_ANX6345) += analogix-anx6345.o
> > > > +obj-$(CONFIG_DRM_ANALOGIX_ANX7688) += analogix-anx7688.o
> > > > obj-$(CONFIG_DRM_ANALOGIX_ANX78XX) += analogix-anx78xx.o
> > > > obj-$(CONFIG_DRM_ANALOGIX_DP) += analogix_dp.o
> > > > diff --git a/drivers/gpu/drm/bridge/analogix/analogix-anx7688.c b/drivers/gpu/drm/bridge/analogix/analogix-anx7688.c
> > > > new file mode 100644
> > > > index 000000000000..10a7cd0f9126
> > > > --- /dev/null
> > > > +++ b/drivers/gpu/drm/bridge/analogix/analogix-anx7688.c
> > > > @@ -0,0 +1,188 @@
> > > > +// SPDX-License-Identifier: GPL-2.0-only
> > > > +/*
> > > > + * ANX7688 HDMI->DP bridge driver
> > > > + *
> > > > + * Copyright 2020 Google LLC
> > > > + */
> > > > +
> > > > +#include <linux/i2c.h>
> > > > +#include <linux/module.h>
> > > > +#include <linux/regmap.h>
> > > > +#include <drm/drm_bridge.h>
> > > > +
> > > > +/* Register addresses */
> > > > +#define VENDOR_ID_REG 0x00
> > > > +#define DEVICE_ID_REG 0x02
> > > > +
> > > > +#define FW_VERSION_REG 0x80
> > > > +
> > > > +#define DP_BANDWIDTH_REG 0x85
> > > > +#define DP_LANE_COUNT_REG 0x86
> > > > +
> > > > +#define VENDOR_ID 0x1f29
> > > > +#define DEVICE_ID 0x7688
> > > > +
> > > > +/* First supported firmware version (0.85) */
> > > > +#define MINIMUM_FW_VERSION 0x0085
> > > > +
> > > > +struct anx7688 {
> > > > + struct drm_bridge bridge;
> > > > + struct i2c_client *client;
> > > > + struct regmap *regmap;
> > > > +
> > > > + bool filter;
> > > > +};
> > > > +
> > > > +static inline struct anx7688 *bridge_to_anx7688(struct drm_bridge *bridge)
> > > > +{
> > > > + return container_of(bridge, struct anx7688, bridge);
> > > > +}
> > > > +
> > > > +static bool anx7688_bridge_mode_fixup(struct drm_bridge *bridge,
> > > > + const struct drm_display_mode *mode,
> > > > + struct drm_display_mode *adjusted_mode)
> > > > +{
> > > > + struct anx7688 *anx7688 = bridge_to_anx7688(bridge);
> > > > + int totalbw, requiredbw;
> > > > + u8 dpbw, lanecount;
> > > > + u8 regs[2];
> > > > + int ret;
> > > > +
> > > > + if (!anx7688->filter)
> > > > + return true;
> > > > +
> > > > + /* Read both regs 0x85 (bandwidth) and 0x86 (lane count). */
> > > > + ret = regmap_bulk_read(anx7688->regmap, DP_BANDWIDTH_REG, regs, 2);
> > > > + if (ret < 0) {
> > > > + dev_err(&anx7688->client->dev,
> > > > + "Failed to read bandwidth/lane count\n");
> > > > + return false;
> > > > + }
> > > > + dpbw = regs[0];
> > > > + lanecount = regs[1];
> > > > +
> > > > + /* Maximum 0x19 bandwidth (6.75 Gbps Turbo mode), 2 lanes */
> > > > + if (dpbw > 0x19 || lanecount > 2) {
> > > > + dev_err(&anx7688->client->dev,
> > > > + "Invalid bandwidth/lane count (%02x/%d)\n",
> > > > + dpbw, lanecount);
> > > > + return false;
> > > > + }
> > > > +
> > > > + /* Compute available bandwidth (kHz) */
> > > > + totalbw = dpbw * lanecount * 270000 * 8 / 10;
> > > > +
> > > > + /* Required bandwidth (8 bpc, kHz) */
> > > > + requiredbw = mode->clock * 8 * 3;
> > > > +
> > > > + dev_dbg(&anx7688->client->dev,
> > > > + "DP bandwidth: %d kHz (%02x/%d); mode requires %d Khz\n",
> > > > + totalbw, dpbw, lanecount, requiredbw);
> > > > +
> > > > + if (totalbw == 0) {
> > > > + dev_warn(&anx7688->client->dev,
> > > > + "Bandwidth/lane count are 0, not rejecting modes\n");
> > > > + return true;
> > > > + }
> > > > +
> > > > + return totalbw >= requiredbw;
> > > > +}
> > > > +
> > > > +static const struct drm_bridge_funcs anx7688_bridge_funcs = {
> > > > + .mode_fixup = anx7688_bridge_mode_fixup,
> > > > +};
> > > > +
> > > > +static const struct regmap_config anx7688_regmap_config = {
> > > > + .reg_bits = 8,
> > > > + .val_bits = 8,
> > > > +};
> > > > +
> > > > +static int anx7688_i2c_probe(struct i2c_client *client)
> > > > +{
> > > > + struct device *dev = &client->dev;
> > > > + struct anx7688 *anx7688;
> > > > + u16 vendor, device;
> > > > + u16 fwversion;
> > > > + u8 buffer[4];
> > > > + int ret;
> > > > +
> > > > + anx7688 = devm_kzalloc(dev, sizeof(*anx7688), GFP_KERNEL);
> > > > + if (!anx7688)
> > > > + return -ENOMEM;
> > > > +
> > > > + anx7688->bridge.of_node = dev->of_node;
> > > > + anx7688->client = client;
> > > > + i2c_set_clientdata(client, anx7688);
> > > > +
> > > > + anx7688->regmap = devm_regmap_init_i2c(client, &anx7688_regmap_config);
> > > > +
> > > > + /* Read both vendor and device id (4 bytes). */
> > > > + ret = regmap_bulk_read(anx7688->regmap, VENDOR_ID_REG, buffer, 4);
> > > > + if (ret) {
> > > > + dev_err(dev, "Failed to read chip vendor/device id\n");
> > > > + return ret;
> > > > + }
> > > > +
> > > > + vendor = (u16)buffer[1] << 8 | buffer[0];
> > > > + device = (u16)buffer[3] << 8 | buffer[2];
> > > > + if (vendor != VENDOR_ID || device != DEVICE_ID) {
> > > > + dev_err(dev, "Invalid vendor/device id %04x/%04x\n",
> > > > + vendor, device);
> > > > + return -ENODEV;
> > > > + }
> > > > +
> > > > + ret = regmap_bulk_read(anx7688->regmap, FW_VERSION_REG, buffer, 2);
> > > > + if (ret) {
> > > > + dev_err(&client->dev, "Failed to read firmware version\n");
> > > > + return ret;
> > > > + }
> > > > +
> > > > + fwversion = (u16)buffer[0] << 8 | buffer[1];
> > > > + dev_info(dev, "ANX7688 firwmare version %02x.%02x\n",
> > > > + buffer[0], buffer[1]);
> > > > +
> > > > + /* FW version >= 0.85 supports bandwidth/lane count registers */
> > > > + if (fwversion >= MINIMUM_FW_VERSION) {
> > > > + anx7688->filter = true;
> > > > + } else {
> > > > + /* Warn, but not fail, for backwards compatibility. */
> > > > + dev_warn(dev,
> > > > + "Old ANX7688 FW version (%02x.%02x), not filtering\n",
> > > > + buffer[0], buffer[1]);
> > > > + }
> > > > +
> > > > + anx7688->bridge.funcs = &anx7688_bridge_funcs;
> > > > + drm_bridge_add(&anx7688->bridge);
> > > > +
> > > > + return 0;
> > > > +}
> > > > +
> > > > +static int anx7688_i2c_remove(struct i2c_client *client)
> > > > +{
> > > > + struct anx7688 *anx7688 = i2c_get_clientdata(client);
> > > > +
> > > > + drm_bridge_remove(&anx7688->bridge);
> > > > +
> > > > + return 0;
> > > > +}
> > > > +
> > > > +static const struct of_device_id anx7688_match_table[] = {
> > > > + { .compatible = "analogix,anx7688", },
> > > > + { }
> > > > +};
> > > > +MODULE_DEVICE_TABLE(of, anx7688_match_table);
> > > > +
> > > > +static struct i2c_driver anx7688_driver = {
> > > > + .probe_new = anx7688_i2c_probe,
> > > > + .remove = anx7688_i2c_remove,
> > > > + .driver = {
> > > > + .name = "anx7688",
> > > > + .of_match_table = anx7688_match_table,
> > > > + },
> > > > +};
> > > > +
> > > > +module_i2c_driver(anx7688_driver);
> > > > +
> > > > +MODULE_DESCRIPTION("ANX7688 HDMI->DP bridge driver");
> > > > +MODULE_AUTHOR("Nicolas Boichat <drinkcat@chromium.org>");
> > > > +MODULE_LICENSE("GPL");
> > > > --
> > > > 2.25.0
> > > >
> > > _______________________________________________
> > > dri-devel mailing list
> > > dri-devel@lists.freedesktop.org
> > > https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply
* Re: [PATCH v2 2/2] drm/bridge: anx7688: Add anx7688 bridge driver support
From: Enric Balletbo Serra @ 2020-02-14 22:20 UTC (permalink / raw)
To: Vasily Khoruzhick
Cc: Jernej Skrabec, Nicolas Boichat, Maxime Ripard, Neil Armstrong,
David Airlie, Torsten Duwe, Jonas Karlman, linux-kernel,
dri-devel, Andrzej Hajda, Matthias Brugger, Laurent Pinchart,
Hsin-Yi Wang, Enric Balletbo i Serra, Thomas Gleixner,
Collabora Kernel ML, Icenowy Zheng
In-Reply-To: <CA+E=qVfGiQseZZVBvmmK6u2Mu=-91ViwLuhNegu96KRZNAHr_w@mail.gmail.com>
Hi Vasily,
Missatge de Vasily Khoruzhick <anarsoul@gmail.com> del dia dv., 14 de
febr. 2020 a les 23:17:
>
> On Fri, Feb 14, 2020 at 1:53 PM Enric Balletbo Serra
> <eballetbo@gmail.com> wrote:
> >
> > Hi Vasily,
> >
> > Missatge de Vasily Khoruzhick <anarsoul@gmail.com> del dia dv., 14 de
> > febr. 2020 a les 22:36:
> > >
> > > On Thu, Feb 13, 2020 at 6:54 AM Enric Balletbo i Serra
> > > <enric.balletbo@collabora.com> wrote:
> > > >
> > > > From: Nicolas Boichat <drinkcat@chromium.org>
> > > >
> > > > ANX7688 is a HDMI to DP converter (as well as USB-C port controller),
> > > > that has an internal microcontroller.
> > > >
> > > > The only reason a Linux kernel driver is necessary is to reject
> > > > resolutions that require more bandwidth than what is available on
> > > > the DP side. DP bandwidth and lane count are reported by the bridge
> > > > via 2 registers on I2C.
> > >
> > > It is true only for your particular platform where usb-c part is
> > > managed by firmware. Pinephone has the same anx7688 but linux will
> > > need a driver that manages usb-c in addition to DP.
> > >
> > > I'd suggest making it MFD driver from the beginning, or at least make
> > > proper bindings so we don't have to rework it and introduce binding
> > > incompatibilities in future.
> > >
> >
> > Do you have example code on how the ANX7866 is used in pinephone?
> > There is a repo somewhere?
>
> I don't think it's implemented yet. I've CCed Icenowy in case if she
> has anything.
>
It would be good to join the effort. Just because I am curious, there
are public schematics for the pinephone that is using that bridge?
> > Thanks,
> > Enric
> >
> > > > Signed-off-by: Nicolas Boichat <drinkcat@chromium.org>
> > > > Signed-off-by: Hsin-Yi Wang <hsinyi@chromium.org>
> > > > Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> > > > ---
> > > >
> > > > Changes in v2:
> > > > - Move driver to drivers/gpu/drm/bridge/analogix.
> > > > - Make the driver OF only so we can reduce the ifdefs.
> > > > - Update the Copyright to 2020.
> > > > - Use probe_new so we can get rid of the i2c_device_id table.
> > > >
> > > > drivers/gpu/drm/bridge/analogix/Kconfig | 12 ++
> > > > drivers/gpu/drm/bridge/analogix/Makefile | 1 +
> > > > .../drm/bridge/analogix/analogix-anx7688.c | 188 ++++++++++++++++++
> > > > 3 files changed, 201 insertions(+)
> > > > create mode 100644 drivers/gpu/drm/bridge/analogix/analogix-anx7688.c
> > > >
> > > > diff --git a/drivers/gpu/drm/bridge/analogix/Kconfig b/drivers/gpu/drm/bridge/analogix/Kconfig
> > > > index e1fa7d820373..af7c2939403c 100644
> > > > --- a/drivers/gpu/drm/bridge/analogix/Kconfig
> > > > +++ b/drivers/gpu/drm/bridge/analogix/Kconfig
> > > > @@ -11,6 +11,18 @@ config DRM_ANALOGIX_ANX6345
> > > > ANX6345 transforms the LVTTL RGB output of an
> > > > application processor to eDP or DisplayPort.
> > > >
> > > > +config DRM_ANALOGIX_ANX7688
> > > > + tristate "Analogix ANX7688 bridge"
> > > > + depends on OF
> > > > + select DRM_KMS_HELPER
> > > > + select REGMAP_I2C
> > > > + help
> > > > + ANX7688 is an ultra-low power 4k Ultra-HD (4096x2160p60)
> > > > + mobile HD transmitter designed for portable devices. The
> > > > + ANX7688 converts HDMI 2.0 to DisplayPort 1.3 Ultra-HD
> > > > + including an intelligent crosspoint switch to support
> > > > + USB Type-C.
> > > > +
> > > > config DRM_ANALOGIX_ANX78XX
> > > > tristate "Analogix ANX78XX bridge"
> > > > select DRM_ANALOGIX_DP
> > > > diff --git a/drivers/gpu/drm/bridge/analogix/Makefile b/drivers/gpu/drm/bridge/analogix/Makefile
> > > > index 97669b374098..27cd73635c8c 100644
> > > > --- a/drivers/gpu/drm/bridge/analogix/Makefile
> > > > +++ b/drivers/gpu/drm/bridge/analogix/Makefile
> > > > @@ -1,5 +1,6 @@
> > > > # SPDX-License-Identifier: GPL-2.0-only
> > > > analogix_dp-objs := analogix_dp_core.o analogix_dp_reg.o analogix-i2c-dptx.o
> > > > obj-$(CONFIG_DRM_ANALOGIX_ANX6345) += analogix-anx6345.o
> > > > +obj-$(CONFIG_DRM_ANALOGIX_ANX7688) += analogix-anx7688.o
> > > > obj-$(CONFIG_DRM_ANALOGIX_ANX78XX) += analogix-anx78xx.o
> > > > obj-$(CONFIG_DRM_ANALOGIX_DP) += analogix_dp.o
> > > > diff --git a/drivers/gpu/drm/bridge/analogix/analogix-anx7688.c b/drivers/gpu/drm/bridge/analogix/analogix-anx7688.c
> > > > new file mode 100644
> > > > index 000000000000..10a7cd0f9126
> > > > --- /dev/null
> > > > +++ b/drivers/gpu/drm/bridge/analogix/analogix-anx7688.c
> > > > @@ -0,0 +1,188 @@
> > > > +// SPDX-License-Identifier: GPL-2.0-only
> > > > +/*
> > > > + * ANX7688 HDMI->DP bridge driver
> > > > + *
> > > > + * Copyright 2020 Google LLC
> > > > + */
> > > > +
> > > > +#include <linux/i2c.h>
> > > > +#include <linux/module.h>
> > > > +#include <linux/regmap.h>
> > > > +#include <drm/drm_bridge.h>
> > > > +
> > > > +/* Register addresses */
> > > > +#define VENDOR_ID_REG 0x00
> > > > +#define DEVICE_ID_REG 0x02
> > > > +
> > > > +#define FW_VERSION_REG 0x80
> > > > +
> > > > +#define DP_BANDWIDTH_REG 0x85
> > > > +#define DP_LANE_COUNT_REG 0x86
> > > > +
> > > > +#define VENDOR_ID 0x1f29
> > > > +#define DEVICE_ID 0x7688
> > > > +
> > > > +/* First supported firmware version (0.85) */
> > > > +#define MINIMUM_FW_VERSION 0x0085
> > > > +
> > > > +struct anx7688 {
> > > > + struct drm_bridge bridge;
> > > > + struct i2c_client *client;
> > > > + struct regmap *regmap;
> > > > +
> > > > + bool filter;
> > > > +};
> > > > +
> > > > +static inline struct anx7688 *bridge_to_anx7688(struct drm_bridge *bridge)
> > > > +{
> > > > + return container_of(bridge, struct anx7688, bridge);
> > > > +}
> > > > +
> > > > +static bool anx7688_bridge_mode_fixup(struct drm_bridge *bridge,
> > > > + const struct drm_display_mode *mode,
> > > > + struct drm_display_mode *adjusted_mode)
> > > > +{
> > > > + struct anx7688 *anx7688 = bridge_to_anx7688(bridge);
> > > > + int totalbw, requiredbw;
> > > > + u8 dpbw, lanecount;
> > > > + u8 regs[2];
> > > > + int ret;
> > > > +
> > > > + if (!anx7688->filter)
> > > > + return true;
> > > > +
> > > > + /* Read both regs 0x85 (bandwidth) and 0x86 (lane count). */
> > > > + ret = regmap_bulk_read(anx7688->regmap, DP_BANDWIDTH_REG, regs, 2);
> > > > + if (ret < 0) {
> > > > + dev_err(&anx7688->client->dev,
> > > > + "Failed to read bandwidth/lane count\n");
> > > > + return false;
> > > > + }
> > > > + dpbw = regs[0];
> > > > + lanecount = regs[1];
> > > > +
> > > > + /* Maximum 0x19 bandwidth (6.75 Gbps Turbo mode), 2 lanes */
> > > > + if (dpbw > 0x19 || lanecount > 2) {
> > > > + dev_err(&anx7688->client->dev,
> > > > + "Invalid bandwidth/lane count (%02x/%d)\n",
> > > > + dpbw, lanecount);
> > > > + return false;
> > > > + }
> > > > +
> > > > + /* Compute available bandwidth (kHz) */
> > > > + totalbw = dpbw * lanecount * 270000 * 8 / 10;
> > > > +
> > > > + /* Required bandwidth (8 bpc, kHz) */
> > > > + requiredbw = mode->clock * 8 * 3;
> > > > +
> > > > + dev_dbg(&anx7688->client->dev,
> > > > + "DP bandwidth: %d kHz (%02x/%d); mode requires %d Khz\n",
> > > > + totalbw, dpbw, lanecount, requiredbw);
> > > > +
> > > > + if (totalbw == 0) {
> > > > + dev_warn(&anx7688->client->dev,
> > > > + "Bandwidth/lane count are 0, not rejecting modes\n");
> > > > + return true;
> > > > + }
> > > > +
> > > > + return totalbw >= requiredbw;
> > > > +}
> > > > +
> > > > +static const struct drm_bridge_funcs anx7688_bridge_funcs = {
> > > > + .mode_fixup = anx7688_bridge_mode_fixup,
> > > > +};
> > > > +
> > > > +static const struct regmap_config anx7688_regmap_config = {
> > > > + .reg_bits = 8,
> > > > + .val_bits = 8,
> > > > +};
> > > > +
> > > > +static int anx7688_i2c_probe(struct i2c_client *client)
> > > > +{
> > > > + struct device *dev = &client->dev;
> > > > + struct anx7688 *anx7688;
> > > > + u16 vendor, device;
> > > > + u16 fwversion;
> > > > + u8 buffer[4];
> > > > + int ret;
> > > > +
> > > > + anx7688 = devm_kzalloc(dev, sizeof(*anx7688), GFP_KERNEL);
> > > > + if (!anx7688)
> > > > + return -ENOMEM;
> > > > +
> > > > + anx7688->bridge.of_node = dev->of_node;
> > > > + anx7688->client = client;
> > > > + i2c_set_clientdata(client, anx7688);
> > > > +
> > > > + anx7688->regmap = devm_regmap_init_i2c(client, &anx7688_regmap_config);
> > > > +
> > > > + /* Read both vendor and device id (4 bytes). */
> > > > + ret = regmap_bulk_read(anx7688->regmap, VENDOR_ID_REG, buffer, 4);
> > > > + if (ret) {
> > > > + dev_err(dev, "Failed to read chip vendor/device id\n");
> > > > + return ret;
> > > > + }
> > > > +
> > > > + vendor = (u16)buffer[1] << 8 | buffer[0];
> > > > + device = (u16)buffer[3] << 8 | buffer[2];
> > > > + if (vendor != VENDOR_ID || device != DEVICE_ID) {
> > > > + dev_err(dev, "Invalid vendor/device id %04x/%04x\n",
> > > > + vendor, device);
> > > > + return -ENODEV;
> > > > + }
> > > > +
> > > > + ret = regmap_bulk_read(anx7688->regmap, FW_VERSION_REG, buffer, 2);
> > > > + if (ret) {
> > > > + dev_err(&client->dev, "Failed to read firmware version\n");
> > > > + return ret;
> > > > + }
> > > > +
> > > > + fwversion = (u16)buffer[0] << 8 | buffer[1];
> > > > + dev_info(dev, "ANX7688 firwmare version %02x.%02x\n",
> > > > + buffer[0], buffer[1]);
> > > > +
> > > > + /* FW version >= 0.85 supports bandwidth/lane count registers */
> > > > + if (fwversion >= MINIMUM_FW_VERSION) {
> > > > + anx7688->filter = true;
> > > > + } else {
> > > > + /* Warn, but not fail, for backwards compatibility. */
> > > > + dev_warn(dev,
> > > > + "Old ANX7688 FW version (%02x.%02x), not filtering\n",
> > > > + buffer[0], buffer[1]);
> > > > + }
> > > > +
> > > > + anx7688->bridge.funcs = &anx7688_bridge_funcs;
> > > > + drm_bridge_add(&anx7688->bridge);
> > > > +
> > > > + return 0;
> > > > +}
> > > > +
> > > > +static int anx7688_i2c_remove(struct i2c_client *client)
> > > > +{
> > > > + struct anx7688 *anx7688 = i2c_get_clientdata(client);
> > > > +
> > > > + drm_bridge_remove(&anx7688->bridge);
> > > > +
> > > > + return 0;
> > > > +}
> > > > +
> > > > +static const struct of_device_id anx7688_match_table[] = {
> > > > + { .compatible = "analogix,anx7688", },
> > > > + { }
> > > > +};
> > > > +MODULE_DEVICE_TABLE(of, anx7688_match_table);
> > > > +
> > > > +static struct i2c_driver anx7688_driver = {
> > > > + .probe_new = anx7688_i2c_probe,
> > > > + .remove = anx7688_i2c_remove,
> > > > + .driver = {
> > > > + .name = "anx7688",
> > > > + .of_match_table = anx7688_match_table,
> > > > + },
> > > > +};
> > > > +
> > > > +module_i2c_driver(anx7688_driver);
> > > > +
> > > > +MODULE_DESCRIPTION("ANX7688 HDMI->DP bridge driver");
> > > > +MODULE_AUTHOR("Nicolas Boichat <drinkcat@chromium.org>");
> > > > +MODULE_LICENSE("GPL");
> > > > --
> > > > 2.25.0
> > > >
> > > _______________________________________________
> > > dri-devel mailing list
> > > dri-devel@lists.freedesktop.org
> > > https://lists.freedesktop.org/mailman/listinfo/dri-devel
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply
* Re: [PATCH v2 2/2] drm/bridge: anx7688: Add anx7688 bridge driver support
From: Vasily Khoruzhick @ 2020-02-14 22:17 UTC (permalink / raw)
To: Enric Balletbo Serra, Icenowy Zheng
Cc: Enric Balletbo i Serra, Jernej Skrabec, Nicolas Boichat,
Laurent Pinchart, Neil Armstrong, David Airlie, Torsten Duwe,
Jonas Karlman, linux-kernel, dri-devel, Andrzej Hajda,
Maxime Ripard, Hsin-Yi Wang, Matthias Brugger, Thomas Gleixner,
Collabora Kernel ML
In-Reply-To: <CAFqH_53crnC6hLExNgQRjMgtO+TLJjT6uzA4g8WXvy7NkwHcJg@mail.gmail.com>
On Fri, Feb 14, 2020 at 1:53 PM Enric Balletbo Serra
<eballetbo@gmail.com> wrote:
>
> Hi Vasily,
>
> Missatge de Vasily Khoruzhick <anarsoul@gmail.com> del dia dv., 14 de
> febr. 2020 a les 22:36:
> >
> > On Thu, Feb 13, 2020 at 6:54 AM Enric Balletbo i Serra
> > <enric.balletbo@collabora.com> wrote:
> > >
> > > From: Nicolas Boichat <drinkcat@chromium.org>
> > >
> > > ANX7688 is a HDMI to DP converter (as well as USB-C port controller),
> > > that has an internal microcontroller.
> > >
> > > The only reason a Linux kernel driver is necessary is to reject
> > > resolutions that require more bandwidth than what is available on
> > > the DP side. DP bandwidth and lane count are reported by the bridge
> > > via 2 registers on I2C.
> >
> > It is true only for your particular platform where usb-c part is
> > managed by firmware. Pinephone has the same anx7688 but linux will
> > need a driver that manages usb-c in addition to DP.
> >
> > I'd suggest making it MFD driver from the beginning, or at least make
> > proper bindings so we don't have to rework it and introduce binding
> > incompatibilities in future.
> >
>
> Do you have example code on how the ANX7866 is used in pinephone?
> There is a repo somewhere?
I don't think it's implemented yet. I've CCed Icenowy in case if she
has anything.
> Thanks,
> Enric
>
> > > Signed-off-by: Nicolas Boichat <drinkcat@chromium.org>
> > > Signed-off-by: Hsin-Yi Wang <hsinyi@chromium.org>
> > > Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> > > ---
> > >
> > > Changes in v2:
> > > - Move driver to drivers/gpu/drm/bridge/analogix.
> > > - Make the driver OF only so we can reduce the ifdefs.
> > > - Update the Copyright to 2020.
> > > - Use probe_new so we can get rid of the i2c_device_id table.
> > >
> > > drivers/gpu/drm/bridge/analogix/Kconfig | 12 ++
> > > drivers/gpu/drm/bridge/analogix/Makefile | 1 +
> > > .../drm/bridge/analogix/analogix-anx7688.c | 188 ++++++++++++++++++
> > > 3 files changed, 201 insertions(+)
> > > create mode 100644 drivers/gpu/drm/bridge/analogix/analogix-anx7688.c
> > >
> > > diff --git a/drivers/gpu/drm/bridge/analogix/Kconfig b/drivers/gpu/drm/bridge/analogix/Kconfig
> > > index e1fa7d820373..af7c2939403c 100644
> > > --- a/drivers/gpu/drm/bridge/analogix/Kconfig
> > > +++ b/drivers/gpu/drm/bridge/analogix/Kconfig
> > > @@ -11,6 +11,18 @@ config DRM_ANALOGIX_ANX6345
> > > ANX6345 transforms the LVTTL RGB output of an
> > > application processor to eDP or DisplayPort.
> > >
> > > +config DRM_ANALOGIX_ANX7688
> > > + tristate "Analogix ANX7688 bridge"
> > > + depends on OF
> > > + select DRM_KMS_HELPER
> > > + select REGMAP_I2C
> > > + help
> > > + ANX7688 is an ultra-low power 4k Ultra-HD (4096x2160p60)
> > > + mobile HD transmitter designed for portable devices. The
> > > + ANX7688 converts HDMI 2.0 to DisplayPort 1.3 Ultra-HD
> > > + including an intelligent crosspoint switch to support
> > > + USB Type-C.
> > > +
> > > config DRM_ANALOGIX_ANX78XX
> > > tristate "Analogix ANX78XX bridge"
> > > select DRM_ANALOGIX_DP
> > > diff --git a/drivers/gpu/drm/bridge/analogix/Makefile b/drivers/gpu/drm/bridge/analogix/Makefile
> > > index 97669b374098..27cd73635c8c 100644
> > > --- a/drivers/gpu/drm/bridge/analogix/Makefile
> > > +++ b/drivers/gpu/drm/bridge/analogix/Makefile
> > > @@ -1,5 +1,6 @@
> > > # SPDX-License-Identifier: GPL-2.0-only
> > > analogix_dp-objs := analogix_dp_core.o analogix_dp_reg.o analogix-i2c-dptx.o
> > > obj-$(CONFIG_DRM_ANALOGIX_ANX6345) += analogix-anx6345.o
> > > +obj-$(CONFIG_DRM_ANALOGIX_ANX7688) += analogix-anx7688.o
> > > obj-$(CONFIG_DRM_ANALOGIX_ANX78XX) += analogix-anx78xx.o
> > > obj-$(CONFIG_DRM_ANALOGIX_DP) += analogix_dp.o
> > > diff --git a/drivers/gpu/drm/bridge/analogix/analogix-anx7688.c b/drivers/gpu/drm/bridge/analogix/analogix-anx7688.c
> > > new file mode 100644
> > > index 000000000000..10a7cd0f9126
> > > --- /dev/null
> > > +++ b/drivers/gpu/drm/bridge/analogix/analogix-anx7688.c
> > > @@ -0,0 +1,188 @@
> > > +// SPDX-License-Identifier: GPL-2.0-only
> > > +/*
> > > + * ANX7688 HDMI->DP bridge driver
> > > + *
> > > + * Copyright 2020 Google LLC
> > > + */
> > > +
> > > +#include <linux/i2c.h>
> > > +#include <linux/module.h>
> > > +#include <linux/regmap.h>
> > > +#include <drm/drm_bridge.h>
> > > +
> > > +/* Register addresses */
> > > +#define VENDOR_ID_REG 0x00
> > > +#define DEVICE_ID_REG 0x02
> > > +
> > > +#define FW_VERSION_REG 0x80
> > > +
> > > +#define DP_BANDWIDTH_REG 0x85
> > > +#define DP_LANE_COUNT_REG 0x86
> > > +
> > > +#define VENDOR_ID 0x1f29
> > > +#define DEVICE_ID 0x7688
> > > +
> > > +/* First supported firmware version (0.85) */
> > > +#define MINIMUM_FW_VERSION 0x0085
> > > +
> > > +struct anx7688 {
> > > + struct drm_bridge bridge;
> > > + struct i2c_client *client;
> > > + struct regmap *regmap;
> > > +
> > > + bool filter;
> > > +};
> > > +
> > > +static inline struct anx7688 *bridge_to_anx7688(struct drm_bridge *bridge)
> > > +{
> > > + return container_of(bridge, struct anx7688, bridge);
> > > +}
> > > +
> > > +static bool anx7688_bridge_mode_fixup(struct drm_bridge *bridge,
> > > + const struct drm_display_mode *mode,
> > > + struct drm_display_mode *adjusted_mode)
> > > +{
> > > + struct anx7688 *anx7688 = bridge_to_anx7688(bridge);
> > > + int totalbw, requiredbw;
> > > + u8 dpbw, lanecount;
> > > + u8 regs[2];
> > > + int ret;
> > > +
> > > + if (!anx7688->filter)
> > > + return true;
> > > +
> > > + /* Read both regs 0x85 (bandwidth) and 0x86 (lane count). */
> > > + ret = regmap_bulk_read(anx7688->regmap, DP_BANDWIDTH_REG, regs, 2);
> > > + if (ret < 0) {
> > > + dev_err(&anx7688->client->dev,
> > > + "Failed to read bandwidth/lane count\n");
> > > + return false;
> > > + }
> > > + dpbw = regs[0];
> > > + lanecount = regs[1];
> > > +
> > > + /* Maximum 0x19 bandwidth (6.75 Gbps Turbo mode), 2 lanes */
> > > + if (dpbw > 0x19 || lanecount > 2) {
> > > + dev_err(&anx7688->client->dev,
> > > + "Invalid bandwidth/lane count (%02x/%d)\n",
> > > + dpbw, lanecount);
> > > + return false;
> > > + }
> > > +
> > > + /* Compute available bandwidth (kHz) */
> > > + totalbw = dpbw * lanecount * 270000 * 8 / 10;
> > > +
> > > + /* Required bandwidth (8 bpc, kHz) */
> > > + requiredbw = mode->clock * 8 * 3;
> > > +
> > > + dev_dbg(&anx7688->client->dev,
> > > + "DP bandwidth: %d kHz (%02x/%d); mode requires %d Khz\n",
> > > + totalbw, dpbw, lanecount, requiredbw);
> > > +
> > > + if (totalbw == 0) {
> > > + dev_warn(&anx7688->client->dev,
> > > + "Bandwidth/lane count are 0, not rejecting modes\n");
> > > + return true;
> > > + }
> > > +
> > > + return totalbw >= requiredbw;
> > > +}
> > > +
> > > +static const struct drm_bridge_funcs anx7688_bridge_funcs = {
> > > + .mode_fixup = anx7688_bridge_mode_fixup,
> > > +};
> > > +
> > > +static const struct regmap_config anx7688_regmap_config = {
> > > + .reg_bits = 8,
> > > + .val_bits = 8,
> > > +};
> > > +
> > > +static int anx7688_i2c_probe(struct i2c_client *client)
> > > +{
> > > + struct device *dev = &client->dev;
> > > + struct anx7688 *anx7688;
> > > + u16 vendor, device;
> > > + u16 fwversion;
> > > + u8 buffer[4];
> > > + int ret;
> > > +
> > > + anx7688 = devm_kzalloc(dev, sizeof(*anx7688), GFP_KERNEL);
> > > + if (!anx7688)
> > > + return -ENOMEM;
> > > +
> > > + anx7688->bridge.of_node = dev->of_node;
> > > + anx7688->client = client;
> > > + i2c_set_clientdata(client, anx7688);
> > > +
> > > + anx7688->regmap = devm_regmap_init_i2c(client, &anx7688_regmap_config);
> > > +
> > > + /* Read both vendor and device id (4 bytes). */
> > > + ret = regmap_bulk_read(anx7688->regmap, VENDOR_ID_REG, buffer, 4);
> > > + if (ret) {
> > > + dev_err(dev, "Failed to read chip vendor/device id\n");
> > > + return ret;
> > > + }
> > > +
> > > + vendor = (u16)buffer[1] << 8 | buffer[0];
> > > + device = (u16)buffer[3] << 8 | buffer[2];
> > > + if (vendor != VENDOR_ID || device != DEVICE_ID) {
> > > + dev_err(dev, "Invalid vendor/device id %04x/%04x\n",
> > > + vendor, device);
> > > + return -ENODEV;
> > > + }
> > > +
> > > + ret = regmap_bulk_read(anx7688->regmap, FW_VERSION_REG, buffer, 2);
> > > + if (ret) {
> > > + dev_err(&client->dev, "Failed to read firmware version\n");
> > > + return ret;
> > > + }
> > > +
> > > + fwversion = (u16)buffer[0] << 8 | buffer[1];
> > > + dev_info(dev, "ANX7688 firwmare version %02x.%02x\n",
> > > + buffer[0], buffer[1]);
> > > +
> > > + /* FW version >= 0.85 supports bandwidth/lane count registers */
> > > + if (fwversion >= MINIMUM_FW_VERSION) {
> > > + anx7688->filter = true;
> > > + } else {
> > > + /* Warn, but not fail, for backwards compatibility. */
> > > + dev_warn(dev,
> > > + "Old ANX7688 FW version (%02x.%02x), not filtering\n",
> > > + buffer[0], buffer[1]);
> > > + }
> > > +
> > > + anx7688->bridge.funcs = &anx7688_bridge_funcs;
> > > + drm_bridge_add(&anx7688->bridge);
> > > +
> > > + return 0;
> > > +}
> > > +
> > > +static int anx7688_i2c_remove(struct i2c_client *client)
> > > +{
> > > + struct anx7688 *anx7688 = i2c_get_clientdata(client);
> > > +
> > > + drm_bridge_remove(&anx7688->bridge);
> > > +
> > > + return 0;
> > > +}
> > > +
> > > +static const struct of_device_id anx7688_match_table[] = {
> > > + { .compatible = "analogix,anx7688", },
> > > + { }
> > > +};
> > > +MODULE_DEVICE_TABLE(of, anx7688_match_table);
> > > +
> > > +static struct i2c_driver anx7688_driver = {
> > > + .probe_new = anx7688_i2c_probe,
> > > + .remove = anx7688_i2c_remove,
> > > + .driver = {
> > > + .name = "anx7688",
> > > + .of_match_table = anx7688_match_table,
> > > + },
> > > +};
> > > +
> > > +module_i2c_driver(anx7688_driver);
> > > +
> > > +MODULE_DESCRIPTION("ANX7688 HDMI->DP bridge driver");
> > > +MODULE_AUTHOR("Nicolas Boichat <drinkcat@chromium.org>");
> > > +MODULE_LICENSE("GPL");
> > > --
> > > 2.25.0
> > >
> > _______________________________________________
> > dri-devel mailing list
> > dri-devel@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply
* Re: [PATCH v2 2/2] drm/bridge: anx7688: Add anx7688 bridge driver support
From: Vasily Khoruzhick @ 2020-02-14 22:17 UTC (permalink / raw)
To: Enric Balletbo Serra, Icenowy Zheng
Cc: Jernej Skrabec, Nicolas Boichat, Neil Armstrong, David Airlie,
Torsten Duwe, Jonas Karlman, linux-kernel, dri-devel,
Andrzej Hajda, Matthias Brugger, Laurent Pinchart, Hsin-Yi Wang,
Enric Balletbo i Serra, Thomas Gleixner, Collabora Kernel ML,
Maxime Ripard
In-Reply-To: <CAFqH_53crnC6hLExNgQRjMgtO+TLJjT6uzA4g8WXvy7NkwHcJg@mail.gmail.com>
On Fri, Feb 14, 2020 at 1:53 PM Enric Balletbo Serra
<eballetbo@gmail.com> wrote:
>
> Hi Vasily,
>
> Missatge de Vasily Khoruzhick <anarsoul@gmail.com> del dia dv., 14 de
> febr. 2020 a les 22:36:
> >
> > On Thu, Feb 13, 2020 at 6:54 AM Enric Balletbo i Serra
> > <enric.balletbo@collabora.com> wrote:
> > >
> > > From: Nicolas Boichat <drinkcat@chromium.org>
> > >
> > > ANX7688 is a HDMI to DP converter (as well as USB-C port controller),
> > > that has an internal microcontroller.
> > >
> > > The only reason a Linux kernel driver is necessary is to reject
> > > resolutions that require more bandwidth than what is available on
> > > the DP side. DP bandwidth and lane count are reported by the bridge
> > > via 2 registers on I2C.
> >
> > It is true only for your particular platform where usb-c part is
> > managed by firmware. Pinephone has the same anx7688 but linux will
> > need a driver that manages usb-c in addition to DP.
> >
> > I'd suggest making it MFD driver from the beginning, or at least make
> > proper bindings so we don't have to rework it and introduce binding
> > incompatibilities in future.
> >
>
> Do you have example code on how the ANX7866 is used in pinephone?
> There is a repo somewhere?
I don't think it's implemented yet. I've CCed Icenowy in case if she
has anything.
> Thanks,
> Enric
>
> > > Signed-off-by: Nicolas Boichat <drinkcat@chromium.org>
> > > Signed-off-by: Hsin-Yi Wang <hsinyi@chromium.org>
> > > Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> > > ---
> > >
> > > Changes in v2:
> > > - Move driver to drivers/gpu/drm/bridge/analogix.
> > > - Make the driver OF only so we can reduce the ifdefs.
> > > - Update the Copyright to 2020.
> > > - Use probe_new so we can get rid of the i2c_device_id table.
> > >
> > > drivers/gpu/drm/bridge/analogix/Kconfig | 12 ++
> > > drivers/gpu/drm/bridge/analogix/Makefile | 1 +
> > > .../drm/bridge/analogix/analogix-anx7688.c | 188 ++++++++++++++++++
> > > 3 files changed, 201 insertions(+)
> > > create mode 100644 drivers/gpu/drm/bridge/analogix/analogix-anx7688.c
> > >
> > > diff --git a/drivers/gpu/drm/bridge/analogix/Kconfig b/drivers/gpu/drm/bridge/analogix/Kconfig
> > > index e1fa7d820373..af7c2939403c 100644
> > > --- a/drivers/gpu/drm/bridge/analogix/Kconfig
> > > +++ b/drivers/gpu/drm/bridge/analogix/Kconfig
> > > @@ -11,6 +11,18 @@ config DRM_ANALOGIX_ANX6345
> > > ANX6345 transforms the LVTTL RGB output of an
> > > application processor to eDP or DisplayPort.
> > >
> > > +config DRM_ANALOGIX_ANX7688
> > > + tristate "Analogix ANX7688 bridge"
> > > + depends on OF
> > > + select DRM_KMS_HELPER
> > > + select REGMAP_I2C
> > > + help
> > > + ANX7688 is an ultra-low power 4k Ultra-HD (4096x2160p60)
> > > + mobile HD transmitter designed for portable devices. The
> > > + ANX7688 converts HDMI 2.0 to DisplayPort 1.3 Ultra-HD
> > > + including an intelligent crosspoint switch to support
> > > + USB Type-C.
> > > +
> > > config DRM_ANALOGIX_ANX78XX
> > > tristate "Analogix ANX78XX bridge"
> > > select DRM_ANALOGIX_DP
> > > diff --git a/drivers/gpu/drm/bridge/analogix/Makefile b/drivers/gpu/drm/bridge/analogix/Makefile
> > > index 97669b374098..27cd73635c8c 100644
> > > --- a/drivers/gpu/drm/bridge/analogix/Makefile
> > > +++ b/drivers/gpu/drm/bridge/analogix/Makefile
> > > @@ -1,5 +1,6 @@
> > > # SPDX-License-Identifier: GPL-2.0-only
> > > analogix_dp-objs := analogix_dp_core.o analogix_dp_reg.o analogix-i2c-dptx.o
> > > obj-$(CONFIG_DRM_ANALOGIX_ANX6345) += analogix-anx6345.o
> > > +obj-$(CONFIG_DRM_ANALOGIX_ANX7688) += analogix-anx7688.o
> > > obj-$(CONFIG_DRM_ANALOGIX_ANX78XX) += analogix-anx78xx.o
> > > obj-$(CONFIG_DRM_ANALOGIX_DP) += analogix_dp.o
> > > diff --git a/drivers/gpu/drm/bridge/analogix/analogix-anx7688.c b/drivers/gpu/drm/bridge/analogix/analogix-anx7688.c
> > > new file mode 100644
> > > index 000000000000..10a7cd0f9126
> > > --- /dev/null
> > > +++ b/drivers/gpu/drm/bridge/analogix/analogix-anx7688.c
> > > @@ -0,0 +1,188 @@
> > > +// SPDX-License-Identifier: GPL-2.0-only
> > > +/*
> > > + * ANX7688 HDMI->DP bridge driver
> > > + *
> > > + * Copyright 2020 Google LLC
> > > + */
> > > +
> > > +#include <linux/i2c.h>
> > > +#include <linux/module.h>
> > > +#include <linux/regmap.h>
> > > +#include <drm/drm_bridge.h>
> > > +
> > > +/* Register addresses */
> > > +#define VENDOR_ID_REG 0x00
> > > +#define DEVICE_ID_REG 0x02
> > > +
> > > +#define FW_VERSION_REG 0x80
> > > +
> > > +#define DP_BANDWIDTH_REG 0x85
> > > +#define DP_LANE_COUNT_REG 0x86
> > > +
> > > +#define VENDOR_ID 0x1f29
> > > +#define DEVICE_ID 0x7688
> > > +
> > > +/* First supported firmware version (0.85) */
> > > +#define MINIMUM_FW_VERSION 0x0085
> > > +
> > > +struct anx7688 {
> > > + struct drm_bridge bridge;
> > > + struct i2c_client *client;
> > > + struct regmap *regmap;
> > > +
> > > + bool filter;
> > > +};
> > > +
> > > +static inline struct anx7688 *bridge_to_anx7688(struct drm_bridge *bridge)
> > > +{
> > > + return container_of(bridge, struct anx7688, bridge);
> > > +}
> > > +
> > > +static bool anx7688_bridge_mode_fixup(struct drm_bridge *bridge,
> > > + const struct drm_display_mode *mode,
> > > + struct drm_display_mode *adjusted_mode)
> > > +{
> > > + struct anx7688 *anx7688 = bridge_to_anx7688(bridge);
> > > + int totalbw, requiredbw;
> > > + u8 dpbw, lanecount;
> > > + u8 regs[2];
> > > + int ret;
> > > +
> > > + if (!anx7688->filter)
> > > + return true;
> > > +
> > > + /* Read both regs 0x85 (bandwidth) and 0x86 (lane count). */
> > > + ret = regmap_bulk_read(anx7688->regmap, DP_BANDWIDTH_REG, regs, 2);
> > > + if (ret < 0) {
> > > + dev_err(&anx7688->client->dev,
> > > + "Failed to read bandwidth/lane count\n");
> > > + return false;
> > > + }
> > > + dpbw = regs[0];
> > > + lanecount = regs[1];
> > > +
> > > + /* Maximum 0x19 bandwidth (6.75 Gbps Turbo mode), 2 lanes */
> > > + if (dpbw > 0x19 || lanecount > 2) {
> > > + dev_err(&anx7688->client->dev,
> > > + "Invalid bandwidth/lane count (%02x/%d)\n",
> > > + dpbw, lanecount);
> > > + return false;
> > > + }
> > > +
> > > + /* Compute available bandwidth (kHz) */
> > > + totalbw = dpbw * lanecount * 270000 * 8 / 10;
> > > +
> > > + /* Required bandwidth (8 bpc, kHz) */
> > > + requiredbw = mode->clock * 8 * 3;
> > > +
> > > + dev_dbg(&anx7688->client->dev,
> > > + "DP bandwidth: %d kHz (%02x/%d); mode requires %d Khz\n",
> > > + totalbw, dpbw, lanecount, requiredbw);
> > > +
> > > + if (totalbw == 0) {
> > > + dev_warn(&anx7688->client->dev,
> > > + "Bandwidth/lane count are 0, not rejecting modes\n");
> > > + return true;
> > > + }
> > > +
> > > + return totalbw >= requiredbw;
> > > +}
> > > +
> > > +static const struct drm_bridge_funcs anx7688_bridge_funcs = {
> > > + .mode_fixup = anx7688_bridge_mode_fixup,
> > > +};
> > > +
> > > +static const struct regmap_config anx7688_regmap_config = {
> > > + .reg_bits = 8,
> > > + .val_bits = 8,
> > > +};
> > > +
> > > +static int anx7688_i2c_probe(struct i2c_client *client)
> > > +{
> > > + struct device *dev = &client->dev;
> > > + struct anx7688 *anx7688;
> > > + u16 vendor, device;
> > > + u16 fwversion;
> > > + u8 buffer[4];
> > > + int ret;
> > > +
> > > + anx7688 = devm_kzalloc(dev, sizeof(*anx7688), GFP_KERNEL);
> > > + if (!anx7688)
> > > + return -ENOMEM;
> > > +
> > > + anx7688->bridge.of_node = dev->of_node;
> > > + anx7688->client = client;
> > > + i2c_set_clientdata(client, anx7688);
> > > +
> > > + anx7688->regmap = devm_regmap_init_i2c(client, &anx7688_regmap_config);
> > > +
> > > + /* Read both vendor and device id (4 bytes). */
> > > + ret = regmap_bulk_read(anx7688->regmap, VENDOR_ID_REG, buffer, 4);
> > > + if (ret) {
> > > + dev_err(dev, "Failed to read chip vendor/device id\n");
> > > + return ret;
> > > + }
> > > +
> > > + vendor = (u16)buffer[1] << 8 | buffer[0];
> > > + device = (u16)buffer[3] << 8 | buffer[2];
> > > + if (vendor != VENDOR_ID || device != DEVICE_ID) {
> > > + dev_err(dev, "Invalid vendor/device id %04x/%04x\n",
> > > + vendor, device);
> > > + return -ENODEV;
> > > + }
> > > +
> > > + ret = regmap_bulk_read(anx7688->regmap, FW_VERSION_REG, buffer, 2);
> > > + if (ret) {
> > > + dev_err(&client->dev, "Failed to read firmware version\n");
> > > + return ret;
> > > + }
> > > +
> > > + fwversion = (u16)buffer[0] << 8 | buffer[1];
> > > + dev_info(dev, "ANX7688 firwmare version %02x.%02x\n",
> > > + buffer[0], buffer[1]);
> > > +
> > > + /* FW version >= 0.85 supports bandwidth/lane count registers */
> > > + if (fwversion >= MINIMUM_FW_VERSION) {
> > > + anx7688->filter = true;
> > > + } else {
> > > + /* Warn, but not fail, for backwards compatibility. */
> > > + dev_warn(dev,
> > > + "Old ANX7688 FW version (%02x.%02x), not filtering\n",
> > > + buffer[0], buffer[1]);
> > > + }
> > > +
> > > + anx7688->bridge.funcs = &anx7688_bridge_funcs;
> > > + drm_bridge_add(&anx7688->bridge);
> > > +
> > > + return 0;
> > > +}
> > > +
> > > +static int anx7688_i2c_remove(struct i2c_client *client)
> > > +{
> > > + struct anx7688 *anx7688 = i2c_get_clientdata(client);
> > > +
> > > + drm_bridge_remove(&anx7688->bridge);
> > > +
> > > + return 0;
> > > +}
> > > +
> > > +static const struct of_device_id anx7688_match_table[] = {
> > > + { .compatible = "analogix,anx7688", },
> > > + { }
> > > +};
> > > +MODULE_DEVICE_TABLE(of, anx7688_match_table);
> > > +
> > > +static struct i2c_driver anx7688_driver = {
> > > + .probe_new = anx7688_i2c_probe,
> > > + .remove = anx7688_i2c_remove,
> > > + .driver = {
> > > + .name = "anx7688",
> > > + .of_match_table = anx7688_match_table,
> > > + },
> > > +};
> > > +
> > > +module_i2c_driver(anx7688_driver);
> > > +
> > > +MODULE_DESCRIPTION("ANX7688 HDMI->DP bridge driver");
> > > +MODULE_AUTHOR("Nicolas Boichat <drinkcat@chromium.org>");
> > > +MODULE_LICENSE("GPL");
> > > --
> > > 2.25.0
> > >
> > _______________________________________________
> > dri-devel mailing list
> > dri-devel@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/dri-devel
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply
* Re: [PATCH] staging: exfat: add exfat filesystem code to staging
From: Valdis Klētnieks @ 2020-02-14 22:16 UTC (permalink / raw)
To: Sasha Levin
Cc: Pali Rohár, Greg Kroah-Hartman, devel, linux-fsdevel,
linux-kernel, Sasha Levin, Christoph Hellwig
In-Reply-To: <20200213211847.GA1734@sasha-vm>
[-- Attachment #1: Type: text/plain, Size: 3080 bytes --]
On Thu, 13 Feb 2020 16:18:47 -0500, Sasha Levin said:
> >> I was hoping that it would be possible to easily use secondary FAT table
> >> (from TexFAT extension) for redundancy without need to implement full
> >> TexFAT, which could be also backward compatible with systems which do
> >> not implement TexFAT extension at all. Similarly like using FAT32 disk
> >> with two FAT tables is possible also on system which use first FAT
> >> table.
OK.. maybe I'm not sufficiently caffeinated, but how do you use 2 FAT tables on
a physical device and expect it to work properly on a system that uses just the
first FAT table, if the device is set to "use second table" when you mount it?
That sounds just too much like the failure modes of running fsck on a mounted
filesystem....
> >By the chance, is there any possibility to release TexFAT specification?
> >Usage of more FAT tables (even for Linux) could help with data recovery.
>
> This would be a major pain in the arse to pull off (even more that
> releasing exFAT itself) because TexFAT is effectively dead and no one
> here cares about it. It's not even the case that there are devices which
> are now left unsupported, the whole TexFAT scheme is just dead and gone.
>
> Could I point you to the TexFAT patent instead
> (https://patents.google.com/patent/US7613738B2/en)? It describes well
> how TexFAT used to work.
I don't think anybody wants the full TexFAT support - but having a backup copy
of the FAT would be nice in some circumstances.
Actually, that raises an question....
What the published spec says:
The File Allocation Table (FAT) region may contain up to two FATs, one in the
First FAT sub-region and another in the Second FAT sub-region. The NumberOfFats
field describes how many FATs this region contains. The valid values for the
NumberOfFats field are 1 and 2. Therefore, the First FAT sub-region always
contains a FAT. If the NumberOfFats field is two, then the Second FAT
sub-region also contains a FAT.
The ActiveFat field of the VolumeFlags field describes which FAT is active.
Only the VolumeFlags field in the Main Boot Sector is current. Implementations
shall treat the FAT which is not active as stale. Use of the inactive FAT and
switching between FATs is implementation specific.
Sasha: can you find out what the Windows implementation does regarding that
last sentence? Does it actively use both FAT sub-regions and switch between
them (probably not), or does it read the ActiveFAT value and use that one, or
does Windows just use NumberOfFats == 1?
I'm assuming that the fact the doc also says "NumberOfFats == 2 is only valid
for TexFAT volumes" possibly means "Microsoft thinks that's hardcoded at 1"
given the death of TexFAT. That would make adding alternate FAT support a
major challenge.
On the other hand, if Windows actually looks at the NumberOfFats value, finds
a 2, and ActiveFAT ==1 (meaning use second table) and says "OK, whatever" and
just uses the second table from there on out, it becomes a lot easier.
[-- Attachment #2: Type: application/pgp-signature, Size: 832 bytes --]
^ permalink raw reply
* [PATCH net] mptcp: Protect subflow socket options before connection completes
From: Mat Martineau @ 2020-02-14 22:14 UTC (permalink / raw)
To: netdev; +Cc: Mat Martineau
Userspace should not be able to directly manipulate subflow socket
options before a connection is established since it is not yet known if
it will be an MPTCP subflow or a TCP fallback subflow. TCP fallback
subflows can be more directly controlled by userspace because they are
regular TCP connections, while MPTCP subflow sockets need to be
configured for the specific needs of MPTCP. Use the same logic as
sendmsg/recvmsg to ensure that socket option calls are only passed
through to known TCP fallback subflows.
Signed-off-by: Mat Martineau <mathew.j.martineau@linux.intel.com>
---
net/mptcp/protocol.c | 48 ++++++++++++++++++--------------------------
1 file changed, 19 insertions(+), 29 deletions(-)
diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index 030dee668e0a..e9aa6807b5be 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -755,60 +755,50 @@ static int mptcp_setsockopt(struct sock *sk, int level, int optname,
char __user *optval, unsigned int optlen)
{
struct mptcp_sock *msk = mptcp_sk(sk);
- int ret = -EOPNOTSUPP;
struct socket *ssock;
- struct sock *ssk;
pr_debug("msk=%p", msk);
/* @@ the meaning of setsockopt() when the socket is connected and
- * there are multiple subflows is not defined.
+ * there are multiple subflows is not yet defined. It is up to the
+ * MPTCP-level socket to configure the subflows until the subflow
+ * is in TCP fallback, when TCP socket options are passed through
+ * to the one remaining subflow.
*/
lock_sock(sk);
- ssock = __mptcp_socket_create(msk, MPTCP_SAME_STATE);
- if (IS_ERR(ssock)) {
- release_sock(sk);
- return ret;
- }
+ ssock = __mptcp_tcp_fallback(msk);
+ if (ssock)
+ return tcp_setsockopt(ssock->sk, level, optname, optval,
+ optlen);
- ssk = ssock->sk;
- sock_hold(ssk);
release_sock(sk);
- ret = tcp_setsockopt(ssk, level, optname, optval, optlen);
- sock_put(ssk);
-
- return ret;
+ return -EOPNOTSUPP;
}
static int mptcp_getsockopt(struct sock *sk, int level, int optname,
char __user *optval, int __user *option)
{
struct mptcp_sock *msk = mptcp_sk(sk);
- int ret = -EOPNOTSUPP;
struct socket *ssock;
- struct sock *ssk;
pr_debug("msk=%p", msk);
- /* @@ the meaning of getsockopt() when the socket is connected and
- * there are multiple subflows is not defined.
+ /* @@ the meaning of setsockopt() when the socket is connected and
+ * there are multiple subflows is not yet defined. It is up to the
+ * MPTCP-level socket to configure the subflows until the subflow
+ * is in TCP fallback, when socket options are passed through
+ * to the one remaining subflow.
*/
lock_sock(sk);
- ssock = __mptcp_socket_create(msk, MPTCP_SAME_STATE);
- if (IS_ERR(ssock)) {
- release_sock(sk);
- return ret;
- }
+ ssock = __mptcp_tcp_fallback(msk);
+ if (ssock)
+ return tcp_getsockopt(ssock->sk, level, optname, optval,
+ option);
- ssk = ssock->sk;
- sock_hold(ssk);
release_sock(sk);
- ret = tcp_getsockopt(ssk, level, optname, optval, option);
- sock_put(ssk);
-
- return ret;
+ return -EOPNOTSUPP;
}
static int mptcp_get_port(struct sock *sk, unsigned short snum)
base-commit: a1fa83bdab784fa0ff2e92870011c0dcdbd2f680
--
2.25.0
^ permalink raw reply related
* Re: [PATCH 1/2] Revert "RDMA/isert: Fix a recently introduced regression related to logout"
From: Martin K. Petersen @ 2020-02-14 22:14 UTC (permalink / raw)
To: target-devel
In-Reply-To: <20200213050900.19094-1-bvanassche@acm.org>
Bart,
> Since commit 04060db41178 introduces soft lockups when toggling
> network interfaces, revert it.
Applied 1+2 to 5.6/scsi-fixes. Thanks!
--
Martin K. Petersen Oracle Linux Engineering
^ permalink raw reply
* Re: [PATCH v2 2/6] Add a concept of a "secure" anonymous file
From: kbuild test robot @ 2020-02-14 22:13 UTC (permalink / raw)
To: Daniel Colascione
Cc: kbuild-all, dancol, timmurray, nosh, nnk, lokeshgidra,
linux-kernel, linux-api, selinux
In-Reply-To: <20200211225547.235083-3-dancol@google.com>
[-- Attachment #1: Type: text/plain, Size: 2082 bytes --]
Hi Daniel,
Thank you for the patch! Yet something to improve:
[auto build test ERROR on pcmoore-selinux/next]
[also build test ERROR on security/next-testing linux/master linus/master v5.6-rc1 next-20200214]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]
url: https://github.com/0day-ci/linux/commits/Daniel-Colascione/Harden-userfaultfd/20200215-034039
base: https://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux.git next
config: i386-tinyconfig (attached as .config)
compiler: gcc-7 (Debian 7.5.0-4) 7.5.0
reproduce:
# save the attached .config to linux build tree
make ARCH=i386
If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>
All errors (new ones prefixed by >>):
fs/anon_inodes.c: In function 'anon_inode_make_secure_inode':
>> fs/anon_inodes.c:67:10: error: implicit declaration of function 'security_inode_init_security_anon'; did you mean 'security_inode_init_security'? [-Werror=implicit-function-declaration]
error = security_inode_init_security_anon(inode, name, fops);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
security_inode_init_security
cc1: some warnings being treated as errors
vim +67 fs/anon_inodes.c
57
58 struct inode *anon_inode_make_secure_inode(const char *name,
59 const struct file_operations *fops)
60 {
61 struct inode *inode;
62 int error;
63 inode = alloc_anon_inode(anon_inode_mnt->mnt_sb);
64 if (IS_ERR(inode))
65 return ERR_PTR(PTR_ERR(inode));
66 inode->i_flags &= ~S_PRIVATE;
> 67 error = security_inode_init_security_anon(inode, name, fops);
68 if (error) {
69 iput(inode);
70 return ERR_PTR(error);
71 }
72 return inode;
73 }
74
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 7239 bytes --]
^ permalink raw reply
* Re: [PATCH v2 2/6] Add a concept of a "secure" anonymous file
From: kbuild test robot @ 2020-02-14 22:13 UTC (permalink / raw)
To: kbuild-all
In-Reply-To: <20200211225547.235083-3-dancol@google.com>
[-- Attachment #1: Type: text/plain, Size: 2138 bytes --]
Hi Daniel,
Thank you for the patch! Yet something to improve:
[auto build test ERROR on pcmoore-selinux/next]
[also build test ERROR on security/next-testing linux/master linus/master v5.6-rc1 next-20200214]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]
url: https://github.com/0day-ci/linux/commits/Daniel-Colascione/Harden-userfaultfd/20200215-034039
base: https://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux.git next
config: i386-tinyconfig (attached as .config)
compiler: gcc-7 (Debian 7.5.0-4) 7.5.0
reproduce:
# save the attached .config to linux build tree
make ARCH=i386
If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>
All errors (new ones prefixed by >>):
fs/anon_inodes.c: In function 'anon_inode_make_secure_inode':
>> fs/anon_inodes.c:67:10: error: implicit declaration of function 'security_inode_init_security_anon'; did you mean 'security_inode_init_security'? [-Werror=implicit-function-declaration]
error = security_inode_init_security_anon(inode, name, fops);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
security_inode_init_security
cc1: some warnings being treated as errors
vim +67 fs/anon_inodes.c
57
58 struct inode *anon_inode_make_secure_inode(const char *name,
59 const struct file_operations *fops)
60 {
61 struct inode *inode;
62 int error;
63 inode = alloc_anon_inode(anon_inode_mnt->mnt_sb);
64 if (IS_ERR(inode))
65 return ERR_PTR(PTR_ERR(inode));
66 inode->i_flags &= ~S_PRIVATE;
> 67 error = security_inode_init_security_anon(inode, name, fops);
68 if (error) {
69 iput(inode);
70 return ERR_PTR(error);
71 }
72 return inode;
73 }
74
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org
[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 7239 bytes --]
^ permalink raw reply
* Re: [RFC PATCH v4 10/25] RDMA/irdma: Add driver framework definitions
From: Parav Pandit @ 2020-02-14 22:13 UTC (permalink / raw)
To: Jeff Kirsher, davem@davemloft.net, gregkh@linuxfoundation.org
Cc: Mustafa Ismail, netdev@vger.kernel.org,
linux-rdma@vger.kernel.org, nhorman@redhat.com,
sassmann@redhat.com, jgg@ziepe.ca, Shiraz Saleem
In-Reply-To: <20200212191424.1715577-11-jeffrey.t.kirsher@intel.com>
On 2/12/2020 1:14 PM, Jeff Kirsher wrote:
> From: Mustafa Ismail <mustafa.ismail@intel.com>
>
> Register irdma as a platform driver capable of supporting platform
> devices from multi-generation RDMA capable Intel HW. Establish the
> interface with all supported netdev peer devices and initialize HW.
>
> Signed-off-by: Mustafa Ismail <mustafa.ismail@intel.com>
> Signed-off-by: Shiraz Saleem <shiraz.saleem@intel.com>
> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
> ---
> drivers/infiniband/hw/irdma/i40iw_if.c | 228 ++++++++++
> drivers/infiniband/hw/irdma/irdma_if.c | 424 ++++++++++++++++++
> drivers/infiniband/hw/irdma/main.c | 572 ++++++++++++++++++++++++
> drivers/infiniband/hw/irdma/main.h | 595 +++++++++++++++++++++++++
> 4 files changed, 1819 insertions(+)
> create mode 100644 drivers/infiniband/hw/irdma/i40iw_if.c
> create mode 100644 drivers/infiniband/hw/irdma/irdma_if.c
> create mode 100644 drivers/infiniband/hw/irdma/main.c
> create mode 100644 drivers/infiniband/hw/irdma/main.h
>
> diff --git a/drivers/infiniband/hw/irdma/i40iw_if.c b/drivers/infiniband/hw/irdma/i40iw_if.c
> new file mode 100644
> index 000000000000..5e69b16a2658
> --- /dev/null
> +++ b/drivers/infiniband/hw/irdma/i40iw_if.c
> @@ -0,0 +1,228 @@
> +// SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB
> +/* Copyright (c) 2015 - 2019 Intel Corporation */
> +#include <linux/module.h>
> +#include <linux/moduleparam.h>
> +#include <linux/netdevice.h>
> +#include <linux/etherdevice.h>
> +#include <linux/net/intel/i40e_client.h>
> +#include <net/addrconf.h>
> +#include "main.h"
> +#include "i40iw_hw.h"
> +
> +/**
> + * i40iw_request_reset - Request a reset
> + * @rf: RDMA PCI function
> + *
> + */
> +static void i40iw_request_reset(struct irdma_pci_f *rf)
> +{
> + struct i40e_info *ldev = rf->ldev.if_ldev;
> +
> + ldev->ops->request_reset(ldev, rf->ldev.if_client, 1);
> +}
> +
> +/**
> + * i40iw_open - client interface operation open for iwarp/uda device
> + * @ldev: LAN device information
> + * @client: iwarp client information, provided during registration
> + *
> + * Called by the LAN driver during the processing of client
> + * register Create device resources, set up queues, pble and hmc
> + * objects and register the device with the ib verbs interface
> + * Return 0 if successful, otherwise return error
> + */
> +static int i40iw_open(struct i40e_info *ldev, struct i40e_client *client)
> +{
> + struct irdma_device *iwdev = NULL;
> + struct irdma_handler *hdl = NULL;
> + struct irdma_priv_ldev *pldev;
> + struct irdma_sc_dev *dev;
> + struct irdma_pci_f *rf;
> + struct irdma_l2params l2params = {};
> + int err = -EIO;
> + int i;
> + u16 qset;
> + u16 last_qset = IRDMA_NO_QSET;
> +
> + hdl = irdma_find_handler(ldev->pcidev);
> + if (hdl)
> + return 0;
> +
> + hdl = kzalloc(sizeof(*hdl), GFP_KERNEL);
> + if (!hdl)
> + return -ENOMEM;
> +
> + rf = &hdl->rf;
> + rf->hdl = hdl;
> + dev = &rf->sc_dev;
> + dev->back_dev = rf;
> + rf->rdma_ver = IRDMA_GEN_1;
> + hdl->vdev = ldev->vdev;
> + irdma_init_rf_config_params(rf);
> + rf->gen_ops.init_hw = i40iw_init_hw;
> + rf->gen_ops.request_reset = i40iw_request_reset;
> + rf->hw.hw_addr = ldev->hw_addr;
> + rf->pdev = ldev->pcidev;
> + rf->netdev = ldev->netdev;
> + dev->pci_rev = rf->pdev->revision;
> +
> + pldev = &rf->ldev;
> + hdl->ldev = pldev;
> + pldev->if_client = client;
> + pldev->if_ldev = ldev;
> + pldev->fn_num = ldev->fid;
> + pldev->ftype = ldev->ftype;
> + pldev->pf_vsi_num = 0;
> + pldev->msix_count = ldev->msix_count;
> + pldev->msix_entries = ldev->msix_entries;
> +
> + if (irdma_ctrl_init_hw(rf)) {
> + err = -EIO;
> + goto err_ctrl_init;
> + }
> +
> + iwdev = ib_alloc_device(irdma_device, ibdev);
> + if (!iwdev) {
> + err = -ENOMEM;
> + goto err_ib_alloc;
> + }
> +
> + iwdev->rf = rf;
> + iwdev->hdl = hdl;
> + iwdev->ldev = &rf->ldev;
> + iwdev->init_state = INITIAL_STATE;
> + iwdev->rcv_wnd = IRDMA_CM_DEFAULT_RCV_WND_SCALED;
> + iwdev->rcv_wscale = IRDMA_CM_DEFAULT_RCV_WND_SCALE;
> + iwdev->netdev = ldev->netdev;
> + iwdev->create_ilq = true;
> + iwdev->vsi_num = 0;
> +
> + l2params.mtu =
> + (ldev->params.mtu) ? ldev->params.mtu : IRDMA_DEFAULT_MTU;
> + for (i = 0; i < I40E_CLIENT_MAX_USER_PRIORITY; i++) {
> + qset = ldev->params.qos.prio_qos[i].qs_handle;
> + l2params.up2tc[i] = ldev->params.qos.prio_qos[i].tc;
> + l2params.qs_handle_list[i] = qset;
> + if (last_qset == IRDMA_NO_QSET)
> + last_qset = qset;
> + else if ((qset != last_qset) && (qset != IRDMA_NO_QSET))
> + iwdev->dcb = true;
> + }
> +
> + if (irdma_rt_init_hw(rf, iwdev, &l2params)) {
> + err = -EIO;
> + goto err_rt_init;
> + }
> +
> + err = irdma_ib_register_device(iwdev);
> + if (err)
> + goto err_ibreg;
> +
> + irdma_add_handler(hdl);
> + dev_dbg(rfdev_to_dev(dev), "INIT: Gen1 VSI open success ldev=%p\n",
> + ldev);
> +
> + return 0;
> +
> +err_ibreg:
> + irdma_rt_deinit_hw(iwdev);
> +err_rt_init:
> + ib_dealloc_device(&iwdev->ibdev);
> +err_ib_alloc:
> + irdma_ctrl_deinit_hw(rf);
> +err_ctrl_init:
> + kfree(hdl);
> +
> + return err;
> +}
> +
> +/**
> + * i40iw_l2param_change - handle mss change
> + * @ldev: lan device information
> + * @client: client for parameter change
> + * @params: new parameters from L2
> + */
> +static void i40iw_l2param_change(struct i40e_info *ldev,
> + struct i40e_client *client,
> + struct i40e_params *params)
> +{
> + struct irdma_l2params l2params = {};
> + struct irdma_device *iwdev;
> +
> + iwdev = irdma_get_device(ldev->netdev);
> + if (!iwdev)
> + return;
> +
> + if (iwdev->vsi.mtu != params->mtu) {
> + l2params.mtu_changed = true;
> + l2params.mtu = params->mtu;
> + }
> + irdma_change_l2params(&iwdev->vsi, &l2params);
> + irdma_put_device(iwdev);
> +}
> +
> +/**
> + * i40iw_close - client interface operation close for iwarp/uda device
> + * @ldev: lan device information
> + * @client: client to close
> + * @reset: flag to indicate close on reset
> + *
> + * Called by the lan driver during the processing of client unregister
> + * Destroy and clean up the driver resources
> + */
> +static void i40iw_close(struct i40e_info *ldev, struct i40e_client *client,
> + bool reset)
> +{
> + struct irdma_handler *hdl;
> + struct irdma_pci_f *rf;
> + struct irdma_device *iwdev;
> +
> + hdl = irdma_find_handler(ldev->pcidev);
> + if (!hdl)
> + return;
> +
> + rf = &hdl->rf;
> + iwdev = list_first_entry_or_null(&rf->vsi_dev_list, struct irdma_device,
> + list);
> + if (reset)
> + iwdev->reset = true;
> +
> + irdma_ib_unregister_device(iwdev);
> + irdma_deinit_rf(rf);
> + pr_debug("INIT: Gen1 VSI close complete ldev=%p\n", ldev);
> +}
> +
> +/* client interface functions */
> +static const struct i40e_client_ops i40e_ops = {
> + .open = i40iw_open,
> + .close = i40iw_close,
> + .l2_param_change = i40iw_l2param_change
> +};
> +
> +static struct i40e_client i40iw_client = {
> + .name = "irdma",
> + .ops = &i40e_ops,
> + .type = I40E_CLIENT_IWARP,
> +};
> +
> +int i40iw_probe(struct virtbus_device *vdev)
> +{
> + struct i40e_virtbus_device *i40e_vdev =
> + container_of(vdev, struct i40e_virtbus_device, vdev);
> + struct i40e_info *ldev = i40e_vdev->ldev;
> +
> + ldev->client = &i40iw_client;
> +
> + return ldev->ops->client_device_register(ldev);
> +}
> +
> +int i40iw_remove(struct virtbus_device *vdev)
> +{
> + struct i40e_virtbus_device *i40e_vdev =
> + container_of(vdev, struct i40e_virtbus_device, vdev);
> + struct i40e_info *ldev = i40e_vdev->ldev;
> +
> + ldev->ops->client_device_unregister(ldev);
> +
> + return 0;
> +}
> diff --git a/drivers/infiniband/hw/irdma/irdma_if.c b/drivers/infiniband/hw/irdma/irdma_if.c
> new file mode 100644
> index 000000000000..b538801ca0b9
> --- /dev/null
> +++ b/drivers/infiniband/hw/irdma/irdma_if.c
> @@ -0,0 +1,424 @@
> +// SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB
> +/* Copyright (c) 2019 Intel Corporation */
> +#include <linux/module.h>
> +#include <linux/moduleparam.h>
> +#include <linux/net/intel/iidc.h>
> +#include "main.h"
> +#include "ws.h"
> +#include "icrdma_hw.h"
> +
> +/**
> + * irdma_lan_register_qset - Register qset with LAN driver
> + * @vsi: vsi structure
> + * @tc_node: Traffic class node
> + */
> +static enum irdma_status_code irdma_lan_register_qset(struct irdma_sc_vsi *vsi,
> + struct irdma_ws_node *tc_node)
> +{
> + struct irdma_device *iwdev = vsi->back_vsi;
> + struct iidc_peer_dev *ldev = iwdev->ldev->if_ldev;
> + struct iidc_res rdma_qset_res = {};
> + int ret;
> +
> + rdma_qset_res.cnt_req = 1;
> + rdma_qset_res.res_type = IIDC_RDMA_QSETS_TXSCHED;
> + rdma_qset_res.res[0].res.qsets.qs_handle = tc_node->qs_handle;
> + rdma_qset_res.res[0].res.qsets.tc = tc_node->traffic_class;
> + rdma_qset_res.res[0].res.qsets.vsi_id = vsi->vsi_idx;
> + ret = ldev->ops->alloc_res(ldev, &rdma_qset_res, 0);
> + if (ret) {
> + dev_dbg(rfdev_to_dev(vsi->dev),
> + "WS: LAN alloc_res for rdma qset failed.\n");
> + return IRDMA_ERR_NO_MEMORY;
> + }
> +
> + tc_node->l2_sched_node_id = rdma_qset_res.res[0].res.qsets.teid;
> + vsi->qos[tc_node->user_pri].l2_sched_node_id =
> + rdma_qset_res.res[0].res.qsets.teid;
> +
> + return 0;
> +}
> +
> +/**
> + * irdma_lan_unregister_qset - Unregister qset with LAN driver
> + * @vsi: vsi structure
> + * @tc_node: Traffic class node
> + */
> +static void irdma_lan_unregister_qset(struct irdma_sc_vsi *vsi,
> + struct irdma_ws_node *tc_node)
> +{
> + struct irdma_device *iwdev = vsi->back_vsi;
> + struct iidc_peer_dev *ldev = iwdev->ldev->if_ldev;
> + struct iidc_res rdma_qset_res = {};
> +
> + rdma_qset_res.res_allocated = 1;
> + rdma_qset_res.res_type = IIDC_RDMA_QSETS_TXSCHED;
> + rdma_qset_res.res[0].res.qsets.vsi_id = vsi->vsi_idx;
> + rdma_qset_res.res[0].res.qsets.teid = tc_node->l2_sched_node_id;
> + rdma_qset_res.res[0].res.qsets.qs_handle = tc_node->qs_handle;
> +
> + if (ldev->ops->free_res(ldev, &rdma_qset_res))
> + dev_dbg(rfdev_to_dev(vsi->dev),
> + "WS: LAN free_res for rdma qset failed.\n");
> +}
> +
> +/**
> + * irdma_prep_tc_change - Prepare for TC changes
> + * @ldev: Peer device structure
> + */
> +static void irdma_prep_tc_change(struct iidc_peer_dev *ldev)
> +{
> + struct irdma_device *iwdev;
> +
> + iwdev = irdma_get_device(ldev->netdev);
> + if (!iwdev)
> + return;
> +
> + if (iwdev->vsi.tc_change_pending)
> + goto done;
> +
> + iwdev->vsi.tc_change_pending = true;
> + irdma_sc_suspend_resume_qps(&iwdev->vsi, IRDMA_OP_SUSPEND);
> +
> + /* Wait for all qp's to suspend */
> + wait_event_timeout(iwdev->suspend_wq,
> + !atomic_read(&iwdev->vsi.qp_suspend_reqs),
> + IRDMA_EVENT_TIMEOUT);
> + irdma_ws_reset(&iwdev->vsi);
> +done:
> + irdma_put_device(iwdev);
> +}
> +
> +static void irdma_log_invalid_mtu(u16 mtu, struct irdma_sc_dev *dev)
> +{
> + if (mtu < IRDMA_MIN_MTU_IPV4)
> + dev_warn(rfdev_to_dev(dev),
> + "MTU setting [%d] too low for RDMA traffic. Minimum MTU is 576 for IPv4\n",
> + mtu);
> + else if (mtu < IRDMA_MIN_MTU_IPV6)
> + dev_warn(rfdev_to_dev(dev),
> + "MTU setting [%d] too low for RDMA traffic. Minimum MTU is 1280 for IPv6\\n",
> + mtu);
> +}
> +
> +/**
> + * irdma_event_handler - Called by LAN driver to notify events
> + * @ldev: Peer device structure
> + * @event: event from LAN driver
> + */
> +static void irdma_event_handler(struct iidc_peer_dev *ldev,
> + struct iidc_event *event)
> +{
> + struct irdma_l2params l2params = {};
> + struct irdma_device *iwdev;
> + int i;
> +
> + iwdev = irdma_get_device(ldev->netdev);
> + if (!iwdev)
> + return;
> +
> + if (*event->type & BIT(IIDC_EVENT_LINK_CHANGE)) {
> + dev_dbg(rfdev_to_dev(&iwdev->rf->sc_dev),
> + "CLNT: LINK_CHANGE event\n");
> + } else if (*event->type & BIT(IIDC_EVENT_MTU_CHANGE)) {
> + dev_dbg(rfdev_to_dev(&iwdev->rf->sc_dev),
> + "CLNT: new MTU = %d\n", event->info.mtu);
> + if (iwdev->vsi.mtu != event->info.mtu) {
> + l2params.mtu = event->info.mtu;
> + l2params.mtu_changed = true;
> + irdma_log_invalid_mtu(l2params.mtu, &iwdev->rf->sc_dev);
> + irdma_change_l2params(&iwdev->vsi, &l2params);
> + }
> + } else if (*event->type & BIT(IIDC_EVENT_TC_CHANGE)) {
> + if (!iwdev->vsi.tc_change_pending)
> + goto done;
> +
> + l2params.tc_changed = true;
> + dev_dbg(rfdev_to_dev(&iwdev->rf->sc_dev), "CLNT: TC Change\n");
> + iwdev->dcb = event->info.port_qos.num_tc > 1 ? true : false;
> +
> + for (i = 0; i < IIDC_MAX_USER_PRIORITY; ++i)
> + l2params.up2tc[i] = event->info.port_qos.up2tc[i];
> + irdma_change_l2params(&iwdev->vsi, &l2params);
> + } else if (*event->type & BIT(IIDC_EVENT_API_CHANGE)) {
> + dev_dbg(rfdev_to_dev(&iwdev->rf->sc_dev),
> + "CLNT: API_CHANGE\n");
> + }
> +
> +done:
> + irdma_put_device(iwdev);
> +}
> +
> +/**
> + * irdma_open - client interface operation open for RDMA device
> + * @ldev: LAN device information
> + *
> + * Called by the LAN driver during the processing of client
> + * register.
> + */
> +static int irdma_open(struct iidc_peer_dev *ldev)
> +{
> + struct irdma_handler *hdl;
> + struct irdma_device *iwdev;
> + struct irdma_sc_dev *dev;
> + struct iidc_event events = {};
> + struct irdma_pci_f *rf;
> + struct irdma_priv_ldev *pldev;
> + struct irdma_l2params l2params = {};
> + int i, ret;
> +
> + hdl = irdma_find_handler(ldev->pdev);
> + if (!hdl)
> + return -ENODEV;
> +
> + rf = &hdl->rf;
> + if (rf->init_state != CEQ0_CREATED)
> + return -EINVAL;
> +
> + iwdev = ib_alloc_device(irdma_device, ibdev);
> + if (!iwdev)
> + return -ENOMEM;
> +
> + pldev = &rf->ldev;
> + pldev->pf_vsi_num = ldev->pf_vsi_num;
> + dev = &hdl->rf.sc_dev;
> +
> + iwdev->hdl = hdl;
> + iwdev->rf = rf;
> + iwdev->ldev = &rf->ldev;
> + iwdev->push_mode = 0;
> + iwdev->rcv_wnd = IRDMA_CM_DEFAULT_RCV_WND_SCALED;
> + iwdev->rcv_wscale = IRDMA_CM_DEFAULT_RCV_WND_SCALE;
> + iwdev->netdev = ldev->netdev;
> + iwdev->create_ilq = true;
> + if (rf->protocol_used == IRDMA_ROCE_PROTOCOL_ONLY) {
> + iwdev->roce_mode = true;
> + iwdev->create_ilq = false;
> + }
> + l2params.mtu = ldev->netdev->mtu;
> + l2params.num_tc = ldev->initial_qos_info.num_tc;
> + l2params.num_apps = ldev->initial_qos_info.num_apps;
> + l2params.vsi_prio_type = ldev->initial_qos_info.vsi_priority_type;
> + l2params.vsi_rel_bw = ldev->initial_qos_info.vsi_relative_bw;
> + for (i = 0; i < l2params.num_tc; i++) {
> + l2params.tc_info[i].egress_virt_up =
> + ldev->initial_qos_info.tc_info[i].egress_virt_up;
> + l2params.tc_info[i].ingress_virt_up =
> + ldev->initial_qos_info.tc_info[i].ingress_virt_up;
> + l2params.tc_info[i].prio_type =
> + ldev->initial_qos_info.tc_info[i].prio_type;
> + l2params.tc_info[i].rel_bw =
> + ldev->initial_qos_info.tc_info[i].rel_bw;
> + l2params.tc_info[i].tc_ctx =
> + ldev->initial_qos_info.tc_info[i].tc_ctx;
> + }
> + for (i = 0; i < IIDC_MAX_USER_PRIORITY; i++)
> + l2params.up2tc[i] = ldev->initial_qos_info.up2tc[i];
> +
> + iwdev->vsi_num = ldev->pf_vsi_num;
> + ldev->ops->update_vsi_filter(ldev, IIDC_RDMA_FILTER_BOTH, true);
> +
> + if (irdma_rt_init_hw(rf, iwdev, &l2params)) {
> + ib_dealloc_device(&iwdev->ibdev);
> + return -EIO;
> + }
> +
> + ret = irdma_ib_register_device(iwdev);
> + if (ret) {
> + irdma_rt_deinit_hw(iwdev);
> + ib_dealloc_device(&iwdev->ibdev);
> + return ret;
> + }
> +
> + events.reporter = ldev;
> + set_bit(IIDC_EVENT_LINK_CHANGE, events.type);
> + set_bit(IIDC_EVENT_MTU_CHANGE, events.type);
> + set_bit(IIDC_EVENT_TC_CHANGE, events.type);
> + set_bit(IIDC_EVENT_API_CHANGE, events.type);
> +
> + ldev->ops->reg_for_notification(ldev, &events);
> + dev_dbg(rfdev_to_dev(dev),
> + "INIT: Gen2 VSI[%d] open success ldev=%p\n", ldev->pf_vsi_num,
> + ldev);
> +
> + return 0;
> +}
> +
> +/**
> + * irdma_close - client interface operation close for iwarp/uda device
> + * @ldev: LAN device information
> + * @reason: reason for closing
> + *
> + * Called by the LAN driver during the processing of client
> + * unregister Destroy and clean up the driver resources
> + */
> +static void irdma_close(struct iidc_peer_dev *ldev,
> + enum iidc_close_reason reason)
> +{
> + struct irdma_handler *hdl;
> + struct irdma_device *iwdev;
> + struct irdma_pci_f *rf;
> +
> + hdl = irdma_find_handler(ldev->pdev);
> + if (!hdl)
> + return;
> +
> + rf = &hdl->rf;
> + iwdev = list_first_entry_or_null(&rf->vsi_dev_list, struct irdma_device,
> + list);
> + if (!iwdev)
> + return;
> +
> + if (reason == IIDC_REASON_GLOBR_REQ || reason == IIDC_REASON_CORER_REQ ||
> + reason == IIDC_REASON_PFR_REQ || rf->reset) {
> + iwdev->reset = true;
> + rf->reset = true;
> + }
> +
> + irdma_ib_unregister_device(iwdev);
> + ldev->ops->update_vsi_filter(ldev, IIDC_RDMA_FILTER_BOTH, false);
> + if (rf->reset)
> + schedule_delayed_work(&rf->rst_work, rf->rst_to * HZ);
> +
> + pr_debug("INIT: Gen2 VSI[%d] close complete ldev=%p\n",
> + ldev->pf_vsi_num, ldev);
> +}
> +
> +/**
> + * irdma_remove - GEN_2 device remove()
> + * @vdev: virtbus device
> + *
> + * Called on module unload.
> + */
> +int irdma_remove(struct virtbus_device *vdev)
> +{
> + struct iidc_virtbus_object *vo =
> + container_of(vdev, struct iidc_virtbus_object, vdev);
> + struct iidc_peer_dev *ldev = vo->peer_dev;
> + struct irdma_handler *hdl;
> +
> + hdl = irdma_find_handler(ldev->pdev);
> + if (!hdl)
> + return 0;
> +
> + cancel_delayed_work_sync(&hdl->rf.rst_work);
> + ldev->ops->peer_unregister(ldev);
> +
> + irdma_deinit_rf(&hdl->rf);
> + pr_debug("INIT: Gen2 device remove success ldev=%p\n", ldev);
> +
> + return 0;
> +}
> +
> +static const struct iidc_peer_ops irdma_peer_ops = {
> + .close = irdma_close,
> + .event_handler = irdma_event_handler,
> + .open = irdma_open,
> + .prep_tc_change = irdma_prep_tc_change,
> +};
> +
> +static struct iidc_peer_drv irdma_peer_drv = {
> + .driver_id = IIDC_PEER_RDMA_DRIVER,
> + .name = KBUILD_MODNAME,
> +};
> +
> +/**
> + * icrdma_request_reset - Request a reset
> + * @rf: RDMA PCI function
> + */
> +static void icrdma_request_reset(struct irdma_pci_f *rf)
> +{
> + struct iidc_peer_dev *ldev = rf->ldev.if_ldev;
> +
> + dev_warn(rfdev_to_dev(&rf->sc_dev), "Requesting a a reset\n");
> + ldev->ops->request_reset(ldev, IIDC_PEER_PFR);
> +}
> +
> +/**
> + * irdma_probe - GEN_2 device probe()
> + * @vdev: virtbus device
> + *
> + * Create device resources, set up queues, pble and hmc objects.
> + * Return 0 if successful, otherwise return error
> + */
> +int irdma_probe(struct virtbus_device *vdev)
> +{
> + struct iidc_virtbus_object *vo =
> + container_of(vdev, struct iidc_virtbus_object, vdev);
> + struct iidc_peer_dev *ldev = vo->peer_dev;
> + struct irdma_handler *hdl;
> + struct irdma_pci_f *rf;
> + struct irdma_sc_dev *dev;
> + struct irdma_priv_ldev *pldev;
> + int err;
> +
> + hdl = irdma_find_handler(ldev->pdev);
> + if (hdl)
> + return -EBUSY;
> +
> + hdl = kzalloc(sizeof(*hdl), GFP_KERNEL);
> + if (!hdl)
> + return -ENOMEM;
> +
> + rf = &hdl->rf;
> + pldev = &rf->ldev;
> + hdl->ldev = pldev;
> + hdl->vdev = vdev;
> + rf->hdl = hdl;
> + dev = &rf->sc_dev;
> + dev->back_dev = rf;
> + rf->gen_ops.init_hw = icrdma_init_hw;
> + rf->gen_ops.request_reset = icrdma_request_reset;
> + rf->gen_ops.register_qset = irdma_lan_register_qset;
> + rf->gen_ops.unregister_qset = irdma_lan_unregister_qset;
> + pldev->if_ldev = ldev;
> + rf->rdma_ver = IRDMA_GEN_2;
> + irdma_init_rf_config_params(rf);
> + INIT_DELAYED_WORK(&rf->rst_work, irdma_reset_task);
> + dev->pci_rev = ldev->pdev->revision;
> + rf->default_vsi.vsi_idx = ldev->pf_vsi_num;
> + /* save information from ldev to priv_ldev*/
> + pldev->fn_num = PCI_FUNC(ldev->pdev->devfn);
> + rf->hw.hw_addr = ldev->hw_addr;
> + rf->pdev = ldev->pdev;
> + rf->netdev = ldev->netdev;
> + pldev->ftype = ldev->ftype;
> + pldev->msix_count = ldev->msix_count;
> + pldev->msix_entries = ldev->msix_entries;
> + irdma_add_handler(hdl);
> + if (irdma_ctrl_init_hw(rf)) {
> + err = -EIO;
> + goto err_ctrl_init;
> + }
> + ldev->peer_ops = &irdma_peer_ops;
> + ldev->peer_drv = &irdma_peer_drv;
> + err = ldev->ops->peer_register(ldev);
> + if (err)
> + goto err_peer_reg;
> +
> + dev_dbg(rfdev_to_dev(dev),
> + "INIT: Gen2 device probe success ldev=%p\n", ldev);
> +
> + return 0;
> +
> +err_peer_reg:
> + irdma_ctrl_deinit_hw(rf);
> +err_ctrl_init:
> + irdma_del_handler(rf->hdl);
> + kfree(rf->hdl);
> +
> + return err;
> +}
> +
> +/*
> + * irdma_lan_vsi_ready - check to see if lan reset done
> + * @vdev: virtbus device
> + */
> +bool irdma_lan_vsi_ready(struct virtbus_device *vdev)
> +{
> + struct iidc_virtbus_object *vo =
> + container_of(vdev, struct iidc_virtbus_object, vdev);
> + struct iidc_peer_dev *ldev = vo->peer_dev;
> +
> + return ldev->ops->is_vsi_ready(ldev) ? true : false;
> +}
> diff --git a/drivers/infiniband/hw/irdma/main.c b/drivers/infiniband/hw/irdma/main.c
> new file mode 100644
> index 000000000000..aa7f2b2f496b
> --- /dev/null
> +++ b/drivers/infiniband/hw/irdma/main.c
> @@ -0,0 +1,572 @@
> +// SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB
> +/* Copyright (c) 2015 - 2019 Intel Corporation */
> +#include "main.h"
> +
> +bool irdma_upload_context;
> +
> +MODULE_ALIAS("i40iw");
> +MODULE_AUTHOR("Intel Corporation, <e1000-rdma@lists.sourceforge.net>");
> +MODULE_DESCRIPTION("Intel(R) Ethernet Protocol Driver for RDMA");
> +MODULE_LICENSE("Dual BSD/GPL");
> +
> +LIST_HEAD(irdma_handlers);
> +DEFINE_SPINLOCK(irdma_handler_lock);
> +
> +static struct notifier_block irdma_inetaddr_notifier = {
> + .notifier_call = irdma_inetaddr_event
> +};
> +
> +static struct notifier_block irdma_inetaddr6_notifier = {
> + .notifier_call = irdma_inet6addr_event
> +};
> +
> +static struct notifier_block irdma_net_notifier = {
> + .notifier_call = irdma_net_event
> +};
> +
> +static struct notifier_block irdma_netdevice_notifier = {
> + .notifier_call = irdma_netdevice_event
> +};
> +
> +/**
> + * set_protocol_used - set protocol_used against HW generation and roce_ena flag
> + * @rf: RDMA PCI function
> + * @roce_ena: RoCE enabled flag
> + */
> +static void set_protocol_used(struct irdma_pci_f *rf, bool roce_ena)
> +{
> + switch (rf->rdma_ver) {
> + case IRDMA_GEN_2:
> + rf->protocol_used = roce_ena ? IRDMA_ROCE_PROTOCOL_ONLY :
> + IRDMA_IWARP_PROTOCOL_ONLY;
> + break;
> + case IRDMA_GEN_1:
> + rf->protocol_used = IRDMA_IWARP_PROTOCOL_ONLY;
> + break;
> + }
> +}
> +
> +void irdma_init_rf_config_params(struct irdma_pci_f *rf)
> +{
> + struct irdma_dl_priv *dl_priv;
> +
> + rf->rsrc_profile = IRDMA_HMC_PROFILE_DEFAULT;
> + dl_priv = dev_get_drvdata(&rf->hdl->vdev->dev);
> + rf->limits_sel = dl_priv->limits_sel;
> + set_protocol_used(rf, dl_priv->roce_ena);
> + rf->rst_to = IRDMA_RST_TIMEOUT_HZ;
> +}
> +
> +/*
> + * irdma_deinit_rf - Clean up resources allocated for RF
> + * @rf: RDMA PCI function
> + */
> +void irdma_deinit_rf(struct irdma_pci_f *rf)
> +{
> + irdma_ctrl_deinit_hw(rf);
> + irdma_del_handler(rf->hdl);
> + kfree(rf->hdl);
> +}
> +
> +/**
> + * irdma_find_ice_handler - find a handler given a client info
> + * @pdev: pointer to pci dev info
> + */
> +struct irdma_handler *irdma_find_handler(struct pci_dev *pdev)
> +{
> + struct irdma_handler *hdl;
> + unsigned long flags;
> +
> + spin_lock_irqsave(&irdma_handler_lock, flags);
> + list_for_each_entry (hdl, &irdma_handlers, list) {
> + if (hdl->rf.pdev->devfn == pdev->devfn &&
> + hdl->rf.pdev->bus->number == pdev->bus->number) {
> + spin_unlock_irqrestore(&irdma_handler_lock, flags);
> + return hdl;
> + }
> + }
> + spin_unlock_irqrestore(&irdma_handler_lock, flags);
> +
> + return NULL;
> +}
> +
> +/**
> + * irdma_add_handler - add a handler to the list
> + * @hdl: handler to be added to the handler list
> + */
> +void irdma_add_handler(struct irdma_handler *hdl)
> +{
> + unsigned long flags;
> +
> + spin_lock_irqsave(&irdma_handler_lock, flags);
> + list_add(&hdl->list, &irdma_handlers);
> + spin_unlock_irqrestore(&irdma_handler_lock, flags);
> +}
> +
> +/**
> + * irdma_del_handler - delete a handler from the list
> + * @hdl: handler to be deleted from the handler list
> + */
> +void irdma_del_handler(struct irdma_handler *hdl)
> +{
> + unsigned long flags;
> +
> + spin_lock_irqsave(&irdma_handler_lock, flags);
> + list_del(&hdl->list);
> + spin_unlock_irqrestore(&irdma_handler_lock, flags);
> +}
> +
> +/**
> + * irdma_register_notifiers - register tcp ip notifiers
> + */
> +void irdma_register_notifiers(void)
> +{
> + register_inetaddr_notifier(&irdma_inetaddr_notifier);
> + register_inet6addr_notifier(&irdma_inetaddr6_notifier);
> + register_netevent_notifier(&irdma_net_notifier);
> + register_netdevice_notifier(&irdma_netdevice_notifier);
> +}
> +
> +void irdma_unregister_notifiers(void)
> +{
> + unregister_netevent_notifier(&irdma_net_notifier);
> + unregister_inetaddr_notifier(&irdma_inetaddr_notifier);
> + unregister_inet6addr_notifier(&irdma_inetaddr6_notifier);
> + unregister_netdevice_notifier(&irdma_netdevice_notifier);
> +}
> +
> +/**
> + * irdma_add_ipv6_addr - add ipv6 address to the hw arp table
> + * @iwdev: irdma device
> + */
> +static void irdma_add_ipv6_addr(struct irdma_device *iwdev)
> +{
> + struct net_device *ip_dev;
> + struct inet6_dev *idev;
> + struct inet6_ifaddr *ifp, *tmp;
> + u32 local_ipaddr6[4];
> +
> + rcu_read_lock();
> + for_each_netdev_rcu (&init_net, ip_dev) {
> + if (((rdma_vlan_dev_vlan_id(ip_dev) < 0xFFFF &&
> + rdma_vlan_dev_real_dev(ip_dev) == iwdev->netdev) ||
> + ip_dev == iwdev->netdev) && ip_dev->flags & IFF_UP) {
> + idev = __in6_dev_get(ip_dev);
> + if (!idev) {
> + dev_err(rfdev_to_dev(&iwdev->rf->sc_dev),
> + "ipv6 inet device not found\n");
> + break;
> + }
> + list_for_each_entry_safe (ifp, tmp, &idev->addr_list,
> + if_list) {
> + dev_dbg(rfdev_to_dev(&iwdev->rf->sc_dev),
> + "INIT: IP=%pI6, vlan_id=%d, MAC=%pM\n",
> + &ifp->addr,
> + rdma_vlan_dev_vlan_id(ip_dev),
> + ip_dev->dev_addr);
> +
> + irdma_copy_ip_ntohl(local_ipaddr6,
> + ifp->addr.in6_u.u6_addr32);
> + irdma_manage_arp_cache(iwdev->rf,
> + ip_dev->dev_addr,
> + local_ipaddr6, false,
> + IRDMA_ARP_ADD);
> + }
> + }
> + }
> + rcu_read_unlock();
> +}
> +
> +/**
> + * irdma_add_ipv4_addr - add ipv4 address to the hw arp table
> + * @iwdev: irdma device
> + */
> +static void irdma_add_ipv4_addr(struct irdma_device *iwdev)
> +{
> + struct net_device *dev;
> + struct in_device *idev;
> + u32 ip_addr;
> +
> + rcu_read_lock();
> + for_each_netdev_rcu (&init_net, dev) {
> + if (((rdma_vlan_dev_vlan_id(dev) < 0xFFFF &&
> + rdma_vlan_dev_real_dev(dev) == iwdev->netdev) ||
> + dev == iwdev->netdev) && dev->flags & IFF_UP) {
> + const struct in_ifaddr *ifa;
> +
> + idev = __in_dev_get_rcu(dev);
> + if (!idev)
> + continue;
> + in_dev_for_each_ifa_rcu(ifa, idev) {
> + dev_dbg(rfdev_to_dev(&iwdev->rf->sc_dev),
> + "CM: IP=%pI4, vlan_id=%d, MAC=%pM\n",
> + &ifa->ifa_address,
> + rdma_vlan_dev_vlan_id(dev),
> + dev->dev_addr);
> +
> + ip_addr = ntohl(ifa->ifa_address);
> + irdma_manage_arp_cache(iwdev->rf, dev->dev_addr,
> + &ip_addr, true,
> + IRDMA_ARP_ADD);
> + }
> + }
> + }
> + rcu_read_unlock();
> +}
> +
> +/**
> + * irdma_add_ip - add ip addresses
> + * @iwdev: irdma device
> + *
> + * Add ipv4/ipv6 addresses to the arp cache
> + */
> +void irdma_add_ip(struct irdma_device *iwdev)
> +{
> + irdma_add_ipv4_addr(iwdev);
> + irdma_add_ipv6_addr(iwdev);
> +}
> +
> +static int irdma_devlink_rsrc_limits_validate(struct devlink *dl, u32 id,
> + union devlink_param_value val,
> + struct netlink_ext_ack *extack)
> +{
> + u8 value = val.vu8;
> +
> + if (value > 5) {
> + NL_SET_ERR_MSG_MOD(extack, "resource limits selector range is (0-5)");
> + return -ERANGE;
> + }
> +
> + return 0;
> +}
> +
> +static int irdma_devlink_enable_roce_validate(struct devlink *dl, u32 id,
> + union devlink_param_value val,
> + struct netlink_ext_ack *extack)
> +{
> + struct irdma_dl_priv *priv = devlink_priv(dl);
> + const struct virtbus_dev_id *vid = priv->vdev->matched_element;
> + u8 gen_ver = vid->driver_data;
> + bool value = val.vbool;
> +
> + if (value && gen_ver == IRDMA_GEN_1) {
> + NL_SET_ERR_MSG_MOD(extack, "RoCE not supported on device");
> + return -EOPNOTSUPP;
> + }
> +
> + return 0;
> +}
> +
> +static int irdma_devlink_upload_ctx_get(struct devlink *devlink, u32 id,
> + struct devlink_param_gset_ctx *ctx)
> +{
> + ctx->val.vbool = irdma_upload_context;
> + return 0;
> +}
> +
> +static int irdma_devlink_upload_ctx_set(struct devlink *devlink, u32 id,
> + struct devlink_param_gset_ctx *ctx)
> +{
> + irdma_upload_context = ctx->val.vbool;
> + return 0;
> +}
> +
> +enum irdma_dl_param_id {
> + IRDMA_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX,
> + IRDMA_DEVLINK_PARAM_ID_LIMITS_SELECTOR,
> + IRDMA_DEVLINK_PARAM_ID_UPLOAD_CONTEXT,
> +};
> +
> +static const struct devlink_param irdma_devlink_params[] = {
> + /* Common */
> + DEVLINK_PARAM_DRIVER(IRDMA_DEVLINK_PARAM_ID_LIMITS_SELECTOR,
> + "resource_limits_selector", DEVLINK_PARAM_TYPE_U8,
> + BIT(DEVLINK_PARAM_CMODE_DRIVERINIT),
> + NULL, NULL, irdma_devlink_rsrc_limits_validate),
> + DEVLINK_PARAM_DRIVER(IRDMA_DEVLINK_PARAM_ID_UPLOAD_CONTEXT,
> + "upload_context", DEVLINK_PARAM_TYPE_BOOL,
> + BIT(DEVLINK_PARAM_CMODE_RUNTIME),
> + irdma_devlink_upload_ctx_get,
> + irdma_devlink_upload_ctx_set, NULL),
> + DEVLINK_PARAM_GENERIC(ENABLE_ROCE, BIT(DEVLINK_PARAM_CMODE_DRIVERINIT),
> + NULL, NULL, irdma_devlink_enable_roce_validate)
> +};
> +
> +static int irdma_devlink_reload_down(struct devlink *devlink, bool netns_change,
> + struct netlink_ext_ack *extack)
> +{
> + struct irdma_dl_priv *priv = devlink_priv(devlink);
> + const struct virtbus_dev_id *id = priv->vdev->matched_element;
> + u8 gen_ver = id->driver_data;
> +
> + switch (gen_ver) {
> + case IRDMA_GEN_2:
> + irdma_remove(priv->vdev);
> + break;
> + case IRDMA_GEN_1:
> + i40iw_remove(priv->vdev);
> + break;
> + default:
> + return -ENODEV;
> + }
> +
> + return 0;
> +}
> +
> +static int irdma_devlink_reload_up(struct devlink *devlink,
> + struct netlink_ext_ack *extack)
> +{
> + struct irdma_dl_priv *priv = devlink_priv(devlink);
> + union devlink_param_value saved_value;
> + const struct virtbus_dev_id *id = priv->vdev->matched_element;
Like irdma_probe(), struct iidc_virtbus_object *vo is accesible for the
given priv.
Please use struct iidc_virtbus_object for any sharing between two drivers.
matched_element modification inside the virtbus match() function and
accessing pointer to some driver data between two driver through this
matched_element is not appropriate.
^ permalink raw reply
* net-next is OPEN
From: David Miller @ 2020-02-14 22:13 UTC (permalink / raw)
To: netdev; +Cc: bpf
Play nice kids.
^ permalink raw reply
* Re: [PATCH v2 2/5] tests/overlay: mount: replace overlay hardcode with OVL_FSTYP variable
From: Amir Goldstein @ 2020-02-14 22:12 UTC (permalink / raw)
To: Mauricio Faria de Oliveira; +Cc: fstests
In-Reply-To: <20200214151848.8328-3-mfo@canonical.com>
On Fri, Feb 14, 2020 at 5:18 PM Mauricio Faria de Oliveira
<mfo@canonical.com> wrote:
>
> This allows other filesystem types to actually be used in these tests.
>
> Well, aufs does not support the options used in most of them anyway,
> so just let it fail to mount (instead of implementing common helpers
> for middle layers.)
>
> On fuse-overlayfs (coming) the options should be supported/compatible,
> and thus just work, so no further changes are needed.
>
> Suggested-by: Amir Goldstein <amir73il@gmail.com>
> Signed-off-by: Mauricio Faria de Oliveira <mfo@canonical.com>
I'm fine with this patch, you may add:
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
but for aufs testers sake, it would be nicer if you added to those tests:
[ "$OVL_FSTYP" != aufs ] || _notrun "This test is not compatible with aufs"
Thanks,
Amir.
> ---
> tests/overlay/011 | 2 +-
> tests/overlay/035 | 2 +-
> tests/overlay/052 | 4 ++--
> tests/overlay/053 | 4 ++--
> tests/overlay/062 | 2 +-
> 5 files changed, 7 insertions(+), 7 deletions(-)
>
> diff --git a/tests/overlay/011 b/tests/overlay/011
> index 1d09341b250a..0b39416c9835 100755
> --- a/tests/overlay/011
> +++ b/tests/overlay/011
> @@ -53,7 +53,7 @@ $SETFATTR_PROG -n "trusted.overlay.opaque" -v "y" $upperdir/testdir
> # $upperdir overlaid on top of $lowerdir, so that "trusted.overlay.opaque"
> # xattr should be honored and should not be listed
> # mount readonly, because there's no upper and workdir
> -$MOUNT_PROG -t overlay -o ro -o lowerdir=$upperdir:$lowerdir $OVL_BASE_SCRATCH_MNT $SCRATCH_MNT
> +$MOUNT_PROG -t $OVL_FSTYP -o ro -o lowerdir=$upperdir:$lowerdir $OVL_BASE_SCRATCH_MNT $SCRATCH_MNT
>
> # Dump trusted.overlay xattr, we should not see the "opaque" xattr
> _getfattr -d -m overlay $SCRATCH_MNT/testdir
> diff --git a/tests/overlay/035 b/tests/overlay/035
> index c0aae935bcf1..bbb158f319cd 100755
> --- a/tests/overlay/035
> +++ b/tests/overlay/035
> @@ -52,7 +52,7 @@ mkdir -p $lowerdir1 $lowerdir2 $upperdir $workdir
>
> # Mount overlay with lower layers only.
> # Verify that overlay is mounted read-only and that it cannot be remounted rw.
> -$MOUNT_PROG -t overlay -o"lowerdir=$lowerdir2:$lowerdir1" \
> +$MOUNT_PROG -t $OVL_FSTYP -o"lowerdir=$lowerdir2:$lowerdir1" \
> $OVL_BASE_SCRATCH_MNT $SCRATCH_MNT
> touch $SCRATCH_MNT/foo 2>&1 | _filter_scratch
> $MOUNT_PROG -o remount,rw $SCRATCH_MNT 2>&1 | _filter_ro_mount
> diff --git a/tests/overlay/052 b/tests/overlay/052
> index b1cf0da64bbf..35a7b5f1a903 100755
> --- a/tests/overlay/052
> +++ b/tests/overlay/052
> @@ -147,7 +147,7 @@ unmount_dirs
>
> # Check encode/decode/read of lower file handles on lower layers only r/o overlay.
> # For non-upper overlay mount, nfs_export requires disabling redirect_dir.
> -$MOUNT_PROG -t overlay $OVL_BASE_SCRATCH_MNT $SCRATCH_MNT \
> +$MOUNT_PROG -t $OVL_FSTYP $OVL_BASE_SCRATCH_MNT $SCRATCH_MNT \
> -o ro,redirect_dir=nofollow,nfs_export=on,lowerdir=$middle:$lower
> test_file_handles $SCRATCH_MNT/lowertestdir -rp
> test_file_handles $SCRATCH_MNT/lowertestdir/subdir -rp
> @@ -158,7 +158,7 @@ unmount_dirs
> # Overlay lookup cannot follow the redirect from $upper/lowertestdir.new to
> # $lower/lowertestdir. Instead, we mount an overlay subtree rooted at these
> # directories.
> -$MOUNT_PROG -t overlay $OVL_BASE_SCRATCH_MNT $SCRATCH_MNT \
> +$MOUNT_PROG -t $OVL_FSTYP $OVL_BASE_SCRATCH_MNT $SCRATCH_MNT \
> -o ro,redirect_dir=nofollow,nfs_export=on,lowerdir=$upper/lowertestdir.new:$lower/lowertestdir
> test_file_handles $SCRATCH_MNT -r
> test_file_handles $SCRATCH_MNT/subdir -rp
> diff --git a/tests/overlay/053 b/tests/overlay/053
> index ff95424741ec..5ac19b32c3cb 100755
> --- a/tests/overlay/053
> +++ b/tests/overlay/053
> @@ -169,7 +169,7 @@ unmount_dirs
>
> # Check encode/decode/read of lower file handles on lower layers only r/o overlay.
> # For non-upper overlay mount, nfs_export requires disabling redirect_dir.
> -$MOUNT_PROG -t overlay $OVL_BASE_SCRATCH_MNT $SCRATCH_MNT \
> +$MOUNT_PROG -t $OVL_FSTYP $OVL_BASE_SCRATCH_MNT $SCRATCH_MNT \
> -o ro,redirect_dir=nofollow,nfs_export=on,lowerdir=$middle:$lower
> test_file_handles $SCRATCH_MNT/lowertestdir -rp
> test_file_handles $SCRATCH_MNT/lowertestdir/subdir -rp
> @@ -180,7 +180,7 @@ unmount_dirs
> # Overlay lookup cannot follow the redirect from $upper/lowertestdir.new to
> # $lower/lowertestdir. Instead, we mount an overlay subtree rooted at these
> # directories.
> -$MOUNT_PROG -t overlay $OVL_BASE_SCRATCH_MNT $SCRATCH_MNT \
> +$MOUNT_PROG -t $OVL_FSTYP $OVL_BASE_SCRATCH_MNT $SCRATCH_MNT \
> -o ro,redirect_dir=nofollow,nfs_export=on,lowerdir=$upper/lowertestdir.new:$lower/lowertestdir
> test_file_handles $SCRATCH_MNT -r
> test_file_handles $SCRATCH_MNT/subdir -rp
> diff --git a/tests/overlay/062 b/tests/overlay/062
> index 2c86a4b6fd1e..afd3562bfd33 100755
> --- a/tests/overlay/062
> +++ b/tests/overlay/062
> @@ -72,7 +72,7 @@ create_test_files $lowertestdir
> $MOUNT_PROG --bind $lowertestdir $lowertestdir
>
> # For non-upper overlay mount, nfs_export requires disabling redirect_dir.
> -$MOUNT_PROG -t overlay $OVL_BASE_SCRATCH_MNT $SCRATCH_MNT \
> +$MOUNT_PROG -t $OVL_FSTYP $OVL_BASE_SCRATCH_MNT $SCRATCH_MNT \
> -o ro,redirect_dir=nofollow,nfs_export=on,lowerdir=$lower:$lower2
>
> # Decode an overlay directory file handle, whose underlying lower dir dentry
> --
> 2.20.1
>
^ permalink raw reply
* Re: [PATCH] memcg: net: do not associate sock with unrelated memcg
From: Shakeel Butt @ 2020-02-14 22:09 UTC (permalink / raw)
To: Roman Gushchin
Cc: Johannes Weiner, Eric Dumazet, Greg Thelen, Michal Hocko,
Vladimir Davydov, Andrew Morton, Cgroups, Linux MM, LKML
In-Reply-To: <CALvZod4sum32d_ujFrRFhBVrE6TmhHrwWu=LPX+mG0urD4w80w@mail.gmail.com>
On Fri, Feb 14, 2020 at 1:52 PM Shakeel Butt <shakeelb@google.com> wrote:
>
> On Fri, Feb 14, 2020 at 1:47 PM Roman Gushchin <guro@fb.com> wrote:
> >
> > Hello, Shakeel!
> >
> > On Thu, Feb 13, 2020 at 11:12:33PM -0800, Shakeel Butt wrote:
> > > We are testing network memory accounting in our setup and noticed
> > > inconsistent network memory usage and often unrelated memcgs network
> > > usage correlates with testing workload. On further inspection, it seems
> > > like mem_cgroup_sk_alloc() is broken in irq context specially for
> > > cgroup v1.
> >
> > A great catch!
> >
> > >
> > > mem_cgroup_sk_alloc() can be called in irq context and kind
> > > of assumes that it can only happen from sk_clone_lock() and the source
> > > sock object has already associated memcg. However in cgroup v1, where
> > > network memory accounting is opt-in, the source sock can be not
> > > associated with any memcg and the new cloned sock can get associated
> > > with unrelated interrupted memcg.
> > >
> > > Cgroup v2 can also suffer if the source sock object was created by
> > > process in the root memcg or if sk_alloc() is called in irq context.
> >
> > Do you mind sharing a call trace?
> >
>
> Sure, see below. I added a dump_stack() in mem_cgroup_sk_alloc().
>
> [ 647.255327] CPU: 68 PID: 15859 Comm: ssh Tainted: G O
> 5.6.0-smp-DEV #1
> [ 647.255328] Hardware name: ...
> [ 647.255328] Call Trace:
> [ 647.255329] <IRQ>
> [ 647.255333] dump_stack+0x57/0x75
> [ 647.255336] mem_cgroup_sk_alloc+0xe9/0xf0
> [ 647.255337] sk_clone_lock+0x2a7/0x420
> [ 647.255339] inet_csk_clone_lock+0x1b/0x110
> [ 647.255340] tcp_create_openreq_child+0x23/0x3b0
> [ 647.255342] tcp_v6_syn_recv_sock+0x88/0x730
> [ 647.255343] tcp_check_req+0x429/0x560
> [ 647.255345] tcp_v6_rcv+0x72d/0xa40
> [ 647.255347] ip6_protocol_deliver_rcu+0xc9/0x400
> [ 647.255348] ip6_input+0x44/0xd0
> [ 647.255349] ? ip6_protocol_deliver_rcu+0x400/0x400
> [ 647.255350] ip6_rcv_finish+0x71/0x80
> [ 647.255351] ipv6_rcv+0x5b/0xe0
> [ 647.255352] ? ip6_sublist_rcv+0x2e0/0x2e0
> [ 647.255354] process_backlog+0x108/0x1e0
> [ 647.255355] net_rx_action+0x26b/0x460
> [ 647.255357] __do_softirq+0x104/0x2a6
> [ 647.255358] do_softirq_own_stack+0x2a/0x40
> [ 647.255359] </IRQ>
> [ 647.255361] do_softirq.part.19+0x40/0x50
> [ 647.255362] __local_bh_enable_ip+0x51/0x60
> [ 647.255363] ip6_finish_output2+0x23d/0x520
> [ 647.255365] ? ip6table_mangle_hook+0x55/0x160
> [ 647.255366] __ip6_finish_output+0xa1/0x100
> [ 647.255367] ip6_finish_output+0x30/0xd0
> [ 647.255368] ip6_output+0x73/0x120
> [ 647.255369] ? __ip6_finish_output+0x100/0x100
> [ 647.255370] ip6_xmit+0x2e3/0x600
> [ 647.255372] ? ipv6_anycast_cleanup+0x50/0x50
> [ 647.255373] ? inet6_csk_route_socket+0x136/0x1e0
> [ 647.255374] ? skb_free_head+0x1e/0x30
> [ 647.255375] inet6_csk_xmit+0x95/0xf0
> [ 647.255377] __tcp_transmit_skb+0x5b4/0xb20
> [ 647.255378] __tcp_send_ack.part.60+0xa3/0x110
> [ 647.255379] tcp_send_ack+0x1d/0x20
> [ 647.255380] tcp_rcv_state_process+0xe64/0xe80
> [ 647.255381] ? tcp_v6_connect+0x5d1/0x5f0
> [ 647.255383] tcp_v6_do_rcv+0x1b1/0x3f0
> [ 647.255384] ? tcp_v6_do_rcv+0x1b1/0x3f0
> [ 647.255385] __release_sock+0x7f/0xd0
> [ 647.255386] release_sock+0x30/0xa0
> [ 647.255388] __inet_stream_connect+0x1c3/0x3b0
> [ 647.255390] ? prepare_to_wait+0xb0/0xb0
> [ 647.255391] inet_stream_connect+0x3b/0x60
> [ 647.255394] __sys_connect+0x101/0x120
> [ 647.255395] ? __sys_getsockopt+0x11b/0x140
> [ 647.255397] __x64_sys_connect+0x1a/0x20
> [ 647.255398] do_syscall_64+0x51/0x200
> [ 647.255399] entry_SYSCALL_64_after_hwframe+0x44/0xa9
> [ 647.255401] RIP: 0033:0x7f45464fcd50
>
> > Also, shouldn't cgroup_sk_alloc() be changed in a similar way?
> >
>
> I will check cgroup_sk_alloc() too.
>
Yes, cgroup_sk_alloc() should be changed similarly too.
^ permalink raw reply
* Re: [PATCH] memcg: net: do not associate sock with unrelated memcg
From: Shakeel Butt @ 2020-02-14 22:09 UTC (permalink / raw)
To: Roman Gushchin
Cc: Johannes Weiner, Eric Dumazet, Greg Thelen, Michal Hocko,
Vladimir Davydov, Andrew Morton, Cgroups, Linux MM, LKML
In-Reply-To: <CALvZod4sum32d_ujFrRFhBVrE6TmhHrwWu=LPX+mG0urD4w80w-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
On Fri, Feb 14, 2020 at 1:52 PM Shakeel Butt <shakeelb-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org> wrote:
>
> On Fri, Feb 14, 2020 at 1:47 PM Roman Gushchin <guro-b10kYP2dOMg@public.gmane.org> wrote:
> >
> > Hello, Shakeel!
> >
> > On Thu, Feb 13, 2020 at 11:12:33PM -0800, Shakeel Butt wrote:
> > > We are testing network memory accounting in our setup and noticed
> > > inconsistent network memory usage and often unrelated memcgs network
> > > usage correlates with testing workload. On further inspection, it seems
> > > like mem_cgroup_sk_alloc() is broken in irq context specially for
> > > cgroup v1.
> >
> > A great catch!
> >
> > >
> > > mem_cgroup_sk_alloc() can be called in irq context and kind
> > > of assumes that it can only happen from sk_clone_lock() and the source
> > > sock object has already associated memcg. However in cgroup v1, where
> > > network memory accounting is opt-in, the source sock can be not
> > > associated with any memcg and the new cloned sock can get associated
> > > with unrelated interrupted memcg.
> > >
> > > Cgroup v2 can also suffer if the source sock object was created by
> > > process in the root memcg or if sk_alloc() is called in irq context.
> >
> > Do you mind sharing a call trace?
> >
>
> Sure, see below. I added a dump_stack() in mem_cgroup_sk_alloc().
>
> [ 647.255327] CPU: 68 PID: 15859 Comm: ssh Tainted: G O
> 5.6.0-smp-DEV #1
> [ 647.255328] Hardware name: ...
> [ 647.255328] Call Trace:
> [ 647.255329] <IRQ>
> [ 647.255333] dump_stack+0x57/0x75
> [ 647.255336] mem_cgroup_sk_alloc+0xe9/0xf0
> [ 647.255337] sk_clone_lock+0x2a7/0x420
> [ 647.255339] inet_csk_clone_lock+0x1b/0x110
> [ 647.255340] tcp_create_openreq_child+0x23/0x3b0
> [ 647.255342] tcp_v6_syn_recv_sock+0x88/0x730
> [ 647.255343] tcp_check_req+0x429/0x560
> [ 647.255345] tcp_v6_rcv+0x72d/0xa40
> [ 647.255347] ip6_protocol_deliver_rcu+0xc9/0x400
> [ 647.255348] ip6_input+0x44/0xd0
> [ 647.255349] ? ip6_protocol_deliver_rcu+0x400/0x400
> [ 647.255350] ip6_rcv_finish+0x71/0x80
> [ 647.255351] ipv6_rcv+0x5b/0xe0
> [ 647.255352] ? ip6_sublist_rcv+0x2e0/0x2e0
> [ 647.255354] process_backlog+0x108/0x1e0
> [ 647.255355] net_rx_action+0x26b/0x460
> [ 647.255357] __do_softirq+0x104/0x2a6
> [ 647.255358] do_softirq_own_stack+0x2a/0x40
> [ 647.255359] </IRQ>
> [ 647.255361] do_softirq.part.19+0x40/0x50
> [ 647.255362] __local_bh_enable_ip+0x51/0x60
> [ 647.255363] ip6_finish_output2+0x23d/0x520
> [ 647.255365] ? ip6table_mangle_hook+0x55/0x160
> [ 647.255366] __ip6_finish_output+0xa1/0x100
> [ 647.255367] ip6_finish_output+0x30/0xd0
> [ 647.255368] ip6_output+0x73/0x120
> [ 647.255369] ? __ip6_finish_output+0x100/0x100
> [ 647.255370] ip6_xmit+0x2e3/0x600
> [ 647.255372] ? ipv6_anycast_cleanup+0x50/0x50
> [ 647.255373] ? inet6_csk_route_socket+0x136/0x1e0
> [ 647.255374] ? skb_free_head+0x1e/0x30
> [ 647.255375] inet6_csk_xmit+0x95/0xf0
> [ 647.255377] __tcp_transmit_skb+0x5b4/0xb20
> [ 647.255378] __tcp_send_ack.part.60+0xa3/0x110
> [ 647.255379] tcp_send_ack+0x1d/0x20
> [ 647.255380] tcp_rcv_state_process+0xe64/0xe80
> [ 647.255381] ? tcp_v6_connect+0x5d1/0x5f0
> [ 647.255383] tcp_v6_do_rcv+0x1b1/0x3f0
> [ 647.255384] ? tcp_v6_do_rcv+0x1b1/0x3f0
> [ 647.255385] __release_sock+0x7f/0xd0
> [ 647.255386] release_sock+0x30/0xa0
> [ 647.255388] __inet_stream_connect+0x1c3/0x3b0
> [ 647.255390] ? prepare_to_wait+0xb0/0xb0
> [ 647.255391] inet_stream_connect+0x3b/0x60
> [ 647.255394] __sys_connect+0x101/0x120
> [ 647.255395] ? __sys_getsockopt+0x11b/0x140
> [ 647.255397] __x64_sys_connect+0x1a/0x20
> [ 647.255398] do_syscall_64+0x51/0x200
> [ 647.255399] entry_SYSCALL_64_after_hwframe+0x44/0xa9
> [ 647.255401] RIP: 0033:0x7f45464fcd50
>
> > Also, shouldn't cgroup_sk_alloc() be changed in a similar way?
> >
>
> I will check cgroup_sk_alloc() too.
>
Yes, cgroup_sk_alloc() should be changed similarly too.
^ permalink raw reply
* [PATCH v6] iio: light: add Dyna-Image AL3010 driver
From: David Heidelberg @ 2020-02-14 22:09 UTC (permalink / raw)
To: Dmitry Osipenko, Daniel Baluta, Jonathan Cameron, Hartmut Knaack,
Lars-Peter Clausen, Peter Meerwald-Stadler, Rob Herring,
Mark Rutland
Cc: David Heidelberg, linux-iio, Michał Mirosław
In-Reply-To: <20200211191201.1049902-5-david@ixit.cz>
Based on:
- 3320A in-kernel driver
- https://www.spinics.net/lists/linux-iio/msg25145.html
- https://lore.kernel.org/patchwork/patch/684179/
I decided to keep it aside of AL3320A due to different approach and much
simpler design of 3010.
Tested on Nexus 7 2012 (grouper/tilapia).
Tested-by: David Heidelberg <david@ixit.cz>
Tested-by: Dmitry Osipenko <digetx@gmail.com>
Tested-by: Michał Mirosław <mirq-linux@rere.qmqm.pl>
Reviewed-by: Dmitry Osipenko <digetx@gmail.com>
Signed-off-by: David Heidelberg <david@ixit.cz>
---
v4:
- SQUASHed: iio: light: al3010 implement suspend support
- switched from _remove to devm_add_action_or_reset
- implement bitfields FIELD_PREP & FIELD_GET, no functionality change
v6:
- add copyright and change driver author field
drivers/iio/light/Kconfig | 10 ++
drivers/iio/light/Makefile | 1 +
drivers/iio/light/al3010.c | 242 +++++++++++++++++++++++++++++++++++++
3 files changed, 253 insertions(+)
create mode 100644 drivers/iio/light/al3010.c
diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig
index 9968f982fbc7..43d9b830279d 100644
--- a/drivers/iio/light/Kconfig
+++ b/drivers/iio/light/Kconfig
@@ -43,6 +43,16 @@ config ADUX1020
To compile this driver as a module, choose M here: the
module will be called adux1020.
+config AL3010
+ tristate "AL3010 ambient light sensor"
+ depends on I2C
+ help
+ Say Y here if you want to build a driver for the Dyna Image AL3010
+ ambient light sensor.
+
+ To compile this driver as a module, choose M here: the
+ module will be called al3010.
+
config AL3320A
tristate "AL3320A ambient light sensor"
depends on I2C
diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile
index c98d1cefb861..88bb93550fcc 100644
--- a/drivers/iio/light/Makefile
+++ b/drivers/iio/light/Makefile
@@ -7,6 +7,7 @@
obj-$(CONFIG_ACPI_ALS) += acpi-als.o
obj-$(CONFIG_ADJD_S311) += adjd_s311.o
obj-$(CONFIG_ADUX1020) += adux1020.o
+obj-$(CONFIG_AL3010) += al3010.o
obj-$(CONFIG_AL3320A) += al3320a.o
obj-$(CONFIG_APDS9300) += apds9300.o
obj-$(CONFIG_APDS9960) += apds9960.o
diff --git a/drivers/iio/light/al3010.c b/drivers/iio/light/al3010.c
new file mode 100644
index 000000000000..84001d04d29d
--- /dev/null
+++ b/drivers/iio/light/al3010.c
@@ -0,0 +1,242 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * AL3010 - Dyna Image Ambient Light Sensor
+ *
+ * Copyright (c) 2014, Intel Corporation.
+ * Copyright (c) 2016, Dyna-Image Corp.
+ * Copyright (c) 2020, David Heidelberg, Michał Mirosław, Dmitry Osipenko
+ *
+ * IIO driver for AL3010 (7-bit I2C slave address 0x1C).
+ *
+ * TODO: interrupt support, thresholds
+ * When the driver will get support for interrupt handling, then interrupt
+ * will need to be disabled before turning sensor OFF in order to avoid
+ * potential races with the interrupt handling.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define AL3010_DRV_NAME "al3010"
+
+#define AL3010_REG_SYSTEM 0x00
+#define AL3010_REG_DATA_LOW 0x0c
+#define AL3010_REG_CONFIG 0x10
+
+#define AL3010_CONFIG_DISABLE 0x00
+#define AL3010_CONFIG_ENABLE 0x01
+
+#define AL3010_GAIN_MASK GENMASK(6,4)
+
+#define AL3010_SCALE_AVAILABLE "1.1872 0.2968 0.0742 0.018"
+
+enum al3xxxx_range {
+ AL3XXX_RANGE_1, /* 77806 lx */
+ AL3XXX_RANGE_2, /* 19542 lx */
+ AL3XXX_RANGE_3, /* 4863 lx */
+ AL3XXX_RANGE_4 /* 1216 lx */
+};
+
+static const int al3010_scales[][2] = {
+ {0, 1187200}, {0, 296800}, {0, 74200}, {0, 18600}
+};
+
+struct al3010_data {
+ struct i2c_client *client;
+};
+
+static const struct iio_chan_spec al3010_channels[] = {
+ {
+ .type = IIO_LIGHT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ }
+};
+
+static IIO_CONST_ATTR(in_illuminance_scale_available, AL3010_SCALE_AVAILABLE);
+
+static struct attribute *al3010_attributes[] = {
+ &iio_const_attr_in_illuminance_scale_available.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group al3010_attribute_group = {
+ .attrs = al3010_attributes,
+};
+
+static int al3010_set_pwr(struct i2c_client *client, bool pwr)
+{
+ u8 val = pwr ? AL3010_CONFIG_ENABLE : AL3010_CONFIG_DISABLE;
+ return i2c_smbus_write_byte_data(client, AL3010_REG_SYSTEM, val);
+}
+
+static void al3010_set_pwr_off(void *_data)
+{
+ struct al3010_data *data = _data;
+
+ al3010_set_pwr(data->client, false);
+}
+
+static int al3010_init(struct al3010_data *data)
+{
+ int ret;
+
+ ret = al3010_set_pwr(data->client, true);
+
+ if (ret < 0)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(data->client, AL3010_REG_CONFIG,
+ FIELD_PREP(AL3010_GAIN_MASK,
+ AL3XXX_RANGE_3));
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int al3010_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val,
+ int *val2, long mask)
+{
+ struct al3010_data *data = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ /*
+ * ALS ADC value is stored in two adjacent registers:
+ * - low byte of output is stored at AL3010_REG_DATA_LOW
+ * - high byte of output is stored at AL3010_REG_DATA_LOW + 1
+ */
+ ret = i2c_smbus_read_word_data(data->client,
+ AL3010_REG_DATA_LOW);
+ if (ret < 0)
+ return ret;
+ *val = ret;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ ret = i2c_smbus_read_byte_data(data->client,
+ AL3010_REG_CONFIG);
+ if (ret < 0)
+ return ret;
+
+ ret = FIELD_GET(AL3010_GAIN_MASK, ret);
+ *val = al3010_scales[ret][0];
+ *val2 = al3010_scales[ret][1];
+
+ return IIO_VAL_INT_PLUS_MICRO;
+ }
+ return -EINVAL;
+}
+
+static int al3010_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int val,
+ int val2, long mask)
+{
+ struct al3010_data *data = iio_priv(indio_dev);
+ int i;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ for (i = 0; i < ARRAY_SIZE(al3010_scales); i++) {
+ if (val != al3010_scales[i][0] ||
+ val2 != al3010_scales[i][1])
+ continue;
+
+ return i2c_smbus_write_byte_data(data->client,
+ AL3010_REG_CONFIG,
+ FIELD_PREP(AL3010_GAIN_MASK, i));
+ }
+ break;
+ }
+ return -EINVAL;
+}
+
+static const struct iio_info al3010_info = {
+ .read_raw = al3010_read_raw,
+ .write_raw = al3010_write_raw,
+ .attrs = &al3010_attribute_group,
+};
+
+static int al3010_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct al3010_data *data;
+ struct iio_dev *indio_dev;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ data = iio_priv(indio_dev);
+ i2c_set_clientdata(client, indio_dev);
+ data->client = client;
+
+ indio_dev->dev.parent = &client->dev;
+ indio_dev->info = &al3010_info;
+ indio_dev->name = AL3010_DRV_NAME;
+ indio_dev->channels = al3010_channels;
+ indio_dev->num_channels = ARRAY_SIZE(al3010_channels);
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = al3010_init(data);
+ if (ret < 0) {
+ dev_err(&client->dev, "al3010 chip init failed\n");
+ return ret;
+ }
+
+ ret = devm_add_action_or_reset(&client->dev,
+ al3010_set_pwr_off,
+ data);
+ if (ret < 0)
+ return ret;
+
+ return devm_iio_device_register(&client->dev, indio_dev);
+}
+
+static int __maybe_unused al3010_suspend(struct device *dev)
+{
+ return al3010_set_pwr(to_i2c_client(dev), false);
+}
+
+static int __maybe_unused al3010_resume(struct device *dev)
+{
+ return al3010_set_pwr(to_i2c_client(dev), true);
+}
+
+SIMPLE_DEV_PM_OPS(al3010_pm_ops, al3010_suspend, al3010_resume);
+
+static const struct i2c_device_id al3010_id[] = {
+ {"al3010", },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, al3010_id);
+
+static const struct of_device_id al3010_of_match[] = {
+ { .compatible = "dynaimage,al3010", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, al3010_of_match);
+
+static struct i2c_driver al3010_driver = {
+ .driver = {
+ .name = AL3010_DRV_NAME,
+ .of_match_table = al3010_of_match,
+ .pm = &al3010_pm_ops,
+ },
+ .probe = al3010_probe,
+ .id_table = al3010_id,
+};
+module_i2c_driver(al3010_driver);
+
+MODULE_AUTHOR("Daniel Baluta <daniel.baluta@nxp.com>");
+MODULE_AUTHOR("David Heidelberg <david@ixit.cz>");
+MODULE_DESCRIPTION("AL3010 Ambient Light Sensor driver");
+MODULE_LICENSE("GPL v2");
--
2.25.0
^ permalink raw reply related
* QEMU Sockets Networking Backend Multicast Networking Fix
From: Faisal Al-Humaimidi @ 2020-02-14 18:51 UTC (permalink / raw)
To: qemu-devel
[-- Attachment #1.1: Type: text/plain, Size: 2272 bytes --]
Hello QEMU developers,
I have noticed a bug in the `mcast` option of the `socket` networking
backend, where I simply cannot join a multicast group (tested in Windows 10
with QEMU 4.2.0 release). I have found a fix to the problem. The problem
was mainly due to the fact that QEMU was binding to the multicast address,
and not the local address or the default INADDR_ANY (0.0.0.0) if no local
address is used.
Here's the patch text (as well as attached with this email), that outlines
my fix:
```
diff -uarN qemu-4.2.0.original/net/socket.c qemu-4.2.0.modified/net/socket.c
--- qemu-4.2.0.original/net/socket.c 2019-12-12 10:20:48.000000000 -0800
+++ qemu-4.2.0.modified/net/socket.c 2020-02-14 10:30:16.395973453 -0800
@@ -253,6 +253,15 @@
goto fail;
}
+ /* Preserve the multicast address, and bind to a non-multicast group
(e.g. a
+ * local address).
+ */
+ struct in_addr group_addr = mcastaddr->sin_addr;
+ if (localaddr) {
+ mcastaddr->sin_addr = *localaddr;
+ } else {
+ mcastaddr->sin_addr.s_addr = htonl(INADDR_ANY);
+ }
ret = bind(fd, (struct sockaddr *)mcastaddr, sizeof(*mcastaddr));
if (ret < 0) {
error_setg_errno(errp, errno, "can't bind ip=%s to socket",
@@ -260,7 +269,10 @@
goto fail;
}
- /* Add host to multicast group */
+ /* Restore the multicast address. */
+ mcastaddr->sin_addr = group_addr;
+
+ /* Add host to multicast group. */
imr.imr_multiaddr = mcastaddr->sin_addr;
if (localaddr) {
imr.imr_interface = *localaddr;
@@ -277,7 +289,7 @@
goto fail;
}
- /* Force mcast msgs to loopback (eg. several QEMUs in same host */
+ /* Force mcast msgs to loopback (eg. several QEMUs in same host). */
loop = 1;
ret = qemu_setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
&loop, sizeof(loop));
@@ -287,7 +299,7 @@
goto fail;
}
- /* If a bind address is given, only send packets from that address */
+ /* If a bind address is given, only send packets from that address. */
if (localaddr != NULL) {
ret = qemu_setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
localaddr, sizeof(*localaddr));
```
Regards,
Faisal Al-Humaimidi
[-- Attachment #1.2: Type: text/html, Size: 2754 bytes --]
[-- Attachment #2: qemu-4.2.0-fix_socket_mcast.patch --]
[-- Type: application/octet-stream, Size: 1745 bytes --]
diff -uarN qemu-4.2.0.original/net/socket.c qemu-4.2.0.modified/net/socket.c
--- qemu-4.2.0.original/net/socket.c 2019-12-12 10:20:48.000000000 -0800
+++ qemu-4.2.0.modified/net/socket.c 2020-02-14 10:30:16.395973453 -0800
@@ -253,6 +253,15 @@
goto fail;
}
+ /* Preserve the multicast address, and bind to a non-multicast group (e.g. a
+ * local address).
+ */
+ struct in_addr group_addr = mcastaddr->sin_addr;
+ if (localaddr) {
+ mcastaddr->sin_addr = *localaddr;
+ } else {
+ mcastaddr->sin_addr.s_addr = htonl(INADDR_ANY);
+ }
ret = bind(fd, (struct sockaddr *)mcastaddr, sizeof(*mcastaddr));
if (ret < 0) {
error_setg_errno(errp, errno, "can't bind ip=%s to socket",
@@ -260,7 +269,10 @@
goto fail;
}
- /* Add host to multicast group */
+ /* Restore the multicast address. */
+ mcastaddr->sin_addr = group_addr;
+
+ /* Add host to multicast group. */
imr.imr_multiaddr = mcastaddr->sin_addr;
if (localaddr) {
imr.imr_interface = *localaddr;
@@ -277,7 +289,7 @@
goto fail;
}
- /* Force mcast msgs to loopback (eg. several QEMUs in same host */
+ /* Force mcast msgs to loopback (eg. several QEMUs in same host). */
loop = 1;
ret = qemu_setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
&loop, sizeof(loop));
@@ -287,7 +299,7 @@
goto fail;
}
- /* If a bind address is given, only send packets from that address */
+ /* If a bind address is given, only send packets from that address. */
if (localaddr != NULL) {
ret = qemu_setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
localaddr, sizeof(*localaddr));
^ permalink raw reply
* Re: [GIT PULL] io_uring fixes for 5.6-rc2
From: Linus Torvalds @ 2020-02-14 22:07 UTC (permalink / raw)
To: Jens Axboe; +Cc: io-uring, linux-kernel@vger.kernel.org
In-Reply-To: <d72d51a9-488d-c75b-4daf-bb74960c7531@kernel.dk>
On Fri, Feb 14, 2020 at 8:45 AM Jens Axboe <axboe@kernel.dk> wrote:
>
> Here's a set of fixes for io_uring that should go into this release.
Whaa?
for_each_node(node) {
+ if (!node_online(node))
+ continue;
that's just silly.
We have 'for_each_online_node()' for this.
There's something like four patterns of that pointless thing.
And in io_wq_create(), do you really want to allocate that wqe for
nodes that aren't online? Right now you _allocate_ the node data for
them (using a non-node-specific allocation), but then you won't
actually create the thread for them io_wq_manager().
Plus if the node online status changes, it looks like you'll mess up
_anyway_, in that io_wq_manager() will first create the workers on
one set of nodes, but then perhaps set the state flags for a
completely different set of nodes if some onlining/offlining has
happened.
I've pulled this, but Jens, you need to be more careful. This all
looks like completely random state that nobody spent any time thinking
about.
Seriously, this "io_uring FIXES ONLY" needs to be stricter than what
you seem to be doing here. This "fix" is opening up a lot of new
possibilities for inconsistencies in the data structures.
Linus
^ permalink raw reply
* Re: [PATCH v6 2/6] lib: introduce generic min-heap
From: Randy Dunlap @ 2020-02-14 22:06 UTC (permalink / raw)
To: Ian Rogers, Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
Andrew Morton, Masahiro Yamada, Shuah Khan, Krzysztof Kozlowski,
Kees Cook, Paul E. McKenney, Masami Hiramatsu, Marco Elver,
Kent Overstreet, Andy Shevchenko, Ard Biesheuvel, Gary Hook,
Kan Liang, linux-kernel
Cc: Stephane Eranian, Andi Kleen
In-Reply-To: <20200214075133.181299-3-irogers@google.com>
Hi,
On 2/13/20 11:51 PM, Ian Rogers wrote:
> diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
> index 1458505192cd..e61e7fee9364 100644
> --- a/lib/Kconfig.debug
> +++ b/lib/Kconfig.debug
> @@ -1771,6 +1771,16 @@ config TEST_LIST_SORT
>
> If unsure, say N.
>
> +config TEST_MIN_HEAP
> + tristate "Min heap test"
> + depends on DEBUG_KERNEL || m
I realize that this is (likely) copied from other config entries,
but the "depends on DEBUG_KERNEL || m" doesn't make any sense to me.
Seems like it should be "depends on DEBUG_KERNEL && m"...
Why should it be "||"??
> + help
> + Enable this to turn on min heap function tests. This test is
> + executed only once during system boot (so affects only boot time),
> + or at module load time.
> +
> + If unsure, say N.
> +
> config TEST_SORT
> tristate "Array-based sort test"
> depends on DEBUG_KERNEL || m
thanks.
--
~Randy
^ permalink raw reply
* Re: [PATCH v2 1/5] common/overlay,rc,config: introduce OVL_FSTYP variable and aufs
From: Amir Goldstein @ 2020-02-14 22:06 UTC (permalink / raw)
To: Mauricio Faria de Oliveira; +Cc: fstests, overlayfs
In-Reply-To: <20200214151848.8328-2-mfo@canonical.com>
On Fri, Feb 14, 2020 at 5:18 PM Mauricio Faria de Oliveira
<mfo@canonical.com> wrote:
>
> Recently I was looking for an aufs test suite, and reached out to
> Okajima, but 'There is no public test suite specific to aufs.' [1],
> and it looks like 'xfstests/tests/generic' should be enough [1, 2].
>
> Thus, building on top existing xfstests support for overlay just
> introduce the OVL_FSTYP variable, and the default value "overlay"
> can be changed to "aufs" (uses overlay's upperdir as a rw-branch
> and lowerdir as a ro-branch; workdir is not used.)
>
> This is indeed a workaround^W simple change that does the job vs.
> creating a new FSTYP "aufs" and mechanically changing the number
> of places that check for "overlay" to just handle "aufs" as well.
> (so the effort is still small as aufs has no specific tests now.)
>
> This also allows testing fuse-overlayfs with the next patches.
>
> The changes are minimal -- just translate overlay mount options
> and use $OVL_FSTYP as filesystem type for checking/mount/umount;
> then report it in log headers and document it in README.overlay.
>
> Currently, running './check -overlay' tests (excluding a few [3]
> which either hang or keep looping) the numbers for aufs on loop
> devices on v5.4-based Ubuntu kernel are:
>
> - Ran: 645 tests
> - Not run: 483 tests
> - Failures: 22 tests
>
> So, hopefully this may help with a starting point for an public
> test suite for aufs.
>
> Thanks to Amir Goldstein for feedback/improvements and pointers
> to support fuse-overlayfs as well [v2].
>
> [1] https://sourceforge.net/p/aufs/mailman/message/36918721/
> [2] https://sourceforge.net/p/aufs/mailman/message/36918932/
> [3] Steps:
>
> $ export OVL_FSTYP=aufs
> $ export FSTYP=ext4
> $ export TEST_DEV=/dev/loop0
> $ export TEST_DIR=/mnt/test
> $ export SCRATCH_DEV=/dev/loop1
> $ export SCRATCH_MNT=/mnt/scratch
>
> $ sudo mkfs.$FSTYP -F $TEST_DEV
> $ sudo mkfs.$FSTYP -F $SCRATCH_DEV
> $ sudo mkdir $TEST_DIR $SCRATCH_MNT
>
> $ cat <<EOF >/tmp/exclude-tests
> generic/013
> generic/070
> generic/075
> generic/112
> generic/127
> generic/461
> generic/476
> generic/522
> generic/530
> overlay/019
> EOF
>
> $ sudo -E ./check -overlay -E /tmp/exclude-tests
>
> Signed-off-by: Mauricio Faria de Oliveira <mfo@canonical.com>
> ---
> README.overlay | 4 ++++
> common/config | 2 ++
> common/overlay | 11 ++++++++---
> common/rc | 6 ++++++
> 4 files changed, 20 insertions(+), 3 deletions(-)
>
> diff --git a/README.overlay b/README.overlay
> index 30b5ddb2d1c3..08a39b8830c9 100644
> --- a/README.overlay
> +++ b/README.overlay
> @@ -50,3 +50,7 @@ In the example above, MOUNT_OPTIONS will be used to mount the base scratch fs,
> TEST_FS_MOUNT_OPTS will be used to mount the base test fs,
> OVERLAY_MOUNT_OPTIONS will be used to mount both test and scratch overlay and
> OVERLAY_FSCK_OPTIONS will be used to check both test and scratch overlay.
> +
> +To test other filesystem types (experimental) configure the OVL_FSTYP variable:
> +
> + OVL_FSTYP=aufs
> diff --git a/common/config b/common/config
> index 9a9c77602b54..d92a78003295 100644
> --- a/common/config
> +++ b/common/config
> @@ -71,6 +71,8 @@ export OVL_LOWER="ovl-lower"
> export OVL_WORK="ovl-work"
> # overlay mount point parent must be the base fs root
> export OVL_MNT="ovl-mnt"
> +# overlay mount filesystem type (for testing other fs)
> +export OVL_FSTYP=${OVL_FSTYP:-overlay}
>
> # From e2fsprogs/e2fsck/e2fsck.h:
> # Exit code used by fsck-type programs
> diff --git a/common/overlay b/common/overlay
> index 65c639e9c6d8..a1076926c23f 100644
> --- a/common/overlay
> +++ b/common/overlay
> @@ -18,10 +18,15 @@ _overlay_mount_dirs()
> local lowerdir=$1
> local upperdir=$2
> local workdir=$3
> + local options
> shift 3
>
> - $MOUNT_PROG -t overlay -o lowerdir=$lowerdir -o upperdir=$upperdir \
> - -o workdir=$workdir `_common_dev_mount_options $*`
> + options="-o lowerdir=$lowerdir -o upperdir=$upperdir -o workdir=$workdir"
> + if [ "$OVL_FSTYP" = "aufs" ]; then
> + options="-o br=$upperdir=rw -o br=$lowerdir=ro"
> + fi
> +
> + $MOUNT_PROG -t $OVL_FSTYP $options `_common_dev_mount_options $*`
> }
>
> # Mount with same options/mnt/dev of scratch mount, but optionally
> @@ -302,7 +307,7 @@ _overlay_check_fs()
> _overlay_base_mount $*
> else
> # Check and umount overlay for dir check
> - ovl_mounted=`_is_dir_mountpoint $ovl_mnt`
> + ovl_mounted=`_is_dir_mountpoint $ovl_mnt $OVL_FSTYP`
> [ -z "$ovl_mounted" ] || $UMOUNT_PROG $ovl_mnt
> fi
>
> diff --git a/common/rc b/common/rc
> index b4a77a2187f4..1feae1a94f9e 100644
> --- a/common/rc
> +++ b/common/rc
> @@ -1471,6 +1471,10 @@ _check_mounted_on()
> return 2 # 2 = mounted on wrong mnt
> fi
>
> + if [ -n "$type" -a "$type" = "overlay" ]; then
> + type="$OVL_FSTYP"
> + fi
> +
Hmm. I found 2 other instances of _fs_type in common/rc.
I think it would be safer to let _fs_type return "overlay" in
case the mounted fs is of type $OVL_FSTYP.
This will be simple to do by extending the sed expression -
no need for special cases and conditions.
Other than that, patch looks good.
Thanks,
Amir.
> if [ -n "$type" -a "`_fs_type $dev`" != "$type" ]; then
> echo "$devname=$dev is mounted but not a type $type filesystem"
> # raw $DF_PROG cannot handle NFS/CIFS/overlay correctly
> @@ -2841,6 +2845,8 @@ _full_fstyp_details()
> FSTYP="$FSTYP (non-debug)"
> fi
> fi
> + elif [ $FSTYP = "overlay" -a "$OVL_FSTYP" != "overlay" ]; then
> + FSTYP="$FSTYP ($OVL_FSTYP)"
> fi
> echo $FSTYP
> }
> --
> 2.20.1
>
^ permalink raw reply
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.