From cb6e097d9340e037ced6c580019e823b702c6bb9 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Wed, 3 Aug 2022 13:28:52 +0300 Subject: dt-bindings: iio: adc: at91-sama5d2_adc: add id for temperature channel Add ID for temperature channel of AT91 SAMA5D2 ADC. Signed-off-by: Claudiu Beznea Acked-by: Rob Herring Link: https://lore.kernel.org/r/20220803102855.2191070-17-claudiu.beznea@microchip.com Signed-off-by: Jonathan Cameron --- include/dt-bindings/iio/adc/at91-sama5d2_adc.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'include') diff --git a/include/dt-bindings/iio/adc/at91-sama5d2_adc.h b/include/dt-bindings/iio/adc/at91-sama5d2_adc.h index 70f99dbdbb42..866d36530583 100644 --- a/include/dt-bindings/iio/adc/at91-sama5d2_adc.h +++ b/include/dt-bindings/iio/adc/at91-sama5d2_adc.h @@ -13,4 +13,7 @@ /* pressure channel index */ #define AT91_SAMA5D2_ADC_P_CHANNEL 26 +/* SAMA7G5 Temperature sensor channel index. */ +#define AT91_SAMA7G5_ADC_TEMP_CHANNEL 31 + #endif -- cgit v1.2.3 From 1e64b9c5f9a01f1a752438724bc83180c451e1c7 Mon Sep 17 00:00:00 2001 From: Nuno Sá Date: Fri, 15 Jul 2022 14:28:53 +0200 Subject: iio: inkern: move to fwnode properties MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This moves the IIO in kernel interface to use fwnode properties and thus be firmware agnostic. Note that the interface is still not firmware agnostic. At this point we have both OF and fwnode interfaces so that we don't break any user. On top of this we also want to have a per driver conversion and that is the main reason we have both of_xlate() and fwnode_xlate() support. Signed-off-by: Nuno Sá Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220715122903.332535-6-nuno.sa@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/inkern.c | 157 +++++++++++++++++++++++-------------------- include/linux/iio/consumer.h | 36 +++++----- include/linux/iio/iio.h | 5 ++ 3 files changed, 108 insertions(+), 90 deletions(-) (limited to 'include') diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c index 9e0c7cc3a093..9cfa66ef9536 100644 --- a/drivers/iio/inkern.c +++ b/drivers/iio/inkern.c @@ -5,6 +5,7 @@ */ #include #include +#include #include #include #include @@ -117,15 +118,8 @@ static const struct iio_chan_spec return chan; } -#ifdef CONFIG_OF - -static int iio_dev_node_match(struct device *dev, const void *data) -{ - return dev->of_node == data && dev->type == &iio_device_type; -} - /** - * __of_iio_simple_xlate - translate iiospec to the IIO channel index + * __fwnode_iio_simple_xlate - translate iiospec to the IIO channel index * @indio_dev: pointer to the iio_dev structure * @iiospec: IIO specifier as found in the device tree * @@ -134,14 +128,14 @@ static int iio_dev_node_match(struct device *dev, const void *data) * whether IIO index is less than num_channels (that is specified in the * iio_dev). */ -static int __of_iio_simple_xlate(struct iio_dev *indio_dev, - const struct of_phandle_args *iiospec) +static int __fwnode_iio_simple_xlate(struct iio_dev *indio_dev, + const struct fwnode_reference_args *iiospec) { - if (!iiospec->args_count) + if (!iiospec->nargs) return 0; if (iiospec->args[0] >= indio_dev->num_channels) { - dev_err(&indio_dev->dev, "invalid channel index %u\n", + dev_err(&indio_dev->dev, "invalid channel index %llu\n", iiospec->args[0]); return -EINVAL; } @@ -149,34 +143,55 @@ static int __of_iio_simple_xlate(struct iio_dev *indio_dev, return iiospec->args[0]; } -static int __of_iio_channel_get(struct iio_channel *channel, - struct device_node *np, int index) +/* + * Simple helper to copy fwnode_reference_args into of_phandle_args so we + * can pass it to of_xlate(). Ultimate goal is to drop this together with + * of_xlate(). + */ +static int __fwnode_to_of_xlate(struct iio_dev *indio_dev, + const struct fwnode_reference_args *iiospec) { + struct of_phandle_args of_args; + unsigned int i; + + of_args.args_count = iiospec->nargs; + of_args.np = to_of_node(iiospec->fwnode); + + for (i = 0; i < MAX_PHANDLE_ARGS; i++) + of_args.args[i] = i < iiospec->nargs ? iiospec->args[i] : 0; + + return indio_dev->info->of_xlate(indio_dev, &of_args); +} + +static int __fwnode_iio_channel_get(struct iio_channel *channel, + struct fwnode_handle *fwnode, int index) +{ + struct fwnode_reference_args iiospec; struct device *idev; struct iio_dev *indio_dev; int err; - struct of_phandle_args iiospec; - err = of_parse_phandle_with_args(np, "io-channels", - "#io-channel-cells", - index, &iiospec); + err = fwnode_property_get_reference_args(fwnode, "io-channels", + "#io-channel-cells", 0, + index, &iiospec); if (err) return err; - idev = bus_find_device(&iio_bus_type, NULL, iiospec.np, - iio_dev_node_match); + idev = bus_find_device_by_fwnode(&iio_bus_type, iiospec.fwnode); if (idev == NULL) { - of_node_put(iiospec.np); + fwnode_handle_put(iiospec.fwnode); return -EPROBE_DEFER; } indio_dev = dev_to_iio_dev(idev); channel->indio_dev = indio_dev; if (indio_dev->info->of_xlate) - index = indio_dev->info->of_xlate(indio_dev, &iiospec); + index = __fwnode_to_of_xlate(indio_dev, &iiospec); + else if (indio_dev->info->fwnode_xlate) + index = indio_dev->info->fwnode_xlate(indio_dev, &iiospec); else - index = __of_iio_simple_xlate(indio_dev, &iiospec); - of_node_put(iiospec.np); + index = __fwnode_iio_simple_xlate(indio_dev, &iiospec); + fwnode_handle_put(iiospec.fwnode); if (index < 0) goto err_put; channel->channel = &indio_dev->channels[index]; @@ -188,7 +203,8 @@ err_put: return index; } -static struct iio_channel *of_iio_channel_get(struct device_node *np, int index) +static struct iio_channel *fwnode_iio_channel_get(struct fwnode_handle *fwnode, + int index) { struct iio_channel *channel; int err; @@ -200,7 +216,7 @@ static struct iio_channel *of_iio_channel_get(struct device_node *np, int index) if (channel == NULL) return ERR_PTR(-ENOMEM); - err = __of_iio_channel_get(channel, np, index); + err = __fwnode_iio_channel_get(channel, fwnode, index); if (err) goto err_free_channel; @@ -211,8 +227,8 @@ err_free_channel: return ERR_PTR(err); } -static struct iio_channel *__of_iio_channel_get_by_name(struct device_node *np, - const char *name) +static struct iio_channel * +__fwnode_iio_channel_get_by_name(struct fwnode_handle *fwnode, const char *name) { struct iio_channel *chan; int index = 0; @@ -220,19 +236,20 @@ static struct iio_channel *__of_iio_channel_get_by_name(struct device_node *np, /* * For named iio channels, first look up the name in the * "io-channel-names" property. If it cannot be found, the - * index will be an error code, and of_iio_channel_get() + * index will be an error code, and fwnode_iio_channel_get() * will fail. */ if (name) - index = of_property_match_string(np, "io-channel-names", name); + index = fwnode_property_match_string(fwnode, "io-channel-names", + name); - chan = of_iio_channel_get(np, index); + chan = fwnode_iio_channel_get(fwnode, index); if (!IS_ERR(chan) || PTR_ERR(chan) == -EPROBE_DEFER) return chan; if (name) { if (index >= 0) { - pr_err("ERROR: could not get IIO channel %pOF:%s(%i)\n", - np, name, index); + pr_err("ERROR: could not get IIO channel %pfw:%s(%i)\n", + fwnode, name, index); /* * In this case, we found 'name' in 'io-channel-names' * but somehow we still fail so that we should not proceed @@ -243,16 +260,16 @@ static struct iio_channel *__of_iio_channel_get_by_name(struct device_node *np, return ERR_PTR(-EINVAL); } /* - * If index < 0, then of_parse_phandle_with_args() fails - * with -EINVAL which is expected. We should not proceed - * if we get any other error. + * If index < 0, then fwnode_property_get_reference_args() fails + * with -EINVAL or -ENOENT (ACPI case) which is expected. We + * should not proceed if we get any other error. */ - if (PTR_ERR(chan) != -EINVAL) + if (PTR_ERR(chan) != -EINVAL && PTR_ERR(chan) != -ENOENT) return chan; } else if (PTR_ERR(chan) != -ENOENT) { /* * if !name, then we should only proceed the lookup if - * of_parse_phandle_with_args() returns -ENOENT. + * fwnode_property_get_reference_args() returns -ENOENT. */ return chan; } @@ -261,13 +278,14 @@ static struct iio_channel *__of_iio_channel_get_by_name(struct device_node *np, return ERR_PTR(-ENODEV); } -struct iio_channel *of_iio_channel_get_by_name(struct device_node *np, - const char *name) +struct iio_channel *fwnode_iio_channel_get_by_name(struct fwnode_handle *fwnode, + const char *name) { + struct fwnode_handle *parent; struct iio_channel *chan; /* Walk up the tree of devices looking for a matching iio channel */ - chan = __of_iio_channel_get_by_name(np, name); + chan = __fwnode_iio_channel_get_by_name(fwnode, name); if (!IS_ERR(chan) || PTR_ERR(chan) != -ENODEV) return chan; @@ -276,33 +294,34 @@ struct iio_channel *of_iio_channel_get_by_name(struct device_node *np, * If the parent node has a "io-channel-ranges" property, * then we can try one of its channels. */ - np = np->parent; - while (np) { - if (!of_get_property(np, "io-channel-ranges", NULL)) + fwnode_for_each_parent_node(fwnode, parent) { + if (!fwnode_property_present(parent, "io-channel-ranges")) { + fwnode_handle_put(parent); return ERR_PTR(-ENODEV); + } - chan = __of_iio_channel_get_by_name(np, name); - if (!IS_ERR(chan) || PTR_ERR(chan) != -ENODEV) + chan = __fwnode_iio_channel_get_by_name(fwnode, name); + if (!IS_ERR(chan) || PTR_ERR(chan) != -ENODEV) { + fwnode_handle_put(parent); return chan; - - np = np->parent; + } } return ERR_PTR(-ENODEV); } -EXPORT_SYMBOL_GPL(of_iio_channel_get_by_name); +EXPORT_SYMBOL_GPL(fwnode_iio_channel_get_by_name); -static struct iio_channel *of_iio_channel_get_all(struct device *dev) +static struct iio_channel *fwnode_iio_channel_get_all(struct device *dev) { + struct fwnode_handle *fwnode = dev_fwnode(dev); struct iio_channel *chans; int i, mapind, nummaps = 0; int ret; do { - ret = of_parse_phandle_with_args(dev->of_node, - "io-channels", - "#io-channel-cells", - nummaps, NULL); + ret = fwnode_property_get_reference_args(fwnode, "io-channels", + "#io-channel-cells", 0, + nummaps, NULL); if (ret < 0) break; } while (++nummaps); @@ -315,10 +334,9 @@ static struct iio_channel *of_iio_channel_get_all(struct device *dev) if (chans == NULL) return ERR_PTR(-ENOMEM); - /* Search for OF matches */ + /* Search for FW matches */ for (mapind = 0; mapind < nummaps; mapind++) { - ret = __of_iio_channel_get(&chans[mapind], dev->of_node, - mapind); + ret = __fwnode_iio_channel_get(&chans[mapind], fwnode, mapind); if (ret) goto error_free_chans; } @@ -331,15 +349,6 @@ error_free_chans: return ERR_PTR(ret); } -#else /* CONFIG_OF */ - -static inline struct iio_channel *of_iio_channel_get_all(struct device *dev) -{ - return ERR_PTR(-ENODEV); -} - -#endif /* CONFIG_OF */ - static struct iio_channel *iio_channel_get_sys(const char *name, const char *channel_name) { @@ -400,8 +409,8 @@ struct iio_channel *iio_channel_get(struct device *dev, struct iio_channel *channel; if (dev) { - channel = of_iio_channel_get_by_name(dev->of_node, - channel_name); + channel = fwnode_iio_channel_get_by_name(dev_fwnode(dev), + channel_name); if (!IS_ERR(channel) || PTR_ERR(channel) != -ENODEV) return channel; } @@ -442,14 +451,14 @@ struct iio_channel *devm_iio_channel_get(struct device *dev, } EXPORT_SYMBOL_GPL(devm_iio_channel_get); -struct iio_channel *devm_of_iio_channel_get_by_name(struct device *dev, - struct device_node *np, - const char *channel_name) +struct iio_channel *devm_fwnode_iio_channel_get_by_name(struct device *dev, + struct fwnode_handle *fwnode, + const char *channel_name) { struct iio_channel *channel; int ret; - channel = of_iio_channel_get_by_name(np, channel_name); + channel = fwnode_iio_channel_get_by_name(fwnode, channel_name); if (IS_ERR(channel)) return channel; @@ -459,7 +468,7 @@ struct iio_channel *devm_of_iio_channel_get_by_name(struct device *dev, return channel; } -EXPORT_SYMBOL_GPL(devm_of_iio_channel_get_by_name); +EXPORT_SYMBOL_GPL(devm_fwnode_iio_channel_get_by_name); struct iio_channel *iio_channel_get_all(struct device *dev) { @@ -473,7 +482,7 @@ struct iio_channel *iio_channel_get_all(struct device *dev) if (dev == NULL) return ERR_PTR(-EINVAL); - chans = of_iio_channel_get_all(dev); + chans = fwnode_iio_channel_get_all(dev); /* * We only want to carry on if the error is -ENODEV. Anything else * should be reported up the stack. diff --git a/include/linux/iio/consumer.h b/include/linux/iio/consumer.h index 5fa5957586cf..2adb1306da3e 100644 --- a/include/linux/iio/consumer.h +++ b/include/linux/iio/consumer.h @@ -7,6 +7,7 @@ #ifndef _IIO_INKERN_CONSUMER_H_ #define _IIO_INKERN_CONSUMER_H_ +#include #include #include @@ -14,6 +15,7 @@ struct iio_dev; struct iio_chan_spec; struct device; struct device_node; +struct fwnode_handle; /** * struct iio_channel - everything needed for a consumer to use a channel @@ -99,26 +101,20 @@ void iio_channel_release_all(struct iio_channel *chan); struct iio_channel *devm_iio_channel_get_all(struct device *dev); /** - * of_iio_channel_get_by_name() - get description of all that is needed to access channel. - * @np: Pointer to consumer device tree node + * fwnode_iio_channel_get_by_name() - get description of all that is needed to access channel. + * @fwnode: Pointer to consumer Firmware node * @consumer_channel: Unique name to identify the channel on the consumer * side. This typically describes the channels use within * the consumer. E.g. 'battery_voltage' */ -#ifdef CONFIG_OF -struct iio_channel *of_iio_channel_get_by_name(struct device_node *np, const char *name); -#else -static inline struct iio_channel * -of_iio_channel_get_by_name(struct device_node *np, const char *name) -{ - return NULL; -} -#endif +struct iio_channel *fwnode_iio_channel_get_by_name(struct fwnode_handle *fwnode, + const char *name); /** - * devm_of_iio_channel_get_by_name() - Resource managed version of of_iio_channel_get_by_name(). + * devm_fwnode_iio_channel_get_by_name() - Resource managed version of + * fwnode_iio_channel_get_by_name(). * @dev: Pointer to consumer device. - * @np: Pointer to consumer device tree node + * @fwnode: Pointer to consumer Firmware node * @consumer_channel: Unique name to identify the channel on the consumer * side. This typically describes the channels use within * the consumer. E.g. 'battery_voltage' @@ -129,9 +125,17 @@ of_iio_channel_get_by_name(struct device_node *np, const char *name) * The allocated iio channel is automatically released when the device is * unbound. */ -struct iio_channel *devm_of_iio_channel_get_by_name(struct device *dev, - struct device_node *np, - const char *consumer_channel); +struct iio_channel *devm_fwnode_iio_channel_get_by_name(struct device *dev, + struct fwnode_handle *fwnode, + const char *consumer_channel); + +static inline struct iio_channel +*devm_of_iio_channel_get_by_name(struct device *dev, struct device_node *np, + const char *consumer_channel) +{ + return devm_fwnode_iio_channel_get_by_name(dev, of_fwnode_handle(np), + consumer_channel); +} struct iio_cb_buffer; /** diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index 5dfbfc991c69..6002f8a0baf1 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -18,6 +18,7 @@ */ struct of_phandle_args; +struct fwnode_reference_args; enum iio_shared_by { IIO_SEPARATE, @@ -429,6 +430,8 @@ struct iio_trigger; /* forward declaration */ * provide a custom of_xlate function that reads the * *args* and returns the appropriate index in registered * IIO channels array. + * @fwnode_xlate: fwnode based function pointer to obtain channel specifier index. + * Functionally the same as @of_xlate. * @hwfifo_set_watermark: function pointer to set the current hardware * fifo watermark level; see hwfifo_* entries in * Documentation/ABI/testing/sysfs-bus-iio for details on @@ -510,6 +513,8 @@ struct iio_info { unsigned *readval); int (*of_xlate)(struct iio_dev *indio_dev, const struct of_phandle_args *iiospec); + int (*fwnode_xlate)(struct iio_dev *indio_dev, + const struct fwnode_reference_args *iiospec); int (*hwfifo_set_watermark)(struct iio_dev *indio_dev, unsigned val); int (*hwfifo_flush_to_buffer)(struct iio_dev *indio_dev, unsigned count); -- cgit v1.2.3 From b22bc4d6072e74b768c4c19e2ff3585ba5927904 Mon Sep 17 00:00:00 2001 From: Nuno Sá Date: Fri, 15 Jul 2022 14:29:02 +0200 Subject: iio: inkern: remove OF dependencies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since all users of the OF dependendent API are now converted to use the firmware agnostic alternative, we can drop OF dependencies from the IIO in kernel interface. Signed-off-by: Nuno Sá Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220715122903.332535-15-nuno.sa@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/inkern.c | 25 +------------------------ include/linux/iio/consumer.h | 10 ---------- include/linux/iio/iio.h | 3 --- 3 files changed, 1 insertion(+), 37 deletions(-) (limited to 'include') diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c index 9cfa66ef9536..b667790b6df9 100644 --- a/drivers/iio/inkern.c +++ b/drivers/iio/inkern.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include @@ -143,26 +142,6 @@ static int __fwnode_iio_simple_xlate(struct iio_dev *indio_dev, return iiospec->args[0]; } -/* - * Simple helper to copy fwnode_reference_args into of_phandle_args so we - * can pass it to of_xlate(). Ultimate goal is to drop this together with - * of_xlate(). - */ -static int __fwnode_to_of_xlate(struct iio_dev *indio_dev, - const struct fwnode_reference_args *iiospec) -{ - struct of_phandle_args of_args; - unsigned int i; - - of_args.args_count = iiospec->nargs; - of_args.np = to_of_node(iiospec->fwnode); - - for (i = 0; i < MAX_PHANDLE_ARGS; i++) - of_args.args[i] = i < iiospec->nargs ? iiospec->args[i] : 0; - - return indio_dev->info->of_xlate(indio_dev, &of_args); -} - static int __fwnode_iio_channel_get(struct iio_channel *channel, struct fwnode_handle *fwnode, int index) { @@ -185,9 +164,7 @@ static int __fwnode_iio_channel_get(struct iio_channel *channel, indio_dev = dev_to_iio_dev(idev); channel->indio_dev = indio_dev; - if (indio_dev->info->of_xlate) - index = __fwnode_to_of_xlate(indio_dev, &iiospec); - else if (indio_dev->info->fwnode_xlate) + if (indio_dev->info->fwnode_xlate) index = indio_dev->info->fwnode_xlate(indio_dev, &iiospec); else index = __fwnode_iio_simple_xlate(indio_dev, &iiospec); diff --git a/include/linux/iio/consumer.h b/include/linux/iio/consumer.h index 2adb1306da3e..6802596b017c 100644 --- a/include/linux/iio/consumer.h +++ b/include/linux/iio/consumer.h @@ -7,14 +7,12 @@ #ifndef _IIO_INKERN_CONSUMER_H_ #define _IIO_INKERN_CONSUMER_H_ -#include #include #include struct iio_dev; struct iio_chan_spec; struct device; -struct device_node; struct fwnode_handle; /** @@ -129,14 +127,6 @@ struct iio_channel *devm_fwnode_iio_channel_get_by_name(struct device *dev, struct fwnode_handle *fwnode, const char *consumer_channel); -static inline struct iio_channel -*devm_of_iio_channel_get_by_name(struct device *dev, struct device_node *np, - const char *consumer_channel) -{ - return devm_fwnode_iio_channel_get_by_name(dev, of_fwnode_handle(np), - consumer_channel); -} - struct iio_cb_buffer; /** * iio_channel_get_all_cb() - register callback for triggered capture diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index 6002f8a0baf1..f0ec8a5e5a7a 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -17,7 +17,6 @@ * Currently assumes nano seconds. */ -struct of_phandle_args; struct fwnode_reference_args; enum iio_shared_by { @@ -511,8 +510,6 @@ struct iio_info { int (*debugfs_reg_access)(struct iio_dev *indio_dev, unsigned reg, unsigned writeval, unsigned *readval); - int (*of_xlate)(struct iio_dev *indio_dev, - const struct of_phandle_args *iiospec); int (*fwnode_xlate)(struct iio_dev *indio_dev, const struct fwnode_reference_args *iiospec); int (*hwfifo_set_watermark)(struct iio_dev *indio_dev, unsigned val); -- cgit v1.2.3 From 5c64990b99aa91622cf044a9a2f7a78de8f770a2 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 26 Jun 2022 13:29:32 +0100 Subject: iio: core: Introduce _zeropoint for differential channels Address an ABI gap for device where the offset of both lines in a differential pair may be controlled so as to allow a wider range of inputs, but without having any direct effect of the differential measurement. _offset cannot be used as to remain in line with existing usage, userspace would be expected to apply it as (_raw + _offset) * _scale whereas _zeropoint is not. i.e. If we were computing the differential in software it would be. ((postive_raw + _zeropoint) - (negative_raw + zeropoint) + _offset) * _scale = ((postive_raw - negative_raw) + _offset) * _scale = (differential_raw + _offset) * _scale Similarly calibbias is expected to tweak the measurement seen, not the adjust the two lines of the differential pair. Needed for in_capacitanceX-capacitanceY_zeropoint for the AD7746 CDC driver. Signed-off-by: Jonathan Cameron Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220626122938.582107-12-jic23@kernel.org --- Documentation/ABI/testing/sysfs-bus-iio | 19 +++++++++++++++++++ drivers/iio/industrialio-core.c | 1 + include/linux/iio/types.h | 1 + 3 files changed, 21 insertions(+) (limited to 'include') diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 979f2e2b44f6..80e8a38d1ee2 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -207,6 +207,25 @@ Description: is required is a consistent labeling. Units after application of scale and offset are nanofarads. +What: /sys/.../iio:deviceX/in_capacitanceY-capacitanceZ_zeropoint +KernelVersion: 6.1 +Contact: linux-iio@vger.kernel.org +Description: + For differential channels, this an offset that is applied + equally to both inputs. As the reading is of the difference + between the two inputs, this should not be applied to the _raw + reading by userspace (unlike _offset) and unlike calibbias + it does not affect the differential value measured because + the effect of _zeropoint cancels out across the two inputs + that make up the differential pair. It's purpose is to bring + the individual signals, before the differential is measured, + within the measurement range of the device. The naming is + chosen because if the separate inputs that make the + differential pair are drawn on a graph in their + _raw units, this is the value that the zero point on the + measurement axis represents. It is expressed with the + same scaling as _raw. + What: /sys/bus/iio/devices/iio:deviceX/in_temp_raw What: /sys/bus/iio/devices/iio:deviceX/in_tempX_raw What: /sys/bus/iio/devices/iio:deviceX/in_temp_x_raw diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 40ebc63b7919..67d3d01d2dac 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -168,6 +168,7 @@ static const char * const iio_chan_info_postfix[] = { [IIO_CHAN_INFO_OVERSAMPLING_RATIO] = "oversampling_ratio", [IIO_CHAN_INFO_THERMOCOUPLE_TYPE] = "thermocouple_type", [IIO_CHAN_INFO_CALIBAMBIENT] = "calibambient", + [IIO_CHAN_INFO_ZEROPOINT] = "zeropoint", }; /** * iio_device_id() - query the unique ID for the device diff --git a/include/linux/iio/types.h b/include/linux/iio/types.h index a7aa91f3a8dc..27143b03909d 100644 --- a/include/linux/iio/types.h +++ b/include/linux/iio/types.h @@ -63,6 +63,7 @@ enum iio_chan_info_enum { IIO_CHAN_INFO_OVERSAMPLING_RATIO, IIO_CHAN_INFO_THERMOCOUPLE_TYPE, IIO_CHAN_INFO_CALIBAMBIENT, + IIO_CHAN_INFO_ZEROPOINT, }; #endif /* _IIO_TYPES_H_ */ -- cgit v1.2.3 From 680f8666baf6b4a6cc368dfff6614010ec23c51d Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Mon, 18 Jul 2022 14:14:08 +0200 Subject: interconnect: Make icc_provider_del() return void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All users ignore the return value of icc_provider_del(). Consequently make it not return an error code. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20220718121409.171773-8-u.kleine-koenig@pengutronix.de Signed-off-by: Georgi Djakov --- drivers/interconnect/core.c | 10 +++------- include/linux/interconnect-provider.h | 5 ++--- 2 files changed, 5 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/drivers/interconnect/core.c b/drivers/interconnect/core.c index 808f6e7a8048..25debded65a8 100644 --- a/drivers/interconnect/core.c +++ b/drivers/interconnect/core.c @@ -1057,29 +1057,25 @@ EXPORT_SYMBOL_GPL(icc_provider_add); /** * icc_provider_del() - delete previously added interconnect provider * @provider: the interconnect provider that will be removed from topology - * - * Return: 0 on success, or an error code otherwise */ -int icc_provider_del(struct icc_provider *provider) +void icc_provider_del(struct icc_provider *provider) { mutex_lock(&icc_lock); if (provider->users) { pr_warn("interconnect provider still has %d users\n", provider->users); mutex_unlock(&icc_lock); - return -EBUSY; + return; } if (!list_empty(&provider->nodes)) { pr_warn("interconnect provider still has nodes\n"); mutex_unlock(&icc_lock); - return -EBUSY; + return; } list_del(&provider->provider_list); mutex_unlock(&icc_lock); - - return 0; } EXPORT_SYMBOL_GPL(icc_provider_del); diff --git a/include/linux/interconnect-provider.h b/include/linux/interconnect-provider.h index 6bd01f7159c6..cd5c5a27557f 100644 --- a/include/linux/interconnect-provider.h +++ b/include/linux/interconnect-provider.h @@ -123,7 +123,7 @@ void icc_node_add(struct icc_node *node, struct icc_provider *provider); void icc_node_del(struct icc_node *node); int icc_nodes_remove(struct icc_provider *provider); int icc_provider_add(struct icc_provider *provider); -int icc_provider_del(struct icc_provider *provider); +void icc_provider_del(struct icc_provider *provider); struct icc_node_data *of_icc_get_from_provider(struct of_phandle_args *spec); void icc_sync_state(struct device *dev); @@ -172,9 +172,8 @@ static inline int icc_provider_add(struct icc_provider *provider) return -ENOTSUPP; } -static inline int icc_provider_del(struct icc_provider *provider) +static inline void icc_provider_del(struct icc_provider *provider) { - return -ENOTSUPP; } static inline struct icc_node_data *of_icc_get_from_provider(struct of_phandle_args *spec) -- cgit v1.2.3 From d2a4cbcb8bdc0e3d1cf85bf47a670695da0bc27a Mon Sep 17 00:00:00 2001 From: Dmitry Rokosov Date: Fri, 12 Aug 2022 16:52:26 +0000 Subject: units: complement the set of Hz units Currently, Hz units do not have milli, micro and nano Hz coefficients. Some drivers (IIO especially) use their analogues to calculate appropriate Hz values. This patch includes them to units.h definitions, so they can be used from different kernel places. Signed-off-by: Dmitry Rokosov Link: https://lore.kernel.org/r/20220812165243.22177-3-ddrokosov@sberdevices.ru Signed-off-by: Jonathan Cameron --- include/linux/units.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'include') diff --git a/include/linux/units.h b/include/linux/units.h index 681fc652e3d7..2793a41e73a2 100644 --- a/include/linux/units.h +++ b/include/linux/units.h @@ -20,6 +20,9 @@ #define PICO 1000000000000ULL #define FEMTO 1000000000000000ULL +#define NANOHZ_PER_HZ 1000000000UL +#define MICROHZ_PER_HZ 1000000UL +#define MILLIHZ_PER_HZ 1000UL #define HZ_PER_KHZ 1000UL #define KHZ_PER_MHZ 1000UL #define HZ_PER_MHZ 1000000UL -- cgit v1.2.3 From 1f5d7ea73c4b630dbb2c90818cb9fc0be54d2fe3 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 22 Aug 2022 17:49:23 +0000 Subject: lib/string_helpers: Add str_read_write() helper Add str_read_write() helper to return 'read' or 'write' string literal. Signed-off-by: Andy Shevchenko Signed-off-by: Dmitry Rokosov Link: https://lore.kernel.org/r/20220822175011.2886-2-ddrokosov@sberdevices.ru Signed-off-by: Jonathan Cameron --- include/linux/string_helpers.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'include') diff --git a/include/linux/string_helpers.h b/include/linux/string_helpers.h index 4d72258d42fd..9e22cd78f3b8 100644 --- a/include/linux/string_helpers.h +++ b/include/linux/string_helpers.h @@ -126,4 +126,9 @@ static inline const char *str_enabled_disabled(bool v) return v ? "enabled" : "disabled"; } +static inline const char *str_read_write(bool v) +{ + return v ? "read" : "write"; +} + #endif -- cgit v1.2.3 From b6df1cbb415e543f2908f9c59a8fb20714b86879 Mon Sep 17 00:00:00 2001 From: James Clark Date: Tue, 30 Aug 2022 18:26:10 +0100 Subject: coresight: Simplify sysfs accessors by using csdev_access abstraction The coresight_device struct is available in the sysfs accessor, and this contains a csdev_access struct which can be used to access registers. Use this instead of passing in the type of each drvdata so that a common function can be shared between all the cs drivers. No functional changes. Signed-off-by: James Clark Reviewed-by: Mike Leach Link: https://lore.kernel.org/r/20220830172614.340962-3-james.clark@arm.com Signed-off-by: Mathieu Poirier --- drivers/hwtracing/coresight/coresight-catu.c | 18 ++++++------ drivers/hwtracing/coresight/coresight-etb10.c | 19 ++++++------- .../hwtracing/coresight/coresight-etm3x-sysfs.c | 23 +++++++-------- drivers/hwtracing/coresight/coresight-priv.h | 14 ++++----- drivers/hwtracing/coresight/coresight-replicator.c | 7 ++--- drivers/hwtracing/coresight/coresight-stm.c | 27 ++++++++---------- drivers/hwtracing/coresight/coresight-tmc-core.c | 33 +++++++++------------- include/linux/coresight.h | 18 ++++++++++++ 8 files changed, 79 insertions(+), 80 deletions(-) (limited to 'include') diff --git a/drivers/hwtracing/coresight/coresight-catu.c b/drivers/hwtracing/coresight/coresight-catu.c index e0740c6dbd54..9d89c4054046 100644 --- a/drivers/hwtracing/coresight/coresight-catu.c +++ b/drivers/hwtracing/coresight/coresight-catu.c @@ -365,16 +365,14 @@ static const struct etr_buf_operations etr_catu_buf_ops = { .get_data = catu_get_data_etr_buf, }; -coresight_simple_reg32(struct catu_drvdata, devid, CORESIGHT_DEVID); -coresight_simple_reg32(struct catu_drvdata, control, CATU_CONTROL); -coresight_simple_reg32(struct catu_drvdata, status, CATU_STATUS); -coresight_simple_reg32(struct catu_drvdata, mode, CATU_MODE); -coresight_simple_reg32(struct catu_drvdata, axictrl, CATU_AXICTRL); -coresight_simple_reg32(struct catu_drvdata, irqen, CATU_IRQEN); -coresight_simple_reg64(struct catu_drvdata, sladdr, - CATU_SLADDRLO, CATU_SLADDRHI); -coresight_simple_reg64(struct catu_drvdata, inaddr, - CATU_INADDRLO, CATU_INADDRHI); +coresight_simple_reg32(devid, CORESIGHT_DEVID); +coresight_simple_reg32(control, CATU_CONTROL); +coresight_simple_reg32(status, CATU_STATUS); +coresight_simple_reg32(mode, CATU_MODE); +coresight_simple_reg32(axictrl, CATU_AXICTRL); +coresight_simple_reg32(irqen, CATU_IRQEN); +coresight_simple_reg64(sladdr, CATU_SLADDRLO, CATU_SLADDRHI); +coresight_simple_reg64(inaddr, CATU_INADDRLO, CATU_INADDRHI); static struct attribute *catu_mgmt_attrs[] = { &dev_attr_devid.attr, diff --git a/drivers/hwtracing/coresight/coresight-etb10.c b/drivers/hwtracing/coresight/coresight-etb10.c index efa39820acec..405bb3355cb1 100644 --- a/drivers/hwtracing/coresight/coresight-etb10.c +++ b/drivers/hwtracing/coresight/coresight-etb10.c @@ -655,17 +655,14 @@ static const struct file_operations etb_fops = { .llseek = no_llseek, }; -#define coresight_etb10_reg(name, offset) \ - coresight_simple_reg32(struct etb_drvdata, name, offset) - -coresight_etb10_reg(rdp, ETB_RAM_DEPTH_REG); -coresight_etb10_reg(sts, ETB_STATUS_REG); -coresight_etb10_reg(rrp, ETB_RAM_READ_POINTER); -coresight_etb10_reg(rwp, ETB_RAM_WRITE_POINTER); -coresight_etb10_reg(trg, ETB_TRG); -coresight_etb10_reg(ctl, ETB_CTL_REG); -coresight_etb10_reg(ffsr, ETB_FFSR); -coresight_etb10_reg(ffcr, ETB_FFCR); +coresight_simple_reg32(rdp, ETB_RAM_DEPTH_REG); +coresight_simple_reg32(sts, ETB_STATUS_REG); +coresight_simple_reg32(rrp, ETB_RAM_READ_POINTER); +coresight_simple_reg32(rwp, ETB_RAM_WRITE_POINTER); +coresight_simple_reg32(trg, ETB_TRG); +coresight_simple_reg32(ctl, ETB_CTL_REG); +coresight_simple_reg32(ffsr, ETB_FFSR); +coresight_simple_reg32(ffcr, ETB_FFCR); static struct attribute *coresight_etb_mgmt_attrs[] = { &dev_attr_rdp.attr, diff --git a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c index 68fcbf4ce7a8..12f8e8176c7e 100644 --- a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c @@ -1252,19 +1252,16 @@ static struct attribute *coresight_etm_attrs[] = { NULL, }; -#define coresight_etm3x_reg(name, offset) \ - coresight_simple_reg32(struct etm_drvdata, name, offset) - -coresight_etm3x_reg(etmccr, ETMCCR); -coresight_etm3x_reg(etmccer, ETMCCER); -coresight_etm3x_reg(etmscr, ETMSCR); -coresight_etm3x_reg(etmidr, ETMIDR); -coresight_etm3x_reg(etmcr, ETMCR); -coresight_etm3x_reg(etmtraceidr, ETMTRACEIDR); -coresight_etm3x_reg(etmteevr, ETMTEEVR); -coresight_etm3x_reg(etmtssvr, ETMTSSCR); -coresight_etm3x_reg(etmtecr1, ETMTECR1); -coresight_etm3x_reg(etmtecr2, ETMTECR2); +coresight_simple_reg32(etmccr, ETMCCR); +coresight_simple_reg32(etmccer, ETMCCER); +coresight_simple_reg32(etmscr, ETMSCR); +coresight_simple_reg32(etmidr, ETMIDR); +coresight_simple_reg32(etmcr, ETMCR); +coresight_simple_reg32(etmtraceidr, ETMTRACEIDR); +coresight_simple_reg32(etmteevr, ETMTEEVR); +coresight_simple_reg32(etmtssvr, ETMTSSCR); +coresight_simple_reg32(etmtecr1, ETMTECR1); +coresight_simple_reg32(etmtecr2, ETMTECR2); static struct attribute *coresight_etm_mgmt_attrs[] = { &dev_attr_etmccr.attr, diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h index f2458b794ef3..cf8ae768106e 100644 --- a/drivers/hwtracing/coresight/coresight-priv.h +++ b/drivers/hwtracing/coresight/coresight-priv.h @@ -40,23 +40,23 @@ #define ETM_MODE_EXCL_KERN BIT(30) #define ETM_MODE_EXCL_USER BIT(31) -#define __coresight_simple_show(type, name, lo_off, hi_off) \ +#define __coresight_simple_show(name, lo_off, hi_off) \ static ssize_t name##_show(struct device *_dev, \ struct device_attribute *attr, char *buf) \ { \ - type *drvdata = dev_get_drvdata(_dev->parent); \ + struct coresight_device *csdev = container_of(_dev, struct coresight_device, dev); \ u64 val; \ pm_runtime_get_sync(_dev->parent); \ - val = coresight_read_reg_pair(drvdata->base, lo_off, hi_off); \ + val = csdev_access_relaxed_read_pair(&csdev->access, lo_off, hi_off); \ pm_runtime_put_sync(_dev->parent); \ return scnprintf(buf, PAGE_SIZE, "0x%llx\n", val); \ } \ static DEVICE_ATTR_RO(name) -#define coresight_simple_reg32(type, name, offset) \ - __coresight_simple_show(type, name, offset, -1) -#define coresight_simple_reg64(type, name, lo_off, hi_off) \ - __coresight_simple_show(type, name, lo_off, hi_off) +#define coresight_simple_reg32(name, offset) \ + __coresight_simple_show(name, offset, -1) +#define coresight_simple_reg64(name, lo_off, hi_off) \ + __coresight_simple_show(name, lo_off, hi_off) extern const u32 coresight_barrier_pkt[4]; #define CORESIGHT_BARRIER_PKT_SIZE (sizeof(coresight_barrier_pkt)) diff --git a/drivers/hwtracing/coresight/coresight-replicator.c b/drivers/hwtracing/coresight/coresight-replicator.c index b86acbc74cf0..7cffcbb2ec42 100644 --- a/drivers/hwtracing/coresight/coresight-replicator.c +++ b/drivers/hwtracing/coresight/coresight-replicator.c @@ -196,11 +196,8 @@ static const struct coresight_ops replicator_cs_ops = { .link_ops = &replicator_link_ops, }; -#define coresight_replicator_reg(name, offset) \ - coresight_simple_reg32(struct replicator_drvdata, name, offset) - -coresight_replicator_reg(idfilter0, REPLICATOR_IDFILTER0); -coresight_replicator_reg(idfilter1, REPLICATOR_IDFILTER1); +coresight_simple_reg32(idfilter0, REPLICATOR_IDFILTER0); +coresight_simple_reg32(idfilter1, REPLICATOR_IDFILTER1); static struct attribute *replicator_mgmt_attrs[] = { &dev_attr_idfilter0.attr, diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c index bb14a3a8a921..4a31905604fe 100644 --- a/drivers/hwtracing/coresight/coresight-stm.c +++ b/drivers/hwtracing/coresight/coresight-stm.c @@ -634,21 +634,18 @@ static ssize_t traceid_store(struct device *dev, } static DEVICE_ATTR_RW(traceid); -#define coresight_stm_reg(name, offset) \ - coresight_simple_reg32(struct stm_drvdata, name, offset) - -coresight_stm_reg(tcsr, STMTCSR); -coresight_stm_reg(tsfreqr, STMTSFREQR); -coresight_stm_reg(syncr, STMSYNCR); -coresight_stm_reg(sper, STMSPER); -coresight_stm_reg(spter, STMSPTER); -coresight_stm_reg(privmaskr, STMPRIVMASKR); -coresight_stm_reg(spscr, STMSPSCR); -coresight_stm_reg(spmscr, STMSPMSCR); -coresight_stm_reg(spfeat1r, STMSPFEAT1R); -coresight_stm_reg(spfeat2r, STMSPFEAT2R); -coresight_stm_reg(spfeat3r, STMSPFEAT3R); -coresight_stm_reg(devid, CORESIGHT_DEVID); +coresight_simple_reg32(tcsr, STMTCSR); +coresight_simple_reg32(tsfreqr, STMTSFREQR); +coresight_simple_reg32(syncr, STMSYNCR); +coresight_simple_reg32(sper, STMSPER); +coresight_simple_reg32(spter, STMSPTER); +coresight_simple_reg32(privmaskr, STMPRIVMASKR); +coresight_simple_reg32(spscr, STMSPSCR); +coresight_simple_reg32(spmscr, STMSPMSCR); +coresight_simple_reg32(spfeat1r, STMSPFEAT1R); +coresight_simple_reg32(spfeat2r, STMSPFEAT2R); +coresight_simple_reg32(spfeat3r, STMSPFEAT3R); +coresight_simple_reg32(devid, CORESIGHT_DEVID); static struct attribute *coresight_stm_attrs[] = { &dev_attr_hwevent_enable.attr, diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c index d0276af82494..781d213526b7 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-core.c +++ b/drivers/hwtracing/coresight/coresight-tmc-core.c @@ -251,25 +251,20 @@ static enum tmc_mem_intf_width tmc_get_memwidth(u32 devid) return memwidth; } -#define coresight_tmc_reg(name, offset) \ - coresight_simple_reg32(struct tmc_drvdata, name, offset) -#define coresight_tmc_reg64(name, lo_off, hi_off) \ - coresight_simple_reg64(struct tmc_drvdata, name, lo_off, hi_off) - -coresight_tmc_reg(rsz, TMC_RSZ); -coresight_tmc_reg(sts, TMC_STS); -coresight_tmc_reg(trg, TMC_TRG); -coresight_tmc_reg(ctl, TMC_CTL); -coresight_tmc_reg(ffsr, TMC_FFSR); -coresight_tmc_reg(ffcr, TMC_FFCR); -coresight_tmc_reg(mode, TMC_MODE); -coresight_tmc_reg(pscr, TMC_PSCR); -coresight_tmc_reg(axictl, TMC_AXICTL); -coresight_tmc_reg(authstatus, TMC_AUTHSTATUS); -coresight_tmc_reg(devid, CORESIGHT_DEVID); -coresight_tmc_reg64(rrp, TMC_RRP, TMC_RRPHI); -coresight_tmc_reg64(rwp, TMC_RWP, TMC_RWPHI); -coresight_tmc_reg64(dba, TMC_DBALO, TMC_DBAHI); +coresight_simple_reg32(rsz, TMC_RSZ); +coresight_simple_reg32(sts, TMC_STS); +coresight_simple_reg32(trg, TMC_TRG); +coresight_simple_reg32(ctl, TMC_CTL); +coresight_simple_reg32(ffsr, TMC_FFSR); +coresight_simple_reg32(ffcr, TMC_FFCR); +coresight_simple_reg32(mode, TMC_MODE); +coresight_simple_reg32(pscr, TMC_PSCR); +coresight_simple_reg32(axictl, TMC_AXICTL); +coresight_simple_reg32(authstatus, TMC_AUTHSTATUS); +coresight_simple_reg32(devid, CORESIGHT_DEVID); +coresight_simple_reg64(rrp, TMC_RRP, TMC_RRPHI); +coresight_simple_reg64(rwp, TMC_RWP, TMC_RWPHI); +coresight_simple_reg64(dba, TMC_DBALO, TMC_DBAHI); static struct attribute *coresight_tmc_mgmt_attrs[] = { &dev_attr_rsz.attr, diff --git a/include/linux/coresight.h b/include/linux/coresight.h index 9f445f09fcfe..a47dd1f62216 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -372,6 +372,24 @@ static inline u32 csdev_access_relaxed_read32(struct csdev_access *csa, return csa->read(offset, true, false); } +static inline u64 csdev_access_relaxed_read_pair(struct csdev_access *csa, + s32 lo_offset, s32 hi_offset) +{ + u64 val; + + if (likely(csa->io_mem)) { + val = readl_relaxed(csa->base + lo_offset); + val |= (hi_offset < 0) ? 0 : + (u64)readl_relaxed(csa->base + hi_offset) << 32; + return val; + } + + val = csa->read(lo_offset, true, false); + val |= (hi_offset < 0) ? 0 : + (u64)csa->read(hi_offset, true, false) << 32; + return val; +} + static inline u32 csdev_access_read32(struct csdev_access *csa, u32 offset) { if (likely(csa->io_mem)) -- cgit v1.2.3 From 0a98181f805058773961c5ab3172ecf1bf1ed0e1 Mon Sep 17 00:00:00 2001 From: James Clark Date: Tue, 30 Aug 2022 18:26:13 +0100 Subject: coresight: Make new csdev_access offsets unsigned New csdev_access functions were added as part of the previous refactor. In order to make them more consistent with the existing ones, change any signed offset types to be unsigned. Now that they are unsigned, stop using hi_off = -1 to signify a single 32bit access. Instead just call the existing 32bit accessors. This is also applied to other parts of the codebase, and the coresight_{read,write}_reg_pair() functions can be deleted. Signed-off-by: James Clark Reviewed-by: Mike Leach Link: https://lore.kernel.org/r/20220830172614.340962-6-james.clark@arm.com Signed-off-by: Mathieu Poirier --- drivers/hwtracing/coresight/coresight-catu.h | 8 +++---- drivers/hwtracing/coresight/coresight-core.c | 18 ++++++++++++-- drivers/hwtracing/coresight/coresight-priv.h | 35 +++++++--------------------- drivers/hwtracing/coresight/coresight-tmc.h | 4 ++-- include/linux/coresight.h | 27 ++++++++++++--------- 5 files changed, 47 insertions(+), 45 deletions(-) (limited to 'include') diff --git a/drivers/hwtracing/coresight/coresight-catu.h b/drivers/hwtracing/coresight/coresight-catu.h index 6160c2d75a56..442e034bbfba 100644 --- a/drivers/hwtracing/coresight/coresight-catu.h +++ b/drivers/hwtracing/coresight/coresight-catu.h @@ -70,24 +70,24 @@ struct catu_drvdata { static inline u32 \ catu_read_##name(struct catu_drvdata *drvdata) \ { \ - return coresight_read_reg_pair(drvdata->base, offset, -1); \ + return csdev_access_relaxed_read32(&drvdata->csdev->access, offset); \ } \ static inline void \ catu_write_##name(struct catu_drvdata *drvdata, u32 val) \ { \ - coresight_write_reg_pair(drvdata->base, val, offset, -1); \ + csdev_access_relaxed_write32(&drvdata->csdev->access, val, offset); \ } #define CATU_REG_PAIR(name, lo_off, hi_off) \ static inline u64 \ catu_read_##name(struct catu_drvdata *drvdata) \ { \ - return coresight_read_reg_pair(drvdata->base, lo_off, hi_off); \ + return csdev_access_relaxed_read_pair(&drvdata->csdev->access, lo_off, hi_off); \ } \ static inline void \ catu_write_##name(struct catu_drvdata *drvdata, u64 val) \ { \ - coresight_write_reg_pair(drvdata->base, val, lo_off, hi_off); \ + csdev_access_relaxed_write_pair(&drvdata->csdev->access, val, lo_off, hi_off); \ } CATU_REG32(control, CATU_CONTROL); diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c index c63b2167a69f..d5dbc67bacb4 100644 --- a/drivers/hwtracing/coresight/coresight-core.c +++ b/drivers/hwtracing/coresight/coresight-core.c @@ -60,7 +60,7 @@ EXPORT_SYMBOL_GPL(coresight_barrier_pkt); static const struct cti_assoc_op *cti_assoc_ops; -ssize_t coresight_simple_show(struct device *_dev, +ssize_t coresight_simple_show_pair(struct device *_dev, struct device_attribute *attr, char *buf) { struct coresight_device *csdev = container_of(_dev, struct coresight_device, dev); @@ -72,7 +72,21 @@ ssize_t coresight_simple_show(struct device *_dev, pm_runtime_put_sync(_dev->parent); return sysfs_emit(buf, "0x%llx\n", val); } -EXPORT_SYMBOL_GPL(coresight_simple_show); +EXPORT_SYMBOL_GPL(coresight_simple_show_pair); + +ssize_t coresight_simple_show32(struct device *_dev, + struct device_attribute *attr, char *buf) +{ + struct coresight_device *csdev = container_of(_dev, struct coresight_device, dev); + struct cs_off_attribute *cs_attr = container_of(attr, struct cs_off_attribute, attr); + u64 val; + + pm_runtime_get_sync(_dev->parent); + val = csdev_access_relaxed_read32(&csdev->access, cs_attr->off); + pm_runtime_put_sync(_dev->parent); + return sysfs_emit(buf, "0x%llx\n", val); +} +EXPORT_SYMBOL_GPL(coresight_simple_show32); void coresight_set_cti_ops(const struct cti_assoc_op *cti_op) { diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h index c211979deca5..595ce5862056 100644 --- a/drivers/hwtracing/coresight/coresight-priv.h +++ b/drivers/hwtracing/coresight/coresight-priv.h @@ -41,8 +41,8 @@ #define ETM_MODE_EXCL_USER BIT(31) struct cs_pair_attribute { struct device_attribute attr; - s32 lo_off; - s32 hi_off; + u32 lo_off; + u32 hi_off; }; struct cs_off_attribute { @@ -50,21 +50,23 @@ struct cs_off_attribute { u32 off; }; -extern ssize_t coresight_simple_show(struct device *_dev, +extern ssize_t coresight_simple_show32(struct device *_dev, + struct device_attribute *attr, char *buf); +extern ssize_t coresight_simple_show_pair(struct device *_dev, struct device_attribute *attr, char *buf); #define coresight_simple_reg32(name, offset) \ - (&((struct cs_pair_attribute[]) { \ + (&((struct cs_off_attribute[]) { \ { \ - __ATTR(name, 0444, coresight_simple_show, NULL), \ - offset, -1 \ + __ATTR(name, 0444, coresight_simple_show32, NULL), \ + offset \ } \ })[0].attr.attr) #define coresight_simple_reg64(name, lo_off, hi_off) \ (&((struct cs_pair_attribute[]) { \ { \ - __ATTR(name, 0444, coresight_simple_show, NULL), \ + __ATTR(name, 0444, coresight_simple_show_pair, NULL), \ lo_off, hi_off \ } \ })[0].attr.attr) @@ -130,25 +132,6 @@ static inline void CS_UNLOCK(void __iomem *addr) } while (0); } -static inline u64 -coresight_read_reg_pair(void __iomem *addr, s32 lo_offset, s32 hi_offset) -{ - u64 val; - - val = readl_relaxed(addr + lo_offset); - val |= (hi_offset < 0) ? 0 : - (u64)readl_relaxed(addr + hi_offset) << 32; - return val; -} - -static inline void coresight_write_reg_pair(void __iomem *addr, u64 val, - s32 lo_offset, s32 hi_offset) -{ - writel_relaxed((u32)val, addr + lo_offset); - if (hi_offset >= 0) - writel_relaxed((u32)(val >> 32), addr + hi_offset); -} - void coresight_disable_path(struct list_head *path); int coresight_enable_path(struct list_head *path, u32 mode, void *sink_data); struct coresight_device *coresight_get_sink(struct list_head *path); diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h index 6bec20a392b3..66959557cf39 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.h +++ b/drivers/hwtracing/coresight/coresight-tmc.h @@ -282,12 +282,12 @@ ssize_t tmc_etr_get_sysfs_trace(struct tmc_drvdata *drvdata, static inline u64 \ tmc_read_##name(struct tmc_drvdata *drvdata) \ { \ - return coresight_read_reg_pair(drvdata->base, lo_off, hi_off); \ + return csdev_access_relaxed_read_pair(&drvdata->csdev->access, lo_off, hi_off); \ } \ static inline void \ tmc_write_##name(struct tmc_drvdata *drvdata, u64 val) \ { \ - coresight_write_reg_pair(drvdata->base, val, lo_off, hi_off); \ + csdev_access_relaxed_write_pair(&drvdata->csdev->access, val, lo_off, hi_off); \ } TMC_REG_PAIR(rrp, TMC_RRP, TMC_RRPHI) diff --git a/include/linux/coresight.h b/include/linux/coresight.h index a47dd1f62216..1554021231f9 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -373,21 +373,26 @@ static inline u32 csdev_access_relaxed_read32(struct csdev_access *csa, } static inline u64 csdev_access_relaxed_read_pair(struct csdev_access *csa, - s32 lo_offset, s32 hi_offset) + u32 lo_offset, u32 hi_offset) { - u64 val; - if (likely(csa->io_mem)) { - val = readl_relaxed(csa->base + lo_offset); - val |= (hi_offset < 0) ? 0 : - (u64)readl_relaxed(csa->base + hi_offset) << 32; - return val; + return readl_relaxed(csa->base + lo_offset) | + ((u64)readl_relaxed(csa->base + hi_offset) << 32); } - val = csa->read(lo_offset, true, false); - val |= (hi_offset < 0) ? 0 : - (u64)csa->read(hi_offset, true, false) << 32; - return val; + return csa->read(lo_offset, true, false) | (csa->read(hi_offset, true, false) << 32); +} + +static inline void csdev_access_relaxed_write_pair(struct csdev_access *csa, u64 val, + u32 lo_offset, u32 hi_offset) +{ + if (likely(csa->io_mem)) { + writel_relaxed((u32)val, csa->base + lo_offset); + writel_relaxed((u32)(val >> 32), csa->base + hi_offset); + } else { + csa->write((u32)val, lo_offset, true, false); + csa->write((u32)(val >> 32), hi_offset, true, false); + } } static inline u32 csdev_access_read32(struct csdev_access *csa, u32 offset) -- cgit v1.2.3 From 2bc9cd66eb25d0fefbb081421d6586495e25840e Mon Sep 17 00:00:00 2001 From: Vincent Whitchurch Date: Mon, 29 Aug 2022 11:18:40 +0200 Subject: iio: Use per-device lockdep class for mlock If an IIO driver uses callbacks from another IIO driver and calls iio_channel_start_all_cb() from one of its buffer setup ops, then lockdep complains due to the lock nesting, as in the below example with lmp91000. Since the locks are being taken on different IIO devices, there is no actual deadlock. Fix the warning by telling lockdep to use a different class for each iio_device. ============================================ WARNING: possible recursive locking detected -------------------------------------------- python3/23 is trying to acquire lock: (&indio_dev->mlock){+.+.}-{3:3}, at: iio_update_buffers but task is already holding lock: (&indio_dev->mlock){+.+.}-{3:3}, at: enable_store other info that might help us debug this: Possible unsafe locking scenario: CPU0 ---- lock(&indio_dev->mlock); lock(&indio_dev->mlock); *** DEADLOCK *** May be due to missing lock nesting notation 5 locks held by python3/23: #0: (sb_writers#5){.+.+}-{0:0}, at: ksys_write #1: (&of->mutex){+.+.}-{3:3}, at: kernfs_fop_write_iter #2: (kn->active#14){.+.+}-{0:0}, at: kernfs_fop_write_iter #3: (&indio_dev->mlock){+.+.}-{3:3}, at: enable_store #4: (&iio_dev_opaque->info_exist_lock){+.+.}-{3:3}, at: iio_update_buffers Call Trace: __mutex_lock iio_update_buffers iio_channel_start_all_cb lmp91000_buffer_postenable __iio_update_buffers enable_store Fixes: 67e17300dc1d76 ("iio: potentiostat: add LMP91000 support") Signed-off-by: Vincent Whitchurch Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220829091840.2791846-1-vincent.whitchurch@axis.com Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-core.c | 5 +++++ include/linux/iio/iio-opaque.h | 2 ++ 2 files changed, 7 insertions(+) (limited to 'include') diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index d38623c046cc..583e0e5205a0 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -1626,6 +1626,8 @@ static void iio_dev_release(struct device *device) iio_device_detach_buffers(indio_dev); + lockdep_unregister_key(&iio_dev_opaque->mlock_key); + ida_free(&iio_ida, iio_dev_opaque->id); kfree(iio_dev_opaque); } @@ -1685,6 +1687,9 @@ struct iio_dev *iio_device_alloc(struct device *parent, int sizeof_priv) INIT_LIST_HEAD(&iio_dev_opaque->buffer_list); INIT_LIST_HEAD(&iio_dev_opaque->ioctl_handlers); + lockdep_register_key(&iio_dev_opaque->mlock_key); + lockdep_set_class(&indio_dev->mlock, &iio_dev_opaque->mlock_key); + return indio_dev; } EXPORT_SYMBOL(iio_device_alloc); diff --git a/include/linux/iio/iio-opaque.h b/include/linux/iio/iio-opaque.h index 6b3586b3f952..d1f8b30a7c8b 100644 --- a/include/linux/iio/iio-opaque.h +++ b/include/linux/iio/iio-opaque.h @@ -11,6 +11,7 @@ * checked by device drivers but should be considered * read-only as this is a core internal bit * @driver_module: used to make it harder to undercut users + * @mlock_key: lockdep class for iio_dev lock * @info_exist_lock: lock to prevent use during removal * @trig_readonly: mark the current trigger immutable * @event_interface: event chrdevs associated with interrupt lines @@ -42,6 +43,7 @@ struct iio_dev_opaque { int currentmode; int id; struct module *driver_module; + struct lock_class_key mlock_key; struct mutex info_exist_lock; bool trig_readonly; struct iio_event_interface *event_interface; -- cgit v1.2.3 From 835e699ef82adfc85ac4cc3f1f237c1adfdefd20 Mon Sep 17 00:00:00 2001 From: Jagath Jog J Date: Wed, 31 Aug 2022 12:01:16 +0530 Subject: iio: Add new event type gesture and use direction for single and double tap Add new event type for tap called gesture and the direction can be used to differentiate single and double tap. This may be used by accelerometer sensors to express single and double tap events. For directional tap, modifiers like IIO_MOD_(X/Y/Z) can be used along with singletap and doubletap direction. Signed-off-by: Jagath Jog J Link: https://lore.kernel.org/r/20220831063117.4141-2-jagathjog1996@gmail.com Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio | 69 +++++++++++++++++++++++++++++++++ drivers/iio/industrialio-event.c | 7 +++- include/linux/iio/types.h | 2 + include/uapi/linux/iio/types.h | 3 ++ tools/iio/iio_event_monitor.c | 8 +++- 5 files changed, 87 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 80e8a38d1ee2..66e81c48ee21 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -2068,3 +2068,72 @@ Description: individual channels. If multiple channels are enabled in a scan, then the sampling_frequency of the scan may be computed from the per channel sampling frequencies. + +What: /sys/.../events/in_accel_gesture_singletap_en +What: /sys/.../events/in_accel_gesture_doubletap_en +KernelVersion: 6.1 +Contact: linux-iio@vger.kernel.org +Description: + Device generates an event on a single or double tap. + +What: /sys/.../events/in_accel_gesture_singletap_value +What: /sys/.../events/in_accel_gesture_doubletap_value +KernelVersion: 6.1 +Contact: linux-iio@vger.kernel.org +Description: + Specifies the threshold value that the device is comparing + against to generate the tap gesture event. The lower + threshold value increases the sensitivity of tap detection. + Units and the exact meaning of value are device-specific. + +What: /sys/.../events/in_accel_gesture_tap_value_available +KernelVersion: 6.1 +Contact: linux-iio@vger.kernel.org +Description: + Lists all available threshold values which can be used to + modify the sensitivity of the tap detection. + +What: /sys/.../events/in_accel_gesture_singletap_reset_timeout +What: /sys/.../events/in_accel_gesture_doubletap_reset_timeout +KernelVersion: 6.1 +Contact: linux-iio@vger.kernel.org +Description: + Specifies the timeout value in seconds for the tap detector + to not to look for another tap event after the event as + occurred. Basically the minimum quiet time between the two + single-tap's or two double-tap's. + +What: /sys/.../events/in_accel_gesture_tap_reset_timeout_available +KernelVersion: 6.1 +Contact: linux-iio@vger.kernel.org +Description: + Lists all available tap reset timeout values. Units in seconds. + +What: /sys/.../events/in_accel_gesture_doubletap_tap2_min_delay +KernelVersion: 6.1 +Contact: linux-iio@vger.kernel.org +Description: + Specifies the minimum quiet time in seconds between the two + taps of a double tap. + +What: /sys/.../events/in_accel_gesture_doubletap_tap2_min_delay_available +KernelVersion: 6.1 +Contact: linux-iio@vger.kernel.org +Description: + Lists all available delay values between two taps in the double + tap. Units in seconds. + +What: /sys/.../events/in_accel_gesture_tap_maxtomin_time +KernelVersion: 6.1 +Contact: linux-iio@vger.kernel.org +Description: + Specifies the maximum time difference allowed between upper + and lower peak of tap to consider it as the valid tap event. + Units in seconds. + +What: /sys/.../events/in_accel_gesture_tap_maxtomin_time_available +KernelVersion: 6.1 +Contact: linux-iio@vger.kernel.org +Description: + Lists all available time values between upper peak to lower + peak. Units in seconds. diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c index 0e2056894965..3d78da2531a9 100644 --- a/drivers/iio/industrialio-event.c +++ b/drivers/iio/industrialio-event.c @@ -231,12 +231,15 @@ static const char * const iio_ev_type_text[] = { [IIO_EV_TYPE_MAG_ADAPTIVE] = "mag_adaptive", [IIO_EV_TYPE_CHANGE] = "change", [IIO_EV_TYPE_MAG_REFERENCED] = "mag_referenced", + [IIO_EV_TYPE_GESTURE] = "gesture", }; static const char * const iio_ev_dir_text[] = { [IIO_EV_DIR_EITHER] = "either", [IIO_EV_DIR_RISING] = "rising", - [IIO_EV_DIR_FALLING] = "falling" + [IIO_EV_DIR_FALLING] = "falling", + [IIO_EV_DIR_SINGLETAP] = "singletap", + [IIO_EV_DIR_DOUBLETAP] = "doubletap", }; static const char * const iio_ev_info_text[] = { @@ -247,6 +250,8 @@ static const char * const iio_ev_info_text[] = { [IIO_EV_INFO_HIGH_PASS_FILTER_3DB] = "high_pass_filter_3db", [IIO_EV_INFO_LOW_PASS_FILTER_3DB] = "low_pass_filter_3db", [IIO_EV_INFO_TIMEOUT] = "timeout", + [IIO_EV_INFO_RESET_TIMEOUT] = "reset_timeout", + [IIO_EV_INFO_TAP2_MIN_DELAY] = "tap2_min_delay", }; static enum iio_event_direction iio_ev_attr_dir(struct iio_dev_attr *attr) diff --git a/include/linux/iio/types.h b/include/linux/iio/types.h index 27143b03909d..82faa98c719a 100644 --- a/include/linux/iio/types.h +++ b/include/linux/iio/types.h @@ -17,6 +17,8 @@ enum iio_event_info { IIO_EV_INFO_HIGH_PASS_FILTER_3DB, IIO_EV_INFO_LOW_PASS_FILTER_3DB, IIO_EV_INFO_TIMEOUT, + IIO_EV_INFO_RESET_TIMEOUT, + IIO_EV_INFO_TAP2_MIN_DELAY, }; #define IIO_VAL_INT 1 diff --git a/include/uapi/linux/iio/types.h b/include/uapi/linux/iio/types.h index 472cead10d8d..913864221ac4 100644 --- a/include/uapi/linux/iio/types.h +++ b/include/uapi/linux/iio/types.h @@ -105,6 +105,7 @@ enum iio_event_type { IIO_EV_TYPE_MAG_ADAPTIVE, IIO_EV_TYPE_CHANGE, IIO_EV_TYPE_MAG_REFERENCED, + IIO_EV_TYPE_GESTURE, }; enum iio_event_direction { @@ -112,6 +113,8 @@ enum iio_event_direction { IIO_EV_DIR_RISING, IIO_EV_DIR_FALLING, IIO_EV_DIR_NONE, + IIO_EV_DIR_SINGLETAP, + IIO_EV_DIR_DOUBLETAP, }; #endif /* _UAPI_IIO_TYPES_H_ */ diff --git a/tools/iio/iio_event_monitor.c b/tools/iio/iio_event_monitor.c index 2f4581658859..b3b3ea399f67 100644 --- a/tools/iio/iio_event_monitor.c +++ b/tools/iio/iio_event_monitor.c @@ -69,12 +69,15 @@ static const char * const iio_ev_type_text[] = { [IIO_EV_TYPE_MAG_ADAPTIVE] = "mag_adaptive", [IIO_EV_TYPE_CHANGE] = "change", [IIO_EV_TYPE_MAG_REFERENCED] = "mag_referenced", + [IIO_EV_TYPE_GESTURE] = "gesture", }; static const char * const iio_ev_dir_text[] = { [IIO_EV_DIR_EITHER] = "either", [IIO_EV_DIR_RISING] = "rising", - [IIO_EV_DIR_FALLING] = "falling" + [IIO_EV_DIR_FALLING] = "falling", + [IIO_EV_DIR_SINGLETAP] = "singletap", + [IIO_EV_DIR_DOUBLETAP] = "doubletap", }; static const char * const iio_modifier_names[] = { @@ -227,6 +230,7 @@ static bool event_is_known(struct iio_event_data *event) case IIO_EV_TYPE_THRESH_ADAPTIVE: case IIO_EV_TYPE_MAG_ADAPTIVE: case IIO_EV_TYPE_CHANGE: + case IIO_EV_TYPE_GESTURE: break; default: return false; @@ -236,6 +240,8 @@ static bool event_is_known(struct iio_event_data *event) case IIO_EV_DIR_EITHER: case IIO_EV_DIR_RISING: case IIO_EV_DIR_FALLING: + case IIO_EV_DIR_SINGLETAP: + case IIO_EV_DIR_DOUBLETAP: case IIO_EV_DIR_NONE: break; default: -- cgit v1.2.3 From f25a72b8b9f4885ea30263a02d1083e283c9e718 Mon Sep 17 00:00:00 2001 From: Bharat Jauhari Date: Wed, 1 Jun 2022 15:18:47 +0300 Subject: habanalabs: fix spelling mistakes Cosmetic commit, no logical changes. It just fixes the spelling mistakes. Signed-off-by: Bharat Jauhari Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/firmware_if.c | 8 ++++---- drivers/misc/habanalabs/common/habanalabs.h | 27 +++++++++++++-------------- drivers/misc/habanalabs/common/memory_mgr.c | 10 +++++----- include/uapi/misc/habanalabs.h | 10 +++++----- 4 files changed, 27 insertions(+), 28 deletions(-) (limited to 'include') diff --git a/drivers/misc/habanalabs/common/firmware_if.c b/drivers/misc/habanalabs/common/firmware_if.c index 608ca67527a5..58c1eff16df6 100644 --- a/drivers/misc/habanalabs/common/firmware_if.c +++ b/drivers/misc/habanalabs/common/firmware_if.c @@ -1514,7 +1514,7 @@ int hl_fw_read_preboot_status(struct hl_device *hdev) hdev->asic_funcs->init_firmware_preload_params(hdev); /* - * In order to determine boot method (static VS dymanic) we need to + * In order to determine boot method (static VS dynamic) we need to * read the boot caps register */ rc = hl_fw_read_preboot_caps(hdev); @@ -1781,7 +1781,7 @@ int hl_fw_dynamic_send_protocol_cmd(struct hl_device *hdev, * * @return the CRC32 result * - * NOTE: kernel's CRC32 differ's from standard CRC32 calculation. + * NOTE: kernel's CRC32 differs from standard CRC32 calculation. * in order to be aligned we need to flip the bits of both the input * initial CRC and kernel's CRC32 result. * in addition both sides use initial CRC of 0, @@ -1798,7 +1798,7 @@ static u32 hl_fw_compat_crc32(u8 *data, size_t size) * * @hdev: pointer to the habanalabs device structure * @addr: device address of memory transfer - * @size: memory transter size + * @size: memory transfer size * @region: PCI memory region * * @return 0 on success, otherwise non-zero error code @@ -2547,7 +2547,7 @@ static int hl_fw_dynamic_init_cpu(struct hl_device *hdev, /* * when testing FW load (without Linux) on PLDM we don't want to * wait until boot fit is active as it may take several hours. - * instead, we load the bootfit and let it do all initializations in + * instead, we load the bootfit and let it do all initialization in * the background. */ if (hdev->pldm && !(hdev->fw_components & FW_TYPE_LINUX)) diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index 8c2c94fb1322..350bc5b9f174 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -94,7 +94,7 @@ struct hl_fpriv; #define MMU_HASH_TABLE_BITS 7 /* 1 << 7 buckets */ /** - * enum hl_mmu_page_table_locaion - mmu page table location + * enum hl_mmu_page_table_location - mmu page table location * @MMU_DR_PGT: page-table is located on device DRAM. * @MMU_HR_PGT: page-table is located on host memory. * @MMU_NUM_PGT_LOCATIONS: number of page-table locations currently supported. @@ -800,7 +800,7 @@ struct hl_fence { * @lock: spinlock to protect fence. * @hdev: habanalabs device structure. * @hw_sob: the H/W SOB used in this signal/wait CS. - * @encaps_sig_hdl: encaps signals hanlder. + * @encaps_sig_hdl: encaps signals handler. * @cs_seq: command submission sequence number. * @type: type of the CS - signal/wait. * @sob_val: the SOB value that is used in this signal/wait CS. @@ -908,7 +908,7 @@ struct hl_mmap_mem_buf { * @size: holds the CB's size. * @cs_cnt: holds number of CS that this CB participates in. * @is_pool: true if CB was acquired from the pool, false otherwise. - * @is_internal: internaly allocated + * @is_internal: internally allocated * @is_mmu_mapped: true if the CB is mapped to the device's MMU. */ struct hl_cb { @@ -1116,7 +1116,7 @@ struct timestamp_reg_info { * @fence: hl fence object for interrupt completion * @cq_target_value: CQ target value * @cq_kernel_addr: CQ kernel address, to be used in the cq interrupt - * handler for taget value comparison + * handler for target value comparison */ struct hl_user_pending_interrupt { struct timestamp_reg_info ts_reg_info; @@ -1742,10 +1742,10 @@ struct hl_cs_outcome { /** * struct hl_cs_outcome_store - represents a limited store of completed CS outcomes - * @outcome_map: index of completed CS searcheable by sequence number + * @outcome_map: index of completed CS searchable by sequence number * @used_list: list of outcome objects currently in use * @free_list: list of outcome objects currently not in use - * @nodes_pool: a static pool of preallocated outcome objects + * @nodes_pool: a static pool of pre-allocated outcome objects * @db_lock: any operation on the store must take this lock */ struct hl_cs_outcome_store { @@ -1769,7 +1769,7 @@ struct hl_cs_outcome_store { * @refcount: reference counter for the context. Context is released only when * this hits 0l. It is incremented on CS and CS_WAIT. * @cs_pending: array of hl fence objects representing pending CS. - * @outcome_store: storage data structure used to remember ouitcomes of completed + * @outcome_store: storage data structure used to remember outcomes of completed * command submissions for a long time after CS id wraparound. * @va_range: holds available virtual addresses for host and dram mappings. * @mem_hash_lock: protects the mem_hash. @@ -1838,7 +1838,6 @@ struct hl_ctx_mgr { }; - /* * COMMAND SUBMISSIONS */ @@ -1904,7 +1903,7 @@ struct hl_userptr { * @tdr_active: true if TDR was activated for this CS (to prevent * double TDR activation). * @aborted: true if CS was aborted due to some device error. - * @timestamp: true if a timestmap must be captured upon completion. + * @timestamp: true if a timestamp must be captured upon completion. * @staged_last: true if this is the last staged CS and needs completion. * @staged_first: true if this is the first staged CS and we need to receive * timeout for this CS. @@ -2229,7 +2228,7 @@ struct hl_info_list { /** * struct hl_debugfs_entry - debugfs dentry wrapper. - * @info_ent: dentry realted ops. + * @info_ent: dentry related ops. * @dev_entry: ASIC specific debugfs manager. */ struct hl_debugfs_entry { @@ -2934,7 +2933,7 @@ struct razwi_info { * struct undefined_opcode_info - info about last undefined opcode error * @timestamp: timestamp of the undefined opcode error * @cb_addr_streams: CB addresses (per stream) that are currently exists in the PQ - * entiers. In case all streams array entries are + * entries. In case all streams array entries are * filled with values, it means the execution was in Lower-CP. * @cq_addr: the address of the current handled command buffer * @cq_size: the size of the current handled command buffer @@ -2975,7 +2974,7 @@ struct last_error_session_info { /** * struct hl_reset_info - holds current device reset information. * @lock: lock to protect critical reset flows. - * @compute_reset_cnt: number of compte resets since the driver was loaded. + * @compute_reset_cnt: number of compute resets since the driver was loaded. * @hard_reset_cnt: number of hard resets since the driver was loaded. * @hard_reset_schedule_flags: hard reset is scheduled to after current compute reset, * here we hold the hard reset flags. @@ -2986,7 +2985,7 @@ struct last_error_session_info { * @hard_reset_pending: is there a hard reset work pending. * @curr_reset_cause: saves an enumerated reset cause when a hard reset is * triggered, and cleared after it is shared with preboot. - * @prev_reset_trigger: saves the previous trigger which caused a reset, overidden + * @prev_reset_trigger: saves the previous trigger which caused a reset, overridden * with a new value on next reset * @reset_trigger_repeated: set if device reset is triggered more than once with * same cause. @@ -3064,7 +3063,7 @@ struct hl_reset_info { * @hl_chip_info: ASIC's sensors information. * @device_status_description: device status description. * @hl_debugfs: device's debugfs manager. - * @cb_pool: list of preallocated CBs. + * @cb_pool: list of pre allocated CBs. * @cb_pool_lock: protects the CB pool. * @internal_cb_pool_virt_addr: internal command buffer pool virtual address. * @internal_cb_pool_dma_addr: internal command buffer pool dma address. diff --git a/drivers/misc/habanalabs/common/memory_mgr.c b/drivers/misc/habanalabs/common/memory_mgr.c index 56df962d2f3c..1936d653699e 100644 --- a/drivers/misc/habanalabs/common/memory_mgr.c +++ b/drivers/misc/habanalabs/common/memory_mgr.c @@ -11,7 +11,7 @@ * hl_mmap_mem_buf_get - increase the buffer refcount and return a pointer to * the buffer descriptor. * - * @mmg: parent unifed memory manager + * @mmg: parent unified memory manager * @handle: requested buffer handle * * Find the buffer in the store and return a pointer to its descriptor. @@ -104,7 +104,7 @@ int hl_mmap_mem_buf_put(struct hl_mmap_mem_buf *buf) * hl_mmap_mem_buf_put_handle - decrease the reference to the buffer with the * given handle. * - * @mmg: parent unifed memory manager + * @mmg: parent unified memory manager * @handle: requested buffer handle * * Decrease the reference to the buffer, and release it if it was the last one. @@ -137,7 +137,7 @@ int hl_mmap_mem_buf_put_handle(struct hl_mem_mgr *mmg, u64 handle) /** * hl_mmap_mem_buf_alloc - allocate a new mappable buffer * - * @mmg: parent unifed memory manager + * @mmg: parent unified memory manager * @behavior: behavior object describing this buffer polymorphic behavior * @gfp: gfp flags to use for the memory allocations * @args: additional args passed to behavior->alloc @@ -222,7 +222,7 @@ static const struct vm_operations_struct hl_mmap_mem_buf_vm_ops = { /** * hl_mem_mgr_mmap - map the given buffer to the user * - * @mmg: unifed memory manager + * @mmg: unified memory manager * @vma: the vma object for which mmap was closed. * @args: additional args passed to behavior->mmap * @@ -322,7 +322,7 @@ void hl_mem_mgr_init(struct device *dev, struct hl_mem_mgr *mmg) /** * hl_mem_mgr_fini - release unified memory manager * - * @mmg: parent unifed memory manager + * @mmg: parent unified memory manager * * Release the unified memory manager. Shall be called from an interrupt context. */ diff --git a/include/uapi/misc/habanalabs.h b/include/uapi/misc/habanalabs.h index 5d06d5c74dd1..be06b1307c44 100644 --- a/include/uapi/misc/habanalabs.h +++ b/include/uapi/misc/habanalabs.h @@ -876,13 +876,13 @@ struct hl_info_hw_idle { __u32 is_idle; /* * Bitmask of busy engines. - * Bits definition is according to `enum _enging_id'. + * Bits definition is according to `enum _engine_id'. */ __u32 busy_engines_mask; /* * Extended Bitmask of busy engines. - * Bits definition is according to `enum _enging_id'. + * Bits definition is according to `enum _engine_id'. */ __u64 busy_engines_mask_ext[HL_BUSY_ENGINES_MASK_EXT_SIZE]; }; @@ -1078,12 +1078,12 @@ struct hl_info_razwi_event { * struct hl_info_undefined_opcode_event - info about last undefined opcode error * @timestamp: timestamp of the undefined opcode error * @cb_addr_streams: CB addresses (per stream) that are currently exists in the PQ - * entiers. In case all streams array entries are + * entries. In case all streams array entries are * filled with values, it means the execution was in Lower-CP. * @cq_addr: the address of the current handled command buffer * @cq_size: the size of the current handled command buffer * @cb_addr_streams_len: num of streams - actual len of cb_addr_streams array. - * should be equal to 1 incase of undefined opcode + * should be equal to 1 in case of undefined opcode * in Upper-CP (specific stream) and equal to 4 incase * of undefined opcode in Lower-CP. * @engine_id: engine-id that the error occurred on @@ -1412,7 +1412,7 @@ struct hl_cs_out { /* Valid only when HL_CS_FLAGS_RESERVE_SIGNALS_ONLY is set */ struct { - /* This is the resereved signal handle id */ + /* This is the reserved signal handle id */ __u32 handle_id; /* This is the signals count */ -- cgit v1.2.3 From f018c54e3de6619c46e33ab1c613761e9fba21d0 Mon Sep 17 00:00:00 2001 From: Dani Liberman Date: Sat, 9 Jul 2022 12:34:17 +0300 Subject: habanalabs: add uapi to retrieve engines status Currently, to get engines status, user needed to read debugfs file with root permissions. This new uapi allows user apace apps retrieve status, so for example, in case of failure, status can be retrieved immediately by the application itself which runs without root permissions. Signed-off-by: Dani Liberman Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/debugfs.c | 3 +- drivers/misc/habanalabs/common/habanalabs_ioctl.c | 40 +++++++++++++++++++++++ include/uapi/misc/habanalabs.h | 9 +++++ 3 files changed, 50 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/drivers/misc/habanalabs/common/debugfs.c b/drivers/misc/habanalabs/common/debugfs.c index 90c91c1b2c10..c297248748d3 100644 --- a/drivers/misc/habanalabs/common/debugfs.c +++ b/drivers/misc/habanalabs/common/debugfs.c @@ -17,7 +17,6 @@ #define MMU_ASID_BUF_SIZE 10 #define MMU_KBUF_SIZE (MMU_ADDR_BUF_SIZE + MMU_ASID_BUF_SIZE) #define I2C_MAX_TRANSACTION_LEN 8 -#define ENGINES_DATA_MAX_SIZE SZ_16K static struct dentry *hl_debug_root; @@ -626,7 +625,7 @@ static int engines_show(struct seq_file *s, void *data) } eng_data.actual_size = 0; - eng_data.allocated_buf_size = ENGINES_DATA_MAX_SIZE; + eng_data.allocated_buf_size = HL_ENGINES_DATA_MAX_SIZE; eng_data.buf = vmalloc(eng_data.allocated_buf_size); if (!eng_data.buf) return -ENOMEM; diff --git a/drivers/misc/habanalabs/common/habanalabs_ioctl.c b/drivers/misc/habanalabs/common/habanalabs_ioctl.c index 6a30bd98ab5e..ec55c66fedd6 100644 --- a/drivers/misc/habanalabs/common/habanalabs_ioctl.c +++ b/drivers/misc/habanalabs/common/habanalabs_ioctl.c @@ -14,6 +14,7 @@ #include #include #include +#include static u32 hl_debug_struct_size[HL_DEBUG_OP_TIMESTAMP + 1] = { [HL_DEBUG_OP_ETR] = sizeof(struct hl_debug_params_etr), @@ -697,6 +698,42 @@ static int eventfd_unregister(struct hl_fpriv *hpriv, struct hl_info_args *args) return 0; } +static int engine_status_info(struct hl_fpriv *hpriv, struct hl_info_args *args) +{ + void __user *out = (void __user *) (uintptr_t) args->return_pointer; + u32 status_buf_size = args->return_size; + struct hl_device *hdev = hpriv->hdev; + struct engines_data eng_data; + int rc; + + if ((status_buf_size < SZ_1K) || (status_buf_size > HL_ENGINES_DATA_MAX_SIZE) || (!out)) + return -EINVAL; + + eng_data.actual_size = 0; + eng_data.allocated_buf_size = status_buf_size; + eng_data.buf = vmalloc(status_buf_size); + if (!eng_data.buf) + return -ENOMEM; + + hdev->asic_funcs->is_device_idle(hdev, NULL, 0, &eng_data); + + if (eng_data.actual_size > eng_data.allocated_buf_size) { + dev_err(hdev->dev, + "Engines data size (%d Bytes) is bigger than allocated size (%u Bytes)\n", + eng_data.actual_size, status_buf_size); + vfree(eng_data.buf); + return -ENOMEM; + } + + args->user_buffer_actual_size = eng_data.actual_size; + rc = copy_to_user(out, eng_data.buf, min_t(size_t, status_buf_size, eng_data.actual_size)) ? + -EFAULT : 0; + + vfree(eng_data.buf); + + return rc; +} + static int _hl_info_ioctl(struct hl_fpriv *hpriv, void *data, struct device *dev) { @@ -812,6 +849,9 @@ static int _hl_info_ioctl(struct hl_fpriv *hpriv, void *data, case HL_INFO_UNREGISTER_EVENTFD: return eventfd_unregister(hpriv, args); + case HL_INFO_ENGINE_STATUS: + return engine_status_info(hpriv, args); + default: dev_err(dev, "Invalid request %d\n", args->op); rc = -EINVAL; diff --git a/include/uapi/misc/habanalabs.h b/include/uapi/misc/habanalabs.h index be06b1307c44..83ca6f40f4ba 100644 --- a/include/uapi/misc/habanalabs.h +++ b/include/uapi/misc/habanalabs.h @@ -787,10 +787,14 @@ enum hl_server_type { #define HL_INFO_UNREGISTER_EVENTFD 29 #define HL_INFO_GET_EVENTS 30 #define HL_INFO_UNDEFINED_OPCODE_EVENT 31 +#define HL_INFO_ENGINE_STATUS 32 #define HL_INFO_VERSION_MAX_LEN 128 #define HL_INFO_CARD_NAME_MAX_LEN 16 +/* Maximum buffer size for retrieving engines status */ +#define HL_ENGINES_DATA_MAX_SIZE SZ_1M + /** * struct hl_info_hw_ip_info - hardware information on various IPs in the ASIC * @sram_base_address: The first SRAM physical base address that is free to be @@ -1130,6 +1134,10 @@ enum gaudi_dcores { * resolution. Currently not in use. * @pll_index: Index as defined in hl__pll_index enumeration. * @eventfd: event file descriptor for event notifications. + * @user_buffer_actual_size: Actual data size which was copied to user allocated buffer by the + * driver. It is possible for the user to allocate buffer larger than + * needed, hence updating this variable so user will know the exact amount + * of bytes copied by the kernel to the buffer. * @pad: Padding to 64 bit. */ struct hl_info_args { @@ -1143,6 +1151,7 @@ struct hl_info_args { __u32 period_ms; __u32 pll_index; __u32 eventfd; + __u32 user_buffer_actual_size; }; __u32 pad; -- cgit v1.2.3 From 7ca9022bd776d5a1c694ec0973e3d2e8671013c2 Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Sun, 31 Jul 2022 08:27:36 +0300 Subject: habanalabs/uapi: move defines to better place inside file Cosmetic change to move the eventfd events defines to a better location in the file, closer to other INFO IOCTL defines. Signed-off-by: Oded Gabbay --- include/uapi/misc/habanalabs.h | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'include') diff --git a/include/uapi/misc/habanalabs.h b/include/uapi/misc/habanalabs.h index 83ca6f40f4ba..0da8894ab94a 100644 --- a/include/uapi/misc/habanalabs.h +++ b/include/uapi/misc/habanalabs.h @@ -707,6 +707,21 @@ enum hl_server_type { HL_SERVER_GAUDI2_HLS2 = 5 }; +/* + * Notifier event values - for the notification mechanism and the HL_INFO_GET_EVENTS command + * + * HL_NOTIFIER_EVENT_TPC_ASSERT - Indicates TPC assert event + * HL_NOTIFIER_EVENT_UNDEFINED_OPCODE - Indicates undefined operation code + * HL_NOTIFIER_EVENT_DEVICE_RESET - Indicates device requires a reset + * HL_NOTIFIER_EVENT_CS_TIMEOUT - Indicates CS timeout error + * HL_NOTIFIER_EVENT_DEVICE_UNAVAILABLE - Indicates device is unavailable + */ +#define HL_NOTIFIER_EVENT_TPC_ASSERT (1ULL << 0) +#define HL_NOTIFIER_EVENT_UNDEFINED_OPCODE (1ULL << 1) +#define HL_NOTIFIER_EVENT_DEVICE_RESET (1ULL << 2) +#define HL_NOTIFIER_EVENT_CS_TIMEOUT (1ULL << 3) +#define HL_NOTIFIER_EVENT_DEVICE_UNAVAILABLE (1ULL << 4) + /* Opcode for management ioctl * * HW_IP_INFO - Receive information about different IP blocks in the @@ -1883,21 +1898,6 @@ struct hl_debug_args { __u32 ctx_id; }; -/* - * Notifier event values - for the notification mechanism and the HL_INFO_GET_EVENTS command - * - * HL_NOTIFIER_EVENT_TPC_ASSERT - Indicates TPC assert event - * HL_NOTIFIER_EVENT_UNDEFINED_OPCODE - Indicates undefined operation code - * HL_NOTIFIER_EVENT_DEVICE_RESET - Indicates device requires a reset - * HL_NOTIFIER_EVENT_CS_TIMEOUT - Indicates CS timeout error - * HL_NOTIFIER_EVENT_DEVICE_UNAVAILABLE - Indicates device is unavailable - */ -#define HL_NOTIFIER_EVENT_TPC_ASSERT (1ULL << 0) -#define HL_NOTIFIER_EVENT_UNDEFINED_OPCODE (1ULL << 1) -#define HL_NOTIFIER_EVENT_DEVICE_RESET (1ULL << 2) -#define HL_NOTIFIER_EVENT_CS_TIMEOUT (1ULL << 3) -#define HL_NOTIFIER_EVENT_DEVICE_UNAVAILABLE (1ULL << 4) - /* * Various information operations such as: * - H/W IP information -- cgit v1.2.3 From 194e515c79462f1ad09ebcc9e01a3acb84a98d82 Mon Sep 17 00:00:00 2001 From: Tal Cohen Date: Thu, 7 Jul 2022 18:42:47 +0300 Subject: habanalabs/gaudi2: new API to control engine cores running mode The current flow of halting the engine cores is implemented by command buffers built by the user space and sent towards the Driver. This current flow is broken since the user space does not know when the cores actually halt as sending a workload is async op. Therefore the application can not free the memory that is mapped to the engine cores. This new API allows the user space to control the running mode. The API call is sync (returns after the cores are set to the requested mode). Signed-off-by: Tal Cohen Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- .../misc/habanalabs/common/command_submission.c | 43 ++++++++++++- drivers/misc/habanalabs/common/habanalabs.h | 8 ++- drivers/misc/habanalabs/gaudi2/gaudi2.c | 72 ++++++++++++++++++++-- .../include/gaudi2/asic_reg/gaudi2_regs.h | 1 + include/uapi/misc/habanalabs.h | 38 ++++++++++-- 5 files changed, 151 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/drivers/misc/habanalabs/common/command_submission.c b/drivers/misc/habanalabs/common/command_submission.c index 304e4f3b0e7e..cf4118515678 100644 --- a/drivers/misc/habanalabs/common/command_submission.c +++ b/drivers/misc/habanalabs/common/command_submission.c @@ -13,7 +13,7 @@ #define HL_CS_FLAGS_TYPE_MASK (HL_CS_FLAGS_SIGNAL | HL_CS_FLAGS_WAIT | \ HL_CS_FLAGS_COLLECTIVE_WAIT | HL_CS_FLAGS_RESERVE_SIGNALS_ONLY | \ - HL_CS_FLAGS_UNRESERVE_SIGNALS_ONLY) + HL_CS_FLAGS_UNRESERVE_SIGNALS_ONLY | HL_CS_FLAGS_ENGINE_CORE_COMMAND) #define MAX_TS_ITER_NUM 10 @@ -1244,6 +1244,8 @@ static enum hl_cs_type hl_cs_get_cs_type(u32 cs_type_flags) return CS_RESERVE_SIGNALS; else if (cs_type_flags & HL_CS_FLAGS_UNRESERVE_SIGNALS_ONLY) return CS_UNRESERVE_SIGNALS; + else if (cs_type_flags & HL_CS_FLAGS_ENGINE_CORE_COMMAND) + return CS_TYPE_ENGINE_CORE; else return CS_TYPE_DEFAULT; } @@ -2355,6 +2357,41 @@ out: return rc; } +static int cs_ioctl_engine_cores(struct hl_fpriv *hpriv, u64 engine_cores, + u32 num_engine_cores, u32 core_command) +{ + int rc; + struct hl_device *hdev = hpriv->hdev; + void __user *engine_cores_arr; + u32 *cores; + + if (!num_engine_cores || num_engine_cores > hdev->asic_prop.num_engine_cores) { + dev_err(hdev->dev, "Number of engine cores %d is invalid\n", num_engine_cores); + return -EINVAL; + } + + if (core_command != HL_ENGINE_CORE_RUN && core_command != HL_ENGINE_CORE_HALT) { + dev_err(hdev->dev, "Engine core command is invalid\n"); + return -EINVAL; + } + + engine_cores_arr = (void __user *) (uintptr_t) engine_cores; + cores = kmalloc_array(num_engine_cores, sizeof(u32), GFP_KERNEL); + if (!cores) + return -ENOMEM; + + if (copy_from_user(cores, engine_cores_arr, num_engine_cores * sizeof(u32))) { + dev_err(hdev->dev, "Failed to copy core-ids array from user\n"); + kfree(cores); + return -EFAULT; + } + + rc = hdev->asic_funcs->set_engine_cores(hdev, cores, num_engine_cores, core_command); + kfree(cores); + + return rc; +} + int hl_cs_ioctl(struct hl_fpriv *hpriv, void *data) { union hl_cs_args *args = data; @@ -2407,6 +2444,10 @@ int hl_cs_ioctl(struct hl_fpriv *hpriv, void *data) rc = cs_ioctl_unreserve_signals(hpriv, args->in.encaps_sig_handle_id); break; + case CS_TYPE_ENGINE_CORE: + rc = cs_ioctl_engine_cores(hpriv, args->in.engine_cores, + args->in.num_engine_cores, args->in.core_command); + break; default: rc = cs_ioctl_default(hpriv, chunks, num_chunks, &cs_seq, args->in.cs_flags, diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index 8d9e96c6092a..ae3f5832fe58 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -345,7 +345,8 @@ enum hl_cs_type { CS_TYPE_WAIT, CS_TYPE_COLLECTIVE_WAIT, CS_RESERVE_SIGNALS, - CS_UNRESERVE_SIGNALS + CS_UNRESERVE_SIGNALS, + CS_TYPE_ENGINE_CORE }; /* @@ -617,6 +618,7 @@ struct hl_hints_range { * which the property supports_user_set_page_size is true * (i.e. the DRAM supports multiple page sizes), otherwise * it will shall be equal to dram_page_size. + * @num_engine_cores: number of engine cpu cores * @collective_first_sob: first sync object available for collective use * @collective_first_mon: first monitor available for collective use * @sync_stream_first_sob: first sync object available for sync stream use @@ -737,6 +739,7 @@ struct asic_fixed_properties { u32 faulty_dram_cluster_map; u32 xbar_edge_enabled_mask; u32 device_mem_alloc_default_page_size; + u32 num_engine_cores; u16 collective_first_sob; u16 collective_first_mon; u16 sync_stream_first_sob; @@ -1511,6 +1514,7 @@ struct engines_data { * @check_if_razwi_happened: check if there was a razwi due to RR violation. * @access_dev_mem: access device memory * @set_dram_bar_base: set the base of the DRAM BAR + * @set_engine_cores: set a config command to enigne cores */ struct hl_asic_funcs { int (*early_init)(struct hl_device *hdev); @@ -1645,6 +1649,8 @@ struct hl_asic_funcs { int (*access_dev_mem)(struct hl_device *hdev, enum pci_region region_type, u64 addr, u64 *val, enum debugfs_access_type acc_type); u64 (*set_dram_bar_base)(struct hl_device *hdev, u64 addr); + int (*set_engine_cores)(struct hl_device *hdev, u32 *core_ids, + u32 num_cores, u32 core_command); }; diff --git a/drivers/misc/habanalabs/gaudi2/gaudi2.c b/drivers/misc/habanalabs/gaudi2/gaudi2.c index 9ccde0258eca..676419961f86 100644 --- a/drivers/misc/habanalabs/gaudi2/gaudi2.c +++ b/drivers/misc/habanalabs/gaudi2/gaudi2.c @@ -1989,6 +1989,7 @@ static int gaudi2_set_fixed_properties(struct hl_device *hdev) prop->pmmu_huge.end_addr = VA_HOST_SPACE_HPAGE_END; } + prop->num_engine_cores = CPU_ID_MAX; prop->cfg_size = CFG_SIZE; prop->max_asid = MAX_ASID; prop->num_of_events = GAUDI2_EVENT_SIZE; @@ -3751,14 +3752,16 @@ static void gaudi2_stop_dec(struct hl_device *hdev) gaudi2_stop_pcie_dec(hdev); } -static void gaudi2_halt_arc(struct hl_device *hdev, u32 cpu_id) +static void gaudi2_set_arc_running_mode(struct hl_device *hdev, u32 cpu_id, u32 run_mode) { u32 reg_base, reg_val; reg_base = gaudi2_arc_blocks_bases[cpu_id]; + if (run_mode == HL_ENGINE_CORE_RUN) + reg_val = FIELD_PREP(ARC_FARM_ARC0_AUX_RUN_HALT_REQ_RUN_REQ_MASK, 1); + else + reg_val = FIELD_PREP(ARC_FARM_ARC0_AUX_RUN_HALT_REQ_HALT_REQ_MASK, 1); - /* Halt ARC */ - reg_val = FIELD_PREP(ARC_FARM_ARC0_AUX_RUN_HALT_REQ_HALT_REQ_MASK, 1); WREG32(reg_base + ARC_HALT_REQ_OFFSET, reg_val); } @@ -3768,10 +3771,37 @@ static void gaudi2_halt_arcs(struct hl_device *hdev) for (arc_id = CPU_ID_SCHED_ARC0; arc_id < CPU_ID_MAX; arc_id++) { if (gaudi2_is_arc_enabled(hdev, arc_id)) - gaudi2_halt_arc(hdev, arc_id); + gaudi2_set_arc_running_mode(hdev, arc_id, HL_ENGINE_CORE_HALT); } } +static int gaudi2_verify_arc_running_mode(struct hl_device *hdev, u32 cpu_id, u32 run_mode) +{ + int rc; + u32 reg_base, val, ack_mask, timeout_usec = 100000; + + if (hdev->pldm) + timeout_usec *= 100; + + reg_base = gaudi2_arc_blocks_bases[cpu_id]; + if (run_mode == HL_ENGINE_CORE_RUN) + ack_mask = ARC_FARM_ARC0_AUX_RUN_HALT_ACK_RUN_ACK_MASK; + else + ack_mask = ARC_FARM_ARC0_AUX_RUN_HALT_ACK_HALT_ACK_MASK; + + rc = hl_poll_timeout(hdev, reg_base + ARC_HALT_ACK_OFFSET, + val, ((val & ack_mask) == ack_mask), + 1000, timeout_usec); + + if (!rc) { + /* Clear */ + val = FIELD_PREP(ARC_FARM_ARC0_AUX_RUN_HALT_REQ_RUN_REQ_MASK, 0); + WREG32(reg_base + ARC_HALT_REQ_OFFSET, val); + } + + return rc; +} + static void gaudi2_reset_arcs(struct hl_device *hdev) { struct gaudi2_device *gaudi2 = hdev->asic_specific; @@ -3796,8 +3826,39 @@ static void gaudi2_nic_qmans_manual_flush(struct hl_device *hdev) queue_id = GAUDI2_QUEUE_ID_NIC_0_0; - for (i = 0 ; i < NIC_NUMBER_OF_ENGINES ; i++, queue_id += NUM_OF_PQ_PER_QMAN) + for (i = 0 ; i < NIC_NUMBER_OF_ENGINES ; i++, queue_id += NUM_OF_PQ_PER_QMAN) { + if (!(hdev->nic_ports_mask & BIT(i))) + continue; + gaudi2_qman_manual_flush_common(hdev, queue_id); + } +} + +static int gaudi2_set_engine_cores(struct hl_device *hdev, u32 *core_ids, + u32 num_cores, u32 core_command) +{ + int i, rc; + + + for (i = 0 ; i < num_cores ; i++) { + if (gaudi2_is_arc_enabled(hdev, core_ids[i])) + gaudi2_set_arc_running_mode(hdev, core_ids[i], core_command); + } + + for (i = 0 ; i < num_cores ; i++) { + if (gaudi2_is_arc_enabled(hdev, core_ids[i])) { + rc = gaudi2_verify_arc_running_mode(hdev, core_ids[i], core_command); + + if (rc) { + dev_err(hdev->dev, "failed to %s arc: %d\n", + (core_command == HL_ENGINE_CORE_HALT) ? + "HALT" : "RUN", core_ids[i]); + return -1; + } + } + } + + return 0; } static void gaudi2_halt_engines(struct hl_device *hdev, bool hard_reset, bool fw_reset) @@ -9968,6 +10029,7 @@ static const struct hl_asic_funcs gaudi2_funcs = { .mmu_get_real_page_size = gaudi2_mmu_get_real_page_size, .access_dev_mem = hl_access_dev_mem, .set_dram_bar_base = gaudi2_set_hbm_bar_base, + .set_engine_cores = gaudi2_set_engine_cores, }; void gaudi2_set_asic_funcs(struct hl_device *hdev) diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/gaudi2_regs.h b/drivers/misc/habanalabs/include/gaudi2/asic_reg/gaudi2_regs.h index d0e2c68a639f..bfda4223bdc8 100644 --- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/gaudi2_regs.h +++ b/drivers/misc/habanalabs/include/gaudi2/asic_reg/gaudi2_regs.h @@ -239,6 +239,7 @@ #define SFT_IF_RTR_OFFSET (mmSFT0_HBW_RTR_IF1_RTR_H3_BASE - mmSFT0_HBW_RTR_IF0_RTR_H3_BASE) #define ARC_HALT_REQ_OFFSET (mmARC_FARM_ARC0_AUX_RUN_HALT_REQ - mmARC_FARM_ARC0_AUX_BASE) +#define ARC_HALT_ACK_OFFSET (mmARC_FARM_ARC0_AUX_RUN_HALT_ACK - mmARC_FARM_ARC0_AUX_BASE) #define ARC_REGION_CFG_OFFSET(region) \ (mmARC_FARM_ARC0_AUX_ARC_REGION_CFG_0 + (region * 4) - mmARC_FARM_ARC0_AUX_BASE) diff --git a/include/uapi/misc/habanalabs.h b/include/uapi/misc/habanalabs.h index 0da8894ab94a..f51c6ae4f94d 100644 --- a/include/uapi/misc/habanalabs.h +++ b/include/uapi/misc/habanalabs.h @@ -1361,17 +1361,47 @@ struct hl_cs_chunk { #define HL_CS_FLAGS_RESERVE_SIGNALS_ONLY 0x1000 #define HL_CS_FLAGS_UNRESERVE_SIGNALS_ONLY 0x2000 +/* + * The engine cores CS is merged into the existing CS ioctls. + * Use it to control the engine cores mode. + */ +#define HL_CS_FLAGS_ENGINE_CORE_COMMAND 0x4000 + #define HL_CS_STATUS_SUCCESS 0 #define HL_MAX_JOBS_PER_CS 512 +/* HL_ENGINE_CORE_ values + * + * HL_ENGINE_CORE_HALT: engine core halt + * HL_ENGINE_CORE_RUN: engine core run + */ +#define HL_ENGINE_CORE_HALT (1 << 0) +#define HL_ENGINE_CORE_RUN (1 << 1) + struct hl_cs_in { - /* this holds address of array of hl_cs_chunk for restore phase */ - __u64 chunks_restore; + union { + struct { + /* this holds address of array of hl_cs_chunk for restore phase */ + __u64 chunks_restore; - /* holds address of array of hl_cs_chunk for execution phase */ - __u64 chunks_execute; + /* holds address of array of hl_cs_chunk for execution phase */ + __u64 chunks_execute; + }; + + /* Valid only when HL_CS_FLAGS_ENGINE_CORE_COMMAND is set */ + struct { + /* this holds address of array of uint32 for engine_cores */ + __u64 engine_cores; + + /* number of engine cores in engine_cores array */ + __u32 num_engine_cores; + + /* the core command to be sent towards engine cores */ + __u32 core_command; + }; + }; union { /* -- cgit v1.2.3 From 38a4358009456bfd7e4893c4f98ee401efce26eb Mon Sep 17 00:00:00 2001 From: Ofir Bitton Date: Wed, 3 Aug 2022 17:25:33 +0300 Subject: habanalabs: expose device security status using info ioctl In order for the user to know if he is running on a secured device or not, we add it also to the hw_ip info ioctl. Signed-off-by: Ofir Bitton Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/habanalabs_ioctl.c | 1 + include/uapi/misc/habanalabs.h | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/misc/habanalabs/common/habanalabs_ioctl.c b/drivers/misc/habanalabs/common/habanalabs_ioctl.c index ec55c66fedd6..c7bd000750c8 100644 --- a/drivers/misc/habanalabs/common/habanalabs_ioctl.c +++ b/drivers/misc/habanalabs/common/habanalabs_ioctl.c @@ -104,6 +104,7 @@ static int hw_ip_info(struct hl_device *hdev, struct hl_info_args *args) hw_ip.edma_enabled_mask = prop->edma_enabled_mask; hw_ip.server_type = prop->server_type; + hw_ip.security_enabled = prop->fw_security_enabled; return copy_to_user(out, &hw_ip, min((size_t) size, sizeof(hw_ip))) ? -EFAULT : 0; diff --git a/include/uapi/misc/habanalabs.h b/include/uapi/misc/habanalabs.h index f51c6ae4f94d..3005cc04d4b1 100644 --- a/include/uapi/misc/habanalabs.h +++ b/include/uapi/misc/habanalabs.h @@ -840,6 +840,7 @@ enum hl_server_type { * @tpc_enabled_mask: Bit-mask that represents which TPCs are enabled. Relevant * for Goya/Gaudi only. * @dram_enabled: Whether the DRAM is enabled. + * @security_enabled: Whether security is enabled on device. * @mme_master_slave_mode: Indicate whether the MME is working in master/slave * configuration. Relevant for Greco and later. * @cpucp_version: The CPUCP f/w version. @@ -871,7 +872,7 @@ struct hl_info_hw_ip_info { __u32 psoc_pci_pll_div_factor; __u8 tpc_enabled_mask; __u8 dram_enabled; - __u8 reserved; + __u8 security_enabled; __u8 mme_master_slave_mode; __u8 cpucp_version[HL_INFO_VERSION_MAX_LEN]; __u8 card_name[HL_INFO_CARD_NAME_MAX_LEN]; -- cgit v1.2.3 From 191a4443c39b278fbb0898590530bef122b26b7e Mon Sep 17 00:00:00 2001 From: Ohad Sharabi Date: Wed, 8 Jun 2022 09:58:59 +0300 Subject: habanalabs: define trace events This patch adds trace events for habanalabs driver to gain all the benefits such an infrastructure can supply. The following events were added: - MMU map/unmap: to be able to track driver's memory allocations - DMA alloc/free: to track our DMA allocation the above trace points in conjunction will help us map the device memory usage as well as to be able to track memory violations. Signed-off-by: Ohad Sharabi Acked-by: Oded Gabbay Reviewed-by: Steven Rostedt (Google) Signed-off-by: Oded Gabbay --- MAINTAINERS | 1 + drivers/misc/habanalabs/common/habanalabs_drv.c | 3 + include/trace/events/habanalabs.h | 90 +++++++++++++++++++++++++ 3 files changed, 94 insertions(+) create mode 100644 include/trace/events/habanalabs.h (limited to 'include') diff --git a/MAINTAINERS b/MAINTAINERS index da6d4fd517b0..20ead1fd0e19 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8886,6 +8886,7 @@ T: git https://git.kernel.org/pub/scm/linux/kernel/git/ogabbay/linux.git F: Documentation/ABI/testing/debugfs-driver-habanalabs F: Documentation/ABI/testing/sysfs-driver-habanalabs F: drivers/misc/habanalabs/ +F: include/trace/events/habanalabs.h F: include/uapi/misc/habanalabs.h HACKRF MEDIA DRIVER diff --git a/drivers/misc/habanalabs/common/habanalabs_drv.c b/drivers/misc/habanalabs/common/habanalabs_drv.c index 8026793d9083..e12148428731 100644 --- a/drivers/misc/habanalabs/common/habanalabs_drv.c +++ b/drivers/misc/habanalabs/common/habanalabs_drv.c @@ -14,6 +14,9 @@ #include #include +#define CREATE_TRACE_POINTS +#include + #define HL_DRIVER_AUTHOR "HabanaLabs Kernel Driver Team" #define HL_DRIVER_DESC "Driver for HabanaLabs's AI Accelerators" diff --git a/include/trace/events/habanalabs.h b/include/trace/events/habanalabs.h new file mode 100644 index 000000000000..09ca516e1624 --- /dev/null +++ b/include/trace/events/habanalabs.h @@ -0,0 +1,90 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright 2016-2021 HabanaLabs, Ltd. + * All Rights Reserved. + * + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM habanalabs + +#if !defined(_TRACE_HABANALABS_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_HABANALABS_H + +#include + +DECLARE_EVENT_CLASS(habanalabs_mmu_template, + TP_PROTO(struct device *dev, u64 virt_addr, u64 phys_addr, u32 page_size, bool flush_pte), + + TP_ARGS(dev, virt_addr, phys_addr, page_size, flush_pte), + + TP_STRUCT__entry( + __string(dname, dev_name(dev)) + __field(u64, virt_addr) + __field(u64, phys_addr) + __field(u32, page_size) + __field(u8, flush_pte) + ), + + TP_fast_assign( + __assign_str(dname, dev_name(dev)); + __entry->virt_addr = virt_addr; + __entry->phys_addr = phys_addr; + __entry->page_size = page_size; + __entry->flush_pte = flush_pte; + ), + + TP_printk("%s: vaddr: %#llx, paddr: %#llx, psize: %#x, flush: %s", + __get_str(dname), + __entry->virt_addr, + __entry->phys_addr, + __entry->page_size, + __entry->flush_pte ? "true" : "false") +); + +DEFINE_EVENT(habanalabs_mmu_template, habanalabs_mmu_map, + TP_PROTO(struct device *dev, u64 virt_addr, u64 phys_addr, u32 page_size, bool flush_pte), + TP_ARGS(dev, virt_addr, phys_addr, page_size, flush_pte)); + +DEFINE_EVENT(habanalabs_mmu_template, habanalabs_mmu_unmap, + TP_PROTO(struct device *dev, u64 virt_addr, u64 phys_addr, u32 page_size, bool flush_pte), + TP_ARGS(dev, virt_addr, phys_addr, page_size, flush_pte)); + +DECLARE_EVENT_CLASS(habanalabs_dma_alloc_template, + TP_PROTO(struct device *dev, u64 cpu_addr, u64 dma_addr, size_t size), + + TP_ARGS(dev, cpu_addr, dma_addr, size), + + TP_STRUCT__entry( + __string(dname, dev_name(dev)) + __field(u64, cpu_addr) + __field(u64, dma_addr) + __field(u32, size) + ), + + TP_fast_assign( + __assign_str(dname, dev_name(dev)); + __entry->cpu_addr = cpu_addr; + __entry->dma_addr = dma_addr; + __entry->size = size; + ), + + TP_printk("%s: cpu_addr: %#llx, dma_addr: %#llx, size: %#x", + __get_str(dname), + __entry->cpu_addr, + __entry->dma_addr, + __entry->size) +); + +DEFINE_EVENT(habanalabs_dma_alloc_template, habanalabs_dma_alloc, + TP_PROTO(struct device *dev, u64 cpu_addr, u64 dma_addr, size_t size), + TP_ARGS(dev, cpu_addr, dma_addr, size)); + +DEFINE_EVENT(habanalabs_dma_alloc_template, habanalabs_dma_free, + TP_PROTO(struct device *dev, u64 cpu_addr, u64 dma_addr, size_t size), + TP_ARGS(dev, cpu_addr, dma_addr, size)); + +#endif /* if !defined(_TRACE_HABANALABS_H) || defined(TRACE_HEADER_MULTI_READ) */ + +/* This part must be outside protection */ +#include -- cgit v1.2.3 From 0263256791094180ab8749b224ef7bfe0bfd67bb Mon Sep 17 00:00:00 2001 From: Ohad Sharabi Date: Sun, 12 Jun 2022 15:00:29 +0300 Subject: habanalabs: trace DMA allocations This patch add tracepoints in the code for DMA allocation. The main purpose is to be able to cross data with the map operations and determine whether memory violation occurred, for example free DMA allocation before unmapping it from device memory. To achieve this the DMA alloc/free code flows were refactored so that a single DMA tracepoint will catch many flows. To get better understanding of what happened in the DMA allocations the real allocating function is added to the trace as well. Signed-off-by: Ohad Sharabi Reviewed-by: Oded Gabbay Reviewed-by: Steven Rostedt (Google) Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/device.c | 49 ++++++++++++++++++----------- drivers/misc/habanalabs/common/habanalabs.h | 40 +++++++++++++++++------ include/trace/events/habanalabs.h | 19 ++++++----- 3 files changed, 73 insertions(+), 35 deletions(-) (limited to 'include') diff --git a/drivers/misc/habanalabs/common/device.c b/drivers/misc/habanalabs/common/device.c index 0b3097802b00..230b7eeef962 100644 --- a/drivers/misc/habanalabs/common/device.c +++ b/drivers/misc/habanalabs/common/device.c @@ -13,6 +13,8 @@ #include #include +#include + #define HL_RESET_DELAY_USEC 10000 /* 10ms */ enum dma_alloc_type { @@ -101,9 +103,10 @@ static int hl_access_sram_dram_region(struct hl_device *hdev, u64 addr, u64 *val } static void *hl_dma_alloc_common(struct hl_device *hdev, size_t size, dma_addr_t *dma_handle, - gfp_t flag, enum dma_alloc_type alloc_type) + gfp_t flag, enum dma_alloc_type alloc_type, + const char *caller) { - void *ptr; + void *ptr = NULL; switch (alloc_type) { case DMA_ALLOC_COHERENT: @@ -117,11 +120,16 @@ static void *hl_dma_alloc_common(struct hl_device *hdev, size_t size, dma_addr_t break; } + if (trace_habanalabs_dma_alloc_enabled() && !ZERO_OR_NULL_PTR(ptr)) + trace_habanalabs_dma_alloc(hdev->dev, (u64) (uintptr_t) ptr, *dma_handle, size, + caller); + return ptr; } static void hl_asic_dma_free_common(struct hl_device *hdev, size_t size, void *cpu_addr, - dma_addr_t dma_handle, enum dma_alloc_type alloc_type) + dma_addr_t dma_handle, enum dma_alloc_type alloc_type, + const char *caller) { switch (alloc_type) { case DMA_ALLOC_COHERENT: @@ -134,39 +142,44 @@ static void hl_asic_dma_free_common(struct hl_device *hdev, size_t size, void *c hdev->asic_funcs->asic_dma_pool_free(hdev, cpu_addr, dma_handle); break; } + + trace_habanalabs_dma_free(hdev->dev, (u64) (uintptr_t) cpu_addr, dma_handle, size, caller); } -void *hl_asic_dma_alloc_coherent(struct hl_device *hdev, size_t size, dma_addr_t *dma_handle, - gfp_t flag) +void *hl_asic_dma_alloc_coherent_caller(struct hl_device *hdev, size_t size, dma_addr_t *dma_handle, + gfp_t flag, const char *caller) { - return hl_dma_alloc_common(hdev, size, dma_handle, flag, DMA_ALLOC_COHERENT); + return hl_dma_alloc_common(hdev, size, dma_handle, flag, DMA_ALLOC_COHERENT, caller); } -void hl_asic_dma_free_coherent(struct hl_device *hdev, size_t size, void *cpu_addr, - dma_addr_t dma_handle) +void hl_asic_dma_free_coherent_caller(struct hl_device *hdev, size_t size, void *cpu_addr, + dma_addr_t dma_handle, const char *caller) { - hl_asic_dma_free_common(hdev, size, cpu_addr, dma_handle, DMA_ALLOC_COHERENT); + hl_asic_dma_free_common(hdev, size, cpu_addr, dma_handle, DMA_ALLOC_COHERENT, caller); } -void *hl_cpu_accessible_dma_pool_alloc(struct hl_device *hdev, size_t size, dma_addr_t *dma_handle) +void *hl_cpu_accessible_dma_pool_alloc_caller(struct hl_device *hdev, size_t size, + dma_addr_t *dma_handle, const char *caller) { - return hl_dma_alloc_common(hdev, size, dma_handle, 0, DMA_ALLOC_CPU_ACCESSIBLE); + return hl_dma_alloc_common(hdev, size, dma_handle, 0, DMA_ALLOC_CPU_ACCESSIBLE, caller); } -void hl_cpu_accessible_dma_pool_free(struct hl_device *hdev, size_t size, void *vaddr) +void hl_cpu_accessible_dma_pool_free_caller(struct hl_device *hdev, size_t size, void *vaddr, + const char *caller) { - hl_asic_dma_free_common(hdev, size, vaddr, 0, DMA_ALLOC_CPU_ACCESSIBLE); + hl_asic_dma_free_common(hdev, size, vaddr, 0, DMA_ALLOC_CPU_ACCESSIBLE, caller); } -void *hl_asic_dma_pool_zalloc(struct hl_device *hdev, size_t size, gfp_t mem_flags, - dma_addr_t *dma_handle) +void *hl_asic_dma_pool_zalloc_caller(struct hl_device *hdev, size_t size, gfp_t mem_flags, + dma_addr_t *dma_handle, const char *caller) { - return hl_dma_alloc_common(hdev, size, dma_handle, mem_flags, DMA_ALLOC_POOL); + return hl_dma_alloc_common(hdev, size, dma_handle, mem_flags, DMA_ALLOC_POOL, caller); } -void hl_asic_dma_pool_free(struct hl_device *hdev, void *vaddr, dma_addr_t dma_addr) +void hl_asic_dma_pool_free_caller(struct hl_device *hdev, void *vaddr, dma_addr_t dma_addr, + const char *caller) { - hl_asic_dma_free_common(hdev, 0, vaddr, dma_addr, DMA_ALLOC_POOL); + hl_asic_dma_free_common(hdev, 0, vaddr, dma_addr, DMA_ALLOC_POOL, caller); } int hl_dma_map_sgtable(struct hl_device *hdev, struct sg_table *sgt, enum dma_data_direction dir) diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index a3c516c31b54..43b9427d9c97 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -143,6 +143,25 @@ enum hl_mmu_enablement { #define HL_MAX_DCORES 8 +/* DMA alloc/free wrappers */ +#define hl_asic_dma_alloc_coherent(hdev, size, dma_handle, flags) \ + hl_asic_dma_alloc_coherent_caller(hdev, size, dma_handle, flags, __func__) + +#define hl_cpu_accessible_dma_pool_alloc(hdev, size, dma_handle) \ + hl_cpu_accessible_dma_pool_alloc_caller(hdev, size, dma_handle, __func__) + +#define hl_asic_dma_pool_zalloc(hdev, size, mem_flags, dma_handle) \ + hl_asic_dma_pool_zalloc_caller(hdev, size, mem_flags, dma_handle, __func__) + +#define hl_asic_dma_free_coherent(hdev, size, cpu_addr, dma_handle) \ + hl_asic_dma_free_coherent_caller(hdev, size, cpu_addr, dma_handle, __func__) + +#define hl_cpu_accessible_dma_pool_free(hdev, size, vaddr) \ + hl_cpu_accessible_dma_pool_free_caller(hdev, size, vaddr, __func__) + +#define hl_asic_dma_pool_free(hdev, vaddr, dma_addr) \ + hl_asic_dma_pool_free_caller(hdev, vaddr, dma_addr, __func__) + /* * Reset Flags * @@ -3446,15 +3465,18 @@ static inline bool hl_mem_area_crosses_range(u64 address, u32 size, } uint64_t hl_set_dram_bar_default(struct hl_device *hdev, u64 addr); -void *hl_asic_dma_alloc_coherent(struct hl_device *hdev, size_t size, dma_addr_t *dma_handle, - gfp_t flag); -void hl_asic_dma_free_coherent(struct hl_device *hdev, size_t size, void *cpu_addr, - dma_addr_t dma_handle); -void *hl_cpu_accessible_dma_pool_alloc(struct hl_device *hdev, size_t size, dma_addr_t *dma_handle); -void hl_cpu_accessible_dma_pool_free(struct hl_device *hdev, size_t size, void *vaddr); -void *hl_asic_dma_pool_zalloc(struct hl_device *hdev, size_t size, gfp_t mem_flags, - dma_addr_t *dma_handle); -void hl_asic_dma_pool_free(struct hl_device *hdev, void *vaddr, dma_addr_t dma_addr); +void *hl_asic_dma_alloc_coherent_caller(struct hl_device *hdev, size_t size, dma_addr_t *dma_handle, + gfp_t flag, const char *caller); +void hl_asic_dma_free_coherent_caller(struct hl_device *hdev, size_t size, void *cpu_addr, + dma_addr_t dma_handle, const char *caller); +void *hl_cpu_accessible_dma_pool_alloc_caller(struct hl_device *hdev, size_t size, + dma_addr_t *dma_handle, const char *caller); +void hl_cpu_accessible_dma_pool_free_caller(struct hl_device *hdev, size_t size, void *vaddr, + const char *caller); +void *hl_asic_dma_pool_zalloc_caller(struct hl_device *hdev, size_t size, gfp_t mem_flags, + dma_addr_t *dma_handle, const char *caller); +void hl_asic_dma_pool_free_caller(struct hl_device *hdev, void *vaddr, dma_addr_t dma_addr, + const char *caller); int hl_dma_map_sgtable(struct hl_device *hdev, struct sg_table *sgt, enum dma_data_direction dir); void hl_dma_unmap_sgtable(struct hl_device *hdev, struct sg_table *sgt, enum dma_data_direction dir); diff --git a/include/trace/events/habanalabs.h b/include/trace/events/habanalabs.h index 09ca516e1624..f05c5fa668a2 100644 --- a/include/trace/events/habanalabs.h +++ b/include/trace/events/habanalabs.h @@ -51,15 +51,16 @@ DEFINE_EVENT(habanalabs_mmu_template, habanalabs_mmu_unmap, TP_ARGS(dev, virt_addr, phys_addr, page_size, flush_pte)); DECLARE_EVENT_CLASS(habanalabs_dma_alloc_template, - TP_PROTO(struct device *dev, u64 cpu_addr, u64 dma_addr, size_t size), + TP_PROTO(struct device *dev, u64 cpu_addr, u64 dma_addr, size_t size, const char *caller), - TP_ARGS(dev, cpu_addr, dma_addr, size), + TP_ARGS(dev, cpu_addr, dma_addr, size, caller), TP_STRUCT__entry( __string(dname, dev_name(dev)) __field(u64, cpu_addr) __field(u64, dma_addr) __field(u32, size) + __field(const char *, caller) ), TP_fast_assign( @@ -67,22 +68,24 @@ DECLARE_EVENT_CLASS(habanalabs_dma_alloc_template, __entry->cpu_addr = cpu_addr; __entry->dma_addr = dma_addr; __entry->size = size; + __entry->caller = caller; ), - TP_printk("%s: cpu_addr: %#llx, dma_addr: %#llx, size: %#x", + TP_printk("%s: cpu_addr: %#llx, dma_addr: %#llx, size: %#x, caller: %s", __get_str(dname), __entry->cpu_addr, __entry->dma_addr, - __entry->size) + __entry->size, + __entry->caller) ); DEFINE_EVENT(habanalabs_dma_alloc_template, habanalabs_dma_alloc, - TP_PROTO(struct device *dev, u64 cpu_addr, u64 dma_addr, size_t size), - TP_ARGS(dev, cpu_addr, dma_addr, size)); + TP_PROTO(struct device *dev, u64 cpu_addr, u64 dma_addr, size_t size, const char *caller), + TP_ARGS(dev, cpu_addr, dma_addr, size, caller)); DEFINE_EVENT(habanalabs_dma_alloc_template, habanalabs_dma_free, - TP_PROTO(struct device *dev, u64 cpu_addr, u64 dma_addr, size_t size), - TP_ARGS(dev, cpu_addr, dma_addr, size)); + TP_PROTO(struct device *dev, u64 cpu_addr, u64 dma_addr, size_t size, const char *caller), + TP_ARGS(dev, cpu_addr, dma_addr, size, caller)); #endif /* if !defined(_TRACE_HABANALABS_H) || defined(TRACE_HEADER_MULTI_READ) */ -- cgit v1.2.3 From 6f0818c9fc9b81d8a303a8d3fb1826d71777f7ed Mon Sep 17 00:00:00 2001 From: Tal Cohen Date: Thu, 18 Aug 2022 12:54:23 +0300 Subject: habanalabs: new notifier events for device state Add new notifier events that inform several device states. General H/W error raised on device general H/W error occurs. User engine error is raised when a device engine informs of an error. Signed-off-by: Tal Cohen Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/gaudi/gaudi.c | 39 +++++++++++++++++++++--- drivers/misc/habanalabs/gaudi2/gaudi2.c | 54 ++++++++++++++++++++++++++++++++- include/uapi/misc/habanalabs.h | 4 +++ 3 files changed, 91 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index 87dbdbb220da..2b328cb62096 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -7685,6 +7685,7 @@ static void gaudi_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_entr case GAUDI_EVENT_NIC0_CS_DBG_DERR ... GAUDI_EVENT_NIC4_CS_DBG_DERR: gaudi_print_irq_info(hdev, event_type, true); gaudi_handle_ecc_event(hdev, event_type, &eq_entry->ecc_data); + event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR; fw_fatal_err_flag = HL_DRV_RESET_FW_FATAL_ERR; goto reset_device; @@ -7694,6 +7695,7 @@ static void gaudi_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_entr case GAUDI_EVENT_PLL0 ... GAUDI_EVENT_PLL17: gaudi_print_irq_info(hdev, event_type, false); fw_fatal_err_flag = HL_DRV_RESET_FW_FATAL_ERR; + event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR; goto reset_device; case GAUDI_EVENT_HBM0_SPI_0: @@ -7705,6 +7707,7 @@ static void gaudi_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_entr gaudi_hbm_event_to_dev(event_type), &eq_entry->hbm_ecc_data); fw_fatal_err_flag = HL_DRV_RESET_FW_FATAL_ERR; + event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR; goto reset_device; case GAUDI_EVENT_HBM0_SPI_1: @@ -7716,6 +7719,7 @@ static void gaudi_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_entr gaudi_hbm_event_to_dev(event_type), &eq_entry->hbm_ecc_data); hl_fw_unmask_irq(hdev, event_type); + event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR; break; case GAUDI_EVENT_TPC0_DEC: @@ -7730,6 +7734,7 @@ static void gaudi_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_entr reset_required = gaudi_tpc_read_interrupts(hdev, tpc_dec_event_to_tpc_id(event_type), "AXI_SLV_DEC_Error"); + event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR; if (reset_required) { dev_err(hdev->dev, "reset required due to %s\n", gaudi_irq_map_table[event_type].name); @@ -7738,6 +7743,7 @@ static void gaudi_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_entr goto reset_device; } else { hl_fw_unmask_irq(hdev, event_type); + event_mask |= HL_NOTIFIER_EVENT_DEVICE_RESET; } break; @@ -7753,6 +7759,7 @@ static void gaudi_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_entr reset_required = gaudi_tpc_read_interrupts(hdev, tpc_krn_event_to_tpc_id(event_type), "KRN_ERR"); + event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR; if (reset_required) { dev_err(hdev->dev, "reset required due to %s\n", gaudi_irq_map_table[event_type].name); @@ -7761,6 +7768,7 @@ static void gaudi_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_entr goto reset_device; } else { hl_fw_unmask_irq(hdev, event_type); + event_mask |= HL_NOTIFIER_EVENT_DEVICE_RESET; } break; @@ -7789,9 +7797,25 @@ static void gaudi_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_entr gaudi_print_irq_info(hdev, event_type, true); gaudi_handle_ecc_event(hdev, event_type, &eq_entry->ecc_data); hl_fw_unmask_irq(hdev, event_type); + event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR; break; case GAUDI_EVENT_PCIE_DEC: + case GAUDI_EVENT_CPU_AXI_SPLITTER: + case GAUDI_EVENT_PSOC_AXI_DEC: + case GAUDI_EVENT_PSOC_PRSTN_FALL: + gaudi_print_irq_info(hdev, event_type, true); + hl_fw_unmask_irq(hdev, event_type); + event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR; + break; + + case GAUDI_EVENT_MMU_PAGE_FAULT: + case GAUDI_EVENT_MMU_WR_PERM: + gaudi_print_irq_info(hdev, event_type, true); + hl_fw_unmask_irq(hdev, event_type); + event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR; + break; + case GAUDI_EVENT_MME0_WBC_RSP: case GAUDI_EVENT_MME0_SBAB0_RSP: case GAUDI_EVENT_MME1_WBC_RSP: @@ -7800,11 +7824,6 @@ static void gaudi_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_entr case GAUDI_EVENT_MME2_SBAB0_RSP: case GAUDI_EVENT_MME3_WBC_RSP: case GAUDI_EVENT_MME3_SBAB0_RSP: - case GAUDI_EVENT_CPU_AXI_SPLITTER: - case GAUDI_EVENT_PSOC_AXI_DEC: - case GAUDI_EVENT_PSOC_PRSTN_FALL: - case GAUDI_EVENT_MMU_PAGE_FAULT: - case GAUDI_EVENT_MMU_WR_PERM: case GAUDI_EVENT_RAZWI_OR_ADC: case GAUDI_EVENT_MME0_QM ... GAUDI_EVENT_MME2_QM: case GAUDI_EVENT_DMA0_QM ... GAUDI_EVENT_DMA7_QM: @@ -7824,10 +7843,12 @@ static void gaudi_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_entr gaudi_print_irq_info(hdev, event_type, true); gaudi_handle_qman_err(hdev, event_type, &event_mask); hl_fw_unmask_irq(hdev, event_type); + event_mask |= (HL_NOTIFIER_EVENT_USER_ENGINE_ERR | HL_NOTIFIER_EVENT_DEVICE_RESET); break; case GAUDI_EVENT_RAZWI_OR_ADC_SW: gaudi_print_irq_info(hdev, event_type, true); + event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR; goto reset_device; case GAUDI_EVENT_TPC0_BMON_SPMU: @@ -7841,11 +7862,13 @@ static void gaudi_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_entr case GAUDI_EVENT_DMA_BM_CH0 ... GAUDI_EVENT_DMA_BM_CH7: gaudi_print_irq_info(hdev, event_type, false); hl_fw_unmask_irq(hdev, event_type); + event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR; break; case GAUDI_EVENT_NIC_SEI_0 ... GAUDI_EVENT_NIC_SEI_4: gaudi_print_nic_axi_irq_info(hdev, event_type, &data); hl_fw_unmask_irq(hdev, event_type); + event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR; break; case GAUDI_EVENT_DMA_IF_SEI_0 ... GAUDI_EVENT_DMA_IF_SEI_3: @@ -7853,6 +7876,7 @@ static void gaudi_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_entr gaudi_print_sm_sei_info(hdev, event_type, &eq_entry->sm_sei_data); rc = hl_state_dump(hdev); + event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR; if (rc) dev_err(hdev->dev, "Error during system state dump %d\n", rc); @@ -7863,6 +7887,7 @@ static void gaudi_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_entr break; case GAUDI_EVENT_FIX_POWER_ENV_S ... GAUDI_EVENT_FIX_THERMAL_ENV_E: + event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR; gaudi_print_clk_change_info(hdev, event_type); hl_fw_unmask_irq(hdev, event_type); break; @@ -7872,20 +7897,24 @@ static void gaudi_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_entr dev_err(hdev->dev, "Received high temp H/W interrupt %d (cause %d)\n", event_type, cause); + event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR; break; case GAUDI_EVENT_DEV_RESET_REQ: gaudi_print_irq_info(hdev, event_type, false); + event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR; goto reset_device; case GAUDI_EVENT_PKT_QUEUE_OUT_SYNC: gaudi_print_irq_info(hdev, event_type, false); gaudi_print_out_of_sync_info(hdev, &eq_entry->pkt_sync_err); + event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR; goto reset_device; case GAUDI_EVENT_FW_ALIVE_S: gaudi_print_irq_info(hdev, event_type, false); gaudi_print_fw_alive_info(hdev, &eq_entry->fw_alive); + event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR; goto reset_device; default: diff --git a/drivers/misc/habanalabs/gaudi2/gaudi2.c b/drivers/misc/habanalabs/gaudi2/gaudi2.c index 60694b8ed6fe..f749f7377ea6 100644 --- a/drivers/misc/habanalabs/gaudi2/gaudi2.c +++ b/drivers/misc/habanalabs/gaudi2/gaudi2.c @@ -8530,6 +8530,7 @@ static void gaudi2_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_ent struct gaudi2_device *gaudi2 = hdev->asic_specific; bool reset_required = false, skip_reset = false; int index, sbte_index; + u64 event_mask = 0; u16 event_type; ctl = le32_to_cpu(eq_entry->hdr.ctl); @@ -8551,6 +8552,7 @@ static void gaudi2_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_ent fallthrough; case GAUDI2_EVENT_ROTATOR0_SERR ... GAUDI2_EVENT_ROTATOR1_DERR: reset_flags |= HL_DRV_RESET_FW_FATAL_ERR; + event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR; reset_required = gaudi2_handle_ecc_event(hdev, event_type, &eq_entry->ecc_data); break; @@ -8560,21 +8562,25 @@ static void gaudi2_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_ent fallthrough; case GAUDI2_EVENT_NIC0_QM0 ... GAUDI2_EVENT_NIC11_QM1: gaudi2_handle_qman_err(hdev, event_type); + event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR; break; case GAUDI2_EVENT_ARC_AXI_ERROR_RESPONSE_0: reset_flags |= HL_DRV_RESET_FW_FATAL_ERR; gaudi2_handle_arc_farm_sei_err(hdev); + event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR; break; case GAUDI2_EVENT_CPU_AXI_ERR_RSP: gaudi2_handle_cpu_sei_err(hdev); + event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR; break; case GAUDI2_EVENT_PDMA_CH0_AXI_ERR_RSP: case GAUDI2_EVENT_PDMA_CH1_AXI_ERR_RSP: reset_flags |= HL_DRV_RESET_FW_FATAL_ERR; gaudi2_handle_qm_sei_err(hdev, event_type, &eq_entry->razwi_info); + event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR; break; case GAUDI2_EVENT_ROTATOR0_AXI_ERROR_RESPONSE: @@ -8582,6 +8588,7 @@ static void gaudi2_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_ent index = event_type - GAUDI2_EVENT_ROTATOR0_AXI_ERROR_RESPONSE; gaudi2_handle_rot_err(hdev, index, &eq_entry->razwi_with_intr_cause); gaudi2_handle_qm_sei_err(hdev, event_type, NULL); + event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR; break; case GAUDI2_EVENT_TPC0_AXI_ERR_RSP ... GAUDI2_EVENT_TPC24_AXI_ERR_RSP: @@ -8589,11 +8596,13 @@ static void gaudi2_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_ent gaudi2_tpc_ack_interrupts(hdev, index, "AXI_ERR_RSP", &eq_entry->razwi_with_intr_cause); gaudi2_handle_qm_sei_err(hdev, event_type, NULL); + event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR; break; case GAUDI2_EVENT_DEC0_AXI_ERR_RSPONSE ... GAUDI2_EVENT_DEC9_AXI_ERR_RSPONSE: index = event_type - GAUDI2_EVENT_DEC0_AXI_ERR_RSPONSE; gaudi2_handle_dec_err(hdev, index, "AXI_ERR_RESPONSE", &eq_entry->razwi_info); + event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR; break; case GAUDI2_EVENT_TPC0_KERNEL_ERR: @@ -8624,6 +8633,7 @@ static void gaudi2_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_ent index = (event_type - GAUDI2_EVENT_TPC0_KERNEL_ERR) / (GAUDI2_EVENT_TPC1_KERNEL_ERR - GAUDI2_EVENT_TPC0_KERNEL_ERR); gaudi2_tpc_ack_interrupts(hdev, index, "KRN_ERR", &eq_entry->razwi_with_intr_cause); + event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR; break; case GAUDI2_EVENT_DEC0_SPI: @@ -8639,6 +8649,7 @@ static void gaudi2_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_ent index = (event_type - GAUDI2_EVENT_DEC0_SPI) / (GAUDI2_EVENT_DEC1_SPI - GAUDI2_EVENT_DEC0_SPI); gaudi2_handle_dec_err(hdev, index, "SPI", &eq_entry->razwi_info); + event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR; break; case GAUDI2_EVENT_MME0_CTRL_AXI_ERROR_RESPONSE: @@ -8651,6 +8662,7 @@ static void gaudi2_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_ent gaudi2_handle_mme_err(hdev, index, "CTRL_AXI_ERROR_RESPONSE", &eq_entry->razwi_info); gaudi2_handle_qm_sei_err(hdev, event_type, NULL); + event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR; break; case GAUDI2_EVENT_MME0_QMAN_SW_ERROR: @@ -8661,6 +8673,7 @@ static void gaudi2_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_ent (GAUDI2_EVENT_MME1_QMAN_SW_ERROR - GAUDI2_EVENT_MME0_QMAN_SW_ERROR); gaudi2_handle_mme_err(hdev, index, "QMAN_SW_ERROR", &eq_entry->razwi_info); + event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR; break; case GAUDI2_EVENT_MME0_WAP_SOURCE_RESULT_INVALID: @@ -8671,50 +8684,58 @@ static void gaudi2_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_ent (GAUDI2_EVENT_MME1_WAP_SOURCE_RESULT_INVALID - GAUDI2_EVENT_MME0_WAP_SOURCE_RESULT_INVALID); gaudi2_handle_mme_wap_err(hdev, index, &eq_entry->razwi_info); + event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR; break; case GAUDI2_EVENT_KDMA_CH0_AXI_ERR_RSP: case GAUDI2_EVENT_KDMA0_CORE: gaudi2_handle_kdma_core_event(hdev, le64_to_cpu(eq_entry->intr_cause.intr_cause_data)); + event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR; break; case GAUDI2_EVENT_HDMA2_CORE ... GAUDI2_EVENT_PDMA1_CORE: gaudi2_handle_dma_core_event(hdev, le64_to_cpu(eq_entry->intr_cause.intr_cause_data)); + event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR; break; case GAUDI2_EVENT_PCIE_ADDR_DEC_ERR: gaudi2_print_pcie_addr_dec_info(hdev, le64_to_cpu(eq_entry->intr_cause.intr_cause_data)); reset_flags |= HL_DRV_RESET_FW_FATAL_ERR; + event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR; break; case GAUDI2_EVENT_HMMU0_PAGE_FAULT_OR_WR_PERM ... GAUDI2_EVENT_HMMU12_SECURITY_ERROR: case GAUDI2_EVENT_HMMU_0_AXI_ERR_RSP ... GAUDI2_EVENT_HMMU_12_AXI_ERR_RSP: - case GAUDI2_EVENT_PMMU0_PAGE_FAULT_WR_PERM ... GAUDI2_EVENT_PMMU0_SECURITY_ERROR: case GAUDI2_EVENT_PMMU_AXI_ERR_RSP_0: gaudi2_handle_mmu_spi_sei_err(hdev, event_type); reset_flags |= HL_DRV_RESET_FW_FATAL_ERR; + event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR; break; case GAUDI2_EVENT_HIF0_FATAL ... GAUDI2_EVENT_HIF12_FATAL: gaudi2_handle_hif_fatal(hdev, event_type, le64_to_cpu(eq_entry->intr_cause.intr_cause_data)); reset_flags |= HL_DRV_RESET_FW_FATAL_ERR; + event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR; break; case GAUDI2_EVENT_PMMU_FATAL_0: gaudi2_handle_pif_fatal(hdev, le64_to_cpu(eq_entry->intr_cause.intr_cause_data)); reset_flags |= HL_DRV_RESET_FW_FATAL_ERR; + event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR; break; case GAUDI2_EVENT_PSOC63_RAZWI_OR_PID_MIN_MAX_INTERRUPT: gaudi2_ack_psoc_razwi_event_handler(hdev); + event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR; break; case GAUDI2_EVENT_HBM0_MC0_SEI_SEVERE ... GAUDI2_EVENT_HBM5_MC1_SEI_NON_SEVERE: + event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR; if (gaudi2_handle_hbm_mc_sei_err(hdev, event_type, &eq_entry->sei_data)) { reset_flags |= HL_DRV_RESET_FW_FATAL_ERR; reset_required = true; @@ -8723,25 +8744,31 @@ static void gaudi2_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_ent case GAUDI2_EVENT_HBM_CATTRIP_0 ... GAUDI2_EVENT_HBM_CATTRIP_5: gaudi2_handle_hbm_cattrip(hdev, le64_to_cpu(eq_entry->intr_cause.intr_cause_data)); + event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR; break; case GAUDI2_EVENT_HBM0_MC0_SPI ... GAUDI2_EVENT_HBM5_MC1_SPI: gaudi2_handle_hbm_mc_spi(hdev, le64_to_cpu(eq_entry->intr_cause.intr_cause_data)); + event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR; break; case GAUDI2_EVENT_PCIE_DRAIN_COMPLETE: gaudi2_handle_pcie_drain(hdev, &eq_entry->pcie_drain_ind_data); + event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR; break; case GAUDI2_EVENT_PSOC59_RPM_ERROR_OR_DRAIN: gaudi2_handle_psoc_drain(hdev, le64_to_cpu(eq_entry->intr_cause.intr_cause_data)); + event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR; break; case GAUDI2_EVENT_CPU_AXI_ECC: reset_flags |= HL_DRV_RESET_FW_FATAL_ERR; + event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR; break; case GAUDI2_EVENT_CPU_L2_RAM_ECC: reset_flags |= HL_DRV_RESET_FW_FATAL_ERR; + event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR; break; case GAUDI2_EVENT_MME0_SBTE0_AXI_ERR_RSP ... GAUDI2_EVENT_MME0_SBTE4_AXI_ERR_RSP: case GAUDI2_EVENT_MME1_SBTE0_AXI_ERR_RSP ... GAUDI2_EVENT_MME1_SBTE4_AXI_ERR_RSP: @@ -8755,17 +8782,24 @@ static void gaudi2_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_ent GAUDI2_EVENT_MME0_SBTE0_AXI_ERR_RSP); gaudi2_handle_mme_sbte_err(hdev, index, sbte_index, le64_to_cpu(eq_entry->intr_cause.intr_cause_data)); + event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR; break; case GAUDI2_EVENT_VM0_ALARM_A ... GAUDI2_EVENT_VM3_ALARM_B: reset_flags |= HL_DRV_RESET_FW_FATAL_ERR; + event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR; break; case GAUDI2_EVENT_PSOC_AXI_ERR_RSP: + event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR; + break; case GAUDI2_EVENT_PSOC_PRSTN_FALL: + event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR; break; case GAUDI2_EVENT_PCIE_APB_TIMEOUT: reset_flags |= HL_DRV_RESET_FW_FATAL_ERR; + event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR; break; case GAUDI2_EVENT_PCIE_FATAL_ERR: + event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR; break; case GAUDI2_EVENT_TPC0_BMON_SPMU: case GAUDI2_EVENT_TPC1_BMON_SPMU: @@ -8817,6 +8851,7 @@ static void gaudi2_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_ent case GAUDI2_EVENT_DEC8_BMON_SPMU: case GAUDI2_EVENT_DEC9_BMON_SPMU: case GAUDI2_EVENT_ROTATOR0_BMON_SPMU ... GAUDI2_EVENT_SM3_BMON_SPMU: + event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR; break; case GAUDI2_EVENT_CPU_FIX_POWER_ENV_S: @@ -8824,43 +8859,53 @@ static void gaudi2_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_ent case GAUDI2_EVENT_CPU_FIX_THERMAL_ENV_S: case GAUDI2_EVENT_CPU_FIX_THERMAL_ENV_E: gaudi2_print_clk_change_info(hdev, event_type); + event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR; break; case GAUDI2_EVENT_CPU_PKT_QUEUE_OUT_SYNC: gaudi2_print_out_of_sync_info(hdev, &eq_entry->pkt_sync_err); + event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR; break; case GAUDI2_EVENT_PCIE_FLR_REQUESTED: + event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR; /* Do nothing- FW will handle it */ break; case GAUDI2_EVENT_PCIE_P2P_MSIX: gaudi2_handle_pcie_p2p_msix(hdev); + event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR; break; case GAUDI2_EVENT_SM0_AXI_ERROR_RESPONSE ... GAUDI2_EVENT_SM3_AXI_ERROR_RESPONSE: index = event_type - GAUDI2_EVENT_SM0_AXI_ERROR_RESPONSE; skip_reset = !gaudi2_handle_sm_err(hdev, index); + event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR; break; case GAUDI2_EVENT_PSOC_MME_PLL_LOCK_ERR ... GAUDI2_EVENT_DCORE2_HBM_PLL_LOCK_ERR: + event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR; break; case GAUDI2_EVENT_CPU_CPLD_SHUTDOWN_CAUSE: dev_info(hdev->dev, "CPLD shutdown cause, reset reason: 0x%llx\n", le64_to_cpu(eq_entry->data[0])); + event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR; break; case GAUDI2_EVENT_CPU_CPLD_SHUTDOWN_EVENT: dev_err(hdev->dev, "CPLD shutdown event, reset reason: 0x%llx\n", le64_to_cpu(eq_entry->data[0])); + event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR; break; case GAUDI2_EVENT_CPU_PKT_SANITY_FAILED: gaudi2_print_cpu_pkt_failure_info(hdev, &eq_entry->pkt_sync_err); + event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR; break; case GAUDI2_EVENT_ARC_DCCM_FULL: hl_arc_event_handle(hdev, &eq_entry->arc_data); + event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR; break; default: @@ -8876,15 +8921,22 @@ static void gaudi2_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_ent if (!gaudi2_irq_map_table[event_type].msg) hl_fw_unmask_irq(hdev, event_type); + if (event_mask) + hl_notifier_event_send_all(hdev, event_mask); + return; reset_device: if (hdev->hard_reset_on_fw_events) { hl_device_reset(hdev, reset_flags); + event_mask |= HL_NOTIFIER_EVENT_DEVICE_RESET; } else { if (!gaudi2_irq_map_table[event_type].msg) hl_fw_unmask_irq(hdev, event_type); } + + if (event_mask) + hl_notifier_event_send_all(hdev, event_mask); } static int gaudi2_memset_device_memory(struct hl_device *hdev, u64 addr, u64 size, u64 val) diff --git a/include/uapi/misc/habanalabs.h b/include/uapi/misc/habanalabs.h index 3005cc04d4b1..a4bab0fd8223 100644 --- a/include/uapi/misc/habanalabs.h +++ b/include/uapi/misc/habanalabs.h @@ -715,12 +715,16 @@ enum hl_server_type { * HL_NOTIFIER_EVENT_DEVICE_RESET - Indicates device requires a reset * HL_NOTIFIER_EVENT_CS_TIMEOUT - Indicates CS timeout error * HL_NOTIFIER_EVENT_DEVICE_UNAVAILABLE - Indicates device is unavailable + * HL_NOTIFIER_EVENT_USER_ENGINE_ERR - Indicates device engine in error state + * HL_NOTIFIER_EVENT_GENERAL_HW_ERR - Indicates device HW error */ #define HL_NOTIFIER_EVENT_TPC_ASSERT (1ULL << 0) #define HL_NOTIFIER_EVENT_UNDEFINED_OPCODE (1ULL << 1) #define HL_NOTIFIER_EVENT_DEVICE_RESET (1ULL << 2) #define HL_NOTIFIER_EVENT_CS_TIMEOUT (1ULL << 3) #define HL_NOTIFIER_EVENT_DEVICE_UNAVAILABLE (1ULL << 4) +#define HL_NOTIFIER_EVENT_USER_ENGINE_ERR (1ULL << 5) +#define HL_NOTIFIER_EVENT_GENERAL_HW_ERR (1ULL << 6) /* Opcode for management ioctl * -- cgit v1.2.3 From 0c88760f8f5e13e32f624a1da71144b240b05125 Mon Sep 17 00:00:00 2001 From: Dani Liberman Date: Mon, 1 Aug 2022 15:23:44 +0300 Subject: habanalabs/gaudi2: add secured attestation info uapi User will provide a nonce via the ioctl, and will retrieve secured attestation data of the boot, generated using given nonce. Signed-off-by: Dani Liberman Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/firmware_if.c | 46 ++++++++++++++ drivers/misc/habanalabs/common/habanalabs.h | 3 + drivers/misc/habanalabs/common/habanalabs_ioctl.c | 52 +++++++++++++++ drivers/misc/habanalabs/include/common/cpucp_if.h | 77 ++++++++++++++++++++++- include/uapi/misc/habanalabs.h | 43 +++++++++++++ 5 files changed, 219 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/drivers/misc/habanalabs/common/firmware_if.c b/drivers/misc/habanalabs/common/firmware_if.c index c2375917fc02..26a7529083e1 100644 --- a/drivers/misc/habanalabs/common/firmware_if.c +++ b/drivers/misc/habanalabs/common/firmware_if.c @@ -2988,3 +2988,49 @@ void hl_fw_set_max_power(struct hl_device *hdev) if (rc) dev_err(hdev->dev, "Failed to set max power, error %d\n", rc); } + +static int hl_fw_get_sec_attest_data(struct hl_device *hdev, u32 packet_id, void *data, u32 size, + u32 nonce, u32 timeout) +{ + struct cpucp_packet pkt = {}; + dma_addr_t req_dma_addr; + void *req_cpu_addr; + int rc; + + req_cpu_addr = hl_cpu_accessible_dma_pool_alloc(hdev, size, &req_dma_addr); + if (!data) { + dev_err(hdev->dev, + "Failed to allocate DMA memory for CPU-CP packet %u\n", packet_id); + return -ENOMEM; + } + + memset(data, 0, size); + + pkt.ctl = cpu_to_le32(packet_id << CPUCP_PKT_CTL_OPCODE_SHIFT); + pkt.addr = cpu_to_le64(req_dma_addr); + pkt.data_max_size = cpu_to_le32(size); + pkt.nonce = cpu_to_le32(nonce); + + rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt), + timeout, NULL); + if (rc) { + dev_err(hdev->dev, + "Failed to handle CPU-CP pkt %u, error %d\n", packet_id, rc); + goto out; + } + + memcpy(data, req_cpu_addr, size); + +out: + hl_cpu_accessible_dma_pool_free(hdev, size, req_cpu_addr); + + return rc; +} + +int hl_fw_get_sec_attest_info(struct hl_device *hdev, struct cpucp_sec_attest_info *sec_attest_info, + u32 nonce) +{ + return hl_fw_get_sec_attest_data(hdev, CPUCP_PACKET_SEC_ATTEST_GET, sec_attest_info, + sizeof(struct cpucp_sec_attest_info), nonce, + HL_CPUCP_SEC_ATTEST_INFO_TINEOUT_USEC); +} diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index 44050d463e23..58c95b13be69 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -66,6 +66,7 @@ struct hl_fpriv; #define HL_CPUCP_INFO_TIMEOUT_USEC 10000000 /* 10s */ #define HL_CPUCP_EEPROM_TIMEOUT_USEC 10000000 /* 10s */ #define HL_CPUCP_MON_DUMP_TIMEOUT_USEC 10000000 /* 10s */ +#define HL_CPUCP_SEC_ATTEST_INFO_TINEOUT_USEC 10000000 /* 10s */ #define HL_FW_STATUS_POLL_INTERVAL_USEC 10000 /* 10ms */ #define HL_FW_COMMS_STATUS_PLDM_POLL_INTERVAL_USEC 1000000 /* 1s */ @@ -3748,6 +3749,8 @@ int hl_get_pwm_info(struct hl_device *hdev, int sensor_index, u32 attr, long *va void hl_set_pwm_info(struct hl_device *hdev, int sensor_index, u32 attr, long value); long hl_fw_get_max_power(struct hl_device *hdev); void hl_fw_set_max_power(struct hl_device *hdev); +int hl_fw_get_sec_attest_info(struct hl_device *hdev, struct cpucp_sec_attest_info *sec_attest_info, + u32 nonce); int hl_set_voltage(struct hl_device *hdev, int sensor_index, u32 attr, long value); int hl_set_current(struct hl_device *hdev, int sensor_index, u32 attr, long value); int hl_set_power(struct hl_device *hdev, int sensor_index, u32 attr, long value); diff --git a/drivers/misc/habanalabs/common/habanalabs_ioctl.c b/drivers/misc/habanalabs/common/habanalabs_ioctl.c index ab0be082f3a6..43afe40966e5 100644 --- a/drivers/misc/habanalabs/common/habanalabs_ioctl.c +++ b/drivers/misc/habanalabs/common/habanalabs_ioctl.c @@ -662,6 +662,55 @@ static int dev_mem_alloc_page_sizes_info(struct hl_fpriv *hpriv, struct hl_info_ return copy_to_user(out, &info, min_t(size_t, max_size, sizeof(info))) ? -EFAULT : 0; } +static int sec_attest_info(struct hl_fpriv *hpriv, struct hl_info_args *args) +{ + void __user *out = (void __user *) (uintptr_t) args->return_pointer; + struct cpucp_sec_attest_info *sec_attest_info; + struct hl_info_sec_attest *info; + u32 max_size = args->return_size; + int rc; + + if ((!max_size) || (!out)) + return -EINVAL; + + sec_attest_info = kmalloc(sizeof(*sec_attest_info), GFP_KERNEL); + if (!sec_attest_info) + return -ENOMEM; + + info = kmalloc(sizeof(*info), GFP_KERNEL); + if (!info) { + rc = -ENOMEM; + goto free_sec_attest_info; + } + + rc = hl_fw_get_sec_attest_info(hpriv->hdev, sec_attest_info, args->sec_attest_nonce); + if (rc) + goto free_info; + + info->nonce = le32_to_cpu(sec_attest_info->nonce); + info->pcr_quote_len = le16_to_cpu(sec_attest_info->pcr_quote_len); + info->pub_data_len = le16_to_cpu(sec_attest_info->pub_data_len); + info->certificate_len = le16_to_cpu(sec_attest_info->certificate_len); + info->pcr_num_reg = sec_attest_info->pcr_num_reg; + info->pcr_reg_len = sec_attest_info->pcr_reg_len; + info->quote_sig_len = sec_attest_info->quote_sig_len; + memcpy(&info->pcr_data, &sec_attest_info->pcr_data, sizeof(info->pcr_data)); + memcpy(&info->pcr_quote, &sec_attest_info->pcr_quote, sizeof(info->pcr_quote)); + memcpy(&info->public_data, &sec_attest_info->public_data, sizeof(info->public_data)); + memcpy(&info->certificate, &sec_attest_info->certificate, sizeof(info->certificate)); + memcpy(&info->quote_sig, &sec_attest_info->quote_sig, sizeof(info->quote_sig)); + + rc = copy_to_user(out, info, + min_t(size_t, max_size, sizeof(*info))) ? -EFAULT : 0; + +free_info: + kfree(info); +free_sec_attest_info: + kfree(sec_attest_info); + + return rc; +} + static int eventfd_register(struct hl_fpriv *hpriv, struct hl_info_args *args) { int rc; @@ -844,6 +893,9 @@ static int _hl_info_ioctl(struct hl_fpriv *hpriv, void *data, case HL_INFO_DRAM_PENDING_ROWS: return dram_pending_rows_info(hpriv, args); + case HL_INFO_SECURED_ATTESTATION: + return sec_attest_info(hpriv, args); + case HL_INFO_REGISTER_EVENTFD: return eventfd_register(hpriv, args); diff --git a/drivers/misc/habanalabs/include/common/cpucp_if.h b/drivers/misc/habanalabs/include/common/cpucp_if.h index 9593d1a26945..baa5aa43b6f4 100644 --- a/drivers/misc/habanalabs/include/common/cpucp_if.h +++ b/drivers/misc/habanalabs/include/common/cpucp_if.h @@ -629,6 +629,12 @@ enum pq_init_status { * CPUCP_PACKET_ENGINE_CORE_ASID_SET - * Packet to perform engine core ASID configuration * + * CPUCP_PACKET_SEC_ATTEST_GET - + * Get the attestaion data that is collected during various stages of the + * boot sequence. the attestation data is also hashed with some unique + * number (nonce) provided by the host to prevent replay attacks. + * public key and certificate also provided as part of the FW response. + * * CPUCP_PACKET_MONITOR_DUMP_GET - * Get monitors registers dump from the CpuCP kernel. * The CPU will put the registers dump in the a buffer allocated by the driver @@ -691,15 +697,15 @@ enum cpucp_packet_id { CPUCP_PACKET_RESERVED, /* not used */ CPUCP_PACKET_ENGINE_CORE_ASID_SET, /* internal */ CPUCP_PACKET_RESERVED2, /* not used */ + CPUCP_PACKET_SEC_ATTEST_GET, /* internal */ CPUCP_PACKET_RESERVED3, /* not used */ CPUCP_PACKET_RESERVED4, /* not used */ - CPUCP_PACKET_RESERVED5, /* not used */ CPUCP_PACKET_MONITOR_DUMP_GET, /* debugfs */ + CPUCP_PACKET_RESERVED5, /* not used */ CPUCP_PACKET_RESERVED6, /* not used */ CPUCP_PACKET_RESERVED7, /* not used */ CPUCP_PACKET_RESERVED8, /* not used */ CPUCP_PACKET_RESERVED9, /* not used */ - CPUCP_PACKET_RESERVED10, /* not used */ CPUCP_PACKET_ACTIVE_STATUS_SET, /* internal */ CPUCP_PACKET_ID_MAX /* must be last */ }; @@ -794,6 +800,9 @@ struct cpucp_packet { * result cannot be used to hold general purpose data. */ __le32 status_mask; + + /* random, used once number, for security packets */ + __le32 nonce; }; /* For NIC requests */ @@ -1219,6 +1228,70 @@ enum cpu_reset_status { CPU_RST_STATUS_SOFT_RST_DONE = 1, }; +#define SEC_PCR_DATA_BUF_SZ 256 +#define SEC_PCR_QUOTE_BUF_SZ 510 /* (512 - 2) 2 bytes used for size */ +#define SEC_SIGNATURE_BUF_SZ 255 /* (256 - 1) 1 byte used for size */ +#define SEC_PUB_DATA_BUF_SZ 510 /* (512 - 2) 2 bytes used for size */ +#define SEC_CERTIFICATE_BUF_SZ 2046 /* (2048 - 2) 2 bytes used for size */ + +/* + * struct cpucp_sec_attest_info - attestation report of the boot + * @pcr_data: raw values of the PCR registers + * @pcr_num_reg: number of PCR registers in the pcr_data array + * @pcr_reg_len: length of each PCR register in the pcr_data array (bytes) + * @nonce: number only used once. random number provided by host. this also + * passed to the quote command as a qualifying data. + * @pcr_quote_len: length of the attestation quote data (bytes) + * @pcr_quote: attestation report data structure + * @quote_sig_len: length of the attestation report signature (bytes) + * @quote_sig: signature structure of the attestation report + * @pub_data_len: length of the public data (bytes) + * @public_data: public key for the signed attestation + * (outPublic + name + qualifiedName) + * @certificate_len: length of the certificate (bytes) + * @certificate: certificate for the attestation signing key + */ +struct cpucp_sec_attest_info { + __u8 pcr_data[SEC_PCR_DATA_BUF_SZ]; + __u8 pcr_num_reg; + __u8 pcr_reg_len; + __le16 pad0; + __le32 nonce; + __le16 pcr_quote_len; + __u8 pcr_quote[SEC_PCR_QUOTE_BUF_SZ]; + __u8 quote_sig_len; + __u8 quote_sig[SEC_SIGNATURE_BUF_SZ]; + __le16 pub_data_len; + __u8 public_data[SEC_PUB_DATA_BUF_SZ]; + __le16 certificate_len; + __u8 certificate[SEC_CERTIFICATE_BUF_SZ]; +}; + +/* + * struct cpucp_dev_info_signed - device information signed by a secured device + * @info: device information structure as defined above + * @nonce: number only used once. random number provided by host. this number is + * hashed and signed along with the device information. + * @info_sig_len: length of the attestation signature (bytes) + * @info_sig: signature of the info + nonce data. + * @pub_data_len: length of the public data (bytes) + * @public_data: public key info signed info data + * (outPublic + name + qualifiedName) + * @certificate_len: length of the certificate (bytes) + * @certificate: certificate for the signing key + */ +struct cpucp_dev_info_signed { + struct cpucp_info info; /* assumed to be 64bit aligned */ + __le32 nonce; + __le32 pad0; + __u8 info_sig_len; + __u8 info_sig[SEC_SIGNATURE_BUF_SZ]; + __le16 pub_data_len; + __u8 public_data[SEC_PUB_DATA_BUF_SZ]; + __le16 certificate_len; + __u8 certificate[SEC_CERTIFICATE_BUF_SZ]; +}; + /* * struct dcore_monitor_regs_data - DCORE monitor regs data. * the structure follows sync manager block layout. relevant only to Gaudi. diff --git a/include/uapi/misc/habanalabs.h b/include/uapi/misc/habanalabs.h index a4bab0fd8223..e00ebe05097d 100644 --- a/include/uapi/misc/habanalabs.h +++ b/include/uapi/misc/habanalabs.h @@ -773,6 +773,7 @@ enum hl_server_type { * Razwi initiator. * Razwi cause, was it a page fault or MMU access error. * HL_INFO_DEV_MEM_ALLOC_PAGE_SIZES - Retrieve valid page sizes for device memory allocation + * HL_INFO_SECURED_ATTESTATION - Retrieve attestation report of the boot. * HL_INFO_REGISTER_EVENTFD - Register eventfd for event notifications. * HL_INFO_UNREGISTER_EVENTFD - Unregister eventfd * HL_INFO_GET_EVENTS - Retrieve the last occurred events @@ -802,6 +803,7 @@ enum hl_server_type { #define HL_INFO_CS_TIMEOUT_EVENT 24 #define HL_INFO_RAZWI_EVENT 25 #define HL_INFO_DEV_MEM_ALLOC_PAGE_SIZES 26 +#define HL_INFO_SECURED_ATTESTATION 27 #define HL_INFO_REGISTER_EVENTFD 28 #define HL_INFO_UNREGISTER_EVENTFD 29 #define HL_INFO_GET_EVENTS 30 @@ -1133,6 +1135,45 @@ struct hl_info_dev_memalloc_page_sizes { __u64 page_order_bitmask; }; +#define SEC_PCR_DATA_BUF_SZ 256 +#define SEC_PCR_QUOTE_BUF_SZ 510 /* (512 - 2) 2 bytes used for size */ +#define SEC_SIGNATURE_BUF_SZ 255 /* (256 - 1) 1 byte used for size */ +#define SEC_PUB_DATA_BUF_SZ 510 /* (512 - 2) 2 bytes used for size */ +#define SEC_CERTIFICATE_BUF_SZ 2046 /* (2048 - 2) 2 bytes used for size */ + +/* + * struct hl_info_sec_attest - attestation report of the boot + * @nonce: number only used once. random number provided by host. this also passed to the quote + * command as a qualifying data. + * @pcr_quote_len: length of the attestation quote data (bytes) + * @pub_data_len: length of the public data (bytes) + * @certificate_len: length of the certificate (bytes) + * @pcr_num_reg: number of PCR registers in the pcr_data array + * @pcr_reg_len: length of each PCR register in the pcr_data array (bytes) + * @quote_sig_len: length of the attestation report signature (bytes) + * @pcr_data: raw values of the PCR registers + * @pcr_quote: attestation report data structure + * @quote_sig: signature structure of the attestation report + * @public_data: public key for the signed attestation + * (outPublic + name + qualifiedName) + * @certificate: certificate for the attestation signing key + */ +struct hl_info_sec_attest { + __u32 nonce; + __u16 pcr_quote_len; + __u16 pub_data_len; + __u16 certificate_len; + __u8 pcr_num_reg; + __u8 pcr_reg_len; + __u8 quote_sig_len; + __u8 pcr_data[SEC_PCR_DATA_BUF_SZ]; + __u8 pcr_quote[SEC_PCR_QUOTE_BUF_SZ]; + __u8 quote_sig[SEC_SIGNATURE_BUF_SZ]; + __u8 public_data[SEC_PUB_DATA_BUF_SZ]; + __u8 certificate[SEC_CERTIFICATE_BUF_SZ]; + __u8 pad0[2]; +}; + enum gaudi_dcores { HL_GAUDI_WS_DCORE, HL_GAUDI_WN_DCORE, @@ -1158,6 +1199,7 @@ enum gaudi_dcores { * driver. It is possible for the user to allocate buffer larger than * needed, hence updating this variable so user will know the exact amount * of bytes copied by the kernel to the buffer. + * @sec_attest_nonce: Nonce number used for attestation report. * @pad: Padding to 64 bit. */ struct hl_info_args { @@ -1172,6 +1214,7 @@ struct hl_info_args { __u32 pll_index; __u32 eventfd; __u32 user_buffer_actual_size; + __u32 sec_attest_nonce; }; __u32 pad; -- cgit v1.2.3 From bcc57a48eaee63a71983996c4c9d89ce7cbf55d9 Mon Sep 17 00:00:00 2001 From: Andrea Merello Date: Wed, 7 Sep 2022 15:21:52 +0200 Subject: iio: add modifiers for linear acceleration Add IIO_MOD_LINEAR_X, IIO_MOD_LINEAR_Y and IIO_MOD_LINEAR_Z modifiers to te IIO core, which is preparatory for adding the Bosch BNO055 IMU driver. Bosch BNO055 IMU can report raw accelerations (among x, y and z axis) as well as the so called "linear accelerations" (again, among x, y and z axis) which is basically the acceleration after subtracting gravity and for which those new modifiers are for. Signed-off-by: Andrea Merello Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220907132205.28021-2-andrea.merello@iit.it Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-core.c | 3 +++ include/uapi/linux/iio/types.h | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 583e0e5205a0..6f7b6fd0c6ef 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -134,6 +134,9 @@ static const char * const iio_modifier_names[] = { [IIO_MOD_ETHANOL] = "ethanol", [IIO_MOD_H2] = "h2", [IIO_MOD_O2] = "o2", + [IIO_MOD_LINEAR_X] = "linear_x", + [IIO_MOD_LINEAR_Y] = "linear_y", + [IIO_MOD_LINEAR_Z] = "linear_z", }; /* relies on pairs of these shared then separate */ diff --git a/include/uapi/linux/iio/types.h b/include/uapi/linux/iio/types.h index 913864221ac4..b7ba9861a24d 100644 --- a/include/uapi/linux/iio/types.h +++ b/include/uapi/linux/iio/types.h @@ -95,6 +95,9 @@ enum iio_modifier { IIO_MOD_ETHANOL, IIO_MOD_H2, IIO_MOD_O2, + IIO_MOD_LINEAR_X, + IIO_MOD_LINEAR_Y, + IIO_MOD_LINEAR_Z, }; enum iio_event_type { @@ -118,4 +121,3 @@ enum iio_event_direction { }; #endif /* _UAPI_IIO_TYPES_H_ */ - -- cgit v1.2.3 From dcedf14553810cd6bbf7227c995beb4548e0859d Mon Sep 17 00:00:00 2001 From: Andrea Merello Date: Wed, 7 Sep 2022 15:21:55 +0200 Subject: iio: add modifers for pitch, yaw, roll Add modifiers for reporting rotations as euler angles (i.e. yaw, pitch and roll). Signed-off-by: Andrea Merello Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220907132205.28021-5-andrea.merello@iit.it Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-core.c | 3 +++ include/uapi/linux/iio/types.h | 3 +++ 2 files changed, 6 insertions(+) (limited to 'include') diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 6f7b6fd0c6ef..8f12993f87be 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -137,6 +137,9 @@ static const char * const iio_modifier_names[] = { [IIO_MOD_LINEAR_X] = "linear_x", [IIO_MOD_LINEAR_Y] = "linear_y", [IIO_MOD_LINEAR_Z] = "linear_z", + [IIO_MOD_PITCH] = "pitch", + [IIO_MOD_YAW] = "yaw", + [IIO_MOD_ROLL] = "roll", }; /* relies on pairs of these shared then separate */ diff --git a/include/uapi/linux/iio/types.h b/include/uapi/linux/iio/types.h index b7ba9861a24d..c79f2f046a0b 100644 --- a/include/uapi/linux/iio/types.h +++ b/include/uapi/linux/iio/types.h @@ -98,6 +98,9 @@ enum iio_modifier { IIO_MOD_LINEAR_X, IIO_MOD_LINEAR_Y, IIO_MOD_LINEAR_Z, + IIO_MOD_PITCH, + IIO_MOD_YAW, + IIO_MOD_ROLL, }; enum iio_event_type { -- cgit v1.2.3 From cca1fd41ab2862465d75443822d751e4f9a112ee Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Thu, 22 Sep 2022 07:20:57 -0400 Subject: counter: Realign counter_comp comment block to 80 characters The member documentation comment lines for struct counter_comp extend past the 80-characters column boundary due to extra identation at the start of each section. This patch realigns the comment block within the 80-characters boundary by removing these superfluous indents. Reviewed-by: Yanteng Si Link: https://lore.kernel.org/r/20220902120839.4260-1-william.gray@linaro.org/ Signed-off-by: William Breathitt Gray Link: https://lore.kernel.org/r/8294b04153c33602e9c3dd21ac90c1e99bd0fdaf.1663844776.git.william.gray@linaro.org Signed-off-by: Greg Kroah-Hartman --- include/linux/counter.h | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) (limited to 'include') diff --git a/include/linux/counter.h b/include/linux/counter.h index 1fe17f5adb09..a81234bc8ea8 100644 --- a/include/linux/counter.h +++ b/include/linux/counter.h @@ -38,64 +38,64 @@ enum counter_comp_type { * @type: Counter component data type * @name: device-specific component name * @priv: component-relevant data - * @action_read: Synapse action mode read callback. The read value of the + * @action_read: Synapse action mode read callback. The read value of the * respective Synapse action mode should be passed back via * the action parameter. - * @device_u8_read: Device u8 component read callback. The read value of the + * @device_u8_read: Device u8 component read callback. The read value of the * respective Device u8 component should be passed back via * the val parameter. - * @count_u8_read: Count u8 component read callback. The read value of the + * @count_u8_read: Count u8 component read callback. The read value of the * respective Count u8 component should be passed back via * the val parameter. - * @signal_u8_read: Signal u8 component read callback. The read value of the + * @signal_u8_read: Signal u8 component read callback. The read value of the * respective Signal u8 component should be passed back via * the val parameter. - * @device_u32_read: Device u32 component read callback. The read value of + * @device_u32_read: Device u32 component read callback. The read value of * the respective Device u32 component should be passed * back via the val parameter. - * @count_u32_read: Count u32 component read callback. The read value of the + * @count_u32_read: Count u32 component read callback. The read value of the * respective Count u32 component should be passed back via * the val parameter. - * @signal_u32_read: Signal u32 component read callback. The read value of + * @signal_u32_read: Signal u32 component read callback. The read value of * the respective Signal u32 component should be passed * back via the val parameter. - * @device_u64_read: Device u64 component read callback. The read value of + * @device_u64_read: Device u64 component read callback. The read value of * the respective Device u64 component should be passed * back via the val parameter. - * @count_u64_read: Count u64 component read callback. The read value of the + * @count_u64_read: Count u64 component read callback. The read value of the * respective Count u64 component should be passed back via * the val parameter. - * @signal_u64_read: Signal u64 component read callback. The read value of + * @signal_u64_read: Signal u64 component read callback. The read value of * the respective Signal u64 component should be passed * back via the val parameter. - * @action_write: Synapse action mode write callback. The write value of + * @action_write: Synapse action mode write callback. The write value of * the respective Synapse action mode is passed via the * action parameter. - * @device_u8_write: Device u8 component write callback. The write value of + * @device_u8_write: Device u8 component write callback. The write value of * the respective Device u8 component is passed via the val * parameter. - * @count_u8_write: Count u8 component write callback. The write value of + * @count_u8_write: Count u8 component write callback. The write value of * the respective Count u8 component is passed via the val * parameter. - * @signal_u8_write: Signal u8 component write callback. The write value of + * @signal_u8_write: Signal u8 component write callback. The write value of * the respective Signal u8 component is passed via the val * parameter. - * @device_u32_write: Device u32 component write callback. The write value of + * @device_u32_write: Device u32 component write callback. The write value of * the respective Device u32 component is passed via the * val parameter. - * @count_u32_write: Count u32 component write callback. The write value of + * @count_u32_write: Count u32 component write callback. The write value of * the respective Count u32 component is passed via the val * parameter. - * @signal_u32_write: Signal u32 component write callback. The write value of + * @signal_u32_write: Signal u32 component write callback. The write value of * the respective Signal u32 component is passed via the * val parameter. - * @device_u64_write: Device u64 component write callback. The write value of + * @device_u64_write: Device u64 component write callback. The write value of * the respective Device u64 component is passed via the * val parameter. - * @count_u64_write: Count u64 component write callback. The write value of + * @count_u64_write: Count u64 component write callback. The write value of * the respective Count u64 component is passed via the val * parameter. - * @signal_u64_write: Signal u64 component write callback. The write value of + * @signal_u64_write: Signal u64 component write callback. The write value of * the respective Signal u64 component is passed via the * val parameter. */ -- cgit v1.2.3 From 4a575865c1ea67018d96acda9b43e5d3d25b2366 Mon Sep 17 00:00:00 2001 From: Rafał Miłecki Date: Fri, 16 Sep 2022 13:20:49 +0100 Subject: mtd: allow getting MTD device associated with a specific DT node MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MTD subsystem API allows interacting with MTD devices (e.g. reading, writing, handling bad blocks). So far a random driver could get MTD device only by its name (get_mtd_device_nm()). This change allows getting them also by a DT node. This API is required for drivers handling DT defined MTD partitions in a specific way (e.g. U-Boot (sub)partition with environment variables). Acked-by: Miquel Raynal Signed-off-by: Rafał Miłecki Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20220916122100.170016-3-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/mtdcore.c | 28 ++++++++++++++++++++++++++++ include/linux/mtd/mtd.h | 1 + 2 files changed, 29 insertions(+) (limited to 'include') diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index a9b8be9f40dc..e3bee273595e 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -1217,6 +1217,34 @@ int __get_mtd_device(struct mtd_info *mtd) } EXPORT_SYMBOL_GPL(__get_mtd_device); +/** + * of_get_mtd_device_by_node - obtain an MTD device associated with a given node + * + * @np: device tree node + */ +struct mtd_info *of_get_mtd_device_by_node(struct device_node *np) +{ + struct mtd_info *mtd = NULL; + struct mtd_info *tmp; + int err; + + mutex_lock(&mtd_table_mutex); + + err = -EPROBE_DEFER; + mtd_for_each_device(tmp) { + if (mtd_get_of_node(tmp) == np) { + mtd = tmp; + err = __get_mtd_device(mtd); + break; + } + } + + mutex_unlock(&mtd_table_mutex); + + return err ? ERR_PTR(err) : mtd; +} +EXPORT_SYMBOL_GPL(of_get_mtd_device_by_node); + /** * get_mtd_device_nm - obtain a validated handle for an MTD device by * device name diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index 955aee14b0f7..6fc841ceef31 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -677,6 +677,7 @@ extern int mtd_device_unregister(struct mtd_info *master); extern struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num); extern int __get_mtd_device(struct mtd_info *mtd); extern void __put_mtd_device(struct mtd_info *mtd); +extern struct mtd_info *of_get_mtd_device_by_node(struct device_node *np); extern struct mtd_info *get_mtd_device_nm(const char *name); extern void put_mtd_device(struct mtd_info *mtd); -- cgit v1.2.3 From 650ae67bbf7ba5ac193f053969612fbb93247b64 Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Tue, 27 Sep 2022 18:53:38 -0400 Subject: counter: Introduce the Signal polarity component The Signal polarity component represents the active level of a respective Signal. There are two possible states: positive (rising edge) and negative (falling edge); enum counter_signal_polarity represents these states. A convenience macro COUNTER_COMP_POLARITY() is provided for driver authors to declare a Signal polarity component. Cc: Julien Panis Link: https://lore.kernel.org/r/8f47d6e1db71a11bb1e2666f8e2a6e9d256d4131.1664204990.git.william.gray@linaro.org/ Signed-off-by: William Breathitt Gray Link: https://lore.kernel.org/r/b6e53438badcb6318997d13dd2fc052f97d808ac.1664318353.git.william.gray@linaro.org Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/testing/sysfs-bus-counter | 14 ++++++++++++++ drivers/counter/counter-chrdev.c | 1 + drivers/counter/counter-sysfs.c | 12 ++++++++++++ include/linux/counter.h | 10 ++++++++++ include/uapi/linux/counter.h | 6 ++++++ 5 files changed, 43 insertions(+) (limited to 'include') diff --git a/Documentation/ABI/testing/sysfs-bus-counter b/Documentation/ABI/testing/sysfs-bus-counter index 06c2b3e27e0b..2a996deabe9e 100644 --- a/Documentation/ABI/testing/sysfs-bus-counter +++ b/Documentation/ABI/testing/sysfs-bus-counter @@ -217,6 +217,7 @@ What: /sys/bus/counter/devices/counterX/signalY/cable_fault_component_id What: /sys/bus/counter/devices/counterX/signalY/cable_fault_enable_component_id What: /sys/bus/counter/devices/counterX/signalY/filter_clock_prescaler_component_id What: /sys/bus/counter/devices/counterX/signalY/index_polarity_component_id +What: /sys/bus/counter/devices/counterX/signalY/polarity_component_id What: /sys/bus/counter/devices/counterX/signalY/synchronous_mode_component_id KernelVersion: 5.16 Contact: linux-iio@vger.kernel.org @@ -303,6 +304,19 @@ Description: Discrete set of available values for the respective Signal Y configuration are listed in this file. +What: /sys/bus/counter/devices/counterX/signalY/polarity +KernelVersion: 6.1 +Contact: linux-iio@vger.kernel.org +Description: + Active level of Signal Y. The following polarity values are + available: + + positive: + Signal high state considered active level (rising edge). + + negative: + Signal low state considered active level (falling edge). + What: /sys/bus/counter/devices/counterX/signalY/name KernelVersion: 5.2 Contact: linux-iio@vger.kernel.org diff --git a/drivers/counter/counter-chrdev.c b/drivers/counter/counter-chrdev.c index 4e71a19d7e6a..120879ee2e87 100644 --- a/drivers/counter/counter-chrdev.c +++ b/drivers/counter/counter-chrdev.c @@ -487,6 +487,7 @@ static int counter_get_data(struct counter_device *const counter, case COUNTER_COMP_ENUM: case COUNTER_COMP_COUNT_DIRECTION: case COUNTER_COMP_COUNT_MODE: + case COUNTER_COMP_SIGNAL_POLARITY: switch (comp_node->component.scope) { case COUNTER_SCOPE_DEVICE: ret = comp->device_u32_read(counter, &value_u32); diff --git a/drivers/counter/counter-sysfs.c b/drivers/counter/counter-sysfs.c index 04eac41dad33..e5dd36e1a45f 100644 --- a/drivers/counter/counter-sysfs.c +++ b/drivers/counter/counter-sysfs.c @@ -91,6 +91,11 @@ static const char *const counter_count_mode_str[] = { [COUNTER_COUNT_MODE_MODULO_N] = "modulo-n" }; +static const char *const counter_signal_polarity_str[] = { + [COUNTER_SIGNAL_POLARITY_POSITIVE] = "positive", + [COUNTER_SIGNAL_POLARITY_NEGATIVE] = "negative" +}; + static ssize_t counter_comp_u8_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -201,6 +206,8 @@ static ssize_t counter_comp_u32_show(struct device *dev, return sysfs_emit(buf, "%s\n", counter_count_direction_str[data]); case COUNTER_COMP_COUNT_MODE: return sysfs_emit(buf, "%s\n", counter_count_mode_str[data]); + case COUNTER_COMP_SIGNAL_POLARITY: + return sysfs_emit(buf, "%s\n", counter_signal_polarity_str[data]); default: return sysfs_emit(buf, "%u\n", (unsigned int)data); } @@ -252,6 +259,10 @@ static ssize_t counter_comp_u32_store(struct device *dev, err = counter_find_enum(&data, avail->enums, avail->num_items, buf, counter_count_mode_str); break; + case COUNTER_COMP_SIGNAL_POLARITY: + err = counter_find_enum(&data, avail->enums, avail->num_items, + buf, counter_signal_polarity_str); + break; default: err = kstrtou32(buf, 0, &data); break; @@ -469,6 +480,7 @@ static int counter_attr_create(struct device *const dev, case COUNTER_COMP_ENUM: case COUNTER_COMP_COUNT_DIRECTION: case COUNTER_COMP_COUNT_MODE: + case COUNTER_COMP_SIGNAL_POLARITY: if (comp->device_u32_read) { dev_attr->attr.mode |= 0444; dev_attr->show = counter_comp_u32_show; diff --git a/include/linux/counter.h b/include/linux/counter.h index a81234bc8ea8..b3fb6b68881a 100644 --- a/include/linux/counter.h +++ b/include/linux/counter.h @@ -31,6 +31,7 @@ enum counter_comp_type { COUNTER_COMP_ENUM, COUNTER_COMP_COUNT_DIRECTION, COUNTER_COMP_COUNT_MODE, + COUNTER_COMP_SIGNAL_POLARITY, }; /** @@ -477,6 +478,15 @@ struct counter_available { #define COUNTER_COMP_FLOOR(_read, _write) \ COUNTER_COMP_COUNT_U64("floor", _read, _write) +#define COUNTER_COMP_POLARITY(_read, _write, _available) \ +{ \ + .type = COUNTER_COMP_SIGNAL_POLARITY, \ + .name = "polarity", \ + .signal_u32_read = (_read), \ + .signal_u32_write = (_write), \ + .priv = &(_available), \ +} + #define COUNTER_COMP_PRESET(_read, _write) \ COUNTER_COMP_COUNT_U64("preset", _read, _write) diff --git a/include/uapi/linux/counter.h b/include/uapi/linux/counter.h index 96c5ffd368ad..e9610e1944dc 100644 --- a/include/uapi/linux/counter.h +++ b/include/uapi/linux/counter.h @@ -153,4 +153,10 @@ enum counter_synapse_action { COUNTER_SYNAPSE_ACTION_BOTH_EDGES, }; +/* Signal polarity values */ +enum counter_signal_polarity { + COUNTER_SIGNAL_POLARITY_POSITIVE, + COUNTER_SIGNAL_POLARITY_NEGATIVE, +}; + #endif /* _UAPI_COUNTER_H_ */ -- cgit v1.2.3 From 45d2918520b2d8e640e4fb3fbf664dfb823dc520 Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Tue, 27 Sep 2022 18:53:40 -0400 Subject: counter: Introduce the Count capture component Some devices provide a latch function to save historic Count values. This patch standardizes exposure of such functionality as Count capture components. A COUNTER_COMP_CAPTURE macro is provided for driver authors to define a capture component. A new event COUNTER_EVENT_CAPTURE is introduced to represent Count value capture events. Cc: Julien Panis Link: https://lore.kernel.org/r/c239572ab4208d0d6728136e82a88ad464369a7a.1664204990.git.william.gray@linaro.org/ Signed-off-by: William Breathitt Gray Link: https://lore.kernel.org/r/3cebaa0b807a225eb277d771504fe6dba7269ffd.1664318353.git.william.gray@linaro.org Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/testing/sysfs-bus-counter | 7 +++++++ include/linux/counter.h | 3 +++ include/uapi/linux/counter.h | 2 ++ 3 files changed, 12 insertions(+) (limited to 'include') diff --git a/Documentation/ABI/testing/sysfs-bus-counter b/Documentation/ABI/testing/sysfs-bus-counter index 2a996deabe9e..3eb6b063970a 100644 --- a/Documentation/ABI/testing/sysfs-bus-counter +++ b/Documentation/ABI/testing/sysfs-bus-counter @@ -4,6 +4,12 @@ Contact: linux-iio@vger.kernel.org Description: Count data of Count Y represented as a string. +What: /sys/bus/counter/devices/counterX/countY/capture +KernelVersion: 6.1 +Contact: linux-iio@vger.kernel.org +Description: + Historical capture of the Count Y count data. + What: /sys/bus/counter/devices/counterX/countY/ceiling KernelVersion: 5.2 Contact: linux-iio@vger.kernel.org @@ -203,6 +209,7 @@ Description: both edges: Any state transition. +What: /sys/bus/counter/devices/counterX/countY/capture_component_id What: /sys/bus/counter/devices/counterX/countY/ceiling_component_id What: /sys/bus/counter/devices/counterX/countY/floor_component_id What: /sys/bus/counter/devices/counterX/countY/count_mode_component_id diff --git a/include/linux/counter.h b/include/linux/counter.h index b3fb6b68881a..e160197971dd 100644 --- a/include/linux/counter.h +++ b/include/linux/counter.h @@ -453,6 +453,9 @@ struct counter_available { .priv = &(_available), \ } +#define COUNTER_COMP_CAPTURE(_read, _write) \ + COUNTER_COMP_COUNT_U64("capture", _read, _write) + #define COUNTER_COMP_CEILING(_read, _write) \ COUNTER_COMP_COUNT_U64("ceiling", _read, _write) diff --git a/include/uapi/linux/counter.h b/include/uapi/linux/counter.h index e9610e1944dc..8ab12d731e3b 100644 --- a/include/uapi/linux/counter.h +++ b/include/uapi/linux/counter.h @@ -63,6 +63,8 @@ enum counter_event_type { COUNTER_EVENT_INDEX, /* State of counter is changed */ COUNTER_EVENT_CHANGE_OF_STATE, + /* Count value captured */ + COUNTER_EVENT_CAPTURE, }; /** -- cgit v1.2.3 From d2011be1e22f7769c7c71d6d7f777ffcc544808d Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Tue, 27 Sep 2022 18:53:42 -0400 Subject: counter: Introduce the COUNTER_COMP_ARRAY component type The COUNTER_COMP_ARRAY Counter component type is introduced to enable support for Counter array components. With Counter array components, exposure for buffers on counter devices can be defined via new Counter array component macros. This should simplify code for driver authors who would otherwise need to define individual Counter components for each array element. Eight Counter array component macros are introduced:: DEFINE_COUNTER_ARRAY_U64(_name, _length) DEFINE_COUNTER_ARRAY_CAPTURE(_name, _length) DEFINE_COUNTER_ARRAY_POLARITY(_name, _enums, _length) COUNTER_COMP_DEVICE_ARRAY_U64(_name, _read, _write, _array) COUNTER_COMP_COUNT_ARRAY_U64(_name, _read, _write, _array) COUNTER_COMP_SIGNAL_ARRAY_U64(_name, _read, _write, _array) COUNTER_COMP_ARRAY_CAPTURE(_read, _write, _array) COUNTER_COMP_ARRAY_POLARITY(_read, _write, _array) Eight Counter array callbacks are introduced as well:: int (*signal_array_u32_read)(struct counter_device *counter, struct counter_signal *signal, size_t idx, u32 *val); int (*signal_array_u32_write)(struct counter_device *counter, struct counter_signal *signal, size_t idx, u32 val); int (*device_array_u64_read)(struct counter_device *counter, size_t idx, u64 *val); int (*count_array_u64_read)(struct counter_device *counter, struct counter_count *count, size_t idx, u64 *val); int (*signal_array_u64_read)(struct counter_device *counter, struct counter_signal *signal, size_t idx, u64 *val); int (*device_array_u64_write)(struct counter_device *counter, size_t idx, u64 val); int (*count_array_u64_write)(struct counter_device *counter, struct counter_count *count, size_t idx, u64 val); int (*signal_array_u64_write)(struct counter_device *counter, struct counter_signal *signal, size_t idx, u64 val); Driver authors can handle reads/writes for an array component by receiving an element index via the `idx` parameter and processing the respective value via the `val` parameter. For example, suppose a driver wants to expose a Count's read-only capture buffer of four elements using a callback `foobar_capture_read()`:: DEFINE_COUNTER_ARRAY_CAPTURE(foobar_capture_array, 4); COUNTER_COMP_ARRAY_CAPTURE(foobar_capture_read, NULL, foobar_capture_array) Respective sysfs attributes for each array element would appear for the respective Count: * /sys/bus/counter/devices/counterX/countY/capture0 * /sys/bus/counter/devices/counterX/countY/capture1 * /sys/bus/counter/devices/counterX/countY/capture2 * /sys/bus/counter/devices/counterX/countY/capture3 If a user tries to read _capture2_ for example, `idx` will be `2` when passed to the `foobar_capture_read()` callback, and thus the driver knows which array element to handle. Counter arrays for polarity elements can be defined in a similar manner as u64 elements:: const enum counter_signal_polarity foobar_polarity_states[] = { COUNTER_SIGNAL_POLARITY_POSITIVE, COUNTER_SIGNAL_POLARITY_NEGATIVE, }; DEFINE_COUNTER_ARRAY_POLARITY(foobar_polarity_array, foobar_polarity_states, 4); COUNTER_COMP_ARRAY_POLARITY(foobar_polarity_read, foobar_polarity_write, foobar_polarity_array) Tested-by: Julien Panis Link: https://lore.kernel.org/r/5310c22520aeae65b1b74952419f49ac4c8e1ec1.1664204990.git.william.gray@linaro.org/ Signed-off-by: William Breathitt Gray Link: https://lore.kernel.org/r/a51fd608704bdfc5a0efa503fc5481df34241e0a.1664318353.git.william.gray@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/counter/counter-chrdev.c | 134 ++++++++++++++++++++++---- drivers/counter/counter-sysfs.c | 198 ++++++++++++++++++++++++++++++++++++++- include/linux/counter.h | 134 ++++++++++++++++++++++++++ 3 files changed, 446 insertions(+), 20 deletions(-) (limited to 'include') diff --git a/drivers/counter/counter-chrdev.c b/drivers/counter/counter-chrdev.c index 120879ee2e87..80acdf62794a 100644 --- a/drivers/counter/counter-chrdev.c +++ b/drivers/counter/counter-chrdev.c @@ -40,7 +40,11 @@ struct counter_comp_node { a.signal_u32_read == b.signal_u32_read || \ a.device_u64_read == b.device_u64_read || \ a.count_u64_read == b.count_u64_read || \ - a.signal_u64_read == b.signal_u64_read) + a.signal_u64_read == b.signal_u64_read || \ + a.signal_array_u32_read == b.signal_array_u32_read || \ + a.device_array_u64_read == b.device_array_u64_read || \ + a.count_array_u64_read == b.count_array_u64_read || \ + a.signal_array_u64_read == b.signal_array_u64_read) #define counter_comp_read_is_set(comp) \ (comp.action_read || \ @@ -52,7 +56,11 @@ struct counter_comp_node { comp.signal_u32_read || \ comp.device_u64_read || \ comp.count_u64_read || \ - comp.signal_u64_read) + comp.signal_u64_read || \ + comp.signal_array_u32_read || \ + comp.device_array_u64_read || \ + comp.count_array_u64_read || \ + comp.signal_array_u64_read) static ssize_t counter_chrdev_read(struct file *filp, char __user *buf, size_t len, loff_t *f_ps) @@ -228,6 +236,31 @@ static int counter_disable_events(struct counter_device *const counter) return err; } +static int counter_get_ext(const struct counter_comp *const ext, + const size_t num_ext, const size_t component_id, + size_t *const ext_idx, size_t *const id) +{ + struct counter_array *element; + + *id = 0; + for (*ext_idx = 0; *ext_idx < num_ext; (*ext_idx)++) { + if (*id == component_id) + return 0; + + if (ext->type == COUNTER_COMP_ARRAY) { + element = ext->priv; + + if (component_id - *id < element->length) + return 0; + + *id += element->length; + } else + (*id)++; + } + + return -EINVAL; +} + static int counter_add_watch(struct counter_device *const counter, const unsigned long arg) { @@ -237,6 +270,7 @@ static int counter_add_watch(struct counter_device *const counter, size_t parent, id; struct counter_comp *ext; size_t num_ext; + size_t ext_idx, ext_id; int err = 0; if (copy_from_user(&watch, uwatch, sizeof(watch))) @@ -314,11 +348,11 @@ static int counter_add_watch(struct counter_device *const counter, comp_node.comp.priv = counter->counts[parent].synapses + id; break; case COUNTER_COMPONENT_EXTENSION: - if (id >= num_ext) - return -EINVAL; - id = array_index_nospec(id, num_ext); + err = counter_get_ext(ext, num_ext, id, &ext_idx, &ext_id); + if (err < 0) + return err; - comp_node.comp = ext[id]; + comp_node.comp = ext[ext_idx]; break; default: return -EINVAL; @@ -451,14 +485,56 @@ void counter_chrdev_remove(struct counter_device *const counter) kfifo_free(&counter->events); } +static int counter_get_array_data(struct counter_device *const counter, + const enum counter_scope scope, + void *const parent, + const struct counter_comp *const comp, + const size_t idx, u64 *const value) +{ + const struct counter_array *const element = comp->priv; + u32 value_u32 = 0; + int ret; + + switch (element->type) { + case COUNTER_COMP_SIGNAL_POLARITY: + if (scope != COUNTER_SCOPE_SIGNAL) + return -EINVAL; + ret = comp->signal_array_u32_read(counter, parent, idx, + &value_u32); + *value = value_u32; + return ret; + case COUNTER_COMP_U64: + switch (scope) { + case COUNTER_SCOPE_DEVICE: + return comp->device_array_u64_read(counter, idx, value); + case COUNTER_SCOPE_SIGNAL: + return comp->signal_array_u64_read(counter, parent, idx, + value); + case COUNTER_SCOPE_COUNT: + return comp->count_array_u64_read(counter, parent, idx, + value); + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + static int counter_get_data(struct counter_device *const counter, const struct counter_comp_node *const comp_node, u64 *const value) { const struct counter_comp *const comp = &comp_node->comp; - void *const parent = comp_node->parent; + const enum counter_scope scope = comp_node->component.scope; + const size_t id = comp_node->component.id; + struct counter_signal *const signal = comp_node->parent; + struct counter_count *const count = comp_node->parent; u8 value_u8 = 0; u32 value_u32 = 0; + const struct counter_comp *ext; + size_t num_ext; + size_t ext_idx, ext_id; int ret; if (comp_node->component.type == COUNTER_COMPONENT_NONE) @@ -467,15 +543,15 @@ static int counter_get_data(struct counter_device *const counter, switch (comp->type) { case COUNTER_COMP_U8: case COUNTER_COMP_BOOL: - switch (comp_node->component.scope) { + switch (scope) { case COUNTER_SCOPE_DEVICE: ret = comp->device_u8_read(counter, &value_u8); break; case COUNTER_SCOPE_SIGNAL: - ret = comp->signal_u8_read(counter, parent, &value_u8); + ret = comp->signal_u8_read(counter, signal, &value_u8); break; case COUNTER_SCOPE_COUNT: - ret = comp->count_u8_read(counter, parent, &value_u8); + ret = comp->count_u8_read(counter, count, &value_u8); break; default: return -EINVAL; @@ -488,16 +564,16 @@ static int counter_get_data(struct counter_device *const counter, case COUNTER_COMP_COUNT_DIRECTION: case COUNTER_COMP_COUNT_MODE: case COUNTER_COMP_SIGNAL_POLARITY: - switch (comp_node->component.scope) { + switch (scope) { case COUNTER_SCOPE_DEVICE: ret = comp->device_u32_read(counter, &value_u32); break; case COUNTER_SCOPE_SIGNAL: - ret = comp->signal_u32_read(counter, parent, + ret = comp->signal_u32_read(counter, signal, &value_u32); break; case COUNTER_SCOPE_COUNT: - ret = comp->count_u32_read(counter, parent, &value_u32); + ret = comp->count_u32_read(counter, count, &value_u32); break; default: return -EINVAL; @@ -505,21 +581,43 @@ static int counter_get_data(struct counter_device *const counter, *value = value_u32; return ret; case COUNTER_COMP_U64: - switch (comp_node->component.scope) { + switch (scope) { case COUNTER_SCOPE_DEVICE: return comp->device_u64_read(counter, value); case COUNTER_SCOPE_SIGNAL: - return comp->signal_u64_read(counter, parent, value); + return comp->signal_u64_read(counter, signal, value); case COUNTER_SCOPE_COUNT: - return comp->count_u64_read(counter, parent, value); + return comp->count_u64_read(counter, count, value); default: return -EINVAL; } case COUNTER_COMP_SYNAPSE_ACTION: - ret = comp->action_read(counter, parent, comp->priv, - &value_u32); + ret = comp->action_read(counter, count, comp->priv, &value_u32); *value = value_u32; return ret; + case COUNTER_COMP_ARRAY: + switch (scope) { + case COUNTER_SCOPE_DEVICE: + ext = counter->ext; + num_ext = counter->num_ext; + break; + case COUNTER_SCOPE_SIGNAL: + ext = signal->ext; + num_ext = signal->num_ext; + break; + case COUNTER_SCOPE_COUNT: + ext = count->ext; + num_ext = count->num_ext; + break; + default: + return -EINVAL; + } + ret = counter_get_ext(ext, num_ext, id, &ext_idx, &ext_id); + if (ret < 0) + return ret; + + return counter_get_array_data(counter, scope, comp_node->parent, + comp, id - ext_id, value); default: return -EINVAL; } diff --git a/drivers/counter/counter-sysfs.c b/drivers/counter/counter-sysfs.c index b393da402e0b..b9efe66f9f8d 100644 --- a/drivers/counter/counter-sysfs.c +++ b/drivers/counter/counter-sysfs.c @@ -352,6 +352,124 @@ static ssize_t counter_comp_u64_store(struct device *dev, return len; } +static ssize_t counter_comp_array_u32_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + const struct counter_attribute *const a = to_counter_attribute(attr); + struct counter_device *const counter = counter_from_dev(dev); + const struct counter_array *const element = a->comp.priv; + int err; + u32 data = 0; + + if (a->scope != COUNTER_SCOPE_SIGNAL || + element->type != COUNTER_COMP_SIGNAL_POLARITY) + return -EINVAL; + + err = a->comp.signal_array_u32_read(counter, a->parent, element->idx, + &data); + if (err < 0) + return err; + + return sysfs_emit(buf, "%s\n", counter_signal_polarity_str[data]); +} + +static ssize_t counter_comp_array_u32_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + const struct counter_attribute *const a = to_counter_attribute(attr); + struct counter_device *const counter = counter_from_dev(dev); + const struct counter_array *const element = a->comp.priv; + int err; + u32 data = 0; + + if (element->type != COUNTER_COMP_SIGNAL_POLARITY || + a->scope != COUNTER_SCOPE_SIGNAL) + return -EINVAL; + + err = counter_find_enum(&data, element->avail->enums, + element->avail->num_items, buf, + counter_signal_polarity_str); + if (err < 0) + return err; + + err = a->comp.signal_array_u32_write(counter, a->parent, element->idx, + data); + if (err < 0) + return err; + + return len; +} + +static ssize_t counter_comp_array_u64_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + const struct counter_attribute *const a = to_counter_attribute(attr); + struct counter_device *const counter = counter_from_dev(dev); + const struct counter_array *const element = a->comp.priv; + int err; + u64 data = 0; + + switch (a->scope) { + case COUNTER_SCOPE_DEVICE: + err = a->comp.device_array_u64_read(counter, element->idx, + &data); + break; + case COUNTER_SCOPE_SIGNAL: + err = a->comp.signal_array_u64_read(counter, a->parent, + element->idx, &data); + break; + case COUNTER_SCOPE_COUNT: + err = a->comp.count_array_u64_read(counter, a->parent, + element->idx, &data); + break; + default: + return -EINVAL; + } + if (err < 0) + return err; + + return sysfs_emit(buf, "%llu\n", (unsigned long long)data); +} + +static ssize_t counter_comp_array_u64_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + const struct counter_attribute *const a = to_counter_attribute(attr); + struct counter_device *const counter = counter_from_dev(dev); + const struct counter_array *const element = a->comp.priv; + int err; + u64 data = 0; + + err = kstrtou64(buf, 0, &data); + if (err < 0) + return err; + + switch (a->scope) { + case COUNTER_SCOPE_DEVICE: + err = a->comp.device_array_u64_write(counter, element->idx, + data); + break; + case COUNTER_SCOPE_SIGNAL: + err = a->comp.signal_array_u64_write(counter, a->parent, + element->idx, data); + break; + case COUNTER_SCOPE_COUNT: + err = a->comp.count_array_u64_write(counter, a->parent, + element->idx, data); + break; + default: + return -EINVAL; + } + if (err < 0) + return err; + + return len; +} + static ssize_t enums_available_show(const u32 *const enums, const size_t num_enums, const char *const strs[], char *buf) @@ -446,6 +564,7 @@ static int counter_attr_create(struct device *const dev, const enum counter_scope scope, void *const parent) { + const struct counter_array *const array = comp->priv; struct counter_attribute *counter_attr; struct device_attribute *dev_attr; @@ -500,6 +619,32 @@ static int counter_attr_create(struct device *const dev, dev_attr->store = counter_comp_u64_store; } break; + case COUNTER_COMP_ARRAY: + switch (array->type) { + case COUNTER_COMP_SIGNAL_POLARITY: + if (comp->signal_array_u32_read) { + dev_attr->attr.mode |= 0444; + dev_attr->show = counter_comp_array_u32_show; + } + if (comp->signal_array_u32_write) { + dev_attr->attr.mode |= 0200; + dev_attr->store = counter_comp_array_u32_store; + } + break; + case COUNTER_COMP_U64: + if (comp->device_array_u64_read) { + dev_attr->attr.mode |= 0444; + dev_attr->show = counter_comp_array_u64_show; + } + if (comp->device_array_u64_write) { + dev_attr->attr.mode |= 0200; + dev_attr->store = counter_comp_array_u64_store; + } + break; + default: + return -EINVAL; + } + break; default: return -EINVAL; } @@ -609,6 +754,45 @@ static int counter_ext_attrs_create(struct device *const dev, return counter_comp_id_attr_create(dev, group, ext->name, id); } +static int counter_array_attrs_create(struct device *const dev, + struct counter_attribute_group *const group, + const struct counter_comp *const comp, + const enum counter_scope scope, + void *const parent, const size_t id) +{ + const struct counter_array *const array = comp->priv; + struct counter_comp ext = *comp; + struct counter_array *element; + size_t idx; + int err; + + /* Create an attribute for each array element */ + for (idx = 0; idx < array->length; idx++) { + /* Generate array element attribute name */ + ext.name = devm_kasprintf(dev, GFP_KERNEL, "%s%zu", comp->name, + idx); + if (!ext.name) + return -ENOMEM; + + /* Allocate and configure array element */ + element = devm_kzalloc(dev, sizeof(*element), GFP_KERNEL); + if (!element) + return -ENOMEM; + element->type = array->type; + element->avail = array->avail; + element->idx = idx; + ext.priv = element; + + /* Create all attributes associated with the array element */ + err = counter_ext_attrs_create(dev, group, &ext, scope, parent, + id + idx); + if (err < 0) + return err; + } + + return 0; +} + static int counter_sysfs_exts_add(struct device *const dev, struct counter_attribute_group *const group, const struct counter_comp *const exts, @@ -619,12 +803,22 @@ static int counter_sysfs_exts_add(struct device *const dev, size_t i; const struct counter_comp *ext; int err; + size_t id = 0; + const struct counter_array *array; /* Create attributes for each extension */ for (i = 0; i < num_ext; i++) { ext = &exts[i]; - err = counter_ext_attrs_create(dev, group, ext, scope, parent, - i); + if (ext->type == COUNTER_COMP_ARRAY) { + err = counter_array_attrs_create(dev, group, ext, scope, + parent, id); + array = ext->priv; + id += array->length; + } else { + err = counter_ext_attrs_create(dev, group, ext, scope, + parent, id); + id++; + } if (err < 0) return err; } diff --git a/include/linux/counter.h b/include/linux/counter.h index e160197971dd..c41fa602ed28 100644 --- a/include/linux/counter.h +++ b/include/linux/counter.h @@ -32,6 +32,7 @@ enum counter_comp_type { COUNTER_COMP_COUNT_DIRECTION, COUNTER_COMP_COUNT_MODE, COUNTER_COMP_SIGNAL_POLARITY, + COUNTER_COMP_ARRAY, }; /** @@ -69,6 +70,30 @@ enum counter_comp_type { * @signal_u64_read: Signal u64 component read callback. The read value of * the respective Signal u64 component should be passed * back via the val parameter. + * @signal_array_u32_read: Signal u32 array component read callback. The + * index of the respective Count u32 array + * component element is passed via the idx + * parameter. The read value of the respective + * Count u32 array component element should be + * passed back via the val parameter. + * @device_array_u64_read: Device u64 array component read callback. The + * index of the respective Device u64 array + * component element is passed via the idx + * parameter. The read value of the respective + * Device u64 array component element should be + * passed back via the val parameter. + * @count_array_u64_read: Count u64 array component read callback. The + * index of the respective Count u64 array + * component element is passed via the idx + * parameter. The read value of the respective + * Count u64 array component element should be + * passed back via the val parameter. + * @signal_array_u64_read: Signal u64 array component read callback. The + * index of the respective Count u64 array + * component element is passed via the idx + * parameter. The read value of the respective + * Count u64 array component element should be + * passed back via the val parameter. * @action_write: Synapse action mode write callback. The write value of * the respective Synapse action mode is passed via the * action parameter. @@ -99,6 +124,30 @@ enum counter_comp_type { * @signal_u64_write: Signal u64 component write callback. The write value of * the respective Signal u64 component is passed via the * val parameter. + * @signal_array_u32_write: Signal u32 array component write callback. The + * index of the respective Signal u32 array + * component element is passed via the idx + * parameter. The write value of the respective + * Signal u32 array component element is passed via + * the val parameter. + * @device_array_u64_write: Device u64 array component write callback. The + * index of the respective Device u64 array + * component element is passed via the idx + * parameter. The write value of the respective + * Device u64 array component element is passed via + * the val parameter. + * @count_array_u64_write: Count u64 array component write callback. The + * index of the respective Count u64 array + * component element is passed via the idx + * parameter. The write value of the respective + * Count u64 array component element is passed via + * the val parameter. + * @signal_array_u64_write: Signal u64 array component write callback. The + * index of the respective Signal u64 array + * component element is passed via the idx + * parameter. The write value of the respective + * Signal u64 array component element is passed via + * the val parameter. */ struct counter_comp { enum counter_comp_type type; @@ -126,6 +175,17 @@ struct counter_comp { struct counter_count *count, u64 *val); int (*signal_u64_read)(struct counter_device *counter, struct counter_signal *signal, u64 *val); + int (*signal_array_u32_read)(struct counter_device *counter, + struct counter_signal *signal, + size_t idx, u32 *val); + int (*device_array_u64_read)(struct counter_device *counter, + size_t idx, u64 *val); + int (*count_array_u64_read)(struct counter_device *counter, + struct counter_count *count, + size_t idx, u64 *val); + int (*signal_array_u64_read)(struct counter_device *counter, + struct counter_signal *signal, + size_t idx, u64 *val); }; union { int (*action_write)(struct counter_device *counter, @@ -149,6 +209,17 @@ struct counter_comp { struct counter_count *count, u64 val); int (*signal_u64_write)(struct counter_device *counter, struct counter_signal *signal, u64 val); + int (*signal_array_u32_write)(struct counter_device *counter, + struct counter_signal *signal, + size_t idx, u32 val); + int (*device_array_u64_write)(struct counter_device *counter, + size_t idx, u64 val); + int (*count_array_u64_write)(struct counter_device *counter, + struct counter_count *count, + size_t idx, u64 val); + int (*signal_array_u64_write)(struct counter_device *counter, + struct counter_signal *signal, + size_t idx, u64 val); }; }; @@ -453,6 +524,57 @@ struct counter_available { .priv = &(_available), \ } +struct counter_array { + enum counter_comp_type type; + const struct counter_available *avail; + union { + size_t length; + size_t idx; + }; +}; + +#define DEFINE_COUNTER_ARRAY_U64(_name, _length) \ + struct counter_array _name = { \ + .type = COUNTER_COMP_U64, \ + .length = (_length), \ + } + +#define DEFINE_COUNTER_ARRAY_CAPTURE(_name, _length) \ + DEFINE_COUNTER_ARRAY_U64(_name, _length) + +#define DEFINE_COUNTER_ARRAY_POLARITY(_name, _enums, _length) \ + DEFINE_COUNTER_AVAILABLE(_name##_available, _enums); \ + struct counter_array _name = { \ + .type = COUNTER_COMP_SIGNAL_POLARITY, \ + .avail = &(_name##_available), \ + .length = (_length), \ + } + +#define COUNTER_COMP_DEVICE_ARRAY_U64(_name, _read, _write, _array) \ +{ \ + .type = COUNTER_COMP_ARRAY, \ + .name = (_name), \ + .device_array_u64_read = (_read), \ + .device_array_u64_write = (_write), \ + .priv = &(_array), \ +} +#define COUNTER_COMP_COUNT_ARRAY_U64(_name, _read, _write, _array) \ +{ \ + .type = COUNTER_COMP_ARRAY, \ + .name = (_name), \ + .count_array_u64_read = (_read), \ + .count_array_u64_write = (_write), \ + .priv = &(_array), \ +} +#define COUNTER_COMP_SIGNAL_ARRAY_U64(_name, _read, _write, _array) \ +{ \ + .type = COUNTER_COMP_ARRAY, \ + .name = (_name), \ + .signal_array_u64_read = (_read), \ + .signal_array_u64_write = (_write), \ + .priv = &(_array), \ +} + #define COUNTER_COMP_CAPTURE(_read, _write) \ COUNTER_COMP_COUNT_U64("capture", _read, _write) @@ -496,4 +618,16 @@ struct counter_available { #define COUNTER_COMP_PRESET_ENABLE(_read, _write) \ COUNTER_COMP_COUNT_BOOL("preset_enable", _read, _write) +#define COUNTER_COMP_ARRAY_CAPTURE(_read, _write, _array) \ + COUNTER_COMP_COUNT_ARRAY_U64("capture", _read, _write, _array) + +#define COUNTER_COMP_ARRAY_POLARITY(_read, _write, _array) \ +{ \ + .type = COUNTER_COMP_ARRAY, \ + .name = "polarity", \ + .signal_array_u32_read = (_read), \ + .signal_array_u32_write = (_write), \ + .priv = &(_array), \ +} + #endif /* _COUNTER_H_ */ -- cgit v1.2.3