Commit a264d830 authored by David S. Miller's avatar David S. Miller

Merge branch 'qeth-next'

Ursula Braun says:

====================
s390: qeth patches

here are patches for the s390 qeth driver for net-next:

Patch 01 is a minor improvement for the bridgeport code in qeth.

Patches 02-07 take care about scatter/gather handling in qeth.

Patch 08 improves handling of multicast IP addresses in the qeth layer3
discipline.

Patches 09-11 improve netdev features related functions in qeth.

Patch 12 implements an outbound queue restriction for HiperSockets.

Patch 13 fixes a wrong indentation in qeth_l3_main.c causing a warning
with gcc-6.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 318d3cc0 77a83ed1
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/ethtool.h> #include <linux/ethtool.h>
#include <linux/hashtable.h> #include <linux/hashtable.h>
#include <linux/ip.h>
#include <net/ipv6.h> #include <net/ipv6.h>
#include <net/if_inet6.h> #include <net/if_inet6.h>
...@@ -144,6 +145,7 @@ struct qeth_perf_stats { ...@@ -144,6 +145,7 @@ struct qeth_perf_stats {
unsigned int sg_alloc_page_rx; unsigned int sg_alloc_page_rx;
unsigned int tx_csum; unsigned int tx_csum;
unsigned int tx_lin; unsigned int tx_lin;
unsigned int tx_linfail;
}; };
/* Routing stuff */ /* Routing stuff */
...@@ -559,7 +561,6 @@ enum qeth_ip_types { ...@@ -559,7 +561,6 @@ enum qeth_ip_types {
QETH_IP_TYPE_NORMAL, QETH_IP_TYPE_NORMAL,
QETH_IP_TYPE_VIPA, QETH_IP_TYPE_VIPA,
QETH_IP_TYPE_RXIP, QETH_IP_TYPE_RXIP,
QETH_IP_TYPE_DEL_ALL_MC,
}; };
enum qeth_cmd_buffer_state { enum qeth_cmd_buffer_state {
...@@ -740,17 +741,10 @@ struct qeth_vlan_vid { ...@@ -740,17 +741,10 @@ struct qeth_vlan_vid {
unsigned short vid; unsigned short vid;
}; };
enum qeth_mac_disposition { enum qeth_addr_disposition {
QETH_DISP_MAC_DELETE = 0, QETH_DISP_ADDR_DELETE = 0,
QETH_DISP_MAC_DO_NOTHING = 1, QETH_DISP_ADDR_DO_NOTHING = 1,
QETH_DISP_MAC_ADD = 2, QETH_DISP_ADDR_ADD = 2,
};
struct qeth_mac {
u8 mac_addr[OSA_ADDR_LEN];
u8 is_uc:1;
u8 disp_flag:2;
struct hlist_node hnode;
}; };
struct qeth_rx { struct qeth_rx {
...@@ -798,6 +792,8 @@ struct qeth_card { ...@@ -798,6 +792,8 @@ struct qeth_card {
unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)]; unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
struct list_head vid_list; struct list_head vid_list;
DECLARE_HASHTABLE(mac_htable, 4); DECLARE_HASHTABLE(mac_htable, 4);
DECLARE_HASHTABLE(ip_htable, 4);
DECLARE_HASHTABLE(ip_mc_htable, 4);
struct work_struct kernel_thread_starter; struct work_struct kernel_thread_starter;
spinlock_t thread_mask_lock; spinlock_t thread_mask_lock;
unsigned long thread_start_mask; unsigned long thread_start_mask;
...@@ -805,8 +801,6 @@ struct qeth_card { ...@@ -805,8 +801,6 @@ struct qeth_card {
unsigned long thread_running_mask; unsigned long thread_running_mask;
struct task_struct *recovery_task; struct task_struct *recovery_task;
spinlock_t ip_lock; spinlock_t ip_lock;
struct list_head ip_list;
struct list_head *ip_tbd_list;
struct qeth_ipato ipato; struct qeth_ipato ipato;
struct list_head cmd_waiter_list; struct list_head cmd_waiter_list;
/* QDIO buffer handling */ /* QDIO buffer handling */
...@@ -844,6 +838,19 @@ struct qeth_trap_id { ...@@ -844,6 +838,19 @@ struct qeth_trap_id {
/*some helper functions*/ /*some helper functions*/
#define QETH_CARD_IFNAME(card) (((card)->dev)? (card)->dev->name : "") #define QETH_CARD_IFNAME(card) (((card)->dev)? (card)->dev->name : "")
/**
* qeth_get_elements_for_range() - find number of SBALEs to cover range.
* @start: Start of the address range.
* @end: Address after the end of the range.
*
* Returns the number of pages, and thus QDIO buffer elements, needed to cover
* the specified address range.
*/
static inline int qeth_get_elements_for_range(addr_t start, addr_t end)
{
return PFN_UP(end - 1) - PFN_DOWN(start);
}
static inline int qeth_get_micros(void) static inline int qeth_get_micros(void)
{ {
return (int) (get_tod_clock() >> 12); return (int) (get_tod_clock() >> 12);
...@@ -865,6 +872,11 @@ static inline int qeth_get_ip_version(struct sk_buff *skb) ...@@ -865,6 +872,11 @@ static inline int qeth_get_ip_version(struct sk_buff *skb)
} }
} }
static inline int qeth_get_ip_protocol(struct sk_buff *skb)
{
return ip_hdr(skb)->protocol;
}
static inline void qeth_put_buffer_pool_entry(struct qeth_card *card, static inline void qeth_put_buffer_pool_entry(struct qeth_card *card,
struct qeth_buffer_pool_entry *entry) struct qeth_buffer_pool_entry *entry)
{ {
...@@ -981,12 +993,13 @@ int qeth_send_setassparms(struct qeth_card *, struct qeth_cmd_buffer *, __u16, ...@@ -981,12 +993,13 @@ int qeth_send_setassparms(struct qeth_card *, struct qeth_cmd_buffer *, __u16,
int (*reply_cb)(struct qeth_card *, int (*reply_cb)(struct qeth_card *,
struct qeth_reply *, unsigned long), struct qeth_reply *, unsigned long),
void *); void *);
int qeth_setassparms_cb(struct qeth_card *, struct qeth_reply *, unsigned long);
struct qeth_cmd_buffer *qeth_get_setassparms_cmd(struct qeth_card *, struct qeth_cmd_buffer *qeth_get_setassparms_cmd(struct qeth_card *,
enum qeth_ipa_funcs, enum qeth_ipa_funcs,
__u16, __u16, __u16, __u16,
enum qeth_prot_versions); enum qeth_prot_versions);
int qeth_start_ipa_tx_checksum(struct qeth_card *); int qeth_set_features(struct net_device *, netdev_features_t);
int qeth_set_rx_csum(struct qeth_card *, int); netdev_features_t qeth_fix_features(struct net_device *, netdev_features_t);
/* exports for OSN */ /* exports for OSN */
int qeth_osn_assist(struct net_device *, void *, int); int qeth_osn_assist(struct net_device *, void *, int);
......
This diff is collapsed.
...@@ -243,6 +243,10 @@ static ssize_t qeth_dev_prioqing_store(struct device *dev, ...@@ -243,6 +243,10 @@ static ssize_t qeth_dev_prioqing_store(struct device *dev,
card->qdio.do_prio_queueing = QETH_NO_PRIO_QUEUEING; card->qdio.do_prio_queueing = QETH_NO_PRIO_QUEUEING;
card->qdio.default_out_queue = 2; card->qdio.default_out_queue = 2;
} else if (sysfs_streq(buf, "no_prio_queueing:3")) { } else if (sysfs_streq(buf, "no_prio_queueing:3")) {
if (card->info.type == QETH_CARD_TYPE_IQD) {
rc = -EPERM;
goto out;
}
card->qdio.do_prio_queueing = QETH_NO_PRIO_QUEUEING; card->qdio.do_prio_queueing = QETH_NO_PRIO_QUEUEING;
card->qdio.default_out_queue = 3; card->qdio.default_out_queue = 3;
} else if (sysfs_streq(buf, "no_prio_queueing")) { } else if (sysfs_streq(buf, "no_prio_queueing")) {
......
...@@ -12,4 +12,11 @@ int qeth_l2_create_device_attributes(struct device *); ...@@ -12,4 +12,11 @@ int qeth_l2_create_device_attributes(struct device *);
void qeth_l2_remove_device_attributes(struct device *); void qeth_l2_remove_device_attributes(struct device *);
void qeth_l2_setup_bridgeport_attrs(struct qeth_card *card); void qeth_l2_setup_bridgeport_attrs(struct qeth_card *card);
struct qeth_mac {
u8 mac_addr[OSA_ADDR_LEN];
u8 is_uc:1;
u8 disp_flag:2;
struct hlist_node hnode;
};
#endif /* __QETH_L2_H__ */ #endif /* __QETH_L2_H__ */
...@@ -404,38 +404,6 @@ static int qeth_l2_vlan_rx_kill_vid(struct net_device *dev, ...@@ -404,38 +404,6 @@ static int qeth_l2_vlan_rx_kill_vid(struct net_device *dev,
return rc; return rc;
} }
static netdev_features_t qeth_l2_fix_features(struct net_device *dev,
netdev_features_t features)
{
struct qeth_card *card = dev->ml_priv;
QETH_DBF_TEXT(SETUP, 2, "fixfeat");
if (!qeth_is_supported(card, IPA_OUTBOUND_CHECKSUM))
features &= ~NETIF_F_IP_CSUM;
if (!qeth_is_supported(card, IPA_INBOUND_CHECKSUM))
features &= ~NETIF_F_RXCSUM;
QETH_DBF_HEX(SETUP, 2, &features, sizeof(features));
return features;
}
static int qeth_l2_set_features(struct net_device *dev,
netdev_features_t features)
{
struct qeth_card *card = dev->ml_priv;
netdev_features_t changed = dev->features ^ features;
QETH_DBF_TEXT(SETUP, 2, "setfeat");
QETH_DBF_HEX(SETUP, 2, &features, sizeof(features));
if (card->state == CARD_STATE_DOWN ||
card->state == CARD_STATE_RECOVER)
return 0;
if (!(changed & NETIF_F_RXCSUM))
return 0;
return qeth_set_rx_csum(card, features & NETIF_F_RXCSUM ? 1 : 0);
}
static void qeth_l2_stop_card(struct qeth_card *card, int recovery_mode) static void qeth_l2_stop_card(struct qeth_card *card, int recovery_mode)
{ {
QETH_DBF_TEXT(SETUP , 2, "stopcard"); QETH_DBF_TEXT(SETUP , 2, "stopcard");
...@@ -780,7 +748,7 @@ qeth_l2_add_mac(struct qeth_card *card, struct netdev_hw_addr *ha, u8 is_uc) ...@@ -780,7 +748,7 @@ qeth_l2_add_mac(struct qeth_card *card, struct netdev_hw_addr *ha, u8 is_uc)
qeth_l2_mac_hash(ha->addr)) { qeth_l2_mac_hash(ha->addr)) {
if (is_uc == mac->is_uc && if (is_uc == mac->is_uc &&
!memcmp(ha->addr, mac->mac_addr, OSA_ADDR_LEN)) { !memcmp(ha->addr, mac->mac_addr, OSA_ADDR_LEN)) {
mac->disp_flag = QETH_DISP_MAC_DO_NOTHING; mac->disp_flag = QETH_DISP_ADDR_DO_NOTHING;
return; return;
} }
} }
...@@ -792,7 +760,7 @@ qeth_l2_add_mac(struct qeth_card *card, struct netdev_hw_addr *ha, u8 is_uc) ...@@ -792,7 +760,7 @@ qeth_l2_add_mac(struct qeth_card *card, struct netdev_hw_addr *ha, u8 is_uc)
memcpy(mac->mac_addr, ha->addr, OSA_ADDR_LEN); memcpy(mac->mac_addr, ha->addr, OSA_ADDR_LEN);
mac->is_uc = is_uc; mac->is_uc = is_uc;
mac->disp_flag = QETH_DISP_MAC_ADD; mac->disp_flag = QETH_DISP_ADDR_ADD;
hash_add(card->mac_htable, &mac->hnode, hash_add(card->mac_htable, &mac->hnode,
qeth_l2_mac_hash(mac->mac_addr)); qeth_l2_mac_hash(mac->mac_addr));
...@@ -825,7 +793,7 @@ static void qeth_l2_set_rx_mode(struct net_device *dev) ...@@ -825,7 +793,7 @@ static void qeth_l2_set_rx_mode(struct net_device *dev)
qeth_l2_add_mac(card, ha, 1); qeth_l2_add_mac(card, ha, 1);
hash_for_each_safe(card->mac_htable, i, tmp, mac, hnode) { hash_for_each_safe(card->mac_htable, i, tmp, mac, hnode) {
if (mac->disp_flag == QETH_DISP_MAC_DELETE) { if (mac->disp_flag == QETH_DISP_ADDR_DELETE) {
if (!mac->is_uc) if (!mac->is_uc)
rc = qeth_l2_send_delgroupmac(card, rc = qeth_l2_send_delgroupmac(card,
mac->mac_addr); mac->mac_addr);
...@@ -837,15 +805,15 @@ static void qeth_l2_set_rx_mode(struct net_device *dev) ...@@ -837,15 +805,15 @@ static void qeth_l2_set_rx_mode(struct net_device *dev)
hash_del(&mac->hnode); hash_del(&mac->hnode);
kfree(mac); kfree(mac);
} else if (mac->disp_flag == QETH_DISP_MAC_ADD) { } else if (mac->disp_flag == QETH_DISP_ADDR_ADD) {
rc = qeth_l2_write_mac(card, mac); rc = qeth_l2_write_mac(card, mac);
if (rc) { if (rc) {
hash_del(&mac->hnode); hash_del(&mac->hnode);
kfree(mac); kfree(mac);
} else } else
mac->disp_flag = QETH_DISP_MAC_DELETE; mac->disp_flag = QETH_DISP_ADDR_DELETE;
} else } else
mac->disp_flag = QETH_DISP_MAC_DELETE; mac->disp_flag = QETH_DISP_ADDR_DELETE;
} }
spin_unlock_bh(&card->mclock); spin_unlock_bh(&card->mclock);
...@@ -869,6 +837,7 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -869,6 +837,7 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
int data_offset = -1; int data_offset = -1;
int elements_needed = 0; int elements_needed = 0;
int hd_len = 0; int hd_len = 0;
int nr_frags;
if (card->qdio.do_prio_queueing || (cast_type && if (card->qdio.do_prio_queueing || (cast_type &&
card->info.is_multicast_different)) card->info.is_multicast_different))
...@@ -892,6 +861,23 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -892,6 +861,23 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
} }
netif_stop_queue(dev); netif_stop_queue(dev);
/* fix hardware limitation: as long as we do not have sbal
* chaining we can not send long frag lists
*/
if ((card->info.type != QETH_CARD_TYPE_IQD) &&
!qeth_get_elements_no(card, new_skb, 0)) {
int lin_rc = skb_linearize(new_skb);
if (card->options.performance_stats) {
if (lin_rc)
card->perf_stats.tx_linfail++;
else
card->perf_stats.tx_lin++;
}
if (lin_rc)
goto tx_drop;
}
if (card->info.type == QETH_CARD_TYPE_OSN) if (card->info.type == QETH_CARD_TYPE_OSN)
hdr = (struct qeth_hdr *)skb->data; hdr = (struct qeth_hdr *)skb->data;
else { else {
...@@ -943,6 +929,14 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -943,6 +929,14 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (!rc) { if (!rc) {
card->stats.tx_packets++; card->stats.tx_packets++;
card->stats.tx_bytes += tx_bytes; card->stats.tx_bytes += tx_bytes;
if (card->options.performance_stats) {
nr_frags = skb_shinfo(new_skb)->nr_frags;
if (nr_frags) {
card->perf_stats.sg_skbs_sent++;
/* nr_frags + skb->data */
card->perf_stats.sg_frags_sent += nr_frags + 1;
}
}
if (new_skb != skb) if (new_skb != skb)
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
rc = NETDEV_TX_OK; rc = NETDEV_TX_OK;
...@@ -1086,8 +1080,8 @@ static const struct net_device_ops qeth_l2_netdev_ops = { ...@@ -1086,8 +1080,8 @@ static const struct net_device_ops qeth_l2_netdev_ops = {
.ndo_vlan_rx_add_vid = qeth_l2_vlan_rx_add_vid, .ndo_vlan_rx_add_vid = qeth_l2_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = qeth_l2_vlan_rx_kill_vid, .ndo_vlan_rx_kill_vid = qeth_l2_vlan_rx_kill_vid,
.ndo_tx_timeout = qeth_tx_timeout, .ndo_tx_timeout = qeth_tx_timeout,
.ndo_fix_features = qeth_l2_fix_features, .ndo_fix_features = qeth_fix_features,
.ndo_set_features = qeth_l2_set_features .ndo_set_features = qeth_set_features
}; };
static int qeth_l2_setup_netdev(struct qeth_card *card) static int qeth_l2_setup_netdev(struct qeth_card *card)
...@@ -1118,12 +1112,25 @@ static int qeth_l2_setup_netdev(struct qeth_card *card) ...@@ -1118,12 +1112,25 @@ static int qeth_l2_setup_netdev(struct qeth_card *card)
&qeth_l2_ethtool_ops : &qeth_l2_osn_ops; &qeth_l2_ethtool_ops : &qeth_l2_osn_ops;
card->dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER; card->dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
if (card->info.type == QETH_CARD_TYPE_OSD && !card->info.guestlan) { if (card->info.type == QETH_CARD_TYPE_OSD && !card->info.guestlan) {
card->dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_RXCSUM; card->dev->hw_features = NETIF_F_SG;
/* Turn on RX offloading per default */ card->dev->vlan_features = NETIF_F_SG;
card->dev->features |= NETIF_F_RXCSUM; /* OSA 3S and earlier has no RX/TX support */
if (qeth_is_supported(card, IPA_OUTBOUND_CHECKSUM)) {
card->dev->hw_features |= NETIF_F_IP_CSUM;
card->dev->vlan_features |= NETIF_F_IP_CSUM;
}
if (qeth_is_supported(card, IPA_INBOUND_CHECKSUM)) {
card->dev->hw_features |= NETIF_F_RXCSUM;
card->dev->vlan_features |= NETIF_F_RXCSUM;
}
/* Turn on SG per default */
card->dev->features |= NETIF_F_SG;
} }
card->info.broadcast_capable = 1; card->info.broadcast_capable = 1;
qeth_l2_request_initial_mac(card); qeth_l2_request_initial_mac(card);
card->dev->gso_max_size = (QETH_MAX_BUFFER_ELEMENTS(card) - 1) *
PAGE_SIZE;
card->dev->gso_max_segs = (QETH_MAX_BUFFER_ELEMENTS(card) - 1);
SET_NETDEV_DEV(card->dev, &card->gdev->dev); SET_NETDEV_DEV(card->dev, &card->gdev->dev);
netif_napi_add(card->dev, &card->napi, qeth_l2_poll, QETH_NAPI_WEIGHT); netif_napi_add(card->dev, &card->napi, qeth_l2_poll, QETH_NAPI_WEIGHT);
netif_carrier_off(card->dev); netif_carrier_off(card->dev);
...@@ -1135,9 +1142,6 @@ static int qeth_l2_start_ipassists(struct qeth_card *card) ...@@ -1135,9 +1142,6 @@ static int qeth_l2_start_ipassists(struct qeth_card *card)
/* configure isolation level */ /* configure isolation level */
if (qeth_set_access_ctrl_online(card, 0)) if (qeth_set_access_ctrl_online(card, 0))
return -ENODEV; return -ENODEV;
if (qeth_is_supported(card, IPA_INBOUND_CHECKSUM))
qeth_set_rx_csum(card, 1);
qeth_start_ipa_tx_checksum(card);
return 0; return 0;
} }
...@@ -1206,7 +1210,8 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode) ...@@ -1206,7 +1210,8 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode)
contin: contin:
if ((card->info.type == QETH_CARD_TYPE_OSD) || if ((card->info.type == QETH_CARD_TYPE_OSD) ||
(card->info.type == QETH_CARD_TYPE_OSX)) { (card->info.type == QETH_CARD_TYPE_OSX)) {
if (qeth_l2_start_ipassists(card)) rc = qeth_l2_start_ipassists(card);
if (rc)
goto out_remove; goto out_remove;
} }
...@@ -1800,6 +1805,12 @@ static int qeth_bridgeport_makerc(struct qeth_card *card, ...@@ -1800,6 +1805,12 @@ static int qeth_bridgeport_makerc(struct qeth_card *card,
dev_err(&card->gdev->dev, dev_err(&card->gdev->dev,
"The device is not configured as a Bridge Port\n"); "The device is not configured as a Bridge Port\n");
break; break;
case 0x2B10:
case 0x0010: /* OS mismatch */
rc = -EPERM;
dev_err(&card->gdev->dev,
"A Bridge Port is already configured by a different operating system\n");
break;
case 0x2B14: case 0x2B14:
case 0x0014: /* Another device is Primary */ case 0x0014: /* Another device is Primary */
switch (setcmd) { switch (setcmd) {
......
...@@ -10,16 +10,23 @@ ...@@ -10,16 +10,23 @@
#define __QETH_L3_H__ #define __QETH_L3_H__
#include "qeth_core.h" #include "qeth_core.h"
#include <linux/hashtable.h>
#define QETH_SNIFF_AVAIL 0x0008 #define QETH_SNIFF_AVAIL 0x0008
struct qeth_ipaddr { struct qeth_ipaddr {
struct list_head entry; struct hlist_node hnode;
enum qeth_ip_types type; enum qeth_ip_types type;
enum qeth_ipa_setdelip_flags set_flags; enum qeth_ipa_setdelip_flags set_flags;
enum qeth_ipa_setdelip_flags del_flags; enum qeth_ipa_setdelip_flags del_flags;
int is_multicast; u8 is_multicast:1;
int users; u8 in_progress:1;
u8 disp_flag:2;
/* is changed only for normal ip addresses
* for non-normal addresses it always is 1
*/
int ref_counter;
enum qeth_prot_versions proto; enum qeth_prot_versions proto;
unsigned char mac[OSA_ADDR_LEN]; unsigned char mac[OSA_ADDR_LEN];
union { union {
...@@ -32,7 +39,24 @@ struct qeth_ipaddr { ...@@ -32,7 +39,24 @@ struct qeth_ipaddr {
unsigned int pfxlen; unsigned int pfxlen;
} a6; } a6;
} u; } u;
}; };
static inline u64 qeth_l3_ipaddr_hash(struct qeth_ipaddr *addr)
{
u64 ret = 0;
u8 *point;
if (addr->proto == QETH_PROT_IPV6) {
point = (u8 *) &addr->u.a6.addr;
ret = get_unaligned((u64 *)point) ^
get_unaligned((u64 *) (point + 8));
}
if (addr->proto == QETH_PROT_IPV4) {
point = (u8 *) &addr->u.a4.addr;
ret = get_unaligned((u32 *) point);
}
return ret;
}
struct qeth_ipato_entry { struct qeth_ipato_entry {
struct list_head entry; struct list_head entry;
...@@ -60,6 +84,5 @@ int qeth_l3_is_addr_covered_by_ipato(struct qeth_card *, struct qeth_ipaddr *); ...@@ -60,6 +84,5 @@ int qeth_l3_is_addr_covered_by_ipato(struct qeth_card *, struct qeth_ipaddr *);
struct qeth_ipaddr *qeth_l3_get_addr_buffer(enum qeth_prot_versions); struct qeth_ipaddr *qeth_l3_get_addr_buffer(enum qeth_prot_versions);
int qeth_l3_add_ip(struct qeth_card *, struct qeth_ipaddr *); int qeth_l3_add_ip(struct qeth_card *, struct qeth_ipaddr *);
int qeth_l3_delete_ip(struct qeth_card *, struct qeth_ipaddr *); int qeth_l3_delete_ip(struct qeth_card *, struct qeth_ipaddr *);
void qeth_l3_set_ip_addr_list(struct qeth_card *);
#endif /* __QETH_L3_H__ */ #endif /* __QETH_L3_H__ */
This diff is collapsed.
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <asm/ebcdic.h> #include <asm/ebcdic.h>
#include <linux/hashtable.h>
#include "qeth_l3.h" #include "qeth_l3.h"
#define QETH_DEVICE_ATTR(_id, _name, _mode, _show, _store) \ #define QETH_DEVICE_ATTR(_id, _name, _mode, _show, _store) \
...@@ -285,19 +286,19 @@ static ssize_t qeth_l3_dev_hsuid_store(struct device *dev, ...@@ -285,19 +286,19 @@ static ssize_t qeth_l3_dev_hsuid_store(struct device *dev,
if (card->options.hsuid[0]) { if (card->options.hsuid[0]) {
/* delete old ip address */ /* delete old ip address */
addr = qeth_l3_get_addr_buffer(QETH_PROT_IPV6); addr = qeth_l3_get_addr_buffer(QETH_PROT_IPV6);
if (addr != NULL) { if (!addr)
addr->u.a6.addr.s6_addr32[0] = 0xfe800000;
addr->u.a6.addr.s6_addr32[1] = 0x00000000;
for (i = 8; i < 16; i++)
addr->u.a6.addr.s6_addr[i] =
card->options.hsuid[i - 8];
addr->u.a6.pfxlen = 0;
addr->type = QETH_IP_TYPE_NORMAL;
} else
return -ENOMEM; return -ENOMEM;
if (!qeth_l3_delete_ip(card, addr))
kfree(addr); addr->u.a6.addr.s6_addr32[0] = 0xfe800000;
qeth_l3_set_ip_addr_list(card); addr->u.a6.addr.s6_addr32[1] = 0x00000000;
for (i = 8; i < 16; i++)
addr->u.a6.addr.s6_addr[i] =
card->options.hsuid[i - 8];
addr->u.a6.pfxlen = 0;
addr->type = QETH_IP_TYPE_NORMAL;
qeth_l3_delete_ip(card, addr);
kfree(addr);
} }
if (strlen(tmp) == 0) { if (strlen(tmp) == 0) {
...@@ -328,9 +329,8 @@ static ssize_t qeth_l3_dev_hsuid_store(struct device *dev, ...@@ -328,9 +329,8 @@ static ssize_t qeth_l3_dev_hsuid_store(struct device *dev,
addr->type = QETH_IP_TYPE_NORMAL; addr->type = QETH_IP_TYPE_NORMAL;
} else } else
return -ENOMEM; return -ENOMEM;
if (!qeth_l3_add_ip(card, addr)) qeth_l3_add_ip(card, addr);
kfree(addr); kfree(addr);
qeth_l3_set_ip_addr_list(card);
return count; return count;
} }
...@@ -367,8 +367,8 @@ static ssize_t qeth_l3_dev_ipato_enable_store(struct device *dev, ...@@ -367,8 +367,8 @@ static ssize_t qeth_l3_dev_ipato_enable_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count) struct device_attribute *attr, const char *buf, size_t count)
{ {
struct qeth_card *card = dev_get_drvdata(dev); struct qeth_card *card = dev_get_drvdata(dev);
struct qeth_ipaddr *tmpipa, *t; struct qeth_ipaddr *addr;
int rc = 0; int i, rc = 0;
if (!card) if (!card)
return -EINVAL; return -EINVAL;
...@@ -384,21 +384,20 @@ static ssize_t qeth_l3_dev_ipato_enable_store(struct device *dev, ...@@ -384,21 +384,20 @@ static ssize_t qeth_l3_dev_ipato_enable_store(struct device *dev,
card->ipato.enabled = (card->ipato.enabled)? 0 : 1; card->ipato.enabled = (card->ipato.enabled)? 0 : 1;
} else if (sysfs_streq(buf, "1")) { } else if (sysfs_streq(buf, "1")) {
card->ipato.enabled = 1; card->ipato.enabled = 1;
list_for_each_entry_safe(tmpipa, t, card->ip_tbd_list, entry) { hash_for_each(card->ip_htable, i, addr, hnode) {
if ((tmpipa->type == QETH_IP_TYPE_NORMAL) && if ((addr->type == QETH_IP_TYPE_NORMAL) &&
qeth_l3_is_addr_covered_by_ipato(card, tmpipa)) qeth_l3_is_addr_covered_by_ipato(card, addr))
tmpipa->set_flags |= addr->set_flags |=
QETH_IPA_SETIP_TAKEOVER_FLAG; QETH_IPA_SETIP_TAKEOVER_FLAG;
} }
} else if (sysfs_streq(buf, "0")) { } else if (sysfs_streq(buf, "0")) {
card->ipato.enabled = 0; card->ipato.enabled = 0;
list_for_each_entry_safe(tmpipa, t, card->ip_tbd_list, entry) { hash_for_each(card->ip_htable, i, addr, hnode) {
if (tmpipa->set_flags & if (addr->set_flags &
QETH_IPA_SETIP_TAKEOVER_FLAG) QETH_IPA_SETIP_TAKEOVER_FLAG)
tmpipa->set_flags &= addr->set_flags &=
~QETH_IPA_SETIP_TAKEOVER_FLAG; ~QETH_IPA_SETIP_TAKEOVER_FLAG;
} }
} else } else
rc = -EINVAL; rc = -EINVAL;
out: out:
...@@ -452,7 +451,6 @@ static ssize_t qeth_l3_dev_ipato_add_show(char *buf, struct qeth_card *card, ...@@ -452,7 +451,6 @@ static ssize_t qeth_l3_dev_ipato_add_show(char *buf, struct qeth_card *card,
enum qeth_prot_versions proto) enum qeth_prot_versions proto)
{ {
struct qeth_ipato_entry *ipatoe; struct qeth_ipato_entry *ipatoe;
unsigned long flags;
char addr_str[40]; char addr_str[40];
int entry_len; /* length of 1 entry string, differs between v4 and v6 */ int entry_len; /* length of 1 entry string, differs between v4 and v6 */
int i = 0; int i = 0;
...@@ -460,7 +458,7 @@ static ssize_t qeth_l3_dev_ipato_add_show(char *buf, struct qeth_card *card, ...@@ -460,7 +458,7 @@ static ssize_t qeth_l3_dev_ipato_add_show(char *buf, struct qeth_card *card,
entry_len = (proto == QETH_PROT_IPV4)? 12 : 40; entry_len = (proto == QETH_PROT_IPV4)? 12 : 40;
/* add strlen for "/<mask>\n" */ /* add strlen for "/<mask>\n" */
entry_len += (proto == QETH_PROT_IPV4)? 5 : 6; entry_len += (proto == QETH_PROT_IPV4)? 5 : 6;
spin_lock_irqsave(&card->ip_lock, flags); spin_lock_bh(&card->ip_lock);
list_for_each_entry(ipatoe, &card->ipato.entries, entry) { list_for_each_entry(ipatoe, &card->ipato.entries, entry) {
if (ipatoe->proto != proto) if (ipatoe->proto != proto)
continue; continue;
...@@ -473,7 +471,7 @@ static ssize_t qeth_l3_dev_ipato_add_show(char *buf, struct qeth_card *card, ...@@ -473,7 +471,7 @@ static ssize_t qeth_l3_dev_ipato_add_show(char *buf, struct qeth_card *card,
i += snprintf(buf + i, PAGE_SIZE - i, i += snprintf(buf + i, PAGE_SIZE - i,
"%s/%i\n", addr_str, ipatoe->mask_bits); "%s/%i\n", addr_str, ipatoe->mask_bits);
} }
spin_unlock_irqrestore(&card->ip_lock, flags); spin_unlock_bh(&card->ip_lock);
i += snprintf(buf + i, PAGE_SIZE - i, "\n"); i += snprintf(buf + i, PAGE_SIZE - i, "\n");
return i; return i;
...@@ -689,15 +687,15 @@ static ssize_t qeth_l3_dev_vipa_add_show(char *buf, struct qeth_card *card, ...@@ -689,15 +687,15 @@ static ssize_t qeth_l3_dev_vipa_add_show(char *buf, struct qeth_card *card,
enum qeth_prot_versions proto) enum qeth_prot_versions proto)
{ {
struct qeth_ipaddr *ipaddr; struct qeth_ipaddr *ipaddr;
struct hlist_node *tmp;
char addr_str[40]; char addr_str[40];
int entry_len; /* length of 1 entry string, differs between v4 and v6 */ int entry_len; /* length of 1 entry string, differs between v4 and v6 */
unsigned long flags;
int i = 0; int i = 0;
entry_len = (proto == QETH_PROT_IPV4)? 12 : 40; entry_len = (proto == QETH_PROT_IPV4)? 12 : 40;
entry_len += 2; /* \n + terminator */ entry_len += 2; /* \n + terminator */
spin_lock_irqsave(&card->ip_lock, flags); spin_lock_bh(&card->ip_lock);
list_for_each_entry(ipaddr, &card->ip_list, entry) { hash_for_each_safe(card->ip_htable, i, tmp, ipaddr, hnode) {
if (ipaddr->proto != proto) if (ipaddr->proto != proto)
continue; continue;
if (ipaddr->type != QETH_IP_TYPE_VIPA) if (ipaddr->type != QETH_IP_TYPE_VIPA)
...@@ -711,7 +709,7 @@ static ssize_t qeth_l3_dev_vipa_add_show(char *buf, struct qeth_card *card, ...@@ -711,7 +709,7 @@ static ssize_t qeth_l3_dev_vipa_add_show(char *buf, struct qeth_card *card,
addr_str); addr_str);
i += snprintf(buf + i, PAGE_SIZE - i, "%s\n", addr_str); i += snprintf(buf + i, PAGE_SIZE - i, "%s\n", addr_str);
} }
spin_unlock_irqrestore(&card->ip_lock, flags); spin_unlock_bh(&card->ip_lock);
i += snprintf(buf + i, PAGE_SIZE - i, "\n"); i += snprintf(buf + i, PAGE_SIZE - i, "\n");
return i; return i;
...@@ -851,15 +849,15 @@ static ssize_t qeth_l3_dev_rxip_add_show(char *buf, struct qeth_card *card, ...@@ -851,15 +849,15 @@ static ssize_t qeth_l3_dev_rxip_add_show(char *buf, struct qeth_card *card,
enum qeth_prot_versions proto) enum qeth_prot_versions proto)
{ {
struct qeth_ipaddr *ipaddr; struct qeth_ipaddr *ipaddr;
struct hlist_node *tmp;
char addr_str[40]; char addr_str[40];
int entry_len; /* length of 1 entry string, differs between v4 and v6 */ int entry_len; /* length of 1 entry string, differs between v4 and v6 */
unsigned long flags;
int i = 0; int i = 0;
entry_len = (proto == QETH_PROT_IPV4)? 12 : 40; entry_len = (proto == QETH_PROT_IPV4)? 12 : 40;
entry_len += 2; /* \n + terminator */ entry_len += 2; /* \n + terminator */
spin_lock_irqsave(&card->ip_lock, flags); spin_lock_bh(&card->ip_lock);
list_for_each_entry(ipaddr, &card->ip_list, entry) { hash_for_each_safe(card->ip_htable, i, tmp, ipaddr, hnode) {
if (ipaddr->proto != proto) if (ipaddr->proto != proto)
continue; continue;
if (ipaddr->type != QETH_IP_TYPE_RXIP) if (ipaddr->type != QETH_IP_TYPE_RXIP)
...@@ -873,7 +871,7 @@ static ssize_t qeth_l3_dev_rxip_add_show(char *buf, struct qeth_card *card, ...@@ -873,7 +871,7 @@ static ssize_t qeth_l3_dev_rxip_add_show(char *buf, struct qeth_card *card,
addr_str); addr_str);
i += snprintf(buf + i, PAGE_SIZE - i, "%s\n", addr_str); i += snprintf(buf + i, PAGE_SIZE - i, "%s\n", addr_str);
} }
spin_unlock_irqrestore(&card->ip_lock, flags); spin_unlock_bh(&card->ip_lock);
i += snprintf(buf + i, PAGE_SIZE - i, "\n"); i += snprintf(buf + i, PAGE_SIZE - i, "\n");
return i; return i;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment