2005-04-17 02:20:36 +04:00
/**
2005-09-25 08:28:13 +04:00
* \ file ati_pcigart . c
2005-04-17 02:20:36 +04: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 03:24:24 +03:00
static int drm_ati_alloc_pcigart_table ( struct drm_device * dev ,
struct drm_ati_pcigart_info * gart_info )
2005-04-17 02:20:36 +04:00
{
2008-03-17 03:24:24 +03:00
gart_info - > table_handle = drm_pci_alloc ( dev , gart_info - > table_size ,
PAGE_SIZE ,
gart_info - > table_mask ) ;
if ( gart_info - > table_handle = = NULL )
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
2008-03-17 03:24:24 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2008-03-17 03:24:24 +03:00
static void drm_ati_free_pcigart_table ( struct drm_device * dev ,
struct drm_ati_pcigart_info * gart_info )
2005-04-17 02:20:36 +04:00
{
2008-03-17 03:24:24 +03:00
drm_pci_free ( dev , gart_info - > table_handle ) ;
gart_info - > table_handle = NULL ;
2005-04-17 02:20:36 +04:00
}
2007-07-11 10:53:40 +04:00
int drm_ati_pcigart_cleanup ( struct drm_device * dev , struct drm_ati_pcigart_info * gart_info )
2005-04-17 02:20:36 +04:00
{
2007-07-11 10:53:40 +04:00
struct drm_sg_mem * entry = dev - > sg ;
2005-04-17 02:20:36 +04:00
unsigned long pages ;
int i ;
2008-03-17 03:24:24 +03:00
int max_pages ;
2005-04-17 02:20:36 +04:00
/* we need to support large memory configurations */
2005-09-25 08:28:13 +04:00
if ( ! entry ) {
DRM_ERROR ( " no scatter/gather memory! \n " ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2005-09-11 14:28:11 +04:00
if ( gart_info - > bus_addr ) {
2005-04-17 02:20:36 +04:00
2007-05-08 09:19:23 +04:00
max_pages = ( gart_info - > table_size / sizeof ( u32 ) ) ;
pages = ( entry - > pages < = max_pages )
? entry - > pages : max_pages ;
2005-04-17 02:20:36 +04:00
2005-09-25 08:28:13 +04:00
for ( i = 0 ; i < pages ; i + + ) {
if ( ! entry - > busaddr [ i ] )
break ;
2008-06-19 05:27:23 +04:00
pci_unmap_page ( dev - > pdev , entry - > busaddr [ i ] ,
2005-04-17 02:20:36 +04:00
PAGE_SIZE , PCI_DMA_TODEVICE ) ;
}
2005-09-25 08:28:13 +04:00
if ( gart_info - > gart_table_location = = DRM_ATI_GART_MAIN )
gart_info - > bus_addr = 0 ;
2005-04-17 02:20:36 +04:00
}
2008-03-17 03:24:24 +03: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-17 02:20:36 +04:00
}
return 1 ;
}
EXPORT_SYMBOL ( drm_ati_pcigart_cleanup ) ;
2007-07-11 10:53:40 +04:00
int drm_ati_pcigart_init ( struct drm_device * dev , struct drm_ati_pcigart_info * gart_info )
2005-04-17 02:20:36 +04:00
{
2007-07-11 10:53:40 +04:00
struct drm_sg_mem * entry = dev - > sg ;
2006-01-02 09:18:39 +03:00
void * address = NULL ;
2005-04-17 02:20:36 +04:00
unsigned long pages ;
2008-03-17 03:24:24 +03:00
u32 * pci_gart , page_base ;
dma_addr_t bus_address = 0 ;
2005-04-17 02:20:36 +04:00
int i , j , ret = 0 ;
2007-05-08 09:19:23 +04:00
int max_pages ;
2005-04-17 02:20:36 +04:00
2005-09-25 08:28:13 +04:00
if ( ! entry ) {
DRM_ERROR ( " no scatter/gather memory! \n " ) ;
2005-04-17 02:20:36 +04:00
goto done ;
}
2005-09-25 08:28:13 +04:00
if ( gart_info - > gart_table_location = = DRM_ATI_GART_MAIN ) {
2005-09-11 14:28:11 +04:00
DRM_DEBUG ( " PCI: no table in VRAM: using normal RAM \n " ) ;
2005-09-25 08:28:13 +04:00
2008-03-17 03:24:24 +03:00
ret = drm_ati_alloc_pcigart_table ( dev , gart_info ) ;
if ( ret ) {
2005-09-25 08:28:13 +04:00
DRM_ERROR ( " cannot allocate PCI GART page! \n " ) ;
2005-09-11 14:28:11 +04:00
goto done ;
}
2005-09-25 08:28:13 +04:00
2008-03-17 03:24:24 +03:00
address = gart_info - > table_handle - > vaddr ;
bus_address = gart_info - > table_handle - > busaddr ;
2005-09-25 08:28:13 +04:00
} else {
2005-09-11 14:28:11 +04:00
address = gart_info - > addr ;
bus_address = gart_info - > bus_addr ;
2008-03-29 00:15:49 +03:00
DRM_DEBUG ( " PCI: Gart Table: VRAM %08LX mapped at %08lX \n " ,
( unsigned long long ) bus_address ,
( unsigned long ) address ) ;
2005-04-17 02:20:36 +04:00
}
2005-09-25 08:28:13 +04:00
pci_gart = ( u32 * ) address ;
2005-04-17 02:20:36 +04:00
2007-05-08 09:19:23 +04:00
max_pages = ( gart_info - > table_size / sizeof ( u32 ) ) ;
pages = ( entry - > pages < = max_pages )
? entry - > pages : max_pages ;
2005-04-17 02:20:36 +04:00
2007-05-08 09:19:23 +04:00
memset ( pci_gart , 0 , max_pages * sizeof ( u32 ) ) ;
2005-04-17 02:20:36 +04:00
2005-09-25 08:28:13 +04:00
for ( i = 0 ; i < pages ; i + + ) {
2005-04-17 02:20:36 +04:00
/* we need to support large memory configurations */
2008-06-19 05:27:23 +04:00
entry - > busaddr [ i ] = pci_map_page ( dev - > pdev , entry - > pagelist [ i ] ,
0 , PAGE_SIZE , PCI_DMA_TODEVICE ) ;
2005-04-17 02:20:36 +04:00
if ( entry - > busaddr [ i ] = = 0 ) {
2005-09-25 08:28:13 +04:00
DRM_ERROR ( " unable to map PCIGART pages! \n " ) ;
2005-09-11 14:28:11 +04:00
drm_ati_pcigart_cleanup ( dev , gart_info ) ;
2006-01-02 09:18:39 +03:00
address = NULL ;
2005-04-17 02:20:36 +04:00
bus_address = 0 ;
goto done ;
}
page_base = ( u32 ) entry - > busaddr [ i ] ;
for ( j = 0 ; j < ( PAGE_SIZE / ATI_PCIGART_PAGE_SIZE ) ; j + + ) {
2007-05-08 09:19:23 +04:00
switch ( gart_info - > gart_reg_if ) {
case DRM_ATI_GART_IGP :
* pci_gart = cpu_to_le32 ( ( page_base ) | 0xc ) ;
break ;
case DRM_ATI_GART_PCIE :
2005-11-09 08:34:31 +03:00
* pci_gart = cpu_to_le32 ( ( page_base > > 8 ) | 0xc ) ;
2007-05-08 09:19:23 +04:00
break ;
default :
case DRM_ATI_GART_PCI :
2005-09-30 13:12:46 +04:00
* pci_gart = cpu_to_le32 ( page_base ) ;
2007-05-08 09:19:23 +04:00
break ;
}
2005-11-09 08:34:31 +03:00
pci_gart + + ;
2005-04-17 02:20:36 +04:00
page_base + = ATI_PCIGART_PAGE_SIZE ;
}
}
ret = 1 ;
# if defined(__i386__) || defined(__x86_64__)
wbinvd ( ) ;
# else
mb ( ) ;
# endif
2005-09-25 08:28:13 +04:00
done :
2005-09-11 14:28:11 +04:00
gart_info - > addr = address ;
2005-09-25 08:28:13 +04:00
gart_info - > bus_addr = bus_address ;
2005-04-17 02:20:36 +04:00
return ret ;
}
EXPORT_SYMBOL ( drm_ati_pcigart_init ) ;