in net/ctcm_fsms.c [1372:1465]
static void ctcmpc_chx_rx(fsm_instance *fi, int event, void *arg)
{
struct channel *ch = arg;
struct net_device *dev = ch->netdev;
struct ctcm_priv *priv = dev->ml_priv;
struct mpc_group *grp = priv->mpcg;
struct sk_buff *skb = ch->trans_skb;
struct sk_buff *new_skb;
unsigned long saveflags = 0; /* avoids compiler warning */
int len = ch->max_bufsize - ch->irb->scsw.cmd.count;
CTCM_PR_DEBUG("%s: %s: cp:%i %s maxbuf : %04x, len: %04x\n",
CTCM_FUNTAIL, dev->name, smp_processor_id(),
ch->id, ch->max_bufsize, len);
fsm_deltimer(&ch->timer);
if (skb == NULL) {
CTCM_DBF_TEXT_(MPC_ERROR, CTC_DBF_ERROR,
"%s(%s): TRANS_SKB = NULL",
CTCM_FUNTAIL, dev->name);
goto again;
}
if (len < TH_HEADER_LENGTH) {
CTCM_DBF_TEXT_(MPC_ERROR, CTC_DBF_ERROR,
"%s(%s): packet length %d to short",
CTCM_FUNTAIL, dev->name, len);
priv->stats.rx_dropped++;
priv->stats.rx_length_errors++;
} else {
/* must have valid th header or game over */
__u32 block_len = len;
len = TH_HEADER_LENGTH + XID2_LENGTH + 4;
new_skb = __dev_alloc_skb(ch->max_bufsize, GFP_ATOMIC);
if (new_skb == NULL) {
CTCM_DBF_TEXT_(MPC_ERROR, CTC_DBF_ERROR,
"%s(%s): skb allocation failed",
CTCM_FUNTAIL, dev->name);
fsm_event(priv->mpcg->fsm, MPCG_EVENT_INOP, dev);
goto again;
}
switch (fsm_getstate(grp->fsm)) {
case MPCG_STATE_RESET:
case MPCG_STATE_INOP:
dev_kfree_skb_any(new_skb);
break;
case MPCG_STATE_FLOWC:
case MPCG_STATE_READY:
skb_put_data(new_skb, skb->data, block_len);
skb_queue_tail(&ch->io_queue, new_skb);
tasklet_schedule(&ch->ch_tasklet);
break;
default:
skb_put_data(new_skb, skb->data, len);
skb_queue_tail(&ch->io_queue, new_skb);
tasklet_hi_schedule(&ch->ch_tasklet);
break;
}
}
again:
switch (fsm_getstate(grp->fsm)) {
int rc, dolock;
case MPCG_STATE_FLOWC:
case MPCG_STATE_READY:
if (ctcm_checkalloc_buffer(ch))
break;
ch->trans_skb->data = ch->trans_skb_data;
skb_reset_tail_pointer(ch->trans_skb);
ch->trans_skb->len = 0;
ch->ccw[1].count = ch->max_bufsize;
if (do_debug_ccw)
ctcmpc_dumpit((char *)&ch->ccw[0],
sizeof(struct ccw1) * 3);
dolock = !in_hardirq();
if (dolock)
spin_lock_irqsave(
get_ccwdev_lock(ch->cdev), saveflags);
rc = ccw_device_start(ch->cdev, &ch->ccw[0], 0, 0xff, 0);
if (dolock) /* see remark about conditional locking */
spin_unlock_irqrestore(
get_ccwdev_lock(ch->cdev), saveflags);
if (rc != 0)
ctcm_ccw_check_rc(ch, rc, "normal RX");
break;
default:
break;
}
CTCM_PR_DEBUG("Exit %s: %s, ch=0x%p, id=%s\n",
__func__, dev->name, ch, ch->id);
}