summaryrefslogtreecommitdiff
path: root/drivers/net
diff options
context:
space:
mode:
authorDominik Sliwa <dominik.sliwa@toradex.com>2018-02-12 12:21:11 +0100
committerMarcel Ziswiler <marcel.ziswiler@toradex.com>2018-03-28 18:31:28 +0200
commite83f0920de7882d09816c57a1e78e253cc3dcd7c (patch)
tree61ce6651ef21c8d4469f363942254326b8a2d15c /drivers/net
parente2479101d95625c1c2fcb7c8f72fe515d9099cc1 (diff)
can: mfd: apalis-tk1: v1.1 frequency adjustments and various fixes
Signed-off-by: Dominik Sliwa <dominik.sliwa@toradex.com> Acked-by: Marcel Ziswiler <marcel.ziswiler@toradex.com>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/can/apalis-tk1-k20-can.c104
1 files changed, 56 insertions, 48 deletions
diff --git a/drivers/net/can/apalis-tk1-k20-can.c b/drivers/net/can/apalis-tk1-k20-can.c
index c32a70181ac1..53f64189a7fb 100644
--- a/drivers/net/can/apalis-tk1-k20-can.c
+++ b/drivers/net/can/apalis-tk1-k20-can.c
@@ -34,22 +34,20 @@
#define CAN_FRAME_MAX_LEN 8
#define CAN_HEADER_MAX_LEN 5
#define CAN_TRANSFER_BUF_LEN (CAN_HEADER_MAX_LEN + CAN_FRAME_MAX_LEN)
-#define CAN_FRAME_MAX_BITS 128
-#define CAN_MAX_CONTINUOUS_READ 8
-#define MB_DLC_OFF 0
-#define MB_EID_OFF 1
+#define MB_DLC_OFF 4
+#define MB_EID_OFF 0
#define MB_RTR_SHIFT 4
#define MB_IDE_SHIFT 5
#define MB_DLC_MASK 0xF
#define MB_EID_LEN 4
#define CANCTRL_MODMASK 0x03
-#define CANCTRL_INTMASK 0x38
#define CANCTRL_INTEN BIT(2)
#define CANINTF_RX BIT(3)
#define CANINTF_TX BIT(4)
#define CANINTF_ERR BIT(5)
+#define CANCTRL_INTMASK (CANINTF_RX | CANINTF_TX | CANINTF_ERR)
#define EFLG_EWARN 0x01
#define EFLG_RXWAR 0x02
@@ -140,42 +138,50 @@ static void apalis_tk1_k20_can_hw_tx(struct net_device *net,
+ CAN_HEADER_MAX_LEN, tx_buf_idx);
}
-static void apalis_tk1_k20_can_hw_rx_frame(struct net_device *net, u8 *buf,
- int buf_idx)
+static void apalis_tk1_k20_can_hw_rx(struct net_device *net, int buf_idx)
{
struct apalis_tk1_k20_priv *priv = netdev_priv(net);
+ struct sk_buff *skb;
+ struct can_frame *frame;
+ u8 buf[CAN_TRANSFER_BUF_LEN * APALIS_TK1_MAX_CAN_DMA_XREF];
+ u32 frame_available = 0;
apalis_tk1_k20_lock(priv->apalis_tk1_k20);
-
+ apalis_tk1_k20_reg_read(priv->apalis_tk1_k20,
+ APALIS_TK1_K20_CAN_IN_BUF_CNT
+ + APALIS_TK1_K20_CAN_DEV_OFFSET(
+ priv->pdata->id), &frame_available);
+ frame_available = min(frame_available, APALIS_TK1_MAX_CAN_DMA_XREF);
apalis_tk1_k20_reg_read_bulk(priv->apalis_tk1_k20,
APALIS_TK1_K20_CAN_IN_BUF
+ APALIS_TK1_K20_CAN_DEV_OFFSET(
priv->pdata->id), buf,
- CAN_TRANSFER_BUF_LEN);
+ CAN_TRANSFER_BUF_LEN * frame_available);
apalis_tk1_k20_unlock(priv->apalis_tk1_k20);
-}
-
-static void apalis_tk1_k20_can_hw_rx(struct net_device *net, int buf_idx)
-{
- struct apalis_tk1_k20_priv *priv = netdev_priv(net);
- struct sk_buff *skb;
- struct can_frame *frame;
- skb = alloc_can_skb(priv->net, &frame);
- if (!skb) {
- dev_err(&net->dev, "cannot allocate RX skb\n");
- priv->net->stats.rx_dropped++;
- return;
- }
+ for (int i = 0; i < frame_available; i++) {
+ skb = alloc_can_skb(priv->net, &frame);
+ if (!skb) {
+ dev_err(&net->dev, "cannot allocate RX skb\n");
+ priv->net->stats.rx_dropped++;
+ return;
+ }
+ memcpy(&frame->can_id, &buf[i * CAN_TRANSFER_BUF_LEN]
+ + MB_EID_OFF, MB_EID_LEN);
+ /* Data length */
+ frame->can_dlc = get_can_dlc(buf[i * CAN_TRANSFER_BUF_LEN
+ + MB_DLC_OFF]);
+ memcpy(frame->data, &buf[i * CAN_TRANSFER_BUF_LEN]
+ + CAN_HEADER_MAX_LEN, frame->can_dlc);
- apalis_tk1_k20_can_hw_rx_frame(net, (unsigned char *)frame, buf_idx);
+ priv->net->stats.rx_packets++;
+ priv->net->stats.rx_bytes += frame->can_dlc;
- priv->net->stats.rx_packets++;
- priv->net->stats.rx_bytes += frame->can_dlc;
+ can_led_event(priv->net, CAN_LED_EVENT_RX);
- can_led_event(priv->net, CAN_LED_EVENT_RX);
+ netif_rx_ni(skb);
+ }
- netif_rx_ni(skb);
}
@@ -503,10 +509,9 @@ static irqreturn_t apalis_tk1_k20_can_ist(int irq, void *dev_id)
{
struct apalis_tk1_k20_priv *priv = dev_id;
struct net_device *net = priv->net;
- int max_continuous_read = CAN_MAX_CONTINUOUS_READ;
mutex_lock(&priv->apalis_tk1_k20_can_lock);
- while (!priv->force_quit && max_continuous_read) {
+ while (!priv->force_quit) {
enum can_state new_state;
int ret;
u32 intf, eflag;
@@ -525,39 +530,37 @@ static irqreturn_t apalis_tk1_k20_can_ist(int irq, void *dev_id)
break;
}
- max_continuous_read--;
-
intf &= CANCTRL_INTMASK;
/* receive */
if (intf & CANINTF_RX)
apalis_tk1_k20_can_hw_rx(net, 0);
- /* any error or TX interrupt we need to clear? */
- if (intf & (CANINTF_ERR | CANINTF_TX))
- clear_intf |= intf & (CANINTF_ERR | CANINTF_TX);
+ /* any error interrupt we need to clear? */
+ if (intf & CANINTF_ERR)
+ clear_intf |= intf & CANINTF_ERR;
apalis_tk1_k20_lock(priv->apalis_tk1_k20);
if (clear_intf)
- ret = apalis_tk1_k20_reg_rmw(priv->apalis_tk1_k20,
- APALIS_TK1_K20_CANREG +
- APALIS_TK1_K20_CAN_DEV_OFFSET(
- priv->pdata->id),
- CANCTRL_INTMASK, 0x00);
+ ret = apalis_tk1_k20_reg_write(priv->apalis_tk1_k20,
+ APALIS_TK1_K20_CANREG_CLR
+ + APALIS_TK1_K20_CAN_DEV_OFFSET(
+ priv->pdata->id),clear_intf);
if (ret) {
apalis_tk1_k20_unlock(priv->apalis_tk1_k20);
dev_err(&net->dev, "Communication error\n");
break;
}
- ret = apalis_tk1_k20_reg_read(priv->apalis_tk1_k20,
- APALIS_TK1_K20_CANERR +
- APALIS_TK1_K20_CAN_DEV_OFFSET(
- priv->pdata->id), &eflag);
- apalis_tk1_k20_unlock(priv->apalis_tk1_k20);
- if (ret) {
- dev_err(&net->dev, "Communication error\n");
- break;
- }
+
/* Update can state */
if (intf & CANINTF_ERR) {
+ ret = apalis_tk1_k20_reg_read(priv->apalis_tk1_k20,
+ APALIS_TK1_K20_CANERR +
+ APALIS_TK1_K20_CAN_DEV_OFFSET(
+ priv->pdata->id), &eflag);
+ apalis_tk1_k20_unlock(priv->apalis_tk1_k20);
+ if (ret) {
+ dev_err(&net->dev, "Communication error\n");
+ break;
+ }
if (eflag & EFLG_TXBO) {
new_state = CAN_STATE_BUS_OFF;
can_id |= CAN_ERR_BUSOFF;
@@ -581,6 +584,9 @@ static irqreturn_t apalis_tk1_k20_can_ist(int irq, void *dev_id)
new_state = CAN_STATE_ERROR_ACTIVE;
}
}
+ else {
+ apalis_tk1_k20_unlock(priv->apalis_tk1_k20);
+ }
/* Update can state statistics */
switch (priv->can.state) {
@@ -630,6 +636,8 @@ static irqreturn_t apalis_tk1_k20_can_ist(int irq, void *dev_id)
priv->tx_len = 0;
}
netif_wake_queue(net);
+ if (!(intf & (CANINTF_RX | CANINTF_ERR)))
+ break;
}
}
mutex_unlock(&priv->apalis_tk1_k20_can_lock);