2010-11-15 04:48:33 +03:00
/*
* Copyright 2010 Red Hat Inc .
*
* Permission is hereby granted , free of charge , to any person obtaining a
* copy of this software and associated documentation files ( the " Software " ) ,
* to deal in the Software without restriction , including without limitation
* the rights to use , copy , modify , merge , publish , distribute , sublicense ,
* and / or sell copies of the Software , and to permit persons to whom the
* Software is furnished to do so , subject to the following conditions :
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL
* THE COPYRIGHT HOLDER ( S ) OR AUTHOR ( S ) BE LIABLE FOR ANY CLAIM , DAMAGES OR
* OTHER LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE ,
* ARISING FROM , OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE .
*
* Authors : Ben Skeggs
*/
# include "drmP.h"
# include "nouveau_drv.h"
# include "nouveau_mm.h"
2011-02-14 00:34:55 +03:00
/* 0 = unsupported
* 1 = non - compressed
* 3 = compressed
*/
static const u8 types [ 256 ] = {
1 , 1 , 3 , 3 , 3 , 3 , 0 , 3 , 3 , 3 , 3 , 0 , 0 , 0 , 0 , 0 ,
0 , 1 , 0 , 0 , 0 , 0 , 0 , 3 , 3 , 3 , 3 , 0 , 0 , 0 , 0 , 0 ,
0 , 0 , 0 , 0 , 0 , 0 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 3 , 3 , 3 , 3 , 3 , 3 ,
3 , 3 , 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
0 , 3 , 3 , 3 , 3 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 ,
0 , 0 , 0 , 0 , 0 , 0 , 3 , 3 , 3 , 3 , 0 , 1 , 1 , 1 , 1 , 0 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
0 , 0 , 0 , 3 , 3 , 3 , 3 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 0 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 3 ,
3 , 3 , 3 , 3 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 3 , 3 , 3 , 3 ,
3 , 3 , 0 , 0 , 0 , 0 , 0 , 0 , 3 , 0 , 0 , 3 , 0 , 3 , 0 , 3 ,
3 , 0 , 3 , 3 , 3 , 3 , 3 , 0 , 0 , 3 , 0 , 3 , 0 , 3 , 3 , 0 ,
3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 0 , 1 , 1 , 0
} ;
2010-11-15 04:48:33 +03:00
bool
nvc0_vram_flags_valid ( struct drm_device * dev , u32 tile_flags )
{
2011-02-14 00:34:55 +03:00
u8 memtype = ( tile_flags & NOUVEAU_GEM_TILE_LAYOUT_MASK ) > > 8 ;
return likely ( ( types [ memtype ] = = 1 ) ) ;
2010-11-15 04:48:33 +03:00
}
int
nvc0_vram_new ( struct drm_device * dev , u64 size , u32 align , u32 ncmin ,
2011-02-10 05:22:52 +03:00
u32 type , struct nouveau_mem * * pmem )
2010-11-15 04:48:33 +03:00
{
struct drm_nouveau_private * dev_priv = dev - > dev_private ;
2011-06-24 04:14:07 +04:00
struct nouveau_mm * mm = & dev_priv - > engine . vram . mm ;
2010-11-15 04:48:33 +03:00
struct nouveau_mm_node * r ;
2011-02-10 05:22:52 +03:00
struct nouveau_mem * mem ;
2010-11-15 04:48:33 +03:00
int ret ;
size > > = 12 ;
align > > = 12 ;
ncmin > > = 12 ;
2011-02-10 05:22:52 +03:00
mem = kzalloc ( sizeof ( * mem ) , GFP_KERNEL ) ;
if ( ! mem )
2010-11-15 04:48:33 +03:00
return - ENOMEM ;
2011-02-10 05:22:52 +03:00
INIT_LIST_HEAD ( & mem - > regions ) ;
mem - > dev = dev_priv - > dev ;
2011-02-14 02:57:35 +03:00
mem - > memtype = ( type & 0xff ) ;
2011-02-10 05:22:52 +03:00
mem - > size = size ;
2010-11-15 04:48:33 +03:00
mutex_lock ( & mm - > mutex ) ;
do {
ret = nouveau_mm_get ( mm , 1 , size , ncmin , align , & r ) ;
if ( ret ) {
mutex_unlock ( & mm - > mutex ) ;
2011-02-10 05:22:52 +03:00
nv50_vram_del ( dev , & mem ) ;
2010-11-15 04:48:33 +03:00
return ret ;
}
2011-02-10 05:22:52 +03:00
list_add_tail ( & r - > rl_entry , & mem - > regions ) ;
2010-11-15 04:48:33 +03:00
size - = r - > length ;
} while ( size ) ;
mutex_unlock ( & mm - > mutex ) ;
2011-02-10 05:22:52 +03:00
r = list_first_entry ( & mem - > regions , struct nouveau_mm_node , rl_entry ) ;
mem - > offset = ( u64 ) r - > offset < < 12 ;
* pmem = mem ;
2010-11-15 04:48:33 +03:00
return 0 ;
}
int
nvc0_vram_init ( struct drm_device * dev )
{
struct drm_nouveau_private * dev_priv = dev - > dev_private ;
2011-06-10 07:36:08 +04:00
struct nouveau_vram_engine * vram = & dev_priv - > engine . vram ;
const u32 rsvd_head = ( 256 * 1024 ) > > 12 ; /* vga memory */
const u32 rsvd_tail = ( 1024 * 1024 ) > > 12 ; /* vbios etc */
2011-06-24 06:47:46 +04:00
u32 parts = nv_rd32 ( dev , 0x121c74 ) ;
u32 bsize = nv_rd32 ( dev , 0x10f20c ) ;
u32 offset , length ;
bool uniform = true ;
int ret , i ;
2010-11-15 04:48:33 +03:00
2011-06-24 06:47:46 +04:00
NV_DEBUG ( dev , " 0x100800: 0x%08x \n " , nv_rd32 ( dev , 0x100800 ) ) ;
NV_DEBUG ( dev , " parts 0x%08x bcast_mem_amount 0x%08x \n " , parts , bsize ) ;
2011-06-10 07:36:08 +04:00
2011-06-24 06:47:46 +04:00
/* read amount of vram attached to each memory controller */
for ( i = 0 ; i < parts ; i + + ) {
u32 psize = nv_rd32 ( dev , 0x11020c + ( i * 0x1000 ) ) ;
if ( psize ! = bsize ) {
if ( psize < bsize )
bsize = psize ;
uniform = false ;
}
NV_DEBUG ( dev , " %d: mem_amount 0x%08x \n " , i , psize ) ;
dev_priv - > vram_size + = ( u64 ) psize < < 20 ;
}
/* if all controllers have the same amount attached, there's no holes */
if ( uniform ) {
offset = rsvd_head ;
length = ( dev_priv - > vram_size > > 12 ) - rsvd_head - rsvd_tail ;
return nouveau_mm_init ( & vram - > mm , offset , length , 1 ) ;
}
2011-06-10 07:36:08 +04:00
2011-06-24 06:47:46 +04:00
/* otherwise, address lowest common amount from 0GiB */
ret = nouveau_mm_init ( & vram - > mm , rsvd_head , ( bsize < < 8 ) * parts , 1 ) ;
if ( ret )
return ret ;
/* and the rest starting from (8GiB + common_size) */
offset = ( 0x0200000000ULL > > 12 ) + ( bsize < < 8 ) ;
length = ( dev_priv - > vram_size > > 12 ) - ( bsize < < 8 ) - rsvd_tail ;
ret = nouveau_mm_init ( & vram - > mm , offset , length , 0 ) ;
if ( ret ) {
nouveau_mm_fini ( & vram - > mm ) ;
return ret ;
}
return 0 ;
2010-11-15 04:48:33 +03:00
}