diff mbox series

[1/6] scsi: hisi_sas: Use sbitmap for IPTT management

Message ID 1571926881-75524-2-git-send-email-john.garry@huawei.com
State New
Headers show
Series hisi_sas: Expose multiple hw queues for v3 hw as experimental | expand

Commit Message

John Garry Oct. 24, 2019, 2:21 p.m. UTC
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@huawei.com>

---
 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(-)

-- 
2.17.1
diff mbox series

Patch

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,