Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 602de7ea authored by David S. Miller's avatar David S. Miller
Browse files

Merge tag 'linux-can-next-for-3.19-20141207' of git://gitorious.org/linux-can/linux-can-next



Marc Kleine-Budde says:

====================
pull-request: can-next 2014-12-07

this is a pull request of 8 patches for net-next/master.

Andri Yngvason contributes 4 patches in which the CAN state change
handling is consolidated and unified among the sja1000, mscan and
flexcan driver. The three patches by Jeremiah Mahler fix spelling
mistakes and eliminate the banner[] variable in various parts. And a
patch by me that switches on sparse endianess checking by default.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 605ad7f1 71a3aedc
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -29,4 +29,5 @@ obj-$(CONFIG_CAN_GRCAN) += grcan.o
obj-$(CONFIG_CAN_RCAR)		+= rcar_can.o
obj-$(CONFIG_CAN_XILINXCAN)	+= xilinx_can.o

subdir-ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
subdir-ccflags-y += -D__CHECK_ENDIAN__
subdir-ccflags-$(CONFIG_CAN_DEBUG_DEVICES) += -DDEBUG
+1 −1
Original line number Diff line number Diff line
@@ -60,7 +60,7 @@ MODULE_DESCRIPTION(KBUILD_MODNAME "CAN netdevice driver");
 *
 * The message objects 1..14 can be used for TX and RX while the message
 * objects 15 is optimized for RX. It has a shadow register for reliable
 * data receiption under heavy bus load. Therefore it makes sense to use
 * data reception under heavy bus load. Therefore it makes sense to use
 * this message object for the needed use case. The frame type (EFF/SFF)
 * for the message object 15 can be defined via kernel module parameter
 * "msgobj15_eff". If not equal 0, it will receive 29-bit EFF frames,
+78 −0
Original line number Diff line number Diff line
@@ -273,6 +273,84 @@ static int can_get_bittiming(struct net_device *dev, struct can_bittiming *bt,
	return err;
}

static void can_update_state_error_stats(struct net_device *dev,
					 enum can_state new_state)
{
	struct can_priv *priv = netdev_priv(dev);

	if (new_state <= priv->state)
		return;

	switch (new_state) {
	case CAN_STATE_ERROR_WARNING:
		priv->can_stats.error_warning++;
		break;
	case CAN_STATE_ERROR_PASSIVE:
		priv->can_stats.error_passive++;
		break;
	case CAN_STATE_BUS_OFF:
	default:
		break;
	};
}

static int can_tx_state_to_frame(struct net_device *dev, enum can_state state)
{
	switch (state) {
	case CAN_STATE_ERROR_ACTIVE:
		return CAN_ERR_CRTL_ACTIVE;
	case CAN_STATE_ERROR_WARNING:
		return CAN_ERR_CRTL_TX_WARNING;
	case CAN_STATE_ERROR_PASSIVE:
		return CAN_ERR_CRTL_TX_PASSIVE;
	default:
		return 0;
	}
}

static int can_rx_state_to_frame(struct net_device *dev, enum can_state state)
{
	switch (state) {
	case CAN_STATE_ERROR_ACTIVE:
		return CAN_ERR_CRTL_ACTIVE;
	case CAN_STATE_ERROR_WARNING:
		return CAN_ERR_CRTL_RX_WARNING;
	case CAN_STATE_ERROR_PASSIVE:
		return CAN_ERR_CRTL_RX_PASSIVE;
	default:
		return 0;
	}
}

void can_change_state(struct net_device *dev, struct can_frame *cf,
		      enum can_state tx_state, enum can_state rx_state)
{
	struct can_priv *priv = netdev_priv(dev);
	enum can_state new_state = max(tx_state, rx_state);

	if (unlikely(new_state == priv->state)) {
		netdev_warn(dev, "%s: oops, state did not change", __func__);
		return;
	}

	netdev_dbg(dev, "New error state: %d\n", new_state);

	can_update_state_error_stats(dev, new_state);
	priv->state = new_state;

	if (unlikely(new_state == CAN_STATE_BUS_OFF)) {
		cf->can_id |= CAN_ERR_BUSOFF;
		return;
	}

	cf->can_id |= CAN_ERR_CRTL;
	cf->data[1] |= tx_state >= rx_state ?
		       can_tx_state_to_frame(dev, tx_state) : 0;
	cf->data[1] |= tx_state <= rx_state ?
		       can_rx_state_to_frame(dev, rx_state) : 0;
}
EXPORT_SYMBOL_GPL(can_change_state);

/*
 * Local echo of CAN messages
 *
+18 −83
Original line number Diff line number Diff line
@@ -577,98 +577,30 @@ static int flexcan_poll_bus_err(struct net_device *dev, u32 reg_esr)
	return 1;
}

static void do_state(struct net_device *dev,
		     struct can_frame *cf, enum can_state new_state)
{
	struct flexcan_priv *priv = netdev_priv(dev);
	struct can_berr_counter bec;

	__flexcan_get_berr_counter(dev, &bec);

	switch (priv->can.state) {
	case CAN_STATE_ERROR_ACTIVE:
		/*
		 * from: ERROR_ACTIVE
		 * to  : ERROR_WARNING, ERROR_PASSIVE, BUS_OFF
		 * =>  : there was a warning int
		 */
		if (new_state >= CAN_STATE_ERROR_WARNING &&
		    new_state <= CAN_STATE_BUS_OFF) {
			netdev_dbg(dev, "Error Warning IRQ\n");
			priv->can.can_stats.error_warning++;

			cf->can_id |= CAN_ERR_CRTL;
			cf->data[1] = (bec.txerr > bec.rxerr) ?
				CAN_ERR_CRTL_TX_WARNING :
				CAN_ERR_CRTL_RX_WARNING;
		}
	case CAN_STATE_ERROR_WARNING:	/* fallthrough */
		/*
		 * from: ERROR_ACTIVE, ERROR_WARNING
		 * to  : ERROR_PASSIVE, BUS_OFF
		 * =>  : error passive int
		 */
		if (new_state >= CAN_STATE_ERROR_PASSIVE &&
		    new_state <= CAN_STATE_BUS_OFF) {
			netdev_dbg(dev, "Error Passive IRQ\n");
			priv->can.can_stats.error_passive++;

			cf->can_id |= CAN_ERR_CRTL;
			cf->data[1] = (bec.txerr > bec.rxerr) ?
				CAN_ERR_CRTL_TX_PASSIVE :
				CAN_ERR_CRTL_RX_PASSIVE;
		}
		break;
	case CAN_STATE_BUS_OFF:
		netdev_err(dev, "BUG! "
			   "hardware recovered automatically from BUS_OFF\n");
		break;
	default:
		break;
	}

	/* process state changes depending on the new state */
	switch (new_state) {
	case CAN_STATE_ERROR_WARNING:
		netdev_dbg(dev, "Error Warning\n");
		cf->can_id |= CAN_ERR_CRTL;
		cf->data[1] = (bec.txerr > bec.rxerr) ?
			CAN_ERR_CRTL_TX_WARNING :
			CAN_ERR_CRTL_RX_WARNING;
		break;
	case CAN_STATE_ERROR_ACTIVE:
		netdev_dbg(dev, "Error Active\n");
		cf->can_id |= CAN_ERR_PROT;
		cf->data[2] = CAN_ERR_PROT_ACTIVE;
		break;
	case CAN_STATE_BUS_OFF:
		cf->can_id |= CAN_ERR_BUSOFF;
		can_bus_off(dev);
		break;
	default:
		break;
	}
}

static int flexcan_poll_state(struct net_device *dev, u32 reg_esr)
{
	struct flexcan_priv *priv = netdev_priv(dev);
	struct sk_buff *skb;
	struct can_frame *cf;
	enum can_state new_state;
	enum can_state new_state = 0, rx_state = 0, tx_state = 0;
	int flt;
	struct can_berr_counter bec;

	flt = reg_esr & FLEXCAN_ESR_FLT_CONF_MASK;
	if (likely(flt == FLEXCAN_ESR_FLT_CONF_ACTIVE)) {
		if (likely(!(reg_esr & (FLEXCAN_ESR_TX_WRN |
					FLEXCAN_ESR_RX_WRN))))
			new_state = CAN_STATE_ERROR_ACTIVE;
		else
			new_state = CAN_STATE_ERROR_WARNING;
	} else if (unlikely(flt == FLEXCAN_ESR_FLT_CONF_PASSIVE))
		tx_state = unlikely(reg_esr & FLEXCAN_ESR_TX_WRN) ?
			   CAN_STATE_ERROR_WARNING : CAN_STATE_ERROR_ACTIVE;
		rx_state = unlikely(reg_esr & FLEXCAN_ESR_RX_WRN) ?
			   CAN_STATE_ERROR_WARNING : CAN_STATE_ERROR_ACTIVE;
		new_state = max(tx_state, rx_state);
	} else if (unlikely(flt == FLEXCAN_ESR_FLT_CONF_PASSIVE)) {
		__flexcan_get_berr_counter(dev, &bec);
		new_state = CAN_STATE_ERROR_PASSIVE;
	else
		rx_state = bec.rxerr >= bec.txerr ? new_state : 0;
		tx_state = bec.rxerr <= bec.txerr ? new_state : 0;
	} else {
		new_state = CAN_STATE_BUS_OFF;
	}

	/* state hasn't changed */
	if (likely(new_state == priv->can.state))
@@ -678,8 +610,11 @@ static int flexcan_poll_state(struct net_device *dev, u32 reg_esr)
	if (unlikely(!skb))
		return 0;

	do_state(dev, cf, new_state);
	priv->can.state = new_state;
	can_change_state(dev, cf, tx_state, rx_state);

	if (unlikely(new_state == CAN_STATE_BUS_OFF))
		can_bus_off(dev);

	netif_receive_skb(skb);

	dev->stats.rx_packets++;
+14 −34
Original line number Diff line number Diff line
@@ -289,18 +289,15 @@ static netdev_tx_t mscan_start_xmit(struct sk_buff *skb, struct net_device *dev)
	return NETDEV_TX_OK;
}

/* This function returns the old state to see where we came from */
static enum can_state check_set_state(struct net_device *dev, u8 canrflg)
static enum can_state get_new_state(struct net_device *dev, u8 canrflg)
{
	struct mscan_priv *priv = netdev_priv(dev);
	enum can_state state, old_state = priv->can.state;

	if (canrflg & MSCAN_CSCIF && old_state <= CAN_STATE_BUS_OFF) {
		state = state_map[max(MSCAN_STATE_RX(canrflg),
	if (unlikely(canrflg & MSCAN_CSCIF))
		return state_map[max(MSCAN_STATE_RX(canrflg),
				 MSCAN_STATE_TX(canrflg))];
		priv->can.state = state;
	}
	return old_state;

	return priv->can.state;
}

static void mscan_get_rx_frame(struct net_device *dev, struct can_frame *frame)
@@ -349,7 +346,7 @@ static void mscan_get_err_frame(struct net_device *dev, struct can_frame *frame,
	struct mscan_priv *priv = netdev_priv(dev);
	struct mscan_regs __iomem *regs = priv->reg_base;
	struct net_device_stats *stats = &dev->stats;
	enum can_state old_state;
	enum can_state new_state;

	netdev_dbg(dev, "error interrupt (canrflg=%#x)\n", canrflg);
	frame->can_id = CAN_ERR_FLAG;
@@ -363,27 +360,13 @@ static void mscan_get_err_frame(struct net_device *dev, struct can_frame *frame,
		frame->data[1] = 0;
	}

	old_state = check_set_state(dev, canrflg);
	/* State changed */
	if (old_state != priv->can.state) {
		switch (priv->can.state) {
		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;
			if ((priv->shadow_statflg & MSCAN_TSTAT_MSK) <
			    (canrflg & MSCAN_TSTAT_MSK))
				frame->data[1] |= CAN_ERR_CRTL_TX_WARNING;
			break;
		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;
			break;
		case CAN_STATE_BUS_OFF:
			frame->can_id |= CAN_ERR_BUSOFF;
	new_state = get_new_state(dev, canrflg);
	if (new_state != priv->can.state) {
		can_change_state(dev, frame,
				 state_map[MSCAN_STATE_TX(canrflg)],
				 state_map[MSCAN_STATE_RX(canrflg)]);

		if (priv->can.state == CAN_STATE_BUS_OFF) {
			/*
			 * The MSCAN on the MPC5200 does recover from bus-off
			 * automatically. To avoid that we stop the chip doing
@@ -396,9 +379,6 @@ static void mscan_get_err_frame(struct net_device *dev, struct can_frame *frame,
					 MSCAN_SLPRQ | MSCAN_INITRQ);
			}
			can_bus_off(dev);
			break;
		default:
			break;
		}
	}
	priv->shadow_statflg = canrflg & MSCAN_STAT_MSK;
Loading