diff options
Diffstat (limited to 'drivers/s390/net/qeth_l2_main.c')
| -rw-r--r-- | drivers/s390/net/qeth_l2_main.c | 68 |
1 files changed, 52 insertions, 16 deletions
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 914d2c121fd..5ef5b4f4575 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -33,6 +33,11 @@ static int qeth_l2_send_setdelmac(struct qeth_card *, __u8 *, unsigned long)); static void qeth_l2_set_multicast_list(struct net_device *); static int qeth_l2_recover(void *); +static void qeth_bridgeport_query_support(struct qeth_card *card); +static void qeth_bridge_state_change(struct qeth_card *card, + struct qeth_ipa_cmd *cmd); +static void qeth_bridge_host_event(struct qeth_card *card, + struct qeth_ipa_cmd *cmd); static int qeth_l2_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { @@ -236,7 +241,7 @@ static inline int qeth_l2_get_cast_type(struct qeth_card *card, } static void qeth_l2_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, - struct sk_buff *skb, int ipv, int cast_type) + struct sk_buff *skb, int cast_type) { struct vlan_ethhdr *veth = (struct vlan_ethhdr *)skb_mac_header(skb); @@ -720,15 +725,20 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) int elements = 0; struct qeth_card *card = dev->ml_priv; struct sk_buff *new_skb = skb; - int ipv = qeth_get_ip_version(skb); int cast_type = qeth_l2_get_cast_type(card, skb); - struct qeth_qdio_out_q *queue = card->qdio.out_qs - [qeth_get_priority_queue(card, skb, ipv, cast_type)]; + struct qeth_qdio_out_q *queue; int tx_bytes = skb->len; int data_offset = -1; int elements_needed = 0; int hd_len = 0; + if (card->qdio.do_prio_queueing || (cast_type && + card->info.is_multicast_different)) + queue = card->qdio.out_qs[qeth_get_priority_queue(card, skb, + qeth_get_ip_version(skb), cast_type)]; + else + queue = card->qdio.out_qs[card->qdio.default_out_queue]; + if ((card->state != CARD_STATE_UP) || !card->lan_online) { card->stats.tx_carrier_errors++; goto tx_drop; @@ -757,7 +767,7 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) goto tx_drop; elements_needed++; skb_reset_mac_header(new_skb); - qeth_l2_fill_header(card, hdr, new_skb, ipv, cast_type); + qeth_l2_fill_header(card, hdr, new_skb, cast_type); hdr->hdr.l2.pkt_length = new_skb->len; memcpy(((char *)hdr) + sizeof(struct qeth_hdr), skb_mac_header(new_skb), ETH_HLEN); @@ -770,7 +780,7 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) hdr = (struct qeth_hdr *)skb_push(new_skb, sizeof(struct qeth_hdr)); skb_set_mac_header(new_skb, sizeof(struct qeth_hdr)); - qeth_l2_fill_header(card, hdr, new_skb, ipv, cast_type); + qeth_l2_fill_header(card, hdr, new_skb, cast_type); } } @@ -959,10 +969,9 @@ static int qeth_l2_setup_netdev(struct qeth_card *card) card->dev->watchdog_timeo = QETH_TX_TIMEOUT; card->dev->mtu = card->info.initial_mtu; card->dev->netdev_ops = &qeth_l2_netdev_ops; - if (card->info.type != QETH_CARD_TYPE_OSN) - SET_ETHTOOL_OPS(card->dev, &qeth_l2_ethtool_ops); - else - SET_ETHTOOL_OPS(card->dev, &qeth_l2_osn_ops); + card->dev->ethtool_ops = + (card->info.type != QETH_CARD_TYPE_OSN) ? + &qeth_l2_ethtool_ops : &qeth_l2_osn_ops; card->dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER; card->info.broadcast_capable = 1; qeth_l2_request_initial_mac(card); @@ -989,6 +998,10 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode) rc = -ENODEV; goto out_remove; } + qeth_bridgeport_query_support(card); + if (card->options.sbp.supported_funcs) + dev_info(&card->gdev->dev, + "The device represents a HiperSockets Bridge Capable Port\n"); qeth_trace_features(card); if (!card->dev && qeth_l2_setup_netdev(card)) { @@ -1082,6 +1095,7 @@ out_remove: ccw_device_set_offline(CARD_DDEV(card)); ccw_device_set_offline(CARD_WDEV(card)); ccw_device_set_offline(CARD_RDEV(card)); + qdio_free(CARD_DDEV(card)); if (recover_flag == CARD_STATE_RECOVER) card->state = CARD_STATE_RECOVER; else @@ -1123,6 +1137,7 @@ static int __qeth_l2_set_offline(struct ccwgroup_device *cgdev, rc = (rc2) ? rc2 : rc3; if (rc) QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc); + qdio_free(CARD_DDEV(card)); if (recover_flag == CARD_STATE_UP) card->state = CARD_STATE_RECOVER; /* let user_space know that device is offline */ @@ -1185,6 +1200,7 @@ static void qeth_l2_shutdown(struct ccwgroup_device *gdev) qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM); qeth_qdio_clear_card(card, 0); qeth_clear_qdio_buffers(card); + qdio_free(CARD_DDEV(card)); } static int qeth_l2_pm_suspend(struct ccwgroup_device *gdev) @@ -1233,6 +1249,26 @@ out: return rc; } +/* Returns zero if the command is successfully "consumed" */ +static int qeth_l2_control_event(struct qeth_card *card, + struct qeth_ipa_cmd *cmd) +{ + switch (cmd->hdr.command) { + case IPA_CMD_SETBRIDGEPORT: + if (cmd->data.sbp.hdr.command_code == + IPA_SBP_BRIDGE_PORT_STATE_CHANGE) { + qeth_bridge_state_change(card, cmd); + return 0; + } else + return 1; + case IPA_CMD_ADDRESS_CHANGE_NOTIF: + qeth_bridge_host_event(card, cmd); + return 0; + default: + return 1; + } +} + struct qeth_discipline qeth_l2_discipline = { .start_poll = qeth_qdio_start_poll, .input_handler = (qdio_handler_t *) qeth_qdio_input_handler, @@ -1246,6 +1282,7 @@ struct qeth_discipline qeth_l2_discipline = { .freeze = qeth_l2_pm_suspend, .thaw = qeth_l2_pm_resume, .restore = qeth_l2_pm_resume, + .control_event_handler = qeth_l2_control_event, }; EXPORT_SYMBOL_GPL(qeth_l2_discipline); @@ -1463,7 +1500,8 @@ static void qeth_bridge_state_change_worker(struct work_struct *work) kfree(data); } -void qeth_bridge_state_change(struct qeth_card *card, struct qeth_ipa_cmd *cmd) +static void qeth_bridge_state_change(struct qeth_card *card, + struct qeth_ipa_cmd *cmd) { struct qeth_sbp_state_change *qports = &cmd->data.sbp.data.state_change; @@ -1488,7 +1526,6 @@ void qeth_bridge_state_change(struct qeth_card *card, struct qeth_ipa_cmd *cmd) sizeof(struct qeth_sbp_state_change) + extrasize); queue_work(qeth_wq, &data->worker); } -EXPORT_SYMBOL(qeth_bridge_state_change); struct qeth_bridge_host_data { struct work_struct worker; @@ -1528,7 +1565,8 @@ static void qeth_bridge_host_event_worker(struct work_struct *work) kfree(data); } -void qeth_bridge_host_event(struct qeth_card *card, struct qeth_ipa_cmd *cmd) +static void qeth_bridge_host_event(struct qeth_card *card, + struct qeth_ipa_cmd *cmd) { struct qeth_ipacmd_addr_change *hostevs = &cmd->data.addrchange; @@ -1560,7 +1598,6 @@ void qeth_bridge_host_event(struct qeth_card *card, struct qeth_ipa_cmd *cmd) sizeof(struct qeth_ipacmd_addr_change) + extrasize); queue_work(qeth_wq, &data->worker); } -EXPORT_SYMBOL(qeth_bridge_host_event); /* SETBRIDGEPORT support; sending commands */ @@ -1683,7 +1720,7 @@ static int qeth_bridgeport_query_support_cb(struct qeth_card *card, * Sets bitmask of supported setbridgeport subfunctions in the qeth_card * strucutre: card->options.sbp.supported_funcs. */ -void qeth_bridgeport_query_support(struct qeth_card *card) +static void qeth_bridgeport_query_support(struct qeth_card *card) { struct qeth_cmd_buffer *iob; struct qeth_ipa_cmd *cmd; @@ -1709,7 +1746,6 @@ void qeth_bridgeport_query_support(struct qeth_card *card) } card->options.sbp.supported_funcs = cbctl.data.supported; } -EXPORT_SYMBOL_GPL(qeth_bridgeport_query_support); static int qeth_bridgeport_query_ports_cb(struct qeth_card *card, struct qeth_reply *reply, unsigned long data) |
