linux/drivers/media/pci/cx23885/cx23885-core.c

2254 lines
61 KiB
C
Raw Normal View History

treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 157 Based on 3 normalized pattern(s): 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 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 [author] [kishon] [vijay] [abraham] [i] [kishon]@[ti] [com] 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 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 [author] [graeme] [gregory] [gg]@[slimlogic] [co] [uk] [author] [kishon] [vijay] [abraham] [i] [kishon]@[ti] [com] [based] [on] [twl6030]_[usb] [c] [author] [hema] [hk] [hemahk]@[ti] [com] 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 extracted by the scancode license scanner the SPDX license identifier GPL-2.0-or-later has been chosen to replace the boilerplate/reference in 1105 file(s). Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Allison Randal <allison@lohutok.net> Reviewed-by: Richard Fontana <rfontana@redhat.com> Reviewed-by: Kate Stewart <kstewart@linuxfoundation.org> Cc: linux-spdx@vger.kernel.org Link: https://lkml.kernel.org/r/20190527070033.202006027@linutronix.de Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2019-05-27 14:55:06 +08:00
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Driver for the Conexant CX23885 PCIe bridge
*
* Copyright (c) 2006 Steven Toth <stoth@linuxtv.org>
*/
#include "cx23885.h"
#include <linux/init.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kmod.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <asm/div64.h>
#include <linux/firmware.h>
#include "cimax2.h"
#include "altera-ci.h"
#include "cx23888-ir.h"
#include "cx23885-ir.h"
#include "cx23885-av.h"
#include "cx23885-input.h"
MODULE_DESCRIPTION("Driver for cx23885 based TV cards");
MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
MODULE_LICENSE("GPL");
MODULE_VERSION(CX23885_VERSION);
/*
* Some platforms have been found to require periodic resetting of the DMA
* engine. Ryzen and XEON platforms are known to be affected. The symptom
* encountered is "mpeg risc op code error". Only Ryzen platforms employ
* this workaround if the option equals 1. The workaround can be explicitly
* disabled for all platforms by setting to 0, the workaround can be forced
* on for any platform by setting to 2.
*/
static unsigned int dma_reset_workaround = 1;
module_param(dma_reset_workaround, int, 0644);
MODULE_PARM_DESC(dma_reset_workaround, "periodic RiSC dma engine reset; 0-force disable, 1-driver detect (default), 2-force enable");
static unsigned int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "enable debug messages");
static unsigned int card[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET };
module_param_array(card, int, NULL, 0444);
MODULE_PARM_DESC(card, "card type");
#define dprintk(level, fmt, arg...)\
do { if (debug >= level)\
printk(KERN_DEBUG pr_fmt("%s: " fmt), \
__func__, ##arg); \
} while (0)
static unsigned int cx23885_devcount;
#define NO_SYNC_LINE (-1U)
/* FIXME, these allocations will change when
* analog arrives. The be reviewed.
* CX23887 Assumptions
* 1 line = 16 bytes of CDT
* cmds size = 80
* cdt size = 16 * linesize
* iqsize = 64
* maxlines = 6
*
* Address Space:
* 0x00000000 0x00008fff FIFO clusters
* 0x00010000 0x000104af Channel Management Data Structures
* 0x000104b0 0x000104ff Free
* 0x00010500 0x000108bf 15 channels * iqsize
* 0x000108c0 0x000108ff Free
* 0x00010900 0x00010e9f IQ's + Cluster Descriptor Tables
* 15 channels * (iqsize + (maxlines * linesize))
* 0x00010ea0 0x00010xxx Free
*/
static struct sram_channel cx23885_sram_channels[] = {
[SRAM_CH01] = {
.name = "VID A",
.cmds_start = 0x10000,
.ctrl_start = 0x10380,
.cdt = 0x104c0,
.fifo_start = 0x40,
.fifo_size = 0x2800,
.ptr1_reg = DMA1_PTR1,
.ptr2_reg = DMA1_PTR2,
.cnt1_reg = DMA1_CNT1,
.cnt2_reg = DMA1_CNT2,
},
[SRAM_CH02] = {
.name = "ch2",
.cmds_start = 0x0,
.ctrl_start = 0x0,
.cdt = 0x0,
.fifo_start = 0x0,
.fifo_size = 0x0,
.ptr1_reg = DMA2_PTR1,
.ptr2_reg = DMA2_PTR2,
.cnt1_reg = DMA2_CNT1,
.cnt2_reg = DMA2_CNT2,
},
[SRAM_CH03] = {
.name = "TS1 B",
.cmds_start = 0x100A0,
.ctrl_start = 0x10400,
.cdt = 0x10580,
.fifo_start = 0x5000,
.fifo_size = 0x1000,
.ptr1_reg = DMA3_PTR1,
.ptr2_reg = DMA3_PTR2,
.cnt1_reg = DMA3_CNT1,
.cnt2_reg = DMA3_CNT2,
},
[SRAM_CH04] = {
.name = "ch4",
.cmds_start = 0x0,
.ctrl_start = 0x0,
.cdt = 0x0,
.fifo_start = 0x0,
.fifo_size = 0x0,
.ptr1_reg = DMA4_PTR1,
.ptr2_reg = DMA4_PTR2,
.cnt1_reg = DMA4_CNT1,
.cnt2_reg = DMA4_CNT2,
},
[SRAM_CH05] = {
.name = "ch5",
.cmds_start = 0x0,
.ctrl_start = 0x0,
.cdt = 0x0,
.fifo_start = 0x0,
.fifo_size = 0x0,
.ptr1_reg = DMA5_PTR1,
.ptr2_reg = DMA5_PTR2,
.cnt1_reg = DMA5_CNT1,
.cnt2_reg = DMA5_CNT2,
},
[SRAM_CH06] = {
.name = "TS2 C",
.cmds_start = 0x10140,
.ctrl_start = 0x10440,
.cdt = 0x105e0,
.fifo_start = 0x6000,
.fifo_size = 0x1000,
.ptr1_reg = DMA5_PTR1,
.ptr2_reg = DMA5_PTR2,
.cnt1_reg = DMA5_CNT1,
.cnt2_reg = DMA5_CNT2,
},
[SRAM_CH07] = {
.name = "TV Audio",
.cmds_start = 0x10190,
.ctrl_start = 0x10480,
.cdt = 0x10a00,
.fifo_start = 0x7000,
.fifo_size = 0x1000,
.ptr1_reg = DMA6_PTR1,
.ptr2_reg = DMA6_PTR2,
.cnt1_reg = DMA6_CNT1,
.cnt2_reg = DMA6_CNT2,
},
[SRAM_CH08] = {
.name = "ch8",
.cmds_start = 0x0,
.ctrl_start = 0x0,
.cdt = 0x0,
.fifo_start = 0x0,
.fifo_size = 0x0,
.ptr1_reg = DMA7_PTR1,
.ptr2_reg = DMA7_PTR2,
.cnt1_reg = DMA7_CNT1,
.cnt2_reg = DMA7_CNT2,
},
[SRAM_CH09] = {
.name = "ch9",
.cmds_start = 0x0,
.ctrl_start = 0x0,
.cdt = 0x0,
.fifo_start = 0x0,
.fifo_size = 0x0,
.ptr1_reg = DMA8_PTR1,
.ptr2_reg = DMA8_PTR2,
.cnt1_reg = DMA8_CNT1,
.cnt2_reg = DMA8_CNT2,
},
};
static struct sram_channel cx23887_sram_channels[] = {
[SRAM_CH01] = {
.name = "VID A",
.cmds_start = 0x10000,
.ctrl_start = 0x105b0,
.cdt = 0x107b0,
.fifo_start = 0x40,
.fifo_size = 0x2800,
.ptr1_reg = DMA1_PTR1,
.ptr2_reg = DMA1_PTR2,
.cnt1_reg = DMA1_CNT1,
.cnt2_reg = DMA1_CNT2,
},
[SRAM_CH02] = {
.name = "VID A (VBI)",
.cmds_start = 0x10050,
.ctrl_start = 0x105F0,
.cdt = 0x10810,
.fifo_start = 0x3000,
.fifo_size = 0x1000,
.ptr1_reg = DMA2_PTR1,
.ptr2_reg = DMA2_PTR2,
.cnt1_reg = DMA2_CNT1,
.cnt2_reg = DMA2_CNT2,
},
[SRAM_CH03] = {
.name = "TS1 B",
.cmds_start = 0x100A0,
.ctrl_start = 0x10630,
.cdt = 0x10870,
.fifo_start = 0x5000,
.fifo_size = 0x1000,
.ptr1_reg = DMA3_PTR1,
.ptr2_reg = DMA3_PTR2,
.cnt1_reg = DMA3_CNT1,
.cnt2_reg = DMA3_CNT2,
},
[SRAM_CH04] = {
.name = "ch4",
.cmds_start = 0x0,
.ctrl_start = 0x0,
.cdt = 0x0,
.fifo_start = 0x0,
.fifo_size = 0x0,
.ptr1_reg = DMA4_PTR1,
.ptr2_reg = DMA4_PTR2,
.cnt1_reg = DMA4_CNT1,
.cnt2_reg = DMA4_CNT2,
},
[SRAM_CH05] = {
.name = "ch5",
.cmds_start = 0x0,
.ctrl_start = 0x0,
.cdt = 0x0,
.fifo_start = 0x0,
.fifo_size = 0x0,
.ptr1_reg = DMA5_PTR1,
.ptr2_reg = DMA5_PTR2,
.cnt1_reg = DMA5_CNT1,
.cnt2_reg = DMA5_CNT2,
},
[SRAM_CH06] = {
.name = "TS2 C",
.cmds_start = 0x10140,
.ctrl_start = 0x10670,
.cdt = 0x108d0,
.fifo_start = 0x6000,
.fifo_size = 0x1000,
.ptr1_reg = DMA5_PTR1,
.ptr2_reg = DMA5_PTR2,
.cnt1_reg = DMA5_CNT1,
.cnt2_reg = DMA5_CNT2,
},
[SRAM_CH07] = {
.name = "TV Audio",
.cmds_start = 0x10190,
.ctrl_start = 0x106B0,
.cdt = 0x10930,
.fifo_start = 0x7000,
.fifo_size = 0x1000,
.ptr1_reg = DMA6_PTR1,
.ptr2_reg = DMA6_PTR2,
.cnt1_reg = DMA6_CNT1,
.cnt2_reg = DMA6_CNT2,
},
[SRAM_CH08] = {
.name = "ch8",
.cmds_start = 0x0,
.ctrl_start = 0x0,
.cdt = 0x0,
.fifo_start = 0x0,
.fifo_size = 0x0,
.ptr1_reg = DMA7_PTR1,
.ptr2_reg = DMA7_PTR2,
.cnt1_reg = DMA7_CNT1,
.cnt2_reg = DMA7_CNT2,
},
[SRAM_CH09] = {
.name = "ch9",
.cmds_start = 0x0,
.ctrl_start = 0x0,
.cdt = 0x0,
.fifo_start = 0x0,
.fifo_size = 0x0,
.ptr1_reg = DMA8_PTR1,
.ptr2_reg = DMA8_PTR2,
.cnt1_reg = DMA8_CNT1,
.cnt2_reg = DMA8_CNT2,
},
};
[media] cx23885: get rid of warning: no previous prototype drivers/media/pci/cx23885/altera-ci.c:266:5: warning: no previous prototype for 'altera_ci_op_cam' [-Wmissing-prototypes] drivers/media/pci/cx23885/altera-ci.c:301:5: warning: no previous prototype for 'altera_ci_read_attribute_mem' [-Wmissing-prototypes] drivers/media/pci/cx23885/altera-ci.c:307:5: warning: no previous prototype for 'altera_ci_write_attribute_mem' [-Wmissing-prototypes] drivers/media/pci/cx23885/altera-ci.c:313:5: warning: no previous prototype for 'altera_ci_read_cam_ctl' [-Wmissing-prototypes] drivers/media/pci/cx23885/altera-ci.c:319:5: warning: no previous prototype for 'altera_ci_write_cam_ctl' [-Wmissing-prototypes] drivers/media/pci/cx23885/altera-ci.c:325:5: warning: no previous prototype for 'altera_ci_slot_reset' [-Wmissing-prototypes] drivers/media/pci/cx23885/altera-ci.c:368:5: warning: no previous prototype for 'altera_ci_slot_shutdown' [-Wmissing-prototypes] drivers/media/pci/cx23885/altera-ci.c:374:5: warning: no previous prototype for 'altera_ci_slot_ts_ctl' [-Wmissing-prototypes] drivers/media/pci/cx23885/altera-ci.c:451:5: warning: no previous prototype for 'altera_poll_ci_slot_status' [-Wmissing-prototypes] drivers/media/pci/cx23885/altera-ci.c:462:6: warning: no previous prototype for 'altera_hw_filt_release' [-Wmissing-prototypes] drivers/media/pci/cx23885/altera-ci.c:584:5: warning: no previous prototype for 'altera_pid_feed_control' [-Wmissing-prototypes] drivers/media/pci/cx23885/altera-ci.c:606:5: warning: no previous prototype for 'altera_ci_start_feed' [-Wmissing-prototypes] drivers/media/pci/cx23885/altera-ci.c:613:5: warning: no previous prototype for 'altera_ci_stop_feed' [-Wmissing-prototypes] drivers/media/pci/cx23885/altera-ci.c:620:5: warning: no previous prototype for 'altera_ci_start_feed_1' [-Wmissing-prototypes] drivers/media/pci/cx23885/altera-ci.c:625:5: warning: no previous prototype for 'altera_ci_stop_feed_1' [-Wmissing-prototypes] drivers/media/pci/cx23885/altera-ci.c:630:5: warning: no previous prototype for 'altera_ci_start_feed_2' [-Wmissing-prototypes] drivers/media/pci/cx23885/altera-ci.c:635:5: warning: no previous prototype for 'altera_ci_stop_feed_2' [-Wmissing-prototypes] drivers/media/pci/cx23885/altera-ci.c:640:5: warning: no previous prototype for 'altera_hw_filt_init' [-Wmissing-prototypes] drivers/media/pci/cx23885/cimax2.c:123:5: warning: no previous prototype for 'netup_write_i2c' [-Wmissing-prototypes] drivers/media/pci/cx23885/cimax2.c:150:5: warning: no previous prototype for 'netup_ci_get_mem' [-Wmissing-prototypes] drivers/media/pci/cx23885/cimax2.c:169:5: warning: no previous prototype for 'netup_ci_op_cam' [-Wmissing-prototypes] drivers/media/pci/cx23885/cimax2.c:239:5: warning: no previous prototype for 'netup_ci_read_attribute_mem' [-Wmissing-prototypes] drivers/media/pci/cx23885/cimax2.c:245:5: warning: no previous prototype for 'netup_ci_write_attribute_mem' [-Wmissing-prototypes] drivers/media/pci/cx23885/cimax2.c:251:5: warning: no previous prototype for 'netup_ci_read_cam_ctl' [-Wmissing-prototypes] drivers/media/pci/cx23885/cimax2.c:257:5: warning: no previous prototype for 'netup_ci_write_cam_ctl' [-Wmissing-prototypes] drivers/media/pci/cx23885/cimax2.c:263:5: warning: no previous prototype for 'netup_ci_slot_reset' [-Wmissing-prototypes] drivers/media/pci/cx23885/cimax2.c:292:5: warning: no previous prototype for 'netup_ci_slot_shutdown' [-Wmissing-prototypes] drivers/media/pci/cx23885/cimax2.c:298:5: warning: no previous prototype for 'netup_ci_set_irq' [-Wmissing-prototypes] drivers/media/pci/cx23885/cimax2.c:319:5: warning: no previous prototype for 'netup_ci_slot_ts_ctl' [-Wmissing-prototypes] drivers/media/pci/cx23885/cimax2.c:375:5: warning: no previous prototype for 'netup_ci_slot_status' [-Wmissing-prototypes] drivers/media/pci/cx23885/cimax2.c:402:5: warning: no previous prototype for 'netup_poll_ci_slot_status' [-Wmissing-prototypes] drivers/media/pci/cx23885/cimax2.c:415:5: warning: no previous prototype for 'netup_ci_init' [-Wmissing-prototypes] drivers/media/pci/cx23885/cimax2.c:520:6: warning: no previous prototype for 'netup_ci_exit' [-Wmissing-prototypes] drivers/media/pci/cx23885/cimax2.c:90:5: warning: no previous prototype for 'netup_read_i2c' [-Wmissing-prototypes] drivers/media/pci/cx23885/cx23885-av.c:26:6: warning: no previous prototype for 'cx23885_av_work_handler' [-Wmissing-prototypes] drivers/media/pci/cx23885/cx23885-cards.c:1430:5: warning: no previous prototype for 'netup_jtag_io' [-Wmissing-prototypes] drivers/media/pci/cx23885/cx23885-core.c:306:6: warning: no previous prototype for 'cx23885_irq_add' [-Wmissing-prototypes] drivers/media/pci/cx23885/cx23885-dvb.c:662:5: warning: no previous prototype for 'netup_altera_fpga_rw' [-Wmissing-prototypes] drivers/media/pci/cx23885/cx23885-f300.c:150:5: warning: no previous prototype for 'f300_set_voltage' [-Wmissing-prototypes] drivers/media/pci/cx23885/cx23885-input.c:249:5: warning: no previous prototype for 'cx23885_input_init' [-Wmissing-prototypes] drivers/media/pci/cx23885/cx23885-input.c:353:6: warning: no previous prototype for 'cx23885_input_fini' [-Wmissing-prototypes] drivers/media/pci/cx23885/cx23885-input.c:76:6: warning: no previous prototype for 'cx23885_input_rx_work_handler' [-Wmissing-prototypes] drivers/media/pci/cx23885/cx23885-ioctl.c:134:5: warning: no previous prototype for 'cx23885_g_register' [-Wmissing-prototypes] drivers/media/pci/cx23885/cx23885-ioctl.c:185:5: warning: no previous prototype for 'cx23885_s_register' [-Wmissing-prototypes] drivers/media/pci/cx23885/cx23885-ioctl.c:27:5: warning: no previous prototype for 'cx23885_g_chip_ident' [-Wmissing-prototypes] drivers/media/pci/cx23885/cx23885-ir.c:101:6: warning: no previous prototype for 'cx23885_ir_tx_v4l2_dev_notify' [-Wmissing-prototypes] drivers/media/pci/cx23885/cx23885-ir.c:37:6: warning: no previous prototype for 'cx23885_ir_rx_work_handler' [-Wmissing-prototypes] drivers/media/pci/cx23885/cx23885-ir.c:60:6: warning: no previous prototype for 'cx23885_ir_tx_work_handler' [-Wmissing-prototypes] drivers/media/pci/cx23885/cx23885-ir.c:76:6: warning: no previous prototype for 'cx23885_ir_rx_v4l2_dev_notify' [-Wmissing-prototypes] drivers/media/pci/cx23885/cx23888-ir.c:1203:5: warning: no previous prototype for 'cx23888_ir_probe' [-Wmissing-prototypes] drivers/media/pci/cx23885/cx23888-ir.c:1253:5: warning: no previous prototype for 'cx23888_ir_remove' [-Wmissing-prototypes] drivers/media/pci/cx23885/netup-init.c:109:6: warning: no previous prototype for 'netup_initialize' [-Wmissing-prototypes] Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
2012-10-27 22:29:23 +08:00
static void cx23885_irq_add(struct cx23885_dev *dev, u32 mask)
{
unsigned long flags;
spin_lock_irqsave(&dev->pci_irqmask_lock, flags);
dev->pci_irqmask |= mask;
spin_unlock_irqrestore(&dev->pci_irqmask_lock, flags);
}
void cx23885_irq_add_enable(struct cx23885_dev *dev, u32 mask)
{
unsigned long flags;
spin_lock_irqsave(&dev->pci_irqmask_lock, flags);
dev->pci_irqmask |= mask;
cx_set(PCI_INT_MSK, mask);
spin_unlock_irqrestore(&dev->pci_irqmask_lock, flags);
}
void cx23885_irq_enable(struct cx23885_dev *dev, u32 mask)
{
u32 v;
unsigned long flags;
spin_lock_irqsave(&dev->pci_irqmask_lock, flags);
v = mask & dev->pci_irqmask;
if (v)
cx_set(PCI_INT_MSK, v);
spin_unlock_irqrestore(&dev->pci_irqmask_lock, flags);
}
static inline void cx23885_irq_enable_all(struct cx23885_dev *dev)
{
cx23885_irq_enable(dev, 0xffffffff);
}
void cx23885_irq_disable(struct cx23885_dev *dev, u32 mask)
{
unsigned long flags;
spin_lock_irqsave(&dev->pci_irqmask_lock, flags);
cx_clear(PCI_INT_MSK, mask);
spin_unlock_irqrestore(&dev->pci_irqmask_lock, flags);
}
static inline void cx23885_irq_disable_all(struct cx23885_dev *dev)
{
cx23885_irq_disable(dev, 0xffffffff);
}
void cx23885_irq_remove(struct cx23885_dev *dev, u32 mask)
{
unsigned long flags;
spin_lock_irqsave(&dev->pci_irqmask_lock, flags);
dev->pci_irqmask &= ~mask;
cx_clear(PCI_INT_MSK, mask);
spin_unlock_irqrestore(&dev->pci_irqmask_lock, flags);
}
static u32 cx23885_irq_get_mask(struct cx23885_dev *dev)
{
u32 v;
unsigned long flags;
spin_lock_irqsave(&dev->pci_irqmask_lock, flags);
v = cx_read(PCI_INT_MSK);
spin_unlock_irqrestore(&dev->pci_irqmask_lock, flags);
return v;
}
static int cx23885_risc_decode(u32 risc)
{
static char *instr[16] = {
[RISC_SYNC >> 28] = "sync",
[RISC_WRITE >> 28] = "write",
[RISC_WRITEC >> 28] = "writec",
[RISC_READ >> 28] = "read",
[RISC_READC >> 28] = "readc",
[RISC_JUMP >> 28] = "jump",
[RISC_SKIP >> 28] = "skip",
[RISC_WRITERM >> 28] = "writerm",
[RISC_WRITECM >> 28] = "writecm",
[RISC_WRITECR >> 28] = "writecr",
};
static int incr[16] = {
[RISC_WRITE >> 28] = 3,
[RISC_JUMP >> 28] = 3,
[RISC_SKIP >> 28] = 1,
[RISC_SYNC >> 28] = 1,
[RISC_WRITERM >> 28] = 3,
[RISC_WRITECM >> 28] = 3,
[RISC_WRITECR >> 28] = 4,
};
static char *bits[] = {
"12", "13", "14", "resync",
"cnt0", "cnt1", "18", "19",
"20", "21", "22", "23",
"irq1", "irq2", "eol", "sol",
};
int i;
printk(KERN_DEBUG "0x%08x [ %s", risc,
instr[risc >> 28] ? instr[risc >> 28] : "INVALID");
for (i = ARRAY_SIZE(bits) - 1; i >= 0; i--)
if (risc & (1 << (i + 12)))
pr_cont(" %s", bits[i]);
pr_cont(" count=%d ]\n", risc & 0xfff);
return incr[risc >> 28] ? incr[risc >> 28] : 1;
}
static void cx23885_wakeup(struct cx23885_tsport *port,
struct cx23885_dmaqueue *q, u32 count)
{
struct cx23885_buffer *buf;
int count_delta;
int max_buf_done = 5; /* service maximum five buffers */
do {
if (list_empty(&q->active))
return;
buf = list_entry(q->active.next,
struct cx23885_buffer, queue);
buf->vb.vb2_buf.timestamp = ktime_get_ns();
buf->vb.sequence = q->count++;
if (count != (q->count % 65536)) {
dprintk(1, "[%p/%d] wakeup reg=%d buf=%d\n", buf,
buf->vb.vb2_buf.index, count, q->count);
} else {
dprintk(7, "[%p/%d] wakeup reg=%d buf=%d\n", buf,
buf->vb.vb2_buf.index, count, q->count);
}
list_del(&buf->queue);
vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
max_buf_done--;
/* count register is 16 bits so apply modulo appropriately */
count_delta = ((int)count - (int)(q->count % 65536));
} while ((count_delta > 0) && (max_buf_done > 0));
}
int cx23885_sram_channel_setup(struct cx23885_dev *dev,
struct sram_channel *ch,
unsigned int bpl, u32 risc)
{
unsigned int i, lines;
u32 cdt;
if (ch->cmds_start == 0) {
dprintk(1, "%s() Erasing channel [%s]\n", __func__,
ch->name);
cx_write(ch->ptr1_reg, 0);
cx_write(ch->ptr2_reg, 0);
cx_write(ch->cnt2_reg, 0);
cx_write(ch->cnt1_reg, 0);
return 0;
} else {
dprintk(1, "%s() Configuring channel [%s]\n", __func__,
ch->name);
}
bpl = (bpl + 7) & ~7; /* alignment */
cdt = ch->cdt;
lines = ch->fifo_size / bpl;
if (lines > 6)
lines = 6;
BUG_ON(lines < 2);
cx_write(8 + 0, RISC_JUMP | RISC_CNT_RESET);
cx_write(8 + 4, 12);
cx_write(8 + 8, 0);
/* write CDT */
for (i = 0; i < lines; i++) {
dprintk(2, "%s() 0x%08x <- 0x%08x\n", __func__, cdt + 16*i,
ch->fifo_start + bpl*i);
cx_write(cdt + 16*i, ch->fifo_start + bpl*i);
cx_write(cdt + 16*i + 4, 0);
cx_write(cdt + 16*i + 8, 0);
cx_write(cdt + 16*i + 12, 0);
}
/* write CMDS */
if (ch->jumponly)
cx_write(ch->cmds_start + 0, 8);
else
cx_write(ch->cmds_start + 0, risc);
cx_write(ch->cmds_start + 4, 0); /* 64 bits 63-32 */
cx_write(ch->cmds_start + 8, cdt);
cx_write(ch->cmds_start + 12, (lines*16) >> 3);
cx_write(ch->cmds_start + 16, ch->ctrl_start);
if (ch->jumponly)
cx_write(ch->cmds_start + 20, 0x80000000 | (64 >> 2));
else
cx_write(ch->cmds_start + 20, 64 >> 2);
for (i = 24; i < 80; i += 4)
cx_write(ch->cmds_start + i, 0);
/* fill registers */
cx_write(ch->ptr1_reg, ch->fifo_start);
cx_write(ch->ptr2_reg, cdt);
cx_write(ch->cnt2_reg, (lines*16) >> 3);
cx_write(ch->cnt1_reg, (bpl >> 3) - 1);
dprintk(2, "[bridge %d] sram setup %s: bpl=%d lines=%d\n",
dev->bridge,
ch->name,
bpl,
lines);
return 0;
}
void cx23885_sram_channel_dump(struct cx23885_dev *dev,
struct sram_channel *ch)
{
static char *name[] = {
"init risc lo",
"init risc hi",
"cdt base",
"cdt size",
"iq base",
"iq size",
"risc pc lo",
"risc pc hi",
"iq wr ptr",
"iq rd ptr",
"cdt current",
"pci target lo",
"pci target hi",
"line / byte",
};
u32 risc;
unsigned int i, j, n;
pr_warn("%s: %s - dma channel status dump\n",
dev->name, ch->name);
for (i = 0; i < ARRAY_SIZE(name); i++)
pr_warn("%s: cmds: %-15s: 0x%08x\n",
dev->name, name[i],
cx_read(ch->cmds_start + 4*i));
for (i = 0; i < 4; i++) {
risc = cx_read(ch->cmds_start + 4 * (i + 14));
pr_warn("%s: risc%d: ", dev->name, i);
cx23885_risc_decode(risc);
}
for (i = 0; i < (64 >> 2); i += n) {
risc = cx_read(ch->ctrl_start + 4 * i);
/* No consideration for bits 63-32 */
pr_warn("%s: (0x%08x) iq %x: ", dev->name,
ch->ctrl_start + 4 * i, i);
n = cx23885_risc_decode(risc);
for (j = 1; j < n; j++) {
risc = cx_read(ch->ctrl_start + 4 * (i + j));
pr_warn("%s: iq %x: 0x%08x [ arg #%d ]\n",
dev->name, i+j, risc, j);
}
}
pr_warn("%s: fifo: 0x%08x -> 0x%x\n",
dev->name, ch->fifo_start, ch->fifo_start+ch->fifo_size);
pr_warn("%s: ctrl: 0x%08x -> 0x%x\n",
dev->name, ch->ctrl_start, ch->ctrl_start + 6*16);
pr_warn("%s: ptr1_reg: 0x%08x\n",
dev->name, cx_read(ch->ptr1_reg));
pr_warn("%s: ptr2_reg: 0x%08x\n",
dev->name, cx_read(ch->ptr2_reg));
pr_warn("%s: cnt1_reg: 0x%08x\n",
dev->name, cx_read(ch->cnt1_reg));
pr_warn("%s: cnt2_reg: 0x%08x\n",
dev->name, cx_read(ch->cnt2_reg));
}
static void cx23885_risc_disasm(struct cx23885_tsport *port,
struct cx23885_riscmem *risc)
{
struct cx23885_dev *dev = port->dev;
unsigned int i, j, n;
pr_info("%s: risc disasm: %p [dma=0x%08lx]\n",
dev->name, risc->cpu, (unsigned long)risc->dma);
for (i = 0; i < (risc->size >> 2); i += n) {
pr_info("%s: %04d: ", dev->name, i);
n = cx23885_risc_decode(le32_to_cpu(risc->cpu[i]));
for (j = 1; j < n; j++)
pr_info("%s: %04d: 0x%08x [ arg #%d ]\n",
dev->name, i + j, risc->cpu[i + j], j);
if (risc->cpu[i] == cpu_to_le32(RISC_JUMP))
break;
}
}
media: cx23885: Ryzen DMA related RiSC engine stall fixes This bug affects all of Hauppauge QuadHD boards when used on all Ryzen platforms and some XEON platforms. On these platforms it is possible to error out the RiSC engine and cause it to stall, whereafter the only way to reset the board to a working state is to reboot. This is the fatal condition with current driver: [ 255.663598] cx23885: cx23885[0]: mpeg risc op code error [ 255.663607] cx23885: cx23885[0]: TS1 B - dma channel status dump [ 255.663612] cx23885: cx23885[0]: cmds: init risc lo : 0xffe54000 [ 255.663615] cx23885: cx23885[0]: cmds: init risc hi : 0x00000000 [ 255.663619] cx23885: cx23885[0]: cmds: cdt base : 0x00010870 [ 255.663622] cx23885: cx23885[0]: cmds: cdt size : 0x0000000a [ 255.663625] cx23885: cx23885[0]: cmds: iq base : 0x00010630 [ 255.663629] cx23885: cx23885[0]: cmds: iq size : 0x00000010 [ 255.663632] cx23885: cx23885[0]: cmds: risc pc lo : 0xffe54018 [ 255.663636] cx23885: cx23885[0]: cmds: risc pc hi : 0x00000000 [ 255.663639] cx23885: cx23885[0]: cmds: iq wr ptr : 0x00004192 [ 255.663642] cx23885: cx23885[0]: cmds: iq rd ptr : 0x0000418c [ 255.663645] cx23885: cx23885[0]: cmds: cdt current : 0x00010898 [ 255.663649] cx23885: cx23885[0]: cmds: pci target lo : 0xf85ca340 [ 255.663652] cx23885: cx23885[0]: cmds: pci target hi : 0x00000000 [ 255.663655] cx23885: cx23885[0]: cmds: line / byte : 0x000c0000 [ 255.663659] cx23885: cx23885[0]: risc0: [ 255.663661] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663666] cx23885: cx23885[0]: risc1: [ 255.663667] 0xf85ca050 [ INVALID sol 22 20 19 18 resync 13 count=80 ] [ 255.663674] cx23885: cx23885[0]: risc2: [ 255.663674] 0x00000000 [ INVALID count=0 ] [ 255.663678] cx23885: cx23885[0]: risc3: [ 255.663679] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663684] cx23885: cx23885[0]: (0x00010630) iq 0: [ 255.663685] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663690] cx23885: cx23885[0]: iq 1: 0xf85ca630 [ arg #1 ] [ 255.663693] cx23885: cx23885[0]: iq 2: 0x00000000 [ arg #2 ] [ 255.663696] cx23885: cx23885[0]: (0x0001063c) iq 3: [ 255.663697] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663702] cx23885: cx23885[0]: iq 4: 0xf85ca920 [ arg #1 ] [ 255.663705] cx23885: cx23885[0]: iq 5: 0x00000000 [ arg #2 ] [ 255.663709] cx23885: cx23885[0]: (0x00010648) iq 6: [ 255.663709] 0xf85ca340 [ INVALID sol 22 20 19 18 resync 13 count=832 ] [ 255.663716] cx23885: cx23885[0]: (0x0001064c) iq 7: [ 255.663717] 0x00000000 [ INVALID count=0 ] [ 255.663721] cx23885: cx23885[0]: (0x00010650) iq 8: [ 255.663721] 0x00000000 [ INVALID count=0 ] [ 255.663725] cx23885: cx23885[0]: (0x00010654) iq 9: [ 255.663726] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663731] cx23885: cx23885[0]: iq a: 0xf85c9780 [ arg #1 ] [ 255.663734] cx23885: cx23885[0]: iq b: 0x00000000 [ arg #2 ] [ 255.663737] cx23885: cx23885[0]: (0x00010660) iq c: [ 255.663738] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663743] cx23885: cx23885[0]: iq d: 0xf85c9a70 [ arg #1 ] [ 255.663746] cx23885: cx23885[0]: iq e: 0x00000000 [ arg #2 ] [ 255.663749] cx23885: cx23885[0]: (0x0001066c) iq f: [ 255.663750] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663755] cx23885: cx23885[0]: iq 10: 0xf4fa2920 [ arg #1 ] [ 255.663758] cx23885: cx23885[0]: iq 11: 0x00000000 [ arg #2 ] [ 255.663759] cx23885: cx23885[0]: fifo: 0x00005000 -> 0x6000 [ 255.663760] cx23885: cx23885[0]: ctrl: 0x00010630 -> 0x10690 [ 255.663764] cx23885: cx23885[0]: ptr1_reg: 0x00005980 [ 255.663767] cx23885: cx23885[0]: ptr2_reg: 0x000108a8 [ 255.663770] cx23885: cx23885[0]: cnt1_reg: 0x0000000b [ 255.663773] cx23885: cx23885[0]: cnt2_reg: 0x00000003 Included is checks of the TC_REQ and TC_REQ_SET registers during states of board initialization, reset, DMA start, and DMA stop. If both registers are set, this indicates a stall in the RiSC engine, at which point the bridge error is cleared. A small delay is introduced in stop_dma as well, to allow transfers in progress to finish. After application all models work on Ryzen, occasionally yielding: cx23885_clear_bridge_error: dma in progress detected 0x00000001 0x00000001, clearing Signed-off-by: Brad Love <brad@nextdimension.cc> Signed-off-by: Hans Verkuil <hansverk@cisco.com> [hansverk@cisco.com: fix compiler warning of unused 'reg' variable] Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
2018-05-09 05:20:18 +08:00
static void cx23885_clear_bridge_error(struct cx23885_dev *dev)
{
uint32_t reg1_val, reg2_val;
if (!dev->need_dma_reset)
return;
reg1_val = cx_read(TC_REQ); /* read-only */
reg2_val = cx_read(TC_REQ_SET);
media: cx23885: Ryzen DMA related RiSC engine stall fixes This bug affects all of Hauppauge QuadHD boards when used on all Ryzen platforms and some XEON platforms. On these platforms it is possible to error out the RiSC engine and cause it to stall, whereafter the only way to reset the board to a working state is to reboot. This is the fatal condition with current driver: [ 255.663598] cx23885: cx23885[0]: mpeg risc op code error [ 255.663607] cx23885: cx23885[0]: TS1 B - dma channel status dump [ 255.663612] cx23885: cx23885[0]: cmds: init risc lo : 0xffe54000 [ 255.663615] cx23885: cx23885[0]: cmds: init risc hi : 0x00000000 [ 255.663619] cx23885: cx23885[0]: cmds: cdt base : 0x00010870 [ 255.663622] cx23885: cx23885[0]: cmds: cdt size : 0x0000000a [ 255.663625] cx23885: cx23885[0]: cmds: iq base : 0x00010630 [ 255.663629] cx23885: cx23885[0]: cmds: iq size : 0x00000010 [ 255.663632] cx23885: cx23885[0]: cmds: risc pc lo : 0xffe54018 [ 255.663636] cx23885: cx23885[0]: cmds: risc pc hi : 0x00000000 [ 255.663639] cx23885: cx23885[0]: cmds: iq wr ptr : 0x00004192 [ 255.663642] cx23885: cx23885[0]: cmds: iq rd ptr : 0x0000418c [ 255.663645] cx23885: cx23885[0]: cmds: cdt current : 0x00010898 [ 255.663649] cx23885: cx23885[0]: cmds: pci target lo : 0xf85ca340 [ 255.663652] cx23885: cx23885[0]: cmds: pci target hi : 0x00000000 [ 255.663655] cx23885: cx23885[0]: cmds: line / byte : 0x000c0000 [ 255.663659] cx23885: cx23885[0]: risc0: [ 255.663661] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663666] cx23885: cx23885[0]: risc1: [ 255.663667] 0xf85ca050 [ INVALID sol 22 20 19 18 resync 13 count=80 ] [ 255.663674] cx23885: cx23885[0]: risc2: [ 255.663674] 0x00000000 [ INVALID count=0 ] [ 255.663678] cx23885: cx23885[0]: risc3: [ 255.663679] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663684] cx23885: cx23885[0]: (0x00010630) iq 0: [ 255.663685] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663690] cx23885: cx23885[0]: iq 1: 0xf85ca630 [ arg #1 ] [ 255.663693] cx23885: cx23885[0]: iq 2: 0x00000000 [ arg #2 ] [ 255.663696] cx23885: cx23885[0]: (0x0001063c) iq 3: [ 255.663697] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663702] cx23885: cx23885[0]: iq 4: 0xf85ca920 [ arg #1 ] [ 255.663705] cx23885: cx23885[0]: iq 5: 0x00000000 [ arg #2 ] [ 255.663709] cx23885: cx23885[0]: (0x00010648) iq 6: [ 255.663709] 0xf85ca340 [ INVALID sol 22 20 19 18 resync 13 count=832 ] [ 255.663716] cx23885: cx23885[0]: (0x0001064c) iq 7: [ 255.663717] 0x00000000 [ INVALID count=0 ] [ 255.663721] cx23885: cx23885[0]: (0x00010650) iq 8: [ 255.663721] 0x00000000 [ INVALID count=0 ] [ 255.663725] cx23885: cx23885[0]: (0x00010654) iq 9: [ 255.663726] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663731] cx23885: cx23885[0]: iq a: 0xf85c9780 [ arg #1 ] [ 255.663734] cx23885: cx23885[0]: iq b: 0x00000000 [ arg #2 ] [ 255.663737] cx23885: cx23885[0]: (0x00010660) iq c: [ 255.663738] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663743] cx23885: cx23885[0]: iq d: 0xf85c9a70 [ arg #1 ] [ 255.663746] cx23885: cx23885[0]: iq e: 0x00000000 [ arg #2 ] [ 255.663749] cx23885: cx23885[0]: (0x0001066c) iq f: [ 255.663750] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663755] cx23885: cx23885[0]: iq 10: 0xf4fa2920 [ arg #1 ] [ 255.663758] cx23885: cx23885[0]: iq 11: 0x00000000 [ arg #2 ] [ 255.663759] cx23885: cx23885[0]: fifo: 0x00005000 -> 0x6000 [ 255.663760] cx23885: cx23885[0]: ctrl: 0x00010630 -> 0x10690 [ 255.663764] cx23885: cx23885[0]: ptr1_reg: 0x00005980 [ 255.663767] cx23885: cx23885[0]: ptr2_reg: 0x000108a8 [ 255.663770] cx23885: cx23885[0]: cnt1_reg: 0x0000000b [ 255.663773] cx23885: cx23885[0]: cnt2_reg: 0x00000003 Included is checks of the TC_REQ and TC_REQ_SET registers during states of board initialization, reset, DMA start, and DMA stop. If both registers are set, this indicates a stall in the RiSC engine, at which point the bridge error is cleared. A small delay is introduced in stop_dma as well, to allow transfers in progress to finish. After application all models work on Ryzen, occasionally yielding: cx23885_clear_bridge_error: dma in progress detected 0x00000001 0x00000001, clearing Signed-off-by: Brad Love <brad@nextdimension.cc> Signed-off-by: Hans Verkuil <hansverk@cisco.com> [hansverk@cisco.com: fix compiler warning of unused 'reg' variable] Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
2018-05-09 05:20:18 +08:00
if (reg1_val && reg2_val) {
cx_write(TC_REQ, reg1_val);
cx_write(TC_REQ_SET, reg2_val);
cx_read(VID_B_DMA);
cx_read(VBI_B_DMA);
cx_read(VID_C_DMA);
cx_read(VBI_C_DMA);
dev_info(&dev->pci->dev,
"dma in progress detected 0x%08x 0x%08x, clearing\n",
reg1_val, reg2_val);
}
}
static void cx23885_shutdown(struct cx23885_dev *dev)
{
/* disable RISC controller */
cx_write(DEV_CNTRL2, 0);
/* Disable all IR activity */
cx_write(IR_CNTRL_REG, 0);
/* Disable Video A/B activity */
cx_write(VID_A_DMA_CTL, 0);
cx_write(VID_B_DMA_CTL, 0);
cx_write(VID_C_DMA_CTL, 0);
/* Disable Audio activity */
cx_write(AUD_INT_DMA_CTL, 0);
cx_write(AUD_EXT_DMA_CTL, 0);
/* Disable Serial port */
cx_write(UART_CTL, 0);
/* Disable Interrupts */
cx23885_irq_disable_all(dev);
cx_write(VID_A_INT_MSK, 0);
cx_write(VID_B_INT_MSK, 0);
cx_write(VID_C_INT_MSK, 0);
cx_write(AUDIO_INT_INT_MSK, 0);
cx_write(AUDIO_EXT_INT_MSK, 0);
}
static void cx23885_reset(struct cx23885_dev *dev)
{
dprintk(1, "%s()\n", __func__);
cx23885_shutdown(dev);
cx_write(PCI_INT_STAT, 0xffffffff);
cx_write(VID_A_INT_STAT, 0xffffffff);
cx_write(VID_B_INT_STAT, 0xffffffff);
cx_write(VID_C_INT_STAT, 0xffffffff);
cx_write(AUDIO_INT_INT_STAT, 0xffffffff);
cx_write(AUDIO_EXT_INT_STAT, 0xffffffff);
cx_write(CLK_DELAY, cx_read(CLK_DELAY) & 0x80000000);
cx_write(PAD_CTRL, 0x00500300);
media: cx23885: Ryzen DMA related RiSC engine stall fixes This bug affects all of Hauppauge QuadHD boards when used on all Ryzen platforms and some XEON platforms. On these platforms it is possible to error out the RiSC engine and cause it to stall, whereafter the only way to reset the board to a working state is to reboot. This is the fatal condition with current driver: [ 255.663598] cx23885: cx23885[0]: mpeg risc op code error [ 255.663607] cx23885: cx23885[0]: TS1 B - dma channel status dump [ 255.663612] cx23885: cx23885[0]: cmds: init risc lo : 0xffe54000 [ 255.663615] cx23885: cx23885[0]: cmds: init risc hi : 0x00000000 [ 255.663619] cx23885: cx23885[0]: cmds: cdt base : 0x00010870 [ 255.663622] cx23885: cx23885[0]: cmds: cdt size : 0x0000000a [ 255.663625] cx23885: cx23885[0]: cmds: iq base : 0x00010630 [ 255.663629] cx23885: cx23885[0]: cmds: iq size : 0x00000010 [ 255.663632] cx23885: cx23885[0]: cmds: risc pc lo : 0xffe54018 [ 255.663636] cx23885: cx23885[0]: cmds: risc pc hi : 0x00000000 [ 255.663639] cx23885: cx23885[0]: cmds: iq wr ptr : 0x00004192 [ 255.663642] cx23885: cx23885[0]: cmds: iq rd ptr : 0x0000418c [ 255.663645] cx23885: cx23885[0]: cmds: cdt current : 0x00010898 [ 255.663649] cx23885: cx23885[0]: cmds: pci target lo : 0xf85ca340 [ 255.663652] cx23885: cx23885[0]: cmds: pci target hi : 0x00000000 [ 255.663655] cx23885: cx23885[0]: cmds: line / byte : 0x000c0000 [ 255.663659] cx23885: cx23885[0]: risc0: [ 255.663661] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663666] cx23885: cx23885[0]: risc1: [ 255.663667] 0xf85ca050 [ INVALID sol 22 20 19 18 resync 13 count=80 ] [ 255.663674] cx23885: cx23885[0]: risc2: [ 255.663674] 0x00000000 [ INVALID count=0 ] [ 255.663678] cx23885: cx23885[0]: risc3: [ 255.663679] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663684] cx23885: cx23885[0]: (0x00010630) iq 0: [ 255.663685] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663690] cx23885: cx23885[0]: iq 1: 0xf85ca630 [ arg #1 ] [ 255.663693] cx23885: cx23885[0]: iq 2: 0x00000000 [ arg #2 ] [ 255.663696] cx23885: cx23885[0]: (0x0001063c) iq 3: [ 255.663697] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663702] cx23885: cx23885[0]: iq 4: 0xf85ca920 [ arg #1 ] [ 255.663705] cx23885: cx23885[0]: iq 5: 0x00000000 [ arg #2 ] [ 255.663709] cx23885: cx23885[0]: (0x00010648) iq 6: [ 255.663709] 0xf85ca340 [ INVALID sol 22 20 19 18 resync 13 count=832 ] [ 255.663716] cx23885: cx23885[0]: (0x0001064c) iq 7: [ 255.663717] 0x00000000 [ INVALID count=0 ] [ 255.663721] cx23885: cx23885[0]: (0x00010650) iq 8: [ 255.663721] 0x00000000 [ INVALID count=0 ] [ 255.663725] cx23885: cx23885[0]: (0x00010654) iq 9: [ 255.663726] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663731] cx23885: cx23885[0]: iq a: 0xf85c9780 [ arg #1 ] [ 255.663734] cx23885: cx23885[0]: iq b: 0x00000000 [ arg #2 ] [ 255.663737] cx23885: cx23885[0]: (0x00010660) iq c: [ 255.663738] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663743] cx23885: cx23885[0]: iq d: 0xf85c9a70 [ arg #1 ] [ 255.663746] cx23885: cx23885[0]: iq e: 0x00000000 [ arg #2 ] [ 255.663749] cx23885: cx23885[0]: (0x0001066c) iq f: [ 255.663750] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663755] cx23885: cx23885[0]: iq 10: 0xf4fa2920 [ arg #1 ] [ 255.663758] cx23885: cx23885[0]: iq 11: 0x00000000 [ arg #2 ] [ 255.663759] cx23885: cx23885[0]: fifo: 0x00005000 -> 0x6000 [ 255.663760] cx23885: cx23885[0]: ctrl: 0x00010630 -> 0x10690 [ 255.663764] cx23885: cx23885[0]: ptr1_reg: 0x00005980 [ 255.663767] cx23885: cx23885[0]: ptr2_reg: 0x000108a8 [ 255.663770] cx23885: cx23885[0]: cnt1_reg: 0x0000000b [ 255.663773] cx23885: cx23885[0]: cnt2_reg: 0x00000003 Included is checks of the TC_REQ and TC_REQ_SET registers during states of board initialization, reset, DMA start, and DMA stop. If both registers are set, this indicates a stall in the RiSC engine, at which point the bridge error is cleared. A small delay is introduced in stop_dma as well, to allow transfers in progress to finish. After application all models work on Ryzen, occasionally yielding: cx23885_clear_bridge_error: dma in progress detected 0x00000001 0x00000001, clearing Signed-off-by: Brad Love <brad@nextdimension.cc> Signed-off-by: Hans Verkuil <hansverk@cisco.com> [hansverk@cisco.com: fix compiler warning of unused 'reg' variable] Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
2018-05-09 05:20:18 +08:00
/* clear dma in progress */
cx23885_clear_bridge_error(dev);
msleep(100);
cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH01],
720*4, 0);
cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH02], 128, 0);
cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH03],
188*4, 0);
cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH04], 128, 0);
cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH05], 128, 0);
cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH06],
188*4, 0);
cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH07], 128, 0);
cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH08], 128, 0);
cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH09], 128, 0);
cx23885_gpio_setup(dev);
media: cx23885: Ryzen DMA related RiSC engine stall fixes This bug affects all of Hauppauge QuadHD boards when used on all Ryzen platforms and some XEON platforms. On these platforms it is possible to error out the RiSC engine and cause it to stall, whereafter the only way to reset the board to a working state is to reboot. This is the fatal condition with current driver: [ 255.663598] cx23885: cx23885[0]: mpeg risc op code error [ 255.663607] cx23885: cx23885[0]: TS1 B - dma channel status dump [ 255.663612] cx23885: cx23885[0]: cmds: init risc lo : 0xffe54000 [ 255.663615] cx23885: cx23885[0]: cmds: init risc hi : 0x00000000 [ 255.663619] cx23885: cx23885[0]: cmds: cdt base : 0x00010870 [ 255.663622] cx23885: cx23885[0]: cmds: cdt size : 0x0000000a [ 255.663625] cx23885: cx23885[0]: cmds: iq base : 0x00010630 [ 255.663629] cx23885: cx23885[0]: cmds: iq size : 0x00000010 [ 255.663632] cx23885: cx23885[0]: cmds: risc pc lo : 0xffe54018 [ 255.663636] cx23885: cx23885[0]: cmds: risc pc hi : 0x00000000 [ 255.663639] cx23885: cx23885[0]: cmds: iq wr ptr : 0x00004192 [ 255.663642] cx23885: cx23885[0]: cmds: iq rd ptr : 0x0000418c [ 255.663645] cx23885: cx23885[0]: cmds: cdt current : 0x00010898 [ 255.663649] cx23885: cx23885[0]: cmds: pci target lo : 0xf85ca340 [ 255.663652] cx23885: cx23885[0]: cmds: pci target hi : 0x00000000 [ 255.663655] cx23885: cx23885[0]: cmds: line / byte : 0x000c0000 [ 255.663659] cx23885: cx23885[0]: risc0: [ 255.663661] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663666] cx23885: cx23885[0]: risc1: [ 255.663667] 0xf85ca050 [ INVALID sol 22 20 19 18 resync 13 count=80 ] [ 255.663674] cx23885: cx23885[0]: risc2: [ 255.663674] 0x00000000 [ INVALID count=0 ] [ 255.663678] cx23885: cx23885[0]: risc3: [ 255.663679] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663684] cx23885: cx23885[0]: (0x00010630) iq 0: [ 255.663685] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663690] cx23885: cx23885[0]: iq 1: 0xf85ca630 [ arg #1 ] [ 255.663693] cx23885: cx23885[0]: iq 2: 0x00000000 [ arg #2 ] [ 255.663696] cx23885: cx23885[0]: (0x0001063c) iq 3: [ 255.663697] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663702] cx23885: cx23885[0]: iq 4: 0xf85ca920 [ arg #1 ] [ 255.663705] cx23885: cx23885[0]: iq 5: 0x00000000 [ arg #2 ] [ 255.663709] cx23885: cx23885[0]: (0x00010648) iq 6: [ 255.663709] 0xf85ca340 [ INVALID sol 22 20 19 18 resync 13 count=832 ] [ 255.663716] cx23885: cx23885[0]: (0x0001064c) iq 7: [ 255.663717] 0x00000000 [ INVALID count=0 ] [ 255.663721] cx23885: cx23885[0]: (0x00010650) iq 8: [ 255.663721] 0x00000000 [ INVALID count=0 ] [ 255.663725] cx23885: cx23885[0]: (0x00010654) iq 9: [ 255.663726] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663731] cx23885: cx23885[0]: iq a: 0xf85c9780 [ arg #1 ] [ 255.663734] cx23885: cx23885[0]: iq b: 0x00000000 [ arg #2 ] [ 255.663737] cx23885: cx23885[0]: (0x00010660) iq c: [ 255.663738] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663743] cx23885: cx23885[0]: iq d: 0xf85c9a70 [ arg #1 ] [ 255.663746] cx23885: cx23885[0]: iq e: 0x00000000 [ arg #2 ] [ 255.663749] cx23885: cx23885[0]: (0x0001066c) iq f: [ 255.663750] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663755] cx23885: cx23885[0]: iq 10: 0xf4fa2920 [ arg #1 ] [ 255.663758] cx23885: cx23885[0]: iq 11: 0x00000000 [ arg #2 ] [ 255.663759] cx23885: cx23885[0]: fifo: 0x00005000 -> 0x6000 [ 255.663760] cx23885: cx23885[0]: ctrl: 0x00010630 -> 0x10690 [ 255.663764] cx23885: cx23885[0]: ptr1_reg: 0x00005980 [ 255.663767] cx23885: cx23885[0]: ptr2_reg: 0x000108a8 [ 255.663770] cx23885: cx23885[0]: cnt1_reg: 0x0000000b [ 255.663773] cx23885: cx23885[0]: cnt2_reg: 0x00000003 Included is checks of the TC_REQ and TC_REQ_SET registers during states of board initialization, reset, DMA start, and DMA stop. If both registers are set, this indicates a stall in the RiSC engine, at which point the bridge error is cleared. A small delay is introduced in stop_dma as well, to allow transfers in progress to finish. After application all models work on Ryzen, occasionally yielding: cx23885_clear_bridge_error: dma in progress detected 0x00000001 0x00000001, clearing Signed-off-by: Brad Love <brad@nextdimension.cc> Signed-off-by: Hans Verkuil <hansverk@cisco.com> [hansverk@cisco.com: fix compiler warning of unused 'reg' variable] Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
2018-05-09 05:20:18 +08:00
cx23885_irq_get_mask(dev);
/* clear dma in progress */
cx23885_clear_bridge_error(dev);
}
static int cx23885_pci_quirks(struct cx23885_dev *dev)
{
dprintk(1, "%s()\n", __func__);
/* The cx23885 bridge has a weird bug which causes NMI to be asserted
* when DMA begins if RDR_TLCTL0 bit4 is not cleared. It does not
* occur on the cx23887 bridge.
*/
if (dev->bridge == CX23885_BRIDGE_885)
cx_clear(RDR_TLCTL0, 1 << 4);
media: cx23885: Ryzen DMA related RiSC engine stall fixes This bug affects all of Hauppauge QuadHD boards when used on all Ryzen platforms and some XEON platforms. On these platforms it is possible to error out the RiSC engine and cause it to stall, whereafter the only way to reset the board to a working state is to reboot. This is the fatal condition with current driver: [ 255.663598] cx23885: cx23885[0]: mpeg risc op code error [ 255.663607] cx23885: cx23885[0]: TS1 B - dma channel status dump [ 255.663612] cx23885: cx23885[0]: cmds: init risc lo : 0xffe54000 [ 255.663615] cx23885: cx23885[0]: cmds: init risc hi : 0x00000000 [ 255.663619] cx23885: cx23885[0]: cmds: cdt base : 0x00010870 [ 255.663622] cx23885: cx23885[0]: cmds: cdt size : 0x0000000a [ 255.663625] cx23885: cx23885[0]: cmds: iq base : 0x00010630 [ 255.663629] cx23885: cx23885[0]: cmds: iq size : 0x00000010 [ 255.663632] cx23885: cx23885[0]: cmds: risc pc lo : 0xffe54018 [ 255.663636] cx23885: cx23885[0]: cmds: risc pc hi : 0x00000000 [ 255.663639] cx23885: cx23885[0]: cmds: iq wr ptr : 0x00004192 [ 255.663642] cx23885: cx23885[0]: cmds: iq rd ptr : 0x0000418c [ 255.663645] cx23885: cx23885[0]: cmds: cdt current : 0x00010898 [ 255.663649] cx23885: cx23885[0]: cmds: pci target lo : 0xf85ca340 [ 255.663652] cx23885: cx23885[0]: cmds: pci target hi : 0x00000000 [ 255.663655] cx23885: cx23885[0]: cmds: line / byte : 0x000c0000 [ 255.663659] cx23885: cx23885[0]: risc0: [ 255.663661] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663666] cx23885: cx23885[0]: risc1: [ 255.663667] 0xf85ca050 [ INVALID sol 22 20 19 18 resync 13 count=80 ] [ 255.663674] cx23885: cx23885[0]: risc2: [ 255.663674] 0x00000000 [ INVALID count=0 ] [ 255.663678] cx23885: cx23885[0]: risc3: [ 255.663679] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663684] cx23885: cx23885[0]: (0x00010630) iq 0: [ 255.663685] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663690] cx23885: cx23885[0]: iq 1: 0xf85ca630 [ arg #1 ] [ 255.663693] cx23885: cx23885[0]: iq 2: 0x00000000 [ arg #2 ] [ 255.663696] cx23885: cx23885[0]: (0x0001063c) iq 3: [ 255.663697] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663702] cx23885: cx23885[0]: iq 4: 0xf85ca920 [ arg #1 ] [ 255.663705] cx23885: cx23885[0]: iq 5: 0x00000000 [ arg #2 ] [ 255.663709] cx23885: cx23885[0]: (0x00010648) iq 6: [ 255.663709] 0xf85ca340 [ INVALID sol 22 20 19 18 resync 13 count=832 ] [ 255.663716] cx23885: cx23885[0]: (0x0001064c) iq 7: [ 255.663717] 0x00000000 [ INVALID count=0 ] [ 255.663721] cx23885: cx23885[0]: (0x00010650) iq 8: [ 255.663721] 0x00000000 [ INVALID count=0 ] [ 255.663725] cx23885: cx23885[0]: (0x00010654) iq 9: [ 255.663726] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663731] cx23885: cx23885[0]: iq a: 0xf85c9780 [ arg #1 ] [ 255.663734] cx23885: cx23885[0]: iq b: 0x00000000 [ arg #2 ] [ 255.663737] cx23885: cx23885[0]: (0x00010660) iq c: [ 255.663738] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663743] cx23885: cx23885[0]: iq d: 0xf85c9a70 [ arg #1 ] [ 255.663746] cx23885: cx23885[0]: iq e: 0x00000000 [ arg #2 ] [ 255.663749] cx23885: cx23885[0]: (0x0001066c) iq f: [ 255.663750] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663755] cx23885: cx23885[0]: iq 10: 0xf4fa2920 [ arg #1 ] [ 255.663758] cx23885: cx23885[0]: iq 11: 0x00000000 [ arg #2 ] [ 255.663759] cx23885: cx23885[0]: fifo: 0x00005000 -> 0x6000 [ 255.663760] cx23885: cx23885[0]: ctrl: 0x00010630 -> 0x10690 [ 255.663764] cx23885: cx23885[0]: ptr1_reg: 0x00005980 [ 255.663767] cx23885: cx23885[0]: ptr2_reg: 0x000108a8 [ 255.663770] cx23885: cx23885[0]: cnt1_reg: 0x0000000b [ 255.663773] cx23885: cx23885[0]: cnt2_reg: 0x00000003 Included is checks of the TC_REQ and TC_REQ_SET registers during states of board initialization, reset, DMA start, and DMA stop. If both registers are set, this indicates a stall in the RiSC engine, at which point the bridge error is cleared. A small delay is introduced in stop_dma as well, to allow transfers in progress to finish. After application all models work on Ryzen, occasionally yielding: cx23885_clear_bridge_error: dma in progress detected 0x00000001 0x00000001, clearing Signed-off-by: Brad Love <brad@nextdimension.cc> Signed-off-by: Hans Verkuil <hansverk@cisco.com> [hansverk@cisco.com: fix compiler warning of unused 'reg' variable] Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
2018-05-09 05:20:18 +08:00
/* clear dma in progress */
cx23885_clear_bridge_error(dev);
return 0;
}
static int get_resources(struct cx23885_dev *dev)
{
if (request_mem_region(pci_resource_start(dev->pci, 0),
pci_resource_len(dev->pci, 0),
dev->name))
return 0;
pr_err("%s: can't get MMIO memory @ 0x%llx\n",
dev->name, (unsigned long long)pci_resource_start(dev->pci, 0));
return -EBUSY;
}
static int cx23885_init_tsport(struct cx23885_dev *dev,
struct cx23885_tsport *port, int portno)
{
dprintk(1, "%s(portno=%d)\n", __func__, portno);
/* Transport bus init dma queue - Common settings */
port->dma_ctl_val = 0x11; /* Enable RISC controller and Fifo */
port->ts_int_msk_val = 0x1111; /* TS port bits for RISC */
port->vld_misc_val = 0x0;
port->hw_sop_ctrl_val = (0x47 << 16 | 188 << 4);
spin_lock_init(&port->slock);
port->dev = dev;
port->nr = portno;
INIT_LIST_HEAD(&port->mpegq.active);
mutex_init(&port->frontends.lock);
INIT_LIST_HEAD(&port->frontends.felist);
port->frontends.active_fe_id = 0;
/* This should be hardcoded allow a single frontend
* attachment to this tsport, keeping the -dvb.c
* code clean and safe.
*/
if (!port->num_frontends)
port->num_frontends = 1;
switch (portno) {
case 1:
port->reg_gpcnt = VID_B_GPCNT;
port->reg_gpcnt_ctl = VID_B_GPCNT_CTL;
port->reg_dma_ctl = VID_B_DMA_CTL;
port->reg_lngth = VID_B_LNGTH;
port->reg_hw_sop_ctrl = VID_B_HW_SOP_CTL;
port->reg_gen_ctrl = VID_B_GEN_CTL;
port->reg_bd_pkt_status = VID_B_BD_PKT_STATUS;
port->reg_sop_status = VID_B_SOP_STATUS;
port->reg_fifo_ovfl_stat = VID_B_FIFO_OVFL_STAT;
port->reg_vld_misc = VID_B_VLD_MISC;
port->reg_ts_clk_en = VID_B_TS_CLK_EN;
port->reg_src_sel = VID_B_SRC_SEL;
port->reg_ts_int_msk = VID_B_INT_MSK;
port->reg_ts_int_stat = VID_B_INT_STAT;
port->sram_chno = SRAM_CH03; /* VID_B */
port->pci_irqmask = 0x02; /* VID_B bit1 */
break;
case 2:
port->reg_gpcnt = VID_C_GPCNT;
port->reg_gpcnt_ctl = VID_C_GPCNT_CTL;
port->reg_dma_ctl = VID_C_DMA_CTL;
port->reg_lngth = VID_C_LNGTH;
port->reg_hw_sop_ctrl = VID_C_HW_SOP_CTL;
port->reg_gen_ctrl = VID_C_GEN_CTL;
port->reg_bd_pkt_status = VID_C_BD_PKT_STATUS;
port->reg_sop_status = VID_C_SOP_STATUS;
port->reg_fifo_ovfl_stat = VID_C_FIFO_OVFL_STAT;
port->reg_vld_misc = VID_C_VLD_MISC;
port->reg_ts_clk_en = VID_C_TS_CLK_EN;
port->reg_src_sel = 0;
port->reg_ts_int_msk = VID_C_INT_MSK;
port->reg_ts_int_stat = VID_C_INT_STAT;
port->sram_chno = SRAM_CH06; /* VID_C */
port->pci_irqmask = 0x04; /* VID_C bit2 */
break;
default:
BUG();
}
return 0;
}
static void cx23885_dev_checkrevision(struct cx23885_dev *dev)
{
switch (cx_read(RDR_CFG2) & 0xff) {
case 0x00:
/* cx23885 */
dev->hwrevision = 0xa0;
break;
case 0x01:
/* CX23885-12Z */
dev->hwrevision = 0xa1;
break;
case 0x02:
/* CX23885-13Z/14Z */
dev->hwrevision = 0xb0;
break;
case 0x03:
if (dev->pci->device == 0x8880) {
/* CX23888-21Z/22Z */
dev->hwrevision = 0xc0;
} else {
/* CX23885-14Z */
dev->hwrevision = 0xa4;
}
break;
case 0x04:
if (dev->pci->device == 0x8880) {
/* CX23888-31Z */
dev->hwrevision = 0xd0;
} else {
/* CX23885-15Z, CX23888-31Z */
dev->hwrevision = 0xa5;
}
break;
case 0x0e:
/* CX23887-15Z */
dev->hwrevision = 0xc0;
break;
case 0x0f:
/* CX23887-14Z */
dev->hwrevision = 0xb1;
break;
default:
pr_err("%s() New hardware revision found 0x%x\n",
__func__, dev->hwrevision);
}
if (dev->hwrevision)
pr_info("%s() Hardware revision = 0x%02x\n",
__func__, dev->hwrevision);
else
pr_err("%s() Hardware revision unknown 0x%x\n",
__func__, dev->hwrevision);
}
/* Find the first v4l2_subdev member of the group id in hw */
struct v4l2_subdev *cx23885_find_hw(struct cx23885_dev *dev, u32 hw)
{
struct v4l2_subdev *result = NULL;
struct v4l2_subdev *sd;
spin_lock(&dev->v4l2_dev.lock);
v4l2_device_for_each_subdev(sd, &dev->v4l2_dev) {
if (sd->grp_id == hw) {
result = sd;
break;
}
}
spin_unlock(&dev->v4l2_dev.lock);
return result;
}
static int cx23885_dev_setup(struct cx23885_dev *dev)
{
int i;
spin_lock_init(&dev->pci_irqmask_lock);
[media] cx23885: Always initialise dev->slock spinlock The slock spinlock in the cx23885_dev struct is only initialised if analogue video is being used, but is used in other places too, leading to the attached lockdep complaint. Move the lock initialisation so that it is done unconditionally. INFO: trying to register non-static key. the code is fine but needs lockdep annotation. turning off the locking correctness validator. CPU: 1 PID: 4413 Comm: scandvb Tainted: G W 4.0.0-rc1-fsdevel+ #25 Hardware name: System manufacturer System Product Name/P5Q PRO TURBO, BIOS 0701 10/08/2012 0000000000000000 ffff880129d779d8 ffffffff8162bbdf 0000000000000006 0000000000000000 ffff880129d77aa8 ffffffff810780e3 0000000000000001 0000000000000046 0000000000000004 ffffffff81c3f180 0000000000000000 Call Trace: [<ffffffff8162bbdf>] dump_stack+0x4c/0x65 [<ffffffff810780e3>] __lock_acquire+0x7b5/0x1a0e [<ffffffff810799ee>] lock_acquire+0x97/0x10c [<ffffffffa006494e>] ? cx23885_buf_queue+0x69/0x142 [cx23885] [<ffffffff8102e9bc>] ? amd_set_subcaches+0x19b/0x19b [<ffffffff816313b4>] _raw_spin_lock_irqsave+0x36/0x4a [<ffffffffa006494e>] ? cx23885_buf_queue+0x69/0x142 [cx23885] [<ffffffffa006494e>] cx23885_buf_queue+0x69/0x142 [cx23885] [<ffffffffa00662cb>] buffer_queue+0x17/0x19 [cx23885] [<ffffffffa00382d5>] __enqueue_in_driver+0x6a/0x6f [videobuf2_core] [<ffffffffa0038ead>] vb2_start_streaming+0x37/0x129 [videobuf2_core] [<ffffffffa003a6c0>] vb2_internal_streamon+0xc5/0x105 [videobuf2_core] [<ffffffffa003b889>] __vb2_init_fileio+0x224/0x286 [videobuf2_core] [<ffffffffa003bcc0>] ? vb2_thread_start+0x7b/0x15f [videobuf2_core] [<ffffffffa0050182>] ? vb2_dvb_start_feed+0x86/0x86 [videobuf2_dvb] [<ffffffffa003bd06>] vb2_thread_start+0xc1/0x15f [videobuf2_core] [<ffffffff8150d393>] ? dmx_section_feed_start_filtering+0x2f/0x14f [<ffffffffa0050157>] vb2_dvb_start_feed+0x5b/0x86 [videobuf2_dvb] [<ffffffff8150d461>] dmx_section_feed_start_filtering+0xfd/0x14f [<ffffffff8150afc7>] dvb_dmxdev_filter_start+0x23f/0x315 [<ffffffff8150b6ad>] dvb_demux_do_ioctl+0x1fb/0x556 [<ffffffff81509e94>] dvb_usercopy+0xb4/0x11c [<ffffffff8150b4b2>] ? dvb_dmxdev_ts_callback+0xd0/0xd0 [<ffffffff8150a11a>] dvb_demux_ioctl+0x10/0x14 [<ffffffff81144ac4>] do_vfs_ioctl+0x3c1/0x474 [<ffffffff8126f181>] ? file_has_perm+0x5b/0x7f [<ffffffff810bf6ca>] ? __audit_syscall_entry+0xbc/0xde [<ffffffff81144bcc>] SyS_ioctl+0x55/0x7a [<ffffffff81631d52>] system_call_fastpath+0x12/0x17 Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2015-03-26 21:06:21 +08:00
spin_lock_init(&dev->slock);
mutex_init(&dev->lock);
mutex_init(&dev->gpio_lock);
atomic_inc(&dev->refcount);
dev->nr = cx23885_devcount++;
sprintf(dev->name, "cx23885[%d]", dev->nr);
/* Configure the internal memory */
if (dev->pci->device == 0x8880) {
/* Could be 887 or 888, assume an 888 default */
dev->bridge = CX23885_BRIDGE_888;
/* Apply a sensible clock frequency for the PCIe bridge */
dev->clk_freq = 50000000;
dev->sram_channels = cx23887_sram_channels;
} else
if (dev->pci->device == 0x8852) {
dev->bridge = CX23885_BRIDGE_885;
/* Apply a sensible clock frequency for the PCIe bridge */
dev->clk_freq = 28000000;
dev->sram_channels = cx23885_sram_channels;
} else
BUG();
dprintk(1, "%s() Memory configured for PCIe bridge type %d\n",
__func__, dev->bridge);
/* board config */
dev->board = UNSET;
if (card[dev->nr] < cx23885_bcount)
dev->board = card[dev->nr];
for (i = 0; UNSET == dev->board && i < cx23885_idcount; i++)
if (dev->pci->subsystem_vendor == cx23885_subids[i].subvendor &&
dev->pci->subsystem_device == cx23885_subids[i].subdevice)
dev->board = cx23885_subids[i].card;
if (UNSET == dev->board) {
dev->board = CX23885_BOARD_UNKNOWN;
cx23885_card_list(dev);
}
if (dev->pci->device == 0x8852) {
/* no DIF on cx23885, so no analog tuner support possible */
if (dev->board == CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC)
dev->board = CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC_885;
else if (dev->board == CX23885_BOARD_HAUPPAUGE_QUADHD_DVB)
dev->board = CX23885_BOARD_HAUPPAUGE_QUADHD_DVB_885;
}
/* If the user specific a clk freq override, apply it */
if (cx23885_boards[dev->board].clk_freq > 0)
dev->clk_freq = cx23885_boards[dev->board].clk_freq;
if (dev->board == CX23885_BOARD_HAUPPAUGE_IMPACTVCBE &&
dev->pci->subsystem_device == 0x7137) {
/* Hauppauge ImpactVCBe device ID 0x7137 is populated
* with an 888, and a 25Mhz crystal, instead of the
* usual third overtone 50Mhz. The default clock rate must
* be overridden so the cx25840 is properly configured
*/
dev->clk_freq = 25000000;
}
dev->pci_bus = dev->pci->bus->number;
dev->pci_slot = PCI_SLOT(dev->pci->devfn);
cx23885_irq_add(dev, 0x001f00);
/* External Master 1 Bus */
dev->i2c_bus[0].nr = 0;
dev->i2c_bus[0].dev = dev;
dev->i2c_bus[0].reg_stat = I2C1_STAT;
dev->i2c_bus[0].reg_ctrl = I2C1_CTRL;
dev->i2c_bus[0].reg_addr = I2C1_ADDR;
dev->i2c_bus[0].reg_rdata = I2C1_RDATA;
dev->i2c_bus[0].reg_wdata = I2C1_WDATA;
dev->i2c_bus[0].i2c_period = (0x9d << 24); /* 100kHz */
/* External Master 2 Bus */
dev->i2c_bus[1].nr = 1;
dev->i2c_bus[1].dev = dev;
dev->i2c_bus[1].reg_stat = I2C2_STAT;
dev->i2c_bus[1].reg_ctrl = I2C2_CTRL;
dev->i2c_bus[1].reg_addr = I2C2_ADDR;
dev->i2c_bus[1].reg_rdata = I2C2_RDATA;
dev->i2c_bus[1].reg_wdata = I2C2_WDATA;
dev->i2c_bus[1].i2c_period = (0x9d << 24); /* 100kHz */
/* Internal Master 3 Bus */
dev->i2c_bus[2].nr = 2;
dev->i2c_bus[2].dev = dev;
dev->i2c_bus[2].reg_stat = I2C3_STAT;
dev->i2c_bus[2].reg_ctrl = I2C3_CTRL;
dev->i2c_bus[2].reg_addr = I2C3_ADDR;
dev->i2c_bus[2].reg_rdata = I2C3_RDATA;
dev->i2c_bus[2].reg_wdata = I2C3_WDATA;
dev->i2c_bus[2].i2c_period = (0x07 << 24); /* 1.95MHz */
if ((cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) ||
(cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER))
cx23885_init_tsport(dev, &dev->ts1, 1);
if ((cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) ||
(cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER))
cx23885_init_tsport(dev, &dev->ts2, 2);
if (get_resources(dev) < 0) {
pr_err("CORE %s No more PCIe resources for subsystem: %04x:%04x\n",
dev->name, dev->pci->subsystem_vendor,
dev->pci->subsystem_device);
cx23885_devcount--;
return -ENODEV;
}
/* PCIe stuff */
dev->lmmio = ioremap(pci_resource_start(dev->pci, 0),
pci_resource_len(dev->pci, 0));
dev->bmmio = (u8 __iomem *)dev->lmmio;
pr_info("CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
dev->name, dev->pci->subsystem_vendor,
dev->pci->subsystem_device, cx23885_boards[dev->board].name,
dev->board, card[dev->nr] == dev->board ?
"insmod option" : "autodetected");
cx23885_pci_quirks(dev);
/* Assume some sensible defaults */
dev->tuner_type = cx23885_boards[dev->board].tuner_type;
dev->tuner_addr = cx23885_boards[dev->board].tuner_addr;
dev->tuner_bus = cx23885_boards[dev->board].tuner_bus;
dev->radio_type = cx23885_boards[dev->board].radio_type;
dev->radio_addr = cx23885_boards[dev->board].radio_addr;
dprintk(1, "%s() tuner_type = 0x%x tuner_addr = 0x%x tuner_bus = %d\n",
__func__, dev->tuner_type, dev->tuner_addr, dev->tuner_bus);
dprintk(1, "%s() radio_type = 0x%x radio_addr = 0x%x\n",
__func__, dev->radio_type, dev->radio_addr);
/* The cx23417 encoder has GPIO's that need to be initialised
* before DVB, so that demodulators and tuners are out of
* reset before DVB uses them.
*/
if ((cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) ||
(cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER))
cx23885_mc417_init(dev);
/* init hardware */
cx23885_reset(dev);
cx23885_i2c_register(&dev->i2c_bus[0]);
cx23885_i2c_register(&dev->i2c_bus[1]);
cx23885_i2c_register(&dev->i2c_bus[2]);
cx23885_card_setup(dev);
call_all(dev, tuner, standby);
cx23885_ir_init(dev);
if (dev->board == CX23885_BOARD_VIEWCAST_460E) {
/*
* GPIOs 9/8 are input detection bits for the breakout video
* (gpio 8) and audio (gpio 9) cables. When they're attached,
* this gpios are pulled high. Make sure these GPIOs are marked
* as inputs.
*/
cx23885_gpio_enable(dev, 0x300, 0);
}
if (cx23885_boards[dev->board].porta == CX23885_ANALOG_VIDEO) {
if (cx23885_video_register(dev) < 0) {
pr_err("%s() Failed to register analog video adapters on VID_A\n",
__func__);
}
}
if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) {
if (cx23885_boards[dev->board].num_fds_portb)
dev->ts1.num_frontends =
cx23885_boards[dev->board].num_fds_portb;
if (cx23885_dvb_register(&dev->ts1) < 0) {
pr_err("%s() Failed to register dvb adapters on VID_B\n",
__func__);
}
} else
if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) {
if (cx23885_417_register(dev) < 0) {
pr_err("%s() Failed to register 417 on VID_B\n",
__func__);
}
}
if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) {
if (cx23885_boards[dev->board].num_fds_portc)
dev->ts2.num_frontends =
cx23885_boards[dev->board].num_fds_portc;
if (cx23885_dvb_register(&dev->ts2) < 0) {
pr_err("%s() Failed to register dvb on VID_C\n",
__func__);
}
} else
if (cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER) {
if (cx23885_417_register(dev) < 0) {
pr_err("%s() Failed to register 417 on VID_C\n",
__func__);
}
}
cx23885_dev_checkrevision(dev);
/* disable MSI for NetUP cards, otherwise CI is not working */
if (cx23885_boards[dev->board].ci_type > 0)
cx_clear(RDR_RDRCTL1, 1 << 8);
switch (dev->board) {
case CX23885_BOARD_TEVII_S470:
case CX23885_BOARD_TEVII_S471:
cx_clear(RDR_RDRCTL1, 1 << 8);
break;
}
return 0;
}
static void cx23885_dev_unregister(struct cx23885_dev *dev)
{
release_mem_region(pci_resource_start(dev->pci, 0),
pci_resource_len(dev->pci, 0));
if (!atomic_dec_and_test(&dev->refcount))
return;
if (cx23885_boards[dev->board].porta == CX23885_ANALOG_VIDEO)
cx23885_video_unregister(dev);
if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB)
cx23885_dvb_unregister(&dev->ts1);
if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER)
cx23885_417_unregister(dev);
if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB)
cx23885_dvb_unregister(&dev->ts2);
if (cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER)
cx23885_417_unregister(dev);
cx23885_i2c_unregister(&dev->i2c_bus[2]);
cx23885_i2c_unregister(&dev->i2c_bus[1]);
cx23885_i2c_unregister(&dev->i2c_bus[0]);
iounmap(dev->lmmio);
}
static __le32 *cx23885_risc_field(__le32 *rp, struct scatterlist *sglist,
unsigned int offset, u32 sync_line,
unsigned int bpl, unsigned int padding,
unsigned int lines, unsigned int lpi, bool jump)
{
struct scatterlist *sg;
unsigned int line, todo, sol;
if (jump) {
*(rp++) = cpu_to_le32(RISC_JUMP);
*(rp++) = cpu_to_le32(0);
*(rp++) = cpu_to_le32(0); /* bits 63-32 */
}
/* sync instruction */
if (sync_line != NO_SYNC_LINE)
*(rp++) = cpu_to_le32(RISC_RESYNC | sync_line);
/* scan lines */
sg = sglist;
for (line = 0; line < lines; line++) {
while (offset && offset >= sg_dma_len(sg)) {
offset -= sg_dma_len(sg);
[media] cx23885: use sg = sg_next(sg) instead of sg++ The cx23885 driver still used sg++ instead of sg = sg_next(sg). This worked with vb1 since that filled in the sglist manually, page-by-page, but it fails with vb2 which uses core scatterlist code that can combine contiguous scatterlist entries into one larger entry. This bug led to the following crash as reported by Mariusz: [20712.990258] BUG: Bad page state in process vb2-cx23885[0] pfn:2ca34 [20712.990265] page:ffffea00009c3b60 count:-1 mapcount:0 mapping: (null) index:0x0 [20712.990266] flags: 0x4000000000000000() [20712.990268] page dumped because: nonzero _count [20712.990269] Modules linked in: tun binfmt_misc nf_conntrack_ipv6 nf_defrag_ipv6 ip6table_filter ip6_tables xt_mark xt_REDIRECT xt_limit xt_conntrack xt_nat xt_tcpudp iptable_mangle iptable_nat nf_conntrack_ipv4 nf_defrag_ipv4 nf_nat_ipv4 nf_nat nf_conntrack iptable_filter ip_tables x_tables sit ip_tunnel nvidia(PO) stb6100 stv090x cx88_dvb videobuf_dvb cx88_vp3054_i2c tuner kvm_amd kvm cx8802 k10temp cx8800 cx88xx btcx_risc videobuf_dma_sg videobuf_core usb_storage ds2490 usbhid ftdi_sio cx23885 tveeprom cx2341x videobuf2_dvb videobuf2_core videobuf2_dma_sg videobuf2_memops asus_atk0110 snd_emu10k1 snd_hwdep snd_util_mem snd_ac97_codec ac97_bus snd_rawmidi snd_pcm_oss snd_mixer_oss snd_pcm snd_timer snd w1_therm wire ipv6 [20712.990301] CPU: 2 PID: 26942 Comm: vb2-cx23885[0] Tainted: P B W O 3.18.0-rc5-00001-gb3652d1 #2 [20712.990303] Hardware name: System manufacturer System Product Name/M4A785TD-V EVO, BIOS 2105 07/23/2010 [20712.990305] ffffffff81765734 ffff880137683a78 ffffffff815b6b32 0000000000000006 [20712.990307] ffffea00009c3b60 ffff880137683aa8 ffffffff8108ec27 ffffffff81765712 [20712.990309] ffffffff8189c840 0000000000000246 ffffea00009c3b60 ffff880137683b78 [20712.990312] Call Trace: [20712.990317] [<ffffffff815b6b32>] dump_stack+0x46/0x58 [20712.990321] [<ffffffff8108ec27>] bad_page+0xe9/0x107 [20712.990323] [<ffffffff810912ca>] get_page_from_freelist+0x3b2/0x505 [20712.990326] [<ffffffff8109150a>] __alloc_pages_nodemask+0xed/0x65f [20712.990330] [<ffffffff81047a52>] ? ttwu_do_activate.constprop.78+0x57/0x5c [20712.990332] [<ffffffff81049ff3>] ? try_to_wake_up+0x21b/0x22d [20712.990336] [<ffffffff810070f4>] dma_generic_alloc_coherent+0x6e/0xf5 [20712.990339] [<ffffffff810261a9>] gart_alloc_coherent+0x105/0x114 [20712.990341] [<ffffffff81025963>] ? flush_gart+0x39/0x3d [20712.990343] [<ffffffff810260a4>] ? gart_map_sg+0x3a0/0x3a0 [20712.990349] [<ffffffffa0141a1e>] cx23885_risc_databuffer+0xa7/0x133 [cx23885] [20712.990354] [<ffffffffa0142764>] cx23885_buf_prepare+0x121/0x134 [cx23885] [20712.990359] [<ffffffffa0144210>] buffer_prepare+0x14/0x16 [cx23885] [20712.990363] [<ffffffffa011f101>] __buf_prepare+0x190/0x279 [videobuf2_core] [20712.990366] [<ffffffffa011d906>] ? vb2_queue_or_prepare_buf+0xb8/0xc0 [videobuf2_core] [20712.990369] [<ffffffffa011f34b>] vb2_internal_qbuf+0x51/0x1e5 [videobuf2_core] [20712.990372] [<ffffffffa0120537>] vb2_thread+0x199/0x1f6 [videobuf2_core] [20712.990376] [<ffffffffa012039e>] ? vb2_fop_write+0xdf/0xdf [videobuf2_core] [20712.990379] [<ffffffff81043e61>] kthread+0xdf/0xe7 [20712.990381] [<ffffffff81043d82>] ? kthread_create_on_node+0x16d/0x16d [20712.990384] [<ffffffff815bd46c>] ret_from_fork+0x7c/0xb0 [20712.990386] [<ffffffff81043d82>] ? kthread_create_on_node+0x16d/0x16d Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Reported-by: Mariusz Bialonczyk <manio@skyboo.net> Tested-by: Mariusz Bialonczyk <manio@skyboo.net> Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2014-11-21 17:20:56 +08:00
sg = sg_next(sg);
}
if (lpi && line > 0 && !(line % lpi))
sol = RISC_SOL | RISC_IRQ1 | RISC_CNT_INC;
else
sol = RISC_SOL;
if (bpl <= sg_dma_len(sg)-offset) {
/* fits into current chunk */
*(rp++) = cpu_to_le32(RISC_WRITE|sol|RISC_EOL|bpl);
*(rp++) = cpu_to_le32(sg_dma_address(sg)+offset);
*(rp++) = cpu_to_le32(0); /* bits 63-32 */
offset += bpl;
} else {
/* scanline needs to be split */
todo = bpl;
*(rp++) = cpu_to_le32(RISC_WRITE|sol|
(sg_dma_len(sg)-offset));
*(rp++) = cpu_to_le32(sg_dma_address(sg)+offset);
*(rp++) = cpu_to_le32(0); /* bits 63-32 */
todo -= (sg_dma_len(sg)-offset);
offset = 0;
[media] cx23885: use sg = sg_next(sg) instead of sg++ The cx23885 driver still used sg++ instead of sg = sg_next(sg). This worked with vb1 since that filled in the sglist manually, page-by-page, but it fails with vb2 which uses core scatterlist code that can combine contiguous scatterlist entries into one larger entry. This bug led to the following crash as reported by Mariusz: [20712.990258] BUG: Bad page state in process vb2-cx23885[0] pfn:2ca34 [20712.990265] page:ffffea00009c3b60 count:-1 mapcount:0 mapping: (null) index:0x0 [20712.990266] flags: 0x4000000000000000() [20712.990268] page dumped because: nonzero _count [20712.990269] Modules linked in: tun binfmt_misc nf_conntrack_ipv6 nf_defrag_ipv6 ip6table_filter ip6_tables xt_mark xt_REDIRECT xt_limit xt_conntrack xt_nat xt_tcpudp iptable_mangle iptable_nat nf_conntrack_ipv4 nf_defrag_ipv4 nf_nat_ipv4 nf_nat nf_conntrack iptable_filter ip_tables x_tables sit ip_tunnel nvidia(PO) stb6100 stv090x cx88_dvb videobuf_dvb cx88_vp3054_i2c tuner kvm_amd kvm cx8802 k10temp cx8800 cx88xx btcx_risc videobuf_dma_sg videobuf_core usb_storage ds2490 usbhid ftdi_sio cx23885 tveeprom cx2341x videobuf2_dvb videobuf2_core videobuf2_dma_sg videobuf2_memops asus_atk0110 snd_emu10k1 snd_hwdep snd_util_mem snd_ac97_codec ac97_bus snd_rawmidi snd_pcm_oss snd_mixer_oss snd_pcm snd_timer snd w1_therm wire ipv6 [20712.990301] CPU: 2 PID: 26942 Comm: vb2-cx23885[0] Tainted: P B W O 3.18.0-rc5-00001-gb3652d1 #2 [20712.990303] Hardware name: System manufacturer System Product Name/M4A785TD-V EVO, BIOS 2105 07/23/2010 [20712.990305] ffffffff81765734 ffff880137683a78 ffffffff815b6b32 0000000000000006 [20712.990307] ffffea00009c3b60 ffff880137683aa8 ffffffff8108ec27 ffffffff81765712 [20712.990309] ffffffff8189c840 0000000000000246 ffffea00009c3b60 ffff880137683b78 [20712.990312] Call Trace: [20712.990317] [<ffffffff815b6b32>] dump_stack+0x46/0x58 [20712.990321] [<ffffffff8108ec27>] bad_page+0xe9/0x107 [20712.990323] [<ffffffff810912ca>] get_page_from_freelist+0x3b2/0x505 [20712.990326] [<ffffffff8109150a>] __alloc_pages_nodemask+0xed/0x65f [20712.990330] [<ffffffff81047a52>] ? ttwu_do_activate.constprop.78+0x57/0x5c [20712.990332] [<ffffffff81049ff3>] ? try_to_wake_up+0x21b/0x22d [20712.990336] [<ffffffff810070f4>] dma_generic_alloc_coherent+0x6e/0xf5 [20712.990339] [<ffffffff810261a9>] gart_alloc_coherent+0x105/0x114 [20712.990341] [<ffffffff81025963>] ? flush_gart+0x39/0x3d [20712.990343] [<ffffffff810260a4>] ? gart_map_sg+0x3a0/0x3a0 [20712.990349] [<ffffffffa0141a1e>] cx23885_risc_databuffer+0xa7/0x133 [cx23885] [20712.990354] [<ffffffffa0142764>] cx23885_buf_prepare+0x121/0x134 [cx23885] [20712.990359] [<ffffffffa0144210>] buffer_prepare+0x14/0x16 [cx23885] [20712.990363] [<ffffffffa011f101>] __buf_prepare+0x190/0x279 [videobuf2_core] [20712.990366] [<ffffffffa011d906>] ? vb2_queue_or_prepare_buf+0xb8/0xc0 [videobuf2_core] [20712.990369] [<ffffffffa011f34b>] vb2_internal_qbuf+0x51/0x1e5 [videobuf2_core] [20712.990372] [<ffffffffa0120537>] vb2_thread+0x199/0x1f6 [videobuf2_core] [20712.990376] [<ffffffffa012039e>] ? vb2_fop_write+0xdf/0xdf [videobuf2_core] [20712.990379] [<ffffffff81043e61>] kthread+0xdf/0xe7 [20712.990381] [<ffffffff81043d82>] ? kthread_create_on_node+0x16d/0x16d [20712.990384] [<ffffffff815bd46c>] ret_from_fork+0x7c/0xb0 [20712.990386] [<ffffffff81043d82>] ? kthread_create_on_node+0x16d/0x16d Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Reported-by: Mariusz Bialonczyk <manio@skyboo.net> Tested-by: Mariusz Bialonczyk <manio@skyboo.net> Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2014-11-21 17:20:56 +08:00
sg = sg_next(sg);
while (todo > sg_dma_len(sg)) {
*(rp++) = cpu_to_le32(RISC_WRITE|
sg_dma_len(sg));
*(rp++) = cpu_to_le32(sg_dma_address(sg));
*(rp++) = cpu_to_le32(0); /* bits 63-32 */
todo -= sg_dma_len(sg);
[media] cx23885: use sg = sg_next(sg) instead of sg++ The cx23885 driver still used sg++ instead of sg = sg_next(sg). This worked with vb1 since that filled in the sglist manually, page-by-page, but it fails with vb2 which uses core scatterlist code that can combine contiguous scatterlist entries into one larger entry. This bug led to the following crash as reported by Mariusz: [20712.990258] BUG: Bad page state in process vb2-cx23885[0] pfn:2ca34 [20712.990265] page:ffffea00009c3b60 count:-1 mapcount:0 mapping: (null) index:0x0 [20712.990266] flags: 0x4000000000000000() [20712.990268] page dumped because: nonzero _count [20712.990269] Modules linked in: tun binfmt_misc nf_conntrack_ipv6 nf_defrag_ipv6 ip6table_filter ip6_tables xt_mark xt_REDIRECT xt_limit xt_conntrack xt_nat xt_tcpudp iptable_mangle iptable_nat nf_conntrack_ipv4 nf_defrag_ipv4 nf_nat_ipv4 nf_nat nf_conntrack iptable_filter ip_tables x_tables sit ip_tunnel nvidia(PO) stb6100 stv090x cx88_dvb videobuf_dvb cx88_vp3054_i2c tuner kvm_amd kvm cx8802 k10temp cx8800 cx88xx btcx_risc videobuf_dma_sg videobuf_core usb_storage ds2490 usbhid ftdi_sio cx23885 tveeprom cx2341x videobuf2_dvb videobuf2_core videobuf2_dma_sg videobuf2_memops asus_atk0110 snd_emu10k1 snd_hwdep snd_util_mem snd_ac97_codec ac97_bus snd_rawmidi snd_pcm_oss snd_mixer_oss snd_pcm snd_timer snd w1_therm wire ipv6 [20712.990301] CPU: 2 PID: 26942 Comm: vb2-cx23885[0] Tainted: P B W O 3.18.0-rc5-00001-gb3652d1 #2 [20712.990303] Hardware name: System manufacturer System Product Name/M4A785TD-V EVO, BIOS 2105 07/23/2010 [20712.990305] ffffffff81765734 ffff880137683a78 ffffffff815b6b32 0000000000000006 [20712.990307] ffffea00009c3b60 ffff880137683aa8 ffffffff8108ec27 ffffffff81765712 [20712.990309] ffffffff8189c840 0000000000000246 ffffea00009c3b60 ffff880137683b78 [20712.990312] Call Trace: [20712.990317] [<ffffffff815b6b32>] dump_stack+0x46/0x58 [20712.990321] [<ffffffff8108ec27>] bad_page+0xe9/0x107 [20712.990323] [<ffffffff810912ca>] get_page_from_freelist+0x3b2/0x505 [20712.990326] [<ffffffff8109150a>] __alloc_pages_nodemask+0xed/0x65f [20712.990330] [<ffffffff81047a52>] ? ttwu_do_activate.constprop.78+0x57/0x5c [20712.990332] [<ffffffff81049ff3>] ? try_to_wake_up+0x21b/0x22d [20712.990336] [<ffffffff810070f4>] dma_generic_alloc_coherent+0x6e/0xf5 [20712.990339] [<ffffffff810261a9>] gart_alloc_coherent+0x105/0x114 [20712.990341] [<ffffffff81025963>] ? flush_gart+0x39/0x3d [20712.990343] [<ffffffff810260a4>] ? gart_map_sg+0x3a0/0x3a0 [20712.990349] [<ffffffffa0141a1e>] cx23885_risc_databuffer+0xa7/0x133 [cx23885] [20712.990354] [<ffffffffa0142764>] cx23885_buf_prepare+0x121/0x134 [cx23885] [20712.990359] [<ffffffffa0144210>] buffer_prepare+0x14/0x16 [cx23885] [20712.990363] [<ffffffffa011f101>] __buf_prepare+0x190/0x279 [videobuf2_core] [20712.990366] [<ffffffffa011d906>] ? vb2_queue_or_prepare_buf+0xb8/0xc0 [videobuf2_core] [20712.990369] [<ffffffffa011f34b>] vb2_internal_qbuf+0x51/0x1e5 [videobuf2_core] [20712.990372] [<ffffffffa0120537>] vb2_thread+0x199/0x1f6 [videobuf2_core] [20712.990376] [<ffffffffa012039e>] ? vb2_fop_write+0xdf/0xdf [videobuf2_core] [20712.990379] [<ffffffff81043e61>] kthread+0xdf/0xe7 [20712.990381] [<ffffffff81043d82>] ? kthread_create_on_node+0x16d/0x16d [20712.990384] [<ffffffff815bd46c>] ret_from_fork+0x7c/0xb0 [20712.990386] [<ffffffff81043d82>] ? kthread_create_on_node+0x16d/0x16d Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Reported-by: Mariusz Bialonczyk <manio@skyboo.net> Tested-by: Mariusz Bialonczyk <manio@skyboo.net> Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2014-11-21 17:20:56 +08:00
sg = sg_next(sg);
}
*(rp++) = cpu_to_le32(RISC_WRITE|RISC_EOL|todo);
*(rp++) = cpu_to_le32(sg_dma_address(sg));
*(rp++) = cpu_to_le32(0); /* bits 63-32 */
offset += todo;
}
offset += padding;
}
return rp;
}
int cx23885_risc_buffer(struct pci_dev *pci, struct cx23885_riscmem *risc,
struct scatterlist *sglist, unsigned int top_offset,
unsigned int bottom_offset, unsigned int bpl,
unsigned int padding, unsigned int lines)
{
u32 instructions, fields;
__le32 *rp;
fields = 0;
if (UNSET != top_offset)
fields++;
if (UNSET != bottom_offset)
fields++;
/* estimate risc mem: worst case is one write per page border +
one write per scan line + syncs + jump (all 2 dwords). Padding
can cause next bpl to start close to a page border. First DMA
region may be smaller than PAGE_SIZE */
/* write and jump need and extra dword */
instructions = fields * (1 + ((bpl + padding) * lines)
/ PAGE_SIZE + lines);
instructions += 5;
risc->size = instructions * 12;
risc->cpu = pci_alloc_consistent(pci, risc->size, &risc->dma);
if (risc->cpu == NULL)
return -ENOMEM;
/* write risc instructions */
rp = risc->cpu;
if (UNSET != top_offset)
rp = cx23885_risc_field(rp, sglist, top_offset, 0,
bpl, padding, lines, 0, true);
if (UNSET != bottom_offset)
rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x200,
bpl, padding, lines, 0, UNSET == top_offset);
/* save pointer to jmp instruction address */
risc->jmp = rp;
BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
return 0;
}
int cx23885_risc_databuffer(struct pci_dev *pci,
struct cx23885_riscmem *risc,
struct scatterlist *sglist,
unsigned int bpl,
unsigned int lines, unsigned int lpi)
{
u32 instructions;
__le32 *rp;
/* estimate risc mem: worst case is one write per page border +
one write per scan line + syncs + jump (all 2 dwords). Here
there is no padding and no sync. First DMA region may be smaller
than PAGE_SIZE */
/* Jump and write need an extra dword */
instructions = 1 + (bpl * lines) / PAGE_SIZE + lines;
instructions += 4;
risc->size = instructions * 12;
risc->cpu = pci_alloc_consistent(pci, risc->size, &risc->dma);
if (risc->cpu == NULL)
return -ENOMEM;
/* write risc instructions */
rp = risc->cpu;
rp = cx23885_risc_field(rp, sglist, 0, NO_SYNC_LINE,
bpl, 0, lines, lpi, lpi == 0);
/* save pointer to jmp instruction address */
risc->jmp = rp;
BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
return 0;
}
int cx23885_risc_vbibuffer(struct pci_dev *pci, struct cx23885_riscmem *risc,
struct scatterlist *sglist, unsigned int top_offset,
unsigned int bottom_offset, unsigned int bpl,
unsigned int padding, unsigned int lines)
{
u32 instructions, fields;
__le32 *rp;
fields = 0;
if (UNSET != top_offset)
fields++;
if (UNSET != bottom_offset)
fields++;
/* estimate risc mem: worst case is one write per page border +
one write per scan line + syncs + jump (all 2 dwords). Padding
can cause next bpl to start close to a page border. First DMA
region may be smaller than PAGE_SIZE */
/* write and jump need and extra dword */
instructions = fields * (1 + ((bpl + padding) * lines)
/ PAGE_SIZE + lines);
instructions += 5;
risc->size = instructions * 12;
risc->cpu = pci_alloc_consistent(pci, risc->size, &risc->dma);
if (risc->cpu == NULL)
return -ENOMEM;
/* write risc instructions */
rp = risc->cpu;
/* Sync to line 6, so US CC line 21 will appear in line '12'
* in the userland vbi payload */
if (UNSET != top_offset)
rp = cx23885_risc_field(rp, sglist, top_offset, 0,
bpl, padding, lines, 0, true);
if (UNSET != bottom_offset)
rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x200,
bpl, padding, lines, 0, UNSET == top_offset);
/* save pointer to jmp instruction address */
risc->jmp = rp;
BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
return 0;
}
void cx23885_free_buffer(struct cx23885_dev *dev, struct cx23885_buffer *buf)
{
struct cx23885_riscmem *risc = &buf->risc;
BUG_ON(in_interrupt());
pci_free_consistent(dev->pci, risc->size, risc->cpu, risc->dma);
}
static void cx23885_tsport_reg_dump(struct cx23885_tsport *port)
{
struct cx23885_dev *dev = port->dev;
dprintk(1, "%s() Register Dump\n", __func__);
dprintk(1, "%s() DEV_CNTRL2 0x%08X\n", __func__,
cx_read(DEV_CNTRL2));
dprintk(1, "%s() PCI_INT_MSK 0x%08X\n", __func__,
cx23885_irq_get_mask(dev));
dprintk(1, "%s() AUD_INT_INT_MSK 0x%08X\n", __func__,
cx_read(AUDIO_INT_INT_MSK));
dprintk(1, "%s() AUD_INT_DMA_CTL 0x%08X\n", __func__,
cx_read(AUD_INT_DMA_CTL));
dprintk(1, "%s() AUD_EXT_INT_MSK 0x%08X\n", __func__,
cx_read(AUDIO_EXT_INT_MSK));
dprintk(1, "%s() AUD_EXT_DMA_CTL 0x%08X\n", __func__,
cx_read(AUD_EXT_DMA_CTL));
dprintk(1, "%s() PAD_CTRL 0x%08X\n", __func__,
cx_read(PAD_CTRL));
dprintk(1, "%s() ALT_PIN_OUT_SEL 0x%08X\n", __func__,
cx_read(ALT_PIN_OUT_SEL));
dprintk(1, "%s() GPIO2 0x%08X\n", __func__,
cx_read(GPIO2));
dprintk(1, "%s() gpcnt(0x%08X) 0x%08X\n", __func__,
port->reg_gpcnt, cx_read(port->reg_gpcnt));
dprintk(1, "%s() gpcnt_ctl(0x%08X) 0x%08x\n", __func__,
port->reg_gpcnt_ctl, cx_read(port->reg_gpcnt_ctl));
dprintk(1, "%s() dma_ctl(0x%08X) 0x%08x\n", __func__,
port->reg_dma_ctl, cx_read(port->reg_dma_ctl));
if (port->reg_src_sel)
dprintk(1, "%s() src_sel(0x%08X) 0x%08x\n", __func__,
port->reg_src_sel, cx_read(port->reg_src_sel));
dprintk(1, "%s() lngth(0x%08X) 0x%08x\n", __func__,
port->reg_lngth, cx_read(port->reg_lngth));
dprintk(1, "%s() hw_sop_ctrl(0x%08X) 0x%08x\n", __func__,
port->reg_hw_sop_ctrl, cx_read(port->reg_hw_sop_ctrl));
dprintk(1, "%s() gen_ctrl(0x%08X) 0x%08x\n", __func__,
port->reg_gen_ctrl, cx_read(port->reg_gen_ctrl));
dprintk(1, "%s() bd_pkt_status(0x%08X) 0x%08x\n", __func__,
port->reg_bd_pkt_status, cx_read(port->reg_bd_pkt_status));
dprintk(1, "%s() sop_status(0x%08X) 0x%08x\n", __func__,
port->reg_sop_status, cx_read(port->reg_sop_status));
dprintk(1, "%s() fifo_ovfl_stat(0x%08X) 0x%08x\n", __func__,
port->reg_fifo_ovfl_stat, cx_read(port->reg_fifo_ovfl_stat));
dprintk(1, "%s() vld_misc(0x%08X) 0x%08x\n", __func__,
port->reg_vld_misc, cx_read(port->reg_vld_misc));
dprintk(1, "%s() ts_clk_en(0x%08X) 0x%08x\n", __func__,
port->reg_ts_clk_en, cx_read(port->reg_ts_clk_en));
dprintk(1, "%s() ts_int_msk(0x%08X) 0x%08x\n", __func__,
port->reg_ts_int_msk, cx_read(port->reg_ts_int_msk));
dprintk(1, "%s() ts_int_status(0x%08X) 0x%08x\n", __func__,
port->reg_ts_int_stat, cx_read(port->reg_ts_int_stat));
dprintk(1, "%s() PCI_INT_STAT 0x%08X\n", __func__,
cx_read(PCI_INT_STAT));
dprintk(1, "%s() VID_B_INT_MSTAT 0x%08X\n", __func__,
cx_read(VID_B_INT_MSTAT));
dprintk(1, "%s() VID_B_INT_SSTAT 0x%08X\n", __func__,
cx_read(VID_B_INT_SSTAT));
dprintk(1, "%s() VID_C_INT_MSTAT 0x%08X\n", __func__,
cx_read(VID_C_INT_MSTAT));
dprintk(1, "%s() VID_C_INT_SSTAT 0x%08X\n", __func__,
cx_read(VID_C_INT_SSTAT));
}
int cx23885_start_dma(struct cx23885_tsport *port,
struct cx23885_dmaqueue *q,
struct cx23885_buffer *buf)
{
struct cx23885_dev *dev = port->dev;
u32 reg;
dprintk(1, "%s() w: %d, h: %d, f: %d\n", __func__,
dev->width, dev->height, dev->field);
media: cx23885: Ryzen DMA related RiSC engine stall fixes This bug affects all of Hauppauge QuadHD boards when used on all Ryzen platforms and some XEON platforms. On these platforms it is possible to error out the RiSC engine and cause it to stall, whereafter the only way to reset the board to a working state is to reboot. This is the fatal condition with current driver: [ 255.663598] cx23885: cx23885[0]: mpeg risc op code error [ 255.663607] cx23885: cx23885[0]: TS1 B - dma channel status dump [ 255.663612] cx23885: cx23885[0]: cmds: init risc lo : 0xffe54000 [ 255.663615] cx23885: cx23885[0]: cmds: init risc hi : 0x00000000 [ 255.663619] cx23885: cx23885[0]: cmds: cdt base : 0x00010870 [ 255.663622] cx23885: cx23885[0]: cmds: cdt size : 0x0000000a [ 255.663625] cx23885: cx23885[0]: cmds: iq base : 0x00010630 [ 255.663629] cx23885: cx23885[0]: cmds: iq size : 0x00000010 [ 255.663632] cx23885: cx23885[0]: cmds: risc pc lo : 0xffe54018 [ 255.663636] cx23885: cx23885[0]: cmds: risc pc hi : 0x00000000 [ 255.663639] cx23885: cx23885[0]: cmds: iq wr ptr : 0x00004192 [ 255.663642] cx23885: cx23885[0]: cmds: iq rd ptr : 0x0000418c [ 255.663645] cx23885: cx23885[0]: cmds: cdt current : 0x00010898 [ 255.663649] cx23885: cx23885[0]: cmds: pci target lo : 0xf85ca340 [ 255.663652] cx23885: cx23885[0]: cmds: pci target hi : 0x00000000 [ 255.663655] cx23885: cx23885[0]: cmds: line / byte : 0x000c0000 [ 255.663659] cx23885: cx23885[0]: risc0: [ 255.663661] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663666] cx23885: cx23885[0]: risc1: [ 255.663667] 0xf85ca050 [ INVALID sol 22 20 19 18 resync 13 count=80 ] [ 255.663674] cx23885: cx23885[0]: risc2: [ 255.663674] 0x00000000 [ INVALID count=0 ] [ 255.663678] cx23885: cx23885[0]: risc3: [ 255.663679] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663684] cx23885: cx23885[0]: (0x00010630) iq 0: [ 255.663685] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663690] cx23885: cx23885[0]: iq 1: 0xf85ca630 [ arg #1 ] [ 255.663693] cx23885: cx23885[0]: iq 2: 0x00000000 [ arg #2 ] [ 255.663696] cx23885: cx23885[0]: (0x0001063c) iq 3: [ 255.663697] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663702] cx23885: cx23885[0]: iq 4: 0xf85ca920 [ arg #1 ] [ 255.663705] cx23885: cx23885[0]: iq 5: 0x00000000 [ arg #2 ] [ 255.663709] cx23885: cx23885[0]: (0x00010648) iq 6: [ 255.663709] 0xf85ca340 [ INVALID sol 22 20 19 18 resync 13 count=832 ] [ 255.663716] cx23885: cx23885[0]: (0x0001064c) iq 7: [ 255.663717] 0x00000000 [ INVALID count=0 ] [ 255.663721] cx23885: cx23885[0]: (0x00010650) iq 8: [ 255.663721] 0x00000000 [ INVALID count=0 ] [ 255.663725] cx23885: cx23885[0]: (0x00010654) iq 9: [ 255.663726] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663731] cx23885: cx23885[0]: iq a: 0xf85c9780 [ arg #1 ] [ 255.663734] cx23885: cx23885[0]: iq b: 0x00000000 [ arg #2 ] [ 255.663737] cx23885: cx23885[0]: (0x00010660) iq c: [ 255.663738] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663743] cx23885: cx23885[0]: iq d: 0xf85c9a70 [ arg #1 ] [ 255.663746] cx23885: cx23885[0]: iq e: 0x00000000 [ arg #2 ] [ 255.663749] cx23885: cx23885[0]: (0x0001066c) iq f: [ 255.663750] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663755] cx23885: cx23885[0]: iq 10: 0xf4fa2920 [ arg #1 ] [ 255.663758] cx23885: cx23885[0]: iq 11: 0x00000000 [ arg #2 ] [ 255.663759] cx23885: cx23885[0]: fifo: 0x00005000 -> 0x6000 [ 255.663760] cx23885: cx23885[0]: ctrl: 0x00010630 -> 0x10690 [ 255.663764] cx23885: cx23885[0]: ptr1_reg: 0x00005980 [ 255.663767] cx23885: cx23885[0]: ptr2_reg: 0x000108a8 [ 255.663770] cx23885: cx23885[0]: cnt1_reg: 0x0000000b [ 255.663773] cx23885: cx23885[0]: cnt2_reg: 0x00000003 Included is checks of the TC_REQ and TC_REQ_SET registers during states of board initialization, reset, DMA start, and DMA stop. If both registers are set, this indicates a stall in the RiSC engine, at which point the bridge error is cleared. A small delay is introduced in stop_dma as well, to allow transfers in progress to finish. After application all models work on Ryzen, occasionally yielding: cx23885_clear_bridge_error: dma in progress detected 0x00000001 0x00000001, clearing Signed-off-by: Brad Love <brad@nextdimension.cc> Signed-off-by: Hans Verkuil <hansverk@cisco.com> [hansverk@cisco.com: fix compiler warning of unused 'reg' variable] Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
2018-05-09 05:20:18 +08:00
/* clear dma in progress */
cx23885_clear_bridge_error(dev);
/* Stop the fifo and risc engine for this port */
cx_clear(port->reg_dma_ctl, port->dma_ctl_val);
/* setup fifo + format */
cx23885_sram_channel_setup(dev,
&dev->sram_channels[port->sram_chno],
port->ts_packet_size, buf->risc.dma);
if (debug > 5) {
cx23885_sram_channel_dump(dev,
&dev->sram_channels[port->sram_chno]);
cx23885_risc_disasm(port, &buf->risc);
}
/* write TS length to chip */
cx_write(port->reg_lngth, port->ts_packet_size);
if ((!(cx23885_boards[dev->board].portb & CX23885_MPEG_DVB)) &&
(!(cx23885_boards[dev->board].portc & CX23885_MPEG_DVB))) {
pr_err("%s() Unsupported .portb/c (0x%08x)/(0x%08x)\n",
__func__,
cx23885_boards[dev->board].portb,
cx23885_boards[dev->board].portc);
return -EINVAL;
}
if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER)
cx23885_av_clk(dev, 0);
udelay(100);
/* If the port supports SRC SELECT, configure it */
if (port->reg_src_sel)
cx_write(port->reg_src_sel, port->src_sel_val);
cx_write(port->reg_hw_sop_ctrl, port->hw_sop_ctrl_val);
cx_write(port->reg_ts_clk_en, port->ts_clk_en_val);
cx_write(port->reg_vld_misc, port->vld_misc_val);
cx_write(port->reg_gen_ctrl, port->gen_ctrl_val);
udelay(100);
/* NOTE: this is 2 (reserved) for portb, does it matter? */
/* reset counter to zero */
cx_write(port->reg_gpcnt_ctl, 3);
q->count = 0;
/* Set VIDB pins to input */
if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) {
reg = cx_read(PAD_CTRL);
reg &= ~0x3; /* Clear TS1_OE & TS1_SOP_OE */
cx_write(PAD_CTRL, reg);
}
/* Set VIDC pins to input */
if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) {
reg = cx_read(PAD_CTRL);
reg &= ~0x4; /* Clear TS2_SOP_OE */
cx_write(PAD_CTRL, reg);
}
if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) {
reg = cx_read(PAD_CTRL);
reg = reg & ~0x1; /* Clear TS1_OE */
/* FIXME, bit 2 writing here is questionable */
/* set TS1_SOP_OE and TS1_OE_HI */
reg = reg | 0xa;
cx_write(PAD_CTRL, reg);
/* Sets MOE_CLK_DIS to disable MoE clock */
/* sets MCLK_DLY_SEL/BCLK_DLY_SEL to 1 buffer delay each */
cx_write(CLK_DELAY, cx_read(CLK_DELAY) | 0x80000011);
/* ALT_GPIO_ALT_SET: GPIO[0]
* IR_ALT_TX_SEL: GPIO[1]
* GPIO1_ALT_SEL: VIP_656_DATA[0]
* GPIO0_ALT_SEL: VIP_656_CLK
*/
cx_write(ALT_PIN_OUT_SEL, 0x10100045);
}
switch (dev->bridge) {
case CX23885_BRIDGE_885:
case CX23885_BRIDGE_887:
case CX23885_BRIDGE_888:
/* enable irqs */
dprintk(1, "%s() enabling TS int's and DMA\n", __func__);
media: cx23885: Ryzen DMA related RiSC engine stall fixes This bug affects all of Hauppauge QuadHD boards when used on all Ryzen platforms and some XEON platforms. On these platforms it is possible to error out the RiSC engine and cause it to stall, whereafter the only way to reset the board to a working state is to reboot. This is the fatal condition with current driver: [ 255.663598] cx23885: cx23885[0]: mpeg risc op code error [ 255.663607] cx23885: cx23885[0]: TS1 B - dma channel status dump [ 255.663612] cx23885: cx23885[0]: cmds: init risc lo : 0xffe54000 [ 255.663615] cx23885: cx23885[0]: cmds: init risc hi : 0x00000000 [ 255.663619] cx23885: cx23885[0]: cmds: cdt base : 0x00010870 [ 255.663622] cx23885: cx23885[0]: cmds: cdt size : 0x0000000a [ 255.663625] cx23885: cx23885[0]: cmds: iq base : 0x00010630 [ 255.663629] cx23885: cx23885[0]: cmds: iq size : 0x00000010 [ 255.663632] cx23885: cx23885[0]: cmds: risc pc lo : 0xffe54018 [ 255.663636] cx23885: cx23885[0]: cmds: risc pc hi : 0x00000000 [ 255.663639] cx23885: cx23885[0]: cmds: iq wr ptr : 0x00004192 [ 255.663642] cx23885: cx23885[0]: cmds: iq rd ptr : 0x0000418c [ 255.663645] cx23885: cx23885[0]: cmds: cdt current : 0x00010898 [ 255.663649] cx23885: cx23885[0]: cmds: pci target lo : 0xf85ca340 [ 255.663652] cx23885: cx23885[0]: cmds: pci target hi : 0x00000000 [ 255.663655] cx23885: cx23885[0]: cmds: line / byte : 0x000c0000 [ 255.663659] cx23885: cx23885[0]: risc0: [ 255.663661] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663666] cx23885: cx23885[0]: risc1: [ 255.663667] 0xf85ca050 [ INVALID sol 22 20 19 18 resync 13 count=80 ] [ 255.663674] cx23885: cx23885[0]: risc2: [ 255.663674] 0x00000000 [ INVALID count=0 ] [ 255.663678] cx23885: cx23885[0]: risc3: [ 255.663679] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663684] cx23885: cx23885[0]: (0x00010630) iq 0: [ 255.663685] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663690] cx23885: cx23885[0]: iq 1: 0xf85ca630 [ arg #1 ] [ 255.663693] cx23885: cx23885[0]: iq 2: 0x00000000 [ arg #2 ] [ 255.663696] cx23885: cx23885[0]: (0x0001063c) iq 3: [ 255.663697] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663702] cx23885: cx23885[0]: iq 4: 0xf85ca920 [ arg #1 ] [ 255.663705] cx23885: cx23885[0]: iq 5: 0x00000000 [ arg #2 ] [ 255.663709] cx23885: cx23885[0]: (0x00010648) iq 6: [ 255.663709] 0xf85ca340 [ INVALID sol 22 20 19 18 resync 13 count=832 ] [ 255.663716] cx23885: cx23885[0]: (0x0001064c) iq 7: [ 255.663717] 0x00000000 [ INVALID count=0 ] [ 255.663721] cx23885: cx23885[0]: (0x00010650) iq 8: [ 255.663721] 0x00000000 [ INVALID count=0 ] [ 255.663725] cx23885: cx23885[0]: (0x00010654) iq 9: [ 255.663726] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663731] cx23885: cx23885[0]: iq a: 0xf85c9780 [ arg #1 ] [ 255.663734] cx23885: cx23885[0]: iq b: 0x00000000 [ arg #2 ] [ 255.663737] cx23885: cx23885[0]: (0x00010660) iq c: [ 255.663738] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663743] cx23885: cx23885[0]: iq d: 0xf85c9a70 [ arg #1 ] [ 255.663746] cx23885: cx23885[0]: iq e: 0x00000000 [ arg #2 ] [ 255.663749] cx23885: cx23885[0]: (0x0001066c) iq f: [ 255.663750] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663755] cx23885: cx23885[0]: iq 10: 0xf4fa2920 [ arg #1 ] [ 255.663758] cx23885: cx23885[0]: iq 11: 0x00000000 [ arg #2 ] [ 255.663759] cx23885: cx23885[0]: fifo: 0x00005000 -> 0x6000 [ 255.663760] cx23885: cx23885[0]: ctrl: 0x00010630 -> 0x10690 [ 255.663764] cx23885: cx23885[0]: ptr1_reg: 0x00005980 [ 255.663767] cx23885: cx23885[0]: ptr2_reg: 0x000108a8 [ 255.663770] cx23885: cx23885[0]: cnt1_reg: 0x0000000b [ 255.663773] cx23885: cx23885[0]: cnt2_reg: 0x00000003 Included is checks of the TC_REQ and TC_REQ_SET registers during states of board initialization, reset, DMA start, and DMA stop. If both registers are set, this indicates a stall in the RiSC engine, at which point the bridge error is cleared. A small delay is introduced in stop_dma as well, to allow transfers in progress to finish. After application all models work on Ryzen, occasionally yielding: cx23885_clear_bridge_error: dma in progress detected 0x00000001 0x00000001, clearing Signed-off-by: Brad Love <brad@nextdimension.cc> Signed-off-by: Hans Verkuil <hansverk@cisco.com> [hansverk@cisco.com: fix compiler warning of unused 'reg' variable] Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
2018-05-09 05:20:18 +08:00
/* clear dma in progress */
cx23885_clear_bridge_error(dev);
cx_set(port->reg_ts_int_msk, port->ts_int_msk_val);
cx_set(port->reg_dma_ctl, port->dma_ctl_val);
media: cx23885: Ryzen DMA related RiSC engine stall fixes This bug affects all of Hauppauge QuadHD boards when used on all Ryzen platforms and some XEON platforms. On these platforms it is possible to error out the RiSC engine and cause it to stall, whereafter the only way to reset the board to a working state is to reboot. This is the fatal condition with current driver: [ 255.663598] cx23885: cx23885[0]: mpeg risc op code error [ 255.663607] cx23885: cx23885[0]: TS1 B - dma channel status dump [ 255.663612] cx23885: cx23885[0]: cmds: init risc lo : 0xffe54000 [ 255.663615] cx23885: cx23885[0]: cmds: init risc hi : 0x00000000 [ 255.663619] cx23885: cx23885[0]: cmds: cdt base : 0x00010870 [ 255.663622] cx23885: cx23885[0]: cmds: cdt size : 0x0000000a [ 255.663625] cx23885: cx23885[0]: cmds: iq base : 0x00010630 [ 255.663629] cx23885: cx23885[0]: cmds: iq size : 0x00000010 [ 255.663632] cx23885: cx23885[0]: cmds: risc pc lo : 0xffe54018 [ 255.663636] cx23885: cx23885[0]: cmds: risc pc hi : 0x00000000 [ 255.663639] cx23885: cx23885[0]: cmds: iq wr ptr : 0x00004192 [ 255.663642] cx23885: cx23885[0]: cmds: iq rd ptr : 0x0000418c [ 255.663645] cx23885: cx23885[0]: cmds: cdt current : 0x00010898 [ 255.663649] cx23885: cx23885[0]: cmds: pci target lo : 0xf85ca340 [ 255.663652] cx23885: cx23885[0]: cmds: pci target hi : 0x00000000 [ 255.663655] cx23885: cx23885[0]: cmds: line / byte : 0x000c0000 [ 255.663659] cx23885: cx23885[0]: risc0: [ 255.663661] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663666] cx23885: cx23885[0]: risc1: [ 255.663667] 0xf85ca050 [ INVALID sol 22 20 19 18 resync 13 count=80 ] [ 255.663674] cx23885: cx23885[0]: risc2: [ 255.663674] 0x00000000 [ INVALID count=0 ] [ 255.663678] cx23885: cx23885[0]: risc3: [ 255.663679] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663684] cx23885: cx23885[0]: (0x00010630) iq 0: [ 255.663685] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663690] cx23885: cx23885[0]: iq 1: 0xf85ca630 [ arg #1 ] [ 255.663693] cx23885: cx23885[0]: iq 2: 0x00000000 [ arg #2 ] [ 255.663696] cx23885: cx23885[0]: (0x0001063c) iq 3: [ 255.663697] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663702] cx23885: cx23885[0]: iq 4: 0xf85ca920 [ arg #1 ] [ 255.663705] cx23885: cx23885[0]: iq 5: 0x00000000 [ arg #2 ] [ 255.663709] cx23885: cx23885[0]: (0x00010648) iq 6: [ 255.663709] 0xf85ca340 [ INVALID sol 22 20 19 18 resync 13 count=832 ] [ 255.663716] cx23885: cx23885[0]: (0x0001064c) iq 7: [ 255.663717] 0x00000000 [ INVALID count=0 ] [ 255.663721] cx23885: cx23885[0]: (0x00010650) iq 8: [ 255.663721] 0x00000000 [ INVALID count=0 ] [ 255.663725] cx23885: cx23885[0]: (0x00010654) iq 9: [ 255.663726] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663731] cx23885: cx23885[0]: iq a: 0xf85c9780 [ arg #1 ] [ 255.663734] cx23885: cx23885[0]: iq b: 0x00000000 [ arg #2 ] [ 255.663737] cx23885: cx23885[0]: (0x00010660) iq c: [ 255.663738] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663743] cx23885: cx23885[0]: iq d: 0xf85c9a70 [ arg #1 ] [ 255.663746] cx23885: cx23885[0]: iq e: 0x00000000 [ arg #2 ] [ 255.663749] cx23885: cx23885[0]: (0x0001066c) iq f: [ 255.663750] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663755] cx23885: cx23885[0]: iq 10: 0xf4fa2920 [ arg #1 ] [ 255.663758] cx23885: cx23885[0]: iq 11: 0x00000000 [ arg #2 ] [ 255.663759] cx23885: cx23885[0]: fifo: 0x00005000 -> 0x6000 [ 255.663760] cx23885: cx23885[0]: ctrl: 0x00010630 -> 0x10690 [ 255.663764] cx23885: cx23885[0]: ptr1_reg: 0x00005980 [ 255.663767] cx23885: cx23885[0]: ptr2_reg: 0x000108a8 [ 255.663770] cx23885: cx23885[0]: cnt1_reg: 0x0000000b [ 255.663773] cx23885: cx23885[0]: cnt2_reg: 0x00000003 Included is checks of the TC_REQ and TC_REQ_SET registers during states of board initialization, reset, DMA start, and DMA stop. If both registers are set, this indicates a stall in the RiSC engine, at which point the bridge error is cleared. A small delay is introduced in stop_dma as well, to allow transfers in progress to finish. After application all models work on Ryzen, occasionally yielding: cx23885_clear_bridge_error: dma in progress detected 0x00000001 0x00000001, clearing Signed-off-by: Brad Love <brad@nextdimension.cc> Signed-off-by: Hans Verkuil <hansverk@cisco.com> [hansverk@cisco.com: fix compiler warning of unused 'reg' variable] Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
2018-05-09 05:20:18 +08:00
/* clear dma in progress */
cx23885_clear_bridge_error(dev);
cx23885_irq_add(dev, port->pci_irqmask);
cx23885_irq_enable_all(dev);
media: cx23885: Ryzen DMA related RiSC engine stall fixes This bug affects all of Hauppauge QuadHD boards when used on all Ryzen platforms and some XEON platforms. On these platforms it is possible to error out the RiSC engine and cause it to stall, whereafter the only way to reset the board to a working state is to reboot. This is the fatal condition with current driver: [ 255.663598] cx23885: cx23885[0]: mpeg risc op code error [ 255.663607] cx23885: cx23885[0]: TS1 B - dma channel status dump [ 255.663612] cx23885: cx23885[0]: cmds: init risc lo : 0xffe54000 [ 255.663615] cx23885: cx23885[0]: cmds: init risc hi : 0x00000000 [ 255.663619] cx23885: cx23885[0]: cmds: cdt base : 0x00010870 [ 255.663622] cx23885: cx23885[0]: cmds: cdt size : 0x0000000a [ 255.663625] cx23885: cx23885[0]: cmds: iq base : 0x00010630 [ 255.663629] cx23885: cx23885[0]: cmds: iq size : 0x00000010 [ 255.663632] cx23885: cx23885[0]: cmds: risc pc lo : 0xffe54018 [ 255.663636] cx23885: cx23885[0]: cmds: risc pc hi : 0x00000000 [ 255.663639] cx23885: cx23885[0]: cmds: iq wr ptr : 0x00004192 [ 255.663642] cx23885: cx23885[0]: cmds: iq rd ptr : 0x0000418c [ 255.663645] cx23885: cx23885[0]: cmds: cdt current : 0x00010898 [ 255.663649] cx23885: cx23885[0]: cmds: pci target lo : 0xf85ca340 [ 255.663652] cx23885: cx23885[0]: cmds: pci target hi : 0x00000000 [ 255.663655] cx23885: cx23885[0]: cmds: line / byte : 0x000c0000 [ 255.663659] cx23885: cx23885[0]: risc0: [ 255.663661] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663666] cx23885: cx23885[0]: risc1: [ 255.663667] 0xf85ca050 [ INVALID sol 22 20 19 18 resync 13 count=80 ] [ 255.663674] cx23885: cx23885[0]: risc2: [ 255.663674] 0x00000000 [ INVALID count=0 ] [ 255.663678] cx23885: cx23885[0]: risc3: [ 255.663679] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663684] cx23885: cx23885[0]: (0x00010630) iq 0: [ 255.663685] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663690] cx23885: cx23885[0]: iq 1: 0xf85ca630 [ arg #1 ] [ 255.663693] cx23885: cx23885[0]: iq 2: 0x00000000 [ arg #2 ] [ 255.663696] cx23885: cx23885[0]: (0x0001063c) iq 3: [ 255.663697] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663702] cx23885: cx23885[0]: iq 4: 0xf85ca920 [ arg #1 ] [ 255.663705] cx23885: cx23885[0]: iq 5: 0x00000000 [ arg #2 ] [ 255.663709] cx23885: cx23885[0]: (0x00010648) iq 6: [ 255.663709] 0xf85ca340 [ INVALID sol 22 20 19 18 resync 13 count=832 ] [ 255.663716] cx23885: cx23885[0]: (0x0001064c) iq 7: [ 255.663717] 0x00000000 [ INVALID count=0 ] [ 255.663721] cx23885: cx23885[0]: (0x00010650) iq 8: [ 255.663721] 0x00000000 [ INVALID count=0 ] [ 255.663725] cx23885: cx23885[0]: (0x00010654) iq 9: [ 255.663726] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663731] cx23885: cx23885[0]: iq a: 0xf85c9780 [ arg #1 ] [ 255.663734] cx23885: cx23885[0]: iq b: 0x00000000 [ arg #2 ] [ 255.663737] cx23885: cx23885[0]: (0x00010660) iq c: [ 255.663738] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663743] cx23885: cx23885[0]: iq d: 0xf85c9a70 [ arg #1 ] [ 255.663746] cx23885: cx23885[0]: iq e: 0x00000000 [ arg #2 ] [ 255.663749] cx23885: cx23885[0]: (0x0001066c) iq f: [ 255.663750] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663755] cx23885: cx23885[0]: iq 10: 0xf4fa2920 [ arg #1 ] [ 255.663758] cx23885: cx23885[0]: iq 11: 0x00000000 [ arg #2 ] [ 255.663759] cx23885: cx23885[0]: fifo: 0x00005000 -> 0x6000 [ 255.663760] cx23885: cx23885[0]: ctrl: 0x00010630 -> 0x10690 [ 255.663764] cx23885: cx23885[0]: ptr1_reg: 0x00005980 [ 255.663767] cx23885: cx23885[0]: ptr2_reg: 0x000108a8 [ 255.663770] cx23885: cx23885[0]: cnt1_reg: 0x0000000b [ 255.663773] cx23885: cx23885[0]: cnt2_reg: 0x00000003 Included is checks of the TC_REQ and TC_REQ_SET registers during states of board initialization, reset, DMA start, and DMA stop. If both registers are set, this indicates a stall in the RiSC engine, at which point the bridge error is cleared. A small delay is introduced in stop_dma as well, to allow transfers in progress to finish. After application all models work on Ryzen, occasionally yielding: cx23885_clear_bridge_error: dma in progress detected 0x00000001 0x00000001, clearing Signed-off-by: Brad Love <brad@nextdimension.cc> Signed-off-by: Hans Verkuil <hansverk@cisco.com> [hansverk@cisco.com: fix compiler warning of unused 'reg' variable] Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
2018-05-09 05:20:18 +08:00
/* clear dma in progress */
cx23885_clear_bridge_error(dev);
break;
default:
BUG();
}
cx_set(DEV_CNTRL2, (1<<5)); /* Enable RISC controller */
media: cx23885: Ryzen DMA related RiSC engine stall fixes This bug affects all of Hauppauge QuadHD boards when used on all Ryzen platforms and some XEON platforms. On these platforms it is possible to error out the RiSC engine and cause it to stall, whereafter the only way to reset the board to a working state is to reboot. This is the fatal condition with current driver: [ 255.663598] cx23885: cx23885[0]: mpeg risc op code error [ 255.663607] cx23885: cx23885[0]: TS1 B - dma channel status dump [ 255.663612] cx23885: cx23885[0]: cmds: init risc lo : 0xffe54000 [ 255.663615] cx23885: cx23885[0]: cmds: init risc hi : 0x00000000 [ 255.663619] cx23885: cx23885[0]: cmds: cdt base : 0x00010870 [ 255.663622] cx23885: cx23885[0]: cmds: cdt size : 0x0000000a [ 255.663625] cx23885: cx23885[0]: cmds: iq base : 0x00010630 [ 255.663629] cx23885: cx23885[0]: cmds: iq size : 0x00000010 [ 255.663632] cx23885: cx23885[0]: cmds: risc pc lo : 0xffe54018 [ 255.663636] cx23885: cx23885[0]: cmds: risc pc hi : 0x00000000 [ 255.663639] cx23885: cx23885[0]: cmds: iq wr ptr : 0x00004192 [ 255.663642] cx23885: cx23885[0]: cmds: iq rd ptr : 0x0000418c [ 255.663645] cx23885: cx23885[0]: cmds: cdt current : 0x00010898 [ 255.663649] cx23885: cx23885[0]: cmds: pci target lo : 0xf85ca340 [ 255.663652] cx23885: cx23885[0]: cmds: pci target hi : 0x00000000 [ 255.663655] cx23885: cx23885[0]: cmds: line / byte : 0x000c0000 [ 255.663659] cx23885: cx23885[0]: risc0: [ 255.663661] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663666] cx23885: cx23885[0]: risc1: [ 255.663667] 0xf85ca050 [ INVALID sol 22 20 19 18 resync 13 count=80 ] [ 255.663674] cx23885: cx23885[0]: risc2: [ 255.663674] 0x00000000 [ INVALID count=0 ] [ 255.663678] cx23885: cx23885[0]: risc3: [ 255.663679] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663684] cx23885: cx23885[0]: (0x00010630) iq 0: [ 255.663685] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663690] cx23885: cx23885[0]: iq 1: 0xf85ca630 [ arg #1 ] [ 255.663693] cx23885: cx23885[0]: iq 2: 0x00000000 [ arg #2 ] [ 255.663696] cx23885: cx23885[0]: (0x0001063c) iq 3: [ 255.663697] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663702] cx23885: cx23885[0]: iq 4: 0xf85ca920 [ arg #1 ] [ 255.663705] cx23885: cx23885[0]: iq 5: 0x00000000 [ arg #2 ] [ 255.663709] cx23885: cx23885[0]: (0x00010648) iq 6: [ 255.663709] 0xf85ca340 [ INVALID sol 22 20 19 18 resync 13 count=832 ] [ 255.663716] cx23885: cx23885[0]: (0x0001064c) iq 7: [ 255.663717] 0x00000000 [ INVALID count=0 ] [ 255.663721] cx23885: cx23885[0]: (0x00010650) iq 8: [ 255.663721] 0x00000000 [ INVALID count=0 ] [ 255.663725] cx23885: cx23885[0]: (0x00010654) iq 9: [ 255.663726] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663731] cx23885: cx23885[0]: iq a: 0xf85c9780 [ arg #1 ] [ 255.663734] cx23885: cx23885[0]: iq b: 0x00000000 [ arg #2 ] [ 255.663737] cx23885: cx23885[0]: (0x00010660) iq c: [ 255.663738] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663743] cx23885: cx23885[0]: iq d: 0xf85c9a70 [ arg #1 ] [ 255.663746] cx23885: cx23885[0]: iq e: 0x00000000 [ arg #2 ] [ 255.663749] cx23885: cx23885[0]: (0x0001066c) iq f: [ 255.663750] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663755] cx23885: cx23885[0]: iq 10: 0xf4fa2920 [ arg #1 ] [ 255.663758] cx23885: cx23885[0]: iq 11: 0x00000000 [ arg #2 ] [ 255.663759] cx23885: cx23885[0]: fifo: 0x00005000 -> 0x6000 [ 255.663760] cx23885: cx23885[0]: ctrl: 0x00010630 -> 0x10690 [ 255.663764] cx23885: cx23885[0]: ptr1_reg: 0x00005980 [ 255.663767] cx23885: cx23885[0]: ptr2_reg: 0x000108a8 [ 255.663770] cx23885: cx23885[0]: cnt1_reg: 0x0000000b [ 255.663773] cx23885: cx23885[0]: cnt2_reg: 0x00000003 Included is checks of the TC_REQ and TC_REQ_SET registers during states of board initialization, reset, DMA start, and DMA stop. If both registers are set, this indicates a stall in the RiSC engine, at which point the bridge error is cleared. A small delay is introduced in stop_dma as well, to allow transfers in progress to finish. After application all models work on Ryzen, occasionally yielding: cx23885_clear_bridge_error: dma in progress detected 0x00000001 0x00000001, clearing Signed-off-by: Brad Love <brad@nextdimension.cc> Signed-off-by: Hans Verkuil <hansverk@cisco.com> [hansverk@cisco.com: fix compiler warning of unused 'reg' variable] Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
2018-05-09 05:20:18 +08:00
/* clear dma in progress */
cx23885_clear_bridge_error(dev);
if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER)
cx23885_av_clk(dev, 1);
if (debug > 4)
cx23885_tsport_reg_dump(port);
media: cx23885: Ryzen DMA related RiSC engine stall fixes This bug affects all of Hauppauge QuadHD boards when used on all Ryzen platforms and some XEON platforms. On these platforms it is possible to error out the RiSC engine and cause it to stall, whereafter the only way to reset the board to a working state is to reboot. This is the fatal condition with current driver: [ 255.663598] cx23885: cx23885[0]: mpeg risc op code error [ 255.663607] cx23885: cx23885[0]: TS1 B - dma channel status dump [ 255.663612] cx23885: cx23885[0]: cmds: init risc lo : 0xffe54000 [ 255.663615] cx23885: cx23885[0]: cmds: init risc hi : 0x00000000 [ 255.663619] cx23885: cx23885[0]: cmds: cdt base : 0x00010870 [ 255.663622] cx23885: cx23885[0]: cmds: cdt size : 0x0000000a [ 255.663625] cx23885: cx23885[0]: cmds: iq base : 0x00010630 [ 255.663629] cx23885: cx23885[0]: cmds: iq size : 0x00000010 [ 255.663632] cx23885: cx23885[0]: cmds: risc pc lo : 0xffe54018 [ 255.663636] cx23885: cx23885[0]: cmds: risc pc hi : 0x00000000 [ 255.663639] cx23885: cx23885[0]: cmds: iq wr ptr : 0x00004192 [ 255.663642] cx23885: cx23885[0]: cmds: iq rd ptr : 0x0000418c [ 255.663645] cx23885: cx23885[0]: cmds: cdt current : 0x00010898 [ 255.663649] cx23885: cx23885[0]: cmds: pci target lo : 0xf85ca340 [ 255.663652] cx23885: cx23885[0]: cmds: pci target hi : 0x00000000 [ 255.663655] cx23885: cx23885[0]: cmds: line / byte : 0x000c0000 [ 255.663659] cx23885: cx23885[0]: risc0: [ 255.663661] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663666] cx23885: cx23885[0]: risc1: [ 255.663667] 0xf85ca050 [ INVALID sol 22 20 19 18 resync 13 count=80 ] [ 255.663674] cx23885: cx23885[0]: risc2: [ 255.663674] 0x00000000 [ INVALID count=0 ] [ 255.663678] cx23885: cx23885[0]: risc3: [ 255.663679] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663684] cx23885: cx23885[0]: (0x00010630) iq 0: [ 255.663685] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663690] cx23885: cx23885[0]: iq 1: 0xf85ca630 [ arg #1 ] [ 255.663693] cx23885: cx23885[0]: iq 2: 0x00000000 [ arg #2 ] [ 255.663696] cx23885: cx23885[0]: (0x0001063c) iq 3: [ 255.663697] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663702] cx23885: cx23885[0]: iq 4: 0xf85ca920 [ arg #1 ] [ 255.663705] cx23885: cx23885[0]: iq 5: 0x00000000 [ arg #2 ] [ 255.663709] cx23885: cx23885[0]: (0x00010648) iq 6: [ 255.663709] 0xf85ca340 [ INVALID sol 22 20 19 18 resync 13 count=832 ] [ 255.663716] cx23885: cx23885[0]: (0x0001064c) iq 7: [ 255.663717] 0x00000000 [ INVALID count=0 ] [ 255.663721] cx23885: cx23885[0]: (0x00010650) iq 8: [ 255.663721] 0x00000000 [ INVALID count=0 ] [ 255.663725] cx23885: cx23885[0]: (0x00010654) iq 9: [ 255.663726] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663731] cx23885: cx23885[0]: iq a: 0xf85c9780 [ arg #1 ] [ 255.663734] cx23885: cx23885[0]: iq b: 0x00000000 [ arg #2 ] [ 255.663737] cx23885: cx23885[0]: (0x00010660) iq c: [ 255.663738] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663743] cx23885: cx23885[0]: iq d: 0xf85c9a70 [ arg #1 ] [ 255.663746] cx23885: cx23885[0]: iq e: 0x00000000 [ arg #2 ] [ 255.663749] cx23885: cx23885[0]: (0x0001066c) iq f: [ 255.663750] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663755] cx23885: cx23885[0]: iq 10: 0xf4fa2920 [ arg #1 ] [ 255.663758] cx23885: cx23885[0]: iq 11: 0x00000000 [ arg #2 ] [ 255.663759] cx23885: cx23885[0]: fifo: 0x00005000 -> 0x6000 [ 255.663760] cx23885: cx23885[0]: ctrl: 0x00010630 -> 0x10690 [ 255.663764] cx23885: cx23885[0]: ptr1_reg: 0x00005980 [ 255.663767] cx23885: cx23885[0]: ptr2_reg: 0x000108a8 [ 255.663770] cx23885: cx23885[0]: cnt1_reg: 0x0000000b [ 255.663773] cx23885: cx23885[0]: cnt2_reg: 0x00000003 Included is checks of the TC_REQ and TC_REQ_SET registers during states of board initialization, reset, DMA start, and DMA stop. If both registers are set, this indicates a stall in the RiSC engine, at which point the bridge error is cleared. A small delay is introduced in stop_dma as well, to allow transfers in progress to finish. After application all models work on Ryzen, occasionally yielding: cx23885_clear_bridge_error: dma in progress detected 0x00000001 0x00000001, clearing Signed-off-by: Brad Love <brad@nextdimension.cc> Signed-off-by: Hans Verkuil <hansverk@cisco.com> [hansverk@cisco.com: fix compiler warning of unused 'reg' variable] Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
2018-05-09 05:20:18 +08:00
cx23885_irq_get_mask(dev);
/* clear dma in progress */
cx23885_clear_bridge_error(dev);
return 0;
}
static int cx23885_stop_dma(struct cx23885_tsport *port)
{
struct cx23885_dev *dev = port->dev;
u32 reg;
media: cx23885: Ryzen DMA related RiSC engine stall fixes This bug affects all of Hauppauge QuadHD boards when used on all Ryzen platforms and some XEON platforms. On these platforms it is possible to error out the RiSC engine and cause it to stall, whereafter the only way to reset the board to a working state is to reboot. This is the fatal condition with current driver: [ 255.663598] cx23885: cx23885[0]: mpeg risc op code error [ 255.663607] cx23885: cx23885[0]: TS1 B - dma channel status dump [ 255.663612] cx23885: cx23885[0]: cmds: init risc lo : 0xffe54000 [ 255.663615] cx23885: cx23885[0]: cmds: init risc hi : 0x00000000 [ 255.663619] cx23885: cx23885[0]: cmds: cdt base : 0x00010870 [ 255.663622] cx23885: cx23885[0]: cmds: cdt size : 0x0000000a [ 255.663625] cx23885: cx23885[0]: cmds: iq base : 0x00010630 [ 255.663629] cx23885: cx23885[0]: cmds: iq size : 0x00000010 [ 255.663632] cx23885: cx23885[0]: cmds: risc pc lo : 0xffe54018 [ 255.663636] cx23885: cx23885[0]: cmds: risc pc hi : 0x00000000 [ 255.663639] cx23885: cx23885[0]: cmds: iq wr ptr : 0x00004192 [ 255.663642] cx23885: cx23885[0]: cmds: iq rd ptr : 0x0000418c [ 255.663645] cx23885: cx23885[0]: cmds: cdt current : 0x00010898 [ 255.663649] cx23885: cx23885[0]: cmds: pci target lo : 0xf85ca340 [ 255.663652] cx23885: cx23885[0]: cmds: pci target hi : 0x00000000 [ 255.663655] cx23885: cx23885[0]: cmds: line / byte : 0x000c0000 [ 255.663659] cx23885: cx23885[0]: risc0: [ 255.663661] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663666] cx23885: cx23885[0]: risc1: [ 255.663667] 0xf85ca050 [ INVALID sol 22 20 19 18 resync 13 count=80 ] [ 255.663674] cx23885: cx23885[0]: risc2: [ 255.663674] 0x00000000 [ INVALID count=0 ] [ 255.663678] cx23885: cx23885[0]: risc3: [ 255.663679] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663684] cx23885: cx23885[0]: (0x00010630) iq 0: [ 255.663685] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663690] cx23885: cx23885[0]: iq 1: 0xf85ca630 [ arg #1 ] [ 255.663693] cx23885: cx23885[0]: iq 2: 0x00000000 [ arg #2 ] [ 255.663696] cx23885: cx23885[0]: (0x0001063c) iq 3: [ 255.663697] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663702] cx23885: cx23885[0]: iq 4: 0xf85ca920 [ arg #1 ] [ 255.663705] cx23885: cx23885[0]: iq 5: 0x00000000 [ arg #2 ] [ 255.663709] cx23885: cx23885[0]: (0x00010648) iq 6: [ 255.663709] 0xf85ca340 [ INVALID sol 22 20 19 18 resync 13 count=832 ] [ 255.663716] cx23885: cx23885[0]: (0x0001064c) iq 7: [ 255.663717] 0x00000000 [ INVALID count=0 ] [ 255.663721] cx23885: cx23885[0]: (0x00010650) iq 8: [ 255.663721] 0x00000000 [ INVALID count=0 ] [ 255.663725] cx23885: cx23885[0]: (0x00010654) iq 9: [ 255.663726] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663731] cx23885: cx23885[0]: iq a: 0xf85c9780 [ arg #1 ] [ 255.663734] cx23885: cx23885[0]: iq b: 0x00000000 [ arg #2 ] [ 255.663737] cx23885: cx23885[0]: (0x00010660) iq c: [ 255.663738] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663743] cx23885: cx23885[0]: iq d: 0xf85c9a70 [ arg #1 ] [ 255.663746] cx23885: cx23885[0]: iq e: 0x00000000 [ arg #2 ] [ 255.663749] cx23885: cx23885[0]: (0x0001066c) iq f: [ 255.663750] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663755] cx23885: cx23885[0]: iq 10: 0xf4fa2920 [ arg #1 ] [ 255.663758] cx23885: cx23885[0]: iq 11: 0x00000000 [ arg #2 ] [ 255.663759] cx23885: cx23885[0]: fifo: 0x00005000 -> 0x6000 [ 255.663760] cx23885: cx23885[0]: ctrl: 0x00010630 -> 0x10690 [ 255.663764] cx23885: cx23885[0]: ptr1_reg: 0x00005980 [ 255.663767] cx23885: cx23885[0]: ptr2_reg: 0x000108a8 [ 255.663770] cx23885: cx23885[0]: cnt1_reg: 0x0000000b [ 255.663773] cx23885: cx23885[0]: cnt2_reg: 0x00000003 Included is checks of the TC_REQ and TC_REQ_SET registers during states of board initialization, reset, DMA start, and DMA stop. If both registers are set, this indicates a stall in the RiSC engine, at which point the bridge error is cleared. A small delay is introduced in stop_dma as well, to allow transfers in progress to finish. After application all models work on Ryzen, occasionally yielding: cx23885_clear_bridge_error: dma in progress detected 0x00000001 0x00000001, clearing Signed-off-by: Brad Love <brad@nextdimension.cc> Signed-off-by: Hans Verkuil <hansverk@cisco.com> [hansverk@cisco.com: fix compiler warning of unused 'reg' variable] Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
2018-05-09 05:20:18 +08:00
int delay = 0;
uint32_t reg1_val;
uint32_t reg2_val;
dprintk(1, "%s()\n", __func__);
/* Stop interrupts and DMA */
cx_clear(port->reg_ts_int_msk, port->ts_int_msk_val);
cx_clear(port->reg_dma_ctl, port->dma_ctl_val);
media: cx23885: Ryzen DMA related RiSC engine stall fixes This bug affects all of Hauppauge QuadHD boards when used on all Ryzen platforms and some XEON platforms. On these platforms it is possible to error out the RiSC engine and cause it to stall, whereafter the only way to reset the board to a working state is to reboot. This is the fatal condition with current driver: [ 255.663598] cx23885: cx23885[0]: mpeg risc op code error [ 255.663607] cx23885: cx23885[0]: TS1 B - dma channel status dump [ 255.663612] cx23885: cx23885[0]: cmds: init risc lo : 0xffe54000 [ 255.663615] cx23885: cx23885[0]: cmds: init risc hi : 0x00000000 [ 255.663619] cx23885: cx23885[0]: cmds: cdt base : 0x00010870 [ 255.663622] cx23885: cx23885[0]: cmds: cdt size : 0x0000000a [ 255.663625] cx23885: cx23885[0]: cmds: iq base : 0x00010630 [ 255.663629] cx23885: cx23885[0]: cmds: iq size : 0x00000010 [ 255.663632] cx23885: cx23885[0]: cmds: risc pc lo : 0xffe54018 [ 255.663636] cx23885: cx23885[0]: cmds: risc pc hi : 0x00000000 [ 255.663639] cx23885: cx23885[0]: cmds: iq wr ptr : 0x00004192 [ 255.663642] cx23885: cx23885[0]: cmds: iq rd ptr : 0x0000418c [ 255.663645] cx23885: cx23885[0]: cmds: cdt current : 0x00010898 [ 255.663649] cx23885: cx23885[0]: cmds: pci target lo : 0xf85ca340 [ 255.663652] cx23885: cx23885[0]: cmds: pci target hi : 0x00000000 [ 255.663655] cx23885: cx23885[0]: cmds: line / byte : 0x000c0000 [ 255.663659] cx23885: cx23885[0]: risc0: [ 255.663661] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663666] cx23885: cx23885[0]: risc1: [ 255.663667] 0xf85ca050 [ INVALID sol 22 20 19 18 resync 13 count=80 ] [ 255.663674] cx23885: cx23885[0]: risc2: [ 255.663674] 0x00000000 [ INVALID count=0 ] [ 255.663678] cx23885: cx23885[0]: risc3: [ 255.663679] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663684] cx23885: cx23885[0]: (0x00010630) iq 0: [ 255.663685] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663690] cx23885: cx23885[0]: iq 1: 0xf85ca630 [ arg #1 ] [ 255.663693] cx23885: cx23885[0]: iq 2: 0x00000000 [ arg #2 ] [ 255.663696] cx23885: cx23885[0]: (0x0001063c) iq 3: [ 255.663697] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663702] cx23885: cx23885[0]: iq 4: 0xf85ca920 [ arg #1 ] [ 255.663705] cx23885: cx23885[0]: iq 5: 0x00000000 [ arg #2 ] [ 255.663709] cx23885: cx23885[0]: (0x00010648) iq 6: [ 255.663709] 0xf85ca340 [ INVALID sol 22 20 19 18 resync 13 count=832 ] [ 255.663716] cx23885: cx23885[0]: (0x0001064c) iq 7: [ 255.663717] 0x00000000 [ INVALID count=0 ] [ 255.663721] cx23885: cx23885[0]: (0x00010650) iq 8: [ 255.663721] 0x00000000 [ INVALID count=0 ] [ 255.663725] cx23885: cx23885[0]: (0x00010654) iq 9: [ 255.663726] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663731] cx23885: cx23885[0]: iq a: 0xf85c9780 [ arg #1 ] [ 255.663734] cx23885: cx23885[0]: iq b: 0x00000000 [ arg #2 ] [ 255.663737] cx23885: cx23885[0]: (0x00010660) iq c: [ 255.663738] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663743] cx23885: cx23885[0]: iq d: 0xf85c9a70 [ arg #1 ] [ 255.663746] cx23885: cx23885[0]: iq e: 0x00000000 [ arg #2 ] [ 255.663749] cx23885: cx23885[0]: (0x0001066c) iq f: [ 255.663750] 0x1c0002f0 [ write sol eol count=752 ] [ 255.663755] cx23885: cx23885[0]: iq 10: 0xf4fa2920 [ arg #1 ] [ 255.663758] cx23885: cx23885[0]: iq 11: 0x00000000 [ arg #2 ] [ 255.663759] cx23885: cx23885[0]: fifo: 0x00005000 -> 0x6000 [ 255.663760] cx23885: cx23885[0]: ctrl: 0x00010630 -> 0x10690 [ 255.663764] cx23885: cx23885[0]: ptr1_reg: 0x00005980 [ 255.663767] cx23885: cx23885[0]: ptr2_reg: 0x000108a8 [ 255.663770] cx23885: cx23885[0]: cnt1_reg: 0x0000000b [ 255.663773] cx23885: cx23885[0]: cnt2_reg: 0x00000003 Included is checks of the TC_REQ and TC_REQ_SET registers during states of board initialization, reset, DMA start, and DMA stop. If both registers are set, this indicates a stall in the RiSC engine, at which point the bridge error is cleared. A small delay is introduced in stop_dma as well, to allow transfers in progress to finish. After application all models work on Ryzen, occasionally yielding: cx23885_clear_bridge_error: dma in progress detected 0x00000001 0x00000001, clearing Signed-off-by: Brad Love <brad@nextdimension.cc> Signed-off-by: Hans Verkuil <hansverk@cisco.com> [hansverk@cisco.com: fix compiler warning of unused 'reg' variable] Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
2018-05-09 05:20:18 +08:00
/* just in case wait for any dma to complete before allowing dealloc */
mdelay(20);
for (delay = 0; delay < 100; delay++) {
reg1_val = cx_read(TC_REQ);
reg2_val = cx_read(TC_REQ_SET);
if (reg1_val == 0 || reg2_val == 0)
break;
mdelay(1);
}
dev_dbg(&dev->pci->dev, "delay=%d reg1=0x%08x reg2=0x%08x\n",
delay, reg1_val, reg2_val);
if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) {
reg = cx_read(PAD_CTRL);
/* Set TS1_OE */
reg = reg | 0x1;
/* clear TS1_SOP_OE and TS1_OE_HI */
reg = reg & ~0xa;
cx_write(PAD_CTRL, reg);
cx_write(port->reg_src_sel, 0);
cx_write(port->reg_gen_ctrl, 8);
}
if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER)
cx23885_av_clk(dev, 0);
return 0;
}
/* ------------------------------------------------------------------ */
int cx23885_buf_prepare(struct cx23885_buffer *buf, struct cx23885_tsport *port)
{
struct cx23885_dev *dev = port->dev;
int size = port->ts_packet_size * port->ts_packet_count;
struct sg_table *sgt = vb2_dma_sg_plane_desc(&buf->vb.vb2_buf, 0);
dprintk(1, "%s: %p\n", __func__, buf);
if (vb2_plane_size(&buf->vb.vb2_buf, 0) < size)
return -EINVAL;
vb2_set_plane_payload(&buf->vb.vb2_buf, 0, size);
cx23885_risc_databuffer(dev->pci, &buf->risc,
sgt->sgl,
port->ts_packet_size, port->ts_packet_count, 0);
return 0;
}
/*
* The risc program for each buffer works as follows: it starts with a simple
* 'JUMP to addr + 12', which is effectively a NOP. Then the code to DMA the
* buffer follows and at the end we have a JUMP back to the start + 12 (skipping
* the initial JUMP).
*
* This is the risc program of the first buffer to be queued if the active list
* is empty and it just keeps DMAing this buffer without generating any
* interrupts.
*
* If a new buffer is added then the initial JUMP in the code for that buffer
* will generate an interrupt which signals that the previous buffer has been
* DMAed successfully and that it can be returned to userspace.
*
* It also sets the final jump of the previous buffer to the start of the new
* buffer, thus chaining the new buffer into the DMA chain. This is a single
* atomic u32 write, so there is no race condition.
*
* The end-result of all this that you only get an interrupt when a buffer
* is ready, so the control flow is very easy.
*/
void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf)
{
struct cx23885_buffer *prev;
struct cx23885_dev *dev = port->dev;
struct cx23885_dmaqueue *cx88q = &port->mpegq;
unsigned long flags;
buf->risc.cpu[1] = cpu_to_le32(buf->risc.dma + 12);
buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_CNT_INC);
buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma + 12);
buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
spin_lock_irqsave(&dev->slock, flags);
if (list_empty(&cx88q->active)) {
list_add_tail(&buf->queue, &cx88q->active);
dprintk(1, "[%p/%d] %s - first active\n",
buf, buf->vb.vb2_buf.index, __func__);
} else {
buf->risc.cpu[0] |= cpu_to_le32(RISC_IRQ1);
prev = list_entry(cx88q->active.prev, struct cx23885_buffer,
queue);
list_add_tail(&buf->queue, &cx88q->active);
prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
dprintk(1, "[%p/%d] %s - append to active\n",
buf, buf->vb.vb2_buf.index, __func__);
}
spin_unlock_irqrestore(&dev->slock, flags);
}
/* ----------------------------------------------------------- */
static void do_cancel_buffers(struct cx23885_tsport *port, char *reason)
{
struct cx23885_dmaqueue *q = &port->mpegq;
struct cx23885_buffer *buf;
unsigned long flags;
spin_lock_irqsave(&port->slock, flags);
while (!list_empty(&q->active)) {
buf = list_entry(q->active.next, struct cx23885_buffer,
queue);
list_del(&buf->queue);
vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
dprintk(1, "[%p/%d] %s - dma=0x%08lx\n",
buf, buf->vb.vb2_buf.index, reason,
(unsigned long)buf->risc.dma);
}
spin_unlock_irqrestore(&port->slock, flags);
}
void cx23885_cancel_buffers(struct cx23885_tsport *port)
{
dprintk(1, "%s()\n", __func__);
cx23885_stop_dma(port);
do_cancel_buffers(port, "cancel");
}
int cx23885_irq_417(struct cx23885_dev *dev, u32 status)
{
/* FIXME: port1 assumption here. */
struct cx23885_tsport *port = &dev->ts1;
int count = 0;
int handled = 0;
if (status == 0)
return handled;
count = cx_read(port->reg_gpcnt);
dprintk(7, "status: 0x%08x mask: 0x%08x count: 0x%x\n",
status, cx_read(port->reg_ts_int_msk), count);
if ((status & VID_B_MSK_BAD_PKT) ||
(status & VID_B_MSK_OPC_ERR) ||
(status & VID_B_MSK_VBI_OPC_ERR) ||
(status & VID_B_MSK_SYNC) ||
(status & VID_B_MSK_VBI_SYNC) ||
(status & VID_B_MSK_OF) ||
(status & VID_B_MSK_VBI_OF)) {
pr_err("%s: V4L mpeg risc op code error, status = 0x%x\n",
dev->name, status);
if (status & VID_B_MSK_BAD_PKT)
dprintk(1, " VID_B_MSK_BAD_PKT\n");
if (status & VID_B_MSK_OPC_ERR)
dprintk(1, " VID_B_MSK_OPC_ERR\n");
if (status & VID_B_MSK_VBI_OPC_ERR)
dprintk(1, " VID_B_MSK_VBI_OPC_ERR\n");
if (status & VID_B_MSK_SYNC)
dprintk(1, " VID_B_MSK_SYNC\n");
if (status & VID_B_MSK_VBI_SYNC)
dprintk(1, " VID_B_MSK_VBI_SYNC\n");
if (status & VID_B_MSK_OF)
dprintk(1, " VID_B_MSK_OF\n");
if (status & VID_B_MSK_VBI_OF)
dprintk(1, " VID_B_MSK_VBI_OF\n");
cx_clear(port->reg_dma_ctl, port->dma_ctl_val);
cx23885_sram_channel_dump(dev,
&dev->sram_channels[port->sram_chno]);
cx23885_417_check_encoder(dev);
} else if (status & VID_B_MSK_RISCI1) {
dprintk(7, " VID_B_MSK_RISCI1\n");
spin_lock(&port->slock);
cx23885_wakeup(port, &port->mpegq, count);
spin_unlock(&port->slock);
}
if (status) {
cx_write(port->reg_ts_int_stat, status);
handled = 1;
}
return handled;
}
static int cx23885_irq_ts(struct cx23885_tsport *port, u32 status)
{
struct cx23885_dev *dev = port->dev;
int handled = 0;
u32 count;
if ((status & VID_BC_MSK_OPC_ERR) ||
(status & VID_BC_MSK_BAD_PKT) ||
(status & VID_BC_MSK_SYNC) ||
(status & VID_BC_MSK_OF)) {
if (status & VID_BC_MSK_OPC_ERR)
dprintk(7, " (VID_BC_MSK_OPC_ERR 0x%08x)\n",
VID_BC_MSK_OPC_ERR);
if (status & VID_BC_MSK_BAD_PKT)
dprintk(7, " (VID_BC_MSK_BAD_PKT 0x%08x)\n",
VID_BC_MSK_BAD_PKT);
if (status & VID_BC_MSK_SYNC)
dprintk(7, " (VID_BC_MSK_SYNC 0x%08x)\n",
VID_BC_MSK_SYNC);
if (status & VID_BC_MSK_OF)
dprintk(7, " (VID_BC_MSK_OF 0x%08x)\n",
VID_BC_MSK_OF);
pr_err("%s: mpeg risc op code error\n", dev->name);
cx_clear(port->reg_dma_ctl, port->dma_ctl_val);
cx23885_sram_channel_dump(dev,
&dev->sram_channels[port->sram_chno]);
} else if (status & VID_BC_MSK_RISCI1) {
dprintk(7, " (RISCI1 0x%08x)\n", VID_BC_MSK_RISCI1);
spin_lock(&port->slock);
count = cx_read(port->reg_gpcnt);
cx23885_wakeup(port, &port->mpegq, count);
spin_unlock(&port->slock);
}
if (status) {
cx_write(port->reg_ts_int_stat, status);
handled = 1;
}
return handled;
}
static irqreturn_t cx23885_irq(int irq, void *dev_id)
{
struct cx23885_dev *dev = dev_id;
struct cx23885_tsport *ts1 = &dev->ts1;
struct cx23885_tsport *ts2 = &dev->ts2;
u32 pci_status, pci_mask;
u32 vida_status, vida_mask;
u32 audint_status, audint_mask;
u32 ts1_status, ts1_mask;
u32 ts2_status, ts2_mask;
int vida_count = 0, ts1_count = 0, ts2_count = 0, handled = 0;
int audint_count = 0;
bool subdev_handled;
pci_status = cx_read(PCI_INT_STAT);
pci_mask = cx23885_irq_get_mask(dev);
if ((pci_status & pci_mask) == 0) {
dprintk(7, "pci_status: 0x%08x pci_mask: 0x%08x\n",
pci_status, pci_mask);
goto out;
}
vida_status = cx_read(VID_A_INT_STAT);
vida_mask = cx_read(VID_A_INT_MSK);
audint_status = cx_read(AUDIO_INT_INT_STAT);
audint_mask = cx_read(AUDIO_INT_INT_MSK);
ts1_status = cx_read(VID_B_INT_STAT);
ts1_mask = cx_read(VID_B_INT_MSK);
ts2_status = cx_read(VID_C_INT_STAT);
ts2_mask = cx_read(VID_C_INT_MSK);
if (((pci_status & pci_mask) == 0) &&
((ts2_status & ts2_mask) == 0) &&
((ts1_status & ts1_mask) == 0))
goto out;
vida_count = cx_read(VID_A_GPCNT);
audint_count = cx_read(AUD_INT_A_GPCNT);
ts1_count = cx_read(ts1->reg_gpcnt);
ts2_count = cx_read(ts2->reg_gpcnt);
dprintk(7, "pci_status: 0x%08x pci_mask: 0x%08x\n",
pci_status, pci_mask);
dprintk(7, "vida_status: 0x%08x vida_mask: 0x%08x count: 0x%x\n",
vida_status, vida_mask, vida_count);
dprintk(7, "audint_status: 0x%08x audint_mask: 0x%08x count: 0x%x\n",
audint_status, audint_mask, audint_count);
dprintk(7, "ts1_status: 0x%08x ts1_mask: 0x%08x count: 0x%x\n",
ts1_status, ts1_mask, ts1_count);
dprintk(7, "ts2_status: 0x%08x ts2_mask: 0x%08x count: 0x%x\n",
ts2_status, ts2_mask, ts2_count);
if (pci_status & (PCI_MSK_RISC_RD | PCI_MSK_RISC_WR |
PCI_MSK_AL_RD | PCI_MSK_AL_WR | PCI_MSK_APB_DMA |
PCI_MSK_VID_C | PCI_MSK_VID_B | PCI_MSK_VID_A |
PCI_MSK_AUD_INT | PCI_MSK_AUD_EXT |
PCI_MSK_GPIO0 | PCI_MSK_GPIO1 |
PCI_MSK_AV_CORE | PCI_MSK_IR)) {
if (pci_status & PCI_MSK_RISC_RD)
dprintk(7, " (PCI_MSK_RISC_RD 0x%08x)\n",
PCI_MSK_RISC_RD);
if (pci_status & PCI_MSK_RISC_WR)
dprintk(7, " (PCI_MSK_RISC_WR 0x%08x)\n",
PCI_MSK_RISC_WR);
if (pci_status & PCI_MSK_AL_RD)
dprintk(7, " (PCI_MSK_AL_RD 0x%08x)\n",
PCI_MSK_AL_RD);
if (pci_status & PCI_MSK_AL_WR)
dprintk(7, " (PCI_MSK_AL_WR 0x%08x)\n",
PCI_MSK_AL_WR);
if (pci_status & PCI_MSK_APB_DMA)
dprintk(7, " (PCI_MSK_APB_DMA 0x%08x)\n",
PCI_MSK_APB_DMA);
if (pci_status & PCI_MSK_VID_C)
dprintk(7, " (PCI_MSK_VID_C 0x%08x)\n",
PCI_MSK_VID_C);
if (pci_status & PCI_MSK_VID_B)
dprintk(7, " (PCI_MSK_VID_B 0x%08x)\n",
PCI_MSK_VID_B);
if (pci_status & PCI_MSK_VID_A)
dprintk(7, " (PCI_MSK_VID_A 0x%08x)\n",
PCI_MSK_VID_A);
if (pci_status & PCI_MSK_AUD_INT)
dprintk(7, " (PCI_MSK_AUD_INT 0x%08x)\n",
PCI_MSK_AUD_INT);
if (pci_status & PCI_MSK_AUD_EXT)
dprintk(7, " (PCI_MSK_AUD_EXT 0x%08x)\n",
PCI_MSK_AUD_EXT);
if (pci_status & PCI_MSK_GPIO0)
dprintk(7, " (PCI_MSK_GPIO0 0x%08x)\n",
PCI_MSK_GPIO0);
if (pci_status & PCI_MSK_GPIO1)
dprintk(7, " (PCI_MSK_GPIO1 0x%08x)\n",
PCI_MSK_GPIO1);
if (pci_status & PCI_MSK_AV_CORE)
dprintk(7, " (PCI_MSK_AV_CORE 0x%08x)\n",
PCI_MSK_AV_CORE);
if (pci_status & PCI_MSK_IR)
dprintk(7, " (PCI_MSK_IR 0x%08x)\n",
PCI_MSK_IR);
}
if (cx23885_boards[dev->board].ci_type == 1 &&
(pci_status & (PCI_MSK_GPIO1 | PCI_MSK_GPIO0)))
handled += netup_ci_slot_status(dev, pci_status);
if (cx23885_boards[dev->board].ci_type == 2 &&
(pci_status & PCI_MSK_GPIO0))
handled += altera_ci_irq(dev);
if (ts1_status) {
if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB)
handled += cx23885_irq_ts(ts1, ts1_status);
else
if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER)
handled += cx23885_irq_417(dev, ts1_status);
}
if (ts2_status) {
if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB)
handled += cx23885_irq_ts(ts2, ts2_status);
else
if (cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER)
handled += cx23885_irq_417(dev, ts2_status);
}
if (vida_status)
handled += cx23885_video_irq(dev, vida_status);
if (audint_status)
handled += cx23885_audio_irq(dev, audint_status, audint_mask);
if (pci_status & PCI_MSK_IR) {
subdev_handled = false;
v4l2_subdev_call(dev->sd_ir, core, interrupt_service_routine,
pci_status, &subdev_handled);
if (subdev_handled)
handled++;
}
if ((pci_status & pci_mask) & PCI_MSK_AV_CORE) {
cx23885_irq_disable(dev, PCI_MSK_AV_CORE);
schedule_work(&dev->cx25840_work);
handled++;
}
if (handled)
cx_write(PCI_INT_STAT, pci_status & pci_mask);
out:
return IRQ_RETVAL(handled);
}
static void cx23885_v4l2_dev_notify(struct v4l2_subdev *sd,
unsigned int notification, void *arg)
{
struct cx23885_dev *dev;
if (sd == NULL)
return;
dev = to_cx23885(sd->v4l2_dev);
switch (notification) {
case V4L2_SUBDEV_IR_RX_NOTIFY: /* Possibly called in an IRQ context */
if (sd == dev->sd_ir)
cx23885_ir_rx_v4l2_dev_notify(sd, *(u32 *)arg);
break;
case V4L2_SUBDEV_IR_TX_NOTIFY: /* Possibly called in an IRQ context */
if (sd == dev->sd_ir)
cx23885_ir_tx_v4l2_dev_notify(sd, *(u32 *)arg);
break;
}
}
static void cx23885_v4l2_dev_notify_init(struct cx23885_dev *dev)
{
INIT_WORK(&dev->cx25840_work, cx23885_av_work_handler);
INIT_WORK(&dev->ir_rx_work, cx23885_ir_rx_work_handler);
INIT_WORK(&dev->ir_tx_work, cx23885_ir_tx_work_handler);
dev->v4l2_dev.notify = cx23885_v4l2_dev_notify;
}
static inline int encoder_on_portb(struct cx23885_dev *dev)
{
return cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER;
}
static inline int encoder_on_portc(struct cx23885_dev *dev)
{
return cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER;
}
/* Mask represents 32 different GPIOs, GPIO's are split into multiple
* registers depending on the board configuration (and whether the
* 417 encoder (wi it's own GPIO's) are present. Each GPIO bit will
* be pushed into the correct hardware register, regardless of the
* physical location. Certain registers are shared so we sanity check
* and report errors if we think we're tampering with a GPIo that might
* be assigned to the encoder (and used for the host bus).
*
* GPIO 2 through 0 - On the cx23885 bridge
* GPIO 18 through 3 - On the cx23417 host bus interface
* GPIO 23 through 19 - On the cx25840 a/v core
*/
void cx23885_gpio_set(struct cx23885_dev *dev, u32 mask)
{
if (mask & 0x7)
cx_set(GP0_IO, mask & 0x7);
if (mask & 0x0007fff8) {
if (encoder_on_portb(dev) || encoder_on_portc(dev))
pr_err("%s: Setting GPIO on encoder ports\n",
dev->name);
cx_set(MC417_RWD, (mask & 0x0007fff8) >> 3);
}
/* TODO: 23-19 */
if (mask & 0x00f80000)
pr_info("%s: Unsupported\n", dev->name);
}
void cx23885_gpio_clear(struct cx23885_dev *dev, u32 mask)
{
if (mask & 0x00000007)
cx_clear(GP0_IO, mask & 0x7);
if (mask & 0x0007fff8) {
if (encoder_on_portb(dev) || encoder_on_portc(dev))
pr_err("%s: Clearing GPIO moving on encoder ports\n",
dev->name);
cx_clear(MC417_RWD, (mask & 0x7fff8) >> 3);
}
/* TODO: 23-19 */
if (mask & 0x00f80000)
pr_info("%s: Unsupported\n", dev->name);
}
u32 cx23885_gpio_get(struct cx23885_dev *dev, u32 mask)
{
if (mask & 0x00000007)
return (cx_read(GP0_IO) >> 8) & mask & 0x7;
if (mask & 0x0007fff8) {
if (encoder_on_portb(dev) || encoder_on_portc(dev))
pr_err("%s: Reading GPIO moving on encoder ports\n",
dev->name);
return (cx_read(MC417_RWD) & ((mask & 0x7fff8) >> 3)) << 3;
}
/* TODO: 23-19 */
if (mask & 0x00f80000)
pr_info("%s: Unsupported\n", dev->name);
return 0;
}
void cx23885_gpio_enable(struct cx23885_dev *dev, u32 mask, int asoutput)
{
if ((mask & 0x00000007) && asoutput)
cx_set(GP0_IO, (mask & 0x7) << 16);
else if ((mask & 0x00000007) && !asoutput)
cx_clear(GP0_IO, (mask & 0x7) << 16);
if (mask & 0x0007fff8) {
if (encoder_on_portb(dev) || encoder_on_portc(dev))
pr_err("%s: Enabling GPIO on encoder ports\n",
dev->name);
}
/* MC417_OEN is active low for output, write 1 for an input */
if ((mask & 0x0007fff8) && asoutput)
cx_clear(MC417_OEN, (mask & 0x7fff8) >> 3);
else if ((mask & 0x0007fff8) && !asoutput)
cx_set(MC417_OEN, (mask & 0x7fff8) >> 3);
/* TODO: 23-19 */
}
static struct {
int vendor, dev;
} const broken_dev_id[] = {
/* According with
* https://openbenchmarking.org/system/1703021-RI-AMDZEN08075/Ryzen%207%201800X/lspci,
* 0x1451 is PCI ID for the IOMMU found on Ryzen
*/
{ PCI_VENDOR_ID_AMD, 0x1451 },
};
static bool cx23885_does_need_dma_reset(void)
{
int i;
struct pci_dev *pdev = NULL;
if (dma_reset_workaround == 0)
return false;
else if (dma_reset_workaround == 2)
return true;
for (i = 0; i < ARRAY_SIZE(broken_dev_id); i++) {
pdev = pci_get_device(broken_dev_id[i].vendor,
broken_dev_id[i].dev, NULL);
if (pdev) {
pci_dev_put(pdev);
return true;
}
}
return false;
}
static int cx23885_initdev(struct pci_dev *pci_dev,
const struct pci_device_id *pci_id)
{
struct cx23885_dev *dev;
struct v4l2_ctrl_handler *hdl;
int err;
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (NULL == dev)
return -ENOMEM;
dev->need_dma_reset = cx23885_does_need_dma_reset();
err = v4l2_device_register(&pci_dev->dev, &dev->v4l2_dev);
if (err < 0)
goto fail_free;
hdl = &dev->ctrl_handler;
v4l2_ctrl_handler_init(hdl, 6);
if (hdl->error) {
err = hdl->error;
goto fail_ctrl;
}
dev->v4l2_dev.ctrl_handler = hdl;
/* Prepare to handle notifications from subdevices */
cx23885_v4l2_dev_notify_init(dev);
/* pci init */
dev->pci = pci_dev;
if (pci_enable_device(pci_dev)) {
err = -EIO;
goto fail_ctrl;
}
if (cx23885_dev_setup(dev) < 0) {
err = -EINVAL;
goto fail_ctrl;
}
/* print pci info */
dev->pci_rev = pci_dev->revision;
pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat);
pr_info("%s/0: found at %s, rev: %d, irq: %d, latency: %d, mmio: 0x%llx\n",
dev->name,
pci_name(pci_dev), dev->pci_rev, pci_dev->irq,
dev->pci_lat,
(unsigned long long)pci_resource_start(pci_dev, 0));
pci_set_master(pci_dev);
err = pci_set_dma_mask(pci_dev, 0xffffffff);
if (err) {
pr_err("%s/0: Oops: no 32bit PCI DMA ???\n", dev->name);
goto fail_ctrl;
}
err = request_irq(pci_dev->irq, cx23885_irq,
IRQF_SHARED, dev->name, dev);
if (err < 0) {
pr_err("%s: can't get IRQ %d\n",
dev->name, pci_dev->irq);
goto fail_irq;
}
switch (dev->board) {
case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
cx23885_irq_add_enable(dev, PCI_MSK_GPIO1 | PCI_MSK_GPIO0);
break;
case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF:
cx23885_irq_add_enable(dev, PCI_MSK_GPIO0);
break;
}
/*
* The CX2388[58] IR controller can start firing interrupts when
* enabled, so these have to take place after the cx23885_irq() handler
* is hooked up by the call to request_irq() above.
*/
cx23885_ir_pci_int_enable(dev);
cx23885_input_init(dev);
return 0;
fail_irq:
cx23885_dev_unregister(dev);
fail_ctrl:
v4l2_ctrl_handler_free(hdl);
v4l2_device_unregister(&dev->v4l2_dev);
fail_free:
kfree(dev);
return err;
}
static void cx23885_finidev(struct pci_dev *pci_dev)
{
struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
struct cx23885_dev *dev = to_cx23885(v4l2_dev);
cx23885_input_fini(dev);
cx23885_ir_fini(dev);
cx23885_shutdown(dev);
/* unregister stuff */
free_irq(pci_dev->irq, dev);
[media] cx23885: fix free interrupt bug First free the interrupt, then disable the PCI device. The other way around will lead to this warning: Jan 19 11:42:02 telek kernel: [ 1440.161234] WARNING: CPU: 0 PID: 2191 at kernel/irq/manage.c:1311 __free_irq+0x97/0x1f0() Jan 19 11:42:02 telek kernel: [ 1440.161236] Trying to free already-free IRQ 0 Jan 19 11:42:02 telek kernel: [ 1440.161237] Modules linked in: tda8290 tda10048 cx25840 cx23885(-) altera_ci tda18271 altera_stapl videobuf2_dvb tveeprom cx2341x videobuf2_dma_sg dvb_core rc_core videobuf2_memops videobuf2_core v4l2_common videodev media nouveau x86_pkg_temp_thermal cfbfillrect cfbimgblt cfbcopyarea ttm drm_kms_helper processor button isci Jan 19 11:42:02 telek kernel: [ 1440.161266] CPU: 0 PID: 2191 Comm: rmmod Tainted: G W 3.19.0-rc1-telek #345 Jan 19 11:42:02 telek kernel: [ 1440.161268] Hardware name: ASUSTeK COMPUTER INC. Z9PE-D8 WS/Z9PE-D8 WS, BIOS 5404 02/10/2014 Jan 19 11:42:02 telek kernel: [ 1440.161270] ffffffff81bf1fce ffff8808958b7cc8 ffffffff8194a97f 0000000000000000 Jan 19 11:42:02 telek kernel: [ 1440.161274] ffff8808958b7d18 ffff8808958b7d08 ffffffff810c56b0 0000000000000286 Jan 19 11:42:02 telek kernel: [ 1440.161279] 0000000000000000 0000000000000000 ffff88089f808890 ffff88089f808800 Jan 19 11:42:02 telek kernel: [ 1440.161284] Call Trace: Jan 19 11:42:02 telek kernel: [ 1440.161290] [<ffffffff8194a97f>] dump_stack+0x4f/0x7b Jan 19 11:42:02 telek kernel: [ 1440.161295] [<ffffffff810c56b0>] warn_slowpath_common+0x80/0xc0 Jan 19 11:42:02 telek kernel: [ 1440.161299] [<ffffffff810c5731>] warn_slowpath_fmt+0x41/0x50 Jan 19 11:42:02 telek kernel: [ 1440.161303] [<ffffffff81955d36>] ? _raw_spin_lock_irqsave+0x56/0x70 Jan 19 11:42:02 telek kernel: [ 1440.161307] [<ffffffff81114849>] ? __free_irq+0x49/0x1f0 Jan 19 11:42:02 telek kernel: [ 1440.161311] [<ffffffff81114897>] __free_irq+0x97/0x1f0 Jan 19 11:42:02 telek kernel: [ 1440.161316] [<ffffffff81114a88>] free_irq+0x48/0xd0 Jan 19 11:42:02 telek kernel: [ 1440.161323] [<ffffffffa00e6deb>] cx23885_finidev+0x4b/0x90 [cx23885] Jan 19 11:42:02 telek kernel: [ 1440.161329] [<ffffffff814529fa>] pci_device_remove+0x3a/0xc0 Jan 19 11:42:02 telek kernel: [ 1440.161334] [<ffffffff8153b4ea>] __device_release_driver+0x7a/0xf0 Jan 19 11:42:02 telek kernel: [ 1440.161338] [<ffffffff8153bc98>] driver_detach+0xc8/0xd0 Jan 19 11:42:02 telek kernel: [ 1440.161341] [<ffffffff8153b1de>] bus_remove_driver+0x4e/0xb0 Jan 19 11:42:02 telek kernel: [ 1440.161345] [<ffffffff8153c2eb>] driver_unregister+0x2b/0x60 Jan 19 11:42:02 telek kernel: [ 1440.161349] [<ffffffff814525c5>] pci_unregister_driver+0x25/0x70 Jan 19 11:42:02 telek kernel: [ 1440.161355] [<ffffffffa00f6ddc>] cx23885_fini+0x10/0x12 [cx23885] Jan 19 11:42:02 telek kernel: [ 1440.161360] [<ffffffff81139a98>] SyS_delete_module+0x1a8/0x1f0 Jan 19 11:42:02 telek kernel: [ 1440.161364] [<ffffffff819561a9>] system_call_fastpath+0x12/0x17 Jan 19 11:42:02 telek kernel: [ 1440.161367] ---[ end trace a9c07cb5f3357020 ]--- Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2015-01-19 18:14:14 +08:00
pci_disable_device(pci_dev);
cx23885_dev_unregister(dev);
v4l2_ctrl_handler_free(&dev->ctrl_handler);
v4l2_device_unregister(v4l2_dev);
kfree(dev);
}
static const struct pci_device_id cx23885_pci_tbl[] = {
{
/* CX23885 */
.vendor = 0x14f1,
.device = 0x8852,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
}, {
/* CX23887 Rev 2 */
.vendor = 0x14f1,
.device = 0x8880,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
}, {
/* --- end of list --- */
}
};
MODULE_DEVICE_TABLE(pci, cx23885_pci_tbl);
static struct pci_driver cx23885_pci_driver = {
.name = "cx23885",
.id_table = cx23885_pci_tbl,
.probe = cx23885_initdev,
.remove = cx23885_finidev,
};
static int __init cx23885_init(void)
{
pr_info("cx23885 driver version %s loaded\n",
CX23885_VERSION);
return pci_register_driver(&cx23885_pci_driver);
}
static void __exit cx23885_fini(void)
{
pci_unregister_driver(&cx23885_pci_driver);
}
module_init(cx23885_init);
module_exit(cx23885_fini);