in pci/pcie-octeon.c [1537:1707]
static int octeon_pcie_read_config(unsigned int pcie_port, struct pci_bus *bus,
unsigned int devfn, int reg, int size,
u32 *val)
{
union octeon_cvmemctl cvmmemctl;
union octeon_cvmemctl cvmmemctl_save;
int bus_number = bus->number;
int cfg_retry = 0;
int retry_cnt = 0;
int max_retry_cnt = 10;
u32 cfg_retry_cnt = 0;
cvmmemctl_save.u64 = 0;
BUG_ON(pcie_port >= ARRAY_SIZE(enable_pcie_bus_num_war));
/*
* For the top level bus make sure our hardware bus number
* matches the software one
*/
if (bus->parent == NULL) {
if (enable_pcie_bus_num_war[pcie_port])
bus_number = 0;
else {
union cvmx_pciercx_cfg006 pciercx_cfg006;
pciercx_cfg006.u32 = cvmx_pcie_cfgx_read(pcie_port,
CVMX_PCIERCX_CFG006(pcie_port));
if (pciercx_cfg006.s.pbnum != bus_number) {
pciercx_cfg006.s.pbnum = bus_number;
pciercx_cfg006.s.sbnum = bus_number;
pciercx_cfg006.s.subbnum = bus_number;
cvmx_pcie_cfgx_write(pcie_port,
CVMX_PCIERCX_CFG006(pcie_port),
pciercx_cfg006.u32);
}
}
}
/*
* PCIe only has a single device connected to Octeon. It is
* always device ID 0. Don't bother doing reads for other
* device IDs on the first segment.
*/
if ((bus->parent == NULL) && (devfn >> 3 != 0))
return PCIBIOS_FUNC_NOT_SUPPORTED;
/*
* The following is a workaround for the CN57XX, CN56XX,
* CN55XX, and CN54XX errata with PCIe config reads from non
* existent devices. These chips will hang the PCIe link if a
* config read is performed that causes a UR response.
*/
if (OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1) ||
OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_1)) {
/*
* For our EBH5600 board, port 0 has a bridge with two
* PCI-X slots. We need a new special checks to make
* sure we only probe valid stuff. The PCIe->PCI-X
* bridge only respondes to device ID 0, function
* 0-1
*/
if ((bus->parent == NULL) && (devfn >= 2))
return PCIBIOS_FUNC_NOT_SUPPORTED;
/*
* The PCI-X slots are device ID 2,3. Choose one of
* the below "if" blocks based on what is plugged into
* the board.
*/
#if 1
/* Use this option if you aren't using either slot */
if (bus_number == 2)
return PCIBIOS_FUNC_NOT_SUPPORTED;
#elif 0
/*
* Use this option if you are using the first slot but
* not the second.
*/
if ((bus_number == 2) && (devfn >> 3 != 2))
return PCIBIOS_FUNC_NOT_SUPPORTED;
#elif 0
/*
* Use this option if you are using the second slot
* but not the first.
*/
if ((bus_number == 2) && (devfn >> 3 != 3))
return PCIBIOS_FUNC_NOT_SUPPORTED;
#elif 0
/* Use this opion if you are using both slots */
if ((bus_number == 2) &&
!((devfn == (2 << 3)) || (devfn == (3 << 3))))
return PCIBIOS_FUNC_NOT_SUPPORTED;
#endif
/* The following #if gives a more complicated example. This is
the required checks for running a Nitrox CN16XX-NHBX in the
slot of the EBH5600. This card has a PLX PCIe bridge with
four Nitrox PLX parts behind it */
#if 0
/* PLX bridge with 4 ports */
if ((bus_number == 4) &&
!((devfn >> 3 >= 1) && (devfn >> 3 <= 4)))
return PCIBIOS_FUNC_NOT_SUPPORTED;
/* Nitrox behind PLX 1 */
if ((bus_number == 5) && (devfn >> 3 != 0))
return PCIBIOS_FUNC_NOT_SUPPORTED;
/* Nitrox behind PLX 2 */
if ((bus_number == 6) && (devfn >> 3 != 0))
return PCIBIOS_FUNC_NOT_SUPPORTED;
/* Nitrox behind PLX 3 */
if ((bus_number == 7) && (devfn >> 3 != 0))
return PCIBIOS_FUNC_NOT_SUPPORTED;
/* Nitrox behind PLX 4 */
if ((bus_number == 8) && (devfn >> 3 != 0))
return PCIBIOS_FUNC_NOT_SUPPORTED;
#endif
/*
* Shorten the DID timeout so bus errors for PCIe
* config reads from non existent devices happen
* faster. This allows us to continue booting even if
* the above "if" checks are wrong. Once one of these
* errors happens, the PCIe port is dead.
*/
cvmmemctl_save.u64 = __read_64bit_c0_register($11, 7);
cvmmemctl.u64 = cvmmemctl_save.u64;
cvmmemctl.s.didtto = 2;
__write_64bit_c0_register($11, 7, cvmmemctl.u64);
}
if ((OCTEON_IS_MODEL(OCTEON_CN63XX)) && (enable_pcie_14459_war))
cfg_retry_cnt = disable_cfg_read_retry();
pr_debug("pcie_cfg_rd port=%d b=%d devfn=0x%03x reg=0x%03x"
" size=%d ", pcie_port, bus_number, devfn, reg, size);
do {
switch (size) {
case 4:
*val = cvmx_pcie_config_read32(pcie_port, bus_number,
devfn >> 3, devfn & 0x7, reg);
break;
case 2:
*val = cvmx_pcie_config_read16(pcie_port, bus_number,
devfn >> 3, devfn & 0x7, reg);
break;
case 1:
*val = cvmx_pcie_config_read8(pcie_port, bus_number,
devfn >> 3, devfn & 0x7, reg);
break;
default:
if (OCTEON_IS_MODEL(OCTEON_CN63XX))
set_cfg_read_retry(cfg_retry_cnt);
return PCIBIOS_FUNC_NOT_SUPPORTED;
}
if ((OCTEON_IS_MODEL(OCTEON_CN63XX)) &&
(enable_pcie_14459_war)) {
cfg_retry = is_cfg_retry();
retry_cnt++;
if (retry_cnt > max_retry_cnt) {
pr_err(" pcie cfg_read retries failed. retry_cnt=%d\n",
retry_cnt);
cfg_retry = 0;
}
}
} while (cfg_retry);
if ((OCTEON_IS_MODEL(OCTEON_CN63XX)) && (enable_pcie_14459_war))
set_cfg_read_retry(cfg_retry_cnt);
pr_debug("val=%08x : tries=%02d\n", *val, retry_cnt);
if (OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1) ||
OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_1))
write_c0_cvmmemctl(cvmmemctl_save.u64);
return PCIBIOS_SUCCESSFUL;
}