aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wimax/i2400m
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wimax/i2400m')
-rw-r--r--drivers/net/wimax/i2400m/Makefile1
-rw-r--r--drivers/net/wimax/i2400m/control.c98
-rw-r--r--drivers/net/wimax/i2400m/debug-levels.h1
-rw-r--r--drivers/net/wimax/i2400m/driver.c10
-rw-r--r--drivers/net/wimax/i2400m/i2400m.h29
-rw-r--r--drivers/net/wimax/i2400m/sysfs.c80
6 files changed, 211 insertions, 8 deletions
diff --git a/drivers/net/wimax/i2400m/Makefile b/drivers/net/wimax/i2400m/Makefile
index 1696e936cf5a..5d9e018d31af 100644
--- a/drivers/net/wimax/i2400m/Makefile
+++ b/drivers/net/wimax/i2400m/Makefile
@@ -8,6 +8,7 @@ i2400m-y := \
8 driver.o \ 8 driver.o \
9 fw.o \ 9 fw.o \
10 op-rfkill.o \ 10 op-rfkill.o \
11 sysfs.o \
11 netdev.o \ 12 netdev.o \
12 tx.o \ 13 tx.o \
13 rx.o 14 rx.o
diff --git a/drivers/net/wimax/i2400m/control.c b/drivers/net/wimax/i2400m/control.c
index c8b3a68b72b8..c3968b240d69 100644
--- a/drivers/net/wimax/i2400m/control.c
+++ b/drivers/net/wimax/i2400m/control.c
@@ -1222,6 +1222,77 @@ EXPORT_SYMBOL_GPL(i2400m_set_init_config);
1222 1222
1223 1223
1224/** 1224/**
1225 * i2400m_set_idle_timeout - Set the device's idle mode timeout
1226 *
1227 * @i2400m: i2400m device descriptor
1228 *
1229 * @msecs: milliseconds for the timeout to enter idle mode. Between
1230 * 100 to 300000 (5m); 0 to disable. In increments of 100.
1231 *
1232 * After this @msecs of the link being idle (no data being sent or
1233 * received), the device will negotiate with the basestation entering
1234 * idle mode for saving power. The connection is maintained, but
1235 * getting out of it (done in tx.c) will require some negotiation,
1236 * possible crypto re-handshake and a possible DHCP re-lease.
1237 *
1238 * Only available if fw_version >= 0x00090002.
1239 *
1240 * Returns: 0 if ok, < 0 errno code on error.
1241 */
1242int i2400m_set_idle_timeout(struct i2400m *i2400m, unsigned msecs)
1243{
1244 int result;
1245 struct device *dev = i2400m_dev(i2400m);
1246 struct sk_buff *ack_skb;
1247 struct {
1248 struct i2400m_l3l4_hdr hdr;
1249 struct i2400m_tlv_config_idle_timeout cit;
1250 } *cmd;
1251 const struct i2400m_l3l4_hdr *ack;
1252 size_t ack_len;
1253 char strerr[32];
1254
1255 result = -ENOSYS;
1256 if (i2400m_le_v1_3(i2400m))
1257 goto error_alloc;
1258 result = -ENOMEM;
1259 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
1260 if (cmd == NULL)
1261 goto error_alloc;
1262 cmd->hdr.type = cpu_to_le16(I2400M_MT_GET_STATE);
1263 cmd->hdr.length = cpu_to_le16(sizeof(*cmd) - sizeof(cmd->hdr));
1264 cmd->hdr.version = cpu_to_le16(I2400M_L3L4_VERSION);
1265
1266 cmd->cit.hdr.type =
1267 cpu_to_le16(I2400M_TLV_CONFIG_IDLE_TIMEOUT);
1268 cmd->cit.hdr.length = cpu_to_le16(sizeof(cmd->cit.timeout));
1269 cmd->cit.timeout = cpu_to_le32(msecs);
1270
1271 ack_skb = i2400m_msg_to_dev(i2400m, cmd, sizeof(*cmd));
1272 if (IS_ERR(ack_skb)) {
1273 dev_err(dev, "Failed to issue 'set idle timeout' command: "
1274 "%ld\n", PTR_ERR(ack_skb));
1275 result = PTR_ERR(ack_skb);
1276 goto error_msg_to_dev;
1277 }
1278 ack = wimax_msg_data_len(ack_skb, &ack_len);
1279 result = i2400m_msg_check_status(ack, strerr, sizeof(strerr));
1280 if (result < 0) {
1281 dev_err(dev, "'set idle timeout' (0x%04x) command failed: "
1282 "%d - %s\n", I2400M_MT_GET_STATE, result, strerr);
1283 goto error_cmd_failed;
1284 }
1285 result = 0;
1286 kfree_skb(ack_skb);
1287error_cmd_failed:
1288error_msg_to_dev:
1289 kfree(cmd);
1290error_alloc:
1291 return result;
1292}
1293
1294
1295/**
1225 * i2400m_dev_initialize - Initialize the device once communications are ready 1296 * i2400m_dev_initialize - Initialize the device once communications are ready
1226 * 1297 *
1227 * @i2400m: device descriptor 1298 * @i2400m: device descriptor
@@ -1239,19 +1310,28 @@ int i2400m_dev_initialize(struct i2400m *i2400m)
1239 int result; 1310 int result;
1240 struct device *dev = i2400m_dev(i2400m); 1311 struct device *dev = i2400m_dev(i2400m);
1241 struct i2400m_tlv_config_idle_parameters idle_params; 1312 struct i2400m_tlv_config_idle_parameters idle_params;
1313 struct i2400m_tlv_config_idle_timeout idle_timeout;
1242 const struct i2400m_tlv_hdr *args[9]; 1314 const struct i2400m_tlv_hdr *args[9];
1243 unsigned argc = 0; 1315 unsigned argc = 0;
1244 1316
1245 d_fnstart(3, dev, "(i2400m %p)\n", i2400m); 1317 d_fnstart(3, dev, "(i2400m %p)\n", i2400m);
1246 /* Useless for now...might change */
1247 if (i2400m_idle_mode_disabled) { 1318 if (i2400m_idle_mode_disabled) {
1248 idle_params.hdr.type = 1319 if (i2400m_le_v1_3(i2400m)) {
1249 cpu_to_le16(I2400M_TLV_CONFIG_IDLE_PARAMETERS); 1320 idle_params.hdr.type =
1250 idle_params.hdr.length = cpu_to_le16( 1321 cpu_to_le16(I2400M_TLV_CONFIG_IDLE_PARAMETERS);
1251 sizeof(idle_params) - sizeof(idle_params.hdr)); 1322 idle_params.hdr.length = cpu_to_le16(
1252 idle_params.idle_timeout = 0; 1323 sizeof(idle_params) - sizeof(idle_params.hdr));
1253 idle_params.idle_paging_interval = 0; 1324 idle_params.idle_timeout = 0;
1254 args[argc++] = &idle_params.hdr; 1325 idle_params.idle_paging_interval = 0;
1326 args[argc++] = &idle_params.hdr;
1327 } else {
1328 idle_timeout.hdr.type =
1329 cpu_to_le16(I2400M_TLV_CONFIG_IDLE_TIMEOUT);
1330 idle_timeout.hdr.length = cpu_to_le16(
1331 sizeof(idle_timeout) - sizeof(idle_timeout.hdr));
1332 idle_timeout.timeout = 0;
1333 args[argc++] = &idle_timeout.hdr;
1334 }
1255 } 1335 }
1256 result = i2400m_set_init_config(i2400m, args, argc); 1336 result = i2400m_set_init_config(i2400m, args, argc);
1257 if (result < 0) 1337 if (result < 0)
@@ -1264,6 +1344,8 @@ int i2400m_dev_initialize(struct i2400m *i2400m)
1264 */ 1344 */
1265 result = i2400m_cmd_get_state(i2400m); 1345 result = i2400m_cmd_get_state(i2400m);
1266error: 1346error:
1347 if (result < 0)
1348 dev_err(dev, "failed to initialize the device: %d\n", result);
1267 d_fnend(3, dev, "(i2400m %p) = %d\n", i2400m, result); 1349 d_fnend(3, dev, "(i2400m %p) = %d\n", i2400m, result);
1268 return result; 1350 return result;
1269} 1351}
diff --git a/drivers/net/wimax/i2400m/debug-levels.h b/drivers/net/wimax/i2400m/debug-levels.h
index 3183baa16a52..48fbfaa0d403 100644
--- a/drivers/net/wimax/i2400m/debug-levels.h
+++ b/drivers/net/wimax/i2400m/debug-levels.h
@@ -38,6 +38,7 @@ enum d_module {
38 D_SUBMODULE_DECLARE(netdev), 38 D_SUBMODULE_DECLARE(netdev),
39 D_SUBMODULE_DECLARE(rfkill), 39 D_SUBMODULE_DECLARE(rfkill),
40 D_SUBMODULE_DECLARE(rx), 40 D_SUBMODULE_DECLARE(rx),
41 D_SUBMODULE_DECLARE(sysfs),
41 D_SUBMODULE_DECLARE(tx), 42 D_SUBMODULE_DECLARE(tx),
42}; 43};
43 44
diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c
index 69a816e7c5db..f988771bfae0 100644
--- a/drivers/net/wimax/i2400m/driver.c
+++ b/drivers/net/wimax/i2400m/driver.c
@@ -662,6 +662,11 @@ int i2400m_setup(struct i2400m *i2400m, enum i2400m_bri bm_flags)
662 wimax_state_change(wimax_dev, WIMAX_ST_UNINITIALIZED); 662 wimax_state_change(wimax_dev, WIMAX_ST_UNINITIALIZED);
663 663
664 /* Now setup all that requires a registered net and wimax device. */ 664 /* Now setup all that requires a registered net and wimax device. */
665 result = sysfs_create_group(&net_dev->dev.kobj, &i2400m_dev_attr_group);
666 if (result < 0) {
667 dev_err(dev, "cannot setup i2400m's sysfs: %d\n", result);
668 goto error_sysfs_setup;
669 }
665 result = i2400m_debugfs_add(i2400m); 670 result = i2400m_debugfs_add(i2400m);
666 if (result < 0) { 671 if (result < 0) {
667 dev_err(dev, "cannot setup i2400m's debugfs: %d\n", result); 672 dev_err(dev, "cannot setup i2400m's debugfs: %d\n", result);
@@ -671,6 +676,9 @@ int i2400m_setup(struct i2400m *i2400m, enum i2400m_bri bm_flags)
671 return result; 676 return result;
672 677
673error_debugfs_setup: 678error_debugfs_setup:
679 sysfs_remove_group(&i2400m->wimax_dev.net_dev->dev.kobj,
680 &i2400m_dev_attr_group);
681error_sysfs_setup:
674 wimax_dev_rm(&i2400m->wimax_dev); 682 wimax_dev_rm(&i2400m->wimax_dev);
675error_wimax_dev_add: 683error_wimax_dev_add:
676 i2400m_dev_stop(i2400m); 684 i2400m_dev_stop(i2400m);
@@ -702,6 +710,8 @@ void i2400m_release(struct i2400m *i2400m)
702 netif_stop_queue(i2400m->wimax_dev.net_dev); 710 netif_stop_queue(i2400m->wimax_dev.net_dev);
703 711
704 i2400m_debugfs_rm(i2400m); 712 i2400m_debugfs_rm(i2400m);
713 sysfs_remove_group(&i2400m->wimax_dev.net_dev->dev.kobj,
714 &i2400m_dev_attr_group);
705 wimax_dev_rm(&i2400m->wimax_dev); 715 wimax_dev_rm(&i2400m->wimax_dev);
706 i2400m_dev_stop(i2400m); 716 i2400m_dev_stop(i2400m);
707 unregister_netdev(i2400m->wimax_dev.net_dev); 717 unregister_netdev(i2400m->wimax_dev.net_dev);
diff --git a/drivers/net/wimax/i2400m/i2400m.h b/drivers/net/wimax/i2400m/i2400m.h
index 5008cdb12b42..0c60d5c43007 100644
--- a/drivers/net/wimax/i2400m/i2400m.h
+++ b/drivers/net/wimax/i2400m/i2400m.h
@@ -585,6 +585,8 @@ unsigned i2400m_brh_get_signature(const struct i2400m_bootrom_header *hdr)
585 * Driver / device setup and internal functions 585 * Driver / device setup and internal functions
586 */ 586 */
587extern void i2400m_netdev_setup(struct net_device *net_dev); 587extern void i2400m_netdev_setup(struct net_device *net_dev);
588extern int i2400m_sysfs_setup(struct device_driver *);
589extern void i2400m_sysfs_release(struct device_driver *);
588extern int i2400m_tx_setup(struct i2400m *); 590extern int i2400m_tx_setup(struct i2400m *);
589extern void i2400m_wake_tx_work(struct work_struct *); 591extern void i2400m_wake_tx_work(struct work_struct *);
590extern void i2400m_tx_release(struct i2400m *); 592extern void i2400m_tx_release(struct i2400m *);
@@ -728,6 +730,7 @@ extern struct sk_buff *i2400m_get_device_info(struct i2400m *);
728extern int i2400m_firmware_check(struct i2400m *); 730extern int i2400m_firmware_check(struct i2400m *);
729extern int i2400m_set_init_config(struct i2400m *, 731extern int i2400m_set_init_config(struct i2400m *,
730 const struct i2400m_tlv_hdr **, size_t); 732 const struct i2400m_tlv_hdr **, size_t);
733extern int i2400m_set_idle_timeout(struct i2400m *, unsigned);
731 734
732static inline 735static inline
733struct usb_endpoint_descriptor *usb_get_epd(struct usb_interface *iface, int ep) 736struct usb_endpoint_descriptor *usb_get_epd(struct usb_interface *iface, int ep)
@@ -740,6 +743,32 @@ extern int i2400m_op_rfkill_sw_toggle(struct wimax_dev *,
740extern void i2400m_report_tlv_rf_switches_status( 743extern void i2400m_report_tlv_rf_switches_status(
741 struct i2400m *, const struct i2400m_tlv_rf_switches_status *); 744 struct i2400m *, const struct i2400m_tlv_rf_switches_status *);
742 745
746/*
747 * Helpers for firmware backwards compability
748 *
749 * As we aim to support at least the firmware version that was
750 * released with the previous kernel/driver release, some code will be
751 * conditionally executed depending on the firmware version. On each
752 * release, the code to support fw releases past the last two ones
753 * will be purged.
754 *
755 * By making it depend on this macros, it is easier to keep it a tab
756 * on what has to go and what not.
757 */
758static inline
759unsigned i2400m_le_v1_3(struct i2400m *i2400m)
760{
761 /* running fw is lower or v1.3 */
762 return i2400m->fw_version <= 0x00090001;
763}
764
765static inline
766unsigned i2400m_ge_v1_4(struct i2400m *i2400m)
767{
768 /* running fw is higher or v1.4 */
769 return i2400m->fw_version >= 0x00090002;
770}
771
743 772
744/* 773/*
745 * Do a millisecond-sleep for allowing wireshark to dump all the data 774 * Do a millisecond-sleep for allowing wireshark to dump all the data
diff --git a/drivers/net/wimax/i2400m/sysfs.c b/drivers/net/wimax/i2400m/sysfs.c
new file mode 100644
index 000000000000..1237109f251a
--- /dev/null
+++ b/drivers/net/wimax/i2400m/sysfs.c
@@ -0,0 +1,80 @@
1/*
2 * Intel Wireless WiMAX Connection 2400m
3 * Sysfs interfaces to show driver and device information
4 *
5 *
6 * Copyright (C) 2007 Intel Corporation <linux-wimax@intel.com>
7 * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License version
11 * 2 as published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 * 02110-1301, USA.
22 */
23
24#include <linux/netdevice.h>
25#include <linux/etherdevice.h>
26#include <linux/spinlock.h>
27#include <linux/device.h>
28#include "i2400m.h"
29
30
31#define D_SUBMODULE sysfs
32#include "debug-levels.h"
33
34
35/*
36 * Set the idle timeout (msecs)
37 *
38 * FIXME: eventually this should be a common WiMAX stack method, but
39 * would like to wait to see how other devices manage it.
40 */
41static
42ssize_t i2400m_idle_timeout_store(struct device *dev,
43 struct device_attribute *attr,
44 const char *buf, size_t size)
45{
46 ssize_t result;
47 struct i2400m *i2400m = net_dev_to_i2400m(to_net_dev(dev));
48 unsigned val;
49
50 result = -EINVAL;
51 if (sscanf(buf, "%u\n", &val) != 1)
52 goto error_no_unsigned;
53 if (val != 0 && (val < 100 || val > 300000 || val % 100 != 0)) {
54 dev_err(dev, "idle_timeout: %u: invalid msecs specification; "
55 "valid values are 0, 100-300000 in 100 increments\n",
56 val);
57 goto error_bad_value;
58 }
59 result = i2400m_set_idle_timeout(i2400m, val);
60 if (result >= 0)
61 result = size;
62error_no_unsigned:
63error_bad_value:
64 return result;
65}
66
67static
68DEVICE_ATTR(i2400m_idle_timeout, S_IWUSR,
69 NULL, i2400m_idle_timeout_store);
70
71static
72struct attribute *i2400m_dev_attrs[] = {
73 &dev_attr_i2400m_idle_timeout.attr,
74 NULL,
75};
76
77struct attribute_group i2400m_dev_attr_group = {
78 .name = NULL, /* we want them in the same directory */
79 .attrs = i2400m_dev_attrs,
80};