int cpci_clear_ext(struct slot* slot) { int hs_cap; u16 hs_csr; hs_cap = pci_bus_find_capability(slot->bus, slot->devfn, PCI_CAP_ID_CHSWP); if (!hs_cap) return -ENODEV; if (pci_bus_read_config_word(slot->bus, slot->devfn, hs_cap + 2, &hs_csr)) return -ENODEV; if (hs_csr & HS_CSR_EXT) { /* Clear EXT (by setting it) */ if (pci_bus_write_config_word(slot->bus, slot->devfn, hs_cap + 2, hs_csr)) return -ENODEV; } return 0; }
int cpci_check_and_clear_ins(struct slot* slot) { int hs_cap; u16 hs_csr; int ins = 0; hs_cap = pci_bus_find_capability(slot->bus, slot->devfn, PCI_CAP_ID_CHSWP); if (!hs_cap) return 0; if (pci_bus_read_config_word(slot->bus, slot->devfn, hs_cap + 2, &hs_csr)) return 0; if (hs_csr & HS_CSR_INS) { /* Clear INS (by setting it) */ if (pci_bus_write_config_word(slot->bus, slot->devfn, hs_cap + 2, hs_csr)) ins = 0; else ins = 1; } return ins; }
int cpci_set_attention_status(struct slot* slot, int status) { int hs_cap; u16 hs_csr; hs_cap = pci_bus_find_capability(slot->bus, slot->devfn, PCI_CAP_ID_CHSWP); if (!hs_cap) return 0; if (pci_bus_read_config_word(slot->bus, slot->devfn, hs_cap + 2, &hs_csr)) return 0; if (status) hs_csr |= HS_CSR_LOO; else hs_csr &= ~HS_CSR_LOO; if (pci_bus_write_config_word(slot->bus, slot->devfn, hs_cap + 2, hs_csr)) return 0; return 1; }
int cpci_led_off(struct slot* slot) { int hs_cap; u16 hs_csr; hs_cap = pci_bus_find_capability(slot->bus, slot->devfn, PCI_CAP_ID_CHSWP); if (!hs_cap) return -ENODEV; if (pci_bus_read_config_word(slot->bus, slot->devfn, hs_cap + 2, &hs_csr)) return -ENODEV; if (hs_csr & HS_CSR_LOO) { hs_csr &= ~HS_CSR_LOO; if (pci_bus_write_config_word(slot->bus, slot->devfn, hs_cap + 2, hs_csr)) { err("Could not clear LOO for slot %s", hotplug_slot_name(slot->hotplug_slot)); return -ENODEV; } } return 0; }
u16 cpci_get_hs_csr(struct slot* slot) { int hs_cap; u16 hs_csr; hs_cap = pci_bus_find_capability(slot->bus, slot->devfn, PCI_CAP_ID_CHSWP); if (!hs_cap) return 0xFFFF; if (pci_bus_read_config_word(slot->bus, slot->devfn, hs_cap + 2, &hs_csr)) return 0xFFFF; return hs_csr; }
u8 cpci_get_attention_status(struct slot* slot) { int hs_cap; u16 hs_csr; hs_cap = pci_bus_find_capability(slot->bus, slot->devfn, PCI_CAP_ID_CHSWP); if (!hs_cap) return 0; if (pci_bus_read_config_word(slot->bus, slot->devfn, hs_cap + 2, &hs_csr)) return 0; return hs_csr & 0x0008 ? 1 : 0; }
int cpci_check_ext(struct slot* slot) { int hs_cap; u16 hs_csr; int ext = 0; hs_cap = pci_bus_find_capability(slot->bus, slot->devfn, PCI_CAP_ID_CHSWP); if (!hs_cap) return 0; if (pci_bus_read_config_word(slot->bus, slot->devfn, hs_cap + 2, &hs_csr)) return 0; if (hs_csr & HS_CSR_EXT) ext = 1; return ext; }
static void __init cns3xxx_pcie_hw_init(struct cns3xxx_pcie *cnspci) { int port = cnspci->port; struct pci_sys_data sd = { .private_data = cnspci, }; struct pci_bus bus = { .number = 0, .ops = &cns3xxx_pcie_ops, .sysdata = &sd, }; u16 mem_base = cnspci->res_mem.start >> 16; u16 mem_limit = cnspci->res_mem.end >> 16; u16 io_base = cnspci->res_io.start >> 16; u16 io_limit = cnspci->res_io.end >> 16; u32 devfn = 0; u8 tmp8; u16 pos; u16 dc; pci_bus_write_config_byte(&bus, devfn, PCI_PRIMARY_BUS, 0); pci_bus_write_config_byte(&bus, devfn, PCI_SECONDARY_BUS, 1); pci_bus_write_config_byte(&bus, devfn, PCI_SUBORDINATE_BUS, 1); pci_bus_read_config_byte(&bus, devfn, PCI_PRIMARY_BUS, &tmp8); pci_bus_read_config_byte(&bus, devfn, PCI_SECONDARY_BUS, &tmp8); pci_bus_read_config_byte(&bus, devfn, PCI_SUBORDINATE_BUS, &tmp8); pci_bus_write_config_word(&bus, devfn, PCI_MEMORY_BASE, mem_base); pci_bus_write_config_word(&bus, devfn, PCI_MEMORY_LIMIT, mem_limit); pci_bus_write_config_word(&bus, devfn, PCI_IO_BASE_UPPER16, io_base); pci_bus_write_config_word(&bus, devfn, PCI_IO_LIMIT_UPPER16, io_limit); if (!cnspci->linked) return; /* Set Device Max_Read_Request_Size to 128 byte */ bus.number = 1; /* directly connected PCIe device */ devfn = PCI_DEVFN(0, 0); pos = pci_bus_find_capability(&bus, devfn, PCI_CAP_ID_EXP); pci_bus_read_config_word(&bus, devfn, pos + PCI_EXP_DEVCTL, &dc); if (dc & PCI_EXP_DEVCTL_READRQ) { dc &= ~PCI_EXP_DEVCTL_READRQ; pci_bus_write_config_word(&bus, devfn, pos + PCI_EXP_DEVCTL, dc); pci_bus_read_config_word(&bus, devfn, pos + PCI_EXP_DEVCTL, &dc); if (dc & PCI_EXP_DEVCTL_READRQ) pr_warn("PCIe: Unable to set device Max_Read_Request_Size\n"); else pr_info("PCIe: Max_Read_Request_Size set to 128 bytes\n"); } /* Disable PCIe0 Interrupt Mask INTA to INTD */ __raw_writel(~0x3FFF, MISC_PCIE_INT_MASK(port)); } static int cns3xxx_pcie_abort_handler(unsigned long addr, unsigned int fsr, struct pt_regs *regs) { if (fsr & (1 << 10)) regs->ARM_pc += 4; return 0; } void __init cns3xxx_pcie_init_late(void) { int i; void *private_data; struct hw_pci hw_pci = { .nr_controllers = 1, .ops = &cns3xxx_pcie_ops, .setup = cns3xxx_pci_setup, .map_irq = cns3xxx_pcie_map_irq, .private_data = &private_data, }; pcibios_min_io = 0; pcibios_min_mem = 0; hook_fault_code(16 + 6, cns3xxx_pcie_abort_handler, SIGBUS, 0, "imprecise external abort"); for (i = 0; i < ARRAY_SIZE(cns3xxx_pcie); i++) { cns3xxx_pwr_clk_en(0x1 << PM_CLK_GATE_REG_OFFSET_PCIE(i)); cns3xxx_pwr_soft_rst(0x1 << PM_SOFT_RST_REG_OFFST_PCIE(i)); cns3xxx_pcie_check_link(&cns3xxx_pcie[i]); cns3xxx_pcie_hw_init(&cns3xxx_pcie[i]); private_data = &cns3xxx_pcie[i]; pci_common_init(&hw_pci); } pci_assign_unassigned_resources(); }
static int iproc_pcie_check_link(struct iproc_pcie *pcie, struct pci_bus *bus) { u8 hdr_type; u32 link_ctrl, class, val; u16 pos, link_status; bool link_is_active = false; val = readl(pcie->base + PCIE_LINK_STATUS_OFFSET); if (!(val & PCIE_PHYLINKUP) || !(val & PCIE_DL_ACTIVE)) { dev_err(pcie->dev, "PHY or data link is INACTIVE!\n"); return -ENODEV; } /* make sure we are not in EP mode */ pci_bus_read_config_byte(bus, 0, PCI_HEADER_TYPE, &hdr_type); if ((hdr_type & 0x7f) != PCI_HEADER_TYPE_BRIDGE) { dev_err(pcie->dev, "in EP mode, hdr=%#02x\n", hdr_type); return -EFAULT; } /* force class to PCI_CLASS_BRIDGE_PCI (0x0604) */ #define PCI_BRIDGE_CTRL_REG_OFFSET 0x43c #define PCI_CLASS_BRIDGE_MASK 0xffff00 #define PCI_CLASS_BRIDGE_SHIFT 8 pci_bus_read_config_dword(bus, 0, PCI_BRIDGE_CTRL_REG_OFFSET, &class); class &= ~PCI_CLASS_BRIDGE_MASK; class |= (PCI_CLASS_BRIDGE_PCI << PCI_CLASS_BRIDGE_SHIFT); pci_bus_write_config_dword(bus, 0, PCI_BRIDGE_CTRL_REG_OFFSET, class); /* check link status to see if link is active */ pos = pci_bus_find_capability(bus, 0, PCI_CAP_ID_EXP); pci_bus_read_config_word(bus, 0, pos + PCI_EXP_LNKSTA, &link_status); if (link_status & PCI_EXP_LNKSTA_NLW) link_is_active = true; if (!link_is_active) { /* try GEN 1 link speed */ #define PCI_LINK_STATUS_CTRL_2_OFFSET 0x0dc #define PCI_TARGET_LINK_SPEED_MASK 0xf #define PCI_TARGET_LINK_SPEED_GEN2 0x2 #define PCI_TARGET_LINK_SPEED_GEN1 0x1 pci_bus_read_config_dword(bus, 0, PCI_LINK_STATUS_CTRL_2_OFFSET, &link_ctrl); if ((link_ctrl & PCI_TARGET_LINK_SPEED_MASK) == PCI_TARGET_LINK_SPEED_GEN2) { link_ctrl &= ~PCI_TARGET_LINK_SPEED_MASK; link_ctrl |= PCI_TARGET_LINK_SPEED_GEN1; pci_bus_write_config_dword(bus, 0, PCI_LINK_STATUS_CTRL_2_OFFSET, link_ctrl); msleep(100); pos = pci_bus_find_capability(bus, 0, PCI_CAP_ID_EXP); pci_bus_read_config_word(bus, 0, pos + PCI_EXP_LNKSTA, &link_status); if (link_status & PCI_EXP_LNKSTA_NLW) link_is_active = true; } } dev_info(pcie->dev, "link: %s\n", link_is_active ? "UP" : "DOWN"); return link_is_active ? 0 : -ENODEV; }