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: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
a264d830ab
|
@ -19,6 +19,7 @@
|
|||
#include <linux/seq_file.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/hashtable.h>
|
||||
#include <linux/ip.h>
|
||||
|
||||
#include <net/ipv6.h>
|
||||
#include <net/if_inet6.h>
|
||||
|
@ -144,6 +145,7 @@ struct qeth_perf_stats {
|
|||
unsigned int sg_alloc_page_rx;
|
||||
unsigned int tx_csum;
|
||||
unsigned int tx_lin;
|
||||
unsigned int tx_linfail;
|
||||
};
|
||||
|
||||
/* Routing stuff */
|
||||
|
@ -559,7 +561,6 @@ enum qeth_ip_types {
|
|||
QETH_IP_TYPE_NORMAL,
|
||||
QETH_IP_TYPE_VIPA,
|
||||
QETH_IP_TYPE_RXIP,
|
||||
QETH_IP_TYPE_DEL_ALL_MC,
|
||||
};
|
||||
|
||||
enum qeth_cmd_buffer_state {
|
||||
|
@ -740,17 +741,10 @@ struct qeth_vlan_vid {
|
|||
unsigned short vid;
|
||||
};
|
||||
|
||||
enum qeth_mac_disposition {
|
||||
QETH_DISP_MAC_DELETE = 0,
|
||||
QETH_DISP_MAC_DO_NOTHING = 1,
|
||||
QETH_DISP_MAC_ADD = 2,
|
||||
};
|
||||
|
||||
struct qeth_mac {
|
||||
u8 mac_addr[OSA_ADDR_LEN];
|
||||
u8 is_uc:1;
|
||||
u8 disp_flag:2;
|
||||
struct hlist_node hnode;
|
||||
enum qeth_addr_disposition {
|
||||
QETH_DISP_ADDR_DELETE = 0,
|
||||
QETH_DISP_ADDR_DO_NOTHING = 1,
|
||||
QETH_DISP_ADDR_ADD = 2,
|
||||
};
|
||||
|
||||
struct qeth_rx {
|
||||
|
@ -798,6 +792,8 @@ struct qeth_card {
|
|||
unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
|
||||
struct list_head vid_list;
|
||||
DECLARE_HASHTABLE(mac_htable, 4);
|
||||
DECLARE_HASHTABLE(ip_htable, 4);
|
||||
DECLARE_HASHTABLE(ip_mc_htable, 4);
|
||||
struct work_struct kernel_thread_starter;
|
||||
spinlock_t thread_mask_lock;
|
||||
unsigned long thread_start_mask;
|
||||
|
@ -805,8 +801,6 @@ struct qeth_card {
|
|||
unsigned long thread_running_mask;
|
||||
struct task_struct *recovery_task;
|
||||
spinlock_t ip_lock;
|
||||
struct list_head ip_list;
|
||||
struct list_head *ip_tbd_list;
|
||||
struct qeth_ipato ipato;
|
||||
struct list_head cmd_waiter_list;
|
||||
/* QDIO buffer handling */
|
||||
|
@ -844,6 +838,19 @@ struct qeth_trap_id {
|
|||
/*some helper functions*/
|
||||
#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)
|
||||
{
|
||||
return (int) (get_tod_clock() >> 12);
|
||||
|
@ -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,
|
||||
struct qeth_buffer_pool_entry *entry)
|
||||
{
|
||||
|
@ -981,12 +993,13 @@ int qeth_send_setassparms(struct qeth_card *, struct qeth_cmd_buffer *, __u16,
|
|||
int (*reply_cb)(struct qeth_card *,
|
||||
struct qeth_reply *, unsigned long),
|
||||
void *);
|
||||
int qeth_setassparms_cb(struct qeth_card *, struct qeth_reply *, unsigned long);
|
||||
struct qeth_cmd_buffer *qeth_get_setassparms_cmd(struct qeth_card *,
|
||||
enum qeth_ipa_funcs,
|
||||
__u16, __u16,
|
||||
enum qeth_prot_versions);
|
||||
int qeth_start_ipa_tx_checksum(struct qeth_card *);
|
||||
int qeth_set_rx_csum(struct qeth_card *, int);
|
||||
int qeth_set_features(struct net_device *, netdev_features_t);
|
||||
netdev_features_t qeth_fix_features(struct net_device *, netdev_features_t);
|
||||
|
||||
/* exports for OSN */
|
||||
int qeth_osn_assist(struct net_device *, void *, int);
|
||||
|
|
|
@ -1464,8 +1464,6 @@ static int qeth_setup_card(struct qeth_card *card)
|
|||
card->thread_allowed_mask = 0;
|
||||
card->thread_running_mask = 0;
|
||||
INIT_WORK(&card->kernel_thread_starter, qeth_start_kernel_thread);
|
||||
INIT_LIST_HEAD(&card->ip_list);
|
||||
INIT_LIST_HEAD(card->ip_tbd_list);
|
||||
INIT_LIST_HEAD(&card->cmd_waiter_list);
|
||||
init_waitqueue_head(&card->wait_q);
|
||||
/* initial options */
|
||||
|
@ -1500,11 +1498,6 @@ static struct qeth_card *qeth_alloc_card(void)
|
|||
if (!card)
|
||||
goto out;
|
||||
QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *));
|
||||
card->ip_tbd_list = kzalloc(sizeof(struct list_head), GFP_KERNEL);
|
||||
if (!card->ip_tbd_list) {
|
||||
QETH_DBF_TEXT(SETUP, 0, "iptbdnom");
|
||||
goto out_card;
|
||||
}
|
||||
if (qeth_setup_channel(&card->read))
|
||||
goto out_ip;
|
||||
if (qeth_setup_channel(&card->write))
|
||||
|
@ -1517,8 +1510,6 @@ static struct qeth_card *qeth_alloc_card(void)
|
|||
out_channel:
|
||||
qeth_clean_channel(&card->read);
|
||||
out_ip:
|
||||
kfree(card->ip_tbd_list);
|
||||
out_card:
|
||||
kfree(card);
|
||||
out:
|
||||
return NULL;
|
||||
|
@ -3757,6 +3748,14 @@ void qeth_qdio_output_handler(struct ccw_device *ccwdev,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(qeth_qdio_output_handler);
|
||||
|
||||
/* We cannot use outbound queue 3 for unicast packets on HiperSockets */
|
||||
static inline int qeth_cut_iqd_prio(struct qeth_card *card, int queue_num)
|
||||
{
|
||||
if ((card->info.type == QETH_CARD_TYPE_IQD) && (queue_num == 3))
|
||||
return 2;
|
||||
return queue_num;
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: Function assumes that we have 4 outbound queues.
|
||||
*/
|
||||
|
@ -3784,9 +3783,9 @@ int qeth_get_priority_queue(struct qeth_card *card, struct sk_buff *skb,
|
|||
return card->qdio.default_out_queue;
|
||||
}
|
||||
if (card->qdio.do_prio_queueing == QETH_PRIO_Q_ING_PREC)
|
||||
return ~tos >> 6 & 3;
|
||||
return qeth_cut_iqd_prio(card, ~tos >> 6 & 3);
|
||||
if (tos & IPTOS_MINCOST)
|
||||
return 3;
|
||||
return qeth_cut_iqd_prio(card, 3);
|
||||
if (tos & IPTOS_RELIABILITY)
|
||||
return 2;
|
||||
if (tos & IPTOS_THROUGHPUT)
|
||||
|
@ -3797,11 +3796,12 @@ int qeth_get_priority_queue(struct qeth_card *card, struct sk_buff *skb,
|
|||
case QETH_PRIO_Q_ING_SKB:
|
||||
if (skb->priority > 5)
|
||||
return 0;
|
||||
return ~skb->priority >> 1 & 3;
|
||||
return qeth_cut_iqd_prio(card, ~skb->priority >> 1 & 3);
|
||||
case QETH_PRIO_Q_ING_VLAN:
|
||||
tci = &((struct ethhdr *)skb->data)->h_proto;
|
||||
if (*tci == ETH_P_8021Q)
|
||||
return ~*(tci + 1) >> (VLAN_PRIO_SHIFT + 1) & 3;
|
||||
return qeth_cut_iqd_prio(card, ~*(tci + 1) >>
|
||||
(VLAN_PRIO_SHIFT + 1) & 3);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -3810,41 +3810,54 @@ int qeth_get_priority_queue(struct qeth_card *card, struct sk_buff *skb,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(qeth_get_priority_queue);
|
||||
|
||||
/**
|
||||
* qeth_get_elements_for_frags() - find number of SBALEs for skb frags.
|
||||
* @skb: SKB address
|
||||
*
|
||||
* Returns the number of pages, and thus QDIO buffer elements, needed to cover
|
||||
* fragmented part of the SKB. Returns zero for linear SKB.
|
||||
*/
|
||||
int qeth_get_elements_for_frags(struct sk_buff *skb)
|
||||
{
|
||||
int cnt, length, e, elements = 0;
|
||||
struct skb_frag_struct *frag;
|
||||
char *data;
|
||||
int cnt, elements = 0;
|
||||
|
||||
for (cnt = 0; cnt < skb_shinfo(skb)->nr_frags; cnt++) {
|
||||
frag = &skb_shinfo(skb)->frags[cnt];
|
||||
data = (char *)page_to_phys(skb_frag_page(frag)) +
|
||||
frag->page_offset;
|
||||
length = frag->size;
|
||||
e = PFN_UP((unsigned long)data + length - 1) -
|
||||
PFN_DOWN((unsigned long)data);
|
||||
elements += e;
|
||||
struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[cnt];
|
||||
|
||||
elements += qeth_get_elements_for_range(
|
||||
(addr_t)skb_frag_address(frag),
|
||||
(addr_t)skb_frag_address(frag) + skb_frag_size(frag));
|
||||
}
|
||||
return elements;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qeth_get_elements_for_frags);
|
||||
|
||||
/**
|
||||
* qeth_get_elements_no() - find number of SBALEs for skb data, inc. frags.
|
||||
* @card: qeth card structure, to check max. elems.
|
||||
* @skb: SKB address
|
||||
* @extra_elems: extra elems needed, to check against max.
|
||||
*
|
||||
* Returns the number of pages, and thus QDIO buffer elements, needed to cover
|
||||
* skb data, including linear part and fragments. Checks if the result plus
|
||||
* extra_elems fits under the limit for the card. Returns 0 if it does not.
|
||||
* Note: extra_elems is not included in the returned result.
|
||||
*/
|
||||
int qeth_get_elements_no(struct qeth_card *card,
|
||||
struct sk_buff *skb, int elems)
|
||||
struct sk_buff *skb, int extra_elems)
|
||||
{
|
||||
int dlen = skb->len - skb->data_len;
|
||||
int elements_needed = PFN_UP((unsigned long)skb->data + dlen - 1) -
|
||||
PFN_DOWN((unsigned long)skb->data);
|
||||
int elements = qeth_get_elements_for_range(
|
||||
(addr_t)skb->data,
|
||||
(addr_t)skb->data + skb_headlen(skb)) +
|
||||
qeth_get_elements_for_frags(skb);
|
||||
|
||||
elements_needed += qeth_get_elements_for_frags(skb);
|
||||
|
||||
if ((elements_needed + elems) > QETH_MAX_BUFFER_ELEMENTS(card)) {
|
||||
if ((elements + extra_elems) > QETH_MAX_BUFFER_ELEMENTS(card)) {
|
||||
QETH_DBF_MESSAGE(2, "Invalid size of IP packet "
|
||||
"(Number=%d / Length=%d). Discarded.\n",
|
||||
(elements_needed+elems), skb->len);
|
||||
elements + extra_elems, skb->len);
|
||||
return 0;
|
||||
}
|
||||
return elements_needed;
|
||||
return elements;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qeth_get_elements_no);
|
||||
|
||||
|
@ -3859,7 +3872,7 @@ int qeth_hdr_chk_and_bounce(struct sk_buff *skb, struct qeth_hdr **hdr, int len)
|
|||
rest = len - inpage;
|
||||
if (rest > hroom)
|
||||
return 1;
|
||||
memmove(skb->data - rest, skb->data, skb->len - skb->data_len);
|
||||
memmove(skb->data - rest, skb->data, skb_headlen(skb));
|
||||
skb->data -= rest;
|
||||
skb->tail -= rest;
|
||||
*hdr = (struct qeth_hdr *)skb->data;
|
||||
|
@ -3873,7 +3886,7 @@ static inline void __qeth_fill_buffer(struct sk_buff *skb,
|
|||
struct qdio_buffer *buffer, int is_tso, int *next_element_to_fill,
|
||||
int offset)
|
||||
{
|
||||
int length = skb->len - skb->data_len;
|
||||
int length = skb_headlen(skb);
|
||||
int length_here;
|
||||
int element;
|
||||
char *data;
|
||||
|
@ -4967,7 +4980,6 @@ static void qeth_core_free_card(struct qeth_card *card)
|
|||
qeth_clean_channel(&card->write);
|
||||
if (card->dev)
|
||||
free_netdev(card->dev);
|
||||
kfree(card->ip_tbd_list);
|
||||
qeth_free_qdio_buffers(card);
|
||||
unregister_service_level(&card->qeth_service_level);
|
||||
kfree(card);
|
||||
|
@ -5265,8 +5277,8 @@ no_mem:
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(qeth_core_get_next_skb);
|
||||
|
||||
static int qeth_setassparms_cb(struct qeth_card *card,
|
||||
struct qeth_reply *reply, unsigned long data)
|
||||
int qeth_setassparms_cb(struct qeth_card *card,
|
||||
struct qeth_reply *reply, unsigned long data)
|
||||
{
|
||||
struct qeth_ipa_cmd *cmd;
|
||||
|
||||
|
@ -5294,6 +5306,7 @@ static int qeth_setassparms_cb(struct qeth_card *card,
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qeth_setassparms_cb);
|
||||
|
||||
struct qeth_cmd_buffer *qeth_get_setassparms_cmd(struct qeth_card *card,
|
||||
enum qeth_ipa_funcs ipa_func,
|
||||
|
@ -5788,6 +5801,7 @@ static struct {
|
|||
{"tx do_QDIO count"},
|
||||
{"tx csum"},
|
||||
{"tx lin"},
|
||||
{"tx linfail"},
|
||||
{"cq handler count"},
|
||||
{"cq handler time"}
|
||||
};
|
||||
|
@ -5848,8 +5862,9 @@ void qeth_core_get_ethtool_stats(struct net_device *dev,
|
|||
data[32] = card->perf_stats.outbound_do_qdio_cnt;
|
||||
data[33] = card->perf_stats.tx_csum;
|
||||
data[34] = card->perf_stats.tx_lin;
|
||||
data[35] = card->perf_stats.cq_cnt;
|
||||
data[36] = card->perf_stats.cq_time;
|
||||
data[35] = card->perf_stats.tx_linfail;
|
||||
data[36] = card->perf_stats.cq_cnt;
|
||||
data[37] = card->perf_stats.cq_time;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qeth_core_get_ethtool_stats);
|
||||
|
||||
|
@ -6048,74 +6063,136 @@ int qeth_core_ethtool_get_settings(struct net_device *netdev,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(qeth_core_ethtool_get_settings);
|
||||
|
||||
static int qeth_send_checksum_command(struct qeth_card *card)
|
||||
static int qeth_send_checksum_on(struct qeth_card *card, int cstype)
|
||||
{
|
||||
long rxtx_arg;
|
||||
int rc;
|
||||
|
||||
rc = qeth_send_simple_setassparms(card, IPA_INBOUND_CHECKSUM,
|
||||
IPA_CMD_ASS_START, 0);
|
||||
rc = qeth_send_simple_setassparms(card, cstype, IPA_CMD_ASS_START, 0);
|
||||
if (rc) {
|
||||
dev_warn(&card->gdev->dev, "Starting HW checksumming for %s "
|
||||
"failed, using SW checksumming\n",
|
||||
QETH_CARD_IFNAME(card));
|
||||
dev_warn(&card->gdev->dev,
|
||||
"Starting HW checksumming for %s failed, using SW checksumming\n",
|
||||
QETH_CARD_IFNAME(card));
|
||||
return rc;
|
||||
}
|
||||
rc = qeth_send_simple_setassparms(card, IPA_INBOUND_CHECKSUM,
|
||||
IPA_CMD_ASS_ENABLE,
|
||||
card->info.csum_mask);
|
||||
rxtx_arg = (cstype == IPA_OUTBOUND_CHECKSUM) ? card->info.tx_csum_mask
|
||||
: card->info.csum_mask;
|
||||
rc = qeth_send_simple_setassparms(card, cstype, IPA_CMD_ASS_ENABLE,
|
||||
rxtx_arg);
|
||||
if (rc) {
|
||||
dev_warn(&card->gdev->dev, "Enabling HW checksumming for %s "
|
||||
"failed, using SW checksumming\n",
|
||||
QETH_CARD_IFNAME(card));
|
||||
dev_warn(&card->gdev->dev,
|
||||
"Enabling HW checksumming for %s failed, using SW checksumming\n",
|
||||
QETH_CARD_IFNAME(card));
|
||||
return rc;
|
||||
}
|
||||
|
||||
dev_info(&card->gdev->dev, "HW Checksumming (%sbound) enabled\n",
|
||||
cstype == IPA_INBOUND_CHECKSUM ? "in" : "out");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qeth_set_rx_csum(struct qeth_card *card, int on)
|
||||
static int qeth_set_ipa_csum(struct qeth_card *card, int on, int cstype)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (on) {
|
||||
rc = qeth_send_checksum_command(card);
|
||||
rc = qeth_send_checksum_on(card, cstype);
|
||||
if (rc)
|
||||
return -EIO;
|
||||
dev_info(&card->gdev->dev,
|
||||
"HW Checksumming (inbound) enabled\n");
|
||||
} else {
|
||||
rc = qeth_send_simple_setassparms(card,
|
||||
IPA_INBOUND_CHECKSUM, IPA_CMD_ASS_STOP, 0);
|
||||
rc = qeth_send_simple_setassparms(card, cstype,
|
||||
IPA_CMD_ASS_STOP, 0);
|
||||
if (rc)
|
||||
return -EIO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qeth_set_rx_csum);
|
||||
|
||||
int qeth_start_ipa_tx_checksum(struct qeth_card *card)
|
||||
static int qeth_set_ipa_tso(struct qeth_card *card, int on)
|
||||
{
|
||||
int rc = 0;
|
||||
int rc;
|
||||
|
||||
if (!qeth_is_supported(card, IPA_OUTBOUND_CHECKSUM))
|
||||
return rc;
|
||||
rc = qeth_send_simple_setassparms(card, IPA_OUTBOUND_CHECKSUM,
|
||||
IPA_CMD_ASS_START, 0);
|
||||
if (rc)
|
||||
goto err_out;
|
||||
rc = qeth_send_simple_setassparms(card, IPA_OUTBOUND_CHECKSUM,
|
||||
IPA_CMD_ASS_ENABLE,
|
||||
card->info.tx_csum_mask);
|
||||
if (rc)
|
||||
goto err_out;
|
||||
QETH_CARD_TEXT(card, 3, "sttso");
|
||||
|
||||
dev_info(&card->gdev->dev, "HW TX Checksumming enabled\n");
|
||||
return rc;
|
||||
err_out:
|
||||
dev_warn(&card->gdev->dev, "Enabling HW TX checksumming for %s "
|
||||
"failed, using SW TX checksumming\n", QETH_CARD_IFNAME(card));
|
||||
if (on) {
|
||||
rc = qeth_send_simple_setassparms(card, IPA_OUTBOUND_TSO,
|
||||
IPA_CMD_ASS_START, 0);
|
||||
if (rc) {
|
||||
dev_warn(&card->gdev->dev,
|
||||
"Starting outbound TCP segmentation offload for %s failed\n",
|
||||
QETH_CARD_IFNAME(card));
|
||||
return -EIO;
|
||||
}
|
||||
dev_info(&card->gdev->dev, "Outbound TSO enabled\n");
|
||||
} else {
|
||||
rc = qeth_send_simple_setassparms(card, IPA_OUTBOUND_TSO,
|
||||
IPA_CMD_ASS_STOP, 0);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qeth_start_ipa_tx_checksum);
|
||||
|
||||
int qeth_set_features(struct net_device *dev, netdev_features_t features)
|
||||
{
|
||||
struct qeth_card *card = dev->ml_priv;
|
||||
netdev_features_t changed = dev->features ^ features;
|
||||
int rc = 0;
|
||||
|
||||
QETH_DBF_TEXT(SETUP, 2, "setfeat");
|
||||
QETH_DBF_HEX(SETUP, 2, &features, sizeof(features));
|
||||
|
||||
if ((changed & NETIF_F_IP_CSUM)) {
|
||||
rc = qeth_set_ipa_csum(card,
|
||||
features & NETIF_F_IP_CSUM ? 1 : 0,
|
||||
IPA_OUTBOUND_CHECKSUM);
|
||||
if (rc)
|
||||
changed ^= NETIF_F_IP_CSUM;
|
||||
}
|
||||
if ((changed & NETIF_F_RXCSUM)) {
|
||||
rc = qeth_set_ipa_csum(card,
|
||||
features & NETIF_F_RXCSUM ? 1 : 0,
|
||||
IPA_INBOUND_CHECKSUM);
|
||||
if (rc)
|
||||
changed ^= NETIF_F_RXCSUM;
|
||||
}
|
||||
if ((changed & NETIF_F_TSO)) {
|
||||
rc = qeth_set_ipa_tso(card, features & NETIF_F_TSO ? 1 : 0);
|
||||
if (rc)
|
||||
changed ^= NETIF_F_TSO;
|
||||
}
|
||||
|
||||
/* everything changed successfully? */
|
||||
if ((dev->features ^ features) == changed)
|
||||
return 0;
|
||||
/* something went wrong. save changed features and return error */
|
||||
dev->features ^= changed;
|
||||
return -EIO;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qeth_set_features);
|
||||
|
||||
netdev_features_t qeth_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;
|
||||
if (!qeth_is_supported(card, IPA_OUTBOUND_TSO)) {
|
||||
features &= ~NETIF_F_TSO;
|
||||
dev_info(&card->gdev->dev, "Outbound TSO not supported on %s\n",
|
||||
QETH_CARD_IFNAME(card));
|
||||
}
|
||||
/* if the card isn't up, remove features that require hw changes */
|
||||
if (card->state == CARD_STATE_DOWN ||
|
||||
card->state == CARD_STATE_RECOVER)
|
||||
features = features & ~(NETIF_F_IP_CSUM | NETIF_F_RXCSUM |
|
||||
NETIF_F_TSO);
|
||||
QETH_DBF_HEX(SETUP, 2, &features, sizeof(features));
|
||||
return features;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qeth_fix_features);
|
||||
|
||||
static int __init qeth_core_init(void)
|
||||
{
|
||||
|
|
|
@ -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.default_out_queue = 2;
|
||||
} 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.default_out_queue = 3;
|
||||
} else if (sysfs_streq(buf, "no_prio_queueing")) {
|
||||
|
|
|
@ -12,4 +12,11 @@ int qeth_l2_create_device_attributes(struct device *);
|
|||
void qeth_l2_remove_device_attributes(struct device *);
|
||||
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__ */
|
||||
|
|
|
@ -404,38 +404,6 @@ static int qeth_l2_vlan_rx_kill_vid(struct net_device *dev,
|
|||
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)
|
||||
{
|
||||
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)
|
|||
qeth_l2_mac_hash(ha->addr)) {
|
||||
if (is_uc == mac->is_uc &&
|
||||
!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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
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,
|
||||
qeth_l2_mac_hash(mac->mac_addr));
|
||||
|
@ -825,7 +793,7 @@ static void qeth_l2_set_rx_mode(struct net_device *dev)
|
|||
qeth_l2_add_mac(card, ha, 1);
|
||||
|
||||
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)
|
||||
rc = qeth_l2_send_delgroupmac(card,
|
||||
mac->mac_addr);
|
||||
|
@ -837,15 +805,15 @@ static void qeth_l2_set_rx_mode(struct net_device *dev)
|
|||
hash_del(&mac->hnode);
|
||||
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);
|
||||
if (rc) {
|
||||
hash_del(&mac->hnode);
|
||||
kfree(mac);
|
||||
} else
|
||||
mac->disp_flag = QETH_DISP_MAC_DELETE;
|
||||
mac->disp_flag = QETH_DISP_ADDR_DELETE;
|
||||
} else
|
||||
mac->disp_flag = QETH_DISP_MAC_DELETE;
|
||||
mac->disp_flag = QETH_DISP_ADDR_DELETE;
|
||||
}
|
||||
|
||||
spin_unlock_bh(&card->mclock);
|
||||
|
@ -869,6 +837,7 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
int data_offset = -1;
|
||||
int elements_needed = 0;
|
||||
int hd_len = 0;
|
||||
int nr_frags;
|
||||
|
||||
if (card->qdio.do_prio_queueing || (cast_type &&
|
||||
card->info.is_multicast_different))
|
||||
|
@ -892,6 +861,23 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *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)
|
||||
hdr = (struct qeth_hdr *)skb->data;
|
||||
else {
|
||||
|
@ -943,6 +929,14 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
if (!rc) {
|
||||
card->stats.tx_packets++;
|
||||
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)
|
||||
dev_kfree_skb_any(skb);
|
||||
rc = NETDEV_TX_OK;
|
||||
|
@ -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_kill_vid = qeth_l2_vlan_rx_kill_vid,
|
||||
.ndo_tx_timeout = qeth_tx_timeout,
|
||||
.ndo_fix_features = qeth_l2_fix_features,
|
||||
.ndo_set_features = qeth_l2_set_features
|
||||
.ndo_fix_features = qeth_fix_features,
|
||||
.ndo_set_features = qeth_set_features
|
||||
};
|
||||
|
||||
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;
|
||||
card->dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
|
||||
if (card->info.type == QETH_CARD_TYPE_OSD && !card->info.guestlan) {
|
||||
card->dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_RXCSUM;
|
||||
/* Turn on RX offloading per default */
|
||||
card->dev->features |= NETIF_F_RXCSUM;
|
||||
card->dev->hw_features = NETIF_F_SG;
|
||||
card->dev->vlan_features = NETIF_F_SG;
|
||||
/* 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;
|
||||
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);
|
||||
netif_napi_add(card->dev, &card->napi, qeth_l2_poll, QETH_NAPI_WEIGHT);
|
||||
netif_carrier_off(card->dev);
|
||||
|
@ -1135,9 +1142,6 @@ static int qeth_l2_start_ipassists(struct qeth_card *card)
|
|||
/* configure isolation level */
|
||||
if (qeth_set_access_ctrl_online(card, 0))
|
||||
return -ENODEV;
|
||||
if (qeth_is_supported(card, IPA_INBOUND_CHECKSUM))
|
||||
qeth_set_rx_csum(card, 1);
|
||||
qeth_start_ipa_tx_checksum(card);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1206,7 +1210,8 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode)
|
|||
contin:
|
||||
if ((card->info.type == QETH_CARD_TYPE_OSD) ||
|
||||
(card->info.type == QETH_CARD_TYPE_OSX)) {
|
||||
if (qeth_l2_start_ipassists(card))
|
||||
rc = qeth_l2_start_ipassists(card);
|
||||
if (rc)
|
||||
goto out_remove;
|
||||
}
|
||||
|
||||
|
@ -1800,6 +1805,12 @@ static int qeth_bridgeport_makerc(struct qeth_card *card,
|
|||
dev_err(&card->gdev->dev,
|
||||
"The device is not configured as a Bridge Port\n");
|
||||
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 0x0014: /* Another device is Primary */
|
||||
switch (setcmd) {
|
||||
|
|
|
@ -10,16 +10,23 @@
|
|||
#define __QETH_L3_H__
|
||||
|
||||
#include "qeth_core.h"
|
||||
#include <linux/hashtable.h>
|
||||
|
||||
#define QETH_SNIFF_AVAIL 0x0008
|
||||
|
||||
struct qeth_ipaddr {
|
||||
struct list_head entry;
|
||||
struct hlist_node hnode;
|
||||
enum qeth_ip_types type;
|
||||
enum qeth_ipa_setdelip_flags set_flags;
|
||||
enum qeth_ipa_setdelip_flags del_flags;
|
||||
int is_multicast;
|
||||
int users;
|
||||
u8 is_multicast:1;
|
||||
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;
|
||||
unsigned char mac[OSA_ADDR_LEN];
|
||||
union {
|
||||
|
@ -32,7 +39,24 @@ struct qeth_ipaddr {
|
|||
unsigned int pfxlen;
|
||||
} a6;
|
||||
} 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 list_head entry;
|
||||
|
@ -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);
|
||||
int qeth_l3_add_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__ */
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include <linux/slab.h>
|
||||
#include <asm/ebcdic.h>
|
||||
#include <linux/hashtable.h>
|
||||
#include "qeth_l3.h"
|
||||
|
||||
#define QETH_DEVICE_ATTR(_id, _name, _mode, _show, _store) \
|
||||
|
@ -285,19 +286,19 @@ static ssize_t qeth_l3_dev_hsuid_store(struct device *dev,
|
|||
if (card->options.hsuid[0]) {
|
||||
/* delete old ip address */
|
||||
addr = qeth_l3_get_addr_buffer(QETH_PROT_IPV6);
|
||||
if (addr != NULL) {
|
||||
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
|
||||
if (!addr)
|
||||
return -ENOMEM;
|
||||
if (!qeth_l3_delete_ip(card, addr))
|
||||
kfree(addr);
|
||||
qeth_l3_set_ip_addr_list(card);
|
||||
|
||||
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;
|
||||
|
||||
qeth_l3_delete_ip(card, addr);
|
||||
kfree(addr);
|
||||
}
|
||||
|
||||
if (strlen(tmp) == 0) {
|
||||
|
@ -328,9 +329,8 @@ static ssize_t qeth_l3_dev_hsuid_store(struct device *dev,
|
|||
addr->type = QETH_IP_TYPE_NORMAL;
|
||||
} else
|
||||
return -ENOMEM;
|
||||
if (!qeth_l3_add_ip(card, addr))
|
||||
kfree(addr);
|
||||
qeth_l3_set_ip_addr_list(card);
|
||||
qeth_l3_add_ip(card, addr);
|
||||
kfree(addr);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
@ -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 qeth_card *card = dev_get_drvdata(dev);
|
||||
struct qeth_ipaddr *tmpipa, *t;
|
||||
int rc = 0;
|
||||
struct qeth_ipaddr *addr;
|
||||
int i, rc = 0;
|
||||
|
||||
if (!card)
|
||||
return -EINVAL;
|
||||
|
@ -384,21 +384,20 @@ static ssize_t qeth_l3_dev_ipato_enable_store(struct device *dev,
|
|||
card->ipato.enabled = (card->ipato.enabled)? 0 : 1;
|
||||
} else if (sysfs_streq(buf, "1")) {
|
||||
card->ipato.enabled = 1;
|
||||
list_for_each_entry_safe(tmpipa, t, card->ip_tbd_list, entry) {
|
||||
if ((tmpipa->type == QETH_IP_TYPE_NORMAL) &&
|
||||
qeth_l3_is_addr_covered_by_ipato(card, tmpipa))
|
||||
tmpipa->set_flags |=
|
||||
hash_for_each(card->ip_htable, i, addr, hnode) {
|
||||
if ((addr->type == QETH_IP_TYPE_NORMAL) &&
|
||||
qeth_l3_is_addr_covered_by_ipato(card, addr))
|
||||
addr->set_flags |=
|
||||
QETH_IPA_SETIP_TAKEOVER_FLAG;
|
||||
}
|
||||
|
||||
}
|
||||
} else if (sysfs_streq(buf, "0")) {
|
||||
card->ipato.enabled = 0;
|
||||
list_for_each_entry_safe(tmpipa, t, card->ip_tbd_list, entry) {
|
||||
if (tmpipa->set_flags &
|
||||
QETH_IPA_SETIP_TAKEOVER_FLAG)
|
||||
tmpipa->set_flags &=
|
||||
~QETH_IPA_SETIP_TAKEOVER_FLAG;
|
||||
}
|
||||
hash_for_each(card->ip_htable, i, addr, hnode) {
|
||||
if (addr->set_flags &
|
||||
QETH_IPA_SETIP_TAKEOVER_FLAG)
|
||||
addr->set_flags &=
|
||||
~QETH_IPA_SETIP_TAKEOVER_FLAG;
|
||||
}
|
||||
} else
|
||||
rc = -EINVAL;
|
||||
out:
|
||||
|
@ -452,7 +451,6 @@ static ssize_t qeth_l3_dev_ipato_add_show(char *buf, struct qeth_card *card,
|
|||
enum qeth_prot_versions proto)
|
||||
{
|
||||
struct qeth_ipato_entry *ipatoe;
|
||||
unsigned long flags;
|
||||
char addr_str[40];
|
||||
int entry_len; /* length of 1 entry string, differs between v4 and v6 */
|
||||
int i = 0;
|
||||
|
@ -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;
|
||||
/* add strlen for "/<mask>\n" */
|
||||
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) {
|
||||
if (ipatoe->proto != proto)
|
||||
continue;
|
||||
|
@ -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,
|
||||
"%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");
|
||||
|
||||
return i;
|
||||
|
@ -689,15 +687,15 @@ static ssize_t qeth_l3_dev_vipa_add_show(char *buf, struct qeth_card *card,
|
|||
enum qeth_prot_versions proto)
|
||||
{
|
||||
struct qeth_ipaddr *ipaddr;
|
||||
struct hlist_node *tmp;
|
||||
char addr_str[40];
|
||||
int entry_len; /* length of 1 entry string, differs between v4 and v6 */
|
||||
unsigned long flags;
|
||||
int i = 0;
|
||||
|
||||
entry_len = (proto == QETH_PROT_IPV4)? 12 : 40;
|
||||
entry_len += 2; /* \n + terminator */
|
||||
spin_lock_irqsave(&card->ip_lock, flags);
|
||||
list_for_each_entry(ipaddr, &card->ip_list, entry) {
|
||||
spin_lock_bh(&card->ip_lock);
|
||||
hash_for_each_safe(card->ip_htable, i, tmp, ipaddr, hnode) {
|
||||
if (ipaddr->proto != proto)
|
||||
continue;
|
||||
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,
|
|||
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");
|
||||
|
||||
return i;
|
||||
|
@ -851,15 +849,15 @@ static ssize_t qeth_l3_dev_rxip_add_show(char *buf, struct qeth_card *card,
|
|||
enum qeth_prot_versions proto)
|
||||
{
|
||||
struct qeth_ipaddr *ipaddr;
|
||||
struct hlist_node *tmp;
|
||||
char addr_str[40];
|
||||
int entry_len; /* length of 1 entry string, differs between v4 and v6 */
|
||||
unsigned long flags;
|
||||
int i = 0;
|
||||
|
||||
entry_len = (proto == QETH_PROT_IPV4)? 12 : 40;
|
||||
entry_len += 2; /* \n + terminator */
|
||||
spin_lock_irqsave(&card->ip_lock, flags);
|
||||
list_for_each_entry(ipaddr, &card->ip_list, entry) {
|
||||
spin_lock_bh(&card->ip_lock);
|
||||
hash_for_each_safe(card->ip_htable, i, tmp, ipaddr, hnode) {
|
||||
if (ipaddr->proto != proto)
|
||||
continue;
|
||||
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,
|
|||
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");
|
||||
|
||||
return i;
|
||||
|
|
Loading…
Reference in New Issue