/** * @INTERNAL * Initialize a host mode PCIe link. This function takes a PCIe * port from reset to a link up state. Software can then begin * configuring the rest of the link. * * @param pcie_port PCIe port to initialize * * @return Zero on success */ static int __cvmx_pcie_rc_initialize_link(int pcie_port) { uint64_t start_cycle; cvmx_pescx_ctl_status_t pescx_ctl_status; cvmx_pciercx_cfg452_t pciercx_cfg452; cvmx_pciercx_cfg032_t pciercx_cfg032; cvmx_pciercx_cfg448_t pciercx_cfg448; /* Set the lane width */ pciercx_cfg452.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG452(pcie_port)); pescx_ctl_status.u64 = cvmx_read_csr(CVMX_PESCX_CTL_STATUS(pcie_port)); if (pescx_ctl_status.s.qlm_cfg == 0) { /* We're in 8 lane (56XX) or 4 lane (54XX) mode */ pciercx_cfg452.s.lme = 0xf; } else { /* We're in 4 lane (56XX) or 2 lane (52XX) mode */ pciercx_cfg452.s.lme = 0x7; } cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG452(pcie_port), pciercx_cfg452.u32); /* CN52XX pass 1.x has an errata where length mismatches on UR responses can cause bus errors on 64bit memory reads. Turning off length error checking fixes this */ if (OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X)) { cvmx_pciercx_cfg455_t pciercx_cfg455; pciercx_cfg455.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG455(pcie_port)); pciercx_cfg455.s.m_cpl_len_err = 1; cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG455(pcie_port), pciercx_cfg455.u32); } /* Lane swap needs to be manually enabled for CN52XX */ if (OCTEON_IS_MODEL(OCTEON_CN52XX) && (pcie_port == 1)) { pescx_ctl_status.s.lane_swp = 1; cvmx_write_csr(CVMX_PESCX_CTL_STATUS(pcie_port),pescx_ctl_status.u64); } /* Bring up the link */ pescx_ctl_status.u64 = cvmx_read_csr(CVMX_PESCX_CTL_STATUS(pcie_port)); pescx_ctl_status.s.lnk_enb = 1; cvmx_write_csr(CVMX_PESCX_CTL_STATUS(pcie_port), pescx_ctl_status.u64); /* CN52XX pass 1.0: Due to a bug in 2nd order CDR, it needs to be disabled */ if (OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_0)) __cvmx_helper_errata_qlm_disable_2nd_order_cdr(0); /* Wait for the link to come up */ start_cycle = cvmx_get_cycle(); do { if (cvmx_get_cycle() - start_cycle > 2*cvmx_sysinfo_get()->cpu_clock_hz) { cvmx_dprintf("PCIe: Port %d link timeout\n", 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); /* Update the Replay Time Limit. Empirically, some PCIe devices take a little longer to respond than expected under load. As a workaround for this we configure the Replay Time Limit to the value expected for a 512 byte MPS instead of our actual 256 byte MPS. The numbers below are directly from the PCIe spec table 3-4 */ pciercx_cfg448.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG448(pcie_port)); switch (pciercx_cfg032.s.nlw) { case 1: /* 1 lane */ pciercx_cfg448.s.rtl = 1677; break; case 2: /* 2 lanes */ pciercx_cfg448.s.rtl = 867; break; case 4: /* 4 lanes */ pciercx_cfg448.s.rtl = 462; break; case 8: /* 8 lanes */ pciercx_cfg448.s.rtl = 258; break; } cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG448(pcie_port), pciercx_cfg448.u32); return 0; }
/** * Initialize a host mode PCIe link. This function takes a PCIe * port from reset to a link up state. Software can then begin * configuring the rest of the link. * * @pcie_port: PCIe port to initialize * * Returns Zero on success */ static int __cvmx_pcie_rc_initialize_link(int pcie_port) { uint64_t start_cycle; union cvmx_pescx_ctl_status pescx_ctl_status; union cvmx_pciercx_cfg452 pciercx_cfg452; union cvmx_pciercx_cfg032 pciercx_cfg032; union cvmx_pciercx_cfg448 pciercx_cfg448; /* Set the lane width */ pciercx_cfg452.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG452(pcie_port)); pescx_ctl_status.u64 = cvmx_read_csr(CVMX_PESCX_CTL_STATUS(pcie_port)); if (pescx_ctl_status.s.qlm_cfg == 0) { /* We're in 8 lane (56XX) or 4 lane (54XX) mode */ pciercx_cfg452.s.lme = 0xf; } else { /* We're in 4 lane (56XX) or 2 lane (52XX) mode */ pciercx_cfg452.s.lme = 0x7; } cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG452(pcie_port), pciercx_cfg452.u32); /* * CN52XX pass 1.x has an errata where length mismatches on UR * responses can cause bus errors on 64bit memory * reads. Turning off length error checking fixes this. */ if (OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X)) { union cvmx_pciercx_cfg455 pciercx_cfg455; pciercx_cfg455.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG455(pcie_port)); pciercx_cfg455.s.m_cpl_len_err = 1; cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG455(pcie_port), pciercx_cfg455.u32); } /* Lane swap needs to be manually enabled for CN52XX */ if (OCTEON_IS_MODEL(OCTEON_CN52XX) && (pcie_port == 1)) { pescx_ctl_status.s.lane_swp = 1; cvmx_write_csr(CVMX_PESCX_CTL_STATUS(pcie_port), pescx_ctl_status.u64); } /* Bring up the link */ pescx_ctl_status.u64 = cvmx_read_csr(CVMX_PESCX_CTL_STATUS(pcie_port)); pescx_ctl_status.s.lnk_enb = 1; cvmx_write_csr(CVMX_PESCX_CTL_STATUS(pcie_port), pescx_ctl_status.u64); /* * CN52XX pass 1.0: Due to a bug in 2nd order CDR, it needs to * be disabled. */ if (OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_0)) __cvmx_helper_errata_qlm_disable_2nd_order_cdr(0); /* Wait for the link to come up */ cvmx_dprintf("PCIe: Waiting for port %d link\n", pcie_port); start_cycle = cvmx_get_cycle(); do { if (cvmx_get_cycle() - start_cycle > 2 * cvmx_sysinfo_get()->cpu_clock_hz) { cvmx_dprintf("PCIe: Port %d link timeout\n", 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); /* Display the link status */ cvmx_dprintf("PCIe: Port %d link active, %d lanes\n", pcie_port, pciercx_cfg032.s.nlw); pciercx_cfg448.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG448(pcie_port)); switch (pciercx_cfg032.s.nlw) { case 1: /* 1 lane */ pciercx_cfg448.s.rtl = 1677; break; case 2: /* 2 lanes */ pciercx_cfg448.s.rtl = 867; break; case 4: /* 4 lanes */ pciercx_cfg448.s.rtl = 462; break; case 8: /* 8 lanes */ pciercx_cfg448.s.rtl = 258; break; } cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG448(pcie_port), pciercx_cfg448.u32); return 0; }