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 LinuxPost by Frank ChanPost by Russell King - ARM LinuxPost by Frank ChanI 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