Re: [PATCH] libata: PIO bounce copies to avoid long IRQ off runs

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, Apr 29, 2008 at 6:47 AM, Alan Cox <alan@xxxxxxxxxxxxxxxxxxx> wrote:
> Right now with PIO transfers we can jam the box up horribly as lock IRQs
>  off when the transfer is from high memory. We still have other things we
>  need to fix in this area to really make a difference but this is the
>  buffering side of the fix (the state machine enable/disable irq stuff is
>  also needed)
>
>  Currently uses kmalloc - which seems to work best, but trivial to
>  allocate at init time if wanted
>
>  Signed-off-by: Alan Cox <alan@xxxxxxxxxx>
>
>  diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.25-mm1/drivers/ata/libata-sff.c linux-2.6.25-mm1/drivers/ata/libata-sff.c
>  --- linux.vanilla-2.6.25-mm1/drivers/ata/libata-sff.c   2008-04-28 11:36:48.000000000 +0100
>  +++ linux-2.6.25-mm1/drivers/ata/libata-sff.c   2008-04-28 11:42:05.000000000 +0100
>  @@ -665,6 +665,62 @@
>   }
>
>   /**
>  + *     ata_bounce_pio_xfer     -       Transfer a block by PIO from high
>  + *     @dev: target device
>  + *     @page: highmem page
>  + *     @offset: offset in page
>  + *     @count: bytes to transfer
>  + *     @do_write: writing if set, reading if not
>  + *
>  + *     Transfer a page of high memory via PIO. Whenever possible use a bounce
>  + *     buffer to avoid transfers occuring with local IRQ disable
>  + */
>  +
>  +static unsigned int ata_bounce_pio_xfer(struct ata_device *dev, struct page *page,
>  +                                 unsigned int offset, int count, int rw)
>  +{
>  +       struct ata_port *ap = dev->link->ap;
>  +       unsigned long flags;
>  +       unsigned char *zebedee;
>  +       unsigned char *buf;
>  +       unsigned int consumed;
>  +
>  +       BUG_ON(offset + count > PAGE_SIZE);
>  +
>  +       zebedee = kmalloc(count, GFP_ATOMIC);
>  +       if (likely(zebedee)) {
>  +               if (rw == WRITE) {
>  +                       local_irq_save(flags);
>  +                       buf = kmap_atomic(page, KM_IRQ0);
>  +                       memcpy(zebedee, buf + offset, count);
>  +                       kunmap_atomic(buf, KM_IRQ0);
>  +                       local_irq_restore(flags);
>  +               }
>  +               /* do the actual data transfer */
>  +               consumed = ap->ops->sff_data_xfer(dev, zebedee, count, rw);
>  +               if (rw == READ) {
>  +                       /* Read so bounce  data upwards */
>  +                       local_irq_save(flags);
>  +                       buf = kmap_atomic(page, KM_IRQ0);
>  +                       memcpy(buf + offset, zebedee, count);
>  +                       kunmap_atomic(buf, KM_IRQ0);
>  +                       local_irq_restore(flags);
>  +               }
>  +               kfree(zebedee);
>  +       } else {
>  +               /* Only used when we are out of buffer memory
>  +                  as a last last resort */
>  +               local_irq_save(flags);
>  +               buf = kmap_atomic(page, KM_IRQ0);
>  +               /* do the actual data transfer */
>  +               consumed = ap->ops->sff_data_xfer(dev, buf + offset, count, rw);
>  +               kunmap_atomic(buf, KM_IRQ0);
>  +               local_irq_restore(flags);
>  +       }
>  +       return consumed;
>  +}
>  +
>  +/**
>   *     ata_pio_sector - Transfer a sector of data.
>   *     @qc: Command on going
>   *
>  @@ -675,7 +731,7 @@
>   */
>   static void ata_pio_sector(struct ata_queued_cmd *qc)
>   {
>  -       int do_write = (qc->tf.flags & ATA_TFLAG_WRITE);
>  +       int do_write = (qc->tf.flags & ATA_TFLAG_WRITE) ? WRITE : READ;
>         struct ata_port *ap = qc->ap;
>         struct page *page;
>         unsigned int offset;
>  @@ -693,19 +749,9 @@
>
>         DPRINTK("data %s\n", qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read");
>
>  -       if (PageHighMem(page)) {
>  -               unsigned long flags;
>  -
>  -               /* FIXME: use a bounce buffer */
>  -               local_irq_save(flags);
>  -               buf = kmap_atomic(page, KM_IRQ0);
>  -
>  -               /* do the actual data transfer */
>  -               ap->ops->sff_data_xfer(qc->dev, buf + offset, qc->sect_size,
>  -                                      do_write);
>  -
>  -               kunmap_atomic(buf, KM_IRQ0);
>  -               local_irq_restore(flags);
>  +       if (PageHighMem(page) || 1 /* TEST FIXME */) {

Did you want the "|| 1" code committed as well?

thanks,
grant

>  +               ata_bounce_pio_xfer(qc->dev, page, offset, qc->sect_size,
>  +                                                               do_write);
>         } else {
>                 buf = page_address(page);
>                 ap->ops->sff_data_xfer(qc->dev, buf + offset, qc->sect_size,
>  @@ -830,19 +876,9 @@
>
>         DPRINTK("data %s\n", qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read");
>
>  -       if (PageHighMem(page)) {
>  -               unsigned long flags;
>  -
>  -               /* FIXME: use bounce buffer */
>  -               local_irq_save(flags);
>  -               buf = kmap_atomic(page, KM_IRQ0);
>  -
>  -               /* do the actual data transfer */
>  -               consumed = ap->ops->sff_data_xfer(dev,  buf + offset, count, rw);
>  -
>  -               kunmap_atomic(buf, KM_IRQ0);
>  -               local_irq_restore(flags);
>  -       } else {
>  +       if (PageHighMem(page))
>  +               consumed = ata_bounce_pio_xfer(qc->dev, page, offset, count, rw);
>  +       else {
>                 buf = page_address(page);
>                 consumed = ap->ops->sff_data_xfer(dev,  buf + offset, count, rw);
>         }
>  --
>  To unsubscribe from this list: send the line "unsubscribe linux-ide" in
>  the body of a message to majordomo@xxxxxxxxxxxxxxx
>  More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
--
To unsubscribe from this list: send the line "unsubscribe linux-ide" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Filesystems]     [Linux SCSI]     [Linux RAID]     [Git]     [Kernel Newbies]     [Linux Newbie]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Samba]     [Device Mapper]

  Powered by Linux