aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSakthivel K <Sakthivel.SaravananKamalRaju@pmcs.com>2013-03-19 08:26:17 -0400
committerJames Bottomley <JBottomley@Parallels.com>2013-05-10 10:47:47 -0400
commit1245ee5996a1270e4fd04f9c2e399521a656c930 (patch)
tree162c4e63c70363e9debe13bad3d8178238860b00
parentf74cf271e692848833b3845b4036a87e5b683fa8 (diff)
[SCSI] pm80xx: MSI-X implementation for using 64 interrupts
Implementation of interrupt handlers and tasklets to support upto 64 interrupt for the device. Signed-off-by: Sakthivel K <Sakthivel.SaravananKamalRaju@pmcs.com> Signed-off-by: Anand Kumar S <AnandKumar.Santhanam@pmcs.com> Acked-by: Jack Wang <jack_wang@usish.com> Reviewed-by: Hannes Reinecke <hare@suse.de> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
-rw-r--r--drivers/scsi/pm8001/pm8001_init.c141
-rw-r--r--drivers/scsi/pm8001/pm8001_sas.h2
2 files changed, 113 insertions, 30 deletions
diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c
index 19fbd03b4190..75270ee1a7f0 100644
--- a/drivers/scsi/pm8001/pm8001_init.c
+++ b/drivers/scsi/pm8001/pm8001_init.c
@@ -159,33 +159,71 @@ static void pm8001_free(struct pm8001_hba_info *pm8001_ha)
159} 159}
160 160
161#ifdef PM8001_USE_TASKLET 161#ifdef PM8001_USE_TASKLET
162
163/**
164 * tasklet for 64 msi-x interrupt handler
165 * @opaque: the passed general host adapter struct
166 * Note: pm8001_tasklet is common for pm8001 & pm80xx
167 */
162static void pm8001_tasklet(unsigned long opaque) 168static void pm8001_tasklet(unsigned long opaque)
163{ 169{
164 struct pm8001_hba_info *pm8001_ha; 170 struct pm8001_hba_info *pm8001_ha;
171 u32 vec;
165 pm8001_ha = (struct pm8001_hba_info *)opaque; 172 pm8001_ha = (struct pm8001_hba_info *)opaque;
166 if (unlikely(!pm8001_ha)) 173 if (unlikely(!pm8001_ha))
167 BUG_ON(1); 174 BUG_ON(1);
168 PM8001_CHIP_DISP->isr(pm8001_ha, 0); 175 vec = pm8001_ha->int_vector;
176 PM8001_CHIP_DISP->isr(pm8001_ha, vec);
177}
178#endif
179
180static struct pm8001_hba_info *outq_to_hba(u8 *outq)
181{
182 return container_of((outq - *outq), struct pm8001_hba_info, outq[0]);
169} 183}
184
185/**
186 * pm8001_interrupt_handler_msix - main MSIX interrupt handler.
187 * It obtains the vector number and calls the equivalent bottom
188 * half or services directly.
189 * @opaque: the passed outbound queue/vector. Host structure is
190 * retrieved from the same.
191 */
192static irqreturn_t pm8001_interrupt_handler_msix(int irq, void *opaque)
193{
194 struct pm8001_hba_info *pm8001_ha = outq_to_hba(opaque);
195 u8 outq = *(u8 *)opaque;
196 irqreturn_t ret = IRQ_HANDLED;
197 if (unlikely(!pm8001_ha))
198 return IRQ_NONE;
199 if (!PM8001_CHIP_DISP->is_our_interupt(pm8001_ha))
200 return IRQ_NONE;
201 pm8001_ha->int_vector = outq;
202#ifdef PM8001_USE_TASKLET
203 tasklet_schedule(&pm8001_ha->tasklet);
204#else
205 ret = PM8001_CHIP_DISP->isr(pm8001_ha, outq);
170#endif 206#endif
207 return ret;
208}
171 209
210/**
211 * pm8001_interrupt_handler_intx - main INTx interrupt handler.
212 * @dev_id: sas_ha structure. The HBA is retrieved from sas_has structure.
213 */
172 214
173 /** 215static irqreturn_t pm8001_interrupt_handler_intx(int irq, void *dev_id)
174 * pm8001_interrupt - when HBA originate a interrupt,we should invoke this
175 * dispatcher to handle each case.
176 * @irq: irq number.
177 * @opaque: the passed general host adapter struct
178 */
179static irqreturn_t pm8001_interrupt(int irq, void *opaque)
180{ 216{
181 struct pm8001_hba_info *pm8001_ha; 217 struct pm8001_hba_info *pm8001_ha;
182 irqreturn_t ret = IRQ_HANDLED; 218 irqreturn_t ret = IRQ_HANDLED;
183 struct sas_ha_struct *sha = opaque; 219 struct sas_ha_struct *sha = dev_id;
184 pm8001_ha = sha->lldd_ha; 220 pm8001_ha = sha->lldd_ha;
185 if (unlikely(!pm8001_ha)) 221 if (unlikely(!pm8001_ha))
186 return IRQ_NONE; 222 return IRQ_NONE;
187 if (!PM8001_CHIP_DISP->is_our_interupt(pm8001_ha)) 223 if (!PM8001_CHIP_DISP->is_our_interupt(pm8001_ha))
188 return IRQ_NONE; 224 return IRQ_NONE;
225
226 pm8001_ha->int_vector = 0;
189#ifdef PM8001_USE_TASKLET 227#ifdef PM8001_USE_TASKLET
190 tasklet_schedule(&pm8001_ha->tasklet); 228 tasklet_schedule(&pm8001_ha->tasklet);
191#else 229#else
@@ -427,8 +465,12 @@ static struct pm8001_hba_info *pm8001_pci_alloc(struct pci_dev *pdev,
427 pm8001_ha->iomb_size = IOMB_SIZE_SPC; 465 pm8001_ha->iomb_size = IOMB_SIZE_SPC;
428 466
429#ifdef PM8001_USE_TASKLET 467#ifdef PM8001_USE_TASKLET
468 /**
469 * default tasklet for non msi-x interrupt handler/first msi-x
470 * interrupt handler
471 **/
430 tasklet_init(&pm8001_ha->tasklet, pm8001_tasklet, 472 tasklet_init(&pm8001_ha->tasklet, pm8001_tasklet,
431 (unsigned long)pm8001_ha); 473 (unsigned long)pm8001_ha);
432#endif 474#endif
433 pm8001_ioremap(pm8001_ha); 475 pm8001_ioremap(pm8001_ha);
434 if (!pm8001_alloc(pm8001_ha, ent)) 476 if (!pm8001_alloc(pm8001_ha, ent))
@@ -591,31 +633,50 @@ static void pm8001_init_sas_add(struct pm8001_hba_info *pm8001_ha)
591 * @chip_info: our ha struct. 633 * @chip_info: our ha struct.
592 * @irq_handler: irq_handler 634 * @irq_handler: irq_handler
593 */ 635 */
594static u32 pm8001_setup_msix(struct pm8001_hba_info *pm8001_ha, 636static u32 pm8001_setup_msix(struct pm8001_hba_info *pm8001_ha)
595 irq_handler_t irq_handler)
596{ 637{
597 u32 i = 0, j = 0; 638 u32 i = 0, j = 0;
598 u32 number_of_intr = 1; 639 u32 number_of_intr;
599 int flag = 0; 640 int flag = 0;
600 u32 max_entry; 641 u32 max_entry;
601 int rc; 642 int rc;
643 static char intr_drvname[PM8001_MAX_MSIX_VEC][sizeof(DRV_NAME)+3];
644
645 /* SPCv controllers supports 64 msi-x */
646 if (pm8001_ha->chip_id == chip_8001) {
647 number_of_intr = 1;
648 flag |= IRQF_DISABLED;
649 } else {
650 number_of_intr = PM8001_MAX_MSIX_VEC;
651 flag &= ~IRQF_SHARED;
652 flag |= IRQF_DISABLED;
653 }
654
602 max_entry = sizeof(pm8001_ha->msix_entries) / 655 max_entry = sizeof(pm8001_ha->msix_entries) /
603 sizeof(pm8001_ha->msix_entries[0]); 656 sizeof(pm8001_ha->msix_entries[0]);
604 flag |= IRQF_DISABLED;
605 for (i = 0; i < max_entry ; i++) 657 for (i = 0; i < max_entry ; i++)
606 pm8001_ha->msix_entries[i].entry = i; 658 pm8001_ha->msix_entries[i].entry = i;
607 rc = pci_enable_msix(pm8001_ha->pdev, pm8001_ha->msix_entries, 659 rc = pci_enable_msix(pm8001_ha->pdev, pm8001_ha->msix_entries,
608 number_of_intr); 660 number_of_intr);
609 pm8001_ha->number_of_intr = number_of_intr; 661 pm8001_ha->number_of_intr = number_of_intr;
610 if (!rc) { 662 if (!rc) {
663 PM8001_INIT_DBG(pm8001_ha, pm8001_printk(
664 "pci_enable_msix request ret:%d no of intr %d\n",
665 rc, pm8001_ha->number_of_intr));
666
667 for (i = 0; i < number_of_intr; i++)
668 pm8001_ha->outq[i] = i;
669
611 for (i = 0; i < number_of_intr; i++) { 670 for (i = 0; i < number_of_intr; i++) {
671 snprintf(intr_drvname[i], sizeof(intr_drvname[0]),
672 DRV_NAME"%d", i);
612 if (request_irq(pm8001_ha->msix_entries[i].vector, 673 if (request_irq(pm8001_ha->msix_entries[i].vector,
613 irq_handler, flag, DRV_NAME, 674 pm8001_interrupt_handler_msix, flag,
614 SHOST_TO_SAS_HA(pm8001_ha->shost))) { 675 intr_drvname[i], &pm8001_ha->outq[i])) {
615 for (j = 0; j < i; j++) 676 for (j = 0; j < i; j++)
616 free_irq( 677 free_irq(
617 pm8001_ha->msix_entries[j].vector, 678 pm8001_ha->msix_entries[j].vector,
618 SHOST_TO_SAS_HA(pm8001_ha->shost)); 679 &pm8001_ha->outq[j]);
619 pci_disable_msix(pm8001_ha->pdev); 680 pci_disable_msix(pm8001_ha->pdev);
620 break; 681 break;
621 } 682 }
@@ -632,22 +693,24 @@ static u32 pm8001_setup_msix(struct pm8001_hba_info *pm8001_ha,
632static u32 pm8001_request_irq(struct pm8001_hba_info *pm8001_ha) 693static u32 pm8001_request_irq(struct pm8001_hba_info *pm8001_ha)
633{ 694{
634 struct pci_dev *pdev; 695 struct pci_dev *pdev;
635 irq_handler_t irq_handler = pm8001_interrupt;
636 int rc; 696 int rc;
637 697
638 pdev = pm8001_ha->pdev; 698 pdev = pm8001_ha->pdev;
639 699
640#ifdef PM8001_USE_MSIX 700#ifdef PM8001_USE_MSIX
641 if (pci_find_capability(pdev, PCI_CAP_ID_MSIX)) 701 if (pci_find_capability(pdev, PCI_CAP_ID_MSIX))
642 return pm8001_setup_msix(pm8001_ha, irq_handler); 702 return pm8001_setup_msix(pm8001_ha);
643 else 703 else {
704 PM8001_INIT_DBG(pm8001_ha,
705 pm8001_printk("MSIX not supported!!!\n"));
644 goto intx; 706 goto intx;
707 }
645#endif 708#endif
646 709
647intx: 710intx:
648 /* initialize the INT-X interrupt */ 711 /* initialize the INT-X interrupt */
649 rc = request_irq(pdev->irq, irq_handler, IRQF_SHARED, DRV_NAME, 712 rc = request_irq(pdev->irq, pm8001_interrupt_handler_intx, IRQF_SHARED,
650 SHOST_TO_SAS_HA(pm8001_ha->shost)); 713 DRV_NAME, SHOST_TO_SAS_HA(pm8001_ha->shost));
651 return rc; 714 return rc;
652} 715}
653 716
@@ -665,6 +728,7 @@ static int pm8001_pci_probe(struct pci_dev *pdev,
665{ 728{
666 unsigned int rc; 729 unsigned int rc;
667 u32 pci_reg; 730 u32 pci_reg;
731 u8 i = 0;
668 struct pm8001_hba_info *pm8001_ha; 732 struct pm8001_hba_info *pm8001_ha;
669 struct Scsi_Host *shost = NULL; 733 struct Scsi_Host *shost = NULL;
670 const struct pm8001_chip_info *chip; 734 const struct pm8001_chip_info *chip;
@@ -729,6 +793,11 @@ static int pm8001_pci_probe(struct pci_dev *pdev,
729 goto err_out_shost; 793 goto err_out_shost;
730 794
731 PM8001_CHIP_DISP->interrupt_enable(pm8001_ha, 0); 795 PM8001_CHIP_DISP->interrupt_enable(pm8001_ha, 0);
796 if (pm8001_ha->chip_id != chip_8001) {
797 for (i = 1; i < pm8001_ha->number_of_intr; i++)
798 PM8001_CHIP_DISP->interrupt_enable(pm8001_ha, i);
799 }
800
732 pm8001_init_sas_add(pm8001_ha); 801 pm8001_init_sas_add(pm8001_ha);
733 pm8001_post_sas_ha_init(shost, chip); 802 pm8001_post_sas_ha_init(shost, chip);
734 rc = sas_register_ha(SHOST_TO_SAS_HA(shost)); 803 rc = sas_register_ha(SHOST_TO_SAS_HA(shost));
@@ -764,14 +833,15 @@ static void pm8001_pci_remove(struct pci_dev *pdev)
764 sas_remove_host(pm8001_ha->shost); 833 sas_remove_host(pm8001_ha->shost);
765 list_del(&pm8001_ha->list); 834 list_del(&pm8001_ha->list);
766 scsi_remove_host(pm8001_ha->shost); 835 scsi_remove_host(pm8001_ha->shost);
767 PM8001_CHIP_DISP->interrupt_disable(pm8001_ha, 0); 836 PM8001_CHIP_DISP->interrupt_disable(pm8001_ha, 0xFF);
768 PM8001_CHIP_DISP->chip_soft_rst(pm8001_ha, 0x252acbcd); 837 PM8001_CHIP_DISP->chip_soft_rst(pm8001_ha, 0x252acbcd);
769 838
770#ifdef PM8001_USE_MSIX 839#ifdef PM8001_USE_MSIX
771 for (i = 0; i < pm8001_ha->number_of_intr; i++) 840 for (i = 0; i < pm8001_ha->number_of_intr; i++)
772 synchronize_irq(pm8001_ha->msix_entries[i].vector); 841 synchronize_irq(pm8001_ha->msix_entries[i].vector);
773 for (i = 0; i < pm8001_ha->number_of_intr; i++) 842 for (i = 0; i < pm8001_ha->number_of_intr; i++)
774 free_irq(pm8001_ha->msix_entries[i].vector, sha); 843 free_irq(pm8001_ha->msix_entries[i].vector,
844 &pm8001_ha->outq[i]);
775 pci_disable_msix(pdev); 845 pci_disable_msix(pdev);
776#else 846#else
777 free_irq(pm8001_ha->irq, sha); 847 free_irq(pm8001_ha->irq, sha);
@@ -808,13 +878,14 @@ static int pm8001_pci_suspend(struct pci_dev *pdev, pm_message_t state)
808 printk(KERN_ERR " PCI PM not supported\n"); 878 printk(KERN_ERR " PCI PM not supported\n");
809 return -ENODEV; 879 return -ENODEV;
810 } 880 }
811 PM8001_CHIP_DISP->interrupt_disable(pm8001_ha, 0); 881 PM8001_CHIP_DISP->interrupt_disable(pm8001_ha, 0xFF);
812 PM8001_CHIP_DISP->chip_soft_rst(pm8001_ha, 0x252acbcd); 882 PM8001_CHIP_DISP->chip_soft_rst(pm8001_ha, 0x252acbcd);
813#ifdef PM8001_USE_MSIX 883#ifdef PM8001_USE_MSIX
814 for (i = 0; i < pm8001_ha->number_of_intr; i++) 884 for (i = 0; i < pm8001_ha->number_of_intr; i++)
815 synchronize_irq(pm8001_ha->msix_entries[i].vector); 885 synchronize_irq(pm8001_ha->msix_entries[i].vector);
816 for (i = 0; i < pm8001_ha->number_of_intr; i++) 886 for (i = 0; i < pm8001_ha->number_of_intr; i++)
817 free_irq(pm8001_ha->msix_entries[i].vector, sha); 887 free_irq(pm8001_ha->msix_entries[i].vector,
888 &pm8001_ha->outq[i]);
818 pci_disable_msix(pdev); 889 pci_disable_msix(pdev);
819#else 890#else
820 free_irq(pm8001_ha->irq, sha); 891 free_irq(pm8001_ha->irq, sha);
@@ -843,6 +914,7 @@ static int pm8001_pci_resume(struct pci_dev *pdev)
843 struct sas_ha_struct *sha = pci_get_drvdata(pdev); 914 struct sas_ha_struct *sha = pci_get_drvdata(pdev);
844 struct pm8001_hba_info *pm8001_ha; 915 struct pm8001_hba_info *pm8001_ha;
845 int rc; 916 int rc;
917 u8 i = 0;
846 u32 device_state; 918 u32 device_state;
847 pm8001_ha = sha->lldd_ha; 919 pm8001_ha = sha->lldd_ha;
848 device_state = pdev->current_state; 920 device_state = pdev->current_state;
@@ -869,15 +941,24 @@ static int pm8001_pci_resume(struct pci_dev *pdev)
869 rc = PM8001_CHIP_DISP->chip_init(pm8001_ha); 941 rc = PM8001_CHIP_DISP->chip_init(pm8001_ha);
870 if (rc) 942 if (rc)
871 goto err_out_disable; 943 goto err_out_disable;
872 PM8001_CHIP_DISP->interrupt_disable(pm8001_ha, 0); 944
945 /* disable all the interrupt bits */
946 PM8001_CHIP_DISP->interrupt_disable(pm8001_ha, 0xFF);
947
873 rc = pm8001_request_irq(pm8001_ha); 948 rc = pm8001_request_irq(pm8001_ha);
874 if (rc) 949 if (rc)
875 goto err_out_disable; 950 goto err_out_disable;
876 #ifdef PM8001_USE_TASKLET 951#ifdef PM8001_USE_TASKLET
952 /* default tasklet for non msi-x interrupt handler/first msi-x
953 * interrupt handler */
877 tasklet_init(&pm8001_ha->tasklet, pm8001_tasklet, 954 tasklet_init(&pm8001_ha->tasklet, pm8001_tasklet,
878 (unsigned long)pm8001_ha); 955 (unsigned long)pm8001_ha);
879 #endif 956#endif
880 PM8001_CHIP_DISP->interrupt_enable(pm8001_ha, 0); 957 PM8001_CHIP_DISP->interrupt_enable(pm8001_ha, 0);
958 if (pm8001_ha->chip_id != chip_8001) {
959 for (i = 1; i < pm8001_ha->number_of_intr; i++)
960 PM8001_CHIP_DISP->interrupt_enable(pm8001_ha, i);
961 }
881 scsi_unblock_requests(pm8001_ha->shost); 962 scsi_unblock_requests(pm8001_ha->shost);
882 return 0; 963 return 0;
883 964
diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h
index e0faa9597c26..8e281c8deff2 100644
--- a/drivers/scsi/pm8001/pm8001_sas.h
+++ b/drivers/scsi/pm8001/pm8001_sas.h
@@ -453,7 +453,9 @@ struct pm8001_hba_info {
453#endif 453#endif
454 u32 logging_level; 454 u32 logging_level;
455 u32 fw_status; 455 u32 fw_status;
456 u32 int_vector;
456 const struct firmware *fw_image; 457 const struct firmware *fw_image;
458 u8 outq[PM8001_MAX_MSIX_VEC];
457}; 459};
458 460
459struct pm8001_work { 461struct pm8001_work {