162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * CAN bus driver for the alone generic (as possible as) MSCAN controller. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2005-2006 Andrey Volkov <avolkov@varma-el.com>, 662306a36Sopenharmony_ci * Varma Electronics Oy 762306a36Sopenharmony_ci * Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com> 862306a36Sopenharmony_ci * Copyright (C) 2008-2009 Pengutronix <kernel@pengutronix.de> 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/kernel.h> 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/interrupt.h> 1462306a36Sopenharmony_ci#include <linux/delay.h> 1562306a36Sopenharmony_ci#include <linux/netdevice.h> 1662306a36Sopenharmony_ci#include <linux/if_arp.h> 1762306a36Sopenharmony_ci#include <linux/if_ether.h> 1862306a36Sopenharmony_ci#include <linux/list.h> 1962306a36Sopenharmony_ci#include <linux/can/dev.h> 2062306a36Sopenharmony_ci#include <linux/can/error.h> 2162306a36Sopenharmony_ci#include <linux/io.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include "mscan.h" 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistatic const struct can_bittiming_const mscan_bittiming_const = { 2662306a36Sopenharmony_ci .name = "mscan", 2762306a36Sopenharmony_ci .tseg1_min = 4, 2862306a36Sopenharmony_ci .tseg1_max = 16, 2962306a36Sopenharmony_ci .tseg2_min = 2, 3062306a36Sopenharmony_ci .tseg2_max = 8, 3162306a36Sopenharmony_ci .sjw_max = 4, 3262306a36Sopenharmony_ci .brp_min = 1, 3362306a36Sopenharmony_ci .brp_max = 64, 3462306a36Sopenharmony_ci .brp_inc = 1, 3562306a36Sopenharmony_ci}; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistruct mscan_state { 3862306a36Sopenharmony_ci u8 mode; 3962306a36Sopenharmony_ci u8 canrier; 4062306a36Sopenharmony_ci u8 cantier; 4162306a36Sopenharmony_ci}; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistatic enum can_state state_map[] = { 4462306a36Sopenharmony_ci CAN_STATE_ERROR_ACTIVE, 4562306a36Sopenharmony_ci CAN_STATE_ERROR_WARNING, 4662306a36Sopenharmony_ci CAN_STATE_ERROR_PASSIVE, 4762306a36Sopenharmony_ci CAN_STATE_BUS_OFF 4862306a36Sopenharmony_ci}; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic int mscan_set_mode(struct net_device *dev, u8 mode) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci struct mscan_priv *priv = netdev_priv(dev); 5362306a36Sopenharmony_ci struct mscan_regs __iomem *regs = priv->reg_base; 5462306a36Sopenharmony_ci int ret = 0; 5562306a36Sopenharmony_ci int i; 5662306a36Sopenharmony_ci u8 canctl1; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci if (mode != MSCAN_NORMAL_MODE) { 5962306a36Sopenharmony_ci if (priv->tx_active) { 6062306a36Sopenharmony_ci /* Abort transfers before going to sleep */# 6162306a36Sopenharmony_ci out_8(®s->cantarq, priv->tx_active); 6262306a36Sopenharmony_ci /* Suppress TX done interrupts */ 6362306a36Sopenharmony_ci out_8(®s->cantier, 0); 6462306a36Sopenharmony_ci } 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci canctl1 = in_8(®s->canctl1); 6762306a36Sopenharmony_ci if ((mode & MSCAN_SLPRQ) && !(canctl1 & MSCAN_SLPAK)) { 6862306a36Sopenharmony_ci setbits8(®s->canctl0, MSCAN_SLPRQ); 6962306a36Sopenharmony_ci for (i = 0; i < MSCAN_SET_MODE_RETRIES; i++) { 7062306a36Sopenharmony_ci if (in_8(®s->canctl1) & MSCAN_SLPAK) 7162306a36Sopenharmony_ci break; 7262306a36Sopenharmony_ci udelay(100); 7362306a36Sopenharmony_ci } 7462306a36Sopenharmony_ci /* 7562306a36Sopenharmony_ci * The mscan controller will fail to enter sleep mode, 7662306a36Sopenharmony_ci * while there are irregular activities on bus, like 7762306a36Sopenharmony_ci * somebody keeps retransmitting. This behavior is 7862306a36Sopenharmony_ci * undocumented and seems to differ between mscan built 7962306a36Sopenharmony_ci * in mpc5200b and mpc5200. We proceed in that case, 8062306a36Sopenharmony_ci * since otherwise the slprq will be kept set and the 8162306a36Sopenharmony_ci * controller will get stuck. NOTE: INITRQ or CSWAI 8262306a36Sopenharmony_ci * will abort all active transmit actions, if still 8362306a36Sopenharmony_ci * any, at once. 8462306a36Sopenharmony_ci */ 8562306a36Sopenharmony_ci if (i >= MSCAN_SET_MODE_RETRIES) 8662306a36Sopenharmony_ci netdev_dbg(dev, 8762306a36Sopenharmony_ci "device failed to enter sleep mode. " 8862306a36Sopenharmony_ci "We proceed anyhow.\n"); 8962306a36Sopenharmony_ci else 9062306a36Sopenharmony_ci priv->can.state = CAN_STATE_SLEEPING; 9162306a36Sopenharmony_ci } 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci if ((mode & MSCAN_INITRQ) && !(canctl1 & MSCAN_INITAK)) { 9462306a36Sopenharmony_ci setbits8(®s->canctl0, MSCAN_INITRQ); 9562306a36Sopenharmony_ci for (i = 0; i < MSCAN_SET_MODE_RETRIES; i++) { 9662306a36Sopenharmony_ci if (in_8(®s->canctl1) & MSCAN_INITAK) 9762306a36Sopenharmony_ci break; 9862306a36Sopenharmony_ci } 9962306a36Sopenharmony_ci if (i >= MSCAN_SET_MODE_RETRIES) 10062306a36Sopenharmony_ci ret = -ENODEV; 10162306a36Sopenharmony_ci } 10262306a36Sopenharmony_ci if (!ret) 10362306a36Sopenharmony_ci priv->can.state = CAN_STATE_STOPPED; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci if (mode & MSCAN_CSWAI) 10662306a36Sopenharmony_ci setbits8(®s->canctl0, MSCAN_CSWAI); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci } else { 10962306a36Sopenharmony_ci canctl1 = in_8(®s->canctl1); 11062306a36Sopenharmony_ci if (canctl1 & (MSCAN_SLPAK | MSCAN_INITAK)) { 11162306a36Sopenharmony_ci clrbits8(®s->canctl0, MSCAN_SLPRQ | MSCAN_INITRQ); 11262306a36Sopenharmony_ci for (i = 0; i < MSCAN_SET_MODE_RETRIES; i++) { 11362306a36Sopenharmony_ci canctl1 = in_8(®s->canctl1); 11462306a36Sopenharmony_ci if (!(canctl1 & (MSCAN_INITAK | MSCAN_SLPAK))) 11562306a36Sopenharmony_ci break; 11662306a36Sopenharmony_ci } 11762306a36Sopenharmony_ci if (i >= MSCAN_SET_MODE_RETRIES) 11862306a36Sopenharmony_ci ret = -ENODEV; 11962306a36Sopenharmony_ci else 12062306a36Sopenharmony_ci priv->can.state = CAN_STATE_ERROR_ACTIVE; 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci return ret; 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cistatic int mscan_start(struct net_device *dev) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci struct mscan_priv *priv = netdev_priv(dev); 12962306a36Sopenharmony_ci struct mscan_regs __iomem *regs = priv->reg_base; 13062306a36Sopenharmony_ci u8 canrflg; 13162306a36Sopenharmony_ci int err; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci out_8(®s->canrier, 0); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci INIT_LIST_HEAD(&priv->tx_head); 13662306a36Sopenharmony_ci priv->prev_buf_id = 0; 13762306a36Sopenharmony_ci priv->cur_pri = 0; 13862306a36Sopenharmony_ci priv->tx_active = 0; 13962306a36Sopenharmony_ci priv->shadow_canrier = 0; 14062306a36Sopenharmony_ci priv->flags = 0; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci if (priv->type == MSCAN_TYPE_MPC5121) { 14362306a36Sopenharmony_ci /* Clear pending bus-off condition */ 14462306a36Sopenharmony_ci if (in_8(®s->canmisc) & MSCAN_BOHOLD) 14562306a36Sopenharmony_ci out_8(®s->canmisc, MSCAN_BOHOLD); 14662306a36Sopenharmony_ci } 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci err = mscan_set_mode(dev, MSCAN_NORMAL_MODE); 14962306a36Sopenharmony_ci if (err) 15062306a36Sopenharmony_ci return err; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci canrflg = in_8(®s->canrflg); 15362306a36Sopenharmony_ci priv->shadow_statflg = canrflg & MSCAN_STAT_MSK; 15462306a36Sopenharmony_ci priv->can.state = state_map[max(MSCAN_STATE_RX(canrflg), 15562306a36Sopenharmony_ci MSCAN_STATE_TX(canrflg))]; 15662306a36Sopenharmony_ci out_8(®s->cantier, 0); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci /* Enable receive interrupts. */ 15962306a36Sopenharmony_ci out_8(®s->canrier, MSCAN_RX_INTS_ENABLE); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci return 0; 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistatic int mscan_restart(struct net_device *dev) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci struct mscan_priv *priv = netdev_priv(dev); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci if (priv->type == MSCAN_TYPE_MPC5121) { 16962306a36Sopenharmony_ci struct mscan_regs __iomem *regs = priv->reg_base; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci priv->can.state = CAN_STATE_ERROR_ACTIVE; 17262306a36Sopenharmony_ci WARN(!(in_8(®s->canmisc) & MSCAN_BOHOLD), 17362306a36Sopenharmony_ci "bus-off state expected\n"); 17462306a36Sopenharmony_ci out_8(®s->canmisc, MSCAN_BOHOLD); 17562306a36Sopenharmony_ci /* Re-enable receive interrupts. */ 17662306a36Sopenharmony_ci out_8(®s->canrier, MSCAN_RX_INTS_ENABLE); 17762306a36Sopenharmony_ci } else { 17862306a36Sopenharmony_ci if (priv->can.state <= CAN_STATE_BUS_OFF) 17962306a36Sopenharmony_ci mscan_set_mode(dev, MSCAN_INIT_MODE); 18062306a36Sopenharmony_ci return mscan_start(dev); 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci return 0; 18462306a36Sopenharmony_ci} 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_cistatic netdev_tx_t mscan_start_xmit(struct sk_buff *skb, struct net_device *dev) 18762306a36Sopenharmony_ci{ 18862306a36Sopenharmony_ci struct can_frame *frame = (struct can_frame *)skb->data; 18962306a36Sopenharmony_ci struct mscan_priv *priv = netdev_priv(dev); 19062306a36Sopenharmony_ci struct mscan_regs __iomem *regs = priv->reg_base; 19162306a36Sopenharmony_ci int i, rtr, buf_id; 19262306a36Sopenharmony_ci u32 can_id; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci if (can_dev_dropped_skb(dev, skb)) 19562306a36Sopenharmony_ci return NETDEV_TX_OK; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci out_8(®s->cantier, 0); 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci i = ~priv->tx_active & MSCAN_TXE; 20062306a36Sopenharmony_ci buf_id = ffs(i) - 1; 20162306a36Sopenharmony_ci switch (hweight8(i)) { 20262306a36Sopenharmony_ci case 0: 20362306a36Sopenharmony_ci netif_stop_queue(dev); 20462306a36Sopenharmony_ci netdev_err(dev, "Tx Ring full when queue awake!\n"); 20562306a36Sopenharmony_ci return NETDEV_TX_BUSY; 20662306a36Sopenharmony_ci case 1: 20762306a36Sopenharmony_ci /* 20862306a36Sopenharmony_ci * if buf_id < 3, then current frame will be send out of order, 20962306a36Sopenharmony_ci * since buffer with lower id have higher priority (hell..) 21062306a36Sopenharmony_ci */ 21162306a36Sopenharmony_ci netif_stop_queue(dev); 21262306a36Sopenharmony_ci fallthrough; 21362306a36Sopenharmony_ci case 2: 21462306a36Sopenharmony_ci if (buf_id < priv->prev_buf_id) { 21562306a36Sopenharmony_ci priv->cur_pri++; 21662306a36Sopenharmony_ci if (priv->cur_pri == 0xff) { 21762306a36Sopenharmony_ci set_bit(F_TX_WAIT_ALL, &priv->flags); 21862306a36Sopenharmony_ci netif_stop_queue(dev); 21962306a36Sopenharmony_ci } 22062306a36Sopenharmony_ci } 22162306a36Sopenharmony_ci set_bit(F_TX_PROGRESS, &priv->flags); 22262306a36Sopenharmony_ci break; 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci priv->prev_buf_id = buf_id; 22562306a36Sopenharmony_ci out_8(®s->cantbsel, i); 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci rtr = frame->can_id & CAN_RTR_FLAG; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci /* RTR is always the lowest bit of interest, then IDs follow */ 23062306a36Sopenharmony_ci if (frame->can_id & CAN_EFF_FLAG) { 23162306a36Sopenharmony_ci can_id = (frame->can_id & CAN_EFF_MASK) 23262306a36Sopenharmony_ci << (MSCAN_EFF_RTR_SHIFT + 1); 23362306a36Sopenharmony_ci if (rtr) 23462306a36Sopenharmony_ci can_id |= 1 << MSCAN_EFF_RTR_SHIFT; 23562306a36Sopenharmony_ci out_be16(®s->tx.idr3_2, can_id); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci can_id >>= 16; 23862306a36Sopenharmony_ci /* EFF_FLAGS are between the IDs :( */ 23962306a36Sopenharmony_ci can_id = (can_id & 0x7) | ((can_id << 2) & 0xffe0) 24062306a36Sopenharmony_ci | MSCAN_EFF_FLAGS; 24162306a36Sopenharmony_ci } else { 24262306a36Sopenharmony_ci can_id = (frame->can_id & CAN_SFF_MASK) 24362306a36Sopenharmony_ci << (MSCAN_SFF_RTR_SHIFT + 1); 24462306a36Sopenharmony_ci if (rtr) 24562306a36Sopenharmony_ci can_id |= 1 << MSCAN_SFF_RTR_SHIFT; 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci out_be16(®s->tx.idr1_0, can_id); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci if (!rtr) { 25062306a36Sopenharmony_ci void __iomem *data = ®s->tx.dsr1_0; 25162306a36Sopenharmony_ci u16 *payload = (u16 *)frame->data; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci for (i = 0; i < frame->len / 2; i++) { 25462306a36Sopenharmony_ci out_be16(data, *payload++); 25562306a36Sopenharmony_ci data += 2 + _MSCAN_RESERVED_DSR_SIZE; 25662306a36Sopenharmony_ci } 25762306a36Sopenharmony_ci /* write remaining byte if necessary */ 25862306a36Sopenharmony_ci if (frame->len & 1) 25962306a36Sopenharmony_ci out_8(data, frame->data[frame->len - 1]); 26062306a36Sopenharmony_ci } 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci out_8(®s->tx.dlr, frame->len); 26362306a36Sopenharmony_ci out_8(®s->tx.tbpr, priv->cur_pri); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci /* Start transmission. */ 26662306a36Sopenharmony_ci out_8(®s->cantflg, 1 << buf_id); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci if (!test_bit(F_TX_PROGRESS, &priv->flags)) 26962306a36Sopenharmony_ci netif_trans_update(dev); 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci list_add_tail(&priv->tx_queue[buf_id].list, &priv->tx_head); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci can_put_echo_skb(skb, dev, buf_id, 0); 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci /* Enable interrupt. */ 27662306a36Sopenharmony_ci priv->tx_active |= 1 << buf_id; 27762306a36Sopenharmony_ci out_8(®s->cantier, priv->tx_active); 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci return NETDEV_TX_OK; 28062306a36Sopenharmony_ci} 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_cistatic enum can_state get_new_state(struct net_device *dev, u8 canrflg) 28362306a36Sopenharmony_ci{ 28462306a36Sopenharmony_ci struct mscan_priv *priv = netdev_priv(dev); 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci if (unlikely(canrflg & MSCAN_CSCIF)) 28762306a36Sopenharmony_ci return state_map[max(MSCAN_STATE_RX(canrflg), 28862306a36Sopenharmony_ci MSCAN_STATE_TX(canrflg))]; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci return priv->can.state; 29162306a36Sopenharmony_ci} 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_cistatic void mscan_get_rx_frame(struct net_device *dev, struct can_frame *frame) 29462306a36Sopenharmony_ci{ 29562306a36Sopenharmony_ci struct mscan_priv *priv = netdev_priv(dev); 29662306a36Sopenharmony_ci struct mscan_regs __iomem *regs = priv->reg_base; 29762306a36Sopenharmony_ci u32 can_id; 29862306a36Sopenharmony_ci int i; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci can_id = in_be16(®s->rx.idr1_0); 30162306a36Sopenharmony_ci if (can_id & (1 << 3)) { 30262306a36Sopenharmony_ci frame->can_id = CAN_EFF_FLAG; 30362306a36Sopenharmony_ci can_id = ((can_id << 16) | in_be16(®s->rx.idr3_2)); 30462306a36Sopenharmony_ci can_id = ((can_id & 0xffe00000) | 30562306a36Sopenharmony_ci ((can_id & 0x7ffff) << 2)) >> 2; 30662306a36Sopenharmony_ci } else { 30762306a36Sopenharmony_ci can_id >>= 4; 30862306a36Sopenharmony_ci frame->can_id = 0; 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci frame->can_id |= can_id >> 1; 31262306a36Sopenharmony_ci if (can_id & 1) 31362306a36Sopenharmony_ci frame->can_id |= CAN_RTR_FLAG; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci frame->len = can_cc_dlc2len(in_8(®s->rx.dlr) & 0xf); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci if (!(frame->can_id & CAN_RTR_FLAG)) { 31862306a36Sopenharmony_ci void __iomem *data = ®s->rx.dsr1_0; 31962306a36Sopenharmony_ci u16 *payload = (u16 *)frame->data; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci for (i = 0; i < frame->len / 2; i++) { 32262306a36Sopenharmony_ci *payload++ = in_be16(data); 32362306a36Sopenharmony_ci data += 2 + _MSCAN_RESERVED_DSR_SIZE; 32462306a36Sopenharmony_ci } 32562306a36Sopenharmony_ci /* read remaining byte if necessary */ 32662306a36Sopenharmony_ci if (frame->len & 1) 32762306a36Sopenharmony_ci frame->data[frame->len - 1] = in_8(data); 32862306a36Sopenharmony_ci } 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci out_8(®s->canrflg, MSCAN_RXF); 33162306a36Sopenharmony_ci} 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_cistatic void mscan_get_err_frame(struct net_device *dev, struct can_frame *frame, 33462306a36Sopenharmony_ci u8 canrflg) 33562306a36Sopenharmony_ci{ 33662306a36Sopenharmony_ci struct mscan_priv *priv = netdev_priv(dev); 33762306a36Sopenharmony_ci struct mscan_regs __iomem *regs = priv->reg_base; 33862306a36Sopenharmony_ci struct net_device_stats *stats = &dev->stats; 33962306a36Sopenharmony_ci enum can_state new_state; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci netdev_dbg(dev, "error interrupt (canrflg=%#x)\n", canrflg); 34262306a36Sopenharmony_ci frame->can_id = CAN_ERR_FLAG; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci if (canrflg & MSCAN_OVRIF) { 34562306a36Sopenharmony_ci frame->can_id |= CAN_ERR_CRTL; 34662306a36Sopenharmony_ci frame->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; 34762306a36Sopenharmony_ci stats->rx_over_errors++; 34862306a36Sopenharmony_ci stats->rx_errors++; 34962306a36Sopenharmony_ci } else { 35062306a36Sopenharmony_ci frame->data[1] = 0; 35162306a36Sopenharmony_ci } 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci new_state = get_new_state(dev, canrflg); 35462306a36Sopenharmony_ci if (new_state != priv->can.state) { 35562306a36Sopenharmony_ci can_change_state(dev, frame, 35662306a36Sopenharmony_ci state_map[MSCAN_STATE_TX(canrflg)], 35762306a36Sopenharmony_ci state_map[MSCAN_STATE_RX(canrflg)]); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci if (priv->can.state == CAN_STATE_BUS_OFF) { 36062306a36Sopenharmony_ci /* 36162306a36Sopenharmony_ci * The MSCAN on the MPC5200 does recover from bus-off 36262306a36Sopenharmony_ci * automatically. To avoid that we stop the chip doing 36362306a36Sopenharmony_ci * a light-weight stop (we are in irq-context). 36462306a36Sopenharmony_ci */ 36562306a36Sopenharmony_ci if (priv->type != MSCAN_TYPE_MPC5121) { 36662306a36Sopenharmony_ci out_8(®s->cantier, 0); 36762306a36Sopenharmony_ci out_8(®s->canrier, 0); 36862306a36Sopenharmony_ci setbits8(®s->canctl0, 36962306a36Sopenharmony_ci MSCAN_SLPRQ | MSCAN_INITRQ); 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci can_bus_off(dev); 37262306a36Sopenharmony_ci } 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci priv->shadow_statflg = canrflg & MSCAN_STAT_MSK; 37562306a36Sopenharmony_ci frame->len = CAN_ERR_DLC; 37662306a36Sopenharmony_ci out_8(®s->canrflg, MSCAN_ERR_IF); 37762306a36Sopenharmony_ci} 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_cistatic int mscan_rx_poll(struct napi_struct *napi, int quota) 38062306a36Sopenharmony_ci{ 38162306a36Sopenharmony_ci struct mscan_priv *priv = container_of(napi, struct mscan_priv, napi); 38262306a36Sopenharmony_ci struct net_device *dev = napi->dev; 38362306a36Sopenharmony_ci struct mscan_regs __iomem *regs = priv->reg_base; 38462306a36Sopenharmony_ci struct net_device_stats *stats = &dev->stats; 38562306a36Sopenharmony_ci int work_done = 0; 38662306a36Sopenharmony_ci struct sk_buff *skb; 38762306a36Sopenharmony_ci struct can_frame *frame; 38862306a36Sopenharmony_ci u8 canrflg; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci while (work_done < quota) { 39162306a36Sopenharmony_ci canrflg = in_8(®s->canrflg); 39262306a36Sopenharmony_ci if (!(canrflg & (MSCAN_RXF | MSCAN_ERR_IF))) 39362306a36Sopenharmony_ci break; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci skb = alloc_can_skb(dev, &frame); 39662306a36Sopenharmony_ci if (!skb) { 39762306a36Sopenharmony_ci if (printk_ratelimit()) 39862306a36Sopenharmony_ci netdev_notice(dev, "packet dropped\n"); 39962306a36Sopenharmony_ci stats->rx_dropped++; 40062306a36Sopenharmony_ci out_8(®s->canrflg, canrflg); 40162306a36Sopenharmony_ci continue; 40262306a36Sopenharmony_ci } 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci if (canrflg & MSCAN_RXF) { 40562306a36Sopenharmony_ci mscan_get_rx_frame(dev, frame); 40662306a36Sopenharmony_ci stats->rx_packets++; 40762306a36Sopenharmony_ci if (!(frame->can_id & CAN_RTR_FLAG)) 40862306a36Sopenharmony_ci stats->rx_bytes += frame->len; 40962306a36Sopenharmony_ci } else if (canrflg & MSCAN_ERR_IF) { 41062306a36Sopenharmony_ci mscan_get_err_frame(dev, frame, canrflg); 41162306a36Sopenharmony_ci } 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci work_done++; 41462306a36Sopenharmony_ci netif_receive_skb(skb); 41562306a36Sopenharmony_ci } 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci if (work_done < quota) { 41862306a36Sopenharmony_ci if (likely(napi_complete_done(&priv->napi, work_done))) { 41962306a36Sopenharmony_ci clear_bit(F_RX_PROGRESS, &priv->flags); 42062306a36Sopenharmony_ci if (priv->can.state < CAN_STATE_BUS_OFF) 42162306a36Sopenharmony_ci out_8(®s->canrier, priv->shadow_canrier); 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci } 42462306a36Sopenharmony_ci return work_done; 42562306a36Sopenharmony_ci} 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_cistatic irqreturn_t mscan_isr(int irq, void *dev_id) 42862306a36Sopenharmony_ci{ 42962306a36Sopenharmony_ci struct net_device *dev = (struct net_device *)dev_id; 43062306a36Sopenharmony_ci struct mscan_priv *priv = netdev_priv(dev); 43162306a36Sopenharmony_ci struct mscan_regs __iomem *regs = priv->reg_base; 43262306a36Sopenharmony_ci struct net_device_stats *stats = &dev->stats; 43362306a36Sopenharmony_ci u8 cantier, cantflg, canrflg; 43462306a36Sopenharmony_ci irqreturn_t ret = IRQ_NONE; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci cantier = in_8(®s->cantier) & MSCAN_TXE; 43762306a36Sopenharmony_ci cantflg = in_8(®s->cantflg) & cantier; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci if (cantier && cantflg) { 44062306a36Sopenharmony_ci struct list_head *tmp, *pos; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci list_for_each_safe(pos, tmp, &priv->tx_head) { 44362306a36Sopenharmony_ci struct tx_queue_entry *entry = 44462306a36Sopenharmony_ci list_entry(pos, struct tx_queue_entry, list); 44562306a36Sopenharmony_ci u8 mask = entry->mask; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci if (!(cantflg & mask)) 44862306a36Sopenharmony_ci continue; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci out_8(®s->cantbsel, mask); 45162306a36Sopenharmony_ci stats->tx_bytes += can_get_echo_skb(dev, entry->id, 45262306a36Sopenharmony_ci NULL); 45362306a36Sopenharmony_ci stats->tx_packets++; 45462306a36Sopenharmony_ci priv->tx_active &= ~mask; 45562306a36Sopenharmony_ci list_del(pos); 45662306a36Sopenharmony_ci } 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci if (list_empty(&priv->tx_head)) { 45962306a36Sopenharmony_ci clear_bit(F_TX_WAIT_ALL, &priv->flags); 46062306a36Sopenharmony_ci clear_bit(F_TX_PROGRESS, &priv->flags); 46162306a36Sopenharmony_ci priv->cur_pri = 0; 46262306a36Sopenharmony_ci } else { 46362306a36Sopenharmony_ci netif_trans_update(dev); 46462306a36Sopenharmony_ci } 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci if (!test_bit(F_TX_WAIT_ALL, &priv->flags)) 46762306a36Sopenharmony_ci netif_wake_queue(dev); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci out_8(®s->cantier, priv->tx_active); 47062306a36Sopenharmony_ci ret = IRQ_HANDLED; 47162306a36Sopenharmony_ci } 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci canrflg = in_8(®s->canrflg); 47462306a36Sopenharmony_ci if ((canrflg & ~MSCAN_STAT_MSK) && 47562306a36Sopenharmony_ci !test_and_set_bit(F_RX_PROGRESS, &priv->flags)) { 47662306a36Sopenharmony_ci if (canrflg & ~MSCAN_STAT_MSK) { 47762306a36Sopenharmony_ci priv->shadow_canrier = in_8(®s->canrier); 47862306a36Sopenharmony_ci out_8(®s->canrier, 0); 47962306a36Sopenharmony_ci napi_schedule(&priv->napi); 48062306a36Sopenharmony_ci ret = IRQ_HANDLED; 48162306a36Sopenharmony_ci } else { 48262306a36Sopenharmony_ci clear_bit(F_RX_PROGRESS, &priv->flags); 48362306a36Sopenharmony_ci } 48462306a36Sopenharmony_ci } 48562306a36Sopenharmony_ci return ret; 48662306a36Sopenharmony_ci} 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_cistatic int mscan_do_set_mode(struct net_device *dev, enum can_mode mode) 48962306a36Sopenharmony_ci{ 49062306a36Sopenharmony_ci int ret = 0; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci switch (mode) { 49362306a36Sopenharmony_ci case CAN_MODE_START: 49462306a36Sopenharmony_ci ret = mscan_restart(dev); 49562306a36Sopenharmony_ci if (ret) 49662306a36Sopenharmony_ci break; 49762306a36Sopenharmony_ci if (netif_queue_stopped(dev)) 49862306a36Sopenharmony_ci netif_wake_queue(dev); 49962306a36Sopenharmony_ci break; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci default: 50262306a36Sopenharmony_ci ret = -EOPNOTSUPP; 50362306a36Sopenharmony_ci break; 50462306a36Sopenharmony_ci } 50562306a36Sopenharmony_ci return ret; 50662306a36Sopenharmony_ci} 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_cistatic int mscan_do_set_bittiming(struct net_device *dev) 50962306a36Sopenharmony_ci{ 51062306a36Sopenharmony_ci struct mscan_priv *priv = netdev_priv(dev); 51162306a36Sopenharmony_ci struct mscan_regs __iomem *regs = priv->reg_base; 51262306a36Sopenharmony_ci struct can_bittiming *bt = &priv->can.bittiming; 51362306a36Sopenharmony_ci u8 btr0, btr1; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci btr0 = BTR0_SET_BRP(bt->brp) | BTR0_SET_SJW(bt->sjw); 51662306a36Sopenharmony_ci btr1 = (BTR1_SET_TSEG1(bt->prop_seg + bt->phase_seg1) | 51762306a36Sopenharmony_ci BTR1_SET_TSEG2(bt->phase_seg2) | 51862306a36Sopenharmony_ci BTR1_SET_SAM(priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)); 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci netdev_info(dev, "setting BTR0=0x%02x BTR1=0x%02x\n", btr0, btr1); 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci out_8(®s->canbtr0, btr0); 52362306a36Sopenharmony_ci out_8(®s->canbtr1, btr1); 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci return 0; 52662306a36Sopenharmony_ci} 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_cistatic int mscan_get_berr_counter(const struct net_device *dev, 52962306a36Sopenharmony_ci struct can_berr_counter *bec) 53062306a36Sopenharmony_ci{ 53162306a36Sopenharmony_ci struct mscan_priv *priv = netdev_priv(dev); 53262306a36Sopenharmony_ci struct mscan_regs __iomem *regs = priv->reg_base; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci bec->txerr = in_8(®s->cantxerr); 53562306a36Sopenharmony_ci bec->rxerr = in_8(®s->canrxerr); 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci return 0; 53862306a36Sopenharmony_ci} 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_cistatic int mscan_open(struct net_device *dev) 54162306a36Sopenharmony_ci{ 54262306a36Sopenharmony_ci int ret; 54362306a36Sopenharmony_ci struct mscan_priv *priv = netdev_priv(dev); 54462306a36Sopenharmony_ci struct mscan_regs __iomem *regs = priv->reg_base; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci ret = clk_prepare_enable(priv->clk_ipg); 54762306a36Sopenharmony_ci if (ret) 54862306a36Sopenharmony_ci goto exit_retcode; 54962306a36Sopenharmony_ci ret = clk_prepare_enable(priv->clk_can); 55062306a36Sopenharmony_ci if (ret) 55162306a36Sopenharmony_ci goto exit_dis_ipg_clock; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci /* common open */ 55462306a36Sopenharmony_ci ret = open_candev(dev); 55562306a36Sopenharmony_ci if (ret) 55662306a36Sopenharmony_ci goto exit_dis_can_clock; 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci napi_enable(&priv->napi); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci ret = request_irq(dev->irq, mscan_isr, 0, dev->name, dev); 56162306a36Sopenharmony_ci if (ret < 0) { 56262306a36Sopenharmony_ci netdev_err(dev, "failed to attach interrupt\n"); 56362306a36Sopenharmony_ci goto exit_napi_disable; 56462306a36Sopenharmony_ci } 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) 56762306a36Sopenharmony_ci setbits8(®s->canctl1, MSCAN_LISTEN); 56862306a36Sopenharmony_ci else 56962306a36Sopenharmony_ci clrbits8(®s->canctl1, MSCAN_LISTEN); 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci ret = mscan_start(dev); 57262306a36Sopenharmony_ci if (ret) 57362306a36Sopenharmony_ci goto exit_free_irq; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci netif_start_queue(dev); 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci return 0; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ciexit_free_irq: 58062306a36Sopenharmony_ci free_irq(dev->irq, dev); 58162306a36Sopenharmony_ciexit_napi_disable: 58262306a36Sopenharmony_ci napi_disable(&priv->napi); 58362306a36Sopenharmony_ci close_candev(dev); 58462306a36Sopenharmony_ciexit_dis_can_clock: 58562306a36Sopenharmony_ci clk_disable_unprepare(priv->clk_can); 58662306a36Sopenharmony_ciexit_dis_ipg_clock: 58762306a36Sopenharmony_ci clk_disable_unprepare(priv->clk_ipg); 58862306a36Sopenharmony_ciexit_retcode: 58962306a36Sopenharmony_ci return ret; 59062306a36Sopenharmony_ci} 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_cistatic int mscan_close(struct net_device *dev) 59362306a36Sopenharmony_ci{ 59462306a36Sopenharmony_ci struct mscan_priv *priv = netdev_priv(dev); 59562306a36Sopenharmony_ci struct mscan_regs __iomem *regs = priv->reg_base; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci netif_stop_queue(dev); 59862306a36Sopenharmony_ci napi_disable(&priv->napi); 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci out_8(®s->cantier, 0); 60162306a36Sopenharmony_ci out_8(®s->canrier, 0); 60262306a36Sopenharmony_ci mscan_set_mode(dev, MSCAN_INIT_MODE); 60362306a36Sopenharmony_ci close_candev(dev); 60462306a36Sopenharmony_ci free_irq(dev->irq, dev); 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci clk_disable_unprepare(priv->clk_can); 60762306a36Sopenharmony_ci clk_disable_unprepare(priv->clk_ipg); 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci return 0; 61062306a36Sopenharmony_ci} 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_cistatic const struct net_device_ops mscan_netdev_ops = { 61362306a36Sopenharmony_ci .ndo_open = mscan_open, 61462306a36Sopenharmony_ci .ndo_stop = mscan_close, 61562306a36Sopenharmony_ci .ndo_start_xmit = mscan_start_xmit, 61662306a36Sopenharmony_ci .ndo_change_mtu = can_change_mtu, 61762306a36Sopenharmony_ci}; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_cistatic const struct ethtool_ops mscan_ethtool_ops = { 62062306a36Sopenharmony_ci .get_ts_info = ethtool_op_get_ts_info, 62162306a36Sopenharmony_ci}; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ciint register_mscandev(struct net_device *dev, int mscan_clksrc) 62462306a36Sopenharmony_ci{ 62562306a36Sopenharmony_ci struct mscan_priv *priv = netdev_priv(dev); 62662306a36Sopenharmony_ci struct mscan_regs __iomem *regs = priv->reg_base; 62762306a36Sopenharmony_ci u8 ctl1; 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci ctl1 = in_8(®s->canctl1); 63062306a36Sopenharmony_ci if (mscan_clksrc) 63162306a36Sopenharmony_ci ctl1 |= MSCAN_CLKSRC; 63262306a36Sopenharmony_ci else 63362306a36Sopenharmony_ci ctl1 &= ~MSCAN_CLKSRC; 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci if (priv->type == MSCAN_TYPE_MPC5121) { 63662306a36Sopenharmony_ci priv->can.do_get_berr_counter = mscan_get_berr_counter; 63762306a36Sopenharmony_ci ctl1 |= MSCAN_BORM; /* bus-off recovery upon request */ 63862306a36Sopenharmony_ci } 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci ctl1 |= MSCAN_CANE; 64162306a36Sopenharmony_ci out_8(®s->canctl1, ctl1); 64262306a36Sopenharmony_ci udelay(100); 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci /* acceptance mask/acceptance code (accept everything) */ 64562306a36Sopenharmony_ci out_be16(®s->canidar1_0, 0); 64662306a36Sopenharmony_ci out_be16(®s->canidar3_2, 0); 64762306a36Sopenharmony_ci out_be16(®s->canidar5_4, 0); 64862306a36Sopenharmony_ci out_be16(®s->canidar7_6, 0); 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci out_be16(®s->canidmr1_0, 0xffff); 65162306a36Sopenharmony_ci out_be16(®s->canidmr3_2, 0xffff); 65262306a36Sopenharmony_ci out_be16(®s->canidmr5_4, 0xffff); 65362306a36Sopenharmony_ci out_be16(®s->canidmr7_6, 0xffff); 65462306a36Sopenharmony_ci /* Two 32 bit Acceptance Filters */ 65562306a36Sopenharmony_ci out_8(®s->canidac, MSCAN_AF_32BIT); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci mscan_set_mode(dev, MSCAN_INIT_MODE); 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci return register_candev(dev); 66062306a36Sopenharmony_ci} 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_civoid unregister_mscandev(struct net_device *dev) 66362306a36Sopenharmony_ci{ 66462306a36Sopenharmony_ci struct mscan_priv *priv = netdev_priv(dev); 66562306a36Sopenharmony_ci struct mscan_regs __iomem *regs = priv->reg_base; 66662306a36Sopenharmony_ci mscan_set_mode(dev, MSCAN_INIT_MODE); 66762306a36Sopenharmony_ci clrbits8(®s->canctl1, MSCAN_CANE); 66862306a36Sopenharmony_ci unregister_candev(dev); 66962306a36Sopenharmony_ci} 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_cistruct net_device *alloc_mscandev(void) 67262306a36Sopenharmony_ci{ 67362306a36Sopenharmony_ci struct net_device *dev; 67462306a36Sopenharmony_ci struct mscan_priv *priv; 67562306a36Sopenharmony_ci int i; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci dev = alloc_candev(sizeof(struct mscan_priv), MSCAN_ECHO_SKB_MAX); 67862306a36Sopenharmony_ci if (!dev) 67962306a36Sopenharmony_ci return NULL; 68062306a36Sopenharmony_ci priv = netdev_priv(dev); 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci dev->netdev_ops = &mscan_netdev_ops; 68362306a36Sopenharmony_ci dev->ethtool_ops = &mscan_ethtool_ops; 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci dev->flags |= IFF_ECHO; /* we support local echo */ 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci netif_napi_add_weight(dev, &priv->napi, mscan_rx_poll, 8); 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci priv->can.bittiming_const = &mscan_bittiming_const; 69062306a36Sopenharmony_ci priv->can.do_set_bittiming = mscan_do_set_bittiming; 69162306a36Sopenharmony_ci priv->can.do_set_mode = mscan_do_set_mode; 69262306a36Sopenharmony_ci priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES | 69362306a36Sopenharmony_ci CAN_CTRLMODE_LISTENONLY; 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci for (i = 0; i < TX_QUEUE_SIZE; i++) { 69662306a36Sopenharmony_ci priv->tx_queue[i].id = i; 69762306a36Sopenharmony_ci priv->tx_queue[i].mask = 1 << i; 69862306a36Sopenharmony_ci } 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci return dev; 70162306a36Sopenharmony_ci} 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ciMODULE_AUTHOR("Andrey Volkov <avolkov@varma-el.com>"); 70462306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 70562306a36Sopenharmony_ciMODULE_DESCRIPTION("CAN port driver for a MSCAN based chips"); 706