This source file includes following definitions.
- display_buffer
- pimfor_encode_header
- pimfor_decode_header
- islpci_mgmt_rx_fill
- islpci_mgt_transmit
- islpci_mgt_receive
- islpci_mgt_cleanup_transmit
- islpci_mgt_transaction
1
2
3
4
5
6
7 #include <linux/netdevice.h>
8 #include <linux/module.h>
9 #include <linux/pci.h>
10 #include <linux/sched.h>
11 #include <linux/slab.h>
12
13 #include <asm/io.h>
14 #include <linux/if_arp.h>
15
16 #include "prismcompat.h"
17 #include "isl_38xx.h"
18 #include "islpci_mgt.h"
19 #include "isl_oid.h"
20 #include "isl_ioctl.h"
21
22 #include <net/iw_handler.h>
23
24
25
26
27 int pc_debug = VERBOSE;
28 module_param(pc_debug, int, 0);
29
30
31
32
33 #if VERBOSE > SHOW_ERROR_MESSAGES
34 void
35 display_buffer(char *buffer, int length)
36 {
37 if ((pc_debug & SHOW_BUFFER_CONTENTS) == 0)
38 return;
39
40 while (length > 0) {
41 printk("[%02x]", *buffer & 255);
42 length--;
43 buffer++;
44 }
45
46 printk("\n");
47 }
48 #endif
49
50
51
52
53
54
55
56
57 static void
58 pimfor_encode_header(int operation, u32 oid, u32 length, pimfor_header_t *h)
59 {
60 h->version = PIMFOR_VERSION;
61 h->operation = operation;
62 h->device_id = PIMFOR_DEV_ID_MHLI_MIB;
63 h->flags = 0;
64 h->oid = cpu_to_be32(oid);
65 h->length = cpu_to_be32(length);
66 }
67
68
69
70
71 static pimfor_header_t *
72 pimfor_decode_header(void *data, int len)
73 {
74 pimfor_header_t *h = data;
75
76 while ((void *) h < data + len) {
77 if (h->flags & PIMFOR_FLAG_LITTLE_ENDIAN) {
78 le32_to_cpus(&h->oid);
79 le32_to_cpus(&h->length);
80 } else {
81 be32_to_cpus(&h->oid);
82 be32_to_cpus(&h->length);
83 }
84 if (h->oid != OID_INL_TUNNEL)
85 return h;
86 h++;
87 }
88 return NULL;
89 }
90
91
92
93
94 int
95 islpci_mgmt_rx_fill(struct net_device *ndev)
96 {
97 islpci_private *priv = netdev_priv(ndev);
98 isl38xx_control_block *cb =
99 (isl38xx_control_block *) priv->control_block;
100 u32 curr = le32_to_cpu(cb->driver_curr_frag[ISL38XX_CB_RX_MGMTQ]);
101
102 #if VERBOSE > SHOW_ERROR_MESSAGES
103 DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgmt_rx_fill\n");
104 #endif
105
106 while (curr - priv->index_mgmt_rx < ISL38XX_CB_MGMT_QSIZE) {
107 u32 index = curr % ISL38XX_CB_MGMT_QSIZE;
108 struct islpci_membuf *buf = &priv->mgmt_rx[index];
109 isl38xx_fragment *frag = &cb->rx_data_mgmt[index];
110
111 if (buf->mem == NULL) {
112 buf->mem = kmalloc(MGMT_FRAME_SIZE, GFP_ATOMIC);
113 if (!buf->mem)
114 return -ENOMEM;
115 buf->size = MGMT_FRAME_SIZE;
116 }
117 if (buf->pci_addr == 0) {
118 buf->pci_addr = pci_map_single(priv->pdev, buf->mem,
119 MGMT_FRAME_SIZE,
120 PCI_DMA_FROMDEVICE);
121 if (pci_dma_mapping_error(priv->pdev, buf->pci_addr)) {
122 printk(KERN_WARNING
123 "Failed to make memory DMA'able.\n");
124 return -ENOMEM;
125 }
126 }
127
128
129 frag->size = cpu_to_le16(MGMT_FRAME_SIZE);
130 frag->flags = 0;
131 frag->address = cpu_to_le32(buf->pci_addr);
132 curr++;
133
134
135
136
137 wmb();
138 cb->driver_curr_frag[ISL38XX_CB_RX_MGMTQ] = cpu_to_le32(curr);
139 }
140 return 0;
141 }
142
143
144
145
146
147
148
149
150 static int
151 islpci_mgt_transmit(struct net_device *ndev, int operation, unsigned long oid,
152 void *data, int length)
153 {
154 islpci_private *priv = netdev_priv(ndev);
155 isl38xx_control_block *cb =
156 (isl38xx_control_block *) priv->control_block;
157 void *p;
158 int err = -EINVAL;
159 unsigned long flags;
160 isl38xx_fragment *frag;
161 struct islpci_membuf buf;
162 u32 curr_frag;
163 int index;
164 int frag_len = length + PIMFOR_HEADER_SIZE;
165
166 #if VERBOSE > SHOW_ERROR_MESSAGES
167 DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgt_transmit\n");
168 #endif
169
170 if (frag_len > MGMT_FRAME_SIZE) {
171 printk(KERN_DEBUG "%s: mgmt frame too large %d\n",
172 ndev->name, frag_len);
173 goto error;
174 }
175
176 err = -ENOMEM;
177 p = buf.mem = kmalloc(frag_len, GFP_KERNEL);
178 if (!buf.mem)
179 goto error;
180
181 buf.size = frag_len;
182
183
184 pimfor_encode_header(operation, oid, length, (pimfor_header_t *) p);
185 p += PIMFOR_HEADER_SIZE;
186
187 if (data)
188 memcpy(p, data, length);
189 else
190 memset(p, 0, length);
191
192 #if VERBOSE > SHOW_ERROR_MESSAGES
193 {
194 pimfor_header_t *h = buf.mem;
195 DEBUG(SHOW_PIMFOR_FRAMES,
196 "PIMFOR: op %i, oid 0x%08lx, device %i, flags 0x%x length 0x%x\n",
197 h->operation, oid, h->device_id, h->flags, length);
198
199
200 display_buffer((char *) h, sizeof (pimfor_header_t));
201 display_buffer(p, length);
202 }
203 #endif
204
205 err = -ENOMEM;
206 buf.pci_addr = pci_map_single(priv->pdev, buf.mem, frag_len,
207 PCI_DMA_TODEVICE);
208 if (pci_dma_mapping_error(priv->pdev, buf.pci_addr)) {
209 printk(KERN_WARNING "%s: cannot map PCI memory for mgmt\n",
210 ndev->name);
211 goto error_free;
212 }
213
214
215 spin_lock_irqsave(&priv->slock, flags);
216 curr_frag = le32_to_cpu(cb->driver_curr_frag[ISL38XX_CB_TX_MGMTQ]);
217 if (curr_frag - priv->index_mgmt_tx >= ISL38XX_CB_MGMT_QSIZE) {
218 printk(KERN_WARNING "%s: mgmt tx queue is still full\n",
219 ndev->name);
220 goto error_unlock;
221 }
222
223
224 index = curr_frag % ISL38XX_CB_MGMT_QSIZE;
225 priv->mgmt_tx[index] = buf;
226 frag = &cb->tx_data_mgmt[index];
227 frag->size = cpu_to_le16(frag_len);
228 frag->flags = 0;
229 frag->address = cpu_to_le32(buf.pci_addr);
230
231
232
233
234 wmb();
235 cb->driver_curr_frag[ISL38XX_CB_TX_MGMTQ] = cpu_to_le32(curr_frag + 1);
236 spin_unlock_irqrestore(&priv->slock, flags);
237
238
239 islpci_trigger(priv);
240 return 0;
241
242 error_unlock:
243 spin_unlock_irqrestore(&priv->slock, flags);
244 error_free:
245 kfree(buf.mem);
246 error:
247 return err;
248 }
249
250
251
252
253
254
255 int
256 islpci_mgt_receive(struct net_device *ndev)
257 {
258 islpci_private *priv = netdev_priv(ndev);
259 isl38xx_control_block *cb =
260 (isl38xx_control_block *) priv->control_block;
261 u32 curr_frag;
262
263 #if VERBOSE > SHOW_ERROR_MESSAGES
264 DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgt_receive\n");
265 #endif
266
267
268
269
270 curr_frag = le32_to_cpu(cb->device_curr_frag[ISL38XX_CB_RX_MGMTQ]);
271 barrier();
272
273 for (; priv->index_mgmt_rx < curr_frag; priv->index_mgmt_rx++) {
274 pimfor_header_t *header;
275 u32 index = priv->index_mgmt_rx % ISL38XX_CB_MGMT_QSIZE;
276 struct islpci_membuf *buf = &priv->mgmt_rx[index];
277 u16 frag_len;
278 int size;
279 struct islpci_mgmtframe *frame;
280
281
282
283 if (le16_to_cpu(cb->rx_data_mgmt[index].flags) != 0) {
284 printk(KERN_WARNING "%s: unknown flags 0x%04x\n",
285 ndev->name,
286 le16_to_cpu(cb->rx_data_mgmt[index].flags));
287 continue;
288 }
289
290
291 frag_len = le16_to_cpu(cb->rx_data_mgmt[index].size);
292
293
294
295
296
297 if (frag_len > MGMT_FRAME_SIZE) {
298 printk(KERN_WARNING
299 "%s: Bogus packet size of %d (%#x).\n",
300 ndev->name, frag_len, frag_len);
301 frag_len = MGMT_FRAME_SIZE;
302 }
303
304
305 pci_dma_sync_single_for_cpu(priv->pdev, buf->pci_addr,
306 buf->size, PCI_DMA_FROMDEVICE);
307
308
309 header = pimfor_decode_header(buf->mem, frag_len);
310 if (!header) {
311 printk(KERN_WARNING "%s: no PIMFOR header found\n",
312 ndev->name);
313 continue;
314 }
315
316
317
318
319 header->device_id = priv->ndev->ifindex;
320
321 #if VERBOSE > SHOW_ERROR_MESSAGES
322 DEBUG(SHOW_PIMFOR_FRAMES,
323 "PIMFOR: op %i, oid 0x%08x, device %i, flags 0x%x length 0x%x\n",
324 header->operation, header->oid, header->device_id,
325 header->flags, header->length);
326
327
328 display_buffer((char *) header, PIMFOR_HEADER_SIZE);
329 display_buffer((char *) header + PIMFOR_HEADER_SIZE,
330 header->length);
331 #endif
332
333
334 if (header->flags & PIMFOR_FLAG_APPLIC_ORIGIN) {
335 printk(KERN_DEBUG
336 "%s: errant PIMFOR application frame\n",
337 ndev->name);
338 continue;
339 }
340
341
342 size = PIMFOR_HEADER_SIZE + header->length;
343 frame = kmalloc(sizeof(struct islpci_mgmtframe) + size,
344 GFP_ATOMIC);
345 if (!frame)
346 continue;
347
348 frame->ndev = ndev;
349 memcpy(&frame->buf, header, size);
350 frame->header = (pimfor_header_t *) frame->buf;
351 frame->data = frame->buf + PIMFOR_HEADER_SIZE;
352
353 #if VERBOSE > SHOW_ERROR_MESSAGES
354 DEBUG(SHOW_PIMFOR_FRAMES,
355 "frame: header: %p, data: %p, size: %d\n",
356 frame->header, frame->data, size);
357 #endif
358
359 if (header->operation == PIMFOR_OP_TRAP) {
360 #if VERBOSE > SHOW_ERROR_MESSAGES
361 printk(KERN_DEBUG
362 "TRAP: oid 0x%x, device %i, flags 0x%x length %i\n",
363 header->oid, header->device_id, header->flags,
364 header->length);
365 #endif
366
367
368
369 INIT_WORK(&frame->ws, prism54_process_trap);
370 schedule_work(&frame->ws);
371
372 } else {
373
374
375 if ((frame = xchg(&priv->mgmt_received, frame)) != NULL) {
376 printk(KERN_WARNING
377 "%s: mgmt response not collected\n",
378 ndev->name);
379 kfree(frame);
380 }
381 #if VERBOSE > SHOW_ERROR_MESSAGES
382 DEBUG(SHOW_TRACING, "Wake up Mgmt Queue\n");
383 #endif
384 wake_up(&priv->mgmt_wqueue);
385 }
386
387 }
388
389 return 0;
390 }
391
392
393
394
395 void
396 islpci_mgt_cleanup_transmit(struct net_device *ndev)
397 {
398 islpci_private *priv = netdev_priv(ndev);
399 isl38xx_control_block *cb =
400 (isl38xx_control_block *) priv->control_block;
401 u32 curr_frag;
402
403 #if VERBOSE > SHOW_ERROR_MESSAGES
404 DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgt_cleanup_transmit\n");
405 #endif
406
407
408
409
410
411 curr_frag = le32_to_cpu(cb->device_curr_frag[ISL38XX_CB_TX_MGMTQ]);
412 barrier();
413
414 for (; priv->index_mgmt_tx < curr_frag; priv->index_mgmt_tx++) {
415 int index = priv->index_mgmt_tx % ISL38XX_CB_MGMT_QSIZE;
416 struct islpci_membuf *buf = &priv->mgmt_tx[index];
417 pci_unmap_single(priv->pdev, buf->pci_addr, buf->size,
418 PCI_DMA_TODEVICE);
419 buf->pci_addr = 0;
420 kfree(buf->mem);
421 buf->mem = NULL;
422 buf->size = 0;
423 }
424 }
425
426
427
428
429 int
430 islpci_mgt_transaction(struct net_device *ndev,
431 int operation, unsigned long oid,
432 void *senddata, int sendlen,
433 struct islpci_mgmtframe **recvframe)
434 {
435 islpci_private *priv = netdev_priv(ndev);
436 const long wait_cycle_jiffies = msecs_to_jiffies(ISL38XX_WAIT_CYCLE * 10);
437 long timeout_left = ISL38XX_MAX_WAIT_CYCLES * wait_cycle_jiffies;
438 int err;
439 DEFINE_WAIT(wait);
440
441 *recvframe = NULL;
442
443 if (mutex_lock_interruptible(&priv->mgmt_lock))
444 return -ERESTARTSYS;
445
446 prepare_to_wait(&priv->mgmt_wqueue, &wait, TASK_UNINTERRUPTIBLE);
447 err = islpci_mgt_transmit(ndev, operation, oid, senddata, sendlen);
448 if (err)
449 goto out;
450
451 err = -ETIMEDOUT;
452 while (timeout_left > 0) {
453 int timeleft;
454 struct islpci_mgmtframe *frame;
455
456 timeleft = schedule_timeout_uninterruptible(wait_cycle_jiffies);
457 frame = xchg(&priv->mgmt_received, NULL);
458 if (frame) {
459 if (frame->header->oid == oid) {
460 *recvframe = frame;
461 err = 0;
462 goto out;
463 } else {
464 printk(KERN_DEBUG
465 "%s: expecting oid 0x%x, received 0x%x.\n",
466 ndev->name, (unsigned int) oid,
467 frame->header->oid);
468 kfree(frame);
469 frame = NULL;
470 }
471 }
472 if (timeleft == 0) {
473 printk(KERN_DEBUG
474 "%s: timeout waiting for mgmt response %lu, "
475 "triggering device\n",
476 ndev->name, timeout_left);
477 islpci_trigger(priv);
478 }
479 timeout_left += timeleft - wait_cycle_jiffies;
480 }
481 printk(KERN_WARNING "%s: timeout waiting for mgmt response\n",
482 ndev->name);
483
484
485 out:
486 finish_wait(&priv->mgmt_wqueue, &wait);
487 mutex_unlock(&priv->mgmt_lock);
488 return err;
489 }
490