Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
1cdc5abf
Commit
1cdc5abf
authored
May 15, 2010
by
David S. Miller
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' of
git://git.kernel.org/pub/scm/linux/kernel/git/inaky/wimax
parents
e0f43752
0fb0a4f0
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
480 additions
and
117 deletions
+480
-117
drivers/net/wimax/i2400m/control.c
drivers/net/wimax/i2400m/control.c
+15
-0
drivers/net/wimax/i2400m/driver.c
drivers/net/wimax/i2400m/driver.c
+128
-37
drivers/net/wimax/i2400m/i2400m-sdio.h
drivers/net/wimax/i2400m/i2400m-sdio.h
+4
-1
drivers/net/wimax/i2400m/i2400m.h
drivers/net/wimax/i2400m/i2400m.h
+73
-9
drivers/net/wimax/i2400m/netdev.c
drivers/net/wimax/i2400m/netdev.c
+5
-7
drivers/net/wimax/i2400m/rx.c
drivers/net/wimax/i2400m/rx.c
+74
-35
drivers/net/wimax/i2400m/sdio-tx.c
drivers/net/wimax/i2400m/sdio-tx.c
+28
-7
drivers/net/wimax/i2400m/sdio.c
drivers/net/wimax/i2400m/sdio.c
+7
-0
drivers/net/wimax/i2400m/tx.c
drivers/net/wimax/i2400m/tx.c
+134
-19
drivers/net/wimax/i2400m/usb.c
drivers/net/wimax/i2400m/usb.c
+11
-1
net/wimax/stack.c
net/wimax/stack.c
+1
-1
No files found.
drivers/net/wimax/i2400m/control.c
View file @
1cdc5abf
...
...
@@ -83,6 +83,21 @@
#define D_SUBMODULE control
#include "debug-levels.h"
static
int
i2400m_idle_mode_disabled
;
/* 0 (idle mode enabled) by default */
module_param_named
(
idle_mode_disabled
,
i2400m_idle_mode_disabled
,
int
,
0644
);
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."
);
/* 0 (power saving enabled) by default */
static
int
i2400m_power_save_disabled
;
module_param_named
(
power_save_disabled
,
i2400m_power_save_disabled
,
int
,
0644
);
MODULE_PARM_DESC
(
power_save_disabled
,
"If true, the driver will not tell the device to enter "
"power saving mode when it reports it is ready for it. "
"False by default (so the device is told to do power "
"saving)."
);
int
i2400m_passive_mode
;
/* 0 (passive mode disabled) by default */
module_param_named
(
passive_mode
,
i2400m_passive_mode
,
int
,
0644
);
MODULE_PARM_DESC
(
passive_mode
,
...
...
drivers/net/wimax/i2400m/driver.c
View file @
1cdc5abf
...
...
@@ -75,25 +75,6 @@
#include "debug-levels.h"
int
i2400m_idle_mode_disabled
;
/* 0 (idle mode enabled) by default */
module_param_named
(
idle_mode_disabled
,
i2400m_idle_mode_disabled
,
int
,
0644
);
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."
);
int
i2400m_power_save_disabled
;
/* 0 (power saving enabled) by default */
module_param_named
(
power_save_disabled
,
i2400m_power_save_disabled
,
int
,
0644
);
MODULE_PARM_DESC
(
power_save_disabled
,
"If true, the driver will not tell the device to enter "
"power saving mode when it reports it is ready for it. "
"False by default (so the device is told to do power "
"saving)."
);
static
char
i2400m_debug_params
[
128
];
module_param_string
(
debug
,
i2400m_debug_params
,
sizeof
(
i2400m_debug_params
),
0644
);
...
...
@@ -395,6 +376,16 @@ int __i2400m_dev_start(struct i2400m *i2400m, enum i2400m_bri flags)
result
=
i2400m_dev_initialize
(
i2400m
);
if
(
result
<
0
)
goto
error_dev_initialize
;
/* We don't want any additional unwanted error recovery triggered
* from any other context so if anything went wrong before we come
* here, let's keep i2400m->error_recovery untouched and leave it to
* dev_reset_handle(). See dev_reset_handle(). */
atomic_dec
(
&
i2400m
->
error_recovery
);
/* Every thing works so far, ok, now we are ready to
* take error recovery if it's required. */
/* At this point, reports will come for the device and set it
* to the right state if it is different than UNINITIALIZED */
d_fnend
(
3
,
dev
,
"(net_dev %p [i2400m %p]) = %d
\n
"
,
...
...
@@ -403,10 +394,10 @@ int __i2400m_dev_start(struct i2400m *i2400m, enum i2400m_bri flags)
error_dev_initialize:
error_check_mac_addr:
error_fw_check:
i2400m
->
ready
=
0
;
wmb
();
/* see i2400m->ready's documentation */
flush_workqueue
(
i2400m
->
work_queue
);
error_fw_check:
if
(
i2400m
->
bus_dev_stop
)
i2400m
->
bus_dev_stop
(
i2400m
);
error_bus_dev_start:
...
...
@@ -436,7 +427,8 @@ int i2400m_dev_start(struct i2400m *i2400m, enum i2400m_bri bm_flags)
result
=
__i2400m_dev_start
(
i2400m
,
bm_flags
);
if
(
result
>=
0
)
{
i2400m
->
updown
=
1
;
wmb
();
/* see i2400m->updown's documentation */
i2400m
->
alive
=
1
;
wmb
();
/* see i2400m->updown and i2400m->alive's doc */
}
}
mutex_unlock
(
&
i2400m
->
init_mutex
);
...
...
@@ -497,7 +489,8 @@ void i2400m_dev_stop(struct i2400m *i2400m)
if
(
i2400m
->
updown
)
{
__i2400m_dev_stop
(
i2400m
);
i2400m
->
updown
=
0
;
wmb
();
/* see i2400m->updown's documentation */
i2400m
->
alive
=
0
;
wmb
();
/* see i2400m->updown and i2400m->alive's doc */
}
mutex_unlock
(
&
i2400m
->
init_mutex
);
}
...
...
@@ -617,12 +610,12 @@ int i2400m_post_reset(struct i2400m *i2400m)
error_dev_start:
if
(
i2400m
->
bus_release
)
i2400m
->
bus_release
(
i2400m
);
error_bus_setup:
/* even if the device was up, it could not be recovered, so we
* mark it as down. */
i2400m
->
updown
=
0
;
wmb
();
/* see i2400m->updown's documentation */
mutex_unlock
(
&
i2400m
->
init_mutex
);
error_bus_setup:
d_fnend
(
3
,
dev
,
"(i2400m %p) = %d
\n
"
,
i2400m
,
result
);
return
result
;
}
...
...
@@ -669,6 +662,9 @@ void __i2400m_dev_reset_handle(struct work_struct *ws)
d_fnstart
(
3
,
dev
,
"(ws %p i2400m %p reason %s)
\n
"
,
ws
,
i2400m
,
reason
);
i2400m
->
boot_mode
=
1
;
wmb
();
/* Make sure i2400m_msg_to_dev() sees boot_mode */
result
=
0
;
if
(
mutex_trylock
(
&
i2400m
->
init_mutex
)
==
0
)
{
/* We are still in i2400m_dev_start() [let it fail] or
...
...
@@ -679,32 +675,62 @@ void __i2400m_dev_reset_handle(struct work_struct *ws)
complete
(
&
i2400m
->
msg_completion
);
goto
out
;
}
if
(
i2400m
->
updown
==
0
)
{
dev_info
(
dev
,
"%s: device is down, doing nothing
\n
"
,
reason
);
goto
out_unlock
;
}
dev_err
(
dev
,
"%s: reinitializing driver
\n
"
,
reason
);
__i2400m_dev_stop
(
i2400m
);
result
=
__i2400m_dev_start
(
i2400m
,
I2400M_BRI_SOFT
|
I2400M_BRI_MAC_REINIT
);
if
(
result
<
0
)
{
rmb
();
if
(
i2400m
->
updown
)
{
__i2400m_dev_stop
(
i2400m
);
i2400m
->
updown
=
0
;
wmb
();
/* see i2400m->updown's documentation */
dev_err
(
dev
,
"%s: cannot start the device: %d
\n
"
,
reason
,
result
);
result
=
-
EUCLEAN
;
}
out_unlock:
if
(
i2400m
->
alive
)
{
result
=
__i2400m_dev_start
(
i2400m
,
I2400M_BRI_SOFT
|
I2400M_BRI_MAC_REINIT
);
if
(
result
<
0
)
{
dev_err
(
dev
,
"%s: cannot start the device: %d
\n
"
,
reason
,
result
);
result
=
-
EUCLEAN
;
if
(
atomic_read
(
&
i2400m
->
bus_reset_retries
)
>=
I2400M_BUS_RESET_RETRIES
)
{
result
=
-
ENODEV
;
dev_err
(
dev
,
"tried too many times to "
"reset the device, giving up
\n
"
);
}
}
}
if
(
i2400m
->
reset_ctx
)
{
ctx
->
result
=
result
;
complete
(
&
ctx
->
completion
);
}
mutex_unlock
(
&
i2400m
->
init_mutex
);
if
(
result
==
-
EUCLEAN
)
{
/*
* We come here because the reset during operational mode
* wasn't successully done and need to proceed to a bus
* reset. For the dev_reset_handle() to be able to handle
* the reset event later properly, we restore boot_mode back
* to the state before previous reset. ie: just like we are
* issuing the bus reset for the first time
*/
i2400m
->
boot_mode
=
0
;
wmb
();
atomic_inc
(
&
i2400m
->
bus_reset_retries
);
/* ops, need to clean up [w/ init_mutex not held] */
result
=
i2400m_reset
(
i2400m
,
I2400M_RT_BUS
);
if
(
result
>=
0
)
result
=
-
ENODEV
;
}
else
{
rmb
();
if
(
i2400m
->
alive
)
{
/* great, we expect the device state up and
* dev_start() actually brings the device state up */
i2400m
->
updown
=
1
;
wmb
();
atomic_set
(
&
i2400m
->
bus_reset_retries
,
0
);
}
}
out:
i2400m_put
(
i2400m
);
...
...
@@ -728,14 +754,72 @@ void __i2400m_dev_reset_handle(struct work_struct *ws)
*/
int
i2400m_dev_reset_handle
(
struct
i2400m
*
i2400m
,
const
char
*
reason
)
{
i2400m
->
boot_mode
=
1
;
wmb
();
/* Make sure i2400m_msg_to_dev() sees boot_mode */
return
i2400m_schedule_work
(
i2400m
,
__i2400m_dev_reset_handle
,
GFP_ATOMIC
,
&
reason
,
sizeof
(
reason
));
}
EXPORT_SYMBOL_GPL
(
i2400m_dev_reset_handle
);
/*
* The actual work of error recovery.
*
* The current implementation of error recovery is to trigger a bus reset.
*/
static
void
__i2400m_error_recovery
(
struct
work_struct
*
ws
)
{
struct
i2400m_work
*
iw
=
container_of
(
ws
,
struct
i2400m_work
,
ws
);
struct
i2400m
*
i2400m
=
iw
->
i2400m
;
i2400m_reset
(
i2400m
,
I2400M_RT_BUS
);
i2400m_put
(
i2400m
);
kfree
(
iw
);
return
;
}
/*
* Schedule a work struct for error recovery.
*
* The intention of error recovery is to bring back the device to some
* known state whenever TX sees -110 (-ETIMEOUT) on copying the data to
* the device. The TX failure could mean a device bus stuck, so the current
* error recovery implementation is to trigger a bus reset to the device
* and hopefully it can bring back the device.
*
* The actual work of error recovery has to be in a thread context because
* it is kicked off in the TX thread (i2400ms->tx_workqueue) which is to be
* destroyed by the error recovery mechanism (currently a bus reset).
*
* Also, there may be already a queue of TX works that all hit
* the -ETIMEOUT error condition because the device is stuck already.
* Since bus reset is used as the error recovery mechanism and we don't
* want consecutive bus resets simply because the multiple TX works
* in the queue all hit the same device erratum, the flag "error_recovery"
* is introduced for preventing unwanted consecutive bus resets.
*
* Error recovery shall only be invoked again if previous one was completed.
* The flag error_recovery is set when error recovery mechanism is scheduled,
* and is checked when we need to schedule another error recovery. If it is
* in place already, then we shouldn't schedule another one.
*/
void
i2400m_error_recovery
(
struct
i2400m
*
i2400m
)
{
struct
device
*
dev
=
i2400m_dev
(
i2400m
);
if
(
atomic_add_return
(
1
,
&
i2400m
->
error_recovery
)
==
1
)
{
if
(
i2400m_schedule_work
(
i2400m
,
__i2400m_error_recovery
,
GFP_ATOMIC
,
NULL
,
0
)
<
0
)
{
dev_err
(
dev
,
"run out of memory for "
"scheduling an error recovery ?
\n
"
);
atomic_dec
(
&
i2400m
->
error_recovery
);
}
}
else
atomic_dec
(
&
i2400m
->
error_recovery
);
return
;
}
EXPORT_SYMBOL_GPL
(
i2400m_error_recovery
);
/*
* Alloc the command and ack buffers for boot mode
*
...
...
@@ -802,6 +886,13 @@ void i2400m_init(struct i2400m *i2400m)
mutex_init
(
&
i2400m
->
init_mutex
);
/* wake_tx_ws is initialized in i2400m_tx_setup() */
atomic_set
(
&
i2400m
->
bus_reset_retries
,
0
);
i2400m
->
alive
=
0
;
/* initialize error_recovery to 1 for denoting we
* are not yet ready to take any error recovery */
atomic_set
(
&
i2400m
->
error_recovery
,
1
);
}
EXPORT_SYMBOL_GPL
(
i2400m_init
);
...
...
drivers/net/wimax/i2400m/i2400m-sdio.h
View file @
1cdc5abf
...
...
@@ -99,7 +99,10 @@ enum {
*
* @tx_workqueue: workqeueue used for data TX; we don't use the
* system's workqueue as that might cause deadlocks with code in
* the bus-generic driver.
* the bus-generic driver. The read/write operation to the queue
* is protected with spinlock (tx_lock in struct i2400m) to avoid
* the queue being destroyed in the middle of a the queue read/write
* operation.
*
* @debugfs_dentry: dentry for the SDIO specific debugfs files
*
...
...
drivers/net/wimax/i2400m/i2400m.h
View file @
1cdc5abf
...
...
@@ -160,6 +160,16 @@
#include <linux/wimax/i2400m.h>
#include <asm/byteorder.h>
enum
{
/* netdev interface */
/*
* Out of NWG spec (R1_v1.2.2), 3.3.3 ASN Bearer Plane MTU Size
*
* The MTU is 1400 or less
*/
I2400M_MAX_MTU
=
1400
,
};
/* Misc constants */
enum
{
/* Size of the Boot Mode Command buffer */
...
...
@@ -167,6 +177,11 @@ enum {
I2400M_BM_ACK_BUF_SIZE
=
256
,
};
enum
{
/* Maximum number of bus reset can be retried */
I2400M_BUS_RESET_RETRIES
=
3
,
};
/**
* struct i2400m_poke_table - Hardware poke table for the Intel 2400m
*
...
...
@@ -227,6 +242,11 @@ struct i2400m_barker_db;
* so we have a tx_blk_size variable that the bus layer sets to
* tell the engine how much of that we need.
*
* @bus_tx_room_min: [fill] Minimum room required while allocating
* TX queue's buffer space for message header. SDIO requires
* 224 bytes and USB 16 bytes. Refer bus specific driver code
* for details.
*
* @bus_pl_size_max: [fill] Maximum payload size.
*
* @bus_setup: [optional fill] Function called by the bus-generic code
...
...
@@ -397,7 +417,7 @@ struct i2400m_barker_db;
*
* @tx_size_max: biggest TX message sent.
*
* @rx_lock: spinlock to protect RX members
* @rx_lock: spinlock to protect RX members
and rx_roq_refcount.
*
* @rx_pl_num: total number of payloads received
*
...
...
@@ -421,6 +441,10 @@ struct i2400m_barker_db;
* delivered. Then the driver can release them to the host. See
* drivers/net/i2400m/rx.c for details.
*
* @rx_roq_refcount: refcount rx_roq. This refcounts any access to
* rx_roq thus preventing rx_roq being destroyed when rx_roq
* is being accessed. rx_roq_refcount is protected by rx_lock.
*
* @rx_reports: reports received from the device that couldn't be
* processed because the driver wasn't still ready; when ready,
* they are pulled from here and chewed.
...
...
@@ -507,6 +531,38 @@ struct i2400m_barker_db;
* same.
*
* @pm_notifier: used to register for PM events
*
* @bus_reset_retries: counter for the number of bus resets attempted for
* this boot. It's not for tracking the number of bus resets during
* the whole driver life cycle (from insmod to rmmod) but for the
* number of dev_start() executed until dev_start() returns a success
* (ie: a good boot means a dev_stop() followed by a successful
* dev_start()). dev_reset_handler() increments this counter whenever
* it is triggering a bus reset. It checks this counter to decide if a
* subsequent bus reset should be retried. dev_reset_handler() retries
* the bus reset until dev_start() succeeds or the counter reaches
* I2400M_BUS_RESET_RETRIES. The counter is cleared to 0 in
* dev_reset_handle() when dev_start() returns a success,
* ie: a successul boot is completed.
*
* @alive: flag to denote if the device *should* be alive. This flag is
* everything like @updown (see doc for @updown) except reflecting
* the device state *we expect* rather than the actual state as denoted
* by @updown. It is set 1 whenever @updown is set 1 in dev_start().
* Then the device is expected to be alive all the time
* (i2400m->alive remains 1) until the driver is removed. Therefore
* all the device reboot events detected can be still handled properly
* by either dev_reset_handle() or .pre_reset/.post_reset as long as
* the driver presents. It is set 0 along with @updown in dev_stop().
*
* @error_recovery: flag to denote if we are ready to take an error recovery.
* 0 for ready to take an error recovery; 1 for not ready. It is
* initialized to 1 while probe() since we don't tend to take any error
* recovery during probe(). It is decremented by 1 whenever dev_start()
* succeeds to indicate we are ready to take error recovery from now on.
* It is checked every time we wanna schedule an error recovery. If an
* error recovery is already in place (error_recovery was set 1), we
* should not schedule another one until the last one is done.
*/
struct
i2400m
{
struct
wimax_dev
wimax_dev
;
/* FIRST! See doc */
...
...
@@ -522,6 +578,7 @@ struct i2400m {
wait_queue_head_t
state_wq
;
/* Woken up when on state updates */
size_t
bus_tx_block_size
;
size_t
bus_tx_room_min
;
size_t
bus_pl_size_max
;
unsigned
bus_bm_retries
;
...
...
@@ -550,10 +607,12 @@ struct i2400m {
tx_num
,
tx_size_acc
,
tx_size_min
,
tx_size_max
;
/* RX stuff */
spinlock_t
rx_lock
;
/* protect RX state */
/* protect RX state and rx_roq_refcount */
spinlock_t
rx_lock
;
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
i2400m_roq
*
rx_roq
;
/* access is refcounted */
struct
kref
rx_roq_refcount
;
/* refcount access to rx_roq */
u8
src_mac_addr
[
ETH_HLEN
];
struct
list_head
rx_reports
;
/* under rx_lock! */
struct
work_struct
rx_report_ws
;
...
...
@@ -581,6 +640,16 @@ struct i2400m {
struct
i2400m_barker_db
*
barker
;
struct
notifier_block
pm_notifier
;
/* counting bus reset retries in this boot */
atomic_t
bus_reset_retries
;
/* if the device is expected to be alive */
unsigned
alive
;
/* 0 if we are ready for error recovery; 1 if not ready */
atomic_t
error_recovery
;
};
...
...
@@ -803,6 +872,7 @@ void i2400m_put(struct i2400m *i2400m)
extern
int
i2400m_dev_reset_handle
(
struct
i2400m
*
,
const
char
*
);
extern
int
i2400m_pre_reset
(
struct
i2400m
*
);
extern
int
i2400m_post_reset
(
struct
i2400m
*
);
extern
void
i2400m_error_recovery
(
struct
i2400m
*
);
/*
* _setup()/_release() are called by the probe/disconnect functions of
...
...
@@ -815,7 +885,6 @@ extern int i2400m_rx(struct i2400m *, struct sk_buff *);
extern
struct
i2400m_msg_hdr
*
i2400m_tx_msg_get
(
struct
i2400m
*
,
size_t
*
);
extern
void
i2400m_tx_msg_sent
(
struct
i2400m
*
);
extern
int
i2400m_power_save_disabled
;
/*
* Utility functions
...
...
@@ -922,10 +991,5 @@ extern int i2400m_barker_db_init(const char *);
extern
void
i2400m_barker_db_exit
(
void
);
/* Module parameters */
extern
int
i2400m_idle_mode_disabled
;
extern
int
i2400m_rx_reorder_disabled
;
#endif
/* #ifndef __I2400M_H__ */
drivers/net/wimax/i2400m/netdev.c
View file @
1cdc5abf
...
...
@@ -84,17 +84,15 @@
enum
{
/* netdev interface */
/*
* Out of NWG spec (R1_v1.2.2), 3.3.3 ASN Bearer Plane MTU Size
*
* The MTU is 1400 or less
*/
I2400M_MAX_MTU
=
1400
,
/* 20 secs? yep, this is the maximum timeout that the device
* might take to get out of IDLE / negotiate it with the base
* station. We add 1sec for good measure. */
I2400M_TX_TIMEOUT
=
21
*
HZ
,
I2400M_TX_QLEN
=
5
,
/*
* Experimentation has determined that, 20 to be a good value
* for minimizing the jitter in the throughput.
*/
I2400M_TX_QLEN
=
20
,
};
...
...
drivers/net/wimax/i2400m/rx.c
View file @
1cdc5abf
...
...
@@ -155,6 +155,11 @@
#define D_SUBMODULE rx
#include "debug-levels.h"
static
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."
);
struct
i2400m_report_hook_args
{
struct
sk_buff
*
skb_rx
;
const
struct
i2400m_l3l4_hdr
*
l3l4_hdr
;
...
...
@@ -300,17 +305,16 @@ void i2400m_rx_ctl_ack(struct i2400m *i2400m,
d_printf
(
1
,
dev
,
"Huh? waiter for command reply cancelled
\n
"
);
goto
error_waiter_cancelled
;
}
if
(
ack_skb
==
NULL
)
{
if
(
IS_ERR
(
ack_skb
))
dev_err
(
dev
,
"CMD/GET/SET ack: cannot allocate SKB
\n
"
);
i2400m
->
ack_skb
=
ERR_PTR
(
-
ENOMEM
);
}
else
i2400m
->
ack_skb
=
ack_skb
;
i2400m
->
ack_skb
=
ack_skb
;
spin_unlock_irqrestore
(
&
i2400m
->
rx_lock
,
flags
);
complete
(
&
i2400m
->
msg_completion
);
return
;
error_waiter_cancelled:
kfree_skb
(
ack_skb
);
if
(
!
IS_ERR
(
ack_skb
))
kfree_skb
(
ack_skb
);
error_no_waiter:
spin_unlock_irqrestore
(
&
i2400m
->
rx_lock
,
flags
);
}
...
...
@@ -741,12 +745,12 @@ unsigned __i2400m_roq_update_ws(struct i2400m *i2400m, struct i2400m_roq *roq,
unsigned
new_nws
,
nsn_itr
;
new_nws
=
__i2400m_roq_nsn
(
roq
,
sn
);
if
(
unlikely
(
new_nws
>=
1024
)
&&
d_test
(
1
))
{
dev_err
(
dev
,
"SW BUG? __update_ws new_nws %u (sn %u ws %u)
\n
"
,
new_nws
,
sn
,
roq
->
ws
);
WARN_ON
(
1
);
i2400m_roq_log_dump
(
i2400m
,
roq
);
}
/*
* For type 2(update_window_start) rx messages, there is no
* need to check if the normalized sequence number is greater 1023.
* Simply insert and deliver all packets to the host up to the
* window start.
*/
skb_queue_walk_safe
(
&
roq
->
queue
,
skb_itr
,
tmp_itr
)
{
roq_data_itr
=
(
struct
i2400m_roq_data
*
)
&
skb_itr
->
cb
;
nsn_itr
=
__i2400m_roq_nsn
(
roq
,
roq_data_itr
->
sn
);
...
...
@@ -885,31 +889,51 @@ void i2400m_roq_queue_update_ws(struct i2400m *i2400m, struct i2400m_roq *roq,
i2400m
,
roq
,
skb
,
sn
);
len
=
skb_queue_len
(
&
roq
->
queue
);
nsn
=
__i2400m_roq_nsn
(
roq
,
sn
);
/*
* For type 3(queue_update_window_start) rx messages, there is no
* need to check if the normalized sequence number is greater 1023.
* Simply insert and deliver all packets to the host up to the
* window start.
*/
old_ws
=
roq
->
ws
;
if
(
unlikely
(
nsn
>=
1024
))
{
dev_err
(
dev
,
"SW BUG? queue_update_ws nsn %u (sn %u ws %u)
\n
"
,
nsn
,
sn
,
roq
->
ws
);
i2400m_roq_log_dump
(
i2400m
,
roq
);
i2400m_reset
(
i2400m
,
I2400M_RT_WARM
);
}
else
{
/* if the queue is empty, don't bother as we'd queue
* it and inmediately unqueue it -- just deliver it */
if
(
len
==
0
)
{
struct
i2400m_roq_data
*
roq_data
;
roq_data
=
(
struct
i2400m_roq_data
*
)
&
skb
->
cb
;
i2400m_net_erx
(
i2400m
,
skb
,
roq_data
->
cs
);
}
else
__i2400m_roq_queue
(
i2400m
,
roq
,
skb
,
sn
,
nsn
);
__i2400m_roq_update_ws
(
i2400m
,
roq
,
sn
+
1
);
i2400m_roq_log_add
(
i2400m
,
roq
,
I2400M_RO_TYPE_PACKET_WS
,
old_ws
,
len
,
sn
,
nsn
,
roq
->
ws
);
}
/* If the queue is empty, don't bother as we'd queue
* it and immediately unqueue it -- just deliver it.
*/
if
(
len
==
0
)
{
struct
i2400m_roq_data
*
roq_data
;
roq_data
=
(
struct
i2400m_roq_data
*
)
&
skb
->
cb
;
i2400m_net_erx
(
i2400m
,
skb
,
roq_data
->
cs
);
}
else
__i2400m_roq_queue
(
i2400m
,
roq
,
skb
,
sn
,
nsn
);
__i2400m_roq_update_ws
(
i2400m
,
roq
,
sn
+
1
);
i2400m_roq_log_add
(
i2400m
,
roq
,
I2400M_RO_TYPE_PACKET_WS
,
old_ws
,
len
,
sn
,
nsn
,
roq
->
ws
);
d_fnend
(
2
,
dev
,
"(i2400m %p roq %p skb %p sn %u) = void
\n
"
,
i2400m
,
roq
,
skb
,
sn
);
}
/*
* This routine destroys the memory allocated for rx_roq, when no
* other thread is accessing it. Access to rx_roq is refcounted by
* rx_roq_refcount, hence memory allocated must be destroyed when
* rx_roq_refcount becomes zero. This routine gets executed when
* rx_roq_refcount becomes zero.
*/
void
i2400m_rx_roq_destroy
(
struct
kref
*
ref
)
{
unsigned
itr
;
struct
i2400m
*
i2400m
=
container_of
(
ref
,
struct
i2400m
,
rx_roq_refcount
);
for
(
itr
=
0
;
itr
<
I2400M_RO_CIN
+
1
;
itr
++
)
__skb_queue_purge
(
&
i2400m
->
rx_roq
[
itr
].
queue
);
kfree
(
i2400m
->
rx_roq
[
0
].
log
);
kfree
(
i2400m
->
rx_roq
);
i2400m
->
rx_roq
=
NULL
;
}
/*
* Receive and send up an extended data packet
*
...
...
@@ -963,6 +987,7 @@ void i2400m_rx_edata(struct i2400m *i2400m, struct sk_buff *skb_rx,
unsigned
ro_needed
,
ro_type
,
ro_cin
,
ro_sn
;
struct
i2400m_roq
*
roq
;
struct
i2400m_roq_data
*
roq_data
;
unsigned
long
flags
;
BUILD_BUG_ON
(
ETH_HLEN
>
sizeof
(
*
hdr
));
...
...
@@ -1001,7 +1026,16 @@ void i2400m_rx_edata(struct i2400m *i2400m, struct sk_buff *skb_rx,
ro_cin
=
(
reorder
>>
I2400M_RO_CIN_SHIFT
)
&
I2400M_RO_CIN
;
ro_sn
=
(
reorder
>>
I2400M_RO_SN_SHIFT
)
&
I2400M_RO_SN
;
spin_lock_irqsave
(
&
i2400m
->
rx_lock
,
flags
);
roq
=
&
i2400m
->
rx_roq
[
ro_cin
];
if
(
roq
==
NULL
)
{
kfree_skb
(
skb
);
/* rx_roq is already destroyed */
spin_unlock_irqrestore
(
&
i2400m
->
rx_lock
,
flags
);
goto
error
;
}
kref_get
(
&
i2400m
->
rx_roq_refcount
);
spin_unlock_irqrestore
(
&
i2400m
->
rx_lock
,
flags
);
roq_data
=
(
struct
i2400m_roq_data
*
)
&
skb
->
cb
;
roq_data
->
sn
=
ro_sn
;
roq_data
->
cs
=
cs
;
...
...
@@ -1028,6 +1062,10 @@ void i2400m_rx_edata(struct i2400m *i2400m, struct sk_buff *skb_rx,
default:
dev_err
(
dev
,
"HW BUG? unknown reorder type %u
\n
"
,
ro_type
);
}
spin_lock_irqsave
(
&
i2400m
->
rx_lock
,
flags
);
kref_put
(
&
i2400m
->
rx_roq_refcount
,
i2400m_rx_roq_destroy
);
spin_unlock_irqrestore
(
&
i2400m
->
rx_lock
,
flags
);
}
else
i2400m_net_erx
(
i2400m
,
skb
,
cs
);
...
...
@@ -1337,6 +1375,7 @@ int i2400m_rx_setup(struct i2400m *i2400m)
__i2400m_roq_init
(
&
i2400m
->
rx_roq
[
itr
]);
i2400m
->
rx_roq
[
itr
].
log
=
&
rd
[
itr
];
}
kref_init
(
&
i2400m
->
rx_roq_refcount
);
}
return
0
;
...
...
@@ -1350,12 +1389,12 @@ int i2400m_rx_setup(struct i2400m *i2400m)
/* Tear down the RX queue and infrastructure */
void
i2400m_rx_release
(
struct
i2400m
*
i2400m
)
{
unsigned
long
flags
;
if
(
i2400m
->
rx_reorder
)
{
unsigned
itr
;
for
(
itr
=
0
;
itr
<
I2400M_RO_CIN
+
1
;
itr
++
)
__skb_queue_purge
(
&
i2400m
->
rx_roq
[
itr
].
queue
);
kfree
(
i2400m
->
rx_roq
[
0
].
log
);
kfree
(
i2400m
->
rx_roq
);
spin_lock_irqsave
(
&
i2400m
->
rx_lock
,
flags
);
kref_put
(
&
i2400m
->
rx_roq_refcount
,
i2400m_rx_roq_destroy
);
spin_unlock_irqrestore
(
&
i2400m
->
rx_lock
,
flags
);
}
/* at this point, nothing can be received... */
i2400m_report_hook_flush
(
i2400m
);
...
...
drivers/net/wimax/i2400m/sdio-tx.c
View file @
1cdc5abf
...
...
@@ -98,6 +98,10 @@ void i2400ms_tx_submit(struct work_struct *ws)
tx_msg_size
,
result
);
}
if
(
result
==
-
ETIMEDOUT
)
{
i2400m_error_recovery
(
i2400m
);
break
;
}
d_printf
(
2
,
dev
,
"TX: %zub submitted
\n
"
,
tx_msg_size
);
}
...
...
@@ -114,13 +118,17 @@ void i2400ms_bus_tx_kick(struct i2400m *i2400m)
{
struct
i2400ms
*
i2400ms
=
container_of
(
i2400m
,
struct
i2400ms
,
i2400m
);
struct
device
*
dev
=
&
i2400ms
->
func
->
dev
;
unsigned
long
flags
;
d_fnstart
(
3
,
dev
,
"(i2400m %p) = void
\n
"
,
i2400m
);
/* schedule tx work, this is because tx may block, therefore
* it has to run in a thread context.
*/
queue_work
(
i2400ms
->
tx_workqueue
,
&
i2400ms
->
tx_worker
);
spin_lock_irqsave
(
&
i2400m
->
tx_lock
,
flags
);
if
(
i2400ms
->
tx_workqueue
!=
NULL
)
queue_work
(
i2400ms
->
tx_workqueue
,
&
i2400ms
->
tx_worker
);
spin_unlock_irqrestore
(
&
i2400m
->
tx_lock
,
flags
);
d_fnend
(
3
,
dev
,
"(i2400m %p) = void
\n
"
,
i2400m
);
}
...
...
@@ -130,27 +138,40 @@ int i2400ms_tx_setup(struct i2400ms *i2400ms)
int
result
;
struct
device
*
dev
=
&
i2400ms
->
func
->
dev
;
struct
i2400m
*
i2400m
=
&
i2400ms
->
i2400m
;
struct
workqueue_struct
*
tx_workqueue
;
unsigned
long
flags
;
d_fnstart
(
5
,
dev
,
"(i2400ms %p)
\n
"
,
i2400ms
);
INIT_WORK
(
&
i2400ms
->
tx_worker
,
i2400ms_tx_submit
);
snprintf
(
i2400ms
->
tx_wq_name
,
sizeof
(
i2400ms
->
tx_wq_name
),
"%s-tx"
,
i2400m
->
wimax_dev
.
name
);
i2400ms
->
tx_workqueue
=
tx_workqueue
=
create_singlethread_workqueue
(
i2400ms
->
tx_wq_name
);
if
(
NULL
==
i2400ms
->
tx_workqueue
)
{
if
(
tx_workqueue
==
NULL
)
{
dev_err
(
dev
,
"TX: failed to create workqueue
\n
"
);
result
=
-
ENOMEM
;
}
else
result
=
0
;
spin_lock_irqsave
(
&
i2400m
->
tx_lock
,
flags
);
i2400ms
->
tx_workqueue
=
tx_workqueue
;
spin_unlock_irqrestore
(
&
i2400m
->
tx_lock
,
flags
);
d_fnend
(
5
,
dev
,
"(i2400ms %p) = %d
\n
"
,
i2400ms
,
result
);
return
result
;
}
void
i2400ms_tx_release
(
struct
i2400ms
*
i2400ms
)
{
if
(
i2400ms
->
tx_workqueue
)
{
destroy_workqueue
(
i2400ms
->
tx_workqueue
);
i2400ms
->
tx_workqueue
=
NULL
;
}
struct
i2400m
*
i2400m
=
&
i2400ms
->
i2400m
;
struct
workqueue_struct
*
tx_workqueue
;
unsigned
long
flags
;
tx_workqueue
=
i2400ms
->
tx_workqueue
;
spin_lock_irqsave
(
&
i2400m
->
tx_lock
,
flags
);
i2400ms
->
tx_workqueue
=
NULL
;
spin_unlock_irqrestore
(
&
i2400m
->
tx_lock
,
flags
);
if
(
tx_workqueue
)
destroy_workqueue
(
tx_workqueue
);
}
drivers/net/wimax/i2400m/sdio.c
View file @
1cdc5abf
...
...
@@ -483,6 +483,13 @@ int i2400ms_probe(struct sdio_func *func,
sdio_set_drvdata
(
func
,
i2400ms
);
i2400m
->
bus_tx_block_size
=
I2400MS_BLK_SIZE
;
/*
* Room required in the TX queue for SDIO message to accommodate
* a smallest payload while allocating header space is 224 bytes,
* which is the smallest message size(the block size 256 bytes)
* minus the smallest message header size(32 bytes).
*/
i2400m
->
bus_tx_room_min
=
I2400MS_BLK_SIZE
-
I2400M_PL_ALIGN
*
2
;
i2400m
->
bus_pl_size_max
=
I2400MS_PL_SIZE_MAX
;
i2400m
->
bus_setup
=
i2400ms_bus_setup
;
i2400m
->
bus_dev_start
=
i2400ms_bus_dev_start
;
...
...
drivers/net/wimax/i2400m/tx.c
View file @
1cdc5abf
...
...
@@ -258,8 +258,10 @@ enum {
* Doc says maximum transaction is 16KiB. If we had 16KiB en
* route and 16KiB being queued, it boils down to needing
* 32KiB.
* 32KiB is insufficient for 1400 MTU, hence increasing
* tx buffer size to 64KiB.
*/
I2400M_TX_BUF_SIZE
=
32768
,
I2400M_TX_BUF_SIZE
=
65536
,
/**
* Message header and payload descriptors have to be 16
* aligned (16 + 4 * N = 16 * M). If we take that average sent
...
...
@@ -270,10 +272,21 @@ enum {
* at the end there are less, we pad up to the nearest
* multiple of 16.
*/
I2400M_TX_PLD_MAX
=
12
,
/*
* According to Intel Wimax i3200, i5x50 and i6x50 specification
* documents, the maximum number of payloads per message can be
* up to 60. Increasing the number of payloads to 60 per message
* helps to accommodate smaller payloads in a single transaction.
*/
I2400M_TX_PLD_MAX
=
60
,
I2400M_TX_PLD_SIZE
=
sizeof
(
struct
i2400m_msg_hdr
)
+
I2400M_TX_PLD_MAX
*
sizeof
(
struct
i2400m_pld
),
I2400M_TX_SKIP
=
0x80000000
,
/*
* According to Intel Wimax i3200, i5x50 and i6x50 specification
* documents, the maximum size of each message can be up to 16KiB.
*/
I2400M_TX_MSG_SIZE
=
16384
,
};
#define TAIL_FULL ((void *)~(unsigned long)NULL)
...
...
@@ -328,6 +341,14 @@ size_t __i2400m_tx_tail_room(struct i2400m *i2400m)
* @padding: ensure that there is at least this many bytes of free
* contiguous space in the fifo. This is needed because later on
* we might need to add padding.
* @try_head: specify either to allocate head room or tail room space
* in the TX FIFO. This boolean is required to avoids a system hang
* due to an infinite loop caused by i2400m_tx_fifo_push().
* The caller must always try to allocate tail room space first by
* calling this routine with try_head = 0. In case if there
* is not enough tail room space but there is enough head room space,
* (i2400m_tx_fifo_push() returns TAIL_FULL) try to allocate head
* room space, by calling this routine again with try_head = 1.
*
* Returns:
*
...
...
@@ -359,6 +380,48 @@ size_t __i2400m_tx_tail_room(struct i2400m *i2400m)
* fail and return TAIL_FULL and let the caller figure out if we wants to
* skip the tail room and try to allocate from the head.
*
* There is a corner case, wherein i2400m_tx_new() can get into
* an infinite loop calling i2400m_tx_fifo_push().
* In certain situations, tx_in would have reached on the top of TX FIFO
* and i2400m_tx_tail_room() returns 0, as described below:
*
* N ___________ tail room is zero
* |<- IN ->|
* | |
* | |
* | |
* | data |
* |<- OUT ->|
* | |
* | |
* | head room |
* 0 -----------
* During such a time, where tail room is zero in the TX FIFO and if there
* is a request to add a payload to TX FIFO, which calls:
* i2400m_tx()
* ->calls i2400m_tx_close()
* ->calls i2400m_tx_skip_tail()
* goto try_new;
* ->calls i2400m_tx_new()
* |----> [try_head:]
* infinite loop | ->calls i2400m_tx_fifo_push()
* | if (tail_room < needed)
* | if (head_room => needed)
* | return TAIL_FULL;
* |<---- goto try_head;
*
* i2400m_tx() calls i2400m_tx_close() to close the message, since there
* is no tail room to accommodate the payload and calls
* i2400m_tx_skip_tail() to skip the tail space. Now i2400m_tx() calls
* i2400m_tx_new() to allocate space for new message header calling
* i2400m_tx_fifo_push() that returns TAIL_FULL, since there is no tail space
* to accommodate the message header, but there is enough head space.
* The i2400m_tx_new() keeps re-retrying by calling i2400m_tx_fifo_push()
* ending up in a loop causing system freeze.
*
* This corner case is avoided by using a try_head boolean,
* as an argument to i2400m_tx_fifo_push().
*
* Note:
*
* Assumes i2400m->tx_lock is taken, and we use that as a barrier
...
...
@@ -367,7 +430,8 @@ size_t __i2400m_tx_tail_room(struct i2400m *i2400m)
* pop data off the queue
*/
static
void
*
i2400m_tx_fifo_push
(
struct
i2400m
*
i2400m
,
size_t
size
,
size_t
padding
)
void
*
i2400m_tx_fifo_push
(
struct
i2400m
*
i2400m
,
size_t
size
,
size_t
padding
,
bool
try_head
)
{
struct
device
*
dev
=
i2400m_dev
(
i2400m
);
size_t
room
,
tail_room
,
needed_size
;
...
...
@@ -382,9 +446,21 @@ void *i2400m_tx_fifo_push(struct i2400m *i2400m, size_t size, size_t padding)
}
/* Is there space at the tail? */
tail_room
=
__i2400m_tx_tail_room
(
i2400m
);
if
(
tail_room
<
needed_size
)
{
if
(
i2400m
->
tx_out
%
I2400M_TX_BUF_SIZE
<
i2400m
->
tx_in
%
I2400M_TX_BUF_SIZE
)
{
if
(
!
try_head
&&
tail_room
<
needed_size
)
{
/*
* If the tail room space is not enough to push the message
* in the TX FIFO, then there are two possibilities:
* 1. There is enough head room space to accommodate
* this message in the TX FIFO.
* 2. There is not enough space in the head room and
* in tail room of the TX FIFO to accommodate the message.
* In the case (1), return TAIL_FULL so that the caller
* can figure out, if the caller wants to push the message
* into the head room space.
* In the case (2), return NULL, indicating that the TX FIFO
* cannot accommodate the message.
*/
if
(
room
-
tail_room
>=
needed_size
)
{
d_printf
(
2
,
dev
,
"fifo push %zu/%zu: tail full
\n
"
,
size
,
padding
);
return
TAIL_FULL
;
/* There might be head space */
...
...
@@ -485,14 +561,25 @@ void i2400m_tx_new(struct i2400m *i2400m)
{
struct
device
*
dev
=
i2400m_dev
(
i2400m
);
struct
i2400m_msg_hdr
*
tx_msg
;
bool
try_head
=
0
;
BUG_ON
(
i2400m
->
tx_msg
!=
NULL
);
/*
* In certain situations, TX queue might have enough space to
* accommodate the new message header I2400M_TX_PLD_SIZE, but
* might not have enough space to accommodate the payloads.
* Adding bus_tx_room_min padding while allocating a new TX message
* increases the possibilities of including at least one payload of the
* size <= bus_tx_room_min.
*/
try_head:
tx_msg
=
i2400m_tx_fifo_push
(
i2400m
,
I2400M_TX_PLD_SIZE
,
0
);
tx_msg
=
i2400m_tx_fifo_push
(
i2400m
,
I2400M_TX_PLD_SIZE
,
i2400m
->
bus_tx_room_min
,
try_head
);
if
(
tx_msg
==
NULL
)
goto
out
;
else
if
(
tx_msg
==
TAIL_FULL
)
{
i2400m_tx_skip_tail
(
i2400m
);
d_printf
(
2
,
dev
,
"new TX message: tail full, trying head
\n
"
);
try_head
=
1
;
goto
try_head
;
}
memset
(
tx_msg
,
0
,
I2400M_TX_PLD_SIZE
);
...
...
@@ -566,7 +653,7 @@ void i2400m_tx_close(struct i2400m *i2400m)
aligned_size
=
ALIGN
(
tx_msg_moved
->
size
,
i2400m
->
bus_tx_block_size
);
padding
=
aligned_size
-
tx_msg_moved
->
size
;
if
(
padding
>
0
)
{
pad_buf
=
i2400m_tx_fifo_push
(
i2400m
,
padding
,
0
);
pad_buf
=
i2400m_tx_fifo_push
(
i2400m
,
padding
,
0
,
0
);
if
(
unlikely
(
WARN_ON
(
pad_buf
==
NULL
||
pad_buf
==
TAIL_FULL
)))
{
/* This should not happen -- append should verify
...
...
@@ -632,6 +719,7 @@ int i2400m_tx(struct i2400m *i2400m, const void *buf, size_t buf_len,
unsigned
long
flags
;
size_t
padded_len
;
void
*
ptr
;
bool
try_head
=
0
;
unsigned
is_singleton
=
pl_type
==
I2400M_PT_RESET_WARM
||
pl_type
==
I2400M_PT_RESET_COLD
;
...
...
@@ -643,9 +731,11 @@ int i2400m_tx(struct i2400m *i2400m, const void *buf, size_t buf_len,
* current one is out of payload slots or we have a singleton,
* close it and start a new one */
spin_lock_irqsave
(
&
i2400m
->
tx_lock
,
flags
);
result
=
-
ESHUTDOWN
;
if
(
i2400m
->
tx_buf
==
NULL
)
/* If tx_buf is NULL, device is shutdown */
if
(
i2400m
->
tx_buf
==
NULL
)
{
result
=
-
ESHUTDOWN
;
goto
error_tx_new
;
}
try_new:
if
(
unlikely
(
i2400m
->
tx_msg
==
NULL
))
i2400m_tx_new
(
i2400m
);
...
...
@@ -659,7 +749,13 @@ int i2400m_tx(struct i2400m *i2400m, const void *buf, size_t buf_len,
}
if
(
i2400m
->
tx_msg
==
NULL
)
goto
error_tx_new
;
if
(
i2400m
->
tx_msg
->
size
+
padded_len
>
I2400M_TX_BUF_SIZE
/
2
)
{
/*
* Check if this skb will fit in the TX queue's current active
* TX message. The total message size must not exceed the maximum
* size of each message I2400M_TX_MSG_SIZE. If it exceeds,
* close the current message and push this skb into the new message.
*/
if
(
i2400m
->
tx_msg
->
size
+
padded_len
>
I2400M_TX_MSG_SIZE
)
{
d_printf
(
2
,
dev
,
"TX: message too big, going new
\n
"
);
i2400m_tx_close
(
i2400m
);
i2400m_tx_new
(
i2400m
);
...
...
@@ -669,11 +765,12 @@ int i2400m_tx(struct i2400m *i2400m, const void *buf, size_t buf_len,
/* So we have a current message header; now append space for
* the message -- if there is not enough, try the head */
ptr
=
i2400m_tx_fifo_push
(
i2400m
,
padded_len
,
i2400m
->
bus_tx_block_size
);
i2400m
->
bus_tx_block_size
,
try_head
);
if
(
ptr
==
TAIL_FULL
)
{
/* Tail is full, try head */
d_printf
(
2
,
dev
,
"pl append: tail full
\n
"
);
i2400m_tx_close
(
i2400m
);
i2400m_tx_skip_tail
(
i2400m
);
try_head
=
1
;
goto
try_new
;
}
else
if
(
ptr
==
NULL
)
{
/* All full */
result
=
-
ENOSPC
;
...
...
@@ -860,25 +957,43 @@ EXPORT_SYMBOL_GPL(i2400m_tx_msg_sent);
* i2400m_tx_setup - Initialize the TX queue and infrastructure
*
* Make sure we reset the TX sequence to zero, as when this function
* is called, the firmware has been just restarted.
* is called, the firmware has been just restarted. Same rational
* for tx_in, tx_out, tx_msg_size and tx_msg. We reset them since
* the memory for TX queue is reallocated.
*/
int
i2400m_tx_setup
(
struct
i2400m
*
i2400m
)
{
int
result
;
int
result
=
0
;
void
*
tx_buf
;
unsigned
long
flags
;
/* Do this here only once -- can't do on
* i2400m_hard_start_xmit() as we'll cause race conditions if
* the WS was scheduled on another CPU */
INIT_WORK
(
&
i2400m
->
wake_tx_ws
,
i2400m_wake_tx_work
);
i2400m
->
tx_sequence
=
0
;
i2400m
->
tx_buf
=
kmalloc
(
I2400M_TX_BUF_SIZE
,
GFP_KERNEL
);
if
(
i2400m
->
tx_buf
==
NULL
)
tx_buf
=
kmalloc
(
I2400M_TX_BUF_SIZE
,
GFP_ATOMIC
);
if
(
tx_buf
==
NULL
)
{
result
=
-
ENOMEM
;
else
result
=
0
;
goto
error_kmalloc
;
}
/*
* Fail the build if we can't fit at least two maximum size messages
* on the TX FIFO [one being delivered while one is constructed].
*/
BUILD_BUG_ON
(
2
*
I2400M_TX_MSG_SIZE
>
I2400M_TX_BUF_SIZE
);
spin_lock_irqsave
(
&
i2400m
->
tx_lock
,
flags
);
i2400m
->
tx_sequence
=
0
;
i2400m
->
tx_in
=
0
;
i2400m
->
tx_out
=
0
;
i2400m
->
tx_msg_size
=
0
;
i2400m
->
tx_msg
=
NULL
;
i2400m
->
tx_buf
=
tx_buf
;
spin_unlock_irqrestore
(
&
i2400m
->
tx_lock
,
flags
);
/* Huh? the bus layer has to define this... */
BUG_ON
(
i2400m
->
bus_tx_block_size
==
0
);
error_kmalloc:
return
result
;
}
...
...
drivers/net/wimax/i2400m/usb.c
View file @
1cdc5abf
...
...
@@ -82,6 +82,8 @@ MODULE_PARM_DESC(debug,
/* Our firmware file name */
static
const
char
*
i2400mu_bus_fw_names_5x50
[]
=
{
#define I2400MU_FW_FILE_NAME_v1_5 "i2400m-fw-usb-1.5.sbcf"
I2400MU_FW_FILE_NAME_v1_5
,
#define I2400MU_FW_FILE_NAME_v1_4 "i2400m-fw-usb-1.4.sbcf"
I2400MU_FW_FILE_NAME_v1_4
,
NULL
,
...
...
@@ -467,6 +469,13 @@ int i2400mu_probe(struct usb_interface *iface,
usb_set_intfdata
(
iface
,
i2400mu
);
i2400m
->
bus_tx_block_size
=
I2400MU_BLK_SIZE
;
/*
* Room required in the Tx queue for USB message to accommodate
* a smallest payload while allocating header space is 16 bytes.
* Adding this room for the new tx message increases the
* possibilities of including any payload with size <= 16 bytes.
*/
i2400m
->
bus_tx_room_min
=
I2400MU_BLK_SIZE
;
i2400m
->
bus_pl_size_max
=
I2400MU_PL_SIZE_MAX
;
i2400m
->
bus_setup
=
NULL
;
i2400m
->
bus_dev_start
=
i2400mu_bus_dev_start
;
...
...
@@ -778,4 +787,5 @@ MODULE_AUTHOR("Intel Corporation <linux-wimax@intel.com>");
MODULE_DESCRIPTION
(
"Driver for USB based Intel Wireless WiMAX Connection 2400M "
"(5x50 & 6050)"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_FIRMWARE
(
I2400MU_FW_FILE_NAME_v1_4
);
MODULE_FIRMWARE
(
I2400MU_FW_FILE_NAME_v1_5
);
MODULE_FIRMWARE
(
I6050U_FW_FILE_NAME_v1_5
);
net/wimax/stack.c
View file @
1cdc5abf
...
...
@@ -315,7 +315,7 @@ void __wimax_state_change(struct wimax_dev *wimax_dev, enum wimax_st new_state)
BUG
();
}
__wimax_state_set
(
wimax_dev
,
new_state
);
if
(
stch_skb
)
if
(
!
IS_ERR
(
stch_skb
)
)
wimax_gnl_re_state_change_send
(
wimax_dev
,
stch_skb
,
header
);
out:
d_fnend
(
3
,
dev
,
"(wimax_dev %p new_state %u [old %u]) = void
\n
"
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment