Module Name:    src
Committed By:   jakllsch
Date:           Tue Nov 17 22:01:39 UTC 2015

Modified Files:
        src/sys/arch/arm/nvidia: tegra_pcie.c

Log Message:
Add PCI Extended Configuration support for tegrapcie(4).

Similar to the acpimcfg code, this only maps the extended configuration
space into KVA for known busses.


To generate a diff of this commit:
cvs rdiff -u -r1.11 -r1.12 src/sys/arch/arm/nvidia/tegra_pcie.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/arm/nvidia/tegra_pcie.c
diff -u src/sys/arch/arm/nvidia/tegra_pcie.c:1.11 src/sys/arch/arm/nvidia/tegra_pcie.c:1.12
--- src/sys/arch/arm/nvidia/tegra_pcie.c:1.11	Tue Nov 17 00:08:33 2015
+++ src/sys/arch/arm/nvidia/tegra_pcie.c	Tue Nov 17 22:01:39 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: tegra_pcie.c,v 1.11 2015/11/17 00:08:33 jakllsch Exp $ */
+/* $NetBSD: tegra_pcie.c,v 1.12 2015/11/17 22:01:39 jakllsch Exp $ */
 
 /*-
  * Copyright (c) 2015 Jared D. McNeill <jmcne...@invisible.ca>
@@ -29,7 +29,7 @@
 #include "locators.h"
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tegra_pcie.c,v 1.11 2015/11/17 00:08:33 jakllsch Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tegra_pcie.c,v 1.12 2015/11/17 22:01:39 jakllsch Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -55,6 +55,9 @@ __KERNEL_RCSID(0, "$NetBSD: tegra_pcie.c
 static int	tegra_pcie_match(device_t, cfdata_t, void *);
 static void	tegra_pcie_attach(device_t, device_t, void *);
 
+#define TEGRA_PCIE_NBUS 256
+#define TEGRA_PCIE_ECFB (1<<(12 - 8))	/* extended conf frags per bus */
+
 struct tegra_pcie_ih {
 	int			(*ih_callback)(void *);
 	void			*ih_arg;
@@ -68,7 +71,6 @@ struct tegra_pcie_softc {
 	bus_space_tag_t		sc_bst;
 	bus_space_handle_t	sc_bsh_afi;
 	bus_space_handle_t	sc_bsh_rpconf;
-	bus_space_handle_t	sc_bsh_conf;
 	int			sc_intr;
 
 	struct arm32_pci_chipset sc_pc;
@@ -79,12 +81,18 @@ struct tegra_pcie_softc {
 
 	TAILQ_HEAD(, tegra_pcie_ih) sc_intrs;
 	u_int			sc_intrgen;
+
+	bus_space_handle_t	sc_bsh_extc[TEGRA_PCIE_NBUS-1][TEGRA_PCIE_ECFB];
 };
 
 static int	tegra_pcie_intr(void *);
 static void	tegra_pcie_init(pci_chipset_tag_t, void *);
 static void	tegra_pcie_enable(struct tegra_pcie_softc *);
 static void	tegra_pcie_setup(struct tegra_pcie_softc * const);
+static void	tegra_pcie_conf_frag_map(struct tegra_pcie_softc * const,
+					 uint, uint);
+static void	tegra_pcie_conf_map_bus(struct tegra_pcie_softc * const, uint);
+static void	tegra_pcie_conf_map_buses(struct tegra_pcie_softc * const);
 
 static void	tegra_pcie_attach_hook(device_t, device_t,
 				       struct pcibus_attach_args *);
@@ -138,9 +146,7 @@ tegra_pcie_attach(device_t parent, devic
 	if (bus_space_map(sc->sc_bst, TEGRA_PCIE_RPCONF_BASE,
 	    TEGRA_PCIE_RPCONF_SIZE, 0, &sc->sc_bsh_rpconf) != 0)
 		panic("couldn't map PCIE root ports");
-	if (bus_space_map(sc->sc_bst, TEGRA_PCIE_CONF_BASE,
-	    TEGRA_PCIE_CONF_SIZE, 0, &sc->sc_bsh_conf) != 0)
-		panic("couldn't map PCIE configuration");
+	tegra_pcie_conf_map_buses(sc);
 
 	TAILQ_INIT(&sc->sc_intrs);
 	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_VM);
@@ -339,6 +345,51 @@ tegra_pcie_enable(struct tegra_pcie_soft
 	    AFI_INTR_MASK_REG, AFI_INTR_MASK_INT);
 }
 
+static void
+tegra_pcie_conf_frag_map(struct tegra_pcie_softc * const sc, uint bus,
+    uint frg)
+{
+	bus_addr_t a;
+
+	KASSERT(bus >= 1);
+	KASSERT(bus < TEGRA_PCIE_NBUS);
+	KASSERT(frg < TEGRA_PCIE_ECFB);
+
+	if (sc->sc_bsh_extc[bus-1][frg] != 0) {
+		device_printf(sc->sc_dev, "bus %u fragment %#x already "
+		    "mapped\n", bus, frg);
+		return;
+	}
+
+	a = TEGRA_PCIE_EXTC_BASE + (bus << 16) + (frg << 24);
+	if (bus_space_map(sc->sc_bst, a, 1 << 16, 0,
+	    &sc->sc_bsh_extc[bus-1][frg]) != 0)
+		device_printf(sc->sc_dev, "couldn't map PCIE "
+		    "configuration for bus %u fragment %#x", bus, frg);
+}
+
+/* map non-non-extended configuration space for full bus range */
+static void
+tegra_pcie_conf_map_bus(struct tegra_pcie_softc * const sc, uint bus)
+{
+	uint i;
+
+	for (i = 1; i < TEGRA_PCIE_ECFB; i++) {
+		tegra_pcie_conf_frag_map(sc, bus, i);
+	}
+}
+
+/* map non-extended configuration space for full bus range */
+static void
+tegra_pcie_conf_map_buses(struct tegra_pcie_softc * const sc)
+{
+	uint b;
+
+	for (b = 1; b < TEGRA_PCIE_NBUS; b++) {
+		tegra_pcie_conf_frag_map(sc, b, 0);
+	}
+}
+
 void
 tegra_pcie_init(pci_chipset_tag_t pc, void *priv)
 {
@@ -364,6 +415,12 @@ static void
 tegra_pcie_attach_hook(device_t parent, device_t self,
     struct pcibus_attach_args *pba)
 {
+	const pci_chipset_tag_t pc = pba->pba_pc;
+	struct tegra_pcie_softc * const sc = pc->pc_conf_v;
+
+	if (pba->pba_bus >= 1) {
+		tegra_pcie_conf_map_bus(sc, pba->pba_bus);
+	}
 }
 
 static int
@@ -402,16 +459,19 @@ tegra_pcie_conf_read(void *v, pcitag_t t
 
 	tegra_pcie_decompose_tag(v, tag, &b, &d, &f);
 
+	if (b >= TEGRA_PCIE_NBUS)
+		return (pcireg_t) -1;
+
 	if (b == 0) {
 		if (d >= 2 || f != 0)
 			return (pcireg_t) -1;
 		reg = d * 0x1000 + offset;
 		bsh = sc->sc_bsh_rpconf;
 	} else {
-		if ((unsigned int)offset >= PCI_CONF_SIZE)
+		reg = (d << 11) | (f << 8) | (offset & 0xff);
+		bsh = sc->sc_bsh_extc[b-1][(offset >> 8) & 0xf];
+		if (bsh == 0)
 			return (pcireg_t) -1;
-		reg = tag | offset;
-		bsh = sc->sc_bsh_conf;
 	}
 
 	return bus_space_read_4(sc->sc_bst, bsh, reg);
@@ -430,16 +490,19 @@ tegra_pcie_conf_write(void *v, pcitag_t 
 
 	tegra_pcie_decompose_tag(v, tag, &b, &d, &f);
 
+	if (b >= TEGRA_PCIE_NBUS)
+		return;
+
 	if (b == 0) {
 		if (d >= 2 || f != 0)
 			return;
 		reg = d * 0x1000 + offset;
 		bsh = sc->sc_bsh_rpconf;
 	} else {
-		if ((unsigned int)offset >= PCI_CONF_SIZE)
+		reg = (d << 11) | (f << 8) | (offset & 0xff);
+		bsh = sc->sc_bsh_extc[b-1][(offset >> 8) & 0xf];
+		if (bsh == 0)
 			return;
-		reg = tag | offset;
-		bsh = sc->sc_bsh_conf;
 	}
 
 	bus_space_write_4(sc->sc_bst, bsh, reg, val);

Reply via email to