~ubuntu-branches/ubuntu/utopic/linux-ti-omap/utopic

« back to all changes in this revision

Viewing changes to drivers/net/wireless/libertas/tx.c

  • Committer: Bazaar Package Importer
  • Author(s): Amit Kucheria, Amit Kucheria
  • Date: 2010-03-10 02:28:15 UTC
  • Revision ID: james.westby@ubuntu.com-20100310022815-7sd3gwvn5kenaq33
Tags: 2.6.33-500.1
[ Amit Kucheria ]

* Initial release of a 2.6.33-based OMAP kernel
* UBUNTU: [Upstream] Fix omap 1-wire driver compilation
* UBUNTU: ubuntu: AppArmor -- update to mainline 2010-03-04

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
  * This file contains the handling of TX in wlan driver.
 
3
  */
 
4
#include <linux/netdevice.h>
 
5
#include <linux/etherdevice.h>
 
6
#include <linux/sched.h>
 
7
 
 
8
#include "host.h"
 
9
#include "radiotap.h"
 
10
#include "decl.h"
 
11
#include "defs.h"
 
12
#include "dev.h"
 
13
#include "wext.h"
 
14
 
 
15
/**
 
16
 *  @brief This function converts Tx/Rx rates from IEEE80211_RADIOTAP_RATE
 
17
 *  units (500 Kb/s) into Marvell WLAN format (see Table 8 in Section 3.2.1)
 
18
 *
 
19
 *  @param rate    Input rate
 
20
 *  @return      Output Rate (0 if invalid)
 
21
 */
 
22
static u32 convert_radiotap_rate_to_mv(u8 rate)
 
23
{
 
24
        switch (rate) {
 
25
        case 2:         /*   1 Mbps */
 
26
                return 0 | (1 << 4);
 
27
        case 4:         /*   2 Mbps */
 
28
                return 1 | (1 << 4);
 
29
        case 11:                /* 5.5 Mbps */
 
30
                return 2 | (1 << 4);
 
31
        case 22:                /*  11 Mbps */
 
32
                return 3 | (1 << 4);
 
33
        case 12:                /*   6 Mbps */
 
34
                return 4 | (1 << 4);
 
35
        case 18:                /*   9 Mbps */
 
36
                return 5 | (1 << 4);
 
37
        case 24:                /*  12 Mbps */
 
38
                return 6 | (1 << 4);
 
39
        case 36:                /*  18 Mbps */
 
40
                return 7 | (1 << 4);
 
41
        case 48:                /*  24 Mbps */
 
42
                return 8 | (1 << 4);
 
43
        case 72:                /*  36 Mbps */
 
44
                return 9 | (1 << 4);
 
45
        case 96:                /*  48 Mbps */
 
46
                return 10 | (1 << 4);
 
47
        case 108:               /*  54 Mbps */
 
48
                return 11 | (1 << 4);
 
49
        }
 
50
        return 0;
 
51
}
 
52
 
 
53
/**
 
54
 *  @brief This function checks the conditions and sends packet to IF
 
55
 *  layer if everything is ok.
 
56
 *
 
57
 *  @param priv    A pointer to struct lbs_private structure
 
58
 *  @param skb     A pointer to skb which includes TX packet
 
59
 *  @return        0 or -1
 
60
 */
 
61
netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
62
{
 
63
        unsigned long flags;
 
64
        struct lbs_private *priv = dev->ml_priv;
 
65
        struct txpd *txpd;
 
66
        char *p802x_hdr;
 
67
        uint16_t pkt_len;
 
68
        netdev_tx_t ret = NETDEV_TX_OK;
 
69
 
 
70
        lbs_deb_enter(LBS_DEB_TX);
 
71
 
 
72
        /* We need to protect against the queues being restarted before
 
73
           we get round to stopping them */
 
74
        spin_lock_irqsave(&priv->driver_lock, flags);
 
75
 
 
76
        if (priv->surpriseremoved)
 
77
                goto free;
 
78
 
 
79
        if (!skb->len || (skb->len > MRVDRV_ETH_TX_PACKET_BUFFER_SIZE)) {
 
80
                lbs_deb_tx("tx err: skb length %d 0 or > %zd\n",
 
81
                       skb->len, MRVDRV_ETH_TX_PACKET_BUFFER_SIZE);
 
82
                /* We'll never manage to send this one; drop it and return 'OK' */
 
83
 
 
84
                dev->stats.tx_dropped++;
 
85
                dev->stats.tx_errors++;
 
86
                goto free;
 
87
        }
 
88
 
 
89
 
 
90
        netif_stop_queue(priv->dev);
 
91
        if (priv->mesh_dev)
 
92
                netif_stop_queue(priv->mesh_dev);
 
93
 
 
94
        if (priv->tx_pending_len) {
 
95
                /* This can happen if packets come in on the mesh and eth
 
96
                   device simultaneously -- there's no mutual exclusion on
 
97
                   hard_start_xmit() calls between devices. */
 
98
                lbs_deb_tx("Packet on %s while busy\n", dev->name);
 
99
                ret = NETDEV_TX_BUSY;
 
100
                goto unlock;
 
101
        }
 
102
 
 
103
        priv->tx_pending_len = -1;
 
104
        spin_unlock_irqrestore(&priv->driver_lock, flags);
 
105
 
 
106
        lbs_deb_hex(LBS_DEB_TX, "TX Data", skb->data, min_t(unsigned int, skb->len, 100));
 
107
 
 
108
        txpd = (void *)priv->tx_pending_buf;
 
109
        memset(txpd, 0, sizeof(struct txpd));
 
110
 
 
111
        p802x_hdr = skb->data;
 
112
        pkt_len = skb->len;
 
113
 
 
114
        if (dev == priv->rtap_net_dev) {
 
115
                struct tx_radiotap_hdr *rtap_hdr = (void *)skb->data;
 
116
 
 
117
                /* set txpd fields from the radiotap header */
 
118
                txpd->tx_control = cpu_to_le32(convert_radiotap_rate_to_mv(rtap_hdr->rate));
 
119
 
 
120
                /* skip the radiotap header */
 
121
                p802x_hdr += sizeof(*rtap_hdr);
 
122
                pkt_len -= sizeof(*rtap_hdr);
 
123
 
 
124
                /* copy destination address from 802.11 header */
 
125
                memcpy(txpd->tx_dest_addr_high, p802x_hdr + 4, ETH_ALEN);
 
126
        } else {
 
127
                /* copy destination address from 802.3 header */
 
128
                memcpy(txpd->tx_dest_addr_high, p802x_hdr, ETH_ALEN);
 
129
        }
 
130
 
 
131
        txpd->tx_packet_length = cpu_to_le16(pkt_len);
 
132
        txpd->tx_packet_location = cpu_to_le32(sizeof(struct txpd));
 
133
 
 
134
        lbs_mesh_set_txpd(priv, dev, txpd);
 
135
 
 
136
        lbs_deb_hex(LBS_DEB_TX, "txpd", (u8 *) &txpd, sizeof(struct txpd));
 
137
 
 
138
        lbs_deb_hex(LBS_DEB_TX, "Tx Data", (u8 *) p802x_hdr, le16_to_cpu(txpd->tx_packet_length));
 
139
 
 
140
        memcpy(&txpd[1], p802x_hdr, le16_to_cpu(txpd->tx_packet_length));
 
141
 
 
142
        spin_lock_irqsave(&priv->driver_lock, flags);
 
143
        priv->tx_pending_len = pkt_len + sizeof(struct txpd);
 
144
 
 
145
        lbs_deb_tx("%s lined up packet\n", __func__);
 
146
 
 
147
        dev->stats.tx_packets++;
 
148
        dev->stats.tx_bytes += skb->len;
 
149
 
 
150
        dev->trans_start = jiffies;
 
151
 
 
152
        if (priv->monitormode) {
 
153
                /* Keep the skb to echo it back once Tx feedback is
 
154
                   received from FW */
 
155
                skb_orphan(skb);
 
156
 
 
157
                /* Keep the skb around for when we get feedback */
 
158
                priv->currenttxskb = skb;
 
159
        } else {
 
160
 free:
 
161
                dev_kfree_skb_any(skb);
 
162
        }
 
163
 unlock:
 
164
        spin_unlock_irqrestore(&priv->driver_lock, flags);
 
165
        wake_up(&priv->waitq);
 
166
 
 
167
        lbs_deb_leave_args(LBS_DEB_TX, "ret %d", ret);
 
168
        return ret;
 
169
}
 
170
 
 
171
/**
 
172
 *  @brief This function sends to the host the last transmitted packet,
 
173
 *  filling the radiotap headers with transmission information.
 
174
 *
 
175
 *  @param priv     A pointer to struct lbs_private structure
 
176
 *  @param status   A 32 bit value containing transmission status.
 
177
 *
 
178
 *  @returns void
 
179
 */
 
180
void lbs_send_tx_feedback(struct lbs_private *priv, u32 try_count)
 
181
{
 
182
        struct tx_radiotap_hdr *radiotap_hdr;
 
183
 
 
184
        if (!priv->monitormode || priv->currenttxskb == NULL)
 
185
                return;
 
186
 
 
187
        radiotap_hdr = (struct tx_radiotap_hdr *)priv->currenttxskb->data;
 
188
 
 
189
        radiotap_hdr->data_retries = try_count ?
 
190
                (1 + priv->txretrycount - try_count) : 0;
 
191
 
 
192
        priv->currenttxskb->protocol = eth_type_trans(priv->currenttxskb,
 
193
                                                      priv->rtap_net_dev);
 
194
        netif_rx(priv->currenttxskb);
 
195
 
 
196
        priv->currenttxskb = NULL;
 
197
 
 
198
        if (priv->connect_status == LBS_CONNECTED)
 
199
                netif_wake_queue(priv->dev);
 
200
 
 
201
        if (priv->mesh_dev && (priv->mesh_connect_status == LBS_CONNECTED))
 
202
                netif_wake_queue(priv->mesh_dev);
 
203
}
 
204
EXPORT_SYMBOL_GPL(lbs_send_tx_feedback);