static void bus_reset_work()

in ohci.c [1873:2056]


static void bus_reset_work(struct work_struct *work)
{
	struct fw_ohci *ohci =
		container_of(work, struct fw_ohci, bus_reset_work);
	int self_id_count, generation, new_generation, i, j;
	u32 reg;
	void *free_rom = NULL;
	dma_addr_t free_rom_bus = 0;
	bool is_new_root;

	reg = reg_read(ohci, OHCI1394_NodeID);
	if (!(reg & OHCI1394_NodeID_idValid)) {
		ohci_notice(ohci,
			    "node ID not valid, new bus reset in progress\n");
		return;
	}
	if ((reg & OHCI1394_NodeID_nodeNumber) == 63) {
		ohci_notice(ohci, "malconfigured bus\n");
		return;
	}
	ohci->node_id = reg & (OHCI1394_NodeID_busNumber |
			       OHCI1394_NodeID_nodeNumber);

	is_new_root = (reg & OHCI1394_NodeID_root) != 0;
	if (!(ohci->is_root && is_new_root))
		reg_write(ohci, OHCI1394_LinkControlSet,
			  OHCI1394_LinkControl_cycleMaster);
	ohci->is_root = is_new_root;

	reg = reg_read(ohci, OHCI1394_SelfIDCount);
	if (reg & OHCI1394_SelfIDCount_selfIDError) {
		ohci_notice(ohci, "self ID receive error\n");
		return;
	}
	/*
	 * The count in the SelfIDCount register is the number of
	 * bytes in the self ID receive buffer.  Since we also receive
	 * the inverted quadlets and a header quadlet, we shift one
	 * bit extra to get the actual number of self IDs.
	 */
	self_id_count = (reg >> 3) & 0xff;

	if (self_id_count > 252) {
		ohci_notice(ohci, "bad selfIDSize (%08x)\n", reg);
		return;
	}

	generation = (cond_le32_to_cpu(ohci->self_id[0]) >> 16) & 0xff;
	rmb();

	for (i = 1, j = 0; j < self_id_count; i += 2, j++) {
		u32 id  = cond_le32_to_cpu(ohci->self_id[i]);
		u32 id2 = cond_le32_to_cpu(ohci->self_id[i + 1]);

		if (id != ~id2) {
			/*
			 * If the invalid data looks like a cycle start packet,
			 * it's likely to be the result of the cycle master
			 * having a wrong gap count.  In this case, the self IDs
			 * so far are valid and should be processed so that the
			 * bus manager can then correct the gap count.
			 */
			if (id == 0xffff008f) {
				ohci_notice(ohci, "ignoring spurious self IDs\n");
				self_id_count = j;
				break;
			}

			ohci_notice(ohci, "bad self ID %d/%d (%08x != ~%08x)\n",
				    j, self_id_count, id, id2);
			return;
		}
		ohci->self_id_buffer[j] = id;
	}

	if (ohci->quirks & QUIRK_TI_SLLZ059) {
		self_id_count = find_and_insert_self_id(ohci, self_id_count);
		if (self_id_count < 0) {
			ohci_notice(ohci,
				    "could not construct local self ID\n");
			return;
		}
	}

	if (self_id_count == 0) {
		ohci_notice(ohci, "no self IDs\n");
		return;
	}
	rmb();

	/*
	 * Check the consistency of the self IDs we just read.  The
	 * problem we face is that a new bus reset can start while we
	 * read out the self IDs from the DMA buffer. If this happens,
	 * the DMA buffer will be overwritten with new self IDs and we
	 * will read out inconsistent data.  The OHCI specification
	 * (section 11.2) recommends a technique similar to
	 * linux/seqlock.h, where we remember the generation of the
	 * self IDs in the buffer before reading them out and compare
	 * it to the current generation after reading them out.  If
	 * the two generations match we know we have a consistent set
	 * of self IDs.
	 */

	new_generation = (reg_read(ohci, OHCI1394_SelfIDCount) >> 16) & 0xff;
	if (new_generation != generation) {
		ohci_notice(ohci, "new bus reset, discarding self ids\n");
		return;
	}

	/* FIXME: Document how the locking works. */
	spin_lock_irq(&ohci->lock);

	ohci->generation = -1; /* prevent AT packet queueing */
	context_stop(&ohci->at_request_ctx);
	context_stop(&ohci->at_response_ctx);

	spin_unlock_irq(&ohci->lock);

	/*
	 * Per OHCI 1.2 draft, clause 7.2.3.3, hardware may leave unsent
	 * packets in the AT queues and software needs to drain them.
	 * Some OHCI 1.1 controllers (JMicron) apparently require this too.
	 */
	at_context_flush(&ohci->at_request_ctx);
	at_context_flush(&ohci->at_response_ctx);

	spin_lock_irq(&ohci->lock);

	ohci->generation = generation;
	reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset);

	if (ohci->quirks & QUIRK_RESET_PACKET)
		ohci->request_generation = generation;

	/*
	 * This next bit is unrelated to the AT context stuff but we
	 * have to do it under the spinlock also.  If a new config rom
	 * was set up before this reset, the old one is now no longer
	 * in use and we can free it. Update the config rom pointers
	 * to point to the current config rom and clear the
	 * next_config_rom pointer so a new update can take place.
	 */

	if (ohci->next_config_rom != NULL) {
		if (ohci->next_config_rom != ohci->config_rom) {
			free_rom      = ohci->config_rom;
			free_rom_bus  = ohci->config_rom_bus;
		}
		ohci->config_rom      = ohci->next_config_rom;
		ohci->config_rom_bus  = ohci->next_config_rom_bus;
		ohci->next_config_rom = NULL;

		/*
		 * Restore config_rom image and manually update
		 * config_rom registers.  Writing the header quadlet
		 * will indicate that the config rom is ready, so we
		 * do that last.
		 */
		reg_write(ohci, OHCI1394_BusOptions,
			  be32_to_cpu(ohci->config_rom[2]));
		ohci->config_rom[0] = ohci->next_header;
		reg_write(ohci, OHCI1394_ConfigROMhdr,
			  be32_to_cpu(ohci->next_header));
	}

	if (param_remote_dma) {
		reg_write(ohci, OHCI1394_PhyReqFilterHiSet, ~0);
		reg_write(ohci, OHCI1394_PhyReqFilterLoSet, ~0);
	}

	spin_unlock_irq(&ohci->lock);

	if (free_rom)
		dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE,
				  free_rom, free_rom_bus);

	log_selfids(ohci, generation, self_id_count);

	fw_core_handle_bus_reset(&ohci->card, ohci->node_id, generation,
				 self_id_count, ohci->self_id_buffer,
				 ohci->csr_state_setclear_abdicate);
	ohci->csr_state_setclear_abdicate = false;
}