[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_SYNC_OUTPUT		0x02 | ||||||
| #define QDIO_FLAG_PCI_OUT		0x10 | #define QDIO_FLAG_PCI_OUT		0x10 | ||||||
| 
 | 
 | ||||||
| extern int qdio_initialize(struct qdio_initialize *init_data); | extern int qdio_initialize(struct qdio_initialize *); | ||||||
| extern int qdio_allocate(struct qdio_initialize *init_data); | extern int qdio_allocate(struct qdio_initialize *); | ||||||
| extern int qdio_establish(struct qdio_initialize *init_data); | extern int qdio_establish(struct qdio_initialize *); | ||||||
| extern int qdio_activate(struct ccw_device *); | extern int qdio_activate(struct ccw_device *); | ||||||
| 
 | 
 | ||||||
| extern int do_QDIO(struct ccw_device*, unsigned int flags, | extern int do_QDIO(struct ccw_device *cdev, unsigned int callflags, | ||||||
| 		   int q_nr, int qidx, int count); | 		   int q_nr, int bufnr, int count); | ||||||
| extern int qdio_cleanup(struct ccw_device*, int how); | extern int qdio_cleanup(struct ccw_device*, int); | ||||||
| extern int qdio_shutdown(struct ccw_device*, int how); | extern int qdio_shutdown(struct ccw_device*, int); | ||||||
| extern int qdio_free(struct ccw_device *); | 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__ */ | #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 qdio_allocate_qs(struct qdio_irq *irq_ptr, int nr_input_qs, | ||||||
| 		     int nr_output_qs); | 		     int nr_output_qs); | ||||||
| void qdio_setup_ssqd_info(struct qdio_irq *irq_ptr); | 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); | int qdio_setup_irq(struct qdio_initialize *init_data); | ||||||
| void qdio_print_subchannel_info(struct qdio_irq *irq_ptr, | void qdio_print_subchannel_info(struct qdio_irq *irq_ptr, | ||||||
| 				struct ccw_device *cdev); | 				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 |  * qdio_get_ssqd_desc - get qdio subchannel description | ||||||
|  * @cdev: ccw device to get description for |  * @cdev: ccw device to get description for | ||||||
|  |  * @data: where to store the ssqd | ||||||
|  * |  * | ||||||
|  * Returns a pointer to the saved qdio subchannel description, |  * Returns 0 or an error code. The results of the chsc are stored in the | ||||||
|  * or NULL for not setup qdio devices. |  * 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]; | 	char dbf_text[15]; | ||||||
| 
 | 
 | ||||||
|  | 	if (!cdev || !cdev->private) | ||||||
|  | 		return -EINVAL; | ||||||
|  | 
 | ||||||
| 	sprintf(dbf_text, "qssq%4x", cdev->private->schid.sch_no); | 	sprintf(dbf_text, "qssq%4x", cdev->private->schid.sch_no); | ||||||
| 	QDIO_DBF_TEXT0(0, setup, dbf_text); | 	QDIO_DBF_TEXT0(0, setup, dbf_text); | ||||||
| 
 | 
 | ||||||
| 	irq_ptr = cdev->private->qdio_data; | 	return qdio_setup_get_ssqd(NULL, &cdev->private->schid, data); | ||||||
| 	if (!irq_ptr) |  | ||||||
| 		return NULL; |  | ||||||
| 
 |  | ||||||
| 	return &irq_ptr->ssqd_desc; |  | ||||||
| } | } | ||||||
| EXPORT_SYMBOL_GPL(qdio_get_ssqd_desc); | EXPORT_SYMBOL_GPL(qdio_get_ssqd_desc); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -243,22 +243,31 @@ no_qebsm: | ||||||
| 	QDIO_DBF_TEXT0(0, setup, "noV=V"); | 	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; | 	struct chsc_ssqd_area *ssqd; | ||||||
| 	int rc; | 	int rc; | ||||||
| 
 | 
 | ||||||
| 	QDIO_DBF_TEXT0(0, setup, "getssqd"); | 	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); | 	memset(ssqd, 0, PAGE_SIZE); | ||||||
| 
 | 
 | ||||||
| 	ssqd->request = (struct chsc_header) { | 	ssqd->request = (struct chsc_header) { | ||||||
| 		.length = 0x0010, | 		.length = 0x0010, | ||||||
| 		.code	= 0x0024, | 		.code	= 0x0024, | ||||||
| 	}; | 	}; | ||||||
| 	ssqd->first_sch = irq_ptr->schid.sch_no; | 	ssqd->first_sch = schid->sch_no; | ||||||
| 	ssqd->last_sch = irq_ptr->schid.sch_no; | 	ssqd->last_sch = schid->sch_no; | ||||||
| 	ssqd->ssid = irq_ptr->schid.ssid; | 	ssqd->ssid = schid->ssid; | ||||||
| 
 | 
 | ||||||
| 	if (chsc(ssqd)) | 	if (chsc(ssqd)) | ||||||
| 		return -EIO; | 		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) || | 	if (!(ssqd->qdio_ssqd.flags & CHSC_FLAG_QDIO_CAPABILITY) || | ||||||
| 	    !(ssqd->qdio_ssqd.flags & CHSC_FLAG_VALIDITY) || | 	    !(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; | 		return -EINVAL; | ||||||
| 
 | 
 | ||||||
| 	memcpy(&irq_ptr->ssqd_desc, &ssqd->qdio_ssqd, | 	if (irq_ptr != NULL) | ||||||
| 	       sizeof(struct qdio_ssqd_desc)); | 		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; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -282,7 +297,7 @@ void qdio_setup_ssqd_info(struct qdio_irq *irq_ptr) | ||||||
| 	char dbf_text[15]; | 	char dbf_text[15]; | ||||||
| 	int rc; | 	int rc; | ||||||
| 
 | 
 | ||||||
| 	rc = __get_ssqd_info(irq_ptr); | 	rc = qdio_setup_get_ssqd(irq_ptr, &irq_ptr->schid, NULL); | ||||||
| 	if (rc) { | 	if (rc) { | ||||||
| 		QDIO_DBF_TEXT2(0, setup, "ssqdasig"); | 		QDIO_DBF_TEXT2(0, setup, "ssqdasig"); | ||||||
| 		sprintf(dbf_text, "schn%4x", irq_ptr->schid.sch_no); | 		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) | int qeth_core_hardsetup_card(struct qeth_card *card) | ||||||
| { | { | ||||||
| 	struct qdio_ssqd_desc *qdio_ssqd; | 	struct qdio_ssqd_desc *ssqd; | ||||||
| 	int retries = 3; | 	int retries = 3; | ||||||
| 	int mpno = 0; | 	int mpno = 0; | ||||||
| 	int rc; | 	int rc; | ||||||
|  | @ -3792,9 +3792,16 @@ retry: | ||||||
| 		return rc; | 		return rc; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	qdio_ssqd = qdio_get_ssqd_desc(CARD_DDEV(card)); | 	ssqd = kmalloc(sizeof(struct qdio_ssqd_desc), GFP_KERNEL); | ||||||
| 	if (qdio_ssqd) | 	if (!ssqd) { | ||||||
| 		mpno = qdio_ssqd->pcnt; | 		rc = -ENOMEM; | ||||||
|  | 		goto out; | ||||||
|  | 	} | ||||||
|  | 	rc = qdio_get_ssqd_desc(CARD_DDEV(card), ssqd); | ||||||
|  | 	if (rc == 0) | ||||||
|  | 		mpno = ssqd->pcnt; | ||||||
|  | 	kfree(ssqd); | ||||||
|  | 
 | ||||||
| 	if (mpno) | 	if (mpno) | ||||||
| 		mpno = min(mpno - 1, QETH_MAX_PORTNO); | 		mpno = min(mpno - 1, QETH_MAX_PORTNO); | ||||||
| 	if (card->info.portno > mpno) { | 	if (card->info.portno > mpno) { | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Jan Glauber
				Jan Glauber