diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/common.h | 1 | ||||
-rw-r--r-- | src/i810_reg.h | 21 | ||||
-rw-r--r-- | src/i830.h | 1 | ||||
-rw-r--r-- | src/i830_driver.c | 68 | ||||
-rw-r--r-- | src/i830_memory.c | 111 |
5 files changed, 158 insertions, 44 deletions
diff --git a/src/common.h b/src/common.h index f299e5dc..f45fc8e5 100644 --- a/src/common.h +++ b/src/common.h @@ -233,6 +233,7 @@ union intfloat { #define INREG8(addr) *(volatile CARD8 *)(RecPtr->MMIOBase + (addr)) #define INREG16(addr) *(volatile CARD16 *)(RecPtr->MMIOBase + (addr)) #define INREG(addr) *(volatile CARD32 *)(RecPtr->MMIOBase + (addr)) +#define INGTT(addr) *(volatile CARD32 *)(RecPtr->GTTBase + (addr)) #define POSTING_READ(addr) (void)INREG(addr) #define OUTREG8(addr, val) do { \ diff --git a/src/i810_reg.h b/src/i810_reg.h index bc944fe5..491c3894 100644 --- a/src/i810_reg.h +++ b/src/i810_reg.h @@ -526,6 +526,15 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define PGETBL_SIZE_256KB (1 << 1) #define PGETBL_SIZE_128KB (2 << 1) +#define I830_PTE_BASE 0x10000 +#define PTE_ADDRESS_MASK 0xfffff000 +#define PTE_ADDRESS_MASK_HIGH 0x000000f0 /* i915+ */ +#define PTE_MAPPING_TYPE_UNCACHED (0 << 1) +#define PTE_MAPPING_TYPE_DCACHE (1 << 1) /* i830 only */ +#define PTE_MAPPING_TYPE_CACHED (3 << 1) +#define PTE_MAPPING_TYPE_MASK (3 << 1) +#define PTE_VALID (1 << 0) + /** @defgroup PGE_ERR * @{ */ @@ -577,18 +586,6 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # define PGTBL_ERR_HOST_GTT_PTE (1 << 0) /** @} */ -/* Page table entries loaded via mmio region, p323 - */ -#define PTE_BASE 0x10000 -#define PTE_ADDR_MASK 0x3FFFF000 -#define PTE_TYPE_MASK 0x00000006 -#define PTE_LOCAL 0x00000002 -#define PTE_MAIN_UNCACHED 0x00000000 -#define PTE_MAIN_CACHED 0x00000006 -#define PTE_VALID_MASK 0x00000001 -#define PTE_VALID 0x00000001 - - /* Ring buffer registers, p277, overview p19 */ #define LP_RING 0x2030 @@ -261,6 +261,7 @@ enum last_3d { typedef struct _I830Rec { unsigned char *MMIOBase; + unsigned char *GTTBase; unsigned char *FbBase; int cpp; diff --git a/src/i830_driver.c b/src/i830_driver.c index 235ee2af..e38b77b5 100644 --- a/src/i830_driver.c +++ b/src/i830_driver.c @@ -521,6 +521,32 @@ I830MapMMIO(ScrnInfoPtr pScrn) pI830->MMIOAddr, I810_REG_SIZE); if (!pI830->MMIOBase) return FALSE; + + /* Set up the GTT mapping for the various places it has been moved over + * time. + */ + if (IS_I9XX(pI830)) { + if (IS_I965G(pI830)) { + pI830->GTTBase = xf86MapPciMem(pScrn->scrnIndex, mmioFlags, + pI830->PciTag, + pI830->MMIOAddr + (512 * 1024), + 512 * 1024); + if (pI830->GTTBase == NULL) + return FALSE; + } else { + CARD32 gttaddr = pI830->PciInfo->memBase[3] & 0xFFFFFF00; + + pI830->GTTBase = xf86MapPciMem(pScrn->scrnIndex, mmioFlags, + pI830->PciTag, + gttaddr, + pI830->FbMapSize / 1024); + if (pI830->GTTBase == NULL) + return FALSE; + } + } else { + pI830->GTTBase = pI830->MMIOBase + I830_PTE_BASE; + } + return TRUE; } @@ -1136,6 +1162,27 @@ I830PreInit(ScrnInfoPtr pScrn, int flags) } xf86CrtcSetSizeRange (pScrn, 320, 200, max_width, max_height); + if (IS_I830(pI830) || IS_845G(pI830)) { + PCITAG bridge; + CARD16 gmch_ctrl; + + bridge = pciTag(0, 0, 0); /* This is always the host bridge */ + gmch_ctrl = pciReadWord(bridge, I830_GMCH_CTRL); + if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_128M) { + pI830->FbMapSize = 0x8000000; + } else { + pI830->FbMapSize = 0x4000000; /* 64MB - has this been tested ?? */ + } + } else { + if (IS_I9XX(pI830)) { + pI830->FbMapSize = 1UL << pciGetBaseSize(pI830->PciTag, 2, TRUE, + NULL); + } else { + /* 128MB aperture for later i8xx series. */ + pI830->FbMapSize = 0x8000000; + } + } + /* Some of the probing needs MMIO access, so map it here. */ I830MapMMIO(pScrn); @@ -1159,27 +1206,6 @@ I830PreInit(ScrnInfoPtr pScrn, int flags) (1 << 23) | (2 << 16)); #endif - if (IS_I830(pI830) || IS_845G(pI830)) { - PCITAG bridge; - CARD16 gmch_ctrl; - - bridge = pciTag(0, 0, 0); /* This is always the host bridge */ - gmch_ctrl = pciReadWord(bridge, I830_GMCH_CTRL); - if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_128M) { - pI830->FbMapSize = 0x8000000; - } else { - pI830->FbMapSize = 0x4000000; /* 64MB - has this been tested ?? */ - } - } else { - if (IS_I9XX(pI830)) { - pI830->FbMapSize = 1UL << pciGetBaseSize(pI830->PciTag, 2, TRUE, - NULL); - } else { - /* 128MB aperture for later i8xx series. */ - pI830->FbMapSize = 0x8000000; - } - } - if (pI830->PciInfo->chipType == PCI_CHIP_E7221_G) num_pipe = 1; else diff --git a/src/i830_memory.c b/src/i830_memory.c index 268d6c52..2cc93272 100644 --- a/src/i830_memory.c +++ b/src/i830_memory.c @@ -309,6 +309,86 @@ i830_allocator_init(ScrnInfoPtr pScrn, unsigned long offset, return TRUE; } +/** + * Reads a GTT entry for the memory at the given offset and returns the + * physical address. + * + * \return physical address if successful. + * \return (unsigned long)-1 if unsuccessful. + */ +static unsigned long +i830_get_gtt_physical(ScrnInfoPtr pScrn, unsigned long offset) +{ + I830Ptr pI830 = I830PTR(pScrn); + CARD32 gttentry = INGTT(offset / 1024); + + /* Mask out these reserved bits on this hardware. */ + if (!IS_I965G(pI830)) + gttentry &= ~PTE_ADDRESS_MASK_HIGH; + + /* If it's not a mapping type we know, then bail. */ + if ((gttentry & PTE_MAPPING_TYPE_MASK) != PTE_MAPPING_TYPE_UNCACHED && + (gttentry & PTE_MAPPING_TYPE_MASK) != PTE_MAPPING_TYPE_CACHED) + { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Unusable physical mapping type 0x%08x\n", + (unsigned int)(gttentry & PTE_MAPPING_TYPE_MASK)); + return -1; + } + /* If we can't represent the address with an unsigned long, bail. */ + if (sizeof(unsigned long) == 4 && + (gttentry & PTE_ADDRESS_MASK_HIGH) != 0) + { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "High memory PTE (0x%08x) on 32-bit system\n", + (unsigned int)gttentry); + return -1; + } + assert((gttentry & PTE_VALID) != 0); + + return (gttentry & PTE_ADDRESS_MASK) | + (gttentry & PTE_ADDRESS_MASK_HIGH << (32 - 4)); +} + +/** + * Reads the GTT entries for stolen memory at the given offset, returning the + * physical address. + * + * \return physical address if successful. + * \return (unsigned long)-1 if unsuccessful. + */ +static unsigned long +i830_get_stolen_physical(ScrnInfoPtr pScrn, unsigned long offset, + unsigned long size) +{ + I830Ptr pI830 = I830PTR(pScrn); + unsigned long physical, scan; + + /* Check that the requested region is within stolen memory. */ + if (offset + size >= pI830->stolen_size) + return -1; + + physical = i830_get_gtt_physical(pScrn, offset); + if (physical == -1) + return -1; + + /* Check that the following pages in our allocation follow the first page + * contiguously. + */ + for (scan = offset + 4096; scan < offset + size; scan += 4096) { + unsigned long scan_physical = i830_get_gtt_physical(pScrn, scan); + + if ((scan - offset) != (scan_physical - physical)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Non-contiguous GTT entries: (%ld,%ld) vs (%ld,%ld)\n", + scan, scan_physical, offset, physical); + return -1; + } + } + + return physical; +} + /* Allocate aperture space for the given size and alignment, and returns the * memory allocation. * @@ -341,13 +421,25 @@ i830_allocate_aperture(ScrnInfoPtr pScrn, const char *name, alignment = GTT_PAGE_SIZE; for (scan = pI830->memory_list; scan->next != NULL; scan = scan->next) { - mem->offset = scan->end; - /* For allocations requiring physical addresses, we have to use AGP - * memory, so move the allocation up out of stolen memory. - */ - if ((flags & NEED_PHYSICAL_ADDR) && mem->offset < pI830->stolen_size) - mem->offset = pI830->stolen_size; - mem->offset = ROUND_TO(mem->offset, alignment); + mem->offset = ROUND_TO(scan->end, alignment); + if ((flags & NEED_PHYSICAL_ADDR) && mem->offset < pI830->stolen_size) { + /* If the allocation is entirely within stolen memory, and we're + * able to get the physical addresses out of the GTT and check that + * it's contiguous (it ought to be), then we can do our physical + * allocations there and not bother the kernel about it. This + * helps avoid aperture fragmentation from our physical + * allocations. + */ + mem->bus_addr = i830_get_stolen_physical(pScrn, mem->offset, + mem->size); + + if (mem->bus_addr == ((unsigned long)-1)) { + /* Move the start of the allocation to just past the end of + * stolen memory. + */ + mem->offset = ROUND_TO(pI830->stolen_size, alignment); + } + } mem->end = mem->offset + size; if (flags & ALIGN_BOTH_ENDS) @@ -385,11 +477,8 @@ i830_allocate_agp_memory(ScrnInfoPtr pScrn, i830_memory *mem, int flags) if (mem->key != -1) return TRUE; - if (mem->offset + mem->size <= pI830->stolen_size && - !(flags & NEED_PHYSICAL_ADDR)) - { + if (mem->offset + mem->size <= pI830->stolen_size) return TRUE; - } if (mem->offset < pI830->stolen_size) mem->agp_offset = pI830->stolen_size; |