netif_wake_queue(dev);
}
+/*
+ * If we have a gap in the pending bits, that means we either
+ * raced with the hardware or failed to readout all upper
+ * objects in the last run due to quota limit.
+ */
+static u32 c_can_adjust_pending(u32 pend)
+{
+ u32 weight, lasts;
+
+ if (pend == RECEIVE_OBJECT_BITS)
+ return pend;
+
+ /*
+ * If the last set bit is larger than the number of pending
+ * bits we have a gap.
+ */
+ weight = hweight32(pend);
+ lasts = fls(pend);
+
+ /* If the bits are linear, nothing to do */
+ if (lasts == weight)
+ return pend;
+
+ /*
+ * Find the first set bit after the gap. We walk backwards
+ * from the last set bit.
+ */
+ for (lasts--; pend & (1 << (lasts - 1)); lasts--);
+
+ return pend & ~((1 << lasts) - 1);
+}
+
/*
* theory of operation:
*
u32 num_rx_pkts = 0;
unsigned int msg_obj, msg_ctrl_save;
struct c_can_priv *priv = netdev_priv(dev);
- u16 val;
+ u32 val, pend = 0;
/*
* It is faster to read only one 16bit register. This is only possible
BUILD_BUG_ON_MSG(C_CAN_MSG_OBJ_RX_LAST > 16,
"Implementation does not support more message objects than 16");
- while (quota > 0 && (val = priv->read_reg(priv, C_CAN_INTPND1_REG))) {
+ while (quota > 0) {
+
+ if (!pend) {
+ pend = priv->read_reg(priv, C_CAN_INTPND1_REG);
+ if (!pend)
+ return num_rx_pkts;
+ /*
+ * If the pending field has a gap, handle the
+ * bits above the gap first.
+ */
+ val = c_can_adjust_pending(pend);
+ } else {
+ val = pend;
+ }
+ /* Remove the bits from pend */
+ pend &= ~val;
+
while ((msg_obj = ffs(val)) && quota > 0) {
val &= ~BIT(msg_obj - 1);