lkml.org 
[lkml]   [2017]   [Jun]   [5]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.4 05/53] s390/qeth: unbreak OSM and OSN support
    Date
    4.4-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Julian Wiedmann <jwi@linux.vnet.ibm.com>


    [ Upstream commit 2d2ebb3ed0c6acfb014f98e427298673a5d07b82 ]

    commit b4d72c08b358 ("qeth: bridgeport support - basic control")
    broke the support for OSM and OSN devices as follows:

    As OSM and OSN are L2 only, qeth_core_probe_device() does an early
    setup by loading the l2 discipline and calling qeth_l2_probe_device().
    In this context, adding the l2-specific bridgeport sysfs attributes
    via qeth_l2_create_device_attributes() hits a BUG_ON in fs/sysfs/group.c,
    since the basic sysfs infrastructure for the device hasn't been
    established yet.

    Note that OSN actually has its own unique sysfs attributes
    (qeth_osn_devtype), so the additional attributes shouldn't be created
    at all.
    For OSM, add a new qeth_l2_devtype that contains all the common
    and l2-specific sysfs attributes.
    When qeth_core_probe_device() does early setup for OSM or OSN, assign
    the corresponding devtype so that the ccwgroup probe code creates the
    full set of sysfs attributes.
    This allows us to skip qeth_l2_create_device_attributes() in case
    of an early setup.

    Any device that can't do early setup will initially have only the
    generic sysfs attributes, and when it's probed later
    qeth_l2_probe_device() adds the l2-specific attributes.

    If an early-setup device is removed (by calling ccwgroup_ungroup()),
    device_unregister() will - using the devtype - delete the
    l2-specific attributes before qeth_l2_remove_device() is called.
    So make sure to not remove them twice.

    What complicates the issue is that qeth_l2_probe_device() and
    qeth_l2_remove_device() is also called on a device when its
    layer2 attribute changes (ie. its layer mode is switched).
    For early-setup devices this wouldn't work properly - we wouldn't
    remove the l2-specific attributes when switching to L3.
    But switching the layer mode doesn't actually make any sense;
    we already decided that the device can only operate in L2!
    So just refuse to switch the layer mode on such devices. Note that
    OSN doesn't have a layer2 attribute, so we only need to special-case
    OSM.

    Based on an initial patch by Ursula Braun.

    Fixes: b4d72c08b358 ("qeth: bridgeport support - basic control")
    Signed-off-by: Julian Wiedmann <jwi@linux.vnet.ibm.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    ---
    drivers/s390/net/qeth_core.h | 4 ++++
    drivers/s390/net/qeth_core_main.c | 17 +++++++++--------
    drivers/s390/net/qeth_core_sys.c | 22 ++++++++++++++--------
    drivers/s390/net/qeth_l2.h | 2 ++
    drivers/s390/net/qeth_l2_main.c | 17 +++++++++++++----
    drivers/s390/net/qeth_l2_sys.c | 8 ++++++++
    drivers/s390/net/qeth_l3_main.c | 1 +
    7 files changed, 51 insertions(+), 20 deletions(-)

    --- a/drivers/s390/net/qeth_core.h
    +++ b/drivers/s390/net/qeth_core.h
    @@ -717,6 +717,7 @@ enum qeth_discipline_id {
    };

    struct qeth_discipline {
    + const struct device_type *devtype;
    void (*start_poll)(struct ccw_device *, int, unsigned long);
    qdio_handler_t *input_handler;
    qdio_handler_t *output_handler;
    @@ -881,6 +882,9 @@ extern struct qeth_discipline qeth_l2_di
    extern struct qeth_discipline qeth_l3_discipline;
    extern const struct attribute_group *qeth_generic_attr_groups[];
    extern const struct attribute_group *qeth_osn_attr_groups[];
    +extern const struct attribute_group qeth_device_attr_group;
    +extern const struct attribute_group qeth_device_blkt_group;
    +extern const struct device_type qeth_generic_devtype;
    extern struct workqueue_struct *qeth_wq;

    int qeth_card_hw_is_reachable(struct qeth_card *);
    --- a/drivers/s390/net/qeth_core_main.c
    +++ b/drivers/s390/net/qeth_core_main.c
    @@ -5449,10 +5449,12 @@ void qeth_core_free_discipline(struct qe
    card->discipline = NULL;
    }

    -static const struct device_type qeth_generic_devtype = {
    +const struct device_type qeth_generic_devtype = {
    .name = "qeth_generic",
    .groups = qeth_generic_attr_groups,
    };
    +EXPORT_SYMBOL_GPL(qeth_generic_devtype);
    +
    static const struct device_type qeth_osn_devtype = {
    .name = "qeth_osn",
    .groups = qeth_osn_attr_groups,
    @@ -5578,23 +5580,22 @@ static int qeth_core_probe_device(struct
    goto err_card;
    }

    - if (card->info.type == QETH_CARD_TYPE_OSN)
    - gdev->dev.type = &qeth_osn_devtype;
    - else
    - gdev->dev.type = &qeth_generic_devtype;
    -
    switch (card->info.type) {
    case QETH_CARD_TYPE_OSN:
    case QETH_CARD_TYPE_OSM:
    rc = qeth_core_load_discipline(card, QETH_DISCIPLINE_LAYER2);
    if (rc)
    goto err_card;
    +
    + gdev->dev.type = (card->info.type != QETH_CARD_TYPE_OSN)
    + ? card->discipline->devtype
    + : &qeth_osn_devtype;
    rc = card->discipline->setup(card->gdev);
    if (rc)
    goto err_disc;
    - case QETH_CARD_TYPE_OSD:
    - case QETH_CARD_TYPE_OSX:
    + break;
    default:
    + gdev->dev.type = &qeth_generic_devtype;
    break;
    }

    --- a/drivers/s390/net/qeth_core_sys.c
    +++ b/drivers/s390/net/qeth_core_sys.c
    @@ -409,12 +409,16 @@ static ssize_t qeth_dev_layer2_store(str

    if (card->options.layer2 == newdis)
    goto out;
    - else {
    - card->info.mac_bits = 0;
    - if (card->discipline) {
    - card->discipline->remove(card->gdev);
    - qeth_core_free_discipline(card);
    - }
    + if (card->info.type == QETH_CARD_TYPE_OSM) {
    + /* fixed layer, can't switch */
    + rc = -EOPNOTSUPP;
    + goto out;
    + }
    +
    + card->info.mac_bits = 0;
    + if (card->discipline) {
    + card->discipline->remove(card->gdev);
    + qeth_core_free_discipline(card);
    }

    rc = qeth_core_load_discipline(card, newdis);
    @@ -701,10 +705,11 @@ static struct attribute *qeth_blkt_devic
    &dev_attr_inter_jumbo.attr,
    NULL,
    };
    -static struct attribute_group qeth_device_blkt_group = {
    +const struct attribute_group qeth_device_blkt_group = {
    .name = "blkt",
    .attrs = qeth_blkt_device_attrs,
    };
    +EXPORT_SYMBOL_GPL(qeth_device_blkt_group);

    static struct attribute *qeth_device_attrs[] = {
    &dev_attr_state.attr,
    @@ -724,9 +729,10 @@ static struct attribute *qeth_device_att
    &dev_attr_switch_attrs.attr,
    NULL,
    };
    -static struct attribute_group qeth_device_attr_group = {
    +const struct attribute_group qeth_device_attr_group = {
    .attrs = qeth_device_attrs,
    };
    +EXPORT_SYMBOL_GPL(qeth_device_attr_group);

    const struct attribute_group *qeth_generic_attr_groups[] = {
    &qeth_device_attr_group,
    --- a/drivers/s390/net/qeth_l2.h
    +++ b/drivers/s390/net/qeth_l2.h
    @@ -8,6 +8,8 @@

    #include "qeth_core.h"

    +extern const struct attribute_group *qeth_l2_attr_groups[];
    +
    int qeth_l2_create_device_attributes(struct device *);
    void qeth_l2_remove_device_attributes(struct device *);
    void qeth_l2_setup_bridgeport_attrs(struct qeth_card *card);
    --- a/drivers/s390/net/qeth_l2_main.c
    +++ b/drivers/s390/net/qeth_l2_main.c
    @@ -1027,14 +1027,21 @@ static int qeth_l2_stop(struct net_devic
    return 0;
    }

    +static const struct device_type qeth_l2_devtype = {
    + .name = "qeth_layer2",
    + .groups = qeth_l2_attr_groups,
    +};
    +
    static int qeth_l2_probe_device(struct ccwgroup_device *gdev)
    {
    struct qeth_card *card = dev_get_drvdata(&gdev->dev);
    int rc;

    - rc = qeth_l2_create_device_attributes(&gdev->dev);
    - if (rc)
    - return rc;
    + if (gdev->dev.type == &qeth_generic_devtype) {
    + rc = qeth_l2_create_device_attributes(&gdev->dev);
    + if (rc)
    + return rc;
    + }
    INIT_LIST_HEAD(&card->vid_list);
    hash_init(card->mac_htable);
    card->options.layer2 = 1;
    @@ -1046,7 +1053,8 @@ static void qeth_l2_remove_device(struct
    {
    struct qeth_card *card = dev_get_drvdata(&cgdev->dev);

    - qeth_l2_remove_device_attributes(&cgdev->dev);
    + if (cgdev->dev.type == &qeth_generic_devtype)
    + qeth_l2_remove_device_attributes(&cgdev->dev);
    qeth_set_allowed_threads(card, 0, 1);
    wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0);

    @@ -1432,6 +1440,7 @@ static int qeth_l2_control_event(struct
    }

    struct qeth_discipline qeth_l2_discipline = {
    + .devtype = &qeth_l2_devtype,
    .start_poll = qeth_qdio_start_poll,
    .input_handler = (qdio_handler_t *) qeth_qdio_input_handler,
    .output_handler = (qdio_handler_t *) qeth_qdio_output_handler,
    --- a/drivers/s390/net/qeth_l2_sys.c
    +++ b/drivers/s390/net/qeth_l2_sys.c
    @@ -272,3 +272,11 @@ void qeth_l2_setup_bridgeport_attrs(stru
    } else
    qeth_bridgeport_an_set(card, 0);
    }
    +
    +const struct attribute_group *qeth_l2_attr_groups[] = {
    + &qeth_device_attr_group,
    + &qeth_device_blkt_group,
    + /* l2 specific, see l2_{create,remove}_device_attributes(): */
    + &qeth_l2_bridgeport_attr_group,
    + NULL,
    +};
    --- a/drivers/s390/net/qeth_l3_main.c
    +++ b/drivers/s390/net/qeth_l3_main.c
    @@ -3522,6 +3522,7 @@ static int qeth_l3_control_event(struct
    }

    struct qeth_discipline qeth_l3_discipline = {
    + .devtype = &qeth_generic_devtype,
    .start_poll = qeth_qdio_start_poll,
    .input_handler = (qdio_handler_t *) qeth_qdio_input_handler,
    .output_handler = (qdio_handler_t *) qeth_qdio_output_handler,

    \
     
     \ /
      Last update: 2017-06-12 00:30    [W:4.330 / U:0.012 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site