2019-05-27 08:55:01 +02:00
// SPDX-License-Identifier: GPL-2.0-or-later
2014-03-06 14:52:28 +11:00
/*
* MSI support for PPC4xx SoCs using High Speed Transfer Assist ( HSTA ) for
* generation of the interrupt .
*
* Copyright © 2013 Alistair Popple < alistair @ popple . id . au > IBM Corporation
*/
# include <linux/kernel.h>
# include <linux/interrupt.h>
# include <linux/msi.h>
# include <linux/of.h>
# include <linux/of_platform.h>
# include <linux/pci.h>
# include <linux/semaphore.h>
# include <asm/msi_bitmap.h>
2015-07-06 09:40:34 +10:00
# include <asm/ppc-pci.h>
2014-03-06 14:52:28 +11:00
struct ppc4xx_hsta_msi {
struct device * dev ;
/* The ioremapped HSTA MSI IO space */
u32 __iomem * data ;
/* Physical address of HSTA MSI IO space */
u64 address ;
struct msi_bitmap bmp ;
/* An array mapping offsets to hardware IRQs */
int * irq_map ;
/* Number of hwirqs supported */
int irq_count ;
} ;
static struct ppc4xx_hsta_msi ppc4xx_hsta_msi ;
static int hsta_setup_msi_irqs ( struct pci_dev * dev , int nvec , int type )
{
struct msi_msg msg ;
struct msi_desc * entry ;
int irq , hwirq ;
u64 addr ;
2014-09-07 20:57:53 +02:00
/* We don't support MSI-X */
if ( type = = PCI_CAP_ID_MSIX ) {
pr_debug ( " %s: MSI-X not supported. \n " , __func__ ) ;
return - EINVAL ;
}
2015-07-09 16:00:38 +08:00
for_each_pci_msi_entry ( entry , dev ) {
2014-03-06 14:52:28 +11:00
irq = msi_bitmap_alloc_hwirqs ( & ppc4xx_hsta_msi . bmp , 1 ) ;
if ( irq < 0 ) {
pr_debug ( " %s: Failed to allocate msi interrupt \n " ,
__func__ ) ;
return irq ;
}
hwirq = ppc4xx_hsta_msi . irq_map [ irq ] ;
2016-09-06 21:53:24 +10:00
if ( ! hwirq ) {
2014-03-06 14:52:28 +11:00
pr_err ( " %s: Failed mapping irq %d \n " , __func__ , irq ) ;
return - EINVAL ;
}
/*
* HSTA generates interrupts on writes to 128 - bit aligned
* addresses .
*/
addr = ppc4xx_hsta_msi . address + irq * 0x10 ;
msg . address_hi = upper_32_bits ( addr ) ;
msg . address_lo = lower_32_bits ( addr ) ;
/* Data is not used by the HSTA. */
msg . data = 0 ;
pr_debug ( " %s: Setup irq %d (0x%0llx) \n " , __func__ , hwirq ,
( ( ( u64 ) msg . address_hi ) < < 32 ) | msg . address_lo ) ;
if ( irq_set_msi_desc ( hwirq , entry ) ) {
pr_err (
" %s: Invalid hwirq %d specified in device tree \n " ,
__func__ , hwirq ) ;
msi_bitmap_free_hwirqs ( & ppc4xx_hsta_msi . bmp , irq , 1 ) ;
return - EINVAL ;
}
2014-11-09 23:10:34 +08:00
pci_write_msi_msg ( hwirq , & msg ) ;
2014-03-06 14:52:28 +11:00
}
return 0 ;
}
static int hsta_find_hwirq_offset ( int hwirq )
{
int irq ;
/* Find the offset given the hwirq */
for ( irq = 0 ; irq < ppc4xx_hsta_msi . irq_count ; irq + + )
if ( ppc4xx_hsta_msi . irq_map [ irq ] = = hwirq )
return irq ;
return - EINVAL ;
}
static void hsta_teardown_msi_irqs ( struct pci_dev * dev )
{
struct msi_desc * entry ;
int irq ;
2015-07-09 16:00:38 +08:00
for_each_pci_msi_entry ( entry , dev ) {
2016-09-06 21:53:24 +10:00
if ( ! entry - > irq )
2014-03-06 14:52:28 +11:00
continue ;
irq = hsta_find_hwirq_offset ( entry - > irq ) ;
/* entry->irq should always be in irq_map */
BUG_ON ( irq < 0 ) ;
irq_set_msi_desc ( entry - > irq , NULL ) ;
msi_bitmap_free_hwirqs ( & ppc4xx_hsta_msi . bmp , irq , 1 ) ;
pr_debug ( " %s: Teardown IRQ %u (index %u) \n " , __func__ ,
entry - > irq , irq ) ;
}
}
static int hsta_msi_probe ( struct platform_device * pdev )
{
struct device * dev = & pdev - > dev ;
struct resource * mem ;
int irq , ret , irq_count ;
2015-04-14 14:28:00 +10:00
struct pci_controller * phb ;
2014-03-06 14:52:28 +11:00
mem = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
2015-04-16 20:18:50 +08:00
if ( ! mem ) {
2014-03-06 14:52:28 +11:00
dev_err ( dev , " Unable to get mmio space \n " ) ;
return - EINVAL ;
}
irq_count = of_irq_count ( dev - > of_node ) ;
if ( ! irq_count ) {
dev_err ( dev , " Unable to find IRQ range \n " ) ;
return - EINVAL ;
}
ppc4xx_hsta_msi . dev = dev ;
ppc4xx_hsta_msi . address = mem - > start ;
ppc4xx_hsta_msi . data = ioremap ( mem - > start , resource_size ( mem ) ) ;
ppc4xx_hsta_msi . irq_count = irq_count ;
2014-07-20 15:20:59 +08:00
if ( ! ppc4xx_hsta_msi . data ) {
2014-03-06 14:52:28 +11:00
dev_err ( dev , " Unable to map memory \n " ) ;
return - ENOMEM ;
}
ret = msi_bitmap_alloc ( & ppc4xx_hsta_msi . bmp , irq_count , dev - > of_node ) ;
if ( ret )
goto out ;
treewide: kmalloc() -> kmalloc_array()
The kmalloc() function has a 2-factor argument form, kmalloc_array(). This
patch replaces cases of:
kmalloc(a * b, gfp)
with:
kmalloc_array(a * b, gfp)
as well as handling cases of:
kmalloc(a * b * c, gfp)
with:
kmalloc(array3_size(a, b, c), gfp)
as it's slightly less ugly than:
kmalloc_array(array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
kmalloc(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 tools/ directory was manually excluded, since it has its own
implementation of kmalloc().
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
type TYPE;
expression THING, E;
@@
(
kmalloc(
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
kmalloc(
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression COUNT;
typedef u8;
typedef __u8;
@@
(
kmalloc(
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(char) * COUNT
+ COUNT
, ...)
|
kmalloc(
- 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;
@@
(
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
identifier SIZE, COUNT;
@@
- kmalloc
+ kmalloc_array
(
- 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;
@@
(
kmalloc(
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- 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;
@@
(
kmalloc(
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kmalloc(
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
kmalloc(
- 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;
@@
(
kmalloc(
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- 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;
@@
(
kmalloc(C1 * C2 * C3, ...)
|
kmalloc(
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- 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;
@@
(
kmalloc(sizeof(THING) * C2, ...)
|
kmalloc(sizeof(TYPE) * C2, ...)
|
kmalloc(C1 * C2 * C3, ...)
|
kmalloc(C1 * C2, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- (E1) * E2
+ E1, E2
, ...)
|
- kmalloc
+ kmalloc_array
(
- (E1) * (E2)
+ E1, E2
, ...)
|
- kmalloc
+ kmalloc_array
(
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-12 13:55:00 -07:00
ppc4xx_hsta_msi . irq_map = kmalloc_array ( irq_count , sizeof ( int ) ,
GFP_KERNEL ) ;
2015-04-16 20:18:50 +08:00
if ( ! ppc4xx_hsta_msi . irq_map ) {
2014-03-06 14:52:28 +11:00
ret = - ENOMEM ;
goto out1 ;
}
/* Setup a mapping from irq offsets to hardware irq numbers */
for ( irq = 0 ; irq < irq_count ; irq + + ) {
ppc4xx_hsta_msi . irq_map [ irq ] =
irq_of_parse_and_map ( dev - > of_node , irq ) ;
2016-09-06 21:53:24 +10:00
if ( ! ppc4xx_hsta_msi . irq_map [ irq ] ) {
2014-03-06 14:52:28 +11:00
dev_err ( dev , " Unable to map IRQ \n " ) ;
ret = - EINVAL ;
goto out2 ;
}
}
2015-04-14 14:28:00 +10:00
list_for_each_entry ( phb , & hose_list , list_node ) {
phb - > controller_ops . setup_msi_irqs = hsta_setup_msi_irqs ;
phb - > controller_ops . teardown_msi_irqs = hsta_teardown_msi_irqs ;
}
2014-03-06 14:52:28 +11:00
return 0 ;
out2 :
kfree ( ppc4xx_hsta_msi . irq_map ) ;
out1 :
msi_bitmap_free ( & ppc4xx_hsta_msi . bmp ) ;
out :
iounmap ( ppc4xx_hsta_msi . data ) ;
return ret ;
}
static const struct of_device_id hsta_msi_ids [ ] = {
{
. compatible = " ibm,hsta-msi " ,
} ,
{ }
} ;
static struct platform_driver hsta_msi_driver = {
. probe = hsta_msi_probe ,
. driver = {
. name = " hsta-msi " ,
. of_match_table = hsta_msi_ids ,
} ,
} ;
static int hsta_msi_init ( void )
{
return platform_driver_register ( & hsta_msi_driver ) ;
}
subsys_initcall ( hsta_msi_init ) ;