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

Merge branch 's390-next'

Julian Wiedmann says:

====================
s390/qeth: updates 2019-11-14

please apply the following qeth patches to net-next.
Along with the usual cleanups, this
(1) reduces collateral packet loss in the RX path when dealing with
    bad packets and/or allocation errors, and
(2) simplifies how the L3 driver deals with mcast IP addresses.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 24df31f8 0b81c6c6
...@@ -368,6 +368,7 @@ enum qeth_header_ids { ...@@ -368,6 +368,7 @@ enum qeth_header_ids {
QETH_HEADER_TYPE_L3_TSO = 0x03, QETH_HEADER_TYPE_L3_TSO = 0x03,
QETH_HEADER_TYPE_OSN = 0x04, QETH_HEADER_TYPE_OSN = 0x04,
QETH_HEADER_TYPE_L2_TSO = 0x06, QETH_HEADER_TYPE_L2_TSO = 0x06,
QETH_HEADER_MASK_INVAL = 0x80,
}; };
/* flags for qeth_hdr.ext_flags */ /* flags for qeth_hdr.ext_flags */
#define QETH_HDR_EXT_VLAN_FRAME 0x01 #define QETH_HDR_EXT_VLAN_FRAME 0x01
...@@ -477,12 +478,16 @@ struct qeth_card_stats { ...@@ -477,12 +478,16 @@ struct qeth_card_stats {
u64 rx_sg_frags; u64 rx_sg_frags;
u64 rx_sg_alloc_page; u64 rx_sg_alloc_page;
u64 rx_dropped_nomem;
u64 rx_dropped_notsupp;
/* rtnl_link_stats64 */ /* rtnl_link_stats64 */
u64 rx_packets; u64 rx_packets;
u64 rx_bytes; u64 rx_bytes;
u64 rx_errors;
u64 rx_dropped;
u64 rx_multicast; u64 rx_multicast;
u64 rx_length_errors;
u64 rx_frame_errors;
u64 rx_fifo_errors;
}; };
struct qeth_out_q_stats { struct qeth_out_q_stats {
...@@ -819,7 +824,6 @@ struct qeth_card { ...@@ -819,7 +824,6 @@ struct qeth_card {
struct workqueue_struct *event_wq; struct workqueue_struct *event_wq;
struct workqueue_struct *cmd_wq; struct workqueue_struct *cmd_wq;
wait_queue_head_t wait_q; wait_queue_head_t wait_q;
unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
DECLARE_HASHTABLE(mac_htable, 4); DECLARE_HASHTABLE(mac_htable, 4);
DECLARE_HASHTABLE(ip_htable, 4); DECLARE_HASHTABLE(ip_htable, 4);
struct mutex ip_lock; struct mutex ip_lock;
......
...@@ -1956,6 +1956,7 @@ static void qeth_idx_setup_activate_cmd(struct qeth_card *card, ...@@ -1956,6 +1956,7 @@ static void qeth_idx_setup_activate_cmd(struct qeth_card *card,
ccw_device_get_id(CARD_DDEV(card), &dev_id); ccw_device_get_id(CARD_DDEV(card), &dev_id);
iob->finalize = qeth_idx_finalize_cmd; iob->finalize = qeth_idx_finalize_cmd;
port |= QETH_IDX_ACT_INVAL_FRAME;
memcpy(QETH_IDX_ACT_PNO(iob->data), &port, 1); memcpy(QETH_IDX_ACT_PNO(iob->data), &port, 1);
memcpy(QETH_IDX_ACT_ISSUER_RM_TOKEN(iob->data), memcpy(QETH_IDX_ACT_ISSUER_RM_TOKEN(iob->data),
&card->token.issuer_rm_w, QETH_MPC_TOKEN_LENGTH); &card->token.issuer_rm_w, QETH_MPC_TOKEN_LENGTH);
...@@ -3093,7 +3094,7 @@ static int qeth_check_qdio_errors(struct qeth_card *card, ...@@ -3093,7 +3094,7 @@ static int qeth_check_qdio_errors(struct qeth_card *card,
buf->element[14].sflags); buf->element[14].sflags);
QETH_CARD_TEXT_(card, 2, " qerr=%X", qdio_error); QETH_CARD_TEXT_(card, 2, " qerr=%X", qdio_error);
if ((buf->element[15].sflags) == 0x12) { if ((buf->element[15].sflags) == 0x12) {
QETH_CARD_STAT_INC(card, rx_dropped); QETH_CARD_STAT_INC(card, rx_fifo_errors);
return 0; return 0;
} else } else
return 1; return 1;
...@@ -4346,7 +4347,9 @@ static int qeth_mdio_read(struct net_device *dev, int phy_id, int regnum) ...@@ -4346,7 +4347,9 @@ static int qeth_mdio_read(struct net_device *dev, int phy_id, int regnum)
case MII_NWAYTEST: /* N-way auto-neg test register */ case MII_NWAYTEST: /* N-way auto-neg test register */
break; break;
case MII_RERRCOUNTER: /* rx error counter */ case MII_RERRCOUNTER: /* rx error counter */
rc = card->stats.rx_errors; rc = card->stats.rx_length_errors +
card->stats.rx_frame_errors +
card->stats.rx_fifo_errors;
break; break;
case MII_SREVISION: /* silicon revision */ case MII_SREVISION: /* silicon revision */
break; break;
...@@ -4852,7 +4855,6 @@ static void qeth_core_free_card(struct qeth_card *card) ...@@ -4852,7 +4855,6 @@ static void qeth_core_free_card(struct qeth_card *card)
qeth_clean_channel(&card->data); qeth_clean_channel(&card->data);
qeth_put_cmd(card->read_cmd); qeth_put_cmd(card->read_cmd);
destroy_workqueue(card->event_wq); destroy_workqueue(card->event_wq);
qeth_free_qdio_queues(card);
unregister_service_level(&card->qeth_service_level); unregister_service_level(&card->qeth_service_level);
dev_set_drvdata(&card->gdev->dev, NULL); dev_set_drvdata(&card->gdev->dev, NULL);
kfree(card); kfree(card);
...@@ -5062,13 +5064,14 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card, ...@@ -5062,13 +5064,14 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card,
struct qdio_buffer_element *element = *__element; struct qdio_buffer_element *element = *__element;
struct qdio_buffer *buffer = qethbuffer->buffer; struct qdio_buffer *buffer = qethbuffer->buffer;
int offset = *__offset; int offset = *__offset;
bool use_rx_sg = false;
unsigned int headroom;
struct sk_buff *skb; struct sk_buff *skb;
int skb_len = 0; int skb_len = 0;
void *data_ptr; void *data_ptr;
int data_len; int data_len;
int headroom = 0;
int use_rx_sg = 0;
next_packet:
/* qeth_hdr must not cross element boundaries */ /* qeth_hdr must not cross element boundaries */
while (element->length < offset + sizeof(struct qeth_hdr)) { while (element->length < offset + sizeof(struct qeth_hdr)) {
if (qeth_is_last_sbale(element)) if (qeth_is_last_sbale(element))
...@@ -5082,27 +5085,45 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card, ...@@ -5082,27 +5085,45 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card,
switch ((*hdr)->hdr.l2.id) { switch ((*hdr)->hdr.l2.id) {
case QETH_HEADER_TYPE_LAYER2: case QETH_HEADER_TYPE_LAYER2:
skb_len = (*hdr)->hdr.l2.pkt_length; skb_len = (*hdr)->hdr.l2.pkt_length;
headroom = 0;
break; break;
case QETH_HEADER_TYPE_LAYER3: case QETH_HEADER_TYPE_LAYER3:
skb_len = (*hdr)->hdr.l3.length; skb_len = (*hdr)->hdr.l3.length;
if (!IS_LAYER3(card)) {
QETH_CARD_STAT_INC(card, rx_dropped_notsupp);
skb = NULL;
goto walk_packet;
}
headroom = ETH_HLEN; headroom = ETH_HLEN;
break; break;
case QETH_HEADER_TYPE_OSN: case QETH_HEADER_TYPE_OSN:
skb_len = (*hdr)->hdr.osn.pdu_length; skb_len = (*hdr)->hdr.osn.pdu_length;
if (!IS_OSN(card)) {
QETH_CARD_STAT_INC(card, rx_dropped_notsupp);
skb = NULL;
goto walk_packet;
}
headroom = sizeof(struct qeth_hdr); headroom = sizeof(struct qeth_hdr);
break; break;
default: default:
break; if ((*hdr)->hdr.l2.id & QETH_HEADER_MASK_INVAL)
QETH_CARD_STAT_INC(card, rx_frame_errors);
else
QETH_CARD_STAT_INC(card, rx_dropped_notsupp);
/* Can't determine packet length, drop the whole buffer. */
return NULL;
} }
if (!skb_len) if (!skb_len)
return NULL; return NULL;
if (((skb_len >= card->options.rx_sg_cb) && use_rx_sg = (card->options.cq == QETH_CQ_ENABLED) ||
!IS_OSN(card) && ((skb_len >= card->options.rx_sg_cb) &&
(!atomic_read(&card->force_alloc_skb))) || !atomic_read(&card->force_alloc_skb) &&
(card->options.cq == QETH_CQ_ENABLED)) !IS_OSN(card));
use_rx_sg = 1;
if (use_rx_sg && qethbuffer->rx_skb) { if (use_rx_sg && qethbuffer->rx_skb) {
/* QETH_CQ_ENABLED only: */ /* QETH_CQ_ENABLED only: */
...@@ -5113,15 +5134,18 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card, ...@@ -5113,15 +5134,18 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card,
skb = napi_alloc_skb(&card->napi, linear + headroom); skb = napi_alloc_skb(&card->napi, linear + headroom);
} }
if (!skb) if (!skb)
goto no_mem; QETH_CARD_STAT_INC(card, rx_dropped_nomem);
if (headroom) else if (headroom)
skb_reserve(skb, headroom); skb_reserve(skb, headroom);
walk_packet:
data_ptr = element->addr + offset; data_ptr = element->addr + offset;
while (skb_len) { while (skb_len) {
data_len = min(skb_len, (int)(element->length - offset)); data_len = min(skb_len, (int)(element->length - offset));
if (data_len) {
if (skb && data_len) {
if (use_rx_sg) if (use_rx_sg)
qeth_create_skb_frag(element, skb, offset, qeth_create_skb_frag(element, skb, offset,
data_len); data_len);
...@@ -5133,8 +5157,11 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card, ...@@ -5133,8 +5157,11 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card,
if (qeth_is_last_sbale(element)) { if (qeth_is_last_sbale(element)) {
QETH_CARD_TEXT(card, 4, "unexeob"); QETH_CARD_TEXT(card, 4, "unexeob");
QETH_CARD_HEX(card, 2, buffer, sizeof(void *)); QETH_CARD_HEX(card, 2, buffer, sizeof(void *));
dev_kfree_skb_any(skb); if (skb) {
QETH_CARD_STAT_INC(card, rx_errors); dev_kfree_skb_any(skb);
QETH_CARD_STAT_INC(card,
rx_length_errors);
}
return NULL; return NULL;
} }
element++; element++;
...@@ -5144,6 +5171,11 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card, ...@@ -5144,6 +5171,11 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card,
offset += data_len; offset += data_len;
} }
} }
/* This packet was skipped, go get another one: */
if (!skb)
goto next_packet;
*__element = element; *__element = element;
*__offset = offset; *__offset = offset;
if (use_rx_sg) { if (use_rx_sg) {
...@@ -5152,12 +5184,6 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card, ...@@ -5152,12 +5184,6 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card,
skb_shinfo(skb)->nr_frags); skb_shinfo(skb)->nr_frags);
} }
return skb; return skb;
no_mem:
if (net_ratelimit()) {
QETH_CARD_TEXT(card, 2, "noskbmem");
}
QETH_CARD_STAT_INC(card, rx_dropped);
return NULL;
} }
EXPORT_SYMBOL_GPL(qeth_core_get_next_skb); EXPORT_SYMBOL_GPL(qeth_core_get_next_skb);
...@@ -5741,6 +5767,8 @@ static void qeth_core_remove_device(struct ccwgroup_device *gdev) ...@@ -5741,6 +5767,8 @@ static void qeth_core_remove_device(struct ccwgroup_device *gdev)
qeth_core_free_discipline(card); qeth_core_free_discipline(card);
} }
qeth_free_qdio_queues(card);
free_netdev(card->dev); free_netdev(card->dev);
qeth_core_free_card(card); qeth_core_free_card(card);
put_device(&gdev->dev); put_device(&gdev->dev);
...@@ -6236,9 +6264,15 @@ void qeth_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) ...@@ -6236,9 +6264,15 @@ void qeth_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
stats->rx_packets = card->stats.rx_packets; stats->rx_packets = card->stats.rx_packets;
stats->rx_bytes = card->stats.rx_bytes; stats->rx_bytes = card->stats.rx_bytes;
stats->rx_errors = card->stats.rx_errors; stats->rx_errors = card->stats.rx_length_errors +
stats->rx_dropped = card->stats.rx_dropped; card->stats.rx_frame_errors +
card->stats.rx_fifo_errors;
stats->rx_dropped = card->stats.rx_dropped_nomem +
card->stats.rx_dropped_notsupp;
stats->multicast = card->stats.rx_multicast; stats->multicast = card->stats.rx_multicast;
stats->rx_length_errors = card->stats.rx_length_errors;
stats->rx_frame_errors = card->stats.rx_frame_errors;
stats->rx_fifo_errors = card->stats.rx_fifo_errors;
for (i = 0; i < card->qdio.no_out_queues; i++) { for (i = 0; i < card->qdio.no_out_queues; i++) {
queue = card->qdio.out_qs[i]; queue = card->qdio.out_qs[i];
......
...@@ -900,6 +900,7 @@ extern unsigned char IDX_ACTIVATE_WRITE[]; ...@@ -900,6 +900,7 @@ extern unsigned char IDX_ACTIVATE_WRITE[];
#define IDX_ACTIVATE_SIZE 0x22 #define IDX_ACTIVATE_SIZE 0x22
#define QETH_IDX_ACT_PNO(buffer) (buffer+0x0b) #define QETH_IDX_ACT_PNO(buffer) (buffer+0x0b)
#define QETH_IDX_ACT_ISSUER_RM_TOKEN(buffer) (buffer + 0x0c) #define QETH_IDX_ACT_ISSUER_RM_TOKEN(buffer) (buffer + 0x0c)
#define QETH_IDX_ACT_INVAL_FRAME 0x40
#define QETH_IDX_NO_PORTNAME_REQUIRED(buffer) ((buffer)[0x0b] & 0x80) #define QETH_IDX_NO_PORTNAME_REQUIRED(buffer) ((buffer)[0x0b] & 0x80)
#define QETH_IDX_ACT_FUNC_LEVEL(buffer) (buffer + 0x10) #define QETH_IDX_ACT_FUNC_LEVEL(buffer) (buffer + 0x10)
#define QETH_IDX_ACT_DATASET_NAME(buffer) (buffer + 0x16) #define QETH_IDX_ACT_DATASET_NAME(buffer) (buffer + 0x16)
......
...@@ -20,8 +20,6 @@ static ssize_t qeth_dev_state_show(struct device *dev, ...@@ -20,8 +20,6 @@ static ssize_t qeth_dev_state_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct qeth_card *card = dev_get_drvdata(dev); struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
switch (card->state) { switch (card->state) {
case CARD_STATE_DOWN: case CARD_STATE_DOWN:
...@@ -45,8 +43,6 @@ static ssize_t qeth_dev_chpid_show(struct device *dev, ...@@ -45,8 +43,6 @@ static ssize_t qeth_dev_chpid_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct qeth_card *card = dev_get_drvdata(dev); struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
return sprintf(buf, "%02X\n", card->info.chpid); return sprintf(buf, "%02X\n", card->info.chpid);
} }
...@@ -57,8 +53,7 @@ static ssize_t qeth_dev_if_name_show(struct device *dev, ...@@ -57,8 +53,7 @@ static ssize_t qeth_dev_if_name_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct qeth_card *card = dev_get_drvdata(dev); struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
return sprintf(buf, "%s\n", QETH_CARD_IFNAME(card)); return sprintf(buf, "%s\n", QETH_CARD_IFNAME(card));
} }
...@@ -68,8 +63,6 @@ static ssize_t qeth_dev_card_type_show(struct device *dev, ...@@ -68,8 +63,6 @@ static ssize_t qeth_dev_card_type_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct qeth_card *card = dev_get_drvdata(dev); struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
return sprintf(buf, "%s\n", qeth_get_cardname_short(card)); return sprintf(buf, "%s\n", qeth_get_cardname_short(card));
} }
...@@ -94,8 +87,6 @@ static ssize_t qeth_dev_inbuf_size_show(struct device *dev, ...@@ -94,8 +87,6 @@ static ssize_t qeth_dev_inbuf_size_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct qeth_card *card = dev_get_drvdata(dev); struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
return sprintf(buf, "%s\n", qeth_get_bufsize_str(card)); return sprintf(buf, "%s\n", qeth_get_bufsize_str(card));
} }
...@@ -106,8 +97,6 @@ static ssize_t qeth_dev_portno_show(struct device *dev, ...@@ -106,8 +97,6 @@ static ssize_t qeth_dev_portno_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct qeth_card *card = dev_get_drvdata(dev); struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
return sprintf(buf, "%i\n", card->dev->dev_port); return sprintf(buf, "%i\n", card->dev->dev_port);
} }
...@@ -120,9 +109,6 @@ static ssize_t qeth_dev_portno_store(struct device *dev, ...@@ -120,9 +109,6 @@ static ssize_t qeth_dev_portno_store(struct device *dev,
unsigned int portno, limit; unsigned int portno, limit;
int rc = 0; int rc = 0;
if (!card)
return -EINVAL;
mutex_lock(&card->conf_mutex); mutex_lock(&card->conf_mutex);
if (card->state != CARD_STATE_DOWN) { if (card->state != CARD_STATE_DOWN) {
rc = -EPERM; rc = -EPERM;
...@@ -171,9 +157,6 @@ static ssize_t qeth_dev_prioqing_show(struct device *dev, ...@@ -171,9 +157,6 @@ static ssize_t qeth_dev_prioqing_show(struct device *dev,
{ {
struct qeth_card *card = dev_get_drvdata(dev); struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
switch (card->qdio.do_prio_queueing) { switch (card->qdio.do_prio_queueing) {
case QETH_PRIO_Q_ING_PREC: case QETH_PRIO_Q_ING_PREC:
return sprintf(buf, "%s\n", "by precedence"); return sprintf(buf, "%s\n", "by precedence");
...@@ -195,9 +178,6 @@ static ssize_t qeth_dev_prioqing_store(struct device *dev, ...@@ -195,9 +178,6 @@ static ssize_t qeth_dev_prioqing_store(struct device *dev,
struct qeth_card *card = dev_get_drvdata(dev); struct qeth_card *card = dev_get_drvdata(dev);
int rc = 0; int rc = 0;
if (!card)
return -EINVAL;
if (IS_IQD(card)) if (IS_IQD(card))
return -EOPNOTSUPP; return -EOPNOTSUPP;
...@@ -262,9 +242,6 @@ static ssize_t qeth_dev_bufcnt_show(struct device *dev, ...@@ -262,9 +242,6 @@ static ssize_t qeth_dev_bufcnt_show(struct device *dev,
{ {
struct qeth_card *card = dev_get_drvdata(dev); struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
return sprintf(buf, "%i\n", card->qdio.in_buf_pool.buf_count); return sprintf(buf, "%i\n", card->qdio.in_buf_pool.buf_count);
} }
...@@ -276,9 +253,6 @@ static ssize_t qeth_dev_bufcnt_store(struct device *dev, ...@@ -276,9 +253,6 @@ static ssize_t qeth_dev_bufcnt_store(struct device *dev,
int cnt, old_cnt; int cnt, old_cnt;
int rc = 0; int rc = 0;
if (!card)
return -EINVAL;
mutex_lock(&card->conf_mutex); mutex_lock(&card->conf_mutex);
if (card->state != CARD_STATE_DOWN) { if (card->state != CARD_STATE_DOWN) {
rc = -EPERM; rc = -EPERM;
...@@ -307,9 +281,6 @@ static ssize_t qeth_dev_recover_store(struct device *dev, ...@@ -307,9 +281,6 @@ static ssize_t qeth_dev_recover_store(struct device *dev,
char *tmp; char *tmp;
int i; int i;
if (!card)
return -EINVAL;
if (!qeth_card_hw_is_reachable(card)) if (!qeth_card_hw_is_reachable(card))
return -EPERM; return -EPERM;
...@@ -325,11 +296,6 @@ static DEVICE_ATTR(recover, 0200, NULL, qeth_dev_recover_store); ...@@ -325,11 +296,6 @@ static DEVICE_ATTR(recover, 0200, NULL, qeth_dev_recover_store);
static ssize_t qeth_dev_performance_stats_show(struct device *dev, static ssize_t qeth_dev_performance_stats_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
return sprintf(buf, "1\n"); return sprintf(buf, "1\n");
} }
...@@ -342,9 +308,6 @@ static ssize_t qeth_dev_performance_stats_store(struct device *dev, ...@@ -342,9 +308,6 @@ static ssize_t qeth_dev_performance_stats_store(struct device *dev,
bool reset; bool reset;
int rc; int rc;
if (!card)
return -EINVAL;
rc = kstrtobool(buf, &reset); rc = kstrtobool(buf, &reset);
if (rc) if (rc)
return rc; return rc;
...@@ -370,9 +333,6 @@ static ssize_t qeth_dev_layer2_show(struct device *dev, ...@@ -370,9 +333,6 @@ static ssize_t qeth_dev_layer2_show(struct device *dev,
{ {
struct qeth_card *card = dev_get_drvdata(dev); struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
return sprintf(buf, "%i\n", card->options.layer); return sprintf(buf, "%i\n", card->options.layer);
} }
...@@ -385,9 +345,6 @@ static ssize_t qeth_dev_layer2_store(struct device *dev, ...@@ -385,9 +345,6 @@ static ssize_t qeth_dev_layer2_store(struct device *dev,
int i, rc = 0; int i, rc = 0;
enum qeth_discipline_id newdis; enum qeth_discipline_id newdis;
if (!card)
return -EINVAL;
mutex_lock(&card->discipline_mutex); mutex_lock(&card->discipline_mutex);
if (card->state != CARD_STATE_DOWN) { if (card->state != CARD_STATE_DOWN) {
rc = -EPERM; rc = -EPERM;
...@@ -453,9 +410,6 @@ static ssize_t qeth_dev_isolation_show(struct device *dev, ...@@ -453,9 +410,6 @@ static ssize_t qeth_dev_isolation_show(struct device *dev,
{ {
struct qeth_card *card = dev_get_drvdata(dev); struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
switch (card->options.isolation) { switch (card->options.isolation) {
case ISOLATION_MODE_NONE: case ISOLATION_MODE_NONE:
return snprintf(buf, 6, "%s\n", ATTR_QETH_ISOLATION_NONE); return snprintf(buf, 6, "%s\n", ATTR_QETH_ISOLATION_NONE);
...@@ -475,9 +429,6 @@ static ssize_t qeth_dev_isolation_store(struct device *dev, ...@@ -475,9 +429,6 @@ static ssize_t qeth_dev_isolation_store(struct device *dev,
enum qeth_ipa_isolation_modes isolation; enum qeth_ipa_isolation_modes isolation;
int rc = 0; int rc = 0;
if (!card)
return -EINVAL;
mutex_lock(&card->conf_mutex); mutex_lock(&card->conf_mutex);
if (!IS_OSD(card) && !IS_OSX(card)) { if (!IS_OSD(card) && !IS_OSX(card)) {
rc = -EOPNOTSUPP; rc = -EOPNOTSUPP;
...@@ -522,9 +473,6 @@ static ssize_t qeth_dev_switch_attrs_show(struct device *dev, ...@@ -522,9 +473,6 @@ static ssize_t qeth_dev_switch_attrs_show(struct device *dev,
struct qeth_switch_info sw_info; struct qeth_switch_info sw_info;
int rc = 0; int rc = 0;
if (!card)
return -EINVAL;
if (!qeth_card_hw_is_reachable(card)) if (!qeth_card_hw_is_reachable(card))
return sprintf(buf, "n/a\n"); return sprintf(buf, "n/a\n");
...@@ -555,8 +503,6 @@ static ssize_t qeth_hw_trap_show(struct device *dev, ...@@ -555,8 +503,6 @@ static ssize_t qeth_hw_trap_show(struct device *dev,
{ {
struct qeth_card *card = dev_get_drvdata(dev); struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
if (card->info.hwtrap) if (card->info.hwtrap)
return snprintf(buf, 5, "arm\n"); return snprintf(buf, 5, "arm\n");
else else
...@@ -570,9 +516,6 @@ static ssize_t qeth_hw_trap_store(struct device *dev, ...@@ -570,9 +516,6 @@ static ssize_t qeth_hw_trap_store(struct device *dev,
int rc = 0; int rc = 0;
int state = 0; int state = 0;
if (!card)
return -EINVAL;
mutex_lock(&card->conf_mutex); mutex_lock(&card->conf_mutex);
if (qeth_card_hw_is_reachable(card)) if (qeth_card_hw_is_reachable(card))
state = 1; state = 1;
...@@ -607,24 +550,12 @@ static ssize_t qeth_hw_trap_store(struct device *dev, ...@@ -607,24 +550,12 @@ static ssize_t qeth_hw_trap_store(struct device *dev,
static DEVICE_ATTR(hw_trap, 0644, qeth_hw_trap_show, static DEVICE_ATTR(hw_trap, 0644, qeth_hw_trap_show,
qeth_hw_trap_store); qeth_hw_trap_store);
static ssize_t qeth_dev_blkt_show(char *buf, struct qeth_card *card, int value)
{
if (!card)
return -EINVAL;
return sprintf(buf, "%i\n", value);
}
static ssize_t qeth_dev_blkt_store(struct qeth_card *card, static ssize_t qeth_dev_blkt_store(struct qeth_card *card,
const char *buf, size_t count, int *value, int max_value) const char *buf, size_t count, int *value, int max_value)
{ {
char *tmp; char *tmp;
int i, rc = 0; int i, rc = 0;
if (!card)
return -EINVAL;
mutex_lock(&card->conf_mutex); mutex_lock(&card->conf_mutex);
if (card->state != CARD_STATE_DOWN) { if (card->state != CARD_STATE_DOWN) {
rc = -EPERM; rc = -EPERM;
...@@ -645,7 +576,7 @@ static ssize_t qeth_dev_blkt_total_show(struct device *dev, ...@@ -645,7 +576,7 @@ static ssize_t qeth_dev_blkt_total_show(struct device *dev,
{ {
struct qeth_card *card = dev_get_drvdata(dev); struct qeth_card *card = dev_get_drvdata(dev);
return qeth_dev_blkt_show(buf, card, card->info.blkt.time_total); return sprintf(buf, "%i\n", card->info.blkt.time_total);
} }
static ssize_t qeth_dev_blkt_total_store(struct device *dev, static ssize_t qeth_dev_blkt_total_store(struct device *dev,
...@@ -657,8 +588,6 @@ static ssize_t qeth_dev_blkt_total_store(struct device *dev, ...@@ -657,8 +588,6 @@ static ssize_t qeth_dev_blkt_total_store(struct device *dev,
&card->info.blkt.time_total, 5000); &card->info.blkt.time_total, 5000);
} }
static DEVICE_ATTR(total, 0644, qeth_dev_blkt_total_show, static DEVICE_ATTR(total, 0644, qeth_dev_blkt_total_show,
qeth_dev_blkt_total_store); qeth_dev_blkt_total_store);
...@@ -667,7 +596,7 @@ static ssize_t qeth_dev_blkt_inter_show(struct device *dev, ...@@ -667,7 +596,7 @@ static ssize_t qeth_dev_blkt_inter_show(struct device *dev,
{ {
struct qeth_card *card = dev_get_drvdata(dev); struct qeth_card *card = dev_get_drvdata(dev);
return qeth_dev_blkt_show(buf, card, card->info.blkt.inter_packet); return sprintf(buf, "%i\n", card->info.blkt.inter_packet);
} }
static ssize_t qeth_dev_blkt_inter_store(struct device *dev, static ssize_t qeth_dev_blkt_inter_store(struct device *dev,
...@@ -687,8 +616,7 @@ static ssize_t qeth_dev_blkt_inter_jumbo_show(struct device *dev, ...@@ -687,8 +616,7 @@ static ssize_t qeth_dev_blkt_inter_jumbo_show(struct device *dev,
{ {
struct qeth_card *card = dev_get_drvdata(dev); struct qeth_card *card = dev_get_drvdata(dev);
return qeth_dev_blkt_show(buf, card, return sprintf(buf, "%i\n", card->info.blkt.inter_packet_jumbo);
card->info.blkt.inter_packet_jumbo);
} }
static ssize_t qeth_dev_blkt_inter_jumbo_store(struct device *dev, static ssize_t qeth_dev_blkt_inter_jumbo_store(struct device *dev,
......
...@@ -49,6 +49,8 @@ static const struct qeth_stats card_stats[] = { ...@@ -49,6 +49,8 @@ static const struct qeth_stats card_stats[] = {
QETH_CARD_STAT("rx0 SG skbs", rx_sg_skbs), QETH_CARD_STAT("rx0 SG skbs", rx_sg_skbs),
QETH_CARD_STAT("rx0 SG page frags", rx_sg_frags), QETH_CARD_STAT("rx0 SG page frags", rx_sg_frags),
QETH_CARD_STAT("rx0 SG page allocs", rx_sg_alloc_page), QETH_CARD_STAT("rx0 SG page allocs", rx_sg_alloc_page),
QETH_CARD_STAT("rx0 dropped, no memory", rx_dropped_nomem),
QETH_CARD_STAT("rx0 dropped, bad format", rx_dropped_notsupp),
}; };
#define TXQ_STATS_LEN ARRAY_SIZE(txq_stats) #define TXQ_STATS_LEN ARRAY_SIZE(txq_stats)
......
...@@ -315,29 +315,19 @@ static int qeth_l2_process_inbound_buffer(struct qeth_card *card, ...@@ -315,29 +315,19 @@ static int qeth_l2_process_inbound_buffer(struct qeth_card *card,
*done = 1; *done = 1;
break; break;
} }
switch (hdr->hdr.l2.id) {
case QETH_HEADER_TYPE_LAYER2: if (hdr->hdr.l2.id == QETH_HEADER_TYPE_LAYER2) {
skb->protocol = eth_type_trans(skb, skb->dev); skb->protocol = eth_type_trans(skb, skb->dev);
qeth_rx_csum(card, skb, hdr->hdr.l2.flags[1]); qeth_rx_csum(card, skb, hdr->hdr.l2.flags[1]);
len = skb->len; len = skb->len;
napi_gro_receive(&card->napi, skb); napi_gro_receive(&card->napi, skb);
break; } else {
case QETH_HEADER_TYPE_OSN: skb_push(skb, sizeof(*hdr));
if (IS_OSN(card)) { skb_copy_to_linear_data(skb, hdr, sizeof(*hdr));
skb_push(skb, sizeof(struct qeth_hdr)); len = skb->len;
skb_copy_to_linear_data(skb, hdr, card->osn_info.data_cb(skb);
sizeof(struct qeth_hdr));
len = skb->len;
card->osn_info.data_cb(skb);
break;
}
/* Else, fall through */
default:
dev_kfree_skb_any(skb);
QETH_CARD_TEXT(card, 3, "inbunkno");
QETH_DBF_HEX(CTRL, 3, hdr, sizeof(*hdr));
continue;
} }
work_done++; work_done++;
budget--; budget--;
QETH_CARD_STAT_INC(card, rx_packets); QETH_CARD_STAT_INC(card, rx_packets);
......
...@@ -18,9 +18,6 @@ static ssize_t qeth_bridge_port_role_state_show(struct device *dev, ...@@ -18,9 +18,6 @@ static ssize_t qeth_bridge_port_role_state_show(struct device *dev,
int rc = 0; int rc = 0;
char *word; char *word;
if (!card)
return -EINVAL;
if (qeth_l2_vnicc_is_in_use(card)) if (qeth_l2_vnicc_is_in_use(card))
return sprintf(buf, "n/a (VNIC characteristics)\n"); return sprintf(buf, "n/a (VNIC characteristics)\n");
...@@ -79,8 +76,6 @@ static ssize_t qeth_bridge_port_role_store(struct device *dev, ...@@ -79,8 +76,6 @@ static ssize_t qeth_bridge_port_role_store(struct device *dev,
int rc = 0; int rc = 0;
enum qeth_sbp_roles role; enum qeth_sbp_roles role;
if (!card)
return -EINVAL;
if (sysfs_streq(buf, "primary")) if (sysfs_streq(buf, "primary"))
role = QETH_SBP_ROLE_PRIMARY; role = QETH_SBP_ROLE_PRIMARY;
else if (sysfs_streq(buf, "secondary")) else if (sysfs_streq(buf, "secondary"))
...@@ -132,9 +127,6 @@ static ssize_t qeth_bridgeport_hostnotification_show(struct device *dev, ...@@ -132,9 +127,6 @@ static ssize_t qeth_bridgeport_hostnotification_show(struct device *dev,
struct qeth_card *card = dev_get_drvdata(dev); struct qeth_card *card = dev_get_drvdata(dev);
int enabled; int enabled;
if (!card)
return -EINVAL;
if (qeth_l2_vnicc_is_in_use(card)) if (qeth_l2_vnicc_is_in_use(card))
return sprintf(buf, "n/a (VNIC characteristics)\n"); return sprintf(buf, "n/a (VNIC characteristics)\n");
...@@ -150,9 +142,6 @@ static ssize_t qeth_bridgeport_hostnotification_store(struct device *dev, ...@@ -150,9 +142,6 @@ static ssize_t qeth_bridgeport_hostnotification_store(struct device *dev,
bool enable; bool enable;
int rc; int rc;
if (!card)
return -EINVAL;
rc = kstrtobool(buf, &enable); rc = kstrtobool(buf, &enable);
if (rc) if (rc)
return rc; return rc;
...@@ -183,9 +172,6 @@ static ssize_t qeth_bridgeport_reflect_show(struct device *dev, ...@@ -183,9 +172,6 @@ static ssize_t qeth_bridgeport_reflect_show(struct device *dev,
struct qeth_card *card = dev_get_drvdata(dev); struct qeth_card *card = dev_get_drvdata(dev);
char *state; char *state;
if (!card)
return -EINVAL;
if (qeth_l2_vnicc_is_in_use(card)) if (qeth_l2_vnicc_is_in_use(card))
return sprintf(buf, "n/a (VNIC characteristics)\n"); return sprintf(buf, "n/a (VNIC characteristics)\n");
...@@ -207,9 +193,6 @@ static ssize_t qeth_bridgeport_reflect_store(struct device *dev, ...@@ -207,9 +193,6 @@ static ssize_t qeth_bridgeport_reflect_store(struct device *dev,
int enable, primary; int enable, primary;
int rc = 0; int rc = 0;
if (!card)
return -EINVAL;
if (sysfs_streq(buf, "none")) { if (sysfs_streq(buf, "none")) {
enable = 0; enable = 0;
primary = 0; primary = 0;
...@@ -315,9 +298,6 @@ static ssize_t qeth_vnicc_timeout_show(struct device *dev, ...@@ -315,9 +298,6 @@ static ssize_t qeth_vnicc_timeout_show(struct device *dev,
u32 timeout; u32 timeout;
int rc; int rc;
if (!card)
return -EINVAL;
rc = qeth_l2_vnicc_get_timeout(card, &timeout); rc = qeth_l2_vnicc_get_timeout(card, &timeout);
if (rc == -EBUSY) if (rc == -EBUSY)
return sprintf(buf, "n/a (BridgePort)\n"); return sprintf(buf, "n/a (BridgePort)\n");
...@@ -335,9 +315,6 @@ static ssize_t qeth_vnicc_timeout_store(struct device *dev, ...@@ -335,9 +315,6 @@ static ssize_t qeth_vnicc_timeout_store(struct device *dev,
u32 timeout; u32 timeout;
int rc; int rc;
if (!card)
return -EINVAL;
rc = kstrtou32(buf, 10, &timeout); rc = kstrtou32(buf, 10, &timeout);
if (rc) if (rc)
return rc; return rc;
...@@ -357,9 +334,6 @@ static ssize_t qeth_vnicc_char_show(struct device *dev, ...@@ -357,9 +334,6 @@ static ssize_t qeth_vnicc_char_show(struct device *dev,
u32 vnicc; u32 vnicc;
int rc; int rc;
if (!card)
return -EINVAL;
vnicc = qeth_l2_vnicc_sysfs_attr_to_char(attr->attr.name); vnicc = qeth_l2_vnicc_sysfs_attr_to_char(attr->attr.name);
rc = qeth_l2_vnicc_get_state(card, vnicc, &state); rc = qeth_l2_vnicc_get_state(card, vnicc, &state);
...@@ -380,9 +354,6 @@ static ssize_t qeth_vnicc_char_store(struct device *dev, ...@@ -380,9 +354,6 @@ static ssize_t qeth_vnicc_char_store(struct device *dev,
u32 vnicc; u32 vnicc;
int rc; int rc;
if (!card)
return -EINVAL;
if (kstrtobool(buf, &state)) if (kstrtobool(buf, &state))
return -EINVAL; return -EINVAL;
......
...@@ -54,6 +54,7 @@ static inline void qeth_l3_init_ipaddr(struct qeth_ipaddr *addr, ...@@ -54,6 +54,7 @@ static inline void qeth_l3_init_ipaddr(struct qeth_ipaddr *addr,
addr->type = type; addr->type = type;
addr->proto = proto; addr->proto = proto;
addr->disp_flag = QETH_DISP_ADDR_DO_NOTHING; addr->disp_flag = QETH_DISP_ADDR_DO_NOTHING;
addr->ref_counter = 1;
} }
static inline bool qeth_l3_addr_match_ip(struct qeth_ipaddr *a1, static inline bool qeth_l3_addr_match_ip(struct qeth_ipaddr *a1,
......
...@@ -39,7 +39,6 @@ ...@@ -39,7 +39,6 @@
static int qeth_l3_set_offline(struct ccwgroup_device *); static int qeth_l3_set_offline(struct ccwgroup_device *);
static void qeth_l3_set_rx_mode(struct net_device *dev);
static int qeth_l3_register_addr_entry(struct qeth_card *, static int qeth_l3_register_addr_entry(struct qeth_card *,
struct qeth_ipaddr *); struct qeth_ipaddr *);
static int qeth_l3_deregister_addr_entry(struct qeth_card *, static int qeth_l3_deregister_addr_entry(struct qeth_card *,
...@@ -64,15 +63,6 @@ void qeth_l3_ipaddr_to_string(enum qeth_prot_versions proto, const __u8 *addr, ...@@ -64,15 +63,6 @@ void qeth_l3_ipaddr_to_string(enum qeth_prot_versions proto, const __u8 *addr,
qeth_l3_ipaddr6_to_string(addr, buf); qeth_l3_ipaddr6_to_string(addr, buf);
} }
static struct qeth_ipaddr *qeth_l3_get_addr_buffer(enum qeth_prot_versions prot)
{
struct qeth_ipaddr *addr = kmalloc(sizeof(*addr), GFP_ATOMIC);
if (addr)
qeth_l3_init_ipaddr(addr, QETH_IP_TYPE_NORMAL, prot);
return addr;
}
static struct qeth_ipaddr *qeth_l3_find_addr_by_ip(struct qeth_card *card, static struct qeth_ipaddr *qeth_l3_find_addr_by_ip(struct qeth_card *card,
struct qeth_ipaddr *query) struct qeth_ipaddr *query)
{ {
...@@ -217,13 +207,10 @@ static int qeth_l3_add_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr) ...@@ -217,13 +207,10 @@ static int qeth_l3_add_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr)
"Registering IP address %s failed\n", buf); "Registering IP address %s failed\n", buf);
return -EADDRINUSE; return -EADDRINUSE;
} else { } else {
addr = qeth_l3_get_addr_buffer(tmp_addr->proto); addr = kmemdup(tmp_addr, sizeof(*tmp_addr), GFP_KERNEL);
if (!addr) if (!addr)
return -ENOMEM; return -ENOMEM;
memcpy(addr, tmp_addr, sizeof(struct qeth_ipaddr));
addr->ref_counter = 1;
if (qeth_l3_is_addr_covered_by_ipato(card, addr)) { if (qeth_l3_is_addr_covered_by_ipato(card, addr)) {
QETH_CARD_TEXT(card, 2, "tkovaddr"); QETH_CARD_TEXT(card, 2, "tkovaddr");
addr->ipato = 1; addr->ipato = 1;
...@@ -1114,171 +1101,83 @@ qeth_diags_trace(struct qeth_card *card, enum qeth_diags_trace_cmds diags_cmd) ...@@ -1114,171 +1101,83 @@ qeth_diags_trace(struct qeth_card *card, enum qeth_diags_trace_cmds diags_cmd)
return qeth_send_ipa_cmd(card, iob, qeth_diags_trace_cb, NULL); return qeth_send_ipa_cmd(card, iob, qeth_diags_trace_cb, NULL);
} }
static void static int qeth_l3_add_mcast_rtnl(struct net_device *dev, int vid, void *arg)
qeth_l3_add_mc_to_hash(struct qeth_card *card, struct in_device *in4_dev)
{ {
struct qeth_card *card = arg;
struct inet6_dev *in6_dev;
struct in_device *in4_dev;
struct qeth_ipaddr *ipm;
struct qeth_ipaddr tmp;
struct ip_mc_list *im4; struct ip_mc_list *im4;
struct qeth_ipaddr *tmp, *ipm; struct ifmcaddr6 *im6;
QETH_CARD_TEXT(card, 4, "addmc"); QETH_CARD_TEXT(card, 4, "addmc");
tmp = qeth_l3_get_addr_buffer(QETH_PROT_IPV4); if (!dev || !(dev->flags & IFF_UP))
if (!tmp) goto out;
return;
for (im4 = rcu_dereference(in4_dev->mc_list); im4 != NULL; in4_dev = __in_dev_get_rtnl(dev);
im4 = rcu_dereference(im4->next_rcu)) { if (!in4_dev)
tmp->u.a4.addr = im4->multiaddr; goto walk_ipv6;
tmp->is_multicast = 1;
ipm = qeth_l3_find_addr_by_ip(card, tmp); qeth_l3_init_ipaddr(&tmp, QETH_IP_TYPE_NORMAL, QETH_PROT_IPV4);
tmp.disp_flag = QETH_DISP_ADDR_ADD;
tmp.is_multicast = 1;
for (im4 = rtnl_dereference(in4_dev->mc_list); im4 != NULL;
im4 = rtnl_dereference(im4->next_rcu)) {
tmp.u.a4.addr = im4->multiaddr;
ipm = qeth_l3_find_addr_by_ip(card, &tmp);
if (ipm) { if (ipm) {
/* for mcast, by-IP match means full match */ /* for mcast, by-IP match means full match */
ipm->disp_flag = QETH_DISP_ADDR_DO_NOTHING; ipm->disp_flag = QETH_DISP_ADDR_DO_NOTHING;
} else { continue;
ipm = qeth_l3_get_addr_buffer(QETH_PROT_IPV4);
if (!ipm)
continue;
ipm->u.a4.addr = im4->multiaddr;
ipm->is_multicast = 1;
ipm->disp_flag = QETH_DISP_ADDR_ADD;
hash_add(card->ip_mc_htable,
&ipm->hnode, qeth_l3_ipaddr_hash(ipm));
} }
}
kfree(tmp);
}
/* called with rcu_read_lock */
static void qeth_l3_add_vlan_mc(struct qeth_card *card)
{
struct in_device *in_dev;
u16 vid;
QETH_CARD_TEXT(card, 4, "addmcvl");
if (!qeth_is_supported(card, IPA_FULL_VLAN)) ipm = kmemdup(&tmp, sizeof(tmp), GFP_KERNEL);
return; if (!ipm)
for_each_set_bit(vid, card->active_vlans, VLAN_N_VID) {
struct net_device *netdev;
netdev = __vlan_find_dev_deep_rcu(card->dev, htons(ETH_P_8021Q),
vid);
if (netdev == NULL ||
!(netdev->flags & IFF_UP))
continue;
in_dev = __in_dev_get_rcu(netdev);
if (!in_dev)
continue; continue;
qeth_l3_add_mc_to_hash(card, in_dev);
}
}
static void qeth_l3_add_multicast_ipv4(struct qeth_card *card)
{
struct in_device *in4_dev;
QETH_CARD_TEXT(card, 4, "chkmcv4");
rcu_read_lock(); hash_add(card->ip_mc_htable, &ipm->hnode,
in4_dev = __in_dev_get_rcu(card->dev); qeth_l3_ipaddr_hash(ipm));
if (in4_dev == NULL) }
goto unlock;
qeth_l3_add_mc_to_hash(card, in4_dev);
qeth_l3_add_vlan_mc(card);
unlock:
rcu_read_unlock();
}
static void qeth_l3_add_mc6_to_hash(struct qeth_card *card, walk_ipv6:
struct inet6_dev *in6_dev) if (!qeth_is_supported(card, IPA_IPV6))
{ goto out;
struct qeth_ipaddr *ipm;
struct ifmcaddr6 *im6;
struct qeth_ipaddr *tmp;
QETH_CARD_TEXT(card, 4, "addmc6"); in6_dev = __in6_dev_get(dev);
if (!in6_dev)
goto out;
tmp = qeth_l3_get_addr_buffer(QETH_PROT_IPV6); qeth_l3_init_ipaddr(&tmp, QETH_IP_TYPE_NORMAL, QETH_PROT_IPV6);
if (!tmp) tmp.disp_flag = QETH_DISP_ADDR_ADD;
return; tmp.is_multicast = 1;
read_lock_bh(&in6_dev->lock);
for (im6 = in6_dev->mc_list; im6 != NULL; im6 = im6->next) { for (im6 = in6_dev->mc_list; im6 != NULL; im6 = im6->next) {
tmp->u.a6.addr = im6->mca_addr; tmp.u.a6.addr = im6->mca_addr;
tmp->is_multicast = 1;
ipm = qeth_l3_find_addr_by_ip(card, tmp); ipm = qeth_l3_find_addr_by_ip(card, &tmp);
if (ipm) { if (ipm) {
/* for mcast, by-IP match means full match */ /* for mcast, by-IP match means full match */
ipm->disp_flag = QETH_DISP_ADDR_DO_NOTHING; ipm->disp_flag = QETH_DISP_ADDR_DO_NOTHING;
continue; continue;
} }
ipm = qeth_l3_get_addr_buffer(QETH_PROT_IPV6); ipm = kmemdup(&tmp, sizeof(tmp), GFP_ATOMIC);
if (!ipm) if (!ipm)
continue; continue;
ipm->u.a6.addr = im6->mca_addr;
ipm->is_multicast = 1;
ipm->disp_flag = QETH_DISP_ADDR_ADD;
hash_add(card->ip_mc_htable, hash_add(card->ip_mc_htable,
&ipm->hnode, qeth_l3_ipaddr_hash(ipm)); &ipm->hnode, qeth_l3_ipaddr_hash(ipm));
} }
kfree(tmp);
}
/* called with rcu_read_lock */
static void qeth_l3_add_vlan_mc6(struct qeth_card *card)
{
struct inet6_dev *in_dev;
u16 vid;
QETH_CARD_TEXT(card, 4, "admc6vl");
if (!qeth_is_supported(card, IPA_FULL_VLAN))
return;
for_each_set_bit(vid, card->active_vlans, VLAN_N_VID) {
struct net_device *netdev;
netdev = __vlan_find_dev_deep_rcu(card->dev, htons(ETH_P_8021Q),
vid);
if (netdev == NULL ||
!(netdev->flags & IFF_UP))
continue;
in_dev = in6_dev_get(netdev);
if (!in_dev)
continue;
read_lock_bh(&in_dev->lock);
qeth_l3_add_mc6_to_hash(card, in_dev);
read_unlock_bh(&in_dev->lock);
in6_dev_put(in_dev);
}
}
static void qeth_l3_add_multicast_ipv6(struct qeth_card *card)
{
struct inet6_dev *in6_dev;
QETH_CARD_TEXT(card, 4, "chkmcv6");
if (!qeth_is_supported(card, IPA_IPV6))
return ;
in6_dev = in6_dev_get(card->dev);
if (!in6_dev)
return;
rcu_read_lock();
read_lock_bh(&in6_dev->lock);
qeth_l3_add_mc6_to_hash(card, in6_dev);
qeth_l3_add_vlan_mc6(card);
read_unlock_bh(&in6_dev->lock); read_unlock_bh(&in6_dev->lock);
rcu_read_unlock();
in6_dev_put(in6_dev); out:
return 0;
} }
static int qeth_l3_vlan_rx_add_vid(struct net_device *dev, static int qeth_l3_vlan_rx_add_vid(struct net_device *dev,
...@@ -1286,7 +1185,7 @@ static int qeth_l3_vlan_rx_add_vid(struct net_device *dev, ...@@ -1286,7 +1185,7 @@ static int qeth_l3_vlan_rx_add_vid(struct net_device *dev,
{ {
struct qeth_card *card = dev->ml_priv; struct qeth_card *card = dev->ml_priv;
set_bit(vid, card->active_vlans); QETH_CARD_TEXT_(card, 4, "aid:%d", vid);
return 0; return 0;
} }
...@@ -1296,9 +1195,6 @@ static int qeth_l3_vlan_rx_kill_vid(struct net_device *dev, ...@@ -1296,9 +1195,6 @@ static int qeth_l3_vlan_rx_kill_vid(struct net_device *dev,
struct qeth_card *card = dev->ml_priv; struct qeth_card *card = dev->ml_priv;
QETH_CARD_TEXT_(card, 4, "kid:%d", vid); QETH_CARD_TEXT_(card, 4, "kid:%d", vid);
clear_bit(vid, card->active_vlans);
qeth_l3_set_rx_mode(dev);
return 0; return 0;
} }
...@@ -1366,7 +1262,6 @@ static int qeth_l3_process_inbound_buffer(struct qeth_card *card, ...@@ -1366,7 +1262,6 @@ static int qeth_l3_process_inbound_buffer(struct qeth_card *card,
int work_done = 0; int work_done = 0;
struct sk_buff *skb; struct sk_buff *skb;
struct qeth_hdr *hdr; struct qeth_hdr *hdr;
unsigned int len;
*done = 0; *done = 0;
WARN_ON_ONCE(!budget); WARN_ON_ONCE(!budget);
...@@ -1378,25 +1273,17 @@ static int qeth_l3_process_inbound_buffer(struct qeth_card *card, ...@@ -1378,25 +1273,17 @@ static int qeth_l3_process_inbound_buffer(struct qeth_card *card,
*done = 1; *done = 1;
break; break;
} }
switch (hdr->hdr.l3.id) {
case QETH_HEADER_TYPE_LAYER3: if (hdr->hdr.l3.id == QETH_HEADER_TYPE_LAYER3)
qeth_l3_rebuild_skb(card, skb, hdr); qeth_l3_rebuild_skb(card, skb, hdr);
/* fall through */
case QETH_HEADER_TYPE_LAYER2: /* for HiperSockets sniffer */ skb->protocol = eth_type_trans(skb, skb->dev);
skb->protocol = eth_type_trans(skb, skb->dev); QETH_CARD_STAT_INC(card, rx_packets);
len = skb->len; QETH_CARD_STAT_ADD(card, rx_bytes, skb->len);
napi_gro_receive(&card->napi, skb);
break; napi_gro_receive(&card->napi, skb);
default:
dev_kfree_skb_any(skb);
QETH_CARD_TEXT(card, 3, "inbunkno");
QETH_DBF_HEX(CTRL, 3, hdr, sizeof(*hdr));
continue;
}
work_done++; work_done++;
budget--; budget--;
QETH_CARD_STAT_INC(card, rx_packets);
QETH_CARD_STAT_ADD(card, rx_bytes, len);
} }
return work_done; return work_done;
} }
...@@ -1462,8 +1349,11 @@ static void qeth_l3_rx_mode_work(struct work_struct *work) ...@@ -1462,8 +1349,11 @@ static void qeth_l3_rx_mode_work(struct work_struct *work)
QETH_CARD_TEXT(card, 3, "setmulti"); QETH_CARD_TEXT(card, 3, "setmulti");
if (!card->options.sniffer) { if (!card->options.sniffer) {
qeth_l3_add_multicast_ipv4(card); rtnl_lock();
qeth_l3_add_multicast_ipv6(card); qeth_l3_add_mcast_rtnl(card->dev, 0, card);
if (qeth_is_supported(card, IPA_FULL_VLAN))
vlan_for_each(card->dev, qeth_l3_add_mcast_rtnl, card);
rtnl_unlock();
hash_for_each_safe(card->ip_mc_htable, i, tmp, addr, hnode) { hash_for_each_safe(card->ip_mc_htable, i, tmp, addr, hnode) {
switch (addr->disp_flag) { switch (addr->disp_flag) {
......
...@@ -60,9 +60,6 @@ static ssize_t qeth_l3_dev_route4_show(struct device *dev, ...@@ -60,9 +60,6 @@ static ssize_t qeth_l3_dev_route4_show(struct device *dev,
{ {
struct qeth_card *card = dev_get_drvdata(dev); struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
return qeth_l3_dev_route_show(card, &card->options.route4, buf); return qeth_l3_dev_route_show(card, &card->options.route4, buf);
} }
...@@ -109,9 +106,6 @@ static ssize_t qeth_l3_dev_route4_store(struct device *dev, ...@@ -109,9 +106,6 @@ static ssize_t qeth_l3_dev_route4_store(struct device *dev,
{ {
struct qeth_card *card = dev_get_drvdata(dev); struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
return qeth_l3_dev_route_store(card, &card->options.route4, return qeth_l3_dev_route_store(card, &card->options.route4,
QETH_PROT_IPV4, buf, count); QETH_PROT_IPV4, buf, count);
} }
...@@ -124,9 +118,6 @@ static ssize_t qeth_l3_dev_route6_show(struct device *dev, ...@@ -124,9 +118,6 @@ static ssize_t qeth_l3_dev_route6_show(struct device *dev,
{ {
struct qeth_card *card = dev_get_drvdata(dev); struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
return qeth_l3_dev_route_show(card, &card->options.route6, buf); return qeth_l3_dev_route_show(card, &card->options.route6, buf);
} }
...@@ -135,9 +126,6 @@ static ssize_t qeth_l3_dev_route6_store(struct device *dev, ...@@ -135,9 +126,6 @@ static ssize_t qeth_l3_dev_route6_store(struct device *dev,
{ {
struct qeth_card *card = dev_get_drvdata(dev); struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
return qeth_l3_dev_route_store(card, &card->options.route6, return qeth_l3_dev_route_store(card, &card->options.route6,
QETH_PROT_IPV6, buf, count); QETH_PROT_IPV6, buf, count);
} }
...@@ -150,9 +138,6 @@ static ssize_t qeth_l3_dev_fake_broadcast_show(struct device *dev, ...@@ -150,9 +138,6 @@ static ssize_t qeth_l3_dev_fake_broadcast_show(struct device *dev,
{ {
struct qeth_card *card = dev_get_drvdata(dev); struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
return sprintf(buf, "%i\n", card->options.fake_broadcast? 1:0); return sprintf(buf, "%i\n", card->options.fake_broadcast? 1:0);
} }
...@@ -163,9 +148,6 @@ static ssize_t qeth_l3_dev_fake_broadcast_store(struct device *dev, ...@@ -163,9 +148,6 @@ static ssize_t qeth_l3_dev_fake_broadcast_store(struct device *dev,
char *tmp; char *tmp;
int i, rc = 0; int i, rc = 0;
if (!card)
return -EINVAL;
mutex_lock(&card->conf_mutex); mutex_lock(&card->conf_mutex);
if (card->state != CARD_STATE_DOWN) { if (card->state != CARD_STATE_DOWN) {
rc = -EPERM; rc = -EPERM;
...@@ -190,9 +172,6 @@ static ssize_t qeth_l3_dev_sniffer_show(struct device *dev, ...@@ -190,9 +172,6 @@ static ssize_t qeth_l3_dev_sniffer_show(struct device *dev,
{ {
struct qeth_card *card = dev_get_drvdata(dev); struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
return sprintf(buf, "%i\n", card->options.sniffer ? 1 : 0); return sprintf(buf, "%i\n", card->options.sniffer ? 1 : 0);
} }
...@@ -203,9 +182,6 @@ static ssize_t qeth_l3_dev_sniffer_store(struct device *dev, ...@@ -203,9 +182,6 @@ static ssize_t qeth_l3_dev_sniffer_store(struct device *dev,
int rc = 0; int rc = 0;
unsigned long i; unsigned long i;
if (!card)
return -EINVAL;
if (!IS_IQD(card)) if (!IS_IQD(card))
return -EPERM; return -EPERM;
if (card->options.cq == QETH_CQ_ENABLED) if (card->options.cq == QETH_CQ_ENABLED)
...@@ -248,16 +224,12 @@ static ssize_t qeth_l3_dev_sniffer_store(struct device *dev, ...@@ -248,16 +224,12 @@ static ssize_t qeth_l3_dev_sniffer_store(struct device *dev,
static DEVICE_ATTR(sniffer, 0644, qeth_l3_dev_sniffer_show, static DEVICE_ATTR(sniffer, 0644, qeth_l3_dev_sniffer_show,
qeth_l3_dev_sniffer_store); qeth_l3_dev_sniffer_store);
static ssize_t qeth_l3_dev_hsuid_show(struct device *dev, static ssize_t qeth_l3_dev_hsuid_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct qeth_card *card = dev_get_drvdata(dev); struct qeth_card *card = dev_get_drvdata(dev);
char tmp_hsuid[9]; char tmp_hsuid[9];
if (!card)
return -EINVAL;
if (!IS_IQD(card)) if (!IS_IQD(card))
return -EPERM; return -EPERM;
...@@ -273,9 +245,6 @@ static ssize_t qeth_l3_dev_hsuid_store(struct device *dev, ...@@ -273,9 +245,6 @@ static ssize_t qeth_l3_dev_hsuid_store(struct device *dev,
char *tmp; char *tmp;
int rc; int rc;
if (!card)
return -EINVAL;
if (!IS_IQD(card)) if (!IS_IQD(card))
return -EPERM; return -EPERM;
if (card->state != CARD_STATE_DOWN) if (card->state != CARD_STATE_DOWN)
...@@ -336,9 +305,6 @@ static ssize_t qeth_l3_dev_ipato_enable_show(struct device *dev, ...@@ -336,9 +305,6 @@ static ssize_t qeth_l3_dev_ipato_enable_show(struct device *dev,
{ {
struct qeth_card *card = dev_get_drvdata(dev); struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
return sprintf(buf, "%i\n", card->ipato.enabled? 1:0); return sprintf(buf, "%i\n", card->ipato.enabled? 1:0);
} }
...@@ -349,9 +315,6 @@ static ssize_t qeth_l3_dev_ipato_enable_store(struct device *dev, ...@@ -349,9 +315,6 @@ static ssize_t qeth_l3_dev_ipato_enable_store(struct device *dev,
bool enable; bool enable;
int rc = 0; int rc = 0;
if (!card)
return -EINVAL;
mutex_lock(&card->conf_mutex); mutex_lock(&card->conf_mutex);
if (card->state != CARD_STATE_DOWN) { if (card->state != CARD_STATE_DOWN) {
rc = -EPERM; rc = -EPERM;
...@@ -385,9 +348,6 @@ static ssize_t qeth_l3_dev_ipato_invert4_show(struct device *dev, ...@@ -385,9 +348,6 @@ static ssize_t qeth_l3_dev_ipato_invert4_show(struct device *dev,
{ {
struct qeth_card *card = dev_get_drvdata(dev); struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
return sprintf(buf, "%i\n", card->ipato.invert4? 1:0); return sprintf(buf, "%i\n", card->ipato.invert4? 1:0);
} }
...@@ -399,9 +359,6 @@ static ssize_t qeth_l3_dev_ipato_invert4_store(struct device *dev, ...@@ -399,9 +359,6 @@ static ssize_t qeth_l3_dev_ipato_invert4_store(struct device *dev,
bool invert; bool invert;
int rc = 0; int rc = 0;
if (!card)
return -EINVAL;
mutex_lock(&card->conf_mutex); mutex_lock(&card->conf_mutex);
if (sysfs_streq(buf, "toggle")) { if (sysfs_streq(buf, "toggle")) {
invert = !card->ipato.invert4; invert = !card->ipato.invert4;
...@@ -460,9 +417,6 @@ static ssize_t qeth_l3_dev_ipato_add4_show(struct device *dev, ...@@ -460,9 +417,6 @@ static ssize_t qeth_l3_dev_ipato_add4_show(struct device *dev,
{ {
struct qeth_card *card = dev_get_drvdata(dev); struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
return qeth_l3_dev_ipato_add_show(buf, card, QETH_PROT_IPV4); return qeth_l3_dev_ipato_add_show(buf, card, QETH_PROT_IPV4);
} }
...@@ -528,9 +482,6 @@ static ssize_t qeth_l3_dev_ipato_add4_store(struct device *dev, ...@@ -528,9 +482,6 @@ static ssize_t qeth_l3_dev_ipato_add4_store(struct device *dev,
{ {
struct qeth_card *card = dev_get_drvdata(dev); struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
return qeth_l3_dev_ipato_add_store(buf, count, card, QETH_PROT_IPV4); return qeth_l3_dev_ipato_add_store(buf, count, card, QETH_PROT_IPV4);
} }
...@@ -558,9 +509,6 @@ static ssize_t qeth_l3_dev_ipato_del4_store(struct device *dev, ...@@ -558,9 +509,6 @@ static ssize_t qeth_l3_dev_ipato_del4_store(struct device *dev,
{ {
struct qeth_card *card = dev_get_drvdata(dev); struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
return qeth_l3_dev_ipato_del_store(buf, count, card, QETH_PROT_IPV4); return qeth_l3_dev_ipato_del_store(buf, count, card, QETH_PROT_IPV4);
} }
...@@ -572,9 +520,6 @@ static ssize_t qeth_l3_dev_ipato_invert6_show(struct device *dev, ...@@ -572,9 +520,6 @@ static ssize_t qeth_l3_dev_ipato_invert6_show(struct device *dev,
{ {
struct qeth_card *card = dev_get_drvdata(dev); struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
return sprintf(buf, "%i\n", card->ipato.invert6? 1:0); return sprintf(buf, "%i\n", card->ipato.invert6? 1:0);
} }
...@@ -585,9 +530,6 @@ static ssize_t qeth_l3_dev_ipato_invert6_store(struct device *dev, ...@@ -585,9 +530,6 @@ static ssize_t qeth_l3_dev_ipato_invert6_store(struct device *dev,
bool invert; bool invert;
int rc = 0; int rc = 0;
if (!card)
return -EINVAL;
mutex_lock(&card->conf_mutex); mutex_lock(&card->conf_mutex);
if (sysfs_streq(buf, "toggle")) { if (sysfs_streq(buf, "toggle")) {
invert = !card->ipato.invert6; invert = !card->ipato.invert6;
...@@ -617,9 +559,6 @@ static ssize_t qeth_l3_dev_ipato_add6_show(struct device *dev, ...@@ -617,9 +559,6 @@ static ssize_t qeth_l3_dev_ipato_add6_show(struct device *dev,
{ {
struct qeth_card *card = dev_get_drvdata(dev); struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
return qeth_l3_dev_ipato_add_show(buf, card, QETH_PROT_IPV6); return qeth_l3_dev_ipato_add_show(buf, card, QETH_PROT_IPV6);
} }
...@@ -628,9 +567,6 @@ static ssize_t qeth_l3_dev_ipato_add6_store(struct device *dev, ...@@ -628,9 +567,6 @@ static ssize_t qeth_l3_dev_ipato_add6_store(struct device *dev,
{ {
struct qeth_card *card = dev_get_drvdata(dev); struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
return qeth_l3_dev_ipato_add_store(buf, count, card, QETH_PROT_IPV6); return qeth_l3_dev_ipato_add_store(buf, count, card, QETH_PROT_IPV6);
} }
...@@ -643,9 +579,6 @@ static ssize_t qeth_l3_dev_ipato_del6_store(struct device *dev, ...@@ -643,9 +579,6 @@ static ssize_t qeth_l3_dev_ipato_del6_store(struct device *dev,
{ {
struct qeth_card *card = dev_get_drvdata(dev); struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
return qeth_l3_dev_ipato_del_store(buf, count, card, QETH_PROT_IPV6); return qeth_l3_dev_ipato_del_store(buf, count, card, QETH_PROT_IPV6);
} }
...@@ -679,9 +612,6 @@ static ssize_t qeth_l3_dev_ip_add_show(struct device *dev, char *buf, ...@@ -679,9 +612,6 @@ static ssize_t qeth_l3_dev_ip_add_show(struct device *dev, char *buf,
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; int i;
if (!card)
return -EINVAL;
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 */
mutex_lock(&card->ip_lock); mutex_lock(&card->ip_lock);
...@@ -741,9 +671,6 @@ static ssize_t qeth_l3_dev_vipa_add4_store(struct device *dev, ...@@ -741,9 +671,6 @@ static ssize_t qeth_l3_dev_vipa_add4_store(struct device *dev,
{ {
struct qeth_card *card = dev_get_drvdata(dev); struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
return qeth_l3_dev_vipa_add_store(buf, count, card, QETH_PROT_IPV4); return qeth_l3_dev_vipa_add_store(buf, count, card, QETH_PROT_IPV4);
} }
...@@ -771,9 +698,6 @@ static ssize_t qeth_l3_dev_vipa_del4_store(struct device *dev, ...@@ -771,9 +698,6 @@ static ssize_t qeth_l3_dev_vipa_del4_store(struct device *dev,
{ {
struct qeth_card *card = dev_get_drvdata(dev); struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
return qeth_l3_dev_vipa_del_store(buf, count, card, QETH_PROT_IPV4); return qeth_l3_dev_vipa_del_store(buf, count, card, QETH_PROT_IPV4);
} }
...@@ -793,9 +717,6 @@ static ssize_t qeth_l3_dev_vipa_add6_store(struct device *dev, ...@@ -793,9 +717,6 @@ static ssize_t qeth_l3_dev_vipa_add6_store(struct device *dev,
{ {
struct qeth_card *card = dev_get_drvdata(dev); struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
return qeth_l3_dev_vipa_add_store(buf, count, card, QETH_PROT_IPV6); return qeth_l3_dev_vipa_add_store(buf, count, card, QETH_PROT_IPV6);
} }
...@@ -808,9 +729,6 @@ static ssize_t qeth_l3_dev_vipa_del6_store(struct device *dev, ...@@ -808,9 +729,6 @@ static ssize_t qeth_l3_dev_vipa_del6_store(struct device *dev,
{ {
struct qeth_card *card = dev_get_drvdata(dev); struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
return qeth_l3_dev_vipa_del_store(buf, count, card, QETH_PROT_IPV6); return qeth_l3_dev_vipa_del_store(buf, count, card, QETH_PROT_IPV6);
} }
...@@ -884,9 +802,6 @@ static ssize_t qeth_l3_dev_rxip_add4_store(struct device *dev, ...@@ -884,9 +802,6 @@ static ssize_t qeth_l3_dev_rxip_add4_store(struct device *dev,
{ {
struct qeth_card *card = dev_get_drvdata(dev); struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
return qeth_l3_dev_rxip_add_store(buf, count, card, QETH_PROT_IPV4); return qeth_l3_dev_rxip_add_store(buf, count, card, QETH_PROT_IPV4);
} }
...@@ -914,9 +829,6 @@ static ssize_t qeth_l3_dev_rxip_del4_store(struct device *dev, ...@@ -914,9 +829,6 @@ static ssize_t qeth_l3_dev_rxip_del4_store(struct device *dev,
{ {
struct qeth_card *card = dev_get_drvdata(dev); struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
return qeth_l3_dev_rxip_del_store(buf, count, card, QETH_PROT_IPV4); return qeth_l3_dev_rxip_del_store(buf, count, card, QETH_PROT_IPV4);
} }
...@@ -936,9 +848,6 @@ static ssize_t qeth_l3_dev_rxip_add6_store(struct device *dev, ...@@ -936,9 +848,6 @@ static ssize_t qeth_l3_dev_rxip_add6_store(struct device *dev,
{ {
struct qeth_card *card = dev_get_drvdata(dev); struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
return qeth_l3_dev_rxip_add_store(buf, count, card, QETH_PROT_IPV6); return qeth_l3_dev_rxip_add_store(buf, count, card, QETH_PROT_IPV6);
} }
...@@ -951,9 +860,6 @@ static ssize_t qeth_l3_dev_rxip_del6_store(struct device *dev, ...@@ -951,9 +860,6 @@ static ssize_t qeth_l3_dev_rxip_del6_store(struct device *dev,
{ {
struct qeth_card *card = dev_get_drvdata(dev); struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
return qeth_l3_dev_rxip_del_store(buf, count, card, QETH_PROT_IPV6); return qeth_l3_dev_rxip_del_store(buf, count, card, QETH_PROT_IPV6);
} }
......
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