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]
Message-ID: <20250609221710.10315-4-james.quinlan@broadcom.com>
Date: Mon,  9 Jun 2025 18:17:06 -0400
From: Jim Quinlan <james.quinlan@...adcom.com>
To: linux-pci@...r.kernel.org,
	Nicolas Saenz Julienne <nsaenz@...nel.org>,
	Bjorn Helgaas <bhelgaas@...gle.com>,
	Lorenzo Pieralisi <lorenzo.pieralisi@....com>,
	bcm-kernel-feedback-list@...adcom.com,
	jim2101024@...il.com,
	james.quinlan@...adcom.com
Cc: Florian Fainelli <florian.fainelli@...adcom.com>,
	Lorenzo Pieralisi <lpieralisi@...nel.org>,
	Krzysztof WilczyƄski <kwilczynski@...nel.org>,
	Manivannan Sadhasivam <mani@...nel.org>,
	Rob Herring <robh@...nel.org>,
	linux-rpi-kernel@...ts.infradead.org (moderated list:BROADCOM BCM2711/BCM2835 ARM ARCHITECTURE),
	linux-arm-kernel@...ts.infradead.org (moderated list:BROADCOM BCM2711/BCM2835 ARM ARCHITECTURE),
	linux-kernel@...r.kernel.org (open list)
Subject: [PATCH 3/3] PCI: brcmstb: Enable Broadcom Cable Modem SoCs

Broadcom's Cable Modem (CM) group also uses this PCIe driver
as it shares the PCIe HW core with the STB group.

Make the modifications to enable the CM SoCs.

Signed-off-by: Jim Quinlan <james.quinlan@...adcom.com>
---
 drivers/pci/controller/pcie-brcmstb.c | 186 +++++++++++++++++++++-----
 1 file changed, 152 insertions(+), 34 deletions(-)

diff --git a/drivers/pci/controller/pcie-brcmstb.c b/drivers/pci/controller/pcie-brcmstb.c
index db7872cda960..e25dbcdc56a7 100644
--- a/drivers/pci/controller/pcie-brcmstb.c
+++ b/drivers/pci/controller/pcie-brcmstb.c
@@ -51,6 +51,9 @@
 #define PCIE_RC_CFG_PRIV1_ROOT_CAP			0x4f8
 #define  PCIE_RC_CFG_PRIV1_ROOT_CAP_L1SS_MODE_MASK	0xf8
 
+#define PCIE_RC_DL_PDL_CONTROL_4			0x1010
+#define  PCIE_RC_DL_PDL_CONTROL_4_NPH_FC_INIT_MASK	0xff000000
+
 #define PCIE_RC_DL_MDIO_ADDR				0x1100
 #define PCIE_RC_DL_MDIO_WR_DATA				0x1104
 #define PCIE_RC_DL_MDIO_RD_DATA				0x1108
@@ -60,6 +63,7 @@
 #define  PCIE_RC_PL_PHY_CTL_15_PM_CLK_PERIOD_MASK	0xff
 
 #define PCIE_MISC_MISC_CTRL				0x4008
+#define  PCIE_MISC_MISC_CTRL_PCIE_IN_CPL_RO_MASK	0x20
 #define  PCIE_MISC_MISC_CTRL_PCIE_RCB_64B_MODE_MASK	0x80
 #define  PCIE_MISC_MISC_CTRL_PCIE_RCB_MPS_MODE_MASK	0x400
 #define  PCIE_MISC_MISC_CTRL_SCB_ACCESS_EN_MASK		0x1000
@@ -170,6 +174,7 @@
 /* MSI target addresses */
 #define BRCM_MSI_TARGET_ADDR_LT_4GB	0x0fffffffcULL
 #define BRCM_MSI_TARGET_ADDR_GT_4GB	0xffffffffcULL
+#define BRCM_MSI_TARGET_ADDR_FOR_CM	0xfffffffffcULL
 
 /* MDIO registers */
 #define MDIO_PORT0			0x0
@@ -223,13 +228,23 @@ enum {
 enum pcie_soc_base {
 	GENERIC,
 	BCM2711,
+	BCM3162,
+	BCM3392,
+	BCM3390,
 	BCM4908,
 	BCM7278,
 	BCM7425,
 	BCM7435,
 	BCM7712,
+	BCM33940,
 };
 
+/*
+ * BCM3390 CM chip actually conforms to STB design, so it
+ * is not present in the macro below.
+ */
+#define IS_CM_SOC(t) ((t) == BCM3162 || (t) == BCM33940 || (t) == BCM3392)
+
 struct inbound_win {
 	u64 size;
 	u64 pci_offset;
@@ -757,6 +772,9 @@ static int brcm_pcie_bridge_sw_init_set_generic(struct brcm_pcie *pcie, u32 val)
 	u32 shift = RGR1_SW_INIT_1_INIT_GENERIC_SHIFT;
 	int ret = 0;
 
+	if (IS_CM_SOC(pcie->cfg->soc_base))
+		return 0;
+
 	if (pcie->bridge_reset) {
 		if (val)
 			ret = reset_control_assert(pcie->bridge_reset);
@@ -891,13 +909,13 @@ static int brcm_pcie_get_inbound_wins(struct brcm_pcie *pcie,
 	struct inbound_win *b = b_begin;
 
 	/*
-	 * STB chips beside 7712 disable the first inbound window default.
-	 * Rather being mapped to system memory it is mapped to the
-	 * internal registers of the SoC.  This feature is deprecated, has
-	 * security considerations, and is not implemented in our modern
-	 * SoCs.
+	 * STB chips beside CM chips and 7712 disable the first inbound
+	 * window default.  Rather being mapped to system memory it is
+	 * mapped to the internal registers of the SoC.  This feature is
+	 * deprecated, has security considerations, and is not
+	 * implemented in our modern SoCs.
 	 */
-	if (pcie->cfg->soc_base != BCM7712)
+	if (pcie->cfg->soc_base != BCM7712 && !IS_CM_SOC(pcie->cfg->soc_base))
 		add_inbound_win(b++, &n, 0, 0, 0);
 
 	resource_list_for_each_entry(entry, &bridge->dma_ranges) {
@@ -905,16 +923,32 @@ static int brcm_pcie_get_inbound_wins(struct brcm_pcie *pcie,
 		u64 cpu_start = entry->res->start;
 
 		size = resource_size(entry->res);
+
+		/*
+		 * For BCM3390, single dma-range may map to the SoC
+		 * register space in [0xf0000000..0xffffffff].  If present,
+		 * this has to be assigned to inbound window #1, as this is
+		 * the only one that HW allows to map to register space.
+		 * So if we see this range, place it in inbound_wins[1]
+		 * which is previously disabled (zeroed out).
+		 */
+		if (pcie->cfg->soc_base == BCM3390 && cpu_start >= 0xf0000000
+		    && cpu_start + size - 1 <= 0xffffffff) {
+			add_inbound_win(b_begin, &n, size, cpu_start, pcie_start);
+			n--;
+			continue;
+		}
+
 		tot_size += size;
 		if (pcie_start < lowest_pcie_addr)
 			lowest_pcie_addr = pcie_start;
 		/*
-		 * 7712 and newer chips may have many BARs, with each
-		 * offering a non-overlapping viewport to system memory.
-		 * That being said, each BARs size must still be a power of
-		 * two.
+		 * 7712, CM, and newer chips may have many inbound windows,
+		 * with each offering a non-overlapping viewport to system
+		 * memory.  That being said, each window's size must still
+		 * be a power of two.
 		 */
-		if (pcie->cfg->soc_base == BCM7712)
+		if (pcie->cfg->soc_base == BCM7712 || IS_CM_SOC(pcie->cfg->soc_base))
 			add_inbound_win(b++, &n, size, cpu_start, pcie_start);
 
 		if (n > pcie->cfg->num_inbound_wins)
@@ -927,11 +961,11 @@ static int brcm_pcie_get_inbound_wins(struct brcm_pcie *pcie,
 	}
 
 	/*
-	 * 7712 and newer chips do not have an internal memory mapping system
-	 * that enables multiple memory controllers.  As such, it can return
-	 * now w/o doing special configuration.
+	 * 7712, CM, and newer chips do not have an internal memory
+	 * mapping system that enables multiple memory controllers.  As
+	 * such, it can return now w/o doing special configuration.
 	 */
-	if (pcie->cfg->soc_base == BCM7712)
+	if (pcie->cfg->soc_base == BCM7712 || IS_CM_SOC(pcie->cfg->soc_base))
 		return n;
 
 	ret = of_property_read_variable_u64_array(pcie->np, "brcm,scb-sizes", pcie->memc_size, 1,
@@ -1051,10 +1085,10 @@ static void set_inbound_win_registers(struct brcm_pcie *pcie,
 		/*
 		 * Most STB chips:
 		 *     Do nothing.
-		 * 7712:
-		 *     All of their BARs need to be set.
+		 * 7712, CM:
+		 *     All of their inbound windows need to be set.
 		 */
-		if (pcie->cfg->soc_base == BCM7712) {
+		if (pcie->cfg->soc_base == BCM7712 || IS_CM_SOC(pcie->cfg->soc_base)) {
 			/* BUS remap register settings */
 			reg_offset = brcm_ubus_reg_offset(i);
 			tmp = lower_32_bits(cpu_addr) & ~0xfff;
@@ -1118,6 +1152,8 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie)
 		burst = 0x0; /* 128 bytes */
 	else if (pcie->cfg->soc_base == BCM7278)
 		burst = 0x3; /* 512 bytes */
+	else if (pcie->cfg->soc_base == BCM3162 || pcie->cfg->soc_base == BCM33940)
+		burst = 0x1; /* Encoding: 0=64, 1=128, 2=Rsvd, 3=Rsvd */
 	else
 		burst = 0x2; /* 512 bytes */
 
@@ -1144,18 +1180,20 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie)
 		return -EINVAL;
 	}
 
-	tmp = readl(base + PCIE_MISC_MISC_CTRL);
-	for (memc = 0; memc < pcie->num_memc; memc++) {
-		u32 scb_size_val = ilog2(pcie->memc_size[memc]) - 15;
-
-		if (memc == 0)
-			u32p_replace_bits(&tmp, scb_size_val, SCB_SIZE_MASK(0));
-		else if (memc == 1)
-			u32p_replace_bits(&tmp, scb_size_val, SCB_SIZE_MASK(1));
-		else if (memc == 2)
-			u32p_replace_bits(&tmp, scb_size_val, SCB_SIZE_MASK(2));
+	if (!IS_CM_SOC(pcie->cfg->soc_base)) {
+		tmp = readl(base + PCIE_MISC_MISC_CTRL);
+		for (memc = 0; memc < pcie->num_memc; memc++) {
+			u32 scb_size_val = ilog2(pcie->memc_size[memc]) - 15;
+
+			if (memc == 0)
+				u32p_replace_bits(&tmp, scb_size_val, SCB_SIZE_MASK(0));
+			else if (memc == 1)
+				u32p_replace_bits(&tmp, scb_size_val, SCB_SIZE_MASK(1));
+			else if (memc == 2)
+				u32p_replace_bits(&tmp, scb_size_val, SCB_SIZE_MASK(2));
+		}
+		writel(tmp, base + PCIE_MISC_MISC_CTRL);
 	}
-	writel(tmp, base + PCIE_MISC_MISC_CTRL);
 
 	/*
 	 * We ideally want the MSI target address to be located in the 32bit
@@ -1164,8 +1202,10 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie)
 	 * 4GB or when the inbound area is smaller than 4GB (taking into
 	 * account the rounding-up we're forced to perform).
 	 */
-	if (inbound_wins[2].pci_offset >= SZ_4G ||
-	    (inbound_wins[2].size + inbound_wins[2].pci_offset) < SZ_4G)
+	if (IS_CM_SOC(pcie->cfg->soc_base))
+		pcie->msi_target_addr = BRCM_MSI_TARGET_ADDR_FOR_CM;
+	else if (inbound_wins[2].pci_offset >= SZ_4G ||
+		 (inbound_wins[2].size + inbound_wins[2].pci_offset) < SZ_4G)
 		pcie->msi_target_addr = BRCM_MSI_TARGET_ADDR_LT_4GB;
 	else
 		pcie->msi_target_addr = BRCM_MSI_TARGET_ADDR_GT_4GB;
@@ -1226,6 +1266,29 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie)
 		PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1_ENDIAN_MODE_BAR2_MASK);
 	writel(tmp, base + PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1);
 
+	/*
+	 * Relax read ordering for chip architectures using RBUS/SCB that
+	 * use WiFi Runner offload (i.e. BCM3390) to avoid deadlock where
+	 * reads are blocked by writes.
+	 */
+	if (pcie->cfg->soc_base == BCM3390) {
+		tmp = readl(base + PCIE_MISC_MISC_CTRL);
+		u32p_replace_bits(&tmp, 1, PCIE_MISC_MISC_CTRL_PCIE_IN_CPL_RO_MASK);
+		writel(tmp, base + PCIE_MISC_MISC_CTRL);
+	}
+
+	/*
+	 * The 3392 has a bug that requires the NP credit advertised by the
+	 * MAC to be overwritten with 0x10 in bits 31:24 of the following
+	 * register.
+	 */
+	if (pcie->cfg->soc_base == BCM3392) {
+		tmp = readl(base + PCIE_RC_DL_PDL_CONTROL_4);
+		u32p_replace_bits(&tmp, 0x10,
+				  PCIE_RC_DL_PDL_CONTROL_4_NPH_FC_INIT_MASK);
+		writel(tmp, base + PCIE_RC_DL_PDL_CONTROL_4);
+	}
+
 	if (pcie->cfg->post_setup) {
 		ret = pcie->cfg->post_setup(pcie);
 		if (ret < 0)
@@ -1246,8 +1309,8 @@ static void brcm_extend_rbus_timeout(struct brcm_pcie *pcie)
 	const unsigned int REG_OFFSET = PCIE_RGR1_SW_INIT_1(pcie) - 8;
 	u32 timeout_us = 4000000; /* 4 seconds, our setting for L1SS */
 
-	/* 7712 does not have this (RGR1) timer */
-	if (pcie->cfg->soc_base == BCM7712)
+	/* CM and 7712 do not have this (RGR1) timer */
+	if (IS_CM_SOC(pcie->cfg->soc_base) || pcie->cfg->soc_base == BCM7712)
 		return;
 
 	/* Each unit in timeout register is 1/216,000,000 seconds */
@@ -1354,7 +1417,10 @@ static int brcm_pcie_start_link(struct brcm_pcie *pcie)
 
 	brcm_config_clkreq(pcie);
 
-	if (pcie->ssc) {
+	if (IS_CM_SOC(pcie->cfg->soc_base)) {
+		/* This driver does configure SSC for CM chips */
+		ssc_str = "";
+	} else if (pcie->ssc) {
 		ret = brcm_pcie_set_ssc(pcie);
 		if (ret == 0)
 			ssc_str = "(SSC)";
@@ -1715,6 +1781,14 @@ static const int pcie_offsets[] = {
 	[PCIE_INTR2_CPU_BASE]	= 0x4300,
 };
 
+static const int pcie_offset_bcm3162[] = {
+	[RGR1_SW_INIT_1] = 0x9210,
+	[EXT_CFG_INDEX] = 0x9000,
+	[EXT_CFG_DATA] = 0x9004,
+	[PCIE_HARD_DEBUG] = 0x4204,
+	[PCIE_INTR2_CPU_BASE] = 0x4300
+};
+
 static const int pcie_offsets_bcm7278[] = {
 	[RGR1_SW_INIT_1]	= 0xc010,
 	[EXT_CFG_INDEX]		= 0x9000,
@@ -1739,6 +1813,14 @@ static const int pcie_offsets_bcm7712[] = {
 	[PCIE_INTR2_CPU_BASE]	= 0x4400,
 };
 
+static const int pcie_offset_bcm33940[] = {
+	[RGR1_SW_INIT_1] = 0x9210,
+	[EXT_CFG_INDEX] = 0x9000,
+	[EXT_CFG_DATA] = 0x9004,
+	[PCIE_HARD_DEBUG] = 0x4304,
+	[PCIE_INTR2_CPU_BASE] = 0x4400
+};
+
 static const struct pcie_cfg_data generic_cfg = {
 	.offsets	= pcie_offsets,
 	.soc_base	= GENERIC,
@@ -1765,6 +1847,30 @@ static const struct pcie_cfg_data bcm2712_cfg = {
 	.num_inbound_wins = 10,
 };
 
+static const struct pcie_cfg_data bcm3162_cfg = {
+	.offsets	= pcie_offset_bcm3162,
+	.soc_base	= BCM3162,
+	.perst_set	= brcm_pcie_perst_set_7278,
+	.bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_generic,
+	.num_inbound_wins = 3,
+};
+
+static const struct pcie_cfg_data bcm3392_cfg = {
+	.offsets	= pcie_offset_bcm33940,
+	.soc_base	= BCM3392,
+	.perst_set	= brcm_pcie_perst_set_7278,
+	.bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_generic,
+	.num_inbound_wins = 10,
+};
+
+static const struct pcie_cfg_data bcm3390_cfg = {
+	.offsets	= pcie_offsets,
+	.soc_base	= BCM3390,
+	.perst_set	= brcm_pcie_perst_set_generic,
+	.bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_generic,
+	.num_inbound_wins = 3,
+};
+
 static const struct pcie_cfg_data bcm4908_cfg = {
 	.offsets	= pcie_offsets,
 	.soc_base	= BCM4908,
@@ -1814,9 +1920,20 @@ static const struct pcie_cfg_data bcm7712_cfg = {
 	.num_inbound_wins = 10,
 };
 
+static const struct pcie_cfg_data bcm33940_cfg = {
+	.offsets	= pcie_offset_bcm33940,
+	.soc_base	= BCM33940,
+	.perst_set	= brcm_pcie_perst_set_7278,
+	.bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_generic,
+	.num_inbound_wins = 10,
+};
+
 static const struct of_device_id brcm_pcie_match[] = {
 	{ .compatible = "brcm,bcm2711-pcie", .data = &bcm2711_cfg },
 	{ .compatible = "brcm,bcm2712-pcie", .data = &bcm2712_cfg },
+	{ .compatible = "brcm,bcm3162-pcie", .data = &bcm3162_cfg },
+	{ .compatible = "brcm,bcm3390-pcie", .data = &bcm3390_cfg },
+	{ .compatible = "brcm,bcm3392-pcie", .data = &bcm3392_cfg },
 	{ .compatible = "brcm,bcm4908-pcie", .data = &bcm4908_cfg },
 	{ .compatible = "brcm,bcm7211-pcie", .data = &generic_cfg },
 	{ .compatible = "brcm,bcm7216-pcie", .data = &bcm7216_cfg },
@@ -1825,6 +1942,7 @@ static const struct of_device_id brcm_pcie_match[] = {
 	{ .compatible = "brcm,bcm7435-pcie", .data = &bcm7435_cfg },
 	{ .compatible = "brcm,bcm7445-pcie", .data = &generic_cfg },
 	{ .compatible = "brcm,bcm7712-pcie", .data = &bcm7712_cfg },
+	{ .compatible = "brcm,bcm33940-pcie", .data = &bcm33940_cfg },
 	{},
 };
 
-- 
2.43.0


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ