[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