Commit fa115adf authored by Alexandra Winter's avatar Alexandra Winter Committed by David S. Miller

s390/qeth: Detect PNSO OC3 capability

This patch detects whether device-to-bridge-notification, provided
by the Perform Network Subchannel Operation (PNSO) operation code
ADDR_INFO (OC3), is supported by this card. A following patch will
map this to the learning_sync bridgeport flag, so we store it in
priv->brport_hw_features in bridgeport flag format.

Only IQD cards provide PNSO.
There is a feature bit to indicate whether the machine provides OC3,
unfortunately it is not set on old machines.
So PNSO is called to find out. As this will disable notification
and is exclusive with bridgeport_notification, this must be done
during card initialisation before previous settings are restored.

PNSO functionality requires some configuration values that are added to
the qeth_card.info structure. Some helper functions are defined to fill
them out when the card is brought online and some other places are
adapted, that can also benefit from these fields.
Signed-off-by: default avatarAlexandra Winter <wintera@linux.ibm.com>
Reviewed-by: default avatarJulian Wiedmann <jwi@linux.ibm.com>
Signed-off-by: default avatarJulian Wiedmann <jwi@linux.ibm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b983aa1f
...@@ -684,9 +684,16 @@ enum qeth_pnso_mode { ...@@ -684,9 +684,16 @@ enum qeth_pnso_mode {
struct qeth_card_info { struct qeth_card_info {
unsigned short unit_addr2; unsigned short unit_addr2;
unsigned short cula; unsigned short cula;
u8 chpid;
__u16 func_level; __u16 func_level;
char mcl_level[QETH_MCL_LENGTH + 1]; 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 dev_addr_is_registered:1;
u8 open_when_online:1; u8 open_when_online:1;
u8 promisc_mode:1; u8 promisc_mode:1;
...@@ -780,6 +787,7 @@ struct qeth_switch_info { ...@@ -780,6 +787,7 @@ struct qeth_switch_info {
struct qeth_priv { struct qeth_priv {
unsigned int rx_copybreak; unsigned int rx_copybreak;
u32 brport_hw_features;
}; };
#define QETH_NAPI_WEIGHT NAPI_POLL_WEIGHT #define QETH_NAPI_WEIGHT NAPI_POLL_WEIGHT
......
...@@ -2311,12 +2311,10 @@ static void qeth_idx_setup_activate_cmd(struct qeth_card *card, ...@@ -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; u16 addr = (card->info.cula << 8) + card->info.unit_addr2;
u8 port = ((u8)card->dev->dev_port) | 0x80; u8 port = ((u8)card->dev->dev_port) | 0x80;
struct ccw1 *ccw = __ccw_from_cmd(iob); 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, qeth_setup_ccw(&ccw[0], CCW_CMD_WRITE, CCW_FLAG_CC, IDX_ACTIVATE_SIZE,
iob->data); iob->data);
qeth_setup_ccw(&ccw[1], CCW_CMD_READ, 0, iob->length, 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; iob->finalize = qeth_idx_finalize_cmd;
port |= QETH_IDX_ACT_INVAL_FRAME; port |= QETH_IDX_ACT_INVAL_FRAME;
...@@ -2325,7 +2323,7 @@ static void qeth_idx_setup_activate_cmd(struct qeth_card *card, ...@@ -2325,7 +2323,7 @@ static void qeth_idx_setup_activate_cmd(struct qeth_card *card,
&card->token.issuer_rm_w, QETH_MPC_TOKEN_LENGTH); &card->token.issuer_rm_w, QETH_MPC_TOKEN_LENGTH);
memcpy(QETH_IDX_ACT_FUNC_LEVEL(iob->data), memcpy(QETH_IDX_ACT_FUNC_LEVEL(iob->data),
&card->info.func_level, 2); &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); memcpy(QETH_IDX_ACT_QDIO_DEV_REALADDR(iob->data), &addr, 2);
} }
...@@ -2599,7 +2597,6 @@ static int qeth_ulp_setup(struct qeth_card *card) ...@@ -2599,7 +2597,6 @@ static int qeth_ulp_setup(struct qeth_card *card)
{ {
__u16 temp; __u16 temp;
struct qeth_cmd_buffer *iob; struct qeth_cmd_buffer *iob;
struct ccw_dev_id dev_id;
QETH_CARD_TEXT(card, 2, "ulpsetup"); QETH_CARD_TEXT(card, 2, "ulpsetup");
...@@ -2614,8 +2611,7 @@ static int qeth_ulp_setup(struct qeth_card *card) ...@@ -2614,8 +2611,7 @@ static int qeth_ulp_setup(struct qeth_card *card)
memcpy(QETH_ULP_SETUP_FILTER_TOKEN(iob->data), memcpy(QETH_ULP_SETUP_FILTER_TOKEN(iob->data),
&card->token.ulp_filter_r, QETH_MPC_TOKEN_LENGTH); &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), &card->info.ddev_devno, 2);
memcpy(QETH_ULP_SETUP_CUA(iob->data), &dev_id.devno, 2);
temp = (card->info.cula << 8) + card->info.unit_addr2; temp = (card->info.cula << 8) + card->info.unit_addr2;
memcpy(QETH_ULP_SETUP_REAL_DEVADDR(iob->data), &temp, 2); memcpy(QETH_ULP_SETUP_REAL_DEVADDR(iob->data), &temp, 2);
return qeth_send_control_data(card, iob, qeth_ulp_setup_cb, NULL); 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) ...@@ -4920,7 +4916,6 @@ int qeth_vm_request_mac(struct qeth_card *card)
{ {
struct diag26c_mac_resp *response; struct diag26c_mac_resp *response;
struct diag26c_mac_req *request; struct diag26c_mac_req *request;
struct ccw_dev_id id;
int rc; int rc;
QETH_CARD_TEXT(card, 2, "vmreqmac"); QETH_CARD_TEXT(card, 2, "vmreqmac");
...@@ -4932,11 +4927,10 @@ int qeth_vm_request_mac(struct qeth_card *card) ...@@ -4932,11 +4927,10 @@ int qeth_vm_request_mac(struct qeth_card *card)
goto out; goto out;
} }
ccw_device_get_id(CARD_DDEV(card), &id);
request->resp_buf_len = sizeof(*response); request->resp_buf_len = sizeof(*response);
request->resp_version = DIAG26C_VERSION2; request->resp_version = DIAG26C_VERSION2;
request->op_code = DIAG26C_GET_MAC; request->op_code = DIAG26C_GET_MAC;
request->devno = id.devno; request->devno = card->info.ddev_devno;
QETH_DBF_HEX(CTRL, 2, request, sizeof(*request)); QETH_DBF_HEX(CTRL, 2, request, sizeof(*request));
rc = diag26c(request, response, DIAG26C_MAC_SERVICES); rc = diag26c(request, response, DIAG26C_MAC_SERVICES);
...@@ -5017,6 +5011,33 @@ static void qeth_determine_capabilities(struct qeth_card *card) ...@@ -5017,6 +5011,33 @@ static void qeth_determine_capabilities(struct qeth_card *card)
return; 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) static int qeth_qdio_establish(struct qeth_card *card)
{ {
struct qdio_buffer **out_sbal_ptrs[QETH_MAX_OUT_QUEUES]; struct qdio_buffer **out_sbal_ptrs[QETH_MAX_OUT_QUEUES];
...@@ -5185,6 +5206,7 @@ int qeth_core_hardsetup_card(struct qeth_card *card, bool *carrier_ok) ...@@ -5185,6 +5206,7 @@ int qeth_core_hardsetup_card(struct qeth_card *card, bool *carrier_ok)
} }
qeth_determine_capabilities(card); qeth_determine_capabilities(card);
qeth_read_ccw_conf_data(card);
qeth_idx_init(card); qeth_idx_init(card);
rc = qeth_idx_activate_read_channel(card); rc = qeth_idx_activate_read_channel(card);
......
...@@ -17,10 +17,12 @@ ...@@ -17,10 +17,12 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/if_bridge.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/hash.h> #include <linux/hash.h>
#include <linux/hashtable.h> #include <linux/hashtable.h>
#include <asm/chsc.h> #include <asm/chsc.h>
#include <asm/css_chars.h>
#include <asm/setup.h> #include <asm/setup.h>
#include "qeth_core.h" #include "qeth_core.h"
#include "qeth_l2.h" #include "qeth_l2.h"
...@@ -826,6 +828,46 @@ static void qeth_l2_setup_bridgeport_attrs(struct qeth_card *card) ...@@ -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) static int qeth_l2_set_online(struct qeth_card *card)
{ {
struct ccwgroup_device *gdev = card->gdev; struct ccwgroup_device *gdev = card->gdev;
...@@ -840,6 +882,9 @@ static int qeth_l2_set_online(struct qeth_card *card) ...@@ -840,6 +882,9 @@ static int qeth_l2_set_online(struct qeth_card *card)
goto out_remove; goto out_remove;
} }
/* query before bridgeport_notification may be enabled */
qeth_l2_detect_dev2br_support(card);
mutex_lock(&card->sbp_lock); mutex_lock(&card->sbp_lock);
qeth_bridgeport_query_support(card); qeth_bridgeport_query_support(card);
if (card->options.sbp.supported_funcs) { if (card->options.sbp.supported_funcs) {
......
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