[go: nahoru, domu]

ozpd.c revision a87c38090ea95d36925fefc5cb3d475416f3796c
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{
140a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger	struct list_head *e, *n;
1416af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare	struct oz_pd *pd;
14218f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
143f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches	oz_pd_dbg(pd, ON, "Destroying PD\n");
1446af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare	pd = container_of(work, struct oz_pd, workitem);
1458fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare	/*Disable timer tasklets*/
1468fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare	tasklet_kill(&pd->heartbeat_tasklet);
1478fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare	tasklet_kill(&pd->timeout_tasklet);
148a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger
149a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger	/* Free streams, queued tx frames and farewells. */
150a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger
151a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger	list_for_each_safe(e, n, &pd->stream_list)
152a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger		oz_isoc_stream_free(list_entry(e, struct oz_isoc_stream, link));
153a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger
154a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger	list_for_each_safe(e, n, &pd->tx_queue) {
155a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger		struct oz_tx_frame *f = list_entry(e, struct oz_tx_frame, link);
15633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		if (f->skb != NULL)
157dd3cef0f0715b79d29a4b0482117175f44b7d83cGreg Kroah-Hartman			kfree_skb(f->skb);
158bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_retire_frame(pd, f);
159bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
160a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger
161bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_elt_buf_term(&pd->elt_buff);
162a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger
163a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger	list_for_each_safe(e, n, &pd->farewell_list)
164a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger		kfree(list_entry(e, struct oz_farewell, link));
165a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger
166bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (pd->net_dev)
167bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		dev_put(pd->net_dev);
1681ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman	kfree(pd);
169bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
1706e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
1714e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
1726af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare * Context: softirq or Process
1736af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare */
1746af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujarevoid oz_pd_destroy(struct oz_pd *pd)
1756af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare{
1766af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare	if (hrtimer_active(&pd->timeout))
1776af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare		hrtimer_cancel(&pd->timeout);
1786af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare	if (hrtimer_active(&pd->heartbeat))
1796af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare		hrtimer_cancel(&pd->heartbeat);
1806af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare
1816af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare	INIT_WORK(&pd->workitem, oz_pd_free);
182dfc065f19fe0ce4ef7a52011801c5c19131e6529Rupesh Gujare	if (!schedule_work(&pd->workitem))
1836af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare		oz_pd_dbg(pd, ON, "failed to schedule workitem\n");
1846af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare}
1856af47622398d65e4cb3a52af5de52c6b447270d5Rupesh Gujare
1864e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
187bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq-serialized
188bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
189bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyint oz_services_start(struct oz_pd *pd, u16 apps, int resume)
190bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
191a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger	int i, rc = 0;
19218f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
193f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches	oz_pd_dbg(pd, ON, "%s: (0x%x) resume(%d)\n", __func__, apps, resume);
194a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger	for (i = 0; i < OZ_NB_APPS; i++) {
195a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger		if (g_app_if[i].start && (apps & (1 << i))) {
196a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger			if (g_app_if[i].start(pd, resume)) {
197bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly				rc = -1;
198f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches				oz_pd_dbg(pd, ON,
199a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger					  "Unable to start service %d\n", i);
200bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly				break;
201bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			}
2026b029336d93d8f9a94b0256b1f7d9c1768eedba7Surendra Patil			spin_lock_bh(&g_polling_lock);
203a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger			pd->total_apps |= (1 << i);
204bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			if (resume)
205a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger				pd->paused_apps &= ~(1 << i);
2066b029336d93d8f9a94b0256b1f7d9c1768eedba7Surendra Patil			spin_unlock_bh(&g_polling_lock);
207bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		}
208bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
209bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return rc;
210bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
2116e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
2124e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
213bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
214bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
215bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_services_stop(struct oz_pd *pd, u16 apps, int pause)
216bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
217a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger	int i;
21818f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
219f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches	oz_pd_dbg(pd, ON, "%s: (0x%x) pause(%d)\n", __func__, apps, pause);
220a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger	for (i = 0; i < OZ_NB_APPS; i++) {
221a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger		if (g_app_if[i].stop && (apps & (1 << i))) {
2226b029336d93d8f9a94b0256b1f7d9c1768eedba7Surendra Patil			spin_lock_bh(&g_polling_lock);
223bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			if (pause) {
224a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger				pd->paused_apps |=  (1 << i);
225bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			} else {
226a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger				pd->total_apps  &= ~(1 << i);
227a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger				pd->paused_apps &= ~(1 << i);
228bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			}
2296b029336d93d8f9a94b0256b1f7d9c1768eedba7Surendra Patil			spin_unlock_bh(&g_polling_lock);
230a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger			g_app_if[i].stop(pd, pause);
231bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		}
232bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
233bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
2346e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
2354e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
236bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
237bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
238bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_pd_heartbeat(struct oz_pd *pd, u16 apps)
239bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
240a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger	int i, more = 0;
24118f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
242a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger	for (i = 0; i < OZ_NB_APPS; i++) {
243a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger		if (g_app_if[i].heartbeat && (apps & (1 << i))) {
244a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger			if (g_app_if[i].heartbeat(pd))
245bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly				more = 1;
246bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		}
247bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
2488fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare	if ((!more) && (hrtimer_active(&pd->heartbeat)))
2498fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare		hrtimer_cancel(&pd->heartbeat);
250bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (pd->mode & OZ_F_ISOC_ANYTIME) {
251bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		int count = 8;
252bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		while (count-- && (oz_send_isoc_frame(pd) >= 0))
253bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			;
254bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
255bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
2566e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
2574e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
258bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
259bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
260bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_pd_stop(struct oz_pd *pd)
261bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
262a15e042e262bb62cd8dd9a7ccda9137c9e65cedcRupesh Gujare	u16 stop_apps;
26318f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
264f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches	oz_dbg(ON, "oz_pd_stop() State = 0x%x\n", pd->state);
265bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_pd_indicate_farewells(pd);
2666b029336d93d8f9a94b0256b1f7d9c1768eedba7Surendra Patil	spin_lock_bh(&g_polling_lock);
267bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	stop_apps = pd->total_apps;
268bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	pd->total_apps = 0;
269bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	pd->paused_apps = 0;
2706b029336d93d8f9a94b0256b1f7d9c1768eedba7Surendra Patil	spin_unlock_bh(&g_polling_lock);
271bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_services_stop(pd, stop_apps, 0);
2726b029336d93d8f9a94b0256b1f7d9c1768eedba7Surendra Patil	spin_lock_bh(&g_polling_lock);
273bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_pd_set_state(pd, OZ_PD_S_STOPPED);
274bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Remove from PD list.*/
275bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	list_del(&pd->link);
2766b029336d93d8f9a94b0256b1f7d9c1768eedba7Surendra Patil	spin_unlock_bh(&g_polling_lock);
277f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches	oz_dbg(ON, "pd ref count = %d\n", atomic_read(&pd->ref_count));
278bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_pd_put(pd);
279bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
2806e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
2814e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
282bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
283bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
284bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyint oz_pd_sleep(struct oz_pd *pd)
285bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
286bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	int do_stop = 0;
287a15e042e262bb62cd8dd9a7ccda9137c9e65cedcRupesh Gujare	u16 stop_apps;
28818f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
2896b029336d93d8f9a94b0256b1f7d9c1768eedba7Surendra Patil	spin_lock_bh(&g_polling_lock);
290bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (pd->state & (OZ_PD_S_SLEEP | OZ_PD_S_STOPPED)) {
2916b029336d93d8f9a94b0256b1f7d9c1768eedba7Surendra Patil		spin_unlock_bh(&g_polling_lock);
292bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return 0;
293bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
2948fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare	if (pd->keep_alive && pd->session_id)
295bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_pd_set_state(pd, OZ_PD_S_SLEEP);
2968fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare	else
297bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		do_stop = 1;
2988fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare
299bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	stop_apps = pd->total_apps;
3006b029336d93d8f9a94b0256b1f7d9c1768eedba7Surendra Patil	spin_unlock_bh(&g_polling_lock);
301bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (do_stop) {
302bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_pd_stop(pd);
303bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	} else {
304bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_services_stop(pd, stop_apps, 1);
3058fd070077410b26847ef6f5856850df417e7b83eRupesh Gujare		oz_timer_add(pd, OZ_TIMER_STOP, pd->keep_alive);
306bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
307bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return do_stop;
308bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
3096e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
3104e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
311bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
312bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
313bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic struct oz_tx_frame *oz_tx_frame_alloc(struct oz_pd *pd)
314bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
31550222db4b03ac8f3259c6d39bbd585ed3358f70fChristoph Jaeger	struct oz_tx_frame *f;
31618f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
31750222db4b03ac8f3259c6d39bbd585ed3358f70fChristoph Jaeger	f = kmem_cache_alloc(oz_tx_frame_cache, GFP_ATOMIC);
318bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (f) {
319bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		f->total_size = sizeof(struct oz_hdr);
320bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		INIT_LIST_HEAD(&f->link);
321bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		INIT_LIST_HEAD(&f->elt_list);
322bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
323bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return f;
324bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
3256e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
3264e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
327bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
328bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
32933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujarestatic void oz_tx_isoc_free(struct oz_pd *pd, struct oz_tx_frame *f)
33033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare{
33133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	pd->nb_queued_isoc_frames--;
33233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	list_del_init(&f->link);
33350222db4b03ac8f3259c6d39bbd585ed3358f70fChristoph Jaeger
33450222db4b03ac8f3259c6d39bbd585ed3358f70fChristoph Jaeger	kmem_cache_free(oz_tx_frame_cache, f);
33550222db4b03ac8f3259c6d39bbd585ed3358f70fChristoph Jaeger
336f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches	oz_dbg(TX_FRAMES, "Releasing ISOC Frame isoc_nb= %d\n",
337f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches	       pd->nb_queued_isoc_frames);
33833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare}
3396e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
3404e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
34133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare * Context: softirq or process
34233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare */
343bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_tx_frame_free(struct oz_pd *pd, struct oz_tx_frame *f)
344bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
34550222db4b03ac8f3259c6d39bbd585ed3358f70fChristoph Jaeger	kmem_cache_free(oz_tx_frame_cache, f);
346bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
3476e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
3484e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
34933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare * Context: softirq-serialized
35033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare */
351a7f74c3005cf6830a20d71c4e1d8d6d77443e5cbPeter Huewestatic void oz_set_more_bit(struct sk_buff *skb)
35233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare{
35333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	struct oz_hdr *oz_hdr = (struct oz_hdr *)skb_network_header(skb);
35418f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
35533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	oz_hdr->control |= OZ_F_MORE_DATA;
35633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare}
3576e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
3584e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
35900ec12b827d2f99202e0c9d804514aef2febf8d6Rupesh Gujare * Context: softirq-serialized
36000ec12b827d2f99202e0c9d804514aef2febf8d6Rupesh Gujare */
361a7f74c3005cf6830a20d71c4e1d8d6d77443e5cbPeter Huewestatic void oz_set_last_pkt_nb(struct oz_pd *pd, struct sk_buff *skb)
36200ec12b827d2f99202e0c9d804514aef2febf8d6Rupesh Gujare{
36300ec12b827d2f99202e0c9d804514aef2febf8d6Rupesh Gujare	struct oz_hdr *oz_hdr = (struct oz_hdr *)skb_network_header(skb);
36418f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
36500ec12b827d2f99202e0c9d804514aef2febf8d6Rupesh Gujare	oz_hdr->last_pkt_num = pd->trigger_pkt_num & OZ_LAST_PN_MASK;
36600ec12b827d2f99202e0c9d804514aef2febf8d6Rupesh Gujare}
3676e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
3684e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
369bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
370bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
371bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyint oz_prepare_frame(struct oz_pd *pd, int empty)
372bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
373bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_tx_frame *f;
37418f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
375bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if ((pd->mode & OZ_MODE_MASK) != OZ_MODE_TRIGGERED)
376bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return -1;
377bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (pd->nb_queued_frames >= OZ_MAX_QUEUED_FRAMES)
378bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return -1;
379bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (!empty && !oz_are_elts_available(&pd->elt_buff))
380bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return -1;
381bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	f = oz_tx_frame_alloc(pd);
38286b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	if (f == NULL)
383bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return -1;
38433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	f->skb = NULL;
385bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	f->hdr.control =
386bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		(OZ_PROTOCOL_VERSION<<OZ_VERSION_SHIFT) | OZ_F_ACK_REQUESTED;
387bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	++pd->last_tx_pkt_num;
388bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	put_unaligned(cpu_to_le32(pd->last_tx_pkt_num), &f->hdr.pkt_num);
389bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (empty == 0) {
390bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_select_elts_for_tx(&pd->elt_buff, 0, &f->total_size,
391bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			pd->max_tx_size, &f->elt_list);
392bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
393bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_lock(&pd->tx_frame_lock);
394bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	list_add_tail(&f->link, &pd->tx_queue);
395bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	pd->nb_queued_frames++;
396bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_unlock(&pd->tx_frame_lock);
397bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return 0;
398bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
3996e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
4004e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
401bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq-serialized
402bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
403bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic struct sk_buff *oz_build_frame(struct oz_pd *pd, struct oz_tx_frame *f)
404bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
40586b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	struct sk_buff *skb;
406bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct net_device *dev = pd->net_dev;
407bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_hdr *oz_hdr;
408bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_elt *elt;
409a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger	struct oz_elt_info *ei;
41018f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
411bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Allocate skb with enough space for the lower layers as well
412bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	 * as the space we need.
413bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	 */
414ec0ee957f657b6200a2629d4c54df68d2c622e12Greg Kroah-Hartman	skb = alloc_skb(f->total_size + OZ_ALLOCATED_SPACE(dev), GFP_ATOMIC);
41586b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	if (skb == NULL)
41686b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe		return NULL;
417bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Reserve the head room for lower layers.
418bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	 */
419bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb_reserve(skb, LL_RESERVED_SPACE(dev));
420bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb_reset_network_header(skb);
421bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb->dev = dev;
422bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb->protocol = htons(OZ_ETHERTYPE);
423bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (dev_hard_header(skb, dev, OZ_ETHERTYPE, pd->mac_addr,
424bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		dev->dev_addr, skb->len) < 0)
425bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		goto fail;
426bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Push the tail to the end of the area we are going to copy to.
427bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	 */
428bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_hdr = (struct oz_hdr *)skb_put(skb, f->total_size);
429bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	f->hdr.last_pkt_num = pd->trigger_pkt_num & OZ_LAST_PN_MASK;
430bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	memcpy(oz_hdr, &f->hdr, sizeof(struct oz_hdr));
431bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Copy the elements into the frame body.
432bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	 */
433bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	elt = (struct oz_elt *)(oz_hdr+1);
434a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger	list_for_each_entry(ei, &f->elt_list, link) {
435bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		memcpy(elt, ei->data, ei->length);
436bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		elt = oz_next_elt(elt);
437bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
438bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return skb;
439bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyfail:
440dd3cef0f0715b79d29a4b0482117175f44b7d83cGreg Kroah-Hartman	kfree_skb(skb);
44186b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	return NULL;
442bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
4436e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
4444e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
445bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
446bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
447bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_retire_frame(struct oz_pd *pd, struct oz_tx_frame *f)
448bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
449a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger	struct oz_elt_info *ei, *n;
45018f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
451a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger	list_for_each_entry_safe(ei, n, &f->elt_list, link) {
452bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		list_del_init(&ei->link);
453bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (ei->callback)
454bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			ei->callback(pd, ei->context);
455bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_lock_bh(&pd->elt_buff.lock);
456bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_elt_info_free(&pd->elt_buff, ei);
457bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_unlock_bh(&pd->elt_buff.lock);
458bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
459bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_tx_frame_free(pd, f);
460bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
4616e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
4624e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
463bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq-serialized
464bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
46533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujarestatic int oz_send_next_queued_frame(struct oz_pd *pd, int more_data)
466bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
467bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct sk_buff *skb;
468bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_tx_frame *f;
469bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct list_head *e;
47018f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
471bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_lock(&pd->tx_frame_lock);
472bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	e = pd->last_sent_frame->next;
473bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (e == &pd->tx_queue) {
474bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_unlock(&pd->tx_frame_lock);
475bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return -1;
476bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
477a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger	f = list_entry(e, struct oz_tx_frame, link);
47833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
47933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	if (f->skb != NULL) {
48033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		skb = f->skb;
48133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		oz_tx_isoc_free(pd, f);
48233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		spin_unlock(&pd->tx_frame_lock);
48333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		if (more_data)
48433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			oz_set_more_bit(skb);
48500ec12b827d2f99202e0c9d804514aef2febf8d6Rupesh Gujare		oz_set_last_pkt_nb(pd, skb);
48633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		if ((int)atomic_read(&g_submitted_isoc) <
48733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare							OZ_MAX_SUBMITTED_ISOC) {
48833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			if (dev_queue_xmit(skb) < 0) {
489f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches				oz_dbg(TX_FRAMES, "Dropping ISOC Frame\n");
49033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				return -1;
49133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			}
49233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			atomic_inc(&g_submitted_isoc);
493f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches			oz_dbg(TX_FRAMES, "Sending ISOC Frame, nb_isoc= %d\n",
494f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches			       pd->nb_queued_isoc_frames);
49533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			return 0;
49633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		} else {
497dd3cef0f0715b79d29a4b0482117175f44b7d83cGreg Kroah-Hartman			kfree_skb(skb);
498f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches			oz_dbg(TX_FRAMES, "Dropping ISOC Frame>\n");
49933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			return -1;
50033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		}
50133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	}
50233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
50333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	pd->last_sent_frame = e;
504bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb = oz_build_frame(pd, f);
505bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_unlock(&pd->tx_frame_lock);
50637bc8f7856fc0c851980f01174ca936741511523Rupesh Gujare	if (!skb)
50737bc8f7856fc0c851980f01174ca936741511523Rupesh Gujare		return -1;
50833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	if (more_data)
50933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		oz_set_more_bit(skb);
510f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches	oz_dbg(TX_FRAMES, "TX frame PN=0x%x\n", f->hdr.pkt_num);
51137bc8f7856fc0c851980f01174ca936741511523Rupesh Gujare	if (dev_queue_xmit(skb) < 0)
51237bc8f7856fc0c851980f01174ca936741511523Rupesh Gujare		return -1;
51333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
514bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return 0;
515bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
5166e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
5174e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
518bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq-serialized
519bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
520bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_send_queued_frames(struct oz_pd *pd, int backlog)
521bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
52233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	while (oz_prepare_frame(pd, 0) >= 0)
52333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		backlog++;
52433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
52533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	switch (pd->mode & (OZ_F_ISOC_NO_ELTS | OZ_F_ISOC_ANYTIME)) {
52633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
52733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		case OZ_F_ISOC_NO_ELTS: {
52833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			backlog += pd->nb_queued_isoc_frames;
52933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			if (backlog <= 0)
53033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				goto out;
53133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			if (backlog > OZ_MAX_SUBMITTED_ISOC)
53233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				backlog = OZ_MAX_SUBMITTED_ISOC;
53333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			break;
534bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		}
53533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		case OZ_NO_ELTS_ANYTIME: {
53633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			if ((backlog <= 0) && (pd->isoc_sent == 0))
53733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				goto out;
53833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			break;
53933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		}
54033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		default: {
54133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			if (backlog <= 0)
54233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				goto out;
54333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			break;
54433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		}
54533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	}
54633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	while (backlog--) {
54733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		if (oz_send_next_queued_frame(pd, backlog) < 0)
54833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			break;
549bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
55033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	return;
55133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
55233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujareout:	oz_prepare_frame(pd, 1);
55333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	oz_send_next_queued_frame(pd, 0);
554bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
5556e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
5564e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
557bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
558bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
559bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic int oz_send_isoc_frame(struct oz_pd *pd)
560bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
56186b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	struct sk_buff *skb;
562bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct net_device *dev = pd->net_dev;
563bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_hdr *oz_hdr;
564bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_elt *elt;
565a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger	struct oz_elt_info *ei;
566a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger	LIST_HEAD(list);
567bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	int total_size = sizeof(struct oz_hdr);
56818f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
569bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_select_elts_for_tx(&pd->elt_buff, 1, &total_size,
570bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->max_tx_size, &list);
571a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger	if (list_empty(&list))
572bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return 0;
573ec0ee957f657b6200a2629d4c54df68d2c622e12Greg Kroah-Hartman	skb = alloc_skb(total_size + OZ_ALLOCATED_SPACE(dev), GFP_ATOMIC);
57486b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	if (skb == NULL) {
575f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches		oz_dbg(ON, "Cannot alloc skb\n");
576bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_elt_info_free_chain(&pd->elt_buff, &list);
577bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return -1;
578bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
579bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb_reserve(skb, LL_RESERVED_SPACE(dev));
580bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb_reset_network_header(skb);
581bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb->dev = dev;
582bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	skb->protocol = htons(OZ_ETHERTYPE);
583bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (dev_hard_header(skb, dev, OZ_ETHERTYPE, pd->mac_addr,
584bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		dev->dev_addr, skb->len) < 0) {
585dd3cef0f0715b79d29a4b0482117175f44b7d83cGreg Kroah-Hartman		kfree_skb(skb);
586bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return -1;
587bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
588bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_hdr = (struct oz_hdr *)skb_put(skb, total_size);
589bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_hdr->control = (OZ_PROTOCOL_VERSION<<OZ_VERSION_SHIFT) | OZ_F_ISOC;
590bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_hdr->last_pkt_num = pd->trigger_pkt_num & OZ_LAST_PN_MASK;
591bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	elt = (struct oz_elt *)(oz_hdr+1);
592bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly
593a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger	list_for_each_entry(ei, &list, link) {
594bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		memcpy(elt, ei->data, ei->length);
595bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		elt = oz_next_elt(elt);
596bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
597bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	dev_queue_xmit(skb);
598bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	oz_elt_info_free_chain(&pd->elt_buff, &list);
599bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return 0;
600bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
6016e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
6024e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
603bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq-serialized
604bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
605bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_retire_tx_frames(struct oz_pd *pd, u8 lpn)
606bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
607a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger	struct oz_tx_frame *f, *tmp = NULL;
608bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	u8 diff;
609bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	u32 pkt_num;
610bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly
611a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger	LIST_HEAD(list);
612a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger
613bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_lock(&pd->tx_frame_lock);
614a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger	list_for_each_entry(f, &pd->tx_queue, link) {
615bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pkt_num = le32_to_cpu(get_unaligned(&f->hdr.pkt_num));
616bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		diff = (lpn - (pkt_num & OZ_LAST_PN_MASK)) & OZ_LAST_PN_MASK;
61733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		if ((diff > OZ_LAST_PN_HALF_CYCLE) || (pkt_num == 0))
618bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			break;
619f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches		oz_dbg(TX_FRAMES, "Releasing pkt_num= %u, nb= %d\n",
620f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches		       pkt_num, pd->nb_queued_frames);
621a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger		tmp = f;
622bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		pd->nb_queued_frames--;
623bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
624a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger	if (tmp)
625a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger		list_cut_position(&list, &pd->tx_queue, &tmp->link);
626bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	pd->last_sent_frame = &pd->tx_queue;
627bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_unlock(&pd->tx_frame_lock);
628a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger
629a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger	list_for_each_entry_safe(f, tmp, &list, link)
630bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_retire_frame(pd, f);
631bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
6326e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
6334e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
634bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Precondition: stream_lock must be held.
635bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
636bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
637bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic struct oz_isoc_stream *pd_stream_find(struct oz_pd *pd, u8 ep_num)
638bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
639bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_isoc_stream *st;
64018f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
641a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger	list_for_each_entry(st, &pd->stream_list, link) {
642bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (st->ep_num == ep_num)
643bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			return st;
644bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
64586b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	return NULL;
646bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
6476e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
6484e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
649bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
650bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
651bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyint oz_isoc_stream_create(struct oz_pd *pd, u8 ep_num)
652bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
653bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_isoc_stream *st =
6541ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman		kzalloc(sizeof(struct oz_isoc_stream), GFP_ATOMIC);
655bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (!st)
6561ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman		return -ENOMEM;
657bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	st->ep_num = ep_num;
658bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_lock_bh(&pd->stream_lock);
659bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (!pd_stream_find(pd, ep_num)) {
660bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		list_add(&st->link, &pd->stream_list);
66186b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe		st = NULL;
662bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
663bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_unlock_bh(&pd->stream_lock);
664b150718ecb6468d2de1ff593c402ec257dd80c8cSachin Kamat	kfree(st);
665bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return 0;
666bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
6676e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
6684e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
669bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
670bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
671bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_isoc_stream_free(struct oz_isoc_stream *st)
672bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
673dd3cef0f0715b79d29a4b0482117175f44b7d83cGreg Kroah-Hartman	kfree_skb(st->skb);
6741ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman	kfree(st);
675bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
6766e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
6774e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
678bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
679bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
680bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyint oz_isoc_stream_delete(struct oz_pd *pd, u8 ep_num)
681bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
682bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_isoc_stream *st;
68318f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
684bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_lock_bh(&pd->stream_lock);
685bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	st = pd_stream_find(pd, ep_num);
686bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (st)
687bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		list_del(&st->link);
688bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_unlock_bh(&pd->stream_lock);
689bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (st)
690bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_isoc_stream_free(st);
691bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return 0;
692bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
6936e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
6944e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
695bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: any
696bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
697bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellystatic void oz_isoc_destructor(struct sk_buff *skb)
698bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
699bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	atomic_dec(&g_submitted_isoc);
700bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
7016e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
7024e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
703bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq
704bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
705dc7f5b3594fdb846890192fd75793a791d7ba83bPeter Hueweint oz_send_isoc_unit(struct oz_pd *pd, u8 ep_num, const u8 *data, int len)
706bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
707bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct net_device *dev = pd->net_dev;
708bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_isoc_stream *st;
709bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	u8 nb_units = 0;
71086b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	struct sk_buff *skb = NULL;
71186b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe	struct oz_hdr *oz_hdr = NULL;
712bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	int size = 0;
71318f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
714bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_lock_bh(&pd->stream_lock);
715bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	st = pd_stream_find(pd, ep_num);
716bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (st) {
717bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		skb = st->skb;
71886b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe		st->skb = NULL;
719bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		nb_units = st->nb_units;
720bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		st->nb_units = 0;
721bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_hdr = st->oz_hdr;
722bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		size = st->size;
723bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
724bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	spin_unlock_bh(&pd->stream_lock);
725bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (!st)
726bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		return 0;
727bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (!skb) {
728bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		/* Allocate enough space for max size frame. */
729ec0ee957f657b6200a2629d4c54df68d2c622e12Greg Kroah-Hartman		skb = alloc_skb(pd->max_tx_size + OZ_ALLOCATED_SPACE(dev),
730ec0ee957f657b6200a2629d4c54df68d2c622e12Greg Kroah-Hartman				GFP_ATOMIC);
73186b02be043c42e1d7450be025177e3e248a2e8c1Peter Huewe		if (skb == NULL)
732bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			return 0;
733bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		/* Reserve the head room for lower layers. */
734bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		skb_reserve(skb, LL_RESERVED_SPACE(dev));
735bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		skb_reset_network_header(skb);
736bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		skb->dev = dev;
737bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		skb->protocol = htons(OZ_ETHERTYPE);
73886c948b4416b4c2c064d6c7e15476afbc04e2bf5Rupesh Gujare		/* For audio packet set priority to AC_VO */
73986c948b4416b4c2c064d6c7e15476afbc04e2bf5Rupesh Gujare		skb->priority = 0x7;
740bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		size = sizeof(struct oz_hdr) + sizeof(struct oz_isoc_large);
741bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz_hdr = (struct oz_hdr *)skb_put(skb, size);
742bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
743bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	memcpy(skb_put(skb, len), data, len);
744bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	size += len;
745bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	if (++nb_units < pd->ms_per_isoc) {
746bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_lock_bh(&pd->stream_lock);
747bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		st->skb = skb;
748bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		st->nb_units = nb_units;
749bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		st->oz_hdr = oz_hdr;
750bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		st->size = size;
751bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_unlock_bh(&pd->stream_lock);
752bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	} else {
753bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		struct oz_hdr oz;
754bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		struct oz_isoc_large iso;
755bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_lock_bh(&pd->stream_lock);
756bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		iso.frame_number = st->frame_num;
757bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		st->frame_num += nb_units;
758bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		spin_unlock_bh(&pd->stream_lock);
759bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz.control =
760bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			(OZ_PROTOCOL_VERSION<<OZ_VERSION_SHIFT) | OZ_F_ISOC;
761bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz.last_pkt_num = pd->trigger_pkt_num & OZ_LAST_PN_MASK;
762bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		oz.pkt_num = 0;
763bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		iso.endpoint = ep_num;
764bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		iso.format = OZ_DATA_F_ISOC_LARGE;
765bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		iso.ms_data = nb_units;
766bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		memcpy(oz_hdr, &oz, sizeof(oz));
767bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		memcpy(oz_hdr+1, &iso, sizeof(iso));
768bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (dev_hard_header(skb, dev, OZ_ETHERTYPE, pd->mac_addr,
76933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				dev->dev_addr, skb->len) < 0)
77033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			goto out;
77133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
77233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		skb->destructor = oz_isoc_destructor;
77333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		/*Queue for Xmit if mode is not ANYTIME*/
77433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		if (!(pd->mode & OZ_F_ISOC_ANYTIME)) {
77533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			struct oz_tx_frame *isoc_unit = NULL;
77633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			int nb = pd->nb_queued_isoc_frames;
77786d03a0f4f575dda7988800a3da8d6e9f776a819Rupesh Gujare			if (nb >= pd->isoc_latency) {
7782dc2ee5ccdaf88b41bf9c025acf14ebdc2959a21Rupesh Gujare				struct oz_tx_frame *f;
779f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches				oz_dbg(TX_FRAMES, "Dropping ISOC Unit nb= %d\n",
780f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches				       nb);
7812dc2ee5ccdaf88b41bf9c025acf14ebdc2959a21Rupesh Gujare				spin_lock(&pd->tx_frame_lock);
782a87c38090ea95d36925fefc5cb3d475416f3796cChristoph Jaeger				list_for_each_entry(f, &pd->tx_queue, link) {
7832dc2ee5ccdaf88b41bf9c025acf14ebdc2959a21Rupesh Gujare					if (f->skb != NULL) {
7842dc2ee5ccdaf88b41bf9c025acf14ebdc2959a21Rupesh Gujare						oz_tx_isoc_free(pd, f);
7852dc2ee5ccdaf88b41bf9c025acf14ebdc2959a21Rupesh Gujare						break;
7862dc2ee5ccdaf88b41bf9c025acf14ebdc2959a21Rupesh Gujare					}
7872dc2ee5ccdaf88b41bf9c025acf14ebdc2959a21Rupesh Gujare				}
7882dc2ee5ccdaf88b41bf9c025acf14ebdc2959a21Rupesh Gujare				spin_unlock(&pd->tx_frame_lock);
78933e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			}
79033e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			isoc_unit = oz_tx_frame_alloc(pd);
79133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			if (isoc_unit == NULL)
79233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				goto out;
79333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			isoc_unit->hdr = oz;
79433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			isoc_unit->skb = skb;
79533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			spin_lock_bh(&pd->tx_frame_lock);
79633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			list_add_tail(&isoc_unit->link, &pd->tx_queue);
79733e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			pd->nb_queued_isoc_frames++;
79833e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			spin_unlock_bh(&pd->tx_frame_lock);
799f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches			oz_dbg(TX_FRAMES,
800f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches			       "Added ISOC Frame to Tx Queue isoc_nb= %d, nb= %d\n",
801f724b5843431aba591a01b6988a725689cd9ebb3Joe Perches			       pd->nb_queued_isoc_frames, pd->nb_queued_frames);
80233e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare			return 0;
803bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		}
80433e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
80533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare		/*In ANYTIME mode Xmit unit immediately*/
806bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (atomic_read(&g_submitted_isoc) < OZ_MAX_SUBMITTED_ISOC) {
807bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			atomic_inc(&g_submitted_isoc);
808255ece7c4d9e63e2a5e784247bc2e7b639cae4ddRupesh Gujare			if (dev_queue_xmit(skb) < 0)
809bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly				return -1;
810255ece7c4d9e63e2a5e784247bc2e7b639cae4ddRupesh Gujare			else
81133e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare				return 0;
812bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		}
81333e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
814255ece7c4d9e63e2a5e784247bc2e7b639cae4ddRupesh Gujareout:	kfree_skb(skb);
81533e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare	return -1;
81633e6ada17fffc54c24607d5acb279363b30ac401Rupesh Gujare
817bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
818bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	return 0;
819bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
8206e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
8214e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
822bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: process
823bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
824bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_apps_init(void)
825bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
826bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	int i;
82718f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
828a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger	for (i = 0; i < OZ_NB_APPS; i++) {
829bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (g_app_if[i].init)
830bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			g_app_if[i].init();
831a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger	}
832bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
8336e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
8344e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
835bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: process
836bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
837bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_apps_term(void)
838bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
839bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	int i;
84018f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
841bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	/* Terminate all the apps. */
842a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger	for (i = 0; i < OZ_NB_APPS; i++) {
843bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (g_app_if[i].term)
844bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			g_app_if[i].term();
845a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger	}
846bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
8476e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
8484e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
849bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq-serialized
850bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
851bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_handle_app_elt(struct oz_pd *pd, u8 app_id, struct oz_elt *elt)
852bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
853a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger	if (app_id < OZ_NB_APPS && g_app_if[app_id].rx)
854a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger		g_app_if[app_id].rx(pd, elt);
855bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
8566e244a8319ab80acdda424795e85687fb6af0be2Rupesh Gujare
8574e7fb829771de2cf8a5ba9576290d76936d3e814Rupesh Gujare/*
858bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly * Context: softirq or process
859bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly */
860bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kellyvoid oz_pd_indicate_farewells(struct oz_pd *pd)
861bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly{
862bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	struct oz_farewell *f;
863a9686e786896297f9f1d74a2cac4ffccc7b3e50eChristoph Jaeger	const struct oz_app_if *ai = &g_app_if[OZ_APPID_USB];
86418f8191e1f35d65221ad3b7c68c08fe1c09edb1dRupesh Gujare
865bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	while (1) {
8666b029336d93d8f9a94b0256b1f7d9c1768eedba7Surendra Patil		spin_lock_bh(&g_polling_lock);
867bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (list_empty(&pd->farewell_list)) {
8686b029336d93d8f9a94b0256b1f7d9c1768eedba7Surendra Patil			spin_unlock_bh(&g_polling_lock);
869bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			break;
870bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		}
871bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		f = list_first_entry(&pd->farewell_list,
872bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly				struct oz_farewell, link);
873bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		list_del(&f->link);
8746b029336d93d8f9a94b0256b1f7d9c1768eedba7Surendra Patil		spin_unlock_bh(&g_polling_lock);
875bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly		if (ai->farewell)
876bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly			ai->farewell(pd, f->ep_num, f->report, f->len);
8771ec41a31fb695682cab7fc7c1f6ced84d188b6f9Greg Kroah-Hartman		kfree(f);
878bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly	}
879bc3157dde35ac3b2ec12229edcfaca58cd7925c0Chris Kelly}
880