2016-02-19 18:22:44 +03:00
/*
* Annapurna Labs MSIX support services
*
* Copyright ( C ) 2016 , Amazon . com , Inc . or its affiliates . All Rights Reserved .
*
* Antoine Tenart < antoine . tenart @ 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 .
*/
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
# include <linux/irqchip.h>
# include <linux/irqchip/arm-gic.h>
# include <linux/msi.h>
# include <linux/of.h>
# include <linux/of_address.h>
# include <linux/of_irq.h>
# include <linux/of_pci.h>
# include <linux/pci.h>
# include <linux/slab.h>
# include <asm/irq.h>
2016-05-05 17:41:05 +03:00
# include <asm/msi.h>
2016-02-19 18:22:44 +03:00
/* MSIX message address format: local GIC target */
# define ALPINE_MSIX_SPI_TARGET_CLUSTER0 BIT(16)
struct alpine_msix_data {
spinlock_t msi_map_lock ;
phys_addr_t addr ;
u32 spi_first ; /* The SGI number that MSIs start */
u32 num_spis ; /* The number of SGIs for MSIs */
unsigned long * msi_map ;
} ;
static void alpine_msix_mask_msi_irq ( struct irq_data * d )
{
pci_msi_mask_irq ( d ) ;
irq_chip_mask_parent ( d ) ;
}
static void alpine_msix_unmask_msi_irq ( struct irq_data * d )
{
pci_msi_unmask_irq ( d ) ;
irq_chip_unmask_parent ( d ) ;
}
static struct irq_chip alpine_msix_irq_chip = {
. name = " MSIx " ,
. irq_mask = alpine_msix_mask_msi_irq ,
. irq_unmask = alpine_msix_unmask_msi_irq ,
. irq_eoi = irq_chip_eoi_parent ,
. irq_set_affinity = irq_chip_set_affinity_parent ,
} ;
static int alpine_msix_allocate_sgi ( struct alpine_msix_data * priv , int num_req )
{
int first ;
spin_lock ( & priv - > msi_map_lock ) ;
first = bitmap_find_next_zero_area ( priv - > msi_map , priv - > num_spis , 0 ,
num_req , 0 ) ;
if ( first > = priv - > num_spis ) {
spin_unlock ( & priv - > msi_map_lock ) ;
return - ENOSPC ;
}
bitmap_set ( priv - > msi_map , first , num_req ) ;
spin_unlock ( & priv - > msi_map_lock ) ;
return priv - > spi_first + first ;
}
static void alpine_msix_free_sgi ( struct alpine_msix_data * priv , unsigned sgi ,
int num_req )
{
int first = sgi - priv - > spi_first ;
spin_lock ( & priv - > msi_map_lock ) ;
bitmap_clear ( priv - > msi_map , first , num_req ) ;
spin_unlock ( & priv - > msi_map_lock ) ;
}
static void alpine_msix_compose_msi_msg ( struct irq_data * data ,
struct msi_msg * msg )
{
struct alpine_msix_data * priv = irq_data_get_irq_chip_data ( data ) ;
phys_addr_t msg_addr = priv - > addr ;
msg_addr | = ( data - > hwirq < < 3 ) ;
msg - > address_hi = upper_32_bits ( msg_addr ) ;
msg - > address_lo = lower_32_bits ( msg_addr ) ;
msg - > data = 0 ;
}
static struct msi_domain_info alpine_msix_domain_info = {
. flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
MSI_FLAG_PCI_MSIX ,
. chip = & alpine_msix_irq_chip ,
} ;
static struct irq_chip middle_irq_chip = {
. name = " alpine_msix_middle " ,
. 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_compose_msi_msg = alpine_msix_compose_msi_msg ,
} ;
static int alpine_msix_gic_domain_alloc ( struct irq_domain * domain ,
unsigned int virq , int sgi )
{
struct irq_fwspec fwspec ;
struct irq_data * d ;
int ret ;
if ( ! is_of_node ( domain - > parent - > fwnode ) )
return - EINVAL ;
fwspec . fwnode = domain - > parent - > fwnode ;
fwspec . param_count = 3 ;
fwspec . param [ 0 ] = 0 ;
fwspec . param [ 1 ] = sgi ;
fwspec . param [ 2 ] = IRQ_TYPE_EDGE_RISING ;
ret = irq_domain_alloc_irqs_parent ( domain , virq , 1 , & fwspec ) ;
if ( ret )
return ret ;
d = irq_domain_get_irq_data ( domain - > parent , virq ) ;
d - > chip - > irq_set_type ( d , IRQ_TYPE_EDGE_RISING ) ;
return 0 ;
}
static int alpine_msix_middle_domain_alloc ( struct irq_domain * domain ,
unsigned int virq ,
unsigned int nr_irqs , void * args )
{
struct alpine_msix_data * priv = domain - > host_data ;
int sgi , err , i ;
sgi = alpine_msix_allocate_sgi ( priv , nr_irqs ) ;
if ( sgi < 0 )
return sgi ;
for ( i = 0 ; i < nr_irqs ; i + + ) {
err = alpine_msix_gic_domain_alloc ( domain , virq + i , sgi + i ) ;
if ( err )
goto err_sgi ;
irq_domain_set_hwirq_and_chip ( domain , virq + i , sgi + i ,
& middle_irq_chip , priv ) ;
}
return 0 ;
err_sgi :
2020-11-29 16:55:25 +03:00
irq_domain_free_irqs_parent ( domain , virq , i - 1 ) ;
2016-02-19 18:22:44 +03:00
alpine_msix_free_sgi ( priv , sgi , nr_irqs ) ;
return err ;
}
static void alpine_msix_middle_domain_free ( struct irq_domain * domain ,
unsigned int virq ,
unsigned int nr_irqs )
{
struct irq_data * d = irq_domain_get_irq_data ( domain , virq ) ;
struct alpine_msix_data * priv = irq_data_get_irq_chip_data ( d ) ;
irq_domain_free_irqs_parent ( domain , virq , nr_irqs ) ;
alpine_msix_free_sgi ( priv , d - > hwirq , nr_irqs ) ;
}
static const struct irq_domain_ops alpine_msix_middle_domain_ops = {
. alloc = alpine_msix_middle_domain_alloc ,
. free = alpine_msix_middle_domain_free ,
} ;
static int alpine_msix_init_domains ( struct alpine_msix_data * priv ,
struct device_node * node )
{
struct irq_domain * middle_domain , * msi_domain , * gic_domain ;
struct device_node * gic_node ;
gic_node = of_irq_find_parent ( node ) ;
if ( ! gic_node ) {
pr_err ( " Failed to find the GIC node \n " ) ;
return - ENODEV ;
}
gic_domain = irq_find_host ( gic_node ) ;
if ( ! gic_domain ) {
pr_err ( " Failed to find the GIC domain \n " ) ;
return - ENXIO ;
}
middle_domain = irq_domain_add_tree ( NULL ,
& alpine_msix_middle_domain_ops ,
priv ) ;
if ( ! middle_domain ) {
pr_err ( " Failed to create the MSIX middle domain \n " ) ;
return - ENOMEM ;
}
middle_domain - > parent = gic_domain ;
msi_domain = pci_msi_create_irq_domain ( of_node_to_fwnode ( node ) ,
& alpine_msix_domain_info ,
middle_domain ) ;
if ( ! msi_domain ) {
pr_err ( " Failed to create MSI domain \n " ) ;
2016-03-11 11:14:43 +03:00
irq_domain_remove ( middle_domain ) ;
2016-02-19 18:22:44 +03:00
return - ENOMEM ;
}
return 0 ;
}
static int alpine_msix_init ( struct device_node * node ,
struct device_node * parent )
{
struct alpine_msix_data * priv ;
struct resource res ;
int ret ;
priv = kzalloc ( sizeof ( * priv ) , GFP_KERNEL ) ;
if ( ! priv )
return - ENOMEM ;
spin_lock_init ( & priv - > msi_map_lock ) ;
ret = of_address_to_resource ( node , 0 , & res ) ;
if ( ret ) {
pr_err ( " Failed to allocate resource \n " ) ;
goto err_priv ;
}
/*
* The 20 least significant bits of addr provide direct information
* regarding the interrupt destination .
*
* To select the primary GIC as the target GIC , bits [ 18 : 17 ] must be set
* to 0x0 . In this case , bit 16 ( SPI_TARGET_CLUSTER0 ) must be set .
*/
priv - > addr = res . start & GENMASK_ULL ( 63 , 20 ) ;
priv - > addr | = ALPINE_MSIX_SPI_TARGET_CLUSTER0 ;
if ( of_property_read_u32 ( node , " al,msi-base-spi " , & priv - > spi_first ) ) {
pr_err ( " Unable to parse MSI base \n " ) ;
ret = - EINVAL ;
goto err_priv ;
}
if ( of_property_read_u32 ( node , " al,msi-num-spis " , & priv - > num_spis ) ) {
pr_err ( " Unable to parse MSI numbers \n " ) ;
ret = - EINVAL ;
goto err_priv ;
}
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
priv - > msi_map = kcalloc ( BITS_TO_LONGS ( priv - > num_spis ) ,
sizeof ( * priv - > msi_map ) ,
2016-02-19 18:22:44 +03:00
GFP_KERNEL ) ;
if ( ! priv - > msi_map ) {
ret = - ENOMEM ;
goto err_priv ;
}
pr_debug ( " Registering %d msixs, starting at %d \n " ,
priv - > num_spis , priv - > spi_first ) ;
ret = alpine_msix_init_domains ( priv , node ) ;
if ( ret )
goto err_map ;
return 0 ;
err_map :
kfree ( priv - > msi_map ) ;
err_priv :
kfree ( priv ) ;
return ret ;
}
IRQCHIP_DECLARE ( alpine_msix , " al,alpine-msix " , alpine_msix_init ) ;