root/drivers/char/agp/intel-agp.c
/*
 * Intel AGPGART routines.
 */

#include <linux/module.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/pagemap.h>
#include <linux/agp_backend.h>
#include <asm/smp.h>
#include "agp.h"
#include "intel-agp.h"
#include <drm/intel/intel-gtt.h>

static int intel_fetch_size(void)
{
        int i;
        u16 temp;
        struct aper_size_info_16 *values;

        pci_read_config_word(agp_bridge->dev, INTEL_APSIZE, &temp);
        values = A_SIZE_16(agp_bridge->driver->aperture_sizes);

        for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) {
                if (temp == values[i].size_value) {
                        agp_bridge->previous_size = agp_bridge->current_size = (void *) (values + i);
                        agp_bridge->aperture_size_idx = i;
                        return values[i].size;
                }
        }

        return 0;
}

static int __intel_8xx_fetch_size(u8 temp)
{
        int i;
        struct aper_size_info_8 *values;

        values = A_SIZE_8(agp_bridge->driver->aperture_sizes);

        for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) {
                if (temp == values[i].size_value) {
                        agp_bridge->previous_size =
                                agp_bridge->current_size = (void *) (values + i);
                        agp_bridge->aperture_size_idx = i;
                        return values[i].size;
                }
        }
        return 0;
}

static int intel_8xx_fetch_size(void)
{
        u8 temp;

        pci_read_config_byte(agp_bridge->dev, INTEL_APSIZE, &temp);
        return __intel_8xx_fetch_size(temp);
}

static int intel_815_fetch_size(void)
{
        u8 temp;

        /* Intel 815 chipsets have a _weird_ APSIZE register with only
         * one non-reserved bit, so mask the others out ... */
        pci_read_config_byte(agp_bridge->dev, INTEL_APSIZE, &temp);
        temp &= (1 << 3);

        return __intel_8xx_fetch_size(temp);
}

static void intel_tlbflush(struct agp_memory *mem)
{
        pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x2200);
        pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x2280);
}


static void intel_8xx_tlbflush(struct agp_memory *mem)
{
        u32 temp;
        pci_read_config_dword(agp_bridge->dev, INTEL_AGPCTRL, &temp);
        pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, temp & ~(1 << 7));
        pci_read_config_dword(agp_bridge->dev, INTEL_AGPCTRL, &temp);
        pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, temp | (1 << 7));
}


static void intel_cleanup(void)
{
        u16 temp;
        struct aper_size_info_16 *previous_size;

        previous_size = A_SIZE_16(agp_bridge->previous_size);
        pci_read_config_word(agp_bridge->dev, INTEL_NBXCFG, &temp);
        pci_write_config_word(agp_bridge->dev, INTEL_NBXCFG, temp & ~(1 << 9));
        pci_write_config_word(agp_bridge->dev, INTEL_APSIZE, previous_size->size_value);
}


static void intel_8xx_cleanup(void)
{
        u16 temp;
        struct aper_size_info_8 *previous_size;

        previous_size = A_SIZE_8(agp_bridge->previous_size);
        pci_read_config_word(agp_bridge->dev, INTEL_NBXCFG, &temp);
        pci_write_config_word(agp_bridge->dev, INTEL_NBXCFG, temp & ~(1 << 9));
        pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, previous_size->size_value);
}


static int intel_configure(void)
{
        u16 temp2;
        struct aper_size_info_16 *current_size;

        current_size = A_SIZE_16(agp_bridge->current_size);

        /* aperture size */
        pci_write_config_word(agp_bridge->dev, INTEL_APSIZE, current_size->size_value);

        /* address to map to */
        agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev,
                                                    AGP_APERTURE_BAR);

        /* attbase - aperture base */
        pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr);

        /* agpctrl */
        pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x2280);

        /* paccfg/nbxcfg */
        pci_read_config_word(agp_bridge->dev, INTEL_NBXCFG, &temp2);
        pci_write_config_word(agp_bridge->dev, INTEL_NBXCFG,
                        (temp2 & ~(1 << 10)) | (1 << 9));
        /* clear any possible error conditions */
        pci_write_config_byte(agp_bridge->dev, INTEL_ERRSTS + 1, 7);
        return 0;
}

static int intel_815_configure(void)
{
        u32 addr;
        u8 temp2;
        struct aper_size_info_8 *current_size;

        /* attbase - aperture base */
        /* the Intel 815 chipset spec. says that bits 29-31 in the
        * ATTBASE register are reserved -> try not to write them */
        if (agp_bridge->gatt_bus_addr & INTEL_815_ATTBASE_MASK) {
                dev_emerg(&agp_bridge->dev->dev, "gatt bus addr too high");
                return -EINVAL;
        }

        current_size = A_SIZE_8(agp_bridge->current_size);

        /* aperture size */
        pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE,
                        current_size->size_value);

        /* address to map to */
        agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev,
                                                    AGP_APERTURE_BAR);

        pci_read_config_dword(agp_bridge->dev, INTEL_ATTBASE, &addr);
        addr &= INTEL_815_ATTBASE_MASK;
        addr |= agp_bridge->gatt_bus_addr;
        pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, addr);

        /* agpctrl */
        pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000);

        /* apcont */
        pci_read_config_byte(agp_bridge->dev, INTEL_815_APCONT, &temp2);
        pci_write_config_byte(agp_bridge->dev, INTEL_815_APCONT, temp2 | (1 << 1));

        /* clear any possible error conditions */
        /* Oddness : this chipset seems to have no ERRSTS register ! */
        return 0;
}

static void intel_820_tlbflush(struct agp_memory *mem)
{
        return;
}

static void intel_820_cleanup(void)
{
        u8 temp;
        struct aper_size_info_8 *previous_size;

        previous_size = A_SIZE_8(agp_bridge->previous_size);
        pci_read_config_byte(agp_bridge->dev, INTEL_I820_RDCR, &temp);
        pci_write_config_byte(agp_bridge->dev, INTEL_I820_RDCR,
                        temp & ~(1 << 1));
        pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE,
                        previous_size->size_value);
}


static int intel_820_configure(void)
{
        u8 temp2;
        struct aper_size_info_8 *current_size;

        current_size = A_SIZE_8(agp_bridge->current_size);

        /* aperture size */
        pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value);

        /* address to map to */
        agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev,
                                                    AGP_APERTURE_BAR);

        /* attbase - aperture base */
        pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr);

        /* agpctrl */
        pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000);

        /* global enable aperture access */
        /* This flag is not accessed through MCHCFG register as in */
        /* i850 chipset. */
        pci_read_config_byte(agp_bridge->dev, INTEL_I820_RDCR, &temp2);
        pci_write_config_byte(agp_bridge->dev, INTEL_I820_RDCR, temp2 | (1 << 1));
        /* clear any possible AGP-related error conditions */
        pci_write_config_word(agp_bridge->dev, INTEL_I820_ERRSTS, 0x001c);
        return 0;
}

static int intel_840_configure(void)
{
        u16 temp2;
        struct aper_size_info_8 *current_size;

        current_size = A_SIZE_8(agp_bridge->current_size);

        /* aperture size */
        pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value);

        /* address to map to */
        agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev,
                                                    AGP_APERTURE_BAR);

        /* attbase - aperture base */
        pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr);

        /* agpctrl */
        pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000);

        /* mcgcfg */
        pci_read_config_word(agp_bridge->dev, INTEL_I840_MCHCFG, &temp2);
        pci_write_config_word(agp_bridge->dev, INTEL_I840_MCHCFG, temp2 | (1 << 9));
        /* clear any possible error conditions */
        pci_write_config_word(agp_bridge->dev, INTEL_I840_ERRSTS, 0xc000);
        return 0;
}

static int intel_845_configure(void)
{
        u8 temp2;
        struct aper_size_info_8 *current_size;

        current_size = A_SIZE_8(agp_bridge->current_size);

        /* aperture size */
        pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value);

        if (agp_bridge->apbase_config != 0) {
                pci_write_config_dword(agp_bridge->dev, AGP_APBASE,
                                       agp_bridge->apbase_config);
        } else {
                /* address to map to */
                agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev,
                                                            AGP_APERTURE_BAR);
                agp_bridge->apbase_config = agp_bridge->gart_bus_addr;
        }

        /* attbase - aperture base */
        pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr);

        /* agpctrl */
        pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000);

        /* agpm */
        pci_read_config_byte(agp_bridge->dev, INTEL_I845_AGPM, &temp2);
        pci_write_config_byte(agp_bridge->dev, INTEL_I845_AGPM, temp2 | (1 << 1));
        /* clear any possible error conditions */
        pci_write_config_word(agp_bridge->dev, INTEL_I845_ERRSTS, 0x001c);
        return 0;
}

static int intel_850_configure(void)
{
        u16 temp2;
        struct aper_size_info_8 *current_size;

        current_size = A_SIZE_8(agp_bridge->current_size);

        /* aperture size */
        pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value);

        /* address to map to */
        agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev,
                                                    AGP_APERTURE_BAR);

        /* attbase - aperture base */
        pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr);

        /* agpctrl */
        pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000);

        /* mcgcfg */
        pci_read_config_word(agp_bridge->dev, INTEL_I850_MCHCFG, &temp2);
        pci_write_config_word(agp_bridge->dev, INTEL_I850_MCHCFG, temp2 | (1 << 9));
        /* clear any possible AGP-related error conditions */
        pci_write_config_word(agp_bridge->dev, INTEL_I850_ERRSTS, 0x001c);
        return 0;
}

static int intel_860_configure(void)
{
        u16 temp2;
        struct aper_size_info_8 *current_size;

        current_size = A_SIZE_8(agp_bridge->current_size);

        /* aperture size */
        pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value);

        /* address to map to */
        agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev,
                                                    AGP_APERTURE_BAR);

        /* attbase - aperture base */
        pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr);

        /* agpctrl */
        pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000);

        /* mcgcfg */
        pci_read_config_word(agp_bridge->dev, INTEL_I860_MCHCFG, &temp2);
        pci_write_config_word(agp_bridge->dev, INTEL_I860_MCHCFG, temp2 | (1 << 9));
        /* clear any possible AGP-related error conditions */
        pci_write_config_word(agp_bridge->dev, INTEL_I860_ERRSTS, 0xf700);
        return 0;
}

static int intel_830mp_configure(void)
{
        u16 temp2;
        struct aper_size_info_8 *current_size;

        current_size = A_SIZE_8(agp_bridge->current_size);

        /* aperture size */
        pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value);

        /* address to map to */
        agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev,
                                                    AGP_APERTURE_BAR);

        /* attbase - aperture base */
        pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr);

        /* agpctrl */
        pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000);

        /* gmch */
        pci_read_config_word(agp_bridge->dev, INTEL_NBXCFG, &temp2);
        pci_write_config_word(agp_bridge->dev, INTEL_NBXCFG, temp2 | (1 << 9));
        /* clear any possible AGP-related error conditions */
        pci_write_config_word(agp_bridge->dev, INTEL_I830_ERRSTS, 0x1c);
        return 0;
}

static int intel_7505_configure(void)
{
        u16 temp2;
        struct aper_size_info_8 *current_size;

        current_size = A_SIZE_8(agp_bridge->current_size);

        /* aperture size */
        pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value);

        /* address to map to */
        agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev,
                                                    AGP_APERTURE_BAR);

        /* attbase - aperture base */
        pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr);

        /* agpctrl */
        pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000);

        /* mchcfg */
        pci_read_config_word(agp_bridge->dev, INTEL_I7505_MCHCFG, &temp2);
        pci_write_config_word(agp_bridge->dev, INTEL_I7505_MCHCFG, temp2 | (1 << 9));

        return 0;
}

/* Setup function */
static const struct gatt_mask intel_generic_masks[] =
{
        {.mask = 0x00000017, .type = 0}
};

static const struct aper_size_info_8 intel_815_sizes[2] =
{
        {64, 16384, 4, 0},
        {32, 8192, 3, 8},
};

static const struct aper_size_info_8 intel_8xx_sizes[7] =
{
        {256, 65536, 6, 0},
        {128, 32768, 5, 32},
        {64, 16384, 4, 48},
        {32, 8192, 3, 56},
        {16, 4096, 2, 60},
        {8, 2048, 1, 62},
        {4, 1024, 0, 63}
};

static const struct aper_size_info_16 intel_generic_sizes[7] =
{
        {256, 65536, 6, 0},
        {128, 32768, 5, 32},
        {64, 16384, 4, 48},
        {32, 8192, 3, 56},
        {16, 4096, 2, 60},
        {8, 2048, 1, 62},
        {4, 1024, 0, 63}
};

static const struct aper_size_info_8 intel_830mp_sizes[4] =
{
        {256, 65536, 6, 0},
        {128, 32768, 5, 32},
        {64, 16384, 4, 48},
        {32, 8192, 3, 56}
};

static const struct agp_bridge_driver intel_generic_driver = {
        .owner                  = THIS_MODULE,
        .aperture_sizes         = intel_generic_sizes,
        .size_type              = U16_APER_SIZE,
        .num_aperture_sizes     = 7,
        .needs_scratch_page     = true,
        .configure              = intel_configure,
        .fetch_size             = intel_fetch_size,
        .cleanup                = intel_cleanup,
        .tlb_flush              = intel_tlbflush,
        .mask_memory            = agp_generic_mask_memory,
        .masks                  = intel_generic_masks,
        .agp_enable             = agp_generic_enable,
        .cache_flush            = global_cache_flush,
        .create_gatt_table      = agp_generic_create_gatt_table,
        .free_gatt_table        = agp_generic_free_gatt_table,
        .insert_memory          = agp_generic_insert_memory,
        .remove_memory          = agp_generic_remove_memory,
        .alloc_by_type          = agp_generic_alloc_by_type,
        .free_by_type           = agp_generic_free_by_type,
        .agp_alloc_page         = agp_generic_alloc_page,
        .agp_alloc_pages        = agp_generic_alloc_pages,
        .agp_destroy_page       = agp_generic_destroy_page,
        .agp_destroy_pages      = agp_generic_destroy_pages,
        .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
};

static const struct agp_bridge_driver intel_815_driver = {
        .owner                  = THIS_MODULE,
        .aperture_sizes         = intel_815_sizes,
        .size_type              = U8_APER_SIZE,
        .num_aperture_sizes     = 2,
        .needs_scratch_page     = true,
        .configure              = intel_815_configure,
        .fetch_size             = intel_815_fetch_size,
        .cleanup                = intel_8xx_cleanup,
        .tlb_flush              = intel_8xx_tlbflush,
        .mask_memory            = agp_generic_mask_memory,
        .masks                  = intel_generic_masks,
        .agp_enable             = agp_generic_enable,
        .cache_flush            = global_cache_flush,
        .create_gatt_table      = agp_generic_create_gatt_table,
        .free_gatt_table        = agp_generic_free_gatt_table,
        .insert_memory          = agp_generic_insert_memory,
        .remove_memory          = agp_generic_remove_memory,
        .alloc_by_type          = agp_generic_alloc_by_type,
        .free_by_type           = agp_generic_free_by_type,
        .agp_alloc_page         = agp_generic_alloc_page,
        .agp_alloc_pages        = agp_generic_alloc_pages,
        .agp_destroy_page       = agp_generic_destroy_page,
        .agp_destroy_pages      = agp_generic_destroy_pages,
        .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
};

static const struct agp_bridge_driver intel_820_driver = {
        .owner                  = THIS_MODULE,
        .aperture_sizes         = intel_8xx_sizes,
        .size_type              = U8_APER_SIZE,
        .num_aperture_sizes     = 7,
        .needs_scratch_page     = true,
        .configure              = intel_820_configure,
        .fetch_size             = intel_8xx_fetch_size,
        .cleanup                = intel_820_cleanup,
        .tlb_flush              = intel_820_tlbflush,
        .mask_memory            = agp_generic_mask_memory,
        .masks                  = intel_generic_masks,
        .agp_enable             = agp_generic_enable,
        .cache_flush            = global_cache_flush,
        .create_gatt_table      = agp_generic_create_gatt_table,
        .free_gatt_table        = agp_generic_free_gatt_table,
        .insert_memory          = agp_generic_insert_memory,
        .remove_memory          = agp_generic_remove_memory,
        .alloc_by_type          = agp_generic_alloc_by_type,
        .free_by_type           = agp_generic_free_by_type,
        .agp_alloc_page         = agp_generic_alloc_page,
        .agp_alloc_pages        = agp_generic_alloc_pages,
        .agp_destroy_page       = agp_generic_destroy_page,
        .agp_destroy_pages      = agp_generic_destroy_pages,
        .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
};

static const struct agp_bridge_driver intel_830mp_driver = {
        .owner                  = THIS_MODULE,
        .aperture_sizes         = intel_830mp_sizes,
        .size_type              = U8_APER_SIZE,
        .num_aperture_sizes     = 4,
        .needs_scratch_page     = true,
        .configure              = intel_830mp_configure,
        .fetch_size             = intel_8xx_fetch_size,
        .cleanup                = intel_8xx_cleanup,
        .tlb_flush              = intel_8xx_tlbflush,
        .mask_memory            = agp_generic_mask_memory,
        .masks                  = intel_generic_masks,
        .agp_enable             = agp_generic_enable,
        .cache_flush            = global_cache_flush,
        .create_gatt_table      = agp_generic_create_gatt_table,
        .free_gatt_table        = agp_generic_free_gatt_table,
        .insert_memory          = agp_generic_insert_memory,
        .remove_memory          = agp_generic_remove_memory,
        .alloc_by_type          = agp_generic_alloc_by_type,
        .free_by_type           = agp_generic_free_by_type,
        .agp_alloc_page         = agp_generic_alloc_page,
        .agp_alloc_pages        = agp_generic_alloc_pages,
        .agp_destroy_page       = agp_generic_destroy_page,
        .agp_destroy_pages      = agp_generic_destroy_pages,
        .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
};

static const struct agp_bridge_driver intel_840_driver = {
        .owner                  = THIS_MODULE,
        .aperture_sizes         = intel_8xx_sizes,
        .size_type              = U8_APER_SIZE,
        .num_aperture_sizes     = 7,
        .needs_scratch_page     = true,
        .configure              = intel_840_configure,
        .fetch_size             = intel_8xx_fetch_size,
        .cleanup                = intel_8xx_cleanup,
        .tlb_flush              = intel_8xx_tlbflush,
        .mask_memory            = agp_generic_mask_memory,
        .masks                  = intel_generic_masks,
        .agp_enable             = agp_generic_enable,
        .cache_flush            = global_cache_flush,
        .create_gatt_table      = agp_generic_create_gatt_table,
        .free_gatt_table        = agp_generic_free_gatt_table,
        .insert_memory          = agp_generic_insert_memory,
        .remove_memory          = agp_generic_remove_memory,
        .alloc_by_type          = agp_generic_alloc_by_type,
        .free_by_type           = agp_generic_free_by_type,
        .agp_alloc_page         = agp_generic_alloc_page,
        .agp_alloc_pages        = agp_generic_alloc_pages,
        .agp_destroy_page       = agp_generic_destroy_page,
        .agp_destroy_pages      = agp_generic_destroy_pages,
        .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
};

static const struct agp_bridge_driver intel_845_driver = {
        .owner                  = THIS_MODULE,
        .aperture_sizes         = intel_8xx_sizes,
        .size_type              = U8_APER_SIZE,
        .num_aperture_sizes     = 7,
        .needs_scratch_page     = true,
        .configure              = intel_845_configure,
        .fetch_size             = intel_8xx_fetch_size,
        .cleanup                = intel_8xx_cleanup,
        .tlb_flush              = intel_8xx_tlbflush,
        .mask_memory            = agp_generic_mask_memory,
        .masks                  = intel_generic_masks,
        .agp_enable             = agp_generic_enable,
        .cache_flush            = global_cache_flush,
        .create_gatt_table      = agp_generic_create_gatt_table,
        .free_gatt_table        = agp_generic_free_gatt_table,
        .insert_memory          = agp_generic_insert_memory,
        .remove_memory          = agp_generic_remove_memory,
        .alloc_by_type          = agp_generic_alloc_by_type,
        .free_by_type           = agp_generic_free_by_type,
        .agp_alloc_page         = agp_generic_alloc_page,
        .agp_alloc_pages        = agp_generic_alloc_pages,
        .agp_destroy_page       = agp_generic_destroy_page,
        .agp_destroy_pages      = agp_generic_destroy_pages,
        .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
};

static const struct agp_bridge_driver intel_850_driver = {
        .owner                  = THIS_MODULE,
        .aperture_sizes         = intel_8xx_sizes,
        .size_type              = U8_APER_SIZE,
        .num_aperture_sizes     = 7,
        .needs_scratch_page     = true,
        .configure              = intel_850_configure,
        .fetch_size             = intel_8xx_fetch_size,
        .cleanup                = intel_8xx_cleanup,
        .tlb_flush              = intel_8xx_tlbflush,
        .mask_memory            = agp_generic_mask_memory,
        .masks                  = intel_generic_masks,
        .agp_enable             = agp_generic_enable,
        .cache_flush            = global_cache_flush,
        .create_gatt_table      = agp_generic_create_gatt_table,
        .free_gatt_table        = agp_generic_free_gatt_table,
        .insert_memory          = agp_generic_insert_memory,
        .remove_memory          = agp_generic_remove_memory,
        .alloc_by_type          = agp_generic_alloc_by_type,
        .free_by_type           = agp_generic_free_by_type,
        .agp_alloc_page         = agp_generic_alloc_page,
        .agp_alloc_pages        = agp_generic_alloc_pages,
        .agp_destroy_page       = agp_generic_destroy_page,
        .agp_destroy_pages      = agp_generic_destroy_pages,
        .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
};

static const struct agp_bridge_driver intel_860_driver = {
        .owner                  = THIS_MODULE,
        .aperture_sizes         = intel_8xx_sizes,
        .size_type              = U8_APER_SIZE,
        .num_aperture_sizes     = 7,
        .needs_scratch_page     = true,
        .configure              = intel_860_configure,
        .fetch_size             = intel_8xx_fetch_size,
        .cleanup                = intel_8xx_cleanup,
        .tlb_flush              = intel_8xx_tlbflush,
        .mask_memory            = agp_generic_mask_memory,
        .masks                  = intel_generic_masks,
        .agp_enable             = agp_generic_enable,
        .cache_flush            = global_cache_flush,
        .create_gatt_table      = agp_generic_create_gatt_table,
        .free_gatt_table        = agp_generic_free_gatt_table,
        .insert_memory          = agp_generic_insert_memory,
        .remove_memory          = agp_generic_remove_memory,
        .alloc_by_type          = agp_generic_alloc_by_type,
        .free_by_type           = agp_generic_free_by_type,
        .agp_alloc_page         = agp_generic_alloc_page,
        .agp_alloc_pages        = agp_generic_alloc_pages,
        .agp_destroy_page       = agp_generic_destroy_page,
        .agp_destroy_pages      = agp_generic_destroy_pages,
        .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
};

static const struct agp_bridge_driver intel_7505_driver = {
        .owner                  = THIS_MODULE,
        .aperture_sizes         = intel_8xx_sizes,
        .size_type              = U8_APER_SIZE,
        .num_aperture_sizes     = 7,
        .needs_scratch_page     = true,
        .configure              = intel_7505_configure,
        .fetch_size             = intel_8xx_fetch_size,
        .cleanup                = intel_8xx_cleanup,
        .tlb_flush              = intel_8xx_tlbflush,
        .mask_memory            = agp_generic_mask_memory,
        .masks                  = intel_generic_masks,
        .agp_enable             = agp_generic_enable,
        .cache_flush            = global_cache_flush,
        .create_gatt_table      = agp_generic_create_gatt_table,
        .free_gatt_table        = agp_generic_free_gatt_table,
        .insert_memory          = agp_generic_insert_memory,
        .remove_memory          = agp_generic_remove_memory,
        .alloc_by_type          = agp_generic_alloc_by_type,
        .free_by_type           = agp_generic_free_by_type,
        .agp_alloc_page         = agp_generic_alloc_page,
        .agp_alloc_pages        = agp_generic_alloc_pages,
        .agp_destroy_page       = agp_generic_destroy_page,
        .agp_destroy_pages      = agp_generic_destroy_pages,
        .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
};

/* Table to describe Intel GMCH and AGP/PCIE GART drivers.  At least one of
 * driver and gmch_driver must be non-null, and find_gmch will determine
 * which one should be used if a gmch_chip_id is present.
 */
static const struct intel_agp_driver_description {
        unsigned int chip_id;
        char *name;
        const struct agp_bridge_driver *driver;
} intel_agp_chipsets[] = {
        { PCI_DEVICE_ID_INTEL_82443LX_0, "440LX", &intel_generic_driver },
        { PCI_DEVICE_ID_INTEL_82443BX_0, "440BX", &intel_generic_driver },
        { PCI_DEVICE_ID_INTEL_82443GX_0, "440GX", &intel_generic_driver },
        { PCI_DEVICE_ID_INTEL_82815_MC, "i815", &intel_815_driver },
        { PCI_DEVICE_ID_INTEL_82820_HB, "i820", &intel_820_driver },
        { PCI_DEVICE_ID_INTEL_82820_UP_HB, "i820", &intel_820_driver },
        { PCI_DEVICE_ID_INTEL_82830_HB, "830M", &intel_830mp_driver },
        { PCI_DEVICE_ID_INTEL_82840_HB, "i840", &intel_840_driver },
        { PCI_DEVICE_ID_INTEL_82845_HB, "i845", &intel_845_driver },
        { PCI_DEVICE_ID_INTEL_82845G_HB, "845G", &intel_845_driver },
        { PCI_DEVICE_ID_INTEL_82850_HB, "i850", &intel_850_driver },
        { PCI_DEVICE_ID_INTEL_82854_HB, "854", &intel_845_driver },
        { PCI_DEVICE_ID_INTEL_82855PM_HB, "855PM", &intel_845_driver },
        { PCI_DEVICE_ID_INTEL_82855GM_HB, "855GM", &intel_845_driver },
        { PCI_DEVICE_ID_INTEL_82860_HB, "i860", &intel_860_driver },
        { PCI_DEVICE_ID_INTEL_82865_HB, "865", &intel_845_driver },
        { PCI_DEVICE_ID_INTEL_82875_HB, "i875", &intel_845_driver },
        { PCI_DEVICE_ID_INTEL_7505_0, "E7505", &intel_7505_driver },
        { PCI_DEVICE_ID_INTEL_7205_0, "E7205", &intel_7505_driver },
        { 0, NULL, NULL }
};

static int agp_intel_probe(struct pci_dev *pdev,
                           const struct pci_device_id *ent)
{
        struct agp_bridge_data *bridge;
        u8 cap_ptr = 0;
        struct resource *r;
        int i, err;

        cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);

        bridge = agp_alloc_bridge();
        if (!bridge)
                return -ENOMEM;

        bridge->capndx = cap_ptr;

        if (intel_gmch_probe(pdev, NULL, bridge))
                goto found_gmch;

        for (i = 0; intel_agp_chipsets[i].name != NULL; i++) {
                /* In case that multiple models of gfx chip may
                   stand on same host bridge type, this can be
                   sure we detect the right IGD. */
                if (pdev->device == intel_agp_chipsets[i].chip_id) {
                        bridge->driver = intel_agp_chipsets[i].driver;
                        break;
                }
        }

        if (!bridge->driver) {
                if (cap_ptr)
                        dev_warn(&pdev->dev, "unsupported Intel chipset [%04x/%04x]\n",
                                 pdev->vendor, pdev->device);
                agp_put_bridge(bridge);
                return -ENODEV;
        }

        bridge->dev = pdev;
        bridge->dev_private_data = NULL;

        dev_info(&pdev->dev, "Intel %s Chipset\n", intel_agp_chipsets[i].name);

        /*
        * The following fixes the case where the BIOS has "forgotten" to
        * provide an address range for the GART.
        * 20030610 - hamish@zot.org
        * This happens before pci_enable_device() intentionally;
        * calling pci_enable_device() before assigning the resource
        * will result in the GART being disabled on machines with such
        * BIOSs (the GART ends up with a BAR starting at 0, which
        * conflicts a lot of other devices).
        */
        r = &pdev->resource[0];
        if (!r->start && r->end) {
                if (pci_assign_resource(pdev, 0)) {
                        dev_err(&pdev->dev, "can't assign resource 0\n");
                        agp_put_bridge(bridge);
                        return -ENODEV;
                }
        }

        /*
        * If the device has not been properly setup, the following will catch
        * the problem and should stop the system from crashing.
        * 20030610 - hamish@zot.org
        */
        if (pci_enable_device(pdev)) {
                dev_err(&pdev->dev, "can't enable PCI device\n");
                agp_put_bridge(bridge);
                return -ENODEV;
        }

        /* Fill in the mode register */
        if (cap_ptr) {
                pci_read_config_dword(pdev,
                                bridge->capndx+PCI_AGP_STATUS,
                                &bridge->mode);
        }

found_gmch:
        pci_set_drvdata(pdev, bridge);
        err = agp_add_bridge(bridge);
        return err;
}

static void agp_intel_remove(struct pci_dev *pdev)
{
        struct agp_bridge_data *bridge = pci_get_drvdata(pdev);

        agp_remove_bridge(bridge);

        intel_gmch_remove();

        agp_put_bridge(bridge);
}

static int agp_intel_resume(struct device *dev)
{
        struct pci_dev *pdev = to_pci_dev(dev);
        struct agp_bridge_data *bridge = pci_get_drvdata(pdev);

        bridge->driver->configure();

        return 0;
}

static const struct pci_device_id agp_intel_pci_table[] = {
#define ID(x)                                           \
        {                                               \
        .class          = (PCI_CLASS_BRIDGE_HOST << 8), \
        .class_mask     = ~0,                           \
        .vendor         = PCI_VENDOR_ID_INTEL,          \
        .device         = x,                            \
        .subvendor      = PCI_ANY_ID,                   \
        .subdevice      = PCI_ANY_ID,                   \
        }
        ID(PCI_DEVICE_ID_INTEL_82441), /* for HAS2 support */
        ID(PCI_DEVICE_ID_INTEL_82443LX_0),
        ID(PCI_DEVICE_ID_INTEL_82443BX_0),
        ID(PCI_DEVICE_ID_INTEL_82443GX_0),
        ID(PCI_DEVICE_ID_INTEL_82810_MC1),
        ID(PCI_DEVICE_ID_INTEL_82810_MC3),
        ID(PCI_DEVICE_ID_INTEL_82810E_MC),
        ID(PCI_DEVICE_ID_INTEL_82815_MC),
        ID(PCI_DEVICE_ID_INTEL_82820_HB),
        ID(PCI_DEVICE_ID_INTEL_82820_UP_HB),
        ID(PCI_DEVICE_ID_INTEL_82830_HB),
        ID(PCI_DEVICE_ID_INTEL_82840_HB),
        ID(PCI_DEVICE_ID_INTEL_82845_HB),
        ID(PCI_DEVICE_ID_INTEL_82845G_HB),
        ID(PCI_DEVICE_ID_INTEL_82850_HB),
        ID(PCI_DEVICE_ID_INTEL_82854_HB),
        ID(PCI_DEVICE_ID_INTEL_82855PM_HB),
        ID(PCI_DEVICE_ID_INTEL_82855GM_HB),
        ID(PCI_DEVICE_ID_INTEL_82860_HB),
        ID(PCI_DEVICE_ID_INTEL_82865_HB),
        ID(PCI_DEVICE_ID_INTEL_82875_HB),
        ID(PCI_DEVICE_ID_INTEL_7505_0),
        ID(PCI_DEVICE_ID_INTEL_7205_0),
        ID(PCI_DEVICE_ID_INTEL_E7221_HB),
        ID(PCI_DEVICE_ID_INTEL_82915G_HB),
        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_82945GME_HB),
        ID(PCI_DEVICE_ID_INTEL_PINEVIEW_M_HB),
        ID(PCI_DEVICE_ID_INTEL_PINEVIEW_HB),
        ID(PCI_DEVICE_ID_INTEL_82946GZ_HB),
        ID(PCI_DEVICE_ID_INTEL_82G35_HB),
        ID(PCI_DEVICE_ID_INTEL_82965Q_HB),
        ID(PCI_DEVICE_ID_INTEL_82965G_HB),
        ID(PCI_DEVICE_ID_INTEL_82965GM_HB),
        ID(PCI_DEVICE_ID_INTEL_82965GME_HB),
        ID(PCI_DEVICE_ID_INTEL_G33_HB),
        ID(PCI_DEVICE_ID_INTEL_Q35_HB),
        ID(PCI_DEVICE_ID_INTEL_Q33_HB),
        ID(PCI_DEVICE_ID_INTEL_GM45_HB),
        ID(PCI_DEVICE_ID_INTEL_EAGLELAKE_HB),
        ID(PCI_DEVICE_ID_INTEL_Q45_HB),
        ID(PCI_DEVICE_ID_INTEL_G45_HB),
        ID(PCI_DEVICE_ID_INTEL_G41_HB),
        ID(PCI_DEVICE_ID_INTEL_B43_HB),
        ID(PCI_DEVICE_ID_INTEL_B43_1_HB),
        ID(PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB),
        ID(PCI_DEVICE_ID_INTEL_IRONLAKE_D2_HB),
        ID(PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB),
        ID(PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB),
        ID(PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB),
        { }
};

MODULE_DEVICE_TABLE(pci, agp_intel_pci_table);

static DEFINE_SIMPLE_DEV_PM_OPS(agp_intel_pm_ops, NULL, agp_intel_resume);

static struct pci_driver agp_intel_pci_driver = {
        .name           = "agpgart-intel",
        .id_table       = agp_intel_pci_table,
        .probe          = agp_intel_probe,
        .remove         = agp_intel_remove,
        .driver.pm      = &agp_intel_pm_ops,
};

static int __init agp_intel_init(void)
{
        if (agp_off)
                return -EINVAL;
        return pci_register_driver(&agp_intel_pci_driver);
}

static void __exit agp_intel_cleanup(void)
{
        pci_unregister_driver(&agp_intel_pci_driver);
}

module_init(agp_intel_init);
module_exit(agp_intel_cleanup);

MODULE_AUTHOR("Dave Jones, Various @Intel");
MODULE_DESCRIPTION("Intel AGPGART routines");
MODULE_LICENSE("GPL and additional rights");