Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

David Kilroy and committed by
John W. Linville
31afcef3 06009fda

+100 -19
+86 -19
drivers/net/wireless/orinoco.c
··· 1178 1178 struct net_device_stats *stats = &priv->stats; 1179 1179 struct iw_statistics *wstats = &priv->wstats; 1180 1180 struct sk_buff *skb = NULL; 1181 - u16 rxfid, status, fc; 1181 + u16 rxfid, status; 1182 1182 int length; 1183 - struct hermes_rx_descriptor desc; 1184 - struct ethhdr *hdr; 1183 + struct hermes_rx_descriptor *desc; 1184 + struct orinoco_rx_data *rx_data; 1185 1185 int err; 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 + } 1186 1194 1187 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 1198 rxfid, 0); 1191 1199 if (err) { 1192 1200 printk(KERN_ERR "%s: error %d reading Rx descriptor. " ··· 1202 1194 goto update_stats; 1203 1195 } 1204 1196 1205 - status = le16_to_cpu(desc.status); 1197 + status = le16_to_cpu(desc->status); 1206 1198 1207 1199 if (status & HERMES_RXSTAT_BADCRC) { 1208 1200 DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n", ··· 1213 1205 1214 1206 /* Handle frames in monitor mode */ 1215 1207 if (priv->iw_mode == IW_MODE_MONITOR) { 1216 - orinoco_rx_monitor(dev, rxfid, &desc); 1217 - return; 1208 + orinoco_rx_monitor(dev, rxfid, desc); 1209 + goto out; 1218 1210 } 1219 1211 1220 1212 if (status & HERMES_RXSTAT_UNDECRYPTABLE) { ··· 1224 1216 goto update_stats; 1225 1217 } 1226 1218 1227 - length = le16_to_cpu(desc.data_len); 1228 - fc = le16_to_cpu(desc.frame_ctl); 1219 + length = le16_to_cpu(desc->data_len); 1229 1220 1230 1221 /* Sanity checks */ 1231 1222 if (length < 3) { /* No for even an 802.2 LLC header */ 1232 1223 /* At least on Symbol firmware with PCF we get quite a 1233 1224 lot of these legitimately - Poll frames with no 1234 1225 data. */ 1235 - return; 1226 + goto out; 1236 1227 } 1237 1228 if (length > IEEE80211_DATA_LEN) { 1238 1229 printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n", ··· 1266 1259 goto drop; 1267 1260 } 1268 1261 1262 + /* Add desc and skb to rx queue */ 1263 + rx_data = kzalloc(sizeof(*rx_data), GFP_ATOMIC); 1264 + if (!rx_data) { 1265 + printk(KERN_WARNING "%s: Can't allocate RX packet\n", 1266 + dev->name); 1267 + goto drop; 1268 + } 1269 + rx_data->desc = desc; 1270 + rx_data->skb = skb; 1271 + list_add_tail(&rx_data->list, &priv->rx_list); 1272 + tasklet_schedule(&priv->rx_tasklet); 1273 + 1274 + return; 1275 + 1276 + drop: 1277 + dev_kfree_skb_irq(skb); 1278 + update_stats: 1279 + stats->rx_errors++; 1280 + stats->rx_dropped++; 1281 + out: 1282 + kfree(desc); 1283 + } 1284 + 1285 + static void orinoco_rx(struct net_device *dev, 1286 + struct hermes_rx_descriptor *desc, 1287 + struct sk_buff *skb) 1288 + { 1289 + struct orinoco_private *priv = netdev_priv(dev); 1290 + struct net_device_stats *stats = &priv->stats; 1291 + u16 status, fc; 1292 + int length; 1293 + struct ethhdr *hdr; 1294 + 1295 + status = le16_to_cpu(desc->status); 1296 + length = le16_to_cpu(desc->data_len); 1297 + fc = le16_to_cpu(desc->frame_ctl); 1298 + 1269 1299 /* Handle decapsulation 1270 1300 * In most cases, the firmware tell us about SNAP frames. 1271 1301 * For some reason, the SNAP frames sent by LinkSys APs ··· 1321 1277 hdr = (struct ethhdr *)skb_push(skb, ETH_HLEN); 1322 1278 hdr->h_proto = htons(length); 1323 1279 } 1324 - memcpy(hdr->h_dest, desc.addr1, ETH_ALEN); 1280 + memcpy(hdr->h_dest, desc->addr1, ETH_ALEN); 1325 1281 if (fc & IEEE80211_FCTL_FROMDS) 1326 - memcpy(hdr->h_source, desc.addr3, ETH_ALEN); 1282 + memcpy(hdr->h_source, desc->addr3, ETH_ALEN); 1327 1283 else 1328 - memcpy(hdr->h_source, desc.addr2, ETH_ALEN); 1284 + memcpy(hdr->h_source, desc->addr2, ETH_ALEN); 1329 1285 1330 1286 dev->last_rx = jiffies; 1331 1287 skb->protocol = eth_type_trans(skb, dev); ··· 1334 1290 skb->pkt_type = PACKET_OTHERHOST; 1335 1291 1336 1292 /* Process the wireless stats if needed */ 1337 - orinoco_stat_gather(dev, skb, &desc); 1293 + orinoco_stat_gather(dev, skb, desc); 1338 1294 1339 1295 /* Pass the packet to the networking stack */ 1340 1296 netif_rx(skb); ··· 1342 1298 stats->rx_bytes += length; 1343 1299 1344 1300 return; 1301 + } 1345 1302 1346 - drop: 1347 - dev_kfree_skb_irq(skb); 1348 - update_stats: 1349 - stats->rx_errors++; 1350 - stats->rx_dropped++; 1303 + static void orinoco_rx_isr_tasklet(unsigned long data) 1304 + { 1305 + struct net_device *dev = (struct net_device *) data; 1306 + struct orinoco_private *priv = netdev_priv(dev); 1307 + struct orinoco_rx_data *rx_data, *temp; 1308 + struct hermes_rx_descriptor *desc; 1309 + struct sk_buff *skb; 1310 + 1311 + /* extract desc and skb from queue */ 1312 + list_for_each_entry_safe(rx_data, temp, &priv->rx_list, list) { 1313 + desc = rx_data->desc; 1314 + skb = rx_data->skb; 1315 + list_del(&rx_data->list); 1316 + kfree(rx_data); 1317 + 1318 + orinoco_rx(dev, desc, skb); 1319 + 1320 + kfree(desc); 1321 + } 1351 1322 } 1352 1323 1353 1324 /********************************************************************/ ··· 3307 3248 INIT_WORK(&priv->join_work, orinoco_join_ap); 3308 3249 INIT_WORK(&priv->wevent_work, orinoco_send_wevents); 3309 3250 3251 + INIT_LIST_HEAD(&priv->rx_list); 3252 + tasklet_init(&priv->rx_tasklet, orinoco_rx_isr_tasklet, 3253 + (unsigned long) dev); 3254 + 3310 3255 netif_carrier_off(dev); 3311 3256 priv->last_linkstatus = 0xffff; 3312 3257 ··· 3321 3258 { 3322 3259 struct orinoco_private *priv = netdev_priv(dev); 3323 3260 3261 + /* No need to empty priv->rx_list: if the tasklet is scheduled 3262 + * when we call tasklet_kill it will run one final time, 3263 + * emptying the list */ 3264 + tasklet_kill(&priv->rx_tasklet); 3324 3265 priv->wpa_ie_len = 0; 3325 3266 kfree(priv->wpa_ie); 3326 3267 orinoco_bss_data_free(priv);
+14
drivers/net/wireless/orinoco.h
··· 9 9 10 10 #define DRIVER_VERSION "0.15" 11 11 12 + #include <linux/interrupt.h> 12 13 #include <linux/netdevice.h> 13 14 #include <linux/wireless.h> 14 15 #include <net/iw_handler.h> ··· 58 57 struct list_head list; 59 58 }; 60 59 60 + struct hermes_rx_descriptor; 61 + 62 + struct orinoco_rx_data { 63 + struct hermes_rx_descriptor *desc; 64 + struct sk_buff *skb; 65 + struct list_head list; 66 + }; 67 + 61 68 struct orinoco_private { 62 69 void *card; /* Pointer to card dependent structure */ 63 70 struct device *dev; ··· 76 67 spinlock_t lock; 77 68 int hw_unavailable; 78 69 struct work_struct reset_work; 70 + 71 + /* Interrupt tasklets */ 72 + struct tasklet_struct rx_tasklet; 73 + struct list_head rx_list; 74 + struct orinoco_rx_data *rx_data; 79 75 80 76 /* driver state */ 81 77 int open;