pm80xx: MSI-X implementation for using 64 interrupts
Subsystems (2)
PATCH v5 5/12 pm80xx: MSI-X implementation for using 64 interrupts
Quoted 1 line
From
c9ef2f3de75ccd7d33ac26ab3e40745ce3134a2bMon Sep 17 00:00:00 2001
From: Sakthivel K <[email protected]>
Date: Tue, 19 Mar 2013 17:56:17 +0530
Subject: [PATCH V5 5/12] 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 <[email protected]>
Signed-off-by Anand Kumar S <[email protected]>
Acked-by Jack Wang <[email protected]>
Reviewed-by Hannes Reinecke <[email protected]>
--- drivers/scsi/pm8001/pm8001_init.c | 141 +++++++++++++++++++++++++++++-------- drivers/scsi/pm8001/pm8001_sas.h | 2 + 2 files changed, 113 insertions(+), 30 deletions(-)
drivers/scsi/pm8001/pm8001_init.c +111 -30
@@ -159,33 +159,71 @@ static void pm8001_free(struct pm8001_hba_info *pm8001_ha) }#ifdef PM8001_USE_TASKLET + +/** +* tasklet for 64 msi-x interrupt handler +* @opaque: the passed general host adapter struct +* Note: pm8001_tasklet is common for pm8001 & pm80xx +*/ static void pm8001_tasklet (unsigned long opaque) {struct pm8001_hba_info *pm8001_ha; +u32 vec; pm8001_ha = (struct pm8001_hba_info *)opaque;if (unlikely (!pm8001_ha))BUG_ON (1 ); -PM8001_CHIP_DISP ->isr (pm8001_ha,0 ); + vec = pm8001_ha->int_vector; +PM8001_CHIP_DISP ->isr (pm8001_ha, vec); +} +#endif + +static struct pm8001_hba_info *outq_to_hba (u8 *outq) +{ + return container_of((outq - *outq), struct pm8001_hba_info, outq[0]); } + +/** +* pm8001_interrupt_handler_msix - main MSIX interrupt handler. +* It obtains the vector number and calls the equivalent bottom +* half or services directly. +* @opaque: the passed outbound queue/vector. Host structure is +* retrieved from the same. +*/ +static irqreturn_t pm8001_interrupt_handler_msix (int irq,void *opaque) +{ +struct pm8001_hba_info *pm8001_ha =outq_to_hba (opaque); +u8 outq = *(u8 *)opaque; +irqreturn_t ret =IRQ_HANDLED ; +if (unlikely (!pm8001_ha)) +return IRQ_NONE ; +if (!PM8001_CHIP_DISP ->is_our_interupt (pm8001_ha)) +return IRQ_NONE ; + pm8001_ha->int_vector = outq; +#ifdef PM8001_USE_TASKLET +tasklet_schedule (&pm8001_ha->tasklet); +#else + ret =PM8001_CHIP_DISP ->isr (pm8001_ha, outq);#endif +return ret; +} +/** +* pm8001_interrupt_handler_intx - main INTx interrupt handler. +* @dev_id: sas_ha structure. The HBA is retrieved from sas_has structure. +*/ -/** -* pm8001_interrupt - when HBA originate a interrupt,we should invoke this -* dispatcher to handle each case. -* @irq: irq number. -* @opaque: the passed general host adapter struct -*/ -static irqreturn_t pm8001_interrupt (int irq,void *opaque) +static irqreturn_t pm8001_interrupt_handler_intx (int irq,void *dev_id) {struct pm8001_hba_info *pm8001_ha;irqreturn_t ret =IRQ_HANDLED ; -struct sas_ha_struct *sha = opaque; +struct sas_ha_struct *sha = dev_id; pm8001_ha = sha->lldd_ha;if (unlikely (!pm8001_ha))return IRQ_NONE ;if (!PM8001_CHIP_DISP ->is_our_interupt (pm8001_ha))return IRQ_NONE ; + + pm8001_ha->int_vector =0 ;#ifdef PM8001_USE_TASKLET tasklet_schedule (&pm8001_ha->tasklet);#else
@@ -427,8 +465,12 @@ static struct pm8001_hba_info *pm8001_pci_alloc(struct pci_dev *pdev, pm8001_ha->iomb_size =IOMB_SIZE_SPC ;#ifdef PM8001_USE_TASKLET +/** +* default tasklet for non msi-x interrupt handler/first msi-x +* interrupt handler +**/ tasklet_init (&pm8001_ha->tasklet, pm8001_tasklet, - (unsigned long )pm8001_ha); + (unsigned long )pm8001_ha);#endif pm8001_ioremap (pm8001_ha);if (!pm8001_alloc (pm8001_ha, ent))
@@ -591,31 +633,50 @@ static void pm8001_init_sas_add(struct pm8001_hba_info *pm8001_ha)* @chip_info: our ha struct. * @irq_handler: irq_handler */ -static u32 pm8001_setup_msix (struct pm8001_hba_info *pm8001_ha, -irq_handler_t irq_handler) +static u32 pm8001_setup_msix (struct pm8001_hba_info *pm8001_ha) {u32 i =0 , j =0 ; -u32 number_of_intr =1 ; +u32 number_of_intr;int flag =0 ;u32 max_entry;int rc; +static char intr_drvname[PM8001_MAX_MSIX_VEC ][sizeof (DRV_NAME )+3 ]; + +/* SPCv controllers supports 64 msi-x */ +if (pm8001_ha->chip_id == chip_8001) { + number_of_intr =1 ; + flag |=IRQF_DISABLED ; + }else { + number_of_intr =PM8001_MAX_MSIX_VEC ; + flag &= ~IRQF_SHARED ; + flag |=IRQF_DISABLED ; + } + max_entry =sizeof (pm8001_ha->msix_entries) /sizeof (pm8001_ha->msix_entries[0 ]); - flag |=IRQF_DISABLED ;for (i =0 ; i < max_entry ; i++) pm8001_ha->msix_entries[i].entry = i; rc =pci_enable_msix (pm8001_ha->pdev, pm8001_ha->msix_entries, number_of_intr); pm8001_ha->number_of_intr = number_of_intr;if (!rc) { +PM8001_INIT_DBG (pm8001_ha,pm8001_printk ( +"pci_enable_msix request ret:%d no of intr %d\n" , + rc, pm8001_ha->number_of_intr)); + +for (i =0 ; i < number_of_intr; i++) + pm8001_ha->outq[i] = i; +for (i =0 ; i < number_of_intr; i++) { +snprintf (intr_drvname[i],sizeof (intr_drvname[0 ]), +DRV_NAME "%d" , i);if (request_irq (pm8001_ha->msix_entries[i].vector, - irq_handler, flag,DRV_NAME , -SHOST_TO_SAS_HA (pm8001_ha->shost))) { + pm8001_interrupt_handler_msix, flag, + intr_drvname[i], &pm8001_ha->outq[i])) {for (j =0 ; j < i; j++)free_irq ( pm8001_ha->msix_entries[j].vector, -SHOST_TO_SAS_HA (pm8001_ha->shost)); + &pm8001_ha->outq[j]);pci_disable_msix (pm8001_ha->pdev);break ; }
@@ -632,22 +693,24 @@ static u32 pm8001_setup_msix(struct pm8001_hba_info *pm8001_ha,static u32 pm8001_request_irq (struct pm8001_hba_info *pm8001_ha) {struct pci_dev *pdev; -irq_handler_t irq_handler = pm8001_interrupt;int rc; pdev = pm8001_ha->pdev;#ifdef PM8001_USE_MSIX if (pci_find_capability (pdev,PCI_CAP_ID_MSIX )) -return pm8001_setup_msix (pm8001_ha, irq_handler); -else +return pm8001_setup_msix (pm8001_ha); +else { +PM8001_INIT_DBG (pm8001_ha, +pm8001_printk ("MSIX not supported!!!\n" )); goto intx; + }#endif intx:/* initialize the INT-X interrupt */ - rc =request_irq (pdev->irq, irq_handler,IRQF_SHARED ,DRV_NAME , -SHOST_TO_SAS_HA (pm8001_ha->shost)); + rc =request_irq (pdev->irq, pm8001_interrupt_handler_intx,IRQF_SHARED , +DRV_NAME ,SHOST_TO_SAS_HA (pm8001_ha->shost));return rc; }
@@ -665,6 +728,7 @@ static int pm8001_pci_probe(struct pci_dev *pdev, {unsigned int rc;u32 pci_reg; +u8 i =0 ;struct pm8001_hba_info *pm8001_ha;struct Scsi_Host *shost =NULL ;const struct pm8001_chip_info *chip;
@@ -729,6 +793,11 @@ static int pm8001_pci_probe(struct pci_dev *pdev, goto err_out_shost;PM8001_CHIP_DISP ->interrupt_enable (pm8001_ha,0 ); +if (pm8001_ha->chip_id != chip_8001) { +for (i =1 ; i < pm8001_ha->number_of_intr; i++) +PM8001_CHIP_DISP ->interrupt_enable (pm8001_ha, i); + } +pm8001_init_sas_add (pm8001_ha);pm8001_post_sas_ha_init (shost, chip); rc =sas_register_ha (SHOST_TO_SAS_HA (shost));
@@ -764,14 +833,15 @@ static void pm8001_pci_remove(struct pci_dev *pdev)sas_remove_host (pm8001_ha->shost);list_del (&pm8001_ha->list);scsi_remove_host (pm8001_ha->shost); -PM8001_CHIP_DISP ->interrupt_disable (pm8001_ha,0 ); +PM8001_CHIP_DISP ->interrupt_disable (pm8001_ha,0xFF );PM8001_CHIP_DISP ->chip_soft_rst (pm8001_ha,0x252acbcd );#ifdef PM8001_USE_MSIX for (i =0 ; i < pm8001_ha->number_of_intr; i++)synchronize_irq (pm8001_ha->msix_entries[i].vector);for (i =0 ; i < pm8001_ha->number_of_intr; i++) -free_irq (pm8001_ha->msix_entries[i].vector, sha); +free_irq (pm8001_ha->msix_entries[i].vector, + &pm8001_ha->outq[i]);pci_disable_msix (pdev);#else free_irq (pm8001_ha->irq, sha);
@@ -808,13 +878,14 @@ static int pm8001_pci_suspend(struct pci_dev *pdev, pm_message_t state)printk (KERN_ERR " PCI PM not supported\n" );return -ENODEV ; } -PM8001_CHIP_DISP ->interrupt_disable (pm8001_ha,0 ); +PM8001_CHIP_DISP ->interrupt_disable (pm8001_ha,0xFF );PM8001_CHIP_DISP ->chip_soft_rst (pm8001_ha,0x252acbcd );#ifdef PM8001_USE_MSIX for (i =0 ; i < pm8001_ha->number_of_intr; i++)synchronize_irq (pm8001_ha->msix_entries[i].vector);for (i =0 ; i < pm8001_ha->number_of_intr; i++) -free_irq (pm8001_ha->msix_entries[i].vector, sha); +free_irq (pm8001_ha->msix_entries[i].vector, + &pm8001_ha->outq[i]);pci_disable_msix (pdev);#else free_irq (pm8001_ha->irq, sha);
@@ -843,6 +914,7 @@ static int pm8001_pci_resume(struct pci_dev *pdev)struct sas_ha_struct *sha =pci_get_drvdata (pdev);struct pm8001_hba_info *pm8001_ha;int rc; +u8 i =0 ;u32 device_state; pm8001_ha = sha->lldd_ha; device_state = pdev->current_state;
@@ -869,15 +941,24 @@ static int pm8001_pci_resume(struct pci_dev *pdev) rc =PM8001_CHIP_DISP ->chip_init (pm8001_ha);if (rc) goto err_out_disable; -PM8001_CHIP_DISP ->interrupt_disable (pm8001_ha,0 ); + +/* disable all the interrupt bits */ +PM8001_CHIP_DISP ->interrupt_disable (pm8001_ha,0xFF ); + rc =pm8001_request_irq (pm8001_ha);if (rc) goto err_out_disable; -#ifdef PM8001_USE_TASKLET +#ifdef PM8001_USE_TASKLET +/* default tasklet for non msi-x interrupt handler/first msi-x +* interrupt handler */ tasklet_init (&pm8001_ha->tasklet, pm8001_tasklet, - (unsigned long )pm8001_ha); -#endif + (unsigned long )pm8001_ha); +#endif PM8001_CHIP_DISP ->interrupt_enable (pm8001_ha,0 ); +if (pm8001_ha->chip_id != chip_8001) { +for (i =1 ; i < pm8001_ha->number_of_intr; i++) +PM8001_CHIP_DISP ->interrupt_enable (pm8001_ha, i); + }scsi_unblock_requests (pm8001_ha->shost);return 0 ;
drivers/scsi/pm8001/pm8001_sas.h +2 -0
@@ -453,7 +453,9 @@ struct pm8001_hba_info {#endif u32 logging_level;u32 fw_status; +u32 int_vector;const struct firmware *fw_image; +u8 outq[PM8001_MAX_MSIX_VEC ]; };struct pm8001_work {
Signature · 1 line
1.7.1