]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/char/agp/generic.c
Merge branch 'for-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jikos/hid
[mv-sheeva.git] / drivers / char / agp / generic.c
index c39200161688eef6ed3b45b6a1de451f4cd67dc9..3491d6f84bc6098b321965edacf416c7a0d277ac 100644 (file)
@@ -419,6 +419,31 @@ static void agp_v2_parse_one(u32 *requested_mode, u32 *bridge_agpstat, u32 *vga_
                *requested_mode &= ~AGP2_RESERVED_MASK;
        }
 
+       /*
+        * Some dumb bridges are programmed to disobey the AGP2 spec.
+        * This is likely a BIOS misprogramming rather than poweron default, or
+        * it would be a lot more common.
+        * https://bugs.freedesktop.org/show_bug.cgi?id=8816
+        * AGPv2 spec 6.1.9 states:
+        *   The RATE field indicates the data transfer rates supported by this
+        *   device. A.G.P. devices must report all that apply.
+        * Fix them up as best we can.
+        */
+       switch (*bridge_agpstat & 7) {
+       case 4:
+               *bridge_agpstat |= (AGPSTAT2_2X | AGPSTAT2_1X);
+               printk(KERN_INFO PFX "BIOS bug. AGP bridge claims to only support x4 rate"
+                       "Fixing up support for x2 & x1\n");
+               break;
+       case 2:
+               *bridge_agpstat |= AGPSTAT2_1X;
+               printk(KERN_INFO PFX "BIOS bug. AGP bridge claims to only support x2 rate"
+                       "Fixing up support for x1\n");
+               break;
+       default:
+               break;
+       }
+
        /* Check the speed bits make sense. Only one should be set. */
        tmp = *requested_mode & 7;
        switch (tmp) {
@@ -940,6 +965,9 @@ int agp_generic_insert_memory(struct agp_memory * mem, off_t pg_start, int type)
        if (!bridge)
                return -EINVAL;
 
+       if (mem->page_count == 0)
+               return 0;
+
        temp = bridge->current_size;
 
        switch (bridge->driver->size_type) {
@@ -991,8 +1019,8 @@ int agp_generic_insert_memory(struct agp_memory * mem, off_t pg_start, int type)
 
        for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
                writel(bridge->driver->mask_memory(bridge, mem->memory[i], mem->type), bridge->gatt_table+j);
-               readl(bridge->gatt_table+j);    /* PCI Posting. */
        }
+       readl(bridge->gatt_table+j-1);  /* PCI Posting. */
 
        bridge->driver->tlb_flush(mem);
        return 0;
@@ -1009,6 +1037,9 @@ int agp_generic_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
        if (!bridge)
                return -EINVAL;
 
+       if (mem->page_count == 0)
+               return 0;
+
        if (type != 0 || mem->type != 0) {
                /* The generic routines know nothing of memory types */
                return -EINVAL;
@@ -1017,10 +1048,9 @@ int agp_generic_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
        /* AK: bogus, should encode addresses > 4GB */
        for (i = pg_start; i < (mem->page_count + pg_start); i++) {
                writel(bridge->scratch_page, bridge->gatt_table+i);
-               readl(bridge->gatt_table+i);    /* PCI Posting. */
        }
+       readl(bridge->gatt_table+i-1);  /* PCI Posting. */
 
-       global_cache_flush();
        bridge->driver->tlb_flush(mem);
        return 0;
 }
@@ -1054,7 +1084,7 @@ void *agp_generic_alloc_page(struct agp_bridge_data *bridge)
 {
        struct page * page;
 
-       page = alloc_page(GFP_KERNEL);
+       page = alloc_page(GFP_KERNEL | GFP_DMA32);
        if (page == NULL)
                return NULL;