static int iproc_pcie_check_link(struct iproc_pcie *pcie, struct pci_bus *bus) { u8 hdr_type; u32 link_ctrl; u16 pos, link_status; int link_is_active = 0; /* 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) */ pci_bus_write_config_word(bus, 0, PCI_CLASS_DEVICE, PCI_CLASS_BRIDGE_PCI); /* 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 = 1; 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 = 1; } } dev_info(pcie->dev, "link: %s\n", link_is_active ? "UP" : "DOWN"); return link_is_active ? 0 : -ENODEV; }
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", slot->hotplug_slot->name); return -ENODEV; } } return 0; }
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 pci_read_config_word(const struct pci_dev *dev, int where, u16 *val) { if (pci_dev_is_disconnected(dev)) { *val = ~0; return PCIBIOS_DEVICE_NOT_FOUND; } return pci_bus_read_config_word(dev->bus, dev->devfn, where, val); }
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 __devinit quirk_intel_irqbalance(struct pci_dev *dev) { u8 config, rev; u16 word; /* BIOS may enable hardware IRQ balancing for * E7520/E7320/E7525(revision ID 0x9 and below) * based platforms. * Disable SW irqbalance/affinity on those platforms. */ pci_read_config_byte(dev, PCI_CLASS_REVISION, &rev); if (rev > 0x9) return; /* enable access to config space*/ pci_read_config_byte(dev, 0xf4, &config); pci_write_config_byte(dev, 0xf4, config|0x2); /* * read xTPR register. We may not have a pci_dev for device 8 * because it might be hidden until the above write. */ pci_bus_read_config_word(dev->bus, PCI_DEVFN(8, 0), 0x4c, &word); if (!(word & (1 << 13))) { dev_info(&dev->dev, "Intel E7520/7320/7525 detected; " "disabling irq balancing and affinity\n"); noirqdebug_setup(""); #ifdef CONFIG_PROC_FS no_irq_affinity = 1; #endif } /* put back the original value for config space*/ if (!(config & 0x2)) pci_write_config_byte(dev, 0xf4, config); }
static unsigned long i915_stolen_to_physical(struct drm_i915_private *dev_priv) { struct pci_dev *pdev = dev_priv->drm.pdev; struct i915_ggtt *ggtt = &dev_priv->ggtt; struct resource *r; u32 base; /* Almost universally we can find the Graphics Base of Stolen Memory * at register BSM (0x5c) in the igfx configuration space. On a few * (desktop) machines this is also mirrored in the bridge device at * different locations, or in the MCHBAR. * * On 865 we just check the TOUD register. * * On 830/845/85x the stolen memory base isn't available in any * register. We need to calculate it as TOM-TSEG_SIZE-stolen_size. * */ base = 0; if (INTEL_GEN(dev_priv) >= 3) { u32 bsm; pci_read_config_dword(pdev, INTEL_BSM, &bsm); base = bsm & INTEL_BSM_MASK; } else if (IS_I865G(dev_priv)) { u32 tseg_size = 0; u16 toud = 0; u8 tmp; pci_bus_read_config_byte(pdev->bus, PCI_DEVFN(0, 0), I845_ESMRAMC, &tmp); if (tmp & TSEG_ENABLE) { switch (tmp & I845_TSEG_SIZE_MASK) { case I845_TSEG_SIZE_512K: tseg_size = KB(512); break; case I845_TSEG_SIZE_1M: tseg_size = MB(1); break; } } pci_bus_read_config_word(pdev->bus, PCI_DEVFN(0, 0), I865_TOUD, &toud); base = (toud << 16) + tseg_size; } else if (IS_I85X(dev_priv)) { u32 tseg_size = 0; u32 tom; u8 tmp; pci_bus_read_config_byte(pdev->bus, PCI_DEVFN(0, 0), I85X_ESMRAMC, &tmp); if (tmp & TSEG_ENABLE) tseg_size = MB(1); pci_bus_read_config_byte(pdev->bus, PCI_DEVFN(0, 1), I85X_DRB3, &tmp); tom = tmp * MB(32); base = tom - tseg_size - ggtt->stolen_size; } else if (IS_845G(dev_priv)) { u32 tseg_size = 0; u32 tom; u8 tmp; pci_bus_read_config_byte(pdev->bus, PCI_DEVFN(0, 0), I845_ESMRAMC, &tmp); if (tmp & TSEG_ENABLE) { switch (tmp & I845_TSEG_SIZE_MASK) { case I845_TSEG_SIZE_512K: tseg_size = KB(512); break; case I845_TSEG_SIZE_1M: tseg_size = MB(1); break; } } pci_bus_read_config_byte(pdev->bus, PCI_DEVFN(0, 0), I830_DRB3, &tmp); tom = tmp * MB(32); base = tom - tseg_size - ggtt->stolen_size; } else if (IS_I830(dev_priv)) { u32 tseg_size = 0; u32 tom; u8 tmp; pci_bus_read_config_byte(pdev->bus, PCI_DEVFN(0, 0), I830_ESMRAMC, &tmp); if (tmp & TSEG_ENABLE) { if (tmp & I830_TSEG_SIZE_1M) tseg_size = MB(1); else tseg_size = KB(512); } pci_bus_read_config_byte(pdev->bus, PCI_DEVFN(0, 0), I830_DRB3, &tmp); tom = tmp * MB(32); base = tom - tseg_size - ggtt->stolen_size; } if (base == 0) return 0; /* make sure we don't clobber the GTT if it's within stolen memory */ if (INTEL_GEN(dev_priv) <= 4 && !IS_G33(dev_priv) && !IS_G4X(dev_priv)) { struct { u32 start, end; } stolen[2] = { { .start = base, .end = base + ggtt->stolen_size, }, { .start = base, .end = base + ggtt->stolen_size, }, };
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 unsigned long i915_stolen_to_physical(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; u32 base; /* Almost universally we can find the Graphics Base of Stolen Memory * at offset 0x5c in the igfx configuration space. On a few (desktop) * machines this is also mirrored in the bridge device at different * locations, or in the MCHBAR. * * On 865 we just check the TOUD register. * * On 830/845/85x the stolen memory base isn't available in any * register. We need to calculate it as TOM-TSEG_SIZE-stolen_size. * */ base = 0; if (INTEL_INFO(dev)->gen >= 3) { /* Read Graphics Base of Stolen Memory directly */ pci_read_config_dword(dev->pdev, 0x5c, &base); base &= ~((1<<20) - 1); #if 0 } else if (IS_I865G(dev)) { u16 toud = 0; /* * FIXME is the graphics stolen memory region * always at TOUD? Ie. is it always the last * one to be allocated by the BIOS? */ pci_bus_read_config_word(dev->pdev->bus, PCI_DEVFN(0, 0), I865_TOUD, &toud); base = toud << 16; } else if (IS_I85X(dev)) { u32 tseg_size = 0; u32 tom; u8 tmp; pci_bus_read_config_byte(dev->pdev->bus, PCI_DEVFN(0, 0), I85X_ESMRAMC, &tmp); if (tmp & TSEG_ENABLE) tseg_size = MB(1); pci_bus_read_config_byte(dev->pdev->bus, PCI_DEVFN(0, 1), I85X_DRB3, &tmp); tom = tmp * MB(32); base = tom - tseg_size - dev_priv->gtt.stolen_size; } else if (IS_845G(dev)) { u32 tseg_size = 0; u32 tom; u8 tmp; pci_bus_read_config_byte(dev->pdev->bus, PCI_DEVFN(0, 0), I845_ESMRAMC, &tmp); if (tmp & TSEG_ENABLE) { switch (tmp & I845_TSEG_SIZE_MASK) { case I845_TSEG_SIZE_512K: tseg_size = KB(512); break; case I845_TSEG_SIZE_1M: tseg_size = MB(1); break; } } pci_bus_read_config_byte(dev->pdev->bus, PCI_DEVFN(0, 0), I830_DRB3, &tmp); tom = tmp * MB(32); base = tom - tseg_size - dev_priv->gtt.stolen_size; } else if (IS_I830(dev)) { u32 tseg_size = 0; u32 tom; u8 tmp; pci_bus_read_config_byte(dev->pdev->bus, PCI_DEVFN(0, 0), I830_ESMRAMC, &tmp); if (tmp & TSEG_ENABLE) { if (tmp & I830_TSEG_SIZE_1M) tseg_size = MB(1); else tseg_size = KB(512); } pci_bus_read_config_byte(dev->pdev->bus, PCI_DEVFN(0, 0), I830_DRB3, &tmp); tom = tmp * MB(32); base = tom - tseg_size - dev_priv->gtt.stolen_size; #endif } if (base == 0) return 0; /* make sure we don't clobber the GTT if it's within stolen memory */ if (INTEL_INFO(dev)->gen <= 4 && !IS_G33(dev) && !IS_G4X(dev)) { struct { u32 start, end; } stolen[2] = { { .start = base, .end = base + dev_priv->gtt.stolen_size, }, { .start = base, .end = base + dev_priv->gtt.stolen_size, }, };
static int iproc_pcie_check_link(struct iproc_pcie *pcie, struct pci_bus *bus) { struct device *dev = pcie->dev; u8 hdr_type; u32 link_ctrl, class, val; u16 pos = PCI_EXP_CAP, link_status; bool link_is_active = false; /* * PAXC connects to emulated endpoint devices directly and does not * have a Serdes. Therefore skip the link detection logic here. */ if (pcie->type == IPROC_PCIE_PAXC) return 0; val = iproc_pcie_read_reg(pcie, IPROC_PCIE_LINK_STATUS); if (!(val & PCIE_PHYLINKUP) || !(val & PCIE_DL_ACTIVE)) { dev_err(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(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 */ 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_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, pos + PCI_EXP_LNKCTL2, &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, pos + PCI_EXP_LNKCTL2, link_ctrl); msleep(100); 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(dev, "link: %s\n", link_is_active ? "UP" : "DOWN"); return link_is_active ? 0 : -ENODEV; }
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; }