aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2015-08-20 00:54:23 -0400
committerBen Skeggs <bskeggs@redhat.com>2015-08-27 22:40:49 -0400
commit340b0e7c500a0ac8fb649c58cf8528550642c1d8 (patch)
tree5d0e79108aee9874fd4eabdb138cf7415ad770c0
parent26c9e8effebb9166eb1cfba2d164676e98c505c7 (diff)
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>
-rw-r--r--drivers/gpu/drm/nouveau/Kbuild1
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/device.h1
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/os.h1
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/core/option.h1
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/pci.h11
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_abi16.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_agp.c198
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_agp.h10
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bo.c17
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_chan.c4
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drm.c11
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drm.h7
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_ttm.c12
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/core/option.c18
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pci/Kbuild1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pci/agp.c171
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pci/agp.h18
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c26
18 files changed, 271 insertions, 239 deletions
diff --git a/drivers/gpu/drm/nouveau/Kbuild b/drivers/gpu/drm/nouveau/Kbuild
index 2b765663c1a3..a34b437dbc8f 100644
--- a/drivers/gpu/drm/nouveau/Kbuild
+++ b/drivers/gpu/drm/nouveau/Kbuild
@@ -18,7 +18,6 @@ nouveau-y += $(nvkm-y)
18ifdef CONFIG_X86 18ifdef CONFIG_X86
19nouveau-$(CONFIG_ACPI) += nouveau_acpi.o 19nouveau-$(CONFIG_ACPI) += nouveau_acpi.o
20endif 20endif
21nouveau-y += nouveau_agp.o
22nouveau-$(CONFIG_DEBUG_FS) += nouveau_debugfs.o 21nouveau-$(CONFIG_DEBUG_FS) += nouveau_debugfs.o
23nouveau-y += nouveau_drm.o 22nouveau-y += nouveau_drm.o
24nouveau-y += nouveau_hwmon.o 23nouveau-y += nouveau_hwmon.o
diff --git a/drivers/gpu/drm/nouveau/include/nvif/device.h b/drivers/gpu/drm/nouveau/include/nvif/device.h
index 900e492549d1..700a9b206726 100644
--- a/drivers/gpu/drm/nouveau/include/nvif/device.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/device.h
@@ -45,6 +45,7 @@ u64 nvif_device_time(struct nvif_device *);
45#include <subdev/i2c.h> 45#include <subdev/i2c.h>
46#include <subdev/timer.h> 46#include <subdev/timer.h>
47#include <subdev/therm.h> 47#include <subdev/therm.h>
48#include <subdev/pci.h>
48 49
49#define nvxx_device(a) ({ \ 50#define nvxx_device(a) ({ \
50 struct nvif_device *_device = (a); \ 51 struct nvif_device *_device = (a); \
diff --git a/drivers/gpu/drm/nouveau/include/nvif/os.h b/drivers/gpu/drm/nouveau/include/nvif/os.h
index 54492cb5011b..97317f7fe4e5 100644
--- a/drivers/gpu/drm/nouveau/include/nvif/os.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/os.h
@@ -24,6 +24,7 @@
24#include <linux/power_supply.h> 24#include <linux/power_supply.h>
25#include <linux/clk.h> 25#include <linux/clk.h>
26#include <linux/regulator/consumer.h> 26#include <linux/regulator/consumer.h>
27#include <linux/agp_backend.h>
27 28
28#include <asm/unaligned.h> 29#include <asm/unaligned.h>
29 30
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/option.h b/drivers/gpu/drm/nouveau/include/nvkm/core/option.h
index 532bfa8e3f72..80fdc146e816 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/core/option.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/option.h
@@ -4,6 +4,7 @@
4 4
5const char *nvkm_stropt(const char *optstr, const char *opt, int *len); 5const char *nvkm_stropt(const char *optstr, const char *opt, int *len);
6bool nvkm_boolopt(const char *optstr, const char *opt, bool value); 6bool nvkm_boolopt(const char *optstr, const char *opt, bool value);
7long nvkm_longopt(const char *optstr, const char *opt, long value);
7int nvkm_dbgopt(const char *optstr, const char *sub); 8int nvkm_dbgopt(const char *optstr, const char *sub);
8 9
9/* compares unterminated string 'str' with zero-terminated string 'cmp' */ 10/* compares unterminated string 'str' with zero-terminated string 'cmp' */
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/pci.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/pci.h
index ac14fdf2f967..5b3c054f3b55 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/pci.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/pci.h
@@ -7,6 +7,17 @@ struct nvkm_pci {
7 struct nvkm_subdev subdev; 7 struct nvkm_subdev subdev;
8 struct pci_dev *pdev; 8 struct pci_dev *pdev;
9 int irq; 9 int irq;
10
11 struct {
12 struct agp_bridge_data *bridge;
13 u32 mode;
14 u64 base;
15 u64 size;
16 int mtrr;
17 bool cma;
18 bool acquired;
19 } agp;
20
10 bool msi; 21 bool msi;
11}; 22};
12 23
diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c
index 4252e7796c4c..d336c2247d6a 100644
--- a/drivers/gpu/drm/nouveau/nouveau_abi16.c
+++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c
@@ -498,7 +498,7 @@ nouveau_abi16_ioctl_notifierobj_alloc(ABI16_IOCTL_ARGS)
498 args.start += chan->ntfy_vma.offset; 498 args.start += chan->ntfy_vma.offset;
499 args.limit += chan->ntfy_vma.offset; 499 args.limit += chan->ntfy_vma.offset;
500 } else 500 } else
501 if (drm->agp.stat == ENABLED) { 501 if (drm->agp.bridge) {
502 args.target = NV_DMA_V0_TARGET_AGP; 502 args.target = NV_DMA_V0_TARGET_AGP;
503 args.access = NV_DMA_V0_ACCESS_RDWR; 503 args.access = NV_DMA_V0_ACCESS_RDWR;
504 args.start += drm->agp.base + chan->ntfy->bo.offset; 504 args.start += drm->agp.base + chan->ntfy->bo.offset;
diff --git a/drivers/gpu/drm/nouveau/nouveau_agp.c b/drivers/gpu/drm/nouveau/nouveau_agp.c
deleted file mode 100644
index c3f3e49e5f8f..000000000000
--- a/drivers/gpu/drm/nouveau/nouveau_agp.c
+++ /dev/null
@@ -1,198 +0,0 @@
1#include <linux/module.h>
2
3#include "nouveau_drm.h"
4#include "nouveau_agp.h"
5#include "nouveau_reg.h"
6
7#include <core/pci.h>
8
9#if __OS_HAS_AGP
10MODULE_PARM_DESC(agpmode, "AGP mode (0 to disable AGP)");
11static int nouveau_agpmode = -1;
12module_param_named(agpmode, nouveau_agpmode, int, 0400);
13
14struct nouveau_agpmode_quirk {
15 u16 hostbridge_vendor;
16 u16 hostbridge_device;
17 u16 chip_vendor;
18 u16 chip_device;
19 int mode;
20};
21
22static struct nouveau_agpmode_quirk nouveau_agpmode_quirk_list[] = {
23 /* VIA Apollo PRO133x / GeForce FX 5600 Ultra, max agpmode 2, fdo #20341 */
24 { PCI_VENDOR_ID_VIA, 0x0691, PCI_VENDOR_ID_NVIDIA, 0x0311, 2 },
25
26 {},
27};
28
29static unsigned long
30get_agp_mode(struct nouveau_drm *drm, const struct drm_agp_info *info)
31{
32 struct nvif_device *device = &drm->device;
33 struct pci_dev *pdev = nvxx_device(device)->func->pci(nvxx_device(device))->pdev;
34 struct nouveau_agpmode_quirk *quirk = nouveau_agpmode_quirk_list;
35 int agpmode = nouveau_agpmode;
36 unsigned long mode = info->mode;
37
38 /*
39 * FW seems to be broken on nv18, it makes the card lock up
40 * randomly.
41 */
42 if (device->info.chipset == 0x18)
43 mode &= ~PCI_AGP_COMMAND_FW;
44
45 /*
46 * Go through the quirks list and adjust the agpmode accordingly.
47 */
48 while (agpmode == -1 && quirk->hostbridge_vendor) {
49 if (info->id_vendor == quirk->hostbridge_vendor &&
50 info->id_device == quirk->hostbridge_device &&
51 pdev->vendor == quirk->chip_vendor &&
52 pdev->device == quirk->chip_device) {
53 agpmode = quirk->mode;
54 NV_INFO(drm, "Forcing agp mode to %dX. Use agpmode to override.\n",
55 agpmode);
56 break;
57 }
58 ++quirk;
59 }
60
61 /*
62 * AGP mode set in the command line.
63 */
64 if (agpmode > 0) {
65 bool agpv3 = mode & 0x8;
66 int rate = agpv3 ? agpmode / 4 : agpmode;
67
68 mode = (mode & ~0x7) | (rate & 0x7);
69 }
70
71 return mode;
72}
73
74static bool
75nouveau_agp_enabled(struct nouveau_drm *drm)
76{
77 struct drm_device *dev = drm->dev;
78
79 if (!dev->pdev || !drm_pci_device_is_agp(dev) || !dev->agp)
80 return false;
81
82 if (drm->agp.stat == UNKNOWN) {
83 if (!nouveau_agpmode)
84 return false;
85#ifdef __powerpc__
86 /* Disable AGP by default on all PowerPC machines for
87 * now -- At least some UniNorth-2 AGP bridges are
88 * known to be broken: DMA from the host to the card
89 * works just fine, but writeback from the card to the
90 * host goes straight to memory untranslated bypassing
91 * the GATT somehow, making them quite painful to deal
92 * with...
93 */
94 if (nouveau_agpmode == -1)
95 return false;
96#endif
97 return true;
98 }
99
100 return (drm->agp.stat == ENABLED);
101}
102#endif
103
104void
105nouveau_agp_reset(struct nouveau_drm *drm)
106{
107#if __OS_HAS_AGP
108 struct nvif_object *device = &drm->device.object;
109 struct drm_device *dev = drm->dev;
110 u32 save[2];
111 int ret;
112
113 if (!nouveau_agp_enabled(drm))
114 return;
115
116 /* First of all, disable fast writes, otherwise if it's
117 * already enabled in the AGP bridge and we disable the card's
118 * AGP controller we might be locking ourselves out of it. */
119 if ((nvif_rd32(device, NV04_PBUS_PCI_NV_19) |
120 dev->agp->mode) & PCI_AGP_COMMAND_FW) {
121 struct drm_agp_info info;
122 struct drm_agp_mode mode;
123
124 ret = drm_agp_info(dev, &info);
125 if (ret)
126 return;
127
128 mode.mode = get_agp_mode(drm, &info);
129 mode.mode &= ~PCI_AGP_COMMAND_FW;
130
131 ret = drm_agp_enable(dev, mode);
132 if (ret)
133 return;
134 }
135
136
137 /* clear busmaster bit, and disable AGP */
138 save[0] = nvif_mask(device, NV04_PBUS_PCI_NV_1, 0x00000004, 0x00000000);
139 nvif_wr32(device, NV04_PBUS_PCI_NV_19, 0);
140
141 /* reset PGRAPH, PFIFO and PTIMER */
142 save[1] = nvif_mask(device, 0x000200, 0x00011100, 0x00000000);
143 nvif_mask(device, 0x000200, 0x00011100, save[1]);
144
145 /* and restore bustmaster bit (gives effect of resetting AGP) */
146 nvif_wr32(device, NV04_PBUS_PCI_NV_1, save[0]);
147#endif
148}
149
150void
151nouveau_agp_init(struct nouveau_drm *drm)
152{
153#if __OS_HAS_AGP
154 struct drm_device *dev = drm->dev;
155 struct drm_agp_info info;
156 struct drm_agp_mode mode;
157 int ret;
158
159 if (!nouveau_agp_enabled(drm))
160 return;
161 drm->agp.stat = DISABLE;
162
163 ret = drm_agp_acquire(dev);
164 if (ret) {
165 NV_ERROR(drm, "unable to acquire AGP: %d\n", ret);
166 return;
167 }
168
169 ret = drm_agp_info(dev, &info);
170 if (ret) {
171 NV_ERROR(drm, "unable to get AGP info: %d\n", ret);
172 return;
173 }
174
175 /* see agp.h for the AGPSTAT_* modes available */
176 mode.mode = get_agp_mode(drm, &info);
177
178 ret = drm_agp_enable(dev, mode);
179 if (ret) {
180 NV_ERROR(drm, "unable to enable AGP: %d\n", ret);
181 return;
182 }
183
184 drm->agp.stat = ENABLED;
185 drm->agp.base = info.aperture_base;
186 drm->agp.size = info.aperture_size;
187#endif
188}
189
190void
191nouveau_agp_fini(struct nouveau_drm *drm)
192{
193#if __OS_HAS_AGP
194 struct drm_device *dev = drm->dev;
195 if (dev->agp && dev->agp->acquired)
196 drm_agp_release(dev);
197#endif
198}
diff --git a/drivers/gpu/drm/nouveau/nouveau_agp.h b/drivers/gpu/drm/nouveau/nouveau_agp.h
deleted file mode 100644
index b55c08652963..000000000000
--- a/drivers/gpu/drm/nouveau/nouveau_agp.h
+++ /dev/null
@@ -1,10 +0,0 @@
1#ifndef __NOUVEAU_AGP_H__
2#define __NOUVEAU_AGP_H__
3
4struct nouveau_drm;
5
6void nouveau_agp_reset(struct nouveau_drm *);
7void nouveau_agp_init(struct nouveau_drm *);
8void nouveau_agp_fini(struct nouveau_drm *);
9
10#endif
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c
index 373fbd2d14ff..15057b39491c 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.c
@@ -576,10 +576,9 @@ nouveau_ttm_tt_create(struct ttm_bo_device *bdev, unsigned long size,
576{ 576{
577#if __OS_HAS_AGP 577#if __OS_HAS_AGP
578 struct nouveau_drm *drm = nouveau_bdev(bdev); 578 struct nouveau_drm *drm = nouveau_bdev(bdev);
579 struct drm_device *dev = drm->dev;
580 579
581 if (drm->agp.stat == ENABLED) { 580 if (drm->agp.bridge) {
582 return ttm_agp_tt_create(bdev, dev->agp->bridge, size, 581 return ttm_agp_tt_create(bdev, drm->agp.bridge, size,
583 page_flags, dummy_read); 582 page_flags, dummy_read);
584 } 583 }
585#endif 584#endif
@@ -631,12 +630,12 @@ nouveau_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
631 if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) 630 if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA)
632 man->func = &nouveau_gart_manager; 631 man->func = &nouveau_gart_manager;
633 else 632 else
634 if (drm->agp.stat != ENABLED) 633 if (!drm->agp.bridge)
635 man->func = &nv04_gart_manager; 634 man->func = &nv04_gart_manager;
636 else 635 else
637 man->func = &ttm_bo_manager_func; 636 man->func = &ttm_bo_manager_func;
638 637
639 if (drm->agp.stat == ENABLED) { 638 if (drm->agp.bridge) {
640 man->flags = TTM_MEMTYPE_FLAG_MAPPABLE; 639 man->flags = TTM_MEMTYPE_FLAG_MAPPABLE;
641 man->available_caching = TTM_PL_FLAG_UNCACHED | 640 man->available_caching = TTM_PL_FLAG_UNCACHED |
642 TTM_PL_FLAG_WC; 641 TTM_PL_FLAG_WC;
@@ -1368,10 +1367,10 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
1368 return 0; 1367 return 0;
1369 case TTM_PL_TT: 1368 case TTM_PL_TT:
1370#if __OS_HAS_AGP 1369#if __OS_HAS_AGP
1371 if (drm->agp.stat == ENABLED) { 1370 if (drm->agp.bridge) {
1372 mem->bus.offset = mem->start << PAGE_SHIFT; 1371 mem->bus.offset = mem->start << PAGE_SHIFT;
1373 mem->bus.base = drm->agp.base; 1372 mem->bus.base = drm->agp.base;
1374 mem->bus.is_iomem = !drm->dev->agp->cant_use_aperture; 1373 mem->bus.is_iomem = !drm->agp.cma;
1375 } 1374 }
1376#endif 1375#endif
1377 if (drm->device.info.family < NV_DEVICE_INFO_V0_TESLA || !node->memtype) 1376 if (drm->device.info.family < NV_DEVICE_INFO_V0_TESLA || !node->memtype)
@@ -1498,7 +1497,7 @@ nouveau_ttm_tt_populate(struct ttm_tt *ttm)
1498 return ttm_dma_populate(ttm_dma, dev->dev); 1497 return ttm_dma_populate(ttm_dma, dev->dev);
1499 1498
1500#if __OS_HAS_AGP 1499#if __OS_HAS_AGP
1501 if (drm->agp.stat == ENABLED) { 1500 if (drm->agp.bridge) {
1502 return ttm_agp_tt_populate(ttm); 1501 return ttm_agp_tt_populate(ttm);
1503 } 1502 }
1504#endif 1503#endif
@@ -1565,7 +1564,7 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm)
1565 } 1564 }
1566 1565
1567#if __OS_HAS_AGP 1566#if __OS_HAS_AGP
1568 if (drm->agp.stat == ENABLED) { 1567 if (drm->agp.bridge) {
1569 ttm_agp_tt_unpopulate(ttm); 1568 ttm_agp_tt_unpopulate(ttm);
1570 return; 1569 return;
1571 } 1570 }
diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.c b/drivers/gpu/drm/nouveau/nouveau_chan.c
index f59c4f5716cc..ff5e59db49db 100644
--- a/drivers/gpu/drm/nouveau/nouveau_chan.c
+++ b/drivers/gpu/drm/nouveau/nouveau_chan.c
@@ -160,7 +160,7 @@ nouveau_channel_prep(struct nouveau_drm *drm, struct nvif_device *device,
160 args.limit = device->info.ram_user - 1; 160 args.limit = device->info.ram_user - 1;
161 } 161 }
162 } else { 162 } else {
163 if (chan->drm->agp.stat == ENABLED) { 163 if (chan->drm->agp.bridge) {
164 args.target = NV_DMA_V0_TARGET_AGP; 164 args.target = NV_DMA_V0_TARGET_AGP;
165 args.access = NV_DMA_V0_ACCESS_RDWR; 165 args.access = NV_DMA_V0_ACCESS_RDWR;
166 args.start = chan->drm->agp.base; 166 args.start = chan->drm->agp.base;
@@ -328,7 +328,7 @@ nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart)
328 args.start = 0; 328 args.start = 0;
329 args.limit = cli->vm->mmu->limit - 1; 329 args.limit = cli->vm->mmu->limit - 1;
330 } else 330 } else
331 if (chan->drm->agp.stat == ENABLED) { 331 if (chan->drm->agp.bridge) {
332 args.target = NV_DMA_V0_TARGET_AGP; 332 args.target = NV_DMA_V0_TARGET_AGP;
333 args.access = NV_DMA_V0_ACCESS_RDWR; 333 args.access = NV_DMA_V0_ACCESS_RDWR;
334 args.start = chan->drm->agp.base; 334 args.start = chan->drm->agp.base;
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c
index 14a13486c27f..ccefb645fd55 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.c
@@ -41,7 +41,6 @@
41#include "nouveau_dma.h" 41#include "nouveau_dma.h"
42#include "nouveau_ttm.h" 42#include "nouveau_ttm.h"
43#include "nouveau_gem.h" 43#include "nouveau_gem.h"
44#include "nouveau_agp.h"
45#include "nouveau_vga.h" 44#include "nouveau_vga.h"
46#include "nouveau_sysfs.h" 45#include "nouveau_sysfs.h"
47#include "nouveau_hwmon.h" 46#include "nouveau_hwmon.h"
@@ -423,7 +422,6 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags)
423 nvif_mask(&drm->device.object, 0x00088080, 0x00000800, 0x00000000); 422 nvif_mask(&drm->device.object, 0x00088080, 0x00000800, 0x00000000);
424 423
425 nouveau_vga_init(drm); 424 nouveau_vga_init(drm);
426 nouveau_agp_init(drm);
427 425
428 if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) { 426 if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) {
429 ret = nvkm_vm_new(nvxx_device(&drm->device), 0, (1ULL << 40), 427 ret = nvkm_vm_new(nvxx_device(&drm->device), 0, (1ULL << 40),
@@ -474,7 +472,6 @@ fail_dispctor:
474fail_bios: 472fail_bios:
475 nouveau_ttm_fini(drm); 473 nouveau_ttm_fini(drm);
476fail_ttm: 474fail_ttm:
477 nouveau_agp_fini(drm);
478 nouveau_vga_fini(drm); 475 nouveau_vga_fini(drm);
479fail_device: 476fail_device:
480 nvif_device_fini(&drm->device); 477 nvif_device_fini(&drm->device);
@@ -500,7 +497,6 @@ nouveau_drm_unload(struct drm_device *dev)
500 nouveau_bios_takedown(dev); 497 nouveau_bios_takedown(dev);
501 498
502 nouveau_ttm_fini(drm); 499 nouveau_ttm_fini(drm);
503 nouveau_agp_fini(drm);
504 nouveau_vga_fini(drm); 500 nouveau_vga_fini(drm);
505 501
506 nvif_device_fini(&drm->device); 502 nvif_device_fini(&drm->device);
@@ -584,7 +580,6 @@ nouveau_do_suspend(struct drm_device *dev, bool runtime)
584 if (ret) 580 if (ret)
585 goto fail_client; 581 goto fail_client;
586 582
587 nouveau_agp_fini(drm);
588 return 0; 583 return 0;
589 584
590fail_client: 585fail_client:
@@ -609,13 +604,8 @@ nouveau_do_resume(struct drm_device *dev, bool runtime)
609 struct nouveau_drm *drm = nouveau_drm(dev); 604 struct nouveau_drm *drm = nouveau_drm(dev);
610 struct nouveau_cli *cli; 605 struct nouveau_cli *cli;
611 606
612 NV_INFO(drm, "re-enabling device...\n");
613
614 nouveau_agp_reset(drm);
615
616 NV_INFO(drm, "resuming kernel object tree...\n"); 607 NV_INFO(drm, "resuming kernel object tree...\n");
617 nvif_client_resume(&drm->client.base); 608 nvif_client_resume(&drm->client.base);
618 nouveau_agp_init(drm);
619 609
620 NV_INFO(drm, "resuming client object trees...\n"); 610 NV_INFO(drm, "resuming client object trees...\n");
621 if (drm->fence && nouveau_fence(drm)->resume) 611 if (drm->fence && nouveau_fence(drm)->resume)
@@ -929,7 +919,6 @@ nouveau_driver_fops = {
929static struct drm_driver 919static struct drm_driver
930driver_stub = { 920driver_stub = {
931 .driver_features = 921 .driver_features =
932 DRIVER_USE_AGP |
933 DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | DRIVER_RENDER | 922 DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | DRIVER_RENDER |
934 DRIVER_KMS_LEGACY_CONTEXT, 923 DRIVER_KMS_LEGACY_CONTEXT,
935 924
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.h b/drivers/gpu/drm/nouveau/nouveau_drm.h
index f18710afcfd3..7fb3a8ad12d7 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.h
@@ -111,13 +111,10 @@ struct nouveau_drm {
111 struct list_head clients; 111 struct list_head clients;
112 112
113 struct { 113 struct {
114 enum { 114 struct agp_bridge_data *bridge;
115 UNKNOWN = 0,
116 DISABLE = 1,
117 ENABLED = 2
118 } stat;
119 u32 base; 115 u32 base;
120 u32 size; 116 u32 size;
117 bool cma;
121 } agp; 118 } agp;
122 119
123 /* TTM interface support */ 120 /* TTM interface support */
diff --git a/drivers/gpu/drm/nouveau/nouveau_ttm.c b/drivers/gpu/drm/nouveau/nouveau_ttm.c
index ba9fd151bd28..3f0fb55cb473 100644
--- a/drivers/gpu/drm/nouveau/nouveau_ttm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_ttm.c
@@ -336,13 +336,21 @@ int
336nouveau_ttm_init(struct nouveau_drm *drm) 336nouveau_ttm_init(struct nouveau_drm *drm)
337{ 337{
338 struct nvkm_device *device = nvxx_device(&drm->device); 338 struct nvkm_device *device = nvxx_device(&drm->device);
339 struct nvkm_pci *pci = device->pci;
339 struct drm_device *dev = drm->dev; 340 struct drm_device *dev = drm->dev;
340 u32 bits; 341 u32 bits;
341 int ret; 342 int ret;
342 343
344 if (pci && pci->agp.bridge) {
345 drm->agp.bridge = pci->agp.bridge;
346 drm->agp.base = pci->agp.base;
347 drm->agp.size = pci->agp.size;
348 drm->agp.cma = pci->agp.cma;
349 }
350
343 bits = nvxx_mmu(&drm->device)->dma_bits; 351 bits = nvxx_mmu(&drm->device)->dma_bits;
344 if (nvxx_device(&drm->device)->func->pci) { 352 if (nvxx_device(&drm->device)->func->pci) {
345 if (drm->agp.stat == ENABLED || 353 if (drm->agp.bridge ||
346 !pci_dma_supported(dev->pdev, DMA_BIT_MASK(bits))) 354 !pci_dma_supported(dev->pdev, DMA_BIT_MASK(bits)))
347 bits = 32; 355 bits = 32;
348 356
@@ -386,7 +394,7 @@ nouveau_ttm_init(struct nouveau_drm *drm)
386 device->func->resource_size(device, 1)); 394 device->func->resource_size(device, 1));
387 395
388 /* GART init */ 396 /* GART init */
389 if (drm->agp.stat != ENABLED) { 397 if (!drm->agp.bridge) {
390 drm->gem.gart_available = nvxx_mmu(&drm->device)->limit; 398 drm->gem.gart_available = nvxx_mmu(&drm->device)->limit;
391 } else { 399 } else {
392 drm->gem.gart_available = drm->agp.size; 400 drm->gem.gart_available = drm->agp.size;
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/option.c b/drivers/gpu/drm/nouveau/nvkm/core/option.c
index 98ebde3b7269..3e62cf8cde08 100644
--- a/drivers/gpu/drm/nouveau/nvkm/core/option.c
+++ b/drivers/gpu/drm/nouveau/nvkm/core/option.c
@@ -73,6 +73,24 @@ nvkm_boolopt(const char *optstr, const char *opt, bool value)
73 return value; 73 return value;
74} 74}
75 75
76long
77nvkm_longopt(const char *optstr, const char *opt, long value)
78{
79 long result = value;
80 int arglen;
81 char *s;
82
83 optstr = nvkm_stropt(optstr, opt, &arglen);
84 if (optstr && (s = kstrndup(optstr, arglen, GFP_KERNEL))) {
85 int ret = kstrtol(s, 0, &value);
86 if (ret == 0)
87 result = value;
88 kfree(s);
89 }
90
91 return result;
92}
93
76int 94int
77nvkm_dbgopt(const char *optstr, const char *sub) 95nvkm_dbgopt(const char *optstr, const char *sub)
78{ 96{
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/Kbuild
index a8e9b0fc447e..99672c3d0bad 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/Kbuild
@@ -1,3 +1,4 @@
1nvkm-y += nvkm/subdev/pci/agp.o
1nvkm-y += nvkm/subdev/pci/base.o 2nvkm-y += nvkm/subdev/pci/base.o
2nvkm-y += nvkm/subdev/pci/nv04.o 3nvkm-y += nvkm/subdev/pci/nv04.o
3nvkm-y += nvkm/subdev/pci/nv40.o 4nvkm-y += nvkm/subdev/pci/nv40.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/agp.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/agp.c
new file mode 100644
index 000000000000..814cb51cc873
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/agp.c
@@ -0,0 +1,171 @@
1/*
2 * Copyright 2015 Nouveau Project
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 */
22#include "agp.h"
23#ifdef __NVKM_PCI_AGP_H__
24#include <core/option.h>
25
26struct nvkm_device_agp_quirk {
27 u16 hostbridge_vendor;
28 u16 hostbridge_device;
29 u16 chip_vendor;
30 u16 chip_device;
31 int mode;
32};
33
34static const struct nvkm_device_agp_quirk
35nvkm_device_agp_quirks[] = {
36 /* VIA Apollo PRO133x / GeForce FX 5600 Ultra - fdo#20341 */
37 { PCI_VENDOR_ID_VIA, 0x0691, PCI_VENDOR_ID_NVIDIA, 0x0311, 2 },
38 {},
39};
40
41void
42nvkm_agp_fini(struct nvkm_pci *pci)
43{
44 if (pci->agp.acquired) {
45 agp_backend_release(pci->agp.bridge);
46 pci->agp.acquired = false;
47 }
48}
49
50/* Ensure AGP controller is in a consistent state in case we need to
51 * execute the VBIOS DEVINIT scripts.
52 */
53void
54nvkm_agp_preinit(struct nvkm_pci *pci)
55{
56 struct nvkm_device *device = pci->subdev.device;
57 u32 mode = nvkm_pci_rd32(pci, 0x004c);
58 u32 save[2];
59
60 /* First of all, disable fast writes, otherwise if it's already
61 * enabled in the AGP bridge and we disable the card's AGP
62 * controller we might be locking ourselves out of it.
63 */
64 if ((mode | pci->agp.mode) & PCI_AGP_COMMAND_FW) {
65 mode = pci->agp.mode & ~PCI_AGP_COMMAND_FW;
66 agp_enable(pci->agp.bridge, mode);
67 }
68
69 /* clear busmaster bit, and disable AGP */
70 save[0] = nvkm_pci_rd32(pci, 0x0004);
71 nvkm_pci_wr32(pci, 0x0004, save[0] & ~0x00000004);
72 nvkm_pci_wr32(pci, 0x004c, 0x00000000);
73
74 /* reset PGRAPH, PFIFO and PTIMER */
75 save[1] = nvkm_mask(device, 0x000200, 0x00011100, 0x00000000);
76 nvkm_mask(device, 0x000200, 0x00011100, save[1]);
77
78 /* and restore busmaster bit (gives effect of resetting AGP) */
79 nvkm_pci_wr32(pci, 0x0004, save[0]);
80}
81
82int
83nvkm_agp_init(struct nvkm_pci *pci)
84{
85 if (!agp_backend_acquire(pci->pdev)) {
86 nvkm_error(&pci->subdev, "failed to acquire agp\n");
87 return -ENODEV;
88 }
89
90 agp_enable(pci->agp.bridge, pci->agp.mode);
91 pci->agp.acquired = true;
92 return 0;
93}
94
95void
96nvkm_agp_dtor(struct nvkm_pci *pci)
97{
98 arch_phys_wc_del(pci->agp.mtrr);
99}
100
101void
102nvkm_agp_ctor(struct nvkm_pci *pci)
103{
104 const struct nvkm_device_agp_quirk *quirk = nvkm_device_agp_quirks;
105 struct nvkm_subdev *subdev = &pci->subdev;
106 struct nvkm_device *device = subdev->device;
107 struct agp_kern_info info;
108 int mode = -1;
109
110#ifdef __powerpc__
111 /* Disable AGP by default on all PowerPC machines for now -- At
112 * least some UniNorth-2 AGP bridges are known to be broken:
113 * DMA from the host to the card works just fine, but writeback
114 * from the card to the host goes straight to memory
115 * untranslated bypassing that GATT somehow, making them quite
116 * painful to deal with...
117 */
118 mode = 0;
119#endif
120 mode = nvkm_longopt(device->cfgopt, "NvAGP", mode);
121
122 /* acquire bridge temporarily, so that we can copy its info */
123 if (!(pci->agp.bridge = agp_backend_acquire(pci->pdev))) {
124 nvkm_warn(subdev, "failed to acquire agp\n");
125 return;
126 }
127 agp_copy_info(pci->agp.bridge, &info);
128 agp_backend_release(pci->agp.bridge);
129
130 pci->agp.mode = info.mode;
131 pci->agp.base = info.aper_base;
132 pci->agp.size = info.aper_size * 1024 * 1024;
133 pci->agp.cma = info.cant_use_aperture;
134 pci->agp.mtrr = -1;
135
136 /* determine if bridge + chipset combination needs a workaround */
137 while (quirk->hostbridge_vendor) {
138 if (info.device->vendor == quirk->hostbridge_vendor &&
139 info.device->device == quirk->hostbridge_device &&
140 pci->pdev->vendor == quirk->chip_vendor &&
141 pci->pdev->device == quirk->chip_device) {
142 nvkm_info(subdev, "forcing default agp mode to %dX, "
143 "use NvAGP=<mode> to override\n",
144 quirk->mode);
145 mode = quirk->mode;
146 break;
147 }
148 quirk++;
149 }
150
151 /* apply quirk / user-specified mode */
152 if (mode >= 1) {
153 if (pci->agp.mode & 0x00000008)
154 mode /= 4; /* AGPv3 */
155 pci->agp.mode &= ~0x00000007;
156 pci->agp.mode |= (mode & 0x7);
157 } else
158 if (mode == 0) {
159 pci->agp.bridge = NULL;
160 return;
161 }
162
163 /* fast writes appear to be broken on nv18, they make the card
164 * lock up randomly.
165 */
166 if (device->chipset == 0x18)
167 pci->agp.mode &= ~PCI_AGP_COMMAND_FW;
168
169 pci->agp.mtrr = arch_phys_wc_add(pci->agp.base, pci->agp.size);
170}
171#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/agp.h b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/agp.h
new file mode 100644
index 000000000000..df2dd08363ad
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/agp.h
@@ -0,0 +1,18 @@
1#include "priv.h"
2#if defined(CONFIG_AGP) || (defined(CONFIG_AGP_MODULE) && defined(MODULE))
3#ifndef __NVKM_PCI_AGP_H__
4#define __NVKM_PCI_AGP_H__
5
6void nvkm_agp_ctor(struct nvkm_pci *);
7void nvkm_agp_dtor(struct nvkm_pci *);
8void nvkm_agp_preinit(struct nvkm_pci *);
9int nvkm_agp_init(struct nvkm_pci *);
10void nvkm_agp_fini(struct nvkm_pci *);
11#endif
12#else
13static inline void nvkm_agp_ctor(struct nvkm_pci *pci) {}
14static inline void nvkm_agp_dtor(struct nvkm_pci *pci) {}
15static inline void nvkm_agp_preinit(struct nvkm_pci *pci) {}
16static inline int nvkm_agp_init(struct nvkm_pci *pci) { return -ENOSYS; }
17static inline void nvkm_agp_fini(struct nvkm_pci *pci) {}
18#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c
index e5e0d02f3d88..d1c148e51922 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c
@@ -22,6 +22,7 @@
22 * Authors: Ben Skeggs <bskeggs@redhat.com> 22 * Authors: Ben Skeggs <bskeggs@redhat.com>
23 */ 23 */
24#include "priv.h" 24#include "priv.h"
25#include "agp.h"
25 26
26#include <core/option.h> 27#include <core/option.h>
27#include <core/pci.h> 28#include <core/pci.h>
@@ -76,10 +77,24 @@ static int
76nvkm_pci_fini(struct nvkm_subdev *subdev, bool suspend) 77nvkm_pci_fini(struct nvkm_subdev *subdev, bool suspend)
77{ 78{
78 struct nvkm_pci *pci = nvkm_pci(subdev); 79 struct nvkm_pci *pci = nvkm_pci(subdev);
80
79 if (pci->irq >= 0) { 81 if (pci->irq >= 0) {
80 free_irq(pci->irq, pci); 82 free_irq(pci->irq, pci);
81 pci->irq = -1; 83 pci->irq = -1;
82 }; 84 };
85
86 if (pci->agp.bridge)
87 nvkm_agp_fini(pci);
88
89 return 0;
90}
91
92static int
93nvkm_pci_preinit(struct nvkm_subdev *subdev)
94{
95 struct nvkm_pci *pci = nvkm_pci(subdev);
96 if (pci->agp.bridge)
97 nvkm_agp_preinit(pci);
83 return 0; 98 return 0;
84} 99}
85 100
@@ -90,6 +105,12 @@ nvkm_pci_init(struct nvkm_subdev *subdev)
90 struct pci_dev *pdev = pci->pdev; 105 struct pci_dev *pdev = pci->pdev;
91 int ret; 106 int ret;
92 107
108 if (pci->agp.bridge) {
109 ret = nvkm_agp_init(pci);
110 if (ret)
111 return ret;
112 }
113
93 ret = request_irq(pdev->irq, nvkm_pci_intr, IRQF_SHARED, "nvkm", pci); 114 ret = request_irq(pdev->irq, nvkm_pci_intr, IRQF_SHARED, "nvkm", pci);
94 if (ret) 115 if (ret)
95 return ret; 116 return ret;
@@ -102,6 +123,7 @@ static void *
102nvkm_pci_dtor(struct nvkm_subdev *subdev) 123nvkm_pci_dtor(struct nvkm_subdev *subdev)
103{ 124{
104 struct nvkm_pci *pci = nvkm_pci(subdev); 125 struct nvkm_pci *pci = nvkm_pci(subdev);
126 nvkm_agp_dtor(pci);
105 if (pci->msi) 127 if (pci->msi)
106 pci_disable_msi(pci->pdev); 128 pci_disable_msi(pci->pdev);
107 return nvkm_pci(subdev); 129 return nvkm_pci(subdev);
@@ -110,6 +132,7 @@ nvkm_pci_dtor(struct nvkm_subdev *subdev)
110static const struct nvkm_subdev_func 132static const struct nvkm_subdev_func
111nvkm_pci_func = { 133nvkm_pci_func = {
112 .dtor = nvkm_pci_dtor, 134 .dtor = nvkm_pci_dtor,
135 .preinit = nvkm_pci_preinit,
113 .init = nvkm_pci_init, 136 .init = nvkm_pci_init,
114 .fini = nvkm_pci_fini, 137 .fini = nvkm_pci_fini,
115}; 138};
@@ -127,6 +150,9 @@ nvkm_pci_new_(const struct nvkm_pci_func *func, struct nvkm_device *device,
127 pci->pdev = device->func->pci(device)->pdev; 150 pci->pdev = device->func->pci(device)->pdev;
128 pci->irq = -1; 151 pci->irq = -1;
129 152
153 if (device->type == NVKM_DEVICE_AGP)
154 nvkm_agp_ctor(pci);
155
130 switch (pci->pdev->device & 0x0ff0) { 156 switch (pci->pdev->device & 0x0ff0) {
131 case 0x00f0: 157 case 0x00f0:
132 case 0x02e0: 158 case 0x02e0: