Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3ad348d9 authored by James Smart's avatar James Smart Committed by Martin K. Petersen
Browse files

scsi: lpfc: Fix oops when fewer hdwqs than cpus



When tearing down the adapter for a reset, online/offline, or driver
unload, the queue free routine would hit a GPF oops.  This only occurs on
conditions where the number of hardware queues created is fewer than the
number of cpus in the system. In this condition cpus share a hardware
queue. And of course, it's the 2nd cpu that shares a hardware that
attempted to free it a second time and hit the oops.

Fix by reworking the cpu to hardware queue mapping such that:
Assignment of hardware queues to cpus occur in two passes:
first pass: is first time assignment of a hardware queue to a cpu.
  This will set the LPFC_CPU_FIRST_IRQ flag for the cpu.
second pass: for cpus that did not get a hardware queue they will
  be assigned one from a primary cpu (one set in first pass).

Deletion of hardware queues is driven by cpu itteration, and queues
will only be deleted if the LPFC_CPU_FIRST_IRQ flag is set.

Also contains a few small cleanup fixes and a little better logging.

Signed-off-by: default avatarDick Kennedy <dick.kennedy@broadcom.com>
Signed-off-by: default avatarJames Smart <jsmart2021@gmail.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 4b0a42be
Loading
Loading
Loading
Loading
+89 −55
Original line number Diff line number Diff line
@@ -8876,7 +8876,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba)
		}
		qdesc->qe_valid = 1;
		qdesc->hdwq = cpup->hdwq;
		qdesc->chann = cpu; /* First CPU this EQ is affinitised to */
		qdesc->chann = cpu; /* First CPU this EQ is affinitized to */
		qdesc->last_cpu = qdesc->chann;

		/* Save the allocated EQ in the Hardware Queue */
@@ -10723,7 +10723,7 @@ lpfc_find_hyper(struct lpfc_hba *phba, int cpu,
static void
lpfc_cpu_affinity_check(struct lpfc_hba *phba, int vectors)
{
	int i, cpu, idx, new_cpu, start_cpu, first_cpu;
	int i, cpu, idx, next_idx, new_cpu, start_cpu, first_cpu;
	int max_phys_id, min_phys_id;
	int max_core_id, min_core_id;
	struct lpfc_vector_map_info *cpup;
@@ -10765,8 +10765,8 @@ lpfc_cpu_affinity_check(struct lpfc_hba *phba, int vectors)
#endif

		lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
				"3328 CPU physid %d coreid %d\n",
				cpup->phys_id, cpup->core_id);
				"3328 CPU %d physid %d coreid %d flag x%x\n",
				cpu, cpup->phys_id, cpup->core_id, cpup->flag);

		if (cpup->phys_id > max_phys_id)
			max_phys_id = cpup->phys_id;
@@ -10805,17 +10805,17 @@ lpfc_cpu_affinity_check(struct lpfc_hba *phba, int vectors)
			cpup->eq = idx;
			cpup->irq = pci_irq_vector(phba->pcidev, idx);

			lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
					"3336 Set Affinity: CPU %d "
					"irq %d eq %d\n",
					cpu, cpup->irq, cpup->eq);

			/* If this is the first CPU thats assigned to this
			 * vector, set LPFC_CPU_FIRST_IRQ.
			 */
			if (!i)
				cpup->flag |= LPFC_CPU_FIRST_IRQ;
			i++;

			lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
					"3336 Set Affinity: CPU %d "
					"irq %d eq %d flag x%x\n",
					cpu, cpup->irq, cpup->eq, cpup->flag);
		}
	}

@@ -10929,30 +10929,68 @@ lpfc_cpu_affinity_check(struct lpfc_hba *phba, int vectors)
		}
	}

	/* Assign hdwq indices that are unique across all cpus in the map
	 * that are also FIRST_CPUs.
	 */
	idx = 0;
	for_each_present_cpu(cpu) {
		cpup = &phba->sli4_hba.cpu_map[cpu];

		/* Only FIRST IRQs get a hdwq index assignment. */
		if (!(cpup->flag & LPFC_CPU_FIRST_IRQ))
			continue;

		/* 1 to 1, the first LPFC_CPU_FIRST_IRQ cpus to a unique hdwq */
		cpup->hdwq = idx;
		idx++;
		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
				"3333 Set Affinity: CPU %d (phys %d core %d): "
				"hdwq %d eq %d irq %d flg x%x\n",
				cpu, cpup->phys_id, cpup->core_id,
				cpup->hdwq, cpup->eq, cpup->irq, cpup->flag);
	}
	/* Finally we need to associate a hdwq with each cpu_map entry
	 * This will be 1 to 1 - hdwq to cpu, unless there are less
	 * hardware queues then CPUs. For that case we will just round-robin
	 * the available hardware queues as they get assigned to CPUs.
	 * The next_idx is the idx from the FIRST_CPU loop above to account
	 * for irq_chann < hdwq.  The idx is used for round-robin assignments
	 * and needs to start at 0.
	 */
	idx = 0;
	next_idx = idx;
	start_cpu = 0;
	idx = 0;
	for_each_present_cpu(cpu) {
		cpup = &phba->sli4_hba.cpu_map[cpu];
		if (idx >=  phba->cfg_hdw_queue) {
			/* We need to reuse a Hardware Queue for another CPU,
			 * so be smart about it and pick one that has its
			 * IRQ/EQ mapped to the same phys_id (CPU package).
			 * and core_id.

		/* FIRST cpus are already mapped. */
		if (cpup->flag & LPFC_CPU_FIRST_IRQ)
			continue;

		/* If the cfg_irq_chann < cfg_hdw_queue, set the hdwq
		 * of the unassigned cpus to the next idx so that all
		 * hdw queues are fully utilized.
		 */
		if (next_idx < phba->cfg_hdw_queue) {
			cpup->hdwq = next_idx;
			next_idx++;
			continue;
		}

		/* Not a First CPU and all hdw_queues are used.  Reuse a
		 * Hardware Queue for another CPU, so be smart about it
		 * and pick one that has its IRQ/EQ mapped to the same phys_id
		 * (CPU package) and core_id.
		 */
		new_cpu = start_cpu;
		for (i = 0; i < phba->sli4_hba.num_present_cpu; i++) {
			new_cpup = &phba->sli4_hba.cpu_map[new_cpu];
				if ((new_cpup->hdwq != LPFC_VECTOR_MAP_EMPTY) &&
				    (new_cpup->phys_id == cpup->phys_id) &&
				    (new_cpup->core_id == cpup->core_id))
			if (new_cpup->hdwq != LPFC_VECTOR_MAP_EMPTY &&
			    new_cpup->phys_id == cpup->phys_id &&
			    new_cpup->core_id == cpup->core_id) {
				goto found_hdwq;
				new_cpu = cpumask_next(
					new_cpu, cpu_present_mask);
			}
			new_cpu = cpumask_next(new_cpu, cpu_present_mask);
			if (new_cpu == nr_cpumask_bits)
				new_cpu = first_cpu;
		}
@@ -10963,17 +11001,18 @@ lpfc_cpu_affinity_check(struct lpfc_hba *phba, int vectors)
		new_cpu = start_cpu;
		for (i = 0; i < phba->sli4_hba.num_present_cpu; i++) {
			new_cpup = &phba->sli4_hba.cpu_map[new_cpu];
				if ((new_cpup->hdwq != LPFC_VECTOR_MAP_EMPTY) &&
				    (new_cpup->phys_id == cpup->phys_id))
			if (new_cpup->hdwq != LPFC_VECTOR_MAP_EMPTY &&
			    new_cpup->phys_id == cpup->phys_id)
				goto found_hdwq;
				new_cpu = cpumask_next(
					new_cpu, cpu_present_mask);

			new_cpu = cpumask_next(new_cpu, cpu_present_mask);
			if (new_cpu == nr_cpumask_bits)
				new_cpu = first_cpu;
		}

		/* Otherwise just round robin on cfg_hdw_queue */
		cpup->hdwq = idx % phba->cfg_hdw_queue;
		idx++;
		goto logit;
 found_hdwq:
		/* We found an available entry, copy the IRQ info */
@@ -10981,17 +11020,12 @@ lpfc_cpu_affinity_check(struct lpfc_hba *phba, int vectors)
		if (start_cpu == nr_cpumask_bits)
			start_cpu = first_cpu;
		cpup->hdwq = new_cpup->hdwq;
		} else {
			/* 1 to 1, CPU to hdwq */
			cpup->hdwq = idx;
		}
 logit:
		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
				"3335 Set Affinity: CPU %d (phys %d core %d): "
				"hdwq %d eq %d irq %d flg x%x\n",
				cpu, cpup->phys_id, cpup->core_id,
				cpup->hdwq, cpup->eq, cpup->irq, cpup->flag);
		idx++;
	}

	/* The cpu_map array will be used later during initialization