2005-04-16 15:20:36 -07:00
/**
2005-09-25 14:28:13 +10:00
* \ file ati_pcigart . c
2005-04-16 15:20:36 -07:00
* ATI PCI GART support
*
* \ author Gareth Hughes < gareth @ valinux . com >
*/
/*
* Created : Wed Dec 13 21 : 52 : 19 2000 by gareth @ valinux . com
*
* Copyright 2000 VA Linux Systems , Inc . , Sunnyvale , California .
* All Rights Reserved .
*
* 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 ( 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 NONINFRINGEMENT . IN NO EVENT SHALL
* PRECISION INSIGHT 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 .
*/
# include "drmP.h"
# define ATI_PCIGART_PAGE_SIZE 4096 /**< PCI GART page size */
2008-03-17 10:24:24 +10:00
static int drm_ati_alloc_pcigart_table ( struct drm_device * dev ,
struct drm_ati_pcigart_info * gart_info )
2005-04-16 15:20:36 -07:00
{
2008-03-17 10:24:24 +10:00
gart_info - > table_handle = drm_pci_alloc ( dev , gart_info - > table_size ,
2010-01-05 11:25:05 +08:00
PAGE_SIZE ) ;
2008-03-17 10:24:24 +10:00
if ( gart_info - > table_handle = = NULL )
return - ENOMEM ;
2005-04-16 15:20:36 -07:00
2008-03-17 10:24:24 +10:00
return 0 ;
2005-04-16 15:20:36 -07:00
}
2008-03-17 10:24:24 +10:00
static void drm_ati_free_pcigart_table ( struct drm_device * dev ,
struct drm_ati_pcigart_info * gart_info )
2005-04-16 15:20:36 -07:00
{
2008-03-17 10:24:24 +10:00
drm_pci_free ( dev , gart_info - > table_handle ) ;
gart_info - > table_handle = NULL ;
2005-04-16 15:20:36 -07:00
}
2007-07-11 16:53:40 +10:00
int drm_ati_pcigart_cleanup ( struct drm_device * dev , struct drm_ati_pcigart_info * gart_info )
2005-04-16 15:20:36 -07:00
{
2007-07-11 16:53:40 +10:00
struct drm_sg_mem * entry = dev - > sg ;
2005-04-16 15:20:36 -07:00
unsigned long pages ;
int i ;
2008-03-17 10:24:24 +10:00
int max_pages ;
2005-04-16 15:20:36 -07:00
/* we need to support large memory configurations */
2005-09-25 14:28:13 +10:00
if ( ! entry ) {
DRM_ERROR ( " no scatter/gather memory! \n " ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2005-09-11 20:28:11 +10:00
if ( gart_info - > bus_addr ) {
2005-04-16 15:20:36 -07:00
2007-05-08 15:19:23 +10:00
max_pages = ( gart_info - > table_size / sizeof ( u32 ) ) ;
pages = ( entry - > pages < = max_pages )
? entry - > pages : max_pages ;
2005-04-16 15:20:36 -07:00
2005-09-25 14:28:13 +10:00
for ( i = 0 ; i < pages ; i + + ) {
if ( ! entry - > busaddr [ i ] )
break ;
2008-06-19 11:27:23 +10:00
pci_unmap_page ( dev - > pdev , entry - > busaddr [ i ] ,
2009-02-12 02:15:34 -08:00
PAGE_SIZE , PCI_DMA_BIDIRECTIONAL ) ;
2005-04-16 15:20:36 -07:00
}
2005-09-25 14:28:13 +10:00
if ( gart_info - > gart_table_location = = DRM_ATI_GART_MAIN )
gart_info - > bus_addr = 0 ;
2005-04-16 15:20:36 -07:00
}
2008-03-17 10:24:24 +10:00
if ( gart_info - > gart_table_location = = DRM_ATI_GART_MAIN & &
gart_info - > table_handle ) {
drm_ati_free_pcigart_table ( dev , gart_info ) ;
2005-04-16 15:20:36 -07:00
}
return 1 ;
}
EXPORT_SYMBOL ( drm_ati_pcigart_cleanup ) ;
2007-07-11 16:53:40 +10:00
int drm_ati_pcigart_init ( struct drm_device * dev , struct drm_ati_pcigart_info * gart_info )
2005-04-16 15:20:36 -07:00
{
2009-02-12 02:15:27 -08:00
struct drm_local_map * map = & gart_info - > mapping ;
2007-07-11 16:53:40 +10:00
struct drm_sg_mem * entry = dev - > sg ;
2006-01-02 17:18:39 +11:00
void * address = NULL ;
2005-04-16 15:20:36 -07:00
unsigned long pages ;
2009-02-26 10:13:47 +10:00
u32 * pci_gart = NULL , page_base , gart_idx ;
2008-03-17 10:24:24 +10:00
dma_addr_t bus_address = 0 ;
2005-04-16 15:20:36 -07:00
int i , j , ret = 0 ;
2009-02-15 01:08:07 -08:00
int max_ati_pages , max_real_pages ;
2005-04-16 15:20:36 -07:00
2005-09-25 14:28:13 +10:00
if ( ! entry ) {
DRM_ERROR ( " no scatter/gather memory! \n " ) ;
2005-04-16 15:20:36 -07:00
goto done ;
}
2005-09-25 14:28:13 +10:00
if ( gart_info - > gart_table_location = = DRM_ATI_GART_MAIN ) {
2005-09-11 20:28:11 +10:00
DRM_DEBUG ( " PCI: no table in VRAM: using normal RAM \n " ) ;
2005-09-25 14:28:13 +10:00
2010-01-05 11:25:05 +08:00
if ( pci_set_dma_mask ( dev - > pdev , gart_info - > table_mask ) ) {
DRM_ERROR ( " fail to set dma mask to 0x%Lx \n " ,
gart_info - > table_mask ) ;
ret = 1 ;
goto done ;
}
2008-03-17 10:24:24 +10:00
ret = drm_ati_alloc_pcigart_table ( dev , gart_info ) ;
if ( ret ) {
2005-09-25 14:28:13 +10:00
DRM_ERROR ( " cannot allocate PCI GART page! \n " ) ;
2005-09-11 20:28:11 +10:00
goto done ;
}
2005-09-25 14:28:13 +10:00
2009-02-26 10:13:47 +10:00
pci_gart = gart_info - > table_handle - > vaddr ;
2008-03-17 10:24:24 +10:00
address = gart_info - > table_handle - > vaddr ;
bus_address = gart_info - > table_handle - > busaddr ;
2005-09-25 14:28:13 +10:00
} else {
2005-09-11 20:28:11 +10:00
address = gart_info - > addr ;
bus_address = gart_info - > bus_addr ;
2008-03-28 14:15:49 -07:00
DRM_DEBUG ( " PCI: Gart Table: VRAM %08LX mapped at %08lX \n " ,
( unsigned long long ) bus_address ,
( unsigned long ) address ) ;
2005-04-16 15:20:36 -07:00
}
2009-02-15 01:08:07 -08:00
max_ati_pages = ( gart_info - > table_size / sizeof ( u32 ) ) ;
max_real_pages = max_ati_pages / ( PAGE_SIZE / ATI_PCIGART_PAGE_SIZE ) ;
pages = ( entry - > pages < = max_real_pages )
? entry - > pages : max_real_pages ;
2005-04-16 15:20:36 -07:00
2009-02-12 02:15:27 -08:00
if ( gart_info - > gart_table_location = = DRM_ATI_GART_MAIN ) {
2009-02-15 01:08:07 -08:00
memset ( pci_gart , 0 , max_ati_pages * sizeof ( u32 ) ) ;
2009-02-12 02:15:27 -08:00
} else {
2009-02-26 10:13:47 +10:00
memset_io ( ( void __iomem * ) map - > handle , 0 , max_ati_pages * sizeof ( u32 ) ) ;
2009-02-12 02:15:27 -08:00
}
2005-04-16 15:20:36 -07:00
2009-02-12 02:15:27 -08:00
gart_idx = 0 ;
2005-09-25 14:28:13 +10:00
for ( i = 0 ; i < pages ; i + + ) {
2005-04-16 15:20:36 -07:00
/* we need to support large memory configurations */
2008-06-19 11:27:23 +10:00
entry - > busaddr [ i ] = pci_map_page ( dev - > pdev , entry - > pagelist [ i ] ,
2009-02-12 02:15:34 -08:00
0 , PAGE_SIZE , PCI_DMA_BIDIRECTIONAL ) ;
2005-04-16 15:20:36 -07:00
if ( entry - > busaddr [ i ] = = 0 ) {
2005-09-25 14:28:13 +10:00
DRM_ERROR ( " unable to map PCIGART pages! \n " ) ;
2005-09-11 20:28:11 +10:00
drm_ati_pcigart_cleanup ( dev , gart_info ) ;
2006-01-02 17:18:39 +11:00
address = NULL ;
2005-04-16 15:20:36 -07:00
bus_address = 0 ;
goto done ;
}
page_base = ( u32 ) entry - > busaddr [ i ] ;
for ( j = 0 ; j < ( PAGE_SIZE / ATI_PCIGART_PAGE_SIZE ) ; j + + ) {
2009-02-12 02:15:27 -08:00
u32 val ;
2007-05-08 15:19:23 +10:00
switch ( gart_info - > gart_reg_if ) {
case DRM_ATI_GART_IGP :
2009-02-12 02:15:27 -08:00
val = page_base | 0xc ;
2007-05-08 15:19:23 +10:00
break ;
case DRM_ATI_GART_PCIE :
2009-02-12 02:15:27 -08:00
val = ( page_base > > 8 ) | 0xc ;
2007-05-08 15:19:23 +10:00
break ;
default :
case DRM_ATI_GART_PCI :
2009-02-12 02:15:27 -08:00
val = page_base ;
2007-05-08 15:19:23 +10:00
break ;
}
2009-02-12 02:15:27 -08:00
if ( gart_info - > gart_table_location = =
DRM_ATI_GART_MAIN )
pci_gart [ gart_idx ] = cpu_to_le32 ( val ) ;
else
DRM_WRITE32 ( map , gart_idx * sizeof ( u32 ) , val ) ;
gart_idx + + ;
2005-04-16 15:20:36 -07:00
page_base + = ATI_PCIGART_PAGE_SIZE ;
}
}
ret = 1 ;
# if defined(__i386__) || defined(__x86_64__)
wbinvd ( ) ;
# else
mb ( ) ;
# endif
2005-09-25 14:28:13 +10:00
done :
2005-09-11 20:28:11 +10:00
gart_info - > addr = address ;
2005-09-25 14:28:13 +10:00
gart_info - > bus_addr = bus_address ;
2005-04-16 15:20:36 -07:00
return ret ;
}
EXPORT_SYMBOL ( drm_ati_pcigart_init ) ;