Commit 0f9ad4e7 authored by David S. Miller's avatar David S. Miller

Merge branch 's390-qeth-next'

Julian Wiedmann says:

====================
s390/qeth: updates 2020-09-10

subject to positive review by the bridge maintainers on patch 5,
please apply the following patch series to netdev's net-next tree.

Alexandra adds BR_LEARNING_SYNC support to qeth. In addition to the
main qeth changes (controlling the feature, and raising switchdev
events), this also needs
- Patch 1 and 2 for some s390/cio infrastructure improvements
  (acked by Heiko to go in via net-next), and
- Patch 5 to introduce a new switchdev_notifier_type, so that a driver
  can clear all previously learned entries from the bridge FDB in case
  things go out-of-sync later on.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents afb83012 521c65b6
......@@ -238,7 +238,10 @@ extern void ccw_device_get_schid(struct ccw_device *, struct subchannel_id *);
struct channel_path_desc_fmt0 *ccw_device_get_chp_desc(struct ccw_device *, int);
u8 *ccw_device_get_util_str(struct ccw_device *cdev, int chp_idx);
int ccw_device_pnso(struct ccw_device *cdev,
struct chsc_pnso_area *pnso_area,
struct chsc_pnso_resume_token resume_token,
int cnc);
struct chsc_pnso_area *pnso_area, u8 oc,
struct chsc_pnso_resume_token resume_token, int cnc);
int ccw_device_get_cssid(struct ccw_device *cdev, u8 *cssid);
int ccw_device_get_iid(struct ccw_device *cdev, u8 *iid);
int ccw_device_get_chpid(struct ccw_device *cdev, int chp_idx, u8 *chpid);
int ccw_device_get_chid(struct ccw_device *cdev, int chp_idx, u16 *chid);
#endif /* _S390_CCWDEV_H_ */
......@@ -11,6 +11,13 @@
#include <uapi/asm/chsc.h>
/**
* Operation codes for CHSC PNSO:
* PNSO_OC_NET_BRIDGE_INFO - only addresses that are visible to a bridgeport
* PNSO_OC_NET_ADDR_INFO - all addresses
*/
#define PNSO_OC_NET_BRIDGE_INFO 0
#define PNSO_OC_NET_ADDR_INFO 3
/**
* struct chsc_pnso_naid_l2 - network address information descriptor
* @nit: Network interface token
......
......@@ -36,7 +36,9 @@ struct css_general_char {
u64 alt_ssi : 1; /* bit 108 */
u64 : 1;
u64 narf : 1; /* bit 110 */
u64 : 12;
u64 : 5;
u64 enarf: 1; /* bit 116 */
u64 : 6;
u64 util_str : 1;/* bit 123 */
} __packed;
......
......@@ -65,6 +65,8 @@ int chsc_error_from_response(int response)
case 0x0100:
case 0x0102:
return -ENOMEM;
case 0x0108: /* "HW limit exceeded" for the op 0x003d */
return -EUSERS;
default:
return -EIO;
}
......@@ -1114,7 +1116,7 @@ int chsc_enable_facility(int operation_code)
return ret;
}
int __init chsc_get_cssid(int idx)
int __init chsc_get_cssid_iid(int idx, u8 *cssid, u8 *iid)
{
struct {
struct chsc_header request;
......@@ -1125,7 +1127,8 @@ int __init chsc_get_cssid(int idx)
u32 reserved2[3];
struct {
u8 cssid;
u32 : 24;
u8 iid;
u32 : 16;
} list[0];
} *sdcal_area;
int ret;
......@@ -1151,8 +1154,10 @@ int __init chsc_get_cssid(int idx)
}
if ((addr_t) &sdcal_area->list[idx] <
(addr_t) &sdcal_area->response + sdcal_area->response.length)
ret = sdcal_area->list[idx].cssid;
(addr_t) &sdcal_area->response + sdcal_area->response.length) {
*cssid = sdcal_area->list[idx].cssid;
*iid = sdcal_area->list[idx].iid;
}
else
ret = -ENODEV;
exit:
......@@ -1340,6 +1345,7 @@ EXPORT_SYMBOL_GPL(chsc_scm_info);
* chsc_pnso() - Perform Network-Subchannel Operation
* @schid: id of the subchannel on which PNSO is performed
* @pnso_area: request and response block for the operation
* @oc: Operation Code
* @resume_token: resume token for multiblock response
* @cnc: Boolean change-notification control
*
......@@ -1347,10 +1353,8 @@ EXPORT_SYMBOL_GPL(chsc_scm_info);
*
* Returns 0 on success.
*/
int chsc_pnso(struct subchannel_id schid,
struct chsc_pnso_area *pnso_area,
struct chsc_pnso_resume_token resume_token,
int cnc)
int chsc_pnso(struct subchannel_id schid, struct chsc_pnso_area *pnso_area,
u8 oc, struct chsc_pnso_resume_token resume_token, int cnc)
{
memset(pnso_area, 0, sizeof(*pnso_area));
pnso_area->request.length = 0x0030;
......@@ -1359,7 +1363,7 @@ int chsc_pnso(struct subchannel_id schid,
pnso_area->ssid = schid.ssid;
pnso_area->sch = schid.sch_no;
pnso_area->cssid = schid.cssid;
pnso_area->oc = 0; /* Store-network-bridging-information list */
pnso_area->oc = oc;
pnso_area->resume_token = resume_token;
pnso_area->n = (cnc != 0);
if (chsc(pnso_area))
......
......@@ -205,12 +205,10 @@ struct chsc_scm_info {
int chsc_scm_info(struct chsc_scm_info *scm_area, u64 token);
int chsc_pnso(struct subchannel_id schid,
struct chsc_pnso_area *pnso_area,
struct chsc_pnso_resume_token resume_token,
int cnc);
int chsc_pnso(struct subchannel_id schid, struct chsc_pnso_area *pnso_area,
u8 oc, struct chsc_pnso_resume_token resume_token, int cnc);
int __init chsc_get_cssid(int idx);
int __init chsc_get_cssid_iid(int idx, u8 *cssid, u8 *iid);
#ifdef CONFIG_SCM_BUS
int scm_update_information(void);
......
......@@ -854,7 +854,7 @@ css_generate_pgid(struct channel_subsystem *css, u32 tod_high)
if (css_general_characteristics.mcss) {
css->global_pgid.pgid_high.ext_cssid.version = 0x80;
css->global_pgid.pgid_high.ext_cssid.cssid =
(css->cssid < 0) ? 0 : css->cssid;
css->id_valid ? css->cssid : 0;
} else {
css->global_pgid.pgid_high.cpu_addr = stap();
}
......@@ -877,7 +877,7 @@ static ssize_t real_cssid_show(struct device *dev, struct device_attribute *a,
{
struct channel_subsystem *css = to_css(dev);
if (css->cssid < 0)
if (!css->id_valid)
return -EINVAL;
return sprintf(buf, "%x\n", css->cssid);
......@@ -975,7 +975,12 @@ static int __init setup_css(int nr)
css->device.dma_mask = &css->device.coherent_dma_mask;
mutex_init(&css->mutex);
css->cssid = chsc_get_cssid(nr);
ret = chsc_get_cssid_iid(nr, &css->cssid, &css->iid);
if (!ret) {
css->id_valid = true;
pr_info("Partition identifier %01x.%01x\n", css->cssid,
css->iid);
}
css_generate_pgid(css, (u32) (get_tod_clock() >> 32));
ret = device_register(&css->device);
......
......@@ -115,7 +115,9 @@ extern int for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *);
void css_update_ssd_info(struct subchannel *sch);
struct channel_subsystem {
int cssid;
u8 cssid;
u8 iid;
bool id_valid; /* cssid,iid */
struct channel_path *chps[__MAX_CHPID + 1];
struct device device;
struct pgid global_pgid;
......
......@@ -714,6 +714,7 @@ EXPORT_SYMBOL_GPL(ccw_device_get_schid);
* ccw_device_pnso() - Perform Network-Subchannel Operation
* @cdev: device on which PNSO is performed
* @pnso_area: request and response block for the operation
* @oc: Operation Code
* @resume_token: resume token for multiblock response
* @cnc: Boolean change-notification control
*
......@@ -722,17 +723,101 @@ EXPORT_SYMBOL_GPL(ccw_device_get_schid);
* Returns 0 on success.
*/
int ccw_device_pnso(struct ccw_device *cdev,
struct chsc_pnso_area *pnso_area,
struct chsc_pnso_resume_token resume_token,
int cnc)
struct chsc_pnso_area *pnso_area, u8 oc,
struct chsc_pnso_resume_token resume_token, int cnc)
{
struct subchannel_id schid;
ccw_device_get_schid(cdev, &schid);
return chsc_pnso(schid, pnso_area, resume_token, cnc);
return chsc_pnso(schid, pnso_area, oc, resume_token, cnc);
}
EXPORT_SYMBOL_GPL(ccw_device_pnso);
/**
* ccw_device_get_cssid() - obtain Channel Subsystem ID
* @cdev: device to obtain the CSSID for
* @cssid: The resulting Channel Subsystem ID
*/
int ccw_device_get_cssid(struct ccw_device *cdev, u8 *cssid)
{
struct device *sch_dev = cdev->dev.parent;
struct channel_subsystem *css = to_css(sch_dev->parent);
if (css->id_valid)
*cssid = css->cssid;
return css->id_valid ? 0 : -ENODEV;
}
EXPORT_SYMBOL_GPL(ccw_device_get_cssid);
/**
* ccw_device_get_iid() - obtain MIF-image ID
* @cdev: device to obtain the MIF-image ID for
* @iid: The resulting MIF-image ID
*/
int ccw_device_get_iid(struct ccw_device *cdev, u8 *iid)
{
struct device *sch_dev = cdev->dev.parent;
struct channel_subsystem *css = to_css(sch_dev->parent);
if (css->id_valid)
*iid = css->iid;
return css->id_valid ? 0 : -ENODEV;
}
EXPORT_SYMBOL_GPL(ccw_device_get_iid);
/**
* ccw_device_get_chpid() - obtain Channel Path ID
* @cdev: device to obtain the Channel Path ID for
* @chp_idx: Index of the channel path
* @chpid: The resulting Channel Path ID
*/
int ccw_device_get_chpid(struct ccw_device *cdev, int chp_idx, u8 *chpid)
{
struct subchannel *sch = to_subchannel(cdev->dev.parent);
int mask;
if ((chp_idx < 0) || (chp_idx > 7))
return -EINVAL;
mask = 0x80 >> chp_idx;
if (!(sch->schib.pmcw.pim & mask))
return -ENODEV;
*chpid = sch->schib.pmcw.chpid[chp_idx];
return 0;
}
EXPORT_SYMBOL_GPL(ccw_device_get_chpid);
/**
* ccw_device_get_chid() - obtain Channel ID associated with specified CHPID
* @cdev: device to obtain the Channel ID for
* @chp_idx: Index of the channel path
* @chid: The resulting Channel ID
*/
int ccw_device_get_chid(struct ccw_device *cdev, int chp_idx, u16 *chid)
{
struct chp_id cssid_chpid;
struct channel_path *chp;
int rc;
chp_id_init(&cssid_chpid);
rc = ccw_device_get_chpid(cdev, chp_idx, &cssid_chpid.id);
if (rc)
return rc;
chp = chpid_to_chp(cssid_chpid);
if (!chp)
return -ENODEV;
mutex_lock(&chp->lock);
if (chp->desc_fmt1.flags & 0x10)
*chid = chp->desc_fmt1.chid;
else
rc = -ENODEV;
mutex_unlock(&chp->lock);
return rc;
}
EXPORT_SYMBOL_GPL(ccw_device_get_chid);
/*
* Allocate zeroed dma coherent 31 bit addressable memory using
* the subchannels dma pool. Maximal size of allocation supported
......
......@@ -677,6 +677,7 @@ struct qeth_card_blkt {
enum qeth_pnso_mode {
QETH_PNSO_NONE,
QETH_PNSO_BRIDGEPORT,
QETH_PNSO_ADDR_INFO,
};
#define QETH_BROADCAST_WITH_ECHO 0x01
......@@ -684,9 +685,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 +788,8 @@ struct qeth_switch_info {
struct qeth_priv {
unsigned int rx_copybreak;
u32 brport_hw_features;
u32 brport_features;
};
#define QETH_NAPI_WEIGHT NAPI_POLL_WEIGHT
......
......@@ -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 @@ static void qeth_determine_capabilities(struct qeth_card *card)
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 @@ int qeth_core_hardsetup_card(struct qeth_card *card, bool *carrier_ok)
}
qeth_determine_capabilities(card);
qeth_read_ccw_conf_data(card);
qeth_idx_init(card);
rc = qeth_idx_activate_read_channel(card);
......
......@@ -23,7 +23,7 @@ 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);
bool qeth_bridgeport_allowed(struct qeth_card *card);
struct qeth_mac {
u8 mac_addr[ETH_ALEN];
......
This diff is collapsed.
......@@ -18,7 +18,7 @@ static ssize_t qeth_bridge_port_role_state_show(struct device *dev,
int rc = 0;
char *word;
if (qeth_l2_vnicc_is_in_use(card))
if (!qeth_bridgeport_allowed(card))
return sprintf(buf, "n/a (VNIC characteristics)\n");
mutex_lock(&card->sbp_lock);
......@@ -65,7 +65,7 @@ static ssize_t qeth_bridge_port_role_show(struct device *dev,
{
struct qeth_card *card = dev_get_drvdata(dev);
if (qeth_l2_vnicc_is_in_use(card))
if (!qeth_bridgeport_allowed(card))
return sprintf(buf, "n/a (VNIC characteristics)\n");
return qeth_bridge_port_role_state_show(dev, attr, buf, 0);
......@@ -90,7 +90,7 @@ static ssize_t qeth_bridge_port_role_store(struct device *dev,
mutex_lock(&card->conf_mutex);
mutex_lock(&card->sbp_lock);
if (qeth_l2_vnicc_is_in_use(card))
if (!qeth_bridgeport_allowed(card))
rc = -EBUSY;
else if (card->options.sbp.reflect_promisc)
/* Forbid direct manipulation */
......@@ -116,7 +116,7 @@ static ssize_t qeth_bridge_port_state_show(struct device *dev,
{
struct qeth_card *card = dev_get_drvdata(dev);
if (qeth_l2_vnicc_is_in_use(card))
if (!qeth_bridgeport_allowed(card))
return sprintf(buf, "n/a (VNIC characteristics)\n");
return qeth_bridge_port_role_state_show(dev, attr, buf, 1);
......@@ -131,7 +131,7 @@ static ssize_t qeth_bridgeport_hostnotification_show(struct device *dev,
struct qeth_card *card = dev_get_drvdata(dev);
int enabled;
if (qeth_l2_vnicc_is_in_use(card))
if (!qeth_bridgeport_allowed(card))
return sprintf(buf, "n/a (VNIC characteristics)\n");
enabled = card->options.sbp.hostnotification;
......@@ -153,7 +153,7 @@ static ssize_t qeth_bridgeport_hostnotification_store(struct device *dev,
mutex_lock(&card->conf_mutex);
mutex_lock(&card->sbp_lock);
if (qeth_l2_vnicc_is_in_use(card))
if (!qeth_bridgeport_allowed(card))
rc = -EBUSY;
else if (qeth_card_hw_is_reachable(card)) {
rc = qeth_bridgeport_an_set(card, enable);
......@@ -179,7 +179,7 @@ static ssize_t qeth_bridgeport_reflect_show(struct device *dev,
struct qeth_card *card = dev_get_drvdata(dev);
char *state;
if (qeth_l2_vnicc_is_in_use(card))
if (!qeth_bridgeport_allowed(card))
return sprintf(buf, "n/a (VNIC characteristics)\n");
if (card->options.sbp.reflect_promisc) {
......@@ -215,7 +215,7 @@ static ssize_t qeth_bridgeport_reflect_store(struct device *dev,
mutex_lock(&card->conf_mutex);
mutex_lock(&card->sbp_lock);
if (qeth_l2_vnicc_is_in_use(card))
if (!qeth_bridgeport_allowed(card))
rc = -EBUSY;
else if (card->options.sbp.role != QETH_SBP_ROLE_NONE)
rc = -EPERM;
......
......@@ -203,6 +203,7 @@ enum switchdev_notifier_type {
SWITCHDEV_FDB_ADD_TO_DEVICE,
SWITCHDEV_FDB_DEL_TO_DEVICE,
SWITCHDEV_FDB_OFFLOADED,
SWITCHDEV_FDB_FLUSH_TO_BRIDGE,
SWITCHDEV_PORT_OBJ_ADD, /* Blocking. */
SWITCHDEV_PORT_OBJ_DEL, /* Blocking. */
......
......@@ -183,6 +183,11 @@ static int br_switchdev_event(struct notifier_block *unused,
br_fdb_offloaded_set(br, p, fdb_info->addr,
fdb_info->vid, fdb_info->offloaded);
break;
case SWITCHDEV_FDB_FLUSH_TO_BRIDGE:
fdb_info = ptr;
/* Don't delete static entries */
br_fdb_delete_by_port(br, p, fdb_info->vid, 0);
break;
}
out:
......
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