/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* 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. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include
#include
#define INVALID_VALUE (~0U)
#define PCI_ERR_VALUE(len) GENMASK(0, len * 8)
int pci_generic_config_read(struct pci_host_bridge *bridge, pci_sbdf_t sbdf,
uint32_t reg, uint32_t len, uint32_t *value)
{
void __iomem *addr = bridge->ops->map_bus(bridge, sbdf, reg);
if ( !addr )
{
*value = INVALID_VALUE;
return -ENODEV;
}
switch ( len )
{
case 1:
*value = readb(addr);
break;
case 2:
*value = readw(addr);
break;
case 4:
*value = readl(addr);
break;
default:
ASSERT_UNREACHABLE();
}
return 0;
}
int pci_generic_config_write(struct pci_host_bridge *bridge, pci_sbdf_t sbdf,
uint32_t reg, uint32_t len, uint32_t value)
{
void __iomem *addr = bridge->ops->map_bus(bridge, sbdf, reg);
if ( !addr )
return -ENODEV;
switch ( len )
{
case 1:
writeb(value, addr);
break;
case 2:
writew(value, addr);
break;
case 4:
writel(value, addr);
break;
default:
ASSERT_UNREACHABLE();
}
return 0;
}
static uint32_t pci_config_read(pci_sbdf_t sbdf, unsigned int reg,
unsigned int len)
{
uint32_t val = PCI_ERR_VALUE(len);
struct pci_host_bridge *bridge = pci_find_host_bridge(sbdf.seg, sbdf.bus);
if ( unlikely(!bridge) )
return val;
if ( unlikely(!bridge->ops->read) )
return val;
bridge->ops->read(bridge, sbdf, reg, len, &val);
return val;
}
static void pci_config_write(pci_sbdf_t sbdf, unsigned int reg,
unsigned int len, uint32_t val)
{
struct pci_host_bridge *bridge = pci_find_host_bridge(sbdf.seg, sbdf.bus);
if ( unlikely(!bridge) )
return;
if ( unlikely(!bridge->ops->write) )
return;
bridge->ops->write(bridge, sbdf, reg, len, val);
}
/*
* Wrappers for all PCI configuration access functions.
*/
#define PCI_OP_WRITE(size, type) \
void pci_conf_write##size(pci_sbdf_t sbdf, \
unsigned int reg, type val) \
{ \
pci_config_write(sbdf, reg, size / 8, val); \
}
#define PCI_OP_READ(size, type) \
type pci_conf_read##size(pci_sbdf_t sbdf, \
unsigned int reg) \
{ \
return pci_config_read(sbdf, reg, size / 8); \
}
PCI_OP_READ(8, uint8_t)
PCI_OP_READ(16, uint16_t)
PCI_OP_READ(32, uint32_t)
PCI_OP_WRITE(8, uint8_t)
PCI_OP_WRITE(16, uint16_t)
PCI_OP_WRITE(32, uint32_t)
/*
* Local variables:
* mode: C
* c-file-style: "BSD"
* c-basic-offset: 4
* tab-width: 4
* indent-tabs-mode: nil
* End:
*/