Esempio n. 1
0
static int c_can_poll(struct napi_struct *napi, int quota)
{
	struct net_device *dev = napi->dev;
	struct c_can_priv *priv = netdev_priv(dev);
	u16 curr, last = priv->last_status;
	int work_done = 0;

	priv->last_status = curr = priv->read_reg(priv, C_CAN_STS_REG);
	/* Ack status on C_CAN. D_CAN is self clearing */
	if (priv->type != BOSCH_D_CAN)
		priv->write_reg(priv, C_CAN_STS_REG, LEC_UNUSED);

	/* handle state changes */
	if ((curr & STATUS_EWARN) && (!(last & STATUS_EWARN))) {
		netdev_dbg(dev, "entered error warning state\n");
		work_done += c_can_handle_state_change(dev, C_CAN_ERROR_WARNING);
	}

	if ((curr & STATUS_EPASS) && (!(last & STATUS_EPASS))) {
		netdev_dbg(dev, "entered error passive state\n");
		work_done += c_can_handle_state_change(dev, C_CAN_ERROR_PASSIVE);
	}

	if ((curr & STATUS_BOFF) && (!(last & STATUS_BOFF))) {
		netdev_dbg(dev, "entered bus off state\n");
		work_done += c_can_handle_state_change(dev, C_CAN_BUS_OFF);
		goto end;
	}

	/* handle bus recovery events */
	if ((!(curr & STATUS_BOFF)) && (last & STATUS_BOFF)) {
		netdev_dbg(dev, "left bus off state\n");
		priv->can.state = CAN_STATE_ERROR_ACTIVE;
	}
	if ((!(curr & STATUS_EPASS)) && (last & STATUS_EPASS)) {
		netdev_dbg(dev, "left error passive state\n");
		priv->can.state = CAN_STATE_ERROR_ACTIVE;
	}

	/* handle lec errors on the bus */
	work_done += c_can_handle_bus_err(dev, curr & LEC_MASK);

	/* Handle Tx/Rx events. We do this unconditionally */
	work_done += c_can_do_rx_poll(dev, (quota - work_done));
	c_can_do_tx(dev);

end:
	if (work_done < quota) {
		napi_complete(napi);
		/* enable all IRQs if we are not in bus off state */
		if (priv->can.state != CAN_STATE_BUS_OFF)
			c_can_irq_control(priv, true);
	}

	return work_done;
}
Esempio n. 2
0
static int c_can_poll(struct napi_struct *napi, int quota)
{
	u16 irqstatus;
	int lec_type = 0;
	int work_done = 0;
	struct net_device *dev = napi->dev;
	struct c_can_priv *priv = netdev_priv(dev);

	irqstatus = priv->irqstatus;
	if (!irqstatus)
		goto end;

	/* status events have the highest priority */
	if (irqstatus == STATUS_INTERRUPT) {
		priv->current_status = priv->read_reg(priv,
					C_CAN_STS_REG);

		/* handle Tx/Rx events */
		if (priv->current_status & STATUS_TXOK)
			priv->write_reg(priv, C_CAN_STS_REG,
					priv->current_status & ~STATUS_TXOK);

		if (priv->current_status & STATUS_RXOK)
			priv->write_reg(priv, C_CAN_STS_REG,
					priv->current_status & ~STATUS_RXOK);

		/* handle state changes */
		if ((priv->current_status & STATUS_EWARN) &&
				(!(priv->last_status & STATUS_EWARN))) {
			netdev_dbg(dev, "entered error warning state\n");
			work_done += c_can_handle_state_change(dev,
						C_CAN_ERROR_WARNING);
		}
		if ((priv->current_status & STATUS_EPASS) &&
				(!(priv->last_status & STATUS_EPASS))) {
			netdev_dbg(dev, "entered error passive state\n");
			work_done += c_can_handle_state_change(dev,
						C_CAN_ERROR_PASSIVE);
		}
		if ((priv->current_status & STATUS_BOFF) &&
				(!(priv->last_status & STATUS_BOFF))) {
			netdev_dbg(dev, "entered bus off state\n");
			work_done += c_can_handle_state_change(dev,
						C_CAN_BUS_OFF);
		}

		/* handle bus recovery events */
		if ((!(priv->current_status & STATUS_BOFF)) &&
				(priv->last_status & STATUS_BOFF)) {
			netdev_dbg(dev, "left bus off state\n");
			priv->can.state = CAN_STATE_ERROR_ACTIVE;
		}
		if ((!(priv->current_status & STATUS_EPASS)) &&
				(priv->last_status & STATUS_EPASS)) {
			netdev_dbg(dev, "left error passive state\n");
			priv->can.state = CAN_STATE_ERROR_ACTIVE;
		}

		priv->last_status = priv->current_status;

		/* handle lec errors on the bus */
		lec_type = c_can_has_and_handle_berr(priv);
		if (lec_type)
			work_done += c_can_handle_bus_err(dev, lec_type);
	} else if ((irqstatus >= C_CAN_MSG_OBJ_RX_FIRST) &&
			(irqstatus <= C_CAN_MSG_OBJ_RX_LAST)) {
		/* handle events corresponding to receive message objects */
		work_done += c_can_do_rx_poll(dev, (quota - work_done));
	} else if ((irqstatus >= C_CAN_MSG_OBJ_TX_FIRST) &&
			(irqstatus <= C_CAN_MSG_OBJ_TX_LAST)) {
		/* handle events corresponding to transmit message objects */
		c_can_do_tx(dev);
	}

end:
	if (work_done < quota) {
		napi_complete(napi);
		/* enable all IRQs */
		c_can_enable_all_interrupts(priv, ENABLE_ALL_INTERRUPTS);
	}

	return work_done;
}