From 804af2cf6e7af31d2e664b54e657dddd9b531dbd Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Wed, 26 Jul 2006 21:39:49 +0100 Subject: [PATCH 01/10] [AGPGART] remove private page protection map AGP keeps its own copy of the protection_map, upcoming DRM changes will also require access to this map from modules. Signed-off-by: Hugh Dickins Signed-off-by: Dave Airlie Signed-off-by: Dave Jones --- drivers/char/agp/frontend.c | 27 ++------------------------- include/linux/mm.h | 1 + mm/mmap.c | 7 +++++++ 3 files changed, 10 insertions(+), 25 deletions(-) diff --git a/drivers/char/agp/frontend.c b/drivers/char/agp/frontend.c index d9c5a9142ad1..0f2ed2aa2d81 100644 --- a/drivers/char/agp/frontend.c +++ b/drivers/char/agp/frontend.c @@ -151,35 +151,12 @@ static void agp_add_seg_to_client(struct agp_client *client, client->segments = seg; } -/* Originally taken from linux/mm/mmap.c from the array - * protection_map. - * The original really should be exported to modules, or - * some routine which does the conversion for you - */ - -static const pgprot_t my_protect_map[16] = -{ - __P000, __P001, __P010, __P011, __P100, __P101, __P110, __P111, - __S000, __S001, __S010, __S011, __S100, __S101, __S110, __S111 -}; - static pgprot_t agp_convert_mmap_flags(int prot) { -#define _trans(x,bit1,bit2) \ -((bit1==bit2)?(x&bit1):(x&bit1)?bit2:0) - unsigned long prot_bits; - pgprot_t temp; - prot_bits = _trans(prot, PROT_READ, VM_READ) | - _trans(prot, PROT_WRITE, VM_WRITE) | - _trans(prot, PROT_EXEC, VM_EXEC); - - prot_bits |= VM_SHARED; - - temp = my_protect_map[prot_bits & 0x0000000f]; - - return temp; + prot_bits = calc_vm_prot_bits(prot) | VM_SHARED; + return vm_get_page_prot(prot_bits); } static int agp_create_segment(struct agp_client *client, struct agp_region *region) diff --git a/include/linux/mm.h b/include/linux/mm.h index 990957e0929f..4fba4560699b 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1012,6 +1012,7 @@ static inline unsigned long vma_pages(struct vm_area_struct *vma) return (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; } +pgprot_t vm_get_page_prot(unsigned long vm_flags); struct vm_area_struct *find_extend_vma(struct mm_struct *, unsigned long addr); struct page *vmalloc_to_page(void *addr); unsigned long vmalloc_to_pfn(void *addr); diff --git a/mm/mmap.c b/mm/mmap.c index c1868ecdbc5f..c7ed061f4507 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -60,6 +60,13 @@ pgprot_t protection_map[16] = { __S000, __S001, __S010, __S011, __S100, __S101, __S110, __S111 }; +pgprot_t vm_get_page_prot(unsigned long vm_flags) +{ + return protection_map[vm_flags & + (VM_READ|VM_WRITE|VM_EXEC|VM_SHARED)]; +} +EXPORT_SYMBOL(vm_get_page_prot); + int sysctl_overcommit_memory = OVERCOMMIT_GUESS; /* heuristic overcommit */ int sysctl_overcommit_ratio = 50; /* default is 50% */ int sysctl_max_map_count __read_mostly = DEFAULT_MAX_MAP_COUNT; From e7745d4e0299a3460128917ceb6b6a807fa7f9e8 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Fri, 11 Aug 2006 18:02:27 -0400 Subject: [PATCH 02/10] [AGPGART] Const'ify the agpgart driver version. Signed-off-by: Dave Jones --- drivers/char/agp/backend.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/agp/backend.c b/drivers/char/agp/backend.c index 509adc403250..d59e037ddd12 100644 --- a/drivers/char/agp/backend.c +++ b/drivers/char/agp/backend.c @@ -44,7 +44,7 @@ * past 0.99 at all due to some boolean logic error. */ #define AGPGART_VERSION_MAJOR 0 #define AGPGART_VERSION_MINOR 101 -static struct agp_version agp_current_version = +static const struct agp_version agp_current_version = { .major = AGPGART_VERSION_MAJOR, .minor = AGPGART_VERSION_MINOR, From 71565619af84a15d0abef6f0d6704e6472cd87c1 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Sat, 12 Aug 2006 01:59:50 +0400 Subject: [PATCH 03/10] [AGPGART] CONFIG_PM=n slim: drivers/char/agp/efficeon-agp.c Signed-off-by: Alexey Dobriyan Signed-off-by: Dave Jones --- drivers/char/agp/efficeon-agp.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/char/agp/efficeon-agp.c b/drivers/char/agp/efficeon-agp.c index b788b0a3bbf3..30f730ff81c1 100644 --- a/drivers/char/agp/efficeon-agp.c +++ b/drivers/char/agp/efficeon-agp.c @@ -337,13 +337,6 @@ static struct agp_bridge_driver efficeon_driver = { .agp_destroy_page = agp_generic_destroy_page, }; - -static int agp_efficeon_resume(struct pci_dev *pdev) -{ - printk(KERN_DEBUG PFX "agp_efficeon_resume()\n"); - return efficeon_configure(); -} - static int __devinit agp_efficeon_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -414,11 +407,18 @@ static void __devexit agp_efficeon_remove(struct pci_dev *pdev) agp_put_bridge(bridge); } +#ifdef CONFIG_PM static int agp_efficeon_suspend(struct pci_dev *dev, pm_message_t state) { return 0; } +static int agp_efficeon_resume(struct pci_dev *pdev) +{ + printk(KERN_DEBUG PFX "agp_efficeon_resume()\n"); + return efficeon_configure(); +} +#endif static struct pci_device_id agp_efficeon_pci_table[] = { { @@ -439,8 +439,10 @@ static struct pci_driver agp_efficeon_pci_driver = { .id_table = agp_efficeon_pci_table, .probe = agp_efficeon_probe, .remove = agp_efficeon_remove, +#ifdef CONFIG_PM .suspend = agp_efficeon_suspend, .resume = agp_efficeon_resume, +#endif }; static int __init agp_efficeon_init(void) From 85be7d60595b4803731cec158b0023bc050fdd14 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Sat, 12 Aug 2006 02:02:02 +0400 Subject: [PATCH 04/10] [AGPGART] CONFIG_PM=n slim: drivers/char/agp/intel-agp.c Signed-off-by: Alexey Dobriyan Signed-off-by: Dave Jones --- drivers/char/agp/intel-agp.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index 61ac3809f997..42a1cb871992 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -1766,6 +1766,7 @@ static void __devexit agp_intel_remove(struct pci_dev *pdev) agp_put_bridge(bridge); } +#ifdef CONFIG_PM static int agp_intel_resume(struct pci_dev *pdev) { struct agp_bridge_data *bridge = pci_get_drvdata(pdev); @@ -1789,6 +1790,7 @@ static int agp_intel_resume(struct pci_dev *pdev) return 0; } +#endif static struct pci_device_id agp_intel_pci_table[] = { #define ID(x) \ @@ -1835,7 +1837,9 @@ static struct pci_driver agp_intel_pci_driver = { .id_table = agp_intel_pci_table, .probe = agp_intel_probe, .remove = __devexit_p(agp_intel_remove), +#ifdef CONFIG_PM .resume = agp_intel_resume, +#endif }; static int __init agp_intel_init(void) From b53e674a707cf77e76339852abdc063696679261 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Fri, 11 Aug 2006 18:13:41 -0400 Subject: [PATCH 05/10] [AGPGART] const'ify VIA AGP PCI table. Signed-off-by: Dave Jones --- drivers/char/agp/via-agp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/char/agp/via-agp.c b/drivers/char/agp/via-agp.c index b8ec25d17478..c149ac9ce9a7 100644 --- a/drivers/char/agp/via-agp.c +++ b/drivers/char/agp/via-agp.c @@ -9,7 +9,7 @@ #include #include "agp.h" -static struct pci_device_id agp_via_pci_table[]; +static const struct pci_device_id agp_via_pci_table[]; #define VIA_GARTCTRL 0x80 #define VIA_APSIZE 0x84 @@ -485,7 +485,7 @@ static int agp_via_resume(struct pci_dev *pdev) #endif /* CONFIG_PM */ /* must be the same order as name table above */ -static struct pci_device_id agp_via_pci_table[] = { +static const struct pci_device_id agp_via_pci_table[] = { #define ID(x) \ { \ .class = (PCI_CLASS_BRIDGE_HOST << 8), \ From 8eb7925f93af75e66a240d148efdec212f95bcb7 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Sun, 20 Aug 2006 18:48:13 +0400 Subject: [PATCH 06/10] [AGPGART] agp.h: constify struct agp_bridge_data::version drivers/char/agp/backend.c: In function `agp_backend_initialize': drivers/char/agp/backend.c:141: warning: assignment discards qualifiers from pointer target type Signed-off-by: Alexey Dobriyan Signed-off-by: Dave Jones --- drivers/char/agp/agp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h index 3c623b67ea1c..8b3317fd46c9 100644 --- a/drivers/char/agp/agp.h +++ b/drivers/char/agp/agp.h @@ -117,7 +117,7 @@ struct agp_bridge_driver { }; struct agp_bridge_data { - struct agp_version *version; + const struct agp_version *version; struct agp_bridge_driver *driver; struct vm_operations_struct *vm_ops; void *previous_size; From 65c25aadfa4e917060e99fe459f33a6a07db53cc Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 6 Sep 2006 11:57:18 -0400 Subject: [PATCH 07/10] [AGPGART] Intel 965 Express support. From: Alan Hourihane From: Eric Anholt Signed-off-by: Dave Jones --- drivers/char/agp/intel-agp.c | 163 ++++++++++++++++++++++++++++++++--- 1 file changed, 152 insertions(+), 11 deletions(-) diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index 42a1cb871992..a425f27af9ea 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -2,14 +2,6 @@ * Intel AGPGART routines. */ -/* - * Intel(R) 855GM/852GM and 865G support added by David Dawes - * . - * - * Intel(R) 915G/915GM support added by Alan Hourihane - * . - */ - #include #include #include @@ -17,6 +9,21 @@ #include #include "agp.h" +#define PCI_DEVICE_ID_INTEL_82946GZ_HB 0x2970 +#define PCI_DEVICE_ID_INTEL_82946GZ_IG 0x2972 +#define PCI_DEVICE_ID_INTEL_82965G_1_HB 0x2980 +#define PCI_DEVICE_ID_INTEL_82965G_1_IG 0x2982 +#define PCI_DEVICE_ID_INTEL_82965Q_HB 0x2990 +#define PCI_DEVICE_ID_INTEL_82965Q_IG 0x2992 +#define PCI_DEVICE_ID_INTEL_82965G_HB 0x29A0 +#define PCI_DEVICE_ID_INTEL_82965G_IG 0x29A2 + +#define IS_I965 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82946GZ_HB || \ + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965G_1_HB || \ + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965Q_HB || \ + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965G_HB) + + /* Intel 815 register */ #define INTEL_815_APCONT 0x51 #define INTEL_815_ATTBASE_MASK ~0x1FFFFFFF @@ -40,6 +47,8 @@ #define I915_GMCH_GMS_STOLEN_48M (0x6 << 4) #define I915_GMCH_GMS_STOLEN_64M (0x7 << 4) +/* Intel 965G registers */ +#define I965_MSAC 0x62 /* Intel 7505 registers */ #define INTEL_I7505_APSIZE 0x74 @@ -354,6 +363,7 @@ static struct aper_size_info_fixed intel_i830_sizes[] = /* The 64M mode still requires a 128k gatt */ {64, 16384, 5}, {256, 65536, 6}, + {512, 131072, 7}, }; static struct _intel_i830_private { @@ -377,7 +387,11 @@ static void intel_i830_init_gtt_entries(void) /* We obtain the size of the GTT, which is also stored (for some * reason) at the top of stolen memory. Then we add 4KB to that * for the video BIOS popup, which is also stored in there. */ - size = agp_bridge->driver->fetch_size() + 4; + + if (IS_I965) + size = 512 + 4; + else + size = agp_bridge->driver->fetch_size() + 4; if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82830_HB || agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) { @@ -423,7 +437,7 @@ static void intel_i830_init_gtt_entries(void) if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915G_HB || agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB || agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB || - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB) + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB || IS_I965 ) gtt_entries = MB(48) - KB(size); else gtt_entries = 0; @@ -433,7 +447,7 @@ static void intel_i830_init_gtt_entries(void) if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915G_HB || agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB || agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB || - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB) + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB || IS_I965) gtt_entries = MB(64) - KB(size); else gtt_entries = 0; @@ -791,6 +805,77 @@ static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge) return 0; } +static int intel_i965_fetch_size(void) +{ + struct aper_size_info_fixed *values; + u32 offset = 0; + u8 temp; + +#define I965_512MB_ADDRESS_MASK (3<<1) + + values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes); + + pci_read_config_byte(intel_i830_private.i830_dev, I965_MSAC, &temp); + temp &= I965_512MB_ADDRESS_MASK; + switch (temp) { + case 0x00: + offset = 0; /* 128MB */ + break; + case 0x06: + offset = 3; /* 512MB */ + break; + default: + case 0x02: + offset = 2; /* 256MB */ + break; + } + + agp_bridge->previous_size = agp_bridge->current_size = (void *)(values + offset); + + return values[offset].size; +} + +/* The intel i965 automatically initializes the agp aperture during POST. ++ * Use the memory already set aside for in the GTT. ++ */ +static int intel_i965_create_gatt_table(struct agp_bridge_data *bridge) +{ + int page_order; + struct aper_size_info_fixed *size; + int num_entries; + u32 temp; + + size = agp_bridge->current_size; + page_order = size->page_order; + num_entries = size->num_entries; + agp_bridge->gatt_table_real = NULL; + + pci_read_config_dword(intel_i830_private.i830_dev, I915_MMADDR, &temp); + + temp &= 0xfff00000; + intel_i830_private.gtt = ioremap((temp + (512 * 1024)) , 512 * 1024); + + if (!intel_i830_private.gtt) + return -ENOMEM; + + + intel_i830_private.registers = ioremap(temp,128 * 4096); + if (!intel_i830_private.registers) + return -ENOMEM; + + temp = readl(intel_i830_private.registers+I810_PGETBL_CTL) & 0xfffff000; + global_cache_flush(); /* FIXME: ? */ + + /* we have to call this as early as possible after the MMIO base address is known */ + intel_i830_init_gtt_entries(); + + agp_bridge->gatt_table = NULL; + + agp_bridge->gatt_bus_addr = temp; + + return 0; +} + static int intel_fetch_size(void) { @@ -1489,6 +1574,29 @@ static struct agp_bridge_driver intel_915_driver = { .agp_destroy_page = agp_generic_destroy_page, }; +static struct agp_bridge_driver intel_i965_driver = { + .owner = THIS_MODULE, + .aperture_sizes = intel_i830_sizes, + .size_type = FIXED_APER_SIZE, + .num_aperture_sizes = 4, + .needs_scratch_page = TRUE, + .configure = intel_i915_configure, + .fetch_size = intel_i965_fetch_size, + .cleanup = intel_i915_cleanup, + .tlb_flush = intel_i810_tlbflush, + .mask_memory = intel_i810_mask_memory, + .masks = intel_i810_masks, + .agp_enable = intel_i810_agp_enable, + .cache_flush = global_cache_flush, + .create_gatt_table = intel_i965_create_gatt_table, + .free_gatt_table = intel_i830_free_gatt_table, + .insert_memory = intel_i915_insert_entries, + .remove_memory = intel_i915_remove_entries, + .alloc_by_type = intel_i830_alloc_by_type, + .free_by_type = intel_i810_free_by_type, + .agp_alloc_page = agp_generic_alloc_page, + .agp_destroy_page = agp_generic_destroy_page, +}; static struct agp_bridge_driver intel_7505_driver = { .owner = THIS_MODULE, @@ -1684,6 +1792,35 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev, bridge->driver = &intel_845_driver; name = "945GM"; break; + case PCI_DEVICE_ID_INTEL_82946GZ_HB: + if (find_i830(PCI_DEVICE_ID_INTEL_82946GZ_IG)) + bridge->driver = &intel_i965_driver; + else + bridge->driver = &intel_845_driver; + name = "946GZ"; + break; + case PCI_DEVICE_ID_INTEL_82965G_1_HB: + if (find_i830(PCI_DEVICE_ID_INTEL_82965G_1_IG)) + bridge->driver = &intel_i965_driver; + else + bridge->driver = &intel_845_driver; + name = "965G"; + break; + case PCI_DEVICE_ID_INTEL_82965Q_HB: + if (find_i830(PCI_DEVICE_ID_INTEL_82965Q_IG)) + bridge->driver = &intel_i965_driver; + else + bridge->driver = &intel_845_driver; + name = "965Q"; + break; + case PCI_DEVICE_ID_INTEL_82965G_HB: + if (find_i830(PCI_DEVICE_ID_INTEL_82965G_IG)) + bridge->driver = &intel_i965_driver; + else + bridge->driver = &intel_845_driver; + name = "965G"; + break; + case PCI_DEVICE_ID_INTEL_7505_0: bridge->driver = &intel_7505_driver; name = "E7505"; @@ -1827,6 +1964,10 @@ static struct pci_device_id agp_intel_pci_table[] = { ID(PCI_DEVICE_ID_INTEL_82915GM_HB), ID(PCI_DEVICE_ID_INTEL_82945G_HB), ID(PCI_DEVICE_ID_INTEL_82945GM_HB), + ID(PCI_DEVICE_ID_INTEL_82946GZ_HB), + ID(PCI_DEVICE_ID_INTEL_82965G_1_HB), + ID(PCI_DEVICE_ID_INTEL_82965Q_HB), + ID(PCI_DEVICE_ID_INTEL_82965G_HB), { } }; From c14635eb4e591c61e419c065df1fdacf9ff90c00 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Wed, 6 Sep 2006 11:59:35 -0400 Subject: [PATCH 08/10] [AGPGART] Fix number of aperture sizes in 830 gart structs. Spotted by Eric Anholt. Signed-off-by: Dave Jones --- drivers/char/agp/intel-agp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index a425f27af9ea..42c7d8dec635 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -1392,7 +1392,7 @@ static struct agp_bridge_driver intel_830_driver = { .owner = THIS_MODULE, .aperture_sizes = intel_i830_sizes, .size_type = FIXED_APER_SIZE, - .num_aperture_sizes = 3, + .num_aperture_sizes = 4, .needs_scratch_page = TRUE, .configure = intel_i830_configure, .fetch_size = intel_i830_fetch_size, @@ -1554,7 +1554,7 @@ static struct agp_bridge_driver intel_915_driver = { .owner = THIS_MODULE, .aperture_sizes = intel_i830_sizes, .size_type = FIXED_APER_SIZE, - .num_aperture_sizes = 3, + .num_aperture_sizes = 4, .needs_scratch_page = TRUE, .configure = intel_i915_configure, .fetch_size = intel_i915_fetch_size, From 08da3f413f6aa3eb48cfc5331c68e57393167fe5 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Sun, 10 Sep 2006 21:09:26 -0400 Subject: [PATCH 09/10] [AGPGART] Add suspend callback for i965 Signed-off-by: Dave Jones --- drivers/char/agp/intel-agp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index 42c7d8dec635..d1ede7db5a12 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -1924,6 +1924,8 @@ static int agp_intel_resume(struct pci_dev *pdev) intel_i830_configure(); else if (bridge->driver == &intel_810_driver) intel_i810_configure(); + else if (bridge->driver == &intel_i965_driver) + intel_i915_configure(); return 0; } From edf03fb0575cbee2595a63374b17dc0921f2094a Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Sun, 10 Sep 2006 21:12:20 -0400 Subject: [PATCH 10/10] [AGPGART] Rework AGPv3 modesetting fallback. Sometimes the logic to handle AGPx8->AGPx4 fallback failed, as can be seen in https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=197346 The failures occured if the bridge was in AGPx8 mode, but the user hadn't specified a mode in their X config. We weren't setting the mode to the highest mode capable by the video card+bridge (as we do in the AGPv2 case), which was leading to all kinds of mayhem including us believing that after falling back from AGPx8, that we couldn't do x4 mode (which is disastrous in AGPv3, as those are the only two modes possible). Signed-off-by: Dave Jones --- drivers/char/agp/generic.c | 39 +++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c index cc5ea347a8a7..0dcdb363923f 100644 --- a/drivers/char/agp/generic.c +++ b/drivers/char/agp/generic.c @@ -568,25 +568,34 @@ static void agp_v3_parse_one(u32 *requested_mode, u32 *bridge_agpstat, u32 *vga_ *bridge_agpstat &= ~(AGPSTAT3_4X | AGPSTAT3_RSVD); goto done; + } else if (*requested_mode & AGPSTAT3_4X) { + *bridge_agpstat &= ~(AGPSTAT3_8X | AGPSTAT3_RSVD); + *bridge_agpstat |= AGPSTAT3_4X; + goto done; + } else { /* - * If we didn't specify AGPx8, we can only do x4. - * If the hardware can't do x4, we're up shit creek, and never - * should have got this far. + * If we didn't specify an AGP mode, we see if both + * the graphics card, and the bridge can do x8, and use if so. + * If not, we fall back to x4 mode. */ - *bridge_agpstat &= ~(AGPSTAT3_8X | AGPSTAT3_RSVD); - if ((*bridge_agpstat & AGPSTAT3_4X) && (*vga_agpstat & AGPSTAT3_4X)) - *bridge_agpstat |= AGPSTAT3_4X; - else { - printk(KERN_INFO PFX "Badness. Don't know which AGP mode to set. " - "[bridge_agpstat:%x vga_agpstat:%x fell back to:- bridge_agpstat:%x vga_agpstat:%x]\n", - origbridge, origvga, *bridge_agpstat, *vga_agpstat); - if (!(*bridge_agpstat & AGPSTAT3_4X)) - printk(KERN_INFO PFX "Bridge couldn't do AGP x4.\n"); - if (!(*vga_agpstat & AGPSTAT3_4X)) - printk(KERN_INFO PFX "Graphic card couldn't do AGP x4.\n"); - return; + if ((*bridge_agpstat & AGPSTAT3_8X) && (*vga_agpstat & AGPSTAT3_8X)) { + printk(KERN_INFO PFX "No AGP mode specified. Setting to highest mode supported by bridge & card (x8).\n"); + *bridge_agpstat &= ~(AGPSTAT3_4X | AGPSTAT3_RSVD); + *vga_agpstat &= ~(AGPSTAT3_4X | AGPSTAT3_RSVD); + } else { + printk(KERN_INFO PFX "Fell back to AGPx4 mode because"); + if (!(*bridge_agpstat & AGPSTAT3_8X)) { + printk("bridge couldn't do x8. bridge_agpstat:%x (orig=%x)\n", *bridge_agpstat, origbridge); + *bridge_agpstat &= ~(AGPSTAT3_8X | AGPSTAT3_RSVD); + *bridge_agpstat |= AGPSTAT3_4X; + } + if (!(*vga_agpstat & AGPSTAT3_8X)) { + printk("graphics card couldn't do x8. vga_agpstat:%x (orig=%x)\n", *vga_agpstat, origvga); + *vga_agpstat &= ~(AGPSTAT3_8X | AGPSTAT3_RSVD); + *vga_agpstat |= AGPSTAT3_4X; + } } }