aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2009-05-29 04:41:32 -0400
committerDavid S. Miller <davem@davemloft.net>2009-05-29 04:41:32 -0400
commit3f1f39c42b24d5c20eb593ce80b9c4d5ec1e2148 (patch)
tree785e5d697e9c2e4b8fd012a7e9c8aac263c186a5
parentdfe9a837987aacaffbce020fbf54d8e0afa4bde1 (diff)
parent7481806dcfd07e9a636155554f6f4b4fbd976381 (diff)
Merge branch 'linux-2.6.31.y' of git://git.kernel.org/pub/scm/linux/kernel/git/inaky/wimax
-rw-r--r--drivers/net/wimax/i2400m/control.c100
-rw-r--r--drivers/net/wimax/i2400m/driver.c5
-rw-r--r--drivers/net/wimax/i2400m/i2400m.h5
-rw-r--r--drivers/net/wimax/i2400m/netdev.c4
-rw-r--r--drivers/net/wimax/i2400m/rx.c6
-rw-r--r--drivers/net/wimax/i2400m/sdio.c18
-rw-r--r--drivers/net/wimax/i2400m/usb.c35
-rw-r--r--include/linux/wimax.h7
-rw-r--r--net/wimax/Makefile1
-rw-r--r--net/wimax/debug-levels.h1
-rw-r--r--net/wimax/debugfs.c1
-rw-r--r--net/wimax/op-msg.c17
-rw-r--r--net/wimax/op-state-get.c86
-rw-r--r--net/wimax/stack.c5
14 files changed, 222 insertions, 69 deletions
diff --git a/drivers/net/wimax/i2400m/control.c b/drivers/net/wimax/i2400m/control.c
index b3cadb626fe0..bd193ae2178b 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 };
344out:
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 };
396out:
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 */
406static
407void 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 */
420static 454static
421void i2400m_report_state_hook(struct i2400m *i2400m, 455void 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 07a54bad237b..ef16c573bb22 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);
241error_msg_to_dev: 239error_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 3ae2df38b59a..434ba310c2fe 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 6b1fe7a81f25..9653f478b382 100644
--- a/drivers/net/wimax/i2400m/netdev.c
+++ b/drivers/net/wimax/i2400m/netdev.c
@@ -404,10 +404,12 @@ static
404void i2400m_rx_fake_eth_header(struct net_device *net_dev, 404void 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 f9fc38902322..7643850a6fb8 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 5ac5e76701cd..777c981676fc 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,
440error_debugfs_add: 440error_debugfs_add:
441 i2400m_release(i2400m); 441 i2400m_release(i2400m);
442error_setup: 442error_setup:
443 sdio_set_drvdata(func, NULL);
444 sdio_claim_host(func); 443 sdio_claim_host(func);
445error_set_blk_size:
446 sdio_disable_func(func); 444 sdio_disable_func(func);
447 sdio_release_host(func); 445 sdio_release_host(func);
448error_func_enable: 446error_func_enable:
447error_set_blk_size:
448 sdio_set_drvdata(func, NULL);
449 free_netdev(net_dev); 449 free_netdev(net_dev);
450error_alloc_netdev: 450error_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 ca4151a9e222..17851321b7fd 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");
528error_enter_powersave: 552error_enter_powersave:
553error_not_now:
529no_firmware: 554no_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 c89de7f4e5b9..4fdcc5635518 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() */
118enum {
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 5b80b941c2c9..8f1510d0cc2b 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
11wimax-$(CONFIG_DEBUG_FS) += debugfs.o 12wimax-$(CONFIG_DEBUG_FS) += debugfs.o
diff --git a/net/wimax/debug-levels.h b/net/wimax/debug-levels.h
index 1c29123a3aa9..0975adba6b71 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 94d216a46407..6c9bedb7431e 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;
66out: 67out:
diff --git a/net/wimax/op-msg.c b/net/wimax/op-msg.c
index 9ad4d893a566..d631a17186bc 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 */
112struct sk_buff *wimax_msg_alloc(struct wimax_dev *wimax_dev, 118struct 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:
161error_new: 167error_new:
162 nlmsg_free(skb); 168 nlmsg_free(skb);
163 return ERR_PTR(result); 169 return ERR_PTR(result);
164
165} 170}
166EXPORT_SYMBOL_GPL(wimax_msg_alloc); 171EXPORT_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 */
260int wimax_msg_send(struct wimax_dev *wimax_dev, struct sk_buff *skb) 271int 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 000000000000..a76b8fcb056d
--- /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
36static const
37struct 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 */
52static
53int 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);
74error_no_wimax_dev:
75 d_fnend(3, NULL, "(skb %p info %p) = %d\n", skb, info, result);
76 return result;
77}
78
79
80struct 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 933e1422b09f..79fb7d7c640f 100644
--- a/net/wimax/stack.c
+++ b/net/wimax/stack.c
@@ -402,13 +402,15 @@ EXPORT_SYMBOL_GPL(wimax_dev_init);
402extern struct genl_ops 402extern 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
407static 408static
408struct genl_ops *wimax_gnl_ops[] = { 409struct 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};
538size_t D_LEVEL_SIZE = ARRAY_SIZE(D_LEVEL); 541size_t D_LEVEL_SIZE = ARRAY_SIZE(D_LEVEL);