diff options
author | Ilia Mirkin <imirkin@alum.mit.edu> | 2013-10-27 11:54:09 -0400 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2013-11-08 00:39:54 -0500 |
commit | fd34381b0e2827228cbda45aa2cca4127ff073b2 (patch) | |
tree | 731942ed4d819678d1993e8dfd3e075d2122fbd7 | |
parent | e8d95b22b415bab6e411d6d0db82e26b4227762b (diff) |
drm/nouveau/agp: add a quirk list to limit agp modes
Certain combinations of hardware can't actually support the maximum
detected speed. Add a quirk list that lists pairs of hostbridge/chip pci
ids and the mode that they should work with.
See https://bugs.freedesktop.org/show_bug.cgi?id=20341
Reported-by: Jason Detring <detringj@gmail.com>
Signed-off-by: Ilia Mirkin <imirkin@alum.mit.edu>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_agp.c | 44 |
1 files changed, 39 insertions, 5 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_agp.c b/drivers/gpu/drm/nouveau/nouveau_agp.c index 6e7a55f93a85..2953c4e91e1a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_agp.c +++ b/drivers/gpu/drm/nouveau/nouveau_agp.c | |||
@@ -11,10 +11,28 @@ MODULE_PARM_DESC(agpmode, "AGP mode (0 to disable AGP)"); | |||
11 | static int nouveau_agpmode = -1; | 11 | static int nouveau_agpmode = -1; |
12 | module_param_named(agpmode, nouveau_agpmode, int, 0400); | 12 | module_param_named(agpmode, nouveau_agpmode, int, 0400); |
13 | 13 | ||
14 | struct nouveau_agpmode_quirk { | ||
15 | u16 hostbridge_vendor; | ||
16 | u16 hostbridge_device; | ||
17 | u16 chip_vendor; | ||
18 | u16 chip_device; | ||
19 | int mode; | ||
20 | }; | ||
21 | |||
22 | static 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 | |||
14 | static unsigned long | 29 | static unsigned long |
15 | get_agp_mode(struct nouveau_drm *drm, unsigned long mode) | 30 | get_agp_mode(struct nouveau_drm *drm, const struct drm_agp_info *info) |
16 | { | 31 | { |
17 | struct nouveau_device *device = nv_device(drm->device); | 32 | struct nouveau_device *device = nv_device(drm->device); |
33 | struct nouveau_agpmode_quirk *quirk = nouveau_agpmode_quirk_list; | ||
34 | int agpmode = nouveau_agpmode; | ||
35 | unsigned long mode = info->mode; | ||
18 | 36 | ||
19 | /* | 37 | /* |
20 | * FW seems to be broken on nv18, it makes the card lock up | 38 | * FW seems to be broken on nv18, it makes the card lock up |
@@ -24,11 +42,27 @@ get_agp_mode(struct nouveau_drm *drm, unsigned long mode) | |||
24 | mode &= ~PCI_AGP_COMMAND_FW; | 42 | mode &= ~PCI_AGP_COMMAND_FW; |
25 | 43 | ||
26 | /* | 44 | /* |
45 | * Go through the quirks list and adjust the agpmode accordingly. | ||
46 | */ | ||
47 | while (agpmode == -1 && quirk->hostbridge_vendor) { | ||
48 | if (info->id_vendor == quirk->hostbridge_vendor && | ||
49 | info->id_device == quirk->hostbridge_device && | ||
50 | device->pdev->vendor == quirk->chip_vendor && | ||
51 | device->pdev->device == quirk->chip_device) { | ||
52 | agpmode = quirk->mode; | ||
53 | nv_info(device, "Forcing agp mode to %dX. Use agpmode to override.\n", | ||
54 | agpmode); | ||
55 | break; | ||
56 | } | ||
57 | ++quirk; | ||
58 | } | ||
59 | |||
60 | /* | ||
27 | * AGP mode set in the command line. | 61 | * AGP mode set in the command line. |
28 | */ | 62 | */ |
29 | if (nouveau_agpmode > 0) { | 63 | if (agpmode > 0) { |
30 | bool agpv3 = mode & 0x8; | 64 | bool agpv3 = mode & 0x8; |
31 | int rate = agpv3 ? nouveau_agpmode / 4 : nouveau_agpmode; | 65 | int rate = agpv3 ? agpmode / 4 : agpmode; |
32 | 66 | ||
33 | mode = (mode & ~0x7) | (rate & 0x7); | 67 | mode = (mode & ~0x7) | (rate & 0x7); |
34 | } | 68 | } |
@@ -90,7 +124,7 @@ nouveau_agp_reset(struct nouveau_drm *drm) | |||
90 | if (ret) | 124 | if (ret) |
91 | return; | 125 | return; |
92 | 126 | ||
93 | mode.mode = get_agp_mode(drm, info.mode); | 127 | mode.mode = get_agp_mode(drm, &info); |
94 | mode.mode &= ~PCI_AGP_COMMAND_FW; | 128 | mode.mode &= ~PCI_AGP_COMMAND_FW; |
95 | 129 | ||
96 | ret = drm_agp_enable(dev, mode); | 130 | ret = drm_agp_enable(dev, mode); |
@@ -139,7 +173,7 @@ nouveau_agp_init(struct nouveau_drm *drm) | |||
139 | } | 173 | } |
140 | 174 | ||
141 | /* see agp.h for the AGPSTAT_* modes available */ | 175 | /* see agp.h for the AGPSTAT_* modes available */ |
142 | mode.mode = get_agp_mode(drm, info.mode); | 176 | mode.mode = get_agp_mode(drm, &info); |
143 | 177 | ||
144 | ret = drm_agp_enable(dev, mode); | 178 | ret = drm_agp_enable(dev, mode); |
145 | if (ret) { | 179 | if (ret) { |