mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-28 11:18:45 +07:00
f3a3e881b8
cx18: Disable write retries for registers that always change - part 1. Interrupt related registers will likely not read back the value we just wrote. Disable retries for these registers for now to avoid accidently discarding interrupts. More intelligent read back verification criteria are needed for these and other registers (e.g. GPIO line registers), which will be addressed in subsequent changes. Signed-off-by: Andy Walls <awalls@radix.net> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
183 lines
5.0 KiB
C
183 lines
5.0 KiB
C
/*
|
|
* cx18 interrupt handling
|
|
*
|
|
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
|
* 02111-1307 USA
|
|
*/
|
|
|
|
#include "cx18-driver.h"
|
|
#include "cx18-io.h"
|
|
#include "cx18-firmware.h"
|
|
#include "cx18-fileops.h"
|
|
#include "cx18-queue.h"
|
|
#include "cx18-irq.h"
|
|
#include "cx18-ioctl.h"
|
|
#include "cx18-mailbox.h"
|
|
#include "cx18-vbi.h"
|
|
#include "cx18-scb.h"
|
|
|
|
#define DMA_MAGIC_COOKIE 0x000001fe
|
|
|
|
static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb)
|
|
{
|
|
u32 handle = mb->args[0];
|
|
struct cx18_stream *s = NULL;
|
|
struct cx18_buffer *buf;
|
|
u32 off;
|
|
int i;
|
|
int id;
|
|
|
|
for (i = 0; i < CX18_MAX_STREAMS; i++) {
|
|
s = &cx->streams[i];
|
|
if ((handle == s->handle) && (s->dvb.enabled))
|
|
break;
|
|
if (s->v4l2dev && handle == s->handle)
|
|
break;
|
|
}
|
|
if (i == CX18_MAX_STREAMS) {
|
|
CX18_WARN("Got DMA done notification for unknown/inactive"
|
|
" handle %d\n", handle);
|
|
mb->error = CXERR_NOT_OPEN;
|
|
mb->cmd = 0;
|
|
cx18_mb_ack(cx, mb);
|
|
return;
|
|
}
|
|
|
|
off = mb->args[1];
|
|
if (mb->args[2] != 1)
|
|
CX18_WARN("Ack struct = %d for %s\n",
|
|
mb->args[2], s->name);
|
|
id = cx18_read_enc(cx, off);
|
|
buf = cx18_queue_get_buf_irq(s, id, cx18_read_enc(cx, off + 4));
|
|
CX18_DEBUG_HI_DMA("DMA DONE for %s (buffer %d)\n", s->name, id);
|
|
if (buf) {
|
|
cx18_buf_sync_for_cpu(s, buf);
|
|
if (s->type == CX18_ENC_STREAM_TYPE_TS && s->dvb.enabled) {
|
|
/* process the buffer here */
|
|
CX18_DEBUG_HI_DMA("TS recv and sent bytesused=%d\n",
|
|
buf->bytesused);
|
|
|
|
dvb_dmx_swfilter(&s->dvb.demux, buf->buf,
|
|
buf->bytesused);
|
|
|
|
cx18_buf_sync_for_device(s, buf);
|
|
cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle,
|
|
(void __iomem *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem,
|
|
1, buf->id, s->buf_size);
|
|
} else
|
|
set_bit(CX18_F_B_NEED_BUF_SWAP, &buf->b_flags);
|
|
} else {
|
|
CX18_WARN("Could not find buf %d for stream %s\n",
|
|
cx18_read_enc(cx, off), s->name);
|
|
}
|
|
mb->error = 0;
|
|
mb->cmd = 0;
|
|
cx18_mb_ack(cx, mb);
|
|
wake_up(&cx->dma_waitq);
|
|
if (s->id != -1)
|
|
wake_up(&s->waitq);
|
|
}
|
|
|
|
static void epu_debug(struct cx18 *cx, struct cx18_mailbox *mb)
|
|
{
|
|
char str[256] = { 0 };
|
|
char *p;
|
|
|
|
if (mb->args[1]) {
|
|
cx18_setup_page(cx, mb->args[1]);
|
|
cx18_memcpy_fromio(cx, str, cx->enc_mem + mb->args[1], 252);
|
|
str[252] = 0;
|
|
}
|
|
cx18_mb_ack(cx, mb);
|
|
CX18_DEBUG_INFO("%x %s\n", mb->args[0], str);
|
|
p = strchr(str, '.');
|
|
if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags) && p && p > str)
|
|
CX18_INFO("FW version: %s\n", p - 1);
|
|
}
|
|
|
|
static void hpu_cmd(struct cx18 *cx, u32 sw1)
|
|
{
|
|
struct cx18_mailbox mb;
|
|
|
|
if (sw1 & IRQ_CPU_TO_EPU) {
|
|
cx18_memcpy_fromio(cx, &mb, &cx->scb->cpu2epu_mb, sizeof(mb));
|
|
mb.error = 0;
|
|
|
|
switch (mb.cmd) {
|
|
case CX18_EPU_DMA_DONE:
|
|
epu_dma_done(cx, &mb);
|
|
break;
|
|
case CX18_EPU_DEBUG:
|
|
epu_debug(cx, &mb);
|
|
break;
|
|
default:
|
|
CX18_WARN("Unexpected mailbox command %08x\n", mb.cmd);
|
|
break;
|
|
}
|
|
}
|
|
if (sw1 & (IRQ_APU_TO_EPU | IRQ_HPU_TO_EPU))
|
|
CX18_WARN("Unexpected interrupt %08x\n", sw1);
|
|
}
|
|
|
|
irqreturn_t cx18_irq_handler(int irq, void *dev_id)
|
|
{
|
|
struct cx18 *cx = (struct cx18 *)dev_id;
|
|
u32 sw1, sw1_mask;
|
|
u32 sw2, sw2_mask;
|
|
u32 hw2, hw2_mask;
|
|
|
|
spin_lock(&cx->dma_reg_lock);
|
|
|
|
hw2_mask = cx18_read_reg(cx, HW2_INT_MASK5_PCI);
|
|
hw2 = cx18_read_reg(cx, HW2_INT_CLR_STATUS) & hw2_mask;
|
|
sw2_mask = cx18_read_reg(cx, SW2_INT_ENABLE_PCI) | IRQ_EPU_TO_HPU_ACK;
|
|
sw2 = cx18_read_reg(cx, SW2_INT_STATUS) & sw2_mask;
|
|
sw1_mask = cx18_read_reg(cx, SW1_INT_ENABLE_PCI) | IRQ_EPU_TO_HPU;
|
|
sw1 = cx18_read_reg(cx, SW1_INT_STATUS) & sw1_mask;
|
|
|
|
cx18_write_reg_noretry(cx, sw2&sw2_mask, SW2_INT_STATUS);
|
|
cx18_write_reg_noretry(cx, sw1&sw1_mask, SW1_INT_STATUS);
|
|
cx18_write_reg_noretry(cx, hw2&hw2_mask, HW2_INT_CLR_STATUS);
|
|
|
|
if (sw1 || sw2 || hw2)
|
|
CX18_DEBUG_HI_IRQ("SW1: %x SW2: %x HW2: %x\n", sw1, sw2, hw2);
|
|
|
|
/* To do: interrupt-based I2C handling
|
|
if (hw2 & 0x00c00000) {
|
|
}
|
|
*/
|
|
|
|
if (sw2) {
|
|
if (sw2 & (cx18_readl(cx, &cx->scb->cpu2hpu_irq_ack) |
|
|
cx18_readl(cx, &cx->scb->cpu2epu_irq_ack)))
|
|
wake_up(&cx->mb_cpu_waitq);
|
|
if (sw2 & (cx18_readl(cx, &cx->scb->apu2hpu_irq_ack) |
|
|
cx18_readl(cx, &cx->scb->apu2epu_irq_ack)))
|
|
wake_up(&cx->mb_apu_waitq);
|
|
if (sw2 & cx18_readl(cx, &cx->scb->epu2hpu_irq_ack))
|
|
wake_up(&cx->mb_epu_waitq);
|
|
if (sw2 & cx18_readl(cx, &cx->scb->hpu2epu_irq_ack))
|
|
wake_up(&cx->mb_hpu_waitq);
|
|
}
|
|
|
|
if (sw1)
|
|
hpu_cmd(cx, sw1);
|
|
spin_unlock(&cx->dma_reg_lock);
|
|
|
|
return (hw2 | sw1 | sw2) ? IRQ_HANDLED : IRQ_NONE;
|
|
}
|