diff options
author | Jan Glauber <jang@linux.vnet.ibm.com> | 2008-12-25 07:38:43 -0500 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2008-12-25 07:38:58 -0500 |
commit | bbd50e172f75b1d12ef9b1bcf593b51a44199016 (patch) | |
tree | 85cffdd66bb9f4da36d604d857959964736f3fde /drivers/s390/cio | |
parent | 43c207e6e5b7e591b59294ee4fc9860b0e3de3b8 (diff) |
[S390] qdio: fix qeth port count detection
qeth needs to get the port count information before
qdio has allocated a page for the chsc operation.
Extend qdio_get_ssqd_desc() to store the data in the
specified structure.
Signed-off-by: Jan Glauber <jang@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/cio')
-rw-r--r-- | drivers/s390/cio/qdio.h | 3 | ||||
-rw-r--r-- | drivers/s390/cio/qdio_main.c | 18 | ||||
-rw-r--r-- | drivers/s390/cio/qdio_setup.c | 33 |
3 files changed, 36 insertions, 18 deletions
diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index e3ea1d5f2810..e4e33839c7fe 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h | |||
@@ -378,6 +378,9 @@ void qdio_int_handler(struct ccw_device *cdev, unsigned long intparm, | |||
378 | int qdio_allocate_qs(struct qdio_irq *irq_ptr, int nr_input_qs, | 378 | int qdio_allocate_qs(struct qdio_irq *irq_ptr, int nr_input_qs, |
379 | int nr_output_qs); | 379 | int nr_output_qs); |
380 | void qdio_setup_ssqd_info(struct qdio_irq *irq_ptr); | 380 | void qdio_setup_ssqd_info(struct qdio_irq *irq_ptr); |
381 | int qdio_setup_get_ssqd(struct qdio_irq *irq_ptr, | ||
382 | struct subchannel_id *schid, | ||
383 | struct qdio_ssqd_desc *data); | ||
381 | int qdio_setup_irq(struct qdio_initialize *init_data); | 384 | int qdio_setup_irq(struct qdio_initialize *init_data); |
382 | void qdio_print_subchannel_info(struct qdio_irq *irq_ptr, | 385 | void qdio_print_subchannel_info(struct qdio_irq *irq_ptr, |
383 | struct ccw_device *cdev); | 386 | struct ccw_device *cdev); |
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 7c8659151993..7572a0057623 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c | |||
@@ -1129,23 +1129,23 @@ void qdio_int_handler(struct ccw_device *cdev, unsigned long intparm, | |||
1129 | /** | 1129 | /** |
1130 | * qdio_get_ssqd_desc - get qdio subchannel description | 1130 | * qdio_get_ssqd_desc - get qdio subchannel description |
1131 | * @cdev: ccw device to get description for | 1131 | * @cdev: ccw device to get description for |
1132 | * @data: where to store the ssqd | ||
1132 | * | 1133 | * |
1133 | * Returns a pointer to the saved qdio subchannel description, | 1134 | * Returns 0 or an error code. The results of the chsc are stored in the |
1134 | * or NULL for not setup qdio devices. | 1135 | * specified structure. |
1135 | */ | 1136 | */ |
1136 | struct qdio_ssqd_desc *qdio_get_ssqd_desc(struct ccw_device *cdev) | 1137 | int qdio_get_ssqd_desc(struct ccw_device *cdev, |
1138 | struct qdio_ssqd_desc *data) | ||
1137 | { | 1139 | { |
1138 | struct qdio_irq *irq_ptr; | ||
1139 | char dbf_text[15]; | 1140 | char dbf_text[15]; |
1140 | 1141 | ||
1142 | if (!cdev || !cdev->private) | ||
1143 | return -EINVAL; | ||
1144 | |||
1141 | sprintf(dbf_text, "qssq%4x", cdev->private->schid.sch_no); | 1145 | sprintf(dbf_text, "qssq%4x", cdev->private->schid.sch_no); |
1142 | QDIO_DBF_TEXT0(0, setup, dbf_text); | 1146 | QDIO_DBF_TEXT0(0, setup, dbf_text); |
1143 | 1147 | ||
1144 | irq_ptr = cdev->private->qdio_data; | 1148 | return qdio_setup_get_ssqd(NULL, &cdev->private->schid, data); |
1145 | if (!irq_ptr) | ||
1146 | return NULL; | ||
1147 | |||
1148 | return &irq_ptr->ssqd_desc; | ||
1149 | } | 1149 | } |
1150 | EXPORT_SYMBOL_GPL(qdio_get_ssqd_desc); | 1150 | EXPORT_SYMBOL_GPL(qdio_get_ssqd_desc); |
1151 | 1151 | ||
diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c index a0b6b46e7466..22ee0272a104 100644 --- a/drivers/s390/cio/qdio_setup.c +++ b/drivers/s390/cio/qdio_setup.c | |||
@@ -243,22 +243,31 @@ no_qebsm: | |||
243 | QDIO_DBF_TEXT0(0, setup, "noV=V"); | 243 | QDIO_DBF_TEXT0(0, setup, "noV=V"); |
244 | } | 244 | } |
245 | 245 | ||
246 | static int __get_ssqd_info(struct qdio_irq *irq_ptr) | 246 | /* |
247 | * If there is a qdio_irq we use the chsc_page and store the information | ||
248 | * in the qdio_irq, otherwise we copy it to the specified structure. | ||
249 | */ | ||
250 | int qdio_setup_get_ssqd(struct qdio_irq *irq_ptr, | ||
251 | struct subchannel_id *schid, | ||
252 | struct qdio_ssqd_desc *data) | ||
247 | { | 253 | { |
248 | struct chsc_ssqd_area *ssqd; | 254 | struct chsc_ssqd_area *ssqd; |
249 | int rc; | 255 | int rc; |
250 | 256 | ||
251 | QDIO_DBF_TEXT0(0, setup, "getssqd"); | 257 | QDIO_DBF_TEXT0(0, setup, "getssqd"); |
252 | ssqd = (struct chsc_ssqd_area *)irq_ptr->chsc_page; | 258 | if (irq_ptr != NULL) |
259 | ssqd = (struct chsc_ssqd_area *)irq_ptr->chsc_page; | ||
260 | else | ||
261 | ssqd = (struct chsc_ssqd_area *)__get_free_page(GFP_KERNEL); | ||
253 | memset(ssqd, 0, PAGE_SIZE); | 262 | memset(ssqd, 0, PAGE_SIZE); |
254 | 263 | ||
255 | ssqd->request = (struct chsc_header) { | 264 | ssqd->request = (struct chsc_header) { |
256 | .length = 0x0010, | 265 | .length = 0x0010, |
257 | .code = 0x0024, | 266 | .code = 0x0024, |
258 | }; | 267 | }; |
259 | ssqd->first_sch = irq_ptr->schid.sch_no; | 268 | ssqd->first_sch = schid->sch_no; |
260 | ssqd->last_sch = irq_ptr->schid.sch_no; | 269 | ssqd->last_sch = schid->sch_no; |
261 | ssqd->ssid = irq_ptr->schid.ssid; | 270 | ssqd->ssid = schid->ssid; |
262 | 271 | ||
263 | if (chsc(ssqd)) | 272 | if (chsc(ssqd)) |
264 | return -EIO; | 273 | return -EIO; |
@@ -268,11 +277,17 @@ static int __get_ssqd_info(struct qdio_irq *irq_ptr) | |||
268 | 277 | ||
269 | if (!(ssqd->qdio_ssqd.flags & CHSC_FLAG_QDIO_CAPABILITY) || | 278 | if (!(ssqd->qdio_ssqd.flags & CHSC_FLAG_QDIO_CAPABILITY) || |
270 | !(ssqd->qdio_ssqd.flags & CHSC_FLAG_VALIDITY) || | 279 | !(ssqd->qdio_ssqd.flags & CHSC_FLAG_VALIDITY) || |
271 | (ssqd->qdio_ssqd.sch != irq_ptr->schid.sch_no)) | 280 | (ssqd->qdio_ssqd.sch != schid->sch_no)) |
272 | return -EINVAL; | 281 | return -EINVAL; |
273 | 282 | ||
274 | memcpy(&irq_ptr->ssqd_desc, &ssqd->qdio_ssqd, | 283 | if (irq_ptr != NULL) |
275 | sizeof(struct qdio_ssqd_desc)); | 284 | memcpy(&irq_ptr->ssqd_desc, &ssqd->qdio_ssqd, |
285 | sizeof(struct qdio_ssqd_desc)); | ||
286 | else { | ||
287 | memcpy(data, &ssqd->qdio_ssqd, | ||
288 | sizeof(struct qdio_ssqd_desc)); | ||
289 | free_page((unsigned long)ssqd); | ||
290 | } | ||
276 | return 0; | 291 | return 0; |
277 | } | 292 | } |
278 | 293 | ||
@@ -282,7 +297,7 @@ void qdio_setup_ssqd_info(struct qdio_irq *irq_ptr) | |||
282 | char dbf_text[15]; | 297 | char dbf_text[15]; |
283 | int rc; | 298 | int rc; |
284 | 299 | ||
285 | rc = __get_ssqd_info(irq_ptr); | 300 | rc = qdio_setup_get_ssqd(irq_ptr, &irq_ptr->schid, NULL); |
286 | if (rc) { | 301 | if (rc) { |
287 | QDIO_DBF_TEXT2(0, setup, "ssqdasig"); | 302 | QDIO_DBF_TEXT2(0, setup, "ssqdasig"); |
288 | sprintf(dbf_text, "schn%4x", irq_ptr->schid.sch_no); | 303 | sprintf(dbf_text, "schn%4x", irq_ptr->schid.sch_no); |