diff options
author | David Kilroy <kilroyd@gmail.com> | 2008-08-21 18:28:04 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-08-22 19:28:06 -0400 |
commit | 31afcef385bb8bf528c6fbe05b359af9f456f02a (patch) | |
tree | c6032f5f81c250cf02bbb6d544bfa9866c5cfc67 /drivers | |
parent | 06009fda9fde1b97074ab3d932d0468396bf5d10 (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.c | 105 | ||||
-rw-r--r-- | drivers/net/wireless/orinoco.h | 14 |
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 | |||
1283 | drop: | ||
1284 | dev_kfree_skb_irq(skb); | ||
1285 | update_stats: | ||
1286 | stats->rx_errors++; | ||
1287 | stats->rx_dropped++; | ||
1288 | out: | ||
1289 | kfree(desc); | ||
1290 | } | ||
1291 | |||
1292 | static 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: | 1347 | static 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 | ||
61 | struct hermes_rx_descriptor; | ||
62 | |||
63 | struct orinoco_rx_data { | ||
64 | struct hermes_rx_descriptor *desc; | ||
65 | struct sk_buff *skb; | ||
66 | struct list_head list; | ||
67 | }; | ||
68 | |||
60 | struct orinoco_private { | 69 | struct 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; |