Commit 3f1f39c4 authored by David S. Miller's avatar David S. Miller
parents dfe9a837 7481806d
...@@ -292,8 +292,6 @@ void i2400m_report_tlv_system_state(struct i2400m *i2400m, ...@@ -292,8 +292,6 @@ void i2400m_report_tlv_system_state(struct i2400m *i2400m,
d_fnstart(3, dev, "(i2400m %p ss %p [%u])\n", i2400m, ss, i2400m_state); d_fnstart(3, dev, "(i2400m %p ss %p [%u])\n", i2400m, ss, i2400m_state);
if (unlikely(i2400m->ready == 0)) /* act if up */
goto out;
if (i2400m->state != i2400m_state) { if (i2400m->state != i2400m_state) {
i2400m->state = i2400m_state; i2400m->state = i2400m_state;
wake_up_all(&i2400m->state_wq); wake_up_all(&i2400m->state_wq);
...@@ -341,7 +339,6 @@ void i2400m_report_tlv_system_state(struct i2400m *i2400m, ...@@ -341,7 +339,6 @@ void i2400m_report_tlv_system_state(struct i2400m *i2400m,
i2400m->bus_reset(i2400m, I2400M_RT_WARM); i2400m->bus_reset(i2400m, I2400M_RT_WARM);
break; break;
}; };
out:
d_fnend(3, dev, "(i2400m %p ss %p [%u]) = void\n", d_fnend(3, dev, "(i2400m %p ss %p [%u]) = void\n",
i2400m, ss, i2400m_state); i2400m, ss, i2400m_state);
} }
...@@ -372,8 +369,6 @@ void i2400m_report_tlv_media_status(struct i2400m *i2400m, ...@@ -372,8 +369,6 @@ void i2400m_report_tlv_media_status(struct i2400m *i2400m,
d_fnstart(3, dev, "(i2400m %p ms %p [%u])\n", i2400m, ms, status); d_fnstart(3, dev, "(i2400m %p ms %p [%u])\n", i2400m, ms, status);
if (unlikely(i2400m->ready == 0)) /* act if up */
goto out;
switch (status) { switch (status) {
case I2400M_MEDIA_STATUS_LINK_UP: case I2400M_MEDIA_STATUS_LINK_UP:
netif_carrier_on(net_dev); netif_carrier_on(net_dev);
...@@ -393,14 +388,59 @@ void i2400m_report_tlv_media_status(struct i2400m *i2400m, ...@@ -393,14 +388,59 @@ void i2400m_report_tlv_media_status(struct i2400m *i2400m,
dev_err(dev, "HW BUG? unknown media status %u\n", dev_err(dev, "HW BUG? unknown media status %u\n",
status); status);
}; };
out:
d_fnend(3, dev, "(i2400m %p ms %p [%u]) = void\n", d_fnend(3, dev, "(i2400m %p ms %p [%u]) = void\n",
i2400m, ms, status); i2400m, ms, status);
} }
/* /*
* Parse a 'state report' and extract carrier on/off information * Process a TLV from a 'state report'
*
* @i2400m: device descriptor
* @tlv: pointer to the TLV header; it has been already validated for
* consistent size.
* @tag: for error messages
*
* Act on the TLVs from a 'state report'.
*/
static
void i2400m_report_state_parse_tlv(struct i2400m *i2400m,
const struct i2400m_tlv_hdr *tlv,
const char *tag)
{
struct device *dev = i2400m_dev(i2400m);
const struct i2400m_tlv_media_status *ms;
const struct i2400m_tlv_system_state *ss;
const struct i2400m_tlv_rf_switches_status *rfss;
if (0 == i2400m_tlv_match(tlv, I2400M_TLV_SYSTEM_STATE, sizeof(*ss))) {
ss = container_of(tlv, typeof(*ss), hdr);
d_printf(2, dev, "%s: system state TLV "
"found (0x%04x), state 0x%08x\n",
tag, I2400M_TLV_SYSTEM_STATE,
le32_to_cpu(ss->state));
i2400m_report_tlv_system_state(i2400m, ss);
}
if (0 == i2400m_tlv_match(tlv, I2400M_TLV_RF_STATUS, sizeof(*rfss))) {
rfss = container_of(tlv, typeof(*rfss), hdr);
d_printf(2, dev, "%s: RF status TLV "
"found (0x%04x), sw 0x%02x hw 0x%02x\n",
tag, I2400M_TLV_RF_STATUS,
le32_to_cpu(rfss->sw_rf_switch),
le32_to_cpu(rfss->hw_rf_switch));
i2400m_report_tlv_rf_switches_status(i2400m, rfss);
}
if (0 == i2400m_tlv_match(tlv, I2400M_TLV_MEDIA_STATUS, sizeof(*ms))) {
ms = container_of(tlv, typeof(*ms), hdr);
d_printf(2, dev, "%s: Media Status TLV: %u\n",
tag, le32_to_cpu(ms->media_status));
i2400m_report_tlv_media_status(i2400m, ms);
}
}
/*
* Parse a 'state report' and extract information
* *
* @i2400m: device descriptor * @i2400m: device descriptor
* @l3l4_hdr: pointer to message; it has been already validated for * @l3l4_hdr: pointer to message; it has been already validated for
...@@ -409,13 +449,7 @@ out: ...@@ -409,13 +449,7 @@ out:
* declaration is assumed to be congruent with @size (as in * declaration is assumed to be congruent with @size (as in
* sizeof(*l3l4_hdr) + l3l4_hdr->length == size) * sizeof(*l3l4_hdr) + l3l4_hdr->length == size)
* *
* Extract from the report state the system state TLV and infer from * Walk over the TLVs in a report state and act on them.
* there if we have a carrier or not. Update our local state and tell
* netdev.
*
* When setting the carrier, it's fine to set OFF twice (for example),
* as netif_carrier_off() will not generate two OFF events (just on
* the transitions).
*/ */
static static
void i2400m_report_state_hook(struct i2400m *i2400m, void i2400m_report_state_hook(struct i2400m *i2400m,
...@@ -424,9 +458,6 @@ void i2400m_report_state_hook(struct i2400m *i2400m, ...@@ -424,9 +458,6 @@ void i2400m_report_state_hook(struct i2400m *i2400m,
{ {
struct device *dev = i2400m_dev(i2400m); struct device *dev = i2400m_dev(i2400m);
const struct i2400m_tlv_hdr *tlv; const struct i2400m_tlv_hdr *tlv;
const struct i2400m_tlv_system_state *ss;
const struct i2400m_tlv_rf_switches_status *rfss;
const struct i2400m_tlv_media_status *ms;
size_t tlv_size = le16_to_cpu(l3l4_hdr->length); size_t tlv_size = le16_to_cpu(l3l4_hdr->length);
d_fnstart(4, dev, "(i2400m %p, l3l4_hdr %p, size %zu, %s)\n", 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,34 +465,8 @@ void i2400m_report_state_hook(struct i2400m *i2400m,
tlv = NULL; tlv = NULL;
while ((tlv = i2400m_tlv_buffer_walk(i2400m, &l3l4_hdr->pl, while ((tlv = i2400m_tlv_buffer_walk(i2400m, &l3l4_hdr->pl,
tlv_size, tlv))) { tlv_size, tlv)))
if (0 == i2400m_tlv_match(tlv, I2400M_TLV_SYSTEM_STATE, i2400m_report_state_parse_tlv(i2400m, tlv, tag);
sizeof(*ss))) {
ss = container_of(tlv, typeof(*ss), hdr);
d_printf(2, dev, "%s: system state TLV "
"found (0x%04x), state 0x%08x\n",
tag, I2400M_TLV_SYSTEM_STATE,
le32_to_cpu(ss->state));
i2400m_report_tlv_system_state(i2400m, ss);
}
if (0 == i2400m_tlv_match(tlv, I2400M_TLV_RF_STATUS,
sizeof(*rfss))) {
rfss = container_of(tlv, typeof(*rfss), hdr);
d_printf(2, dev, "%s: RF status TLV "
"found (0x%04x), sw 0x%02x hw 0x%02x\n",
tag, I2400M_TLV_RF_STATUS,
le32_to_cpu(rfss->sw_rf_switch),
le32_to_cpu(rfss->hw_rf_switch));
i2400m_report_tlv_rf_switches_status(i2400m, rfss);
}
if (0 == i2400m_tlv_match(tlv, I2400M_TLV_MEDIA_STATUS,
sizeof(*ms))) {
ms = container_of(tlv, typeof(*ms), hdr);
d_printf(2, dev, "%s: Media Status TLV: %u\n",
tag, le32_to_cpu(ms->media_status));
i2400m_report_tlv_media_status(i2400m, ms);
}
}
d_fnend(4, dev, "(i2400m %p, l3l4_hdr %p, size %zu, %s) = void\n", d_fnend(4, dev, "(i2400m %p, l3l4_hdr %p, size %zu, %s) = void\n",
i2400m, l3l4_hdr, size, tag); i2400m, l3l4_hdr, size, tag);
} }
...@@ -721,6 +726,8 @@ struct sk_buff *i2400m_msg_to_dev(struct i2400m *i2400m, ...@@ -721,6 +726,8 @@ struct sk_buff *i2400m_msg_to_dev(struct i2400m *i2400m,
ack_timeout = HZ; ack_timeout = HZ;
}; };
if (unlikely(i2400m->trace_msg_from_user))
wimax_msg(&i2400m->wimax_dev, "echo", buf, buf_len, GFP_KERNEL);
/* The RX path in rx.c will put any response for this message /* The RX path in rx.c will put any response for this message
* in i2400m->ack_skb and wake us up. If we cancel the wait, * in i2400m->ack_skb and wake us up. If we cancel the wait,
* we need to change the value of i2400m->ack_skb to something * 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,6 +762,9 @@ struct sk_buff *i2400m_msg_to_dev(struct i2400m *i2400m,
ack_l3l4_hdr = wimax_msg_data_len(ack_skb, &ack_len); ack_l3l4_hdr = wimax_msg_data_len(ack_skb, &ack_len);
/* Check the ack and deliver it if it is ok */ /* Check the ack and deliver it if it is ok */
if (unlikely(i2400m->trace_msg_from_user))
wimax_msg(&i2400m->wimax_dev, "echo",
ack_l3l4_hdr, ack_len, GFP_KERNEL);
result = i2400m_msg_size_check(i2400m, ack_l3l4_hdr, ack_len); result = i2400m_msg_size_check(i2400m, ack_l3l4_hdr, ack_len);
if (result < 0) { if (result < 0) {
dev_err(dev, "HW BUG? reply to message 0x%04x: %d\n", dev_err(dev, "HW BUG? reply to message 0x%04x: %d\n",
......
...@@ -62,6 +62,7 @@ ...@@ -62,6 +62,7 @@
* unregister_netdev() * unregister_netdev()
*/ */
#include "i2400m.h" #include "i2400m.h"
#include <linux/etherdevice.h>
#include <linux/wimax/i2400m.h> #include <linux/wimax/i2400m.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
...@@ -234,9 +235,6 @@ int i2400m_op_msg_from_user(struct wimax_dev *wimax_dev, ...@@ -234,9 +235,6 @@ int i2400m_op_msg_from_user(struct wimax_dev *wimax_dev,
result = PTR_ERR(ack_skb); result = PTR_ERR(ack_skb);
if (IS_ERR(ack_skb)) if (IS_ERR(ack_skb))
goto error_msg_to_dev; goto error_msg_to_dev;
if (unlikely(i2400m->trace_msg_from_user))
wimax_msg(&i2400m->wimax_dev, "trace",
msg_buf, msg_len, GFP_KERNEL);
result = wimax_msg_send(&i2400m->wimax_dev, ack_skb); result = wimax_msg_send(&i2400m->wimax_dev, ack_skb);
error_msg_to_dev: error_msg_to_dev:
d_fnend(4, dev, "(wimax_dev %p [i2400m %p] msg_buf %p msg_len %zu " 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,6 +648,7 @@ int i2400m_setup(struct i2400m *i2400m, enum i2400m_bri bm_flags)
result = i2400m_read_mac_addr(i2400m); result = i2400m_read_mac_addr(i2400m);
if (result < 0) if (result < 0)
goto error_read_mac_addr; goto error_read_mac_addr;
random_ether_addr(i2400m->src_mac_addr);
result = register_netdev(net_dev); /* Okey dokey, bring it up */ result = register_netdev(net_dev); /* Okey dokey, bring it up */
if (result < 0) { if (result < 0) {
......
...@@ -323,6 +323,10 @@ struct i2400m_roq; ...@@ -323,6 +323,10 @@ struct i2400m_roq;
* delivered. Then the driver can release them to the host. See * delivered. Then the driver can release them to the host. See
* drivers/net/i2400m/rx.c for details. * drivers/net/i2400m/rx.c for details.
* *
* @src_mac_addr: MAC address used to make ethernet packets be coming
* from. This is generated at i2400m_setup() time and used during
* the life cycle of the instance. See i2400m_fake_eth_header().
*
* @init_mutex: Mutex used for serializing the device bringup * @init_mutex: Mutex used for serializing the device bringup
* sequence; this way if the device reboots in the middle, we * sequence; this way if the device reboots in the middle, we
* don't try to do a bringup again while we are tearing down the * don't try to do a bringup again while we are tearing down the
...@@ -421,6 +425,7 @@ struct i2400m { ...@@ -421,6 +425,7 @@ struct i2400m {
unsigned rx_pl_num, rx_pl_max, rx_pl_min, unsigned rx_pl_num, rx_pl_max, rx_pl_min,
rx_num, rx_size_acc, rx_size_min, rx_size_max; rx_num, rx_size_acc, rx_size_min, rx_size_max;
struct i2400m_roq *rx_roq; /* not under rx_lock! */ struct i2400m_roq *rx_roq; /* not under rx_lock! */
u8 src_mac_addr[ETH_HLEN];
struct mutex msg_mutex; /* serialize command execution */ struct mutex msg_mutex; /* serialize command execution */
struct completion msg_completion; struct completion msg_completion;
......
...@@ -404,10 +404,12 @@ static ...@@ -404,10 +404,12 @@ static
void i2400m_rx_fake_eth_header(struct net_device *net_dev, void i2400m_rx_fake_eth_header(struct net_device *net_dev,
void *_eth_hdr, __be16 protocol) void *_eth_hdr, __be16 protocol)
{ {
struct i2400m *i2400m = net_dev_to_i2400m(net_dev);
struct ethhdr *eth_hdr = _eth_hdr; struct ethhdr *eth_hdr = _eth_hdr;
memcpy(eth_hdr->h_dest, net_dev->dev_addr, sizeof(eth_hdr->h_dest)); memcpy(eth_hdr->h_dest, net_dev->dev_addr, sizeof(eth_hdr->h_dest));
memset(eth_hdr->h_source, 0, sizeof(eth_hdr->h_dest)); memcpy(eth_hdr->h_source, i2400m->src_mac_addr,
sizeof(eth_hdr->h_source));
eth_hdr->h_proto = protocol; eth_hdr->h_proto = protocol;
} }
......
...@@ -177,7 +177,8 @@ void i2400m_report_hook_work(struct work_struct *ws) ...@@ -177,7 +177,8 @@ void i2400m_report_hook_work(struct work_struct *ws)
struct i2400m_work *iw = struct i2400m_work *iw =
container_of(ws, struct i2400m_work, ws); container_of(ws, struct i2400m_work, ws);
struct i2400m_report_hook_args *args = (void *) iw->pl; struct i2400m_report_hook_args *args = (void *) iw->pl;
i2400m_report_hook(iw->i2400m, args->l3l4_hdr, args->size); if (iw->i2400m->ready)
i2400m_report_hook(iw->i2400m, args->l3l4_hdr, args->size);
kfree_skb(args->skb_rx); kfree_skb(args->skb_rx);
i2400m_put(iw->i2400m); i2400m_put(iw->i2400m);
kfree(iw); kfree(iw);
...@@ -309,6 +310,9 @@ void i2400m_rx_ctl(struct i2400m *i2400m, struct sk_buff *skb_rx, ...@@ -309,6 +310,9 @@ void i2400m_rx_ctl(struct i2400m *i2400m, struct sk_buff *skb_rx,
skb_get(skb_rx); skb_get(skb_rx);
i2400m_queue_work(i2400m, i2400m_report_hook_work, i2400m_queue_work(i2400m, i2400m_report_hook_work,
GFP_KERNEL, &args, sizeof(args)); GFP_KERNEL, &args, sizeof(args));
if (unlikely(i2400m->trace_msg_from_user))
wimax_msg(&i2400m->wimax_dev, "echo",
l3l4_hdr, size, GFP_KERNEL);
result = wimax_msg(&i2400m->wimax_dev, NULL, l3l4_hdr, size, result = wimax_msg(&i2400m->wimax_dev, NULL, l3l4_hdr, size,
GFP_KERNEL); GFP_KERNEL);
if (result < 0) if (result < 0)
......
...@@ -409,19 +409,19 @@ int i2400ms_probe(struct sdio_func *func, ...@@ -409,19 +409,19 @@ int i2400ms_probe(struct sdio_func *func,
i2400m->bus_fw_names = i2400ms_bus_fw_names; i2400m->bus_fw_names = i2400ms_bus_fw_names;
i2400m->bus_bm_mac_addr_impaired = 1; i2400m->bus_bm_mac_addr_impaired = 1;
result = i2400ms_enable_function(i2400ms->func);
if (result < 0) {
dev_err(dev, "Cannot enable SDIO function: %d\n", result);
goto error_func_enable;
}
sdio_claim_host(func); sdio_claim_host(func);
result = sdio_set_block_size(func, I2400MS_BLK_SIZE); result = sdio_set_block_size(func, I2400MS_BLK_SIZE);
sdio_release_host(func);
if (result < 0) { if (result < 0) {
dev_err(dev, "Failed to set block size: %d\n", result); dev_err(dev, "Failed to set block size: %d\n", result);
goto error_set_blk_size; goto error_set_blk_size;
} }
sdio_release_host(func);
result = i2400ms_enable_function(i2400ms->func);
if (result < 0) {
dev_err(dev, "Cannot enable SDIO function: %d\n", result);
goto error_func_enable;
}
result = i2400m_setup(i2400m, I2400M_BRI_NO_REBOOT); result = i2400m_setup(i2400m, I2400M_BRI_NO_REBOOT);
if (result < 0) { if (result < 0) {
...@@ -440,12 +440,12 @@ int i2400ms_probe(struct sdio_func *func, ...@@ -440,12 +440,12 @@ int i2400ms_probe(struct sdio_func *func,
error_debugfs_add: error_debugfs_add:
i2400m_release(i2400m); i2400m_release(i2400m);
error_setup: error_setup:
sdio_set_drvdata(func, NULL);
sdio_claim_host(func); sdio_claim_host(func);
error_set_blk_size:
sdio_disable_func(func); sdio_disable_func(func);
sdio_release_host(func); sdio_release_host(func);
error_func_enable: error_func_enable:
error_set_blk_size:
sdio_set_drvdata(func, NULL);
free_netdev(net_dev); free_netdev(net_dev);
error_alloc_netdev: error_alloc_netdev:
return result; return result;
......
...@@ -505,27 +505,52 @@ int i2400mu_suspend(struct usb_interface *iface, pm_message_t pm_msg) ...@@ -505,27 +505,52 @@ int i2400mu_suspend(struct usb_interface *iface, pm_message_t pm_msg)
#ifdef CONFIG_PM #ifdef CONFIG_PM
struct usb_device *usb_dev = i2400mu->usb_dev; struct usb_device *usb_dev = i2400mu->usb_dev;
#endif #endif
unsigned is_autosuspend = 0;
struct i2400m *i2400m = &i2400mu->i2400m; struct i2400m *i2400m = &i2400mu->i2400m;
#ifdef CONFIG_PM
if (usb_dev->auto_pm > 0)
is_autosuspend = 1;
#endif
d_fnstart(3, dev, "(iface %p pm_msg %u)\n", iface, pm_msg.event); d_fnstart(3, dev, "(iface %p pm_msg %u)\n", iface, pm_msg.event);
if (i2400m->updown == 0) if (i2400m->updown == 0)
goto no_firmware; goto no_firmware;
d_printf(1, dev, "fw up, requesting standby\n"); if (i2400m->state == I2400M_SS_DATA_PATH_CONNECTED && is_autosuspend) {
/* ugh -- the device is connected and this suspend
* request is an autosuspend one (not a system standby
* / hibernate).
*
* The only way the device can go to standby is if the
* link with the base station is in IDLE mode; that
* were the case, we'd be in status
* I2400M_SS_CONNECTED_IDLE. But we are not.
*
* If we *tell* him to go power save now, it'll reset
* as a precautionary measure, so if this is an
* autosuspend thing, say no and it'll come back
* later, when the link is IDLE
*/
result = -EBADF;
d_printf(1, dev, "fw up, link up, not-idle, autosuspend: "
"not entering powersave\n");
goto error_not_now;
}
d_printf(1, dev, "fw up: entering powersave\n");
atomic_dec(&i2400mu->do_autopm); atomic_dec(&i2400mu->do_autopm);
result = i2400m_cmd_enter_powersave(i2400m); result = i2400m_cmd_enter_powersave(i2400m);
atomic_inc(&i2400mu->do_autopm); atomic_inc(&i2400mu->do_autopm);
#ifdef CONFIG_PM if (result < 0 && !is_autosuspend) {
if (result < 0 && usb_dev->auto_pm == 0) {
/* System suspend, can't fail */ /* System suspend, can't fail */
dev_err(dev, "failed to suspend, will reset on resume\n"); dev_err(dev, "failed to suspend, will reset on resume\n");
result = 0; result = 0;
} }
#endif
if (result < 0) if (result < 0)
goto error_enter_powersave; goto error_enter_powersave;
i2400mu_notification_release(i2400mu); i2400mu_notification_release(i2400mu);
d_printf(1, dev, "fw up, got standby\n"); d_printf(1, dev, "powersave requested\n");
error_enter_powersave: error_enter_powersave:
error_not_now:
no_firmware: no_firmware:
d_fnend(3, dev, "(iface %p pm_msg %u) = %d\n", d_fnend(3, dev, "(iface %p pm_msg %u) = %d\n",
iface, pm_msg.event, result); iface, pm_msg.event, result);
......
...@@ -59,7 +59,7 @@ enum { ...@@ -59,7 +59,7 @@ enum {
* M - Major: change if removing or modifying an existing call. * M - Major: change if removing or modifying an existing call.
* m - minor: change when adding a new call * m - minor: change when adding a new call
*/ */
WIMAX_GNL_VERSION = 00, WIMAX_GNL_VERSION = 01,
/* Generic NetLink attributes */ /* Generic NetLink attributes */
WIMAX_GNL_ATTR_INVALID = 0x00, WIMAX_GNL_ATTR_INVALID = 0x00,
WIMAX_GNL_ATTR_MAX = 10, WIMAX_GNL_ATTR_MAX = 10,
...@@ -78,6 +78,7 @@ enum { ...@@ -78,6 +78,7 @@ enum {
WIMAX_GNL_OP_RFKILL, /* Run wimax_rfkill() */ WIMAX_GNL_OP_RFKILL, /* Run wimax_rfkill() */
WIMAX_GNL_OP_RESET, /* Run wimax_rfkill() */ WIMAX_GNL_OP_RESET, /* Run wimax_rfkill() */
WIMAX_GNL_RE_STATE_CHANGE, /* Report: status change */ WIMAX_GNL_RE_STATE_CHANGE, /* Report: status change */
WIMAX_GNL_OP_STATE_GET, /* Request for current state */
}; };
...@@ -113,6 +114,10 @@ enum { ...@@ -113,6 +114,10 @@ enum {
WIMAX_GNL_RESET_IFIDX = 1, WIMAX_GNL_RESET_IFIDX = 1,
}; };
/* Atributes for wimax_state_get() */
enum {
WIMAX_GNL_STGET_IFIDX = 1,
};
/* /*
* Attributes for the Report State Change * Attributes for the Report State Change
......
...@@ -6,6 +6,7 @@ wimax-y := \ ...@@ -6,6 +6,7 @@ wimax-y := \
op-msg.o \ op-msg.o \
op-reset.o \ op-reset.o \
op-rfkill.o \ op-rfkill.o \
op-state-get.o \
stack.o stack.o
wimax-$(CONFIG_DEBUG_FS) += debugfs.o wimax-$(CONFIG_DEBUG_FS) += debugfs.o
......
...@@ -36,6 +36,7 @@ enum d_module { ...@@ -36,6 +36,7 @@ enum d_module {
D_SUBMODULE_DECLARE(op_msg), D_SUBMODULE_DECLARE(op_msg),
D_SUBMODULE_DECLARE(op_reset), D_SUBMODULE_DECLARE(op_reset),
D_SUBMODULE_DECLARE(op_rfkill), D_SUBMODULE_DECLARE(op_rfkill),
D_SUBMODULE_DECLARE(op_state_get),
D_SUBMODULE_DECLARE(stack), D_SUBMODULE_DECLARE(stack),
}; };
......
...@@ -61,6 +61,7 @@ int wimax_debugfs_add(struct wimax_dev *wimax_dev) ...@@ -61,6 +61,7 @@ int wimax_debugfs_add(struct wimax_dev *wimax_dev)
__debugfs_register("wimax_dl_", op_msg, dentry); __debugfs_register("wimax_dl_", op_msg, dentry);
__debugfs_register("wimax_dl_", op_reset, dentry); __debugfs_register("wimax_dl_", op_reset, dentry);
__debugfs_register("wimax_dl_", op_rfkill, dentry); __debugfs_register("wimax_dl_", op_rfkill, dentry);
__debugfs_register("wimax_dl_", op_state_get, dentry);
__debugfs_register("wimax_dl_", stack, dentry); __debugfs_register("wimax_dl_", stack, dentry);
result = 0; result = 0;
out: out:
......
...@@ -108,6 +108,12 @@ ...@@ -108,6 +108,12 @@
* Don't use skb_push()/skb_pull()/skb_reserve() on the skb, as * Don't use skb_push()/skb_pull()/skb_reserve() on the skb, as
* wimax_msg_send() depends on skb->data being placed at the * wimax_msg_send() depends on skb->data being placed at the
* beginning of the user message. * beginning of the user message.
*
* Unlike other WiMAX stack calls, this call can be used way early,
* even before wimax_dev_add() is called, as long as the
* wimax_dev->net_dev pointer is set to point to a proper
* net_dev. This is so that drivers can use it early in case they need
* to send stuff around or communicate with user space.
*/ */
struct sk_buff *wimax_msg_alloc(struct wimax_dev *wimax_dev, struct sk_buff *wimax_msg_alloc(struct wimax_dev *wimax_dev,
const char *pipe_name, const char *pipe_name,
...@@ -115,7 +121,7 @@ struct sk_buff *wimax_msg_alloc(struct wimax_dev *wimax_dev, ...@@ -115,7 +121,7 @@ struct sk_buff *wimax_msg_alloc(struct wimax_dev *wimax_dev,
gfp_t gfp_flags) gfp_t gfp_flags)
{ {
int result; int result;
struct device *dev = wimax_dev->net_dev->dev.parent; struct device *dev = wimax_dev_to_dev(wimax_dev);
size_t msg_size; size_t msg_size;
void *genl_msg; void *genl_msg;
struct sk_buff *skb; struct sk_buff *skb;
...@@ -161,7 +167,6 @@ error_genlmsg_put: ...@@ -161,7 +167,6 @@ error_genlmsg_put:
error_new: error_new:
nlmsg_free(skb); nlmsg_free(skb);
return ERR_PTR(result); return ERR_PTR(result);
} }
EXPORT_SYMBOL_GPL(wimax_msg_alloc); EXPORT_SYMBOL_GPL(wimax_msg_alloc);
...@@ -256,10 +261,16 @@ EXPORT_SYMBOL_GPL(wimax_msg_len); ...@@ -256,10 +261,16 @@ EXPORT_SYMBOL_GPL(wimax_msg_len);
* Don't use skb_push()/skb_pull()/skb_reserve() on the skb, as * Don't use skb_push()/skb_pull()/skb_reserve() on the skb, as
* wimax_msg_send() depends on skb->data being placed at the * wimax_msg_send() depends on skb->data being placed at the
* beginning of the user message. * beginning of the user message.
*
* Unlike other WiMAX stack calls, this call can be used way early,
* even before wimax_dev_add() is called, as long as the
* wimax_dev->net_dev pointer is set to point to a proper
* net_dev. This is so that drivers can use it early in case they need
* to send stuff around or communicate with user space.
*/ */
int wimax_msg_send(struct wimax_dev *wimax_dev, struct sk_buff *skb) int wimax_msg_send(struct wimax_dev *wimax_dev, struct sk_buff *skb)
{ {
struct device *dev = wimax_dev->net_dev->dev.parent; struct device *dev = wimax_dev_to_dev(wimax_dev);
void *msg = skb->data; void *msg = skb->data;
size_t size = skb->len; size_t size = skb->len;
might_sleep(); might_sleep();
......
/*
* Linux WiMAX
* Implement and export a method for getting a WiMAX device current state
*
* Copyright (C) 2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
*
* Based on previous WiMAX core work by:
* Copyright (C) 2008 Intel Corporation <linux-wimax@intel.com>
* Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <net/wimax.h>
#include <net/genetlink.h>
#include <linux/wimax.h>
#include <linux/security.h>
#include "wimax-internal.h"
#define D_SUBMODULE op_state_get
#include "debug-levels.h"
static const
struct nla_policy wimax_gnl_state_get_policy[WIMAX_GNL_ATTR_MAX + 1] = {
[WIMAX_GNL_STGET_IFIDX] = {
.type = NLA_U32,
},
};
/*
* Exporting to user space over generic netlink
*
* Parse the state get command from user space, return a combination
* value that describe the current state.
*
* No attributes.
*/
static
int wimax_gnl_doit_state_get(struct sk_buff *skb, struct genl_info *info)
{
int result, ifindex;
struct wimax_dev *wimax_dev;
struct device *dev;
d_fnstart(3, NULL, "(skb %p info %p)\n", skb, info);
result = -ENODEV;
if (info->attrs[WIMAX_GNL_STGET_IFIDX] == NULL) {
printk(KERN_ERR "WIMAX_GNL_OP_STATE_GET: can't find IFIDX "
"attribute\n");
goto error_no_wimax_dev;
}
ifindex = nla_get_u32(info->attrs[WIMAX_GNL_STGET_IFIDX]);
wimax_dev = wimax_dev_get_by_genl_info(info, ifindex);
if (wimax_dev == NULL)
goto error_no_wimax_dev;
dev = wimax_dev_to_dev(wimax_dev);
/* Execute the operation and send the result back to user space */
result = wimax_state_get(wimax_dev);
dev_put(wimax_dev->net_dev);
error_no_wimax_dev:
d_fnend(3, NULL, "(skb %p info %p) = %d\n", skb, info, result);
return result;
}
struct genl_ops wimax_gnl_state_get = {
.cmd = WIMAX_GNL_OP_STATE_GET,
.flags = GENL_ADMIN_PERM,
.policy = wimax_gnl_state_get_policy,
.doit = wimax_gnl_doit_state_get,
.dumpit = NULL,
};
...@@ -402,13 +402,15 @@ EXPORT_SYMBOL_GPL(wimax_dev_init); ...@@ -402,13 +402,15 @@ EXPORT_SYMBOL_GPL(wimax_dev_init);
extern struct genl_ops extern struct genl_ops
wimax_gnl_msg_from_user, wimax_gnl_msg_from_user,
wimax_gnl_reset, wimax_gnl_reset,
wimax_gnl_rfkill; wimax_gnl_rfkill,
wimax_gnl_state_get;
static static
struct genl_ops *wimax_gnl_ops[] = { struct genl_ops *wimax_gnl_ops[] = {
&wimax_gnl_msg_from_user, &wimax_gnl_msg_from_user,
&wimax_gnl_reset, &wimax_gnl_reset,
&wimax_gnl_rfkill, &wimax_gnl_rfkill,
&wimax_gnl_state_get,
}; };
...@@ -533,6 +535,7 @@ struct d_level D_LEVEL[] = { ...@@ -533,6 +535,7 @@ struct d_level D_LEVEL[] = {
D_SUBMODULE_DEFINE(op_msg), D_SUBMODULE_DEFINE(op_msg),
D_SUBMODULE_DEFINE(op_reset), D_SUBMODULE_DEFINE(op_reset),
D_SUBMODULE_DEFINE(op_rfkill), D_SUBMODULE_DEFINE(op_rfkill),
D_SUBMODULE_DEFINE(op_state_get),
D_SUBMODULE_DEFINE(stack), D_SUBMODULE_DEFINE(stack),
}; };
size_t D_LEVEL_SIZE = ARRAY_SIZE(D_LEVEL); size_t D_LEVEL_SIZE = ARRAY_SIZE(D_LEVEL);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment