diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c
index 663eb4247029..4b969f29ba55 100644
--- a/drivers/net/can/m_can/m_can.c
+++ b/drivers/net/can/m_can/m_can.c
@@ -1208,6 +1208,7 @@ static void m_can_coalescing_update(struct m_can_classdev *cdev, u32 ir)
 static int m_can_interrupt_handler(struct m_can_classdev *cdev)
 {
 	struct net_device *dev = cdev->net;
+	u32 all_interrupts = 0;
 	u32 ir;
 	int ret;
 
@@ -1215,56 +1216,75 @@ static int m_can_interrupt_handler(struct m_can_classdev *cdev)
 		return IRQ_NONE;
 
 	ir = m_can_read(cdev, M_CAN_IR);
-	m_can_coalescing_update(cdev, ir);
-	if (!ir)
+	all_interrupts |= ir;
+	if (!ir) {
+		m_can_coalescing_update(cdev, 0);
 		return IRQ_NONE;
-
-	/* ACK all irqs */
-	m_can_write(cdev, M_CAN_IR, ir);
-
-	if (cdev->ops->clear_interrupts)
-		cdev->ops->clear_interrupts(cdev);
-
-	/* schedule NAPI in case of
-	 * - rx IRQ
-	 * - state change IRQ
-	 * - bus error IRQ and bus error reporting
-	 */
-	if (ir & (IR_RF0N | IR_RF0W | IR_ERR_ALL_30X)) {
-		cdev->irqstatus = ir;
-		if (!cdev->is_peripheral) {
-			m_can_disable_all_interrupts(cdev);
-			napi_schedule(&cdev->napi);
-		} else {
-			ret = m_can_rx_handler(dev, NAPI_POLL_WEIGHT, ir);
-			if (ret < 0)
-				return ret;
-		}
 	}
 
-	if (cdev->version == 30) {
-		if (ir & IR_TC) {
-			/* Transmission Complete Interrupt*/
-			u32 timestamp = 0;
-			unsigned int frame_len;
+	do {
+		/* ACK all irqs */
+		m_can_write(cdev, M_CAN_IR, ir);
 
-			if (cdev->is_peripheral)
-				timestamp = m_can_get_timestamp(cdev);
-			frame_len = m_can_tx_update_stats(cdev, 0, timestamp);
-			m_can_finish_tx(cdev, 1, frame_len);
+		if (cdev->ops->clear_interrupts)
+			cdev->ops->clear_interrupts(cdev);
+
+		/* schedule NAPI in case of
+		 * - rx IRQ
+		 * - state change IRQ
+		 * - bus error IRQ and bus error reporting
+		 */
+		if (ir & (IR_RF0N | IR_RF0W | IR_ERR_ALL_30X)) {
+			cdev->irqstatus = ir;
+			if (!cdev->is_peripheral) {
+				m_can_disable_all_interrupts(cdev);
+				napi_schedule(&cdev->napi);
+			} else {
+				ret = m_can_rx_handler(dev, NAPI_POLL_WEIGHT, ir);
+				if (ret < 0)
+					return ret;
+			}
 		}
-	} else  {
-		if (ir & (IR_TEFN | IR_TEFW)) {
-			/* New TX FIFO Element arrived */
-			ret = m_can_echo_tx_event(dev);
-			if (ret != 0)
-				return ret;
+
+		if (cdev->version == 30) {
+			if (ir & IR_TC) {
+				/* Transmission Complete Interrupt*/
+				u32 timestamp = 0;
+				unsigned int frame_len;
+
+				if (cdev->is_peripheral)
+					timestamp = m_can_get_timestamp(cdev);
+				frame_len = m_can_tx_update_stats(cdev, 0, timestamp);
+				m_can_finish_tx(cdev, 1, frame_len);
+			}
+		} else  {
+			if (ir & (IR_TEFN | IR_TEFW)) {
+				/* New TX FIFO Element arrived */
+				ret = m_can_echo_tx_event(dev);
+				if (ret != 0)
+					return ret;
+			}
 		}
-	}
+		if (!cdev->irq_type_edge)
+			break;
+
+
+		/* For edge interrupts we need to read the IR register again to
+		 * check that everything is cleared. If it is not, we can not
+		 * make sure the interrupt line is inactive again which is
+		 * required at this point to not miss any new interrupts. So in
+		 * case there are interrupts signaled in IR we repeat the
+		 * interrupt handling.
+		 */
+		ir = m_can_read(cdev, M_CAN_IR);
+		all_interrupts |= ir;
+	} while (ir);
 
 	if (cdev->is_peripheral)
 		can_rx_offload_threaded_irq_finish(&cdev->offload);
 
+	m_can_coalescing_update(cdev, all_interrupts);
+
 	return IRQ_HANDLED;
 }
 
@@ -2009,6 +2029,11 @@ static enum hrtimer_restart hrtimer_callback(struct hrtimer *timer)
 	return HRTIMER_RESTART;
 }
 
+static irqreturn_t m_can_hardirq(int irq, void *dev_id)
+{
+	return IRQ_WAKE_THREAD;
+}
+
 static int m_can_open(struct net_device *dev)
 {
 	struct m_can_classdev *cdev = netdev_priv(dev);
@@ -2034,6 +2059,9 @@ static int m_can_open(struct net_device *dev)
 
 	/* register interrupt handler */
 	if (cdev->is_peripheral) {
+		cdev->irq_type_edge = !(irq_get_trigger_type(dev->irq) &
+					IRQ_TYPE_LEVEL_MASK);
+
 		cdev->tx_wq = alloc_ordered_workqueue("mcan_wq",
 						      WQ_FREEZABLE | WQ_MEM_RECLAIM);
 		if (!cdev->tx_wq) {
@@ -2046,9 +2074,11 @@ static int m_can_open(struct net_device *dev)
 			INIT_WORK(&cdev->tx_ops[i].work, m_can_tx_work_queue);
 		}
 
-		err = request_threaded_irq(dev->irq, NULL, m_can_isr,
-					   IRQF_ONESHOT,
+		err = request_threaded_irq(dev->irq, m_can_hardirq, m_can_isr,
+					   (cdev->irq_type_edge ? 0 : IRQF_ONESHOT),
 					   dev->name, dev);
+		if (cdev->irq_type_edge)
+			netdev_info(dev, "Operating a level interrupt chip with an edge interrupt.\n");
 	} else if (dev->irq) {
 		err = request_irq(dev->irq, m_can_isr, IRQF_SHARED, dev->name,
 				  dev);
diff --git a/drivers/net/can/m_can/m_can.h b/drivers/net/can/m_can/m_can.h
index 3a9edc292593..17de56056352 100644
--- a/drivers/net/can/m_can/m_can.h
+++ b/drivers/net/can/m_can/m_can.h
@@ -99,6 +99,7 @@ struct m_can_classdev {
 	int pm_clock_support;
 	int pm_wake_source;
 	int is_peripheral;
+	bool irq_type_edge;
 
 	// Cached M_CAN_IE register content
 	u32 active_interrupts;
