[go: nahoru, domu]

ozpd.c revision 255ece7c4d9e63e2a5e784247bc2e7b639cae4dd
1bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/* -----------------------------------------------------------------------------
2bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Copyright (c) 2011 Ozmo Inc
3bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Released under the GNU General Public License Version 2 (GPLv2).
4bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * -----------------------------------------------------------------------------
5bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
6bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly#include <linux/init.h>
7bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly#include <linux/module.h>
8bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly#include <linux/timer.h>
9bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly#include <linux/sched.h>
10bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly#include <linux/netdevice.h>
11bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly#include <linux/errno.h>
12bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly#include "ozconfig.h"
13bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly#include "ozprotocol.h"
14bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly#include "ozeltbuf.h"
15bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly#include "ozpd.h"
16bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly#include "ozproto.h"
17bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly#include "oztrace.h"
18bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly#include "ozcdev.h"
19bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly#include "ozusbsvc.h"
20bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly#include <asm/unaligned.h>
21bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly#include <linux/uaccess.h>
22bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly#include <net/psnap.h>
23bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
24bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
25bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly#define OZ_MAX_TX_POOL_SIZE	6
26bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
27bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
28bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic struct oz_tx_frame *oz_tx_frame_alloc(struct oz_pd *pd);
29bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_tx_frame_free(struct oz_pd *pd, struct oz_tx_frame *f);
3033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujarestatic void oz_tx_isoc_free(struct oz_pd *pd, struct oz_tx_frame *f);
31bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic struct sk_buff *oz_build_frame(struct oz_pd *pd, struct oz_tx_frame *f);
32bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic int oz_send_isoc_frame(struct oz_pd *pd);
33bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_retire_frame(struct oz_pd *pd, struct oz_tx_frame *f);
34bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_isoc_stream_free(struct oz_isoc_stream *st);
3533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujarestatic int oz_send_next_queued_frame(struct oz_pd *pd, int more_data);
36bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_isoc_destructor(struct sk_buff *skb);
37bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic int oz_def_app_init(void);
38bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_def_app_term(void);
39bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic int oz_def_app_start(struct oz_pd *pd, int resume);
40bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_def_app_stop(struct oz_pd *pd, int pause);
41bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_def_app_rx(struct oz_pd *pd, struct oz_elt *elt);
42bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
43bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Counts the uncompleted isoc frames submitted to netcard.
44bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
45bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic atomic_t g_submitted_isoc = ATOMIC_INIT(0);
46bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/* Application handler functions.
47bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
48dc7f5b3594fdb846890192fd75793a791d7ba83bPeter Huewestatic const struct oz_app_if g_app_if[OZ_APPID_MAX] = {
49bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	{oz_usb_init,
50bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_usb_term,
51bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_usb_start,
52bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_usb_stop,
53bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_usb_rx,
54bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_usb_heartbeat,
55bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_usb_farewell,
56bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	OZ_APPID_USB},
57bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly
58bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	{oz_def_app_init,
59bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_def_app_term,
60bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_def_app_start,
61bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_def_app_stop,
62bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_def_app_rx,
6386b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	NULL,
6486b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	NULL,
65bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	OZ_APPID_UNUSED1},
66bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly
67bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	{oz_def_app_init,
68bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_def_app_term,
69bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_def_app_start,
70bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_def_app_stop,
71bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_def_app_rx,
7286b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	NULL,
7386b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	NULL,
74bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	OZ_APPID_UNUSED2},
75bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly
76bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	{oz_cdev_init,
77bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_cdev_term,
78bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_cdev_start,
79bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_cdev_stop,
80bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_cdev_rx,
8186b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	NULL,
8286b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	NULL,
83bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	OZ_APPID_SERIAL},
84bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly};
85bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
86bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: process
87bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
88bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic int oz_def_app_init(void)
89bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
90bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return 0;
91bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
92bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
93bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: process
94bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
95bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_def_app_term(void)
96bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
97bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
98bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
99bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
100bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
101bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic int oz_def_app_start(struct oz_pd *pd, int resume)
102bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
103bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return 0;
104bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
105bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
106bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
107bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
108bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_def_app_stop(struct oz_pd *pd, int pause)
109bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
110bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
111bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
112bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
113bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
114bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_def_app_rx(struct oz_pd *pd, struct oz_elt *elt)
115bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
116bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
117bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
118bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
119bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
120bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_pd_set_state(struct oz_pd *pd, unsigned state)
121bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
122bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	pd->state = state;
123bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly#ifdef WANT_TRACE
124bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	switch (state) {
125bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	case OZ_PD_S_IDLE:
126bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_trace("PD State: OZ_PD_S_IDLE\n");
127bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		break;
128bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	case OZ_PD_S_CONNECTED:
129bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_trace("PD State: OZ_PD_S_CONNECTED\n");
130bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		break;
131bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	case OZ_PD_S_STOPPED:
132bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_trace("PD State: OZ_PD_S_STOPPED\n");
133bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		break;
134bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	case OZ_PD_S_SLEEP:
135bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_trace("PD State: OZ_PD_S_SLEEP\n");
136bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		break;
137bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
138bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly#endif /* WANT_TRACE */
139bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
140bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
141bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
142bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
143bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_pd_get(struct oz_pd *pd)
144bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
145bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	atomic_inc(&pd->ref_count);
146bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
147bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
148bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
149bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
150bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_pd_put(struct oz_pd *pd)
151bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
152bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (atomic_dec_and_test(&pd->ref_count))
153bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_pd_destroy(pd);
154bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
155bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
156bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq-serialized
157bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
158dc7f5b3594fdb846890192fd75793a791d7ba83bPeter Huewestruct oz_pd *oz_pd_alloc(const u8 *mac_addr)
159bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
1601ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman	struct oz_pd *pd = kzalloc(sizeof(struct oz_pd), GFP_ATOMIC);
161bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (pd) {
162bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		int i;
163bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		atomic_set(&pd->ref_count, 2);
164bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		for (i = 0; i < OZ_APPID_MAX; i++)
165bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			spin_lock_init(&pd->app_lock[i]);
166bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->last_rx_pkt_num = 0xffffffff;
167bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_pd_set_state(pd, OZ_PD_S_IDLE);
168bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->max_tx_size = OZ_MAX_TX_SIZE;
169bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		memcpy(pd->mac_addr, mac_addr, ETH_ALEN);
170bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (0 != oz_elt_buf_init(&pd->elt_buff)) {
1711ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman			kfree(pd);
17286b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe			pd = NULL;
173bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		}
174bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_lock_init(&pd->tx_frame_lock);
175bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		INIT_LIST_HEAD(&pd->tx_queue);
176bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		INIT_LIST_HEAD(&pd->farewell_list);
177bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->last_sent_frame = &pd->tx_queue;
178bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_lock_init(&pd->stream_lock);
179bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		INIT_LIST_HEAD(&pd->stream_list);
180bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
181bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return pd;
182bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
183bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
184bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
185bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
186bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_pd_destroy(struct oz_pd *pd)
187bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
188bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct list_head *e;
189bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_tx_frame *f;
190bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_isoc_stream *st;
191bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_farewell *fwell;
192bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_trace("Destroying PD\n");
193bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Delete any streams.
194bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	 */
195bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	e = pd->stream_list.next;
196bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	while (e != &pd->stream_list) {
197bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		st = container_of(e, struct oz_isoc_stream, link);
198bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		e = e->next;
199bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_isoc_stream_free(st);
200bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
201bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Free any queued tx frames.
202bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	 */
203bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	e = pd->tx_queue.next;
204bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	while (e != &pd->tx_queue) {
205bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		f = container_of(e, struct oz_tx_frame, link);
206bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		e = e->next;
20733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		if (f->skb != NULL)
208dd3cef0f0715b79d29a4b0482117175f44b7d83cGreg Kroah-Hartman			kfree_skb(f->skb);
209bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_retire_frame(pd, f);
210bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
211bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_elt_buf_term(&pd->elt_buff);
212bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Free any farewells.
213bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	 */
214bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	e = pd->farewell_list.next;
215bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	while (e != &pd->farewell_list) {
216bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		fwell = container_of(e, struct oz_farewell, link);
217bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		e = e->next;
2181ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman		kfree(fwell);
219bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
220bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Deallocate all frames in tx pool.
221bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	 */
222bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	while (pd->tx_pool) {
223bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		e = pd->tx_pool;
224bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->tx_pool = e->next;
2251ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman		kfree(container_of(e, struct oz_tx_frame, link));
226bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
227bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (pd->net_dev)
228bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		dev_put(pd->net_dev);
2291ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman	kfree(pd);
230bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
231bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
232bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq-serialized
233bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
234bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyint oz_services_start(struct oz_pd *pd, u16 apps, int resume)
235bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
236dc7f5b3594fdb846890192fd75793a791d7ba83bPeter Huewe	const struct oz_app_if *ai;
237bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	int rc = 0;
238bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_trace("oz_services_start(0x%x) resume(%d)\n", apps, resume);
239bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	for (ai = g_app_if; ai < &g_app_if[OZ_APPID_MAX]; ai++) {
240bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (apps & (1<<ai->app_id)) {
241bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			if (ai->start(pd, resume)) {
242bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly				rc = -1;
243bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly				oz_trace("Unabled to start service %d\n",
244bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly					ai->app_id);
245bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly				break;
246bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			}
247bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			oz_polling_lock_bh();
248bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			pd->total_apps |= (1<<ai->app_id);
249bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			if (resume)
250bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly				pd->paused_apps &= ~(1<<ai->app_id);
251bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			oz_polling_unlock_bh();
252bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		}
253bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
254bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return rc;
255bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
256bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
257bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
258bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
259bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_services_stop(struct oz_pd *pd, u16 apps, int pause)
260bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
261dc7f5b3594fdb846890192fd75793a791d7ba83bPeter Huewe	const struct oz_app_if *ai;
262bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_trace("oz_stop_services(0x%x) pause(%d)\n", apps, pause);
263bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	for (ai = g_app_if; ai < &g_app_if[OZ_APPID_MAX]; ai++) {
264bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (apps & (1<<ai->app_id)) {
265bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			oz_polling_lock_bh();
266bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			if (pause) {
267bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly				pd->paused_apps |= (1<<ai->app_id);
268bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			} else {
269bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly				pd->total_apps &= ~(1<<ai->app_id);
270bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly				pd->paused_apps &= ~(1<<ai->app_id);
271bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			}
272bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			oz_polling_unlock_bh();
273bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			ai->stop(pd, pause);
274bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		}
275bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
276bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
277bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
278bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
279bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
280bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_pd_heartbeat(struct oz_pd *pd, u16 apps)
281bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
282dc7f5b3594fdb846890192fd75793a791d7ba83bPeter Huewe	const struct oz_app_if *ai;
283bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	int more = 0;
284bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	for (ai = g_app_if; ai < &g_app_if[OZ_APPID_MAX]; ai++) {
285bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (ai->heartbeat && (apps & (1<<ai->app_id))) {
286bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			if (ai->heartbeat(pd))
287bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly				more = 1;
288bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		}
289bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
290bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (more)
291bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_pd_request_heartbeat(pd);
292bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (pd->mode & OZ_F_ISOC_ANYTIME) {
293bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		int count = 8;
294bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		while (count-- && (oz_send_isoc_frame(pd) >= 0))
295bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			;
296bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
297bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
298bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
299bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
300bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
301bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_pd_stop(struct oz_pd *pd)
302bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
303bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	u16 stop_apps = 0;
304bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_trace("oz_pd_stop() State = 0x%x\n", pd->state);
305bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_pd_indicate_farewells(pd);
306bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_polling_lock_bh();
307bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	stop_apps = pd->total_apps;
308bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	pd->total_apps = 0;
309bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	pd->paused_apps = 0;
310bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_polling_unlock_bh();
311bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_services_stop(pd, stop_apps, 0);
312bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_polling_lock_bh();
313bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_pd_set_state(pd, OZ_PD_S_STOPPED);
314bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Remove from PD list.*/
315bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	list_del(&pd->link);
316bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_polling_unlock_bh();
317bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_trace("pd ref count = %d\n", atomic_read(&pd->ref_count));
318bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_timer_delete(pd, 0);
319bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_pd_put(pd);
320bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
321bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
322bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
323bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
324bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyint oz_pd_sleep(struct oz_pd *pd)
325bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
326bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	int do_stop = 0;
327bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	u16 stop_apps = 0;
328bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_polling_lock_bh();
329bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (pd->state & (OZ_PD_S_SLEEP | OZ_PD_S_STOPPED)) {
330bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_polling_unlock_bh();
331bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return 0;
332bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
333bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (pd->keep_alive_j && pd->session_id) {
334bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_pd_set_state(pd, OZ_PD_S_SLEEP);
335bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->pulse_time_j = jiffies + pd->keep_alive_j;
336bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_trace("Sleep Now %lu until %lu\n",
337bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			jiffies, pd->pulse_time_j);
338bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	} else {
339bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		do_stop = 1;
340bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
341bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	stop_apps = pd->total_apps;
342bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_polling_unlock_bh();
343bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (do_stop) {
344bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_pd_stop(pd);
345bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	} else {
346bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_services_stop(pd, stop_apps, 1);
347bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_timer_add(pd, OZ_TIMER_STOP, jiffies + pd->keep_alive_j, 1);
348bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
349bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return do_stop;
350bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
351bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
352bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
353bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
354bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic struct oz_tx_frame *oz_tx_frame_alloc(struct oz_pd *pd)
355bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
35686b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	struct oz_tx_frame *f = NULL;
357bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_lock_bh(&pd->tx_frame_lock);
358bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (pd->tx_pool) {
359bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		f = container_of(pd->tx_pool, struct oz_tx_frame, link);
360bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->tx_pool = pd->tx_pool->next;
361bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->tx_pool_count--;
362bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
363bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_unlock_bh(&pd->tx_frame_lock);
36486b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	if (f == NULL)
3651ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman		f = kmalloc(sizeof(struct oz_tx_frame), GFP_ATOMIC);
366bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (f) {
367bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		f->total_size = sizeof(struct oz_hdr);
368bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		INIT_LIST_HEAD(&f->link);
369bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		INIT_LIST_HEAD(&f->elt_list);
370bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
371bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return f;
372bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
373bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
374bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
375bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
37633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujarestatic void oz_tx_isoc_free(struct oz_pd *pd, struct oz_tx_frame *f)
37733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare{
37833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	pd->nb_queued_isoc_frames--;
37933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	list_del_init(&f->link);
38033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	if (pd->tx_pool_count < OZ_MAX_TX_POOL_SIZE) {
38133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		f->link.next = pd->tx_pool;
38233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		pd->tx_pool = &f->link;
38333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		pd->tx_pool_count++;
38433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	} else {
38533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		kfree(f);
38633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	}
38733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	oz_trace2(OZ_TRACE_TX_FRAMES, "Releasing ISOC Frame isoc_nb= %d\n",
38833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare						pd->nb_queued_isoc_frames);
38933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare}
39033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare/*------------------------------------------------------------------------------
39133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare * Context: softirq or process
39233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare */
393bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_tx_frame_free(struct oz_pd *pd, struct oz_tx_frame *f)
394bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
395bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_lock_bh(&pd->tx_frame_lock);
396bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (pd->tx_pool_count < OZ_MAX_TX_POOL_SIZE) {
397bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		f->link.next = pd->tx_pool;
398bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->tx_pool = &f->link;
399bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->tx_pool_count++;
40086b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe		f = NULL;
401bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
402bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_unlock_bh(&pd->tx_frame_lock);
403b150718ecb6468d2de1ff593c402ec257dd80c8cSachin Kamat	kfree(f);
404bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
405bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
40633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare * Context: softirq-serialized
40733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare */
408a7f74c3005cf6830a20d71c4e1d8d6d77443e5cbPeter Huewestatic void oz_set_more_bit(struct sk_buff *skb)
40933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare{
41033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	struct oz_hdr *oz_hdr = (struct oz_hdr *)skb_network_header(skb);
41133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	oz_hdr->control |= OZ_F_MORE_DATA;
41233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare}
41333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare/*------------------------------------------------------------------------------
41400ec12b827d2f99202e0c9d804514aef2febf8d6Rupesh Gujare * Context: softirq-serialized
41500ec12b827d2f99202e0c9d804514aef2febf8d6Rupesh Gujare */
416a7f74c3005cf6830a20d71c4e1d8d6d77443e5cbPeter Huewestatic void oz_set_last_pkt_nb(struct oz_pd *pd, struct sk_buff *skb)
41700ec12b827d2f99202e0c9d804514aef2febf8d6Rupesh Gujare{
41800ec12b827d2f99202e0c9d804514aef2febf8d6Rupesh Gujare	struct oz_hdr *oz_hdr = (struct oz_hdr *)skb_network_header(skb);
41900ec12b827d2f99202e0c9d804514aef2febf8d6Rupesh Gujare	oz_hdr->last_pkt_num = pd->trigger_pkt_num & OZ_LAST_PN_MASK;
42000ec12b827d2f99202e0c9d804514aef2febf8d6Rupesh Gujare}
42100ec12b827d2f99202e0c9d804514aef2febf8d6Rupesh Gujare/*------------------------------------------------------------------------------
422bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
423bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
424bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyint oz_prepare_frame(struct oz_pd *pd, int empty)
425bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
426bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_tx_frame *f;
427bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if ((pd->mode & OZ_MODE_MASK) != OZ_MODE_TRIGGERED)
428bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return -1;
429bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (pd->nb_queued_frames >= OZ_MAX_QUEUED_FRAMES)
430bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return -1;
431bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (!empty && !oz_are_elts_available(&pd->elt_buff))
432bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return -1;
433bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	f = oz_tx_frame_alloc(pd);
43486b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	if (f == NULL)
435bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return -1;
43633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	f->skb = NULL;
437bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	f->hdr.control =
438bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		(OZ_PROTOCOL_VERSION<<OZ_VERSION_SHIFT) | OZ_F_ACK_REQUESTED;
439bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	++pd->last_tx_pkt_num;
440bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	put_unaligned(cpu_to_le32(pd->last_tx_pkt_num), &f->hdr.pkt_num);
441bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (empty == 0) {
442bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_select_elts_for_tx(&pd->elt_buff, 0, &f->total_size,
443bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			pd->max_tx_size, &f->elt_list);
444bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
445bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_lock(&pd->tx_frame_lock);
446bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	list_add_tail(&f->link, &pd->tx_queue);
447bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	pd->nb_queued_frames++;
448bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_unlock(&pd->tx_frame_lock);
449bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return 0;
450bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
451bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
452bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq-serialized
453bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
454bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic struct sk_buff *oz_build_frame(struct oz_pd *pd, struct oz_tx_frame *f)
455bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
45686b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	struct sk_buff *skb;
457bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct net_device *dev = pd->net_dev;
458bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_hdr *oz_hdr;
459bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_elt *elt;
460bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct list_head *e;
461bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Allocate skb with enough space for the lower layers as well
462bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	 * as the space we need.
463bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	 */
464ec0ee957f657b6200a2629d4c54df68d2c622e12Greg Kroah-Hartman	skb = alloc_skb(f->total_size + OZ_ALLOCATED_SPACE(dev), GFP_ATOMIC);
46586b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	if (skb == NULL)
46686b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe		return NULL;
467bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Reserve the head room for lower layers.
468bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	 */
469bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb_reserve(skb, LL_RESERVED_SPACE(dev));
470bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb_reset_network_header(skb);
471bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb->dev = dev;
472bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb->protocol = htons(OZ_ETHERTYPE);
473bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (dev_hard_header(skb, dev, OZ_ETHERTYPE, pd->mac_addr,
474bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		dev->dev_addr, skb->len) < 0)
475bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		goto fail;
476bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Push the tail to the end of the area we are going to copy to.
477bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	 */
478bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_hdr = (struct oz_hdr *)skb_put(skb, f->total_size);
479bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	f->hdr.last_pkt_num = pd->trigger_pkt_num & OZ_LAST_PN_MASK;
480bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	memcpy(oz_hdr, &f->hdr, sizeof(struct oz_hdr));
481bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Copy the elements into the frame body.
482bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	 */
483bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	elt = (struct oz_elt *)(oz_hdr+1);
484bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	for (e = f->elt_list.next; e != &f->elt_list; e = e->next) {
485bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		struct oz_elt_info *ei;
486bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		ei = container_of(e, struct oz_elt_info, link);
487bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		memcpy(elt, ei->data, ei->length);
488bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		elt = oz_next_elt(elt);
489bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
490bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return skb;
491bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyfail:
492dd3cef0f0715b79d29a4b0482117175f44b7d83cGreg Kroah-Hartman	kfree_skb(skb);
49386b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	return NULL;
494bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
495bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
496bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
497bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
498bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_retire_frame(struct oz_pd *pd, struct oz_tx_frame *f)
499bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
500bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct list_head *e;
501bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_elt_info *ei;
502bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	e = f->elt_list.next;
503bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	while (e != &f->elt_list) {
504bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		ei = container_of(e, struct oz_elt_info, link);
505bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		e = e->next;
506bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		list_del_init(&ei->link);
507bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (ei->callback)
508bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			ei->callback(pd, ei->context);
509bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_lock_bh(&pd->elt_buff.lock);
510bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_elt_info_free(&pd->elt_buff, ei);
511bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_unlock_bh(&pd->elt_buff.lock);
512bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
513bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_tx_frame_free(pd, f);
514bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (pd->elt_buff.free_elts > pd->elt_buff.max_free_elts)
515bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_trim_elt_pool(&pd->elt_buff);
516bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
517bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
518bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq-serialized
519bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
52033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujarestatic int oz_send_next_queued_frame(struct oz_pd *pd, int more_data)
521bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
522bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct sk_buff *skb;
523bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_tx_frame *f;
524bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct list_head *e;
525bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_lock(&pd->tx_frame_lock);
526bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	e = pd->last_sent_frame->next;
527bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (e == &pd->tx_queue) {
528bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_unlock(&pd->tx_frame_lock);
529bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return -1;
530bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
531bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	f = container_of(e, struct oz_tx_frame, link);
53233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
53333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	if (f->skb != NULL) {
53433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		skb = f->skb;
53533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		oz_tx_isoc_free(pd, f);
53633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		spin_unlock(&pd->tx_frame_lock);
53733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		if (more_data)
53833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			oz_set_more_bit(skb);
53900ec12b827d2f99202e0c9d804514aef2febf8d6Rupesh Gujare		oz_set_last_pkt_nb(pd, skb);
54033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		if ((int)atomic_read(&g_submitted_isoc) <
54133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare							OZ_MAX_SUBMITTED_ISOC) {
54233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			if (dev_queue_xmit(skb) < 0) {
54333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				oz_trace2(OZ_TRACE_TX_FRAMES,
54433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare						"Dropping ISOC Frame\n");
54533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				return -1;
54633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			}
54733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			atomic_inc(&g_submitted_isoc);
54833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			oz_trace2(OZ_TRACE_TX_FRAMES,
54933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare					"Sending ISOC Frame, nb_isoc= %d\n",
55033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare						pd->nb_queued_isoc_frames);
55133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			return 0;
55233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		} else {
553dd3cef0f0715b79d29a4b0482117175f44b7d83cGreg Kroah-Hartman			kfree_skb(skb);
55433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			oz_trace2(OZ_TRACE_TX_FRAMES, "Dropping ISOC Frame>\n");
55533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			return -1;
55633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		}
55733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	}
55833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
55933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	pd->last_sent_frame = e;
560bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb = oz_build_frame(pd, f);
561bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_unlock(&pd->tx_frame_lock);
56233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	if (more_data)
56333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		oz_set_more_bit(skb);
564bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_trace2(OZ_TRACE_TX_FRAMES, "TX frame PN=0x%x\n", f->hdr.pkt_num);
565bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (skb) {
566bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (dev_queue_xmit(skb) < 0)
567bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			return -1;
56833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
569bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
570bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return 0;
571bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
572bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
573bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq-serialized
574bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
575bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_send_queued_frames(struct oz_pd *pd, int backlog)
576bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
57733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	while (oz_prepare_frame(pd, 0) >= 0)
57833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		backlog++;
57933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
58033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	switch (pd->mode & (OZ_F_ISOC_NO_ELTS | OZ_F_ISOC_ANYTIME)) {
58133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
58233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		case OZ_F_ISOC_NO_ELTS: {
58333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			backlog += pd->nb_queued_isoc_frames;
58433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			if (backlog <= 0)
58533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				goto out;
58633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			if (backlog > OZ_MAX_SUBMITTED_ISOC)
58733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				backlog = OZ_MAX_SUBMITTED_ISOC;
58833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			break;
589bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		}
59033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		case OZ_NO_ELTS_ANYTIME: {
59133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			if ((backlog <= 0) && (pd->isoc_sent == 0))
59233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				goto out;
59333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			break;
59433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		}
59533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		default: {
59633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			if (backlog <= 0)
59733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				goto out;
59833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			break;
59933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		}
60033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	}
60133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	while (backlog--) {
60233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		if (oz_send_next_queued_frame(pd, backlog) < 0)
60333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			break;
604bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
60533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	return;
60633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
60733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujareout:	oz_prepare_frame(pd, 1);
60833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	oz_send_next_queued_frame(pd, 0);
609bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
610bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
611bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
612bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
613bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic int oz_send_isoc_frame(struct oz_pd *pd)
614bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
61586b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	struct sk_buff *skb;
616bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct net_device *dev = pd->net_dev;
617bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_hdr *oz_hdr;
618bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_elt *elt;
619bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct list_head *e;
620bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct list_head list;
621bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	int total_size = sizeof(struct oz_hdr);
622bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	INIT_LIST_HEAD(&list);
623bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly
624bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_select_elts_for_tx(&pd->elt_buff, 1, &total_size,
625bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->max_tx_size, &list);
626bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (list.next == &list)
627bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return 0;
628ec0ee957f657b6200a2629d4c54df68d2c622e12Greg Kroah-Hartman	skb = alloc_skb(total_size + OZ_ALLOCATED_SPACE(dev), GFP_ATOMIC);
62986b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	if (skb == NULL) {
630bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_trace("Cannot alloc skb\n");
631bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_elt_info_free_chain(&pd->elt_buff, &list);
632bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return -1;
633bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
634bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb_reserve(skb, LL_RESERVED_SPACE(dev));
635bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb_reset_network_header(skb);
636bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb->dev = dev;
637bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb->protocol = htons(OZ_ETHERTYPE);
638bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (dev_hard_header(skb, dev, OZ_ETHERTYPE, pd->mac_addr,
639bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		dev->dev_addr, skb->len) < 0) {
640dd3cef0f0715b79d29a4b0482117175f44b7d83cGreg Kroah-Hartman		kfree_skb(skb);
641bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return -1;
642bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
643bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_hdr = (struct oz_hdr *)skb_put(skb, total_size);
644bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_hdr->control = (OZ_PROTOCOL_VERSION<<OZ_VERSION_SHIFT) | OZ_F_ISOC;
645bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_hdr->last_pkt_num = pd->trigger_pkt_num & OZ_LAST_PN_MASK;
646bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	elt = (struct oz_elt *)(oz_hdr+1);
647bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly
648bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	for (e = list.next; e != &list; e = e->next) {
649bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		struct oz_elt_info *ei;
650bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		ei = container_of(e, struct oz_elt_info, link);
651bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		memcpy(elt, ei->data, ei->length);
652bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		elt = oz_next_elt(elt);
653bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
654bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	dev_queue_xmit(skb);
655bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_elt_info_free_chain(&pd->elt_buff, &list);
656bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return 0;
657bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
658bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
659bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq-serialized
660bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
661bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_retire_tx_frames(struct oz_pd *pd, u8 lpn)
662bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
663bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct list_head *e;
664bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_tx_frame *f;
66586b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	struct list_head *first = NULL;
66686b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	struct list_head *last = NULL;
667bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	u8 diff;
668bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	u32 pkt_num;
669bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly
670bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_lock(&pd->tx_frame_lock);
671bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	e = pd->tx_queue.next;
672bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	while (e != &pd->tx_queue) {
673bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		f = container_of(e, struct oz_tx_frame, link);
674bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pkt_num = le32_to_cpu(get_unaligned(&f->hdr.pkt_num));
675bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		diff = (lpn - (pkt_num & OZ_LAST_PN_MASK)) & OZ_LAST_PN_MASK;
67633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		if ((diff > OZ_LAST_PN_HALF_CYCLE) || (pkt_num == 0))
677bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			break;
67833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		oz_trace2(OZ_TRACE_TX_FRAMES, "Releasing pkt_num= %u, nb= %d\n",
67933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare						 pkt_num, pd->nb_queued_frames);
68086b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe		if (first == NULL)
681bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			first = e;
682bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		last = e;
683bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		e = e->next;
684bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->nb_queued_frames--;
685bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
686bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (first) {
687bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		last->next->prev = &pd->tx_queue;
688bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->tx_queue.next = last->next;
68986b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe		last->next = NULL;
690bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
691bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	pd->last_sent_frame = &pd->tx_queue;
692bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_unlock(&pd->tx_frame_lock);
693bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	while (first) {
694bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		f = container_of(first, struct oz_tx_frame, link);
695bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		first = first->next;
696bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_retire_frame(pd, f);
697bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
698bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
699bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
700bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Precondition: stream_lock must be held.
701bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
702bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
703bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic struct oz_isoc_stream *pd_stream_find(struct oz_pd *pd, u8 ep_num)
704bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
705bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct list_head *e;
706bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_isoc_stream *st;
707bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	list_for_each(e, &pd->stream_list) {
708bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		st = container_of(e, struct oz_isoc_stream, link);
709bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (st->ep_num == ep_num)
710bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			return st;
711bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
71286b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	return NULL;
713bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
714bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
715bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
716bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
717bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyint oz_isoc_stream_create(struct oz_pd *pd, u8 ep_num)
718bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
719bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_isoc_stream *st =
7201ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman		kzalloc(sizeof(struct oz_isoc_stream), GFP_ATOMIC);
721bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (!st)
7221ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman		return -ENOMEM;
723bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	st->ep_num = ep_num;
724bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_lock_bh(&pd->stream_lock);
725bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (!pd_stream_find(pd, ep_num)) {
726bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		list_add(&st->link, &pd->stream_list);
72786b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe		st = NULL;
728bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
729bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_unlock_bh(&pd->stream_lock);
730b150718ecb6468d2de1ff593c402ec257dd80c8cSachin Kamat	kfree(st);
731bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return 0;
732bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
733bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
734bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
735bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
736bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_isoc_stream_free(struct oz_isoc_stream *st)
737bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
738dd3cef0f0715b79d29a4b0482117175f44b7d83cGreg Kroah-Hartman	kfree_skb(st->skb);
7391ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman	kfree(st);
740bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
741bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
742bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
743bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
744bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyint oz_isoc_stream_delete(struct oz_pd *pd, u8 ep_num)
745bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
746bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_isoc_stream *st;
747bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_lock_bh(&pd->stream_lock);
748bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	st = pd_stream_find(pd, ep_num);
749bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (st)
750bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		list_del(&st->link);
751bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_unlock_bh(&pd->stream_lock);
752bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (st)
753bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_isoc_stream_free(st);
754bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return 0;
755bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
756bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
757bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: any
758bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
759bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_isoc_destructor(struct sk_buff *skb)
760bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
761bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	atomic_dec(&g_submitted_isoc);
762bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
763bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
764bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
765bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
766dc7f5b3594fdb846890192fd75793a791d7ba83bPeter Hueweint oz_send_isoc_unit(struct oz_pd *pd, u8 ep_num, const u8 *data, int len)
767bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
768bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct net_device *dev = pd->net_dev;
769bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_isoc_stream *st;
770bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	u8 nb_units = 0;
77186b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	struct sk_buff *skb = NULL;
77286b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	struct oz_hdr *oz_hdr = NULL;
773bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	int size = 0;
774bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_lock_bh(&pd->stream_lock);
775bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	st = pd_stream_find(pd, ep_num);
776bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (st) {
777bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		skb = st->skb;
77886b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe		st->skb = NULL;
779bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		nb_units = st->nb_units;
780bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		st->nb_units = 0;
781bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_hdr = st->oz_hdr;
782bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		size = st->size;
783bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
784bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_unlock_bh(&pd->stream_lock);
785bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (!st)
786bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return 0;
787bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (!skb) {
788bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		/* Allocate enough space for max size frame. */
789ec0ee957f657b6200a2629d4c54df68d2c622e12Greg Kroah-Hartman		skb = alloc_skb(pd->max_tx_size + OZ_ALLOCATED_SPACE(dev),
790ec0ee957f657b6200a2629d4c54df68d2c622e12Greg Kroah-Hartman				GFP_ATOMIC);
79186b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe		if (skb == NULL)
792bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			return 0;
793bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		/* Reserve the head room for lower layers. */
794bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		skb_reserve(skb, LL_RESERVED_SPACE(dev));
795bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		skb_reset_network_header(skb);
796bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		skb->dev = dev;
797bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		skb->protocol = htons(OZ_ETHERTYPE);
79886c948b4416b4c2c064d6c7e15476afbc04e2bf5Rupesh Gujare		/* For audio packet set priority to AC_VO */
79986c948b4416b4c2c064d6c7e15476afbc04e2bf5Rupesh Gujare		skb->priority = 0x7;
800bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		size = sizeof(struct oz_hdr) + sizeof(struct oz_isoc_large);
801bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_hdr = (struct oz_hdr *)skb_put(skb, size);
802bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
803bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	memcpy(skb_put(skb, len), data, len);
804bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	size += len;
805bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (++nb_units < pd->ms_per_isoc) {
806bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_lock_bh(&pd->stream_lock);
807bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		st->skb = skb;
808bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		st->nb_units = nb_units;
809bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		st->oz_hdr = oz_hdr;
810bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		st->size = size;
811bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_unlock_bh(&pd->stream_lock);
812bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	} else {
813bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		struct oz_hdr oz;
814bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		struct oz_isoc_large iso;
815bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_lock_bh(&pd->stream_lock);
816bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		iso.frame_number = st->frame_num;
817bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		st->frame_num += nb_units;
818bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_unlock_bh(&pd->stream_lock);
819bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz.control =
820bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			(OZ_PROTOCOL_VERSION<<OZ_VERSION_SHIFT) | OZ_F_ISOC;
821bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz.last_pkt_num = pd->trigger_pkt_num & OZ_LAST_PN_MASK;
822bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz.pkt_num = 0;
823bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		iso.endpoint = ep_num;
824bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		iso.format = OZ_DATA_F_ISOC_LARGE;
825bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		iso.ms_data = nb_units;
826bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		memcpy(oz_hdr, &oz, sizeof(oz));
827bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		memcpy(oz_hdr+1, &iso, sizeof(iso));
828bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (dev_hard_header(skb, dev, OZ_ETHERTYPE, pd->mac_addr,
82933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				dev->dev_addr, skb->len) < 0)
83033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			goto out;
83133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
83233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		skb->destructor = oz_isoc_destructor;
83333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		/*Queue for Xmit if mode is not ANYTIME*/
83433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		if (!(pd->mode & OZ_F_ISOC_ANYTIME)) {
83533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			struct oz_tx_frame *isoc_unit = NULL;
83633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			int nb = pd->nb_queued_isoc_frames;
83786d03a0f4f575dda7988800a3da8d6e9f776a819Rupesh Gujare			if (nb >= pd->isoc_latency) {
83833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				oz_trace2(OZ_TRACE_TX_FRAMES,
83933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare						"Dropping ISOC Unit nb= %d\n",
84033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare									nb);
84133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				goto out;
84233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			}
84333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			isoc_unit = oz_tx_frame_alloc(pd);
84433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			if (isoc_unit == NULL)
84533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				goto out;
84633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			isoc_unit->hdr = oz;
84733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			isoc_unit->skb = skb;
84833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			spin_lock_bh(&pd->tx_frame_lock);
84933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			list_add_tail(&isoc_unit->link, &pd->tx_queue);
85033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			pd->nb_queued_isoc_frames++;
85133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			spin_unlock_bh(&pd->tx_frame_lock);
85233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			oz_trace2(OZ_TRACE_TX_FRAMES,
85333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			"Added ISOC Frame to Tx Queue isoc_nb= %d, nb= %d\n",
85433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			pd->nb_queued_isoc_frames, pd->nb_queued_frames);
85533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			return 0;
856bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		}
85733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
85833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		/*In ANYTIME mode Xmit unit immediately*/
859bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (atomic_read(&g_submitted_isoc) < OZ_MAX_SUBMITTED_ISOC) {
860bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			atomic_inc(&g_submitted_isoc);
861255ece7c4d9e63e2a5e784247bc2e7b639cae4ddRupesh Gujare			if (dev_queue_xmit(skb) < 0)
862bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly				return -1;
863255ece7c4d9e63e2a5e784247bc2e7b639cae4ddRupesh Gujare			else
86433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				return 0;
865bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		}
86633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
867255ece7c4d9e63e2a5e784247bc2e7b639cae4ddRupesh Gujareout:	kfree_skb(skb);
86833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	return -1;
86933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
870bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
871bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return 0;
872bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
873bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
874bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: process
875bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
876bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_apps_init(void)
877bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
878bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	int i;
879bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	for (i = 0; i < OZ_APPID_MAX; i++)
880bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (g_app_if[i].init)
881bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			g_app_if[i].init();
882bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
883bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
884bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: process
885bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
886bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_apps_term(void)
887bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
888bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	int i;
889bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Terminate all the apps. */
890bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	for (i = 0; i < OZ_APPID_MAX; i++)
891bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (g_app_if[i].term)
892bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			g_app_if[i].term();
893bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
894bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
895bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq-serialized
896bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
897bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_handle_app_elt(struct oz_pd *pd, u8 app_id, struct oz_elt *elt)
898bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
899dc7f5b3594fdb846890192fd75793a791d7ba83bPeter Huewe	const struct oz_app_if *ai;
90092a6253299d74833a36edb94d5a4bc541418b17aDan Carpenter	if (app_id == 0 || app_id > OZ_APPID_MAX)
901bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return;
902bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	ai = &g_app_if[app_id-1];
903bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	ai->rx(pd, elt);
904bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
905bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
906bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
907bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
908bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_pd_indicate_farewells(struct oz_pd *pd)
909bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
910bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_farewell *f;
911dc7f5b3594fdb846890192fd75793a791d7ba83bPeter Huewe	const struct oz_app_if *ai = &g_app_if[OZ_APPID_USB-1];
912bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	while (1) {
913bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_polling_lock_bh();
914bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (list_empty(&pd->farewell_list)) {
915bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			oz_polling_unlock_bh();
916bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			break;
917bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		}
918bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		f = list_first_entry(&pd->farewell_list,
919bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly				struct oz_farewell, link);
920bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		list_del(&f->link);
921bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_polling_unlock_bh();
922bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (ai->farewell)
923bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			ai->farewell(pd, f->ep_num, f->report, f->len);
9241ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman		kfree(f);
925bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
926bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
927