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; }
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; }