From: Marc Kleine-Budde <mkl@pengutronix.de>
To: netdev@vger.kernel.org
Cc: davem@davemloft.net, linux-can@vger.kernel.org,
kernel@pengutronix.de, Thomas Gleixner <tglx@linutronix.de>,
Marc Kleine-Budde <mkl@pengutronix.de>
Subject: [PATCH 10/26] can: c_can: Get rid of pointless interrupts
Date: Fri, 25 Apr 2014 00:00:13 +0200 [thread overview]
Message-ID: <1398376829-6771-11-git-send-email-mkl@pengutronix.de> (raw)
In-Reply-To: <1398376829-6771-1-git-send-email-mkl@pengutronix.de>
From: Thomas Gleixner <tglx@linutronix.de>
The driver handles pointlessly TWO interrupts per packet. The reason
is that it enables the status interrupt which fires for each rx and tx
packet and it enables the per message object interrupts as well.
The status interrupt merily acks or in case of D_CAN ignores the TX/RX
state and then the message object interrupt fires.
The message objects interrupts are only useful if all message objects
have hardware filters activated.
But we don't have that and its not simple to implement in that driver
without rewriting it completely.
So we can ditch the message object interrupts and handle the RX/TX
right away from the status interrupt. Instead of TWO we handle ONE.
Note: We must keep the TXIE/RXIE bits in the message buffers because
the status interrupt alone is not reliable enough in corner cases.
If we ever have the need for HW filtering, then this code needs a
complete overhaul and we can think about it then. For now we prefer a
lower interrupt load.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Alexander Stein <alexander.stein@systec-electronic.com>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
drivers/net/can/c_can/c_can.c | 122 ++++++++++++++++--------------------------
drivers/net/can/c_can/c_can.h | 3 +-
2 files changed, 48 insertions(+), 77 deletions(-)
diff --git a/drivers/net/can/c_can/c_can.c b/drivers/net/can/c_can/c_can.c
index b381f7b..09cb687 100644
--- a/drivers/net/can/c_can/c_can.c
+++ b/drivers/net/can/c_can/c_can.c
@@ -593,7 +593,7 @@ static void c_can_configure_msg_objects(struct net_device *dev)
/* setup receive message objects */
for (i = C_CAN_MSG_OBJ_RX_FIRST; i < C_CAN_MSG_OBJ_RX_LAST; i++)
c_can_setup_receive_object(dev, IF_RX, i, 0, 0,
- (IF_MCONT_RXIE | IF_MCONT_UMASK) & ~IF_MCONT_EOB);
+ IF_MCONT_RXIE | IF_MCONT_UMASK);
c_can_setup_receive_object(dev, IF_RX, C_CAN_MSG_OBJ_RX_LAST, 0, 0,
IF_MCONT_EOB | IF_MCONT_RXIE | IF_MCONT_UMASK);
@@ -649,8 +649,9 @@ static int c_can_start(struct net_device *dev)
priv->can.state = CAN_STATE_ERROR_ACTIVE;
- /* reset tx helper pointers */
+ /* reset tx helper pointers and the rx mask */
priv->tx_next = priv->tx_echo = 0;
+ priv->rxmasked = 0;
return 0;
}
@@ -823,9 +824,13 @@ static int c_can_read_objects(struct net_device *dev, struct c_can_priv *priv,
/* read the data from the message object */
c_can_read_msg_object(dev, IF_RX, ctrl);
- if (obj == C_CAN_MSG_RX_LOW_LAST)
+ if (obj < C_CAN_MSG_RX_LOW_LAST)
+ priv->rxmasked |= BIT(obj - 1);
+ else if (obj == C_CAN_MSG_RX_LOW_LAST) {
+ priv->rxmasked = 0;
/* activate all lower message objects */
c_can_activate_all_lower_rx_msg_obj(dev, IF_RX);
+ }
pkts++;
quota--;
@@ -870,7 +875,8 @@ static int c_can_do_rx_poll(struct net_device *dev, int quota)
while (quota > 0) {
if (!pend) {
- pend = priv->read_reg(priv, C_CAN_INTPND1_REG);
+ pend = priv->read_reg(priv, C_CAN_NEWDAT1_REG);
+ pend &= ~priv->rxmasked;
if (!pend)
break;
/*
@@ -1040,10 +1046,6 @@ static int c_can_handle_bus_err(struct net_device *dev,
break;
}
- /* set a `lec` value so that we can check for updates later */
- if (priv->type != BOSCH_D_CAN)
- priv->write_reg(priv, C_CAN_STS_REG, LEC_UNUSED);
-
stats->rx_packets++;
stats->rx_bytes += cf->can_dlc;
netif_receive_skb(skb);
@@ -1052,79 +1054,50 @@ static int c_can_handle_bus_err(struct net_device *dev,
static int c_can_poll(struct napi_struct *napi, int quota)
{
- u16 irqstatus;
- int work_done = 0;
struct net_device *dev = napi->dev;
struct c_can_priv *priv = netdev_priv(dev);
+ u16 curr, last = priv->last_status;
+ int work_done = 0;
- irqstatus = priv->irqstatus;
- if (!irqstatus)
- goto end;
+ priv->last_status = curr = priv->read_reg(priv, C_CAN_STS_REG);
+ /* Ack status on C_CAN. D_CAN is self clearing */
+ if (priv->type != BOSCH_D_CAN)
+ priv->write_reg(priv, C_CAN_STS_REG, LEC_UNUSED);
- /* status events have the highest priority */
- if (irqstatus == STATUS_INTERRUPT) {
- priv->current_status = priv->read_reg(priv,
- C_CAN_STS_REG);
-
- /* handle Tx/Rx events */
- if (priv->current_status & STATUS_TXOK &&
- priv->type != BOSCH_D_CAN)
- priv->write_reg(priv, C_CAN_STS_REG,
- priv->current_status & ~STATUS_TXOK);
-
- if (priv->current_status & STATUS_RXOK &&
- priv->type != BOSCH_D_CAN)
- priv->write_reg(priv, C_CAN_STS_REG,
- priv->current_status & ~STATUS_RXOK);
-
- /* handle state changes */
- if ((priv->current_status & STATUS_EWARN) &&
- (!(priv->last_status & STATUS_EWARN))) {
- netdev_dbg(dev, "entered error warning state\n");
- work_done += c_can_handle_state_change(dev,
- C_CAN_ERROR_WARNING);
- }
- if ((priv->current_status & STATUS_EPASS) &&
- (!(priv->last_status & STATUS_EPASS))) {
- netdev_dbg(dev, "entered error passive state\n");
- work_done += c_can_handle_state_change(dev,
- C_CAN_ERROR_PASSIVE);
- }
- if ((priv->current_status & STATUS_BOFF) &&
- (!(priv->last_status & STATUS_BOFF))) {
- netdev_dbg(dev, "entered bus off state\n");
- work_done += c_can_handle_state_change(dev,
- C_CAN_BUS_OFF);
- goto end;
- }
+ /* handle state changes */
+ if ((curr & STATUS_EWARN) && (!(last & STATUS_EWARN))) {
+ netdev_dbg(dev, "entered error warning state\n");
+ work_done += c_can_handle_state_change(dev, C_CAN_ERROR_WARNING);
+ }
- /* handle bus recovery events */
- if ((!(priv->current_status & STATUS_BOFF)) &&
- (priv->last_status & STATUS_BOFF)) {
- netdev_dbg(dev, "left bus off state\n");
- priv->can.state = CAN_STATE_ERROR_ACTIVE;
- }
- if ((!(priv->current_status & STATUS_EPASS)) &&
- (priv->last_status & STATUS_EPASS)) {
- netdev_dbg(dev, "left error passive state\n");
- priv->can.state = CAN_STATE_ERROR_ACTIVE;
- }
+ if ((curr & STATUS_EPASS) && (!(last & STATUS_EPASS))) {
+ netdev_dbg(dev, "entered error passive state\n");
+ work_done += c_can_handle_state_change(dev, C_CAN_ERROR_PASSIVE);
+ }
- priv->last_status = priv->current_status;
-
- /* handle lec errors on the bus */
- work_done += c_can_handle_bus_err(dev,
- priv->current_status & LEC_MASK);
- } else if ((irqstatus >= C_CAN_MSG_OBJ_RX_FIRST) &&
- (irqstatus <= C_CAN_MSG_OBJ_RX_LAST)) {
- /* handle events corresponding to receive message objects */
- work_done += c_can_do_rx_poll(dev, (quota - work_done));
- } else if ((irqstatus >= C_CAN_MSG_OBJ_TX_FIRST) &&
- (irqstatus <= C_CAN_MSG_OBJ_TX_LAST)) {
- /* handle events corresponding to transmit message objects */
- c_can_do_tx(dev);
+ if ((curr & STATUS_BOFF) && (!(last & STATUS_BOFF))) {
+ netdev_dbg(dev, "entered bus off state\n");
+ work_done += c_can_handle_state_change(dev, C_CAN_BUS_OFF);
+ goto end;
}
+ /* handle bus recovery events */
+ if ((!(curr & STATUS_BOFF)) && (last & STATUS_BOFF)) {
+ netdev_dbg(dev, "left bus off state\n");
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+ }
+ if ((!(curr & STATUS_EPASS)) && (last & STATUS_EPASS)) {
+ netdev_dbg(dev, "left error passive state\n");
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+ }
+
+ /* handle lec errors on the bus */
+ work_done += c_can_handle_bus_err(dev, curr & LEC_MASK);
+
+ /* Handle Tx/Rx events. We do this unconditionally */
+ work_done += c_can_do_rx_poll(dev, (quota - work_done));
+ c_can_do_tx(dev);
+
end:
if (work_done < quota) {
napi_complete(napi);
@@ -1141,8 +1114,7 @@ static irqreturn_t c_can_isr(int irq, void *dev_id)
struct net_device *dev = (struct net_device *)dev_id;
struct c_can_priv *priv = netdev_priv(dev);
- priv->irqstatus = priv->read_reg(priv, C_CAN_INT_REG);
- if (!priv->irqstatus)
+ if (!priv->read_reg(priv, C_CAN_INT_REG))
return IRQ_NONE;
/* disable all interrupts and schedule the NAPI */
diff --git a/drivers/net/can/c_can/c_can.h b/drivers/net/can/c_can/c_can.h
index faa8404..cd91960 100644
--- a/drivers/net/can/c_can/c_can.h
+++ b/drivers/net/can/c_can/c_can.h
@@ -185,7 +185,6 @@ struct c_can_priv {
struct device *device;
spinlock_t xmit_lock;
int tx_object;
- int current_status;
int last_status;
u16 (*read_reg) (struct c_can_priv *priv, enum reg index);
void (*write_reg) (struct c_can_priv *priv, enum reg index, u16 val);
@@ -195,11 +194,11 @@ struct c_can_priv {
unsigned int tx_next;
unsigned int tx_echo;
void *priv; /* for board-specific data */
- u16 irqstatus;
enum c_can_dev_id type;
u32 __iomem *raminit_ctrlreg;
unsigned int instance;
void (*raminit) (const struct c_can_priv *priv, bool enable);
+ u32 rxmasked;
u32 dlc[C_CAN_MSG_OBJ_TX_NUM];
};
--
1.9.0.279.gdc9e3eb
next prev parent reply other threads:[~2014-04-24 22:00 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-04-24 22:00 pull-request: can 2014-04-24 Marc Kleine-Budde
2014-04-24 22:00 ` [PATCH 01/26] can: c_can_pci: Set the type of the IP core Marc Kleine-Budde
2014-04-24 22:00 ` [PATCH 02/26] can: c_can: Fix startup logic Marc Kleine-Budde
2014-04-29 7:29 ` Yegor Yefremov
2014-05-02 12:37 ` Marc Kleine-Budde
2014-04-24 22:00 ` [PATCH 03/26] can: c_can: Make bus off interrupt disable logic work Marc Kleine-Budde
2014-04-24 22:00 ` [PATCH 04/26] can: c_can: Do not access skb after net_receive_skb() Marc Kleine-Budde
2014-04-24 22:00 ` [PATCH 05/26] can: c_can: Handle state change correctly Marc Kleine-Budde
2014-04-24 22:00 ` [PATCH 06/26] can: c_can: Fix berr reporting Marc Kleine-Budde
2014-04-24 22:00 ` [PATCH 07/26] can: c_can: Always update error stats Marc Kleine-Budde
2014-04-24 22:00 ` [PATCH 08/26] can: c_can: Simplify buffer reenabling Marc Kleine-Budde
2014-04-24 22:00 ` [PATCH 09/26] can: c_can: Avoid status register update for D_CAN Marc Kleine-Budde
2014-04-24 22:00 ` Marc Kleine-Budde [this message]
2014-04-24 22:00 ` [PATCH 11/26] can: c_can: Disable rx split as workaround Marc Kleine-Budde
2014-04-24 22:00 ` [PATCH 12/26] can: c_can: Work around C_CAN RX wreckage Marc Kleine-Budde
2014-04-24 22:00 ` [PATCH 13/26] can: c_can: Cleanup irq enable/disable Marc Kleine-Budde
2014-04-24 22:00 ` [PATCH 14/26] can: c_can: Cleanup c_can_read_msg_object() Marc Kleine-Budde
2014-04-24 22:00 ` [PATCH 15/26] can: c_can: Cleanup setup of receive buffers Marc Kleine-Budde
2014-04-24 22:00 ` [PATCH 16/26] can: c_can: Cleanup c_can_inval_msg_object() Marc Kleine-Budde
2014-04-24 22:00 ` [PATCH 17/26] can: c_can: Cleanup c_can_msg_obj_put/get() Marc Kleine-Budde
2014-04-24 22:00 ` [PATCH 18/26] can: c_can: Cleanup c_can_write_msg_object() Marc Kleine-Budde
2014-04-24 22:00 ` [PATCH 19/26] can: c_can: Use proper u32 variables in c_can_write_msg_object() Marc Kleine-Budde
2014-04-24 22:00 ` [PATCH 20/26] can: c_can: Remove tx locking Marc Kleine-Budde
2014-04-24 22:00 ` [PATCH 21/26] can: c_can: Speed up tx buffer invalidation Marc Kleine-Budde
2014-04-24 22:00 ` [PATCH 22/26] can: c_can: use proper type for 'instance' Marc Kleine-Budde
2014-04-24 22:00 ` [PATCH 23/26] can: c_can_pci: enable PCI bus master only for MSI Marc Kleine-Budde
2014-04-24 22:00 ` [PATCH 24/26] can: sja1000_isa: add locking for indirect register access mode Marc Kleine-Budde
2014-04-24 22:00 ` [PATCH 25/26] can: fix return value from can_get_bittiming() Marc Kleine-Budde
2014-04-24 22:00 ` [PATCH 26/26] can: slcan: Fix spinlock variant Marc Kleine-Budde
2014-04-24 22:04 ` pull-request: can 2014-04-24 Marc Kleine-Budde
2014-04-26 16:31 ` David Miller
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1398376829-6771-11-git-send-email-mkl@pengutronix.de \
--to=mkl@pengutronix.de \
--cc=davem@davemloft.net \
--cc=kernel@pengutronix.de \
--cc=linux-can@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=tglx@linutronix.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).