diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index da46af682af8..14c583b5ea11 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -684,9 +684,16 @@ enum qeth_pnso_mode { struct qeth_card_info { unsigned short unit_addr2; unsigned short cula; - u8 chpid; __u16 func_level; char mcl_level[QETH_MCL_LENGTH + 1]; + /* doubleword below corresponds to net_if_token */ + u16 ddev_devno; + u8 cssid; + u8 iid; + u8 ssid; + u8 chpid; + u16 chid; + u8 ids_valid:1; /* cssid,iid,chid */ u8 dev_addr_is_registered:1; u8 open_when_online:1; u8 promisc_mode:1; @@ -780,6 +787,7 @@ struct qeth_switch_info { struct qeth_priv { unsigned int rx_copybreak; + u32 brport_hw_features; }; #define QETH_NAPI_WEIGHT NAPI_POLL_WEIGHT diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index e19640bc6daa..7cd0cbf8a4f0 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -2311,12 +2311,10 @@ static void qeth_idx_setup_activate_cmd(struct qeth_card *card, u16 addr = (card->info.cula << 8) + card->info.unit_addr2; u8 port = ((u8)card->dev->dev_port) | 0x80; struct ccw1 *ccw = __ccw_from_cmd(iob); - struct ccw_dev_id dev_id; qeth_setup_ccw(&ccw[0], CCW_CMD_WRITE, CCW_FLAG_CC, IDX_ACTIVATE_SIZE, iob->data); qeth_setup_ccw(&ccw[1], CCW_CMD_READ, 0, iob->length, iob->data); - ccw_device_get_id(CARD_DDEV(card), &dev_id); iob->finalize = qeth_idx_finalize_cmd; port |= QETH_IDX_ACT_INVAL_FRAME; @@ -2325,7 +2323,7 @@ static void qeth_idx_setup_activate_cmd(struct qeth_card *card, &card->token.issuer_rm_w, QETH_MPC_TOKEN_LENGTH); memcpy(QETH_IDX_ACT_FUNC_LEVEL(iob->data), &card->info.func_level, 2); - memcpy(QETH_IDX_ACT_QDIO_DEV_CUA(iob->data), &dev_id.devno, 2); + memcpy(QETH_IDX_ACT_QDIO_DEV_CUA(iob->data), &card->info.ddev_devno, 2); memcpy(QETH_IDX_ACT_QDIO_DEV_REALADDR(iob->data), &addr, 2); } @@ -2599,7 +2597,6 @@ static int qeth_ulp_setup(struct qeth_card *card) { __u16 temp; struct qeth_cmd_buffer *iob; - struct ccw_dev_id dev_id; QETH_CARD_TEXT(card, 2, "ulpsetup"); @@ -2614,8 +2611,7 @@ static int qeth_ulp_setup(struct qeth_card *card) memcpy(QETH_ULP_SETUP_FILTER_TOKEN(iob->data), &card->token.ulp_filter_r, QETH_MPC_TOKEN_LENGTH); - ccw_device_get_id(CARD_DDEV(card), &dev_id); - memcpy(QETH_ULP_SETUP_CUA(iob->data), &dev_id.devno, 2); + memcpy(QETH_ULP_SETUP_CUA(iob->data), &card->info.ddev_devno, 2); temp = (card->info.cula << 8) + card->info.unit_addr2; memcpy(QETH_ULP_SETUP_REAL_DEVADDR(iob->data), &temp, 2); return qeth_send_control_data(card, iob, qeth_ulp_setup_cb, NULL); @@ -4920,7 +4916,6 @@ int qeth_vm_request_mac(struct qeth_card *card) { struct diag26c_mac_resp *response; struct diag26c_mac_req *request; - struct ccw_dev_id id; int rc; QETH_CARD_TEXT(card, 2, "vmreqmac"); @@ -4932,11 +4927,10 @@ int qeth_vm_request_mac(struct qeth_card *card) goto out; } - ccw_device_get_id(CARD_DDEV(card), &id); request->resp_buf_len = sizeof(*response); request->resp_version = DIAG26C_VERSION2; request->op_code = DIAG26C_GET_MAC; - request->devno = id.devno; + request->devno = card->info.ddev_devno; QETH_DBF_HEX(CTRL, 2, request, sizeof(*request)); rc = diag26c(request, response, DIAG26C_MAC_SERVICES); @@ -5017,6 +5011,33 @@ out: return; } +static void qeth_read_ccw_conf_data(struct qeth_card *card) +{ + struct qeth_card_info *info = &card->info; + struct ccw_device *cdev = CARD_DDEV(card); + struct ccw_dev_id dev_id; + + QETH_CARD_TEXT(card, 2, "ccwconfd"); + ccw_device_get_id(cdev, &dev_id); + + info->ddev_devno = dev_id.devno; + info->ids_valid = !ccw_device_get_cssid(cdev, &info->cssid) && + !ccw_device_get_iid(cdev, &info->iid) && + !ccw_device_get_chid(cdev, 0, &info->chid); + info->ssid = dev_id.ssid; + + dev_info(&card->gdev->dev, "CHID: %x CHPID: %x\n", + info->chid, info->chpid); + + QETH_CARD_TEXT_(card, 3, "devn%x", info->ddev_devno); + QETH_CARD_TEXT_(card, 3, "cssid:%x", info->cssid); + QETH_CARD_TEXT_(card, 3, "iid:%x", info->iid); + QETH_CARD_TEXT_(card, 3, "ssid:%x", info->ssid); + QETH_CARD_TEXT_(card, 3, "chpid:%x", info->chpid); + QETH_CARD_TEXT_(card, 3, "chid:%x", info->chid); + QETH_CARD_TEXT_(card, 3, "idval%x", info->ids_valid); +} + static int qeth_qdio_establish(struct qeth_card *card) { struct qdio_buffer **out_sbal_ptrs[QETH_MAX_OUT_QUEUES]; @@ -5185,6 +5206,7 @@ retriable: } qeth_determine_capabilities(card); + qeth_read_ccw_conf_data(card); qeth_idx_init(card); rc = qeth_idx_activate_read_channel(card); diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 2ab130d5c42d..7cba3d0035bf 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -17,10 +17,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include "qeth_core.h" #include "qeth_l2.h" @@ -826,6 +828,46 @@ static void qeth_l2_setup_bridgeport_attrs(struct qeth_card *card) } } +/** + * qeth_l2_detect_dev2br_support() - + * Detect whether this card supports 'dev to bridge fdb network address + * change notification' and thus can support the learning_sync bridgeport + * attribute + * @card: qeth_card structure pointer + * + * This is a destructive test and must be called before dev2br or + * bridgeport address notification is enabled! + */ +static void qeth_l2_detect_dev2br_support(struct qeth_card *card) +{ + struct qeth_priv *priv = netdev_priv(card->dev); + bool dev2br_supported; + int rc; + + QETH_CARD_TEXT(card, 2, "d2brsup"); + if (!IS_IQD(card)) + return; + + /* dev2br requires valid cssid,iid,chid */ + if (!card->info.ids_valid) { + dev2br_supported = false; + } else if (css_general_characteristics.enarf) { + dev2br_supported = true; + } else { + /* Old machines don't have the feature bit: + * Probe by testing whether a disable succeeds + */ + rc = qeth_l2_pnso(card, PNSO_OC_NET_ADDR_INFO, 0, NULL, NULL); + dev2br_supported = !rc; + } + QETH_CARD_TEXT_(card, 2, "D2Bsup%02x", dev2br_supported); + + if (dev2br_supported) + priv->brport_hw_features |= BR_LEARNING_SYNC; + else + priv->brport_hw_features &= ~BR_LEARNING_SYNC; +} + static int qeth_l2_set_online(struct qeth_card *card) { struct ccwgroup_device *gdev = card->gdev; @@ -840,6 +882,9 @@ static int qeth_l2_set_online(struct qeth_card *card) goto out_remove; } + /* query before bridgeport_notification may be enabled */ + qeth_l2_detect_dev2br_support(card); + mutex_lock(&card->sbp_lock); qeth_bridgeport_query_support(card); if (card->options.sbp.supported_funcs) {