/**
 * hsi_driver_int_proc - check all channels / ports for interrupts events
 * @hsi_ctrl - HSI controler data
 * @status_offset: interrupt status register offset
 * @enable_offset: interrupt enable regiser offset
 * @start: interrupt index to start on
 * @stop: interrupt index to stop on
 *
 * This function calls the related processing functions and triggered events
*/
static void hsi_driver_int_proc(struct hsi_port *pport,
		unsigned long status_offset, unsigned long enable_offset,
		unsigned int start, unsigned int stop)
{
	struct hsi_dev *hsi_ctrl = pport->hsi_controller;
	void __iomem *base = hsi_ctrl->base;
	unsigned int port = pport->port_number;
	unsigned int channel;
	u32 status_reg;
	u32 hsr_err_reg;
	u32 channels_served = 0;

	status_reg = hsi_inl(base, status_offset);
	status_reg &= hsi_inl(base, enable_offset);

	for (channel = start; channel < stop; channel++) {
		if (status_reg & HSI_HST_DATAACCEPT(channel)) {

			do_channel_tx(&pport->hsi_channel[channel]);
			channels_served |= HSI_HST_DATAACCEPT(channel);
		}

		if (status_reg & HSI_HSR_DATAAVAILABLE(channel)) {
			do_channel_rx(&pport->hsi_channel[channel]);
			channels_served |= HSI_HSR_DATAAVAILABLE(channel);
		}
	}

	if (status_reg & HSI_BREAKDETECTED) {
		dev_info(hsi_ctrl->dev, "Hardware BREAK on port %d\n", port);
		hsi_outl(0, base, HSI_HSR_BREAK_REG(port));
		hsi_port_event_handler(pport, HSI_EVENT_BREAK_DETECTED, NULL);
		channels_served |= HSI_BREAKDETECTED;
	}

	if (status_reg & HSI_ERROROCCURED) {
		hsr_err_reg = hsi_inl(base, HSI_HSR_ERROR_REG(port));
		dev_err(hsi_ctrl->dev, "HSI ERROR Port %d: 0x%x\n",
							port, hsr_err_reg);
		hsi_outl(hsr_err_reg, base, HSI_HSR_ERRORACK_REG(port));
		if (hsr_err_reg) /* ignore spurious errors */
			hsi_port_event_handler(pport, HSI_EVENT_ERROR, NULL);
		else
			dev_dbg(hsi_ctrl->dev, "Spurious HSI error!\n");

		channels_served |= HSI_ERROROCCURED;
	}

	hsi_outl(channels_served, base, status_offset);
}
static void do_channel_rx(struct hsi_channel *ch)
{
	struct hsi_dev *hsi_ctrl = ch->hsi_port->hsi_controller;
	void __iomem *base = ch->hsi_port->hsi_controller->base;
	unsigned int n_ch;
	unsigned int n_p;
	unsigned int irq;
	long buff_offset;
	int rx_poll = 0;
	int data_read = 0;

	n_ch = ch->channel_number;
	n_p = ch->hsi_port->port_number;
	irq = ch->hsi_port->n_irq;

	spin_lock(&hsi_ctrl->lock);

	if (ch->flags & HSI_CH_RX_POLL)
		rx_poll = 1;

	if (ch->read_data.addr) {
		buff_offset = hsi_hsr_buffer_reg(hsi_ctrl, n_p, n_ch);
		if (buff_offset >= 0) {
			data_read = 1;
			*(ch->read_data.addr) = hsi_inl(base, buff_offset);
		}
	}

	hsi_outl_and(~HSI_HSR_DATAAVAILABLE(n_ch), base,
				HSI_SYS_MPU_ENABLE_CH_REG(n_p, irq, n_ch));
	hsi_reset_ch_read(ch);

	spin_unlock(&hsi_ctrl->lock);

	if (rx_poll)
		hsi_port_event_handler(ch->hsi_port,
				HSI_EVENT_HSR_DATAAVAILABLE, (void *)n_ch);

	if (data_read)
		(*ch->read_done)(ch->dev, 1);
}
/**
 * hsi_driver_int_proc - check all channels / ports for interrupts events
 * @hsi_ctrl - HSI controler data
 * @status_offset: interrupt status register offset
 * @enable_offset: interrupt enable regiser offset
 * @start: interrupt index to start on
 * @stop: interrupt index to stop on
 *
 * returns the bitmap of processed events
 *
 * This function calls the related processing functions and triggered events.
 * Events are cleared after corresponding function has been called.
*/
static u32 hsi_driver_int_proc(struct hsi_port *pport,
				unsigned long status_offset,
				unsigned long enable_offset, unsigned int start,
				unsigned int stop,
				bool cawake_double_int)
{
	struct hsi_dev *hsi_ctrl = pport->hsi_controller;
	void __iomem *base = hsi_ctrl->base;
	unsigned int port = pport->port_number;
	unsigned int channel;
	u32 status_reg;
	u32 hsr_err_reg;
	u32 channels_served = 0;

	/* Get events status */
	status_reg = hsi_inl(base, status_offset);
	status_reg &= hsi_inl(base, enable_offset);

	/* Check if we need to process an additional CAWAKE interrupt */
	if (cawake_double_int)
		status_reg |= HSI_CAWAKEDETECTED;

	if (pport->cawake_off_event) {
		dev_dbg(hsi_ctrl->dev, "CAWAKE detected from OFF mode.\n");
	} else if (!status_reg) {
		dev_dbg(hsi_ctrl->dev, "Channels [%d,%d] : no event, exit.\n",
			start, stop);
			return 0;
	} else {
		dev_dbg(hsi_ctrl->dev, "Channels [%d,%d] : Events 0x%08x\n",
			start, stop, status_reg);
	}

	if (status_reg & HSI_BREAKDETECTED) {
		dev_info(hsi_ctrl->dev, "Hardware BREAK on port %d\n", port);
		spin_unlock(&hsi_ctrl->lock);
		hsi_port_event_handler(pport, HSI_EVENT_BREAK_DETECTED, NULL);
		spin_lock(&hsi_ctrl->lock);

		channels_served |= HSI_BREAKDETECTED;
	}

	if (status_reg & HSI_ERROROCCURED) {
		hsr_err_reg = hsi_inl(base, HSI_HSR_ERROR_REG(port));
		if (hsr_err_reg & HSI_HSR_ERROR_SIG)
			dev_err(hsi_ctrl->dev, "HSI ERROR Port %d: 0x%x: %s\n",
				port, hsr_err_reg, "Signal Error");
		if (hsr_err_reg & HSI_HSR_ERROR_FTE)
			dev_err(hsi_ctrl->dev, "HSI ERROR Port %d: 0x%x: %s\n",
				port, hsr_err_reg, "Frame Timeout Error");
		if (hsr_err_reg & HSI_HSR_ERROR_TBE)
			dev_err(hsi_ctrl->dev, "HSI ERROR Port %d: 0x%x: %s\n",
				port, hsr_err_reg, "Tailing Bit Error");
		if (hsr_err_reg & HSI_HSR_ERROR_RME)
			dev_err(hsi_ctrl->dev, "HSI ERROR Port %d: 0x%x: %s\n",
				port, hsr_err_reg, "RX Mapping Error");
		if (hsr_err_reg & HSI_HSR_ERROR_TME)
			dev_err(hsi_ctrl->dev, "HSI ERROR Port %d: 0x%x: %s\n",
				port, hsr_err_reg, "TX Mapping Error");
		/* Clear error event bit */
		hsi_outl(hsr_err_reg, base, HSI_HSR_ERRORACK_REG(port));
		if (hsr_err_reg) {	/* ignore spurious errors */
			spin_unlock(&hsi_ctrl->lock);
			hsi_port_event_handler(pport, HSI_EVENT_ERROR, NULL);
			spin_lock(&hsi_ctrl->lock);
		} else
			dev_dbg(hsi_ctrl->dev, "Spurious HSI error!\n");

		channels_served |= HSI_ERROROCCURED;
	}

	for (channel = start; channel <= stop; channel++) {
		if (status_reg & HSI_HST_DATAACCEPT(channel)) {
			hsi_do_channel_tx(&pport->hsi_channel[channel]);
			channels_served |= HSI_HST_DATAACCEPT(channel);
		}

		if (status_reg & HSI_HSR_DATAAVAILABLE(channel)) {
			hsi_do_channel_rx(&pport->hsi_channel[channel]);
			channels_served |= HSI_HSR_DATAAVAILABLE(channel);
		}

		if (status_reg & HSI_HSR_DATAOVERRUN(channel)) {
			/*HSI_TODO : Data overrun handling*/
			dev_err(hsi_ctrl->dev,
				"Data overrun in real time mode !\n");
		}
	}

	/* CAWAKE falling or rising edge detected */
	if ((status_reg & HSI_CAWAKEDETECTED) || pport->cawake_off_event) {
		if (hsi_do_cawake_process(pport) == -EAGAIN)
			goto proc_done;

		channels_served |= HSI_CAWAKEDETECTED;
		pport->cawake_off_event = false;
	}
proc_done:
	/* Reset status bits */
	hsi_outl(channels_served, base, status_offset);

	return channels_served;
}
/**
 * hsi_do_cawake_process - CAWAKE line management
 * @pport - HSI port to process
 *
 * This function handles the CAWAKE L/H transitions and call the event callback
 * accordingly.
 *
 * Returns 0 if CAWAKE event process, -EAGAIN if CAWAKE event processing is
 * delayed due to a pending DMA interrupt.
 * If -EAGAIN is returned, pport->hsi_tasklet has to be re-scheduled once
 * DMA tasklet has be executed. This should be done automatically by driver.
 *
*/
int hsi_do_cawake_process(struct hsi_port *pport)
{
	struct hsi_dev *hsi_ctrl = pport->hsi_controller;
	bool cawake_status = hsi_get_cawake(pport);

	if (pport->wake_rx_3_wires_mode) {
		dev_warn(hsi_ctrl->dev, "CAWAKE edge in RX 3 wires, exiting\n");
		return 0;
	}

	/* Deal with init condition */
	if (unlikely(pport->cawake_status < 0))
		pport->cawake_status = !cawake_status;
	dev_dbg(hsi_ctrl->dev, "%s: Interrupts are not enabled but CAWAKE came."
		"hsi: port[%d] irq[%d] irq_en=0x%08x dma_irq_en=0x%08x\n",
		__func__, pport->port_number, pport->n_irq,
		hsi_inl(pport->hsi_controller->base,
			HSI_SYS_MPU_ENABLE_REG(pport->port_number,
					pport->n_irq)),
		hsi_inl(pport->hsi_controller->base,
			HSI_SYS_GDD_MPU_IRQ_ENABLE_REG));

	/* Check CAWAKE line status */
	if (cawake_status) {
		dev_dbg(hsi_ctrl->dev, "CAWAKE rising edge detected\n");

		/* Check for possible mismatch (race condition) */
		if (unlikely(pport->cawake_status)) {
			dev_warn(hsi_ctrl->dev,
				"Missed previous CAWAKE falling edge...\n");
			spin_unlock(&hsi_ctrl->lock);
			hsi_port_event_handler(pport, HSI_EVENT_CAWAKE_DOWN,
						NULL);
			spin_lock(&hsi_ctrl->lock);

			/* In case another CAWAKE interrupt occured and caused
			 * a race condition, clear CAWAKE backup interrupt to
			 * avoid handling twice the race condition */
			hsi_driver_ack_interrupt(pport, HSI_CAWAKEDETECTED,
						 true);
		}
		pport->cawake_status = 1;

		spin_unlock(&hsi_ctrl->lock);
		hsi_port_event_handler(pport, HSI_EVENT_CAWAKE_UP, NULL);
		spin_lock(&hsi_ctrl->lock);

		/*
		* HSI - OMAP4430-2.2BUG00055: i702
		* HSI: DSP Swakeup generated is the same than MPU Swakeup.
		* System cannot enter in off mode due to the DSP.
		*/
		if (is_hsi_errata(hsi_ctrl, HSI_ERRATUM_i702_PM_HSI_SWAKEUP))
			omap_pm_clear_dsp_wake_up();

	} else {
		dev_dbg(hsi_ctrl->dev, "CAWAKE falling edge detected\n");

		/* Check for pending DMA interrupt */
		if (hsi_is_dma_read_int_pending(hsi_ctrl)) {
			dev_dbg(hsi_ctrl->dev, "Pending DMA Read interrupt "
					       "before CAWAKE->L, exiting "
					       "Interrupt tasklet.\n");
			return -EAGAIN;
		}
		if (unlikely(!pport->cawake_status)) {
			dev_warn(hsi_ctrl->dev,
				"Missed previous CAWAKE rising edge...\n");
			spin_unlock(&hsi_ctrl->lock);
			hsi_port_event_handler(pport, HSI_EVENT_CAWAKE_UP,
						NULL);
			spin_lock(&hsi_ctrl->lock);

			/* In case another CAWAKE interrupt occured and caused
			 * a race condition, clear CAWAKE backup interrupt to
			 * avoid handling twice the race condition */
			hsi_driver_ack_interrupt(pport, HSI_CAWAKEDETECTED,
						 true);
		}
		pport->cawake_status = 0;

		spin_unlock(&hsi_ctrl->lock);
		hsi_port_event_handler(pport, HSI_EVENT_CAWAKE_DOWN, NULL);
		spin_lock(&hsi_ctrl->lock);
	}

	/* If another CAWAKE event occured while previous is still processed */
	/* do not clear the status bit */
	cawake_status = hsi_get_cawake(pport);
	if (cawake_status != pport->cawake_status) {
		dev_warn(hsi_ctrl->dev, "CAWAKE line changed to %d while CAWAKE"
					"event is still being processed\n",
					cawake_status);
		return -EAGAIN;
	}

	return 0;
}
/* HSR_AVAILABLE interrupt processing */
static void hsi_do_channel_rx(struct hsi_channel *ch)
{
	struct hsi_dev *hsi_ctrl = ch->hsi_port->hsi_controller;
	void __iomem *base = ch->hsi_port->hsi_controller->base;
	unsigned int n_ch;
	unsigned int n_p;
	unsigned int irq;
	long buff_offset;
	int rx_poll = 0;
	int data_read = 0;
	int fifo, fifo_words_avail;

	n_ch = ch->channel_number;
	n_p = ch->hsi_port->port_number;
	irq = ch->hsi_port->n_irq;

	dev_dbg(hsi_ctrl->dev,
		"Data Available interrupt for channel %d.\n", n_ch);

	/* Check if there is data in FIFO available for reading */
	if (hsi_driver_device_is_hsi(to_platform_device(hsi_ctrl->dev))) {
		fifo = hsi_fifo_get_id(hsi_ctrl, n_ch, n_p);
		if (unlikely(fifo < 0)) {
			dev_err(hsi_ctrl->dev, "No valid FIFO id found for "
					       "channel %d.\n", n_ch);
			return;
		}
		fifo_words_avail = hsi_get_rx_fifo_occupancy(hsi_ctrl, fifo);
		if (!fifo_words_avail) {
			dev_dbg(hsi_ctrl->dev,
				"WARNING: RX FIFO %d empty before CPU copy\n",
				fifo);

			/* Do not disable interrupt becaue another interrupt */
			/* can still come, this time with a real frame. */
			return;
		}
	}

	/* Disable interrupts if not needed for polling */
	if (!(ch->flags & HSI_CH_RX_POLL))
		hsi_driver_disable_read_interrupt(ch);

	/*
	 * Check race condition: RX transmission initiated but DMA transmission
	 * already started - acknowledge then ignore interrupt occurence
	 */
	if (ch->read_data.lch != -1) {
		dev_warn(hsi_ctrl->dev,
			"Race condition between RX Int ch %d and DMA %0x\n",
			n_ch, ch->read_data.lch);
		goto done;
	}

	if (ch->flags & HSI_CH_RX_POLL)
		rx_poll = 1;

	if (ch->read_data.addr) {
		buff_offset = hsi_hsr_buffer_reg(hsi_ctrl, n_p, n_ch);
		if (buff_offset >= 0) {
			data_read = 1;
			*(ch->read_data.addr) = hsi_inl(base, buff_offset);
		}
	}

	hsi_reset_ch_read(ch);

done:
	if (rx_poll) {
		spin_unlock(&hsi_ctrl->lock);
		hsi_port_event_handler(ch->hsi_port,
				       HSI_EVENT_HSR_DATAAVAILABLE,
				       (void *)n_ch);
		spin_lock(&hsi_ctrl->lock);
	}

	if (data_read) {
		spin_unlock(&hsi_ctrl->lock);
		dev_dbg(hsi_ctrl->dev, "Calling ch %d read callback.\n", n_ch);
		(*ch->read_done) (ch->dev, 1);
		spin_lock(&hsi_ctrl->lock);
	}
}
/**
 * hsi_do_cawake_process - CAWAKE line management
 * @pport - HSI port to process
 *
 * This function handles the CAWAKE L/H transitions and call the event callback
 * accordingly.
 *
 * Returns 0 if CAWAKE event process, -EAGAIN if CAWAKE event processing is
 * delayed due to a pending DMA interrupt.
 * If -EAGAIN is returned, pport->hsi_tasklet has to be re-scheduled once
 * DMA tasklet has be executed. This should be done automatically by driver.
 *
*/
int hsi_do_cawake_process(struct hsi_port *pport)
{
	struct hsi_dev *hsi_ctrl = pport->hsi_controller;
	bool cawake_status = hsi_get_cawake(pport);

	if (pport->wake_rx_3_wires_mode) {
		dev_warn(hsi_ctrl->dev, "CAWAKE edge in RX 3 wires, exiting\n");
		return 0;
	}

	/* Deal with init condition */
	if (unlikely(pport->cawake_status < 0))
		pport->cawake_status = !cawake_status;

	/* Check CAWAKE line status */
	if (cawake_status) {
		dev_dbg(hsi_ctrl->dev, "CAWAKE rising edge detected\n");

		/* Check for possible mismatch (race condition) */
		if (unlikely(pport->cawake_status)) {
			dev_warn(hsi_ctrl->dev,
				"Missed previous CAWAKE falling edge...\n");
			spin_unlock(&hsi_ctrl->lock);
			hsi_port_event_handler(pport, HSI_EVENT_CAWAKE_DOWN,
						NULL);
			spin_lock(&hsi_ctrl->lock);

			/* In case another CAWAKE interrupt occured and caused
			 * a race condition, clear CAWAKE backup interrupt to
			 * avoid handling twice the race condition */
			hsi_driver_ack_interrupt(pport, HSI_CAWAKEDETECTED,
						 true);
		}
		pport->cawake_status = 1;

		/* Allow data reception */
		hsi_hsr_resume(hsi_ctrl);

		spin_unlock(&hsi_ctrl->lock);
		hsi_port_event_handler(pport, HSI_EVENT_CAWAKE_UP, NULL);
		spin_lock(&hsi_ctrl->lock);

		/*
		* HSI - OMAP4430-2.2BUG00055: i702
		* HSI: DSP Swakeup generated is the same than MPU Swakeup.
		* System cannot enter in off mode due to the DSP.
		*/
		if (is_hsi_errata(hsi_ctrl, HSI_ERRATUM_i702_PM_HSI_SWAKEUP))
			omap_pm_clear_dsp_wake_up();

	} else {
		dev_dbg(hsi_ctrl->dev, "CAWAKE falling edge detected\n");

		/* Check for pending DMA interrupt */
		if (hsi_is_dma_read_int_pending(hsi_ctrl)) {
			dev_dbg(hsi_ctrl->dev, "Pending DMA Read interrupt "
					       "before CAWAKE->L, exiting "
					       "Interrupt tasklet.\n");
			return -EAGAIN;
		}
		if (unlikely(!pport->cawake_status)) {
			dev_warn(hsi_ctrl->dev,
				"Missed previous CAWAKE rising edge...\n");
			spin_unlock(&hsi_ctrl->lock);
			hsi_port_event_handler(pport, HSI_EVENT_CAWAKE_UP,
						NULL);
			spin_lock(&hsi_ctrl->lock);

			/* In case another CAWAKE interrupt occured and caused
			 * a race condition, clear CAWAKE backup interrupt to
			 * avoid handling twice the race condition */
			hsi_driver_ack_interrupt(pport, HSI_CAWAKEDETECTED,
						 true);
		}
		pport->cawake_status = 0;

		/* Forbid data reception */
		hsi_hsr_suspend(hsi_ctrl);

		spin_unlock(&hsi_ctrl->lock);
		hsi_port_event_handler(pport, HSI_EVENT_CAWAKE_DOWN, NULL);
		spin_lock(&hsi_ctrl->lock);
	}

	return 0;
}
Beispiel #7
0
static void do_hsi_gdd_lch(struct hsi_dev *hsi_ctrl, unsigned int gdd_lch)
{
	void __iomem *base = hsi_ctrl->base;
	struct platform_device *pdev = to_platform_device(hsi_ctrl->dev);
	struct hsi_channel *ch;
	unsigned int port;
	unsigned int channel;
	unsigned int is_read_path;
	u32 gdd_csr;
	dma_addr_t dma_h;
	size_t size;
	int fifo, fifo_words_avail;

	if (hsi_get_info_from_gdd_lch(hsi_ctrl, gdd_lch, &port, &channel,
				      &is_read_path) < 0) {
		dev_err(hsi_ctrl->dev, "Unable to match the DMA channel %d with"
			" an HSI channel\n", gdd_lch);
		return;
	} else {
		dev_dbg(hsi_ctrl->dev, "DMA event on gdd_lch=%d => port=%d, "
			"channel=%d, read=%d\n", gdd_lch, port, channel,
			is_read_path);
	}

	hsi_outl_and(~HSI_GDD_LCH(gdd_lch), base,
		     HSI_SYS_GDD_MPU_IRQ_ENABLE_REG);
	/* Warning : CSR register is cleared automaticaly by HW after SW read */
	gdd_csr = hsi_inw(base, HSI_GDD_CSR_REG(gdd_lch));

	if (!(gdd_csr & HSI_CSR_TOUT)) {
		if (is_read_path) {	/* Read path */
			dma_h = hsi_inl(base, HSI_GDD_CDSA_REG(gdd_lch));
			size = hsi_inw(base, HSI_GDD_CEN_REG(gdd_lch)) * 4;
			dma_sync_single_for_cpu(hsi_ctrl->dev, dma_h, size,
						DMA_FROM_DEVICE);
			dma_unmap_single(hsi_ctrl->dev, dma_h, size,
					 DMA_FROM_DEVICE);
			ch = hsi_ctrl_get_ch(hsi_ctrl, port, channel);
			hsi_reset_ch_read(ch);

			dev_dbg(hsi_ctrl->dev, "Calling ch %d read callback "
					"(size %d).\n", channel,  size/4);
			spin_unlock(&hsi_ctrl->lock);
			ch->read_done(ch->dev, size / 4);
			spin_lock(&hsi_ctrl->lock);

			/* Check if FIFO is correctly emptied */
			if (hsi_driver_device_is_hsi(pdev)) {
				fifo = hsi_fifo_get_id(hsi_ctrl, channel, port);
				if (unlikely(fifo < 0)) {
					dev_err(hsi_ctrl->dev, "No valid FIFO "
						"id found for channel %d.\n",
						channel);
					return;
				}
				fifo_words_avail =
					hsi_get_rx_fifo_occupancy(hsi_ctrl,
								fifo);
				if (fifo_words_avail)
					dev_dbg(hsi_ctrl->dev,
						"FIFO %d not empty "
						"after DMA copy, remaining "
						"%d/%d frames\n",
						fifo, fifo_words_avail,
						HSI_HSR_FIFO_SIZE);
			}
			/* Re-enable interrupts for polling if needed */
			if (ch->flags & HSI_CH_RX_POLL)
				hsi_driver_enable_read_interrupt(ch, NULL);
		} else {	/* Write path */
			dma_h = hsi_inl(base, HSI_GDD_CSSA_REG(gdd_lch));
			size = hsi_inw(base, HSI_GDD_CEN_REG(gdd_lch)) * 4;
			dma_unmap_single(hsi_ctrl->dev, dma_h, size,
					 DMA_TO_DEVICE);
			ch = hsi_ctrl_get_ch(hsi_ctrl, port, channel);
			hsi_reset_ch_write(ch);

			dev_dbg(hsi_ctrl->dev, "Calling ch %d write callback "
					"(size %d).\n", channel, size/4);
			spin_unlock(&hsi_ctrl->lock);
			ch->write_done(ch->dev, size / 4);
			spin_lock(&hsi_ctrl->lock);
		}
	} else {
		dev_err(hsi_ctrl->dev, "Time-out overflow Error on GDD transfer"
			" on gdd channel %d\n", gdd_lch);
		spin_unlock(&hsi_ctrl->lock);
		/* TODO : need to perform a DMA soft reset */
		hsi_port_event_handler(&hsi_ctrl->hsi_port[port - 1],
				       HSI_EVENT_ERROR, NULL);
		spin_lock(&hsi_ctrl->lock);
	}
}