/** * Build a PCIe config space request address for a device * * @pcie_port: PCIe port to access * @bus: Sub bus * @dev: Device ID * @fn: Device sub function * @reg: Register to access * * Returns 64bit Octeon IO address */ static inline uint64_t __cvmx_pcie_build_config_addr(int pcie_port, int bus, int dev, int fn, int reg) { union cvmx_pcie_address pcie_addr; union cvmx_pciercx_cfg006 pciercx_cfg006; pciercx_cfg006.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG006(pcie_port)); if ((bus <= pciercx_cfg006.s.pbnum) && (dev != 0)) return 0; pcie_addr.u64 = 0; pcie_addr.config.upper = 2; pcie_addr.config.io = 1; pcie_addr.config.did = 3; pcie_addr.config.subdid = 1; pcie_addr.config.es = 1; pcie_addr.config.port = pcie_port; pcie_addr.config.ty = (bus > pciercx_cfg006.s.pbnum); pcie_addr.config.bus = bus; pcie_addr.config.dev = dev; pcie_addr.config.func = fn; pcie_addr.config.reg = reg; return pcie_addr.u64; }
/** * @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; }
/** * @INTERNAL * Initialize the RC config space CSRs * * @param pcie_port PCIe port to initialize */ static void __cvmx_pcie_rc_initialize_config_space(int pcie_port) { /* Max Payload Size (PCIE*_CFG030[MPS]) */ /* Max Read Request Size (PCIE*_CFG030[MRRS]) */ /* Relaxed-order, no-snoop enables (PCIE*_CFG030[RO_EN,NS_EN] */ /* Error Message Enables (PCIE*_CFG030[CE_EN,NFE_EN,FE_EN,UR_EN]) */ { cvmx_pciercx_cfg030_t pciercx_cfg030; pciercx_cfg030.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG030(pcie_port)); pciercx_cfg030.s.mps = 0; /* Max payload size = 128 bytes for best Octeon DMA performance */ pciercx_cfg030.s.mrrs = 0; /* Max read request size = 128 bytes for best Octeon DMA performance */ pciercx_cfg030.s.ro_en = 1; /* Enable relaxed order processing. This will allow devices to affect read response ordering */ pciercx_cfg030.s.ns_en = 1; /* Enable no snoop processing. Not used by Octeon */ pciercx_cfg030.s.ce_en = 1; /* Correctable error reporting enable. */ pciercx_cfg030.s.nfe_en = 1; /* Non-fatal error reporting enable. */ pciercx_cfg030.s.fe_en = 1; /* Fatal error reporting enable. */ pciercx_cfg030.s.ur_en = 1; /* Unsupported request reporting enable. */ cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG030(pcie_port), pciercx_cfg030.u32); } /* Max Payload Size (NPEI_CTL_STATUS2[MPS]) must match PCIE*_CFG030[MPS] */ /* Max Read Request Size (NPEI_CTL_STATUS2[MRRS]) must not exceed PCIE*_CFG030[MRRS] */ { cvmx_npei_ctl_status2_t npei_ctl_status2; npei_ctl_status2.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_CTL_STATUS2); npei_ctl_status2.s.mps = 0; /* Max payload size = 128 bytes for best Octeon DMA performance */ npei_ctl_status2.s.mrrs = 0; /* Max read request size = 128 bytes for best Octeon DMA performance */ cvmx_write_csr(CVMX_PEXP_NPEI_CTL_STATUS2, npei_ctl_status2.u64); } /* ECRC Generation (PCIE*_CFG070[GE,CE]) */ { cvmx_pciercx_cfg070_t pciercx_cfg070; pciercx_cfg070.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG070(pcie_port)); pciercx_cfg070.s.ge = 1; /* ECRC generation enable. */ pciercx_cfg070.s.ce = 1; /* ECRC check enable. */ cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG070(pcie_port), pciercx_cfg070.u32); } /* Access Enables (PCIE*_CFG001[MSAE,ME]) */ /* ME and MSAE should always be set. */ /* Interrupt Disable (PCIE*_CFG001[I_DIS]) */ /* System Error Message Enable (PCIE*_CFG001[SEE]) */ { cvmx_pciercx_cfg001_t pciercx_cfg001; pciercx_cfg001.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG001(pcie_port)); pciercx_cfg001.s.msae = 1; /* Memory space enable. */ pciercx_cfg001.s.me = 1; /* Bus master enable. */ pciercx_cfg001.s.i_dis = 1; /* INTx assertion disable. */ pciercx_cfg001.s.see = 1; /* SERR# enable */ cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG001(pcie_port), pciercx_cfg001.u32); } /* Advanced Error Recovery Message Enables */ /* (PCIE*_CFG066,PCIE*_CFG067,PCIE*_CFG069) */ cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG066(pcie_port), 0); /* Use CVMX_PCIERCX_CFG067 hardware default */ cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG069(pcie_port), 0); /* Active State Power Management (PCIE*_CFG032[ASLPC]) */ { cvmx_pciercx_cfg032_t pciercx_cfg032; pciercx_cfg032.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port)); pciercx_cfg032.s.aslpc = 0; /* Active state Link PM control. */ cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG032(pcie_port), pciercx_cfg032.u32); } /* Entrance Latencies (PCIE*_CFG451[L0EL,L1EL]) */ // FIXME: Anything needed here? /* Link Width Mode (PCIERCn_CFG452[LME]) - Set during cvmx_pcie_rc_initialize_link() */ /* Primary Bus Number (PCIERCn_CFG006[PBNUM]) */ { /* We set the primary bus number to 1 so IDT bridges are happy. They don't like zero */ cvmx_pciercx_cfg006_t pciercx_cfg006; pciercx_cfg006.u32 = 0; pciercx_cfg006.s.pbnum = 1; pciercx_cfg006.s.sbnum = 1; pciercx_cfg006.s.subbnum = 1; cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG006(pcie_port), pciercx_cfg006.u32); } /* Memory-mapped I/O BAR (PCIERCn_CFG008) */ /* Most applications should disable the memory-mapped I/O BAR by */ /* setting PCIERCn_CFG008[ML_ADDR] < PCIERCn_CFG008[MB_ADDR] */ { cvmx_pciercx_cfg008_t pciercx_cfg008; pciercx_cfg008.u32 = 0; pciercx_cfg008.s.mb_addr = 0x100; pciercx_cfg008.s.ml_addr = 0; cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG008(pcie_port), pciercx_cfg008.u32); } /* Prefetchable BAR (PCIERCn_CFG009,PCIERCn_CFG010,PCIERCn_CFG011) */ /* Most applications should disable the prefetchable BAR by setting */ /* PCIERCn_CFG011[UMEM_LIMIT],PCIERCn_CFG009[LMEM_LIMIT] < */ /* PCIERCn_CFG010[UMEM_BASE],PCIERCn_CFG009[LMEM_BASE] */ { cvmx_pciercx_cfg009_t pciercx_cfg009; cvmx_pciercx_cfg010_t pciercx_cfg010; cvmx_pciercx_cfg011_t pciercx_cfg011; pciercx_cfg009.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG009(pcie_port)); pciercx_cfg010.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG010(pcie_port)); pciercx_cfg011.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG011(pcie_port)); pciercx_cfg009.s.lmem_base = 0x100; pciercx_cfg009.s.lmem_limit = 0; pciercx_cfg010.s.umem_base = 0x100; pciercx_cfg011.s.umem_limit = 0; cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG009(pcie_port), pciercx_cfg009.u32); cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG010(pcie_port), pciercx_cfg010.u32); cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG011(pcie_port), pciercx_cfg011.u32); } /* System Error Interrupt Enables (PCIERCn_CFG035[SECEE,SEFEE,SENFEE]) */ /* PME Interrupt Enables (PCIERCn_CFG035[PMEIE]) */ { cvmx_pciercx_cfg035_t pciercx_cfg035; pciercx_cfg035.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG035(pcie_port)); pciercx_cfg035.s.secee = 1; /* System error on correctable error enable. */ pciercx_cfg035.s.sefee = 1; /* System error on fatal error enable. */ pciercx_cfg035.s.senfee = 1; /* System error on non-fatal error enable. */ pciercx_cfg035.s.pmeie = 1; /* PME interrupt enable. */ cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG035(pcie_port), pciercx_cfg035.u32); } /* Advanced Error Recovery Interrupt Enables */ /* (PCIERCn_CFG075[CERE,NFERE,FERE]) */ { cvmx_pciercx_cfg075_t pciercx_cfg075; pciercx_cfg075.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG075(pcie_port)); pciercx_cfg075.s.cere = 1; /* Correctable error reporting enable. */ pciercx_cfg075.s.nfere = 1; /* Non-fatal error reporting enable. */ pciercx_cfg075.s.fere = 1; /* Fatal error reporting enable. */ cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG075(pcie_port), pciercx_cfg075.u32); } /* HP Interrupt Enables (PCIERCn_CFG034[HPINT_EN], */ /* PCIERCn_CFG034[DLLS_EN,CCINT_EN]) */ { cvmx_pciercx_cfg034_t pciercx_cfg034; pciercx_cfg034.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG034(pcie_port)); pciercx_cfg034.s.hpint_en = 1; /* Hot-plug interrupt enable. */ pciercx_cfg034.s.dlls_en = 1; /* Data Link Layer state changed enable */ pciercx_cfg034.s.ccint_en = 1; /* Command completed interrupt enable. */ cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG034(pcie_port), pciercx_cfg034.u32); } }
/** * 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; }