Using sbitmap will be more efficient in scenarios where we generate the IPTT in the driver, so make the transition. For non-v2 hw, we only use the sbitmap to manage reserved tags. For v2 hw, we use separate sbitmap sets to manage SAS/SMP and SATA tags. Using separate SATA sbitmaps for v2 hw was suggested by Hannes Reinecke. Signed-off-by: John Garry <john.garry@xxxxxxxxxx> --- drivers/scsi/hisi_sas/hisi_sas.h | 7 +- drivers/scsi/hisi_sas/hisi_sas_main.c | 82 +++++++------------ drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 107 +++++++++++++++++-------- 3 files changed, 109 insertions(+), 87 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index 233c73e01246..fbfaa92765cf 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -279,6 +279,8 @@ struct hisi_sas_hw { struct hisi_sas_device *device); int (*slot_index_alloc)(struct hisi_hba *hisi_hba, struct domain_device *device); + void (*slot_index_free)(struct hisi_hba *hisi_hba, int slot_idx); + int (*bitmaps_alloc)(struct hisi_hba *hisi_hba); struct hisi_sas_device *(*alloc_dev)(struct domain_device *device); void (*sl_notify_ssp)(struct hisi_hba *hisi_hba, int phy_no); void (*start_delivery)(struct hisi_sas_dq *dq); @@ -388,10 +390,9 @@ struct hisi_hba { struct timer_list timer; struct workqueue_struct *wq; - int slot_index_count; int last_slot_index; int last_dev_id; - unsigned long *slot_index_tags; + struct sbitmap slot_index_tags; unsigned long reject_stp_links_msk; /* SCSI/SAS glue */ @@ -424,6 +425,8 @@ struct hisi_hba { unsigned long flags; const struct hisi_sas_hw *hw; /* Low level hw interface */ unsigned long sata_dev_bitmap[BITS_TO_LONGS(HISI_SAS_MAX_DEVICES)]; + struct sbitmap sata_slot_index_tags[HISI_SAS_MAX_DEVICES]; + int sbitmap_alloc_hint; struct work_struct rst_work; struct work_struct debugfs_work; u32 phy_state; diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index a7af9483b678..f4937da9baf8 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -156,65 +156,36 @@ EXPORT_SYMBOL_GPL(hisi_sas_stop_phys); static void hisi_sas_slot_index_clear(struct hisi_hba *hisi_hba, int slot_idx) { - void *bitmap = hisi_hba->slot_index_tags; + struct sbitmap *slot_index_tags = &hisi_hba->slot_index_tags; - clear_bit(slot_idx, bitmap); + sbitmap_clear_bit(slot_index_tags, slot_idx); } static void hisi_sas_slot_index_free(struct hisi_hba *hisi_hba, int slot_idx) { - unsigned long flags; - - if (hisi_hba->hw->slot_index_alloc || - slot_idx >= HISI_SAS_UNRESERVED_IPTT) { - spin_lock_irqsave(&hisi_hba->lock, flags); - hisi_sas_slot_index_clear(hisi_hba, slot_idx); - spin_unlock_irqrestore(&hisi_hba->lock, flags); - } -} - -static void hisi_sas_slot_index_set(struct hisi_hba *hisi_hba, int slot_idx) -{ - void *bitmap = hisi_hba->slot_index_tags; - - set_bit(slot_idx, bitmap); + if (hisi_hba->hw->slot_index_free) + hisi_hba->hw->slot_index_free(hisi_hba, slot_idx); + else if (slot_idx >= HISI_SAS_UNRESERVED_IPTT) + hisi_sas_slot_index_clear(hisi_hba, + slot_idx - HISI_SAS_UNRESERVED_IPTT); } static int hisi_sas_slot_index_alloc(struct hisi_hba *hisi_hba, struct scsi_cmnd *scsi_cmnd) { + struct sbitmap *slot_index_tags = &hisi_hba->slot_index_tags; int index; - void *bitmap = hisi_hba->slot_index_tags; - unsigned long flags; if (scsi_cmnd) return scsi_cmnd->request->tag; - spin_lock_irqsave(&hisi_hba->lock, flags); - index = find_next_zero_bit(bitmap, hisi_hba->slot_index_count, - hisi_hba->last_slot_index + 1); - if (index >= hisi_hba->slot_index_count) { - index = find_next_zero_bit(bitmap, - hisi_hba->slot_index_count, - HISI_SAS_UNRESERVED_IPTT); - if (index >= hisi_hba->slot_index_count) { - spin_unlock_irqrestore(&hisi_hba->lock, flags); - return -SAS_QUEUE_FULL; - } - } - hisi_sas_slot_index_set(hisi_hba, index); - hisi_hba->last_slot_index = index; - spin_unlock_irqrestore(&hisi_hba->lock, flags); + index = sbitmap_get(slot_index_tags, hisi_hba->sbitmap_alloc_hint, + false); + if (index == -1) + return index; + hisi_hba->sbitmap_alloc_hint = (index + 1) % slot_index_tags->depth; - return index; -} - -static void hisi_sas_slot_index_init(struct hisi_hba *hisi_hba) -{ - int i; - - for (i = 0; i < hisi_hba->slot_index_count; ++i) - hisi_sas_slot_index_clear(hisi_hba, i); + return index + HISI_SAS_UNRESERVED_IPTT; } void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task, @@ -481,7 +452,7 @@ static int hisi_sas_task_prep(struct sas_task *task, scsi_cmnd = task->uldd_task; } } - rc = hisi_sas_slot_index_alloc(hisi_hba, scsi_cmnd); + rc = hisi_sas_slot_index_alloc(hisi_hba, scsi_cmnd); } if (rc < 0) goto err_out_dif_dma_unmap; @@ -1957,7 +1928,10 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id, port = to_hisi_sas_port(sas_port); /* simply get a slot and send abort command */ - rc = hisi_sas_slot_index_alloc(hisi_hba, NULL); + if (hisi_hba->hw->slot_index_alloc) + rc = hisi_hba->hw->slot_index_alloc(hisi_hba, device); + else + rc = hisi_sas_slot_index_alloc(hisi_hba, NULL); if (rc < 0) goto err_out; @@ -2309,7 +2283,7 @@ int hisi_sas_alloc(struct hisi_hba *hisi_hba) struct device *dev = hisi_hba->dev; int i, j, s, max_command_entries = HISI_SAS_MAX_COMMANDS; int max_command_entries_ru, sz_slot_buf_ru; - int blk_cnt, slots_per_blk; + int blk_cnt, slots_per_blk, rc; sema_init(&hisi_hba->sem, 1); spin_lock_init(&hisi_hba->lock); @@ -2415,10 +2389,13 @@ int hisi_sas_alloc(struct hisi_hba *hisi_hba) if (!hisi_hba->breakpoint) goto err_out; - hisi_hba->slot_index_count = max_command_entries; - s = hisi_hba->slot_index_count / BITS_PER_BYTE; - hisi_hba->slot_index_tags = devm_kzalloc(dev, s, GFP_KERNEL); - if (!hisi_hba->slot_index_tags) + if (hisi_hba->hw->bitmaps_alloc) + rc = hisi_hba->hw->bitmaps_alloc(hisi_hba); + else + rc = sbitmap_init_node(&hisi_hba->slot_index_tags, + HISI_SAS_RESERVED_IPTT, -1, + GFP_KERNEL, dev_to_node(dev)); + if (rc) goto err_out; s = sizeof(struct hisi_sas_initial_fis) * HISI_SAS_MAX_PHYS; @@ -2435,7 +2412,6 @@ int hisi_sas_alloc(struct hisi_hba *hisi_hba) if (!hisi_hba->sata_breakpoint) goto err_out; - hisi_sas_slot_index_init(hisi_hba); hisi_hba->last_slot_index = HISI_SAS_UNRESERVED_IPTT; hisi_hba->wq = create_singlethread_workqueue(dev_name(dev)); @@ -2460,6 +2436,10 @@ void hisi_sas_free(struct hisi_hba *hisi_hba) del_timer_sync(&phy->timer); } + sbitmap_free(&hisi_hba->slot_index_tags); + for (i = 0; i < HISI_SAS_MAX_DEVICES; i++) + sbitmap_free(&hisi_hba->sata_slot_index_tags[i]); + if (hisi_hba->wq) destroy_workqueue(hisi_hba->wq); } diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 61b1e2693b08..683e1b99c9ae 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -763,59 +763,96 @@ static u32 hisi_sas_phy_read32(struct hisi_hba *hisi_hba, return readl(regs); } -/* This function needs to be protected from pre-emption. */ +static int bitmaps_alloc_v2_hw(struct hisi_hba *hisi_hba) +{ + struct device *dev = hisi_hba->dev; + int sata_idx, i; + + if (sbitmap_init_node(&hisi_hba->slot_index_tags, + HISI_SAS_MAX_COMMANDS / 2, -1, + GFP_KERNEL, dev_to_node(hisi_hba->dev))) + return -ENOMEM; + + for (sata_idx = 0; sata_idx < HISI_MAX_SATA_SUPPORT_V2_HW; sata_idx++) { + if (sbitmap_init_node(&hisi_hba->sata_slot_index_tags[sata_idx], + 32, -1, GFP_KERNEL, dev_to_node(dev))) + goto free_slot_index_tags; + } + + return 0; + +free_slot_index_tags: + sbitmap_free(&hisi_hba->slot_index_tags); + for (i = 0; i < HISI_MAX_SATA_SUPPORT_V2_HW; i++) + sbitmap_free(&hisi_hba->sata_slot_index_tags[sata_idx]); + + return -ENOMEM; +} + static int slot_index_alloc_quirk_v2_hw(struct hisi_hba *hisi_hba, struct domain_device *device) { + struct sbitmap *slot_index_tags; int sata_dev = dev_is_sata(device); - void *bitmap = hisi_hba->slot_index_tags; struct hisi_sas_device *sas_dev = device->lldd_dev; int sata_idx = sas_dev->sata_idx; - int start, end; - unsigned long flags; + int start; + + if (sata_dev) { + int start; + int base = 64 * (sata_idx + 1); - if (!sata_dev) { - /* - * STP link SoC bug workaround: index starts from 1. - * additionally, we can only allocate odd IPTT(1~4095) - * for SAS/SMP device. - */ - start = 1; - end = hisi_hba->slot_index_count; - } else { if (sata_idx >= HISI_MAX_SATA_SUPPORT_V2_HW) return -EINVAL; - /* * For SATA device: allocate even IPTT in this interval * [64*(sata_idx+1), 64*(sata_idx+2)], then each SATA device * own 32 IPTTs. IPTT 0 shall not be used duing to STP link * SoC bug workaround. So we ignore the first 32 even IPTTs. */ - start = 64 * (sata_idx + 1); - end = 64 * (sata_idx + 2); - } - spin_lock_irqsave(&hisi_hba->lock, flags); - while (1) { - start = find_next_zero_bit(bitmap, - hisi_hba->slot_index_count, start); - if (start >= end) { - spin_unlock_irqrestore(&hisi_hba->lock, flags); - return -SAS_QUEUE_FULL; - } - /* - * SAS IPTT bit0 should be 1, and SATA IPTT bit0 should be 0. - */ - if (sata_dev ^ (start & 1)) - break; - start++; + slot_index_tags = &hisi_hba->sata_slot_index_tags[sata_idx]; + + start = sbitmap_get(slot_index_tags, 0, true); + if (start == -1) + return -ENOMEM; + start *= 2; + return start + base; } - set_bit(start, bitmap); - spin_unlock_irqrestore(&hisi_hba->lock, flags); - return start; + slot_index_tags = &hisi_hba->slot_index_tags; + start = sbitmap_get(slot_index_tags, hisi_hba->sbitmap_alloc_hint, + true); + if (start == -1) + return -ENOMEM; + + /* + * SAS/SMP IPTT bit0 should be 1, and SATA IPTT bit0 should be 0. + */ + return (start * 2) + 1; +} + +static void slot_index_free_quirk_v2_hw(struct hisi_hba *hisi_hba, int slot_idx) +{ + struct sbitmap *slot_index_tags; + + if (slot_idx & 1) { + int start = (slot_idx - 1) / 2; + + slot_index_tags = &hisi_hba->slot_index_tags; + sbitmap_clear_bit(&hisi_hba->slot_index_tags, start); + hisi_hba->sbitmap_alloc_hint = (start + 1) % + slot_index_tags->depth; + } else { + int sata_idx = (slot_idx / 64) - 1; + int base = 64 * (sata_idx + 1); + + slot_index_tags = &hisi_hba->sata_slot_index_tags[sata_idx]; + slot_idx -= base; + slot_idx /= 2; + sbitmap_clear_bit(slot_index_tags, slot_idx); + } } static bool sata_index_alloc_v2_hw(struct hisi_hba *hisi_hba, int *idx) @@ -3559,6 +3596,8 @@ static const struct hisi_sas_hw hisi_sas_v2_hw = { .hw_init = hisi_sas_v2_init, .setup_itct = setup_itct_v2_hw, .slot_index_alloc = slot_index_alloc_quirk_v2_hw, + .slot_index_free = slot_index_free_quirk_v2_hw, + .bitmaps_alloc = bitmaps_alloc_v2_hw, .alloc_dev = alloc_dev_quirk_v2_hw, .sl_notify_ssp = sl_notify_ssp_v2_hw, .get_wideport_bitmap = get_wideport_bitmap_v2_hw, -- 2.17.1