aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/saa7164
diff options
context:
space:
mode:
authorSteven Toth <stoth@kernellabs.com>2010-07-31 13:46:51 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2010-10-21 05:54:36 -0400
commit91d80189fab8c473a392d81b6834b8032191c990 (patch)
treef9d987bc2e8aa7cccd6739914040798fbecb4889 /drivers/media/video/saa7164
parent7615e434aefd95181eae099c4f019e021b024eb6 (diff)
[media] saa7164: Implement encoder irq handling in a deferred work queue
Signed-off-by: Steven Toth <stoth@kernellabs.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/saa7164')
-rw-r--r--drivers/media/video/saa7164/saa7164-core.c223
-rw-r--r--drivers/media/video/saa7164/saa7164.h23
2 files changed, 217 insertions, 29 deletions
diff --git a/drivers/media/video/saa7164/saa7164-core.c b/drivers/media/video/saa7164/saa7164-core.c
index b8e56d88743f..591a3c101c0f 100644
--- a/drivers/media/video/saa7164/saa7164-core.c
+++ b/drivers/media/video/saa7164/saa7164-core.c
@@ -57,6 +57,10 @@ static unsigned int card[] = {[0 ... (SAA7164_MAXBOARDS - 1)] = UNSET };
57module_param_array(card, int, NULL, 0444); 57module_param_array(card, int, NULL, 0444);
58MODULE_PARM_DESC(card, "card type"); 58MODULE_PARM_DESC(card, "card type");
59 59
60unsigned int print_histogram = 64;
61module_param(print_histogram, int, 0644);
62MODULE_PARM_DESC(debug, "print histogram values once");
63
60static unsigned int saa7164_devcount; 64static unsigned int saa7164_devcount;
61 65
62static DEFINE_MUTEX(devlist); 66static DEFINE_MUTEX(devlist);
@@ -64,49 +68,120 @@ LIST_HEAD(saa7164_devlist);
64 68
65#define INT_SIZE 16 69#define INT_SIZE 16
66 70
67static void saa7164_work_cmdhandler(struct work_struct *w) 71static void saa7164_histogram_reset(struct saa7164_histogram *hg, char *name)
68{ 72{
69 struct saa7164_dev *dev = container_of(w, struct saa7164_dev, workcmd); 73 int i;
70 74
71 /* Wake up any complete commands */ 75 memset(hg, 0, sizeof(struct saa7164_histogram));
72 saa7164_irq_dequeue(dev); 76 strcpy(hg->name, name);
77
78 /* First 30ms x 1ms */
79 for (i = 0; i < 30; i++) {
80 hg->counter1[0 + i].val = i;
81 }
82
83 /* 30 - 200ms x 10ms */
84 for (i = 0; i < 18; i++) {
85 hg->counter1[30 + i].val = 30 + (i * 10);
86 }
87
88 /* 200 - 2000ms x 100ms */
89 for (i = 0; i < 15; i++) {
90 hg->counter1[48 + i].val = 200 + (i * 100);
91 }
92
93 /* Catch all massive value (1hr) */
94 hg->counter1[63].val = 3600000;
73} 95}
74 96
75static void saa7164_buffer_deliver(struct saa7164_buffer *buf) 97static void saa7164_histogram_update(struct saa7164_histogram *hg, u32 val)
76{ 98{
77 struct saa7164_port *port = buf->port; 99 int i;
100 for (i = 0; i < 64; i++ ) {
101 if (val <= hg->counter1[i].val) {
102 hg->counter1[i].count++;
103 hg->counter1[i].update_time = jiffies;
104 break;
105 }
106 }
107}
78 108
79 /* Feed the transport payload into the kernel demux */ 109static void saa7164_histogram_print(struct saa7164_port *port,
80 dvb_dmx_swfilter_packets(&port->dvb.demux, (u8 *)buf->cpu, 110 struct saa7164_histogram *hg)
81 SAA7164_TS_NUMBER_OF_LINES); 111{
112 struct saa7164_dev *dev = port->dev;
113 u32 entries = 0;
114 int i;
115
116 printk(KERN_ERR "Histogram named %s\n", hg->name);
117 for (i = 0; i < 64; i++ ) {
118 if (hg->counter1[i].count == 0)
119 continue;
82 120
121 printk(KERN_ERR " %4d %12d %Ld\n",
122 hg->counter1[i].val,
123 hg->counter1[i].count,
124 hg->counter1[i].update_time);
125
126 entries++;
127 }
128 printk(KERN_ERR "Total: %d\n", entries);
83} 129}
84 130
85static irqreturn_t saa7164_irq_encoder(struct saa7164_port *port) 131static void saa7164_work_enchandler(struct work_struct *w)
86{ 132{
133 struct saa7164_port *port =
134 container_of(w, struct saa7164_port, workenc);
87 struct saa7164_dev *dev = port->dev; 135 struct saa7164_dev *dev = port->dev;
88 struct saa7164_buffer *buf; 136 struct saa7164_buffer *buf;
89 struct saa7164_user_buffer *ubuf; 137 struct saa7164_user_buffer *ubuf;
90 struct list_head *c, *n; 138 struct list_head *c, *n;
91 int wp, i = 0, rp; 139 int wp, rp, i = 0;
92 140
93 /* Find the current write point from the hardware */ 141 port->last_svc_msecs_diff = port->last_svc_msecs;
94 wp = saa7164_readl(port->bufcounter); 142 port->last_svc_msecs = jiffies_to_msecs(jiffies);
95 if (wp > (port->hwcfg.buffercount - 1)) 143 port->last_svc_wp = saa7164_readl(port->bufcounter);
96 BUG(); 144 port->last_svc_rp = port->last_irq_rp;
145 wp = port->last_svc_wp;
146 rp = port->last_svc_rp;
97 147
98 /* Find the previous buffer to the current write point */
99 if (wp == 0)
100 rp = 7;
101 else
102 rp = wp - 1;
103 148
104 /* Lookup the WP in the buffer list */ 149 port->last_svc_msecs_diff = port->last_svc_msecs -
105 /* TODO: turn this into a worker thread */ 150 port->last_svc_msecs_diff;
151
152 saa7164_histogram_update(&port->svc_interval,
153 port->last_svc_msecs_diff);
154
155 port->last_irq_svc_msecs_diff = port->last_svc_msecs -
156 port->last_irq_msecs;
157
158 saa7164_histogram_update(&port->irq_svc_interval,
159 port->last_irq_svc_msecs_diff);
160
161 dprintk(DBGLVL_IRQ,
162 "%s() %Ldms elapsed irq->deferred %Ldms wp: %d rp: %d\n",
163 __func__,
164 port->last_svc_msecs_diff,
165 port->last_irq_svc_msecs_diff,
166 port->last_svc_wp,
167 port->last_svc_rp
168 );
169
170 if ((rp < 0) || (rp > 7)) {
171 printk(KERN_ERR "%s() illegal rp count %d\n", __func__, rp);
172 return;
173 }
174
175 mutex_lock(&port->dmaqueue_lock);
176
106 list_for_each_safe(c, n, &port->dmaqueue.list) { 177 list_for_each_safe(c, n, &port->dmaqueue.list) {
178
107 buf = list_entry(c, struct saa7164_buffer, list); 179 buf = list_entry(c, struct saa7164_buffer, list);
108 if (i++ > port->hwcfg.buffercount) 180 if (i++ > port->hwcfg.buffercount) {
109 BUG(); 181 printk(KERN_ERR "%s() illegal i count %d\n",
182 __func__, i);
183 break;
184 }
110 185
111 if (buf->idx == rp) { 186 if (buf->idx == rp) {
112 /* Found the buffer, deal with it */ 187 /* Found the buffer, deal with it */
@@ -122,15 +197,14 @@ static irqreturn_t saa7164_irq_encoder(struct saa7164_port *port)
122 struct saa7164_user_buffer, list); 197 struct saa7164_user_buffer, list);
123 198
124 if (ubuf->actual_size == buf->actual_size) 199 if (ubuf->actual_size == buf->actual_size)
125 memcpy(ubuf->data, buf->cpu, ubuf->actual_size); 200 memcpy(ubuf->data, buf->cpu,
201 ubuf->actual_size);
126 202
127 /* Requeue the buffer on the free list */ 203 /* Requeue the buffer on the free list */
128 ubuf->pos = 0; 204 ubuf->pos = 0;
129 205
130 206 list_move_tail(&ubuf->list,
131// mutex_lock(&port->dmaqueue_lock); 207 &port->list_buf_used.list);
132 list_move_tail(&ubuf->list, &port->list_buf_used.list);
133// mutex_unlock(&port->dmaqueue_lock);
134 208
135 /* Flag any userland waiters */ 209 /* Flag any userland waiters */
136 wake_up_interruptible(&port->wait_read); 210 wake_up_interruptible(&port->wait_read);
@@ -142,6 +216,81 @@ static irqreturn_t saa7164_irq_encoder(struct saa7164_port *port)
142 } 216 }
143 217
144 } 218 }
219 mutex_unlock(&port->dmaqueue_lock);
220
221 if (print_histogram == port->nr) {
222 saa7164_histogram_print(port, &port->irq_interval);
223 saa7164_histogram_print(port, &port->svc_interval);
224 saa7164_histogram_print(port, &port->irq_svc_interval);
225 print_histogram = 64 + port->nr;
226 }
227}
228
229static void saa7164_work_cmdhandler(struct work_struct *w)
230{
231 struct saa7164_dev *dev = container_of(w, struct saa7164_dev, workcmd);
232
233 /* Wake up any complete commands */
234 saa7164_irq_dequeue(dev);
235}
236
237static void saa7164_buffer_deliver(struct saa7164_buffer *buf)
238{
239 struct saa7164_port *port = buf->port;
240
241 /* Feed the transport payload into the kernel demux */
242 dvb_dmx_swfilter_packets(&port->dvb.demux, (u8 *)buf->cpu,
243 SAA7164_TS_NUMBER_OF_LINES);
244
245}
246
247static irqreturn_t saa7164_irq_encoder(struct saa7164_port *port)
248{
249 struct saa7164_dev *dev = port->dev;
250 int wp, rp;
251
252 /* Find the current write point from the hardware */
253 wp = saa7164_readl(port->bufcounter);
254 if (wp > (port->hwcfg.buffercount - 1)) {
255 printk(KERN_ERR "%s() illegal buf count %d\n", __func__, wp);
256 return 0;
257 }
258
259 /* Find the previous buffer to the current write point */
260 if (wp == 0)
261 rp = 7;
262 else
263 rp = wp - 1;
264
265 if ((rp < 0) || (rp > 7)) {
266 printk(KERN_ERR "%s() illegal rp count %d\n", __func__, rp);
267 return 0;
268 }
269
270 /* Sore old time */
271 port->last_irq_msecs_diff = port->last_irq_msecs;
272
273 /* Collect new stats */
274 port->last_irq_msecs = jiffies_to_msecs(jiffies);
275 port->last_irq_wp = wp;
276 port->last_irq_rp = rp;
277
278 /* Calculate stats */
279 port->last_irq_msecs_diff = port->last_irq_msecs -
280 port->last_irq_msecs_diff;
281
282 saa7164_histogram_update(&port->irq_interval,
283 port->last_irq_msecs_diff);
284
285 dprintk(DBGLVL_IRQ, "%s() %Ldms elapsed wp: %d rp: %d\n",
286 __func__,
287 port->last_irq_msecs_diff,
288 port->last_irq_wp,
289 port->last_irq_rp
290 );
291
292 schedule_work(&port->workenc);
293
145 return 0; 294 return 0;
146} 295}
147 296
@@ -506,6 +655,15 @@ static int saa7164_port_init(struct saa7164_dev *dev, int portnr)
506 INIT_LIST_HEAD(&port->list_buf_used.list); 655 INIT_LIST_HEAD(&port->list_buf_used.list);
507 INIT_LIST_HEAD(&port->list_buf_free.list); 656 INIT_LIST_HEAD(&port->list_buf_free.list);
508 init_waitqueue_head(&port->wait_read); 657 init_waitqueue_head(&port->wait_read);
658
659 /* We need a deferred interrupt handler for cmd handling */
660 INIT_WORK(&port->workenc, saa7164_work_enchandler);
661
662 saa7164_histogram_reset(&port->irq_interval, "irq intervals");
663 saa7164_histogram_reset(&port->svc_interval, "deferred intervals");
664 saa7164_histogram_reset(&port->irq_svc_interval,
665 "irq to deferred intervals");
666
509 return 0; 667 return 0;
510} 668}
511 669
@@ -784,6 +942,13 @@ static void __devexit saa7164_finidev(struct pci_dev *pci_dev)
784{ 942{
785 struct saa7164_dev *dev = pci_get_drvdata(pci_dev); 943 struct saa7164_dev *dev = pci_get_drvdata(pci_dev);
786 944
945 saa7164_histogram_print(&dev->ports[ SAA7164_PORT_ENC1 ],
946 &dev->ports[ SAA7164_PORT_ENC1 ].irq_interval);
947 saa7164_histogram_print(&dev->ports[ SAA7164_PORT_ENC1 ],
948 &dev->ports[ SAA7164_PORT_ENC1 ].svc_interval);
949 saa7164_histogram_print(&dev->ports[ SAA7164_PORT_ENC1 ],
950 &dev->ports[ SAA7164_PORT_ENC1 ].irq_svc_interval);
951
787 saa7164_shutdown(dev); 952 saa7164_shutdown(dev);
788 953
789 if (saa7164_boards[dev->board].porta == SAA7164_MPEG_DVB) 954 if (saa7164_boards[dev->board].porta == SAA7164_MPEG_DVB)
diff --git a/drivers/media/video/saa7164/saa7164.h b/drivers/media/video/saa7164/saa7164.h
index ad3907244020..a262875a39e3 100644
--- a/drivers/media/video/saa7164/saa7164.h
+++ b/drivers/media/video/saa7164/saa7164.h
@@ -176,6 +176,17 @@ struct saa7164_fh {
176 atomic_t v4l_reading; 176 atomic_t v4l_reading;
177}; 177};
178 178
179struct saa7164_histogram_bucket {
180 u32 val;
181 u32 count;
182 u64 update_time;
183};
184
185struct saa7164_histogram {
186 char name[32];
187 struct saa7164_histogram_bucket counter1[64];
188};
189
179struct saa7164_user_buffer { 190struct saa7164_user_buffer {
180 struct list_head list; 191 struct list_head list;
181 192
@@ -308,6 +319,16 @@ struct saa7164_port {
308 struct mutex dmaqueue_lock; 319 struct mutex dmaqueue_lock;
309 struct saa7164_buffer dmaqueue; 320 struct saa7164_buffer dmaqueue;
310 321
322 u64 last_irq_msecs, last_svc_msecs;
323 u64 last_irq_msecs_diff, last_svc_msecs_diff;
324 u32 last_irq_wp, last_svc_wp;
325 u32 last_irq_rp, last_svc_rp;
326 u64 last_irq_svc_msecs_diff;
327
328 struct saa7164_histogram irq_interval;
329 struct saa7164_histogram svc_interval;
330 struct saa7164_histogram irq_svc_interval;
331
311 /* --- DVB Transport Specific --- */ 332 /* --- DVB Transport Specific --- */
312 struct saa7164_dvb dvb; 333 struct saa7164_dvb dvb;
313 334
@@ -338,6 +359,8 @@ struct saa7164_port {
338 tmComResExtDevDescrHeader_t ifunit; 359 tmComResExtDevDescrHeader_t ifunit;
339 tmComResTunerDescrHeader_t tunerunit; 360 tmComResTunerDescrHeader_t tunerunit;
340 361
362 struct work_struct workenc;
363
341 /* V4L */ 364 /* V4L */
342 struct saa7164_encoder_params encoder_params; 365 struct saa7164_encoder_params encoder_params;
343 struct video_device *v4l_device; 366 struct video_device *v4l_device;