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