2017-06-21 16:29:14 +03:00
/*
* Copyright ( C ) 2017 Marvell
*
* Thomas Petazzoni < thomas . petazzoni @ free - electrons . com >
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed " as is " without any
* warranty of any kind , whether express or implied .
*/
# include <linux/io.h>
# include <linux/irq.h>
# include <linux/irqdomain.h>
# include <linux/msi.h>
# include <linux/of.h>
# include <linux/of_irq.h>
# include <linux/of_platform.h>
# include <linux/platform_device.h>
# include <dt-bindings/interrupt-controller/arm-gic.h>
# define GICP_SETSPI_NSR_OFFSET 0x0
# define GICP_CLRSPI_NSR_OFFSET 0x8
struct mvebu_gicp_spi_range {
unsigned int start ;
unsigned int count ;
} ;
struct mvebu_gicp {
struct mvebu_gicp_spi_range * spi_ranges ;
unsigned int spi_ranges_cnt ;
unsigned int spi_cnt ;
unsigned long * spi_bitmap ;
spinlock_t spi_lock ;
struct resource * res ;
struct device * dev ;
} ;
static int gicp_idx_to_spi ( struct mvebu_gicp * gicp , int idx )
{
int i ;
for ( i = 0 ; i < gicp - > spi_ranges_cnt ; i + + ) {
struct mvebu_gicp_spi_range * r = & gicp - > spi_ranges [ i ] ;
if ( idx < r - > count )
return r - > start + idx ;
idx - = r - > count ;
}
return - EINVAL ;
}
static void gicp_compose_msi_msg ( struct irq_data * data , struct msi_msg * msg )
{
struct mvebu_gicp * gicp = data - > chip_data ;
phys_addr_t setspi = gicp - > res - > start + GICP_SETSPI_NSR_OFFSET ;
2018-05-08 15:14:32 +03:00
phys_addr_t clrspi = gicp - > res - > start + GICP_CLRSPI_NSR_OFFSET ;
msg [ 0 ] . data = data - > hwirq ;
msg [ 0 ] . address_lo = lower_32_bits ( setspi ) ;
msg [ 0 ] . address_hi = upper_32_bits ( setspi ) ;
msg [ 1 ] . data = data - > hwirq ;
msg [ 1 ] . address_lo = lower_32_bits ( clrspi ) ;
msg [ 1 ] . address_hi = upper_32_bits ( clrspi ) ;
2017-06-21 16:29:14 +03:00
}
static struct irq_chip gicp_irq_chip = {
. name = " GICP " ,
. irq_mask = irq_chip_mask_parent ,
. irq_unmask = irq_chip_unmask_parent ,
. irq_eoi = irq_chip_eoi_parent ,
. irq_set_affinity = irq_chip_set_affinity_parent ,
. irq_set_type = irq_chip_set_type_parent ,
. irq_compose_msi_msg = gicp_compose_msi_msg ,
} ;
static int gicp_irq_domain_alloc ( struct irq_domain * domain , unsigned int virq ,
unsigned int nr_irqs , void * args )
{
struct mvebu_gicp * gicp = domain - > host_data ;
struct irq_fwspec fwspec ;
unsigned int hwirq ;
int ret ;
spin_lock ( & gicp - > spi_lock ) ;
hwirq = find_first_zero_bit ( gicp - > spi_bitmap , gicp - > spi_cnt ) ;
if ( hwirq = = gicp - > spi_cnt ) {
spin_unlock ( & gicp - > spi_lock ) ;
return - ENOSPC ;
}
__set_bit ( hwirq , gicp - > spi_bitmap ) ;
spin_unlock ( & gicp - > spi_lock ) ;
fwspec . fwnode = domain - > parent - > fwnode ;
fwspec . param_count = 3 ;
fwspec . param [ 0 ] = GIC_SPI ;
fwspec . param [ 1 ] = gicp_idx_to_spi ( gicp , hwirq ) - 32 ;
/*
* Assume edge rising for now , it will be properly set when
* - > set_type ( ) is called
*/
fwspec . param [ 2 ] = IRQ_TYPE_EDGE_RISING ;
ret = irq_domain_alloc_irqs_parent ( domain , virq , 1 , & fwspec ) ;
if ( ret ) {
dev_err ( gicp - > dev , " Cannot allocate parent IRQ \n " ) ;
goto free_hwirq ;
}
ret = irq_domain_set_hwirq_and_chip ( domain , virq , hwirq ,
& gicp_irq_chip , gicp ) ;
if ( ret )
goto free_irqs_parent ;
return 0 ;
free_irqs_parent :
irq_domain_free_irqs_parent ( domain , virq , nr_irqs ) ;
free_hwirq :
spin_lock ( & gicp - > spi_lock ) ;
__clear_bit ( hwirq , gicp - > spi_bitmap ) ;
spin_unlock ( & gicp - > spi_lock ) ;
return ret ;
}
static void gicp_irq_domain_free ( struct irq_domain * domain ,
unsigned int virq , unsigned int nr_irqs )
{
struct mvebu_gicp * gicp = domain - > host_data ;
struct irq_data * d = irq_domain_get_irq_data ( domain , virq ) ;
if ( d - > hwirq > = gicp - > spi_cnt ) {
dev_err ( gicp - > dev , " Invalid hwirq %lu \n " , d - > hwirq ) ;
return ;
}
irq_domain_free_irqs_parent ( domain , virq , nr_irqs ) ;
spin_lock ( & gicp - > spi_lock ) ;
__clear_bit ( d - > hwirq , gicp - > spi_bitmap ) ;
spin_unlock ( & gicp - > spi_lock ) ;
}
static const struct irq_domain_ops gicp_domain_ops = {
. alloc = gicp_irq_domain_alloc ,
. free = gicp_irq_domain_free ,
} ;
static struct irq_chip gicp_msi_irq_chip = {
. name = " GICP " ,
. irq_set_type = irq_chip_set_type_parent ,
2018-05-08 15:14:32 +03:00
. flags = IRQCHIP_SUPPORTS_LEVEL_MSI ,
2017-06-21 16:29:14 +03:00
} ;
static struct msi_domain_ops gicp_msi_ops = {
} ;
static struct msi_domain_info gicp_msi_domain_info = {
2018-05-08 15:14:32 +03:00
. flags = ( MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
MSI_FLAG_LEVEL_CAPABLE ) ,
2017-06-21 16:29:14 +03:00
. ops = & gicp_msi_ops ,
. chip = & gicp_msi_irq_chip ,
} ;
static int mvebu_gicp_probe ( struct platform_device * pdev )
{
struct mvebu_gicp * gicp ;
struct irq_domain * inner_domain , * plat_domain , * parent_domain ;
struct device_node * node = pdev - > dev . of_node ;
struct device_node * irq_parent_dn ;
int ret , i ;
gicp = devm_kzalloc ( & pdev - > dev , sizeof ( * gicp ) , GFP_KERNEL ) ;
if ( ! gicp )
return - ENOMEM ;
gicp - > dev = & pdev - > dev ;
2017-10-25 10:23:26 +03:00
spin_lock_init ( & gicp - > spi_lock ) ;
2017-06-21 16:29:14 +03:00
gicp - > res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
if ( ! gicp - > res )
return - ENODEV ;
ret = of_property_count_u32_elems ( node , " marvell,spi-ranges " ) ;
if ( ret < 0 )
return ret ;
gicp - > spi_ranges_cnt = ret / 2 ;
gicp - > spi_ranges =
treewide: devm_kzalloc() -> devm_kcalloc()
The devm_kzalloc() function has a 2-factor argument form, devm_kcalloc().
This patch replaces cases of:
devm_kzalloc(handle, a * b, gfp)
with:
devm_kcalloc(handle, a * b, gfp)
as well as handling cases of:
devm_kzalloc(handle, a * b * c, gfp)
with:
devm_kzalloc(handle, array3_size(a, b, c), gfp)
as it's slightly less ugly than:
devm_kcalloc(handle, array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
devm_kzalloc(handle, 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.
Some manual whitespace fixes were needed in this patch, as Coccinelle
really liked to write "=devm_kcalloc..." instead of "= devm_kcalloc...".
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
expression HANDLE;
type TYPE;
expression THING, E;
@@
(
devm_kzalloc(HANDLE,
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
devm_kzalloc(HANDLE,
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression HANDLE;
expression COUNT;
typedef u8;
typedef __u8;
@@
(
devm_kzalloc(HANDLE,
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(char) * COUNT
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
expression HANDLE;
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
expression HANDLE;
identifier SIZE, COUNT;
@@
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression HANDLE;
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
devm_kzalloc(HANDLE,
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression HANDLE;
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
devm_kzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
expression HANDLE;
identifier STRIDE, SIZE, COUNT;
@@
(
devm_kzalloc(HANDLE,
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- 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 HANDLE;
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
devm_kzalloc(HANDLE, C1 * C2 * C3, ...)
|
devm_kzalloc(HANDLE,
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
devm_kzalloc(HANDLE,
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
devm_kzalloc(HANDLE,
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
devm_kzalloc(HANDLE,
- 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 HANDLE;
expression THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
devm_kzalloc(HANDLE, sizeof(THING) * C2, ...)
|
devm_kzalloc(HANDLE, sizeof(TYPE) * C2, ...)
|
devm_kzalloc(HANDLE, C1 * C2 * C3, ...)
|
devm_kzalloc(HANDLE, C1 * C2, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- (E1) * E2
+ E1, E2
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- (E1) * (E2)
+ E1, E2
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-13 00:07:58 +03:00
devm_kcalloc ( & pdev - > dev ,
gicp - > spi_ranges_cnt ,
2017-06-21 16:29:14 +03:00
sizeof ( struct mvebu_gicp_spi_range ) ,
GFP_KERNEL ) ;
if ( ! gicp - > spi_ranges )
return - ENOMEM ;
for ( i = 0 ; i < gicp - > spi_ranges_cnt ; i + + ) {
of_property_read_u32_index ( node , " marvell,spi-ranges " ,
i * 2 ,
& gicp - > spi_ranges [ i ] . start ) ;
of_property_read_u32_index ( node , " marvell,spi-ranges " ,
i * 2 + 1 ,
& gicp - > spi_ranges [ i ] . count ) ;
gicp - > spi_cnt + = gicp - > spi_ranges [ i ] . count ;
}
2021-06-18 18:16:56 +03:00
gicp - > spi_bitmap = devm_bitmap_zalloc ( & pdev - > dev , gicp - > spi_cnt , GFP_KERNEL ) ;
2017-06-21 16:29:14 +03:00
if ( ! gicp - > spi_bitmap )
return - ENOMEM ;
irq_parent_dn = of_irq_find_parent ( node ) ;
if ( ! irq_parent_dn ) {
dev_err ( & pdev - > dev , " failed to find parent IRQ node \n " ) ;
return - ENODEV ;
}
parent_domain = irq_find_host ( irq_parent_dn ) ;
if ( ! parent_domain ) {
dev_err ( & pdev - > dev , " failed to find parent IRQ domain \n " ) ;
return - ENODEV ;
}
inner_domain = irq_domain_create_hierarchy ( parent_domain , 0 ,
gicp - > spi_cnt ,
of_node_to_fwnode ( node ) ,
& gicp_domain_ops , gicp ) ;
if ( ! inner_domain )
return - ENOMEM ;
plat_domain = platform_msi_create_irq_domain ( of_node_to_fwnode ( node ) ,
& gicp_msi_domain_info ,
inner_domain ) ;
if ( ! plat_domain ) {
irq_domain_remove ( inner_domain ) ;
return - ENOMEM ;
}
platform_set_drvdata ( pdev , gicp ) ;
return 0 ;
}
static const struct of_device_id mvebu_gicp_of_match [ ] = {
{ . compatible = " marvell,ap806-gicp " , } ,
{ } ,
} ;
static struct platform_driver mvebu_gicp_driver = {
. probe = mvebu_gicp_probe ,
. driver = {
. name = " mvebu-gicp " ,
. of_match_table = mvebu_gicp_of_match ,
} ,
} ;
builtin_platform_driver ( mvebu_gicp_driver ) ;