diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile index 40c311e24bcd65e1a93fa965a4e5c7b02053a592..8b632934f01d4f499914cf5361b2fa355a28baaf 100644 --- a/drivers/gpu/drm/nouveau/Makefile +++ b/drivers/gpu/drm/nouveau/Makefile @@ -70,7 +70,7 @@ nouveau-y += nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \ nouveau_display.o nouveau_connector.o nouveau_fbcon.o \ nouveau_hdmi.o nouveau_dp.o \ nouveau_pm.o nouveau_volt.o nouveau_perf.o nouveau_temp.o \ - nouveau_mxm.o \ + nouveau_mxm.o nouveau_agp.o \ nouveau_abi16.o \ nouveau_bios.o \ nv04_fence.o nv10_fence.o nv84_fence.o nvc0_fence.o \ diff --git a/drivers/gpu/drm/nouveau/nouveau_agp.c b/drivers/gpu/drm/nouveau/nouveau_agp.c new file mode 100644 index 0000000000000000000000000000000000000000..d33201c56aa17a3c4ea7d540c0410a6f05ddd23f --- /dev/null +++ b/drivers/gpu/drm/nouveau/nouveau_agp.c @@ -0,0 +1,152 @@ +#include + +#include "drmP.h" +#include "drm.h" + +#include "nouveau_drv.h" +#include "nouveau_agp.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); + +static unsigned long +get_agp_mode(struct drm_device *dev, unsigned long mode) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + + /* + * FW seems to be broken on nv18, it makes the card lock up + * randomly. + */ + if (dev_priv->chipset == 0x18) + mode &= ~PCI_AGP_COMMAND_FW; + + /* + * AGP mode set in the command line. + */ + if (nouveau_agpmode > 0) { + bool agpv3 = mode & 0x8; + int rate = agpv3 ? nouveau_agpmode / 4 : nouveau_agpmode; + + mode = (mode & ~0x7) | (rate & 0x7); + } + + return mode; +} + +static bool +nouveau_agp_enabled(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + + if (!drm_pci_device_is_agp(dev) || !dev->agp) + return false; + + switch (dev_priv->gart_info.type) { + case NOUVEAU_GART_NONE: + if (!nouveau_agpmode) + return false; + break; + case NOUVEAU_GART_AGP: + break; + default: + return false; + } + + return true; +} +#endif + +void +nouveau_agp_reset(struct drm_device *dev) +{ +#if __OS_HAS_AGP + u32 save[2]; + int ret; + + if (!nouveau_agp_enabled(dev)) + 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 ((nv_rd32(dev, 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(dev, info.mode); + mode.mode &= ~PCI_AGP_COMMAND_FW; + + ret = drm_agp_enable(dev, mode); + if (ret) + return; + } + + + /* clear busmaster bit, and disable AGP */ + save[0] = nv_mask(dev, NV04_PBUS_PCI_NV_1, 0x00000004, 0x00000000); + nv_wr32(dev, NV04_PBUS_PCI_NV_19, 0); + + /* reset PGRAPH, PFIFO and PTIMER */ + save[1] = nv_mask(dev, 0x000200, 0x00011100, 0x00000000); + nv_mask(dev, 0x000200, 0x00011100, save[1]); + + /* and restore bustmaster bit (gives effect of resetting AGP) */ + nv_wr32(dev, NV04_PBUS_PCI_NV_1, save[0]); +#endif +} + +void +nouveau_agp_init(struct drm_device *dev) +{ +#if __OS_HAS_AGP + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct drm_agp_info info; + struct drm_agp_mode mode; + int ret; + + if (!nouveau_agp_enabled(dev)) + return; + + ret = drm_agp_acquire(dev); + if (ret) { + NV_ERROR(dev, "Unable to acquire AGP: %d\n", ret); + return; + } + + ret = drm_agp_info(dev, &info); + if (ret) { + NV_ERROR(dev, "Unable to get AGP info: %d\n", ret); + return; + } + + /* see agp.h for the AGPSTAT_* modes available */ + mode.mode = get_agp_mode(dev, info.mode); + + ret = drm_agp_enable(dev, mode); + if (ret) { + NV_ERROR(dev, "Unable to enable AGP: %d\n", ret); + return; + } + + dev_priv->gart_info.type = NOUVEAU_GART_AGP; + dev_priv->gart_info.aper_base = info.aperture_base; + dev_priv->gart_info.aper_size = info.aperture_size; +#endif +} + +void +nouveau_agp_fini(struct drm_device *dev) +{ +#if __OS_HAS_AGP + if (dev->agp && dev->agp->acquired) + drm_agp_release(dev); +#endif +} diff --git a/drivers/gpu/drm/nouveau/nouveau_agp.h b/drivers/gpu/drm/nouveau/nouveau_agp.h new file mode 100644 index 0000000000000000000000000000000000000000..b23db55eb2cadda5d3f406c548e9794e2d9260ae --- /dev/null +++ b/drivers/gpu/drm/nouveau/nouveau_agp.h @@ -0,0 +1,8 @@ +#ifndef __NOUVEAU_AGP_H__ +#define __NOUVEAU_AGP_H__ + +void nouveau_agp_reset(struct drm_device *); +void nouveau_agp_init(struct drm_device *); +void nouveau_agp_fini(struct drm_device *); + +#endif diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c index 74c226587d52bf6ea7a02ff98bbea1454618f95b..33dd955e26d3c4111b9aede4e6dc2bad6805633f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.c +++ b/drivers/gpu/drm/nouveau/nouveau_drv.c @@ -29,6 +29,7 @@ #include "drm.h" #include "drm_crtc_helper.h" #include "nouveau_drv.h" +#include "nouveau_agp.h" #include "nouveau_abi16.h" #include "nouveau_hw.h" #include "nouveau_fb.h" @@ -39,10 +40,6 @@ #include "drm_pciids.h" -MODULE_PARM_DESC(agpmode, "AGP mode (0 to disable AGP)"); -int nouveau_agpmode = -1; -module_param_named(agpmode, nouveau_agpmode, int, 0400); - MODULE_PARM_DESC(modeset, "Enable kernel modesetting"); int nouveau_modeset = -1; module_param_named(modeset, nouveau_modeset, int, 0400); @@ -248,6 +245,8 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state) goto out_abort; } + nouveau_agp_fini(dev); + NV_INFO(dev, "And we're gone!\n"); pci_save_state(pdev); if (pm_state.event == PM_EVENT_SUSPEND) { @@ -287,8 +286,7 @@ nouveau_pci_resume(struct pci_dev *pdev) pci_set_master(dev->pdev); /* Make sure the AGP controller is in a consistent state */ - if (dev_priv->gart_info.type == NOUVEAU_GART_AGP) - nouveau_mem_reset_agp(dev); + nouveau_agp_reset(dev); /* Make the CRTCs accessible */ engine->display.early_init(dev); @@ -298,13 +296,7 @@ nouveau_pci_resume(struct pci_dev *pdev) if (ret) return ret; - if (dev_priv->gart_info.type == NOUVEAU_GART_AGP) { - ret = nouveau_mem_init_agp(dev); - if (ret) { - NV_ERROR(dev, "error reinitialising AGP: %d\n", ret); - return ret; - } - } + nouveau_agp_init(dev); NV_INFO(dev, "Restoring GPU objects...\n"); nouveau_gpuobj_resume(dev); diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index a781d440010504d7eaf0245340bbca09ec497379..2158710cd6adf8755b6881803878fd8560729cc6 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -836,7 +836,6 @@ nouveau_bo_ref(struct nouveau_bo *ref, struct nouveau_bo **pnvbo) /* nouveau_drv.c */ extern int nouveau_modeset; -extern int nouveau_agpmode; extern int nouveau_duallink; extern int nouveau_uscript_lvds; extern int nouveau_uscript_tmds; @@ -884,8 +883,6 @@ extern int nouveau_mem_vram_init(struct drm_device *); extern void nouveau_mem_vram_fini(struct drm_device *); extern int nouveau_mem_gart_init(struct drm_device *); extern void nouveau_mem_gart_fini(struct drm_device *); -extern int nouveau_mem_init_agp(struct drm_device *); -extern int nouveau_mem_reset_agp(struct drm_device *); extern void nouveau_mem_close(struct drm_device *); extern bool nouveau_mem_flags_valid(struct drm_device *, u32 tile_flags); extern int nouveau_mem_timing_calc(struct drm_device *, u32 freq, diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index 0887236a3645629de756f5b70d98f838f01d718c..c816e03c15d4b1cda609f28f2833afcdbb0b9223 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -36,6 +36,7 @@ #include "drm_sarea.h" #include "nouveau_drv.h" +#include "nouveau_agp.h" #include "nouveau_pm.h" #include #include @@ -172,26 +173,7 @@ void nouveau_mem_gart_fini(struct drm_device *dev) { nouveau_sgdma_takedown(dev); - - if (drm_core_has_AGP(dev) && dev->agp) { - struct drm_agp_mem *entry, *tempe; - - /* Remove AGP resources, but leave dev->agp - intact until drv_cleanup is called. */ - list_for_each_entry_safe(entry, tempe, &dev->agp->memory, head) { - if (entry->bound) - drm_unbind_agp(entry->memory); - drm_free_agp(entry->memory, entry->pages); - kfree(entry); - } - INIT_LIST_HEAD(&dev->agp->memory); - - if (dev->agp->acquired) - drm_agp_release(dev); - - dev->agp->acquired = 0; - dev->agp->enabled = 0; - } + nouveau_agp_fini(dev); } bool @@ -203,121 +185,6 @@ nouveau_mem_flags_valid(struct drm_device *dev, u32 tile_flags) return false; } -#if __OS_HAS_AGP -static unsigned long -get_agp_mode(struct drm_device *dev, unsigned long mode) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - - /* - * FW seems to be broken on nv18, it makes the card lock up - * randomly. - */ - if (dev_priv->chipset == 0x18) - mode &= ~PCI_AGP_COMMAND_FW; - - /* - * AGP mode set in the command line. - */ - if (nouveau_agpmode > 0) { - bool agpv3 = mode & 0x8; - int rate = agpv3 ? nouveau_agpmode / 4 : nouveau_agpmode; - - mode = (mode & ~0x7) | (rate & 0x7); - } - - return mode; -} -#endif - -int -nouveau_mem_reset_agp(struct drm_device *dev) -{ -#if __OS_HAS_AGP - uint32_t saved_pci_nv_1, pmc_enable; - int ret; - - /* 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 ((nv_rd32(dev, 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 ret; - - mode.mode = get_agp_mode(dev, info.mode) & ~PCI_AGP_COMMAND_FW; - ret = drm_agp_enable(dev, mode); - if (ret) - return ret; - } - - saved_pci_nv_1 = nv_rd32(dev, NV04_PBUS_PCI_NV_1); - - /* clear busmaster bit */ - nv_wr32(dev, NV04_PBUS_PCI_NV_1, saved_pci_nv_1 & ~0x4); - /* disable AGP */ - nv_wr32(dev, NV04_PBUS_PCI_NV_19, 0); - - /* power cycle pgraph, if enabled */ - pmc_enable = nv_rd32(dev, NV03_PMC_ENABLE); - if (pmc_enable & NV_PMC_ENABLE_PGRAPH) { - nv_wr32(dev, NV03_PMC_ENABLE, - pmc_enable & ~NV_PMC_ENABLE_PGRAPH); - nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) | - NV_PMC_ENABLE_PGRAPH); - } - - /* and restore (gives effect of resetting AGP) */ - nv_wr32(dev, NV04_PBUS_PCI_NV_1, saved_pci_nv_1); -#endif - - return 0; -} - -int -nouveau_mem_init_agp(struct drm_device *dev) -{ -#if __OS_HAS_AGP - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct drm_agp_info info; - struct drm_agp_mode mode; - int ret; - - if (!dev->agp->acquired) { - ret = drm_agp_acquire(dev); - if (ret) { - NV_ERROR(dev, "Unable to acquire AGP: %d\n", ret); - return ret; - } - } - - nouveau_mem_reset_agp(dev); - - ret = drm_agp_info(dev, &info); - if (ret) { - NV_ERROR(dev, "Unable to get AGP info: %d\n", ret); - return ret; - } - - /* see agp.h for the AGPSTAT_* modes available */ - mode.mode = get_agp_mode(dev, info.mode); - ret = drm_agp_enable(dev, mode); - if (ret) { - NV_ERROR(dev, "Unable to enable AGP: %d\n", ret); - return ret; - } - - dev_priv->gart_info.type = NOUVEAU_GART_AGP; - dev_priv->gart_info.aper_base = info.aperture_base; - dev_priv->gart_info.aper_size = info.aperture_size; -#endif - return 0; -} - static const struct vram_types { int value; const char *name; @@ -441,15 +308,7 @@ nouveau_mem_gart_init(struct drm_device *dev) struct ttm_bo_device *bdev = &dev_priv->ttm.bdev; int ret; - dev_priv->gart_info.type = NOUVEAU_GART_NONE; - -#if !defined(__powerpc__) && !defined(__ia64__) - if (drm_pci_device_is_agp(dev) && dev->agp && nouveau_agpmode) { - ret = nouveau_mem_init_agp(dev); - if (ret) - NV_ERROR(dev, "Error initialising AGP: %d\n", ret); - } -#endif + nouveau_agp_init(dev); if (dev_priv->gart_info.type == NOUVEAU_GART_NONE) { ret = nouveau_sgdma_init(dev); diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index 0e8f325c709c8df2ced1e61d6eb0b78f90df6013..31c570c2bc361b29db5339d4a8cd411493a1ca72 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -34,6 +34,7 @@ #include "nouveau_drv.h" #include "nouveau_drm.h" +#include "nouveau_agp.h" #include "nouveau_fbcon.h" #include #include @@ -547,6 +548,9 @@ nouveau_card_init(struct drm_device *dev) spin_lock_init(&dev_priv->context_switch_lock); spin_lock_init(&dev_priv->vm_lock); + /* Make sure the AGP controller is in a consistent state */ + nouveau_agp_reset(dev); + /* Make the CRTCs and I2C buses accessible */ ret = engine->display.early_init(dev); if (ret)