diff options
author | Steven Toth <stoth@kernellabs.com> | 2010-07-31 15:13:45 -0300 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2010-10-21 07:54:54 -0200 |
commit | 12d3203e39db306f56611b3f47ba425ca6a409f9 (patch) | |
tree | 3e7eba22186a7015be6529abd2c3ee3659b0b77c | |
parent | 46eeb8dd30d3651e6ea55c2e60594206cd591d79 (diff) |
[media] saa7164: buffer crc checks and ensure we use the memcpy func
Buffer crc checks and ensure we use the correct PCIe IO memcpy func
Signed-off-by: Steven Toth <stoth@kernellabs.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r-- | drivers/media/video/saa7164/saa7164-buffer.c | 7 | ||||
-rw-r--r-- | drivers/media/video/saa7164/saa7164-bus.c | 46 | ||||
-rw-r--r-- | drivers/media/video/saa7164/saa7164-core.c | 157 | ||||
-rw-r--r-- | drivers/media/video/saa7164/saa7164-encoder.c | 9 | ||||
-rw-r--r-- | drivers/media/video/saa7164/saa7164.h | 12 |
5 files changed, 191 insertions, 40 deletions
diff --git a/drivers/media/video/saa7164/saa7164-buffer.c b/drivers/media/video/saa7164/saa7164-buffer.c index 0760891d5fa..b75157d411d 100644 --- a/drivers/media/video/saa7164/saa7164-buffer.c +++ b/drivers/media/video/saa7164/saa7164-buffer.c @@ -113,6 +113,7 @@ struct saa7164_buffer *saa7164_buffer_alloc(struct saa7164_port *port, buf->flags = SAA7164_BUFFER_FREE; buf->pos = 0; buf->actual_size = params->pitch * params->numberoflines; + buf->crc = 0; /* TODO: arg len is being ignored */ buf->pci_size = SAA7164_PT_ENTRIES * 0x1000; buf->pt_size = (SAA7164_PT_ENTRIES * sizeof(u64)) + 0x1000; @@ -129,8 +130,9 @@ struct saa7164_buffer *saa7164_buffer_alloc(struct saa7164_port *port, goto fail2; /* init the buffers to a known pattern, easier during debugging */ - memset(buf->cpu, 0xff, buf->pci_size); - memset(buf->pt_cpu, 0xff, buf->pt_size); + memset_io(buf->cpu, 0xff, buf->pci_size); + buf->crc = crc32(0, buf->cpu, buf->actual_size); + memset_io(buf->pt_cpu, 0xff, buf->pt_size); dprintk(DBGLVL_BUF, "%s() allocated buffer @ 0x%p\n", __func__, buf); @@ -296,6 +298,7 @@ struct saa7164_user_buffer *saa7164_buffer_alloc_user(struct saa7164_dev *dev, u buf->actual_size = len; buf->pos = 0; + buf->crc = 0; dprintk(DBGLVL_BUF, "%s() allocated user buffer @ 0x%p\n", __func__, buf); diff --git a/drivers/media/video/saa7164/saa7164-bus.c b/drivers/media/video/saa7164/saa7164-bus.c index 49414c81485..ccc61007f33 100644 --- a/drivers/media/video/saa7164/saa7164-bus.c +++ b/drivers/media/video/saa7164/saa7164-bus.c @@ -217,28 +217,28 @@ int saa7164_bus_set(struct saa7164_dev *dev, tmComResInfo_t* msg, void *buf) dprintk(DBGLVL_BUS, "%s() tr4\n", __func__); /* Split the msg into pieces as the ring wraps */ - memcpy(bus->m_pdwSetRing + curr_swp, msg, space_rem); - memcpy(bus->m_pdwSetRing, (u8 *)msg + space_rem, + memcpy_toio(bus->m_pdwSetRing + curr_swp, msg, space_rem); + memcpy_toio(bus->m_pdwSetRing, (u8 *)msg + space_rem, sizeof(*msg) - space_rem); - memcpy(bus->m_pdwSetRing + sizeof(*msg) - space_rem, + memcpy_toio(bus->m_pdwSetRing + sizeof(*msg) - space_rem, buf, msg->size); } else if (space_rem == sizeof(*msg)) { dprintk(DBGLVL_BUS, "%s() tr5\n", __func__); /* Additional data at the beginning of the ring */ - memcpy(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg)); - memcpy(bus->m_pdwSetRing, buf, msg->size); + memcpy_toio(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg)); + memcpy_toio(bus->m_pdwSetRing, buf, msg->size); } else { /* Additional data wraps around the ring */ - memcpy(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg)); + memcpy_toio(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg)); if (msg->size > 0) { - memcpy(bus->m_pdwSetRing + curr_swp + + memcpy_toio(bus->m_pdwSetRing + curr_swp + sizeof(*msg), buf, space_rem - sizeof(*msg)); - memcpy(bus->m_pdwSetRing, (u8 *)buf + + memcpy_toio(bus->m_pdwSetRing, (u8 *)buf + space_rem - sizeof(*msg), bytes_to_write - space_rem); } @@ -250,8 +250,8 @@ int saa7164_bus_set(struct saa7164_dev *dev, tmComResInfo_t* msg, void *buf) dprintk(DBGLVL_BUS, "%s() tr6\n", __func__); /* The ring buffer doesn't wrap, two simple copies */ - memcpy(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg)); - memcpy(bus->m_pdwSetRing + curr_swp + sizeof(*msg), buf, + memcpy_toio(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg)); + memcpy_toio(bus->m_pdwSetRing + curr_swp + sizeof(*msg), buf, msg->size); } @@ -343,19 +343,19 @@ int saa7164_bus_get(struct saa7164_dev *dev, tmComResInfo_t* msg, void *buf, new_grp -= bus->m_dwSizeGetRing; space_rem = bus->m_dwSizeGetRing - curr_grp; - memcpy(&msg_tmp, bus->m_pdwGetRing + curr_grp, space_rem); - memcpy((u8 *)&msg_tmp + space_rem, bus->m_pdwGetRing, + memcpy_fromio(&msg_tmp, bus->m_pdwGetRing + curr_grp, space_rem); + memcpy_fromio((u8 *)&msg_tmp + space_rem, bus->m_pdwGetRing, bytes_to_read - space_rem); } else { /* No wrapping */ - memcpy(&msg_tmp, bus->m_pdwGetRing + curr_grp, bytes_to_read); + memcpy_fromio(&msg_tmp, bus->m_pdwGetRing + curr_grp, bytes_to_read); } /* No need to update the read positions, because this was a peek */ /* If the caller specifically want to peek, return */ if (peekonly) { - memcpy(msg, &msg_tmp, sizeof(*msg)); + memcpy_fromio(msg, &msg_tmp, sizeof(*msg)); goto peekout; } @@ -401,24 +401,24 @@ int saa7164_bus_get(struct saa7164_dev *dev, tmComResInfo_t* msg, void *buf, if (space_rem < sizeof(*msg)) { /* msg wraps around the ring */ - memcpy(msg, bus->m_pdwGetRing + curr_grp, space_rem); - memcpy((u8 *)msg + space_rem, bus->m_pdwGetRing, + memcpy_fromio(msg, bus->m_pdwGetRing + curr_grp, space_rem); + memcpy_fromio((u8 *)msg + space_rem, bus->m_pdwGetRing, sizeof(*msg) - space_rem); if (buf) - memcpy(buf, bus->m_pdwGetRing + sizeof(*msg) - + memcpy_fromio(buf, bus->m_pdwGetRing + sizeof(*msg) - space_rem, buf_size); } else if (space_rem == sizeof(*msg)) { - memcpy(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg)); + memcpy_fromio(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg)); if (buf) memcpy(buf, bus->m_pdwGetRing, buf_size); } else { /* Additional data wraps around the ring */ - memcpy(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg)); + memcpy_fromio(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg)); if (buf) { - memcpy(buf, bus->m_pdwGetRing + curr_grp + + memcpy_fromio(buf, bus->m_pdwGetRing + curr_grp + sizeof(*msg), space_rem - sizeof(*msg)); - memcpy(buf + space_rem - sizeof(*msg), + memcpy_fromio(buf + space_rem - sizeof(*msg), bus->m_pdwGetRing, bytes_to_read - space_rem); } @@ -427,9 +427,9 @@ int saa7164_bus_get(struct saa7164_dev *dev, tmComResInfo_t* msg, void *buf, } else { /* No wrapping */ - memcpy(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg)); + memcpy_fromio(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg)); if (buf) - memcpy(buf, bus->m_pdwGetRing + curr_grp + sizeof(*msg), + memcpy_fromio(buf, bus->m_pdwGetRing + curr_grp + sizeof(*msg), buf_size); } diff --git a/drivers/media/video/saa7164/saa7164-core.c b/drivers/media/video/saa7164/saa7164-core.c index e96bbe4698b..79e1a2ee7e9 100644 --- a/drivers/media/video/saa7164/saa7164-core.c +++ b/drivers/media/video/saa7164/saa7164-core.c @@ -72,6 +72,28 @@ LIST_HEAD(saa7164_devlist); #define INT_SIZE 16 +void saa7164_dumphex16FF(struct saa7164_dev *dev, u8 *buf, int len) +{ + int i; + u8 tmp[16]; + memset(&tmp[0], 0xff, sizeof(tmp)); + + printk(KERN_INFO "--------------------> " + "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n"); + + for (i = 0; i < len; i += 16) { + if (memcmp(&tmp, buf + i, sizeof(tmp)) != 0) { + printk(KERN_INFO " [0x%08x] " + "%02x %02x %02x %02x %02x %02x %02x %02x " + "%02x %02x %02x %02x %02x %02x %02x %02x\n", i, + *(buf+i+0), *(buf+i+1), *(buf+i+2), *(buf+i+3), + *(buf+i+4), *(buf+i+5), *(buf+i+6), *(buf+i+7), + *(buf+i+8), *(buf+i+9), *(buf+i+10), *(buf+i+11), + *(buf+i+12), *(buf+i+13), *(buf+i+14), *(buf+i+15)); + } + } +} + static void saa7164_ts_verifier(struct saa7164_buffer *buf) { struct saa7164_port *port = buf->port; @@ -216,6 +238,7 @@ static void saa7164_work_enchandler(struct work_struct *w) struct saa7164_user_buffer *ubuf; struct list_head *c, *n; int wp, rp, i = 0; + u32 crc, ok = 0; u8 *p; port->last_svc_msecs_diff = port->last_svc_msecs; @@ -277,10 +300,19 @@ static void saa7164_work_enchandler(struct work_struct *w) saa7164_dumphex16(dev, p + buf->actual_size - 32, 64); } + if (buf->idx == wp) { + /* Ignore this, it's being updated currently by the dma engine */ + } else if (buf->idx == rp) { + + crc = crc32(0, buf->cpu, buf->actual_size); + if (crc != port->shadow_crc[rp]) + printk(KERN_ERR "%s crc didn't match shadow was 0x%x now 0x%x\n", + __func__, port->shadow_crc[rp], crc); + /* Found the buffer, deal with it */ - dprintk(DBGLVL_IRQ, "%s() wp: %d processing: %d\n", - __func__, wp, rp); + dprintk(DBGLVL_IRQ, "%s() wp: %d processing: %d crc32: 0x%x\n", + __func__, wp, rp, buf->crc); /* Validate the incoming buffer content */ if (port->encoder_params.stream_type == V4L2_MPEG_STREAM_TYPE_MPEG2_TS) @@ -293,9 +325,23 @@ static void saa7164_work_enchandler(struct work_struct *w) ubuf = list_first_entry(&port->list_buf_free.list, struct saa7164_user_buffer, list); - if (ubuf->actual_size == buf->actual_size) { - memcpy(ubuf->data, buf->cpu, - ubuf->actual_size); + if (ubuf->actual_size >= buf->actual_size) { + memcpy(ubuf->data, port->shadow_buf[rp], 312 * 188); + + /* Throw a new checksum on the read buffer */ + ubuf->crc = crc32(0, ubuf->data, ubuf->actual_size); + + if ((crc == port->shadow_crc[rp]) && (crc == ubuf->crc)) + ok = 1; + else + ok = 0; + + if (ok == 0) + printk(KERN_ERR + "rp: %d dmacrc: 0x%08x shadcrc: 0x%08x ubufcrc: 0x%08x %s\n", + rp, buf->crc, port->shadow_crc[rp], ubuf->crc, + ok ? "crcgood" : "crcbad"); + } else { printk(KERN_ERR "buf %p actual fails match\n", buf); } @@ -315,9 +361,21 @@ static void saa7164_work_enchandler(struct work_struct *w) /* Ensure offset into buffer remains 0, fill buffer * with known bad data. */ saa7164_buffer_zero_offsets(port, rp); - memset(buf->cpu, 0xff, buf->pci_size); + memset_io(buf->cpu, 0xff, buf->pci_size); + buf->crc = crc32(0, buf->cpu, buf->actual_size); + +// break; + } else { + /* Validate all other checksums, on previous buffers - they should never change */ + crc = crc32(0, buf->cpu, buf->actual_size); + if (crc != buf->crc) { + printk(KERN_ERR "buf[%d].crc became invalid, was 0x%x became 0x%x rp: %d wp: %d\n", + buf->idx, buf->crc, crc, rp, wp); + //saa7164_dumphex16FF(dev, (u8 *)buf->cpu, buf->actual_size); + saa7164_dumphex16FF(dev, (u8 *)buf->cpu, 256); + buf->crc = crc; + } - break; } } @@ -332,7 +390,6 @@ static void saa7164_work_enchandler(struct work_struct *w) print_histogram = 64 + port->nr; } } - static void saa7164_work_cmdhandler(struct work_struct *w) { struct saa7164_dev *dev = container_of(w, struct saa7164_dev, workcmd); @@ -354,7 +411,11 @@ static void saa7164_buffer_deliver(struct saa7164_buffer *buf) static irqreturn_t saa7164_irq_encoder(struct saa7164_port *port) { struct saa7164_dev *dev = port->dev; - int wp, rp; + struct saa7164_buffer *buf; + struct saa7164_user_buffer *ubuf; + struct list_head *c, *n; + int wp, rp, i = 0; + u8 *p; /* Find the current write point from the hardware */ wp = saa7164_readl(port->bufcounter); @@ -400,7 +461,48 @@ static irqreturn_t saa7164_irq_encoder(struct saa7164_port *port) port->last_irq_wp, port->last_irq_rp ); + /* Find the used buffer, shadow copy it before we've + * acked the interrupt. + */ +// mutex_lock(&port->dmaqueue_lock); + list_for_each_safe(c, n, &port->dmaqueue.list) { + + buf = list_entry(c, struct saa7164_buffer, list); + if (i++ > port->hwcfg.buffercount) { + printk(KERN_ERR "%s() illegal i count %d\n", + __func__, i); + break; + } + + p = (u8 *)buf->cpu; + if ( (*(p + buf->actual_size + 0) != 0xff) || + (*(p + buf->actual_size + 1) != 0xff) || + (*(p + buf->actual_size + 2) != 0xff) || + (*(p + buf->actual_size + 3) != 0xff) || + (*(p + buf->actual_size + 0x10) != 0xff) || + (*(p + buf->actual_size + 0x11) != 0xff) || + (*(p + buf->actual_size + 0x12) != 0xff) || + (*(p + buf->actual_size + 0x13) != 0xff) ) + { + printk(KERN_ERR "buf %p failed guard check\n", buf); + saa7164_dumphex16(dev, p + buf->actual_size - 32, 64); + } + + if (buf->idx == rp) { + + memcpy_fromio(port->shadow_buf[rp], buf->cpu, 312 * 188); + port->shadow_crc[rp] = crc32(0, port->shadow_buf[rp], 312 * 188); + buf->crc = crc32(0, buf->cpu, 312 * 188); + + if (port->shadow_crc[rp] != buf->crc) + printk(KERN_ERR "%s() crc check failed 0x%x vs 0x%x\n", + __func__, port->shadow_crc[rp], buf->crc); + break; + } + + } +// mutex_unlock(&port->dmaqueue_lock); schedule_work(&port->workenc); return 0; @@ -693,10 +795,10 @@ static void saa7164_dump_busdesc(struct saa7164_dev *dev) */ static void saa7164_get_descriptors(struct saa7164_dev *dev) { - memcpy(&dev->hwdesc, dev->bmmio, sizeof(tmComResHWDescr_t)); - memcpy(&dev->intfdesc, dev->bmmio + sizeof(tmComResHWDescr_t), + memcpy_fromio(&dev->hwdesc, dev->bmmio, sizeof(tmComResHWDescr_t)); + memcpy_fromio(&dev->intfdesc, dev->bmmio + sizeof(tmComResHWDescr_t), sizeof(tmComResInterfaceDescr_t)); - memcpy(&dev->busdesc, dev->bmmio + dev->intfdesc.BARLocation, + memcpy_fromio(&dev->busdesc, dev->bmmio + dev->intfdesc.BARLocation, sizeof(tmComResBusDescr_t)); if (dev->hwdesc.bLength != sizeof(tmComResHWDescr_t)) { @@ -742,6 +844,7 @@ static int get_resources(struct saa7164_dev *dev) static int saa7164_port_init(struct saa7164_dev *dev, int portnr) { struct saa7164_port *port = 0; + int i; if ((portnr < 0) || (portnr >= SAA7164_MAX_PORTS)) BUG(); @@ -780,6 +883,18 @@ static int saa7164_port_init(struct saa7164_dev *dev, int portnr) saa7164_histogram_reset(&port->poll_interval, "encoder poll() intervals"); + if (port->type == SAA7164_MPEG_ENCODER) { + for (i = 0; i < 8; i ++) { + port->shadow_buf[i] = kzalloc(312 * 188, GFP_KERNEL); + if (port->shadow_buf[i] == 0) + printk(KERN_ERR "%s() shadow_buf ENOMEM\n", __func__); + else { + memset(port->shadow_buf[i], 0xff, 312 * 188); + port->shadow_crc[i] = crc32(0, port->shadow_buf[i], 312 * 188); + } + } + } + return 0; } @@ -1057,6 +1172,8 @@ static void saa7164_shutdown(struct saa7164_dev *dev) static void __devexit saa7164_finidev(struct pci_dev *pci_dev) { struct saa7164_dev *dev = pci_get_drvdata(pci_dev); + struct saa7164_port *port; + int i; saa7164_histogram_print(&dev->ports[ SAA7164_PORT_ENC1 ], &dev->ports[ SAA7164_PORT_ENC1 ].irq_interval); @@ -1071,6 +1188,22 @@ static void __devexit saa7164_finidev(struct pci_dev *pci_dev) saa7164_shutdown(dev); + port = &dev->ports[ SAA7164_PORT_ENC1 ]; + if (port->type == SAA7164_MPEG_ENCODER) { + for (i = 0; i < 8; i ++) { + kfree(port->shadow_buf[i]); + port->shadow_buf[i] = 0; + } + } + port = &dev->ports[ SAA7164_PORT_ENC2 ]; + if (port->type == SAA7164_MPEG_ENCODER) { + for (i = 0; i < 8; i ++) { + kfree(port->shadow_buf[i]); + port->shadow_buf[i] = 0; + } + } + + if (saa7164_boards[dev->board].porta == SAA7164_MPEG_DVB) saa7164_dvb_unregister(&dev->ports[ SAA7164_PORT_TS1 ]); diff --git a/drivers/media/video/saa7164/saa7164-encoder.c b/drivers/media/video/saa7164/saa7164-encoder.c index c61907d0efb..f3ecdc93e20 100644 --- a/drivers/media/video/saa7164/saa7164-encoder.c +++ b/drivers/media/video/saa7164/saa7164-encoder.c @@ -865,6 +865,7 @@ static int saa7164_encoder_start_streaming(struct saa7164_port *port) /* Configure the encoder with any cache values */ saa7164_api_set_encoder(port); + saa7164_api_get_encoder(port); saa7164_buffer_cfg_port(port); @@ -1006,11 +1007,19 @@ struct saa7164_user_buffer *saa7164_enc_next_buf(struct saa7164_port *port) { struct saa7164_user_buffer *buf = 0; struct saa7164_dev *dev = port->dev; + u32 crc; mutex_lock(&port->dmaqueue_lock); if (!list_empty(&port->list_buf_used.list)) { buf = list_first_entry(&port->list_buf_used.list, struct saa7164_user_buffer, list); + + crc = crc32(0, buf->data, buf->actual_size); + if (crc != buf->crc) { + printk(KERN_ERR "%s() buf %p crc became invalid, was 0x%x became 0x%x\n", __func__, + buf, buf->crc, crc); + } + } mutex_unlock(&port->dmaqueue_lock); diff --git a/drivers/media/video/saa7164/saa7164.h b/drivers/media/video/saa7164/saa7164.h index 796d21df52b..a8a29e56b2c 100644 --- a/drivers/media/video/saa7164/saa7164.h +++ b/drivers/media/video/saa7164/saa7164.h @@ -50,6 +50,7 @@ #include <linux/kdev_t.h> #include <linux/version.h> #include <linux/mutex.h> +#include <linux/crc32.h> #include <media/tuner.h> #include <media/tveeprom.h> @@ -194,6 +195,8 @@ struct saa7164_user_buffer { u8 *data; u32 pos; u32 actual_size; + + u32 crc; }; struct saa7164_fw_status { @@ -282,12 +285,13 @@ struct saa7164_buffer { /* A block of page align PCI memory */ u32 pci_size; /* PCI allocation size in bytes */ - u64 *cpu; /* Virtual address */ + u64 __iomem *cpu; /* Virtual address */ dma_addr_t dma; /* Physical address */ + u32 crc; /* Checksum for the entire buffer data */ /* A page table that splits the block into a number of entries */ u32 pt_size; /* PCI allocation size in bytes */ - u64 *pt_cpu; /* Virtual address */ + u64 __iomem *pt_cpu; /* Virtual address */ dma_addr_t pt_dma; /* Physical address */ /* Encoder fops */ @@ -386,6 +390,9 @@ struct saa7164_port { u32 a_cc_errors; u8 last_v_cc; u8 last_a_cc; + + u8 *shadow_buf[8]; + u32 shadow_crc[8]; }; struct saa7164_dev { @@ -536,7 +543,6 @@ extern struct saa7164_user_buffer *saa7164_buffer_alloc_user( extern void saa7164_buffer_dealloc_user(struct saa7164_user_buffer *buf); extern int saa7164_buffer_zero_offsets(struct saa7164_port *port, int i); - /* ----------------------------------------------------------- */ /* saa7164-encoder.c */ int saa7164_encoder_register(struct saa7164_port *port); |