[go: nahoru, domu]

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;
109ce6880e17508b31e04628a71d4691ef4a00a8b3fAdrian Nicoara
110bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		atomic_set(&pd->ref_count, 2);
111a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger		for (i = 0; i < OZ_NB_APPS; i++)
112bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			spin_lock_init(&pd->app_lock[i]);
113bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->last_rx_pkt_num = 0xffffffff;
114bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_pd_set_state(pd, OZ_PD_S_IDLE);
115bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->max_tx_size = OZ_MAX_TX_SIZE;
116072dc1146fb85a9c344138a9751136dff1251333Jérôme Pinot		ether_addr_copy(pd->mac_addr, mac_addr);
117a7ae725c9295d9076c889bbb75f83cd8e053bfb6Christoph Jaeger		oz_elt_buf_init(&pd->elt_buff);
118bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_lock_init(&pd->tx_frame_lock);
119bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		INIT_LIST_HEAD(&pd->tx_queue);
120bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		INIT_LIST_HEAD(&pd->farewell_list);
121bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->last_sent_frame = &pd->tx_queue;
122bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_lock_init(&pd->stream_lock);
123bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		INIT_LIST_HEAD(&pd->stream_list);
1248fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare		tasklet_init(&pd->heartbeat_tasklet, oz_pd_heartbeat_handler,
1258fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare							(unsigned long)pd);
1268fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare		tasklet_init(&pd->timeout_tasklet, oz_pd_timeout_handler,
1278fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare							(unsigned long)pd);
1288fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare		hrtimer_init(&pd->heartbeat, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
1298fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare		hrtimer_init(&pd->timeout, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
1308fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare		pd->heartbeat.function = oz_pd_heartbeat_event;
1318fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare		pd->timeout.function = oz_pd_timeout_event;
132bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
133bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return pd;
134bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
1356e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
1364e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
137bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
138bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
139421acbc251a016b98797a06103374b48b30f943aFengguang Wustatic void oz_pd_free(struct work_struct *work)
140bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
141a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger	struct list_head *e, *n;
1426af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare	struct oz_pd *pd;
14318f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
144f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches	oz_pd_dbg(pd, ON, "Destroying PD\n");
1456af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare	pd = container_of(work, struct oz_pd, workitem);
1468fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare	/*Disable timer tasklets*/
1478fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare	tasklet_kill(&pd->heartbeat_tasklet);
1488fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare	tasklet_kill(&pd->timeout_tasklet);
149a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger
150a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger	/* Free streams, queued tx frames and farewells. */
151a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger
152a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger	list_for_each_safe(e, n, &pd->stream_list)
153a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger		oz_isoc_stream_free(list_entry(e, struct oz_isoc_stream, link));
154a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger
155a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger	list_for_each_safe(e, n, &pd->tx_queue) {
156a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger		struct oz_tx_frame *f = list_entry(e, struct oz_tx_frame, link);
157ce6880e17508b31e04628a71d4691ef4a00a8b3fAdrian Nicoara
15833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		if (f->skb != NULL)
159dd3cef0f0715b79d29a4b0482117175f44b7d83cGreg Kroah-Hartman			kfree_skb(f->skb);
160bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_retire_frame(pd, f);
161bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
162a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger
163bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_elt_buf_term(&pd->elt_buff);
164a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger
165a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger	list_for_each_safe(e, n, &pd->farewell_list)
166a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger		kfree(list_entry(e, struct oz_farewell, link));
167a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger
168bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (pd->net_dev)
169bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		dev_put(pd->net_dev);
1701ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman	kfree(pd);
171bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
1726e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
1734e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
1746af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare * Context: softirq or Process
1756af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare */
1766af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujarevoid oz_pd_destroy(struct oz_pd *pd)
1776af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare{
1786af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare	if (hrtimer_active(&pd->timeout))
1796af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare		hrtimer_cancel(&pd->timeout);
1806af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare	if (hrtimer_active(&pd->heartbeat))
1816af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare		hrtimer_cancel(&pd->heartbeat);
1826af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare
1836af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare	INIT_WORK(&pd->workitem, oz_pd_free);
184dfc065f19fe0ce4ef7a52011801c5c19131e6529Rupesh Gujare	if (!schedule_work(&pd->workitem))
1856af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare		oz_pd_dbg(pd, ON, "failed to schedule workitem\n");
1866af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare}
1876af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare
1884e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
189bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq-serialized
190bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
191bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyint oz_services_start(struct oz_pd *pd, u16 apps, int resume)
192bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
193a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger	int i, rc = 0;
19418f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
195f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches	oz_pd_dbg(pd, ON, "%s: (0x%x) resume(%d)\n", __func__, apps, resume);
196a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger	for (i = 0; i < OZ_NB_APPS; i++) {
197a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger		if (g_app_if[i].start && (apps & (1 << i))) {
198a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger			if (g_app_if[i].start(pd, resume)) {
199bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly				rc = -1;
200f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches				oz_pd_dbg(pd, ON,
201a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger					  "Unable to start service %d\n", i);
202bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly				break;
203bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			}
2046b029336d93d8f9a94b0256b1f7d9c1768eedba7Surendra Patil			spin_lock_bh(&g_polling_lock);
205a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger			pd->total_apps |= (1 << i);
206bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			if (resume)
207a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger				pd->paused_apps &= ~(1 << i);
2086b029336d93d8f9a94b0256b1f7d9c1768eedba7Surendra Patil			spin_unlock_bh(&g_polling_lock);
209bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		}
210bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
211bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return rc;
212bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
2136e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
2144e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
215bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
216bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
217bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_services_stop(struct oz_pd *pd, u16 apps, int pause)
218bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
219a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger	int i;
22018f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
221f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches	oz_pd_dbg(pd, ON, "%s: (0x%x) pause(%d)\n", __func__, apps, pause);
222a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger	for (i = 0; i < OZ_NB_APPS; i++) {
223a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger		if (g_app_if[i].stop && (apps & (1 << i))) {
2246b029336d93d8f9a94b0256b1f7d9c1768eedba7Surendra Patil			spin_lock_bh(&g_polling_lock);
225bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			if (pause) {
226a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger				pd->paused_apps |=  (1 << i);
227bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			} else {
228a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger				pd->total_apps  &= ~(1 << i);
229a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger				pd->paused_apps &= ~(1 << i);
230bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			}
2316b029336d93d8f9a94b0256b1f7d9c1768eedba7Surendra Patil			spin_unlock_bh(&g_polling_lock);
232a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger			g_app_if[i].stop(pd, pause);
233bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		}
234bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
235bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
2366e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
2374e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
238bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
239bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
240bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_pd_heartbeat(struct oz_pd *pd, u16 apps)
241bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
242a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger	int i, more = 0;
24318f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
244a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger	for (i = 0; i < OZ_NB_APPS; i++) {
245a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger		if (g_app_if[i].heartbeat && (apps & (1 << i))) {
246a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger			if (g_app_if[i].heartbeat(pd))
247bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly				more = 1;
248bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		}
249bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
2508fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare	if ((!more) && (hrtimer_active(&pd->heartbeat)))
2518fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare		hrtimer_cancel(&pd->heartbeat);
252bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (pd->mode & OZ_F_ISOC_ANYTIME) {
253bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		int count = 8;
254ce6880e17508b31e04628a71d4691ef4a00a8b3fAdrian Nicoara
255bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		while (count-- && (oz_send_isoc_frame(pd) >= 0))
256bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			;
257bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
258bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
2596e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
2604e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
261bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
262bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
263bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_pd_stop(struct oz_pd *pd)
264bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
265a15e042e262bb62cd8dd9a7ccda9137c9e65cedcRupesh Gujare	u16 stop_apps;
26618f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
267f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches	oz_dbg(ON, "oz_pd_stop() State = 0x%x\n", pd->state);
268bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_pd_indicate_farewells(pd);
2696b029336d93d8f9a94b0256b1f7d9c1768eedba7Surendra Patil	spin_lock_bh(&g_polling_lock);
270bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	stop_apps = pd->total_apps;
271bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	pd->total_apps = 0;
272bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	pd->paused_apps = 0;
2736b029336d93d8f9a94b0256b1f7d9c1768eedba7Surendra Patil	spin_unlock_bh(&g_polling_lock);
274bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_services_stop(pd, stop_apps, 0);
2756b029336d93d8f9a94b0256b1f7d9c1768eedba7Surendra Patil	spin_lock_bh(&g_polling_lock);
276bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_pd_set_state(pd, OZ_PD_S_STOPPED);
277bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Remove from PD list.*/
278bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	list_del(&pd->link);
2796b029336d93d8f9a94b0256b1f7d9c1768eedba7Surendra Patil	spin_unlock_bh(&g_polling_lock);
280f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches	oz_dbg(ON, "pd ref count = %d\n", atomic_read(&pd->ref_count));
281bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_pd_put(pd);
282bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
2836e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
2844e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
285bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
286bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
287bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyint oz_pd_sleep(struct oz_pd *pd)
288bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
289bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	int do_stop = 0;
290a15e042e262bb62cd8dd9a7ccda9137c9e65cedcRupesh Gujare	u16 stop_apps;
29118f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
2926b029336d93d8f9a94b0256b1f7d9c1768eedba7Surendra Patil	spin_lock_bh(&g_polling_lock);
293bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (pd->state & (OZ_PD_S_SLEEP | OZ_PD_S_STOPPED)) {
2946b029336d93d8f9a94b0256b1f7d9c1768eedba7Surendra Patil		spin_unlock_bh(&g_polling_lock);
295bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return 0;
296bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
2978fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare	if (pd->keep_alive && pd->session_id)
298bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_pd_set_state(pd, OZ_PD_S_SLEEP);
2998fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare	else
300bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		do_stop = 1;
3018fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare
302bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	stop_apps = pd->total_apps;
3036b029336d93d8f9a94b0256b1f7d9c1768eedba7Surendra Patil	spin_unlock_bh(&g_polling_lock);
304bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (do_stop) {
305bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_pd_stop(pd);
306bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	} else {
307bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_services_stop(pd, stop_apps, 1);
3088fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare		oz_timer_add(pd, OZ_TIMER_STOP, pd->keep_alive);
309bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
310bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return do_stop;
311bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
3126e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
3134e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
314bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
315bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
316bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic struct oz_tx_frame *oz_tx_frame_alloc(struct oz_pd *pd)
317bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
31850222db4b03ac8f3259c6d39bbd585ed3358f70fChristoph Jaeger	struct oz_tx_frame *f;
31918f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
32050222db4b03ac8f3259c6d39bbd585ed3358f70fChristoph Jaeger	f = kmem_cache_alloc(oz_tx_frame_cache, GFP_ATOMIC);
321bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (f) {
322bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		f->total_size = sizeof(struct oz_hdr);
323bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		INIT_LIST_HEAD(&f->link);
324bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		INIT_LIST_HEAD(&f->elt_list);
325bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
326bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return f;
327bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
3286e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
3294e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
330bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
331bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
33233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujarestatic void oz_tx_isoc_free(struct oz_pd *pd, struct oz_tx_frame *f)
33333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare{
33433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	pd->nb_queued_isoc_frames--;
33533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	list_del_init(&f->link);
33650222db4b03ac8f3259c6d39bbd585ed3358f70fChristoph Jaeger
33750222db4b03ac8f3259c6d39bbd585ed3358f70fChristoph Jaeger	kmem_cache_free(oz_tx_frame_cache, f);
33850222db4b03ac8f3259c6d39bbd585ed3358f70fChristoph Jaeger
339f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches	oz_dbg(TX_FRAMES, "Releasing ISOC Frame isoc_nb= %d\n",
340f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches	       pd->nb_queued_isoc_frames);
34133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare}
3426e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
3434e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
34433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare * Context: softirq or process
34533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare */
346bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_tx_frame_free(struct oz_pd *pd, struct oz_tx_frame *f)
347bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
34850222db4b03ac8f3259c6d39bbd585ed3358f70fChristoph Jaeger	kmem_cache_free(oz_tx_frame_cache, f);
349bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
3506e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
3514e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
35233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare * Context: softirq-serialized
35333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare */
354a7f74c3005cf6830a20d71c4e1d8d6d77443e5cbPeter Huewestatic void oz_set_more_bit(struct sk_buff *skb)
35533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare{
35633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	struct oz_hdr *oz_hdr = (struct oz_hdr *)skb_network_header(skb);
35718f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
35833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	oz_hdr->control |= OZ_F_MORE_DATA;
35933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare}
3606e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
3614e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
36200ec12b827d2f99202e0c9d804514aef2febf8d6Rupesh Gujare * Context: softirq-serialized
36300ec12b827d2f99202e0c9d804514aef2febf8d6Rupesh Gujare */
364a7f74c3005cf6830a20d71c4e1d8d6d77443e5cbPeter Huewestatic void oz_set_last_pkt_nb(struct oz_pd *pd, struct sk_buff *skb)
36500ec12b827d2f99202e0c9d804514aef2febf8d6Rupesh Gujare{
36600ec12b827d2f99202e0c9d804514aef2febf8d6Rupesh Gujare	struct oz_hdr *oz_hdr = (struct oz_hdr *)skb_network_header(skb);
36718f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
36800ec12b827d2f99202e0c9d804514aef2febf8d6Rupesh Gujare	oz_hdr->last_pkt_num = pd->trigger_pkt_num & OZ_LAST_PN_MASK;
36900ec12b827d2f99202e0c9d804514aef2febf8d6Rupesh Gujare}
3706e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
3714e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
372bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
373bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
374bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyint oz_prepare_frame(struct oz_pd *pd, int empty)
375bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
376bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_tx_frame *f;
37718f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
378bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if ((pd->mode & OZ_MODE_MASK) != OZ_MODE_TRIGGERED)
379bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return -1;
380bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (pd->nb_queued_frames >= OZ_MAX_QUEUED_FRAMES)
381bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return -1;
382bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (!empty && !oz_are_elts_available(&pd->elt_buff))
383bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return -1;
384bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	f = oz_tx_frame_alloc(pd);
38586b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	if (f == NULL)
386bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return -1;
38733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	f->skb = NULL;
388bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	f->hdr.control =
389bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		(OZ_PROTOCOL_VERSION<<OZ_VERSION_SHIFT) | OZ_F_ACK_REQUESTED;
390bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	++pd->last_tx_pkt_num;
391bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	put_unaligned(cpu_to_le32(pd->last_tx_pkt_num), &f->hdr.pkt_num);
392bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (empty == 0) {
393bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_select_elts_for_tx(&pd->elt_buff, 0, &f->total_size,
394bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			pd->max_tx_size, &f->elt_list);
395bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
396bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_lock(&pd->tx_frame_lock);
397bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	list_add_tail(&f->link, &pd->tx_queue);
398bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	pd->nb_queued_frames++;
399bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_unlock(&pd->tx_frame_lock);
400bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return 0;
401bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
4026e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
4034e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
404bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq-serialized
405bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
406bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic struct sk_buff *oz_build_frame(struct oz_pd *pd, struct oz_tx_frame *f)
407bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
40886b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	struct sk_buff *skb;
409bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct net_device *dev = pd->net_dev;
410bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_hdr *oz_hdr;
411bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_elt *elt;
412a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger	struct oz_elt_info *ei;
41318f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
414bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Allocate skb with enough space for the lower layers as well
415bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	 * as the space we need.
416bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	 */
417ec0ee957f657b6200a2629d4c54df68d2c622e12Greg Kroah-Hartman	skb = alloc_skb(f->total_size + OZ_ALLOCATED_SPACE(dev), GFP_ATOMIC);
41886b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	if (skb == NULL)
41986b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe		return NULL;
420bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Reserve the head room for lower layers.
421bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	 */
422bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb_reserve(skb, LL_RESERVED_SPACE(dev));
423bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb_reset_network_header(skb);
424bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb->dev = dev;
425bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb->protocol = htons(OZ_ETHERTYPE);
426bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (dev_hard_header(skb, dev, OZ_ETHERTYPE, pd->mac_addr,
427bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		dev->dev_addr, skb->len) < 0)
428bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		goto fail;
429bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Push the tail to the end of the area we are going to copy to.
430bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	 */
431bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_hdr = (struct oz_hdr *)skb_put(skb, f->total_size);
432bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	f->hdr.last_pkt_num = pd->trigger_pkt_num & OZ_LAST_PN_MASK;
433bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	memcpy(oz_hdr, &f->hdr, sizeof(struct oz_hdr));
434bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Copy the elements into the frame body.
435bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	 */
436bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	elt = (struct oz_elt *)(oz_hdr+1);
437a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger	list_for_each_entry(ei, &f->elt_list, link) {
438bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		memcpy(elt, ei->data, ei->length);
439bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		elt = oz_next_elt(elt);
440bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
441bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return skb;
442bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyfail:
443dd3cef0f0715b79d29a4b0482117175f44b7d83cGreg Kroah-Hartman	kfree_skb(skb);
44486b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	return NULL;
445bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
4466e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
4474e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
448bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
449bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
450bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_retire_frame(struct oz_pd *pd, struct oz_tx_frame *f)
451bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
452a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger	struct oz_elt_info *ei, *n;
45318f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
454a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger	list_for_each_entry_safe(ei, n, &f->elt_list, link) {
455bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		list_del_init(&ei->link);
456bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (ei->callback)
457bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			ei->callback(pd, ei->context);
458bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_lock_bh(&pd->elt_buff.lock);
459bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_elt_info_free(&pd->elt_buff, ei);
460bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_unlock_bh(&pd->elt_buff.lock);
461bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
462bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_tx_frame_free(pd, f);
463bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
4646e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
4654e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
466bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq-serialized
467bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
46833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujarestatic int oz_send_next_queued_frame(struct oz_pd *pd, int more_data)
469bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
470bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct sk_buff *skb;
471bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_tx_frame *f;
472bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct list_head *e;
47318f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
474bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_lock(&pd->tx_frame_lock);
475bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	e = pd->last_sent_frame->next;
476bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (e == &pd->tx_queue) {
477bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_unlock(&pd->tx_frame_lock);
478bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return -1;
479bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
480a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger	f = list_entry(e, struct oz_tx_frame, link);
48133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
48233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	if (f->skb != NULL) {
48333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		skb = f->skb;
48433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		oz_tx_isoc_free(pd, f);
48533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		spin_unlock(&pd->tx_frame_lock);
48633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		if (more_data)
48733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			oz_set_more_bit(skb);
48800ec12b827d2f99202e0c9d804514aef2febf8d6Rupesh Gujare		oz_set_last_pkt_nb(pd, skb);
48933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		if ((int)atomic_read(&g_submitted_isoc) <
49033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare							OZ_MAX_SUBMITTED_ISOC) {
49133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			if (dev_queue_xmit(skb) < 0) {
492f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches				oz_dbg(TX_FRAMES, "Dropping ISOC Frame\n");
49333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				return -1;
49433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			}
49533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			atomic_inc(&g_submitted_isoc);
496f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches			oz_dbg(TX_FRAMES, "Sending ISOC Frame, nb_isoc= %d\n",
497f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches			       pd->nb_queued_isoc_frames);
49833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			return 0;
49933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		}
500d75b6c6154267618363f0126bd50c73f8d448a24Adrian Nicoara		kfree_skb(skb);
501d75b6c6154267618363f0126bd50c73f8d448a24Adrian Nicoara		oz_dbg(TX_FRAMES, "Dropping ISOC Frame>\n");
502d75b6c6154267618363f0126bd50c73f8d448a24Adrian Nicoara		return -1;
50333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	}
50433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
50533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	pd->last_sent_frame = e;
506bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb = oz_build_frame(pd, f);
507bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_unlock(&pd->tx_frame_lock);
50837bc8f7856fc0c851980f01174ca936741511523Rupesh Gujare	if (!skb)
50937bc8f7856fc0c851980f01174ca936741511523Rupesh Gujare		return -1;
51033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	if (more_data)
51133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		oz_set_more_bit(skb);
512f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches	oz_dbg(TX_FRAMES, "TX frame PN=0x%x\n", f->hdr.pkt_num);
51337bc8f7856fc0c851980f01174ca936741511523Rupesh Gujare	if (dev_queue_xmit(skb) < 0)
51437bc8f7856fc0c851980f01174ca936741511523Rupesh Gujare		return -1;
51533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
516bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return 0;
517bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
5186e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
5194e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
520bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq-serialized
521bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
522bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_send_queued_frames(struct oz_pd *pd, int backlog)
523bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
52433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	while (oz_prepare_frame(pd, 0) >= 0)
52533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		backlog++;
52633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
52733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	switch (pd->mode & (OZ_F_ISOC_NO_ELTS | OZ_F_ISOC_ANYTIME)) {
52833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
52933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		case OZ_F_ISOC_NO_ELTS: {
53033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			backlog += pd->nb_queued_isoc_frames;
53133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			if (backlog <= 0)
53233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				goto out;
53333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			if (backlog > OZ_MAX_SUBMITTED_ISOC)
53433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				backlog = OZ_MAX_SUBMITTED_ISOC;
53533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			break;
536bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		}
53733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		case OZ_NO_ELTS_ANYTIME: {
53833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			if ((backlog <= 0) && (pd->isoc_sent == 0))
53933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				goto out;
54033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			break;
54133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		}
54233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		default: {
54333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			if (backlog <= 0)
54433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				goto out;
54533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			break;
54633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		}
54733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	}
54833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	while (backlog--) {
54933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		if (oz_send_next_queued_frame(pd, backlog) < 0)
55033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			break;
551bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
55233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	return;
55333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
55433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujareout:	oz_prepare_frame(pd, 1);
55533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	oz_send_next_queued_frame(pd, 0);
556bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
5576e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
5584e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
559bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
560bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
561bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic int oz_send_isoc_frame(struct oz_pd *pd)
562bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
56386b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	struct sk_buff *skb;
564bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct net_device *dev = pd->net_dev;
565bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_hdr *oz_hdr;
566bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_elt *elt;
567a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger	struct oz_elt_info *ei;
568a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger	LIST_HEAD(list);
569bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	int total_size = sizeof(struct oz_hdr);
57018f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
571bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_select_elts_for_tx(&pd->elt_buff, 1, &total_size,
572bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->max_tx_size, &list);
573a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger	if (list_empty(&list))
574bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return 0;
575ec0ee957f657b6200a2629d4c54df68d2c622e12Greg Kroah-Hartman	skb = alloc_skb(total_size + OZ_ALLOCATED_SPACE(dev), GFP_ATOMIC);
57686b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	if (skb == NULL) {
577f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches		oz_dbg(ON, "Cannot alloc skb\n");
578bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_elt_info_free_chain(&pd->elt_buff, &list);
579bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return -1;
580bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
581bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb_reserve(skb, LL_RESERVED_SPACE(dev));
582bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb_reset_network_header(skb);
583bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb->dev = dev;
584bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb->protocol = htons(OZ_ETHERTYPE);
585bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (dev_hard_header(skb, dev, OZ_ETHERTYPE, pd->mac_addr,
586bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		dev->dev_addr, skb->len) < 0) {
587dd3cef0f0715b79d29a4b0482117175f44b7d83cGreg Kroah-Hartman		kfree_skb(skb);
588bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return -1;
589bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
590bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_hdr = (struct oz_hdr *)skb_put(skb, total_size);
591bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_hdr->control = (OZ_PROTOCOL_VERSION<<OZ_VERSION_SHIFT) | OZ_F_ISOC;
592bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_hdr->last_pkt_num = pd->trigger_pkt_num & OZ_LAST_PN_MASK;
593bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	elt = (struct oz_elt *)(oz_hdr+1);
594bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly
595a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger	list_for_each_entry(ei, &list, link) {
596bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		memcpy(elt, ei->data, ei->length);
597bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		elt = oz_next_elt(elt);
598bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
599bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	dev_queue_xmit(skb);
600bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_elt_info_free_chain(&pd->elt_buff, &list);
601bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return 0;
602bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
6036e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
6044e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
605bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq-serialized
606bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
607bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_retire_tx_frames(struct oz_pd *pd, u8 lpn)
608bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
609a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger	struct oz_tx_frame *f, *tmp = NULL;
610bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	u8 diff;
611bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	u32 pkt_num;
612bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly
613a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger	LIST_HEAD(list);
614a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger
615bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_lock(&pd->tx_frame_lock);
616a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger	list_for_each_entry(f, &pd->tx_queue, link) {
617bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pkt_num = le32_to_cpu(get_unaligned(&f->hdr.pkt_num));
618bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		diff = (lpn - (pkt_num & OZ_LAST_PN_MASK)) & OZ_LAST_PN_MASK;
61933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		if ((diff > OZ_LAST_PN_HALF_CYCLE) || (pkt_num == 0))
620bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			break;
621f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches		oz_dbg(TX_FRAMES, "Releasing pkt_num= %u, nb= %d\n",
622f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches		       pkt_num, pd->nb_queued_frames);
623a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger		tmp = f;
624bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->nb_queued_frames--;
625bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
626a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger	if (tmp)
627a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger		list_cut_position(&list, &pd->tx_queue, &tmp->link);
628bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	pd->last_sent_frame = &pd->tx_queue;
629bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_unlock(&pd->tx_frame_lock);
630a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger
631a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger	list_for_each_entry_safe(f, tmp, &list, link)
632bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_retire_frame(pd, f);
633bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
6346e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
6354e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
636bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Precondition: stream_lock must be held.
637bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
638bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
639bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic struct oz_isoc_stream *pd_stream_find(struct oz_pd *pd, u8 ep_num)
640bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
641bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_isoc_stream *st;
64218f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
643a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger	list_for_each_entry(st, &pd->stream_list, link) {
644bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (st->ep_num == ep_num)
645bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			return st;
646bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
64786b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	return NULL;
648bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
6496e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
6504e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
651bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
652bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
653bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyint oz_isoc_stream_create(struct oz_pd *pd, u8 ep_num)
654bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
655bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_isoc_stream *st =
6561ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman		kzalloc(sizeof(struct oz_isoc_stream), GFP_ATOMIC);
657bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (!st)
6581ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman		return -ENOMEM;
659bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	st->ep_num = ep_num;
660bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_lock_bh(&pd->stream_lock);
661bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (!pd_stream_find(pd, ep_num)) {
662bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		list_add(&st->link, &pd->stream_list);
66386b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe		st = NULL;
664bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
665bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_unlock_bh(&pd->stream_lock);
666b150718ecb6468d2de1ff593c402ec257dd80c8cSachin Kamat	kfree(st);
667bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return 0;
668bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
6696e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
6704e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
671bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
672bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
673bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_isoc_stream_free(struct oz_isoc_stream *st)
674bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
675dd3cef0f0715b79d29a4b0482117175f44b7d83cGreg Kroah-Hartman	kfree_skb(st->skb);
6761ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman	kfree(st);
677bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
6786e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
6794e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
680bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
681bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
682bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyint oz_isoc_stream_delete(struct oz_pd *pd, u8 ep_num)
683bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
684bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_isoc_stream *st;
68518f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
686bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_lock_bh(&pd->stream_lock);
687bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	st = pd_stream_find(pd, ep_num);
688bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (st)
689bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		list_del(&st->link);
690bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_unlock_bh(&pd->stream_lock);
691bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (st)
692bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_isoc_stream_free(st);
693bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return 0;
694bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
6956e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
6964e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
697bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: any
698bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
699bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_isoc_destructor(struct sk_buff *skb)
700bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
701bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	atomic_dec(&g_submitted_isoc);
702bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
7036e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
7044e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
705bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
706bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
707dc7f5b3594fdb846890192fd75793a791d7ba83bPeter Hueweint oz_send_isoc_unit(struct oz_pd *pd, u8 ep_num, const u8 *data, int len)
708bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
709bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct net_device *dev = pd->net_dev;
710bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_isoc_stream *st;
711bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	u8 nb_units = 0;
71286b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	struct sk_buff *skb = NULL;
71386b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	struct oz_hdr *oz_hdr = NULL;
714bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	int size = 0;
71518f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
716bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_lock_bh(&pd->stream_lock);
717bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	st = pd_stream_find(pd, ep_num);
718bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (st) {
719bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		skb = st->skb;
72086b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe		st->skb = NULL;
721bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		nb_units = st->nb_units;
722bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		st->nb_units = 0;
723bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_hdr = st->oz_hdr;
724bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		size = st->size;
725bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
726bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_unlock_bh(&pd->stream_lock);
727bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (!st)
728bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return 0;
729bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (!skb) {
730bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		/* Allocate enough space for max size frame. */
731ec0ee957f657b6200a2629d4c54df68d2c622e12Greg Kroah-Hartman		skb = alloc_skb(pd->max_tx_size + OZ_ALLOCATED_SPACE(dev),
732ec0ee957f657b6200a2629d4c54df68d2c622e12Greg Kroah-Hartman				GFP_ATOMIC);
73386b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe		if (skb == NULL)
734bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			return 0;
735bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		/* Reserve the head room for lower layers. */
736bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		skb_reserve(skb, LL_RESERVED_SPACE(dev));
737bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		skb_reset_network_header(skb);
738bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		skb->dev = dev;
739bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		skb->protocol = htons(OZ_ETHERTYPE);
74086c948b4416b4c2c064d6c7e15476afbc04e2bf5Rupesh Gujare		/* For audio packet set priority to AC_VO */
74186c948b4416b4c2c064d6c7e15476afbc04e2bf5Rupesh Gujare		skb->priority = 0x7;
742bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		size = sizeof(struct oz_hdr) + sizeof(struct oz_isoc_large);
743bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_hdr = (struct oz_hdr *)skb_put(skb, size);
744bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
745bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	memcpy(skb_put(skb, len), data, len);
746bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	size += len;
747bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (++nb_units < pd->ms_per_isoc) {
748bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_lock_bh(&pd->stream_lock);
749bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		st->skb = skb;
750bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		st->nb_units = nb_units;
751bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		st->oz_hdr = oz_hdr;
752bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		st->size = size;
753bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_unlock_bh(&pd->stream_lock);
754bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	} else {
755bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		struct oz_hdr oz;
756bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		struct oz_isoc_large iso;
757ce6880e17508b31e04628a71d4691ef4a00a8b3fAdrian Nicoara
758bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_lock_bh(&pd->stream_lock);
759bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		iso.frame_number = st->frame_num;
760bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		st->frame_num += nb_units;
761bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_unlock_bh(&pd->stream_lock);
762bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz.control =
763bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			(OZ_PROTOCOL_VERSION<<OZ_VERSION_SHIFT) | OZ_F_ISOC;
764bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz.last_pkt_num = pd->trigger_pkt_num & OZ_LAST_PN_MASK;
765bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz.pkt_num = 0;
766bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		iso.endpoint = ep_num;
767bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		iso.format = OZ_DATA_F_ISOC_LARGE;
768bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		iso.ms_data = nb_units;
769bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		memcpy(oz_hdr, &oz, sizeof(oz));
770bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		memcpy(oz_hdr+1, &iso, sizeof(iso));
771bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (dev_hard_header(skb, dev, OZ_ETHERTYPE, pd->mac_addr,
77233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				dev->dev_addr, skb->len) < 0)
77333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			goto out;
77433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
77533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		skb->destructor = oz_isoc_destructor;
77633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		/*Queue for Xmit if mode is not ANYTIME*/
77733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		if (!(pd->mode & OZ_F_ISOC_ANYTIME)) {
77833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			struct oz_tx_frame *isoc_unit = NULL;
77933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			int nb = pd->nb_queued_isoc_frames;
780ce6880e17508b31e04628a71d4691ef4a00a8b3fAdrian Nicoara
78186d03a0f4f575dda7988800a3da8d6e9f776a819Rupesh Gujare			if (nb >= pd->isoc_latency) {
7822dc2ee5ccdaf88b41bf9c025acf14ebdc2959a21Rupesh Gujare				struct oz_tx_frame *f;
783ce6880e17508b31e04628a71d4691ef4a00a8b3fAdrian Nicoara
784f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches				oz_dbg(TX_FRAMES, "Dropping ISOC Unit nb= %d\n",
785f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches				       nb);
7862dc2ee5ccdaf88b41bf9c025acf14ebdc2959a21Rupesh Gujare				spin_lock(&pd->tx_frame_lock);
787a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger				list_for_each_entry(f, &pd->tx_queue, link) {
7882dc2ee5ccdaf88b41bf9c025acf14ebdc2959a21Rupesh Gujare					if (f->skb != NULL) {
7892dc2ee5ccdaf88b41bf9c025acf14ebdc2959a21Rupesh Gujare						oz_tx_isoc_free(pd, f);
7902dc2ee5ccdaf88b41bf9c025acf14ebdc2959a21Rupesh Gujare						break;
7912dc2ee5ccdaf88b41bf9c025acf14ebdc2959a21Rupesh Gujare					}
7922dc2ee5ccdaf88b41bf9c025acf14ebdc2959a21Rupesh Gujare				}
7932dc2ee5ccdaf88b41bf9c025acf14ebdc2959a21Rupesh Gujare				spin_unlock(&pd->tx_frame_lock);
79433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			}
79533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			isoc_unit = oz_tx_frame_alloc(pd);
79633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			if (isoc_unit == NULL)
79733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				goto out;
79833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			isoc_unit->hdr = oz;
79933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			isoc_unit->skb = skb;
80033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			spin_lock_bh(&pd->tx_frame_lock);
80133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			list_add_tail(&isoc_unit->link, &pd->tx_queue);
80233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			pd->nb_queued_isoc_frames++;
80333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			spin_unlock_bh(&pd->tx_frame_lock);
804f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches			oz_dbg(TX_FRAMES,
805f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches			       "Added ISOC Frame to Tx Queue isoc_nb= %d, nb= %d\n",
806f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches			       pd->nb_queued_isoc_frames, pd->nb_queued_frames);
80733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			return 0;
808bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		}
80933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
81033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		/*In ANYTIME mode Xmit unit immediately*/
811bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (atomic_read(&g_submitted_isoc) < OZ_MAX_SUBMITTED_ISOC) {
812bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			atomic_inc(&g_submitted_isoc);
813255ece7c4d9e63e2a5e784247bc2e7b639cae4ddRupesh Gujare			if (dev_queue_xmit(skb) < 0)
814bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly				return -1;
815d75b6c6154267618363f0126bd50c73f8d448a24Adrian Nicoara			return 0;
816bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		}
81733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
818255ece7c4d9e63e2a5e784247bc2e7b639cae4ddRupesh Gujareout:	kfree_skb(skb);
81933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	return -1;
82033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
821bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
822bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return 0;
823bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
8246e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
8254e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
826bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: process
827bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
828bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_apps_init(void)
829bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
830bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	int i;
83118f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
832a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger	for (i = 0; i < OZ_NB_APPS; i++) {
833bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (g_app_if[i].init)
834bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			g_app_if[i].init();
835a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger	}
836bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
8376e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
8384e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
839bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: process
840bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
841bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_apps_term(void)
842bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
843bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	int i;
84418f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
845bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Terminate all the apps. */
846a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger	for (i = 0; i < OZ_NB_APPS; i++) {
847bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (g_app_if[i].term)
848bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			g_app_if[i].term();
849a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger	}
850bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
8516e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
8524e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
853bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq-serialized
854bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
855bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_handle_app_elt(struct oz_pd *pd, u8 app_id, struct oz_elt *elt)
856bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
857a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger	if (app_id < OZ_NB_APPS && g_app_if[app_id].rx)
858a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger		g_app_if[app_id].rx(pd, elt);
859bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
8606e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
8614e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
862bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
863bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
864bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_pd_indicate_farewells(struct oz_pd *pd)
865bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
866bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_farewell *f;
867a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger	const struct oz_app_if *ai = &g_app_if[OZ_APPID_USB];
86818f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
869bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	while (1) {
8706b029336d93d8f9a94b0256b1f7d9c1768eedba7Surendra Patil		spin_lock_bh(&g_polling_lock);
871bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (list_empty(&pd->farewell_list)) {
8726b029336d93d8f9a94b0256b1f7d9c1768eedba7Surendra Patil			spin_unlock_bh(&g_polling_lock);
873bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			break;
874bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		}
875bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		f = list_first_entry(&pd->farewell_list,
876bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly				struct oz_farewell, link);
877bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		list_del(&f->link);
8786b029336d93d8f9a94b0256b1f7d9c1768eedba7Surendra Patil		spin_unlock_bh(&g_polling_lock);
879bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (ai->farewell)
880bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			ai->farewell(pd, f->ep_num, f->report, f->len);
8811ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman		kfree(f);
882bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
883bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
884