Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
linux-davinci
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
linux
linux-davinci
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
Hide 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
);
result
=
schedule_work
(
&
iw
->
ws
);
if
(
result
==
0
)
result
=
-
ENXIO
;
error_kzalloc:
iw
=
__i2400m_work_setup
(
i2400m
,
fn
,
gfp_flags
,
pl
,
pl_size
);
if
(
iw
!=
NULL
)
{
result
=
schedule_work
(
&
iw
->
ws
);
if
(
WARN_ON
(
result
==
0
))
result
=
-
ENXIO
;
}
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 @@ retry:
dev_err
(
dev
,
"cannot create workqueue
\n
"
);
goto
error_create_workqueue
;
}
result
=
i2400m
->
bus_dev_start
(
i2400m
);
if
(
result
<
0
)
goto
error_bus_dev_start
;
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 @@ retry:
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,8 +411,12 @@ retry:
error_dev_initialize:
error_check_mac_addr:
i2400m
->
ready
=
0
;
wmb
();
/* see i2400m->ready's documentation */
flush_workqueue
(
i2400m
->
work_queue
);
error_fw_check:
i2400m
->
bus_dev_stop
(
i2400m
);
if
(
i2400m
->
bus_dev_stop
)
i2400m
->
bus_dev_stop
(
i2400m
);
error_bus_dev_start:
destroy_workqueue
(
i2400m
->
work_queue
);
error_create_workqueue:
...
...
@@ -466,11 +438,15 @@ error_bootstrap:
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 */
result
=
__i2400m_dev_start
(
i2400m
,
bm_flags
);
if
(
result
>=
0
)
i2400m
->
updown
=
1
;
if
(
i2400m
->
updown
==
0
)
{
result
=
__i2400m_dev_start
(
i2400m
,
bm_flags
);
if
(
result
>=
0
)
{
i2400m
->
updown
=
1
;
wmb
();
/* see i2400m->updown's documentation */
}
}
mutex_unlock
(
&
i2400m
->
init_mutex
);
return
result
;
}
...
...
@@ -495,9 +471,20 @@ 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
;
i2400m
->
bus_dev_stop
(
i2400m
);
/*
* 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
);
i2400m_tx_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 @@ out:
* 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_kz
alloc
;
result
=
i2400m_bm_buf_alloc
(
i2400m
);
if
(
result
<
0
)
{
dev_err
(
dev
,
"cannot allocate
bootmode scratch buffers
\n
"
);
goto
error_bm_
buf_
alloc
;
}
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
;
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
;
}
}
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_check
* i2400m_fw_dnload
* 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 @@ error_send:
}
/*
* 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
"
);
goto
do_reboot_ack
;
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 @@ do_reboot:
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 @@ do_reboot:
* 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 @@ do_reboot_ack:
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
);
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
;
}
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
);
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
);
/* 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
,
"bad fw %s: unexpected module type 0x%x; "
"aborting
\n
"
,
i2400m
->
fw_name
,
module_type
);
goto
error
;
dev_err
(
dev
,
"firmware %s #%zd@%08zx: unexpected module "
"type 0x%x; aborting
\n
"
,
i2400m
->
fw_name
,
index
,
offset
,
module_type
);
return
-
EBADF
;
}
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
;
}
/* Check soft-er errors */
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:
dev_warn
(
dev
,
"firmware %s #%zd@%08zx: build date %08x "
"too old; unsupported
\n
"
,
i2400m
->
fw_name
,
index
,
offset
,
date
);
return
0
;
}
/*
* 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
;
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
;
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 @@ error:
*/
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 @@ hw_reboot:
* 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 @@ hw_reboot:
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 @@ hw_reboot:
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 @@ error_dev_rebooted:
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 @@ error_dev_rebooted:
*/
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
;
}
i2400m
->
fw_name
=
fw_name
;
ret
=
i2400m_fw_bootstrap
(
i2400m
,
fw
,
flags
);
release_firmware
(
fw
);
if
(
ret
>=
0
)
/* firmware loaded succesfully */
break
;
i2400m
->
fw_name
=
NULL
;
}
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:
release_firmware
(
fw
);
error_no_fw:
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,27 +216,50 @@ 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
* the device.
*
* @bus_tx_kick: [fill] Function called by the bus-generic code to let
* the bus-specific code know that there is data available in the
* TX FIFO for transmission to the device.
...
...
@@ -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,10 +837,12 @@ 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
*
,
void
(
*
)(
struct
work_struct
*
),
gfp_t
,
extern
int
i2400m_schedule_work
(
struct
i2400m
*
,
void
(
*
)(
struct
work_struct
*
),
gfp_t
,
const
void
*
,
size_t
);
extern
int
i2400m_msg_check_status
(
const
struct
i2400m_l3l4_hdr
*
,
...
...
@@ -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
);
goto
error
;
"%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
);
kfree_skb
(
args
->
skb_rx
);
i2400m_put
(
iw
->
i2400m
);
kfree
(
iw
);
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
);
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 @@ error_msg_hdr_check:
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 @@ error_memcpy_fromio:
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
)
{
destroy_workqueue
(
i2400ms
->
tx_workqueue
);
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 @@ function_enabled:
/*
* 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 @@ error_kzalloc:
* 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
;
}
result
=
i2400ms_enable_function
(
i2400ms
->
func
);
if
(
result
<
0
)
{
dev_err
(
dev
,
"Cannot enable SDIO function: %d
\n
"
,
result
);
goto
error_func_enable
;
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_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 @@ try_new:
}
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 @@ retry:
}
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 @@ retry:
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 @@ error_dev_gone:
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
)))
{
ret
=
0
;
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
);
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 @@ retry:
}
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 @@ retry:
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 @@ out:
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"
,
wimax_dev
->
name
);
if
(
IS_ERR
(
i2400mu
->
rx_kthread
))
{
result
=
PTR_ERR
(
i2400mu
->
rx_kthread
);
kthread
=
kthread_run
(
i2400mu_rxd
,
i2400mu
,
"%s-rx"
,
wimax_dev
->
name
);
/* 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 @@ retry:
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"
,
wimax_dev
->
name
);
if
(
IS_ERR
(
i2400mu
->
tx_kthread
))
{
result
=
PTR_ERR
(
i2400mu
->
tx_kthread
);
kthread
=
kthread_run
(
i2400mu_txd
,
i2400mu
,
"%s-tx"
,
wimax_dev
->
name
);
/* 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,14 +172,59 @@ 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
);
ret
=
-
EIO
;
&
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:
...
...
@@ -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
,
sizeof
(
i2400m_WARM_BOOT_BARKER
),
I2400MU_EP_BULK_OUT
);
result
=
__i2400mu_send_barker
(
i2400mu
,
i2400m_WARM_BOOT_BARKER
,
sizeof
(
i2400m_WARM_BOOT_BARKER
),
i2400mu
->
endpoint_cfg
.
bulk_out
);
else
if
(
rt
==
I2400M_RT_COLD
)
result
=
__i2400mu_send_barker
(
i2400mu
,
i2400m_COLD_BOOT_BARKER
,
sizeof
(
i2400m_COLD_BOOT_BARKER
),
I2400MU_EP_RESET_COLD
);
result
=
__i2400mu_send_barker
(
i2400mu
,
i2400m_COLD_BOOT_BARKER
,
sizeof
(
i2400m_COLD_BOOT_BARKER
),
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 @@ do_bus_reset:
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 @@ do_bus_reset:
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 @@ out:
}
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