aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorDavid Kilroy <kilroyd@gmail.com>2008-08-21 18:28:04 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-08-22 19:28:06 -0400
commit31afcef385bb8bf528c6fbe05b359af9f456f02a (patch)
treec6032f5f81c250cf02bbb6d544bfa9866c5cfc67 /drivers
parent06009fda9fde1b97074ab3d932d0468396bf5d10 (diff)
orinoco: Process bulk of receive interrupt in a tasklet
Read the packet data off the hardware and straight into an skb in the interrupt. We have to do this in case we don't process the tasklet in time. Signed-off-by: David Kilroy <kilroyd@gmail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/orinoco.c105
-rw-r--r--drivers/net/wireless/orinoco.h14
2 files changed, 100 insertions, 19 deletions
diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c
index 5e6f90ba9088..768b39452674 100644
--- a/drivers/net/wireless/orinoco.c
+++ b/drivers/net/wireless/orinoco.c
@@ -1178,15 +1178,23 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
1178 struct net_device_stats *stats = &priv->stats; 1178 struct net_device_stats *stats = &priv->stats;
1179 struct iw_statistics *wstats = &priv->wstats; 1179 struct iw_statistics *wstats = &priv->wstats;
1180 struct sk_buff *skb = NULL; 1180 struct sk_buff *skb = NULL;
1181 u16 rxfid, status, fc; 1181 u16 rxfid, status;
1182 int length; 1182 int length;
1183 struct hermes_rx_descriptor desc; 1183 struct hermes_rx_descriptor *desc;
1184 struct ethhdr *hdr; 1184 struct orinoco_rx_data *rx_data;
1185 int err; 1185 int err;
1186 1186
1187 desc = kmalloc(sizeof(*desc), GFP_ATOMIC);
1188 if (!desc) {
1189 printk(KERN_WARNING
1190 "%s: Can't allocate space for RX descriptor\n",
1191 dev->name);
1192 goto update_stats;
1193 }
1194
1187 rxfid = hermes_read_regn(hw, RXFID); 1195 rxfid = hermes_read_regn(hw, RXFID);
1188 1196
1189 err = hermes_bap_pread(hw, IRQ_BAP, &desc, sizeof(desc), 1197 err = hermes_bap_pread(hw, IRQ_BAP, desc, sizeof(*desc),
1190 rxfid, 0); 1198 rxfid, 0);
1191 if (err) { 1199 if (err) {
1192 printk(KERN_ERR "%s: error %d reading Rx descriptor. " 1200 printk(KERN_ERR "%s: error %d reading Rx descriptor. "
@@ -1194,7 +1202,7 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
1194 goto update_stats; 1202 goto update_stats;
1195 } 1203 }
1196 1204
1197 status = le16_to_cpu(desc.status); 1205 status = le16_to_cpu(desc->status);
1198 1206
1199 if (status & HERMES_RXSTAT_BADCRC) { 1207 if (status & HERMES_RXSTAT_BADCRC) {
1200 DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n", 1208 DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n",
@@ -1205,8 +1213,8 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
1205 1213
1206 /* Handle frames in monitor mode */ 1214 /* Handle frames in monitor mode */
1207 if (priv->iw_mode == IW_MODE_MONITOR) { 1215 if (priv->iw_mode == IW_MODE_MONITOR) {
1208 orinoco_rx_monitor(dev, rxfid, &desc); 1216 orinoco_rx_monitor(dev, rxfid, desc);
1209 return; 1217 goto out;
1210 } 1218 }
1211 1219
1212 if (status & HERMES_RXSTAT_UNDECRYPTABLE) { 1220 if (status & HERMES_RXSTAT_UNDECRYPTABLE) {
@@ -1216,15 +1224,14 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
1216 goto update_stats; 1224 goto update_stats;
1217 } 1225 }
1218 1226
1219 length = le16_to_cpu(desc.data_len); 1227 length = le16_to_cpu(desc->data_len);
1220 fc = le16_to_cpu(desc.frame_ctl);
1221 1228
1222 /* Sanity checks */ 1229 /* Sanity checks */
1223 if (length < 3) { /* No for even an 802.2 LLC header */ 1230 if (length < 3) { /* No for even an 802.2 LLC header */
1224 /* At least on Symbol firmware with PCF we get quite a 1231 /* At least on Symbol firmware with PCF we get quite a
1225 lot of these legitimately - Poll frames with no 1232 lot of these legitimately - Poll frames with no
1226 data. */ 1233 data. */
1227 return; 1234 goto out;
1228 } 1235 }
1229 if (length > IEEE80211_DATA_LEN) { 1236 if (length > IEEE80211_DATA_LEN) {
1230 printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n", 1237 printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n",
@@ -1259,6 +1266,43 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
1259 goto drop; 1266 goto drop;
1260 } 1267 }
1261 1268
1269 /* Add desc and skb to rx queue */
1270 rx_data = kzalloc(sizeof(*rx_data), GFP_ATOMIC);
1271 if (!rx_data) {
1272 printk(KERN_WARNING "%s: Can't allocate RX packet\n",
1273 dev->name);
1274 goto drop;
1275 }
1276 rx_data->desc = desc;
1277 rx_data->skb = skb;
1278 list_add_tail(&rx_data->list, &priv->rx_list);
1279 tasklet_schedule(&priv->rx_tasklet);
1280
1281 return;
1282
1283drop:
1284 dev_kfree_skb_irq(skb);
1285update_stats:
1286 stats->rx_errors++;
1287 stats->rx_dropped++;
1288out:
1289 kfree(desc);
1290}
1291
1292static void orinoco_rx(struct net_device *dev,
1293 struct hermes_rx_descriptor *desc,
1294 struct sk_buff *skb)
1295{
1296 struct orinoco_private *priv = netdev_priv(dev);
1297 struct net_device_stats *stats = &priv->stats;
1298 u16 status, fc;
1299 int length;
1300 struct ethhdr *hdr;
1301
1302 status = le16_to_cpu(desc->status);
1303 length = le16_to_cpu(desc->data_len);
1304 fc = le16_to_cpu(desc->frame_ctl);
1305
1262 /* Handle decapsulation 1306 /* Handle decapsulation
1263 * In most cases, the firmware tell us about SNAP frames. 1307 * In most cases, the firmware tell us about SNAP frames.
1264 * For some reason, the SNAP frames sent by LinkSys APs 1308 * For some reason, the SNAP frames sent by LinkSys APs
@@ -1277,11 +1321,11 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
1277 hdr = (struct ethhdr *)skb_push(skb, ETH_HLEN); 1321 hdr = (struct ethhdr *)skb_push(skb, ETH_HLEN);
1278 hdr->h_proto = htons(length); 1322 hdr->h_proto = htons(length);
1279 } 1323 }
1280 memcpy(hdr->h_dest, desc.addr1, ETH_ALEN); 1324 memcpy(hdr->h_dest, desc->addr1, ETH_ALEN);
1281 if (fc & IEEE80211_FCTL_FROMDS) 1325 if (fc & IEEE80211_FCTL_FROMDS)
1282 memcpy(hdr->h_source, desc.addr3, ETH_ALEN); 1326 memcpy(hdr->h_source, desc->addr3, ETH_ALEN);
1283 else 1327 else
1284 memcpy(hdr->h_source, desc.addr2, ETH_ALEN); 1328 memcpy(hdr->h_source, desc->addr2, ETH_ALEN);
1285 1329
1286 dev->last_rx = jiffies; 1330 dev->last_rx = jiffies;
1287 skb->protocol = eth_type_trans(skb, dev); 1331 skb->protocol = eth_type_trans(skb, dev);
@@ -1290,7 +1334,7 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
1290 skb->pkt_type = PACKET_OTHERHOST; 1334 skb->pkt_type = PACKET_OTHERHOST;
1291 1335
1292 /* Process the wireless stats if needed */ 1336 /* Process the wireless stats if needed */
1293 orinoco_stat_gather(dev, skb, &desc); 1337 orinoco_stat_gather(dev, skb, desc);
1294 1338
1295 /* Pass the packet to the networking stack */ 1339 /* Pass the packet to the networking stack */
1296 netif_rx(skb); 1340 netif_rx(skb);
@@ -1298,12 +1342,27 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
1298 stats->rx_bytes += length; 1342 stats->rx_bytes += length;
1299 1343
1300 return; 1344 return;
1345}
1301 1346
1302 drop: 1347static void orinoco_rx_isr_tasklet(unsigned long data)
1303 dev_kfree_skb_irq(skb); 1348{
1304 update_stats: 1349 struct net_device *dev = (struct net_device *) data;
1305 stats->rx_errors++; 1350 struct orinoco_private *priv = netdev_priv(dev);
1306 stats->rx_dropped++; 1351 struct orinoco_rx_data *rx_data, *temp;
1352 struct hermes_rx_descriptor *desc;
1353 struct sk_buff *skb;
1354
1355 /* extract desc and skb from queue */
1356 list_for_each_entry_safe(rx_data, temp, &priv->rx_list, list) {
1357 desc = rx_data->desc;
1358 skb = rx_data->skb;
1359 list_del(&rx_data->list);
1360 kfree(rx_data);
1361
1362 orinoco_rx(dev, desc, skb);
1363
1364 kfree(desc);
1365 }
1307} 1366}
1308 1367
1309/********************************************************************/ 1368/********************************************************************/
@@ -3248,6 +3307,10 @@ struct net_device
3248 INIT_WORK(&priv->join_work, orinoco_join_ap); 3307 INIT_WORK(&priv->join_work, orinoco_join_ap);
3249 INIT_WORK(&priv->wevent_work, orinoco_send_wevents); 3308 INIT_WORK(&priv->wevent_work, orinoco_send_wevents);
3250 3309
3310 INIT_LIST_HEAD(&priv->rx_list);
3311 tasklet_init(&priv->rx_tasklet, orinoco_rx_isr_tasklet,
3312 (unsigned long) dev);
3313
3251 netif_carrier_off(dev); 3314 netif_carrier_off(dev);
3252 priv->last_linkstatus = 0xffff; 3315 priv->last_linkstatus = 0xffff;
3253 3316
@@ -3258,6 +3321,10 @@ void free_orinocodev(struct net_device *dev)
3258{ 3321{
3259 struct orinoco_private *priv = netdev_priv(dev); 3322 struct orinoco_private *priv = netdev_priv(dev);
3260 3323
3324 /* No need to empty priv->rx_list: if the tasklet is scheduled
3325 * when we call tasklet_kill it will run one final time,
3326 * emptying the list */
3327 tasklet_kill(&priv->rx_tasklet);
3261 priv->wpa_ie_len = 0; 3328 priv->wpa_ie_len = 0;
3262 kfree(priv->wpa_ie); 3329 kfree(priv->wpa_ie);
3263 orinoco_bss_data_free(priv); 3330 orinoco_bss_data_free(priv);
diff --git a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco.h
index bfab88f51362..e0c9be3daa30 100644
--- a/drivers/net/wireless/orinoco.h
+++ b/drivers/net/wireless/orinoco.h
@@ -9,6 +9,7 @@
9 9
10#define DRIVER_VERSION "0.15" 10#define DRIVER_VERSION "0.15"
11 11
12#include <linux/interrupt.h>
12#include <linux/netdevice.h> 13#include <linux/netdevice.h>
13#include <linux/wireless.h> 14#include <linux/wireless.h>
14#include <net/iw_handler.h> 15#include <net/iw_handler.h>
@@ -57,6 +58,14 @@ struct xbss_element {
57 struct list_head list; 58 struct list_head list;
58}; 59};
59 60
61struct hermes_rx_descriptor;
62
63struct orinoco_rx_data {
64 struct hermes_rx_descriptor *desc;
65 struct sk_buff *skb;
66 struct list_head list;
67};
68
60struct orinoco_private { 69struct orinoco_private {
61 void *card; /* Pointer to card dependent structure */ 70 void *card; /* Pointer to card dependent structure */
62 struct device *dev; 71 struct device *dev;
@@ -68,6 +77,11 @@ struct orinoco_private {
68 int hw_unavailable; 77 int hw_unavailable;
69 struct work_struct reset_work; 78 struct work_struct reset_work;
70 79
80 /* Interrupt tasklets */
81 struct tasklet_struct rx_tasklet;
82 struct list_head rx_list;
83 struct orinoco_rx_data *rx_data;
84
71 /* driver state */ 85 /* driver state */
72 int open; 86 int open;
73 u16 last_linkstatus; 87 u16 last_linkstatus;