[Nouveau] [PATCH v2 3/9] pci: implement generic code for PCIe speed change
Ben Skeggs
skeggsb at gmail.com
Tue Oct 13 15:55:43 PDT 2015
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256
On 10/13/2015 07:44 PM, Karol Herbst wrote:
> v2: rename and group functions
>
> 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 | 5 ++
> drm/nouveau/nvkm/subdev/pci/pcie.c | 165
> ++++++++++++++++++++++++++++++++++
> drm/nouveau/nvkm/subdev/pci/priv.h | 15 ++++ 5 files changed,
> 200 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..95a8d05 100644
> --- a/drm/nouveau/nvkm/subdev/pci/base.c +++
> b/drm/nouveau/nvkm/subdev/pci/base.c @@ -117,6 +117,9 @@
> 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) @@ -160,6 +163,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..e60d0ba --- /dev/null +++
> b/drm/nouveau/nvkm/subdev/pci/pcie.c @@ -0,0 +1,165 @@ +/* + *
> Copyright 2015 Karol Herbst + * + * 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 s8
> +nvkm_pci_get_pcie_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 s8
> +nvkm_pci_raise_pcie_version(struct nvkm_pci *pci) +{ + int ret,
> supported; + + if (!pci_is_pcie(pci->pdev)) + return -ENODEV; + +
> if (!pci->func->pcie.set_version ||
> !pci->func->pcie.version_supported) + return -ENOSYS; + + ret =
> nvkm_pci_get_pcie_version(pci); + supported =
> pci->func->pcie.version_supported(pci); + if (ret == 1 && ret <
> supported) { + nvkm_debug(&pci->subdev, "raising version\n"); +
> pci->func->pcie.set_version(pci, supported); + ret =
> nvkm_pci_get_pcie_version(pci); + } + return ret >= supported ? ret
> : -EINVAL; +} + +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_pci_raise_pcie_version(pci); + if
> (ret <= 0) + nvkm_error(subdev, "couldn't raise version: %i\n",
> ret); + + if (pci->func->pcie.init) + pci->func->pcie.init(pci);
> + + nvkm_info(subdev, "pcie version: %i\n",
> nvkm_pci_get_pcie_version(pci)); + if (pci->func->pcie.max_speed) +
> nvkm_info(subdev, "pcie max speed: %s\n", +
> pcie_speed_strings[pci->func->pcie.max_speed(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..5370f0d 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 *);
Very minor nit-pick: most of the code uses "blah_set" etc rather than
"set_blah", it would be nice to be consistent with these here.
> + } pcie; };
>
> u32 nv40_pci_rd32(struct nvkm_pci *, u16); @@ -22,4 +34,7 @@ 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_init(struct nvkm_pci *pci); #endif
>
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2
iQIcBAEBCAAGBQJWHYvvAAoJEHYLnGJQkpH7L3kP/RMT3TfEl1Ecwm02PrIyygMK
vYq3sQvQ6+ZvMLkSJReUNbMmaqBfoeNmzO+zWhdPlzObh5K8lNMxD35WTSQYnzCr
ACdo0wc0JBfa5MMIuhU2Am/GfZrLm9lZ6m9Ke3LMkdmFWHx7WGZX2HVWUHSKFL7f
NlTYLS0SNKf6lab0gOiG5TMPxYcGmxYgCGdVhtYWfiu3raTUwfCQDj1qlztjAa8L
lRK/i0KtCMVB1t/fB/u3ekao3RHJNU6fcn50TmcMS4zS3p3LrowXhqAyVK27dYly
EDzC43o91cYFSNfHvMH9ZiIK54EKQI/vY2WrZdARRwQrNL/IO0UkNhh1g8llwmDb
3Ze7hY7xtomJSkqp7QFfjA8Iglpm9Z7DQP2vFqgoup3MVqDKBUscqoIkuu+HO+zR
nB+zuDSyNSnyWyUjaKlbcKucCJEsIF/EKw5OosegPNgQ6LGEFc+ub+ELk9+ozSDu
UxZvYfMb+P3jHBaPe2XoXoFnDvWUkrH70sodeYvii+jyYNxmhyEsVQVbKVAfTZ9B
1UUkmS9Mv0PvVeCBwThoyQ6x8fFAq3qkOKGtmepvzT8zY0E3Ps1RxQGQipPDrtdV
Tj7VEZdHbR7WUov2xz3pkh3f2MEhck+8idYR88JR6ijzbx7Bxz36gth624RSxu+L
VV3t6v60pr1hO25Xvz+G
=zLyv
-----END PGP SIGNATURE-----
More information about the Nouveau
mailing list