[go: nahoru, domu]

ozpd.c revision 05f608f237dcc3c4e5188d054d9918cbfd2916c2
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 */
605f608f237dcc3c4e5188d054d9918cbfd2916c2Joe Perches
7bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly#include <linux/init.h>
8bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly#include <linux/module.h>
9bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly#include <linux/timer.h>
10bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly#include <linux/sched.h>
11bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly#include <linux/netdevice.h>
12bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly#include <linux/errno.h>
13f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches#include "ozdbg.h"
14bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly#include "ozprotocol.h"
15bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly#include "ozeltbuf.h"
16bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly#include "ozpd.h"
17bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly#include "ozproto.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>
2305f608f237dcc3c4e5188d054d9918cbfd2916c2Joe Perches
24bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
25bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
26bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly#define OZ_MAX_TX_POOL_SIZE	6
27bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
28bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
29bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic struct oz_tx_frame *oz_tx_frame_alloc(struct oz_pd *pd);
30bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_tx_frame_free(struct oz_pd *pd, struct oz_tx_frame *f);
3133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujarestatic void oz_tx_isoc_free(struct oz_pd *pd, struct oz_tx_frame *f);
32bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic struct sk_buff *oz_build_frame(struct oz_pd *pd, struct oz_tx_frame *f);
33bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic int oz_send_isoc_frame(struct oz_pd *pd);
34bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_retire_frame(struct oz_pd *pd, struct oz_tx_frame *f);
35bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_isoc_stream_free(struct oz_isoc_stream *st);
3633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujarestatic int oz_send_next_queued_frame(struct oz_pd *pd, int more_data);
37bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_isoc_destructor(struct sk_buff *skb);
38bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic int oz_def_app_init(void);
39bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_def_app_term(void);
40bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic int oz_def_app_start(struct oz_pd *pd, int resume);
41bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_def_app_stop(struct oz_pd *pd, int pause);
42bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_def_app_rx(struct oz_pd *pd, struct oz_elt *elt);
43bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
44bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Counts the uncompleted isoc frames submitted to netcard.
45bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
46bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic atomic_t g_submitted_isoc = ATOMIC_INIT(0);
47bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/* Application handler functions.
48bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
49dc7f5b3594fdb846890192fd75793a791d7ba83bPeter Huewestatic const struct oz_app_if g_app_if[OZ_APPID_MAX] = {
50bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	{oz_usb_init,
51bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_usb_term,
52bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_usb_start,
53bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_usb_stop,
54bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_usb_rx,
55bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_usb_heartbeat,
56bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_usb_farewell,
57bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	OZ_APPID_USB},
58bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly
59bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	{oz_def_app_init,
60bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_def_app_term,
61bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_def_app_start,
62bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_def_app_stop,
63bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_def_app_rx,
6486b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	NULL,
6586b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	NULL,
66bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	OZ_APPID_UNUSED1},
67bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly
68bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	{oz_def_app_init,
69bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_def_app_term,
70bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_def_app_start,
71bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_def_app_stop,
72bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_def_app_rx,
7386b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	NULL,
7486b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	NULL,
75bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	OZ_APPID_UNUSED2},
76bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly
77bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	{oz_cdev_init,
78bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_cdev_term,
79bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_cdev_start,
80bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_cdev_stop,
81bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_cdev_rx,
8286b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	NULL,
8386b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	NULL,
84bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	OZ_APPID_SERIAL},
85bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly};
86bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
87bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: process
88bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
89bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic int oz_def_app_init(void)
90bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
91bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return 0;
92bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
93bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
94bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: process
95bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
96bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_def_app_term(void)
97bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
98bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
99bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
100bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
101bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
102bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic int oz_def_app_start(struct oz_pd *pd, int resume)
103bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
104bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return 0;
105bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
106bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
107bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
108bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
109bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_def_app_stop(struct oz_pd *pd, int pause)
110bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
111bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
112bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
113bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
114bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
115bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_def_app_rx(struct oz_pd *pd, struct oz_elt *elt)
116bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
117bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
118bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
119bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
120bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
121bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_pd_set_state(struct oz_pd *pd, unsigned state)
122bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
123bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	pd->state = state;
124bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	switch (state) {
125bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	case OZ_PD_S_IDLE:
126f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches		oz_pd_dbg(pd, ON, "PD State: OZ_PD_S_IDLE\n");
127bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		break;
128bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	case OZ_PD_S_CONNECTED:
129f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches		oz_pd_dbg(pd, ON, "PD State: OZ_PD_S_CONNECTED\n");
130bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		break;
131bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	case OZ_PD_S_STOPPED:
132f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches		oz_pd_dbg(pd, ON, "PD State: OZ_PD_S_STOPPED\n");
133bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		break;
134bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	case OZ_PD_S_SLEEP:
135f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches		oz_pd_dbg(pd, ON, "PD State: OZ_PD_S_SLEEP\n");
136bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		break;
137bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
138bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
139bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
140bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
141bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
142bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_pd_get(struct oz_pd *pd)
143bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
144bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	atomic_inc(&pd->ref_count);
145bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
146bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
147bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
148bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
149bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_pd_put(struct oz_pd *pd)
150bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
151bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (atomic_dec_and_test(&pd->ref_count))
152bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_pd_destroy(pd);
153bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
154bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
155bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq-serialized
156bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
157dc7f5b3594fdb846890192fd75793a791d7ba83bPeter Huewestruct oz_pd *oz_pd_alloc(const u8 *mac_addr)
158bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
1591ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman	struct oz_pd *pd = kzalloc(sizeof(struct oz_pd), GFP_ATOMIC);
160bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (pd) {
161bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		int i;
162bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		atomic_set(&pd->ref_count, 2);
163bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		for (i = 0; i < OZ_APPID_MAX; i++)
164bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			spin_lock_init(&pd->app_lock[i]);
165bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->last_rx_pkt_num = 0xffffffff;
166bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_pd_set_state(pd, OZ_PD_S_IDLE);
167bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->max_tx_size = OZ_MAX_TX_SIZE;
168bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		memcpy(pd->mac_addr, mac_addr, ETH_ALEN);
169bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (0 != oz_elt_buf_init(&pd->elt_buff)) {
1701ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman			kfree(pd);
17186b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe			pd = NULL;
172bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		}
173bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_lock_init(&pd->tx_frame_lock);
174bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		INIT_LIST_HEAD(&pd->tx_queue);
175bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		INIT_LIST_HEAD(&pd->farewell_list);
176bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->last_sent_frame = &pd->tx_queue;
177bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_lock_init(&pd->stream_lock);
178bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		INIT_LIST_HEAD(&pd->stream_list);
179bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
180bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return pd;
181bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
182bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
183bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
184bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
185bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_pd_destroy(struct oz_pd *pd)
186bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
187bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct list_head *e;
188bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_tx_frame *f;
189bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_isoc_stream *st;
190bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_farewell *fwell;
191f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches	oz_pd_dbg(pd, ON, "Destroying PD\n");
192bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Delete any streams.
193bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	 */
194bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	e = pd->stream_list.next;
195bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	while (e != &pd->stream_list) {
196bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		st = container_of(e, struct oz_isoc_stream, link);
197bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		e = e->next;
198bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_isoc_stream_free(st);
199bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
200bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Free any queued tx frames.
201bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	 */
202bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	e = pd->tx_queue.next;
203bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	while (e != &pd->tx_queue) {
204bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		f = container_of(e, struct oz_tx_frame, link);
205bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		e = e->next;
20633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		if (f->skb != NULL)
207dd3cef0f0715b79d29a4b0482117175f44b7d83cGreg Kroah-Hartman			kfree_skb(f->skb);
208bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_retire_frame(pd, f);
209bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
210bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_elt_buf_term(&pd->elt_buff);
211bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Free any farewells.
212bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	 */
213bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	e = pd->farewell_list.next;
214bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	while (e != &pd->farewell_list) {
215bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		fwell = container_of(e, struct oz_farewell, link);
216bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		e = e->next;
2171ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman		kfree(fwell);
218bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
219bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Deallocate all frames in tx pool.
220bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	 */
221bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	while (pd->tx_pool) {
222bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		e = pd->tx_pool;
223bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->tx_pool = e->next;
2241ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman		kfree(container_of(e, struct oz_tx_frame, link));
225bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
226bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (pd->net_dev)
227bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		dev_put(pd->net_dev);
2281ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman	kfree(pd);
229bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
230bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
231bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq-serialized
232bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
233bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyint oz_services_start(struct oz_pd *pd, u16 apps, int resume)
234bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
235dc7f5b3594fdb846890192fd75793a791d7ba83bPeter Huewe	const struct oz_app_if *ai;
236bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	int rc = 0;
237f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches	oz_pd_dbg(pd, ON, "%s: (0x%x) resume(%d)\n", __func__, apps, resume);
238bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	for (ai = g_app_if; ai < &g_app_if[OZ_APPID_MAX]; ai++) {
239bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (apps & (1<<ai->app_id)) {
240bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			if (ai->start(pd, resume)) {
241bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly				rc = -1;
242f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches				oz_pd_dbg(pd, ON,
243f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches					  "Unable to start service %d\n",
244f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches					  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;
262f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches	oz_pd_dbg(pd, ON, "%s: (0x%x) pause(%d)\n", __func__, 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;
304f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches	oz_dbg(ON, "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();
317f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches	oz_dbg(ON, "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;
336f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches		oz_dbg(ON, "Sleep Now %lu until %lu\n",
337f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches		       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	}
387f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches	oz_dbg(TX_FRAMES, "Releasing ISOC Frame isoc_nb= %d\n",
388f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches	       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) {
543f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches				oz_dbg(TX_FRAMES, "Dropping ISOC Frame\n");
54433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				return -1;
54533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			}
54633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			atomic_inc(&g_submitted_isoc);
547f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches			oz_dbg(TX_FRAMES, "Sending ISOC Frame, nb_isoc= %d\n",
548f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches			       pd->nb_queued_isoc_frames);
54933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			return 0;
55033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		} else {
551dd3cef0f0715b79d29a4b0482117175f44b7d83cGreg Kroah-Hartman			kfree_skb(skb);
552f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches			oz_dbg(TX_FRAMES, "Dropping ISOC Frame>\n");
55333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			return -1;
55433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		}
55533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	}
55633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
55733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	pd->last_sent_frame = e;
558bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb = oz_build_frame(pd, f);
559bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_unlock(&pd->tx_frame_lock);
56033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	if (more_data)
56133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		oz_set_more_bit(skb);
562f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches	oz_dbg(TX_FRAMES, "TX frame PN=0x%x\n", f->hdr.pkt_num);
563bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (skb) {
564bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (dev_queue_xmit(skb) < 0)
565bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			return -1;
56633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
567bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
568bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return 0;
569bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
570bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
571bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq-serialized
572bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
573bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_send_queued_frames(struct oz_pd *pd, int backlog)
574bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
57533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	while (oz_prepare_frame(pd, 0) >= 0)
57633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		backlog++;
57733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
57833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	switch (pd->mode & (OZ_F_ISOC_NO_ELTS | OZ_F_ISOC_ANYTIME)) {
57933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
58033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		case OZ_F_ISOC_NO_ELTS: {
58133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			backlog += pd->nb_queued_isoc_frames;
58233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			if (backlog <= 0)
58333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				goto out;
58433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			if (backlog > OZ_MAX_SUBMITTED_ISOC)
58533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				backlog = OZ_MAX_SUBMITTED_ISOC;
58633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			break;
587bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		}
58833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		case OZ_NO_ELTS_ANYTIME: {
58933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			if ((backlog <= 0) && (pd->isoc_sent == 0))
59033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				goto out;
59133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			break;
59233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		}
59333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		default: {
59433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			if (backlog <= 0)
59533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				goto out;
59633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			break;
59733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		}
59833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	}
59933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	while (backlog--) {
60033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		if (oz_send_next_queued_frame(pd, backlog) < 0)
60133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			break;
602bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
60333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	return;
60433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
60533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujareout:	oz_prepare_frame(pd, 1);
60633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	oz_send_next_queued_frame(pd, 0);
607bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
608bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
609bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
610bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
611bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic int oz_send_isoc_frame(struct oz_pd *pd)
612bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
61386b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	struct sk_buff *skb;
614bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct net_device *dev = pd->net_dev;
615bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_hdr *oz_hdr;
616bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_elt *elt;
617bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct list_head *e;
618bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct list_head list;
619bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	int total_size = sizeof(struct oz_hdr);
620bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	INIT_LIST_HEAD(&list);
621bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly
622bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_select_elts_for_tx(&pd->elt_buff, 1, &total_size,
623bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->max_tx_size, &list);
624bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (list.next == &list)
625bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return 0;
626ec0ee957f657b6200a2629d4c54df68d2c622e12Greg Kroah-Hartman	skb = alloc_skb(total_size + OZ_ALLOCATED_SPACE(dev), GFP_ATOMIC);
62786b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	if (skb == NULL) {
628f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches		oz_dbg(ON, "Cannot alloc skb\n");
629bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_elt_info_free_chain(&pd->elt_buff, &list);
630bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return -1;
631bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
632bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb_reserve(skb, LL_RESERVED_SPACE(dev));
633bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb_reset_network_header(skb);
634bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb->dev = dev;
635bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb->protocol = htons(OZ_ETHERTYPE);
636bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (dev_hard_header(skb, dev, OZ_ETHERTYPE, pd->mac_addr,
637bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		dev->dev_addr, skb->len) < 0) {
638dd3cef0f0715b79d29a4b0482117175f44b7d83cGreg Kroah-Hartman		kfree_skb(skb);
639bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return -1;
640bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
641bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_hdr = (struct oz_hdr *)skb_put(skb, total_size);
642bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_hdr->control = (OZ_PROTOCOL_VERSION<<OZ_VERSION_SHIFT) | OZ_F_ISOC;
643bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_hdr->last_pkt_num = pd->trigger_pkt_num & OZ_LAST_PN_MASK;
644bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	elt = (struct oz_elt *)(oz_hdr+1);
645bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly
646bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	for (e = list.next; e != &list; e = e->next) {
647bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		struct oz_elt_info *ei;
648bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		ei = container_of(e, struct oz_elt_info, link);
649bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		memcpy(elt, ei->data, ei->length);
650bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		elt = oz_next_elt(elt);
651bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
652bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	dev_queue_xmit(skb);
653bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_elt_info_free_chain(&pd->elt_buff, &list);
654bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return 0;
655bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
656bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
657bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq-serialized
658bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
659bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_retire_tx_frames(struct oz_pd *pd, u8 lpn)
660bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
661bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct list_head *e;
662bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_tx_frame *f;
66386b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	struct list_head *first = NULL;
66486b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	struct list_head *last = NULL;
665bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	u8 diff;
666bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	u32 pkt_num;
667bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly
668bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_lock(&pd->tx_frame_lock);
669bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	e = pd->tx_queue.next;
670bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	while (e != &pd->tx_queue) {
671bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		f = container_of(e, struct oz_tx_frame, link);
672bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pkt_num = le32_to_cpu(get_unaligned(&f->hdr.pkt_num));
673bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		diff = (lpn - (pkt_num & OZ_LAST_PN_MASK)) & OZ_LAST_PN_MASK;
67433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		if ((diff > OZ_LAST_PN_HALF_CYCLE) || (pkt_num == 0))
675bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			break;
676f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches		oz_dbg(TX_FRAMES, "Releasing pkt_num= %u, nb= %d\n",
677f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches		       pkt_num, pd->nb_queued_frames);
67886b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe		if (first == NULL)
679bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			first = e;
680bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		last = e;
681bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		e = e->next;
682bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->nb_queued_frames--;
683bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
684bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (first) {
685bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		last->next->prev = &pd->tx_queue;
686bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->tx_queue.next = last->next;
68786b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe		last->next = NULL;
688bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
689bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	pd->last_sent_frame = &pd->tx_queue;
690bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_unlock(&pd->tx_frame_lock);
691bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	while (first) {
692bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		f = container_of(first, struct oz_tx_frame, link);
693bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		first = first->next;
694bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_retire_frame(pd, f);
695bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
696bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
697bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
698bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Precondition: stream_lock must be held.
699bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
700bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
701bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic struct oz_isoc_stream *pd_stream_find(struct oz_pd *pd, u8 ep_num)
702bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
703bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct list_head *e;
704bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_isoc_stream *st;
705bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	list_for_each(e, &pd->stream_list) {
706bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		st = container_of(e, struct oz_isoc_stream, link);
707bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (st->ep_num == ep_num)
708bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			return st;
709bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
71086b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	return NULL;
711bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
712bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
713bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
714bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
715bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyint oz_isoc_stream_create(struct oz_pd *pd, u8 ep_num)
716bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
717bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_isoc_stream *st =
7181ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman		kzalloc(sizeof(struct oz_isoc_stream), GFP_ATOMIC);
719bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (!st)
7201ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman		return -ENOMEM;
721bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	st->ep_num = ep_num;
722bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_lock_bh(&pd->stream_lock);
723bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (!pd_stream_find(pd, ep_num)) {
724bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		list_add(&st->link, &pd->stream_list);
72586b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe		st = NULL;
726bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
727bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_unlock_bh(&pd->stream_lock);
728b150718ecb6468d2de1ff593c402ec257dd80c8cSachin Kamat	kfree(st);
729bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return 0;
730bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
731bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
732bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
733bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
734bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_isoc_stream_free(struct oz_isoc_stream *st)
735bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
736dd3cef0f0715b79d29a4b0482117175f44b7d83cGreg Kroah-Hartman	kfree_skb(st->skb);
7371ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman	kfree(st);
738bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
739bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
740bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
741bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
742bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyint oz_isoc_stream_delete(struct oz_pd *pd, u8 ep_num)
743bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
744bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_isoc_stream *st;
745bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_lock_bh(&pd->stream_lock);
746bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	st = pd_stream_find(pd, ep_num);
747bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (st)
748bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		list_del(&st->link);
749bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_unlock_bh(&pd->stream_lock);
750bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (st)
751bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_isoc_stream_free(st);
752bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return 0;
753bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
754bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
755bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: any
756bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
757bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_isoc_destructor(struct sk_buff *skb)
758bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
759bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	atomic_dec(&g_submitted_isoc);
760bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
761bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
762bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
763bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
764dc7f5b3594fdb846890192fd75793a791d7ba83bPeter Hueweint oz_send_isoc_unit(struct oz_pd *pd, u8 ep_num, const u8 *data, int len)
765bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
766bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct net_device *dev = pd->net_dev;
767bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_isoc_stream *st;
768bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	u8 nb_units = 0;
76986b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	struct sk_buff *skb = NULL;
77086b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	struct oz_hdr *oz_hdr = NULL;
771bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	int size = 0;
772bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_lock_bh(&pd->stream_lock);
773bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	st = pd_stream_find(pd, ep_num);
774bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (st) {
775bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		skb = st->skb;
77686b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe		st->skb = NULL;
777bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		nb_units = st->nb_units;
778bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		st->nb_units = 0;
779bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_hdr = st->oz_hdr;
780bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		size = st->size;
781bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
782bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_unlock_bh(&pd->stream_lock);
783bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (!st)
784bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return 0;
785bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (!skb) {
786bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		/* Allocate enough space for max size frame. */
787ec0ee957f657b6200a2629d4c54df68d2c622e12Greg Kroah-Hartman		skb = alloc_skb(pd->max_tx_size + OZ_ALLOCATED_SPACE(dev),
788ec0ee957f657b6200a2629d4c54df68d2c622e12Greg Kroah-Hartman				GFP_ATOMIC);
78986b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe		if (skb == NULL)
790bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			return 0;
791bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		/* Reserve the head room for lower layers. */
792bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		skb_reserve(skb, LL_RESERVED_SPACE(dev));
793bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		skb_reset_network_header(skb);
794bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		skb->dev = dev;
795bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		skb->protocol = htons(OZ_ETHERTYPE);
79686c948b4416b4c2c064d6c7e15476afbc04e2bf5Rupesh Gujare		/* For audio packet set priority to AC_VO */
79786c948b4416b4c2c064d6c7e15476afbc04e2bf5Rupesh Gujare		skb->priority = 0x7;
798bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		size = sizeof(struct oz_hdr) + sizeof(struct oz_isoc_large);
799bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_hdr = (struct oz_hdr *)skb_put(skb, size);
800bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
801bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	memcpy(skb_put(skb, len), data, len);
802bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	size += len;
803bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (++nb_units < pd->ms_per_isoc) {
804bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_lock_bh(&pd->stream_lock);
805bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		st->skb = skb;
806bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		st->nb_units = nb_units;
807bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		st->oz_hdr = oz_hdr;
808bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		st->size = size;
809bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_unlock_bh(&pd->stream_lock);
810bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	} else {
811bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		struct oz_hdr oz;
812bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		struct oz_isoc_large iso;
813bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_lock_bh(&pd->stream_lock);
814bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		iso.frame_number = st->frame_num;
815bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		st->frame_num += nb_units;
816bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_unlock_bh(&pd->stream_lock);
817bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz.control =
818bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			(OZ_PROTOCOL_VERSION<<OZ_VERSION_SHIFT) | OZ_F_ISOC;
819bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz.last_pkt_num = pd->trigger_pkt_num & OZ_LAST_PN_MASK;
820bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz.pkt_num = 0;
821bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		iso.endpoint = ep_num;
822bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		iso.format = OZ_DATA_F_ISOC_LARGE;
823bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		iso.ms_data = nb_units;
824bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		memcpy(oz_hdr, &oz, sizeof(oz));
825bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		memcpy(oz_hdr+1, &iso, sizeof(iso));
826bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (dev_hard_header(skb, dev, OZ_ETHERTYPE, pd->mac_addr,
82733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				dev->dev_addr, skb->len) < 0)
82833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			goto out;
82933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
83033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		skb->destructor = oz_isoc_destructor;
83133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		/*Queue for Xmit if mode is not ANYTIME*/
83233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		if (!(pd->mode & OZ_F_ISOC_ANYTIME)) {
83333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			struct oz_tx_frame *isoc_unit = NULL;
83433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			int nb = pd->nb_queued_isoc_frames;
83586d03a0f4f575dda7988800a3da8d6e9f776a819Rupesh Gujare			if (nb >= pd->isoc_latency) {
836f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches				oz_dbg(TX_FRAMES, "Dropping ISOC Unit nb= %d\n",
837f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches				       nb);
83833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				goto out;
83933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			}
84033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			isoc_unit = oz_tx_frame_alloc(pd);
84133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			if (isoc_unit == NULL)
84233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				goto out;
84333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			isoc_unit->hdr = oz;
84433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			isoc_unit->skb = skb;
84533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			spin_lock_bh(&pd->tx_frame_lock);
84633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			list_add_tail(&isoc_unit->link, &pd->tx_queue);
84733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			pd->nb_queued_isoc_frames++;
84833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			spin_unlock_bh(&pd->tx_frame_lock);
849f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches			oz_dbg(TX_FRAMES,
850f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches			       "Added ISOC Frame to Tx Queue isoc_nb= %d, nb= %d\n",
851f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches			       pd->nb_queued_isoc_frames, pd->nb_queued_frames);
85233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			return 0;
853bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		}
85433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
85533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		/*In ANYTIME mode Xmit unit immediately*/
856bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (atomic_read(&g_submitted_isoc) < OZ_MAX_SUBMITTED_ISOC) {
857bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			atomic_inc(&g_submitted_isoc);
858255ece7c4d9e63e2a5e784247bc2e7b639cae4ddRupesh Gujare			if (dev_queue_xmit(skb) < 0)
859bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly				return -1;
860255ece7c4d9e63e2a5e784247bc2e7b639cae4ddRupesh Gujare			else
86133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				return 0;
862bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		}
86333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
864255ece7c4d9e63e2a5e784247bc2e7b639cae4ddRupesh Gujareout:	kfree_skb(skb);
86533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	return -1;
86633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
867bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
868bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return 0;
869bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
870bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
871bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: process
872bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
873bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_apps_init(void)
874bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
875bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	int i;
876bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	for (i = 0; i < OZ_APPID_MAX; i++)
877bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (g_app_if[i].init)
878bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			g_app_if[i].init();
879bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
880bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
881bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: process
882bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
883bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_apps_term(void)
884bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
885bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	int i;
886bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Terminate all the apps. */
887bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	for (i = 0; i < OZ_APPID_MAX; i++)
888bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (g_app_if[i].term)
889bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			g_app_if[i].term();
890bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
891bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
892bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq-serialized
893bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
894bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_handle_app_elt(struct oz_pd *pd, u8 app_id, struct oz_elt *elt)
895bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
896dc7f5b3594fdb846890192fd75793a791d7ba83bPeter Huewe	const struct oz_app_if *ai;
89792a6253299d74833a36edb94d5a4bc541418b17aDan Carpenter	if (app_id == 0 || app_id > OZ_APPID_MAX)
898bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return;
899bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	ai = &g_app_if[app_id-1];
900bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	ai->rx(pd, elt);
901bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
902bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
903bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
904bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
905bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_pd_indicate_farewells(struct oz_pd *pd)
906bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
907bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_farewell *f;
908dc7f5b3594fdb846890192fd75793a791d7ba83bPeter Huewe	const struct oz_app_if *ai = &g_app_if[OZ_APPID_USB-1];
909bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	while (1) {
910bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_polling_lock_bh();
911bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (list_empty(&pd->farewell_list)) {
912bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			oz_polling_unlock_bh();
913bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			break;
914bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		}
915bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		f = list_first_entry(&pd->farewell_list,
916bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly				struct oz_farewell, link);
917bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		list_del(&f->link);
918bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_polling_unlock_bh();
919bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (ai->farewell)
920bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			ai->farewell(pd, f->ep_num, f->report, f->len);
9211ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman		kfree(f);
922bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
923bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
924