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"
# 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 */
2006-01-02 17:18:39 +11:00
static void * drm_ati_alloc_pcigart_table ( void )
2005-04-16 15:20:36 -07:00
{
unsigned long address ;
struct page * page ;
int i ;
2005-09-25 14:28:13 +10:00
DRM_DEBUG ( " %s \n " , __FUNCTION__ ) ;
2005-04-16 15:20:36 -07:00
2006-01-25 14:58:58 +11:00
address = __get_free_pages ( GFP_KERNEL | __GFP_COMP ,
ATI_PCIGART_TABLE_ORDER ) ;
2005-09-25 14:28:13 +10:00
if ( address = = 0UL ) {
2006-01-25 14:54:15 +11:00
return NULL ;
2005-04-16 15:20:36 -07:00
}
2005-09-25 14:28:13 +10:00
page = virt_to_page ( address ) ;
2005-04-16 15:20:36 -07:00
2006-01-25 14:58:58 +11:00
for ( i = 0 ; i < ATI_PCIGART_TABLE_PAGES ; i + + , page + + )
2005-09-25 14:28:13 +10:00
SetPageReserved ( page ) ;
2005-04-16 15:20:36 -07:00
2005-09-25 14:28:13 +10:00
DRM_DEBUG ( " %s: returning 0x%08lx \n " , __FUNCTION__ , address ) ;
2006-01-02 17:18:39 +11:00
return ( void * ) address ;
2005-04-16 15:20:36 -07:00
}
2006-01-02 17:18:39 +11:00
static void drm_ati_free_pcigart_table ( void * address )
2005-04-16 15:20:36 -07:00
{
struct page * page ;
int i ;
2005-09-25 14:28:13 +10:00
DRM_DEBUG ( " %s \n " , __FUNCTION__ ) ;
2005-04-16 15:20:36 -07:00
2006-01-02 17:18:39 +11:00
page = virt_to_page ( ( unsigned long ) address ) ;
2005-04-16 15:20:36 -07:00
2006-01-25 14:58:58 +11:00
for ( i = 0 ; i < ATI_PCIGART_TABLE_PAGES ; i + + , page + + )
2005-09-25 14:28:13 +10:00
ClearPageReserved ( page ) ;
2005-04-16 15:20:36 -07:00
2006-01-02 17:18:39 +11:00
free_pages ( ( unsigned long ) address , ATI_PCIGART_TABLE_ORDER ) ;
2005-04-16 15:20:36 -07:00
}
2006-01-02 17:18:39 +11:00
int drm_ati_pcigart_cleanup ( drm_device_t * dev , drm_ati_pcigart_info * gart_info )
2005-04-16 15:20:36 -07:00
{
drm_sg_mem_t * entry = dev - > sg ;
unsigned long pages ;
int i ;
/* 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-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
pci_unmap_single ( dev - > pdev , gart_info - > bus_addr ,
ATI_PCIGART_TABLE_PAGES * PAGE_SIZE ,
PCI_DMA_TODEVICE ) ;
}
2005-04-16 15:20:36 -07:00
2005-09-25 14:28:13 +10:00
pages = ( entry - > pages < = ATI_MAX_PCIGART_PAGES )
? entry - > pages : ATI_MAX_PCIGART_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 ;
2005-04-16 15:20:36 -07:00
pci_unmap_single ( dev - > pdev , entry - > busaddr [ i ] ,
PAGE_SIZE , PCI_DMA_TODEVICE ) ;
}
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
}
2005-09-25 14:28:13 +10:00
if ( gart_info - > gart_table_location = = DRM_ATI_GART_MAIN
& & gart_info - > addr ) {
2005-09-11 20:28:11 +10:00
drm_ati_free_pcigart_table ( gart_info - > addr ) ;
2006-01-25 14:54:15 +11:00
gart_info - > addr = NULL ;
2005-04-16 15:20:36 -07:00
}
return 1 ;
}
2005-09-25 14:28:13 +10:00
2005-04-16 15:20:36 -07:00
EXPORT_SYMBOL ( drm_ati_pcigart_cleanup ) ;
2006-01-02 17:18:39 +11:00
int drm_ati_pcigart_init ( drm_device_t * dev , drm_ati_pcigart_info * gart_info )
2005-04-16 15:20:36 -07:00
{
drm_sg_mem_t * 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 ;
u32 * pci_gart , page_base , bus_address = 0 ;
int i , j , ret = 0 ;
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
2005-09-11 20:28:11 +10:00
address = drm_ati_alloc_pcigart_table ( ) ;
2005-09-25 14:28:13 +10:00
if ( ! address ) {
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
if ( ! dev - > pdev ) {
DRM_ERROR ( " PCI device unknown! \n " ) ;
2005-09-11 20:28:11 +10:00
goto done ;
}
2005-04-16 15:20:36 -07:00
2006-01-02 17:18:39 +11:00
bus_address = pci_map_single ( dev - > pdev , address ,
2005-09-25 14:28:13 +10:00
ATI_PCIGART_TABLE_PAGES *
PAGE_SIZE , PCI_DMA_TODEVICE ) ;
2005-09-11 20:28:11 +10:00
if ( bus_address = = 0 ) {
2005-09-25 14:28:13 +10:00
DRM_ERROR ( " unable to map PCIGART pages! \n " ) ;
drm_ati_free_pcigart_table ( address ) ;
2006-01-25 14:54:15 +11:00
address = NULL ;
2005-09-11 20:28:11 +10:00
goto done ;
}
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 ;
2005-09-25 14:28:13 +10:00
DRM_DEBUG ( " PCI: Gart Table: VRAM %08X mapped at %08lX \n " ,
2006-01-02 17:18:39 +11:00
bus_address , ( unsigned long ) address ) ;
2005-04-16 15:20:36 -07:00
}
2005-09-25 14:28:13 +10:00
pci_gart = ( u32 * ) address ;
2005-04-16 15:20:36 -07:00
2005-09-25 14:28:13 +10:00
pages = ( entry - > pages < = ATI_MAX_PCIGART_PAGES )
? entry - > pages : ATI_MAX_PCIGART_PAGES ;
2005-04-16 15:20:36 -07:00
2005-09-25 14:28:13 +10:00
memset ( pci_gart , 0 , ATI_MAX_PCIGART_PAGES * sizeof ( u32 ) ) ;
2005-04-16 15:20:36 -07:00
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 */
entry - > busaddr [ i ] = pci_map_single ( dev - > pdev ,
2005-09-25 14:28:13 +10:00
page_address ( entry - >
pagelist [ i ] ) ,
PAGE_SIZE , PCI_DMA_TODEVICE ) ;
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 + + ) {
2005-09-11 20:28:11 +10:00
if ( gart_info - > is_pcie )
2005-11-08 21:34:31 -08:00
* pci_gart = cpu_to_le32 ( ( page_base > > 8 ) | 0xc ) ;
2005-09-11 20:28:11 +10:00
else
2005-09-30 19:12:46 +10:00
* pci_gart = cpu_to_le32 ( page_base ) ;
2005-11-08 21:34:31 -08:00
pci_gart + + ;
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 ;
}
2005-09-25 14:28:13 +10:00
2005-04-16 15:20:36 -07:00
EXPORT_SYMBOL ( drm_ati_pcigart_init ) ;