Example #1
0
/*
  ret < 0  : error
  ret == 0 : no data
  ret > 0  : valid data
*/
static int dpram_ipc_recv_data(struct dpram_link_device *dpld, int dev)
{
	struct link_device *ld = &dpld->ld;
	struct dpram_rxb *rxb;
	u8 __iomem *src = get_rx_buff(dpld, dev);
	u32 qsize = get_rx_buff_size(dpld, dev);
	u32 in = get_rx_head(dpld, dev);
	u32 out = get_rx_tail(dpld, dev);
	u32 rcvd = 0;
	struct mif_irq_map map;

	if (in == out)
		return 0;

	if (dev == IPC_FMT) {
		set_dpram_map(dpld, &map);
		mif_irq_log(ld->mc->msd, map, "ipc_recv", sizeof("ipc_recv"));
	}

	/* Get data length in DPRAM*/
	rcvd = (in > out) ? (in - out) : (qsize - out + in);

	mif_debug("%s: %s qsize[%u] in[%u] out[%u] rcvd[%u]\n",
		ld->name, get_dev_name(dev), qsize, in, out, rcvd);

	/* Check each queue */
	if (!dpram_circ_valid(qsize, in, out)) {
		mif_err("%s: ERR! %s_RXQ invalid (size:%d in:%d out:%d)\n",
			ld->name, get_dev_name(dev), qsize, in, out);
#if 0
		set_rx_head(dpld, dev, 0);
		set_rx_tail(dpld, dev, 0);
#else
		dpram_trigger_force_cp_crash(dpld);
#endif
		return -EINVAL;
	}

	/* Allocate an rxb */
	rxb = rxbq_get_free_rxb(&dpld->rxbq[dev]);
	if (!rxb) {
		mif_info("%s: ERR! %s rxbq_get_free_rxb fail\n",
			ld->name, get_dev_name(dev));
		return -ENOMEM;
	}

	/* Read data from each DPRAM buffer */
	dpram_ipc_read(dpld, dev, rxb_put(rxb, rcvd), src, out, rcvd, qsize);

	/* Calculate and set new out */
	out += rcvd;
	if (out >= qsize)
		out -= qsize;
	set_rx_tail(dpld, dev, out);

	return rcvd;
}
Example #2
0
static void dpram_ipc_write(struct dpram_link_device *dpld, int dev,
		u32 qsize, u32 in, u32 out, struct sk_buff *skb)
{
	struct link_device *ld = &dpld->ld;
	u8 __iomem *buff = get_tx_buff(dpld, dev);
	u8 *src = skb->data;
	u32 len = skb->len;
	u32 inp;
	struct mif_irq_map map;

	if (in < out) {
		/* +++++++++ in ---------- out ++++++++++ */
		memcpy((buff + in), src, len);
	} else {
		/* ------ out +++++++++++ in ------------ */
		u32 space = qsize - in;

		/* 1) in -> buffer end */
		memcpy((buff + in), src, ((len > space) ? space : len));

		/* 2) buffer start -> out */
		if (len > space)
			memcpy(buff, (src + space), (len - space));
	}

	/* update new in pointer */
	inp = in + len;
	if (inp >= qsize)
		inp -= qsize;
	set_tx_head(dpld, dev, inp);

	if (dev == IPC_FMT) {
		set_dpram_map(dpld, &map);
		mif_irq_log(ld->mc->msd, map, "ipc_write", sizeof("ipc_write"));
		mif_ipc_log(MIF_IPC_AP2CP, ld->mc->msd, skb->data, skb->len);
	}

	if (ld->aligned && memcmp16_to_io((buff + in), src, 4)) {
		mif_err("%s: memcmp16_to_io fail\n", ld->name);
		dpram_trigger_force_cp_crash(dpld);
	}
}
/*
  ret < 0  : error
  ret == 0 : no data
  ret > 0  : valid data
*/
static int dpram_ipc_recv_data_with_rxb(struct dpram_link_device *dpld, int dev)
{
	struct link_device *ld = &dpld->ld;
	struct dpram_rxb *rxb;
	u8 __iomem *src = get_rx_buff(dpld, dev);
	u32 qsize = get_rx_buff_size(dpld, dev);
	u32 in;
	u32 out;
	u32 rcvd;
	struct mif_irq_map map;

	rcvd = dpram_get_rxq_rcvd(dpld, dev, qsize, &in, &out);
	if (rcvd <= 0)
		return rcvd;

	if (dev == IPC_FMT) {
		set_dpram_map(dpld, &map);
		mif_irq_log(ld->mc->msd, map, "ipc_recv", sizeof("ipc_recv"));
	}

	/* Allocate an rxb */
	rxb = rxbq_get_free_rxb(&dpld->rxbq[dev]);
	if (!rxb) {
		mif_info("%s: ERR! %s rxbq_get_free_rxb fail\n",
			ld->name, get_dev_name(dev));
		return -ENOMEM;
	}

	/* Read data from each DPRAM buffer */
	dpram_ipc_read(dpld, dev, rxb_put(rxb, rcvd), src, out, rcvd, qsize);

	/* Calculate and set new out */
	out += rcvd;
	if (out >= qsize)
		out -= qsize;
	set_rx_tail(dpld, dev, out);

	return rcvd;
}
/*
  ret < 0  : error
  ret == 0 : no data
  ret > 0  : valid data
*/
static int dpram_ipc_recv_data_with_skb(struct dpram_link_device *dpld, int dev)
{
	struct link_device *ld = &dpld->ld;
	struct io_device *iod = dpld->iod[dev];
	struct sk_buff *skb;
	u8 __iomem *src = get_rx_buff(dpld, dev);
	u32 qsize = get_rx_buff_size(dpld, dev);
	u32 in;
	u32 out;
	u32 rcvd;
	int rest;
	u8 *frm;
	u8 *dst;
	unsigned int len;
	unsigned int pad;
	unsigned int tot;
	struct mif_irq_map map;

	rcvd = dpram_get_rxq_rcvd(dpld, dev, qsize, &in, &out);
	if (rcvd <= 0)
		return rcvd;

	if (dev == IPC_FMT) {
		set_dpram_map(dpld, &map);
		mif_irq_log(ld->mc->msd, map, "ipc_recv", sizeof("ipc_recv"));
	}

	rest = rcvd;
	while (rest > 0) {
		frm = src + out;
		if (unlikely(!sipc5_start_valid(frm[0]))) {
			mif_err("%s: ERR! %s invalid start 0x%02X\n",
				ld->name, get_dev_name(dev), frm[0]);
			skb_queue_purge(&dpld->skb_rxq[dev]);
			return -EBADMSG;
		}

		len = sipc5_get_frame_sz16(frm);
		if (unlikely(len > rest)) {
			mif_err("%s: ERR! %s len %d > rest %d\n",
				ld->name, get_dev_name(dev), len, rest);
			skb_queue_purge(&dpld->skb_rxq[dev]);
			return -EBADMSG;
		}

		pad = sipc5_calc_padding_size(len);
		tot = len + pad;

		/* Allocate an skb */
		skb = dev_alloc_skb(tot);
		if (!skb) {
			mif_err("%s: ERR! %s dev_alloc_skb fail\n",
				ld->name, get_dev_name(dev));
			return -ENOMEM;
		}

		/* Read data from each DPRAM buffer */
		dst = skb_put(skb, tot);
		dpram_ipc_read(dpld, dev, dst, src, out, tot, qsize);
		skb_trim(skb, len);
		iod->recv_skb(iod, ld, skb);

		/* Calculate and set new out */
		rest -= tot;
		out += tot;
		if (out >= qsize)
			out -= qsize;
	}

	set_rx_tail(dpld, dev, out);

	return rcvd;
}