Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
raspberrypi-kernel
提交
62d83681
R
raspberrypi-kernel
项目概览
openeuler
/
raspberrypi-kernel
通知
13
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
raspberrypi-kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
62d83681
编写于
11月 06, 2009
作者:
D
David S. Miller
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'linux-2.6.33.y' of
git://git.kernel.org/pub/scm/linux/kernel/git/inaky/wimax
上级
230f9bb7
e7fec0bb
变更
26
展开全部
隐藏空白更改
内联
并排
Showing
26 changed file
with
2104 addition
and
618 deletion
+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
未找到文件。
drivers/net/wimax/i2400m/control.c
浏览文件 @
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
浏览文件 @
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
浏览文件 @
62d83681
此差异已折叠。
点击以展开。
drivers/net/wimax/i2400m/fw.c
浏览文件 @
62d83681
此差异已折叠。
点击以展开。
drivers/net/wimax/i2400m/i2400m-sdio.h
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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 @@ int i2400m_rx(struct i2400m *i2400m, struct sk_buff *skb)
EXPORT_SYMBOL_GPL
(
i2400m_rx
);
void
i2400m_unknown_barker
(
struct
i2400m
*
i2400m
,
const
void
*
buf
,
size_t
size
)
{
struct
device
*
dev
=
i2400m_dev
(
i2400m
);
char
prefix
[
64
];
const
__le32
*
barker
=
buf
;
dev_err
(
dev
,
"RX: HW BUG? unknown barker %08x, "
"dropping %zu bytes
\n
"
,
le32_to_cpu
(
*
barker
),
size
);
snprintf
(
prefix
,
sizeof
(
prefix
),
"%s %s: "
,
dev_driver_string
(
dev
),
dev_name
(
dev
));
if
(
size
>
64
)
{
print_hex_dump
(
KERN_ERR
,
prefix
,
DUMP_PREFIX_OFFSET
,
8
,
4
,
buf
,
64
,
0
);
printk
(
KERN_ERR
"%s... (only first 64 bytes "
"dumped)
\n
"
,
prefix
);
}
else
print_hex_dump
(
KERN_ERR
,
prefix
,
DUMP_PREFIX_OFFSET
,
8
,
4
,
buf
,
size
,
0
);
}
EXPORT_SYMBOL
(
i2400m_unknown_barker
);
/*
* Initialize the RX queue and infrastructure
*
...
...
@@ -1261,4 +1363,6 @@ void i2400m_rx_release(struct i2400m *i2400m)
kfree
(
i2400m
->
rx_roq
[
0
].
log
);
kfree
(
i2400m
->
rx_roq
);
}
/* at this point, nothing can be received... */
i2400m_report_hook_flush
(
i2400m
);
}
drivers/net/wimax/i2400m/sdio-fw.c
浏览文件 @
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
浏览文件 @
62d83681
...
...
@@ -53,6 +53,7 @@
* i2400ms_irq()
* i2400ms_rx()
* __i2400ms_rx_get_size()
* i2400m_is_boot_barker()
* i2400m_rx()
*
* i2400ms_rx_setup()
...
...
@@ -138,6 +139,11 @@ void i2400ms_rx(struct i2400ms *i2400ms)
ret
=
rx_size
;
goto
error_get_size
;
}
/*
* Hardware quirk: make sure to clear the INTR status register
* AFTER getting the data transfer size.
*/
sdio_writeb
(
func
,
1
,
I2400MS_INTR_CLEAR_ADDR
,
&
ret
);
ret
=
-
ENOMEM
;
skb
=
alloc_skb
(
rx_size
,
GFP_ATOMIC
);
...
...
@@ -153,25 +159,34 @@ void i2400ms_rx(struct i2400ms *i2400ms)
}
rmb
();
/* make sure we get boot_mode from dev_reset_handle */
if
(
i2400m
->
boot_mode
==
1
)
{
if
(
unlikely
(
i2400m
->
boot_mode
==
1
)
)
{
spin_lock
(
&
i2400m
->
rx_lock
);
i2400ms
->
bm_ack_size
=
rx_size
;
spin_unlock
(
&
i2400m
->
rx_lock
);
memcpy
(
i2400m
->
bm_ack_buf
,
skb
->
data
,
rx_size
);
wake_up
(
&
i2400ms
->
bm_wfa_wq
);
d
ev_err
(
dev
,
"RX: SDIO boot mode message
\n
"
);
d
_printf
(
5
,
dev
,
"RX: SDIO boot mode message
\n
"
);
kfree_skb
(
skb
);
}
else
if
(
unlikely
(
!
memcmp
(
skb
->
data
,
i2400m_NBOOT_BARKER
,
sizeof
(
i2400m_NBOOT_BARKER
))
||
!
memcmp
(
skb
->
data
,
i2400m_SBOOT_BARKER
,
sizeof
(
i2400m_SBOOT_BARKER
))))
{
ret
=
i2400m_dev_reset_handle
(
i2400m
);
goto
out
;
}
ret
=
-
EIO
;
if
(
unlikely
(
rx_size
<
sizeof
(
__le32
)))
{
dev_err
(
dev
,
"HW BUG? only %zu bytes received
\n
"
,
rx_size
);
goto
error_bad_size
;
}
if
(
likely
(
i2400m_is_d2h_barker
(
skb
->
data
)))
{
skb_put
(
skb
,
rx_size
);
i2400m_rx
(
i2400m
,
skb
);
}
else
if
(
unlikely
(
i2400m_is_boot_barker
(
i2400m
,
skb
->
data
,
rx_size
)))
{
ret
=
i2400m_dev_reset_handle
(
i2400m
,
"device rebooted"
);
dev_err
(
dev
,
"RX: SDIO reboot barker
\n
"
);
kfree_skb
(
skb
);
}
else
{
skb_put
(
skb
,
rx_size
);
i2400m_rx
(
i2400m
,
skb
);
i2400m_unknown_barker
(
i2400m
,
skb
->
data
,
rx_size
);
kfree_skb
(
skb
);
}
out:
d_fnend
(
7
,
dev
,
"(i2400ms %p) = void
\n
"
,
i2400ms
);
return
;
...
...
@@ -179,6 +194,7 @@ void i2400ms_rx(struct i2400ms *i2400ms)
kfree_skb
(
skb
);
error_alloc_skb:
error_get_size:
error_bad_size:
d_fnend
(
7
,
dev
,
"(i2400ms %p) = %d
\n
"
,
i2400ms
,
ret
);
return
;
}
...
...
@@ -209,7 +225,6 @@ void i2400ms_irq(struct sdio_func *func)
dev_err
(
dev
,
"RX: BUG? got IRQ but no interrupt ready?
\n
"
);
goto
error_no_irq
;
}
sdio_writeb
(
func
,
1
,
I2400MS_INTR_CLEAR_ADDR
,
&
ret
);
i2400ms_rx
(
i2400ms
);
error_no_irq:
d_fnend
(
6
,
dev
,
"(i2400ms %p) = void
\n
"
,
i2400ms
);
...
...
@@ -234,6 +249,13 @@ int i2400ms_rx_setup(struct i2400ms *i2400ms)
init_waitqueue_head
(
&
i2400ms
->
bm_wfa_wq
);
spin_lock
(
&
i2400m
->
rx_lock
);
i2400ms
->
bm_wait_result
=
-
EINPROGRESS
;
/*
* Before we are about to enable the RX interrupt, make sure
* bm_ack_size is cleared to -EINPROGRESS which indicates
* no RX interrupt happened yet or the previous interrupt
* has been handled, we are ready to take the new interrupt
*/
i2400ms
->
bm_ack_size
=
-
EINPROGRESS
;
spin_unlock
(
&
i2400m
->
rx_lock
);
sdio_claim_host
(
func
);
...
...
drivers/net/wimax/i2400m/sdio-tx.c
浏览文件 @
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
浏览文件 @
62d83681
...
...
@@ -43,18 +43,9 @@
* i2400m_release()
* free_netdev(net_dev)
*
* i2400ms_bus_reset() Called by i2400m
->bus
_reset
* i2400ms_bus_reset() Called by i2400m_reset
* __i2400ms_reset()
* __i2400ms_send_barker()
*
* i2400ms_bus_dev_start() Called by i2400m_dev_start() [who is
* i2400ms_tx_setup() called by i2400m_setup()]
* i2400ms_rx_setup()
*
* i2400ms_bus_dev_stop() Called by i2400m_dev_stop() [who is
* i2400ms_rx_release() is called by i2400m_release()]
* i2400ms_tx_release()
*
*/
#include <linux/debugfs.h>
...
...
@@ -71,6 +62,14 @@
static
int
ioe_timeout
=
2
;
module_param
(
ioe_timeout
,
int
,
0
);
static
char
i2400ms_debug_params
[
128
];
module_param_string
(
debug
,
i2400ms_debug_params
,
sizeof
(
i2400ms_debug_params
),
0644
);
MODULE_PARM_DESC
(
debug
,
"String of space-separated NAME:VALUE pairs, where NAMEs "
"are the different debug submodules and VALUE are the "
"initial debug value to set."
);
/* Our firmware file name list */
static
const
char
*
i2400ms_bus_fw_names
[]
=
{
#define I2400MS_FW_FILE_NAME "i2400m-fw-sdio-1.3.sbcf"
...
...
@@ -95,17 +94,24 @@ static const struct i2400m_poke_table i2400ms_pokes[] = {
* when we ask it to explicitly doing). Tries until a timeout is
* reached.
*
* The @maxtries argument indicates how many times (at most) it should
* be tried to enable the function. 0 means forever. This acts along
* with the timeout (ie: it'll stop trying as soon as the maximum
* number of tries is reached _or_ as soon as the timeout is reached).
*
* The reverse of this is...sdio_disable_function()
*
* Returns: 0 if the SDIO function was enabled, < 0 errno code on
* error (-ENODEV when it was unable to enable the function).
*/
static
int
i2400ms_enable_function
(
struct
sdio_func
*
func
)
int
i2400ms_enable_function
(
struct
i2400ms
*
i2400ms
,
unsigned
maxtries
)
{
struct
sdio_func
*
func
=
i2400ms
->
func
;
u64
timeout
;
int
err
;
struct
device
*
dev
=
&
func
->
dev
;
unsigned
tries
=
0
;
d_fnstart
(
3
,
dev
,
"(func %p)
\n
"
,
func
);
/* Setup timeout (FIXME: This needs to read the CIS table to
...
...
@@ -115,6 +121,14 @@ int i2400ms_enable_function(struct sdio_func *func)
err
=
-
ENODEV
;
while
(
err
!=
0
&&
time_before64
(
get_jiffies_64
(),
timeout
))
{
sdio_claim_host
(
func
);
/*
* There is a sillicon bug on the IWMC3200, where the
* IOE timeout will cause problems on Moorestown
* platforms (system hang). We explicitly overwrite
* func->enable_timeout here to work around the issue.
*/
if
(
i2400ms
->
iwmc3200
)
func
->
enable_timeout
=
IWMC3200_IOR_TIMEOUT
;
err
=
sdio_enable_func
(
func
);
if
(
0
==
err
)
{
sdio_release_host
(
func
);
...
...
@@ -122,8 +136,11 @@ int i2400ms_enable_function(struct sdio_func *func)
goto
function_enabled
;
}
d_printf
(
2
,
dev
,
"SDIO function failed to enable: %d
\n
"
,
err
);
sdio_disable_func
(
func
);
sdio_release_host
(
func
);
if
(
maxtries
>
0
&&
++
tries
>=
maxtries
)
{
err
=
-
ETIME
;
break
;
}
msleep
(
I2400MS_INIT_SLEEP_INTERVAL
);
}
/* If timed out, device is not there yet -- get -ENODEV so
...
...
@@ -140,46 +157,99 @@ int i2400ms_enable_function(struct sdio_func *func)
/*
* Setup driver resources needed to communicate with the device
* Setup minimal device communication infrastructure needed to at
* least be able to update the firmware.
*
* The fw needs some time to settle, and it was just uploaded,
* so give it a break first. I'd prefer to just wait for the device to
* send something, but seems the poking we do to enable SDIO stuff
* interferes with it, so just give it a break before starting...
* Note the ugly trick: if we are in the probe path
* (i2400ms->debugfs_dentry == NULL), we only retry function
* enablement one, to avoid racing with the iwmc3200 top controller.
*/
static
int
i2400ms_bus_
dev_start
(
struct
i2400m
*
i2400m
)
int
i2400ms_bus_
setup
(
struct
i2400m
*
i2400m
)
{
int
result
;
struct
i2400ms
*
i2400ms
=
container_of
(
i2400m
,
struct
i2400ms
,
i2400m
);
struct
i2400ms
*
i2400ms
=
container_of
(
i2400m
,
struct
i2400ms
,
i2400m
);
struct
device
*
dev
=
i2400m_dev
(
i2400m
);
struct
sdio_func
*
func
=
i2400ms
->
func
;
struct
device
*
dev
=
&
func
->
dev
;
int
retries
;
sdio_claim_host
(
func
);
result
=
sdio_set_block_size
(
func
,
I2400MS_BLK_SIZE
);
sdio_release_host
(
func
);
if
(
result
<
0
)
{
dev_err
(
dev
,
"Failed to set block size: %d
\n
"
,
result
);
goto
error_set_blk_size
;
}
if
(
i2400ms
->
iwmc3200
&&
i2400ms
->
debugfs_dentry
==
NULL
)
retries
=
1
;
else
retries
=
0
;
result
=
i2400ms_enable_function
(
i2400ms
,
retries
);
if
(
result
<
0
)
{
dev_err
(
dev
,
"Cannot enable SDIO function: %d
\n
"
,
result
);
goto
error_func_enable
;
}
d_fnstart
(
3
,
dev
,
"(i2400m %p)
\n
"
,
i2400m
);
msleep
(
200
);
result
=
i2400ms_tx_setup
(
i2400ms
);
if
(
result
<
0
)
goto
error_tx_setup
;
d_fnend
(
3
,
dev
,
"(i2400m %p) = %d
\n
"
,
i2400m
,
result
);
return
result
;
result
=
i2400ms_rx_setup
(
i2400ms
);
if
(
result
<
0
)
goto
error_rx_setup
;
return
0
;
error_
t
x_setup:
error_
r
x_setup:
i2400ms_tx_release
(
i2400ms
);
d_fnend
(
3
,
dev
,
"(i2400m %p) = void
\n
"
,
i2400m
);
error_tx_setup:
sdio_claim_host
(
func
);
sdio_disable_func
(
func
);
sdio_release_host
(
func
);
error_func_enable:
error_set_blk_size:
return
result
;
}
/*
* Tear down minimal device communication infrastructure needed to at
* least be able to update the firmware.
*/
static
void
i2400ms_bus_release
(
struct
i2400m
*
i2400m
)
{
struct
i2400ms
*
i2400ms
=
container_of
(
i2400m
,
struct
i2400ms
,
i2400m
);
struct
sdio_func
*
func
=
i2400ms
->
func
;
i2400ms_rx_release
(
i2400ms
);
i2400ms_tx_release
(
i2400ms
);
sdio_claim_host
(
func
);
sdio_disable_func
(
func
);
sdio_release_host
(
func
);
}
/*
* Setup driver resources needed to communicate with the device
*
* The fw needs some time to settle, and it was just uploaded,
* so give it a break first. I'd prefer to just wait for the device to
* send something, but seems the poking we do to enable SDIO stuff
* interferes with it, so just give it a break before starting...
*/
static
void
i2400ms_bus_dev_stop
(
struct
i2400m
*
i2400m
)
int
i2400ms_bus_dev_start
(
struct
i2400m
*
i2400m
)
{
struct
i2400ms
*
i2400ms
=
container_of
(
i2400m
,
struct
i2400ms
,
i2400m
);
struct
sdio_func
*
func
=
i2400ms
->
func
;
struct
device
*
dev
=
&
func
->
dev
;
d_fnstart
(
3
,
dev
,
"(i2400m %p)
\n
"
,
i2400m
);
i2400ms_tx_release
(
i2400ms
);
d_fnend
(
3
,
dev
,
"(i2400m %p) = void
\n
"
,
i2400m
);
msleep
(
200
);
d_fnend
(
3
,
dev
,
"(i2400m %p) = %d
\n
"
,
i2400m
,
0
);
return
0
;
}
...
...
@@ -233,18 +303,17 @@ int __i2400ms_send_barker(struct i2400ms *i2400ms,
* Warm reset:
*
* The device will be fully reset internally, but won't be
* disconnected from the
USB
bus (so no reenumeration will
* disconnected from the bus (so no reenumeration will
* happen). Firmware upload will be neccessary.
*
* The device will send a reboot barker in the notification endpoint
* that will trigger the driver to reinitialize the state
* automatically from notif.c:i2400m_notification_grok() into
* i2400m_dev_bootstrap_delayed().
* The device will send a reboot barker that will trigger the driver
* to reinitialize the state via __i2400m_dev_reset_handle.
*
* Cold and bus (USB) reset:
*
* Cold and bus reset:
*
* The device will be fully reset internally, disconnected from the
*
USB
bus an a reenumeration will happen. Firmware upload will be
* bus an a reenumeration will happen. Firmware upload will be
* neccessary. Thus, we don't do any locking or struct
* reinitialization, as we are going to be fully disconnected and
* reenumerated.
...
...
@@ -283,25 +352,13 @@ int i2400ms_bus_reset(struct i2400m *i2400m, enum i2400m_reset_type rt)
sizeof
(
i2400m_COLD_BOOT_BARKER
));
else
if
(
rt
==
I2400M_RT_BUS
)
{
do_bus_reset:
/* call netif_tx_disable() before sending IOE disable,
* so that all the tx from network layer are stopped
* while IOE is being reset. Make sure it is called
* only after register_netdev() was issued.
*/
if
(
i2400m
->
wimax_dev
.
net_dev
->
reg_state
==
NETREG_REGISTERED
)
netif_tx_disable
(
i2400m
->
wimax_dev
.
net_dev
);
i2400ms_rx_release
(
i2400ms
);
sdio_claim_host
(
i2400ms
->
func
);
sdio_disable_func
(
i2400ms
->
func
);
sdio_release_host
(
i2400ms
->
func
);
i2400ms_bus_release
(
i2400m
);
/* Wait for the device to settle */
msleep
(
40
);
result
=
i2400ms_enable_function
(
i2400ms
->
func
);
if
(
result
>=
0
)
i2400ms_rx_setup
(
i2400ms
);
result
=
i2400ms_bus_setup
(
i2400m
);
}
else
BUG
();
if
(
result
<
0
&&
rt
!=
I2400M_RT_BUS
)
{
...
...
@@ -350,7 +407,7 @@ int i2400ms_debugfs_add(struct i2400ms *i2400ms)
int
result
;
struct
dentry
*
dentry
=
i2400ms
->
i2400m
.
wimax_dev
.
debugfs_dentry
;
dentry
=
debugfs_create_dir
(
"i2400m-
usb
"
,
dentry
);
dentry
=
debugfs_create_dir
(
"i2400m-
sdio
"
,
dentry
);
result
=
PTR_ERR
(
dentry
);
if
(
IS_ERR
(
dentry
))
{
if
(
result
==
-
ENODEV
)
...
...
@@ -367,6 +424,7 @@ int i2400ms_debugfs_add(struct i2400ms *i2400ms)
error:
debugfs_remove_recursive
(
i2400ms
->
debugfs_dentry
);
i2400ms
->
debugfs_dentry
=
NULL
;
return
result
;
}
...
...
@@ -425,37 +483,30 @@ int i2400ms_probe(struct sdio_func *func,
i2400m
->
bus_tx_block_size
=
I2400MS_BLK_SIZE
;
i2400m
->
bus_pl_size_max
=
I2400MS_PL_SIZE_MAX
;
i2400m
->
bus_setup
=
i2400ms_bus_setup
;
i2400m
->
bus_dev_start
=
i2400ms_bus_dev_start
;
i2400m
->
bus_dev_stop
=
i2400ms_bus_dev_stop
;
i2400m
->
bus_dev_stop
=
NULL
;
i2400m
->
bus_release
=
i2400ms_bus_release
;
i2400m
->
bus_tx_kick
=
i2400ms_bus_tx_kick
;
i2400m
->
bus_reset
=
i2400ms_bus_reset
;
/* The iwmc3200-wimax sometimes requires the driver to try
* hard when we paint it into a corner. */
i2400m
->
bus_bm_retries
=
I
3200
_BOOT_RETRIES
;
i2400m
->
bus_bm_retries
=
I
2400M_SDIO
_BOOT_RETRIES
;
i2400m
->
bus_bm_cmd_send
=
i2400ms_bus_bm_cmd_send
;
i2400m
->
bus_bm_wait_for_ack
=
i2400ms_bus_bm_wait_for_ack
;
i2400m
->
bus_fw_names
=
i2400ms_bus_fw_names
;
i2400m
->
bus_bm_mac_addr_impaired
=
1
;
i2400m
->
bus_bm_pokes_table
=
&
i2400ms_pokes
[
0
];
sdio_claim_host
(
func
);
result
=
sdio_set_block_size
(
func
,
I2400MS_BLK_SIZE
);
sdio_release_host
(
func
);
if
(
result
<
0
)
{
dev_err
(
dev
,
"Failed to set block size: %d
\n
"
,
result
);
goto
error_set_blk_size
;
}
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
浏览文件 @
62d83681
...
...
@@ -310,7 +310,7 @@ size_t __i2400m_tx_tail_room(struct i2400m *i2400m)
size_t
tail_room
;
size_t
tx_in
;
if
(
unlikely
(
i2400m
->
tx_in
)
==
0
)
if
(
unlikely
(
i2400m
->
tx_in
==
0
)
)
return
I2400M_TX_BUF_SIZE
;
tx_in
=
i2400m
->
tx_in
%
I2400M_TX_BUF_SIZE
;
tail_room
=
I2400M_TX_BUF_SIZE
-
tx_in
;
...
...
@@ -642,6 +642,9 @@ int i2400m_tx(struct i2400m *i2400m, const void *buf, size_t buf_len,
* current one is out of payload slots or we have a singleton,
* close it and start a new one */
spin_lock_irqsave
(
&
i2400m
->
tx_lock
,
flags
);
result
=
-
ESHUTDOWN
;
if
(
i2400m
->
tx_buf
==
NULL
)
goto
error_tx_new
;
try_new:
if
(
unlikely
(
i2400m
->
tx_msg
==
NULL
))
i2400m_tx_new
(
i2400m
);
...
...
@@ -697,7 +700,10 @@ int i2400m_tx(struct i2400m *i2400m, const void *buf, size_t buf_len,
}
error_tx_new:
spin_unlock_irqrestore
(
&
i2400m
->
tx_lock
,
flags
);
i2400m
->
bus_tx_kick
(
i2400m
);
/* always kick, might free up space */
/* kick in most cases, except when the TX subsys is down, as
* it might free space */
if
(
likely
(
result
!=
-
ESHUTDOWN
))
i2400m
->
bus_tx_kick
(
i2400m
);
d_fnend
(
3
,
dev
,
"(i2400m %p skb %p [%zu bytes] pt %u) = %d
\n
"
,
i2400m
,
buf
,
buf_len
,
pl_type
,
result
);
return
result
;
...
...
@@ -740,6 +746,9 @@ struct i2400m_msg_hdr *i2400m_tx_msg_get(struct i2400m *i2400m,
d_fnstart
(
3
,
dev
,
"(i2400m %p bus_size %p)
\n
"
,
i2400m
,
bus_size
);
spin_lock_irqsave
(
&
i2400m
->
tx_lock
,
flags
);
tx_msg_moved
=
NULL
;
if
(
i2400m
->
tx_buf
==
NULL
)
goto
out_unlock
;
skip:
tx_msg_moved
=
NULL
;
if
(
i2400m
->
tx_in
==
i2400m
->
tx_out
)
{
/* Empty FIFO? */
...
...
@@ -829,6 +838,8 @@ void i2400m_tx_msg_sent(struct i2400m *i2400m)
d_fnstart
(
3
,
dev
,
"(i2400m %p)
\n
"
,
i2400m
);
spin_lock_irqsave
(
&
i2400m
->
tx_lock
,
flags
);
if
(
i2400m
->
tx_buf
==
NULL
)
goto
out_unlock
;
i2400m
->
tx_out
+=
i2400m
->
tx_msg_size
;
d_printf
(
2
,
dev
,
"TX: sent %zu b
\n
"
,
(
size_t
)
i2400m
->
tx_msg_size
);
i2400m
->
tx_msg_size
=
0
;
...
...
@@ -837,6 +848,7 @@ void i2400m_tx_msg_sent(struct i2400m *i2400m)
n
=
i2400m
->
tx_out
/
I2400M_TX_BUF_SIZE
;
i2400m
->
tx_out
%=
I2400M_TX_BUF_SIZE
;
i2400m
->
tx_in
-=
n
*
I2400M_TX_BUF_SIZE
;
out_unlock:
spin_unlock_irqrestore
(
&
i2400m
->
tx_lock
,
flags
);
d_fnend
(
3
,
dev
,
"(i2400m %p) = void
\n
"
,
i2400m
);
}
...
...
@@ -876,5 +888,9 @@ int i2400m_tx_setup(struct i2400m *i2400m)
*/
void
i2400m_tx_release
(
struct
i2400m
*
i2400m
)
{
unsigned
long
flags
;
spin_lock_irqsave
(
&
i2400m
->
tx_lock
,
flags
);
kfree
(
i2400m
->
tx_buf
);
i2400m
->
tx_buf
=
NULL
;
spin_unlock_irqrestore
(
&
i2400m
->
tx_lock
,
flags
);
}
drivers/net/wimax/i2400m/usb-fw.c
浏览文件 @
62d83681
...
...
@@ -99,10 +99,10 @@ ssize_t i2400mu_tx_bulk_out(struct i2400mu *i2400mu, void *buf, size_t buf_size)
dev_err
(
dev
,
"BM-CMD: can't get autopm: %d
\n
"
,
result
);
do_autopm
=
0
;
}
epd
=
usb_get_epd
(
i2400mu
->
usb_iface
,
I2400MU_EP_BULK_OUT
);
epd
=
usb_get_epd
(
i2400mu
->
usb_iface
,
i2400mu
->
endpoint_cfg
.
bulk_out
);
pipe
=
usb_sndbulkpipe
(
i2400mu
->
usb_dev
,
epd
->
bEndpointAddress
);
retry:
result
=
usb_bulk_msg
(
i2400mu
->
usb_dev
,
pipe
,
buf
,
buf_size
,
&
len
,
HZ
);
result
=
usb_bulk_msg
(
i2400mu
->
usb_dev
,
pipe
,
buf
,
buf_size
,
&
len
,
200
);
switch
(
result
)
{
case
0
:
if
(
len
!=
buf_size
)
{
...
...
@@ -113,6 +113,28 @@ ssize_t i2400mu_tx_bulk_out(struct i2400mu *i2400mu, void *buf, size_t buf_size)
}
result
=
len
;
break
;
case
-
EPIPE
:
/*
* Stall -- maybe the device is choking with our
* requests. Clear it and give it some time. If they
* happen to often, it might be another symptom, so we
* reset.
*
* No error handling for usb_clear_halt(0; if it
* works, the retry works; if it fails, this switch
* does the error handling for us.
*/
if
(
edc_inc
(
&
i2400mu
->
urb_edc
,
10
*
EDC_MAX_ERRORS
,
EDC_ERROR_TIMEFRAME
))
{
dev_err
(
dev
,
"BM-CMD: too many stalls in "
"URB; resetting device
\n
"
);
usb_queue_reset_device
(
i2400mu
->
usb_iface
);
/* fallthrough */
}
else
{
usb_clear_halt
(
i2400mu
->
usb_dev
,
pipe
);
msleep
(
10
);
/* give the device some time */
goto
retry
;
}
case
-
EINVAL
:
/* while removing driver */
case
-
ENODEV
:
/* dev disconnect ... */
case
-
ENOENT
:
/* just ignore it */
...
...
@@ -135,7 +157,6 @@ ssize_t i2400mu_tx_bulk_out(struct i2400mu *i2400mu, void *buf, size_t buf_size)
result
);
goto
retry
;
}
result
=
len
;
if
(
do_autopm
)
usb_autopm_put_interface
(
i2400mu
->
usb_iface
);
return
result
;
...
...
@@ -172,7 +193,8 @@ ssize_t i2400mu_bus_bm_cmd_send(struct i2400m *i2400m,
result
=
-
E2BIG
;
if
(
cmd_size
>
I2400M_BM_CMD_BUF_SIZE
)
goto
error_too_big
;
memcpy
(
i2400m
->
bm_cmd_buf
,
_cmd
,
cmd_size
);
if
(
_cmd
!=
i2400m
->
bm_cmd_buf
)
memmove
(
i2400m
->
bm_cmd_buf
,
_cmd
,
cmd_size
);
cmd
=
i2400m
->
bm_cmd_buf
;
if
(
cmd_size_a
>
cmd_size
)
/* Zero pad space */
memset
(
i2400m
->
bm_cmd_buf
+
cmd_size
,
0
,
cmd_size_a
-
cmd_size
);
...
...
@@ -226,7 +248,8 @@ int i2400mu_notif_submit(struct i2400mu *i2400mu, struct urb *urb,
struct
usb_endpoint_descriptor
*
epd
;
int
pipe
;
epd
=
usb_get_epd
(
i2400mu
->
usb_iface
,
I2400MU_EP_NOTIFICATION
);
epd
=
usb_get_epd
(
i2400mu
->
usb_iface
,
i2400mu
->
endpoint_cfg
.
notification
);
pipe
=
usb_rcvintpipe
(
i2400mu
->
usb_dev
,
epd
->
bEndpointAddress
);
usb_fill_int_urb
(
urb
,
i2400mu
->
usb_dev
,
pipe
,
i2400m
->
bm_ack_buf
,
I2400M_BM_ACK_BUF_SIZE
,
...
...
@@ -328,8 +351,8 @@ ssize_t i2400mu_bus_bm_wait_for_ack(struct i2400m *i2400m,
out:
if
(
do_autopm
)
usb_autopm_put_interface
(
i2400mu
->
usb_iface
);
d_fnend
(
8
,
dev
,
"(i2400m %p ack %p size %zu) = %
z
d
\n
"
,
i2400m
,
ack
,
ack_size
,
result
);
d_fnend
(
8
,
dev
,
"(i2400m %p ack %p size %zu) = %
l
d
\n
"
,
i2400m
,
ack
,
ack_size
,
(
long
)
result
);
return
result
;
error_exceeded:
...
...
drivers/net/wimax/i2400m/usb-notif.c
浏览文件 @
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
浏览文件 @
62d83681
...
...
@@ -204,7 +204,7 @@ struct sk_buff *i2400mu_rx(struct i2400mu *i2400mu, struct sk_buff *rx_skb)
dev_err
(
dev
,
"RX: can't get autopm: %d
\n
"
,
result
);
do_autopm
=
0
;
}
epd
=
usb_get_epd
(
i2400mu
->
usb_iface
,
I2400MU_EP_BULK_IN
);
epd
=
usb_get_epd
(
i2400mu
->
usb_iface
,
i2400mu
->
endpoint_cfg
.
bulk_in
);
usb_pipe
=
usb_rcvbulkpipe
(
i2400mu
->
usb_dev
,
epd
->
bEndpointAddress
);
retry:
rx_size
=
skb_end_pointer
(
rx_skb
)
-
rx_skb
->
data
-
rx_skb
->
len
;
...
...
@@ -214,7 +214,7 @@ struct sk_buff *i2400mu_rx(struct i2400mu *i2400mu, struct sk_buff *rx_skb)
}
result
=
usb_bulk_msg
(
i2400mu
->
usb_dev
,
usb_pipe
,
rx_skb
->
data
+
rx_skb
->
len
,
rx_size
,
&
read_size
,
HZ
);
rx_size
,
&
read_size
,
200
);
usb_mark_last_busy
(
i2400mu
->
usb_dev
);
switch
(
result
)
{
case
0
:
...
...
@@ -222,6 +222,26 @@ struct sk_buff *i2400mu_rx(struct i2400mu *i2400mu, struct sk_buff *rx_skb)
goto
retry
;
/* ZLP, just resubmit */
skb_put
(
rx_skb
,
read_size
);
break
;
case
-
EPIPE
:
/*
* Stall -- maybe the device is choking with our
* requests. Clear it and give it some time. If they
* happen to often, it might be another symptom, so we
* reset.
*
* No error handling for usb_clear_halt(0; if it
* works, the retry works; if it fails, this switch
* does the error handling for us.
*/
if
(
edc_inc
(
&
i2400mu
->
urb_edc
,
10
*
EDC_MAX_ERRORS
,
EDC_ERROR_TIMEFRAME
))
{
dev_err
(
dev
,
"BM-CMD: too many stalls in "
"URB; resetting device
\n
"
);
goto
do_reset
;
}
usb_clear_halt
(
i2400mu
->
usb_dev
,
usb_pipe
);
msleep
(
10
);
/* give the device some time */
goto
retry
;
case
-
EINVAL
:
/* while removing driver */
case
-
ENODEV
:
/* dev disconnect ... */
case
-
ENOENT
:
/* just ignore it */
...
...
@@ -283,6 +303,7 @@ struct sk_buff *i2400mu_rx(struct i2400mu *i2400mu, struct sk_buff *rx_skb)
error_reset:
dev_err
(
dev
,
"RX: maximum errors in URB exceeded; "
"resetting device
\n
"
);
do_reset:
usb_queue_reset_device
(
i2400mu
->
usb_iface
);
rx_skb
=
ERR_PTR
(
result
);
goto
out
;
...
...
@@ -316,10 +337,15 @@ int i2400mu_rxd(void *_i2400mu)
size_t
pending
;
int
rx_size
;
struct
sk_buff
*
rx_skb
;
unsigned
long
flags
;
d_fnstart
(
4
,
dev
,
"(i2400mu %p)
\n
"
,
i2400mu
);
spin_lock_irqsave
(
&
i2400m
->
rx_lock
,
flags
);
BUG_ON
(
i2400mu
->
rx_kthread
!=
NULL
);
i2400mu
->
rx_kthread
=
current
;
spin_unlock_irqrestore
(
&
i2400m
->
rx_lock
,
flags
);
while
(
1
)
{
d_printf
(
2
,
dev
,
"
T
X: waiting for messages
\n
"
);
d_printf
(
2
,
dev
,
"
R
X: waiting for messages
\n
"
);
pending
=
0
;
wait_event_interruptible
(
i2400mu
->
rx_wq
,
...
...
@@ -367,6 +393,9 @@ int i2400mu_rxd(void *_i2400mu)
}
result
=
0
;
out:
spin_lock_irqsave
(
&
i2400m
->
rx_lock
,
flags
);
i2400mu
->
rx_kthread
=
NULL
;
spin_unlock_irqrestore
(
&
i2400m
->
rx_lock
,
flags
);
d_fnend
(
4
,
dev
,
"(i2400mu %p) = %d
\n
"
,
i2400mu
,
result
);
return
result
;
...
...
@@ -403,18 +432,33 @@ int i2400mu_rx_setup(struct i2400mu *i2400mu)
struct
i2400m
*
i2400m
=
&
i2400mu
->
i2400m
;
struct
device
*
dev
=
&
i2400mu
->
usb_iface
->
dev
;
struct
wimax_dev
*
wimax_dev
=
&
i2400m
->
wimax_dev
;
struct
task_struct
*
kthread
;
i2400mu
->
rx_kthread
=
kthread_run
(
i2400mu_rxd
,
i2400mu
,
"%s-rx"
,
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
浏览文件 @
62d83681
...
...
@@ -101,11 +101,11 @@ int i2400mu_tx(struct i2400mu *i2400mu, struct i2400m_msg_hdr *tx_msg,
dev_err
(
dev
,
"TX: can't get autopm: %d
\n
"
,
result
);
do_autopm
=
0
;
}
epd
=
usb_get_epd
(
i2400mu
->
usb_iface
,
I2400MU_EP_BULK_OUT
);
epd
=
usb_get_epd
(
i2400mu
->
usb_iface
,
i2400mu
->
endpoint_cfg
.
bulk_out
);
usb_pipe
=
usb_sndbulkpipe
(
i2400mu
->
usb_dev
,
epd
->
bEndpointAddress
);
retry:
result
=
usb_bulk_msg
(
i2400mu
->
usb_dev
,
usb_pipe
,
tx_msg
,
tx_msg_size
,
&
sent_size
,
HZ
);
tx_msg
,
tx_msg_size
,
&
sent_size
,
200
);
usb_mark_last_busy
(
i2400mu
->
usb_dev
);
switch
(
result
)
{
case
0
:
...
...
@@ -115,6 +115,28 @@ int i2400mu_tx(struct i2400mu *i2400mu, struct i2400m_msg_hdr *tx_msg,
result
=
-
EIO
;
}
break
;
case
-
EPIPE
:
/*
* Stall -- maybe the device is choking with our
* requests. Clear it and give it some time. If they
* happen to often, it might be another symptom, so we
* reset.
*
* No error handling for usb_clear_halt(0; if it
* works, the retry works; if it fails, this switch
* does the error handling for us.
*/
if
(
edc_inc
(
&
i2400mu
->
urb_edc
,
10
*
EDC_MAX_ERRORS
,
EDC_ERROR_TIMEFRAME
))
{
dev_err
(
dev
,
"BM-CMD: too many stalls in "
"URB; resetting device
\n
"
);
usb_queue_reset_device
(
i2400mu
->
usb_iface
);
/* fallthrough */
}
else
{
usb_clear_halt
(
i2400mu
->
usb_dev
,
usb_pipe
);
msleep
(
10
);
/* give the device some time */
goto
retry
;
}
case
-
EINVAL
:
/* while removing driver */
case
-
ENODEV
:
/* dev disconnect ... */
case
-
ENOENT
:
/* just ignore it */
...
...
@@ -161,9 +183,15 @@ int i2400mu_txd(void *_i2400mu)
struct
device
*
dev
=
&
i2400mu
->
usb_iface
->
dev
;
struct
i2400m_msg_hdr
*
tx_msg
;
size_t
tx_msg_size
;
unsigned
long
flags
;
d_fnstart
(
4
,
dev
,
"(i2400mu %p)
\n
"
,
i2400mu
);
spin_lock_irqsave
(
&
i2400m
->
tx_lock
,
flags
);
BUG_ON
(
i2400mu
->
tx_kthread
!=
NULL
);
i2400mu
->
tx_kthread
=
current
;
spin_unlock_irqrestore
(
&
i2400m
->
tx_lock
,
flags
);
while
(
1
)
{
d_printf
(
2
,
dev
,
"TX: waiting for messages
\n
"
);
tx_msg
=
NULL
;
...
...
@@ -183,6 +211,11 @@ int i2400mu_txd(void *_i2400mu)
if
(
result
<
0
)
break
;
}
spin_lock_irqsave
(
&
i2400m
->
tx_lock
,
flags
);
i2400mu
->
tx_kthread
=
NULL
;
spin_unlock_irqrestore
(
&
i2400m
->
tx_lock
,
flags
);
d_fnend
(
4
,
dev
,
"(i2400mu %p) = %d
\n
"
,
i2400mu
,
result
);
return
result
;
}
...
...
@@ -213,11 +246,13 @@ int i2400mu_tx_setup(struct i2400mu *i2400mu)
struct
i2400m
*
i2400m
=
&
i2400mu
->
i2400m
;
struct
device
*
dev
=
&
i2400mu
->
usb_iface
->
dev
;
struct
wimax_dev
*
wimax_dev
=
&
i2400m
->
wimax_dev
;
struct
task_struct
*
kthread
;
i2400mu
->
tx_kthread
=
kthread_run
(
i2400mu_txd
,
i2400mu
,
"%s-tx"
,
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
浏览文件 @
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 @@ int i2400mu_bus_reset(struct i2400m *i2400m, enum i2400m_reset_type rt)
case
-
ENODEV
:
case
-
ENOENT
:
case
-
ESHUTDOWN
:
result
=
rt
==
I2400M_RT_WARM
?
-
ENODEV
:
0
;
result
=
0
;
break
;
/* We assume the device is disconnected */
default:
dev_err
(
dev
,
"USB reset failed (%d), giving up!
\n
"
,
...
...
@@ -261,10 +319,17 @@ int i2400mu_bus_reset(struct i2400m *i2400m, enum i2400m_reset_type rt)
if
(
result
<
0
&&
result
!=
-
EINVAL
/* device is gone */
&&
rt
!=
I2400M_RT_BUS
)
{
/*
* Things failed -- resort to lower level reset, that
* we queue in another context; the reason for this is
* that the pre and post reset functionality requires
* the i2400m->init_mutex; RT_WARM and RT_COLD can
* come from areas where i2400m->init_mutex is taken.
*/
dev_err
(
dev
,
"%s reset failed (%d); trying USB reset
\n
"
,
rt
==
I2400M_RT_WARM
?
"warm"
:
"cold"
,
result
);
rt
=
I2400M_RT_BUS
;
goto
do_bus_reset
;
usb_queue_reset_device
(
i2400mu
->
usb_iface
)
;
result
=
-
ENODEV
;
}
d_fnend
(
3
,
dev
,
"(i2400m %p rt %u) = %d
\n
"
,
i2400m
,
rt
,
result
);
return
result
;
...
...
@@ -402,20 +467,33 @@ int i2400mu_probe(struct usb_interface *iface,
i2400m
->
bus_tx_block_size
=
I2400MU_BLK_SIZE
;
i2400m
->
bus_pl_size_max
=
I2400MU_PL_SIZE_MAX
;
i2400m
->
bus_setup
=
NULL
;
i2400m
->
bus_dev_start
=
i2400mu_bus_dev_start
;
i2400m
->
bus_dev_stop
=
i2400mu_bus_dev_stop
;
i2400m
->
bus_release
=
NULL
;
i2400m
->
bus_tx_kick
=
i2400mu_bus_tx_kick
;
i2400m
->
bus_reset
=
i2400mu_bus_reset
;
i2400m
->
bus_bm_retries
=
I2400M_BOOT_RETRIES
;
i2400m
->
bus_bm_retries
=
I2400M_
USB_
BOOT_RETRIES
;
i2400m
->
bus_bm_cmd_send
=
i2400mu_bus_bm_cmd_send
;
i2400m
->
bus_bm_wait_for_ack
=
i2400mu_bus_bm_wait_for_ack
;
i2400m
->
bus_fw_names
=
i2400mu_bus_fw_names
;
i2400m
->
bus_bm_mac_addr_impaired
=
0
;
if
(
id
->
idProduct
==
USB_DEVICE_ID_I6050
)
{
i2400m
->
bus_fw_names
=
i2400mu_bus_fw_names_6050
;
i2400mu
->
endpoint_cfg
.
bulk_out
=
0
;
i2400mu
->
endpoint_cfg
.
notification
=
3
;
i2400mu
->
endpoint_cfg
.
reset_cold
=
2
;
i2400mu
->
endpoint_cfg
.
bulk_in
=
1
;
}
else
{
i2400m
->
bus_fw_names
=
i2400mu_bus_fw_names_5x50
;
i2400mu
->
endpoint_cfg
.
bulk_out
=
0
;
i2400mu
->
endpoint_cfg
.
notification
=
1
;
i2400mu
->
endpoint_cfg
.
reset_cold
=
2
;
i2400mu
->
endpoint_cfg
.
bulk_in
=
3
;
}
#ifdef CONFIG_PM
iface
->
needs_remote_wakeup
=
1
;
/* autosuspend (15s delay) */
device_init_wakeup
(
dev
,
1
);
usb_autopm_enable
(
i2400mu
->
usb_iface
);
usb_dev
->
autosuspend_delay
=
15
*
HZ
;
usb_dev
->
autosuspend_disabled
=
0
;
#endif
...
...
@@ -483,7 +561,10 @@ void i2400mu_disconnect(struct usb_interface *iface)
* So at the end, the three cases require common handling.
*
* If at the time of this call the device's firmware is not loaded,
* nothing has to be done.
* nothing has to be done. Note we can be "loose" about not reading
* i2400m->updown under i2400m->init_mutex. If it happens to change
* inmediately, other parts of the call flow will fail and effectively
* catch it.
*
* If the firmware is loaded, we need to:
*
...
...
@@ -522,6 +603,7 @@ int i2400mu_suspend(struct usb_interface *iface, pm_message_t pm_msg)
#endif
d_fnstart
(
3
,
dev
,
"(iface %p pm_msg %u)
\n
"
,
iface
,
pm_msg
.
event
);
rmb
();
/* see i2400m->updown's documentation */
if
(
i2400m
->
updown
==
0
)
goto
no_firmware
;
if
(
i2400m
->
state
==
I2400M_SS_DATA_PATH_CONNECTED
&&
is_autosuspend
)
{
...
...
@@ -575,6 +657,7 @@ int i2400mu_resume(struct usb_interface *iface)
struct
i2400m
*
i2400m
=
&
i2400mu
->
i2400m
;
d_fnstart
(
3
,
dev
,
"(iface %p)
\n
"
,
iface
);
rmb
();
/* see i2400m->updown's documentation */
if
(
i2400m
->
updown
==
0
)
{
d_printf
(
1
,
dev
,
"fw was down, no resume neeed
\n
"
);
goto
out
;
...
...
@@ -590,8 +673,55 @@ int i2400mu_resume(struct usb_interface *iface)
}
static
int
i2400mu_reset_resume
(
struct
usb_interface
*
iface
)
{
int
result
;
struct
device
*
dev
=
&
iface
->
dev
;
struct
i2400mu
*
i2400mu
=
usb_get_intfdata
(
iface
);
struct
i2400m
*
i2400m
=
&
i2400mu
->
i2400m
;
d_fnstart
(
3
,
dev
,
"(iface %p)
\n
"
,
iface
);
result
=
i2400m_dev_reset_handle
(
i2400m
,
"device reset on resume"
);
d_fnend
(
3
,
dev
,
"(iface %p) = %d
\n
"
,
iface
,
result
);
return
result
<
0
?
result
:
0
;
}
/*
* Another driver or user space is triggering a reset on the device
* which contains the interface passed as an argument. Cease IO and
* save any device state you need to restore.
*
* If you need to allocate memory here, use GFP_NOIO or GFP_ATOMIC, if
* you are in atomic context.
*/
static
int
i2400mu_pre_reset
(
struct
usb_interface
*
iface
)
{
struct
i2400mu
*
i2400mu
=
usb_get_intfdata
(
iface
);
return
i2400m_pre_reset
(
&
i2400mu
->
i2400m
);
}
/*
* The reset has completed. Restore any saved device state and begin
* using the device again.
*
* If you need to allocate memory here, use GFP_NOIO or GFP_ATOMIC, if
* you are in atomic context.
*/
static
int
i2400mu_post_reset
(
struct
usb_interface
*
iface
)
{
struct
i2400mu
*
i2400mu
=
usb_get_intfdata
(
iface
);
return
i2400m_post_reset
(
&
i2400mu
->
i2400m
);
}
static
struct
usb_device_id
i2400mu_id_table
[]
=
{
{
USB_DEVICE
(
0x8086
,
USB_DEVICE_ID_I6050
)
},
{
USB_DEVICE
(
0x8086
,
0x0181
)
},
{
USB_DEVICE
(
0x8086
,
0x1403
)
},
{
USB_DEVICE
(
0x8086
,
0x1405
)
},
...
...
@@ -609,8 +739,11 @@ struct usb_driver i2400mu_driver = {
.
name
=
KBUILD_MODNAME
,
.
suspend
=
i2400mu_suspend
,
.
resume
=
i2400mu_resume
,
.
reset_resume
=
i2400mu_reset_resume
,
.
probe
=
i2400mu_probe
,
.
disconnect
=
i2400mu_disconnect
,
.
pre_reset
=
i2400mu_pre_reset
,
.
post_reset
=
i2400mu_post_reset
,
.
id_table
=
i2400mu_id_table
,
.
supports_autosuspend
=
1
,
};
...
...
@@ -618,6 +751,8 @@ struct usb_driver i2400mu_driver = {
static
int
__init
i2400mu_driver_init
(
void
)
{
d_parse_params
(
D_LEVEL
,
D_LEVEL_SIZE
,
i2400mu_debug_params
,
"i2400m_usb.debug"
);
return
usb_register
(
&
i2400mu_driver
);
}
module_init
(
i2400mu_driver_init
);
...
...
@@ -632,7 +767,7 @@ void __exit i2400mu_driver_exit(void)
module_exit
(
i2400mu_driver_exit
);
MODULE_AUTHOR
(
"Intel Corporation <linux-wimax@intel.com>"
);
MODULE_DESCRIPTION
(
"Intel 2400M WiMAX networking for USB"
);
MODULE_DESCRIPTION
(
"Driver for USB based Intel Wireless WiMAX Connection 2400M "
"(5x50 & 6050)"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_FIRMWARE
(
I2400MU_FW_FILE_NAME_v1_4
);
MODULE_FIRMWARE
(
I2400MU_FW_FILE_NAME_v1_3
);
include/linux/mmc/sdio_ids.h
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
);
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录