2011-03-05 02:00:17 +03:00
/*
* Programmable Real - Time Unit Sub System ( PRUSS ) UIO driver ( uio_pruss )
*
* This driver exports PRUSS host event out interrupts and PRUSS , L3 RAM ,
* and DDR RAM to user space for applications interacting with PRUSS firmware
*
* Copyright ( C ) 2010 - 11 Texas Instruments Incorporated - http : //www.ti.com/
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation version 2.
*
* This program is distributed " as is " WITHOUT ANY WARRANTY of any
* kind , whether express or implied ; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*/
# include <linux/device.h>
# include <linux/module.h>
# include <linux/moduleparam.h>
# include <linux/platform_device.h>
# include <linux/uio_driver.h>
# include <linux/platform_data/uio_pruss.h>
# include <linux/io.h>
# include <linux/clk.h>
# include <linux/dma-mapping.h>
2015-06-10 20:00:19 +03:00
# include <linux/sizes.h>
2011-03-05 02:00:17 +03:00
# include <linux/slab.h>
2012-10-05 21:04:40 +04:00
# include <linux/genalloc.h>
2011-03-05 02:00:17 +03:00
# define DRV_NAME "pruss_uio"
# define DRV_VERSION "1.0"
static int sram_pool_sz = SZ_16K ;
module_param ( sram_pool_sz , int , 0 ) ;
MODULE_PARM_DESC ( sram_pool_sz , " sram pool size to allocate " ) ;
static int extram_pool_sz = SZ_256K ;
module_param ( extram_pool_sz , int , 0 ) ;
MODULE_PARM_DESC ( extram_pool_sz , " external ram pool size to allocate " ) ;
/*
2011-03-31 05:57:33 +04:00
* Host event IRQ numbers from PRUSS - PRUSS can generate up to 8 interrupt
2011-03-05 02:00:17 +03:00
* events to AINTC of ARM host processor - which can be used for IPC b / w PRUSS
* firmware and user space application , async notification from PRU firmware
* to user space application
* 3 PRU_EVTOUT0
* 4 PRU_EVTOUT1
* 5 PRU_EVTOUT2
* 6 PRU_EVTOUT3
* 7 PRU_EVTOUT4
* 8 PRU_EVTOUT5
* 9 PRU_EVTOUT6
* 10 PRU_EVTOUT7
*/
# define MAX_PRUSS_EVT 8
# define PINTC_HIDISR 0x0038
# define PINTC_HIPIR 0x0900
# define HIPIR_NOPEND 0x80000000
# define PINTC_HIER 0x1500
struct uio_pruss_dev {
struct uio_info * info ;
struct clk * pruss_clk ;
dma_addr_t sram_paddr ;
dma_addr_t ddr_paddr ;
void __iomem * prussio_vaddr ;
2012-10-05 21:04:40 +04:00
unsigned long sram_vaddr ;
2011-03-05 02:00:17 +03:00
void * ddr_vaddr ;
unsigned int hostirq_start ;
unsigned int pintc_base ;
2012-10-05 21:04:40 +04:00
struct gen_pool * sram_pool ;
2011-03-05 02:00:17 +03:00
} ;
static irqreturn_t pruss_handler ( int irq , struct uio_info * info )
{
struct uio_pruss_dev * gdev = info - > priv ;
int intr_bit = ( irq - gdev - > hostirq_start + 2 ) ;
int val , intr_mask = ( 1 < < intr_bit ) ;
void __iomem * base = gdev - > prussio_vaddr + gdev - > pintc_base ;
void __iomem * intren_reg = base + PINTC_HIER ;
void __iomem * intrdis_reg = base + PINTC_HIDISR ;
void __iomem * intrstat_reg = base + PINTC_HIPIR + ( intr_bit < < 2 ) ;
val = ioread32 ( intren_reg ) ;
/* Is interrupt enabled and active ? */
if ( ! ( val & intr_mask ) & & ( ioread32 ( intrstat_reg ) & HIPIR_NOPEND ) )
return IRQ_NONE ;
/* Disable interrupt */
iowrite32 ( intr_bit , intrdis_reg ) ;
return IRQ_HANDLED ;
}
2014-06-29 20:21:35 +04:00
static void pruss_cleanup ( struct device * dev , struct uio_pruss_dev * gdev )
2011-03-05 02:00:17 +03:00
{
int cnt ;
struct uio_info * p = gdev - > info ;
for ( cnt = 0 ; cnt < MAX_PRUSS_EVT ; cnt + + , p + + ) {
uio_unregister_device ( p ) ;
kfree ( p - > name ) ;
}
iounmap ( gdev - > prussio_vaddr ) ;
if ( gdev - > ddr_vaddr ) {
2014-06-29 20:21:35 +04:00
dma_free_coherent ( dev , extram_pool_sz , gdev - > ddr_vaddr ,
2011-03-05 02:00:17 +03:00
gdev - > ddr_paddr ) ;
}
if ( gdev - > sram_vaddr )
2012-10-05 21:04:40 +04:00
gen_pool_free ( gdev - > sram_pool ,
gdev - > sram_vaddr ,
sram_pool_sz ) ;
2011-03-05 02:00:17 +03:00
kfree ( gdev - > info ) ;
2016-11-26 00:55:30 +03:00
clk_disable ( gdev - > pruss_clk ) ;
2011-03-05 02:00:17 +03:00
clk_put ( gdev - > pruss_clk ) ;
kfree ( gdev ) ;
}
2014-06-29 20:21:35 +04:00
static int pruss_probe ( struct platform_device * pdev )
2011-03-05 02:00:17 +03:00
{
struct uio_info * p ;
struct uio_pruss_dev * gdev ;
struct resource * regs_prussio ;
2014-06-29 20:21:35 +04:00
struct device * dev = & pdev - > dev ;
2018-08-02 10:15:58 +03:00
int ret , cnt , i , len ;
2014-06-29 20:21:35 +04:00
struct uio_pruss_pdata * pdata = dev_get_platdata ( dev ) ;
2011-03-05 02:00:17 +03:00
gdev = kzalloc ( sizeof ( struct uio_pruss_dev ) , GFP_KERNEL ) ;
if ( ! gdev )
return - ENOMEM ;
treewide: kzalloc() -> kcalloc()
The kzalloc() function has a 2-factor argument form, kcalloc(). This
patch replaces cases of:
kzalloc(a * b, gfp)
with:
kcalloc(a * b, gfp)
as well as handling cases of:
kzalloc(a * b * c, gfp)
with:
kzalloc(array3_size(a, b, c), gfp)
as it's slightly less ugly than:
kzalloc_array(array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
kzalloc(4 * 1024, gfp)
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;
@@
(
kzalloc(
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
kzalloc(
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression COUNT;
typedef u8;
typedef __u8;
@@
(
kzalloc(
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(char) * COUNT
+ COUNT
, ...)
|
kzalloc(
- 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;
@@
(
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
identifier SIZE, COUNT;
@@
- kzalloc
+ kcalloc
(
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
kzalloc(
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- 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;
@@
(
kzalloc(
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kzalloc(
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
kzalloc(
- 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;
@@
(
kzalloc(
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- 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;
@@
(
kzalloc(C1 * C2 * C3, ...)
|
kzalloc(
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants,
// keeping sizeof() as the second factor argument.
@@
expression THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
kzalloc(sizeof(THING) * C2, ...)
|
kzalloc(sizeof(TYPE) * C2, ...)
|
kzalloc(C1 * C2 * C3, ...)
|
kzalloc(C1 * C2, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- (E1) * E2
+ E1, E2
, ...)
|
- kzalloc
+ kcalloc
(
- (E1) * (E2)
+ E1, E2
, ...)
|
- kzalloc
+ kcalloc
(
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-13 00:03:40 +03:00
gdev - > info = kcalloc ( MAX_PRUSS_EVT , sizeof ( * p ) , GFP_KERNEL ) ;
2011-03-05 02:00:17 +03:00
if ( ! gdev - > info ) {
2018-08-02 10:15:58 +03:00
ret = - ENOMEM ;
goto err_free_gdev ;
2011-03-05 02:00:17 +03:00
}
2014-06-29 20:21:35 +04:00
2011-03-05 02:00:17 +03:00
/* Power on PRU in case its not done as part of boot-loader */
2014-06-29 20:21:35 +04:00
gdev - > pruss_clk = clk_get ( dev , " pruss " ) ;
2011-03-05 02:00:17 +03:00
if ( IS_ERR ( gdev - > pruss_clk ) ) {
2014-06-29 20:21:35 +04:00
dev_err ( dev , " Failed to get clock \n " ) ;
2013-06-06 17:55:28 +04:00
ret = PTR_ERR ( gdev - > pruss_clk ) ;
2018-08-02 10:15:58 +03:00
goto err_free_info ;
}
ret = clk_enable ( gdev - > pruss_clk ) ;
if ( ret ) {
dev_err ( dev , " Failed to enable clock \n " ) ;
goto err_clk_put ;
2011-03-05 02:00:17 +03:00
}
2014-06-29 20:21:35 +04:00
regs_prussio = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
2011-03-05 02:00:17 +03:00
if ( ! regs_prussio ) {
2014-06-29 20:21:35 +04:00
dev_err ( dev , " No PRUSS I/O resource specified \n " ) ;
2018-08-02 10:15:58 +03:00
ret = - EIO ;
goto err_clk_disable ;
2011-03-05 02:00:17 +03:00
}
if ( ! regs_prussio - > start ) {
2014-06-29 20:21:35 +04:00
dev_err ( dev , " Invalid memory resource \n " ) ;
2018-08-02 10:15:58 +03:00
ret = - EIO ;
goto err_clk_disable ;
2011-03-05 02:00:17 +03:00
}
2012-10-05 21:04:40 +04:00
if ( pdata - > sram_pool ) {
gdev - > sram_pool = pdata - > sram_pool ;
gdev - > sram_vaddr =
2013-11-13 03:09:57 +04:00
( unsigned long ) gen_pool_dma_alloc ( gdev - > sram_pool ,
sram_pool_sz , & gdev - > sram_paddr ) ;
2012-10-05 21:04:40 +04:00
if ( ! gdev - > sram_vaddr ) {
2014-06-29 20:21:35 +04:00
dev_err ( dev , " Could not allocate SRAM pool \n " ) ;
2018-08-02 10:15:58 +03:00
ret = - ENOMEM ;
goto err_clk_disable ;
2012-10-05 21:04:40 +04:00
}
2011-03-05 02:00:17 +03:00
}
2014-06-29 20:21:35 +04:00
gdev - > ddr_vaddr = dma_alloc_coherent ( dev , extram_pool_sz ,
2011-03-05 02:00:17 +03:00
& ( gdev - > ddr_paddr ) , GFP_KERNEL | GFP_DMA ) ;
if ( ! gdev - > ddr_vaddr ) {
2014-06-29 20:21:35 +04:00
dev_err ( dev , " Could not allocate external memory \n " ) ;
2018-08-02 10:15:58 +03:00
ret = - ENOMEM ;
goto err_free_sram ;
2011-03-05 02:00:17 +03:00
}
len = resource_size ( regs_prussio ) ;
gdev - > prussio_vaddr = ioremap ( regs_prussio - > start , len ) ;
if ( ! gdev - > prussio_vaddr ) {
2014-06-29 20:21:35 +04:00
dev_err ( dev , " Can't remap PRUSS I/O address range \n " ) ;
2018-08-02 10:15:58 +03:00
ret = - ENOMEM ;
goto err_free_ddr_vaddr ;
2011-03-05 02:00:17 +03:00
}
gdev - > pintc_base = pdata - > pintc_base ;
2014-06-29 20:21:35 +04:00
gdev - > hostirq_start = platform_get_irq ( pdev , 0 ) ;
2011-03-05 02:00:17 +03:00
for ( cnt = 0 , p = gdev - > info ; cnt < MAX_PRUSS_EVT ; cnt + + , p + + ) {
p - > mem [ 0 ] . addr = regs_prussio - > start ;
p - > mem [ 0 ] . size = resource_size ( regs_prussio ) ;
p - > mem [ 0 ] . memtype = UIO_MEM_PHYS ;
p - > mem [ 1 ] . addr = gdev - > sram_paddr ;
p - > mem [ 1 ] . size = sram_pool_sz ;
p - > mem [ 1 ] . memtype = UIO_MEM_PHYS ;
p - > mem [ 2 ] . addr = gdev - > ddr_paddr ;
p - > mem [ 2 ] . size = extram_pool_sz ;
p - > mem [ 2 ] . memtype = UIO_MEM_PHYS ;
p - > name = kasprintf ( GFP_KERNEL , " pruss_evt%d " , cnt ) ;
p - > version = DRV_VERSION ;
/* Register PRUSS IRQ lines */
p - > irq = gdev - > hostirq_start + cnt ;
p - > handler = pruss_handler ;
p - > priv = gdev ;
2014-06-29 20:21:35 +04:00
ret = uio_register_device ( dev , p ) ;
2018-08-02 10:15:58 +03:00
if ( ret < 0 ) {
kfree ( p - > name ) ;
goto err_unloop ;
}
2011-03-05 02:00:17 +03:00
}
2014-06-29 20:21:35 +04:00
platform_set_drvdata ( pdev , gdev ) ;
2011-03-05 02:00:17 +03:00
return 0 ;
2018-08-02 10:15:58 +03:00
err_unloop :
for ( i = 0 , p = gdev - > info ; i < cnt ; i + + , p + + ) {
uio_unregister_device ( p ) ;
kfree ( p - > name ) ;
}
iounmap ( gdev - > prussio_vaddr ) ;
err_free_ddr_vaddr :
dma_free_coherent ( dev , extram_pool_sz , gdev - > ddr_vaddr ,
gdev - > ddr_paddr ) ;
err_free_sram :
if ( pdata - > sram_pool )
gen_pool_free ( gdev - > sram_pool , gdev - > sram_vaddr , sram_pool_sz ) ;
err_clk_disable :
clk_disable ( gdev - > pruss_clk ) ;
err_clk_put :
clk_put ( gdev - > pruss_clk ) ;
err_free_info :
kfree ( gdev - > info ) ;
err_free_gdev :
kfree ( gdev ) ;
2011-03-05 02:00:17 +03:00
return ret ;
}
2012-11-19 22:26:19 +04:00
static int pruss_remove ( struct platform_device * dev )
2011-03-05 02:00:17 +03:00
{
struct uio_pruss_dev * gdev = platform_get_drvdata ( dev ) ;
2014-06-29 20:21:35 +04:00
pruss_cleanup ( & dev - > dev , gdev ) ;
2011-03-05 02:00:17 +03:00
return 0 ;
}
static struct platform_driver pruss_driver = {
. probe = pruss_probe ,
2012-11-19 22:21:07 +04:00
. remove = pruss_remove ,
2011-03-05 02:00:17 +03:00
. driver = {
. name = DRV_NAME ,
} ,
} ;
2011-11-26 11:18:55 +04:00
module_platform_driver ( pruss_driver ) ;
2011-03-05 02:00:17 +03:00
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_VERSION ( DRV_VERSION ) ;
MODULE_AUTHOR ( " Amit Chatterjee <amit.chatterjee@ti.com> " ) ;
MODULE_AUTHOR ( " Pratheesh Gangadhar <pratheesh@ti.com> " ) ;