diff --git a/drivers/misc/mods/mods_internal.h b/drivers/misc/mods/mods_internal.h index a2eafc31..9c640d13 100644 --- a/drivers/misc/mods/mods_internal.h +++ b/drivers/misc/mods/mods_internal.h @@ -2,7 +2,7 @@ /* * mods_internal.h - This file is part of NVIDIA MODS kernel driver. * - * Copyright (c) 2008-2020, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2008-2021, NVIDIA CORPORATION. All rights reserved. * * NVIDIA MODS kernel driver is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License, @@ -579,6 +579,12 @@ int esc_mods_query_irq_3(struct mods_client *client, #ifdef CONFIG_ARCH_TEGRA +/* bpmp uphy */ +int esc_mods_bpmp_set_pcie_state(struct mods_client *client, + struct MODS_SET_PCIE_STATE *p); +int esc_mods_bpmp_init_pcie_ep_pll(struct mods_client *client, + struct MODS_INIT_PCIE_EP_PLL *p); + /* clock */ int esc_mods_get_clock_handle(struct mods_client *client, struct MODS_GET_CLOCK_HANDLE *p); diff --git a/drivers/misc/mods/mods_krnl.c b/drivers/misc/mods/mods_krnl.c index 3a8c3f4f..4e295e8a 100644 --- a/drivers/misc/mods/mods_krnl.c +++ b/drivers/misc/mods/mods_krnl.c @@ -2,7 +2,7 @@ /* * mods_krnl.c - This file is part of NVIDIA MODS kernel driver. * - * Copyright (c) 2008-2020, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2008-2021, NVIDIA CORPORATION. All rights reserved. * * NVIDIA MODS kernel driver is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License, @@ -50,10 +50,6 @@ static unsigned int mods_krnl_poll(struct file *, poll_table *); static int mods_krnl_mmap(struct file *, struct vm_area_struct *); static long mods_krnl_ioctl(struct file *, unsigned int, unsigned long); -#if defined(CONFIG_PCI) && defined(MODS_HAS_SRIOV) -static int mods_pci_sriov_configure(struct pci_dev *dev, int numvfs); -#endif - /* character driver entry points */ static const struct file_operations mods_fops = { .owner = THIS_MODULE, @@ -120,6 +116,10 @@ static int mods_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) return 0; } +#if defined(CONFIG_PCI) && defined(MODS_HAS_SRIOV) +static int mods_pci_sriov_configure(struct pci_dev *dev, int numvfs); +#endif + struct pci_driver mods_pci_driver = { .name = DEVICE_NAME, .id_table = mods_pci_table, @@ -149,28 +149,15 @@ static u32 access_token = MODS_ACCESS_TOKEN_NONE; #if defined(CONFIG_PCI) && defined(MODS_HAS_SRIOV) static int mods_pci_sriov_configure(struct pci_dev *dev, int numvfs) { - int totalvfs; - struct en_dev_entry *dpriv; + int totalvfs; + int err = 0; LOG_ENT(); - dpriv = pci_get_drvdata(dev); - if (!dpriv) { - mods_error_printk( - "failed to enable sriov, dev %04x:%02x:%02x.%x was not enabled\n", - pci_domain_nr(dev->bus), - dev->bus->number, - PCI_SLOT(dev->devfn), - PCI_FUNC(dev->devfn)); - - LOG_EXT(); - return -EBUSY; - } - totalvfs = pci_sriov_get_totalvfs(dev); if (numvfs > 0) { - int err = pci_enable_sriov(dev, numvfs); + err = pci_enable_sriov(dev, numvfs); if (unlikely(err)) { mods_error_printk( @@ -185,8 +172,6 @@ static int mods_pci_sriov_configure(struct pci_dev *dev, int numvfs) err); numvfs = err; } else { - dpriv->num_vfs = numvfs; - mods_info_printk( "enabled sriov on dev %04x:%02x:%02x.%x %s numvfs=%d (totalvfs=%d)\n", pci_domain_nr(dev->bus), @@ -200,8 +185,8 @@ static int mods_pci_sriov_configure(struct pci_dev *dev, int numvfs) } else { pci_disable_sriov(dev); + numvfs = 0; - dpriv->num_vfs = 0; mods_info_printk( "disabled sriov on dev %04x:%02x:%02x.%x %s (totalvfs=%d)\n", @@ -213,6 +198,14 @@ static int mods_pci_sriov_configure(struct pci_dev *dev, int numvfs) totalvfs); } + /* If this function has been invoked via an ioctl, remember numvfs */ + if (!err) { + struct en_dev_entry *dpriv = pci_get_drvdata(dev); + + if (dpriv) + dpriv->num_vfs = numvfs; + } + LOG_EXT(); return numvfs; } @@ -2356,6 +2349,17 @@ static long mods_krnl_ioctl(struct file *fp, break; #endif #if defined(CONFIG_ARCH_TEGRA) + case MODS_ESC_BPMP_SET_PCIE_STATE: + MODS_IOCTL(MODS_ESC_BPMP_SET_PCIE_STATE, + esc_mods_bpmp_set_pcie_state, + MODS_SET_PCIE_STATE); + break; + + case MODS_ESC_BPMP_INIT_PCIE_EP_PLL: + MODS_IOCTL(MODS_ESC_BPMP_INIT_PCIE_EP_PLL, + esc_mods_bpmp_init_pcie_ep_pll, + MODS_INIT_PCIE_EP_PLL); + break; case MODS_ESC_FLUSH_CPU_CACHE_RANGE: MODS_IOCTL_NORETVAL(MODS_ESC_FLUSH_CPU_CACHE_RANGE, esc_mods_flush_cpu_cache_range, diff --git a/drivers/misc/mods/mods_tegraprod.c b/drivers/misc/mods/mods_tegraprod.c index a12632ab..c34bc2df 100644 --- a/drivers/misc/mods/mods_tegraprod.c +++ b/drivers/misc/mods/mods_tegraprod.c @@ -2,7 +2,7 @@ /* * mods_tegraprod.c - This file is part of NVIDIA MODS kernel driver. * - * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2017-2021, NVIDIA CORPORATION. All rights reserved. * * NVIDIA MODS kernel driver is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License, @@ -25,6 +25,8 @@ #include #include #include +#include +#include #define MAX_REG_INFO_ENTRY 400 #define MAX_IO_MAP_ENTRY 200 @@ -636,3 +638,68 @@ int esc_mods_tegra_prod_set_prod_exact( return ret; } +static int bpmp_send_uphy_message_atomic( + struct mrq_uphy_request *req, int size, + struct mrq_uphy_response *reply, + int reply_size +) +{ + unsigned long flags; + int err; + + local_irq_save(flags); + err = tegra_bpmp_send_receive_atomic(MRQ_UPHY, req, size, reply, + reply_size); + local_irq_restore(flags); + + return err; +} + +static int bpmp_send_uphy_message( + struct mrq_uphy_request *req, int size, + struct mrq_uphy_response *reply, + int reply_size +) +{ + int err; + + err = tegra_bpmp_send_receive(MRQ_UPHY, req, size, reply, reply_size); + if (err != -EAGAIN) + return err; + + /* + * in case the mail systems worker threads haven't been started yet, + * use the atomic send/receive interface. This happens because the + * clocks are initialized before the IPC mechanism. + */ + return bpmp_send_uphy_message_atomic(req, size, reply, reply_size); +} + +int esc_mods_bpmp_set_pcie_state( + struct mods_client *client, + struct MODS_SET_PCIE_STATE *p +) +{ + struct mrq_uphy_request req; + struct mrq_uphy_response resp; + + req.cmd = CMD_UPHY_PCIE_CONTROLLER_STATE; + req.controller_state.pcie_controller = p->controller; + req.controller_state.enable = p->enable; + + return bpmp_send_uphy_message(&req, sizeof(req), &resp, sizeof(resp)); +} + +int esc_mods_bpmp_init_pcie_ep_pll( + struct mods_client *client, + struct MODS_INIT_PCIE_EP_PLL *p +) +{ + struct mrq_uphy_request req; + struct mrq_uphy_response resp; + + req.cmd = CMD_UPHY_PCIE_EP_CONTROLLER_PLL_INIT; + req.ep_ctrlr_pll_init.ep_controller = p->ep_id; + + return bpmp_send_uphy_message(&req, sizeof(req), &resp, sizeof(resp)); +} diff --git a/include/uapi/misc/mods.h b/include/uapi/misc/mods.h index 6ed28684..03f8dfd7 100644 --- a/include/uapi/misc/mods.h +++ b/include/uapi/misc/mods.h @@ -2,7 +2,7 @@ /* * mods.h - This file is part of NVIDIA MODS kernel driver. * - * Copyright (c) 2008-2020, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2008-2021, NVIDIA CORPORATION. All rights reserved. * * NVIDIA MODS kernel driver is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License, @@ -418,6 +418,25 @@ struct MODS_FIND_PCI_DEVICE_2 { struct mods_pci_dev_2 pci_device; }; +/* Used by MODS_ESC_BPMP_SET_PCIE_STATE ioctl. + * + * Set PCIE state through BPMP Uphy driver + */ +struct MODS_SET_PCIE_STATE { + /* IN */ + __u32 controller; + __u32 enable; +}; + +/* Used by MODS_ESC_BPMP_INIT_PCIE_EP_PLL ioctl. + * + * Initialize PCIE EP PLL through BPMP Uphy driver + */ +struct MODS_INIT_PCIE_EP_PLL { + /* IN */ + __u32 ep_id; +}; + /* Used by legacy MODS_ESC_FIND_PCI_DEVICE ioctl */ struct MODS_FIND_PCI_DEVICE { /* IN */ @@ -1958,5 +1977,7 @@ struct MODS_IOMMU_DMA_MAP_MEMORY { #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) +#define MODS_ESC_BPMP_SET_PCIE_STATE MODSIO(W, 136, MODS_SET_PCIE_STATE) +#define MODS_ESC_BPMP_INIT_PCIE_EP_PLL MODSIO(W, 137, MODS_INIT_PCIE_EP_PLL) #endif /* _UAPI_MODS_H_ */