lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Fri,  7 Oct 2016 18:15:55 +0300
From:   Pantelis Antoniou <pantelis.antoniou@...sulko.com>
To:     Greg Kroah-Hartman <gregkh@...uxfoundation.org>
Cc:     Debjit Ghosh <dghosh@...iper.net>,
        Georgi Vlaev <gvlaev@...iper.net>,
        Guenter Roeck <linux@...ck-us.net>,
        JawaharBalaji Thirumalaisamy <jawaharb@...iper.net>,
        Rajat Jain <rajatjain@...iper.net>,
        Shyamshankar Dharmarajan <shyamd@...iper.net>,
        Pantelis Antoniou <pantelis.antoniou@...sulko.com>,
        linux-kernel@...r.kernel.org, devel@...verdev.osuosl.org
Subject: [PATCH 2/3] staging: jnx: Common Juniper PCI methods

From: Rajat Jain <rajatjain@...iper.net>

All Juniper PTX platforms, whether powerpc or x86 based, use
similar PCI bridges (PLX & IDT). We don't want to duplicate
code in different arch directories, so put them here.

Signed-off-by: Debjit Ghosh <dghosh@...iper.net>
Signed-off-by: Guenter Roeck <groeck@...iper.net>
Signed-off-by: JawaharBalaji Thirumalaisamy <jawaharb@...iper.net>
Signed-off-by: Rajat Jain <rajatjain@...iper.net>
[Ported from Juniper kernel]
Signed-off-by: Pantelis Antoniou <pantelis.antoniou@...sulko.com>
---
 drivers/staging/jnx/Kconfig          |   6 +
 drivers/staging/jnx/Makefile         |   1 +
 drivers/staging/jnx/jnx_common_pci.c | 244 +++++++++++++++++++++++++++++++++++
 include/linux/jnx/jnx_common_pci.h   |  49 +++++++
 4 files changed, 300 insertions(+)
 create mode 100644 drivers/staging/jnx/jnx_common_pci.c
 create mode 100644 include/linux/jnx/jnx_common_pci.h

diff --git a/drivers/staging/jnx/Kconfig b/drivers/staging/jnx/Kconfig
index f01ef54..507f10d 100644
--- a/drivers/staging/jnx/Kconfig
+++ b/drivers/staging/jnx/Kconfig
@@ -21,6 +21,12 @@ config JNX_SYSTEM
 
 endmenu
 
+config JNX_COMMON_PCI
+	bool
+	---help---
+	  JNX common PCI code used by the quircks for configuring the PCIe
+	  switches in the system.
+
 config JNX_CHIP_PCI_QUIRKS
 	bool
 	select PCI_MMCONFIG
diff --git a/drivers/staging/jnx/Makefile b/drivers/staging/jnx/Makefile
index b29699c..0171476 100644
--- a/drivers/staging/jnx/Makefile
+++ b/drivers/staging/jnx/Makefile
@@ -4,3 +4,4 @@
 
 obj-$(CONFIG_JNX_SYSTEM)	+= jnx-subsys.o jnx-board-core.o
 obj-$(CONFIG_JNX_CHIP_PCI_QUIRKS)+= jnx-chip-pci-quirks.o
+obj-$(CONFIG_JNX_COMMON_PCI)	+= jnx_common_pci.o
diff --git a/drivers/staging/jnx/jnx_common_pci.c b/drivers/staging/jnx/jnx_common_pci.c
new file mode 100644
index 0000000..d234465
--- /dev/null
+++ b/drivers/staging/jnx/jnx_common_pci.c
@@ -0,0 +1,244 @@
+/*
+ * Common PTXPMB Board Setup - PCI fixup code
+ *
+ * Guenter Roeck <groeck@...iper.net>
+ * Copyright 2012-2014 Juniper Networks
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/bitops.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/jnx/pci_ids.h>
+#include <linux/of_platform.h>
+#include <linux/memblock.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+
+#include <linux/jnx/jnx_common_pci.h>
+
+#define IDT_GASAADDR		0x00000FF8	/* IDT Global Access Addr Reg */
+#define IDT_GASADATA		0x00000FFC	/* IDT Global Access Data Reg */
+#define IDT_SWCTL		0x0003E000	/* IDT Switch Ctl Register */
+#define IDT_SWCTL_REGUNLOCK	BIT(3)		/* "Unlock" bit in Switch Ctl */
+
+#define PLX_MAGIC_REG		0x660
+#define PLX_MAGIC_BIT		BIT(30)
+
+/*
+ * Use undocumented PLX technique to unlock all registers
+ * (Including the "Read only" ones)
+ */
+void plx_unlock_registers(struct pci_dev *dev)
+{
+	u32 reg32;
+
+	pci_read_config_dword(dev, PLX_MAGIC_REG, &reg32);
+	pci_write_config_dword(dev, PLX_MAGIC_REG, reg32 | PLX_MAGIC_BIT);
+	pci_read_config_dword(dev, PLX_MAGIC_REG, &reg32);
+}
+
+/*
+ * Lock back the Read only registers
+ */
+void plx_lock_registers(struct pci_dev *dev)
+{
+	u32 reg32;
+
+	pci_read_config_dword(dev, PLX_MAGIC_REG, &reg32);
+	/*
+	 * This is a hack. For some reason, if I lock it back, the
+	 * INTERRUPT_PIN register is not getting cleared. Will need to talk to
+	 * PLX about this. For now, leave it unlocked.
+	 * pci_write_config_dword(dev, PLX_MAGIC_REG, reg32 & ~PLX_MAGIC_BIT);
+	 */
+	pci_write_config_dword(dev, PLX_MAGIC_REG, reg32 | PLX_MAGIC_BIT);
+	pci_read_config_dword(dev, PLX_MAGIC_REG, &reg32);
+}
+
+/*
+ * Unlock all IDT registers (include read only registers)
+ */
+void idt_48H12G2_unlock_registers(struct pci_dev *dev)
+{
+	u32 reg32;
+
+	pci_write_config_dword(dev, IDT_GASAADDR, IDT_SWCTL);
+	pci_read_config_dword(dev, IDT_GASADATA, &reg32);
+	pci_write_config_dword(dev, IDT_GASAADDR, IDT_SWCTL);
+	pci_write_config_dword(dev, IDT_GASADATA, reg32 | IDT_SWCTL_REGUNLOCK);
+}
+
+/*
+ * Lock back the read only registers.
+ */
+void idt_48H12G2_lock_registers(struct pci_dev *dev)
+{
+	u32 reg32;
+
+	pci_write_config_dword(dev, IDT_GASAADDR, IDT_SWCTL);
+	pci_read_config_dword(dev, IDT_GASADATA, &reg32);
+	pci_write_config_dword(dev, IDT_GASAADDR, IDT_SWCTL);
+	pci_write_config_dword(dev, IDT_GASADATA, reg32 & ~IDT_SWCTL_REGUNLOCK);
+}
+
+/*
+ * Turn a downstream port into hot-pluggable slot (to be managed by hot-plug
+ * driver) by setting the required bits in the capability registers. The
+ * function ensures that only ports with link change notification capability
+ * are turned into hotpluggable slots.
+ */
+static void make_hotpluggable_slot(struct pci_dev *dev)
+{
+	u32 reg32, psn;
+	u16 reg16;
+
+	/*
+	 * Only configure downstream ports as hot-pluggable
+	 */
+	if (!pci_find_capability(dev, PCI_CAP_ID_EXP) ||
+	    pci_pcie_type(dev) != PCI_EXP_TYPE_DOWNSTREAM)
+		return;
+
+	/*
+	 * There is no point in making it hot-plug if the port
+	 * does not support link change notifications.
+	 */
+	pcie_capability_read_dword(dev, PCI_EXP_LNKCAP, &reg32);
+	if (!(reg32 & PCI_EXP_LNKCAP_DLLLARC)) {
+		dev_warn(&dev->dev,
+			 "port does not support link state reporting\n");
+		return;
+	}
+
+	/*
+	 * Set the PCIe Capability register and the cached copy
+	 * Set "Slot Implemented" bit
+	 */
+	pcie_capability_read_word(dev, PCI_EXP_FLAGS, &reg16);
+	reg16 |= PCI_EXP_FLAGS_SLOT;
+	pcie_capability_write_word(dev, PCI_EXP_FLAGS, reg16);
+	dev->pcie_flags_reg = reg16;
+
+	/*
+	 * Use port number as "Slot number"
+	 */
+	pcie_capability_read_dword(dev, PCI_EXP_LNKCAP, &reg32);
+	psn = (reg32 & PCI_EXP_LNKCAP_PN) >> 24;
+	psn = (psn << 19) & PCI_EXP_SLTCAP_PSN;
+
+	/*
+	 * Set the Slot capability register
+	 * Set "HP capable" and "Physical Slot number"
+	 */
+	pcie_capability_read_dword(dev, PCI_EXP_SLTCAP, &reg32);
+	reg32 &= ~PCI_EXP_SLTCAP_PSN;
+	reg32 |= PCI_EXP_SLTCAP_HPC | psn;
+	pcie_capability_write_dword(dev, PCI_EXP_SLTCAP, reg32);
+}
+
+static int ptx_get_pci_mem_region(struct pci_bus *bus,
+				  struct pci_bus_region *region)
+{
+	int i;
+	struct resource *res;
+
+	pci_bus_for_each_resource(bus, res, i) {
+		if (i > PCI_STD_RESOURCE_END && i < PCI_BRIDGE_RESOURCES)
+			continue;
+		if (res && (res->flags & IORESOURCE_MEM)) {
+			pcibios_resource_to_bus(bus, region, res);
+			return 0;
+		}
+	}
+	return -ENOMEM;
+}
+
+void jnx_fixup_pcie_bridge(struct pci_dev *dev, struct bus_assigns *ap,
+			   u16 base)
+{
+	for (; ap->bus; ap++) {
+		if (ap->bus == dev->bus->number &&
+		    (ap->slot == ANY || ap->slot == PCI_SLOT(dev->devfn))) {
+			pci_write_config_dword(dev, PCI_PRIMARY_BUS, ap->range);
+			if (ap->flags & PCI_MEM_WINDOW_DISABLED) {
+				pci_write_config_word(dev, PCI_MEMORY_BASE,
+						      0xFFFF);
+				pci_write_config_word(dev, PCI_MEMORY_LIMIT,
+						      0x0000);
+			} else {
+				pci_write_config_word(dev, PCI_MEMORY_BASE,
+						      base + ap->offset);
+				pci_write_config_word(dev, PCI_MEMORY_LIMIT,
+						      base + ap->offset +
+						      ap->limit);
+			}
+			pci_write_config_word(dev, PCI_IO_BASE, 0x0);
+			pci_write_config_word(dev, PCI_COMMAND, ap->command);
+			if (ap->flags & PCI_PORT_IS_HOTPLUGGABLE)
+				make_hotpluggable_slot(dev);
+			if (ap->flags & PCI_PORT_POWERON_DELAY)
+				dev->poweron_delay = 1;
+
+			return;
+		}
+	}
+	dev_err(&dev->dev,
+		"No configuration [bus 0x%x slot 0x%x devfn 0x%x]\n",
+		dev->bus->number, PCI_SLOT(dev->devfn), dev->devfn);
+}
+EXPORT_SYMBOL(jnx_fixup_pcie_bridge);
+
+void ptx_init_pci_bridge(struct pci_dev *dev, struct bus_assigns *ap)
+{
+	struct pci_bus_region region;
+	u32 base;
+
+	/* Get memory base address from parent bus */
+	if (!ptx_get_pci_mem_region(dev->bus->parent, &region)) {
+		base = (region.start >> 16) & 0xfff0;
+	} else {
+		dev_err(&dev->dev, "Can not allocate bridge memory\n");
+		base = 0;
+	}
+	jnx_fixup_pcie_bridge(dev, ap, base);
+}
+EXPORT_SYMBOL(ptx_init_pci_bridge);
+
+static void ptx_init_pci_root_bridge(struct pci_dev *dev)
+{
+	struct pci_bus_region region;
+	u32 base, limit;
+
+	if (!ptx_get_pci_mem_region(dev->bus, &region)) {
+		base = (region.start >> 16) & 0xfff0;
+		limit = (region.end >> 16) & 0xfff0;
+	} else {
+		dev_err(&dev->dev, "Can not allocate root bridge memory\n");
+		base = 0;
+		limit = 0;
+	}
+
+	pci_write_config_dword(dev, PCI_PRIMARY_BUS, 0xff0100);
+	pci_write_config_word(dev, PCI_MEMORY_BASE, base);
+	pci_write_config_word(dev, PCI_MEMORY_LIMIT, limit);
+	pci_write_config_word(dev, PCI_COMMAND, PCI_CMD_MEM_MSTR);
+	dev->class = PCI_CLASS_BRIDGE_PCI << 8;
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_FREESCALE, PCI_DEVICE_ID_P2020E,
+			ptx_init_pci_root_bridge);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_FREESCALE, PCI_DEVICE_ID_P2020,
+			ptx_init_pci_root_bridge);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_FREESCALE, 0x0450, /* P5040 */
+			ptx_init_pci_root_bridge);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_FREESCALE, PCI_DEVICE_ID_P5020E,
+			ptx_init_pci_root_bridge);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_FREESCALE, PCI_DEVICE_ID_P5020,
+			ptx_init_pci_root_bridge);
+
diff --git a/include/linux/jnx/jnx_common_pci.h b/include/linux/jnx/jnx_common_pci.h
new file mode 100644
index 0000000..c89e2de
--- /dev/null
+++ b/include/linux/jnx/jnx_common_pci.h
@@ -0,0 +1,49 @@
+/*
+ * Common Juniper PCI routine declarations
+ *
+ * Rajat Jain <rajatjain@...iper.net>
+ * Copyright 2014 Juniper Networks
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __JNX_COMMON_PCI_H__
+#define __JNX_COMMON_PCI_H__
+
+/*
+ * Normally bus number ranges, memory maps for PCI bridges and hotplug
+ * capabilities should be initialized by the ROMMON or BIOS or u-boot.
+ * Unfortunately, that is not done correctly today. If that happens and
+ * if the PCIe switch is correctly configured in ROMMON/BIOS/uboot,
+ * we may not need this.
+ */
+struct bus_assigns {
+	u8 bus;		/* bus number */
+	u8 slot;	/* slot number, ANY for all */
+#define ANY		0xff
+	u32 range;	/* bus number range. Three bytes <max, min, curr> */
+	u16 offset;	/* base address offset relative to parent */
+	u16 limit;	/* memory limit (size), added to offset & base */
+	u16 command;	/* command to write into command word */
+#define PCI_CMD_MEM_MSTR    (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER)
+	u32 flags;
+#define PCI_PORT_IS_HOTPLUGGABLE (1 << 0) /* true if port is hotpluggable */
+#define PCI_MEM_WINDOW_DISABLED	 (1 << 1)
+#define PCI_PORT_POWERON_DELAY	 (1 << 2) /* true if port needs poweron delay */
+};
+
+/* Common helper routines */
+void jnx_fixup_pcie_bridge(struct pci_dev *, struct bus_assigns *, u16);
+extern void ptx_init_pci_bridge(struct pci_dev *, struct bus_assigns *);
+
+/* PLX routines */
+extern void plx_unlock_registers(struct pci_dev *dev);
+extern void plx_lock_registers(struct pci_dev *dev);
+
+/* IDT routines */
+extern void idt_48H12G2_unlock_registers(struct pci_dev *dev);
+extern void idt_48H12G2_lock_registers(struct pci_dev *dev);
+#endif /* __JNX_COMMON_PCI_H__ */
-- 
1.9.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ