2018-10-18 18:37:16 +03:00
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright ( C ) 2018 Marvell
*
* Author : Thomas Petazzoni < thomas . petazzoni @ bootlin . com >
*
* This file helps PCI controller drivers implement a fake root port
* PCI bridge when the HW doesn ' t provide such a root port PCI
* bridge .
*
* It emulates a PCI bridge by providing a fake PCI configuration
* space ( and optionally a PCIe capability configuration space ) in
* memory . By default the read / write operations simply read and update
* this fake configuration space in memory . However , PCI controller
* drivers can provide through the ' struct pci_sw_bridge_ops '
* structure a set of operations to override or complement this
* default behavior .
*/
# include <linux/pci.h>
# include "pci-bridge-emul.h"
# define PCI_BRIDGE_CONF_END PCI_STD_HEADER_SIZEOF
2021-02-02 20:07:46 +03:00
# define PCI_CAP_PCIE_SIZEOF (PCI_EXP_SLTSTA2 + 2)
2018-10-18 18:37:16 +03:00
# define PCI_CAP_PCIE_START PCI_BRIDGE_CONF_END
2021-02-02 20:07:46 +03:00
# define PCI_CAP_PCIE_END (PCI_CAP_PCIE_START + PCI_CAP_PCIE_SIZEOF)
2018-10-18 18:37:16 +03:00
2020-05-11 19:21:17 +03:00
/**
* struct pci_bridge_reg_behavior - register bits behaviors
* @ ro : Read - Only bits
* @ rw : Read - Write bits
* @ w1c : Write - 1 - to - Clear bits
*
* Reads and Writes will be filtered by specified behavior . All other bits not
* declared are assumed ' Reserved ' and will return 0 on reads , per PCIe 5.0 :
* " Reserved register fields must be read only and must return 0 (all 0's for
* multi - bit fields ) when read " .
*/
2018-10-18 18:37:16 +03:00
struct pci_bridge_reg_behavior {
/* Read-only bits */
u32 ro ;
/* Read-write bits */
u32 rw ;
/* Write-1-to-clear bits */
u32 w1c ;
} ;
2021-02-02 20:07:46 +03:00
static const
struct pci_bridge_reg_behavior pci_regs_behavior [ PCI_STD_HEADER_SIZEOF / 4 ] = {
2018-10-18 18:37:16 +03:00
[ PCI_VENDOR_ID / 4 ] = { . ro = ~ 0 } ,
[ PCI_COMMAND / 4 ] = {
. rw = ( PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
PCI_COMMAND_MASTER | PCI_COMMAND_PARITY |
PCI_COMMAND_SERR ) ,
. ro = ( ( PCI_COMMAND_SPECIAL | PCI_COMMAND_INVALIDATE |
PCI_COMMAND_VGA_PALETTE | PCI_COMMAND_WAIT |
PCI_COMMAND_FAST_BACK ) |
( PCI_STATUS_CAP_LIST | PCI_STATUS_66MHZ |
PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MASK ) < < 16 ) ,
2020-03-01 01:28:18 +03:00
. w1c = PCI_STATUS_ERROR_BITS < < 16 ,
2018-10-18 18:37:16 +03:00
} ,
[ PCI_CLASS_REVISION / 4 ] = { . ro = ~ 0 } ,
/*
* Cache Line Size register : implement as read - only , we do not
* pretend implementing " Memory Write and Invalidate "
* transactions "
*
* Latency Timer Register : implemented as read - only , as " A
* bridge that is not capable of a burst transfer of more than
* two data phases on its primary interface is permitted to
* hardwire the Latency Timer to a value of 16 or less "
*
* Header Type : always read - only
*
* BIST register : implemented as read - only , as " A bridge that
* does not support BIST must implement this register as a
* read - only register that returns 0 when read "
*/
[ PCI_CACHE_LINE_SIZE / 4 ] = { . ro = ~ 0 } ,
/*
* Base Address registers not used must be implemented as
* read - only registers that return 0 when read .
*/
[ PCI_BASE_ADDRESS_0 / 4 ] = { . ro = ~ 0 } ,
[ PCI_BASE_ADDRESS_1 / 4 ] = { . ro = ~ 0 } ,
[ PCI_PRIMARY_BUS / 4 ] = {
/* Primary, secondary and subordinate bus are RW */
. rw = GENMASK ( 24 , 0 ) ,
/* Secondary latency is read-only */
. ro = GENMASK ( 31 , 24 ) ,
} ,
[ PCI_IO_BASE / 4 ] = {
/* The high four bits of I/O base/limit are RW */
. rw = ( GENMASK ( 15 , 12 ) | GENMASK ( 7 , 4 ) ) ,
/* The low four bits of I/O base/limit are RO */
. ro = ( ( ( PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK |
PCI_STATUS_DEVSEL_MASK ) < < 16 ) |
GENMASK ( 11 , 8 ) | GENMASK ( 3 , 0 ) ) ,
2020-03-01 01:28:18 +03:00
. w1c = PCI_STATUS_ERROR_BITS < < 16 ,
2018-10-18 18:37:16 +03:00
} ,
[ PCI_MEMORY_BASE / 4 ] = {
/* The high 12-bits of mem base/limit are RW */
. rw = GENMASK ( 31 , 20 ) | GENMASK ( 15 , 4 ) ,
/* The low four bits of mem base/limit are RO */
. ro = GENMASK ( 19 , 16 ) | GENMASK ( 3 , 0 ) ,
} ,
[ PCI_PREF_MEMORY_BASE / 4 ] = {
/* The high 12-bits of pref mem base/limit are RW */
. rw = GENMASK ( 31 , 20 ) | GENMASK ( 15 , 4 ) ,
/* The low four bits of pref mem base/limit are RO */
. ro = GENMASK ( 19 , 16 ) | GENMASK ( 3 , 0 ) ,
} ,
[ PCI_PREF_BASE_UPPER32 / 4 ] = {
. rw = ~ 0 ,
} ,
[ PCI_PREF_LIMIT_UPPER32 / 4 ] = {
. rw = ~ 0 ,
} ,
[ PCI_IO_BASE_UPPER16 / 4 ] = {
. rw = ~ 0 ,
} ,
[ PCI_CAPABILITY_LIST / 4 ] = {
. ro = GENMASK ( 7 , 0 ) ,
} ,
2021-11-24 18:59:39 +03:00
/*
* If expansion ROM is unsupported then ROM Base Address register must
* be implemented as read - only register that return 0 when read , same
* as for unused Base Address registers .
*/
2018-10-18 18:37:16 +03:00
[ PCI_ROM_ADDRESS1 / 4 ] = {
2021-11-24 18:59:39 +03:00
. ro = ~ 0 ,
2018-10-18 18:37:16 +03:00
} ,
/*
* Interrupt line ( bits 7 : 0 ) are RW , interrupt pin ( bits 15 : 8 )
* are RO , and bridge control ( 31 : 16 ) are a mix of RW , RO ,
* reserved and W1C bits
*/
[ PCI_INTERRUPT_LINE / 4 ] = {
/* Interrupt line is RW */
. rw = ( GENMASK ( 7 , 0 ) |
( ( PCI_BRIDGE_CTL_PARITY |
PCI_BRIDGE_CTL_SERR |
PCI_BRIDGE_CTL_ISA |
PCI_BRIDGE_CTL_VGA |
PCI_BRIDGE_CTL_MASTER_ABORT |
PCI_BRIDGE_CTL_BUS_RESET |
BIT ( 8 ) | BIT ( 9 ) | BIT ( 11 ) ) < < 16 ) ) ,
/* Interrupt pin is RO */
. ro = ( GENMASK ( 15 , 8 ) | ( ( PCI_BRIDGE_CTL_FAST_BACK ) < < 16 ) ) ,
. w1c = BIT ( 10 ) < < 16 ,
} ,
} ;
2021-02-02 20:07:46 +03:00
static const
struct pci_bridge_reg_behavior pcie_cap_regs_behavior [ PCI_CAP_PCIE_SIZEOF / 4 ] = {
2018-10-18 18:37:16 +03:00
[ PCI_CAP_LIST_ID / 4 ] = {
/*
* Capability ID , Next Capability Pointer and
2021-11-24 18:59:42 +03:00
* bits [ 14 : 0 ] of Capabilities register are all read - only .
* Bit 15 of Capabilities register is reserved .
2018-10-18 18:37:16 +03:00
*/
2021-11-24 18:59:42 +03:00
. ro = GENMASK ( 30 , 0 ) ,
2018-10-18 18:37:16 +03:00
} ,
[ PCI_EXP_DEVCAP / 4 ] = {
2021-11-24 18:59:42 +03:00
/*
* Bits [ 31 : 29 ] and [ 17 : 16 ] are reserved .
* Bits [ 27 : 18 ] are reserved for non - upstream ports .
* Bits 28 and [ 14 : 6 ] are reserved for non - endpoint devices .
* Other bits are read - only .
*/
. ro = BIT ( 15 ) | GENMASK ( 5 , 0 ) ,
2018-10-18 18:37:16 +03:00
} ,
[ PCI_EXP_DEVCTL / 4 ] = {
2021-11-24 18:59:42 +03:00
/*
* Device control register is RW , except bit 15 which is
* reserved for non - endpoints or non - PCIe - to - PCI / X bridges .
*/
. rw = GENMASK ( 14 , 0 ) ,
2018-10-18 18:37:16 +03:00
/*
2020-05-11 19:21:16 +03:00
* Device status register has bits 6 and [ 3 : 0 ] W1C , [ 5 : 4 ] RO ,
2021-11-24 18:59:42 +03:00
* the rest is reserved . Also bit 6 is reserved for non - upstream
* ports .
2018-10-18 18:37:16 +03:00
*/
2021-11-24 18:59:42 +03:00
. w1c = GENMASK ( 3 , 0 ) < < 16 ,
2020-05-11 19:21:16 +03:00
. ro = GENMASK ( 5 , 4 ) < < 16 ,
2018-10-18 18:37:16 +03:00
} ,
[ PCI_EXP_LNKCAP / 4 ] = {
2021-11-24 18:59:42 +03:00
/*
* All bits are RO , except bit 23 which is reserved and
* bit 18 which is reserved for non - upstream ports .
*/
. ro = lower_32_bits ( ~ ( BIT ( 23 ) | PCI_EXP_LNKCAP_CLKPM ) ) ,
2018-10-18 18:37:16 +03:00
} ,
[ PCI_EXP_LNKCTL / 4 ] = {
/*
2020-05-11 19:21:16 +03:00
* Link control has bits [ 15 : 14 ] , [ 11 : 3 ] and [ 1 : 0 ] RW , the
2021-11-24 18:59:42 +03:00
* rest is reserved . Bit 8 is reserved for non - upstream ports .
2020-05-11 19:21:16 +03:00
*
* Link status has bits [ 13 : 0 ] RO , and bits [ 15 : 14 ]
2018-10-18 18:37:16 +03:00
* W1C .
*/
2021-11-24 18:59:42 +03:00
. rw = GENMASK ( 15 , 14 ) | GENMASK ( 11 , 9 ) | GENMASK ( 7 , 3 ) | GENMASK ( 1 , 0 ) ,
2018-10-18 18:37:16 +03:00
. ro = GENMASK ( 13 , 0 ) < < 16 ,
. w1c = GENMASK ( 15 , 14 ) < < 16 ,
} ,
[ PCI_EXP_SLTCAP / 4 ] = {
. ro = ~ 0 ,
} ,
[ PCI_EXP_SLTCTL / 4 ] = {
/*
2020-05-11 19:21:16 +03:00
* Slot control has bits [ 14 : 0 ] RW , the rest is
2018-10-18 18:37:16 +03:00
* reserved .
*
2020-05-11 19:21:16 +03:00
* Slot status has bits 8 and [ 4 : 0 ] W1C , bits [ 7 : 5 ] RO , the
* rest is reserved .
2018-10-18 18:37:16 +03:00
*/
2020-05-11 19:21:16 +03:00
. rw = GENMASK ( 14 , 0 ) ,
2018-10-18 18:37:16 +03:00
. w1c = ( PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD |
PCI_EXP_SLTSTA_MRLSC | PCI_EXP_SLTSTA_PDC |
PCI_EXP_SLTSTA_CC | PCI_EXP_SLTSTA_DLLSC ) < < 16 ,
. ro = ( PCI_EXP_SLTSTA_MRLSS | PCI_EXP_SLTSTA_PDS |
PCI_EXP_SLTSTA_EIS ) < < 16 ,
} ,
[ PCI_EXP_RTCTL / 4 ] = {
/*
* Root control has bits [ 4 : 0 ] RW , the rest is
* reserved .
*
2020-05-11 19:21:15 +03:00
* Root capabilities has bit 0 RO , the rest is reserved .
2018-10-18 18:37:16 +03:00
*/
. rw = ( PCI_EXP_RTCTL_SECEE | PCI_EXP_RTCTL_SENFEE |
PCI_EXP_RTCTL_SEFEE | PCI_EXP_RTCTL_PMEIE |
PCI_EXP_RTCTL_CRSSVE ) ,
. ro = PCI_EXP_RTCAP_CRSVIS < < 16 ,
} ,
[ PCI_EXP_RTSTA / 4 ] = {
2020-05-11 19:21:15 +03:00
/*
* Root status has bits 17 and [ 15 : 0 ] RO , bit 16 W1C , the rest
* is reserved .
*/
2018-10-18 18:37:16 +03:00
. ro = GENMASK ( 15 , 0 ) | PCI_EXP_RTSTA_PENDING ,
. w1c = PCI_EXP_RTSTA_PME ,
} ,
2021-11-30 20:29:04 +03:00
[ PCI_EXP_DEVCAP2 / 4 ] = {
/*
* Device capabilities 2 register has reserved bits [ 30 : 27 ] .
* Also bits [ 26 : 24 ] are reserved for non - upstream ports .
*/
. ro = BIT ( 31 ) | GENMASK ( 23 , 0 ) ,
} ,
[ PCI_EXP_DEVCTL2 / 4 ] = {
/*
* Device control 2 register is RW . Bit 11 is reserved for
* non - upstream ports .
*
* Device status 2 register is reserved .
*/
. rw = GENMASK ( 15 , 12 ) | GENMASK ( 10 , 0 ) ,
} ,
[ PCI_EXP_LNKCAP2 / 4 ] = {
/* Link capabilities 2 register has reserved bits [30:25] and 0. */
. ro = BIT ( 31 ) | GENMASK ( 24 , 1 ) ,
} ,
[ PCI_EXP_LNKCTL2 / 4 ] = {
/*
* Link control 2 register is RW .
*
* Link status 2 register has bits 5 , 15 W1C ;
* bits 10 , 11 reserved and others are RO .
*/
. rw = GENMASK ( 15 , 0 ) ,
. w1c = ( BIT ( 15 ) | BIT ( 5 ) ) < < 16 ,
. ro = ( GENMASK ( 14 , 12 ) | GENMASK ( 9 , 6 ) | GENMASK ( 4 , 0 ) ) < < 16 ,
} ,
[ PCI_EXP_SLTCAP2 / 4 ] = {
/* Slot capabilities 2 register is reserved. */
} ,
[ PCI_EXP_SLTCTL2 / 4 ] = {
/* Both Slot control 2 and Slot status 2 registers are reserved. */
} ,
2018-10-18 18:37:16 +03:00
} ;
2019-02-20 12:48:40 +03:00
/*
* Initialize a pci_bridge_emul structure to represent a fake PCI
* bridge configuration space . The caller needs to have initialized
* the PCI configuration space with whatever values make sense
* ( typically at least vendor , device , revision ) , the - > ops pointer ,
* and optionally - > data and - > has_pcie .
*/
2019-02-20 12:48:41 +03:00
int pci_bridge_emul_init ( struct pci_bridge_emul * bridge ,
unsigned int flags )
2019-02-20 12:48:40 +03:00
{
2021-02-02 20:07:46 +03:00
BUILD_BUG_ON ( sizeof ( bridge - > conf ) ! = PCI_BRIDGE_CONF_END ) ;
2021-11-30 20:29:03 +03:00
/*
* class_revision : Class is high 24 bits and revision is low 8 bit of this member ,
* while class for PCI Bridge Normal Decode has the 24 - bit value : PCI_CLASS_BRIDGE_PCI < < 8
*/
bridge - > conf . class_revision | = cpu_to_le32 ( ( PCI_CLASS_BRIDGE_PCI < < 8 ) < < 8 ) ;
2019-02-20 12:48:40 +03:00
bridge - > conf . header_type = PCI_HEADER_TYPE_BRIDGE ;
bridge - > conf . cache_line_size = 0x10 ;
2019-07-16 15:13:46 +03:00
bridge - > conf . status = cpu_to_le16 ( PCI_STATUS_CAP_LIST ) ;
2019-02-20 12:48:40 +03:00
bridge - > pci_regs_behavior = kmemdup ( pci_regs_behavior ,
sizeof ( pci_regs_behavior ) ,
GFP_KERNEL ) ;
if ( ! bridge - > pci_regs_behavior )
return - ENOMEM ;
if ( bridge - > has_pcie ) {
bridge - > conf . capabilities_pointer = PCI_CAP_PCIE_START ;
2021-11-24 18:59:44 +03:00
bridge - > conf . status | = cpu_to_le16 ( PCI_STATUS_CAP_LIST ) ;
2019-02-20 12:48:40 +03:00
bridge - > pcie_conf . cap_id = PCI_CAP_ID_EXP ;
2021-11-24 18:59:43 +03:00
bridge - > pcie_conf . cap | = cpu_to_le16 ( PCI_EXP_TYPE_ROOT_PORT < < 4 ) ;
2019-02-20 12:48:40 +03:00
bridge - > pcie_cap_regs_behavior =
kmemdup ( pcie_cap_regs_behavior ,
sizeof ( pcie_cap_regs_behavior ) ,
GFP_KERNEL ) ;
if ( ! bridge - > pcie_cap_regs_behavior ) {
kfree ( bridge - > pci_regs_behavior ) ;
return - ENOMEM ;
}
2021-11-24 18:59:40 +03:00
/* These bits are applicable only for PCI and reserved on PCIe */
bridge - > pci_regs_behavior [ PCI_CACHE_LINE_SIZE / 4 ] . ro & =
~ GENMASK ( 15 , 8 ) ;
bridge - > pci_regs_behavior [ PCI_COMMAND / 4 ] . ro & =
~ ( ( PCI_COMMAND_SPECIAL | PCI_COMMAND_INVALIDATE |
PCI_COMMAND_VGA_PALETTE | PCI_COMMAND_WAIT |
PCI_COMMAND_FAST_BACK ) |
( PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK |
PCI_STATUS_DEVSEL_MASK ) < < 16 ) ;
bridge - > pci_regs_behavior [ PCI_PRIMARY_BUS / 4 ] . ro & =
~ GENMASK ( 31 , 24 ) ;
bridge - > pci_regs_behavior [ PCI_IO_BASE / 4 ] . ro & =
~ ( ( PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK |
PCI_STATUS_DEVSEL_MASK ) < < 16 ) ;
bridge - > pci_regs_behavior [ PCI_INTERRUPT_LINE / 4 ] . rw & =
~ ( ( PCI_BRIDGE_CTL_MASTER_ABORT |
BIT ( 8 ) | BIT ( 9 ) | BIT ( 11 ) ) < < 16 ) ;
bridge - > pci_regs_behavior [ PCI_INTERRUPT_LINE / 4 ] . ro & =
~ ( ( PCI_BRIDGE_CTL_FAST_BACK ) < < 16 ) ;
bridge - > pci_regs_behavior [ PCI_INTERRUPT_LINE / 4 ] . w1c & =
~ ( BIT ( 10 ) < < 16 ) ;
2019-02-20 12:48:40 +03:00
}
2019-02-20 12:48:41 +03:00
if ( flags & PCI_BRIDGE_EMUL_NO_PREFETCHABLE_BAR ) {
bridge - > pci_regs_behavior [ PCI_PREF_MEMORY_BASE / 4 ] . ro = ~ 0 ;
bridge - > pci_regs_behavior [ PCI_PREF_MEMORY_BASE / 4 ] . rw = 0 ;
}
2019-02-20 12:48:40 +03:00
return 0 ;
}
2020-09-07 14:10:36 +03:00
EXPORT_SYMBOL_GPL ( pci_bridge_emul_init ) ;
2019-02-20 12:48:40 +03:00
/*
2019-05-30 16:05:58 +03:00
* Cleanup a pci_bridge_emul structure that was previously initialized
2019-02-20 12:48:40 +03:00
* using pci_bridge_emul_init ( ) .
*/
void pci_bridge_emul_cleanup ( struct pci_bridge_emul * bridge )
{
if ( bridge - > has_pcie )
kfree ( bridge - > pcie_cap_regs_behavior ) ;
kfree ( bridge - > pci_regs_behavior ) ;
}
2020-09-07 14:10:36 +03:00
EXPORT_SYMBOL_GPL ( pci_bridge_emul_cleanup ) ;
2019-02-20 12:48:40 +03:00
2018-10-18 18:37:16 +03:00
/*
* Should be called by the PCI controller driver when reading the PCI
* configuration space of the fake bridge . It will call back the
* - > ops - > read_base or - > ops - > read_pcie operations .
*/
int pci_bridge_emul_conf_read ( struct pci_bridge_emul * bridge , int where ,
int size , u32 * value )
{
int ret ;
int reg = where & ~ 3 ;
pci_bridge_emul_read_status_t ( * read_op ) ( struct pci_bridge_emul * bridge ,
int reg , u32 * value ) ;
2019-07-16 15:13:46 +03:00
__le32 * cfgspace ;
2018-10-18 18:37:16 +03:00
const struct pci_bridge_reg_behavior * behavior ;
if ( bridge - > has_pcie & & reg > = PCI_CAP_PCIE_END ) {
* value = 0 ;
return PCIBIOS_SUCCESSFUL ;
}
if ( ! bridge - > has_pcie & & reg > = PCI_BRIDGE_CONF_END ) {
* value = 0 ;
return PCIBIOS_SUCCESSFUL ;
}
if ( bridge - > has_pcie & & reg > = PCI_CAP_PCIE_START ) {
reg - = PCI_CAP_PCIE_START ;
read_op = bridge - > ops - > read_pcie ;
2019-07-16 15:13:46 +03:00
cfgspace = ( __le32 * ) & bridge - > pcie_conf ;
2019-02-20 12:48:40 +03:00
behavior = bridge - > pcie_cap_regs_behavior ;
2018-10-18 18:37:16 +03:00
} else {
read_op = bridge - > ops - > read_base ;
2019-07-16 15:13:46 +03:00
cfgspace = ( __le32 * ) & bridge - > conf ;
2019-02-20 12:48:40 +03:00
behavior = bridge - > pci_regs_behavior ;
2018-10-18 18:37:16 +03:00
}
if ( read_op )
ret = read_op ( bridge , reg , value ) ;
else
ret = PCI_BRIDGE_EMUL_NOT_HANDLED ;
if ( ret = = PCI_BRIDGE_EMUL_NOT_HANDLED )
2019-07-16 15:13:46 +03:00
* value = le32_to_cpu ( cfgspace [ reg / 4 ] ) ;
2018-10-18 18:37:16 +03:00
/*
* Make sure we never return any reserved bit with a value
* different from 0.
*/
2020-05-11 19:21:17 +03:00
* value & = behavior [ reg / 4 ] . ro | behavior [ reg / 4 ] . rw |
behavior [ reg / 4 ] . w1c ;
2018-10-18 18:37:16 +03:00
if ( size = = 1 )
* value = ( * value > > ( 8 * ( where & 3 ) ) ) & 0xff ;
else if ( size = = 2 )
* value = ( * value > > ( 8 * ( where & 3 ) ) ) & 0xffff ;
else if ( size ! = 4 )
return PCIBIOS_BAD_REGISTER_NUMBER ;
return PCIBIOS_SUCCESSFUL ;
}
2020-09-07 14:10:36 +03:00
EXPORT_SYMBOL_GPL ( pci_bridge_emul_conf_read ) ;
2018-10-18 18:37:16 +03:00
/*
* Should be called by the PCI controller driver when writing the PCI
* configuration space of the fake bridge . It will call back the
* - > ops - > write_base or - > ops - > write_pcie operations .
*/
int pci_bridge_emul_conf_write ( struct pci_bridge_emul * bridge , int where ,
int size , u32 value )
{
int reg = where & ~ 3 ;
int mask , ret , old , new , shift ;
void ( * write_op ) ( struct pci_bridge_emul * bridge , int reg ,
u32 old , u32 new , u32 mask ) ;
2019-07-16 15:13:46 +03:00
__le32 * cfgspace ;
2018-10-18 18:37:16 +03:00
const struct pci_bridge_reg_behavior * behavior ;
if ( bridge - > has_pcie & & reg > = PCI_CAP_PCIE_END )
return PCIBIOS_SUCCESSFUL ;
if ( ! bridge - > has_pcie & & reg > = PCI_BRIDGE_CONF_END )
return PCIBIOS_SUCCESSFUL ;
shift = ( where & 0x3 ) * 8 ;
if ( size = = 4 )
mask = 0xffffffff ;
else if ( size = = 2 )
mask = 0xffff < < shift ;
else if ( size = = 1 )
mask = 0xff < < shift ;
else
return PCIBIOS_BAD_REGISTER_NUMBER ;
ret = pci_bridge_emul_conf_read ( bridge , reg , 4 , & old ) ;
if ( ret ! = PCIBIOS_SUCCESSFUL )
return ret ;
if ( bridge - > has_pcie & & reg > = PCI_CAP_PCIE_START ) {
reg - = PCI_CAP_PCIE_START ;
write_op = bridge - > ops - > write_pcie ;
2019-07-16 15:13:46 +03:00
cfgspace = ( __le32 * ) & bridge - > pcie_conf ;
2019-02-20 12:48:40 +03:00
behavior = bridge - > pcie_cap_regs_behavior ;
2018-10-18 18:37:16 +03:00
} else {
write_op = bridge - > ops - > write_base ;
2019-07-16 15:13:46 +03:00
cfgspace = ( __le32 * ) & bridge - > conf ;
2019-02-20 12:48:40 +03:00
behavior = bridge - > pci_regs_behavior ;
2018-10-18 18:37:16 +03:00
}
/* Keep all bits, except the RW bits */
new = old & ( ~ mask | ~ behavior [ reg / 4 ] . rw ) ;
/* Update the value of the RW bits */
new | = ( value < < shift ) & ( behavior [ reg / 4 ] . rw & mask ) ;
/* Clear the W1C bits */
new & = ~ ( ( value < < shift ) & ( behavior [ reg / 4 ] . w1c & mask ) ) ;
2021-10-28 21:56:53 +03:00
/* Save the new value with the cleared W1C bits into the cfgspace */
2019-07-16 15:13:46 +03:00
cfgspace [ reg / 4 ] = cpu_to_le32 ( new ) ;
2018-10-18 18:37:16 +03:00
2021-10-28 21:56:53 +03:00
/*
* Clear the W1C bits not specified by the write mask , so that the
* write_op ( ) does not clear them .
*/
new & = ~ ( behavior [ reg / 4 ] . w1c & ~ mask ) ;
/*
* Set the W1C bits specified by the write mask , so that write_op ( )
* knows about that they are to be cleared .
*/
new | = ( value < < shift ) & ( behavior [ reg / 4 ] . w1c & mask ) ;
2018-10-18 18:37:16 +03:00
if ( write_op )
write_op ( bridge , reg , old , new , mask ) ;
return PCIBIOS_SUCCESSFUL ;
}
2020-09-07 14:10:36 +03:00
EXPORT_SYMBOL_GPL ( pci_bridge_emul_conf_write ) ;