[go: nahoru, domu]

ozpd.c revision 50222db4b03ac8f3259c6d39bbd585ed3358f70f
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/module.h>
8bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly#include <linux/timer.h>
9bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly#include <linux/sched.h>
10bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly#include <linux/netdevice.h>
11072dc1146fb85a9c344138a9751136dff1251333Jérôme Pinot#include <linux/etherdevice.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 Kellystatic struct oz_tx_frame *oz_tx_frame_alloc(struct oz_pd *pd);
25bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_tx_frame_free(struct oz_pd *pd, struct oz_tx_frame *f);
2633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujarestatic void oz_tx_isoc_free(struct oz_pd *pd, struct oz_tx_frame *f);
27bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic struct sk_buff *oz_build_frame(struct oz_pd *pd, struct oz_tx_frame *f);
28bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic int oz_send_isoc_frame(struct oz_pd *pd);
29bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_retire_frame(struct oz_pd *pd, struct oz_tx_frame *f);
30bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_isoc_stream_free(struct oz_isoc_stream *st);
3133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujarestatic int oz_send_next_queued_frame(struct oz_pd *pd, int more_data);
32bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_isoc_destructor(struct sk_buff *skb);
336e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
344e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
35bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Counts the uncompleted isoc frames submitted to netcard.
36bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
37bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic atomic_t g_submitted_isoc = ATOMIC_INIT(0);
386e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
39bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly/* Application handler functions.
40bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
41a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaegerstatic const struct oz_app_if g_app_if[OZ_NB_APPS] = {
42a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger	[OZ_APPID_USB] = {
43a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger		.init      = oz_usb_init,
44a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger		.term      = oz_usb_term,
45a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger		.start     = oz_usb_start,
46a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger		.stop      = oz_usb_stop,
47a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger		.rx        = oz_usb_rx,
48a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger		.heartbeat = oz_usb_heartbeat,
49a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger		.farewell  = oz_usb_farewell,
50a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger	},
51a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger	[OZ_APPID_SERIAL] = {
52a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger		.init      = oz_cdev_init,
53a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger		.term      = oz_cdev_term,
54a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger		.start     = oz_cdev_start,
55a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger		.stop      = oz_cdev_stop,
56a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger		.rx        = oz_cdev_rx,
57a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger	},
58bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly};
596e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
606e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
614e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
62bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
63bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
64bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_pd_set_state(struct oz_pd *pd, unsigned state)
65bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
66bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	pd->state = state;
67bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	switch (state) {
68bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	case OZ_PD_S_IDLE:
69f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches		oz_pd_dbg(pd, ON, "PD State: OZ_PD_S_IDLE\n");
70bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		break;
71bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	case OZ_PD_S_CONNECTED:
72f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches		oz_pd_dbg(pd, ON, "PD State: OZ_PD_S_CONNECTED\n");
73bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		break;
74bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	case OZ_PD_S_STOPPED:
75f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches		oz_pd_dbg(pd, ON, "PD State: OZ_PD_S_STOPPED\n");
76bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		break;
77bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	case OZ_PD_S_SLEEP:
78f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches		oz_pd_dbg(pd, ON, "PD State: OZ_PD_S_SLEEP\n");
79bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		break;
80bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
81bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
826e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
834e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
84bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
85bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
86bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_pd_get(struct oz_pd *pd)
87bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
88bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	atomic_inc(&pd->ref_count);
89bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
906e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
914e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
92bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
93bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
94bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_pd_put(struct oz_pd *pd)
95bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
96bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (atomic_dec_and_test(&pd->ref_count))
97bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_pd_destroy(pd);
98bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
996e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
1004e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
101bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq-serialized
102bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
103dc7f5b3594fdb846890192fd75793a791d7ba83bPeter Huewestruct oz_pd *oz_pd_alloc(const u8 *mac_addr)
104bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
1051ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman	struct oz_pd *pd = kzalloc(sizeof(struct oz_pd), GFP_ATOMIC);
10618f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
107bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (pd) {
108bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		int i;
109bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		atomic_set(&pd->ref_count, 2);
110a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger		for (i = 0; i < OZ_NB_APPS; i++)
111bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			spin_lock_init(&pd->app_lock[i]);
112bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->last_rx_pkt_num = 0xffffffff;
113bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_pd_set_state(pd, OZ_PD_S_IDLE);
114bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->max_tx_size = OZ_MAX_TX_SIZE;
115072dc1146fb85a9c344138a9751136dff1251333Jérôme Pinot		ether_addr_copy(pd->mac_addr, mac_addr);
116a7ae725c9295d9076c889bbb75f83cd8e053bfb6Christoph Jaeger		oz_elt_buf_init(&pd->elt_buff);
117bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_lock_init(&pd->tx_frame_lock);
118bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		INIT_LIST_HEAD(&pd->tx_queue);
119bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		INIT_LIST_HEAD(&pd->farewell_list);
120bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->last_sent_frame = &pd->tx_queue;
121bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_lock_init(&pd->stream_lock);
122bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		INIT_LIST_HEAD(&pd->stream_list);
1238fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare		tasklet_init(&pd->heartbeat_tasklet, oz_pd_heartbeat_handler,
1248fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare							(unsigned long)pd);
1258fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare		tasklet_init(&pd->timeout_tasklet, oz_pd_timeout_handler,
1268fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare							(unsigned long)pd);
1278fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare		hrtimer_init(&pd->heartbeat, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
1288fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare		hrtimer_init(&pd->timeout, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
1298fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare		pd->heartbeat.function = oz_pd_heartbeat_event;
1308fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare		pd->timeout.function = oz_pd_timeout_event;
131bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
132bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return pd;
133bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
1346e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
1354e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
136bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
137bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
138421acbc251a016b98797a06103374b48b30f943aFengguang Wustatic void oz_pd_free(struct work_struct *work)
139bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
140bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct list_head *e;
141bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_tx_frame *f;
142bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_isoc_stream *st;
143bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_farewell *fwell;
1446af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare	struct oz_pd *pd;
14518f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
146f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches	oz_pd_dbg(pd, ON, "Destroying PD\n");
1476af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare	pd = container_of(work, struct oz_pd, workitem);
1488fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare	/*Disable timer tasklets*/
1498fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare	tasklet_kill(&pd->heartbeat_tasklet);
1508fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare	tasklet_kill(&pd->timeout_tasklet);
151bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Delete any streams.
152bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	 */
153bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	e = pd->stream_list.next;
154bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	while (e != &pd->stream_list) {
155bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		st = container_of(e, struct oz_isoc_stream, link);
156bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		e = e->next;
157bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_isoc_stream_free(st);
158bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
159bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Free any queued tx frames.
160bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	 */
161bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	e = pd->tx_queue.next;
162bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	while (e != &pd->tx_queue) {
163bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		f = container_of(e, struct oz_tx_frame, link);
164bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		e = e->next;
16533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		if (f->skb != NULL)
166dd3cef0f0715b79d29a4b0482117175f44b7d83cGreg Kroah-Hartman			kfree_skb(f->skb);
167bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_retire_frame(pd, f);
168bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
169bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_elt_buf_term(&pd->elt_buff);
170bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Free any farewells.
171bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	 */
172bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	e = pd->farewell_list.next;
173bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	while (e != &pd->farewell_list) {
174bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		fwell = container_of(e, struct oz_farewell, link);
175bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		e = e->next;
1761ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman		kfree(fwell);
177bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
178bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (pd->net_dev)
179bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		dev_put(pd->net_dev);
1801ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman	kfree(pd);
181bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
1826e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
1834e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
1846af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare * Context: softirq or Process
1856af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare */
1866af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujarevoid oz_pd_destroy(struct oz_pd *pd)
1876af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare{
1886af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare	if (hrtimer_active(&pd->timeout))
1896af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare		hrtimer_cancel(&pd->timeout);
1906af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare	if (hrtimer_active(&pd->heartbeat))
1916af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare		hrtimer_cancel(&pd->heartbeat);
1926af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare
1936af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare	INIT_WORK(&pd->workitem, oz_pd_free);
194dfc065f19fe0ce4ef7a52011801c5c19131e6529Rupesh Gujare	if (!schedule_work(&pd->workitem))
1956af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare		oz_pd_dbg(pd, ON, "failed to schedule workitem\n");
1966af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare}
1976af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare
1984e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
199bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq-serialized
200bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
201bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyint oz_services_start(struct oz_pd *pd, u16 apps, int resume)
202bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
203a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger	int i, rc = 0;
20418f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
205f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches	oz_pd_dbg(pd, ON, "%s: (0x%x) resume(%d)\n", __func__, apps, resume);
206a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger	for (i = 0; i < OZ_NB_APPS; i++) {
207a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger		if (g_app_if[i].start && (apps & (1 << i))) {
208a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger			if (g_app_if[i].start(pd, resume)) {
209bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly				rc = -1;
210f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches				oz_pd_dbg(pd, ON,
211a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger					  "Unable to start service %d\n", i);
212bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly				break;
213bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			}
2146b029336d93d8f9a94b0256b1f7d9c1768eedba7Surendra Patil			spin_lock_bh(&g_polling_lock);
215a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger			pd->total_apps |= (1 << i);
216bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			if (resume)
217a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger				pd->paused_apps &= ~(1 << i);
2186b029336d93d8f9a94b0256b1f7d9c1768eedba7Surendra Patil			spin_unlock_bh(&g_polling_lock);
219bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		}
220bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
221bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return rc;
222bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
2236e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
2244e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
225bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
226bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
227bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_services_stop(struct oz_pd *pd, u16 apps, int pause)
228bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
229a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger	int i;
23018f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
231f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches	oz_pd_dbg(pd, ON, "%s: (0x%x) pause(%d)\n", __func__, apps, pause);
232a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger	for (i = 0; i < OZ_NB_APPS; i++) {
233a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger		if (g_app_if[i].stop && (apps & (1 << i))) {
2346b029336d93d8f9a94b0256b1f7d9c1768eedba7Surendra Patil			spin_lock_bh(&g_polling_lock);
235bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			if (pause) {
236a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger				pd->paused_apps |=  (1 << i);
237bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			} else {
238a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger				pd->total_apps  &= ~(1 << i);
239a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger				pd->paused_apps &= ~(1 << i);
240bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			}
2416b029336d93d8f9a94b0256b1f7d9c1768eedba7Surendra Patil			spin_unlock_bh(&g_polling_lock);
242a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger			g_app_if[i].stop(pd, pause);
243bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		}
244bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
245bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
2466e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
2474e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
248bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
249bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
250bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_pd_heartbeat(struct oz_pd *pd, u16 apps)
251bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
252a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger	int i, more = 0;
25318f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
254a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger	for (i = 0; i < OZ_NB_APPS; i++) {
255a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger		if (g_app_if[i].heartbeat && (apps & (1 << i))) {
256a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger			if (g_app_if[i].heartbeat(pd))
257bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly				more = 1;
258bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		}
259bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
2608fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare	if ((!more) && (hrtimer_active(&pd->heartbeat)))
2618fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare		hrtimer_cancel(&pd->heartbeat);
262bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (pd->mode & OZ_F_ISOC_ANYTIME) {
263bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		int count = 8;
264bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		while (count-- && (oz_send_isoc_frame(pd) >= 0))
265bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			;
266bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
267bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
2686e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
2694e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
270bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
271bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
272bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_pd_stop(struct oz_pd *pd)
273bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
274a15e042e262bb62cd8dd9a7ccda9137c9e65cedcRupesh Gujare	u16 stop_apps;
27518f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
276f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches	oz_dbg(ON, "oz_pd_stop() State = 0x%x\n", pd->state);
277bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_pd_indicate_farewells(pd);
2786b029336d93d8f9a94b0256b1f7d9c1768eedba7Surendra Patil	spin_lock_bh(&g_polling_lock);
279bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	stop_apps = pd->total_apps;
280bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	pd->total_apps = 0;
281bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	pd->paused_apps = 0;
2826b029336d93d8f9a94b0256b1f7d9c1768eedba7Surendra Patil	spin_unlock_bh(&g_polling_lock);
283bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_services_stop(pd, stop_apps, 0);
2846b029336d93d8f9a94b0256b1f7d9c1768eedba7Surendra Patil	spin_lock_bh(&g_polling_lock);
285bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_pd_set_state(pd, OZ_PD_S_STOPPED);
286bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Remove from PD list.*/
287bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	list_del(&pd->link);
2886b029336d93d8f9a94b0256b1f7d9c1768eedba7Surendra Patil	spin_unlock_bh(&g_polling_lock);
289f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches	oz_dbg(ON, "pd ref count = %d\n", atomic_read(&pd->ref_count));
290bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_pd_put(pd);
291bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
2926e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
2934e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
294bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
295bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
296bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyint oz_pd_sleep(struct oz_pd *pd)
297bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
298bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	int do_stop = 0;
299a15e042e262bb62cd8dd9a7ccda9137c9e65cedcRupesh Gujare	u16 stop_apps;
30018f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
3016b029336d93d8f9a94b0256b1f7d9c1768eedba7Surendra Patil	spin_lock_bh(&g_polling_lock);
302bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (pd->state & (OZ_PD_S_SLEEP | OZ_PD_S_STOPPED)) {
3036b029336d93d8f9a94b0256b1f7d9c1768eedba7Surendra Patil		spin_unlock_bh(&g_polling_lock);
304bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return 0;
305bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
3068fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare	if (pd->keep_alive && pd->session_id)
307bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_pd_set_state(pd, OZ_PD_S_SLEEP);
3088fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare	else
309bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		do_stop = 1;
3108fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare
311bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	stop_apps = pd->total_apps;
3126b029336d93d8f9a94b0256b1f7d9c1768eedba7Surendra Patil	spin_unlock_bh(&g_polling_lock);
313bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (do_stop) {
314bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_pd_stop(pd);
315bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	} else {
316bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_services_stop(pd, stop_apps, 1);
3178fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare		oz_timer_add(pd, OZ_TIMER_STOP, pd->keep_alive);
318bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
319bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return do_stop;
320bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
3216e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
3224e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
323bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
324bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
325bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic struct oz_tx_frame *oz_tx_frame_alloc(struct oz_pd *pd)
326bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
32750222db4b03ac8f3259c6d39bbd585ed3358f70fChristoph Jaeger	struct oz_tx_frame *f;
32818f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
32950222db4b03ac8f3259c6d39bbd585ed3358f70fChristoph Jaeger	f = kmem_cache_alloc(oz_tx_frame_cache, GFP_ATOMIC);
330bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (f) {
331bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		f->total_size = sizeof(struct oz_hdr);
332bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		INIT_LIST_HEAD(&f->link);
333bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		INIT_LIST_HEAD(&f->elt_list);
334bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
335bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return f;
336bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
3376e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
3384e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
339bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
340bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
34133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujarestatic void oz_tx_isoc_free(struct oz_pd *pd, struct oz_tx_frame *f)
34233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare{
34333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	pd->nb_queued_isoc_frames--;
34433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	list_del_init(&f->link);
34550222db4b03ac8f3259c6d39bbd585ed3358f70fChristoph Jaeger
34650222db4b03ac8f3259c6d39bbd585ed3358f70fChristoph Jaeger	kmem_cache_free(oz_tx_frame_cache, f);
34750222db4b03ac8f3259c6d39bbd585ed3358f70fChristoph Jaeger
348f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches	oz_dbg(TX_FRAMES, "Releasing ISOC Frame isoc_nb= %d\n",
349f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches	       pd->nb_queued_isoc_frames);
35033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare}
3516e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
3524e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
35333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare * Context: softirq or process
35433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare */
355bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_tx_frame_free(struct oz_pd *pd, struct oz_tx_frame *f)
356bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
35750222db4b03ac8f3259c6d39bbd585ed3358f70fChristoph Jaeger	kmem_cache_free(oz_tx_frame_cache, f);
358bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
3596e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
3604e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
36133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare * Context: softirq-serialized
36233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare */
363a7f74c3005cf6830a20d71c4e1d8d6d77443e5cbPeter Huewestatic void oz_set_more_bit(struct sk_buff *skb)
36433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare{
36533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	struct oz_hdr *oz_hdr = (struct oz_hdr *)skb_network_header(skb);
36618f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
36733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	oz_hdr->control |= OZ_F_MORE_DATA;
36833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare}
3696e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
3704e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
37100ec12b827d2f99202e0c9d804514aef2febf8d6Rupesh Gujare * Context: softirq-serialized
37200ec12b827d2f99202e0c9d804514aef2febf8d6Rupesh Gujare */
373a7f74c3005cf6830a20d71c4e1d8d6d77443e5cbPeter Huewestatic void oz_set_last_pkt_nb(struct oz_pd *pd, struct sk_buff *skb)
37400ec12b827d2f99202e0c9d804514aef2febf8d6Rupesh Gujare{
37500ec12b827d2f99202e0c9d804514aef2febf8d6Rupesh Gujare	struct oz_hdr *oz_hdr = (struct oz_hdr *)skb_network_header(skb);
37618f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
37700ec12b827d2f99202e0c9d804514aef2febf8d6Rupesh Gujare	oz_hdr->last_pkt_num = pd->trigger_pkt_num & OZ_LAST_PN_MASK;
37800ec12b827d2f99202e0c9d804514aef2febf8d6Rupesh Gujare}
3796e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
3804e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
381bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
382bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
383bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyint oz_prepare_frame(struct oz_pd *pd, int empty)
384bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
385bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_tx_frame *f;
38618f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
387bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if ((pd->mode & OZ_MODE_MASK) != OZ_MODE_TRIGGERED)
388bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return -1;
389bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (pd->nb_queued_frames >= OZ_MAX_QUEUED_FRAMES)
390bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return -1;
391bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (!empty && !oz_are_elts_available(&pd->elt_buff))
392bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return -1;
393bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	f = oz_tx_frame_alloc(pd);
39486b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	if (f == NULL)
395bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return -1;
39633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	f->skb = NULL;
397bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	f->hdr.control =
398bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		(OZ_PROTOCOL_VERSION<<OZ_VERSION_SHIFT) | OZ_F_ACK_REQUESTED;
399bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	++pd->last_tx_pkt_num;
400bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	put_unaligned(cpu_to_le32(pd->last_tx_pkt_num), &f->hdr.pkt_num);
401bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (empty == 0) {
402bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_select_elts_for_tx(&pd->elt_buff, 0, &f->total_size,
403bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			pd->max_tx_size, &f->elt_list);
404bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
405bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_lock(&pd->tx_frame_lock);
406bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	list_add_tail(&f->link, &pd->tx_queue);
407bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	pd->nb_queued_frames++;
408bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_unlock(&pd->tx_frame_lock);
409bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return 0;
410bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
4116e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
4124e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
413bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq-serialized
414bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
415bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic struct sk_buff *oz_build_frame(struct oz_pd *pd, struct oz_tx_frame *f)
416bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
41786b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	struct sk_buff *skb;
418bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct net_device *dev = pd->net_dev;
419bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_hdr *oz_hdr;
420bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_elt *elt;
421bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct list_head *e;
42218f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
423bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Allocate skb with enough space for the lower layers as well
424bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	 * as the space we need.
425bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	 */
426ec0ee957f657b6200a2629d4c54df68d2c622e12Greg Kroah-Hartman	skb = alloc_skb(f->total_size + OZ_ALLOCATED_SPACE(dev), GFP_ATOMIC);
42786b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	if (skb == NULL)
42886b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe		return NULL;
429bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Reserve the head room for lower layers.
430bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	 */
431bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb_reserve(skb, LL_RESERVED_SPACE(dev));
432bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb_reset_network_header(skb);
433bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb->dev = dev;
434bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb->protocol = htons(OZ_ETHERTYPE);
435bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (dev_hard_header(skb, dev, OZ_ETHERTYPE, pd->mac_addr,
436bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		dev->dev_addr, skb->len) < 0)
437bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		goto fail;
438bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Push the tail to the end of the area we are going to copy to.
439bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	 */
440bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_hdr = (struct oz_hdr *)skb_put(skb, f->total_size);
441bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	f->hdr.last_pkt_num = pd->trigger_pkt_num & OZ_LAST_PN_MASK;
442bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	memcpy(oz_hdr, &f->hdr, sizeof(struct oz_hdr));
443bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Copy the elements into the frame body.
444bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	 */
445bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	elt = (struct oz_elt *)(oz_hdr+1);
446bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	for (e = f->elt_list.next; e != &f->elt_list; e = e->next) {
447bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		struct oz_elt_info *ei;
448bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		ei = container_of(e, struct oz_elt_info, link);
449bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		memcpy(elt, ei->data, ei->length);
450bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		elt = oz_next_elt(elt);
451bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
452bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return skb;
453bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyfail:
454dd3cef0f0715b79d29a4b0482117175f44b7d83cGreg Kroah-Hartman	kfree_skb(skb);
45586b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	return NULL;
456bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
4576e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
4584e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
459bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
460bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
461bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_retire_frame(struct oz_pd *pd, struct oz_tx_frame *f)
462bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
463bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct list_head *e;
464bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_elt_info *ei;
46518f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
466bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	e = f->elt_list.next;
467bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	while (e != &f->elt_list) {
468bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		ei = container_of(e, struct oz_elt_info, link);
469bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		e = e->next;
470bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		list_del_init(&ei->link);
471bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (ei->callback)
472bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			ei->callback(pd, ei->context);
473bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_lock_bh(&pd->elt_buff.lock);
474bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_elt_info_free(&pd->elt_buff, ei);
475bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_unlock_bh(&pd->elt_buff.lock);
476bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
477bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_tx_frame_free(pd, f);
478bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
4796e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
4804e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
481bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq-serialized
482bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
48333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujarestatic int oz_send_next_queued_frame(struct oz_pd *pd, int more_data)
484bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
485bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct sk_buff *skb;
486bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_tx_frame *f;
487bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct list_head *e;
48818f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
489bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_lock(&pd->tx_frame_lock);
490bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	e = pd->last_sent_frame->next;
491bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (e == &pd->tx_queue) {
492bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_unlock(&pd->tx_frame_lock);
493bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return -1;
494bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
495bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	f = container_of(e, struct oz_tx_frame, link);
49633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
49733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	if (f->skb != NULL) {
49833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		skb = f->skb;
49933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		oz_tx_isoc_free(pd, f);
50033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		spin_unlock(&pd->tx_frame_lock);
50133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		if (more_data)
50233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			oz_set_more_bit(skb);
50300ec12b827d2f99202e0c9d804514aef2febf8d6Rupesh Gujare		oz_set_last_pkt_nb(pd, skb);
50433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		if ((int)atomic_read(&g_submitted_isoc) <
50533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare							OZ_MAX_SUBMITTED_ISOC) {
50633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			if (dev_queue_xmit(skb) < 0) {
507f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches				oz_dbg(TX_FRAMES, "Dropping ISOC Frame\n");
50833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				return -1;
50933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			}
51033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			atomic_inc(&g_submitted_isoc);
511f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches			oz_dbg(TX_FRAMES, "Sending ISOC Frame, nb_isoc= %d\n",
512f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches			       pd->nb_queued_isoc_frames);
51333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			return 0;
51433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		} else {
515dd3cef0f0715b79d29a4b0482117175f44b7d83cGreg Kroah-Hartman			kfree_skb(skb);
516f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches			oz_dbg(TX_FRAMES, "Dropping ISOC Frame>\n");
51733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			return -1;
51833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		}
51933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	}
52033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
52133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	pd->last_sent_frame = e;
522bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb = oz_build_frame(pd, f);
523bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_unlock(&pd->tx_frame_lock);
52437bc8f7856fc0c851980f01174ca936741511523Rupesh Gujare	if (!skb)
52537bc8f7856fc0c851980f01174ca936741511523Rupesh Gujare		return -1;
52633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	if (more_data)
52733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		oz_set_more_bit(skb);
528f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches	oz_dbg(TX_FRAMES, "TX frame PN=0x%x\n", f->hdr.pkt_num);
52937bc8f7856fc0c851980f01174ca936741511523Rupesh Gujare	if (dev_queue_xmit(skb) < 0)
53037bc8f7856fc0c851980f01174ca936741511523Rupesh Gujare		return -1;
53133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
532bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return 0;
533bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
5346e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
5354e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
536bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq-serialized
537bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
538bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_send_queued_frames(struct oz_pd *pd, int backlog)
539bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
54033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	while (oz_prepare_frame(pd, 0) >= 0)
54133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		backlog++;
54233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
54333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	switch (pd->mode & (OZ_F_ISOC_NO_ELTS | OZ_F_ISOC_ANYTIME)) {
54433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
54533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		case OZ_F_ISOC_NO_ELTS: {
54633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			backlog += pd->nb_queued_isoc_frames;
54733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			if (backlog <= 0)
54833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				goto out;
54933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			if (backlog > OZ_MAX_SUBMITTED_ISOC)
55033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				backlog = OZ_MAX_SUBMITTED_ISOC;
55133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			break;
552bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		}
55333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		case OZ_NO_ELTS_ANYTIME: {
55433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			if ((backlog <= 0) && (pd->isoc_sent == 0))
55533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				goto out;
55633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			break;
55733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		}
55833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		default: {
55933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			if (backlog <= 0)
56033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				goto out;
56133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			break;
56233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		}
56333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	}
56433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	while (backlog--) {
56533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		if (oz_send_next_queued_frame(pd, backlog) < 0)
56633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			break;
567bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
56833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	return;
56933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
57033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujareout:	oz_prepare_frame(pd, 1);
57133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	oz_send_next_queued_frame(pd, 0);
572bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
5736e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
5744e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
575bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
576bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
577bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic int oz_send_isoc_frame(struct oz_pd *pd)
578bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
57986b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	struct sk_buff *skb;
580bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct net_device *dev = pd->net_dev;
581bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_hdr *oz_hdr;
582bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_elt *elt;
583bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct list_head *e;
584bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct list_head list;
585bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	int total_size = sizeof(struct oz_hdr);
58618f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
587bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	INIT_LIST_HEAD(&list);
588bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly
589bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_select_elts_for_tx(&pd->elt_buff, 1, &total_size,
590bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->max_tx_size, &list);
591bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (list.next == &list)
592bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return 0;
593ec0ee957f657b6200a2629d4c54df68d2c622e12Greg Kroah-Hartman	skb = alloc_skb(total_size + OZ_ALLOCATED_SPACE(dev), GFP_ATOMIC);
59486b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	if (skb == NULL) {
595f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches		oz_dbg(ON, "Cannot alloc skb\n");
596bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_elt_info_free_chain(&pd->elt_buff, &list);
597bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return -1;
598bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
599bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb_reserve(skb, LL_RESERVED_SPACE(dev));
600bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb_reset_network_header(skb);
601bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb->dev = dev;
602bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb->protocol = htons(OZ_ETHERTYPE);
603bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (dev_hard_header(skb, dev, OZ_ETHERTYPE, pd->mac_addr,
604bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		dev->dev_addr, skb->len) < 0) {
605dd3cef0f0715b79d29a4b0482117175f44b7d83cGreg Kroah-Hartman		kfree_skb(skb);
606bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return -1;
607bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
608bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_hdr = (struct oz_hdr *)skb_put(skb, total_size);
609bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_hdr->control = (OZ_PROTOCOL_VERSION<<OZ_VERSION_SHIFT) | OZ_F_ISOC;
610bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_hdr->last_pkt_num = pd->trigger_pkt_num & OZ_LAST_PN_MASK;
611bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	elt = (struct oz_elt *)(oz_hdr+1);
612bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly
613bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	for (e = list.next; e != &list; e = e->next) {
614bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		struct oz_elt_info *ei;
615bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		ei = container_of(e, struct oz_elt_info, link);
616bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		memcpy(elt, ei->data, ei->length);
617bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		elt = oz_next_elt(elt);
618bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
619bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	dev_queue_xmit(skb);
620bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_elt_info_free_chain(&pd->elt_buff, &list);
621bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return 0;
622bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
6236e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
6244e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
625bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq-serialized
626bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
627bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_retire_tx_frames(struct oz_pd *pd, u8 lpn)
628bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
629bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct list_head *e;
630bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_tx_frame *f;
63186b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	struct list_head *first = NULL;
63286b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	struct list_head *last = NULL;
633bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	u8 diff;
634bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	u32 pkt_num;
635bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly
636bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_lock(&pd->tx_frame_lock);
637bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	e = pd->tx_queue.next;
638bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	while (e != &pd->tx_queue) {
639bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		f = container_of(e, struct oz_tx_frame, link);
640bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pkt_num = le32_to_cpu(get_unaligned(&f->hdr.pkt_num));
641bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		diff = (lpn - (pkt_num & OZ_LAST_PN_MASK)) & OZ_LAST_PN_MASK;
64233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		if ((diff > OZ_LAST_PN_HALF_CYCLE) || (pkt_num == 0))
643bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			break;
644f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches		oz_dbg(TX_FRAMES, "Releasing pkt_num= %u, nb= %d\n",
645f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches		       pkt_num, pd->nb_queued_frames);
64686b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe		if (first == NULL)
647bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			first = e;
648bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		last = e;
649bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		e = e->next;
650bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->nb_queued_frames--;
651bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
652bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (first) {
653bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		last->next->prev = &pd->tx_queue;
654bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->tx_queue.next = last->next;
65586b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe		last->next = NULL;
656bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
657bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	pd->last_sent_frame = &pd->tx_queue;
658bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_unlock(&pd->tx_frame_lock);
659bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	while (first) {
660bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		f = container_of(first, struct oz_tx_frame, link);
661bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		first = first->next;
662bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_retire_frame(pd, f);
663bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
664bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
6656e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
6664e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
667bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Precondition: stream_lock must be held.
668bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
669bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
670bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic struct oz_isoc_stream *pd_stream_find(struct oz_pd *pd, u8 ep_num)
671bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
672bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct list_head *e;
673bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_isoc_stream *st;
67418f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
675bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	list_for_each(e, &pd->stream_list) {
676bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		st = container_of(e, struct oz_isoc_stream, link);
677bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (st->ep_num == ep_num)
678bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			return st;
679bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
68086b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	return NULL;
681bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
6826e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
6834e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
684bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
685bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
686bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyint oz_isoc_stream_create(struct oz_pd *pd, u8 ep_num)
687bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
688bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_isoc_stream *st =
6891ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman		kzalloc(sizeof(struct oz_isoc_stream), GFP_ATOMIC);
690bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (!st)
6911ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman		return -ENOMEM;
692bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	st->ep_num = ep_num;
693bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_lock_bh(&pd->stream_lock);
694bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (!pd_stream_find(pd, ep_num)) {
695bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		list_add(&st->link, &pd->stream_list);
69686b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe		st = NULL;
697bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
698bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_unlock_bh(&pd->stream_lock);
699b150718ecb6468d2de1ff593c402ec257dd80c8cSachin Kamat	kfree(st);
700bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return 0;
701bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
7026e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
7034e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
704bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
705bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
706bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_isoc_stream_free(struct oz_isoc_stream *st)
707bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
708dd3cef0f0715b79d29a4b0482117175f44b7d83cGreg Kroah-Hartman	kfree_skb(st->skb);
7091ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman	kfree(st);
710bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
7116e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
7124e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
713bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
714bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
715bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyint oz_isoc_stream_delete(struct oz_pd *pd, u8 ep_num)
716bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
717bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_isoc_stream *st;
71818f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
719bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_lock_bh(&pd->stream_lock);
720bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	st = pd_stream_find(pd, ep_num);
721bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (st)
722bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		list_del(&st->link);
723bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_unlock_bh(&pd->stream_lock);
724bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (st)
725bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_isoc_stream_free(st);
726bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return 0;
727bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
7286e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
7294e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
730bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: any
731bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
732bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_isoc_destructor(struct sk_buff *skb)
733bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
734bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	atomic_dec(&g_submitted_isoc);
735bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
7366e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
7374e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
738bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
739bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
740dc7f5b3594fdb846890192fd75793a791d7ba83bPeter Hueweint oz_send_isoc_unit(struct oz_pd *pd, u8 ep_num, const u8 *data, int len)
741bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
742bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct net_device *dev = pd->net_dev;
743bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_isoc_stream *st;
744bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	u8 nb_units = 0;
74586b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	struct sk_buff *skb = NULL;
74686b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	struct oz_hdr *oz_hdr = NULL;
747bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	int size = 0;
74818f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
749bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_lock_bh(&pd->stream_lock);
750bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	st = pd_stream_find(pd, ep_num);
751bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (st) {
752bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		skb = st->skb;
75386b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe		st->skb = NULL;
754bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		nb_units = st->nb_units;
755bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		st->nb_units = 0;
756bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_hdr = st->oz_hdr;
757bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		size = st->size;
758bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
759bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_unlock_bh(&pd->stream_lock);
760bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (!st)
761bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return 0;
762bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (!skb) {
763bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		/* Allocate enough space for max size frame. */
764ec0ee957f657b6200a2629d4c54df68d2c622e12Greg Kroah-Hartman		skb = alloc_skb(pd->max_tx_size + OZ_ALLOCATED_SPACE(dev),
765ec0ee957f657b6200a2629d4c54df68d2c622e12Greg Kroah-Hartman				GFP_ATOMIC);
76686b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe		if (skb == NULL)
767bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			return 0;
768bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		/* Reserve the head room for lower layers. */
769bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		skb_reserve(skb, LL_RESERVED_SPACE(dev));
770bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		skb_reset_network_header(skb);
771bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		skb->dev = dev;
772bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		skb->protocol = htons(OZ_ETHERTYPE);
77386c948b4416b4c2c064d6c7e15476afbc04e2bf5Rupesh Gujare		/* For audio packet set priority to AC_VO */
77486c948b4416b4c2c064d6c7e15476afbc04e2bf5Rupesh Gujare		skb->priority = 0x7;
775bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		size = sizeof(struct oz_hdr) + sizeof(struct oz_isoc_large);
776bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_hdr = (struct oz_hdr *)skb_put(skb, size);
777bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
778bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	memcpy(skb_put(skb, len), data, len);
779bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	size += len;
780bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (++nb_units < pd->ms_per_isoc) {
781bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_lock_bh(&pd->stream_lock);
782bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		st->skb = skb;
783bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		st->nb_units = nb_units;
784bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		st->oz_hdr = oz_hdr;
785bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		st->size = size;
786bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_unlock_bh(&pd->stream_lock);
787bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	} else {
788bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		struct oz_hdr oz;
789bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		struct oz_isoc_large iso;
790bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_lock_bh(&pd->stream_lock);
791bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		iso.frame_number = st->frame_num;
792bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		st->frame_num += nb_units;
793bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_unlock_bh(&pd->stream_lock);
794bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz.control =
795bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			(OZ_PROTOCOL_VERSION<<OZ_VERSION_SHIFT) | OZ_F_ISOC;
796bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz.last_pkt_num = pd->trigger_pkt_num & OZ_LAST_PN_MASK;
797bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz.pkt_num = 0;
798bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		iso.endpoint = ep_num;
799bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		iso.format = OZ_DATA_F_ISOC_LARGE;
800bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		iso.ms_data = nb_units;
801bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		memcpy(oz_hdr, &oz, sizeof(oz));
802bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		memcpy(oz_hdr+1, &iso, sizeof(iso));
803bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (dev_hard_header(skb, dev, OZ_ETHERTYPE, pd->mac_addr,
80433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				dev->dev_addr, skb->len) < 0)
80533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			goto out;
80633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
80733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		skb->destructor = oz_isoc_destructor;
80833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		/*Queue for Xmit if mode is not ANYTIME*/
80933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		if (!(pd->mode & OZ_F_ISOC_ANYTIME)) {
81033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			struct oz_tx_frame *isoc_unit = NULL;
81133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			int nb = pd->nb_queued_isoc_frames;
81286d03a0f4f575dda7988800a3da8d6e9f776a819Rupesh Gujare			if (nb >= pd->isoc_latency) {
8132dc2ee5ccdaf88b41bf9c025acf14ebdc2959a21Rupesh Gujare				struct list_head *e;
8142dc2ee5ccdaf88b41bf9c025acf14ebdc2959a21Rupesh Gujare				struct oz_tx_frame *f;
815f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches				oz_dbg(TX_FRAMES, "Dropping ISOC Unit nb= %d\n",
816f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches				       nb);
8172dc2ee5ccdaf88b41bf9c025acf14ebdc2959a21Rupesh Gujare				spin_lock(&pd->tx_frame_lock);
8182dc2ee5ccdaf88b41bf9c025acf14ebdc2959a21Rupesh Gujare				list_for_each(e, &pd->tx_queue) {
8192dc2ee5ccdaf88b41bf9c025acf14ebdc2959a21Rupesh Gujare					f = container_of(e, struct oz_tx_frame,
8202dc2ee5ccdaf88b41bf9c025acf14ebdc2959a21Rupesh Gujare									link);
8212dc2ee5ccdaf88b41bf9c025acf14ebdc2959a21Rupesh Gujare					if (f->skb != NULL) {
8222dc2ee5ccdaf88b41bf9c025acf14ebdc2959a21Rupesh Gujare						oz_tx_isoc_free(pd, f);
8232dc2ee5ccdaf88b41bf9c025acf14ebdc2959a21Rupesh Gujare						break;
8242dc2ee5ccdaf88b41bf9c025acf14ebdc2959a21Rupesh Gujare					}
8252dc2ee5ccdaf88b41bf9c025acf14ebdc2959a21Rupesh Gujare				}
8262dc2ee5ccdaf88b41bf9c025acf14ebdc2959a21Rupesh Gujare				spin_unlock(&pd->tx_frame_lock);
82733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			}
82833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			isoc_unit = oz_tx_frame_alloc(pd);
82933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			if (isoc_unit == NULL)
83033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				goto out;
83133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			isoc_unit->hdr = oz;
83233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			isoc_unit->skb = skb;
83333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			spin_lock_bh(&pd->tx_frame_lock);
83433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			list_add_tail(&isoc_unit->link, &pd->tx_queue);
83533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			pd->nb_queued_isoc_frames++;
83633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			spin_unlock_bh(&pd->tx_frame_lock);
837f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches			oz_dbg(TX_FRAMES,
838f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches			       "Added ISOC Frame to Tx Queue isoc_nb= %d, nb= %d\n",
839f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches			       pd->nb_queued_isoc_frames, pd->nb_queued_frames);
84033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			return 0;
841bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		}
84233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
84333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		/*In ANYTIME mode Xmit unit immediately*/
844bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (atomic_read(&g_submitted_isoc) < OZ_MAX_SUBMITTED_ISOC) {
845bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			atomic_inc(&g_submitted_isoc);
846255ece7c4d9e63e2a5e784247bc2e7b639cae4ddRupesh Gujare			if (dev_queue_xmit(skb) < 0)
847bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly				return -1;
848255ece7c4d9e63e2a5e784247bc2e7b639cae4ddRupesh Gujare			else
84933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				return 0;
850bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		}
85133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
852255ece7c4d9e63e2a5e784247bc2e7b639cae4ddRupesh Gujareout:	kfree_skb(skb);
85333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	return -1;
85433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
855bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
856bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return 0;
857bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
8586e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
8594e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
860bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: process
861bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
862bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_apps_init(void)
863bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
864bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	int i;
86518f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
866a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger	for (i = 0; i < OZ_NB_APPS; i++) {
867bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (g_app_if[i].init)
868bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			g_app_if[i].init();
869a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger	}
870bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
8716e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
8724e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
873bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: process
874bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
875bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_apps_term(void)
876bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
877bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	int i;
87818f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
879bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Terminate all the apps. */
880a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger	for (i = 0; i < OZ_NB_APPS; i++) {
881bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (g_app_if[i].term)
882bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			g_app_if[i].term();
883a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger	}
884bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
8856e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
8864e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
887bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq-serialized
888bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
889bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_handle_app_elt(struct oz_pd *pd, u8 app_id, struct oz_elt *elt)
890bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
891a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger	if (app_id < OZ_NB_APPS && g_app_if[app_id].rx)
892a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger		g_app_if[app_id].rx(pd, elt);
893bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
8946e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
8954e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
896bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
897bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
898bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_pd_indicate_farewells(struct oz_pd *pd)
899bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
900bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_farewell *f;
901a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger	const struct oz_app_if *ai = &g_app_if[OZ_APPID_USB];
90218f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
903bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	while (1) {
9046b029336d93d8f9a94b0256b1f7d9c1768eedba7Surendra Patil		spin_lock_bh(&g_polling_lock);
905bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (list_empty(&pd->farewell_list)) {
9066b029336d93d8f9a94b0256b1f7d9c1768eedba7Surendra Patil			spin_unlock_bh(&g_polling_lock);
907bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			break;
908bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		}
909bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		f = list_first_entry(&pd->farewell_list,
910bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly				struct oz_farewell, link);
911bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		list_del(&f->link);
9126b029336d93d8f9a94b0256b1f7d9c1768eedba7Surendra Patil		spin_unlock_bh(&g_polling_lock);
913bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (ai->farewell)
914bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			ai->farewell(pd, f->ep_num, f->report, f->len);
9151ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman		kfree(f);
916bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
917bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
918