Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
cloud-kernel
提交
8a75e7d6
cloud-kernel
项目概览
openanolis
/
cloud-kernel
1 年多 前同步成功
通知
161
Star
36
Fork
7
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
10
列表
看板
标记
里程碑
合并请求
2
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
cloud-kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
10
Issue
10
列表
看板
标记
里程碑
合并请求
2
合并请求
2
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
8a75e7d6
编写于
5月 25, 2005
作者:
提交者:
Jeff Garzik
5月 25, 2005
浏览文件
操作
浏览文件
下载
差异文件
Automatic merge of /spare/repo/netdev-2.6 branch qeth
上级
f5a702b2
05e08a2a
变更
14
隐藏空白更改
内联
并排
Showing
14 changed file
with
914 addition
and
901 deletion
+914
-901
drivers/s390/net/Makefile
drivers/s390/net/Makefile
+2
-1
drivers/s390/net/ctcdbug.h
drivers/s390/net/ctcdbug.h
+8
-4
drivers/s390/net/ctcmain.c
drivers/s390/net/ctcmain.c
+206
-410
drivers/s390/net/ctcmain.h
drivers/s390/net/ctcmain.h
+276
-0
drivers/s390/net/ctctty.c
drivers/s390/net/ctctty.c
+2
-3
drivers/s390/net/cu3088.c
drivers/s390/net/cu3088.c
+3
-1
drivers/s390/net/cu3088.h
drivers/s390/net/cu3088.h
+3
-0
drivers/s390/net/iucv.c
drivers/s390/net/iucv.c
+5
-5
drivers/s390/net/lcs.c
drivers/s390/net/lcs.c
+17
-16
drivers/s390/net/qeth.h
drivers/s390/net/qeth.h
+28
-7
drivers/s390/net/qeth_eddp.c
drivers/s390/net/qeth_eddp.c
+20
-31
drivers/s390/net/qeth_main.c
drivers/s390/net/qeth_main.c
+213
-103
drivers/s390/net/qeth_tso.c
drivers/s390/net/qeth_tso.c
+0
-285
drivers/s390/net/qeth_tso.h
drivers/s390/net/qeth_tso.h
+131
-35
未找到文件。
drivers/s390/net/Makefile
浏览文件 @
8a75e7d6
...
...
@@ -9,6 +9,7 @@ obj-$(CONFIG_NETIUCV) += netiucv.o fsm.o
obj-$(CONFIG_SMSGIUCV)
+=
smsgiucv.o
obj-$(CONFIG_CTC)
+=
ctc.o fsm.o cu3088.o
obj-$(CONFIG_LCS)
+=
lcs.o cu3088.o
qeth-y
:=
qeth_main.o qeth_mpc.o qeth_sys.o qeth_eddp.o qeth_tso.o
obj-$(CONFIG_CLAW)
+=
claw.o cu3088.o
qeth-y
:=
qeth_main.o qeth_mpc.o qeth_sys.o qeth_eddp.o
qeth-$(CONFIG_PROC_FS)
+=
qeth_proc.o
obj-$(CONFIG_QETH)
+=
qeth.o
drivers/s390/net/ctcdbug.h
浏览文件 @
8a75e7d6
/*
*
* linux/drivers/s390/net/ctcdbug.h ($Revision: 1.
4
$)
* linux/drivers/s390/net/ctcdbug.h ($Revision: 1.
5
$)
*
* CTC / ESCON network driver - s390 dbf exploit.
*
...
...
@@ -9,7 +9,7 @@
* Author(s): Original Code written by
* Peter Tiedemann (ptiedem@de.ibm.com)
*
* $Revision: 1.
4 $ $Date: 2004/10/15 09:26:58
$
* $Revision: 1.
5 $ $Date: 2005/02/27 19:46:44
$
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
...
...
@@ -25,9 +25,11 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _CTCDBUG_H_
#define _CTCDBUG_H_
#include <asm/debug.h>
#include "ctcmain.h"
/**
* Debug Facility stuff
*/
...
...
@@ -41,7 +43,7 @@
#define CTC_DBF_DATA_LEN 128
#define CTC_DBF_DATA_INDEX 3
#define CTC_DBF_DATA_NR_AREAS 1
#define CTC_DBF_DATA_LEVEL
2
#define CTC_DBF_DATA_LEVEL
3
#define CTC_DBF_TRACE_NAME "ctc_trace"
#define CTC_DBF_TRACE_LEN 16
...
...
@@ -121,3 +123,5 @@ hex_dump(unsigned char *buf, size_t len)
printk
(
"
\n
"
);
}
#endif
drivers/s390/net/ctcmain.c
浏览文件 @
8a75e7d6
/*
* $Id: ctcmain.c,v 1.7
2 2005/03/17 10:51:52 ptiedem
Exp $
* $Id: ctcmain.c,v 1.7
4 2005/03/24 09:04:17 mschwide
Exp $
*
* CTC / ESCON network driver
*
...
...
@@ -37,12 +37,11 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* RELEASE-TAG: CTC/ESCON network driver $Revision: 1.7
2
$
* RELEASE-TAG: CTC/ESCON network driver $Revision: 1.7
4
$
*
*/
#undef DEBUG
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
...
...
@@ -74,288 +73,13 @@
#include "ctctty.h"
#include "fsm.h"
#include "cu3088.h"
#include "ctcdbug.h"
#include "ctcmain.h"
MODULE_AUTHOR
(
"(C) 2000 IBM Corp. by Fritz Elfert (felfert@millenux.com)"
);
MODULE_DESCRIPTION
(
"Linux for S/390 CTC/Escon Driver"
);
MODULE_LICENSE
(
"GPL"
);
/**
* CCW commands, used in this driver.
*/
#define CCW_CMD_WRITE 0x01
#define CCW_CMD_READ 0x02
#define CCW_CMD_SET_EXTENDED 0xc3
#define CCW_CMD_PREPARE 0xe3
#define CTC_PROTO_S390 0
#define CTC_PROTO_LINUX 1
#define CTC_PROTO_LINUX_TTY 2
#define CTC_PROTO_OS390 3
#define CTC_PROTO_MAX 3
#define CTC_BUFSIZE_LIMIT 65535
#define CTC_BUFSIZE_DEFAULT 32768
#define CTC_TIMEOUT_5SEC 5000
#define CTC_INITIAL_BLOCKLEN 2
#define READ 0
#define WRITE 1
#define CTC_ID_SIZE BUS_ID_SIZE+3
struct
ctc_profile
{
unsigned
long
maxmulti
;
unsigned
long
maxcqueue
;
unsigned
long
doios_single
;
unsigned
long
doios_multi
;
unsigned
long
txlen
;
unsigned
long
tx_time
;
struct
timespec
send_stamp
;
};
/**
* Definition of one channel
*/
struct
channel
{
/**
* Pointer to next channel in list.
*/
struct
channel
*
next
;
char
id
[
CTC_ID_SIZE
];
struct
ccw_device
*
cdev
;
/**
* Type of this channel.
* CTC/A or Escon for valid channels.
*/
enum
channel_types
type
;
/**
* Misc. flags. See CHANNEL_FLAGS_... below
*/
__u32
flags
;
/**
* The protocol of this channel
*/
__u16
protocol
;
/**
* I/O and irq related stuff
*/
struct
ccw1
*
ccw
;
struct
irb
*
irb
;
/**
* RX/TX buffer size
*/
int
max_bufsize
;
/**
* Transmit/Receive buffer.
*/
struct
sk_buff
*
trans_skb
;
/**
* Universal I/O queue.
*/
struct
sk_buff_head
io_queue
;
/**
* TX queue for collecting skb's during busy.
*/
struct
sk_buff_head
collect_queue
;
/**
* Amount of data in collect_queue.
*/
int
collect_len
;
/**
* spinlock for collect_queue and collect_len
*/
spinlock_t
collect_lock
;
/**
* Timer for detecting unresposive
* I/O operations.
*/
fsm_timer
timer
;
/**
* Retry counter for misc. operations.
*/
int
retry
;
/**
* The finite state machine of this channel
*/
fsm_instance
*
fsm
;
/**
* The corresponding net_device this channel
* belongs to.
*/
struct
net_device
*
netdev
;
struct
ctc_profile
prof
;
unsigned
char
*
trans_skb_data
;
__u16
logflags
;
};
#define CHANNEL_FLAGS_READ 0
#define CHANNEL_FLAGS_WRITE 1
#define CHANNEL_FLAGS_INUSE 2
#define CHANNEL_FLAGS_BUFSIZE_CHANGED 4
#define CHANNEL_FLAGS_FAILED 8
#define CHANNEL_FLAGS_WAITIRQ 16
#define CHANNEL_FLAGS_RWMASK 1
#define CHANNEL_DIRECTION(f) (f & CHANNEL_FLAGS_RWMASK)
#define LOG_FLAG_ILLEGALPKT 1
#define LOG_FLAG_ILLEGALSIZE 2
#define LOG_FLAG_OVERRUN 4
#define LOG_FLAG_NOMEM 8
#define CTC_LOGLEVEL_INFO 1
#define CTC_LOGLEVEL_NOTICE 2
#define CTC_LOGLEVEL_WARN 4
#define CTC_LOGLEVEL_EMERG 8
#define CTC_LOGLEVEL_ERR 16
#define CTC_LOGLEVEL_DEBUG 32
#define CTC_LOGLEVEL_CRIT 64
#define CTC_LOGLEVEL_DEFAULT \
(CTC_LOGLEVEL_INFO | CTC_LOGLEVEL_NOTICE | CTC_LOGLEVEL_WARN | CTC_LOGLEVEL_CRIT)
#define CTC_LOGLEVEL_MAX ((CTC_LOGLEVEL_CRIT<<1)-1)
static
int
loglevel
=
CTC_LOGLEVEL_DEFAULT
;
#define ctc_pr_debug(fmt, arg...) \
do { if (loglevel & CTC_LOGLEVEL_DEBUG) printk(KERN_DEBUG fmt,##arg); } while (0)
#define ctc_pr_info(fmt, arg...) \
do { if (loglevel & CTC_LOGLEVEL_INFO) printk(KERN_INFO fmt,##arg); } while (0)
#define ctc_pr_notice(fmt, arg...) \
do { if (loglevel & CTC_LOGLEVEL_NOTICE) printk(KERN_NOTICE fmt,##arg); } while (0)
#define ctc_pr_warn(fmt, arg...) \
do { if (loglevel & CTC_LOGLEVEL_WARN) printk(KERN_WARNING fmt,##arg); } while (0)
#define ctc_pr_emerg(fmt, arg...) \
do { if (loglevel & CTC_LOGLEVEL_EMERG) printk(KERN_EMERG fmt,##arg); } while (0)
#define ctc_pr_err(fmt, arg...) \
do { if (loglevel & CTC_LOGLEVEL_ERR) printk(KERN_ERR fmt,##arg); } while (0)
#define ctc_pr_crit(fmt, arg...) \
do { if (loglevel & CTC_LOGLEVEL_CRIT) printk(KERN_CRIT fmt,##arg); } while (0)
/**
* Linked list of all detected channels.
*/
static
struct
channel
*
channels
=
NULL
;
struct
ctc_priv
{
struct
net_device_stats
stats
;
unsigned
long
tbusy
;
/**
* The finite state machine of this interface.
*/
fsm_instance
*
fsm
;
/**
* The protocol of this device
*/
__u16
protocol
;
/**
* Timer for restarting after I/O Errors
*/
fsm_timer
restart_timer
;
int
buffer_size
;
struct
channel
*
channel
[
2
];
};
/**
* Definition of our link level header.
*/
struct
ll_header
{
__u16
length
;
__u16
type
;
__u16
unused
;
};
#define LL_HEADER_LENGTH (sizeof(struct ll_header))
/**
* Compatibility macros for busy handling
* of network devices.
*/
static
__inline__
void
ctc_clear_busy
(
struct
net_device
*
dev
)
{
clear_bit
(
0
,
&
(((
struct
ctc_priv
*
)
dev
->
priv
)
->
tbusy
));
if
(((
struct
ctc_priv
*
)
dev
->
priv
)
->
protocol
!=
CTC_PROTO_LINUX_TTY
)
netif_wake_queue
(
dev
);
}
static
__inline__
int
ctc_test_and_set_busy
(
struct
net_device
*
dev
)
{
if
(((
struct
ctc_priv
*
)
dev
->
priv
)
->
protocol
!=
CTC_PROTO_LINUX_TTY
)
netif_stop_queue
(
dev
);
return
test_and_set_bit
(
0
,
&
((
struct
ctc_priv
*
)
dev
->
priv
)
->
tbusy
);
}
/**
* Print Banner.
*/
static
void
print_banner
(
void
)
{
static
int
printed
=
0
;
char
vbuf
[]
=
"$Revision: 1.72 $"
;
char
*
version
=
vbuf
;
if
(
printed
)
return
;
if
((
version
=
strchr
(
version
,
':'
)))
{
char
*
p
=
strchr
(
version
+
1
,
'$'
);
if
(
p
)
*
p
=
'\0'
;
}
else
version
=
" ??? "
;
printk
(
KERN_INFO
"CTC driver Version%s"
#ifdef DEBUG
" (DEBUG-VERSION, "
__DATE__
__TIME__
")"
#endif
" initialized
\n
"
,
version
);
printed
=
1
;
}
/**
* Return type of a detected device.
*/
static
enum
channel_types
get_channel_type
(
struct
ccw_device_id
*
id
)
{
enum
channel_types
type
=
(
enum
channel_types
)
id
->
driver_info
;
if
(
type
==
channel_type_ficon
)
type
=
channel_type_escon
;
return
type
;
}
/**
* States of the interface statemachine.
*/
...
...
@@ -371,7 +95,7 @@ enum dev_states {
/**
* MUST be always the last element!!
*/
NR_DEV_STATES
CTC_
NR_DEV_STATES
};
static
const
char
*
dev_state_names
[]
=
{
...
...
@@ -399,7 +123,7 @@ enum dev_events {
/**
* MUST be always the last element!!
*/
NR_DEV_EVENTS
CTC_
NR_DEV_EVENTS
};
static
const
char
*
dev_event_names
[]
=
{
...
...
@@ -476,40 +200,6 @@ enum ch_events {
NR_CH_EVENTS
,
};
static
const
char
*
ch_event_names
[]
=
{
"ccw_device success"
,
"ccw_device busy"
,
"ccw_device enodev"
,
"ccw_device ioerr"
,
"ccw_device unknown"
,
"Status ATTN & BUSY"
,
"Status ATTN"
,
"Status BUSY"
,
"Unit check remote reset"
,
"Unit check remote system reset"
,
"Unit check TX timeout"
,
"Unit check TX parity"
,
"Unit check Hardware failure"
,
"Unit check RX parity"
,
"Unit check ZERO"
,
"Unit check Unknown"
,
"SubChannel check Unknown"
,
"Machine check failure"
,
"Machine check operational"
,
"IRQ normal"
,
"IRQ final"
,
"Timer"
,
"Start"
,
"Stop"
,
};
/**
* States of the channel statemachine.
*/
...
...
@@ -545,6 +235,87 @@ enum ch_states {
NR_CH_STATES
,
};
static
int
loglevel
=
CTC_LOGLEVEL_DEFAULT
;
/**
* Linked list of all detected channels.
*/
static
struct
channel
*
channels
=
NULL
;
/**
* Print Banner.
*/
static
void
print_banner
(
void
)
{
static
int
printed
=
0
;
char
vbuf
[]
=
"$Revision: 1.74 $"
;
char
*
version
=
vbuf
;
if
(
printed
)
return
;
if
((
version
=
strchr
(
version
,
':'
)))
{
char
*
p
=
strchr
(
version
+
1
,
'$'
);
if
(
p
)
*
p
=
'\0'
;
}
else
version
=
" ??? "
;
printk
(
KERN_INFO
"CTC driver Version%s"
#ifdef DEBUG
" (DEBUG-VERSION, "
__DATE__
__TIME__
")"
#endif
" initialized
\n
"
,
version
);
printed
=
1
;
}
/**
* Return type of a detected device.
*/
static
enum
channel_types
get_channel_type
(
struct
ccw_device_id
*
id
)
{
enum
channel_types
type
=
(
enum
channel_types
)
id
->
driver_info
;
if
(
type
==
channel_type_ficon
)
type
=
channel_type_escon
;
return
type
;
}
static
const
char
*
ch_event_names
[]
=
{
"ccw_device success"
,
"ccw_device busy"
,
"ccw_device enodev"
,
"ccw_device ioerr"
,
"ccw_device unknown"
,
"Status ATTN & BUSY"
,
"Status ATTN"
,
"Status BUSY"
,
"Unit check remote reset"
,
"Unit check remote system reset"
,
"Unit check TX timeout"
,
"Unit check TX parity"
,
"Unit check Hardware failure"
,
"Unit check RX parity"
,
"Unit check ZERO"
,
"Unit check Unknown"
,
"SubChannel check Unknown"
,
"Machine check failure"
,
"Machine check operational"
,
"IRQ normal"
,
"IRQ final"
,
"Timer"
,
"Start"
,
"Stop"
,
};
static
const
char
*
ch_state_names
[]
=
{
"Idle"
,
"Stopped"
,
...
...
@@ -1934,7 +1705,6 @@ add_channel(struct ccw_device *cdev, enum channel_types type)
ch
->
cdev
=
cdev
;
snprintf
(
ch
->
id
,
CTC_ID_SIZE
,
"ch-%s"
,
cdev
->
dev
.
bus_id
);
ch
->
type
=
type
;
loglevel
=
CTC_LOGLEVEL_DEFAULT
;
ch
->
fsm
=
init_fsm
(
ch
->
id
,
ch_state_names
,
ch_event_names
,
NR_CH_STATES
,
NR_CH_EVENTS
,
ch_fsm
,
CH_FSM_LEN
,
GFP_KERNEL
);
...
...
@@ -2697,6 +2467,7 @@ ctc_stats(struct net_device * dev)
/*
* sysfs attributes
*/
static
ssize_t
buffer_show
(
struct
device
*
dev
,
char
*
buf
)
{
...
...
@@ -2715,57 +2486,61 @@ buffer_write(struct device *dev, const char *buf, size_t count)
struct
ctc_priv
*
priv
;
struct
net_device
*
ndev
;
int
bs1
;
char
buffer
[
16
];
DBF_TEXT
(
trace
,
3
,
__FUNCTION__
);
DBF_TEXT
(
trace
,
3
,
buf
);
priv
=
dev
->
driver_data
;
if
(
!
priv
)
if
(
!
priv
)
{
DBF_TEXT
(
trace
,
3
,
"bfnopriv"
);
return
-
ENODEV
;
}
sscanf
(
buf
,
"%u"
,
&
bs1
);
if
(
bs1
>
CTC_BUFSIZE_LIMIT
)
goto
einval
;
if
(
bs1
<
(
576
+
LL_HEADER_LENGTH
+
2
))
goto
einval
;
priv
->
buffer_size
=
bs1
;
// just to overwrite the default
ndev
=
priv
->
channel
[
READ
]
->
netdev
;
if
(
!
ndev
)
if
(
!
ndev
)
{
DBF_TEXT
(
trace
,
3
,
"bfnondev"
);
return
-
ENODEV
;
sscanf
(
buf
,
"%u"
,
&
bs1
);
}
if
(
bs1
>
CTC_BUFSIZE_LIMIT
)
return
-
EINVAL
;
if
((
ndev
->
flags
&
IFF_RUNNING
)
&&
(
bs1
<
(
ndev
->
mtu
+
LL_HEADER_LENGTH
+
2
)))
return
-
EINVAL
;
if
(
bs1
<
(
576
+
LL_HEADER_LENGTH
+
2
))
return
-
EINVAL
;
goto
einval
;
priv
->
buffer_size
=
bs1
;
priv
->
channel
[
READ
]
->
max_bufsize
=
priv
->
channel
[
WRITE
]
->
max_bufsize
=
bs1
;
priv
->
channel
[
READ
]
->
max_bufsize
=
bs1
;
priv
->
channel
[
WRITE
]
->
max_bufsize
=
bs1
;
if
(
!
(
ndev
->
flags
&
IFF_RUNNING
))
ndev
->
mtu
=
bs1
-
LL_HEADER_LENGTH
-
2
;
priv
->
channel
[
READ
]
->
flags
|=
CHANNEL_FLAGS_BUFSIZE_CHANGED
;
priv
->
channel
[
WRITE
]
->
flags
|=
CHANNEL_FLAGS_BUFSIZE_CHANGED
;
sprintf
(
buffer
,
"%d"
,
priv
->
buffer_size
);
DBF_TEXT
(
trace
,
3
,
buffer
);
return
count
;
einval:
DBF_TEXT
(
trace
,
3
,
"buff_err"
);
return
-
EINVAL
;
}
static
ssize_t
loglevel_show
(
struct
device
*
dev
,
char
*
buf
)
{
struct
ctc_priv
*
priv
;
priv
=
dev
->
driver_data
;
if
(
!
priv
)
return
-
ENODEV
;
return
sprintf
(
buf
,
"%d
\n
"
,
loglevel
);
}
static
ssize_t
loglevel_write
(
struct
device
*
dev
,
const
char
*
buf
,
size_t
count
)
{
struct
ctc_priv
*
priv
;
int
ll1
;
DBF_TEXT
(
trace
,
5
,
__FUNCTION__
);
priv
=
dev
->
driver_data
;
if
(
!
priv
)
return
-
ENODEV
;
sscanf
(
buf
,
"%i"
,
&
ll1
);
if
((
ll1
>
CTC_LOGLEVEL_MAX
)
||
(
ll1
<
0
))
...
...
@@ -2835,27 +2610,6 @@ stats_write(struct device *dev, const char *buf, size_t count)
return
count
;
}
static
DEVICE_ATTR
(
buffer
,
0644
,
buffer_show
,
buffer_write
);
static
DEVICE_ATTR
(
loglevel
,
0644
,
loglevel_show
,
loglevel_write
);
static
DEVICE_ATTR
(
stats
,
0644
,
stats_show
,
stats_write
);
static
int
ctc_add_attributes
(
struct
device
*
dev
)
{
// device_create_file(dev, &dev_attr_buffer);
device_create_file
(
dev
,
&
dev_attr_loglevel
);
device_create_file
(
dev
,
&
dev_attr_stats
);
return
0
;
}
static
void
ctc_remove_attributes
(
struct
device
*
dev
)
{
device_remove_file
(
dev
,
&
dev_attr_stats
);
device_remove_file
(
dev
,
&
dev_attr_loglevel
);
// device_remove_file(dev, &dev_attr_buffer);
}
static
void
ctc_netdev_unregister
(
struct
net_device
*
dev
)
...
...
@@ -2899,52 +2653,6 @@ ctc_free_netdevice(struct net_device * dev, int free_dev)
#endif
}
/**
* Initialize everything of the net device except the name and the
* channel structs.
*/
static
struct
net_device
*
ctc_init_netdevice
(
struct
net_device
*
dev
,
int
alloc_device
,
struct
ctc_priv
*
privptr
)
{
if
(
!
privptr
)
return
NULL
;
DBF_TEXT
(
setup
,
3
,
__FUNCTION__
);
if
(
alloc_device
)
{
dev
=
kmalloc
(
sizeof
(
struct
net_device
),
GFP_KERNEL
);
if
(
!
dev
)
return
NULL
;
memset
(
dev
,
0
,
sizeof
(
struct
net_device
));
}
dev
->
priv
=
privptr
;
privptr
->
fsm
=
init_fsm
(
"ctcdev"
,
dev_state_names
,
dev_event_names
,
NR_DEV_STATES
,
NR_DEV_EVENTS
,
dev_fsm
,
DEV_FSM_LEN
,
GFP_KERNEL
);
if
(
privptr
->
fsm
==
NULL
)
{
if
(
alloc_device
)
kfree
(
dev
);
return
NULL
;
}
fsm_newstate
(
privptr
->
fsm
,
DEV_STATE_STOPPED
);
fsm_settimer
(
privptr
->
fsm
,
&
privptr
->
restart_timer
);
if
(
dev
->
mtu
==
0
)
dev
->
mtu
=
CTC_BUFSIZE_DEFAULT
-
LL_HEADER_LENGTH
-
2
;
dev
->
hard_start_xmit
=
ctc_tx
;
dev
->
open
=
ctc_open
;
dev
->
stop
=
ctc_close
;
dev
->
get_stats
=
ctc_stats
;
dev
->
change_mtu
=
ctc_change_mtu
;
dev
->
hard_header_len
=
LL_HEADER_LENGTH
+
2
;
dev
->
addr_len
=
0
;
dev
->
type
=
ARPHRD_SLIP
;
dev
->
tx_queue_len
=
100
;
dev
->
flags
=
IFF_POINTOPOINT
|
IFF_NOARP
;
SET_MODULE_OWNER
(
dev
);
return
dev
;
}
static
ssize_t
ctc_proto_show
(
struct
device
*
dev
,
char
*
buf
)
{
...
...
@@ -2977,7 +2685,6 @@ ctc_proto_store(struct device *dev, const char *buf, size_t count)
return
count
;
}
static
DEVICE_ATTR
(
protocol
,
0644
,
ctc_proto_show
,
ctc_proto_store
);
static
ssize_t
ctc_type_show
(
struct
device
*
dev
,
char
*
buf
)
...
...
@@ -2991,8 +2698,13 @@ ctc_type_show(struct device *dev, char *buf)
return
sprintf
(
buf
,
"%s
\n
"
,
cu3088_type
[
cgdev
->
cdev
[
0
]
->
id
.
driver_info
]);
}
static
DEVICE_ATTR
(
buffer
,
0644
,
buffer_show
,
buffer_write
);
static
DEVICE_ATTR
(
protocol
,
0644
,
ctc_proto_show
,
ctc_proto_store
);
static
DEVICE_ATTR
(
type
,
0444
,
ctc_type_show
,
NULL
);
static
DEVICE_ATTR
(
loglevel
,
0644
,
loglevel_show
,
loglevel_write
);
static
DEVICE_ATTR
(
stats
,
0644
,
stats_show
,
stats_write
);
static
struct
attribute
*
ctc_attr
[]
=
{
&
dev_attr_protocol
.
attr
,
&
dev_attr_type
.
attr
,
...
...
@@ -3004,6 +2716,21 @@ static struct attribute_group ctc_attr_group = {
.
attrs
=
ctc_attr
,
};
static
int
ctc_add_attributes
(
struct
device
*
dev
)
{
device_create_file
(
dev
,
&
dev_attr_loglevel
);
device_create_file
(
dev
,
&
dev_attr_stats
);
return
0
;
}
static
void
ctc_remove_attributes
(
struct
device
*
dev
)
{
device_remove_file
(
dev
,
&
dev_attr_stats
);
device_remove_file
(
dev
,
&
dev_attr_loglevel
);
}
static
int
ctc_add_files
(
struct
device
*
dev
)
{
...
...
@@ -3028,15 +2755,15 @@ ctc_remove_files(struct device *dev)
*
* @returns 0 on success, !0 on failure.
*/
static
int
ctc_probe_device
(
struct
ccwgroup_device
*
cgdev
)
{
struct
ctc_priv
*
priv
;
int
rc
;
char
buffer
[
16
];
pr_debug
(
"%s() called
\n
"
,
__FUNCTION__
);
DBF_TEXT
(
trace
,
3
,
__FUNCTION__
);
DBF_TEXT
(
setup
,
3
,
__FUNCTION__
);
if
(
!
get_device
(
&
cgdev
->
dev
))
return
-
ENODEV
;
...
...
@@ -3060,9 +2787,69 @@ ctc_probe_device(struct ccwgroup_device *cgdev)
cgdev
->
cdev
[
1
]
->
handler
=
ctc_irq_handler
;
cgdev
->
dev
.
driver_data
=
priv
;
sprintf
(
buffer
,
"%p"
,
priv
);
DBF_TEXT
(
data
,
3
,
buffer
);
sprintf
(
buffer
,
"%u"
,
(
unsigned
int
)
sizeof
(
struct
ctc_priv
));
DBF_TEXT
(
data
,
3
,
buffer
);
sprintf
(
buffer
,
"%p"
,
&
channels
);
DBF_TEXT
(
data
,
3
,
buffer
);
sprintf
(
buffer
,
"%u"
,
(
unsigned
int
)
sizeof
(
struct
channel
));
DBF_TEXT
(
data
,
3
,
buffer
);
return
0
;
}
/**
* Initialize everything of the net device except the name and the
* channel structs.
*/
static
struct
net_device
*
ctc_init_netdevice
(
struct
net_device
*
dev
,
int
alloc_device
,
struct
ctc_priv
*
privptr
)
{
if
(
!
privptr
)
return
NULL
;
DBF_TEXT
(
setup
,
3
,
__FUNCTION__
);
if
(
alloc_device
)
{
dev
=
kmalloc
(
sizeof
(
struct
net_device
),
GFP_KERNEL
);
if
(
!
dev
)
return
NULL
;
memset
(
dev
,
0
,
sizeof
(
struct
net_device
));
}
dev
->
priv
=
privptr
;
privptr
->
fsm
=
init_fsm
(
"ctcdev"
,
dev_state_names
,
dev_event_names
,
CTC_NR_DEV_STATES
,
CTC_NR_DEV_EVENTS
,
dev_fsm
,
DEV_FSM_LEN
,
GFP_KERNEL
);
if
(
privptr
->
fsm
==
NULL
)
{
if
(
alloc_device
)
kfree
(
dev
);
return
NULL
;
}
fsm_newstate
(
privptr
->
fsm
,
DEV_STATE_STOPPED
);
fsm_settimer
(
privptr
->
fsm
,
&
privptr
->
restart_timer
);
if
(
dev
->
mtu
==
0
)
dev
->
mtu
=
CTC_BUFSIZE_DEFAULT
-
LL_HEADER_LENGTH
-
2
;
dev
->
hard_start_xmit
=
ctc_tx
;
dev
->
open
=
ctc_open
;
dev
->
stop
=
ctc_close
;
dev
->
get_stats
=
ctc_stats
;
dev
->
change_mtu
=
ctc_change_mtu
;
dev
->
hard_header_len
=
LL_HEADER_LENGTH
+
2
;
dev
->
addr_len
=
0
;
dev
->
type
=
ARPHRD_SLIP
;
dev
->
tx_queue_len
=
100
;
dev
->
flags
=
IFF_POINTOPOINT
|
IFF_NOARP
;
SET_MODULE_OWNER
(
dev
);
return
dev
;
}
/**
*
* Setup an interface.
...
...
@@ -3081,6 +2868,7 @@ ctc_new_device(struct ccwgroup_device *cgdev)
struct
ctc_priv
*
privptr
;
struct
net_device
*
dev
;
int
ret
;
char
buffer
[
16
];
pr_debug
(
"%s() called
\n
"
,
__FUNCTION__
);
DBF_TEXT
(
setup
,
3
,
__FUNCTION__
);
...
...
@@ -3089,6 +2877,9 @@ ctc_new_device(struct ccwgroup_device *cgdev)
if
(
!
privptr
)
return
-
ENODEV
;
sprintf
(
buffer
,
"%d"
,
privptr
->
buffer_size
);
DBF_TEXT
(
setup
,
3
,
buffer
);
type
=
get_channel_type
(
&
cgdev
->
cdev
[
0
]
->
id
);
snprintf
(
read_id
,
CTC_ID_SIZE
,
"ch-%s"
,
cgdev
->
cdev
[
0
]
->
dev
.
bus_id
);
...
...
@@ -3177,9 +2968,10 @@ ctc_shutdown_device(struct ccwgroup_device *cgdev)
struct
ctc_priv
*
priv
;
struct
net_device
*
ndev
;
DBF_TEXT
(
trace
,
3
,
__FUNCTION__
);
DBF_TEXT
(
setup
,
3
,
__FUNCTION__
);
pr_debug
(
"%s() called
\n
"
,
__FUNCTION__
);
priv
=
cgdev
->
dev
.
driver_data
;
ndev
=
NULL
;
if
(
!
priv
)
...
...
@@ -3215,7 +3007,6 @@ ctc_shutdown_device(struct ccwgroup_device *cgdev)
channel_remove
(
priv
->
channel
[
READ
]);
if
(
priv
->
channel
[
WRITE
])
channel_remove
(
priv
->
channel
[
WRITE
]);
priv
->
channel
[
READ
]
=
priv
->
channel
[
WRITE
]
=
NULL
;
return
0
;
...
...
@@ -3228,7 +3019,7 @@ ctc_remove_device(struct ccwgroup_device *cgdev)
struct
ctc_priv
*
priv
;
pr_debug
(
"%s() called
\n
"
,
__FUNCTION__
);
DBF_TEXT
(
trace
,
3
,
__FUNCTION__
);
DBF_TEXT
(
setup
,
3
,
__FUNCTION__
);
priv
=
cgdev
->
dev
.
driver_data
;
if
(
!
priv
)
...
...
@@ -3265,6 +3056,7 @@ static struct ccwgroup_driver ctc_group_driver = {
static
void
__exit
ctc_exit
(
void
)
{
DBF_TEXT
(
setup
,
3
,
__FUNCTION__
);
unregister_cu3088_discipline
(
&
ctc_group_driver
);
ctc_tty_cleanup
();
ctc_unregister_dbf_views
();
...
...
@@ -3282,6 +3074,10 @@ ctc_init(void)
{
int
ret
=
0
;
loglevel
=
CTC_LOGLEVEL_DEFAULT
;
DBF_TEXT
(
setup
,
3
,
__FUNCTION__
);
print_banner
();
ret
=
ctc_register_dbf_views
();
...
...
drivers/s390/net/ctcmain.h
0 → 100644
浏览文件 @
8a75e7d6
/*
* $Id: ctcmain.h,v 1.4 2005/03/24 09:04:17 mschwide Exp $
*
* CTC / ESCON network driver
*
* Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Author(s): Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com)
Peter Tiedemann (ptiedem@de.ibm.com)
*
*
* Documentation used:
* - Principles of Operation (IBM doc#: SA22-7201-06)
* - Common IO/-Device Commands and Self Description (IBM doc#: SA22-7204-02)
* - Common IO/-Device Commands and Self Description (IBM doc#: SN22-5535)
* - ESCON Channel-to-Channel Adapter (IBM doc#: SA22-7203-00)
* - ESCON I/O Interface (IBM doc#: SA22-7202-029
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* RELEASE-TAG: CTC/ESCON network driver $Revision: 1.4 $
*
*/
#ifndef _CTCMAIN_H_
#define _CTCMAIN_H_
#include <asm/ccwdev.h>
#include <asm/ccwgroup.h>
#include "ctctty.h"
#include "fsm.h"
#include "cu3088.h"
/**
* CCW commands, used in this driver.
*/
#define CCW_CMD_WRITE 0x01
#define CCW_CMD_READ 0x02
#define CCW_CMD_SET_EXTENDED 0xc3
#define CCW_CMD_PREPARE 0xe3
#define CTC_PROTO_S390 0
#define CTC_PROTO_LINUX 1
#define CTC_PROTO_LINUX_TTY 2
#define CTC_PROTO_OS390 3
#define CTC_PROTO_MAX 3
#define CTC_BUFSIZE_LIMIT 65535
#define CTC_BUFSIZE_DEFAULT 32768
#define CTC_TIMEOUT_5SEC 5000
#define CTC_INITIAL_BLOCKLEN 2
#define READ 0
#define WRITE 1
#define CTC_ID_SIZE BUS_ID_SIZE+3
struct
ctc_profile
{
unsigned
long
maxmulti
;
unsigned
long
maxcqueue
;
unsigned
long
doios_single
;
unsigned
long
doios_multi
;
unsigned
long
txlen
;
unsigned
long
tx_time
;
struct
timespec
send_stamp
;
};
/**
* Definition of one channel
*/
struct
channel
{
/**
* Pointer to next channel in list.
*/
struct
channel
*
next
;
char
id
[
CTC_ID_SIZE
];
struct
ccw_device
*
cdev
;
/**
* Type of this channel.
* CTC/A or Escon for valid channels.
*/
enum
channel_types
type
;
/**
* Misc. flags. See CHANNEL_FLAGS_... below
*/
__u32
flags
;
/**
* The protocol of this channel
*/
__u16
protocol
;
/**
* I/O and irq related stuff
*/
struct
ccw1
*
ccw
;
struct
irb
*
irb
;
/**
* RX/TX buffer size
*/
int
max_bufsize
;
/**
* Transmit/Receive buffer.
*/
struct
sk_buff
*
trans_skb
;
/**
* Universal I/O queue.
*/
struct
sk_buff_head
io_queue
;
/**
* TX queue for collecting skb's during busy.
*/
struct
sk_buff_head
collect_queue
;
/**
* Amount of data in collect_queue.
*/
int
collect_len
;
/**
* spinlock for collect_queue and collect_len
*/
spinlock_t
collect_lock
;
/**
* Timer for detecting unresposive
* I/O operations.
*/
fsm_timer
timer
;
/**
* Retry counter for misc. operations.
*/
int
retry
;
/**
* The finite state machine of this channel
*/
fsm_instance
*
fsm
;
/**
* The corresponding net_device this channel
* belongs to.
*/
struct
net_device
*
netdev
;
struct
ctc_profile
prof
;
unsigned
char
*
trans_skb_data
;
__u16
logflags
;
};
#define CHANNEL_FLAGS_READ 0
#define CHANNEL_FLAGS_WRITE 1
#define CHANNEL_FLAGS_INUSE 2
#define CHANNEL_FLAGS_BUFSIZE_CHANGED 4
#define CHANNEL_FLAGS_FAILED 8
#define CHANNEL_FLAGS_WAITIRQ 16
#define CHANNEL_FLAGS_RWMASK 1
#define CHANNEL_DIRECTION(f) (f & CHANNEL_FLAGS_RWMASK)
#define LOG_FLAG_ILLEGALPKT 1
#define LOG_FLAG_ILLEGALSIZE 2
#define LOG_FLAG_OVERRUN 4
#define LOG_FLAG_NOMEM 8
#define CTC_LOGLEVEL_INFO 1
#define CTC_LOGLEVEL_NOTICE 2
#define CTC_LOGLEVEL_WARN 4
#define CTC_LOGLEVEL_EMERG 8
#define CTC_LOGLEVEL_ERR 16
#define CTC_LOGLEVEL_DEBUG 32
#define CTC_LOGLEVEL_CRIT 64
#define CTC_LOGLEVEL_DEFAULT \
(CTC_LOGLEVEL_INFO | CTC_LOGLEVEL_NOTICE | CTC_LOGLEVEL_WARN | CTC_LOGLEVEL_CRIT)
#define CTC_LOGLEVEL_MAX ((CTC_LOGLEVEL_CRIT<<1)-1)
#define ctc_pr_debug(fmt, arg...) \
do { if (loglevel & CTC_LOGLEVEL_DEBUG) printk(KERN_DEBUG fmt,##arg); } while (0)
#define ctc_pr_info(fmt, arg...) \
do { if (loglevel & CTC_LOGLEVEL_INFO) printk(KERN_INFO fmt,##arg); } while (0)
#define ctc_pr_notice(fmt, arg...) \
do { if (loglevel & CTC_LOGLEVEL_NOTICE) printk(KERN_NOTICE fmt,##arg); } while (0)
#define ctc_pr_warn(fmt, arg...) \
do { if (loglevel & CTC_LOGLEVEL_WARN) printk(KERN_WARNING fmt,##arg); } while (0)
#define ctc_pr_emerg(fmt, arg...) \
do { if (loglevel & CTC_LOGLEVEL_EMERG) printk(KERN_EMERG fmt,##arg); } while (0)
#define ctc_pr_err(fmt, arg...) \
do { if (loglevel & CTC_LOGLEVEL_ERR) printk(KERN_ERR fmt,##arg); } while (0)
#define ctc_pr_crit(fmt, arg...) \
do { if (loglevel & CTC_LOGLEVEL_CRIT) printk(KERN_CRIT fmt,##arg); } while (0)
struct
ctc_priv
{
struct
net_device_stats
stats
;
unsigned
long
tbusy
;
/**
* The finite state machine of this interface.
*/
fsm_instance
*
fsm
;
/**
* The protocol of this device
*/
__u16
protocol
;
/**
* Timer for restarting after I/O Errors
*/
fsm_timer
restart_timer
;
int
buffer_size
;
struct
channel
*
channel
[
2
];
};
/**
* Definition of our link level header.
*/
struct
ll_header
{
__u16
length
;
__u16
type
;
__u16
unused
;
};
#define LL_HEADER_LENGTH (sizeof(struct ll_header))
/**
* Compatibility macros for busy handling
* of network devices.
*/
static
__inline__
void
ctc_clear_busy
(
struct
net_device
*
dev
)
{
clear_bit
(
0
,
&
(((
struct
ctc_priv
*
)
dev
->
priv
)
->
tbusy
));
if
(((
struct
ctc_priv
*
)
dev
->
priv
)
->
protocol
!=
CTC_PROTO_LINUX_TTY
)
netif_wake_queue
(
dev
);
}
static
__inline__
int
ctc_test_and_set_busy
(
struct
net_device
*
dev
)
{
if
(((
struct
ctc_priv
*
)
dev
->
priv
)
->
protocol
!=
CTC_PROTO_LINUX_TTY
)
netif_stop_queue
(
dev
);
return
test_and_set_bit
(
0
,
&
((
struct
ctc_priv
*
)
dev
->
priv
)
->
tbusy
);
}
#endif
drivers/s390/net/ctctty.c
浏览文件 @
8a75e7d6
/*
* $Id: ctctty.c,v 1.2
6 2004/08/04 11:06:55
mschwide Exp $
* $Id: ctctty.c,v 1.2
9 2005/04/05 08:50:44
mschwide Exp $
*
* CTC / ESCON network driver, tty interface.
*
...
...
@@ -1056,8 +1056,7 @@ ctc_tty_close(struct tty_struct *tty, struct file *filp)
info
->
tty
=
0
;
tty
->
closing
=
0
;
if
(
info
->
blocked_open
)
{
set_current_state
(
TASK_INTERRUPTIBLE
);
schedule_timeout
(
HZ
/
2
);
msleep_interruptible
(
500
);
wake_up_interruptible
(
&
info
->
open_wait
);
}
info
->
flags
&=
~
(
CTC_ASYNC_NORMAL_ACTIVE
|
CTC_ASYNC_CLOSING
);
...
...
drivers/s390/net/cu3088.c
浏览文件 @
8a75e7d6
/*
* $Id: cu3088.c,v 1.3
4 2004/06/15 13:16:27 pavlic
Exp $
* $Id: cu3088.c,v 1.3
5 2005/03/30 19:28:52 richtera
Exp $
*
* CTC / LCS ccw_device driver
*
...
...
@@ -39,6 +39,7 @@ const char *cu3088_type[] = {
"FICON channel"
,
"P390 LCS card"
,
"OSA LCS card"
,
"CLAW channel device"
,
"unknown channel type"
,
"unsupported channel type"
,
};
...
...
@@ -51,6 +52,7 @@ static struct ccw_device_id cu3088_ids[] = {
{
CCW_DEVICE
(
0x3088
,
0x1e
),
.
driver_info
=
channel_type_ficon
},
{
CCW_DEVICE
(
0x3088
,
0x01
),
.
driver_info
=
channel_type_p390
},
{
CCW_DEVICE
(
0x3088
,
0x60
),
.
driver_info
=
channel_type_osa2
},
{
CCW_DEVICE
(
0x3088
,
0x61
),
.
driver_info
=
channel_type_claw
},
{
/* end of list */
}
};
...
...
drivers/s390/net/cu3088.h
浏览文件 @
8a75e7d6
...
...
@@ -23,6 +23,9 @@ enum channel_types {
/* Device is a OSA2 card */
channel_type_osa2
,
/* Device is a CLAW channel device */
channel_type_claw
,
/* Device is a channel, but we don't know
* anything about it */
channel_type_unknown
,
...
...
drivers/s390/net/iucv.c
浏览文件 @
8a75e7d6
/*
* $Id: iucv.c,v 1.4
3 2005/02/09 14:47:43
braunu Exp $
* $Id: iucv.c,v 1.4
5 2005/04/26 22:59:06
braunu Exp $
*
* IUCV network driver
*
...
...
@@ -29,7 +29,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* RELEASE-TAG: IUCV lowlevel driver $Revision: 1.4
3
$
* RELEASE-TAG: IUCV lowlevel driver $Revision: 1.4
5
$
*
*/
...
...
@@ -355,7 +355,7 @@ do { \
static
void
iucv_banner
(
void
)
{
char
vbuf
[]
=
"$Revision: 1.4
3
$"
;
char
vbuf
[]
=
"$Revision: 1.4
5
$"
;
char
*
version
=
vbuf
;
if
((
version
=
strchr
(
version
,
':'
)))
{
...
...
@@ -2553,12 +2553,12 @@ EXPORT_SYMBOL (iucv_resume);
#endif
EXPORT_SYMBOL
(
iucv_reply_prmmsg
);
EXPORT_SYMBOL
(
iucv_send
);
#if 0
EXPORT_SYMBOL
(
iucv_send2way
);
EXPORT_SYMBOL
(
iucv_send2way_array
);
EXPORT_SYMBOL (iucv_send_array);
EXPORT_SYMBOL
(
iucv_send2way_prmmsg
);
EXPORT_SYMBOL
(
iucv_send2way_prmmsg_array
);
#if 0
EXPORT_SYMBOL (iucv_send_array);
EXPORT_SYMBOL (iucv_send_prmmsg);
EXPORT_SYMBOL (iucv_setmask);
#endif
...
...
drivers/s390/net/lcs.c
浏览文件 @
8a75e7d6
...
...
@@ -11,7 +11,7 @@
* Frank Pavlic (pavlic@de.ibm.com) and
* Martin Schwidefsky <schwidefsky@de.ibm.com>
*
* $Revision: 1.9
6 $ $Date: 2004/11/11 13:42:33
$
* $Revision: 1.9
8 $ $Date: 2005/04/18 13:41:29
$
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
...
...
@@ -59,7 +59,7 @@
/**
* initialization string for output
*/
#define VERSION_LCS_C "$Revision: 1.9
6
$"
#define VERSION_LCS_C "$Revision: 1.9
8
$"
static
char
version
[]
__initdata
=
"LCS driver ("
VERSION_LCS_C
"/"
VERSION_LCS_H
")"
;
static
char
debug_buffer
[
255
];
...
...
@@ -1098,14 +1098,6 @@ lcs_check_multicast_support(struct lcs_card *card)
PRINT_ERR
(
"Query IPAssist failed. Assuming unsupported!
\n
"
);
return
-
EOPNOTSUPP
;
}
/* Print out supported assists: IPv6 */
PRINT_INFO
(
"LCS device %s %s IPv6 support
\n
"
,
card
->
dev
->
name
,
(
card
->
ip_assists_supported
&
LCS_IPASS_IPV6_SUPPORT
)
?
"with"
:
"without"
);
/* Print out supported assist: Multicast */
PRINT_INFO
(
"LCS device %s %s Multicast support
\n
"
,
card
->
dev
->
name
,
(
card
->
ip_assists_supported
&
LCS_IPASS_MULTICAST_SUPPORT
)
?
"with"
:
"without"
);
if
(
card
->
ip_assists_supported
&
LCS_IPASS_MULTICAST_SUPPORT
)
return
0
;
return
-
EOPNOTSUPP
;
...
...
@@ -1160,7 +1152,7 @@ lcs_fix_multicast_list(struct lcs_card *card)
}
}
/* re-insert all entries from the failed_list into ipm_list */
list_for_each_entry
(
ipm
,
&
failed_list
,
list
)
{
list_for_each_entry
_safe
(
ipm
,
tmp
,
&
failed_list
,
list
)
{
list_del_init
(
&
ipm
->
list
);
list_add_tail
(
&
ipm
->
list
,
&
card
->
ipm_list
);
}
...
...
@@ -2198,30 +2190,39 @@ lcs_new_device(struct ccwgroup_device *ccwgdev)
if
(
!
dev
)
goto
out
;
card
->
dev
=
dev
;
netdev_out:
card
->
dev
->
priv
=
card
;
card
->
dev
->
open
=
lcs_open_device
;
card
->
dev
->
stop
=
lcs_stop_device
;
card
->
dev
->
hard_start_xmit
=
lcs_start_xmit
;
card
->
dev
->
get_stats
=
lcs_getstats
;
SET_MODULE_OWNER
(
dev
);
if
(
lcs_register_netdev
(
ccwgdev
)
!=
0
)
goto
out
;
memcpy
(
card
->
dev
->
dev_addr
,
card
->
mac
,
LCS_MAC_LENGTH
);
#ifdef CONFIG_IP_MULTICAST
if
(
!
lcs_check_multicast_support
(
card
))
card
->
dev
->
set_multicast_list
=
lcs_set_multicast_list
;
#endif
netif_stop_queue
(
card
->
dev
);
netdev_out:
lcs_set_allowed_threads
(
card
,
0xffffffff
);
if
(
recover_state
==
DEV_STATE_RECOVER
)
{
lcs_set_multicast_list
(
card
->
dev
);
card
->
dev
->
flags
|=
IFF_UP
;
netif_wake_queue
(
card
->
dev
);
card
->
state
=
DEV_STATE_UP
;
}
else
}
else
{
lcs_stopcard
(
card
);
}
if
(
lcs_register_netdev
(
ccwgdev
)
!=
0
)
goto
out
;
/* Print out supported assists: IPv6 */
PRINT_INFO
(
"LCS device %s %s IPv6 support
\n
"
,
card
->
dev
->
name
,
(
card
->
ip_assists_supported
&
LCS_IPASS_IPV6_SUPPORT
)
?
"with"
:
"without"
);
/* Print out supported assist: Multicast */
PRINT_INFO
(
"LCS device %s %s Multicast support
\n
"
,
card
->
dev
->
name
,
(
card
->
ip_assists_supported
&
LCS_IPASS_MULTICAST_SUPPORT
)
?
"with"
:
"without"
);
return
0
;
out:
...
...
drivers/s390/net/qeth.h
浏览文件 @
8a75e7d6
...
...
@@ -24,7 +24,7 @@
#include "qeth_mpc.h"
#define VERSION_QETH_H "$Revision: 1.13
5
$"
#define VERSION_QETH_H "$Revision: 1.13
9
$"
#ifdef CONFIG_QETH_IPV6
#define QETH_VERSION_IPV6 ":IPv6"
...
...
@@ -288,7 +288,8 @@ qeth_is_ipa_enabled(struct qeth_ipa_info *ipa, enum qeth_ipa_funcs func)
#define QETH_TX_TIMEOUT 100 * HZ
#define QETH_HEADER_SIZE 32
#define MAX_PORTNO 15
#define QETH_FAKE_LL_LEN ETH_HLEN
#define QETH_FAKE_LL_LEN_ETH ETH_HLEN
#define QETH_FAKE_LL_LEN_TR (sizeof(struct trh_hdr)-TR_MAXRIFLEN+sizeof(struct trllc))
#define QETH_FAKE_LL_V6_ADDR_POS 24
/*IPv6 address autoconfiguration stuff*/
...
...
@@ -369,6 +370,25 @@ struct qeth_hdr {
}
hdr
;
}
__attribute__
((
packed
));
/*TCP Segmentation Offload header*/
struct
qeth_hdr_ext_tso
{
__u16
hdr_tot_len
;
__u8
imb_hdr_no
;
__u8
reserved
;
__u8
hdr_type
;
__u8
hdr_version
;
__u16
hdr_len
;
__u32
payload_len
;
__u16
mss
;
__u16
dg_hdr_len
;
__u8
padding
[
16
];
}
__attribute__
((
packed
));
struct
qeth_hdr_tso
{
struct
qeth_hdr
hdr
;
/*hdr->hdr.l3.xxx*/
struct
qeth_hdr_ext_tso
ext
;
}
__attribute__
((
packed
));
/* flags for qeth_hdr.flags */
#define QETH_HDR_PASSTHRU 0x10
...
...
@@ -866,6 +886,7 @@ qeth_push_skb(struct qeth_card *card, struct sk_buff **skb, int size)
return
hdr
;
}
inline
static
int
qeth_get_hlen
(
__u8
link_type
)
{
...
...
@@ -873,19 +894,19 @@ qeth_get_hlen(__u8 link_type)
switch
(
link_type
)
{
case
QETH_LINK_TYPE_HSTR
:
case
QETH_LINK_TYPE_LANE_TR
:
return
sizeof
(
struct
qeth_hdr
)
+
TR_HLEN
;
return
sizeof
(
struct
qeth_hdr
_tso
)
+
TR_HLEN
;
default:
#ifdef CONFIG_QETH_VLAN
return
sizeof
(
struct
qeth_hdr
)
+
VLAN_ETH_HLEN
;
return
sizeof
(
struct
qeth_hdr
_tso
)
+
VLAN_ETH_HLEN
;
#else
return
sizeof
(
struct
qeth_hdr
)
+
ETH_HLEN
;
return
sizeof
(
struct
qeth_hdr
_tso
)
+
ETH_HLEN
;
#endif
}
#else
/* CONFIG_QETH_IPV6 */
#ifdef CONFIG_QETH_VLAN
return
sizeof
(
struct
qeth_hdr
)
+
VLAN_HLEN
;
return
sizeof
(
struct
qeth_hdr
_tso
)
+
VLAN_HLEN
;
#else
return
sizeof
(
struct
qeth_hdr
);
return
sizeof
(
struct
qeth_hdr
_tso
);
#endif
#endif
/* CONFIG_QETH_IPV6 */
}
...
...
drivers/s390/net/qeth_eddp.c
浏览文件 @
8a75e7d6
/*
*
* linux/drivers/s390/net/qeth_eddp.c ($Revision: 1.1
1
$)
* linux/drivers/s390/net/qeth_eddp.c ($Revision: 1.1
3
$)
*
* Enhanced Device Driver Packing (EDDP) support for the qeth driver.
*
...
...
@@ -8,7 +8,7 @@
*
* Author(s): Thomas Spatzier <tspat@de.ibm.com>
*
* $Revision: 1.1
1 $ $Date: 2005/03/24 09:04
:18 $
* $Revision: 1.1
3 $ $Date: 2005/05/04 20:19
:18 $
*
*/
#include <linux/config.h>
...
...
@@ -85,7 +85,7 @@ void
qeth_eddp_buf_release_contexts
(
struct
qeth_qdio_out_buffer
*
buf
)
{
struct
qeth_eddp_context_reference
*
ref
;
QETH_DBF_TEXT
(
trace
,
6
,
"eddprctx"
);
while
(
!
list_empty
(
&
buf
->
ctx_list
)){
ref
=
list_entry
(
buf
->
ctx_list
.
next
,
...
...
@@ -139,7 +139,7 @@ qeth_eddp_fill_buffer(struct qeth_qdio_out_q *queue,
"buffer!
\n
"
);
goto
out
;
}
}
}
/* check if the whole next skb fits into current buffer */
if
((
QETH_MAX_BUFFER_ELEMENTS
(
queue
->
card
)
-
buf
->
next_element_to_fill
)
...
...
@@ -152,7 +152,7 @@ qeth_eddp_fill_buffer(struct qeth_qdio_out_q *queue,
* and increment ctx's refcnt */
must_refcnt
=
1
;
continue
;
}
}
if
(
must_refcnt
){
must_refcnt
=
0
;
if
(
qeth_eddp_buf_ref_context
(
buf
,
ctx
)){
...
...
@@ -202,40 +202,29 @@ qeth_eddp_fill_buffer(struct qeth_qdio_out_q *queue,
return
flush_cnt
;
}
static
inline
int
qeth_get_skb_data_len
(
struct
sk_buff
*
skb
)
{
int
len
=
skb
->
len
;
int
i
;
for
(
i
=
0
;
i
<
skb_shinfo
(
skb
)
->
nr_frags
;
++
i
)
len
-=
skb_shinfo
(
skb
)
->
frags
[
i
].
size
;
return
len
;
}
static
inline
void
qeth_eddp_create_segment_hdrs
(
struct
qeth_eddp_context
*
ctx
,
struct
qeth_eddp_data
*
eddp
)
struct
qeth_eddp_data
*
eddp
,
int
data_len
)
{
u8
*
page
;
int
page_remainder
;
int
page_offset
;
int
hdr
_len
;
int
pkt
_len
;
struct
qeth_eddp_element
*
element
;
QETH_DBF_TEXT
(
trace
,
5
,
"eddpcrsh"
);
page
=
ctx
->
pages
[
ctx
->
offset
>>
PAGE_SHIFT
];
page_offset
=
ctx
->
offset
%
PAGE_SIZE
;
element
=
&
ctx
->
elements
[
ctx
->
num_elements
];
hdr_len
=
eddp
->
nhl
+
eddp
->
thl
;
pkt_len
=
eddp
->
nhl
+
eddp
->
thl
+
data_len
;
/* FIXME: layer2 and VLAN !!! */
if
(
eddp
->
qh
.
hdr
.
l2
.
id
==
QETH_HEADER_TYPE_LAYER2
)
hdr
_len
+=
ETH_HLEN
;
pkt
_len
+=
ETH_HLEN
;
if
(
eddp
->
mac
.
h_proto
==
__constant_htons
(
ETH_P_8021Q
))
hdr
_len
+=
VLAN_HLEN
;
/* does complete
header
fit in current page ? */
pkt
_len
+=
VLAN_HLEN
;
/* does complete
packet
fit in current page ? */
page_remainder
=
PAGE_SIZE
-
page_offset
;
if
(
page_remainder
<
(
sizeof
(
struct
qeth_hdr
)
+
hdr
_len
)){
if
(
page_remainder
<
(
sizeof
(
struct
qeth_hdr
)
+
pkt
_len
)){
/* no -> go to start of next page */
ctx
->
offset
+=
page_remainder
;
page
=
ctx
->
pages
[
ctx
->
offset
>>
PAGE_SHIFT
];
...
...
@@ -281,7 +270,7 @@ qeth_eddp_copy_data_tcp(char *dst, struct qeth_eddp_data *eddp, int len,
int
left_in_frag
;
int
copy_len
;
u8
*
src
;
QETH_DBF_TEXT
(
trace
,
5
,
"eddpcdtc"
);
if
(
skb_shinfo
(
eddp
->
skb
)
->
nr_frags
==
0
)
{
memcpy
(
dst
,
eddp
->
skb
->
data
+
eddp
->
skb_offset
,
len
);
...
...
@@ -292,7 +281,7 @@ qeth_eddp_copy_data_tcp(char *dst, struct qeth_eddp_data *eddp, int len,
while
(
len
>
0
)
{
if
(
eddp
->
frag
<
0
)
{
/* we're in skb->data */
left_in_frag
=
qeth_get_skb_data_len
(
eddp
->
skb
)
left_in_frag
=
(
eddp
->
skb
->
len
-
eddp
->
skb
->
data_len
)
-
eddp
->
skb_offset
;
src
=
eddp
->
skb
->
data
+
eddp
->
skb_offset
;
}
else
{
...
...
@@ -424,7 +413,7 @@ __qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
struct
tcphdr
*
tcph
;
int
data_len
;
u32
hcsum
;
QETH_DBF_TEXT
(
trace
,
5
,
"eddpftcp"
);
eddp
->
skb_offset
=
sizeof
(
struct
qeth_hdr
)
+
eddp
->
nhl
+
eddp
->
thl
;
tcph
=
eddp
->
skb
->
h
.
th
;
...
...
@@ -464,7 +453,7 @@ __qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
else
hcsum
=
qeth_eddp_check_tcp6_hdr
(
eddp
,
data_len
);
/* fill the next segment into the context */
qeth_eddp_create_segment_hdrs
(
ctx
,
eddp
);
qeth_eddp_create_segment_hdrs
(
ctx
,
eddp
,
data_len
);
qeth_eddp_create_segment_data_tcp
(
ctx
,
eddp
,
data_len
,
hcsum
);
if
(
eddp
->
skb_offset
>=
eddp
->
skb
->
len
)
break
;
...
...
@@ -474,13 +463,13 @@ __qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
eddp
->
th
.
tcp
.
h
.
seq
+=
data_len
;
}
}
static
inline
int
qeth_eddp_fill_context_tcp
(
struct
qeth_eddp_context
*
ctx
,
struct
sk_buff
*
skb
,
struct
qeth_hdr
*
qhdr
)
{
struct
qeth_eddp_data
*
eddp
=
NULL
;
QETH_DBF_TEXT
(
trace
,
5
,
"eddpficx"
);
/* create our segmentation headers and copy original headers */
if
(
skb
->
protocol
==
ETH_P_IP
)
...
...
@@ -520,7 +509,7 @@ qeth_eddp_calc_num_pages(struct qeth_eddp_context *ctx, struct sk_buff *skb,
int
hdr_len
)
{
int
skbs_per_page
;
QETH_DBF_TEXT
(
trace
,
5
,
"eddpcanp"
);
/* can we put multiple skbs in one page? */
skbs_per_page
=
PAGE_SIZE
/
(
skb_shinfo
(
skb
)
->
tso_size
+
hdr_len
);
...
...
@@ -600,7 +589,7 @@ qeth_eddp_create_context_tcp(struct qeth_card *card, struct sk_buff *skb,
struct
qeth_hdr
*
qhdr
)
{
struct
qeth_eddp_context
*
ctx
=
NULL
;
QETH_DBF_TEXT
(
trace
,
5
,
"creddpct"
);
if
(
skb
->
protocol
==
ETH_P_IP
)
ctx
=
qeth_eddp_create_context_generic
(
card
,
skb
,
...
...
drivers/s390/net/qeth_main.c
浏览文件 @
8a75e7d6
/*
*
* linux/drivers/s390/net/qeth_main.c ($Revision: 1.2
06
$)
* linux/drivers/s390/net/qeth_main.c ($Revision: 1.2
14
$)
*
* Linux on zSeries OSA Express and HiperSockets support
*
...
...
@@ -12,7 +12,7 @@
* Frank Pavlic (pavlic@de.ibm.com) and
* Thomas Spatzier <tspat@de.ibm.com>
*
* $Revision: 1.2
06 $ $Date: 2005/03/24 09:04
:18 $
* $Revision: 1.2
14 $ $Date: 2005/05/04 20:19
:18 $
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
...
...
@@ -80,7 +80,7 @@ qeth_eyecatcher(void)
#include "qeth_eddp.h"
#include "qeth_tso.h"
#define VERSION_QETH_C "$Revision: 1.2
06
$"
#define VERSION_QETH_C "$Revision: 1.2
14
$"
static
const
char
*
version
=
"qeth S/390 OSA-Express driver"
;
/**
...
...
@@ -158,6 +158,9 @@ qeth_irq_tasklet(unsigned long);
static
int
qeth_set_online
(
struct
ccwgroup_device
*
);
static
int
__qeth_set_online
(
struct
ccwgroup_device
*
gdev
,
int
recovery_mode
);
static
struct
qeth_ipaddr
*
qeth_get_addr_buffer
(
enum
qeth_prot_versions
);
...
...
@@ -510,10 +513,10 @@ qeth_irq_tasklet(unsigned long data)
wake_up
(
&
card
->
wait_q
);
}
static
int
qeth_stop_card
(
struct
qeth_card
*
);
static
int
qeth_stop_card
(
struct
qeth_card
*
,
int
);
static
int
qeth_set_offline
(
struct
ccwgroup_device
*
cgdev
)
__qeth_set_offline
(
struct
ccwgroup_device
*
cgdev
,
int
recovery_mode
)
{
struct
qeth_card
*
card
=
(
struct
qeth_card
*
)
cgdev
->
dev
.
driver_data
;
int
rc
=
0
;
...
...
@@ -523,7 +526,7 @@ qeth_set_offline(struct ccwgroup_device *cgdev)
QETH_DBF_HEX
(
setup
,
3
,
&
card
,
sizeof
(
void
*
));
recover_flag
=
card
->
state
;
if
(
qeth_stop_card
(
card
)
==
-
ERESTARTSYS
){
if
(
qeth_stop_card
(
card
,
recovery_mode
)
==
-
ERESTARTSYS
){
PRINT_WARN
(
"Stopping card %s interrupted by user!
\n
"
,
CARD_BUS_ID
(
card
));
return
-
ERESTARTSYS
;
...
...
@@ -539,6 +542,12 @@ qeth_set_offline(struct ccwgroup_device *cgdev)
return
0
;
}
static
int
qeth_set_offline
(
struct
ccwgroup_device
*
cgdev
)
{
return
__qeth_set_offline
(
cgdev
,
0
);
}
static
int
qeth_wait_for_threads
(
struct
qeth_card
*
card
,
unsigned
long
threads
);
...
...
@@ -953,8 +962,8 @@ qeth_recover(void *ptr)
PRINT_WARN
(
"Recovery of device %s started ...
\n
"
,
CARD_BUS_ID
(
card
));
card
->
use_hard_stop
=
1
;
qeth_set_offline
(
card
->
gdev
);
rc
=
qeth_set_online
(
card
->
gdev
);
__qeth_set_offline
(
card
->
gdev
,
1
);
rc
=
__qeth_set_online
(
card
->
gdev
,
1
);
if
(
!
rc
)
PRINT_INFO
(
"Device %s successfully recovered!
\n
"
,
CARD_BUS_ID
(
card
));
...
...
@@ -2152,9 +2161,15 @@ qeth_get_next_skb(struct qeth_card *card, struct qdio_buffer *buffer,
if
(
!
skb_len
)
return
NULL
;
if
(
card
->
options
.
fake_ll
){
if
(
!
(
skb
=
qeth_get_skb
(
skb_len
+
QETH_FAKE_LL_LEN
)))
goto
no_mem
;
skb_pull
(
skb
,
QETH_FAKE_LL_LEN
);
if
(
card
->
dev
->
type
==
ARPHRD_IEEE802_TR
){
if
(
!
(
skb
=
qeth_get_skb
(
skb_len
+
QETH_FAKE_LL_LEN_TR
)))
goto
no_mem
;
skb_reserve
(
skb
,
QETH_FAKE_LL_LEN_TR
);
}
else
{
if
(
!
(
skb
=
qeth_get_skb
(
skb_len
+
QETH_FAKE_LL_LEN_ETH
)))
goto
no_mem
;
skb_reserve
(
skb
,
QETH_FAKE_LL_LEN_ETH
);
}
}
else
if
(
!
(
skb
=
qeth_get_skb
(
skb_len
)))
goto
no_mem
;
data_ptr
=
element
->
addr
+
offset
;
...
...
@@ -2229,14 +2244,68 @@ qeth_type_trans(struct sk_buff *skb, struct net_device *dev)
}
static
inline
void
qeth_rebuild_skb_fake_ll
(
struct
qeth_card
*
card
,
struct
sk_buff
*
skb
,
qeth_rebuild_skb_fake_ll_tr
(
struct
qeth_card
*
card
,
struct
sk_buff
*
skb
,
struct
qeth_hdr
*
hdr
)
{
struct
trh_hdr
*
fake_hdr
;
struct
trllc
*
fake_llc
;
struct
iphdr
*
ip_hdr
;
QETH_DBF_TEXT
(
trace
,
5
,
"skbfktr"
);
skb
->
mac
.
raw
=
skb
->
data
-
QETH_FAKE_LL_LEN_TR
;
/* this is a fake ethernet header */
fake_hdr
=
(
struct
trh_hdr
*
)
skb
->
mac
.
raw
;
/* the destination MAC address */
switch
(
skb
->
pkt_type
){
case
PACKET_MULTICAST
:
switch
(
skb
->
protocol
){
#ifdef CONFIG_QETH_IPV6
case
__constant_htons
(
ETH_P_IPV6
):
ndisc_mc_map
((
struct
in6_addr
*
)
skb
->
data
+
QETH_FAKE_LL_V6_ADDR_POS
,
fake_hdr
->
daddr
,
card
->
dev
,
0
);
break
;
#endif
/* CONFIG_QETH_IPV6 */
case
__constant_htons
(
ETH_P_IP
):
ip_hdr
=
(
struct
iphdr
*
)
skb
->
data
;
ip_tr_mc_map
(
ip_hdr
->
daddr
,
fake_hdr
->
daddr
);
break
;
default:
memcpy
(
fake_hdr
->
daddr
,
card
->
dev
->
dev_addr
,
TR_ALEN
);
}
break
;
case
PACKET_BROADCAST
:
memset
(
fake_hdr
->
daddr
,
0xff
,
TR_ALEN
);
break
;
default:
memcpy
(
fake_hdr
->
daddr
,
card
->
dev
->
dev_addr
,
TR_ALEN
);
}
/* the source MAC address */
if
(
hdr
->
hdr
.
l3
.
ext_flags
&
QETH_HDR_EXT_SRC_MAC_ADDR
)
memcpy
(
fake_hdr
->
saddr
,
&
hdr
->
hdr
.
l3
.
dest_addr
[
2
],
TR_ALEN
);
else
memset
(
fake_hdr
->
saddr
,
0
,
TR_ALEN
);
fake_hdr
->
rcf
=
0
;
fake_llc
=
(
struct
trllc
*
)
&
(
fake_hdr
->
rcf
);
fake_llc
->
dsap
=
EXTENDED_SAP
;
fake_llc
->
ssap
=
EXTENDED_SAP
;
fake_llc
->
llc
=
UI_CMD
;
fake_llc
->
protid
[
0
]
=
0
;
fake_llc
->
protid
[
1
]
=
0
;
fake_llc
->
protid
[
2
]
=
0
;
fake_llc
->
ethertype
=
ETH_P_IP
;
}
static
inline
void
qeth_rebuild_skb_fake_ll_eth
(
struct
qeth_card
*
card
,
struct
sk_buff
*
skb
,
struct
qeth_hdr
*
hdr
)
{
struct
ethhdr
*
fake_hdr
;
struct
iphdr
*
ip_hdr
;
QETH_DBF_TEXT
(
trace
,
5
,
"skbf
ake
"
);
skb
->
mac
.
raw
=
skb
->
data
-
QETH_FAKE_LL_LEN
;
QETH_DBF_TEXT
(
trace
,
5
,
"skbf
keth
"
);
skb
->
mac
.
raw
=
skb
->
data
-
QETH_FAKE_LL_LEN
_ETH
;
/* this is a fake ethernet header */
fake_hdr
=
(
struct
ethhdr
*
)
skb
->
mac
.
raw
;
...
...
@@ -2253,10 +2322,7 @@ qeth_rebuild_skb_fake_ll(struct qeth_card *card, struct sk_buff *skb,
#endif
/* CONFIG_QETH_IPV6 */
case
__constant_htons
(
ETH_P_IP
):
ip_hdr
=
(
struct
iphdr
*
)
skb
->
data
;
if
(
card
->
dev
->
type
==
ARPHRD_IEEE802_TR
)
ip_tr_mc_map
(
ip_hdr
->
daddr
,
fake_hdr
->
h_dest
);
else
ip_eth_mc_map
(
ip_hdr
->
daddr
,
fake_hdr
->
h_dest
);
ip_eth_mc_map
(
ip_hdr
->
daddr
,
fake_hdr
->
h_dest
);
break
;
default:
memcpy
(
fake_hdr
->
h_dest
,
card
->
dev
->
dev_addr
,
ETH_ALEN
);
...
...
@@ -2277,6 +2343,16 @@ qeth_rebuild_skb_fake_ll(struct qeth_card *card, struct sk_buff *skb,
fake_hdr
->
h_proto
=
skb
->
protocol
;
}
static
inline
void
qeth_rebuild_skb_fake_ll
(
struct
qeth_card
*
card
,
struct
sk_buff
*
skb
,
struct
qeth_hdr
*
hdr
)
{
if
(
card
->
dev
->
type
==
ARPHRD_IEEE802_TR
)
qeth_rebuild_skb_fake_ll_tr
(
card
,
skb
,
hdr
);
else
qeth_rebuild_skb_fake_ll_eth
(
card
,
skb
,
hdr
);
}
static
inline
void
qeth_rebuild_skb_vlan
(
struct
qeth_card
*
card
,
struct
sk_buff
*
skb
,
struct
qeth_hdr
*
hdr
)
...
...
@@ -3440,16 +3516,25 @@ qeth_fake_header(struct sk_buff *skb, struct net_device *dev,
unsigned
short
type
,
void
*
daddr
,
void
*
saddr
,
unsigned
len
)
{
struct
ethhdr
*
hdr
;
if
(
dev
->
type
==
ARPHRD_IEEE802_TR
){
struct
trh_hdr
*
hdr
;
hdr
=
(
struct
trh_hdr
*
)
skb_push
(
skb
,
QETH_FAKE_LL_LEN_TR
);
memcpy
(
hdr
->
saddr
,
dev
->
dev_addr
,
TR_ALEN
);
memcpy
(
hdr
->
daddr
,
"FAKELL"
,
TR_ALEN
);
return
QETH_FAKE_LL_LEN_TR
;
}
else
{
struct
ethhdr
*
hdr
;
hdr
=
(
struct
ethhdr
*
)
skb_push
(
skb
,
QETH_FAKE_LL_LEN_ETH
);
memcpy
(
hdr
->
h_source
,
dev
->
dev_addr
,
ETH_ALEN
);
memcpy
(
hdr
->
h_dest
,
"FAKELL"
,
ETH_ALEN
);
if
(
type
!=
ETH_P_802_3
)
hdr
->
h_proto
=
htons
(
type
);
else
hdr
->
h_proto
=
htons
(
len
);
return
QETH_FAKE_LL_LEN_ETH
;
hdr
=
(
struct
ethhdr
*
)
skb_push
(
skb
,
QETH_FAKE_LL_LEN
);
memcpy
(
hdr
->
h_source
,
dev
->
dev_addr
,
ETH_ALEN
);
memcpy
(
hdr
->
h_dest
,
"FAKELL"
,
ETH_ALEN
);
if
(
type
!=
ETH_P_802_3
)
hdr
->
h_proto
=
htons
(
type
);
else
hdr
->
h_proto
=
htons
(
len
);
return
QETH_FAKE_LL_LEN
;
}
}
static
inline
int
...
...
@@ -3710,16 +3795,12 @@ static inline int
qeth_prepare_skb
(
struct
qeth_card
*
card
,
struct
sk_buff
**
skb
,
struct
qeth_hdr
**
hdr
,
int
ipv
)
{
int
rc
=
0
;
#ifdef CONFIG_QETH_VLAN
u16
*
tag
;
#endif
QETH_DBF_TEXT
(
trace
,
6
,
"prepskb"
);
rc
=
qeth_realloc_headroom
(
card
,
skb
,
sizeof
(
struct
qeth_hdr
));
if
(
rc
)
return
rc
;
#ifdef CONFIG_QETH_VLAN
if
(
card
->
vlangrp
&&
vlan_tx_tag_present
(
*
skb
)
&&
((
ipv
==
6
)
||
card
->
options
.
layer2
)
)
{
...
...
@@ -3882,9 +3963,15 @@ qeth_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
memcpy
(
hdr
->
hdr
.
l3
.
dest_addr
,
&
skb
->
nh
.
ipv6h
->
daddr
,
16
);
}
}
else
{
/* passthrough */
if
(
!
memcmp
(
skb
->
data
+
sizeof
(
struct
qeth_hdr
),
if
((
skb
->
dev
->
type
==
ARPHRD_IEEE802_TR
)
&&
!
memcmp
(
skb
->
data
+
sizeof
(
struct
qeth_hdr
)
+
sizeof
(
__u16
),
skb
->
dev
->
broadcast
,
6
))
{
hdr
->
hdr
.
l3
.
flags
=
QETH_CAST_BROADCAST
|
QETH_HDR_PASSTHRU
;
}
else
if
(
!
memcmp
(
skb
->
data
+
sizeof
(
struct
qeth_hdr
),
skb
->
dev
->
broadcast
,
6
))
{
/* broadcast? */
hdr
->
hdr
.
l3
.
flags
=
QETH_CAST_BROADCAST
|
QETH_HDR_PASSTHRU
;
hdr
->
hdr
.
l3
.
flags
=
QETH_CAST_BROADCAST
|
QETH_HDR_PASSTHRU
;
}
else
{
hdr
->
hdr
.
l3
.
flags
=
(
cast_type
==
RTN_MULTICAST
)
?
QETH_CAST_MULTICAST
|
QETH_HDR_PASSTHRU
:
...
...
@@ -3893,68 +3980,30 @@ qeth_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
}
}
static
inline
void
__qeth_fill_buffer_frag
(
struct
sk_buff
*
skb
,
struct
qdio_buffer
*
buffer
,
int
*
next_element_to_fill
)
{
int
length
=
skb
->
len
;
struct
skb_frag_struct
*
frag
;
int
fragno
;
unsigned
long
addr
;
int
element
;
int
first_lap
=
1
;
fragno
=
skb_shinfo
(
skb
)
->
nr_frags
;
/* start with last frag */
element
=
*
next_element_to_fill
+
fragno
;
while
(
length
>
0
)
{
if
(
fragno
>
0
)
{
frag
=
&
skb_shinfo
(
skb
)
->
frags
[
fragno
-
1
];
addr
=
(
page_to_pfn
(
frag
->
page
)
<<
PAGE_SHIFT
)
+
frag
->
page_offset
;
buffer
->
element
[
element
].
addr
=
(
char
*
)
addr
;
buffer
->
element
[
element
].
length
=
frag
->
size
;
length
-=
frag
->
size
;
if
(
first_lap
)
buffer
->
element
[
element
].
flags
=
SBAL_FLAGS_LAST_FRAG
;
else
buffer
->
element
[
element
].
flags
=
SBAL_FLAGS_MIDDLE_FRAG
;
}
else
{
buffer
->
element
[
element
].
addr
=
skb
->
data
;
buffer
->
element
[
element
].
length
=
length
;
length
=
0
;
buffer
->
element
[
element
].
flags
=
SBAL_FLAGS_FIRST_FRAG
;
}
element
--
;
fragno
--
;
first_lap
=
0
;
}
*
next_element_to_fill
+=
skb_shinfo
(
skb
)
->
nr_frags
+
1
;
}
static
inline
void
__qeth_fill_buffer
(
struct
sk_buff
*
skb
,
struct
qdio_buffer
*
buffer
,
int
*
next_element_to_fill
)
int
is_tso
,
int
*
next_element_to_fill
)
{
int
length
=
skb
->
len
;
int
length_here
;
int
element
;
char
*
data
;
int
first_lap
=
1
;
int
first_lap
;
element
=
*
next_element_to_fill
;
data
=
skb
->
data
;
first_lap
=
(
is_tso
==
0
?
1
:
0
);
while
(
length
>
0
)
{
/* length_here is the remaining amount of data in this page */
length_here
=
PAGE_SIZE
-
((
unsigned
long
)
data
%
PAGE_SIZE
);
if
(
length
<
length_here
)
length_here
=
length
;
buffer
->
element
[
element
].
addr
=
data
;
buffer
->
element
[
element
].
length
=
length_here
;
length
-=
length_here
;
if
(
!
length
){
if
(
!
length
)
{
if
(
first_lap
)
buffer
->
element
[
element
].
flags
=
0
;
else
...
...
@@ -3981,17 +4030,35 @@ qeth_fill_buffer(struct qeth_qdio_out_q *queue,
struct
sk_buff
*
skb
)
{
struct
qdio_buffer
*
buffer
;
int
flush_cnt
=
0
;
struct
qeth_hdr_tso
*
hdr
;
int
flush_cnt
=
0
,
hdr_len
,
large_send
=
0
;
QETH_DBF_TEXT
(
trace
,
6
,
"qdfillbf"
);
buffer
=
buf
->
buffer
;
atomic_inc
(
&
skb
->
users
);
skb_queue_tail
(
&
buf
->
skb_list
,
skb
);
hdr
=
(
struct
qeth_hdr_tso
*
)
skb
->
data
;
/*check first on TSO ....*/
if
(
hdr
->
hdr
.
hdr
.
l3
.
id
==
QETH_HEADER_TYPE_TSO
)
{
int
element
=
buf
->
next_element_to_fill
;
hdr_len
=
sizeof
(
struct
qeth_hdr_tso
)
+
hdr
->
ext
.
dg_hdr_len
;
/*fill first buffer entry only with header information */
buffer
->
element
[
element
].
addr
=
skb
->
data
;
buffer
->
element
[
element
].
length
=
hdr_len
;
buffer
->
element
[
element
].
flags
=
SBAL_FLAGS_FIRST_FRAG
;
buf
->
next_element_to_fill
++
;
skb
->
data
+=
hdr_len
;
skb
->
len
-=
hdr_len
;
large_send
=
1
;
}
if
(
skb_shinfo
(
skb
)
->
nr_frags
==
0
)
__qeth_fill_buffer
(
skb
,
buffer
,
__qeth_fill_buffer
(
skb
,
buffer
,
large_send
,
(
int
*
)
&
buf
->
next_element_to_fill
);
else
__qeth_fill_buffer_frag
(
skb
,
buffer
,
__qeth_fill_buffer_frag
(
skb
,
buffer
,
large_send
,
(
int
*
)
&
buf
->
next_element_to_fill
);
if
(
!
queue
->
do_pack
)
{
...
...
@@ -4183,6 +4250,25 @@ qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue,
return
rc
;
}
static
inline
int
qeth_get_elements_no
(
struct
qeth_card
*
card
,
void
*
hdr
,
struct
sk_buff
*
skb
)
{
int
elements_needed
=
0
;
if
(
skb_shinfo
(
skb
)
->
nr_frags
>
0
)
{
elements_needed
=
(
skb_shinfo
(
skb
)
->
nr_frags
+
1
);
}
if
(
elements_needed
==
0
)
elements_needed
=
1
+
(((((
unsigned
long
)
hdr
)
%
PAGE_SIZE
)
+
skb
->
len
)
>>
PAGE_SHIFT
);
if
(
elements_needed
>
QETH_MAX_BUFFER_ELEMENTS
(
card
)){
PRINT_ERR
(
"qeth_do_send_packet: invalid size of "
"IP packet. Discarded."
);
return
0
;
}
return
elements_needed
;
}
static
inline
int
qeth_send_packet
(
struct
qeth_card
*
card
,
struct
sk_buff
*
skb
)
{
...
...
@@ -4205,7 +4291,11 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
dev_kfree_skb_irq
(
skb
);
return
0
;
}
skb_pull
(
skb
,
QETH_FAKE_LL_LEN
);
if
(
card
->
dev
->
type
==
ARPHRD_IEEE802_TR
){
skb_pull
(
skb
,
QETH_FAKE_LL_LEN_TR
);
}
else
{
skb_pull
(
skb
,
QETH_FAKE_LL_LEN_ETH
);
}
}
}
cast_type
=
qeth_get_cast_type
(
card
,
skb
);
...
...
@@ -4221,19 +4311,25 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
if
(
skb_shinfo
(
skb
)
->
tso_size
)
large_send
=
card
->
options
.
large_send
;
if
((
rc
=
qeth_prepare_skb
(
card
,
&
skb
,
&
hdr
,
ipv
))){
QETH_DBF_TEXT_
(
trace
,
4
,
"pskbe%d"
,
rc
);
return
rc
;
}
/*are we able to do TSO ? If so ,prepare and send it from here */
if
((
large_send
==
QETH_LARGE_SEND_TSO
)
&&
(
cast_type
==
RTN_UNSPEC
))
{
rc
=
qeth_tso_send_packet
(
card
,
skb
,
queue
,
ipv
,
cast_type
);
goto
do_statistics
;
rc
=
qeth_tso_prepare_packet
(
card
,
skb
,
ipv
,
cast_type
);
if
(
rc
)
{
card
->
stats
.
tx_dropped
++
;
card
->
stats
.
tx_errors
++
;
dev_kfree_skb_any
(
skb
);
return
NETDEV_TX_OK
;
}
elements_needed
++
;
}
else
{
if
((
rc
=
qeth_prepare_skb
(
card
,
&
skb
,
&
hdr
,
ipv
)))
{
QETH_DBF_TEXT_
(
trace
,
4
,
"pskbe%d"
,
rc
);
return
rc
;
}
qeth_fill_header
(
card
,
hdr
,
skb
,
ipv
,
cast_type
);
}
qeth_fill_header
(
card
,
hdr
,
skb
,
ipv
,
cast_type
);
if
(
large_send
==
QETH_LARGE_SEND_EDDP
)
{
ctx
=
qeth_eddp_create_context
(
card
,
skb
,
hdr
);
if
(
ctx
==
NULL
)
{
...
...
@@ -4241,7 +4337,7 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
return
-
EINVAL
;
}
}
else
{
elements_needed
=
qeth_get_elements_no
(
card
,(
void
*
)
hdr
,
skb
);
elements_needed
+
=
qeth_get_elements_no
(
card
,(
void
*
)
hdr
,
skb
);
if
(
!
elements_needed
)
return
-
EINVAL
;
}
...
...
@@ -4252,12 +4348,12 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
else
rc
=
qeth_do_send_packet_fast
(
card
,
queue
,
skb
,
hdr
,
elements_needed
,
ctx
);
do_statistics:
if
(
!
rc
){
card
->
stats
.
tx_packets
++
;
card
->
stats
.
tx_bytes
+=
skb
->
len
;
#ifdef CONFIG_QETH_PERF_STATS
if
(
skb_shinfo
(
skb
)
->
tso_size
)
{
if
(
skb_shinfo
(
skb
)
->
tso_size
&&
!
(
large_send
==
QETH_LARGE_SEND_NO
))
{
card
->
perf_stats
.
large_send_bytes
+=
skb
->
len
;
card
->
perf_stats
.
large_send_cnt
++
;
}
...
...
@@ -7154,7 +7250,7 @@ qeth_wait_for_threads(struct qeth_card *card, unsigned long threads)
}
static
int
qeth_stop_card
(
struct
qeth_card
*
card
)
qeth_stop_card
(
struct
qeth_card
*
card
,
int
recovery_mode
)
{
int
rc
=
0
;
...
...
@@ -7167,9 +7263,13 @@ qeth_stop_card(struct qeth_card *card)
if
(
card
->
read
.
state
==
CH_STATE_UP
&&
card
->
write
.
state
==
CH_STATE_UP
&&
(
card
->
state
==
CARD_STATE_UP
))
{
rtnl_lock
();
dev_close
(
card
->
dev
);
rtnl_unlock
();
if
(
recovery_mode
)
{
qeth_stop
(
card
->
dev
);
}
else
{
rtnl_lock
();
dev_close
(
card
->
dev
);
rtnl_unlock
();
}
if
(
!
card
->
use_hard_stop
)
{
__u8
*
mac
=
&
card
->
dev
->
dev_addr
[
0
];
rc
=
qeth_layer2_send_delmac
(
card
,
mac
);
...
...
@@ -7341,13 +7441,17 @@ qeth_register_netdev(struct qeth_card *card)
}
static
void
qeth_start_again
(
struct
qeth_card
*
card
)
qeth_start_again
(
struct
qeth_card
*
card
,
int
recovery_mode
)
{
QETH_DBF_TEXT
(
setup
,
2
,
"startag"
);
rtnl_lock
();
dev_open
(
card
->
dev
);
rtnl_unlock
();
if
(
recovery_mode
)
{
qeth_open
(
card
->
dev
);
}
else
{
rtnl_lock
();
dev_open
(
card
->
dev
);
rtnl_unlock
();
}
/* this also sets saved unicast addresses */
qeth_set_multicast_list
(
card
->
dev
);
}
...
...
@@ -7404,7 +7508,7 @@ static void qeth_make_parameters_consistent(struct qeth_card *card)
static
int
qeth_set_online
(
struct
ccwgroup_device
*
gdev
)
__qeth_set_online
(
struct
ccwgroup_device
*
gdev
,
int
recovery_mode
)
{
struct
qeth_card
*
card
=
gdev
->
dev
.
driver_data
;
int
rc
=
0
;
...
...
@@ -7464,12 +7568,12 @@ qeth_set_online(struct ccwgroup_device *gdev)
* we can also use this state for recovery purposes*/
qeth_set_allowed_threads
(
card
,
0xffffffff
,
0
);
if
(
recover_flag
==
CARD_STATE_RECOVER
)
qeth_start_again
(
card
);
qeth_start_again
(
card
,
recovery_mode
);
qeth_notify_processes
();
return
0
;
out_remove:
card
->
use_hard_stop
=
1
;
qeth_stop_card
(
card
);
qeth_stop_card
(
card
,
0
);
ccw_device_set_offline
(
CARD_DDEV
(
card
));
ccw_device_set_offline
(
CARD_WDEV
(
card
));
ccw_device_set_offline
(
CARD_RDEV
(
card
));
...
...
@@ -7480,6 +7584,12 @@ qeth_set_online(struct ccwgroup_device *gdev)
return
-
ENODEV
;
}
static
int
qeth_set_online
(
struct
ccwgroup_device
*
gdev
)
{
return
__qeth_set_online
(
gdev
,
0
);
}
static
struct
ccw_device_id
qeth_ids
[]
=
{
{
CCW_DEVICE
(
0x1731
,
0x01
),
driver_info
:
QETH_CARD_TYPE_OSAE
},
{
CCW_DEVICE
(
0x1731
,
0x05
),
driver_info
:
QETH_CARD_TYPE_IQD
},
...
...
drivers/s390/net/qeth_tso.c
已删除
100644 → 0
浏览文件 @
f5a702b2
/*
* linux/drivers/s390/net/qeth_tso.c ($Revision: 1.6 $)
*
* Header file for qeth TCP Segmentation Offload support.
*
* Copyright 2004 IBM Corporation
*
* Author(s): Frank Pavlic <pavlic@de.ibm.com>
*
* $Revision: 1.6 $ $Date: 2005/03/24 09:04:18 $
*
*/
#include <linux/skbuff.h>
#include <linux/tcp.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <net/ip6_checksum.h>
#include "qeth.h"
#include "qeth_mpc.h"
#include "qeth_tso.h"
/**
* skb already partially prepared
* classic qdio header in skb->data
* */
static
inline
struct
qeth_hdr_tso
*
qeth_tso_prepare_skb
(
struct
qeth_card
*
card
,
struct
sk_buff
**
skb
)
{
int
rc
=
0
;
QETH_DBF_TEXT
(
trace
,
5
,
"tsoprsk"
);
rc
=
qeth_realloc_headroom
(
card
,
skb
,
sizeof
(
struct
qeth_hdr_ext_tso
));
if
(
rc
)
return
NULL
;
return
qeth_push_skb
(
card
,
skb
,
sizeof
(
struct
qeth_hdr_ext_tso
));
}
/**
* fill header for a TSO packet
*/
static
inline
void
qeth_tso_fill_header
(
struct
qeth_card
*
card
,
struct
sk_buff
*
skb
)
{
struct
qeth_hdr_tso
*
hdr
;
struct
tcphdr
*
tcph
;
struct
iphdr
*
iph
;
QETH_DBF_TEXT
(
trace
,
5
,
"tsofhdr"
);
hdr
=
(
struct
qeth_hdr_tso
*
)
skb
->
data
;
iph
=
skb
->
nh
.
iph
;
tcph
=
skb
->
h
.
th
;
/*fix header to TSO values ...*/
hdr
->
hdr
.
hdr
.
l3
.
id
=
QETH_HEADER_TYPE_TSO
;
/*set values which are fix for the first approach ...*/
hdr
->
ext
.
hdr_tot_len
=
(
__u16
)
sizeof
(
struct
qeth_hdr_ext_tso
);
hdr
->
ext
.
imb_hdr_no
=
1
;
hdr
->
ext
.
hdr_type
=
1
;
hdr
->
ext
.
hdr_version
=
1
;
hdr
->
ext
.
hdr_len
=
28
;
/*insert non-fix values */
hdr
->
ext
.
mss
=
skb_shinfo
(
skb
)
->
tso_size
;
hdr
->
ext
.
dg_hdr_len
=
(
__u16
)(
iph
->
ihl
*
4
+
tcph
->
doff
*
4
);
hdr
->
ext
.
payload_len
=
(
__u16
)(
skb
->
len
-
hdr
->
ext
.
dg_hdr_len
-
sizeof
(
struct
qeth_hdr_tso
));
}
/**
* change some header values as requested by hardware
*/
static
inline
void
qeth_tso_set_tcpip_header
(
struct
qeth_card
*
card
,
struct
sk_buff
*
skb
)
{
struct
iphdr
*
iph
;
struct
ipv6hdr
*
ip6h
;
struct
tcphdr
*
tcph
;
iph
=
skb
->
nh
.
iph
;
ip6h
=
skb
->
nh
.
ipv6h
;
tcph
=
skb
->
h
.
th
;
tcph
->
check
=
0
;
if
(
skb
->
protocol
==
ETH_P_IPV6
)
{
ip6h
->
payload_len
=
0
;
tcph
->
check
=
~
csum_ipv6_magic
(
&
ip6h
->
saddr
,
&
ip6h
->
daddr
,
0
,
IPPROTO_TCP
,
0
);
return
;
}
/*OSA want us to set these values ...*/
tcph
->
check
=
~
csum_tcpudp_magic
(
iph
->
saddr
,
iph
->
daddr
,
0
,
IPPROTO_TCP
,
0
);
iph
->
tot_len
=
0
;
iph
->
check
=
0
;
}
static
inline
struct
qeth_hdr_tso
*
qeth_tso_prepare_packet
(
struct
qeth_card
*
card
,
struct
sk_buff
*
skb
,
int
ipv
,
int
cast_type
)
{
struct
qeth_hdr_tso
*
hdr
;
int
rc
=
0
;
QETH_DBF_TEXT
(
trace
,
5
,
"tsoprep"
);
/*get headroom for tso qdio header */
hdr
=
(
struct
qeth_hdr_tso
*
)
qeth_tso_prepare_skb
(
card
,
&
skb
);
if
(
hdr
==
NULL
)
{
QETH_DBF_TEXT_
(
trace
,
4
,
"2err%d"
,
rc
);
return
NULL
;
}
memset
(
hdr
,
0
,
sizeof
(
struct
qeth_hdr_tso
));
/*fill first 32 bytes of qdio header as used
*FIXME: TSO has two struct members
* with different names but same size
* */
qeth_fill_header
(
card
,
&
hdr
->
hdr
,
skb
,
ipv
,
cast_type
);
qeth_tso_fill_header
(
card
,
skb
);
qeth_tso_set_tcpip_header
(
card
,
skb
);
return
hdr
;
}
static
inline
int
qeth_tso_get_queue_buffer
(
struct
qeth_qdio_out_q
*
queue
)
{
struct
qeth_qdio_out_buffer
*
buffer
;
int
flush_cnt
=
0
;
QETH_DBF_TEXT
(
trace
,
5
,
"tsobuf"
);
/* force to non-packing*/
if
(
queue
->
do_pack
)
queue
->
do_pack
=
0
;
buffer
=
&
queue
->
bufs
[
queue
->
next_buf_to_fill
];
/* get a new buffer if current is already in use*/
if
((
atomic_read
(
&
buffer
->
state
)
==
QETH_QDIO_BUF_EMPTY
)
&&
(
buffer
->
next_element_to_fill
>
0
))
{
atomic_set
(
&
buffer
->
state
,
QETH_QDIO_BUF_PRIMED
);
queue
->
next_buf_to_fill
=
(
queue
->
next_buf_to_fill
+
1
)
%
QDIO_MAX_BUFFERS_PER_Q
;
flush_cnt
++
;
}
return
flush_cnt
;
}
static
inline
void
__qeth_tso_fill_buffer_frag
(
struct
qeth_qdio_out_buffer
*
buf
,
struct
sk_buff
*
skb
)
{
struct
skb_frag_struct
*
frag
;
struct
qdio_buffer
*
buffer
;
int
fragno
,
cnt
,
element
;
unsigned
long
addr
;
QETH_DBF_TEXT
(
trace
,
6
,
"tsfilfrg"
);
/*initialize variables ...*/
fragno
=
skb_shinfo
(
skb
)
->
nr_frags
;
buffer
=
buf
->
buffer
;
element
=
buf
->
next_element_to_fill
;
/*fill buffer elements .....*/
for
(
cnt
=
0
;
cnt
<
fragno
;
cnt
++
)
{
frag
=
&
skb_shinfo
(
skb
)
->
frags
[
cnt
];
addr
=
(
page_to_pfn
(
frag
->
page
)
<<
PAGE_SHIFT
)
+
frag
->
page_offset
;
buffer
->
element
[
element
].
addr
=
(
char
*
)
addr
;
buffer
->
element
[
element
].
length
=
frag
->
size
;
if
(
cnt
<
(
fragno
-
1
))
buffer
->
element
[
element
].
flags
=
SBAL_FLAGS_MIDDLE_FRAG
;
else
buffer
->
element
[
element
].
flags
=
SBAL_FLAGS_LAST_FRAG
;
element
++
;
}
buf
->
next_element_to_fill
=
element
;
}
static
inline
int
qeth_tso_fill_buffer
(
struct
qeth_qdio_out_buffer
*
buf
,
struct
sk_buff
*
skb
)
{
int
length
,
length_here
,
element
;
int
hdr_len
;
struct
qdio_buffer
*
buffer
;
struct
qeth_hdr_tso
*
hdr
;
char
*
data
;
QETH_DBF_TEXT
(
trace
,
3
,
"tsfilbuf"
);
/*increment user count and queue skb ...*/
atomic_inc
(
&
skb
->
users
);
skb_queue_tail
(
&
buf
->
skb_list
,
skb
);
/*initialize all variables...*/
buffer
=
buf
->
buffer
;
hdr
=
(
struct
qeth_hdr_tso
*
)
skb
->
data
;
hdr_len
=
sizeof
(
struct
qeth_hdr_tso
)
+
hdr
->
ext
.
dg_hdr_len
;
data
=
skb
->
data
+
hdr_len
;
length
=
skb
->
len
-
hdr_len
;
element
=
buf
->
next_element_to_fill
;
/*fill first buffer entry only with header information */
buffer
->
element
[
element
].
addr
=
skb
->
data
;
buffer
->
element
[
element
].
length
=
hdr_len
;
buffer
->
element
[
element
].
flags
=
SBAL_FLAGS_FIRST_FRAG
;
buf
->
next_element_to_fill
++
;
if
(
skb_shinfo
(
skb
)
->
nr_frags
>
0
)
{
__qeth_tso_fill_buffer_frag
(
buf
,
skb
);
goto
out
;
}
/*start filling buffer entries ...*/
element
++
;
while
(
length
>
0
)
{
/* length_here is the remaining amount of data in this page */
length_here
=
PAGE_SIZE
-
((
unsigned
long
)
data
%
PAGE_SIZE
);
if
(
length
<
length_here
)
length_here
=
length
;
buffer
->
element
[
element
].
addr
=
data
;
buffer
->
element
[
element
].
length
=
length_here
;
length
-=
length_here
;
if
(
!
length
)
buffer
->
element
[
element
].
flags
=
SBAL_FLAGS_LAST_FRAG
;
else
buffer
->
element
[
element
].
flags
=
SBAL_FLAGS_MIDDLE_FRAG
;
data
+=
length_here
;
element
++
;
}
/*set the buffer to primed ...*/
buf
->
next_element_to_fill
=
element
;
out:
atomic_set
(
&
buf
->
state
,
QETH_QDIO_BUF_PRIMED
);
return
1
;
}
int
qeth_tso_send_packet
(
struct
qeth_card
*
card
,
struct
sk_buff
*
skb
,
struct
qeth_qdio_out_q
*
queue
,
int
ipv
,
int
cast_type
)
{
int
flush_cnt
=
0
;
struct
qeth_hdr_tso
*
hdr
;
struct
qeth_qdio_out_buffer
*
buffer
;
int
start_index
;
QETH_DBF_TEXT
(
trace
,
3
,
"tsosend"
);
if
(
!
(
hdr
=
qeth_tso_prepare_packet
(
card
,
skb
,
ipv
,
cast_type
)))
return
-
ENOMEM
;
/*check if skb fits in one SBAL ...*/
if
(
!
(
qeth_get_elements_no
(
card
,
(
void
*
)
hdr
,
skb
)))
return
-
EINVAL
;
/*lock queue, force switching to non-packing and send it ...*/
while
(
atomic_compare_and_swap
(
QETH_OUT_Q_UNLOCKED
,
QETH_OUT_Q_LOCKED
,
&
queue
->
state
));
start_index
=
queue
->
next_buf_to_fill
;
buffer
=
&
queue
->
bufs
[
queue
->
next_buf_to_fill
];
/*check if card is too busy ...*/
if
(
atomic_read
(
&
buffer
->
state
)
!=
QETH_QDIO_BUF_EMPTY
){
card
->
stats
.
tx_dropped
++
;
goto
out
;
}
/*let's force to non-packing and get a new SBAL*/
flush_cnt
+=
qeth_tso_get_queue_buffer
(
queue
);
buffer
=
&
queue
->
bufs
[
queue
->
next_buf_to_fill
];
if
(
atomic_read
(
&
buffer
->
state
)
!=
QETH_QDIO_BUF_EMPTY
)
{
card
->
stats
.
tx_dropped
++
;
goto
out
;
}
flush_cnt
+=
qeth_tso_fill_buffer
(
buffer
,
skb
);
queue
->
next_buf_to_fill
=
(
queue
->
next_buf_to_fill
+
1
)
%
QDIO_MAX_BUFFERS_PER_Q
;
out:
atomic_set
(
&
queue
->
state
,
QETH_OUT_Q_UNLOCKED
);
if
(
flush_cnt
)
qeth_flush_buffers
(
queue
,
0
,
start_index
,
flush_cnt
);
/*do some statistics */
card
->
stats
.
tx_packets
++
;
card
->
stats
.
tx_bytes
+=
skb
->
len
;
return
0
;
}
drivers/s390/net/qeth_tso.h
浏览文件 @
8a75e7d6
/*
* linux/drivers/s390/net/qeth_tso.h ($Revision: 1.
4
$)
* linux/drivers/s390/net/qeth_tso.h ($Revision: 1.
7
$)
*
* Header file for qeth TCP Segmentation Offload support.
*
...
...
@@ -7,52 +7,148 @@
*
* Author(s): Frank Pavlic <pavlic@de.ibm.com>
*
* $Revision: 1.
4 $ $Date: 2005/03/24 09:04
:18 $
* $Revision: 1.
7 $ $Date: 2005/05/04 20:19
:18 $
*
*/
#ifndef __QETH_TSO_H__
#define __QETH_TSO_H__
#include <linux/skbuff.h>
#include <linux/tcp.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <net/ip6_checksum.h>
#include "qeth.h"
#include "qeth_mpc.h"
extern
int
qeth_tso_send_packet
(
struct
qeth_card
*
,
struct
sk_buff
*
,
struct
qeth_qdio_out_q
*
,
int
,
int
);
struct
qeth_hdr_ext_tso
{
__u16
hdr_tot_len
;
__u8
imb_hdr_no
;
__u8
reserved
;
__u8
hdr_type
;
__u8
hdr_version
;
__u16
hdr_len
;
__u32
payload_len
;
__u16
mss
;
__u16
dg_hdr_len
;
__u8
padding
[
16
];
}
__attribute__
((
packed
));
static
inline
struct
qeth_hdr_tso
*
qeth_tso_prepare_skb
(
struct
qeth_card
*
card
,
struct
sk_buff
**
skb
)
{
QETH_DBF_TEXT
(
trace
,
5
,
"tsoprsk"
);
return
qeth_push_skb
(
card
,
skb
,
sizeof
(
struct
qeth_hdr_tso
));
}
/**
* fill header for a TSO packet
*/
static
inline
void
qeth_tso_fill_header
(
struct
qeth_card
*
card
,
struct
sk_buff
*
skb
)
{
struct
qeth_hdr_tso
*
hdr
;
struct
tcphdr
*
tcph
;
struct
iphdr
*
iph
;
QETH_DBF_TEXT
(
trace
,
5
,
"tsofhdr"
);
hdr
=
(
struct
qeth_hdr_tso
*
)
skb
->
data
;
iph
=
skb
->
nh
.
iph
;
tcph
=
skb
->
h
.
th
;
/*fix header to TSO values ...*/
hdr
->
hdr
.
hdr
.
l3
.
id
=
QETH_HEADER_TYPE_TSO
;
/*set values which are fix for the first approach ...*/
hdr
->
ext
.
hdr_tot_len
=
(
__u16
)
sizeof
(
struct
qeth_hdr_ext_tso
);
hdr
->
ext
.
imb_hdr_no
=
1
;
hdr
->
ext
.
hdr_type
=
1
;
hdr
->
ext
.
hdr_version
=
1
;
hdr
->
ext
.
hdr_len
=
28
;
/*insert non-fix values */
hdr
->
ext
.
mss
=
skb_shinfo
(
skb
)
->
tso_size
;
hdr
->
ext
.
dg_hdr_len
=
(
__u16
)(
iph
->
ihl
*
4
+
tcph
->
doff
*
4
);
hdr
->
ext
.
payload_len
=
(
__u16
)(
skb
->
len
-
hdr
->
ext
.
dg_hdr_len
-
sizeof
(
struct
qeth_hdr_tso
));
}
/**
* change some header values as requested by hardware
*/
static
inline
void
qeth_tso_set_tcpip_header
(
struct
qeth_card
*
card
,
struct
sk_buff
*
skb
)
{
struct
iphdr
*
iph
;
struct
ipv6hdr
*
ip6h
;
struct
tcphdr
*
tcph
;
struct
qeth_hdr_tso
{
struct
qeth_hdr
hdr
;
/*hdr->hdr.l3.xxx*/
struct
qeth_hdr_ext_tso
ext
;
}
__attribute__
((
packed
));
iph
=
skb
->
nh
.
iph
;
ip6h
=
skb
->
nh
.
ipv6h
;
tcph
=
skb
->
h
.
th
;
/*some helper functions*/
tcph
->
check
=
0
;
if
(
skb
->
protocol
==
ETH_P_IPV6
)
{
ip6h
->
payload_len
=
0
;
tcph
->
check
=
~
csum_ipv6_magic
(
&
ip6h
->
saddr
,
&
ip6h
->
daddr
,
0
,
IPPROTO_TCP
,
0
);
return
;
}
/*OSA want us to set these values ...*/
tcph
->
check
=
~
csum_tcpudp_magic
(
iph
->
saddr
,
iph
->
daddr
,
0
,
IPPROTO_TCP
,
0
);
iph
->
tot_len
=
0
;
iph
->
check
=
0
;
}
static
inline
int
qeth_get_elements_no
(
struct
qeth_card
*
card
,
void
*
hdr
,
struct
sk_buff
*
skb
)
qeth_tso_prepare_packet
(
struct
qeth_card
*
card
,
struct
sk_buff
*
skb
,
int
ipv
,
int
cast_type
)
{
struct
qeth_hdr_tso
*
hdr
;
QETH_DBF_TEXT
(
trace
,
5
,
"tsoprep"
);
hdr
=
(
struct
qeth_hdr_tso
*
)
qeth_tso_prepare_skb
(
card
,
&
skb
);
if
(
hdr
==
NULL
)
{
QETH_DBF_TEXT
(
trace
,
4
,
"tsoperr"
);
return
-
ENOMEM
;
}
memset
(
hdr
,
0
,
sizeof
(
struct
qeth_hdr_tso
));
/*fill first 32 bytes of qdio header as used
*FIXME: TSO has two struct members
* with different names but same size
* */
qeth_fill_header
(
card
,
&
hdr
->
hdr
,
skb
,
ipv
,
cast_type
);
qeth_tso_fill_header
(
card
,
skb
);
qeth_tso_set_tcpip_header
(
card
,
skb
);
return
0
;
}
static
inline
void
__qeth_fill_buffer_frag
(
struct
sk_buff
*
skb
,
struct
qdio_buffer
*
buffer
,
int
is_tso
,
int
*
next_element_to_fill
)
{
int
elements_needed
=
0
;
if
(
skb_shinfo
(
skb
)
->
nr_frags
>
0
)
elements_needed
=
(
skb_shinfo
(
skb
)
->
nr_frags
+
1
);
if
(
elements_needed
==
0
)
elements_needed
=
1
+
(((((
unsigned
long
)
hdr
)
%
PAGE_SIZE
)
+
skb
->
len
)
>>
PAGE_SHIFT
);
if
(
elements_needed
>
QETH_MAX_BUFFER_ELEMENTS
(
card
)){
PRINT_ERR
(
"qeth_do_send_packet: invalid size of "
"IP packet. Discarded."
);
return
0
;
struct
skb_frag_struct
*
frag
;
int
fragno
;
unsigned
long
addr
;
int
element
,
cnt
,
dlen
;
fragno
=
skb_shinfo
(
skb
)
->
nr_frags
;
element
=
*
next_element_to_fill
;
dlen
=
0
;
if
(
is_tso
)
buffer
->
element
[
element
].
flags
=
SBAL_FLAGS_MIDDLE_FRAG
;
else
buffer
->
element
[
element
].
flags
=
SBAL_FLAGS_FIRST_FRAG
;
if
(
(
dlen
=
(
skb
->
len
-
skb
->
data_len
))
)
{
buffer
->
element
[
element
].
addr
=
skb
->
data
;
buffer
->
element
[
element
].
length
=
dlen
;
element
++
;
}
for
(
cnt
=
0
;
cnt
<
fragno
;
cnt
++
)
{
frag
=
&
skb_shinfo
(
skb
)
->
frags
[
cnt
];
addr
=
(
page_to_pfn
(
frag
->
page
)
<<
PAGE_SHIFT
)
+
frag
->
page_offset
;
buffer
->
element
[
element
].
addr
=
(
char
*
)
addr
;
buffer
->
element
[
element
].
length
=
frag
->
size
;
if
(
cnt
<
(
fragno
-
1
))
buffer
->
element
[
element
].
flags
=
SBAL_FLAGS_MIDDLE_FRAG
;
else
buffer
->
element
[
element
].
flags
=
SBAL_FLAGS_LAST_FRAG
;
element
++
;
}
return
elements_needed
;
*
next_element_to_fill
=
element
;
}
#endif
/* __QETH_TSO_H__ */
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录