2018-05-07 01:16:22 +02:00
// SPDX-License-Identifier: GPL-2.0 OR MIT
2009-12-11 19:24:15 +10:00
/*
* Copyright ( c ) 2007 - 2008 Tungsten Graphics , Inc . , Cedar Park , TX . , USA ,
* Copyright ( c ) 2009 VMware , Inc . , Palo Alto , CA . , USA ,
*
* 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 , sub license ,
* 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 ( including the
* next paragraph ) 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 NON - INFRINGEMENT . IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS , AUTHORS AND / OR ITS SUPPLIERS 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 .
*/
2016-05-20 09:22:55 +10:00
# include "nouveau_drv.h"
2012-07-20 08:17:34 +10:00
# include "nouveau_gem.h"
2017-11-01 03:56:19 +10:00
# include "nouveau_mem.h"
# include "nouveau_ttm.h"
2009-12-11 19:24:15 +10:00
2017-04-24 13:50:29 +09:00
# include <drm/drm_legacy.h>
2015-09-04 19:59:34 +09:00
# include <core/tegra.h>
2012-07-19 17:54:21 +10:00
static int
2017-11-01 03:56:19 +10:00
nouveau_manager_init ( struct ttm_mem_type_manager * man , unsigned long psize )
2012-07-19 17:54:21 +10:00
{
return 0 ;
}
static int
2017-11-01 03:56:19 +10:00
nouveau_manager_fini ( struct ttm_mem_type_manager * man )
2012-07-19 17:54:21 +10:00
{
return 0 ;
}
2017-11-01 03:56:19 +10:00
static void
2017-11-01 03:56:19 +10:00
nouveau_manager_del ( struct ttm_mem_type_manager * man , struct ttm_mem_reg * reg )
2017-11-01 03:56:19 +10:00
{
2017-11-01 03:56:19 +10:00
nouveau_mem_del ( reg ) ;
2017-11-01 03:56:19 +10:00
}
2017-11-01 03:56:19 +10:00
static void
nouveau_manager_debug ( struct ttm_mem_type_manager * man ,
struct drm_printer * printer )
2012-07-19 17:54:21 +10:00
{
}
static int
nouveau_vram_manager_new ( struct ttm_mem_type_manager * man ,
struct ttm_buffer_object * bo ,
2014-08-27 13:16:04 +02:00
const struct ttm_place * place ,
2016-05-17 11:13:37 +10:00
struct ttm_mem_reg * reg )
2012-07-19 17:54:21 +10:00
{
struct nouveau_bo * nvbo = nouveau_bo ( bo ) ;
2018-05-08 20:39:47 +10:00
struct nouveau_drm * drm = nouveau_bdev ( bo - > bdev ) ;
2012-07-19 17:54:21 +10:00
int ret ;
2016-05-18 13:57:42 +10:00
if ( drm - > client . device . info . ram_size = = 0 )
2015-02-20 18:22:59 +09:00
return - ENOMEM ;
2017-11-01 03:56:19 +10:00
ret = nouveau_mem_new ( & drm - > master , nvbo - > kind , nvbo - > comp , reg ) ;
if ( ret )
return ret ;
2012-07-19 17:54:21 +10:00
2017-11-01 03:56:19 +10:00
ret = nouveau_mem_vram ( reg , nvbo - > contig , nvbo - > page ) ;
2012-07-19 17:54:21 +10:00
if ( ret ) {
2017-11-01 03:56:19 +10:00
nouveau_mem_del ( reg ) ;
if ( ret = = - ENOSPC ) {
reg - > mm_node = NULL ;
return 0 ;
}
return ret ;
2012-07-19 17:54:21 +10:00
}
return 0 ;
}
const struct ttm_mem_type_manager_func nouveau_vram_manager = {
2017-11-01 03:56:19 +10:00
. init = nouveau_manager_init ,
. takedown = nouveau_manager_fini ,
2016-12-16 17:04:42 -08:00
. get_node = nouveau_vram_manager_new ,
2017-11-01 03:56:20 +10:00
. put_node = nouveau_manager_del ,
2017-11-01 03:56:19 +10:00
. debug = nouveau_manager_debug ,
2012-07-19 17:54:21 +10:00
} ;
static int
nouveau_gart_manager_new ( struct ttm_mem_type_manager * man ,
struct ttm_buffer_object * bo ,
2014-08-27 13:16:04 +02:00
const struct ttm_place * place ,
2016-05-17 11:13:37 +10:00
struct ttm_mem_reg * reg )
2012-07-19 17:54:21 +10:00
{
2013-03-22 12:12:17 +10:00
struct nouveau_bo * nvbo = nouveau_bo ( bo ) ;
2018-05-08 20:39:47 +10:00
struct nouveau_drm * drm = nouveau_bdev ( bo - > bdev ) ;
2017-11-01 03:56:19 +10:00
int ret ;
2012-07-19 17:54:21 +10:00
2017-11-01 03:56:19 +10:00
ret = nouveau_mem_new ( & drm - > master , nvbo - > kind , nvbo - > comp , reg ) ;
if ( ret )
return ret ;
2013-03-22 12:12:17 +10:00
2017-11-01 03:56:19 +10:00
reg - > start = 0 ;
2012-07-19 17:54:21 +10:00
return 0 ;
}
const struct ttm_mem_type_manager_func nouveau_gart_manager = {
2017-11-01 03:56:19 +10:00
. init = nouveau_manager_init ,
. takedown = nouveau_manager_fini ,
2016-12-16 17:04:42 -08:00
. get_node = nouveau_gart_manager_new ,
2017-11-01 03:56:19 +10:00
. put_node = nouveau_manager_del ,
2017-11-01 03:56:19 +10:00
. debug = nouveau_manager_debug
2012-07-19 17:54:21 +10:00
} ;
static int
nv04_gart_manager_new ( struct ttm_mem_type_manager * man ,
struct ttm_buffer_object * bo ,
2014-08-27 13:16:04 +02:00
const struct ttm_place * place ,
2016-05-17 11:13:37 +10:00
struct ttm_mem_reg * reg )
2012-07-19 17:54:21 +10:00
{
2017-11-01 03:56:19 +10:00
struct nouveau_bo * nvbo = nouveau_bo ( bo ) ;
2018-05-08 20:39:47 +10:00
struct nouveau_drm * drm = nouveau_bdev ( bo - > bdev ) ;
2017-11-01 03:56:19 +10:00
struct nouveau_mem * mem ;
2012-07-19 17:54:21 +10:00
int ret ;
2017-11-01 03:56:19 +10:00
ret = nouveau_mem_new ( & drm - > master , nvbo - > kind , nvbo - > comp , reg ) ;
mem = nouveau_mem ( reg ) ;
if ( ret )
return ret ;
2012-07-19 17:54:21 +10:00
2017-11-01 03:56:20 +10:00
ret = nvif_vmm_get ( & mem - > cli - > vmm . vmm , PTES , false , 12 , 0 ,
reg - > num_pages < < PAGE_SHIFT , & mem - > vma [ 0 ] ) ;
2012-07-19 17:54:21 +10:00
if ( ret ) {
2017-11-01 03:56:19 +10:00
nouveau_mem_del ( reg ) ;
2017-11-01 03:56:19 +10:00
if ( ret = = - ENOSPC ) {
reg - > mm_node = NULL ;
2017-11-01 03:56:19 +10:00
return 0 ;
2017-11-01 03:56:19 +10:00
}
2012-07-19 17:54:21 +10:00
return ret ;
}
2017-11-01 03:56:19 +10:00
reg - > start = mem - > vma [ 0 ] . addr > > PAGE_SHIFT ;
2012-07-19 17:54:21 +10:00
return 0 ;
}
const struct ttm_mem_type_manager_func nv04_gart_manager = {
2017-11-01 03:56:19 +10:00
. init = nouveau_manager_init ,
. takedown = nouveau_manager_fini ,
2016-12-16 17:04:42 -08:00
. get_node = nv04_gart_manager_new ,
2017-11-01 03:56:19 +10:00
. put_node = nouveau_manager_del ,
2017-11-01 03:56:19 +10:00
. debug = nouveau_manager_debug
2012-07-19 17:54:21 +10:00
} ;
2009-12-11 19:24:15 +10:00
int
nouveau_ttm_mmap ( struct file * filp , struct vm_area_struct * vma )
{
struct drm_file * file_priv = filp - > private_data ;
2012-07-31 16:16:21 +10:00
struct nouveau_drm * drm = nouveau_drm ( file_priv - > minor - > dev ) ;
2009-12-11 19:24:15 +10:00
2012-07-20 08:17:34 +10:00
return ttm_bo_mmap ( filp , vma , & drm - > ttm . bdev ) ;
2009-12-11 19:24:15 +10:00
}
2017-12-14 11:19:27 +10:00
static int
nouveau_ttm_init_host ( struct nouveau_drm * drm , u8 kind )
2012-07-20 08:17:34 +10:00
{
2017-11-01 03:56:20 +10:00
struct nvif_mmu * mmu = & drm - > client . mmu ;
2017-12-14 11:19:27 +10:00
int typei ;
2017-11-01 03:56:20 +10:00
typei = nvif_mmu_type ( mmu , NVIF_MEM_HOST | NVIF_MEM_MAPPABLE |
2017-12-14 11:19:27 +10:00
kind | NVIF_MEM_COHERENT ) ;
2017-11-01 03:56:20 +10:00
if ( typei < 0 )
return - ENOSYS ;
2017-12-14 11:19:27 +10:00
drm - > ttm . type_host [ ! ! kind ] = typei ;
2017-11-01 03:56:20 +10:00
2017-12-14 11:19:27 +10:00
typei = nvif_mmu_type ( mmu , NVIF_MEM_HOST | NVIF_MEM_MAPPABLE | kind ) ;
2017-11-01 03:56:20 +10:00
if ( typei < 0 )
return - ENOSYS ;
2017-12-14 11:19:27 +10:00
drm - > ttm . type_ncoh [ ! ! kind ] = typei ;
return 0 ;
}
int
nouveau_ttm_init ( struct nouveau_drm * drm )
{
struct nvkm_device * device = nvxx_device ( & drm - > client . device ) ;
struct nvkm_pci * pci = device - > pci ;
struct nvif_mmu * mmu = & drm - > client . mmu ;
struct drm_device * dev = drm - > dev ;
int typei , ret ;
ret = nouveau_ttm_init_host ( drm , 0 ) ;
if ( ret )
return ret ;
if ( drm - > client . device . info . family > = NV_DEVICE_INFO_V0_TESLA & &
drm - > client . device . info . chipset ! = 0x50 ) {
ret = nouveau_ttm_init_host ( drm , NVIF_MEM_KIND ) ;
if ( ret )
return ret ;
}
2017-11-01 03:56:20 +10:00
if ( drm - > client . device . info . platform ! = NV_DEVICE_INFO_V0_SOC & &
drm - > client . device . info . family > = NV_DEVICE_INFO_V0_TESLA ) {
typei = nvif_mmu_type ( mmu , NVIF_MEM_VRAM | NVIF_MEM_MAPPABLE |
NVIF_MEM_KIND |
NVIF_MEM_COMP |
NVIF_MEM_DISP ) ;
if ( typei < 0 )
return - ENOSYS ;
drm - > ttm . type_vram = typei ;
} else {
drm - > ttm . type_vram = - 1 ;
}
2012-07-20 08:17:34 +10:00
2015-08-20 14:54:23 +10:00
if ( pci & & pci - > agp . bridge ) {
drm - > agp . bridge = pci - > agp . bridge ;
drm - > agp . base = pci - > agp . base ;
drm - > agp . size = pci - > agp . size ;
drm - > agp . cma = pci - > agp . cma ;
}
2012-07-20 08:17:34 +10:00
ret = ttm_bo_device_init ( & drm - > ttm . bdev ,
2013-08-13 19:10:30 +02:00
& nouveau_bo_driver ,
dev - > anon_inode - > i_mapping ,
2019-09-05 09:05:03 +02:00
dev - > vma_offset_manager ,
2017-11-01 03:56:19 +10:00
drm - > client . mmu . dmabits < = 32 ? true : false ) ;
2012-07-20 08:17:34 +10:00
if ( ret ) {
NV_ERROR ( drm , " error initialising bo driver, %d \n " , ret ) ;
return ret ;
}
/* VRAM init */
2016-05-18 13:57:42 +10:00
drm - > gem . vram_available = drm - > client . device . info . ram_user ;
2012-07-20 08:17:34 +10:00
2016-10-24 15:37:48 +10:00
arch_io_reserve_memtype_wc ( device - > func - > resource_addr ( device , 1 ) ,
device - > func - > resource_size ( device , 1 ) ) ;
2012-07-20 08:17:34 +10:00
ret = ttm_bo_init_mm ( & drm - > ttm . bdev , TTM_PL_VRAM ,
drm - > gem . vram_available > > PAGE_SHIFT ) ;
if ( ret ) {
NV_ERROR ( drm , " VRAM mm init failed, %d \n " , ret ) ;
return ret ;
}
2015-08-20 14:54:23 +10:00
drm - > ttm . mtrr = arch_phys_wc_add ( device - > func - > resource_addr ( device , 1 ) ,
device - > func - > resource_size ( device , 1 ) ) ;
2012-07-20 08:17:34 +10:00
/* GART init */
2015-08-20 14:54:23 +10:00
if ( ! drm - > agp . bridge ) {
2017-11-01 03:56:20 +10:00
drm - > gem . gart_available = drm - > client . vmm . vmm . limit ;
2012-07-20 08:17:34 +10:00
} else {
drm - > gem . gart_available = drm - > agp . size ;
}
ret = ttm_bo_init_mm ( & drm - > ttm . bdev , TTM_PL_TT ,
drm - > gem . gart_available > > PAGE_SHIFT ) ;
if ( ret ) {
NV_ERROR ( drm , " GART mm init failed, %d \n " , ret ) ;
return ret ;
}
NV_INFO ( drm , " VRAM: %d MiB \n " , ( u32 ) ( drm - > gem . vram_available > > 20 ) ) ;
NV_INFO ( drm , " GART: %d MiB \n " , ( u32 ) ( drm - > gem . gart_available > > 20 ) ) ;
return 0 ;
}
void
nouveau_ttm_fini ( struct nouveau_drm * drm )
{
2016-05-18 13:57:42 +10:00
struct nvkm_device * device = nvxx_device ( & drm - > client . device ) ;
2016-10-24 15:37:48 +10:00
2012-07-20 08:17:34 +10:00
ttm_bo_clean_mm ( & drm - > ttm . bdev , TTM_PL_VRAM ) ;
ttm_bo_clean_mm ( & drm - > ttm . bdev , TTM_PL_TT ) ;
ttm_bo_device_release ( & drm - > ttm . bdev ) ;
2013-05-13 23:58:41 +00:00
arch_phys_wc_del ( drm - > ttm . mtrr ) ;
drm - > ttm . mtrr = 0 ;
2016-10-24 15:37:48 +10:00
arch_io_free_memtype_wc ( device - > func - > resource_addr ( device , 1 ) ,
device - > func - > resource_size ( device , 1 ) ) ;
2009-12-11 19:24:15 +10:00
}