summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common.h1
-rw-r--r--src/i810_reg.h21
-rw-r--r--src/i830.h1
-rw-r--r--src/i830_driver.c68
-rw-r--r--src/i830_memory.c111
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
diff --git a/src/i830.h b/src/i830.h
index d81857bd..f69ad737 100644
--- a/src/i830.h
+++ b/src/i830.h
@@ -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;