Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 33e6ada1 authored by Rupesh Gujare's avatar Rupesh Gujare Committed by Greg Kroah-Hartman
Browse files

staging: ozwpan: ISOC transfer in triggered mode



This patch implements ISOC frame transfer while PD is in
 triggered mode.

Signed-off-by: default avatarRupesh Gujare <rgujare@ozmodevices.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 3403cc0f
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -59,6 +59,6 @@ module_exit(ozwpan_exit);

MODULE_AUTHOR("Chris Kelly");
MODULE_DESCRIPTION("Ozmo Devices USB over WiFi hcd driver");
MODULE_VERSION("1.0.9");
MODULE_VERSION("1.0.10");
MODULE_LICENSE("GPL");
+141 −30
Original line number Diff line number Diff line
@@ -24,18 +24,22 @@
/*------------------------------------------------------------------------------
 */
#define OZ_MAX_TX_POOL_SIZE	6
/* Maximum number of uncompleted isoc frames that can be pending.
/* Maximum number of uncompleted isoc frames that can be pending in network.
 */
#define OZ_MAX_SUBMITTED_ISOC	16
/* Maximum number of uncompleted isoc frames that can be pending in Tx Queue.
 */
#define OZ_MAX_TX_QUEUE_ISOC	32
/*------------------------------------------------------------------------------
 */
static struct oz_tx_frame *oz_tx_frame_alloc(struct oz_pd *pd);
static void oz_tx_frame_free(struct oz_pd *pd, struct oz_tx_frame *f);
static void oz_tx_isoc_free(struct oz_pd *pd, struct oz_tx_frame *f);
static struct sk_buff *oz_build_frame(struct oz_pd *pd, struct oz_tx_frame *f);
static int oz_send_isoc_frame(struct oz_pd *pd);
static void oz_retire_frame(struct oz_pd *pd, struct oz_tx_frame *f);
static void oz_isoc_stream_free(struct oz_isoc_stream *st);
static int oz_send_next_queued_frame(struct oz_pd *pd, int *more_data);
static int oz_send_next_queued_frame(struct oz_pd *pd, int more_data);
static void oz_isoc_destructor(struct sk_buff *skb);
static int oz_def_app_init(void);
static void oz_def_app_term(void);
@@ -208,6 +212,8 @@ void oz_pd_destroy(struct oz_pd *pd)
	while (e != &pd->tx_queue) {
		f = container_of(e, struct oz_tx_frame, link);
		e = e->next;
		if (f->skb != NULL)
			kfree_skb(f->skb);
		oz_retire_frame(pd, f);
	}
	oz_elt_buf_term(&pd->elt_buff);
@@ -372,6 +378,23 @@ static struct oz_tx_frame *oz_tx_frame_alloc(struct oz_pd *pd)
	}
	return f;
}
/*------------------------------------------------------------------------------
 * Context: softirq or process
 */
static void oz_tx_isoc_free(struct oz_pd *pd, struct oz_tx_frame *f)
{
	pd->nb_queued_isoc_frames--;
	list_del_init(&f->link);
	if (pd->tx_pool_count < OZ_MAX_TX_POOL_SIZE) {
		f->link.next = pd->tx_pool;
		pd->tx_pool = &f->link;
		pd->tx_pool_count++;
	} else {
		kfree(f);
	}
	oz_trace2(OZ_TRACE_TX_FRAMES, "Releasing ISOC Frame isoc_nb= %d\n",
						pd->nb_queued_isoc_frames);
}
/*------------------------------------------------------------------------------
 * Context: softirq or process
 */
@@ -388,6 +411,14 @@ static void oz_tx_frame_free(struct oz_pd *pd, struct oz_tx_frame *f)
	if (f)
		kfree(f);
}
/*------------------------------------------------------------------------------
 * Context: softirq-serialized
 */
void oz_set_more_bit(struct sk_buff *skb)
{
	struct oz_hdr *oz_hdr = (struct oz_hdr *)skb_network_header(skb);
	oz_hdr->control |= OZ_F_MORE_DATA;
}
/*------------------------------------------------------------------------------
 * Context: softirq
 */
@@ -403,6 +434,7 @@ int oz_prepare_frame(struct oz_pd *pd, int empty)
	f = oz_tx_frame_alloc(pd);
	if (f == 0)
		return -1;
	f->skb = NULL;
	f->hdr.control =
		(OZ_PROTOCOL_VERSION<<OZ_VERSION_SHIFT) | OZ_F_ACK_REQUESTED;
	++pd->last_tx_pkt_num;
@@ -486,24 +518,51 @@ static void oz_retire_frame(struct oz_pd *pd, struct oz_tx_frame *f)
/*------------------------------------------------------------------------------
 * Context: softirq-serialized
 */
static int oz_send_next_queued_frame(struct oz_pd *pd, int *more_data)
static int oz_send_next_queued_frame(struct oz_pd *pd, int more_data)
{
	struct sk_buff *skb;
	struct oz_tx_frame *f;
	struct list_head *e;
	*more_data = 0;
	spin_lock(&pd->tx_frame_lock);
	e = pd->last_sent_frame->next;
	if (e == &pd->tx_queue) {
		spin_unlock(&pd->tx_frame_lock);
		return -1;
	}
	pd->last_sent_frame = e;
	if (e->next != &pd->tx_queue)
		*more_data = 1;
	f = container_of(e, struct oz_tx_frame, link);

	if (f->skb != NULL) {
		skb = f->skb;
		oz_tx_isoc_free(pd, f);
		spin_unlock(&pd->tx_frame_lock);
		if (more_data)
			oz_set_more_bit(skb);
		if ((int)atomic_read(&g_submitted_isoc) <
							OZ_MAX_SUBMITTED_ISOC) {
			if (dev_queue_xmit(skb) < 0) {
				oz_trace2(OZ_TRACE_TX_FRAMES,
						"Dropping ISOC Frame\n");
				oz_event_log(OZ_EVT_TX_ISOC_DROP, 0, 0, 0, 0);
				return -1;
			}
			atomic_inc(&g_submitted_isoc);
			oz_trace2(OZ_TRACE_TX_FRAMES,
					"Sending ISOC Frame, nb_isoc= %d\n",
						pd->nb_queued_isoc_frames);
			return 0;
		} else {
			kfree_skb(skb);
			oz_trace2(OZ_TRACE_TX_FRAMES, "Dropping ISOC Frame>\n");
			oz_event_log(OZ_EVT_TX_ISOC_DROP, 0, 0, 0, 0);
			return -1;
		}
	}

	pd->last_sent_frame = e;
	skb = oz_build_frame(pd, f);
	spin_unlock(&pd->tx_frame_lock);
	if (more_data)
		oz_set_more_bit(skb);
	oz_trace2(OZ_TRACE_TX_FRAMES, "TX frame PN=0x%x\n", f->hdr.pkt_num);
	if (skb) {
		oz_event_log(OZ_EVT_TX_FRAME,
@@ -512,6 +571,7 @@ static int oz_send_next_queued_frame(struct oz_pd *pd, int *more_data)
			0, f->hdr.pkt_num);
		if (dev_queue_xmit(skb) < 0)
			return -1;

	}
	return 0;
}
@@ -520,21 +580,38 @@ static int oz_send_next_queued_frame(struct oz_pd *pd, int *more_data)
 */
void oz_send_queued_frames(struct oz_pd *pd, int backlog)
{
	int more;
	if (backlog <  OZ_MAX_QUEUED_FRAMES) {
		if (oz_send_next_queued_frame(pd, &more) >= 0) {
			while (more && oz_send_next_queued_frame(pd, &more))
				;
		} else {
			if (((pd->mode & OZ_F_ISOC_ANYTIME) == 0)
				|| (pd->isoc_sent == 0)) {
				if (oz_prepare_frame(pd, 1) >= 0)
					oz_send_next_queued_frame(pd, &more);
	while (oz_prepare_frame(pd, 0) >= 0)
		backlog++;

	switch (pd->mode & (OZ_F_ISOC_NO_ELTS | OZ_F_ISOC_ANYTIME)) {

		case OZ_F_ISOC_NO_ELTS: {
			backlog += pd->nb_queued_isoc_frames;
			if (backlog <= 0)
				goto out;
			if (backlog > OZ_MAX_SUBMITTED_ISOC)
				backlog = OZ_MAX_SUBMITTED_ISOC;
			break;
		}
		case OZ_NO_ELTS_ANYTIME: {
			if ((backlog <= 0) && (pd->isoc_sent == 0))
				goto out;
			break;
		}
	} else {
		oz_send_next_queued_frame(pd, &more);
		default: {
			if (backlog <= 0)
				goto out;
			break;
		}
	}
	while (backlog--) {
		if (oz_send_next_queued_frame(pd, backlog) < 0)
			break;
	}
	return;

out:	oz_prepare_frame(pd, 1);
	oz_send_next_queued_frame(pd, 0);
}
/*------------------------------------------------------------------------------
 * Context: softirq
@@ -603,8 +680,10 @@ void oz_retire_tx_frames(struct oz_pd *pd, u8 lpn)
		f = container_of(e, struct oz_tx_frame, link);
		pkt_num = le32_to_cpu(get_unaligned(&f->hdr.pkt_num));
		diff = (lpn - (pkt_num & OZ_LAST_PN_MASK)) & OZ_LAST_PN_MASK;
		if (diff > OZ_LAST_PN_HALF_CYCLE)
		if ((diff > OZ_LAST_PN_HALF_CYCLE) || (pkt_num == 0))
			break;
		oz_trace2(OZ_TRACE_TX_FRAMES, "Releasing pkt_num= %u, nb= %d\n",
						 pkt_num, pd->nb_queued_frames);
		if (first == 0)
			first = e;
		last = e;
@@ -756,21 +835,53 @@ int oz_send_isoc_unit(struct oz_pd *pd, u8 ep_num, u8 *data, int len)
		memcpy(oz_hdr, &oz, sizeof(oz));
		memcpy(oz_hdr+1, &iso, sizeof(iso));
		if (dev_hard_header(skb, dev, OZ_ETHERTYPE, pd->mac_addr,
				dev->dev_addr, skb->len) < 0) {
			kfree_skb(skb);
			return -1;
				dev->dev_addr, skb->len) < 0)
			goto out;

		skb->destructor = oz_isoc_destructor;
		/*Queue for Xmit if mode is not ANYTIME*/
		if (!(pd->mode & OZ_F_ISOC_ANYTIME)) {
			struct oz_tx_frame *isoc_unit = NULL;
			int nb = pd->nb_queued_isoc_frames;
			if (nb >= OZ_MAX_TX_QUEUE_ISOC) {
				oz_trace2(OZ_TRACE_TX_FRAMES,
						"Dropping ISOC Unit nb= %d\n",
									nb);
				goto out;
			}
			isoc_unit = oz_tx_frame_alloc(pd);
			if (isoc_unit == NULL)
				goto out;
			isoc_unit->hdr = oz;
			isoc_unit->skb = skb;
			spin_lock_bh(&pd->tx_frame_lock);
			list_add_tail(&isoc_unit->link, &pd->tx_queue);
			pd->nb_queued_isoc_frames++;
			spin_unlock_bh(&pd->tx_frame_lock);
			oz_trace2(OZ_TRACE_TX_FRAMES,
			"Added ISOC Frame to Tx Queue isoc_nb= %d, nb= %d\n",
			pd->nb_queued_isoc_frames, pd->nb_queued_frames);
			oz_event_log(OZ_EVT_TX_ISOC, nb_units, iso.frame_number,
					skb, atomic_read(&g_submitted_isoc));
			return 0;
		}

		/*In ANYTIME mode Xmit unit immediately*/
		if (atomic_read(&g_submitted_isoc) < OZ_MAX_SUBMITTED_ISOC) {
			skb->destructor = oz_isoc_destructor;
			atomic_inc(&g_submitted_isoc);
			oz_event_log(OZ_EVT_TX_ISOC, nb_units, iso.frame_number,
					skb, atomic_read(&g_submitted_isoc));
			if (dev_queue_xmit(skb) < 0)
				return -1;
		} else {
			if (dev_queue_xmit(skb) < 0) {
				oz_event_log(OZ_EVT_TX_ISOC_DROP, 0, 0, 0, 0);
			kfree_skb(skb);
				return -1;
			} else
				return 0;
		}

out:	oz_event_log(OZ_EVT_TX_ISOC_DROP, 0, 0, 0, 0);
	kfree_skb(skb);
	return -1;

	}
	return 0;
}
+2 −1
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ struct oz_tx_frame {
	struct list_head link;
	struct list_head elt_list;
	struct oz_hdr hdr;
	struct sk_buff *skb;
	int total_size;
};

@@ -83,6 +84,7 @@ struct oz_pd {
	u8		ms_per_isoc;
	unsigned	max_stream_buffering;
	int		nb_queued_frames;
	int		nb_queued_isoc_frames;
	struct list_head *tx_pool;
	int		tx_pool_count;
	spinlock_t	tx_frame_lock;
@@ -118,4 +120,3 @@ void oz_apps_init(void);
void oz_apps_term(void);

#endif /* Sentry */
+1 −3
Original line number Diff line number Diff line
@@ -217,7 +217,6 @@ static struct oz_pd *oz_connect_req(struct oz_pd *cur_pd, struct oz_elt *elt,
	pd->mode = body->mode;
	pd->pd_info = body->pd_info;
	if (pd->mode & OZ_F_ISOC_NO_ELTS) {
		pd->mode |= OZ_F_ISOC_ANYTIME;
		pd->ms_per_isoc = body->ms_per_isoc;
		if (!pd->ms_per_isoc)
			pd->ms_per_isoc = 4;
@@ -366,6 +365,7 @@ static void oz_rx_frame(struct sk_buff *skb)
	}

	if (pd && !dup && ((pd->mode & OZ_MODE_MASK) == OZ_MODE_TRIGGERED)) {
		oz_trace2(OZ_TRACE_RX_FRAMES, "Received TRIGGER Frame\n");
		pd->last_sent_frame = &pd->tx_queue;
		if (oz_hdr->control & OZ_F_ACK) {
			/* Retire completed frames */
@@ -376,8 +376,6 @@ static void oz_rx_frame(struct sk_buff *skb)
			int backlog = pd->nb_queued_frames;
			pd->trigger_pkt_num = pkt_num;
			/* Send queued frames */
			while (oz_prepare_frame(pd, 0) >= 0)
				;
			oz_send_queued_frames(pd, backlog);
		}
	}
+1 −0
Original line number Diff line number Diff line
@@ -89,6 +89,7 @@ struct oz_elt_connect_req {
#define OZ_MODE_MASK		0xf
#define OZ_F_ISOC_NO_ELTS	0x40
#define OZ_F_ISOC_ANYTIME	0x80
#define OZ_NO_ELTS_ANYTIME	0xc0

/* Keep alive field.
 */