static u32 board_added()

in hotplug/cpqphp_ctrl.c [1405:1601]


static u32 board_added(struct pci_func *func, struct controller *ctrl)
{
	u8 hp_slot;
	u8 temp_byte;
	u8 adapter_speed;
	int index;
	u32 temp_register = 0xFFFFFFFF;
	u32 rc = 0;
	struct pci_func *new_slot = NULL;
	struct pci_bus *bus = ctrl->pci_bus;
	struct slot *p_slot;
	struct resource_lists res_lists;

	hp_slot = func->device - ctrl->slot_device_offset;
	dbg("%s: func->device, slot_offset, hp_slot = %d, %d ,%d\n",
	    __func__, func->device, ctrl->slot_device_offset, hp_slot);

	mutex_lock(&ctrl->crit_sect);

	/* turn on board without attaching to the bus */
	enable_slot_power(ctrl, hp_slot);

	set_SOGO(ctrl);

	/* Wait for SOBS to be unset */
	wait_for_ctrl_irq(ctrl);

	/* Change bits in slot power register to force another shift out
	 * NOTE: this is to work around the timer bug
	 */
	temp_byte = readb(ctrl->hpc_reg + SLOT_POWER);
	writeb(0x00, ctrl->hpc_reg + SLOT_POWER);
	writeb(temp_byte, ctrl->hpc_reg + SLOT_POWER);

	set_SOGO(ctrl);

	/* Wait for SOBS to be unset */
	wait_for_ctrl_irq(ctrl);

	adapter_speed = get_adapter_speed(ctrl, hp_slot);
	if (bus->cur_bus_speed != adapter_speed)
		if (set_controller_speed(ctrl, adapter_speed, hp_slot))
			rc = WRONG_BUS_FREQUENCY;

	/* turn off board without attaching to the bus */
	disable_slot_power(ctrl, hp_slot);

	set_SOGO(ctrl);

	/* Wait for SOBS to be unset */
	wait_for_ctrl_irq(ctrl);

	mutex_unlock(&ctrl->crit_sect);

	if (rc)
		return rc;

	p_slot = cpqhp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);

	/* turn on board and blink green LED */

	dbg("%s: before down\n", __func__);
	mutex_lock(&ctrl->crit_sect);
	dbg("%s: after down\n", __func__);

	dbg("%s: before slot_enable\n", __func__);
	slot_enable(ctrl, hp_slot);

	dbg("%s: before green_LED_blink\n", __func__);
	green_LED_blink(ctrl, hp_slot);

	dbg("%s: before amber_LED_blink\n", __func__);
	amber_LED_off(ctrl, hp_slot);

	dbg("%s: before set_SOGO\n", __func__);
	set_SOGO(ctrl);

	/* Wait for SOBS to be unset */
	dbg("%s: before wait_for_ctrl_irq\n", __func__);
	wait_for_ctrl_irq(ctrl);
	dbg("%s: after wait_for_ctrl_irq\n", __func__);

	dbg("%s: before up\n", __func__);
	mutex_unlock(&ctrl->crit_sect);
	dbg("%s: after up\n", __func__);

	/* Wait for ~1 second because of hot plug spec */
	dbg("%s: before long_delay\n", __func__);
	long_delay(1*HZ);
	dbg("%s: after long_delay\n", __func__);

	dbg("%s: func status = %x\n", __func__, func->status);
	/* Check for a power fault */
	if (func->status == 0xFF) {
		/* power fault occurred, but it was benign */
		temp_register = 0xFFFFFFFF;
		dbg("%s: temp register set to %x by power fault\n", __func__, temp_register);
		rc = POWER_FAILURE;
		func->status = 0;
	} else {
		/* Get vendor/device ID u32 */
		ctrl->pci_bus->number = func->bus;
		rc = pci_bus_read_config_dword(ctrl->pci_bus, PCI_DEVFN(func->device, func->function), PCI_VENDOR_ID, &temp_register);
		dbg("%s: pci_read_config_dword returns %d\n", __func__, rc);
		dbg("%s: temp_register is %x\n", __func__, temp_register);

		if (rc != 0) {
			/* Something's wrong here */
			temp_register = 0xFFFFFFFF;
			dbg("%s: temp register set to %x by error\n", __func__, temp_register);
		}
		/* Preset return code.  It will be changed later if things go okay. */
		rc = NO_ADAPTER_PRESENT;
	}

	/* All F's is an empty slot or an invalid board */
	if (temp_register != 0xFFFFFFFF) {
		res_lists.io_head = ctrl->io_head;
		res_lists.mem_head = ctrl->mem_head;
		res_lists.p_mem_head = ctrl->p_mem_head;
		res_lists.bus_head = ctrl->bus_head;
		res_lists.irqs = NULL;

		rc = configure_new_device(ctrl, func, 0, &res_lists);

		dbg("%s: back from configure_new_device\n", __func__);
		ctrl->io_head = res_lists.io_head;
		ctrl->mem_head = res_lists.mem_head;
		ctrl->p_mem_head = res_lists.p_mem_head;
		ctrl->bus_head = res_lists.bus_head;

		cpqhp_resource_sort_and_combine(&(ctrl->mem_head));
		cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head));
		cpqhp_resource_sort_and_combine(&(ctrl->io_head));
		cpqhp_resource_sort_and_combine(&(ctrl->bus_head));

		if (rc) {
			mutex_lock(&ctrl->crit_sect);

			amber_LED_on(ctrl, hp_slot);
			green_LED_off(ctrl, hp_slot);
			slot_disable(ctrl, hp_slot);

			set_SOGO(ctrl);

			/* Wait for SOBS to be unset */
			wait_for_ctrl_irq(ctrl);

			mutex_unlock(&ctrl->crit_sect);
			return rc;
		} else {
			cpqhp_save_slot_config(ctrl, func);
		}


		func->status = 0;
		func->switch_save = 0x10;
		func->is_a_board = 0x01;

		/* next, we will instantiate the linux pci_dev structures (with
		 * appropriate driver notification, if already present) */
		dbg("%s: configure linux pci_dev structure\n", __func__);
		index = 0;
		do {
			new_slot = cpqhp_slot_find(ctrl->bus, func->device, index++);
			if (new_slot && !new_slot->pci_dev)
				cpqhp_configure_device(ctrl, new_slot);
		} while (new_slot);

		mutex_lock(&ctrl->crit_sect);

		green_LED_on(ctrl, hp_slot);

		set_SOGO(ctrl);

		/* Wait for SOBS to be unset */
		wait_for_ctrl_irq(ctrl);

		mutex_unlock(&ctrl->crit_sect);
	} else {
		mutex_lock(&ctrl->crit_sect);

		amber_LED_on(ctrl, hp_slot);
		green_LED_off(ctrl, hp_slot);
		slot_disable(ctrl, hp_slot);

		set_SOGO(ctrl);

		/* Wait for SOBS to be unset */
		wait_for_ctrl_irq(ctrl);

		mutex_unlock(&ctrl->crit_sect);

		return rc;
	}
	return 0;
}