diff options
author | David Woodhouse <dwmw2@infradead.org> | 2007-12-09 14:37:59 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-28 18:06:25 -0500 |
commit | a2b62dc1f17db16034cd4eee0f14e6e56065547c (patch) | |
tree | 453e3e9fe97df882946fd05805860fc9c6221843 | |
parent | 8af23b2f96dc3dabbc791c75f7c98a7b0d287177 (diff) |
libertas: clean up lbs_hard_start_xmit()
Having merged the nest of functions into one, now we can clean it up and
fix the error handling, and the duplication -- and at least make a start
on the locking.
Signed-off-by: David Woodhouse <dwmw2@infradead.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | drivers/net/wireless/libertas/tx.c | 133 |
1 files changed, 63 insertions, 70 deletions
diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c index 7bc212438259..aefe52419baa 100644 --- a/drivers/net/wireless/libertas/tx.c +++ b/drivers/net/wireless/libertas/tx.c | |||
@@ -58,22 +58,16 @@ static u32 convert_radiotap_rate_to_mv(u8 rate) | |||
58 | */ | 58 | */ |
59 | int lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | 59 | int lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) |
60 | { | 60 | { |
61 | unsigned long flags; | ||
61 | struct lbs_private *priv = dev->priv; | 62 | struct lbs_private *priv = dev->priv; |
62 | int ret = -1; | 63 | struct txpd *txpd; |
63 | struct txpd localtxpd; | 64 | char *p802x_hdr; |
64 | struct txpd *plocaltxpd = &localtxpd; | 65 | uint16_t pkt_len; |
65 | u8 *p802x_hdr; | 66 | int ret; |
66 | struct tx_radiotap_hdr *pradiotap_hdr; | ||
67 | u32 new_rate; | ||
68 | u8 *ptr = priv->tmptxbuf; | ||
69 | 67 | ||
70 | lbs_deb_enter(LBS_DEB_TX); | 68 | lbs_deb_enter(LBS_DEB_TX); |
71 | 69 | ||
72 | lbs_deb_hex(LBS_DEB_TX, "TX Data", skb->data, min_t(unsigned int, skb->len, 100)); | 70 | ret = NETDEV_TX_BUSY; |
73 | |||
74 | netif_stop_queue(priv->dev); | ||
75 | if (priv->mesh_dev) | ||
76 | netif_stop_queue(priv->mesh_dev); | ||
77 | 71 | ||
78 | if (priv->dnld_sent) { | 72 | if (priv->dnld_sent) { |
79 | lbs_pr_alert( "TX error: dnld_sent = %d, not sending\n", | 73 | lbs_pr_alert( "TX error: dnld_sent = %d, not sending\n", |
@@ -94,98 +88,97 @@ int lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
94 | } | 88 | } |
95 | 89 | ||
96 | if (priv->surpriseremoved) | 90 | if (priv->surpriseremoved) |
97 | return -1; | 91 | goto drop; |
98 | 92 | ||
99 | if (!skb->len || (skb->len > MRVDRV_ETH_TX_PACKET_BUFFER_SIZE)) { | 93 | if (!skb->len || (skb->len > MRVDRV_ETH_TX_PACKET_BUFFER_SIZE)) { |
100 | lbs_deb_tx("tx err: skb length %d 0 or > %zd\n", | 94 | lbs_deb_tx("tx err: skb length %d 0 or > %zd\n", |
101 | skb->len, MRVDRV_ETH_TX_PACKET_BUFFER_SIZE); | 95 | skb->len, MRVDRV_ETH_TX_PACKET_BUFFER_SIZE); |
102 | goto done_tx; | 96 | /* We'll never manage to send this one; drop it and return 'OK' */ |
97 | goto drop; | ||
103 | } | 98 | } |
104 | 99 | ||
105 | ret = 0; | 100 | lbs_deb_hex(LBS_DEB_TX, "TX Data", skb->data, min_t(unsigned int, skb->len, 100)); |
106 | memset(plocaltxpd, 0, sizeof(struct txpd)); | ||
107 | |||
108 | plocaltxpd->tx_packet_length = cpu_to_le16(skb->len); | ||
109 | 101 | ||
110 | /* offset of actual data */ | 102 | txpd = (void *)priv->tmptxbuf; |
111 | plocaltxpd->tx_packet_location = cpu_to_le32(sizeof(struct txpd)); | 103 | memset(txpd, 0, sizeof(struct txpd)); |
112 | 104 | ||
113 | p802x_hdr = skb->data; | 105 | p802x_hdr = skb->data; |
114 | if (priv->monitormode != LBS_MONITOR_OFF) { | 106 | pkt_len = skb->len; |
115 | 107 | ||
116 | /* locate radiotap header */ | 108 | if (priv->monitormode != LBS_MONITOR_OFF) { |
117 | pradiotap_hdr = (struct tx_radiotap_hdr *)skb->data; | 109 | struct tx_radiotap_hdr *rtap_hdr = (void *)skb->data; |
118 | 110 | ||
119 | /* set txpd fields from the radiotap header */ | 111 | /* set txpd fields from the radiotap header */ |
120 | new_rate = convert_radiotap_rate_to_mv(pradiotap_hdr->rate); | 112 | txpd->tx_control = cpu_to_le32(convert_radiotap_rate_to_mv(rtap_hdr->rate)); |
121 | if (new_rate != 0) { | ||
122 | /* use new tx_control[4:0] */ | ||
123 | plocaltxpd->tx_control = cpu_to_le32(new_rate); | ||
124 | } | ||
125 | 113 | ||
126 | /* skip the radiotap header */ | 114 | /* skip the radiotap header */ |
127 | p802x_hdr += sizeof(struct tx_radiotap_hdr); | 115 | p802x_hdr += sizeof(*rtap_hdr); |
128 | plocaltxpd->tx_packet_length = | 116 | pkt_len -= sizeof(*rtap_hdr); |
129 | cpu_to_le16(le16_to_cpu(plocaltxpd->tx_packet_length) | ||
130 | - sizeof(struct tx_radiotap_hdr)); | ||
131 | 117 | ||
118 | /* copy destination address from 802.11 header */ | ||
119 | memcpy(txpd->tx_dest_addr_high, p802x_hdr + 4, ETH_ALEN); | ||
120 | } else { | ||
121 | /* copy destination address from 802.3 header */ | ||
122 | memcpy(txpd->tx_dest_addr_high, p802x_hdr, ETH_ALEN); | ||
132 | } | 123 | } |
133 | /* copy destination address from 802.3 or 802.11 header */ | ||
134 | if (priv->monitormode != LBS_MONITOR_OFF) | ||
135 | memcpy(plocaltxpd->tx_dest_addr_high, p802x_hdr + 4, ETH_ALEN); | ||
136 | else | ||
137 | memcpy(plocaltxpd->tx_dest_addr_high, p802x_hdr, ETH_ALEN); | ||
138 | 124 | ||
139 | lbs_deb_hex(LBS_DEB_TX, "txpd", (u8 *) plocaltxpd, sizeof(struct txpd)); | 125 | txpd->tx_packet_length = cpu_to_le16(pkt_len); |
126 | txpd->tx_packet_location = cpu_to_le32(sizeof(struct txpd)); | ||
140 | 127 | ||
141 | if (IS_MESH_FRAME(skb)) { | 128 | if (dev == priv->mesh_dev) |
142 | plocaltxpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME); | 129 | txpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME); |
143 | } | ||
144 | 130 | ||
145 | memcpy(ptr, plocaltxpd, sizeof(struct txpd)); | 131 | lbs_deb_hex(LBS_DEB_TX, "txpd", (u8 *) &txpd, sizeof(struct txpd)); |
146 | 132 | ||
147 | ptr += sizeof(struct txpd); | 133 | lbs_deb_hex(LBS_DEB_TX, "Tx Data", (u8 *) p802x_hdr, le16_to_cpu(txpd->tx_packet_length)); |
148 | 134 | ||
149 | lbs_deb_hex(LBS_DEB_TX, "Tx Data", (u8 *) p802x_hdr, le16_to_cpu(plocaltxpd->tx_packet_length)); | 135 | memcpy(&txpd[1], p802x_hdr, le16_to_cpu(txpd->tx_packet_length)); |
150 | memcpy(ptr, p802x_hdr, le16_to_cpu(plocaltxpd->tx_packet_length)); | ||
151 | ret = priv->hw_host_to_card(priv, MVMS_DAT, | ||
152 | priv->tmptxbuf, | ||
153 | le16_to_cpu(plocaltxpd->tx_packet_length) + | ||
154 | sizeof(struct txpd)); | ||
155 | 136 | ||
156 | if (ret) { | 137 | /* We need to protect against the queues being restarted before |
157 | lbs_deb_tx("tx err: hw_host_to_card returned 0x%X\n", ret); | 138 | we get round to stopping them */ |
158 | goto done_tx; | 139 | spin_lock_irqsave(&priv->driver_lock, flags); |
159 | } | ||
160 | 140 | ||
161 | lbs_deb_tx("%s succeeds\n", __func__); | 141 | ret = priv->hw_host_to_card(priv, MVMS_DAT, priv->tmptxbuf, |
142 | pkt_len + sizeof(struct txpd)); | ||
162 | 143 | ||
163 | done_tx: | ||
164 | if (!ret) { | 144 | if (!ret) { |
145 | lbs_deb_tx("%s succeeds\n", __func__); | ||
146 | |||
147 | /* Stop processing outgoing pkts before submitting */ | ||
148 | netif_stop_queue(priv->dev); | ||
149 | if (priv->mesh_dev) | ||
150 | netif_stop_queue(priv->mesh_dev); | ||
151 | |||
165 | priv->stats.tx_packets++; | 152 | priv->stats.tx_packets++; |
166 | priv->stats.tx_bytes += skb->len; | 153 | priv->stats.tx_bytes += skb->len; |
167 | 154 | ||
168 | dev->trans_start = jiffies; | 155 | dev->trans_start = jiffies; |
169 | } else { | 156 | |
170 | priv->stats.tx_dropped++; | 157 | if (priv->monitormode != LBS_MONITOR_OFF) { |
171 | priv->stats.tx_errors++; | 158 | /* Keep the skb to echo it back once Tx feedback is |
159 | received from FW */ | ||
160 | skb_orphan(skb); | ||
161 | |||
162 | /* Keep the skb around for when we get feedback */ | ||
163 | priv->currenttxskb = skb; | ||
164 | } | ||
172 | } | 165 | } |
166 | |||
167 | spin_unlock_irqrestore(&priv->driver_lock, flags); | ||
173 | 168 | ||
174 | if (!ret && priv->monitormode != LBS_MONITOR_OFF) { | 169 | if (ret) { |
175 | /* Keep the skb to echo it back once Tx feedback is | 170 | lbs_deb_tx("tx err: hw_host_to_card returned 0x%X\n", ret); |
176 | received from FW */ | 171 | drop: |
177 | skb_orphan(skb); | 172 | priv->stats.tx_dropped++; |
178 | /* stop processing outgoing pkts */ | 173 | priv->stats.tx_errors++; |
179 | netif_stop_queue(priv->dev); | ||
180 | if (priv->mesh_dev) | ||
181 | netif_stop_queue(priv->mesh_dev); | ||
182 | 174 | ||
183 | /* Keep the skb around for when we get feedback */ | ||
184 | priv->currenttxskb = skb; | ||
185 | } else { | ||
186 | dev_kfree_skb_any(skb); | 175 | dev_kfree_skb_any(skb); |
187 | } | 176 | } |
188 | 177 | ||
178 | /* Even if we dropped the packet, return OK. Otherwise the | ||
179 | packet gets requeued. */ | ||
180 | ret = NETDEV_TX_OK; | ||
181 | |||
189 | done: | 182 | done: |
190 | lbs_deb_leave_args(LBS_DEB_TX, "ret %d", ret); | 183 | lbs_deb_leave_args(LBS_DEB_TX, "ret %d", ret); |
191 | return ret; | 184 | return ret; |