]>
Commit | Line | Data |
---|---|---|
099dc4fb DS |
1 | /* |
2 | * IPWireless 3G PCMCIA Network Driver | |
3 | * | |
4 | * Original code | |
5 | * by Stephen Blackheath <stephen@blacksapphire.com>, | |
6 | * Ben Martel <benm@symmetric.co.nz> | |
7 | * | |
8 | * Copyrighted as follows: | |
9 | * Copyright (C) 2004 by Symmetric Systems Ltd (NZ) | |
10 | * | |
11 | * Various driver changes and rewrites, port to new kernels | |
12 | * Copyright (C) 2006-2007 Jiri Kosina | |
13 | * | |
14 | * Misc code cleanups and updates | |
15 | * Copyright (C) 2007 David Sterba | |
16 | */ | |
17 | ||
18 | #include <linux/interrupt.h> | |
19 | #include <linux/io.h> | |
20 | #include <linux/irq.h> | |
21 | #include <linux/kernel.h> | |
22 | #include <linux/list.h> | |
23 | #include <linux/slab.h> | |
24 | ||
25 | #include "hardware.h" | |
26 | #include "setup_protocol.h" | |
27 | #include "network.h" | |
28 | #include "main.h" | |
29 | ||
30 | static void ipw_send_setup_packet(struct ipw_hardware *hw); | |
31 | static void handle_received_SETUP_packet(struct ipw_hardware *ipw, | |
32 | unsigned int address, | |
33 | unsigned char *data, int len, | |
34 | int is_last); | |
35 | static void ipwireless_setup_timer(unsigned long data); | |
36 | static void handle_received_CTRL_packet(struct ipw_hardware *hw, | |
37 | unsigned int channel_idx, unsigned char *data, int len); | |
38 | ||
39 | /*#define TIMING_DIAGNOSTICS*/ | |
40 | ||
41 | #ifdef TIMING_DIAGNOSTICS | |
42 | ||
43 | static struct timing_stats { | |
44 | unsigned long last_report_time; | |
45 | unsigned long read_time; | |
46 | unsigned long write_time; | |
47 | unsigned long read_bytes; | |
48 | unsigned long write_bytes; | |
49 | unsigned long start_time; | |
50 | }; | |
51 | ||
52 | static void start_timing(void) | |
53 | { | |
54 | timing_stats.start_time = jiffies; | |
55 | } | |
56 | ||
57 | static void end_read_timing(unsigned length) | |
58 | { | |
59 | timing_stats.read_time += (jiffies - start_time); | |
60 | timing_stats.read_bytes += length + 2; | |
61 | report_timing(); | |
62 | } | |
63 | ||
64 | static void end_write_timing(unsigned length) | |
65 | { | |
66 | timing_stats.write_time += (jiffies - start_time); | |
67 | timing_stats.write_bytes += length + 2; | |
68 | report_timing(); | |
69 | } | |
70 | ||
71 | static void report_timing(void) | |
72 | { | |
73 | unsigned long since = jiffies - timing_stats.last_report_time; | |
74 | ||
75 | /* If it's been more than one second... */ | |
76 | if (since >= HZ) { | |
77 | int first = (timing_stats.last_report_time == 0); | |
78 | ||
79 | timing_stats.last_report_time = jiffies; | |
80 | if (!first) | |
81 | printk(KERN_INFO IPWIRELESS_PCCARD_NAME | |
82 | ": %u us elapsed - read %lu bytes in %u us, " | |
83 | "wrote %lu bytes in %u us\n", | |
84 | jiffies_to_usecs(since), | |
85 | timing_stats.read_bytes, | |
86 | jiffies_to_usecs(timing_stats.read_time), | |
87 | timing_stats.write_bytes, | |
88 | jiffies_to_usecs(timing_stats.write_time)); | |
89 | ||
90 | timing_stats.read_time = 0; | |
91 | timing_stats.write_time = 0; | |
92 | timing_stats.read_bytes = 0; | |
93 | timing_stats.write_bytes = 0; | |
94 | } | |
95 | } | |
96 | #else | |
97 | static void start_timing(void) { } | |
98 | static void end_read_timing(unsigned length) { } | |
99 | static void end_write_timing(unsigned length) { } | |
100 | #endif | |
101 | ||
102 | /* Imported IPW definitions */ | |
103 | ||
104 | #define LL_MTU_V1 318 | |
105 | #define LL_MTU_V2 250 | |
106 | #define LL_MTU_MAX (LL_MTU_V1 > LL_MTU_V2 ? LL_MTU_V1 : LL_MTU_V2) | |
107 | ||
108 | #define PRIO_DATA 2 | |
109 | #define PRIO_CTRL 1 | |
110 | #define PRIO_SETUP 0 | |
111 | ||
112 | /* Addresses */ | |
113 | #define ADDR_SETUP_PROT 0 | |
114 | ||
115 | /* Protocol ids */ | |
116 | enum { | |
117 | /* Identifier for the Com Data protocol */ | |
118 | TL_PROTOCOLID_COM_DATA = 0, | |
119 | ||
120 | /* Identifier for the Com Control protocol */ | |
121 | TL_PROTOCOLID_COM_CTRL = 1, | |
122 | ||
123 | /* Identifier for the Setup protocol */ | |
124 | TL_PROTOCOLID_SETUP = 2 | |
125 | }; | |
126 | ||
127 | /* Number of bytes in NL packet header (cannot do | |
128 | * sizeof(nl_packet_header) since it's a bitfield) */ | |
129 | #define NL_FIRST_PACKET_HEADER_SIZE 3 | |
130 | ||
131 | /* Number of bytes in NL packet header (cannot do | |
132 | * sizeof(nl_packet_header) since it's a bitfield) */ | |
133 | #define NL_FOLLOWING_PACKET_HEADER_SIZE 1 | |
134 | ||
135 | struct nl_first_packet_header { | |
136 | #if defined(__BIG_ENDIAN_BITFIELD) | |
137 | unsigned char packet_rank:2; | |
138 | unsigned char address:3; | |
139 | unsigned char protocol:3; | |
140 | #else | |
141 | unsigned char protocol:3; | |
142 | unsigned char address:3; | |
143 | unsigned char packet_rank:2; | |
144 | #endif | |
145 | unsigned char length_lsb; | |
146 | unsigned char length_msb; | |
147 | }; | |
148 | ||
149 | struct nl_packet_header { | |
150 | #if defined(__BIG_ENDIAN_BITFIELD) | |
151 | unsigned char packet_rank:2; | |
152 | unsigned char address:3; | |
153 | unsigned char protocol:3; | |
154 | #else | |
155 | unsigned char protocol:3; | |
156 | unsigned char address:3; | |
157 | unsigned char packet_rank:2; | |
158 | #endif | |
159 | }; | |
160 | ||
161 | /* Value of 'packet_rank' above */ | |
162 | #define NL_INTERMEDIATE_PACKET 0x0 | |
163 | #define NL_LAST_PACKET 0x1 | |
164 | #define NL_FIRST_PACKET 0x2 | |
165 | ||
166 | union nl_packet { | |
167 | /* Network packet header of the first packet (a special case) */ | |
168 | struct nl_first_packet_header hdr_first; | |
169 | /* Network packet header of the following packets (if any) */ | |
170 | struct nl_packet_header hdr; | |
171 | /* Complete network packet (header + data) */ | |
172 | unsigned char rawpkt[LL_MTU_MAX]; | |
173 | } __attribute__ ((__packed__)); | |
174 | ||
175 | #define HW_VERSION_UNKNOWN -1 | |
176 | #define HW_VERSION_1 1 | |
177 | #define HW_VERSION_2 2 | |
178 | ||
179 | /* IPW I/O ports */ | |
180 | #define IOIER 0x00 /* Interrupt Enable Register */ | |
181 | #define IOIR 0x02 /* Interrupt Source/ACK register */ | |
182 | #define IODCR 0x04 /* Data Control Register */ | |
183 | #define IODRR 0x06 /* Data Read Register */ | |
184 | #define IODWR 0x08 /* Data Write Register */ | |
185 | #define IOESR 0x0A /* Embedded Driver Status Register */ | |
186 | #define IORXR 0x0C /* Rx Fifo Register (Host to Embedded) */ | |
187 | #define IOTXR 0x0E /* Tx Fifo Register (Embedded to Host) */ | |
188 | ||
189 | /* I/O ports and bit definitions for version 1 of the hardware */ | |
190 | ||
191 | /* IER bits*/ | |
192 | #define IER_RXENABLED 0x1 | |
193 | #define IER_TXENABLED 0x2 | |
194 | ||
195 | /* ISR bits */ | |
196 | #define IR_RXINTR 0x1 | |
197 | #define IR_TXINTR 0x2 | |
198 | ||
199 | /* DCR bits */ | |
200 | #define DCR_RXDONE 0x1 | |
201 | #define DCR_TXDONE 0x2 | |
202 | #define DCR_RXRESET 0x4 | |
203 | #define DCR_TXRESET 0x8 | |
204 | ||
205 | /* I/O ports and bit definitions for version 2 of the hardware */ | |
206 | ||
207 | struct MEMCCR { | |
208 | unsigned short reg_config_option; /* PCCOR: Configuration Option Register */ | |
209 | unsigned short reg_config_and_status; /* PCCSR: Configuration and Status Register */ | |
210 | unsigned short reg_pin_replacement; /* PCPRR: Pin Replacemant Register */ | |
211 | unsigned short reg_socket_and_copy; /* PCSCR: Socket and Copy Register */ | |
212 | unsigned short reg_ext_status; /* PCESR: Extendend Status Register */ | |
213 | unsigned short reg_io_base; /* PCIOB: I/O Base Register */ | |
214 | }; | |
215 | ||
216 | struct MEMINFREG { | |
217 | unsigned short memreg_tx_old; /* TX Register (R/W) */ | |
218 | unsigned short pad1; | |
219 | unsigned short memreg_rx_done; /* RXDone Register (R/W) */ | |
220 | unsigned short pad2; | |
221 | unsigned short memreg_rx; /* RX Register (R/W) */ | |
222 | unsigned short pad3; | |
223 | unsigned short memreg_pc_interrupt_ack; /* PC intr Ack Register (W) */ | |
224 | unsigned short pad4; | |
225 | unsigned long memreg_card_present;/* Mask for Host to check (R) for | |
226 | * CARD_PRESENT_VALUE */ | |
227 | unsigned short memreg_tx_new; /* TX2 (new) Register (R/W) */ | |
228 | }; | |
229 | ||
230 | #define IODMADPR 0x00 /* DMA Data Port Register (R/W) */ | |
231 | ||
232 | #define CARD_PRESENT_VALUE (0xBEEFCAFEUL) | |
233 | ||
234 | #define MEMTX_TX 0x0001 | |
235 | #define MEMRX_RX 0x0001 | |
236 | #define MEMRX_RX_DONE 0x0001 | |
237 | #define MEMRX_PCINTACKK 0x0001 | |
238 | #define MEMRX_MEMSPURIOUSINT 0x0001 | |
239 | ||
240 | #define NL_NUM_OF_PRIORITIES 3 | |
241 | #define NL_NUM_OF_PROTOCOLS 3 | |
242 | #define NL_NUM_OF_ADDRESSES NO_OF_IPW_CHANNELS | |
243 | ||
244 | struct ipw_hardware { | |
245 | unsigned int base_port; | |
246 | short hw_version; | |
247 | unsigned short ll_mtu; | |
248 | spinlock_t spinlock; | |
249 | ||
250 | int initializing; | |
251 | int init_loops; | |
252 | struct timer_list setup_timer; | |
253 | ||
eb4e545d | 254 | /* Flag if hw is ready to send next packet */ |
099dc4fb | 255 | int tx_ready; |
eb4e545d | 256 | /* Count of pending packets to be sent */ |
099dc4fb | 257 | int tx_queued; |
eb4e545d | 258 | struct list_head tx_queue[NL_NUM_OF_PRIORITIES]; |
099dc4fb DS |
259 | |
260 | int rx_bytes_queued; | |
261 | struct list_head rx_queue; | |
262 | /* Pool of rx_packet structures that are not currently used. */ | |
263 | struct list_head rx_pool; | |
264 | int rx_pool_size; | |
265 | /* True if reception of data is blocked while userspace processes it. */ | |
266 | int blocking_rx; | |
267 | /* True if there is RX data ready on the hardware. */ | |
268 | int rx_ready; | |
269 | unsigned short last_memtx_serial; | |
270 | /* | |
271 | * Newer versions of the V2 card firmware send serial numbers in the | |
272 | * MemTX register. 'serial_number_detected' is set true when we detect | |
273 | * a non-zero serial number (indicating the new firmware). Thereafter, | |
274 | * the driver can safely ignore the Timer Recovery re-sends to avoid | |
275 | * out-of-sync problems. | |
276 | */ | |
277 | int serial_number_detected; | |
278 | struct work_struct work_rx; | |
279 | ||
280 | /* True if we are to send the set-up data to the hardware. */ | |
281 | int to_setup; | |
282 | ||
283 | /* Card has been removed */ | |
284 | int removed; | |
285 | /* Saved irq value when we disable the interrupt. */ | |
286 | int irq; | |
287 | /* True if this driver is shutting down. */ | |
288 | int shutting_down; | |
289 | /* Modem control lines */ | |
290 | unsigned int control_lines[NL_NUM_OF_ADDRESSES]; | |
291 | struct ipw_rx_packet *packet_assembler[NL_NUM_OF_ADDRESSES]; | |
292 | ||
293 | struct tasklet_struct tasklet; | |
294 | ||
295 | /* The handle for the network layer, for the sending of events to it. */ | |
296 | struct ipw_network *network; | |
297 | struct MEMINFREG __iomem *memory_info_regs; | |
298 | struct MEMCCR __iomem *memregs_CCR; | |
299 | void (*reboot_callback) (void *data); | |
300 | void *reboot_callback_data; | |
301 | ||
302 | unsigned short __iomem *memreg_tx; | |
303 | }; | |
304 | ||
305 | /* | |
306 | * Packet info structure for tx packets. | |
307 | * Note: not all the fields defined here are required for all protocols | |
308 | */ | |
309 | struct ipw_tx_packet { | |
310 | struct list_head queue; | |
311 | /* channel idx + 1 */ | |
312 | unsigned char dest_addr; | |
313 | /* SETUP, CTRL or DATA */ | |
314 | unsigned char protocol; | |
315 | /* Length of data block, which starts at the end of this structure */ | |
316 | unsigned short length; | |
317 | /* Sending state */ | |
318 | /* Offset of where we've sent up to so far */ | |
319 | unsigned long offset; | |
320 | /* Count of packet fragments, starting at 0 */ | |
321 | int fragment_count; | |
322 | ||
323 | /* Called after packet is sent and before is freed */ | |
324 | void (*packet_callback) (void *cb_data, unsigned int packet_length); | |
325 | void *callback_data; | |
326 | }; | |
327 | ||
328 | /* Signals from DTE */ | |
329 | #define COMCTRL_RTS 0 | |
330 | #define COMCTRL_DTR 1 | |
331 | ||
332 | /* Signals from DCE */ | |
333 | #define COMCTRL_CTS 2 | |
334 | #define COMCTRL_DCD 3 | |
335 | #define COMCTRL_DSR 4 | |
336 | #define COMCTRL_RI 5 | |
337 | ||
338 | struct ipw_control_packet_body { | |
339 | /* DTE signal or DCE signal */ | |
340 | unsigned char sig_no; | |
341 | /* 0: set signal, 1: clear signal */ | |
342 | unsigned char value; | |
343 | } __attribute__ ((__packed__)); | |
344 | ||
345 | struct ipw_control_packet { | |
346 | struct ipw_tx_packet header; | |
347 | struct ipw_control_packet_body body; | |
348 | }; | |
349 | ||
350 | struct ipw_rx_packet { | |
351 | struct list_head queue; | |
352 | unsigned int capacity; | |
353 | unsigned int length; | |
354 | unsigned int protocol; | |
355 | unsigned int channel_idx; | |
356 | }; | |
357 | ||
099dc4fb DS |
358 | static char *data_type(const unsigned char *buf, unsigned length) |
359 | { | |
360 | struct nl_packet_header *hdr = (struct nl_packet_header *) buf; | |
361 | ||
362 | if (length == 0) | |
363 | return " "; | |
364 | ||
365 | if (hdr->packet_rank & NL_FIRST_PACKET) { | |
366 | switch (hdr->protocol) { | |
367 | case TL_PROTOCOLID_COM_DATA: return "DATA "; | |
368 | case TL_PROTOCOLID_COM_CTRL: return "CTRL "; | |
369 | case TL_PROTOCOLID_SETUP: return "SETUP"; | |
370 | default: return "???? "; | |
371 | } | |
372 | } else | |
373 | return " "; | |
374 | } | |
375 | ||
376 | #define DUMP_MAX_BYTES 64 | |
377 | ||
378 | static void dump_data_bytes(const char *type, const unsigned char *data, | |
379 | unsigned length) | |
380 | { | |
381 | char prefix[56]; | |
382 | ||
383 | sprintf(prefix, IPWIRELESS_PCCARD_NAME ": %s %s ", | |
384 | type, data_type(data, length)); | |
385 | print_hex_dump_bytes(prefix, 0, (void *)data, | |
386 | length < DUMP_MAX_BYTES ? length : DUMP_MAX_BYTES); | |
387 | } | |
388 | ||
389 | static int do_send_fragment(struct ipw_hardware *hw, const unsigned char *data, | |
390 | unsigned length) | |
391 | { | |
392 | int i; | |
393 | unsigned long flags; | |
394 | ||
395 | start_timing(); | |
396 | ||
397 | if (length == 0) | |
398 | return 0; | |
399 | ||
400 | if (length > hw->ll_mtu) | |
401 | return -1; | |
402 | ||
403 | if (ipwireless_debug) | |
404 | dump_data_bytes("send", data, length); | |
405 | ||
406 | spin_lock_irqsave(&hw->spinlock, flags); | |
407 | ||
eb4e545d DS |
408 | hw->tx_ready = 0; |
409 | ||
099dc4fb DS |
410 | if (hw->hw_version == HW_VERSION_1) { |
411 | outw((unsigned short) length, hw->base_port + IODWR); | |
412 | ||
413 | for (i = 0; i < length; i += 2) { | |
414 | unsigned short d = data[i]; | |
415 | __le16 raw_data; | |
416 | ||
417 | if (likely(i + 1 < length)) | |
418 | d |= data[i + 1] << 8; | |
419 | raw_data = cpu_to_le16(d); | |
420 | outw(raw_data, hw->base_port + IODWR); | |
421 | } | |
422 | ||
423 | outw(DCR_TXDONE, hw->base_port + IODCR); | |
424 | } else if (hw->hw_version == HW_VERSION_2) { | |
425 | outw((unsigned short) length, hw->base_port + IODMADPR); | |
426 | ||
427 | for (i = 0; i < length; i += 2) { | |
428 | unsigned short d = data[i]; | |
429 | __le16 raw_data; | |
430 | ||
431 | if ((i + 1 < length)) | |
432 | d |= data[i + 1] << 8; | |
433 | raw_data = cpu_to_le16(d); | |
434 | outw(raw_data, hw->base_port + IODMADPR); | |
435 | } | |
436 | while ((i & 3) != 2) { | |
437 | outw((unsigned short) 0xDEAD, hw->base_port + IODMADPR); | |
438 | i += 2; | |
439 | } | |
440 | writew(MEMRX_RX, &hw->memory_info_regs->memreg_rx); | |
441 | } | |
442 | ||
443 | spin_unlock_irqrestore(&hw->spinlock, flags); | |
444 | ||
445 | end_write_timing(length); | |
446 | ||
447 | return 0; | |
448 | } | |
449 | ||
450 | static int do_send_packet(struct ipw_hardware *hw, struct ipw_tx_packet *packet) | |
451 | { | |
452 | unsigned short fragment_data_len; | |
453 | unsigned short data_left = packet->length - packet->offset; | |
454 | unsigned short header_size; | |
455 | union nl_packet pkt; | |
456 | ||
457 | header_size = | |
458 | (packet->fragment_count == 0) | |
459 | ? NL_FIRST_PACKET_HEADER_SIZE | |
460 | : NL_FOLLOWING_PACKET_HEADER_SIZE; | |
461 | fragment_data_len = hw->ll_mtu - header_size; | |
462 | if (data_left < fragment_data_len) | |
463 | fragment_data_len = data_left; | |
464 | ||
465 | pkt.hdr_first.protocol = packet->protocol; | |
466 | pkt.hdr_first.address = packet->dest_addr; | |
467 | pkt.hdr_first.packet_rank = 0; | |
468 | ||
469 | /* First packet? */ | |
470 | if (packet->fragment_count == 0) { | |
471 | pkt.hdr_first.packet_rank |= NL_FIRST_PACKET; | |
472 | pkt.hdr_first.length_lsb = (unsigned char) packet->length; | |
473 | pkt.hdr_first.length_msb = | |
474 | (unsigned char) (packet->length >> 8); | |
475 | } | |
476 | ||
477 | memcpy(pkt.rawpkt + header_size, | |
478 | ((unsigned char *) packet) + sizeof(struct ipw_tx_packet) + | |
479 | packet->offset, fragment_data_len); | |
480 | packet->offset += fragment_data_len; | |
481 | packet->fragment_count++; | |
482 | ||
483 | /* Last packet? (May also be first packet.) */ | |
484 | if (packet->offset == packet->length) | |
485 | pkt.hdr_first.packet_rank |= NL_LAST_PACKET; | |
486 | do_send_fragment(hw, pkt.rawpkt, header_size + fragment_data_len); | |
487 | ||
488 | /* If this packet has unsent data, then re-queue it. */ | |
489 | if (packet->offset < packet->length) { | |
490 | /* | |
491 | * Re-queue it at the head of the highest priority queue so | |
492 | * it goes before all other packets | |
493 | */ | |
494 | unsigned long flags; | |
495 | ||
496 | spin_lock_irqsave(&hw->spinlock, flags); | |
497 | list_add(&packet->queue, &hw->tx_queue[0]); | |
eb4e545d | 498 | hw->tx_queued++; |
099dc4fb DS |
499 | spin_unlock_irqrestore(&hw->spinlock, flags); |
500 | } else { | |
501 | if (packet->packet_callback) | |
502 | packet->packet_callback(packet->callback_data, | |
503 | packet->length); | |
504 | kfree(packet); | |
505 | } | |
506 | ||
507 | return 0; | |
508 | } | |
509 | ||
510 | static void ipw_setup_hardware(struct ipw_hardware *hw) | |
511 | { | |
512 | unsigned long flags; | |
513 | ||
514 | spin_lock_irqsave(&hw->spinlock, flags); | |
515 | if (hw->hw_version == HW_VERSION_1) { | |
516 | /* Reset RX FIFO */ | |
517 | outw(DCR_RXRESET, hw->base_port + IODCR); | |
518 | /* SB: Reset TX FIFO */ | |
519 | outw(DCR_TXRESET, hw->base_port + IODCR); | |
520 | ||
521 | /* Enable TX and RX interrupts. */ | |
522 | outw(IER_TXENABLED | IER_RXENABLED, hw->base_port + IOIER); | |
523 | } else { | |
524 | /* | |
525 | * Set INTRACK bit (bit 0), which means we must explicitly | |
526 | * acknowledge interrupts by clearing bit 2 of reg_config_and_status. | |
527 | */ | |
528 | unsigned short csr = readw(&hw->memregs_CCR->reg_config_and_status); | |
529 | ||
530 | csr |= 1; | |
531 | writew(csr, &hw->memregs_CCR->reg_config_and_status); | |
532 | } | |
533 | spin_unlock_irqrestore(&hw->spinlock, flags); | |
534 | } | |
535 | ||
536 | /* | |
537 | * If 'packet' is NULL, then this function allocates a new packet, setting its | |
538 | * length to 0 and ensuring it has the specified minimum amount of free space. | |
539 | * | |
540 | * If 'packet' is not NULL, then this function enlarges it if it doesn't | |
541 | * have the specified minimum amount of free space. | |
542 | * | |
543 | */ | |
544 | static struct ipw_rx_packet *pool_allocate(struct ipw_hardware *hw, | |
545 | struct ipw_rx_packet *packet, | |
546 | int minimum_free_space) | |
547 | { | |
548 | ||
549 | if (!packet) { | |
550 | unsigned long flags; | |
551 | ||
552 | /* | |
553 | * If this is the first fragment, then we will need to fetch a | |
554 | * packet to put it in. | |
555 | */ | |
556 | spin_lock_irqsave(&hw->spinlock, flags); | |
557 | /* If we have one in our pool, then pull it out. */ | |
558 | if (!list_empty(&hw->rx_pool)) { | |
559 | packet = list_first_entry(&hw->rx_pool, | |
560 | struct ipw_rx_packet, queue); | |
561 | list_del(&packet->queue); | |
562 | hw->rx_pool_size--; | |
563 | spin_unlock_irqrestore(&hw->spinlock, flags); | |
564 | } else { | |
565 | /* Otherwise allocate a new one. */ | |
566 | static int min_capacity = 256; | |
567 | int new_capacity; | |
568 | ||
569 | spin_unlock_irqrestore(&hw->spinlock, flags); | |
570 | new_capacity = | |
571 | minimum_free_space > min_capacity | |
572 | ? minimum_free_space | |
573 | : min_capacity; | |
574 | packet = kmalloc(sizeof(struct ipw_rx_packet) | |
575 | + new_capacity, GFP_ATOMIC); | |
576 | if (!packet) | |
577 | return NULL; | |
578 | packet->capacity = new_capacity; | |
579 | } | |
580 | packet->length = 0; | |
581 | } | |
582 | ||
583 | /* | |
584 | * If this packet does not have sufficient capacity for the data we | |
585 | * want to add, then make it bigger. | |
586 | */ | |
587 | if (packet->length + minimum_free_space > packet->capacity) { | |
588 | struct ipw_rx_packet *old_packet = packet; | |
589 | ||
590 | packet = kmalloc(sizeof(struct ipw_rx_packet) + | |
591 | old_packet->length + minimum_free_space, | |
592 | GFP_ATOMIC); | |
43f77e91 DJ |
593 | if (!packet) { |
594 | kfree(old_packet); | |
099dc4fb | 595 | return NULL; |
43f77e91 | 596 | } |
099dc4fb DS |
597 | memcpy(packet, old_packet, |
598 | sizeof(struct ipw_rx_packet) | |
599 | + old_packet->length); | |
600 | packet->capacity = old_packet->length + minimum_free_space; | |
601 | kfree(old_packet); | |
602 | } | |
603 | ||
604 | return packet; | |
605 | } | |
606 | ||
607 | static void pool_free(struct ipw_hardware *hw, struct ipw_rx_packet *packet) | |
608 | { | |
609 | if (hw->rx_pool_size > 6) | |
610 | kfree(packet); | |
611 | else { | |
612 | hw->rx_pool_size++; | |
613 | list_add_tail(&packet->queue, &hw->rx_pool); | |
614 | } | |
615 | } | |
616 | ||
617 | static void queue_received_packet(struct ipw_hardware *hw, | |
618 | unsigned int protocol, unsigned int address, | |
619 | unsigned char *data, int length, int is_last) | |
620 | { | |
621 | unsigned int channel_idx = address - 1; | |
622 | struct ipw_rx_packet *packet = NULL; | |
623 | unsigned long flags; | |
624 | ||
625 | /* Discard packet if channel index is out of range. */ | |
626 | if (channel_idx >= NL_NUM_OF_ADDRESSES) { | |
627 | printk(KERN_INFO IPWIRELESS_PCCARD_NAME | |
628 | ": data packet has bad address %u\n", address); | |
629 | return; | |
630 | } | |
631 | ||
632 | /* | |
633 | * ->packet_assembler is safe to touch unlocked, this is the only place | |
634 | */ | |
635 | if (protocol == TL_PROTOCOLID_COM_DATA) { | |
636 | struct ipw_rx_packet **assem = | |
637 | &hw->packet_assembler[channel_idx]; | |
638 | ||
639 | /* | |
640 | * Create a new packet, or assembler already contains one | |
641 | * enlarge it by 'length' bytes. | |
642 | */ | |
643 | (*assem) = pool_allocate(hw, *assem, length); | |
644 | if (!(*assem)) { | |
645 | printk(KERN_ERR IPWIRELESS_PCCARD_NAME | |
646 | ": no memory for incomming data packet, dropped!\n"); | |
647 | return; | |
648 | } | |
649 | (*assem)->protocol = protocol; | |
650 | (*assem)->channel_idx = channel_idx; | |
651 | ||
652 | /* Append this packet data onto existing data. */ | |
653 | memcpy((unsigned char *)(*assem) + | |
654 | sizeof(struct ipw_rx_packet) | |
655 | + (*assem)->length, data, length); | |
656 | (*assem)->length += length; | |
657 | if (is_last) { | |
658 | packet = *assem; | |
659 | *assem = NULL; | |
660 | /* Count queued DATA bytes only */ | |
661 | spin_lock_irqsave(&hw->spinlock, flags); | |
662 | hw->rx_bytes_queued += packet->length; | |
663 | spin_unlock_irqrestore(&hw->spinlock, flags); | |
664 | } | |
665 | } else { | |
666 | /* If it's a CTRL packet, don't assemble, just queue it. */ | |
667 | packet = pool_allocate(hw, NULL, length); | |
668 | if (!packet) { | |
669 | printk(KERN_ERR IPWIRELESS_PCCARD_NAME | |
670 | ": no memory for incomming ctrl packet, dropped!\n"); | |
671 | return; | |
672 | } | |
673 | packet->protocol = protocol; | |
674 | packet->channel_idx = channel_idx; | |
675 | memcpy((unsigned char *)packet + sizeof(struct ipw_rx_packet), | |
676 | data, length); | |
677 | packet->length = length; | |
678 | } | |
679 | ||
680 | /* | |
681 | * If this is the last packet, then send the assembled packet on to the | |
682 | * network layer. | |
683 | */ | |
684 | if (packet) { | |
685 | spin_lock_irqsave(&hw->spinlock, flags); | |
686 | list_add_tail(&packet->queue, &hw->rx_queue); | |
687 | /* Block reception of incoming packets if queue is full. */ | |
688 | hw->blocking_rx = | |
689 | hw->rx_bytes_queued >= IPWIRELESS_RX_QUEUE_SIZE; | |
690 | ||
691 | spin_unlock_irqrestore(&hw->spinlock, flags); | |
692 | schedule_work(&hw->work_rx); | |
693 | } | |
694 | } | |
695 | ||
696 | /* | |
697 | * Workqueue callback | |
698 | */ | |
699 | static void ipw_receive_data_work(struct work_struct *work_rx) | |
700 | { | |
701 | struct ipw_hardware *hw = | |
702 | container_of(work_rx, struct ipw_hardware, work_rx); | |
703 | unsigned long flags; | |
704 | ||
705 | spin_lock_irqsave(&hw->spinlock, flags); | |
706 | while (!list_empty(&hw->rx_queue)) { | |
707 | struct ipw_rx_packet *packet = | |
708 | list_first_entry(&hw->rx_queue, | |
709 | struct ipw_rx_packet, queue); | |
710 | ||
711 | if (hw->shutting_down) | |
712 | break; | |
713 | list_del(&packet->queue); | |
714 | ||
715 | /* | |
716 | * Note: ipwireless_network_packet_received must be called in a | |
717 | * process context (i.e. via schedule_work) because the tty | |
718 | * output code can sleep in the tty_flip_buffer_push call. | |
719 | */ | |
720 | if (packet->protocol == TL_PROTOCOLID_COM_DATA) { | |
721 | if (hw->network != NULL) { | |
722 | /* If the network hasn't been disconnected. */ | |
723 | spin_unlock_irqrestore(&hw->spinlock, flags); | |
724 | /* | |
725 | * This must run unlocked due to tty processing | |
726 | * and mutex locking | |
727 | */ | |
728 | ipwireless_network_packet_received( | |
729 | hw->network, | |
730 | packet->channel_idx, | |
731 | (unsigned char *)packet | |
732 | + sizeof(struct ipw_rx_packet), | |
733 | packet->length); | |
734 | spin_lock_irqsave(&hw->spinlock, flags); | |
735 | } | |
736 | /* Count queued DATA bytes only */ | |
737 | hw->rx_bytes_queued -= packet->length; | |
738 | } else { | |
739 | /* | |
740 | * This is safe to be called locked, callchain does | |
741 | * not block | |
742 | */ | |
743 | handle_received_CTRL_packet(hw, packet->channel_idx, | |
744 | (unsigned char *)packet | |
745 | + sizeof(struct ipw_rx_packet), | |
746 | packet->length); | |
747 | } | |
748 | pool_free(hw, packet); | |
749 | /* | |
750 | * Unblock reception of incoming packets if queue is no longer | |
751 | * full. | |
752 | */ | |
753 | hw->blocking_rx = | |
754 | hw->rx_bytes_queued >= IPWIRELESS_RX_QUEUE_SIZE; | |
755 | if (hw->shutting_down) | |
756 | break; | |
757 | } | |
758 | spin_unlock_irqrestore(&hw->spinlock, flags); | |
759 | } | |
760 | ||
761 | static void handle_received_CTRL_packet(struct ipw_hardware *hw, | |
762 | unsigned int channel_idx, | |
763 | unsigned char *data, int len) | |
764 | { | |
765 | struct ipw_control_packet_body *body = | |
766 | (struct ipw_control_packet_body *) data; | |
767 | unsigned int changed_mask; | |
768 | ||
769 | if (len != sizeof(struct ipw_control_packet_body)) { | |
770 | printk(KERN_INFO IPWIRELESS_PCCARD_NAME | |
771 | ": control packet was %d bytes - wrong size!\n", | |
772 | len); | |
773 | return; | |
774 | } | |
775 | ||
776 | switch (body->sig_no) { | |
777 | case COMCTRL_CTS: | |
778 | changed_mask = IPW_CONTROL_LINE_CTS; | |
779 | break; | |
780 | case COMCTRL_DCD: | |
781 | changed_mask = IPW_CONTROL_LINE_DCD; | |
782 | break; | |
783 | case COMCTRL_DSR: | |
784 | changed_mask = IPW_CONTROL_LINE_DSR; | |
785 | break; | |
786 | case COMCTRL_RI: | |
787 | changed_mask = IPW_CONTROL_LINE_RI; | |
788 | break; | |
789 | default: | |
790 | changed_mask = 0; | |
791 | } | |
792 | ||
793 | if (changed_mask != 0) { | |
794 | if (body->value) | |
795 | hw->control_lines[channel_idx] |= changed_mask; | |
796 | else | |
797 | hw->control_lines[channel_idx] &= ~changed_mask; | |
798 | if (hw->network) | |
799 | ipwireless_network_notify_control_line_change( | |
800 | hw->network, | |
801 | channel_idx, | |
802 | hw->control_lines[channel_idx], | |
803 | changed_mask); | |
804 | } | |
805 | } | |
806 | ||
807 | static void handle_received_packet(struct ipw_hardware *hw, | |
808 | union nl_packet *packet, | |
809 | unsigned short len) | |
810 | { | |
811 | unsigned int protocol = packet->hdr.protocol; | |
812 | unsigned int address = packet->hdr.address; | |
813 | unsigned int header_length; | |
814 | unsigned char *data; | |
815 | unsigned int data_len; | |
816 | int is_last = packet->hdr.packet_rank & NL_LAST_PACKET; | |
817 | ||
818 | if (packet->hdr.packet_rank & NL_FIRST_PACKET) | |
819 | header_length = NL_FIRST_PACKET_HEADER_SIZE; | |
820 | else | |
821 | header_length = NL_FOLLOWING_PACKET_HEADER_SIZE; | |
822 | ||
823 | data = packet->rawpkt + header_length; | |
824 | data_len = len - header_length; | |
825 | switch (protocol) { | |
826 | case TL_PROTOCOLID_COM_DATA: | |
827 | case TL_PROTOCOLID_COM_CTRL: | |
828 | queue_received_packet(hw, protocol, address, data, data_len, | |
829 | is_last); | |
830 | break; | |
831 | case TL_PROTOCOLID_SETUP: | |
832 | handle_received_SETUP_packet(hw, address, data, data_len, | |
833 | is_last); | |
834 | break; | |
835 | } | |
836 | } | |
837 | ||
838 | static void acknowledge_data_read(struct ipw_hardware *hw) | |
839 | { | |
840 | if (hw->hw_version == HW_VERSION_1) | |
841 | outw(DCR_RXDONE, hw->base_port + IODCR); | |
842 | else | |
843 | writew(MEMRX_PCINTACKK, | |
844 | &hw->memory_info_regs->memreg_pc_interrupt_ack); | |
845 | } | |
846 | ||
847 | /* | |
848 | * Retrieve a packet from the IPW hardware. | |
849 | */ | |
850 | static void do_receive_packet(struct ipw_hardware *hw) | |
851 | { | |
852 | unsigned len; | |
853 | unsigned int i; | |
854 | unsigned char pkt[LL_MTU_MAX]; | |
855 | ||
856 | start_timing(); | |
857 | ||
858 | if (hw->hw_version == HW_VERSION_1) { | |
859 | len = inw(hw->base_port + IODRR); | |
860 | if (len > hw->ll_mtu) { | |
861 | printk(KERN_INFO IPWIRELESS_PCCARD_NAME | |
862 | ": received a packet of %u bytes - " | |
863 | "longer than the MTU!\n", len); | |
864 | outw(DCR_RXDONE | DCR_RXRESET, hw->base_port + IODCR); | |
865 | return; | |
866 | } | |
867 | ||
868 | for (i = 0; i < len; i += 2) { | |
869 | __le16 raw_data = inw(hw->base_port + IODRR); | |
870 | unsigned short data = le16_to_cpu(raw_data); | |
871 | ||
872 | pkt[i] = (unsigned char) data; | |
873 | pkt[i + 1] = (unsigned char) (data >> 8); | |
874 | } | |
875 | } else { | |
876 | len = inw(hw->base_port + IODMADPR); | |
877 | if (len > hw->ll_mtu) { | |
878 | printk(KERN_INFO IPWIRELESS_PCCARD_NAME | |
879 | ": received a packet of %u bytes - " | |
880 | "longer than the MTU!\n", len); | |
881 | writew(MEMRX_PCINTACKK, | |
882 | &hw->memory_info_regs->memreg_pc_interrupt_ack); | |
883 | return; | |
884 | } | |
885 | ||
886 | for (i = 0; i < len; i += 2) { | |
887 | __le16 raw_data = inw(hw->base_port + IODMADPR); | |
888 | unsigned short data = le16_to_cpu(raw_data); | |
889 | ||
890 | pkt[i] = (unsigned char) data; | |
891 | pkt[i + 1] = (unsigned char) (data >> 8); | |
892 | } | |
893 | ||
894 | while ((i & 3) != 2) { | |
895 | inw(hw->base_port + IODMADPR); | |
896 | i += 2; | |
897 | } | |
898 | } | |
899 | ||
900 | acknowledge_data_read(hw); | |
901 | ||
902 | if (ipwireless_debug) | |
903 | dump_data_bytes("recv", pkt, len); | |
904 | ||
905 | handle_received_packet(hw, (union nl_packet *) pkt, len); | |
906 | ||
907 | end_read_timing(len); | |
908 | } | |
909 | ||
910 | static int get_current_packet_priority(struct ipw_hardware *hw) | |
911 | { | |
912 | /* | |
913 | * If we're initializing, don't send anything of higher priority than | |
914 | * PRIO_SETUP. The network layer therefore need not care about | |
915 | * hardware initialization - any of its stuff will simply be queued | |
916 | * until setup is complete. | |
917 | */ | |
918 | return (hw->to_setup || hw->initializing | |
919 | ? PRIO_SETUP + 1 : | |
920 | NL_NUM_OF_PRIORITIES); | |
921 | } | |
922 | ||
923 | /* | |
924 | * return 1 if something has been received from hw | |
925 | */ | |
926 | static int get_packets_from_hw(struct ipw_hardware *hw) | |
927 | { | |
928 | int received = 0; | |
929 | unsigned long flags; | |
930 | ||
931 | spin_lock_irqsave(&hw->spinlock, flags); | |
932 | while (hw->rx_ready && !hw->blocking_rx) { | |
933 | received = 1; | |
934 | hw->rx_ready--; | |
935 | spin_unlock_irqrestore(&hw->spinlock, flags); | |
936 | ||
937 | do_receive_packet(hw); | |
938 | ||
939 | spin_lock_irqsave(&hw->spinlock, flags); | |
940 | } | |
941 | spin_unlock_irqrestore(&hw->spinlock, flags); | |
942 | ||
943 | return received; | |
944 | } | |
945 | ||
946 | /* | |
947 | * Send pending packet up to given priority, prioritize SETUP data until | |
948 | * hardware is fully setup. | |
949 | * | |
950 | * return 1 if more packets can be sent | |
951 | */ | |
952 | static int send_pending_packet(struct ipw_hardware *hw, int priority_limit) | |
953 | { | |
954 | int more_to_send = 0; | |
955 | unsigned long flags; | |
956 | ||
957 | spin_lock_irqsave(&hw->spinlock, flags); | |
eb4e545d | 958 | if (hw->tx_queued && hw->tx_ready) { |
099dc4fb DS |
959 | int priority; |
960 | struct ipw_tx_packet *packet = NULL; | |
961 | ||
099dc4fb DS |
962 | /* Pick a packet */ |
963 | for (priority = 0; priority < priority_limit; priority++) { | |
964 | if (!list_empty(&hw->tx_queue[priority])) { | |
965 | packet = list_first_entry( | |
966 | &hw->tx_queue[priority], | |
967 | struct ipw_tx_packet, | |
968 | queue); | |
969 | ||
eb4e545d | 970 | hw->tx_queued--; |
099dc4fb DS |
971 | list_del(&packet->queue); |
972 | ||
973 | break; | |
974 | } | |
975 | } | |
976 | if (!packet) { | |
977 | hw->tx_queued = 0; | |
978 | spin_unlock_irqrestore(&hw->spinlock, flags); | |
979 | return 0; | |
980 | } | |
eb4e545d | 981 | |
099dc4fb DS |
982 | spin_unlock_irqrestore(&hw->spinlock, flags); |
983 | ||
984 | /* Send */ | |
985 | do_send_packet(hw, packet); | |
986 | ||
987 | /* Check if more to send */ | |
988 | spin_lock_irqsave(&hw->spinlock, flags); | |
989 | for (priority = 0; priority < priority_limit; priority++) | |
990 | if (!list_empty(&hw->tx_queue[priority])) { | |
991 | more_to_send = 1; | |
992 | break; | |
993 | } | |
994 | ||
995 | if (!more_to_send) | |
996 | hw->tx_queued = 0; | |
997 | } | |
998 | spin_unlock_irqrestore(&hw->spinlock, flags); | |
999 | ||
1000 | return more_to_send; | |
1001 | } | |
1002 | ||
1003 | /* | |
1004 | * Send and receive all queued packets. | |
1005 | */ | |
1006 | static void ipwireless_do_tasklet(unsigned long hw_) | |
1007 | { | |
1008 | struct ipw_hardware *hw = (struct ipw_hardware *) hw_; | |
1009 | unsigned long flags; | |
1010 | ||
1011 | spin_lock_irqsave(&hw->spinlock, flags); | |
1012 | if (hw->shutting_down) { | |
1013 | spin_unlock_irqrestore(&hw->spinlock, flags); | |
1014 | return; | |
1015 | } | |
1016 | ||
1017 | if (hw->to_setup == 1) { | |
1018 | /* | |
1019 | * Initial setup data sent to hardware | |
1020 | */ | |
1021 | hw->to_setup = 2; | |
1022 | spin_unlock_irqrestore(&hw->spinlock, flags); | |
1023 | ||
1024 | ipw_setup_hardware(hw); | |
1025 | ipw_send_setup_packet(hw); | |
1026 | ||
1027 | send_pending_packet(hw, PRIO_SETUP + 1); | |
1028 | get_packets_from_hw(hw); | |
1029 | } else { | |
1030 | int priority_limit = get_current_packet_priority(hw); | |
1031 | int again; | |
1032 | ||
1033 | spin_unlock_irqrestore(&hw->spinlock, flags); | |
1034 | ||
1035 | do { | |
1036 | again = send_pending_packet(hw, priority_limit); | |
1037 | again |= get_packets_from_hw(hw); | |
1038 | } while (again); | |
1039 | } | |
1040 | } | |
1041 | ||
1042 | /* | |
1043 | * return true if the card is physically present. | |
1044 | */ | |
1045 | static int is_card_present(struct ipw_hardware *hw) | |
1046 | { | |
1047 | if (hw->hw_version == HW_VERSION_1) | |
1048 | return inw(hw->base_port + IOIR) != 0xFFFF; | |
1049 | else | |
1050 | return readl(&hw->memory_info_regs->memreg_card_present) == | |
1051 | CARD_PRESENT_VALUE; | |
1052 | } | |
1053 | ||
1054 | static irqreturn_t ipwireless_handle_v1_interrupt(int irq, | |
1055 | struct ipw_hardware *hw) | |
1056 | { | |
1057 | unsigned short irqn; | |
1058 | ||
1059 | irqn = inw(hw->base_port + IOIR); | |
1060 | ||
1061 | /* Check if card is present */ | |
1062 | if (irqn == 0xFFFF) | |
1063 | return IRQ_NONE; | |
1064 | else if (irqn != 0) { | |
1065 | unsigned short ack = 0; | |
1066 | unsigned long flags; | |
1067 | ||
1068 | /* Transmit complete. */ | |
1069 | if (irqn & IR_TXINTR) { | |
1070 | ack |= IR_TXINTR; | |
1071 | spin_lock_irqsave(&hw->spinlock, flags); | |
eb4e545d | 1072 | hw->tx_ready = 1; |
099dc4fb DS |
1073 | spin_unlock_irqrestore(&hw->spinlock, flags); |
1074 | } | |
1075 | /* Received data */ | |
1076 | if (irqn & IR_RXINTR) { | |
1077 | ack |= IR_RXINTR; | |
1078 | spin_lock_irqsave(&hw->spinlock, flags); | |
1079 | hw->rx_ready++; | |
1080 | spin_unlock_irqrestore(&hw->spinlock, flags); | |
1081 | } | |
1082 | if (ack != 0) { | |
1083 | outw(ack, hw->base_port + IOIR); | |
1084 | tasklet_schedule(&hw->tasklet); | |
1085 | } | |
1086 | return IRQ_HANDLED; | |
1087 | } | |
1088 | return IRQ_NONE; | |
1089 | } | |
1090 | ||
1091 | static void acknowledge_pcmcia_interrupt(struct ipw_hardware *hw) | |
1092 | { | |
1093 | unsigned short csr = readw(&hw->memregs_CCR->reg_config_and_status); | |
1094 | ||
1095 | csr &= 0xfffd; | |
1096 | writew(csr, &hw->memregs_CCR->reg_config_and_status); | |
1097 | } | |
1098 | ||
1099 | static irqreturn_t ipwireless_handle_v2_v3_interrupt(int irq, | |
1100 | struct ipw_hardware *hw) | |
1101 | { | |
1102 | int tx = 0; | |
1103 | int rx = 0; | |
1104 | int rx_repeat = 0; | |
1105 | int try_mem_tx_old; | |
1106 | unsigned long flags; | |
1107 | ||
1108 | do { | |
1109 | ||
1110 | unsigned short memtx = readw(hw->memreg_tx); | |
1111 | unsigned short memtx_serial; | |
1112 | unsigned short memrxdone = | |
1113 | readw(&hw->memory_info_regs->memreg_rx_done); | |
1114 | ||
1115 | try_mem_tx_old = 0; | |
1116 | ||
1117 | /* check whether the interrupt was generated by ipwireless card */ | |
1118 | if (!(memtx & MEMTX_TX) && !(memrxdone & MEMRX_RX_DONE)) { | |
1119 | ||
1120 | /* check if the card uses memreg_tx_old register */ | |
1121 | if (hw->memreg_tx == &hw->memory_info_regs->memreg_tx_new) { | |
1122 | memtx = readw(&hw->memory_info_regs->memreg_tx_old); | |
1123 | if (memtx & MEMTX_TX) { | |
1124 | printk(KERN_INFO IPWIRELESS_PCCARD_NAME | |
1125 | ": Using memreg_tx_old\n"); | |
1126 | hw->memreg_tx = | |
1127 | &hw->memory_info_regs->memreg_tx_old; | |
1128 | } else { | |
1129 | return IRQ_NONE; | |
1130 | } | |
1131 | } else { | |
1132 | return IRQ_NONE; | |
1133 | } | |
1134 | } | |
1135 | ||
1136 | /* | |
1137 | * See if the card is physically present. Note that while it is | |
1138 | * powering up, it appears not to be present. | |
1139 | */ | |
1140 | if (!is_card_present(hw)) { | |
1141 | acknowledge_pcmcia_interrupt(hw); | |
1142 | return IRQ_HANDLED; | |
1143 | } | |
1144 | ||
1145 | memtx_serial = memtx & (unsigned short) 0xff00; | |
1146 | if (memtx & MEMTX_TX) { | |
1147 | writew(memtx_serial, hw->memreg_tx); | |
1148 | ||
1149 | if (hw->serial_number_detected) { | |
1150 | if (memtx_serial != hw->last_memtx_serial) { | |
1151 | hw->last_memtx_serial = memtx_serial; | |
1152 | spin_lock_irqsave(&hw->spinlock, flags); | |
1153 | hw->rx_ready++; | |
1154 | spin_unlock_irqrestore(&hw->spinlock, flags); | |
1155 | rx = 1; | |
1156 | } else | |
1157 | /* Ignore 'Timer Recovery' duplicates. */ | |
1158 | rx_repeat = 1; | |
1159 | } else { | |
1160 | /* | |
1161 | * If a non-zero serial number is seen, then enable | |
1162 | * serial number checking. | |
1163 | */ | |
1164 | if (memtx_serial != 0) { | |
1165 | hw->serial_number_detected = 1; | |
1166 | printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME | |
1167 | ": memreg_tx serial num detected\n"); | |
1168 | ||
1169 | spin_lock_irqsave(&hw->spinlock, flags); | |
1170 | hw->rx_ready++; | |
1171 | spin_unlock_irqrestore(&hw->spinlock, flags); | |
1172 | } | |
1173 | rx = 1; | |
1174 | } | |
1175 | } | |
1176 | if (memrxdone & MEMRX_RX_DONE) { | |
1177 | writew(0, &hw->memory_info_regs->memreg_rx_done); | |
1178 | spin_lock_irqsave(&hw->spinlock, flags); | |
eb4e545d | 1179 | hw->tx_ready = 1; |
099dc4fb DS |
1180 | spin_unlock_irqrestore(&hw->spinlock, flags); |
1181 | tx = 1; | |
1182 | } | |
1183 | if (tx) | |
1184 | writew(MEMRX_PCINTACKK, | |
1185 | &hw->memory_info_regs->memreg_pc_interrupt_ack); | |
1186 | ||
1187 | acknowledge_pcmcia_interrupt(hw); | |
1188 | ||
1189 | if (tx || rx) | |
1190 | tasklet_schedule(&hw->tasklet); | |
1191 | else if (!rx_repeat) { | |
1192 | if (hw->memreg_tx == &hw->memory_info_regs->memreg_tx_new) { | |
1193 | if (hw->serial_number_detected) | |
1194 | printk(KERN_WARNING IPWIRELESS_PCCARD_NAME | |
1195 | ": spurious interrupt - new_tx mode\n"); | |
1196 | else { | |
1197 | printk(KERN_WARNING IPWIRELESS_PCCARD_NAME | |
1198 | ": no valid memreg_tx value - " | |
1199 | "switching to the old memreg_tx\n"); | |
1200 | hw->memreg_tx = | |
1201 | &hw->memory_info_regs->memreg_tx_old; | |
1202 | try_mem_tx_old = 1; | |
1203 | } | |
1204 | } else | |
1205 | printk(KERN_WARNING IPWIRELESS_PCCARD_NAME | |
1206 | ": spurious interrupt - old_tx mode\n"); | |
1207 | } | |
1208 | ||
1209 | } while (try_mem_tx_old == 1); | |
1210 | ||
1211 | return IRQ_HANDLED; | |
1212 | } | |
1213 | ||
1214 | irqreturn_t ipwireless_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |
1215 | { | |
1216 | struct ipw_hardware *hw = dev_id; | |
1217 | ||
1218 | if (hw->hw_version == HW_VERSION_1) | |
1219 | return ipwireless_handle_v1_interrupt(irq, hw); | |
1220 | else | |
1221 | return ipwireless_handle_v2_v3_interrupt(irq, hw); | |
1222 | } | |
1223 | ||
1224 | static void flush_packets_to_hw(struct ipw_hardware *hw) | |
1225 | { | |
1226 | int priority_limit; | |
1227 | unsigned long flags; | |
1228 | ||
1229 | spin_lock_irqsave(&hw->spinlock, flags); | |
1230 | priority_limit = get_current_packet_priority(hw); | |
1231 | spin_unlock_irqrestore(&hw->spinlock, flags); | |
1232 | ||
1233 | while (send_pending_packet(hw, priority_limit)); | |
1234 | } | |
1235 | ||
1236 | static void send_packet(struct ipw_hardware *hw, int priority, | |
1237 | struct ipw_tx_packet *packet) | |
1238 | { | |
1239 | unsigned long flags; | |
1240 | ||
1241 | spin_lock_irqsave(&hw->spinlock, flags); | |
1242 | list_add_tail(&packet->queue, &hw->tx_queue[priority]); | |
eb4e545d | 1243 | hw->tx_queued++; |
099dc4fb DS |
1244 | spin_unlock_irqrestore(&hw->spinlock, flags); |
1245 | ||
1246 | flush_packets_to_hw(hw); | |
1247 | } | |
1248 | ||
1249 | /* Create data packet, non-atomic allocation */ | |
1250 | static void *alloc_data_packet(int data_size, | |
1251 | unsigned char dest_addr, | |
1252 | unsigned char protocol) | |
1253 | { | |
1254 | struct ipw_tx_packet *packet = kzalloc( | |
1255 | sizeof(struct ipw_tx_packet) + data_size, | |
1256 | GFP_ATOMIC); | |
1257 | ||
1258 | if (!packet) | |
1259 | return NULL; | |
1260 | ||
1261 | INIT_LIST_HEAD(&packet->queue); | |
1262 | packet->dest_addr = dest_addr; | |
1263 | packet->protocol = protocol; | |
1264 | packet->length = data_size; | |
1265 | ||
1266 | return packet; | |
1267 | } | |
1268 | ||
1269 | static void *alloc_ctrl_packet(int header_size, | |
1270 | unsigned char dest_addr, | |
1271 | unsigned char protocol, | |
1272 | unsigned char sig_no) | |
1273 | { | |
1274 | /* | |
1275 | * sig_no is located right after ipw_tx_packet struct in every | |
1276 | * CTRL or SETUP packets, we can use ipw_control_packet as a | |
1277 | * common struct | |
1278 | */ | |
1279 | struct ipw_control_packet *packet = kzalloc(header_size, GFP_ATOMIC); | |
1280 | ||
1281 | if (!packet) | |
1282 | return NULL; | |
1283 | ||
1284 | INIT_LIST_HEAD(&packet->header.queue); | |
1285 | packet->header.dest_addr = dest_addr; | |
1286 | packet->header.protocol = protocol; | |
1287 | packet->header.length = header_size - sizeof(struct ipw_tx_packet); | |
1288 | packet->body.sig_no = sig_no; | |
1289 | ||
1290 | return packet; | |
1291 | } | |
1292 | ||
1293 | int ipwireless_send_packet(struct ipw_hardware *hw, unsigned int channel_idx, | |
1294 | unsigned char *data, unsigned int length, | |
1295 | void (*callback) (void *cb, unsigned int length), | |
1296 | void *callback_data) | |
1297 | { | |
1298 | struct ipw_tx_packet *packet; | |
1299 | ||
1300 | packet = alloc_data_packet(length, | |
1301 | (unsigned char) (channel_idx + 1), | |
1302 | TL_PROTOCOLID_COM_DATA); | |
1303 | if (!packet) | |
1304 | return -ENOMEM; | |
1305 | packet->packet_callback = callback; | |
1306 | packet->callback_data = callback_data; | |
1307 | memcpy((unsigned char *) packet + | |
1308 | sizeof(struct ipw_tx_packet), data, length); | |
1309 | ||
1310 | send_packet(hw, PRIO_DATA, packet); | |
1311 | return 0; | |
1312 | } | |
1313 | ||
1314 | static int set_control_line(struct ipw_hardware *hw, int prio, | |
1315 | unsigned int channel_idx, int line, int state) | |
1316 | { | |
1317 | struct ipw_control_packet *packet; | |
1318 | int protocolid = TL_PROTOCOLID_COM_CTRL; | |
1319 | ||
1320 | if (prio == PRIO_SETUP) | |
1321 | protocolid = TL_PROTOCOLID_SETUP; | |
1322 | ||
1323 | packet = alloc_ctrl_packet(sizeof(struct ipw_control_packet), | |
1324 | (unsigned char) (channel_idx + 1), | |
1325 | protocolid, line); | |
1326 | if (!packet) | |
1327 | return -ENOMEM; | |
1328 | packet->header.length = sizeof(struct ipw_control_packet_body); | |
1329 | packet->body.value = (unsigned char) (state == 0 ? 0 : 1); | |
1330 | send_packet(hw, prio, &packet->header); | |
1331 | return 0; | |
1332 | } | |
1333 | ||
1334 | ||
1335 | static int set_DTR(struct ipw_hardware *hw, int priority, | |
1336 | unsigned int channel_idx, int state) | |
1337 | { | |
1338 | if (state != 0) | |
1339 | hw->control_lines[channel_idx] |= IPW_CONTROL_LINE_DTR; | |
1340 | else | |
1341 | hw->control_lines[channel_idx] &= ~IPW_CONTROL_LINE_DTR; | |
1342 | ||
1343 | return set_control_line(hw, priority, channel_idx, COMCTRL_DTR, state); | |
1344 | } | |
1345 | ||
1346 | static int set_RTS(struct ipw_hardware *hw, int priority, | |
1347 | unsigned int channel_idx, int state) | |
1348 | { | |
1349 | if (state != 0) | |
1350 | hw->control_lines[channel_idx] |= IPW_CONTROL_LINE_RTS; | |
1351 | else | |
1352 | hw->control_lines[channel_idx] &= ~IPW_CONTROL_LINE_RTS; | |
1353 | ||
1354 | return set_control_line(hw, priority, channel_idx, COMCTRL_RTS, state); | |
1355 | } | |
1356 | ||
1357 | int ipwireless_set_DTR(struct ipw_hardware *hw, unsigned int channel_idx, | |
1358 | int state) | |
1359 | { | |
1360 | return set_DTR(hw, PRIO_CTRL, channel_idx, state); | |
1361 | } | |
1362 | ||
1363 | int ipwireless_set_RTS(struct ipw_hardware *hw, unsigned int channel_idx, | |
1364 | int state) | |
1365 | { | |
1366 | return set_RTS(hw, PRIO_CTRL, channel_idx, state); | |
1367 | } | |
1368 | ||
1369 | struct ipw_setup_get_version_query_packet { | |
1370 | struct ipw_tx_packet header; | |
1371 | struct tl_setup_get_version_qry body; | |
1372 | }; | |
1373 | ||
1374 | struct ipw_setup_config_packet { | |
1375 | struct ipw_tx_packet header; | |
1376 | struct tl_setup_config_msg body; | |
1377 | }; | |
1378 | ||
1379 | struct ipw_setup_config_done_packet { | |
1380 | struct ipw_tx_packet header; | |
1381 | struct tl_setup_config_done_msg body; | |
1382 | }; | |
1383 | ||
1384 | struct ipw_setup_open_packet { | |
1385 | struct ipw_tx_packet header; | |
1386 | struct tl_setup_open_msg body; | |
1387 | }; | |
1388 | ||
1389 | struct ipw_setup_info_packet { | |
1390 | struct ipw_tx_packet header; | |
1391 | struct tl_setup_info_msg body; | |
1392 | }; | |
1393 | ||
1394 | struct ipw_setup_reboot_msg_ack { | |
1395 | struct ipw_tx_packet header; | |
1396 | struct TlSetupRebootMsgAck body; | |
1397 | }; | |
1398 | ||
1399 | /* This handles the actual initialization of the card */ | |
1400 | static void __handle_setup_get_version_rsp(struct ipw_hardware *hw) | |
1401 | { | |
1402 | struct ipw_setup_config_packet *config_packet; | |
1403 | struct ipw_setup_config_done_packet *config_done_packet; | |
1404 | struct ipw_setup_open_packet *open_packet; | |
1405 | struct ipw_setup_info_packet *info_packet; | |
1406 | int port; | |
1407 | unsigned int channel_idx; | |
1408 | ||
1409 | /* generate config packet */ | |
1410 | for (port = 1; port <= NL_NUM_OF_ADDRESSES; port++) { | |
1411 | config_packet = alloc_ctrl_packet( | |
1412 | sizeof(struct ipw_setup_config_packet), | |
1413 | ADDR_SETUP_PROT, | |
1414 | TL_PROTOCOLID_SETUP, | |
1415 | TL_SETUP_SIGNO_CONFIG_MSG); | |
1416 | if (!config_packet) | |
1417 | goto exit_nomem; | |
1418 | config_packet->header.length = sizeof(struct tl_setup_config_msg); | |
1419 | config_packet->body.port_no = port; | |
1420 | config_packet->body.prio_data = PRIO_DATA; | |
1421 | config_packet->body.prio_ctrl = PRIO_CTRL; | |
1422 | send_packet(hw, PRIO_SETUP, &config_packet->header); | |
1423 | } | |
1424 | config_done_packet = alloc_ctrl_packet( | |
1425 | sizeof(struct ipw_setup_config_done_packet), | |
1426 | ADDR_SETUP_PROT, | |
1427 | TL_PROTOCOLID_SETUP, | |
1428 | TL_SETUP_SIGNO_CONFIG_DONE_MSG); | |
1429 | if (!config_done_packet) | |
1430 | goto exit_nomem; | |
1431 | config_done_packet->header.length = sizeof(struct tl_setup_config_done_msg); | |
1432 | send_packet(hw, PRIO_SETUP, &config_done_packet->header); | |
1433 | ||
1434 | /* generate open packet */ | |
1435 | for (port = 1; port <= NL_NUM_OF_ADDRESSES; port++) { | |
1436 | open_packet = alloc_ctrl_packet( | |
1437 | sizeof(struct ipw_setup_open_packet), | |
1438 | ADDR_SETUP_PROT, | |
1439 | TL_PROTOCOLID_SETUP, | |
1440 | TL_SETUP_SIGNO_OPEN_MSG); | |
1441 | if (!open_packet) | |
1442 | goto exit_nomem; | |
1443 | open_packet->header.length = sizeof(struct tl_setup_open_msg); | |
1444 | open_packet->body.port_no = port; | |
1445 | send_packet(hw, PRIO_SETUP, &open_packet->header); | |
1446 | } | |
1447 | for (channel_idx = 0; | |
1448 | channel_idx < NL_NUM_OF_ADDRESSES; channel_idx++) { | |
1449 | int ret; | |
1450 | ||
1451 | ret = set_DTR(hw, PRIO_SETUP, channel_idx, | |
1452 | (hw->control_lines[channel_idx] & | |
1453 | IPW_CONTROL_LINE_DTR) != 0); | |
1454 | if (ret) { | |
1455 | printk(KERN_ERR IPWIRELESS_PCCARD_NAME | |
1456 | ": error setting DTR (%d)\n", ret); | |
1457 | return; | |
1458 | } | |
1459 | ||
1460 | set_RTS(hw, PRIO_SETUP, channel_idx, | |
1461 | (hw->control_lines [channel_idx] & | |
1462 | IPW_CONTROL_LINE_RTS) != 0); | |
1463 | if (ret) { | |
1464 | printk(KERN_ERR IPWIRELESS_PCCARD_NAME | |
1465 | ": error setting RTS (%d)\n", ret); | |
1466 | return; | |
1467 | } | |
1468 | } | |
1469 | /* | |
1470 | * For NDIS we assume that we are using sync PPP frames, for COM async. | |
1471 | * This driver uses NDIS mode too. We don't bother with translation | |
1472 | * from async -> sync PPP. | |
1473 | */ | |
1474 | info_packet = alloc_ctrl_packet(sizeof(struct ipw_setup_info_packet), | |
1475 | ADDR_SETUP_PROT, | |
1476 | TL_PROTOCOLID_SETUP, | |
1477 | TL_SETUP_SIGNO_INFO_MSG); | |
1478 | if (!info_packet) | |
1479 | goto exit_nomem; | |
1480 | info_packet->header.length = sizeof(struct tl_setup_info_msg); | |
1481 | info_packet->body.driver_type = NDISWAN_DRIVER; | |
1482 | info_packet->body.major_version = NDISWAN_DRIVER_MAJOR_VERSION; | |
1483 | info_packet->body.minor_version = NDISWAN_DRIVER_MINOR_VERSION; | |
1484 | send_packet(hw, PRIO_SETUP, &info_packet->header); | |
1485 | ||
1486 | /* Initialization is now complete, so we clear the 'to_setup' flag */ | |
1487 | hw->to_setup = 0; | |
1488 | ||
1489 | return; | |
1490 | ||
1491 | exit_nomem: | |
1492 | printk(KERN_ERR IPWIRELESS_PCCARD_NAME | |
1493 | ": not enough memory to alloc control packet\n"); | |
1494 | hw->to_setup = -1; | |
1495 | } | |
1496 | ||
1497 | static void handle_setup_get_version_rsp(struct ipw_hardware *hw, | |
1498 | unsigned char vers_no) | |
1499 | { | |
1500 | del_timer(&hw->setup_timer); | |
1501 | hw->initializing = 0; | |
1502 | printk(KERN_INFO IPWIRELESS_PCCARD_NAME ": card is ready.\n"); | |
1503 | ||
1504 | if (vers_no == TL_SETUP_VERSION) | |
1505 | __handle_setup_get_version_rsp(hw); | |
1506 | else | |
1507 | printk(KERN_ERR | |
1508 | IPWIRELESS_PCCARD_NAME | |
1509 | ": invalid hardware version no %u\n", | |
1510 | (unsigned int) vers_no); | |
1511 | } | |
1512 | ||
1513 | static void ipw_send_setup_packet(struct ipw_hardware *hw) | |
1514 | { | |
1515 | struct ipw_setup_get_version_query_packet *ver_packet; | |
1516 | ||
1517 | ver_packet = alloc_ctrl_packet( | |
1518 | sizeof(struct ipw_setup_get_version_query_packet), | |
1519 | ADDR_SETUP_PROT, TL_PROTOCOLID_SETUP, | |
1520 | TL_SETUP_SIGNO_GET_VERSION_QRY); | |
1521 | ver_packet->header.length = sizeof(struct tl_setup_get_version_qry); | |
1522 | ||
1523 | /* | |
1524 | * Response is handled in handle_received_SETUP_packet | |
1525 | */ | |
1526 | send_packet(hw, PRIO_SETUP, &ver_packet->header); | |
1527 | } | |
1528 | ||
1529 | static void handle_received_SETUP_packet(struct ipw_hardware *hw, | |
1530 | unsigned int address, | |
1531 | unsigned char *data, int len, | |
1532 | int is_last) | |
1533 | { | |
1534 | union ipw_setup_rx_msg *rx_msg = (union ipw_setup_rx_msg *) data; | |
1535 | ||
1536 | if (address != ADDR_SETUP_PROT) { | |
1537 | printk(KERN_INFO IPWIRELESS_PCCARD_NAME | |
1538 | ": setup packet has bad address %d\n", address); | |
1539 | return; | |
1540 | } | |
1541 | ||
1542 | switch (rx_msg->sig_no) { | |
1543 | case TL_SETUP_SIGNO_GET_VERSION_RSP: | |
1544 | if (hw->to_setup) | |
1545 | handle_setup_get_version_rsp(hw, | |
1546 | rx_msg->version_rsp_msg.version); | |
1547 | break; | |
1548 | ||
1549 | case TL_SETUP_SIGNO_OPEN_MSG: | |
1550 | if (ipwireless_debug) { | |
1551 | unsigned int channel_idx = rx_msg->open_msg.port_no - 1; | |
1552 | ||
1553 | printk(KERN_INFO IPWIRELESS_PCCARD_NAME | |
1554 | ": OPEN_MSG [channel %u] reply received\n", | |
1555 | channel_idx); | |
1556 | } | |
1557 | break; | |
1558 | ||
1559 | case TL_SETUP_SIGNO_INFO_MSG_ACK: | |
1560 | if (ipwireless_debug) | |
1561 | printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME | |
1562 | ": card successfully configured as NDISWAN\n"); | |
1563 | break; | |
1564 | ||
1565 | case TL_SETUP_SIGNO_REBOOT_MSG: | |
1566 | if (hw->to_setup) | |
1567 | printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME | |
1568 | ": Setup not completed - ignoring reboot msg\n"); | |
1569 | else { | |
1570 | struct ipw_setup_reboot_msg_ack *packet; | |
1571 | ||
1572 | printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME | |
1573 | ": Acknowledging REBOOT message\n"); | |
1574 | packet = alloc_ctrl_packet( | |
1575 | sizeof(struct ipw_setup_reboot_msg_ack), | |
1576 | ADDR_SETUP_PROT, TL_PROTOCOLID_SETUP, | |
1577 | TL_SETUP_SIGNO_REBOOT_MSG_ACK); | |
1578 | packet->header.length = | |
1579 | sizeof(struct TlSetupRebootMsgAck); | |
1580 | send_packet(hw, PRIO_SETUP, &packet->header); | |
1581 | if (hw->reboot_callback) | |
1582 | hw->reboot_callback(hw->reboot_callback_data); | |
1583 | } | |
1584 | break; | |
1585 | ||
1586 | default: | |
1587 | printk(KERN_INFO IPWIRELESS_PCCARD_NAME | |
1588 | ": unknown setup message %u received\n", | |
1589 | (unsigned int) rx_msg->sig_no); | |
1590 | } | |
1591 | } | |
1592 | ||
1593 | static void do_close_hardware(struct ipw_hardware *hw) | |
1594 | { | |
1595 | unsigned int irqn; | |
1596 | ||
1597 | if (hw->hw_version == HW_VERSION_1) { | |
1598 | /* Disable TX and RX interrupts. */ | |
1599 | outw(0, hw->base_port + IOIER); | |
1600 | ||
1601 | /* Acknowledge any outstanding interrupt requests */ | |
1602 | irqn = inw(hw->base_port + IOIR); | |
1603 | if (irqn & IR_TXINTR) | |
1604 | outw(IR_TXINTR, hw->base_port + IOIR); | |
1605 | if (irqn & IR_RXINTR) | |
1606 | outw(IR_RXINTR, hw->base_port + IOIR); | |
1607 | ||
1608 | synchronize_irq(hw->irq); | |
1609 | } | |
1610 | } | |
1611 | ||
1612 | struct ipw_hardware *ipwireless_hardware_create(void) | |
1613 | { | |
1614 | int i; | |
1615 | struct ipw_hardware *hw = | |
1616 | kzalloc(sizeof(struct ipw_hardware), GFP_KERNEL); | |
1617 | ||
1618 | if (!hw) | |
1619 | return NULL; | |
1620 | ||
1621 | hw->irq = -1; | |
1622 | hw->initializing = 1; | |
1623 | hw->tx_ready = 1; | |
1624 | hw->rx_bytes_queued = 0; | |
1625 | hw->rx_pool_size = 0; | |
1626 | hw->last_memtx_serial = (unsigned short) 0xffff; | |
1627 | for (i = 0; i < NL_NUM_OF_PRIORITIES; i++) | |
1628 | INIT_LIST_HEAD(&hw->tx_queue[i]); | |
1629 | ||
1630 | INIT_LIST_HEAD(&hw->rx_queue); | |
1631 | INIT_LIST_HEAD(&hw->rx_pool); | |
1632 | spin_lock_init(&hw->spinlock); | |
1633 | tasklet_init(&hw->tasklet, ipwireless_do_tasklet, (unsigned long) hw); | |
1634 | INIT_WORK(&hw->work_rx, ipw_receive_data_work); | |
1635 | setup_timer(&hw->setup_timer, ipwireless_setup_timer, | |
1636 | (unsigned long) hw); | |
1637 | ||
1638 | return hw; | |
1639 | } | |
1640 | ||
1641 | void ipwireless_init_hardware_v1(struct ipw_hardware *hw, | |
1642 | unsigned int base_port, | |
1643 | void __iomem *attr_memory, | |
1644 | void __iomem *common_memory, | |
1645 | int is_v2_card, | |
1646 | void (*reboot_callback) (void *data), | |
1647 | void *reboot_callback_data) | |
1648 | { | |
1649 | if (hw->removed) { | |
1650 | hw->removed = 0; | |
1651 | enable_irq(hw->irq); | |
1652 | } | |
1653 | hw->base_port = base_port; | |
1654 | hw->hw_version = is_v2_card ? HW_VERSION_2 : HW_VERSION_1; | |
1655 | hw->ll_mtu = hw->hw_version == HW_VERSION_1 ? LL_MTU_V1 : LL_MTU_V2; | |
1656 | hw->memregs_CCR = (struct MEMCCR __iomem *) | |
1657 | ((unsigned short __iomem *) attr_memory + 0x200); | |
1658 | hw->memory_info_regs = (struct MEMINFREG __iomem *) common_memory; | |
1659 | hw->memreg_tx = &hw->memory_info_regs->memreg_tx_new; | |
1660 | hw->reboot_callback = reboot_callback; | |
1661 | hw->reboot_callback_data = reboot_callback_data; | |
1662 | } | |
1663 | ||
1664 | void ipwireless_init_hardware_v2_v3(struct ipw_hardware *hw) | |
1665 | { | |
1666 | hw->initializing = 1; | |
1667 | hw->init_loops = 0; | |
1668 | printk(KERN_INFO IPWIRELESS_PCCARD_NAME | |
1669 | ": waiting for card to start up...\n"); | |
1670 | ipwireless_setup_timer((unsigned long) hw); | |
1671 | } | |
1672 | ||
1673 | static void ipwireless_setup_timer(unsigned long data) | |
1674 | { | |
1675 | struct ipw_hardware *hw = (struct ipw_hardware *) data; | |
1676 | ||
1677 | hw->init_loops++; | |
1678 | ||
1679 | if (hw->init_loops == TL_SETUP_MAX_VERSION_QRY && | |
1680 | hw->hw_version == HW_VERSION_2 && | |
1681 | hw->memreg_tx == &hw->memory_info_regs->memreg_tx_new) { | |
1682 | printk(KERN_INFO IPWIRELESS_PCCARD_NAME | |
1683 | ": failed to startup using TX2, trying TX\n"); | |
1684 | ||
1685 | hw->memreg_tx = &hw->memory_info_regs->memreg_tx_old; | |
1686 | hw->init_loops = 0; | |
1687 | } | |
1688 | /* Give up after a certain number of retries */ | |
1689 | if (hw->init_loops == TL_SETUP_MAX_VERSION_QRY) { | |
1690 | printk(KERN_INFO IPWIRELESS_PCCARD_NAME | |
1691 | ": card failed to start up!\n"); | |
1692 | hw->initializing = 0; | |
1693 | } else { | |
1694 | /* Do not attempt to write to the board if it is not present. */ | |
1695 | if (is_card_present(hw)) { | |
1696 | unsigned long flags; | |
1697 | ||
1698 | spin_lock_irqsave(&hw->spinlock, flags); | |
1699 | hw->to_setup = 1; | |
1700 | hw->tx_ready = 1; | |
1701 | spin_unlock_irqrestore(&hw->spinlock, flags); | |
1702 | tasklet_schedule(&hw->tasklet); | |
1703 | } | |
1704 | ||
1705 | mod_timer(&hw->setup_timer, | |
1706 | jiffies + msecs_to_jiffies(TL_SETUP_VERSION_QRY_TMO)); | |
1707 | } | |
1708 | } | |
1709 | ||
1710 | /* | |
1711 | * Stop any interrupts from executing so that, once this function returns, | |
1712 | * other layers of the driver can be sure they won't get any more callbacks. | |
1713 | * Thus must be called on a proper process context. | |
1714 | */ | |
1715 | void ipwireless_stop_interrupts(struct ipw_hardware *hw) | |
1716 | { | |
1717 | if (!hw->shutting_down) { | |
1718 | /* Tell everyone we are going down. */ | |
1719 | hw->shutting_down = 1; | |
1720 | del_timer(&hw->setup_timer); | |
1721 | ||
1722 | /* Prevent the hardware from sending any more interrupts */ | |
1723 | do_close_hardware(hw); | |
1724 | } | |
1725 | } | |
1726 | ||
1727 | void ipwireless_hardware_free(struct ipw_hardware *hw) | |
1728 | { | |
1729 | int i; | |
1730 | struct ipw_rx_packet *rp, *rq; | |
1731 | struct ipw_tx_packet *tp, *tq; | |
1732 | ||
1733 | ipwireless_stop_interrupts(hw); | |
1734 | ||
1735 | flush_scheduled_work(); | |
1736 | ||
1737 | for (i = 0; i < NL_NUM_OF_ADDRESSES; i++) | |
1738 | if (hw->packet_assembler[i] != NULL) | |
1739 | kfree(hw->packet_assembler[i]); | |
1740 | ||
1741 | for (i = 0; i < NL_NUM_OF_PRIORITIES; i++) | |
1742 | list_for_each_entry_safe(tp, tq, &hw->tx_queue[i], queue) { | |
1743 | list_del(&tp->queue); | |
1744 | kfree(tp); | |
1745 | } | |
1746 | ||
1747 | list_for_each_entry_safe(rp, rq, &hw->rx_queue, queue) { | |
1748 | list_del(&rp->queue); | |
1749 | kfree(rp); | |
1750 | } | |
1751 | ||
1752 | list_for_each_entry_safe(rp, rq, &hw->rx_pool, queue) { | |
1753 | list_del(&rp->queue); | |
1754 | kfree(rp); | |
1755 | } | |
1756 | kfree(hw); | |
1757 | } | |
1758 | ||
1759 | /* | |
1760 | * Associate the specified network with this hardware, so it will receive events | |
1761 | * from it. | |
1762 | */ | |
1763 | void ipwireless_associate_network(struct ipw_hardware *hw, | |
1764 | struct ipw_network *network) | |
1765 | { | |
1766 | hw->network = network; | |
1767 | } |