2008-07-30 23:06:12 +04:00
/**************************************************************************
*
* Copyright ( c ) 2006 - 2007 Tungsten Graphics , Inc . , Cedar Park , TX . , USA
* 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 , 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 .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
* Authors : Thomas Hellström < thomas - at - tungstengraphics - dot - com >
*/
2011-08-31 02:16:33 +04:00
# include <linux/export.h>
2012-10-02 21:01:07 +04:00
# include <drm/drmP.h>
2008-07-30 23:06:12 +04:00
# if defined(CONFIG_X86)
2014-12-15 23:26:46 +03:00
# include <asm/smp.h>
2014-02-26 23:06:51 +04:00
/*
* clflushopt is an unordered instruction which needs fencing with mfence or
* sfence to avoid ordering issues . For drm_clflush_page this fencing happens
* in the caller .
*/
2008-07-30 23:06:12 +04:00
static void
drm_clflush_page ( struct page * page )
{
uint8_t * page_virtual ;
unsigned int i ;
2012-09-19 05:12:41 +04:00
const int size = boot_cpu_data . x86_clflush_size ;
2008-07-30 23:06:12 +04:00
if ( unlikely ( page = = NULL ) )
return ;
2011-11-25 19:14:20 +04:00
page_virtual = kmap_atomic ( page ) ;
2012-09-19 05:12:41 +04:00
for ( i = 0 ; i < PAGE_SIZE ; i + = size )
2014-02-26 23:06:51 +04:00
clflushopt ( page_virtual + i ) ;
2011-11-25 19:14:20 +04:00
kunmap_atomic ( page_virtual ) ;
2008-07-30 23:06:12 +04:00
}
2009-08-27 03:53:47 +04:00
static void drm_cache_flush_clflush ( struct page * pages [ ] ,
unsigned long num_pages )
{
unsigned long i ;
mb ( ) ;
for ( i = 0 ; i < num_pages ; i + + )
drm_clflush_page ( * pages + + ) ;
mb ( ) ;
}
# endif
2009-09-02 03:41:13 +04:00
2008-07-30 23:06:12 +04:00
void
drm_clflush_pages ( struct page * pages [ ] , unsigned long num_pages )
{
# if defined(CONFIG_X86)
if ( cpu_has_clflush ) {
2009-08-27 03:53:47 +04:00
drm_cache_flush_clflush ( pages , num_pages ) ;
2008-07-30 23:06:12 +04:00
return ;
}
2014-12-15 23:26:46 +03:00
if ( wbinvd_on_all_cpus ( ) )
2009-08-27 03:53:47 +04:00
printk ( KERN_ERR " Timed out waiting for cache flush. \n " ) ;
# elif defined(__powerpc__)
unsigned long i ;
for ( i = 0 ; i < num_pages ; i + + ) {
struct page * page = pages [ i ] ;
void * page_virtual ;
if ( unlikely ( page = = NULL ) )
continue ;
2011-11-25 19:14:20 +04:00
page_virtual = kmap_atomic ( page ) ;
2009-08-27 03:53:47 +04:00
flush_dcache_range ( ( unsigned long ) page_virtual ,
( unsigned long ) page_virtual + PAGE_SIZE ) ;
2011-11-25 19:14:20 +04:00
kunmap_atomic ( page_virtual ) ;
2009-08-27 03:53:47 +04:00
}
# else
2009-09-02 03:41:13 +04:00
printk ( KERN_ERR " Architecture has no drm_cache.c support \n " ) ;
WARN_ON_ONCE ( 1 ) ;
2008-10-07 07:41:49 +04:00
# endif
2008-07-30 23:06:12 +04:00
}
EXPORT_SYMBOL ( drm_clflush_pages ) ;
2012-03-25 21:47:30 +04:00
2012-06-01 18:20:22 +04:00
void
drm_clflush_sg ( struct sg_table * st )
{
# if defined(CONFIG_X86)
if ( cpu_has_clflush ) {
2013-02-18 21:28:01 +04:00
struct sg_page_iter sg_iter ;
2012-06-01 18:20:22 +04:00
mb ( ) ;
2013-02-18 21:28:01 +04:00
for_each_sg_page ( st - > sgl , & sg_iter , st - > nents , 0 )
2013-03-26 17:14:18 +04:00
drm_clflush_page ( sg_page_iter_page ( & sg_iter ) ) ;
2012-06-01 18:20:22 +04:00
mb ( ) ;
return ;
}
2014-12-15 23:26:46 +03:00
if ( wbinvd_on_all_cpus ( ) )
2012-06-01 18:20:22 +04:00
printk ( KERN_ERR " Timed out waiting for cache flush. \n " ) ;
# else
printk ( KERN_ERR " Architecture has no drm_cache.c support \n " ) ;
WARN_ON_ONCE ( 1 ) ;
# endif
}
EXPORT_SYMBOL ( drm_clflush_sg ) ;
2012-03-25 21:47:30 +04:00
void
2014-04-01 13:59:08 +04:00
drm_clflush_virt_range ( void * addr , unsigned long length )
2012-03-25 21:47:30 +04:00
{
# if defined(CONFIG_X86)
if ( cpu_has_clflush ) {
2015-06-10 17:58:01 +03:00
const int size = boot_cpu_data . x86_clflush_size ;
2014-04-01 13:59:08 +04:00
void * end = addr + length ;
2015-06-10 17:58:01 +03:00
addr = ( void * ) ( ( ( unsigned long ) addr ) & - size ) ;
2012-03-25 21:47:30 +04:00
mb ( ) ;
2015-06-10 17:58:01 +03:00
for ( ; addr < end ; addr + = size )
2014-05-14 19:41:12 +04:00
clflushopt ( addr ) ;
2012-03-25 21:47:30 +04:00
mb ( ) ;
return ;
}
2014-12-15 23:26:46 +03:00
if ( wbinvd_on_all_cpus ( ) )
2012-03-25 21:47:30 +04:00
printk ( KERN_ERR " Timed out waiting for cache flush. \n " ) ;
# else
printk ( KERN_ERR " Architecture has no drm_cache.c support \n " ) ;
WARN_ON_ONCE ( 1 ) ;
# endif
}
EXPORT_SYMBOL ( drm_clflush_virt_range ) ;