Re: [PATCH v2 03/15] media: intel/ipu6: add IPU6 buttress interface driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Bingbu,

On Wed, Jan 03, 2024 at 09:33:26PM +0800, Bingbu Cao wrote:
> On 1/3/24 6:49 PM, Laurent Pinchart wrote:
> > On Wed, Jan 03, 2024 at 10:22:20AM +0100, Andreas Helbech Kleist wrote:
> >> On Tue, 2023-10-24 at 19:29 +0800, bingbu.cao@xxxxxxxxx wrote:
> >>> From: Bingbu Cao <bingbu.cao@xxxxxxxxx>
> >>>
> >>> The IPU6 buttress is the interface between IPU device (input system
> >>> and processing system) with rest of the SoC. It contains overall IPU
> >>> hardware control registers, these control registers are used as the
> >>> interfaces with the Intel Converged Security Engine and Punit to do
> >>> firmware authentication and power management.
> >>>
> >>> Signed-off-by: Bingbu Cao <bingbu.cao@xxxxxxxxx>
> >>> ---
> >>
> >> ...
> >>
> >>> +static irqreturn_t ipu6_buttress_call_isr(struct ipu6_bus_device *adev)
> >>> +{
> >>> +	irqreturn_t ret = IRQ_WAKE_THREAD;
> >>> +
> >>> +	if (!adev || !adev->auxdrv || !adev->auxdrv_data)
> >>> +		return IRQ_NONE;
> >>> +
> >>> +	if (adev->auxdrv_data->isr)
> >>> +		ret = adev->auxdrv_data->isr(adev);
> >>> +
> >>> +	if (ret == IRQ_WAKE_THREAD && !adev->auxdrv_data->isr_threaded)
> >>> +		ret = IRQ_NONE;
> >>> +
> >>> +	return ret;
> >>> +}
> >>> +
> >>> +irqreturn_t ipu6_buttress_isr(int irq, void *isp_ptr)
> >>> +{
> >>> +	struct ipu6_device *isp = isp_ptr;
> >>> +	struct ipu6_bus_device *adev[] = { isp->isys, isp->psys };
> >>> +	struct ipu6_buttress *b = &isp->buttress;
> >>> +	u32 reg_irq_sts = BUTTRESS_REG_ISR_STATUS;
> >>> +	irqreturn_t ret = IRQ_NONE;
> >>> +	u32 disable_irqs = 0;
> >>> +	u32 irq_status;
> >>> +	u32 i, count = 0;
> >>> +
> >>> +	pm_runtime_get_noresume(&isp->pdev->dev);
> >>> +
> >>> +	irq_status = readl(isp->base + reg_irq_sts);
> > 
> > A drive-by comment: this seems dodgy. If someone calls pm_runtime_put*()
> > just before the pm_runtime_get_noresume() above, the device won't be
> > resumed when reading the register, which will likely not lead to the
> > desired result.
> 
> Thanks for your review. 
> What do you think using pm_runtime_get_if_in_use() here?

This is the second discussion in a few weeks about this topic. See
https://lore.kernel.org/linux-media/60b3aec2-294f-4ab0-8a4b-0c32a52c84a0@xxxxxxxxxxxxxxxx

Sakari, should we try to handle this issue with shared helpers ?

> >>> +	if (!irq_status) {
> >>> +		pm_runtime_put_noidle(&isp->pdev->dev);
> >>> +		return IRQ_NONE;
> >>> +	}
> >>> +
> >>> +	do {
> >>> +		writel(irq_status, isp->base + BUTTRESS_REG_ISR_CLEAR);
> >>> +
> >>> +		for (i = 0; i < ARRAY_SIZE(ipu6_adev_irq_mask); i++) {
> >>> +			irqreturn_t r = ipu6_buttress_call_isr(adev[i]);
> >>> +
> >>> +			if (!(irq_status & ipu6_adev_irq_mask[i]))
> >>> +				continue;
> >>> +
> >>> +			if (r == IRQ_WAKE_THREAD) {
> >>> +				ret = IRQ_WAKE_THREAD;
> >>> +				disable_irqs |= ipu6_adev_irq_mask[i];
> >>> +			} else if (ret == IRQ_NONE && r == IRQ_HANDLED) {
> >>> +				ret = IRQ_HANDLED;
> >>> +			}
> >>> +		}
> >>
> >> It seems wrong to call the ISR for a adev[i] before checking the
> >> corresponding IRQ mask. If the mask is not set, the ISR is still
> >> called, but the result is thrown away.
> >>
> >> I started investigating this because I'm seeing "general protection
> >> fault, probably for non-canonical address 0x6b6b6b6b6b6b6b6b" in this
> >> function when unbinding the IPU4 driver.
> >>
> >> How do you ensure that the ISR is not called on a ipu6-bus device that
> >> has been deleted? Specifically in ipu6_pci_remove, ipu6_bus_del_devices
> >> is called before ipu6_buttress_exit (which disables buttress IRQs).
> >> Perhaps the above for loop should really be a "for each ipu6-bus
> >> device" loop?
> >>
> >>> +
> >>> +		if ((irq_status & BUTTRESS_EVENT) && ret == IRQ_NONE)
> >>> +			ret = IRQ_HANDLED;
> >>> +
> >>> +		if (irq_status & BUTTRESS_ISR_IPC_FROM_CSE_IS_WAITING) {
> >>> +			dev_dbg(&isp->pdev->dev,
> >>> +				"BUTTRESS_ISR_IPC_FROM_CSE_IS_WAITING\n");
> >>> +			ipu6_buttress_ipc_recv(isp, &b->cse, &b->cse.recv_data);
> >>> +			complete(&b->cse.recv_complete);
> >>> +		}
> >>> +
> >>> +		if (irq_status & BUTTRESS_ISR_IPC_FROM_ISH_IS_WAITING) {
> >>> +			dev_dbg(&isp->pdev->dev,
> >>> +				"BUTTRESS_ISR_IPC_FROM_ISH_IS_WAITING\n");
> >>> +			ipu6_buttress_ipc_recv(isp, &b->ish, &b->ish.recv_data);
> >>> +			complete(&b->ish.recv_complete);
> >>> +		}
> >>> +
> >>> +		if (irq_status & BUTTRESS_ISR_IPC_EXEC_DONE_BY_CSE) {
> >>> +			dev_dbg(&isp->pdev->dev,
> >>> +				"BUTTRESS_ISR_IPC_EXEC_DONE_BY_CSE\n");
> >>> +			complete(&b->cse.send_complete);
> >>> +		}
> >>> +
> >>> +		if (irq_status & BUTTRESS_ISR_IPC_EXEC_DONE_BY_ISH) {
> >>> +			dev_dbg(&isp->pdev->dev,
> >>> +				"BUTTRESS_ISR_IPC_EXEC_DONE_BY_CSE\n");
> >>> +			complete(&b->ish.send_complete);
> >>> +		}
> >>> +
> >>> +		if (irq_status & BUTTRESS_ISR_SAI_VIOLATION &&
> >>> +		    ipu6_buttress_get_secure_mode(isp))
> >>> +			dev_err(&isp->pdev->dev,
> >>> +				"BUTTRESS_ISR_SAI_VIOLATION\n");
> >>> +
> >>> +		if (irq_status & (BUTTRESS_ISR_IS_FATAL_MEM_ERR |
> >>> +				  BUTTRESS_ISR_PS_FATAL_MEM_ERR))
> >>> +			dev_err(&isp->pdev->dev,
> >>> +				"BUTTRESS_ISR_FATAL_MEM_ERR\n");
> >>> +
> >>> +		if (irq_status & BUTTRESS_ISR_UFI_ERROR)
> >>> +			dev_err(&isp->pdev->dev, "BUTTRESS_ISR_UFI_ERROR\n");
> >>> +
> >>> +		if (++count == BUTTRESS_MAX_CONSECUTIVE_IRQS) {
> >>> +			dev_err(&isp->pdev->dev, "too many consecutive IRQs\n");
> >>> +			ret = IRQ_NONE;
> >>> +			break;
> >>> +		}
> >>> +
> >>> +		irq_status = readl(isp->base + reg_irq_sts);
> >>> +	} while (irq_status);
> >>> +
> >>> +	if (disable_irqs)
> >>> +		writel(BUTTRESS_IRQS & ~disable_irqs,
> >>> +		       isp->base + BUTTRESS_REG_ISR_ENABLE);
> >>> +
> >>> +	pm_runtime_put(&isp->pdev->dev);
> >>> +
> >>> +	return ret;
> >>> +}
> >>
> >> ...

-- 
Regards,

Laurent Pinchart




[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]

  Powered by Linux