Browse Source

cnss2: Add one MSI vector support

Some platforms can't meet the number of MSI interrupt vectors that
wlan driver requires.
Add one MSI interrupt vector support.
If CONFIG_ONE_MSI_VECTOR is not defined, wlan driver fails to load
if reuired MSI vector allocation fails. It is current behavior.
If CONFIG_ONE_MSI_VECTOR is defined, firstly it will allocate multiple
MSI vectors based on MSI config. If MSI vector allocation fails, it
fallbacks to one MSI vector automatically.

Change-Id: I813f7ddf678ecf405e573f3bc72af3e758d1c96d
CRs-Fixed: 3312670
Bing Sun 2 years ago
parent
commit
fe37b559b9
5 changed files with 118 additions and 4 deletions
  1. 4 0
      Kbuild
  2. 28 4
      cnss2/pci.c
  3. 4 0
      cnss2/pci_platform.h
  4. 81 0
      cnss2/pci_qcom.c
  5. 1 0
      inc/cnss2.h

+ 4 - 0
Kbuild

@@ -10,6 +10,10 @@ ifeq ($(CONFIG_CNSS2_QMI),y)
 KBUILD_CPPFLAGS += -DCONFIG_CNSS2_QMI
 endif
 
+ifeq ($(CONFIG_ONE_MSI_VECTOR),y)
+KBUILD_CPPFLAGS += -DCONFIG_ONE_MSI_VECTOR
+endif
+
 ifeq ($(CONFIG_ICNSS2_DEBUG),y)
 KBUILD_CPPFLAGS += -DCONFIG_ICNSS2_DEBUG
 endif

+ 28 - 4
cnss2/pci.c

@@ -4446,7 +4446,8 @@ static int cnss_pci_enable_msi(struct cnss_pci_data *pci_priv)
 					    msi_config->total_vectors,
 					    msi_config->total_vectors,
 					    PCI_IRQ_MSI);
-	if (num_vectors != msi_config->total_vectors) {
+	if ((num_vectors != msi_config->total_vectors) &&
+	    !cnss_pci_fallback_one_msi(pci_priv, &num_vectors)) {
 		cnss_pr_err("Failed to get enough MSI vectors (%d), available vectors = %d",
 			    msi_config->total_vectors, num_vectors);
 		if (num_vectors >= 0)
@@ -4535,6 +4536,17 @@ int cnss_get_msi_irq(struct device *dev, unsigned int vector)
 }
 EXPORT_SYMBOL(cnss_get_msi_irq);
 
+bool cnss_is_one_msi(struct device *dev)
+{
+	struct cnss_pci_data *pci_priv = cnss_get_pci_priv(to_pci_dev(dev));
+
+	if (!pci_priv)
+		return false;
+
+	return cnss_pci_is_one_msi(pci_priv);
+}
+EXPORT_SYMBOL(cnss_is_one_msi);
+
 void cnss_get_msi_address(struct device *dev, u32 *msi_addr_low,
 			  u32 *msi_addr_high)
 {
@@ -5521,6 +5533,8 @@ static int cnss_pci_get_mhi_msi(struct cnss_pci_data *pci_priv)
 	int ret, num_vectors, i;
 	u32 user_base_data, base_vector;
 	int *irq;
+	unsigned int msi_data;
+	bool is_one_msi = false;
 
 	ret = cnss_get_user_msi_assignment(&pci_priv->pci_dev->dev,
 					   MHI_MSI_NAME, &num_vectors,
@@ -5528,6 +5542,10 @@ static int cnss_pci_get_mhi_msi(struct cnss_pci_data *pci_priv)
 	if (ret)
 		return ret;
 
+	if (cnss_pci_is_one_msi(pci_priv)) {
+		is_one_msi = true;
+		num_vectors = cnss_pci_get_one_msi_mhi_irq_array_size(pci_priv);
+	}
 	cnss_pr_dbg("Number of assigned MSI for MHI is %d, base vector is %d\n",
 		    num_vectors, base_vector);
 
@@ -5535,9 +5553,12 @@ static int cnss_pci_get_mhi_msi(struct cnss_pci_data *pci_priv)
 	if (!irq)
 		return -ENOMEM;
 
-	for (i = 0; i < num_vectors; i++)
-		irq[i] = cnss_get_msi_irq(&pci_priv->pci_dev->dev,
-					  base_vector + i);
+	for (i = 0; i < num_vectors; i++) {
+		msi_data = base_vector;
+		if (!is_one_msi)
+			msi_data += i;
+		irq[i] = cnss_get_msi_irq(&pci_priv->pci_dev->dev, msi_data);
+	}
 
 	pci_priv->mhi_ctrl->irq = irq;
 	pci_priv->mhi_ctrl->nr_irqs = num_vectors;
@@ -5671,6 +5692,9 @@ static int cnss_pci_register_mhi(struct cnss_pci_data *pci_priv)
 		goto free_mhi_ctrl;
 	}
 
+	if (cnss_pci_is_one_msi(pci_priv))
+		mhi_ctrl->irq_flags = IRQF_SHARED | IRQF_NOBALANCING;
+
 	if (pci_priv->smmu_s1_enable) {
 		mhi_ctrl->iova_start = pci_priv->smmu_iova_start;
 		mhi_ctrl->iova_stop = pci_priv->smmu_iova_start +

+ 4 - 0
cnss2/pci_platform.h

@@ -105,6 +105,10 @@ int cnss_set_pci_link(struct cnss_pci_data *pci_priv, bool link_up);
 int cnss_pci_prevent_l1(struct device *dev);
 void cnss_pci_allow_l1(struct device *dev);
 int cnss_pci_get_msi_assignment(struct cnss_pci_data *pci_priv);
+bool cnss_pci_fallback_one_msi(struct cnss_pci_data *pci_priv,
+			       int *num_vectors);
+bool cnss_pci_is_one_msi(struct cnss_pci_data *pci_priv);
+int cnss_pci_get_one_msi_mhi_irq_array_size(struct cnss_pci_data *pci_priv);
 int cnss_pci_init_smmu(struct cnss_pci_data *pci_priv);
 bool cnss_pci_is_drv_supported(struct cnss_pci_data *pci_priv);
 /**

+ 81 - 0
cnss2/pci_qcom.c

@@ -15,6 +15,25 @@ static struct cnss_msi_config msi_config = {
 	},
 };
 
+#ifdef CONFIG_ONE_MSI_VECTOR
+/**
+ * All the user share the same vector and msi data
+ * For MHI user, we need pass IRQ array information to MHI component
+ * MHI_IRQ_NUMBER is defined to specify this MHI IRQ array size
+ */
+#define MHI_IRQ_NUMBER 3
+static struct cnss_msi_config msi_config_one_msi = {
+	.total_vectors = 1,
+	.total_users = 4,
+	.users = (struct cnss_msi_user[]) {
+		{ .name = "MHI", .num_vectors = 1, .base_vector = 0 },
+		{ .name = "CE", .num_vectors = 1, .base_vector = 0 },
+		{ .name = "WAKE", .num_vectors = 1, .base_vector = 0 },
+		{ .name = "DP", .num_vectors = 1, .base_vector = 0 },
+	},
+};
+#endif
+
 int _cnss_pci_enumerate(struct cnss_plat_data *plat_priv, u32 rc_num)
 {
 	return msm_pcie_enumerate(rc_num);
@@ -436,6 +455,68 @@ int cnss_pci_get_msi_assignment(struct cnss_pci_data *pci_priv)
 	return 0;
 }
 
+#ifdef CONFIG_ONE_MSI_VECTOR
+static int cnss_pci_get_one_msi_assignment(struct cnss_pci_data *pci_priv)
+{
+	pci_priv->msi_config = &msi_config_one_msi;
+
+	return 0;
+}
+
+bool cnss_pci_fallback_one_msi(struct cnss_pci_data *pci_priv,
+			       int *num_vectors)
+{
+	struct pci_dev *pci_dev = pci_priv->pci_dev;
+	struct cnss_msi_config *msi_config;
+
+	cnss_pci_get_one_msi_assignment(pci_priv);
+	msi_config = pci_priv->msi_config;
+	if (!msi_config) {
+		cnss_pr_err("one msi_config is NULL!\n");
+		return false;
+	}
+	*num_vectors = pci_alloc_irq_vectors(pci_dev,
+					     msi_config->total_vectors,
+					     msi_config->total_vectors,
+					     PCI_IRQ_MSI);
+	if (*num_vectors < 0) {
+		cnss_pr_err("Failed to get one MSI vector!\n");
+		return false;
+	}
+	cnss_pr_dbg("request MSI one vector\n");
+
+	return true;
+}
+
+bool cnss_pci_is_one_msi(struct cnss_pci_data *pci_priv)
+{
+	return pci_priv && pci_priv->msi_config &&
+	       (pci_priv->msi_config->total_vectors == 1);
+}
+
+int cnss_pci_get_one_msi_mhi_irq_array_size(struct cnss_pci_data *pci_priv)
+{
+	return MHI_IRQ_NUMBER;
+}
+
+#else
+bool cnss_pci_fallback_one_msi(struct cnss_pci_data *pci_priv,
+			       int *num_vectors)
+{
+	return false;
+}
+
+bool cnss_pci_is_one_msi(struct cnss_pci_data *pci_priv)
+{
+	return false;
+}
+
+int cnss_pci_get_one_msi_mhi_irq_array_size(struct cnss_pci_data *pci_priv)
+{
+	return 0;
+}
+#endif
+
 static int cnss_pci_smmu_fault_handler(struct iommu_domain *domain,
 				       struct device *dev, unsigned long iova,
 				       int flags, void *handler_token)

+ 1 - 0
inc/cnss2.h

@@ -270,6 +270,7 @@ extern int cnss_get_user_msi_assignment(struct device *dev, char *user_name,
 					uint32_t *user_base_data,
 					uint32_t *base_vector);
 extern int cnss_get_msi_irq(struct device *dev, unsigned int vector);
+extern bool cnss_is_one_msi(struct device *dev);
 extern void cnss_get_msi_address(struct device *dev, uint32_t *msi_addr_low,
 				 uint32_t *msi_addr_high);
 extern int cnss_wlan_hw_enable(void);