2011-04-11 05:37:07 +04:00
# include <linux/kernel.h>
# include <linux/of_pci.h>
# include <linux/of_irq.h>
2011-07-29 10:05:38 +04:00
# include <linux/export.h>
2011-04-11 05:37:07 +04:00
/**
2013-09-19 20:22:36 +04:00
* of_irq_parse_pci - Resolve the interrupt for a PCI device
2011-04-11 05:37:07 +04:00
* @ pdev : the device whose interrupt is to be resolved
* @ out_irq : structure of_irq filled by this function
*
* This function resolves the PCI interrupt for a given PCI device . If a
* device - node exists for a given pci_dev , it will use normal OF tree
* walking . If not , it will implement standard swizzling and walk up the
* PCI tree until an device - node is found , at which point it will finish
* resolving using the OF tree walking .
*/
2013-09-15 19:39:11 +04:00
int of_irq_parse_pci ( const struct pci_dev * pdev , struct of_phandle_args * out_irq )
2011-04-11 05:37:07 +04:00
{
struct device_node * dn , * ppnode ;
struct pci_dev * ppdev ;
__be32 laddr [ 3 ] ;
u8 pin ;
int rc ;
/* Check if we have a device node, if yes, fallback to standard
* device tree parsing
*/
dn = pci_device_to_OF_node ( pdev ) ;
if ( dn ) {
2013-09-19 20:22:36 +04:00
rc = of_irq_parse_one ( dn , 0 , out_irq ) ;
2011-04-11 05:37:07 +04:00
if ( ! rc )
return rc ;
}
/* Ok, we don't, time to have fun. Let's start by building up an
* interrupt spec . we assume # interrupt - cells is 1 , which is standard
* for PCI . If you do different , then don ' t use that routine .
*/
rc = pci_read_config_byte ( pdev , PCI_INTERRUPT_PIN , & pin ) ;
if ( rc ! = 0 )
2015-09-10 01:57:59 +03:00
goto err ;
/* No pin, exit with no error message. */
2011-04-11 05:37:07 +04:00
if ( pin = = 0 )
return - ENODEV ;
/* Now we walk up the PCI tree */
for ( ; ; ) {
/* Get the pci_dev of our parent */
ppdev = pdev - > bus - > self ;
/* Ouch, it's a host bridge... */
if ( ppdev = = NULL ) {
ppnode = pci_bus_to_OF_node ( pdev - > bus ) ;
/* No node for host bridge ? give up */
2015-09-10 01:57:59 +03:00
if ( ppnode = = NULL ) {
rc = - EINVAL ;
goto err ;
}
2011-04-11 05:37:07 +04:00
} else {
/* We found a P2P bridge, check if it has a node */
ppnode = pci_device_to_OF_node ( ppdev ) ;
}
/* Ok, we have found a parent with a device-node, hand over to
* the OF parsing code .
* We build a unit address from the linux device to be used for
* resolution . Note that we use the linux bus number which may
* not match your firmware bus numbering .
* Fortunately , in most cases , interrupt - map - mask doesn ' t
* include the bus number as part of the matching .
* You should still be careful about that though if you intend
* to rely on this function ( you ship a firmware that doesn ' t
* create device nodes for all PCI devices ) .
*/
if ( ppnode )
break ;
/* We can only get here if we hit a P2P bridge with no node,
* let ' s do standard swizzling and try again
*/
2014-05-25 22:50:06 +04:00
pin = pci_swizzle_interrupt_pin ( pdev , pin ) ;
2011-04-11 05:37:07 +04:00
pdev = ppdev ;
}
2013-09-16 01:32:39 +04:00
out_irq - > np = ppnode ;
out_irq - > args_count = 1 ;
2014-05-25 22:50:06 +04:00
out_irq - > args [ 0 ] = pin ;
2011-04-11 05:37:07 +04:00
laddr [ 0 ] = cpu_to_be32 ( ( pdev - > bus - > number < < 16 ) | ( pdev - > devfn < < 8 ) ) ;
2013-09-16 01:32:39 +04:00
laddr [ 1 ] = laddr [ 2 ] = cpu_to_be32 ( 0 ) ;
2015-09-10 01:57:59 +03:00
rc = of_irq_parse_raw ( laddr , out_irq ) ;
if ( rc )
goto err ;
return 0 ;
err :
dev_err ( & pdev - > dev , " of_irq_parse_pci() failed with rc=%d \n " , rc ) ;
return rc ;
2011-04-11 05:37:07 +04:00
}
2013-09-19 20:22:36 +04:00
EXPORT_SYMBOL_GPL ( of_irq_parse_pci ) ;
2013-09-20 01:44:55 +04:00
/**
* of_irq_parse_and_map_pci ( ) - Decode a PCI irq from the device tree and map to a virq
* @ dev : The pci device needing an irq
* @ slot : PCI slot number ; passed when used as map_irq callback . Unused
* @ pin : PCI irq pin number ; passed when used as map_irq callback . Unused
*
* @ slot and @ pin are unused , but included in the function so that this
* function can be used directly as the map_irq callback to pci_fixup_irqs ( ) .
*/
int of_irq_parse_and_map_pci ( const struct pci_dev * dev , u8 slot , u8 pin )
{
struct of_phandle_args oirq ;
int ret ;
ret = of_irq_parse_pci ( dev , & oirq ) ;
2015-09-10 01:57:59 +03:00
if ( ret )
2013-09-20 01:44:55 +04:00
return 0 ; /* Proper return code 0 == NO_IRQ */
return irq_create_of_mapping ( & oirq ) ;
}
EXPORT_SYMBOL_GPL ( of_irq_parse_and_map_pci ) ;