diff options
Diffstat (limited to 'cvmx-pcie.c')
| -rw-r--r-- | cvmx-pcie.c | 145 |
1 files changed, 111 insertions, 34 deletions
diff --git a/cvmx-pcie.c b/cvmx-pcie.c index 8053737e97373..493197b9062e8 100644 --- a/cvmx-pcie.c +++ b/cvmx-pcie.c @@ -1,5 +1,5 @@ /***********************license start*************** - * Copyright (c) 2003-2010 Cavium Networks (support@cavium.com). All rights + * Copyright (c) 2003-2011 Cavium, Inc. <support@cavium.com>. All rights * reserved. * * @@ -15,7 +15,7 @@ * disclaimer in the documentation and/or other materials provided * with the distribution. - * * Neither the name of Cavium Networks nor the names of + * * Neither the name of Cavium Inc. nor the names of * its contributors may be used to endorse or promote products * derived from this software without specific prior written * permission. @@ -26,7 +26,7 @@ * countries. * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" - * AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS OR + * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM @@ -37,18 +37,12 @@ * PERFORMANCE OF THE SOFTWARE LIES WITH YOU. ***********************license end**************************************/ - - - - - - /** * @file * * Interface to PCIe as a host(RC) or target(EP) * - * <hr>$Revision: 52004 $<hr> + * <hr>$Revision: 70030 $<hr> */ #ifdef CVMX_BUILD_FOR_LINUX_KERNEL #include <asm/octeon/cvmx.h> @@ -56,6 +50,7 @@ #include <asm/octeon/cvmx-clock.h> #include <asm/octeon/cvmx-ciu-defs.h> #include <asm/octeon/cvmx-dpi-defs.h> +#include <asm/octeon/cvmx-mio-defs.h> #include <asm/octeon/cvmx-npi-defs.h> #include <asm/octeon/cvmx-npei-defs.h> #include <asm/octeon/cvmx-pci-defs.h> @@ -66,6 +61,7 @@ #include <asm/octeon/cvmx-pescx-defs.h> #include <asm/octeon/cvmx-sli-defs.h> #include <asm/octeon/cvmx-sriox-defs.h> +#include <asm/octeon/cvmx-helper-jtag.h> #ifdef CONFIG_CAVIUM_DECODE_RSL #include <asm/octeon/cvmx-error.h> @@ -73,6 +69,7 @@ #include <asm/octeon/cvmx-helper.h> #include <asm/octeon/cvmx-helper-board.h> #include <asm/octeon/cvmx-helper-errata.h> +#include <asm/octeon/cvmx-qlm.h> #include <asm/octeon/cvmx-pcie.h> #include <asm/octeon/cvmx-sysinfo.h> #include <asm/octeon/cvmx-swap.h> @@ -86,6 +83,7 @@ #include "cvmx-wqe.h" #include "cvmx-error.h" #include "cvmx-helper-errata.h" +#include "cvmx-qlm.h" #endif #define MRRS_CN5XXX 0 /* 128 byte Max Read Request Size */ @@ -221,6 +219,8 @@ static void __cvmx_pcie_rc_initialize_config_space(int pcie_port) prt_cfg.u64 = cvmx_read_csr(CVMX_DPI_SLI_PRTX_CFG(pcie_port)); prt_cfg.s.mps = MPS_CN6XXX; prt_cfg.s.mrrs = MRRS_CN6XXX; + /* Max outstanding load request. */ + prt_cfg.s.molr = 32; cvmx_write_csr(CVMX_DPI_SLI_PRTX_CFG(pcie_port), prt_cfg.u64); sli_s2m_portx_ctl.u64 = cvmx_read_csr(CVMX_PEXP_SLI_S2M_PORTX_CTL(pcie_port)); @@ -447,6 +447,13 @@ static int __cvmx_pcie_rc_initialize_link_gen1(int pcie_port) return 0; } +static inline void __cvmx_increment_ba(cvmx_sli_mem_access_subidx_t *pmas) +{ + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) + pmas->cn68xx.ba++; + else + pmas->cn63xx.ba++; +} /** * Initialize a PCIe gen 1 port for use in host(RC) mode. It doesn't enumerate @@ -807,7 +814,6 @@ retry: return 0; } - /** * @INTERNAL * Initialize a host mode PCIe gen 2 link. This function takes a PCIe @@ -838,7 +844,7 @@ static int __cvmx_pcie_rc_initialize_link_gen2(int pcie_port) return -1; cvmx_wait(10000); pciercx_cfg032.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port)); - } while (pciercx_cfg032.s.dlla == 0); + } while ((pciercx_cfg032.s.dlla == 0) || (pciercx_cfg032.s.lt == 1)); /* Update the Replay Time Limit. Empirically, some PCIe devices take a little longer to respond than expected under load. As a workaround for @@ -889,21 +895,75 @@ static int __cvmx_pcie_rc_initialize_gen2(int pcie_port) cvmx_sli_ctl_portx_t sli_ctl_portx; cvmx_sli_mem_access_ctl_t sli_mem_access_ctl; cvmx_sli_mem_access_subidx_t mem_access_subid; - cvmx_mio_rst_ctlx_t mio_rst_ctlx; - cvmx_sriox_status_reg_t sriox_status_reg; cvmx_pemx_bar1_indexx_t bar1_index; + int ep_mode; - /* Make sure this interface isn't SRIO */ - sriox_status_reg.u64 = cvmx_read_csr(CVMX_SRIOX_STATUS_REG(pcie_port)); - if (sriox_status_reg.s.srio) + /* Make sure this interface is PCIe */ + if (OCTEON_IS_MODEL(OCTEON_CN6XXX) || OCTEON_IS_MODEL(OCTEON_CNF71XX)) { - cvmx_dprintf("PCIe: Port %d is SRIO, skipping.\n", pcie_port); - return -1; + /* Requires reading the MIO_QLMX_CFG register to figure + out the port type. */ + int qlm = pcie_port; + int status; + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) + qlm = 3 - (pcie_port * 2); + else if (OCTEON_IS_MODEL(OCTEON_CN61XX)) + { + cvmx_mio_qlmx_cfg_t qlm_cfg; + qlm_cfg.u64 = cvmx_read_csr(CVMX_MIO_QLMX_CFG(1)); + if (qlm_cfg.s.qlm_cfg == 1) + qlm = 1; + } + /* PCIe is allowed only in QLM1, 1 PCIe port in x2 or + 2 PCIe ports in x1 */ + else if (OCTEON_IS_MODEL(OCTEON_CNF71XX)) + qlm = 1; + status = cvmx_qlm_get_status(qlm); + if (status == 4 || status == 5) + { + cvmx_dprintf("PCIe: Port %d is SRIO, skipping.\n", pcie_port); + return -1; + } + if (status == 1) + { + cvmx_dprintf("PCIe: Port %d is SGMII, skipping.\n", pcie_port); + return -1; + } + if (status == 2) + { + cvmx_dprintf("PCIe: Port %d is XAUI, skipping.\n", pcie_port); + return -1; + } + if (status == -1) + { + cvmx_dprintf("PCIe: Port %d is unknown, skipping.\n", pcie_port); + return -1; + } } +#if 0 + /* This code is so that the PCIe analyzer is able to see 63XX traffic */ + cvmx_dprintf("PCIE : init for pcie analyzer.\n"); + cvmx_helper_qlm_jtag_init(); + cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 85); + cvmx_helper_qlm_jtag_shift(pcie_port, 1, 1); + cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 300-86); + cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 85); + cvmx_helper_qlm_jtag_shift(pcie_port, 1, 1); + cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 300-86); + cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 85); + cvmx_helper_qlm_jtag_shift(pcie_port, 1, 1); + cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 300-86); + cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 85); + cvmx_helper_qlm_jtag_shift(pcie_port, 1, 1); + cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 300-86); + cvmx_helper_qlm_jtag_update(pcie_port); +#endif + /* Make sure we aren't trying to setup a target mode interface in host mode */ mio_rst_ctl.u64 = cvmx_read_csr(CVMX_MIO_RST_CTLX(pcie_port)); - if (!mio_rst_ctl.s.host_mode) + ep_mode = (OCTEON_IS_MODEL(OCTEON_CN61XX || OCTEON_IS_MODEL(OCTEON_CNF71XX)) ? (mio_rst_ctl.s.prtmode != 1) : (!mio_rst_ctl.s.host_mode)); + if (ep_mode) { cvmx_dprintf("PCIe: Port %d in endpoint mode.\n", pcie_port); return -1; @@ -931,7 +991,6 @@ static int __cvmx_pcie_rc_initialize_gen2(int pcie_port) cvmx_write_csr(CVMX_CIU_QLM0, ciu_qlm.u64); } } - /* Bring the PCIe out of reset */ if (pcie_port) ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST1); @@ -970,8 +1029,7 @@ static int __cvmx_pcie_rc_initialize_gen2(int pcie_port) /* Check and make sure PCIe came out of reset. If it doesn't the board probably hasn't wired the clocks up and the interface should be skipped */ - mio_rst_ctlx.u64 = cvmx_read_csr(CVMX_MIO_RST_CTLX(pcie_port)); - if (!mio_rst_ctlx.s.rst_done) + if (CVMX_WAIT_FOR_FIELD64(CVMX_MIO_RST_CTLX(pcie_port), cvmx_mio_rst_ctlx_t, rst_done, ==, 1, 10000)) { cvmx_dprintf("PCIe: Port %d stuck in reset, skipping.\n", pcie_port); return -1; @@ -982,6 +1040,9 @@ static int __cvmx_pcie_rc_initialize_gen2(int pcie_port) if (pemx_bist_status.u64) cvmx_dprintf("PCIe: BIST FAILED for port %d (0x%016llx)\n", pcie_port, CAST64(pemx_bist_status.u64)); pemx_bist_status2.u64 = cvmx_read_csr(CVMX_PEMX_BIST_STATUS2(pcie_port)); + /* Errata PCIE-14766 may cause the lower 6 bits to be randomly set on CN63XXp1 */ + if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X)) + pemx_bist_status2.u64 &= ~0x3full; if (pemx_bist_status2.u64) cvmx_dprintf("PCIe: BIST2 FAILED for port %d (0x%016llx)\n", pcie_port, CAST64(pemx_bist_status2.u64)); @@ -1001,7 +1062,7 @@ static int __cvmx_pcie_rc_initialize_gen2(int pcie_port) cvmx_pciercx_cfg031_t pciercx_cfg031; pciercx_cfg031.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG031(pcie_port)); pciercx_cfg031.s.mls = 1; - cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG031(pcie_port), pciercx_cfg515.u32); + cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG031(pcie_port), pciercx_cfg031.u32); if (__cvmx_pcie_rc_initialize_link_gen2(pcie_port)) { cvmx_dprintf("PCIe: Link timeout on port %d, probably the slot is empty\n", pcie_port); @@ -1023,22 +1084,30 @@ static int __cvmx_pcie_rc_initialize_gen2(int pcie_port) mem_access_subid.s.esw = 1; /* Endian-swap for Writes. */ mem_access_subid.s.wtype = 0; /* "No snoop" and "Relaxed ordering" are not set */ mem_access_subid.s.rtype = 0; /* "No snoop" and "Relaxed ordering" are not set */ - mem_access_subid.s.ba = 0; /* PCIe Adddress Bits <63:34>. */ + /* PCIe Adddress Bits <63:34>. */ + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) + mem_access_subid.cn68xx.ba = 0; + else + mem_access_subid.cn63xx.ba = 0; /* Setup mem access 12-15 for port 0, 16-19 for port 1, supplying 36 bits of address space */ for (i=12 + pcie_port*4; i<16 + pcie_port*4; i++) { cvmx_write_csr(CVMX_PEXP_SLI_MEM_ACCESS_SUBIDX(i), mem_access_subid.u64); - mem_access_subid.s.ba += 1; /* Set each SUBID to extend the addressable range */ + /* Set each SUBID to extend the addressable range */ + __cvmx_increment_ba(&mem_access_subid); } - /* Disable the peer to peer forwarding register. This must be setup - by the OS after it enumerates the bus and assigns addresses to the - PCIe busses */ - for (i=0; i<4; i++) + if (!OCTEON_IS_MODEL(OCTEON_CN61XX)) { - cvmx_write_csr(CVMX_PEMX_P2P_BARX_START(i, pcie_port), -1); - cvmx_write_csr(CVMX_PEMX_P2P_BARX_END(i, pcie_port), -1); + /* Disable the peer to peer forwarding register. This must be setup + by the OS after it enumerates the bus and assigns addresses to the + PCIe busses */ + for (i=0; i<4; i++) + { + cvmx_write_csr(CVMX_PEMX_P2P_BARX_START(i, pcie_port), -1); + cvmx_write_csr(CVMX_PEMX_P2P_BARX_END(i, pcie_port), -1); + } } /* Set Octeon's BAR0 to decode 0-16KB. It overlaps with Bar2 */ @@ -1394,8 +1463,10 @@ int cvmx_pcie_ep_initialize(int pcie_port) else { cvmx_mio_rst_ctlx_t mio_rst_ctl; + int ep_mode; mio_rst_ctl.u64 = cvmx_read_csr(CVMX_MIO_RST_CTLX(pcie_port)); - if (mio_rst_ctl.s.host_mode) + ep_mode = (OCTEON_IS_MODEL(OCTEON_CN61XX) ? (mio_rst_ctl.s.prtmode != 0) : mio_rst_ctl.s.host_mode); + if (ep_mode) return -1; } @@ -1470,6 +1541,8 @@ int cvmx_pcie_ep_initialize(int pcie_port) prt_cfg.u64 = cvmx_read_csr(CVMX_DPI_SLI_PRTX_CFG(pcie_port)); prt_cfg.s.mps = MPS_CN6XXX; prt_cfg.s.mrrs = MRRS_CN6XXX; + /* Max outstanding load request. */ + prt_cfg.s.molr = 32; cvmx_write_csr(CVMX_DPI_SLI_PRTX_CFG(pcie_port), prt_cfg.u64); sli_s2m_portx_ctl.u64 = cvmx_read_csr(CVMX_PEXP_SLI_S2M_PORTX_CTL(pcie_port)); @@ -1503,7 +1576,11 @@ int cvmx_pcie_ep_initialize(int pcie_port) mem_access_subid.s.esw = 0; /* Endian-swap for Writes. */ mem_access_subid.s.wtype = 0; /* "No snoop" and "Relaxed ordering" are not set */ mem_access_subid.s.rtype = 0; /* "No snoop" and "Relaxed ordering" are not set */ - mem_access_subid.s.ba = 0; /* PCIe Adddress Bits <63:34>. */ + /* PCIe Adddress Bits <63:34>. */ + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) + mem_access_subid.cn68xx.ba = 0; + else + mem_access_subid.cn63xx.ba = 0; cvmx_write_csr(CVMX_PEXP_SLI_MEM_ACCESS_SUBIDX(12 + pcie_port*4), mem_access_subid.u64); } return 0; |
