mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-28 22:54:05 +08:00
[S390] cio: Introduce modalias for css bus.
Add modalias and subchannel type attributes for all subchannels. I/O subchannel specific attributes are now created in io_subchannel_probe(). modalias and subchannel type are also added to the uevent for the css bus. Also make the css modalias known. Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com> Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
This commit is contained in:
parent
0ae7a7b250
commit
7e9db9eaef
35
Documentation/ABI/testing/sysfs-bus-css
Normal file
35
Documentation/ABI/testing/sysfs-bus-css
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
What: /sys/bus/css/devices/.../type
|
||||||
|
Date: March 2008
|
||||||
|
Contact: Cornelia Huck <cornelia.huck@de.ibm.com>
|
||||||
|
linux-s390@vger.kernel.org
|
||||||
|
Description: Contains the subchannel type, as reported by the hardware.
|
||||||
|
This attribute is present for all subchannel types.
|
||||||
|
|
||||||
|
What: /sys/bus/css/devices/.../modalias
|
||||||
|
Date: March 2008
|
||||||
|
Contact: Cornelia Huck <cornelia.huck@de.ibm.com>
|
||||||
|
linux-s390@vger.kernel.org
|
||||||
|
Description: Contains the module alias as reported with uevents.
|
||||||
|
It is of the format css:t<type> and present for all
|
||||||
|
subchannel types.
|
||||||
|
|
||||||
|
What: /sys/bus/css/drivers/io_subchannel/.../chpids
|
||||||
|
Date: December 2002
|
||||||
|
Contact: Cornelia Huck <cornelia.huck@de.ibm.com>
|
||||||
|
linux-s390@vger.kernel.org
|
||||||
|
Description: Contains the ids of the channel paths used by this
|
||||||
|
subchannel, as reported by the channel subsystem
|
||||||
|
during subchannel recognition.
|
||||||
|
Note: This is an I/O-subchannel specific attribute.
|
||||||
|
Users: s390-tools, HAL
|
||||||
|
|
||||||
|
What: /sys/bus/css/drivers/io_subchannel/.../pimpampom
|
||||||
|
Date: December 2002
|
||||||
|
Contact: Cornelia Huck <cornelia.huck@de.ibm.com>
|
||||||
|
linux-s390@vger.kernel.org
|
||||||
|
Description: Contains the PIM/PAM/POM values, as reported by the
|
||||||
|
channel subsystem when last queried by the common I/O
|
||||||
|
layer (this implies that this attribute is not neccessarily
|
||||||
|
in sync with the values current in the channel subsystem).
|
||||||
|
Note: This is an I/O-subchannel specific attribute.
|
||||||
|
Users: s390-tools, HAL
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
|
#include <linux/mod_devicetable.h>
|
||||||
#include <asm/chpid.h>
|
#include <asm/chpid.h>
|
||||||
#include "chsc.h"
|
#include "chsc.h"
|
||||||
#include "schid.h"
|
#include "schid.h"
|
||||||
|
@ -2,8 +2,7 @@
|
|||||||
* drivers/s390/cio/css.c
|
* drivers/s390/cio/css.c
|
||||||
* driver for channel subsystem
|
* driver for channel subsystem
|
||||||
*
|
*
|
||||||
* Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
|
* Copyright IBM Corp. 2002,2008
|
||||||
* IBM Corporation
|
|
||||||
* Author(s): Arnd Bergmann (arndb@de.ibm.com)
|
* Author(s): Arnd Bergmann (arndb@de.ibm.com)
|
||||||
* Cornelia Huck (cornelia.huck@de.ibm.com)
|
* Cornelia Huck (cornelia.huck@de.ibm.com)
|
||||||
*/
|
*/
|
||||||
@ -210,6 +209,41 @@ void css_update_ssd_info(struct subchannel *sch)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ssize_t type_show(struct device *dev, struct device_attribute *attr,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
struct subchannel *sch = to_subchannel(dev);
|
||||||
|
|
||||||
|
return sprintf(buf, "%01x\n", sch->st);
|
||||||
|
}
|
||||||
|
|
||||||
|
static DEVICE_ATTR(type, 0444, type_show, NULL);
|
||||||
|
|
||||||
|
static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
struct subchannel *sch = to_subchannel(dev);
|
||||||
|
|
||||||
|
return sprintf(buf, "css:t%01X\n", sch->st);
|
||||||
|
}
|
||||||
|
|
||||||
|
static DEVICE_ATTR(modalias, 0444, modalias_show, NULL);
|
||||||
|
|
||||||
|
static struct attribute *subch_attrs[] = {
|
||||||
|
&dev_attr_type.attr,
|
||||||
|
&dev_attr_modalias.attr,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct attribute_group subch_attr_group = {
|
||||||
|
.attrs = subch_attrs,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct attribute_group *default_subch_attr_groups[] = {
|
||||||
|
&subch_attr_group,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
static int css_register_subchannel(struct subchannel *sch)
|
static int css_register_subchannel(struct subchannel *sch)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
@ -218,16 +252,17 @@ static int css_register_subchannel(struct subchannel *sch)
|
|||||||
sch->dev.parent = &channel_subsystems[0]->device;
|
sch->dev.parent = &channel_subsystems[0]->device;
|
||||||
sch->dev.bus = &css_bus_type;
|
sch->dev.bus = &css_bus_type;
|
||||||
sch->dev.release = &css_subchannel_release;
|
sch->dev.release = &css_subchannel_release;
|
||||||
sch->dev.groups = subch_attr_groups;
|
sch->dev.groups = default_subch_attr_groups;
|
||||||
/*
|
/*
|
||||||
* We don't want to generate uevents for I/O subchannels that don't
|
* We don't want to generate uevents for I/O subchannels that don't
|
||||||
* have a working ccw device behind them since they will be
|
* have a working ccw device behind them since they will be
|
||||||
* unregistered before they can be used anyway, so we delay the add
|
* unregistered before they can be used anyway, so we delay the add
|
||||||
* uevent until after device recognition was successful.
|
* uevent until after device recognition was successful.
|
||||||
|
* Note that we suppress the uevent for all subchannel types;
|
||||||
|
* the subchannel driver can decide itself when it wants to inform
|
||||||
|
* userspace of its existence.
|
||||||
*/
|
*/
|
||||||
if (!cio_is_console(sch->schid))
|
sch->dev.uevent_suppress = 1;
|
||||||
/* Console is special, no need to suppress. */
|
|
||||||
sch->dev.uevent_suppress = 1;
|
|
||||||
css_update_ssd_info(sch);
|
css_update_ssd_info(sch);
|
||||||
/* make it known to the system */
|
/* make it known to the system */
|
||||||
ret = css_sch_device_register(sch);
|
ret = css_sch_device_register(sch);
|
||||||
@ -236,6 +271,15 @@ static int css_register_subchannel(struct subchannel *sch)
|
|||||||
sch->schid.ssid, sch->schid.sch_no, ret);
|
sch->schid.ssid, sch->schid.sch_no, ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
if (!sch->driver) {
|
||||||
|
/*
|
||||||
|
* No driver matched. Generate the uevent now so that
|
||||||
|
* a fitting driver module may be loaded based on the
|
||||||
|
* modalias.
|
||||||
|
*/
|
||||||
|
sch->dev.uevent_suppress = 0;
|
||||||
|
kobject_uevent(&sch->dev.kobj, KOBJ_ADD);
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -926,12 +970,25 @@ static void css_shutdown(struct device *dev)
|
|||||||
sch->driver->shutdown(sch);
|
sch->driver->shutdown(sch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int css_uevent(struct device *dev, struct kobj_uevent_env *env)
|
||||||
|
{
|
||||||
|
struct subchannel *sch = to_subchannel(dev);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = add_uevent_var(env, "ST=%01X", sch->st);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
ret = add_uevent_var(env, "MODALIAS=css:t%01X", sch->st);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
struct bus_type css_bus_type = {
|
struct bus_type css_bus_type = {
|
||||||
.name = "css",
|
.name = "css",
|
||||||
.match = css_bus_match,
|
.match = css_bus_match,
|
||||||
.probe = css_probe,
|
.probe = css_probe,
|
||||||
.remove = css_remove,
|
.remove = css_remove,
|
||||||
.shutdown = css_shutdown,
|
.shutdown = css_shutdown,
|
||||||
|
.uevent = css_uevent,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -143,6 +143,4 @@ int css_sch_is_valid(struct schib *);
|
|||||||
|
|
||||||
extern struct workqueue_struct *slow_path_wq;
|
extern struct workqueue_struct *slow_path_wq;
|
||||||
void css_wait_for_slow_path(void);
|
void css_wait_for_slow_path(void);
|
||||||
|
|
||||||
extern struct attribute_group *subch_attr_groups[];
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -585,19 +585,14 @@ static DEVICE_ATTR(modalias, 0444, modalias_show, NULL);
|
|||||||
static DEVICE_ATTR(online, 0644, online_show, online_store);
|
static DEVICE_ATTR(online, 0644, online_show, online_store);
|
||||||
static DEVICE_ATTR(availability, 0444, available_show, NULL);
|
static DEVICE_ATTR(availability, 0444, available_show, NULL);
|
||||||
|
|
||||||
static struct attribute * subch_attrs[] = {
|
static struct attribute *io_subchannel_attrs[] = {
|
||||||
&dev_attr_chpids.attr,
|
&dev_attr_chpids.attr,
|
||||||
&dev_attr_pimpampom.attr,
|
&dev_attr_pimpampom.attr,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct attribute_group subch_attr_group = {
|
static struct attribute_group io_subchannel_attr_group = {
|
||||||
.attrs = subch_attrs,
|
.attrs = io_subchannel_attrs,
|
||||||
};
|
|
||||||
|
|
||||||
struct attribute_group *subch_attr_groups[] = {
|
|
||||||
&subch_attr_group,
|
|
||||||
NULL,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct attribute * ccwdev_attrs[] = {
|
static struct attribute * ccwdev_attrs[] = {
|
||||||
@ -1157,11 +1152,21 @@ static int io_subchannel_probe(struct subchannel *sch)
|
|||||||
|
|
||||||
cdev = sch_get_cdev(sch);
|
cdev = sch_get_cdev(sch);
|
||||||
if (cdev) {
|
if (cdev) {
|
||||||
|
rc = sysfs_create_group(&sch->dev.kobj,
|
||||||
|
&io_subchannel_attr_group);
|
||||||
|
if (rc)
|
||||||
|
CIO_MSG_EVENT(0, "Failed to create io subchannel "
|
||||||
|
"attributes for subchannel "
|
||||||
|
"0.%x.%04x (rc=%d)\n",
|
||||||
|
sch->schid.ssid, sch->schid.sch_no, rc);
|
||||||
/*
|
/*
|
||||||
* This subchannel already has an associated ccw_device.
|
* This subchannel already has an associated ccw_device.
|
||||||
* Register it and exit. This happens for all early
|
* Throw the delayed uevent for the subchannel, register
|
||||||
* device, e.g. the console.
|
* the ccw_device and exit. This happens for all early
|
||||||
|
* devices, e.g. the console.
|
||||||
*/
|
*/
|
||||||
|
sch->dev.uevent_suppress = 0;
|
||||||
|
kobject_uevent(&sch->dev.kobj, KOBJ_ADD);
|
||||||
cdev->dev.groups = ccwdev_attr_groups;
|
cdev->dev.groups = ccwdev_attr_groups;
|
||||||
device_initialize(&cdev->dev);
|
device_initialize(&cdev->dev);
|
||||||
ccw_device_register(cdev);
|
ccw_device_register(cdev);
|
||||||
@ -1184,11 +1189,17 @@ static int io_subchannel_probe(struct subchannel *sch)
|
|||||||
*/
|
*/
|
||||||
dev_id.devno = sch->schib.pmcw.dev;
|
dev_id.devno = sch->schib.pmcw.dev;
|
||||||
dev_id.ssid = sch->schid.ssid;
|
dev_id.ssid = sch->schid.ssid;
|
||||||
|
rc = sysfs_create_group(&sch->dev.kobj,
|
||||||
|
&io_subchannel_attr_group);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
/* Allocate I/O subchannel private data. */
|
/* Allocate I/O subchannel private data. */
|
||||||
sch->private = kzalloc(sizeof(struct io_subchannel_private),
|
sch->private = kzalloc(sizeof(struct io_subchannel_private),
|
||||||
GFP_KERNEL | GFP_DMA);
|
GFP_KERNEL | GFP_DMA);
|
||||||
if (!sch->private)
|
if (!sch->private) {
|
||||||
return -ENOMEM;
|
rc = -ENOMEM;
|
||||||
|
goto out_err;
|
||||||
|
}
|
||||||
cdev = get_disc_ccwdev_by_dev_id(&dev_id, NULL);
|
cdev = get_disc_ccwdev_by_dev_id(&dev_id, NULL);
|
||||||
if (!cdev)
|
if (!cdev)
|
||||||
cdev = get_orphaned_ccwdev_by_dev_id(to_css(sch->dev.parent),
|
cdev = get_orphaned_ccwdev_by_dev_id(to_css(sch->dev.parent),
|
||||||
@ -1207,8 +1218,8 @@ static int io_subchannel_probe(struct subchannel *sch)
|
|||||||
}
|
}
|
||||||
cdev = io_subchannel_create_ccwdev(sch);
|
cdev = io_subchannel_create_ccwdev(sch);
|
||||||
if (IS_ERR(cdev)) {
|
if (IS_ERR(cdev)) {
|
||||||
kfree(sch->private);
|
rc = PTR_ERR(cdev);
|
||||||
return PTR_ERR(cdev);
|
goto out_err;
|
||||||
}
|
}
|
||||||
rc = io_subchannel_recog(cdev, sch);
|
rc = io_subchannel_recog(cdev, sch);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
@ -1217,9 +1228,12 @@ static int io_subchannel_probe(struct subchannel *sch)
|
|||||||
spin_unlock_irqrestore(sch->lock, flags);
|
spin_unlock_irqrestore(sch->lock, flags);
|
||||||
if (cdev->dev.release)
|
if (cdev->dev.release)
|
||||||
cdev->dev.release(&cdev->dev);
|
cdev->dev.release(&cdev->dev);
|
||||||
kfree(sch->private);
|
goto out_err;
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
|
out_err:
|
||||||
|
kfree(sch->private);
|
||||||
|
sysfs_remove_group(&sch->dev.kobj, &io_subchannel_attr_group);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1240,6 +1254,7 @@ io_subchannel_remove (struct subchannel *sch)
|
|||||||
ccw_device_unregister(cdev);
|
ccw_device_unregister(cdev);
|
||||||
put_device(&cdev->dev);
|
put_device(&cdev->dev);
|
||||||
kfree(sch->private);
|
kfree(sch->private);
|
||||||
|
sysfs_remove_group(&sch->dev.kobj, &io_subchannel_attr_group);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,6 +159,15 @@ struct ap_device_id {
|
|||||||
|
|
||||||
#define AP_DEVICE_ID_MATCH_DEVICE_TYPE 0x01
|
#define AP_DEVICE_ID_MATCH_DEVICE_TYPE 0x01
|
||||||
|
|
||||||
|
/* s390 css bus devices (subchannels) */
|
||||||
|
struct css_device_id {
|
||||||
|
__u8 type; /* subchannel type */
|
||||||
|
__u8 pad1;
|
||||||
|
__u16 pad2;
|
||||||
|
__u32 pad3;
|
||||||
|
kernel_ulong_t driver_data;
|
||||||
|
};
|
||||||
|
|
||||||
#define ACPI_ID_LEN 16 /* only 9 bytes needed here, 16 bytes are used */
|
#define ACPI_ID_LEN 16 /* only 9 bytes needed here, 16 bytes are used */
|
||||||
/* to workaround crosscompile issues */
|
/* to workaround crosscompile issues */
|
||||||
|
|
||||||
|
@ -304,6 +304,14 @@ static int do_ap_entry(const char *filename,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* looks like: "css:tN" */
|
||||||
|
static int do_css_entry(const char *filename,
|
||||||
|
struct css_device_id *id, char *alias)
|
||||||
|
{
|
||||||
|
sprintf(alias, "css:t%01X", id->type);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Looks like: "serio:tyNprNidNexN" */
|
/* Looks like: "serio:tyNprNidNexN" */
|
||||||
static int do_serio_entry(const char *filename,
|
static int do_serio_entry(const char *filename,
|
||||||
struct serio_device_id *id, char *alias)
|
struct serio_device_id *id, char *alias)
|
||||||
@ -680,6 +688,10 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
|
|||||||
do_table(symval, sym->st_size,
|
do_table(symval, sym->st_size,
|
||||||
sizeof(struct ap_device_id), "ap",
|
sizeof(struct ap_device_id), "ap",
|
||||||
do_ap_entry, mod);
|
do_ap_entry, mod);
|
||||||
|
else if (sym_is(symname, "__mod_css_device_table"))
|
||||||
|
do_table(symval, sym->st_size,
|
||||||
|
sizeof(struct css_device_id), "css",
|
||||||
|
do_css_entry, mod);
|
||||||
else if (sym_is(symname, "__mod_serio_device_table"))
|
else if (sym_is(symname, "__mod_serio_device_table"))
|
||||||
do_table(symval, sym->st_size,
|
do_table(symval, sym->st_size,
|
||||||
sizeof(struct serio_device_id), "serio",
|
sizeof(struct serio_device_id), "serio",
|
||||||
|
Loading…
Reference in New Issue
Block a user