2005-11-23 09:53:42 +03:00
# undef DEBUG
# include <linux/kernel.h>
# include <linux/string.h>
# include <linux/pci_regs.h>
# include <linux/module.h>
2005-11-30 08:57:28 +03:00
# include <linux/ioport.h>
2007-02-16 21:01:29 +03:00
# include <linux/etherdevice.h>
2010-06-08 17:48:09 +04:00
# include <linux/of_address.h>
2005-11-23 09:53:42 +03:00
# include <asm/prom.h>
2005-11-30 08:57:28 +03:00
# include <asm/pci-bridge.h>
2005-11-23 09:53:42 +03:00
2006-10-17 01:03:33 +04:00
# ifdef CONFIG_PCI
int of_irq_map_pci ( struct pci_dev * pdev , struct of_irq * out_irq )
{
struct device_node * dn , * ppnode ;
struct pci_dev * ppdev ;
u32 lspec ;
u32 laddr [ 3 ] ;
u8 pin ;
int rc ;
/* Check if we have a device node, if yes, fallback to standard OF
* parsing
*/
dn = pci_device_to_OF_node ( pdev ) ;
2008-11-19 06:55:35 +03:00
if ( dn ) {
rc = of_irq_map_one ( dn , 0 , out_irq ) ;
if ( ! rc )
return rc ;
}
2006-10-17 01:03:33 +04:00
/* 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 )
return rc ;
/* No pin, exit */
if ( pin = = 0 )
return - ENODEV ;
/* Now we walk up the PCI tree */
lspec = pin ;
for ( ; ; ) {
/* Get the pci_dev of our parent */
ppdev = pdev - > bus - > self ;
/* Ouch, it's a host bridge... */
if ( ppdev = = NULL ) {
# ifdef CONFIG_PPC64
ppnode = pci_bus_to_OF_node ( pdev - > bus ) ;
# else
struct pci_controller * host ;
host = pci_bus_to_host ( pdev - > bus ) ;
2007-12-10 06:33:21 +03:00
ppnode = host ? host - > dn : NULL ;
2006-10-17 01:03:33 +04:00
# endif
/* No node for host bridge ? give up */
if ( ppnode = = NULL )
return - EINVAL ;
} 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
*/
2008-12-10 02:12:27 +03:00
lspec = pci_swizzle_interrupt_pin ( pdev , lspec ) ;
2006-10-17 01:03:33 +04:00
pdev = ppdev ;
}
laddr [ 0 ] = ( pdev - > bus - > number < < 16 )
| ( pdev - > devfn < < 8 ) ;
laddr [ 1 ] = laddr [ 2 ] = 0 ;
return of_irq_map_raw ( ppnode , & lspec , 1 , laddr , out_irq ) ;
}
EXPORT_SYMBOL_GPL ( of_irq_map_pci ) ;
# endif /* CONFIG_PCI */
2006-07-12 09:35:54 +04:00
void of_parse_dma_window ( struct device_node * dn , const void * dma_window_prop ,
2006-05-18 12:05:15 +04:00
unsigned long * busno , unsigned long * phys , unsigned long * size )
{
2006-07-12 09:35:54 +04:00
const u32 * dma_window ;
u32 cells ;
const unsigned char * prop ;
2006-05-18 12:05:15 +04:00
2006-07-12 09:35:54 +04:00
dma_window = dma_window_prop ;
2006-05-18 12:05:15 +04:00
/* busno is always one cell */
* busno = * ( dma_window + + ) ;
2007-04-03 16:26:41 +04:00
prop = of_get_property ( dn , " ibm,#dma-address-cells " , NULL ) ;
2006-05-30 22:38:40 +04:00
if ( ! prop )
2007-04-03 16:26:41 +04:00
prop = of_get_property ( dn , " #address-cells " , NULL ) ;
2006-05-30 22:38:40 +04:00
2007-04-03 04:56:50 +04:00
cells = prop ? * ( u32 * ) prop : of_n_addr_cells ( dn ) ;
2006-07-03 13:35:17 +04:00
* phys = of_read_number ( dma_window , cells ) ;
2006-05-18 12:05:15 +04:00
dma_window + = cells ;
2007-04-03 16:26:41 +04:00
prop = of_get_property ( dn , " ibm,#dma-size-cells " , NULL ) ;
2007-04-03 04:57:48 +04:00
cells = prop ? * ( u32 * ) prop : of_n_size_cells ( dn ) ;
2006-07-03 13:35:17 +04:00
* size = of_read_number ( dma_window , cells ) ;
}