2012-04-07 17:10:17 -04:00
/*
* Copyright 2012 Tilera Corporation . All Rights Reserved .
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation , version 2.
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE , GOOD TITLE or
* NON INFRINGEMENT . See the GNU General Public License for
* more details .
*/
# include <linux/kernel.h>
# include <linux/mmzone.h>
# include <linux/pci.h>
# include <linux/delay.h>
# include <linux/string.h>
# include <linux/init.h>
# include <linux/capability.h>
# include <linux/sched.h>
# include <linux/errno.h>
# include <linux/irq.h>
# include <linux/msi.h>
# include <linux/io.h>
# include <linux/uaccess.h>
# include <linux/ctype.h>
# include <asm/processor.h>
# include <asm/sections.h>
# include <asm/byteorder.h>
# include <gxio/iorpc_globals.h>
# include <gxio/kiorpc.h>
# include <gxio/trio.h>
# include <gxio/iorpc_trio.h>
# include <hv/drv_trio_intf.h>
# include <arch/sim.h>
/*
2016-05-21 14:10:49 +02:00
* This file contains the routines to search for PCI buses ,
2012-04-07 17:10:17 -04:00
* enumerate the buses , and configure any attached devices .
*/
# define DEBUG_PCI_CFG 0
# if DEBUG_PCI_CFG
# define TRACE_CFG_WR(size, val, bus, dev, func, offset) \
pr_info ( " CFG WR %d-byte VAL %#x to bus %d dev %d func %d addr %u \n " , \
size , val , bus , dev , func , offset & 0xFFF ) ;
# define TRACE_CFG_RD(size, val, bus, dev, func, offset) \
pr_info ( " CFG RD %d-byte VAL %#x from bus %d dev %d func %d addr %u \n " , \
size , val , bus , dev , func , offset & 0xFFF ) ;
# else
# define TRACE_CFG_WR(...)
# define TRACE_CFG_RD(...)
# endif
2012-12-21 14:06:37 -08:00
static int pci_probe = 1 ;
2012-04-07 17:10:17 -04:00
/* Information on the PCIe RC ports configuration. */
2012-12-21 14:06:37 -08:00
static int pcie_rc [ TILEGX_NUM_TRIO ] [ TILEGX_TRIO_PCIES ] ;
2012-04-07 17:10:17 -04:00
/*
* On some platforms with one or more Gx endpoint ports , we need to
* delay the PCIe RC port probe for a few seconds to work around
* a HW PCIe link - training bug . The exact delay is specified with
* a kernel boot argument in the form of " pcie_rc_delay=T,P,S " ,
* where T is the TRIO instance number , P is the port number and S is
2013-08-02 11:47:29 -04:00
* the delay in seconds . If the argument is specified , but the delay is
* not provided , the value will be DEFAULT_RC_DELAY .
2012-04-07 17:10:17 -04:00
*/
2012-12-21 14:06:37 -08:00
static int rc_delay [ TILEGX_NUM_TRIO ] [ TILEGX_TRIO_PCIES ] ;
2012-04-07 17:10:17 -04:00
/* Default number of seconds that the PCIe RC port probe can be delayed. */
# define DEFAULT_RC_DELAY 10
2013-08-02 16:45:22 -04:00
/* The PCI I/O space size in each PCI domain. */
# define IO_SPACE_SIZE 0x10000
2013-08-05 13:18:02 -04:00
/* Provide shorter versions of some very long constant names. */
# define AUTO_CONFIG_RC \
TRIO_PCIE_INTFC_PORT_CONFIG__STRAP_STATE_VAL_AUTO_CONFIG_RC
# define AUTO_CONFIG_RC_G1 \
TRIO_PCIE_INTFC_PORT_CONFIG__STRAP_STATE_VAL_AUTO_CONFIG_RC_G1
# define AUTO_CONFIG_EP \
TRIO_PCIE_INTFC_PORT_CONFIG__STRAP_STATE_VAL_AUTO_CONFIG_ENDPOINT
# define AUTO_CONFIG_EP_G1 \
TRIO_PCIE_INTFC_PORT_CONFIG__STRAP_STATE_VAL_AUTO_CONFIG_ENDPOINT_G1
2012-04-07 17:10:17 -04:00
/* Array of the PCIe ports configuration info obtained from the BIB. */
2013-08-05 13:32:52 -04:00
struct pcie_trio_ports_property pcie_ports [ TILEGX_NUM_TRIO ] ;
2012-04-07 17:10:17 -04:00
2013-08-05 13:18:02 -04:00
/* Number of configured TRIO instances. */
int num_trio_shims ;
2012-04-07 17:10:17 -04:00
/* All drivers share the TRIO contexts defined here. */
gxio_trio_context_t trio_contexts [ TILEGX_NUM_TRIO ] ;
/* Pointer to an array of PCIe RC controllers. */
struct pci_controller pci_controllers [ TILEGX_NUM_TRIO * TILEGX_TRIO_PCIES ] ;
int num_rc_controllers ;
static struct pci_ops tile_cfg_ops ;
/* Mask of CPUs that should receive PCIe interrupts. */
static struct cpumask intr_cpus_map ;
2013-08-05 13:29:34 -04:00
/* We don't need to worry about the alignment of resources. */
2012-04-07 17:10:17 -04:00
resource_size_t pcibios_align_resource ( void * data , const struct resource * res ,
2013-08-05 13:29:34 -04:00
resource_size_t size ,
resource_size_t align )
2012-04-07 17:10:17 -04:00
{
return res - > start ;
}
EXPORT_SYMBOL ( pcibios_align_resource ) ;
/*
* Pick a CPU to receive and handle the PCIe interrupts , based on the IRQ # .
* For now , we simply send interrupts to non - dataplane CPUs .
* We may implement methods to allow user to specify the target CPUs ,
* e . g . via boot arguments .
*/
static int tile_irq_cpu ( int irq )
{
unsigned int count ;
int i = 0 ;
int cpu ;
count = cpumask_weight ( & intr_cpus_map ) ;
if ( unlikely ( count = = 0 ) ) {
2014-10-31 10:50:46 -07:00
pr_warn ( " intr_cpus_map empty, interrupts will be delievered to dataplane tiles \n " ) ;
2012-04-07 17:10:17 -04:00
return irq % ( smp_height * smp_width ) ;
}
count = irq % count ;
for_each_cpu ( cpu , & intr_cpus_map ) {
if ( i + + = = count )
break ;
}
return cpu ;
}
2013-08-05 13:29:34 -04:00
/* Open a file descriptor to the TRIO shim. */
2012-12-21 14:06:37 -08:00
static int tile_pcie_open ( int trio_index )
2012-04-07 17:10:17 -04:00
{
gxio_trio_context_t * context = & trio_contexts [ trio_index ] ;
int ret ;
2013-08-05 13:18:02 -04:00
int mac ;
2012-04-07 17:10:17 -04:00
2013-08-05 13:29:34 -04:00
/* This opens a file descriptor to the TRIO shim. */
2012-04-07 17:10:17 -04:00
ret = gxio_trio_init ( context , trio_index ) ;
if ( ret < 0 )
2013-08-05 13:18:02 -04:00
goto gxio_trio_init_failure ;
2012-04-07 17:10:17 -04:00
2013-08-05 13:29:34 -04:00
/* Allocate an ASID for the kernel. */
2012-04-07 17:10:17 -04:00
ret = gxio_trio_alloc_asids ( context , 1 , 0 , 0 ) ;
if ( ret < 0 ) {
pr_err ( " PCI: ASID alloc failure on TRIO %d, give up \n " ,
trio_index ) ;
goto asid_alloc_failure ;
}
context - > asid = ret ;
# ifdef USE_SHARED_PCIE_CONFIG_REGION
/*
* Alloc a PIO region for config access , shared by all MACs per TRIO .
* This shouldn ' t fail since the kernel is supposed to the first
* client of the TRIO ' s PIO regions .
*/
ret = gxio_trio_alloc_pio_regions ( context , 1 , 0 , 0 ) ;
if ( ret < 0 ) {
pr_err ( " PCI: CFG PIO alloc failure on TRIO %d, give up \n " ,
trio_index ) ;
goto pio_alloc_failure ;
}
context - > pio_cfg_index = ret ;
/*
* For PIO CFG , the bus_address_hi parameter is 0. The mac parameter
* is also 0 because it is specified in PIO_REGION_SETUP_CFG_ADDR .
*/
ret = gxio_trio_init_pio_region_aux ( context , context - > pio_cfg_index ,
0 , 0 , HV_TRIO_PIO_FLAG_CONFIG_SPACE ) ;
if ( ret < 0 ) {
pr_err ( " PCI: CFG PIO init failure on TRIO %d, give up \n " ,
trio_index ) ;
goto pio_alloc_failure ;
}
# endif
2013-08-05 13:18:02 -04:00
/* Get the properties of the PCIe ports on this TRIO instance. */
2013-08-05 13:32:52 -04:00
ret = gxio_trio_get_port_property ( context , & pcie_ports [ trio_index ] ) ;
2013-08-05 13:18:02 -04:00
if ( ret < 0 ) {
2014-10-31 10:50:46 -07:00
pr_err ( " PCI: PCIE_GET_PORT_PROPERTY failure, error %d, on TRIO %d \n " ,
ret , trio_index ) ;
2013-08-05 13:18:02 -04:00
goto get_port_property_failure ;
}
context - > mmio_base_mac =
iorpc_ioremap ( context - > fd , 0 , HV_TRIO_CONFIG_IOREMAP_SIZE ) ;
if ( context - > mmio_base_mac = = NULL ) {
2014-10-31 10:50:46 -07:00
pr_err ( " PCI: TRIO config space mapping failure, error %d, on TRIO %d \n " ,
ret , trio_index ) ;
2013-08-05 13:18:02 -04:00
ret = - ENOMEM ;
goto trio_mmio_mapping_failure ;
}
/* Check the port strap state which will override the BIB setting. */
for ( mac = 0 ; mac < TILEGX_TRIO_PCIES ; mac + + ) {
TRIO_PCIE_INTFC_PORT_CONFIG_t port_config ;
unsigned int reg_offset ;
/* Ignore ports that are not specified in the BIB. */
2013-08-05 13:32:52 -04:00
if ( ! pcie_ports [ trio_index ] . ports [ mac ] . allow_rc & &
! pcie_ports [ trio_index ] . ports [ mac ] . allow_ep )
2013-08-05 13:18:02 -04:00
continue ;
reg_offset =
( TRIO_PCIE_INTFC_PORT_CONFIG < <
TRIO_CFG_REGION_ADDR__REG_SHIFT ) |
( TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_INTERFACE < <
TRIO_CFG_REGION_ADDR__INTFC_SHIFT ) |
( mac < < TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT ) ;
port_config . word =
__gxio_mmio_read ( context - > mmio_base_mac + reg_offset ) ;
if ( port_config . strap_state ! = AUTO_CONFIG_RC & &
port_config . strap_state ! = AUTO_CONFIG_RC_G1 ) {
/*
* If this is really intended to be an EP port , record
* it so that the endpoint driver will know about it .
*/
if ( port_config . strap_state = = AUTO_CONFIG_EP | |
port_config . strap_state = = AUTO_CONFIG_EP_G1 )
2013-08-05 13:32:52 -04:00
pcie_ports [ trio_index ] . ports [ mac ] . allow_ep = 1 ;
2013-08-05 13:18:02 -04:00
}
}
2012-04-07 17:10:17 -04:00
return ret ;
2013-08-05 13:18:02 -04:00
trio_mmio_mapping_failure :
get_port_property_failure :
2012-04-07 17:10:17 -04:00
asid_alloc_failure :
# ifdef USE_SHARED_PCIE_CONFIG_REGION
pio_alloc_failure :
# endif
hv_dev_close ( context - > fd ) ;
2013-08-05 13:18:02 -04:00
gxio_trio_init_failure :
context - > fd = - 1 ;
2012-04-07 17:10:17 -04:00
return ret ;
}
2013-08-05 13:18:02 -04:00
static int __init tile_trio_init ( void )
{
int i ;
/* We loop over all the TRIO shims. */
for ( i = 0 ; i < TILEGX_NUM_TRIO ; i + + ) {
if ( tile_pcie_open ( i ) < 0 )
continue ;
num_trio_shims + + ;
}
return 0 ;
}
postcore_initcall ( tile_trio_init ) ;
2013-08-05 13:29:34 -04:00
static void tilegx_legacy_irq_ack ( struct irq_data * d )
2012-04-07 17:10:17 -04:00
{
__insn_mtspr ( SPR_IPI_EVENT_RESET_K , 1UL < < d - > irq ) ;
}
2013-08-05 13:29:34 -04:00
static void tilegx_legacy_irq_mask ( struct irq_data * d )
2012-04-07 17:10:17 -04:00
{
__insn_mtspr ( SPR_IPI_MASK_SET_K , 1UL < < d - > irq ) ;
}
2013-08-05 13:29:34 -04:00
static void tilegx_legacy_irq_unmask ( struct irq_data * d )
2012-04-07 17:10:17 -04:00
{
__insn_mtspr ( SPR_IPI_MASK_RESET_K , 1UL < < d - > irq ) ;
}
static struct irq_chip tilegx_legacy_irq_chip = {
. name = " tilegx_legacy_irq " ,
. irq_ack = tilegx_legacy_irq_ack ,
. irq_mask = tilegx_legacy_irq_mask ,
. irq_unmask = tilegx_legacy_irq_unmask ,
/* TBD: support set_affinity. */
} ;
/*
* This is a wrapper function of the kernel level - trigger interrupt
* handler handle_level_irq ( ) for PCI legacy interrupts . The TRIO
* is configured such that only INTx Assert interrupts are proxied
* to Linux which just calls handle_level_irq ( ) after clearing the
* MAC INTx Assert status bit associated with this interrupt .
*/
2015-09-14 10:42:37 +02:00
static void trio_handle_level_irq ( struct irq_desc * desc )
2012-04-07 17:10:17 -04:00
{
struct pci_controller * controller = irq_desc_get_handler_data ( desc ) ;
gxio_trio_context_t * trio_context = controller - > trio ;
uint64_t intx = ( uint64_t ) irq_desc_get_chip_data ( desc ) ;
int mac = controller - > mac ;
unsigned int reg_offset ;
uint64_t level_mask ;
2015-09-14 10:42:37 +02:00
handle_level_irq ( desc ) ;
2012-04-07 17:10:17 -04:00
/*
* Clear the INTx Level status , otherwise future interrupts are
* not sent .
*/
reg_offset = ( TRIO_PCIE_INTFC_MAC_INT_STS < <
TRIO_CFG_REGION_ADDR__REG_SHIFT ) |
( TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_INTERFACE < <
TRIO_CFG_REGION_ADDR__INTFC_SHIFT ) |
( mac < < TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT ) ;
level_mask = TRIO_PCIE_INTFC_MAC_INT_STS__INT_LEVEL_MASK < < intx ;
__gxio_mmio_write ( trio_context - > mmio_base_mac + reg_offset , level_mask ) ;
}
/*
* Create kernel irqs and set up the handlers for the legacy interrupts .
* Also some minimum initialization for the MSI support .
*/
2012-12-21 14:06:37 -08:00
static int tile_init_irqs ( struct pci_controller * controller )
2012-04-07 17:10:17 -04:00
{
int i ;
int j ;
int irq ;
int result ;
cpumask_copy ( & intr_cpus_map , cpu_online_mask ) ;
for ( i = 0 ; i < 4 ; i + + ) {
gxio_trio_context_t * context = controller - > trio ;
int cpu ;
/* Ask the kernel to allocate an IRQ. */
2014-05-07 15:44:16 +00:00
irq = irq_alloc_hwirq ( - 1 ) ;
if ( ! irq ) {
2012-04-07 17:10:17 -04:00
pr_err ( " PCI: no free irq vectors, failed for %d \n " , i ) ;
goto free_irqs ;
}
controller - > irq_intx_table [ i ] = irq ;
/* Distribute the 4 IRQs to different tiles. */
cpu = tile_irq_cpu ( irq ) ;
/* Configure the TRIO intr binding for this IRQ. */
result = gxio_trio_config_legacy_intr ( context , cpu_x ( cpu ) ,
cpu_y ( cpu ) , KERNEL_PL ,
irq , controller - > mac , i ) ;
if ( result < 0 ) {
pr_err ( " PCI: MAC intx config failed for %d \n " , i ) ;
goto free_irqs ;
}
2013-08-05 13:29:34 -04:00
/* Register the IRQ handler with the kernel. */
2012-04-07 17:10:17 -04:00
irq_set_chip_and_handler ( irq , & tilegx_legacy_irq_chip ,
trio_handle_level_irq ) ;
irq_set_chip_data ( irq , ( void * ) ( uint64_t ) i ) ;
irq_set_handler_data ( irq , controller ) ;
}
return 0 ;
free_irqs :
for ( j = 0 ; j < i ; j + + )
2014-05-07 15:44:16 +00:00
irq_free_hwirq ( controller - > irq_intx_table [ j ] ) ;
2012-04-07 17:10:17 -04:00
return - 1 ;
}
2013-08-05 13:18:02 -04:00
/*
* Return 1 if the port is strapped to operate in RC mode .
*/
static int
strapped_for_rc ( gxio_trio_context_t * trio_context , int mac )
{
TRIO_PCIE_INTFC_PORT_CONFIG_t port_config ;
unsigned int reg_offset ;
/* Check the port configuration. */
reg_offset =
( TRIO_PCIE_INTFC_PORT_CONFIG < <
TRIO_CFG_REGION_ADDR__REG_SHIFT ) |
( TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_INTERFACE < <
TRIO_CFG_REGION_ADDR__INTFC_SHIFT ) |
( mac < < TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT ) ;
port_config . word =
__gxio_mmio_read ( trio_context - > mmio_base_mac + reg_offset ) ;
if ( port_config . strap_state = = AUTO_CONFIG_RC | |
port_config . strap_state = = AUTO_CONFIG_RC_G1 )
return 1 ;
else
return 0 ;
}
2012-04-07 17:10:17 -04:00
/*
* Find valid controllers and fill in pci_controller structs for each
* of them .
*
2013-08-05 13:18:02 -04:00
* Return the number of controllers discovered .
2012-04-07 17:10:17 -04:00
*/
int __init tile_pci_init ( void )
{
int ctl_index = 0 ;
int i , j ;
if ( ! pci_probe ) {
pr_info ( " PCI: disabled by boot argument \n " ) ;
return 0 ;
}
pr_info ( " PCI: Searching for controllers... \n " ) ;
if ( num_trio_shims = = 0 | | sim_is_simulator ( ) )
return 0 ;
/*
2013-08-05 13:32:52 -04:00
* Now determine which PCIe ports are configured to operate in RC
2016-05-21 14:10:49 +02:00
* mode . There is a difference in the port configuration capability
2013-08-05 14:27:05 -04:00
* between the Gx36 and Gx72 devices .
*
* The Gx36 has configuration capability for each of the 3 PCIe
* interfaces ( disable , auto endpoint , auto RC , etc . ) .
* On the Gx72 , you can only select one of the 3 PCIe interfaces per
* TRIO to train automatically . Further , the allowable training modes
* are reduced to four options ( auto endpoint , auto RC , stream x1 ,
* stream x4 ) .
*
* For Gx36 ports , it must be allowed to be in RC mode by the
2013-08-05 13:32:52 -04:00
* Board Information Block , and the hardware strapping pins must be
* set to RC mode .
2013-08-05 14:27:05 -04:00
*
* For Gx72 ports , the port will operate in RC mode if either of the
* following is true :
* 1. It is allowed to be in RC mode by the Board Information Block ,
* and the BIB doesn ' t allow the EP mode .
* 2. It is allowed to be in either the RC or the EP mode by the BIB ,
* and the hardware strapping pin is set to RC mode .
2012-04-07 17:10:17 -04:00
*/
for ( i = 0 ; i < TILEGX_NUM_TRIO ; i + + ) {
gxio_trio_context_t * context = & trio_contexts [ i ] ;
if ( context - > fd < 0 )
continue ;
for ( j = 0 ; j < TILEGX_TRIO_PCIES ; j + + ) {
2013-08-05 14:27:05 -04:00
int is_rc = 0 ;
if ( pcie_ports [ i ] . is_gx72 & &
pcie_ports [ i ] . ports [ j ] . allow_rc ) {
if ( ! pcie_ports [ i ] . ports [ j ] . allow_ep | |
strapped_for_rc ( context , j ) )
is_rc = 1 ;
} else if ( pcie_ports [ i ] . ports [ j ] . allow_rc & &
strapped_for_rc ( context , j ) ) {
is_rc = 1 ;
}
if ( is_rc ) {
2012-04-07 17:10:17 -04:00
pcie_rc [ i ] [ j ] = 1 ;
num_rc_controllers + + ;
}
}
}
2013-08-05 13:29:34 -04:00
/* Return if no PCIe ports are configured to operate in RC mode. */
2012-04-07 17:10:17 -04:00
if ( num_rc_controllers = = 0 )
return 0 ;
2013-08-05 13:29:34 -04:00
/* Set the TRIO pointer and MAC index for each PCIe RC port. */
2012-04-07 17:10:17 -04:00
for ( i = 0 ; i < TILEGX_NUM_TRIO ; i + + ) {
for ( j = 0 ; j < TILEGX_TRIO_PCIES ; j + + ) {
if ( pcie_rc [ i ] [ j ] ) {
pci_controllers [ ctl_index ] . trio =
& trio_contexts [ i ] ;
pci_controllers [ ctl_index ] . mac = j ;
pci_controllers [ ctl_index ] . trio_index = i ;
ctl_index + + ;
if ( ctl_index = = num_rc_controllers )
goto out ;
}
}
}
out :
2013-08-05 13:29:34 -04:00
/* Configure each PCIe RC port. */
2012-04-07 17:10:17 -04:00
for ( i = 0 ; i < num_rc_controllers ; i + + ) {
2013-08-05 13:29:34 -04:00
/* Configure the PCIe MAC to run in RC mode. */
2012-04-07 17:10:17 -04:00
struct pci_controller * controller = & pci_controllers [ i ] ;
controller - > index = i ;
controller - > ops = & tile_cfg_ops ;
2013-08-02 16:45:22 -04:00
controller - > io_space . start = PCIBIOS_MIN_IO +
( i * IO_SPACE_SIZE ) ;
controller - > io_space . end = controller - > io_space . start +
IO_SPACE_SIZE - 1 ;
BUG_ON ( controller - > io_space . end > IO_SPACE_LIMIT ) ;
controller - > io_space . flags = IORESOURCE_IO ;
snprintf ( controller - > io_space_name ,
sizeof ( controller - > io_space_name ) ,
" PCI I/O domain %d " , i ) ;
controller - > io_space . name = controller - > io_space_name ;
2012-07-18 12:06:19 -04:00
/*
* The PCI memory resource is located above the PA space .
* For every host bridge , the BAR window or the MMIO aperture
* is in range [ 3 GB , 4 GB - 1 ] of a 4 GB space beyond the
* PA space .
*/
controller - > mem_offset = TILE_PCI_MEM_START +
( i * TILE_PCI_BAR_WINDOW_TOP ) ;
controller - > mem_space . start = controller - > mem_offset +
TILE_PCI_BAR_WINDOW_TOP - TILE_PCI_BAR_WINDOW_SIZE ;
controller - > mem_space . end = controller - > mem_offset +
TILE_PCI_BAR_WINDOW_TOP - 1 ;
controller - > mem_space . flags = IORESOURCE_MEM ;
snprintf ( controller - > mem_space_name ,
sizeof ( controller - > mem_space_name ) ,
" PCI mem domain %d " , i ) ;
controller - > mem_space . name = controller - > mem_space_name ;
2012-04-07 17:10:17 -04:00
}
return num_rc_controllers ;
}
/*
* ( pin - 1 ) converts from the PCI standard ' s [ 1 : 4 ] convention to
* a normal [ 0 : 3 ] range .
*/
static int tile_map_irq ( const struct pci_dev * dev , u8 device , u8 pin )
{
struct pci_controller * controller =
( struct pci_controller * ) dev - > sysdata ;
return controller - > irq_intx_table [ pin - 1 ] ;
}
2012-12-21 14:06:37 -08:00
static void fixup_read_and_payload_sizes ( struct pci_controller * controller )
2012-04-07 17:10:17 -04:00
{
gxio_trio_context_t * trio_context = controller - > trio ;
struct pci_bus * root_bus = controller - > root_bus ;
TRIO_PCIE_RC_DEVICE_CONTROL_t dev_control ;
TRIO_PCIE_RC_DEVICE_CAP_t rc_dev_cap ;
unsigned int reg_offset ;
struct pci_bus * child ;
int mac ;
int err ;
mac = controller - > mac ;
2013-08-05 13:29:34 -04:00
/* Set our max read request size to be 4KB. */
2012-04-07 17:10:17 -04:00
reg_offset =
( TRIO_PCIE_RC_DEVICE_CONTROL < <
TRIO_CFG_REGION_ADDR__REG_SHIFT ) |
( TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_STANDARD < <
TRIO_CFG_REGION_ADDR__INTFC_SHIFT ) |
( mac < < TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT ) ;
dev_control . word = __gxio_mmio_read32 ( trio_context - > mmio_base_mac +
2013-08-05 13:29:34 -04:00
reg_offset ) ;
2012-04-07 17:10:17 -04:00
dev_control . max_read_req_sz = 5 ;
__gxio_mmio_write32 ( trio_context - > mmio_base_mac + reg_offset ,
2013-08-05 13:29:34 -04:00
dev_control . word ) ;
2012-04-07 17:10:17 -04:00
/*
* Set the max payload size supported by this Gx PCIe MAC .
* Though Gx PCIe supports Max Payload Size of up to 1024 bytes ,
* experiments have shown that setting MPS to 256 yields the
* best performance .
*/
reg_offset =
( TRIO_PCIE_RC_DEVICE_CAP < <
TRIO_CFG_REGION_ADDR__REG_SHIFT ) |
( TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_STANDARD < <
TRIO_CFG_REGION_ADDR__INTFC_SHIFT ) |
( mac < < TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT ) ;
rc_dev_cap . word = __gxio_mmio_read32 ( trio_context - > mmio_base_mac +
2013-08-05 13:29:34 -04:00
reg_offset ) ;
2012-04-07 17:10:17 -04:00
rc_dev_cap . mps_sup = 1 ;
__gxio_mmio_write32 ( trio_context - > mmio_base_mac + reg_offset ,
2013-08-05 13:29:34 -04:00
rc_dev_cap . word ) ;
2012-04-07 17:10:17 -04:00
/* Configure PCI Express MPS setting. */
2013-08-22 11:24:44 +08:00
list_for_each_entry ( child , & root_bus - > children , node )
pcie_bus_configure_settings ( child ) ;
2012-04-07 17:10:17 -04:00
/*
* Set the mac_config register in trio based on the MPS / MRS of the link .
*/
reg_offset =
( TRIO_PCIE_RC_DEVICE_CONTROL < <
TRIO_CFG_REGION_ADDR__REG_SHIFT ) |
( TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_STANDARD < <
TRIO_CFG_REGION_ADDR__INTFC_SHIFT ) |
( mac < < TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT ) ;
dev_control . word = __gxio_mmio_read32 ( trio_context - > mmio_base_mac +
reg_offset ) ;
err = gxio_trio_set_mps_mrs ( trio_context ,
dev_control . max_payload_size ,
dev_control . max_read_req_sz ,
mac ) ;
2013-08-05 13:29:34 -04:00
if ( err < 0 ) {
2014-10-31 10:50:46 -07:00
pr_err ( " PCI: PCIE_CONFIGURE_MAC_MPS_MRS failure, MAC %d on TRIO %d \n " ,
mac , controller - > trio_index ) ;
2012-04-07 17:10:17 -04:00
}
}
2012-12-21 14:06:37 -08:00
static int setup_pcie_rc_delay ( char * str )
2012-04-07 17:10:17 -04:00
{
unsigned long delay = 0 ;
unsigned long trio_index ;
unsigned long mac ;
if ( str = = NULL | | ! isdigit ( * str ) )
return - EINVAL ;
trio_index = simple_strtoul ( str , ( char * * ) & str , 10 ) ;
if ( trio_index > = TILEGX_NUM_TRIO )
return - EINVAL ;
if ( * str ! = ' , ' )
return - EINVAL ;
str + + ;
if ( ! isdigit ( * str ) )
return - EINVAL ;
mac = simple_strtoul ( str , ( char * * ) & str , 10 ) ;
if ( mac > = TILEGX_TRIO_PCIES )
return - EINVAL ;
if ( * str ! = ' \0 ' ) {
if ( * str ! = ' , ' )
return - EINVAL ;
str + + ;
if ( ! isdigit ( * str ) )
return - EINVAL ;
delay = simple_strtoul ( str , ( char * * ) & str , 10 ) ;
}
rc_delay [ trio_index ] [ mac ] = delay ? : DEFAULT_RC_DELAY ;
return 0 ;
}
early_param ( " pcie_rc_delay " , setup_pcie_rc_delay ) ;
2013-08-05 13:29:34 -04:00
/* PCI initialization entry point, called by subsys_initcall. */
2012-04-07 17:10:17 -04:00
int __init pcibios_init ( void )
{
resource_size_t offset ;
LIST_HEAD ( resources ) ;
2012-07-18 12:06:19 -04:00
int next_busno ;
2012-04-07 17:10:17 -04:00
int i ;
2012-06-15 15:23:06 -04:00
tile_pci_init ( ) ;
2013-08-05 13:18:02 -04:00
if ( num_rc_controllers = = 0 )
2012-04-07 17:10:17 -04:00
return 0 ;
/*
* Delay a bit in case devices aren ' t ready . Some devices are
* known to require at least 20 ms here , but we use a more
* conservative value .
*/
msleep ( 250 ) ;
/* Scan all of the recorded PCI controllers. */
2012-07-18 12:06:19 -04:00
for ( next_busno = 0 , i = 0 ; i < num_rc_controllers ; i + + ) {
2012-04-07 17:10:17 -04:00
struct pci_controller * controller = & pci_controllers [ i ] ;
gxio_trio_context_t * trio_context = controller - > trio ;
TRIO_PCIE_INTFC_PORT_STATUS_t port_status ;
TRIO_PCIE_INTFC_TX_FIFO_CTL_t tx_fifo_ctl ;
struct pci_bus * bus ;
unsigned int reg_offset ;
unsigned int class_code_revision ;
int trio_index ;
int mac ;
int ret ;
if ( trio_context - > fd < 0 )
continue ;
trio_index = controller - > trio_index ;
mac = controller - > mac ;
/*
2013-08-02 11:56:44 -04:00
* Check for PCIe link - up status to decide if we need
* to force the link to come up .
2012-04-07 17:10:17 -04:00
*/
reg_offset =
2013-08-02 11:56:44 -04:00
( TRIO_PCIE_INTFC_PORT_STATUS < <
2012-04-07 17:10:17 -04:00
TRIO_CFG_REGION_ADDR__REG_SHIFT ) |
( TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_INTERFACE < <
2013-08-02 11:56:44 -04:00
TRIO_CFG_REGION_ADDR__INTFC_SHIFT ) |
2012-04-07 17:10:17 -04:00
( mac < < TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT ) ;
2013-08-02 11:56:44 -04:00
port_status . word =
2012-04-07 17:10:17 -04:00
__gxio_mmio_read ( trio_context - > mmio_base_mac +
reg_offset ) ;
2013-08-02 11:56:44 -04:00
if ( ! port_status . dl_up ) {
if ( rc_delay [ trio_index ] [ mac ] ) {
2014-10-31 10:50:46 -07:00
pr_info ( " Delaying PCIe RC TRIO init %d sec on MAC %d on TRIO %d \n " ,
2013-08-02 11:56:44 -04:00
rc_delay [ trio_index ] [ mac ] , mac ,
trio_index ) ;
msleep ( rc_delay [ trio_index ] [ mac ] * 1000 ) ;
}
ret = gxio_trio_force_rc_link_up ( trio_context , mac ) ;
if ( ret < 0 )
2014-10-31 10:50:46 -07:00
pr_err ( " PCI: PCIE_FORCE_LINK_UP failure, MAC %d on TRIO %d \n " ,
mac , trio_index ) ;
2012-04-07 17:10:17 -04:00
}
2014-10-31 10:50:46 -07:00
pr_info ( " PCI: Found PCI controller #%d on TRIO %d MAC %d \n " ,
i , trio_index , controller - > mac ) ;
2012-04-07 17:10:17 -04:00
2013-08-05 13:29:34 -04:00
/* Delay the bus probe if needed. */
2013-08-02 11:47:29 -04:00
if ( rc_delay [ trio_index ] [ mac ] ) {
2014-10-31 10:50:46 -07:00
pr_info ( " Delaying PCIe RC bus enumerating %d sec on MAC %d on TRIO %d \n " ,
rc_delay [ trio_index ] [ mac ] , mac , trio_index ) ;
2013-08-02 11:47:29 -04:00
msleep ( rc_delay [ trio_index ] [ mac ] * 1000 ) ;
} else {
/*
* Wait a bit here because some EP devices
* take longer to come up .
*/
msleep ( 1000 ) ;
}
2012-04-07 17:10:17 -04:00
2013-08-05 13:29:34 -04:00
/* Check for PCIe link-up status again. */
2012-04-07 17:10:17 -04:00
port_status . word =
__gxio_mmio_read ( trio_context - > mmio_base_mac +
reg_offset ) ;
if ( ! port_status . dl_up ) {
2013-08-05 13:32:52 -04:00
if ( pcie_ports [ trio_index ] . ports [ mac ] . removable ) {
2013-08-02 16:12:49 -04:00
pr_info ( " PCI: link is down, MAC %d on TRIO %d \n " ,
mac , trio_index ) ;
2014-10-31 10:50:46 -07:00
pr_info ( " This is expected if no PCIe card is connected to this link \n " ) ;
2013-08-02 16:12:49 -04:00
} else
pr_err ( " PCI: link is down, MAC %d on TRIO %d \n " ,
2014-10-31 10:50:46 -07:00
mac , trio_index ) ;
2012-04-07 17:10:17 -04:00
continue ;
}
/*
* Ensure that the link can come out of L1 power down state .
* Strictly speaking , this is needed only in the case of
* heavy RC - initiated DMAs .
*/
reg_offset =
( TRIO_PCIE_INTFC_TX_FIFO_CTL < <
TRIO_CFG_REGION_ADDR__REG_SHIFT ) |
( TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_INTERFACE < <
TRIO_CFG_REGION_ADDR__INTFC_SHIFT ) |
( mac < < TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT ) ;
tx_fifo_ctl . word =
__gxio_mmio_read ( trio_context - > mmio_base_mac +
reg_offset ) ;
tx_fifo_ctl . min_p_credits = 0 ;
__gxio_mmio_write ( trio_context - > mmio_base_mac + reg_offset ,
tx_fifo_ctl . word ) ;
/*
* Change the device ID so that Linux bus crawl doesn ' t confuse
* the internal bridge with any Tilera endpoints .
*/
reg_offset =
( TRIO_PCIE_RC_DEVICE_ID_VEN_ID < <
TRIO_CFG_REGION_ADDR__REG_SHIFT ) |
( TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_STANDARD < <
TRIO_CFG_REGION_ADDR__INTFC_SHIFT ) |
( mac < < TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT ) ;
__gxio_mmio_write32 ( trio_context - > mmio_base_mac + reg_offset ,
( TILERA_GX36_RC_DEV_ID < <
TRIO_PCIE_RC_DEVICE_ID_VEN_ID__DEV_ID_SHIFT ) |
TILERA_VENDOR_ID ) ;
2013-08-05 13:29:34 -04:00
/* Set the internal P2P bridge class code. */
2012-04-07 17:10:17 -04:00
reg_offset =
( TRIO_PCIE_RC_REVISION_ID < <
TRIO_CFG_REGION_ADDR__REG_SHIFT ) |
( TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_STANDARD < <
TRIO_CFG_REGION_ADDR__INTFC_SHIFT ) |
( mac < < TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT ) ;
class_code_revision =
__gxio_mmio_read32 ( trio_context - > mmio_base_mac +
reg_offset ) ;
2013-08-05 13:29:34 -04:00
class_code_revision = ( class_code_revision & 0xff ) |
( PCI_CLASS_BRIDGE_PCI < < 16 ) ;
2012-04-07 17:10:17 -04:00
__gxio_mmio_write32 ( trio_context - > mmio_base_mac +
reg_offset , class_code_revision ) ;
# ifdef USE_SHARED_PCIE_CONFIG_REGION
2013-08-05 13:29:34 -04:00
/* Map in the MMIO space for the PIO region. */
2012-04-07 17:10:17 -04:00
offset = HV_TRIO_PIO_OFFSET ( trio_context - > pio_cfg_index ) |
( ( ( unsigned long long ) mac ) < <
TRIO_TILE_PIO_REGION_SETUP_CFG_ADDR__MAC_SHIFT ) ;
# else
2013-08-05 13:29:34 -04:00
/* Alloc a PIO region for PCI config access per MAC. */
2012-04-07 17:10:17 -04:00
ret = gxio_trio_alloc_pio_regions ( trio_context , 1 , 0 , 0 ) ;
if ( ret < 0 ) {
2014-10-31 10:50:46 -07:00
pr_err ( " PCI: PCI CFG PIO alloc failure for mac %d on TRIO %d, give up \n " ,
mac , trio_index ) ;
2012-04-07 17:10:17 -04:00
continue ;
}
trio_context - > pio_cfg_index [ mac ] = ret ;
2013-08-05 13:29:34 -04:00
/* For PIO CFG, the bus_address_hi parameter is 0. */
2012-04-07 17:10:17 -04:00
ret = gxio_trio_init_pio_region_aux ( trio_context ,
trio_context - > pio_cfg_index [ mac ] ,
mac , 0 , HV_TRIO_PIO_FLAG_CONFIG_SPACE ) ;
if ( ret < 0 ) {
2014-10-31 10:50:46 -07:00
pr_err ( " PCI: PCI CFG PIO init failure for mac %d on TRIO %d, give up \n " ,
mac , trio_index ) ;
2012-04-07 17:10:17 -04:00
continue ;
}
offset = HV_TRIO_PIO_OFFSET ( trio_context - > pio_cfg_index [ mac ] ) |
( ( ( unsigned long long ) mac ) < <
TRIO_TILE_PIO_REGION_SETUP_CFG_ADDR__MAC_SHIFT ) ;
# endif
2013-08-05 14:33:17 -04:00
/*
* To save VMALLOC space , we take advantage of the fact that
* bit 29 in the PIO CFG address format is reserved 0. With
* TRIO_TILE_PIO_REGION_SETUP_CFG_ADDR__MAC_SHIFT being 30 ,
* this cuts VMALLOC space usage from 1 GB to 512 MB per mac .
*/
2012-04-07 17:10:17 -04:00
trio_context - > mmio_base_pio_cfg [ mac ] =
2013-08-05 14:33:17 -04:00
iorpc_ioremap ( trio_context - > fd , offset , ( 1UL < <
( TRIO_TILE_PIO_REGION_SETUP_CFG_ADDR__MAC_SHIFT - 1 ) ) ) ;
2012-04-07 17:10:17 -04:00
if ( trio_context - > mmio_base_pio_cfg [ mac ] = = NULL ) {
pr_err ( " PCI: PIO map failure for mac %d on TRIO %d \n " ,
2014-10-31 10:50:46 -07:00
mac , trio_index ) ;
2012-04-07 17:10:17 -04:00
continue ;
}
2013-08-05 13:29:34 -04:00
/* Initialize the PCIe interrupts. */
2012-04-07 17:10:17 -04:00
if ( tile_init_irqs ( controller ) ) {
pr_err ( " PCI: IRQs init failure for mac %d on TRIO %d \n " ,
mac , trio_index ) ;
continue ;
}
2012-06-15 15:23:06 -04:00
/*
* The PCI memory resource is located above the PA space .
* The memory range for the PCI root bus should not overlap
2013-08-02 16:45:22 -04:00
* with the physical RAM .
2012-06-15 15:23:06 -04:00
*/
2012-07-18 12:06:19 -04:00
pci_add_resource_offset ( & resources , & controller - > mem_space ,
controller - > mem_offset ) ;
2013-08-02 16:45:22 -04:00
pci_add_resource ( & resources , & controller - > io_space ) ;
2012-07-18 12:06:19 -04:00
controller - > first_busno = next_busno ;
bus = pci_scan_root_bus ( NULL , next_busno , controller - > ops ,
2012-04-07 17:10:17 -04:00
controller , & resources ) ;
controller - > root_bus = bus ;
2012-07-25 15:40:50 -04:00
next_busno = bus - > busn_res . end + 1 ;
2012-04-07 17:10:17 -04:00
}
/* Do machine dependent PCI interrupt routing */
pci_fixup_irqs ( pci_common_swizzle , tile_map_irq ) ;
/*
* This comes from the generic Linux PCI driver .
*
* It allocates all of the resources ( I / O memory , etc )
* associated with the devices read in above .
*/
pci_assign_unassigned_resources ( ) ;
/* Record the I/O resources in the PCI controller structure. */
for ( i = 0 ; i < num_rc_controllers ; i + + ) {
struct pci_controller * controller = & pci_controllers [ i ] ;
gxio_trio_context_t * trio_context = controller - > trio ;
struct pci_bus * root_bus = pci_controllers [ i ] . root_bus ;
int ret ;
int j ;
/*
* Skip controllers that are not properly initialized or
* have down links .
*/
if ( root_bus = = NULL )
continue ;
/* Configure the max_payload_size values for this domain. */
fixup_read_and_payload_sizes ( controller ) ;
2013-08-05 13:29:34 -04:00
/* Alloc a PIO region for PCI memory access for each RC port. */
2012-04-07 17:10:17 -04:00
ret = gxio_trio_alloc_pio_regions ( trio_context , 1 , 0 , 0 ) ;
if ( ret < 0 ) {
2014-10-31 10:50:46 -07:00
pr_err ( " PCI: MEM PIO alloc failure on TRIO %d mac %d, give up \n " ,
controller - > trio_index , controller - > mac ) ;
2012-04-07 17:10:17 -04:00
continue ;
}
controller - > pio_mem_index = ret ;
/*
* For PIO MEM , the bus_address_hi parameter is hard - coded 0
* because we always assign 32 - bit PCI bus BAR ranges .
*/
ret = gxio_trio_init_pio_region_aux ( trio_context ,
controller - > pio_mem_index ,
controller - > mac ,
2012-06-15 15:23:06 -04:00
0 ,
2012-04-07 17:10:17 -04:00
0 ) ;
if ( ret < 0 ) {
2014-10-31 10:50:46 -07:00
pr_err ( " PCI: MEM PIO init failure on TRIO %d mac %d, give up \n " ,
controller - > trio_index , controller - > mac ) ;
2012-04-07 17:10:17 -04:00
continue ;
}
2013-08-02 16:45:22 -04:00
# ifdef CONFIG_TILE_PCI_IO
/*
* Alloc a PIO region for PCI I / O space access for each RC port .
*/
ret = gxio_trio_alloc_pio_regions ( trio_context , 1 , 0 , 0 ) ;
if ( ret < 0 ) {
2014-10-31 10:50:46 -07:00
pr_err ( " PCI: I/O PIO alloc failure on TRIO %d mac %d, give up \n " ,
controller - > trio_index , controller - > mac ) ;
2013-08-02 16:45:22 -04:00
continue ;
}
controller - > pio_io_index = ret ;
/*
* For PIO IO , the bus_address_hi parameter is hard - coded 0
* because PCI I / O address space is 32 - bit .
*/
ret = gxio_trio_init_pio_region_aux ( trio_context ,
controller - > pio_io_index ,
controller - > mac ,
0 ,
HV_TRIO_PIO_FLAG_IO_SPACE ) ;
if ( ret < 0 ) {
2014-10-31 10:50:46 -07:00
pr_err ( " PCI: I/O PIO init failure on TRIO %d mac %d, give up \n " ,
controller - > trio_index , controller - > mac ) ;
2013-08-02 16:45:22 -04:00
continue ;
}
# endif
2012-04-07 17:10:17 -04:00
/*
* Configure a Mem - Map region for each memory controller so
* that Linux can map all of its PA space to the PCI bus .
* Use the IOMMU to handle hash - for - home memory .
*/
for_each_online_node ( j ) {
unsigned long start_pfn = node_start_pfn [ j ] ;
unsigned long end_pfn = node_end_pfn [ j ] ;
unsigned long nr_pages = end_pfn - start_pfn ;
ret = gxio_trio_alloc_memory_maps ( trio_context , 1 , 0 ,
0 ) ;
if ( ret < 0 ) {
2014-10-31 10:50:46 -07:00
pr_err ( " PCI: Mem-Map alloc failure on TRIO %d mac %d for MC %d, give up \n " ,
controller - > trio_index , controller - > mac ,
j ) ;
2012-04-07 17:10:17 -04:00
goto alloc_mem_map_failed ;
}
controller - > mem_maps [ j ] = ret ;
/*
* Initialize the Mem - Map and the I / O MMU so that all
* the physical memory can be accessed by the endpoint
* devices . The base bus address is set to the base CPA
2012-06-15 15:23:06 -04:00
* of this memory controller plus an offset ( see pci . h ) .
* The region ' s base VA is set to the base CPA . The
2012-04-07 17:10:17 -04:00
* I / O MMU table essentially translates the CPA to
2012-06-15 15:23:06 -04:00
* the real PA . Implicitly , for node 0 , we create
* a separate Mem - Map region that serves as the inbound
* window for legacy 32 - bit devices . This is a direct
* map of the low 4 GB CPA space .
2012-04-07 17:10:17 -04:00
*/
ret = gxio_trio_init_memory_map_mmu_aux ( trio_context ,
controller - > mem_maps [ j ] ,
start_pfn < < PAGE_SHIFT ,
nr_pages < < PAGE_SHIFT ,
trio_context - > asid ,
controller - > mac ,
2012-06-15 15:23:06 -04:00
( start_pfn < < PAGE_SHIFT ) +
TILE_PCI_MEM_MAP_BASE_OFFSET ,
2012-04-07 17:10:17 -04:00
j ,
GXIO_TRIO_ORDER_MODE_UNORDERED ) ;
if ( ret < 0 ) {
2014-10-31 10:50:46 -07:00
pr_err ( " PCI: Mem-Map init failure on TRIO %d mac %d for MC %d, give up \n " ,
controller - > trio_index , controller - > mac ,
j ) ;
2012-04-07 17:10:17 -04:00
goto alloc_mem_map_failed ;
}
continue ;
alloc_mem_map_failed :
break ;
}
PCI: Assign resources before drivers claim devices (pci_scan_root_bus())
Previously, pci_scan_root_bus() created a root PCI bus, enumerated the
devices on it, and called pci_bus_add_devices(), which made the devices
available for drivers to claim them.
Most callers assigned resources to devices after pci_scan_root_bus()
returns, which may be after drivers have claimed the devices. This is
incorrect; the PCI core should not change device resources while a driver
is managing the device.
Remove pci_bus_add_devices() from pci_scan_root_bus() and do it after any
resource assignment in the callers.
Note that ARM's pci_common_init_dev() already called pci_bus_add_devices()
after pci_scan_root_bus(), so we only need to remove the first call:
pci_common_init_dev
pcibios_init_hw
pci_scan_root_bus
pci_bus_add_devices # first call
pci_bus_assign_resources
pci_bus_add_devices # second call
[bhelgaas: changelog, drop "root_bus" var in alpha common_init_pci(),
return failure earlier in mn10300, add "return" in x86 pcibios_scan_root(),
return early if xtensa platform_pcibios_fixup() fails]
Signed-off-by: Yijing Wang <wangyijing@huawei.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
CC: Richard Henderson <rth@twiddle.net>
CC: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
CC: Matt Turner <mattst88@gmail.com>
CC: David Howells <dhowells@redhat.com>
CC: Tony Luck <tony.luck@intel.com>
CC: Michal Simek <monstr@monstr.eu>
CC: Ralf Baechle <ralf@linux-mips.org>
CC: Koichi Yasutake <yasutake.koichi@jp.panasonic.com>
CC: Sebastian Ott <sebott@linux.vnet.ibm.com>
CC: "David S. Miller" <davem@davemloft.net>
CC: Chris Metcalf <cmetcalf@ezchip.com>
CC: Chris Zankel <chris@zankel.net>
CC: Max Filippov <jcmvbkbc@gmail.com>
CC: Thomas Gleixner <tglx@linutronix.de>
2015-03-16 11:18:56 +08:00
pci_bus_add_devices ( root_bus ) ;
2012-04-07 17:10:17 -04:00
}
return 0 ;
}
subsys_initcall ( pcibios_init ) ;
2013-08-05 13:29:34 -04:00
/* No bus fixups needed. */
2012-12-21 14:06:37 -08:00
void pcibios_fixup_bus ( struct pci_bus * bus )
2012-04-07 17:10:17 -04:00
{
}
2013-08-05 13:29:34 -04:00
/* Process any "pci=" kernel boot arguments. */
2013-08-13 15:17:38 -04:00
char * __init pcibios_setup ( char * str )
2012-04-07 17:10:17 -04:00
{
if ( ! strcmp ( str , " off " ) ) {
pci_probe = 0 ;
return NULL ;
}
return str ;
}
2013-08-30 10:12:36 -04:00
/*
* Called for each device after PCI setup is done .
* We initialize the PCI device capabilities conservatively , assuming that
* all devices can only address the 32 - bit DMA space . The exception here is
* that the device dma_offset is set to the value that matches the 64 - bit
* capable devices . This is OK because dma_offset is not used by legacy
* dma_ops , nor by the hybrid dma_ops ' s streaming DMAs , which are 64 - bit ops .
* This implementation matches the kernel design of setting PCI devices '
* coherent_dma_mask to 0xffffffffull by default , allowing the device drivers
* to skip calling pci_set_consistent_dma_mask ( DMA_BIT_MASK ( 32 ) ) .
*/
2012-10-25 16:36:11 -04:00
static void pcibios_fixup_final ( struct pci_dev * pdev )
2012-06-15 15:23:06 -04:00
{
2013-08-30 10:12:36 -04:00
set_dma_ops ( & pdev - > dev , gx_legacy_pci_dma_map_ops ) ;
2012-06-15 15:23:06 -04:00
set_dma_offset ( & pdev - > dev , TILE_PCI_MEM_MAP_BASE_OFFSET ) ;
pdev - > dev . archdata . max_direct_dma_addr =
TILE_PCI_MAX_DIRECT_DMA_ADDRESS ;
2013-08-30 10:12:36 -04:00
pdev - > dev . coherent_dma_mask = TILE_PCI_MAX_DIRECT_DMA_ADDRESS ;
2012-06-15 15:23:06 -04:00
}
DECLARE_PCI_FIXUP_FINAL ( PCI_ANY_ID , PCI_ANY_ID , pcibios_fixup_final ) ;
2012-04-07 17:10:17 -04:00
/* Map a PCI MMIO bus address into VA space. */
void __iomem * ioremap ( resource_size_t phys_addr , unsigned long size )
{
struct pci_controller * controller = NULL ;
resource_size_t bar_start ;
resource_size_t bar_end ;
resource_size_t offset ;
resource_size_t start ;
resource_size_t end ;
int trio_fd ;
2013-08-05 13:18:34 -04:00
int i ;
2012-04-07 17:10:17 -04:00
start = phys_addr ;
end = phys_addr + size - 1 ;
/*
2013-08-05 13:18:34 -04:00
* By searching phys_addr in each controller ' s mem_space , we can
2012-04-07 17:10:17 -04:00
* determine the controller that should accept the PCI memory access .
*/
for ( i = 0 ; i < num_rc_controllers ; i + + ) {
/*
* Skip controllers that are not properly initialized or
* have down links .
*/
if ( pci_controllers [ i ] . root_bus = = NULL )
continue ;
2013-08-05 13:18:34 -04:00
bar_start = pci_controllers [ i ] . mem_space . start ;
bar_end = pci_controllers [ i ] . mem_space . end ;
2012-04-07 17:10:17 -04:00
2013-08-05 13:18:34 -04:00
if ( ( start > = bar_start ) & & ( end < = bar_end ) ) {
controller = & pci_controllers [ i ] ;
break ;
2012-04-07 17:10:17 -04:00
}
}
if ( controller = = NULL )
return NULL ;
trio_fd = controller - > trio - > fd ;
2012-07-18 12:06:19 -04:00
/* Convert the resource start to the bus address offset. */
start = phys_addr - controller - > mem_offset ;
offset = HV_TRIO_PIO_OFFSET ( controller - > pio_mem_index ) + start ;
2012-04-07 17:10:17 -04:00
2013-08-05 13:29:34 -04:00
/* We need to keep the PCI bus address's in-page offset in the VA. */
2012-04-07 17:10:17 -04:00
return iorpc_ioremap ( trio_fd , offset , size ) +
2013-08-02 16:45:22 -04:00
( start & ( PAGE_SIZE - 1 ) ) ;
2012-04-07 17:10:17 -04:00
}
EXPORT_SYMBOL ( ioremap ) ;
2013-08-02 16:45:22 -04:00
# ifdef CONFIG_TILE_PCI_IO
/* Map a PCI I/O address into VA space. */
void __iomem * ioport_map ( unsigned long port , unsigned int size )
{
struct pci_controller * controller = NULL ;
resource_size_t bar_start ;
resource_size_t bar_end ;
resource_size_t offset ;
resource_size_t start ;
resource_size_t end ;
int trio_fd ;
int i ;
start = port ;
end = port + size - 1 ;
/*
2013-08-05 13:18:34 -04:00
* By searching the port in each controller ' s io_space , we can
* determine the controller that should accept the PCI I / O access .
2013-08-02 16:45:22 -04:00
*/
for ( i = 0 ; i < num_rc_controllers ; i + + ) {
/*
* Skip controllers that are not properly initialized or
* have down links .
*/
if ( pci_controllers [ i ] . root_bus = = NULL )
continue ;
2013-08-05 13:18:34 -04:00
bar_start = pci_controllers [ i ] . io_space . start ;
bar_end = pci_controllers [ i ] . io_space . end ;
2013-08-02 16:45:22 -04:00
if ( ( start > = bar_start ) & & ( end < = bar_end ) ) {
controller = & pci_controllers [ i ] ;
2013-08-05 13:18:34 -04:00
break ;
2013-08-02 16:45:22 -04:00
}
}
if ( controller = = NULL )
return NULL ;
trio_fd = controller - > trio - > fd ;
/* Convert the resource start to the bus address offset. */
port - = controller - > io_space . start ;
offset = HV_TRIO_PIO_OFFSET ( controller - > pio_io_index ) + port ;
2013-08-05 13:29:34 -04:00
/* We need to keep the PCI bus address's in-page offset in the VA. */
2013-08-02 16:45:22 -04:00
return iorpc_ioremap ( trio_fd , offset , size ) + ( port & ( PAGE_SIZE - 1 ) ) ;
}
EXPORT_SYMBOL ( ioport_map ) ;
void ioport_unmap ( void __iomem * addr )
{
iounmap ( addr ) ;
}
EXPORT_SYMBOL ( ioport_unmap ) ;
# endif
2012-04-07 17:10:17 -04:00
void pci_iounmap ( struct pci_dev * dev , void __iomem * addr )
{
iounmap ( addr ) ;
}
EXPORT_SYMBOL ( pci_iounmap ) ;
/****************************************************************
*
* Tile PCI config space read / write routines
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
* These are the normal read and write ops
* These are expanded with macros from pci_bus_read_config_byte ( ) etc .
*
* devfn is the combined PCI device & function .
*
* offset is in bytes , from the start of config space for the
* specified bus & device .
*/
2012-12-21 14:06:37 -08:00
static int tile_cfg_read ( struct pci_bus * bus , unsigned int devfn , int offset ,
int size , u32 * val )
2012-04-07 17:10:17 -04:00
{
struct pci_controller * controller = bus - > sysdata ;
gxio_trio_context_t * trio_context = controller - > trio ;
int busnum = bus - > number & 0xff ;
int device = PCI_SLOT ( devfn ) ;
int function = PCI_FUNC ( devfn ) ;
int config_type = 1 ;
TRIO_TILE_PIO_REGION_SETUP_CFG_ADDR_t cfg_addr ;
void * mmio_addr ;
/*
2012-07-18 12:06:19 -04:00
* Map all accesses to the local device on root bus into the
2012-04-07 17:10:17 -04:00
* MMIO space of the MAC . Accesses to the downstream devices
* go to the PIO space .
*/
2012-07-18 12:06:19 -04:00
if ( pci_is_root_bus ( bus ) ) {
2012-04-07 17:10:17 -04:00
if ( device = = 0 ) {
/*
* This is the internal downstream P2P bridge ,
* access directly .
*/
unsigned int reg_offset ;
reg_offset = ( ( offset & 0xFFF ) < <
TRIO_CFG_REGION_ADDR__REG_SHIFT ) |
( TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_PROTECTED
< < TRIO_CFG_REGION_ADDR__INTFC_SHIFT ) |
( controller - > mac < <
TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT ) ;
mmio_addr = trio_context - > mmio_base_mac + reg_offset ;
goto valid_device ;
} else {
/*
* We fake an empty device for ( device > 0 ) ,
* since there is only one device on bus 0.
*/
goto invalid_device ;
}
}
/*
2012-07-18 12:06:19 -04:00
* Accesses to the directly attached device have to be
2012-04-07 17:10:17 -04:00
* sent as type - 0 configs .
*/
2012-07-18 12:06:19 -04:00
if ( busnum = = ( controller - > first_busno + 1 ) ) {
2012-04-07 17:10:17 -04:00
/*
* There is only one device off of our built - in P2P bridge .
*/
if ( device ! = 0 )
goto invalid_device ;
config_type = 0 ;
}
cfg_addr . word = 0 ;
cfg_addr . reg_addr = ( offset & 0xFFF ) ;
cfg_addr . fn = function ;
cfg_addr . dev = device ;
cfg_addr . bus = busnum ;
cfg_addr . type = config_type ;
/*
* Note that we don ' t set the mac field in cfg_addr because the
* mapping is per port .
*/
mmio_addr = trio_context - > mmio_base_pio_cfg [ controller - > mac ] +
2013-08-05 13:29:34 -04:00
cfg_addr . word ;
2012-04-07 17:10:17 -04:00
valid_device :
switch ( size ) {
case 4 :
* val = __gxio_mmio_read32 ( mmio_addr ) ;
break ;
case 2 :
* val = __gxio_mmio_read16 ( mmio_addr ) ;
break ;
case 1 :
* val = __gxio_mmio_read8 ( mmio_addr ) ;
break ;
default :
return PCIBIOS_FUNC_NOT_SUPPORTED ;
}
TRACE_CFG_RD ( size , * val , busnum , device , function , offset ) ;
return 0 ;
invalid_device :
switch ( size ) {
case 4 :
* val = 0xFFFFFFFF ;
break ;
case 2 :
* val = 0xFFFF ;
break ;
case 1 :
* val = 0xFF ;
break ;
default :
return PCIBIOS_FUNC_NOT_SUPPORTED ;
}
return 0 ;
}
/*
2016-03-04 11:22:24 -08:00
* See tile_cfg_read ( ) for relevant comments .
2012-04-07 17:10:17 -04:00
* Note that " val " is the value to write , not a pointer to that value .
*/
2012-12-21 14:06:37 -08:00
static int tile_cfg_write ( struct pci_bus * bus , unsigned int devfn , int offset ,
int size , u32 val )
2012-04-07 17:10:17 -04:00
{
struct pci_controller * controller = bus - > sysdata ;
gxio_trio_context_t * trio_context = controller - > trio ;
int busnum = bus - > number & 0xff ;
int device = PCI_SLOT ( devfn ) ;
int function = PCI_FUNC ( devfn ) ;
int config_type = 1 ;
TRIO_TILE_PIO_REGION_SETUP_CFG_ADDR_t cfg_addr ;
void * mmio_addr ;
u32 val_32 = ( u32 ) val ;
u16 val_16 = ( u16 ) val ;
u8 val_8 = ( u8 ) val ;
/*
2012-07-18 12:06:19 -04:00
* Map all accesses to the local device on root bus into the
2012-04-07 17:10:17 -04:00
* MMIO space of the MAC . Accesses to the downstream devices
* go to the PIO space .
*/
2012-07-18 12:06:19 -04:00
if ( pci_is_root_bus ( bus ) ) {
2012-04-07 17:10:17 -04:00
if ( device = = 0 ) {
/*
* This is the internal downstream P2P bridge ,
* access directly .
*/
unsigned int reg_offset ;
reg_offset = ( ( offset & 0xFFF ) < <
TRIO_CFG_REGION_ADDR__REG_SHIFT ) |
( TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_PROTECTED
< < TRIO_CFG_REGION_ADDR__INTFC_SHIFT ) |
( controller - > mac < <
TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT ) ;
mmio_addr = trio_context - > mmio_base_mac + reg_offset ;
goto valid_device ;
} else {
/*
* We fake an empty device for ( device > 0 ) ,
* since there is only one device on bus 0.
*/
goto invalid_device ;
}
}
/*
2012-07-18 12:06:19 -04:00
* Accesses to the directly attached device have to be
2012-04-07 17:10:17 -04:00
* sent as type - 0 configs .
*/
2012-07-18 12:06:19 -04:00
if ( busnum = = ( controller - > first_busno + 1 ) ) {
2012-04-07 17:10:17 -04:00
/*
* There is only one device off of our built - in P2P bridge .
*/
if ( device ! = 0 )
goto invalid_device ;
config_type = 0 ;
}
cfg_addr . word = 0 ;
cfg_addr . reg_addr = ( offset & 0xFFF ) ;
cfg_addr . fn = function ;
cfg_addr . dev = device ;
cfg_addr . bus = busnum ;
cfg_addr . type = config_type ;
/*
* Note that we don ' t set the mac field in cfg_addr because the
* mapping is per port .
*/
mmio_addr = trio_context - > mmio_base_pio_cfg [ controller - > mac ] +
cfg_addr . word ;
valid_device :
switch ( size ) {
case 4 :
__gxio_mmio_write32 ( mmio_addr , val_32 ) ;
TRACE_CFG_WR ( size , val_32 , busnum , device , function , offset ) ;
break ;
case 2 :
__gxio_mmio_write16 ( mmio_addr , val_16 ) ;
TRACE_CFG_WR ( size , val_16 , busnum , device , function , offset ) ;
break ;
case 1 :
__gxio_mmio_write8 ( mmio_addr , val_8 ) ;
TRACE_CFG_WR ( size , val_8 , busnum , device , function , offset ) ;
break ;
default :
return PCIBIOS_FUNC_NOT_SUPPORTED ;
}
invalid_device :
return 0 ;
}
static struct pci_ops tile_cfg_ops = {
. read = tile_cfg_read ,
. write = tile_cfg_write ,
} ;
2013-08-05 13:29:34 -04:00
/* MSI support starts here. */
static unsigned int tilegx_msi_startup ( struct irq_data * d )
2012-04-07 17:10:17 -04:00
{
2015-06-01 16:05:42 +08:00
if ( irq_data_get_msi_desc ( d ) )
2014-11-23 12:23:20 +01:00
pci_msi_unmask_irq ( d ) ;
2012-04-07 17:10:17 -04:00
return 0 ;
}
2013-08-05 13:29:34 -04:00
static void tilegx_msi_ack ( struct irq_data * d )
2012-04-07 17:10:17 -04:00
{
__insn_mtspr ( SPR_IPI_EVENT_RESET_K , 1UL < < d - > irq ) ;
}
2013-08-05 13:29:34 -04:00
static void tilegx_msi_mask ( struct irq_data * d )
2012-04-07 17:10:17 -04:00
{
2014-11-23 12:23:20 +01:00
pci_msi_mask_irq ( d ) ;
2012-04-07 17:10:17 -04:00
__insn_mtspr ( SPR_IPI_MASK_SET_K , 1UL < < d - > irq ) ;
}
2013-08-05 13:29:34 -04:00
static void tilegx_msi_unmask ( struct irq_data * d )
2012-04-07 17:10:17 -04:00
{
__insn_mtspr ( SPR_IPI_MASK_RESET_K , 1UL < < d - > irq ) ;
2014-11-23 12:23:20 +01:00
pci_msi_unmask_irq ( d ) ;
2012-04-07 17:10:17 -04:00
}
static struct irq_chip tilegx_msi_chip = {
. name = " tilegx_msi " ,
. irq_startup = tilegx_msi_startup ,
. irq_ack = tilegx_msi_ack ,
. irq_mask = tilegx_msi_mask ,
. irq_unmask = tilegx_msi_unmask ,
/* TBD: support set_affinity. */
} ;
int arch_setup_msi_irq ( struct pci_dev * pdev , struct msi_desc * desc )
{
struct pci_controller * controller ;
gxio_trio_context_t * trio_context ;
struct msi_msg msg ;
int default_irq ;
uint64_t mem_map_base ;
uint64_t mem_map_limit ;
u64 msi_addr ;
int mem_map ;
int cpu ;
int irq ;
int ret ;
2014-05-07 15:44:16 +00:00
irq = irq_alloc_hwirq ( - 1 ) ;
if ( ! irq )
return - ENOSPC ;
2012-04-07 17:10:17 -04:00
/*
* Since we use a 64 - bit Mem - Map to accept the MSI write , we fail
* devices that are not capable of generating a 64 - bit message address .
* These devices will fall back to using the legacy interrupts .
* Most PCIe endpoint devices do support 64 - bit message addressing .
*/
if ( desc - > msi_attrib . is_64 = = 0 ) {
2014-10-31 10:50:46 -07:00
dev_info ( & pdev - > dev , " 64-bit MSI message address not supported, falling back to legacy interrupts \n " ) ;
2012-04-07 17:10:17 -04:00
ret = - ENOMEM ;
goto is_64_failure ;
}
default_irq = desc - > msi_attrib . default_irq ;
controller = irq_get_handler_data ( default_irq ) ;
BUG_ON ( ! controller ) ;
trio_context = controller - > trio ;
/*
2013-08-02 12:55:15 -04:00
* Allocate a scatter - queue that will accept the MSI write and
* trigger the TILE - side interrupts . We use the scatter - queue regions
* before the mem map regions , because the latter are needed by more
* applications .
2012-04-07 17:10:17 -04:00
*/
2013-08-02 12:55:15 -04:00
mem_map = gxio_trio_alloc_scatter_queues ( trio_context , 1 , 0 , 0 ) ;
if ( mem_map > = 0 ) {
TRIO_MAP_SQ_DOORBELL_FMT_t doorbell_template = { {
. pop = 0 ,
. doorbell = 1 ,
} } ;
mem_map + = TRIO_NUM_MAP_MEM_REGIONS ;
mem_map_base = MEM_MAP_INTR_REGIONS_BASE +
mem_map * MEM_MAP_INTR_REGION_SIZE ;
mem_map_limit = mem_map_base + MEM_MAP_INTR_REGION_SIZE - 1 ;
msi_addr = mem_map_base + MEM_MAP_INTR_REGION_SIZE - 8 ;
msg . data = ( unsigned int ) doorbell_template . word ;
} else {
/* SQ regions are out, allocate from map mem regions. */
mem_map = gxio_trio_alloc_memory_maps ( trio_context , 1 , 0 , 0 ) ;
if ( mem_map < 0 ) {
2014-10-31 10:50:46 -07:00
dev_info ( & pdev - > dev , " %s Mem-Map alloc failure - failed to initialize MSI interrupts - falling back to legacy interrupts \n " ,
desc - > msi_attrib . is_msix ? " MSI-X " : " MSI " ) ;
2013-08-02 12:55:15 -04:00
ret = - ENOMEM ;
goto msi_mem_map_alloc_failure ;
}
2012-04-07 17:10:17 -04:00
2013-08-02 12:55:15 -04:00
mem_map_base = MEM_MAP_INTR_REGIONS_BASE +
mem_map * MEM_MAP_INTR_REGION_SIZE ;
mem_map_limit = mem_map_base + MEM_MAP_INTR_REGION_SIZE - 1 ;
msi_addr = mem_map_base + TRIO_MAP_MEM_REG_INT3 -
TRIO_MAP_MEM_REG_INT0 ;
msg . data = mem_map ;
2012-04-07 17:10:17 -04:00
}
/* We try to distribute different IRQs to different tiles. */
cpu = tile_irq_cpu ( irq ) ;
/*
2013-08-02 12:55:15 -04:00
* Now call up to the HV to configure the MSI interrupt and
2012-04-07 17:10:17 -04:00
* set up the IPI binding .
*/
ret = gxio_trio_config_msi_intr ( trio_context , cpu_x ( cpu ) , cpu_y ( cpu ) ,
KERNEL_PL , irq , controller - > mac ,
mem_map , mem_map_base , mem_map_limit ,
trio_context - > asid ) ;
if ( ret < 0 ) {
2014-10-31 10:50:46 -07:00
dev_info ( & pdev - > dev , " HV MSI config failed \n " ) ;
2012-04-07 17:10:17 -04:00
goto hv_msi_config_failure ;
}
irq_set_msi_desc ( irq , desc ) ;
msg . address_hi = msi_addr > > 32 ;
msg . address_lo = msi_addr & 0xffffffff ;
2014-11-09 23:10:34 +08:00
pci_write_msi_msg ( irq , & msg ) ;
2012-04-07 17:10:17 -04:00
irq_set_chip_and_handler ( irq , & tilegx_msi_chip , handle_level_irq ) ;
irq_set_handler_data ( irq , controller ) ;
return 0 ;
hv_msi_config_failure :
/* Free mem-map */
msi_mem_map_alloc_failure :
is_64_failure :
2014-05-07 15:44:16 +00:00
irq_free_hwirq ( irq ) ;
2012-04-07 17:10:17 -04:00
return ret ;
}
void arch_teardown_msi_irq ( unsigned int irq )
{
2014-05-07 15:44:16 +00:00
irq_free_hwirq ( irq ) ;
2012-04-07 17:10:17 -04:00
}