Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

authored by

Jan Glauber and committed by
Martin Schwidefsky
bbd50e17 43c207e6

+55 -30
+8 -8
arch/s390/include/asm/qdio.h
··· 373 373 #define QDIO_FLAG_SYNC_OUTPUT 0x02 374 374 #define QDIO_FLAG_PCI_OUT 0x10 375 375 376 - extern int qdio_initialize(struct qdio_initialize *init_data); 377 - extern int qdio_allocate(struct qdio_initialize *init_data); 378 - extern int qdio_establish(struct qdio_initialize *init_data); 376 + extern int qdio_initialize(struct qdio_initialize *); 377 + extern int qdio_allocate(struct qdio_initialize *); 378 + extern int qdio_establish(struct qdio_initialize *); 379 379 extern int qdio_activate(struct ccw_device *); 380 380 381 - extern int do_QDIO(struct ccw_device*, unsigned int flags, 382 - int q_nr, int qidx, int count); 383 - extern int qdio_cleanup(struct ccw_device*, int how); 384 - extern int qdio_shutdown(struct ccw_device*, int how); 381 + extern int do_QDIO(struct ccw_device *cdev, unsigned int callflags, 382 + int q_nr, int bufnr, int count); 383 + extern int qdio_cleanup(struct ccw_device*, int); 384 + extern int qdio_shutdown(struct ccw_device*, int); 385 385 extern int qdio_free(struct ccw_device *); 386 - extern struct qdio_ssqd_desc *qdio_get_ssqd_desc(struct ccw_device *cdev); 386 + extern int qdio_get_ssqd_desc(struct ccw_device *dev, struct qdio_ssqd_desc*); 387 387 388 388 #endif /* __QDIO_H__ */
+3
drivers/s390/cio/qdio.h
··· 378 378 int qdio_allocate_qs(struct qdio_irq *irq_ptr, int nr_input_qs, 379 379 int nr_output_qs); 380 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 384 int qdio_setup_irq(struct qdio_initialize *init_data); 382 385 void qdio_print_subchannel_info(struct qdio_irq *irq_ptr, 383 386 struct ccw_device *cdev);
+9 -9
drivers/s390/cio/qdio_main.c
··· 1129 1129 /** 1130 1130 * qdio_get_ssqd_desc - get qdio subchannel description 1131 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 - * or NULL for not setup qdio devices. 1134 + * Returns 0 or an error code. The results of the chsc are stored in the 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 1140 char dbf_text[15]; 1141 + 1142 + if (!cdev || !cdev->private) 1143 + return -EINVAL; 1140 1144 1141 1145 sprintf(dbf_text, "qssq%4x", cdev->private->schid.sch_no); 1142 1146 QDIO_DBF_TEXT0(0, setup, dbf_text); 1143 1147 1144 - irq_ptr = cdev->private->qdio_data; 1145 - if (!irq_ptr) 1146 - return NULL; 1147 - 1148 - return &irq_ptr->ssqd_desc; 1148 + return qdio_setup_get_ssqd(NULL, &cdev->private->schid, data); 1149 1149 } 1150 1150 EXPORT_SYMBOL_GPL(qdio_get_ssqd_desc); 1151 1151
+24 -9
drivers/s390/cio/qdio_setup.c
··· 243 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 254 struct chsc_ssqd_area *ssqd; 249 255 int rc; 250 256 251 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 262 memset(ssqd, 0, PAGE_SIZE); 254 263 255 264 ssqd->request = (struct chsc_header) { 256 265 .length = 0x0010, 257 266 .code = 0x0024, 258 267 }; 259 - ssqd->first_sch = irq_ptr->schid.sch_no; 260 - ssqd->last_sch = irq_ptr->schid.sch_no; 261 - ssqd->ssid = irq_ptr->schid.ssid; 268 + ssqd->first_sch = schid->sch_no; 269 + ssqd->last_sch = schid->sch_no; 270 + ssqd->ssid = schid->ssid; 262 271 263 272 if (chsc(ssqd)) 264 273 return -EIO; ··· 277 268 278 269 if (!(ssqd->qdio_ssqd.flags & CHSC_FLAG_QDIO_CAPABILITY) || 279 270 !(ssqd->qdio_ssqd.flags & CHSC_FLAG_VALIDITY) || 280 - (ssqd->qdio_ssqd.sch != irq_ptr->schid.sch_no)) 271 + (ssqd->qdio_ssqd.sch != schid->sch_no)) 281 272 return -EINVAL; 282 273 283 - memcpy(&irq_ptr->ssqd_desc, &ssqd->qdio_ssqd, 284 - sizeof(struct qdio_ssqd_desc)); 274 + if (irq_ptr != NULL) 275 + memcpy(&irq_ptr->ssqd_desc, &ssqd->qdio_ssqd, 276 + sizeof(struct qdio_ssqd_desc)); 277 + else { 278 + memcpy(data, &ssqd->qdio_ssqd, 279 + sizeof(struct qdio_ssqd_desc)); 280 + free_page((unsigned long)ssqd); 281 + } 285 282 return 0; 286 283 } 287 284 ··· 297 282 char dbf_text[15]; 298 283 int rc; 299 284 300 - rc = __get_ssqd_info(irq_ptr); 285 + rc = qdio_setup_get_ssqd(irq_ptr, &irq_ptr->schid, NULL); 301 286 if (rc) { 302 287 QDIO_DBF_TEXT2(0, setup, "ssqdasig"); 303 288 sprintf(dbf_text, "schn%4x", irq_ptr->schid.sch_no);
+11 -4
drivers/s390/net/qeth_core_main.c
··· 3757 3757 3758 3758 int qeth_core_hardsetup_card(struct qeth_card *card) 3759 3759 { 3760 - struct qdio_ssqd_desc *qdio_ssqd; 3760 + struct qdio_ssqd_desc *ssqd; 3761 3761 int retries = 3; 3762 3762 int mpno = 0; 3763 3763 int rc; ··· 3792 3792 return rc; 3793 3793 } 3794 3794 3795 - qdio_ssqd = qdio_get_ssqd_desc(CARD_DDEV(card)); 3796 - if (qdio_ssqd) 3797 - mpno = qdio_ssqd->pcnt; 3795 + ssqd = kmalloc(sizeof(struct qdio_ssqd_desc), GFP_KERNEL); 3796 + if (!ssqd) { 3797 + rc = -ENOMEM; 3798 + goto out; 3799 + } 3800 + rc = qdio_get_ssqd_desc(CARD_DDEV(card), ssqd); 3801 + if (rc == 0) 3802 + mpno = ssqd->pcnt; 3803 + kfree(ssqd); 3804 + 3798 3805 if (mpno) 3799 3806 mpno = min(mpno - 1, QETH_MAX_PORTNO); 3800 3807 if (card->info.portno > mpno) {