overall it is for the most part the same as my older version. I cleaned up some copyright things, so that it is more like the others. Also I moved the print about the max speed supported into preinit and did some other minor cleanups in the 3rd commit. Happy testing (and performance for prime offloading setups) Karol Herbst (9): pci: add gk104 variant pci: add gf106 variant pci: implement generic code for PCIe speed change pci: implement pcie speed change for tesla pci: implement pcie speed change on Fermi pci: implement PCIe speed change for kepler+ bios/perf: parse the pci speed from the bios for tesla and newer cards perf: add fields for pci speed and width and use it for the pstates perf: change pcie speed on pstate change drm/nouveau/include/nvkm/subdev/bios/perf.h | 2 + drm/nouveau/include/nvkm/subdev/clk.h | 3 + drm/nouveau/include/nvkm/subdev/pci.h | 16 ++ drm/nouveau/nvkm/engine/device/base.c | 30 ++-- drm/nouveau/nvkm/subdev/bios/perf.c | 16 ++ drm/nouveau/nvkm/subdev/clk/base.c | 6 + drm/nouveau/nvkm/subdev/pci/Kbuild | 3 + drm/nouveau/nvkm/subdev/pci/base.c | 14 ++ drm/nouveau/nvkm/subdev/pci/g84.c | 97 ++++++++++++ drm/nouveau/nvkm/subdev/pci/g94.c | 18 +++ drm/nouveau/nvkm/subdev/pci/gf100.c | 64 ++++++++ drm/nouveau/nvkm/subdev/pci/gf106.c | 48 ++++++ drm/nouveau/nvkm/subdev/pci/gk104.c | 229 ++++++++++++++++++++++++++++ drm/nouveau/nvkm/subdev/pci/pcie.c | 182 ++++++++++++++++++++++ drm/nouveau/nvkm/subdev/pci/priv.h | 33 ++++ 15 files changed, 746 insertions(+), 15 deletions(-) create mode 100644 drm/nouveau/nvkm/subdev/pci/gf106.c create mode 100644 drm/nouveau/nvkm/subdev/pci/gk104.c create mode 100644 drm/nouveau/nvkm/subdev/pci/pcie.c -- 2.6.4
v2: change email used in header v4: change Copyright information Signed-off-by: Karol Herbst <nouveau at karolherbst.de> --- drm/nouveau/include/nvkm/subdev/pci.h | 1 + drm/nouveau/nvkm/engine/device/base.c | 20 +++++++++--------- drm/nouveau/nvkm/subdev/pci/Kbuild | 1 + drm/nouveau/nvkm/subdev/pci/gk104.c | 38 +++++++++++++++++++++++++++++++++++ 4 files changed, 50 insertions(+), 10 deletions(-) create mode 100644 drm/nouveau/nvkm/subdev/pci/gk104.c diff --git a/drm/nouveau/include/nvkm/subdev/pci.h b/drm/nouveau/include/nvkm/subdev/pci.h index fee0a97..1cf5f72 100644 --- a/drm/nouveau/include/nvkm/subdev/pci.h +++ b/drm/nouveau/include/nvkm/subdev/pci.h @@ -34,4 +34,5 @@ int nv4c_pci_new(struct nvkm_device *, int, struct nvkm_pci **); int g84_pci_new(struct nvkm_device *, int, struct nvkm_pci **); int g94_pci_new(struct nvkm_device *, int, struct nvkm_pci **); int gf100_pci_new(struct nvkm_device *, int, struct nvkm_pci **); +int gk104_pci_new(struct nvkm_device *, int, struct nvkm_pci **); #endif diff --git a/drm/nouveau/nvkm/engine/device/base.c b/drm/nouveau/nvkm/engine/device/base.c index 7476ac2..e4e3ee5 100644 --- a/drm/nouveau/nvkm/engine/device/base.c +++ b/drm/nouveau/nvkm/engine/device/base.c @@ -1669,7 +1669,7 @@ nve4_chipset = { .mc = gf100_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, - .pci = g94_pci_new, + .pci = gk104_pci_new, .pmu = gk104_pmu_new, .therm = gf119_therm_new, .timer = nv41_timer_new, @@ -1706,7 +1706,7 @@ nve6_chipset = { .mc = gf100_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, - .pci = g94_pci_new, + .pci = gk104_pci_new, .pmu = gk104_pmu_new, .therm = gf119_therm_new, .timer = nv41_timer_new, @@ -1743,7 +1743,7 @@ nve7_chipset = { .mc = gf100_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, - .pci = g94_pci_new, + .pci = gk104_pci_new, .pmu = gk104_pmu_new, .therm = gf119_therm_new, .timer = nv41_timer_new, @@ -1804,7 +1804,7 @@ nvf0_chipset = { .mc = gf100_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, - .pci = g94_pci_new, + .pci = gk104_pci_new, .pmu = gk110_pmu_new, .therm = gf119_therm_new, .timer = nv41_timer_new, @@ -1840,7 +1840,7 @@ nvf1_chipset = { .mc = gf100_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, - .pci = g94_pci_new, + .pci = gk104_pci_new, .pmu = gk110_pmu_new, .therm = gf119_therm_new, .timer = nv41_timer_new, @@ -1876,7 +1876,7 @@ nv106_chipset = { .mc = gk20a_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, - .pci = g94_pci_new, + .pci = gk104_pci_new, .pmu = gk208_pmu_new, .therm = gf119_therm_new, .timer = nv41_timer_new, @@ -1912,7 +1912,7 @@ nv108_chipset = { .mc = gk20a_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, - .pci = g94_pci_new, + .pci = gk104_pci_new, .pmu = gk208_pmu_new, .therm = gf119_therm_new, .timer = nv41_timer_new, @@ -1948,7 +1948,7 @@ nv117_chipset = { .mc = gk20a_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, - .pci = g94_pci_new, + .pci = gk104_pci_new, .pmu = gm107_pmu_new, .therm = gm107_therm_new, .timer = gk20a_timer_new, @@ -1979,7 +1979,7 @@ nv124_chipset = { .mc = gk20a_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, - .pci = g94_pci_new, + .pci = gk104_pci_new, .pmu = gm107_pmu_new, .timer = gk20a_timer_new, .volt = gk104_volt_new, @@ -2010,7 +2010,7 @@ nv126_chipset = { .mc = gk20a_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, - .pci = g94_pci_new, + .pci = gk104_pci_new, .pmu = gm107_pmu_new, .timer = gk20a_timer_new, .volt = gk104_volt_new, diff --git a/drm/nouveau/nvkm/subdev/pci/Kbuild b/drm/nouveau/nvkm/subdev/pci/Kbuild index 4476ef7..1a29869 100644 --- a/drm/nouveau/nvkm/subdev/pci/Kbuild +++ b/drm/nouveau/nvkm/subdev/pci/Kbuild @@ -7,3 +7,4 @@ nvkm-y += nvkm/subdev/pci/nv4c.o nvkm-y += nvkm/subdev/pci/g84.o nvkm-y += nvkm/subdev/pci/g94.o nvkm-y += nvkm/subdev/pci/gf100.o +nvkm-y += nvkm/subdev/pci/gk104.o diff --git a/drm/nouveau/nvkm/subdev/pci/gk104.c b/drm/nouveau/nvkm/subdev/pci/gk104.c new file mode 100644 index 0000000..d0c6fef --- /dev/null +++ b/drm/nouveau/nvkm/subdev/pci/gk104.c @@ -0,0 +1,38 @@ +/* + * Copyright 2015 The Nouveau community + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Karol Herbst <nouveau at karolherbst.de> + */ +#include "priv.h" + +static const struct nvkm_pci_func +gk104_pci_func = { + .rd32 = nv40_pci_rd32, + .wr08 = nv40_pci_wr08, + .wr32 = nv40_pci_wr32, + .msi_rearm = nv40_pci_msi_rearm, +}; + +int +gk104_pci_new(struct nvkm_device *device, int index, struct nvkm_pci **ppci) +{ + return nvkm_pci_new_(&gk104_pci_func, device, index, ppci); +} -- 2.6.4
v2: change email used in header v4: change Copyright information Signed-off-by: Karol Herbst <nouveau at karolherbst.de> --- drm/nouveau/include/nvkm/subdev/pci.h | 1 + drm/nouveau/nvkm/engine/device/base.c | 10 ++++----- drm/nouveau/nvkm/subdev/pci/Kbuild | 1 + drm/nouveau/nvkm/subdev/pci/gf106.c | 38 +++++++++++++++++++++++++++++++++++ 4 files changed, 45 insertions(+), 5 deletions(-) create mode 100644 drm/nouveau/nvkm/subdev/pci/gf106.c diff --git a/drm/nouveau/include/nvkm/subdev/pci.h b/drm/nouveau/include/nvkm/subdev/pci.h index 1cf5f72..17fe7b7 100644 --- a/drm/nouveau/include/nvkm/subdev/pci.h +++ b/drm/nouveau/include/nvkm/subdev/pci.h @@ -34,5 +34,6 @@ int nv4c_pci_new(struct nvkm_device *, int, struct nvkm_pci **); int g84_pci_new(struct nvkm_device *, int, struct nvkm_pci **); int g94_pci_new(struct nvkm_device *, int, struct nvkm_pci **); int gf100_pci_new(struct nvkm_device *, int, struct nvkm_pci **); +int gf106_pci_new(struct nvkm_device *, int, struct nvkm_pci **); int gk104_pci_new(struct nvkm_device *, int, struct nvkm_pci **); #endif diff --git a/drm/nouveau/nvkm/engine/device/base.c b/drm/nouveau/nvkm/engine/device/base.c index e4e3ee5..8532810 100644 --- a/drm/nouveau/nvkm/engine/device/base.c +++ b/drm/nouveau/nvkm/engine/device/base.c @@ -1388,7 +1388,7 @@ nvc1_chipset = { .mc = gf100_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, - .pci = g94_pci_new, + .pci = gf106_pci_new, .pmu = gf100_pmu_new, .therm = gt215_therm_new, .timer = nv41_timer_new, @@ -1423,7 +1423,7 @@ nvc3_chipset = { .mc = gf100_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, - .pci = g94_pci_new, + .pci = gf106_pci_new, .pmu = gf100_pmu_new, .therm = gt215_therm_new, .timer = nv41_timer_new, @@ -1566,7 +1566,7 @@ nvcf_chipset = { .mc = gf100_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, - .pci = g94_pci_new, + .pci = gf106_pci_new, .pmu = gf100_pmu_new, .therm = gt215_therm_new, .timer = nv41_timer_new, @@ -1601,7 +1601,7 @@ nvd7_chipset = { .mc = gf100_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, - .pci = g94_pci_new, + .pci = gf106_pci_new, .therm = gf119_therm_new, .timer = nv41_timer_new, .ce[0] = gf100_ce_new, @@ -1634,7 +1634,7 @@ nvd9_chipset = { .mc = gf100_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, - .pci = g94_pci_new, + .pci = gf106_pci_new, .pmu = gf119_pmu_new, .therm = gf119_therm_new, .timer = nv41_timer_new, diff --git a/drm/nouveau/nvkm/subdev/pci/Kbuild b/drm/nouveau/nvkm/subdev/pci/Kbuild index 1a29869..724afd4 100644 --- a/drm/nouveau/nvkm/subdev/pci/Kbuild +++ b/drm/nouveau/nvkm/subdev/pci/Kbuild @@ -7,4 +7,5 @@ nvkm-y += nvkm/subdev/pci/nv4c.o nvkm-y += nvkm/subdev/pci/g84.o nvkm-y += nvkm/subdev/pci/g94.o nvkm-y += nvkm/subdev/pci/gf100.o +nvkm-y += nvkm/subdev/pci/gf106.o nvkm-y += nvkm/subdev/pci/gk104.o diff --git a/drm/nouveau/nvkm/subdev/pci/gf106.c b/drm/nouveau/nvkm/subdev/pci/gf106.c new file mode 100644 index 0000000..ad42c82 --- /dev/null +++ b/drm/nouveau/nvkm/subdev/pci/gf106.c @@ -0,0 +1,38 @@ +/* + * Copyright 2015 The Nouveau community + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Karol Herbst <nouveau at karolherbst.de> + */ +#include "priv.h" + +static const struct nvkm_pci_func +gf106_pci_func = { + .rd32 = nv40_pci_rd32, + .wr08 = nv40_pci_wr08, + .wr32 = nv40_pci_wr32, + .msi_rearm = nv40_pci_msi_rearm, +}; + +int +gf106_pci_new(struct nvkm_device *device, int index, struct nvkm_pci **ppci) +{ + return nvkm_pci_new_(&gf106_pci_func, device, index, ppci); +} -- 2.6.4
Karol Herbst
2016-Jan-01 18:58 UTC
[Nouveau] [PATCH v4 3/9] pci: implement generic code for PCIe speed change
v2: rename and group functions v4: change copyright information move printing of pcie speeds into oneinit, rename all pcie functions to nvkm_pcie_* don't try to raise the pcie version when no higher one is supported Signed-off-by: Karol Herbst <nouveau at karolherbst.de> --- drm/nouveau/include/nvkm/subdev/pci.h | 14 +++ drm/nouveau/nvkm/subdev/pci/Kbuild | 1 + drm/nouveau/nvkm/subdev/pci/base.c | 14 +++ drm/nouveau/nvkm/subdev/pci/pcie.c | 182 ++++++++++++++++++++++++++++++++++ drm/nouveau/nvkm/subdev/pci/priv.h | 16 +++ 5 files changed, 227 insertions(+) create mode 100644 drm/nouveau/nvkm/subdev/pci/pcie.c diff --git a/drm/nouveau/include/nvkm/subdev/pci.h b/drm/nouveau/include/nvkm/subdev/pci.h index 17fe7b7..ab9d5cc 100644 --- a/drm/nouveau/include/nvkm/subdev/pci.h +++ b/drm/nouveau/include/nvkm/subdev/pci.h @@ -2,6 +2,12 @@ #define __NVKM_PCI_H__ #include <core/subdev.h> +enum nvkm_pcie_speed { + NVKM_PCIE_SPEED_2_5, + NVKM_PCIE_SPEED_5_0, + NVKM_PCIE_SPEED_8_0, +}; + struct nvkm_pci { const struct nvkm_pci_func *func; struct nvkm_subdev subdev; @@ -18,6 +24,11 @@ struct nvkm_pci { bool acquired; } agp; + struct { + enum nvkm_pcie_speed last_speed; + u8 last_width; + } pcie; + bool msi; }; @@ -36,4 +47,7 @@ int g94_pci_new(struct nvkm_device *, int, struct nvkm_pci **); int gf100_pci_new(struct nvkm_device *, int, struct nvkm_pci **); int gf106_pci_new(struct nvkm_device *, int, struct nvkm_pci **); int gk104_pci_new(struct nvkm_device *, int, struct nvkm_pci **); + +/* pcie functions */ +int nvkm_pcie_set_link(struct nvkm_pci *, enum nvkm_pcie_speed, u8 width); #endif diff --git a/drm/nouveau/nvkm/subdev/pci/Kbuild b/drm/nouveau/nvkm/subdev/pci/Kbuild index 724afd4..3c2519f 100644 --- a/drm/nouveau/nvkm/subdev/pci/Kbuild +++ b/drm/nouveau/nvkm/subdev/pci/Kbuild @@ -1,5 +1,6 @@ nvkm-y += nvkm/subdev/pci/agp.o nvkm-y += nvkm/subdev/pci/base.o +nvkm-y += nvkm/subdev/pci/pcie.o nvkm-y += nvkm/subdev/pci/nv04.o nvkm-y += nvkm/subdev/pci/nv40.o nvkm-y += nvkm/subdev/pci/nv46.o diff --git a/drm/nouveau/nvkm/subdev/pci/base.c b/drm/nouveau/nvkm/subdev/pci/base.c index d671dcf..475fb6d 100644 --- a/drm/nouveau/nvkm/subdev/pci/base.c +++ b/drm/nouveau/nvkm/subdev/pci/base.c @@ -107,6 +107,15 @@ nvkm_pci_preinit(struct nvkm_subdev *subdev) } static int +nvkm_pci_oneinit(struct nvkm_subdev *subdev) +{ + struct nvkm_pci *pci = nvkm_pci(subdev); + if (pci_is_pcie(pci->pdev)) + return nvkm_pcie_oneinit(pci); + return 0; +} + +static int nvkm_pci_init(struct nvkm_subdev *subdev) { struct nvkm_pci *pci = nvkm_pci(subdev); @@ -117,6 +126,8 @@ nvkm_pci_init(struct nvkm_subdev *subdev) ret = nvkm_agp_init(pci); if (ret) return ret; + } else if (pci_is_pcie(pci->pdev)) { + nvkm_pcie_init(pci); } if (pci->func->init) @@ -143,6 +154,7 @@ nvkm_pci_dtor(struct nvkm_subdev *subdev) static const struct nvkm_subdev_func nvkm_pci_func = { .dtor = nvkm_pci_dtor, + .oneinit = nvkm_pci_oneinit, .preinit = nvkm_pci_preinit, .init = nvkm_pci_init, .fini = nvkm_pci_fini, @@ -160,6 +172,8 @@ nvkm_pci_new_(const struct nvkm_pci_func *func, struct nvkm_device *device, pci->func = func; pci->pdev = device->func->pci(device)->pdev; pci->irq = -1; + pci->pcie.last_speed = -1; + pci->pcie.last_width = -1; if (device->type == NVKM_DEVICE_AGP) nvkm_agp_ctor(pci); diff --git a/drm/nouveau/nvkm/subdev/pci/pcie.c b/drm/nouveau/nvkm/subdev/pci/pcie.c new file mode 100644 index 0000000..cbc8c1c --- /dev/null +++ b/drm/nouveau/nvkm/subdev/pci/pcie.c @@ -0,0 +1,182 @@ +/* + * Copyright 2015 The Nouveau community + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Karol Herbst <git at karolherbst.de> + */ +#include "priv.h" + +static char *pcie_speed_strings[] = { + "2.5GT/s", + "5.0GT/s", + "8.0GT/s", +}; + +static enum nvkm_pcie_speed +pci_bus_speed_to_nvkm_pcie_speed(enum pci_bus_speed speed) +{ + switch (speed) { + case PCIE_SPEED_2_5GT: + return NVKM_PCIE_SPEED_2_5; + case PCIE_SPEED_5_0GT: + return NVKM_PCIE_SPEED_5_0; + case PCIE_SPEED_8_0GT: + return NVKM_PCIE_SPEED_8_0; + default: + /* XXX 0x16 is 8_0, assume 0x17 will be 16_0 for now */ + if (speed == 0x17) + return NVKM_PCIE_SPEED_8_0; + return -1; + } +} + +static int +nvkm_pcie_get_version(struct nvkm_pci *pci) +{ + if (!pci_is_pcie(pci->pdev)) + return -ENODEV; + + if (!pci->func->pcie.version) + return -ENOSYS; + + return pci->func->pcie.version(pci); +} + +static int +nvkm_pcie_get_max_version(struct nvkm_pci *pci) +{ + if (!pci_is_pcie(pci->pdev)) + return -ENODEV; + + if (!pci->func->pcie.version_supported) + return -ENOSYS; + + return pci->func->pcie.version_supported(pci); +} + +static int +nvkm_pcie_raise_version(struct nvkm_pci *pci, int version) +{ + if (!pci_is_pcie(pci->pdev)) + return -ENODEV; + + if (!pci->func->pcie.set_version) + return -ENOSYS; + + nvkm_debug(&pci->subdev, "raising version\n"); + pci->func->pcie.set_version(pci, version); + return nvkm_pcie_get_version(pci); +} + +int +nvkm_pcie_oneinit(struct nvkm_pci *pci) +{ + if (pci->func->pcie.max_speed) + nvkm_info(&pci->subdev, "pcie max speed: %s\n", + pcie_speed_strings[pci->func->pcie.max_speed(pci)]); + return 0; +} + +int +nvkm_pcie_init(struct nvkm_pci *pci) +{ + struct nvkm_subdev *subdev = &pci->subdev; + int ret; + + if (!pci_is_pcie(pci->pdev)) + return -ENODEV; + + /* raise pcie version first */ + ret = nvkm_pcie_get_version(pci); + if (ret > 0) { + int max_version = nvkm_pcie_get_max_version(pci); + if (max_version > 0 && max_version > ret) + ret = nvkm_pcie_raise_version(pci, max_version); + + if (ret < max_version) + nvkm_error(subdev, "couldn't raise version: %i\n", ret); + } + + if (pci->func->pcie.init) + pci->func->pcie.init(pci); + + nvkm_debug(subdev, "pcie version: %i\n", nvkm_pcie_get_version(pci)); + + if (pci->pcie.last_speed != -1) + nvkm_pcie_set_link(pci, pci->pcie.last_speed, pci->pcie.last_width); + + return 0; +} + +int +nvkm_pcie_set_link(struct nvkm_pci *pci, enum nvkm_pcie_speed req_speed, + u8 req_width) +{ + struct nvkm_subdev *subdev = &pci->subdev; + enum nvkm_pcie_speed sys_cur_speed, sys_max_speed; + struct pci_bus *pbus = pci->pdev->bus; + int ret; + + if (!pci_is_pcie(pci->pdev)) + return -ENODEV; + + if (!pci->func->pcie.set_link || !pci->func->pcie.version + || !pci->func->pcie.max_speed || !pci->func->pcie.cur_speed) + return -ENOSYS; + + nvkm_debug(subdev, "pcie speed %s requested\n", + pcie_speed_strings[req_speed]); + + if (pci->func->pcie.version(pci) < 2) { + nvkm_error(subdev, "can't change link speed, " + "because current version too low\n"); + return -ENODEV; + } + + sys_cur_speed = pci->func->pcie.cur_speed(pci); + sys_max_speed = min(pci_bus_speed_to_nvkm_pcie_speed(pbus->max_bus_speed), + pci->func->pcie.max_speed(pci)); + + nvkm_debug(subdev, "bus current speed: %s max speed: %s\n", + pcie_speed_strings[sys_cur_speed], pcie_speed_strings[sys_max_speed]); + + if (req_speed > sys_max_speed) { + req_speed = sys_max_speed; + nvkm_warn(subdev, "bus or card not fast enough, dropping " + "requested speed to %s", pcie_speed_strings[req_speed]); + } + + pci->pcie.last_speed = req_speed; + pci->pcie.last_width = req_width; + + if (req_speed == sys_cur_speed) { + nvkm_debug(subdev, "requested speed matches current speed already\n"); + return req_speed; + } + + nvkm_debug(subdev, "set link to speed: %s width: x%i\n", + pcie_speed_strings[req_speed], req_width); + ret = pci->func->pcie.set_link(pci, req_speed, req_width); + + if (ret < 0) + nvkm_error(subdev, "setting link failed with ret: %i\n", ret); + + return ret; +} diff --git a/drm/nouveau/nvkm/subdev/pci/priv.h b/drm/nouveau/nvkm/subdev/pci/priv.h index cf46d38..79eb979 100644 --- a/drm/nouveau/nvkm/subdev/pci/priv.h +++ b/drm/nouveau/nvkm/subdev/pci/priv.h @@ -12,6 +12,18 @@ struct nvkm_pci_func { void (*wr08)(struct nvkm_pci *, u16 addr, u8 data); void (*wr32)(struct nvkm_pci *, u16 addr, u32 data); void (*msi_rearm)(struct nvkm_pci *); + + struct { + int (*init)(struct nvkm_pci *); + int (*set_link)(struct nvkm_pci *, enum nvkm_pcie_speed, u8); + + enum nvkm_pcie_speed (*max_speed)(struct nvkm_pci *); + enum nvkm_pcie_speed (*cur_speed)(struct nvkm_pci *); + + void (*set_version)(struct nvkm_pci *, u8); + int (*version)(struct nvkm_pci *); + int (*version_supported)(struct nvkm_pci *); + } pcie; }; u32 nv40_pci_rd32(struct nvkm_pci *, u16); @@ -22,4 +34,8 @@ void nv40_pci_msi_rearm(struct nvkm_pci *); void nv46_pci_msi_rearm(struct nvkm_pci *); void g84_pci_init(struct nvkm_pci *pci); + +/* pcie functions */ +int nvkm_pcie_oneinit(struct nvkm_pci *); +int nvkm_pcie_init(struct nvkm_pci *); #endif -- 2.6.4
Karol Herbst
2016-Jan-01 18:58 UTC
[Nouveau] [PATCH v4 4/9] pci: implement pcie speed change for tesla
v2: rename functions and simplify init v3: give g84/6 their own implementation Signed-off-by: Karol Herbst <nouveau at karolherbst.de> --- drm/nouveau/nvkm/subdev/pci/g84.c | 97 +++++++++++++++++++++++++++++++++++++ drm/nouveau/nvkm/subdev/pci/g94.c | 18 +++++++ drm/nouveau/nvkm/subdev/pci/gf100.c | 5 ++ drm/nouveau/nvkm/subdev/pci/gf106.c | 5 ++ drm/nouveau/nvkm/subdev/pci/gk104.c | 2 + drm/nouveau/nvkm/subdev/pci/priv.h | 10 ++++ 6 files changed, 137 insertions(+) diff --git a/drm/nouveau/nvkm/subdev/pci/g84.c b/drm/nouveau/nvkm/subdev/pci/g84.c index 3faa6bf..521f9c2 100644 --- a/drm/nouveau/nvkm/subdev/pci/g84.c +++ b/drm/nouveau/nvkm/subdev/pci/g84.c @@ -25,6 +25,86 @@ #include <core/pci.h> +static int +g84_pcie_version_supported(struct nvkm_pci *pci) +{ + /* g84 and g86 report wrong information about what they support */ + return 1; +} + +int +g84_pcie_version(struct nvkm_pci *pci) +{ + struct nvkm_device *device = pci->subdev.device; + return (nvkm_rd32(device, 0x00154c) & 0x1) + 1; +} + +void +g84_pcie_set_version(struct nvkm_pci *pci, u8 ver) +{ + struct nvkm_device *device = pci->subdev.device; + nvkm_mask(device, 0x00154c, 0x1, (ver >= 2 ? 0x1 : 0x0)); +} + +static void +g84_pcie_set_cap_speed(struct nvkm_pci *pci, bool full_speed) +{ + struct nvkm_device *device = pci->subdev.device; + nvkm_mask(device, 0x00154c, 0x80, full_speed ? 0x80 : 0x0); +} + +enum nvkm_pcie_speed +g84_pcie_cur_speed(struct nvkm_pci *pci) +{ + u32 reg_v = nvkm_pci_rd32(pci, 0x88) & 0x30000; + switch (reg_v) { + case 0x30000: + return NVKM_PCIE_SPEED_8_0; + case 0x20000: + return NVKM_PCIE_SPEED_5_0; + case 0x10000: + default: + return NVKM_PCIE_SPEED_2_5; + } +} + +enum nvkm_pcie_speed +g84_pcie_max_speed(struct nvkm_pci *pci) +{ + u32 reg_v = nvkm_pci_rd32(pci, 0x460) & 0x3300; + if (reg_v == 0x2200) + return NVKM_PCIE_SPEED_5_0; + return NVKM_PCIE_SPEED_2_5; +} + +void +g84_pcie_set_link_speed(struct nvkm_pci *pci, enum nvkm_pcie_speed speed) +{ + u32 mask_value; + + if (speed == NVKM_PCIE_SPEED_5_0) + mask_value = 0x20; + else + mask_value = 0x10; + + nvkm_pci_mask(pci, 0x460, 0x30, mask_value); + nvkm_pci_mask(pci, 0x460, 0x1, 0x1); +} + +int +g84_pcie_set_link(struct nvkm_pci *pci, enum nvkm_pcie_speed req_speed, + u8 req_width) +{ + if (req_speed == NVKM_PCIE_SPEED_5_0) + g84_pcie_set_cap_speed(pci, true); + else + g84_pcie_set_cap_speed(pci, false); + + g84_pcie_set_link_speed(pci, req_speed); + + return 0; +} + void g84_pci_init(struct nvkm_pci *pci) { @@ -48,6 +128,13 @@ g84_pci_init(struct nvkm_pci *pci) nvkm_pci_mask(pci, 0x041c, 0x00000060, 0x00000000); } +int +g84_pcie_init(struct nvkm_pci *pci) +{ + g84_pcie_set_cap_speed(pci, g84_pcie_cur_speed(pci) == NVKM_PCIE_SPEED_5_0); + return 0; +} + static const struct nvkm_pci_func g84_pci_func = { .init = g84_pci_init, @@ -55,6 +142,16 @@ g84_pci_func = { .wr08 = nv40_pci_wr08, .wr32 = nv40_pci_wr32, .msi_rearm = nv46_pci_msi_rearm, + + .pcie.init = g84_pcie_init, + .pcie.set_link = g84_pcie_set_link, + + .pcie.max_speed = g84_pcie_max_speed, + .pcie.cur_speed = g84_pcie_cur_speed, + + .pcie.set_version = g84_pcie_set_version, + .pcie.version = g84_pcie_version, + .pcie.version_supported = g84_pcie_version_supported, }; int diff --git a/drm/nouveau/nvkm/subdev/pci/g94.c b/drm/nouveau/nvkm/subdev/pci/g94.c index cd311ee..4344412 100644 --- a/drm/nouveau/nvkm/subdev/pci/g94.c +++ b/drm/nouveau/nvkm/subdev/pci/g94.c @@ -23,6 +23,14 @@ */ #include "priv.h" +int +g94_pcie_version_supported(struct nvkm_pci *pci) +{ + if ((nvkm_pci_rd32(pci, 0x460) & 0x200) == 0x200) + return 2; + return 1; +} + static const struct nvkm_pci_func g94_pci_func = { .init = g84_pci_init, @@ -30,6 +38,16 @@ g94_pci_func = { .wr08 = nv40_pci_wr08, .wr32 = nv40_pci_wr32, .msi_rearm = nv40_pci_msi_rearm, + + .pcie.init = g84_pcie_init, + .pcie.set_link = g84_pcie_set_link, + + .pcie.max_speed = g84_pcie_max_speed, + .pcie.cur_speed = g84_pcie_cur_speed, + + .pcie.set_version = g84_pcie_set_version, + .pcie.version = g84_pcie_version, + .pcie.version_supported = g94_pcie_version_supported, }; int diff --git a/drm/nouveau/nvkm/subdev/pci/gf100.c b/drm/nouveau/nvkm/subdev/pci/gf100.c index 25e1ae7..5e57c0b 100644 --- a/drm/nouveau/nvkm/subdev/pci/gf100.c +++ b/drm/nouveau/nvkm/subdev/pci/gf100.c @@ -36,6 +36,11 @@ gf100_pci_func = { .wr08 = nv40_pci_wr08, .wr32 = nv40_pci_wr32, .msi_rearm = gf100_pci_msi_rearm, + + .pcie.max_speed = g84_pcie_max_speed, + .pcie.cur_speed = g84_pcie_cur_speed, + + .pcie.version_supported = g94_pcie_version_supported, }; int diff --git a/drm/nouveau/nvkm/subdev/pci/gf106.c b/drm/nouveau/nvkm/subdev/pci/gf106.c index ad42c82..8ee197a 100644 --- a/drm/nouveau/nvkm/subdev/pci/gf106.c +++ b/drm/nouveau/nvkm/subdev/pci/gf106.c @@ -29,6 +29,11 @@ gf106_pci_func = { .wr08 = nv40_pci_wr08, .wr32 = nv40_pci_wr32, .msi_rearm = nv40_pci_msi_rearm, + + .pcie.max_speed = g84_pcie_max_speed, + .pcie.cur_speed = g84_pcie_cur_speed, + + .pcie.version_supported = g94_pcie_version_supported, }; int diff --git a/drm/nouveau/nvkm/subdev/pci/gk104.c b/drm/nouveau/nvkm/subdev/pci/gk104.c index d0c6fef..f24fdd8 100644 --- a/drm/nouveau/nvkm/subdev/pci/gk104.c +++ b/drm/nouveau/nvkm/subdev/pci/gk104.c @@ -29,6 +29,8 @@ gk104_pci_func = { .wr08 = nv40_pci_wr08, .wr32 = nv40_pci_wr32, .msi_rearm = nv40_pci_msi_rearm, + + .pcie.cur_speed = g84_pcie_cur_speed, }; int diff --git a/drm/nouveau/nvkm/subdev/pci/priv.h b/drm/nouveau/nvkm/subdev/pci/priv.h index 79eb979..8c389a6 100644 --- a/drm/nouveau/nvkm/subdev/pci/priv.h +++ b/drm/nouveau/nvkm/subdev/pci/priv.h @@ -36,6 +36,16 @@ void nv46_pci_msi_rearm(struct nvkm_pci *); void g84_pci_init(struct nvkm_pci *pci); /* pcie functions */ +void g84_pcie_set_version(struct nvkm_pci *, u8); +int g84_pcie_version(struct nvkm_pci *); +void g84_pcie_set_link_speed(struct nvkm_pci *, enum nvkm_pcie_speed); +enum nvkm_pcie_speed g84_pcie_cur_speed(struct nvkm_pci *); +enum nvkm_pcie_speed g84_pcie_max_speed(struct nvkm_pci *); +int g84_pcie_init(struct nvkm_pci *); +int g84_pcie_set_link(struct nvkm_pci *, enum nvkm_pcie_speed, u8); + +int g94_pcie_version_supported(struct nvkm_pci *); + int nvkm_pcie_oneinit(struct nvkm_pci *); int nvkm_pcie_init(struct nvkm_pci *); #endif -- 2.6.4
Karol Herbst
2016-Jan-01 18:58 UTC
[Nouveau] [PATCH v4 5/9] pci: implement pcie speed change on Fermi
v2: rename functions and simplify code a little Signed-off-by: Karol Herbst <nouveau at karolherbst.de> --- drm/nouveau/nvkm/subdev/pci/gf100.c | 59 +++++++++++++++++++++++++++++++++++++ drm/nouveau/nvkm/subdev/pci/gf106.c | 5 ++++ drm/nouveau/nvkm/subdev/pci/gk104.c | 3 ++ drm/nouveau/nvkm/subdev/pci/priv.h | 7 +++++ 4 files changed, 74 insertions(+) diff --git a/drm/nouveau/nvkm/subdev/pci/gf100.c b/drm/nouveau/nvkm/subdev/pci/gf100.c index 5e57c0b..cfc866e 100644 --- a/drm/nouveau/nvkm/subdev/pci/gf100.c +++ b/drm/nouveau/nvkm/subdev/pci/gf100.c @@ -29,6 +29,60 @@ gf100_pci_msi_rearm(struct nvkm_pci *pci) nvkm_pci_wr08(pci, 0x0704, 0xff); } +void +gf100_pcie_set_version(struct nvkm_pci *pci, u8 ver) +{ + struct nvkm_device *device = pci->subdev.device; + + if (ver > 1) + ver = 1; + else + ver = 0; + + nvkm_mask(device, 0x02241c, 0x1, ver); +} + +int +gf100_pcie_version(struct nvkm_pci *pci) +{ + struct nvkm_device *device = pci->subdev.device; + return (nvkm_rd32(device, 0x02241c) & 0x1) + 1; +} + +void +gf100_pcie_set_cap_speed(struct nvkm_pci *pci, bool full_speed) +{ + struct nvkm_device *device = pci->subdev.device; + nvkm_mask(device, 0x02241c, 0x80, full_speed ? 0x80 : 0x0); +} + +int +gf100_pcie_cap_speed(struct nvkm_pci *pci) +{ + struct nvkm_device *device = pci->subdev.device; + u8 punits_pci_cap_speed = nvkm_rd32(device, 0x02241c) & 0x80; + if (punits_pci_cap_speed == 0x80) + return 1; + return 0; +} + +int +gf100_pcie_init(struct nvkm_pci *pci) +{ + gf100_pcie_set_cap_speed(pci, + g84_pcie_cur_speed(pci) == NVKM_PCIE_SPEED_5_0); + return 0; +} + +int +gf100_pcie_set_link(struct nvkm_pci *pci, enum nvkm_pcie_speed req_speed, + u8 req_width) +{ + gf100_pcie_set_cap_speed(pci, req_speed == NVKM_PCIE_SPEED_5_0); + g84_pcie_set_link_speed(pci, req_speed); + return 0; +} + static const struct nvkm_pci_func gf100_pci_func = { .init = g84_pci_init, @@ -37,9 +91,14 @@ gf100_pci_func = { .wr32 = nv40_pci_wr32, .msi_rearm = gf100_pci_msi_rearm, + .pcie.init = gf100_pcie_init, + .pcie.set_link = gf100_pcie_set_link, + .pcie.max_speed = g84_pcie_max_speed, .pcie.cur_speed = g84_pcie_cur_speed, + .pcie.set_version = gf100_pcie_set_version, + .pcie.version = gf100_pcie_version, .pcie.version_supported = g94_pcie_version_supported, }; diff --git a/drm/nouveau/nvkm/subdev/pci/gf106.c b/drm/nouveau/nvkm/subdev/pci/gf106.c index 8ee197a..fbbddab 100644 --- a/drm/nouveau/nvkm/subdev/pci/gf106.c +++ b/drm/nouveau/nvkm/subdev/pci/gf106.c @@ -30,9 +30,14 @@ gf106_pci_func = { .wr32 = nv40_pci_wr32, .msi_rearm = nv40_pci_msi_rearm, + .pcie.init = gf100_pcie_init, + .pcie.set_link = gf100_pcie_set_link, + .pcie.max_speed = g84_pcie_max_speed, .pcie.cur_speed = g84_pcie_cur_speed, + .pcie.set_version = gf100_pcie_set_version, + .pcie.version = gf100_pcie_version, .pcie.version_supported = g94_pcie_version_supported, }; diff --git a/drm/nouveau/nvkm/subdev/pci/gk104.c b/drm/nouveau/nvkm/subdev/pci/gk104.c index f24fdd8..47c4736 100644 --- a/drm/nouveau/nvkm/subdev/pci/gk104.c +++ b/drm/nouveau/nvkm/subdev/pci/gk104.c @@ -31,6 +31,9 @@ gk104_pci_func = { .msi_rearm = nv40_pci_msi_rearm, .pcie.cur_speed = g84_pcie_cur_speed, + + .pcie.set_version = gf100_pcie_set_version, + .pcie.version = gf100_pcie_version, }; int diff --git a/drm/nouveau/nvkm/subdev/pci/priv.h b/drm/nouveau/nvkm/subdev/pci/priv.h index 8c389a6..23de318 100644 --- a/drm/nouveau/nvkm/subdev/pci/priv.h +++ b/drm/nouveau/nvkm/subdev/pci/priv.h @@ -46,6 +46,13 @@ int g84_pcie_set_link(struct nvkm_pci *, enum nvkm_pcie_speed, u8); int g94_pcie_version_supported(struct nvkm_pci *); +void gf100_pcie_set_version(struct nvkm_pci *, u8); +int gf100_pcie_version(struct nvkm_pci *); +void gf100_pcie_set_cap_speed(struct nvkm_pci *, bool); +int gf100_pcie_cap_speed(struct nvkm_pci *); +int gf100_pcie_init(struct nvkm_pci *); +int gf100_pcie_set_link(struct nvkm_pci *, enum nvkm_pcie_speed, u8); + int nvkm_pcie_oneinit(struct nvkm_pci *); int nvkm_pcie_init(struct nvkm_pci *); #endif -- 2.6.4
Karol Herbst
2016-Jan-01 18:58 UTC
[Nouveau] [PATCH v4 6/9] pci: implement PCIe speed change for kepler+
v2: rename functions v3: remove pcie2 accessors Signed-off-by: Karol Herbst <nouveau at karolherbst.de> --- drm/nouveau/nvkm/subdev/pci/gk104.c | 186 ++++++++++++++++++++++++++++++++++++ 1 file changed, 186 insertions(+) diff --git a/drm/nouveau/nvkm/subdev/pci/gk104.c b/drm/nouveau/nvkm/subdev/pci/gk104.c index 47c4736..e88817c 100644 --- a/drm/nouveau/nvkm/subdev/pci/gk104.c +++ b/drm/nouveau/nvkm/subdev/pci/gk104.c @@ -23,6 +23,187 @@ */ #include "priv.h" +static int +gk104_pcie_version_supported(struct nvkm_pci *pci) +{ + return (nvkm_rd32(pci->subdev.device, 0x8c1c0) & 0x4) == 0x4 ? 2 : 1; +} + +static void +gk104_pcie_set_cap_speed(struct nvkm_pci *pci, enum nvkm_pcie_speed speed) +{ + struct nvkm_device *device = pci->subdev.device; + + switch (speed) { + case NVKM_PCIE_SPEED_2_5: + gf100_pcie_set_cap_speed(pci, false); + nvkm_mask(device, 0x8c1c0, 0x30000, 0x10000); + break; + case NVKM_PCIE_SPEED_5_0: + gf100_pcie_set_cap_speed(pci, true); + nvkm_mask(device, 0x8c1c0, 0x30000, 0x20000); + break; + case NVKM_PCIE_SPEED_8_0: + gf100_pcie_set_cap_speed(pci, true); + nvkm_mask(device, 0x8c1c0, 0x30000, 0x30000); + break; + } +} + +static enum nvkm_pcie_speed +gk104_pcie_cap_speed(struct nvkm_pci *pci) +{ + int speed = gf100_pcie_cap_speed(pci); + if (speed < 0) + return speed; + + if (speed == 0) + return NVKM_PCIE_SPEED_2_5; + + if (speed >= 1) { + int speed2 = nvkm_rd32(pci->subdev.device, 0x8c1c0) & 0x30000; + switch (speed2) { + case 0x00000: + case 0x10000: + return NVKM_PCIE_SPEED_2_5; + case 0x20000: + return NVKM_PCIE_SPEED_5_0; + case 0x30000: + return NVKM_PCIE_SPEED_8_0; + } + } + return -EINVAL; +} + +static void +gk104_pcie_set_lnkctl_speed(struct nvkm_pci *pci, enum nvkm_pcie_speed speed) +{ + u8 reg_v = 0; + switch (speed) { + case NVKM_PCIE_SPEED_2_5: + reg_v = 1; + break; + case NVKM_PCIE_SPEED_5_0: + reg_v = 2; + break; + case NVKM_PCIE_SPEED_8_0: + reg_v = 3; + break; + } + nvkm_pci_mask(pci, 0xa8, 0x3, reg_v); +} + +static enum nvkm_pcie_speed +gk104_pcie_lnkctl_speed(struct nvkm_pci *pci) +{ + u8 reg_v = nvkm_pci_rd32(pci, 0xa8) & 0x3; + switch (reg_v) { + case 0: + case 1: + return NVKM_PCIE_SPEED_2_5; + case 2: + return NVKM_PCIE_SPEED_5_0; + case 3: + return NVKM_PCIE_SPEED_8_0; + } + return -1; +} + +static enum nvkm_pcie_speed +gk104_pcie_max_speed(struct nvkm_pci *pci) +{ + u32 max_speed = nvkm_rd32(pci->subdev.device, 0x8c1c0) & 0x300000; + switch (max_speed) { + case 0x000000: + return NVKM_PCIE_SPEED_8_0; + case 0x100000: + return NVKM_PCIE_SPEED_5_0; + case 0x200000: + return NVKM_PCIE_SPEED_2_5; + } + return NVKM_PCIE_SPEED_2_5; +} + +static void +gk104_pcie_set_link_speed(struct nvkm_pci *pci, enum nvkm_pcie_speed speed) +{ + struct nvkm_device *device = pci->subdev.device; + u32 mask_value; + + switch (speed) { + default: + case NVKM_PCIE_SPEED_2_5: + mask_value = 0x80000; + break; + case NVKM_PCIE_SPEED_5_0: + mask_value = 0x40000; + break; + case NVKM_PCIE_SPEED_8_0: + mask_value = 0x00000; + break; + } + nvkm_mask(device, 0x8c040, 0xc0000, mask_value); + nvkm_mask(device, 0x8c040, 0x1, 0x1); +} + +static int +gk104_pcie_init(struct nvkm_pci * pci) +{ + if (!pci_is_pcie(pci->pdev)) + return -ENODEV; + + if (gf100_pcie_version(pci) > 1) { + enum nvkm_pcie_speed + lnkctl_speed = gk104_pcie_lnkctl_speed(pci), + max_speed = gk104_pcie_max_speed(pci), + cap_speed = gk104_pcie_cap_speed(pci); + + if (cap_speed != max_speed) { + nvkm_debug(&pci->subdev, "adjusting cap speed to max speed\n"); + gk104_pcie_set_cap_speed(pci, max_speed); + cap_speed = gk104_pcie_cap_speed(pci); + if (cap_speed != max_speed) + nvkm_error(&pci->subdev, "couldn't adjust cap speed\n"); + } + + if (lnkctl_speed != max_speed) { + nvkm_debug(&pci->subdev, + "adjusting link control speed to max speed\n"); + gk104_pcie_set_lnkctl_speed(pci, max_speed); + lnkctl_speed = gk104_pcie_lnkctl_speed(pci); + if (lnkctl_speed != max_speed) + nvkm_error(&pci->subdev, + "couldn't adjust link control speed\n"); + } + } + return 0; +} + +static int +gk104_pcie_set_link(struct nvkm_pci *pci, enum nvkm_pcie_speed req_speed, + u8 req_width) +{ + enum nvkm_pcie_speed + lnk_ctl_speed = gk104_pcie_lnkctl_speed(pci), + lnk_cap_speed = gk104_pcie_cap_speed(pci); + + if (req_speed > lnk_cap_speed) { + req_speed = lnk_cap_speed; + nvkm_warn(&pci->subdev, "dropping requested PCIe speed due to low" + " cap speed\n"); + } + + if (req_speed > lnk_ctl_speed) { + req_speed = lnk_ctl_speed; + nvkm_warn(&pci->subdev, "dropping requested PCIe speed due to low" + " control speed\n"); + } + + gk104_pcie_set_link_speed(pci, req_speed); + return 0; +} + + static const struct nvkm_pci_func gk104_pci_func = { .rd32 = nv40_pci_rd32, @@ -30,10 +211,15 @@ gk104_pci_func = { .wr32 = nv40_pci_wr32, .msi_rearm = nv40_pci_msi_rearm, + .pcie.init = gk104_pcie_init, + .pcie.set_link = gk104_pcie_set_link, + + .pcie.max_speed = gk104_pcie_max_speed, .pcie.cur_speed = g84_pcie_cur_speed, .pcie.set_version = gf100_pcie_set_version, .pcie.version = gf100_pcie_version, + .pcie.version_supported = gk104_pcie_version_supported, }; int -- 2.6.4
Karol Herbst
2016-Jan-01 18:58 UTC
[Nouveau] [PATCH v4 7/9] bios/perf: parse the pci speed from the bios for tesla and newer cards
Signed-off-by: Karol Herbst <nouveau at karolherbst.de> --- drm/nouveau/include/nvkm/subdev/bios/perf.h | 2 ++ drm/nouveau/nvkm/subdev/bios/perf.c | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/drm/nouveau/include/nvkm/subdev/bios/perf.h b/drm/nouveau/include/nvkm/subdev/bios/perf.h index 7cc2bec..d3bd250 100644 --- a/drm/nouveau/include/nvkm/subdev/bios/perf.h +++ b/drm/nouveau/include/nvkm/subdev/bios/perf.h @@ -13,6 +13,8 @@ struct nvbios_perfE { u32 vdec; u32 disp; u32 script; + u8 pcie_speed; + u8 pcie_width; }; u16 nvbios_perf_entry(struct nvkm_bios *, int idx, diff --git a/drm/nouveau/nvkm/subdev/bios/perf.c b/drm/nouveau/nvkm/subdev/bios/perf.c index aa7e33b..636bfb6 100644 --- a/drm/nouveau/nvkm/subdev/bios/perf.c +++ b/drm/nouveau/nvkm/subdev/bios/perf.c @@ -24,6 +24,7 @@ #include <subdev/bios.h> #include <subdev/bios/bit.h> #include <subdev/bios/perf.h> +#include <subdev/pci.h> u16 nvbios_perf_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, @@ -145,6 +146,21 @@ nvbios_perfEp(struct nvkm_bios *bios, int idx, break; case 0x40: info->voltage = nvbios_rd08(bios, perf + 0x02); + switch (nvbios_rd08(bios, perf + 0xb) & 0x3) { + case 0: + info->pcie_speed = NVKM_PCIE_SPEED_5_0; + break; + case 3: + case 1: + info->pcie_speed = NVKM_PCIE_SPEED_2_5; + break; + case 2: + info->pcie_speed = NVKM_PCIE_SPEED_8_0; + break; + default: + break; + } + info->pcie_width = 0xff; break; default: return 0x0000; -- 2.6.4
Karol Herbst
2016-Jan-01 18:58 UTC
[Nouveau] [PATCH v4 8/9] perf: add fields for pci speed and width and use it for the pstates
Signed-off-by: Karol Herbst <nouveau at karolherbst.de> --- drm/nouveau/include/nvkm/subdev/clk.h | 3 +++ drm/nouveau/nvkm/subdev/clk/base.c | 2 ++ 2 files changed, 5 insertions(+) diff --git a/drm/nouveau/include/nvkm/subdev/clk.h b/drm/nouveau/include/nvkm/subdev/clk.h index 8708f0a..e9c4a81 100644 --- a/drm/nouveau/include/nvkm/subdev/clk.h +++ b/drm/nouveau/include/nvkm/subdev/clk.h @@ -2,6 +2,7 @@ #define __NVKM_CLK_H__ #include <core/subdev.h> #include <core/notify.h> +#include <subdev/pci.h> struct nvbios_pll; struct nvkm_pll_vals; @@ -59,6 +60,8 @@ struct nvkm_pstate { struct nvkm_cstate base; u8 pstate; u8 fanspeed; + enum nvkm_pcie_speed pcie_speed; + u8 pcie_width; }; struct nvkm_domain { diff --git a/drm/nouveau/nvkm/subdev/clk/base.c b/drm/nouveau/nvkm/subdev/clk/base.c index dc8682c..c769aff 100644 --- a/drm/nouveau/nvkm/subdev/clk/base.c +++ b/drm/nouveau/nvkm/subdev/clk/base.c @@ -330,6 +330,8 @@ nvkm_pstate_new(struct nvkm_clk *clk, int idx) pstate->pstate = perfE.pstate; pstate->fanspeed = perfE.fanspeed; + pstate->pcie_speed = perfE.pcie_speed; + pstate->pcie_width = perfE.pcie_width; cstate->voltage = perfE.voltage; cstate->domain[nv_clk_src_core] = perfE.core; cstate->domain[nv_clk_src_shader] = perfE.shader; -- 2.6.4
Karol Herbst
2016-Jan-01 18:58 UTC
[Nouveau] [PATCH v4 9/9] perf: change pcie speed on pstate change
v2: remove error and only set link for pcie devices Signed-off-by: Karol Herbst <nouveau at karolherbst.de> --- drm/nouveau/nvkm/subdev/clk/base.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drm/nouveau/nvkm/subdev/clk/base.c b/drm/nouveau/nvkm/subdev/clk/base.c index c769aff..004882d 100644 --- a/drm/nouveau/nvkm/subdev/clk/base.c +++ b/drm/nouveau/nvkm/subdev/clk/base.c @@ -176,6 +176,7 @@ nvkm_pstate_prog(struct nvkm_clk *clk, int pstatei) { struct nvkm_subdev *subdev = &clk->subdev; struct nvkm_ram *ram = subdev->device->fb->ram; + struct nvkm_pci *pci = subdev->device->pci; struct nvkm_pstate *pstate; int ret, idx = 0; @@ -187,6 +188,9 @@ nvkm_pstate_prog(struct nvkm_clk *clk, int pstatei) nvkm_debug(subdev, "setting performance state %d\n", pstatei); clk->pstate = pstatei; + if (pci && pci_is_pcie(pci->pdev)) + nvkm_pcie_set_link(pci, pstate->pcie_speed, pstate->pcie_width); + if (ram && ram->func->calc) { int khz = pstate->base.domain[nv_clk_src_mem]; do { -- 2.6.4