From f6978ee69cd95c5e794d027f4fd5277f2aa26ed2 Mon Sep 17 00:00:00 2001 From: Manoj Chourasia Date: Tue, 30 Aug 2016 11:29:42 +0530 Subject: mttcan:wake netif queue if stopped Check for Tx buffer space availabed before queuing new tx requests. ACK TX Interrupt independendly to prevent unintentional reset of other interrupt. Also check DLEC in PSR in case of interrupt of protocol error in data phase. Bug 200232485 Bug 1785239 Bug 200164764 Change-Id: Ibf972dbbda0da93e23e756479f7d76b0865e1f2f Signed-off-by: Manoj Chourasia Reviewed-on: http://git-master/r/1209559 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit Reviewed-by: Rajesh Hosakote Tested-by: Rajesh Hosakote Reviewed-by: Sandeep Trasi --- drivers/staging/mttcan/hw/m_ttcan.c | 22 ++++-- drivers/staging/mttcan/hw/m_ttcan.h | 2 + drivers/staging/mttcan/hw/m_ttcan_linux.h | 3 +- drivers/staging/mttcan/m_ttcan_linux.c | 108 +++++++++++++++++------------- 4 files changed, 81 insertions(+), 54 deletions(-) diff --git a/drivers/staging/mttcan/hw/m_ttcan.c b/drivers/staging/mttcan/hw/m_ttcan.c index 51c3af25b..227d1646f 100644 --- a/drivers/staging/mttcan/hw/m_ttcan.c +++ b/drivers/staging/mttcan/hw/m_ttcan.c @@ -403,6 +403,19 @@ int ttcan_tx_buff_req_pending(struct ttcan_controller *ttcan, u8 index) return 0; } +int ttcan_tx_buffers_full(struct ttcan_controller *ttcan) +{ + u32 txbrp_reg; + u32 mask = (1 << ttcan->mram_cfg[MRAM_TXB].num) - 1; + + txbrp_reg = ttcan_read32(ttcan, ADR_MTTCAN_TXBRP); + + if ((txbrp_reg & mask) == mask) + return 1; + else + return 0; +} + void ttcan_tx_ded_msg_write(struct ttcan_controller *ttcan, struct ttcanfd_frame *ttcanfd, u8 index, bool tt_en) @@ -486,7 +499,7 @@ int ttcan_set_tx_buffer_addr(struct ttcan_controller *ttcan) /* Queue Message in Tx Queue * Return - * -1 in case of error + * -ve in case of error * idx written buffer index */ int ttcan_tx_fifo_queue_msg(struct ttcan_controller *ttcan, @@ -500,10 +513,9 @@ int ttcan_tx_fifo_queue_msg(struct ttcan_controller *ttcan, if ((txfqs_reg & MTT_TXFQS_TFQF_MASK) == 0) { ttcan_tx_ded_msg_write(ttcan, ttcanfd, put_idx, 0); return put_idx; - } else { - pr_err("%s: Tx queue/FIFO full\n", __func__); - return -ENOMEM; } + + return -ENOMEM; } /* Check tx fifo status @@ -615,7 +627,6 @@ unsigned int ttcan_read_rx_fifo0(struct ttcan_controller *ttcan) rxf0s_reg = ttcan_read32(ttcan, ADR_MTTCAN_RXF0S); if (!(rxf0s_reg & MTT_RXF0S_F0FL_MASK)) { - pr_info("%s: Rx fifo0 empty\n", __func__); return msgs_read; } @@ -663,7 +674,6 @@ unsigned int ttcan_read_rx_fifo1(struct ttcan_controller *ttcan) rxf1s_reg = ttcan_read32(ttcan, ADR_MTTCAN_RXF1S); if (!(rxf1s_reg & MTT_RXF1S_F1FL_MASK)) { - pr_info("%s: Rx fifo1 empty\n", __func__); return msgs_read; } diff --git a/drivers/staging/mttcan/hw/m_ttcan.h b/drivers/staging/mttcan/hw/m_ttcan.h index e1c2ed46d..e8f309675 100644 --- a/drivers/staging/mttcan/hw/m_ttcan.h +++ b/drivers/staging/mttcan/hw/m_ttcan.h @@ -423,6 +423,8 @@ void ttcan_set_rx_buffers_elements(struct ttcan_controller *ttcan); int ttcan_set_tx_buffer_addr(struct ttcan_controller *ttcan); int ttcan_tx_fifo_full(struct ttcan_controller *ttcan); +int ttcan_tx_buffers_full(struct ttcan_controller *ttcan); + int ttcan_tx_fifo_queue_msg(struct ttcan_controller *ttcan, struct ttcanfd_frame *ttcanfd); int ttcan_tx_fifo_get_free_element(struct ttcan_controller *ttcan); diff --git a/drivers/staging/mttcan/hw/m_ttcan_linux.h b/drivers/staging/mttcan/hw/m_ttcan_linux.h index 607c88738..5a5c0ef23 100644 --- a/drivers/staging/mttcan/hw/m_ttcan_linux.h +++ b/drivers/staging/mttcan/hw/m_ttcan_linux.h @@ -46,9 +46,8 @@ #define MTTCAN_RX_FIFO_INTR (0xFF) #define MTTCAN_RX_HP_INTR (0x1 << 8) #define MTTCAN_TX_EV_FIFO_INTR (0xF << 12) -#define MTTCAN_DRX_INTR (0x1 << 19) -#define MTTCAN_ERR_INTR (0x3FF7 << 16) +#define MTTCAN_ERR_INTR (0x1FF9 << 17) #define MTTCAN_BUS_OFF (1 << 25) #define MTTCAN_ERR_WARN (1 << 24) #define MTTCAN_ERR_PASS (1 << 23) diff --git a/drivers/staging/mttcan/m_ttcan_linux.c b/drivers/staging/mttcan/m_ttcan_linux.c index a32624370..43f54c419 100644 --- a/drivers/staging/mttcan/m_ttcan_linux.c +++ b/drivers/staging/mttcan/m_ttcan_linux.c @@ -104,9 +104,6 @@ static __init int mttcan_hw_init(struct mttcan_priv *priv) ttcan_prog_trigger_mem(ttcan, priv->tmc_shadow); } - ttcan_clear_intr(ttcan); - ttcan_clear_tt_intr(ttcan); - ttcan_print_version(ttcan); return err; @@ -161,8 +158,6 @@ static __init int mttcan_hw_reinit(const struct mttcan_priv *priv) if (ttcan->mram_cfg[MRAM_TMC].num) ttcan_prog_trigger_mem(ttcan, priv->tmc_shadow); - ttcan_clear_intr(ttcan); - ttcan_clear_tt_intr(ttcan); return err; } @@ -538,13 +533,12 @@ static void mttcan_tx_event(struct net_device *dev) static void mttcan_tx_complete(struct net_device *dev) { - u32 completed_tx; u32 msg_no; struct mttcan_priv *priv = netdev_priv(dev); struct net_device_stats *stats = &dev->stats; - completed_tx = ttcan_read_tx_complete_reg(priv->ttcan); + u32 completed_tx = ttcan_read_tx_complete_reg(priv->ttcan); /*TODO:- fix how to handle wrap around of tx_next and echo */ for (; (priv->tx_next - priv->tx_echo) > 0; priv->tx_echo++) { @@ -568,9 +562,6 @@ static void mttcan_tx_complete(struct net_device *dev) } if (netif_queue_stopped(dev)) - netif_start_queue(dev); - - if ((priv->tx_next - priv->tx_echo) > 0) netif_wake_queue(dev); } @@ -626,6 +617,8 @@ static int mttcan_poll_ir(struct napi_struct *napi, int quota) if (ir & MTTCAN_ERR_INTR) { psr = ttcan_read_psr(priv->ttcan); priv->ttcan->proto_state = psr; + ack = ir & MTTCAN_ERR_INTR; + ttcan_ir_write(priv->ttcan, ack); if ((ir & MTT_IR_EW_MASK) && (psr & MTT_PSR_EW_MASK)) { work_done += mttcan_state_change(dev, CAN_STATE_ERROR_WARNING); @@ -660,9 +653,14 @@ static int mttcan_poll_ir(struct napi_struct *napi, int quota) if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) { if ((ir & MTT_IR_PED_MASK) || (ir & MTT_IR_PEA_MASK)) { - enum ttcan_lec_type lec = - (psr & MTT_PSR_LEC_MASK) - >> MTT_PSR_LEC_SHIFT; + enum ttcan_lec_type lec; + + if (ir & MTT_IR_PEA_MASK) + lec = (psr & MTT_PSR_LEC_MASK) + >> MTT_PSR_LEC_SHIFT; + else + lec = (psr & MTT_PSR_DLEC_MASK) + >> MTT_PSR_DLEC_SHIFT; work_done += mttcan_handle_bus_err(dev, lec); netdev_err(dev, "IR = 0x%x PSR 0x%x\n", @@ -672,8 +670,12 @@ static int mttcan_poll_ir(struct napi_struct *napi, int quota) if (ir & MTT_IR_WDI_MASK) netdev_warn(dev, "Message RAM watchdog not handled\n"); - ack = MTTCAN_ERR_INTR; + } + + if (ir & MTT_IR_TOO_MASK) { + ack = MTT_IR_TOO_MASK; ttcan_ir_write(priv->ttcan, ack); + netdev_warn(dev, "Rx timeout not handled\n"); } /* High Priority Message */ @@ -698,25 +700,27 @@ static int mttcan_poll_ir(struct napi_struct *napi, int quota) pr_debug("%s: buffer mesg received\n", __func__); } + /* Handle RX Fifo interrupt */ if (ir & MTTCAN_RX_FIFO_INTR) { if (ir & MTT_IR_RF1L_MASK) { - mttcan_handle_lost_frame(dev, 1); - work_done++; ack = MTT_IR_RF1L_MASK; ttcan_ir_write(priv->ttcan, ack); + mttcan_handle_lost_frame(dev, 1); + work_done++; } if (ir & MTT_IR_RF0L_MASK) { - mttcan_handle_lost_frame(dev, 0); - work_done++; ack = MTT_IR_RF0L_MASK; ttcan_ir_write(priv->ttcan, ack); + mttcan_handle_lost_frame(dev, 0); + work_done++; } if (ir & (MTT_IR_RF1F_MASK | MTT_IR_RF1W_MASK | MTT_IR_RF1N_MASK)) { - ack = MTT_IR_RF1F_MASK | MTT_IR_RF1W_MASK | - MTT_IR_RF1N_MASK; + ack = ir & (MTT_IR_RF1F_MASK | + MTT_IR_RF1W_MASK | + MTT_IR_RF1N_MASK); ttcan_ir_write(priv->ttcan, ack); rec_msgs = ttcan_read_rx_fifo1(priv->ttcan); @@ -729,8 +733,9 @@ static int mttcan_poll_ir(struct napi_struct *napi, int quota) } if (ir & (MTT_IR_RF0F_MASK | MTT_IR_RF0W_MASK | MTT_IR_RF0N_MASK)) { - ack = MTT_IR_RF0F_MASK | MTT_IR_RF0W_MASK | - MTT_IR_RF0N_MASK; + ack = ir & (MTT_IR_RF0F_MASK | + MTT_IR_RF0W_MASK | + MTT_IR_RF0N_MASK); ttcan_ir_write(priv->ttcan, ack); rec_msgs = ttcan_read_rx_fifo0(priv->ttcan); work_done += @@ -742,14 +747,14 @@ static int mttcan_poll_ir(struct napi_struct *napi, int quota) } if (ir & MTT_IR_RF0L_MASK) { - netdev_err(dev, "%s: some msgs lost on in Q0\n", + netdev_warn(dev, "%s: some msgs lost on in Q0\n", __func__); ack = MTT_IR_RF0L_MASK; ttcan_ir_write(priv->ttcan, ack); } if (ir & MTT_IR_RF1L_MASK) { - netdev_err(dev, "%s: some msgs lost on in Q1\n", + netdev_warn(dev, "%s: some msgs lost on in Q1\n", __func__); ack = MTT_IR_RF1L_MASK; ttcan_ir_write(priv->ttcan, ack); @@ -765,20 +770,28 @@ static int mttcan_poll_ir(struct napi_struct *napi, int quota) ttcan_ir_write(priv->ttcan, ack); } + /* Handle TX complete */ if (ir & MTTCAN_TX_INTR) { /* Transmission cancellation finished */ - if (ir & MTT_IR_TCF_MASK) + if (ir & MTT_IR_TCF_MASK) { mttcan_tx_cancelled(dev); - - if (ir & MTT_IR_TC_MASK) + ack = MTT_IR_TCF_MASK; + ttcan_ir_write(priv->ttcan, ack); + } + if (ir & MTT_IR_TC_MASK) { mttcan_tx_complete(dev); + ack = MTT_IR_TC_MASK; + ttcan_ir_write(priv->ttcan, ack); + } - /* if (ir & MTT_IR_TFE_MASK) - netdev_warn(dev, "Tx Fifo Empty\n"); */ - - ack = MTTCAN_TX_INTR; - ttcan_ir_write(priv->ttcan, ack); + if (ir & MTT_IR_TFE_MASK) { + /* + * netdev_info(dev, "Tx Fifo Empty %x\n", ir); + */ + ack = MTT_IR_TFE_MASK; + ttcan_ir_write(priv->ttcan, ack); + } } /* Handle Tx Event */ if (ir & MTTCAN_TX_EV_FIFO_INTR) { @@ -791,7 +804,7 @@ static int mttcan_poll_ir(struct napi_struct *napi, int quota) if ((ir & MTT_IR_TEFL_MASK) && priv->ttcan->tx_config.evt_q_num) - netdev_err(dev, "Tx event lost\n"); + netdev_warn(dev, "Tx event lost\n"); ack = MTTCAN_TX_EV_FIFO_INTR; ttcan_ir_write(priv->ttcan, ack); @@ -939,27 +952,31 @@ static void mttcan_controller_config(struct net_device *dev) static void mttcan_start(struct net_device *dev) { struct mttcan_priv *priv = netdev_priv(dev); + struct ttcan_controller *ttcan = priv->ttcan; u32 psr; mttcan_controller_config(dev); priv->tx_next = priv->tx_echo = 0; + ttcan_clear_intr(ttcan); + ttcan_clear_tt_intr(ttcan); + ttcan_set_intrpts(priv->ttcan, 1); /* Set current state of CAN controller * * It is assumed the controller is reset durning probing time * It should be in sane state at first start but not guaranteed */ - if (priv->ttcan->proto_state) - psr = priv->ttcan->proto_state; + if (ttcan->proto_state) + psr = ttcan->proto_state; else - psr = ttcan_read_psr(priv->ttcan); + psr = ttcan_read_psr(ttcan); if (psr & MTT_PSR_BO_MASK) { /* Bus off */ priv->can.state = CAN_STATE_BUS_OFF; - ttcan_set_intrpts(priv->ttcan, 0); + ttcan_set_intrpts(ttcan, 0); can_bus_off(dev); } else if (psr & MTT_PSR_EP_MASK) { /* Error Passive */ @@ -974,7 +991,7 @@ static void mttcan_start(struct net_device *dev) /* start Tx/Rx and enable protected mode */ if (!priv->tt_param[0]) - ttcan_reset_init(priv->ttcan); + ttcan_reset_init(ttcan); if (priv->poll) schedule_delayed_work(&priv->can_work, @@ -1183,6 +1200,11 @@ static netdev_tx_t mttcan_start_xmit(struct sk_buff *skb, if (can_is_canfd_skb(skb)) frame->flags |= CAN_FD_FLAG; + if (ttcan_tx_buffers_full(priv->ttcan)) { + netif_stop_queue(dev); + smp_mb(); + return NETDEV_TX_BUSY; + } /* try on buffers first */ msg_no = ttcan_tx_msg_buffer_write(priv->ttcan, (struct ttcanfd_frame *)frame, @@ -1193,10 +1215,10 @@ static netdev_tx_t mttcan_start_xmit(struct sk_buff *skb, (struct ttcanfd_frame *)frame); if (msg_no < 0) { - netdev_err(dev, "Tx message queue full\n"); + netdev_warn(dev, "No Tx space left\n"); kfree_skb(skb); dev->stats.tx_dropped++; - goto stopq; + return NETDEV_TX_OK; } can_put_echo_skb(skb, dev, msg_no); @@ -1205,12 +1227,6 @@ static netdev_tx_t mttcan_start_xmit(struct sk_buff *skb, priv->tx_object |= 1 << msg_no; priv->tx_obj_cancelled &= ~(1 << msg_no); -stopq: /*if next tx is not possible stop the queue */ - if (ttcan_tx_fifo_full(priv->ttcan)) { - netdev_err(dev, "Tx message queue full\n"); - netif_stop_queue(dev); - } - return NETDEV_TX_OK; } -- cgit v1.2.2