2011-11-16 19:36:37 +04:00
/*
* IOMMU API for GART in Tegra20
*
* Copyright ( c ) 2010 - 2012 , NVIDIA CORPORATION . All rights reserved .
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms and conditions of the GNU General Public License ,
* version 2 , as published by the Free Software Foundation .
*
* This program is distributed in the hope it will be useful , but WITHOUT
* ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License for
* more details .
*
* You should have received a copy of the GNU General Public License along with
* this program ; if not , write to the Free Software Foundation , Inc . ,
* 51 Franklin St - Fifth Floor , Boston , MA 02110 - 1301 USA .
*/
# define pr_fmt(fmt) "%s(): " fmt, __func__
# include <linux/module.h>
# include <linux/platform_device.h>
# include <linux/spinlock.h>
# include <linux/slab.h>
# include <linux/vmalloc.h>
# include <linux/mm.h>
# include <linux/list.h>
# include <linux/device.h>
# include <linux/io.h>
# include <linux/iommu.h>
2012-04-13 17:08:08 +04:00
# include <linux/of.h>
2011-11-16 19:36:37 +04:00
# include <asm/cacheflush.h>
/* bitmap of the page sizes currently supported */
# define GART_IOMMU_PGSIZES (SZ_4K)
2012-05-10 11:45:32 +04:00
# define GART_REG_BASE 0x24
# define GART_CONFIG (0x24 - GART_REG_BASE)
# define GART_ENTRY_ADDR (0x28 - GART_REG_BASE)
# define GART_ENTRY_DATA (0x2c - GART_REG_BASE)
2011-11-16 19:36:37 +04:00
# define GART_ENTRY_PHYS_ADDR_VALID (1 << 31)
# define GART_PAGE_SHIFT 12
# define GART_PAGE_SIZE (1 << GART_PAGE_SHIFT)
# define GART_PAGE_MASK \
( ~ ( GART_PAGE_SIZE - 1 ) & ~ GART_ENTRY_PHYS_ADDR_VALID )
struct gart_client {
struct device * dev ;
struct list_head list ;
} ;
struct gart_device {
void __iomem * regs ;
u32 * savedata ;
u32 page_count ; /* total remappable size */
dma_addr_t iovmm_base ; /* offset to vmm_area */
spinlock_t pte_lock ; /* for pagetable */
struct list_head client ;
spinlock_t client_lock ; /* for client list */
struct device * dev ;
2017-08-10 01:17:28 +03:00
struct iommu_device iommu ; /* IOMMU Core handle */
2011-11-16 19:36:37 +04:00
} ;
2015-03-26 15:43:13 +03:00
struct gart_domain {
struct iommu_domain domain ; /* generic domain handle */
struct gart_device * gart ; /* link to gart device */
} ;
2011-11-16 19:36:37 +04:00
static struct gart_device * gart_handle ; /* unique for a system */
2018-04-09 23:07:19 +03:00
static bool gart_debug ;
2011-11-16 19:36:37 +04:00
# define GART_PTE(_pfn) \
( GART_ENTRY_PHYS_ADDR_VALID | ( ( _pfn ) < < PAGE_SHIFT ) )
2015-03-26 15:43:13 +03:00
static struct gart_domain * to_gart_domain ( struct iommu_domain * dom )
{
return container_of ( dom , struct gart_domain , domain ) ;
}
2011-11-16 19:36:37 +04:00
/*
* Any interaction between any block on PPSB and a block on APB or AHB
* must have these read - back to ensure the APB / AHB bus transaction is
* complete before initiating activity on the PPSB block .
*/
# define FLUSH_GART_REGS(gart) ((void)readl((gart)->regs + GART_CONFIG))
# define for_each_gart_pte(gart, iova) \
for ( iova = gart - > iovmm_base ; \
iova < gart - > iovmm_base + GART_PAGE_SIZE * gart - > page_count ; \
iova + = GART_PAGE_SIZE )
static inline void gart_set_pte ( struct gart_device * gart ,
unsigned long offs , u32 pte )
{
writel ( offs , gart - > regs + GART_ENTRY_ADDR ) ;
writel ( pte , gart - > regs + GART_ENTRY_DATA ) ;
dev_dbg ( gart - > dev , " %s %08lx:%08x \n " ,
pte ? " map " : " unmap " , offs , pte & GART_PAGE_MASK ) ;
}
static inline unsigned long gart_read_pte ( struct gart_device * gart ,
unsigned long offs )
{
unsigned long pte ;
writel ( offs , gart - > regs + GART_ENTRY_ADDR ) ;
pte = readl ( gart - > regs + GART_ENTRY_DATA ) ;
return pte ;
}
static void do_gart_setup ( struct gart_device * gart , const u32 * data )
{
unsigned long iova ;
for_each_gart_pte ( gart , iova )
gart_set_pte ( gart , iova , data ? * ( data + + ) : 0 ) ;
writel ( 1 , gart - > regs + GART_CONFIG ) ;
FLUSH_GART_REGS ( gart ) ;
}
# ifdef DEBUG
static void gart_dump_table ( struct gart_device * gart )
{
unsigned long iova ;
unsigned long flags ;
spin_lock_irqsave ( & gart - > pte_lock , flags ) ;
for_each_gart_pte ( gart , iova ) {
unsigned long pte ;
pte = gart_read_pte ( gart , iova ) ;
dev_dbg ( gart - > dev , " %s %08lx:%08lx \n " ,
( GART_ENTRY_PHYS_ADDR_VALID & pte ) ? " v " : " " ,
iova , pte & GART_PAGE_MASK ) ;
}
spin_unlock_irqrestore ( & gart - > pte_lock , flags ) ;
}
# else
static inline void gart_dump_table ( struct gart_device * gart )
{
}
# endif
static inline bool gart_iova_range_valid ( struct gart_device * gart ,
unsigned long iova , size_t bytes )
{
unsigned long iova_start , iova_end , gart_start , gart_end ;
iova_start = iova ;
iova_end = iova_start + bytes - 1 ;
gart_start = gart - > iovmm_base ;
gart_end = gart_start + gart - > page_count * GART_PAGE_SIZE - 1 ;
if ( iova_start < gart_start )
return false ;
if ( iova_end > gart_end )
return false ;
return true ;
}
static int gart_iommu_attach_dev ( struct iommu_domain * domain ,
struct device * dev )
{
2015-03-26 15:43:13 +03:00
struct gart_domain * gart_domain = to_gart_domain ( domain ) ;
2015-04-02 14:33:19 +03:00
struct gart_device * gart = gart_domain - > gart ;
2011-11-16 19:36:37 +04:00
struct gart_client * client , * c ;
int err = 0 ;
client = devm_kzalloc ( gart - > dev , sizeof ( * c ) , GFP_KERNEL ) ;
if ( ! client )
return - ENOMEM ;
client - > dev = dev ;
spin_lock ( & gart - > client_lock ) ;
list_for_each_entry ( c , & gart - > client , list ) {
if ( c - > dev = = dev ) {
dev_err ( gart - > dev ,
" %s is already attached \n " , dev_name ( dev ) ) ;
err = - EINVAL ;
goto fail ;
}
}
list_add ( & client - > list , & gart - > client ) ;
spin_unlock ( & gart - > client_lock ) ;
dev_dbg ( gart - > dev , " Attached %s \n " , dev_name ( dev ) ) ;
return 0 ;
fail :
devm_kfree ( gart - > dev , client ) ;
spin_unlock ( & gart - > client_lock ) ;
return err ;
}
static void gart_iommu_detach_dev ( struct iommu_domain * domain ,
struct device * dev )
{
2015-03-26 15:43:13 +03:00
struct gart_domain * gart_domain = to_gart_domain ( domain ) ;
struct gart_device * gart = gart_domain - > gart ;
2011-11-16 19:36:37 +04:00
struct gart_client * c ;
spin_lock ( & gart - > client_lock ) ;
list_for_each_entry ( c , & gart - > client , list ) {
if ( c - > dev = = dev ) {
list_del ( & c - > list ) ;
devm_kfree ( gart - > dev , c ) ;
dev_dbg ( gart - > dev , " Detached %s \n " , dev_name ( dev ) ) ;
goto out ;
}
}
dev_err ( gart - > dev , " Couldn't find \n " ) ;
out :
spin_unlock ( & gart - > client_lock ) ;
}
2015-03-26 15:43:13 +03:00
static struct iommu_domain * gart_iommu_domain_alloc ( unsigned type )
2011-11-16 19:36:37 +04:00
{
2015-03-26 15:43:13 +03:00
struct gart_domain * gart_domain ;
2015-03-27 13:07:26 +03:00
struct gart_device * gart ;
2011-11-16 19:36:37 +04:00
2015-03-26 15:43:13 +03:00
if ( type ! = IOMMU_DOMAIN_UNMANAGED )
return NULL ;
2011-11-16 19:36:37 +04:00
2015-03-27 13:07:26 +03:00
gart = gart_handle ;
2011-11-16 19:36:37 +04:00
if ( ! gart )
2015-04-02 14:33:19 +03:00
return NULL ;
2011-11-16 19:36:37 +04:00
2015-03-26 15:43:13 +03:00
gart_domain = kzalloc ( sizeof ( * gart_domain ) , GFP_KERNEL ) ;
if ( ! gart_domain )
return NULL ;
2015-03-27 13:07:26 +03:00
2015-04-02 14:33:19 +03:00
gart_domain - > gart = gart ;
gart_domain - > domain . geometry . aperture_start = gart - > iovmm_base ;
gart_domain - > domain . geometry . aperture_end = gart - > iovmm_base +
2015-03-27 13:07:26 +03:00
gart - > page_count * GART_PAGE_SIZE - 1 ;
2015-04-02 14:33:19 +03:00
gart_domain - > domain . geometry . force_aperture = true ;
2015-03-27 13:07:26 +03:00
2015-03-26 15:43:13 +03:00
return & gart_domain - > domain ;
2011-11-16 19:36:37 +04:00
}
2015-03-26 15:43:13 +03:00
static void gart_iommu_domain_free ( struct iommu_domain * domain )
2011-11-16 19:36:37 +04:00
{
2015-03-26 15:43:13 +03:00
struct gart_domain * gart_domain = to_gart_domain ( domain ) ;
struct gart_device * gart = gart_domain - > gart ;
2011-11-16 19:36:37 +04:00
2015-03-26 15:43:13 +03:00
if ( gart ) {
spin_lock ( & gart - > client_lock ) ;
if ( ! list_empty ( & gart - > client ) ) {
struct gart_client * c ;
2011-11-16 19:36:37 +04:00
2015-03-26 15:43:13 +03:00
list_for_each_entry ( c , & gart - > client , list )
gart_iommu_detach_dev ( domain , c - > dev ) ;
}
spin_unlock ( & gart - > client_lock ) ;
2011-11-16 19:36:37 +04:00
}
2015-03-26 15:43:13 +03:00
kfree ( gart_domain ) ;
2011-11-16 19:36:37 +04:00
}
static int gart_iommu_map ( struct iommu_domain * domain , unsigned long iova ,
phys_addr_t pa , size_t bytes , int prot )
{
2015-03-26 15:43:13 +03:00
struct gart_domain * gart_domain = to_gart_domain ( domain ) ;
struct gart_device * gart = gart_domain - > gart ;
2011-11-16 19:36:37 +04:00
unsigned long flags ;
unsigned long pfn ;
2018-04-09 23:07:19 +03:00
unsigned long pte ;
2011-11-16 19:36:37 +04:00
if ( ! gart_iova_range_valid ( gart , iova , bytes ) )
return - EINVAL ;
spin_lock_irqsave ( & gart - > pte_lock , flags ) ;
pfn = __phys_to_pfn ( pa ) ;
if ( ! pfn_valid ( pfn ) ) {
2013-09-17 12:19:31 +04:00
dev_err ( gart - > dev , " Invalid page: %pa \n " , & pa ) ;
2012-03-12 23:15:01 +04:00
spin_unlock_irqrestore ( & gart - > pte_lock , flags ) ;
2011-11-16 19:36:37 +04:00
return - EINVAL ;
}
2018-04-09 23:07:19 +03:00
if ( gart_debug ) {
pte = gart_read_pte ( gart , iova ) ;
if ( pte & GART_ENTRY_PHYS_ADDR_VALID ) {
spin_unlock_irqrestore ( & gart - > pte_lock , flags ) ;
dev_err ( gart - > dev , " Page entry is in-use \n " ) ;
return - EBUSY ;
}
}
2011-11-16 19:36:37 +04:00
gart_set_pte ( gart , iova , GART_PTE ( pfn ) ) ;
FLUSH_GART_REGS ( gart ) ;
spin_unlock_irqrestore ( & gart - > pte_lock , flags ) ;
return 0 ;
}
static size_t gart_iommu_unmap ( struct iommu_domain * domain , unsigned long iova ,
size_t bytes )
{
2015-03-26 15:43:13 +03:00
struct gart_domain * gart_domain = to_gart_domain ( domain ) ;
struct gart_device * gart = gart_domain - > gart ;
2011-11-16 19:36:37 +04:00
unsigned long flags ;
if ( ! gart_iova_range_valid ( gart , iova , bytes ) )
return 0 ;
spin_lock_irqsave ( & gart - > pte_lock , flags ) ;
gart_set_pte ( gart , iova , 0 ) ;
FLUSH_GART_REGS ( gart ) ;
spin_unlock_irqrestore ( & gart - > pte_lock , flags ) ;
2018-04-09 23:07:20 +03:00
return bytes ;
2011-11-16 19:36:37 +04:00
}
static phys_addr_t gart_iommu_iova_to_phys ( struct iommu_domain * domain ,
2013-03-28 23:53:58 +04:00
dma_addr_t iova )
2011-11-16 19:36:37 +04:00
{
2015-03-26 15:43:13 +03:00
struct gart_domain * gart_domain = to_gart_domain ( domain ) ;
struct gart_device * gart = gart_domain - > gart ;
2011-11-16 19:36:37 +04:00
unsigned long pte ;
phys_addr_t pa ;
unsigned long flags ;
if ( ! gart_iova_range_valid ( gart , iova , 0 ) )
return - EINVAL ;
spin_lock_irqsave ( & gart - > pte_lock , flags ) ;
pte = gart_read_pte ( gart , iova ) ;
spin_unlock_irqrestore ( & gart - > pte_lock , flags ) ;
pa = ( pte & GART_PAGE_MASK ) ;
if ( ! pfn_valid ( __phys_to_pfn ( pa ) ) ) {
2013-09-17 12:19:31 +04:00
dev_err ( gart - > dev , " No entry for %08llx:%pa \n " ,
( unsigned long long ) iova , & pa ) ;
2011-11-16 19:36:37 +04:00
gart_dump_table ( gart ) ;
return - EINVAL ;
}
return pa ;
}
2014-09-05 12:51:37 +04:00
static bool gart_iommu_capable ( enum iommu_cap cap )
2011-11-16 19:36:37 +04:00
{
2014-09-05 12:51:37 +04:00
return false ;
2011-11-16 19:36:37 +04:00
}
2017-07-21 15:12:37 +03:00
static int gart_iommu_add_device ( struct device * dev )
{
struct iommu_group * group = iommu_group_get_for_dev ( dev ) ;
if ( IS_ERR ( group ) )
return PTR_ERR ( group ) ;
iommu_group_put ( group ) ;
2017-08-10 01:17:28 +03:00
iommu_device_link ( & gart_handle - > iommu , dev ) ;
2017-07-21 15:12:37 +03:00
return 0 ;
}
static void gart_iommu_remove_device ( struct device * dev )
{
iommu_group_remove_device ( dev ) ;
2017-08-10 01:17:28 +03:00
iommu_device_unlink ( & gart_handle - > iommu , dev ) ;
2017-07-21 15:12:37 +03:00
}
2014-06-27 11:03:12 +04:00
static const struct iommu_ops gart_iommu_ops = {
2014-09-05 12:51:37 +04:00
. capable = gart_iommu_capable ,
2015-03-26 15:43:13 +03:00
. domain_alloc = gart_iommu_domain_alloc ,
. domain_free = gart_iommu_domain_free ,
2011-11-16 19:36:37 +04:00
. attach_dev = gart_iommu_attach_dev ,
. detach_dev = gart_iommu_detach_dev ,
2017-07-21 15:12:37 +03:00
. add_device = gart_iommu_add_device ,
. remove_device = gart_iommu_remove_device ,
. device_group = generic_device_group ,
2011-11-16 19:36:37 +04:00
. map = gart_iommu_map ,
. unmap = gart_iommu_unmap ,
. iova_to_phys = gart_iommu_iova_to_phys ,
. pgsize_bitmap = GART_IOMMU_PGSIZES ,
} ;
static int tegra_gart_suspend ( struct device * dev )
{
struct gart_device * gart = dev_get_drvdata ( dev ) ;
unsigned long iova ;
u32 * data = gart - > savedata ;
unsigned long flags ;
spin_lock_irqsave ( & gart - > pte_lock , flags ) ;
for_each_gart_pte ( gart , iova )
* ( data + + ) = gart_read_pte ( gart , iova ) ;
spin_unlock_irqrestore ( & gart - > pte_lock , flags ) ;
return 0 ;
}
static int tegra_gart_resume ( struct device * dev )
{
struct gart_device * gart = dev_get_drvdata ( dev ) ;
unsigned long flags ;
spin_lock_irqsave ( & gart - > pte_lock , flags ) ;
do_gart_setup ( gart , gart - > savedata ) ;
spin_unlock_irqrestore ( & gart - > pte_lock , flags ) ;
return 0 ;
}
static int tegra_gart_probe ( struct platform_device * pdev )
{
struct gart_device * gart ;
struct resource * res , * res_remap ;
void __iomem * gart_regs ;
struct device * dev = & pdev - > dev ;
2017-08-10 01:17:28 +03:00
int ret ;
2011-11-16 19:36:37 +04:00
if ( gart_handle )
return - EIO ;
BUILD_BUG_ON ( PAGE_SHIFT ! = GART_PAGE_SHIFT ) ;
/* the GART memory aperture is required */
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
res_remap = platform_get_resource ( pdev , IORESOURCE_MEM , 1 ) ;
if ( ! res | | ! res_remap ) {
dev_err ( dev , " GART memory aperture expected \n " ) ;
return - ENXIO ;
}
gart = devm_kzalloc ( dev , sizeof ( * gart ) , GFP_KERNEL ) ;
if ( ! gart ) {
dev_err ( dev , " failed to allocate gart_device \n " ) ;
return - ENOMEM ;
}
gart_regs = devm_ioremap ( dev , res - > start , resource_size ( res ) ) ;
if ( ! gart_regs ) {
dev_err ( dev , " failed to remap GART registers \n " ) ;
2013-09-24 07:40:24 +04:00
return - ENXIO ;
2011-11-16 19:36:37 +04:00
}
2017-08-10 01:17:28 +03:00
ret = iommu_device_sysfs_add ( & gart - > iommu , & pdev - > dev , NULL ,
dev_name ( & pdev - > dev ) ) ;
if ( ret ) {
dev_err ( dev , " Failed to register IOMMU in sysfs \n " ) ;
return ret ;
}
iommu_device_set_ops ( & gart - > iommu , & gart_iommu_ops ) ;
ret = iommu_device_register ( & gart - > iommu ) ;
if ( ret ) {
dev_err ( dev , " Failed to register IOMMU \n " ) ;
iommu_device_sysfs_remove ( & gart - > iommu ) ;
return ret ;
}
2011-11-16 19:36:37 +04:00
gart - > dev = & pdev - > dev ;
spin_lock_init ( & gart - > pte_lock ) ;
spin_lock_init ( & gart - > client_lock ) ;
INIT_LIST_HEAD ( & gart - > client ) ;
gart - > regs = gart_regs ;
gart - > iovmm_base = ( dma_addr_t ) res_remap - > start ;
gart - > page_count = ( resource_size ( res_remap ) > > GART_PAGE_SHIFT ) ;
treewide: Use array_size() in vmalloc()
The vmalloc() function has no 2-factor argument form, so multiplication
factors need to be wrapped in array_size(). This patch replaces cases of:
vmalloc(a * b)
with:
vmalloc(array_size(a, b))
as well as handling cases of:
vmalloc(a * b * c)
with:
vmalloc(array3_size(a, b, c))
This does, however, attempt to ignore constant size factors like:
vmalloc(4 * 1024)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
type TYPE;
expression THING, E;
@@
(
vmalloc(
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
vmalloc(
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression COUNT;
typedef u8;
typedef __u8;
@@
(
vmalloc(
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
vmalloc(
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
vmalloc(
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
vmalloc(
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
vmalloc(
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
vmalloc(
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
vmalloc(
- sizeof(char) * COUNT
+ COUNT
, ...)
|
vmalloc(
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
vmalloc(
- sizeof(TYPE) * (COUNT_ID)
+ array_size(COUNT_ID, sizeof(TYPE))
, ...)
|
vmalloc(
- sizeof(TYPE) * COUNT_ID
+ array_size(COUNT_ID, sizeof(TYPE))
, ...)
|
vmalloc(
- sizeof(TYPE) * (COUNT_CONST)
+ array_size(COUNT_CONST, sizeof(TYPE))
, ...)
|
vmalloc(
- sizeof(TYPE) * COUNT_CONST
+ array_size(COUNT_CONST, sizeof(TYPE))
, ...)
|
vmalloc(
- sizeof(THING) * (COUNT_ID)
+ array_size(COUNT_ID, sizeof(THING))
, ...)
|
vmalloc(
- sizeof(THING) * COUNT_ID
+ array_size(COUNT_ID, sizeof(THING))
, ...)
|
vmalloc(
- sizeof(THING) * (COUNT_CONST)
+ array_size(COUNT_CONST, sizeof(THING))
, ...)
|
vmalloc(
- sizeof(THING) * COUNT_CONST
+ array_size(COUNT_CONST, sizeof(THING))
, ...)
)
// 2-factor product, only identifiers.
@@
identifier SIZE, COUNT;
@@
vmalloc(
- SIZE * COUNT
+ array_size(COUNT, SIZE)
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
vmalloc(
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
vmalloc(
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
vmalloc(
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
vmalloc(
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
vmalloc(
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
vmalloc(
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
vmalloc(
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
vmalloc(
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
vmalloc(
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
vmalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
vmalloc(
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
vmalloc(
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
vmalloc(
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
vmalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
identifier STRIDE, SIZE, COUNT;
@@
(
vmalloc(
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vmalloc(
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vmalloc(
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vmalloc(
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vmalloc(
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vmalloc(
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vmalloc(
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vmalloc(
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products
// when they're not all constants...
@@
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
vmalloc(C1 * C2 * C3, ...)
|
vmalloc(
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants.
@@
expression E1, E2;
constant C1, C2;
@@
(
vmalloc(C1 * C2, ...)
|
vmalloc(
- E1 * E2
+ array_size(E1, E2)
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-13 00:27:11 +03:00
gart - > savedata = vmalloc ( array_size ( sizeof ( u32 ) , gart - > page_count ) ) ;
2011-11-16 19:36:37 +04:00
if ( ! gart - > savedata ) {
dev_err ( dev , " failed to allocate context save area \n " ) ;
2013-09-24 07:40:24 +04:00
return - ENOMEM ;
2011-11-16 19:36:37 +04:00
}
platform_set_drvdata ( pdev , gart ) ;
do_gart_setup ( gart , NULL ) ;
gart_handle = gart ;
2015-01-23 18:37:51 +03:00
2011-11-16 19:36:37 +04:00
return 0 ;
}
static int tegra_gart_remove ( struct platform_device * pdev )
{
struct gart_device * gart = platform_get_drvdata ( pdev ) ;
2017-08-10 01:17:28 +03:00
iommu_device_unregister ( & gart - > iommu ) ;
iommu_device_sysfs_remove ( & gart - > iommu ) ;
2011-11-16 19:36:37 +04:00
writel ( 0 , gart - > regs + GART_CONFIG ) ;
if ( gart - > savedata )
vfree ( gart - > savedata ) ;
gart_handle = NULL ;
return 0 ;
}
2013-10-08 14:51:03 +04:00
static const struct dev_pm_ops tegra_gart_pm_ops = {
2011-11-16 19:36:37 +04:00
. suspend = tegra_gart_suspend ,
. resume = tegra_gart_resume ,
} ;
2014-09-11 17:37:36 +04:00
static const struct of_device_id tegra_gart_of_match [ ] = {
2012-04-13 17:08:08 +04:00
{ . compatible = " nvidia,tegra20-gart " , } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , tegra_gart_of_match ) ;
2011-11-16 19:36:37 +04:00
static struct platform_driver tegra_gart_driver = {
. probe = tegra_gart_probe ,
. remove = tegra_gart_remove ,
. driver = {
. name = " tegra-gart " ,
. pm = & tegra_gart_pm_ops ,
2013-02-16 02:01:06 +04:00
. of_match_table = tegra_gart_of_match ,
2011-11-16 19:36:37 +04:00
} ,
} ;
2012-12-22 03:05:21 +04:00
static int tegra_gart_init ( void )
2011-11-16 19:36:37 +04:00
{
return platform_driver_register ( & tegra_gart_driver ) ;
}
static void __exit tegra_gart_exit ( void )
{
platform_driver_unregister ( & tegra_gart_driver ) ;
}
subsys_initcall ( tegra_gart_init ) ;
module_exit ( tegra_gart_exit ) ;
2018-04-09 23:07:19 +03:00
module_param ( gart_debug , bool , 0644 ) ;
2011-11-16 19:36:37 +04:00
2018-04-09 23:07:19 +03:00
MODULE_PARM_DESC ( gart_debug , " Enable GART debugging " ) ;
2011-11-16 19:36:37 +04:00
MODULE_DESCRIPTION ( " IOMMU API for GART in Tegra20 " ) ;
MODULE_AUTHOR ( " Hiroshi DOYU <hdoyu@nvidia.com> " ) ;
2012-04-13 17:08:08 +04:00
MODULE_ALIAS ( " platform:tegra-gart " ) ;
2011-11-16 19:36:37 +04:00
MODULE_LICENSE ( " GPL v2 " ) ;