diff options
Diffstat (limited to 'drivers/s390/net')
-rw-r--r-- | drivers/s390/net/Kconfig | 9 | ||||
-rw-r--r-- | drivers/s390/net/Makefile | 1 | ||||
-rw-r--r-- | drivers/s390/net/ctcmain.c | 3 | ||||
-rw-r--r-- | drivers/s390/net/iucv.c | 4 | ||||
-rw-r--r-- | drivers/s390/net/lcs.c | 13 | ||||
-rw-r--r-- | drivers/s390/net/netiucv.c | 80 | ||||
-rw-r--r-- | drivers/s390/net/qeth.h | 73 | ||||
-rw-r--r-- | drivers/s390/net/qeth_eddp.c | 5 | ||||
-rw-r--r-- | drivers/s390/net/qeth_main.c | 517 | ||||
-rw-r--r-- | drivers/s390/net/qeth_proc.c | 23 | ||||
-rw-r--r-- | drivers/s390/net/qeth_sys.c | 64 | ||||
-rw-r--r-- | drivers/s390/net/qeth_tso.h | 2 |
12 files changed, 453 insertions, 341 deletions
diff --git a/drivers/s390/net/Kconfig b/drivers/s390/net/Kconfig index 548854754921..1a93fa684e9f 100644 --- a/drivers/s390/net/Kconfig +++ b/drivers/s390/net/Kconfig | |||
@@ -92,15 +92,6 @@ config QETH_VLAN | |||
92 | If CONFIG_QETH is switched on, this option will include IEEE | 92 | If CONFIG_QETH is switched on, this option will include IEEE |
93 | 802.1q VLAN support in the qeth device driver. | 93 | 802.1q VLAN support in the qeth device driver. |
94 | 94 | ||
95 | config QETH_PERF_STATS | ||
96 | bool "Performance statistics in /proc" | ||
97 | depends on QETH | ||
98 | help | ||
99 | When switched on, this option will add a file in the proc-fs | ||
100 | (/proc/qeth_perf_stats) containing performance statistics. It | ||
101 | may slightly impact performance, so this is only recommended for | ||
102 | internal tuning of the device driver. | ||
103 | |||
104 | config CCWGROUP | 95 | config CCWGROUP |
105 | tristate | 96 | tristate |
106 | default (LCS || CTC || QETH) | 97 | default (LCS || CTC || QETH) |
diff --git a/drivers/s390/net/Makefile b/drivers/s390/net/Makefile index 6775a837d646..4777e36a922f 100644 --- a/drivers/s390/net/Makefile +++ b/drivers/s390/net/Makefile | |||
@@ -10,7 +10,6 @@ obj-$(CONFIG_SMSGIUCV) += smsgiucv.o | |||
10 | obj-$(CONFIG_CTC) += ctc.o fsm.o cu3088.o | 10 | obj-$(CONFIG_CTC) += ctc.o fsm.o cu3088.o |
11 | obj-$(CONFIG_LCS) += lcs.o cu3088.o | 11 | obj-$(CONFIG_LCS) += lcs.o cu3088.o |
12 | obj-$(CONFIG_CLAW) += claw.o cu3088.o | 12 | obj-$(CONFIG_CLAW) += claw.o cu3088.o |
13 | obj-$(CONFIG_MPC) += ctcmpc.o fsm.o cu3088.o | ||
14 | qeth-y := qeth_main.o qeth_mpc.o qeth_sys.o qeth_eddp.o | 13 | qeth-y := qeth_main.o qeth_mpc.o qeth_sys.o qeth_eddp.o |
15 | qeth-$(CONFIG_PROC_FS) += qeth_proc.o | 14 | qeth-$(CONFIG_PROC_FS) += qeth_proc.o |
16 | obj-$(CONFIG_QETH) += qeth.o | 15 | obj-$(CONFIG_QETH) += qeth.o |
diff --git a/drivers/s390/net/ctcmain.c b/drivers/s390/net/ctcmain.c index 8a4b58120146..3257c22dd79c 100644 --- a/drivers/s390/net/ctcmain.c +++ b/drivers/s390/net/ctcmain.c | |||
@@ -1714,6 +1714,9 @@ add_channel(struct ccw_device *cdev, enum channel_types type) | |||
1714 | kfree(ch); | 1714 | kfree(ch); |
1715 | return 0; | 1715 | return 0; |
1716 | } | 1716 | } |
1717 | |||
1718 | spin_lock_init(&ch->collect_lock); | ||
1719 | |||
1717 | fsm_settimer(ch->fsm, &ch->timer); | 1720 | fsm_settimer(ch->fsm, &ch->timer); |
1718 | skb_queue_head_init(&ch->io_queue); | 1721 | skb_queue_head_init(&ch->io_queue); |
1719 | skb_queue_head_init(&ch->collect_queue); | 1722 | skb_queue_head_init(&ch->collect_queue); |
diff --git a/drivers/s390/net/iucv.c b/drivers/s390/net/iucv.c index 0e863df4027a..821dde86e240 100644 --- a/drivers/s390/net/iucv.c +++ b/drivers/s390/net/iucv.c | |||
@@ -335,8 +335,8 @@ do { \ | |||
335 | 335 | ||
336 | #else | 336 | #else |
337 | 337 | ||
338 | #define iucv_debug(lvl, fmt, args...) | 338 | #define iucv_debug(lvl, fmt, args...) do { } while (0) |
339 | #define iucv_dumpit(title, buf, len) | 339 | #define iucv_dumpit(title, buf, len) do { } while (0) |
340 | 340 | ||
341 | #endif | 341 | #endif |
342 | 342 | ||
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index 2eded55ae88d..16ac68c27a27 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c | |||
@@ -670,9 +670,8 @@ lcs_ready_buffer(struct lcs_channel *channel, struct lcs_buffer *buffer) | |||
670 | int index, rc; | 670 | int index, rc; |
671 | 671 | ||
672 | LCS_DBF_TEXT(5, trace, "rdybuff"); | 672 | LCS_DBF_TEXT(5, trace, "rdybuff"); |
673 | if (buffer->state != BUF_STATE_LOCKED && | 673 | BUG_ON(buffer->state != BUF_STATE_LOCKED && |
674 | buffer->state != BUF_STATE_PROCESSED) | 674 | buffer->state != BUF_STATE_PROCESSED); |
675 | BUG(); | ||
676 | spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); | 675 | spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); |
677 | buffer->state = BUF_STATE_READY; | 676 | buffer->state = BUF_STATE_READY; |
678 | index = buffer - channel->iob; | 677 | index = buffer - channel->iob; |
@@ -696,8 +695,7 @@ __lcs_processed_buffer(struct lcs_channel *channel, struct lcs_buffer *buffer) | |||
696 | int index, prev, next; | 695 | int index, prev, next; |
697 | 696 | ||
698 | LCS_DBF_TEXT(5, trace, "prcsbuff"); | 697 | LCS_DBF_TEXT(5, trace, "prcsbuff"); |
699 | if (buffer->state != BUF_STATE_READY) | 698 | BUG_ON(buffer->state != BUF_STATE_READY); |
700 | BUG(); | ||
701 | buffer->state = BUF_STATE_PROCESSED; | 699 | buffer->state = BUF_STATE_PROCESSED; |
702 | index = buffer - channel->iob; | 700 | index = buffer - channel->iob; |
703 | prev = (index - 1) & (LCS_NUM_BUFFS - 1); | 701 | prev = (index - 1) & (LCS_NUM_BUFFS - 1); |
@@ -729,9 +727,8 @@ lcs_release_buffer(struct lcs_channel *channel, struct lcs_buffer *buffer) | |||
729 | unsigned long flags; | 727 | unsigned long flags; |
730 | 728 | ||
731 | LCS_DBF_TEXT(5, trace, "relbuff"); | 729 | LCS_DBF_TEXT(5, trace, "relbuff"); |
732 | if (buffer->state != BUF_STATE_LOCKED && | 730 | BUG_ON(buffer->state != BUF_STATE_LOCKED && |
733 | buffer->state != BUF_STATE_PROCESSED) | 731 | buffer->state != BUF_STATE_PROCESSED); |
734 | BUG(); | ||
735 | spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); | 732 | spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); |
736 | buffer->state = BUF_STATE_EMPTY; | 733 | buffer->state = BUF_STATE_EMPTY; |
737 | spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags); | 734 | spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags); |
diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index 5d6e6cbfa360..d7d1cc0a5c8e 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c | |||
@@ -112,7 +112,12 @@ struct iucv_connection { | |||
112 | /** | 112 | /** |
113 | * Linked list of all connection structs. | 113 | * Linked list of all connection structs. |
114 | */ | 114 | */ |
115 | static struct iucv_connection *iucv_connections; | 115 | struct iucv_connection_struct { |
116 | struct iucv_connection *iucv_connections; | ||
117 | rwlock_t iucv_rwlock; | ||
118 | }; | ||
119 | |||
120 | static struct iucv_connection_struct iucv_conns; | ||
116 | 121 | ||
117 | /** | 122 | /** |
118 | * Representation of event-data for the | 123 | * Representation of event-data for the |
@@ -1368,8 +1373,10 @@ user_write (struct device *dev, struct device_attribute *attr, const char *buf, | |||
1368 | struct net_device *ndev = priv->conn->netdev; | 1373 | struct net_device *ndev = priv->conn->netdev; |
1369 | char *p; | 1374 | char *p; |
1370 | char *tmp; | 1375 | char *tmp; |
1371 | char username[10]; | 1376 | char username[9]; |
1372 | int i; | 1377 | int i; |
1378 | struct iucv_connection **clist = &iucv_conns.iucv_connections; | ||
1379 | unsigned long flags; | ||
1373 | 1380 | ||
1374 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); | 1381 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); |
1375 | if (count>9) { | 1382 | if (count>9) { |
@@ -1382,7 +1389,7 @@ user_write (struct device *dev, struct device_attribute *attr, const char *buf, | |||
1382 | tmp = strsep((char **) &buf, "\n"); | 1389 | tmp = strsep((char **) &buf, "\n"); |
1383 | for (i=0, p=tmp; i<8 && *p; i++, p++) { | 1390 | for (i=0, p=tmp; i<8 && *p; i++, p++) { |
1384 | if (isalnum(*p) || (*p == '$')) | 1391 | if (isalnum(*p) || (*p == '$')) |
1385 | username[i]= *p; | 1392 | username[i]= toupper(*p); |
1386 | else if (*p == '\n') { | 1393 | else if (*p == '\n') { |
1387 | /* trailing lf, grr */ | 1394 | /* trailing lf, grr */ |
1388 | break; | 1395 | break; |
@@ -1395,11 +1402,11 @@ user_write (struct device *dev, struct device_attribute *attr, const char *buf, | |||
1395 | return -EINVAL; | 1402 | return -EINVAL; |
1396 | } | 1403 | } |
1397 | } | 1404 | } |
1398 | while (i<9) | 1405 | while (i<8) |
1399 | username[i++] = ' '; | 1406 | username[i++] = ' '; |
1400 | username[9] = '\0'; | 1407 | username[8] = '\0'; |
1401 | 1408 | ||
1402 | if (memcmp(username, priv->conn->userid, 8)) { | 1409 | if (memcmp(username, priv->conn->userid, 9)) { |
1403 | /* username changed */ | 1410 | /* username changed */ |
1404 | if (ndev->flags & (IFF_UP | IFF_RUNNING)) { | 1411 | if (ndev->flags & (IFF_UP | IFF_RUNNING)) { |
1405 | PRINT_WARN( | 1412 | PRINT_WARN( |
@@ -1410,6 +1417,19 @@ user_write (struct device *dev, struct device_attribute *attr, const char *buf, | |||
1410 | return -EBUSY; | 1417 | return -EBUSY; |
1411 | } | 1418 | } |
1412 | } | 1419 | } |
1420 | read_lock_irqsave(&iucv_conns.iucv_rwlock, flags); | ||
1421 | while (*clist) { | ||
1422 | if (!strncmp(username, (*clist)->userid, 9) || | ||
1423 | ((*clist)->netdev != ndev)) | ||
1424 | break; | ||
1425 | clist = &((*clist)->next); | ||
1426 | } | ||
1427 | read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); | ||
1428 | if (*clist) { | ||
1429 | PRINT_WARN("netiucv: Connection to %s already exists\n", | ||
1430 | username); | ||
1431 | return -EEXIST; | ||
1432 | } | ||
1413 | memcpy(priv->conn->userid, username, 9); | 1433 | memcpy(priv->conn->userid, username, 9); |
1414 | 1434 | ||
1415 | return count; | 1435 | return count; |
@@ -1781,13 +1801,15 @@ netiucv_unregister_device(struct device *dev) | |||
1781 | static struct iucv_connection * | 1801 | static struct iucv_connection * |
1782 | netiucv_new_connection(struct net_device *dev, char *username) | 1802 | netiucv_new_connection(struct net_device *dev, char *username) |
1783 | { | 1803 | { |
1784 | struct iucv_connection **clist = &iucv_connections; | 1804 | unsigned long flags; |
1805 | struct iucv_connection **clist = &iucv_conns.iucv_connections; | ||
1785 | struct iucv_connection *conn = | 1806 | struct iucv_connection *conn = |
1786 | kzalloc(sizeof(struct iucv_connection), GFP_KERNEL); | 1807 | kzalloc(sizeof(struct iucv_connection), GFP_KERNEL); |
1787 | 1808 | ||
1788 | if (conn) { | 1809 | if (conn) { |
1789 | skb_queue_head_init(&conn->collect_queue); | 1810 | skb_queue_head_init(&conn->collect_queue); |
1790 | skb_queue_head_init(&conn->commit_queue); | 1811 | skb_queue_head_init(&conn->commit_queue); |
1812 | spin_lock_init(&conn->collect_lock); | ||
1791 | conn->max_buffsize = NETIUCV_BUFSIZE_DEFAULT; | 1813 | conn->max_buffsize = NETIUCV_BUFSIZE_DEFAULT; |
1792 | conn->netdev = dev; | 1814 | conn->netdev = dev; |
1793 | 1815 | ||
@@ -1822,8 +1844,10 @@ netiucv_new_connection(struct net_device *dev, char *username) | |||
1822 | fsm_newstate(conn->fsm, CONN_STATE_STOPPED); | 1844 | fsm_newstate(conn->fsm, CONN_STATE_STOPPED); |
1823 | } | 1845 | } |
1824 | 1846 | ||
1847 | write_lock_irqsave(&iucv_conns.iucv_rwlock, flags); | ||
1825 | conn->next = *clist; | 1848 | conn->next = *clist; |
1826 | *clist = conn; | 1849 | *clist = conn; |
1850 | write_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); | ||
1827 | } | 1851 | } |
1828 | return conn; | 1852 | return conn; |
1829 | } | 1853 | } |
@@ -1835,14 +1859,17 @@ netiucv_new_connection(struct net_device *dev, char *username) | |||
1835 | static void | 1859 | static void |
1836 | netiucv_remove_connection(struct iucv_connection *conn) | 1860 | netiucv_remove_connection(struct iucv_connection *conn) |
1837 | { | 1861 | { |
1838 | struct iucv_connection **clist = &iucv_connections; | 1862 | struct iucv_connection **clist = &iucv_conns.iucv_connections; |
1863 | unsigned long flags; | ||
1839 | 1864 | ||
1840 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); | 1865 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); |
1841 | if (conn == NULL) | 1866 | if (conn == NULL) |
1842 | return; | 1867 | return; |
1868 | write_lock_irqsave(&iucv_conns.iucv_rwlock, flags); | ||
1843 | while (*clist) { | 1869 | while (*clist) { |
1844 | if (*clist == conn) { | 1870 | if (*clist == conn) { |
1845 | *clist = conn->next; | 1871 | *clist = conn->next; |
1872 | write_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); | ||
1846 | if (conn->handle) { | 1873 | if (conn->handle) { |
1847 | iucv_unregister_program(conn->handle); | 1874 | iucv_unregister_program(conn->handle); |
1848 | conn->handle = NULL; | 1875 | conn->handle = NULL; |
@@ -1855,6 +1882,7 @@ netiucv_remove_connection(struct iucv_connection *conn) | |||
1855 | } | 1882 | } |
1856 | clist = &((*clist)->next); | 1883 | clist = &((*clist)->next); |
1857 | } | 1884 | } |
1885 | write_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); | ||
1858 | } | 1886 | } |
1859 | 1887 | ||
1860 | /** | 1888 | /** |
@@ -1947,9 +1975,11 @@ static ssize_t | |||
1947 | conn_write(struct device_driver *drv, const char *buf, size_t count) | 1975 | conn_write(struct device_driver *drv, const char *buf, size_t count) |
1948 | { | 1976 | { |
1949 | char *p; | 1977 | char *p; |
1950 | char username[10]; | 1978 | char username[9]; |
1951 | int i, ret; | 1979 | int i, ret; |
1952 | struct net_device *dev; | 1980 | struct net_device *dev; |
1981 | struct iucv_connection **clist = &iucv_conns.iucv_connections; | ||
1982 | unsigned long flags; | ||
1953 | 1983 | ||
1954 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); | 1984 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); |
1955 | if (count>9) { | 1985 | if (count>9) { |
@@ -1960,7 +1990,7 @@ conn_write(struct device_driver *drv, const char *buf, size_t count) | |||
1960 | 1990 | ||
1961 | for (i=0, p=(char *)buf; i<8 && *p; i++, p++) { | 1991 | for (i=0, p=(char *)buf; i<8 && *p; i++, p++) { |
1962 | if (isalnum(*p) || (*p == '$')) | 1992 | if (isalnum(*p) || (*p == '$')) |
1963 | username[i]= *p; | 1993 | username[i]= toupper(*p); |
1964 | else if (*p == '\n') { | 1994 | else if (*p == '\n') { |
1965 | /* trailing lf, grr */ | 1995 | /* trailing lf, grr */ |
1966 | break; | 1996 | break; |
@@ -1971,9 +2001,22 @@ conn_write(struct device_driver *drv, const char *buf, size_t count) | |||
1971 | return -EINVAL; | 2001 | return -EINVAL; |
1972 | } | 2002 | } |
1973 | } | 2003 | } |
1974 | while (i<9) | 2004 | while (i<8) |
1975 | username[i++] = ' '; | 2005 | username[i++] = ' '; |
1976 | username[9] = '\0'; | 2006 | username[8] = '\0'; |
2007 | |||
2008 | read_lock_irqsave(&iucv_conns.iucv_rwlock, flags); | ||
2009 | while (*clist) { | ||
2010 | if (!strncmp(username, (*clist)->userid, 9)) | ||
2011 | break; | ||
2012 | clist = &((*clist)->next); | ||
2013 | } | ||
2014 | read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); | ||
2015 | if (*clist) { | ||
2016 | PRINT_WARN("netiucv: Connection to %s already exists\n", | ||
2017 | username); | ||
2018 | return -EEXIST; | ||
2019 | } | ||
1977 | dev = netiucv_init_netdevice(username); | 2020 | dev = netiucv_init_netdevice(username); |
1978 | if (!dev) { | 2021 | if (!dev) { |
1979 | PRINT_WARN( | 2022 | PRINT_WARN( |
@@ -2015,7 +2058,8 @@ DRIVER_ATTR(connection, 0200, NULL, conn_write); | |||
2015 | static ssize_t | 2058 | static ssize_t |
2016 | remove_write (struct device_driver *drv, const char *buf, size_t count) | 2059 | remove_write (struct device_driver *drv, const char *buf, size_t count) |
2017 | { | 2060 | { |
2018 | struct iucv_connection **clist = &iucv_connections; | 2061 | struct iucv_connection **clist = &iucv_conns.iucv_connections; |
2062 | unsigned long flags; | ||
2019 | struct net_device *ndev; | 2063 | struct net_device *ndev; |
2020 | struct netiucv_priv *priv; | 2064 | struct netiucv_priv *priv; |
2021 | struct device *dev; | 2065 | struct device *dev; |
@@ -2026,7 +2070,7 @@ remove_write (struct device_driver *drv, const char *buf, size_t count) | |||
2026 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); | 2070 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); |
2027 | 2071 | ||
2028 | if (count >= IFNAMSIZ) | 2072 | if (count >= IFNAMSIZ) |
2029 | count = IFNAMSIZ-1; | 2073 | count = IFNAMSIZ - 1;; |
2030 | 2074 | ||
2031 | for (i=0, p=(char *)buf; i<count && *p; i++, p++) { | 2075 | for (i=0, p=(char *)buf; i<count && *p; i++, p++) { |
2032 | if ((*p == '\n') || (*p == ' ')) { | 2076 | if ((*p == '\n') || (*p == ' ')) { |
@@ -2038,6 +2082,7 @@ remove_write (struct device_driver *drv, const char *buf, size_t count) | |||
2038 | } | 2082 | } |
2039 | name[i] = '\0'; | 2083 | name[i] = '\0'; |
2040 | 2084 | ||
2085 | read_lock_irqsave(&iucv_conns.iucv_rwlock, flags); | ||
2041 | while (*clist) { | 2086 | while (*clist) { |
2042 | ndev = (*clist)->netdev; | 2087 | ndev = (*clist)->netdev; |
2043 | priv = (struct netiucv_priv*)ndev->priv; | 2088 | priv = (struct netiucv_priv*)ndev->priv; |
@@ -2047,6 +2092,7 @@ remove_write (struct device_driver *drv, const char *buf, size_t count) | |||
2047 | clist = &((*clist)->next); | 2092 | clist = &((*clist)->next); |
2048 | continue; | 2093 | continue; |
2049 | } | 2094 | } |
2095 | read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); | ||
2050 | if (ndev->flags & (IFF_UP | IFF_RUNNING)) { | 2096 | if (ndev->flags & (IFF_UP | IFF_RUNNING)) { |
2051 | PRINT_WARN( | 2097 | PRINT_WARN( |
2052 | "netiucv: net device %s active with peer %s\n", | 2098 | "netiucv: net device %s active with peer %s\n", |
@@ -2060,6 +2106,7 @@ remove_write (struct device_driver *drv, const char *buf, size_t count) | |||
2060 | netiucv_unregister_device(dev); | 2106 | netiucv_unregister_device(dev); |
2061 | return count; | 2107 | return count; |
2062 | } | 2108 | } |
2109 | read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); | ||
2063 | PRINT_WARN("netiucv: net device %s unknown\n", name); | 2110 | PRINT_WARN("netiucv: net device %s unknown\n", name); |
2064 | IUCV_DBF_TEXT(data, 2, "remove_write: unknown device\n"); | 2111 | IUCV_DBF_TEXT(data, 2, "remove_write: unknown device\n"); |
2065 | return -EINVAL; | 2112 | return -EINVAL; |
@@ -2077,8 +2124,8 @@ static void __exit | |||
2077 | netiucv_exit(void) | 2124 | netiucv_exit(void) |
2078 | { | 2125 | { |
2079 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); | 2126 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); |
2080 | while (iucv_connections) { | 2127 | while (iucv_conns.iucv_connections) { |
2081 | struct net_device *ndev = iucv_connections->netdev; | 2128 | struct net_device *ndev = iucv_conns.iucv_connections->netdev; |
2082 | struct netiucv_priv *priv = (struct netiucv_priv*)ndev->priv; | 2129 | struct netiucv_priv *priv = (struct netiucv_priv*)ndev->priv; |
2083 | struct device *dev = priv->dev; | 2130 | struct device *dev = priv->dev; |
2084 | 2131 | ||
@@ -2120,6 +2167,7 @@ netiucv_init(void) | |||
2120 | if (!ret) { | 2167 | if (!ret) { |
2121 | ret = driver_create_file(&netiucv_driver, &driver_attr_remove); | 2168 | ret = driver_create_file(&netiucv_driver, &driver_attr_remove); |
2122 | netiucv_banner(); | 2169 | netiucv_banner(); |
2170 | rwlock_init(&iucv_conns.iucv_rwlock); | ||
2123 | } else { | 2171 | } else { |
2124 | PRINT_ERR("NETIUCV: failed to add driver attribute.\n"); | 2172 | PRINT_ERR("NETIUCV: failed to add driver attribute.\n"); |
2125 | IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_create_file\n", ret); | 2173 | IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_create_file\n", ret); |
diff --git a/drivers/s390/net/qeth.h b/drivers/s390/net/qeth.h index 619f4a0c7160..821383d8cbe7 100644 --- a/drivers/s390/net/qeth.h +++ b/drivers/s390/net/qeth.h | |||
@@ -176,7 +176,6 @@ extern struct ccwgroup_driver qeth_ccwgroup_driver; | |||
176 | /** | 176 | /** |
177 | * card stuff | 177 | * card stuff |
178 | */ | 178 | */ |
179 | #ifdef CONFIG_QETH_PERF_STATS | ||
180 | struct qeth_perf_stats { | 179 | struct qeth_perf_stats { |
181 | unsigned int bufs_rec; | 180 | unsigned int bufs_rec; |
182 | unsigned int bufs_sent; | 181 | unsigned int bufs_sent; |
@@ -211,8 +210,10 @@ struct qeth_perf_stats { | |||
211 | unsigned int large_send_cnt; | 210 | unsigned int large_send_cnt; |
212 | unsigned int sg_skbs_sent; | 211 | unsigned int sg_skbs_sent; |
213 | unsigned int sg_frags_sent; | 212 | unsigned int sg_frags_sent; |
213 | /* initial values when measuring starts */ | ||
214 | unsigned long initial_rx_packets; | ||
215 | unsigned long initial_tx_packets; | ||
214 | }; | 216 | }; |
215 | #endif /* CONFIG_QETH_PERF_STATS */ | ||
216 | 217 | ||
217 | /* Routing stuff */ | 218 | /* Routing stuff */ |
218 | struct qeth_routing_info { | 219 | struct qeth_routing_info { |
@@ -462,6 +463,7 @@ enum qeth_qdio_info_states { | |||
462 | QETH_QDIO_UNINITIALIZED, | 463 | QETH_QDIO_UNINITIALIZED, |
463 | QETH_QDIO_ALLOCATED, | 464 | QETH_QDIO_ALLOCATED, |
464 | QETH_QDIO_ESTABLISHED, | 465 | QETH_QDIO_ESTABLISHED, |
466 | QETH_QDIO_CLEANING | ||
465 | }; | 467 | }; |
466 | 468 | ||
467 | struct qeth_buffer_pool_entry { | 469 | struct qeth_buffer_pool_entry { |
@@ -536,7 +538,7 @@ struct qeth_qdio_out_q { | |||
536 | } __attribute__ ((aligned(256))); | 538 | } __attribute__ ((aligned(256))); |
537 | 539 | ||
538 | struct qeth_qdio_info { | 540 | struct qeth_qdio_info { |
539 | volatile enum qeth_qdio_info_states state; | 541 | atomic_t state; |
540 | /* input */ | 542 | /* input */ |
541 | struct qeth_qdio_q *in_q; | 543 | struct qeth_qdio_q *in_q; |
542 | struct qeth_qdio_buffer_pool in_buf_pool; | 544 | struct qeth_qdio_buffer_pool in_buf_pool; |
@@ -767,6 +769,7 @@ struct qeth_card_options { | |||
767 | int fake_ll; | 769 | int fake_ll; |
768 | int layer2; | 770 | int layer2; |
769 | enum qeth_large_send_types large_send; | 771 | enum qeth_large_send_types large_send; |
772 | int performance_stats; | ||
770 | }; | 773 | }; |
771 | 774 | ||
772 | /* | 775 | /* |
@@ -819,9 +822,7 @@ struct qeth_card { | |||
819 | struct list_head cmd_waiter_list; | 822 | struct list_head cmd_waiter_list; |
820 | /* QDIO buffer handling */ | 823 | /* QDIO buffer handling */ |
821 | struct qeth_qdio_info qdio; | 824 | struct qeth_qdio_info qdio; |
822 | #ifdef CONFIG_QETH_PERF_STATS | ||
823 | struct qeth_perf_stats perf_stats; | 825 | struct qeth_perf_stats perf_stats; |
824 | #endif /* CONFIG_QETH_PERF_STATS */ | ||
825 | int use_hard_stop; | 826 | int use_hard_stop; |
826 | int (*orig_hard_header)(struct sk_buff *,struct net_device *, | 827 | int (*orig_hard_header)(struct sk_buff *,struct net_device *, |
827 | unsigned short,void *,void *,unsigned); | 828 | unsigned short,void *,void *,unsigned); |
@@ -859,23 +860,18 @@ qeth_get_ipa_adp_type(enum qeth_link_types link_type) | |||
859 | } | 860 | } |
860 | } | 861 | } |
861 | 862 | ||
862 | static inline int | 863 | static inline struct sk_buff * |
863 | qeth_realloc_headroom(struct qeth_card *card, struct sk_buff **skb, int size) | 864 | qeth_realloc_headroom(struct qeth_card *card, struct sk_buff *skb, int size) |
864 | { | 865 | { |
865 | struct sk_buff *new_skb = NULL; | 866 | struct sk_buff *new_skb = skb; |
866 | 867 | ||
867 | if (skb_headroom(*skb) < size){ | 868 | if (skb_headroom(skb) >= size) |
868 | new_skb = skb_realloc_headroom(*skb, size); | 869 | return skb; |
869 | if (!new_skb) { | 870 | new_skb = skb_realloc_headroom(skb, size); |
870 | PRINT_ERR("qeth_prepare_skb: could " | 871 | if (!new_skb) |
871 | "not realloc headroom for qeth_hdr " | 872 | PRINT_ERR("Could not realloc headroom for qeth_hdr " |
872 | "on interface %s", QETH_CARD_IFNAME(card)); | 873 | "on interface %s", QETH_CARD_IFNAME(card)); |
873 | return -ENOMEM; | 874 | return new_skb; |
874 | } | ||
875 | kfree_skb(*skb); | ||
876 | *skb = new_skb; | ||
877 | } | ||
878 | return 0; | ||
879 | } | 875 | } |
880 | 876 | ||
881 | static inline struct sk_buff * | 877 | static inline struct sk_buff * |
@@ -885,16 +881,15 @@ qeth_pskb_unshare(struct sk_buff *skb, int pri) | |||
885 | if (!skb_cloned(skb)) | 881 | if (!skb_cloned(skb)) |
886 | return skb; | 882 | return skb; |
887 | nskb = skb_copy(skb, pri); | 883 | nskb = skb_copy(skb, pri); |
888 | kfree_skb(skb); /* free our shared copy */ | ||
889 | return nskb; | 884 | return nskb; |
890 | } | 885 | } |
891 | 886 | ||
892 | static inline void * | 887 | static inline void * |
893 | qeth_push_skb(struct qeth_card *card, struct sk_buff **skb, int size) | 888 | qeth_push_skb(struct qeth_card *card, struct sk_buff *skb, int size) |
894 | { | 889 | { |
895 | void *hdr; | 890 | void *hdr; |
896 | 891 | ||
897 | hdr = (void *) skb_push(*skb, size); | 892 | hdr = (void *) skb_push(skb, size); |
898 | /* | 893 | /* |
899 | * sanity check, the Linux memory allocation scheme should | 894 | * sanity check, the Linux memory allocation scheme should |
900 | * never present us cases like this one (the qdio header size plus | 895 | * never present us cases like this one (the qdio header size plus |
@@ -903,8 +898,7 @@ qeth_push_skb(struct qeth_card *card, struct sk_buff **skb, int size) | |||
903 | if ((((unsigned long) hdr) & (~(PAGE_SIZE - 1))) != | 898 | if ((((unsigned long) hdr) & (~(PAGE_SIZE - 1))) != |
904 | (((unsigned long) hdr + size + | 899 | (((unsigned long) hdr + size + |
905 | QETH_IP_HEADER_SIZE) & (~(PAGE_SIZE - 1)))) { | 900 | QETH_IP_HEADER_SIZE) & (~(PAGE_SIZE - 1)))) { |
906 | PRINT_ERR("qeth_prepare_skb: misaligned " | 901 | PRINT_ERR("Misaligned packet on interface %s. Discarded.", |
907 | "packet on interface %s. Discarded.", | ||
908 | QETH_CARD_IFNAME(card)); | 902 | QETH_CARD_IFNAME(card)); |
909 | return NULL; | 903 | return NULL; |
910 | } | 904 | } |
@@ -1056,13 +1050,11 @@ qeth_get_arphdr_type(int cardtype, int linktype) | |||
1056 | } | 1050 | } |
1057 | } | 1051 | } |
1058 | 1052 | ||
1059 | #ifdef CONFIG_QETH_PERF_STATS | ||
1060 | static inline int | 1053 | static inline int |
1061 | qeth_get_micros(void) | 1054 | qeth_get_micros(void) |
1062 | { | 1055 | { |
1063 | return (int) (get_clock() >> 12); | 1056 | return (int) (get_clock() >> 12); |
1064 | } | 1057 | } |
1065 | #endif | ||
1066 | 1058 | ||
1067 | static inline int | 1059 | static inline int |
1068 | qeth_get_qdio_q_format(struct qeth_card *card) | 1060 | qeth_get_qdio_q_format(struct qeth_card *card) |
@@ -1096,10 +1088,11 @@ qeth_string_to_ipaddr4(const char *buf, __u8 *addr) | |||
1096 | { | 1088 | { |
1097 | int count = 0, rc = 0; | 1089 | int count = 0, rc = 0; |
1098 | int in[4]; | 1090 | int in[4]; |
1091 | char c; | ||
1099 | 1092 | ||
1100 | rc = sscanf(buf, "%d.%d.%d.%d%n", | 1093 | rc = sscanf(buf, "%u.%u.%u.%u%c", |
1101 | &in[0], &in[1], &in[2], &in[3], &count); | 1094 | &in[0], &in[1], &in[2], &in[3], &c); |
1102 | if (rc != 4 || count<=0) | 1095 | if (rc != 4 && (rc != 5 || c != '\n')) |
1103 | return -EINVAL; | 1096 | return -EINVAL; |
1104 | for (count = 0; count < 4; count++) { | 1097 | for (count = 0; count < 4; count++) { |
1105 | if (in[count] > 255) | 1098 | if (in[count] > 255) |
@@ -1123,24 +1116,28 @@ qeth_ipaddr6_to_string(const __u8 *addr, char *buf) | |||
1123 | static inline int | 1116 | static inline int |
1124 | qeth_string_to_ipaddr6(const char *buf, __u8 *addr) | 1117 | qeth_string_to_ipaddr6(const char *buf, __u8 *addr) |
1125 | { | 1118 | { |
1126 | char *end, *start; | 1119 | const char *end, *end_tmp, *start; |
1127 | __u16 *in; | 1120 | __u16 *in; |
1128 | char num[5]; | 1121 | char num[5]; |
1129 | int num2, cnt, out, found, save_cnt; | 1122 | int num2, cnt, out, found, save_cnt; |
1130 | unsigned short in_tmp[8] = {0, }; | 1123 | unsigned short in_tmp[8] = {0, }; |
1131 | 1124 | ||
1132 | cnt = out = found = save_cnt = num2 = 0; | 1125 | cnt = out = found = save_cnt = num2 = 0; |
1133 | end = start = (char *) buf; | 1126 | end = start = buf; |
1134 | in = (__u16 *) addr; | 1127 | in = (__u16 *) addr; |
1135 | memset(in, 0, 16); | 1128 | memset(in, 0, 16); |
1136 | while (end) { | 1129 | while (*end) { |
1137 | end = strchr(end,':'); | 1130 | end = strchr(start,':'); |
1138 | if (end == NULL) { | 1131 | if (end == NULL) { |
1139 | end = (char *)buf + (strlen(buf)); | 1132 | end = buf + strlen(buf); |
1140 | out = 1; | 1133 | if ((end_tmp = strchr(start, '\n')) != NULL) |
1134 | end = end_tmp; | ||
1135 | out = 1; | ||
1141 | } | 1136 | } |
1142 | if ((end - start)) { | 1137 | if ((end - start)) { |
1143 | memset(num, 0, 5); | 1138 | memset(num, 0, 5); |
1139 | if ((end - start) > 4) | ||
1140 | return -EINVAL; | ||
1144 | memcpy(num, start, end - start); | 1141 | memcpy(num, start, end - start); |
1145 | if (!qeth_isxdigit(num)) | 1142 | if (!qeth_isxdigit(num)) |
1146 | return -EINVAL; | 1143 | return -EINVAL; |
@@ -1158,6 +1155,8 @@ qeth_string_to_ipaddr6(const char *buf, __u8 *addr) | |||
1158 | } | 1155 | } |
1159 | start = ++end; | 1156 | start = ++end; |
1160 | } | 1157 | } |
1158 | if (cnt + save_cnt > 8) | ||
1159 | return -EINVAL; | ||
1161 | cnt = 7; | 1160 | cnt = 7; |
1162 | while (save_cnt) | 1161 | while (save_cnt) |
1163 | in[cnt--] = in_tmp[--save_cnt]; | 1162 | in[cnt--] = in_tmp[--save_cnt]; |
diff --git a/drivers/s390/net/qeth_eddp.c b/drivers/s390/net/qeth_eddp.c index 8491598f9149..a363721cf28d 100644 --- a/drivers/s390/net/qeth_eddp.c +++ b/drivers/s390/net/qeth_eddp.c | |||
@@ -179,9 +179,8 @@ out_check: | |||
179 | flush_cnt++; | 179 | flush_cnt++; |
180 | } | 180 | } |
181 | } else { | 181 | } else { |
182 | #ifdef CONFIG_QETH_PERF_STATS | 182 | if (queue->card->options.performance_stats) |
183 | queue->card->perf_stats.skbs_sent_pack++; | 183 | queue->card->perf_stats.skbs_sent_pack++; |
184 | #endif | ||
185 | QETH_DBF_TEXT(trace, 6, "fillbfpa"); | 184 | QETH_DBF_TEXT(trace, 6, "fillbfpa"); |
186 | if (buf->next_element_to_fill >= | 185 | if (buf->next_element_to_fill >= |
187 | QETH_MAX_BUFFER_ELEMENTS(queue->card)) { | 186 | QETH_MAX_BUFFER_ELEMENTS(queue->card)) { |
diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index e1327b8fce00..5613b4564fa2 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c | |||
@@ -1073,6 +1073,7 @@ qeth_set_intial_options(struct qeth_card *card) | |||
1073 | card->options.layer2 = 1; | 1073 | card->options.layer2 = 1; |
1074 | else | 1074 | else |
1075 | card->options.layer2 = 0; | 1075 | card->options.layer2 = 0; |
1076 | card->options.performance_stats = 1; | ||
1076 | } | 1077 | } |
1077 | 1078 | ||
1078 | /** | 1079 | /** |
@@ -1708,6 +1709,7 @@ qeth_check_ipa_data(struct qeth_card *card, struct qeth_cmd_buffer *iob) | |||
1708 | "IP address reset.\n", | 1709 | "IP address reset.\n", |
1709 | QETH_CARD_IFNAME(card), | 1710 | QETH_CARD_IFNAME(card), |
1710 | card->info.chpid); | 1711 | card->info.chpid); |
1712 | netif_carrier_on(card->dev); | ||
1711 | qeth_schedule_recovery(card); | 1713 | qeth_schedule_recovery(card); |
1712 | return NULL; | 1714 | return NULL; |
1713 | case IPA_CMD_MODCCID: | 1715 | case IPA_CMD_MODCCID: |
@@ -2464,24 +2466,6 @@ qeth_rebuild_skb_fake_ll(struct qeth_card *card, struct sk_buff *skb, | |||
2464 | qeth_rebuild_skb_fake_ll_eth(card, skb, hdr); | 2466 | qeth_rebuild_skb_fake_ll_eth(card, skb, hdr); |
2465 | } | 2467 | } |
2466 | 2468 | ||
2467 | static inline void | ||
2468 | qeth_rebuild_skb_vlan(struct qeth_card *card, struct sk_buff *skb, | ||
2469 | struct qeth_hdr *hdr) | ||
2470 | { | ||
2471 | #ifdef CONFIG_QETH_VLAN | ||
2472 | u16 *vlan_tag; | ||
2473 | |||
2474 | if (hdr->hdr.l3.ext_flags & | ||
2475 | (QETH_HDR_EXT_VLAN_FRAME | QETH_HDR_EXT_INCLUDE_VLAN_TAG)) { | ||
2476 | vlan_tag = (u16 *) skb_push(skb, VLAN_HLEN); | ||
2477 | *vlan_tag = (hdr->hdr.l3.ext_flags & QETH_HDR_EXT_VLAN_FRAME)? | ||
2478 | hdr->hdr.l3.vlan_id : *((u16 *)&hdr->hdr.l3.dest_addr[12]); | ||
2479 | *(vlan_tag + 1) = skb->protocol; | ||
2480 | skb->protocol = __constant_htons(ETH_P_8021Q); | ||
2481 | } | ||
2482 | #endif /* CONFIG_QETH_VLAN */ | ||
2483 | } | ||
2484 | |||
2485 | static inline __u16 | 2469 | static inline __u16 |
2486 | qeth_layer2_rebuild_skb(struct qeth_card *card, struct sk_buff *skb, | 2470 | qeth_layer2_rebuild_skb(struct qeth_card *card, struct sk_buff *skb, |
2487 | struct qeth_hdr *hdr) | 2471 | struct qeth_hdr *hdr) |
@@ -2510,15 +2494,16 @@ qeth_layer2_rebuild_skb(struct qeth_card *card, struct sk_buff *skb, | |||
2510 | return vlan_id; | 2494 | return vlan_id; |
2511 | } | 2495 | } |
2512 | 2496 | ||
2513 | static inline void | 2497 | static inline __u16 |
2514 | qeth_rebuild_skb(struct qeth_card *card, struct sk_buff *skb, | 2498 | qeth_rebuild_skb(struct qeth_card *card, struct sk_buff *skb, |
2515 | struct qeth_hdr *hdr) | 2499 | struct qeth_hdr *hdr) |
2516 | { | 2500 | { |
2501 | unsigned short vlan_id = 0; | ||
2517 | #ifdef CONFIG_QETH_IPV6 | 2502 | #ifdef CONFIG_QETH_IPV6 |
2518 | if (hdr->hdr.l3.flags & QETH_HDR_PASSTHRU) { | 2503 | if (hdr->hdr.l3.flags & QETH_HDR_PASSTHRU) { |
2519 | skb->pkt_type = PACKET_HOST; | 2504 | skb->pkt_type = PACKET_HOST; |
2520 | skb->protocol = qeth_type_trans(skb, card->dev); | 2505 | skb->protocol = qeth_type_trans(skb, card->dev); |
2521 | return; | 2506 | return 0; |
2522 | } | 2507 | } |
2523 | #endif /* CONFIG_QETH_IPV6 */ | 2508 | #endif /* CONFIG_QETH_IPV6 */ |
2524 | skb->protocol = htons((hdr->hdr.l3.flags & QETH_HDR_IPV6)? ETH_P_IPV6 : | 2509 | skb->protocol = htons((hdr->hdr.l3.flags & QETH_HDR_IPV6)? ETH_P_IPV6 : |
@@ -2540,7 +2525,13 @@ qeth_rebuild_skb(struct qeth_card *card, struct sk_buff *skb, | |||
2540 | default: | 2525 | default: |
2541 | skb->pkt_type = PACKET_HOST; | 2526 | skb->pkt_type = PACKET_HOST; |
2542 | } | 2527 | } |
2543 | qeth_rebuild_skb_vlan(card, skb, hdr); | 2528 | |
2529 | if (hdr->hdr.l3.ext_flags & | ||
2530 | (QETH_HDR_EXT_VLAN_FRAME | QETH_HDR_EXT_INCLUDE_VLAN_TAG)) { | ||
2531 | vlan_id = (hdr->hdr.l3.ext_flags & QETH_HDR_EXT_VLAN_FRAME)? | ||
2532 | hdr->hdr.l3.vlan_id : *((u16 *)&hdr->hdr.l3.dest_addr[12]); | ||
2533 | } | ||
2534 | |||
2544 | if (card->options.fake_ll) | 2535 | if (card->options.fake_ll) |
2545 | qeth_rebuild_skb_fake_ll(card, skb, hdr); | 2536 | qeth_rebuild_skb_fake_ll(card, skb, hdr); |
2546 | else | 2537 | else |
@@ -2556,6 +2547,7 @@ qeth_rebuild_skb(struct qeth_card *card, struct sk_buff *skb, | |||
2556 | else | 2547 | else |
2557 | skb->ip_summed = SW_CHECKSUMMING; | 2548 | skb->ip_summed = SW_CHECKSUMMING; |
2558 | } | 2549 | } |
2550 | return vlan_id; | ||
2559 | } | 2551 | } |
2560 | 2552 | ||
2561 | static inline void | 2553 | static inline void |
@@ -2568,20 +2560,20 @@ qeth_process_inbound_buffer(struct qeth_card *card, | |||
2568 | int offset; | 2560 | int offset; |
2569 | int rxrc; | 2561 | int rxrc; |
2570 | __u16 vlan_tag = 0; | 2562 | __u16 vlan_tag = 0; |
2563 | __u16 *vlan_addr; | ||
2571 | 2564 | ||
2572 | /* get first element of current buffer */ | 2565 | /* get first element of current buffer */ |
2573 | element = (struct qdio_buffer_element *)&buf->buffer->element[0]; | 2566 | element = (struct qdio_buffer_element *)&buf->buffer->element[0]; |
2574 | offset = 0; | 2567 | offset = 0; |
2575 | #ifdef CONFIG_QETH_PERF_STATS | 2568 | if (card->options.performance_stats) |
2576 | card->perf_stats.bufs_rec++; | 2569 | card->perf_stats.bufs_rec++; |
2577 | #endif | ||
2578 | while((skb = qeth_get_next_skb(card, buf->buffer, &element, | 2570 | while((skb = qeth_get_next_skb(card, buf->buffer, &element, |
2579 | &offset, &hdr))) { | 2571 | &offset, &hdr))) { |
2580 | skb->dev = card->dev; | 2572 | skb->dev = card->dev; |
2581 | if (hdr->hdr.l2.id == QETH_HEADER_TYPE_LAYER2) | 2573 | if (hdr->hdr.l2.id == QETH_HEADER_TYPE_LAYER2) |
2582 | vlan_tag = qeth_layer2_rebuild_skb(card, skb, hdr); | 2574 | vlan_tag = qeth_layer2_rebuild_skb(card, skb, hdr); |
2583 | else if (hdr->hdr.l3.id == QETH_HEADER_TYPE_LAYER3) | 2575 | else if (hdr->hdr.l3.id == QETH_HEADER_TYPE_LAYER3) |
2584 | qeth_rebuild_skb(card, skb, hdr); | 2576 | vlan_tag = qeth_rebuild_skb(card, skb, hdr); |
2585 | else { /*in case of OSN*/ | 2577 | else { /*in case of OSN*/ |
2586 | skb_push(skb, sizeof(struct qeth_hdr)); | 2578 | skb_push(skb, sizeof(struct qeth_hdr)); |
2587 | memcpy(skb->data, hdr, sizeof(struct qeth_hdr)); | 2579 | memcpy(skb->data, hdr, sizeof(struct qeth_hdr)); |
@@ -2591,14 +2583,19 @@ qeth_process_inbound_buffer(struct qeth_card *card, | |||
2591 | dev_kfree_skb_any(skb); | 2583 | dev_kfree_skb_any(skb); |
2592 | continue; | 2584 | continue; |
2593 | } | 2585 | } |
2586 | if (card->info.type == QETH_CARD_TYPE_OSN) | ||
2587 | rxrc = card->osn_info.data_cb(skb); | ||
2588 | else | ||
2594 | #ifdef CONFIG_QETH_VLAN | 2589 | #ifdef CONFIG_QETH_VLAN |
2595 | if (vlan_tag) | 2590 | if (vlan_tag) |
2596 | vlan_hwaccel_rx(skb, card->vlangrp, vlan_tag); | 2591 | if (card->vlangrp) |
2592 | vlan_hwaccel_rx(skb, card->vlangrp, vlan_tag); | ||
2593 | else { | ||
2594 | dev_kfree_skb_any(skb); | ||
2595 | continue; | ||
2596 | } | ||
2597 | else | 2597 | else |
2598 | #endif | 2598 | #endif |
2599 | if (card->info.type == QETH_CARD_TYPE_OSN) | ||
2600 | rxrc = card->osn_info.data_cb(skb); | ||
2601 | else | ||
2602 | rxrc = netif_rx(skb); | 2599 | rxrc = netif_rx(skb); |
2603 | card->dev->last_rx = jiffies; | 2600 | card->dev->last_rx = jiffies; |
2604 | card->stats.rx_packets++; | 2601 | card->stats.rx_packets++; |
@@ -2626,7 +2623,7 @@ qeth_init_input_buffer(struct qeth_card *card, struct qeth_qdio_buffer *buf) | |||
2626 | { | 2623 | { |
2627 | struct qeth_buffer_pool_entry *pool_entry; | 2624 | struct qeth_buffer_pool_entry *pool_entry; |
2628 | int i; | 2625 | int i; |
2629 | 2626 | ||
2630 | pool_entry = qeth_get_buffer_pool_entry(card); | 2627 | pool_entry = qeth_get_buffer_pool_entry(card); |
2631 | /* | 2628 | /* |
2632 | * since the buffer is accessed only from the input_tasklet | 2629 | * since the buffer is accessed only from the input_tasklet |
@@ -2700,17 +2697,18 @@ qeth_queue_input_buffer(struct qeth_card *card, int index) | |||
2700 | * 'index') un-requeued -> this buffer is the first buffer that | 2697 | * 'index') un-requeued -> this buffer is the first buffer that |
2701 | * will be requeued the next time | 2698 | * will be requeued the next time |
2702 | */ | 2699 | */ |
2703 | #ifdef CONFIG_QETH_PERF_STATS | 2700 | if (card->options.performance_stats) { |
2704 | card->perf_stats.inbound_do_qdio_cnt++; | 2701 | card->perf_stats.inbound_do_qdio_cnt++; |
2705 | card->perf_stats.inbound_do_qdio_start_time = qeth_get_micros(); | 2702 | card->perf_stats.inbound_do_qdio_start_time = |
2706 | #endif | 2703 | qeth_get_micros(); |
2704 | } | ||
2707 | rc = do_QDIO(CARD_DDEV(card), | 2705 | rc = do_QDIO(CARD_DDEV(card), |
2708 | QDIO_FLAG_SYNC_INPUT | QDIO_FLAG_UNDER_INTERRUPT, | 2706 | QDIO_FLAG_SYNC_INPUT | QDIO_FLAG_UNDER_INTERRUPT, |
2709 | 0, queue->next_buf_to_init, count, NULL); | 2707 | 0, queue->next_buf_to_init, count, NULL); |
2710 | #ifdef CONFIG_QETH_PERF_STATS | 2708 | if (card->options.performance_stats) |
2711 | card->perf_stats.inbound_do_qdio_time += qeth_get_micros() - | 2709 | card->perf_stats.inbound_do_qdio_time += |
2712 | card->perf_stats.inbound_do_qdio_start_time; | 2710 | qeth_get_micros() - |
2713 | #endif | 2711 | card->perf_stats.inbound_do_qdio_start_time; |
2714 | if (rc){ | 2712 | if (rc){ |
2715 | PRINT_WARN("qeth_queue_input_buffer's do_QDIO " | 2713 | PRINT_WARN("qeth_queue_input_buffer's do_QDIO " |
2716 | "return %i (device %s).\n", | 2714 | "return %i (device %s).\n", |
@@ -2746,10 +2744,10 @@ qeth_qdio_input_handler(struct ccw_device * ccwdev, unsigned int status, | |||
2746 | QETH_DBF_TEXT(trace, 6, "qdinput"); | 2744 | QETH_DBF_TEXT(trace, 6, "qdinput"); |
2747 | card = (struct qeth_card *) card_ptr; | 2745 | card = (struct qeth_card *) card_ptr; |
2748 | net_dev = card->dev; | 2746 | net_dev = card->dev; |
2749 | #ifdef CONFIG_QETH_PERF_STATS | 2747 | if (card->options.performance_stats) { |
2750 | card->perf_stats.inbound_cnt++; | 2748 | card->perf_stats.inbound_cnt++; |
2751 | card->perf_stats.inbound_start_time = qeth_get_micros(); | 2749 | card->perf_stats.inbound_start_time = qeth_get_micros(); |
2752 | #endif | 2750 | } |
2753 | if (status & QDIO_STATUS_LOOK_FOR_ERROR) { | 2751 | if (status & QDIO_STATUS_LOOK_FOR_ERROR) { |
2754 | if (status & QDIO_STATUS_ACTIVATE_CHECK_CONDITION){ | 2752 | if (status & QDIO_STATUS_ACTIVATE_CHECK_CONDITION){ |
2755 | QETH_DBF_TEXT(trace, 1,"qdinchk"); | 2753 | QETH_DBF_TEXT(trace, 1,"qdinchk"); |
@@ -2771,10 +2769,9 @@ qeth_qdio_input_handler(struct ccw_device * ccwdev, unsigned int status, | |||
2771 | qeth_put_buffer_pool_entry(card, buffer->pool_entry); | 2769 | qeth_put_buffer_pool_entry(card, buffer->pool_entry); |
2772 | qeth_queue_input_buffer(card, index); | 2770 | qeth_queue_input_buffer(card, index); |
2773 | } | 2771 | } |
2774 | #ifdef CONFIG_QETH_PERF_STATS | 2772 | if (card->options.performance_stats) |
2775 | card->perf_stats.inbound_time += qeth_get_micros() - | 2773 | card->perf_stats.inbound_time += qeth_get_micros() - |
2776 | card->perf_stats.inbound_start_time; | 2774 | card->perf_stats.inbound_start_time; |
2777 | #endif | ||
2778 | } | 2775 | } |
2779 | 2776 | ||
2780 | static inline int | 2777 | static inline int |
@@ -2864,10 +2861,11 @@ qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int, | |||
2864 | } | 2861 | } |
2865 | 2862 | ||
2866 | queue->card->dev->trans_start = jiffies; | 2863 | queue->card->dev->trans_start = jiffies; |
2867 | #ifdef CONFIG_QETH_PERF_STATS | 2864 | if (queue->card->options.performance_stats) { |
2868 | queue->card->perf_stats.outbound_do_qdio_cnt++; | 2865 | queue->card->perf_stats.outbound_do_qdio_cnt++; |
2869 | queue->card->perf_stats.outbound_do_qdio_start_time = qeth_get_micros(); | 2866 | queue->card->perf_stats.outbound_do_qdio_start_time = |
2870 | #endif | 2867 | qeth_get_micros(); |
2868 | } | ||
2871 | if (under_int) | 2869 | if (under_int) |
2872 | rc = do_QDIO(CARD_DDEV(queue->card), | 2870 | rc = do_QDIO(CARD_DDEV(queue->card), |
2873 | QDIO_FLAG_SYNC_OUTPUT | QDIO_FLAG_UNDER_INTERRUPT, | 2871 | QDIO_FLAG_SYNC_OUTPUT | QDIO_FLAG_UNDER_INTERRUPT, |
@@ -2875,10 +2873,10 @@ qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int, | |||
2875 | else | 2873 | else |
2876 | rc = do_QDIO(CARD_DDEV(queue->card), QDIO_FLAG_SYNC_OUTPUT, | 2874 | rc = do_QDIO(CARD_DDEV(queue->card), QDIO_FLAG_SYNC_OUTPUT, |
2877 | queue->queue_no, index, count, NULL); | 2875 | queue->queue_no, index, count, NULL); |
2878 | #ifdef CONFIG_QETH_PERF_STATS | 2876 | if (queue->card->options.performance_stats) |
2879 | queue->card->perf_stats.outbound_do_qdio_time += qeth_get_micros() - | 2877 | queue->card->perf_stats.outbound_do_qdio_time += |
2880 | queue->card->perf_stats.outbound_do_qdio_start_time; | 2878 | qeth_get_micros() - |
2881 | #endif | 2879 | queue->card->perf_stats.outbound_do_qdio_start_time; |
2882 | if (rc){ | 2880 | if (rc){ |
2883 | QETH_DBF_TEXT(trace, 2, "flushbuf"); | 2881 | QETH_DBF_TEXT(trace, 2, "flushbuf"); |
2884 | QETH_DBF_TEXT_(trace, 2, " err%d", rc); | 2882 | QETH_DBF_TEXT_(trace, 2, " err%d", rc); |
@@ -2890,9 +2888,8 @@ qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int, | |||
2890 | return; | 2888 | return; |
2891 | } | 2889 | } |
2892 | atomic_add(count, &queue->used_buffers); | 2890 | atomic_add(count, &queue->used_buffers); |
2893 | #ifdef CONFIG_QETH_PERF_STATS | 2891 | if (queue->card->options.performance_stats) |
2894 | queue->card->perf_stats.bufs_sent += count; | 2892 | queue->card->perf_stats.bufs_sent += count; |
2895 | #endif | ||
2896 | } | 2893 | } |
2897 | 2894 | ||
2898 | /* | 2895 | /* |
@@ -2907,9 +2904,8 @@ qeth_switch_to_packing_if_needed(struct qeth_qdio_out_q *queue) | |||
2907 | >= QETH_HIGH_WATERMARK_PACK){ | 2904 | >= QETH_HIGH_WATERMARK_PACK){ |
2908 | /* switch non-PACKING -> PACKING */ | 2905 | /* switch non-PACKING -> PACKING */ |
2909 | QETH_DBF_TEXT(trace, 6, "np->pack"); | 2906 | QETH_DBF_TEXT(trace, 6, "np->pack"); |
2910 | #ifdef CONFIG_QETH_PERF_STATS | 2907 | if (queue->card->options.performance_stats) |
2911 | queue->card->perf_stats.sc_dp_p++; | 2908 | queue->card->perf_stats.sc_dp_p++; |
2912 | #endif | ||
2913 | queue->do_pack = 1; | 2909 | queue->do_pack = 1; |
2914 | } | 2910 | } |
2915 | } | 2911 | } |
@@ -2932,9 +2928,8 @@ qeth_switch_to_nonpacking_if_needed(struct qeth_qdio_out_q *queue) | |||
2932 | <= QETH_LOW_WATERMARK_PACK) { | 2928 | <= QETH_LOW_WATERMARK_PACK) { |
2933 | /* switch PACKING -> non-PACKING */ | 2929 | /* switch PACKING -> non-PACKING */ |
2934 | QETH_DBF_TEXT(trace, 6, "pack->np"); | 2930 | QETH_DBF_TEXT(trace, 6, "pack->np"); |
2935 | #ifdef CONFIG_QETH_PERF_STATS | 2931 | if (queue->card->options.performance_stats) |
2936 | queue->card->perf_stats.sc_p_dp++; | 2932 | queue->card->perf_stats.sc_p_dp++; |
2937 | #endif | ||
2938 | queue->do_pack = 0; | 2933 | queue->do_pack = 0; |
2939 | /* flush packing buffers */ | 2934 | /* flush packing buffers */ |
2940 | buffer = &queue->bufs[queue->next_buf_to_fill]; | 2935 | buffer = &queue->bufs[queue->next_buf_to_fill]; |
@@ -2946,7 +2941,7 @@ qeth_switch_to_nonpacking_if_needed(struct qeth_qdio_out_q *queue) | |||
2946 | queue->next_buf_to_fill = | 2941 | queue->next_buf_to_fill = |
2947 | (queue->next_buf_to_fill + 1) % | 2942 | (queue->next_buf_to_fill + 1) % |
2948 | QDIO_MAX_BUFFERS_PER_Q; | 2943 | QDIO_MAX_BUFFERS_PER_Q; |
2949 | } | 2944 | } |
2950 | } | 2945 | } |
2951 | } | 2946 | } |
2952 | return flush_count; | 2947 | return flush_count; |
@@ -3002,11 +2997,10 @@ qeth_check_outbound_queue(struct qeth_qdio_out_q *queue) | |||
3002 | !atomic_read(&queue->set_pci_flags_count)) | 2997 | !atomic_read(&queue->set_pci_flags_count)) |
3003 | flush_cnt += | 2998 | flush_cnt += |
3004 | qeth_flush_buffers_on_no_pci(queue); | 2999 | qeth_flush_buffers_on_no_pci(queue); |
3005 | #ifdef CONFIG_QETH_PERF_STATS | 3000 | if (queue->card->options.performance_stats && |
3006 | if (q_was_packing) | 3001 | q_was_packing) |
3007 | queue->card->perf_stats.bufs_sent_pack += | 3002 | queue->card->perf_stats.bufs_sent_pack += |
3008 | flush_cnt; | 3003 | flush_cnt; |
3009 | #endif | ||
3010 | if (flush_cnt) | 3004 | if (flush_cnt) |
3011 | qeth_flush_buffers(queue, 1, index, flush_cnt); | 3005 | qeth_flush_buffers(queue, 1, index, flush_cnt); |
3012 | atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED); | 3006 | atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED); |
@@ -3036,10 +3030,11 @@ qeth_qdio_output_handler(struct ccw_device * ccwdev, unsigned int status, | |||
3036 | return; | 3030 | return; |
3037 | } | 3031 | } |
3038 | } | 3032 | } |
3039 | #ifdef CONFIG_QETH_PERF_STATS | 3033 | if (card->options.performance_stats) { |
3040 | card->perf_stats.outbound_handler_cnt++; | 3034 | card->perf_stats.outbound_handler_cnt++; |
3041 | card->perf_stats.outbound_handler_start_time = qeth_get_micros(); | 3035 | card->perf_stats.outbound_handler_start_time = |
3042 | #endif | 3036 | qeth_get_micros(); |
3037 | } | ||
3043 | for(i = first_element; i < (first_element + count); ++i){ | 3038 | for(i = first_element; i < (first_element + count); ++i){ |
3044 | buffer = &queue->bufs[i % QDIO_MAX_BUFFERS_PER_Q]; | 3039 | buffer = &queue->bufs[i % QDIO_MAX_BUFFERS_PER_Q]; |
3045 | /*we only handle the KICK_IT error by doing a recovery */ | 3040 | /*we only handle the KICK_IT error by doing a recovery */ |
@@ -3058,10 +3053,9 @@ qeth_qdio_output_handler(struct ccw_device * ccwdev, unsigned int status, | |||
3058 | qeth_check_outbound_queue(queue); | 3053 | qeth_check_outbound_queue(queue); |
3059 | 3054 | ||
3060 | netif_wake_queue(queue->card->dev); | 3055 | netif_wake_queue(queue->card->dev); |
3061 | #ifdef CONFIG_QETH_PERF_STATS | 3056 | if (card->options.performance_stats) |
3062 | card->perf_stats.outbound_handler_time += qeth_get_micros() - | 3057 | card->perf_stats.outbound_handler_time += qeth_get_micros() - |
3063 | card->perf_stats.outbound_handler_start_time; | 3058 | card->perf_stats.outbound_handler_start_time; |
3064 | #endif | ||
3065 | } | 3059 | } |
3066 | 3060 | ||
3067 | static void | 3061 | static void |
@@ -3185,13 +3179,14 @@ qeth_alloc_qdio_buffers(struct qeth_card *card) | |||
3185 | 3179 | ||
3186 | QETH_DBF_TEXT(setup, 2, "allcqdbf"); | 3180 | QETH_DBF_TEXT(setup, 2, "allcqdbf"); |
3187 | 3181 | ||
3188 | if (card->qdio.state == QETH_QDIO_ALLOCATED) | 3182 | if (atomic_cmpxchg(&card->qdio.state, QETH_QDIO_UNINITIALIZED, |
3183 | QETH_QDIO_ALLOCATED) != QETH_QDIO_UNINITIALIZED) | ||
3189 | return 0; | 3184 | return 0; |
3190 | 3185 | ||
3191 | card->qdio.in_q = kmalloc(sizeof(struct qeth_qdio_q), | 3186 | card->qdio.in_q = kmalloc(sizeof(struct qeth_qdio_q), |
3192 | GFP_KERNEL|GFP_DMA); | 3187 | GFP_KERNEL|GFP_DMA); |
3193 | if (!card->qdio.in_q) | 3188 | if (!card->qdio.in_q) |
3194 | return - ENOMEM; | 3189 | goto out_nomem; |
3195 | QETH_DBF_TEXT(setup, 2, "inq"); | 3190 | QETH_DBF_TEXT(setup, 2, "inq"); |
3196 | QETH_DBF_HEX(setup, 2, &card->qdio.in_q, sizeof(void *)); | 3191 | QETH_DBF_HEX(setup, 2, &card->qdio.in_q, sizeof(void *)); |
3197 | memset(card->qdio.in_q, 0, sizeof(struct qeth_qdio_q)); | 3192 | memset(card->qdio.in_q, 0, sizeof(struct qeth_qdio_q)); |
@@ -3200,27 +3195,19 @@ qeth_alloc_qdio_buffers(struct qeth_card *card) | |||
3200 | card->qdio.in_q->bufs[i].buffer = | 3195 | card->qdio.in_q->bufs[i].buffer = |
3201 | &card->qdio.in_q->qdio_bufs[i]; | 3196 | &card->qdio.in_q->qdio_bufs[i]; |
3202 | /* inbound buffer pool */ | 3197 | /* inbound buffer pool */ |
3203 | if (qeth_alloc_buffer_pool(card)){ | 3198 | if (qeth_alloc_buffer_pool(card)) |
3204 | kfree(card->qdio.in_q); | 3199 | goto out_freeinq; |
3205 | return -ENOMEM; | ||
3206 | } | ||
3207 | /* outbound */ | 3200 | /* outbound */ |
3208 | card->qdio.out_qs = | 3201 | card->qdio.out_qs = |
3209 | kmalloc(card->qdio.no_out_queues * | 3202 | kmalloc(card->qdio.no_out_queues * |
3210 | sizeof(struct qeth_qdio_out_q *), GFP_KERNEL); | 3203 | sizeof(struct qeth_qdio_out_q *), GFP_KERNEL); |
3211 | if (!card->qdio.out_qs){ | 3204 | if (!card->qdio.out_qs) |
3212 | qeth_free_buffer_pool(card); | 3205 | goto out_freepool; |
3213 | return -ENOMEM; | 3206 | for (i = 0; i < card->qdio.no_out_queues; ++i) { |
3214 | } | ||
3215 | for (i = 0; i < card->qdio.no_out_queues; ++i){ | ||
3216 | card->qdio.out_qs[i] = kmalloc(sizeof(struct qeth_qdio_out_q), | 3207 | card->qdio.out_qs[i] = kmalloc(sizeof(struct qeth_qdio_out_q), |
3217 | GFP_KERNEL|GFP_DMA); | 3208 | GFP_KERNEL|GFP_DMA); |
3218 | if (!card->qdio.out_qs[i]){ | 3209 | if (!card->qdio.out_qs[i]) |
3219 | while (i > 0) | 3210 | goto out_freeoutq; |
3220 | kfree(card->qdio.out_qs[--i]); | ||
3221 | kfree(card->qdio.out_qs); | ||
3222 | return -ENOMEM; | ||
3223 | } | ||
3224 | QETH_DBF_TEXT_(setup, 2, "outq %i", i); | 3211 | QETH_DBF_TEXT_(setup, 2, "outq %i", i); |
3225 | QETH_DBF_HEX(setup, 2, &card->qdio.out_qs[i], sizeof(void *)); | 3212 | QETH_DBF_HEX(setup, 2, &card->qdio.out_qs[i], sizeof(void *)); |
3226 | memset(card->qdio.out_qs[i], 0, sizeof(struct qeth_qdio_out_q)); | 3213 | memset(card->qdio.out_qs[i], 0, sizeof(struct qeth_qdio_out_q)); |
@@ -3237,8 +3224,19 @@ qeth_alloc_qdio_buffers(struct qeth_card *card) | |||
3237 | INIT_LIST_HEAD(&card->qdio.out_qs[i]->bufs[j].ctx_list); | 3224 | INIT_LIST_HEAD(&card->qdio.out_qs[i]->bufs[j].ctx_list); |
3238 | } | 3225 | } |
3239 | } | 3226 | } |
3240 | card->qdio.state = QETH_QDIO_ALLOCATED; | ||
3241 | return 0; | 3227 | return 0; |
3228 | |||
3229 | out_freeoutq: | ||
3230 | while (i > 0) | ||
3231 | kfree(card->qdio.out_qs[--i]); | ||
3232 | kfree(card->qdio.out_qs); | ||
3233 | out_freepool: | ||
3234 | qeth_free_buffer_pool(card); | ||
3235 | out_freeinq: | ||
3236 | kfree(card->qdio.in_q); | ||
3237 | out_nomem: | ||
3238 | atomic_set(&card->qdio.state, QETH_QDIO_UNINITIALIZED); | ||
3239 | return -ENOMEM; | ||
3242 | } | 3240 | } |
3243 | 3241 | ||
3244 | static void | 3242 | static void |
@@ -3247,7 +3245,8 @@ qeth_free_qdio_buffers(struct qeth_card *card) | |||
3247 | int i, j; | 3245 | int i, j; |
3248 | 3246 | ||
3249 | QETH_DBF_TEXT(trace, 2, "freeqdbf"); | 3247 | QETH_DBF_TEXT(trace, 2, "freeqdbf"); |
3250 | if (card->qdio.state == QETH_QDIO_UNINITIALIZED) | 3248 | if (atomic_swap(&card->qdio.state, QETH_QDIO_UNINITIALIZED) == |
3249 | QETH_QDIO_UNINITIALIZED) | ||
3251 | return; | 3250 | return; |
3252 | kfree(card->qdio.in_q); | 3251 | kfree(card->qdio.in_q); |
3253 | /* inbound buffer pool */ | 3252 | /* inbound buffer pool */ |
@@ -3260,7 +3259,6 @@ qeth_free_qdio_buffers(struct qeth_card *card) | |||
3260 | kfree(card->qdio.out_qs[i]); | 3259 | kfree(card->qdio.out_qs[i]); |
3261 | } | 3260 | } |
3262 | kfree(card->qdio.out_qs); | 3261 | kfree(card->qdio.out_qs); |
3263 | card->qdio.state = QETH_QDIO_UNINITIALIZED; | ||
3264 | } | 3262 | } |
3265 | 3263 | ||
3266 | static void | 3264 | static void |
@@ -3282,7 +3280,7 @@ static void | |||
3282 | qeth_init_qdio_info(struct qeth_card *card) | 3280 | qeth_init_qdio_info(struct qeth_card *card) |
3283 | { | 3281 | { |
3284 | QETH_DBF_TEXT(setup, 4, "intqdinf"); | 3282 | QETH_DBF_TEXT(setup, 4, "intqdinf"); |
3285 | card->qdio.state = QETH_QDIO_UNINITIALIZED; | 3283 | atomic_set(&card->qdio.state, QETH_QDIO_UNINITIALIZED); |
3286 | /* inbound */ | 3284 | /* inbound */ |
3287 | card->qdio.in_buf_size = QETH_IN_BUF_SIZE_DEFAULT; | 3285 | card->qdio.in_buf_size = QETH_IN_BUF_SIZE_DEFAULT; |
3288 | card->qdio.init_pool.buf_count = QETH_IN_BUF_COUNT_DEFAULT; | 3286 | card->qdio.init_pool.buf_count = QETH_IN_BUF_COUNT_DEFAULT; |
@@ -3345,7 +3343,7 @@ qeth_qdio_establish(struct qeth_card *card) | |||
3345 | struct qdio_buffer **in_sbal_ptrs; | 3343 | struct qdio_buffer **in_sbal_ptrs; |
3346 | struct qdio_buffer **out_sbal_ptrs; | 3344 | struct qdio_buffer **out_sbal_ptrs; |
3347 | int i, j, k; | 3345 | int i, j, k; |
3348 | int rc; | 3346 | int rc = 0; |
3349 | 3347 | ||
3350 | QETH_DBF_TEXT(setup, 2, "qdioest"); | 3348 | QETH_DBF_TEXT(setup, 2, "qdioest"); |
3351 | 3349 | ||
@@ -3404,8 +3402,10 @@ qeth_qdio_establish(struct qeth_card *card) | |||
3404 | init_data.input_sbal_addr_array = (void **) in_sbal_ptrs; | 3402 | init_data.input_sbal_addr_array = (void **) in_sbal_ptrs; |
3405 | init_data.output_sbal_addr_array = (void **) out_sbal_ptrs; | 3403 | init_data.output_sbal_addr_array = (void **) out_sbal_ptrs; |
3406 | 3404 | ||
3407 | if (!(rc = qdio_initialize(&init_data))) | 3405 | if (atomic_cmpxchg(&card->qdio.state, QETH_QDIO_ALLOCATED, |
3408 | card->qdio.state = QETH_QDIO_ESTABLISHED; | 3406 | QETH_QDIO_ESTABLISHED) == QETH_QDIO_ALLOCATED) |
3407 | if ((rc = qdio_initialize(&init_data))) | ||
3408 | atomic_set(&card->qdio.state, QETH_QDIO_ALLOCATED); | ||
3409 | 3409 | ||
3410 | kfree(out_sbal_ptrs); | 3410 | kfree(out_sbal_ptrs); |
3411 | kfree(in_sbal_ptrs); | 3411 | kfree(in_sbal_ptrs); |
@@ -3521,13 +3521,20 @@ qeth_qdio_clear_card(struct qeth_card *card, int use_halt) | |||
3521 | int rc = 0; | 3521 | int rc = 0; |
3522 | 3522 | ||
3523 | QETH_DBF_TEXT(trace,3,"qdioclr"); | 3523 | QETH_DBF_TEXT(trace,3,"qdioclr"); |
3524 | if (card->qdio.state == QETH_QDIO_ESTABLISHED){ | 3524 | switch (atomic_cmpxchg(&card->qdio.state, QETH_QDIO_ESTABLISHED, |
3525 | QETH_QDIO_CLEANING)) { | ||
3526 | case QETH_QDIO_ESTABLISHED: | ||
3525 | if ((rc = qdio_cleanup(CARD_DDEV(card), | 3527 | if ((rc = qdio_cleanup(CARD_DDEV(card), |
3526 | (card->info.type == QETH_CARD_TYPE_IQD) ? | 3528 | (card->info.type == QETH_CARD_TYPE_IQD) ? |
3527 | QDIO_FLAG_CLEANUP_USING_HALT : | 3529 | QDIO_FLAG_CLEANUP_USING_HALT : |
3528 | QDIO_FLAG_CLEANUP_USING_CLEAR))) | 3530 | QDIO_FLAG_CLEANUP_USING_CLEAR))) |
3529 | QETH_DBF_TEXT_(trace, 3, "1err%d", rc); | 3531 | QETH_DBF_TEXT_(trace, 3, "1err%d", rc); |
3530 | card->qdio.state = QETH_QDIO_ALLOCATED; | 3532 | atomic_set(&card->qdio.state, QETH_QDIO_ALLOCATED); |
3533 | break; | ||
3534 | case QETH_QDIO_CLEANING: | ||
3535 | return rc; | ||
3536 | default: | ||
3537 | break; | ||
3531 | } | 3538 | } |
3532 | if ((rc = qeth_clear_halt_card(card, use_halt))) | 3539 | if ((rc = qeth_clear_halt_card(card, use_halt))) |
3533 | QETH_DBF_TEXT_(trace, 3, "2err%d", rc); | 3540 | QETH_DBF_TEXT_(trace, 3, "2err%d", rc); |
@@ -3687,10 +3694,10 @@ qeth_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
3687 | /* return OK; otherwise ksoftirqd goes to 100% */ | 3694 | /* return OK; otherwise ksoftirqd goes to 100% */ |
3688 | return NETDEV_TX_OK; | 3695 | return NETDEV_TX_OK; |
3689 | } | 3696 | } |
3690 | #ifdef CONFIG_QETH_PERF_STATS | 3697 | if (card->options.performance_stats) { |
3691 | card->perf_stats.outbound_cnt++; | 3698 | card->perf_stats.outbound_cnt++; |
3692 | card->perf_stats.outbound_start_time = qeth_get_micros(); | 3699 | card->perf_stats.outbound_start_time = qeth_get_micros(); |
3693 | #endif | 3700 | } |
3694 | netif_stop_queue(dev); | 3701 | netif_stop_queue(dev); |
3695 | if ((rc = qeth_send_packet(card, skb))) { | 3702 | if ((rc = qeth_send_packet(card, skb))) { |
3696 | if (rc == -EBUSY) { | 3703 | if (rc == -EBUSY) { |
@@ -3704,10 +3711,9 @@ qeth_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
3704 | } | 3711 | } |
3705 | } | 3712 | } |
3706 | netif_wake_queue(dev); | 3713 | netif_wake_queue(dev); |
3707 | #ifdef CONFIG_QETH_PERF_STATS | 3714 | if (card->options.performance_stats) |
3708 | card->perf_stats.outbound_time += qeth_get_micros() - | 3715 | card->perf_stats.outbound_time += qeth_get_micros() - |
3709 | card->perf_stats.outbound_start_time; | 3716 | card->perf_stats.outbound_start_time; |
3710 | #endif | ||
3711 | return rc; | 3717 | return rc; |
3712 | } | 3718 | } |
3713 | 3719 | ||
@@ -3922,49 +3928,59 @@ qeth_get_ip_version(struct sk_buff *skb) | |||
3922 | } | 3928 | } |
3923 | } | 3929 | } |
3924 | 3930 | ||
3925 | static inline int | 3931 | static inline struct qeth_hdr * |
3926 | qeth_prepare_skb(struct qeth_card *card, struct sk_buff **skb, | 3932 | __qeth_prepare_skb(struct qeth_card *card, struct sk_buff *skb, int ipv) |
3927 | struct qeth_hdr **hdr, int ipv) | ||
3928 | { | 3933 | { |
3929 | int rc = 0; | ||
3930 | #ifdef CONFIG_QETH_VLAN | 3934 | #ifdef CONFIG_QETH_VLAN |
3931 | u16 *tag; | 3935 | u16 *tag; |
3932 | #endif | 3936 | if (card->vlangrp && vlan_tx_tag_present(skb) && |
3933 | |||
3934 | QETH_DBF_TEXT(trace, 6, "prepskb"); | ||
3935 | if (card->info.type == QETH_CARD_TYPE_OSN) { | ||
3936 | *hdr = (struct qeth_hdr *)(*skb)->data; | ||
3937 | return rc; | ||
3938 | } | ||
3939 | rc = qeth_realloc_headroom(card, skb, sizeof(struct qeth_hdr)); | ||
3940 | if (rc) | ||
3941 | return rc; | ||
3942 | #ifdef CONFIG_QETH_VLAN | ||
3943 | if (card->vlangrp && vlan_tx_tag_present(*skb) && | ||
3944 | ((ipv == 6) || card->options.layer2) ) { | 3937 | ((ipv == 6) || card->options.layer2) ) { |
3945 | /* | 3938 | /* |
3946 | * Move the mac addresses (6 bytes src, 6 bytes dest) | 3939 | * Move the mac addresses (6 bytes src, 6 bytes dest) |
3947 | * to the beginning of the new header. We are using three | 3940 | * to the beginning of the new header. We are using three |
3948 | * memcpys instead of one memmove to save cycles. | 3941 | * memcpys instead of one memmove to save cycles. |
3949 | */ | 3942 | */ |
3950 | skb_push(*skb, VLAN_HLEN); | 3943 | skb_push(skb, VLAN_HLEN); |
3951 | memcpy((*skb)->data, (*skb)->data + 4, 4); | 3944 | memcpy(skb->data, skb->data + 4, 4); |
3952 | memcpy((*skb)->data + 4, (*skb)->data + 8, 4); | 3945 | memcpy(skb->data + 4, skb->data + 8, 4); |
3953 | memcpy((*skb)->data + 8, (*skb)->data + 12, 4); | 3946 | memcpy(skb->data + 8, skb->data + 12, 4); |
3954 | tag = (u16 *)((*skb)->data + 12); | 3947 | tag = (u16 *)(skb->data + 12); |
3955 | /* | 3948 | /* |
3956 | * first two bytes = ETH_P_8021Q (0x8100) | 3949 | * first two bytes = ETH_P_8021Q (0x8100) |
3957 | * second two bytes = VLANID | 3950 | * second two bytes = VLANID |
3958 | */ | 3951 | */ |
3959 | *tag = __constant_htons(ETH_P_8021Q); | 3952 | *tag = __constant_htons(ETH_P_8021Q); |
3960 | *(tag + 1) = htons(vlan_tx_tag_get(*skb)); | 3953 | *(tag + 1) = htons(vlan_tx_tag_get(skb)); |
3961 | } | 3954 | } |
3962 | #endif | 3955 | #endif |
3963 | *hdr = (struct qeth_hdr *) | 3956 | return ((struct qeth_hdr *) |
3964 | qeth_push_skb(card, skb, sizeof(struct qeth_hdr)); | 3957 | qeth_push_skb(card, skb, sizeof(struct qeth_hdr))); |
3965 | if (*hdr == NULL) | 3958 | } |
3966 | return -EINVAL; | 3959 | |
3967 | return 0; | 3960 | static inline void |
3961 | __qeth_free_new_skb(struct sk_buff *orig_skb, struct sk_buff *new_skb) | ||
3962 | { | ||
3963 | if (orig_skb != new_skb) | ||
3964 | dev_kfree_skb_any(new_skb); | ||
3965 | } | ||
3966 | |||
3967 | static inline struct sk_buff * | ||
3968 | qeth_prepare_skb(struct qeth_card *card, struct sk_buff *skb, | ||
3969 | struct qeth_hdr **hdr, int ipv) | ||
3970 | { | ||
3971 | struct sk_buff *new_skb; | ||
3972 | |||
3973 | QETH_DBF_TEXT(trace, 6, "prepskb"); | ||
3974 | |||
3975 | new_skb = qeth_realloc_headroom(card, skb, sizeof(struct qeth_hdr)); | ||
3976 | if (new_skb == NULL) | ||
3977 | return NULL; | ||
3978 | *hdr = __qeth_prepare_skb(card, new_skb, ipv); | ||
3979 | if (*hdr == NULL) { | ||
3980 | __qeth_free_new_skb(skb, new_skb); | ||
3981 | return NULL; | ||
3982 | } | ||
3983 | return new_skb; | ||
3968 | } | 3984 | } |
3969 | 3985 | ||
3970 | static inline u8 | 3986 | static inline u8 |
@@ -4206,9 +4222,8 @@ qeth_fill_buffer(struct qeth_qdio_out_q *queue, | |||
4206 | flush_cnt = 1; | 4222 | flush_cnt = 1; |
4207 | } else { | 4223 | } else { |
4208 | QETH_DBF_TEXT(trace, 6, "fillbfpa"); | 4224 | QETH_DBF_TEXT(trace, 6, "fillbfpa"); |
4209 | #ifdef CONFIG_QETH_PERF_STATS | 4225 | if (queue->card->options.performance_stats) |
4210 | queue->card->perf_stats.skbs_sent_pack++; | 4226 | queue->card->perf_stats.skbs_sent_pack++; |
4211 | #endif | ||
4212 | if (buf->next_element_to_fill >= | 4227 | if (buf->next_element_to_fill >= |
4213 | QETH_MAX_BUFFER_ELEMENTS(queue->card)) { | 4228 | QETH_MAX_BUFFER_ELEMENTS(queue->card)) { |
4214 | /* | 4229 | /* |
@@ -4245,21 +4260,15 @@ qeth_do_send_packet_fast(struct qeth_card *card, struct qeth_qdio_out_q *queue, | |||
4245 | * check if buffer is empty to make sure that we do not 'overtake' | 4260 | * check if buffer is empty to make sure that we do not 'overtake' |
4246 | * ourselves and try to fill a buffer that is already primed | 4261 | * ourselves and try to fill a buffer that is already primed |
4247 | */ | 4262 | */ |
4248 | if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY) { | 4263 | if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY) |
4249 | card->stats.tx_dropped++; | 4264 | goto out; |
4250 | atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED); | ||
4251 | return -EBUSY; | ||
4252 | } | ||
4253 | if (ctx == NULL) | 4265 | if (ctx == NULL) |
4254 | queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) % | 4266 | queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) % |
4255 | QDIO_MAX_BUFFERS_PER_Q; | 4267 | QDIO_MAX_BUFFERS_PER_Q; |
4256 | else { | 4268 | else { |
4257 | buffers_needed = qeth_eddp_check_buffers_for_context(queue,ctx); | 4269 | buffers_needed = qeth_eddp_check_buffers_for_context(queue,ctx); |
4258 | if (buffers_needed < 0) { | 4270 | if (buffers_needed < 0) |
4259 | card->stats.tx_dropped++; | 4271 | goto out; |
4260 | atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED); | ||
4261 | return -EBUSY; | ||
4262 | } | ||
4263 | queue->next_buf_to_fill = | 4272 | queue->next_buf_to_fill = |
4264 | (queue->next_buf_to_fill + buffers_needed) % | 4273 | (queue->next_buf_to_fill + buffers_needed) % |
4265 | QDIO_MAX_BUFFERS_PER_Q; | 4274 | QDIO_MAX_BUFFERS_PER_Q; |
@@ -4274,6 +4283,9 @@ qeth_do_send_packet_fast(struct qeth_card *card, struct qeth_qdio_out_q *queue, | |||
4274 | qeth_flush_buffers(queue, 0, index, flush_cnt); | 4283 | qeth_flush_buffers(queue, 0, index, flush_cnt); |
4275 | } | 4284 | } |
4276 | return 0; | 4285 | return 0; |
4286 | out: | ||
4287 | atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED); | ||
4288 | return -EBUSY; | ||
4277 | } | 4289 | } |
4278 | 4290 | ||
4279 | static inline int | 4291 | static inline int |
@@ -4299,8 +4311,7 @@ qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue, | |||
4299 | * check if buffer is empty to make sure that we do not 'overtake' | 4311 | * check if buffer is empty to make sure that we do not 'overtake' |
4300 | * ourselves and try to fill a buffer that is already primed | 4312 | * ourselves and try to fill a buffer that is already primed |
4301 | */ | 4313 | */ |
4302 | if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY){ | 4314 | if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY) { |
4303 | card->stats.tx_dropped++; | ||
4304 | atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED); | 4315 | atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED); |
4305 | return -EBUSY; | 4316 | return -EBUSY; |
4306 | } | 4317 | } |
@@ -4323,7 +4334,6 @@ qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue, | |||
4323 | * again */ | 4334 | * again */ |
4324 | if (atomic_read(&buffer->state) != | 4335 | if (atomic_read(&buffer->state) != |
4325 | QETH_QDIO_BUF_EMPTY){ | 4336 | QETH_QDIO_BUF_EMPTY){ |
4326 | card->stats.tx_dropped++; | ||
4327 | qeth_flush_buffers(queue, 0, start_index, flush_count); | 4337 | qeth_flush_buffers(queue, 0, start_index, flush_count); |
4328 | atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED); | 4338 | atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED); |
4329 | return -EBUSY; | 4339 | return -EBUSY; |
@@ -4334,7 +4344,6 @@ qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue, | |||
4334 | * free buffers) to handle eddp context */ | 4344 | * free buffers) to handle eddp context */ |
4335 | if (qeth_eddp_check_buffers_for_context(queue,ctx) < 0){ | 4345 | if (qeth_eddp_check_buffers_for_context(queue,ctx) < 0){ |
4336 | printk("eddp tx_dropped 1\n"); | 4346 | printk("eddp tx_dropped 1\n"); |
4337 | card->stats.tx_dropped++; | ||
4338 | rc = -EBUSY; | 4347 | rc = -EBUSY; |
4339 | goto out; | 4348 | goto out; |
4340 | } | 4349 | } |
@@ -4346,7 +4355,6 @@ qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue, | |||
4346 | tmp = qeth_eddp_fill_buffer(queue,ctx,queue->next_buf_to_fill); | 4355 | tmp = qeth_eddp_fill_buffer(queue,ctx,queue->next_buf_to_fill); |
4347 | if (tmp < 0) { | 4356 | if (tmp < 0) { |
4348 | printk("eddp tx_dropped 2\n"); | 4357 | printk("eddp tx_dropped 2\n"); |
4349 | card->stats.tx_dropped++; | ||
4350 | rc = - EBUSY; | 4358 | rc = - EBUSY; |
4351 | goto out; | 4359 | goto out; |
4352 | } | 4360 | } |
@@ -4380,10 +4388,8 @@ out: | |||
4380 | qeth_flush_buffers(queue, 0, start_index, flush_count); | 4388 | qeth_flush_buffers(queue, 0, start_index, flush_count); |
4381 | } | 4389 | } |
4382 | /* at this point the queue is UNLOCKED again */ | 4390 | /* at this point the queue is UNLOCKED again */ |
4383 | #ifdef CONFIG_QETH_PERF_STATS | 4391 | if (queue->card->options.performance_stats && do_pack) |
4384 | if (do_pack) | ||
4385 | queue->card->perf_stats.bufs_sent_pack += flush_count; | 4392 | queue->card->perf_stats.bufs_sent_pack += flush_count; |
4386 | #endif /* CONFIG_QETH_PERF_STATS */ | ||
4387 | 4393 | ||
4388 | return rc; | 4394 | return rc; |
4389 | } | 4395 | } |
@@ -4394,21 +4400,21 @@ qeth_get_elements_no(struct qeth_card *card, void *hdr, | |||
4394 | { | 4400 | { |
4395 | int elements_needed = 0; | 4401 | int elements_needed = 0; |
4396 | 4402 | ||
4397 | if (skb_shinfo(skb)->nr_frags > 0) { | 4403 | if (skb_shinfo(skb)->nr_frags > 0) |
4398 | elements_needed = (skb_shinfo(skb)->nr_frags + 1); | 4404 | elements_needed = (skb_shinfo(skb)->nr_frags + 1); |
4399 | } | 4405 | if (elements_needed == 0) |
4400 | if (elements_needed == 0 ) | ||
4401 | elements_needed = 1 + (((((unsigned long) hdr) % PAGE_SIZE) | 4406 | elements_needed = 1 + (((((unsigned long) hdr) % PAGE_SIZE) |
4402 | + skb->len) >> PAGE_SHIFT); | 4407 | + skb->len) >> PAGE_SHIFT); |
4403 | if ((elements_needed + elems) > QETH_MAX_BUFFER_ELEMENTS(card)){ | 4408 | if ((elements_needed + elems) > QETH_MAX_BUFFER_ELEMENTS(card)){ |
4404 | PRINT_ERR("qeth_do_send_packet: invalid size of " | 4409 | PRINT_ERR("Invalid size of IP packet " |
4405 | "IP packet (Number=%d / Length=%d). Discarded.\n", | 4410 | "(Number=%d / Length=%d). Discarded.\n", |
4406 | (elements_needed+elems), skb->len); | 4411 | (elements_needed+elems), skb->len); |
4407 | return 0; | 4412 | return 0; |
4408 | } | 4413 | } |
4409 | return elements_needed; | 4414 | return elements_needed; |
4410 | } | 4415 | } |
4411 | 4416 | ||
4417 | |||
4412 | static inline int | 4418 | static inline int |
4413 | qeth_send_packet(struct qeth_card *card, struct sk_buff *skb) | 4419 | qeth_send_packet(struct qeth_card *card, struct sk_buff *skb) |
4414 | { | 4420 | { |
@@ -4420,112 +4426,112 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb) | |||
4420 | enum qeth_large_send_types large_send = QETH_LARGE_SEND_NO; | 4426 | enum qeth_large_send_types large_send = QETH_LARGE_SEND_NO; |
4421 | struct qeth_eddp_context *ctx = NULL; | 4427 | struct qeth_eddp_context *ctx = NULL; |
4422 | int tx_bytes = skb->len; | 4428 | int tx_bytes = skb->len; |
4423 | #ifdef CONFIG_QETH_PERF_STATS | ||
4424 | unsigned short nr_frags = skb_shinfo(skb)->nr_frags; | 4429 | unsigned short nr_frags = skb_shinfo(skb)->nr_frags; |
4425 | unsigned short tso_size = skb_shinfo(skb)->gso_size; | 4430 | unsigned short tso_size = skb_shinfo(skb)->gso_size; |
4426 | #endif | 4431 | struct sk_buff *new_skb, *new_skb2; |
4427 | int rc; | 4432 | int rc; |
4428 | 4433 | ||
4429 | QETH_DBF_TEXT(trace, 6, "sendpkt"); | 4434 | QETH_DBF_TEXT(trace, 6, "sendpkt"); |
4430 | 4435 | ||
4436 | new_skb = skb; | ||
4437 | if ((card->info.type == QETH_CARD_TYPE_OSN) && | ||
4438 | (skb->protocol == htons(ETH_P_IPV6))) | ||
4439 | return -EPERM; | ||
4440 | cast_type = qeth_get_cast_type(card, skb); | ||
4441 | if ((cast_type == RTN_BROADCAST) && | ||
4442 | (card->info.broadcast_capable == 0)) | ||
4443 | return -EPERM; | ||
4444 | queue = card->qdio.out_qs | ||
4445 | [qeth_get_priority_queue(card, skb, ipv, cast_type)]; | ||
4431 | if (!card->options.layer2) { | 4446 | if (!card->options.layer2) { |
4432 | ipv = qeth_get_ip_version(skb); | 4447 | ipv = qeth_get_ip_version(skb); |
4433 | if ((card->dev->hard_header == qeth_fake_header) && ipv) { | 4448 | if ((card->dev->hard_header == qeth_fake_header) && ipv) { |
4434 | if ((skb = qeth_pskb_unshare(skb,GFP_ATOMIC)) == NULL) { | 4449 | new_skb = qeth_pskb_unshare(skb, GFP_ATOMIC); |
4435 | card->stats.tx_dropped++; | 4450 | if (!new_skb) |
4436 | dev_kfree_skb_irq(skb); | 4451 | return -ENOMEM; |
4437 | return 0; | ||
4438 | } | ||
4439 | if(card->dev->type == ARPHRD_IEEE802_TR){ | 4452 | if(card->dev->type == ARPHRD_IEEE802_TR){ |
4440 | skb_pull(skb, QETH_FAKE_LL_LEN_TR); | 4453 | skb_pull(new_skb, QETH_FAKE_LL_LEN_TR); |
4441 | } else { | 4454 | } else { |
4442 | skb_pull(skb, QETH_FAKE_LL_LEN_ETH); | 4455 | skb_pull(new_skb, QETH_FAKE_LL_LEN_ETH); |
4443 | } | 4456 | } |
4444 | } | 4457 | } |
4445 | } | 4458 | } |
4446 | if ((card->info.type == QETH_CARD_TYPE_OSN) && | ||
4447 | (skb->protocol == htons(ETH_P_IPV6))) { | ||
4448 | dev_kfree_skb_any(skb); | ||
4449 | return 0; | ||
4450 | } | ||
4451 | cast_type = qeth_get_cast_type(card, skb); | ||
4452 | if ((cast_type == RTN_BROADCAST) && | ||
4453 | (card->info.broadcast_capable == 0)){ | ||
4454 | card->stats.tx_dropped++; | ||
4455 | card->stats.tx_errors++; | ||
4456 | dev_kfree_skb_any(skb); | ||
4457 | return NETDEV_TX_OK; | ||
4458 | } | ||
4459 | queue = card->qdio.out_qs | ||
4460 | [qeth_get_priority_queue(card, skb, ipv, cast_type)]; | ||
4461 | |||
4462 | if (skb_is_gso(skb)) | 4459 | if (skb_is_gso(skb)) |
4463 | large_send = card->options.large_send; | 4460 | large_send = card->options.large_send; |
4464 | 4461 | /* check on OSN device*/ | |
4465 | /*are we able to do TSO ? If so ,prepare and send it from here */ | 4462 | if (card->info.type == QETH_CARD_TYPE_OSN) |
4463 | hdr = (struct qeth_hdr *)new_skb->data; | ||
4464 | /*are we able to do TSO ? */ | ||
4466 | if ((large_send == QETH_LARGE_SEND_TSO) && | 4465 | if ((large_send == QETH_LARGE_SEND_TSO) && |
4467 | (cast_type == RTN_UNSPEC)) { | 4466 | (cast_type == RTN_UNSPEC)) { |
4468 | rc = qeth_tso_prepare_packet(card, skb, ipv, cast_type); | 4467 | rc = qeth_tso_prepare_packet(card, new_skb, ipv, cast_type); |
4469 | if (rc) { | 4468 | if (rc) { |
4470 | card->stats.tx_dropped++; | 4469 | __qeth_free_new_skb(skb, new_skb); |
4471 | card->stats.tx_errors++; | 4470 | return rc; |
4472 | dev_kfree_skb_any(skb); | ||
4473 | return NETDEV_TX_OK; | ||
4474 | } | 4471 | } |
4475 | elements_needed++; | 4472 | elements_needed++; |
4476 | } else { | 4473 | } else if (card->info.type != QETH_CARD_TYPE_OSN) { |
4477 | if ((rc = qeth_prepare_skb(card, &skb, &hdr, ipv))) { | 4474 | new_skb2 = qeth_prepare_skb(card, new_skb, &hdr, ipv); |
4478 | QETH_DBF_TEXT_(trace, 4, "pskbe%d", rc); | 4475 | if (!new_skb2) { |
4479 | return rc; | 4476 | __qeth_free_new_skb(skb, new_skb); |
4477 | return -EINVAL; | ||
4480 | } | 4478 | } |
4481 | if (card->info.type != QETH_CARD_TYPE_OSN) | 4479 | if (new_skb != skb) |
4482 | qeth_fill_header(card, hdr, skb, ipv, cast_type); | 4480 | __qeth_free_new_skb(new_skb2, new_skb); |
4481 | new_skb = new_skb2; | ||
4482 | qeth_fill_header(card, hdr, new_skb, ipv, cast_type); | ||
4483 | } | 4483 | } |
4484 | |||
4485 | if (large_send == QETH_LARGE_SEND_EDDP) { | 4484 | if (large_send == QETH_LARGE_SEND_EDDP) { |
4486 | ctx = qeth_eddp_create_context(card, skb, hdr); | 4485 | ctx = qeth_eddp_create_context(card, new_skb, hdr); |
4487 | if (ctx == NULL) { | 4486 | if (ctx == NULL) { |
4487 | __qeth_free_new_skb(skb, new_skb); | ||
4488 | PRINT_WARN("could not create eddp context\n"); | 4488 | PRINT_WARN("could not create eddp context\n"); |
4489 | return -EINVAL; | 4489 | return -EINVAL; |
4490 | } | 4490 | } |
4491 | } else { | 4491 | } else { |
4492 | int elems = qeth_get_elements_no(card,(void*) hdr, skb, | 4492 | int elems = qeth_get_elements_no(card,(void*) hdr, new_skb, |
4493 | elements_needed); | 4493 | elements_needed); |
4494 | if (!elems) | 4494 | if (!elems) { |
4495 | __qeth_free_new_skb(skb, new_skb); | ||
4495 | return -EINVAL; | 4496 | return -EINVAL; |
4497 | } | ||
4496 | elements_needed += elems; | 4498 | elements_needed += elems; |
4497 | } | 4499 | } |
4498 | 4500 | ||
4499 | if (card->info.type != QETH_CARD_TYPE_IQD) | 4501 | if (card->info.type != QETH_CARD_TYPE_IQD) |
4500 | rc = qeth_do_send_packet(card, queue, skb, hdr, | 4502 | rc = qeth_do_send_packet(card, queue, new_skb, hdr, |
4501 | elements_needed, ctx); | 4503 | elements_needed, ctx); |
4502 | else | 4504 | else |
4503 | rc = qeth_do_send_packet_fast(card, queue, skb, hdr, | 4505 | rc = qeth_do_send_packet_fast(card, queue, new_skb, hdr, |
4504 | elements_needed, ctx); | 4506 | elements_needed, ctx); |
4505 | if (!rc){ | 4507 | if (!rc) { |
4506 | card->stats.tx_packets++; | 4508 | card->stats.tx_packets++; |
4507 | card->stats.tx_bytes += tx_bytes; | 4509 | card->stats.tx_bytes += tx_bytes; |
4508 | #ifdef CONFIG_QETH_PERF_STATS | 4510 | if (new_skb != skb) |
4509 | if (tso_size && | 4511 | dev_kfree_skb_any(skb); |
4510 | !(large_send == QETH_LARGE_SEND_NO)) { | 4512 | if (card->options.performance_stats) { |
4511 | card->perf_stats.large_send_bytes += tx_bytes; | 4513 | if (tso_size && |
4512 | card->perf_stats.large_send_cnt++; | 4514 | !(large_send == QETH_LARGE_SEND_NO)) { |
4513 | } | 4515 | card->perf_stats.large_send_bytes += tx_bytes; |
4514 | if (nr_frags > 0){ | 4516 | card->perf_stats.large_send_cnt++; |
4515 | card->perf_stats.sg_skbs_sent++; | 4517 | } |
4516 | /* nr_frags + skb->data */ | 4518 | if (nr_frags > 0) { |
4517 | card->perf_stats.sg_frags_sent += | 4519 | card->perf_stats.sg_skbs_sent++; |
4518 | nr_frags + 1; | 4520 | /* nr_frags + skb->data */ |
4521 | card->perf_stats.sg_frags_sent += | ||
4522 | nr_frags + 1; | ||
4523 | } | ||
4519 | } | 4524 | } |
4520 | #endif /* CONFIG_QETH_PERF_STATS */ | 4525 | } else { |
4526 | card->stats.tx_dropped++; | ||
4527 | __qeth_free_new_skb(skb, new_skb); | ||
4521 | } | 4528 | } |
4522 | if (ctx != NULL) { | 4529 | if (ctx != NULL) { |
4523 | /* drop creator's reference */ | 4530 | /* drop creator's reference */ |
4524 | qeth_eddp_put_context(ctx); | 4531 | qeth_eddp_put_context(ctx); |
4525 | /* free skb; it's not referenced by a buffer */ | 4532 | /* free skb; it's not referenced by a buffer */ |
4526 | if (rc == 0) | 4533 | if (!rc) |
4527 | dev_kfree_skb_any(skb); | 4534 | dev_kfree_skb_any(new_skb); |
4528 | |||
4529 | } | 4535 | } |
4530 | return rc; | 4536 | return rc; |
4531 | } | 4537 | } |
@@ -7338,6 +7344,8 @@ qeth_setrouting_v6(struct qeth_card *card) | |||
7338 | QETH_DBF_TEXT(trace,3,"setrtg6"); | 7344 | QETH_DBF_TEXT(trace,3,"setrtg6"); |
7339 | #ifdef CONFIG_QETH_IPV6 | 7345 | #ifdef CONFIG_QETH_IPV6 |
7340 | 7346 | ||
7347 | if (!qeth_is_supported(card, IPA_IPV6)) | ||
7348 | return 0; | ||
7341 | qeth_correct_routing_type(card, &card->options.route6.type, | 7349 | qeth_correct_routing_type(card, &card->options.route6.type, |
7342 | QETH_PROT_IPV6); | 7350 | QETH_PROT_IPV6); |
7343 | 7351 | ||
@@ -7876,12 +7884,12 @@ __qeth_set_online(struct ccwgroup_device *gdev, int recovery_mode) | |||
7876 | QETH_DBF_TEXT_(setup, 2, "5err%d", rc); | 7884 | QETH_DBF_TEXT_(setup, 2, "5err%d", rc); |
7877 | goto out_remove; | 7885 | goto out_remove; |
7878 | } | 7886 | } |
7879 | card->state = CARD_STATE_SOFTSETUP; | ||
7880 | 7887 | ||
7881 | if ((rc = qeth_init_qdio_queues(card))){ | 7888 | if ((rc = qeth_init_qdio_queues(card))){ |
7882 | QETH_DBF_TEXT_(setup, 2, "6err%d", rc); | 7889 | QETH_DBF_TEXT_(setup, 2, "6err%d", rc); |
7883 | goto out_remove; | 7890 | goto out_remove; |
7884 | } | 7891 | } |
7892 | card->state = CARD_STATE_SOFTSETUP; | ||
7885 | netif_carrier_on(card->dev); | 7893 | netif_carrier_on(card->dev); |
7886 | 7894 | ||
7887 | qeth_set_allowed_threads(card, 0xffffffff, 0); | 7895 | qeth_set_allowed_threads(card, 0xffffffff, 0); |
@@ -8538,34 +8546,44 @@ qeth_ipv6_uninit(void) | |||
8538 | static void | 8546 | static void |
8539 | qeth_sysfs_unregister(void) | 8547 | qeth_sysfs_unregister(void) |
8540 | { | 8548 | { |
8549 | s390_root_dev_unregister(qeth_root_dev); | ||
8541 | qeth_remove_driver_attributes(); | 8550 | qeth_remove_driver_attributes(); |
8542 | ccw_driver_unregister(&qeth_ccw_driver); | 8551 | ccw_driver_unregister(&qeth_ccw_driver); |
8543 | ccwgroup_driver_unregister(&qeth_ccwgroup_driver); | 8552 | ccwgroup_driver_unregister(&qeth_ccwgroup_driver); |
8544 | s390_root_dev_unregister(qeth_root_dev); | ||
8545 | } | 8553 | } |
8554 | |||
8546 | /** | 8555 | /** |
8547 | * register qeth at sysfs | 8556 | * register qeth at sysfs |
8548 | */ | 8557 | */ |
8549 | static int | 8558 | static int |
8550 | qeth_sysfs_register(void) | 8559 | qeth_sysfs_register(void) |
8551 | { | 8560 | { |
8552 | int rc=0; | 8561 | int rc; |
8553 | 8562 | ||
8554 | rc = ccwgroup_driver_register(&qeth_ccwgroup_driver); | 8563 | rc = ccwgroup_driver_register(&qeth_ccwgroup_driver); |
8555 | if (rc) | 8564 | if (rc) |
8556 | return rc; | 8565 | goto out; |
8566 | |||
8557 | rc = ccw_driver_register(&qeth_ccw_driver); | 8567 | rc = ccw_driver_register(&qeth_ccw_driver); |
8558 | if (rc) | 8568 | if (rc) |
8559 | return rc; | 8569 | goto out_ccw_driver; |
8570 | |||
8560 | rc = qeth_create_driver_attributes(); | 8571 | rc = qeth_create_driver_attributes(); |
8561 | if (rc) | 8572 | if (rc) |
8562 | return rc; | 8573 | goto out_qeth_attr; |
8574 | |||
8563 | qeth_root_dev = s390_root_dev_register("qeth"); | 8575 | qeth_root_dev = s390_root_dev_register("qeth"); |
8564 | if (IS_ERR(qeth_root_dev)) { | 8576 | rc = IS_ERR(qeth_root_dev) ? PTR_ERR(qeth_root_dev) : 0; |
8565 | rc = PTR_ERR(qeth_root_dev); | 8577 | if (!rc) |
8566 | return rc; | 8578 | goto out; |
8567 | } | 8579 | |
8568 | return 0; | 8580 | qeth_remove_driver_attributes(); |
8581 | out_qeth_attr: | ||
8582 | ccw_driver_unregister(&qeth_ccw_driver); | ||
8583 | out_ccw_driver: | ||
8584 | ccwgroup_driver_unregister(&qeth_ccwgroup_driver); | ||
8585 | out: | ||
8586 | return rc; | ||
8569 | } | 8587 | } |
8570 | 8588 | ||
8571 | /*** | 8589 | /*** |
@@ -8574,7 +8592,7 @@ qeth_sysfs_register(void) | |||
8574 | static int __init | 8592 | static int __init |
8575 | qeth_init(void) | 8593 | qeth_init(void) |
8576 | { | 8594 | { |
8577 | int rc=0; | 8595 | int rc; |
8578 | 8596 | ||
8579 | PRINT_INFO("loading %s\n", version); | 8597 | PRINT_INFO("loading %s\n", version); |
8580 | 8598 | ||
@@ -8583,20 +8601,26 @@ qeth_init(void) | |||
8583 | spin_lock_init(&qeth_notify_lock); | 8601 | spin_lock_init(&qeth_notify_lock); |
8584 | rwlock_init(&qeth_card_list.rwlock); | 8602 | rwlock_init(&qeth_card_list.rwlock); |
8585 | 8603 | ||
8586 | if (qeth_register_dbf_views()) | 8604 | rc = qeth_register_dbf_views(); |
8605 | if (rc) | ||
8587 | goto out_err; | 8606 | goto out_err; |
8588 | if (qeth_sysfs_register()) | 8607 | |
8589 | goto out_sysfs; | 8608 | rc = qeth_sysfs_register(); |
8609 | if (rc) | ||
8610 | goto out_dbf; | ||
8590 | 8611 | ||
8591 | #ifdef CONFIG_QETH_IPV6 | 8612 | #ifdef CONFIG_QETH_IPV6 |
8592 | if (qeth_ipv6_init()) { | 8613 | rc = qeth_ipv6_init(); |
8593 | PRINT_ERR("Out of memory during ipv6 init.\n"); | 8614 | if (rc) { |
8615 | PRINT_ERR("Out of memory during ipv6 init code = %d\n", rc); | ||
8594 | goto out_sysfs; | 8616 | goto out_sysfs; |
8595 | } | 8617 | } |
8596 | #endif /* QETH_IPV6 */ | 8618 | #endif /* QETH_IPV6 */ |
8597 | if (qeth_register_notifiers()) | 8619 | rc = qeth_register_notifiers(); |
8620 | if (rc) | ||
8598 | goto out_ipv6; | 8621 | goto out_ipv6; |
8599 | if (qeth_create_procfs_entries()) | 8622 | rc = qeth_create_procfs_entries(); |
8623 | if (rc) | ||
8600 | goto out_notifiers; | 8624 | goto out_notifiers; |
8601 | 8625 | ||
8602 | return rc; | 8626 | return rc; |
@@ -8606,12 +8630,13 @@ out_notifiers: | |||
8606 | out_ipv6: | 8630 | out_ipv6: |
8607 | #ifdef CONFIG_QETH_IPV6 | 8631 | #ifdef CONFIG_QETH_IPV6 |
8608 | qeth_ipv6_uninit(); | 8632 | qeth_ipv6_uninit(); |
8609 | #endif /* QETH_IPV6 */ | ||
8610 | out_sysfs: | 8633 | out_sysfs: |
8634 | #endif /* QETH_IPV6 */ | ||
8611 | qeth_sysfs_unregister(); | 8635 | qeth_sysfs_unregister(); |
8636 | out_dbf: | ||
8612 | qeth_unregister_dbf_views(); | 8637 | qeth_unregister_dbf_views(); |
8613 | out_err: | 8638 | out_err: |
8614 | PRINT_ERR("Initialization failed"); | 8639 | PRINT_ERR("Initialization failed with code %d\n", rc); |
8615 | return rc; | 8640 | return rc; |
8616 | } | 8641 | } |
8617 | 8642 | ||
diff --git a/drivers/s390/net/qeth_proc.c b/drivers/s390/net/qeth_proc.c index 66f2da14e6e3..faa768e59257 100644 --- a/drivers/s390/net/qeth_proc.c +++ b/drivers/s390/net/qeth_proc.c | |||
@@ -173,7 +173,6 @@ static struct file_operations qeth_procfile_fops = { | |||
173 | #define QETH_PERF_PROCFILE_NAME "qeth_perf" | 173 | #define QETH_PERF_PROCFILE_NAME "qeth_perf" |
174 | static struct proc_dir_entry *qeth_perf_procfile; | 174 | static struct proc_dir_entry *qeth_perf_procfile; |
175 | 175 | ||
176 | #ifdef CONFIG_QETH_PERF_STATS | ||
177 | static int | 176 | static int |
178 | qeth_perf_procfile_seq_show(struct seq_file *s, void *it) | 177 | qeth_perf_procfile_seq_show(struct seq_file *s, void *it) |
179 | { | 178 | { |
@@ -192,14 +191,21 @@ qeth_perf_procfile_seq_show(struct seq_file *s, void *it) | |||
192 | CARD_DDEV_ID(card), | 191 | CARD_DDEV_ID(card), |
193 | QETH_CARD_IFNAME(card) | 192 | QETH_CARD_IFNAME(card) |
194 | ); | 193 | ); |
194 | if (!card->options.performance_stats) | ||
195 | seq_printf(s, "Performance statistics are deactivated.\n"); | ||
195 | seq_printf(s, " Skb's/buffers received : %lu/%u\n" | 196 | seq_printf(s, " Skb's/buffers received : %lu/%u\n" |
196 | " Skb's/buffers sent : %lu/%u\n\n", | 197 | " Skb's/buffers sent : %lu/%u\n\n", |
197 | card->stats.rx_packets, card->perf_stats.bufs_rec, | 198 | card->stats.rx_packets - |
198 | card->stats.tx_packets, card->perf_stats.bufs_sent | 199 | card->perf_stats.initial_rx_packets, |
200 | card->perf_stats.bufs_rec, | ||
201 | card->stats.tx_packets - | ||
202 | card->perf_stats.initial_tx_packets, | ||
203 | card->perf_stats.bufs_sent | ||
199 | ); | 204 | ); |
200 | seq_printf(s, " Skb's/buffers sent without packing : %lu/%u\n" | 205 | seq_printf(s, " Skb's/buffers sent without packing : %lu/%u\n" |
201 | " Skb's/buffers sent with packing : %u/%u\n\n", | 206 | " Skb's/buffers sent with packing : %u/%u\n\n", |
202 | card->stats.tx_packets - card->perf_stats.skbs_sent_pack, | 207 | card->stats.tx_packets - card->perf_stats.initial_tx_packets |
208 | - card->perf_stats.skbs_sent_pack, | ||
203 | card->perf_stats.bufs_sent - card->perf_stats.bufs_sent_pack, | 209 | card->perf_stats.bufs_sent - card->perf_stats.bufs_sent_pack, |
204 | card->perf_stats.skbs_sent_pack, | 210 | card->perf_stats.skbs_sent_pack, |
205 | card->perf_stats.bufs_sent_pack | 211 | card->perf_stats.bufs_sent_pack |
@@ -275,11 +281,6 @@ static struct file_operations qeth_perf_procfile_fops = { | |||
275 | .release = seq_release, | 281 | .release = seq_release, |
276 | }; | 282 | }; |
277 | 283 | ||
278 | #define qeth_perf_procfile_created qeth_perf_procfile | ||
279 | #else | ||
280 | #define qeth_perf_procfile_created 1 | ||
281 | #endif /* CONFIG_QETH_PERF_STATS */ | ||
282 | |||
283 | int __init | 284 | int __init |
284 | qeth_create_procfs_entries(void) | 285 | qeth_create_procfs_entries(void) |
285 | { | 286 | { |
@@ -288,15 +289,13 @@ qeth_create_procfs_entries(void) | |||
288 | if (qeth_procfile) | 289 | if (qeth_procfile) |
289 | qeth_procfile->proc_fops = &qeth_procfile_fops; | 290 | qeth_procfile->proc_fops = &qeth_procfile_fops; |
290 | 291 | ||
291 | #ifdef CONFIG_QETH_PERF_STATS | ||
292 | qeth_perf_procfile = create_proc_entry(QETH_PERF_PROCFILE_NAME, | 292 | qeth_perf_procfile = create_proc_entry(QETH_PERF_PROCFILE_NAME, |
293 | S_IFREG | 0444, NULL); | 293 | S_IFREG | 0444, NULL); |
294 | if (qeth_perf_procfile) | 294 | if (qeth_perf_procfile) |
295 | qeth_perf_procfile->proc_fops = &qeth_perf_procfile_fops; | 295 | qeth_perf_procfile->proc_fops = &qeth_perf_procfile_fops; |
296 | #endif /* CONFIG_QETH_PERF_STATS */ | ||
297 | 296 | ||
298 | if (qeth_procfile && | 297 | if (qeth_procfile && |
299 | qeth_perf_procfile_created) | 298 | qeth_perf_procfile) |
300 | return 0; | 299 | return 0; |
301 | else | 300 | else |
302 | return -ENOMEM; | 301 | return -ENOMEM; |
diff --git a/drivers/s390/net/qeth_sys.c b/drivers/s390/net/qeth_sys.c index 001497bbea16..5836737ac58f 100644 --- a/drivers/s390/net/qeth_sys.c +++ b/drivers/s390/net/qeth_sys.c | |||
@@ -743,6 +743,47 @@ static DEVICE_ATTR(layer2, 0644, qeth_dev_layer2_show, | |||
743 | qeth_dev_layer2_store); | 743 | qeth_dev_layer2_store); |
744 | 744 | ||
745 | static ssize_t | 745 | static ssize_t |
746 | qeth_dev_performance_stats_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
747 | { | ||
748 | struct qeth_card *card = dev->driver_data; | ||
749 | |||
750 | if (!card) | ||
751 | return -EINVAL; | ||
752 | |||
753 | return sprintf(buf, "%i\n", card->options.performance_stats ? 1:0); | ||
754 | } | ||
755 | |||
756 | static ssize_t | ||
757 | qeth_dev_performance_stats_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | ||
758 | { | ||
759 | struct qeth_card *card = dev->driver_data; | ||
760 | char *tmp; | ||
761 | int i; | ||
762 | |||
763 | if (!card) | ||
764 | return -EINVAL; | ||
765 | |||
766 | i = simple_strtoul(buf, &tmp, 16); | ||
767 | if ((i == 0) || (i == 1)) { | ||
768 | if (i == card->options.performance_stats) | ||
769 | return count; | ||
770 | card->options.performance_stats = i; | ||
771 | if (i == 0) | ||
772 | memset(&card->perf_stats, 0, | ||
773 | sizeof(struct qeth_perf_stats)); | ||
774 | card->perf_stats.initial_rx_packets = card->stats.rx_packets; | ||
775 | card->perf_stats.initial_tx_packets = card->stats.tx_packets; | ||
776 | } else { | ||
777 | PRINT_WARN("performance_stats: write 0 or 1 to this file!\n"); | ||
778 | return -EINVAL; | ||
779 | } | ||
780 | return count; | ||
781 | } | ||
782 | |||
783 | static DEVICE_ATTR(performance_stats, 0644, qeth_dev_performance_stats_show, | ||
784 | qeth_dev_performance_stats_store); | ||
785 | |||
786 | static ssize_t | ||
746 | qeth_dev_large_send_show(struct device *dev, struct device_attribute *attr, char *buf) | 787 | qeth_dev_large_send_show(struct device *dev, struct device_attribute *attr, char *buf) |
747 | { | 788 | { |
748 | struct qeth_card *card = dev->driver_data; | 789 | struct qeth_card *card = dev->driver_data; |
@@ -928,6 +969,7 @@ static struct device_attribute * qeth_device_attrs[] = { | |||
928 | &dev_attr_canonical_macaddr, | 969 | &dev_attr_canonical_macaddr, |
929 | &dev_attr_layer2, | 970 | &dev_attr_layer2, |
930 | &dev_attr_large_send, | 971 | &dev_attr_large_send, |
972 | &dev_attr_performance_stats, | ||
931 | NULL, | 973 | NULL, |
932 | }; | 974 | }; |
933 | 975 | ||
@@ -1110,12 +1152,12 @@ qeth_parse_ipatoe(const char* buf, enum qeth_prot_versions proto, | |||
1110 | { | 1152 | { |
1111 | const char *start, *end; | 1153 | const char *start, *end; |
1112 | char *tmp; | 1154 | char *tmp; |
1113 | char buffer[49] = {0, }; | 1155 | char buffer[40] = {0, }; |
1114 | 1156 | ||
1115 | start = buf; | 1157 | start = buf; |
1116 | /* get address string */ | 1158 | /* get address string */ |
1117 | end = strchr(start, '/'); | 1159 | end = strchr(start, '/'); |
1118 | if (!end || (end-start >= 49)){ | 1160 | if (!end || (end - start >= 40)){ |
1119 | PRINT_WARN("Invalid format for ipato_addx/delx. " | 1161 | PRINT_WARN("Invalid format for ipato_addx/delx. " |
1120 | "Use <ip addr>/<mask bits>\n"); | 1162 | "Use <ip addr>/<mask bits>\n"); |
1121 | return -EINVAL; | 1163 | return -EINVAL; |
@@ -1127,7 +1169,12 @@ qeth_parse_ipatoe(const char* buf, enum qeth_prot_versions proto, | |||
1127 | } | 1169 | } |
1128 | start = end + 1; | 1170 | start = end + 1; |
1129 | *mask_bits = simple_strtoul(start, &tmp, 10); | 1171 | *mask_bits = simple_strtoul(start, &tmp, 10); |
1130 | 1172 | if (!strlen(start) || | |
1173 | (tmp == start) || | ||
1174 | (*mask_bits > ((proto == QETH_PROT_IPV4) ? 32 : 128))) { | ||
1175 | PRINT_WARN("Invalid mask bits for ipato_addx/delx !\n"); | ||
1176 | return -EINVAL; | ||
1177 | } | ||
1131 | return 0; | 1178 | return 0; |
1132 | } | 1179 | } |
1133 | 1180 | ||
@@ -1698,11 +1745,16 @@ qeth_create_device_attributes(struct device *dev) | |||
1698 | sysfs_remove_group(&dev->kobj, &qeth_device_attr_group); | 1745 | sysfs_remove_group(&dev->kobj, &qeth_device_attr_group); |
1699 | sysfs_remove_group(&dev->kobj, &qeth_device_ipato_group); | 1746 | sysfs_remove_group(&dev->kobj, &qeth_device_ipato_group); |
1700 | sysfs_remove_group(&dev->kobj, &qeth_device_vipa_group); | 1747 | sysfs_remove_group(&dev->kobj, &qeth_device_vipa_group); |
1748 | return ret; | ||
1701 | } | 1749 | } |
1702 | if ((ret = sysfs_create_group(&dev->kobj, &qeth_device_blkt_group))) | 1750 | if ((ret = sysfs_create_group(&dev->kobj, &qeth_device_blkt_group))){ |
1751 | sysfs_remove_group(&dev->kobj, &qeth_device_attr_group); | ||
1752 | sysfs_remove_group(&dev->kobj, &qeth_device_ipato_group); | ||
1753 | sysfs_remove_group(&dev->kobj, &qeth_device_vipa_group); | ||
1754 | sysfs_remove_group(&dev->kobj, &qeth_device_rxip_group); | ||
1703 | return ret; | 1755 | return ret; |
1704 | 1756 | } | |
1705 | return ret; | 1757 | return 0; |
1706 | } | 1758 | } |
1707 | 1759 | ||
1708 | void | 1760 | void |
diff --git a/drivers/s390/net/qeth_tso.h b/drivers/s390/net/qeth_tso.h index 593f298142c1..14504afb044e 100644 --- a/drivers/s390/net/qeth_tso.h +++ b/drivers/s390/net/qeth_tso.h | |||
@@ -24,7 +24,7 @@ static inline struct qeth_hdr_tso * | |||
24 | qeth_tso_prepare_skb(struct qeth_card *card, struct sk_buff **skb) | 24 | qeth_tso_prepare_skb(struct qeth_card *card, struct sk_buff **skb) |
25 | { | 25 | { |
26 | QETH_DBF_TEXT(trace, 5, "tsoprsk"); | 26 | QETH_DBF_TEXT(trace, 5, "tsoprsk"); |
27 | return qeth_push_skb(card, skb, sizeof(struct qeth_hdr_tso)); | 27 | return qeth_push_skb(card, *skb, sizeof(struct qeth_hdr_tso)); |
28 | } | 28 | } |
29 | 29 | ||
30 | /** | 30 | /** |