From a51241efacac8e7669bd61b1123dceddb8e35217 Mon Sep 17 00:00:00 2001 From: Chris Dragan Date: Tue, 8 Dec 2020 01:45:00 -0800 Subject: [PATCH] misc: mods: update MODS kernel driver to 4.1 Change-Id: I56377b85ff0909dba419c8e3f6df16c9302d6dc5 Signed-off-by: Chris Dragan Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2456573 Reviewed-by: svcguardwords Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Sachin Nikam Reviewed-by: mobile promotions Tested-by: mobile promotions GVS: Gerrit_Virtual_Submit --- drivers/misc/mods/mods_acpi.c | 2 +- drivers/misc/mods/mods_config.h | 8 +++ drivers/misc/mods/mods_irq.c | 2 +- drivers/misc/mods/mods_krnl.c | 103 ++++++++++++++++++++++++++------ drivers/misc/mods/mods_pci.c | 59 +++++++++++++++++- include/uapi/misc/mods.h | 7 +-- 6 files changed, 153 insertions(+), 28 deletions(-) diff --git a/drivers/misc/mods/mods_acpi.c b/drivers/misc/mods/mods_acpi.c index d2f4df4e..0d914482 100644 --- a/drivers/misc/mods/mods_acpi.c +++ b/drivers/misc/mods/mods_acpi.c @@ -336,7 +336,7 @@ static int mods_eval_acpi_method(struct mods_client *client, &output); if (ACPI_FAILURE(status)) { - cl_error("ACPI method %s failed\n", p->method_name); + cl_info("ACPI method %s failed\n", p->method_name); pci_dev_put(dev); LOG_EXT(); return -EINVAL; diff --git a/drivers/misc/mods/mods_config.h b/drivers/misc/mods/mods_config.h index 641f9747..ef08bd22 100644 --- a/drivers/misc/mods/mods_config.h +++ b/drivers/misc/mods/mods_config.h @@ -79,8 +79,16 @@ # define MODS_HAS_SET_MEMORY_HEADER 1 #endif +#if KERNEL_VERSION(4, 13, 0) <= MODS_KERNEL_VERSION +# define MODS_HAS_FLR_SUPPORT +#if KERNEL_VERSION(4, 17, 0) <= MODS_KERNEL_VERSION +# define MODS_PCIE_FLR_HAS_ERR +#endif +#endif + #if KERNEL_VERSION(4, 16, 0) > MODS_KERNEL_VERSION && defined(CONFIG_X86) # define MODS_HAS_MAP_SG_ATTRS #endif + #endif /* _MODS_CONFIG_H_ */ diff --git a/drivers/misc/mods/mods_irq.c b/drivers/misc/mods/mods_irq.c index 65b05c96..a55b2296 100644 --- a/drivers/misc/mods/mods_irq.c +++ b/drivers/misc/mods/mods_irq.c @@ -127,7 +127,7 @@ void mods_disable_device(struct mods_client *client, WARN_ON(!mutex_is_locked(&mp.mtx)); #ifdef MODS_HAS_SRIOV - if (dpriv->num_vfs) + if (dpriv && dpriv->num_vfs) pci_disable_sriov(dev); #endif diff --git a/drivers/misc/mods/mods_krnl.c b/drivers/misc/mods/mods_krnl.c index ed31e66b..d4847ac9 100644 --- a/drivers/misc/mods/mods_krnl.c +++ b/drivers/misc/mods/mods_krnl.c @@ -1310,6 +1310,11 @@ static int esc_mods_get_screen_info(struct mods_client *client, static int esc_mods_get_screen_info_2(struct mods_client *client, struct MODS_SCREEN_INFO_2 *p) { +#if defined(CONFIG_FB) + unsigned int i; + bool found = false; +#endif + mods_get_screen_info(&p->info); #if defined(VIDEO_CAPABILITY_64BIT_BASE) @@ -1318,6 +1323,42 @@ static int esc_mods_get_screen_info_2(struct mods_client *client, p->ext_lfb_base = 0; #endif +#if defined(CONFIG_FB) + if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI) + return OK; + + /* With pci=realloc on the kernel command line, GPU BAR1 can be + * reassigned after the OS console is allocated. When this + * occurs the lfb_base variable is *not* updated for an EFI + * console. The incorrect lfb_base variable will prevent other + * drivers or user space applications from identifying memory + * in use by the console and potentially using it themselves. + + * For an EFI console, pull the FB base address from the FB + * driver registered_fb data instead of screen_info + */ + for (i = 0; i < ARRAY_SIZE(registered_fb); i++) { + bool skipped = true; + + if (!registered_fb[i]) + continue; + + if (!strcmp(registered_fb[i]->fix.id, "EFI VGA") && !found) { + p->info.lfb_base = + registered_fb[i]->fix.smem_start & 0xFFFFFFFF; + p->ext_lfb_base = + registered_fb[i]->fix.smem_start >> 32; + found = true; + skipped = false; + } + + cl_info("%s fb%d '%s' @0x%llx\n", + skipped ? "skip" : "found", + i, registered_fb[i]->fix.id, + (u64)registered_fb[i]->fix.smem_start); + } +#endif + return OK; } #endif @@ -1352,6 +1393,9 @@ static int esc_mods_unlock_console(struct mods_client *client) static int esc_mods_suspend_console(struct mods_client *client) { int err = -EINVAL; +#if defined(CONFIG_FB) + unsigned int i; +#endif LOG_ENT(); @@ -1362,19 +1406,25 @@ static int esc_mods_suspend_console(struct mods_client *client) } #if defined(CONFIG_FB) - if (num_registered_fb) { - /* tell the os to block fb accesses */ - int i = 0; + /* tell the os to block fb accesses */ + for (i = 0; i < ARRAY_SIZE(registered_fb); i++) { + bool suspended = false; - for (i = 0; i < num_registered_fb; i++) { - console_lock(); - if (registered_fb[i]->state != FBINFO_STATE_SUSPENDED) { - fb_set_suspend(registered_fb[i], 1); - client->mods_fb_suspended[i] = 1; - } - console_unlock(); + if (!registered_fb[i]) + continue; + + console_lock(); + if (registered_fb[i]->state != FBINFO_STATE_SUSPENDED) { + fb_set_suspend(registered_fb[i], 1); + client->mods_fb_suspended[i] = 1; + suspended = true; } + console_unlock(); err = OK; + + if (suspended) + cl_info("suspended fb%u '%s'\n", i, + registered_fb[i]->fix.id); } #endif @@ -1387,9 +1437,14 @@ static int esc_mods_suspend_console(struct mods_client *client) do_take_over_console(&dummy_con, 0, 0, 0); console_unlock(); err = OK; + + cl_info("switched console to dummy\n"); } #endif + if (err) + cl_warn("no methods to suspend console available\n"); + atomic_set(&console_is_locked, 0); LOG_EXT(); @@ -1405,6 +1460,9 @@ static int esc_mods_resume_console(struct mods_client *client) static int mods_resume_console(struct mods_client *client) { int err = -EINVAL; +#if defined(CONFIG_FB) + unsigned int i; +#endif LOG_ENT(); @@ -1418,18 +1476,23 @@ static int mods_resume_console(struct mods_client *client) } #if defined(CONFIG_FB) - if (num_registered_fb) { - int i = 0; + for (i = 0; i < ARRAY_SIZE(registered_fb); i++) { + bool resumed = false; - for (i = 0; i < num_registered_fb; i++) { - console_lock(); - if (client->mods_fb_suspended[i]) { - fb_set_suspend(registered_fb[i], 0); - client->mods_fb_suspended[i] = 0; - } - console_unlock(); + if (!registered_fb[i]) + continue; + + console_lock(); + if (client->mods_fb_suspended[i]) { + fb_set_suspend(registered_fb[i], 0); + client->mods_fb_suspended[i] = 0; + resumed = true; } + console_unlock(); err = OK; + + if (resumed) + cl_info("resumed fb%u\n", i); } #endif @@ -1442,6 +1505,8 @@ static int mods_resume_console(struct mods_client *client) do_unbind_con_driver(vc_cons[fg_console].d->vc_sw, 0, 0, 0); console_unlock(); err = OK; + + cl_info("restored vga console\n"); } #endif atomic_set(&console_is_locked, 0); diff --git a/drivers/misc/mods/mods_pci.c b/drivers/misc/mods/mods_pci.c index 3307d33b..52e15274 100644 --- a/drivers/misc/mods/mods_pci.c +++ b/drivers/misc/mods/mods_pci.c @@ -20,8 +20,10 @@ #include "mods_internal.h" +#include #include #include +#include #if defined(MODS_HAS_DMA_OPS) #include #endif @@ -921,8 +923,11 @@ int esc_mods_pci_set_dma_mask(struct mods_client *client, int esc_mods_pci_reset_function(struct mods_client *client, struct mods_pci_dev_2 *pcidev) { +#if defined(MODS_HAS_FLR_SUPPORT) int err; struct pci_dev *dev; + u32 cap; + const struct pci_error_handlers *err_handler; LOG_ENT(); @@ -938,14 +943,62 @@ int esc_mods_pci_reset_function(struct mods_client *client, return err; } - err = pci_reset_function(dev); - if (unlikely(err)) - cl_error("pci_reset_function failed on dev %04x:%02x:%02x.%x\n", + pcie_capability_read_dword(dev, PCI_EXP_DEVCAP, &cap); + if ((dev->dev_flags & PCI_DEV_FLAGS_NO_FLR_RESET) || + !(cap & PCI_EXP_DEVCAP_FLR)) { + cl_error( + "function level reset not supported on dev %04x:%02x:%02x.%x\n", pcidev->domain, pcidev->bus, pcidev->device, pcidev->function); + err = -ENOTTY; + goto error; + } + + pci_cfg_access_lock(dev); + device_lock(&dev->dev); + + err_handler = dev->driver ? dev->driver->err_handler : NULL; + if (err_handler && err_handler->reset_prepare) + err_handler->reset_prepare(dev); + + pci_set_power_state(dev, PCI_D0); + pci_save_state(dev); + pci_write_config_word(dev, PCI_COMMAND, PCI_COMMAND_INTX_DISABLE); + +#if defined(MODS_PCIE_FLR_HAS_ERR) + err = pcie_flr(dev); + + if (unlikely(err)) + cl_error("pcie_flr failed on dev %04x:%02x:%02x.%x\n", + pcidev->domain, + pcidev->bus, + pcidev->device, + pcidev->function); +#else + pcie_flr(dev); +#endif + + if (!err) + cl_info("pcie_flr succeeded on dev %04x:%02x:%02x.%x\n", + pcidev->domain, + pcidev->bus, + pcidev->device, + pcidev->function); + + pci_restore_state(dev); + + if (err_handler && err_handler->reset_done) + err_handler->reset_done(dev); + + device_unlock(&dev->dev); + pci_cfg_access_unlock(dev); +error: pci_dev_put(dev); LOG_EXT(); return err; +#else + return -EINVAL; +#endif } diff --git a/include/uapi/misc/mods.h b/include/uapi/misc/mods.h index fd559045..2bb089b9 100644 --- a/include/uapi/misc/mods.h +++ b/include/uapi/misc/mods.h @@ -24,8 +24,8 @@ #include /* Driver version */ -#define MODS_DRIVER_VERSION_MAJOR 3 -#define MODS_DRIVER_VERSION_MINOR 99 +#define MODS_DRIVER_VERSION_MAJOR 4 +#define MODS_DRIVER_VERSION_MINOR 1 #define MODS_DRIVER_VERSION ((MODS_DRIVER_VERSION_MAJOR << 8) | \ ((MODS_DRIVER_VERSION_MINOR / 10) << 4) | \ (MODS_DRIVER_VERSION_MINOR % 10)) @@ -830,7 +830,7 @@ struct MODS_REGISTER_IRQ_3 { /* Used by ioctls: * - MODS_ESC_UNREGISTER_IRQ_2 * - MODS_ESC_REGISTER_IRQ_2 (deprectated) - * - MODS_ESC_IRQ_HANDLED_2 (deprectated) + * - MODS_ESC_IRQ_HANDLED_2 (only Tegra) * * MODS_ESC_UNREGISTER_IRQ_2 is used to unhook interrupt for the given device. */ @@ -1848,7 +1848,6 @@ struct MODS_IOMMU_DMA_MAP_MEMORY { /* Deprecated */ #define MODS_ESC_REGISTER_IRQ_2 MODSIO(W, 64, MODS_REGISTER_IRQ_2) #define MODS_ESC_UNREGISTER_IRQ_2 MODSIO(W, 65, MODS_REGISTER_IRQ_2) -/* Deprecated */ #define MODS_ESC_IRQ_HANDLED_2 MODSIO(W, 66, MODS_REGISTER_IRQ_2) /* Deprecated */ #define MODS_ESC_QUERY_IRQ_2 MODSIO(R, 67, MODS_QUERY_IRQ_2)