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: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2019-11-14 18:16:51 -08:00
commit a98cdaf73e
10 changed files with 150 additions and 423 deletions

View File

@ -368,6 +368,7 @@ enum qeth_header_ids {
QETH_HEADER_TYPE_L3_TSO = 0x03,
QETH_HEADER_TYPE_OSN = 0x04,
QETH_HEADER_TYPE_L2_TSO = 0x06,
QETH_HEADER_MASK_INVAL = 0x80,
};
/* flags for qeth_hdr.ext_flags */
#define QETH_HDR_EXT_VLAN_FRAME 0x01
@ -477,12 +478,16 @@ struct qeth_card_stats {
u64 rx_sg_frags;
u64 rx_sg_alloc_page;
u64 rx_dropped_nomem;
u64 rx_dropped_notsupp;
/* rtnl_link_stats64 */
u64 rx_packets;
u64 rx_bytes;
u64 rx_errors;
u64 rx_dropped;
u64 rx_multicast;
u64 rx_length_errors;
u64 rx_frame_errors;
u64 rx_fifo_errors;
};
struct qeth_out_q_stats {
@ -819,7 +824,6 @@ struct qeth_card {
struct workqueue_struct *event_wq;
struct workqueue_struct *cmd_wq;
wait_queue_head_t wait_q;
unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
DECLARE_HASHTABLE(mac_htable, 4);
DECLARE_HASHTABLE(ip_htable, 4);
struct mutex ip_lock;

View File

@ -1956,6 +1956,7 @@ static void qeth_idx_setup_activate_cmd(struct qeth_card *card,
ccw_device_get_id(CARD_DDEV(card), &dev_id);
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_ISSUER_RM_TOKEN(iob->data),
&card->token.issuer_rm_w, QETH_MPC_TOKEN_LENGTH);
@ -3093,7 +3094,7 @@ static int qeth_check_qdio_errors(struct qeth_card *card,
buf->element[14].sflags);
QETH_CARD_TEXT_(card, 2, " qerr=%X", qdio_error);
if ((buf->element[15].sflags) == 0x12) {
QETH_CARD_STAT_INC(card, rx_dropped);
QETH_CARD_STAT_INC(card, rx_fifo_errors);
return 0;
} else
return 1;
@ -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 */
break;
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;
case MII_SREVISION: /* silicon revision */
break;
@ -4852,7 +4855,6 @@ static void qeth_core_free_card(struct qeth_card *card)
qeth_clean_channel(&card->data);
qeth_put_cmd(card->read_cmd);
destroy_workqueue(card->event_wq);
qeth_free_qdio_queues(card);
unregister_service_level(&card->qeth_service_level);
dev_set_drvdata(&card->gdev->dev, NULL);
kfree(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 *buffer = qethbuffer->buffer;
int offset = *__offset;
bool use_rx_sg = false;
unsigned int headroom;
struct sk_buff *skb;
int skb_len = 0;
void *data_ptr;
int data_len;
int headroom = 0;
int use_rx_sg = 0;
next_packet:
/* qeth_hdr must not cross element boundaries */
while (element->length < offset + sizeof(struct qeth_hdr)) {
if (qeth_is_last_sbale(element))
@ -5082,27 +5085,45 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card,
switch ((*hdr)->hdr.l2.id) {
case QETH_HEADER_TYPE_LAYER2:
skb_len = (*hdr)->hdr.l2.pkt_length;
headroom = 0;
break;
case QETH_HEADER_TYPE_LAYER3:
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;
break;
case QETH_HEADER_TYPE_OSN:
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);
break;
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)
return NULL;
if (((skb_len >= card->options.rx_sg_cb) &&
!IS_OSN(card) &&
(!atomic_read(&card->force_alloc_skb))) ||
(card->options.cq == QETH_CQ_ENABLED))
use_rx_sg = 1;
use_rx_sg = (card->options.cq == QETH_CQ_ENABLED) ||
((skb_len >= card->options.rx_sg_cb) &&
!atomic_read(&card->force_alloc_skb) &&
!IS_OSN(card));
if (use_rx_sg && qethbuffer->rx_skb) {
/* QETH_CQ_ENABLED only: */
@ -5113,15 +5134,18 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card,
skb = napi_alloc_skb(&card->napi, linear + headroom);
}
if (!skb)
goto no_mem;
if (headroom)
QETH_CARD_STAT_INC(card, rx_dropped_nomem);
else if (headroom)
skb_reserve(skb, headroom);
walk_packet:
data_ptr = element->addr + offset;
while (skb_len) {
data_len = min(skb_len, (int)(element->length - offset));
if (data_len) {
if (skb && data_len) {
if (use_rx_sg)
qeth_create_skb_frag(element, skb, offset,
data_len);
@ -5133,8 +5157,11 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card,
if (qeth_is_last_sbale(element)) {
QETH_CARD_TEXT(card, 4, "unexeob");
QETH_CARD_HEX(card, 2, buffer, sizeof(void *));
dev_kfree_skb_any(skb);
QETH_CARD_STAT_INC(card, rx_errors);
if (skb) {
dev_kfree_skb_any(skb);
QETH_CARD_STAT_INC(card,
rx_length_errors);
}
return NULL;
}
element++;
@ -5144,6 +5171,11 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card,
offset += data_len;
}
}
/* This packet was skipped, go get another one: */
if (!skb)
goto next_packet;
*__element = element;
*__offset = offset;
if (use_rx_sg) {
@ -5152,12 +5184,6 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card,
skb_shinfo(skb)->nr_frags);
}
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);
@ -5741,6 +5767,8 @@ static void qeth_core_remove_device(struct ccwgroup_device *gdev)
qeth_core_free_discipline(card);
}
qeth_free_qdio_queues(card);
free_netdev(card->dev);
qeth_core_free_card(card);
put_device(&gdev->dev);
@ -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_bytes = card->stats.rx_bytes;
stats->rx_errors = card->stats.rx_errors;
stats->rx_dropped = card->stats.rx_dropped;
stats->rx_errors = card->stats.rx_length_errors +
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->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++) {
queue = card->qdio.out_qs[i];

View File

@ -900,6 +900,7 @@ extern unsigned char IDX_ACTIVATE_WRITE[];
#define IDX_ACTIVATE_SIZE 0x22
#define QETH_IDX_ACT_PNO(buffer) (buffer+0x0b)
#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_ACT_FUNC_LEVEL(buffer) (buffer + 0x10)
#define QETH_IDX_ACT_DATASET_NAME(buffer) (buffer + 0x16)

View File

@ -20,8 +20,6 @@ static ssize_t qeth_dev_state_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
switch (card->state) {
case CARD_STATE_DOWN:
@ -45,8 +43,6 @@ static ssize_t qeth_dev_chpid_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
return sprintf(buf, "%02X\n", card->info.chpid);
}
@ -57,8 +53,7 @@ static ssize_t qeth_dev_if_name_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
return sprintf(buf, "%s\n", QETH_CARD_IFNAME(card));
}
@ -68,8 +63,6 @@ static ssize_t qeth_dev_card_type_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
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,
struct device_attribute *attr, char *buf)
{
struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
return sprintf(buf, "%s\n", qeth_get_bufsize_str(card));
}
@ -106,8 +97,6 @@ static ssize_t qeth_dev_portno_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
return sprintf(buf, "%i\n", card->dev->dev_port);
}
@ -120,9 +109,6 @@ static ssize_t qeth_dev_portno_store(struct device *dev,
unsigned int portno, limit;
int rc = 0;
if (!card)
return -EINVAL;
mutex_lock(&card->conf_mutex);
if (card->state != CARD_STATE_DOWN) {
rc = -EPERM;
@ -171,9 +157,6 @@ static ssize_t qeth_dev_prioqing_show(struct device *dev,
{
struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
switch (card->qdio.do_prio_queueing) {
case QETH_PRIO_Q_ING_PREC:
return sprintf(buf, "%s\n", "by precedence");
@ -195,9 +178,6 @@ static ssize_t qeth_dev_prioqing_store(struct device *dev,
struct qeth_card *card = dev_get_drvdata(dev);
int rc = 0;
if (!card)
return -EINVAL;
if (IS_IQD(card))
return -EOPNOTSUPP;
@ -262,9 +242,6 @@ static ssize_t qeth_dev_bufcnt_show(struct device *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);
}
@ -276,9 +253,6 @@ static ssize_t qeth_dev_bufcnt_store(struct device *dev,
int cnt, old_cnt;
int rc = 0;
if (!card)
return -EINVAL;
mutex_lock(&card->conf_mutex);
if (card->state != CARD_STATE_DOWN) {
rc = -EPERM;
@ -307,9 +281,6 @@ static ssize_t qeth_dev_recover_store(struct device *dev,
char *tmp;
int i;
if (!card)
return -EINVAL;
if (!qeth_card_hw_is_reachable(card))
return -EPERM;
@ -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,
struct device_attribute *attr, char *buf)
{
struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
return sprintf(buf, "1\n");
}
@ -342,9 +308,6 @@ static ssize_t qeth_dev_performance_stats_store(struct device *dev,
bool reset;
int rc;
if (!card)
return -EINVAL;
rc = kstrtobool(buf, &reset);
if (rc)
return rc;
@ -370,9 +333,6 @@ static ssize_t qeth_dev_layer2_show(struct device *dev,
{
struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
return sprintf(buf, "%i\n", card->options.layer);
}
@ -385,9 +345,6 @@ static ssize_t qeth_dev_layer2_store(struct device *dev,
int i, rc = 0;
enum qeth_discipline_id newdis;
if (!card)
return -EINVAL;
mutex_lock(&card->discipline_mutex);
if (card->state != CARD_STATE_DOWN) {
rc = -EPERM;
@ -453,9 +410,6 @@ static ssize_t qeth_dev_isolation_show(struct device *dev,
{
struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
switch (card->options.isolation) {
case ISOLATION_MODE_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,
enum qeth_ipa_isolation_modes isolation;
int rc = 0;
if (!card)
return -EINVAL;
mutex_lock(&card->conf_mutex);
if (!IS_OSD(card) && !IS_OSX(card)) {
rc = -EOPNOTSUPP;
@ -522,9 +473,6 @@ static ssize_t qeth_dev_switch_attrs_show(struct device *dev,
struct qeth_switch_info sw_info;
int rc = 0;
if (!card)
return -EINVAL;
if (!qeth_card_hw_is_reachable(card))
return sprintf(buf, "n/a\n");
@ -555,8 +503,6 @@ static ssize_t qeth_hw_trap_show(struct device *dev,
{
struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
if (card->info.hwtrap)
return snprintf(buf, 5, "arm\n");
else
@ -570,9 +516,6 @@ static ssize_t qeth_hw_trap_store(struct device *dev,
int rc = 0;
int state = 0;
if (!card)
return -EINVAL;
mutex_lock(&card->conf_mutex);
if (qeth_card_hw_is_reachable(card))
state = 1;
@ -607,24 +550,12 @@ static ssize_t qeth_hw_trap_store(struct device *dev,
static DEVICE_ATTR(hw_trap, 0644, qeth_hw_trap_show,
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,
const char *buf, size_t count, int *value, int max_value)
{
char *tmp;
int i, rc = 0;
if (!card)
return -EINVAL;
mutex_lock(&card->conf_mutex);
if (card->state != CARD_STATE_DOWN) {
rc = -EPERM;
@ -645,7 +576,7 @@ static ssize_t qeth_dev_blkt_total_show(struct device *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,
@ -657,8 +588,6 @@ static ssize_t qeth_dev_blkt_total_store(struct device *dev,
&card->info.blkt.time_total, 5000);
}
static DEVICE_ATTR(total, 0644, qeth_dev_blkt_total_show,
qeth_dev_blkt_total_store);
@ -667,7 +596,7 @@ static ssize_t qeth_dev_blkt_inter_show(struct device *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,
@ -687,8 +616,7 @@ static ssize_t qeth_dev_blkt_inter_jumbo_show(struct device *dev,
{
struct qeth_card *card = dev_get_drvdata(dev);
return qeth_dev_blkt_show(buf, card,
card->info.blkt.inter_packet_jumbo);
return sprintf(buf, "%i\n", card->info.blkt.inter_packet_jumbo);
}
static ssize_t qeth_dev_blkt_inter_jumbo_store(struct device *dev,

View File

@ -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 page frags", rx_sg_frags),
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)

View File

@ -315,29 +315,19 @@ static int qeth_l2_process_inbound_buffer(struct qeth_card *card,
*done = 1;
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);
qeth_rx_csum(card, skb, hdr->hdr.l2.flags[1]);
len = skb->len;
napi_gro_receive(&card->napi, skb);
break;
case QETH_HEADER_TYPE_OSN:
if (IS_OSN(card)) {
skb_push(skb, sizeof(struct qeth_hdr));
skb_copy_to_linear_data(skb, hdr,
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;
} else {
skb_push(skb, sizeof(*hdr));
skb_copy_to_linear_data(skb, hdr, sizeof(*hdr));
len = skb->len;
card->osn_info.data_cb(skb);
}
work_done++;
budget--;
QETH_CARD_STAT_INC(card, rx_packets);

View File

@ -18,9 +18,6 @@ static ssize_t qeth_bridge_port_role_state_show(struct device *dev,
int rc = 0;
char *word;
if (!card)
return -EINVAL;
if (qeth_l2_vnicc_is_in_use(card))
return sprintf(buf, "n/a (VNIC characteristics)\n");
@ -79,8 +76,6 @@ static ssize_t qeth_bridge_port_role_store(struct device *dev,
int rc = 0;
enum qeth_sbp_roles role;
if (!card)
return -EINVAL;
if (sysfs_streq(buf, "primary"))
role = QETH_SBP_ROLE_PRIMARY;
else if (sysfs_streq(buf, "secondary"))
@ -132,9 +127,6 @@ static ssize_t qeth_bridgeport_hostnotification_show(struct device *dev,
struct qeth_card *card = dev_get_drvdata(dev);
int enabled;
if (!card)
return -EINVAL;
if (qeth_l2_vnicc_is_in_use(card))
return sprintf(buf, "n/a (VNIC characteristics)\n");
@ -150,9 +142,6 @@ static ssize_t qeth_bridgeport_hostnotification_store(struct device *dev,
bool enable;
int rc;
if (!card)
return -EINVAL;
rc = kstrtobool(buf, &enable);
if (rc)
return rc;
@ -183,9 +172,6 @@ static ssize_t qeth_bridgeport_reflect_show(struct device *dev,
struct qeth_card *card = dev_get_drvdata(dev);
char *state;
if (!card)
return -EINVAL;
if (qeth_l2_vnicc_is_in_use(card))
return sprintf(buf, "n/a (VNIC characteristics)\n");
@ -207,9 +193,6 @@ static ssize_t qeth_bridgeport_reflect_store(struct device *dev,
int enable, primary;
int rc = 0;
if (!card)
return -EINVAL;
if (sysfs_streq(buf, "none")) {
enable = 0;
primary = 0;
@ -315,9 +298,6 @@ static ssize_t qeth_vnicc_timeout_show(struct device *dev,
u32 timeout;
int rc;
if (!card)
return -EINVAL;
rc = qeth_l2_vnicc_get_timeout(card, &timeout);
if (rc == -EBUSY)
return sprintf(buf, "n/a (BridgePort)\n");
@ -335,9 +315,6 @@ static ssize_t qeth_vnicc_timeout_store(struct device *dev,
u32 timeout;
int rc;
if (!card)
return -EINVAL;
rc = kstrtou32(buf, 10, &timeout);
if (rc)
return rc;
@ -357,9 +334,6 @@ static ssize_t qeth_vnicc_char_show(struct device *dev,
u32 vnicc;
int rc;
if (!card)
return -EINVAL;
vnicc = qeth_l2_vnicc_sysfs_attr_to_char(attr->attr.name);
rc = qeth_l2_vnicc_get_state(card, vnicc, &state);
@ -380,9 +354,6 @@ static ssize_t qeth_vnicc_char_store(struct device *dev,
u32 vnicc;
int rc;
if (!card)
return -EINVAL;
if (kstrtobool(buf, &state))
return -EINVAL;

View File

@ -54,6 +54,7 @@ static inline void qeth_l3_init_ipaddr(struct qeth_ipaddr *addr,
addr->type = type;
addr->proto = proto;
addr->disp_flag = QETH_DISP_ADDR_DO_NOTHING;
addr->ref_counter = 1;
}
static inline bool qeth_l3_addr_match_ip(struct qeth_ipaddr *a1,

View File

@ -39,7 +39,6 @@
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 *,
struct qeth_ipaddr *);
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,
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,
struct qeth_ipaddr *query)
{
@ -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);
return -EADDRINUSE;
} else {
addr = qeth_l3_get_addr_buffer(tmp_addr->proto);
addr = kmemdup(tmp_addr, sizeof(*tmp_addr), GFP_KERNEL);
if (!addr)
return -ENOMEM;
memcpy(addr, tmp_addr, sizeof(struct qeth_ipaddr));
addr->ref_counter = 1;
if (qeth_l3_is_addr_covered_by_ipato(card, addr)) {
QETH_CARD_TEXT(card, 2, "tkovaddr");
addr->ipato = 1;
@ -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);
}
static void
qeth_l3_add_mc_to_hash(struct qeth_card *card, struct in_device *in4_dev)
static int qeth_l3_add_mcast_rtnl(struct net_device *dev, int vid, void *arg)
{
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 qeth_ipaddr *tmp, *ipm;
struct ifmcaddr6 *im6;
QETH_CARD_TEXT(card, 4, "addmc");
tmp = qeth_l3_get_addr_buffer(QETH_PROT_IPV4);
if (!tmp)
return;
if (!dev || !(dev->flags & IFF_UP))
goto out;
for (im4 = rcu_dereference(in4_dev->mc_list); im4 != NULL;
im4 = rcu_dereference(im4->next_rcu)) {
tmp->u.a4.addr = im4->multiaddr;
tmp->is_multicast = 1;
in4_dev = __in_dev_get_rtnl(dev);
if (!in4_dev)
goto walk_ipv6;
ipm = qeth_l3_find_addr_by_ip(card, tmp);
if (ipm) {
/* for mcast, by-IP match means full match */
ipm->disp_flag = QETH_DISP_ADDR_DO_NOTHING;
} else {
ipm = qeth_l3_get_addr_buffer(QETH_PROT_IPV4);
if (!ipm)
continue;
qeth_l3_init_ipaddr(&tmp, QETH_IP_TYPE_NORMAL, QETH_PROT_IPV4);
tmp.disp_flag = QETH_DISP_ADDR_ADD;
tmp.is_multicast = 1;
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));
}
}
for (im4 = rtnl_dereference(in4_dev->mc_list); im4 != NULL;
im4 = rtnl_dereference(im4->next_rcu)) {
tmp.u.a4.addr = im4->multiaddr;
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))
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 = __in_dev_get_rcu(netdev);
if (!in_dev)
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();
in4_dev = __in_dev_get_rcu(card->dev);
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,
struct inet6_dev *in6_dev)
{
struct qeth_ipaddr *ipm;
struct ifmcaddr6 *im6;
struct qeth_ipaddr *tmp;
QETH_CARD_TEXT(card, 4, "addmc6");
tmp = qeth_l3_get_addr_buffer(QETH_PROT_IPV6);
if (!tmp)
return;
for (im6 = in6_dev->mc_list; im6 != NULL; im6 = im6->next) {
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) {
/* for mcast, by-IP match means full match */
ipm->disp_flag = QETH_DISP_ADDR_DO_NOTHING;
continue;
}
ipm = qeth_l3_get_addr_buffer(QETH_PROT_IPV6);
ipm = kmemdup(&tmp, sizeof(tmp), GFP_KERNEL);
if (!ipm)
continue;
hash_add(card->ip_mc_htable, &ipm->hnode,
qeth_l3_ipaddr_hash(ipm));
}
walk_ipv6:
if (!qeth_is_supported(card, IPA_IPV6))
goto out;
in6_dev = __in6_dev_get(dev);
if (!in6_dev)
goto out;
qeth_l3_init_ipaddr(&tmp, QETH_IP_TYPE_NORMAL, QETH_PROT_IPV6);
tmp.disp_flag = QETH_DISP_ADDR_ADD;
tmp.is_multicast = 1;
read_lock_bh(&in6_dev->lock);
for (im6 = in6_dev->mc_list; im6 != NULL; im6 = im6->next) {
tmp.u.a6.addr = im6->mca_addr;
ipm = qeth_l3_find_addr_by_ip(card, &tmp);
if (ipm) {
/* for mcast, by-IP match means full match */
ipm->disp_flag = QETH_DISP_ADDR_DO_NOTHING;
continue;
}
ipm = kmemdup(&tmp, sizeof(tmp), GFP_ATOMIC);
if (!ipm)
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,
&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);
rcu_read_unlock();
in6_dev_put(in6_dev);
out:
return 0;
}
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;
set_bit(vid, card->active_vlans);
QETH_CARD_TEXT_(card, 4, "aid:%d", vid);
return 0;
}
@ -1296,9 +1195,6 @@ static int qeth_l3_vlan_rx_kill_vid(struct net_device *dev,
struct qeth_card *card = dev->ml_priv;
QETH_CARD_TEXT_(card, 4, "kid:%d", vid);
clear_bit(vid, card->active_vlans);
qeth_l3_set_rx_mode(dev);
return 0;
}
@ -1366,7 +1262,6 @@ static int qeth_l3_process_inbound_buffer(struct qeth_card *card,
int work_done = 0;
struct sk_buff *skb;
struct qeth_hdr *hdr;
unsigned int len;
*done = 0;
WARN_ON_ONCE(!budget);
@ -1378,25 +1273,17 @@ static int qeth_l3_process_inbound_buffer(struct qeth_card *card,
*done = 1;
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);
/* fall through */
case QETH_HEADER_TYPE_LAYER2: /* for HiperSockets sniffer */
skb->protocol = eth_type_trans(skb, skb->dev);
len = skb->len;
napi_gro_receive(&card->napi, skb);
break;
default:
dev_kfree_skb_any(skb);
QETH_CARD_TEXT(card, 3, "inbunkno");
QETH_DBF_HEX(CTRL, 3, hdr, sizeof(*hdr));
continue;
}
skb->protocol = eth_type_trans(skb, skb->dev);
QETH_CARD_STAT_INC(card, rx_packets);
QETH_CARD_STAT_ADD(card, rx_bytes, skb->len);
napi_gro_receive(&card->napi, skb);
work_done++;
budget--;
QETH_CARD_STAT_INC(card, rx_packets);
QETH_CARD_STAT_ADD(card, rx_bytes, len);
}
return work_done;
}
@ -1462,8 +1349,11 @@ static void qeth_l3_rx_mode_work(struct work_struct *work)
QETH_CARD_TEXT(card, 3, "setmulti");
if (!card->options.sniffer) {
qeth_l3_add_multicast_ipv4(card);
qeth_l3_add_multicast_ipv6(card);
rtnl_lock();
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) {
switch (addr->disp_flag) {

View File

@ -60,9 +60,6 @@ static ssize_t qeth_l3_dev_route4_show(struct device *dev,
{
struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
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,
{
struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
return qeth_l3_dev_route_store(card, &card->options.route4,
QETH_PROT_IPV4, buf, count);
}
@ -124,9 +118,6 @@ static ssize_t qeth_l3_dev_route6_show(struct device *dev,
{
struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
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,
{
struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
return qeth_l3_dev_route_store(card, &card->options.route6,
QETH_PROT_IPV6, buf, count);
}
@ -150,9 +138,6 @@ static ssize_t qeth_l3_dev_fake_broadcast_show(struct device *dev,
{
struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
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,
char *tmp;
int i, rc = 0;
if (!card)
return -EINVAL;
mutex_lock(&card->conf_mutex);
if (card->state != CARD_STATE_DOWN) {
rc = -EPERM;
@ -190,9 +172,6 @@ static ssize_t qeth_l3_dev_sniffer_show(struct device *dev,
{
struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
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,
int rc = 0;
unsigned long i;
if (!card)
return -EINVAL;
if (!IS_IQD(card))
return -EPERM;
if (card->options.cq == QETH_CQ_ENABLED)
@ -248,16 +224,12 @@ out:
static DEVICE_ATTR(sniffer, 0644, qeth_l3_dev_sniffer_show,
qeth_l3_dev_sniffer_store);
static ssize_t qeth_l3_dev_hsuid_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct qeth_card *card = dev_get_drvdata(dev);
char tmp_hsuid[9];
if (!card)
return -EINVAL;
if (!IS_IQD(card))
return -EPERM;
@ -273,9 +245,6 @@ static ssize_t qeth_l3_dev_hsuid_store(struct device *dev,
char *tmp;
int rc;
if (!card)
return -EINVAL;
if (!IS_IQD(card))
return -EPERM;
if (card->state != CARD_STATE_DOWN)
@ -336,9 +305,6 @@ static ssize_t qeth_l3_dev_ipato_enable_show(struct device *dev,
{
struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
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,
bool enable;
int rc = 0;
if (!card)
return -EINVAL;
mutex_lock(&card->conf_mutex);
if (card->state != CARD_STATE_DOWN) {
rc = -EPERM;
@ -385,9 +348,6 @@ static ssize_t qeth_l3_dev_ipato_invert4_show(struct device *dev,
{
struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
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,
bool invert;
int rc = 0;
if (!card)
return -EINVAL;
mutex_lock(&card->conf_mutex);
if (sysfs_streq(buf, "toggle")) {
invert = !card->ipato.invert4;
@ -460,9 +417,6 @@ static ssize_t qeth_l3_dev_ipato_add4_show(struct device *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);
}
@ -528,9 +482,6 @@ static ssize_t qeth_l3_dev_ipato_add4_store(struct device *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);
}
@ -558,9 +509,6 @@ static ssize_t qeth_l3_dev_ipato_del4_store(struct device *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);
}
@ -572,9 +520,6 @@ static ssize_t qeth_l3_dev_ipato_invert6_show(struct device *dev,
{
struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
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,
bool invert;
int rc = 0;
if (!card)
return -EINVAL;
mutex_lock(&card->conf_mutex);
if (sysfs_streq(buf, "toggle")) {
invert = !card->ipato.invert6;
@ -617,9 +559,6 @@ static ssize_t qeth_l3_dev_ipato_add6_show(struct device *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);
}
@ -628,9 +567,6 @@ static ssize_t qeth_l3_dev_ipato_add6_store(struct device *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);
}
@ -643,9 +579,6 @@ static ssize_t qeth_l3_dev_ipato_del6_store(struct device *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);
}
@ -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 i;
if (!card)
return -EINVAL;
entry_len = (proto == QETH_PROT_IPV4)? 12 : 40;
entry_len += 2; /* \n + terminator */
mutex_lock(&card->ip_lock);
@ -741,9 +671,6 @@ static ssize_t qeth_l3_dev_vipa_add4_store(struct device *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);
}
@ -771,9 +698,6 @@ static ssize_t qeth_l3_dev_vipa_del4_store(struct device *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);
}
@ -793,9 +717,6 @@ static ssize_t qeth_l3_dev_vipa_add6_store(struct device *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);
}
@ -808,9 +729,6 @@ static ssize_t qeth_l3_dev_vipa_del6_store(struct device *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);
}
@ -884,9 +802,6 @@ static ssize_t qeth_l3_dev_rxip_add4_store(struct device *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);
}
@ -914,9 +829,6 @@ static ssize_t qeth_l3_dev_rxip_del4_store(struct device *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);
}
@ -936,9 +848,6 @@ static ssize_t qeth_l3_dev_rxip_add6_store(struct device *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);
}
@ -951,9 +860,6 @@ static ssize_t qeth_l3_dev_rxip_del6_store(struct device *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);
}