diff options
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; |