* [PATCH v15 9/9] nvmet-configfs: Introduce passthru configfs interface
From: Logan Gunthorpe @ 2020-07-16 20:33 UTC (permalink / raw)
To: linux-kernel, linux-nvme
Cc: Christoph Hellwig, Sagi Grimberg, Keith Busch, Jens Axboe,
Chaitanya Kulkarni, Max Gurtovoy, Stephen Bates, Logan Gunthorpe
In-Reply-To: <20200716203319.16022-1-logang@deltatee.com>
When CONFIG_NVME_TARGET_PASSTHRU as 'passthru' directory will
be added to each subsystem. The directory is similar to a namespace
and has two attributes: device_path and enable. The user must set the
path to the nvme controller's char device and write '1' to enable the
subsystem to use passthru.
Any given subsystem is prevented from enabling both a regular namespace
and the passthru device. If one is enabled, enabling the other will
produce an error.
Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
---
drivers/nvme/target/configfs.c | 99 ++++++++++++++++++++++++++++++++++
drivers/nvme/target/nvmet.h | 1 +
2 files changed, 100 insertions(+)
diff --git a/drivers/nvme/target/configfs.c b/drivers/nvme/target/configfs.c
index 61c258dea88a..74b2b61c773b 100644
--- a/drivers/nvme/target/configfs.c
+++ b/drivers/nvme/target/configfs.c
@@ -666,6 +666,103 @@ static const struct config_item_type nvmet_namespaces_type = {
.ct_owner = THIS_MODULE,
};
+#ifdef CONFIG_NVME_TARGET_PASSTHRU
+
+static ssize_t nvmet_passthru_device_path_show(struct config_item *item,
+ char *page)
+{
+ struct nvmet_subsys *subsys = to_subsys(item->ci_parent);
+
+ return snprintf(page, PAGE_SIZE, "%s\n", subsys->passthru_ctrl_path);
+}
+
+static ssize_t nvmet_passthru_device_path_store(struct config_item *item,
+ const char *page, size_t count)
+{
+ struct nvmet_subsys *subsys = to_subsys(item->ci_parent);
+ size_t len;
+ int ret;
+
+ mutex_lock(&subsys->lock);
+
+ ret = -EBUSY;
+ if (subsys->passthru_ctrl)
+ goto out_unlock;
+
+ ret = -EINVAL;
+ len = strcspn(page, "\n");
+ if (!len)
+ goto out_unlock;
+
+ kfree(subsys->passthru_ctrl_path);
+ ret = -ENOMEM;
+ subsys->passthru_ctrl_path = kstrndup(page, len, GFP_KERNEL);
+ if (!subsys->passthru_ctrl_path)
+ goto out_unlock;
+
+ mutex_unlock(&subsys->lock);
+
+ return count;
+out_unlock:
+ mutex_unlock(&subsys->lock);
+ return ret;
+}
+CONFIGFS_ATTR(nvmet_passthru_, device_path);
+
+static ssize_t nvmet_passthru_enable_show(struct config_item *item,
+ char *page)
+{
+ struct nvmet_subsys *subsys = to_subsys(item->ci_parent);
+
+ return sprintf(page, "%d\n", subsys->passthru_ctrl ? 1 : 0);
+}
+
+static ssize_t nvmet_passthru_enable_store(struct config_item *item,
+ const char *page, size_t count)
+{
+ struct nvmet_subsys *subsys = to_subsys(item->ci_parent);
+ bool enable;
+ int ret = 0;
+
+ if (strtobool(page, &enable))
+ return -EINVAL;
+
+ if (enable)
+ ret = nvmet_passthru_ctrl_enable(subsys);
+ else
+ nvmet_passthru_ctrl_disable(subsys);
+
+ return ret ? ret : count;
+}
+CONFIGFS_ATTR(nvmet_passthru_, enable);
+
+static struct configfs_attribute *nvmet_passthru_attrs[] = {
+ &nvmet_passthru_attr_device_path,
+ &nvmet_passthru_attr_enable,
+ NULL,
+};
+
+static const struct config_item_type nvmet_passthru_type = {
+ .ct_attrs = nvmet_passthru_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
+static void nvmet_add_passthru_group(struct nvmet_subsys *subsys)
+{
+ config_group_init_type_name(&subsys->passthru_group,
+ "passthru", &nvmet_passthru_type);
+ configfs_add_default_group(&subsys->passthru_group,
+ &subsys->group);
+}
+
+#else /* CONFIG_NVME_TARGET_PASSTHRU */
+
+static void nvmet_add_passthru_group(struct nvmet_subsys *subsys)
+{
+}
+
+#endif /* CONFIG_NVME_TARGET_PASSTHRU */
+
static int nvmet_port_subsys_allow_link(struct config_item *parent,
struct config_item *target)
{
@@ -1125,6 +1222,8 @@ static struct config_group *nvmet_subsys_make(struct config_group *group,
configfs_add_default_group(&subsys->allowed_hosts_group,
&subsys->group);
+ nvmet_add_passthru_group(subsys);
+
return &subsys->group;
}
diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
index d8689744e0f7..deb3c52aae6d 100644
--- a/drivers/nvme/target/nvmet.h
+++ b/drivers/nvme/target/nvmet.h
@@ -249,6 +249,7 @@ struct nvmet_subsys {
#ifdef CONFIG_NVME_TARGET_PASSTHRU
struct nvme_ctrl *passthru_ctrl;
char *passthru_ctrl_path;
+ struct config_group passthru_group;
#endif /* CONFIG_NVME_TARGET_PASSTHRU */
};
--
2.20.1
^ permalink raw reply related
* [PATCH v15 8/9] nvmet-passthru: Add enable/disable helpers
From: Logan Gunthorpe @ 2020-07-16 20:33 UTC (permalink / raw)
To: linux-kernel, linux-nvme
Cc: Christoph Hellwig, Sagi Grimberg, Keith Busch, Jens Axboe,
Chaitanya Kulkarni, Max Gurtovoy, Stephen Bates, Logan Gunthorpe,
Chaitanya Kulkarni
In-Reply-To: <20200716203319.16022-1-logang@deltatee.com>
This patch adds helper functions which are used in the NVMeOF configfs
when the user is configuring the passthru subsystem. Here we ensure
that only one subsys is assigned to each nvme_ctrl by using an xarray
on the cntlid.
The subsystem's version number is overridden by the passed through
controller's version. However, if that version is less than 1.2.1,
then we bump the advertised version to that and print a warning
in dmesg.
Based-on-a-patch-by: Chaitanya Kulkarni <chaitanya.kulkarni@wdc.com>
Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
---
drivers/nvme/target/configfs.c | 4 ++
drivers/nvme/target/core.c | 10 +++-
drivers/nvme/target/nvmet.h | 12 +++++
drivers/nvme/target/passthru.c | 86 ++++++++++++++++++++++++++++++++++
4 files changed, 111 insertions(+), 1 deletion(-)
diff --git a/drivers/nvme/target/configfs.c b/drivers/nvme/target/configfs.c
index cdec47de89ed..61c258dea88a 100644
--- a/drivers/nvme/target/configfs.c
+++ b/drivers/nvme/target/configfs.c
@@ -879,6 +879,10 @@ static ssize_t nvmet_subsys_attr_version_store(struct config_item *item,
int major, minor, tertiary = 0;
int ret;
+ /* passthru subsystems use the underlying controller's version */
+ if (nvmet_passthru_ctrl(subsys))
+ return -EINVAL;
+
ret = sscanf(page, "%d.%d.%d\n", &major, &minor, &tertiary);
if (ret != 2 && ret != 3)
return -EINVAL;
diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c
index 86fc913f481a..c0c7a0d75a01 100644
--- a/drivers/nvme/target/core.c
+++ b/drivers/nvme/target/core.c
@@ -558,6 +558,12 @@ int nvmet_ns_enable(struct nvmet_ns *ns)
mutex_lock(&subsys->lock);
ret = 0;
+
+ if (nvmet_passthru_ctrl(subsys)) {
+ pr_info("cannot enable both passthru and regular namespaces for a single subsystem");
+ goto out_unlock;
+ }
+
if (ns->enabled)
goto out_unlock;
@@ -1498,7 +1504,7 @@ struct nvmet_subsys *nvmet_subsys_alloc(const char *subsysnqn,
if (!subsys)
return ERR_PTR(-ENOMEM);
- subsys->ver = NVME_VS(1, 3, 0); /* NVMe 1.3.0 */
+ subsys->ver = NVMET_DEFAULT_VS;
/* generate a random serial number as our controllers are ephemeral: */
get_random_bytes(&subsys->serial, sizeof(subsys->serial));
@@ -1540,6 +1546,8 @@ static void nvmet_subsys_free(struct kref *ref)
WARN_ON_ONCE(!list_empty(&subsys->namespaces));
+ nvmet_passthru_subsys_free(subsys);
+
kfree(subsys->subsysnqn);
kfree_rcu(subsys->model, rcuhead);
kfree(subsys);
diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
index 03a92dba24c3..d8689744e0f7 100644
--- a/drivers/nvme/target/nvmet.h
+++ b/drivers/nvme/target/nvmet.h
@@ -21,6 +21,8 @@
#include <linux/radix-tree.h>
#include <linux/t10-pi.h>
+#define NVMET_DEFAULT_VS NVME_VS(1, 3, 0)
+
#define NVMET_ASYNC_EVENTS 4
#define NVMET_ERROR_LOG_SLOTS 128
#define NVMET_NO_ERROR_LOC ((u16)-1)
@@ -246,6 +248,7 @@ struct nvmet_subsys {
#ifdef CONFIG_NVME_TARGET_PASSTHRU
struct nvme_ctrl *passthru_ctrl;
+ char *passthru_ctrl_path;
#endif /* CONFIG_NVME_TARGET_PASSTHRU */
};
@@ -545,6 +548,9 @@ static inline u32 nvmet_dsm_len(struct nvmet_req *req)
}
#ifdef CONFIG_NVME_TARGET_PASSTHRU
+void nvmet_passthru_subsys_free(struct nvmet_subsys *subsys);
+int nvmet_passthru_ctrl_enable(struct nvmet_subsys *subsys);
+void nvmet_passthru_ctrl_disable(struct nvmet_subsys *subsys);
u16 nvmet_parse_passthru_admin_cmd(struct nvmet_req *req);
u16 nvmet_parse_passthru_io_cmd(struct nvmet_req *req);
static inline struct nvme_ctrl *nvmet_passthru_ctrl(struct nvmet_subsys *subsys)
@@ -552,6 +558,12 @@ static inline struct nvme_ctrl *nvmet_passthru_ctrl(struct nvmet_subsys *subsys)
return subsys->passthru_ctrl;
}
#else /* CONFIG_NVME_TARGET_PASSTHRU */
+static inline void nvmet_passthru_subsys_free(struct nvmet_subsys *subsys)
+{
+}
+static inline void nvmet_passthru_ctrl_disable(struct nvmet_subsys *subsys)
+{
+}
static inline u16 nvmet_parse_passthru_admin_cmd(struct nvmet_req *req)
{
return 0;
diff --git a/drivers/nvme/target/passthru.c b/drivers/nvme/target/passthru.c
index 96799febdbc3..d7f80e82bd3e 100644
--- a/drivers/nvme/target/passthru.c
+++ b/drivers/nvme/target/passthru.c
@@ -11,6 +11,11 @@
#include "../host/nvme.h"
#include "nvmet.h"
+/*
+ * xarray to maintain one passthru subsystem per nvme controller.
+ */
+static DEFINE_XARRAY(passthru_subsystems);
+
static void nvmet_passthru_execute_cmd_work(struct work_struct *w)
{
struct nvmet_req *req = container_of(w, struct nvmet_req, p.work);
@@ -455,3 +460,84 @@ u16 nvmet_parse_passthru_admin_cmd(struct nvmet_req *req)
return NVME_SC_INVALID_OPCODE | NVME_SC_DNR;
}
}
+
+int nvmet_passthru_ctrl_enable(struct nvmet_subsys *subsys)
+{
+ struct nvme_ctrl *ctrl;
+ int ret = -EINVAL;
+ void *old;
+
+ mutex_lock(&subsys->lock);
+ if (!subsys->passthru_ctrl_path)
+ goto out_unlock;
+ if (subsys->passthru_ctrl)
+ goto out_unlock;
+
+ if (subsys->nr_namespaces) {
+ pr_info("cannot enable both passthru and regular namespaces for a single subsystem");
+ goto out_unlock;
+ }
+
+ ctrl = nvme_ctrl_get_by_path(subsys->passthru_ctrl_path);
+ if (IS_ERR(ctrl)) {
+ ret = PTR_ERR(ctrl);
+ pr_err("failed to open nvme controller %s\n",
+ subsys->passthru_ctrl_path);
+
+ goto out_unlock;
+ }
+
+ old = xa_cmpxchg(&passthru_subsystems, ctrl->cntlid, NULL,
+ subsys, GFP_KERNEL);
+ if (xa_is_err(old)) {
+ ret = xa_err(old);
+ goto out_put_ctrl;
+ }
+
+ if (old)
+ goto out_put_ctrl;
+
+ subsys->passthru_ctrl = ctrl;
+ subsys->ver = ctrl->vs;
+
+ if (subsys->ver < NVME_VS(1, 2, 1)) {
+ pr_warn("nvme controller version is too old: %llu.%llu.%llu, advertising 1.2.1\n",
+ NVME_MAJOR(subsys->ver), NVME_MINOR(subsys->ver),
+ NVME_TERTIARY(subsys->ver));
+ subsys->ver = NVME_VS(1, 2, 1);
+ }
+
+ mutex_unlock(&subsys->lock);
+ return 0;
+
+out_put_ctrl:
+ nvme_put_ctrl(ctrl);
+out_unlock:
+ mutex_unlock(&subsys->lock);
+ return ret;
+}
+
+static void __nvmet_passthru_ctrl_disable(struct nvmet_subsys *subsys)
+{
+ if (subsys->passthru_ctrl) {
+ xa_erase(&passthru_subsystems, subsys->passthru_ctrl->cntlid);
+ nvme_put_ctrl(subsys->passthru_ctrl);
+ }
+ subsys->passthru_ctrl = NULL;
+ subsys->ver = NVMET_DEFAULT_VS;
+}
+
+void nvmet_passthru_ctrl_disable(struct nvmet_subsys *subsys)
+{
+ mutex_lock(&subsys->lock);
+ __nvmet_passthru_ctrl_disable(subsys);
+ mutex_unlock(&subsys->lock);
+}
+
+void nvmet_passthru_subsys_free(struct nvmet_subsys *subsys)
+{
+ mutex_lock(&subsys->lock);
+ __nvmet_passthru_ctrl_disable(subsys);
+ mutex_unlock(&subsys->lock);
+ kfree(subsys->passthru_ctrl_path);
+}
--
2.20.1
^ permalink raw reply related
* [PATCH v15 5/9] nvme-core: Introduce nvme_ctrl_get_by_path()
From: Logan Gunthorpe @ 2020-07-16 20:33 UTC (permalink / raw)
To: linux-kernel, linux-nvme
Cc: Christoph Hellwig, Sagi Grimberg, Keith Busch, Jens Axboe,
Chaitanya Kulkarni, Max Gurtovoy, Stephen Bates, Logan Gunthorpe
In-Reply-To: <20200716203319.16022-1-logang@deltatee.com>
nvme_ctrl_get_by_path() is analagous to blkdev_get_by_path() except it
gets a struct nvme_ctrl from the path to its char dev (/dev/nvme0).
It makes use of filp_open() to open the file and uses the private
data to obtain a pointer to the struct nvme_ctrl. If the fops of the
file do not match, -EINVAL is returned.
The purpose of this function is to support NVMe-OF target passthru.
Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
Reviewed-by: Max Gurtovoy <maxg@mellanox.com>
Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
---
drivers/nvme/host/core.c | 31 +++++++++++++++++++++++++++++++
drivers/nvme/host/nvme.h | 6 ++++++
2 files changed, 37 insertions(+)
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 817ab76d2838..6e7d5cb43a06 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -4572,6 +4572,37 @@ void nvme_sync_queues(struct nvme_ctrl *ctrl)
}
EXPORT_SYMBOL_GPL(nvme_sync_queues);
+#ifdef CONFIG_NVME_TARGET_PASSTHRU
+/*
+ * The exports that follow within this ifdef are only for
+ * use by the nvmet-passthru and should not be used for
+ * other things.
+ */
+
+struct nvme_ctrl *nvme_ctrl_get_by_path(const char *path)
+{
+ struct nvme_ctrl *ctrl;
+ struct file *f;
+
+ f = filp_open(path, O_RDWR, 0);
+ if (IS_ERR(f))
+ return ERR_CAST(f);
+
+ if (f->f_op != &nvme_dev_fops) {
+ ctrl = ERR_PTR(-EINVAL);
+ goto out_close;
+ }
+
+ ctrl = f->private_data;
+ nvme_get_ctrl(ctrl);
+
+out_close:
+ filp_close(f, NULL);
+ return ctrl;
+}
+EXPORT_SYMBOL_GPL(nvme_ctrl_get_by_path);
+#endif /* CONFIG_NVME_TARGET_PASSTHRU */
+
/*
* Check we didn't inadvertently grow the command structure sizes:
*/
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index 13ca90bcd352..485492a98ef5 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -763,4 +763,10 @@ void nvme_hwmon_init(struct nvme_ctrl *ctrl);
static inline void nvme_hwmon_init(struct nvme_ctrl *ctrl) { }
#endif
+/*
+ * These functions are only for use by nvmet-passthru and are only exported
+ * if CONFIG_NVME_TARGET_PASSTHRU is set.
+ */
+struct nvme_ctrl *nvme_ctrl_get_by_path(const char *path);
+
#endif /* _NVME_H */
--
2.20.1
^ permalink raw reply related
* [PATCH][next] pinctrl: lpc18xx: Use fallthrough pseudo-keyword
From: Gustavo A. R. Silva @ 2020-07-16 21:21 UTC (permalink / raw)
To: Linus Walleij, Vladimir Zapolskiy
Cc: linux-gpio, linux-kernel, linux-arm-kernel, Gustavo A. R. Silva
Replace the existing /* fall through */ comments and its variants with
the new pseudo-keyword macro fallthrough[1].
[1] https://www.kernel.org/doc/html/latest/process/deprecated.html?highlight=fallthrough#implicit-switch-case-fall-through
Signed-off-by: Gustavo A. R. Silva <gustavoars@kernel.org>
---
drivers/pinctrl/pinctrl-lpc18xx.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/pinctrl/pinctrl-lpc18xx.c b/drivers/pinctrl/pinctrl-lpc18xx.c
index e4677546aec4..7b2f885e68bd 100644
--- a/drivers/pinctrl/pinctrl-lpc18xx.c
+++ b/drivers/pinctrl/pinctrl-lpc18xx.c
@@ -838,11 +838,11 @@ static int lpc18xx_pconf_get_pin(struct pinctrl_dev *pctldev, unsigned param,
*arg = (reg & LPC18XX_SCU_PIN_EHD_MASK) >> LPC18XX_SCU_PIN_EHD_POS;
switch (*arg) {
case 3: *arg += 5;
- /* fall through */
+ fallthrough;
case 2: *arg += 5;
- /* fall through */
+ fallthrough;
case 1: *arg += 3;
- /* fall through */
+ fallthrough;
case 0: *arg += 4;
}
break;
@@ -1057,11 +1057,11 @@ static int lpc18xx_pconf_set_pin(struct pinctrl_dev *pctldev, unsigned param,
switch (param_val) {
case 20: param_val -= 5;
- /* fall through */
+ fallthrough;
case 14: param_val -= 5;
- /* fall through */
+ fallthrough;
case 8: param_val -= 3;
- /* fall through */
+ fallthrough;
case 4: param_val -= 4;
break;
default:
--
2.27.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* Re: [PATCH 08/35] libmultipath: create bitfield abstraction
From: Benjamin Marzinski @ 2020-07-16 21:17 UTC (permalink / raw)
To: mwilck; +Cc: dm-devel
In-Reply-To: <20200709101620.6786-9-mwilck@suse.com>
On Thu, Jul 09, 2020 at 12:15:53PM +0200, mwilck@suse.com wrote:
> From: Martin Wilck <mwilck@suse.com>
>
> In e32d521d ("libmultipath: coalesce_paths: fix size mismatch handling"),
> we introduced simple bitmap handling functions. We can do better. This
> patch introduces a bitfield type with overflow detection and a
> find_first_set() method.
>
> Use this in coalesce_paths(), and adapt the unit tests. Also, add
> unit tests for "odd" bitfield sizes; so far we tested only multiples
> of 64.
>
> Signed-off-by: Martin Wilck <mwilck@suse.com>
> ---
> libmultipath/configure.c | 9 +-
> libmultipath/util.c | 35 ++++++
> libmultipath/util.h | 57 ++++++++-
> tests/util.c | 263 +++++++++++++++++++++++++++++++++++----
> 4 files changed, 327 insertions(+), 37 deletions(-)
>
> diff --git a/libmultipath/configure.c b/libmultipath/configure.c
> index 96c7961..fe590f4 100644
> --- a/libmultipath/configure.c
> +++ b/libmultipath/configure.c
> @@ -1092,7 +1092,7 @@ int coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid,
> vector pathvec = vecs->pathvec;
> struct config *conf;
> int allow_queueing;
> - uint64_t *size_mismatch_seen;
> + struct bitfield *size_mismatch_seen;
>
> /* ignore refwwid if it's empty */
> if (refwwid && !strlen(refwwid))
> @@ -1106,8 +1106,7 @@ int coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid,
>
> if (VECTOR_SIZE(pathvec) == 0)
> return CP_OK;
> - size_mismatch_seen = calloc((VECTOR_SIZE(pathvec) - 1) / 64 + 1,
> - sizeof(uint64_t));
> + size_mismatch_seen = alloc_bitfield(VECTOR_SIZE(pathvec));
> if (size_mismatch_seen == NULL)
> return CP_FAIL;
>
> @@ -1131,7 +1130,7 @@ int coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid,
> }
>
> /* 2. if path already coalesced, or seen and discarded */
> - if (pp1->mpp || is_bit_set_in_array(k, size_mismatch_seen))
> + if (pp1->mpp || is_bit_set_in_bitfield(k, size_mismatch_seen))
> continue;
>
> /* 3. if path has disappeared */
> @@ -1183,7 +1182,7 @@ int coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid,
> "Discard", pp2->dev, pp2->size,
> mpp->size);
> mpp->action = ACT_REJECT;
> - set_bit_in_array(i, size_mismatch_seen);
> + set_bit_in_bitfield(i, size_mismatch_seen);
> }
> }
> verify_paths(mpp, vecs);
> diff --git a/libmultipath/util.c b/libmultipath/util.c
> index 3c43f28..46cacd4 100644
> --- a/libmultipath/util.c
> +++ b/libmultipath/util.c
> @@ -404,3 +404,38 @@ void close_fd(void *arg)
> {
> close((long)arg);
> }
> +
> +struct bitfield *alloc_bitfield(unsigned int maxbit)
> +{
> + unsigned int n;
> + struct bitfield *bf;
> +
> + n = maxbit > 0 ? (maxbit - 1) / bits_per_slot + 1 : 0;
What's the point in accepting 0? That's an empty bitmap.
> + bf = calloc(1, sizeof(struct bitfield) + n * sizeof(bitfield_t));
Need to check that bf got set before dereferencing it.
> + bf->len = maxbit;
> + return bf;
> +}
> +
> +void _log_bitfield_overflow(const char *f, unsigned int bit, unsigned int len)
> +{
> + condlog(0, "%s: bitfield overflow: %u >= %u", f, bit, len);
> +}
> +
> +unsigned int find_first_set(const struct bitfield *bf)
> +{
> + unsigned int b = 0, i, n;
> +
> + for (i = 0; i < bf->len; i+= bits_per_slot) {
> + b = _ffs(bf->bits[i / bits_per_slot]);
> + if (b != 0)
> + break;
> + };
> + if (b == 0)
> + return 0;
> +
> + n = i + b;
> + if (n <= bf->len)
> + return n;
> +
> + return 0;
> +}
This is neat and all, but what's it for? I didn't see it used in the
rest of the patches. Did I miss it, or do you have a future use for it?
> diff --git a/libmultipath/util.h b/libmultipath/util.h
> index df75c4f..ec6de6d 100644
> --- a/libmultipath/util.h
> +++ b/libmultipath/util.h
> @@ -1,6 +1,9 @@
> #ifndef _UTIL_H
> #define _UTIL_H
>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <limits.h>
> #include <sys/types.h>
> /* for rlim_t */
> #include <sys/resource.h>
> @@ -51,19 +54,61 @@ struct scandir_result {
> };
> void free_scandir_result(struct scandir_result *);
>
> -static inline bool is_bit_set_in_array(unsigned int bit, const uint64_t *arr)
> +/*
> + * ffsll() is also available on glibc < 2.27 if _GNU_SOURCE is defined.
> + * But relying on that would require that every program using this header file
> + * set _GNU_SOURCE during compilation, because otherwise the library and the
> + * program would use different types for bitfield_t, causing errors.
> + * That's too error prone, so if in doubt, use ffs().
> + */
> +#if __GLIBC_PREREQ(2, 27)
> +typedef unsigned long long int bitfield_t;
> +#define _ffs(x) ffsll(x)
> +#else
> +typedef unsigned int bitfield_t;
> +#define _ffs(x) ffs(x)
> +#endif
> +#define bits_per_slot (sizeof(bitfield_t) * CHAR_BIT)
> +
> +struct bitfield {
> + unsigned int len;
> + bitfield_t bits[];
> +};
> +
> +struct bitfield *alloc_bitfield(unsigned int maxbit);
> +
> +void _log_bitfield_overflow(const char *f, unsigned int bit, unsigned int len);
> +#define log_bitfield_overflow(bit, len) \
> + _log_bitfield_overflow(__func__, bit, len)
> +
> +static inline bool is_bit_set_in_bitfield(unsigned int bit,
> + const struct bitfield *bf)
> {
> - return arr[bit / 64] & (1ULL << (bit % 64)) ? 1 : 0;
> + if (bit >= bf->len) {
> + log_bitfield_overflow(bit, bf->len);
> + return false;
> + }
> + return !!(bf->bits[bit / bits_per_slot] &
> + (1ULL << (bit % bits_per_slot)));
> }
>
> -static inline void set_bit_in_array(unsigned int bit, uint64_t *arr)
> +static inline void set_bit_in_bitfield(unsigned int bit, struct bitfield *bf)
> {
> - arr[bit / 64] |= (1ULL << (bit % 64));
> + if (bit >= bf->len) {
> + log_bitfield_overflow(bit, bf->len);
> + return;
> + }
> + bf->bits[bit / bits_per_slot] |= (1ULL << (bit % bits_per_slot));
> }
>
> -static inline void clear_bit_in_array(unsigned int bit, uint64_t *arr)
> +static inline void clear_bit_in_bitfield(unsigned int bit, struct bitfield *bf)
> {
> - arr[bit / 64] &= ~(1ULL << (bit % 64));
> + if (bit >= bf->len) {
> + log_bitfield_overflow(bit, bf->len);
> + return;
> + }
> + bf->bits[bit / bits_per_slot] &= ~(1ULL << (bit % bits_per_slot));
> }
>
> +unsigned int find_first_set(const struct bitfield *bf);
> #endif /* _UTIL_H */
> diff --git a/tests/util.c b/tests/util.c
> index 6d12fda..db7c05f 100644
> --- a/tests/util.c
> +++ b/tests/util.c
> @@ -164,19 +164,25 @@ static int test_basenamecpy(void)
>
> static void test_bitmask_1(void **state)
> {
> - uint64_t arr[BITARR_SZ];
> + struct bitfield *bf;
> + uint64_t *arr;
> int i, j, k, m, b;
>
> - memset(arr, 0, sizeof(arr));
> + bf = alloc_bitfield(BITARR_SZ * 64);
> + assert_non_null(bf);
> + assert_int_equal(bf->len, BITARR_SZ * 64);
> + arr = (uint64_t *)bf->bits;
>
> for (j = 0; j < BITARR_SZ; j++) {
> for (i = 0; i < 64; i++) {
> b = 64 * j + i;
> - assert(!is_bit_set_in_array(b, arr));
> - set_bit_in_array(b, arr);
> + assert(!is_bit_set_in_bitfield(b, bf));
> + set_bit_in_bitfield(b, bf);
> for (k = 0; k < BITARR_SZ; k++) {
> +#if 0
> printf("b = %d j = %d k = %d a = %"PRIx64"\n",
> b, j, k, arr[k]);
> +#endif
> if (k == j)
> assert_int_equal(arr[j], 1ULL << i);
> else
> @@ -184,39 +190,46 @@ static void test_bitmask_1(void **state)
> }
> for (m = 0; m < 64; m++)
> if (i == m)
> - assert(is_bit_set_in_array(64 * j + m,
> - arr));
> + assert(is_bit_set_in_bitfield(64 * j + m,
> + bf));
> else
> - assert(!is_bit_set_in_array(64 * j + m,
> - arr));
> - clear_bit_in_array(b, arr);
> - assert(!is_bit_set_in_array(b, arr));
> + assert(!is_bit_set_in_bitfield(64 * j + m,
> + bf));
> + assert_int_equal(find_first_set(bf), b + 1);
> + clear_bit_in_bitfield(b, bf);
> + assert(!is_bit_set_in_bitfield(b, bf));
> for (k = 0; k < BITARR_SZ; k++)
> assert_int_equal(arr[k], 0ULL);
> }
> }
> + free(bf);
> }
>
> static void test_bitmask_2(void **state)
> {
> - uint64_t arr[BITARR_SZ];
> + struct bitfield *bf;
> + uint64_t *arr;
> int i, j, k, m, b;
>
> - memset(arr, 0, sizeof(arr));
> + bf = alloc_bitfield(BITARR_SZ * 64);
> + assert_non_null(bf);
> + assert_int_equal(bf->len, BITARR_SZ * 64);
> + arr = (uint64_t *)bf->bits;
>
> for (j = 0; j < BITARR_SZ; j++) {
> for (i = 0; i < 64; i++) {
> b = 64 * j + i;
> - assert(!is_bit_set_in_array(b, arr));
> - set_bit_in_array(b, arr);
> + assert(!is_bit_set_in_bitfield(b, bf));
> + set_bit_in_bitfield(b, bf);
> for (m = 0; m < 64; m++)
> if (m <= i)
> - assert(is_bit_set_in_array(64 * j + m,
> - arr));
> + assert(is_bit_set_in_bitfield(64 * j + m,
> + bf));
> else
> - assert(!is_bit_set_in_array(64 * j + m,
> - arr));
> - assert(is_bit_set_in_array(b, arr));
> + assert(!is_bit_set_in_bitfield(64 * j + m,
> + bf));
> + assert(is_bit_set_in_bitfield(b, bf));
> + assert_int_equal(find_first_set(bf), 1);
> for (k = 0; k < BITARR_SZ; k++) {
> if (k < j || (k == j && i == 63))
> assert_int_equal(arr[k], ~0ULL);
> @@ -232,16 +245,20 @@ static void test_bitmask_2(void **state)
> for (j = 0; j < BITARR_SZ; j++) {
> for (i = 0; i < 64; i++) {
> b = 64 * j + i;
> - assert(is_bit_set_in_array(b, arr));
> - clear_bit_in_array(b, arr);
> + assert(is_bit_set_in_bitfield(b, bf));
> + clear_bit_in_bitfield(b, bf);
> for (m = 0; m < 64; m++)
> if (m <= i)
> - assert(!is_bit_set_in_array(64 * j + m,
> - arr));
> + assert(!is_bit_set_in_bitfield(64 * j + m,
> + bf));
> else
> - assert(is_bit_set_in_array(64 * j + m,
> - arr));
> - assert(!is_bit_set_in_array(b, arr));
> + assert(is_bit_set_in_bitfield(64 * j + m,
> + bf));
> + assert(!is_bit_set_in_bitfield(b, bf));
> + if (b == 64 * BITARR_SZ - 1)
> + assert_int_equal(find_first_set(bf), 0);
> + else
> + assert_int_equal(find_first_set(bf), b + 2);
> for (k = 0; k < BITARR_SZ; k++) {
> if (k < j || (k == j && i == 63))
> assert_int_equal(arr[k], 0ULL);
> @@ -254,13 +271,207 @@ static void test_bitmask_2(void **state)
> }
> }
> }
> + free(bf);
> }
>
> +/*
> + * Test operations on a 0-length bitfield
> + */
> +static void test_bitmask_len_0(void **state)
> +{
> + struct bitfield *bf;
> +
> + bf = alloc_bitfield(0);
> + assert_non_null(bf);
> + assert_int_equal(bf->len, 0);
> + assert_int_equal(is_bit_set_in_bitfield(0, bf), 0);
> + assert_int_equal(is_bit_set_in_bitfield(1, bf), 0);
> + assert_int_equal(find_first_set(bf), 0);
> + set_bit_in_bitfield(0, bf);
> + assert_int_equal(is_bit_set_in_bitfield(0, bf), 0);
> + assert_int_equal(find_first_set(bf), 0);
> + clear_bit_in_bitfield(0, bf);
> + assert_int_equal(is_bit_set_in_bitfield(0, bf), 0);
> + set_bit_in_bitfield(11, bf);
> + assert_int_equal(find_first_set(bf), 0);
> + assert_int_equal(is_bit_set_in_bitfield(11, bf), 0);
> + clear_bit_in_bitfield(11, bf);
> + assert_int_equal(is_bit_set_in_bitfield(11, bf), 0);
> + free(bf);
> +}
> +
> +static void _test_bitmask_small(unsigned int n)
> +{
> + struct bitfield *bf;
> + uint64_t *arr;
> +
> + assert(n <= 64);
> + assert(n >= 1);
> +
> + bf = alloc_bitfield(n);
> + assert_non_null(bf);
> + assert_int_equal(bf->len, n);
> + arr = (uint64_t *)bf->bits;
> +
> + assert_int_equal(*arr, 0);
> +
> + set_bit_in_bitfield(n + 1, bf);
> + assert_int_equal(*arr, 0);
> + assert_int_equal(find_first_set(bf), 0);
> +
> + set_bit_in_bitfield(n, bf);
> + assert_int_equal(*arr, 0);
> + assert_int_equal(find_first_set(bf), 0);
> +
> + set_bit_in_bitfield(n - 1, bf);
> + assert_int_equal(*arr, 1ULL << (n - 1));
> + assert_int_equal(find_first_set(bf), n);
> +
> + clear_bit_in_bitfield(n - 1, bf);
> + assert_int_equal(*arr, 0);
> + assert_int_equal(find_first_set(bf), 0);
> +
> + set_bit_in_bitfield(0, bf);
> + assert_int_equal(*arr, 1);
> + assert_int_equal(find_first_set(bf), 1);
> +
> + free(bf);
> +}
> +
> +static void _test_bitmask_small_2(unsigned int n)
> +{
> + struct bitfield *bf;
> + uint64_t *arr;
> +
> + assert(n <= 128);
> + assert(n >= 65);
> +
> + bf = alloc_bitfield(n);
> + assert_non_null(bf);
> + assert_int_equal(bf->len, n);
> + arr = (uint64_t *)bf->bits;
> +
> + assert_int_equal(arr[0], 0);
> + assert_int_equal(arr[1], 0);
> +
> + set_bit_in_bitfield(n + 1, bf);
> + assert_int_equal(arr[0], 0);
> + assert_int_equal(arr[1], 0);
> + assert_int_equal(find_first_set(bf), 0);
> +
> + set_bit_in_bitfield(n, bf);
> + assert_int_equal(arr[0], 0);
> + assert_int_equal(arr[1], 0);
> + assert_int_equal(find_first_set(bf), 0);
> +
> + set_bit_in_bitfield(n - 1, bf);
> + assert_int_equal(arr[0], 0);
> + assert_int_equal(arr[1], 1ULL << (n - 65));
> + assert_int_equal(find_first_set(bf), n);
> +
> + set_bit_in_bitfield(0, bf);
> + assert_int_equal(arr[0], 1);
> + assert_int_equal(arr[1], 1ULL << (n - 65));
> + assert_int_equal(find_first_set(bf), 1);
> +
> + set_bit_in_bitfield(64, bf);
> + assert_int_equal(arr[0], 1);
> + assert_int_equal(arr[1], (1ULL << (n - 65)) | 1);
> + assert_int_equal(find_first_set(bf), 1);
> +
> + clear_bit_in_bitfield(0, bf);
> + assert_int_equal(arr[0], 0);
> + assert_int_equal(arr[1], (1ULL << (n - 65)) | 1);
> + assert_int_equal(find_first_set(bf), 65);
> +
> + free(bf);
> +}
> +
> +static void test_bitmask_len_1(void **state)
> +{
> + _test_bitmask_small(1);
> +}
> +
> +static void test_bitmask_len_2(void **state)
> +{
> + _test_bitmask_small(2);
> +}
> +
> +static void test_bitmask_len_3(void **state)
> +{
> + _test_bitmask_small(3);
> +}
> +
> +static void test_bitmask_len_23(void **state)
> +{
> + _test_bitmask_small(23);
> +}
> +
> +static void test_bitmask_len_63(void **state)
> +{
> + _test_bitmask_small(63);
> +}
> +
> +static void test_bitmask_len_64(void **state)
> +{
> + _test_bitmask_small(63);
> +}
> +
> +static void test_bitmask_len_65(void **state)
> +{
> + _test_bitmask_small_2(65);
> +}
> +
> +static void test_bitmask_len_66(void **state)
> +{
> + _test_bitmask_small_2(66);
> +}
> +
> +static void test_bitmask_len_67(void **state)
> +{
> + _test_bitmask_small_2(67);
> +}
> +
> +static void test_bitmask_len_103(void **state)
> +{
> + _test_bitmask_small_2(103);
> +}
> +
> +static void test_bitmask_len_126(void **state)
> +{
> + _test_bitmask_small_2(126);
> +}
> +
> +static void test_bitmask_len_127(void **state)
> +{
> + _test_bitmask_small_2(127);
> +}
> +
> +static void test_bitmask_len_128(void **state)
> +{
> + _test_bitmask_small_2(128);
> +}
> +
> +
> static int test_bitmasks(void)
> {
> const struct CMUnitTest tests[] = {
> cmocka_unit_test(test_bitmask_1),
> cmocka_unit_test(test_bitmask_2),
> + cmocka_unit_test(test_bitmask_len_0),
> + cmocka_unit_test(test_bitmask_len_1),
> + cmocka_unit_test(test_bitmask_len_2),
> + cmocka_unit_test(test_bitmask_len_3),
> + cmocka_unit_test(test_bitmask_len_23),
> + cmocka_unit_test(test_bitmask_len_63),
> + cmocka_unit_test(test_bitmask_len_64),
> + cmocka_unit_test(test_bitmask_len_65),
> + cmocka_unit_test(test_bitmask_len_66),
> + cmocka_unit_test(test_bitmask_len_67),
> + cmocka_unit_test(test_bitmask_len_103),
> + cmocka_unit_test(test_bitmask_len_126),
> + cmocka_unit_test(test_bitmask_len_127),
> + cmocka_unit_test(test_bitmask_len_128),
> };
> return cmocka_run_group_tests(tests, NULL, NULL);
> }
> --
> 2.26.2
^ permalink raw reply
* Re: [PATCH v3 05/12] powerpc/drmem: make lmb walk a bit more flexible
From: Hari Bathini @ 2020-07-16 21:09 UTC (permalink / raw)
To: Thiago Jung Bauermann
Cc: Pingfan Liu, Petr Tesarik, Nayna Jain, Kexec-ml,
Mahesh J Salgaonkar, Mimi Zohar, lkml, linuxppc-dev, Sourabh Jain,
Andrew Morton, Dave Young, Vivek Goyal, Eric Biederman
In-Reply-To: <871rld8mic.fsf@morokweng.localdomain>
On 15/07/20 9:20 am, Thiago Jung Bauermann wrote:
>
> Hari Bathini <hbathini@linux.ibm.com> writes:
>
>> @@ -534,7 +537,7 @@ static int __init early_init_dt_scan_memory_ppc(unsigned long node,
>> #ifdef CONFIG_PPC_PSERIES
>> if (depth == 1 &&
>> strcmp(uname, "ibm,dynamic-reconfiguration-memory") == 0) {
>> - walk_drmem_lmbs_early(node, early_init_drmem_lmb);
>> + walk_drmem_lmbs_early(node, NULL, early_init_drmem_lmb);
>
> walk_drmem_lmbs_early() can now fail. Should this failure be propagated
> as a return value of early_init_dt_scan_memory_ppc()?
>
>> return 0;
>> }
>> #endif
> <snip>
>
>> @@ -787,7 +790,7 @@ static int __init parse_numa_properties(void)
>> */
>> memory = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory");
>> if (memory) {
>> - walk_drmem_lmbs(memory, numa_setup_drmem_lmb);
>> + walk_drmem_lmbs(memory, NULL, numa_setup_drmem_lmb);
>
> Similarly here. Now that this call can fail, should
> parse_numa_properties() handle or propagate the failure?
They would still not fail unless the callbacks early_init_drmem_lmb() & numa_setup_drmem_lmb()
are updated to have failure scenarios. Also, these call sites always ignored failure scenarios
even before walk_drmem_lmbs() was introduced. So, I prefer to keep them the way they are?
Thanks
Hari
^ permalink raw reply
* [PATCH][next] pinctrl: qcom: spmi-gpio: Use fallthrough pseudo-keyword
From: Gustavo A. R. Silva @ 2020-07-16 21:22 UTC (permalink / raw)
To: Bjorn Andersson, Andy Gross, Linus Walleij
Cc: linux-arm-msm, linux-gpio, linux-kernel, Gustavo A. R. Silva
Replace the existing /* fall through */ comments and its variants with
the new pseudo-keyword macro fallthrough[1].
[1] https://www.kernel.org/doc/html/latest/process/deprecated.html?highlight=fallthrough#implicit-switch-case-fall-through
Signed-off-by: Gustavo A. R. Silva <gustavoars@kernel.org>
---
drivers/pinctrl/qcom/pinctrl-spmi-gpio.c | 4 ++--
drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
index 66cbcfe7950e..17441388ce8f 100644
--- a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
+++ b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
@@ -794,13 +794,13 @@ static int pmic_gpio_populate(struct pmic_gpio_state *state,
switch (subtype) {
case PMIC_GPIO_SUBTYPE_GPIO_4CH:
pad->have_buffer = true;
- /* Fall through */
+ fallthrough;
case PMIC_GPIO_SUBTYPE_GPIOC_4CH:
pad->num_sources = 4;
break;
case PMIC_GPIO_SUBTYPE_GPIO_8CH:
pad->have_buffer = true;
- /* Fall through */
+ fallthrough;
case PMIC_GPIO_SUBTYPE_GPIOC_8CH:
pad->num_sources = 8;
break;
diff --git a/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c b/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c
index 338a15d08629..b5949f766a7a 100644
--- a/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c
+++ b/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c
@@ -346,7 +346,7 @@ static int pm8xxx_pin_config_set(struct pinctrl_dev *pctldev,
return -EINVAL;
}
pin->pull_up_strength = arg;
- /* FALLTHROUGH */
+ fallthrough;
case PIN_CONFIG_BIAS_PULL_UP:
pin->bias = pin->pull_up_strength;
banks |= BIT(2);
--
2.27.0
^ permalink raw reply related
* Re: [PATCH 5.9 0/7] recv/rw select-buffer fortifying
From: Pavel Begunkov @ 2020-07-16 21:14 UTC (permalink / raw)
To: Jens Axboe, io-uring
In-Reply-To: <9a2d155c-ddc9-8c7a-5f9f-87dcaab02693@kernel.dk>
On 17/07/2020 00:13, Jens Axboe wrote:
> On 7/16/20 2:27 PM, Pavel Begunkov wrote:
>> This series makes selected buffer managment more resilient to errors,
>> especially io_recv[msg](). Even though, it makes some small accidential
>> optimisations, I don't think performance difference will be observable
>> at the end.
>
> I shuffled this a little bit, as it relies on both 5.9 and the leak
> fix from 5.8.
>
> Also, some of your commit messages use really short lines, just use
> 72 consistently for all of them. Minor detail, just not sure why
> they are different. I fixed them up.
I'll double check the next time, thanks
--
Pavel Begunkov
^ permalink raw reply
* Re: [PATCH bpf-next 3/5] bpf: propagate poke descriptors to subprograms
From: Daniel Borkmann @ 2020-07-16 21:16 UTC (permalink / raw)
To: Maciej Fijalkowski, ast; +Cc: bpf, netdev, bjorn.topel, magnus.karlsson
In-Reply-To: <20200715233634.3868-4-maciej.fijalkowski@intel.com>
On 7/16/20 1:36 AM, Maciej Fijalkowski wrote:
> Previously, there was no need for poke descriptors being present in
> subprogram's bpf_prog_aux struct since tailcalls were simply not allowed
> in them. Each subprog is JITed independently so in order to enable
> JITing such subprograms, simply copy poke descriptors from main program
> to subprogram's poke tab.
>
> Add also subprog's aux struct to the BPF map poke_progs list by calling
> on it map_poke_track().
>
> Signed-off-by: Maciej Fijalkowski <maciej.fijalkowski@intel.com>
> ---
> kernel/bpf/verifier.c | 9 +++++++++
> 1 file changed, 9 insertions(+)
>
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index 6481342b31ba..3b406b2860ef 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -9932,6 +9932,9 @@ static int jit_subprogs(struct bpf_verifier_env *env)
> goto out_undo_insn;
>
> for (i = 0; i < env->subprog_cnt; i++) {
> + struct bpf_map *map_ptr;
> + int j;
> +
> subprog_start = subprog_end;
> subprog_end = env->subprog_info[i + 1].start;
>
> @@ -9956,6 +9959,12 @@ static int jit_subprogs(struct bpf_verifier_env *env)
> func[i]->aux->btf = prog->aux->btf;
> func[i]->aux->func_info = prog->aux->func_info;
>
> + for (j = 0; j < prog->aux->size_poke_tab; j++) {
> + bpf_jit_add_poke_descriptor(func[i], &prog->aux->poke_tab[j]);
> + map_ptr = func[i]->aux->poke_tab[j].tail_call.map;
> + map_ptr->ops->map_poke_track(map_ptr, func[i]->aux);
Error checking missing for bpf_jit_add_poke_descriptor() and map_poke_track() ..? It
must be guaranteed that adding this to the tracker must not fail, otherwise this will
be a real pain to debug given the prog will never be patched.
> + }
> +
> /* Use bpf_prog_F_tag to indicate functions in stack traces.
> * Long term would need debug info to populate names
> */
>
^ permalink raw reply
* Re: [PATCH 2/4] fs: Remove FIRMWARE_PREALLOC_BUFFER from kernel_read_file() enums
From: Kees Cook @ 2020-07-16 21:16 UTC (permalink / raw)
To: Scott Branden
Cc: Matthew Wilcox, James Morris, Luis Chamberlain, Mimi Zohar,
Greg Kroah-Hartman, Rafael J. Wysocki, Alexander Viro, Jessica Yu,
Dmitry Kasatkin, Serge E. Hallyn, Casey Schaufler,
Eric W. Biederman, Peter Zijlstra, Matthew Garrett, David Howells,
Mauro Carvalho Chehab, Randy Dunlap, Joel Fernandes (Google),
KP Singh, Dave Olsthoorn, Hans de Goede, Peter Jones,
Andrew Morton, Stephen Boyd, Paul Moore, linux-kernel,
linux-fsdevel, linux-integrity, linux-security-module
In-Reply-To: <9ba08503-e515-6761-63de-a3b611720b1b@broadcom.com>
On Thu, Jul 16, 2020 at 01:35:17PM -0700, Scott Branden wrote:
> On 2020-07-10 3:44 p.m., Kees Cook wrote:
> > On Fri, Jul 10, 2020 at 03:10:25PM -0700, Scott Branden wrote:
> > >
> > > On 2020-07-10 3:04 p.m., Matthew Wilcox wrote:
> > > > On Fri, Jul 10, 2020 at 02:00:32PM -0700, Scott Branden wrote:
> > > > > > @@ -950,8 +951,8 @@ int kernel_read_file(struct file *file, void **buf, loff_t *size,
> > > > > > goto out;
> > > > > > }
> > > > > > - if (id != READING_FIRMWARE_PREALLOC_BUFFER)
> > > > > > - *buf = vmalloc(i_size);
> > > > > > + if (!*buf)
> > > > > The assumption that *buf is always NULL when id !=
> > > > > READING_FIRMWARE_PREALLOC_BUFFER doesn't appear to be correct.
> > > > > I get unhandled page faults due to this change on boot.
> > > > Did it give you a stack backtrace?
> > > Yes, but there's no requirement that *buf need to be NULL when calling this
> > > function.
> > > To fix my particular crash I added the following locally:
> > >
> > > --- a/kernel/module.c
> > > +++ b/kernel/module.c
> > > @@ -3989,7 +3989,7 @@ SYSCALL_DEFINE3(finit_module, int, fd, const char
> > > __user *, uargs, int, flags)
> > > {
> > > struct load_info info = { };
> > > loff_t size;
> > > - void *hdr;
> > > + void *hdr = NULL;
> > > int err;
> > >
> > > err = may_init_module();
> > Thanks for the diagnosis and fix! I haven't had time to cycle back
> > around to this series yet. Hopefully soon. :)
> >
> In order to assist in your patchset I have combined it with my patch series
> here:
> https://github.com/sbranden/linux/tree/kernel_read_file_for_kees
>
> Please let me know if this matches your expectations for my patches or if
> there is something else I need to change.
Thanks! I was working on the next revision of this last night, and I'm
trying to get through today's email to finish it. I'll take a look!
--
Kees Cook
^ permalink raw reply
* [PATCH][next] pinctrl: lpc18xx: Use fallthrough pseudo-keyword
From: Gustavo A. R. Silva @ 2020-07-16 21:21 UTC (permalink / raw)
To: Linus Walleij, Vladimir Zapolskiy
Cc: linux-gpio, linux-arm-kernel, linux-kernel, Gustavo A. R. Silva
Replace the existing /* fall through */ comments and its variants with
the new pseudo-keyword macro fallthrough[1].
[1] https://www.kernel.org/doc/html/latest/process/deprecated.html?highlight=fallthrough#implicit-switch-case-fall-through
Signed-off-by: Gustavo A. R. Silva <gustavoars@kernel.org>
---
drivers/pinctrl/pinctrl-lpc18xx.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/pinctrl/pinctrl-lpc18xx.c b/drivers/pinctrl/pinctrl-lpc18xx.c
index e4677546aec4..7b2f885e68bd 100644
--- a/drivers/pinctrl/pinctrl-lpc18xx.c
+++ b/drivers/pinctrl/pinctrl-lpc18xx.c
@@ -838,11 +838,11 @@ static int lpc18xx_pconf_get_pin(struct pinctrl_dev *pctldev, unsigned param,
*arg = (reg & LPC18XX_SCU_PIN_EHD_MASK) >> LPC18XX_SCU_PIN_EHD_POS;
switch (*arg) {
case 3: *arg += 5;
- /* fall through */
+ fallthrough;
case 2: *arg += 5;
- /* fall through */
+ fallthrough;
case 1: *arg += 3;
- /* fall through */
+ fallthrough;
case 0: *arg += 4;
}
break;
@@ -1057,11 +1057,11 @@ static int lpc18xx_pconf_set_pin(struct pinctrl_dev *pctldev, unsigned param,
switch (param_val) {
case 20: param_val -= 5;
- /* fall through */
+ fallthrough;
case 14: param_val -= 5;
- /* fall through */
+ fallthrough;
case 8: param_val -= 3;
- /* fall through */
+ fallthrough;
case 4: param_val -= 4;
break;
default:
--
2.27.0
^ permalink raw reply related
* Re: [PATCH v3 04/12] ppc64/kexec_file: avoid stomping memory used by special regions
From: Hari Bathini @ 2020-07-16 21:09 UTC (permalink / raw)
To: Thiago Jung Bauermann
Cc: Pingfan Liu, Petr Tesarik, Nayna Jain, Kexec-ml,
Mahesh J Salgaonkar, Mimi Zohar, lkml, linuxppc-dev, Sourabh Jain,
Andrew Morton, Dave Young, Vivek Goyal, Eric Biederman
In-Reply-To: <87365t8pse.fsf@morokweng.localdomain>
On 15/07/20 8:09 am, Thiago Jung Bauermann wrote:
>
> Hari Bathini <hbathini@linux.ibm.com> writes:
>
<snip>
>> +/**
>> + * __locate_mem_hole_top_down - Looks top down for a large enough memory hole
>> + * in the memory regions between buf_min & buf_max
>> + * for the buffer. If found, sets kbuf->mem.
>> + * @kbuf: Buffer contents and memory parameters.
>> + * @buf_min: Minimum address for the buffer.
>> + * @buf_max: Maximum address for the buffer.
>> + *
>> + * Returns 0 on success, negative errno on error.
>> + */
>> +static int __locate_mem_hole_top_down(struct kexec_buf *kbuf,
>> + u64 buf_min, u64 buf_max)
>> +{
>> + int ret = -EADDRNOTAVAIL;
>> + phys_addr_t start, end;
>> + u64 i;
>> +
>> + for_each_mem_range_rev(i, &memblock.memory, NULL, NUMA_NO_NODE,
>> + MEMBLOCK_NONE, &start, &end, NULL) {
>> + if (start > buf_max)
>> + continue;
>> +
>> + /* Memory hole not found */
>> + if (end < buf_min)
>> + break;
>> +
>> + /* Adjust memory region based on the given range */
>> + if (start < buf_min)
>> + start = buf_min;
>> + if (end > buf_max)
>> + end = buf_max;
>> +
>> + start = ALIGN(start, kbuf->buf_align);
>> + if (start < end && (end - start + 1) >= kbuf->memsz) {
>
> This is why I dislike using start and end to express address ranges:
>
> While struct resource seems to use the [address, end] convention, my
struct crash_mem also uses [address, end] convention.
This off-by-one error did not cause any issues as the hole start and size we try to find
are at least page aligned.
Nonetheless, I think fixing 'end' early in the loop with "end -= 1" would ensure
correctness while continuing to use the same convention for structs crash_mem & resource.
Thanks
Hari
^ permalink raw reply
* Re: [patch V3 08/13] x86/entry: Use generic syscall entry function
From: Kees Cook @ 2020-07-16 21:13 UTC (permalink / raw)
To: Thomas Gleixner
Cc: LKML, x86, linux-arch, Will Deacon, Arnd Bergmann, Mark Rutland,
Keno Fischer, Paolo Bonzini, kvm
In-Reply-To: <20200716185424.765294277@linutronix.de>
On Thu, Jul 16, 2020 at 08:22:16PM +0200, Thomas Gleixner wrote:
> From: Thomas Gleixner <tglx@linutronix.de>
>
> Replace the syscall entry work handling with the generic version. Provide
> the necessary helper inlines to handle the real architecture specific
> parts, e.g. audit and seccomp invocations.
>
> Use a temporary define for idtentry_enter_user which will be cleaned up
> seperately.
>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
> [...]
> --- /dev/null
> +++ b/arch/x86/include/asm/entry-common.h
> @@ -0,0 +1,86 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +#ifndef _ASM_X86_ENTRY_COMMON_H
> +#define _ASM_X86_ENTRY_COMMON_H
> +
> +#include <linux/seccomp.h>
> +#include <linux/audit.h>
> +
> +/* Check that the stack and regs on entry from user mode are sane. */
> +static __always_inline void arch_check_user_regs(struct pt_regs *regs)
> +{
> + if (IS_ENABLED(CONFIG_DEBUG_ENTRY)) {
> + /*
> + * Make sure that the entry code gave us a sensible EFLAGS
> + * register. Native because we want to check the actual CPU
> + * state, not the interrupt state as imagined by Xen.
> + */
> + unsigned long flags = native_save_fl();
> + WARN_ON_ONCE(flags & (X86_EFLAGS_AC | X86_EFLAGS_DF |
> + X86_EFLAGS_NT));
> +
> + /* We think we came from user mode. Make sure pt_regs agrees. */
> + WARN_ON_ONCE(!user_mode(regs));
> +
> + /*
> + * All entries from user mode (except #DF) should be on the
> + * normal thread stack and should have user pt_regs in the
> + * correct location.
> + */
> + WARN_ON_ONCE(!on_thread_stack());
> + WARN_ON_ONCE(regs != task_pt_regs(current));
> + }
> +}
> +#define arch_check_user_regs arch_check_user_regs
Will architectures implement subsets of these functions? (i.e. instead
of each of the defines, is CONFIG_ENTRY_GENERIC sufficient for the
no-op inlines?)
> +
> +static inline long arch_syscall_enter_seccomp(struct pt_regs *regs)
> +{
> +#ifdef CONFIG_SECCOMP
> + u32 arch = in_ia32_syscall() ? AUDIT_ARCH_I386 : AUDIT_ARCH_X86_64;
> + struct seccomp_data sd;
> +
> + sd.arch = arch;
> + sd.nr = regs->orig_ax;
> + sd.instruction_pointer = regs->ip;
> +
> +#ifdef CONFIG_X86_64
> + if (arch == AUDIT_ARCH_X86_64) {
> + sd.args[0] = regs->di;
> + sd.args[1] = regs->si;
> + sd.args[2] = regs->dx;
> + sd.args[3] = regs->r10;
> + sd.args[4] = regs->r8;
> + sd.args[5] = regs->r9;
> + } else
> +#endif
> + {
> + sd.args[0] = regs->bx;
> + sd.args[1] = regs->cx;
> + sd.args[2] = regs->dx;
> + sd.args[3] = regs->si;
> + sd.args[4] = regs->di;
> + sd.args[5] = regs->bp;
> + }
> +
> + return __secure_computing(&sd);
> +#else
> + return 0;
> +#endif
> +}
> +#define arch_syscall_enter_seccomp arch_syscall_enter_seccomp
Actually, I've been meaning to clean this up. It's not needed at all.
This was left over from the seccomp fast-path code that got ripped out a
while ago. seccomp already has everything it needs to do this work, so
just:
__secure_computing(NULL);
is sufficient for every architecture that supports seccomp. (See kernel/seccomp.c
populate_seccomp_data().)
And if you want more generalization work, note that the secure_computing()
macro performs a TIF test before calling __secure_computing(NULL). But
my point is, I think arch_syscall_enter_seccomp() is not needed.
> +static inline void arch_syscall_enter_audit(struct pt_regs *regs)
> +{
> +#ifdef CONFIG_X86_64
> + if (in_ia32_syscall()) {
> + audit_syscall_entry(regs->orig_ax, regs->di,
> + regs->si, regs->dx, regs->r10);
> + } else
> +#endif
> + {
> + audit_syscall_entry(regs->orig_ax, regs->bx,
> + regs->cx, regs->dx, regs->si);
> + }
> +}
> +#define arch_syscall_enter_audit arch_syscall_enter_audit
Similarly, I think these can be redefined in the generic case
using the existing accessors for syscall arguments, etc. e.g.
arch_syscall_enter_audit() is not needed for any architecture, and the
generic is:
unsigned long args[6];
syscall_get_arguments(task, regs, args);
audit_syscall_entry(syscall_get_nr(current, regs),
args[0], args[1], args[2], args[3]);
--
Kees Cook
^ permalink raw reply
* [PATCH][next] pinctrl: baytrail: Use fallthrough pseudo-keyword
From: Gustavo A. R. Silva @ 2020-07-16 21:19 UTC (permalink / raw)
To: Mika Westerberg, Andy Shevchenko, Linus Walleij
Cc: linux-gpio, linux-kernel, Gustavo A. R. Silva
Replace the existing /* fall through */ comments and its variants with
the new pseudo-keyword macro fallthrough[1].
[1] https://www.kernel.org/doc/html/latest/process/deprecated.html?highlight=fallthrough#implicit-switch-case-fall-through
Signed-off-by: Gustavo A. R. Silva <gustavoars@kernel.org>
---
drivers/pinctrl/intel/pinctrl-baytrail.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/pinctrl/intel/pinctrl-baytrail.c b/drivers/pinctrl/intel/pinctrl-baytrail.c
index a917a2df520e..d6e35cba3065 100644
--- a/drivers/pinctrl/intel/pinctrl-baytrail.c
+++ b/drivers/pinctrl/intel/pinctrl-baytrail.c
@@ -1372,13 +1372,13 @@ static void byt_irq_unmask(struct irq_data *d)
switch (irqd_get_trigger_type(d)) {
case IRQ_TYPE_LEVEL_HIGH:
value |= BYT_TRIG_LVL;
- /* fall through */
+ fallthrough;
case IRQ_TYPE_EDGE_RISING:
value |= BYT_TRIG_POS;
break;
case IRQ_TYPE_LEVEL_LOW:
value |= BYT_TRIG_LVL;
- /* fall through */
+ fallthrough;
case IRQ_TYPE_EDGE_FALLING:
value |= BYT_TRIG_NEG;
break;
--
2.27.0
^ permalink raw reply related
* Re: [PATCH 5.9 0/7] recv/rw select-buffer fortifying
From: Jens Axboe @ 2020-07-16 21:13 UTC (permalink / raw)
To: Pavel Begunkov, io-uring
In-Reply-To: <cover.1594930020.git.asml.silence@gmail.com>
On 7/16/20 2:27 PM, Pavel Begunkov wrote:
> This series makes selected buffer managment more resilient to errors,
> especially io_recv[msg](). Even though, it makes some small accidential
> optimisations, I don't think performance difference will be observable
> at the end.
I shuffled this a little bit, as it relies on both 5.9 and the leak
fix from 5.8.
Also, some of your commit messages use really short lines, just use
72 consistently for all of them. Minor detail, just not sure why
they are different. I fixed them up.
--
Jens Axboe
^ permalink raw reply
* Re: [PATCH v3 07/12] ppc64/kexec_file: add support to relocate purgatory
From: Hari Bathini @ 2020-07-16 21:11 UTC (permalink / raw)
To: Thiago Jung Bauermann
Cc: kernel test robot, Pingfan Liu, Nayna Jain, Kexec-ml,
Mahesh J Salgaonkar, Mimi Zohar, lkml, linuxppc-dev, Sourabh Jain,
Petr Tesarik, Andrew Morton, Dave Young, Vivek Goyal,
Eric Biederman
In-Reply-To: <871rlc9upc.fsf@morokweng.localdomain>
On 16/07/20 5:50 am, Thiago Jung Bauermann wrote:
>
> Hari Bathini <hbathini@linux.ibm.com> writes:
>
>> Right now purgatory implementation is only minimal. But if purgatory
>> code is to be enhanced to copy memory to the backup region and verify
>
> Can't the memcpy be done in asm? We have arch/powerpc/lib/memcpy_64.S
> for example, perhaps it could be linked in with the purgatory?
I wanted to avoid touching common code to make it work for purgatory
for now.
>
>> sha256 digest, relocations may have to be applied to the purgatory.
>
> Do we want to do the sha256 verification? My original patch series for
> kexec_file_load() had a purgatory in C from kexec-tools which did the
> sha256 verification but Michael Ellerman thought it was unnecessary and
> decided to use the simpler purgatory in asm from kexec-lite.
kexec_file_load could as well be used without IMA or secureboot. With sha256 digest
calculated anyway, verifying it would make sense to accommodate that case as well.
>
>> So, add support to relocate purgatory in kexec_file_load system call
>> by setting up TOC pointer and applying RELA relocations as needed.
>
> If we do want to use a C purgatory, Michael Ellerman had suggested
> building it as a Position Independent Executable, which greatly reduces
> the number and types of relocations that are needed. See patches 4 and 9
> here:
>
> https://lore.kernel.org/linuxppc-dev/1478748449-3894-1-git-send-email-bauerman@linux.vnet.ibm.com/
>
> In the series above I hadn't converted x86 to PIE. If I had done that,
> possibly Dave Young's opinion would have been different. :-)
>
> If that's still not desirable, he suggested in that discussion lifting
> some code from x86 to generic code, which I implemented and would
> simplify this patch as well:
>
> https://lore.kernel.org/linuxppc-dev/5009580.5GxAkTrMYA@morokweng/
>
Agreed. But I prefer to work on PIE and/or moving common relocation_add code
for x86 & s390 to generic code later when I try to build on these purgatory
changes. So, a separate series later to rework purgatory with the things you
mentioned above sounds ok?
Thanks
Hari
^ permalink raw reply
* Re: [PATCH v16 13/22] mm/lru: introduce TestClearPageLRU
From: Alexander Duyck @ 2020-07-16 21:12 UTC (permalink / raw)
To: Alex Shi
Cc: Andrew Morton, Mel Gorman, Tejun Heo, Hugh Dickins,
Konstantin Khlebnikov, Daniel Jordan, Yang Shi, Matthew Wilcox,
Johannes Weiner, kbuild test robot, linux-mm, LKML, cgroups,
Shakeel Butt, Joonsoo Kim, Wei Yang, Kirill A. Shutemov,
Michal Hocko, Vladimir Davydov
In-Reply-To: <1594429136-20002-14-git-send-email-alex.shi@linux.alibaba.com>
On Fri, Jul 10, 2020 at 5:59 PM Alex Shi <alex.shi@linux.alibaba.com> wrote:
>
> Combine PageLRU check and ClearPageLRU into a function by new
> introduced func TestClearPageLRU. This function will be used as page
> isolation precondition to prevent other isolations some where else.
> Then there are may non PageLRU page on lru list, need to remove BUG
> checking accordingly.
>
> Hugh Dickins pointed that __page_cache_release and release_pages
> has no need to do atomic clear bit since no user on the page at that
> moment. and no need get_page() before lru bit clear in isolate_lru_page,
> since it '(1) Must be called with an elevated refcount on the page'.
>
> As Andrew Morton mentioned this change would dirty cacheline for page
> isn't on LRU. But the lost would be acceptable with Rong Chen
> <rong.a.chen@intel.com> report:
> https://lkml.org/lkml/2020/3/4/173
>
> Suggested-by: Johannes Weiner <hannes@cmpxchg.org>
> Signed-off-by: Alex Shi <alex.shi@linux.alibaba.com>
> Cc: Hugh Dickins <hughd@google.com>
> Cc: Johannes Weiner <hannes@cmpxchg.org>
> Cc: Michal Hocko <mhocko@kernel.org>
> Cc: Vladimir Davydov <vdavydov.dev@gmail.com>
> Cc: Andrew Morton <akpm@linux-foundation.org>
> Cc: linux-kernel@vger.kernel.org
> Cc: cgroups@vger.kernel.org
> Cc: linux-mm@kvack.org
> ---
> include/linux/page-flags.h | 1 +
> mm/mlock.c | 3 +--
> mm/swap.c | 6 ++----
> mm/vmscan.c | 26 +++++++++++---------------
> 4 files changed, 15 insertions(+), 21 deletions(-)
>
> diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
> index 6be1aa559b1e..9554ed1387dc 100644
> --- a/include/linux/page-flags.h
> +++ b/include/linux/page-flags.h
> @@ -326,6 +326,7 @@ static inline void page_init_poison(struct page *page, size_t size)
> PAGEFLAG(Dirty, dirty, PF_HEAD) TESTSCFLAG(Dirty, dirty, PF_HEAD)
> __CLEARPAGEFLAG(Dirty, dirty, PF_HEAD)
> PAGEFLAG(LRU, lru, PF_HEAD) __CLEARPAGEFLAG(LRU, lru, PF_HEAD)
> + TESTCLEARFLAG(LRU, lru, PF_HEAD)
> PAGEFLAG(Active, active, PF_HEAD) __CLEARPAGEFLAG(Active, active, PF_HEAD)
> TESTCLEARFLAG(Active, active, PF_HEAD)
> PAGEFLAG(Workingset, workingset, PF_HEAD)
> diff --git a/mm/mlock.c b/mm/mlock.c
> index f8736136fad7..228ba5a8e0a5 100644
> --- a/mm/mlock.c
> +++ b/mm/mlock.c
> @@ -108,13 +108,12 @@ void mlock_vma_page(struct page *page)
> */
> static bool __munlock_isolate_lru_page(struct page *page, bool getpage)
> {
> - if (PageLRU(page)) {
> + if (TestClearPageLRU(page)) {
> struct lruvec *lruvec;
>
> lruvec = mem_cgroup_page_lruvec(page, page_pgdat(page));
> if (getpage)
> get_page(page);
> - ClearPageLRU(page);
> del_page_from_lru_list(page, lruvec, page_lru(page));
> return true;
> }
> diff --git a/mm/swap.c b/mm/swap.c
> index f645965fde0e..5092fe9c8c47 100644
> --- a/mm/swap.c
> +++ b/mm/swap.c
> @@ -83,10 +83,9 @@ static void __page_cache_release(struct page *page)
> struct lruvec *lruvec;
> unsigned long flags;
>
> + __ClearPageLRU(page);
> spin_lock_irqsave(&pgdat->lru_lock, flags);
> lruvec = mem_cgroup_page_lruvec(page, pgdat);
> - VM_BUG_ON_PAGE(!PageLRU(page), page);
> - __ClearPageLRU(page);
> del_page_from_lru_list(page, lruvec, page_off_lru(page));
> spin_unlock_irqrestore(&pgdat->lru_lock, flags);
> }
So this piece doesn't make much sense to me. Why not use
TestClearPageLRU(page) here? Just a few lines above you are testing
for PageLRU(page) and it seems like if you are going to go for an
atomic test/clear and then remove the page from the LRU list you
should be using it here as well otherwise it seems like you could run
into a potential collision since you are testing here without clearing
the bit.
> @@ -878,9 +877,8 @@ void release_pages(struct page **pages, int nr)
> spin_lock_irqsave(&locked_pgdat->lru_lock, flags);
> }
>
> - lruvec = mem_cgroup_page_lruvec(page, locked_pgdat);
> - VM_BUG_ON_PAGE(!PageLRU(page), page);
> __ClearPageLRU(page);
> + lruvec = mem_cgroup_page_lruvec(page, locked_pgdat);
> del_page_from_lru_list(page, lruvec, page_off_lru(page));
> }
>
Same here. You are just moving the flag clearing, but you didn't
combine it with the test. It seems like if you are expecting this to
be treated as an atomic operation. It should be a relatively low cost
to do since you already should own the cacheline as a result of
calling put_page_testzero so I am not sure why you are not combining
the two.
> diff --git a/mm/vmscan.c b/mm/vmscan.c
> index c1c4259b4de5..18986fefd49b 100644
> --- a/mm/vmscan.c
> +++ b/mm/vmscan.c
> @@ -1548,16 +1548,16 @@ int __isolate_lru_page(struct page *page, isolate_mode_t mode)
> {
> int ret = -EINVAL;
>
> - /* Only take pages on the LRU. */
> - if (!PageLRU(page))
> - return ret;
> -
> /* Compaction should not handle unevictable pages but CMA can do so */
> if (PageUnevictable(page) && !(mode & ISOLATE_UNEVICTABLE))
> return ret;
>
> ret = -EBUSY;
>
> + /* Only take pages on the LRU. */
> + if (!PageLRU(page))
> + return ret;
> +
> /*
> * To minimise LRU disruption, the caller can indicate that it only
> * wants to isolate pages it will be able to operate on without
> @@ -1671,8 +1671,6 @@ static unsigned long isolate_lru_pages(unsigned long nr_to_scan,
> page = lru_to_page(src);
> prefetchw_prev_lru_page(page, src, flags);
>
> - VM_BUG_ON_PAGE(!PageLRU(page), page);
> -
> nr_pages = compound_nr(page);
> total_scan += nr_pages;
>
So effectively the changes here are making it so that a !PageLRU page
will cycle to the start of the LRU list. Now if I understand correctly
we are guaranteed that if the flag is not set it cannot be set while
we are holding the lru_lock, however it can be cleared while we are
holding the lock, correct? Thus that is why isolate_lru_pages has to
call TestClearPageLRU after the earlier check in __isolate_lru_page.
It might make it more readable to pull in the later patch that
modifies isolate_lru_pages that has it using TestClearPageLRU.
> @@ -1769,21 +1767,19 @@ int isolate_lru_page(struct page *page)
> VM_BUG_ON_PAGE(!page_count(page), page);
> WARN_RATELIMIT(PageTail(page), "trying to isolate tail page");
>
> - if (PageLRU(page)) {
> + if (TestClearPageLRU(page)) {
> pg_data_t *pgdat = page_pgdat(page);
> struct lruvec *lruvec;
> + int lru = page_lru(page);
>
> - spin_lock_irq(&pgdat->lru_lock);
> + get_page(page);
> lruvec = mem_cgroup_page_lruvec(page, pgdat);
> - if (PageLRU(page)) {
> - int lru = page_lru(page);
> - get_page(page);
> - ClearPageLRU(page);
> - del_page_from_lru_list(page, lruvec, lru);
> - ret = 0;
> - }
> + spin_lock_irq(&pgdat->lru_lock);
> + del_page_from_lru_list(page, lruvec, lru);
> spin_unlock_irq(&pgdat->lru_lock);
> + ret = 0;
> }
> +
> return ret;
> }
>
> --
> 1.8.3.1
>
>
^ permalink raw reply
* Re: [PATCH v3 03/12] powerpc/kexec_file: add helper functions for getting memory ranges
From: Hari Bathini @ 2020-07-16 21:08 UTC (permalink / raw)
To: Thiago Jung Bauermann
Cc: Pingfan Liu, Petr Tesarik, Nayna Jain, Kexec-ml,
Mahesh J Salgaonkar, Mimi Zohar, lkml, linuxppc-dev, Sourabh Jain,
Andrew Morton, Dave Young, Vivek Goyal, Eric Biederman
In-Reply-To: <874kq98xo4.fsf@morokweng.localdomain>
On 15/07/20 5:19 am, Thiago Jung Bauermann wrote:
>
<snip>
> <snip>
>
>> +/**
>> + * get_mem_rngs_size - Get the allocated size of mrngs based on
>> + * max_nr_ranges and chunk size.
>> + * @mrngs: Memory ranges.
>> + *
>> + * Returns the maximum no. of ranges.
>
> This isn't correct. It returns the maximum size of @mrngs.
True. Will update..
> <snip>
>
>> +/**
>> + * add_tce_mem_ranges - Adds tce-table range to the given memory ranges list.
>> + * @mem_ranges: Range list to add the memory range(s) to.
>> + *
>> + * Returns 0 on success, negative errno on error.
>> + */
>> +int add_tce_mem_ranges(struct crash_mem **mem_ranges)
>> +{
>> + struct device_node *dn;
>> + int ret;
>> +
>> + for_each_node_by_type(dn, "pci") {
>> + u64 base;
>> + u32 size;
>> +
>> + ret = of_property_read_u64(dn, "linux,tce-base", &base);
>> + ret |= of_property_read_u32(dn, "linux,tce-size", &size);
>> + if (!ret)
>
> Shouldn't the condition be `ret` instead of `!ret`?
Oops! Will fix it.
>> +/**
>> + * sort_memory_ranges - Sorts the given memory ranges list.
>> + * @mem_ranges: Range list to sort.
>> + * @merge: If true, merge the list after sorting.
>> + *
>> + * Returns nothing.
>> + */
>> +void sort_memory_ranges(struct crash_mem *mrngs, bool merge)
>> +{
>> + struct crash_mem_range *rngs;
>> + struct crash_mem_range rng;
>> + int i, j, idx;
>> +
>> + if (!mrngs)
>> + return;
>> +
>> + /* Sort the ranges in-place */
>> + rngs = &mrngs->ranges[0];
>> + for (i = 0; i < mrngs->nr_ranges; i++) {
>> + idx = i;
>> + for (j = (i + 1); j < mrngs->nr_ranges; j++) {
>> + if (rngs[idx].start > rngs[j].start)
>> + idx = j;
>> + }
>> + if (idx != i) {
>> + rng = rngs[idx];
>> + rngs[idx] = rngs[i];
>> + rngs[i] = rng;
>> + }
>> + }
>
> Would it work using sort() from lib/sort.c here?
Yeah. I think we could reuse it with a simple compare callback. Will do that.
Thanks
Hari
^ permalink raw reply
* Re: [PATCH v16 13/22] mm/lru: introduce TestClearPageLRU
From: Alexander Duyck @ 2020-07-16 21:12 UTC (permalink / raw)
To: Alex Shi
Cc: Andrew Morton, Mel Gorman, Tejun Heo, Hugh Dickins,
Konstantin Khlebnikov, Daniel Jordan, Yang Shi, Matthew Wilcox,
Johannes Weiner, kbuild test robot, linux-mm, LKML,
cgroups-u79uwXL29TY76Z2rM5mHXA, Shakeel Butt, Joonsoo Kim,
Wei Yang, Kirill A. Shutemov, Michal Hocko, Vladimir Davydov
In-Reply-To: <1594429136-20002-14-git-send-email-alex.shi-KPsoFbNs7GizrGE5bRqYAgC/G2K4zDHf@public.gmane.org>
On Fri, Jul 10, 2020 at 5:59 PM Alex Shi <alex.shi-KPsoFbNs7GizrGE5bRqYAgC/G2K4zDHf@public.gmane.org> wrote:
>
> Combine PageLRU check and ClearPageLRU into a function by new
> introduced func TestClearPageLRU. This function will be used as page
> isolation precondition to prevent other isolations some where else.
> Then there are may non PageLRU page on lru list, need to remove BUG
> checking accordingly.
>
> Hugh Dickins pointed that __page_cache_release and release_pages
> has no need to do atomic clear bit since no user on the page at that
> moment. and no need get_page() before lru bit clear in isolate_lru_page,
> since it '(1) Must be called with an elevated refcount on the page'.
>
> As Andrew Morton mentioned this change would dirty cacheline for page
> isn't on LRU. But the lost would be acceptable with Rong Chen
> <rong.a.chen-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org> report:
> https://lkml.org/lkml/2020/3/4/173
>
> Suggested-by: Johannes Weiner <hannes-druUgvl0LCNAfugRpC6u6w@public.gmane.org>
> Signed-off-by: Alex Shi <alex.shi-KPsoFbNs7GizrGE5bRqYAgC/G2K4zDHf@public.gmane.org>
> Cc: Hugh Dickins <hughd-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
> Cc: Johannes Weiner <hannes-druUgvl0LCNAfugRpC6u6w@public.gmane.org>
> Cc: Michal Hocko <mhocko-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> Cc: Vladimir Davydov <vdavydov.dev-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> Cc: Andrew Morton <akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b@public.gmane.org>
> Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> Cc: cgroups-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> Cc: linux-mm-Bw31MaZKKs3YtjvyW6yDsg@public.gmane.org
> ---
> include/linux/page-flags.h | 1 +
> mm/mlock.c | 3 +--
> mm/swap.c | 6 ++----
> mm/vmscan.c | 26 +++++++++++---------------
> 4 files changed, 15 insertions(+), 21 deletions(-)
>
> diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
> index 6be1aa559b1e..9554ed1387dc 100644
> --- a/include/linux/page-flags.h
> +++ b/include/linux/page-flags.h
> @@ -326,6 +326,7 @@ static inline void page_init_poison(struct page *page, size_t size)
> PAGEFLAG(Dirty, dirty, PF_HEAD) TESTSCFLAG(Dirty, dirty, PF_HEAD)
> __CLEARPAGEFLAG(Dirty, dirty, PF_HEAD)
> PAGEFLAG(LRU, lru, PF_HEAD) __CLEARPAGEFLAG(LRU, lru, PF_HEAD)
> + TESTCLEARFLAG(LRU, lru, PF_HEAD)
> PAGEFLAG(Active, active, PF_HEAD) __CLEARPAGEFLAG(Active, active, PF_HEAD)
> TESTCLEARFLAG(Active, active, PF_HEAD)
> PAGEFLAG(Workingset, workingset, PF_HEAD)
> diff --git a/mm/mlock.c b/mm/mlock.c
> index f8736136fad7..228ba5a8e0a5 100644
> --- a/mm/mlock.c
> +++ b/mm/mlock.c
> @@ -108,13 +108,12 @@ void mlock_vma_page(struct page *page)
> */
> static bool __munlock_isolate_lru_page(struct page *page, bool getpage)
> {
> - if (PageLRU(page)) {
> + if (TestClearPageLRU(page)) {
> struct lruvec *lruvec;
>
> lruvec = mem_cgroup_page_lruvec(page, page_pgdat(page));
> if (getpage)
> get_page(page);
> - ClearPageLRU(page);
> del_page_from_lru_list(page, lruvec, page_lru(page));
> return true;
> }
> diff --git a/mm/swap.c b/mm/swap.c
> index f645965fde0e..5092fe9c8c47 100644
> --- a/mm/swap.c
> +++ b/mm/swap.c
> @@ -83,10 +83,9 @@ static void __page_cache_release(struct page *page)
> struct lruvec *lruvec;
> unsigned long flags;
>
> + __ClearPageLRU(page);
> spin_lock_irqsave(&pgdat->lru_lock, flags);
> lruvec = mem_cgroup_page_lruvec(page, pgdat);
> - VM_BUG_ON_PAGE(!PageLRU(page), page);
> - __ClearPageLRU(page);
> del_page_from_lru_list(page, lruvec, page_off_lru(page));
> spin_unlock_irqrestore(&pgdat->lru_lock, flags);
> }
So this piece doesn't make much sense to me. Why not use
TestClearPageLRU(page) here? Just a few lines above you are testing
for PageLRU(page) and it seems like if you are going to go for an
atomic test/clear and then remove the page from the LRU list you
should be using it here as well otherwise it seems like you could run
into a potential collision since you are testing here without clearing
the bit.
> @@ -878,9 +877,8 @@ void release_pages(struct page **pages, int nr)
> spin_lock_irqsave(&locked_pgdat->lru_lock, flags);
> }
>
> - lruvec = mem_cgroup_page_lruvec(page, locked_pgdat);
> - VM_BUG_ON_PAGE(!PageLRU(page), page);
> __ClearPageLRU(page);
> + lruvec = mem_cgroup_page_lruvec(page, locked_pgdat);
> del_page_from_lru_list(page, lruvec, page_off_lru(page));
> }
>
Same here. You are just moving the flag clearing, but you didn't
combine it with the test. It seems like if you are expecting this to
be treated as an atomic operation. It should be a relatively low cost
to do since you already should own the cacheline as a result of
calling put_page_testzero so I am not sure why you are not combining
the two.
> diff --git a/mm/vmscan.c b/mm/vmscan.c
> index c1c4259b4de5..18986fefd49b 100644
> --- a/mm/vmscan.c
> +++ b/mm/vmscan.c
> @@ -1548,16 +1548,16 @@ int __isolate_lru_page(struct page *page, isolate_mode_t mode)
> {
> int ret = -EINVAL;
>
> - /* Only take pages on the LRU. */
> - if (!PageLRU(page))
> - return ret;
> -
> /* Compaction should not handle unevictable pages but CMA can do so */
> if (PageUnevictable(page) && !(mode & ISOLATE_UNEVICTABLE))
> return ret;
>
> ret = -EBUSY;
>
> + /* Only take pages on the LRU. */
> + if (!PageLRU(page))
> + return ret;
> +
> /*
> * To minimise LRU disruption, the caller can indicate that it only
> * wants to isolate pages it will be able to operate on without
> @@ -1671,8 +1671,6 @@ static unsigned long isolate_lru_pages(unsigned long nr_to_scan,
> page = lru_to_page(src);
> prefetchw_prev_lru_page(page, src, flags);
>
> - VM_BUG_ON_PAGE(!PageLRU(page), page);
> -
> nr_pages = compound_nr(page);
> total_scan += nr_pages;
>
So effectively the changes here are making it so that a !PageLRU page
will cycle to the start of the LRU list. Now if I understand correctly
we are guaranteed that if the flag is not set it cannot be set while
we are holding the lru_lock, however it can be cleared while we are
holding the lock, correct? Thus that is why isolate_lru_pages has to
call TestClearPageLRU after the earlier check in __isolate_lru_page.
It might make it more readable to pull in the later patch that
modifies isolate_lru_pages that has it using TestClearPageLRU.
> @@ -1769,21 +1767,19 @@ int isolate_lru_page(struct page *page)
> VM_BUG_ON_PAGE(!page_count(page), page);
> WARN_RATELIMIT(PageTail(page), "trying to isolate tail page");
>
> - if (PageLRU(page)) {
> + if (TestClearPageLRU(page)) {
> pg_data_t *pgdat = page_pgdat(page);
> struct lruvec *lruvec;
> + int lru = page_lru(page);
>
> - spin_lock_irq(&pgdat->lru_lock);
> + get_page(page);
> lruvec = mem_cgroup_page_lruvec(page, pgdat);
> - if (PageLRU(page)) {
> - int lru = page_lru(page);
> - get_page(page);
> - ClearPageLRU(page);
> - del_page_from_lru_list(page, lruvec, lru);
> - ret = 0;
> - }
> + spin_lock_irq(&pgdat->lru_lock);
> + del_page_from_lru_list(page, lruvec, lru);
> spin_unlock_irq(&pgdat->lru_lock);
> + ret = 0;
> }
> +
> return ret;
> }
>
> --
> 1.8.3.1
>
>
^ permalink raw reply
* hw-display-qxl.so: undefined symbol: qemu_qxl_io_log_semaphore
From: Cole Robinson @ 2020-07-16 21:10 UTC (permalink / raw)
To: qemu-devel, Gerd Hoffmann
Hi Gerd,
I'm trying to build qemu 5.1.0-rc0 in Fedora. I'm hitting some issues.
Using this configure line:
./configure --prefix=/usr --libdir=/usr/lib64 --sysconfdir=/etc
--localstatedir=/var --libexecdir=/usr/libexec
--interp-prefix=/usr/qemu-%M --with-pkgversion=qemu-5.1.0-0.1.rc0.fc33
'--extra-ldflags=-Wl,--build-id -Wl,-z,relro -Wl,-z,now'
'--extra-cflags=-O2 -g -pipe -Wall -Werror=format-security
-Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fexceptions
-fstack-protector-strong -grecord-gcc-switches
-specs=/usr/lib/rpm/redhat/redhat-hardened-cc1
-specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -mtune=generic
-fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection'
--enable-trace-backend=dtrace --audio-drv-list=pa,sdl,alsa,oss
--enable-kvm --target-list=x86_64-softmmu --enable-pie --enable-modules
--enable-spice
Build and then run:
$ ./x86_64-softmmu/qemu-system-x86_64 -device \? | grep qxl
Failed to open module:
/home/crobinso/src/qemu/x86_64-softmmu/../hw-display-qxl.so: undefined
symbol: qemu_qxl_io_log_semaphore
That error breaks iotests 127:
--- /home/crobinso/src/qemu/tests/qemu-iotests/127.out 2020-07-15
04:00:10.589138586 -0400
+++ /home/crobinso/src/qemu/tests/qemu-iotests/127.out.bad 2020-07-16
16:44:37.717248172 -0400
@@ -1,4 +1,5 @@
QA output created by 127
+Failed to open module:
/home/crobinso/src/qemu/x86_64-softmmu/../hw-display-qxl.so: undefined
symbol: qemu_qxl_io_log_semaphore
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=65536
Formatting 'TEST_DIR/t.IMGFMT.overlay0', fmt=IMGFMT size=65536
backing_file=TEST_DIR/t.IMGFMT backing_fmt=IMGFMT
Formatting 'TEST_DIR/t.IMGFMT.overlay1', fmt=IMGFMT size=65536
backing_file=TEST_DIR/t.IMGFMT backing_fmt=IMGFMT
Doing a build with every target and running 'make check' will show
undefined symbol errors for other targets with hw-display-qxl too. Most
reference the qxl_io_log call but some are like:
Failed to open module:
/home/crobinso/src/qemu/microblaze-softmmu/../hw-display-qxl.so:
undefined symbol: vga_ioport_read
Also as a side note though I think it's pre-existing: running the test
suite with --enable-modules while there are host installed modules is
very noisy with lots of repetitive warnings like:
Failed to initialize module: /usr/lib64/qemu/audio-oss.so
Note: only modules from the same build can be loaded.
Failed to initialize module: /usr/lib64/qemu/audio-pa.so
Note: only modules from the same build can be loaded.
Failed to initialize module: /usr/lib64/qemu/audio-sdl.so
Note: only modules from the same build can be loaded.
Failed to initialize module: /usr/lib64/qemu/ui-curses.so
Note: only modules from the same build can be loaded.
Failed to initialize module: /usr/lib64/qemu/ui-gtk.so
Note: only modules from the same build can be loaded.
It would be nice if those could be avoided somehow. Maybe
QEMU_MODULE_DIR can help?
Thanks,
Cole
^ permalink raw reply
* Re: [PATCH v3 10/12] ppc64/kexec_file: prepare elfcore header for crashing kernel
From: Hari Bathini @ 2020-07-16 21:07 UTC (permalink / raw)
To: Thiago Jung Bauermann
Cc: Pingfan Liu, Petr Tesarik, Nayna Jain, Kexec-ml,
Mahesh J Salgaonkar, Mimi Zohar, lkml, linuxppc-dev, Sourabh Jain,
Andrew Morton, Dave Young, Vivek Goyal, Eric Biederman
In-Reply-To: <87tuy88ai7.fsf@morokweng.localdomain>
On 16/07/20 7:52 am, Thiago Jung Bauermann wrote:
>
> Hari Bathini <hbathini@linux.ibm.com> writes:
>
>> /**
>> + * get_crash_memory_ranges - Get crash memory ranges. This list includes
>> + * first/crashing kernel's memory regions that
>> + * would be exported via an elfcore.
>> + * @mem_ranges: Range list to add the memory ranges to.
>> + *
>> + * Returns 0 on success, negative errno on error.
>> + */
>> +static int get_crash_memory_ranges(struct crash_mem **mem_ranges)
>> +{
>> + struct memblock_region *reg;
>> + struct crash_mem *tmem;
>> + int ret;
>> +
>> + for_each_memblock(memory, reg) {
>> + u64 base, size;
>> +
>> + base = (u64)reg->base;
>> + size = (u64)reg->size;
>> +
>> + /* Skip backup memory region, which needs a separate entry */
>> + if (base == BACKUP_SRC_START) {
>> + if (size > BACKUP_SRC_SIZE) {
>> + base = BACKUP_SRC_END + 1;
>> + size -= BACKUP_SRC_SIZE;
>> + } else
>> + continue;
>> + }
>> +
>> + ret = add_mem_range(mem_ranges, base, size);
>> + if (ret)
>> + goto out;
>> +
>> + /* Try merging adjacent ranges before reallocation attempt */
>> + if ((*mem_ranges)->nr_ranges == (*mem_ranges)->max_nr_ranges)
>> + sort_memory_ranges(*mem_ranges, true);
>> + }
>> +
>> + /* Reallocate memory ranges if there is no space to split ranges */
>> + tmem = *mem_ranges;
>> + if (tmem && (tmem->nr_ranges == tmem->max_nr_ranges)) {
>> + tmem = realloc_mem_ranges(mem_ranges);
>> + if (!tmem)
>> + goto out;
>> + }
>> +
>> + /* Exclude crashkernel region */
>> + ret = crash_exclude_mem_range(tmem, crashk_res.start, crashk_res.end);
>> + if (ret)
>> + goto out;
>> +
>> + ret = add_rtas_mem_range(mem_ranges);
>> + if (ret)
>> + goto out;
>> +
>> + ret = add_opal_mem_range(mem_ranges);
>> + if (ret)
>> + goto out;
>
> Maybe I'm confused, but don't you add the RTAS and OPAL regions as
> usable memory for the crashkernel? In that case they shouldn't show up
> in the core file.
kexec-tools does the same thing. I am not endorsing it but I was trying to stay
in parity to avoid breaking any userspace tools/commands. But as you rightly
pointed, this is NOT right. The right thing to do, to get the rtas/opal data at
the time of crash, is to have a backup region for them just like we have for
the first 64K memory. I was hoping to do that later.
Will check how userspace tools respond to dropping these regions. If that makes
the tools unhappy, will retain the regions with a FIXME. Sorry about the confusion.
Thanks
Hari
^ permalink raw reply
* Re: [PATCH v3 09/12] ppc64/kexec_file: setup backup region for kdump kernel
From: Hari Bathini @ 2020-07-16 21:10 UTC (permalink / raw)
To: Thiago Jung Bauermann
Cc: kernel test robot, Pingfan Liu, Nayna Jain, Kexec-ml,
Mahesh J Salgaonkar, Mimi Zohar, lkml, linuxppc-dev, Sourabh Jain,
Petr Tesarik, Andrew Morton, Dave Young, Vivek Goyal,
Eric Biederman
In-Reply-To: <87y2nk8cjq.fsf@morokweng.localdomain>
On 16/07/20 7:08 am, Thiago Jung Bauermann wrote:
>
> Hari Bathini <hbathini@linux.ibm.com> writes:
>
>> @@ -968,7 +1040,7 @@ int setup_new_fdt_ppc64(const struct kimage *image, void *fdt,
>>
>> /*
>> * Restrict memory usage for kdump kernel by setting up
>> - * usable memory ranges.
>> + * usable memory ranges and memory reserve map.
>> */
>> if (image->type == KEXEC_TYPE_CRASH) {
>> ret = get_usable_memory_ranges(&umem);
>> @@ -980,6 +1052,24 @@ int setup_new_fdt_ppc64(const struct kimage *image, void *fdt,
>> pr_err("Error setting up usable-memory property for kdump kernel\n");
>> goto out;
>> }
>> +
>> + ret = fdt_add_mem_rsv(fdt, BACKUP_SRC_START + BACKUP_SRC_SIZE,
>> + crashk_res.start - BACKUP_SRC_SIZE);
>
> I believe this answers my question from the other email about how the
> crashkernel is prevented from stomping in the crashed kernel's memory,
> right? I needed to think for a bit to understand what the above
> reservation was protecting. I think it's worth adding a comment.
Right. The reason to add it in the first place is, prom presses the panic button if
it can't find low memory. Marking it reserved seems to keep it quiet though. so..
Will add comment mentioning that..
>> +void purgatory(void)
>> +{
>> + void *dest, *src;
>> +
>> + src = (void *)BACKUP_SRC_START;
>> + if (backup_start) {
>> + dest = (void *)backup_start;
>> + __memcpy(dest, src, BACKUP_SRC_SIZE);
>> + }
>> +}
>
> In general I'm in favor of using C code over assembly, but having to
> bring in that relocation support just for the above makes me wonder if
> it's worth it in this case.
I am planning to build on purgatory later with "I'm in purgatory" print support
for pseries at least and also, sha256 digest check.
Thanks
Hari
^ permalink raw reply
* [Buildroot] [git commit] package/lm-sensors: always pass TARGET_CONFIGURE_OPTS
From: Thomas Petazzoni @ 2020-07-16 21:10 UTC (permalink / raw)
To: buildroot
commit: https://git.buildroot.net/buildroot/commit/?id=654ade68a69805647f97e3fa456f31e623e72c15
branch: https://git.buildroot.net/buildroot/commit/?id=refs/heads/master
lm-sensors dropped MACHINE variable since version 3.6.0 and
https://github.com/lm-sensors/lm-sensors/commit/0863eff8fa1d32797e3aec19672878aff893b0ae
instead it uses $(CC) -dumpmachine to guess the architecture
However, as $(TARGET_CONFIGURE_OPTS) is only passed to build step and
not to install steps, this result in some binaries being built for the
host during install step and raising a build failure on some autobuilders
Fixes:
- http://autobuild.buildroot.org/results/0180989afdd9272ecd5010a787931e0b10a6cdcf
Signed-off-by: Fabrice Fontaine <fontaine.fabrice@gmail.com>
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
---
package/lm-sensors/lm-sensors.mk | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/package/lm-sensors/lm-sensors.mk b/package/lm-sensors/lm-sensors.mk
index a69ca6e2bf..8975efaffa 100644
--- a/package/lm-sensors/lm-sensors.mk
+++ b/package/lm-sensors/lm-sensors.mk
@@ -20,7 +20,7 @@ LM_SENSORS_BINS_$(BR2_PACKAGE_LM_SENSORS_PWMCONFIG) += sbin/pwmconfig
LM_SENSORS_BINS_$(BR2_PACKAGE_LM_SENSORS_SENSORS_DETECT) += sbin/sensors-detect
LM_SENSORS_MAKE_OPTS = \
- MACHINE=$(KERNEL_ARCH) \
+ $(TARGET_CONFIGURE_OPTS) \
PREFIX=/usr
ifeq ($(BR2_STATIC_LIBS),y)
@@ -36,7 +36,7 @@ LM_SENSORS_MAKE_OPTS += BUILD_STATIC_LIB=1
endif
define LM_SENSORS_BUILD_CMDS
- $(TARGET_MAKE_ENV) $(MAKE) $(TARGET_CONFIGURE_OPTS) $(LM_SENSORS_MAKE_OPTS) -C $(@D)
+ $(TARGET_MAKE_ENV) $(MAKE) $(LM_SENSORS_MAKE_OPTS) -C $(@D)
endef
define LM_SENSORS_INSTALL_STAGING_CMDS
^ permalink raw reply related
* Re: [PATCH v3 06/12] ppc64/kexec_file: restrict memory usage of kdump kernel
From: Hari Bathini @ 2020-07-16 21:10 UTC (permalink / raw)
To: Thiago Jung Bauermann
Cc: Pingfan Liu, Nayna Jain, Kexec-ml, Mahesh J Salgaonkar,
Mimi Zohar, lkml, linuxppc-dev, Sourabh Jain, Petr Tesarik,
Andrew Morton, Dave Young, Vivek Goyal, Eric Biederman
In-Reply-To: <87365s9ysj.fsf@morokweng.localdomain>
On 16/07/20 4:22 am, Thiago Jung Bauermann wrote:
>
> Hari Bathini <hbathini@linux.ibm.com> writes:
>
<snip>
>> +/**
>> + * get_node_path - Get the full path of the given node.
>> + * @dn: Node.
>> + * @path: Updated with the full path of the node.
>> + *
>> + * Returns nothing.
>> + */
>> +static void get_node_path(struct device_node *dn, char *path)
>> +{
>> + if (!dn)
>> + return;
>> +
>> + get_node_path(dn->parent, path);
>
> Is it ok to do recursion in the kernel? In this case I believe it's not
> problematic since the maximum call depth will be the maximum depth of a
> device tree node which shouldn't be too much. Also, there are no local
> variables in this function. But I thought it was worth mentioning.
You are right. We are better off avoiding the recursion here. Will
change it to an iterative version instead.
>> + * each representing a memory range.
>> + */
>> + ranges = (len >> 2) / (n_mem_addr_cells + n_mem_size_cells);
>> +
>> + for (i = 0; i < ranges; i++) {
>> + base = of_read_number(prop, n_mem_addr_cells);
>> + prop += n_mem_addr_cells;
>> + end = base + of_read_number(prop, n_mem_size_cells) - 1;
prop is not used after the above.
> You need to `prop += n_mem_size_cells` here.
But yeah, adding it would make it look complete in some sense..
Thanks
Hari
^ permalink raw reply
* [Intel-gfx] [PATCH v7 06/11] drm/i915: Enable big joiner support in enable and disable sequences.
From: Manasi Navare @ 2020-07-16 21:12 UTC (permalink / raw)
To: intel-gfx
In-Reply-To: <20200715224222.7557-6-manasi.d.navare@intel.com>
From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Make vdsc work when no output is enabled. The big joiner needs VDSC
on the slave, so enable it and set the appropriate bits.
Also update timestamping constants, because slave crtc's are not
updated in drm_atomic_helper_update_legacy_modeset_state().
This should be enough to bring up CRTC's in a big joiner configuration,
without any plane configuration on the second pipe yet.
HOWEVER, we still bring up the crtc's in the wrong order. We need to
make sure that the master crtc is brought up after the slave crtc.
This is done correctly later in this series.
The next steps are to enable planes correctly, and make sure we enable
and update both master and slave in the correct order.
v2:
* Manual rebase (Manasi)
v3:
* Rebase (Manasi)
v4:
* Rebase (Manasi)
v5:
* Get dsc power domain in ddi_init (Manasi)
Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
---
drivers/gpu/drm/i915/display/icl_dsi.c | 2 -
drivers/gpu/drm/i915/display/intel_ddi.c | 65 ++-
drivers/gpu/drm/i915/display/intel_display.c | 377 ++++++++++++------
.../drm/i915/display/intel_display_types.h | 1 +
drivers/gpu/drm/i915/display/intel_dp.c | 6 +-
drivers/gpu/drm/i915/display/intel_vdsc.c | 199 ++++-----
drivers/gpu/drm/i915/display/intel_vdsc.h | 7 +-
7 files changed, 416 insertions(+), 241 deletions(-)
diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c
index 8c55f5bee9ab..26f7372b4c25 100644
--- a/drivers/gpu/drm/i915/display/icl_dsi.c
+++ b/drivers/gpu/drm/i915/display/icl_dsi.c
@@ -1454,8 +1454,6 @@ static void gen11_dsi_get_config(struct intel_encoder *encoder,
struct intel_crtc *crtc = to_intel_crtc(pipe_config->uapi.crtc);
struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
- intel_dsc_get_config(encoder, pipe_config);
-
/* FIXME: adapt icl_ddi_clock_get() for DSI and use that? */
pipe_config->port_clock = intel_dpll_get_freq(i915,
pipe_config->shared_dpll);
diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c
index c52ad5ecb645..3e32412eaaac 100644
--- a/drivers/gpu/drm/i915/display/intel_ddi.c
+++ b/drivers/gpu/drm/i915/display/intel_ddi.c
@@ -28,6 +28,7 @@
#include <drm/drm_scdc_helper.h>
#include "i915_drv.h"
+#include "i915_trace.h"
#include "intel_audio.h"
#include "intel_combo_phy.h"
#include "intel_connector.h"
@@ -2075,11 +2076,12 @@ static void intel_ddi_get_power_domains(struct intel_encoder *encoder,
intel_ddi_main_link_aux_domain(dig_port));
/*
- * VDSC power is needed when DSC is enabled
+ * VDSC power well needed when DSC enabled
*/
if (crtc_state->dsc.compression_enable)
intel_display_power_get(dev_priv,
intel_dsc_power_domain(crtc_state));
+
}
void intel_ddi_enable_pipe_clock(struct intel_encoder *encoder,
@@ -3356,7 +3358,8 @@ static void tgl_ddi_pre_enable_dp(struct intel_atomic_state *state,
/* 7.l Configure and enable FEC if needed */
intel_ddi_enable_fec(encoder, crtc_state);
- intel_dsc_enable(encoder, crtc_state);
+ if (!crtc_state->bigjoiner)
+ intel_dsc_enable(encoder, crtc_state);
}
static void hsw_ddi_pre_enable_dp(struct intel_atomic_state *state,
@@ -3427,7 +3430,8 @@ static void hsw_ddi_pre_enable_dp(struct intel_atomic_state *state,
if (!is_mst)
intel_ddi_enable_pipe_clock(encoder, crtc_state);
- intel_dsc_enable(encoder, crtc_state);
+ if (!crtc_state->bigjoiner)
+ intel_dsc_enable(encoder, crtc_state);
}
static void intel_ddi_pre_enable_dp(struct intel_atomic_state *state,
@@ -3682,6 +3686,21 @@ static void intel_ddi_post_disable(struct intel_atomic_state *state,
ilk_pfit_disable(old_crtc_state);
}
+ if (old_crtc_state->bigjoiner_linked_crtc) {
+ struct intel_atomic_state *state =
+ to_intel_atomic_state(old_crtc_state->uapi.state);
+ struct intel_crtc *slave =
+ old_crtc_state->bigjoiner_linked_crtc;
+ const struct intel_crtc_state *old_slave_crtc_state =
+ intel_atomic_get_old_crtc_state(state, slave);
+
+ intel_crtc_vblank_off(old_slave_crtc_state);
+ trace_intel_pipe_disable(slave);
+
+ intel_dsc_disable(old_slave_crtc_state);
+ skl_scaler_disable(old_slave_crtc_state);
+ }
+
/*
* When called from DP MST code:
* - old_conn_state will be NULL
@@ -3896,7 +3915,8 @@ static void intel_enable_ddi(struct intel_atomic_state *state,
{
drm_WARN_ON(state->base.dev, crtc_state->has_pch_encoder);
- intel_ddi_enable_transcoder_func(encoder, crtc_state);
+ if (!crtc_state->bigjoiner_slave)
+ intel_ddi_enable_transcoder_func(encoder, crtc_state);
intel_enable_pipe(crtc_state);
@@ -4243,8 +4263,8 @@ static void bdw_get_trans_port_sync_config(struct intel_crtc_state *crtc_state)
crtc_state->sync_mode_slaves_mask);
}
-void intel_ddi_get_config(struct intel_encoder *encoder,
- struct intel_crtc_state *pipe_config)
+static void intel_ddi_read_func_ctl(struct intel_encoder *encoder,
+ struct intel_crtc_state *pipe_config)
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->uapi.crtc);
@@ -4252,13 +4272,10 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
u32 temp, flags = 0;
- /* XXX: DSI transcoder paranoia */
- if (drm_WARN_ON(&dev_priv->drm, transcoder_is_dsi(cpu_transcoder)))
+ temp = intel_de_read(dev_priv, TRANS_DDI_FUNC_CTL(cpu_transcoder));
+ if (!(temp & TRANS_DDI_FUNC_ENABLE))
return;
- intel_dsc_get_config(encoder, pipe_config);
-
- temp = intel_de_read(dev_priv, TRANS_DDI_FUNC_CTL(cpu_transcoder));
if (temp & TRANS_DDI_PHSYNC)
flags |= DRM_MODE_FLAG_PHSYNC;
else
@@ -4366,6 +4383,29 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
intel_dp->regs.dp_tp_ctl = TGL_DP_TP_CTL(transcoder);
intel_dp->regs.dp_tp_status = TGL_DP_TP_STATUS(transcoder);
}
+}
+
+void intel_ddi_get_config(struct intel_encoder *encoder,
+ struct intel_crtc_state *pipe_config)
+{
+ struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+ enum transcoder cpu_transcoder = pipe_config->cpu_transcoder;
+
+ /* XXX: DSI transcoder paranoia */
+ if (WARN_ON(transcoder_is_dsi(cpu_transcoder)))
+ return;
+
+ intel_ddi_read_func_ctl(encoder, pipe_config);
+ if (pipe_config->bigjoiner_slave) {
+ /* read out pipe settings from master */
+ enum transcoder save = pipe_config->cpu_transcoder;
+
+ /* Our own transcoder needs to be disabled when reading it in intel_ddi_read_func_ctl() */
+ WARN_ON(pipe_config->output_types);
+ pipe_config->cpu_transcoder = (enum transcoder)pipe_config->bigjoiner_linked_crtc->pipe;
+ intel_ddi_read_func_ctl(encoder, pipe_config);
+ pipe_config->cpu_transcoder = save;
+ }
pipe_config->has_audio =
intel_ddi_is_audio_enabled(dev_priv, cpu_transcoder);
@@ -4391,7 +4431,8 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
dev_priv->vbt.edp.bpp = pipe_config->pipe_bpp;
}
- intel_ddi_clock_get(encoder, pipe_config);
+ if (!pipe_config->bigjoiner_slave)
+ intel_ddi_clock_get(encoder, pipe_config);
if (IS_GEN9_LP(dev_priv))
pipe_config->lane_lat_optim_mask =
diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
index 955e19abb563..1cda8900d8f5 100644
--- a/drivers/gpu/drm/i915/display/intel_display.c
+++ b/drivers/gpu/drm/i915/display/intel_display.c
@@ -7023,6 +7023,45 @@ static void hsw_set_frame_start_delay(const struct intel_crtc_state *crtc_state)
intel_de_write(dev_priv, reg, val);
}
+static void tgl_ddi_bigjoiner_pre_enable(struct intel_atomic_state *state,
+ const struct intel_crtc_state *crtc_state)
+{
+ struct intel_crtc *master = to_intel_crtc(crtc_state->uapi.crtc);
+ struct intel_crtc_state *master_crtc_state;
+ struct drm_connector_state *conn_state;
+ struct drm_connector *conn;
+ struct intel_encoder *encoder = NULL;
+ int i;
+
+ if (crtc_state->bigjoiner_slave)
+ master = crtc_state->bigjoiner_linked_crtc;
+
+ master_crtc_state = intel_atomic_get_new_crtc_state(state, master);
+
+ for_each_new_connector_in_state(&state->base, conn, conn_state, i) {
+ if (conn_state->crtc != &master->base)
+ continue;
+
+ encoder = to_intel_encoder(conn_state->best_encoder);
+ break;
+ }
+
+ if (!crtc_state->bigjoiner_slave) {
+ /* need to enable VDSC, which we skipped in pre-enable */
+ intel_dsc_enable(encoder, crtc_state);
+ } else {
+ /*
+ * Enable sequence steps 1-7 on bigjoiner master
+ */
+ intel_encoders_pre_pll_enable(state, master);
+ intel_enable_shared_dpll(master_crtc_state);
+ intel_encoders_pre_enable(state, master);
+
+ /* and DSC on slave */
+ intel_dsc_enable(NULL, crtc_state);
+ }
+}
+
static void hsw_crtc_enable(struct intel_atomic_state *state,
struct intel_crtc *crtc)
{
@@ -7036,34 +7075,39 @@ static void hsw_crtc_enable(struct intel_atomic_state *state,
if (drm_WARN_ON(&dev_priv->drm, crtc->active))
return;
- intel_encoders_pre_pll_enable(state, crtc);
-
- if (new_crtc_state->shared_dpll)
- intel_enable_shared_dpll(new_crtc_state);
+ if (!new_crtc_state->bigjoiner) {
+ intel_encoders_pre_pll_enable(state, crtc);
- intel_encoders_pre_enable(state, crtc);
+ if (new_crtc_state->shared_dpll)
+ intel_enable_shared_dpll(new_crtc_state);
- if (!transcoder_is_dsi(cpu_transcoder))
- intel_set_transcoder_timings(new_crtc_state);
+ intel_encoders_pre_enable(state, crtc);
+ } else {
+ tgl_ddi_bigjoiner_pre_enable(state, new_crtc_state);
+ }
intel_set_pipe_src_size(new_crtc_state);
+ if (INTEL_GEN(dev_priv) >= 9 || IS_BROADWELL(dev_priv))
+ bdw_set_pipemisc(new_crtc_state);
- if (cpu_transcoder != TRANSCODER_EDP &&
- !transcoder_is_dsi(cpu_transcoder))
- intel_de_write(dev_priv, PIPE_MULT(cpu_transcoder),
- new_crtc_state->pixel_multiplier - 1);
+ if (!new_crtc_state->bigjoiner_slave && !transcoder_is_dsi(cpu_transcoder)) {
+ if (!transcoder_is_dsi(cpu_transcoder))
+ intel_set_transcoder_timings(new_crtc_state);
- if (new_crtc_state->has_pch_encoder)
- intel_cpu_transcoder_set_m_n(new_crtc_state,
- &new_crtc_state->fdi_m_n, NULL);
+ if (cpu_transcoder != TRANSCODER_EDP &&
+ !transcoder_is_dsi(cpu_transcoder))
+ intel_de_write(dev_priv, PIPE_MULT(cpu_transcoder),
+ new_crtc_state->pixel_multiplier - 1);
+
+ if (new_crtc_state->has_pch_encoder)
+ intel_cpu_transcoder_set_m_n(new_crtc_state,
+ &new_crtc_state->fdi_m_n, NULL);
- if (!transcoder_is_dsi(cpu_transcoder)) {
hsw_set_frame_start_delay(new_crtc_state);
- hsw_set_pipeconf(new_crtc_state);
}
- if (INTEL_GEN(dev_priv) >= 9 || IS_BROADWELL(dev_priv))
- bdw_set_pipemisc(new_crtc_state);
+ if (!transcoder_is_dsi(cpu_transcoder))
+ hsw_set_pipeconf(new_crtc_state);
crtc->active = true;
@@ -7099,6 +7143,11 @@ static void hsw_crtc_enable(struct intel_atomic_state *state,
if (INTEL_GEN(dev_priv) >= 11)
icl_pipe_mbus_enable(crtc);
+ if (new_crtc_state->bigjoiner_slave) {
+ trace_intel_pipe_enable(crtc);
+ intel_crtc_vblank_on(new_crtc_state);
+ }
+
intel_encoders_enable(state, crtc);
if (psl_clkgate_wa) {
@@ -7381,6 +7430,9 @@ static u64 get_crtc_power_domains(struct intel_crtc_state *crtc_state)
if (crtc_state->shared_dpll)
mask |= BIT_ULL(POWER_DOMAIN_DISPLAY_CORE);
+ if (crtc_state->dsc.compression_enable)
+ mask |= BIT_ULL(intel_dsc_power_domain(crtc_state));
+
return mask;
}
@@ -7999,6 +8051,30 @@ static u32 ilk_pipe_pixel_rate(const struct intel_crtc_state *crtc_state)
pfit_w * pfit_h);
}
+static void intel_encoder_get_config(struct intel_encoder *encoder,
+ struct intel_crtc_state *crtc_state)
+{
+ struct drm_display_mode *pipe_mode = &crtc_state->hw.pipe_mode;
+
+ encoder->get_config(encoder, crtc_state);
+
+ *pipe_mode = crtc_state->hw.adjusted_mode;
+ if (crtc_state->bigjoiner) {
+ /*
+ * transcoder is programmed to the full mode,
+ * but pipe timings are half of the transcoder mode
+ */
+ pipe_mode->crtc_hdisplay /= 2;
+ pipe_mode->crtc_hblank_start /= 2;
+ pipe_mode->crtc_hblank_end /= 2;
+ pipe_mode->crtc_hsync_start /= 2;
+ pipe_mode->crtc_hsync_end /= 2;
+ pipe_mode->crtc_htotal /= 2;
+ pipe_mode->crtc_hskew /= 2;
+ pipe_mode->crtc_clock /= 2;
+ }
+}
+
static void intel_crtc_compute_pixel_rate(struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
@@ -8910,20 +8986,22 @@ static void intel_get_pipe_src_size(struct intel_crtc *crtc,
void intel_mode_from_pipe_config(struct drm_display_mode *mode,
struct intel_crtc_state *pipe_config)
{
- mode->hdisplay = pipe_config->hw.adjusted_mode.crtc_hdisplay;
- mode->htotal = pipe_config->hw.adjusted_mode.crtc_htotal;
- mode->hsync_start = pipe_config->hw.adjusted_mode.crtc_hsync_start;
- mode->hsync_end = pipe_config->hw.adjusted_mode.crtc_hsync_end;
+ struct drm_display_mode *hw_mode = &pipe_config->hw.adjusted_mode;
- mode->vdisplay = pipe_config->hw.adjusted_mode.crtc_vdisplay;
- mode->vtotal = pipe_config->hw.adjusted_mode.crtc_vtotal;
- mode->vsync_start = pipe_config->hw.adjusted_mode.crtc_vsync_start;
- mode->vsync_end = pipe_config->hw.adjusted_mode.crtc_vsync_end;
+ mode->hdisplay = hw_mode->crtc_hdisplay;
+ mode->htotal = hw_mode->crtc_htotal;
+ mode->hsync_start = hw_mode->crtc_hsync_start;
+ mode->hsync_end = hw_mode->crtc_hsync_end;
- mode->flags = pipe_config->hw.adjusted_mode.flags;
+ mode->vdisplay = hw_mode->crtc_vdisplay;
+ mode->vtotal = hw_mode->crtc_vtotal;
+ mode->vsync_start = hw_mode->crtc_vsync_start;
+ mode->vsync_end = hw_mode->crtc_vsync_end;
+
+ mode->flags = hw_mode->flags;
mode->type = DRM_MODE_TYPE_DRIVER;
- mode->clock = pipe_config->hw.adjusted_mode.crtc_clock;
+ mode->clock = hw_mode->crtc_clock;
drm_mode_set_name(mode);
}
@@ -11081,6 +11159,9 @@ static void hsw_get_ddi_port_state(struct intel_crtc *crtc,
} else {
tmp = intel_de_read(dev_priv,
TRANS_DDI_FUNC_CTL(cpu_transcoder));
+ if (!(tmp & TRANS_DDI_FUNC_ENABLE))
+ return;
+
if (INTEL_GEN(dev_priv) >= 12)
port = TGL_TRANS_DDI_FUNC_CTL_VAL_TO_PORT(tmp);
else
@@ -11153,12 +11234,20 @@ static bool hsw_get_pipe_config(struct intel_crtc *crtc,
drm_WARN_ON(&dev_priv->drm, active);
active = true;
}
+ intel_dsc_get_config(pipe_config);
- if (!active)
- goto out;
+ if (!active) {
+ /* bigjoiner slave doesn't enable transcoder */
+ if (!pipe_config->bigjoiner_slave)
+ goto out;
- if (!transcoder_is_dsi(pipe_config->cpu_transcoder) ||
- INTEL_GEN(dev_priv) >= 11) {
+ active = true;
+ pipe_config->pixel_multiplier = 1;
+
+ /* we cannot read out most state, so don't bother.. */
+ pipe_config->quirks |= PIPE_CONFIG_QUIRK_BIGJOINER_SLAVE;
+ } else if (!transcoder_is_dsi(pipe_config->cpu_transcoder) ||
+ INTEL_GEN(dev_priv) >= 11) {
hsw_get_ddi_port_state(crtc, pipe_config);
intel_get_transcoder_timings(crtc, pipe_config);
}
@@ -11244,8 +11333,11 @@ static bool hsw_get_pipe_config(struct intel_crtc *crtc,
}
}
- if (pipe_config->cpu_transcoder != TRANSCODER_EDP &&
- !transcoder_is_dsi(pipe_config->cpu_transcoder)) {
+ if (pipe_config->bigjoiner_slave) {
+ /* Cannot be read out as a slave, set to 0. */
+ pipe_config->pixel_multiplier = 0;
+ } else if (pipe_config->cpu_transcoder != TRANSCODER_EDP &&
+ !transcoder_is_dsi(pipe_config->cpu_transcoder)) {
pipe_config->pixel_multiplier =
intel_de_read(dev_priv,
PIPE_MULT(pipe_config->cpu_transcoder)) + 1;
@@ -12260,7 +12352,7 @@ intel_encoder_current_mode(struct intel_encoder *encoder)
return NULL;
}
- encoder->get_config(encoder, crtc_state);
+ intel_encoder_get_config(encoder, crtc_state);
intel_mode_from_pipe_config(mode, crtc_state);
@@ -13252,10 +13344,12 @@ intel_crtc_copy_uapi_to_hw_state(struct intel_atomic_state *state,
static void intel_crtc_copy_hw_to_uapi_state(struct intel_crtc_state *crtc_state,
struct drm_display_mode *user_mode)
{
- crtc_state->uapi.enable = crtc_state->hw.enable;
- crtc_state->uapi.active = crtc_state->hw.active;
- drm_WARN_ON(crtc_state->uapi.crtc->dev,
- drm_atomic_set_mode_for_crtc(&crtc_state->uapi, user_mode) < 0);
+ if (!crtc_state->bigjoiner_slave) {
+ crtc_state->uapi.enable = crtc_state->hw.enable;
+ crtc_state->uapi.active = crtc_state->hw.active;
+ drm_WARN_ON(crtc_state->uapi.crtc->dev,
+ drm_atomic_set_mode_for_crtc(&crtc_state->uapi, user_mode) < 0);
+ }
crtc_state->uapi.adjusted_mode = crtc_state->hw.adjusted_mode;
@@ -13902,21 +13996,42 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,
PIPE_CONF_CHECK_X(output_types);
- PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_hdisplay);
- PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_htotal);
- PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_hblank_start);
- PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_hblank_end);
- PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_hsync_start);
- PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_hsync_end);
-
- PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_vdisplay);
- PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_vtotal);
- PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_vblank_start);
- PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_vblank_end);
- PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_vsync_start);
- PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_vsync_end);
-
- PIPE_CONF_CHECK_I(pixel_multiplier);
+ if (!PIPE_CONF_QUIRK(PIPE_CONFIG_QUIRK_BIGJOINER_SLAVE)) {
+ /* bigjoiner mode = transcoder mode / 2, for calculations */
+ PIPE_CONF_CHECK_I(hw.pipe_mode.crtc_hdisplay);
+ PIPE_CONF_CHECK_I(hw.pipe_mode.crtc_htotal);
+ PIPE_CONF_CHECK_I(hw.pipe_mode.crtc_vdisplay);
+ PIPE_CONF_CHECK_I(hw.pipe_mode.crtc_vtotal);
+
+ PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_hdisplay);
+ PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_htotal);
+ PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_hblank_start);
+ PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_hblank_end);
+ PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_hsync_start);
+ PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_hsync_end);
+
+ PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_vdisplay);
+ PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_vtotal);
+ PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_vblank_start);
+ PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_vblank_end);
+ PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_vsync_start);
+ PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_vsync_end);
+
+ PIPE_CONF_CHECK_FLAGS(hw.adjusted_mode.flags,
+ DRM_MODE_FLAG_INTERLACE);
+
+ if (!PIPE_CONF_QUIRK(PIPE_CONFIG_QUIRK_MODE_SYNC_FLAGS)) {
+ PIPE_CONF_CHECK_FLAGS(hw.adjusted_mode.flags,
+ DRM_MODE_FLAG_PHSYNC);
+ PIPE_CONF_CHECK_FLAGS(hw.adjusted_mode.flags,
+ DRM_MODE_FLAG_NHSYNC);
+ PIPE_CONF_CHECK_FLAGS(hw.adjusted_mode.flags,
+ DRM_MODE_FLAG_PVSYNC);
+ PIPE_CONF_CHECK_FLAGS(hw.adjusted_mode.flags,
+ DRM_MODE_FLAG_NVSYNC);
+ }
+ PIPE_CONF_CHECK_I(pixel_multiplier);
+ }
PIPE_CONF_CHECK_I(output_format);
PIPE_CONF_CHECK_BOOL(has_hdmi_sink);
if ((INTEL_GEN(dev_priv) < 8 && !IS_HASWELL(dev_priv)) ||
@@ -13926,24 +14041,11 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,
PIPE_CONF_CHECK_BOOL(hdmi_scrambling);
PIPE_CONF_CHECK_BOOL(hdmi_high_tmds_clock_ratio);
PIPE_CONF_CHECK_BOOL(has_infoframe);
- PIPE_CONF_CHECK_BOOL(fec_enable);
+ if (!PIPE_CONF_QUIRK(PIPE_CONFIG_QUIRK_BIGJOINER_SLAVE))
+ PIPE_CONF_CHECK_BOOL(fec_enable);
PIPE_CONF_CHECK_BOOL_INCOMPLETE(has_audio);
- PIPE_CONF_CHECK_FLAGS(hw.adjusted_mode.flags,
- DRM_MODE_FLAG_INTERLACE);
-
- if (!PIPE_CONF_QUIRK(PIPE_CONFIG_QUIRK_MODE_SYNC_FLAGS)) {
- PIPE_CONF_CHECK_FLAGS(hw.adjusted_mode.flags,
- DRM_MODE_FLAG_PHSYNC);
- PIPE_CONF_CHECK_FLAGS(hw.adjusted_mode.flags,
- DRM_MODE_FLAG_NHSYNC);
- PIPE_CONF_CHECK_FLAGS(hw.adjusted_mode.flags,
- DRM_MODE_FLAG_PVSYNC);
- PIPE_CONF_CHECK_FLAGS(hw.adjusted_mode.flags,
- DRM_MODE_FLAG_NVSYNC);
- }
-
PIPE_CONF_CHECK_X(gmch_pfit.control);
/* pfit ratios are autocomputed by the hw on gen4+ */
if (INTEL_GEN(dev_priv) < 4)
@@ -13969,7 +14071,8 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,
}
PIPE_CONF_CHECK_I(scaler_state.scaler_id);
- PIPE_CONF_CHECK_CLOCK_FUZZY(pixel_rate);
+ if (!PIPE_CONF_QUIRK(PIPE_CONFIG_QUIRK_BIGJOINER_SLAVE))
+ PIPE_CONF_CHECK_CLOCK_FUZZY(pixel_rate);
PIPE_CONF_CHECK_X(gamma_mode);
if (IS_CHERRYVIEW(dev_priv))
@@ -13990,48 +14093,51 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,
PIPE_CONF_CHECK_BOOL(double_wide);
PIPE_CONF_CHECK_P(shared_dpll);
- PIPE_CONF_CHECK_X(dpll_hw_state.dpll);
- PIPE_CONF_CHECK_X(dpll_hw_state.dpll_md);
- PIPE_CONF_CHECK_X(dpll_hw_state.fp0);
- PIPE_CONF_CHECK_X(dpll_hw_state.fp1);
- PIPE_CONF_CHECK_X(dpll_hw_state.wrpll);
- PIPE_CONF_CHECK_X(dpll_hw_state.spll);
- PIPE_CONF_CHECK_X(dpll_hw_state.ctrl1);
- PIPE_CONF_CHECK_X(dpll_hw_state.cfgcr1);
- PIPE_CONF_CHECK_X(dpll_hw_state.cfgcr2);
- PIPE_CONF_CHECK_X(dpll_hw_state.cfgcr0);
- PIPE_CONF_CHECK_X(dpll_hw_state.ebb0);
- PIPE_CONF_CHECK_X(dpll_hw_state.ebb4);
- PIPE_CONF_CHECK_X(dpll_hw_state.pll0);
- PIPE_CONF_CHECK_X(dpll_hw_state.pll1);
- PIPE_CONF_CHECK_X(dpll_hw_state.pll2);
- PIPE_CONF_CHECK_X(dpll_hw_state.pll3);
- PIPE_CONF_CHECK_X(dpll_hw_state.pll6);
- PIPE_CONF_CHECK_X(dpll_hw_state.pll8);
- PIPE_CONF_CHECK_X(dpll_hw_state.pll9);
- PIPE_CONF_CHECK_X(dpll_hw_state.pll10);
- PIPE_CONF_CHECK_X(dpll_hw_state.pcsdw12);
- PIPE_CONF_CHECK_X(dpll_hw_state.mg_refclkin_ctl);
- PIPE_CONF_CHECK_X(dpll_hw_state.mg_clktop2_coreclkctl1);
- PIPE_CONF_CHECK_X(dpll_hw_state.mg_clktop2_hsclkctl);
- PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_div0);
- PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_div1);
- PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_lf);
- PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_frac_lock);
- PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_ssc);
- PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_bias);
- PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_tdc_coldst_bias);
-
- PIPE_CONF_CHECK_X(dsi_pll.ctrl);
- PIPE_CONF_CHECK_X(dsi_pll.div);
-
- if (IS_G4X(dev_priv) || INTEL_GEN(dev_priv) >= 5)
- PIPE_CONF_CHECK_I(pipe_bpp);
-
- PIPE_CONF_CHECK_CLOCK_FUZZY(hw.adjusted_mode.crtc_clock);
- PIPE_CONF_CHECK_CLOCK_FUZZY(port_clock);
-
- PIPE_CONF_CHECK_I(min_voltage_level);
+ if (!PIPE_CONF_QUIRK(PIPE_CONFIG_QUIRK_BIGJOINER_SLAVE)) {
+ PIPE_CONF_CHECK_X(dpll_hw_state.dpll);
+ PIPE_CONF_CHECK_X(dpll_hw_state.dpll_md);
+ PIPE_CONF_CHECK_X(dpll_hw_state.fp0);
+ PIPE_CONF_CHECK_X(dpll_hw_state.fp1);
+ PIPE_CONF_CHECK_X(dpll_hw_state.wrpll);
+ PIPE_CONF_CHECK_X(dpll_hw_state.spll);
+ PIPE_CONF_CHECK_X(dpll_hw_state.ctrl1);
+ PIPE_CONF_CHECK_X(dpll_hw_state.cfgcr1);
+ PIPE_CONF_CHECK_X(dpll_hw_state.cfgcr2);
+ PIPE_CONF_CHECK_X(dpll_hw_state.cfgcr0);
+ PIPE_CONF_CHECK_X(dpll_hw_state.ebb0);
+ PIPE_CONF_CHECK_X(dpll_hw_state.ebb4);
+ PIPE_CONF_CHECK_X(dpll_hw_state.pll0);
+ PIPE_CONF_CHECK_X(dpll_hw_state.pll1);
+ PIPE_CONF_CHECK_X(dpll_hw_state.pll2);
+ PIPE_CONF_CHECK_X(dpll_hw_state.pll3);
+ PIPE_CONF_CHECK_X(dpll_hw_state.pll6);
+ PIPE_CONF_CHECK_X(dpll_hw_state.pll8);
+ PIPE_CONF_CHECK_X(dpll_hw_state.pll9);
+ PIPE_CONF_CHECK_X(dpll_hw_state.pll10);
+ PIPE_CONF_CHECK_X(dpll_hw_state.pcsdw12);
+ PIPE_CONF_CHECK_X(dpll_hw_state.mg_refclkin_ctl);
+ PIPE_CONF_CHECK_X(dpll_hw_state.mg_clktop2_coreclkctl1);
+ PIPE_CONF_CHECK_X(dpll_hw_state.mg_clktop2_hsclkctl);
+ PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_div0);
+ PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_div1);
+ PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_lf);
+ PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_frac_lock);
+ PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_ssc);
+ PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_bias);
+ PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_tdc_coldst_bias);
+
+ PIPE_CONF_CHECK_X(dsi_pll.ctrl);
+ PIPE_CONF_CHECK_X(dsi_pll.div);
+
+ if (IS_G4X(dev_priv) || INTEL_GEN(dev_priv) >= 5)
+ PIPE_CONF_CHECK_I(pipe_bpp);
+
+ PIPE_CONF_CHECK_CLOCK_FUZZY(hw.adjusted_mode.crtc_clock);
+ PIPE_CONF_CHECK_CLOCK_FUZZY(hw.pipe_mode.crtc_clock);
+ PIPE_CONF_CHECK_CLOCK_FUZZY(port_clock);
+
+ PIPE_CONF_CHECK_I(min_voltage_level);
+ }
PIPE_CONF_CHECK_X(infoframes.enable);
PIPE_CONF_CHECK_X(infoframes.gcp);
@@ -14043,11 +14149,12 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,
PIPE_CONF_CHECK_X(sync_mode_slaves_mask);
PIPE_CONF_CHECK_I(master_transcoder);
-
+ PIPE_CONF_CHECK_BOOL(bigjoiner);
+ PIPE_CONF_CHECK_BOOL(bigjoiner_slave);
+ PIPE_CONF_CHECK_P(bigjoiner_linked_crtc);
PIPE_CONF_CHECK_I(dsc.compression_enable);
PIPE_CONF_CHECK_I(dsc.dsc_split);
PIPE_CONF_CHECK_I(dsc.compressed_bpp);
-
PIPE_CONF_CHECK_I(mst_master_transcoder);
#undef PIPE_CONF_CHECK_X
@@ -14314,6 +14421,7 @@ verify_crtc_state(struct intel_crtc *crtc,
struct intel_encoder *encoder;
struct intel_crtc_state *pipe_config = old_crtc_state;
struct drm_atomic_state *state = old_crtc_state->uapi.state;
+ struct intel_crtc *master = crtc;
bool active;
__drm_atomic_helper_crtc_destroy_state(&old_crtc_state->uapi);
@@ -14340,7 +14448,10 @@ verify_crtc_state(struct intel_crtc *crtc,
"(expected %i, found %i)\n",
new_crtc_state->hw.active, crtc->active);
- for_each_encoder_on_crtc(dev, &crtc->base, encoder) {
+ if (new_crtc_state->bigjoiner_slave)
+ master = new_crtc_state->bigjoiner_linked_crtc;
+
+ for_each_encoder_on_crtc(dev, &master->base, encoder) {
enum pipe pipe;
active = encoder->get_hw_state(encoder, &pipe);
@@ -14349,12 +14460,12 @@ verify_crtc_state(struct intel_crtc *crtc,
encoder->base.base.id, active,
new_crtc_state->hw.active);
- I915_STATE_WARN(active && crtc->pipe != pipe,
+ I915_STATE_WARN(active && master->pipe != pipe,
"Encoder connected to wrong pipe %c\n",
pipe_name(pipe));
if (active)
- encoder->get_config(encoder, pipe_config);
+ intel_encoder_get_config(encoder, pipe_config);
}
intel_crtc_compute_pixel_rate(pipe_config);
@@ -15376,7 +15487,12 @@ static void intel_old_crtc_state_disables(struct intel_atomic_state *state,
{
struct drm_i915_private *dev_priv = to_i915(state->base.dev);
+ drm_WARN_ON(&dev_priv->drm, old_crtc_state->bigjoiner_slave);
+
intel_crtc_disable_planes(state, crtc);
+ if (old_crtc_state->bigjoiner)
+ intel_crtc_disable_planes(state,
+ old_crtc_state->bigjoiner_linked_crtc);
/*
* We need to disable pipe CRC before disabling the pipe,
@@ -15406,7 +15522,7 @@ static void intel_commit_modeset_disables(struct intel_atomic_state *state)
/* Only disable port sync and MST slaves */
for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
new_crtc_state, i) {
- if (!needs_modeset(new_crtc_state))
+ if (!needs_modeset(new_crtc_state) || old_crtc_state->bigjoiner_slave)
continue;
if (!old_crtc_state->hw.active)
@@ -15421,7 +15537,6 @@ static void intel_commit_modeset_disables(struct intel_atomic_state *state)
!intel_dp_mst_is_slave_trans(old_crtc_state))
continue;
- intel_pre_plane_update(state, crtc);
intel_old_crtc_state_disables(state, old_crtc_state,
new_crtc_state, crtc);
handled |= BIT(crtc->pipe);
@@ -15431,10 +15546,18 @@ static void intel_commit_modeset_disables(struct intel_atomic_state *state)
for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
new_crtc_state, i) {
if (!needs_modeset(new_crtc_state) ||
- (handled & BIT(crtc->pipe)))
+ (handled & BIT(crtc->pipe)) ||
+ old_crtc_state->bigjoiner_slave)
continue;
intel_pre_plane_update(state, crtc);
+ if (old_crtc_state->bigjoiner) {
+ struct intel_crtc *slave =
+ old_crtc_state->bigjoiner_linked_crtc;
+
+ intel_pre_plane_update(state, slave);
+ }
+
if (old_crtc_state->hw.active)
intel_old_crtc_state_disables(state, old_crtc_state,
new_crtc_state, crtc);
@@ -18063,7 +18186,7 @@ int intel_modeset_init(struct drm_i915_private *i915)
for_each_intel_crtc(dev, crtc) {
struct intel_initial_plane_config plane_config = {};
- if (!crtc->active)
+ if (!to_intel_crtc_state(crtc->base.state)->uapi.active)
continue;
/*
@@ -18562,7 +18685,17 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
crtc_state = to_intel_crtc_state(crtc->base.state);
encoder->base.crtc = &crtc->base;
- encoder->get_config(encoder, crtc_state);
+ intel_encoder_get_config(encoder, crtc_state);
+
+ /* read out to slave crtc as well for bigjoiner */
+ if (crtc_state->bigjoiner) {
+ /* encoder should read be linked to bigjoiner master */
+ WARN_ON(crtc_state->bigjoiner_slave);
+
+ crtc = crtc_state->bigjoiner_linked_crtc;
+ crtc_state = to_intel_crtc_state(crtc->base.state);
+ intel_encoder_get_config(encoder, crtc_state);
+ }
} else {
encoder->base.crtc = NULL;
}
diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
index d9d56f15bff1..e93493757cbf 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -826,6 +826,7 @@ struct intel_crtc_state {
* accordingly.
*/
#define PIPE_CONFIG_QUIRK_MODE_SYNC_FLAGS (1<<0) /* unreliable sync mode.flags */
+#define PIPE_CONFIG_QUIRK_BIGJOINER_SLAVE (1<<1) /* bigjoiner slave, partial readout */
unsigned long quirks;
unsigned fb_bits; /* framebuffers to flip */
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 29f45d2206af..41cb9f9c0292 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -2004,12 +2004,10 @@ static bool intel_dp_supports_fec(struct intel_dp *intel_dp,
static bool intel_dp_supports_dsc(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state)
{
- struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
-
- if (!intel_dp_is_edp(intel_dp) && !crtc_state->fec_enable)
+ if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP) && !crtc_state->fec_enable)
return false;
- return intel_dsc_source_support(encoder, crtc_state) &&
+ return intel_dsc_source_support(crtc_state) &&
drm_dp_sink_supports_dsc(intel_dp->dsc_dpcd);
}
diff --git a/drivers/gpu/drm/i915/display/intel_vdsc.c b/drivers/gpu/drm/i915/display/intel_vdsc.c
index c5735c365659..2d343ccef497 100644
--- a/drivers/gpu/drm/i915/display/intel_vdsc.c
+++ b/drivers/gpu/drm/i915/display/intel_vdsc.c
@@ -332,11 +332,10 @@ static const struct rc_parameters *get_rc_params(u16 compressed_bpp,
return &rc_parameters[row_index][column_index];
}
-bool intel_dsc_source_support(struct intel_encoder *encoder,
- const struct intel_crtc_state *crtc_state)
+bool intel_dsc_source_support(const struct intel_crtc_state *crtc_state)
{
const struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
- struct drm_i915_private *i915 = to_i915(encoder->base.dev);
+ struct drm_i915_private *i915 = to_i915(crtc->base.dev);
enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
enum pipe pipe = crtc->pipe;
@@ -490,11 +489,10 @@ intel_dsc_power_domain(const struct intel_crtc_state *crtc_state)
return POWER_DOMAIN_TRANSCODER_VDSC_PW2;
}
-static void intel_dsc_pps_configure(struct intel_encoder *encoder,
- const struct intel_crtc_state *crtc_state)
+static void intel_dsc_pps_configure(const struct intel_crtc_state *crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
- struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+ struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
const struct drm_dsc_config *vdsc_cfg = &crtc_state->dsc.config;
enum pipe pipe = crtc->pipe;
u32 pps_val = 0;
@@ -503,6 +501,9 @@ static void intel_dsc_pps_configure(struct intel_encoder *encoder,
u8 num_vdsc_instances = (crtc_state->dsc.dsc_split) ? 2 : 1;
int i = 0;
+ if (crtc_state->bigjoiner)
+ num_vdsc_instances *= 2;
+
/* Populate PICTURE_PARAMETER_SET_0 registers */
pps_val = DSC_VER_MAJ | vdsc_cfg->dsc_version_minor <<
DSC_VER_MIN_SHIFT |
@@ -973,55 +974,6 @@ static void intel_dsc_pps_configure(struct intel_encoder *encoder,
}
}
-void intel_dsc_get_config(struct intel_encoder *encoder,
- struct intel_crtc_state *crtc_state)
-{
- struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
- struct drm_dsc_config *vdsc_cfg = &crtc_state->dsc.config;
- struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
- enum pipe pipe = crtc->pipe;
- enum intel_display_power_domain power_domain;
- intel_wakeref_t wakeref;
- u32 dss_ctl1, dss_ctl2, val;
-
- if (!intel_dsc_source_support(encoder, crtc_state))
- return;
-
- power_domain = intel_dsc_power_domain(crtc_state);
-
- wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
- if (!wakeref)
- return;
-
- if (!is_pipe_dsc(crtc_state)) {
- dss_ctl1 = intel_de_read(dev_priv, DSS_CTL1);
- dss_ctl2 = intel_de_read(dev_priv, DSS_CTL2);
- } else {
- dss_ctl1 = intel_de_read(dev_priv, ICL_PIPE_DSS_CTL1(pipe));
- dss_ctl2 = intel_de_read(dev_priv, ICL_PIPE_DSS_CTL2(pipe));
- }
-
- crtc_state->dsc.compression_enable = dss_ctl2 & LEFT_BRANCH_VDSC_ENABLE;
- if (!crtc_state->dsc.compression_enable)
- goto out;
-
- crtc_state->dsc.dsc_split = (dss_ctl2 & RIGHT_BRANCH_VDSC_ENABLE) &&
- (dss_ctl1 & JOINER_ENABLE);
-
- /* FIXME: add more state readout as needed */
-
- /* PPS1 */
- if (!is_pipe_dsc(crtc_state))
- val = intel_de_read(dev_priv, DSCA_PICTURE_PARAMETER_SET_1);
- else
- val = intel_de_read(dev_priv,
- ICL_DSC0_PICTURE_PARAMETER_SET_1(pipe));
- vdsc_cfg->bits_per_pixel = val;
- crtc_state->dsc.compressed_bpp = vdsc_cfg->bits_per_pixel >> 4;
-out:
- intel_display_power_put(dev_priv, power_domain, wakeref);
-}
-
static void intel_dsc_dsi_pps_write(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state)
{
@@ -1060,77 +1012,130 @@ static void intel_dsc_dp_pps_write(struct intel_encoder *encoder,
sizeof(dp_dsc_pps_sdp));
}
+static i915_reg_t dss_ctl1_reg(const struct intel_crtc_state *crtc_state)
+{
+ enum pipe pipe = to_intel_crtc(crtc_state->uapi.crtc)->pipe;
+
+ if (crtc_state->cpu_transcoder == TRANSCODER_EDP)
+ return DSS_CTL1;
+
+ return ICL_PIPE_DSS_CTL1(pipe);
+}
+
+static i915_reg_t dss_ctl2_reg(const struct intel_crtc_state *crtc_state)
+{
+ enum pipe pipe = to_intel_crtc(crtc_state->uapi.crtc)->pipe;
+
+ if (crtc_state->cpu_transcoder == TRANSCODER_EDP)
+ return DSS_CTL2;
+
+ return ICL_PIPE_DSS_CTL2(pipe);
+}
+
void intel_dsc_enable(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
- struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
- enum pipe pipe = crtc->pipe;
- i915_reg_t dss_ctl1_reg, dss_ctl2_reg;
+ struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
u32 dss_ctl1_val = 0;
u32 dss_ctl2_val = 0;
if (!crtc_state->dsc.compression_enable)
return;
- /* Enable Power wells for VDSC/joining */
- intel_display_power_get(dev_priv,
- intel_dsc_power_domain(crtc_state));
+ intel_dsc_pps_configure(crtc_state);
- intel_dsc_pps_configure(encoder, crtc_state);
-
- if (encoder->type == INTEL_OUTPUT_DSI)
- intel_dsc_dsi_pps_write(encoder, crtc_state);
- else
- intel_dsc_dp_pps_write(encoder, crtc_state);
-
- if (!is_pipe_dsc(crtc_state)) {
- dss_ctl1_reg = DSS_CTL1;
- dss_ctl2_reg = DSS_CTL2;
- } else {
- dss_ctl1_reg = ICL_PIPE_DSS_CTL1(pipe);
- dss_ctl2_reg = ICL_PIPE_DSS_CTL2(pipe);
+ if (!crtc_state->bigjoiner_slave) {
+ if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DSI))
+ intel_dsc_dsi_pps_write(encoder, crtc_state);
+ else
+ intel_dsc_dp_pps_write(encoder, crtc_state);
}
+
dss_ctl2_val |= LEFT_BRANCH_VDSC_ENABLE;
if (crtc_state->dsc.dsc_split) {
dss_ctl2_val |= RIGHT_BRANCH_VDSC_ENABLE;
dss_ctl1_val |= JOINER_ENABLE;
}
- intel_de_write(dev_priv, dss_ctl1_reg, dss_ctl1_val);
- intel_de_write(dev_priv, dss_ctl2_reg, dss_ctl2_val);
+ if (crtc_state->bigjoiner) {
+ dss_ctl1_val |= BIG_JOINER_ENABLE;
+ if (!crtc_state->bigjoiner_slave)
+ dss_ctl1_val |= MASTER_BIG_JOINER_ENABLE;
+ }
+ intel_de_write(dev_priv, dss_ctl1_reg(crtc_state), dss_ctl1_val);
+ intel_de_write(dev_priv, dss_ctl2_reg(crtc_state), dss_ctl2_val);
}
void intel_dsc_disable(const struct intel_crtc_state *old_crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc);
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
- enum pipe pipe = crtc->pipe;
- i915_reg_t dss_ctl1_reg, dss_ctl2_reg;
- u32 dss_ctl1_val = 0, dss_ctl2_val = 0;
if (!old_crtc_state->dsc.compression_enable)
return;
- if (!is_pipe_dsc(old_crtc_state)) {
- dss_ctl1_reg = DSS_CTL1;
- dss_ctl2_reg = DSS_CTL2;
- } else {
- dss_ctl1_reg = ICL_PIPE_DSS_CTL1(pipe);
- dss_ctl2_reg = ICL_PIPE_DSS_CTL2(pipe);
- }
- dss_ctl1_val = intel_de_read(dev_priv, dss_ctl1_reg);
- if (dss_ctl1_val & JOINER_ENABLE)
- dss_ctl1_val &= ~JOINER_ENABLE;
- intel_de_write(dev_priv, dss_ctl1_reg, dss_ctl1_val);
-
- dss_ctl2_val = intel_de_read(dev_priv, dss_ctl2_reg);
- if (dss_ctl2_val & LEFT_BRANCH_VDSC_ENABLE ||
- dss_ctl2_val & RIGHT_BRANCH_VDSC_ENABLE)
- dss_ctl2_val &= ~(LEFT_BRANCH_VDSC_ENABLE |
- RIGHT_BRANCH_VDSC_ENABLE);
- intel_de_write(dev_priv, dss_ctl2_reg, dss_ctl2_val);
+ intel_de_write(dev_priv, dss_ctl1_reg(old_crtc_state), 0);
+ intel_de_write(dev_priv, dss_ctl2_reg(old_crtc_state), 0);
/* Disable Power wells for VDSC/joining */
intel_display_power_put_unchecked(dev_priv,
intel_dsc_power_domain(old_crtc_state));
}
+
+void intel_dsc_get_config(struct intel_crtc_state *crtc_state)
+{
+ struct drm_dsc_config *vdsc_cfg = &crtc_state->dsc.config;
+ struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+ struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ enum pipe pipe = crtc->pipe;
+ enum intel_display_power_domain power_domain;
+ intel_wakeref_t wakeref;
+ u32 dss_ctl1, dss_ctl2, val;
+
+ if (!intel_dsc_source_support(crtc_state))
+ return;
+
+ power_domain = intel_dsc_power_domain(crtc_state);
+
+ wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
+ if (!wakeref)
+ return;
+
+ dss_ctl1 = intel_de_read(dev_priv, dss_ctl1_reg(crtc_state));
+ dss_ctl2 = intel_de_read(dev_priv, dss_ctl2_reg(crtc_state));
+
+ crtc_state->dsc.compression_enable = dss_ctl2 & LEFT_BRANCH_VDSC_ENABLE;
+ if (!crtc_state->dsc.compression_enable)
+ goto out;
+
+ crtc_state->dsc.dsc_split = (dss_ctl2 & RIGHT_BRANCH_VDSC_ENABLE) &&
+ (dss_ctl1 & JOINER_ENABLE);
+
+ if (dss_ctl1 & BIG_JOINER_ENABLE) {
+ crtc_state->bigjoiner = true;
+
+ if (!(dss_ctl1 & MASTER_BIG_JOINER_ENABLE)) {
+ crtc_state->bigjoiner_slave = true;
+ if (!WARN_ON(crtc->pipe == PIPE_A))
+ crtc_state->bigjoiner_linked_crtc =
+ intel_get_crtc_for_pipe(dev_priv, crtc->pipe - 1);
+ } else {
+ if (!WARN_ON(INTEL_NUM_PIPES(dev_priv) == crtc->pipe + 1))
+ crtc_state->bigjoiner_linked_crtc =
+ intel_get_crtc_for_pipe(dev_priv, crtc->pipe + 1);
+ }
+ }
+
+ /* FIXME: add more state readout as needed */
+
+ /* PPS1 */
+ if (!is_pipe_dsc(crtc_state))
+ val = intel_de_read(dev_priv, DSCA_PICTURE_PARAMETER_SET_1);
+ else
+ val = intel_de_read(dev_priv,
+ ICL_DSC0_PICTURE_PARAMETER_SET_1(pipe));
+ vdsc_cfg->bits_per_pixel = val;
+ crtc_state->dsc.compressed_bpp = vdsc_cfg->bits_per_pixel >> 4;
+out:
+ intel_display_power_put(dev_priv, power_domain, wakeref);
+}
diff --git a/drivers/gpu/drm/i915/display/intel_vdsc.h b/drivers/gpu/drm/i915/display/intel_vdsc.h
index e56a3254c214..5301345ac5e7 100644
--- a/drivers/gpu/drm/i915/display/intel_vdsc.h
+++ b/drivers/gpu/drm/i915/display/intel_vdsc.h
@@ -11,15 +11,14 @@
struct intel_encoder;
struct intel_crtc_state;
-bool intel_dsc_source_support(struct intel_encoder *encoder,
- const struct intel_crtc_state *crtc_state);
+bool intel_dsc_source_support(const struct intel_crtc_state *crtc_state);
void intel_dsc_enable(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state);
void intel_dsc_disable(const struct intel_crtc_state *crtc_state);
int intel_dsc_compute_params(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config);
-void intel_dsc_get_config(struct intel_encoder *encoder,
- struct intel_crtc_state *crtc_state);
+void intel_dsc_get_config(struct intel_crtc_state *crtc_state);
+
enum intel_display_power_domain
intel_dsc_power_domain(const struct intel_crtc_state *crtc_state);
--
2.19.1
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.