diff options
-rw-r--r-- | drivers/net/wimax/i2400m/control.c | 100 | ||||
-rw-r--r-- | drivers/net/wimax/i2400m/driver.c | 5 | ||||
-rw-r--r-- | drivers/net/wimax/i2400m/i2400m.h | 5 | ||||
-rw-r--r-- | drivers/net/wimax/i2400m/netdev.c | 4 | ||||
-rw-r--r-- | drivers/net/wimax/i2400m/rx.c | 6 | ||||
-rw-r--r-- | drivers/net/wimax/i2400m/sdio.c | 18 | ||||
-rw-r--r-- | drivers/net/wimax/i2400m/usb.c | 35 | ||||
-rw-r--r-- | include/linux/wimax.h | 7 | ||||
-rw-r--r-- | net/wimax/Makefile | 1 | ||||
-rw-r--r-- | net/wimax/debug-levels.h | 1 | ||||
-rw-r--r-- | net/wimax/debugfs.c | 1 | ||||
-rw-r--r-- | net/wimax/op-msg.c | 17 | ||||
-rw-r--r-- | net/wimax/op-state-get.c | 86 | ||||
-rw-r--r-- | net/wimax/stack.c | 5 |
14 files changed, 222 insertions, 69 deletions
diff --git a/drivers/net/wimax/i2400m/control.c b/drivers/net/wimax/i2400m/control.c index b3cadb626fe..bd193ae2178 100644 --- a/drivers/net/wimax/i2400m/control.c +++ b/drivers/net/wimax/i2400m/control.c | |||
@@ -292,8 +292,6 @@ void i2400m_report_tlv_system_state(struct i2400m *i2400m, | |||
292 | 292 | ||
293 | d_fnstart(3, dev, "(i2400m %p ss %p [%u])\n", i2400m, ss, i2400m_state); | 293 | d_fnstart(3, dev, "(i2400m %p ss %p [%u])\n", i2400m, ss, i2400m_state); |
294 | 294 | ||
295 | if (unlikely(i2400m->ready == 0)) /* act if up */ | ||
296 | goto out; | ||
297 | if (i2400m->state != i2400m_state) { | 295 | if (i2400m->state != i2400m_state) { |
298 | i2400m->state = i2400m_state; | 296 | i2400m->state = i2400m_state; |
299 | wake_up_all(&i2400m->state_wq); | 297 | wake_up_all(&i2400m->state_wq); |
@@ -341,7 +339,6 @@ void i2400m_report_tlv_system_state(struct i2400m *i2400m, | |||
341 | i2400m->bus_reset(i2400m, I2400M_RT_WARM); | 339 | i2400m->bus_reset(i2400m, I2400M_RT_WARM); |
342 | break; | 340 | break; |
343 | }; | 341 | }; |
344 | out: | ||
345 | d_fnend(3, dev, "(i2400m %p ss %p [%u]) = void\n", | 342 | d_fnend(3, dev, "(i2400m %p ss %p [%u]) = void\n", |
346 | i2400m, ss, i2400m_state); | 343 | i2400m, ss, i2400m_state); |
347 | } | 344 | } |
@@ -372,8 +369,6 @@ void i2400m_report_tlv_media_status(struct i2400m *i2400m, | |||
372 | 369 | ||
373 | d_fnstart(3, dev, "(i2400m %p ms %p [%u])\n", i2400m, ms, status); | 370 | d_fnstart(3, dev, "(i2400m %p ms %p [%u])\n", i2400m, ms, status); |
374 | 371 | ||
375 | if (unlikely(i2400m->ready == 0)) /* act if up */ | ||
376 | goto out; | ||
377 | switch (status) { | 372 | switch (status) { |
378 | case I2400M_MEDIA_STATUS_LINK_UP: | 373 | case I2400M_MEDIA_STATUS_LINK_UP: |
379 | netif_carrier_on(net_dev); | 374 | netif_carrier_on(net_dev); |
@@ -393,14 +388,59 @@ void i2400m_report_tlv_media_status(struct i2400m *i2400m, | |||
393 | dev_err(dev, "HW BUG? unknown media status %u\n", | 388 | dev_err(dev, "HW BUG? unknown media status %u\n", |
394 | status); | 389 | status); |
395 | }; | 390 | }; |
396 | out: | ||
397 | d_fnend(3, dev, "(i2400m %p ms %p [%u]) = void\n", | 391 | d_fnend(3, dev, "(i2400m %p ms %p [%u]) = void\n", |
398 | i2400m, ms, status); | 392 | i2400m, ms, status); |
399 | } | 393 | } |
400 | 394 | ||
401 | 395 | ||
402 | /* | 396 | /* |
403 | * Parse a 'state report' and extract carrier on/off information | 397 | * Process a TLV from a 'state report' |
398 | * | ||
399 | * @i2400m: device descriptor | ||
400 | * @tlv: pointer to the TLV header; it has been already validated for | ||
401 | * consistent size. | ||
402 | * @tag: for error messages | ||
403 | * | ||
404 | * Act on the TLVs from a 'state report'. | ||
405 | */ | ||
406 | static | ||
407 | void i2400m_report_state_parse_tlv(struct i2400m *i2400m, | ||
408 | const struct i2400m_tlv_hdr *tlv, | ||
409 | const char *tag) | ||
410 | { | ||
411 | struct device *dev = i2400m_dev(i2400m); | ||
412 | const struct i2400m_tlv_media_status *ms; | ||
413 | const struct i2400m_tlv_system_state *ss; | ||
414 | const struct i2400m_tlv_rf_switches_status *rfss; | ||
415 | |||
416 | if (0 == i2400m_tlv_match(tlv, I2400M_TLV_SYSTEM_STATE, sizeof(*ss))) { | ||
417 | ss = container_of(tlv, typeof(*ss), hdr); | ||
418 | d_printf(2, dev, "%s: system state TLV " | ||
419 | "found (0x%04x), state 0x%08x\n", | ||
420 | tag, I2400M_TLV_SYSTEM_STATE, | ||
421 | le32_to_cpu(ss->state)); | ||
422 | i2400m_report_tlv_system_state(i2400m, ss); | ||
423 | } | ||
424 | if (0 == i2400m_tlv_match(tlv, I2400M_TLV_RF_STATUS, sizeof(*rfss))) { | ||
425 | rfss = container_of(tlv, typeof(*rfss), hdr); | ||
426 | d_printf(2, dev, "%s: RF status TLV " | ||
427 | "found (0x%04x), sw 0x%02x hw 0x%02x\n", | ||
428 | tag, I2400M_TLV_RF_STATUS, | ||
429 | le32_to_cpu(rfss->sw_rf_switch), | ||
430 | le32_to_cpu(rfss->hw_rf_switch)); | ||
431 | i2400m_report_tlv_rf_switches_status(i2400m, rfss); | ||
432 | } | ||
433 | if (0 == i2400m_tlv_match(tlv, I2400M_TLV_MEDIA_STATUS, sizeof(*ms))) { | ||
434 | ms = container_of(tlv, typeof(*ms), hdr); | ||
435 | d_printf(2, dev, "%s: Media Status TLV: %u\n", | ||
436 | tag, le32_to_cpu(ms->media_status)); | ||
437 | i2400m_report_tlv_media_status(i2400m, ms); | ||
438 | } | ||
439 | } | ||
440 | |||
441 | |||
442 | /* | ||
443 | * Parse a 'state report' and extract information | ||
404 | * | 444 | * |
405 | * @i2400m: device descriptor | 445 | * @i2400m: device descriptor |
406 | * @l3l4_hdr: pointer to message; it has been already validated for | 446 | * @l3l4_hdr: pointer to message; it has been already validated for |
@@ -409,13 +449,7 @@ out: | |||
409 | * declaration is assumed to be congruent with @size (as in | 449 | * declaration is assumed to be congruent with @size (as in |
410 | * sizeof(*l3l4_hdr) + l3l4_hdr->length == size) | 450 | * sizeof(*l3l4_hdr) + l3l4_hdr->length == size) |
411 | * | 451 | * |
412 | * Extract from the report state the system state TLV and infer from | 452 | * Walk over the TLVs in a report state and act on them. |
413 | * there if we have a carrier or not. Update our local state and tell | ||
414 | * netdev. | ||
415 | * | ||
416 | * When setting the carrier, it's fine to set OFF twice (for example), | ||
417 | * as netif_carrier_off() will not generate two OFF events (just on | ||
418 | * the transitions). | ||
419 | */ | 453 | */ |
420 | static | 454 | static |
421 | void i2400m_report_state_hook(struct i2400m *i2400m, | 455 | void i2400m_report_state_hook(struct i2400m *i2400m, |
@@ -424,9 +458,6 @@ void i2400m_report_state_hook(struct i2400m *i2400m, | |||
424 | { | 458 | { |
425 | struct device *dev = i2400m_dev(i2400m); | 459 | struct device *dev = i2400m_dev(i2400m); |
426 | const struct i2400m_tlv_hdr *tlv; | 460 | const struct i2400m_tlv_hdr *tlv; |
427 | const struct i2400m_tlv_system_state *ss; | ||
428 | const struct i2400m_tlv_rf_switches_status *rfss; | ||
429 | const struct i2400m_tlv_media_status *ms; | ||
430 | size_t tlv_size = le16_to_cpu(l3l4_hdr->length); | 461 | size_t tlv_size = le16_to_cpu(l3l4_hdr->length); |
431 | 462 | ||
432 | d_fnstart(4, dev, "(i2400m %p, l3l4_hdr %p, size %zu, %s)\n", | 463 | d_fnstart(4, dev, "(i2400m %p, l3l4_hdr %p, size %zu, %s)\n", |
@@ -434,34 +465,8 @@ void i2400m_report_state_hook(struct i2400m *i2400m, | |||
434 | tlv = NULL; | 465 | tlv = NULL; |
435 | 466 | ||
436 | while ((tlv = i2400m_tlv_buffer_walk(i2400m, &l3l4_hdr->pl, | 467 | while ((tlv = i2400m_tlv_buffer_walk(i2400m, &l3l4_hdr->pl, |
437 | tlv_size, tlv))) { | 468 | tlv_size, tlv))) |
438 | if (0 == i2400m_tlv_match(tlv, I2400M_TLV_SYSTEM_STATE, | 469 | i2400m_report_state_parse_tlv(i2400m, tlv, tag); |
439 | sizeof(*ss))) { | ||
440 | ss = container_of(tlv, typeof(*ss), hdr); | ||
441 | d_printf(2, dev, "%s: system state TLV " | ||
442 | "found (0x%04x), state 0x%08x\n", | ||
443 | tag, I2400M_TLV_SYSTEM_STATE, | ||
444 | le32_to_cpu(ss->state)); | ||
445 | i2400m_report_tlv_system_state(i2400m, ss); | ||
446 | } | ||
447 | if (0 == i2400m_tlv_match(tlv, I2400M_TLV_RF_STATUS, | ||
448 | sizeof(*rfss))) { | ||
449 | rfss = container_of(tlv, typeof(*rfss), hdr); | ||
450 | d_printf(2, dev, "%s: RF status TLV " | ||
451 | "found (0x%04x), sw 0x%02x hw 0x%02x\n", | ||
452 | tag, I2400M_TLV_RF_STATUS, | ||
453 | le32_to_cpu(rfss->sw_rf_switch), | ||
454 | le32_to_cpu(rfss->hw_rf_switch)); | ||
455 | i2400m_report_tlv_rf_switches_status(i2400m, rfss); | ||
456 | } | ||
457 | if (0 == i2400m_tlv_match(tlv, I2400M_TLV_MEDIA_STATUS, | ||
458 | sizeof(*ms))) { | ||
459 | ms = container_of(tlv, typeof(*ms), hdr); | ||
460 | d_printf(2, dev, "%s: Media Status TLV: %u\n", | ||
461 | tag, le32_to_cpu(ms->media_status)); | ||
462 | i2400m_report_tlv_media_status(i2400m, ms); | ||
463 | } | ||
464 | } | ||
465 | d_fnend(4, dev, "(i2400m %p, l3l4_hdr %p, size %zu, %s) = void\n", | 470 | d_fnend(4, dev, "(i2400m %p, l3l4_hdr %p, size %zu, %s) = void\n", |
466 | i2400m, l3l4_hdr, size, tag); | 471 | i2400m, l3l4_hdr, size, tag); |
467 | } | 472 | } |
@@ -721,6 +726,8 @@ struct sk_buff *i2400m_msg_to_dev(struct i2400m *i2400m, | |||
721 | ack_timeout = HZ; | 726 | ack_timeout = HZ; |
722 | }; | 727 | }; |
723 | 728 | ||
729 | if (unlikely(i2400m->trace_msg_from_user)) | ||
730 | wimax_msg(&i2400m->wimax_dev, "echo", buf, buf_len, GFP_KERNEL); | ||
724 | /* The RX path in rx.c will put any response for this message | 731 | /* The RX path in rx.c will put any response for this message |
725 | * in i2400m->ack_skb and wake us up. If we cancel the wait, | 732 | * in i2400m->ack_skb and wake us up. If we cancel the wait, |
726 | * we need to change the value of i2400m->ack_skb to something | 733 | * we need to change the value of i2400m->ack_skb to something |
@@ -755,6 +762,9 @@ struct sk_buff *i2400m_msg_to_dev(struct i2400m *i2400m, | |||
755 | ack_l3l4_hdr = wimax_msg_data_len(ack_skb, &ack_len); | 762 | ack_l3l4_hdr = wimax_msg_data_len(ack_skb, &ack_len); |
756 | 763 | ||
757 | /* Check the ack and deliver it if it is ok */ | 764 | /* Check the ack and deliver it if it is ok */ |
765 | if (unlikely(i2400m->trace_msg_from_user)) | ||
766 | wimax_msg(&i2400m->wimax_dev, "echo", | ||
767 | ack_l3l4_hdr, ack_len, GFP_KERNEL); | ||
758 | result = i2400m_msg_size_check(i2400m, ack_l3l4_hdr, ack_len); | 768 | result = i2400m_msg_size_check(i2400m, ack_l3l4_hdr, ack_len); |
759 | if (result < 0) { | 769 | if (result < 0) { |
760 | dev_err(dev, "HW BUG? reply to message 0x%04x: %d\n", | 770 | dev_err(dev, "HW BUG? reply to message 0x%04x: %d\n", |
diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c index 07a54bad237..ef16c573bb2 100644 --- a/drivers/net/wimax/i2400m/driver.c +++ b/drivers/net/wimax/i2400m/driver.c | |||
@@ -62,6 +62,7 @@ | |||
62 | * unregister_netdev() | 62 | * unregister_netdev() |
63 | */ | 63 | */ |
64 | #include "i2400m.h" | 64 | #include "i2400m.h" |
65 | #include <linux/etherdevice.h> | ||
65 | #include <linux/wimax/i2400m.h> | 66 | #include <linux/wimax/i2400m.h> |
66 | #include <linux/module.h> | 67 | #include <linux/module.h> |
67 | #include <linux/moduleparam.h> | 68 | #include <linux/moduleparam.h> |
@@ -234,9 +235,6 @@ int i2400m_op_msg_from_user(struct wimax_dev *wimax_dev, | |||
234 | result = PTR_ERR(ack_skb); | 235 | result = PTR_ERR(ack_skb); |
235 | if (IS_ERR(ack_skb)) | 236 | if (IS_ERR(ack_skb)) |
236 | goto error_msg_to_dev; | 237 | goto error_msg_to_dev; |
237 | if (unlikely(i2400m->trace_msg_from_user)) | ||
238 | wimax_msg(&i2400m->wimax_dev, "trace", | ||
239 | msg_buf, msg_len, GFP_KERNEL); | ||
240 | result = wimax_msg_send(&i2400m->wimax_dev, ack_skb); | 238 | result = wimax_msg_send(&i2400m->wimax_dev, ack_skb); |
241 | error_msg_to_dev: | 239 | error_msg_to_dev: |
242 | d_fnend(4, dev, "(wimax_dev %p [i2400m %p] msg_buf %p msg_len %zu " | 240 | d_fnend(4, dev, "(wimax_dev %p [i2400m %p] msg_buf %p msg_len %zu " |
@@ -650,6 +648,7 @@ int i2400m_setup(struct i2400m *i2400m, enum i2400m_bri bm_flags) | |||
650 | result = i2400m_read_mac_addr(i2400m); | 648 | result = i2400m_read_mac_addr(i2400m); |
651 | if (result < 0) | 649 | if (result < 0) |
652 | goto error_read_mac_addr; | 650 | goto error_read_mac_addr; |
651 | random_ether_addr(i2400m->src_mac_addr); | ||
653 | 652 | ||
654 | result = register_netdev(net_dev); /* Okey dokey, bring it up */ | 653 | result = register_netdev(net_dev); /* Okey dokey, bring it up */ |
655 | if (result < 0) { | 654 | if (result < 0) { |
diff --git a/drivers/net/wimax/i2400m/i2400m.h b/drivers/net/wimax/i2400m/i2400m.h index 3ae2df38b59..434ba310c2f 100644 --- a/drivers/net/wimax/i2400m/i2400m.h +++ b/drivers/net/wimax/i2400m/i2400m.h | |||
@@ -323,6 +323,10 @@ struct i2400m_roq; | |||
323 | * delivered. Then the driver can release them to the host. See | 323 | * delivered. Then the driver can release them to the host. See |
324 | * drivers/net/i2400m/rx.c for details. | 324 | * drivers/net/i2400m/rx.c for details. |
325 | * | 325 | * |
326 | * @src_mac_addr: MAC address used to make ethernet packets be coming | ||
327 | * from. This is generated at i2400m_setup() time and used during | ||
328 | * the life cycle of the instance. See i2400m_fake_eth_header(). | ||
329 | * | ||
326 | * @init_mutex: Mutex used for serializing the device bringup | 330 | * @init_mutex: Mutex used for serializing the device bringup |
327 | * sequence; this way if the device reboots in the middle, we | 331 | * sequence; this way if the device reboots in the middle, we |
328 | * don't try to do a bringup again while we are tearing down the | 332 | * don't try to do a bringup again while we are tearing down the |
@@ -421,6 +425,7 @@ struct i2400m { | |||
421 | unsigned rx_pl_num, rx_pl_max, rx_pl_min, | 425 | unsigned rx_pl_num, rx_pl_max, rx_pl_min, |
422 | rx_num, rx_size_acc, rx_size_min, rx_size_max; | 426 | rx_num, rx_size_acc, rx_size_min, rx_size_max; |
423 | struct i2400m_roq *rx_roq; /* not under rx_lock! */ | 427 | struct i2400m_roq *rx_roq; /* not under rx_lock! */ |
428 | u8 src_mac_addr[ETH_HLEN]; | ||
424 | 429 | ||
425 | struct mutex msg_mutex; /* serialize command execution */ | 430 | struct mutex msg_mutex; /* serialize command execution */ |
426 | struct completion msg_completion; | 431 | struct completion msg_completion; |
diff --git a/drivers/net/wimax/i2400m/netdev.c b/drivers/net/wimax/i2400m/netdev.c index 6b1fe7a81f2..9653f478b38 100644 --- a/drivers/net/wimax/i2400m/netdev.c +++ b/drivers/net/wimax/i2400m/netdev.c | |||
@@ -404,10 +404,12 @@ static | |||
404 | void i2400m_rx_fake_eth_header(struct net_device *net_dev, | 404 | void i2400m_rx_fake_eth_header(struct net_device *net_dev, |
405 | void *_eth_hdr, __be16 protocol) | 405 | void *_eth_hdr, __be16 protocol) |
406 | { | 406 | { |
407 | struct i2400m *i2400m = net_dev_to_i2400m(net_dev); | ||
407 | struct ethhdr *eth_hdr = _eth_hdr; | 408 | struct ethhdr *eth_hdr = _eth_hdr; |
408 | 409 | ||
409 | memcpy(eth_hdr->h_dest, net_dev->dev_addr, sizeof(eth_hdr->h_dest)); | 410 | memcpy(eth_hdr->h_dest, net_dev->dev_addr, sizeof(eth_hdr->h_dest)); |
410 | memset(eth_hdr->h_source, 0, sizeof(eth_hdr->h_dest)); | 411 | memcpy(eth_hdr->h_source, i2400m->src_mac_addr, |
412 | sizeof(eth_hdr->h_source)); | ||
411 | eth_hdr->h_proto = protocol; | 413 | eth_hdr->h_proto = protocol; |
412 | } | 414 | } |
413 | 415 | ||
diff --git a/drivers/net/wimax/i2400m/rx.c b/drivers/net/wimax/i2400m/rx.c index f9fc3890232..7643850a6fb 100644 --- a/drivers/net/wimax/i2400m/rx.c +++ b/drivers/net/wimax/i2400m/rx.c | |||
@@ -177,7 +177,8 @@ void i2400m_report_hook_work(struct work_struct *ws) | |||
177 | struct i2400m_work *iw = | 177 | struct i2400m_work *iw = |
178 | container_of(ws, struct i2400m_work, ws); | 178 | container_of(ws, struct i2400m_work, ws); |
179 | struct i2400m_report_hook_args *args = (void *) iw->pl; | 179 | struct i2400m_report_hook_args *args = (void *) iw->pl; |
180 | i2400m_report_hook(iw->i2400m, args->l3l4_hdr, args->size); | 180 | if (iw->i2400m->ready) |
181 | i2400m_report_hook(iw->i2400m, args->l3l4_hdr, args->size); | ||
181 | kfree_skb(args->skb_rx); | 182 | kfree_skb(args->skb_rx); |
182 | i2400m_put(iw->i2400m); | 183 | i2400m_put(iw->i2400m); |
183 | kfree(iw); | 184 | kfree(iw); |
@@ -309,6 +310,9 @@ void i2400m_rx_ctl(struct i2400m *i2400m, struct sk_buff *skb_rx, | |||
309 | skb_get(skb_rx); | 310 | skb_get(skb_rx); |
310 | i2400m_queue_work(i2400m, i2400m_report_hook_work, | 311 | i2400m_queue_work(i2400m, i2400m_report_hook_work, |
311 | GFP_KERNEL, &args, sizeof(args)); | 312 | GFP_KERNEL, &args, sizeof(args)); |
313 | if (unlikely(i2400m->trace_msg_from_user)) | ||
314 | wimax_msg(&i2400m->wimax_dev, "echo", | ||
315 | l3l4_hdr, size, GFP_KERNEL); | ||
312 | result = wimax_msg(&i2400m->wimax_dev, NULL, l3l4_hdr, size, | 316 | result = wimax_msg(&i2400m->wimax_dev, NULL, l3l4_hdr, size, |
313 | GFP_KERNEL); | 317 | GFP_KERNEL); |
314 | if (result < 0) | 318 | if (result < 0) |
diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c index 5ac5e76701c..777c981676f 100644 --- a/drivers/net/wimax/i2400m/sdio.c +++ b/drivers/net/wimax/i2400m/sdio.c | |||
@@ -409,19 +409,19 @@ int i2400ms_probe(struct sdio_func *func, | |||
409 | i2400m->bus_fw_names = i2400ms_bus_fw_names; | 409 | i2400m->bus_fw_names = i2400ms_bus_fw_names; |
410 | i2400m->bus_bm_mac_addr_impaired = 1; | 410 | i2400m->bus_bm_mac_addr_impaired = 1; |
411 | 411 | ||
412 | result = i2400ms_enable_function(i2400ms->func); | ||
413 | if (result < 0) { | ||
414 | dev_err(dev, "Cannot enable SDIO function: %d\n", result); | ||
415 | goto error_func_enable; | ||
416 | } | ||
417 | |||
418 | sdio_claim_host(func); | 412 | sdio_claim_host(func); |
419 | result = sdio_set_block_size(func, I2400MS_BLK_SIZE); | 413 | result = sdio_set_block_size(func, I2400MS_BLK_SIZE); |
414 | sdio_release_host(func); | ||
420 | if (result < 0) { | 415 | if (result < 0) { |
421 | dev_err(dev, "Failed to set block size: %d\n", result); | 416 | dev_err(dev, "Failed to set block size: %d\n", result); |
422 | goto error_set_blk_size; | 417 | goto error_set_blk_size; |
423 | } | 418 | } |
424 | sdio_release_host(func); | 419 | |
420 | result = i2400ms_enable_function(i2400ms->func); | ||
421 | if (result < 0) { | ||
422 | dev_err(dev, "Cannot enable SDIO function: %d\n", result); | ||
423 | goto error_func_enable; | ||
424 | } | ||
425 | 425 | ||
426 | result = i2400m_setup(i2400m, I2400M_BRI_NO_REBOOT); | 426 | result = i2400m_setup(i2400m, I2400M_BRI_NO_REBOOT); |
427 | if (result < 0) { | 427 | if (result < 0) { |
@@ -440,12 +440,12 @@ int i2400ms_probe(struct sdio_func *func, | |||
440 | error_debugfs_add: | 440 | error_debugfs_add: |
441 | i2400m_release(i2400m); | 441 | i2400m_release(i2400m); |
442 | error_setup: | 442 | error_setup: |
443 | sdio_set_drvdata(func, NULL); | ||
444 | sdio_claim_host(func); | 443 | sdio_claim_host(func); |
445 | error_set_blk_size: | ||
446 | sdio_disable_func(func); | 444 | sdio_disable_func(func); |
447 | sdio_release_host(func); | 445 | sdio_release_host(func); |
448 | error_func_enable: | 446 | error_func_enable: |
447 | error_set_blk_size: | ||
448 | sdio_set_drvdata(func, NULL); | ||
449 | free_netdev(net_dev); | 449 | free_netdev(net_dev); |
450 | error_alloc_netdev: | 450 | error_alloc_netdev: |
451 | return result; | 451 | return result; |
diff --git a/drivers/net/wimax/i2400m/usb.c b/drivers/net/wimax/i2400m/usb.c index ca4151a9e22..17851321b7f 100644 --- a/drivers/net/wimax/i2400m/usb.c +++ b/drivers/net/wimax/i2400m/usb.c | |||
@@ -505,27 +505,52 @@ int i2400mu_suspend(struct usb_interface *iface, pm_message_t pm_msg) | |||
505 | #ifdef CONFIG_PM | 505 | #ifdef CONFIG_PM |
506 | struct usb_device *usb_dev = i2400mu->usb_dev; | 506 | struct usb_device *usb_dev = i2400mu->usb_dev; |
507 | #endif | 507 | #endif |
508 | unsigned is_autosuspend = 0; | ||
508 | struct i2400m *i2400m = &i2400mu->i2400m; | 509 | struct i2400m *i2400m = &i2400mu->i2400m; |
509 | 510 | ||
511 | #ifdef CONFIG_PM | ||
512 | if (usb_dev->auto_pm > 0) | ||
513 | is_autosuspend = 1; | ||
514 | #endif | ||
515 | |||
510 | d_fnstart(3, dev, "(iface %p pm_msg %u)\n", iface, pm_msg.event); | 516 | d_fnstart(3, dev, "(iface %p pm_msg %u)\n", iface, pm_msg.event); |
511 | if (i2400m->updown == 0) | 517 | if (i2400m->updown == 0) |
512 | goto no_firmware; | 518 | goto no_firmware; |
513 | d_printf(1, dev, "fw up, requesting standby\n"); | 519 | if (i2400m->state == I2400M_SS_DATA_PATH_CONNECTED && is_autosuspend) { |
520 | /* ugh -- the device is connected and this suspend | ||
521 | * request is an autosuspend one (not a system standby | ||
522 | * / hibernate). | ||
523 | * | ||
524 | * The only way the device can go to standby is if the | ||
525 | * link with the base station is in IDLE mode; that | ||
526 | * were the case, we'd be in status | ||
527 | * I2400M_SS_CONNECTED_IDLE. But we are not. | ||
528 | * | ||
529 | * If we *tell* him to go power save now, it'll reset | ||
530 | * as a precautionary measure, so if this is an | ||
531 | * autosuspend thing, say no and it'll come back | ||
532 | * later, when the link is IDLE | ||
533 | */ | ||
534 | result = -EBADF; | ||
535 | d_printf(1, dev, "fw up, link up, not-idle, autosuspend: " | ||
536 | "not entering powersave\n"); | ||
537 | goto error_not_now; | ||
538 | } | ||
539 | d_printf(1, dev, "fw up: entering powersave\n"); | ||
514 | atomic_dec(&i2400mu->do_autopm); | 540 | atomic_dec(&i2400mu->do_autopm); |
515 | result = i2400m_cmd_enter_powersave(i2400m); | 541 | result = i2400m_cmd_enter_powersave(i2400m); |
516 | atomic_inc(&i2400mu->do_autopm); | 542 | atomic_inc(&i2400mu->do_autopm); |
517 | #ifdef CONFIG_PM | 543 | if (result < 0 && !is_autosuspend) { |
518 | if (result < 0 && usb_dev->auto_pm == 0) { | ||
519 | /* System suspend, can't fail */ | 544 | /* System suspend, can't fail */ |
520 | dev_err(dev, "failed to suspend, will reset on resume\n"); | 545 | dev_err(dev, "failed to suspend, will reset on resume\n"); |
521 | result = 0; | 546 | result = 0; |
522 | } | 547 | } |
523 | #endif | ||
524 | if (result < 0) | 548 | if (result < 0) |
525 | goto error_enter_powersave; | 549 | goto error_enter_powersave; |
526 | i2400mu_notification_release(i2400mu); | 550 | i2400mu_notification_release(i2400mu); |
527 | d_printf(1, dev, "fw up, got standby\n"); | 551 | d_printf(1, dev, "powersave requested\n"); |
528 | error_enter_powersave: | 552 | error_enter_powersave: |
553 | error_not_now: | ||
529 | no_firmware: | 554 | no_firmware: |
530 | d_fnend(3, dev, "(iface %p pm_msg %u) = %d\n", | 555 | d_fnend(3, dev, "(iface %p pm_msg %u) = %d\n", |
531 | iface, pm_msg.event, result); | 556 | iface, pm_msg.event, result); |
diff --git a/include/linux/wimax.h b/include/linux/wimax.h index c89de7f4e5b..4fdcc563551 100644 --- a/include/linux/wimax.h +++ b/include/linux/wimax.h | |||
@@ -59,7 +59,7 @@ enum { | |||
59 | * M - Major: change if removing or modifying an existing call. | 59 | * M - Major: change if removing or modifying an existing call. |
60 | * m - minor: change when adding a new call | 60 | * m - minor: change when adding a new call |
61 | */ | 61 | */ |
62 | WIMAX_GNL_VERSION = 00, | 62 | WIMAX_GNL_VERSION = 01, |
63 | /* Generic NetLink attributes */ | 63 | /* Generic NetLink attributes */ |
64 | WIMAX_GNL_ATTR_INVALID = 0x00, | 64 | WIMAX_GNL_ATTR_INVALID = 0x00, |
65 | WIMAX_GNL_ATTR_MAX = 10, | 65 | WIMAX_GNL_ATTR_MAX = 10, |
@@ -78,6 +78,7 @@ enum { | |||
78 | WIMAX_GNL_OP_RFKILL, /* Run wimax_rfkill() */ | 78 | WIMAX_GNL_OP_RFKILL, /* Run wimax_rfkill() */ |
79 | WIMAX_GNL_OP_RESET, /* Run wimax_rfkill() */ | 79 | WIMAX_GNL_OP_RESET, /* Run wimax_rfkill() */ |
80 | WIMAX_GNL_RE_STATE_CHANGE, /* Report: status change */ | 80 | WIMAX_GNL_RE_STATE_CHANGE, /* Report: status change */ |
81 | WIMAX_GNL_OP_STATE_GET, /* Request for current state */ | ||
81 | }; | 82 | }; |
82 | 83 | ||
83 | 84 | ||
@@ -113,6 +114,10 @@ enum { | |||
113 | WIMAX_GNL_RESET_IFIDX = 1, | 114 | WIMAX_GNL_RESET_IFIDX = 1, |
114 | }; | 115 | }; |
115 | 116 | ||
117 | /* Atributes for wimax_state_get() */ | ||
118 | enum { | ||
119 | WIMAX_GNL_STGET_IFIDX = 1, | ||
120 | }; | ||
116 | 121 | ||
117 | /* | 122 | /* |
118 | * Attributes for the Report State Change | 123 | * Attributes for the Report State Change |
diff --git a/net/wimax/Makefile b/net/wimax/Makefile index 5b80b941c2c..8f1510d0cc2 100644 --- a/net/wimax/Makefile +++ b/net/wimax/Makefile | |||
@@ -6,6 +6,7 @@ wimax-y := \ | |||
6 | op-msg.o \ | 6 | op-msg.o \ |
7 | op-reset.o \ | 7 | op-reset.o \ |
8 | op-rfkill.o \ | 8 | op-rfkill.o \ |
9 | op-state-get.o \ | ||
9 | stack.o | 10 | stack.o |
10 | 11 | ||
11 | wimax-$(CONFIG_DEBUG_FS) += debugfs.o | 12 | wimax-$(CONFIG_DEBUG_FS) += debugfs.o |
diff --git a/net/wimax/debug-levels.h b/net/wimax/debug-levels.h index 1c29123a3aa..0975adba6b7 100644 --- a/net/wimax/debug-levels.h +++ b/net/wimax/debug-levels.h | |||
@@ -36,6 +36,7 @@ enum d_module { | |||
36 | D_SUBMODULE_DECLARE(op_msg), | 36 | D_SUBMODULE_DECLARE(op_msg), |
37 | D_SUBMODULE_DECLARE(op_reset), | 37 | D_SUBMODULE_DECLARE(op_reset), |
38 | D_SUBMODULE_DECLARE(op_rfkill), | 38 | D_SUBMODULE_DECLARE(op_rfkill), |
39 | D_SUBMODULE_DECLARE(op_state_get), | ||
39 | D_SUBMODULE_DECLARE(stack), | 40 | D_SUBMODULE_DECLARE(stack), |
40 | }; | 41 | }; |
41 | 42 | ||
diff --git a/net/wimax/debugfs.c b/net/wimax/debugfs.c index 94d216a4640..6c9bedb7431 100644 --- a/net/wimax/debugfs.c +++ b/net/wimax/debugfs.c | |||
@@ -61,6 +61,7 @@ int wimax_debugfs_add(struct wimax_dev *wimax_dev) | |||
61 | __debugfs_register("wimax_dl_", op_msg, dentry); | 61 | __debugfs_register("wimax_dl_", op_msg, dentry); |
62 | __debugfs_register("wimax_dl_", op_reset, dentry); | 62 | __debugfs_register("wimax_dl_", op_reset, dentry); |
63 | __debugfs_register("wimax_dl_", op_rfkill, dentry); | 63 | __debugfs_register("wimax_dl_", op_rfkill, dentry); |
64 | __debugfs_register("wimax_dl_", op_state_get, dentry); | ||
64 | __debugfs_register("wimax_dl_", stack, dentry); | 65 | __debugfs_register("wimax_dl_", stack, dentry); |
65 | result = 0; | 66 | result = 0; |
66 | out: | 67 | out: |
diff --git a/net/wimax/op-msg.c b/net/wimax/op-msg.c index 9ad4d893a56..d631a17186b 100644 --- a/net/wimax/op-msg.c +++ b/net/wimax/op-msg.c | |||
@@ -108,6 +108,12 @@ | |||
108 | * Don't use skb_push()/skb_pull()/skb_reserve() on the skb, as | 108 | * Don't use skb_push()/skb_pull()/skb_reserve() on the skb, as |
109 | * wimax_msg_send() depends on skb->data being placed at the | 109 | * wimax_msg_send() depends on skb->data being placed at the |
110 | * beginning of the user message. | 110 | * beginning of the user message. |
111 | * | ||
112 | * Unlike other WiMAX stack calls, this call can be used way early, | ||
113 | * even before wimax_dev_add() is called, as long as the | ||
114 | * wimax_dev->net_dev pointer is set to point to a proper | ||
115 | * net_dev. This is so that drivers can use it early in case they need | ||
116 | * to send stuff around or communicate with user space. | ||
111 | */ | 117 | */ |
112 | struct sk_buff *wimax_msg_alloc(struct wimax_dev *wimax_dev, | 118 | struct sk_buff *wimax_msg_alloc(struct wimax_dev *wimax_dev, |
113 | const char *pipe_name, | 119 | const char *pipe_name, |
@@ -115,7 +121,7 @@ struct sk_buff *wimax_msg_alloc(struct wimax_dev *wimax_dev, | |||
115 | gfp_t gfp_flags) | 121 | gfp_t gfp_flags) |
116 | { | 122 | { |
117 | int result; | 123 | int result; |
118 | struct device *dev = wimax_dev->net_dev->dev.parent; | 124 | struct device *dev = wimax_dev_to_dev(wimax_dev); |
119 | size_t msg_size; | 125 | size_t msg_size; |
120 | void *genl_msg; | 126 | void *genl_msg; |
121 | struct sk_buff *skb; | 127 | struct sk_buff *skb; |
@@ -161,7 +167,6 @@ error_genlmsg_put: | |||
161 | error_new: | 167 | error_new: |
162 | nlmsg_free(skb); | 168 | nlmsg_free(skb); |
163 | return ERR_PTR(result); | 169 | return ERR_PTR(result); |
164 | |||
165 | } | 170 | } |
166 | EXPORT_SYMBOL_GPL(wimax_msg_alloc); | 171 | EXPORT_SYMBOL_GPL(wimax_msg_alloc); |
167 | 172 | ||
@@ -256,10 +261,16 @@ EXPORT_SYMBOL_GPL(wimax_msg_len); | |||
256 | * Don't use skb_push()/skb_pull()/skb_reserve() on the skb, as | 261 | * Don't use skb_push()/skb_pull()/skb_reserve() on the skb, as |
257 | * wimax_msg_send() depends on skb->data being placed at the | 262 | * wimax_msg_send() depends on skb->data being placed at the |
258 | * beginning of the user message. | 263 | * beginning of the user message. |
264 | * | ||
265 | * Unlike other WiMAX stack calls, this call can be used way early, | ||
266 | * even before wimax_dev_add() is called, as long as the | ||
267 | * wimax_dev->net_dev pointer is set to point to a proper | ||
268 | * net_dev. This is so that drivers can use it early in case they need | ||
269 | * to send stuff around or communicate with user space. | ||
259 | */ | 270 | */ |
260 | int wimax_msg_send(struct wimax_dev *wimax_dev, struct sk_buff *skb) | 271 | int wimax_msg_send(struct wimax_dev *wimax_dev, struct sk_buff *skb) |
261 | { | 272 | { |
262 | struct device *dev = wimax_dev->net_dev->dev.parent; | 273 | struct device *dev = wimax_dev_to_dev(wimax_dev); |
263 | void *msg = skb->data; | 274 | void *msg = skb->data; |
264 | size_t size = skb->len; | 275 | size_t size = skb->len; |
265 | might_sleep(); | 276 | might_sleep(); |
diff --git a/net/wimax/op-state-get.c b/net/wimax/op-state-get.c new file mode 100644 index 00000000000..a76b8fcb056 --- /dev/null +++ b/net/wimax/op-state-get.c | |||
@@ -0,0 +1,86 @@ | |||
1 | /* | ||
2 | * Linux WiMAX | ||
3 | * Implement and export a method for getting a WiMAX device current state | ||
4 | * | ||
5 | * Copyright (C) 2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt> | ||
6 | * | ||
7 | * Based on previous WiMAX core work by: | ||
8 | * Copyright (C) 2008 Intel Corporation <linux-wimax@intel.com> | ||
9 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License version | ||
13 | * 2 as published by the Free Software Foundation. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
23 | * 02110-1301, USA. | ||
24 | */ | ||
25 | |||
26 | #include <net/wimax.h> | ||
27 | #include <net/genetlink.h> | ||
28 | #include <linux/wimax.h> | ||
29 | #include <linux/security.h> | ||
30 | #include "wimax-internal.h" | ||
31 | |||
32 | #define D_SUBMODULE op_state_get | ||
33 | #include "debug-levels.h" | ||
34 | |||
35 | |||
36 | static const | ||
37 | struct nla_policy wimax_gnl_state_get_policy[WIMAX_GNL_ATTR_MAX + 1] = { | ||
38 | [WIMAX_GNL_STGET_IFIDX] = { | ||
39 | .type = NLA_U32, | ||
40 | }, | ||
41 | }; | ||
42 | |||
43 | |||
44 | /* | ||
45 | * Exporting to user space over generic netlink | ||
46 | * | ||
47 | * Parse the state get command from user space, return a combination | ||
48 | * value that describe the current state. | ||
49 | * | ||
50 | * No attributes. | ||
51 | */ | ||
52 | static | ||
53 | int wimax_gnl_doit_state_get(struct sk_buff *skb, struct genl_info *info) | ||
54 | { | ||
55 | int result, ifindex; | ||
56 | struct wimax_dev *wimax_dev; | ||
57 | struct device *dev; | ||
58 | |||
59 | d_fnstart(3, NULL, "(skb %p info %p)\n", skb, info); | ||
60 | result = -ENODEV; | ||
61 | if (info->attrs[WIMAX_GNL_STGET_IFIDX] == NULL) { | ||
62 | printk(KERN_ERR "WIMAX_GNL_OP_STATE_GET: can't find IFIDX " | ||
63 | "attribute\n"); | ||
64 | goto error_no_wimax_dev; | ||
65 | } | ||
66 | ifindex = nla_get_u32(info->attrs[WIMAX_GNL_STGET_IFIDX]); | ||
67 | wimax_dev = wimax_dev_get_by_genl_info(info, ifindex); | ||
68 | if (wimax_dev == NULL) | ||
69 | goto error_no_wimax_dev; | ||
70 | dev = wimax_dev_to_dev(wimax_dev); | ||
71 | /* Execute the operation and send the result back to user space */ | ||
72 | result = wimax_state_get(wimax_dev); | ||
73 | dev_put(wimax_dev->net_dev); | ||
74 | error_no_wimax_dev: | ||
75 | d_fnend(3, NULL, "(skb %p info %p) = %d\n", skb, info, result); | ||
76 | return result; | ||
77 | } | ||
78 | |||
79 | |||
80 | struct genl_ops wimax_gnl_state_get = { | ||
81 | .cmd = WIMAX_GNL_OP_STATE_GET, | ||
82 | .flags = GENL_ADMIN_PERM, | ||
83 | .policy = wimax_gnl_state_get_policy, | ||
84 | .doit = wimax_gnl_doit_state_get, | ||
85 | .dumpit = NULL, | ||
86 | }; | ||
diff --git a/net/wimax/stack.c b/net/wimax/stack.c index 933e1422b09..79fb7d7c640 100644 --- a/net/wimax/stack.c +++ b/net/wimax/stack.c | |||
@@ -402,13 +402,15 @@ EXPORT_SYMBOL_GPL(wimax_dev_init); | |||
402 | extern struct genl_ops | 402 | extern struct genl_ops |
403 | wimax_gnl_msg_from_user, | 403 | wimax_gnl_msg_from_user, |
404 | wimax_gnl_reset, | 404 | wimax_gnl_reset, |
405 | wimax_gnl_rfkill; | 405 | wimax_gnl_rfkill, |
406 | wimax_gnl_state_get; | ||
406 | 407 | ||
407 | static | 408 | static |
408 | struct genl_ops *wimax_gnl_ops[] = { | 409 | struct genl_ops *wimax_gnl_ops[] = { |
409 | &wimax_gnl_msg_from_user, | 410 | &wimax_gnl_msg_from_user, |
410 | &wimax_gnl_reset, | 411 | &wimax_gnl_reset, |
411 | &wimax_gnl_rfkill, | 412 | &wimax_gnl_rfkill, |
413 | &wimax_gnl_state_get, | ||
412 | }; | 414 | }; |
413 | 415 | ||
414 | 416 | ||
@@ -533,6 +535,7 @@ struct d_level D_LEVEL[] = { | |||
533 | D_SUBMODULE_DEFINE(op_msg), | 535 | D_SUBMODULE_DEFINE(op_msg), |
534 | D_SUBMODULE_DEFINE(op_reset), | 536 | D_SUBMODULE_DEFINE(op_reset), |
535 | D_SUBMODULE_DEFINE(op_rfkill), | 537 | D_SUBMODULE_DEFINE(op_rfkill), |
538 | D_SUBMODULE_DEFINE(op_state_get), | ||
536 | D_SUBMODULE_DEFINE(stack), | 539 | D_SUBMODULE_DEFINE(stack), |
537 | }; | 540 | }; |
538 | size_t D_LEVEL_SIZE = ARRAY_SIZE(D_LEVEL); | 541 | size_t D_LEVEL_SIZE = ARRAY_SIZE(D_LEVEL); |