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/net/wireless/orinoco.c | |
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/net/wireless/orinoco.c')
-rw-r--r-- | drivers/net/wireless/orinoco.c | 105 |
1 files changed, 86 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); |