Make number of D_CAN RX message objects configurable. This will allow
having bigger (or smaller) RX buffer instead of 50/50 split for RX/TX.
Signed-off-by: Andrejs Cainikovs <[email protected]>
---
drivers/net/can/c_can/Kconfig | 8 ++++++
drivers/net/can/c_can/c_can.c | 64 +++++++++++++++++++++++++++++--------------
drivers/net/can/c_can/c_can.h | 16 +++++------
3 files changed, 58 insertions(+), 30 deletions(-)
diff --git a/drivers/net/can/c_can/Kconfig b/drivers/net/can/c_can/Kconfig
index 6c1ada7291df..949d2d12d71e 100644
--- a/drivers/net/can/c_can/Kconfig
+++ b/drivers/net/can/c_can/Kconfig
@@ -32,4 +32,12 @@ config CAN_C_CAN_DCAN_64_MSG_OBJECTS
Enabling this option extends max D_CAN message objects up to
64.
+config CAN_C_CAN_DCAN_RX_MSG_OBJECTS
+ int "Specify amount of D_CAN RX message objects"
+ depends on CAN_C_CAN_DCAN_64_MSG_OBJECTS
+ default 32
+ ---help---
+ Use specific number of message objects for RX, instead of
+ 50/50 split between RX/TX.
+
endif
diff --git a/drivers/net/can/c_can/c_can.c b/drivers/net/can/c_can/c_can.c
index 5d695b89b459..675bc223e222 100644
--- a/drivers/net/can/c_can/c_can.c
+++ b/drivers/net/can/c_can/c_can.c
@@ -208,6 +208,26 @@ static const struct can_bittiming_const c_can_bittiming_const = {
.brp_inc = 1,
};
+static inline u64 c_can_get_mask(int bits)
+{
+ return ((u64)1 << bits) - 1;
+}
+
+static inline int c_can_ffs64(u64 x)
+{
+ int b;
+
+ b = ffs(x);
+
+ if (!b) {
+ b = ffs(x >> 32);
+ if (b)
+ b += 32;
+ }
+
+ return b;
+}
+
static inline void c_can_pm_runtime_enable(const struct c_can_priv *priv)
{
if (priv->device)
@@ -695,24 +715,23 @@ static void c_can_do_tx(struct net_device *dev)
{
struct c_can_priv *priv = netdev_priv(dev);
struct net_device_stats *stats = &dev->stats;
- u32 idx, obj, pkts = 0, bytes = 0, pend, clr;
+ u32 idx, obj, pkts = 0, bytes = 0;
+ u64 pend, clr;
+ /* Mask interrupt pending bits */
+ pend = priv->read_reg32(priv, C_CAN_INTPND1_REG);
#ifdef CONFIG_CAN_C_CAN_DCAN_64_MSG_OBJECTS
if (priv->type == BOSCH_D_CAN) {
- pend = priv->read_reg32(priv, C_CAN_INTPND3_REG);
- } else {
-#endif
- pend = priv->read_reg(priv, C_CAN_INTPND2_REG);
-#ifdef CONFIG_CAN_C_CAN_DCAN_64_MSG_OBJECTS
+ pend |= (u64)priv->read_reg32(priv, C_CAN_INTPND3_REG) << 32;
}
#endif
- clr = pend;
+ pend &= ~c_can_get_mask(C_CAN_MSG_OBJ_RX_NUM);
+ clr = pend >> C_CAN_MSG_OBJ_RX_NUM;
- while ((idx = ffs(pend))) {
- idx--;
- pend &= ~(1 << idx);
- obj = idx + C_CAN_MSG_OBJ_TX_FIRST;
+ while ((obj = c_can_ffs64(pend))) {
+ pend &= ~((u64)1 << (obj - 1));
c_can_inval_tx_object(dev, IF_RX, obj);
+ idx = obj - C_CAN_MSG_OBJ_TX_FIRST;
can_get_echo_skb(dev, idx);
bytes += priv->dlc[idx];
pkts++;
@@ -736,19 +755,19 @@ static void c_can_do_tx(struct net_device *dev)
* raced with the hardware or failed to readout all upper
* objects in the last run due to quota limit.
*/
-static u32 c_can_adjust_pending(u32 pend)
+static u64 c_can_adjust_pending(u64 pend)
{
- u32 weight, lasts;
+ u64 weight, lasts;
- if (pend == RECEIVE_OBJECT_BITS)
+ if (pend == c_can_get_mask(C_CAN_MSG_OBJ_RX_NUM))
return pend;
/*
* If the last set bit is larger than the number of pending
* bits we have a gap.
*/
- weight = hweight32(pend);
- lasts = fls(pend);
+ weight = hweight64(pend);
+ lasts = fls64(pend);
/* If the bits are linear, nothing to do */
if (lasts == weight)
@@ -777,11 +796,11 @@ static inline void c_can_rx_finalize(struct net_device *dev,
}
static int c_can_read_objects(struct net_device *dev, struct c_can_priv *priv,
- u32 pend, int quota)
+ u64 pend, int quota)
{
u32 pkts = 0, ctrl, obj;
- while ((obj = ffs(pend)) && quota > 0) {
+ while ((obj = c_can_ffs64(pend)) && quota > 0) {
pend &= ~BIT(obj - 1);
c_can_rx_object_get(dev, priv, obj);
@@ -815,13 +834,15 @@ static int c_can_read_objects(struct net_device *dev, struct c_can_priv *priv,
return pkts;
}
-static inline u32 c_can_get_pending(struct c_can_priv *priv)
+static inline u64 c_can_get_pending(struct c_can_priv *priv)
{
- u32 pend;
+ u64 pend;
#ifdef CONFIG_CAN_C_CAN_DCAN_64_MSG_OBJECTS
if (priv->type == BOSCH_D_CAN) {
pend = priv->read_reg32(priv, C_CAN_NEWDAT1_REG);
+ pend |= (u64)priv->read_reg32(priv, C_CAN_NEWDAT3_REG) << 32;
+ pend &= c_can_get_mask(C_CAN_MSG_OBJ_RX_NUM);
} else {
#endif
pend = priv->read_reg(priv, C_CAN_NEWDAT1_REG);
@@ -847,7 +868,8 @@ static inline u32 c_can_get_pending(struct c_can_priv *priv)
static int c_can_do_rx_poll(struct net_device *dev, int quota)
{
struct c_can_priv *priv = netdev_priv(dev);
- u32 pkts = 0, pend = 0, toread, n;
+ u32 pkts = 0, n;
+ u64 pend = 0, toread;
while (quota > 0) {
if (!pend) {
diff --git a/drivers/net/can/c_can/c_can.h b/drivers/net/can/c_can/c_can.h
index e44b686a70a2..4a0759ee249d 100644
--- a/drivers/net/can/c_can/c_can.h
+++ b/drivers/net/can/c_can/c_can.h
@@ -26,12 +26,12 @@
#ifdef CONFIG_CAN_C_CAN_DCAN_64_MSG_OBJECTS
#define C_CAN_NO_OF_OBJECTS 64
+#define C_CAN_MSG_OBJ_RX_NUM CONFIG_CAN_C_CAN_DCAN_RX_MSG_OBJECTS
#else
#define C_CAN_NO_OF_OBJECTS 32
+#define C_CAN_MSG_OBJ_RX_NUM 16
#endif
-
-#define C_CAN_MSG_OBJ_TX_NUM (C_CAN_NO_OF_OBJECTS >> 1)
-#define C_CAN_MSG_OBJ_RX_NUM (C_CAN_NO_OF_OBJECTS - C_CAN_MSG_OBJ_TX_NUM)
+#define C_CAN_MSG_OBJ_TX_NUM (C_CAN_NO_OF_OBJECTS - C_CAN_MSG_OBJ_RX_NUM)
#define C_CAN_MSG_OBJ_RX_FIRST 1
#define C_CAN_MSG_OBJ_RX_LAST (C_CAN_MSG_OBJ_RX_FIRST + \
@@ -41,12 +41,6 @@
#define C_CAN_MSG_OBJ_TX_LAST (C_CAN_MSG_OBJ_TX_FIRST + \
C_CAN_MSG_OBJ_TX_NUM - 1)
-#ifdef CONFIG_CAN_C_CAN_DCAN_64_MSG_OBJECTS
-#define RECEIVE_OBJECT_BITS 0xffffffff
-#else
-#define RECEIVE_OBJECT_BITS 0x0000ffff
-#endif
-
enum reg {
C_CAN_CTRL_REG = 0,
C_CAN_CTRL_EX_REG,
@@ -82,6 +76,8 @@ enum reg {
C_CAN_TXRQST2_REG,
C_CAN_NEWDAT1_REG,
C_CAN_NEWDAT2_REG,
+ C_CAN_NEWDAT3_REG,
+ C_CAN_NEWDAT4_REG,
C_CAN_INTPND1_REG,
C_CAN_INTPND2_REG,
C_CAN_INTPND3_REG,
@@ -145,6 +141,8 @@ static const u16 reg_map_d_can[] = {
[C_CAN_TXRQST2_REG] = 0x8A,
[C_CAN_NEWDAT1_REG] = 0x9C,
[C_CAN_NEWDAT2_REG] = 0x9E,
+ [C_CAN_NEWDAT3_REG] = 0xA0,
+ [C_CAN_NEWDAT4_REG] = 0xA2,
[C_CAN_INTPND1_REG] = 0xB0,
[C_CAN_INTPND2_REG] = 0xB2,
[C_CAN_INTPND3_REG] = 0xB4,
--
2.11.0