drivers/scsi/pm8001/pm8001_hwi.c

Source file repositories/reference/linux-study-clean/drivers/scsi/pm8001/pm8001_hwi.c

File Facts

System
Linux kernel
Corpus path
drivers/scsi/pm8001/pm8001_hwi.c
Extension
.c
Size
157383 bytes
Lines
4780
Domain
Driver Families
Bucket
drivers/scsi
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (-1 == pm8001_bar4_shift(pm8001_ha, GSM_SM_BASE)) {
			pm8001_dbg(pm8001_ha, FAIL,
				   "Shift Bar4 to 0x%x failed\n",
				   GSM_SM_BASE);
			return -1;
		}
	}
	/* check the firmware status */
	if (-1 == check_fw_ready(pm8001_ha)) {
		pm8001_dbg(pm8001_ha, FAIL, "Firmware is not ready!\n");
		return -EBUSY;
	}

	/* Initialize pci space address eg: mpi offset */
	init_pci_device_addresses(pm8001_ha);
	init_default_table_values(pm8001_ha);
	read_main_config_table(pm8001_ha);
	read_general_status_table(pm8001_ha);
	read_inbnd_queue_table(pm8001_ha);
	read_outbnd_queue_table(pm8001_ha);
	/* update main config table ,inbound table and outbound table */
	update_main_config_table(pm8001_ha);
	for (i = 0; i < pm8001_ha->max_q_num; i++)
		update_inbnd_queue_table(pm8001_ha, i);
	for (i = 0; i < pm8001_ha->max_q_num; i++)
		update_outbnd_queue_table(pm8001_ha, i);
	/* 8081 controller donot require these operations */
	if (deviceid != 0x8081 && deviceid != 0x0042) {
		mpi_set_phys_g3_with_ssc(pm8001_ha, 0);
		/* 7->130ms, 34->500ms, 119->1.5s */
		mpi_set_open_retry_interval_reg(pm8001_ha, 119);
	}
	/* notify firmware update finished and check initialization status */
	if (0 == mpi_init_check(pm8001_ha)) {
		pm8001_dbg(pm8001_ha, INIT, "MPI initialize successful!\n");
	} else
		return -EBUSY;
	/*This register is a 16-bit timer with a resolution of 1us. This is the
	timer used for interrupt delay/coalescing in the PCIe Application Layer.
	Zero is not a valid value. A value of 1 in the register will cause the
	interrupts to be normal. A value greater than 1 will cause coalescing
	delays.*/
	pm8001_cw32(pm8001_ha, 1, 0x0033c0, 0x1);
	pm8001_cw32(pm8001_ha, 1, 0x0033c4, 0x0);
	return 0;
}

static void pm8001_chip_post_init(struct pm8001_hba_info *pm8001_ha)
{
}

static int mpi_uninit_check(struct pm8001_hba_info *pm8001_ha)
{
	u32 max_wait_count;
	u32 value;
	u32 gst_len_mpistate;
	u16 deviceid;
	pci_read_config_word(pm8001_ha->pdev, PCI_DEVICE_ID, &deviceid);
	if (deviceid == 0x8081 || deviceid == 0x0042) {
		if (-1 == pm8001_bar4_shift(pm8001_ha, GSM_SM_BASE)) {
			pm8001_dbg(pm8001_ha, FAIL,
				   "Shift Bar4 to 0x%x failed\n",
				   GSM_SM_BASE);
			return -1;
		}
	}
	init_pci_device_addresses(pm8001_ha);
	/* Write bit1=1 to Inbound DoorBell Register to tell the SPC FW the
	table is stop */
	pm8001_cw32(pm8001_ha, 0, MSGU_IBDB_SET, SPC_MSGU_CFG_TABLE_RESET);

	/* wait until Inbound DoorBell Clear Register toggled */
	max_wait_count = 1 * 1000 * 1000;/* 1 sec */
	do {
		udelay(1);
		value = pm8001_cr32(pm8001_ha, 0, MSGU_IBDB_SET);
		value &= SPC_MSGU_CFG_TABLE_RESET;
	} while ((value != 0) && (--max_wait_count));

	if (!max_wait_count) {
		pm8001_dbg(pm8001_ha, FAIL, "TIMEOUT:IBDB value/=0x%x\n",
			   value);
		return -1;
	}

	/* check the MPI-State for termination in progress */
	/* wait until Inbound DoorBell Clear Register toggled */
	max_wait_count = 1 * 1000 * 1000;  /* 1 sec */
	do {
		udelay(1);

Annotation

Implementation Notes