diff options
author | Frank Haverkamp <haver@linux.vnet.ibm.com> | 2014-09-10 10:37:53 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-09-24 02:15:47 -0400 |
commit | 1451f414639465995dfc1f820aa1a64723cbd662 (patch) | |
tree | d1983ab9e5d532368ad82261295a78c114fa8514 | |
parent | 08e4906cc29d092ae2da0ff089efe1488e584d3c (diff) |
GenWQE: Support blocking when DDCB queue is busy
When the GenWQE hardware queue was busy, the driver returned simply
-EBUSY. This caused polling by applications which increased the load
on the already busy system. This change implements the possiblity to
sleep on a waitqueue instead when the DDCB queue is busy. The
requestor is woken up when there is free space on the queue again.
The old way to get -EBUSY is still available if the device is openend
with O_NONBLOCKING. The default is now blocking behavior.
Signed-off-by: Frank Haverkamp <haver@linux.vnet.ibm.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/misc/genwqe/card_base.h | 17 | ||||
-rw-r--r-- | drivers/misc/genwqe/card_ddcb.c | 44 | ||||
-rw-r--r-- | drivers/misc/genwqe/card_debugfs.c | 6 | ||||
-rw-r--r-- | drivers/misc/genwqe/card_dev.c | 12 |
4 files changed, 57 insertions, 22 deletions
diff --git a/drivers/misc/genwqe/card_base.h b/drivers/misc/genwqe/card_base.h index b622d204b72b..c64d7cad1085 100644 --- a/drivers/misc/genwqe/card_base.h +++ b/drivers/misc/genwqe/card_base.h | |||
@@ -201,7 +201,8 @@ static inline void genwqe_mapping_init(struct dma_mapping *m, | |||
201 | * @ddcb_seq: Sequence number of last DDCB | 201 | * @ddcb_seq: Sequence number of last DDCB |
202 | * @ddcbs_in_flight: Currently enqueued DDCBs | 202 | * @ddcbs_in_flight: Currently enqueued DDCBs |
203 | * @ddcbs_completed: Number of already completed DDCBs | 203 | * @ddcbs_completed: Number of already completed DDCBs |
204 | * @busy: Number of -EBUSY returns | 204 | * @return_on_busy: Number of -EBUSY returns on full queue |
205 | * @wait_on_busy: Number of waits on full queue | ||
205 | * @ddcb_daddr: DMA address of first DDCB in the queue | 206 | * @ddcb_daddr: DMA address of first DDCB in the queue |
206 | * @ddcb_vaddr: Kernel virtual address of first DDCB in the queue | 207 | * @ddcb_vaddr: Kernel virtual address of first DDCB in the queue |
207 | * @ddcb_req: Associated requests (one per DDCB) | 208 | * @ddcb_req: Associated requests (one per DDCB) |
@@ -218,7 +219,8 @@ struct ddcb_queue { | |||
218 | unsigned int ddcbs_in_flight; /* number of ddcbs in processing */ | 219 | unsigned int ddcbs_in_flight; /* number of ddcbs in processing */ |
219 | unsigned int ddcbs_completed; | 220 | unsigned int ddcbs_completed; |
220 | unsigned int ddcbs_max_in_flight; | 221 | unsigned int ddcbs_max_in_flight; |
221 | unsigned int busy; /* how many times -EBUSY? */ | 222 | unsigned int return_on_busy; /* how many times -EBUSY? */ |
223 | unsigned int wait_on_busy; | ||
222 | 224 | ||
223 | dma_addr_t ddcb_daddr; /* DMA address */ | 225 | dma_addr_t ddcb_daddr; /* DMA address */ |
224 | struct ddcb *ddcb_vaddr; /* kernel virtual addr for DDCBs */ | 226 | struct ddcb *ddcb_vaddr; /* kernel virtual addr for DDCBs */ |
@@ -226,7 +228,7 @@ struct ddcb_queue { | |||
226 | wait_queue_head_t *ddcb_waitqs; /* waitqueue per ddcb */ | 228 | wait_queue_head_t *ddcb_waitqs; /* waitqueue per ddcb */ |
227 | 229 | ||
228 | spinlock_t ddcb_lock; /* exclusive access to queue */ | 230 | spinlock_t ddcb_lock; /* exclusive access to queue */ |
229 | wait_queue_head_t ddcb_waitq; /* wait for ddcb processing */ | 231 | wait_queue_head_t busy_waitq; /* wait for ddcb processing */ |
230 | 232 | ||
231 | /* registers or the respective queue to be used */ | 233 | /* registers or the respective queue to be used */ |
232 | u32 IO_QUEUE_CONFIG; | 234 | u32 IO_QUEUE_CONFIG; |
@@ -508,7 +510,7 @@ static inline bool dma_mapping_used(struct dma_mapping *m) | |||
508 | * buildup and teardown. | 510 | * buildup and teardown. |
509 | */ | 511 | */ |
510 | int __genwqe_execute_ddcb(struct genwqe_dev *cd, | 512 | int __genwqe_execute_ddcb(struct genwqe_dev *cd, |
511 | struct genwqe_ddcb_cmd *cmd); | 513 | struct genwqe_ddcb_cmd *cmd, unsigned int f_flags); |
512 | 514 | ||
513 | /** | 515 | /** |
514 | * __genwqe_execute_raw_ddcb() - Execute DDCB request without addr translation | 516 | * __genwqe_execute_raw_ddcb() - Execute DDCB request without addr translation |
@@ -520,9 +522,12 @@ int __genwqe_execute_ddcb(struct genwqe_dev *cd, | |||
520 | * modification. | 522 | * modification. |
521 | */ | 523 | */ |
522 | int __genwqe_execute_raw_ddcb(struct genwqe_dev *cd, | 524 | int __genwqe_execute_raw_ddcb(struct genwqe_dev *cd, |
523 | struct genwqe_ddcb_cmd *cmd); | 525 | struct genwqe_ddcb_cmd *cmd, |
526 | unsigned int f_flags); | ||
527 | int __genwqe_enqueue_ddcb(struct genwqe_dev *cd, | ||
528 | struct ddcb_requ *req, | ||
529 | unsigned int f_flags); | ||
524 | 530 | ||
525 | int __genwqe_enqueue_ddcb(struct genwqe_dev *cd, struct ddcb_requ *req); | ||
526 | int __genwqe_wait_ddcb(struct genwqe_dev *cd, struct ddcb_requ *req); | 531 | int __genwqe_wait_ddcb(struct genwqe_dev *cd, struct ddcb_requ *req); |
527 | int __genwqe_purge_ddcb(struct genwqe_dev *cd, struct ddcb_requ *req); | 532 | int __genwqe_purge_ddcb(struct genwqe_dev *cd, struct ddcb_requ *req); |
528 | 533 | ||
diff --git a/drivers/misc/genwqe/card_ddcb.c b/drivers/misc/genwqe/card_ddcb.c index 51480e4f8054..6d51e5f08664 100644 --- a/drivers/misc/genwqe/card_ddcb.c +++ b/drivers/misc/genwqe/card_ddcb.c | |||
@@ -448,8 +448,10 @@ static int genwqe_check_ddcb_queue(struct genwqe_dev *cd, | |||
448 | queue->ddcbs_completed++; | 448 | queue->ddcbs_completed++; |
449 | queue->ddcbs_in_flight--; | 449 | queue->ddcbs_in_flight--; |
450 | 450 | ||
451 | /* wake up process waiting for this DDCB */ | 451 | /* wake up process waiting for this DDCB, and |
452 | processes on the busy queue */ | ||
452 | wake_up_interruptible(&queue->ddcb_waitqs[queue->ddcb_act]); | 453 | wake_up_interruptible(&queue->ddcb_waitqs[queue->ddcb_act]); |
454 | wake_up_interruptible(&queue->busy_waitq); | ||
453 | 455 | ||
454 | pick_next_one: | 456 | pick_next_one: |
455 | queue->ddcb_act = (queue->ddcb_act + 1) % queue->ddcb_max; | 457 | queue->ddcb_act = (queue->ddcb_act + 1) % queue->ddcb_max; |
@@ -745,14 +747,16 @@ int genwqe_init_debug_data(struct genwqe_dev *cd, struct genwqe_debug_data *d) | |||
745 | 747 | ||
746 | /** | 748 | /** |
747 | * __genwqe_enqueue_ddcb() - Enqueue a DDCB | 749 | * __genwqe_enqueue_ddcb() - Enqueue a DDCB |
748 | * @cd: pointer to genwqe device descriptor | 750 | * @cd: pointer to genwqe device descriptor |
749 | * @req: pointer to DDCB execution request | 751 | * @req: pointer to DDCB execution request |
752 | * @f_flags: file mode: blocking, non-blocking | ||
750 | * | 753 | * |
751 | * Return: 0 if enqueuing succeeded | 754 | * Return: 0 if enqueuing succeeded |
752 | * -EIO if card is unusable/PCIe problems | 755 | * -EIO if card is unusable/PCIe problems |
753 | * -EBUSY if enqueuing failed | 756 | * -EBUSY if enqueuing failed |
754 | */ | 757 | */ |
755 | int __genwqe_enqueue_ddcb(struct genwqe_dev *cd, struct ddcb_requ *req) | 758 | int __genwqe_enqueue_ddcb(struct genwqe_dev *cd, struct ddcb_requ *req, |
759 | unsigned int f_flags) | ||
756 | { | 760 | { |
757 | struct ddcb *pddcb; | 761 | struct ddcb *pddcb; |
758 | unsigned long flags; | 762 | unsigned long flags; |
@@ -760,6 +764,7 @@ int __genwqe_enqueue_ddcb(struct genwqe_dev *cd, struct ddcb_requ *req) | |||
760 | struct pci_dev *pci_dev = cd->pci_dev; | 764 | struct pci_dev *pci_dev = cd->pci_dev; |
761 | u16 icrc; | 765 | u16 icrc; |
762 | 766 | ||
767 | retry: | ||
763 | if (cd->card_state != GENWQE_CARD_USED) { | 768 | if (cd->card_state != GENWQE_CARD_USED) { |
764 | printk_ratelimited(KERN_ERR | 769 | printk_ratelimited(KERN_ERR |
765 | "%s %s: [%s] Card is unusable/PCIe problem Req#%d\n", | 770 | "%s %s: [%s] Card is unusable/PCIe problem Req#%d\n", |
@@ -785,9 +790,24 @@ int __genwqe_enqueue_ddcb(struct genwqe_dev *cd, struct ddcb_requ *req) | |||
785 | 790 | ||
786 | pddcb = get_next_ddcb(cd, queue, &req->num); /* get ptr and num */ | 791 | pddcb = get_next_ddcb(cd, queue, &req->num); /* get ptr and num */ |
787 | if (pddcb == NULL) { | 792 | if (pddcb == NULL) { |
793 | int rc; | ||
794 | |||
788 | spin_unlock_irqrestore(&queue->ddcb_lock, flags); | 795 | spin_unlock_irqrestore(&queue->ddcb_lock, flags); |
789 | queue->busy++; | 796 | |
790 | return -EBUSY; | 797 | if (f_flags & O_NONBLOCK) { |
798 | queue->return_on_busy++; | ||
799 | return -EBUSY; | ||
800 | } | ||
801 | |||
802 | queue->wait_on_busy++; | ||
803 | rc = wait_event_interruptible(queue->busy_waitq, | ||
804 | queue_free_ddcbs(queue) != 0); | ||
805 | dev_dbg(&pci_dev->dev, "[%s] waiting for free DDCB: rc=%d\n", | ||
806 | __func__, rc); | ||
807 | if (rc == -ERESTARTSYS) | ||
808 | return rc; /* interrupted by a signal */ | ||
809 | |||
810 | goto retry; | ||
791 | } | 811 | } |
792 | 812 | ||
793 | if (queue->ddcb_req[req->num] != NULL) { | 813 | if (queue->ddcb_req[req->num] != NULL) { |
@@ -890,9 +910,11 @@ int __genwqe_enqueue_ddcb(struct genwqe_dev *cd, struct ddcb_requ *req) | |||
890 | * __genwqe_execute_raw_ddcb() - Setup and execute DDCB | 910 | * __genwqe_execute_raw_ddcb() - Setup and execute DDCB |
891 | * @cd: pointer to genwqe device descriptor | 911 | * @cd: pointer to genwqe device descriptor |
892 | * @req: user provided DDCB request | 912 | * @req: user provided DDCB request |
913 | * @f_flags: file mode: blocking, non-blocking | ||
893 | */ | 914 | */ |
894 | int __genwqe_execute_raw_ddcb(struct genwqe_dev *cd, | 915 | int __genwqe_execute_raw_ddcb(struct genwqe_dev *cd, |
895 | struct genwqe_ddcb_cmd *cmd) | 916 | struct genwqe_ddcb_cmd *cmd, |
917 | unsigned int f_flags) | ||
896 | { | 918 | { |
897 | int rc = 0; | 919 | int rc = 0; |
898 | struct pci_dev *pci_dev = cd->pci_dev; | 920 | struct pci_dev *pci_dev = cd->pci_dev; |
@@ -908,7 +930,7 @@ int __genwqe_execute_raw_ddcb(struct genwqe_dev *cd, | |||
908 | __func__, cmd->asiv_length); | 930 | __func__, cmd->asiv_length); |
909 | return -EINVAL; | 931 | return -EINVAL; |
910 | } | 932 | } |
911 | rc = __genwqe_enqueue_ddcb(cd, req); | 933 | rc = __genwqe_enqueue_ddcb(cd, req, f_flags); |
912 | if (rc != 0) | 934 | if (rc != 0) |
913 | return rc; | 935 | return rc; |
914 | 936 | ||
@@ -1014,7 +1036,8 @@ static int setup_ddcb_queue(struct genwqe_dev *cd, struct ddcb_queue *queue) | |||
1014 | queue->ddcbs_in_flight = 0; /* statistics */ | 1036 | queue->ddcbs_in_flight = 0; /* statistics */ |
1015 | queue->ddcbs_max_in_flight = 0; | 1037 | queue->ddcbs_max_in_flight = 0; |
1016 | queue->ddcbs_completed = 0; | 1038 | queue->ddcbs_completed = 0; |
1017 | queue->busy = 0; | 1039 | queue->return_on_busy = 0; |
1040 | queue->wait_on_busy = 0; | ||
1018 | 1041 | ||
1019 | queue->ddcb_seq = 0x100; /* start sequence number */ | 1042 | queue->ddcb_seq = 0x100; /* start sequence number */ |
1020 | queue->ddcb_max = genwqe_ddcb_max; /* module parameter */ | 1043 | queue->ddcb_max = genwqe_ddcb_max; /* module parameter */ |
@@ -1054,7 +1077,7 @@ static int setup_ddcb_queue(struct genwqe_dev *cd, struct ddcb_queue *queue) | |||
1054 | queue->ddcb_next = 0; /* queue is empty */ | 1077 | queue->ddcb_next = 0; /* queue is empty */ |
1055 | 1078 | ||
1056 | spin_lock_init(&queue->ddcb_lock); | 1079 | spin_lock_init(&queue->ddcb_lock); |
1057 | init_waitqueue_head(&queue->ddcb_waitq); | 1080 | init_waitqueue_head(&queue->busy_waitq); |
1058 | 1081 | ||
1059 | val64 = ((u64)(queue->ddcb_max - 1) << 8); /* lastptr */ | 1082 | val64 = ((u64)(queue->ddcb_max - 1) << 8); /* lastptr */ |
1060 | __genwqe_writeq(cd, queue->IO_QUEUE_CONFIG, 0x07); /* iCRC/vCRC */ | 1083 | __genwqe_writeq(cd, queue->IO_QUEUE_CONFIG, 0x07); /* iCRC/vCRC */ |
@@ -1302,6 +1325,7 @@ static int queue_wake_up_all(struct genwqe_dev *cd) | |||
1302 | for (i = 0; i < queue->ddcb_max; i++) | 1325 | for (i = 0; i < queue->ddcb_max; i++) |
1303 | wake_up_interruptible(&queue->ddcb_waitqs[queue->ddcb_act]); | 1326 | wake_up_interruptible(&queue->ddcb_waitqs[queue->ddcb_act]); |
1304 | 1327 | ||
1328 | wake_up_interruptible(&queue->busy_waitq); | ||
1305 | spin_unlock_irqrestore(&queue->ddcb_lock, flags); | 1329 | spin_unlock_irqrestore(&queue->ddcb_lock, flags); |
1306 | 1330 | ||
1307 | return 0; | 1331 | return 0; |
diff --git a/drivers/misc/genwqe/card_debugfs.c b/drivers/misc/genwqe/card_debugfs.c index 40b425d35866..c715534e7fe7 100644 --- a/drivers/misc/genwqe/card_debugfs.c +++ b/drivers/misc/genwqe/card_debugfs.c | |||
@@ -244,14 +244,16 @@ static int genwqe_ddcb_info_show(struct seq_file *s, void *unused) | |||
244 | " ddcbs_in_flight: %u\n" | 244 | " ddcbs_in_flight: %u\n" |
245 | " ddcbs_max_in_flight: %u\n" | 245 | " ddcbs_max_in_flight: %u\n" |
246 | " ddcbs_completed: %u\n" | 246 | " ddcbs_completed: %u\n" |
247 | " busy: %u\n" | 247 | " return_on_busy: %u\n" |
248 | " wait_on_busy: %u\n" | ||
248 | " irqs_processed: %u\n", | 249 | " irqs_processed: %u\n", |
249 | queue->ddcb_max, (long long)queue->ddcb_daddr, | 250 | queue->ddcb_max, (long long)queue->ddcb_daddr, |
250 | (long long)queue->ddcb_daddr + | 251 | (long long)queue->ddcb_daddr + |
251 | (queue->ddcb_max * DDCB_LENGTH), | 252 | (queue->ddcb_max * DDCB_LENGTH), |
252 | (long long)queue->ddcb_vaddr, queue->ddcbs_in_flight, | 253 | (long long)queue->ddcb_vaddr, queue->ddcbs_in_flight, |
253 | queue->ddcbs_max_in_flight, queue->ddcbs_completed, | 254 | queue->ddcbs_max_in_flight, queue->ddcbs_completed, |
254 | queue->busy, cd->irqs_processed); | 255 | queue->return_on_busy, queue->wait_on_busy, |
256 | cd->irqs_processed); | ||
255 | 257 | ||
256 | /* Hardware State */ | 258 | /* Hardware State */ |
257 | seq_printf(s, " 0x%08x 0x%016llx IO_QUEUE_CONFIG\n" | 259 | seq_printf(s, " 0x%08x 0x%016llx IO_QUEUE_CONFIG\n" |
diff --git a/drivers/misc/genwqe/card_dev.c b/drivers/misc/genwqe/card_dev.c index 59e0081acc8f..5918586f2f76 100644 --- a/drivers/misc/genwqe/card_dev.c +++ b/drivers/misc/genwqe/card_dev.c | |||
@@ -516,6 +516,7 @@ static int do_flash_update(struct genwqe_file *cfile, | |||
516 | u32 crc; | 516 | u32 crc; |
517 | u8 cmdopts; | 517 | u8 cmdopts; |
518 | struct genwqe_dev *cd = cfile->cd; | 518 | struct genwqe_dev *cd = cfile->cd; |
519 | struct file *filp = cfile->filp; | ||
519 | struct pci_dev *pci_dev = cd->pci_dev; | 520 | struct pci_dev *pci_dev = cd->pci_dev; |
520 | 521 | ||
521 | if ((load->size & 0x3) != 0) | 522 | if ((load->size & 0x3) != 0) |
@@ -610,7 +611,7 @@ static int do_flash_update(struct genwqe_file *cfile, | |||
610 | /* For Genwqe5 we get back the calculated CRC */ | 611 | /* For Genwqe5 we get back the calculated CRC */ |
611 | *(u64 *)&req->asv[0] = 0ULL; /* 0x80 */ | 612 | *(u64 *)&req->asv[0] = 0ULL; /* 0x80 */ |
612 | 613 | ||
613 | rc = __genwqe_execute_raw_ddcb(cd, req); | 614 | rc = __genwqe_execute_raw_ddcb(cd, req, filp->f_flags); |
614 | 615 | ||
615 | load->retc = req->retc; | 616 | load->retc = req->retc; |
616 | load->attn = req->attn; | 617 | load->attn = req->attn; |
@@ -650,6 +651,7 @@ static int do_flash_read(struct genwqe_file *cfile, | |||
650 | u8 *xbuf; | 651 | u8 *xbuf; |
651 | u8 cmdopts; | 652 | u8 cmdopts; |
652 | struct genwqe_dev *cd = cfile->cd; | 653 | struct genwqe_dev *cd = cfile->cd; |
654 | struct file *filp = cfile->filp; | ||
653 | struct pci_dev *pci_dev = cd->pci_dev; | 655 | struct pci_dev *pci_dev = cd->pci_dev; |
654 | struct genwqe_ddcb_cmd *cmd; | 656 | struct genwqe_ddcb_cmd *cmd; |
655 | 657 | ||
@@ -727,7 +729,7 @@ static int do_flash_read(struct genwqe_file *cfile, | |||
727 | /* we only get back the calculated CRC */ | 729 | /* we only get back the calculated CRC */ |
728 | *(u64 *)&cmd->asv[0] = 0ULL; /* 0x80 */ | 730 | *(u64 *)&cmd->asv[0] = 0ULL; /* 0x80 */ |
729 | 731 | ||
730 | rc = __genwqe_execute_raw_ddcb(cd, cmd); | 732 | rc = __genwqe_execute_raw_ddcb(cd, cmd, filp->f_flags); |
731 | 733 | ||
732 | load->retc = cmd->retc; | 734 | load->retc = cmd->retc; |
733 | load->attn = cmd->attn; | 735 | load->attn = cmd->attn; |
@@ -988,13 +990,14 @@ static int genwqe_execute_ddcb(struct genwqe_file *cfile, | |||
988 | { | 990 | { |
989 | int rc; | 991 | int rc; |
990 | struct genwqe_dev *cd = cfile->cd; | 992 | struct genwqe_dev *cd = cfile->cd; |
993 | struct file *filp = cfile->filp; | ||
991 | struct ddcb_requ *req = container_of(cmd, struct ddcb_requ, cmd); | 994 | struct ddcb_requ *req = container_of(cmd, struct ddcb_requ, cmd); |
992 | 995 | ||
993 | rc = ddcb_cmd_fixups(cfile, req); | 996 | rc = ddcb_cmd_fixups(cfile, req); |
994 | if (rc != 0) | 997 | if (rc != 0) |
995 | return rc; | 998 | return rc; |
996 | 999 | ||
997 | rc = __genwqe_execute_raw_ddcb(cd, cmd); | 1000 | rc = __genwqe_execute_raw_ddcb(cd, cmd, filp->f_flags); |
998 | ddcb_cmd_cleanup(cfile, req); | 1001 | ddcb_cmd_cleanup(cfile, req); |
999 | return rc; | 1002 | return rc; |
1000 | } | 1003 | } |
@@ -1006,6 +1009,7 @@ static int do_execute_ddcb(struct genwqe_file *cfile, | |||
1006 | struct genwqe_ddcb_cmd *cmd; | 1009 | struct genwqe_ddcb_cmd *cmd; |
1007 | struct ddcb_requ *req; | 1010 | struct ddcb_requ *req; |
1008 | struct genwqe_dev *cd = cfile->cd; | 1011 | struct genwqe_dev *cd = cfile->cd; |
1012 | struct file *filp = cfile->filp; | ||
1009 | 1013 | ||
1010 | cmd = ddcb_requ_alloc(); | 1014 | cmd = ddcb_requ_alloc(); |
1011 | if (cmd == NULL) | 1015 | if (cmd == NULL) |
@@ -1021,7 +1025,7 @@ static int do_execute_ddcb(struct genwqe_file *cfile, | |||
1021 | if (!raw) | 1025 | if (!raw) |
1022 | rc = genwqe_execute_ddcb(cfile, cmd); | 1026 | rc = genwqe_execute_ddcb(cfile, cmd); |
1023 | else | 1027 | else |
1024 | rc = __genwqe_execute_raw_ddcb(cd, cmd); | 1028 | rc = __genwqe_execute_raw_ddcb(cd, cmd, filp->f_flags); |
1025 | 1029 | ||
1026 | /* Copy back only the modifed fields. Do not copy ASIV | 1030 | /* Copy back only the modifed fields. Do not copy ASIV |
1027 | back since the copy got modified by the driver. */ | 1031 | back since the copy got modified by the driver. */ |