diff --git a/drivers/misc/mods/mods_internal.h b/drivers/misc/mods/mods_internal.h index 297ffbc1..a2eafc31 100644 --- a/drivers/misc/mods/mods_internal.h +++ b/drivers/misc/mods/mods_internal.h @@ -113,6 +113,7 @@ struct mods_client { #if defined(MODS_HAS_CONSOLE_LOCK) atomic_t console_is_locked; #endif + atomic_t last_bad_dbdf; u8 client_id; }; diff --git a/drivers/misc/mods/mods_irq.c b/drivers/misc/mods/mods_irq.c index a55b2296..80f42261 100644 --- a/drivers/misc/mods/mods_irq.c +++ b/drivers/misc/mods/mods_irq.c @@ -667,6 +667,7 @@ struct mods_client *mods_alloc_client(void) memset(client, 0, sizeof(*client)); client->client_id = idx; client->access_token = MODS_ACCESS_TOKEN_NONE; + atomic_set(&client->last_bad_dbdf, -1); cl_debug(DEBUG_IOCTL, "open client (bit mask 0x%lx)\n", diff --git a/drivers/misc/mods/mods_krnl.c b/drivers/misc/mods/mods_krnl.c index 85145f21..3a8c3f4f 100644 --- a/drivers/misc/mods/mods_krnl.c +++ b/drivers/misc/mods/mods_krnl.c @@ -1609,19 +1609,19 @@ static void sysfs_write_task(struct work_struct *w) struct mods_file_work, work); struct file *f; - mm_segment_t old_fs; LOG_ENT(); task->err = -EINVAL; - old_fs = get_fs(); - set_fs(KERNEL_DS); - f = filp_open(task->path, O_WRONLY, 0); if (IS_ERR(f)) task->err = PTR_ERR(f); else { +#ifndef MODS_HAS_KERNEL_WRITE + mm_segment_t old_fs = get_fs(); +#endif + f->f_pos = 0; #ifdef MODS_HAS_KERNEL_WRITE task->err = kernel_write(f, @@ -1629,16 +1629,18 @@ static void sysfs_write_task(struct work_struct *w) task->data_size, &f->f_pos); #else + set_fs(KERNEL_DS); + task->err = vfs_write(f, (__force const char __user *)task->data, task->data_size, &f->f_pos); + + set_fs(old_fs); #endif filp_close(f, NULL); } - set_fs(old_fs); - LOG_EXT(); } @@ -1769,6 +1771,20 @@ static int esc_mods_write_msr(struct mods_client *client, struct MODS_MSR *p) } #endif +static int esc_mods_get_driver_stats(struct mods_client *client, + struct MODS_GET_DRIVER_STATS *p) +{ + LOG_ENT(); + + memset(p, 0, sizeof(*p)); + p->version = MODS_DRIVER_STATS_VERSION; + p->num_allocs = atomic_read(&client->num_allocs); + p->num_pages = atomic_read(&client->num_pages); + + LOG_EXT(); + return 0; +} + /************** * IO control * **************/ @@ -2585,6 +2601,11 @@ static long mods_krnl_ioctl(struct file *fp, break; #endif + case MODS_ESC_MODS_GET_DRIVER_STATS: + MODS_IOCTL(MODS_ESC_MODS_GET_DRIVER_STATS, + esc_mods_get_driver_stats, MODS_GET_DRIVER_STATS); + break; + default: cl_error( "unrecognized ioctl 0x%x, dir %u, type 0x%x, nr %u, size 0x%x\n", diff --git a/drivers/misc/mods/mods_pci.c b/drivers/misc/mods/mods_pci.c index 52e15274..4012bd91 100644 --- a/drivers/misc/mods/mods_pci.c +++ b/drivers/misc/mods/mods_pci.c @@ -367,6 +367,7 @@ int esc_mods_pci_read_2(struct mods_client *client, struct MODS_PCI_READ_2 *p) { struct pci_dev *dev; int err; + int dbdf; LOG_ENT(); @@ -410,19 +411,27 @@ int esc_mods_pci_read_2(struct mods_client *client, struct MODS_PCI_READ_2 *p) p->data_size, p->data); + dbdf = (int)(((u32)p->pci_device.domain << 16) | + ((u32)(p->pci_device.bus & 0xFFU) << 8) | + (u32)(p->pci_device.device & 0xFFU)); + /* Usually one of the first reads from PCI config space occurs * at address 0 and or 2 to read PCI device vendor/id. * If this reads all Fs, the device probably fell off the bus. */ - if (p->address <= 4 && (p->data == ~0U || p->data == 0xFFFFU)) - cl_warn("pci read dev %04x:%02x:%02x.%x, addr 0x%04x, size %u, data 0x%x\n", - p->pci_device.domain, - p->pci_device.bus, - p->pci_device.device, - p->pci_device.function, - p->address, - p->data_size, - p->data); + if (p->address <= 4 && (p->data == ~0U || p->data == 0xFFFFU)) { + if (dbdf != atomic_read(&client->last_bad_dbdf)) + cl_warn("pci read dev %04x:%02x:%02x.%x, addr 0x%04x, size %u, data 0x%x\n", + p->pci_device.domain, + p->pci_device.bus, + p->pci_device.device, + p->pci_device.function, + p->address, + p->data_size, + p->data); + atomic_set(&client->last_bad_dbdf, dbdf); + } else if (dbdf == atomic_read(&client->last_bad_dbdf)) + atomic_set(&client->last_bad_dbdf, -1); pci_dev_put(dev); LOG_EXT(); diff --git a/include/uapi/misc/mods.h b/include/uapi/misc/mods.h index 2bb089b9..6ed28684 100644 --- a/include/uapi/misc/mods.h +++ b/include/uapi/misc/mods.h @@ -25,7 +25,7 @@ /* Driver version */ #define MODS_DRIVER_VERSION_MAJOR 4 -#define MODS_DRIVER_VERSION_MINOR 1 +#define MODS_DRIVER_VERSION_MINOR 2 #define MODS_DRIVER_VERSION ((MODS_DRIVER_VERSION_MAJOR << 8) | \ ((MODS_DRIVER_VERSION_MINOR / 10) << 4) | \ (MODS_DRIVER_VERSION_MINOR % 10)) @@ -1386,6 +1386,20 @@ struct MODS_SYSCTL_INT { __s64 value; }; +#define MODS_DRIVER_STATS_VERSION 1 + +/* Used by MODS_ESC_MODS_GET_DRIVER_STATS ioctl. + * + * Returns driver operation statistics. + */ +struct MODS_GET_DRIVER_STATS { + /* OUT */ + __u64 version; + __u64 num_allocs; + __u64 num_pages; + __u64 reserved[13]; +}; + #define MAX_CLOCK_HANDLE_NAME 64 /* Used by MODS_ESC_GET_CLOCK_HANDLE ioctl. @@ -1943,5 +1957,6 @@ struct MODS_IOMMU_DMA_MAP_MEMORY { #define MODS_ESC_GET_RESET_HANDLE MODSIO(WR, 132, MODS_GET_RESET_HANDLE) #define MODS_ESC_SYSCTL_WRITE_INT MODSIO(W, 133, MODS_SYSCTL_INT) #define MODS_ESC_PCI_RESET_FUNCTION MODSIO(W, 134, mods_pci_dev_2) +#define MODS_ESC_MODS_GET_DRIVER_STATS MODSIO(R, 135, MODS_GET_DRIVER_STATS) #endif /* _UAPI_MODS_H_ */