ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / drivers / net / wireless / prism54 / islpci_eth.c
1 /*  $Header: /var/lib/cvs/prism54-ng/ksrc/islpci_eth.c,v 1.27 2004/01/30 16:24:00 ajfa Exp $
2  *  
3  *  Copyright (C) 2002 Intersil Americas Inc.
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  *
18  */
19
20 #include <linux/version.h>
21 #include <linux/module.h>
22
23 #include <linux/pci.h>
24 #include <linux/delay.h>
25 #include <linux/netdevice.h>
26 #include <linux/etherdevice.h>
27
28 #include "isl_38xx.h"
29 #include "islpci_eth.h"
30 #include "islpci_mgt.h"
31
32 /******************************************************************************
33     Network Interface functions
34 ******************************************************************************/
35 void
36 islpci_eth_cleanup_transmit(islpci_private *priv,
37                             isl38xx_control_block *control_block)
38 {
39         struct sk_buff *skb;
40         u32 index;
41
42         /* compare the control block read pointer with the free pointer */
43         while (priv->free_data_tx !=
44                le32_to_cpu(control_block->
45                            device_curr_frag[ISL38XX_CB_TX_DATA_LQ])) {
46                 /* read the index of the first fragment to be freed */
47                 index = priv->free_data_tx % ISL38XX_CB_TX_QSIZE;
48
49                 /* check for holes in the arrays caused by multi fragment frames 
50                  * searching for the last fragment of a frame */
51                 if (priv->pci_map_tx_address[index] != (dma_addr_t) NULL) {
52                         /* entry is the last fragment of a frame
53                          * free the skb structure and unmap pci memory */
54                         skb = priv->data_low_tx[index];
55
56 #if VERBOSE > SHOW_ERROR_MESSAGES
57                         DEBUG(SHOW_TRACING,
58                               "cleanup skb %p skb->data %p skb->len %u truesize %u\n ",
59                               skb, skb->data, skb->len, skb->truesize);
60 #endif
61
62                         pci_unmap_single(priv->pdev,
63                                          priv->pci_map_tx_address[index],
64                                          skb->len, PCI_DMA_TODEVICE);
65                         dev_kfree_skb_irq(skb);
66                         skb = NULL;
67                 }
68                 /* increment the free data low queue pointer */
69                 priv->free_data_tx++;
70         }
71 }
72
73 int
74 islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev)
75 {
76         islpci_private *priv = netdev_priv(ndev);
77         isl38xx_control_block *cb = priv->control_block;
78         u32 index;
79         dma_addr_t pci_map_address;
80         int frame_size;
81         isl38xx_fragment *fragment;
82         int offset;
83         struct sk_buff *newskb;
84         int newskb_offset;
85         unsigned long flags;
86         unsigned char wds_mac[6];
87         u32 curr_frag;
88         int err = 0;
89
90 #if VERBOSE > SHOW_ERROR_MESSAGES
91         DEBUG(SHOW_FUNCTION_CALLS, "islpci_eth_transmit \n");
92 #endif
93
94         /* lock the driver code */
95         spin_lock_irqsave(&priv->slock, flags);
96
97         /* determine the amount of fragments needed to store the frame */
98
99         frame_size = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;
100         if (init_wds)
101                 frame_size += 6;
102
103         /* check whether the destination queue has enough fragments for the frame */
104         curr_frag = le32_to_cpu(cb->driver_curr_frag[ISL38XX_CB_TX_DATA_LQ]);
105         if (curr_frag - priv->free_data_tx >= ISL38XX_CB_TX_QSIZE) {
106                 printk(KERN_ERR "%s: transmit device queue full when awake\n",
107                        ndev->name);
108                 netif_stop_queue(ndev);
109
110                 /* trigger the device */
111                 isl38xx_w32_flush(priv->device_base, ISL38XX_DEV_INT_UPDATE,
112                                   ISL38XX_DEV_INT_REG);
113                 udelay(ISL38XX_WRITEIO_DELAY);
114
115                 err = -EBUSY;
116                 goto drop_free;
117         }
118         /* Check alignment and WDS frame formatting. The start of the packet should
119          * be aligned on a 4-byte boundary. If WDS is enabled add another 6 bytes
120          * and add WDS address information */
121         if (((long) skb->data & 0x03) | init_wds) {
122                 /* get the number of bytes to add and re-allign */
123                 offset = (4 - (long) skb->data) & 0x03;
124                 offset += init_wds ? 6 : 0;
125
126                 /* check whether the current skb can be used  */
127                 if (!skb_cloned(skb) && (skb_tailroom(skb) >= offset)) {
128                         unsigned char *src = skb->data;
129
130 #if VERBOSE > SHOW_ERROR_MESSAGES
131                         DEBUG(SHOW_TRACING, "skb offset %i wds %i\n", offset,
132                               init_wds);
133 #endif
134
135                         /* align the buffer on 4-byte boundary */
136                         skb_reserve(skb, (4 - (long) skb->data) & 0x03);
137                         if (init_wds) {
138                                 /* wds requires an additional address field of 6 bytes */
139                                 skb_put(skb, 6);
140 #ifdef ISLPCI_ETH_DEBUG
141                                 printk("islpci_eth_transmit:wds_mac\n");
142 #endif
143                                 memmove(skb->data + 6, src, skb->len);
144                                 memcpy(skb->data, wds_mac, 6);
145                         } else {
146                                 memmove(skb->data, src, skb->len);
147                         }
148
149 #if VERBOSE > SHOW_ERROR_MESSAGES
150                         DEBUG(SHOW_TRACING, "memmove %p %p %i \n", skb->data,
151                               src, skb->len);
152 #endif
153                 } else {
154                         newskb =
155                             dev_alloc_skb(init_wds ? skb->len + 6 : skb->len);
156                         newskb_offset = (4 - (long) newskb->data) & 0x03;
157
158                         /* Check if newskb->data is aligned */
159                         if (newskb_offset)
160                                 skb_reserve(newskb, newskb_offset);
161
162                         skb_put(newskb, init_wds ? skb->len + 6 : skb->len);
163                         if (init_wds) {
164                                 memcpy(newskb->data + 6, skb->data, skb->len);
165                                 memcpy(newskb->data, wds_mac, 6);
166 #ifdef ISLPCI_ETH_DEBUG
167                                 printk("islpci_eth_transmit:wds_mac\n");
168 #endif
169                         } else
170                                 memcpy(newskb->data, skb->data, skb->len);
171
172 #if VERBOSE > SHOW_ERROR_MESSAGES
173                         DEBUG(SHOW_TRACING, "memcpy %p %p %i wds %i\n",
174                               newskb->data, skb->data, skb->len, init_wds);
175 #endif
176
177                         newskb->dev = skb->dev;
178                         dev_kfree_skb(skb);
179                         skb = newskb;
180                 }
181         }
182         /* display the buffer contents for debugging */
183 #if VERBOSE > SHOW_ERROR_MESSAGES
184         DEBUG(SHOW_BUFFER_CONTENTS, "\ntx %p ", skb->data);
185         display_buffer((char *) skb->data, skb->len);
186 #endif
187
188         /* map the skb buffer to pci memory for DMA operation */
189         pci_map_address = pci_map_single(priv->pdev,
190                                          (void *) skb->data, skb->len,
191                                          PCI_DMA_TODEVICE);
192         if (pci_map_address == 0) {
193                 printk(KERN_WARNING "%s: cannot map buffer to PCI\n",
194                        ndev->name);
195
196                 err = -EIO;
197                 goto drop_free;
198         }
199         /* Place the fragment in the control block structure. */
200         index = curr_frag % ISL38XX_CB_TX_QSIZE;
201         fragment = &cb->tx_data_low[index];
202
203         priv->pci_map_tx_address[index] = pci_map_address;
204         /* store the skb address for future freeing  */
205         priv->data_low_tx[index] = skb;
206         /* set the proper fragment start address and size information */
207         fragment->size = cpu_to_le16(frame_size);
208         fragment->flags = cpu_to_le16(0);  /* set to 1 if more fragments */
209         fragment->address = cpu_to_le32(pci_map_address);
210         curr_frag++;
211
212         /* The fragment address in the control block must have been
213          * written before announcing the frame buffer to device. */
214         wmb();
215         cb->driver_curr_frag[ISL38XX_CB_TX_DATA_LQ] = cpu_to_le32(curr_frag);
216
217         if (curr_frag - priv->free_data_tx + ISL38XX_MIN_QTHRESHOLD
218                                                    > ISL38XX_CB_TX_QSIZE) {
219                 /* stop sends from upper layers */
220                 netif_stop_queue(ndev);
221
222                 /* set the full flag for the transmission queue */
223                 priv->data_low_tx_full = 1;
224         }
225
226         /* trigger the device */
227         islpci_trigger(priv);
228
229         /* unlock the driver code */
230         spin_unlock_irqrestore(&priv->slock, flags);
231
232         /* set the transmission time */
233         ndev->trans_start = jiffies;
234         priv->statistics.tx_packets++;
235         priv->statistics.tx_bytes += skb->len;
236
237         return 0;
238
239  drop_free:
240         /* free the skbuf structure before aborting */
241         dev_kfree_skb(skb);
242         skb = NULL;
243
244         priv->statistics.tx_dropped++;
245         spin_unlock_irqrestore(&priv->slock, flags);
246         return err;
247 }
248
249 int
250 islpci_eth_receive(islpci_private *priv)
251 {
252         struct net_device *ndev = priv->ndev;
253         isl38xx_control_block *control_block = priv->control_block;
254         struct sk_buff *skb;
255         u16 size;
256         u32 index, offset;
257         unsigned char *src;
258         int discard = 0;
259
260 #if VERBOSE > SHOW_ERROR_MESSAGES
261         DEBUG(SHOW_FUNCTION_CALLS, "islpci_eth_receive \n");
262 #endif
263
264         /* the device has written an Ethernet frame in the data area
265          * of the sk_buff without updating the structure, do it now */
266         index = priv->free_data_rx % ISL38XX_CB_RX_QSIZE;
267         size = le16_to_cpu(control_block->rx_data_low[index].size);
268         skb = priv->data_low_rx[index];
269         offset = ((unsigned long) le32_to_cpu(control_block->rx_data_low[index].address) -
270                   (unsigned long) skb->data) & 3;
271
272 #if VERBOSE > SHOW_ERROR_MESSAGES
273         DEBUG(SHOW_TRACING,
274               "frq->addr %x skb->data %p skb->len %u offset %u truesize %u\n ",
275               control_block->rx_data_low[priv->free_data_rx].address, skb->data,
276               skb->len, offset, skb->truesize);
277 #endif
278
279         /* delete the streaming DMA mapping before processing the skb */
280         pci_unmap_single(priv->pdev,
281                          priv->pci_map_rx_address[index],
282                          MAX_FRAGMENT_SIZE_RX + 2, PCI_DMA_FROMDEVICE);
283
284         /* update the skb structure and allign the buffer */
285         skb_put(skb, size);
286         if (offset) {
287                 /* shift the buffer allocation offset bytes to get the right frame */
288                 skb_pull(skb, 2);
289                 skb_put(skb, 2);
290         }
291 #if VERBOSE > SHOW_ERROR_MESSAGES
292         /* display the buffer contents for debugging */
293         DEBUG(SHOW_BUFFER_CONTENTS, "\nrx %p ", skb->data);
294         display_buffer((char *) skb->data, skb->len);
295 #endif
296
297         /* check whether WDS is enabled and whether the data frame is a WDS frame */
298
299         if (init_wds) {
300                 /* WDS enabled, check for the wds address on the first 6 bytes of the buffer */
301                 src = skb->data + 6;
302                 memmove(skb->data, src, skb->len - 6);
303                 skb_trim(skb, skb->len - 6);
304         }
305 #if VERBOSE > SHOW_ERROR_MESSAGES
306         DEBUG(SHOW_TRACING, "Fragment size %i in skb at %p\n", size, skb);
307         DEBUG(SHOW_TRACING, "Skb data at %p, length %i\n", skb->data, skb->len);
308
309         /* display the buffer contents for debugging */
310         DEBUG(SHOW_BUFFER_CONTENTS, "\nrx %p ", skb->data);
311         display_buffer((char *) skb->data, skb->len);
312 #endif
313
314         /* do some additional sk_buff and network layer parameters */
315         skb->dev = ndev;
316
317         /* take care of monitor mode */
318         if (priv->iw_mode == IW_MODE_MONITOR) {
319                 /* The card reports full 802.11 packets but with a 20 bytes
320                  * header and without the FCS. But there a is a bit that
321                  * indicates if the packet is corrupted :-) */
322                 /* int i; */
323                 if (skb->data[8] & 0x01){
324                         /* This one is bad. Drop it !*/
325                         discard = 1;
326                         /* printk("BAD\n");*/
327                 }
328                 /*
329                 for(i=0;i<50;i++)
330                         printk("%2.2X:",skb->data[i]);
331                 printk("\n");
332                 */              
333                 skb_pull(skb, 20);
334                 skb->protocol = htons(ETH_P_802_2);
335                 skb->mac.raw = skb->data;
336                 skb->pkt_type = PACKET_OTHERHOST;
337         } else
338                 skb->protocol = eth_type_trans(skb, ndev);
339
340         skb->ip_summed = CHECKSUM_NONE;
341         priv->statistics.rx_packets++;
342         priv->statistics.rx_bytes += size;
343
344         /* deliver the skb to the network layer */
345 #ifdef ISLPCI_ETH_DEBUG
346         printk
347             ("islpci_eth_receive:netif_rx %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
348              skb->data[0], skb->data[1], skb->data[2], skb->data[3],
349              skb->data[4], skb->data[5]);
350 #endif
351         if (discard) {
352                 dev_kfree_skb(skb);
353                 skb = NULL;
354         }
355         else
356                 netif_rx(skb);
357
358         /* increment the read index for the rx data low queue */
359         priv->free_data_rx++;
360
361         /* add one or more sk_buff structures */
362         while (index =
363                le32_to_cpu(control_block->
364                            driver_curr_frag[ISL38XX_CB_RX_DATA_LQ]),
365                index - priv->free_data_rx < ISL38XX_CB_RX_QSIZE) {
366                 /* allocate an sk_buff for received data frames storage
367                  * include any required allignment operations */
368                 if (skb = dev_alloc_skb(MAX_FRAGMENT_SIZE_RX + 2), skb == NULL) {
369                         /* error allocating an sk_buff structure elements */
370                         DEBUG(SHOW_ERROR_MESSAGES, "Error allocating skb \n");
371                         break;
372                 }
373                 /* store the new skb structure pointer */
374                 index = index % ISL38XX_CB_RX_QSIZE;
375                 priv->data_low_rx[index] = skb;
376
377 #if VERBOSE > SHOW_ERROR_MESSAGES
378                 DEBUG(SHOW_TRACING,
379                       "new alloc skb %p skb->data %p skb->len %u index %u truesize %u\n ",
380                       skb, skb->data, skb->len, index, skb->truesize);
381 #endif
382
383                 /* set the streaming DMA mapping for proper PCI bus operation */
384                 priv->pci_map_rx_address[index] =
385                     pci_map_single(priv->pdev, (void *) skb->data,
386                                    MAX_FRAGMENT_SIZE_RX + 2,
387                                    PCI_DMA_FROMDEVICE);
388                 if (priv->pci_map_rx_address[index] == (dma_addr_t) NULL) {
389                         /* error mapping the buffer to device accessable memory address */
390                         DEBUG(SHOW_ERROR_MESSAGES,
391                               "Error mapping DMA address\n");
392
393                         /* free the skbuf structure before aborting */
394                         dev_kfree_skb((struct sk_buff *) skb);
395                         skb = NULL;
396                         break;
397                 }
398                 /* update the fragment address */
399                 control_block->rx_data_low[index].address = cpu_to_le32((u32)
400                                                                         priv->
401                                                                         pci_map_rx_address
402                                                                         [index]);
403                 wmb();
404
405                 /* increment the driver read pointer */
406                 add_le32p((u32 *) & control_block->
407                           driver_curr_frag[ISL38XX_CB_RX_DATA_LQ], 1);
408         }
409
410         /* trigger the device */
411         islpci_trigger(priv);
412
413         return 0;
414 }
415
416 void
417 islpci_eth_tx_timeout(struct net_device *ndev)
418 {
419         islpci_private *priv = netdev_priv(ndev);
420         struct net_device_stats *statistics = &priv->statistics;
421
422         /* increment the transmit error counter */
423         statistics->tx_errors++;
424
425 #if 0
426         /* don't do this here! we are not allowed to sleep since we are in interrupt context */
427         if (islpci_reset(priv))
428                 printk(KERN_ERR "%s: error on TX timeout card reset!\n",
429                        ndev->name);
430 #endif
431
432         /* netif_wake_queue(ndev); */
433         return;
434 }