[PATCH 04/15] can: m_can: Use transmit event FIFO watermark level interrupt

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Currently the only mode of operation is an interrupt for every transmit
event. This is inefficient for peripheral chips. Use the transmit FIFO
event watermark interrupt instead if the FIFO size is more than 2. Use
FIFOsize - 1 for the watermark so the interrupt is triggered early
enough to not stop transmitting.

Note that if the number of transmits is less than the watermark level,
the transmit events will not be processed until there is any other
interrupt. This will only affect statistic counters. Also there is an
interrupt every time the timestamp wraps around.

Signed-off-by: Markus Schneider-Pargmann <msp@xxxxxxxxxxxx>
---
 drivers/net/can/m_can/m_can.c | 27 ++++++++++++++++++---------
 1 file changed, 18 insertions(+), 9 deletions(-)

diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c
index f5bba848bd56..4a6972c8bacd 100644
--- a/drivers/net/can/m_can/m_can.c
+++ b/drivers/net/can/m_can/m_can.c
@@ -254,6 +254,7 @@ enum m_can_reg {
 #define TXESC_TBDS_64B		0x7
 
 /* Tx Event FIFO Configuration (TXEFC) */
+#define TXEFC_EFWM_MASK		GENMASK(29, 24)
 #define TXEFC_EFS_MASK		GENMASK(21, 16)
 
 /* Tx Event FIFO Status (TXEFS) */
@@ -1094,8 +1095,8 @@ static irqreturn_t m_can_isr(int irq, void *dev_id)
 			netif_wake_queue(dev);
 		}
 	} else  {
-		if (ir & IR_TEFN) {
-			/* New TX FIFO Element arrived */
+		if (ir & (IR_TEFN | IR_TEFW)) {
+			/* New TX FIFO Element arrived or watermark reached */
 			if (m_can_echo_tx_event(dev) != 0)
 				goto out_fail;
 			if (!cdev->tx_skb && netif_queue_stopped(dev))
@@ -1242,6 +1243,7 @@ static void m_can_chip_config(struct net_device *dev)
 {
 	struct m_can_classdev *cdev = netdev_priv(dev);
 	u32 cccr, test;
+	u32 interrupts = IR_ALL_INT;
 
 	m_can_config_endisable(cdev, true);
 
@@ -1276,11 +1278,20 @@ static void m_can_chip_config(struct net_device *dev)
 			    FIELD_PREP(TXEFC_EFS_MASK, 1) |
 			    cdev->mcfg[MRAM_TXE].off);
 	} else {
+		u32 txe_watermark;
+
+		txe_watermark = cdev->mcfg[MRAM_TXE].num - 1;
 		/* Full TX Event FIFO is used */
 		m_can_write(cdev, M_CAN_TXEFC,
+			    FIELD_PREP(TXEFC_EFWM_MASK,
+				       txe_watermark) |
 			    FIELD_PREP(TXEFC_EFS_MASK,
 				       cdev->mcfg[MRAM_TXE].num) |
 			    cdev->mcfg[MRAM_TXE].off);
+
+		/* Watermark interrupt mode */
+		if (txe_watermark)
+			interrupts &= ~IR_TEFN;
 	}
 
 	/* rx fifo configuration, blocking mode, fifo size 1 */
@@ -1338,15 +1349,13 @@ static void m_can_chip_config(struct net_device *dev)
 
 	/* Enable interrupts */
 	m_can_write(cdev, M_CAN_IR, IR_ALL_INT);
-	if (!(cdev->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING))
+	if (!(cdev->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)) {
 		if (cdev->version == 30)
-			m_can_write(cdev, M_CAN_IE, IR_ALL_INT &
-				    ~(IR_ERR_LEC_30X));
+			interrupts &= ~(IR_ERR_LEC_30X);
 		else
-			m_can_write(cdev, M_CAN_IE, IR_ALL_INT &
-				    ~(IR_ERR_LEC_31X));
-	else
-		m_can_write(cdev, M_CAN_IE, IR_ALL_INT);
+			interrupts &= ~(IR_ERR_LEC_31X);
+	}
+	m_can_write(cdev, M_CAN_IE, interrupts);
 
 	/* route all interrupts to INT0 */
 	m_can_write(cdev, M_CAN_ILS, ILS_ALL_INT0);
-- 
2.38.1




[Index of Archives]     [Automotive Discussions]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [eCos]     [Asterisk Internet PBX]     [Linux API]     [CAN Bus]

  Powered by Linux