Discussion:
How to make kernel memory access noncacheable
Frank Chan
2006-08-31 04:12:35 UTC
Permalink
Hi Folks,

I have a buffer which is allocated using alloc_pages(), then these
pages are mapping to a read/write buffer: buf = kmap(page) + offset.
The memory buffer is accessed by reading from io memory or writing to
io memory. How to make all the access to the memory buffer
noncacheable or cache coherent? May I replace kmap with
ioremap_nocache()?

The platform I use is ARM IOP80321 with VIVT type cache.

Thanks,
Fajun

-------------------------------------------------------------------
List admin: http://lists.arm.linux.org.uk/mailman/listinfo/linux-arm-kernel
FAQ: http://www.arm.linux.org.uk/mailinglists/faq.php
Etiquette: http://www.arm.linux.org.uk/mailinglists/etiquette.php
Russell King - ARM Linux
2006-08-31 08:33:16 UTC
Permalink
Post by Frank Chan
I have a buffer which is allocated using alloc_pages(), then these
pages are mapping to a read/write buffer: buf = kmap(page) + offset.
The memory buffer is accessed by reading from io memory or writing to
io memory. How to make all the access to the memory buffer
noncacheable or cache coherent? May I replace kmap with
ioremap_nocache()?
You don't say what you're doing with the buffer. If you're intending to
use it for DMA, use the DMA API.

-------------------------------------------------------------------
List admin: http://lists.arm.linux.org.uk/mailman/listinfo/linux-arm-kernel
FAQ: http://www.arm.linux.org.uk/mailinglists/faq.php
Etiquette: http://www.arm.linux.org.uk/mailinglists/etiquette.php
Frank Chan
2006-08-31 14:32:05 UTC
Permalink
Post by Russell King - ARM Linux
Post by Frank Chan
I have a buffer which is allocated using alloc_pages(), then these
pages are mapping to a read/write buffer: buf = kmap(page) + offset.
The memory buffer is accessed by reading from io memory or writing to
io memory. How to make all the access to the memory buffer
noncacheable or cache coherent? May I replace kmap with
ioremap_nocache()?
You don't say what you're doing with the buffer. If you're intending to
use it for DMA, use the DMA API.
In fact, I use this buffer for PIO read/write. Which APIs should I
use to ensure cache coherency?

-------------------------------------------------------------------
List admin: http://lists.arm.linux.org.uk/mailman/listinfo/linux-arm-kernel
FAQ: http://www.arm.linux.org.uk/mailinglists/faq.php
Etiquette: http://www.arm.linux.org.uk/mailinglists/etiquette.php
Russell King - ARM Linux
2006-08-31 14:38:40 UTC
Permalink
Post by Frank Chan
Post by Russell King - ARM Linux
Post by Frank Chan
I have a buffer which is allocated using alloc_pages(), then these
pages are mapping to a read/write buffer: buf = kmap(page) + offset.
The memory buffer is accessed by reading from io memory or writing to
io memory. How to make all the access to the memory buffer
noncacheable or cache coherent? May I replace kmap with
ioremap_nocache()?
You don't say what you're doing with the buffer. If you're intending to
use it for DMA, use the DMA API.
In fact, I use this buffer for PIO read/write. Which APIs should I
use to ensure cache coherency?
That sounds like you're munging terms, since you've just said that you're
trying to do programmed IO to memory.

Please explain in detail what you're trying to do.

-------------------------------------------------------------------
List admin: http://lists.arm.linux.org.uk/mailman/listinfo/linux-arm-kernel
FAQ: http://www.arm.linux.org.uk/mailinglists/faq.php
Etiquette: http://www.arm.linux.org.uk/mailinglists/etiquette.php
Frank Chan
2006-08-31 14:47:57 UTC
Permalink
Post by Russell King - ARM Linux
Post by Frank Chan
Post by Russell King - ARM Linux
Post by Frank Chan
I have a buffer which is allocated using alloc_pages(), then these
pages are mapping to a read/write buffer: buf = kmap(page) + offset.
The memory buffer is accessed by reading from io memory or writing to
io memory. How to make all the access to the memory buffer
noncacheable or cache coherent? May I replace kmap with
ioremap_nocache()?
You don't say what you're doing with the buffer. If you're intending to
use it for DMA, use the DMA API.
In fact, I use this buffer for PIO read/write. Which APIs should I
use to ensure cache coherency?
That sounds like you're munging terms, since you've just said that you're
trying to do programmed IO to memory.
Please explain in detail what you're trying to do.
Sorry about the confusion. Listed below are the relevant code. Note
that ap->ops->data_xfer() is ata_pio_data_xfer() function. So how to
ensure cache coherency for VIVT type cache in this context?

void ata_pio_data_xfer(struct ata_device *adev, unsigned char *buf,
unsigned int buflen, int write_data)
{
struct ata_port *ap = adev->ap;
unsigned int words = buflen >> 1;

/* Transfer multiple of 2 bytes */
if (write_data)
outsw(ap->ioaddr.data_addr, buf, words);
else
insw(ap->ioaddr.data_addr, buf, words);

/* Transfer trailing 1 byte, if any. */
if (unlikely(buflen & 0x01)) {
u16 align_buf[1] = { 0 };
unsigned char *trailing_buf = buf + buflen - 1;

if (write_data) {
memcpy(align_buf, trailing_buf, 1);
outw(le16_to_cpu(align_buf[0]), ap->ioaddr.data_addr);
} else {
align_buf[0] = cpu_to_le16(inw(ap->ioaddr.data_addr));
memcpy(trailing_buf, align_buf, 1);
}
}
}

static void ata_pio_sector(struct ata_queued_cmd *qc)
{
int do_write = (qc->tf.flags & ATA_TFLAG_WRITE);
struct scatterlist *sg = qc->__sg;
struct ata_port *ap = qc->ap;
struct page *page;
unsigned int offset;
unsigned char *buf;

if (qc->cursect == (qc->nsect - 1))
ap->hsm_task_state = HSM_ST_LAST;

page = sg[qc->cursg].page;
offset = sg[qc->cursg].offset + qc->cursg_ofs * ATA_SECT_SIZE;

/* get the current page and offset */
page = nth_page(page, (offset >> PAGE_SHIFT));
offset %= PAGE_SIZE;

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->data_xfer(qc->dev, buf + offset, ATA_SECT_SIZE, do_write);

kunmap_atomic(buf, KM_IRQ0);
local_irq_restore(flags);
} else {
buf = page_address(page);
ap->ops->data_xfer(qc->dev, buf + offset, ATA_SECT_SIZE, do_write);
}

qc->cursect++;
qc->cursg_ofs++;

if ((qc->cursg_ofs * ATA_SECT_SIZE) == (&sg[qc->cursg])->length) {
qc->cursg++;
qc->cursg_ofs = 0;
}
}

-------------------------------------------------------------------
List admin: http://lists.arm.linux.org.uk/mailman/listinfo/linux-arm-kernel
FAQ: http://www.arm.linux.org.uk/mailinglists/faq.php
Etiquette: http://www.arm.linux.org.uk/mailinglists/etiquette.php
Russell King - ARM Linux
2006-08-31 15:02:05 UTC
Permalink
Post by Frank Chan
Post by Russell King - ARM Linux
Post by Frank Chan
Post by Russell King - ARM Linux
Post by Frank Chan
I have a buffer which is allocated using alloc_pages(), then these
pages are mapping to a read/write buffer: buf = kmap(page) + offset.
The memory buffer is accessed by reading from io memory or writing to
io memory. How to make all the access to the memory buffer
noncacheable or cache coherent? May I replace kmap with
ioremap_nocache()?
You don't say what you're doing with the buffer. If you're intending to
use it for DMA, use the DMA API.
In fact, I use this buffer for PIO read/write. Which APIs should I
use to ensure cache coherency?
That sounds like you're munging terms, since you've just said that you're
trying to do programmed IO to memory.
Please explain in detail what you're trying to do.
Sorry about the confusion. Listed below are the relevant code. Note
that ap->ops->data_xfer() is ata_pio_data_xfer() function. So how to
ensure cache coherency for VIVT type cache in this context?
I still don't get what you're trying to do. You should not have to
concern yourself with cache coherency at this point, and you certainly
should not be looking at how to disable the cache here.

Try describing the problem that you're seeing, or if you aren't seeing
a problem, describe exactly what you're trying to achieve overall.

-------------------------------------------------------------------
List admin: http://lists.arm.linux.org.uk/mailman/listinfo/linux-arm-kernel
FAQ: http://www.arm.linux.org.uk/mailinglists/faq.php
Etiquette: http://www.arm.linux.org.uk/mailinglists/etiquette.php
Frank Chan
2006-08-31 15:32:29 UTC
Permalink
Post by Russell King - ARM Linux
Post by Frank Chan
Post by Russell King - ARM Linux
Post by Frank Chan
Post by Russell King - ARM Linux
Post by Frank Chan
I have a buffer which is allocated using alloc_pages(), then these
pages are mapping to a read/write buffer: buf = kmap(page) + offset.
The memory buffer is accessed by reading from io memory or writing to
io memory. How to make all the access to the memory buffer
noncacheable or cache coherent? May I replace kmap with
ioremap_nocache()?
You don't say what you're doing with the buffer. If you're intending to
use it for DMA, use the DMA API.
In fact, I use this buffer for PIO read/write. Which APIs should I
use to ensure cache coherency?
That sounds like you're munging terms, since you've just said that you're
trying to do programmed IO to memory.
Please explain in detail what you're trying to do.
Sorry about the confusion. Listed below are the relevant code. Note
that ap->ops->data_xfer() is ata_pio_data_xfer() function. So how to
ensure cache coherency for VIVT type cache in this context?
I still don't get what you're trying to do. You should not have to
concern yourself with cache coherency at this point, and you certainly
should not be looking at how to disable the cache here.
Try describing the problem that you're seeing, or if you aren't seeing
a problem, describe exactly what you're trying to achieve overall.
We use sg/libata for data read/write test in ARM XScale platform. We
experienced data miscompare issue during heavy testing on both DMA and
PIO read/write. In this particular application, data buffer is
allocated inside kernel using alloc_pages() and mmapped to user space.
So essentially this buffer can be accessed by user space, kernel for
PIO and hardware for DMA. After changing mmapped vma to noncache, we
haven't seen any data miscompare in DMA read/write, but data
miscompare in PIO read/write still exists sporadically. I suspect
this is caused by kernel cache alias during PIO read/write. What I am
after is a way to make kernel access to this buffer uncached. In
other words, may I manipulate the PTEs of this buffer or remap this
buffer to make its access uncached from the rest of the kernel?

-------------------------------------------------------------------
List admin: http://lists.arm.linux.org.uk/mailman/listinfo/linux-arm-kernel
FAQ: http://www.arm.linux.org.uk/mailinglists/faq.php
Etiquette: http://www.arm.linux.org.uk/mailinglists/etiquette.php
Russell King - ARM Linux
2006-08-31 16:29:14 UTC
Permalink
Post by Frank Chan
Post by Frank Chan
Post by Frank Chan
Post by Russell King - ARM Linux
Post by Frank Chan
Post by Russell King - ARM Linux
Post by Frank Chan
I have a buffer which is allocated using alloc_pages(), then these
pages are mapping to a read/write buffer: buf = kmap(page) +
offset.
Post by Frank Chan
Post by Russell King - ARM Linux
Post by Frank Chan
Post by Russell King - ARM Linux
Post by Frank Chan
The memory buffer is accessed by reading from io memory or writing
to
Post by Frank Chan
Post by Russell King - ARM Linux
Post by Frank Chan
Post by Russell King - ARM Linux
Post by Frank Chan
io memory. How to make all the access to the memory buffer
noncacheable or cache coherent? May I replace kmap with
ioremap_nocache()?
You don't say what you're doing with the buffer. If you're
intending to
Post by Frank Chan
Post by Russell King - ARM Linux
Post by Frank Chan
Post by Russell King - ARM Linux
use it for DMA, use the DMA API.
In fact, I use this buffer for PIO read/write. Which APIs should I
use to ensure cache coherency?
That sounds like you're munging terms, since you've just said that
you're
Post by Frank Chan
Post by Russell King - ARM Linux
trying to do programmed IO to memory.
Please explain in detail what you're trying to do.
Sorry about the confusion. Listed below are the relevant code. Note
that ap->ops->data_xfer() is ata_pio_data_xfer() function. So how to
ensure cache coherency for VIVT type cache in this context?
I still don't get what you're trying to do. You should not have to
concern yourself with cache coherency at this point, and you certainly
should not be looking at how to disable the cache here.
Try describing the problem that you're seeing, or if you aren't seeing
a problem, describe exactly what you're trying to achieve overall.
We use sg/libata for data read/write test in ARM XScale platform. We
experienced data miscompare issue during heavy testing on both DMA and
PIO read/write. In this particular application, data buffer is
allocated inside kernel using alloc_pages() and mmapped to user space.
So essentially this buffer can be accessed by user space, kernel for
PIO and hardware for DMA. After changing mmapped vma to noncache, we
haven't seen any data miscompare in DMA read/write, but data
miscompare in PIO read/write still exists sporadically. I suspect
this is caused by kernel cache alias during PIO read/write. What I am
after is a way to make kernel access to this buffer uncached. In
other words, may I manipulate the PTEs of this buffer or remap this
buffer to make its access uncached from the rest of the kernel?
Hmm, this doesn't sound like the way to go about it. However, I have
_zero_ experience of the Linux sgio implementation, ditto for the
libata code. Sorry, can't help. Maybe you should talk to the libata
people?

(and no, you can't change individual pages in the kernel to be
uncached.)

-------------------------------------------------------------------
List admin: http://lists.arm.linux.org.uk/mailman/listinfo/linux-arm-kernel
FAQ: http://www.arm.linux.org.uk/mailinglists/faq.php
Etiquette: http://www.arm.linux.org.uk/mailinglists/etiquette.php
Stanley Cai
2006-08-31 08:47:50 UTC
Permalink
Hi Frank,

you may take a look at the implementation of
__dma_alloc() in arch/arm/mm/consistent.c. It get some
free pages by alloc_pages() and then setup the ptes
with noncache attributes.

Regards,
-stanley
Post by Frank Chan
Hi Folks,
I have a buffer which is allocated using
alloc_pages(), then these
pages are mapping to a read/write buffer: buf =
kmap(page) + offset.
The memory buffer is accessed by reading from io
memory or writing to
io memory. How to make all the access to the memory
buffer
noncacheable or cache coherent? May I replace kmap
with
ioremap_nocache()?
The platform I use is ARM IOP80321 with VIVT type
cache.
Thanks,
Fajun
-------------------------------------------------------------------
http://lists.arm.linux.org.uk/mailman/listinfo/linux-arm-kernel
Post by Frank Chan
http://www.arm.linux.org.uk/mailinglists/faq.php
http://www.arm.linux.org.uk/mailinglists/etiquette.php
__________________________________________________
Do You Yahoo!?
Tired of spam? Yahoo! Mail has the best spam protection around
http://mail.yahoo.com

-------------------------------------------------------------------
List admin: http://lists.arm.linux.org.uk/mailman/listinfo/linux-arm-kernel
FAQ: http://www.arm.linux.org.uk/mailinglists/faq.php
Etiquette: http://www.arm.linux.org.uk/mailinglists/etiquette.php
Michael Schnell
2006-08-31 09:15:38 UTC
Permalink
Post by Stanley Cai
you may take a look at the implementation of
__dma_alloc() in arch/arm/mm/consistent.c.
What is the recommended way to do DMA in and out moves ?

With DMA out, it would be best to disable and flush the cache just
before starting the DMA and re-enable it afterwards.
With DMA in, it would be best to disable the cache just before starting
the DMA.and re-enable (and invalidate) it afterwards to optimize the
subsequent CPU accesses.

Can this be done or will the DMA memory be forcibly used uncached all
the time, needing a DRAM access for _any_ r/w cycle instead of one per
cache-line ?

-Michael

-------------------------------------------------------------------
List admin: http://lists.arm.linux.org.uk/mailman/listinfo/linux-arm-kernel
FAQ: http://www.arm.linux.org.uk/mailinglists/faq.php
Etiquette: http://www.arm.linux.org.uk/mailinglists/etiquette.php
Russell King - ARM Linux
2006-08-31 09:45:31 UTC
Permalink
Post by Michael Schnell
Post by Stanley Cai
you may take a look at the implementation of
__dma_alloc() in arch/arm/mm/consistent.c.
What is the recommended way to do DMA in and out moves ?
With DMA out, it would be best to disable and flush the cache just
before starting the DMA and re-enable it afterwards.
With DMA in, it would be best to disable the cache just before starting
the DMA.and re-enable (and invalidate) it afterwards to optimize the
subsequent CPU accesses.
Can this be done or will the DMA memory be forcibly used uncached all
the time, needing a DRAM access for _any_ r/w cycle instead of one per
cache-line ?
Look at the DMA API, documented in the Documentation subdirectory. There
are two classes contained there in:

1. a streaming API
2. a cache coherent API

You seem to be referring to the streaming API.

-------------------------------------------------------------------
List admin: http://lists.arm.linux.org.uk/mailman/listinfo/linux-arm-kernel
FAQ: http://www.arm.linux.org.uk/mailinglists/faq.php
Etiquette: http://www.arm.linux.org.uk/mailinglists/etiquette.php
Michael Schnell
2006-08-31 09:52:02 UTC
Permalink
Post by Russell King - ARM Linux
You seem to be referring to the streaming API.
Thanks a lot for the pointer
-Michael

-------------------------------------------------------------------
List admin: http://lists.arm.linux.org.uk/mailman/listinfo/linux-arm-kernel
FAQ: http://www.arm.linux.org.uk/mailinglists/faq.php
Etiquette: http://www.arm.linux.org.uk/mailinglists/etiquette.php
Schaaf, Christian (GE Infra, Oil & Gas)
2006-09-01 09:07:59 UTC
Permalink
Hello,

I've been searching on LXR but haven't found any hints how to change
a mmapped vma to 'nonchache'. Does anybody has some for me?
What do you think about using 'flush_dcache_page(page)'
to avoid cache effects?

Regards,
Christian Schaaf

-----Original Message-----
From: linux-arm-kernel-***@lists.arm.linux.org.uk
[mailto:linux-arm-kernel-***@lists.arm.linux.org.uk]On Behalf Of
Frank Chan
Sent: Donnerstag, 31. August 2006 16:48
To: Frank Chan; linux-arm-***@lists.arm.linux.org.uk
Subject: Re: How to make kernel memory access noncacheable
Post by Russell King - ARM Linux
Post by Frank Chan
Post by Russell King - ARM Linux
Post by Frank Chan
I have a buffer which is allocated using alloc_pages(), then these
pages are mapping to a read/write buffer: buf = kmap(page) + offset.
The memory buffer is accessed by reading from io memory or writing to
io memory. How to make all the access to the memory buffer
noncacheable or cache coherent? May I replace kmap with
ioremap_nocache()?
You don't say what you're doing with the buffer. If you're intending to
use it for DMA, use the DMA API.
In fact, I use this buffer for PIO read/write. Which APIs should I
use to ensure cache coherency?
That sounds like you're munging terms, since you've just said that you're
trying to do programmed IO to memory.
Please explain in detail what you're trying to do.
Sorry about the confusion. Listed below are the relevant code. Note
that ap->ops->data_xfer() is ata_pio_data_xfer() function. So how to
ensure cache coherency for VIVT type cache in this context?

void ata_pio_data_xfer(struct ata_device *adev, unsigned char *buf,
unsigned int buflen, int write_data)
{
struct ata_port *ap = adev->ap;
unsigned int words = buflen >> 1;

/* Transfer multiple of 2 bytes */
if (write_data)
outsw(ap->ioaddr.data_addr, buf, words);
else
insw(ap->ioaddr.data_addr, buf, words);

/* Transfer trailing 1 byte, if any. */
if (unlikely(buflen & 0x01)) {
u16 align_buf[1] = { 0 };
unsigned char *trailing_buf = buf + buflen - 1;

if (write_data) {
memcpy(align_buf, trailing_buf, 1);
outw(le16_to_cpu(align_buf[0]), ap->ioaddr.data_addr);
} else {
align_buf[0] = cpu_to_le16(inw(ap->ioaddr.data_addr));
memcpy(trailing_buf, align_buf, 1);
}
}
}

static void ata_pio_sector(struct ata_queued_cmd *qc)
{
int do_write = (qc->tf.flags & ATA_TFLAG_WRITE);
struct scatterlist *sg = qc->__sg;
struct ata_port *ap = qc->ap;
struct page *page;
unsigned int offset;
unsigned char *buf;

if (qc->cursect == (qc->nsect - 1))
ap->hsm_task_state = HSM_ST_LAST;

page = sg[qc->cursg].page;
offset = sg[qc->cursg].offset + qc->cursg_ofs * ATA_SECT_SIZE;

/* get the current page and offset */
page = nth_page(page, (offset >> PAGE_SHIFT));
offset %= PAGE_SIZE;

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->data_xfer(qc->dev, buf + offset, ATA_SECT_SIZE, do_write);

kunmap_atomic(buf, KM_IRQ0);
local_irq_restore(flags);
} else {
buf = page_address(page);
ap->ops->data_xfer(qc->dev, buf + offset, ATA_SECT_SIZE, do_write);
}

qc->cursect++;
qc->cursg_ofs++;

if ((qc->cursg_ofs * ATA_SECT_SIZE) == (&sg[qc->cursg])->length) {
qc->cursg++;
qc->cursg_ofs = 0;
}
}

-------------------------------------------------------------------
List admin: http://lists.arm.linux.org.uk/mailman/listinfo/linux-arm-kernel
FAQ: http://www.arm.linux.org.uk/mailinglists/faq.php
Etiquette: http://www.arm.linux.org.uk/mailinglists/etiquette.php

-------------------------------------------------------------------
List admin: http://lists.arm.linux.org.uk/mailman/listinfo/linux-arm-kernel
FAQ: http://www.arm.linux.org.uk/mailinglists/faq.php
Etiquette: http://www.arm.linux.org.uk/mailinglists/etiquette.php
Frank Chan
2006-09-01 22:08:49 UTC
Permalink
On 9/1/06, Schaaf, Christian (GE Infra, Oil & Gas)
Post by Schaaf, Christian (GE Infra, Oil & Gas)
Hello,
I've been searching on LXR but haven't found any hints how to change
a mmapped vma to 'nonchache'. Does anybody has some for me?
What do you think about using 'flush_dcache_page(page)'
to avoid cache effects?
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot) should make
mmaped vma uncached. flush_dcache_page(page) is the one to make
kernel cache coherent. I currently use this one after reading data in
PIO mode.
Post by Schaaf, Christian (GE Infra, Oil & Gas)
-----Original Message-----
Frank Chan
Sent: Donnerstag, 31. August 2006 16:48
Subject: Re: How to make kernel memory access noncacheable
Post by Russell King - ARM Linux
Post by Frank Chan
Post by Russell King - ARM Linux
Post by Frank Chan
I have a buffer which is allocated using alloc_pages(), then these
pages are mapping to a read/write buffer: buf = kmap(page) + offset.
The memory buffer is accessed by reading from io memory or writing to
io memory. How to make all the access to the memory buffer
noncacheable or cache coherent? May I replace kmap with
ioremap_nocache()?
You don't say what you're doing with the buffer. If you're intending to
use it for DMA, use the DMA API.
In fact, I use this buffer for PIO read/write. Which APIs should I
use to ensure cache coherency?
That sounds like you're munging terms, since you've just said that you're
trying to do programmed IO to memory.
Please explain in detail what you're trying to do.
Sorry about the confusion. Listed below are the relevant code. Note
that ap->ops->data_xfer() is ata_pio_data_xfer() function. So how to
ensure cache coherency for VIVT type cache in this context?
void ata_pio_data_xfer(struct ata_device *adev, unsigned char *buf,
unsigned int buflen, int write_data)
{
struct ata_port *ap = adev->ap;
unsigned int words = buflen >> 1;
/* Transfer multiple of 2 bytes */
if (write_data)
outsw(ap->ioaddr.data_addr, buf, words);
else
insw(ap->ioaddr.data_addr, buf, words);
/* Transfer trailing 1 byte, if any. */
if (unlikely(buflen & 0x01)) {
u16 align_buf[1] = { 0 };
unsigned char *trailing_buf = buf + buflen - 1;
if (write_data) {
memcpy(align_buf, trailing_buf, 1);
outw(le16_to_cpu(align_buf[0]), ap->ioaddr.data_addr);
} else {
align_buf[0] = cpu_to_le16(inw(ap->ioaddr.data_addr));
memcpy(trailing_buf, align_buf, 1);
}
}
}
static void ata_pio_sector(struct ata_queued_cmd *qc)
{
int do_write = (qc->tf.flags & ATA_TFLAG_WRITE);
struct scatterlist *sg = qc->__sg;
struct ata_port *ap = qc->ap;
struct page *page;
unsigned int offset;
unsigned char *buf;
if (qc->cursect == (qc->nsect - 1))
ap->hsm_task_state = HSM_ST_LAST;
page = sg[qc->cursg].page;
offset = sg[qc->cursg].offset + qc->cursg_ofs * ATA_SECT_SIZE;
/* get the current page and offset */
page = nth_page(page, (offset >> PAGE_SHIFT));
offset %= PAGE_SIZE;
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->data_xfer(qc->dev, buf + offset, ATA_SECT_SIZE, do_write);
kunmap_atomic(buf, KM_IRQ0);
local_irq_restore(flags);
} else {
buf = page_address(page);
ap->ops->data_xfer(qc->dev, buf + offset, ATA_SECT_SIZE, do_write);
}
qc->cursect++;
qc->cursg_ofs++;
if ((qc->cursg_ofs * ATA_SECT_SIZE) == (&sg[qc->cursg])->length) {
qc->cursg++;
qc->cursg_ofs = 0;
}
}
-------------------------------------------------------------------
List admin: http://lists.arm.linux.org.uk/mailman/listinfo/linux-arm-kernel
FAQ: http://www.arm.linux.org.uk/mailinglists/faq.php
Etiquette: http://www.arm.linux.org.uk/mailinglists/etiquette.php
-------------------------------------------------------------------
List admin: http://lists.arm.linux.org.uk/mailman/listinfo/linux-arm-kernel
FAQ: http://www.arm.linux.org.uk/mailinglists/faq.php
Etiquette: http://www.arm.linux.org.uk/mailinglists/etiquette.php
-------------------------------------------------------------------
List admin: http://lists.arm.linux.org.uk/mailman/listinfo/linux-arm-kernel
FAQ: http://www.arm.linux.org.uk/mailinglists/faq.php
Etiquette: http://www.arm.linux.org.uk/mailinglists/etiquette.php
Loading...