mirror of https://gitee.com/openkylin/linux.git
drm/nouveau/pci: merge agp handling from nouveau drm
This commit reinstates the pre-DEVINIT AGP fiddling that was broken in an earlier commit. Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
This commit is contained in:
parent
26c9e8effe
commit
340b0e7c50
|
@ -18,7 +18,6 @@ nouveau-y += $(nvkm-y)
|
|||
ifdef CONFIG_X86
|
||||
nouveau-$(CONFIG_ACPI) += nouveau_acpi.o
|
||||
endif
|
||||
nouveau-y += nouveau_agp.o
|
||||
nouveau-$(CONFIG_DEBUG_FS) += nouveau_debugfs.o
|
||||
nouveau-y += nouveau_drm.o
|
||||
nouveau-y += nouveau_hwmon.o
|
||||
|
|
|
@ -45,6 +45,7 @@ u64 nvif_device_time(struct nvif_device *);
|
|||
#include <subdev/i2c.h>
|
||||
#include <subdev/timer.h>
|
||||
#include <subdev/therm.h>
|
||||
#include <subdev/pci.h>
|
||||
|
||||
#define nvxx_device(a) ({ \
|
||||
struct nvif_device *_device = (a); \
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <linux/power_supply.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/agp_backend.h>
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
const char *nvkm_stropt(const char *optstr, const char *opt, int *len);
|
||||
bool nvkm_boolopt(const char *optstr, const char *opt, bool value);
|
||||
long nvkm_longopt(const char *optstr, const char *opt, long value);
|
||||
int nvkm_dbgopt(const char *optstr, const char *sub);
|
||||
|
||||
/* compares unterminated string 'str' with zero-terminated string 'cmp' */
|
||||
|
|
|
@ -7,6 +7,17 @@ struct nvkm_pci {
|
|||
struct nvkm_subdev subdev;
|
||||
struct pci_dev *pdev;
|
||||
int irq;
|
||||
|
||||
struct {
|
||||
struct agp_bridge_data *bridge;
|
||||
u32 mode;
|
||||
u64 base;
|
||||
u64 size;
|
||||
int mtrr;
|
||||
bool cma;
|
||||
bool acquired;
|
||||
} agp;
|
||||
|
||||
bool msi;
|
||||
};
|
||||
|
||||
|
|
|
@ -498,7 +498,7 @@ nouveau_abi16_ioctl_notifierobj_alloc(ABI16_IOCTL_ARGS)
|
|||
args.start += chan->ntfy_vma.offset;
|
||||
args.limit += chan->ntfy_vma.offset;
|
||||
} else
|
||||
if (drm->agp.stat == ENABLED) {
|
||||
if (drm->agp.bridge) {
|
||||
args.target = NV_DMA_V0_TARGET_AGP;
|
||||
args.access = NV_DMA_V0_ACCESS_RDWR;
|
||||
args.start += drm->agp.base + chan->ntfy->bo.offset;
|
||||
|
|
|
@ -1,198 +0,0 @@
|
|||
#include <linux/module.h>
|
||||
|
||||
#include "nouveau_drm.h"
|
||||
#include "nouveau_agp.h"
|
||||
#include "nouveau_reg.h"
|
||||
|
||||
#include <core/pci.h>
|
||||
|
||||
#if __OS_HAS_AGP
|
||||
MODULE_PARM_DESC(agpmode, "AGP mode (0 to disable AGP)");
|
||||
static int nouveau_agpmode = -1;
|
||||
module_param_named(agpmode, nouveau_agpmode, int, 0400);
|
||||
|
||||
struct nouveau_agpmode_quirk {
|
||||
u16 hostbridge_vendor;
|
||||
u16 hostbridge_device;
|
||||
u16 chip_vendor;
|
||||
u16 chip_device;
|
||||
int mode;
|
||||
};
|
||||
|
||||
static struct nouveau_agpmode_quirk nouveau_agpmode_quirk_list[] = {
|
||||
/* VIA Apollo PRO133x / GeForce FX 5600 Ultra, max agpmode 2, fdo #20341 */
|
||||
{ PCI_VENDOR_ID_VIA, 0x0691, PCI_VENDOR_ID_NVIDIA, 0x0311, 2 },
|
||||
|
||||
{},
|
||||
};
|
||||
|
||||
static unsigned long
|
||||
get_agp_mode(struct nouveau_drm *drm, const struct drm_agp_info *info)
|
||||
{
|
||||
struct nvif_device *device = &drm->device;
|
||||
struct pci_dev *pdev = nvxx_device(device)->func->pci(nvxx_device(device))->pdev;
|
||||
struct nouveau_agpmode_quirk *quirk = nouveau_agpmode_quirk_list;
|
||||
int agpmode = nouveau_agpmode;
|
||||
unsigned long mode = info->mode;
|
||||
|
||||
/*
|
||||
* FW seems to be broken on nv18, it makes the card lock up
|
||||
* randomly.
|
||||
*/
|
||||
if (device->info.chipset == 0x18)
|
||||
mode &= ~PCI_AGP_COMMAND_FW;
|
||||
|
||||
/*
|
||||
* Go through the quirks list and adjust the agpmode accordingly.
|
||||
*/
|
||||
while (agpmode == -1 && quirk->hostbridge_vendor) {
|
||||
if (info->id_vendor == quirk->hostbridge_vendor &&
|
||||
info->id_device == quirk->hostbridge_device &&
|
||||
pdev->vendor == quirk->chip_vendor &&
|
||||
pdev->device == quirk->chip_device) {
|
||||
agpmode = quirk->mode;
|
||||
NV_INFO(drm, "Forcing agp mode to %dX. Use agpmode to override.\n",
|
||||
agpmode);
|
||||
break;
|
||||
}
|
||||
++quirk;
|
||||
}
|
||||
|
||||
/*
|
||||
* AGP mode set in the command line.
|
||||
*/
|
||||
if (agpmode > 0) {
|
||||
bool agpv3 = mode & 0x8;
|
||||
int rate = agpv3 ? agpmode / 4 : agpmode;
|
||||
|
||||
mode = (mode & ~0x7) | (rate & 0x7);
|
||||
}
|
||||
|
||||
return mode;
|
||||
}
|
||||
|
||||
static bool
|
||||
nouveau_agp_enabled(struct nouveau_drm *drm)
|
||||
{
|
||||
struct drm_device *dev = drm->dev;
|
||||
|
||||
if (!dev->pdev || !drm_pci_device_is_agp(dev) || !dev->agp)
|
||||
return false;
|
||||
|
||||
if (drm->agp.stat == UNKNOWN) {
|
||||
if (!nouveau_agpmode)
|
||||
return false;
|
||||
#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
|
||||
* the GATT somehow, making them quite painful to deal
|
||||
* with...
|
||||
*/
|
||||
if (nouveau_agpmode == -1)
|
||||
return false;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
return (drm->agp.stat == ENABLED);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
nouveau_agp_reset(struct nouveau_drm *drm)
|
||||
{
|
||||
#if __OS_HAS_AGP
|
||||
struct nvif_object *device = &drm->device.object;
|
||||
struct drm_device *dev = drm->dev;
|
||||
u32 save[2];
|
||||
int ret;
|
||||
|
||||
if (!nouveau_agp_enabled(drm))
|
||||
return;
|
||||
|
||||
/* 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 ((nvif_rd32(device, NV04_PBUS_PCI_NV_19) |
|
||||
dev->agp->mode) & PCI_AGP_COMMAND_FW) {
|
||||
struct drm_agp_info info;
|
||||
struct drm_agp_mode mode;
|
||||
|
||||
ret = drm_agp_info(dev, &info);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
mode.mode = get_agp_mode(drm, &info);
|
||||
mode.mode &= ~PCI_AGP_COMMAND_FW;
|
||||
|
||||
ret = drm_agp_enable(dev, mode);
|
||||
if (ret)
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* clear busmaster bit, and disable AGP */
|
||||
save[0] = nvif_mask(device, NV04_PBUS_PCI_NV_1, 0x00000004, 0x00000000);
|
||||
nvif_wr32(device, NV04_PBUS_PCI_NV_19, 0);
|
||||
|
||||
/* reset PGRAPH, PFIFO and PTIMER */
|
||||
save[1] = nvif_mask(device, 0x000200, 0x00011100, 0x00000000);
|
||||
nvif_mask(device, 0x000200, 0x00011100, save[1]);
|
||||
|
||||
/* and restore bustmaster bit (gives effect of resetting AGP) */
|
||||
nvif_wr32(device, NV04_PBUS_PCI_NV_1, save[0]);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_agp_init(struct nouveau_drm *drm)
|
||||
{
|
||||
#if __OS_HAS_AGP
|
||||
struct drm_device *dev = drm->dev;
|
||||
struct drm_agp_info info;
|
||||
struct drm_agp_mode mode;
|
||||
int ret;
|
||||
|
||||
if (!nouveau_agp_enabled(drm))
|
||||
return;
|
||||
drm->agp.stat = DISABLE;
|
||||
|
||||
ret = drm_agp_acquire(dev);
|
||||
if (ret) {
|
||||
NV_ERROR(drm, "unable to acquire AGP: %d\n", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = drm_agp_info(dev, &info);
|
||||
if (ret) {
|
||||
NV_ERROR(drm, "unable to get AGP info: %d\n", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
/* see agp.h for the AGPSTAT_* modes available */
|
||||
mode.mode = get_agp_mode(drm, &info);
|
||||
|
||||
ret = drm_agp_enable(dev, mode);
|
||||
if (ret) {
|
||||
NV_ERROR(drm, "unable to enable AGP: %d\n", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
drm->agp.stat = ENABLED;
|
||||
drm->agp.base = info.aperture_base;
|
||||
drm->agp.size = info.aperture_size;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_agp_fini(struct nouveau_drm *drm)
|
||||
{
|
||||
#if __OS_HAS_AGP
|
||||
struct drm_device *dev = drm->dev;
|
||||
if (dev->agp && dev->agp->acquired)
|
||||
drm_agp_release(dev);
|
||||
#endif
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
#ifndef __NOUVEAU_AGP_H__
|
||||
#define __NOUVEAU_AGP_H__
|
||||
|
||||
struct nouveau_drm;
|
||||
|
||||
void nouveau_agp_reset(struct nouveau_drm *);
|
||||
void nouveau_agp_init(struct nouveau_drm *);
|
||||
void nouveau_agp_fini(struct nouveau_drm *);
|
||||
|
||||
#endif
|
|
@ -576,10 +576,9 @@ nouveau_ttm_tt_create(struct ttm_bo_device *bdev, unsigned long size,
|
|||
{
|
||||
#if __OS_HAS_AGP
|
||||
struct nouveau_drm *drm = nouveau_bdev(bdev);
|
||||
struct drm_device *dev = drm->dev;
|
||||
|
||||
if (drm->agp.stat == ENABLED) {
|
||||
return ttm_agp_tt_create(bdev, dev->agp->bridge, size,
|
||||
if (drm->agp.bridge) {
|
||||
return ttm_agp_tt_create(bdev, drm->agp.bridge, size,
|
||||
page_flags, dummy_read);
|
||||
}
|
||||
#endif
|
||||
|
@ -631,12 +630,12 @@ nouveau_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
|
|||
if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA)
|
||||
man->func = &nouveau_gart_manager;
|
||||
else
|
||||
if (drm->agp.stat != ENABLED)
|
||||
if (!drm->agp.bridge)
|
||||
man->func = &nv04_gart_manager;
|
||||
else
|
||||
man->func = &ttm_bo_manager_func;
|
||||
|
||||
if (drm->agp.stat == ENABLED) {
|
||||
if (drm->agp.bridge) {
|
||||
man->flags = TTM_MEMTYPE_FLAG_MAPPABLE;
|
||||
man->available_caching = TTM_PL_FLAG_UNCACHED |
|
||||
TTM_PL_FLAG_WC;
|
||||
|
@ -1368,10 +1367,10 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
|
|||
return 0;
|
||||
case TTM_PL_TT:
|
||||
#if __OS_HAS_AGP
|
||||
if (drm->agp.stat == ENABLED) {
|
||||
if (drm->agp.bridge) {
|
||||
mem->bus.offset = mem->start << PAGE_SHIFT;
|
||||
mem->bus.base = drm->agp.base;
|
||||
mem->bus.is_iomem = !drm->dev->agp->cant_use_aperture;
|
||||
mem->bus.is_iomem = !drm->agp.cma;
|
||||
}
|
||||
#endif
|
||||
if (drm->device.info.family < NV_DEVICE_INFO_V0_TESLA || !node->memtype)
|
||||
|
@ -1498,7 +1497,7 @@ nouveau_ttm_tt_populate(struct ttm_tt *ttm)
|
|||
return ttm_dma_populate(ttm_dma, dev->dev);
|
||||
|
||||
#if __OS_HAS_AGP
|
||||
if (drm->agp.stat == ENABLED) {
|
||||
if (drm->agp.bridge) {
|
||||
return ttm_agp_tt_populate(ttm);
|
||||
}
|
||||
#endif
|
||||
|
@ -1565,7 +1564,7 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm)
|
|||
}
|
||||
|
||||
#if __OS_HAS_AGP
|
||||
if (drm->agp.stat == ENABLED) {
|
||||
if (drm->agp.bridge) {
|
||||
ttm_agp_tt_unpopulate(ttm);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -160,7 +160,7 @@ nouveau_channel_prep(struct nouveau_drm *drm, struct nvif_device *device,
|
|||
args.limit = device->info.ram_user - 1;
|
||||
}
|
||||
} else {
|
||||
if (chan->drm->agp.stat == ENABLED) {
|
||||
if (chan->drm->agp.bridge) {
|
||||
args.target = NV_DMA_V0_TARGET_AGP;
|
||||
args.access = NV_DMA_V0_ACCESS_RDWR;
|
||||
args.start = chan->drm->agp.base;
|
||||
|
@ -328,7 +328,7 @@ nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart)
|
|||
args.start = 0;
|
||||
args.limit = cli->vm->mmu->limit - 1;
|
||||
} else
|
||||
if (chan->drm->agp.stat == ENABLED) {
|
||||
if (chan->drm->agp.bridge) {
|
||||
args.target = NV_DMA_V0_TARGET_AGP;
|
||||
args.access = NV_DMA_V0_ACCESS_RDWR;
|
||||
args.start = chan->drm->agp.base;
|
||||
|
|
|
@ -41,7 +41,6 @@
|
|||
#include "nouveau_dma.h"
|
||||
#include "nouveau_ttm.h"
|
||||
#include "nouveau_gem.h"
|
||||
#include "nouveau_agp.h"
|
||||
#include "nouveau_vga.h"
|
||||
#include "nouveau_sysfs.h"
|
||||
#include "nouveau_hwmon.h"
|
||||
|
@ -423,7 +422,6 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags)
|
|||
nvif_mask(&drm->device.object, 0x00088080, 0x00000800, 0x00000000);
|
||||
|
||||
nouveau_vga_init(drm);
|
||||
nouveau_agp_init(drm);
|
||||
|
||||
if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) {
|
||||
ret = nvkm_vm_new(nvxx_device(&drm->device), 0, (1ULL << 40),
|
||||
|
@ -474,7 +472,6 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags)
|
|||
fail_bios:
|
||||
nouveau_ttm_fini(drm);
|
||||
fail_ttm:
|
||||
nouveau_agp_fini(drm);
|
||||
nouveau_vga_fini(drm);
|
||||
fail_device:
|
||||
nvif_device_fini(&drm->device);
|
||||
|
@ -500,7 +497,6 @@ nouveau_drm_unload(struct drm_device *dev)
|
|||
nouveau_bios_takedown(dev);
|
||||
|
||||
nouveau_ttm_fini(drm);
|
||||
nouveau_agp_fini(drm);
|
||||
nouveau_vga_fini(drm);
|
||||
|
||||
nvif_device_fini(&drm->device);
|
||||
|
@ -584,7 +580,6 @@ nouveau_do_suspend(struct drm_device *dev, bool runtime)
|
|||
if (ret)
|
||||
goto fail_client;
|
||||
|
||||
nouveau_agp_fini(drm);
|
||||
return 0;
|
||||
|
||||
fail_client:
|
||||
|
@ -609,13 +604,8 @@ nouveau_do_resume(struct drm_device *dev, bool runtime)
|
|||
struct nouveau_drm *drm = nouveau_drm(dev);
|
||||
struct nouveau_cli *cli;
|
||||
|
||||
NV_INFO(drm, "re-enabling device...\n");
|
||||
|
||||
nouveau_agp_reset(drm);
|
||||
|
||||
NV_INFO(drm, "resuming kernel object tree...\n");
|
||||
nvif_client_resume(&drm->client.base);
|
||||
nouveau_agp_init(drm);
|
||||
|
||||
NV_INFO(drm, "resuming client object trees...\n");
|
||||
if (drm->fence && nouveau_fence(drm)->resume)
|
||||
|
@ -929,7 +919,6 @@ nouveau_driver_fops = {
|
|||
static struct drm_driver
|
||||
driver_stub = {
|
||||
.driver_features =
|
||||
DRIVER_USE_AGP |
|
||||
DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | DRIVER_RENDER |
|
||||
DRIVER_KMS_LEGACY_CONTEXT,
|
||||
|
||||
|
|
|
@ -111,13 +111,10 @@ struct nouveau_drm {
|
|||
struct list_head clients;
|
||||
|
||||
struct {
|
||||
enum {
|
||||
UNKNOWN = 0,
|
||||
DISABLE = 1,
|
||||
ENABLED = 2
|
||||
} stat;
|
||||
struct agp_bridge_data *bridge;
|
||||
u32 base;
|
||||
u32 size;
|
||||
bool cma;
|
||||
} agp;
|
||||
|
||||
/* TTM interface support */
|
||||
|
|
|
@ -336,13 +336,21 @@ int
|
|||
nouveau_ttm_init(struct nouveau_drm *drm)
|
||||
{
|
||||
struct nvkm_device *device = nvxx_device(&drm->device);
|
||||
struct nvkm_pci *pci = device->pci;
|
||||
struct drm_device *dev = drm->dev;
|
||||
u32 bits;
|
||||
int ret;
|
||||
|
||||
if (pci && pci->agp.bridge) {
|
||||
drm->agp.bridge = pci->agp.bridge;
|
||||
drm->agp.base = pci->agp.base;
|
||||
drm->agp.size = pci->agp.size;
|
||||
drm->agp.cma = pci->agp.cma;
|
||||
}
|
||||
|
||||
bits = nvxx_mmu(&drm->device)->dma_bits;
|
||||
if (nvxx_device(&drm->device)->func->pci) {
|
||||
if (drm->agp.stat == ENABLED ||
|
||||
if (drm->agp.bridge ||
|
||||
!pci_dma_supported(dev->pdev, DMA_BIT_MASK(bits)))
|
||||
bits = 32;
|
||||
|
||||
|
@ -386,7 +394,7 @@ nouveau_ttm_init(struct nouveau_drm *drm)
|
|||
device->func->resource_size(device, 1));
|
||||
|
||||
/* GART init */
|
||||
if (drm->agp.stat != ENABLED) {
|
||||
if (!drm->agp.bridge) {
|
||||
drm->gem.gart_available = nvxx_mmu(&drm->device)->limit;
|
||||
} else {
|
||||
drm->gem.gart_available = drm->agp.size;
|
||||
|
|
|
@ -73,6 +73,24 @@ nvkm_boolopt(const char *optstr, const char *opt, bool value)
|
|||
return value;
|
||||
}
|
||||
|
||||
long
|
||||
nvkm_longopt(const char *optstr, const char *opt, long value)
|
||||
{
|
||||
long result = value;
|
||||
int arglen;
|
||||
char *s;
|
||||
|
||||
optstr = nvkm_stropt(optstr, opt, &arglen);
|
||||
if (optstr && (s = kstrndup(optstr, arglen, GFP_KERNEL))) {
|
||||
int ret = kstrtol(s, 0, &value);
|
||||
if (ret == 0)
|
||||
result = value;
|
||||
kfree(s);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int
|
||||
nvkm_dbgopt(const char *optstr, const char *sub)
|
||||
{
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
nvkm-y += nvkm/subdev/pci/agp.o
|
||||
nvkm-y += nvkm/subdev/pci/base.o
|
||||
nvkm-y += nvkm/subdev/pci/nv04.o
|
||||
nvkm-y += nvkm/subdev/pci/nv40.o
|
||||
|
|
|
@ -0,0 +1,171 @@
|
|||
/*
|
||||
* 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 },
|
||||
{},
|
||||
};
|
||||
|
||||
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 &&
|
||||
pci->pdev->vendor == quirk->chip_vendor &&
|
||||
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,18 @@
|
|||
#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
|
|
@ -22,6 +22,7 @@
|
|||
* Authors: Ben Skeggs <bskeggs@redhat.com>
|
||||
*/
|
||||
#include "priv.h"
|
||||
#include "agp.h"
|
||||
|
||||
#include <core/option.h>
|
||||
#include <core/pci.h>
|
||||
|
@ -76,10 +77,24 @@ static int
|
|||
nvkm_pci_fini(struct nvkm_subdev *subdev, bool suspend)
|
||||
{
|
||||
struct nvkm_pci *pci = nvkm_pci(subdev);
|
||||
|
||||
if (pci->irq >= 0) {
|
||||
free_irq(pci->irq, pci);
|
||||
pci->irq = -1;
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -90,6 +105,12 @@ nvkm_pci_init(struct nvkm_subdev *subdev)
|
|||
struct pci_dev *pdev = pci->pdev;
|
||||
int ret;
|
||||
|
||||
if (pci->agp.bridge) {
|
||||
ret = nvkm_agp_init(pci);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = request_irq(pdev->irq, nvkm_pci_intr, IRQF_SHARED, "nvkm", pci);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -102,6 +123,7 @@ 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);
|
||||
|
@ -110,6 +132,7 @@ nvkm_pci_dtor(struct nvkm_subdev *subdev)
|
|||
static const struct nvkm_subdev_func
|
||||
nvkm_pci_func = {
|
||||
.dtor = nvkm_pci_dtor,
|
||||
.preinit = nvkm_pci_preinit,
|
||||
.init = nvkm_pci_init,
|
||||
.fini = nvkm_pci_fini,
|
||||
};
|
||||
|
@ -127,6 +150,9 @@ nvkm_pci_new_(const struct nvkm_pci_func *func, struct nvkm_device *device,
|
|||
pci->pdev = device->func->pci(device)->pdev;
|
||||
pci->irq = -1;
|
||||
|
||||
if (device->type == NVKM_DEVICE_AGP)
|
||||
nvkm_agp_ctor(pci);
|
||||
|
||||
switch (pci->pdev->device & 0x0ff0) {
|
||||
case 0x00f0:
|
||||
case 0x02e0:
|
||||
|
|
Loading…
Reference in New Issue