diff options
-rw-r--r-- | Documentation/ABI/testing/sysfs-pps-gen-tio | 6 | ||||
-rw-r--r-- | Documentation/driver-api/pps.rst | 27 | ||||
-rw-r--r-- | MAINTAINERS | 1 | ||||
-rw-r--r-- | drivers/android/binder_internal.h | 1 | ||||
-rw-r--r-- | drivers/char/sonypi.c | 11 | ||||
-rw-r--r-- | drivers/char/virtio_console.c | 9 | ||||
-rw-r--r-- | drivers/greybus/gb-beagleplay.c | 4 | ||||
-rw-r--r-- | drivers/misc/eeprom/ee1004.c | 4 | ||||
-rw-r--r-- | drivers/misc/mei/bus.c | 52 | ||||
-rw-r--r-- | drivers/misc/mei/client.c | 22 | ||||
-rw-r--r-- | drivers/misc/mei/client.h | 2 | ||||
-rw-r--r-- | drivers/misc/mei/hw-txe.c | 45 | ||||
-rw-r--r-- | drivers/misc/mei/hw-txe.h | 2 | ||||
-rw-r--r-- | drivers/pps/generators/Kconfig | 16 | ||||
-rw-r--r-- | drivers/pps/generators/Makefile | 1 | ||||
-rw-r--r-- | drivers/pps/generators/pps_gen-dummy.c | 2 | ||||
-rw-r--r-- | drivers/pps/generators/pps_gen.c | 14 | ||||
-rw-r--r-- | drivers/pps/generators/pps_gen_tio.c | 272 | ||||
-rw-r--r-- | drivers/pps/generators/sysfs.c | 6 | ||||
-rw-r--r-- | include/linux/mei_cl_bus.h | 5 | ||||
-rw-r--r-- | include/linux/pps_gen_kernel.h | 4 | ||||
-rw-r--r-- | lib/Kconfig.debug | 15 | ||||
-rw-r--r-- | rust/kernel/miscdevice.rs | 297 | ||||
-rwxr-xr-x | scripts/tags.sh | 1 |
24 files changed, 505 insertions, 314 deletions
diff --git a/Documentation/ABI/testing/sysfs-pps-gen-tio b/Documentation/ABI/testing/sysfs-pps-gen-tio new file mode 100644 index 000000000000..3c34ff17a335 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-pps-gen-tio @@ -0,0 +1,6 @@ +What: /sys/class/pps-gen/pps-genx/enable +Date: April 2025 +KernelVersion: 6.15 +Contact: Subramanian Mohan<subramanian.mohan@intel.com> +Description: + Enable or disable PPS TIO generator output. diff --git a/Documentation/driver-api/pps.rst b/Documentation/driver-api/pps.rst index 71ad04c82d6c..598729f9cd27 100644 --- a/Documentation/driver-api/pps.rst +++ b/Documentation/driver-api/pps.rst @@ -206,8 +206,7 @@ To do so the class pps-gen has been added. PPS generators can be registered in the kernel by defining a struct pps_gen_source_info as follows:: - static struct pps_gen_source_info pps_gen_dummy_info = { - .name = "dummy", + static const struct pps_gen_source_info pps_gen_dummy_info = { .use_system_clock = true, .get_time = pps_gen_dummy_get_time, .enable = pps_gen_dummy_enable, @@ -286,3 +285,27 @@ delay between assert and clear edge as small as possible to reduce system latencies. But if it is too small slave won't be able to capture clear edge transition. The default of 30us should be good enough in most situations. The delay can be selected using 'delay' pps_gen_parport module parameter. + + +Intel Timed I/O PPS signal generator +------------------------------------ + +Intel Timed I/O is a high precision device, present on 2019 and newer Intel +CPUs, that can generate PPS signals. + +Timed I/O and system time are both driven by same hardware clock. The signal +is generated with a precision of ~20 nanoseconds. The generated PPS signal +is used to synchronize an external device with system clock. For example, +it can be used to share your clock with a device that receives PPS signal, +generated by Timed I/O device. There are dedicated Timed I/O pins to deliver +the PPS signal to an external device. + +Usage of Intel Timed I/O as PPS generator: + +Start generating PPS signal:: + + $echo 1 > /sys/class/pps-gen/pps-genx/enable + +Stop generating PPS signal:: + + $echo 0 > /sys/class/pps-gen/pps-genx/enable diff --git a/MAINTAINERS b/MAINTAINERS index ed7aa6867674..82b653f9c789 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -18926,6 +18926,7 @@ S: Maintained W: http://wiki.enneenne.com/index.php/LinuxPPS_support F: Documentation/ABI/testing/sysfs-pps F: Documentation/ABI/testing/sysfs-pps-gen +F: Documentation/ABI/testing/sysfs-pps-gen-tio F: Documentation/devicetree/bindings/pps/pps-gpio.yaml F: Documentation/driver-api/pps.rst F: drivers/pps/ diff --git a/drivers/android/binder_internal.h b/drivers/android/binder_internal.h index e4eb8357989c..6a66c9769c6c 100644 --- a/drivers/android/binder_internal.h +++ b/drivers/android/binder_internal.h @@ -3,7 +3,6 @@ #ifndef _LINUX_BINDER_INTERNAL_H #define _LINUX_BINDER_INTERNAL_H -#include <linux/export.h> #include <linux/fs.h> #include <linux/list.h> #include <linux/miscdevice.h> diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c index f887569fd3d0..677bb5ac950a 100644 --- a/drivers/char/sonypi.c +++ b/drivers/char/sonypi.c @@ -37,6 +37,7 @@ #include <linux/kfifo.h> #include <linux/platform_device.h> #include <linux/gfp.h> +#include <linux/string_choices.h> #include <linux/uaccess.h> #include <asm/io.h> @@ -1268,12 +1269,12 @@ static void sonypi_display_info(void) "compat = %s, mask = 0x%08lx, useinput = %s, acpi = %s\n", sonypi_device.model, verbose, - fnkeyinit ? "on" : "off", - camera ? "on" : "off", - compat ? "on" : "off", + str_on_off(fnkeyinit), + str_on_off(camera), + str_on_off(compat), mask, - useinput ? "on" : "off", - SONYPI_ACPI_ACTIVE ? "on" : "off"); + str_on_off(useinput), + str_on_off(SONYPI_ACPI_ACTIVE)); printk(KERN_INFO "sonypi: enabled at irq=%d, port1=0x%x, port2=0x%x\n", sonypi_device.irq, sonypi_device.ioport1, sonypi_device.ioport2); diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 18f92dd44d45..5f04951d0dd4 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -26,6 +26,7 @@ #include <linux/workqueue.h> #include <linux/module.h> #include <linux/dma-mapping.h> +#include <linux/string_choices.h> #include "../tty/hvc/hvc_console.h" #define is_rproc_enabled IS_ENABLED(CONFIG_REMOTEPROC) @@ -1269,8 +1270,7 @@ static int port_debugfs_show(struct seq_file *s, void *data) seq_printf(s, "bytes_sent: %lu\n", port->stats.bytes_sent); seq_printf(s, "bytes_received: %lu\n", port->stats.bytes_received); seq_printf(s, "bytes_discarded: %lu\n", port->stats.bytes_discarded); - seq_printf(s, "is_console: %s\n", - is_console_port(port) ? "yes" : "no"); + seq_printf(s, "is_console: %s\n", str_yes_no(is_console_port(port))); seq_printf(s, "console_vtermno: %u\n", port->cons.vtermno); return 0; @@ -1321,7 +1321,6 @@ static void send_sigio_to_port(struct port *port) static int add_port(struct ports_device *portdev, u32 id) { - char debugfs_name[16]; struct port *port; dev_t devt; int err; @@ -1424,9 +1423,7 @@ static int add_port(struct ports_device *portdev, u32 id) * Finally, create the debugfs file that we can use to * inspect a port's state at any time */ - snprintf(debugfs_name, sizeof(debugfs_name), "vport%up%u", - port->portdev->vdev->index, id); - port->debugfs_file = debugfs_create_file(debugfs_name, 0444, + port->debugfs_file = debugfs_create_file(dev_name(port->dev), 0444, pdrvdata.debugfs_dir, port, &port_debugfs_fops); return 0; diff --git a/drivers/greybus/gb-beagleplay.c b/drivers/greybus/gb-beagleplay.c index 473ac3f2d382..da31f1131afc 100644 --- a/drivers/greybus/gb-beagleplay.c +++ b/drivers/greybus/gb-beagleplay.c @@ -912,7 +912,9 @@ static enum fw_upload_err cc1352_prepare(struct fw_upload *fw_upload, cc1352_bootloader_reset(bg); WRITE_ONCE(bg->flashing_mode, false); msleep(200); - gb_greybus_init(bg); + if (gb_greybus_init(bg) < 0) + return dev_err_probe(&bg->sd->dev, FW_UPLOAD_ERR_RW_ERROR, + "Failed to initialize greybus"); gb_beagleplay_start_svc(bg); return FW_UPLOAD_ERR_FW_INVALID; } diff --git a/drivers/misc/eeprom/ee1004.c b/drivers/misc/eeprom/ee1004.c index 89224d4af4a2..e13f9fdd9d7b 100644 --- a/drivers/misc/eeprom/ee1004.c +++ b/drivers/misc/eeprom/ee1004.c @@ -304,6 +304,10 @@ static int ee1004_probe(struct i2c_client *client) I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_READ_BYTE_DATA)) return -EPFNOSUPPORT; + err = i2c_smbus_read_byte(client); + if (err < 0) + return -ENODEV; + mutex_lock(&ee1004_bus_lock); err = ee1004_init_bus_data(client); diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index 718ec5d81d94..67176caf5416 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c @@ -324,28 +324,6 @@ ssize_t mei_cldev_recv_vtag(struct mei_cl_device *cldev, u8 *buf, size_t length, EXPORT_SYMBOL_GPL(mei_cldev_recv_vtag); /** - * mei_cldev_recv_nonblock_vtag - non block client receive with vtag (read) - * - * @cldev: me client device - * @buf: buffer to receive - * @length: buffer length - * @vtag: virtual tag - * - * Return: - * * read size in bytes - * * -EAGAIN if function will block. - * * < 0 on other error - */ -ssize_t mei_cldev_recv_nonblock_vtag(struct mei_cl_device *cldev, u8 *buf, - size_t length, u8 *vtag) -{ - struct mei_cl *cl = cldev->cl; - - return __mei_cl_recv(cl, buf, length, vtag, MEI_CL_IO_RX_NONBLOCK, 0); -} -EXPORT_SYMBOL_GPL(mei_cldev_recv_nonblock_vtag); - -/** * mei_cldev_recv_timeout - client receive with timeout (read) * * @cldev: me client device @@ -439,23 +417,6 @@ ssize_t mei_cldev_recv(struct mei_cl_device *cldev, u8 *buf, size_t length) EXPORT_SYMBOL_GPL(mei_cldev_recv); /** - * mei_cldev_recv_nonblock - non block client receive (read) - * - * @cldev: me client device - * @buf: buffer to receive - * @length: buffer length - * - * Return: read size in bytes of < 0 on error - * -EAGAIN if function will block. - */ -ssize_t mei_cldev_recv_nonblock(struct mei_cl_device *cldev, u8 *buf, - size_t length) -{ - return mei_cldev_recv_nonblock_vtag(cldev, buf, length, NULL); -} -EXPORT_SYMBOL_GPL(mei_cldev_recv_nonblock); - -/** * mei_cl_bus_rx_work - dispatch rx event for a bus device * * @work: work @@ -641,19 +602,6 @@ void mei_cldev_set_drvdata(struct mei_cl_device *cldev, void *data) EXPORT_SYMBOL_GPL(mei_cldev_set_drvdata); /** - * mei_cldev_uuid - return uuid of the underlying me client - * - * @cldev: mei client device - * - * Return: me client uuid - */ -const uuid_le *mei_cldev_uuid(const struct mei_cl_device *cldev) -{ - return mei_me_cl_uuid(cldev->me_cl); -} -EXPORT_SYMBOL_GPL(mei_cldev_uuid); - -/** * mei_cldev_ver - return protocol version of the underlying me client * * @cldev: mei client device diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index be011cef12e5..3db07d2a881f 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c @@ -272,28 +272,6 @@ void mei_me_cl_rm_by_uuid(struct mei_device *dev, const uuid_le *uuid) } /** - * mei_me_cl_rm_by_uuid_id - remove all me clients matching client id - * - * @dev: the device structure - * @uuid: me client uuid - * @id: me client id - * - * Locking: called under "dev->device_lock" lock - */ -void mei_me_cl_rm_by_uuid_id(struct mei_device *dev, const uuid_le *uuid, u8 id) -{ - struct mei_me_client *me_cl; - - dev_dbg(dev->dev, "remove %pUl %d\n", uuid, id); - - down_write(&dev->me_clients_rwsem); - me_cl = __mei_me_cl_by_uuid_id(dev, uuid, id); - __mei_me_cl_del(dev, me_cl); - mei_me_cl_put(me_cl); - up_write(&dev->me_clients_rwsem); -} - -/** * mei_me_cl_rm_all - remove all me clients * * @dev: the device structure diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h index 9052860bcfe0..01ed26a148c4 100644 --- a/drivers/misc/mei/client.h +++ b/drivers/misc/mei/client.h @@ -29,8 +29,6 @@ struct mei_me_client *mei_me_cl_by_id(struct mei_device *dev, u8 client_id); struct mei_me_client *mei_me_cl_by_uuid_id(struct mei_device *dev, const uuid_le *uuid, u8 client_id); void mei_me_cl_rm_by_uuid(struct mei_device *dev, const uuid_le *uuid); -void mei_me_cl_rm_by_uuid_id(struct mei_device *dev, - const uuid_le *uuid, u8 id); void mei_me_cl_rm_all(struct mei_device *dev); /** diff --git a/drivers/misc/mei/hw-txe.c b/drivers/misc/mei/hw-txe.c index 5d0f68b95c29..e9476f9ae25d 100644 --- a/drivers/misc/mei/hw-txe.c +++ b/drivers/misc/mei/hw-txe.c @@ -1209,48 +1209,3 @@ struct mei_device *mei_txe_dev_init(struct pci_dev *pdev) return dev; } - -/** - * mei_txe_setup_satt2 - SATT2 configuration for DMA support. - * - * @dev: the device structure - * @addr: physical address start of the range - * @range: physical range size - * - * Return: 0 on success an error code otherwise - */ -int mei_txe_setup_satt2(struct mei_device *dev, phys_addr_t addr, u32 range) -{ - struct mei_txe_hw *hw = to_txe_hw(dev); - - u32 lo32 = lower_32_bits(addr); - u32 hi32 = upper_32_bits(addr); - u32 ctrl; - - /* SATT is limited to 36 Bits */ - if (hi32 & ~0xF) - return -EINVAL; - - /* SATT has to be 16Byte aligned */ - if (lo32 & 0xF) - return -EINVAL; - - /* SATT range has to be 4Bytes aligned */ - if (range & 0x4) - return -EINVAL; - - /* SATT is limited to 32 MB range*/ - if (range > SATT_RANGE_MAX) - return -EINVAL; - - ctrl = SATT2_CTRL_VALID_MSK; - ctrl |= hi32 << SATT2_CTRL_BR_BASE_ADDR_REG_SHIFT; - - mei_txe_br_reg_write(hw, SATT2_SAP_SIZE_REG, range); - mei_txe_br_reg_write(hw, SATT2_BRG_BA_LSB_REG, lo32); - mei_txe_br_reg_write(hw, SATT2_CTRL_REG, ctrl); - dev_dbg(dev->dev, "SATT2: SAP_SIZE_OFFSET=0x%08X, BRG_BA_LSB_OFFSET=0x%08X, CTRL_OFFSET=0x%08X\n", - range, lo32, ctrl); - - return 0; -} diff --git a/drivers/misc/mei/hw-txe.h b/drivers/misc/mei/hw-txe.h index 96511b04bf88..6790e646895d 100644 --- a/drivers/misc/mei/hw-txe.h +++ b/drivers/misc/mei/hw-txe.h @@ -59,7 +59,5 @@ irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id); int mei_txe_aliveness_set_sync(struct mei_device *dev, u32 req); -int mei_txe_setup_satt2(struct mei_device *dev, phys_addr_t addr, u32 range); - #endif /* _MEI_HW_TXE_H_ */ diff --git a/drivers/pps/generators/Kconfig b/drivers/pps/generators/Kconfig index cd94bf3bfaf2..b3f340ed3163 100644 --- a/drivers/pps/generators/Kconfig +++ b/drivers/pps/generators/Kconfig @@ -31,4 +31,20 @@ config PPS_GENERATOR_PARPORT utilizes STROBE pin of a parallel port to send PPS signals. It uses parport abstraction layer and hrtimers to precisely control the signal. +config PPS_GENERATOR_TIO + tristate "TIO PPS signal generator" + depends on X86 && CPU_SUP_INTEL + help + If you say yes here you get support for a PPS TIO signal generator + which generates a pulse at a prescribed time based on the system clock. + It uses time translation and hrtimers to precisely generate a pulse. + This hardware is present on 2019 and newer Intel CPUs. However, this + driver is not useful without adding highly specialized hardware outside + the Linux system to observe these pulses. + + To compile this driver as a module, choose M here: the module + will be called pps_gen_tio. + + If unsure, say N. + endif # PPS_GENERATOR diff --git a/drivers/pps/generators/Makefile b/drivers/pps/generators/Makefile index dc1aa5a4688b..e109920e8a2d 100644 --- a/drivers/pps/generators/Makefile +++ b/drivers/pps/generators/Makefile @@ -8,5 +8,6 @@ obj-$(CONFIG_PPS_GENERATOR) := pps_gen_core.o obj-$(CONFIG_PPS_GENERATOR_DUMMY) += pps_gen-dummy.o obj-$(CONFIG_PPS_GENERATOR_PARPORT) += pps_gen_parport.o +obj-$(CONFIG_PPS_GENERATOR_TIO) += pps_gen_tio.o ccflags-$(CONFIG_PPS_DEBUG) := -DDEBUG diff --git a/drivers/pps/generators/pps_gen-dummy.c b/drivers/pps/generators/pps_gen-dummy.c index b284c200cbe5..55de4aecf35e 100644 --- a/drivers/pps/generators/pps_gen-dummy.c +++ b/drivers/pps/generators/pps_gen-dummy.c @@ -61,7 +61,7 @@ static int pps_gen_dummy_enable(struct pps_gen_device *pps_gen, bool enable) * The PPS info struct */ -static struct pps_gen_source_info pps_gen_dummy_info = { +static const struct pps_gen_source_info pps_gen_dummy_info = { .use_system_clock = true, .get_time = pps_gen_dummy_get_time, .enable = pps_gen_dummy_enable, diff --git a/drivers/pps/generators/pps_gen.c b/drivers/pps/generators/pps_gen.c index ca592f1736f4..5b8bb454913c 100644 --- a/drivers/pps/generators/pps_gen.c +++ b/drivers/pps/generators/pps_gen.c @@ -66,7 +66,7 @@ static long pps_gen_cdev_ioctl(struct file *file, if (ret) return -EFAULT; - ret = pps_gen->info.enable(pps_gen, status); + ret = pps_gen->info->enable(pps_gen, status); if (ret) return ret; pps_gen->enabled = status; @@ -76,7 +76,7 @@ static long pps_gen_cdev_ioctl(struct file *file, case PPS_GEN_USESYSTEMCLOCK: dev_dbg(pps_gen->dev, "PPS_GEN_USESYSTEMCLOCK\n"); - ret = put_user(pps_gen->info.use_system_clock, uiuarg); + ret = put_user(pps_gen->info->use_system_clock, uiuarg); if (ret) return -EFAULT; @@ -175,7 +175,7 @@ static int pps_gen_register_cdev(struct pps_gen_device *pps_gen) devt = MKDEV(MAJOR(pps_gen_devt), pps_gen->id); cdev_init(&pps_gen->cdev, &pps_gen_cdev_fops); - pps_gen->cdev.owner = pps_gen->info.owner; + pps_gen->cdev.owner = pps_gen->info->owner; err = cdev_add(&pps_gen->cdev, devt, 1); if (err) { @@ -183,8 +183,8 @@ static int pps_gen_register_cdev(struct pps_gen_device *pps_gen) MAJOR(pps_gen_devt), pps_gen->id); goto free_ida; } - pps_gen->dev = device_create(pps_gen_class, pps_gen->info.parent, devt, - pps_gen, "pps-gen%d", pps_gen->id); + pps_gen->dev = device_create(pps_gen_class, pps_gen->info->parent, devt, + pps_gen, "pps-gen%d", pps_gen->id); if (IS_ERR(pps_gen->dev)) { err = PTR_ERR(pps_gen->dev); goto del_cdev; @@ -225,7 +225,7 @@ static void pps_gen_unregister_cdev(struct pps_gen_device *pps_gen) * Return: the PPS generator device in case of success, and ERR_PTR(errno) * otherwise. */ -struct pps_gen_device *pps_gen_register_source(struct pps_gen_source_info *info) +struct pps_gen_device *pps_gen_register_source(const struct pps_gen_source_info *info) { struct pps_gen_device *pps_gen; int err; @@ -235,7 +235,7 @@ struct pps_gen_device *pps_gen_register_source(struct pps_gen_source_info *info) err = -ENOMEM; goto pps_gen_register_source_exit; } - pps_gen->info = *info; + pps_gen->info = info; pps_gen->enabled = false; init_waitqueue_head(&pps_gen->queue); diff --git a/drivers/pps/generators/pps_gen_tio.c b/drivers/pps/generators/pps_gen_tio.c new file mode 100644 index 000000000000..6c46b46c66cd --- /dev/null +++ b/drivers/pps/generators/pps_gen_tio.c @@ -0,0 +1,272 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Intel PPS signal Generator Driver + * + * Copyright (C) 2024 Intel Corporation + */ + +#include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/cleanup.h> +#include <linux/container_of.h> +#include <linux/device.h> +#include <linux/hrtimer.h> +#include <linux/io-64-nonatomic-hi-lo.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/pps_gen_kernel.h> +#include <linux/timekeeping.h> +#include <linux/types.h> + +#include <asm/cpu_device_id.h> + +#define TIOCTL 0x00 +#define TIOCOMPV 0x10 +#define TIOEC 0x30 + +/* Control Register */ +#define TIOCTL_EN BIT(0) +#define TIOCTL_DIR BIT(1) +#define TIOCTL_EP GENMASK(3, 2) +#define TIOCTL_EP_RISING_EDGE FIELD_PREP(TIOCTL_EP, 0) +#define TIOCTL_EP_FALLING_EDGE FIELD_PREP(TIOCTL_EP, 1) +#define TIOCTL_EP_TOGGLE_EDGE FIELD_PREP(TIOCTL_EP, 2) + +/* Safety time to set hrtimer early */ +#define SAFE_TIME_NS (10 * NSEC_PER_MSEC) + +#define MAGIC_CONST (NSEC_PER_SEC - SAFE_TIME_NS) +#define ART_HW_DELAY_CYCLES 2 + +struct pps_tio { + struct pps_gen_source_info gen_info; + struct pps_gen_device *pps_gen; + struct hrtimer timer; + void __iomem *base; + u32 prev_count; + spinlock_t lock; + struct device *dev; +}; + +static inline u32 pps_tio_read(u32 offset, struct pps_tio *tio) +{ + return readl(tio->base + offset); +} + +static inline void pps_ctl_write(u32 value, struct pps_tio *tio) +{ + writel(value, tio->base + TIOCTL); +} + +/* + * For COMPV register, It's safer to write + * higher 32-bit followed by lower 32-bit + */ +static inline void pps_compv_write(u64 value, struct pps_tio *tio) +{ + hi_lo_writeq(value, tio->base + TIOCOMPV); +} + +static inline ktime_t first_event(struct pps_tio *tio) +{ + return ktime_set(ktime_get_real_seconds() + 1, MAGIC_CONST); +} + +static u32 pps_tio_disable(struct pps_tio *tio) +{ + u32 ctrl; + + ctrl = pps_tio_read(TIOCTL, tio); + pps_compv_write(0, tio); + + ctrl &= ~TIOCTL_EN; + pps_ctl_write(ctrl, tio); + tio->pps_gen->enabled = false; + tio->prev_count = 0; + return ctrl; +} + +static void pps_tio_enable(struct pps_tio *tio) +{ + u32 ctrl; + + ctrl = pps_tio_read(TIOCTL, tio); + ctrl |= TIOCTL_EN; + pps_ctl_write(ctrl, tio); + tio->pps_gen->enabled = true; +} + +static void pps_tio_direction_output(struct pps_tio *tio) +{ + u32 ctrl; + + ctrl = pps_tio_disable(tio); + + /* + * We enable the device, be sure that the + * 'compare' value is invalid + */ + pps_compv_write(0, tio); + + ctrl &= ~(TIOCTL_DIR | TIOCTL_EP); + ctrl |= TIOCTL_EP_TOGGLE_EDGE; + pps_ctl_write(ctrl, tio); + pps_tio_enable(tio); +} + +static bool pps_generate_next_pulse(ktime_t expires, struct pps_tio *tio) +{ + u64 art; + + if (!ktime_real_to_base_clock(expires, CSID_X86_ART, &art)) { + pps_tio_disable(tio); + return false; + } + + pps_compv_write(art - ART_HW_DELAY_CYCLES, tio); + return true; +} + +static enum hrtimer_restart hrtimer_callback(struct hrtimer *timer) +{ + ktime_t expires, now; + u32 event_count; + struct pps_tio *tio = container_of(timer, struct pps_tio, timer); + + guard(spinlock)(&tio->lock); + + /* + * Check if any event is missed. + * If an event is missed, TIO will be disabled. + */ + event_count = pps_tio_read(TIOEC, tio); + if (tio->prev_count && tio->prev_count == event_count) + goto err; + tio->prev_count = event_count; + + expires = hrtimer_get_expires(timer); + + now = ktime_get_real(); + if (now - expires >= SAFE_TIME_NS) + goto err; + + tio->pps_gen->enabled = pps_generate_next_pulse(expires + SAFE_TIME_NS, tio); + if (!tio->pps_gen->enabled) + return HRTIMER_NORESTART; + + hrtimer_forward(timer, now, NSEC_PER_SEC / 2); + return HRTIMER_RESTART; + +err: + dev_err(tio->dev, "Event missed, Disabling Timed I/O"); + pps_tio_disable(tio); + pps_gen_event(tio->pps_gen, PPS_GEN_EVENT_MISSEDPULSE, NULL); + return HRTIMER_NORESTART; +} + +static int pps_tio_gen_enable(struct pps_gen_device *pps_gen, bool enable) +{ + struct pps_tio *tio = container_of(pps_gen->info, struct pps_tio, gen_info); + + if (!timekeeping_clocksource_has_base(CSID_X86_ART)) { + dev_err_once(tio->dev, "PPS cannot be used as clock is not related to ART"); + return -ENODEV; + } + + guard(spinlock_irqsave)(&tio->lock); + if (enable && !pps_gen->enabled) { + pps_tio_direction_output(tio); + hrtimer_start(&tio->timer, first_event(tio), HRTIMER_MODE_ABS); + } else if (!enable && pps_gen->enabled) { + hrtimer_cancel(&tio->timer); + pps_tio_disable(tio); + } + + return 0; +} + +static int pps_tio_get_time(struct pps_gen_device *pps_gen, + struct timespec64 *time) +{ + struct system_time_snapshot snap; + + ktime_get_snapshot(&snap); + *time = ktime_to_timespec64(snap.real); + + return 0; +} + +static int pps_gen_tio_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct pps_tio *tio; + + if (!(cpu_feature_enabled(X86_FEATURE_TSC_KNOWN_FREQ) && + cpu_feature_enabled(X86_FEATURE_ART))) { + dev_warn(dev, "TSC/ART is not enabled"); + return -ENODEV; + } + + tio = devm_kzalloc(dev, sizeof(*tio), GFP_KERNEL); + if (!tio) + return -ENOMEM; + + tio->gen_info.use_system_clock = true; + tio->gen_info.enable = pps_tio_gen_enable; + tio->gen_info.get_time = pps_tio_get_time; + tio->gen_info.owner = THIS_MODULE; + + tio->pps_gen = pps_gen_register_source(&tio->gen_info); + if (IS_ERR(tio->pps_gen)) + return PTR_ERR(tio->pps_gen); + + tio->dev = dev; + tio->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(tio->base)) + return PTR_ERR(tio->base); + + pps_tio_disable(tio); + hrtimer_init(&tio->timer, CLOCK_REALTIME, HRTIMER_MODE_ABS); + tio->timer.function = hrtimer_callback; + spin_lock_init(&tio->lock); + platform_set_drvdata(pdev, &tio); + + return 0; +} + +static void pps_gen_tio_remove(struct platform_device *pdev) +{ + struct pps_tio *tio = platform_get_drvdata(pdev); + + hrtimer_cancel(&tio->timer); + pps_tio_disable(tio); + pps_gen_unregister_source(tio->pps_gen); +} + +static const struct acpi_device_id intel_pmc_tio_acpi_match[] = { + { "INTC1021" }, + { "INTC1022" }, + { "INTC1023" }, + { "INTC1024" }, + {} +}; +MODULE_DEVICE_TABLE(acpi, intel_pmc_tio_acpi_match); + +static struct platform_driver pps_gen_tio_driver = { + .probe = pps_gen_tio_probe, + .remove = pps_gen_tio_remove, + .driver = { + .name = "intel-pps-gen-tio", + .acpi_match_table = intel_pmc_tio_acpi_match, + }, +}; +module_platform_driver(pps_gen_tio_driver); + +MODULE_AUTHOR("Christopher Hall <christopher.s.hall@intel.com>"); +MODULE_AUTHOR("Lakshmi Sowjanya D <lakshmi.sowjanya.d@intel.com>"); +MODULE_AUTHOR("Pandith N <pandith.n@intel.com>"); +MODULE_AUTHOR("Thejesh Reddy T R <thejesh.reddy.t.r@intel.com>"); +MODULE_AUTHOR("Subramanian Mohan <subramanian.mohan@intel.com>"); +MODULE_DESCRIPTION("Intel PMC Time-Aware IO Generator Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/pps/generators/sysfs.c b/drivers/pps/generators/sysfs.c index faf8b1c6d202..6d6bc0006fea 100644 --- a/drivers/pps/generators/sysfs.c +++ b/drivers/pps/generators/sysfs.c @@ -19,7 +19,7 @@ static ssize_t system_show(struct device *dev, struct device_attribute *attr, { struct pps_gen_device *pps_gen = dev_get_drvdata(dev); - return sysfs_emit(buf, "%d\n", pps_gen->info.use_system_clock); + return sysfs_emit(buf, "%d\n", pps_gen->info->use_system_clock); } static DEVICE_ATTR_RO(system); @@ -30,7 +30,7 @@ static ssize_t time_show(struct device *dev, struct device_attribute *attr, struct timespec64 time; int ret; - ret = pps_gen->info.get_time(pps_gen, &time); + ret = pps_gen->info->get_time(pps_gen, &time); if (ret) return ret; @@ -49,7 +49,7 @@ static ssize_t enable_store(struct device *dev, struct device_attribute *attr, if (ret) return ret; - ret = pps_gen->info.enable(pps_gen, status); + ret = pps_gen->info->enable(pps_gen, status); if (ret) return ret; pps_gen->enabled = status; diff --git a/include/linux/mei_cl_bus.h b/include/linux/mei_cl_bus.h index b38a56a13f39..725fd7727422 100644 --- a/include/linux/mei_cl_bus.h +++ b/include/linux/mei_cl_bus.h @@ -97,8 +97,6 @@ ssize_t mei_cldev_send(struct mei_cl_device *cldev, const u8 *buf, ssize_t mei_cldev_send_timeout(struct mei_cl_device *cldev, const u8 *buf, size_t length, unsigned long timeout); ssize_t mei_cldev_recv(struct mei_cl_device *cldev, u8 *buf, size_t length); -ssize_t mei_cldev_recv_nonblock(struct mei_cl_device *cldev, u8 *buf, - size_t length); ssize_t mei_cldev_recv_timeout(struct mei_cl_device *cldev, u8 *buf, size_t length, unsigned long timeout); ssize_t mei_cldev_send_vtag(struct mei_cl_device *cldev, const u8 *buf, @@ -107,8 +105,6 @@ ssize_t mei_cldev_send_vtag_timeout(struct mei_cl_device *cldev, const u8 *buf, size_t length, u8 vtag, unsigned long timeout); ssize_t mei_cldev_recv_vtag(struct mei_cl_device *cldev, u8 *buf, size_t length, u8 *vtag); -ssize_t mei_cldev_recv_nonblock_vtag(struct mei_cl_device *cldev, u8 *buf, - size_t length, u8 *vtag); ssize_t mei_cldev_recv_vtag_timeout(struct mei_cl_device *cldev, u8 *buf, size_t length, u8 *vtag, unsigned long timeout); @@ -116,7 +112,6 @@ int mei_cldev_register_rx_cb(struct mei_cl_device *cldev, mei_cldev_cb_t rx_cb); int mei_cldev_register_notif_cb(struct mei_cl_device *cldev, mei_cldev_cb_t notif_cb); -const uuid_le *mei_cldev_uuid(const struct mei_cl_device *cldev); u8 mei_cldev_ver(const struct mei_cl_device *cldev); void *mei_cldev_get_drvdata(const struct mei_cl_device *cldev); diff --git a/include/linux/pps_gen_kernel.h b/include/linux/pps_gen_kernel.h index 022ea0ac4440..6214c8aa2e02 100644 --- a/include/linux/pps_gen_kernel.h +++ b/include/linux/pps_gen_kernel.h @@ -43,7 +43,7 @@ struct pps_gen_source_info { /* The main struct */ struct pps_gen_device { - struct pps_gen_source_info info; /* PSS generator info */ + const struct pps_gen_source_info *info; /* PSS generator info */ bool enabled; /* PSS generator status */ unsigned int event; @@ -70,7 +70,7 @@ extern const struct attribute_group *pps_gen_groups[]; */ extern struct pps_gen_device *pps_gen_register_source( - struct pps_gen_source_info *info); + const struct pps_gen_source_info *info); extern void pps_gen_unregister_source(struct pps_gen_device *pps_gen); extern void pps_gen_event(struct pps_gen_device *pps_gen, unsigned int event, void *data); diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 35796c290ca3..01b5bb2ba7b9 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -2479,13 +2479,20 @@ config TEST_IDA tristate "Perform selftest on IDA functions" config TEST_MISC_MINOR - tristate "Basic misc minor Kunit test" if !KUNIT_ALL_TESTS + tristate "miscdevice KUnit test" if !KUNIT_ALL_TESTS depends on KUNIT default KUNIT_ALL_TESTS help - Kunit test for the misc minor. - It tests misc minor functions for dynamic and misc dynamic minor. - This include misc_xxx functions + Kunit test for miscdevice API, specially its behavior in respect to + static and dynamic minor numbers. + + KUnit tests run during boot and output the results to the debug log + in TAP format (https://testanything.org/). Only useful for kernel devs + running the KUnit test harness, and not intended for inclusion into a + production build. + + For more information on KUnit and unit tests in general please refer + to the KUnit documentation in Documentation/dev-tools/kunit/. If unsure, say N. diff --git a/rust/kernel/miscdevice.rs b/rust/kernel/miscdevice.rs index e14433b2ab9d..fa9ecc42602a 100644 --- a/rust/kernel/miscdevice.rs +++ b/rust/kernel/miscdevice.rs @@ -35,7 +35,7 @@ impl MiscDeviceOptions { let mut result: bindings::miscdevice = unsafe { MaybeUninit::zeroed().assume_init() }; result.minor = bindings::MISC_DYNAMIC_MINOR as _; result.name = self.name.as_char_ptr(); - result.fops = create_vtable::<T>(); + result.fops = MiscdeviceVTable::<T>::build(); result } } @@ -160,171 +160,160 @@ pub trait MiscDevice: Sized { } } -const fn create_vtable<T: MiscDevice>() -> &'static bindings::file_operations { - const fn maybe_fn<T: Copy>(check: bool, func: T) -> Option<T> { - if check { - Some(func) - } else { - None +/// A vtable for the file operations of a Rust miscdevice. +struct MiscdeviceVTable<T: MiscDevice>(PhantomData<T>); + +impl<T: MiscDevice> MiscdeviceVTable<T> { + /// # Safety + /// + /// `file` and `inode` must be the file and inode for a file that is undergoing initialization. + /// The file must be associated with a `MiscDeviceRegistration<T>`. + unsafe extern "C" fn open(inode: *mut bindings::inode, raw_file: *mut bindings::file) -> c_int { + // SAFETY: The pointers are valid and for a file being opened. + let ret = unsafe { bindings::generic_file_open(inode, raw_file) }; + if ret != 0 { + return ret; } - } - struct VtableHelper<T: MiscDevice> { - _t: PhantomData<T>, - } - impl<T: MiscDevice> VtableHelper<T> { - const VTABLE: bindings::file_operations = bindings::file_operations { - open: Some(fops_open::<T>), - release: Some(fops_release::<T>), - unlocked_ioctl: maybe_fn(T::HAS_IOCTL, fops_ioctl::<T>), - #[cfg(CONFIG_COMPAT)] - compat_ioctl: if T::HAS_COMPAT_IOCTL { - Some(fops_compat_ioctl::<T>) - } else if T::HAS_IOCTL { - Some(bindings::compat_ptr_ioctl) - } else { - None - }, - show_fdinfo: maybe_fn(T::HAS_SHOW_FDINFO, fops_show_fdinfo::<T>), - // SAFETY: All zeros is a valid value for `bindings::file_operations`. - ..unsafe { MaybeUninit::zeroed().assume_init() } - }; - } + // SAFETY: The open call of a file can access the private data. + let misc_ptr = unsafe { (*raw_file).private_data }; - &VtableHelper::<T>::VTABLE -} + // SAFETY: This is a miscdevice, so `misc_open()` set the private data to a pointer to the + // associated `struct miscdevice` before calling into this method. Furthermore, + // `misc_open()` ensures that the miscdevice can't be unregistered and freed during this + // call to `fops_open`. + let misc = unsafe { &*misc_ptr.cast::<MiscDeviceRegistration<T>>() }; -/// # Safety -/// -/// `file` and `inode` must be the file and inode for a file that is undergoing initialization. -/// The file must be associated with a `MiscDeviceRegistration<T>`. -unsafe extern "C" fn fops_open<T: MiscDevice>( - inode: *mut bindings::inode, - raw_file: *mut bindings::file, -) -> c_int { - // SAFETY: The pointers are valid and for a file being opened. - let ret = unsafe { bindings::generic_file_open(inode, raw_file) }; - if ret != 0 { - return ret; - } + // SAFETY: + // * This underlying file is valid for (much longer than) the duration of `T::open`. + // * There is no active fdget_pos region on the file on this thread. + let file = unsafe { File::from_raw_file(raw_file) }; - // SAFETY: The open call of a file can access the private data. - let misc_ptr = unsafe { (*raw_file).private_data }; - - // SAFETY: This is a miscdevice, so `misc_open()` set the private data to a pointer to the - // associated `struct miscdevice` before calling into this method. Furthermore, `misc_open()` - // ensures that the miscdevice can't be unregistered and freed during this call to `fops_open`. - let misc = unsafe { &*misc_ptr.cast::<MiscDeviceRegistration<T>>() }; + let ptr = match T::open(file, misc) { + Ok(ptr) => ptr, + Err(err) => return err.to_errno(), + }; - // SAFETY: - // * This underlying file is valid for (much longer than) the duration of `T::open`. - // * There is no active fdget_pos region on the file on this thread. - let file = unsafe { File::from_raw_file(raw_file) }; + // This overwrites the private data with the value specified by the user, changing the type + // of this file's private data. All future accesses to the private data is performed by + // other fops_* methods in this file, which all correctly cast the private data to the new + // type. + // + // SAFETY: The open call of a file can access the private data. + unsafe { (*raw_file).private_data = ptr.into_foreign() }; - let ptr = match T::open(file, misc) { - Ok(ptr) => ptr, - Err(err) => return err.to_errno(), - }; - - // This overwrites the private data with the value specified by the user, changing the type of - // this file's private data. All future accesses to the private data is performed by other - // fops_* methods in this file, which all correctly cast the private data to the new type. - // - // SAFETY: The open call of a file can access the private data. - unsafe { (*raw_file).private_data = ptr.into_foreign() }; + 0 + } - 0 -} + /// # Safety + /// + /// `file` and `inode` must be the file and inode for a file that is being released. The file + /// must be associated with a `MiscDeviceRegistration<T>`. + unsafe extern "C" fn release(_inode: *mut bindings::inode, file: *mut bindings::file) -> c_int { + // SAFETY: The release call of a file owns the private data. + let private = unsafe { (*file).private_data }; + // SAFETY: The release call of a file owns the private data. + let ptr = unsafe { <T::Ptr as ForeignOwnable>::from_foreign(private) }; + + // SAFETY: + // * The file is valid for the duration of this call. + // * There is no active fdget_pos region on the file on this thread. + T::release(ptr, unsafe { File::from_raw_file(file) }); + + 0 + } -/// # Safety -/// -/// `file` and `inode` must be the file and inode for a file that is being released. The file must -/// be associated with a `MiscDeviceRegistration<T>`. -unsafe extern "C" fn fops_release<T: MiscDevice>( - _inode: *mut bindings::inode, - file: *mut bindings::file, -) -> c_int { - // SAFETY: The release call of a file owns the private data. - let private = unsafe { (*file).private_data }; - // SAFETY: The release call of a file owns the private data. - let ptr = unsafe { <T::Ptr as ForeignOwnable>::from_foreign(private) }; - - // SAFETY: - // * The file is valid for the duration of this call. - // * There is no active fdget_pos region on the file on this thread. - T::release(ptr, unsafe { File::from_raw_file(file) }); - - 0 -} + /// # Safety + /// + /// `file` must be a valid file that is associated with a `MiscDeviceRegistration<T>`. + unsafe extern "C" fn ioctl(file: *mut bindings::file, cmd: c_uint, arg: c_ulong) -> c_long { + // SAFETY: The ioctl call of a file can access the private data. + let private = unsafe { (*file).private_data }; + // SAFETY: Ioctl calls can borrow the private data of the file. + let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) }; + + // SAFETY: + // * The file is valid for the duration of this call. + // * There is no active fdget_pos region on the file on this thread. + let file = unsafe { File::from_raw_file(file) }; + + match T::ioctl(device, file, cmd, arg) { + Ok(ret) => ret as c_long, + Err(err) => err.to_errno() as c_long, + } + } -/// # Safety -/// -/// `file` must be a valid file that is associated with a `MiscDeviceRegistration<T>`. -unsafe extern "C" fn fops_ioctl<T: MiscDevice>( - file: *mut bindings::file, - cmd: c_uint, - arg: c_ulong, -) -> c_long { - // SAFETY: The ioctl call of a file can access the private data. - let private = unsafe { (*file).private_data }; - // SAFETY: Ioctl calls can borrow the private data of the file. - let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) }; - - // SAFETY: - // * The file is valid for the duration of this call. - // * There is no active fdget_pos region on the file on this thread. - let file = unsafe { File::from_raw_file(file) }; - - match T::ioctl(device, file, cmd, arg) { - Ok(ret) => ret as c_long, - Err(err) => err.to_errno() as c_long, + /// # Safety + /// + /// `file` must be a valid file that is associated with a `MiscDeviceRegistration<T>`. + #[cfg(CONFIG_COMPAT)] + unsafe extern "C" fn compat_ioctl( + file: *mut bindings::file, + cmd: c_uint, + arg: c_ulong, + ) -> c_long { + // SAFETY: The compat ioctl call of a file can access the private data. + let private = unsafe { (*file).private_data }; + // SAFETY: Ioctl calls can borrow the private data of the file. + let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) }; + + // SAFETY: + // * The file is valid for the duration of this call. + // * There is no active fdget_pos region on the file on this thread. + let file = unsafe { File::from_raw_file(file) }; + + match T::compat_ioctl(device, file, cmd, arg) { + Ok(ret) => ret as c_long, + Err(err) => err.to_errno() as c_long, + } } -} -/// # Safety -/// -/// `file` must be a valid file that is associated with a `MiscDeviceRegistration<T>`. -#[cfg(CONFIG_COMPAT)] -unsafe extern "C" fn fops_compat_ioctl<T: MiscDevice>( - file: *mut bindings::file, - cmd: c_uint, - arg: c_ulong, -) -> c_long { - // SAFETY: The compat ioctl call of a file can access the private data. - let private = unsafe { (*file).private_data }; - // SAFETY: Ioctl calls can borrow the private data of the file. - let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) }; - - // SAFETY: - // * The file is valid for the duration of this call. - // * There is no active fdget_pos region on the file on this thread. - let file = unsafe { File::from_raw_file(file) }; - - match T::compat_ioctl(device, file, cmd, arg) { - Ok(ret) => ret as c_long, - Err(err) => err.to_errno() as c_long, + /// # Safety + /// + /// - `file` must be a valid file that is associated with a `MiscDeviceRegistration<T>`. + /// - `seq_file` must be a valid `struct seq_file` that we can write to. + unsafe extern "C" fn show_fdinfo(seq_file: *mut bindings::seq_file, file: *mut bindings::file) { + // SAFETY: The release call of a file owns the private data. + let private = unsafe { (*file).private_data }; + // SAFETY: Ioctl calls can borrow the private data of the file. + let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) }; + // SAFETY: + // * The file is valid for the duration of this call. + // * There is no active fdget_pos region on the file on this thread. + let file = unsafe { File::from_raw_file(file) }; + // SAFETY: The caller ensures that the pointer is valid and exclusive for the duration in + // which this method is called. + let m = unsafe { SeqFile::from_raw(seq_file) }; + + T::show_fdinfo(device, m, file); } -} -/// # Safety -/// -/// - `file` must be a valid file that is associated with a `MiscDeviceRegistration<T>`. -/// - `seq_file` must be a valid `struct seq_file` that we can write to. -unsafe extern "C" fn fops_show_fdinfo<T: MiscDevice>( - seq_file: *mut bindings::seq_file, - file: *mut bindings::file, -) { - // SAFETY: The release call of a file owns the private data. - let private = unsafe { (*file).private_data }; - // SAFETY: Ioctl calls can borrow the private data of the file. - let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) }; - // SAFETY: - // * The file is valid for the duration of this call. - // * There is no active fdget_pos region on the file on this thread. - let file = unsafe { File::from_raw_file(file) }; - // SAFETY: The caller ensures that the pointer is valid and exclusive for the duration in which - // this method is called. - let m = unsafe { SeqFile::from_raw(seq_file) }; - - T::show_fdinfo(device, m, file); + const VTABLE: bindings::file_operations = bindings::file_operations { + open: Some(Self::open), + release: Some(Self::release), + unlocked_ioctl: if T::HAS_IOCTL { + Some(Self::ioctl) + } else { + None + }, + #[cfg(CONFIG_COMPAT)] + compat_ioctl: if T::HAS_COMPAT_IOCTL { + Some(Self::compat_ioctl) + } else if T::HAS_IOCTL { + Some(bindings::compat_ptr_ioctl) + } else { + None + }, + show_fdinfo: if T::HAS_SHOW_FDINFO { + Some(Self::show_fdinfo) + } else { + None + }, + // SAFETY: All zeros is a valid value for `bindings::file_operations`. + ..unsafe { MaybeUninit::zeroed().assume_init() } + }; + + const fn build() -> &'static bindings::file_operations { + &Self::VTABLE + } } diff --git a/scripts/tags.sh b/scripts/tags.sh index 45eaf35f5bff..98680e9cd7be 100755 --- a/scripts/tags.sh +++ b/scripts/tags.sh @@ -146,6 +146,7 @@ dogtags() # a ^[^#] is prepended by setup_regex unless an anchor is already present regex_asm=( '/^\(ENTRY\|_GLOBAL\)([[:space:]]*\([[:alnum:]_\\]*\)).*/\2/' + '/^SYM_[[:alnum:]_]*START[[:alnum:]_]*([[:space:]]*\([[:alnum:]_\\]*\)).*/\1/' ) regex_c=( '/^SYSCALL_DEFINE[0-9]([[:space:]]*\([[:alnum:]_]*\).*/sys_\1/' |