Skip to content

Commit

Permalink
wimax/i2400m: implement RX reorder support
Browse files Browse the repository at this point in the history
Allow the device to give the driver RX data with reorder information.

When that is done, the device will indicate the driver if a packet has
to be held in a (sorted) queue. It will also tell the driver when held
packets have to be released to the OS.

This is done to improve the WiMAX-protocol level retransmission
support when missing frames are detected.

The code docs provide details about the implementation.

In general, this just hooks into the RX path in rx.c; if a packet with
the reorder bit in the RX header is detected, the reorder information
in the header is extracted and one of the four main reorder operations
are executed. In one case (queue) no packet will be delivered to the
networking stack, just queued, whereas in the others (reset, update_ws
and queue_update_ws), queued packet might be delivered depending on
the window start for the specific queue.

The modifications to files other than rx.c are:

- control.c: during device initialization, enable reordering support
  if the rx_reorder_disabled module parameter is not enabled

- driver.c: expose a rx_reorder_disable module parameter and call
  i2400m_rx_setup/release() to initialize/shutdown RX reorder
  support.

- i2400m.h: introduce members in 'struct i2400m' needed for
  implementing reorder support.

- linux/i2400m.h: introduce TLVs, commands and constant definitions
  related to RX reorder

Last but not least, the rx reorder code includes an small circular log
where the last N reorder operations are recorded to be displayed in
case of inconsistency. Otherwise diagnosing issues would be almost
impossible.

Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Inaky Perez-Gonzalez authored and David S. Miller committed Mar 2, 2009
1 parent 61b8d26 commit c747583
Show file tree
Hide file tree
Showing 5 changed files with 723 additions and 30 deletions.
14 changes: 14 additions & 0 deletions drivers/net/wimax/i2400m/control.c
Original file line number Diff line number Diff line change
Expand Up @@ -1312,10 +1312,12 @@ int i2400m_dev_initialize(struct i2400m *i2400m)
struct i2400m_tlv_config_idle_parameters idle_params;
struct i2400m_tlv_config_idle_timeout idle_timeout;
struct i2400m_tlv_config_d2h_data_format df;
struct i2400m_tlv_config_dl_host_reorder dlhr;
const struct i2400m_tlv_hdr *args[9];
unsigned argc = 0;

d_fnstart(3, dev, "(i2400m %p)\n", i2400m);
/* Disable idle mode? (enabled by default) */
if (i2400m_idle_mode_disabled) {
if (i2400m_le_v1_3(i2400m)) {
idle_params.hdr.type =
Expand All @@ -1335,12 +1337,24 @@ int i2400m_dev_initialize(struct i2400m *i2400m)
}
}
if (i2400m_ge_v1_4(i2400m)) {
/* Enable extended RX data format? */
df.hdr.type =
cpu_to_le16(I2400M_TLV_CONFIG_D2H_DATA_FORMAT);
df.hdr.length = cpu_to_le16(
sizeof(df) - sizeof(df.hdr));
df.format = 1;
args[argc++] = &df.hdr;

/* Enable RX data reordering?
* (switch flipped in rx.c:i2400m_rx_setup() after fw upload) */
if (i2400m->rx_reorder) {
dlhr.hdr.type =
cpu_to_le16(I2400M_TLV_CONFIG_DL_HOST_REORDER);
dlhr.hdr.length = cpu_to_le16(
sizeof(dlhr) - sizeof(dlhr.hdr));
dlhr.reorder = 1;
args[argc++] = &dlhr.hdr;
}
}
result = i2400m_set_init_config(i2400m, args, argc);
if (result < 0)
Expand Down
11 changes: 11 additions & 0 deletions drivers/net/wimax/i2400m/driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ MODULE_PARM_DESC(idle_mode_disabled,
"If true, the device will not enable idle mode negotiation "
"with the base station (when connected) to save power.");

int i2400m_rx_reorder_disabled; /* 0 (rx reorder enabled) by default */
module_param_named(rx_reorder_disabled, i2400m_rx_reorder_disabled, int, 0644);
MODULE_PARM_DESC(rx_reorder_disabled,
"If true, RX reordering will be disabled.");

/**
* i2400m_queue_work - schedule work on a i2400m's queue
*
Expand Down Expand Up @@ -396,6 +401,9 @@ int __i2400m_dev_start(struct i2400m *i2400m, enum i2400m_bri flags)
result = i2400m_tx_setup(i2400m);
if (result < 0)
goto error_tx_setup;
result = i2400m_rx_setup(i2400m);
if (result < 0)
goto error_rx_setup;
result = i2400m->bus_dev_start(i2400m);
if (result < 0)
goto error_bus_dev_start;
Expand Down Expand Up @@ -430,6 +438,8 @@ int __i2400m_dev_start(struct i2400m *i2400m, enum i2400m_bri flags)
error_create_workqueue:
i2400m->bus_dev_stop(i2400m);
error_bus_dev_start:
i2400m_rx_release(i2400m);
error_rx_setup:
i2400m_tx_release(i2400m);
error_tx_setup:
error_bootstrap:
Expand Down Expand Up @@ -477,6 +487,7 @@ void __i2400m_dev_stop(struct i2400m *i2400m)
i2400m->ready = 0;
destroy_workqueue(i2400m->work_queue);
i2400m->bus_dev_stop(i2400m);
i2400m_rx_release(i2400m);
i2400m_tx_release(i2400m);
wimax_state_change(wimax_dev, WIMAX_ST_DOWN);
d_fnend(3, dev, "(i2400m %p) = 0\n", i2400m);
Expand Down
19 changes: 18 additions & 1 deletion drivers/net/wimax/i2400m/i2400m.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ enum i2400m_reset_type {
};

struct i2400m_reset_ctx;
struct i2400m_roq;

/**
* struct i2400m - descriptor for an Intel 2400m
Expand Down Expand Up @@ -257,6 +258,9 @@ struct i2400m_reset_ctx;
* force this to be the first field so that we can get from
* netdev_priv() the right pointer.
*
* @rx_reorder: 1 if RX reordering is enabled; this can only be
* set at probe time.
*
* @state: device's state (as reported by it)
*
* @state_wq: waitqueue that is woken up whenever the state changes
Expand Down Expand Up @@ -313,6 +317,12 @@ struct i2400m_reset_ctx;
*
* @rx_size_max: buggest RX message received.
*
* @rx_roq: RX ReOrder queues. (fw >= v1.4) When packets are received
* out of order, the device will ask the driver to hold certain
* packets until the ones that are received out of order can be
* delivered. Then the driver can release them to the host. See
* drivers/net/i2400m/rx.c for details.
*
* @init_mutex: Mutex used for serializing the device bringup
* 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
Expand Down Expand Up @@ -377,6 +387,7 @@ struct i2400m {
unsigned boot_mode:1; /* is the device in boot mode? */
unsigned sboot:1; /* signed or unsigned fw boot */
unsigned ready:1; /* all probing steps done */
unsigned rx_reorder:1; /* RX reorder is enabled */
u8 trace_msg_from_user; /* echo rx msgs to 'trace' pipe */
/* typed u8 so debugfs/u8 can tweak */
enum i2400m_system_state state;
Expand Down Expand Up @@ -405,10 +416,11 @@ struct i2400m {
unsigned tx_pl_num, tx_pl_max, tx_pl_min,
tx_num, tx_size_acc, tx_size_min, tx_size_max;

/* RX stats */
/* RX stuff */
spinlock_t rx_lock; /* protect RX state */
unsigned rx_pl_num, rx_pl_max, rx_pl_min,
rx_num, rx_size_acc, rx_size_min, rx_size_max;
struct i2400m_roq *rx_roq; /* not under rx_lock! */

struct mutex msg_mutex; /* serialize command execution */
struct completion msg_completion;
Expand Down Expand Up @@ -442,6 +454,7 @@ void i2400m_init(struct i2400m *i2400m)
wimax_dev_init(&i2400m->wimax_dev);

i2400m->boot_mode = 1;
i2400m->rx_reorder = 1;
init_waitqueue_head(&i2400m->state_wq);

spin_lock_init(&i2400m->tx_lock);
Expand Down Expand Up @@ -591,6 +604,9 @@ extern int i2400m_tx_setup(struct i2400m *);
extern void i2400m_wake_tx_work(struct work_struct *);
extern void i2400m_tx_release(struct i2400m *);

extern int i2400m_rx_setup(struct i2400m *);
extern void i2400m_rx_release(struct i2400m *);

extern void i2400m_net_rx(struct i2400m *, struct sk_buff *, unsigned,
const void *, int);
extern void i2400m_net_erx(struct i2400m *, struct sk_buff *,
Expand Down Expand Up @@ -788,6 +804,7 @@ void __i2400m_msleep(unsigned ms)
/* Module parameters */

extern int i2400m_idle_mode_disabled;
extern int i2400m_rx_reorder_disabled;


#endif /* #ifndef __I2400M_H__ */
Loading

0 comments on commit c747583

Please sign in to comment.