[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>
This commit is contained in:
		
					parent
					
						
							
								43c207e6e5
							
						
					
				
			
			
				commit
				
					
						bbd50e172f
					
				
			
		
					 5 changed files with 55 additions and 30 deletions
				
			
		|  | @ -373,16 +373,16 @@ struct qdio_initialize { | |||
| #define QDIO_FLAG_SYNC_OUTPUT		0x02 | ||||
| #define QDIO_FLAG_PCI_OUT		0x10 | ||||
| 
 | ||||
| extern int qdio_initialize(struct qdio_initialize *init_data); | ||||
| extern int qdio_allocate(struct qdio_initialize *init_data); | ||||
| extern int qdio_establish(struct qdio_initialize *init_data); | ||||
| extern int qdio_initialize(struct qdio_initialize *); | ||||
| extern int qdio_allocate(struct qdio_initialize *); | ||||
| extern int qdio_establish(struct qdio_initialize *); | ||||
| extern int qdio_activate(struct ccw_device *); | ||||
| 
 | ||||
| extern int do_QDIO(struct ccw_device*, unsigned int flags, | ||||
| 		   int q_nr, int qidx, int count); | ||||
| extern int qdio_cleanup(struct ccw_device*, int how); | ||||
| extern int qdio_shutdown(struct ccw_device*, int how); | ||||
| extern int do_QDIO(struct ccw_device *cdev, unsigned int callflags, | ||||
| 		   int q_nr, int bufnr, int count); | ||||
| extern int qdio_cleanup(struct ccw_device*, int); | ||||
| extern int qdio_shutdown(struct ccw_device*, int); | ||||
| extern int qdio_free(struct ccw_device *); | ||||
| extern struct qdio_ssqd_desc *qdio_get_ssqd_desc(struct ccw_device *cdev); | ||||
| extern int qdio_get_ssqd_desc(struct ccw_device *dev, struct qdio_ssqd_desc*); | ||||
| 
 | ||||
| #endif /* __QDIO_H__ */ | ||||
|  |  | |||
|  | @ -378,6 +378,9 @@ void qdio_int_handler(struct ccw_device *cdev, unsigned long intparm, | |||
| int qdio_allocate_qs(struct qdio_irq *irq_ptr, int nr_input_qs, | ||||
| 		     int nr_output_qs); | ||||
| void qdio_setup_ssqd_info(struct qdio_irq *irq_ptr); | ||||
| int qdio_setup_get_ssqd(struct qdio_irq *irq_ptr, | ||||
| 			struct subchannel_id *schid, | ||||
| 			struct qdio_ssqd_desc *data); | ||||
| int qdio_setup_irq(struct qdio_initialize *init_data); | ||||
| void qdio_print_subchannel_info(struct qdio_irq *irq_ptr, | ||||
| 				struct ccw_device *cdev); | ||||
|  |  | |||
|  | @ -1129,23 +1129,23 @@ void qdio_int_handler(struct ccw_device *cdev, unsigned long intparm, | |||
| /**
 | ||||
|  * qdio_get_ssqd_desc - get qdio subchannel description | ||||
|  * @cdev: ccw device to get description for | ||||
|  * @data: where to store the ssqd | ||||
|  * | ||||
|  * Returns a pointer to the saved qdio subchannel description, | ||||
|  * or NULL for not setup qdio devices. | ||||
|  * Returns 0 or an error code. The results of the chsc are stored in the | ||||
|  * specified structure. | ||||
|  */ | ||||
| struct qdio_ssqd_desc *qdio_get_ssqd_desc(struct ccw_device *cdev) | ||||
| int qdio_get_ssqd_desc(struct ccw_device *cdev, | ||||
| 		       struct qdio_ssqd_desc *data) | ||||
| { | ||||
| 	struct qdio_irq *irq_ptr; | ||||
| 	char dbf_text[15]; | ||||
| 
 | ||||
| 	if (!cdev || !cdev->private) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	sprintf(dbf_text, "qssq%4x", cdev->private->schid.sch_no); | ||||
| 	QDIO_DBF_TEXT0(0, setup, dbf_text); | ||||
| 
 | ||||
| 	irq_ptr = cdev->private->qdio_data; | ||||
| 	if (!irq_ptr) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	return &irq_ptr->ssqd_desc; | ||||
| 	return qdio_setup_get_ssqd(NULL, &cdev->private->schid, data); | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(qdio_get_ssqd_desc); | ||||
| 
 | ||||
|  |  | |||
|  | @ -243,22 +243,31 @@ no_qebsm: | |||
| 	QDIO_DBF_TEXT0(0, setup, "noV=V"); | ||||
| } | ||||
| 
 | ||||
| static int __get_ssqd_info(struct qdio_irq *irq_ptr) | ||||
| /*
 | ||||
|  * If there is a qdio_irq we use the chsc_page and store the information | ||||
|  * in the qdio_irq, otherwise we copy it to the specified structure. | ||||
|  */ | ||||
| int qdio_setup_get_ssqd(struct qdio_irq *irq_ptr, | ||||
| 			struct subchannel_id *schid, | ||||
| 			struct qdio_ssqd_desc *data) | ||||
| { | ||||
| 	struct chsc_ssqd_area *ssqd; | ||||
| 	int rc; | ||||
| 
 | ||||
| 	QDIO_DBF_TEXT0(0, setup, "getssqd"); | ||||
| 	ssqd = (struct chsc_ssqd_area *)irq_ptr->chsc_page; | ||||
| 	if (irq_ptr != NULL) | ||||
| 		ssqd = (struct chsc_ssqd_area *)irq_ptr->chsc_page; | ||||
| 	else | ||||
| 		ssqd = (struct chsc_ssqd_area *)__get_free_page(GFP_KERNEL); | ||||
| 	memset(ssqd, 0, PAGE_SIZE); | ||||
| 
 | ||||
| 	ssqd->request = (struct chsc_header) { | ||||
| 		.length = 0x0010, | ||||
| 		.code	= 0x0024, | ||||
| 	}; | ||||
| 	ssqd->first_sch = irq_ptr->schid.sch_no; | ||||
| 	ssqd->last_sch = irq_ptr->schid.sch_no; | ||||
| 	ssqd->ssid = irq_ptr->schid.ssid; | ||||
| 	ssqd->first_sch = schid->sch_no; | ||||
| 	ssqd->last_sch = schid->sch_no; | ||||
| 	ssqd->ssid = schid->ssid; | ||||
| 
 | ||||
| 	if (chsc(ssqd)) | ||||
| 		return -EIO; | ||||
|  | @ -268,11 +277,17 @@ static int __get_ssqd_info(struct qdio_irq *irq_ptr) | |||
| 
 | ||||
| 	if (!(ssqd->qdio_ssqd.flags & CHSC_FLAG_QDIO_CAPABILITY) || | ||||
| 	    !(ssqd->qdio_ssqd.flags & CHSC_FLAG_VALIDITY) || | ||||
| 	    (ssqd->qdio_ssqd.sch != irq_ptr->schid.sch_no)) | ||||
| 	    (ssqd->qdio_ssqd.sch != schid->sch_no)) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	memcpy(&irq_ptr->ssqd_desc, &ssqd->qdio_ssqd, | ||||
| 	       sizeof(struct qdio_ssqd_desc)); | ||||
| 	if (irq_ptr != NULL) | ||||
| 		memcpy(&irq_ptr->ssqd_desc, &ssqd->qdio_ssqd, | ||||
| 		       sizeof(struct qdio_ssqd_desc)); | ||||
| 	else { | ||||
| 		memcpy(data, &ssqd->qdio_ssqd, | ||||
| 		       sizeof(struct qdio_ssqd_desc)); | ||||
| 		free_page((unsigned long)ssqd); | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
|  | @ -282,7 +297,7 @@ void qdio_setup_ssqd_info(struct qdio_irq *irq_ptr) | |||
| 	char dbf_text[15]; | ||||
| 	int rc; | ||||
| 
 | ||||
| 	rc = __get_ssqd_info(irq_ptr); | ||||
| 	rc = qdio_setup_get_ssqd(irq_ptr, &irq_ptr->schid, NULL); | ||||
| 	if (rc) { | ||||
| 		QDIO_DBF_TEXT2(0, setup, "ssqdasig"); | ||||
| 		sprintf(dbf_text, "schn%4x", irq_ptr->schid.sch_no); | ||||
|  |  | |||
|  | @ -3757,7 +3757,7 @@ static int qeth_core_driver_group(const char *buf, struct device *root_dev, | |||
| 
 | ||||
| int qeth_core_hardsetup_card(struct qeth_card *card) | ||||
| { | ||||
| 	struct qdio_ssqd_desc *qdio_ssqd; | ||||
| 	struct qdio_ssqd_desc *ssqd; | ||||
| 	int retries = 3; | ||||
| 	int mpno = 0; | ||||
| 	int rc; | ||||
|  | @ -3792,9 +3792,16 @@ retry: | |||
| 		return rc; | ||||
| 	} | ||||
| 
 | ||||
| 	qdio_ssqd = qdio_get_ssqd_desc(CARD_DDEV(card)); | ||||
| 	if (qdio_ssqd) | ||||
| 		mpno = qdio_ssqd->pcnt; | ||||
| 	ssqd = kmalloc(sizeof(struct qdio_ssqd_desc), GFP_KERNEL); | ||||
| 	if (!ssqd) { | ||||
| 		rc = -ENOMEM; | ||||
| 		goto out; | ||||
| 	} | ||||
| 	rc = qdio_get_ssqd_desc(CARD_DDEV(card), ssqd); | ||||
| 	if (rc == 0) | ||||
| 		mpno = ssqd->pcnt; | ||||
| 	kfree(ssqd); | ||||
| 
 | ||||
| 	if (mpno) | ||||
| 		mpno = min(mpno - 1, QETH_MAX_PORTNO); | ||||
| 	if (card->info.portno > mpno) { | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Jan Glauber
				Jan Glauber