@@ -248,8 +248,6 @@ static void asd_get_max_scb_ddb(struct asd_ha_struct *asd_ha)
/* ---------- Done List initialization ---------- */
-static void asd_dl_tasklet_handler(unsigned long);
-
static int asd_init_dl(struct asd_ha_struct *asd_ha)
{
asd_ha->seq.actual_dl
@@ -261,8 +259,6 @@ static int asd_init_dl(struct asd_ha_struct *asd_ha)
asd_ha->seq.dl = asd_ha->seq.actual_dl->vaddr;
asd_ha->seq.dl_toggle = ASD_DEF_DL_TOGGLE;
asd_ha->seq.dl_next = 0;
- tasklet_init(&asd_ha->seq.dl_tasklet, asd_dl_tasklet_handler,
- (unsigned long) asd_ha);
return 0;
}
@@ -711,7 +707,7 @@ static void asd_chip_reset(struct asd_ha_struct *asd_ha)
/* ---------- Done List Routines ---------- */
-static void asd_dl_tasklet_handler(unsigned long data)
+irqreturn_t asd_dl_handler(int irq, void *data)
{
struct asd_ha_struct *asd_ha = (struct asd_ha_struct *) data;
struct asd_seq_data *seq = &asd_ha->seq;
@@ -741,26 +737,19 @@ static void asd_dl_tasklet_handler(unsigned long data)
seq->pending--;
spin_unlock_irqrestore(&seq->pend_q_lock, flags);
out:
- ascb->tasklet_complete(ascb, dl);
+ ascb->complete(ascb, dl);
next_1:
seq->dl_next = (seq->dl_next + 1) & (ASD_DL_SIZE-1);
if (!seq->dl_next)
seq->dl_toggle ^= DL_TOGGLE_MASK;
}
+
+ return IRQ_HANDLED;
}
/* ---------- Interrupt Service Routines ---------- */
-/**
- * asd_process_donelist_isr -- schedule processing of done list entries
- * @asd_ha: pointer to host adapter structure
- */
-static void asd_process_donelist_isr(struct asd_ha_struct *asd_ha)
-{
- tasklet_schedule(&asd_ha->seq.dl_tasklet);
-}
-
/**
* asd_com_sas_isr -- process device communication interrupt (COMINT)
* @asd_ha: pointer to host adapter structure
@@ -1011,8 +1000,6 @@ irqreturn_t asd_hw_isr(int irq, void *dev_id)
asd_write_reg_dword(asd_ha, CHIMINT, chimint);
(void) asd_read_reg_dword(asd_ha, CHIMINT);
- if (chimint & DLAVAIL)
- asd_process_donelist_isr(asd_ha);
if (chimint & COMINT)
asd_com_sas_isr(asd_ha);
if (chimint & DEVINT)
@@ -1021,6 +1008,8 @@ irqreturn_t asd_hw_isr(int irq, void *dev_id)
asd_rbi_exsi_isr(asd_ha);
if (chimint & HOSTERR)
asd_hst_pcix_isr(asd_ha);
+ if (chimint & DLAVAIL)
+ return IRQ_WAKE_THREAD;
return IRQ_HANDLED;
}
@@ -117,7 +117,7 @@ struct asd_ascb {
struct asd_dma_tok dma_scb;
struct asd_dma_tok *sg_arr;
- void (*tasklet_complete)(struct asd_ascb *, struct done_list_struct *);
+ void (*complete)(struct asd_ascb *, struct done_list_struct *);
u8 uldd_timer:1;
/* internally generated command */
@@ -152,7 +152,6 @@ struct asd_seq_data {
void *tc_index_bitmap;
int tc_index_bitmap_bits;
- struct tasklet_struct dl_tasklet;
struct done_list_struct *dl; /* array of done list entries, equals */
struct asd_dma_tok *actual_dl; /* actual_dl->vaddr */
int dl_toggle;
@@ -356,7 +355,7 @@ static inline void asd_ascb_free_list(struct asd_ascb *ascb_list)
int asd_init_hw(struct asd_ha_struct *asd_ha);
irqreturn_t asd_hw_isr(int irq, void *dev_id);
-
+irqreturn_t asd_dl_handler(int irq, void *data);
struct asd_ascb *asd_ascb_alloc_list(struct asd_ha_struct
*asd_ha, int *num,
@@ -790,8 +790,9 @@ static int asd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
if (use_msi)
pci_enable_msi(asd_ha->pcidev);
- err = request_irq(asd_ha->pcidev->irq, asd_hw_isr, IRQF_SHARED,
- ASD_DRIVER_NAME, asd_ha);
+ err = request_threaded_irq(asd_ha->pcidev->irq, asd_hw_isr,
+ asd_dl_handler, IRQF_SHARED,
+ ASD_DRIVER_NAME, asd_ha);
if (err) {
asd_printk("couldn't get irq %d for %s\n",
asd_ha->pcidev->irq, pci_name(asd_ha->pcidev));
@@ -64,8 +64,8 @@ static void get_lrate_mode(struct asd_phy *phy, u8 oob_mode)
phy->sas_phy.oob_mode = SATA_OOB_MODE;
}
-static void asd_phy_event_tasklet(struct asd_ascb *ascb,
- struct done_list_struct *dl)
+static void asd_phy_event(struct asd_ascb *ascb,
+ struct done_list_struct *dl)
{
struct asd_ha_struct *asd_ha = ascb->ha;
int phy_id = dl->status_block[0] & DL_PHY_MASK;
@@ -215,9 +215,9 @@ static void asd_deform_port(struct asd_ha_struct *asd_ha, struct asd_phy *phy)
spin_unlock_irqrestore(&asd_ha->asd_ports_lock, flags);
}
-static void asd_bytes_dmaed_tasklet(struct asd_ascb *ascb,
- struct done_list_struct *dl,
- int edb_id, int phy_id)
+static void asd_bytes_dmaed(struct asd_ascb *ascb,
+ struct done_list_struct *dl,
+ int edb_id, int phy_id)
{
unsigned long flags;
int edb_el = edb_id + ascb->edb_index;
@@ -237,9 +237,9 @@ static void asd_bytes_dmaed_tasklet(struct asd_ascb *ascb,
sas_notify_port_event(&phy->sas_phy, PORTE_BYTES_DMAED, GFP_ATOMIC);
}
-static void asd_link_reset_err_tasklet(struct asd_ascb *ascb,
- struct done_list_struct *dl,
- int phy_id)
+static void asd_link_reset_err(struct asd_ascb *ascb,
+ struct done_list_struct *dl,
+ int phy_id)
{
struct asd_ha_struct *asd_ha = ascb->ha;
struct sas_ha_struct *sas_ha = &asd_ha->sas_ha;
@@ -290,9 +290,9 @@ static void asd_link_reset_err_tasklet(struct asd_ascb *ascb,
;
}
-static void asd_primitive_rcvd_tasklet(struct asd_ascb *ascb,
- struct done_list_struct *dl,
- int phy_id)
+static void asd_primitive_rcvd(struct asd_ascb *ascb,
+ struct done_list_struct *dl,
+ int phy_id)
{
unsigned long flags;
struct sas_ha_struct *sas_ha = &ascb->ha->sas_ha;
@@ -361,7 +361,6 @@ static void asd_primitive_rcvd_tasklet(struct asd_ascb *ascb,
*
* After an EDB has been invalidated, if all EDBs in this ESCB have been
* invalidated, the ESCB is posted back to the sequencer.
- * Context is tasklet/IRQ.
*/
void asd_invalidate_edb(struct asd_ascb *ascb, int edb_id)
{
@@ -396,8 +395,8 @@ void asd_invalidate_edb(struct asd_ascb *ascb, int edb_id)
}
}
-static void escb_tasklet_complete(struct asd_ascb *ascb,
- struct done_list_struct *dl)
+static void escb_complete(struct asd_ascb *ascb,
+ struct done_list_struct *dl)
{
struct asd_ha_struct *asd_ha = ascb->ha;
struct sas_ha_struct *sas_ha = &asd_ha->sas_ha;
@@ -546,21 +545,21 @@ static void escb_tasklet_complete(struct asd_ascb *ascb,
switch (sb_opcode) {
case BYTES_DMAED:
ASD_DPRINTK("%s: phy%d: BYTES_DMAED\n", __func__, phy_id);
- asd_bytes_dmaed_tasklet(ascb, dl, edb, phy_id);
+ asd_bytes_dmaed(ascb, dl, edb, phy_id);
break;
case PRIMITIVE_RECVD:
ASD_DPRINTK("%s: phy%d: PRIMITIVE_RECVD\n", __func__,
phy_id);
- asd_primitive_rcvd_tasklet(ascb, dl, phy_id);
+ asd_primitive_rcvd(ascb, dl, phy_id);
break;
case PHY_EVENT:
ASD_DPRINTK("%s: phy%d: PHY_EVENT\n", __func__, phy_id);
- asd_phy_event_tasklet(ascb, dl);
+ asd_phy_event(ascb, dl);
break;
case LINK_RESET_ERROR:
ASD_DPRINTK("%s: phy%d: LINK_RESET_ERROR\n", __func__,
phy_id);
- asd_link_reset_err_tasklet(ascb, dl, phy_id);
+ asd_link_reset_err(ascb, dl, phy_id);
break;
case TIMER_EVENT:
ASD_DPRINTK("%s: phy%d: TIMER_EVENT, lost dw sync\n",
@@ -600,7 +599,7 @@ int asd_init_post_escbs(struct asd_ha_struct *asd_ha)
int i;
for (i = 0; i < seq->num_escbs; i++)
- seq->escb_arr[i]->tasklet_complete = escb_tasklet_complete;
+ seq->escb_arr[i]->complete = escb_complete;
ASD_DPRINTK("posting %d escbs\n", i);
return asd_post_escb_list(asd_ha, seq->escb_arr[0], seq->num_escbs);
@@ -613,7 +612,7 @@ int asd_init_post_escbs(struct asd_ha_struct *asd_ha)
| CURRENT_OOB_ERROR)
/**
- * control_phy_tasklet_complete -- tasklet complete for CONTROL PHY ascb
+ * control_phy_complete -- complete for CONTROL PHY ascb
* @ascb: pointer to an ascb
* @dl: pointer to the done list entry
*
@@ -623,8 +622,8 @@ int asd_init_post_escbs(struct asd_ha_struct *asd_ha)
* - if a device is connected to the LED, it is lit,
* - if no device is connected to the LED, is is dimmed (off).
*/
-static void control_phy_tasklet_complete(struct asd_ascb *ascb,
- struct done_list_struct *dl)
+static void control_phy_complete(struct asd_ascb *ascb,
+ struct done_list_struct *dl)
{
struct asd_ha_struct *asd_ha = ascb->ha;
struct scb *scb = ascb->scb;
@@ -758,10 +757,9 @@ static void set_speed_mask(u8 *speed_mask, struct asd_phy_desc *pd)
*
* This function builds a CONTROL PHY scb. No allocation of any kind
* is performed. @ascb is allocated with the list function.
- * The caller can override the ascb->tasklet_complete to point
+ * The caller can override the ascb->complete to point
* to its own callback function. It must call asd_ascb_free()
- * at its tasklet complete function.
- * See the default implementation.
+ * at its complete function. See the default implementation.
*/
void asd_build_control_phy(struct asd_ascb *ascb, int phy_id, u8 subfunc)
{
@@ -806,47 +804,9 @@ void asd_build_control_phy(struct asd_ascb *ascb, int phy_id, u8 subfunc)
control_phy->conn_handle = cpu_to_le16(0xFFFF);
- ascb->tasklet_complete = control_phy_tasklet_complete;
+ ascb->complete = control_phy_complete;
}
-/* ---------- INITIATE LINK ADM TASK ---------- */
-
-#if 0
-
-static void link_adm_tasklet_complete(struct asd_ascb *ascb,
- struct done_list_struct *dl)
-{
- u8 opcode = dl->opcode;
- struct initiate_link_adm *link_adm = &ascb->scb->link_adm;
- u8 phy_id = link_adm->phy_id;
-
- if (opcode != TC_NO_ERROR) {
- asd_printk("phy%d: link adm task 0x%x completed with error "
- "0x%x\n", phy_id, link_adm->sub_func, opcode);
- }
- ASD_DPRINTK("phy%d: link adm task 0x%x: 0x%x\n",
- phy_id, link_adm->sub_func, opcode);
-
- asd_ascb_free(ascb);
-}
-
-void asd_build_initiate_link_adm_task(struct asd_ascb *ascb, int phy_id,
- u8 subfunc)
-{
- struct scb *scb = ascb->scb;
- struct initiate_link_adm *link_adm = &scb->link_adm;
-
- scb->header.opcode = INITIATE_LINK_ADM_TASK;
-
- link_adm->phy_id = phy_id;
- link_adm->sub_func = subfunc;
- link_adm->conn_handle = cpu_to_le16(0xFFFF);
-
- ascb->tasklet_complete = link_adm_tasklet_complete;
-}
-
-#endif /* 0 */
-
/* ---------- SCB timer ---------- */
/**
@@ -135,10 +135,10 @@ static void asd_unmap_scatterlist(struct asd_ascb *ascb)
task->num_scatter, task->data_dir);
}
-/* ---------- Task complete tasklet ---------- */
+/* ---------- Task complete ---------- */
-static void asd_get_response_tasklet(struct asd_ascb *ascb,
- struct done_list_struct *dl)
+static void asd_get_response(struct asd_ascb *ascb,
+ struct done_list_struct *dl)
{
struct asd_ha_struct *asd_ha = ascb->ha;
struct sas_task *task = ascb->uldd_task;
@@ -191,7 +191,7 @@ static void asd_get_response_tasklet(struct asd_ascb *ascb,
asd_invalidate_edb(escb, edb_id);
}
-static void asd_task_tasklet_complete(struct asd_ascb *ascb,
+static void asd_task_complete(struct asd_ascb *ascb,
struct done_list_struct *dl)
{
struct sas_task *task = ascb->uldd_task;
@@ -221,7 +221,7 @@ static void asd_task_tasklet_complete(struct asd_ascb *ascb,
case TC_ATA_RESP:
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_PROTO_RESPONSE;
- asd_get_response_tasklet(ascb, dl);
+ asd_get_response(ascb, dl);
break;
case TF_OPEN_REJECT:
ts->resp = SAS_TASK_UNDELIVERED;
@@ -394,7 +394,7 @@ static int asd_build_ata_ascb(struct asd_ascb *ascb, struct sas_task *task,
flags |= STP_AFFIL_POLICY;
scb->ata_task.flags = flags;
}
- ascb->tasklet_complete = asd_task_tasklet_complete;
+ ascb->complete = asd_task_complete;
if (likely(!task->ata_task.device_control_reg_update))
res = asd_map_scatterlist(task, scb->ata_task.sg_element,
@@ -442,7 +442,7 @@ static int asd_build_smp_ascb(struct asd_ascb *ascb, struct sas_task *task,
scb->smp_task.conn_handle = cpu_to_le16((u16)
(unsigned long)dev->lldd_dev);
- ascb->tasklet_complete = asd_task_tasklet_complete;
+ ascb->complete = asd_task_complete;
return 0;
}
@@ -495,7 +495,7 @@ static int asd_build_ssp_ascb(struct asd_ascb *ascb, struct sas_task *task,
scb->ssp_task.data_dir = data_dir_flags[task->data_dir];
scb->ssp_task.retry_count = scb->ssp_task.retry_count;
- ascb->tasklet_complete = asd_task_tasklet_complete;
+ ascb->complete = asd_task_complete;
res = asd_map_scatterlist(task, scb->ssp_task.sg_element, gfp_flags);
@@ -15,13 +15,13 @@
/* ---------- Internal enqueue ---------- */
static int asd_enqueue_internal(struct asd_ascb *ascb,
- void (*tasklet_complete)(struct asd_ascb *,
- struct done_list_struct *),
+ void (*complete)(struct asd_ascb *,
+ struct done_list_struct *),
void (*timed_out)(struct timer_list *t))
{
int res;
- ascb->tasklet_complete = tasklet_complete;
+ ascb->complete = complete;
ascb->uldd_timer = 1;
ascb->timer.function = timed_out;
@@ -37,7 +37,7 @@ static int asd_enqueue_internal(struct asd_ascb *ascb,
/* ---------- CLEAR NEXUS ---------- */
-struct tasklet_completion_status {
+struct completion_status {
int dl_opcode;
int tmf_state;
u8 tag_valid:1;
@@ -45,7 +45,7 @@ struct tasklet_completion_status {
};
#define DECLARE_TCS(tcs) \
- struct tasklet_completion_status tcs = { \
+ struct completion_status tcs = { \
.dl_opcode = 0, \
.tmf_state = 0, \
.tag_valid = 0, \
@@ -53,10 +53,10 @@ struct tasklet_completion_status {
}
-static void asd_clear_nexus_tasklet_complete(struct asd_ascb *ascb,
- struct done_list_struct *dl)
+static void asd_clear_nexus_complete(struct asd_ascb *ascb,
+ struct done_list_struct *dl)
{
- struct tasklet_completion_status *tcs = ascb->uldd_task;
+ struct completion_status *tcs = ascb->uldd_task;
ASD_DPRINTK("%s: here\n", __func__);
if (!del_timer(&ascb->timer)) {
ASD_DPRINTK("%s: couldn't delete timer\n", __func__);
@@ -71,7 +71,7 @@ static void asd_clear_nexus_tasklet_complete(struct asd_ascb *ascb,
static void asd_clear_nexus_timedout(struct timer_list *t)
{
struct asd_ascb *ascb = from_timer(ascb, t, timer);
- struct tasklet_completion_status *tcs = ascb->uldd_task;
+ struct completion_status *tcs = ascb->uldd_task;
ASD_DPRINTK("%s: here\n", __func__);
tcs->dl_opcode = TMF_RESP_FUNC_FAILED;
@@ -98,7 +98,7 @@ static void asd_clear_nexus_timedout(struct timer_list *t)
#define CLEAR_NEXUS_POST \
ASD_DPRINTK("%s: POST\n", __func__); \
- res = asd_enqueue_internal(ascb, asd_clear_nexus_tasklet_complete, \
+ res = asd_enqueue_internal(ascb, asd_clear_nexus_complete, \
asd_clear_nexus_timedout); \
if (res) \
goto out_err; \
@@ -245,14 +245,14 @@ static int asd_clear_nexus_index(struct sas_task *task)
static void asd_tmf_timedout(struct timer_list *t)
{
struct asd_ascb *ascb = from_timer(ascb, t, timer);
- struct tasklet_completion_status *tcs = ascb->uldd_task;
+ struct completion_status *tcs = ascb->uldd_task;
ASD_DPRINTK("tmf timed out\n");
tcs->tmf_state = TMF_RESP_FUNC_FAILED;
complete(ascb->completion);
}
-static int asd_get_tmf_resp_tasklet(struct asd_ascb *ascb,
+static int asd_get_tmf_resp(struct asd_ascb *ascb,
struct done_list_struct *dl)
{
struct asd_ha_struct *asd_ha = ascb->ha;
@@ -270,7 +270,7 @@ static int asd_get_tmf_resp_tasklet(struct asd_ascb *ascb,
struct ssp_response_iu *ru;
int res = TMF_RESP_FUNC_FAILED;
- ASD_DPRINTK("tmf resp tasklet\n");
+ ASD_DPRINTK("tmf resp\n");
spin_lock_irqsave(&asd_ha->seq.tc_index_lock, flags);
escb = asd_tc_index_find(&asd_ha->seq,
@@ -298,21 +298,21 @@ static int asd_get_tmf_resp_tasklet(struct asd_ascb *ascb,
return res;
}
-static void asd_tmf_tasklet_complete(struct asd_ascb *ascb,
- struct done_list_struct *dl)
+static void asd_tmf_complete(struct asd_ascb *ascb,
+ struct done_list_struct *dl)
{
- struct tasklet_completion_status *tcs;
+ struct completion_status *tcs;
if (!del_timer(&ascb->timer))
return;
tcs = ascb->uldd_task;
- ASD_DPRINTK("tmf tasklet complete\n");
+ ASD_DPRINTK("tmf complete\n");
tcs->dl_opcode = dl->opcode;
if (dl->opcode == TC_SSP_RESP) {
- tcs->tmf_state = asd_get_tmf_resp_tasklet(ascb, dl);
+ tcs->tmf_state = asd_get_tmf_resp(ascb, dl);
tcs->tag_valid = ascb->tag_valid;
tcs->tag = ascb->tag;
}
@@ -452,7 +452,7 @@ int asd_abort_task(struct sas_task *task)
scb->abort_task.index = cpu_to_le16((u16)tascb->tc_index);
scb->abort_task.itnl_to = cpu_to_le16(ITNL_TIMEOUT_CONST);
- res = asd_enqueue_internal(ascb, asd_tmf_tasklet_complete,
+ res = asd_enqueue_internal(ascb, asd_tmf_complete,
asd_tmf_timedout);
if (res)
goto out_free;
@@ -600,7 +600,7 @@ static int asd_initiate_ssp_tmf(struct domain_device *dev, u8 *lun,
if (tmf == TMF_QUERY_TASK)
scb->ssp_tmf.index = cpu_to_le16(index);
- res = asd_enqueue_internal(ascb, asd_tmf_tasklet_complete,
+ res = asd_enqueue_internal(ascb, asd_tmf_complete,
asd_tmf_timedout);
if (res)
goto out_err;
Tasklets have long been deprecated as being too heavy on the system by running in irq context - and this is not a performance critical path. If a higher priority process wants to run, it must wait for the tasklet to finish before doing so. A more suitable equivalent is to converted to threaded irq instead and deal with the processing of donelist entries task context. Also rename a lot of calls removing the 'tasklet' part, which of course no longer applies. Signed-off-by: Davidlohr Bueso <dave@stgolabs.net> --- drivers/scsi/aic94xx/aic94xx_hwi.c | 23 ++------ drivers/scsi/aic94xx/aic94xx_hwi.h | 5 +- drivers/scsi/aic94xx/aic94xx_init.c | 5 +- drivers/scsi/aic94xx/aic94xx_scb.c | 88 ++++++++--------------------- drivers/scsi/aic94xx/aic94xx_task.c | 16 +++--- drivers/scsi/aic94xx/aic94xx_tmf.c | 40 ++++++------- 6 files changed, 63 insertions(+), 114 deletions(-)