diff options
author | Steven Toth <stoth@kernellabs.com> | 2010-07-31 13:46:51 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2010-10-21 05:54:36 -0400 |
commit | 91d80189fab8c473a392d81b6834b8032191c990 (patch) | |
tree | f9d987bc2e8aa7cccd6739914040798fbecb4889 /drivers | |
parent | 7615e434aefd95181eae099c4f019e021b024eb6 (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')
-rw-r--r-- | drivers/media/video/saa7164/saa7164-core.c | 223 | ||||
-rw-r--r-- | drivers/media/video/saa7164/saa7164.h | 23 |
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 }; | |||
57 | module_param_array(card, int, NULL, 0444); | 57 | module_param_array(card, int, NULL, 0444); |
58 | MODULE_PARM_DESC(card, "card type"); | 58 | MODULE_PARM_DESC(card, "card type"); |
59 | 59 | ||
60 | unsigned int print_histogram = 64; | ||
61 | module_param(print_histogram, int, 0644); | ||
62 | MODULE_PARM_DESC(debug, "print histogram values once"); | ||
63 | |||
60 | static unsigned int saa7164_devcount; | 64 | static unsigned int saa7164_devcount; |
61 | 65 | ||
62 | static DEFINE_MUTEX(devlist); | 66 | static 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 | ||
67 | static void saa7164_work_cmdhandler(struct work_struct *w) | 71 | static 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 | ||
75 | static void saa7164_buffer_deliver(struct saa7164_buffer *buf) | 97 | static 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 */ | 109 | static 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 | ||
85 | static irqreturn_t saa7164_irq_encoder(struct saa7164_port *port) | 131 | static 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 | |||
229 | static 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 | |||
237 | static 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 | |||
247 | static 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 | ||
179 | struct saa7164_histogram_bucket { | ||
180 | u32 val; | ||
181 | u32 count; | ||
182 | u64 update_time; | ||
183 | }; | ||
184 | |||
185 | struct saa7164_histogram { | ||
186 | char name[32]; | ||
187 | struct saa7164_histogram_bucket counter1[64]; | ||
188 | }; | ||
189 | |||
179 | struct saa7164_user_buffer { | 190 | struct 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; |