/** @brief pass a socket buffer to the DEMUX layer Invokes the recv_skb_single method in the io_device instance to perform receiving IPC messages from each skb. @param mld the pointer to a mem_link_device instance @param skb the pointer to an sk_buff instance @retval "> 0" if succeeded to pass an @b @@skb to the DEMUX layer @retval "< 0" an error code */ static void pass_skb_to_demux(struct mem_link_device *mld, struct sk_buff *skb) { struct link_device *ld = &mld->link_dev; struct io_device *iod; int ch; int ret; ch = sipc5_get_ch_id(skb->data); iod = link_get_iod_with_channel(ld, ch); if (unlikely(!iod)) { mif_err("%s: ERR! No IO device for Ch.%d\n", ld->name, ch); dev_kfree_skb_any(skb); mem_forced_cp_crash(mld); return; } /* Record the RX IO device into the "iod" field in &skb->cb */ skbpriv(skb)->iod = iod; /* Record the RX link device into the "ld" field in &skb->cb */ skbpriv(skb)->ld = ld; #ifdef DEBUG_MODEM_IF_LINK_RX log_ipc_pkt(sipc5_get_ch_id(skb->data), LINK, RX, skb, true, true); #endif ret = iod->recv_skb_single(iod, ld, skb); if (unlikely(ret < 0)) { mif_err("%s: ERR! %s->recv_skb_single fail (%d)\n", ld->name, iod->name, ret); dev_kfree_skb_any(skb); } }
int tx_frames_to_rb(struct sbd_ring_buffer *rb) { struct sk_buff_head *skb_txq = &rb->skb_q; int tx_bytes = 0; int ret = 0; while (1) { struct sk_buff *skb; skb = skb_dequeue(skb_txq); if (unlikely(!skb)) break; ret = sbd_pio_tx(rb, skb); if (unlikely(ret < 0)) { /* Take the skb back to the skb_txq */ skb_queue_head(skb_txq, skb); break; } tx_bytes += ret; log_ipc_pkt(LNK_TX, rb->ch, skb); trace_mif_event(skb, skb->len, FUNC); dev_kfree_skb_any(skb); } return (ret < 0) ? ret : tx_bytes; }
static void pass_skb_to_net(struct mem_link_device *mld, struct sk_buff *skb) { struct link_device *ld = &mld->link_dev; struct skbuff_private *priv; struct io_device *iod; int ret; priv = skbpriv(skb); if (unlikely(!priv)) { mif_err("%s: ERR! No PRIV in skb@%p\n", ld->name, skb); dev_kfree_skb_any(skb); mem_forced_cp_crash(mld); return; } iod = priv->iod; if (unlikely(!iod)) { mif_err("%s: ERR! No IOD in skb@%p\n", ld->name, skb); dev_kfree_skb_any(skb); mem_forced_cp_crash(mld); return; } #if defined(DEBUG_MODEM_IF_LINK_RX) && defined(DEBUG_MODEM_IF_PS_DATA) log_ipc_pkt(iod->id, LINK, RX, skb, priv->lnk_hdr ? skb->data : NULL); #endif ret = iod->recv_net_skb(iod, ld, skb); if (unlikely(ret < 0)) { struct modem_ctl *mc = ld->mc; mif_err_limited("%s: %s<-%s: ERR! %s->recv_net_skb fail (%d)\n", ld->name, iod->name, mc->name, iod->name, ret); dev_kfree_skb_any(skb); } }
static void pass_skb_to_net(struct mem_link_device *mld, struct sk_buff *skb) { struct link_device *ld = &mld->link_dev; struct skbuff_private *priv; struct io_device *iod; int ret; priv = skbpriv(skb); if (unlikely(!priv)) { mif_err("%s: ERR! No PRIV in skb@%p\n", ld->name, skb); dev_kfree_skb_any(skb); modemctl_notify_event(MDM_CRASH_INVALID_SKBCB); return; } iod = priv->iod; if (unlikely(!iod)) { mif_err("%s: ERR! No IOD in skb@%p\n", ld->name, skb); dev_kfree_skb_any(skb); modemctl_notify_event(MDM_CRASH_INVALID_SKBIOD); return; } log_ipc_pkt(LNK_RX, iod->id, skb); ret = iod->recv_net_skb(iod, ld, skb); if (unlikely(ret < 0)) { struct modem_ctl *mc = ld->mc; mif_err_limited("%s: %s<-%s: ERR! %s->recv_net_skb fail (%d)\n", ld->name, iod->name, mc->name, iod->name, ret); dev_kfree_skb_any(skb); } }
static void pass_skb_to_demux(struct mem_link_device *mld, struct sk_buff *skb) { struct link_device *ld = &mld->link_dev; struct io_device *iod = skbpriv(skb)->iod; int ret; u8 ch = skbpriv(skb)->sipc_ch; #ifdef DEBUG_MODEM_IF_LINK_RX u8 *hdr; #endif if (unlikely(!iod)) { mif_err("%s: ERR! No IOD for CH.%d\n", ld->name, ch); dev_kfree_skb_any(skb); mem_forced_cp_crash(mld); return; } #ifdef DEBUG_MODEM_IF_LINK_RX hdr = skbpriv(skb)->lnk_hdr ? skb->data : NULL; log_ipc_pkt(ch, LINK, RX, skb, hdr); #endif ret = iod->recv_skb_single(iod, ld, skb); if (unlikely(ret < 0)) { struct modem_ctl *mc = ld->mc; mif_err_limited("%s: %s<-%s: ERR! %s->recv_skb fail (%d)\n", ld->name, iod->name, mc->name, iod->name, ret); dev_kfree_skb_any(skb); } }
static int xmit_udl(struct mem_link_device *mld, struct io_device *iod, enum sipc_ch_id ch, struct sk_buff *skb) { int ret; struct mem_ipc_device *dev = mld->dev[IPC_RAW]; int count = skb->len; int tried = 0; while (1) { ret = udl_write(mld, dev, skb); if (ret == count) break; if (ret != -ENOSPC) goto exit; tried++; if (tried >= 20) goto exit; if (in_interrupt()) mdelay(50); else msleep(50); } #ifdef DEBUG_MODEM_IF_LINK_TX log_ipc_pkt(ch, LINK, TX, skb, skb->data); #endif dev_kfree_skb_any(skb); exit: return ret; }
static int tx_frames_to_rb(struct sbd_ring_buffer *rb) { struct sk_buff_head *skb_txq = &rb->skb_q; int tx_bytes = 0; int ret = 0; while (1) { struct sk_buff *skb; #ifdef DEBUG_MODEM_IF u8 *hdr; #endif skb = skb_dequeue(skb_txq); if (unlikely(!skb)) break; ret = sbd_pio_tx(rb, skb); if (unlikely(ret < 0)) { /* Take the skb back to the skb_txq */ skb_queue_head(skb_txq, skb); break; } tx_bytes += ret; #ifdef DEBUG_MODEM_IF hdr = skbpriv(skb)->lnk_hdr ? skb->data : NULL; #ifdef DEBUG_MODEM_IF_IP_DATA if (sipc_ps_ch(rb->ch)) { u8 *ip_pkt = skb->data; if (hdr) ip_pkt += sipc5_get_hdr_len(hdr); print_ipv4_packet(ip_pkt, TX); } #endif #ifdef DEBUG_MODEM_IF_LINK_TX log_ipc_pkt(rb->ch, LINK, TX, skb, hdr); #endif #endif dev_kfree_skb_any(skb); } return (ret < 0) ? ret : tx_bytes; }
static int tx_frames_to_dev(struct mem_link_device *mld, struct mem_ipc_device *dev) { struct sk_buff_head *skb_txq = dev->skb_txq; int tx_bytes = 0; int ret = 0; while (1) { struct sk_buff *skb; #ifdef DEBUG_MODEM_IF_LINK_TX u8 *hdr; u8 ch; #endif skb = skb_dequeue(skb_txq); if (unlikely(!skb)) break; ret = txq_write(mld, dev, skb); if (unlikely(ret < 0)) { /* Take the skb back to the skb_txq */ skb_queue_head(skb_txq, skb); break; } tx_bytes += ret; #ifdef DEBUG_MODEM_IF_LINK_TX hdr = skbpriv(skb)->lnk_hdr ? skb->data : NULL; ch = skbpriv(skb)->sipc_ch; log_ipc_pkt(ch, LINK, TX, skb, hdr); #endif dev_kfree_skb_any(skb); } return (ret < 0) ? ret : tx_bytes; }
/** @brief copy data in an skb to a circular TXQ Enqueues a frame in @b @@skb to the @b @@dev TXQ if there is enough space in the TXQ, then releases @b @@skb. @param mld the pointer to a mem_link_device instance @param dev the pointer to a mem_ipc_device instance @param skb the pointer to an sk_buff instance @retval "> 0" the size of the frame written in the TXQ @retval "< 0" an error code (-EBUSY, -ENOSPC, or -EIO) */ static int txq_write(struct mem_link_device *mld, struct mem_ipc_device *dev, struct sk_buff *skb) { char *src = skb->data; unsigned int count = skb->len; char *dst = get_txq_buff(dev); unsigned int qsize = get_txq_buff_size(dev); unsigned int in = get_txq_head(dev); unsigned int out = get_txq_tail(dev); int space; space = check_txq_space(mld, dev, qsize, in, out, count); if (unlikely(space < 0)) return space; #ifdef DEBUG_MODEM_IF_LINK_TX /* Record the time-stamp */ getnstimeofday(&skbpriv(skb)->ts); #endif circ_write(dst, src, qsize, in, count); set_txq_head(dev, circ_new_ptr(qsize, in, count)); /* Commit the item before incrementing the head */ smp_mb(); #ifdef DEBUG_MODEM_IF_LINK_TX if (likely(src)) log_ipc_pkt(sipc5_get_ch_id(src), LINK, TX, skb, true, true); #endif dev_kfree_skb_any(skb); return count; }
/** @brief pass a socket buffer to the DEMUX layer Invokes the recv_skb_single method in the io_device instance to perform receiving IPC messages from each skb. @param mld the pointer to a mem_link_device instance @param skb the pointer to an sk_buff instance @retval "> 0" if succeeded to pass an @b @@skb to the DEMUX layer @retval "< 0" an error code */ static void pass_skb_to_demux(struct mem_link_device *mld, struct sk_buff *skb) { struct link_device *ld = &mld->link_dev; struct io_device *iod = skbpriv(skb)->iod; int ret; u8 ch = skbpriv(skb)->sipc_ch; if (unlikely(!iod)) { mif_err("%s: ERR! No IOD for CH.%d\n", ld->name, ch); dev_kfree_skb_any(skb); modemctl_notify_event(MDM_CRASH_INVALID_IOD); return; } log_ipc_pkt(LNK_RX, ch, skb); ret = iod->recv_skb_single(iod, ld, skb); if (unlikely(ret < 0)) { struct modem_ctl *mc = ld->mc; mif_err_limited("%s: %s<-%s: ERR! %s->recv_skb fail (%d)\n", ld->name, iod->name, mc->name, iod->name, ret); dev_kfree_skb_any(skb); } }