[go: nahoru, domu]

ozpd.c revision f724b5843431aba591a01b6988a725689cd9ebb3
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>
12f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches#include "ozdbg.h"
13bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly#include "ozconfig.h"
14bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly#include "ozprotocol.h"
15bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly#include "ozeltbuf.h"
16bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly#include "ozpd.h"
17bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly#include "ozproto.h"
18bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly#include "oztrace.h"
19bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly#include "ozcdev.h"
20bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly#include "ozusbsvc.h"
21bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly#include <asm/unaligned.h>
22bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly#include <linux/uaccess.h>
23bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly#include <net/psnap.h>
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#ifdef WANT_TRACE
125bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	switch (state) {
126bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	case OZ_PD_S_IDLE:
127f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches		oz_pd_dbg(pd, ON, "PD State: OZ_PD_S_IDLE\n");
128bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		break;
129bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	case OZ_PD_S_CONNECTED:
130f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches		oz_pd_dbg(pd, ON, "PD State: OZ_PD_S_CONNECTED\n");
131bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		break;
132bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	case OZ_PD_S_STOPPED:
133f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches		oz_pd_dbg(pd, ON, "PD State: OZ_PD_S_STOPPED\n");
134bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		break;
135bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	case OZ_PD_S_SLEEP:
136f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches		oz_pd_dbg(pd, ON, "PD State: OZ_PD_S_SLEEP\n");
137bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		break;
138bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
139bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly#endif /* WANT_TRACE */
140bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
141bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
142bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
143bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
144bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_pd_get(struct oz_pd *pd)
145bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
146bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	atomic_inc(&pd->ref_count);
147bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
148bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
149bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
150bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
151bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_pd_put(struct oz_pd *pd)
152bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
153bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (atomic_dec_and_test(&pd->ref_count))
154bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_pd_destroy(pd);
155bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
156bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
157bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq-serialized
158bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
159dc7f5b3594fdb846890192fd75793a791d7ba83bPeter Huewestruct oz_pd *oz_pd_alloc(const u8 *mac_addr)
160bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
1611ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman	struct oz_pd *pd = kzalloc(sizeof(struct oz_pd), GFP_ATOMIC);
162bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (pd) {
163bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		int i;
164bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		atomic_set(&pd->ref_count, 2);
165bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		for (i = 0; i < OZ_APPID_MAX; i++)
166bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			spin_lock_init(&pd->app_lock[i]);
167bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->last_rx_pkt_num = 0xffffffff;
168bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_pd_set_state(pd, OZ_PD_S_IDLE);
169bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->max_tx_size = OZ_MAX_TX_SIZE;
170bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		memcpy(pd->mac_addr, mac_addr, ETH_ALEN);
171bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (0 != oz_elt_buf_init(&pd->elt_buff)) {
1721ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman			kfree(pd);
17386b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe			pd = NULL;
174bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		}
175bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_lock_init(&pd->tx_frame_lock);
176bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		INIT_LIST_HEAD(&pd->tx_queue);
177bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		INIT_LIST_HEAD(&pd->farewell_list);
178bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->last_sent_frame = &pd->tx_queue;
179bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_lock_init(&pd->stream_lock);
180bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		INIT_LIST_HEAD(&pd->stream_list);
181bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
182bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return pd;
183bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
184bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
185bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
186bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
187bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_pd_destroy(struct oz_pd *pd)
188bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
189bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct list_head *e;
190bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_tx_frame *f;
191bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_isoc_stream *st;
192bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_farewell *fwell;
193f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches	oz_pd_dbg(pd, ON, "Destroying PD\n");
194bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Delete any streams.
195bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	 */
196bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	e = pd->stream_list.next;
197bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	while (e != &pd->stream_list) {
198bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		st = container_of(e, struct oz_isoc_stream, link);
199bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		e = e->next;
200bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_isoc_stream_free(st);
201bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
202bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Free any queued tx frames.
203bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	 */
204bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	e = pd->tx_queue.next;
205bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	while (e != &pd->tx_queue) {
206bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		f = container_of(e, struct oz_tx_frame, link);
207bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		e = e->next;
20833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		if (f->skb != NULL)
209dd3cef0f0715b79d29a4b0482117175f44b7d83cGreg Kroah-Hartman			kfree_skb(f->skb);
210bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_retire_frame(pd, f);
211bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
212bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_elt_buf_term(&pd->elt_buff);
213bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Free any farewells.
214bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	 */
215bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	e = pd->farewell_list.next;
216bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	while (e != &pd->farewell_list) {
217bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		fwell = container_of(e, struct oz_farewell, link);
218bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		e = e->next;
2191ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman		kfree(fwell);
220bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
221bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Deallocate all frames in tx pool.
222bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	 */
223bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	while (pd->tx_pool) {
224bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		e = pd->tx_pool;
225bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->tx_pool = e->next;
2261ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman		kfree(container_of(e, struct oz_tx_frame, link));
227bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
228bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (pd->net_dev)
229bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		dev_put(pd->net_dev);
2301ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman	kfree(pd);
231bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
232bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
233bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq-serialized
234bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
235bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyint oz_services_start(struct oz_pd *pd, u16 apps, int resume)
236bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
237dc7f5b3594fdb846890192fd75793a791d7ba83bPeter Huewe	const struct oz_app_if *ai;
238bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	int rc = 0;
239f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches	oz_pd_dbg(pd, ON, "%s: (0x%x) resume(%d)\n", __func__, apps, resume);
240bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	for (ai = g_app_if; ai < &g_app_if[OZ_APPID_MAX]; ai++) {
241bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (apps & (1<<ai->app_id)) {
242bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			if (ai->start(pd, resume)) {
243bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly				rc = -1;
244f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches				oz_pd_dbg(pd, ON,
245f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches					  "Unable to start service %d\n",
246f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches					  ai->app_id);
247bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly				break;
248bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			}
249bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			oz_polling_lock_bh();
250bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			pd->total_apps |= (1<<ai->app_id);
251bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			if (resume)
252bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly				pd->paused_apps &= ~(1<<ai->app_id);
253bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			oz_polling_unlock_bh();
254bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		}
255bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
256bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return rc;
257bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
258bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
259bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
260bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
261bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_services_stop(struct oz_pd *pd, u16 apps, int pause)
262bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
263dc7f5b3594fdb846890192fd75793a791d7ba83bPeter Huewe	const struct oz_app_if *ai;
264f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches	oz_pd_dbg(pd, ON, "%s: (0x%x) pause(%d)\n", __func__, apps, pause);
265bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	for (ai = g_app_if; ai < &g_app_if[OZ_APPID_MAX]; ai++) {
266bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (apps & (1<<ai->app_id)) {
267bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			oz_polling_lock_bh();
268bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			if (pause) {
269bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly				pd->paused_apps |= (1<<ai->app_id);
270bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			} else {
271bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly				pd->total_apps &= ~(1<<ai->app_id);
272bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly				pd->paused_apps &= ~(1<<ai->app_id);
273bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			}
274bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			oz_polling_unlock_bh();
275bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			ai->stop(pd, pause);
276bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		}
277bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
278bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
279bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
280bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
281bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
282bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_pd_heartbeat(struct oz_pd *pd, u16 apps)
283bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
284dc7f5b3594fdb846890192fd75793a791d7ba83bPeter Huewe	const struct oz_app_if *ai;
285bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	int more = 0;
286bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	for (ai = g_app_if; ai < &g_app_if[OZ_APPID_MAX]; ai++) {
287bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (ai->heartbeat && (apps & (1<<ai->app_id))) {
288bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			if (ai->heartbeat(pd))
289bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly				more = 1;
290bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		}
291bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
292bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (more)
293bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_pd_request_heartbeat(pd);
294bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (pd->mode & OZ_F_ISOC_ANYTIME) {
295bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		int count = 8;
296bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		while (count-- && (oz_send_isoc_frame(pd) >= 0))
297bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			;
298bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
299bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
300bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
301bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
302bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
303bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_pd_stop(struct oz_pd *pd)
304bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
305bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	u16 stop_apps = 0;
306f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches	oz_dbg(ON, "oz_pd_stop() State = 0x%x\n", pd->state);
307bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_pd_indicate_farewells(pd);
308bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_polling_lock_bh();
309bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	stop_apps = pd->total_apps;
310bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	pd->total_apps = 0;
311bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	pd->paused_apps = 0;
312bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_polling_unlock_bh();
313bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_services_stop(pd, stop_apps, 0);
314bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_polling_lock_bh();
315bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_pd_set_state(pd, OZ_PD_S_STOPPED);
316bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Remove from PD list.*/
317bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	list_del(&pd->link);
318bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_polling_unlock_bh();
319f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches	oz_dbg(ON, "pd ref count = %d\n", atomic_read(&pd->ref_count));
320bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_timer_delete(pd, 0);
321bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_pd_put(pd);
322bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
323bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
324bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
325bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
326bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyint oz_pd_sleep(struct oz_pd *pd)
327bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
328bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	int do_stop = 0;
329bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	u16 stop_apps = 0;
330bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_polling_lock_bh();
331bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (pd->state & (OZ_PD_S_SLEEP | OZ_PD_S_STOPPED)) {
332bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_polling_unlock_bh();
333bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return 0;
334bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
335bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (pd->keep_alive_j && pd->session_id) {
336bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_pd_set_state(pd, OZ_PD_S_SLEEP);
337bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->pulse_time_j = jiffies + pd->keep_alive_j;
338f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches		oz_dbg(ON, "Sleep Now %lu until %lu\n",
339f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches		       jiffies, pd->pulse_time_j);
340bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	} else {
341bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		do_stop = 1;
342bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
343bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	stop_apps = pd->total_apps;
344bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_polling_unlock_bh();
345bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (do_stop) {
346bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_pd_stop(pd);
347bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	} else {
348bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_services_stop(pd, stop_apps, 1);
349bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_timer_add(pd, OZ_TIMER_STOP, jiffies + pd->keep_alive_j, 1);
350bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
351bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return do_stop;
352bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
353bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
354bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
355bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
356bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic struct oz_tx_frame *oz_tx_frame_alloc(struct oz_pd *pd)
357bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
35886b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	struct oz_tx_frame *f = NULL;
359bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_lock_bh(&pd->tx_frame_lock);
360bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (pd->tx_pool) {
361bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		f = container_of(pd->tx_pool, struct oz_tx_frame, link);
362bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->tx_pool = pd->tx_pool->next;
363bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->tx_pool_count--;
364bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
365bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_unlock_bh(&pd->tx_frame_lock);
36686b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	if (f == NULL)
3671ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman		f = kmalloc(sizeof(struct oz_tx_frame), GFP_ATOMIC);
368bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (f) {
369bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		f->total_size = sizeof(struct oz_hdr);
370bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		INIT_LIST_HEAD(&f->link);
371bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		INIT_LIST_HEAD(&f->elt_list);
372bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
373bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return f;
374bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
375bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
376bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
377bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
37833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujarestatic void oz_tx_isoc_free(struct oz_pd *pd, struct oz_tx_frame *f)
37933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare{
38033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	pd->nb_queued_isoc_frames--;
38133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	list_del_init(&f->link);
38233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	if (pd->tx_pool_count < OZ_MAX_TX_POOL_SIZE) {
38333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		f->link.next = pd->tx_pool;
38433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		pd->tx_pool = &f->link;
38533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		pd->tx_pool_count++;
38633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	} else {
38733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		kfree(f);
38833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	}
389f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches	oz_dbg(TX_FRAMES, "Releasing ISOC Frame isoc_nb= %d\n",
390f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches	       pd->nb_queued_isoc_frames);
39133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare}
39233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare/*------------------------------------------------------------------------------
39333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare * Context: softirq or process
39433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare */
395bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_tx_frame_free(struct oz_pd *pd, struct oz_tx_frame *f)
396bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
397bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_lock_bh(&pd->tx_frame_lock);
398bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (pd->tx_pool_count < OZ_MAX_TX_POOL_SIZE) {
399bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		f->link.next = pd->tx_pool;
400bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->tx_pool = &f->link;
401bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->tx_pool_count++;
40286b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe		f = NULL;
403bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
404bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_unlock_bh(&pd->tx_frame_lock);
405b150718ecb6468d2de1ff593c402ec257dd80c8cSachin Kamat	kfree(f);
406bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
407bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
40833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare * Context: softirq-serialized
40933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare */
410a7f74c3005cf6830a20d71c4e1d8d6d77443e5cbPeter Huewestatic void oz_set_more_bit(struct sk_buff *skb)
41133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare{
41233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	struct oz_hdr *oz_hdr = (struct oz_hdr *)skb_network_header(skb);
41333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	oz_hdr->control |= OZ_F_MORE_DATA;
41433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare}
41533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare/*------------------------------------------------------------------------------
41600ec12b827d2f99202e0c9d804514aef2febf8d6Rupesh Gujare * Context: softirq-serialized
41700ec12b827d2f99202e0c9d804514aef2febf8d6Rupesh Gujare */
418a7f74c3005cf6830a20d71c4e1d8d6d77443e5cbPeter Huewestatic void oz_set_last_pkt_nb(struct oz_pd *pd, struct sk_buff *skb)
41900ec12b827d2f99202e0c9d804514aef2febf8d6Rupesh Gujare{
42000ec12b827d2f99202e0c9d804514aef2febf8d6Rupesh Gujare	struct oz_hdr *oz_hdr = (struct oz_hdr *)skb_network_header(skb);
42100ec12b827d2f99202e0c9d804514aef2febf8d6Rupesh Gujare	oz_hdr->last_pkt_num = pd->trigger_pkt_num & OZ_LAST_PN_MASK;
42200ec12b827d2f99202e0c9d804514aef2febf8d6Rupesh Gujare}
42300ec12b827d2f99202e0c9d804514aef2febf8d6Rupesh Gujare/*------------------------------------------------------------------------------
424bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
425bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
426bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyint oz_prepare_frame(struct oz_pd *pd, int empty)
427bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
428bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_tx_frame *f;
429bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if ((pd->mode & OZ_MODE_MASK) != OZ_MODE_TRIGGERED)
430bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return -1;
431bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (pd->nb_queued_frames >= OZ_MAX_QUEUED_FRAMES)
432bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return -1;
433bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (!empty && !oz_are_elts_available(&pd->elt_buff))
434bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return -1;
435bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	f = oz_tx_frame_alloc(pd);
43686b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	if (f == NULL)
437bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return -1;
43833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	f->skb = NULL;
439bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	f->hdr.control =
440bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		(OZ_PROTOCOL_VERSION<<OZ_VERSION_SHIFT) | OZ_F_ACK_REQUESTED;
441bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	++pd->last_tx_pkt_num;
442bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	put_unaligned(cpu_to_le32(pd->last_tx_pkt_num), &f->hdr.pkt_num);
443bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (empty == 0) {
444bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_select_elts_for_tx(&pd->elt_buff, 0, &f->total_size,
445bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			pd->max_tx_size, &f->elt_list);
446bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
447bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_lock(&pd->tx_frame_lock);
448bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	list_add_tail(&f->link, &pd->tx_queue);
449bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	pd->nb_queued_frames++;
450bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_unlock(&pd->tx_frame_lock);
451bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return 0;
452bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
453bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
454bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq-serialized
455bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
456bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic struct sk_buff *oz_build_frame(struct oz_pd *pd, struct oz_tx_frame *f)
457bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
45886b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	struct sk_buff *skb;
459bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct net_device *dev = pd->net_dev;
460bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_hdr *oz_hdr;
461bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_elt *elt;
462bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct list_head *e;
463bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Allocate skb with enough space for the lower layers as well
464bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	 * as the space we need.
465bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	 */
466ec0ee957f657b6200a2629d4c54df68d2c622e12Greg Kroah-Hartman	skb = alloc_skb(f->total_size + OZ_ALLOCATED_SPACE(dev), GFP_ATOMIC);
46786b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	if (skb == NULL)
46886b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe		return NULL;
469bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Reserve the head room for lower layers.
470bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	 */
471bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb_reserve(skb, LL_RESERVED_SPACE(dev));
472bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb_reset_network_header(skb);
473bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb->dev = dev;
474bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb->protocol = htons(OZ_ETHERTYPE);
475bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (dev_hard_header(skb, dev, OZ_ETHERTYPE, pd->mac_addr,
476bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		dev->dev_addr, skb->len) < 0)
477bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		goto fail;
478bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Push the tail to the end of the area we are going to copy to.
479bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	 */
480bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_hdr = (struct oz_hdr *)skb_put(skb, f->total_size);
481bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	f->hdr.last_pkt_num = pd->trigger_pkt_num & OZ_LAST_PN_MASK;
482bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	memcpy(oz_hdr, &f->hdr, sizeof(struct oz_hdr));
483bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Copy the elements into the frame body.
484bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	 */
485bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	elt = (struct oz_elt *)(oz_hdr+1);
486bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	for (e = f->elt_list.next; e != &f->elt_list; e = e->next) {
487bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		struct oz_elt_info *ei;
488bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		ei = container_of(e, struct oz_elt_info, link);
489bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		memcpy(elt, ei->data, ei->length);
490bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		elt = oz_next_elt(elt);
491bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
492bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return skb;
493bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyfail:
494dd3cef0f0715b79d29a4b0482117175f44b7d83cGreg Kroah-Hartman	kfree_skb(skb);
49586b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	return NULL;
496bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
497bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
498bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
499bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
500bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_retire_frame(struct oz_pd *pd, struct oz_tx_frame *f)
501bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
502bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct list_head *e;
503bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_elt_info *ei;
504bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	e = f->elt_list.next;
505bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	while (e != &f->elt_list) {
506bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		ei = container_of(e, struct oz_elt_info, link);
507bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		e = e->next;
508bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		list_del_init(&ei->link);
509bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (ei->callback)
510bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			ei->callback(pd, ei->context);
511bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_lock_bh(&pd->elt_buff.lock);
512bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_elt_info_free(&pd->elt_buff, ei);
513bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_unlock_bh(&pd->elt_buff.lock);
514bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
515bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_tx_frame_free(pd, f);
516bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (pd->elt_buff.free_elts > pd->elt_buff.max_free_elts)
517bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_trim_elt_pool(&pd->elt_buff);
518bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
519bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
520bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq-serialized
521bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
52233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujarestatic int oz_send_next_queued_frame(struct oz_pd *pd, int more_data)
523bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
524bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct sk_buff *skb;
525bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_tx_frame *f;
526bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct list_head *e;
527bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_lock(&pd->tx_frame_lock);
528bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	e = pd->last_sent_frame->next;
529bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (e == &pd->tx_queue) {
530bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_unlock(&pd->tx_frame_lock);
531bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return -1;
532bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
533bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	f = container_of(e, struct oz_tx_frame, link);
53433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
53533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	if (f->skb != NULL) {
53633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		skb = f->skb;
53733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		oz_tx_isoc_free(pd, f);
53833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		spin_unlock(&pd->tx_frame_lock);
53933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		if (more_data)
54033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			oz_set_more_bit(skb);
54100ec12b827d2f99202e0c9d804514aef2febf8d6Rupesh Gujare		oz_set_last_pkt_nb(pd, skb);
54233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		if ((int)atomic_read(&g_submitted_isoc) <
54333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare							OZ_MAX_SUBMITTED_ISOC) {
54433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			if (dev_queue_xmit(skb) < 0) {
545f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches				oz_dbg(TX_FRAMES, "Dropping ISOC Frame\n");
54633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				return -1;
54733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			}
54833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			atomic_inc(&g_submitted_isoc);
549f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches			oz_dbg(TX_FRAMES, "Sending ISOC Frame, nb_isoc= %d\n",
550f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches			       pd->nb_queued_isoc_frames);
55133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			return 0;
55233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		} else {
553dd3cef0f0715b79d29a4b0482117175f44b7d83cGreg Kroah-Hartman			kfree_skb(skb);
554f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches			oz_dbg(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);
564f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches	oz_dbg(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) {
630f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches		oz_dbg(ON, "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;
678f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches		oz_dbg(TX_FRAMES, "Releasing pkt_num= %u, nb= %d\n",
679f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches		       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) {
838f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches				oz_dbg(TX_FRAMES, "Dropping ISOC Unit nb= %d\n",
839f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches				       nb);
84033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				goto out;
84133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			}
84233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			isoc_unit = oz_tx_frame_alloc(pd);
84333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			if (isoc_unit == NULL)
84433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				goto out;
84533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			isoc_unit->hdr = oz;
84633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			isoc_unit->skb = skb;
84733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			spin_lock_bh(&pd->tx_frame_lock);
84833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			list_add_tail(&isoc_unit->link, &pd->tx_queue);
84933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			pd->nb_queued_isoc_frames++;
85033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			spin_unlock_bh(&pd->tx_frame_lock);
851f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches			oz_dbg(TX_FRAMES,
852f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches			       "Added ISOC Frame to Tx Queue isoc_nb= %d, nb= %d\n",
853f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches			       pd->nb_queued_isoc_frames, pd->nb_queued_frames);
85433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			return 0;
855bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		}
85633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
85733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		/*In ANYTIME mode Xmit unit immediately*/
858bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (atomic_read(&g_submitted_isoc) < OZ_MAX_SUBMITTED_ISOC) {
859bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			atomic_inc(&g_submitted_isoc);
860255ece7c4d9e63e2a5e784247bc2e7b639cae4ddRupesh Gujare			if (dev_queue_xmit(skb) < 0)
861bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly				return -1;
862255ece7c4d9e63e2a5e784247bc2e7b639cae4ddRupesh Gujare			else
86333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				return 0;
864bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		}
86533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
866255ece7c4d9e63e2a5e784247bc2e7b639cae4ddRupesh Gujareout:	kfree_skb(skb);
86733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	return -1;
86833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
869bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
870bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return 0;
871bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
872bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
873bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: process
874bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
875bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_apps_init(void)
876bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
877bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	int i;
878bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	for (i = 0; i < OZ_APPID_MAX; i++)
879bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (g_app_if[i].init)
880bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			g_app_if[i].init();
881bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
882bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
883bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: process
884bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
885bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_apps_term(void)
886bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
887bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	int i;
888bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Terminate all the apps. */
889bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	for (i = 0; i < OZ_APPID_MAX; i++)
890bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (g_app_if[i].term)
891bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			g_app_if[i].term();
892bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
893bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
894bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq-serialized
895bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
896bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_handle_app_elt(struct oz_pd *pd, u8 app_id, struct oz_elt *elt)
897bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
898dc7f5b3594fdb846890192fd75793a791d7ba83bPeter Huewe	const struct oz_app_if *ai;
89992a6253299d74833a36edb94d5a4bc541418b17aDan Carpenter	if (app_id == 0 || app_id > OZ_APPID_MAX)
900bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return;
901bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	ai = &g_app_if[app_id-1];
902bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	ai->rx(pd, elt);
903bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
904bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
905bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
906bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
907bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_pd_indicate_farewells(struct oz_pd *pd)
908bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
909bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_farewell *f;
910dc7f5b3594fdb846890192fd75793a791d7ba83bPeter Huewe	const struct oz_app_if *ai = &g_app_if[OZ_APPID_USB-1];
911bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	while (1) {
912bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_polling_lock_bh();
913bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (list_empty(&pd->farewell_list)) {
914bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			oz_polling_unlock_bh();
915bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			break;
916bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		}
917bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		f = list_first_entry(&pd->farewell_list,
918bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly				struct oz_farewell, link);
919bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		list_del(&f->link);
920bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_polling_unlock_bh();
921bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (ai->farewell)
922bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			ai->farewell(pd, f->ep_num, f->report, f->len);
9231ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman		kfree(f);
924bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
925bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
926