Commit 5416953f authored by David S. Miller's avatar David S. Miller

Merge branch 's390-qeth-next'

Julian Wiedmann says:

====================
s390/qeth: updates 2017-09-18

first batch of patches for 4.15. One larger item in there is Hans'
addition of new configuration options for flexible packet processing
('VNIC characteristics'). The patch descriptions have all the details.
Please apply.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents f231c417 e878c5e6
...@@ -182,6 +182,21 @@ struct qeth_sbp_info { ...@@ -182,6 +182,21 @@ struct qeth_sbp_info {
__u32 reflect_promisc_primary:1; __u32 reflect_promisc_primary:1;
}; };
struct qeth_vnicc_info {
/* supported/currently configured VNICCs; updated in IPA exchanges */
u32 sup_chars;
u32 cur_chars;
/* supported commands: bitmasks which VNICCs support respective cmd */
u32 set_char_sup;
u32 getset_timeout_sup;
/* timeout value for the learning characteristic */
u32 learning_timeout;
/* characteristics wanted/configured by user */
u32 wanted_chars;
/* has user explicitly enabled rx_bcast while online? */
bool rx_bcast_enabled;
};
static inline int qeth_is_ipa_supported(struct qeth_ipa_info *ipa, static inline int qeth_is_ipa_supported(struct qeth_ipa_info *ipa,
enum qeth_ipa_funcs func) enum qeth_ipa_funcs func)
{ {
...@@ -673,6 +688,7 @@ struct qeth_card_options { ...@@ -673,6 +688,7 @@ struct qeth_card_options {
struct qeth_routing_info route6; struct qeth_routing_info route6;
struct qeth_ipa_info ipa6; struct qeth_ipa_info ipa6;
struct qeth_sbp_info sbp; /* SETBRIDGEPORT options */ struct qeth_sbp_info sbp; /* SETBRIDGEPORT options */
struct qeth_vnicc_info vnicc; /* VNICC options */
int fake_broadcast; int fake_broadcast;
int layer2; int layer2;
int performance_stats; int performance_stats;
...@@ -946,13 +962,13 @@ int qeth_get_priority_queue(struct qeth_card *, struct sk_buff *, int, int); ...@@ -946,13 +962,13 @@ int qeth_get_priority_queue(struct qeth_card *, struct sk_buff *, int, int);
int qeth_get_elements_no(struct qeth_card *card, struct sk_buff *skb, int qeth_get_elements_no(struct qeth_card *card, struct sk_buff *skb,
int extra_elems, int data_offset); int extra_elems, int data_offset);
int qeth_get_elements_for_frags(struct sk_buff *); int qeth_get_elements_for_frags(struct sk_buff *);
int qeth_do_send_packet_fast(struct qeth_card *card, int qeth_do_send_packet_fast(struct qeth_qdio_out_q *queue, struct sk_buff *skb,
struct qeth_qdio_out_q *queue, struct sk_buff *skb,
struct qeth_hdr *hdr, unsigned int offset, struct qeth_hdr *hdr, unsigned int offset,
unsigned int hd_len); unsigned int hd_len);
int qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue, int qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue,
struct sk_buff *skb, struct qeth_hdr *hdr, struct sk_buff *skb, struct qeth_hdr *hdr,
unsigned int hd_len, unsigned int offset, int elements); unsigned int offset, unsigned int hd_len,
int elements_needed);
int qeth_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); int qeth_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
int qeth_core_get_sset_count(struct net_device *, int); int qeth_core_get_sset_count(struct net_device *, int);
void qeth_core_get_ethtool_stats(struct net_device *, void qeth_core_get_ethtool_stats(struct net_device *,
......
...@@ -4040,35 +4040,23 @@ static int qeth_fill_buffer(struct qeth_qdio_out_q *queue, ...@@ -4040,35 +4040,23 @@ static int qeth_fill_buffer(struct qeth_qdio_out_q *queue,
return flush_cnt; return flush_cnt;
} }
int qeth_do_send_packet_fast(struct qeth_card *card, int qeth_do_send_packet_fast(struct qeth_qdio_out_q *queue, struct sk_buff *skb,
struct qeth_qdio_out_q *queue, struct sk_buff *skb,
struct qeth_hdr *hdr, unsigned int offset, struct qeth_hdr *hdr, unsigned int offset,
unsigned int hd_len) unsigned int hd_len)
{ {
struct qeth_qdio_out_buffer *buffer; int index = queue->next_buf_to_fill;
int index; struct qeth_qdio_out_buffer *buffer = queue->bufs[index];
/* spin until we get the queue ... */
while (atomic_cmpxchg(&queue->state, QETH_OUT_Q_UNLOCKED,
QETH_OUT_Q_LOCKED) != QETH_OUT_Q_UNLOCKED);
/* ... now we've got the queue */
index = queue->next_buf_to_fill;
buffer = queue->bufs[queue->next_buf_to_fill];
/* /*
* check if buffer is empty to make sure that we do not 'overtake' * check if buffer is empty to make sure that we do not 'overtake'
* ourselves and try to fill a buffer that is already primed * ourselves and try to fill a buffer that is already primed
*/ */
if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY) if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY)
goto out; return -EBUSY;
queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) % queue->next_buf_to_fill = (index + 1) % QDIO_MAX_BUFFERS_PER_Q;
QDIO_MAX_BUFFERS_PER_Q;
atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED);
qeth_fill_buffer(queue, buffer, skb, hdr, offset, hd_len); qeth_fill_buffer(queue, buffer, skb, hdr, offset, hd_len);
qeth_flush_buffers(queue, index, 1); qeth_flush_buffers(queue, index, 1);
return 0; return 0;
out:
atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED);
return -EBUSY;
} }
EXPORT_SYMBOL_GPL(qeth_do_send_packet_fast); EXPORT_SYMBOL_GPL(qeth_do_send_packet_fast);
...@@ -4923,7 +4911,6 @@ static void qeth_qdio_establish_cq(struct qeth_card *card, ...@@ -4923,7 +4911,6 @@ static void qeth_qdio_establish_cq(struct qeth_card *card,
if (card->options.cq == QETH_CQ_ENABLED) { if (card->options.cq == QETH_CQ_ENABLED) {
int offset = QDIO_MAX_BUFFERS_PER_Q * int offset = QDIO_MAX_BUFFERS_PER_Q *
(card->qdio.no_in_queues - 1); (card->qdio.no_in_queues - 1);
i = QDIO_MAX_BUFFERS_PER_Q * (card->qdio.no_in_queues - 1);
for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; ++i) { for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; ++i) {
in_sbal_ptrs[offset + i] = (struct qdio_buffer *) in_sbal_ptrs[offset + i] = (struct qdio_buffer *)
virt_to_phys(card->qdio.c_q->bufs[i].buffer); virt_to_phys(card->qdio.c_q->bufs[i].buffer);
......
...@@ -167,7 +167,7 @@ static struct ipa_rc_msg qeth_ipa_rc_msg[] = { ...@@ -167,7 +167,7 @@ static struct ipa_rc_msg qeth_ipa_rc_msg[] = {
{IPA_RC_IP_TABLE_FULL, "Add Addr IP Table Full - ipv6"}, {IPA_RC_IP_TABLE_FULL, "Add Addr IP Table Full - ipv6"},
{IPA_RC_UNKNOWN_ERROR, "IPA command failed - reason unknown"}, {IPA_RC_UNKNOWN_ERROR, "IPA command failed - reason unknown"},
{IPA_RC_UNSUPPORTED_COMMAND, "Command not supported"}, {IPA_RC_UNSUPPORTED_COMMAND, "Command not supported"},
{IPA_RC_TRACE_ALREADY_ACTIVE, "trace already active"}, {IPA_RC_VNICC_OOSEQ, "Command issued out of sequence"},
{IPA_RC_INVALID_FORMAT, "invalid format or length"}, {IPA_RC_INVALID_FORMAT, "invalid format or length"},
{IPA_RC_DUP_IPV6_REMOTE, "ipv6 address already registered remote"}, {IPA_RC_DUP_IPV6_REMOTE, "ipv6 address already registered remote"},
{IPA_RC_SBP_IQD_NOT_CONFIGURED, "Not configured for bridgeport"}, {IPA_RC_SBP_IQD_NOT_CONFIGURED, "Not configured for bridgeport"},
...@@ -193,6 +193,7 @@ static struct ipa_rc_msg qeth_ipa_rc_msg[] = { ...@@ -193,6 +193,7 @@ static struct ipa_rc_msg qeth_ipa_rc_msg[] = {
{IPA_RC_L2_INVALID_VLAN_ID, "L2 invalid vlan id"}, {IPA_RC_L2_INVALID_VLAN_ID, "L2 invalid vlan id"},
{IPA_RC_L2_DUP_VLAN_ID, "L2 duplicate vlan id"}, {IPA_RC_L2_DUP_VLAN_ID, "L2 duplicate vlan id"},
{IPA_RC_L2_VLAN_ID_NOT_FOUND, "L2 vlan id not found"}, {IPA_RC_L2_VLAN_ID_NOT_FOUND, "L2 vlan id not found"},
{IPA_RC_VNICC_VNICBP, "VNIC is BridgePort"},
{IPA_RC_SBP_OSA_NOT_CONFIGURED, "Not configured for bridgeport"}, {IPA_RC_SBP_OSA_NOT_CONFIGURED, "Not configured for bridgeport"},
{IPA_RC_SBP_OSA_OS_MISMATCH, "OS mismatch"}, {IPA_RC_SBP_OSA_OS_MISMATCH, "OS mismatch"},
{IPA_RC_SBP_OSA_ANO_DEV_PRIMARY, "Primary bridgeport exists already"}, {IPA_RC_SBP_OSA_ANO_DEV_PRIMARY, "Primary bridgeport exists already"},
...@@ -253,6 +254,7 @@ static struct ipa_cmd_names qeth_ipa_cmd_names[] = { ...@@ -253,6 +254,7 @@ static struct ipa_cmd_names qeth_ipa_cmd_names[] = {
{IPA_CMD_DELGMAC, "delgmac"}, {IPA_CMD_DELGMAC, "delgmac"},
{IPA_CMD_SETVLAN, "setvlan"}, {IPA_CMD_SETVLAN, "setvlan"},
{IPA_CMD_DELVLAN, "delvlan"}, {IPA_CMD_DELVLAN, "delvlan"},
{IPA_CMD_VNICC, "vnic_characteristics"},
{IPA_CMD_SETBRIDGEPORT_OSA, "set_bridge_port(osa)"}, {IPA_CMD_SETBRIDGEPORT_OSA, "set_bridge_port(osa)"},
{IPA_CMD_SETCCID, "setccid"}, {IPA_CMD_SETCCID, "setccid"},
{IPA_CMD_DELCCID, "delccid"}, {IPA_CMD_DELCCID, "delccid"},
......
...@@ -90,6 +90,7 @@ enum qeth_ipa_cmds { ...@@ -90,6 +90,7 @@ enum qeth_ipa_cmds {
IPA_CMD_DELGMAC = 0x24, IPA_CMD_DELGMAC = 0x24,
IPA_CMD_SETVLAN = 0x25, IPA_CMD_SETVLAN = 0x25,
IPA_CMD_DELVLAN = 0x26, IPA_CMD_DELVLAN = 0x26,
IPA_CMD_VNICC = 0x2a,
IPA_CMD_SETBRIDGEPORT_OSA = 0x2b, IPA_CMD_SETBRIDGEPORT_OSA = 0x2b,
IPA_CMD_SETCCID = 0x41, IPA_CMD_SETCCID = 0x41,
IPA_CMD_DELCCID = 0x42, IPA_CMD_DELCCID = 0x42,
...@@ -165,6 +166,8 @@ enum qeth_ipa_return_codes { ...@@ -165,6 +166,8 @@ enum qeth_ipa_return_codes {
IPA_RC_L2_INVALID_VLAN_ID = 0x2015, IPA_RC_L2_INVALID_VLAN_ID = 0x2015,
IPA_RC_L2_DUP_VLAN_ID = 0x2016, IPA_RC_L2_DUP_VLAN_ID = 0x2016,
IPA_RC_L2_VLAN_ID_NOT_FOUND = 0x2017, IPA_RC_L2_VLAN_ID_NOT_FOUND = 0x2017,
IPA_RC_L2_VLAN_ID_NOT_ALLOWED = 0x2050,
IPA_RC_VNICC_VNICBP = 0x20B0,
IPA_RC_SBP_OSA_NOT_CONFIGURED = 0x2B0C, IPA_RC_SBP_OSA_NOT_CONFIGURED = 0x2B0C,
IPA_RC_SBP_OSA_OS_MISMATCH = 0x2B10, IPA_RC_SBP_OSA_OS_MISMATCH = 0x2B10,
IPA_RC_SBP_OSA_ANO_DEV_PRIMARY = 0x2B14, IPA_RC_SBP_OSA_ANO_DEV_PRIMARY = 0x2B14,
...@@ -197,6 +200,9 @@ enum qeth_ipa_return_codes { ...@@ -197,6 +200,9 @@ enum qeth_ipa_return_codes {
IPA_RC_ENOMEM = 0xfffe, IPA_RC_ENOMEM = 0xfffe,
IPA_RC_FFFF = 0xffff IPA_RC_FFFF = 0xffff
}; };
/* for VNIC Characteristics */
#define IPA_RC_VNICC_OOSEQ 0x0005
/* for SET_DIAGNOSTIC_ASSIST */ /* for SET_DIAGNOSTIC_ASSIST */
#define IPA_RC_INVALID_SUBCMD IPA_RC_IP_TABLE_FULL #define IPA_RC_INVALID_SUBCMD IPA_RC_IP_TABLE_FULL
#define IPA_RC_HARDWARE_AUTH_ERROR IPA_RC_UNKNOWN_ERROR #define IPA_RC_HARDWARE_AUTH_ERROR IPA_RC_UNKNOWN_ERROR
...@@ -551,6 +557,71 @@ struct qeth_ipacmd_diagass { ...@@ -551,6 +557,71 @@ struct qeth_ipacmd_diagass {
__u8 cdata[64]; __u8 cdata[64];
} __attribute__ ((packed)); } __attribute__ ((packed));
/* VNIC Characteristics IPA Command: *****************************************/
/* IPA commands/sub commands for VNICC */
#define IPA_VNICC_QUERY_CHARS 0x00000000L
#define IPA_VNICC_QUERY_CMDS 0x00000001L
#define IPA_VNICC_ENABLE 0x00000002L
#define IPA_VNICC_DISABLE 0x00000004L
#define IPA_VNICC_SET_TIMEOUT 0x00000008L
#define IPA_VNICC_GET_TIMEOUT 0x00000010L
/* VNICC flags */
#define QETH_VNICC_FLOODING 0x80000000
#define QETH_VNICC_MCAST_FLOODING 0x40000000
#define QETH_VNICC_LEARNING 0x20000000
#define QETH_VNICC_TAKEOVER_SETVMAC 0x10000000
#define QETH_VNICC_TAKEOVER_LEARNING 0x08000000
#define QETH_VNICC_BRIDGE_INVISIBLE 0x04000000
#define QETH_VNICC_RX_BCAST 0x02000000
/* VNICC default values */
#define QETH_VNICC_ALL 0xff000000
#define QETH_VNICC_DEFAULT QETH_VNICC_RX_BCAST
/* default VNICC timeout in seconds */
#define QETH_VNICC_DEFAULT_TIMEOUT 600
/* VNICC header */
struct qeth_ipacmd_vnicc_hdr {
u32 sup;
u32 cur;
};
/* VNICC sub command header */
struct qeth_vnicc_sub_hdr {
u16 data_length;
u16 reserved;
u32 sub_command;
};
/* query supported commands for VNIC characteristic */
struct qeth_vnicc_query_cmds {
u32 vnic_char;
u32 sup_cmds;
};
/* enable/disable VNIC characteristic */
struct qeth_vnicc_set_char {
u32 vnic_char;
};
/* get/set timeout for VNIC characteristic */
struct qeth_vnicc_getset_timeout {
u32 vnic_char;
u32 timeout;
};
/* complete VNICC IPA command message */
struct qeth_ipacmd_vnicc {
struct qeth_ipacmd_vnicc_hdr hdr;
struct qeth_vnicc_sub_hdr sub_hdr;
union {
struct qeth_vnicc_query_cmds query_cmds;
struct qeth_vnicc_set_char set_char;
struct qeth_vnicc_getset_timeout getset_timeout;
};
};
/* SETBRIDGEPORT IPA Command: *********************************************/ /* SETBRIDGEPORT IPA Command: *********************************************/
enum qeth_ipa_sbp_cmd { enum qeth_ipa_sbp_cmd {
IPA_SBP_QUERY_COMMANDS_SUPPORTED = 0x00000000L, IPA_SBP_QUERY_COMMANDS_SUPPORTED = 0x00000000L,
...@@ -692,6 +763,7 @@ struct qeth_ipa_cmd { ...@@ -692,6 +763,7 @@ struct qeth_ipa_cmd {
struct qeth_ipacmd_diagass diagass; struct qeth_ipacmd_diagass diagass;
struct qeth_ipacmd_setbridgeport sbp; struct qeth_ipacmd_setbridgeport sbp;
struct qeth_ipacmd_addr_change addrchange; struct qeth_ipacmd_addr_change addrchange;
struct qeth_ipacmd_vnicc vnicc;
} data; } data;
} __attribute__ ((packed)); } __attribute__ ((packed));
......
...@@ -14,6 +14,12 @@ int qeth_l2_create_device_attributes(struct device *); ...@@ -14,6 +14,12 @@ int qeth_l2_create_device_attributes(struct device *);
void qeth_l2_remove_device_attributes(struct device *); void qeth_l2_remove_device_attributes(struct device *);
void qeth_l2_setup_bridgeport_attrs(struct qeth_card *card); void qeth_l2_setup_bridgeport_attrs(struct qeth_card *card);
int qeth_l2_vnicc_set_state(struct qeth_card *card, u32 vnicc, bool state);
int qeth_l2_vnicc_get_state(struct qeth_card *card, u32 vnicc, bool *state);
int qeth_l2_vnicc_set_timeout(struct qeth_card *card, u32 timeout);
int qeth_l2_vnicc_get_timeout(struct qeth_card *card, u32 *timeout);
bool qeth_l2_vnicc_is_in_use(struct qeth_card *card);
struct qeth_mac { struct qeth_mac {
u8 mac_addr[OSA_ADDR_LEN]; u8 mac_addr[OSA_ADDR_LEN];
u8 is_uc:1; u8 is_uc:1;
......
This diff is collapsed.
...@@ -20,6 +20,9 @@ static ssize_t qeth_bridge_port_role_state_show(struct device *dev, ...@@ -20,6 +20,9 @@ static ssize_t qeth_bridge_port_role_state_show(struct device *dev,
if (!card) if (!card)
return -EINVAL; return -EINVAL;
if (qeth_l2_vnicc_is_in_use(card))
return sprintf(buf, "n/a (VNIC characteristics)\n");
if (qeth_card_hw_is_reachable(card) && if (qeth_card_hw_is_reachable(card) &&
card->options.sbp.supported_funcs) card->options.sbp.supported_funcs)
rc = qeth_bridgeport_query_ports(card, rc = qeth_bridgeport_query_ports(card,
...@@ -60,6 +63,11 @@ static ssize_t qeth_bridge_port_role_state_show(struct device *dev, ...@@ -60,6 +63,11 @@ static ssize_t qeth_bridge_port_role_state_show(struct device *dev,
static ssize_t qeth_bridge_port_role_show(struct device *dev, static ssize_t qeth_bridge_port_role_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 (qeth_l2_vnicc_is_in_use(card))
return sprintf(buf, "n/a (VNIC characteristics)\n");
return qeth_bridge_port_role_state_show(dev, attr, buf, 0); return qeth_bridge_port_role_state_show(dev, attr, buf, 0);
} }
...@@ -83,7 +91,10 @@ static ssize_t qeth_bridge_port_role_store(struct device *dev, ...@@ -83,7 +91,10 @@ static ssize_t qeth_bridge_port_role_store(struct device *dev,
mutex_lock(&card->conf_mutex); mutex_lock(&card->conf_mutex);
if (card->options.sbp.reflect_promisc) /* Forbid direct manipulation */ if (qeth_l2_vnicc_is_in_use(card))
rc = -EBUSY;
else if (card->options.sbp.reflect_promisc)
/* Forbid direct manipulation */
rc = -EPERM; rc = -EPERM;
else if (qeth_card_hw_is_reachable(card)) { else if (qeth_card_hw_is_reachable(card)) {
rc = qeth_bridgeport_setrole(card, role); rc = qeth_bridgeport_setrole(card, role);
...@@ -103,6 +114,11 @@ static DEVICE_ATTR(bridge_role, 0644, qeth_bridge_port_role_show, ...@@ -103,6 +114,11 @@ static DEVICE_ATTR(bridge_role, 0644, qeth_bridge_port_role_show,
static ssize_t qeth_bridge_port_state_show(struct device *dev, static ssize_t qeth_bridge_port_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);
if (qeth_l2_vnicc_is_in_use(card))
return sprintf(buf, "n/a (VNIC characteristics)\n");
return qeth_bridge_port_role_state_show(dev, attr, buf, 1); return qeth_bridge_port_role_state_show(dev, attr, buf, 1);
} }
...@@ -118,6 +134,9 @@ static ssize_t qeth_bridgeport_hostnotification_show(struct device *dev, ...@@ -118,6 +134,9 @@ static ssize_t qeth_bridgeport_hostnotification_show(struct device *dev,
if (!card) if (!card)
return -EINVAL; return -EINVAL;
if (qeth_l2_vnicc_is_in_use(card))
return sprintf(buf, "n/a (VNIC characteristics)\n");
enabled = card->options.sbp.hostnotification; enabled = card->options.sbp.hostnotification;
return sprintf(buf, "%d\n", enabled); return sprintf(buf, "%d\n", enabled);
...@@ -142,7 +161,9 @@ static ssize_t qeth_bridgeport_hostnotification_store(struct device *dev, ...@@ -142,7 +161,9 @@ static ssize_t qeth_bridgeport_hostnotification_store(struct device *dev,
mutex_lock(&card->conf_mutex); mutex_lock(&card->conf_mutex);
if (qeth_card_hw_is_reachable(card)) { if (qeth_l2_vnicc_is_in_use(card))
rc = -EBUSY;
else if (qeth_card_hw_is_reachable(card)) {
rc = qeth_bridgeport_an_set(card, enable); rc = qeth_bridgeport_an_set(card, enable);
if (!rc) if (!rc)
card->options.sbp.hostnotification = enable; card->options.sbp.hostnotification = enable;
...@@ -167,6 +188,9 @@ static ssize_t qeth_bridgeport_reflect_show(struct device *dev, ...@@ -167,6 +188,9 @@ static ssize_t qeth_bridgeport_reflect_show(struct device *dev,
if (!card) if (!card)
return -EINVAL; return -EINVAL;
if (qeth_l2_vnicc_is_in_use(card))
return sprintf(buf, "n/a (VNIC characteristics)\n");
if (card->options.sbp.reflect_promisc) { if (card->options.sbp.reflect_promisc) {
if (card->options.sbp.reflect_promisc_primary) if (card->options.sbp.reflect_promisc_primary)
state = "primary"; state = "primary";
...@@ -202,7 +226,9 @@ static ssize_t qeth_bridgeport_reflect_store(struct device *dev, ...@@ -202,7 +226,9 @@ static ssize_t qeth_bridgeport_reflect_store(struct device *dev,
mutex_lock(&card->conf_mutex); mutex_lock(&card->conf_mutex);
if (card->options.sbp.role != QETH_SBP_ROLE_NONE) if (qeth_l2_vnicc_is_in_use(card))
rc = -EBUSY;
else if (card->options.sbp.role != QETH_SBP_ROLE_NONE)
rc = -EPERM; rc = -EPERM;
else { else {
card->options.sbp.reflect_promisc = enable; card->options.sbp.reflect_promisc = enable;
...@@ -231,16 +257,6 @@ static struct attribute_group qeth_l2_bridgeport_attr_group = { ...@@ -231,16 +257,6 @@ static struct attribute_group qeth_l2_bridgeport_attr_group = {
.attrs = qeth_l2_bridgeport_attrs, .attrs = qeth_l2_bridgeport_attrs,
}; };
int qeth_l2_create_device_attributes(struct device *dev)
{
return sysfs_create_group(&dev->kobj, &qeth_l2_bridgeport_attr_group);
}
void qeth_l2_remove_device_attributes(struct device *dev)
{
sysfs_remove_group(&dev->kobj, &qeth_l2_bridgeport_attr_group);
}
/** /**
* qeth_l2_setup_bridgeport_attrs() - set/restore attrs when turning online. * qeth_l2_setup_bridgeport_attrs() - set/restore attrs when turning online.
* @card: qeth_card structure pointer * @card: qeth_card structure pointer
...@@ -270,10 +286,168 @@ void qeth_l2_setup_bridgeport_attrs(struct qeth_card *card) ...@@ -270,10 +286,168 @@ void qeth_l2_setup_bridgeport_attrs(struct qeth_card *card)
qeth_bridgeport_an_set(card, 0); qeth_bridgeport_an_set(card, 0);
} }
/* VNIC CHARS support */
/* convert sysfs attr name to VNIC characteristic */
static u32 qeth_l2_vnicc_sysfs_attr_to_char(const char *attr_name)
{
if (sysfs_streq(attr_name, "flooding"))
return QETH_VNICC_FLOODING;
else if (sysfs_streq(attr_name, "mcast_flooding"))
return QETH_VNICC_MCAST_FLOODING;
else if (sysfs_streq(attr_name, "learning"))
return QETH_VNICC_LEARNING;
else if (sysfs_streq(attr_name, "takeover_setvmac"))
return QETH_VNICC_TAKEOVER_SETVMAC;
else if (sysfs_streq(attr_name, "takeover_learning"))
return QETH_VNICC_TAKEOVER_LEARNING;
else if (sysfs_streq(attr_name, "bridge_invisible"))
return QETH_VNICC_BRIDGE_INVISIBLE;
else if (sysfs_streq(attr_name, "rx_bcast"))
return QETH_VNICC_RX_BCAST;
return 0;
}
/* get current timeout setting */
static ssize_t qeth_vnicc_timeout_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct qeth_card *card = dev_get_drvdata(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");
if (rc == -EOPNOTSUPP)
return sprintf(buf, "n/a\n");
return rc ? rc : sprintf(buf, "%d\n", timeout);
}
/* change timeout setting */
static ssize_t qeth_vnicc_timeout_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct qeth_card *card = dev_get_drvdata(dev);
u32 timeout;
int rc;
if (!card)
return -EINVAL;
rc = kstrtou32(buf, 10, &timeout);
if (rc)
return rc;
mutex_lock(&card->conf_mutex);
rc = qeth_l2_vnicc_set_timeout(card, timeout);
mutex_unlock(&card->conf_mutex);
return rc ? rc : count;
}
/* get current setting of characteristic */
static ssize_t qeth_vnicc_char_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct qeth_card *card = dev_get_drvdata(dev);
bool state;
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);
if (rc == -EBUSY)
return sprintf(buf, "n/a (BridgePort)\n");
if (rc == -EOPNOTSUPP)
return sprintf(buf, "n/a\n");
return rc ? rc : sprintf(buf, "%d\n", state);
}
/* change setting of characteristic */
static ssize_t qeth_vnicc_char_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct qeth_card *card = dev_get_drvdata(dev);
bool state;
u32 vnicc;
int rc;
if (!card)
return -EINVAL;
if (kstrtobool(buf, &state))
return -EINVAL;
vnicc = qeth_l2_vnicc_sysfs_attr_to_char(attr->attr.name);
mutex_lock(&card->conf_mutex);
rc = qeth_l2_vnicc_set_state(card, vnicc, state);
mutex_unlock(&card->conf_mutex);
return rc ? rc : count;
}
static DEVICE_ATTR(flooding, 0644, qeth_vnicc_char_show, qeth_vnicc_char_store);
static DEVICE_ATTR(mcast_flooding, 0644, qeth_vnicc_char_show,
qeth_vnicc_char_store);
static DEVICE_ATTR(learning, 0644, qeth_vnicc_char_show, qeth_vnicc_char_store);
static DEVICE_ATTR(learning_timeout, 0644, qeth_vnicc_timeout_show,
qeth_vnicc_timeout_store);
static DEVICE_ATTR(takeover_setvmac, 0644, qeth_vnicc_char_show,
qeth_vnicc_char_store);
static DEVICE_ATTR(takeover_learning, 0644, qeth_vnicc_char_show,
qeth_vnicc_char_store);
static DEVICE_ATTR(bridge_invisible, 0644, qeth_vnicc_char_show,
qeth_vnicc_char_store);
static DEVICE_ATTR(rx_bcast, 0644, qeth_vnicc_char_show, qeth_vnicc_char_store);
static struct attribute *qeth_l2_vnicc_attrs[] = {
&dev_attr_flooding.attr,
&dev_attr_mcast_flooding.attr,
&dev_attr_learning.attr,
&dev_attr_learning_timeout.attr,
&dev_attr_takeover_setvmac.attr,
&dev_attr_takeover_learning.attr,
&dev_attr_bridge_invisible.attr,
&dev_attr_rx_bcast.attr,
NULL,
};
static struct attribute_group qeth_l2_vnicc_attr_group = {
.attrs = qeth_l2_vnicc_attrs,
.name = "vnicc",
};
static const struct attribute_group *qeth_l2_only_attr_groups[] = {
&qeth_l2_bridgeport_attr_group,
&qeth_l2_vnicc_attr_group,
NULL,
};
int qeth_l2_create_device_attributes(struct device *dev)
{
return sysfs_create_groups(&dev->kobj, qeth_l2_only_attr_groups);
}
void qeth_l2_remove_device_attributes(struct device *dev)
{
sysfs_remove_groups(&dev->kobj, qeth_l2_only_attr_groups);
}
const struct attribute_group *qeth_l2_attr_groups[] = { const struct attribute_group *qeth_l2_attr_groups[] = {
&qeth_device_attr_group, &qeth_device_attr_group,
&qeth_device_blkt_group, &qeth_device_blkt_group,
/* l2 specific, see l2_{create,remove}_device_attributes(): */ /* l2 specific, see qeth_l2_only_attr_groups: */
&qeth_l2_bridgeport_attr_group, &qeth_l2_bridgeport_attr_group,
&qeth_l2_vnicc_attr_group,
NULL, NULL,
}; };
...@@ -1646,13 +1646,12 @@ static int qeth_l3_vlan_rx_kill_vid(struct net_device *dev, ...@@ -1646,13 +1646,12 @@ static int qeth_l3_vlan_rx_kill_vid(struct net_device *dev,
return 0; return 0;
} }
static int qeth_l3_rebuild_skb(struct qeth_card *card, struct sk_buff *skb, static void qeth_l3_rebuild_skb(struct qeth_card *card, struct sk_buff *skb,
struct qeth_hdr *hdr, unsigned short *vlan_id) struct qeth_hdr *hdr)
{ {
__u16 prot; __u16 prot;
struct iphdr *ip_hdr; struct iphdr *ip_hdr;
unsigned char tg_addr[MAX_ADDR_LEN]; unsigned char tg_addr[MAX_ADDR_LEN];
int is_vlan = 0;
if (!(hdr->hdr.l3.flags & QETH_HDR_PASSTHRU)) { if (!(hdr->hdr.l3.flags & QETH_HDR_PASSTHRU)) {
prot = (hdr->hdr.l3.flags & QETH_HDR_IPV6) ? ETH_P_IPV6 : prot = (hdr->hdr.l3.flags & QETH_HDR_IPV6) ? ETH_P_IPV6 :
...@@ -1706,11 +1705,14 @@ static int qeth_l3_rebuild_skb(struct qeth_card *card, struct sk_buff *skb, ...@@ -1706,11 +1705,14 @@ static int qeth_l3_rebuild_skb(struct qeth_card *card, struct sk_buff *skb,
skb->protocol = eth_type_trans(skb, card->dev); skb->protocol = eth_type_trans(skb, card->dev);
if (hdr->hdr.l3.ext_flags & /* copy VLAN tag from hdr into skb */
(QETH_HDR_EXT_VLAN_FRAME | QETH_HDR_EXT_INCLUDE_VLAN_TAG)) { if (!card->options.sniffer &&
*vlan_id = (hdr->hdr.l3.ext_flags & QETH_HDR_EXT_VLAN_FRAME) ? (hdr->hdr.l3.ext_flags & (QETH_HDR_EXT_VLAN_FRAME |
hdr->hdr.l3.vlan_id : *((u16 *)&hdr->hdr.l3.dest_addr[12]); QETH_HDR_EXT_INCLUDE_VLAN_TAG))) {
is_vlan = 1; u16 tag = (hdr->hdr.l3.ext_flags & QETH_HDR_EXT_VLAN_FRAME) ?
hdr->hdr.l3.vlan_id :
*((u16 *)&hdr->hdr.l3.dest_addr[12]);
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), tag);
} }
if (card->dev->features & NETIF_F_RXCSUM) { if (card->dev->features & NETIF_F_RXCSUM) {
...@@ -1724,7 +1726,6 @@ static int qeth_l3_rebuild_skb(struct qeth_card *card, struct sk_buff *skb, ...@@ -1724,7 +1726,6 @@ static int qeth_l3_rebuild_skb(struct qeth_card *card, struct sk_buff *skb,
skb->ip_summed = CHECKSUM_NONE; skb->ip_summed = CHECKSUM_NONE;
} else } else
skb->ip_summed = CHECKSUM_NONE; skb->ip_summed = CHECKSUM_NONE;
return is_vlan;
} }
static int qeth_l3_process_inbound_buffer(struct qeth_card *card, static int qeth_l3_process_inbound_buffer(struct qeth_card *card,
...@@ -1733,8 +1734,6 @@ static int qeth_l3_process_inbound_buffer(struct qeth_card *card, ...@@ -1733,8 +1734,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;
__u16 vlan_tag = 0;
int is_vlan;
unsigned int len; unsigned int len;
__u16 magic; __u16 magic;
...@@ -1764,12 +1763,8 @@ static int qeth_l3_process_inbound_buffer(struct qeth_card *card, ...@@ -1764,12 +1763,8 @@ static int qeth_l3_process_inbound_buffer(struct qeth_card *card,
card->dev->addr_len); card->dev->addr_len);
netif_receive_skb(skb); netif_receive_skb(skb);
} else { } else {
is_vlan = qeth_l3_rebuild_skb(card, skb, hdr, qeth_l3_rebuild_skb(card, skb, hdr);
&vlan_tag);
len = skb->len; len = skb->len;
if (is_vlan && !card->options.sniffer)
__vlan_hwaccel_put_tag(skb,
htons(ETH_P_8021Q), vlan_tag);
napi_gro_receive(&card->napi, skb); napi_gro_receive(&card->napi, skb);
} }
break; break;
...@@ -2771,8 +2766,8 @@ static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb, ...@@ -2771,8 +2766,8 @@ static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb,
rc = qeth_do_send_packet(card, queue, new_skb, hdr, hd_len, rc = qeth_do_send_packet(card, queue, new_skb, hdr, hd_len,
hd_len, elements); hd_len, elements);
} else } else
rc = qeth_do_send_packet_fast(card, queue, new_skb, hdr, rc = qeth_do_send_packet_fast(queue, new_skb, hdr, data_offset,
data_offset, hd_len); hd_len);
if (!rc) { if (!rc) {
card->stats.tx_packets++; card->stats.tx_packets++;
......
...@@ -1028,52 +1028,31 @@ static const struct attribute_group qeth_device_rxip_group = { ...@@ -1028,52 +1028,31 @@ static const struct attribute_group qeth_device_rxip_group = {
.attrs = qeth_rxip_device_attrs, .attrs = qeth_rxip_device_attrs,
}; };
static const struct attribute_group *qeth_l3_only_attr_groups[] = {
&qeth_l3_device_attr_group,
&qeth_device_ipato_group,
&qeth_device_vipa_group,
&qeth_device_rxip_group,
NULL,
};
int qeth_l3_create_device_attributes(struct device *dev) int qeth_l3_create_device_attributes(struct device *dev)
{ {
int ret; return sysfs_create_groups(&dev->kobj, qeth_l3_only_attr_groups);
ret = sysfs_create_group(&dev->kobj, &qeth_l3_device_attr_group);
if (ret)
return ret;
ret = sysfs_create_group(&dev->kobj, &qeth_device_ipato_group);
if (ret) {
sysfs_remove_group(&dev->kobj, &qeth_l3_device_attr_group);
return ret;
}
ret = sysfs_create_group(&dev->kobj, &qeth_device_vipa_group);
if (ret) {
sysfs_remove_group(&dev->kobj, &qeth_l3_device_attr_group);
sysfs_remove_group(&dev->kobj, &qeth_device_ipato_group);
return ret;
}
ret = sysfs_create_group(&dev->kobj, &qeth_device_rxip_group);
if (ret) {
sysfs_remove_group(&dev->kobj, &qeth_l3_device_attr_group);
sysfs_remove_group(&dev->kobj, &qeth_device_ipato_group);
sysfs_remove_group(&dev->kobj, &qeth_device_vipa_group);
return ret;
}
return 0;
} }
void qeth_l3_remove_device_attributes(struct device *dev) void qeth_l3_remove_device_attributes(struct device *dev)
{ {
sysfs_remove_group(&dev->kobj, &qeth_l3_device_attr_group); sysfs_remove_groups(&dev->kobj, qeth_l3_only_attr_groups);
sysfs_remove_group(&dev->kobj, &qeth_device_ipato_group);
sysfs_remove_group(&dev->kobj, &qeth_device_vipa_group);
sysfs_remove_group(&dev->kobj, &qeth_device_rxip_group);
} }
const struct attribute_group *qeth_l3_attr_groups[] = { const struct attribute_group *qeth_l3_attr_groups[] = {
&qeth_device_attr_group, &qeth_device_attr_group,
&qeth_device_blkt_group, &qeth_device_blkt_group,
/* l3 specific, see l3_{create,remove}_device_attributes(): */ /* l3 specific, see qeth_l3_only_attr_groups: */
&qeth_l3_device_attr_group, &qeth_l3_device_attr_group,
&qeth_device_ipato_group, &qeth_device_ipato_group,
&qeth_device_vipa_group, &qeth_device_vipa_group,
&qeth_device_rxip_group, &qeth_device_rxip_group,
NULL, NULL,
}; };
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