Pierre Moreau
2015-Sep-16 20:26 UTC
[Nouveau] [PATCH v3] pci: Handle 5-bit and 8-bit tag field
If the hardware supports extended tag field (8-bit ones), then enabled it. This is usually done by the VBIOS, but not on some MBPs (see fdo#86537). In case extended tag field is not supported, 5-bit tag field is used which limits the possible values to 32. Apparently bits 7:0 of 0x8841c stores some number of outstanding requests, so cap it to 32 if extended tag is unsupported. Fixes: fdo#86537 v2: Restrict changes to chipsets >= 0x84 v3: * Add nvkm_pci_mask to pci.h * Mask bit 8 before setting it Signed-off-by: Pierre Moreau <pierre.morrow at free.fr> --- drm/nouveau/include/nvkm/subdev/pci.h | 1 + drm/nouveau/nvkm/subdev/pci/base.c | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/drm/nouveau/include/nvkm/subdev/pci.h b/drm/nouveau/include/nvkm/subdev/pci.h index 5b3c054..774ca66 100644 --- a/drm/nouveau/include/nvkm/subdev/pci.h +++ b/drm/nouveau/include/nvkm/subdev/pci.h @@ -24,6 +24,7 @@ struct nvkm_pci { u32 nvkm_pci_rd32(struct nvkm_pci *, u16 addr); void nvkm_pci_wr08(struct nvkm_pci *, u16 addr, u8 data); void nvkm_pci_wr32(struct nvkm_pci *, u16 addr, u32 data); +u32 nvkm_pci_mask(struct nvkm_pci *, u16 addr, u32 mask, u32 add); void nvkm_pci_rom_shadow(struct nvkm_pci *, bool shadow); int nv04_pci_new(struct nvkm_device *, int, struct nvkm_pci **); diff --git a/drm/nouveau/nvkm/subdev/pci/base.c b/drm/nouveau/nvkm/subdev/pci/base.c index d1c148e..cb2835b 100644 --- a/drm/nouveau/nvkm/subdev/pci/base.c +++ b/drm/nouveau/nvkm/subdev/pci/base.c @@ -46,6 +46,14 @@ nvkm_pci_wr32(struct nvkm_pci *pci, u16 addr, u32 data) pci->func->wr32(pci, addr, data); } +u32 +nvkm_pci_mask(struct nvkm_pci *pci, u16 addr, u32 mask, u32 add) +{ + u32 data = pci->func->rd32(pci, addr); + pci->func->wr32(pci, addr, (data & ~mask) | add); + return data; +} + void nvkm_pci_rom_shadow(struct nvkm_pci *pci, bool shadow) { @@ -115,6 +123,23 @@ nvkm_pci_init(struct nvkm_subdev *subdev) if (ret) return ret; + if (pci_is_pcie(pdev) && subdev->device->chipset >= 0x84) { + /* 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); + } + pci->irq = pdev->irq; return ret; } -- 2.5.2
Pierre Moreau
2015-Sep-26 08:42 UTC
[Nouveau] [PATCH v3] pci: Handle 5-bit and 8-bit tag field
----- Mail original -----> If the hardware supports extended tag field (8-bit ones), then > enabled it. This > is usually done by the VBIOS, but not on some MBPs (see fdo#86537). > In case extended tag field is not supported, 5-bit tag field is used > which > limits the possible values to 32. Apparently bits 7:0 of 0x8841c > stores some > number of outstanding requests, so cap it to 32 if extended tag is > unsupported. > > Fixes: fdo#86537 > > v2: Restrict changes to chipsets >= 0x84 > v3: > * Add nvkm_pci_mask to pci.h > * Mask bit 8 before setting it > > Signed-off-by: Pierre Moreau <pierre.morrow at free.fr>Tested-by: Karol Herbst <freedesktop at karolherbst.de>> --- > drm/nouveau/include/nvkm/subdev/pci.h | 1 + > drm/nouveau/nvkm/subdev/pci/base.c | 25 +++++++++++++++++++++++++ > 2 files changed, 26 insertions(+) > > diff --git a/drm/nouveau/include/nvkm/subdev/pci.h > b/drm/nouveau/include/nvkm/subdev/pci.h > index 5b3c054..774ca66 100644 > --- a/drm/nouveau/include/nvkm/subdev/pci.h > +++ b/drm/nouveau/include/nvkm/subdev/pci.h > @@ -24,6 +24,7 @@ struct nvkm_pci { > u32 nvkm_pci_rd32(struct nvkm_pci *, u16 addr); > void nvkm_pci_wr08(struct nvkm_pci *, u16 addr, u8 data); > void nvkm_pci_wr32(struct nvkm_pci *, u16 addr, u32 data); > +u32 nvkm_pci_mask(struct nvkm_pci *, u16 addr, u32 mask, u32 add); > void nvkm_pci_rom_shadow(struct nvkm_pci *, bool shadow); > > int nv04_pci_new(struct nvkm_device *, int, struct nvkm_pci **); > diff --git a/drm/nouveau/nvkm/subdev/pci/base.c > b/drm/nouveau/nvkm/subdev/pci/base.c > index d1c148e..cb2835b 100644 > --- a/drm/nouveau/nvkm/subdev/pci/base.c > +++ b/drm/nouveau/nvkm/subdev/pci/base.c > @@ -46,6 +46,14 @@ nvkm_pci_wr32(struct nvkm_pci *pci, u16 addr, u32 > data) > pci->func->wr32(pci, addr, data); > } > > +u32 > +nvkm_pci_mask(struct nvkm_pci *pci, u16 addr, u32 mask, u32 add) > +{ > + u32 data = pci->func->rd32(pci, addr); > + pci->func->wr32(pci, addr, (data & ~mask) | add); > + return data; > +} > + > void > nvkm_pci_rom_shadow(struct nvkm_pci *pci, bool shadow) > { > @@ -115,6 +123,23 @@ nvkm_pci_init(struct nvkm_subdev *subdev) > if (ret) > return ret; > > + if (pci_is_pcie(pdev) && subdev->device->chipset >= 0x84) { > + /* 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); > + } > + > pci->irq = pdev->irq; > return ret; > } > -- > 2.5.2 > > _______________________________________________ > dri-devel mailing list > dri-devel at lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/dri-devel >
Ben Skeggs
2015-Sep-29 21:01 UTC
[Nouveau] [PATCH v3] pci: Handle 5-bit and 8-bit tag field
On 09/17/2015 06:26 AM, Pierre Moreau wrote:> If the hardware supports extended tag field (8-bit ones), then > enabled it. This is usually done by the VBIOS, but not on some MBPs > (see fdo#86537). In case extended tag field is not supported, 5-bit > tag field is used which limits the possible values to 32. > Apparently bits 7:0 of 0x8841c stores some number of outstanding > requests, so cap it to 32 if extended tag is unsupported. > > Fixes: fdo#86537 > > v2: Restrict changes to chipsets >= 0x84 v3: * Add nvkm_pci_mask to > pci.h * Mask bit 8 before setting it > > Signed-off-by: Pierre Moreau <pierre.morrow at free.fr> --- > drm/nouveau/include/nvkm/subdev/pci.h | 1 + > drm/nouveau/nvkm/subdev/pci/base.c | 25 > +++++++++++++++++++++++++ 2 files changed, 26 insertions(+) > > diff --git a/drm/nouveau/include/nvkm/subdev/pci.h > b/drm/nouveau/include/nvkm/subdev/pci.h index 5b3c054..774ca66 > 100644 --- a/drm/nouveau/include/nvkm/subdev/pci.h +++ > b/drm/nouveau/include/nvkm/subdev/pci.h @@ -24,6 +24,7 @@ struct > nvkm_pci { u32 nvkm_pci_rd32(struct nvkm_pci *, u16 addr); void > nvkm_pci_wr08(struct nvkm_pci *, u16 addr, u8 data); void > nvkm_pci_wr32(struct nvkm_pci *, u16 addr, u32 data); +u32 > nvkm_pci_mask(struct nvkm_pci *, u16 addr, u32 mask, u32 add); void > nvkm_pci_rom_shadow(struct nvkm_pci *, bool shadow); > > int nv04_pci_new(struct nvkm_device *, int, struct nvkm_pci **); > diff --git a/drm/nouveau/nvkm/subdev/pci/base.c > b/drm/nouveau/nvkm/subdev/pci/base.c index d1c148e..cb2835b 100644 > --- a/drm/nouveau/nvkm/subdev/pci/base.c +++ > b/drm/nouveau/nvkm/subdev/pci/base.c @@ -46,6 +46,14 @@ > nvkm_pci_wr32(struct nvkm_pci *pci, u16 addr, u32 data) > pci->func->wr32(pci, addr, data); } > > +u32 +nvkm_pci_mask(struct nvkm_pci *pci, u16 addr, u32 mask, u32 > add) +{ + u32 data = pci->func->rd32(pci, addr); + > pci->func->wr32(pci, addr, (data & ~mask) | add); + return data; > +} + void nvkm_pci_rom_shadow(struct nvkm_pci *pci, bool shadow) { > @@ -115,6 +123,23 @@ nvkm_pci_init(struct nvkm_subdev *subdev) if > (ret) return ret; > > + if (pci_is_pcie(pdev) && subdev->device->chipset >= 0x84) { + /* > 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); + }Please introduce a .init() to nvkm_pci_func(), and implement a g84.c that handles this (gf100.c can use g84_pci_init() from there). The check for PCI-E is redundant too, all these boards are PCI-E. Other than the above nit-picking, looks fine. Thanks, Ben.> + pci->irq = pdev->irq; return ret; } >
Pierre Moreau
2015-Sep-30 20:51 UTC
[Nouveau] [PATCH v4] pci: Handle 5-bit and 8-bit tag field
If the hardware supports extended tag field (8-bit ones), then enabled it. This is usually done by the VBIOS, but not on some MBPs (see fdo#86537). In case extended tag field is not supported, 5-bit tag field is used which limits the possible values to 32. Apparently bits 7:0 of 0x8841c stores some number of outstanding requests, so cap it to 32 if extended tag is unsupported. Fixes: fdo#86537 v2: Restrict changes to chipsets >= 0x84 v3: * Add nvkm_pci_mask to pci.h * Mask bit 8 before setting it v4: * Rename `add` argument of nvkm_pci_mask to `value` * Move code from nvkm_pci_init to g84_pci_init and remove PCIe and chipset checks Signed-off-by: Pierre Moreau <pierre.morrow at free.fr> --- drm/nouveau/include/nvkm/subdev/pci.h | 4 +++ drm/nouveau/nvkm/engine/device/base.c | 64 +++++++++++++++++------------------ drm/nouveau/nvkm/subdev/pci/Kbuild | 1 + drm/nouveau/nvkm/subdev/pci/base.c | 43 ++++++++++++++++++++--- drm/nouveau/nvkm/subdev/pci/g84.c | 55 ++++++++++++++++++++++++++++++ drm/nouveau/nvkm/subdev/pci/gf100.c | 6 ++++ drm/nouveau/nvkm/subdev/pci/nv40.c | 6 ++++ drm/nouveau/nvkm/subdev/pci/nv50.c | 6 ++++ drm/nouveau/nvkm/subdev/pci/priv.h | 11 ++++++ 9 files changed, 159 insertions(+), 37 deletions(-) create mode 100644 drm/nouveau/nvkm/subdev/pci/g84.c diff --git a/drm/nouveau/include/nvkm/subdev/pci.h b/drm/nouveau/include/nvkm/subdev/pci.h index 5b3c054..ab79fd0 100644 --- a/drm/nouveau/include/nvkm/subdev/pci.h +++ b/drm/nouveau/include/nvkm/subdev/pci.h @@ -24,11 +24,15 @@ struct nvkm_pci { u32 nvkm_pci_rd32(struct nvkm_pci *, u16 addr); void nvkm_pci_wr08(struct nvkm_pci *, u16 addr, u8 data); void nvkm_pci_wr32(struct nvkm_pci *, u16 addr, u32 data); +u32 nvkm_pci_mask(struct nvkm_pci *, u16 addr, u32 mask, u32 value); void nvkm_pci_rom_shadow(struct nvkm_pci *, bool shadow); int nv04_pci_new(struct nvkm_device *, int, struct nvkm_pci **); int nv40_pci_new(struct nvkm_device *, int, struct nvkm_pci **); +int nv40_pci_new_g84_init(struct nvkm_device *, int, struct nvkm_pci **); int nv4c_pci_new(struct nvkm_device *, int, struct nvkm_pci **); int nv50_pci_new(struct nvkm_device *, int, struct nvkm_pci **); +int nv50_pci_new_g84_init(struct nvkm_device *, int, struct nvkm_pci **); int gf100_pci_new(struct nvkm_device *, int, struct nvkm_pci **); +int gf100_pci_new_g84_init(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 acc2fe9..9b19b52 100644 --- a/drm/nouveau/nvkm/engine/device/base.c +++ b/drm/nouveau/nvkm/engine/device/base.c @@ -929,7 +929,7 @@ nv84_chipset = { .mc = nv50_mc_new, .mmu = nv50_mmu_new, .mxm = nv50_mxm_new, - .pci = nv50_pci_new, + .pci = nv50_pci_new_g84_init, .therm = g84_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, @@ -961,7 +961,7 @@ nv86_chipset = { .mc = nv50_mc_new, .mmu = nv50_mmu_new, .mxm = nv50_mxm_new, - .pci = nv50_pci_new, + .pci = nv50_pci_new_g84_init, .therm = g84_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, @@ -993,7 +993,7 @@ nv92_chipset = { .mc = nv50_mc_new, .mmu = nv50_mmu_new, .mxm = nv50_mxm_new, - .pci = nv50_pci_new, + .pci = nv50_pci_new_g84_init, .therm = g84_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, @@ -1025,7 +1025,7 @@ nv94_chipset = { .mc = nv50_mc_new, .mmu = nv50_mmu_new, .mxm = nv50_mxm_new, - .pci = nv40_pci_new, + .pci = nv40_pci_new_g84_init, .therm = g84_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, @@ -1057,7 +1057,7 @@ nv96_chipset = { .mc = nv50_mc_new, .mmu = nv50_mmu_new, .mxm = nv50_mxm_new, - .pci = nv40_pci_new, + .pci = nv40_pci_new_g84_init, .therm = g84_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, @@ -1089,7 +1089,7 @@ nv98_chipset = { .mc = g98_mc_new, .mmu = nv50_mmu_new, .mxm = nv50_mxm_new, - .pci = nv40_pci_new, + .pci = nv40_pci_new_g84_init, .therm = g84_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, @@ -1121,7 +1121,7 @@ nva0_chipset = { .mc = g98_mc_new, .mmu = nv50_mmu_new, .mxm = nv50_mxm_new, - .pci = nv40_pci_new, + .pci = nv40_pci_new_g84_init, .therm = g84_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, @@ -1153,7 +1153,7 @@ nva3_chipset = { .mc = g98_mc_new, .mmu = nv50_mmu_new, .mxm = nv50_mxm_new, - .pci = nv40_pci_new, + .pci = nv40_pci_new_g84_init, .pmu = gt215_pmu_new, .therm = gt215_therm_new, .timer = nv41_timer_new, @@ -1187,7 +1187,7 @@ nva5_chipset = { .mc = g98_mc_new, .mmu = nv50_mmu_new, .mxm = nv50_mxm_new, - .pci = nv40_pci_new, + .pci = nv40_pci_new_g84_init, .pmu = gt215_pmu_new, .therm = gt215_therm_new, .timer = nv41_timer_new, @@ -1220,7 +1220,7 @@ nva8_chipset = { .mc = g98_mc_new, .mmu = nv50_mmu_new, .mxm = nv50_mxm_new, - .pci = nv40_pci_new, + .pci = nv40_pci_new_g84_init, .pmu = gt215_pmu_new, .therm = gt215_therm_new, .timer = nv41_timer_new, @@ -1253,7 +1253,7 @@ nvaa_chipset = { .mc = g98_mc_new, .mmu = nv50_mmu_new, .mxm = nv50_mxm_new, - .pci = nv40_pci_new, + .pci = nv40_pci_new_g84_init, .therm = g84_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, @@ -1285,7 +1285,7 @@ nvac_chipset = { .mc = g98_mc_new, .mmu = nv50_mmu_new, .mxm = nv50_mxm_new, - .pci = nv40_pci_new, + .pci = nv40_pci_new_g84_init, .therm = g84_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, @@ -1317,7 +1317,7 @@ nvaf_chipset = { .mc = g98_mc_new, .mmu = nv50_mmu_new, .mxm = nv50_mxm_new, - .pci = nv40_pci_new, + .pci = nv40_pci_new_g84_init, .pmu = gt215_pmu_new, .therm = gt215_therm_new, .timer = nv41_timer_new, @@ -1352,7 +1352,7 @@ nvc0_chipset = { .mc = gf100_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, - .pci = gf100_pci_new, + .pci = gf100_pci_new_g84_init, .pmu = gf100_pmu_new, .therm = gt215_therm_new, .timer = nv41_timer_new, @@ -1388,7 +1388,7 @@ nvc1_chipset = { .mc = gf100_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, - .pci = nv40_pci_new, + .pci = nv40_pci_new_g84_init, .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 = nv40_pci_new, + .pci = nv40_pci_new_g84_init, .pmu = gf100_pmu_new, .therm = gt215_therm_new, .timer = nv41_timer_new, @@ -1458,7 +1458,7 @@ nvc4_chipset = { .mc = gf100_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, - .pci = gf100_pci_new, + .pci = gf100_pci_new_g84_init, .pmu = gf100_pmu_new, .therm = gt215_therm_new, .timer = nv41_timer_new, @@ -1494,7 +1494,7 @@ nvc8_chipset = { .mc = gf100_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, - .pci = gf100_pci_new, + .pci = gf100_pci_new_g84_init, .pmu = gf100_pmu_new, .therm = gt215_therm_new, .timer = nv41_timer_new, @@ -1530,7 +1530,7 @@ nvce_chipset = { .mc = gf100_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, - .pci = gf100_pci_new, + .pci = gf100_pci_new_g84_init, .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 = nv40_pci_new, + .pci = nv40_pci_new_g84_init, .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 = nv40_pci_new, + .pci = nv40_pci_new_g84_init, .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 = nv40_pci_new, + .pci = nv40_pci_new_g84_init, .pmu = gf119_pmu_new, .therm = gf119_therm_new, .timer = nv41_timer_new, @@ -1669,7 +1669,7 @@ nve4_chipset = { .mc = gf100_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, - .pci = nv40_pci_new, + .pci = nv40_pci_new_g84_init, .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 = nv40_pci_new, + .pci = nv40_pci_new_g84_init, .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 = nv40_pci_new, + .pci = nv40_pci_new_g84_init, .pmu = gf119_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 = nv40_pci_new, + .pci = nv40_pci_new_g84_init, .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 = nv40_pci_new, + .pci = nv40_pci_new_g84_init, .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 = nv40_pci_new, + .pci = nv40_pci_new_g84_init, .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 = nv40_pci_new, + .pci = nv40_pci_new_g84_init, .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 = nv40_pci_new, + .pci = nv40_pci_new_g84_init, .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 = nv40_pci_new, + .pci = nv40_pci_new_g84_init, .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 = nv40_pci_new, + .pci = nv40_pci_new_g84_init, .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 99672c3..57652f5 100644 --- a/drm/nouveau/nvkm/subdev/pci/Kbuild +++ b/drm/nouveau/nvkm/subdev/pci/Kbuild @@ -4,4 +4,5 @@ nvkm-y += nvkm/subdev/pci/nv04.o nvkm-y += nvkm/subdev/pci/nv40.o nvkm-y += nvkm/subdev/pci/nv4c.o nvkm-y += nvkm/subdev/pci/nv50.o +nvkm-y += nvkm/subdev/pci/g84.o nvkm-y += nvkm/subdev/pci/gf100.o diff --git a/drm/nouveau/nvkm/subdev/pci/base.c b/drm/nouveau/nvkm/subdev/pci/base.c index d1c148e..7ad4796 100644 --- a/drm/nouveau/nvkm/subdev/pci/base.c +++ b/drm/nouveau/nvkm/subdev/pci/base.c @@ -46,6 +46,14 @@ nvkm_pci_wr32(struct nvkm_pci *pci, u16 addr, u32 data) pci->func->wr32(pci, addr, data); } +u32 +nvkm_pci_mask(struct nvkm_pci *pci, u16 valuer, u32 mask, u32 value) +{ + u32 data = pci->func->rd32(pci, valuer); + pci->func->wr32(pci, valuer, (data & ~mask) | value); + return data; +} + void nvkm_pci_rom_shadow(struct nvkm_pci *pci, bool shadow) { @@ -73,7 +81,7 @@ nvkm_pci_intr(int irq, void *arg) return handled ? IRQ_HANDLED : IRQ_NONE; } -static int +int nvkm_pci_fini(struct nvkm_subdev *subdev, bool suspend) { struct nvkm_pci *pci = nvkm_pci(subdev); @@ -89,7 +97,7 @@ nvkm_pci_fini(struct nvkm_subdev *subdev, bool suspend) return 0; } -static int +int nvkm_pci_preinit(struct nvkm_subdev *subdev) { struct nvkm_pci *pci = nvkm_pci(subdev); @@ -98,7 +106,7 @@ nvkm_pci_preinit(struct nvkm_subdev *subdev) return 0; } -static int +int nvkm_pci_init(struct nvkm_subdev *subdev) { struct nvkm_pci *pci = nvkm_pci(subdev); @@ -115,11 +123,28 @@ nvkm_pci_init(struct nvkm_subdev *subdev) if (ret) return ret; + if (pci_is_pcie(pdev) && subdev->device->chipset >= 0x84) { + /* 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); + } + pci->irq = pdev->irq; return ret; } -static void * +void * nvkm_pci_dtor(struct nvkm_subdev *subdev) { struct nvkm_pci *pci = nvkm_pci(subdev); @@ -141,11 +166,19 @@ int nvkm_pci_new_(const struct nvkm_pci_func *func, struct nvkm_device *device, int index, struct nvkm_pci **ppci) { + return nvkm_pci_new(&nvkm_pci_func, func, device, index, ppci); +} + +int +nvkm_pci_new(const struct nvkm_subdev_func *subdev_func, + const struct nvkm_pci_func *func, struct nvkm_device *device, + int index, struct nvkm_pci **ppci) +{ struct nvkm_pci *pci; if (!(pci = *ppci = kzalloc(sizeof(**ppci), GFP_KERNEL))) return -ENOMEM; - nvkm_subdev_ctor(&nvkm_pci_func, device, index, 0, &pci->subdev); + nvkm_subdev_ctor(subdev_func, device, index, 0, &pci->subdev); pci->func = func; pci->pdev = device->func->pci(device)->pdev; pci->irq = -1; diff --git a/drm/nouveau/nvkm/subdev/pci/g84.c b/drm/nouveau/nvkm/subdev/pci/g84.c new file mode 100644 index 0000000..202c07a --- /dev/null +++ b/drm/nouveau/nvkm/subdev/pci/g84.c @@ -0,0 +1,55 @@ +/* + * 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 at redhat.com> + */ +#include "priv.h" + +int +g84_pci_init(struct nvkm_subdev *subdev) +{ + struct nvkm_pci *pci = nvkm_pci(subdev); + + /* 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); + + return nvkm_pci_init(subdev); +} + +const struct nvkm_subdev_func +g84_pci_func = { + .dtor = nvkm_pci_dtor, + .preinit = nvkm_pci_preinit, + .init = g84_pci_init, + .fini = nvkm_pci_fini, +}; diff --git a/drm/nouveau/nvkm/subdev/pci/gf100.c b/drm/nouveau/nvkm/subdev/pci/gf100.c index 86f8226..a836d5f 100644 --- a/drm/nouveau/nvkm/subdev/pci/gf100.c +++ b/drm/nouveau/nvkm/subdev/pci/gf100.c @@ -42,3 +42,9 @@ gf100_pci_new(struct nvkm_device *device, int index, struct nvkm_pci **ppci) { return nvkm_pci_new_(&gf100_pci_func, device, index, ppci); } + +int +gf100_pci_new_g84_init(struct nvkm_device *device, int index, struct nvkm_pci **ppci) +{ + return nvkm_pci_new(&g84_pci_func, &gf100_pci_func, device, index, ppci); +} diff --git a/drm/nouveau/nvkm/subdev/pci/nv40.c b/drm/nouveau/nvkm/subdev/pci/nv40.c index 090a187..5e2ef13 100644 --- a/drm/nouveau/nvkm/subdev/pci/nv40.c +++ b/drm/nouveau/nvkm/subdev/pci/nv40.c @@ -63,3 +63,9 @@ nv40_pci_new(struct nvkm_device *device, int index, struct nvkm_pci **ppci) { return nvkm_pci_new_(&nv40_pci_func, device, index, ppci); } + +int +nv40_pci_new_g84_init(struct nvkm_device *device, int index, struct nvkm_pci **ppci) +{ + return nvkm_pci_new(&g84_pci_func, &nv40_pci_func, device, index, ppci); +} diff --git a/drm/nouveau/nvkm/subdev/pci/nv50.c b/drm/nouveau/nvkm/subdev/pci/nv50.c index 3e167d4..998453e 100644 --- a/drm/nouveau/nvkm/subdev/pci/nv50.c +++ b/drm/nouveau/nvkm/subdev/pci/nv50.c @@ -49,3 +49,9 @@ nv50_pci_new(struct nvkm_device *device, int index, struct nvkm_pci **ppci) { return nvkm_pci_new_(&nv50_pci_func, device, index, ppci); } + +int +nv50_pci_new_g84_init(struct nvkm_device *device, int index, struct nvkm_pci **ppci) +{ + return nvkm_pci_new(&g84_pci_func, &nv50_pci_func, device, index, ppci); +} diff --git a/drm/nouveau/nvkm/subdev/pci/priv.h b/drm/nouveau/nvkm/subdev/pci/priv.h index d22c2c1..9615ae0 100644 --- a/drm/nouveau/nvkm/subdev/pci/priv.h +++ b/drm/nouveau/nvkm/subdev/pci/priv.h @@ -3,8 +3,17 @@ #define nvkm_pci(p) container_of((p), struct nvkm_pci, subdev) #include <subdev/pci.h> + + +int nvkm_pci_fini(struct nvkm_subdev *subdev, bool suspend); +int nvkm_pci_preinit(struct nvkm_subdev *subdev); +int nvkm_pci_init(struct nvkm_subdev *subdev); +void * nvkm_pci_dtor(struct nvkm_subdev *subdev); int nvkm_pci_new_(const struct nvkm_pci_func *, struct nvkm_device *, int index, struct nvkm_pci **); +int nvkm_pci_new(const struct nvkm_subdev_func *, + const struct nvkm_pci_func *, struct nvkm_device *, + int index, struct nvkm_pci **); struct nvkm_pci_func { u32 (*rd32)(struct nvkm_pci *, u16 addr); @@ -13,6 +22,8 @@ struct nvkm_pci_func { void (*msi_rearm)(struct nvkm_pci *); }; +extern const struct nvkm_subdev_func g84_pci_func; + u32 nv40_pci_rd32(struct nvkm_pci *, u16); void nv40_pci_wr08(struct nvkm_pci *, u16, u8); void nv40_pci_wr32(struct nvkm_pci *, u16, u32); -- 2.5.3
Pierre Moreau
2015-Oct-03 19:35 UTC
[Nouveau] [PATCH v5] pci: Handle 5-bit and 8-bit tag field
If the hardware supports extended tag field (8-bit ones), then enable it. This is usually done by the VBIOS, but not on some MBPs (see fdo#86537). In case extended tag field is not supported, 5-bit tag field is used which limits the possible number of requests to 32. Apparently bits 7:0 of 0x08841c stores some number of outstanding requests, so cap it to 32 if extended tag is unsupported. Fixes: fdo#86537 v2: Restrict changes to chipsets >= 0x84 v3: * Add nvkm_pci_mask to pci.h * Mask bit 8 before setting it v4: * Rename `add` argument of nvkm_pci_mask to `value` * Move code from nvkm_pci_init to g84_pci_init and remove PCIe and chipset checks v5: * Rebase code on latest PCI structure * Restore PCIe check * Fix namings in nvkm_pci_mask * Rephrase part of the commit message Signed-off-by: Pierre Moreau <pierre.morrow at free.fr> --- drm/nouveau/include/nvkm/subdev/pci.h | 1 + drm/nouveau/nvkm/subdev/pci/base.c | 8 ++++++++ drm/nouveau/nvkm/subdev/pci/g84.c | 24 ++++++++++++++++++++++++ drm/nouveau/nvkm/subdev/pci/g94.c | 1 + drm/nouveau/nvkm/subdev/pci/gf100.c | 1 + drm/nouveau/nvkm/subdev/pci/priv.h | 2 ++ 6 files changed, 37 insertions(+) diff --git a/drm/nouveau/include/nvkm/subdev/pci.h b/drm/nouveau/include/nvkm/subdev/pci.h index 39ca88f..fee0a97 100644 --- a/drm/nouveau/include/nvkm/subdev/pci.h +++ b/drm/nouveau/include/nvkm/subdev/pci.h @@ -24,6 +24,7 @@ struct nvkm_pci { u32 nvkm_pci_rd32(struct nvkm_pci *, u16 addr); void nvkm_pci_wr08(struct nvkm_pci *, u16 addr, u8 data); void nvkm_pci_wr32(struct nvkm_pci *, u16 addr, u32 data); +u32 nvkm_pci_mask(struct nvkm_pci *, u16 addr, u32 mask, u32 value); void nvkm_pci_rom_shadow(struct nvkm_pci *, bool shadow); int nv04_pci_new(struct nvkm_device *, int, struct nvkm_pci **); diff --git a/drm/nouveau/nvkm/subdev/pci/base.c b/drm/nouveau/nvkm/subdev/pci/base.c index 2110622..d671dcf 100644 --- a/drm/nouveau/nvkm/subdev/pci/base.c +++ b/drm/nouveau/nvkm/subdev/pci/base.c @@ -46,6 +46,14 @@ nvkm_pci_wr32(struct nvkm_pci *pci, u16 addr, u32 data) pci->func->wr32(pci, addr, data); } +u32 +nvkm_pci_mask(struct nvkm_pci *pci, u16 addr, u32 mask, u32 value) +{ + u32 data = pci->func->rd32(pci, addr); + pci->func->wr32(pci, addr, (data & ~mask) | value); + return data; +} + void nvkm_pci_rom_shadow(struct nvkm_pci *pci, bool shadow) { diff --git a/drm/nouveau/nvkm/subdev/pci/g84.c b/drm/nouveau/nvkm/subdev/pci/g84.c index 8f3b001..3faa6bf 100644 --- a/drm/nouveau/nvkm/subdev/pci/g84.c +++ b/drm/nouveau/nvkm/subdev/pci/g84.c @@ -25,8 +25,32 @@ #include <core/pci.h> +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); +} + static const struct nvkm_pci_func g84_pci_func = { + .init = g84_pci_init, .rd32 = nv40_pci_rd32, .wr08 = nv40_pci_wr08, .wr32 = nv40_pci_wr32, diff --git a/drm/nouveau/nvkm/subdev/pci/g94.c b/drm/nouveau/nvkm/subdev/pci/g94.c index 1714421..cd311ee 100644 --- a/drm/nouveau/nvkm/subdev/pci/g94.c +++ b/drm/nouveau/nvkm/subdev/pci/g94.c @@ -25,6 +25,7 @@ static const struct nvkm_pci_func g94_pci_func = { + .init = g84_pci_init, .rd32 = nv40_pci_rd32, .wr08 = nv40_pci_wr08, .wr32 = nv40_pci_wr32, diff --git a/drm/nouveau/nvkm/subdev/pci/gf100.c b/drm/nouveau/nvkm/subdev/pci/gf100.c index 86f8226..25e1ae7 100644 --- a/drm/nouveau/nvkm/subdev/pci/gf100.c +++ b/drm/nouveau/nvkm/subdev/pci/gf100.c @@ -31,6 +31,7 @@ gf100_pci_msi_rearm(struct nvkm_pci *pci) static const struct nvkm_pci_func gf100_pci_func = { + .init = g84_pci_init, .rd32 = nv40_pci_rd32, .wr08 = nv40_pci_wr08, .wr32 = nv40_pci_wr32, diff --git a/drm/nouveau/nvkm/subdev/pci/priv.h b/drm/nouveau/nvkm/subdev/pci/priv.h index 1acd4bc..cf46d38 100644 --- a/drm/nouveau/nvkm/subdev/pci/priv.h +++ b/drm/nouveau/nvkm/subdev/pci/priv.h @@ -20,4 +20,6 @@ void nv40_pci_wr32(struct nvkm_pci *, u16, u32); void nv40_pci_msi_rearm(struct nvkm_pci *); void nv46_pci_msi_rearm(struct nvkm_pci *); + +void g84_pci_init(struct nvkm_pci *pci); #endif -- 2.6.0