aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2014-03-18 13:19:13 -0400
committerMarc Kleine-Budde <mkl@pengutronix.de>2014-04-01 05:55:01 -0400
commitc0a9f4d396c9d3cf34d21e318a422f9461d93042 (patch)
tree9c5559cc237a158eec12c1a778806cdd0c8b0e34
parent520f570c4378d23b595e52213601d62332174462 (diff)
can: c_can: Reduce register access
commit 4ce78a838c (can: c_can: Speed up rx_poll function) hyped a performance improvement by reducing the access to the interrupt pending register from a dual 16 bit to a single 16 bit access. Wow! Thereby it crippled the driver to cast the 16 msg objects in stone, which is completly braindead as contemporary hardware has up to 128 message objects. Supporting larger object buffers is a major surgery, but it'd be definitely worth it especially as the driver does not support HW message filtering .... The logic of the "FIFO" implementation is to split the FIFO in half. For the lower half we read the buffers and clear the interrupt pending bit, but keep the newdat bit set, so the HW will queue above those buffers. When we read out the last low buffer then we reenable all the low half buffers by clearing the newdat bit. The upper half buffers clear the newdat and the interrupt pending bit right away as we know that the lower half bits are clear and give us a headstart against the hardware. Now the implementation is: transfer_message_object() read_object_and_put_into_skb(); if (obj < END_OF_LOW_BUF) clear_intpending(obj) else if (obj > END_OF_LOW_BUF) clear_intpending_and_newdat(obj) else if (obj == END_OF_LOW_BUF) clear_newdat_of_all_low_objects() The hardware allows to avoid most of the mess simply because we can tell the transfer_message_object() function to clear bits right away. So we can be clever and do: if (obj <= END_OF_LOW_BUF) ctrl = TRANSFER_MSG | CLEAR_INTPND; else ctrl = TRANSFER_MSG | CLEAR_INTPND | CLEAR_NEWDAT; transfer_message_object(ctrl) read_object_and_put_into_skb(); if (obj == END_OF_LOW_BUF) clear_newdat_of_all_low_objects() So we save a complete control operation on all message objects except the one which is the end of the low buffer. That's a few micro seconds per object. I'm not adding a boasting profile to that, simply because it's self explaining. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> [mkl: adjusted subject and commit message] Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
-rw-r--r--drivers/net/can/c_can/c_can.c49
1 files changed, 15 insertions, 34 deletions
diff --git a/drivers/net/can/c_can/c_can.c b/drivers/net/can/c_can/c_can.c
index bd7234eb42f4..8ea1379a398b 100644
--- a/drivers/net/can/c_can/c_can.c
+++ b/drivers/net/can/c_can/c_can.c
@@ -114,6 +114,14 @@
114 IF_COMM_CONTROL | IF_COMM_TXRQST | \ 114 IF_COMM_CONTROL | IF_COMM_TXRQST | \
115 IF_COMM_DATAA | IF_COMM_DATAB) 115 IF_COMM_DATAA | IF_COMM_DATAB)
116 116
117/* For the low buffers we clear the interrupt bit, but keep newdat */
118#define IF_COMM_RCV_LOW (IF_COMM_MASK | IF_COMM_ARB | \
119 IF_COMM_CONTROL | IF_COMM_CLR_INT_PND | \
120 IF_COMM_DATAA | IF_COMM_DATAB)
121
122/* For the high buffers we clear the interrupt bit and newdat */
123#define IF_COMM_RCV_HIGH (IF_COMM_RCV_LOW | IF_COMM_TXRQST)
124
117/* IFx arbitration */ 125/* IFx arbitration */
118#define IF_ARB_MSGVAL BIT(15) 126#define IF_ARB_MSGVAL BIT(15)
119#define IF_ARB_MSGXTD BIT(14) 127#define IF_ARB_MSGXTD BIT(14)
@@ -371,18 +379,6 @@ static void c_can_write_msg_object(struct net_device *dev,
371 c_can_object_put(dev, iface, objno, IF_COMM_ALL); 379 c_can_object_put(dev, iface, objno, IF_COMM_ALL);
372} 380}
373 381
374static inline void c_can_mark_rx_msg_obj(struct net_device *dev,
375 int iface, int ctrl_mask,
376 int obj)
377{
378 struct c_can_priv *priv = netdev_priv(dev);
379
380 priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface),
381 ctrl_mask & ~(IF_MCONT_MSGLST | IF_MCONT_INTPND));
382 c_can_object_put(dev, iface, obj, IF_COMM_CONTROL);
383
384}
385
386static inline void c_can_activate_all_lower_rx_msg_obj(struct net_device *dev, 382static inline void c_can_activate_all_lower_rx_msg_obj(struct net_device *dev,
387 int iface, 383 int iface,
388 int ctrl_mask) 384 int ctrl_mask)
@@ -392,24 +388,11 @@ static inline void c_can_activate_all_lower_rx_msg_obj(struct net_device *dev,
392 388
393 for (i = C_CAN_MSG_OBJ_RX_FIRST; i <= C_CAN_MSG_RX_LOW_LAST; i++) { 389 for (i = C_CAN_MSG_OBJ_RX_FIRST; i <= C_CAN_MSG_RX_LOW_LAST; i++) {
394 priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface), 390 priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface),
395 ctrl_mask & ~(IF_MCONT_MSGLST | 391 ctrl_mask & ~IF_MCONT_NEWDAT);
396 IF_MCONT_INTPND | IF_MCONT_NEWDAT));
397 c_can_object_put(dev, iface, i, IF_COMM_CONTROL); 392 c_can_object_put(dev, iface, i, IF_COMM_CONTROL);
398 } 393 }
399} 394}
400 395
401static inline void c_can_activate_rx_msg_obj(struct net_device *dev,
402 int iface, int ctrl_mask,
403 int obj)
404{
405 struct c_can_priv *priv = netdev_priv(dev);
406
407 priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface),
408 ctrl_mask & ~(IF_MCONT_MSGLST |
409 IF_MCONT_INTPND | IF_MCONT_NEWDAT));
410 c_can_object_put(dev, iface, obj, IF_COMM_CONTROL);
411}
412
413static int c_can_handle_lost_msg_obj(struct net_device *dev, 396static int c_can_handle_lost_msg_obj(struct net_device *dev,
414 int iface, int objno, u32 ctrl) 397 int iface, int objno, u32 ctrl)
415{ 398{
@@ -852,12 +835,15 @@ static u32 c_can_adjust_pending(u32 pend)
852static int c_can_read_objects(struct net_device *dev, struct c_can_priv *priv, 835static int c_can_read_objects(struct net_device *dev, struct c_can_priv *priv,
853 u32 pend, int quota) 836 u32 pend, int quota)
854{ 837{
855 u32 pkts = 0, ctrl, obj; 838 u32 pkts = 0, ctrl, obj, mcmd;
856 839
857 while ((obj = ffs(pend)) && quota > 0) { 840 while ((obj = ffs(pend)) && quota > 0) {
858 pend &= ~BIT(obj - 1); 841 pend &= ~BIT(obj - 1);
859 842
860 c_can_object_get(dev, IF_RX, obj, IF_COMM_ALL & ~IF_COMM_TXRQST); 843 mcmd = obj < C_CAN_MSG_RX_LOW_LAST ?
844 IF_COMM_RCV_LOW : IF_COMM_RCV_HIGH;
845
846 c_can_object_get(dev, IF_RX, obj, mcmd);
861 ctrl = priv->read_reg(priv, C_CAN_IFACE(MSGCTRL_REG, IF_RX)); 847 ctrl = priv->read_reg(priv, C_CAN_IFACE(MSGCTRL_REG, IF_RX));
862 848
863 if (ctrl & IF_MCONT_MSGLST) { 849 if (ctrl & IF_MCONT_MSGLST) {
@@ -879,12 +865,7 @@ static int c_can_read_objects(struct net_device *dev, struct c_can_priv *priv,
879 /* read the data from the message object */ 865 /* read the data from the message object */
880 c_can_read_msg_object(dev, IF_RX, ctrl); 866 c_can_read_msg_object(dev, IF_RX, ctrl);
881 867
882 if (obj < C_CAN_MSG_RX_LOW_LAST) 868 if (obj == C_CAN_MSG_RX_LOW_LAST)
883 c_can_mark_rx_msg_obj(dev, IF_RX, ctrl, obj);
884 else if (obj > C_CAN_MSG_RX_LOW_LAST)
885 /* activate this msg obj */
886 c_can_activate_rx_msg_obj(dev, IF_RX, ctrl, obj);
887 else if (obj == C_CAN_MSG_RX_LOW_LAST)
888 /* activate all lower message objects */ 869 /* activate all lower message objects */
889 c_can_activate_all_lower_rx_msg_obj(dev, IF_RX, ctrl); 870 c_can_activate_all_lower_rx_msg_obj(dev, IF_RX, ctrl);
890 871