#include <linux/if_arp.h>
#include <linux/if_ether.h>
#include <linux/list.h>
-#include <linux/can.h>
-#include <linux/can/dev.h>
-#include <linux/can/error.h>
+#include <socketcan/can.h>
+#include <socketcan/can/dev.h>
+#include <socketcan/can/error.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
#include <linux/io.h>
#else
#include "mscan.h"
-#include <linux/can/version.h> /* for RCSID. Removed by mkpatch script */
+#include <socketcan/can/version.h> /* for RCSID. Removed by mkpatch script */
RCSID("$Id$");
#define MSCAN_NORMAL_MODE 0
#define MSCAN_INIT_MODE (MSCAN_INITRQ | MSCAN_SLPRQ)
#define MSCAN_POWEROFF_MODE (MSCAN_CSWAI | MSCAN_SLPRQ)
#define MSCAN_SET_MODE_RETRIES 255
+#define MSCAN_ECHO_SKB_MAX 3
#define BTR0_BRP_MASK 0x3f
#define BTR0_SJW_SHIFT 6
#define BTR1_SET_TSEG1(tseg1) (((tseg1) - 1) & BTR1_TSEG1_MASK)
#define BTR1_SET_TSEG2(tseg2) ((((tseg2) - 1) << BTR1_TSEG2_SHIFT) & \
BTR1_TSEG2_MASK)
-#define BTR1_SET_SAM(sam) (((sam) & 1) << BTR1_SAM_SHIFT)
+#define BTR1_SET_SAM(sam) ((sam) ? 1 << BTR1_SAM_SHIFT : 0)
static struct can_bittiming_const mscan_bittiming_const = {
+ .name = "mscan",
.tseg1_min = 4,
.tseg1_max = 16,
.tseg2_min = 2,
struct mscan_priv {
struct can_priv can;
long open_time;
- volatile unsigned long flags;
+ unsigned long flags;
u8 shadow_statflg;
u8 shadow_canrier;
u8 cur_pri;
+ u8 prev_buf_id;
u8 tx_active;
struct list_head tx_head;
#define F_TX_WAIT_ALL 2
static enum can_state state_map[] = {
- CAN_STATE_ACTIVE,
- CAN_STATE_BUS_WARNING,
- CAN_STATE_BUS_PASSIVE,
+ CAN_STATE_ERROR_ACTIVE,
+ CAN_STATE_ERROR_WARNING,
+ CAN_STATE_ERROR_PASSIVE,
CAN_STATE_BUS_OFF
};
if (mode != MSCAN_NORMAL_MODE) {
if (priv->tx_active) {
- /* Abort transfers before going to sleep */
- out_8(®s->cantier, 0);
+ /* Abort transfers before going to sleep */#
out_8(®s->cantarq, priv->tx_active);
- out_8(®s->cantier, priv->tx_active);
+ /* Suppress TX done interrupts */
+ out_8(®s->cantier, 0);
}
canctl1 = in_8(®s->canctl1);
if (i >= MSCAN_SET_MODE_RETRIES)
ret = -ENODEV;
else
- priv->can.state = CAN_STATE_ACTIVE;
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
}
}
return ret;
out_8(®s->canrier, 0);
INIT_LIST_HEAD(&priv->tx_head);
+ priv->prev_buf_id = 0;
priv->cur_pri = 0;
priv->tx_active = 0;
priv->shadow_canrier = 0;
return 0;
}
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
static int mscan_start_xmit(struct sk_buff *skb, struct net_device *dev)
+#else
+static netdev_tx_t mscan_start_xmit(struct sk_buff *skb, struct net_device *dev)
+#endif
{
struct can_frame *frame = (struct can_frame *)skb->data;
struct mscan_regs *regs = (struct mscan_regs *)dev->base_addr;
case 1:
/* if buf_id < 3, then current frame will be send out of order,
since buffer with lower id have higher priority (hell..) */
- if (buf_id < 3)
- priv->cur_pri++;
- if (priv->cur_pri == 0xff)
- set_bit(F_TX_WAIT_ALL, &priv->flags);
netif_stop_queue(dev);
case 2:
+ if (buf_id < priv->prev_buf_id) {
+ priv->cur_pri++;
+ if (priv->cur_pri == 0xff) {
+ set_bit(F_TX_WAIT_ALL, &priv->flags);
+ netif_stop_queue(dev);
+ }
+ }
set_bit(F_TX_PROGRESS, &priv->flags);
+ break;
}
+ priv->prev_buf_id = buf_id;
out_8(®s->cantbsel, i);
rtr = frame->can_id & CAN_RTR_FLAG;
out_be16(®s->tx.idr1_0, can_id);
if (!rtr) {
- volatile void __iomem *data = ®s->tx.dsr1_0;
+ void __iomem *data = ®s->tx.dsr1_0;
u16 *payload = (u16 *) frame->data;
/*Its safe to write into dsr[dlc+1] */
for (i = 0; i < (frame->can_dlc + 1) / 2; i++) {
MSCAN_STATE_TX(canrflg))];
if (priv->can.state < state)
ret = 1;
- if (state == CAN_STATE_BUS_OFF)
- can_bus_off(dev);
priv->can.state = state;
return ret;
}
while (npackets < quota && ((canrflg = in_8(®s->canrflg)) &
(MSCAN_RXF | MSCAN_ERR_IF))) {
- skb = dev_alloc_skb(sizeof(struct can_frame));
+ skb = alloc_can_skb(dev, &frame);
if (!skb) {
if (printk_ratelimit())
dev_notice(ND2D(dev), "packet dropped\n");
continue;
}
- frame = (struct can_frame *)skb_put(skb, sizeof(*frame));
- memset(frame, 0, sizeof(*frame));
-
if (canrflg & MSCAN_RXF) {
can_id = in_be16(®s->rx.idr1_0);
if (can_id & (1 << 3)) {
frame->can_dlc = in_8(®s->rx.dlr) & 0xf;
if (!(frame->can_id & CAN_RTR_FLAG)) {
- volatile void __iomem *data = ®s->rx.dsr1_0;
+ void __iomem *data = ®s->rx.dsr1_0;
u16 *payload = (u16 *) frame->data;
for (i = 0; i < (frame->can_dlc + 1) / 2; i++) {
*payload++ = in_be16(data);
}
out_8(®s->canrflg, MSCAN_RXF);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
dev->last_rx = jiffies;
+#endif
stats->rx_packets++;
stats->rx_bytes += frame->can_dlc;
} else if (canrflg & MSCAN_ERR_IF) {
frame->can_id |= CAN_ERR_CRTL;
frame->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
stats->rx_over_errors++;
+ stats->rx_errors++;
} else
frame->data[1] = 0;
if (check_set_state(dev, canrflg)) {
- frame->can_id |= CAN_ERR_CRTL;
switch (priv->can.state) {
- case CAN_STATE_BUS_WARNING:
+ case CAN_STATE_ERROR_WARNING:
+ frame->can_id |= CAN_ERR_CRTL;
+ priv->can.can_stats.error_warning++;
if ((priv->shadow_statflg &
MSCAN_RSTAT_MSK) <
(canrflg & MSCAN_RSTAT_MSK))
frame->data[1] |=
- CAN_ERR_CRTL_RX_WARNING;
+ CAN_ERR_CRTL_RX_WARNING;
if ((priv->shadow_statflg &
MSCAN_TSTAT_MSK) <
frame->data[1] |=
CAN_ERR_CRTL_TX_WARNING;
break;
- case CAN_STATE_BUS_PASSIVE:
+ case CAN_STATE_ERROR_PASSIVE:
+ frame->can_id |= CAN_ERR_CRTL;
+ priv->can.can_stats.error_passive++;
frame->data[1] |=
- CAN_ERR_CRTL_RX_PASSIVE;
+ CAN_ERR_CRTL_RX_PASSIVE;
break;
case CAN_STATE_BUS_OFF:
frame->can_id |= CAN_ERR_BUSOFF;
- frame->can_id &= ~CAN_ERR_CRTL;
+ can_bus_off(dev);
break;
default:
break;
}
npackets++;
- skb->dev = dev;
- skb->protocol = __constant_htons(ETH_P_CAN);
- skb->ip_summed = CHECKSUM_UNNECESSARY;
netif_receive_skb(skb);
}
return ret;
}
-
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
static irqreturn_t mscan_isr(int irq, void *dev_id, struct pt_regs *r)
#else
struct mscan_priv *priv = netdev_priv(dev);
struct mscan_regs *regs = (struct mscan_regs *)dev->base_addr;
- /* determine and set bittime */
- ret = can_set_bittiming(dev);
+ /* common open */
+ ret = open_candev(dev);
if (ret)
return ret;
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,23)
napi_enable(&priv->napi);
#endif
- ret = request_irq(dev->irq, mscan_isr, 0, dev->name, dev);
+ ret = request_irq(dev->irq, mscan_isr, 0, dev->name, dev);
if (ret < 0) {
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,23)
napi_disable(&priv->napi);
struct mscan_regs *regs = (struct mscan_regs *)dev->base_addr;
struct mscan_priv *priv = netdev_priv(dev);
+ netif_stop_queue(dev);
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,23)
napi_disable(&priv->napi);
#endif
out_8(®s->cantier, 0);
out_8(®s->canrier, 0);
- free_irq(dev->irq, dev);
mscan_set_mode(dev, MSCAN_INIT_MODE);
- can_close_cleanup(dev);
- netif_stop_queue(dev);
+ close_candev(dev);
+ free_irq(dev->irq, dev);
priv->open_time = 0;
return 0;
return register_candev(dev);
}
-EXPORT_SYMBOL(register_mscandev);
+EXPORT_SYMBOL_GPL(register_mscandev);
void unregister_mscandev(struct net_device *dev)
{
out_8(®s->canctl1, in_8(®s->canctl1) & ~MSCAN_CANE);
unregister_candev(dev);
}
-EXPORT_SYMBOL(unregister_mscandev);
+EXPORT_SYMBOL_GPL(unregister_mscandev);
struct net_device *alloc_mscandev(void)
{
struct mscan_priv *priv;
int i;
- dev = alloc_candev(sizeof(struct mscan_priv));
+ dev = alloc_candev(sizeof(struct mscan_priv), MSCAN_ECHO_SKB_MAX);
if (!dev)
return NULL;
priv = netdev_priv(dev);
return dev;
}
-EXPORT_SYMBOL(alloc_mscandev);
+EXPORT_SYMBOL_GPL(alloc_mscandev);
MODULE_AUTHOR("Andrey Volkov <avolkov@varma-el.com>");
MODULE_LICENSE("GPL v2");