Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
@@ -0,0 +1,16 @@
# SPDX-License-Identifier: MIT
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
nvkm-y += nvkm/subdev/pci/nv4c.o
nvkm-y += nvkm/subdev/pci/g84.o
nvkm-y += nvkm/subdev/pci/g92.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
nvkm-y += nvkm/subdev/pci/gp100.o
nvkm-y += nvkm/subdev/pci/gh100.o
@@ -0,0 +1,175 @@
/*
* Copyright 2015 Nouveau Project
*
* 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.
*/
#include "agp.h"
#ifdef __NVKM_PCI_AGP_H__
#include <core/option.h>
struct nvkm_device_agp_quirk {
u16 hostbridge_vendor;
u16 hostbridge_device;
u16 chip_vendor;
u16 chip_device;
int mode;
};
static const struct nvkm_device_agp_quirk
nvkm_device_agp_quirks[] = {
/* VIA Apollo PRO133x / GeForce FX 5600 Ultra - fdo#20341 */
{ PCI_VENDOR_ID_VIA, 0x0691, PCI_VENDOR_ID_NVIDIA, 0x0311, 2 },
/* SiS 761 does not support AGP cards, use PCI mode */
{ PCI_VENDOR_ID_SI, 0x0761, PCI_ANY_ID, PCI_ANY_ID, 0 },
{},
};
void
nvkm_agp_fini(struct nvkm_pci *pci)
{
if (pci->agp.acquired) {
agp_backend_release(pci->agp.bridge);
pci->agp.acquired = false;
}
}
/* Ensure AGP controller is in a consistent state in case we need to
* execute the VBIOS DEVINIT scripts.
*/
void
nvkm_agp_preinit(struct nvkm_pci *pci)
{
struct nvkm_device *device = pci->subdev.device;
u32 mode = nvkm_pci_rd32(pci, 0x004c);
u32 save[2];
/* First of all, disable fast writes, otherwise if it's already
* enabled in the AGP bridge and we disable the card's AGP
* controller we might be locking ourselves out of it.
*/
if ((mode | pci->agp.mode) & PCI_AGP_COMMAND_FW) {
mode = pci->agp.mode & ~PCI_AGP_COMMAND_FW;
agp_enable(pci->agp.bridge, mode);
}
/* clear busmaster bit, and disable AGP */
save[0] = nvkm_pci_rd32(pci, 0x0004);
nvkm_pci_wr32(pci, 0x0004, save[0] & ~0x00000004);
nvkm_pci_wr32(pci, 0x004c, 0x00000000);
/* reset PGRAPH, PFIFO and PTIMER */
save[1] = nvkm_mask(device, 0x000200, 0x00011100, 0x00000000);
nvkm_mask(device, 0x000200, 0x00011100, save[1]);
/* and restore busmaster bit (gives effect of resetting AGP) */
nvkm_pci_wr32(pci, 0x0004, save[0]);
}
int
nvkm_agp_init(struct nvkm_pci *pci)
{
if (!agp_backend_acquire(pci->pdev)) {
nvkm_error(&pci->subdev, "failed to acquire agp\n");
return -ENODEV;
}
agp_enable(pci->agp.bridge, pci->agp.mode);
pci->agp.acquired = true;
return 0;
}
void
nvkm_agp_dtor(struct nvkm_pci *pci)
{
arch_phys_wc_del(pci->agp.mtrr);
}
void
nvkm_agp_ctor(struct nvkm_pci *pci)
{
const struct nvkm_device_agp_quirk *quirk = nvkm_device_agp_quirks;
struct nvkm_subdev *subdev = &pci->subdev;
struct nvkm_device *device = subdev->device;
struct agp_kern_info info;
int mode = -1;
#ifdef __powerpc__
/* Disable AGP by default on all PowerPC machines for now -- At
* least some UniNorth-2 AGP bridges are known to be broken:
* DMA from the host to the card works just fine, but writeback
* from the card to the host goes straight to memory
* untranslated bypassing that GATT somehow, making them quite
* painful to deal with...
*/
mode = 0;
#endif
mode = nvkm_longopt(device->cfgopt, "NvAGP", mode);
/* acquire bridge temporarily, so that we can copy its info */
if (!(pci->agp.bridge = agp_backend_acquire(pci->pdev))) {
nvkm_warn(subdev, "failed to acquire agp\n");
return;
}
agp_copy_info(pci->agp.bridge, &info);
agp_backend_release(pci->agp.bridge);
pci->agp.mode = info.mode;
pci->agp.base = info.aper_base;
pci->agp.size = info.aper_size * 1024 * 1024;
pci->agp.cma = info.cant_use_aperture;
pci->agp.mtrr = -1;
/* determine if bridge + chipset combination needs a workaround */
while (quirk->hostbridge_vendor) {
if (info.device->vendor == quirk->hostbridge_vendor &&
info.device->device == quirk->hostbridge_device &&
(quirk->chip_vendor == (u16)PCI_ANY_ID ||
pci->pdev->vendor == quirk->chip_vendor) &&
(quirk->chip_device == (u16)PCI_ANY_ID ||
pci->pdev->device == quirk->chip_device)) {
nvkm_info(subdev, "forcing default agp mode to %dX, "
"use NvAGP=<mode> to override\n",
quirk->mode);
mode = quirk->mode;
break;
}
quirk++;
}
/* apply quirk / user-specified mode */
if (mode >= 1) {
if (pci->agp.mode & 0x00000008)
mode /= 4; /* AGPv3 */
pci->agp.mode &= ~0x00000007;
pci->agp.mode |= (mode & 0x7);
} else
if (mode == 0) {
pci->agp.bridge = NULL;
return;
}
/* fast writes appear to be broken on nv18, they make the card
* lock up randomly.
*/
if (device->chipset == 0x18)
pci->agp.mode &= ~PCI_AGP_COMMAND_FW;
pci->agp.mtrr = arch_phys_wc_add(pci->agp.base, pci->agp.size);
}
#endif
@@ -0,0 +1,19 @@
/* SPDX-License-Identifier: MIT */
#include "priv.h"
#if defined(CONFIG_AGP) || (defined(CONFIG_AGP_MODULE) && defined(MODULE))
#ifndef __NVKM_PCI_AGP_H__
#define __NVKM_PCI_AGP_H__
void nvkm_agp_ctor(struct nvkm_pci *);
void nvkm_agp_dtor(struct nvkm_pci *);
void nvkm_agp_preinit(struct nvkm_pci *);
int nvkm_agp_init(struct nvkm_pci *);
void nvkm_agp_fini(struct nvkm_pci *);
#endif
#else
static inline void nvkm_agp_ctor(struct nvkm_pci *pci) {}
static inline void nvkm_agp_dtor(struct nvkm_pci *pci) {}
static inline void nvkm_agp_preinit(struct nvkm_pci *pci) {}
static inline int nvkm_agp_init(struct nvkm_pci *pci) { return -ENOSYS; }
static inline void nvkm_agp_fini(struct nvkm_pci *pci) {}
#endif
@@ -0,0 +1,206 @@
/*
* Copyright 2015 Red Hat Inc.
*
* 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: Ben Skeggs <bskeggs@redhat.com>
*/
#include "priv.h"
#include "agp.h"
#include <core/option.h>
#include <core/pci.h>
void
nvkm_pci_msi_rearm(struct nvkm_device *device)
{
struct nvkm_pci *pci = device->pci;
if (pci && pci->msi)
pci->func->msi_rearm(pci);
}
u32
nvkm_pci_rd32(struct nvkm_pci *pci, u16 addr)
{
return nvkm_rd32(pci->subdev.device, pci->func->cfg.addr + addr);
}
void
nvkm_pci_wr08(struct nvkm_pci *pci, u16 addr, u8 data)
{
nvkm_wr08(pci->subdev.device, pci->func->cfg.addr + addr, data);
}
void
nvkm_pci_wr32(struct nvkm_pci *pci, u16 addr, u32 data)
{
nvkm_wr32(pci->subdev.device, pci->func->cfg.addr + addr, data);
}
u32
nvkm_pci_mask(struct nvkm_pci *pci, u16 addr, u32 mask, u32 value)
{
u32 data = nvkm_pci_rd32(pci, addr);
nvkm_pci_wr32(pci, addr, (data & ~mask) | value);
return data;
}
void
nvkm_pci_rom_shadow(struct nvkm_pci *pci, bool shadow)
{
u32 data = nvkm_pci_rd32(pci, 0x0050);
if (shadow)
data |= 0x00000001;
else
data &= ~0x00000001;
nvkm_pci_wr32(pci, 0x0050, data);
}
static int
nvkm_pci_fini(struct nvkm_subdev *subdev, enum nvkm_suspend_state suspend)
{
struct nvkm_pci *pci = nvkm_pci(subdev);
if (pci->agp.bridge)
nvkm_agp_fini(pci);
return 0;
}
static int
nvkm_pci_preinit(struct nvkm_subdev *subdev)
{
struct nvkm_pci *pci = nvkm_pci(subdev);
if (pci->agp.bridge)
nvkm_agp_preinit(pci);
return 0;
}
static int
nvkm_pci_oneinit(struct nvkm_subdev *subdev)
{
struct nvkm_pci *pci = nvkm_pci(subdev);
int ret;
if (pci_is_pcie(pci->pdev)) {
ret = nvkm_pcie_oneinit(pci);
if (ret)
return ret;
}
return 0;
}
static int
nvkm_pci_init(struct nvkm_subdev *subdev)
{
struct nvkm_pci *pci = nvkm_pci(subdev);
int ret;
if (pci->agp.bridge) {
ret = nvkm_agp_init(pci);
if (ret)
return ret;
} else if (pci_is_pcie(pci->pdev)) {
nvkm_pcie_init(pci);
}
if (pci->func->init)
pci->func->init(pci);
/* Ensure MSI interrupts are armed, for the case where there are
* already interrupts pending (for whatever reason) at load time.
*/
if (pci->msi)
pci->func->msi_rearm(pci);
return 0;
}
static void *
nvkm_pci_dtor(struct nvkm_subdev *subdev)
{
struct nvkm_pci *pci = nvkm_pci(subdev);
nvkm_agp_dtor(pci);
if (pci->msi)
pci_disable_msi(pci->pdev);
return nvkm_pci(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,
};
int
nvkm_pci_new_(const struct nvkm_pci_func *func, struct nvkm_device *device,
enum nvkm_subdev_type type, int inst, struct nvkm_pci **ppci)
{
struct nvkm_pci *pci;
if (!(pci = *ppci = kzalloc_obj(**ppci)))
return -ENOMEM;
nvkm_subdev_ctor(&nvkm_pci_func, device, type, inst, &pci->subdev);
pci->func = func;
pci->pdev = device->func->pci(device)->pdev;
pci->pcie.speed = -1;
pci->pcie.width = -1;
if (device->type == NVKM_DEVICE_AGP)
nvkm_agp_ctor(pci);
switch (pci->pdev->device & 0x0ff0) {
case 0x00f0:
case 0x02e0:
/* BR02? NFI how these would be handled yet exactly */
break;
default:
switch (device->chipset) {
case 0xaa:
/* reported broken, nv also disable it */
break;
default:
pci->msi = true;
break;
}
}
#ifdef __BIG_ENDIAN
pci->msi = false;
#endif
pci->msi = nvkm_boolopt(device->cfgopt, "NvMSI", pci->msi);
if (pci->msi && func->msi_rearm) {
pci->msi = pci_enable_msi(pci->pdev) == 0;
if (pci->msi)
nvkm_debug(&pci->subdev, "MSI enabled\n");
} else {
pci->msi = false;
}
return 0;
}
@@ -0,0 +1,156 @@
/*
* Copyright 2015 Red Hat Inc.
*
* 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: Ben Skeggs <bskeggs@redhat.com>
*/
#include "priv.h"
#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 speed, u8 width)
{
g84_pcie_set_cap_speed(pci, speed == NVKM_PCIE_SPEED_5_0);
g84_pcie_set_link_speed(pci, speed);
return 0;
}
void
g84_pci_init(struct nvkm_pci *pci)
{
/* The following only concerns PCIe cards. */
if (!pci_is_pcie(pci->pdev))
return;
/* Tag field is 8-bit long, regardless of EXT_TAG.
* However, if EXT_TAG is disabled, only the lower 5 bits of the tag
* field should be used, limiting the number of request to 32.
*
* Apparently, 0x041c stores some limit on the number of requests
* possible, so if EXT_TAG is disabled, limit that requests number to
* 32
*
* Fixes fdo#86537
*/
if (nvkm_pci_rd32(pci, 0x007c) & 0x00000020)
nvkm_pci_mask(pci, 0x0080, 0x00000100, 0x00000100);
else
nvkm_pci_mask(pci, 0x041c, 0x00000060, 0x00000000);
}
int
g84_pcie_init(struct nvkm_pci *pci)
{
bool full_speed = g84_pcie_cur_speed(pci) == NVKM_PCIE_SPEED_5_0;
g84_pcie_set_cap_speed(pci, full_speed);
return 0;
}
static const struct nvkm_pci_func
g84_pci_func = {
.cfg = { .addr = 0x088000, .size = 0x1000 },
.init = g84_pci_init,
.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
g84_pci_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_pci **ppci)
{
return nvkm_pci_new_(&g84_pci_func, device, type, inst, ppci);
}
@@ -0,0 +1,57 @@
/*
* Copyright 2015 Red Hat Inc.
*
* 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: Ben Skeggs <bskeggs@redhat.com>
*/
#include "priv.h"
int
g92_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
g92_pci_func = {
.cfg = { .addr = 0x088000, .size = 0x1000 },
.init = g84_pci_init,
.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 = g92_pcie_version_supported,
};
int
g92_pci_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_pci **ppci)
{
return nvkm_pci_new_(&g92_pci_func, device, type, inst, ppci);
}
@@ -0,0 +1,49 @@
/*
* Copyright 2015 Red Hat Inc.
*
* 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: Ben Skeggs <bskeggs@redhat.com>
*/
#include "priv.h"
static const struct nvkm_pci_func
g94_pci_func = {
.cfg = { .addr = 0x088000, .size = 0x1000 },
.init = g84_pci_init,
.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 = g92_pcie_version_supported,
};
int
g94_pci_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_pci **ppci)
{
return nvkm_pci_new_(&g94_pci_func, device, type, inst, ppci);
}
@@ -0,0 +1,102 @@
/*
* Copyright 2015 Red Hat Inc.
*
* 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: Ben Skeggs <bskeggs@redhat.com>
*/
#include "priv.h"
static void
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;
nvkm_mask(device, 0x02241c, 0x1, ver > 1 ? 1 : 0);
}
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)
{
bool full_speed = g84_pcie_cur_speed(pci) == NVKM_PCIE_SPEED_5_0;
gf100_pcie_set_cap_speed(pci, full_speed);
return 0;
}
int
gf100_pcie_set_link(struct nvkm_pci *pci, enum nvkm_pcie_speed speed, u8 width)
{
gf100_pcie_set_cap_speed(pci, speed == NVKM_PCIE_SPEED_5_0);
g84_pcie_set_link_speed(pci, speed);
return 0;
}
static const struct nvkm_pci_func
gf100_pci_func = {
.cfg = { .addr = 0x088000, .size = 0x1000 },
.init = g84_pci_init,
.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 = g92_pcie_version_supported,
};
int
gf100_pci_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_pci **ppci)
{
return nvkm_pci_new_(&gf100_pci_func, device, type, inst, ppci);
}
@@ -0,0 +1,49 @@
/*
* Copyright 2015 Karol Herbst <nouveau@karolherbst.de>
*
* 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@karolherbst.de>
*/
#include "priv.h"
static const struct nvkm_pci_func
gf106_pci_func = {
.cfg = { .addr = 0x088000, .size = 0x1000 },
.init = g84_pci_init,
.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 = g92_pcie_version_supported,
};
int
gf106_pci_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_pci **ppci)
{
return nvkm_pci_new_(&gf106_pci_func, device, type, inst, ppci);
}
@@ -0,0 +1,30 @@
/* SPDX-License-Identifier: MIT
*
* Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
*/
#include "priv.h"
#include <nvhw/drf.h>
#include <nvhw/ref/gh100/dev_xtl_ep_pri.h>
static void
gh100_pci_msi_rearm(struct nvkm_pci *pci)
{
/* Handled by top-level intr ACK. */
}
static const struct nvkm_pci_func
gh100_pci = {
.cfg = {
.addr = DRF_LO(NV_EP_PCFGM),
.size = DRF_HI(NV_EP_PCFGM) - DRF_LO(NV_EP_PCFGM) + 1,
},
.msi_rearm = gh100_pci_msi_rearm,
};
int
gh100_pci_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_pci **ppci)
{
return nvkm_pci_new_(&gh100_pci, device, type, inst, ppci);
}
@@ -0,0 +1,228 @@
/*
* Copyright 2015 Karol Herbst <nouveau@karolherbst.de>
*
* 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@karolherbst.de>
*/
#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 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) {
case NVKM_PCIE_SPEED_8_0:
mask_value = 0x00000;
break;
case NVKM_PCIE_SPEED_5_0:
mask_value = 0x40000;
break;
case NVKM_PCIE_SPEED_2_5:
default:
mask_value = 0x80000;
break;
}
nvkm_mask(device, 0x8c040, 0xc0000, mask_value);
nvkm_mask(device, 0x8c040, 0x1, 0x1);
}
static int
gk104_pcie_init(struct nvkm_pci * pci)
{
enum nvkm_pcie_speed lnkctl_speed, max_speed, cap_speed;
struct nvkm_subdev *subdev = &pci->subdev;
if (gf100_pcie_version(pci) < 2)
return 0;
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_trace(subdev, "adjusting cap 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_warn(subdev, "failed to adjust cap speed\n");
}
if (lnkctl_speed != max_speed) {
nvkm_debug(subdev, "adjusting lnkctl 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(subdev, "failed to adjust lnkctl speed\n");
}
return 0;
}
static int
gk104_pcie_set_link(struct nvkm_pci *pci, enum nvkm_pcie_speed speed, u8 width)
{
struct nvkm_subdev *subdev = &pci->subdev;
enum nvkm_pcie_speed lnk_ctl_speed = gk104_pcie_lnkctl_speed(pci);
enum nvkm_pcie_speed lnk_cap_speed = gk104_pcie_cap_speed(pci);
if (speed > lnk_cap_speed) {
speed = lnk_cap_speed;
nvkm_warn(subdev, "dropping requested speed due too low cap"
" speed\n");
}
if (speed > lnk_ctl_speed) {
speed = lnk_ctl_speed;
nvkm_warn(subdev, "dropping requested speed due too low"
" lnkctl speed\n");
}
gk104_pcie_set_link_speed(pci, speed);
return 0;
}
static const struct nvkm_pci_func
gk104_pci_func = {
.cfg = { .addr = 0x088000, .size = 0x1000 },
.init = g84_pci_init,
.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
gk104_pci_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_pci **ppci)
{
return nvkm_pci_new_(&gk104_pci_func, device, type, inst, ppci);
}
@@ -0,0 +1,43 @@
/*
* Copyright 2015 Red Hat Inc.
*
* 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: Ben Skeggs <bskeggs@redhat.com>
*/
#include "priv.h"
static void
gp100_pci_msi_rearm(struct nvkm_pci *pci)
{
nvkm_pci_wr32(pci, 0x0704, 0x00000000);
}
static const struct nvkm_pci_func
gp100_pci_func = {
.cfg = { .addr = 0x088000, .size = 0x1000 },
.msi_rearm = gp100_pci_msi_rearm,
};
int
gp100_pci_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_pci **ppci)
{
return nvkm_pci_new_(&gp100_pci_func, device, type, inst, ppci);
}
@@ -0,0 +1,36 @@
/*
* Copyright 2015 Red Hat Inc.
*
* 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: Ben Skeggs <bskeggs@redhat.com>
*/
#include "priv.h"
static const struct nvkm_pci_func
nv04_pci_func = {
.cfg = { .addr = 0x001800, .size = 0x1000 },
};
int
nv04_pci_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_pci **ppci)
{
return nvkm_pci_new_(&nv04_pci_func, device, type, inst, ppci);
}
@@ -0,0 +1,43 @@
/*
* Copyright 2015 Red Hat Inc.
*
* 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: Ben Skeggs <bskeggs@redhat.com>
*/
#include "priv.h"
void
nv40_pci_msi_rearm(struct nvkm_pci *pci)
{
nvkm_pci_wr08(pci, 0x0068, 0xff);
}
static const struct nvkm_pci_func
nv40_pci_func = {
.cfg = { .addr = 0x088000, .size = 0x1000 },
.msi_rearm = nv40_pci_msi_rearm,
};
int
nv40_pci_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_pci **ppci)
{
return nvkm_pci_new_(&nv40_pci_func, device, type, inst, ppci);
}
@@ -0,0 +1,50 @@
/*
* Copyright 2015 Red Hat Inc.
*
* 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: Ben Skeggs <bskeggs@redhat.com>
*/
#include "priv.h"
#include <core/pci.h>
/* MSI re-arm through the PRI appears to be broken on NV46/NV50/G84/G86/G92,
* so we access it via alternate PCI config space mechanisms.
*/
void
nv46_pci_msi_rearm(struct nvkm_pci *pci)
{
struct nvkm_device *device = pci->subdev.device;
struct pci_dev *pdev = device->func->pci(device)->pdev;
pci_write_config_byte(pdev, 0x68, 0xff);
}
static const struct nvkm_pci_func
nv46_pci_func = {
.cfg = { .addr = 0x088000, .size = 0x1000 },
.msi_rearm = nv46_pci_msi_rearm,
};
int
nv46_pci_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_pci **ppci)
{
return nvkm_pci_new_(&nv46_pci_func, device, type, inst, ppci);
}
@@ -0,0 +1,36 @@
/*
* Copyright 2015 Red Hat Inc.
*
* 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: Ben Skeggs <bskeggs@redhat.com>
*/
#include "priv.h"
static const struct nvkm_pci_func
nv4c_pci_func = {
.cfg = { .addr = 0x088000, .size = 0x1000 },
};
int
nv4c_pci_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_pci **ppci)
{
return nvkm_pci_new_(&nv4c_pci_func, device, type, inst, ppci);
}
@@ -0,0 +1,164 @@
/*
* Copyright 2015 Karol Herbst <nouveau@karolherbst.de>
*
* 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@karolherbst.de>
*/
#include "priv.h"
static char *nvkm_pcie_speeds[] = {
"2.5GT/s",
"5.0GT/s",
"8.0GT/s",
};
static enum nvkm_pcie_speed
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->func->pcie.version)
return -ENOSYS;
return pci->func->pcie.version(pci);
}
static int
nvkm_pcie_get_max_version(struct nvkm_pci *pci)
{
if (!pci->func->pcie.version_supported)
return -ENOSYS;
return pci->func->pcie.version_supported(pci);
}
static int
nvkm_pcie_set_version(struct nvkm_pci *pci, int version)
{
if (!pci->func->pcie.set_version)
return -ENOSYS;
nvkm_trace(&pci->subdev, "set to version %i\n", version);
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_debug(&pci->subdev, "pcie max speed: %s\n",
nvkm_pcie_speeds[pci->func->pcie.max_speed(pci)]);
return 0;
}
int
nvkm_pcie_init(struct nvkm_pci *pci)
{
struct nvkm_subdev *subdev = &pci->subdev;
int ret;
/* 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_set_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);
if (pci->pcie.speed != -1)
nvkm_pcie_set_link(pci, pci->pcie.speed, pci->pcie.width);
return 0;
}
int
nvkm_pcie_set_link(struct nvkm_pci *pci, enum nvkm_pcie_speed speed, u8 width)
{
struct nvkm_subdev *subdev;
enum nvkm_pcie_speed cur_speed, max_speed;
int ret;
if (!pci || !pci_is_pcie(pci->pdev))
return 0;
if (!pci->func->pcie.set_link)
return -ENOSYS;
subdev = &pci->subdev;
nvkm_trace(subdev, "requested %s\n", nvkm_pcie_speeds[speed]);
if (pci->func->pcie.version(pci) < 2) {
nvkm_error(subdev, "setting link failed due to low version\n");
return -ENODEV;
}
cur_speed = pci->func->pcie.cur_speed(pci);
max_speed = min(nvkm_pcie_speed(pci->pdev->bus->max_bus_speed),
pci->func->pcie.max_speed(pci));
nvkm_trace(subdev, "current speed: %s\n", nvkm_pcie_speeds[cur_speed]);
if (speed > max_speed) {
nvkm_debug(subdev, "%s not supported by bus or card, dropping"
"requested speed to %s", nvkm_pcie_speeds[speed],
nvkm_pcie_speeds[max_speed]);
speed = max_speed;
}
pci->pcie.speed = speed;
pci->pcie.width = width;
if (speed == cur_speed) {
nvkm_debug(subdev, "requested matches current speed\n");
return speed;
}
nvkm_debug(subdev, "set link to %s x%i\n",
nvkm_pcie_speeds[speed], width);
ret = pci->func->pcie.set_link(pci, speed, width);
if (ret < 0)
nvkm_error(subdev, "setting link failed: %i\n", ret);
return ret;
}
@@ -0,0 +1,58 @@
/* SPDX-License-Identifier: MIT */
#ifndef __NVKM_PCI_PRIV_H__
#define __NVKM_PCI_PRIV_H__
#define nvkm_pci(p) container_of((p), struct nvkm_pci, subdev)
#include <subdev/pci.h>
int nvkm_pci_new_(const struct nvkm_pci_func *, struct nvkm_device *, enum nvkm_subdev_type, int,
struct nvkm_pci **);
struct nvkm_pci_func {
struct {
u32 addr;
u16 size;
} cfg;
void (*init)(struct nvkm_pci *);
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;
};
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 */
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 g92_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