drm/radeon/kms: avoid possible oops (call gart_fini before gart_disable)
[linux-2.6.git] / drivers / gpu / drm / radeon / r300.c
index 748335c..1023eeb 100644 (file)
@@ -30,6 +30,7 @@
 #include "drm.h"
 #include "radeon_reg.h"
 #include "radeon.h"
+#include "radeon_asic.h"
 #include "radeon_drm.h"
 #include "r100_track.h"
 #include "r300d.h"
@@ -117,18 +118,19 @@ int rv370_pcie_gart_enable(struct radeon_device *rdev)
        r = radeon_gart_table_vram_pin(rdev);
        if (r)
                return r;
+       radeon_gart_restore(rdev);
        /* discard memory request outside of configured range */
        tmp = RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_DISCARD;
        WREG32_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp);
-       WREG32_PCIE(RADEON_PCIE_TX_GART_START_LO, rdev->mc.gtt_location);
-       tmp = rdev->mc.gtt_location + rdev->mc.gtt_size - RADEON_GPU_PAGE_SIZE;
+       WREG32_PCIE(RADEON_PCIE_TX_GART_START_LO, rdev->mc.gtt_start);
+       tmp = rdev->mc.gtt_end & ~RADEON_GPU_PAGE_MASK;
        WREG32_PCIE(RADEON_PCIE_TX_GART_END_LO, tmp);
        WREG32_PCIE(RADEON_PCIE_TX_GART_START_HI, 0);
        WREG32_PCIE(RADEON_PCIE_TX_GART_END_HI, 0);
        table_addr = rdev->gart.table_addr;
        WREG32_PCIE(RADEON_PCIE_TX_GART_BASE, table_addr);
        /* FIXME: setup default page */
-       WREG32_PCIE(RADEON_PCIE_TX_DISCARD_RD_ADDR_LO, rdev->mc.vram_location);
+       WREG32_PCIE(RADEON_PCIE_TX_DISCARD_RD_ADDR_LO, rdev->mc.vram_start);
        WREG32_PCIE(RADEON_PCIE_TX_DISCARD_RD_ADDR_HI, 0);
        /* Clear error */
        WREG32_PCIE(0x18, 0);
@@ -163,9 +165,9 @@ void rv370_pcie_gart_disable(struct radeon_device *rdev)
 
 void rv370_pcie_gart_fini(struct radeon_device *rdev)
 {
+       radeon_gart_fini(rdev);
        rv370_pcie_gart_disable(rdev);
        radeon_gart_table_vram_free(rdev);
-       radeon_gart_fini(rdev);
 }
 
 void r300_fence_ring_emit(struct radeon_device *rdev,
@@ -200,50 +202,6 @@ void r300_fence_ring_emit(struct radeon_device *rdev,
        radeon_ring_write(rdev, RADEON_SW_INT_FIRE);
 }
 
-int r300_copy_dma(struct radeon_device *rdev,
-                 uint64_t src_offset,
-                 uint64_t dst_offset,
-                 unsigned num_pages,
-                 struct radeon_fence *fence)
-{
-       uint32_t size;
-       uint32_t cur_size;
-       int i, num_loops;
-       int r = 0;
-
-       /* radeon pitch is /64 */
-       size = num_pages << PAGE_SHIFT;
-       num_loops = DIV_ROUND_UP(size, 0x1FFFFF);
-       r = radeon_ring_lock(rdev, num_loops * 4 + 64);
-       if (r) {
-               DRM_ERROR("radeon: moving bo (%d).\n", r);
-               return r;
-       }
-       /* Must wait for 2D idle & clean before DMA or hangs might happen */
-       radeon_ring_write(rdev, PACKET0(RADEON_WAIT_UNTIL, 0 ));
-       radeon_ring_write(rdev, RADEON_WAIT_2D_IDLECLEAN);
-       for (i = 0; i < num_loops; i++) {
-               cur_size = size;
-               if (cur_size > 0x1FFFFF) {
-                       cur_size = 0x1FFFFF;
-               }
-               size -= cur_size;
-               radeon_ring_write(rdev, PACKET0(0x720, 2));
-               radeon_ring_write(rdev, src_offset);
-               radeon_ring_write(rdev, dst_offset);
-               radeon_ring_write(rdev, cur_size | (1 << 31) | (1 << 30));
-               src_offset += cur_size;
-               dst_offset += cur_size;
-       }
-       radeon_ring_write(rdev, PACKET0(RADEON_WAIT_UNTIL, 0));
-       radeon_ring_write(rdev, RADEON_WAIT_DMA_GUI_IDLE);
-       if (fence) {
-               r = radeon_fence_emit(rdev, fence);
-       }
-       radeon_ring_unlock_commit(rdev);
-       return r;
-}
-
 void r300_ring_start(struct radeon_device *rdev)
 {
        unsigned gb_tile_config;
@@ -502,13 +460,13 @@ int r300_gpu_reset(struct radeon_device *rdev)
 /*
  * r300,r350,rv350,rv380 VRAM info
  */
-void r300_vram_info(struct radeon_device *rdev)
+void r300_mc_init(struct radeon_device *rdev)
 {
-       uint32_t tmp;
+       u64 base;
+       u32 tmp;
 
        /* DDR for all card after R300 & IGP */
        rdev->mc.vram_is_ddr = true;
-
        tmp = RREG32(RADEON_MEM_CNTL);
        tmp &= R300_MEM_NUM_CHANNELS_MASK;
        switch (tmp) {
@@ -517,8 +475,14 @@ void r300_vram_info(struct radeon_device *rdev)
        case 2: rdev->mc.vram_width = 256; break;
        default:  rdev->mc.vram_width = 128; break;
        }
-
        r100_vram_init_sizes(rdev);
+       base = rdev->mc.aper_base;
+       if (rdev->flags & RADEON_IS_IGP)
+               base = (RREG32(RADEON_NB_TOM) & 0xffff) << 16;
+       radeon_vram_location(rdev, &rdev->mc, base);
+       if (!(rdev->flags & RADEON_IS_AGP))
+               radeon_gtt_location(rdev, &rdev->mc);
+       radeon_update_bandwidth_info(rdev);
 }
 
 void rv370_set_pcie_lanes(struct radeon_device *rdev, int lanes)
@@ -580,6 +544,40 @@ void rv370_set_pcie_lanes(struct radeon_device *rdev, int lanes)
 
 }
 
+int rv370_get_pcie_lanes(struct radeon_device *rdev)
+{
+       u32 link_width_cntl;
+
+       if (rdev->flags & RADEON_IS_IGP)
+               return 0;
+
+       if (!(rdev->flags & RADEON_IS_PCIE))
+               return 0;
+
+       /* FIXME wait for idle */
+
+       if (rdev->family < CHIP_R600)
+               link_width_cntl = RREG32_PCIE(RADEON_PCIE_LC_LINK_WIDTH_CNTL);
+       else
+               link_width_cntl = RREG32_PCIE_P(RADEON_PCIE_LC_LINK_WIDTH_CNTL);
+
+       switch ((link_width_cntl & RADEON_PCIE_LC_LINK_WIDTH_RD_MASK) >> RADEON_PCIE_LC_LINK_WIDTH_RD_SHIFT) {
+       case RADEON_PCIE_LC_LINK_WIDTH_X0:
+               return 0;
+       case RADEON_PCIE_LC_LINK_WIDTH_X1:
+               return 1;
+       case RADEON_PCIE_LC_LINK_WIDTH_X2:
+               return 2;
+       case RADEON_PCIE_LC_LINK_WIDTH_X4:
+               return 4;
+       case RADEON_PCIE_LC_LINK_WIDTH_X8:
+               return 8;
+       case RADEON_PCIE_LC_LINK_WIDTH_X16:
+       default:
+               return 16;
+       }
+}
+
 #if defined(CONFIG_DEBUG_FS)
 static int rv370_debugfs_pcie_gart_info(struct seq_file *m, void *data)
 {
@@ -709,6 +707,8 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
                        tile_flags |= R300_TXO_MACRO_TILE;
                if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO)
                        tile_flags |= R300_TXO_MICRO_TILE;
+               else if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO_SQUARE)
+                       tile_flags |= R300_TXO_MICRO_TILE_SQUARE;
 
                tmp = idx_value + ((u32)reloc->lobj.gpu_offset);
                tmp |= tile_flags;
@@ -759,6 +759,8 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
                        tile_flags |= R300_COLOR_TILE_ENABLE;
                if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO)
                        tile_flags |= R300_COLOR_MICROTILE_ENABLE;
+               else if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO_SQUARE)
+                       tile_flags |= R300_COLOR_MICROTILE_SQUARE_ENABLE;
 
                tmp = idx_value & ~(0x7 << 16);
                tmp |= tile_flags;
@@ -830,7 +832,9 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
                if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO)
                        tile_flags |= R300_DEPTHMACROTILE_ENABLE;
                if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO)
-                       tile_flags |= R300_DEPTHMICROTILE_TILED;;
+                       tile_flags |= R300_DEPTHMICROTILE_TILED;
+               else if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO_SQUARE)
+                       tile_flags |= R300_DEPTHMICROTILE_TILED_SQUARE;
 
                tmp = idx_value & ~(0x7 << 16);
                tmp |= tile_flags;
@@ -1332,6 +1336,7 @@ int r300_suspend(struct radeon_device *rdev)
 
 void r300_fini(struct radeon_device *rdev)
 {
+       radeon_pm_fini(rdev);
        r100_cp_fini(rdev);
        r100_wb_fini(rdev);
        r100_ib_fini(rdev);
@@ -1389,12 +1394,15 @@ int r300_init(struct radeon_device *rdev)
        radeon_get_clock_info(rdev->ddev);
        /* Initialize power management */
        radeon_pm_init(rdev);
-       /* Get vram informations */
-       r300_vram_info(rdev);
-       /* Initialize memory controller (also test AGP) */
-       r = r420_mc_init(rdev);
-       if (r)
-               return r;
+       /* initialize AGP */
+       if (rdev->flags & RADEON_IS_AGP) {
+               r = radeon_agp_init(rdev);
+               if (r) {
+                       radeon_agp_disable(rdev);
+               }
+       }
+       /* initialize memory controller */
+       r300_mc_init(rdev);
        /* Fence driver */
        r = radeon_fence_driver_init(rdev);
        if (r)