Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
8a75e7d6
Commit
8a75e7d6
authored
May 25, 2005
by
Committed by
Jeff Garzik
May 25, 2005
Browse files
Options
Browse Files
Download
Plain Diff
Automatic merge of /spare/repo/netdev-2.6 branch qeth
parents
f5a702b2
05e08a2a
Changes
14
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
914 additions
and
901 deletions
+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
No files found.
drivers/s390/net/Makefile
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
deleted
100644 → 0
View file @
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
View file @
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__ */
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment