[go: nahoru, domu]

ozpd.c revision dfc065f19fe0ce4ef7a52011801c5c19131e6529
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
276e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
28bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
29bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
30bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic struct oz_tx_frame *oz_tx_frame_alloc(struct oz_pd *pd);
31bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_tx_frame_free(struct oz_pd *pd, struct oz_tx_frame *f);
3233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujarestatic void oz_tx_isoc_free(struct oz_pd *pd, struct oz_tx_frame *f);
33bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic struct sk_buff *oz_build_frame(struct oz_pd *pd, struct oz_tx_frame *f);
34bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic int oz_send_isoc_frame(struct oz_pd *pd);
35bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_retire_frame(struct oz_pd *pd, struct oz_tx_frame *f);
36bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_isoc_stream_free(struct oz_isoc_stream *st);
3733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujarestatic int oz_send_next_queued_frame(struct oz_pd *pd, int more_data);
38bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_isoc_destructor(struct sk_buff *skb);
39bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic int oz_def_app_init(void);
40bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_def_app_term(void);
41bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic int oz_def_app_start(struct oz_pd *pd, int resume);
42bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_def_app_stop(struct oz_pd *pd, int pause);
43bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_def_app_rx(struct oz_pd *pd, struct oz_elt *elt);
446e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
45bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
46bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Counts the uncompleted isoc frames submitted to netcard.
47bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
48bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic atomic_t g_submitted_isoc = ATOMIC_INIT(0);
496e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
50bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/* Application handler functions.
51bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
52dc7f5b3594fdb846890192fd75793a791d7ba83bPeter Huewestatic const struct oz_app_if g_app_if[OZ_APPID_MAX] = {
53bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	{oz_usb_init,
54bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_usb_term,
55bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_usb_start,
56bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_usb_stop,
57bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_usb_rx,
58bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_usb_heartbeat,
59bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_usb_farewell,
60bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	OZ_APPID_USB},
61bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly
62bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	{oz_def_app_init,
63bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_def_app_term,
64bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_def_app_start,
65bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_def_app_stop,
66bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_def_app_rx,
6786b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	NULL,
6886b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	NULL,
69bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	OZ_APPID_UNUSED1},
70bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly
71bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	{oz_def_app_init,
72bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_def_app_term,
73bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_def_app_start,
74bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_def_app_stop,
75bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_def_app_rx,
7686b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	NULL,
7786b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	NULL,
78bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	OZ_APPID_UNUSED2},
79bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly
80bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	{oz_cdev_init,
81bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_cdev_term,
82bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_cdev_start,
83bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_cdev_stop,
84bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_cdev_rx,
8586b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	NULL,
8686b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	NULL,
87bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	OZ_APPID_SERIAL},
88bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly};
896e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
90bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
91bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: process
92bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
93bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic int oz_def_app_init(void)
94bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
95bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return 0;
96bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
976e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
98bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
99bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: process
100bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
101bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_def_app_term(void)
102bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
103bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
1046e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
105bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
106bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
107bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
108bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic int oz_def_app_start(struct oz_pd *pd, int resume)
109bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
110bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return 0;
111bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
1126e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
113bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
114bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
115bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
116bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_def_app_stop(struct oz_pd *pd, int pause)
117bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
118bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
1196e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
120bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
121bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
122bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
123bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_def_app_rx(struct oz_pd *pd, struct oz_elt *elt)
124bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
125bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
1266e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
127bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
128bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
129bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
130bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_pd_set_state(struct oz_pd *pd, unsigned state)
131bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
132bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	pd->state = state;
133bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	switch (state) {
134bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	case OZ_PD_S_IDLE:
135f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches		oz_pd_dbg(pd, ON, "PD State: OZ_PD_S_IDLE\n");
136bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		break;
137bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	case OZ_PD_S_CONNECTED:
138f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches		oz_pd_dbg(pd, ON, "PD State: OZ_PD_S_CONNECTED\n");
139bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		break;
140bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	case OZ_PD_S_STOPPED:
141f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches		oz_pd_dbg(pd, ON, "PD State: OZ_PD_S_STOPPED\n");
142bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		break;
143bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	case OZ_PD_S_SLEEP:
144f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches		oz_pd_dbg(pd, ON, "PD State: OZ_PD_S_SLEEP\n");
145bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		break;
146bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
147bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
1486e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
149bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
150bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
151bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
152bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_pd_get(struct oz_pd *pd)
153bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
154bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	atomic_inc(&pd->ref_count);
155bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
1566e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
157bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
158bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
159bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
160bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_pd_put(struct oz_pd *pd)
161bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
162bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (atomic_dec_and_test(&pd->ref_count))
163bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_pd_destroy(pd);
164bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
1656e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
166bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
167bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq-serialized
168bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
169dc7f5b3594fdb846890192fd75793a791d7ba83bPeter Huewestruct oz_pd *oz_pd_alloc(const u8 *mac_addr)
170bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
1711ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman	struct oz_pd *pd = kzalloc(sizeof(struct oz_pd), GFP_ATOMIC);
17218f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
173bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (pd) {
174bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		int i;
175bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		atomic_set(&pd->ref_count, 2);
176bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		for (i = 0; i < OZ_APPID_MAX; i++)
177bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			spin_lock_init(&pd->app_lock[i]);
178bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->last_rx_pkt_num = 0xffffffff;
179bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_pd_set_state(pd, OZ_PD_S_IDLE);
180bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->max_tx_size = OZ_MAX_TX_SIZE;
181bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		memcpy(pd->mac_addr, mac_addr, ETH_ALEN);
182bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (0 != oz_elt_buf_init(&pd->elt_buff)) {
1831ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman			kfree(pd);
18486b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe			pd = NULL;
185bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		}
186bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_lock_init(&pd->tx_frame_lock);
187bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		INIT_LIST_HEAD(&pd->tx_queue);
188bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		INIT_LIST_HEAD(&pd->farewell_list);
189bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->last_sent_frame = &pd->tx_queue;
190bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_lock_init(&pd->stream_lock);
191bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		INIT_LIST_HEAD(&pd->stream_list);
1928fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare		tasklet_init(&pd->heartbeat_tasklet, oz_pd_heartbeat_handler,
1938fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare							(unsigned long)pd);
1948fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare		tasklet_init(&pd->timeout_tasklet, oz_pd_timeout_handler,
1958fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare							(unsigned long)pd);
1968fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare		hrtimer_init(&pd->heartbeat, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
1978fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare		hrtimer_init(&pd->timeout, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
1988fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare		pd->heartbeat.function = oz_pd_heartbeat_event;
1998fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare		pd->timeout.function = oz_pd_timeout_event;
200bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
201bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return pd;
202bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
2036e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
204bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
205bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
206bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
2076af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujarevoid oz_pd_free(struct work_struct *work)
208bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
209bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct list_head *e;
210bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_tx_frame *f;
211bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_isoc_stream *st;
212bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_farewell *fwell;
2136af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare	struct oz_pd *pd;
21418f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
215f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches	oz_pd_dbg(pd, ON, "Destroying PD\n");
2166af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare	pd = container_of(work, struct oz_pd, workitem);
2178fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare	/*Disable timer tasklets*/
2188fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare	tasklet_kill(&pd->heartbeat_tasklet);
2198fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare	tasklet_kill(&pd->timeout_tasklet);
220bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Delete any streams.
221bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	 */
222bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	e = pd->stream_list.next;
223bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	while (e != &pd->stream_list) {
224bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		st = container_of(e, struct oz_isoc_stream, link);
225bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		e = e->next;
226bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_isoc_stream_free(st);
227bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
228bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Free any queued tx frames.
229bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	 */
230bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	e = pd->tx_queue.next;
231bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	while (e != &pd->tx_queue) {
232bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		f = container_of(e, struct oz_tx_frame, link);
233bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		e = e->next;
23433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		if (f->skb != NULL)
235dd3cef0f0715b79d29a4b0482117175f44b7d83cGreg Kroah-Hartman			kfree_skb(f->skb);
236bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_retire_frame(pd, f);
237bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
238bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_elt_buf_term(&pd->elt_buff);
239bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Free any farewells.
240bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	 */
241bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	e = pd->farewell_list.next;
242bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	while (e != &pd->farewell_list) {
243bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		fwell = container_of(e, struct oz_farewell, link);
244bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		e = e->next;
2451ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman		kfree(fwell);
246bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
247bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Deallocate all frames in tx pool.
248bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	 */
249bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	while (pd->tx_pool) {
250bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		e = pd->tx_pool;
251bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->tx_pool = e->next;
2521ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman		kfree(container_of(e, struct oz_tx_frame, link));
253bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
254bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (pd->net_dev)
255bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		dev_put(pd->net_dev);
2561ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman	kfree(pd);
257bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
2586e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
259bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
2606af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare * Context: softirq or Process
2616af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare */
2626af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujarevoid oz_pd_destroy(struct oz_pd *pd)
2636af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare{
2646af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare	if (hrtimer_active(&pd->timeout))
2656af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare		hrtimer_cancel(&pd->timeout);
2666af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare	if (hrtimer_active(&pd->heartbeat))
2676af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare		hrtimer_cancel(&pd->heartbeat);
2686af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare
2696af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare	INIT_WORK(&pd->workitem, oz_pd_free);
270dfc065f19fe0ce4ef7a52011801c5c19131e6529Rupesh Gujare	if (!schedule_work(&pd->workitem))
2716af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare		oz_pd_dbg(pd, ON, "failed to schedule workitem\n");
2726af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare}
2736af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare
2746af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare/*------------------------------------------------------------------------------
275bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq-serialized
276bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
277bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyint oz_services_start(struct oz_pd *pd, u16 apps, int resume)
278bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
279dc7f5b3594fdb846890192fd75793a791d7ba83bPeter Huewe	const struct oz_app_if *ai;
280bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	int rc = 0;
28118f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
282f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches	oz_pd_dbg(pd, ON, "%s: (0x%x) resume(%d)\n", __func__, apps, resume);
283bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	for (ai = g_app_if; ai < &g_app_if[OZ_APPID_MAX]; ai++) {
284bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (apps & (1<<ai->app_id)) {
285bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			if (ai->start(pd, resume)) {
286bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly				rc = -1;
287f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches				oz_pd_dbg(pd, ON,
288f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches					  "Unable to start service %d\n",
289f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches					  ai->app_id);
290bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly				break;
291bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			}
292bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			oz_polling_lock_bh();
293bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			pd->total_apps |= (1<<ai->app_id);
294bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			if (resume)
295bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly				pd->paused_apps &= ~(1<<ai->app_id);
296bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			oz_polling_unlock_bh();
297bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		}
298bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
299bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return rc;
300bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
3016e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
302bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
303bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
304bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
305bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_services_stop(struct oz_pd *pd, u16 apps, int pause)
306bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
307dc7f5b3594fdb846890192fd75793a791d7ba83bPeter Huewe	const struct oz_app_if *ai;
30818f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
309f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches	oz_pd_dbg(pd, ON, "%s: (0x%x) pause(%d)\n", __func__, apps, pause);
310bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	for (ai = g_app_if; ai < &g_app_if[OZ_APPID_MAX]; ai++) {
311bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (apps & (1<<ai->app_id)) {
312bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			oz_polling_lock_bh();
313bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			if (pause) {
314bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly				pd->paused_apps |= (1<<ai->app_id);
315bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			} else {
316bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly				pd->total_apps &= ~(1<<ai->app_id);
317bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly				pd->paused_apps &= ~(1<<ai->app_id);
318bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			}
319bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			oz_polling_unlock_bh();
320bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			ai->stop(pd, pause);
321bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		}
322bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
323bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
3246e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
325bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
326bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
327bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
328bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_pd_heartbeat(struct oz_pd *pd, u16 apps)
329bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
330dc7f5b3594fdb846890192fd75793a791d7ba83bPeter Huewe	const struct oz_app_if *ai;
331bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	int more = 0;
33218f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
333bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	for (ai = g_app_if; ai < &g_app_if[OZ_APPID_MAX]; ai++) {
334bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (ai->heartbeat && (apps & (1<<ai->app_id))) {
335bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			if (ai->heartbeat(pd))
336bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly				more = 1;
337bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		}
338bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
3398fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare	if ((!more) && (hrtimer_active(&pd->heartbeat)))
3408fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare		hrtimer_cancel(&pd->heartbeat);
341bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (pd->mode & OZ_F_ISOC_ANYTIME) {
342bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		int count = 8;
343bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		while (count-- && (oz_send_isoc_frame(pd) >= 0))
344bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			;
345bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
346bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
3476e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
348bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
349bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
350bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
351bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_pd_stop(struct oz_pd *pd)
352bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
353a15e042e262bb62cd8dd9a7ccda9137c9e65cedcRupesh Gujare	u16 stop_apps;
35418f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
355f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches	oz_dbg(ON, "oz_pd_stop() State = 0x%x\n", pd->state);
356bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_pd_indicate_farewells(pd);
357bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_polling_lock_bh();
358bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	stop_apps = pd->total_apps;
359bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	pd->total_apps = 0;
360bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	pd->paused_apps = 0;
361bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_polling_unlock_bh();
362bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_services_stop(pd, stop_apps, 0);
363bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_polling_lock_bh();
364bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_pd_set_state(pd, OZ_PD_S_STOPPED);
365bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Remove from PD list.*/
366bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	list_del(&pd->link);
367bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_polling_unlock_bh();
368f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches	oz_dbg(ON, "pd ref count = %d\n", atomic_read(&pd->ref_count));
369bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_pd_put(pd);
370bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
3716e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
372bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
373bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
374bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
375bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyint oz_pd_sleep(struct oz_pd *pd)
376bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
377bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	int do_stop = 0;
378a15e042e262bb62cd8dd9a7ccda9137c9e65cedcRupesh Gujare	u16 stop_apps;
37918f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
380bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_polling_lock_bh();
381bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (pd->state & (OZ_PD_S_SLEEP | OZ_PD_S_STOPPED)) {
382bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_polling_unlock_bh();
383bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return 0;
384bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
3858fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare	if (pd->keep_alive && pd->session_id)
386bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_pd_set_state(pd, OZ_PD_S_SLEEP);
3878fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare	else
388bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		do_stop = 1;
3898fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare
390bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	stop_apps = pd->total_apps;
391bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_polling_unlock_bh();
392bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (do_stop) {
393bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_pd_stop(pd);
394bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	} else {
395bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_services_stop(pd, stop_apps, 1);
3968fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare		oz_timer_add(pd, OZ_TIMER_STOP, pd->keep_alive);
397bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
398bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return do_stop;
399bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
4006e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
401bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
402bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
403bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
404bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic struct oz_tx_frame *oz_tx_frame_alloc(struct oz_pd *pd)
405bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
40686b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	struct oz_tx_frame *f = NULL;
40718f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
408bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_lock_bh(&pd->tx_frame_lock);
409bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (pd->tx_pool) {
410bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		f = container_of(pd->tx_pool, struct oz_tx_frame, link);
411bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->tx_pool = pd->tx_pool->next;
412bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->tx_pool_count--;
413bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
414bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_unlock_bh(&pd->tx_frame_lock);
41586b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	if (f == NULL)
4161ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman		f = kmalloc(sizeof(struct oz_tx_frame), GFP_ATOMIC);
417bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (f) {
418bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		f->total_size = sizeof(struct oz_hdr);
419bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		INIT_LIST_HEAD(&f->link);
420bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		INIT_LIST_HEAD(&f->elt_list);
421bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
422bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return f;
423bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
4246e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
425bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
426bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
427bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
42833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujarestatic void oz_tx_isoc_free(struct oz_pd *pd, struct oz_tx_frame *f)
42933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare{
43033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	pd->nb_queued_isoc_frames--;
43133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	list_del_init(&f->link);
43233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	if (pd->tx_pool_count < OZ_MAX_TX_POOL_SIZE) {
43333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		f->link.next = pd->tx_pool;
43433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		pd->tx_pool = &f->link;
43533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		pd->tx_pool_count++;
43633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	} else {
43733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		kfree(f);
43833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	}
439f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches	oz_dbg(TX_FRAMES, "Releasing ISOC Frame isoc_nb= %d\n",
440f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches	       pd->nb_queued_isoc_frames);
44133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare}
4426e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
44333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare/*------------------------------------------------------------------------------
44433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare * Context: softirq or process
44533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare */
446bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_tx_frame_free(struct oz_pd *pd, struct oz_tx_frame *f)
447bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
448bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_lock_bh(&pd->tx_frame_lock);
449bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (pd->tx_pool_count < OZ_MAX_TX_POOL_SIZE) {
450bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		f->link.next = pd->tx_pool;
451bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->tx_pool = &f->link;
452bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->tx_pool_count++;
45386b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe		f = NULL;
454bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
455bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_unlock_bh(&pd->tx_frame_lock);
456b150718ecb6468d2de1ff593c402ec257dd80c8cSachin Kamat	kfree(f);
457bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
4586e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
459bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
46033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare * Context: softirq-serialized
46133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare */
462a7f74c3005cf6830a20d71c4e1d8d6d77443e5cbPeter Huewestatic void oz_set_more_bit(struct sk_buff *skb)
46333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare{
46433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	struct oz_hdr *oz_hdr = (struct oz_hdr *)skb_network_header(skb);
46518f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
46633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	oz_hdr->control |= OZ_F_MORE_DATA;
46733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare}
4686e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
46933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare/*------------------------------------------------------------------------------
47000ec12b827d2f99202e0c9d804514aef2febf8d6Rupesh Gujare * Context: softirq-serialized
47100ec12b827d2f99202e0c9d804514aef2febf8d6Rupesh Gujare */
472a7f74c3005cf6830a20d71c4e1d8d6d77443e5cbPeter Huewestatic void oz_set_last_pkt_nb(struct oz_pd *pd, struct sk_buff *skb)
47300ec12b827d2f99202e0c9d804514aef2febf8d6Rupesh Gujare{
47400ec12b827d2f99202e0c9d804514aef2febf8d6Rupesh Gujare	struct oz_hdr *oz_hdr = (struct oz_hdr *)skb_network_header(skb);
47518f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
47600ec12b827d2f99202e0c9d804514aef2febf8d6Rupesh Gujare	oz_hdr->last_pkt_num = pd->trigger_pkt_num & OZ_LAST_PN_MASK;
47700ec12b827d2f99202e0c9d804514aef2febf8d6Rupesh Gujare}
4786e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
47900ec12b827d2f99202e0c9d804514aef2febf8d6Rupesh Gujare/*------------------------------------------------------------------------------
480bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
481bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
482bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyint oz_prepare_frame(struct oz_pd *pd, int empty)
483bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
484bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_tx_frame *f;
48518f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
486bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if ((pd->mode & OZ_MODE_MASK) != OZ_MODE_TRIGGERED)
487bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return -1;
488bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (pd->nb_queued_frames >= OZ_MAX_QUEUED_FRAMES)
489bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return -1;
490bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (!empty && !oz_are_elts_available(&pd->elt_buff))
491bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return -1;
492bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	f = oz_tx_frame_alloc(pd);
49386b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	if (f == NULL)
494bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return -1;
49533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	f->skb = NULL;
496bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	f->hdr.control =
497bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		(OZ_PROTOCOL_VERSION<<OZ_VERSION_SHIFT) | OZ_F_ACK_REQUESTED;
498bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	++pd->last_tx_pkt_num;
499bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	put_unaligned(cpu_to_le32(pd->last_tx_pkt_num), &f->hdr.pkt_num);
500bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (empty == 0) {
501bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_select_elts_for_tx(&pd->elt_buff, 0, &f->total_size,
502bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			pd->max_tx_size, &f->elt_list);
503bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
504bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_lock(&pd->tx_frame_lock);
505bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	list_add_tail(&f->link, &pd->tx_queue);
506bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	pd->nb_queued_frames++;
507bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_unlock(&pd->tx_frame_lock);
508bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return 0;
509bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
5106e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
511bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
512bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq-serialized
513bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
514bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic struct sk_buff *oz_build_frame(struct oz_pd *pd, struct oz_tx_frame *f)
515bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
51686b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	struct sk_buff *skb;
517bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct net_device *dev = pd->net_dev;
518bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_hdr *oz_hdr;
519bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_elt *elt;
520bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct list_head *e;
52118f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
522bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Allocate skb with enough space for the lower layers as well
523bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	 * as the space we need.
524bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	 */
525ec0ee957f657b6200a2629d4c54df68d2c622e12Greg Kroah-Hartman	skb = alloc_skb(f->total_size + OZ_ALLOCATED_SPACE(dev), GFP_ATOMIC);
52686b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	if (skb == NULL)
52786b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe		return NULL;
528bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Reserve the head room for lower layers.
529bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	 */
530bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb_reserve(skb, LL_RESERVED_SPACE(dev));
531bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb_reset_network_header(skb);
532bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb->dev = dev;
533bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb->protocol = htons(OZ_ETHERTYPE);
534bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (dev_hard_header(skb, dev, OZ_ETHERTYPE, pd->mac_addr,
535bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		dev->dev_addr, skb->len) < 0)
536bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		goto fail;
537bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Push the tail to the end of the area we are going to copy to.
538bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	 */
539bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_hdr = (struct oz_hdr *)skb_put(skb, f->total_size);
540bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	f->hdr.last_pkt_num = pd->trigger_pkt_num & OZ_LAST_PN_MASK;
541bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	memcpy(oz_hdr, &f->hdr, sizeof(struct oz_hdr));
542bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Copy the elements into the frame body.
543bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	 */
544bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	elt = (struct oz_elt *)(oz_hdr+1);
545bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	for (e = f->elt_list.next; e != &f->elt_list; e = e->next) {
546bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		struct oz_elt_info *ei;
547bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		ei = container_of(e, struct oz_elt_info, link);
548bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		memcpy(elt, ei->data, ei->length);
549bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		elt = oz_next_elt(elt);
550bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
551bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return skb;
552bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyfail:
553dd3cef0f0715b79d29a4b0482117175f44b7d83cGreg Kroah-Hartman	kfree_skb(skb);
55486b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	return NULL;
555bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
5566e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
557bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
558bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
559bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
560bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_retire_frame(struct oz_pd *pd, struct oz_tx_frame *f)
561bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
562bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct list_head *e;
563bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_elt_info *ei;
56418f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
565bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	e = f->elt_list.next;
566bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	while (e != &f->elt_list) {
567bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		ei = container_of(e, struct oz_elt_info, link);
568bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		e = e->next;
569bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		list_del_init(&ei->link);
570bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (ei->callback)
571bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			ei->callback(pd, ei->context);
572bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_lock_bh(&pd->elt_buff.lock);
573bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_elt_info_free(&pd->elt_buff, ei);
574bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_unlock_bh(&pd->elt_buff.lock);
575bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
576bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_tx_frame_free(pd, f);
577bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (pd->elt_buff.free_elts > pd->elt_buff.max_free_elts)
578bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_trim_elt_pool(&pd->elt_buff);
579bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
5806e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
581bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
582bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq-serialized
583bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
58433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujarestatic int oz_send_next_queued_frame(struct oz_pd *pd, int more_data)
585bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
586bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct sk_buff *skb;
587bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_tx_frame *f;
588bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct list_head *e;
58918f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
590bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_lock(&pd->tx_frame_lock);
591bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	e = pd->last_sent_frame->next;
592bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (e == &pd->tx_queue) {
593bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_unlock(&pd->tx_frame_lock);
594bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return -1;
595bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
596bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	f = container_of(e, struct oz_tx_frame, link);
59733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
59833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	if (f->skb != NULL) {
59933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		skb = f->skb;
60033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		oz_tx_isoc_free(pd, f);
60133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		spin_unlock(&pd->tx_frame_lock);
60233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		if (more_data)
60333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			oz_set_more_bit(skb);
60400ec12b827d2f99202e0c9d804514aef2febf8d6Rupesh Gujare		oz_set_last_pkt_nb(pd, skb);
60533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		if ((int)atomic_read(&g_submitted_isoc) <
60633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare							OZ_MAX_SUBMITTED_ISOC) {
60733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			if (dev_queue_xmit(skb) < 0) {
608f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches				oz_dbg(TX_FRAMES, "Dropping ISOC Frame\n");
60933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				return -1;
61033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			}
61133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			atomic_inc(&g_submitted_isoc);
612f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches			oz_dbg(TX_FRAMES, "Sending ISOC Frame, nb_isoc= %d\n",
613f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches			       pd->nb_queued_isoc_frames);
61433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			return 0;
61533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		} else {
616dd3cef0f0715b79d29a4b0482117175f44b7d83cGreg Kroah-Hartman			kfree_skb(skb);
617f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches			oz_dbg(TX_FRAMES, "Dropping ISOC Frame>\n");
61833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			return -1;
61933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		}
62033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	}
62133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
62233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	pd->last_sent_frame = e;
623bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb = oz_build_frame(pd, f);
624bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_unlock(&pd->tx_frame_lock);
62533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	if (more_data)
62633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		oz_set_more_bit(skb);
627f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches	oz_dbg(TX_FRAMES, "TX frame PN=0x%x\n", f->hdr.pkt_num);
628bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (skb) {
629bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (dev_queue_xmit(skb) < 0)
630bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			return -1;
63133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
632bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
633bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return 0;
634bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
6356e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
636bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
637bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq-serialized
638bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
639bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_send_queued_frames(struct oz_pd *pd, int backlog)
640bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
64133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	while (oz_prepare_frame(pd, 0) >= 0)
64233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		backlog++;
64333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
64433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	switch (pd->mode & (OZ_F_ISOC_NO_ELTS | OZ_F_ISOC_ANYTIME)) {
64533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
64633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		case OZ_F_ISOC_NO_ELTS: {
64733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			backlog += pd->nb_queued_isoc_frames;
64833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			if (backlog <= 0)
64933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				goto out;
65033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			if (backlog > OZ_MAX_SUBMITTED_ISOC)
65133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				backlog = OZ_MAX_SUBMITTED_ISOC;
65233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			break;
653bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		}
65433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		case OZ_NO_ELTS_ANYTIME: {
65533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			if ((backlog <= 0) && (pd->isoc_sent == 0))
65633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				goto out;
65733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			break;
65833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		}
65933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		default: {
66033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			if (backlog <= 0)
66133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				goto out;
66233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			break;
66333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		}
66433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	}
66533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	while (backlog--) {
66633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		if (oz_send_next_queued_frame(pd, backlog) < 0)
66733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			break;
668bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
66933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	return;
67033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
67133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujareout:	oz_prepare_frame(pd, 1);
67233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	oz_send_next_queued_frame(pd, 0);
673bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
6746e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
675bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
676bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
677bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
678bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic int oz_send_isoc_frame(struct oz_pd *pd)
679bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
68086b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	struct sk_buff *skb;
681bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct net_device *dev = pd->net_dev;
682bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_hdr *oz_hdr;
683bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_elt *elt;
684bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct list_head *e;
685bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct list_head list;
686bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	int total_size = sizeof(struct oz_hdr);
68718f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
688bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	INIT_LIST_HEAD(&list);
689bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly
690bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_select_elts_for_tx(&pd->elt_buff, 1, &total_size,
691bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->max_tx_size, &list);
692bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (list.next == &list)
693bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return 0;
694ec0ee957f657b6200a2629d4c54df68d2c622e12Greg Kroah-Hartman	skb = alloc_skb(total_size + OZ_ALLOCATED_SPACE(dev), GFP_ATOMIC);
69586b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	if (skb == NULL) {
696f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches		oz_dbg(ON, "Cannot alloc skb\n");
697bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_elt_info_free_chain(&pd->elt_buff, &list);
698bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return -1;
699bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
700bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb_reserve(skb, LL_RESERVED_SPACE(dev));
701bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb_reset_network_header(skb);
702bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb->dev = dev;
703bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb->protocol = htons(OZ_ETHERTYPE);
704bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (dev_hard_header(skb, dev, OZ_ETHERTYPE, pd->mac_addr,
705bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		dev->dev_addr, skb->len) < 0) {
706dd3cef0f0715b79d29a4b0482117175f44b7d83cGreg Kroah-Hartman		kfree_skb(skb);
707bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return -1;
708bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
709bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_hdr = (struct oz_hdr *)skb_put(skb, total_size);
710bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_hdr->control = (OZ_PROTOCOL_VERSION<<OZ_VERSION_SHIFT) | OZ_F_ISOC;
711bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_hdr->last_pkt_num = pd->trigger_pkt_num & OZ_LAST_PN_MASK;
712bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	elt = (struct oz_elt *)(oz_hdr+1);
713bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly
714bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	for (e = list.next; e != &list; e = e->next) {
715bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		struct oz_elt_info *ei;
716bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		ei = container_of(e, struct oz_elt_info, link);
717bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		memcpy(elt, ei->data, ei->length);
718bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		elt = oz_next_elt(elt);
719bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
720bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	dev_queue_xmit(skb);
721bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_elt_info_free_chain(&pd->elt_buff, &list);
722bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return 0;
723bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
7246e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
725bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
726bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq-serialized
727bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
728bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_retire_tx_frames(struct oz_pd *pd, u8 lpn)
729bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
730bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct list_head *e;
731bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_tx_frame *f;
73286b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	struct list_head *first = NULL;
73386b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	struct list_head *last = NULL;
734bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	u8 diff;
735bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	u32 pkt_num;
736bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly
737bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_lock(&pd->tx_frame_lock);
738bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	e = pd->tx_queue.next;
739bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	while (e != &pd->tx_queue) {
740bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		f = container_of(e, struct oz_tx_frame, link);
741bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pkt_num = le32_to_cpu(get_unaligned(&f->hdr.pkt_num));
742bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		diff = (lpn - (pkt_num & OZ_LAST_PN_MASK)) & OZ_LAST_PN_MASK;
74333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		if ((diff > OZ_LAST_PN_HALF_CYCLE) || (pkt_num == 0))
744bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			break;
745f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches		oz_dbg(TX_FRAMES, "Releasing pkt_num= %u, nb= %d\n",
746f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches		       pkt_num, pd->nb_queued_frames);
74786b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe		if (first == NULL)
748bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			first = e;
749bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		last = e;
750bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		e = e->next;
751bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->nb_queued_frames--;
752bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
753bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (first) {
754bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		last->next->prev = &pd->tx_queue;
755bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->tx_queue.next = last->next;
75686b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe		last->next = NULL;
757bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
758bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	pd->last_sent_frame = &pd->tx_queue;
759bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_unlock(&pd->tx_frame_lock);
760bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	while (first) {
761bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		f = container_of(first, struct oz_tx_frame, link);
762bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		first = first->next;
763bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_retire_frame(pd, f);
764bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
765bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
7666e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
767bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
768bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Precondition: stream_lock must be held.
769bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
770bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
771bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic struct oz_isoc_stream *pd_stream_find(struct oz_pd *pd, u8 ep_num)
772bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
773bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct list_head *e;
774bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_isoc_stream *st;
77518f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
776bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	list_for_each(e, &pd->stream_list) {
777bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		st = container_of(e, struct oz_isoc_stream, link);
778bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (st->ep_num == ep_num)
779bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			return st;
780bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
78186b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	return NULL;
782bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
7836e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
784bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
785bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
786bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
787bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyint oz_isoc_stream_create(struct oz_pd *pd, u8 ep_num)
788bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
789bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_isoc_stream *st =
7901ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman		kzalloc(sizeof(struct oz_isoc_stream), GFP_ATOMIC);
791bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (!st)
7921ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman		return -ENOMEM;
793bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	st->ep_num = ep_num;
794bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_lock_bh(&pd->stream_lock);
795bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (!pd_stream_find(pd, ep_num)) {
796bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		list_add(&st->link, &pd->stream_list);
79786b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe		st = NULL;
798bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
799bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_unlock_bh(&pd->stream_lock);
800b150718ecb6468d2de1ff593c402ec257dd80c8cSachin Kamat	kfree(st);
801bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return 0;
802bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
8036e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
804bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
805bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
806bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
807bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_isoc_stream_free(struct oz_isoc_stream *st)
808bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
809dd3cef0f0715b79d29a4b0482117175f44b7d83cGreg Kroah-Hartman	kfree_skb(st->skb);
8101ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman	kfree(st);
811bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
8126e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
813bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
814bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
815bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
816bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyint oz_isoc_stream_delete(struct oz_pd *pd, u8 ep_num)
817bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
818bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_isoc_stream *st;
81918f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
820bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_lock_bh(&pd->stream_lock);
821bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	st = pd_stream_find(pd, ep_num);
822bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (st)
823bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		list_del(&st->link);
824bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_unlock_bh(&pd->stream_lock);
825bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (st)
826bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_isoc_stream_free(st);
827bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return 0;
828bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
8296e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
830bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
831bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: any
832bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
833bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_isoc_destructor(struct sk_buff *skb)
834bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
835bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	atomic_dec(&g_submitted_isoc);
836bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
8376e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
838bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
839bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
840bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
841dc7f5b3594fdb846890192fd75793a791d7ba83bPeter Hueweint oz_send_isoc_unit(struct oz_pd *pd, u8 ep_num, const u8 *data, int len)
842bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
843bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct net_device *dev = pd->net_dev;
844bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_isoc_stream *st;
845bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	u8 nb_units = 0;
84686b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	struct sk_buff *skb = NULL;
84786b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	struct oz_hdr *oz_hdr = NULL;
848bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	int size = 0;
84918f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
850bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_lock_bh(&pd->stream_lock);
851bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	st = pd_stream_find(pd, ep_num);
852bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (st) {
853bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		skb = st->skb;
85486b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe		st->skb = NULL;
855bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		nb_units = st->nb_units;
856bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		st->nb_units = 0;
857bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_hdr = st->oz_hdr;
858bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		size = st->size;
859bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
860bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_unlock_bh(&pd->stream_lock);
861bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (!st)
862bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return 0;
863bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (!skb) {
864bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		/* Allocate enough space for max size frame. */
865ec0ee957f657b6200a2629d4c54df68d2c622e12Greg Kroah-Hartman		skb = alloc_skb(pd->max_tx_size + OZ_ALLOCATED_SPACE(dev),
866ec0ee957f657b6200a2629d4c54df68d2c622e12Greg Kroah-Hartman				GFP_ATOMIC);
86786b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe		if (skb == NULL)
868bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			return 0;
869bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		/* Reserve the head room for lower layers. */
870bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		skb_reserve(skb, LL_RESERVED_SPACE(dev));
871bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		skb_reset_network_header(skb);
872bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		skb->dev = dev;
873bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		skb->protocol = htons(OZ_ETHERTYPE);
87486c948b4416b4c2c064d6c7e15476afbc04e2bf5Rupesh Gujare		/* For audio packet set priority to AC_VO */
87586c948b4416b4c2c064d6c7e15476afbc04e2bf5Rupesh Gujare		skb->priority = 0x7;
876bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		size = sizeof(struct oz_hdr) + sizeof(struct oz_isoc_large);
877bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_hdr = (struct oz_hdr *)skb_put(skb, size);
878bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
879bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	memcpy(skb_put(skb, len), data, len);
880bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	size += len;
881bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (++nb_units < pd->ms_per_isoc) {
882bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_lock_bh(&pd->stream_lock);
883bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		st->skb = skb;
884bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		st->nb_units = nb_units;
885bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		st->oz_hdr = oz_hdr;
886bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		st->size = size;
887bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_unlock_bh(&pd->stream_lock);
888bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	} else {
889bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		struct oz_hdr oz;
890bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		struct oz_isoc_large iso;
891bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_lock_bh(&pd->stream_lock);
892bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		iso.frame_number = st->frame_num;
893bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		st->frame_num += nb_units;
894bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_unlock_bh(&pd->stream_lock);
895bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz.control =
896bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			(OZ_PROTOCOL_VERSION<<OZ_VERSION_SHIFT) | OZ_F_ISOC;
897bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz.last_pkt_num = pd->trigger_pkt_num & OZ_LAST_PN_MASK;
898bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz.pkt_num = 0;
899bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		iso.endpoint = ep_num;
900bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		iso.format = OZ_DATA_F_ISOC_LARGE;
901bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		iso.ms_data = nb_units;
902bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		memcpy(oz_hdr, &oz, sizeof(oz));
903bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		memcpy(oz_hdr+1, &iso, sizeof(iso));
904bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (dev_hard_header(skb, dev, OZ_ETHERTYPE, pd->mac_addr,
90533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				dev->dev_addr, skb->len) < 0)
90633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			goto out;
90733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
90833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		skb->destructor = oz_isoc_destructor;
90933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		/*Queue for Xmit if mode is not ANYTIME*/
91033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		if (!(pd->mode & OZ_F_ISOC_ANYTIME)) {
91133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			struct oz_tx_frame *isoc_unit = NULL;
91233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			int nb = pd->nb_queued_isoc_frames;
91386d03a0f4f575dda7988800a3da8d6e9f776a819Rupesh Gujare			if (nb >= pd->isoc_latency) {
9142dc2ee5ccdaf88b41bf9c025acf14ebdc2959a21Rupesh Gujare				struct list_head *e;
9152dc2ee5ccdaf88b41bf9c025acf14ebdc2959a21Rupesh Gujare				struct oz_tx_frame *f;
916f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches				oz_dbg(TX_FRAMES, "Dropping ISOC Unit nb= %d\n",
917f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches				       nb);
9182dc2ee5ccdaf88b41bf9c025acf14ebdc2959a21Rupesh Gujare				spin_lock(&pd->tx_frame_lock);
9192dc2ee5ccdaf88b41bf9c025acf14ebdc2959a21Rupesh Gujare				list_for_each(e, &pd->tx_queue) {
9202dc2ee5ccdaf88b41bf9c025acf14ebdc2959a21Rupesh Gujare					f = container_of(e, struct oz_tx_frame,
9212dc2ee5ccdaf88b41bf9c025acf14ebdc2959a21Rupesh Gujare									link);
9222dc2ee5ccdaf88b41bf9c025acf14ebdc2959a21Rupesh Gujare					if (f->skb != NULL) {
9232dc2ee5ccdaf88b41bf9c025acf14ebdc2959a21Rupesh Gujare						oz_tx_isoc_free(pd, f);
9242dc2ee5ccdaf88b41bf9c025acf14ebdc2959a21Rupesh Gujare						break;
9252dc2ee5ccdaf88b41bf9c025acf14ebdc2959a21Rupesh Gujare					}
9262dc2ee5ccdaf88b41bf9c025acf14ebdc2959a21Rupesh Gujare				}
9272dc2ee5ccdaf88b41bf9c025acf14ebdc2959a21Rupesh Gujare				spin_unlock(&pd->tx_frame_lock);
92833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			}
92933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			isoc_unit = oz_tx_frame_alloc(pd);
93033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			if (isoc_unit == NULL)
93133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				goto out;
93233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			isoc_unit->hdr = oz;
93333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			isoc_unit->skb = skb;
93433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			spin_lock_bh(&pd->tx_frame_lock);
93533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			list_add_tail(&isoc_unit->link, &pd->tx_queue);
93633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			pd->nb_queued_isoc_frames++;
93733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			spin_unlock_bh(&pd->tx_frame_lock);
938f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches			oz_dbg(TX_FRAMES,
939f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches			       "Added ISOC Frame to Tx Queue isoc_nb= %d, nb= %d\n",
940f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches			       pd->nb_queued_isoc_frames, pd->nb_queued_frames);
94133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			return 0;
942bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		}
94333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
94433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		/*In ANYTIME mode Xmit unit immediately*/
945bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (atomic_read(&g_submitted_isoc) < OZ_MAX_SUBMITTED_ISOC) {
946bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			atomic_inc(&g_submitted_isoc);
947255ece7c4d9e63e2a5e784247bc2e7b639cae4ddRupesh Gujare			if (dev_queue_xmit(skb) < 0)
948bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly				return -1;
949255ece7c4d9e63e2a5e784247bc2e7b639cae4ddRupesh Gujare			else
95033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				return 0;
951bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		}
95233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
953255ece7c4d9e63e2a5e784247bc2e7b639cae4ddRupesh Gujareout:	kfree_skb(skb);
95433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	return -1;
95533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
956bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
957bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return 0;
958bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
9596e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
960bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
961bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: process
962bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
963bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_apps_init(void)
964bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
965bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	int i;
96618f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
967bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	for (i = 0; i < OZ_APPID_MAX; i++)
968bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (g_app_if[i].init)
969bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			g_app_if[i].init();
970bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
9716e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
972bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
973bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: process
974bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
975bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_apps_term(void)
976bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
977bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	int i;
97818f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
979bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Terminate all the apps. */
980bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	for (i = 0; i < OZ_APPID_MAX; i++)
981bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (g_app_if[i].term)
982bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			g_app_if[i].term();
983bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
9846e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
985bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
986bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq-serialized
987bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
988bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_handle_app_elt(struct oz_pd *pd, u8 app_id, struct oz_elt *elt)
989bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
990dc7f5b3594fdb846890192fd75793a791d7ba83bPeter Huewe	const struct oz_app_if *ai;
99118f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
99292a6253299d74833a36edb94d5a4bc541418b17aDan Carpenter	if (app_id == 0 || app_id > OZ_APPID_MAX)
993bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return;
994bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	ai = &g_app_if[app_id-1];
995bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	ai->rx(pd, elt);
996bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
9976e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
998bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/*------------------------------------------------------------------------------
999bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
1000bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
1001bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_pd_indicate_farewells(struct oz_pd *pd)
1002bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
1003bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_farewell *f;
1004dc7f5b3594fdb846890192fd75793a791d7ba83bPeter Huewe	const struct oz_app_if *ai = &g_app_if[OZ_APPID_USB-1];
100518f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
1006bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	while (1) {
1007bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_polling_lock_bh();
1008bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (list_empty(&pd->farewell_list)) {
1009bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			oz_polling_unlock_bh();
1010bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			break;
1011bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		}
1012bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		f = list_first_entry(&pd->farewell_list,
1013bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly				struct oz_farewell, link);
1014bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		list_del(&f->link);
1015bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_polling_unlock_bh();
1016bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (ai->farewell)
1017bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			ai->farewell(pd, f->ep_num, f->report, f->len);
10181ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman		kfree(f);
1019bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
1020bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
1021