120,6 → 120,164 |
#define IS_IRONLAKE intel_private.driver->is_ironlake |
#define HAS_PGTBL_EN intel_private.driver->has_pgtbl_enable |
|
#if IS_ENABLED(CONFIG_AGP_INTEL) |
static int intel_gtt_map_memory(struct page **pages, |
unsigned int num_entries, |
struct sg_table *st) |
{ |
struct scatterlist *sg; |
int i; |
|
DBG("try mapping %lu pages\n", (unsigned long)num_entries); |
|
if (sg_alloc_table(st, num_entries, GFP_KERNEL)) |
goto err; |
|
for_each_sg(st->sgl, sg, num_entries, i) |
sg_set_page(sg, pages[i], PAGE_SIZE, 0); |
|
if (!pci_map_sg(intel_private.pcidev, |
st->sgl, st->nents, PCI_DMA_BIDIRECTIONAL)) |
goto err; |
|
return 0; |
|
err: |
sg_free_table(st); |
return -ENOMEM; |
} |
|
static void intel_gtt_unmap_memory(struct scatterlist *sg_list, int num_sg) |
{ |
struct sg_table st; |
DBG("try unmapping %lu pages\n", (unsigned long)mem->page_count); |
|
pci_unmap_sg(intel_private.pcidev, sg_list, |
num_sg, PCI_DMA_BIDIRECTIONAL); |
|
st.sgl = sg_list; |
st.orig_nents = st.nents = num_sg; |
|
sg_free_table(&st); |
} |
|
static void intel_fake_agp_enable(struct agp_bridge_data *bridge, u32 mode) |
{ |
return; |
} |
|
/* Exists to support ARGB cursors */ |
static struct page *i8xx_alloc_pages(void) |
{ |
struct page *page; |
|
page = alloc_pages(GFP_KERNEL | GFP_DMA32, 2); |
if (page == NULL) |
return NULL; |
|
if (set_pages_uc(page, 4) < 0) { |
set_pages_wb(page, 4); |
__free_pages(page, 2); |
return NULL; |
} |
atomic_inc(&agp_bridge->current_memory_agp); |
return page; |
} |
|
static void i8xx_destroy_pages(struct page *page) |
{ |
if (page == NULL) |
return; |
|
set_pages_wb(page, 4); |
__free_pages(page, 2); |
atomic_dec(&agp_bridge->current_memory_agp); |
} |
#endif |
|
#if IS_ENABLED(CONFIG_AGP_INTEL) |
static int i810_insert_dcache_entries(struct agp_memory *mem, off_t pg_start, |
int type) |
{ |
int i; |
|
if ((pg_start + mem->page_count) |
> intel_private.num_dcache_entries) |
return -EINVAL; |
|
if (!mem->is_flushed) |
global_cache_flush(); |
|
for (i = pg_start; i < (pg_start + mem->page_count); i++) { |
dma_addr_t addr = i << PAGE_SHIFT; |
intel_private.driver->write_entry(addr, |
i, type); |
} |
wmb(); |
|
return 0; |
} |
|
/* |
* The i810/i830 requires a physical address to program its mouse |
* pointer into hardware. |
* However the Xserver still writes to it through the agp aperture. |
*/ |
static struct agp_memory *alloc_agpphysmem_i8xx(size_t pg_count, int type) |
{ |
struct agp_memory *new; |
struct page *page; |
|
switch (pg_count) { |
case 1: page = agp_bridge->driver->agp_alloc_page(agp_bridge); |
break; |
case 4: |
/* kludge to get 4 physical pages for ARGB cursor */ |
page = i8xx_alloc_pages(); |
break; |
default: |
return NULL; |
} |
|
if (page == NULL) |
return NULL; |
|
new = agp_create_memory(pg_count); |
if (new == NULL) |
return NULL; |
|
new->pages[0] = page; |
if (pg_count == 4) { |
/* kludge to get 4 physical pages for ARGB cursor */ |
new->pages[1] = new->pages[0] + 1; |
new->pages[2] = new->pages[1] + 1; |
new->pages[3] = new->pages[2] + 1; |
} |
new->page_count = pg_count; |
new->num_scratch_pages = pg_count; |
new->type = AGP_PHYS_MEMORY; |
new->physical = page_to_phys(new->pages[0]); |
return new; |
} |
|
static void intel_i810_free_by_type(struct agp_memory *curr) |
{ |
agp_free_key(curr->key); |
if (curr->type == AGP_PHYS_MEMORY) { |
if (curr->page_count == 4) |
i8xx_destroy_pages(curr->pages[0]); |
else { |
agp_bridge->driver->agp_destroy_page(curr->pages[0], |
AGP_PAGE_DESTROY_UNMAP); |
agp_bridge->driver->agp_destroy_page(curr->pages[0], |
AGP_PAGE_DESTROY_FREE); |
} |
agp_free_page_array(curr); |
} |
kfree(curr); |
} |
#endif |
|
static int intel_gtt_setup_scratch_page(void) |
{ |
struct page *page; |
373,7 → 531,7 |
/* Query intel_iommu to see if we need the workaround. Presumably that |
* was loaded first. |
*/ |
if ((gpu_devid == PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB || |
if ((gpu_devid == PCI_DEVICE_ID_INTEL_IRONLAKE_D_IG || |
gpu_devid == PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG) && |
intel_iommu_gfx_mapped) |
return 1; |
456,7 → 614,27 |
return 0; |
} |
|
#if IS_ENABLED(CONFIG_AGP_INTEL) |
static int intel_fake_agp_fetch_size(void) |
{ |
int num_sizes = ARRAY_SIZE(intel_fake_agp_sizes); |
unsigned int aper_size; |
int i; |
|
aper_size = (intel_private.gtt_mappable_entries << PAGE_SHIFT) / MB(1); |
|
for (i = 0; i < num_sizes; i++) { |
if (aper_size == intel_fake_agp_sizes[i].size) { |
agp_bridge->current_size = |
(void *) (intel_fake_agp_sizes + i); |
return aper_size; |
} |
} |
|
return 0; |
} |
#endif |
|
static void i830_write_entry(dma_addr_t addr, unsigned int entry, |
unsigned int flags) |
{ |
511,7 → 689,35 |
|
return true; |
} |
EXPORT_SYMBOL(intel_enable_gtt); |
|
#if IS_ENABLED(CONFIG_AGP_INTEL) |
static int intel_fake_agp_create_gatt_table(struct agp_bridge_data *bridge) |
{ |
agp_bridge->gatt_table_real = NULL; |
agp_bridge->gatt_table = NULL; |
agp_bridge->gatt_bus_addr = 0; |
|
return 0; |
} |
|
static int intel_fake_agp_free_gatt_table(struct agp_bridge_data *bridge) |
{ |
return 0; |
} |
|
static int intel_fake_agp_configure(void) |
{ |
if (!intel_enable_gtt()) |
return -EIO; |
|
intel_private.clear_fake_agp = true; |
agp_bridge->gart_bus_addr = intel_private.gma_bus_addr; |
|
return 0; |
} |
#endif |
|
static bool i830_check_flags(unsigned int flags) |
{ |
switch (flags) { |
545,7 → 751,7 |
j++; |
} |
} |
readl(intel_private.gtt+j-1); |
wmb(); |
} |
EXPORT_SYMBOL(intel_gtt_insert_sg_entries); |
|
562,7 → 768,7 |
intel_private.driver->write_entry(addr, |
j, flags); |
} |
readl(intel_private.gtt+j-1); |
wmb(); |
} |
|
static int intel_fake_agp_insert_entries(struct agp_memory *mem, |
625,8 → 831,53 |
intel_private.driver->write_entry(intel_private.scratch_page_dma, |
i, 0); |
} |
readl(intel_private.gtt+i-1); |
wmb(); |
} |
EXPORT_SYMBOL(intel_gtt_clear_range); |
|
#if IS_ENABLED(CONFIG_AGP_INTEL) |
static int intel_fake_agp_remove_entries(struct agp_memory *mem, |
off_t pg_start, int type) |
{ |
if (mem->page_count == 0) |
return 0; |
|
intel_gtt_clear_range(pg_start, mem->page_count); |
|
if (intel_private.needs_dmar) { |
intel_gtt_unmap_memory(mem->sg_list, mem->num_sg); |
mem->sg_list = NULL; |
mem->num_sg = 0; |
} |
|
return 0; |
} |
|
static struct agp_memory *intel_fake_agp_alloc_by_type(size_t pg_count, |
int type) |
{ |
struct agp_memory *new; |
|
if (type == AGP_DCACHE_MEMORY && INTEL_GTT_GEN == 1) { |
if (pg_count != intel_private.num_dcache_entries) |
return NULL; |
|
new = agp_create_memory(1); |
if (new == NULL) |
return NULL; |
|
new->type = AGP_DCACHE_MEMORY; |
new->page_count = pg_count; |
new->num_scratch_pages = 0; |
agp_free_page_array(new); |
return new; |
} |
if (type == AGP_PHYS_MEMORY) |
return alloc_agpphysmem_i8xx(pg_count, type); |
/* always return NULL for other allocation types for now */ |
return NULL; |
} |
#endif |
static void intel_i915_setup_chipset_flush(void) |
{ |
int ret; |
769,6 → 1020,29 |
return 0; |
} |
|
#if IS_ENABLED(CONFIG_AGP_INTEL) |
static const struct agp_bridge_driver intel_fake_agp_driver = { |
.owner = THIS_MODULE, |
.size_type = FIXED_APER_SIZE, |
.aperture_sizes = intel_fake_agp_sizes, |
.num_aperture_sizes = ARRAY_SIZE(intel_fake_agp_sizes), |
.configure = intel_fake_agp_configure, |
.fetch_size = intel_fake_agp_fetch_size, |
.cleanup = intel_gtt_cleanup, |
.agp_enable = intel_fake_agp_enable, |
.cache_flush = global_cache_flush, |
.create_gatt_table = intel_fake_agp_create_gatt_table, |
.free_gatt_table = intel_fake_agp_free_gatt_table, |
.insert_memory = intel_fake_agp_insert_entries, |
.remove_memory = intel_fake_agp_remove_entries, |
.alloc_by_type = intel_fake_agp_alloc_by_type, |
.free_by_type = intel_i810_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, |
}; |
#endif |
static const struct intel_gtt_driver i915_gtt_driver = { |
.gen = 3, |
.has_pgtbl_enable = 1, |
970,8 → 1244,8 |
} |
EXPORT_SYMBOL(intel_gmch_probe); |
|
void intel_gtt_get(size_t *gtt_total, size_t *stolen_size, |
phys_addr_t *mappable_base, unsigned long *mappable_end) |
void intel_gtt_get(u64 *gtt_total, size_t *stolen_size, |
phys_addr_t *mappable_base, u64 *mappable_end) |
{ |
*gtt_total = intel_private.gtt_total_entries << PAGE_SHIFT; |
*stolen_size = intel_private.stolen_size; |
988,5 → 1262,5 |
EXPORT_SYMBOL(intel_gtt_chipset_flush); |
|
|
MODULE_AUTHOR("Dave Jones <davej@redhat.com>"); |
MODULE_AUTHOR("Dave Jones, Various @Intel"); |
MODULE_LICENSE("GPL and additional rights"); |