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
nexedi
linux
Commits
62d83681
Commit
62d83681
authored
Nov 06, 2009
by
David S. Miller
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'linux-2.6.33.y' of
git://git.kernel.org/pub/scm/linux/kernel/git/inaky/wimax
parents
230f9bb7
e7fec0bb
Changes
26
Show whitespace changes
Inline
Side-by-side
Showing
26 changed files
with
2104 additions
and
618 deletions
+2104
-618
drivers/net/wimax/i2400m/control.c
drivers/net/wimax/i2400m/control.c
+13
-3
drivers/net/wimax/i2400m/debugfs.c
drivers/net/wimax/i2400m/debugfs.c
+1
-1
drivers/net/wimax/i2400m/driver.c
drivers/net/wimax/i2400m/driver.c
+364
-136
drivers/net/wimax/i2400m/fw.c
drivers/net/wimax/i2400m/fw.c
+729
-157
drivers/net/wimax/i2400m/i2400m-sdio.h
drivers/net/wimax/i2400m/i2400m-sdio.h
+15
-1
drivers/net/wimax/i2400m/i2400m-usb.h
drivers/net/wimax/i2400m/i2400m-usb.h
+11
-5
drivers/net/wimax/i2400m/i2400m.h
drivers/net/wimax/i2400m/i2400m.h
+141
-68
drivers/net/wimax/i2400m/netdev.c
drivers/net/wimax/i2400m/netdev.c
+94
-33
drivers/net/wimax/i2400m/rx.c
drivers/net/wimax/i2400m/rx.c
+137
-33
drivers/net/wimax/i2400m/sdio-fw.c
drivers/net/wimax/i2400m/sdio-fw.c
+6
-5
drivers/net/wimax/i2400m/sdio-rx.c
drivers/net/wimax/i2400m/sdio-rx.c
+32
-10
drivers/net/wimax/i2400m/sdio-tx.c
drivers/net/wimax/i2400m/sdio-tx.c
+4
-1
drivers/net/wimax/i2400m/sdio.c
drivers/net/wimax/i2400m/sdio.c
+125
-80
drivers/net/wimax/i2400m/tx.c
drivers/net/wimax/i2400m/tx.c
+18
-2
drivers/net/wimax/i2400m/usb-fw.c
drivers/net/wimax/i2400m/usb-fw.c
+30
-7
drivers/net/wimax/i2400m/usb-notif.c
drivers/net/wimax/i2400m/usb-notif.c
+13
-22
drivers/net/wimax/i2400m/usb-rx.c
drivers/net/wimax/i2400m/usb-rx.c
+52
-8
drivers/net/wimax/i2400m/usb-tx.c
drivers/net/wimax/i2400m/usb-tx.c
+54
-7
drivers/net/wimax/i2400m/usb.c
drivers/net/wimax/i2400m/usb.c
+162
-27
include/linux/mmc/sdio_ids.h
include/linux/mmc/sdio_ids.h
+1
-0
include/linux/wimax/debug.h
include/linux/wimax/debug.h
+72
-0
include/linux/wimax/i2400m.h
include/linux/wimax/i2400m.h
+2
-11
include/net/wimax.h
include/net/wimax.h
+6
-0
net/wimax/op-msg.c
net/wimax/op-msg.c
+2
-0
net/wimax/op-rfkill.c
net/wimax/op-rfkill.c
+9
-1
net/wimax/stack.c
net/wimax/stack.c
+11
-0
No files found.
drivers/net/wimax/i2400m/control.c
View file @
62d83681
...
...
@@ -54,7 +54,7 @@
* i2400m_set_init_config()
* i2400m_cmd_get_state()
* i2400m_dev_shutdown() Called by i2400m_dev_stop()
* i2400m
->bus
_reset()
* i2400m_reset()
*
* i2400m_{cmd,get,set}_*()
* i2400m_msg_to_dev()
...
...
@@ -82,6 +82,13 @@
#define D_SUBMODULE control
#include "debug-levels.h"
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
,
"If true, the driver will not do any device setup "
"and leave it up to user space, who must be properly "
"setup."
);
/*
* Return if a TLV is of a give type and size
...
...
@@ -263,7 +270,7 @@ int i2400m_msg_check_status(const struct i2400m_l3l4_hdr *l3l4_hdr,
if
(
status
==
0
)
return
0
;
if
(
status
>
ARRAY_SIZE
(
ms_to_errno
))
{
if
(
status
>
=
ARRAY_SIZE
(
ms_to_errno
))
{
str
=
"unknown status code"
;
result
=
-
EBADR
;
}
else
{
...
...
@@ -336,7 +343,7 @@ void i2400m_report_tlv_system_state(struct i2400m *i2400m,
/* Huh? just in case, shut it down */
dev_err
(
dev
,
"HW BUG? unknown state %u: shutting down
\n
"
,
i2400m_state
);
i2400m
->
bus
_reset
(
i2400m
,
I2400M_RT_WARM
);
i2400m_reset
(
i2400m
,
I2400M_RT_WARM
);
break
;
};
d_fnend
(
3
,
dev
,
"(i2400m %p ss %p [%u]) = void
\n
"
,
...
...
@@ -1335,6 +1342,8 @@ int i2400m_dev_initialize(struct i2400m *i2400m)
unsigned
argc
=
0
;
d_fnstart
(
3
,
dev
,
"(i2400m %p)
\n
"
,
i2400m
);
if
(
i2400m_passive_mode
)
goto
out_passive
;
/* Disable idle mode? (enabled by default) */
if
(
i2400m_idle_mode_disabled
)
{
if
(
i2400m_le_v1_3
(
i2400m
))
{
...
...
@@ -1377,6 +1386,7 @@ int i2400m_dev_initialize(struct i2400m *i2400m)
result
=
i2400m_set_init_config
(
i2400m
,
args
,
argc
);
if
(
result
<
0
)
goto
error
;
out_passive:
/*
* Update state: Here it just calls a get state; parsing the
* result (System State TLV and RF Status TLV [done in the rx
...
...
drivers/net/wimax/i2400m/debugfs.c
View file @
62d83681
...
...
@@ -214,7 +214,7 @@ int debugfs_i2400m_reset_set(void *data, u64 val)
case
I2400M_RT_WARM
:
case
I2400M_RT_COLD
:
case
I2400M_RT_BUS
:
result
=
i2400m
->
bus
_reset
(
i2400m
,
rt
);
result
=
i2400m_reset
(
i2400m
,
rt
);
if
(
result
>=
0
)
result
=
0
;
default:
...
...
drivers/net/wimax/i2400m/driver.c
View file @
62d83681
...
...
@@ -41,8 +41,10 @@
* __i2400m_dev_start()
*
* i2400m_setup()
* i2400m->bus_setup()
* i2400m_bootrom_init()
* register_netdev()
* wimax_dev_add()
* i2400m_dev_start()
* __i2400m_dev_start()
* i2400m_dev_bootstrap()
...
...
@@ -50,15 +52,15 @@
* i2400m->bus_dev_start()
* i2400m_firmware_check()
* i2400m_check_mac_addr()
* wimax_dev_add()
*
* i2400m_release()
* wimax_dev_rm()
* i2400m_dev_stop()
* __i2400m_dev_stop()
* i2400m_dev_shutdown()
* i2400m->bus_dev_stop()
* i2400m_tx_release()
* i2400m->bus_release()
* wimax_dev_rm()
* unregister_netdev()
*/
#include "i2400m.h"
...
...
@@ -66,6 +68,7 @@
#include <linux/wimax/i2400m.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/suspend.h>
#define D_SUBMODULE driver
#include "debug-levels.h"
...
...
@@ -90,76 +93,39 @@ MODULE_PARM_DESC(power_save_disabled,
"False by default (so the device is told to do power "
"saving)."
);
/**
* i2400m_queue_work - schedule work on a i2400m's queue
*
* @i2400m: device descriptor
*
* @fn: function to run to execute work. It gets passed a 'struct
* work_struct' that is wrapped in a 'struct i2400m_work'. Once
* done, you have to (1) i2400m_put(i2400m_work->i2400m) and then
* (2) kfree(i2400m_work).
*
* @gfp_flags: GFP flags for memory allocation.
*
* @pl: pointer to a payload buffer that you want to pass to the _work
* function. Use this to pack (for example) a struct with extra
* arguments.
*
* @pl_size: size of the payload buffer.
*
* We do this quite often, so this just saves typing; allocate a
* wrapper for a i2400m, get a ref to it, pack arguments and launch
* the work.
*
* A usual workflow is:
*
* struct my_work_args {
* void *something;
* int whatever;
* };
* ...
*
* struct my_work_args my_args = {
* .something = FOO,
* .whaetever = BLAH
* };
* i2400m_queue_work(i2400m, 1, my_work_function, GFP_KERNEL,
* &args, sizeof(args))
*
* And now the work function can unpack the arguments and call the
* real function (or do the job itself):
*
* static
* void my_work_fn((struct work_struct *ws)
* {
* struct i2400m_work *iw =
* container_of(ws, struct i2400m_work, ws);
* struct my_work_args *my_args = (void *) iw->pl;
*
* my_work(iw->i2400m, my_args->something, my_args->whatevert);
* }
*/
int
i2400m_queue_work
(
struct
i2400m
*
i2400m
,
void
(
*
fn
)(
struct
work_struct
*
),
gfp_t
gfp_flags
,
const
void
*
pl
,
size_t
pl_size
)
static
char
i2400m_debug_params
[
128
];
module_param_string
(
debug
,
i2400m_debug_params
,
sizeof
(
i2400m_debug_params
),
0644
);
MODULE_PARM_DESC
(
debug
,
"String of space-separated NAME:VALUE pairs, where NAMEs "
"are the different debug submodules and VALUE are the "
"initial debug value to set."
);
static
char
i2400m_barkers_params
[
128
];
module_param_string
(
barkers
,
i2400m_barkers_params
,
sizeof
(
i2400m_barkers_params
),
0644
);
MODULE_PARM_DESC
(
barkers
,
"String of comma-separated 32-bit values; each is "
"recognized as the value the device sends as a reboot "
"signal; values are appended to a list--setting one value "
"as zero cleans the existing list and starts a new one."
);
static
struct
i2400m_work
*
__i2400m_work_setup
(
struct
i2400m
*
i2400m
,
void
(
*
fn
)(
struct
work_struct
*
),
gfp_t
gfp_flags
,
const
void
*
pl
,
size_t
pl_size
)
{
int
result
;
struct
i2400m_work
*
iw
;
BUG_ON
(
i2400m
->
work_queue
==
NULL
);
result
=
-
ENOMEM
;
iw
=
kzalloc
(
sizeof
(
*
iw
)
+
pl_size
,
gfp_flags
);
if
(
iw
==
NULL
)
goto
error_kzalloc
;
return
NULL
;
iw
->
i2400m
=
i2400m_get
(
i2400m
);
iw
->
pl_size
=
pl_size
;
memcpy
(
iw
->
pl
,
pl
,
pl_size
);
INIT_WORK
(
&
iw
->
ws
,
fn
);
result
=
queue_work
(
i2400m
->
work_queue
,
&
iw
->
ws
);
error_kzalloc:
return
result
;
return
iw
;
}
EXPORT_SYMBOL_GPL
(
i2400m_queue_work
);
/*
...
...
@@ -175,21 +141,19 @@ EXPORT_SYMBOL_GPL(i2400m_queue_work);
* it should not happen.
*/
int
i2400m_schedule_work
(
struct
i2400m
*
i2400m
,
void
(
*
fn
)(
struct
work_struct
*
),
gfp_t
gfp_flags
)
void
(
*
fn
)(
struct
work_struct
*
),
gfp_t
gfp_flags
,
const
void
*
pl
,
size_t
pl_size
)
{
int
result
;
struct
i2400m_work
*
iw
;
result
=
-
ENOMEM
;
iw
=
kzalloc
(
sizeof
(
*
iw
),
gfp_flags
);
if
(
iw
==
NULL
)
goto
error_kzalloc
;
iw
->
i2400m
=
i2400m_get
(
i2400m
);
INIT_WORK
(
&
iw
->
ws
,
fn
);
iw
=
__i2400m_work_setup
(
i2400m
,
fn
,
gfp_flags
,
pl
,
pl_size
);
if
(
iw
!=
NULL
)
{
result
=
schedule_work
(
&
iw
->
ws
);
if
(
result
==
0
)
if
(
WARN_ON
(
result
==
0
)
)
result
=
-
ENXIO
;
error_kzalloc:
}
return
result
;
}
...
...
@@ -291,7 +255,7 @@ int i2400m_op_reset(struct wimax_dev *wimax_dev)
mutex_lock
(
&
i2400m
->
init_mutex
);
i2400m
->
reset_ctx
=
&
ctx
;
mutex_unlock
(
&
i2400m
->
init_mutex
);
result
=
i2400m
->
bus
_reset
(
i2400m
,
I2400M_RT_WARM
);
result
=
i2400m_reset
(
i2400m
,
I2400M_RT_WARM
);
if
(
result
<
0
)
goto
out
;
result
=
wait_for_completion_timeout
(
&
ctx
.
completion
,
4
*
HZ
);
...
...
@@ -420,9 +384,15 @@ int __i2400m_dev_start(struct i2400m *i2400m, enum i2400m_bri flags)
dev_err
(
dev
,
"cannot create workqueue
\n
"
);
goto
error_create_workqueue
;
}
if
(
i2400m
->
bus_dev_start
)
{
result
=
i2400m
->
bus_dev_start
(
i2400m
);
if
(
result
<
0
)
goto
error_bus_dev_start
;
}
i2400m
->
ready
=
1
;
wmb
();
/* see i2400m->ready's documentation */
/* process pending reports from the device */
queue_work
(
i2400m
->
work_queue
,
&
i2400m
->
rx_report_ws
);
result
=
i2400m_firmware_check
(
i2400m
);
/* fw versions ok? */
if
(
result
<
0
)
goto
error_fw_check
;
...
...
@@ -430,8 +400,6 @@ int __i2400m_dev_start(struct i2400m *i2400m, enum i2400m_bri flags)
result
=
i2400m_check_mac_addr
(
i2400m
);
if
(
result
<
0
)
goto
error_check_mac_addr
;
i2400m
->
ready
=
1
;
wimax_state_change
(
wimax_dev
,
WIMAX_ST_UNINITIALIZED
);
result
=
i2400m_dev_initialize
(
i2400m
);
if
(
result
<
0
)
goto
error_dev_initialize
;
...
...
@@ -443,7 +411,11 @@ int __i2400m_dev_start(struct i2400m *i2400m, enum i2400m_bri flags)
error_dev_initialize:
error_check_mac_addr:
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:
destroy_workqueue
(
i2400m
->
work_queue
);
...
...
@@ -466,11 +438,15 @@ int __i2400m_dev_start(struct i2400m *i2400m, enum i2400m_bri flags)
static
int
i2400m_dev_start
(
struct
i2400m
*
i2400m
,
enum
i2400m_bri
bm_flags
)
{
int
result
;
int
result
=
0
;
mutex_lock
(
&
i2400m
->
init_mutex
);
/* Well, start the device */
if
(
i2400m
->
updown
==
0
)
{
result
=
__i2400m_dev_start
(
i2400m
,
bm_flags
);
if
(
result
>=
0
)
if
(
result
>=
0
)
{
i2400m
->
updown
=
1
;
wmb
();
/* see i2400m->updown's documentation */
}
}
mutex_unlock
(
&
i2400m
->
init_mutex
);
return
result
;
}
...
...
@@ -495,8 +471,19 @@ void __i2400m_dev_stop(struct i2400m *i2400m)
d_fnstart
(
3
,
dev
,
"(i2400m %p)
\n
"
,
i2400m
);
wimax_state_change
(
wimax_dev
,
__WIMAX_ST_QUIESCING
);
i2400m_msg_to_dev_cancel_wait
(
i2400m
,
-
EL3RST
);
complete
(
&
i2400m
->
msg_completion
);
i2400m_net_wake_stop
(
i2400m
);
i2400m_dev_shutdown
(
i2400m
);
i2400m
->
ready
=
0
;
/*
* Make sure no report hooks are running *before* we stop the
* communication infrastructure with the device.
*/
i2400m
->
ready
=
0
;
/* nobody can queue work anymore */
wmb
();
/* see i2400m->ready's documentation */
flush_workqueue
(
i2400m
->
work_queue
);
if
(
i2400m
->
bus_dev_stop
)
i2400m
->
bus_dev_stop
(
i2400m
);
destroy_workqueue
(
i2400m
->
work_queue
);
i2400m_rx_release
(
i2400m
);
...
...
@@ -518,11 +505,138 @@ void i2400m_dev_stop(struct i2400m *i2400m)
if
(
i2400m
->
updown
)
{
__i2400m_dev_stop
(
i2400m
);
i2400m
->
updown
=
0
;
wmb
();
/* see i2400m->updown's documentation */
}
mutex_unlock
(
&
i2400m
->
init_mutex
);
}
/*
* Listen to PM events to cache the firmware before suspend/hibernation
*
* When the device comes out of suspend, it might go into reset and
* firmware has to be uploaded again. At resume, most of the times, we
* can't load firmware images from disk, so we need to cache it.
*
* i2400m_fw_cache() will allocate a kobject and attach the firmware
* to it; that way we don't have to worry too much about the fw loader
* hitting a race condition.
*
* Note: modus operandi stolen from the Orinoco driver; thx.
*/
static
int
i2400m_pm_notifier
(
struct
notifier_block
*
notifier
,
unsigned
long
pm_event
,
void
*
unused
)
{
struct
i2400m
*
i2400m
=
container_of
(
notifier
,
struct
i2400m
,
pm_notifier
);
struct
device
*
dev
=
i2400m_dev
(
i2400m
);
d_fnstart
(
3
,
dev
,
"(i2400m %p pm_event %lx)
\n
"
,
i2400m
,
pm_event
);
switch
(
pm_event
)
{
case
PM_HIBERNATION_PREPARE
:
case
PM_SUSPEND_PREPARE
:
i2400m_fw_cache
(
i2400m
);
break
;
case
PM_POST_RESTORE
:
/* Restore from hibernation failed. We need to clean
* up in exactly the same way, so fall through. */
case
PM_POST_HIBERNATION
:
case
PM_POST_SUSPEND
:
i2400m_fw_uncache
(
i2400m
);
break
;
case
PM_RESTORE_PREPARE
:
default:
break
;
}
d_fnend
(
3
,
dev
,
"(i2400m %p pm_event %lx) = void
\n
"
,
i2400m
,
pm_event
);
return
NOTIFY_DONE
;
}
/*
* pre-reset is called before a device is going on reset
*
* This has to be followed by a call to i2400m_post_reset(), otherwise
* bad things might happen.
*/
int
i2400m_pre_reset
(
struct
i2400m
*
i2400m
)
{
int
result
;
struct
device
*
dev
=
i2400m_dev
(
i2400m
);
d_fnstart
(
3
,
dev
,
"(i2400m %p)
\n
"
,
i2400m
);
d_printf
(
1
,
dev
,
"pre-reset shut down
\n
"
);
result
=
0
;
mutex_lock
(
&
i2400m
->
init_mutex
);
if
(
i2400m
->
updown
)
{
netif_tx_disable
(
i2400m
->
wimax_dev
.
net_dev
);
__i2400m_dev_stop
(
i2400m
);
result
=
0
;
/* down't set updown to zero -- this way
* post_reset can restore properly */
}
mutex_unlock
(
&
i2400m
->
init_mutex
);
if
(
i2400m
->
bus_release
)
i2400m
->
bus_release
(
i2400m
);
d_fnend
(
3
,
dev
,
"(i2400m %p) = %d
\n
"
,
i2400m
,
result
);
return
result
;
}
EXPORT_SYMBOL_GPL
(
i2400m_pre_reset
);
/*
* Restore device state after a reset
*
* Do the work needed after a device reset to bring it up to the same
* state as it was before the reset.
*
* NOTE: this requires i2400m->init_mutex taken
*/
int
i2400m_post_reset
(
struct
i2400m
*
i2400m
)
{
int
result
=
0
;
struct
device
*
dev
=
i2400m_dev
(
i2400m
);
d_fnstart
(
3
,
dev
,
"(i2400m %p)
\n
"
,
i2400m
);
d_printf
(
1
,
dev
,
"post-reset start
\n
"
);
if
(
i2400m
->
bus_setup
)
{
result
=
i2400m
->
bus_setup
(
i2400m
);
if
(
result
<
0
)
{
dev_err
(
dev
,
"bus-specific setup failed: %d
\n
"
,
result
);
goto
error_bus_setup
;
}
}
mutex_lock
(
&
i2400m
->
init_mutex
);
if
(
i2400m
->
updown
)
{
result
=
__i2400m_dev_start
(
i2400m
,
I2400M_BRI_SOFT
|
I2400M_BRI_MAC_REINIT
);
if
(
result
<
0
)
goto
error_dev_start
;
}
mutex_unlock
(
&
i2400m
->
init_mutex
);
d_fnend
(
3
,
dev
,
"(i2400m %p) = %d
\n
"
,
i2400m
,
result
);
return
result
;
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
);
d_fnend
(
3
,
dev
,
"(i2400m %p) = %d
\n
"
,
i2400m
,
result
);
return
result
;
}
EXPORT_SYMBOL_GPL
(
i2400m_post_reset
);
/*
* The device has rebooted; fix up the device and the driver
*
...
...
@@ -542,56 +656,69 @@ void i2400m_dev_stop(struct i2400m *i2400m)
* _stop()], don't do anything, let it fail and handle it.
*
* This function is ran always in a thread context
*
* This function gets passed, as payload to i2400m_work() a 'const
* char *' ptr with a "reason" why the reset happened (for messages).
*/
static
void
__i2400m_dev_reset_handle
(
struct
work_struct
*
ws
)
{
int
result
;
struct
i2400m_work
*
iw
=
container_of
(
ws
,
struct
i2400m_work
,
ws
);
const
char
*
reason
;
struct
i2400m
*
i2400m
=
iw
->
i2400m
;
struct
device
*
dev
=
i2400m_dev
(
i2400m
);
enum
wimax_st
wimax_state
;
struct
i2400m_reset_ctx
*
ctx
=
i2400m
->
reset_ctx
;
d_fnstart
(
3
,
dev
,
"(ws %p i2400m %p)
\n
"
,
ws
,
i2400m
);
if
(
WARN_ON
(
iw
->
pl_size
!=
sizeof
(
reason
)))
reason
=
"SW BUG: reason n/a"
;
else
memcpy
(
&
reason
,
iw
->
pl
,
sizeof
(
reason
));
d_fnstart
(
3
,
dev
,
"(ws %p i2400m %p reason %s)
\n
"
,
ws
,
i2400m
,
reason
);
result
=
0
;
if
(
mutex_trylock
(
&
i2400m
->
init_mutex
)
==
0
)
{
/* We are still in i2400m_dev_start() [let it fail] or
* i2400m_dev_stop() [we are shutting down anyway, so
* ignore it] or we are resetting somewhere else. */
dev_err
(
dev
,
"device rebooted
\n
"
);
dev_err
(
dev
,
"device rebooted
somewhere else?
\n
"
);
i2400m_msg_to_dev_cancel_wait
(
i2400m
,
-
EL3RST
);
complete
(
&
i2400m
->
msg_completion
);
goto
out
;
}
wimax_state
=
wimax_state_get
(
&
i2400m
->
wimax_dev
);
if
(
wimax_state
<
WIMAX_ST_UNINITIALIZED
)
{
dev_info
(
dev
,
"device rebooted: it is down, ignoring
\n
"
);
goto
out_unlock
;
/* ifconfig up/down wasn't called */
if
(
i2400m
->
updown
==
0
)
{
dev_info
(
dev
,
"%s: device is down, doing nothing
\n
"
,
reason
);
goto
out_unlock
;
}
dev_err
(
dev
,
"
device rebooted: reinitializing driver
\n
"
);
dev_err
(
dev
,
"
%s: reinitializing driver
\n
"
,
reason
);
__i2400m_dev_stop
(
i2400m
);
i2400m
->
updown
=
0
;
result
=
__i2400m_dev_start
(
i2400m
,
I2400M_BRI_SOFT
|
I2400M_BRI_MAC_REINIT
);
if
(
result
<
0
)
{
dev_err
(
dev
,
"device reboot: cannot start the device: %d
\n
"
,
result
);
result
=
i2400m
->
bus_reset
(
i2400m
,
I2400M_RT_BUS
);
if
(
result
>=
0
)
result
=
-
ENODEV
;
}
else
i2400m
->
updown
=
1
;
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
->
reset_ctx
)
{
ctx
->
result
=
result
;
complete
(
&
ctx
->
completion
);
}
mutex_unlock
(
&
i2400m
->
init_mutex
);
if
(
result
==
-
EUCLEAN
)
{
/* ops, need to clean up [w/ init_mutex not held] */
result
=
i2400m_reset
(
i2400m
,
I2400M_RT_BUS
);
if
(
result
>=
0
)
result
=
-
ENODEV
;
}
out:
i2400m_put
(
i2400m
);
kfree
(
iw
);
d_fnend
(
3
,
dev
,
"(ws %p i2400m %p) = void
\n
"
,
ws
,
i2400m
);
d_fnend
(
3
,
dev
,
"(ws %p i2400m %p reason %s) = void
\n
"
,
ws
,
i2400m
,
reason
);
return
;
}
...
...
@@ -608,16 +735,104 @@ void __i2400m_dev_reset_handle(struct work_struct *ws)
* reinitializing the driver to handle the reset, calling into the
* bus-specific functions ops as needed.
*/
int
i2400m_dev_reset_handle
(
struct
i2400m
*
i2400m
)
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
);
GFP_ATOMIC
,
&
reason
,
sizeof
(
reason
)
);
}
EXPORT_SYMBOL_GPL
(
i2400m_dev_reset_handle
);
/*
* Alloc the command and ack buffers for boot mode
*
* Get the buffers needed to deal with boot mode messages. These
* buffers need to be allocated before the sdio recieve irq is setup.
*/
static
int
i2400m_bm_buf_alloc
(
struct
i2400m
*
i2400m
)
{
int
result
;
result
=
-
ENOMEM
;
i2400m
->
bm_cmd_buf
=
kzalloc
(
I2400M_BM_CMD_BUF_SIZE
,
GFP_KERNEL
);
if
(
i2400m
->
bm_cmd_buf
==
NULL
)
goto
error_bm_cmd_kzalloc
;
i2400m
->
bm_ack_buf
=
kzalloc
(
I2400M_BM_ACK_BUF_SIZE
,
GFP_KERNEL
);
if
(
i2400m
->
bm_ack_buf
==
NULL
)
goto
error_bm_ack_buf_kzalloc
;
return
0
;
error_bm_ack_buf_kzalloc:
kfree
(
i2400m
->
bm_cmd_buf
);
error_bm_cmd_kzalloc:
return
result
;
}
/*
* Free boot mode command and ack buffers.
*/
static
void
i2400m_bm_buf_free
(
struct
i2400m
*
i2400m
)
{
kfree
(
i2400m
->
bm_ack_buf
);
kfree
(
i2400m
->
bm_cmd_buf
);
}
/**
* i2400m_init - Initialize a 'struct i2400m' from all zeroes
*
* This is a bus-generic API call.
*/
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
);
i2400m
->
tx_pl_min
=
UINT_MAX
;
i2400m
->
tx_size_min
=
UINT_MAX
;
spin_lock_init
(
&
i2400m
->
rx_lock
);
i2400m
->
rx_pl_min
=
UINT_MAX
;
i2400m
->
rx_size_min
=
UINT_MAX
;
INIT_LIST_HEAD
(
&
i2400m
->
rx_reports
);
INIT_WORK
(
&
i2400m
->
rx_report_ws
,
i2400m_report_hook_work
);
mutex_init
(
&
i2400m
->
msg_mutex
);
init_completion
(
&
i2400m
->
msg_completion
);
mutex_init
(
&
i2400m
->
init_mutex
);
/* wake_tx_ws is initialized in i2400m_tx_setup() */
}
EXPORT_SYMBOL_GPL
(
i2400m_init
);
int
i2400m_reset
(
struct
i2400m
*
i2400m
,
enum
i2400m_reset_type
rt
)
{
struct
net_device
*
net_dev
=
i2400m
->
wimax_dev
.
net_dev
;
/*
* Make sure we stop TXs and down the carrier before
* resetting; this is needed to avoid things like
* i2400m_wake_tx() scheduling stuff in parallel.
*/
if
(
net_dev
->
reg_state
==
NETREG_REGISTERED
)
{
netif_tx_disable
(
net_dev
);
netif_carrier_off
(
net_dev
);
}
return
i2400m
->
bus_reset
(
i2400m
,
rt
);
}
EXPORT_SYMBOL_GPL
(
i2400m_reset
);
/**
* i2400m_setup - bus-generic setup function for the i2400m device
*
...
...
@@ -625,13 +840,9 @@ EXPORT_SYMBOL_GPL(i2400m_dev_reset_handle);
*
* Returns: 0 if ok, < 0 errno code on error.
*
* Initializes the bus-generic parts of the i2400m driver; the
* bus-specific parts have been initialized, function pointers filled
* out by the bus-specific probe function.
*
* As well, this registers the WiMAX and net device nodes. Once this
* function returns, the device is operative and has to be ready to
* receive and send network traffic and WiMAX control operations.
* Sets up basic device comunication infrastructure, boots the ROM to
* read the MAC address, registers with the WiMAX and network stacks
* and then brings up the device.
*/
int
i2400m_setup
(
struct
i2400m
*
i2400m
,
enum
i2400m_bri
bm_flags
)
{
...
...
@@ -645,16 +856,21 @@ int i2400m_setup(struct i2400m *i2400m, enum i2400m_bri bm_flags)
snprintf
(
wimax_dev
->
name
,
sizeof
(
wimax_dev
->
name
),
"i2400m-%s:%s"
,
dev
->
bus
->
name
,
dev_name
(
dev
));
i2400m
->
bm_cmd_buf
=
kzalloc
(
I2400M_BM_CMD_BUF_SIZE
,
GFP_KERNEL
);
if
(
i2400m
->
bm_cmd_buf
==
NULL
)
{
dev_err
(
dev
,
"cannot allocate USB command buffer
\n
"
);
goto
error_bm_cmd_kzalloc
;
result
=
i2400m_bm_buf_alloc
(
i2400m
);
if
(
result
<
0
)
{
dev_err
(
dev
,
"cannot allocate bootmode scratch buffers
\n
"
);
goto
error_bm_buf_alloc
;
}
if
(
i2400m
->
bus_setup
)
{
result
=
i2400m
->
bus_setup
(
i2400m
);
if
(
result
<
0
)
{
dev_err
(
dev
,
"bus-specific setup failed: %d
\n
"
,
result
);
goto
error_bus_setup
;
}
i2400m
->
bm_ack_buf
=
kzalloc
(
I2400M_BM_ACK_BUF_SIZE
,
GFP_KERNEL
);
if
(
i2400m
->
bm_ack_buf
==
NULL
)
{
dev_err
(
dev
,
"cannot allocate USB ack buffer
\n
"
);
goto
error_bm_ack_buf_kzalloc
;
}
result
=
i2400m_bootrom_init
(
i2400m
,
bm_flags
);
if
(
result
<
0
)
{
dev_err
(
dev
,
"read mac addr: bootrom init "
...
...
@@ -666,6 +882,9 @@ int i2400m_setup(struct i2400m *i2400m, enum i2400m_bri bm_flags)
goto
error_read_mac_addr
;
random_ether_addr
(
i2400m
->
src_mac_addr
);
i2400m
->
pm_notifier
.
notifier_call
=
i2400m_pm_notifier
;
register_pm_notifier
(
&
i2400m
->
pm_notifier
);
result
=
register_netdev
(
net_dev
);
/* Okey dokey, bring it up */
if
(
result
<
0
)
{
dev_err
(
dev
,
"cannot register i2400m network device: %d
\n
"
,
...
...
@@ -674,18 +893,13 @@ int i2400m_setup(struct i2400m *i2400m, enum i2400m_bri bm_flags)
}
netif_carrier_off
(
net_dev
);
result
=
i2400m_dev_start
(
i2400m
,
bm_flags
);
if
(
result
<
0
)
goto
error_dev_start
;
i2400m
->
wimax_dev
.
op_msg_from_user
=
i2400m_op_msg_from_user
;
i2400m
->
wimax_dev
.
op_rfkill_sw_toggle
=
i2400m_op_rfkill_sw_toggle
;
i2400m
->
wimax_dev
.
op_reset
=
i2400m_op_reset
;
result
=
wimax_dev_add
(
&
i2400m
->
wimax_dev
,
net_dev
);
if
(
result
<
0
)
goto
error_wimax_dev_add
;
/* User space needs to do some init stuff */
wimax_state_change
(
wimax_dev
,
WIMAX_ST_UNINITIALIZED
);
/* Now setup all that requires a registered net and wimax device. */
result
=
sysfs_create_group
(
&
net_dev
->
dev
.
kobj
,
&
i2400m_dev_attr_group
);
...
...
@@ -693,30 +907,37 @@ int i2400m_setup(struct i2400m *i2400m, enum i2400m_bri bm_flags)
dev_err
(
dev
,
"cannot setup i2400m's sysfs: %d
\n
"
,
result
);
goto
error_sysfs_setup
;
}
result
=
i2400m_debugfs_add
(
i2400m
);
if
(
result
<
0
)
{
dev_err
(
dev
,
"cannot setup i2400m's debugfs: %d
\n
"
,
result
);
goto
error_debugfs_setup
;
}
result
=
i2400m_dev_start
(
i2400m
,
bm_flags
);
if
(
result
<
0
)
goto
error_dev_start
;
d_fnend
(
3
,
dev
,
"(i2400m %p) = %d
\n
"
,
i2400m
,
result
);
return
result
;
error_dev_start:
i2400m_debugfs_rm
(
i2400m
);
error_debugfs_setup:
sysfs_remove_group
(
&
i2400m
->
wimax_dev
.
net_dev
->
dev
.
kobj
,
&
i2400m_dev_attr_group
);
error_sysfs_setup:
wimax_dev_rm
(
&
i2400m
->
wimax_dev
);
error_wimax_dev_add:
i2400m_dev_stop
(
i2400m
);
error_dev_start:
unregister_netdev
(
net_dev
);
error_register_netdev:
unregister_pm_notifier
(
&
i2400m
->
pm_notifier
);
error_read_mac_addr:
error_bootrom_init:
kfree
(
i2400m
->
bm_ack_buf
);
error_bm_ack_buf_kzalloc:
kfree
(
i2400m
->
bm_cmd_buf
);
error_bm_cmd_kzalloc:
if
(
i2400m
->
bus_release
)
i2400m
->
bus_release
(
i2400m
);
error_bus_setup:
i2400m_bm_buf_free
(
i2400m
);
error_bm_buf_alloc:
d_fnend
(
3
,
dev
,
"(i2400m %p) = %d
\n
"
,
i2400m
,
result
);
return
result
;
}
...
...
@@ -735,14 +956,17 @@ void i2400m_release(struct i2400m *i2400m)
d_fnstart
(
3
,
dev
,
"(i2400m %p)
\n
"
,
i2400m
);
netif_stop_queue
(
i2400m
->
wimax_dev
.
net_dev
);
i2400m_dev_stop
(
i2400m
);
i2400m_debugfs_rm
(
i2400m
);
sysfs_remove_group
(
&
i2400m
->
wimax_dev
.
net_dev
->
dev
.
kobj
,
&
i2400m_dev_attr_group
);
wimax_dev_rm
(
&
i2400m
->
wimax_dev
);
i2400m_dev_stop
(
i2400m
);
unregister_netdev
(
i2400m
->
wimax_dev
.
net_dev
);
kfree
(
i2400m
->
bm_ack_buf
);
kfree
(
i2400m
->
bm_cmd_buf
);
unregister_pm_notifier
(
&
i2400m
->
pm_notifier
);
if
(
i2400m
->
bus_release
)
i2400m
->
bus_release
(
i2400m
);
i2400m_bm_buf_free
(
i2400m
);
d_fnend
(
3
,
dev
,
"(i2400m %p) = void
\n
"
,
i2400m
);
}
EXPORT_SYMBOL_GPL
(
i2400m_release
);
...
...
@@ -759,6 +983,7 @@ struct d_level D_LEVEL[] = {
D_SUBMODULE_DEFINE
(
netdev
),
D_SUBMODULE_DEFINE
(
rfkill
),
D_SUBMODULE_DEFINE
(
rx
),
D_SUBMODULE_DEFINE
(
sysfs
),
D_SUBMODULE_DEFINE
(
tx
),
};
size_t
D_LEVEL_SIZE
=
ARRAY_SIZE
(
D_LEVEL
);
...
...
@@ -767,7 +992,9 @@ size_t D_LEVEL_SIZE = ARRAY_SIZE(D_LEVEL);
static
int
__init
i2400m_driver_init
(
void
)
{
return
0
;
d_parse_params
(
D_LEVEL
,
D_LEVEL_SIZE
,
i2400m_debug_params
,
"i2400m.debug"
);
return
i2400m_barker_db_init
(
i2400m_barkers_params
);
}
module_init
(
i2400m_driver_init
);
...
...
@@ -776,6 +1003,7 @@ void __exit i2400m_driver_exit(void)
{
/* for scheds i2400m_dev_reset_handle() */
flush_scheduled_work
();
i2400m_barker_db_exit
();
return
;
}
module_exit
(
i2400m_driver_exit
);
...
...
drivers/net/wimax/i2400m/fw.c
View file @
62d83681
...
...
@@ -40,11 +40,9 @@
*
* THE PROCEDURE
*
* (this is decribed for USB, but for SDIO is similar)
*
* The 2400m works in two modes: boot-mode or normal mode. In boot
* mode we can execute only a handful of commands targeted at
* uploading the firmware and launching it.
* The 2400m and derived devices work in two modes: boot-mode or
* normal mode. In boot mode we can execute only a handful of commands
* targeted at uploading the firmware and launching it.
*
* The 2400m enters boot mode when it is first connected to the
* system, when it crashes and when you ask it to reboot. There are
...
...
@@ -52,18 +50,26 @@
* firmwares signed with a certain private key, non-signed takes any
* firmware. Normal hardware takes only signed firmware.
*
* Upon entrance to boot mode, the device sends a few zero length
* packets (ZLPs) on the notification endpoint, then a reboot barker
* (4 le32 words with value I2400M_{S,N}BOOT_BARKER). We ack it by
* sending the same barker on the bulk out endpoint. The device acks
* with a reboot ack barker (4 le32 words with value 0xfeedbabe) and
* then the device is fully rebooted. At this point we can upload the
* firmware.
* On boot mode, in USB, we write to the device using the bulk out
* endpoint and read from it in the notification endpoint. In SDIO we
* talk to it via the write address and read from the read address.
*
* Upon entrance to boot mode, the device sends (preceeded with a few
* zero length packets (ZLPs) on the notification endpoint in USB) a
* reboot barker (4 le32 words with the same value). We ack it by
* sending the same barker to the device. The device acks with a
* reboot ack barker (4 le32 words with value I2400M_ACK_BARKER) and
* then is fully booted. At this point we can upload the firmware.
*
* Note that different iterations of the device and EEPROM
* configurations will send different [re]boot barkers; these are
* collected in i2400m_barker_db along with the firmware
* characteristics they require.
*
* This process is accomplished by the i2400m_bootrom_init()
* function. All the device interaction happens through the
* i2400m_bm_cmd() [boot mode command]. Special return values will
* indicate if the device
reset
s.
* indicate if the device
did reset during the proces
s.
*
* After this, we read the MAC address and then (if needed)
* reinitialize the device. We need to read it ahead of time because
...
...
@@ -72,11 +78,11 @@
*
* We can then upload the firmware file. The file is composed of a BCF
* header (basic data, keys and signatures) and a list of write
* commands and payloads.
We first upload the header
*
[i2400m_dnload_init()] and then pass the commands and payloads
*
verbatim to the i2400m_bm_cmd() function
*
[i2400m_dnload_bcf()]. Then we tell the device to jump to the new
* firmware [i2400m_dnload_finalize()].
* commands and payloads.
Optionally more BCF headers might follow the
*
main payload. We first upload the header [i2400m_dnload_init()] and
*
then pass the commands and payloads verbatim to the i2400m_bm_cmd()
*
function [i2400m_dnload_bcf()]. Then we tell the device to jump to
*
the new
firmware [i2400m_dnload_finalize()].
*
* Once firmware is uploaded, we are good to go :)
*
...
...
@@ -99,18 +105,32 @@
* read an acknolwedgement from it (or an asynchronous notification)
* from it.
*
* FIRMWARE LOADING
*
* Note that in some cases, we can't just load a firmware file (for
* example, when resuming). For that, we might cache the firmware
* file. Thus, when doing the bootstrap, if there is a cache firmware
* file, it is used; if not, loading from disk is attempted.
*
* ROADMAP
*
* i2400m_barker_db_init Called by i2400m_driver_init()
* i2400m_barker_db_add
*
* i2400m_barker_db_exit Called by i2400m_driver_exit()
*
* i2400m_dev_bootstrap Called by __i2400m_dev_start()
* request_firmware
* i2400m_fw_bootstrap
* i2400m_fw_check
* i2400m_fw_hdr_check
* i2400m_fw_dnload
* release_firmware
*
* i2400m_fw_dnload
* i2400m_bootrom_init
* i2400m_bm_cmd
* i2400m
->bus
_reset
* i2400m_reset
* i2400m_dnload_init
* i2400m_dnload_init_signed
* i2400m_dnload_init_nonsigned
...
...
@@ -125,9 +145,14 @@
* i2400m->bus_bm_cmd_send()
* i2400m->bus_bm_wait_for_ack
* __i2400m_bm_ack_verify
* i2400m_is_boot_barker
*
* i2400m_bm_cmd_prepare Used by bus-drivers to prep
* commands before sending
*
* i2400m_pm_notifier Called on Power Management events
* i2400m_fw_cache
* i2400m_fw_uncache
*/
#include <linux/firmware.h>
#include <linux/sched.h>
...
...
@@ -174,6 +199,240 @@ void i2400m_bm_cmd_prepare(struct i2400m_bootrom_header *cmd)
EXPORT_SYMBOL_GPL
(
i2400m_bm_cmd_prepare
);
/*
* Database of known barkers.
*
* A barker is what the device sends indicating he is ready to be
* bootloaded. Different versions of the device will send different
* barkers. Depending on the barker, it might mean the device wants
* some kind of firmware or the other.
*/
static
struct
i2400m_barker_db
{
__le32
data
[
4
];
}
*
i2400m_barker_db
;
static
size_t
i2400m_barker_db_used
,
i2400m_barker_db_size
;
static
int
i2400m_zrealloc_2x
(
void
**
ptr
,
size_t
*
_count
,
size_t
el_size
,
gfp_t
gfp_flags
)
{
size_t
old_count
=
*
_count
,
new_count
=
old_count
?
2
*
old_count
:
2
,
old_size
=
el_size
*
old_count
,
new_size
=
el_size
*
new_count
;
void
*
nptr
=
krealloc
(
*
ptr
,
new_size
,
gfp_flags
);
if
(
nptr
)
{
/* zero the other half or the whole thing if old_count
* was zero */
if
(
old_size
==
0
)
memset
(
nptr
,
0
,
new_size
);
else
memset
(
nptr
+
old_size
,
0
,
old_size
);
*
_count
=
new_count
;
*
ptr
=
nptr
;
return
0
;
}
else
return
-
ENOMEM
;
}
/*
* Add a barker to the database
*
* This cannot used outside of this module and only at at module_init
* time. This is to avoid the need to do locking.
*/
static
int
i2400m_barker_db_add
(
u32
barker_id
)
{
int
result
;
struct
i2400m_barker_db
*
barker
;
if
(
i2400m_barker_db_used
>=
i2400m_barker_db_size
)
{
result
=
i2400m_zrealloc_2x
(
(
void
**
)
&
i2400m_barker_db
,
&
i2400m_barker_db_size
,
sizeof
(
i2400m_barker_db
[
0
]),
GFP_KERNEL
);
if
(
result
<
0
)
return
result
;
}
barker
=
i2400m_barker_db
+
i2400m_barker_db_used
++
;
barker
->
data
[
0
]
=
le32_to_cpu
(
barker_id
);
barker
->
data
[
1
]
=
le32_to_cpu
(
barker_id
);
barker
->
data
[
2
]
=
le32_to_cpu
(
barker_id
);
barker
->
data
[
3
]
=
le32_to_cpu
(
barker_id
);
return
0
;
}
void
i2400m_barker_db_exit
(
void
)
{
kfree
(
i2400m_barker_db
);
i2400m_barker_db
=
NULL
;
i2400m_barker_db_size
=
0
;
i2400m_barker_db_used
=
0
;
}
/*
* Helper function to add all the known stable barkers to the barker
* database.
*/
static
int
i2400m_barker_db_known_barkers
(
void
)
{
int
result
;
result
=
i2400m_barker_db_add
(
I2400M_NBOOT_BARKER
);
if
(
result
<
0
)
goto
error_add
;
result
=
i2400m_barker_db_add
(
I2400M_SBOOT_BARKER
);
if
(
result
<
0
)
goto
error_add
;
result
=
i2400m_barker_db_add
(
I2400M_SBOOT_BARKER_6050
);
if
(
result
<
0
)
goto
error_add
;
error_add:
return
result
;
}
/*
* Initialize the barker database
*
* This can only be used from the module_init function for this
* module; this is to avoid the need to do locking.
*
* @options: command line argument with extra barkers to
* recognize. This is a comma-separated list of 32-bit hex
* numbers. They are appended to the existing list. Setting 0
* cleans the existing list and starts a new one.
*/
int
i2400m_barker_db_init
(
const
char
*
_options
)
{
int
result
;
char
*
options
=
NULL
,
*
options_orig
,
*
token
;
i2400m_barker_db
=
NULL
;
i2400m_barker_db_size
=
0
;
i2400m_barker_db_used
=
0
;
result
=
i2400m_barker_db_known_barkers
();
if
(
result
<
0
)
goto
error_add
;
/* parse command line options from i2400m.barkers */
if
(
_options
!=
NULL
)
{
unsigned
barker
;
options_orig
=
kstrdup
(
_options
,
GFP_KERNEL
);
if
(
options_orig
==
NULL
)
goto
error_parse
;
options
=
options_orig
;
while
((
token
=
strsep
(
&
options
,
","
))
!=
NULL
)
{
if
(
*
token
==
'\0'
)
/* eat joint commas */
continue
;
if
(
sscanf
(
token
,
"%x"
,
&
barker
)
!=
1
||
barker
>
0xffffffff
)
{
printk
(
KERN_ERR
"%s: can't recognize "
"i2400m.barkers value '%s' as "
"a 32-bit number
\n
"
,
__func__
,
token
);
result
=
-
EINVAL
;
goto
error_parse
;
}
if
(
barker
==
0
)
{
/* clean list and start new */
i2400m_barker_db_exit
();
continue
;
}
result
=
i2400m_barker_db_add
(
barker
);
if
(
result
<
0
)
goto
error_add
;
}
kfree
(
options_orig
);
}
return
0
;
error_parse:
error_add:
kfree
(
i2400m_barker_db
);
return
result
;
}
/*
* Recognize a boot barker
*
* @buf: buffer where the boot barker.
* @buf_size: size of the buffer (has to be 16 bytes). It is passed
* here so the function can check it for the caller.
*
* Note that as a side effect, upon identifying the obtained boot
* barker, this function will set i2400m->barker to point to the right
* barker database entry. Subsequent calls to the function will result
* in verifying that the same type of boot barker is returned when the
* device [re]boots (as long as the same device instance is used).
*
* Return: 0 if @buf matches a known boot barker. -ENOENT if the
* buffer in @buf doesn't match any boot barker in the database or
* -EILSEQ if the buffer doesn't have the right size.
*/
int
i2400m_is_boot_barker
(
struct
i2400m
*
i2400m
,
const
void
*
buf
,
size_t
buf_size
)
{
int
result
;
struct
device
*
dev
=
i2400m_dev
(
i2400m
);
struct
i2400m_barker_db
*
barker
;
int
i
;
result
=
-
ENOENT
;
if
(
buf_size
!=
sizeof
(
i2400m_barker_db
[
i
].
data
))
return
result
;
/* Short circuit if we have already discovered the barker
* associated with the device. */
if
(
i2400m
->
barker
&&
!
memcmp
(
buf
,
i2400m
->
barker
,
sizeof
(
i2400m
->
barker
->
data
)))
{
unsigned
index
=
(
i2400m
->
barker
-
i2400m_barker_db
)
/
sizeof
(
*
i2400m
->
barker
);
d_printf
(
2
,
dev
,
"boot barker cache-confirmed #%u/%08x
\n
"
,
index
,
le32_to_cpu
(
i2400m
->
barker
->
data
[
0
]));
return
0
;
}
for
(
i
=
0
;
i
<
i2400m_barker_db_used
;
i
++
)
{
barker
=
&
i2400m_barker_db
[
i
];
BUILD_BUG_ON
(
sizeof
(
barker
->
data
)
!=
16
);
if
(
memcmp
(
buf
,
barker
->
data
,
sizeof
(
barker
->
data
)))
continue
;
if
(
i2400m
->
barker
==
NULL
)
{
i2400m
->
barker
=
barker
;
d_printf
(
1
,
dev
,
"boot barker set to #%u/%08x
\n
"
,
i
,
le32_to_cpu
(
barker
->
data
[
0
]));
if
(
barker
->
data
[
0
]
==
le32_to_cpu
(
I2400M_NBOOT_BARKER
))
i2400m
->
sboot
=
0
;
else
i2400m
->
sboot
=
1
;
}
else
if
(
i2400m
->
barker
!=
barker
)
{
dev_err
(
dev
,
"HW inconsistency: device "
"reports a different boot barker "
"than set (from %08x to %08x)
\n
"
,
le32_to_cpu
(
i2400m
->
barker
->
data
[
0
]),
le32_to_cpu
(
barker
->
data
[
0
]));
result
=
-
EIO
;
}
else
d_printf
(
2
,
dev
,
"boot barker confirmed #%u/%08x
\n
"
,
i
,
le32_to_cpu
(
barker
->
data
[
0
]));
result
=
0
;
break
;
}
return
result
;
}
EXPORT_SYMBOL_GPL
(
i2400m_is_boot_barker
);
/*
* Verify the ack data received
*
...
...
@@ -204,20 +463,10 @@ ssize_t __i2400m_bm_ack_verify(struct i2400m *i2400m, int opcode,
opcode
,
ack_size
,
sizeof
(
*
ack
));
goto
error_ack_short
;
}
if
(
ack_size
==
sizeof
(
i2400m_NBOOT_BARKER
)
&&
memcmp
(
ack
,
i2400m_NBOOT_BARKER
,
sizeof
(
*
ack
))
=
=
0
)
{
result
=
i2400m_is_boot_barker
(
i2400m
,
ack
,
ack_size
);
if
(
result
>
=
0
)
{
result
=
-
ERESTARTSYS
;
i2400m
->
sboot
=
0
;
d_printf
(
6
,
dev
,
"boot-mode cmd %d: "
"HW non-signed boot barker
\n
"
,
opcode
);
goto
error_reboot
;
}
if
(
ack_size
==
sizeof
(
i2400m_SBOOT_BARKER
)
&&
memcmp
(
ack
,
i2400m_SBOOT_BARKER
,
sizeof
(
*
ack
))
==
0
)
{
result
=
-
ERESTARTSYS
;
i2400m
->
sboot
=
1
;
d_printf
(
6
,
dev
,
"boot-mode cmd %d: HW signed reboot barker
\n
"
,
opcode
);
d_printf
(
6
,
dev
,
"boot-mode cmd %d: HW boot barker
\n
"
,
opcode
);
goto
error_reboot
;
}
if
(
ack_size
==
sizeof
(
i2400m_ACK_BARKER
)
...
...
@@ -343,7 +592,6 @@ ssize_t i2400m_bm_cmd(struct i2400m *i2400m,
BUG_ON
(
i2400m
->
boot_mode
==
0
);
if
(
cmd
!=
NULL
)
{
/* send the command */
memcpy
(
i2400m
->
bm_cmd_buf
,
cmd
,
cmd_size
);
result
=
i2400m
->
bus_bm_cmd_send
(
i2400m
,
cmd
,
cmd_size
,
flags
);
if
(
result
<
0
)
goto
error_cmd_send
;
...
...
@@ -432,8 +680,8 @@ static int i2400m_download_chunk(struct i2400m *i2400m, const void *chunk,
* Download a BCF file's sections to the device
*
* @i2400m: device descriptor
* @bcf: pointer to firmware data (f
ollowed by the payloads). Assumed
*
verified and consistent.
* @bcf: pointer to firmware data (f
irst header followed by the
*
payloads). Assumed
verified and consistent.
* @bcf_len: length (in bytes) of the @bcf buffer.
*
* Returns: < 0 errno code on error or the offset to the jump instruction.
...
...
@@ -472,14 +720,17 @@ ssize_t i2400m_dnload_bcf(struct i2400m *i2400m,
"downloading section #%zu (@%zu %zu B) to 0x%08x
\n
"
,
section
,
offset
,
sizeof
(
*
bh
)
+
data_size
,
le32_to_cpu
(
bh
->
target_addr
));
if
(
i2400m_brh_get_opcode
(
bh
)
==
I2400M_BRH_SIGNED_JUMP
)
{
/* Secure boot needs to stop here */
d_printf
(
5
,
dev
,
"signed jump found @%zu
\n
"
,
offset
);
/*
* We look for JUMP cmd from the bootmode header,
* either I2400M_BRH_SIGNED_JUMP for secure boot
* or I2400M_BRH_JUMP for unsecure boot, the last chunk
* should be the bootmode header with JUMP cmd.
*/
if
(
i2400m_brh_get_opcode
(
bh
)
==
I2400M_BRH_SIGNED_JUMP
||
i2400m_brh_get_opcode
(
bh
)
==
I2400M_BRH_JUMP
)
{
d_printf
(
5
,
dev
,
"jump found @%zu
\n
"
,
offset
);
break
;
}
if
(
offset
+
section_size
==
bcf_len
)
/* Non-secure boot stops here */
break
;
if
(
offset
+
section_size
>
bcf_len
)
{
dev_err
(
dev
,
"fw %s: bad section #%zu, "
"end (@%zu) beyond EOF (@%zu)
\n
"
,
...
...
@@ -509,14 +760,31 @@ ssize_t i2400m_dnload_bcf(struct i2400m *i2400m,
}
/*
* Indicate if the device emitted a reboot barker that indicates
* "signed boot"
*/
static
unsigned
i2400m_boot_is_signed
(
struct
i2400m
*
i2400m
)
{
return
likely
(
i2400m
->
sboot
);
}
/*
* Do the final steps of uploading firmware
*
* @bcf_hdr: BCF header we are actually using
* @bcf: pointer to the firmware image (which matches the first header
* that is followed by the actual payloads).
* @offset: [byte] offset into @bcf for the command we need to send.
*
* Depending on the boot mode (signed vs non-signed), different
* actions need to be taken.
*/
static
int
i2400m_dnload_finalize
(
struct
i2400m
*
i2400m
,
const
struct
i2400m_bcf_hdr
*
bcf_hdr
,
const
struct
i2400m_bcf_hdr
*
bcf
,
size_t
offset
)
{
int
ret
=
0
;
...
...
@@ -530,10 +798,14 @@ int i2400m_dnload_finalize(struct i2400m *i2400m,
d_fnstart
(
3
,
dev
,
"offset %zu
\n
"
,
offset
);
cmd
=
(
void
*
)
bcf
+
offset
;
if
(
i2400m
->
sboot
==
0
)
{
if
(
i2400m
_boot_is_signed
(
i2400m
)
==
0
)
{
struct
i2400m_bootrom_header
jump_ack
;
d_printf
(
1
,
dev
,
"unsecure boot, jumping to 0x%08x
\n
"
,
le32_to_cpu
(
cmd
->
target_addr
));
cmd_buf
=
i2400m
->
bm_cmd_buf
;
memcpy
(
&
cmd_buf
->
cmd
,
cmd
,
sizeof
(
*
cmd
));
cmd
=
&
cmd_buf
->
cmd
;
/* now cmd points to the actual bootrom_header in cmd_buf */
i2400m_brh_set_opcode
(
cmd
,
I2400M_BRH_JUMP
);
cmd
->
data_size
=
0
;
ret
=
i2400m_bm_cmd
(
i2400m
,
cmd
,
sizeof
(
*
cmd
),
...
...
@@ -544,12 +816,13 @@ int i2400m_dnload_finalize(struct i2400m *i2400m,
cmd_buf
=
i2400m
->
bm_cmd_buf
;
memcpy
(
&
cmd_buf
->
cmd
,
cmd
,
sizeof
(
*
cmd
));
signature_block_offset
=
sizeof
(
*
bcf
)
+
le32_to_cpu
(
bcf
->
key_size
)
*
sizeof
(
u32
)
+
le32_to_cpu
(
bcf
->
exponent_size
)
*
sizeof
(
u32
);
sizeof
(
*
bcf
_hdr
)
+
le32_to_cpu
(
bcf
_hdr
->
key_size
)
*
sizeof
(
u32
)
+
le32_to_cpu
(
bcf
_hdr
->
exponent_size
)
*
sizeof
(
u32
);
signature_block_size
=
le32_to_cpu
(
bcf
->
modulus_size
)
*
sizeof
(
u32
);
memcpy
(
cmd_buf
->
cmd_pl
,
(
void
*
)
bcf
+
signature_block_offset
,
le32_to_cpu
(
bcf_hdr
->
modulus_size
)
*
sizeof
(
u32
);
memcpy
(
cmd_buf
->
cmd_pl
,
(
void
*
)
bcf_hdr
+
signature_block_offset
,
signature_block_size
);
ret
=
i2400m_bm_cmd
(
i2400m
,
&
cmd_buf
->
cmd
,
sizeof
(
cmd_buf
->
cmd
)
+
signature_block_size
,
...
...
@@ -565,7 +838,7 @@ int i2400m_dnload_finalize(struct i2400m *i2400m,
*
* @i2400m: device descriptor
* @flags:
* I2400M_BRI_SOFT: a reboot
notification
has been seen
* I2400M_BRI_SOFT: a reboot
barker
has been seen
* already, so don't wait for it.
*
* I2400M_BRI_NO_REBOOT: Don't send a reboot command, but wait
...
...
@@ -576,17 +849,15 @@ int i2400m_dnload_finalize(struct i2400m *i2400m,
*
* < 0 errno code on error, 0 if ok.
*
* i2400m->sboot set to 0 for unsecure boot process, 1 for secure
* boot process.
*
* Description:
*
* Tries hard enough to put the device in boot-mode. There are two
* main phases to this:
*
* a. (1) send a reboot command and (2) get a reboot barker
* b. (1) ack the reboot sending a reboot barker and (2) getting an
* ack barker in return
*
* b. (1) echo/ack the reboot sending the reboot barker back and (2)
* getting an ack barker in return
*
* We want to skip (a) in some cases [soft]. The state machine is
* horrible, but it is basically: on each phase, send what has to be
...
...
@@ -594,6 +865,16 @@ int i2400m_dnload_finalize(struct i2400m *i2400m,
* have to backtrack and retry, so we keep a max tries counter for
* that.
*
* It sucks because we don't know ahead of time which is going to be
* the reboot barker (the device might send different ones depending
* on its EEPROM config) and once the device reboots and waits for the
* echo/ack reboot barker being sent back, it doesn't understand
* anything else. So we can be left at the point where we don't know
* what to send to it -- cold reset and bus reset seem to have little
* effect. So the function iterates (in this case) through all the
* known barkers and tries them all until an ACK is
* received. Otherwise, it gives up.
*
* If we get a timeout after sending a warm reset, we do it again.
*/
int
i2400m_bootrom_init
(
struct
i2400m
*
i2400m
,
enum
i2400m_bri
flags
)
...
...
@@ -602,10 +883,11 @@ int i2400m_bootrom_init(struct i2400m *i2400m, enum i2400m_bri flags)
struct
device
*
dev
=
i2400m_dev
(
i2400m
);
struct
i2400m_bootrom_header
*
cmd
;
struct
i2400m_bootrom_header
ack
;
int
count
=
I2400M_BOOT_RETRIES
;
int
count
=
i2400m
->
bus_bm_retries
;
int
ack_timeout_cnt
=
1
;
unsigned
i
;
BUILD_BUG_ON
(
sizeof
(
*
cmd
)
!=
sizeof
(
i2400m_
NBOOT_BARKER
));
BUILD_BUG_ON
(
sizeof
(
*
cmd
)
!=
sizeof
(
i2400m_
barker_db
[
0
].
data
));
BUILD_BUG_ON
(
sizeof
(
ack
)
!=
sizeof
(
i2400m_ACK_BARKER
));
d_fnstart
(
4
,
dev
,
"(i2400m %p flags 0x%08x)
\n
"
,
i2400m
,
flags
);
...
...
@@ -614,27 +896,59 @@ int i2400m_bootrom_init(struct i2400m *i2400m, enum i2400m_bri flags)
if
(
flags
&
I2400M_BRI_SOFT
)
goto
do_reboot_ack
;
do_reboot:
ack_timeout_cnt
=
1
;
if
(
--
count
<
0
)
goto
error_timeout
;
d_printf
(
4
,
dev
,
"device reboot: reboot command [%d # left]
\n
"
,
count
);
if
((
flags
&
I2400M_BRI_NO_REBOOT
)
==
0
)
i2400m
->
bus
_reset
(
i2400m
,
I2400M_RT_WARM
);
i2400m_reset
(
i2400m
,
I2400M_RT_WARM
);
result
=
i2400m_bm_cmd
(
i2400m
,
NULL
,
0
,
&
ack
,
sizeof
(
ack
),
I2400M_BM_CMD_RAW
);
flags
&=
~
I2400M_BRI_NO_REBOOT
;
switch
(
result
)
{
case
-
ERESTARTSYS
:
/*
* at this point, i2400m_bm_cmd(), through
* __i2400m_bm_ack_process(), has updated
* i2400m->barker and we are good to go.
*/
d_printf
(
4
,
dev
,
"device reboot: got reboot barker
\n
"
);
break
;
case
-
EISCONN
:
/* we don't know how it got here...but we follow it */
d_printf
(
4
,
dev
,
"device reboot: got ack barker - whatever
\n
"
);
goto
do_reboot
;
case
-
ETIMEDOUT
:
/* device has timed out, we might be in boot
* mode already and expecting an ack, let's try
* that */
dev_info
(
dev
,
"warm reset timed out, trying an ack
\n
"
);
case
-
ETIMEDOUT
:
/*
* Device has timed out, we might be in boot mode
* already and expecting an ack; if we don't know what
* the barker is, we just send them all. Cold reset
* and bus reset don't work. Beats me.
*/
if
(
i2400m
->
barker
!=
NULL
)
{
dev_err
(
dev
,
"device boot: reboot barker timed out, "
"trying (set) %08x echo/ack
\n
"
,
le32_to_cpu
(
i2400m
->
barker
->
data
[
0
]));
goto
do_reboot_ack
;
}
for
(
i
=
0
;
i
<
i2400m_barker_db_used
;
i
++
)
{
struct
i2400m_barker_db
*
barker
=
&
i2400m_barker_db
[
i
];
memcpy
(
cmd
,
barker
->
data
,
sizeof
(
barker
->
data
));
result
=
i2400m_bm_cmd
(
i2400m
,
cmd
,
sizeof
(
*
cmd
),
&
ack
,
sizeof
(
ack
),
I2400M_BM_CMD_RAW
);
if
(
result
==
-
EISCONN
)
{
dev_warn
(
dev
,
"device boot: got ack barker "
"after sending echo/ack barker "
"#%d/%08x; rebooting j.i.c.
\n
"
,
i
,
le32_to_cpu
(
barker
->
data
[
0
]));
flags
&=
~
I2400M_BRI_NO_REBOOT
;
goto
do_reboot
;
}
}
dev_err
(
dev
,
"device boot: tried all the echo/acks, could "
"not get device to respond; giving up"
);
result
=
-
ESHUTDOWN
;
case
-
EPROTO
:
case
-
ESHUTDOWN
:
/* dev is gone */
case
-
EINTR
:
/* user cancelled */
...
...
@@ -642,6 +956,7 @@ int i2400m_bootrom_init(struct i2400m *i2400m, enum i2400m_bri flags)
default:
dev_err
(
dev
,
"device reboot: error %d while waiting "
"for reboot barker - rebooting
\n
"
,
result
);
d_dump
(
1
,
dev
,
&
ack
,
result
);
goto
do_reboot
;
}
/* At this point we ack back with 4 REBOOT barkers and expect
...
...
@@ -650,12 +965,7 @@ int i2400m_bootrom_init(struct i2400m *i2400m, enum i2400m_bri flags)
* notification and report it as -EISCONN. */
do_reboot_ack:
d_printf
(
4
,
dev
,
"device reboot ack: sending ack [%d # left]
\n
"
,
count
);
if
(
i2400m
->
sboot
==
0
)
memcpy
(
cmd
,
i2400m_NBOOT_BARKER
,
sizeof
(
i2400m_NBOOT_BARKER
));
else
memcpy
(
cmd
,
i2400m_SBOOT_BARKER
,
sizeof
(
i2400m_SBOOT_BARKER
));
memcpy
(
cmd
,
i2400m
->
barker
->
data
,
sizeof
(
i2400m
->
barker
->
data
));
result
=
i2400m_bm_cmd
(
i2400m
,
cmd
,
sizeof
(
*
cmd
),
&
ack
,
sizeof
(
ack
),
I2400M_BM_CMD_RAW
);
switch
(
result
)
{
...
...
@@ -668,10 +978,8 @@ int i2400m_bootrom_init(struct i2400m *i2400m, enum i2400m_bri flags)
d_printf
(
4
,
dev
,
"reboot ack: got ack barker - good
\n
"
);
break
;
case
-
ETIMEDOUT
:
/* no response, maybe it is the other type? */
if
(
ack_timeout_cnt
--
>=
0
)
{
d_printf
(
4
,
dev
,
"reboot ack timedout: "
"trying the other type?
\n
"
);
i2400m
->
sboot
=
!
i2400m
->
sboot
;
if
(
ack_timeout_cnt
--
<
0
)
{
d_printf
(
4
,
dev
,
"reboot ack timedout: retrying
\n
"
);
goto
do_reboot_ack
;
}
else
{
dev_err
(
dev
,
"reboot ack timedout too long: "
...
...
@@ -839,32 +1147,29 @@ int i2400m_dnload_init_signed(struct i2400m *i2400m,
* (signed or non-signed).
*/
static
int
i2400m_dnload_init
(
struct
i2400m
*
i2400m
,
const
struct
i2400m_bcf_hdr
*
bcf
)
int
i2400m_dnload_init
(
struct
i2400m
*
i2400m
,
const
struct
i2400m_bcf_hdr
*
bcf_hdr
)
{
int
result
;
struct
device
*
dev
=
i2400m_dev
(
i2400m
);
u32
module_id
=
le32_to_cpu
(
bcf
->
module_id
);
if
(
i2400m
->
sboot
==
0
&&
(
module_id
&
I2400M_BCF_MOD_ID_POKES
)
==
0
)
{
/* non-signed boot process without pokes */
result
=
i2400m_dnload_init_nonsigned
(
i2400m
);
if
(
i2400m_boot_is_signed
(
i2400m
))
{
d_printf
(
1
,
dev
,
"signed boot
\n
"
);
result
=
i2400m_dnload_init_signed
(
i2400m
,
bcf_hdr
);
if
(
result
==
-
ERESTARTSYS
)
return
result
;
if
(
result
<
0
)
dev_err
(
dev
,
"f
w %s: non-signed
download "
dev_err
(
dev
,
"f
irmware %s: signed boot
download "
"initialization failed: %d
\n
"
,
i2400m
->
fw_name
,
result
);
}
else
if
(
i2400m
->
sboot
==
0
&&
(
module_id
&
I2400M_BCF_MOD_ID_POKES
))
{
/* non-signed boot process with pokes, nothing to do */
result
=
0
;
}
else
{
/* signed boot process */
result
=
i2400m_dnload_init_signed
(
i2400m
,
bcf
);
}
else
{
/* non-signed boot process without pokes */
d_printf
(
1
,
dev
,
"non-signed boot
\n
"
);
result
=
i2400m_dnload_init_nonsigned
(
i2400m
);
if
(
result
==
-
ERESTARTSYS
)
return
result
;
if
(
result
<
0
)
dev_err
(
dev
,
"f
w %s: signed boot
download "
dev_err
(
dev
,
"f
irmware %s: non-signed
download "
"initialization failed: %d
\n
"
,
i2400m
->
fw_name
,
result
);
}
...
...
@@ -873,73 +1178,200 @@ int i2400m_dnload_init(struct i2400m *i2400m, const struct i2400m_bcf_hdr *bcf)
/*
* Run
quick consistency tests on the firmware file
* Run
consistency tests on the firmware file and load up headers
*
* Check for the firmware being made for the i2400m device,
* etc...These checks are mostly informative, as the device will make
* them too; but the driver's response is more informative on what
* went wrong.
*
* This will also look at all the headers present on the firmware
* file, and update i2400m->fw_bcf_hdr to point to them.
*/
static
int
i2400m_fw_check
(
struct
i2400m
*
i2400m
,
const
struct
i2400m_bcf_hdr
*
bcf
,
size_t
bcf_size
)
int
i2400m_fw_
hdr_
check
(
struct
i2400m
*
i2400m
,
const
struct
i2400m_bcf_hdr
*
bcf_hdr
,
size_t
index
,
size_t
offset
)
{
int
result
;
struct
device
*
dev
=
i2400m_dev
(
i2400m
);
unsigned
module_type
,
header_len
,
major_version
,
minor_version
,
module_id
,
module_vendor
,
date
,
size
;
/* Check hard errors */
result
=
-
EINVAL
;
if
(
bcf_size
<
sizeof
(
*
bcf
))
{
/* big enough header? */
dev_err
(
dev
,
"firmware %s too short: "
"%zu B vs %zu (at least) expected
\n
"
,
i2400m
->
fw_name
,
bcf_size
,
sizeof
(
*
bcf
));
goto
error
;
module_type
=
bcf_hdr
->
module_type
;
header_len
=
sizeof
(
u32
)
*
le32_to_cpu
(
bcf_hdr
->
header_len
);
major_version
=
(
le32_to_cpu
(
bcf_hdr
->
header_version
)
&
0xffff0000
)
>>
16
;
minor_version
=
le32_to_cpu
(
bcf_hdr
->
header_version
)
&
0x0000ffff
;
module_id
=
le32_to_cpu
(
bcf_hdr
->
module_id
);
module_vendor
=
le32_to_cpu
(
bcf_hdr
->
module_vendor
);
date
=
le32_to_cpu
(
bcf_hdr
->
date
);
size
=
sizeof
(
u32
)
*
le32_to_cpu
(
bcf_hdr
->
size
);
d_printf
(
1
,
dev
,
"firmware %s #%zd@%08zx: BCF header "
"type:vendor:id 0x%x:%x:%x v%u.%u (%u/%u B) built %08x
\n
"
,
i2400m
->
fw_name
,
index
,
offset
,
module_type
,
module_vendor
,
module_id
,
major_version
,
minor_version
,
header_len
,
size
,
date
);
/* Hard errors */
if
(
major_version
!=
1
)
{
dev_err
(
dev
,
"firmware %s #%zd@%08zx: major header version "
"v%u.%u not supported
\n
"
,
i2400m
->
fw_name
,
index
,
offset
,
major_version
,
minor_version
);
return
-
EBADF
;
}
if
(
module_type
!=
6
)
{
/* built for the right hardware? */
dev_err
(
dev
,
"firmware %s #%zd@%08zx: unexpected module "
"type 0x%x; aborting
\n
"
,
i2400m
->
fw_name
,
index
,
offset
,
module_type
);
return
-
EBADF
;
}
module_type
=
bcf
->
module_type
;
header_len
=
sizeof
(
u32
)
*
le32_to_cpu
(
bcf
->
header_len
);
major_version
=
le32_to_cpu
(
bcf
->
header_version
)
&
0xffff0000
>>
16
;
minor_version
=
le32_to_cpu
(
bcf
->
header_version
)
&
0x0000ffff
;
module_id
=
le32_to_cpu
(
bcf
->
module_id
);
module_vendor
=
le32_to_cpu
(
bcf
->
module_vendor
);
date
=
le32_to_cpu
(
bcf
->
date
);
size
=
sizeof
(
u32
)
*
le32_to_cpu
(
bcf
->
size
);
if
(
bcf_size
!=
size
)
{
/* annoyingly paranoid */
dev_err
(
dev
,
"firmware %s: bad size, got "
"%zu B vs %u expected
\n
"
,
i2400m
->
fw_name
,
bcf_size
,
size
);
goto
error
;
if
(
module_vendor
!=
0x8086
)
{
dev_err
(
dev
,
"firmware %s #%zd@%08zx: unexpected module "
"vendor 0x%x; aborting
\n
"
,
i2400m
->
fw_name
,
index
,
offset
,
module_vendor
);
return
-
EBADF
;
}
d_printf
(
2
,
dev
,
"type 0x%x id 0x%x vendor 0x%x; header v%u.%u (%zu B) "
"date %08x (%zu B)
\n
"
,
module_type
,
module_id
,
module_vendor
,
major_version
,
minor_version
,
(
size_t
)
header_len
,
date
,
(
size_t
)
size
);
if
(
date
<
0x20080300
)
dev_warn
(
dev
,
"firmware %s #%zd@%08zx: build date %08x "
"too old; unsupported
\n
"
,
i2400m
->
fw_name
,
index
,
offset
,
date
);
return
0
;
}
if
(
module_type
!=
6
)
{
/* built for the right hardware? */
dev_err
(
dev
,
"bad fw %s: unexpected module type 0x%x; "
"aborting
\n
"
,
i2400m
->
fw_name
,
module_type
);
goto
error
;
/*
* Run consistency tests on the firmware file and load up headers
*
* Check for the firmware being made for the i2400m device,
* etc...These checks are mostly informative, as the device will make
* them too; but the driver's response is more informative on what
* went wrong.
*
* This will also look at all the headers present on the firmware
* file, and update i2400m->fw_hdrs to point to them.
*/
static
int
i2400m_fw_check
(
struct
i2400m
*
i2400m
,
const
void
*
bcf
,
size_t
bcf_size
)
{
int
result
;
struct
device
*
dev
=
i2400m_dev
(
i2400m
);
size_t
headers
=
0
;
const
struct
i2400m_bcf_hdr
*
bcf_hdr
;
const
void
*
itr
,
*
next
,
*
top
;
size_t
slots
=
0
,
used_slots
=
0
;
for
(
itr
=
bcf
,
top
=
itr
+
bcf_size
;
itr
<
top
;
headers
++
,
itr
=
next
)
{
size_t
leftover
,
offset
,
header_len
,
size
;
leftover
=
top
-
itr
;
offset
=
itr
-
(
const
void
*
)
bcf
;
if
(
leftover
<=
sizeof
(
*
bcf_hdr
))
{
dev_err
(
dev
,
"firmware %s: %zu B left at @%zx, "
"not enough for BCF header
\n
"
,
i2400m
->
fw_name
,
leftover
,
offset
);
break
;
}
bcf_hdr
=
itr
;
/* Only the first header is supposed to be followed by
* payload */
header_len
=
sizeof
(
u32
)
*
le32_to_cpu
(
bcf_hdr
->
header_len
);
size
=
sizeof
(
u32
)
*
le32_to_cpu
(
bcf_hdr
->
size
);
if
(
headers
==
0
)
next
=
itr
+
size
;
else
next
=
itr
+
header_len
;
/* Check soft-er errors */
result
=
i2400m_fw_hdr_check
(
i2400m
,
bcf_hdr
,
headers
,
offset
);
if
(
result
<
0
)
continue
;
if
(
used_slots
+
1
>=
slots
)
{
/* +1 -> we need to account for the one we'll
* occupy and at least an extra one for
* always being NULL */
result
=
i2400m_zrealloc_2x
(
(
void
**
)
&
i2400m
->
fw_hdrs
,
&
slots
,
sizeof
(
i2400m
->
fw_hdrs
[
0
]),
GFP_KERNEL
);
if
(
result
<
0
)
goto
error_zrealloc
;
}
i2400m
->
fw_hdrs
[
used_slots
]
=
bcf_hdr
;
used_slots
++
;
}
if
(
headers
==
0
)
{
dev_err
(
dev
,
"firmware %s: no usable headers found
\n
"
,
i2400m
->
fw_name
);
result
=
-
EBADF
;
}
else
result
=
0
;
if
(
module_vendor
!=
0x8086
)
dev_err
(
dev
,
"bad fw %s? unexpected vendor 0x%04x
\n
"
,
i2400m
->
fw_name
,
module_vendor
);
if
(
date
<
0x20080300
)
dev_err
(
dev
,
"bad fw %s? build date too old %08x
\n
"
,
i2400m
->
fw_name
,
date
);
error:
error_zrealloc:
return
result
;
}
/*
* Match a barker to a BCF header module ID
*
* The device sends a barker which tells the firmware loader which
* header in the BCF file has to be used. This does the matching.
*/
static
unsigned
i2400m_bcf_hdr_match
(
struct
i2400m
*
i2400m
,
const
struct
i2400m_bcf_hdr
*
bcf_hdr
)
{
u32
barker
=
le32_to_cpu
(
i2400m
->
barker
->
data
[
0
])
&
0x7fffffff
;
u32
module_id
=
le32_to_cpu
(
bcf_hdr
->
module_id
)
&
0x7fffffff
;
/* high bit used for something else */
/* special case for 5x50 */
if
(
barker
==
I2400M_SBOOT_BARKER
&&
module_id
==
0
)
return
1
;
if
(
module_id
==
barker
)
return
1
;
return
0
;
}
static
const
struct
i2400m_bcf_hdr
*
i2400m_bcf_hdr_find
(
struct
i2400m
*
i2400m
)
{
struct
device
*
dev
=
i2400m_dev
(
i2400m
);
const
struct
i2400m_bcf_hdr
**
bcf_itr
,
*
bcf_hdr
;
unsigned
i
=
0
;
u32
barker
=
le32_to_cpu
(
i2400m
->
barker
->
data
[
0
]);
d_printf
(
2
,
dev
,
"finding BCF header for barker %08x
\n
"
,
barker
);
if
(
barker
==
I2400M_NBOOT_BARKER
)
{
bcf_hdr
=
i2400m
->
fw_hdrs
[
0
];
d_printf
(
1
,
dev
,
"using BCF header #%u/%08x for non-signed "
"barker
\n
"
,
0
,
le32_to_cpu
(
bcf_hdr
->
module_id
));
return
bcf_hdr
;
}
for
(
bcf_itr
=
i2400m
->
fw_hdrs
;
*
bcf_itr
!=
NULL
;
bcf_itr
++
,
i
++
)
{
bcf_hdr
=
*
bcf_itr
;
if
(
i2400m_bcf_hdr_match
(
i2400m
,
bcf_hdr
))
{
d_printf
(
1
,
dev
,
"hit on BCF hdr #%u/%08x
\n
"
,
i
,
le32_to_cpu
(
bcf_hdr
->
module_id
));
return
bcf_hdr
;
}
else
d_printf
(
1
,
dev
,
"miss on BCF hdr #%u/%08x
\n
"
,
i
,
le32_to_cpu
(
bcf_hdr
->
module_id
));
}
dev_err
(
dev
,
"cannot find a matching BCF header for barker %08x
\n
"
,
barker
);
return
NULL
;
}
/*
* Download the firmware to the device
*
...
...
@@ -956,14 +1388,16 @@ int i2400m_fw_check(struct i2400m *i2400m,
*/
static
int
i2400m_fw_dnload
(
struct
i2400m
*
i2400m
,
const
struct
i2400m_bcf_hdr
*
bcf
,
size_t
bcf
_size
,
enum
i2400m_bri
flags
)
size_t
fw
_size
,
enum
i2400m_bri
flags
)
{
int
ret
=
0
;
struct
device
*
dev
=
i2400m_dev
(
i2400m
);
int
count
=
i2400m
->
bus_bm_retries
;
const
struct
i2400m_bcf_hdr
*
bcf_hdr
;
size_t
bcf_size
;
d_fnstart
(
5
,
dev
,
"(i2400m %p bcf %p size %zu)
\n
"
,
i2400m
,
bcf
,
bcf
_size
);
d_fnstart
(
5
,
dev
,
"(i2400m %p bcf %p
fw
size %zu)
\n
"
,
i2400m
,
bcf
,
fw
_size
);
i2400m
->
boot_mode
=
1
;
wmb
();
/* Make sure other readers see it */
hw_reboot:
...
...
@@ -985,13 +1419,28 @@ int i2400m_fw_dnload(struct i2400m *i2400m, const struct i2400m_bcf_hdr *bcf,
* Initialize the download, push the bytes to the device and
* then jump to the new firmware. Note @ret is passed with the
* offset of the jump instruction to _dnload_finalize()
*
* Note we need to use the BCF header in the firmware image
* that matches the barker that the device sent when it
* rebooted, so it has to be passed along.
*/
ret
=
i2400m_dnload_init
(
i2400m
,
bcf
);
/* Init device's dnload */
ret
=
-
EBADF
;
bcf_hdr
=
i2400m_bcf_hdr_find
(
i2400m
);
if
(
bcf_hdr
==
NULL
)
goto
error_bcf_hdr_find
;
ret
=
i2400m_dnload_init
(
i2400m
,
bcf_hdr
);
if
(
ret
==
-
ERESTARTSYS
)
goto
error_dev_rebooted
;
if
(
ret
<
0
)
goto
error_dnload_init
;
/*
* bcf_size refers to one header size plus the fw sections size
* indicated by the header,ie. if there are other extended headers
* at the tail, they are not counted
*/
bcf_size
=
sizeof
(
u32
)
*
le32_to_cpu
(
bcf_hdr
->
size
);
ret
=
i2400m_dnload_bcf
(
i2400m
,
bcf
,
bcf_size
);
if
(
ret
==
-
ERESTARTSYS
)
goto
error_dev_rebooted
;
...
...
@@ -1001,7 +1450,7 @@ int i2400m_fw_dnload(struct i2400m *i2400m, const struct i2400m_bcf_hdr *bcf,
goto
error_dnload_bcf
;
}
ret
=
i2400m_dnload_finalize
(
i2400m
,
bcf
,
ret
);
ret
=
i2400m_dnload_finalize
(
i2400m
,
bcf
_hdr
,
bcf
,
ret
);
if
(
ret
==
-
ERESTARTSYS
)
goto
error_dev_rebooted
;
if
(
ret
<
0
)
{
...
...
@@ -1018,10 +1467,11 @@ int i2400m_fw_dnload(struct i2400m *i2400m, const struct i2400m_bcf_hdr *bcf,
error_dnload_finalize:
error_dnload_bcf:
error_dnload_init:
error_bcf_hdr_find:
error_bootrom_init:
error_too_many_reboots:
d_fnend
(
5
,
dev
,
"(i2400m %p bcf %p size %zu) = %d
\n
"
,
i2400m
,
bcf
,
bcf
_size
,
ret
);
i2400m
,
bcf
,
fw
_size
,
ret
);
return
ret
;
error_dev_rebooted:
...
...
@@ -1031,6 +1481,61 @@ int i2400m_fw_dnload(struct i2400m *i2400m, const struct i2400m_bcf_hdr *bcf,
goto
hw_reboot
;
}
static
int
i2400m_fw_bootstrap
(
struct
i2400m
*
i2400m
,
const
struct
firmware
*
fw
,
enum
i2400m_bri
flags
)
{
int
ret
;
struct
device
*
dev
=
i2400m_dev
(
i2400m
);
const
struct
i2400m_bcf_hdr
*
bcf
;
/* Firmware data */
d_fnstart
(
5
,
dev
,
"(i2400m %p)
\n
"
,
i2400m
);
bcf
=
(
void
*
)
fw
->
data
;
ret
=
i2400m_fw_check
(
i2400m
,
bcf
,
fw
->
size
);
if
(
ret
>=
0
)
ret
=
i2400m_fw_dnload
(
i2400m
,
bcf
,
fw
->
size
,
flags
);
if
(
ret
<
0
)
dev_err
(
dev
,
"%s: cannot use: %d, skipping
\n
"
,
i2400m
->
fw_name
,
ret
);
kfree
(
i2400m
->
fw_hdrs
);
i2400m
->
fw_hdrs
=
NULL
;
d_fnend
(
5
,
dev
,
"(i2400m %p) = %d
\n
"
,
i2400m
,
ret
);
return
ret
;
}
/* Refcounted container for firmware data */
struct
i2400m_fw
{
struct
kref
kref
;
const
struct
firmware
*
fw
;
};
static
void
i2400m_fw_destroy
(
struct
kref
*
kref
)
{
struct
i2400m_fw
*
i2400m_fw
=
container_of
(
kref
,
struct
i2400m_fw
,
kref
);
release_firmware
(
i2400m_fw
->
fw
);
kfree
(
i2400m_fw
);
}
static
struct
i2400m_fw
*
i2400m_fw_get
(
struct
i2400m_fw
*
i2400m_fw
)
{
if
(
i2400m_fw
!=
NULL
&&
i2400m_fw
!=
(
void
*
)
~
0
)
kref_get
(
&
i2400m_fw
->
kref
);
return
i2400m_fw
;
}
static
void
i2400m_fw_put
(
struct
i2400m_fw
*
i2400m_fw
)
{
kref_put
(
&
i2400m_fw
->
kref
,
i2400m_fw_destroy
);
}
/**
* i2400m_dev_bootstrap - Bring the device to a known state and upload firmware
...
...
@@ -1049,42 +1554,109 @@ int i2400m_fw_dnload(struct i2400m *i2400m, const struct i2400m_bcf_hdr *bcf,
*/
int
i2400m_dev_bootstrap
(
struct
i2400m
*
i2400m
,
enum
i2400m_bri
flags
)
{
int
ret
=
0
,
itr
=
0
;
int
ret
,
itr
;
struct
device
*
dev
=
i2400m_dev
(
i2400m
);
const
struct
firmware
*
fw
;
struct
i2400m_fw
*
i2400m_
fw
;
const
struct
i2400m_bcf_hdr
*
bcf
;
/* Firmware data */
const
struct
firmware
*
fw
;
const
char
*
fw_name
;
d_fnstart
(
5
,
dev
,
"(i2400m %p)
\n
"
,
i2400m
);
ret
=
-
ENODEV
;
spin_lock
(
&
i2400m
->
rx_lock
);
i2400m_fw
=
i2400m_fw_get
(
i2400m
->
fw_cached
);
spin_unlock
(
&
i2400m
->
rx_lock
);
if
(
i2400m_fw
==
(
void
*
)
~
0
)
{
dev_err
(
dev
,
"can't load firmware now!"
);
goto
out
;
}
else
if
(
i2400m_fw
!=
NULL
)
{
dev_info
(
dev
,
"firmware %s: loading from cache
\n
"
,
i2400m
->
fw_name
);
ret
=
i2400m_fw_bootstrap
(
i2400m
,
i2400m_fw
->
fw
,
flags
);
i2400m_fw_put
(
i2400m_fw
);
goto
out
;
}
/* Load firmware files to memory. */
itr
=
0
;
while
(
1
)
{
for
(
itr
=
0
,
bcf
=
NULL
,
ret
=
-
ENOENT
;
;
itr
++
)
{
fw_name
=
i2400m
->
bus_fw_names
[
itr
];
if
(
fw_name
==
NULL
)
{
dev_err
(
dev
,
"Could not find a usable firmware image
\n
"
);
ret
=
-
ENOENT
;
goto
error_no_fw
;
break
;
}
d_printf
(
1
,
dev
,
"trying firmware %s (%d)
\n
"
,
fw_name
,
itr
);
ret
=
request_firmware
(
&
fw
,
fw_name
,
dev
);
if
(
ret
==
0
)
break
;
/* got it */
if
(
ret
<
0
)
if
(
ret
<
0
)
{
dev_err
(
dev
,
"fw %s: cannot load file: %d
\n
"
,
fw_name
,
ret
);
itr
++
;
continue
;
}
bcf
=
(
void
*
)
fw
->
data
;
i2400m
->
fw_name
=
fw_name
;
ret
=
i2400m_fw_check
(
i2400m
,
bcf
,
fw
->
size
);
if
(
ret
<
0
)
goto
error_fw_bad
;
ret
=
i2400m_fw_dnload
(
i2400m
,
bcf
,
fw
->
size
,
flags
);
error_fw_bad:
ret
=
i2400m_fw_bootstrap
(
i2400m
,
fw
,
flags
);
release_firmware
(
fw
);
error_no_fw:
if
(
ret
>=
0
)
/* firmware loaded succesfully */
break
;
i2400m
->
fw_name
=
NULL
;
}
out:
d_fnend
(
5
,
dev
,
"(i2400m %p) = %d
\n
"
,
i2400m
,
ret
);
return
ret
;
}
EXPORT_SYMBOL_GPL
(
i2400m_dev_bootstrap
);
void
i2400m_fw_cache
(
struct
i2400m
*
i2400m
)
{
int
result
;
struct
i2400m_fw
*
i2400m_fw
;
struct
device
*
dev
=
i2400m_dev
(
i2400m
);
/* if there is anything there, free it -- now, this'd be weird */
spin_lock
(
&
i2400m
->
rx_lock
);
i2400m_fw
=
i2400m
->
fw_cached
;
spin_unlock
(
&
i2400m
->
rx_lock
);
if
(
i2400m_fw
!=
NULL
&&
i2400m_fw
!=
(
void
*
)
~
0
)
{
i2400m_fw_put
(
i2400m_fw
);
WARN
(
1
,
"%s:%u: still cached fw still present?
\n
"
,
__func__
,
__LINE__
);
}
if
(
i2400m
->
fw_name
==
NULL
)
{
dev_err
(
dev
,
"firmware n/a: can't cache
\n
"
);
i2400m_fw
=
(
void
*
)
~
0
;
goto
out
;
}
i2400m_fw
=
kzalloc
(
sizeof
(
*
i2400m_fw
),
GFP_ATOMIC
);
if
(
i2400m_fw
==
NULL
)
goto
out
;
kref_init
(
&
i2400m_fw
->
kref
);
result
=
request_firmware
(
&
i2400m_fw
->
fw
,
i2400m
->
fw_name
,
dev
);
if
(
result
<
0
)
{
dev_err
(
dev
,
"firmware %s: failed to cache: %d
\n
"
,
i2400m
->
fw_name
,
result
);
kfree
(
i2400m_fw
);
i2400m_fw
=
(
void
*
)
~
0
;
}
else
dev_info
(
dev
,
"firmware %s: cached
\n
"
,
i2400m
->
fw_name
);
out:
spin_lock
(
&
i2400m
->
rx_lock
);
i2400m
->
fw_cached
=
i2400m_fw
;
spin_unlock
(
&
i2400m
->
rx_lock
);
}
void
i2400m_fw_uncache
(
struct
i2400m
*
i2400m
)
{
struct
i2400m_fw
*
i2400m_fw
;
spin_lock
(
&
i2400m
->
rx_lock
);
i2400m_fw
=
i2400m
->
fw_cached
;
i2400m
->
fw_cached
=
NULL
;
spin_unlock
(
&
i2400m
->
rx_lock
);
if
(
i2400m_fw
!=
NULL
&&
i2400m_fw
!=
(
void
*
)
~
0
)
i2400m_fw_put
(
i2400m_fw
);
}
drivers/net/wimax/i2400m/i2400m-sdio.h
View file @
62d83681
...
...
@@ -67,6 +67,7 @@
/* Host-Device interface for SDIO */
enum
{
I2400M_SDIO_BOOT_RETRIES
=
3
,
I2400MS_BLK_SIZE
=
256
,
I2400MS_PL_SIZE_MAX
=
0x3E00
,
...
...
@@ -77,9 +78,11 @@ enum {
I2400MS_INTR_GET_SIZE_ADDR
=
0x2C
,
/* The number of ticks to wait for the device to signal that
* it is ready */
I2400MS_INIT_SLEEP_INTERVAL
=
10
,
I2400MS_INIT_SLEEP_INTERVAL
=
10
0
,
/* How long to wait for the device to settle after reset */
I2400MS_SETTLE_TIME
=
40
,
/* The number of msec to wait for IOR after sending IOE */
IWMC3200_IOR_TIMEOUT
=
10
,
};
...
...
@@ -97,6 +100,14 @@ 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.
*
* @debugfs_dentry: dentry for the SDIO specific debugfs files
*
* Note this value is set to NULL upon destruction; this is
* because some routinges use it to determine if we are inside the
* probe() path or some other path. When debugfs is disabled,
* creation sets the dentry to '(void*) -ENODEV', which is valid
* for the test.
*/
struct
i2400ms
{
struct
i2400m
i2400m
;
/* FIRST! See doc */
...
...
@@ -111,6 +122,9 @@ struct i2400ms {
wait_queue_head_t
bm_wfa_wq
;
int
bm_wait_result
;
size_t
bm_ack_size
;
/* Device is any of the iwmc3200 SKUs */
unsigned
iwmc3200
:
1
;
};
...
...
drivers/net/wimax/i2400m/i2400m-usb.h
View file @
62d83681
...
...
@@ -88,6 +88,13 @@ struct edc {
u16
errorcount
;
};
struct
i2400m_endpoint_cfg
{
unsigned
char
bulk_out
;
unsigned
char
notification
;
unsigned
char
reset_cold
;
unsigned
char
bulk_in
;
};
static
inline
void
edc_init
(
struct
edc
*
edc
)
{
edc
->
timestart
=
jiffies
;
...
...
@@ -137,15 +144,13 @@ static inline int edc_inc(struct edc *edc, u16 max_err, u16 timeframe)
/* Host-Device interface for USB */
enum
{
I2400M_USB_BOOT_RETRIES
=
3
,
I2400MU_MAX_NOTIFICATION_LEN
=
256
,
I2400MU_BLK_SIZE
=
16
,
I2400MU_PL_SIZE_MAX
=
0x3EFF
,
/* Endpoints */
I2400MU_EP_BULK_OUT
=
0
,
I2400MU_EP_NOTIFICATION
,
I2400MU_EP_RESET_COLD
,
I2400MU_EP_BULK_IN
,
/* Device IDs */
USB_DEVICE_ID_I6050
=
0x0186
,
};
...
...
@@ -215,6 +220,7 @@ struct i2400mu {
struct
usb_device
*
usb_dev
;
struct
usb_interface
*
usb_iface
;
struct
edc
urb_edc
;
/* Error density counter */
struct
i2400m_endpoint_cfg
endpoint_cfg
;
struct
urb
*
notif_urb
;
struct
task_struct
*
tx_kthread
;
...
...
drivers/net/wimax/i2400m/i2400m.h
View file @
62d83681
...
...
@@ -117,16 +117,30 @@
* well as i2400m->wimax_dev.net_dev and call i2400m_setup(). The
* i2400m driver will only register with the WiMAX and network stacks;
* the only access done to the device is to read the MAC address so we
* can register a network device. This calls i2400m_dev_start() to
* load firmware, setup communication with the device and configure it
* for operation.
* can register a network device.
*
* At this point, control and data communications are possible.
* The high-level call flow is:
*
* bus_probe()
* i2400m_setup()
* i2400m->bus_setup()
* boot rom initialization / read mac addr
* network / WiMAX stacks registration
* i2400m_dev_start()
* i2400m->bus_dev_start()
* i2400m_dev_initialize()
*
* On disconnect/driver unload, the bus-specific disconnect function
* calls i2400m_release() to undo i2400m_setup(). i2400m_dev_stop()
* shuts the firmware down and releases resources uses to communicate
* with the device.
* The reverse applies for a disconnect() call:
*
* bus_disconnect()
* i2400m_release()
* i2400m_dev_stop()
* i2400m_dev_shutdown()
* i2400m->bus_dev_stop()
* network / WiMAX stack unregistration
* i2400m->bus_release()
*
* At this point, control and data communications are possible.
*
* While the device is up, it might reset. The bus-specific driver has
* to catch that situation and call i2400m_dev_reset_handle() to deal
...
...
@@ -148,9 +162,6 @@
/* Misc constants */
enum
{
/* Firmware uploading */
I2400M_BOOT_RETRIES
=
3
,
I3200_BOOT_RETRIES
=
3
,
/* Size of the Boot Mode Command buffer */
I2400M_BM_CMD_BUF_SIZE
=
16
*
1024
,
I2400M_BM_ACK_BUF_SIZE
=
256
,
...
...
@@ -197,6 +208,7 @@ enum i2400m_reset_type {
struct
i2400m_reset_ctx
;
struct
i2400m_roq
;
struct
i2400m_barker_db
;
/**
* struct i2400m - descriptor for an Intel 2400m
...
...
@@ -204,22 +216,45 @@ struct i2400m_roq;
* Members marked with [fill] must be filled out/initialized before
* calling i2400m_setup().
*
* Note the @bus_setup/@bus_release, @bus_dev_start/@bus_dev_release
* call pairs are very much doing almost the same, and depending on
* the underlying bus, some stuff has to be put in one or the
* other. The idea of setup/release is that they setup the minimal
* amount needed for loading firmware, where us dev_start/stop setup
* the rest needed to do full data/control traffic.
*
* @bus_tx_block_size: [fill] SDIO imposes a 256 block size, USB 16,
* so we have a tx_blk_size variable that the bus layer sets to
* tell the engine how much of that we need.
*
* @bus_pl_size_max: [fill] Maximum payload size.
*
* @bus_
dev_start: [
fill] Function called by the bus-generic code
* [i2400m_
dev_start()] to setup the
bus-specific communications
* to the the device. See LIFE CYCLE above.
* @bus_
setup: [optional
fill] Function called by the bus-generic code
* [i2400m_
setup()] to setup the basic
bus-specific communications
* to the the device
needed to load firmware
. See LIFE CYCLE above.
*
* NOTE: Doesn't need to upload the firmware, as that is taken
* care of by the bus-generic code.
*
* @bus_dev_stop: [fill] Function called by the bus-generic code
* [i2400m_dev_stop()] to shutdown the bus-specific communications
* to the the device. See LIFE CYCLE above.
* @bus_release: [optional fill] Function called by the bus-generic
* code [i2400m_release()] to shutdown the basic bus-specific
* communications to the the device needed to load firmware. See
* LIFE CYCLE above.
*
* This function does not need to reset the device, just tear down
* all the host resources created to handle communication with
* the device.
*
* @bus_dev_start: [optional fill] Function called by the bus-generic
* code [i2400m_dev_start()] to do things needed to start the
* device. See LIFE CYCLE above.
*
* NOTE: Doesn't need to upload the firmware, as that is taken
* care of by the bus-generic code.
*
* @bus_dev_stop: [optional fill] Function called by the bus-generic
* code [i2400m_dev_stop()] to do things needed for stopping the
* device. See LIFE CYCLE above.
*
* This function does not need to reset the device, just tear down
* all the host resources created to handle communication with
...
...
@@ -246,6 +281,9 @@ struct i2400m_roq;
* process, so it cannot rely on common infrastructure being laid
* out.
*
* IMPORTANT: don't call reset on RT_BUS with i2400m->init_mutex
* held, as the .pre/.post reset handlers will deadlock.
*
* @bus_bm_retries: [fill] How many times shall a firmware upload /
* device initialization be retried? Different models of the same
* device might need different values, hence it is set by the
...
...
@@ -297,6 +335,27 @@ struct i2400m_roq;
* force this to be the first field so that we can get from
* netdev_priv() the right pointer.
*
* @updown: the device is up and ready for transmitting control and
* data packets. This implies @ready (communication infrastructure
* with the device is ready) and the device's firmware has been
* loaded and the device initialized.
*
* Write to it only inside a i2400m->init_mutex protected area
* followed with a wmb(); rmb() before accesing (unless locked
* inside i2400m->init_mutex). Read access can be loose like that
* [just using rmb()] because the paths that use this also do
* other error checks later on.
*
* @ready: Communication infrastructure with the device is ready, data
* frames can start to be passed around (this is lighter than
* using the WiMAX state for certain hot paths).
*
* Write to it only inside a i2400m->init_mutex protected area
* followed with a wmb(); rmb() before accesing (unless locked
* inside i2400m->init_mutex). Read access can be loose like that
* [just using rmb()] because the paths that use this also do
* other error checks later on.
*
* @rx_reorder: 1 if RX reordering is enabled; this can only be
* set at probe time.
*
...
...
@@ -362,6 +421,13 @@ struct i2400m_roq;
* delivered. Then the driver can release them to the host. See
* drivers/net/i2400m/rx.c for details.
*
* @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.
*
* @rx_reports_ws: Work struct used to kick a scan of the RX reports
* list and to process each.
*
* @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().
...
...
@@ -422,6 +488,25 @@ struct i2400m_roq;
*
* @fw_version: version of the firmware interface, Major.minor,
* encoded in the high word and low word (major << 16 | minor).
*
* @fw_hdrs: NULL terminated array of pointers to the firmware
* headers. This is only available during firmware load time.
*
* @fw_cached: Used to cache firmware when the system goes to
* suspend/standby/hibernation (as on resume we can't read it). If
* NULL, no firmware was cached, read it. If ~0, you can't read
* any firmware files (the system still didn't come out of suspend
* and failed to cache one), so abort; otherwise, a valid cached
* firmware to be used. Access to this variable is protected by
* the spinlock i2400m->rx_lock.
*
* @barker: barker type that the device uses; this is initialized by
* i2400m_is_boot_barker() the first time it is called. Then it
* won't change during the life cycle of the device and everytime
* a boot barker is received, it is just verified for it being the
* same.
*
* @pm_notifier: used to register for PM events
*/
struct
i2400m
{
struct
wimax_dev
wimax_dev
;
/* FIRST! See doc */
...
...
@@ -429,7 +514,7 @@ struct i2400m {
unsigned
updown
:
1
;
/* Network device is up or down */
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
ready
:
1
;
/*
Device comm infrastructure ready
*/
unsigned
rx_reorder
:
1
;
/* RX reorder is enabled */
u8
trace_msg_from_user
;
/* echo rx msgs to 'trace' pipe */
/* typed u8 so /sys/kernel/debug/u8 can tweak */
...
...
@@ -440,8 +525,10 @@ struct i2400m {
size_t
bus_pl_size_max
;
unsigned
bus_bm_retries
;
int
(
*
bus_setup
)(
struct
i2400m
*
);
int
(
*
bus_dev_start
)(
struct
i2400m
*
);
void
(
*
bus_dev_stop
)(
struct
i2400m
*
);
void
(
*
bus_release
)(
struct
i2400m
*
);
void
(
*
bus_tx_kick
)(
struct
i2400m
*
);
int
(
*
bus_reset
)(
struct
i2400m
*
,
enum
i2400m_reset_type
);
ssize_t
(
*
bus_bm_cmd_send
)(
struct
i2400m
*
,
...
...
@@ -468,6 +555,8 @@ struct i2400m {
rx_num
,
rx_size_acc
,
rx_size_min
,
rx_size_max
;
struct
i2400m_roq
*
rx_roq
;
/* not under rx_lock! */
u8
src_mac_addr
[
ETH_HLEN
];
struct
list_head
rx_reports
;
/* under rx_lock! */
struct
work_struct
rx_report_ws
;
struct
mutex
msg_mutex
;
/* serialize command execution */
struct
completion
msg_completion
;
...
...
@@ -487,37 +576,12 @@ struct i2400m {
struct
dentry
*
debugfs_dentry
;
const
char
*
fw_name
;
/* name of the current firmware image */
unsigned
long
fw_version
;
/* version of the firmware interface */
};
const
struct
i2400m_bcf_hdr
**
fw_hdrs
;
struct
i2400m_fw
*
fw_cached
;
/* protected by rx_lock */
struct
i2400m_barker_db
*
barker
;
/*
* Initialize a 'struct i2400m' from all zeroes
*
* This is a bus-generic API call.
*/
static
inline
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
);
i2400m
->
tx_pl_min
=
UINT_MAX
;
i2400m
->
tx_size_min
=
UINT_MAX
;
spin_lock_init
(
&
i2400m
->
rx_lock
);
i2400m
->
rx_pl_min
=
UINT_MAX
;
i2400m
->
rx_size_min
=
UINT_MAX
;
mutex_init
(
&
i2400m
->
msg_mutex
);
init_completion
(
&
i2400m
->
msg_completion
);
mutex_init
(
&
i2400m
->
init_mutex
);
/* wake_tx_ws is initialized in i2400m_tx_setup() */
}
struct
notifier_block
pm_notifier
;
};
/*
...
...
@@ -577,6 +641,14 @@ extern void i2400m_bm_cmd_prepare(struct i2400m_bootrom_header *);
extern
int
i2400m_dev_bootstrap
(
struct
i2400m
*
,
enum
i2400m_bri
);
extern
int
i2400m_read_mac_addr
(
struct
i2400m
*
);
extern
int
i2400m_bootrom_init
(
struct
i2400m
*
,
enum
i2400m_bri
);
extern
int
i2400m_is_boot_barker
(
struct
i2400m
*
,
const
void
*
,
size_t
);
static
inline
int
i2400m_is_d2h_barker
(
const
void
*
buf
)
{
const
__le32
*
barker
=
buf
;
return
le32_to_cpu
(
*
barker
)
==
I2400M_D2H_MSG_BARKER
;
}
extern
void
i2400m_unknown_barker
(
struct
i2400m
*
,
const
void
*
,
size_t
);
/* Make/grok boot-rom header commands */
...
...
@@ -644,6 +716,8 @@ unsigned i2400m_brh_get_signature(const struct i2400m_bootrom_header *hdr)
/*
* Driver / device setup and internal functions
*/
extern
void
i2400m_init
(
struct
i2400m
*
);
extern
int
i2400m_reset
(
struct
i2400m
*
,
enum
i2400m_reset_type
);
extern
void
i2400m_netdev_setup
(
struct
net_device
*
net_dev
);
extern
int
i2400m_sysfs_setup
(
struct
device_driver
*
);
extern
void
i2400m_sysfs_release
(
struct
device_driver
*
);
...
...
@@ -654,10 +728,14 @@ extern void i2400m_tx_release(struct i2400m *);
extern
int
i2400m_rx_setup
(
struct
i2400m
*
);
extern
void
i2400m_rx_release
(
struct
i2400m
*
);
extern
void
i2400m_fw_cache
(
struct
i2400m
*
);
extern
void
i2400m_fw_uncache
(
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
*
,
enum
i2400m_cs
);
extern
void
i2400m_net_wake_stop
(
struct
i2400m
*
);
enum
i2400m_pt
;
extern
int
i2400m_tx
(
struct
i2400m
*
,
const
void
*
,
size_t
,
enum
i2400m_pt
);
...
...
@@ -672,14 +750,12 @@ static inline int i2400m_debugfs_add(struct i2400m *i2400m)
static
inline
void
i2400m_debugfs_rm
(
struct
i2400m
*
i2400m
)
{}
#endif
/*
Called by _dev_start()/_dev_stop() to initialize the device itself
*/
/*
Initialize/shutdown the device
*/
extern
int
i2400m_dev_initialize
(
struct
i2400m
*
);
extern
void
i2400m_dev_shutdown
(
struct
i2400m
*
);
extern
struct
attribute_group
i2400m_dev_attr_group
;
extern
int
i2400m_schedule_work
(
struct
i2400m
*
,
void
(
*
)(
struct
work_struct
*
),
gfp_t
);
/* HDI message's payload description handling */
...
...
@@ -724,7 +800,9 @@ void i2400m_put(struct i2400m *i2400m)
dev_put
(
i2400m
->
wimax_dev
.
net_dev
);
}
extern
int
i2400m_dev_reset_handle
(
struct
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
*
);
/*
* _setup()/_release() are called by the probe/disconnect functions of
...
...
@@ -737,20 +815,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
*
);
static
const
__le32
i2400m_NBOOT_BARKER
[
4
]
=
{
cpu_to_le32
(
I2400M_NBOOT_BARKER
),
cpu_to_le32
(
I2400M_NBOOT_BARKER
),
cpu_to_le32
(
I2400M_NBOOT_BARKER
),
cpu_to_le32
(
I2400M_NBOOT_BARKER
)
};
static
const
__le32
i2400m_SBOOT_BARKER
[
4
]
=
{
cpu_to_le32
(
I2400M_SBOOT_BARKER
),
cpu_to_le32
(
I2400M_SBOOT_BARKER
),
cpu_to_le32
(
I2400M_SBOOT_BARKER
),
cpu_to_le32
(
I2400M_SBOOT_BARKER
)
};
extern
int
i2400m_power_save_disabled
;
/*
...
...
@@ -773,9 +837,11 @@ struct device *i2400m_dev(struct i2400m *i2400m)
struct
i2400m_work
{
struct
work_struct
ws
;
struct
i2400m
*
i2400m
;
size_t
pl_size
;
u8
pl
[
0
];
};
extern
int
i2400m_queue_work
(
struct
i2400m
*
,
extern
int
i2400m_schedule_work
(
struct
i2400m
*
,
void
(
*
)(
struct
work_struct
*
),
gfp_t
,
const
void
*
,
size_t
);
...
...
@@ -789,6 +855,7 @@ extern void i2400m_msg_ack_hook(struct i2400m *,
const
struct
i2400m_l3l4_hdr
*
,
size_t
);
extern
void
i2400m_report_hook
(
struct
i2400m
*
,
const
struct
i2400m_l3l4_hdr
*
,
size_t
);
extern
void
i2400m_report_hook_work
(
struct
work_struct
*
);
extern
int
i2400m_cmd_enter_powersave
(
struct
i2400m
*
);
extern
int
i2400m_cmd_get_state
(
struct
i2400m
*
);
extern
int
i2400m_cmd_exit_idle
(
struct
i2400m
*
);
...
...
@@ -849,6 +916,12 @@ void __i2400m_msleep(unsigned ms)
#endif
}
/* module initialization helpers */
extern
int
i2400m_barker_db_init
(
const
char
*
);
extern
void
i2400m_barker_db_exit
(
void
);
/* Module parameters */
extern
int
i2400m_idle_mode_disabled
;
...
...
drivers/net/wimax/i2400m/netdev.c
View file @
62d83681
...
...
@@ -74,6 +74,7 @@
*/
#include <linux/if_arp.h>
#include <linux/netdevice.h>
#include <linux/ethtool.h>
#include "i2400m.h"
...
...
@@ -88,7 +89,10 @@ enum {
* The MTU is 1400 or less
*/
I2400M_MAX_MTU
=
1400
,
I2400M_TX_TIMEOUT
=
HZ
,
/* 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
,
};
...
...
@@ -101,22 +105,19 @@ int i2400m_open(struct net_device *net_dev)
struct
device
*
dev
=
i2400m_dev
(
i2400m
);
d_fnstart
(
3
,
dev
,
"(net_dev %p [i2400m %p])
\n
"
,
net_dev
,
i2400m
);
if
(
i2400m
->
ready
==
0
)
{
dev_err
(
dev
,
"Device is still initializing
\n
"
);
result
=
-
EBUSY
;
}
else
/* Make sure we wait until init is complete... */
mutex_lock
(
&
i2400m
->
init_mutex
);
if
(
i2400m
->
updown
)
result
=
0
;
else
result
=
-
EBUSY
;
mutex_unlock
(
&
i2400m
->
init_mutex
);
d_fnend
(
3
,
dev
,
"(net_dev %p [i2400m %p]) = %d
\n
"
,
net_dev
,
i2400m
,
result
);
return
result
;
}
/*
*
* On kernel versions where cancel_work_sync() didn't return anything,
* we rely on wake_tx_skb() being non-NULL.
*/
static
int
i2400m_stop
(
struct
net_device
*
net_dev
)
{
...
...
@@ -124,21 +125,7 @@ int i2400m_stop(struct net_device *net_dev)
struct
device
*
dev
=
i2400m_dev
(
i2400m
);
d_fnstart
(
3
,
dev
,
"(net_dev %p [i2400m %p])
\n
"
,
net_dev
,
i2400m
);
/* See i2400m_hard_start_xmit(), references are taken there
* and here we release them if the work was still
* pending. Note we can't differentiate work not pending vs
* never scheduled, so the NULL check does that. */
if
(
cancel_work_sync
(
&
i2400m
->
wake_tx_ws
)
==
0
&&
i2400m
->
wake_tx_skb
!=
NULL
)
{
unsigned
long
flags
;
struct
sk_buff
*
wake_tx_skb
;
spin_lock_irqsave
(
&
i2400m
->
tx_lock
,
flags
);
wake_tx_skb
=
i2400m
->
wake_tx_skb
;
/* compat help */
i2400m
->
wake_tx_skb
=
NULL
;
/* compat help */
spin_unlock_irqrestore
(
&
i2400m
->
tx_lock
,
flags
);
i2400m_put
(
i2400m
);
kfree_skb
(
wake_tx_skb
);
}
i2400m_net_wake_stop
(
i2400m
);
d_fnend
(
3
,
dev
,
"(net_dev %p [i2400m %p]) = 0
\n
"
,
net_dev
,
i2400m
);
return
0
;
}
...
...
@@ -167,6 +154,7 @@ void i2400m_wake_tx_work(struct work_struct *ws)
{
int
result
;
struct
i2400m
*
i2400m
=
container_of
(
ws
,
struct
i2400m
,
wake_tx_ws
);
struct
net_device
*
net_dev
=
i2400m
->
wimax_dev
.
net_dev
;
struct
device
*
dev
=
i2400m_dev
(
i2400m
);
struct
sk_buff
*
skb
=
i2400m
->
wake_tx_skb
;
unsigned
long
flags
;
...
...
@@ -182,27 +170,36 @@ void i2400m_wake_tx_work(struct work_struct *ws)
dev_err
(
dev
,
"WAKE&TX: skb dissapeared!
\n
"
);
goto
out_put
;
}
/* If we have, somehow, lost the connection after this was
* queued, don't do anything; this might be the device got
* reset or just disconnected. */
if
(
unlikely
(
!
netif_carrier_ok
(
net_dev
)))
goto
out_kfree
;
result
=
i2400m_cmd_exit_idle
(
i2400m
);
if
(
result
==
-
EILSEQ
)
result
=
0
;
if
(
result
<
0
)
{
dev_err
(
dev
,
"WAKE&TX: device didn't get out of idle: "
"%d
\n
"
,
result
);
"%d - resetting
\n
"
,
result
);
i2400m_reset
(
i2400m
,
I2400M_RT_BUS
);
goto
error
;
}
result
=
wait_event_timeout
(
i2400m
->
state_wq
,
i2400m
->
state
!=
I2400M_SS_IDLE
,
5
*
HZ
);
i2400m
->
state
!=
I2400M_SS_IDLE
,
net_dev
->
watchdog_timeo
-
HZ
/
2
);
if
(
result
==
0
)
result
=
-
ETIMEDOUT
;
if
(
result
<
0
)
{
dev_err
(
dev
,
"WAKE&TX: error waiting for device to exit IDLE: "
"%d
\n
"
,
result
);
"%d - resetting
\n
"
,
result
);
i2400m_reset
(
i2400m
,
I2400M_RT_BUS
);
goto
error
;
}
msleep
(
20
);
/* device still needs some time or it drops it */
result
=
i2400m_tx
(
i2400m
,
skb
->
data
,
skb
->
len
,
I2400M_PT_DATA
);
netif_wake_queue
(
i2400m
->
wimax_dev
.
net_dev
);
error:
netif_wake_queue
(
net_dev
);
out_kfree:
kfree_skb
(
skb
);
/* refcount transferred by _hard_start_xmit() */
out_put:
i2400m_put
(
i2400m
);
...
...
@@ -229,6 +226,38 @@ void i2400m_tx_prep_header(struct sk_buff *skb)
}
/*
* Cleanup resources acquired during i2400m_net_wake_tx()
*
* This is called by __i2400m_dev_stop and means we have to make sure
* the workqueue is flushed from any pending work.
*/
void
i2400m_net_wake_stop
(
struct
i2400m
*
i2400m
)
{
struct
device
*
dev
=
i2400m_dev
(
i2400m
);
d_fnstart
(
3
,
dev
,
"(i2400m %p)
\n
"
,
i2400m
);
/* See i2400m_hard_start_xmit(), references are taken there
* and here we release them if the work was still
* pending. Note we can't differentiate work not pending vs
* never scheduled, so the NULL check does that. */
if
(
cancel_work_sync
(
&
i2400m
->
wake_tx_ws
)
==
0
&&
i2400m
->
wake_tx_skb
!=
NULL
)
{
unsigned
long
flags
;
struct
sk_buff
*
wake_tx_skb
;
spin_lock_irqsave
(
&
i2400m
->
tx_lock
,
flags
);
wake_tx_skb
=
i2400m
->
wake_tx_skb
;
/* compat help */
i2400m
->
wake_tx_skb
=
NULL
;
/* compat help */
spin_unlock_irqrestore
(
&
i2400m
->
tx_lock
,
flags
);
i2400m_put
(
i2400m
);
kfree_skb
(
wake_tx_skb
);
}
d_fnend
(
3
,
dev
,
"(i2400m %p) = void
\n
"
,
i2400m
);
return
;
}
/*
* TX an skb to an idle device
*
...
...
@@ -342,6 +371,20 @@ netdev_tx_t i2400m_hard_start_xmit(struct sk_buff *skb,
int
result
;
d_fnstart
(
3
,
dev
,
"(skb %p net_dev %p)
\n
"
,
skb
,
net_dev
);
if
(
skb_header_cloned
(
skb
))
{
/*
* Make tcpdump/wireshark happy -- if they are
* running, the skb is cloned and we will overwrite
* the mac fields in i2400m_tx_prep_header. Expand
* seems to fix this...
*/
result
=
pskb_expand_head
(
skb
,
0
,
0
,
GFP_ATOMIC
);
if
(
result
)
{
result
=
NETDEV_TX_BUSY
;
goto
error_expand
;
}
}
if
(
i2400m
->
state
==
I2400M_SS_IDLE
)
result
=
i2400m_net_wake_tx
(
i2400m
,
net_dev
,
skb
);
else
...
...
@@ -352,10 +395,11 @@ netdev_tx_t i2400m_hard_start_xmit(struct sk_buff *skb,
net_dev
->
stats
.
tx_packets
++
;
net_dev
->
stats
.
tx_bytes
+=
skb
->
len
;
}
result
=
NETDEV_TX_OK
;
error_expand:
kfree_skb
(
skb
);
d_fnend
(
3
,
dev
,
"(skb %p net_dev %p)
\n
"
,
skb
,
net_dev
);
return
NETDEV_TX_OK
;
d_fnend
(
3
,
dev
,
"(skb %p net_dev %p) = %d
\n
"
,
skb
,
net_dev
,
result
);
return
result
;
}
...
...
@@ -559,6 +603,22 @@ static const struct net_device_ops i2400m_netdev_ops = {
.
ndo_change_mtu
=
i2400m_change_mtu
,
};
static
void
i2400m_get_drvinfo
(
struct
net_device
*
net_dev
,
struct
ethtool_drvinfo
*
info
)
{
struct
i2400m
*
i2400m
=
net_dev_to_i2400m
(
net_dev
);
strncpy
(
info
->
driver
,
KBUILD_MODNAME
,
sizeof
(
info
->
driver
)
-
1
);
strncpy
(
info
->
fw_version
,
i2400m
->
fw_name
,
sizeof
(
info
->
fw_version
)
-
1
);
if
(
net_dev
->
dev
.
parent
)
strncpy
(
info
->
bus_info
,
dev_name
(
net_dev
->
dev
.
parent
),
sizeof
(
info
->
bus_info
)
-
1
);
}
static
const
struct
ethtool_ops
i2400m_ethtool_ops
=
{
.
get_drvinfo
=
i2400m_get_drvinfo
,
.
get_link
=
ethtool_op_get_link
,
};
/**
* i2400m_netdev_setup - Setup setup @net_dev's i2400m private data
...
...
@@ -580,6 +640,7 @@ void i2400m_netdev_setup(struct net_device *net_dev)
&
~
IFF_MULTICAST
);
net_dev
->
watchdog_timeo
=
I2400M_TX_TIMEOUT
;
net_dev
->
netdev_ops
=
&
i2400m_netdev_ops
;
net_dev
->
ethtool_ops
=
&
i2400m_ethtool_ops
;
d_fnend
(
3
,
NULL
,
"(net_dev %p) = void
\n
"
,
net_dev
);
}
EXPORT_SYMBOL_GPL
(
i2400m_netdev_setup
);
...
...
drivers/net/wimax/i2400m/rx.c
View file @
62d83681
...
...
@@ -158,30 +158,104 @@ struct i2400m_report_hook_args {
struct
sk_buff
*
skb_rx
;
const
struct
i2400m_l3l4_hdr
*
l3l4_hdr
;
size_t
size
;
struct
list_head
list_node
;
};
/*
* Execute i2400m_report_hook in a workqueue
*
*
Unpacks arguments from the deferred call, executes it and then
*
drops the references
.
*
Goes over the list of queued reports in i2400m->rx_reports and
*
processes them
.
*
*
Obvious NOTE: References are needed because we are a separat
e
*
thread; otherwise the buffer changes under us because it is
*
released by the original caller
.
*
NOTE: refcounts on i2400m are not needed because we flush th
e
*
workqueue this runs on (i2400m->work_queue) before destroying
*
i2400m
.
*/
static
void
i2400m_report_hook_work
(
struct
work_struct
*
ws
)
{
struct
i2400m_work
*
iw
=
container_of
(
ws
,
struct
i2400m_work
,
ws
);
struct
i2400m_report_hook_args
*
args
=
(
void
*
)
iw
->
pl
;
if
(
iw
->
i2400m
->
ready
)
i2400m_report_hook
(
iw
->
i2400m
,
args
->
l3l4_hdr
,
args
->
size
);
struct
i2400m
*
i2400m
=
container_of
(
ws
,
struct
i2400m
,
rx_report_ws
);
struct
device
*
dev
=
i2400m_dev
(
i2400m
);
struct
i2400m_report_hook_args
*
args
,
*
args_next
;
LIST_HEAD
(
list
);
unsigned
long
flags
;
while
(
1
)
{
spin_lock_irqsave
(
&
i2400m
->
rx_lock
,
flags
);
list_splice_init
(
&
i2400m
->
rx_reports
,
&
list
);
spin_unlock_irqrestore
(
&
i2400m
->
rx_lock
,
flags
);
if
(
list_empty
(
&
list
))
break
;
else
d_printf
(
1
,
dev
,
"processing queued reports
\n
"
);
list_for_each_entry_safe
(
args
,
args_next
,
&
list
,
list_node
)
{
d_printf
(
2
,
dev
,
"processing queued report %p
\n
"
,
args
);
i2400m_report_hook
(
i2400m
,
args
->
l3l4_hdr
,
args
->
size
);
kfree_skb
(
args
->
skb_rx
);
list_del
(
&
args
->
list_node
);
kfree
(
args
);
}
}
}
/*
* Flush the list of queued reports
*/
static
void
i2400m_report_hook_flush
(
struct
i2400m
*
i2400m
)
{
struct
device
*
dev
=
i2400m_dev
(
i2400m
);
struct
i2400m_report_hook_args
*
args
,
*
args_next
;
LIST_HEAD
(
list
);
unsigned
long
flags
;
d_printf
(
1
,
dev
,
"flushing queued reports
\n
"
);
spin_lock_irqsave
(
&
i2400m
->
rx_lock
,
flags
);
list_splice_init
(
&
i2400m
->
rx_reports
,
&
list
);
spin_unlock_irqrestore
(
&
i2400m
->
rx_lock
,
flags
);
list_for_each_entry_safe
(
args
,
args_next
,
&
list
,
list_node
)
{
d_printf
(
2
,
dev
,
"flushing queued report %p
\n
"
,
args
);
kfree_skb
(
args
->
skb_rx
);
i2400m_put
(
iw
->
i2400m
);
kfree
(
iw
);
list_del
(
&
args
->
list_node
);
kfree
(
args
);
}
}
/*
* Queue a report for later processing
*
* @i2400m: device descriptor
* @skb_rx: skb that contains the payload (for reference counting)
* @l3l4_hdr: pointer to the control
* @size: size of the message
*/
static
void
i2400m_report_hook_queue
(
struct
i2400m
*
i2400m
,
struct
sk_buff
*
skb_rx
,
const
void
*
l3l4_hdr
,
size_t
size
)
{
struct
device
*
dev
=
i2400m_dev
(
i2400m
);
unsigned
long
flags
;
struct
i2400m_report_hook_args
*
args
;
args
=
kzalloc
(
sizeof
(
*
args
),
GFP_NOIO
);
if
(
args
)
{
args
->
skb_rx
=
skb_get
(
skb_rx
);
args
->
l3l4_hdr
=
l3l4_hdr
;
args
->
size
=
size
;
spin_lock_irqsave
(
&
i2400m
->
rx_lock
,
flags
);
list_add_tail
(
&
args
->
list_node
,
&
i2400m
->
rx_reports
);
spin_unlock_irqrestore
(
&
i2400m
->
rx_lock
,
flags
);
d_printf
(
2
,
dev
,
"queued report %p
\n
"
,
args
);
rmb
();
/* see i2400m->ready's documentation */
if
(
likely
(
i2400m
->
ready
))
/* only send if up */
queue_work
(
i2400m
->
work_queue
,
&
i2400m
->
rx_report_ws
);
}
else
{
if
(
printk_ratelimit
())
dev_err
(
dev
,
"%s:%u: Can't allocate %zu B
\n
"
,
__func__
,
__LINE__
,
sizeof
(
*
args
));
}
}
...
...
@@ -295,21 +369,29 @@ void i2400m_rx_ctl(struct i2400m *i2400m, struct sk_buff *skb_rx,
msg_type
,
size
);
d_dump
(
2
,
dev
,
l3l4_hdr
,
size
);
if
(
msg_type
&
I2400M_MT_REPORT_MASK
)
{
/* These hooks have to be ran serialized; as well, the
* handling might force the execution of commands, and
* that might cause reentrancy issues with
* bus-specific subdrivers and workqueues. So we run
* it in a separate workqueue. */
struct
i2400m_report_hook_args
args
=
{
.
skb_rx
=
skb_rx
,
.
l3l4_hdr
=
l3l4_hdr
,
.
size
=
size
};
if
(
unlikely
(
i2400m
->
ready
==
0
))
/* only send if up */
return
;
skb_get
(
skb_rx
);
i2400m_queue_work
(
i2400m
,
i2400m_report_hook_work
,
GFP_KERNEL
,
&
args
,
sizeof
(
args
));
/*
* Process each report
*
* - has to be ran serialized as well
*
* - the handling might force the execution of
* commands. That might cause reentrancy issues with
* bus-specific subdrivers and workqueues, so the we
* run it in a separate workqueue.
*
* - when the driver is not yet ready to handle them,
* they are queued and at some point the queue is
* restarted [NOTE: we can't queue SKBs directly, as
* this might be a piece of a SKB, not the whole
* thing, and this is cheaper than cloning the
* SKB].
*
* Note we don't do refcounting for the device
* structure; this is because before destroying
* 'i2400m', we make sure to flush the
* i2400m->work_queue, so there are no issues.
*/
i2400m_report_hook_queue
(
i2400m
,
skb_rx
,
l3l4_hdr
,
size
);
if
(
unlikely
(
i2400m
->
trace_msg_from_user
))
wimax_msg
(
&
i2400m
->
wimax_dev
,
"echo"
,
l3l4_hdr
,
size
,
GFP_KERNEL
);
...
...
@@ -363,8 +445,6 @@ void i2400m_rx_trace(struct i2400m *i2400m,
msg_type
&
I2400M_MT_REPORT_MASK
?
"REPORT"
:
"CMD/SET/GET"
,
msg_type
,
size
);
d_dump
(
2
,
dev
,
l3l4_hdr
,
size
);
if
(
unlikely
(
i2400m
->
ready
==
0
))
/* only send if up */
return
;
result
=
wimax_msg
(
wimax_dev
,
"trace"
,
l3l4_hdr
,
size
,
GFP_KERNEL
);
if
(
result
<
0
)
dev_err
(
dev
,
"error sending trace to userspace: %d
\n
"
,
...
...
@@ -748,7 +828,7 @@ void i2400m_roq_queue(struct i2400m *i2400m, struct i2400m_roq *roq,
dev_err
(
dev
,
"SW BUG? queue nsn %d (lbn %u ws %u)
\n
"
,
nsn
,
lbn
,
roq
->
ws
);
i2400m_roq_log_dump
(
i2400m
,
roq
);
i2400m
->
bus
_reset
(
i2400m
,
I2400M_RT_WARM
);
i2400m_reset
(
i2400m
,
I2400M_RT_WARM
);
}
else
{
__i2400m_roq_queue
(
i2400m
,
roq
,
skb
,
lbn
,
nsn
);
i2400m_roq_log_add
(
i2400m
,
roq
,
I2400M_RO_TYPE_PACKET
,
...
...
@@ -814,7 +894,7 @@ void i2400m_roq_queue_update_ws(struct i2400m *i2400m, struct i2400m_roq *roq,
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
->
bus
_reset
(
i2400m
,
I2400M_RT_WARM
);
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 */
...
...
@@ -1194,6 +1274,28 @@ int i2400m_rx(struct i2400m *i2400m, struct sk_buff *skb)
EXPORT_SYMBOL_GPL
(
i2400m_rx
);
void
i2400m_unknown_barker
(
struct
i2400m
*
i2400m
,
const
void
*
buf
,
size_t
size
)
{
struct
device
*
dev
=
i2400m_dev
(
i2400m
);
char
prefix
[
64
];
const
__le32
*
barker
=
buf
;
dev_err
(
dev
,
"RX: HW BUG? unknown barker %08x, "
"dropping %zu bytes
\n
"
,
le32_to_cpu
(
*
barker
),
size
);
snprintf
(
prefix
,
sizeof
(
prefix
),
"%s %s: "
,
dev_driver_string
(
dev
),
dev_name
(
dev
));
if
(
size
>
64
)
{
print_hex_dump
(
KERN_ERR
,
prefix
,
DUMP_PREFIX_OFFSET
,
8
,
4
,
buf
,
64
,
0
);
printk
(
KERN_ERR
"%s... (only first 64 bytes "
"dumped)
\n
"
,
prefix
);
}
else
print_hex_dump
(
KERN_ERR
,
prefix
,
DUMP_PREFIX_OFFSET
,
8
,
4
,
buf
,
size
,
0
);
}
EXPORT_SYMBOL
(
i2400m_unknown_barker
);
/*
* Initialize the RX queue and infrastructure
*
...
...
@@ -1261,4 +1363,6 @@ void i2400m_rx_release(struct i2400m *i2400m)
kfree
(
i2400m
->
rx_roq
[
0
].
log
);
kfree
(
i2400m
->
rx_roq
);
}
/* at this point, nothing can be received... */
i2400m_report_hook_flush
(
i2400m
);
}
drivers/net/wimax/i2400m/sdio-fw.c
View file @
62d83681
...
...
@@ -118,7 +118,8 @@ ssize_t i2400ms_bus_bm_cmd_send(struct i2400m *i2400m,
if
(
cmd_size
>
I2400M_BM_CMD_BUF_SIZE
)
goto
error_too_big
;
memcpy
(
i2400m
->
bm_cmd_buf
,
_cmd
,
cmd_size
);
/* Prep command */
if
(
_cmd
!=
i2400m
->
bm_cmd_buf
)
memmove
(
i2400m
->
bm_cmd_buf
,
_cmd
,
cmd_size
);
cmd
=
i2400m
->
bm_cmd_buf
;
if
(
cmd_size_a
>
cmd_size
)
/* Zero pad space */
memset
(
i2400m
->
bm_cmd_buf
+
cmd_size
,
0
,
cmd_size_a
-
cmd_size
);
...
...
@@ -177,10 +178,6 @@ ssize_t i2400ms_bus_bm_wait_for_ack(struct i2400m *i2400m,
d_fnstart
(
5
,
dev
,
"(i2400m %p ack %p size %zu)
\n
"
,
i2400m
,
ack
,
ack_size
);
spin_lock
(
&
i2400m
->
rx_lock
);
i2400ms
->
bm_ack_size
=
-
EINPROGRESS
;
spin_unlock
(
&
i2400m
->
rx_lock
);
result
=
wait_event_timeout
(
i2400ms
->
bm_wfa_wq
,
i2400ms
->
bm_ack_size
!=
-
EINPROGRESS
,
2
*
HZ
);
...
...
@@ -199,6 +196,10 @@ ssize_t i2400ms_bus_bm_wait_for_ack(struct i2400m *i2400m,
size
=
min
(
ack_size
,
i2400ms
->
bm_ack_size
);
memcpy
(
ack
,
i2400m
->
bm_ack_buf
,
size
);
}
/*
* Remember always to clear the bm_ack_size to -EINPROGRESS
* after the RX data is processed
*/
i2400ms
->
bm_ack_size
=
-
EINPROGRESS
;
spin_unlock
(
&
i2400m
->
rx_lock
);
...
...
drivers/net/wimax/i2400m/sdio-rx.c
View file @
62d83681
...
...
@@ -53,6 +53,7 @@
* i2400ms_irq()
* i2400ms_rx()
* __i2400ms_rx_get_size()
* i2400m_is_boot_barker()
* i2400m_rx()
*
* i2400ms_rx_setup()
...
...
@@ -138,6 +139,11 @@ void i2400ms_rx(struct i2400ms *i2400ms)
ret
=
rx_size
;
goto
error_get_size
;
}
/*
* Hardware quirk: make sure to clear the INTR status register
* AFTER getting the data transfer size.
*/
sdio_writeb
(
func
,
1
,
I2400MS_INTR_CLEAR_ADDR
,
&
ret
);
ret
=
-
ENOMEM
;
skb
=
alloc_skb
(
rx_size
,
GFP_ATOMIC
);
...
...
@@ -153,25 +159,34 @@ void i2400ms_rx(struct i2400ms *i2400ms)
}
rmb
();
/* make sure we get boot_mode from dev_reset_handle */
if
(
i2400m
->
boot_mode
==
1
)
{
if
(
unlikely
(
i2400m
->
boot_mode
==
1
)
)
{
spin_lock
(
&
i2400m
->
rx_lock
);
i2400ms
->
bm_ack_size
=
rx_size
;
spin_unlock
(
&
i2400m
->
rx_lock
);
memcpy
(
i2400m
->
bm_ack_buf
,
skb
->
data
,
rx_size
);
wake_up
(
&
i2400ms
->
bm_wfa_wq
);
d
ev_err
(
dev
,
"RX: SDIO boot mode message
\n
"
);
d
_printf
(
5
,
dev
,
"RX: SDIO boot mode message
\n
"
);
kfree_skb
(
skb
);
}
else
if
(
unlikely
(
!
memcmp
(
skb
->
data
,
i2400m_NBOOT_BARKER
,
sizeof
(
i2400m_NBOOT_BARKER
))
||
!
memcmp
(
skb
->
data
,
i2400m_SBOOT_BARKER
,
sizeof
(
i2400m_SBOOT_BARKER
))))
{
ret
=
i2400m_dev_reset_handle
(
i2400m
);
goto
out
;
}
ret
=
-
EIO
;
if
(
unlikely
(
rx_size
<
sizeof
(
__le32
)))
{
dev_err
(
dev
,
"HW BUG? only %zu bytes received
\n
"
,
rx_size
);
goto
error_bad_size
;
}
if
(
likely
(
i2400m_is_d2h_barker
(
skb
->
data
)))
{
skb_put
(
skb
,
rx_size
);
i2400m_rx
(
i2400m
,
skb
);
}
else
if
(
unlikely
(
i2400m_is_boot_barker
(
i2400m
,
skb
->
data
,
rx_size
)))
{
ret
=
i2400m_dev_reset_handle
(
i2400m
,
"device rebooted"
);
dev_err
(
dev
,
"RX: SDIO reboot barker
\n
"
);
kfree_skb
(
skb
);
}
else
{
skb_put
(
skb
,
rx_size
);
i2400m_rx
(
i2400m
,
skb
);
i2400m_unknown_barker
(
i2400m
,
skb
->
data
,
rx_size
);
kfree_skb
(
skb
);
}
out:
d_fnend
(
7
,
dev
,
"(i2400ms %p) = void
\n
"
,
i2400ms
);
return
;
...
...
@@ -179,6 +194,7 @@ void i2400ms_rx(struct i2400ms *i2400ms)
kfree_skb
(
skb
);
error_alloc_skb:
error_get_size:
error_bad_size:
d_fnend
(
7
,
dev
,
"(i2400ms %p) = %d
\n
"
,
i2400ms
,
ret
);
return
;
}
...
...
@@ -209,7 +225,6 @@ void i2400ms_irq(struct sdio_func *func)
dev_err
(
dev
,
"RX: BUG? got IRQ but no interrupt ready?
\n
"
);
goto
error_no_irq
;
}
sdio_writeb
(
func
,
1
,
I2400MS_INTR_CLEAR_ADDR
,
&
ret
);
i2400ms_rx
(
i2400ms
);
error_no_irq:
d_fnend
(
6
,
dev
,
"(i2400ms %p) = void
\n
"
,
i2400ms
);
...
...
@@ -234,6 +249,13 @@ int i2400ms_rx_setup(struct i2400ms *i2400ms)
init_waitqueue_head
(
&
i2400ms
->
bm_wfa_wq
);
spin_lock
(
&
i2400m
->
rx_lock
);
i2400ms
->
bm_wait_result
=
-
EINPROGRESS
;
/*
* Before we are about to enable the RX interrupt, make sure
* bm_ack_size is cleared to -EINPROGRESS which indicates
* no RX interrupt happened yet or the previous interrupt
* has been handled, we are ready to take the new interrupt
*/
i2400ms
->
bm_ack_size
=
-
EINPROGRESS
;
spin_unlock
(
&
i2400m
->
rx_lock
);
sdio_claim_host
(
func
);
...
...
drivers/net/wimax/i2400m/sdio-tx.c
View file @
62d83681
...
...
@@ -149,5 +149,8 @@ int i2400ms_tx_setup(struct i2400ms *i2400ms)
void
i2400ms_tx_release
(
struct
i2400ms
*
i2400ms
)
{
if
(
i2400ms
->
tx_workqueue
)
{
destroy_workqueue
(
i2400ms
->
tx_workqueue
);
i2400ms
->
tx_workqueue
=
NULL
;
}
}
drivers/net/wimax/i2400m/sdio.c
View file @
62d83681
...
...
@@ -43,18 +43,9 @@
* i2400m_release()
* free_netdev(net_dev)
*
* i2400ms_bus_reset() Called by i2400m
->bus
_reset
* i2400ms_bus_reset() Called by i2400m_reset
* __i2400ms_reset()
* __i2400ms_send_barker()
*
* i2400ms_bus_dev_start() Called by i2400m_dev_start() [who is
* i2400ms_tx_setup() called by i2400m_setup()]
* i2400ms_rx_setup()
*
* i2400ms_bus_dev_stop() Called by i2400m_dev_stop() [who is
* i2400ms_rx_release() is called by i2400m_release()]
* i2400ms_tx_release()
*
*/
#include <linux/debugfs.h>
...
...
@@ -71,6 +62,14 @@
static
int
ioe_timeout
=
2
;
module_param
(
ioe_timeout
,
int
,
0
);
static
char
i2400ms_debug_params
[
128
];
module_param_string
(
debug
,
i2400ms_debug_params
,
sizeof
(
i2400ms_debug_params
),
0644
);
MODULE_PARM_DESC
(
debug
,
"String of space-separated NAME:VALUE pairs, where NAMEs "
"are the different debug submodules and VALUE are the "
"initial debug value to set."
);
/* Our firmware file name list */
static
const
char
*
i2400ms_bus_fw_names
[]
=
{
#define I2400MS_FW_FILE_NAME "i2400m-fw-sdio-1.3.sbcf"
...
...
@@ -95,17 +94,24 @@ static const struct i2400m_poke_table i2400ms_pokes[] = {
* when we ask it to explicitly doing). Tries until a timeout is
* reached.
*
* The @maxtries argument indicates how many times (at most) it should
* be tried to enable the function. 0 means forever. This acts along
* with the timeout (ie: it'll stop trying as soon as the maximum
* number of tries is reached _or_ as soon as the timeout is reached).
*
* The reverse of this is...sdio_disable_function()
*
* Returns: 0 if the SDIO function was enabled, < 0 errno code on
* error (-ENODEV when it was unable to enable the function).
*/
static
int
i2400ms_enable_function
(
struct
sdio_func
*
func
)
int
i2400ms_enable_function
(
struct
i2400ms
*
i2400ms
,
unsigned
maxtries
)
{
struct
sdio_func
*
func
=
i2400ms
->
func
;
u64
timeout
;
int
err
;
struct
device
*
dev
=
&
func
->
dev
;
unsigned
tries
=
0
;
d_fnstart
(
3
,
dev
,
"(func %p)
\n
"
,
func
);
/* Setup timeout (FIXME: This needs to read the CIS table to
...
...
@@ -115,6 +121,14 @@ int i2400ms_enable_function(struct sdio_func *func)
err
=
-
ENODEV
;
while
(
err
!=
0
&&
time_before64
(
get_jiffies_64
(),
timeout
))
{
sdio_claim_host
(
func
);
/*
* There is a sillicon bug on the IWMC3200, where the
* IOE timeout will cause problems on Moorestown
* platforms (system hang). We explicitly overwrite
* func->enable_timeout here to work around the issue.
*/
if
(
i2400ms
->
iwmc3200
)
func
->
enable_timeout
=
IWMC3200_IOR_TIMEOUT
;
err
=
sdio_enable_func
(
func
);
if
(
0
==
err
)
{
sdio_release_host
(
func
);
...
...
@@ -122,8 +136,11 @@ int i2400ms_enable_function(struct sdio_func *func)
goto
function_enabled
;
}
d_printf
(
2
,
dev
,
"SDIO function failed to enable: %d
\n
"
,
err
);
sdio_disable_func
(
func
);
sdio_release_host
(
func
);
if
(
maxtries
>
0
&&
++
tries
>=
maxtries
)
{
err
=
-
ETIME
;
break
;
}
msleep
(
I2400MS_INIT_SLEEP_INTERVAL
);
}
/* If timed out, device is not there yet -- get -ENODEV so
...
...
@@ -140,46 +157,99 @@ int i2400ms_enable_function(struct sdio_func *func)
/*
* Setup driver resources needed to communicate with the device
* Setup minimal device communication infrastructure needed to at
* least be able to update the firmware.
*
* The fw needs some time to settle, and it was just uploaded,
* so give it a break first. I'd prefer to just wait for the device to
* send something, but seems the poking we do to enable SDIO stuff
* interferes with it, so just give it a break before starting...
* Note the ugly trick: if we are in the probe path
* (i2400ms->debugfs_dentry == NULL), we only retry function
* enablement one, to avoid racing with the iwmc3200 top controller.
*/
static
int
i2400ms_bus_
dev_start
(
struct
i2400m
*
i2400m
)
int
i2400ms_bus_
setup
(
struct
i2400m
*
i2400m
)
{
int
result
;
struct
i2400ms
*
i2400ms
=
container_of
(
i2400m
,
struct
i2400ms
,
i2400m
);
struct
i2400ms
*
i2400ms
=
container_of
(
i2400m
,
struct
i2400ms
,
i2400m
);
struct
device
*
dev
=
i2400m_dev
(
i2400m
);
struct
sdio_func
*
func
=
i2400ms
->
func
;
struct
device
*
dev
=
&
func
->
dev
;
int
retries
;
sdio_claim_host
(
func
);
result
=
sdio_set_block_size
(
func
,
I2400MS_BLK_SIZE
);
sdio_release_host
(
func
);
if
(
result
<
0
)
{
dev_err
(
dev
,
"Failed to set block size: %d
\n
"
,
result
);
goto
error_set_blk_size
;
}
if
(
i2400ms
->
iwmc3200
&&
i2400ms
->
debugfs_dentry
==
NULL
)
retries
=
1
;
else
retries
=
0
;
result
=
i2400ms_enable_function
(
i2400ms
,
retries
);
if
(
result
<
0
)
{
dev_err
(
dev
,
"Cannot enable SDIO function: %d
\n
"
,
result
);
goto
error_func_enable
;
}
d_fnstart
(
3
,
dev
,
"(i2400m %p)
\n
"
,
i2400m
);
msleep
(
200
);
result
=
i2400ms_tx_setup
(
i2400ms
);
if
(
result
<
0
)
goto
error_tx_setup
;
d_fnend
(
3
,
dev
,
"(i2400m %p) = %d
\n
"
,
i2400m
,
result
);
return
result
;
result
=
i2400ms_rx_setup
(
i2400ms
);
if
(
result
<
0
)
goto
error_rx_setup
;
return
0
;
error_
t
x_setup:
error_
r
x_setup:
i2400ms_tx_release
(
i2400ms
);
d_fnend
(
3
,
dev
,
"(i2400m %p) = void
\n
"
,
i2400m
);
error_tx_setup:
sdio_claim_host
(
func
);
sdio_disable_func
(
func
);
sdio_release_host
(
func
);
error_func_enable:
error_set_blk_size:
return
result
;
}
/*
* Tear down minimal device communication infrastructure needed to at
* least be able to update the firmware.
*/
static
void
i2400ms_bus_release
(
struct
i2400m
*
i2400m
)
{
struct
i2400ms
*
i2400ms
=
container_of
(
i2400m
,
struct
i2400ms
,
i2400m
);
struct
sdio_func
*
func
=
i2400ms
->
func
;
i2400ms_rx_release
(
i2400ms
);
i2400ms_tx_release
(
i2400ms
);
sdio_claim_host
(
func
);
sdio_disable_func
(
func
);
sdio_release_host
(
func
);
}
/*
* Setup driver resources needed to communicate with the device
*
* The fw needs some time to settle, and it was just uploaded,
* so give it a break first. I'd prefer to just wait for the device to
* send something, but seems the poking we do to enable SDIO stuff
* interferes with it, so just give it a break before starting...
*/
static
void
i2400ms_bus_dev_stop
(
struct
i2400m
*
i2400m
)
int
i2400ms_bus_dev_start
(
struct
i2400m
*
i2400m
)
{
struct
i2400ms
*
i2400ms
=
container_of
(
i2400m
,
struct
i2400ms
,
i2400m
);
struct
sdio_func
*
func
=
i2400ms
->
func
;
struct
device
*
dev
=
&
func
->
dev
;
d_fnstart
(
3
,
dev
,
"(i2400m %p)
\n
"
,
i2400m
);
i2400ms_tx_release
(
i2400ms
);
d_fnend
(
3
,
dev
,
"(i2400m %p) = void
\n
"
,
i2400m
);
msleep
(
200
);
d_fnend
(
3
,
dev
,
"(i2400m %p) = %d
\n
"
,
i2400m
,
0
);
return
0
;
}
...
...
@@ -233,18 +303,17 @@ int __i2400ms_send_barker(struct i2400ms *i2400ms,
* Warm reset:
*
* The device will be fully reset internally, but won't be
* disconnected from the
USB
bus (so no reenumeration will
* disconnected from the bus (so no reenumeration will
* happen). Firmware upload will be neccessary.
*
* The device will send a reboot barker in the notification endpoint
* that will trigger the driver to reinitialize the state
* automatically from notif.c:i2400m_notification_grok() into
* i2400m_dev_bootstrap_delayed().
* The device will send a reboot barker that will trigger the driver
* to reinitialize the state via __i2400m_dev_reset_handle.
*
*
* Cold and bus
(USB)
reset:
* Cold and bus reset:
*
* The device will be fully reset internally, disconnected from the
*
USB
bus an a reenumeration will happen. Firmware upload will be
* bus an a reenumeration will happen. Firmware upload will be
* neccessary. Thus, we don't do any locking or struct
* reinitialization, as we are going to be fully disconnected and
* reenumerated.
...
...
@@ -283,25 +352,13 @@ int i2400ms_bus_reset(struct i2400m *i2400m, enum i2400m_reset_type rt)
sizeof
(
i2400m_COLD_BOOT_BARKER
));
else
if
(
rt
==
I2400M_RT_BUS
)
{
do_bus_reset:
/* call netif_tx_disable() before sending IOE disable,
* so that all the tx from network layer are stopped
* while IOE is being reset. Make sure it is called
* only after register_netdev() was issued.
*/
if
(
i2400m
->
wimax_dev
.
net_dev
->
reg_state
==
NETREG_REGISTERED
)
netif_tx_disable
(
i2400m
->
wimax_dev
.
net_dev
);
i2400ms_rx_release
(
i2400ms
);
sdio_claim_host
(
i2400ms
->
func
);
sdio_disable_func
(
i2400ms
->
func
);
sdio_release_host
(
i2400ms
->
func
);
i2400ms_bus_release
(
i2400m
);
/* Wait for the device to settle */
msleep
(
40
);
result
=
i2400ms_enable_function
(
i2400ms
->
func
);
if
(
result
>=
0
)
i2400ms_rx_setup
(
i2400ms
);
result
=
i2400ms_bus_setup
(
i2400m
);
}
else
BUG
();
if
(
result
<
0
&&
rt
!=
I2400M_RT_BUS
)
{
...
...
@@ -350,7 +407,7 @@ int i2400ms_debugfs_add(struct i2400ms *i2400ms)
int
result
;
struct
dentry
*
dentry
=
i2400ms
->
i2400m
.
wimax_dev
.
debugfs_dentry
;
dentry
=
debugfs_create_dir
(
"i2400m-
usb
"
,
dentry
);
dentry
=
debugfs_create_dir
(
"i2400m-
sdio
"
,
dentry
);
result
=
PTR_ERR
(
dentry
);
if
(
IS_ERR
(
dentry
))
{
if
(
result
==
-
ENODEV
)
...
...
@@ -367,6 +424,7 @@ int i2400ms_debugfs_add(struct i2400ms *i2400ms)
error:
debugfs_remove_recursive
(
i2400ms
->
debugfs_dentry
);
i2400ms
->
debugfs_dentry
=
NULL
;
return
result
;
}
...
...
@@ -425,37 +483,30 @@ int i2400ms_probe(struct sdio_func *func,
i2400m
->
bus_tx_block_size
=
I2400MS_BLK_SIZE
;
i2400m
->
bus_pl_size_max
=
I2400MS_PL_SIZE_MAX
;
i2400m
->
bus_setup
=
i2400ms_bus_setup
;
i2400m
->
bus_dev_start
=
i2400ms_bus_dev_start
;
i2400m
->
bus_dev_stop
=
i2400ms_bus_dev_stop
;
i2400m
->
bus_dev_stop
=
NULL
;
i2400m
->
bus_release
=
i2400ms_bus_release
;
i2400m
->
bus_tx_kick
=
i2400ms_bus_tx_kick
;
i2400m
->
bus_reset
=
i2400ms_bus_reset
;
/* The iwmc3200-wimax sometimes requires the driver to try
* hard when we paint it into a corner. */
i2400m
->
bus_bm_retries
=
I
3200
_BOOT_RETRIES
;
i2400m
->
bus_bm_retries
=
I
2400M_SDIO
_BOOT_RETRIES
;
i2400m
->
bus_bm_cmd_send
=
i2400ms_bus_bm_cmd_send
;
i2400m
->
bus_bm_wait_for_ack
=
i2400ms_bus_bm_wait_for_ack
;
i2400m
->
bus_fw_names
=
i2400ms_bus_fw_names
;
i2400m
->
bus_bm_mac_addr_impaired
=
1
;
i2400m
->
bus_bm_pokes_table
=
&
i2400ms_pokes
[
0
];
sdio_claim_host
(
func
);
result
=
sdio_set_block_size
(
func
,
I2400MS_BLK_SIZE
);
sdio_release_host
(
func
);
if
(
result
<
0
)
{
dev_err
(
dev
,
"Failed to set block size: %d
\n
"
,
result
);
goto
error_set_blk_size
;
switch
(
func
->
device
)
{
case
SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX
:
case
SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX_2G5
:
i2400ms
->
iwmc3200
=
1
;
break
;
default:
i2400ms
->
iwmc3200
=
0
;
}
result
=
i2400ms_enable_function
(
i2400ms
->
func
);
if
(
result
<
0
)
{
dev_err
(
dev
,
"Cannot enable SDIO function: %d
\n
"
,
result
);
goto
error_func_enable
;
}
result
=
i2400ms_rx_setup
(
i2400ms
);
if
(
result
<
0
)
goto
error_rx_setup
;
result
=
i2400m_setup
(
i2400m
,
I2400M_BRI_NO_REBOOT
);
if
(
result
<
0
)
{
dev_err
(
dev
,
"cannot setup device: %d
\n
"
,
result
);
...
...
@@ -473,13 +524,6 @@ int i2400ms_probe(struct sdio_func *func,
error_debugfs_add:
i2400m_release
(
i2400m
);
error_setup:
i2400ms_rx_release
(
i2400ms
);
error_rx_setup:
sdio_claim_host
(
func
);
sdio_disable_func
(
func
);
sdio_release_host
(
func
);
error_func_enable:
error_set_blk_size:
sdio_set_drvdata
(
func
,
NULL
);
free_netdev
(
net_dev
);
error_alloc_netdev:
...
...
@@ -497,12 +541,9 @@ void i2400ms_remove(struct sdio_func *func)
d_fnstart
(
3
,
dev
,
"SDIO func %p
\n
"
,
func
);
debugfs_remove_recursive
(
i2400ms
->
debugfs_dentry
);
i2400ms
_rx_release
(
i2400ms
)
;
i2400ms
->
debugfs_dentry
=
NULL
;
i2400m_release
(
i2400m
);
sdio_set_drvdata
(
func
,
NULL
);
sdio_claim_host
(
func
);
sdio_disable_func
(
func
);
sdio_release_host
(
func
);
free_netdev
(
net_dev
);
d_fnend
(
3
,
dev
,
"SDIO func %p
\n
"
,
func
);
}
...
...
@@ -512,6 +553,8 @@ const struct sdio_device_id i2400ms_sdio_ids[] = {
/* Intel: i2400m WiMAX (iwmc3200) over SDIO */
{
SDIO_DEVICE
(
SDIO_VENDOR_ID_INTEL
,
SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX
)
},
{
SDIO_DEVICE
(
SDIO_VENDOR_ID_INTEL
,
SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX_2G5
)
},
{
/* end: all zeroes */
},
};
MODULE_DEVICE_TABLE
(
sdio
,
i2400ms_sdio_ids
);
...
...
@@ -529,6 +572,8 @@ struct sdio_driver i2400m_sdio_driver = {
static
int
__init
i2400ms_driver_init
(
void
)
{
d_parse_params
(
D_LEVEL
,
D_LEVEL_SIZE
,
i2400ms_debug_params
,
"i2400m_sdio.debug"
);
return
sdio_register_driver
(
&
i2400m_sdio_driver
);
}
module_init
(
i2400ms_driver_init
);
...
...
drivers/net/wimax/i2400m/tx.c
View file @
62d83681
...
...
@@ -310,7 +310,7 @@ size_t __i2400m_tx_tail_room(struct i2400m *i2400m)
size_t
tail_room
;
size_t
tx_in
;
if
(
unlikely
(
i2400m
->
tx_in
)
==
0
)
if
(
unlikely
(
i2400m
->
tx_in
==
0
)
)
return
I2400M_TX_BUF_SIZE
;
tx_in
=
i2400m
->
tx_in
%
I2400M_TX_BUF_SIZE
;
tail_room
=
I2400M_TX_BUF_SIZE
-
tx_in
;
...
...
@@ -642,6 +642,9 @@ 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
)
goto
error_tx_new
;
try_new:
if
(
unlikely
(
i2400m
->
tx_msg
==
NULL
))
i2400m_tx_new
(
i2400m
);
...
...
@@ -697,7 +700,10 @@ int i2400m_tx(struct i2400m *i2400m, const void *buf, size_t buf_len,
}
error_tx_new:
spin_unlock_irqrestore
(
&
i2400m
->
tx_lock
,
flags
);
i2400m
->
bus_tx_kick
(
i2400m
);
/* always kick, might free up space */
/* kick in most cases, except when the TX subsys is down, as
* it might free space */
if
(
likely
(
result
!=
-
ESHUTDOWN
))
i2400m
->
bus_tx_kick
(
i2400m
);
d_fnend
(
3
,
dev
,
"(i2400m %p skb %p [%zu bytes] pt %u) = %d
\n
"
,
i2400m
,
buf
,
buf_len
,
pl_type
,
result
);
return
result
;
...
...
@@ -740,6 +746,9 @@ struct i2400m_msg_hdr *i2400m_tx_msg_get(struct i2400m *i2400m,
d_fnstart
(
3
,
dev
,
"(i2400m %p bus_size %p)
\n
"
,
i2400m
,
bus_size
);
spin_lock_irqsave
(
&
i2400m
->
tx_lock
,
flags
);
tx_msg_moved
=
NULL
;
if
(
i2400m
->
tx_buf
==
NULL
)
goto
out_unlock
;
skip:
tx_msg_moved
=
NULL
;
if
(
i2400m
->
tx_in
==
i2400m
->
tx_out
)
{
/* Empty FIFO? */
...
...
@@ -829,6 +838,8 @@ void i2400m_tx_msg_sent(struct i2400m *i2400m)
d_fnstart
(
3
,
dev
,
"(i2400m %p)
\n
"
,
i2400m
);
spin_lock_irqsave
(
&
i2400m
->
tx_lock
,
flags
);
if
(
i2400m
->
tx_buf
==
NULL
)
goto
out_unlock
;
i2400m
->
tx_out
+=
i2400m
->
tx_msg_size
;
d_printf
(
2
,
dev
,
"TX: sent %zu b
\n
"
,
(
size_t
)
i2400m
->
tx_msg_size
);
i2400m
->
tx_msg_size
=
0
;
...
...
@@ -837,6 +848,7 @@ void i2400m_tx_msg_sent(struct i2400m *i2400m)
n
=
i2400m
->
tx_out
/
I2400M_TX_BUF_SIZE
;
i2400m
->
tx_out
%=
I2400M_TX_BUF_SIZE
;
i2400m
->
tx_in
-=
n
*
I2400M_TX_BUF_SIZE
;
out_unlock:
spin_unlock_irqrestore
(
&
i2400m
->
tx_lock
,
flags
);
d_fnend
(
3
,
dev
,
"(i2400m %p) = void
\n
"
,
i2400m
);
}
...
...
@@ -876,5 +888,9 @@ int i2400m_tx_setup(struct i2400m *i2400m)
*/
void
i2400m_tx_release
(
struct
i2400m
*
i2400m
)
{
unsigned
long
flags
;
spin_lock_irqsave
(
&
i2400m
->
tx_lock
,
flags
);
kfree
(
i2400m
->
tx_buf
);
i2400m
->
tx_buf
=
NULL
;
spin_unlock_irqrestore
(
&
i2400m
->
tx_lock
,
flags
);
}
drivers/net/wimax/i2400m/usb-fw.c
View file @
62d83681
...
...
@@ -99,10 +99,10 @@ ssize_t i2400mu_tx_bulk_out(struct i2400mu *i2400mu, void *buf, size_t buf_size)
dev_err
(
dev
,
"BM-CMD: can't get autopm: %d
\n
"
,
result
);
do_autopm
=
0
;
}
epd
=
usb_get_epd
(
i2400mu
->
usb_iface
,
I2400MU_EP_BULK_OUT
);
epd
=
usb_get_epd
(
i2400mu
->
usb_iface
,
i2400mu
->
endpoint_cfg
.
bulk_out
);
pipe
=
usb_sndbulkpipe
(
i2400mu
->
usb_dev
,
epd
->
bEndpointAddress
);
retry:
result
=
usb_bulk_msg
(
i2400mu
->
usb_dev
,
pipe
,
buf
,
buf_size
,
&
len
,
HZ
);
result
=
usb_bulk_msg
(
i2400mu
->
usb_dev
,
pipe
,
buf
,
buf_size
,
&
len
,
200
);
switch
(
result
)
{
case
0
:
if
(
len
!=
buf_size
)
{
...
...
@@ -113,6 +113,28 @@ ssize_t i2400mu_tx_bulk_out(struct i2400mu *i2400mu, void *buf, size_t buf_size)
}
result
=
len
;
break
;
case
-
EPIPE
:
/*
* Stall -- maybe the device is choking with our
* requests. Clear it and give it some time. If they
* happen to often, it might be another symptom, so we
* reset.
*
* No error handling for usb_clear_halt(0; if it
* works, the retry works; if it fails, this switch
* does the error handling for us.
*/
if
(
edc_inc
(
&
i2400mu
->
urb_edc
,
10
*
EDC_MAX_ERRORS
,
EDC_ERROR_TIMEFRAME
))
{
dev_err
(
dev
,
"BM-CMD: too many stalls in "
"URB; resetting device
\n
"
);
usb_queue_reset_device
(
i2400mu
->
usb_iface
);
/* fallthrough */
}
else
{
usb_clear_halt
(
i2400mu
->
usb_dev
,
pipe
);
msleep
(
10
);
/* give the device some time */
goto
retry
;
}
case
-
EINVAL
:
/* while removing driver */
case
-
ENODEV
:
/* dev disconnect ... */
case
-
ENOENT
:
/* just ignore it */
...
...
@@ -135,7 +157,6 @@ ssize_t i2400mu_tx_bulk_out(struct i2400mu *i2400mu, void *buf, size_t buf_size)
result
);
goto
retry
;
}
result
=
len
;
if
(
do_autopm
)
usb_autopm_put_interface
(
i2400mu
->
usb_iface
);
return
result
;
...
...
@@ -172,7 +193,8 @@ ssize_t i2400mu_bus_bm_cmd_send(struct i2400m *i2400m,
result
=
-
E2BIG
;
if
(
cmd_size
>
I2400M_BM_CMD_BUF_SIZE
)
goto
error_too_big
;
memcpy
(
i2400m
->
bm_cmd_buf
,
_cmd
,
cmd_size
);
if
(
_cmd
!=
i2400m
->
bm_cmd_buf
)
memmove
(
i2400m
->
bm_cmd_buf
,
_cmd
,
cmd_size
);
cmd
=
i2400m
->
bm_cmd_buf
;
if
(
cmd_size_a
>
cmd_size
)
/* Zero pad space */
memset
(
i2400m
->
bm_cmd_buf
+
cmd_size
,
0
,
cmd_size_a
-
cmd_size
);
...
...
@@ -226,7 +248,8 @@ int i2400mu_notif_submit(struct i2400mu *i2400mu, struct urb *urb,
struct
usb_endpoint_descriptor
*
epd
;
int
pipe
;
epd
=
usb_get_epd
(
i2400mu
->
usb_iface
,
I2400MU_EP_NOTIFICATION
);
epd
=
usb_get_epd
(
i2400mu
->
usb_iface
,
i2400mu
->
endpoint_cfg
.
notification
);
pipe
=
usb_rcvintpipe
(
i2400mu
->
usb_dev
,
epd
->
bEndpointAddress
);
usb_fill_int_urb
(
urb
,
i2400mu
->
usb_dev
,
pipe
,
i2400m
->
bm_ack_buf
,
I2400M_BM_ACK_BUF_SIZE
,
...
...
@@ -328,8 +351,8 @@ ssize_t i2400mu_bus_bm_wait_for_ack(struct i2400m *i2400m,
out:
if
(
do_autopm
)
usb_autopm_put_interface
(
i2400mu
->
usb_iface
);
d_fnend
(
8
,
dev
,
"(i2400m %p ack %p size %zu) = %
z
d
\n
"
,
i2400m
,
ack
,
ack_size
,
result
);
d_fnend
(
8
,
dev
,
"(i2400m %p ack %p size %zu) = %
l
d
\n
"
,
i2400m
,
ack
,
ack_size
,
(
long
)
result
);
return
result
;
error_exceeded:
...
...
drivers/net/wimax/i2400m/usb-notif.c
View file @
62d83681
...
...
@@ -51,6 +51,7 @@
*
* i2400mu_usb_notification_cb() Called when a URB is ready
* i2400mu_notif_grok()
* i2400m_is_boot_barker()
* i2400m_dev_reset_handle()
* i2400mu_rx_kick()
*/
...
...
@@ -87,32 +88,21 @@ int i2400mu_notification_grok(struct i2400mu *i2400mu, const void *buf,
d_fnstart
(
4
,
dev
,
"(i2400m %p buf %p buf_len %zu)
\n
"
,
i2400mu
,
buf
,
buf_len
);
ret
=
-
EIO
;
if
(
buf_len
<
sizeof
(
i2400m_
NBOOT
_BARKER
))
if
(
buf_len
<
sizeof
(
i2400m_
ZERO
_BARKER
))
/* Not a bug, just ignore */
goto
error_bad_size
;
if
(
!
memcmp
(
i2400m_NBOOT_BARKER
,
buf
,
sizeof
(
i2400m_NBOOT_BARKER
))
||
!
memcmp
(
i2400m_SBOOT_BARKER
,
buf
,
sizeof
(
i2400m_SBOOT_BARKER
)))
ret
=
i2400m_dev_reset_handle
(
i2400m
);
else
if
(
!
memcmp
(
i2400m_ZERO_BARKER
,
buf
,
sizeof
(
i2400m_ZERO_BARKER
)))
{
i2400mu_rx_kick
(
i2400mu
);
ret
=
0
;
}
else
{
/* Unknown or unexpected data in the notif message */
char
prefix
[
64
];
ret
=
-
EIO
;
dev_err
(
dev
,
"HW BUG? Unknown/unexpected data in notification "
"message (%zu bytes)
\n
"
,
buf_len
);
snprintf
(
prefix
,
sizeof
(
prefix
),
"%s %s: "
,
dev_driver_string
(
dev
),
dev_name
(
dev
));
if
(
buf_len
>
64
)
{
print_hex_dump
(
KERN_ERR
,
prefix
,
DUMP_PREFIX_OFFSET
,
8
,
4
,
buf
,
64
,
0
);
printk
(
KERN_ERR
"%s... (only first 64 bytes "
"dumped)
\n
"
,
prefix
);
}
else
print_hex_dump
(
KERN_ERR
,
prefix
,
DUMP_PREFIX_OFFSET
,
8
,
4
,
buf
,
buf_len
,
0
);
if
(
!
memcmp
(
i2400m_ZERO_BARKER
,
buf
,
sizeof
(
i2400m_ZERO_BARKER
)))
{
i2400mu_rx_kick
(
i2400mu
);
goto
out
;
}
ret
=
i2400m_is_boot_barker
(
i2400m
,
buf
,
buf_len
);
if
(
unlikely
(
ret
>=
0
))
ret
=
i2400m_dev_reset_handle
(
i2400m
,
"device rebooted"
);
else
/* Unknown or unexpected data in the notif message */
i2400m_unknown_barker
(
i2400m
,
buf
,
buf_len
);
error_bad_size:
out:
d_fnend
(
4
,
dev
,
"(i2400m %p buf %p buf_len %zu) = %d
\n
"
,
i2400mu
,
buf
,
buf_len
,
ret
);
return
ret
;
...
...
@@ -220,7 +210,8 @@ int i2400mu_notification_setup(struct i2400mu *i2400mu)
dev_err
(
dev
,
"notification: cannot allocate URB
\n
"
);
goto
error_alloc_urb
;
}
epd
=
usb_get_epd
(
i2400mu
->
usb_iface
,
I2400MU_EP_NOTIFICATION
);
epd
=
usb_get_epd
(
i2400mu
->
usb_iface
,
i2400mu
->
endpoint_cfg
.
notification
);
usb_pipe
=
usb_rcvintpipe
(
i2400mu
->
usb_dev
,
epd
->
bEndpointAddress
);
usb_fill_int_urb
(
i2400mu
->
notif_urb
,
i2400mu
->
usb_dev
,
usb_pipe
,
buf
,
I2400MU_MAX_NOTIFICATION_LEN
,
...
...
drivers/net/wimax/i2400m/usb-rx.c
View file @
62d83681
...
...
@@ -204,7 +204,7 @@ struct sk_buff *i2400mu_rx(struct i2400mu *i2400mu, struct sk_buff *rx_skb)
dev_err
(
dev
,
"RX: can't get autopm: %d
\n
"
,
result
);
do_autopm
=
0
;
}
epd
=
usb_get_epd
(
i2400mu
->
usb_iface
,
I2400MU_EP_BULK_IN
);
epd
=
usb_get_epd
(
i2400mu
->
usb_iface
,
i2400mu
->
endpoint_cfg
.
bulk_in
);
usb_pipe
=
usb_rcvbulkpipe
(
i2400mu
->
usb_dev
,
epd
->
bEndpointAddress
);
retry:
rx_size
=
skb_end_pointer
(
rx_skb
)
-
rx_skb
->
data
-
rx_skb
->
len
;
...
...
@@ -214,7 +214,7 @@ struct sk_buff *i2400mu_rx(struct i2400mu *i2400mu, struct sk_buff *rx_skb)
}
result
=
usb_bulk_msg
(
i2400mu
->
usb_dev
,
usb_pipe
,
rx_skb
->
data
+
rx_skb
->
len
,
rx_size
,
&
read_size
,
HZ
);
rx_size
,
&
read_size
,
200
);
usb_mark_last_busy
(
i2400mu
->
usb_dev
);
switch
(
result
)
{
case
0
:
...
...
@@ -222,6 +222,26 @@ struct sk_buff *i2400mu_rx(struct i2400mu *i2400mu, struct sk_buff *rx_skb)
goto
retry
;
/* ZLP, just resubmit */
skb_put
(
rx_skb
,
read_size
);
break
;
case
-
EPIPE
:
/*
* Stall -- maybe the device is choking with our
* requests. Clear it and give it some time. If they
* happen to often, it might be another symptom, so we
* reset.
*
* No error handling for usb_clear_halt(0; if it
* works, the retry works; if it fails, this switch
* does the error handling for us.
*/
if
(
edc_inc
(
&
i2400mu
->
urb_edc
,
10
*
EDC_MAX_ERRORS
,
EDC_ERROR_TIMEFRAME
))
{
dev_err
(
dev
,
"BM-CMD: too many stalls in "
"URB; resetting device
\n
"
);
goto
do_reset
;
}
usb_clear_halt
(
i2400mu
->
usb_dev
,
usb_pipe
);
msleep
(
10
);
/* give the device some time */
goto
retry
;
case
-
EINVAL
:
/* while removing driver */
case
-
ENODEV
:
/* dev disconnect ... */
case
-
ENOENT
:
/* just ignore it */
...
...
@@ -283,6 +303,7 @@ struct sk_buff *i2400mu_rx(struct i2400mu *i2400mu, struct sk_buff *rx_skb)
error_reset:
dev_err
(
dev
,
"RX: maximum errors in URB exceeded; "
"resetting device
\n
"
);
do_reset:
usb_queue_reset_device
(
i2400mu
->
usb_iface
);
rx_skb
=
ERR_PTR
(
result
);
goto
out
;
...
...
@@ -316,10 +337,15 @@ int i2400mu_rxd(void *_i2400mu)
size_t
pending
;
int
rx_size
;
struct
sk_buff
*
rx_skb
;
unsigned
long
flags
;
d_fnstart
(
4
,
dev
,
"(i2400mu %p)
\n
"
,
i2400mu
);
spin_lock_irqsave
(
&
i2400m
->
rx_lock
,
flags
);
BUG_ON
(
i2400mu
->
rx_kthread
!=
NULL
);
i2400mu
->
rx_kthread
=
current
;
spin_unlock_irqrestore
(
&
i2400m
->
rx_lock
,
flags
);
while
(
1
)
{
d_printf
(
2
,
dev
,
"
T
X: waiting for messages
\n
"
);
d_printf
(
2
,
dev
,
"
R
X: waiting for messages
\n
"
);
pending
=
0
;
wait_event_interruptible
(
i2400mu
->
rx_wq
,
...
...
@@ -367,6 +393,9 @@ int i2400mu_rxd(void *_i2400mu)
}
result
=
0
;
out:
spin_lock_irqsave
(
&
i2400m
->
rx_lock
,
flags
);
i2400mu
->
rx_kthread
=
NULL
;
spin_unlock_irqrestore
(
&
i2400m
->
rx_lock
,
flags
);
d_fnend
(
4
,
dev
,
"(i2400mu %p) = %d
\n
"
,
i2400mu
,
result
);
return
result
;
...
...
@@ -403,18 +432,33 @@ int i2400mu_rx_setup(struct i2400mu *i2400mu)
struct
i2400m
*
i2400m
=
&
i2400mu
->
i2400m
;
struct
device
*
dev
=
&
i2400mu
->
usb_iface
->
dev
;
struct
wimax_dev
*
wimax_dev
=
&
i2400m
->
wimax_dev
;
struct
task_struct
*
kthread
;
i2400mu
->
rx_
kthread
=
kthread_run
(
i2400mu_rxd
,
i2400mu
,
"%s-rx"
,
kthread
=
kthread_run
(
i2400mu_rxd
,
i2400mu
,
"%s-rx"
,
wimax_dev
->
name
);
if
(
IS_ERR
(
i2400mu
->
rx_kthread
))
{
result
=
PTR_ERR
(
i2400mu
->
rx_kthread
);
/* the kthread function sets i2400mu->rx_thread */
if
(
IS_ERR
(
kthread
))
{
result
=
PTR_ERR
(
kthread
);
dev_err
(
dev
,
"RX: cannot start thread: %d
\n
"
,
result
);
}
return
result
;
}
void
i2400mu_rx_release
(
struct
i2400mu
*
i2400mu
)
{
kthread_stop
(
i2400mu
->
rx_kthread
);
unsigned
long
flags
;
struct
i2400m
*
i2400m
=
&
i2400mu
->
i2400m
;
struct
device
*
dev
=
i2400m_dev
(
i2400m
);
struct
task_struct
*
kthread
;
spin_lock_irqsave
(
&
i2400m
->
rx_lock
,
flags
);
kthread
=
i2400mu
->
rx_kthread
;
i2400mu
->
rx_kthread
=
NULL
;
spin_unlock_irqrestore
(
&
i2400m
->
rx_lock
,
flags
);
if
(
kthread
)
kthread_stop
(
kthread
);
else
d_printf
(
1
,
dev
,
"RX: kthread had already exited
\n
"
);
}
drivers/net/wimax/i2400m/usb-tx.c
View file @
62d83681
...
...
@@ -101,11 +101,11 @@ int i2400mu_tx(struct i2400mu *i2400mu, struct i2400m_msg_hdr *tx_msg,
dev_err
(
dev
,
"TX: can't get autopm: %d
\n
"
,
result
);
do_autopm
=
0
;
}
epd
=
usb_get_epd
(
i2400mu
->
usb_iface
,
I2400MU_EP_BULK_OUT
);
epd
=
usb_get_epd
(
i2400mu
->
usb_iface
,
i2400mu
->
endpoint_cfg
.
bulk_out
);
usb_pipe
=
usb_sndbulkpipe
(
i2400mu
->
usb_dev
,
epd
->
bEndpointAddress
);
retry:
result
=
usb_bulk_msg
(
i2400mu
->
usb_dev
,
usb_pipe
,
tx_msg
,
tx_msg_size
,
&
sent_size
,
HZ
);
tx_msg
,
tx_msg_size
,
&
sent_size
,
200
);
usb_mark_last_busy
(
i2400mu
->
usb_dev
);
switch
(
result
)
{
case
0
:
...
...
@@ -115,6 +115,28 @@ int i2400mu_tx(struct i2400mu *i2400mu, struct i2400m_msg_hdr *tx_msg,
result
=
-
EIO
;
}
break
;
case
-
EPIPE
:
/*
* Stall -- maybe the device is choking with our
* requests. Clear it and give it some time. If they
* happen to often, it might be another symptom, so we
* reset.
*
* No error handling for usb_clear_halt(0; if it
* works, the retry works; if it fails, this switch
* does the error handling for us.
*/
if
(
edc_inc
(
&
i2400mu
->
urb_edc
,
10
*
EDC_MAX_ERRORS
,
EDC_ERROR_TIMEFRAME
))
{
dev_err
(
dev
,
"BM-CMD: too many stalls in "
"URB; resetting device
\n
"
);
usb_queue_reset_device
(
i2400mu
->
usb_iface
);
/* fallthrough */
}
else
{
usb_clear_halt
(
i2400mu
->
usb_dev
,
usb_pipe
);
msleep
(
10
);
/* give the device some time */
goto
retry
;
}
case
-
EINVAL
:
/* while removing driver */
case
-
ENODEV
:
/* dev disconnect ... */
case
-
ENOENT
:
/* just ignore it */
...
...
@@ -161,9 +183,15 @@ int i2400mu_txd(void *_i2400mu)
struct
device
*
dev
=
&
i2400mu
->
usb_iface
->
dev
;
struct
i2400m_msg_hdr
*
tx_msg
;
size_t
tx_msg_size
;
unsigned
long
flags
;
d_fnstart
(
4
,
dev
,
"(i2400mu %p)
\n
"
,
i2400mu
);
spin_lock_irqsave
(
&
i2400m
->
tx_lock
,
flags
);
BUG_ON
(
i2400mu
->
tx_kthread
!=
NULL
);
i2400mu
->
tx_kthread
=
current
;
spin_unlock_irqrestore
(
&
i2400m
->
tx_lock
,
flags
);
while
(
1
)
{
d_printf
(
2
,
dev
,
"TX: waiting for messages
\n
"
);
tx_msg
=
NULL
;
...
...
@@ -183,6 +211,11 @@ int i2400mu_txd(void *_i2400mu)
if
(
result
<
0
)
break
;
}
spin_lock_irqsave
(
&
i2400m
->
tx_lock
,
flags
);
i2400mu
->
tx_kthread
=
NULL
;
spin_unlock_irqrestore
(
&
i2400m
->
tx_lock
,
flags
);
d_fnend
(
4
,
dev
,
"(i2400mu %p) = %d
\n
"
,
i2400mu
,
result
);
return
result
;
}
...
...
@@ -213,11 +246,13 @@ int i2400mu_tx_setup(struct i2400mu *i2400mu)
struct
i2400m
*
i2400m
=
&
i2400mu
->
i2400m
;
struct
device
*
dev
=
&
i2400mu
->
usb_iface
->
dev
;
struct
wimax_dev
*
wimax_dev
=
&
i2400m
->
wimax_dev
;
struct
task_struct
*
kthread
;
i2400mu
->
tx_
kthread
=
kthread_run
(
i2400mu_txd
,
i2400mu
,
"%s-tx"
,
kthread
=
kthread_run
(
i2400mu_txd
,
i2400mu
,
"%s-tx"
,
wimax_dev
->
name
);
if
(
IS_ERR
(
i2400mu
->
tx_kthread
))
{
result
=
PTR_ERR
(
i2400mu
->
tx_kthread
);
/* the kthread function sets i2400mu->tx_thread */
if
(
IS_ERR
(
kthread
))
{
result
=
PTR_ERR
(
kthread
);
dev_err
(
dev
,
"TX: cannot start thread: %d
\n
"
,
result
);
}
return
result
;
...
...
@@ -225,5 +260,17 @@ int i2400mu_tx_setup(struct i2400mu *i2400mu)
void
i2400mu_tx_release
(
struct
i2400mu
*
i2400mu
)
{
kthread_stop
(
i2400mu
->
tx_kthread
);
unsigned
long
flags
;
struct
i2400m
*
i2400m
=
&
i2400mu
->
i2400m
;
struct
device
*
dev
=
i2400m_dev
(
i2400m
);
struct
task_struct
*
kthread
;
spin_lock_irqsave
(
&
i2400m
->
tx_lock
,
flags
);
kthread
=
i2400mu
->
tx_kthread
;
i2400mu
->
tx_kthread
=
NULL
;
spin_unlock_irqrestore
(
&
i2400m
->
tx_lock
,
flags
);
if
(
kthread
)
kthread_stop
(
kthread
);
else
d_printf
(
1
,
dev
,
"TX: kthread had already exited
\n
"
);
}
drivers/net/wimax/i2400m/usb.c
View file @
62d83681
...
...
@@ -58,7 +58,7 @@
* i2400mu_rx_release()
* i2400mu_tx_release()
*
* i2400mu_bus_reset() Called by i2400m
->bus
_reset
* i2400mu_bus_reset() Called by i2400m_reset
* __i2400mu_reset()
* __i2400mu_send_barker()
* usb_reset_device()
...
...
@@ -71,13 +71,25 @@
#define D_SUBMODULE usb
#include "usb-debug-levels.h"
static
char
i2400mu_debug_params
[
128
];
module_param_string
(
debug
,
i2400mu_debug_params
,
sizeof
(
i2400mu_debug_params
),
0644
);
MODULE_PARM_DESC
(
debug
,
"String of space-separated NAME:VALUE pairs, where NAMEs "
"are the different debug submodules and VALUE are the "
"initial debug value to set."
);
/* Our firmware file name */
static
const
char
*
i2400mu_bus_fw_names
[]
=
{
static
const
char
*
i2400mu_bus_fw_names
_5x50
[]
=
{
#define I2400MU_FW_FILE_NAME_v1_4 "i2400m-fw-usb-1.4.sbcf"
I2400MU_FW_FILE_NAME_v1_4
,
#define I2400MU_FW_FILE_NAME_v1_3 "i2400m-fw-usb-1.3.sbcf"
I2400MU_FW_FILE_NAME_v1_3
,
NULL
,
};
static
const
char
*
i2400mu_bus_fw_names_6050
[]
=
{
#define I6050U_FW_FILE_NAME_v1_5 "i6050-fw-usb-1.5.sbcf"
I6050U_FW_FILE_NAME_v1_5
,
NULL
,
};
...
...
@@ -160,15 +172,60 @@ int __i2400mu_send_barker(struct i2400mu *i2400mu,
epd
=
usb_get_epd
(
i2400mu
->
usb_iface
,
endpoint
);
pipe
=
usb_sndbulkpipe
(
i2400mu
->
usb_dev
,
epd
->
bEndpointAddress
);
memcpy
(
buffer
,
barker
,
barker_size
);
retry:
ret
=
usb_bulk_msg
(
i2400mu
->
usb_dev
,
pipe
,
buffer
,
barker_size
,
&
actual_len
,
HZ
);
if
(
ret
<
0
)
{
if
(
ret
!=
-
EINVAL
)
dev_err
(
dev
,
"E: barker error: %d
\n
"
,
ret
);
}
else
if
(
actual_len
!=
barker_size
)
{
dev_err
(
dev
,
"E: only %d bytes transmitted
\n
"
,
actual_len
);
&
actual_len
,
200
);
switch
(
ret
)
{
case
0
:
if
(
actual_len
!=
barker_size
)
{
/* Too short? drop it */
dev_err
(
dev
,
"E: %s: short write (%d B vs %zu "
"expected)
\n
"
,
__func__
,
actual_len
,
barker_size
);
ret
=
-
EIO
;
}
break
;
case
-
EPIPE
:
/*
* Stall -- maybe the device is choking with our
* requests. Clear it and give it some time. If they
* happen to often, it might be another symptom, so we
* reset.
*
* No error handling for usb_clear_halt(0; if it
* works, the retry works; if it fails, this switch
* does the error handling for us.
*/
if
(
edc_inc
(
&
i2400mu
->
urb_edc
,
10
*
EDC_MAX_ERRORS
,
EDC_ERROR_TIMEFRAME
))
{
dev_err
(
dev
,
"E: %s: too many stalls in "
"URB; resetting device
\n
"
,
__func__
);
usb_queue_reset_device
(
i2400mu
->
usb_iface
);
/* fallthrough */
}
else
{
usb_clear_halt
(
i2400mu
->
usb_dev
,
pipe
);
msleep
(
10
);
/* give the device some time */
goto
retry
;
}
case
-
EINVAL
:
/* while removing driver */
case
-
ENODEV
:
/* dev disconnect ... */
case
-
ENOENT
:
/* just ignore it */
case
-
ESHUTDOWN
:
/* and exit */
case
-
ECONNRESET
:
ret
=
-
ESHUTDOWN
;
break
;
default:
/* Some error? */
if
(
edc_inc
(
&
i2400mu
->
urb_edc
,
EDC_MAX_ERRORS
,
EDC_ERROR_TIMEFRAME
))
{
dev_err
(
dev
,
"E: %s: maximum errors in URB "
"exceeded; resetting device
\n
"
,
__func__
);
usb_queue_reset_device
(
i2400mu
->
usb_iface
);
}
else
{
dev_warn
(
dev
,
"W: %s: cannot send URB: %d
\n
"
,
__func__
,
ret
);
goto
retry
;
}
}
kfree
(
buffer
);
error_kzalloc:
if
(
do_autopm
)
...
...
@@ -232,15 +289,16 @@ int i2400mu_bus_reset(struct i2400m *i2400m, enum i2400m_reset_type rt)
d_fnstart
(
3
,
dev
,
"(i2400m %p rt %u)
\n
"
,
i2400m
,
rt
);
if
(
rt
==
I2400M_RT_WARM
)
result
=
__i2400mu_send_barker
(
i2400mu
,
i2400m_WARM_BOOT_BARKER
,
result
=
__i2400mu_send_barker
(
i2400mu
,
i2400m_WARM_BOOT_BARKER
,
sizeof
(
i2400m_WARM_BOOT_BARKER
),
I2400MU_EP_BULK_OUT
);
i2400mu
->
endpoint_cfg
.
bulk_out
);
else
if
(
rt
==
I2400M_RT_COLD
)
result
=
__i2400mu_send_barker
(
i2400mu
,
i2400m_COLD_BOOT_BARKER
,
result
=
__i2400mu_send_barker
(
i2400mu
,
i2400m_COLD_BOOT_BARKER
,
sizeof
(
i2400m_COLD_BOOT_BARKER
),
I2400MU_EP_RESET_COLD
);
i2400mu
->
endpoint_cfg
.
reset_cold
);
else
if
(
rt
==
I2400M_RT_BUS
)
{
do_bus_reset:
result
=
usb_reset_device
(
i2400mu
->
usb_dev
);
switch
(
result
)
{
case
0
:
...
...
@@ -248,7 +306,7 @@ int i2400mu_bus_reset(struct i2400m *i2400m, enum i2400m_reset_type rt)
case
-
ENODEV
:
case
-
ENOENT
:
case
-
ESHUTDOWN
:
result
=
rt
==
I2400M_RT_WARM
?
-
ENODEV
:
0
;
result
=
0
;
break
;
/* We assume the device is disconnected */
default:
dev_err
(
dev
,
"USB reset failed (%d), giving up!
\n
"
,
...
...
@@ -261,10 +319,17 @@ int i2400mu_bus_reset(struct i2400m *i2400m, enum i2400m_reset_type rt)
if
(
result
<
0
&&
result
!=
-
EINVAL
/* device is gone */
&&
rt
!=
I2400M_RT_BUS
)
{
/*
* Things failed -- resort to lower level reset, that
* we queue in another context; the reason for this is
* that the pre and post reset functionality requires
* the i2400m->init_mutex; RT_WARM and RT_COLD can
* come from areas where i2400m->init_mutex is taken.
*/
dev_err
(
dev
,
"%s reset failed (%d); trying USB reset
\n
"
,
rt
==
I2400M_RT_WARM
?
"warm"
:
"cold"
,
result
);
rt
=
I2400M_RT_BUS
;
goto
do_bus_reset
;
usb_queue_reset_device
(
i2400mu
->
usb_iface
)
;
result
=
-
ENODEV
;
}
d_fnend
(
3
,
dev
,
"(i2400m %p rt %u) = %d
\n
"
,
i2400m
,
rt
,
result
);
return
result
;
...
...
@@ -402,20 +467,33 @@ int i2400mu_probe(struct usb_interface *iface,
i2400m
->
bus_tx_block_size
=
I2400MU_BLK_SIZE
;
i2400m
->
bus_pl_size_max
=
I2400MU_PL_SIZE_MAX
;
i2400m
->
bus_setup
=
NULL
;
i2400m
->
bus_dev_start
=
i2400mu_bus_dev_start
;
i2400m
->
bus_dev_stop
=
i2400mu_bus_dev_stop
;
i2400m
->
bus_release
=
NULL
;
i2400m
->
bus_tx_kick
=
i2400mu_bus_tx_kick
;
i2400m
->
bus_reset
=
i2400mu_bus_reset
;
i2400m
->
bus_bm_retries
=
I2400M_BOOT_RETRIES
;
i2400m
->
bus_bm_retries
=
I2400M_
USB_
BOOT_RETRIES
;
i2400m
->
bus_bm_cmd_send
=
i2400mu_bus_bm_cmd_send
;
i2400m
->
bus_bm_wait_for_ack
=
i2400mu_bus_bm_wait_for_ack
;
i2400m
->
bus_fw_names
=
i2400mu_bus_fw_names
;
i2400m
->
bus_bm_mac_addr_impaired
=
0
;
if
(
id
->
idProduct
==
USB_DEVICE_ID_I6050
)
{
i2400m
->
bus_fw_names
=
i2400mu_bus_fw_names_6050
;
i2400mu
->
endpoint_cfg
.
bulk_out
=
0
;
i2400mu
->
endpoint_cfg
.
notification
=
3
;
i2400mu
->
endpoint_cfg
.
reset_cold
=
2
;
i2400mu
->
endpoint_cfg
.
bulk_in
=
1
;
}
else
{
i2400m
->
bus_fw_names
=
i2400mu_bus_fw_names_5x50
;
i2400mu
->
endpoint_cfg
.
bulk_out
=
0
;
i2400mu
->
endpoint_cfg
.
notification
=
1
;
i2400mu
->
endpoint_cfg
.
reset_cold
=
2
;
i2400mu
->
endpoint_cfg
.
bulk_in
=
3
;
}
#ifdef CONFIG_PM
iface
->
needs_remote_wakeup
=
1
;
/* autosuspend (15s delay) */
device_init_wakeup
(
dev
,
1
);
usb_autopm_enable
(
i2400mu
->
usb_iface
);
usb_dev
->
autosuspend_delay
=
15
*
HZ
;
usb_dev
->
autosuspend_disabled
=
0
;
#endif
...
...
@@ -483,7 +561,10 @@ void i2400mu_disconnect(struct usb_interface *iface)
* So at the end, the three cases require common handling.
*
* If at the time of this call the device's firmware is not loaded,
* nothing has to be done.
* nothing has to be done. Note we can be "loose" about not reading
* i2400m->updown under i2400m->init_mutex. If it happens to change
* inmediately, other parts of the call flow will fail and effectively
* catch it.
*
* If the firmware is loaded, we need to:
*
...
...
@@ -522,6 +603,7 @@ int i2400mu_suspend(struct usb_interface *iface, pm_message_t pm_msg)
#endif
d_fnstart
(
3
,
dev
,
"(iface %p pm_msg %u)
\n
"
,
iface
,
pm_msg
.
event
);
rmb
();
/* see i2400m->updown's documentation */
if
(
i2400m
->
updown
==
0
)
goto
no_firmware
;
if
(
i2400m
->
state
==
I2400M_SS_DATA_PATH_CONNECTED
&&
is_autosuspend
)
{
...
...
@@ -575,6 +657,7 @@ int i2400mu_resume(struct usb_interface *iface)
struct
i2400m
*
i2400m
=
&
i2400mu
->
i2400m
;
d_fnstart
(
3
,
dev
,
"(iface %p)
\n
"
,
iface
);
rmb
();
/* see i2400m->updown's documentation */
if
(
i2400m
->
updown
==
0
)
{
d_printf
(
1
,
dev
,
"fw was down, no resume neeed
\n
"
);
goto
out
;
...
...
@@ -590,8 +673,55 @@ int i2400mu_resume(struct usb_interface *iface)
}
static
int
i2400mu_reset_resume
(
struct
usb_interface
*
iface
)
{
int
result
;
struct
device
*
dev
=
&
iface
->
dev
;
struct
i2400mu
*
i2400mu
=
usb_get_intfdata
(
iface
);
struct
i2400m
*
i2400m
=
&
i2400mu
->
i2400m
;
d_fnstart
(
3
,
dev
,
"(iface %p)
\n
"
,
iface
);
result
=
i2400m_dev_reset_handle
(
i2400m
,
"device reset on resume"
);
d_fnend
(
3
,
dev
,
"(iface %p) = %d
\n
"
,
iface
,
result
);
return
result
<
0
?
result
:
0
;
}
/*
* Another driver or user space is triggering a reset on the device
* which contains the interface passed as an argument. Cease IO and
* save any device state you need to restore.
*
* If you need to allocate memory here, use GFP_NOIO or GFP_ATOMIC, if
* you are in atomic context.
*/
static
int
i2400mu_pre_reset
(
struct
usb_interface
*
iface
)
{
struct
i2400mu
*
i2400mu
=
usb_get_intfdata
(
iface
);
return
i2400m_pre_reset
(
&
i2400mu
->
i2400m
);
}
/*
* The reset has completed. Restore any saved device state and begin
* using the device again.
*
* If you need to allocate memory here, use GFP_NOIO or GFP_ATOMIC, if
* you are in atomic context.
*/
static
int
i2400mu_post_reset
(
struct
usb_interface
*
iface
)
{
struct
i2400mu
*
i2400mu
=
usb_get_intfdata
(
iface
);
return
i2400m_post_reset
(
&
i2400mu
->
i2400m
);
}
static
struct
usb_device_id
i2400mu_id_table
[]
=
{
{
USB_DEVICE
(
0x8086
,
USB_DEVICE_ID_I6050
)
},
{
USB_DEVICE
(
0x8086
,
0x0181
)
},
{
USB_DEVICE
(
0x8086
,
0x1403
)
},
{
USB_DEVICE
(
0x8086
,
0x1405
)
},
...
...
@@ -609,8 +739,11 @@ struct usb_driver i2400mu_driver = {
.
name
=
KBUILD_MODNAME
,
.
suspend
=
i2400mu_suspend
,
.
resume
=
i2400mu_resume
,
.
reset_resume
=
i2400mu_reset_resume
,
.
probe
=
i2400mu_probe
,
.
disconnect
=
i2400mu_disconnect
,
.
pre_reset
=
i2400mu_pre_reset
,
.
post_reset
=
i2400mu_post_reset
,
.
id_table
=
i2400mu_id_table
,
.
supports_autosuspend
=
1
,
};
...
...
@@ -618,6 +751,8 @@ struct usb_driver i2400mu_driver = {
static
int
__init
i2400mu_driver_init
(
void
)
{
d_parse_params
(
D_LEVEL
,
D_LEVEL_SIZE
,
i2400mu_debug_params
,
"i2400m_usb.debug"
);
return
usb_register
(
&
i2400mu_driver
);
}
module_init
(
i2400mu_driver_init
);
...
...
@@ -632,7 +767,7 @@ void __exit i2400mu_driver_exit(void)
module_exit
(
i2400mu_driver_exit
);
MODULE_AUTHOR
(
"Intel Corporation <linux-wimax@intel.com>"
);
MODULE_DESCRIPTION
(
"Intel 2400M WiMAX networking for USB"
);
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_3
);
include/linux/mmc/sdio_ids.h
View file @
62d83681
...
...
@@ -28,6 +28,7 @@
#define SDIO_DEVICE_ID_INTEL_IWMC3200TOP 0x1404
#define SDIO_DEVICE_ID_INTEL_IWMC3200GPS 0x1405
#define SDIO_DEVICE_ID_INTEL_IWMC3200BT 0x1406
#define SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX_2G5 0x1407
#define SDIO_VENDOR_ID_MARVELL 0x02df
#define SDIO_DEVICE_ID_MARVELL_LIBERTAS 0x9103
...
...
include/linux/wimax/debug.h
View file @
62d83681
...
...
@@ -450,4 +450,76 @@ do { \
})
static
inline
void
d_submodule_set
(
struct
d_level
*
d_level
,
size_t
d_level_size
,
const
char
*
submodule
,
u8
level
,
const
char
*
tag
)
{
struct
d_level
*
itr
,
*
top
;
int
index
=
-
1
;
for
(
itr
=
d_level
,
top
=
itr
+
d_level_size
;
itr
<
top
;
itr
++
)
{
index
++
;
if
(
itr
->
name
==
NULL
)
{
printk
(
KERN_ERR
"%s: itr->name NULL?? (%p, #%d)
\n
"
,
tag
,
itr
,
index
);
continue
;
}
if
(
!
strcmp
(
itr
->
name
,
submodule
))
{
itr
->
level
=
level
;
return
;
}
}
printk
(
KERN_ERR
"%s: unknown submodule %s
\n
"
,
tag
,
submodule
);
}
/**
* d_parse_params - Parse a string with debug parameters from the
* command line
*
* @d_level: level structure (D_LEVEL)
* @d_level_size: number of items in the level structure
* (D_LEVEL_SIZE).
* @_params: string with the parameters; this is a space (not tab!)
* separated list of NAME:VALUE, where value is the debug level
* and NAME is the name of the submodule.
* @tag: string for error messages (example: MODULE.ARGNAME).
*/
static
inline
void
d_parse_params
(
struct
d_level
*
d_level
,
size_t
d_level_size
,
const
char
*
_params
,
const
char
*
tag
)
{
char
submodule
[
130
],
*
params
,
*
params_orig
,
*
token
,
*
colon
;
unsigned
level
,
tokens
;
if
(
_params
==
NULL
)
return
;
params_orig
=
kstrdup
(
_params
,
GFP_KERNEL
);
params
=
params_orig
;
while
(
1
)
{
token
=
strsep
(
&
params
,
" "
);
if
(
token
==
NULL
)
break
;
if
(
*
token
==
'\0'
)
/* eat joint spaces */
continue
;
/* kernel's sscanf %s eats until whitespace, so we
* replace : by \n so it doesn't get eaten later by
* strsep */
colon
=
strchr
(
token
,
':'
);
if
(
colon
!=
NULL
)
*
colon
=
'\n'
;
tokens
=
sscanf
(
token
,
"%s
\n
%u"
,
submodule
,
&
level
);
if
(
colon
!=
NULL
)
*
colon
=
':'
;
/* set back, for error messages */
if
(
tokens
==
2
)
d_submodule_set
(
d_level
,
d_level_size
,
submodule
,
level
,
tag
);
else
printk
(
KERN_ERR
"%s: can't parse '%s' as a "
"SUBMODULE:LEVEL (%d tokens)
\n
"
,
tag
,
token
,
tokens
);
}
kfree
(
params_orig
);
}
#endif
/* #ifndef __debug__h__ */
include/linux/wimax/i2400m.h
View file @
62d83681
...
...
@@ -138,7 +138,7 @@ struct i2400m_bcf_hdr {
__le32
module_id
;
__le32
module_vendor
;
__le32
date
;
/* BCD YYYMMDD */
__le32
size
;
__le32
size
;
/* in dwords */
__le32
key_size
;
/* in dwords */
__le32
modulus_size
;
/* in dwords */
__le32
exponent_size
;
/* in dwords */
...
...
@@ -168,16 +168,6 @@ enum i2400m_brh {
};
/* Constants for bcf->module_id */
enum
i2400m_bcf_mod_id
{
/* Firmware file carries its own pokes -- pokes are a set of
* magical values that have to be written in certain memory
* addresses to get the device up and ready for firmware
* download when it is in non-signed boot mode. */
I2400M_BCF_MOD_ID_POKES
=
0x000000001
,
};
/**
* i2400m_bootrom_header - Header for a boot-mode command
*
...
...
@@ -276,6 +266,7 @@ enum {
I2400M_WARM_RESET_BARKER
=
0x50f750f7
,
I2400M_NBOOT_BARKER
=
0xdeadbeef
,
I2400M_SBOOT_BARKER
=
0x0ff1c1a1
,
I2400M_SBOOT_BARKER_6050
=
0x80000001
,
I2400M_ACK_BARKER
=
0xfeedbabe
,
I2400M_D2H_MSG_BARKER
=
0xbeefbabe
,
};
...
...
include/net/wimax.h
View file @
62d83681
...
...
@@ -195,6 +195,12 @@
* defining the `struct nla_policy` for each message, it has to have
* an array size of WIMAX_GNL_ATTR_MAX+1.
*
* The op_*() function pointers will not be called if the wimax_dev is
* in a state <= %WIMAX_ST_UNINITIALIZED. The exception is:
*
* - op_reset: can be called at any time after wimax_dev_add() has
* been called.
*
* THE PIPE INTERFACE:
*
* This interface is kept intentionally simple. The driver can send
...
...
net/wimax/op-msg.c
View file @
62d83681
...
...
@@ -388,6 +388,8 @@ int wimax_gnl_doit_msg_from_user(struct sk_buff *skb, struct genl_info *info)
}
mutex_lock
(
&
wimax_dev
->
mutex
);
result
=
wimax_dev_is_ready
(
wimax_dev
);
if
(
result
==
-
ENOMEDIUM
)
result
=
0
;
if
(
result
<
0
)
goto
error_not_ready
;
result
=
-
ENOSYS
;
...
...
net/wimax/op-rfkill.c
View file @
62d83681
...
...
@@ -305,8 +305,15 @@ int wimax_rfkill(struct wimax_dev *wimax_dev, enum wimax_rf_state state)
d_fnstart
(
3
,
dev
,
"(wimax_dev %p state %u)
\n
"
,
wimax_dev
,
state
);
mutex_lock
(
&
wimax_dev
->
mutex
);
result
=
wimax_dev_is_ready
(
wimax_dev
);
if
(
result
<
0
)
if
(
result
<
0
)
{
/* While initializing, < 1.4.3 wimax-tools versions use
* this call to check if the device is a valid WiMAX
* device; so we allow it to proceed always,
* considering the radios are all off. */
if
(
result
==
-
ENOMEDIUM
&&
state
==
WIMAX_RF_QUERY
)
result
=
WIMAX_RF_OFF
<<
1
|
WIMAX_RF_OFF
;
goto
error_not_ready
;
}
switch
(
state
)
{
case
WIMAX_RF_ON
:
case
WIMAX_RF_OFF
:
...
...
@@ -355,6 +362,7 @@ int wimax_rfkill_add(struct wimax_dev *wimax_dev)
wimax_dev
->
rfkill
=
rfkill
;
rfkill_init_sw_state
(
rfkill
,
1
);
result
=
rfkill_register
(
wimax_dev
->
rfkill
);
if
(
result
<
0
)
goto
error_rfkill_register
;
...
...
net/wimax/stack.c
View file @
62d83681
...
...
@@ -60,6 +60,14 @@
#define D_SUBMODULE stack
#include "debug-levels.h"
static
char
wimax_debug_params
[
128
];
module_param_string
(
debug
,
wimax_debug_params
,
sizeof
(
wimax_debug_params
),
0644
);
MODULE_PARM_DESC
(
debug
,
"String of space-separated NAME:VALUE pairs, where NAMEs "
"are the different debug submodules and VALUE are the "
"initial debug value to set."
);
/*
* Authoritative source for the RE_STATE_CHANGE attribute policy
*
...
...
@@ -562,6 +570,9 @@ int __init wimax_subsys_init(void)
int
result
,
cnt
;
d_fnstart
(
4
,
NULL
,
"()
\n
"
);
d_parse_params
(
D_LEVEL
,
D_LEVEL_SIZE
,
wimax_debug_params
,
"wimax.debug"
);
snprintf
(
wimax_gnl_family
.
name
,
sizeof
(
wimax_gnl_family
.
name
),
"WiMAX"
);
result
=
genl_register_family
(
&
wimax_gnl_family
);
...
...
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