From f2b04cd219e5c0f1214c0eeeec814ddd08a12c1b Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 8 May 2007 15:19:23 +1000 Subject: drm/radeon: upgrade to 1.27 - make PCI GART more flexible radeon: make PCI GART aperture size variable, but making table size variable This is precursor to getting a TTM backend for this stuff, and also allows the PCI table to be allocated at fb 0 radeon: add support for reverse engineered xpress200m The IGPGART setup code was traced using mmio-trace on fglrx by myself and Phillip Ezolt on dri-devel. This code doesn't let the 3D driver work properly as the card has no vertex shader support. Thanks to Matthew Garrett + Ubuntu for providing me some hardware to do this work on. Signed-off-by: Dave Airlie --- drivers/char/drm/ati_pcigart.c | 84 ++++++++++++++++++++++------------------- drivers/char/drm/drmP.h | 7 +++- drivers/char/drm/drm_pciids.h | 1 + drivers/char/drm/r128_cce.c | 3 +- drivers/char/drm/r128_drv.h | 2 + drivers/char/drm/radeon_cp.c | 71 +++++++++++++++++++++++++++++++--- drivers/char/drm/radeon_drm.h | 1 + drivers/char/drm/radeon_drv.h | 23 ++++++++++- drivers/char/drm/radeon_state.c | 6 +++ 9 files changed, 150 insertions(+), 48 deletions(-) diff --git a/drivers/char/drm/ati_pcigart.c b/drivers/char/drm/ati_pcigart.c index bd7be09ea53..5b91bc04ea4 100644 --- a/drivers/char/drm/ati_pcigart.c +++ b/drivers/char/drm/ati_pcigart.c @@ -33,59 +33,44 @@ #include "drmP.h" -#if PAGE_SIZE == 65536 -# define ATI_PCIGART_TABLE_ORDER 0 -# define ATI_PCIGART_TABLE_PAGES (1 << 0) -#elif PAGE_SIZE == 16384 -# define ATI_PCIGART_TABLE_ORDER 1 -# define ATI_PCIGART_TABLE_PAGES (1 << 1) -#elif PAGE_SIZE == 8192 -# define ATI_PCIGART_TABLE_ORDER 2 -# define ATI_PCIGART_TABLE_PAGES (1 << 2) -#elif PAGE_SIZE == 4096 -# define ATI_PCIGART_TABLE_ORDER 3 -# define ATI_PCIGART_TABLE_PAGES (1 << 3) -#else -# error - PAGE_SIZE not 64K, 16K, 8K or 4K -#endif - -# define ATI_MAX_PCIGART_PAGES 8192 /**< 32 MB aperture, 4K pages */ # define ATI_PCIGART_PAGE_SIZE 4096 /**< PCI GART page size */ -static void *drm_ati_alloc_pcigart_table(void) +static void *drm_ati_alloc_pcigart_table(int order) { unsigned long address; struct page *page; int i; - DRM_DEBUG("%s\n", __FUNCTION__); + + DRM_DEBUG("%s: alloc %d order\n", __FUNCTION__, order); address = __get_free_pages(GFP_KERNEL | __GFP_COMP, - ATI_PCIGART_TABLE_ORDER); + order); if (address == 0UL) { return NULL; } page = virt_to_page(address); - for (i = 0; i < ATI_PCIGART_TABLE_PAGES; i++, page++) + for (i = 0; i < order; i++, page++) SetPageReserved(page); DRM_DEBUG("%s: returning 0x%08lx\n", __FUNCTION__, address); return (void *)address; } -static void drm_ati_free_pcigart_table(void *address) +static void drm_ati_free_pcigart_table(void *address, int order) { struct page *page; int i; + int num_pages = 1 << order; DRM_DEBUG("%s\n", __FUNCTION__); page = virt_to_page((unsigned long)address); - for (i = 0; i < ATI_PCIGART_TABLE_PAGES; i++, page++) + for (i = 0; i < num_pages; i++, page++) ClearPageReserved(page); - free_pages((unsigned long)address, ATI_PCIGART_TABLE_ORDER); + free_pages((unsigned long)address, order); } int drm_ati_pcigart_cleanup(drm_device_t *dev, drm_ati_pcigart_info *gart_info) @@ -93,6 +78,8 @@ int drm_ati_pcigart_cleanup(drm_device_t *dev, drm_ati_pcigart_info *gart_info) drm_sg_mem_t *entry = dev->sg; unsigned long pages; int i; + int order; + int num_pages, max_pages; /* we need to support large memory configurations */ if (!entry) { @@ -100,15 +87,19 @@ int drm_ati_pcigart_cleanup(drm_device_t *dev, drm_ati_pcigart_info *gart_info) return 0; } + order = drm_order((gart_info->table_size + (PAGE_SIZE-1)) / PAGE_SIZE); + num_pages = 1 << order; + if (gart_info->bus_addr) { if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) { pci_unmap_single(dev->pdev, gart_info->bus_addr, - ATI_PCIGART_TABLE_PAGES * PAGE_SIZE, + num_pages * PAGE_SIZE, PCI_DMA_TODEVICE); } - pages = (entry->pages <= ATI_MAX_PCIGART_PAGES) - ? entry->pages : ATI_MAX_PCIGART_PAGES; + max_pages = (gart_info->table_size / sizeof(u32)); + pages = (entry->pages <= max_pages) + ? entry->pages : max_pages; for (i = 0; i < pages; i++) { if (!entry->busaddr[i]) @@ -123,13 +114,12 @@ int drm_ati_pcigart_cleanup(drm_device_t *dev, drm_ati_pcigart_info *gart_info) if (gart_info->gart_table_location == DRM_ATI_GART_MAIN && gart_info->addr) { - drm_ati_free_pcigart_table(gart_info->addr); + drm_ati_free_pcigart_table(gart_info->addr, order); gart_info->addr = NULL; } return 1; } - EXPORT_SYMBOL(drm_ati_pcigart_cleanup); int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info) @@ -139,6 +129,9 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info) unsigned long pages; u32 *pci_gart, page_base, bus_address = 0; int i, j, ret = 0; + int order; + int max_pages; + int num_pages; if (!entry) { DRM_ERROR("no scatter/gather memory!\n"); @@ -148,7 +141,10 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info) if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) { DRM_DEBUG("PCI: no table in VRAM: using normal RAM\n"); - address = drm_ati_alloc_pcigart_table(); + order = drm_order((gart_info->table_size + + (PAGE_SIZE-1)) / PAGE_SIZE); + num_pages = 1 << order; + address = drm_ati_alloc_pcigart_table(order); if (!address) { DRM_ERROR("cannot allocate PCI GART page!\n"); goto done; @@ -160,11 +156,13 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info) } bus_address = pci_map_single(dev->pdev, address, - ATI_PCIGART_TABLE_PAGES * - PAGE_SIZE, PCI_DMA_TODEVICE); + num_pages * PAGE_SIZE, + PCI_DMA_TODEVICE); if (bus_address == 0) { DRM_ERROR("unable to map PCIGART pages!\n"); - drm_ati_free_pcigart_table(address); + order = drm_order((gart_info->table_size + + (PAGE_SIZE-1)) / PAGE_SIZE); + drm_ati_free_pcigart_table(address, order); address = NULL; goto done; } @@ -177,10 +175,11 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info) pci_gart = (u32 *) address; - pages = (entry->pages <= ATI_MAX_PCIGART_PAGES) - ? entry->pages : ATI_MAX_PCIGART_PAGES; + max_pages = (gart_info->table_size / sizeof(u32)); + pages = (entry->pages <= max_pages) + ? entry->pages : max_pages; - memset(pci_gart, 0, ATI_MAX_PCIGART_PAGES * sizeof(u32)); + memset(pci_gart, 0, max_pages * sizeof(u32)); for (i = 0; i < pages; i++) { /* we need to support large memory configurations */ @@ -198,10 +197,18 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info) page_base = (u32) entry->busaddr[i]; for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); j++) { - if (gart_info->is_pcie) + switch(gart_info->gart_reg_if) { + case DRM_ATI_GART_IGP: + *pci_gart = cpu_to_le32((page_base) | 0xc); + break; + case DRM_ATI_GART_PCIE: *pci_gart = cpu_to_le32((page_base >> 8) | 0xc); - else + break; + default: + case DRM_ATI_GART_PCI: *pci_gart = cpu_to_le32(page_base); + break; + } pci_gart++; page_base += ATI_PCIGART_PAGE_SIZE; } @@ -220,5 +227,4 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info) gart_info->bus_addr = bus_address; return ret; } - EXPORT_SYMBOL(drm_ati_pcigart_init); diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h index 80041d5b792..d494315752a 100644 --- a/drivers/char/drm/drmP.h +++ b/drivers/char/drm/drmP.h @@ -519,12 +519,17 @@ typedef struct drm_vbl_sig { #define DRM_ATI_GART_MAIN 1 #define DRM_ATI_GART_FB 2 +#define DRM_ATI_GART_PCI 1 +#define DRM_ATI_GART_PCIE 2 +#define DRM_ATI_GART_IGP 3 + typedef struct ati_pcigart_info { int gart_table_location; - int is_pcie; + int gart_reg_if; void *addr; dma_addr_t bus_addr; drm_local_map_t mapping; + int table_size; } drm_ati_pcigart_info; /* diff --git a/drivers/char/drm/drm_pciids.h b/drivers/char/drm/drm_pciids.h index 01cf482d2d0..31cdde83713 100644 --- a/drivers/char/drm/drm_pciids.h +++ b/drivers/char/drm/drm_pciids.h @@ -102,6 +102,7 @@ {0x1002, 0x5653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x5834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP}, \ {0x1002, 0x5835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \ + {0x1002, 0x5955, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \ {0x1002, 0x5960, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ {0x1002, 0x5961, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ {0x1002, 0x5962, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ diff --git a/drivers/char/drm/r128_cce.c b/drivers/char/drm/r128_cce.c index db5a60450e6..1014602c43a 100644 --- a/drivers/char/drm/r128_cce.c +++ b/drivers/char/drm/r128_cce.c @@ -560,9 +560,10 @@ static int r128_do_init_cce(drm_device_t * dev, drm_r128_init_t * init) if (dev_priv->is_pci) { #endif dev_priv->gart_info.gart_table_location = DRM_ATI_GART_MAIN; + dev_priv->gart_info.table_size = R128_PCIGART_TABLE_SIZE; dev_priv->gart_info.addr = NULL; dev_priv->gart_info.bus_addr = 0; - dev_priv->gart_info.is_pcie = 0; + dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCI; if (!drm_ati_pcigart_init(dev, &dev_priv->gart_info)) { DRM_ERROR("failed to init PCI GART!\n"); dev->dev_private = (void *)dev_priv; diff --git a/drivers/char/drm/r128_drv.h b/drivers/char/drm/r128_drv.h index f1efb49de8d..9086835686d 100644 --- a/drivers/char/drm/r128_drv.h +++ b/drivers/char/drm/r128_drv.h @@ -383,6 +383,8 @@ extern long r128_compat_ioctl(struct file *filp, unsigned int cmd, #define R128_PERFORMANCE_BOXES 0 +#define R128_PCIGART_TABLE_SIZE 32768 + #define R128_READ(reg) DRM_READ32( dev_priv->mmio, (reg) ) #define R128_WRITE(reg,val) DRM_WRITE32( dev_priv->mmio, (reg), (val) ) #define R128_READ8(reg) DRM_READ8( dev_priv->mmio, (reg) ) diff --git a/drivers/char/drm/radeon_cp.c b/drivers/char/drm/radeon_cp.c index c1850ecac30..68338389d83 100644 --- a/drivers/char/drm/radeon_cp.c +++ b/drivers/char/drm/radeon_cp.c @@ -830,6 +830,15 @@ static int RADEON_READ_PCIE(drm_radeon_private_t *dev_priv, int addr) return RADEON_READ(RADEON_PCIE_DATA); } +static u32 RADEON_READ_IGPGART(drm_radeon_private_t *dev_priv, int addr) +{ + u32 ret; + RADEON_WRITE(RADEON_IGPGART_INDEX, addr & 0x7f); + ret = RADEON_READ(RADEON_IGPGART_DATA); + RADEON_WRITE(RADEON_IGPGART_INDEX, 0x7f); + return ret; +} + #if RADEON_FIFO_DEBUG static void radeon_status(drm_radeon_private_t * dev_priv) { @@ -1267,7 +1276,44 @@ static void radeon_test_writeback(drm_radeon_private_t * dev_priv) } } -/* Enable or disable PCI-E GART on the chip */ +/* Enable or disable IGP GART on the chip */ +static void radeon_set_igpgart(drm_radeon_private_t * dev_priv, int on) +{ + u32 temp, tmp; + + tmp = RADEON_READ(RADEON_AIC_CNTL); + if (on) { + DRM_DEBUG("programming igpgart %08X %08lX %08X\n", + dev_priv->gart_vm_start, + (long)dev_priv->gart_info.bus_addr, + dev_priv->gart_size); + + RADEON_WRITE_IGPGART(RADEON_IGPGART_UNK_18, 0x1000); + RADEON_WRITE_IGPGART(RADEON_IGPGART_ENABLE, 0x1); + RADEON_WRITE_IGPGART(RADEON_IGPGART_CTRL, 0x42040800); + RADEON_WRITE_IGPGART(RADEON_IGPGART_BASE_ADDR, + dev_priv->gart_info.bus_addr); + + temp = RADEON_READ_IGPGART(dev_priv, RADEON_IGPGART_UNK_39); + RADEON_WRITE_IGPGART(RADEON_IGPGART_UNK_39, temp); + + RADEON_WRITE(RADEON_AGP_BASE, (unsigned int)dev_priv->gart_vm_start); + dev_priv->gart_size = 32*1024*1024; + RADEON_WRITE(RADEON_MC_AGP_LOCATION, + (((dev_priv->gart_vm_start - 1 + + dev_priv->gart_size) & 0xffff0000) | + (dev_priv->gart_vm_start >> 16))); + + temp = RADEON_READ_IGPGART(dev_priv, RADEON_IGPGART_ENABLE); + RADEON_WRITE_IGPGART(RADEON_IGPGART_ENABLE, temp); + + RADEON_READ_IGPGART(dev_priv, RADEON_IGPGART_FLUSH); + RADEON_WRITE_IGPGART(RADEON_IGPGART_FLUSH, 0x1); + RADEON_READ_IGPGART(dev_priv, RADEON_IGPGART_FLUSH); + RADEON_WRITE_IGPGART(RADEON_IGPGART_FLUSH, 0x0); + } +} + static void radeon_set_pciegart(drm_radeon_private_t * dev_priv, int on) { u32 tmp = RADEON_READ_PCIE(dev_priv, RADEON_PCIE_TX_GART_CNTL); @@ -1302,6 +1348,11 @@ static void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on) { u32 tmp; + if (dev_priv->flags & RADEON_IS_IGPGART) { + radeon_set_igpgart(dev_priv, on); + return; + } + if (dev_priv->flags & RADEON_IS_PCIE) { radeon_set_pciegart(dev_priv, on); return; @@ -1620,20 +1671,22 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init) #endif { /* if we have an offset set from userspace */ - if (dev_priv->pcigart_offset) { + if (dev_priv->pcigart_offset_set) { dev_priv->gart_info.bus_addr = dev_priv->pcigart_offset + dev_priv->fb_location; dev_priv->gart_info.mapping.offset = dev_priv->gart_info.bus_addr; dev_priv->gart_info.mapping.size = - RADEON_PCIGART_TABLE_SIZE; + dev_priv->gart_info.table_size; drm_core_ioremap(&dev_priv->gart_info.mapping, dev); dev_priv->gart_info.addr = dev_priv->gart_info.mapping.handle; - dev_priv->gart_info.is_pcie = - !!(dev_priv->flags & RADEON_IS_PCIE); + if (dev_priv->flags & RADEON_IS_PCIE) + dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCIE; + else + dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCI; dev_priv->gart_info.gart_table_location = DRM_ATI_GART_FB; @@ -1641,6 +1694,10 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init) dev_priv->gart_info.addr, dev_priv->pcigart_offset); } else { + if (dev_priv->flags & RADEON_IS_IGPGART) + dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_IGP; + else + dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCI; dev_priv->gart_info.gart_table_location = DRM_ATI_GART_MAIN; dev_priv->gart_info.addr = NULL; @@ -1714,7 +1771,7 @@ static int radeon_do_cleanup_cp(drm_device_t * dev) if (dev_priv->gart_info.gart_table_location == DRM_ATI_GART_FB) { drm_core_ioremapfree(&dev_priv->gart_info.mapping, dev); - dev_priv->gart_info.addr = NULL; + dev_priv->gart_info.addr = 0; } } /* only clear to the start of flags */ @@ -2222,6 +2279,8 @@ int radeon_driver_firstopen(struct drm_device *dev) drm_local_map_t *map; drm_radeon_private_t *dev_priv = dev->dev_private; + dev_priv->gart_info.table_size = RADEON_PCIGART_TABLE_SIZE; + ret = drm_addmap(dev, drm_get_resource_start(dev, 2), drm_get_resource_len(dev, 2), _DRM_REGISTERS, _DRM_READ_ONLY, &dev_priv->mmio); diff --git a/drivers/char/drm/radeon_drm.h b/drivers/char/drm/radeon_drm.h index 8d6350dd536..66c4b6fed04 100644 --- a/drivers/char/drm/radeon_drm.h +++ b/drivers/char/drm/radeon_drm.h @@ -707,6 +707,7 @@ typedef struct drm_radeon_setparam { #define RADEON_SETPARAM_SWITCH_TILING 2 /* enable/disable color tiling */ #define RADEON_SETPARAM_PCIGART_LOCATION 3 /* PCI Gart Location */ #define RADEON_SETPARAM_NEW_MEMMAP 4 /* Use new memory map */ +#define RADEON_SETPARAM_PCIGART_TABLE_SIZE 5 /* PCI GART Table Size */ /* 1.14: Clients can allocate/free a surface */ diff --git a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h index 8b105f1460a..97c27da2d26 100644 --- a/drivers/char/drm/radeon_drv.h +++ b/drivers/char/drm/radeon_drv.h @@ -95,9 +95,11 @@ * 1.24- Add general-purpose packet for manipulating scratch registers (r300) * 1.25- Add support for r200 vertex programs (R200_EMIT_VAP_PVS_CNTL, * new packet type) + * 1.26- Add support for variable size PCI(E) gart aperture + * 1.27- Add support for IGP GART */ #define DRIVER_MAJOR 1 -#define DRIVER_MINOR 25 +#define DRIVER_MINOR 27 #define DRIVER_PATCHLEVEL 0 /* @@ -143,6 +145,7 @@ enum radeon_chip_flags { RADEON_IS_PCIE = 0x00200000UL, RADEON_NEW_MEMMAP = 0x00400000UL, RADEON_IS_PCI = 0x00800000UL, + RADEON_IS_IGPGART = 0x01000000UL, }; #define GET_RING_HEAD(dev_priv) (dev_priv->writeback_works ? \ @@ -280,6 +283,7 @@ typedef struct drm_radeon_private { struct radeon_virt_surface virt_surfaces[2 * RADEON_MAX_SURFACES]; unsigned long pcigart_offset; + unsigned int pcigart_offset_set; drm_ati_pcigart_info gart_info; u32 scratch_ages[5]; @@ -432,6 +436,15 @@ extern int r300_do_cp_cmdbuf(drm_device_t * dev, DRMFILE filp, #define RADEON_PCIE_TX_GART_END_LO 0x16 #define RADEON_PCIE_TX_GART_END_HI 0x17 +#define RADEON_IGPGART_INDEX 0x168 +#define RADEON_IGPGART_DATA 0x16c +#define RADEON_IGPGART_UNK_18 0x18 +#define RADEON_IGPGART_CTRL 0x2b +#define RADEON_IGPGART_BASE_ADDR 0x2c +#define RADEON_IGPGART_FLUSH 0x2e +#define RADEON_IGPGART_ENABLE 0x38 +#define RADEON_IGPGART_UNK_39 0x39 + #define RADEON_MPP_TB_CONFIG 0x01c0 #define RADEON_MEM_CNTL 0x0140 #define RADEON_MEM_SDRAM_MODE_REG 0x0158 @@ -964,6 +977,14 @@ do { \ RADEON_WRITE( RADEON_CLOCK_CNTL_DATA, (val) ); \ } while (0) +#define RADEON_WRITE_IGPGART( addr, val ) \ +do { \ + RADEON_WRITE( RADEON_IGPGART_INDEX, \ + ((addr) & 0x7f) | (1 << 8)); \ + RADEON_WRITE( RADEON_IGPGART_DATA, (val) ); \ + RADEON_WRITE( RADEON_IGPGART_INDEX, 0x7f ); \ +} while (0) + #define RADEON_WRITE_PCIE( addr, val ) \ do { \ RADEON_WRITE8( RADEON_PCIE_INDEX, \ diff --git a/drivers/char/drm/radeon_state.c b/drivers/char/drm/radeon_state.c index 938eccb78cc..d6041911c47 100644 --- a/drivers/char/drm/radeon_state.c +++ b/drivers/char/drm/radeon_state.c @@ -3145,10 +3145,16 @@ static int radeon_cp_setparam(DRM_IOCTL_ARGS) break; case RADEON_SETPARAM_PCIGART_LOCATION: dev_priv->pcigart_offset = sp.value; + dev_priv->pcigart_offset_set = 1; break; case RADEON_SETPARAM_NEW_MEMMAP: dev_priv->new_memmap = sp.value; break; + case RADEON_SETPARAM_PCIGART_TABLE_SIZE: + dev_priv->gart_info.table_size = sp.value; + if (dev_priv->gart_info.table_size < RADEON_PCIGART_TABLE_SIZE) + dev_priv->gart_info.table_size = RADEON_PCIGART_TABLE_SIZE; + break; default: DRM_DEBUG("Invalid parameter %d\n", sp.param); return DRM_ERR(EINVAL); -- cgit v1.2.3 From 453ff94ca502d0a7441912823f20ed130f685429 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Tue, 8 May 2007 15:21:14 +1000 Subject: radeon: Don't mess up page flipping when a file descriptor is closed. There can still be other contexts that may use page flipping later on, so do just unilaterally 'clean it up', which could lead to the wrong page being displayed, e.g. when running 3D apps with a GLX compositing manager such as compiz using page flipping. Signed-off-by: Dave Airlie --- drivers/char/drm/radeon_drv.h | 1 - drivers/char/drm/radeon_state.c | 46 +++++++++++++++++------------------------ 2 files changed, 19 insertions(+), 28 deletions(-) diff --git a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h index 97c27da2d26..54f49ef4bef 100644 --- a/drivers/char/drm/radeon_drv.h +++ b/drivers/char/drm/radeon_drv.h @@ -243,7 +243,6 @@ typedef struct drm_radeon_private { int do_boxes; int page_flipping; - int current_page; u32 color_fmt; unsigned int front_offset; diff --git a/drivers/char/drm/radeon_state.c b/drivers/char/drm/radeon_state.c index d6041911c47..98c5f1d3a8e 100644 --- a/drivers/char/drm/radeon_state.c +++ b/drivers/char/drm/radeon_state.c @@ -773,7 +773,7 @@ static void radeon_clear_box(drm_radeon_private_t * dev_priv, RADEON_GMC_SRC_DATATYPE_COLOR | RADEON_ROP3_P | RADEON_GMC_CLR_CMP_CNTL_DIS); - if (dev_priv->page_flipping && dev_priv->current_page == 1) { + if (dev_priv->sarea_priv->pfCurrentPage == 1) { OUT_RING(dev_priv->front_pitch_offset); } else { OUT_RING(dev_priv->back_pitch_offset); @@ -861,7 +861,7 @@ static void radeon_cp_dispatch_clear(drm_device_t * dev, dev_priv->stats.clears++; - if (dev_priv->page_flipping && dev_priv->current_page == 1) { + if (dev_priv->sarea_priv->pfCurrentPage == 1) { unsigned int tmp = flags; flags &= ~(RADEON_FRONT | RADEON_BACK); @@ -1382,7 +1382,7 @@ static void radeon_cp_dispatch_swap(drm_device_t * dev) /* Make this work even if front & back are flipped: */ OUT_RING(CP_PACKET0(RADEON_SRC_PITCH_OFFSET, 1)); - if (dev_priv->current_page == 0) { + if (dev_priv->sarea_priv->pfCurrentPage == 0) { OUT_RING(dev_priv->back_pitch_offset); OUT_RING(dev_priv->front_pitch_offset); } else { @@ -1416,12 +1416,12 @@ static void radeon_cp_dispatch_flip(drm_device_t * dev) { drm_radeon_private_t *dev_priv = dev->dev_private; drm_sarea_t *sarea = (drm_sarea_t *) dev_priv->sarea->handle; - int offset = (dev_priv->current_page == 1) + int offset = (dev_priv->sarea_priv->pfCurrentPage == 1) ? dev_priv->front_offset : dev_priv->back_offset; RING_LOCALS; - DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n", + DRM_DEBUG("%s: pfCurrentPage=%d\n", __FUNCTION__, - dev_priv->current_page, dev_priv->sarea_priv->pfCurrentPage); + dev_priv->sarea_priv->pfCurrentPage); /* Do some trivial performance monitoring... */ @@ -1449,8 +1449,8 @@ static void radeon_cp_dispatch_flip(drm_device_t * dev) * performing the swapbuffer ioctl. */ dev_priv->sarea_priv->last_frame++; - dev_priv->sarea_priv->pfCurrentPage = dev_priv->current_page = - 1 - dev_priv->current_page; + dev_priv->sarea_priv->pfCurrentPage = + 1 - dev_priv->sarea_priv->pfCurrentPage; BEGIN_RING(2); @@ -2152,24 +2152,10 @@ static int radeon_do_init_pageflip(drm_device_t * dev) ADVANCE_RING(); dev_priv->page_flipping = 1; - dev_priv->current_page = 0; - dev_priv->sarea_priv->pfCurrentPage = dev_priv->current_page; - return 0; -} - -/* Called whenever a client dies, from drm_release. - * NOTE: Lock isn't necessarily held when this is called! - */ -static int radeon_do_cleanup_pageflip(drm_device_t * dev) -{ - drm_radeon_private_t *dev_priv = dev->dev_private; - DRM_DEBUG("\n"); + if (dev_priv->sarea_priv->pfCurrentPage != 1) + dev_priv->sarea_priv->pfCurrentPage = 0; - if (dev_priv->current_page != 0) - radeon_cp_dispatch_flip(dev); - - dev_priv->page_flipping = 0; return 0; } @@ -3174,9 +3160,7 @@ void radeon_driver_preclose(drm_device_t * dev, DRMFILE filp) { if (dev->dev_private) { drm_radeon_private_t *dev_priv = dev->dev_private; - if (dev_priv->page_flipping) { - radeon_do_cleanup_pageflip(dev); - } + dev_priv->page_flipping = 0; radeon_mem_release(filp, dev_priv->gart_heap); radeon_mem_release(filp, dev_priv->fb_heap); radeon_surfaces_release(filp, dev_priv); @@ -3185,6 +3169,14 @@ void radeon_driver_preclose(drm_device_t * dev, DRMFILE filp) void radeon_driver_lastclose(drm_device_t * dev) { + if (dev->dev_private) { + drm_radeon_private_t *dev_priv = dev->dev_private; + + if (dev_priv->sarea_priv && + dev_priv->sarea_priv->pfCurrentPage != 0) + radeon_cp_dispatch_flip(dev); + } + radeon_do_release(dev); } -- cgit v1.2.3 From 0515b93c0ea89eb2120b0ec1d148359da01ad2e5 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 8 May 2007 15:28:15 +1000 Subject: drm: rename badly named define and cleanup ioctl code spacing Signed-off-by: Dave Airlie --- drivers/char/drm/drm_drv.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/char/drm/drm_drv.c b/drivers/char/drm/drm_drv.c index 26bec30ee86..8e77b7ed0f4 100644 --- a/drivers/char/drm/drm_drv.c +++ b/drivers/char/drm/drm_drv.c @@ -15,8 +15,6 @@ * #define DRIVER_DESC "Matrox G200/G400" * #define DRIVER_DATE "20001127" * - * #define DRIVER_IOCTL_COUNT DRM_ARRAY_SIZE( mga_ioctls ) - * * #define drm_x mga_##x * \endcode */ @@ -120,7 +118,7 @@ static drm_ioctl_desc_t drm_ioctls[] = { [DRM_IOCTL_NR(DRM_IOCTL_UPDATE_DRAW)] = {drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, }; -#define DRIVER_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) +#define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) /** * Take down the DRM device. @@ -496,11 +494,11 @@ int drm_ioctl(struct inode *inode, struct file *filp, (long)old_encode_dev(priv->head->device), priv->authenticated); - if ((nr >= DRIVER_IOCTL_COUNT) && + if ((nr >= DRM_CORE_IOCTL_COUNT) && ((nr < DRM_COMMAND_BASE) || (nr >= DRM_COMMAND_END))) goto err_i1; - if ((nr >= DRM_COMMAND_BASE) && (nr < DRM_COMMAND_END) - && (nr < DRM_COMMAND_BASE + dev->driver->num_ioctls)) + if ((nr >= DRM_COMMAND_BASE) && (nr < DRM_COMMAND_END) && + (nr < DRM_COMMAND_BASE + dev->driver->num_ioctls)) ioctl = &dev->driver->ioctls[nr - DRM_COMMAND_BASE]; else if ((nr >= DRM_COMMAND_END) || (nr < DRM_COMMAND_BASE)) ioctl = &drm_ioctls[nr]; -- cgit v1.2.3 From bc07dc7f07a2f2d4d0aa4ffb9597413ad9137d44 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 8 May 2007 15:32:35 +1000 Subject: drm: remove old taskqueue remnant Signed-off-by: Dave Airlie --- drivers/char/drm/drm_os_linux.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/char/drm/drm_os_linux.h b/drivers/char/drm/drm_os_linux.h index 2908b72daa6..0fe7b449792 100644 --- a/drivers/char/drm/drm_os_linux.h +++ b/drivers/char/drm/drm_os_linux.h @@ -70,9 +70,6 @@ static __inline__ int mtrr_del(int reg, unsigned long base, unsigned long size) #endif -/** Task queue handler arguments */ -#define DRM_TASKQUEUE_ARGS void *arg - /** For data going into the kernel through the ioctl argument */ #define DRM_COPY_FROM_USER_IOCTL(arg1, arg2, arg3) \ if ( copy_from_user(&arg1, arg2, arg3) ) \ -- cgit v1.2.3 From a0a6dd0b221260be1e3da725e6b49797e5fa7429 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 8 May 2007 15:47:41 +1000 Subject: via: Try to improve command-buffer chaining. Bump driver date and patchlevel. Signed-off-by: Dave Airlie --- drivers/char/drm/via_dma.c | 107 ++++++++++++++++++--------------------------- drivers/char/drm/via_drv.h | 5 ++- 2 files changed, 46 insertions(+), 66 deletions(-) diff --git a/drivers/char/drm/via_dma.c b/drivers/char/drm/via_dma.c index c0539c6299c..7635e859b87 100644 --- a/drivers/char/drm/via_dma.c +++ b/drivers/char/drm/via_dma.c @@ -252,7 +252,7 @@ static int via_dma_init(DRM_IOCTL_ARGS) break; case VIA_DMA_INITIALIZED: retcode = (dev_priv->ring.virtual_start != NULL) ? - 0 : DRM_ERR(EFAULT); + 0 : DRM_ERR(EFAULT); break; default: retcode = DRM_ERR(EINVAL); @@ -432,56 +432,32 @@ static int via_hook_segment(drm_via_private_t * dev_priv, { int paused, count; volatile uint32_t *paused_at = dev_priv->last_pause_ptr; + uint32_t reader,ptr; + paused = 0; via_flush_write_combine(); - while (!*(via_get_dma(dev_priv) - 1)) ; *dev_priv->last_pause_ptr = pause_addr_lo; via_flush_write_combine(); - - /* - * The below statement is inserted to really force the flush. - * Not sure it is needed. - */ - - while (!*dev_priv->last_pause_ptr) ; + reader = *(dev_priv->hw_addr_ptr); + ptr = ((volatile char *)paused_at - dev_priv->dma_ptr) + + dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4; dev_priv->last_pause_ptr = via_get_dma(dev_priv) - 1; - while (!*dev_priv->last_pause_ptr) ; - paused = 0; - count = 20; - - while (!(paused = (VIA_READ(0x41c) & 0x80000000)) && count--) ; - if ((count <= 8) && (count >= 0)) { - uint32_t rgtr, ptr; - rgtr = *(dev_priv->hw_addr_ptr); - ptr = ((volatile char *)dev_priv->last_pause_ptr - - dev_priv->dma_ptr) + dev_priv->dma_offset + - (uint32_t) dev_priv->agpAddr + 4 - CMDBUF_ALIGNMENT_SIZE; - if (rgtr <= ptr) { - DRM_ERROR - ("Command regulator\npaused at count %d, address %x, " - "while current pause address is %x.\n" - "Please mail this message to " - "\n", count, - rgtr, ptr); - } + if ((ptr - reader) <= dev_priv->dma_diff ) { + count = 10000000; + while (!(paused = (VIA_READ(0x41c) & 0x80000000)) && count--); } if (paused && !no_pci_fire) { - uint32_t rgtr, ptr; - uint32_t ptr_low; + reader = *(dev_priv->hw_addr_ptr); + if ((ptr - reader) == dev_priv->dma_diff) { - count = 1000000; - while ((VIA_READ(VIA_REG_STATUS) & VIA_CMD_RGTR_BUSY) - && count--) ; + /* + * There is a concern that these writes may stall the PCI bus + * if the GPU is not idle. However, idling the GPU first + * doesn't make a difference. + */ - rgtr = *(dev_priv->hw_addr_ptr); - ptr = ((volatile char *)paused_at - dev_priv->dma_ptr) + - dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4; - - ptr_low = (ptr > 3 * CMDBUF_ALIGNMENT_SIZE) ? - ptr - 3 * CMDBUF_ALIGNMENT_SIZE : 0; - if (rgtr <= ptr && rgtr >= ptr_low) { VIA_WRITE(VIA_REG_TRANSET, (HC_ParaType_PreCR << 16)); VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_hi); VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_lo); @@ -494,6 +470,9 @@ static int via_hook_segment(drm_via_private_t * dev_priv, static int via_wait_idle(drm_via_private_t * dev_priv) { int count = 10000000; + + while (!(VIA_READ(VIA_REG_STATUS) & VIA_VR_QUEUE_BUSY) && count--); + while (count-- && (VIA_READ(VIA_REG_STATUS) & (VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY | VIA_3D_ENG_BUSY))) ; @@ -537,6 +516,9 @@ static void via_cmdbuf_start(drm_via_private_t * dev_priv) uint32_t end_addr, end_addr_lo; uint32_t command; uint32_t agp_base; + uint32_t ptr; + uint32_t reader; + int count; dev_priv->dma_low = 0; @@ -554,7 +536,7 @@ static void via_cmdbuf_start(drm_via_private_t * dev_priv) &pause_addr_hi, &pause_addr_lo, 1) - 1; via_flush_write_combine(); - while (!*dev_priv->last_pause_ptr) ; + while(! *dev_priv->last_pause_ptr); VIA_WRITE(VIA_REG_TRANSET, (HC_ParaType_PreCR << 16)); VIA_WRITE(VIA_REG_TRANSPACE, command); @@ -566,6 +548,24 @@ static void via_cmdbuf_start(drm_via_private_t * dev_priv) DRM_WRITEMEMORYBARRIER(); VIA_WRITE(VIA_REG_TRANSPACE, command | HC_HAGPCMNT_MASK); VIA_READ(VIA_REG_TRANSPACE); + + dev_priv->dma_diff = 0; + + count = 10000000; + while (!(VIA_READ(0x41c) & 0x80000000) && count--); + + reader = *(dev_priv->hw_addr_ptr); + ptr = ((volatile char *)dev_priv->last_pause_ptr - dev_priv->dma_ptr) + + dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4; + + /* + * This is the difference between where we tell the + * command reader to pause and where it actually pauses. + * This differs between hw implementation so we need to + * detect it. + */ + + dev_priv->dma_diff = ptr - reader; } static void via_pad_cache(drm_via_private_t * dev_priv, int qwords) @@ -592,7 +592,6 @@ static void via_cmdbuf_jump(drm_via_private_t * dev_priv) uint32_t pause_addr_lo, pause_addr_hi; uint32_t jump_addr_lo, jump_addr_hi; volatile uint32_t *last_pause_ptr; - uint32_t dma_low_save1, dma_low_save2; agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr; via_align_cmd(dev_priv, HC_HAGPBpID_JUMP, 0, &jump_addr_hi, @@ -619,31 +618,11 @@ static void via_cmdbuf_jump(drm_via_private_t * dev_priv) &pause_addr_lo, 0); *last_pause_ptr = pause_addr_lo; - dma_low_save1 = dev_priv->dma_low; - - /* - * Now, set a trap that will pause the regulator if it tries to rerun the old - * command buffer. (Which may happen if via_hook_segment detecs a command regulator pause - * and reissues the jump command over PCI, while the regulator has already taken the jump - * and actually paused at the current buffer end). - * There appears to be no other way to detect this condition, since the hw_addr_pointer - * does not seem to get updated immediately when a jump occurs. - */ - last_pause_ptr = - via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi, - &pause_addr_lo, 0) - 1; - via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi, - &pause_addr_lo, 0); - *last_pause_ptr = pause_addr_lo; - - dma_low_save2 = dev_priv->dma_low; - dev_priv->dma_low = dma_low_save1; - via_hook_segment(dev_priv, jump_addr_hi, jump_addr_lo, 0); - dev_priv->dma_low = dma_low_save2; - via_hook_segment(dev_priv, pause_addr_hi, pause_addr_lo, 0); + via_hook_segment( dev_priv, jump_addr_hi, jump_addr_lo, 0); } + static void via_cmdbuf_rewind(drm_via_private_t * dev_priv) { via_cmdbuf_jump(dev_priv); diff --git a/drivers/char/drm/via_drv.h b/drivers/char/drm/via_drv.h index 8b8778d4a42..b46ca8e6306 100644 --- a/drivers/char/drm/via_drv.h +++ b/drivers/char/drm/via_drv.h @@ -29,11 +29,11 @@ #define DRIVER_NAME "via" #define DRIVER_DESC "VIA Unichrome / Pro" -#define DRIVER_DATE "20061227" +#define DRIVER_DATE "20070202" #define DRIVER_MAJOR 2 #define DRIVER_MINOR 11 -#define DRIVER_PATCHLEVEL 0 +#define DRIVER_PATCHLEVEL 1 #include "via_verifier.h" @@ -93,6 +93,7 @@ typedef struct drm_via_private { unsigned long vram_offset; unsigned long agp_offset; drm_via_blitq_t blit_queues[VIA_NUM_BLIT_ENGINES]; + uint32_t dma_diff; } drm_via_private_t; enum via_family { -- cgit v1.2.3 From ef68d295508d52e792abf70d4f84461104d33b9d Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 8 May 2007 15:48:39 +1000 Subject: via: Make sure we flush write-combining using a follow-up read. Signed-off-by: Dave Airlie --- drivers/char/drm/via_dma.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/char/drm/via_dma.c b/drivers/char/drm/via_dma.c index 7635e859b87..13a9c5ca459 100644 --- a/drivers/char/drm/via_dma.c +++ b/drivers/char/drm/via_dma.c @@ -436,8 +436,10 @@ static int via_hook_segment(drm_via_private_t * dev_priv, paused = 0; via_flush_write_combine(); - *dev_priv->last_pause_ptr = pause_addr_lo; + (void) *(volatile uint32_t *)(via_get_dma(dev_priv) -1); + *paused_at = pause_addr_lo; via_flush_write_combine(); + (void) *paused_at; reader = *(dev_priv->hw_addr_ptr); ptr = ((volatile char *)paused_at - dev_priv->dma_ptr) + dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4; @@ -536,7 +538,7 @@ static void via_cmdbuf_start(drm_via_private_t * dev_priv) &pause_addr_hi, &pause_addr_lo, 1) - 1; via_flush_write_combine(); - while(! *dev_priv->last_pause_ptr); + (void) *(volatile uint32_t *)dev_priv->last_pause_ptr; VIA_WRITE(VIA_REG_TRANSET, (HC_ParaType_PreCR << 16)); VIA_WRITE(VIA_REG_TRANSPACE, command); -- cgit v1.2.3