diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2023-11-03 14:51:08 -1000 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2023-11-03 14:51:08 -1000 |
commit | d99b91a99be430be45413052bb428107c435918b (patch) | |
tree | 61f44b60b9423760c1b078421d1ebabcb6cf7ae2 /drivers/misc | |
parent | e392ea4d4d00880bf94550151b1ace4f88a4b17a (diff) | |
parent | fa10f413091a43f801f82b3cf484f15d6fc9266f (diff) |
Merge tag 'char-misc-6.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc
Pull char/misc updates from Greg KH:
"Here is the big set of char/misc and other small driver subsystem
changes for 6.7-rc1. Included in here are:
- IIO subsystem driver updates and additions (largest part of this
pull request)
- FPGA subsystem driver updates
- Counter subsystem driver updates
- ICC subsystem driver updates
- extcon subsystem driver updates
- mei driver updates and additions
- nvmem subsystem driver updates and additions
- comedi subsystem dependency fixes
- parport driver fixups
- cdx subsystem driver and core updates
- splice support for /dev/zero and /dev/full
- other smaller driver cleanups
All of these have been in linux-next for a while with no reported
issues"
* tag 'char-misc-6.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (326 commits)
cdx: add sysfs for subsystem, class and revision
cdx: add sysfs for bus reset
cdx: add support for bus enable and disable
cdx: Register cdx bus as a device on cdx subsystem
cdx: Create symbol namespaces for cdx subsystem
cdx: Introduce lock to protect controller ops
cdx: Remove cdx controller list from cdx bus system
dts: ti: k3-am625-beagleplay: Add beaglecc1352
greybus: Add BeaglePlay Linux Driver
dt-bindings: net: Add ti,cc1352p7
dt-bindings: eeprom: at24: allow NVMEM cells based on old syntax
dt-bindings: nvmem: SID: allow NVMEM cells based on old syntax
Revert "nvmem: add new config option"
MAINTAINERS: coresight: Add missing Coresight files
misc: pci_endpoint_test: Add deviceID for J721S2 PCIe EP device support
firmware: xilinx: Move EXPORT_SYMBOL_GPL next to zynqmp_pm_feature definition
uacce: make uacce_class constant
ocxl: make ocxl_class constant
cxl: make cxl_class constant
misc: phantom: make phantom_class constant
...
Diffstat (limited to 'drivers/misc')
32 files changed, 492 insertions, 465 deletions
diff --git a/drivers/misc/bcm-vk/bcm_vk_msg.c b/drivers/misc/bcm-vk/bcm_vk_msg.c index e17d81231ea6..1f42d1d5a630 100644 --- a/drivers/misc/bcm-vk/bcm_vk_msg.c +++ b/drivers/misc/bcm-vk/bcm_vk_msg.c @@ -703,12 +703,12 @@ int bcm_vk_send_shutdown_msg(struct bcm_vk *vk, u32 shut_type, entry = kzalloc(struct_size(entry, to_v_msg, 1), GFP_KERNEL); if (!entry) return -ENOMEM; + entry->to_v_blks = 1; /* always 1 block */ /* fill up necessary data */ entry->to_v_msg[0].function_id = VK_FID_SHUTDOWN; set_q_num(&entry->to_v_msg[0], q_num); set_msg_id(&entry->to_v_msg[0], VK_SIMPLEX_MSG_ID); - entry->to_v_blks = 1; /* always 1 block */ entry->to_v_msg[0].cmd = shut_type; entry->to_v_msg[0].arg = pid; diff --git a/drivers/misc/bcm-vk/bcm_vk_msg.h b/drivers/misc/bcm-vk/bcm_vk_msg.h index 56784c8896d8..157495e48f15 100644 --- a/drivers/misc/bcm-vk/bcm_vk_msg.h +++ b/drivers/misc/bcm-vk/bcm_vk_msg.h @@ -116,7 +116,7 @@ struct bcm_vk_wkent { u32 usr_msg_id; u32 to_v_blks; u32 seq_num; - struct vk_msg_blk to_v_msg[]; + struct vk_msg_blk to_v_msg[] __counted_by(to_v_blks); }; /* queue stats counters */ diff --git a/drivers/misc/c2port/core.c b/drivers/misc/c2port/core.c index f574c83b82cf..2bb1dd2511f9 100644 --- a/drivers/misc/c2port/core.c +++ b/drivers/misc/c2port/core.c @@ -923,7 +923,7 @@ struct c2port_device *c2port_device_register(char *name, } dev_set_drvdata(c2dev->dev, c2dev); - strncpy(c2dev->name, name, C2PORT_NAME_LEN - 1); + strscpy(c2dev->name, name, sizeof(c2dev->name)); c2dev->ops = ops; mutex_init(&c2dev->mutex); diff --git a/drivers/misc/cxl/file.c b/drivers/misc/cxl/file.c index 144d1f2d78ce..012e11b959bc 100644 --- a/drivers/misc/cxl/file.c +++ b/drivers/misc/cxl/file.c @@ -38,8 +38,6 @@ static dev_t cxl_dev; -static struct class *cxl_class; - static int __afu_open(struct inode *inode, struct file *file, bool master) { struct cxl *adapter; @@ -559,7 +557,10 @@ static char *cxl_devnode(const struct device *dev, umode_t *mode) return kasprintf(GFP_KERNEL, "cxl/%s", dev_name(dev)); } -extern struct class *cxl_class; +static const struct class cxl_class = { + .name = "cxl", + .devnode = cxl_devnode, +}; static int cxl_add_chardev(struct cxl_afu *afu, dev_t devt, struct cdev *cdev, struct device **chardev, char *postfix, char *desc, @@ -575,7 +576,7 @@ static int cxl_add_chardev(struct cxl_afu *afu, dev_t devt, struct cdev *cdev, return rc; } - dev = device_create(cxl_class, &afu->dev, devt, afu, + dev = device_create(&cxl_class, &afu->dev, devt, afu, "afu%i.%i%s", afu->adapter->adapter_num, afu->slice, postfix); if (IS_ERR(dev)) { rc = PTR_ERR(dev); @@ -633,14 +634,14 @@ void cxl_chardev_afu_remove(struct cxl_afu *afu) int cxl_register_afu(struct cxl_afu *afu) { - afu->dev.class = cxl_class; + afu->dev.class = &cxl_class; return device_register(&afu->dev); } int cxl_register_adapter(struct cxl *adapter) { - adapter->dev.class = cxl_class; + adapter->dev.class = &cxl_class; /* * Future: When we support dynamically reprogramming the PSL & AFU we @@ -678,13 +679,11 @@ int __init cxl_file_init(void) pr_devel("CXL device allocated, MAJOR %i\n", MAJOR(cxl_dev)); - cxl_class = class_create("cxl"); - if (IS_ERR(cxl_class)) { + rc = class_register(&cxl_class); + if (rc) { pr_err("Unable to create CXL class\n"); - rc = PTR_ERR(cxl_class); goto err; } - cxl_class->devnode = cxl_devnode; return 0; @@ -696,5 +695,5 @@ err: void cxl_file_exit(void) { unregister_chrdev_region(cxl_dev, CXL_NUM_MINORS); - class_destroy(cxl_class); + class_unregister(&cxl_class); } diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig index 2d240bfa819f..4e61ac18cc96 100644 --- a/drivers/misc/eeprom/Kconfig +++ b/drivers/misc/eeprom/Kconfig @@ -46,20 +46,6 @@ config EEPROM_AT25 This driver can also be built as a module. If so, the module will be called at25. -config EEPROM_LEGACY - tristate "Old I2C EEPROM reader (DEPRECATED)" - depends on I2C && SYSFS - help - If you say yes here you get read-only access to the EEPROM data - available on modern memory DIMMs and Sony Vaio laptops via I2C. Such - EEPROMs could theoretically be available on other devices as well. - - This driver is deprecated and will be removed soon, please use the - better at24 driver instead. - - This driver can also be built as a module. If so, the module - will be called eeprom. - config EEPROM_MAX6875 tristate "Maxim MAX6874/5 power supply supervisor" depends on I2C diff --git a/drivers/misc/eeprom/Makefile b/drivers/misc/eeprom/Makefile index a9b4b6579b75..65794e526d5d 100644 --- a/drivers/misc/eeprom/Makefile +++ b/drivers/misc/eeprom/Makefile @@ -1,7 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_EEPROM_AT24) += at24.o obj-$(CONFIG_EEPROM_AT25) += at25.o -obj-$(CONFIG_EEPROM_LEGACY) += eeprom.o obj-$(CONFIG_EEPROM_MAX6875) += max6875.o obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o obj-$(CONFIG_EEPROM_93XX46) += eeprom_93xx46.o diff --git a/drivers/misc/eeprom/eeprom.c b/drivers/misc/eeprom/eeprom.c deleted file mode 100644 index ccb7c2f7ee2f..000000000000 --- a/drivers/misc/eeprom/eeprom.c +++ /dev/null @@ -1,214 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 1998, 1999 Frodo Looijaard <frodol@dds.nl> and - * Philip Edelbrock <phil@netroedge.com> - * Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com> - * Copyright (C) 2003 IBM Corp. - * Copyright (C) 2004 Jean Delvare <jdelvare@suse.de> - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/device.h> -#include <linux/capability.h> -#include <linux/jiffies.h> -#include <linux/i2c.h> -#include <linux/mutex.h> - -/* Addresses to scan */ -static const unsigned short normal_i2c[] = { 0x50, 0x51, 0x52, 0x53, 0x54, - 0x55, 0x56, 0x57, I2C_CLIENT_END }; - - -/* Size of EEPROM in bytes */ -#define EEPROM_SIZE 256 - -/* possible types of eeprom devices */ -enum eeprom_nature { - UNKNOWN, - VAIO, -}; - -/* Each client has this additional data */ -struct eeprom_data { - struct mutex update_lock; - u8 valid; /* bitfield, bit!=0 if slice is valid */ - unsigned long last_updated[8]; /* In jiffies, 8 slices */ - u8 data[EEPROM_SIZE]; /* Register values */ - enum eeprom_nature nature; -}; - - -static void eeprom_update_client(struct i2c_client *client, u8 slice) -{ - struct eeprom_data *data = i2c_get_clientdata(client); - int i; - - mutex_lock(&data->update_lock); - - if (!(data->valid & (1 << slice)) || - time_after(jiffies, data->last_updated[slice] + 300 * HZ)) { - dev_dbg(&client->dev, "Starting eeprom update, slice %u\n", slice); - - if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { - for (i = slice << 5; i < (slice + 1) << 5; i += 32) - if (i2c_smbus_read_i2c_block_data(client, i, - 32, data->data + i) - != 32) - goto exit; - } else { - for (i = slice << 5; i < (slice + 1) << 5; i += 2) { - int word = i2c_smbus_read_word_data(client, i); - if (word < 0) - goto exit; - data->data[i] = word & 0xff; - data->data[i + 1] = word >> 8; - } - } - data->last_updated[slice] = jiffies; - data->valid |= (1 << slice); - } -exit: - mutex_unlock(&data->update_lock); -} - -static ssize_t eeprom_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) -{ - struct i2c_client *client = kobj_to_i2c_client(kobj); - struct eeprom_data *data = i2c_get_clientdata(client); - u8 slice; - - /* Only refresh slices which contain requested bytes */ - for (slice = off >> 5; slice <= (off + count - 1) >> 5; slice++) - eeprom_update_client(client, slice); - - /* Hide Vaio private settings to regular users: - - BIOS passwords: bytes 0x00 to 0x0f - - UUID: bytes 0x10 to 0x1f - - Serial number: 0xc0 to 0xdf */ - if (data->nature == VAIO && !capable(CAP_SYS_ADMIN)) { - int i; - - for (i = 0; i < count; i++) { - if ((off + i <= 0x1f) || - (off + i >= 0xc0 && off + i <= 0xdf)) - buf[i] = 0; - else - buf[i] = data->data[off + i]; - } - } else { - memcpy(buf, &data->data[off], count); - } - - return count; -} - -static const struct bin_attribute eeprom_attr = { - .attr = { - .name = "eeprom", - .mode = S_IRUGO, - }, - .size = EEPROM_SIZE, - .read = eeprom_read, -}; - -/* Return 0 if detection is successful, -ENODEV otherwise */ -static int eeprom_detect(struct i2c_client *client, struct i2c_board_info *info) -{ - struct i2c_adapter *adapter = client->adapter; - - /* EDID EEPROMs are often 24C00 EEPROMs, which answer to all - addresses 0x50-0x57, but we only care about 0x50. So decline - attaching to addresses >= 0x51 on DDC buses */ - if (!(adapter->class & I2C_CLASS_SPD) && client->addr >= 0x51) - return -ENODEV; - - /* There are four ways we can read the EEPROM data: - (1) I2C block reads (faster, but unsupported by most adapters) - (2) Word reads (128% overhead) - (3) Consecutive byte reads (88% overhead, unsafe) - (4) Regular byte data reads (265% overhead) - The third and fourth methods are not implemented by this driver - because all known adapters support one of the first two. */ - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_WORD_DATA) - && !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) - return -ENODEV; - - strscpy(info->type, "eeprom", I2C_NAME_SIZE); - - return 0; -} - -static int eeprom_probe(struct i2c_client *client) -{ - struct i2c_adapter *adapter = client->adapter; - struct eeprom_data *data; - - data = devm_kzalloc(&client->dev, sizeof(struct eeprom_data), - GFP_KERNEL); - if (!data) - return -ENOMEM; - - memset(data->data, 0xff, EEPROM_SIZE); - i2c_set_clientdata(client, data); - mutex_init(&data->update_lock); - data->nature = UNKNOWN; - - /* Detect the Vaio nature of EEPROMs. - We use the "PCG-" or "VGN-" prefix as the signature. */ - if (client->addr == 0x57 - && i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA)) { - char name[4]; - - name[0] = i2c_smbus_read_byte_data(client, 0x80); - name[1] = i2c_smbus_read_byte_data(client, 0x81); - name[2] = i2c_smbus_read_byte_data(client, 0x82); - name[3] = i2c_smbus_read_byte_data(client, 0x83); - - if (!memcmp(name, "PCG-", 4) || !memcmp(name, "VGN-", 4)) { - dev_info(&client->dev, "Vaio EEPROM detected, " - "enabling privacy protection\n"); - data->nature = VAIO; - } - } - - /* Let the users know they are using deprecated driver */ - dev_notice(&client->dev, - "eeprom driver is deprecated, please use at24 instead\n"); - - /* create the sysfs eeprom file */ - return sysfs_create_bin_file(&client->dev.kobj, &eeprom_attr); -} - -static void eeprom_remove(struct i2c_client *client) -{ - sysfs_remove_bin_file(&client->dev.kobj, &eeprom_attr); -} - -static const struct i2c_device_id eeprom_id[] = { - { "eeprom", 0 }, - { } -}; - -static struct i2c_driver eeprom_driver = { - .driver = { - .name = "eeprom", - }, - .probe = eeprom_probe, - .remove = eeprom_remove, - .id_table = eeprom_id, - - .class = I2C_CLASS_DDC | I2C_CLASS_SPD, - .detect = eeprom_detect, - .address_list = normal_i2c, -}; - -module_i2c_driver(eeprom_driver); - -MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and " - "Philip Edelbrock <phil@netroedge.com> and " - "Greg Kroah-Hartman <greg@kroah.com>"); -MODULE_DESCRIPTION("I2C EEPROM driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/misc/eeprom/idt_89hpesx.c b/drivers/misc/eeprom/idt_89hpesx.c index 1d1f30b5c426..d807d08e2614 100644 --- a/drivers/misc/eeprom/idt_89hpesx.c +++ b/drivers/misc/eeprom/idt_89hpesx.c @@ -905,7 +905,7 @@ static ssize_t idt_dbgfs_csr_write(struct file *filep, const char __user *ubuf, { struct idt_89hpesx_dev *pdev = filep->private_data; char *colon_ch, *csraddr_str, *csrval_str; - int ret, csraddr_len; + int ret; u32 csraddr, csrval; char *buf; @@ -927,21 +927,16 @@ static ssize_t idt_dbgfs_csr_write(struct file *filep, const char __user *ubuf, * no new CSR value */ if (colon_ch != NULL) { - csraddr_len = colon_ch - buf; - csraddr_str = - kmalloc(csraddr_len + 1, GFP_KERNEL); + /* Copy the register address to the substring buffer */ + csraddr_str = kmemdup_nul(buf, colon_ch - buf, GFP_KERNEL); if (csraddr_str == NULL) { ret = -ENOMEM; goto free_buf; } - /* Copy the register address to the substring buffer */ - strncpy(csraddr_str, buf, csraddr_len); - csraddr_str[csraddr_len] = '\0'; /* Register value must follow the colon */ csrval_str = colon_ch + 1; } else /* if (str_colon == NULL) */ { csraddr_str = (char *)buf; /* Just to shut warning up */ - csraddr_len = strnlen(csraddr_str, count); csrval_str = NULL; } diff --git a/drivers/misc/ibmvmc.c b/drivers/misc/ibmvmc.c index 7739b783c2db..e5f935b5249d 100644 --- a/drivers/misc/ibmvmc.c +++ b/drivers/misc/ibmvmc.c @@ -1249,9 +1249,7 @@ static long ibmvmc_ioctl_sethmcid(struct ibmvmc_file_session *session, return -EIO; } - /* Make sure buffer is NULL terminated before trying to print it */ - memset(print_buffer, 0, HMC_ID_LEN + 1); - strncpy(print_buffer, hmc->hmc_id, HMC_ID_LEN); + strscpy(print_buffer, hmc->hmc_id, sizeof(print_buffer)); pr_info("ibmvmc: sethmcid: Set HMC ID: \"%s\"\n", print_buffer); memcpy(buffer->real_addr_local, hmc->hmc_id, HMC_ID_LEN); diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index 2e65ce6bdec7..f9bcff197615 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c @@ -257,7 +257,7 @@ out: } /** - * mei_cldev_send_vtag - me device send with vtag (write) + * mei_cldev_send_vtag - me device send with vtag (write) * * @cldev: me client device * @buf: buffer to send @@ -279,6 +279,29 @@ ssize_t mei_cldev_send_vtag(struct mei_cl_device *cldev, const u8 *buf, EXPORT_SYMBOL_GPL(mei_cldev_send_vtag); /** + * mei_cldev_send_vtag_timeout - me device send with vtag and timeout (write) + * + * @cldev: me client device + * @buf: buffer to send + * @length: buffer length + * @vtag: virtual tag + * @timeout: send timeout in milliseconds, 0 for infinite timeout + * + * Return: + * * written size in bytes + * * < 0 on error + */ + +ssize_t mei_cldev_send_vtag_timeout(struct mei_cl_device *cldev, const u8 *buf, + size_t length, u8 vtag, unsigned long timeout) +{ + struct mei_cl *cl = cldev->cl; + + return __mei_cl_send_timeout(cl, buf, length, vtag, MEI_CL_IO_TX_BLOCKING, timeout); +} +EXPORT_SYMBOL_GPL(mei_cldev_send_vtag_timeout); + +/** * mei_cldev_recv_vtag - client receive with vtag (read) * * @cldev: me client device @@ -323,7 +346,49 @@ ssize_t mei_cldev_recv_nonblock_vtag(struct mei_cl_device *cldev, u8 *buf, EXPORT_SYMBOL_GPL(mei_cldev_recv_nonblock_vtag); /** - * mei_cldev_send - me device send (write) + * mei_cldev_recv_timeout - client receive with timeout (read) + * + * @cldev: me client device + * @buf: buffer to receive + * @length: buffer length + * @timeout: send timeout in milliseconds, 0 for infinite timeout + * + * Return: + * * read size in bytes + * * < 0 on error + */ +ssize_t mei_cldev_recv_timeout(struct mei_cl_device *cldev, u8 *buf, size_t length, + unsigned long timeout) +{ + return mei_cldev_recv_vtag_timeout(cldev, buf, length, NULL, timeout); +} +EXPORT_SYMBOL_GPL(mei_cldev_recv_timeout); + +/** + * mei_cldev_recv_vtag_timeout - client receive with vtag (read) + * + * @cldev: me client device + * @buf: buffer to receive + * @length: buffer length + * @vtag: virtual tag + * @timeout: recv timeout in milliseconds, 0 for infinite timeout + * + * Return: + * * read size in bytes + * * < 0 on error + */ + +ssize_t mei_cldev_recv_vtag_timeout(struct mei_cl_device *cldev, u8 *buf, size_t length, + u8 *vtag, unsigned long timeout) +{ + struct mei_cl *cl = cldev->cl; + + return __mei_cl_recv(cl, buf, length, vtag, 0, timeout); +} +EXPORT_SYMBOL_GPL(mei_cldev_recv_vtag_timeout); + +/** + * mei_cldev_send - me device send (write) * * @cldev: me client device * @buf: buffer to send @@ -340,6 +405,25 @@ ssize_t mei_cldev_send(struct mei_cl_device *cldev, const u8 *buf, size_t length EXPORT_SYMBOL_GPL(mei_cldev_send); /** + * mei_cldev_send_timeout - me device send with timeout (write) + * + * @cldev: me client device + * @buf: buffer to send + * @length: buffer length + * @timeout: send timeout in milliseconds, 0 for infinite timeout + * + * Return: + * * written size in bytes + * * < 0 on error + */ +ssize_t mei_cldev_send_timeout(struct mei_cl_device *cldev, const u8 *buf, size_t length, + unsigned long timeout) +{ + return mei_cldev_send_vtag_timeout(cldev, buf, length, 0, timeout); +} +EXPORT_SYMBOL_GPL(mei_cldev_send_timeout); + +/** * mei_cldev_recv - client receive (read) * * @cldev: me client device @@ -1301,7 +1385,7 @@ static inline void mei_cl_bus_set_name(struct mei_cl_device *cldev) * @bus: mei device * @me_cl: me client * - * Return: allocated device structur or NULL on allocation failure + * Return: allocated device structure or NULL on allocation failure */ static struct mei_cl_device *mei_cl_bus_dev_alloc(struct mei_device *bus, struct mei_me_client *me_cl) @@ -1361,7 +1445,7 @@ static bool mei_cl_bus_dev_setup(struct mei_device *bus, * * @cldev: me client device * - * Return: 0 on success; < 0 on failre + * Return: 0 on success; < 0 on failure */ static int mei_cl_bus_dev_add(struct mei_cl_device *cldev) { diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index 5c19097266fe..9c8fc87938a7 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c @@ -48,9 +48,9 @@ struct mei_me_client *mei_me_cl_get(struct mei_me_client *me_cl) /** * mei_me_cl_release - free me client * - * Locking: called under "dev->device_lock" lock - * * @ref: me_client refcount + * + * Locking: called under "dev->device_lock" lock */ static void mei_me_cl_release(struct kref *ref) { @@ -63,9 +63,9 @@ static void mei_me_cl_release(struct kref *ref) /** * mei_me_cl_put - decrease me client refcount and free client if necessary * - * Locking: called under "dev->device_lock" lock - * * @me_cl: me client + * + * Locking: called under "dev->device_lock" lock */ void mei_me_cl_put(struct mei_me_client *me_cl) { @@ -329,10 +329,10 @@ void mei_io_cb_free(struct mei_cl_cb *cb) /** * mei_tx_cb_enqueue - queue tx callback * - * Locking: called under "dev->device_lock" lock - * * @cb: mei callback struct * @head: an instance of list to queue on + * + * Locking: called under "dev->device_lock" lock */ static inline void mei_tx_cb_enqueue(struct mei_cl_cb *cb, struct list_head *head) @@ -344,9 +344,9 @@ static inline void mei_tx_cb_enqueue(struct mei_cl_cb *cb, /** * mei_tx_cb_dequeue - dequeue tx callback * - * Locking: called under "dev->device_lock" lock - * * @cb: mei callback struct to dequeue and free + * + * Locking: called under "dev->device_lock" lock */ static inline void mei_tx_cb_dequeue(struct mei_cl_cb *cb) { @@ -359,10 +359,10 @@ static inline void mei_tx_cb_dequeue(struct mei_cl_cb *cb) /** * mei_cl_set_read_by_fp - set pending_read flag to vtag struct for given fp * - * Locking: called under "dev->device_lock" lock - * * @cl: mei client * @fp: pointer to file structure + * + * Locking: called under "dev->device_lock" lock */ static void mei_cl_set_read_by_fp(const struct mei_cl *cl, const struct file *fp) diff --git a/drivers/misc/mei/dma-ring.c b/drivers/misc/mei/dma-ring.c index ef56f849b251..651e77ef82bd 100644 --- a/drivers/misc/mei/dma-ring.c +++ b/drivers/misc/mei/dma-ring.c @@ -124,6 +124,8 @@ void mei_dma_ring_reset(struct mei_device *dev) * @buf: data buffer * @offset: offset in slots. * @n: number of slots to copy. + * + * Return: number of bytes copied */ static size_t mei_dma_copy_from(struct mei_device *dev, unsigned char *buf, u32 offset, u32 n) @@ -144,6 +146,8 @@ static size_t mei_dma_copy_from(struct mei_device *dev, unsigned char *buf, * @buf: data buffer * @offset: offset in slots. * @n: number of slots to copy. + * + * Return: number of bytes copied */ static size_t mei_dma_copy_to(struct mei_device *dev, unsigned char *buf, u32 offset, u32 n) @@ -161,7 +165,7 @@ static size_t mei_dma_copy_to(struct mei_device *dev, unsigned char *buf, /** * mei_dma_ring_read() - read data from the ring * @dev: mei device - * @buf: buffer to read into: may be NULL in case of droping the data. + * @buf: buffer to read into: may be NULL in case of dropping the data. * @len: length to read. */ void mei_dma_ring_read(struct mei_device *dev, unsigned char *buf, u32 len) diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c index 12a62a911e42..026b1f686c16 100644 --- a/drivers/misc/mei/hbm.c +++ b/drivers/misc/mei/hbm.c @@ -91,6 +91,8 @@ static int mei_cl_conn_status_to_errno(enum mei_cl_connect_status status) * @dev: mei device * @hdr: mei header * @data: payload + * + * Return: >=0 on success, <0 on error */ static inline int mei_hbm_write_message(struct mei_device *dev, struct mei_msg_hdr *hdr, @@ -111,7 +113,7 @@ void mei_hbm_idle(struct mei_device *dev) } /** - * mei_hbm_reset - reset hbm counters and book keeping data structurs + * mei_hbm_reset - reset hbm counters and book keeping data structures * * @dev: the device structure */ @@ -907,7 +909,7 @@ int mei_hbm_cl_disconnect_req(struct mei_device *dev, struct mei_cl *cl) } /** - * mei_hbm_cl_disconnect_rsp - sends disconnect respose to the FW + * mei_hbm_cl_disconnect_rsp - sends disconnect response to the FW * * @dev: the device structure * @cl: a client to disconnect from diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h index bdc65d50b945..961e5d53a27a 100644 --- a/drivers/misc/mei/hw-me-regs.h +++ b/drivers/misc/mei/hw-me-regs.h @@ -123,6 +123,9 @@ # define PCI_CFG_HFS_1_OPMODE_MSK 0xf0000 /* OP MODE Mask: SPS <= 4.0 */ # define PCI_CFG_HFS_1_OPMODE_SPS 0xf0000 /* SPS SKU : SPS <= 4.0 */ #define PCI_CFG_HFS_2 0x48 +# define PCI_CFG_HFS_2_PM_CMOFF_TO_CMX_ERROR 0x1000000 /* CMoff->CMx wake after an error */ +# define PCI_CFG_HFS_2_PM_CM_RESET_ERROR 0x5000000 /* CME reset due to exception */ +# define PCI_CFG_HFS_2_PM_EVENT_MASK 0xf000000 #define PCI_CFG_HFS_3 0x60 # define PCI_CFG_HFS_3_FW_SKU_MSK 0x00000070 # define PCI_CFG_HFS_3_FW_SKU_IGN 0x00000000 diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c index da4ef0b51954..d11a0740b47c 100644 --- a/drivers/misc/mei/hw-me.c +++ b/drivers/misc/mei/hw-me.c @@ -443,11 +443,22 @@ static void mei_gsc_pxp_check(struct mei_device *dev) struct mei_me_hw *hw = to_me_hw(dev); u32 fwsts5 = 0; - if (dev->pxp_mode == MEI_DEV_PXP_DEFAULT) + if (!kind_is_gsc(dev) && !kind_is_gscfi(dev)) return; hw->read_fws(dev, PCI_CFG_HFS_5, &fwsts5); trace_mei_pci_cfg_read(dev->dev, "PCI_CFG_HFS_5", PCI_CFG_HFS_5, fwsts5); + + if ((fwsts5 & GSC_CFG_HFS_5_BOOT_TYPE_MSK) == GSC_CFG_HFS_5_BOOT_TYPE_PXP) { + if (dev->gsc_reset_to_pxp == MEI_DEV_RESET_TO_PXP_DEFAULT) + dev->gsc_reset_to_pxp = MEI_DEV_RESET_TO_PXP_PERFORMED; + } else { + dev->gsc_reset_to_pxp = MEI_DEV_RESET_TO_PXP_DEFAULT; + } + + if (dev->pxp_mode == MEI_DEV_PXP_DEFAULT) + return; + if ((fwsts5 & GSC_CFG_HFS_5_BOOT_TYPE_MSK) == GSC_CFG_HFS_5_BOOT_TYPE_PXP) { dev_dbg(dev->dev, "pxp mode is ready 0x%08x\n", fwsts5); dev->pxp_mode = MEI_DEV_PXP_READY; @@ -483,6 +494,43 @@ static int mei_me_hw_ready_wait(struct mei_device *dev) } /** + * mei_me_check_fw_reset - check for the firmware reset error and exception conditions + * + * @dev: mei device + */ +static void mei_me_check_fw_reset(struct mei_device *dev) +{ + struct mei_fw_status fw_status; + char fw_sts_str[MEI_FW_STATUS_STR_SZ] = {0}; + int ret; + u32 fw_pm_event = 0; + + if (!dev->saved_fw_status_flag) + goto end; + + if (dev->gsc_reset_to_pxp == MEI_DEV_RESET_TO_PXP_PERFORMED) { + ret = mei_fw_status(dev, &fw_status); + if (!ret) { + fw_pm_event = fw_status.status[1] & PCI_CFG_HFS_2_PM_EVENT_MASK; + if (fw_pm_event != PCI_CFG_HFS_2_PM_CMOFF_TO_CMX_ERROR && + fw_pm_event != PCI_CFG_HFS_2_PM_CM_RESET_ERROR) + goto end; + } else { + dev_err(dev->dev, "failed to read firmware status: %d\n", ret); + } + } + + mei_fw_status2str(&dev->saved_fw_status, fw_sts_str, sizeof(fw_sts_str)); + dev_warn(dev->dev, "unexpected reset: fw_pm_event = 0x%x, dev_state = %u fw status = %s\n", + fw_pm_event, dev->saved_dev_state, fw_sts_str); + +end: + if (dev->gsc_reset_to_pxp == MEI_DEV_RESET_TO_PXP_PERFORMED) + dev->gsc_reset_to_pxp = MEI_DEV_RESET_TO_PXP_DONE; + dev->saved_fw_status_flag = false; +} + +/** * mei_me_hw_start - hw start routine * * @dev: mei device @@ -492,6 +540,8 @@ static int mei_me_hw_start(struct mei_device *dev) { int ret = mei_me_hw_ready_wait(dev); + if (kind_is_gsc(dev) || kind_is_gscfi(dev)) + mei_me_check_fw_reset(dev); if (ret) return ret; dev_dbg(dev->dev, "hw is ready\n"); @@ -1300,8 +1350,13 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id) /* check if ME wants a reset */ if (!mei_hw_is_ready(dev) && dev->dev_state != MEI_DEV_RESETTING) { - dev_warn(dev->dev, "FW not ready: resetting: dev_state = %d pxp = %d\n", - dev->dev_state, dev->pxp_mode); + if (kind_is_gsc(dev) || kind_is_gscfi(dev)) { + dev_dbg(dev->dev, "FW not ready: resetting: dev_state = %d\n", + dev->dev_state); + } else { + dev_warn(dev->dev, "FW not ready: resetting: dev_state = %d\n", + dev->dev_state); + } if (dev->dev_state == MEI_DEV_POWERING_DOWN || dev->dev_state == MEI_DEV_POWER_DOWN) mei_cl_all_disconnect(dev); @@ -1379,6 +1434,8 @@ EXPORT_SYMBOL_GPL(mei_me_irq_thread_handler); /** * mei_me_polling_thread - interrupt register polling thread * + * @_dev: mei device + * * The thread monitors the interrupt source register and calls * mei_me_irq_thread_handler() to handle the firmware * input. @@ -1388,8 +1445,6 @@ EXPORT_SYMBOL_GPL(mei_me_irq_thread_handler); * time increases yet again by MEI_POLLING_TIMEOUT_ACTIVE * up to MEI_POLLING_TIMEOUT_IDLE. * - * @_dev: mei device - * * Return: always 0 */ int mei_me_polling_thread(void *_dev) @@ -1468,12 +1523,12 @@ static const struct mei_hw_ops mei_me_hw_ops = { /** * mei_me_fw_type_nm() - check for nm sku * + * @pdev: pci device + * * Read ME FW Status register to check for the Node Manager (NM) Firmware. * The NM FW is only signaled in PCI function 0. * __Note__: Deprecated by PCH8 and newer. * - * @pdev: pci device - * * Return: true in case of NM firmware */ static bool mei_me_fw_type_nm(const struct pci_dev *pdev) @@ -1494,12 +1549,12 @@ static bool mei_me_fw_type_nm(const struct pci_dev *pdev) /** * mei_me_fw_type_sps_4() - check for sps 4.0 sku * + * @pdev: pci device + * * Read ME FW Status register to check for SPS Firmware. * The SPS FW is only signaled in the PCI function 0. * __Note__: Deprecated by SPS 5.0 and newer. * - * @pdev: pci device - * * Return: true in case of SPS firmware */ static bool mei_me_fw_type_sps_4(const struct pci_dev *pdev) @@ -1519,11 +1574,11 @@ static bool mei_me_fw_type_sps_4(const struct pci_dev *pdev) /** * mei_me_fw_type_sps_ign() - check for sps or ign sku * + * @pdev: pci device + * * Read ME FW Status register to check for SPS or IGN Firmware. * The SPS/IGN FW is only signaled in pci function 0 * - * @pdev: pci device - * * Return: true in case of SPS/IGN firmware */ static bool mei_me_fw_type_sps_ign(const struct pci_dev *pdev) diff --git a/drivers/misc/mei/hw-me.h b/drivers/misc/mei/hw-me.h index 95cf830b7c7b..204b92af6c47 100644 --- a/drivers/misc/mei/hw-me.h +++ b/drivers/misc/mei/hw-me.h @@ -102,10 +102,14 @@ static inline bool mei_me_hw_use_polling(const struct mei_me_hw *hw) * @MEI_ME_PCH12_SPS_CFG: Platform Controller Hub Gen12 5.0 and newer * servers platforms with quirk for * SPS firmware exclusion. + * @MEI_ME_PCH12_SPS_ITOUCH_CFG: Platform Controller Hub Gen12 + * client platforms (iTouch) * @MEI_ME_PCH15_CFG: Platform Controller Hub Gen15 and newer * @MEI_ME_PCH15_SPS_CFG: Platform Controller Hub Gen15 and newer * servers platforms with quirk for * SPS firmware exclusion. + * @MEI_ME_GSC_CFG: Graphics System Controller + * @MEI_ME_GSCFI_CFG: Graphics System Controller Firmware Interface * @MEI_ME_NUM_CFG: Upper Sentinel. */ enum mei_cfg_idx { diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h index e910302fcd1f..eb800a07a84b 100644 --- a/drivers/misc/mei/hw.h +++ b/drivers/misc/mei/hw.h @@ -429,7 +429,7 @@ struct mei_bus_message { } __packed; /** - * struct hbm_cl_cmd - client specific host bus command + * struct mei_hbm_cl_cmd - client specific host bus command * CONNECT, DISCONNECT, and FlOW CONTROL * * @hbm_cmd: bus message command header @@ -733,7 +733,7 @@ struct hbm_dma_setup_response { } __packed; /** - * struct mei_dma_ring_ctrl - dma ring control block + * struct hbm_dma_ring_ctrl - dma ring control block * * @hbuf_wr_idx: host circular buffer write index in slots * @reserved1: reserved for alignment @@ -806,8 +806,8 @@ struct hbm_client_dma_map_request { } __packed; /** - * struct hbm_client_dma_unmap_request - * client dma unmap request from the host to the firmware + * struct hbm_client_dma_unmap_request - client dma unmap request + * from the host to the firmware * * @hbm_cmd: bus message command header * @status: unmap status @@ -822,8 +822,8 @@ struct hbm_client_dma_unmap_request { } __packed; /** - * struct hbm_client_dma_response - * client dma unmap response from the firmware to the host + * struct hbm_client_dma_response - client dma unmap response + * from the firmware to the host * * @hbm_cmd: bus message command header * @status: command status diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c index c35e005b26be..8ef2b1df8ac7 100644 --- a/drivers/misc/mei/init.c +++ b/drivers/misc/mei/init.c @@ -89,6 +89,22 @@ void mei_cancel_work(struct mei_device *dev) } EXPORT_SYMBOL_GPL(mei_cancel_work); +static void mei_save_fw_status(struct mei_device *dev) +{ + struct mei_fw_status fw_status; + int ret; + + ret = mei_fw_status(dev, &fw_status); + if (ret) { + dev_err(dev->dev, "failed to read firmware status: %d\n", ret); + return; + } + + dev->saved_dev_state = dev->dev_state; + dev->saved_fw_status_flag = true; + memcpy(&dev->saved_fw_status, &fw_status, sizeof(fw_status)); +} + /** * mei_reset - resets host and fw. * @@ -109,8 +125,14 @@ int mei_reset(struct mei_device *dev) char fw_sts_str[MEI_FW_STATUS_STR_SZ]; mei_fw_status_str(dev, fw_sts_str, MEI_FW_STATUS_STR_SZ); - dev_warn(dev->dev, "unexpected reset: dev_state = %s fw status = %s\n", - mei_dev_state_str(state), fw_sts_str); + if (kind_is_gsc(dev) || kind_is_gscfi(dev)) { + dev_dbg(dev->dev, "unexpected reset: dev_state = %s fw status = %s\n", + mei_dev_state_str(state), fw_sts_str); + mei_save_fw_status(dev); + } else { + dev_warn(dev->dev, "unexpected reset: dev_state = %s fw status = %s\n", + mei_dev_state_str(state), fw_sts_str); + } } mei_clear_interrupts(dev); @@ -394,6 +416,7 @@ void mei_device_init(struct mei_device *dev, dev->open_handle_count = 0; dev->pxp_mode = MEI_DEV_PXP_DEFAULT; + dev->gsc_reset_to_pxp = MEI_DEV_RESET_TO_PXP_DEFAULT; /* * Reserving the first client ID diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index 0a0e984e5673..b09b79fedaba 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c @@ -72,7 +72,7 @@ static void mei_irq_discard_msg(struct mei_device *dev, struct mei_msg_hdr *hdr, discard_len = 0; } /* - * no need to check for size as it is guarantied + * no need to check for size as it is guaranteed * that length fits into rd_msg_buf */ mei_read_slots(dev, dev->rd_msg_buf, discard_len); @@ -626,9 +626,9 @@ static void mei_connect_timeout(struct mei_cl *cl) /** * mei_schedule_stall_timer - re-arm stall_timer work * - * Schedule stall timer - * * @dev: the device structure + * + * Schedule stall timer */ void mei_schedule_stall_timer(struct mei_device *dev) { diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index bb4e9eabda97..79e6f3c1341f 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -460,11 +460,11 @@ end: /** * mei_vt_support_check - check if client support vtags * - * Locking: called under "dev->device_lock" lock - * * @dev: mei_device * @uuid: client UUID * + * Locking: called under "dev->device_lock" lock + * * Return: * 0 - supported * -ENOTTY - no such client @@ -587,8 +587,8 @@ static int mei_ioctl_connect_vtag(struct file *file, } /** - * mei_ioctl_client_notify_request - - * propagate event notification request to client + * mei_ioctl_client_notify_request - propagate event notification + * request to client * * @file: pointer to file structure * @request: 0 - disable, 1 - enable diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index cdf8a2edf0b3..37d7fb15cad7 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -70,9 +70,9 @@ enum mei_dev_state { /** * enum mei_dev_pxp_mode - MEI PXP mode state * - * @MEI_DEV_PXP_DEFAULT: PCH based device, no initailization required + * @MEI_DEV_PXP_DEFAULT: PCH based device, no initialization required * @MEI_DEV_PXP_INIT: device requires initialization, send setup message to firmware - * @MEI_DEV_PXP_SETUP: device is in setup stage, waiting for firmware repsonse + * @MEI_DEV_PXP_SETUP: device is in setup stage, waiting for firmware response * @MEI_DEV_PXP_READY: device initialized */ enum mei_dev_pxp_mode { @@ -82,6 +82,19 @@ enum mei_dev_pxp_mode { MEI_DEV_PXP_READY = 3, }; +/** + * enum mei_dev_reset_to_pxp - reset to PXP mode performed + * + * @MEI_DEV_RESET_TO_PXP_DEFAULT: before reset + * @MEI_DEV_RESET_TO_PXP_PERFORMED: reset performed + * @MEI_DEV_RESET_TO_PXP_DONE: reset processed + */ +enum mei_dev_reset_to_pxp { + MEI_DEV_RESET_TO_PXP_DEFAULT = 0, + MEI_DEV_RESET_TO_PXP_PERFORMED = 1, + MEI_DEV_RESET_TO_PXP_DONE = 2, +}; + const char *mei_dev_state_str(int state); enum mei_file_transaction_states { @@ -534,6 +547,11 @@ struct mei_dev_timeouts { * * @dbgfs_dir : debugfs mei root directory * + * @saved_fw_status : saved firmware status + * @saved_dev_state : saved device state + * @saved_fw_status_flag : flag indicating that firmware status was saved + * @gsc_reset_to_pxp : state of reset to the PXP mode + * * @ops: : hw specific operations * @hw : hw specific data */ @@ -630,6 +648,11 @@ struct mei_device { struct dentry *dbgfs_dir; #endif /* CONFIG_DEBUG_FS */ + struct mei_fw_status saved_fw_status; + enum mei_dev_state saved_dev_state; + bool saved_fw_status_flag; + enum mei_dev_reset_to_pxp gsc_reset_to_pxp; + const struct mei_hw_ops *ops; char hw[] __aligned(sizeof(void *)); }; @@ -874,5 +897,29 @@ static inline ssize_t mei_fw_status_str(struct mei_device *dev, return ret; } +/** + * kind_is_gsc - checks whether the device is gsc + * + * @dev: the device structure + * + * Return: whether the device is gsc + */ +static inline bool kind_is_gsc(struct mei_device *dev) +{ + /* check kind for NULL because it may be not set, like at the fist call to hw_start */ + return dev->kind && (strcmp(dev->kind, "gsc") == 0); +} +/** + * kind_is_gscfi - checks whether the device is gscfi + * + * @dev: the device structure + * + * Return: whether the device is gscfi + */ +static inline bool kind_is_gscfi(struct mei_device *dev) +{ + /* check kind for NULL because it may be not set, like at the fist call to hw_start */ + return dev->kind && (strcmp(dev->kind, "gscfi") == 0); +} #endif diff --git a/drivers/misc/mei/pxp/mei_pxp.c b/drivers/misc/mei/pxp/mei_pxp.c index 2dcb9169e404..f77d78fa5054 100644 --- a/drivers/misc/mei/pxp/mei_pxp.c +++ b/drivers/misc/mei/pxp/mei_pxp.c @@ -11,6 +11,7 @@ * negotiation messages to ME FW command payloads and vice versa. */ +#include <linux/delay.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/mei.h> @@ -22,31 +23,70 @@ #include "mei_pxp.h" +static inline int mei_pxp_reenable(const struct device *dev, struct mei_cl_device *cldev) +{ + int ret; + + dev_warn(dev, "Trying to reset the channel...\n"); + ret = mei_cldev_disable(cldev); + if (ret < 0) + dev_warn(dev, "mei_cldev_disable failed. %d\n", ret); + /* + * Explicitly ignoring disable failure, + * enable may fix the states and succeed + */ + ret = mei_cldev_enable(cldev); + if (ret < 0) + dev_err(dev, "mei_cldev_enable failed. %d\n", ret); + return ret; +} + /** * mei_pxp_send_message() - Sends a PXP message to ME FW. * @dev: device corresponding to the mei_cl_device * @message: a message buffer to send * @size: size of the message - * Return: 0 on Success, <0 on Failure + * @timeout_ms: timeout in milliseconds, zero means wait indefinitely. + * + * Returns: 0 on Success, <0 on Failure with the following defined failures. + * -ENODEV: Client was not connected. + * Caller may attempt to try again immediately. + * -ENOMEM: Internal memory allocation failure experienced. + * Caller may sleep to allow kernel reclaim before retrying. + * -EINTR : Calling thread received a signal. Caller may choose + * to abandon with the same thread id. + * -ETIME : Request is timed out. + * Caller may attempt to try again immediately. */ static int -mei_pxp_send_message(struct device *dev, const void *message, size_t size) +mei_pxp_send_message(struct device *dev, const void *message, size_t size, unsigned long timeout_ms) { struct mei_cl_device *cldev; ssize_t byte; + int ret; if (!dev || !message) return -EINVAL; cldev = to_mei_cl_device(dev); - byte = mei_cldev_send(cldev, message, size); + byte = mei_cldev_send_timeout(cldev, message, size, timeout_ms); if (byte < 0) { dev_dbg(dev, "mei_cldev_send failed. %zd\n", byte); - return byte; + switch (byte) { + case -ENOMEM: + fallthrough; + case -ENODEV: + fallthrough; + case -ETIME: + ret = mei_pxp_reenable(dev, cldev); + if (ret) + byte = ret; + break; + } } - return 0; + return byte; } /** @@ -54,23 +94,53 @@ mei_pxp_send_message(struct device *dev, const void *message, size_t size) * @dev: device corresponding to the mei_cl_device * @buffer: a message buffer to contain the received message * @size: size of the buffer - * Return: bytes sent on Success, <0 on Failure + * @timeout_ms: timeout in milliseconds, zero means wait indefinitely. + * + * Returns: number of bytes send on Success, <0 on Failure with the following defined failures. + * -ENODEV: Client was not connected. + * Caller may attempt to try again from send immediately. + * -ENOMEM: Internal memory allocation failure experienced. + * Caller may sleep to allow kernel reclaim before retrying. + * -EINTR : Calling thread received a signal. Caller will need to repeat calling + * (with a different owning thread) to retrieve existing unclaimed response + * (and may discard it). + * -ETIME : Request is timed out. + * Caller may attempt to try again from send immediately. */ static int -mei_pxp_receive_message(struct device *dev, void *buffer, size_t size) +mei_pxp_receive_message(struct device *dev, void *buffer, size_t size, unsigned long timeout_ms) { struct mei_cl_device *cldev; ssize_t byte; + bool retry = false; + int ret; if (!dev || !buffer) return -EINVAL; cldev = to_mei_cl_device(dev); - byte = mei_cldev_recv(cldev, buffer, size); +retry: + byte = mei_cldev_recv_timeout(cldev, buffer, size, timeout_ms); if (byte < 0) { dev_dbg(dev, "mei_cldev_recv failed. %zd\n", byte); - return byte; + switch (byte) { + case -ENOMEM: + /* Retry the read when pages are reclaimed */ + msleep(20); + if (!retry) { + retry = true; + goto retry; + } + fallthrough; + case -ENODEV: + fallthrough; + case -ETIME: + ret = mei_pxp_reenable(dev, cldev); + if (ret) + byte = ret; + break; + } } return byte; diff --git a/drivers/misc/ocxl/file.c b/drivers/misc/ocxl/file.c index 6e63f060e4cc..ac69b7f361f5 100644 --- a/drivers/misc/ocxl/file.c +++ b/drivers/misc/ocxl/file.c @@ -14,7 +14,6 @@ #define OCXL_NUM_MINORS 256 /* Total to reserve */ static dev_t ocxl_dev; -static struct class *ocxl_class; static DEFINE_MUTEX(minors_idr_lock); static struct idr minors_idr; @@ -509,6 +508,16 @@ static void ocxl_file_make_invisible(struct ocxl_file_info *info) cdev_del(&info->cdev); } +static char *ocxl_devnode(const struct device *dev, umode_t *mode) +{ + return kasprintf(GFP_KERNEL, "ocxl/%s", dev_name(dev)); +} + +static const struct class ocxl_class = { + .name = "ocxl", + .devnode = ocxl_devnode, +}; + int ocxl_file_register_afu(struct ocxl_afu *afu) { int minor; @@ -529,7 +538,7 @@ int ocxl_file_register_afu(struct ocxl_afu *afu) info->dev.parent = &fn->dev; info->dev.devt = MKDEV(MAJOR(ocxl_dev), minor); - info->dev.class = ocxl_class; + info->dev.class = &ocxl_class; info->dev.release = info_release; info->afu = afu; @@ -584,11 +593,6 @@ void ocxl_file_unregister_afu(struct ocxl_afu *afu) device_unregister(&info->dev); } -static char *ocxl_devnode(const struct device *dev, umode_t *mode) -{ - return kasprintf(GFP_KERNEL, "ocxl/%s", dev_name(dev)); -} - int ocxl_file_init(void) { int rc; @@ -601,20 +605,19 @@ int ocxl_file_init(void) return rc; } - ocxl_class = class_create("ocxl"); - if (IS_ERR(ocxl_class)) { + rc = class_register(&ocxl_class); + if (rc) { pr_err("Unable to create ocxl class\n"); unregister_chrdev_region(ocxl_dev, OCXL_NUM_MINORS); - return PTR_ERR(ocxl_class); + return rc; } - ocxl_class->devnode = ocxl_devnode; return 0; } void ocxl_file_exit(void) { - class_destroy(ocxl_class); + class_unregister(&ocxl_class); unregister_chrdev_region(ocxl_dev, OCXL_NUM_MINORS); idr_destroy(&minors_idr); } diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c index 150083dab71a..af519088732d 100644 --- a/drivers/misc/pci_endpoint_test.c +++ b/drivers/misc/pci_endpoint_test.c @@ -71,6 +71,7 @@ #define PCI_DEVICE_ID_TI_AM654 0xb00c #define PCI_DEVICE_ID_TI_J7200 0xb00f #define PCI_DEVICE_ID_TI_AM64 0xb010 +#define PCI_DEVICE_ID_TI_J721S2 0xb013 #define PCI_DEVICE_ID_LS1088A 0x80c0 #define PCI_DEVICE_ID_IMX8 0x0808 @@ -1003,6 +1004,9 @@ static const struct pci_device_id pci_endpoint_test_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_AM64), .driver_data = (kernel_ulong_t)&j721e_data, }, + { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_J721S2), + .driver_data = (kernel_ulong_t)&j721e_data, + }, { } }; MODULE_DEVICE_TABLE(pci, pci_endpoint_test_tbl); diff --git a/drivers/misc/phantom.c b/drivers/misc/phantom.c index 7966a6b8b5b3..30bd7c39c261 100644 --- a/drivers/misc/phantom.c +++ b/drivers/misc/phantom.c @@ -35,9 +35,12 @@ #define PHB_NOT_OH 2 static DEFINE_MUTEX(phantom_mutex); -static struct class *phantom_class; static int phantom_major; +static const struct class phantom_class = { + .name = "phantom", +}; + struct phantom_device { unsigned int opened; void __iomem *caddr; @@ -403,7 +406,7 @@ static int phantom_probe(struct pci_dev *pdev, goto err_irq; } - if (IS_ERR(device_create(phantom_class, &pdev->dev, + if (IS_ERR(device_create(&phantom_class, &pdev->dev, MKDEV(phantom_major, minor), NULL, "phantom%u", minor))) dev_err(&pdev->dev, "can't create device\n"); @@ -436,7 +439,7 @@ static void phantom_remove(struct pci_dev *pdev) struct phantom_device *pht = pci_get_drvdata(pdev); unsigned int minor = MINOR(pht->cdev.dev); - device_destroy(phantom_class, MKDEV(phantom_major, minor)); + device_destroy(&phantom_class, MKDEV(phantom_major, minor)); cdev_del(&pht->cdev); @@ -503,13 +506,12 @@ static int __init phantom_init(void) int retval; dev_t dev; - phantom_class = class_create("phantom"); - if (IS_ERR(phantom_class)) { - retval = PTR_ERR(phantom_class); + retval = class_register(&phantom_class); + if (retval) { printk(KERN_ERR "phantom: can't register phantom class\n"); goto err; } - retval = class_create_file(phantom_class, &class_attr_version.attr); + retval = class_create_file(&phantom_class, &class_attr_version.attr); if (retval) { printk(KERN_ERR "phantom: can't create sysfs version file\n"); goto err_class; @@ -535,9 +537,9 @@ static int __init phantom_init(void) err_unchr: unregister_chrdev_region(dev, PHANTOM_MAX_MINORS); err_attr: - class_remove_file(phantom_class, &class_attr_version.attr); + class_remove_file(&phantom_class, &class_attr_version.attr); err_class: - class_destroy(phantom_class); + class_unregister(&phantom_class); err: return retval; } @@ -548,8 +550,8 @@ static void __exit phantom_exit(void) unregister_chrdev_region(MKDEV(phantom_major, 0), PHANTOM_MAX_MINORS); - class_remove_file(phantom_class, &class_attr_version.attr); - class_destroy(phantom_class); + class_remove_file(&phantom_class, &class_attr_version.attr); + class_unregister(&phantom_class); pr_debug("phantom: module successfully removed\n"); } diff --git a/drivers/misc/pvpanic/pvpanic-mmio.c b/drivers/misc/pvpanic/pvpanic-mmio.c index eb97167c03fb..9715798acce3 100644 --- a/drivers/misc/pvpanic/pvpanic-mmio.c +++ b/drivers/misc/pvpanic/pvpanic-mmio.c @@ -24,52 +24,9 @@ MODULE_AUTHOR("Hu Tao <hutao@cn.fujitsu.com>"); MODULE_DESCRIPTION("pvpanic-mmio device driver"); MODULE_LICENSE("GPL"); -static ssize_t capability_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct pvpanic_instance *pi = dev_get_drvdata(dev); - - return sysfs_emit(buf, "%x\n", pi->capability); -} -static DEVICE_ATTR_RO(capability); - -static ssize_t events_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct pvpanic_instance *pi = dev_get_drvdata(dev); - - return sysfs_emit(buf, "%x\n", pi->events); -} - -static ssize_t events_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct pvpanic_instance *pi = dev_get_drvdata(dev); - unsigned int tmp; - int err; - - err = kstrtouint(buf, 16, &tmp); - if (err) - return err; - - if ((tmp & pi->capability) != tmp) - return -EINVAL; - - pi->events = tmp; - - return count; -} -static DEVICE_ATTR_RW(events); - -static struct attribute *pvpanic_mmio_dev_attrs[] = { - &dev_attr_capability.attr, - &dev_attr_events.attr, - NULL -}; -ATTRIBUTE_GROUPS(pvpanic_mmio_dev); - static int pvpanic_mmio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct pvpanic_instance *pi; struct resource *res; void __iomem *base; @@ -92,18 +49,7 @@ static int pvpanic_mmio_probe(struct platform_device *pdev) return -EINVAL; } - pi = devm_kmalloc(dev, sizeof(*pi), GFP_KERNEL); - if (!pi) - return -ENOMEM; - - pi->base = base; - pi->capability = PVPANIC_PANICKED | PVPANIC_CRASH_LOADED; - - /* initialize capability by RDPT */ - pi->capability &= ioread8(base); - pi->events = pi->capability; - - return devm_pvpanic_probe(dev, pi); + return devm_pvpanic_probe(dev, base); } static const struct of_device_id pvpanic_mmio_match[] = { @@ -123,7 +69,7 @@ static struct platform_driver pvpanic_mmio_driver = { .name = "pvpanic-mmio", .of_match_table = pvpanic_mmio_match, .acpi_match_table = pvpanic_device_ids, - .dev_groups = pvpanic_mmio_dev_groups, + .dev_groups = pvpanic_dev_groups, }, .probe = pvpanic_mmio_probe, }; diff --git a/drivers/misc/pvpanic/pvpanic-pci.c b/drivers/misc/pvpanic/pvpanic-pci.c index 07eddb5ea30f..689af4c28c2a 100644 --- a/drivers/misc/pvpanic/pvpanic-pci.c +++ b/drivers/misc/pvpanic/pvpanic-pci.c @@ -22,51 +22,8 @@ MODULE_AUTHOR("Mihai Carabas <mihai.carabas@oracle.com>"); MODULE_DESCRIPTION("pvpanic device driver"); MODULE_LICENSE("GPL"); -static ssize_t capability_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct pvpanic_instance *pi = dev_get_drvdata(dev); - - return sysfs_emit(buf, "%x\n", pi->capability); -} -static DEVICE_ATTR_RO(capability); - -static ssize_t events_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct pvpanic_instance *pi = dev_get_drvdata(dev); - - return sysfs_emit(buf, "%x\n", pi->events); -} - -static ssize_t events_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct pvpanic_instance *pi = dev_get_drvdata(dev); - unsigned int tmp; - int err; - - err = kstrtouint(buf, 16, &tmp); - if (err) - return err; - - if ((tmp & pi->capability) != tmp) - return -EINVAL; - - pi->events = tmp; - - return count; -} -static DEVICE_ATTR_RW(events); - -static struct attribute *pvpanic_pci_dev_attrs[] = { - &dev_attr_capability.attr, - &dev_attr_events.attr, - NULL -}; -ATTRIBUTE_GROUPS(pvpanic_pci_dev); - static int pvpanic_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { - struct pvpanic_instance *pi; void __iomem *base; int ret; @@ -78,18 +35,7 @@ static int pvpanic_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e if (!base) return -ENOMEM; - pi = devm_kmalloc(&pdev->dev, sizeof(*pi), GFP_KERNEL); - if (!pi) - return -ENOMEM; - - pi->base = base; - pi->capability = PVPANIC_PANICKED | PVPANIC_CRASH_LOADED; - - /* initlize capability by RDPT */ - pi->capability &= ioread8(base); - pi->events = pi->capability; - - return devm_pvpanic_probe(&pdev->dev, pi); + return devm_pvpanic_probe(&pdev->dev, base); } static const struct pci_device_id pvpanic_pci_id_tbl[] = { @@ -103,7 +49,7 @@ static struct pci_driver pvpanic_pci_driver = { .id_table = pvpanic_pci_id_tbl, .probe = pvpanic_pci_probe, .driver = { - .dev_groups = pvpanic_pci_dev_groups, + .dev_groups = pvpanic_dev_groups, }, }; module_pci_driver(pvpanic_pci_driver); diff --git a/drivers/misc/pvpanic/pvpanic.c b/drivers/misc/pvpanic/pvpanic.c index 049a12006348..305b367e0ce3 100644 --- a/drivers/misc/pvpanic/pvpanic.c +++ b/drivers/misc/pvpanic/pvpanic.c @@ -7,6 +7,7 @@ * Copyright (C) 2021 Oracle. */ +#include <linux/device.h> #include <linux/io.h> #include <linux/kernel.h> #include <linux/kexec.h> @@ -26,6 +27,13 @@ MODULE_AUTHOR("Mihai Carabas <mihai.carabas@oracle.com>"); MODULE_DESCRIPTION("pvpanic device driver"); MODULE_LICENSE("GPL"); +struct pvpanic_instance { + void __iomem *base; + unsigned int capability; + unsigned int events; + struct list_head list; +}; + static struct list_head pvpanic_list; static spinlock_t pvpanic_lock; @@ -81,11 +89,75 @@ static void pvpanic_remove(void *param) spin_unlock(&pvpanic_lock); } -int devm_pvpanic_probe(struct device *dev, struct pvpanic_instance *pi) +static ssize_t capability_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct pvpanic_instance *pi = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%x\n", pi->capability); +} +static DEVICE_ATTR_RO(capability); + +static ssize_t events_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct pvpanic_instance *pi = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%x\n", pi->events); +} + +static ssize_t events_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct pvpanic_instance *pi = dev_get_drvdata(dev); + unsigned int tmp; + int err; + + err = kstrtouint(buf, 16, &tmp); + if (err) + return err; + + if ((tmp & pi->capability) != tmp) + return -EINVAL; + + pi->events = tmp; + + return count; +} +static DEVICE_ATTR_RW(events); + +static struct attribute *pvpanic_dev_attrs[] = { + &dev_attr_capability.attr, + &dev_attr_events.attr, + NULL +}; + +static const struct attribute_group pvpanic_dev_group = { + .attrs = pvpanic_dev_attrs, +}; + +const struct attribute_group *pvpanic_dev_groups[] = { + &pvpanic_dev_group, + NULL +}; +EXPORT_SYMBOL_GPL(pvpanic_dev_groups); + +int devm_pvpanic_probe(struct device *dev, void __iomem *base) { - if (!pi || !pi->base) + struct pvpanic_instance *pi; + + if (!base) return -EINVAL; + pi = devm_kmalloc(dev, sizeof(*pi), GFP_KERNEL); + if (!pi) + return -ENOMEM; + + pi->base = base; + pi->capability = PVPANIC_PANICKED | PVPANIC_CRASH_LOADED; + + /* initlize capability by RDPT */ + pi->capability &= ioread8(base); + pi->events = pi->capability; + spin_lock(&pvpanic_lock); list_add(&pi->list, &pvpanic_list); spin_unlock(&pvpanic_lock); diff --git a/drivers/misc/pvpanic/pvpanic.h b/drivers/misc/pvpanic/pvpanic.h index 493545951754..46ffb10438ad 100644 --- a/drivers/misc/pvpanic/pvpanic.h +++ b/drivers/misc/pvpanic/pvpanic.h @@ -8,13 +8,7 @@ #ifndef PVPANIC_H_ #define PVPANIC_H_ -struct pvpanic_instance { - void __iomem *base; - unsigned int capability; - unsigned int events; - struct list_head list; -}; - -int devm_pvpanic_probe(struct device *dev, struct pvpanic_instance *pi); +int devm_pvpanic_probe(struct device *dev, void __iomem *base); +extern const struct attribute_group *pvpanic_dev_groups[]; #endif /* PVPANIC_H_ */ diff --git a/drivers/misc/ti-st/st_core.c b/drivers/misc/ti-st/st_core.c index c1a134bd8ba7..b878431553ab 100644 --- a/drivers/misc/ti-st/st_core.c +++ b/drivers/misc/ti-st/st_core.c @@ -15,6 +15,7 @@ #include <linux/skbuff.h> #include <linux/ti_wilink_st.h> +#include <linux/netdevice.h> /* * function pointer pointing to either, @@ -429,7 +430,7 @@ static void st_int_enqueue(struct st_data_s *st_gdata, struct sk_buff *skb) case ST_LL_AWAKE_TO_ASLEEP: pr_err("ST LL is illegal state(%ld)," "purging received skb.", st_ll_getstate(st_gdata)); - kfree_skb(skb); + dev_kfree_skb_irq(skb); break; case ST_LL_ASLEEP: skb_queue_tail(&st_gdata->tx_waitq, skb); @@ -438,7 +439,7 @@ static void st_int_enqueue(struct st_data_s *st_gdata, struct sk_buff *skb) default: pr_err("ST LL is illegal state(%ld)," "purging received skb.", st_ll_getstate(st_gdata)); - kfree_skb(skb); + dev_kfree_skb_irq(skb); break; } @@ -492,7 +493,7 @@ void st_tx_wakeup(struct st_data_s *st_data) spin_unlock_irqrestore(&st_data->lock, flags); break; } - kfree_skb(skb); + dev_kfree_skb_irq(skb); spin_unlock_irqrestore(&st_data->lock, flags); } /* if wake-up is set in another context- restart sending */ diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c index fe682e0553b2..4b1be0bb6ac0 100644 --- a/drivers/misc/ti-st/st_kim.c +++ b/drivers/misc/ti-st/st_kim.c @@ -590,7 +590,7 @@ static ssize_t store_dev_name(struct device *dev, { struct kim_data_s *kim_data = dev_get_drvdata(dev); pr_debug("storing dev name >%s<", buf); - strncpy(kim_data->dev_name, buf, count); + strscpy(kim_data->dev_name, buf, sizeof(kim_data->dev_name)); pr_debug("stored dev name >%s<", kim_data->dev_name); return count; } @@ -751,7 +751,8 @@ static int kim_probe(struct platform_device *pdev) } /* copying platform data */ - strncpy(kim_gdata->dev_name, pdata->dev_name, UART_DEV_NAME_LEN); + strscpy(kim_gdata->dev_name, pdata->dev_name, + sizeof(kim_gdata->dev_name)); kim_gdata->flow_cntrl = pdata->flow_cntrl; kim_gdata->baud_rate = pdata->baud_rate; pr_info("sysfs entries created\n"); diff --git a/drivers/misc/uacce/uacce.c b/drivers/misc/uacce/uacce.c index 930c252753a0..bdc2e6fda782 100644 --- a/drivers/misc/uacce/uacce.c +++ b/drivers/misc/uacce/uacce.c @@ -7,10 +7,13 @@ #include <linux/slab.h> #include <linux/uacce.h> -static struct class *uacce_class; static dev_t uacce_devt; static DEFINE_XARRAY_ALLOC(uacce_xa); +static const struct class uacce_class = { + .name = UACCE_NAME, +}; + /* * If the parent driver or the device disappears, the queue state is invalid and * ops are not usable anymore. @@ -530,7 +533,7 @@ struct uacce_device *uacce_alloc(struct device *parent, mutex_init(&uacce->mutex); device_initialize(&uacce->dev); uacce->dev.devt = MKDEV(MAJOR(uacce_devt), uacce->dev_id); - uacce->dev.class = uacce_class; + uacce->dev.class = &uacce_class; uacce->dev.groups = uacce_dev_groups; uacce->dev.parent = uacce->parent; uacce->dev.release = uacce_release; @@ -623,13 +626,13 @@ static int __init uacce_init(void) { int ret; - uacce_class = class_create(UACCE_NAME); - if (IS_ERR(uacce_class)) - return PTR_ERR(uacce_class); + ret = class_register(&uacce_class); + if (ret) + return ret; ret = alloc_chrdev_region(&uacce_devt, 0, MINORMASK, UACCE_NAME); if (ret) - class_destroy(uacce_class); + class_unregister(&uacce_class); return ret; } @@ -637,7 +640,7 @@ static int __init uacce_init(void) static __exit void uacce_exit(void) { unregister_chrdev_region(uacce_devt, MINORMASK); - class_destroy(uacce_class); + class_unregister(&uacce_class); } subsys_initcall(uacce_init); |