qcacmn: Add API to support configuring external group interrupts

Added API to support configuring external group interrupts for AHB bus.

Change-Id: If65984183db808e68dea680c585692e1533e4c7a
CRs-Fixed: 2018655
diff --git a/hif/inc/hif.h b/hif/inc/hif.h
index 20925f1..edeae7a 100644
--- a/hif/inc/hif.h
+++ b/hif/inc/hif.h
@@ -852,6 +852,8 @@
 		uint32_t numirq, uint32_t irq[], ext_intr_handler handler,
 		void *context);
 
+uint32_t hif_configure_ext_group_interrupts(struct hif_opaque_softc *hif_ctx);
+
 void hif_update_pipe_callback(struct hif_opaque_softc *osc,
 				u_int8_t pipeid,
 				struct hif_msg_callbacks *callbacks);
diff --git a/hif/src/dispatcher/ahb_api.h b/hif/src/dispatcher/ahb_api.h
index 75f1506..1a05196 100644
--- a/hif/src/dispatcher/ahb_api.h
+++ b/hif/src/dispatcher/ahb_api.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -46,5 +46,6 @@
 		struct platform_device *pdev,
 		const struct platform_device_id *id);
 int hif_ahb_configure_irq(struct hif_pci_softc *sc);
+int hif_ahb_configure_grp_irq(struct hif_softc *scn);
 
 #endif
diff --git a/hif/src/dispatcher/dummy.c b/hif/src/dispatcher/dummy.c
index b83bf9a..dbf061e 100644
--- a/hif/src/dispatcher/dummy.c
+++ b/hif/src/dispatcher/dummy.c
@@ -261,6 +261,18 @@
  */
 void hif_dummy_grp_irq_disable(struct hif_softc *hif_sc, uint32_t grp_id)
 {}
+
+/**
+ * hif_dummy_grp_irq_configure - dummy call
+ * hif_ctx: hif context
+ *
+ * Return: none
+ */
+int hif_dummy_grp_irq_configure(struct hif_softc *hif_sc)
+{
+    return 0;
+}
+
 /**
  * hif_dummy_dump_registers - dummy call
  * hif_sc: hif context
diff --git a/hif/src/dispatcher/dummy.h b/hif/src/dispatcher/dummy.h
index 0bafe8a..e3e9773 100644
--- a/hif/src/dispatcher/dummy.h
+++ b/hif/src/dispatcher/dummy.h
@@ -49,6 +49,7 @@
 void hif_dummy_irq_disable(struct hif_softc *hif_sc, int irq_id);
 void hif_dummy_grp_irq_enable(struct hif_softc *hif_sc, uint32_t grp_id);
 void hif_dummy_grp_irq_disable(struct hif_softc *hif_sc, uint32_t grp_id);
+int hif_dummy_grp_irq_configure(struct hif_softc *hif_sc);
 int hif_dummy_dump_registers(struct hif_softc *hif_sc);
 void hif_dummy_dump_target_memory(struct hif_softc *hif_sc, void *ramdump_base,
 				  uint32_t address, uint32_t size);
diff --git a/hif/src/dispatcher/multibus.c b/hif/src/dispatcher/multibus.c
index 4a8f7e7..a922ed5 100644
--- a/hif/src/dispatcher/multibus.c
+++ b/hif/src/dispatcher/multibus.c
@@ -67,6 +67,7 @@
 	bus_ops->hif_grp_irq_disable = &hif_dummy_grp_irq_disable;
 	bus_ops->hif_grp_irq_enable = &hif_dummy_grp_irq_enable;
 	bus_ops->hif_map_ce_to_irq = &hif_dummy_map_ce_to_irq;
+	bus_ops->hif_grp_irq_configure = &hif_dummy_grp_irq_configure;
 }
 
 #define NUM_OPS (sizeof(struct hif_bus_ops) / sizeof(void *))
@@ -322,6 +323,11 @@
 	hif_sc->bus_ops.hif_grp_irq_disable(hif_sc, grp_id);
 }
 
+int hif_grp_irq_configure(struct hif_softc *hif_sc)
+{
+	return hif_sc->bus_ops.hif_grp_irq_configure(hif_sc);
+}
+
 int hif_dump_registers(struct hif_opaque_softc *hif_hdl)
 {
 	struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_hdl);
diff --git a/hif/src/dispatcher/multibus.h b/hif/src/dispatcher/multibus.h
index 7d7768d..eb5d77f 100644
--- a/hif/src/dispatcher/multibus.h
+++ b/hif/src/dispatcher/multibus.h
@@ -66,6 +66,7 @@
 	void (*hif_grp_irq_disable)(struct hif_softc *hif_sc, uint32_t grp_id);
 	void (*hif_irq_enable)(struct hif_softc *hif_sc, int ce_id);
 	void (*hif_grp_irq_enable)(struct hif_softc *hif_sc, uint32_t grp_id);
+	int (*hif_grp_irq_configure)(struct hif_softc *hif_sc);
 	int (*hif_dump_registers)(struct hif_softc *hif_sc);
 	void (*hif_dump_target_memory)(struct hif_softc *hif_sc,
 				       void *ramdump_base,
diff --git a/hif/src/dispatcher/multibus_ahb.c b/hif/src/dispatcher/multibus_ahb.c
index d67c9ec..005e7f5 100644
--- a/hif/src/dispatcher/multibus_ahb.c
+++ b/hif/src/dispatcher/multibus_ahb.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2017 The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -68,6 +68,7 @@
 		&hif_dummy_disable_power_management;
 	bus_ops->hif_grp_irq_disable = &hif_ahb_grp_irq_disable;
 	bus_ops->hif_grp_irq_enable = &hif_ahb_grp_irq_enable;
+	bus_ops->hif_grp_irq_configure = &hif_ahb_configure_grp_irq;
 
 	return QDF_STATUS_SUCCESS;
 }
diff --git a/hif/src/dispatcher/multibus_pci.c b/hif/src/dispatcher/multibus_pci.c
index da4caed..e65763e 100644
--- a/hif/src/dispatcher/multibus_pci.c
+++ b/hif/src/dispatcher/multibus_pci.c
@@ -89,6 +89,7 @@
 		&hif_pci_clear_stats;
 	bus_ops->hif_grp_irq_disable = &hif_dummy_grp_irq_disable;
 	bus_ops->hif_grp_irq_enable = &hif_dummy_grp_irq_enable;
+	bus_ops->hif_grp_irq_configure = &hif_dummy_grp_irq_configure;
 
 	/* default to legacy mapping handler; override as needed */
 	bus_ops->hif_map_ce_to_irq = &hif_pci_legacy_map_ce_to_irq;
diff --git a/hif/src/dispatcher/multibus_sdio.c b/hif/src/dispatcher/multibus_sdio.c
index 1f957c4..6c35963 100644
--- a/hif/src/dispatcher/multibus_sdio.c
+++ b/hif/src/dispatcher/multibus_sdio.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2017 The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -66,6 +66,7 @@
 		&hif_dummy_disable_power_management;
 	bus_ops->hif_grp_irq_disable = &hif_dummy_grp_irq_disable;
 	bus_ops->hif_grp_irq_enable = &hif_dummy_grp_irq_enable;
+	bus_ops->hif_grp_irq_configure = &hif_dummy_grp_irq_configure;
 
 	return QDF_STATUS_SUCCESS;
 }
diff --git a/hif/src/dispatcher/multibus_snoc.c b/hif/src/dispatcher/multibus_snoc.c
index b0f4358..bd9f291 100644
--- a/hif/src/dispatcher/multibus_snoc.c
+++ b/hif/src/dispatcher/multibus_snoc.c
@@ -84,6 +84,7 @@
 	bus_ops->hif_grp_irq_disable = &hif_dummy_grp_irq_disable;
 	bus_ops->hif_grp_irq_enable = &hif_dummy_grp_irq_enable;
 	bus_ops->hif_map_ce_to_irq = &hif_snoc_map_ce_to_irq;
+	bus_ops->hif_grp_irq_configure = &hif_dummy_grp_irq_configure;
 
 	return QDF_STATUS_SUCCESS;
 }
diff --git a/hif/src/dispatcher/multibus_usb.c b/hif/src/dispatcher/multibus_usb.c
index 0f3af60..f4cee6f 100644
--- a/hif/src/dispatcher/multibus_usb.c
+++ b/hif/src/dispatcher/multibus_usb.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2017 The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -64,6 +64,7 @@
 			&hif_dummy_disable_power_management;
 	bus_ops->hif_set_bundle_mode = hif_usb_set_bundle_mode;
 	bus_ops->hif_bus_reset_resume = hif_usb_bus_reset_resume;
+	bus_ops->hif_grp_irq_configure = &hif_dummy_grp_irq_configure;
 
 	return QDF_STATUS_SUCCESS;
 }
diff --git a/hif/src/hif_io32.h b/hif/src/hif_io32.h
index 8c1453f..96a3821 100644
--- a/hif/src/hif_io32.h
+++ b/hif/src/hif_io32.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2017 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -106,5 +106,6 @@
 void hif_irq_disable(struct hif_softc *scn, int irq_id);
 void hif_grp_irq_enable(struct hif_softc *scn, uint32_t grp_id);
 void hif_grp_irq_disable(struct hif_softc *scn, uint32_t grp_id);
+int hif_grp_irq_configure(struct hif_softc *scn);
 
 #endif /* __HIF_IO32_H__ */
diff --git a/hif/src/hif_main.c b/hif/src/hif_main.c
index c8847c3..b938ba2 100644
--- a/hif/src/hif_main.c
+++ b/hif/src/hif_main.c
@@ -1209,8 +1209,8 @@
 	struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn);
 	struct hif_ext_group_entry *hif_ext_group;
 
-	if (scn->hif_init_done) {
-		HIF_ERROR("%s Called after HIF initialization \n", __func__);
+	if (scn->ext_grp_irq_configured) {
+		HIF_ERROR("%s Called after ext grp irq configured\n", __func__);
 		return QDF_STATUS_E_FAILURE;
 	}
 
@@ -1239,6 +1239,28 @@
 }
 
 /**
+ * hif_configure_ext_group_interrupts() - API to configure external group
+ * interrpts
+ * @hif_ctx : HIF Context
+ *
+ * Return: status
+ */
+uint32_t hif_configure_ext_group_interrupts(struct hif_opaque_softc *hif_ctx)
+{
+	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
+
+	if (scn->ext_grp_irq_configured) {
+		HIF_ERROR("%s Called after ext grp irq configured\n", __func__);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	hif_grp_irq_configure(scn);
+	scn->ext_grp_irq_configured = true;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
  * hif_ext_grp_tasklet() - grp tasklet
  * data: context
  *
diff --git a/hif/src/hif_main.h b/hif/src/hif_main.h
index 481440d..b70a46c 100644
--- a/hif/src/hif_main.h
+++ b/hif/src/hif_main.h
@@ -142,6 +142,7 @@
 	qdf_device_t qdf_dev;
 	bool hif_init_done;
 	bool request_irq_done;
+	bool ext_grp_irq_configured;
 	/* Packet statistics */
 	struct hif_ce_stats pkt_stats;
 	enum hif_target_status target_status;
diff --git a/hif/src/snoc/if_ahb.c b/hif/src/snoc/if_ahb.c
index ee1ce6f..00cb7e1 100644
--- a/hif/src/snoc/if_ahb.c
+++ b/hif/src/snoc/if_ahb.c
@@ -250,9 +250,8 @@
 	struct hif_softc *scn = HIF_GET_SOFTC(sc);
 	struct platform_device *pdev = (struct platform_device *)sc->pdev;
 	struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn);
-	struct hif_ext_group_entry *hif_ext_group;
 	int irq = 0;
-	int i, j;
+	int i;
 
 	/* configure per CE interrupts */
 	for (i = 0; i < scn->ce_count; i++) {
@@ -270,6 +269,20 @@
 		hif_ahb_irq_enable(scn, i);
 	}
 
+end:
+	return ret;
+}
+
+int hif_ahb_configure_grp_irq(struct hif_softc *scn)
+{
+	int ret = 0;
+	struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn);
+	struct platform_device *pdev = (struct platform_device *)sc->pdev;
+	struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn);
+	struct hif_ext_group_entry *hif_ext_group;
+	int irq = 0;
+	int i, j;
+
 	/* configure external interrupts */
 	for (i = 0; i < hif_state->hif_num_extgroup; i++) {
 
@@ -304,6 +317,25 @@
 	return ret;
 }
 
+void hif_ahb_deconfigure_grp_irq(struct hif_softc *scn)
+{
+	struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn);
+	struct hif_ext_group_entry *hif_ext_group;
+	int i, j;
+
+	/* configure external interrupts */
+	for (i = 0; i < hif_state->hif_num_extgroup; i++) {
+		hif_ext_group = &hif_state->hif_ext_group[i];
+		if (hif_ext_group->inited == true) {
+			hif_ext_group->inited = false;
+			for (j = 0; j < hif_ext_group->numirq; j++) {
+				free_irq(ic_irqnum[hif_ext_group->irq[i]],
+						hif_ext_group);
+			}
+		}
+	}
+}
+
 irqreturn_t hif_ahb_interrupt_handler(int irq, void *context)
 {
 	struct ce_tasklet_entry *tasklet_entry = context;
@@ -581,6 +613,7 @@
 				free_irq(ic_irqnum[HIF_IC_CE0_IRQ_OFFSET + i],
 						&hif_state->tasklets[i]);
 			}
+			hif_ahb_deconfigure_grp_irq(scn);
 		}
 	}
 	scn->request_irq_done = false;