static ssize_t dump_rb_frame(char *buf, size_t size, struct sbd_ring_buffer *rb) { int idx; u32 i, j, nr, nc, len = 0; nr = min_t(u32, rb->len, sipc_ps_ch(rb->ch) ? 48 : 32); /* 52 Bytes = ip header(20) + TCP header(32) */ nc = sipc_ps_ch(rb->ch) ? 52 : 16; /* dumps recent n frames */ for (i = 0; i < nr; i++) { idx = *rb->wp - i - 1; if (idx < 0) idx = rb->len + idx; /* len += snprintf((buf + len), (size - len), "rb[%03d] ", idx); */ for (j = 0; j < nc; j++) len += snprintf((buf + len), (size - len), "%02x", rb->buff[idx][j]); len += snprintf((buf + len), (size - len), "\n"); } return len; }
static int rx_frames_from_dev(struct mem_link_device *mld, struct mem_ipc_device *dev) { struct link_device *ld = &mld->link_dev; struct sk_buff_head *skb_rxq = dev->skb_rxq; unsigned int qsize = get_rxq_buff_size(dev); unsigned int in = get_rxq_head(dev); unsigned int out = get_rxq_tail(dev); unsigned int size = circ_get_usage(qsize, in, out); int rcvd = 0; if (unlikely(circ_empty(in, out))) return 0; while (rcvd < size) { struct sk_buff *skb; u8 ch; struct io_device *iod; skb = rxq_read(mld, dev, in); if (!skb) break; ch = sipc5_get_ch(skb->data); iod = link_get_iod_with_channel(ld, ch); if (!iod) { mif_err("%s: ERR! No IOD for CH.%d\n", ld->name, ch); dev_kfree_skb_any(skb); mem_forced_cp_crash(mld); break; } /* Record the IO device and the link device into the &skb->cb */ skbpriv(skb)->iod = iod; skbpriv(skb)->ld = ld; skbpriv(skb)->lnk_hdr = iod->link_header; skbpriv(skb)->sipc_ch = ch; /* The $rcvd must be accumulated here, because $skb can be freed in pass_skb_to_demux(). */ rcvd += skb->len; if (likely(sipc_ps_ch(ch))) skb_queue_tail(skb_rxq, skb); else pass_skb_to_demux(mld, skb); } if (rcvd < size) { struct link_device *ld = &mld->link_dev; mif_err("%s: WARN! rcvd %d < size %d\n", ld->name, rcvd, size); } return rcvd; }
static void recv_sbd_ipc_frames(struct mem_link_device *mld, struct mem_snapshot *mst) { struct sbd_link_device *sl = &mld->sbd_link_dev; int i; for (i = 0; i < sl->num_channels; i++) { struct sbd_ring_buffer *rb = sbd_id2rb(sl, i, RX); if (unlikely(rb_empty(rb))) continue; if (likely(sipc_ps_ch(rb->ch))) rx_net_frames_from_rb(rb); else rx_ipc_frames_from_rb(rb); } }
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; }
/** @brief extract all IPC link frames from a circular queue In a while loop,\n 1) Receives each IPC link frame stored in the @b @@dev RXQ.\n 2) If the frame is a PS (network) data frame, stores it to an skb_rxq and schedules a delayed work for PS data reception.\n 3) Otherwise, passes it to the DEMUX layer immediately.\n @param mld the pointer to a mem_link_device instance @param dev the pointer to a mem_ipc_device instance (IPC_FMT, etc.) @retval "> 0" if valid data received @retval "= 0" if no data received @retval "< 0" if ANY error */ static int rx_frames_from_dev(struct mem_link_device *mld, struct mem_ipc_device *dev) { struct sk_buff_head *skb_rxq = dev->skb_rxq; unsigned int qsize = get_rxq_buff_size(dev); unsigned int in = get_rxq_head(dev); unsigned int out = get_rxq_tail(dev); unsigned int size = circ_get_usage(qsize, in, out); int rcvd = 0; if (unlikely(circ_empty(in, out))) return 0; while (rcvd < size) { struct sk_buff *skb; skb = rxq_read(mld, dev, in); if (!skb) break; /* The $rcvd must be accumulated here, because $skb can be freed in pass_skb_to_demux(). */ rcvd += skb->len; if (likely(sipc_ps_ch(sipc5_get_ch_id(skb->data)))) skb_queue_tail(skb_rxq, skb); else pass_skb_to_demux(mld, skb); } #ifdef DEBUG_MODEM_IF if (rcvd < size) { struct link_device *ld = &mld->link_dev; mif_err("%s: WARN! rcvd %d < size %d\n", ld->name, rcvd, size); } #endif return rcvd; }
static inline bool log_enabled(u8 ch, enum ipc_layer layer) { if (unlikely(layer == IOD_RX || layer == IOD_TX)) if (unlikely(!test_bit(DEBUG_FLAG_IOD, &dflags))) return false; if (sipc5_fmt_ch(ch)) return test_bit(DEBUG_FLAG_FMT, &dflags); else if (sipc_ps_ch(ch)) return test_bit(DEBUG_FLAG_PS, &dflags); else if (sipc5_rfs_ch(ch)) return test_bit(DEBUG_FLAG_RFS, &dflags); else if (sipc_csd_ch(ch)) return test_bit(DEBUG_FLAG_CSVT, &dflags); else if (sipc_log_ch(ch)) return test_bit(DEBUG_FLAG_LOG, &dflags); else if (sipc5_boot_ch(ch)) return test_bit(DEBUG_FLAG_BOOT, &dflags); else if (sipc5_dump_ch(ch)) return test_bit(DEBUG_FLAG_DUMP, &dflags); else return false; }
/** @brief receive all @b IPC message frames in all RXQs In a for loop,\n 1) Checks any REQ_ACK received.\n 2) Receives all IPC link frames in every RXQ.\n 3) Sends RES_ACK if there was REQ_ACK from CP.\n 4) Checks any RES_ACK received.\n @param mld the pointer to a mem_link_device instance @param mst the pointer to a mem_snapshot instance */ void recv_sbd_ipc_frames(struct mem_link_device *mld) { struct sbd_link_device *sl = &mld->sbd_link_dev; int i; for (i = 0; i < sl->num_channels; i++) { struct sbd_ring_buffer *rb = sbd_id2rb(sl, i, RX); if (unlikely(rb_empty(rb))) continue; if (likely(sipc_ps_ch(rb->ch))) { #ifdef CONFIG_LINK_DEVICE_NAPI //mld->link_dev.disable_irq(&mld->link_dev); if (napi_schedule_prep(&rb->iod->napi)) __napi_schedule(&rb->iod->napi); #else rx_net_frames_from_rb(rb, 0); #endif } else { rx_ipc_frames_from_rb(rb); } } }