#include <linux/trdevice.h>
#include <linux/etherdevice.h>
#include <linux/if_vlan.h>
+#include <linux/ctype.h>
#include <net/ipv6.h>
#include <linux/in6.h>
#include <net/addrconf.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
+
#include <asm/debug.h>
#include <asm/qdio.h>
#include <asm/ccwdev.h>
#include "qeth_mpc.h"
-#define VERSION_QETH_H "$Revision: 1.110 $"
-
#ifdef CONFIG_QETH_IPV6
#define QETH_VERSION_IPV6 ":IPv6"
#else
*/
#define QETH_DBF_SETUP_NAME "qeth_setup"
#define QETH_DBF_SETUP_LEN 8
-#define QETH_DBF_SETUP_INDEX 3
+#define QETH_DBF_SETUP_PAGES 8
#define QETH_DBF_SETUP_NR_AREAS 1
-#define QETH_DBF_SETUP_LEVEL 3
+#define QETH_DBF_SETUP_LEVEL 5
#define QETH_DBF_MISC_NAME "qeth_misc"
#define QETH_DBF_MISC_LEN 128
-#define QETH_DBF_MISC_INDEX 1
+#define QETH_DBF_MISC_PAGES 2
#define QETH_DBF_MISC_NR_AREAS 1
#define QETH_DBF_MISC_LEVEL 2
#define QETH_DBF_DATA_NAME "qeth_data"
#define QETH_DBF_DATA_LEN 96
-#define QETH_DBF_DATA_INDEX 3
+#define QETH_DBF_DATA_PAGES 8
#define QETH_DBF_DATA_NR_AREAS 1
#define QETH_DBF_DATA_LEVEL 2
#define QETH_DBF_CONTROL_NAME "qeth_control"
#define QETH_DBF_CONTROL_LEN 256
-#define QETH_DBF_CONTROL_INDEX 3
+#define QETH_DBF_CONTROL_PAGES 8
#define QETH_DBF_CONTROL_NR_AREAS 2
-#define QETH_DBF_CONTROL_LEVEL 2
+#define QETH_DBF_CONTROL_LEVEL 5
#define QETH_DBF_TRACE_NAME "qeth_trace"
#define QETH_DBF_TRACE_LEN 8
-#define QETH_DBF_TRACE_INDEX 2
+#define QETH_DBF_TRACE_PAGES 4
#define QETH_DBF_TRACE_NR_AREAS 2
#define QETH_DBF_TRACE_LEVEL 3
+extern debug_info_t *qeth_dbf_trace;
#define QETH_DBF_SENSE_NAME "qeth_sense"
#define QETH_DBF_SENSE_LEN 64
-#define QETH_DBF_SENSE_INDEX 1
+#define QETH_DBF_SENSE_PAGES 2
#define QETH_DBF_SENSE_NR_AREAS 1
#define QETH_DBF_SENSE_LEVEL 2
#define QETH_DBF_QERR_NAME "qeth_qerr"
#define QETH_DBF_QERR_LEN 8
-#define QETH_DBF_QERR_INDEX 1
+#define QETH_DBF_QERR_PAGES 2
#define QETH_DBF_QERR_NR_AREAS 2
#define QETH_DBF_QERR_LEVEL 2
debug_event(qeth_dbf_##name,level,(void*)(addr),len); \
} while (0)
-extern DEFINE_PER_CPU(char[256], qeth_dbf_txt_buf);
+DECLARE_PER_CPU(char[256], qeth_dbf_txt_buf);
#define QETH_DBF_TEXT_(name,level,text...) \
do { \
#define SENSE_RESETTING_EVENT_BYTE 1
#define SENSE_RESETTING_EVENT_FLAG 0x80
+#define atomic_swap(a,b) xchg((int *)a.counter, b)
+
/*
* Common IO related definitions
*/
__u64 outbound_do_qdio_start_time;
unsigned int outbound_do_qdio_cnt;
unsigned int outbound_do_qdio_time;
+ /* eddp data */
+ unsigned int large_send_bytes;
+ unsigned int large_send_cnt;
+ unsigned int sg_skbs_sent;
+ unsigned int sg_frags_sent;
};
#endif /* CONFIG_QETH_PERF_STATS */
QETH_IDX_FUNC_LEVEL_IQD_ENA_IPAT, \
QETH_IDX_FUNC_LEVEL_IQD_DIS_IPAT, \
QETH_MAX_QUEUES,0x103}, \
+ {0x1731,0x06,0x1732,0x06,QETH_CARD_TYPE_OSN,0, \
+ QETH_IDX_FUNC_LEVEL_OSAE_ENA_IPAT, \
+ QETH_IDX_FUNC_LEVEL_OSAE_DIS_IPAT, \
+ QETH_MAX_QUEUES,0}, \
{0,0,0,0,0,0,0,0,0}}
#define QETH_REAL_CARD 1
#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*/
#define QETH_WATERMARK_PACK_FUZZ 1
#define QETH_IP_HEADER_SIZE 40
-/* VLAN defines */
-#define QETH_EXT_HDR_VLAN_FRAME 0x01
-#define QETH_EXT_HDR_TOKEN_ID 0x02
-#define QETH_EXT_HDR_INCLUDE_VLAN_TAG 0x04
-struct qeth_hdr {
+struct qeth_hdr_layer3 {
__u8 id;
__u8 flags;
- __u16 inbound_checksum;
- __u32 token;
+ __u16 inbound_checksum; /*TSO:__u16 seqno */
+ __u32 token; /*TSO: __u32 reserved */
__u16 length;
__u8 vlan_prio;
__u8 ext_flags;
__u8 dest_addr[16];
} __attribute__ ((packed));
+struct qeth_hdr_layer2 {
+ __u8 id;
+ __u8 flags[3];
+ __u8 port_no;
+ __u8 hdr_length;
+ __u16 pkt_length;
+ __u16 seq_no;
+ __u16 vlan_id;
+ __u32 reserved;
+ __u8 reserved2[16];
+} __attribute__ ((packed));
+
+struct qeth_hdr_osn {
+ __u8 id;
+ __u8 reserved;
+ __u16 seq_no;
+ __u16 reserved2;
+ __u16 control_flags;
+ __u16 pdu_length;
+ __u8 reserved3[18];
+ __u32 ccid;
+} __attribute__ ((packed));
+
+struct qeth_hdr {
+ union {
+ struct qeth_hdr_layer2 l2;
+ struct qeth_hdr_layer3 l3;
+ struct qeth_hdr_osn osn;
+ } 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
#define QETH_HDR_IPV6 0x80
QETH_CAST_NOCAST = 0x00,
};
+enum qeth_layer2_frame_flags {
+ QETH_LAYER2_FLAG_MULTICAST = 0x01,
+ QETH_LAYER2_FLAG_BROADCAST = 0x02,
+ QETH_LAYER2_FLAG_UNICAST = 0x04,
+ QETH_LAYER2_FLAG_VLAN = 0x10,
+};
+
+enum qeth_header_ids {
+ QETH_HEADER_TYPE_LAYER3 = 0x01,
+ QETH_HEADER_TYPE_LAYER2 = 0x02,
+ QETH_HEADER_TYPE_TSO = 0x03,
+ QETH_HEADER_TYPE_OSN = 0x04,
+};
/* flags for qeth_hdr.ext_flags */
-#define QETH_HDR_EXT_VLAN_FRAME 0x01
-#define QETH_HDR_EXT_CSUM_HDR_REQ 0x10
-#define QETH_HDR_EXT_CSUM_TRANSP_REQ 0x20
-#define QETH_HDR_EXT_SRC_MAC_ADDR 0x08
+#define QETH_HDR_EXT_VLAN_FRAME 0x01
+#define QETH_HDR_EXT_TOKEN_ID 0x02
+#define QETH_HDR_EXT_INCLUDE_VLAN_TAG 0x04
+#define QETH_HDR_EXT_SRC_MAC_ADDR 0x08
+#define QETH_HDR_EXT_CSUM_HDR_REQ 0x10
+#define QETH_HDR_EXT_CSUM_TRANSP_REQ 0x20
+#define QETH_HDR_EXT_UDP_TSO 0x40 /*bit off for TCP*/
static inline int
qeth_is_last_sbale(struct qdio_buffer_element *sbale)
volatile int next_buf_to_init;
} __attribute__ ((aligned(256)));
+/* possible types of qeth large_send support */
+enum qeth_large_send_types {
+ QETH_LARGE_SEND_NO,
+ QETH_LARGE_SEND_EDDP,
+ QETH_LARGE_SEND_TSO,
+};
+
struct qeth_qdio_out_buffer {
struct qdio_buffer *buffer;
atomic_t state;
volatile int next_element_to_fill;
struct sk_buff_head skb_list;
+ struct list_head ctx_list;
};
struct qeth_card;
+enum qeth_out_q_states {
+ QETH_OUT_Q_UNLOCKED,
+ QETH_OUT_Q_LOCKED,
+ QETH_OUT_Q_LOCKED_FLUSH,
+};
+
struct qeth_qdio_out_q {
struct qdio_buffer qdio_bufs[QDIO_MAX_BUFFERS_PER_Q];
struct qeth_qdio_out_buffer bufs[QDIO_MAX_BUFFERS_PER_Q];
int queue_no;
struct qeth_card *card;
- spinlock_t lock;
+ atomic_t state;
volatile int do_pack;
/*
* index of buffer to be filled by driver; state EMPTY or PACKING
* Protocol versions
*/
enum qeth_prot_versions {
- QETH_PROT_SNA = 0x0001,
QETH_PROT_IPV4 = 0x0004,
QETH_PROT_IPV6 = 0x0006,
};
QETH_IP_TYPE_NORMAL,
QETH_IP_TYPE_VIPA,
QETH_IP_TYPE_RXIP,
+ QETH_IP_TYPE_DEL_ALL_MC,
};
enum qeth_cmd_buffer_state {
__u32 trans_hdr;
__u32 pdu_hdr;
__u32 pdu_hdr_ack;
- __u32 ipa;
+ __u16 ipa;
+ __u32 pkt_seqno;
};
struct qeth_reply {
struct list_head list;
wait_queue_head_t wait_q;
int (*callback)(struct qeth_card *,struct qeth_reply *,unsigned long);
- int seqno;
+ u32 seqno;
unsigned long offset;
int received;
int rc;
atomic_t refcnt;
};
-#define QETH_BROADCAST_WITH_ECHO 1
-#define QETH_BROADCAST_WITHOUT_ECHO 2
+struct qeth_card_blkt {
+ int time_total;
+ int inter_packet;
+ int inter_packet_jumbo;
+};
+
+#define QETH_BROADCAST_WITH_ECHO 0x01
+#define QETH_BROADCAST_WITHOUT_ECHO 0x02
+#define QETH_LAYER2_MAC_READ 0x01
+#define QETH_LAYER2_MAC_REGISTERED 0x02
struct qeth_card_info {
- char if_name[IF_NAME_LEN];
unsigned short unit_addr2;
unsigned short cula;
unsigned short chpid;
__u16 func_level;
char mcl_level[QETH_MCL_LENGTH + 1];
int guestlan;
+ int mac_bits;
int portname_required;
int portno;
char portname[9];
int max_mtu;
int broadcast_capable;
int unique_id;
+ struct qeth_card_blkt blkt;
__u32 csum_mask;
+ enum qeth_ipa_promisc_modes promisc_mode;
};
struct qeth_card_options {
int fake_broadcast;
int add_hhlen;
int fake_ll;
+ int layer2;
+ enum qeth_large_send_types large_send;
};
/*
*/
enum qeth_threads {
QETH_SET_IP_THREAD = 1,
- QETH_SET_MC_THREAD = 2,
- QETH_RECOVER_THREAD = 4,
+ QETH_RECOVER_THREAD = 2,
+ QETH_SET_PROMISC_MODE_THREAD = 4,
+};
+
+struct qeth_osn_info {
+ int (*assist_cb)(struct net_device *dev, void *data);
+ int (*data_cb)(struct sk_buff *skb);
};
struct qeth_card {
volatile unsigned long thread_running_mask;
spinlock_t ip_lock;
struct list_head ip_list;
- struct list_head ip_tbd_list;
+ struct list_head *ip_tbd_list;
struct qeth_ipato ipato;
struct list_head cmd_waiter_list;
/* QDIO buffer handling */
struct qeth_perf_stats perf_stats;
#endif /* CONFIG_QETH_PERF_STATS */
int use_hard_stop;
+ int (*orig_hard_header)(struct sk_buff *,struct net_device *,
+ unsigned short,void *,void *,unsigned);
+ struct qeth_osn_info osn_info;
};
struct qeth_card_list_struct {
/*some helper functions*/
-inline static __u8
+#define QETH_CARD_IFNAME(card) (((card)->dev)? (card)->dev->name : "")
+
+static inline __u8
qeth_get_ipa_adp_type(enum qeth_link_types link_type)
{
switch (link_type) {
}
}
-inline static int
+static inline int
+qeth_realloc_headroom(struct qeth_card *card, struct sk_buff **skb, int size)
+{
+ struct sk_buff *new_skb = NULL;
+
+ if (skb_headroom(*skb) < size){
+ new_skb = skb_realloc_headroom(*skb, size);
+ if (!new_skb) {
+ PRINT_ERR("qeth_prepare_skb: could "
+ "not realloc headroom for qeth_hdr "
+ "on interface %s", QETH_CARD_IFNAME(card));
+ return -ENOMEM;
+ }
+ kfree_skb(*skb);
+ *skb = new_skb;
+ }
+ return 0;
+}
+
+static inline struct sk_buff *
+qeth_pskb_unshare(struct sk_buff *skb, int pri)
+{
+ struct sk_buff *nskb;
+ if (!skb_cloned(skb))
+ return skb;
+ nskb = skb_copy(skb, pri);
+ kfree_skb(skb); /* free our shared copy */
+ return nskb;
+}
+
+static inline void *
+qeth_push_skb(struct qeth_card *card, struct sk_buff **skb, int size)
+{
+ void *hdr;
+
+ hdr = (void *) skb_push(*skb, size);
+ /*
+ * sanity check, the Linux memory allocation scheme should
+ * never present us cases like this one (the qdio header size plus
+ * the first 40 bytes of the paket cross a 4k boundary)
+ */
+ if ((((unsigned long) hdr) & (~(PAGE_SIZE - 1))) !=
+ (((unsigned long) hdr + size +
+ QETH_IP_HEADER_SIZE) & (~(PAGE_SIZE - 1)))) {
+ PRINT_ERR("qeth_prepare_skb: misaligned "
+ "packet on interface %s. Discarded.",
+ QETH_CARD_IFNAME(card));
+ return NULL;
+ }
+ return hdr;
+}
+
+
+static inline int
qeth_get_hlen(__u8 link_type)
{
#ifdef CONFIG_QETH_IPV6
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 */
}
-inline static unsigned short
-qeth_get_netdev_flags(int cardtype)
+static inline unsigned short
+qeth_get_netdev_flags(struct qeth_card *card)
{
- switch (cardtype) {
+ if (card->options.layer2 &&
+ (card->info.type == QETH_CARD_TYPE_OSAE))
+ return 0;
+ switch (card->info.type) {
case QETH_CARD_TYPE_IQD:
+ case QETH_CARD_TYPE_OSN:
return IFF_NOARP;
#ifdef CONFIG_QETH_IPV6
default:
}
}
-inline static int
+static inline int
qeth_get_initial_mtu_for_card(struct qeth_card * card)
{
switch (card->info.type) {
}
}
-inline static int
+static inline int
qeth_get_max_mtu_for_card(int cardtype)
{
switch (cardtype) {
+
case QETH_CARD_TYPE_UNKNOWN:
- return 61440;
case QETH_CARD_TYPE_OSAE:
+ case QETH_CARD_TYPE_OSN:
return 61440;
case QETH_CARD_TYPE_IQD:
return 57344;
}
}
-inline static int
+static inline int
qeth_get_mtu_out_of_mpc(int cardtype)
{
switch (cardtype) {
}
}
-inline static int
+static inline int
qeth_get_mtu_outof_framesize(int framesize)
{
switch (framesize) {
}
}
-inline static int
+static inline int
qeth_mtu_is_valid(struct qeth_card * card, int mtu)
{
switch (card->info.type) {
case QETH_CARD_TYPE_IQD:
return ((mtu >= 576) &&
(mtu <= card->info.max_mtu + 4096 - 32));
+ case QETH_CARD_TYPE_OSN:
case QETH_CARD_TYPE_UNKNOWN:
default:
return 1;
}
}
-inline static int
+static inline int
qeth_get_arphdr_type(int cardtype, int linktype)
{
switch (cardtype) {
case QETH_CARD_TYPE_OSAE:
+ case QETH_CARD_TYPE_OSN:
switch (linktype) {
case QETH_LINK_TYPE_LANE_TR:
case QETH_LINK_TYPE_HSTR:
}
#ifdef CONFIG_QETH_PERF_STATS
-inline static int
+static inline int
qeth_get_micros(void)
{
return (int) (get_clock() >> 12);
}
}
+static inline int
+qeth_isxdigit(char * buf)
+{
+ while (*buf) {
+ if (!isxdigit(*buf++))
+ return 0;
+ }
+ return 1;
+}
+
static inline void
qeth_ipaddr4_to_string(const __u8 *addr, char *buf)
{
static inline int
qeth_string_to_ipaddr4(const char *buf, __u8 *addr)
{
- const char *start, *end;
- char abuf[4];
- char *tmp;
- int len;
- int i;
-
- start = buf;
- for (i = 0; i < 3; i++) {
- if (!(end = strchr(start, '.')))
+ int count = 0, rc = 0;
+ int in[4];
+
+ rc = sscanf(buf, "%d.%d.%d.%d%n",
+ &in[0], &in[1], &in[2], &in[3], &count);
+ if (rc != 4 || count<=0)
+ return -EINVAL;
+ for (count = 0; count < 4; count++) {
+ if (in[count] > 255)
return -EINVAL;
- len = end - start;
- memset(abuf, 0, 4);
- strncpy(abuf, start, len);
- addr[i] = simple_strtoul(abuf, &tmp, 10);
- start = end + 1;
+ addr[count] = in[count];
}
- memset(abuf, 0, 4);
- strcpy(abuf, start);
- addr[3] = simple_strtoul(abuf, &tmp, 10);
return 0;
}
static inline int
qeth_string_to_ipaddr6(const char *buf, __u8 *addr)
{
- const char *start, *end;
- u16 *tmp_addr;
- char abuf[5];
- char *tmp;
- int len;
- int i;
-
- tmp_addr = (u16 *)addr;
- start = buf;
- for (i = 0; i < 7; i++) {
- if (!(end = strchr(start, ':')))
- return -EINVAL;
- len = end - start;
- memset(abuf, 0, 5);
- strncpy(abuf, start, len);
- tmp_addr[i] = simple_strtoul(abuf, &tmp, 16);
- start = end + 1;
- }
- memset(abuf, 0, 5);
- strcpy(abuf, start);
- tmp_addr[7] = simple_strtoul(abuf, &tmp, 16);
+ char *end, *start;
+ __u16 *in;
+ char num[5];
+ int num2, cnt, out, found, save_cnt;
+ unsigned short in_tmp[8] = {0, };
+
+ cnt = out = found = save_cnt = num2 = 0;
+ end = start = (char *) buf;
+ in = (__u16 *) addr;
+ memset(in, 0, 16);
+ while (end) {
+ end = strchr(end,':');
+ if (end == NULL) {
+ end = (char *)buf + (strlen(buf));
+ out = 1;
+ }
+ if ((end - start)) {
+ memset(num, 0, 5);
+ memcpy(num, start, end - start);
+ if (!qeth_isxdigit(num))
+ return -EINVAL;
+ sscanf(start, "%x", &num2);
+ if (found)
+ in_tmp[save_cnt++] = num2;
+ else
+ in[cnt++] = num2;
+ if (out)
+ break;
+ } else {
+ if (found)
+ return -EINVAL;
+ found = 1;
+ }
+ start = ++end;
+ }
+ cnt = 7;
+ while (save_cnt)
+ in[cnt--] = in_tmp[--save_cnt];
return 0;
}
extern int
qeth_realloc_buffer_pool(struct qeth_card *, int);
+
+extern int
+qeth_set_large_send(struct qeth_card *, enum qeth_large_send_types);
+
+extern void
+qeth_fill_header(struct qeth_card *, struct qeth_hdr *,
+ struct sk_buff *, int, int);
+extern void
+qeth_flush_buffers(struct qeth_qdio_out_q *, int, int, int);
+
+extern int
+qeth_osn_assist(struct net_device *, void *, int);
+
+extern int
+qeth_osn_register(unsigned char *read_dev_no,
+ struct net_device **,
+ int (*assist_cb)(struct net_device *, void *),
+ int (*data_cb)(struct sk_buff *));
+
+extern void
+qeth_osn_deregister(struct net_device *);
+
#endif /* __QETH_H__ */