Commit a28c6944 authored by Cornelia Huck's avatar Cornelia Huck Committed by Linus Torvalds

[PATCH] s390: introduce struct channel_subsystem

struct channel_subsystem encapsulates several per channel subsystem
properties, like status of chpids or the global path group id.
Signed-off-by: default avatarCornelia Huck <cohuck@de.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent f97a56fb
...@@ -24,8 +24,6 @@ ...@@ -24,8 +24,6 @@
#include "ioasm.h" #include "ioasm.h"
#include "chsc.h" #include "chsc.h"
static struct channel_path *chps[NR_CHPIDS];
static void *sei_page; static void *sei_page;
static int new_channel_path(int chpid); static int new_channel_path(int chpid);
...@@ -33,13 +31,13 @@ static int new_channel_path(int chpid); ...@@ -33,13 +31,13 @@ static int new_channel_path(int chpid);
static inline void static inline void
set_chp_logically_online(int chp, int onoff) set_chp_logically_online(int chp, int onoff)
{ {
chps[chp]->state = onoff; css[0]->chps[chp]->state = onoff;
} }
static int static int
get_chp_status(int chp) get_chp_status(int chp)
{ {
return (chps[chp] ? chps[chp]->state : -ENODEV); return (css[0]->chps[chp] ? css[0]->chps[chp]->state : -ENODEV);
} }
void void
...@@ -219,13 +217,13 @@ s390_subchannel_remove_chpid(struct device *dev, void *data) ...@@ -219,13 +217,13 @@ s390_subchannel_remove_chpid(struct device *dev, void *data)
int j; int j;
int mask; int mask;
struct subchannel *sch; struct subchannel *sch;
__u8 *chpid; struct channel_path *chpid;
struct schib schib; struct schib schib;
sch = to_subchannel(dev); sch = to_subchannel(dev);
chpid = data; chpid = data;
for (j = 0; j < 8; j++) for (j = 0; j < 8; j++)
if (sch->schib.pmcw.chpid[j] == *chpid) if (sch->schib.pmcw.chpid[j] == chpid->id)
break; break;
if (j >= 8) if (j >= 8)
return 0; return 0;
...@@ -296,18 +294,20 @@ static inline void ...@@ -296,18 +294,20 @@ static inline void
s390_set_chpid_offline( __u8 chpid) s390_set_chpid_offline( __u8 chpid)
{ {
char dbf_txt[15]; char dbf_txt[15];
struct device *dev;
sprintf(dbf_txt, "chpr%x", chpid); sprintf(dbf_txt, "chpr%x", chpid);
CIO_TRACE_EVENT(2, dbf_txt); CIO_TRACE_EVENT(2, dbf_txt);
if (get_chp_status(chpid) <= 0) if (get_chp_status(chpid) <= 0)
return; return;
dev = get_device(&css[0]->chps[chpid]->dev);
bus_for_each_dev(&css_bus_type, NULL, &chpid, bus_for_each_dev(&css_bus_type, NULL, to_channelpath(dev),
s390_subchannel_remove_chpid); s390_subchannel_remove_chpid);
if (need_rescan || css_slow_subchannels_exist()) if (need_rescan || css_slow_subchannels_exist())
queue_work(slow_path_wq, &slow_path_work); queue_work(slow_path_wq, &slow_path_work);
put_device(dev);
} }
struct res_acc_data { struct res_acc_data {
...@@ -511,6 +511,7 @@ chsc_process_crw(void) ...@@ -511,6 +511,7 @@ chsc_process_crw(void)
ret = 0; ret = 0;
do { do {
int ccode, status; int ccode, status;
struct device *dev;
memset(sei_area, 0, sizeof(*sei_area)); memset(sei_area, 0, sizeof(*sei_area));
memset(&res_data, 0, sizeof(struct res_acc_data)); memset(&res_data, 0, sizeof(struct res_acc_data));
sei_area->request = (struct chsc_header) { sei_area->request = (struct chsc_header) {
...@@ -586,7 +587,8 @@ chsc_process_crw(void) ...@@ -586,7 +587,8 @@ chsc_process_crw(void)
new_channel_path(sei_area->rsid); new_channel_path(sei_area->rsid);
else if (!status) else if (!status)
break; break;
res_data.chp = chps[sei_area->rsid]; dev = get_device(&css[0]->chps[sei_area->rsid]->dev);
res_data.chp = to_channelpath(dev);
pr_debug("chpid: %x", sei_area->rsid); pr_debug("chpid: %x", sei_area->rsid);
if ((sei_area->vf & 0xc0) != 0) { if ((sei_area->vf & 0xc0) != 0) {
res_data.fla = sei_area->fla; res_data.fla = sei_area->fla;
...@@ -602,6 +604,7 @@ chsc_process_crw(void) ...@@ -602,6 +604,7 @@ chsc_process_crw(void)
} }
ret = s390_process_res_acc(&res_data); ret = s390_process_res_acc(&res_data);
pr_debug("\n\n"); pr_debug("\n\n");
put_device(dev);
break; break;
default: /* other stuff */ default: /* other stuff */
...@@ -678,6 +681,7 @@ chp_add(int chpid) ...@@ -678,6 +681,7 @@ chp_add(int chpid)
{ {
int rc; int rc;
char dbf_txt[15]; char dbf_txt[15];
struct device *dev;
if (!get_chp_status(chpid)) if (!get_chp_status(chpid))
return 0; /* no need to do the rest */ return 0; /* no need to do the rest */
...@@ -685,11 +689,13 @@ chp_add(int chpid) ...@@ -685,11 +689,13 @@ chp_add(int chpid)
sprintf(dbf_txt, "cadd%x", chpid); sprintf(dbf_txt, "cadd%x", chpid);
CIO_TRACE_EVENT(2, dbf_txt); CIO_TRACE_EVENT(2, dbf_txt);
rc = for_each_subchannel(__chp_add, chps[chpid]); dev = get_device(&css[0]->chps[chpid]->dev);
rc = for_each_subchannel(__chp_add, to_channelpath(dev));
if (css_slow_subchannels_exist()) if (css_slow_subchannels_exist())
rc = -EAGAIN; rc = -EAGAIN;
if (rc != -EAGAIN) if (rc != -EAGAIN)
rc = 0; rc = 0;
put_device(dev);
return rc; return rc;
} }
...@@ -1016,7 +1022,7 @@ new_channel_path(int chpid) ...@@ -1016,7 +1022,7 @@ new_channel_path(int chpid)
chp->id = chpid; chp->id = chpid;
chp->state = 1; chp->state = 1;
chp->dev = (struct device) { chp->dev = (struct device) {
.parent = &css_bus_device, .parent = &css[0]->device,
.release = chp_release, .release = chp_release,
}; };
snprintf(chp->dev.bus_id, BUS_ID_SIZE, "chp0.%x", chpid); snprintf(chp->dev.bus_id, BUS_ID_SIZE, "chp0.%x", chpid);
...@@ -1038,7 +1044,7 @@ new_channel_path(int chpid) ...@@ -1038,7 +1044,7 @@ new_channel_path(int chpid)
device_unregister(&chp->dev); device_unregister(&chp->dev);
goto out_free; goto out_free;
} else } else
chps[chpid] = chp; css[0]->chps[chpid] = chp;
return ret; return ret;
out_free: out_free:
kfree(chp); kfree(chp);
...@@ -1051,7 +1057,7 @@ chsc_get_chp_desc(struct subchannel *sch, int chp_no) ...@@ -1051,7 +1057,7 @@ chsc_get_chp_desc(struct subchannel *sch, int chp_no)
struct channel_path *chp; struct channel_path *chp;
struct channel_path_desc *desc; struct channel_path_desc *desc;
chp = chps[sch->schib.pmcw.chpid[chp_no]]; chp = css[0]->chps[sch->schib.pmcw.chpid[chp_no]];
if (!chp) if (!chp)
return NULL; return NULL;
desc = kmalloc(sizeof(struct channel_path_desc), GFP_KERNEL); desc = kmalloc(sizeof(struct channel_path_desc), GFP_KERNEL);
......
#ifndef S390_CHSC_H #ifndef S390_CHSC_H
#define S390_CHSC_H #define S390_CHSC_H
#define NR_CHPIDS 256
#define CHSC_SEI_ACC_CHPID 1 #define CHSC_SEI_ACC_CHPID 1
#define CHSC_SEI_ACC_LINKADDR 2 #define CHSC_SEI_ACC_LINKADDR 2
#define CHSC_SEI_ACC_FULLLINKADDR 3 #define CHSC_SEI_ACC_FULLLINKADDR 3
...@@ -65,4 +63,7 @@ extern int chsc_determine_css_characteristics(void); ...@@ -65,4 +63,7 @@ extern int chsc_determine_css_characteristics(void);
extern int css_characteristics_avail; extern int css_characteristics_avail;
extern void *chsc_get_chp_desc(struct subchannel*, int); extern void *chsc_get_chp_desc(struct subchannel*, int);
#define to_channelpath(dev) container_of(dev, struct channel_path, dev)
#endif #endif
...@@ -24,12 +24,9 @@ ...@@ -24,12 +24,9 @@
int need_rescan = 0; int need_rescan = 0;
int css_init_done = 0; int css_init_done = 0;
struct pgid global_pgid; struct channel_subsystem *css[__MAX_CSSID + 1];
int css_characteristics_avail = 0;
struct device css_bus_device = { int css_characteristics_avail = 0;
.bus_id = "css0",
};
inline int inline int
for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *data) for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *data)
...@@ -112,7 +109,7 @@ css_register_subchannel(struct subchannel *sch) ...@@ -112,7 +109,7 @@ css_register_subchannel(struct subchannel *sch)
int ret; int ret;
/* Initialize the subchannel structure */ /* Initialize the subchannel structure */
sch->dev.parent = &css_bus_device; sch->dev.parent = &css[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;
...@@ -421,21 +418,35 @@ __init_channel_subsystem(struct subchannel_id schid, void *data) ...@@ -421,21 +418,35 @@ __init_channel_subsystem(struct subchannel_id schid, void *data)
} }
static void __init static void __init
css_generate_pgid(void) css_generate_pgid(struct channel_subsystem *css, u32 tod_high)
{ {
/* Let's build our path group ID here. */ if (css_characteristics_avail && css_general_characteristics.mcss) {
if (css_characteristics_avail && css_general_characteristics.mcss) css->global_pgid.pgid_high.ext_cssid.version = 0x80;
global_pgid.cpu_addr = 0x8000; css->global_pgid.pgid_high.ext_cssid.cssid = css->cssid;
else { } else {
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
global_pgid.cpu_addr = hard_smp_processor_id(); css->global_pgid.pgid_high.cpu_addr = hard_smp_processor_id();
#else #else
global_pgid.cpu_addr = 0; css->global_pgid.pgid_high.cpu_addr = 0;
#endif #endif
} }
global_pgid.cpu_id = ((cpuid_t *) __LC_CPUID)->ident; css->global_pgid.cpu_id = ((cpuid_t *) __LC_CPUID)->ident;
global_pgid.cpu_model = ((cpuid_t *) __LC_CPUID)->machine; css->global_pgid.cpu_model = ((cpuid_t *) __LC_CPUID)->machine;
global_pgid.tod_high = (__u32) (get_clock() >> 32); css->global_pgid.tod_high = tod_high;
}
static inline void __init
setup_css(int nr)
{
u32 tod_high;
memset(css[nr], 0, sizeof(struct channel_subsystem));
css[nr]->valid = 1;
css[nr]->cssid = nr;
sprintf(css[nr]->device.bus_id, "css%x", nr);
tod_high = (u32) (get_clock() >> 32);
css_generate_pgid(css[nr], tod_high);
} }
/* /*
...@@ -446,25 +457,39 @@ css_generate_pgid(void) ...@@ -446,25 +457,39 @@ css_generate_pgid(void)
static int __init static int __init
init_channel_subsystem (void) init_channel_subsystem (void)
{ {
int ret; int ret, i;
if (chsc_determine_css_characteristics() == 0) if (chsc_determine_css_characteristics() == 0)
css_characteristics_avail = 1; css_characteristics_avail = 1;
css_generate_pgid();
if ((ret = bus_register(&css_bus_type))) if ((ret = bus_register(&css_bus_type)))
goto out; goto out;
if ((ret = device_register (&css_bus_device)))
goto out_bus;
/* Setup css structure. */
for (i = 0; i <= __MAX_CSSID; i++) {
css[i] = kmalloc(sizeof(struct channel_subsystem), GFP_KERNEL);
if (!css[i]) {
ret = -ENOMEM;
goto out_bus;
}
setup_css(i);
ret = device_register(&css[i]->device);
if (ret)
goto out_free;
}
css_init_done = 1; css_init_done = 1;
ctl_set_bit(6, 28); ctl_set_bit(6, 28);
for_each_subchannel(__init_channel_subsystem, NULL); for_each_subchannel(__init_channel_subsystem, NULL);
return 0; return 0;
out_free:
kfree(css[i]);
out_bus: out_bus:
while (i > 0) {
i--;
device_unregister(&css[i]->device);
}
bus_unregister(&css_bus_type); bus_unregister(&css_bus_type);
out: out:
return ret; return ret;
......
...@@ -35,19 +35,25 @@ struct path_state { ...@@ -35,19 +35,25 @@ struct path_state {
__u8 resvd : 3; /* reserved */ __u8 resvd : 3; /* reserved */
} __attribute__ ((packed)); } __attribute__ ((packed));
struct extended_cssid {
u8 version;
u8 cssid;
} __attribute__ ((packed));
struct pgid { struct pgid {
union { union {
__u8 fc; /* SPID function code */ __u8 fc; /* SPID function code */
struct path_state ps; /* SNID path state */ struct path_state ps; /* SNID path state */
} inf; } inf;
union {
__u32 cpu_addr : 16; /* CPU address */ __u32 cpu_addr : 16; /* CPU address */
struct extended_cssid ext_cssid;
} pgid_high;
__u32 cpu_id : 24; /* CPU identification */ __u32 cpu_id : 24; /* CPU identification */
__u32 cpu_model : 16; /* CPU model */ __u32 cpu_model : 16; /* CPU model */
__u32 tod_high; /* high word TOD clock */ __u32 tod_high; /* high word TOD clock */
} __attribute__ ((packed)); } __attribute__ ((packed));
extern struct pgid global_pgid;
#define MAX_CIWS 8 #define MAX_CIWS 8
/* /*
...@@ -129,9 +135,20 @@ extern int css_init_done; ...@@ -129,9 +135,20 @@ extern int css_init_done;
extern int for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *); extern int for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *);
#define __MAX_SUBCHANNEL 65535 #define __MAX_SUBCHANNEL 65535
#define __MAX_CHPID 255
#define __MAX_CSSID 0
struct channel_subsystem {
u8 cssid;
int valid;
struct channel_path *chps[__MAX_CHPID];
struct device device;
struct pgid global_pgid;
};
#define to_css(dev) container_of(dev, struct channel_subsystem, device)
extern struct bus_type css_bus_type; extern struct bus_type css_bus_type;
extern struct device css_bus_device; extern struct channel_subsystem *css[];
/* Some helper functions for disconnected state. */ /* Some helper functions for disconnected state. */
int device_is_disconnected(struct subchannel *); int device_is_disconnected(struct subchannel *);
......
...@@ -986,10 +986,6 @@ ccw_device_console_enable (struct ccw_device *cdev, struct subchannel *sch) ...@@ -986,10 +986,6 @@ ccw_device_console_enable (struct ccw_device *cdev, struct subchannel *sch)
cdev->dev = (struct device) { cdev->dev = (struct device) {
.parent = &sch->dev, .parent = &sch->dev,
}; };
/* Initialize the subchannel structure */
sch->dev.parent = &css_bus_device;
sch->dev.bus = &css_bus_type;
rc = io_subchannel_recog(cdev, sch); rc = io_subchannel_recog(cdev, sch);
if (rc) if (rc)
return rc; return rc;
......
...@@ -164,7 +164,7 @@ ccw_device_sense_pgid_irq(struct ccw_device *cdev, enum dev_event dev_event) ...@@ -164,7 +164,7 @@ ccw_device_sense_pgid_irq(struct ccw_device *cdev, enum dev_event dev_event)
/* 0, -ETIME, -EOPNOTSUPP, -EAGAIN, -EACCES or -EUSERS */ /* 0, -ETIME, -EOPNOTSUPP, -EAGAIN, -EACCES or -EUSERS */
case 0: /* Sense Path Group ID successful. */ case 0: /* Sense Path Group ID successful. */
if (cdev->private->pgid.inf.ps.state1 == SNID_STATE1_RESET) if (cdev->private->pgid.inf.ps.state1 == SNID_STATE1_RESET)
memcpy(&cdev->private->pgid, &global_pgid, memcpy(&cdev->private->pgid, &css[0]->global_pgid,
sizeof(struct pgid)); sizeof(struct pgid));
ccw_device_sense_pgid_done(cdev, 0); ccw_device_sense_pgid_done(cdev, 0);
break; break;
......
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