diff options
author | Andy Walls <awalls@md.metrocast.net> | 2010-07-19 00:19:43 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2010-08-08 22:42:55 -0400 |
commit | dbe83a3b921328e12b2abe894fc692afba293d7f (patch) | |
tree | e13443d29b6b929a61584b06dec5f3eff84e2111 | |
parent | 98d109f90fc02ce8baf1c2471ffcf8d66fb0d8e6 (diff) |
V4L/DVB: cx23885: Protect PCI interrupt mask manipulations with a spinlock
This patch encapsulates access to the PCI_INT_MSK register and
dev->pci_irqmask variable and protects them with a spinlock.
This is needed because both the hard IRQ handler and a workhandler
will need to manipulate the mask to disable the AV_CORE interrupt.
Signed-off-by: Andy Walls <awalls@md.metrocast.net>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r-- | drivers/media/video/cx23885/cx23885-cards.c | 17 | ||||
-rw-r--r-- | drivers/media/video/cx23885/cx23885-core.c | 94 | ||||
-rw-r--r-- | drivers/media/video/cx23885/cx23885-vbi.c | 2 | ||||
-rw-r--r-- | drivers/media/video/cx23885/cx23885-video.c | 7 | ||||
-rw-r--r-- | drivers/media/video/cx23885/cx23885.h | 5 |
5 files changed, 103 insertions, 22 deletions
diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index 294a7530caf7..d72b48ef940e 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c | |||
@@ -1012,7 +1012,6 @@ int cx23885_ir_init(struct cx23885_dev *dev) | |||
1012 | dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_888_IR); | 1012 | dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_888_IR); |
1013 | v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config, | 1013 | v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config, |
1014 | ir_rxtx_pin_cfg_count, ir_rxtx_pin_cfg); | 1014 | ir_rxtx_pin_cfg_count, ir_rxtx_pin_cfg); |
1015 | dev->pci_irqmask |= PCI_MSK_IR; | ||
1016 | /* | 1015 | /* |
1017 | * For these boards we need to invert the Tx output via the | 1016 | * For these boards we need to invert the Tx output via the |
1018 | * IR controller to have the LED off while idle | 1017 | * IR controller to have the LED off while idle |
@@ -1033,7 +1032,6 @@ int cx23885_ir_init(struct cx23885_dev *dev) | |||
1033 | } | 1032 | } |
1034 | v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config, | 1033 | v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config, |
1035 | ir_rx_pin_cfg_count, ir_rx_pin_cfg); | 1034 | ir_rx_pin_cfg_count, ir_rx_pin_cfg); |
1036 | dev->pci_irqmask |= PCI_MSK_AV_CORE; | ||
1037 | break; | 1035 | break; |
1038 | case CX23885_BOARD_HAUPPAUGE_HVR1250: | 1036 | case CX23885_BOARD_HAUPPAUGE_HVR1250: |
1039 | dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_AV_CORE); | 1037 | dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_AV_CORE); |
@@ -1043,7 +1041,6 @@ int cx23885_ir_init(struct cx23885_dev *dev) | |||
1043 | } | 1041 | } |
1044 | v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config, | 1042 | v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config, |
1045 | ir_rxtx_pin_cfg_count, ir_rxtx_pin_cfg); | 1043 | ir_rxtx_pin_cfg_count, ir_rxtx_pin_cfg); |
1046 | dev->pci_irqmask |= PCI_MSK_AV_CORE; | ||
1047 | break; | 1044 | break; |
1048 | case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP: | 1045 | case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP: |
1049 | request_module("ir-kbd-i2c"); | 1046 | request_module("ir-kbd-i2c"); |
@@ -1058,15 +1055,13 @@ void cx23885_ir_fini(struct cx23885_dev *dev) | |||
1058 | switch (dev->board) { | 1055 | switch (dev->board) { |
1059 | case CX23885_BOARD_HAUPPAUGE_HVR1850: | 1056 | case CX23885_BOARD_HAUPPAUGE_HVR1850: |
1060 | case CX23885_BOARD_HAUPPAUGE_HVR1290: | 1057 | case CX23885_BOARD_HAUPPAUGE_HVR1290: |
1061 | dev->pci_irqmask &= ~PCI_MSK_IR; | 1058 | cx23885_irq_remove(dev, PCI_MSK_IR); |
1062 | cx_clear(PCI_INT_MSK, PCI_MSK_IR); | ||
1063 | cx23888_ir_remove(dev); | 1059 | cx23888_ir_remove(dev); |
1064 | dev->sd_ir = NULL; | 1060 | dev->sd_ir = NULL; |
1065 | break; | 1061 | break; |
1066 | case CX23885_BOARD_TEVII_S470: | 1062 | case CX23885_BOARD_TEVII_S470: |
1067 | case CX23885_BOARD_HAUPPAUGE_HVR1250: | 1063 | case CX23885_BOARD_HAUPPAUGE_HVR1250: |
1068 | dev->pci_irqmask &= ~PCI_MSK_AV_CORE; | 1064 | cx23885_irq_remove(dev, PCI_MSK_AV_CORE); |
1069 | cx_clear(PCI_INT_MSK, PCI_MSK_AV_CORE); | ||
1070 | /* sd_ir is a duplicate pointer to the AV Core, just clear it */ | 1065 | /* sd_ir is a duplicate pointer to the AV Core, just clear it */ |
1071 | dev->sd_ir = NULL; | 1066 | dev->sd_ir = NULL; |
1072 | break; | 1067 | break; |
@@ -1078,13 +1073,13 @@ void cx23885_ir_pci_int_enable(struct cx23885_dev *dev) | |||
1078 | switch (dev->board) { | 1073 | switch (dev->board) { |
1079 | case CX23885_BOARD_HAUPPAUGE_HVR1850: | 1074 | case CX23885_BOARD_HAUPPAUGE_HVR1850: |
1080 | case CX23885_BOARD_HAUPPAUGE_HVR1290: | 1075 | case CX23885_BOARD_HAUPPAUGE_HVR1290: |
1081 | if (dev->sd_ir && (dev->pci_irqmask & PCI_MSK_IR)) | 1076 | if (dev->sd_ir) |
1082 | cx_set(PCI_INT_MSK, PCI_MSK_IR); | 1077 | cx23885_irq_add_enable(dev, PCI_MSK_IR); |
1083 | break; | 1078 | break; |
1084 | case CX23885_BOARD_TEVII_S470: | 1079 | case CX23885_BOARD_TEVII_S470: |
1085 | case CX23885_BOARD_HAUPPAUGE_HVR1250: | 1080 | case CX23885_BOARD_HAUPPAUGE_HVR1250: |
1086 | if (dev->sd_ir && (dev->pci_irqmask & PCI_MSK_AV_CORE)) | 1081 | if (dev->sd_ir) |
1087 | cx_set(PCI_INT_MSK, PCI_MSK_AV_CORE); | 1082 | cx23885_irq_add_enable(dev, PCI_MSK_AV_CORE); |
1088 | break; | 1083 | break; |
1089 | } | 1084 | } |
1090 | } | 1085 | } |
diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 93e7afb98889..0765abf4e42e 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c | |||
@@ -299,6 +299,83 @@ static struct sram_channel cx23887_sram_channels[] = { | |||
299 | }, | 299 | }, |
300 | }; | 300 | }; |
301 | 301 | ||
302 | void cx23885_irq_add(struct cx23885_dev *dev, u32 mask) | ||
303 | { | ||
304 | unsigned long flags; | ||
305 | spin_lock_irqsave(&dev->pci_irqmask_lock, flags); | ||
306 | |||
307 | dev->pci_irqmask |= mask; | ||
308 | |||
309 | spin_unlock_irqrestore(&dev->pci_irqmask_lock, flags); | ||
310 | } | ||
311 | |||
312 | void cx23885_irq_add_enable(struct cx23885_dev *dev, u32 mask) | ||
313 | { | ||
314 | unsigned long flags; | ||
315 | spin_lock_irqsave(&dev->pci_irqmask_lock, flags); | ||
316 | |||
317 | dev->pci_irqmask |= mask; | ||
318 | cx_set(PCI_INT_MSK, mask); | ||
319 | |||
320 | spin_unlock_irqrestore(&dev->pci_irqmask_lock, flags); | ||
321 | } | ||
322 | |||
323 | void cx23885_irq_enable(struct cx23885_dev *dev, u32 mask) | ||
324 | { | ||
325 | u32 v; | ||
326 | unsigned long flags; | ||
327 | spin_lock_irqsave(&dev->pci_irqmask_lock, flags); | ||
328 | |||
329 | v = mask & dev->pci_irqmask; | ||
330 | if (v) | ||
331 | cx_set(PCI_INT_MSK, v); | ||
332 | |||
333 | spin_unlock_irqrestore(&dev->pci_irqmask_lock, flags); | ||
334 | } | ||
335 | |||
336 | static inline void cx23885_irq_enable_all(struct cx23885_dev *dev) | ||
337 | { | ||
338 | cx23885_irq_enable(dev, 0xffffffff); | ||
339 | } | ||
340 | |||
341 | void cx23885_irq_disable(struct cx23885_dev *dev, u32 mask) | ||
342 | { | ||
343 | unsigned long flags; | ||
344 | spin_lock_irqsave(&dev->pci_irqmask_lock, flags); | ||
345 | |||
346 | cx_clear(PCI_INT_MSK, mask); | ||
347 | |||
348 | spin_unlock_irqrestore(&dev->pci_irqmask_lock, flags); | ||
349 | } | ||
350 | |||
351 | static inline void cx23885_irq_disable_all(struct cx23885_dev *dev) | ||
352 | { | ||
353 | cx23885_irq_disable(dev, 0xffffffff); | ||
354 | } | ||
355 | |||
356 | void cx23885_irq_remove(struct cx23885_dev *dev, u32 mask) | ||
357 | { | ||
358 | unsigned long flags; | ||
359 | spin_lock_irqsave(&dev->pci_irqmask_lock, flags); | ||
360 | |||
361 | dev->pci_irqmask &= ~mask; | ||
362 | cx_clear(PCI_INT_MSK, mask); | ||
363 | |||
364 | spin_unlock_irqrestore(&dev->pci_irqmask_lock, flags); | ||
365 | } | ||
366 | |||
367 | static u32 cx23885_irq_get_mask(struct cx23885_dev *dev) | ||
368 | { | ||
369 | u32 v; | ||
370 | unsigned long flags; | ||
371 | spin_lock_irqsave(&dev->pci_irqmask_lock, flags); | ||
372 | |||
373 | v = cx_read(PCI_INT_MSK); | ||
374 | |||
375 | spin_unlock_irqrestore(&dev->pci_irqmask_lock, flags); | ||
376 | return v; | ||
377 | } | ||
378 | |||
302 | static int cx23885_risc_decode(u32 risc) | 379 | static int cx23885_risc_decode(u32 risc) |
303 | { | 380 | { |
304 | static char *instr[16] = { | 381 | static char *instr[16] = { |
@@ -548,7 +625,7 @@ static void cx23885_shutdown(struct cx23885_dev *dev) | |||
548 | cx_write(UART_CTL, 0); | 625 | cx_write(UART_CTL, 0); |
549 | 626 | ||
550 | /* Disable Interrupts */ | 627 | /* Disable Interrupts */ |
551 | cx_write(PCI_INT_MSK, 0); | 628 | cx23885_irq_disable_all(dev); |
552 | cx_write(VID_A_INT_MSK, 0); | 629 | cx_write(VID_A_INT_MSK, 0); |
553 | cx_write(VID_B_INT_MSK, 0); | 630 | cx_write(VID_B_INT_MSK, 0); |
554 | cx_write(VID_C_INT_MSK, 0); | 631 | cx_write(VID_C_INT_MSK, 0); |
@@ -774,6 +851,8 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) | |||
774 | { | 851 | { |
775 | int i; | 852 | int i; |
776 | 853 | ||
854 | spin_lock_init(&dev->pci_irqmask_lock); | ||
855 | |||
777 | mutex_init(&dev->lock); | 856 | mutex_init(&dev->lock); |
778 | mutex_init(&dev->gpio_lock); | 857 | mutex_init(&dev->gpio_lock); |
779 | 858 | ||
@@ -820,9 +899,9 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) | |||
820 | 899 | ||
821 | dev->pci_bus = dev->pci->bus->number; | 900 | dev->pci_bus = dev->pci->bus->number; |
822 | dev->pci_slot = PCI_SLOT(dev->pci->devfn); | 901 | dev->pci_slot = PCI_SLOT(dev->pci->devfn); |
823 | dev->pci_irqmask = 0x001f00; | 902 | cx23885_irq_add(dev, 0x001f00); |
824 | if (cx23885_boards[dev->board].cimax > 0) | 903 | if (cx23885_boards[dev->board].cimax > 0) |
825 | dev->pci_irqmask |= 0x01800000; /* for CiMaxes */ | 904 | cx23885_irq_add(dev, 0x01800000); /* for CiMaxes */ |
826 | 905 | ||
827 | /* External Master 1 Bus */ | 906 | /* External Master 1 Bus */ |
828 | dev->i2c_bus[0].nr = 0; | 907 | dev->i2c_bus[0].nr = 0; |
@@ -1156,7 +1235,7 @@ static void cx23885_tsport_reg_dump(struct cx23885_tsport *port) | |||
1156 | dprintk(1, "%s() DEV_CNTRL2 0x%08X\n", __func__, | 1235 | dprintk(1, "%s() DEV_CNTRL2 0x%08X\n", __func__, |
1157 | cx_read(DEV_CNTRL2)); | 1236 | cx_read(DEV_CNTRL2)); |
1158 | dprintk(1, "%s() PCI_INT_MSK 0x%08X\n", __func__, | 1237 | dprintk(1, "%s() PCI_INT_MSK 0x%08X\n", __func__, |
1159 | cx_read(PCI_INT_MSK)); | 1238 | cx23885_irq_get_mask(dev)); |
1160 | dprintk(1, "%s() AUD_INT_INT_MSK 0x%08X\n", __func__, | 1239 | dprintk(1, "%s() AUD_INT_INT_MSK 0x%08X\n", __func__, |
1161 | cx_read(AUDIO_INT_INT_MSK)); | 1240 | cx_read(AUDIO_INT_INT_MSK)); |
1162 | dprintk(1, "%s() AUD_INT_DMA_CTL 0x%08X\n", __func__, | 1241 | dprintk(1, "%s() AUD_INT_DMA_CTL 0x%08X\n", __func__, |
@@ -1292,7 +1371,8 @@ static int cx23885_start_dma(struct cx23885_tsport *port, | |||
1292 | dprintk(1, "%s() enabling TS int's and DMA\n", __func__); | 1371 | dprintk(1, "%s() enabling TS int's and DMA\n", __func__); |
1293 | cx_set(port->reg_ts_int_msk, port->ts_int_msk_val); | 1372 | cx_set(port->reg_ts_int_msk, port->ts_int_msk_val); |
1294 | cx_set(port->reg_dma_ctl, port->dma_ctl_val); | 1373 | cx_set(port->reg_dma_ctl, port->dma_ctl_val); |
1295 | cx_set(PCI_INT_MSK, dev->pci_irqmask | port->pci_irqmask); | 1374 | cx23885_irq_add(dev, port->pci_irqmask); |
1375 | cx23885_irq_enable_all(dev); | ||
1296 | break; | 1376 | break; |
1297 | default: | 1377 | default: |
1298 | BUG(); | 1378 | BUG(); |
@@ -1653,7 +1733,7 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) | |||
1653 | bool subdev_handled; | 1733 | bool subdev_handled; |
1654 | 1734 | ||
1655 | pci_status = cx_read(PCI_INT_STAT); | 1735 | pci_status = cx_read(PCI_INT_STAT); |
1656 | pci_mask = cx_read(PCI_INT_MSK); | 1736 | pci_mask = cx23885_irq_get_mask(dev); |
1657 | vida_status = cx_read(VID_A_INT_STAT); | 1737 | vida_status = cx_read(VID_A_INT_STAT); |
1658 | vida_mask = cx_read(VID_A_INT_MSK); | 1738 | vida_mask = cx_read(VID_A_INT_MSK); |
1659 | ts1_status = cx_read(VID_B_INT_STAT); | 1739 | ts1_status = cx_read(VID_B_INT_STAT); |
@@ -1981,7 +2061,7 @@ static int __devinit cx23885_initdev(struct pci_dev *pci_dev, | |||
1981 | 2061 | ||
1982 | switch (dev->board) { | 2062 | switch (dev->board) { |
1983 | case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: | 2063 | case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: |
1984 | cx_set(PCI_INT_MSK, 0x01800000); /* for NetUP */ | 2064 | cx23885_irq_add_enable(dev, 0x01800000); /* for NetUP */ |
1985 | break; | 2065 | break; |
1986 | } | 2066 | } |
1987 | 2067 | ||
diff --git a/drivers/media/video/cx23885/cx23885-vbi.c b/drivers/media/video/cx23885/cx23885-vbi.c index 708a8c766d1a..c0b60382ad13 100644 --- a/drivers/media/video/cx23885/cx23885-vbi.c +++ b/drivers/media/video/cx23885/cx23885-vbi.c | |||
@@ -74,7 +74,7 @@ static int cx23885_start_vbi_dma(struct cx23885_dev *dev, | |||
74 | q->count = 1; | 74 | q->count = 1; |
75 | 75 | ||
76 | /* enable irqs */ | 76 | /* enable irqs */ |
77 | cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | 0x01); | 77 | cx23885_irq_add_enable(dev, 0x01); |
78 | cx_set(VID_A_INT_MSK, 0x000022); | 78 | cx_set(VID_A_INT_MSK, 0x000022); |
79 | 79 | ||
80 | /* start dma */ | 80 | /* start dma */ |
diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c index 25194553c529..da66e5f8d91d 100644 --- a/drivers/media/video/cx23885/cx23885-video.c +++ b/drivers/media/video/cx23885/cx23885-video.c | |||
@@ -441,7 +441,7 @@ static int cx23885_start_video_dma(struct cx23885_dev *dev, | |||
441 | q->count = 1; | 441 | q->count = 1; |
442 | 442 | ||
443 | /* enable irq */ | 443 | /* enable irq */ |
444 | cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | 0x01); | 444 | cx23885_irq_add_enable(dev, 0x01); |
445 | cx_set(VID_A_INT_MSK, 0x000011); | 445 | cx_set(VID_A_INT_MSK, 0x000011); |
446 | 446 | ||
447 | /* start dma */ | 447 | /* start dma */ |
@@ -1465,7 +1465,7 @@ static const struct v4l2_file_operations radio_fops = { | |||
1465 | void cx23885_video_unregister(struct cx23885_dev *dev) | 1465 | void cx23885_video_unregister(struct cx23885_dev *dev) |
1466 | { | 1466 | { |
1467 | dprintk(1, "%s()\n", __func__); | 1467 | dprintk(1, "%s()\n", __func__); |
1468 | cx_clear(PCI_INT_MSK, 1); | 1468 | cx23885_irq_remove(dev, 0x01); |
1469 | 1469 | ||
1470 | if (dev->video_dev) { | 1470 | if (dev->video_dev) { |
1471 | if (video_is_registered(dev->video_dev)) | 1471 | if (video_is_registered(dev->video_dev)) |
@@ -1502,7 +1502,8 @@ int cx23885_video_register(struct cx23885_dev *dev) | |||
1502 | VID_A_DMA_CTL, 0x11, 0x00); | 1502 | VID_A_DMA_CTL, 0x11, 0x00); |
1503 | 1503 | ||
1504 | /* Don't enable VBI yet */ | 1504 | /* Don't enable VBI yet */ |
1505 | cx_set(PCI_INT_MSK, 1); | 1505 | |
1506 | cx23885_irq_add_enable(dev, 0x01); | ||
1506 | 1507 | ||
1507 | if (TUNER_ABSENT != dev->tuner_type) { | 1508 | if (TUNER_ABSENT != dev->tuner_type) { |
1508 | struct v4l2_subdev *sd = NULL; | 1509 | struct v4l2_subdev *sd = NULL; |
diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index 460f430d028f..5bf6ed09c970 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h | |||
@@ -325,6 +325,7 @@ struct cx23885_dev { | |||
325 | u32 __iomem *lmmio; | 325 | u32 __iomem *lmmio; |
326 | u8 __iomem *bmmio; | 326 | u8 __iomem *bmmio; |
327 | int pci_irqmask; | 327 | int pci_irqmask; |
328 | spinlock_t pci_irqmask_lock; /* protects mask reg too */ | ||
328 | int hwrevision; | 329 | int hwrevision; |
329 | 330 | ||
330 | /* This valud is board specific and is used to configure the | 331 | /* This valud is board specific and is used to configure the |
@@ -485,6 +486,10 @@ extern u32 cx23885_gpio_get(struct cx23885_dev *dev, u32 mask); | |||
485 | extern void cx23885_gpio_enable(struct cx23885_dev *dev, u32 mask, | 486 | extern void cx23885_gpio_enable(struct cx23885_dev *dev, u32 mask, |
486 | int asoutput); | 487 | int asoutput); |
487 | 488 | ||
489 | extern void cx23885_irq_add_enable(struct cx23885_dev *dev, u32 mask); | ||
490 | extern void cx23885_irq_enable(struct cx23885_dev *dev, u32 mask); | ||
491 | extern void cx23885_irq_disable(struct cx23885_dev *dev, u32 mask); | ||
492 | extern void cx23885_irq_remove(struct cx23885_dev *dev, u32 mask); | ||
488 | 493 | ||
489 | /* ----------------------------------------------------------- */ | 494 | /* ----------------------------------------------------------- */ |
490 | /* cx23885-cards.c */ | 495 | /* cx23885-cards.c */ |