From patchwork Thu Feb 19 05:18:47 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: "Igor M. Liplianin" X-Patchwork-Id: 7919 Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id n1J5IrQw029935 for ; Thu, 19 Feb 2009 05:18:53 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752558AbZBSFSw (ORCPT ); Thu, 19 Feb 2009 00:18:52 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1752581AbZBSFSw (ORCPT ); Thu, 19 Feb 2009 00:18:52 -0500 Received: from mail.tut.by ([195.137.160.40]:45194 "EHLO speedy.tutby.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752193AbZBSFSu (ORCPT ); Thu, 19 Feb 2009 00:18:50 -0500 X-VBA32: Checked Received: from [93.125.74.3] (account liplianin@tut.by HELO [172.30.2.32]) by speedy.tutby.com (CommuniGate Pro SMTP 5.2.12) with ESMTPA id 10813036 for linux-media@vger.kernel.org; Thu, 19 Feb 2009 07:18:43 +0200 From: "Igor M. Liplianin" To: linux-media@vger.kernel.org Subject: dm1105: not demuxing from interrupt context Date: Thu, 19 Feb 2009 07:18:47 +0200 User-Agent: KMail/1.9.9 MIME-Version: 1.0 Content-Disposition: inline Message-Id: <200902190718.47890.liplianin@tut.by> Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org I read in mailing list about design error in dm1105. So I am designer. DMA buffer in the driver itself organized like ringbuffer and not difficult to bind it to tasklet or work queue. I choose work queue, because it is like trend :) The code tested by me on quite fast computer and it works as usual. I think, on slow computer difference must be noticeable. The patch is preliminary. Anyone can criticize.    /* register with input layer */ @@ -717,7 +732,7 @@           dm1105dvb = kzalloc(sizeof(struct dm1105dvb), GFP_KERNEL);         if (!dm1105dvb) -               goto out; +               return -ENOMEM;           dm1105dvb->pdev = pdev;         dm1105dvb->buffer_size = 5 * DM1105_DMA_BYTES; @@ -747,13 +762,9 @@         spin_lock_init(&dm1105dvb->lock);         pci_set_drvdata(pdev, dm1105dvb);   -       ret = request_irq(pdev->irq, dm1105dvb_irq, IRQF_SHARED, DRIVER_NAME, dm1105dvb); +       ret = dm1105dvb_hw_init(dm1105dvb);         if (ret < 0)                 goto err_pci_iounmap; - -       ret = dm1105dvb_hw_init(dm1105dvb); -       if (ret < 0) -               goto err_free_irq;           /* i2c */         i2c_set_adapdata(&dm1105dvb->i2c_adap, dm1105dvb); @@ -820,8 +831,19 @@           dvb_net_init(dvb_adapter, &dm1105dvb->dvbnet, dmx);         dm1105_ir_init(dm1105dvb); -out: -       return ret; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) +       INIT_WORK(&dm1105dvb->work, dm1105_dmx_buffer, dm1105dvb); +#else +       INIT_WORK(&dm1105dvb->work, dm1105_dmx_buffer); +#endif + +       ret = request_irq(pdev->irq, dm1105dvb_irq, IRQF_SHARED, +                                               DRIVER_NAME, dm1105dvb); +       if (ret < 0) +               goto err_free_irq; + +       return 0;    err_disconnect_frontend:         dmx->disconnect_frontend(dmx); @@ -850,7 +872,7 @@  err_kfree:         pci_set_drvdata(pdev, NULL);         kfree(dm1105dvb); -       goto out; +       return ret;  }    static void __devexit dm1105_remove(struct pci_dev *pdev) diff -r 359d95e1d541 -r f22da8d6a83c linux/drivers/media/dvb/dm1105/dm1105.c --- a/linux/drivers/media/dvb/dm1105/dm1105.c   Wed Feb 18 09:49:37 2009 -0300 +++ b/linux/drivers/media/dvb/dm1105/dm1105.c   Thu Feb 19 04:38:32 2009 +0200 @@ -220,10 +220,14 @@         /* i2c */         struct i2c_adapter i2c_adap;   +       /* irq */ +       struct work_struct work; +         /* dma */         dma_addr_t dma_addr;         unsigned char *ts_buf;         u32 wrp; +       u32 nextwrp;         u32 buffer_size;         unsigned int    PacketErrorCount;         unsigned int dmarst; @@ -418,6 +422,9 @@         u8 data;         u16 keycode;   +       if (ir_debug) +               printk(KERN_INFO "%s: received byte 0x%04x\n", __func__, ircom); +         data = (ircom >> 8) & 0x7f;           input_event(ir->input_dev, EV_MSC, MSC_RAW, (0x0000f8 << 16) | data); @@ -434,6 +441,50 @@    }   +/* work handler */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) +static void dm1105_dmx_buffer(void *_dm1105dvb) +#else +static void dm1105_dmx_buffer(struct work_struct *work) +#endif +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) +       struct dm1105dvb *dm1105dvb = _dm1105dvb; +#else +       struct dm1105dvb *dm1105dvb = +                               container_of(work, struct dm1105dvb, work); +#endif +       unsigned int nbpackets; +       u32 oldwrp = dm1105dvb->wrp; +       u32 nextwrp = dm1105dvb->nextwrp; + +       if (!((dm1105dvb->ts_buf[oldwrp] == 0x47) && +                       (dm1105dvb->ts_buf[oldwrp + 188] == 0x47) && +                       (dm1105dvb->ts_buf[oldwrp + 188 * 2] == 0x47))) { +               dm1105dvb->PacketErrorCount++; +               /* bad packet found */ +               if ((dm1105dvb->PacketErrorCount >= 2) && +                               (dm1105dvb->dmarst == 0)) { +                       outb(1, dm_io_mem(DM1105_RST)); +                       dm1105dvb->wrp = 0; +                       dm1105dvb->PacketErrorCount = 0; +                       dm1105dvb->dmarst = 0; +                       return; +               } +       } + +       if (nextwrp < oldwrp) { +               memcpy(dm1105dvb->ts_buf + dm1105dvb->buffer_size, +                                               dm1105dvb->ts_buf, nextwrp); +               nbpackets = ((dm1105dvb->buffer_size - oldwrp) + nextwrp) / 188; +       } else +               nbpackets = (nextwrp - oldwrp) / 188; + +       dm1105dvb->wrp = nextwrp; +       dvb_dmx_swfilter_packets(&dm1105dvb->demux, +                                       &dm1105dvb->ts_buf[oldwrp], nbpackets); +} +  #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)  static irqreturn_t dm1105dvb_irq(int irq, void *dev_id, struct pt_regs *regs)  #else @@ -441,11 +492,6 @@  #endif  {         struct dm1105dvb *dm1105dvb = dev_id; -       unsigned int piece; -       unsigned int nbpackets; -       u32 command; -       u32 nextwrp; -       u32 oldwrp;           /* Read-Write INSTS Ack's Interrupt for DM1105 chip 16.03.2008 */         unsigned int intsts = inb(dm_io_mem(DM1105_INTSTS)); @@ -454,48 +500,17 @@         switch (intsts) {         case INTSTS_TSIRQ:         case (INTSTS_TSIRQ | INTSTS_IR): -               nextwrp = inl(dm_io_mem(DM1105_WRP)) - -                       inl(dm_io_mem(DM1105_STADR)) ; -               oldwrp = dm1105dvb->wrp; -               spin_lock(&dm1105dvb->lock); -               if (!((dm1105dvb->ts_buf[oldwrp] == 0x47) && -                               (dm1105dvb->ts_buf[oldwrp + 188] == 0x47) && -                               (dm1105dvb->ts_buf[oldwrp + 188 * 2] == 0x47))) { -                       dm1105dvb->PacketErrorCount++; -                       /* bad packet found */ -                       if ((dm1105dvb->PacketErrorCount >= 2) && -                                       (dm1105dvb->dmarst == 0)) { -                               outb(1, dm_io_mem(DM1105_RST)); -                               dm1105dvb->wrp = 0; -                               dm1105dvb->PacketErrorCount = 0; -                               dm1105dvb->dmarst = 0; -                               spin_unlock(&dm1105dvb->lock); -                               return IRQ_HANDLED; -                       } -               } -               if (nextwrp < oldwrp) { -                       piece = dm1105dvb->buffer_size - oldwrp; -                       memcpy(dm1105dvb->ts_buf + dm1105dvb->buffer_size, dm1105dvb->ts_buf, nextwrp); -                       nbpackets = (piece + nextwrp)/188; -               } else  { -                       nbpackets = (nextwrp - oldwrp)/188; -               } -               dvb_dmx_swfilter_packets(&dm1105dvb->demux, &dm1105dvb->ts_buf[oldwrp], nbpackets); -               dm1105dvb->wrp = nextwrp; -               spin_unlock(&dm1105dvb->lock); +               dm1105dvb->nextwrp = inl(dm_io_mem(DM1105_WRP)) - +                                       inl(dm_io_mem(DM1105_STADR)); +               schedule_work(&dm1105dvb->work);                 break;         case INTSTS_IR: -               command = inl(dm_io_mem(DM1105_IRCODE)); -               if (ir_debug) -                       printk("dm1105: received byte 0x%04x\n", command); - -               dm1105dvb->ir.ir_command = command; +               dm1105dvb->ir.ir_command = inl(dm_io_mem(DM1105_IRCODE));                 tasklet_schedule(&dm1105dvb->ir.ir_tasklet);                 break;         } +         return IRQ_HANDLED; - -  }