Justing bumping this topic, I'm really stuck and could use some (any) help
here. I understand that people are busy and most effort is focused on
2.6.23, but I haven't received any response regarding my prelimenary patch
and its been over a week.
One final question, does Legacy PCI have any other names? Someone who
wrote an IRIX PCI driver awhile back gave me a number of PCI addresses on
the O2, but nothing that seemed like Legacy IO.
Thanks in advance for any response.
> I finally got a prelimenary patch together. It works in the sense it:
>
> a) Compiles (native on the O2 and cross, based on 2.6.21.3).
> b) Boots on the O2 and gives no apparent problems with any supported PCI
> devices (ethernet, SCSI, etc.).
> c) Gives legacy_io and legacy_mem in /sys/class/pci_bus/0000:xx/
> d) Reduces the errors X.org gives from 16 to 4 when I try to use a PCI
> video card on my O2.
>
> However, PCI video still does not work. My best guess is that when I
> copied the ia64 Legacy code, I left in incorrect offsets for the O2. I'm a
> bit stuck as I don't really know how to test PCI Legacy (X.org could be
> failing for other reasons) or figure out the proper offsets myself. Sadly,
> I only half know what I doing here, so some input here would be much
> appreciated. I've more or less exhausted any ideas that I had and thus am
> stuck.
>
> Also, since the offsets would be different for different supported
> platforms, this should be written in the proper extensible way (i.e. not
> hardcoded) though being new to kernel work, I'm not sure the right way to
> do this so some pointers so I could make this more than a hack for my O2
> and something everyone could benefit from would be helpful.
>
> Here is the patch:
>
> diff -uprN -X linux-2.6.21.3/Documentation/dontdiff
> linux-2.6.21.3/arch/mips/pci/pci.c
> linux-2.6.21.3_patch/arch/mips/pci/pci.c
> --- linux-2.6.21.3/arch/mips/pci/pci.c 2007-05-29 09:15:01.000000000
> -0400
> +++ linux-2.6.21.3_patch/arch/mips/pci/pci.c 2007-06-08
> 03:18:05.000000000 -0400
> @@ -13,6 +13,9 @@
> #include <linux/types.h>
> #include <linux/pci.h>
>
> +#include <asm/pgtable.h>
> +#include <asm/io.h>
> +
> /*
> * Indicate whether we respect the PCI setup left by the firmware.
> *
> @@ -338,3 +341,148 @@ char *pcibios_setup(char *str)
> {
> return str;
> }
> +
> + int
> + pci_mmap_page_range (struct pci_dev *dev, struct vm_area_struct *vma,
> + enum pci_mmap_state mmap_state, int write_combine)
> + {
> + /*
> + * I/O space cannot be accessed via normal processor loads and
> + * stores on this platform.
> + */
> + if (mmap_state == pci_mmap_io)
> + /*
> + * XXX we could relax this for I/O spaces for which ACPI
> + * indicates that the space is 1-to-1 mapped. But at the
> + * moment, we don't support multiple PCI address spaces
> and
> + * the legacy I/O space is not 1-to-1 mapped, so this is
> moot.
> + */
> + return -EINVAL;
> +
> + /*
> + * Leave vm_pgoff as-is, the PCI space address is the physical
> + * address on this platform.
> + */
> + if (write_combine)
> + vma->vm_page_prot =
> pgprot_writecombine(vma->vm_page_prot);
> + else
> + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
> +
> + if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
> + vma->vm_end - vma->vm_start,
> vma->vm_page_prot))
> + return -EAGAIN;
> +
> + return 0;
> + }
> +
> + /**
> + * mips_pci_get_legacy_mem - generic legacy mem routine
> + * @bus: bus to get legacy memory base address for
> + *
> + * Find the base of legacy memory for @bus. This is typically the first
> + * megabyte of bus address space for @bus or is simply 0 on platforms
> whose
> + * chipsets support legacy I/O and memory routing. Returns the base
> address
> + * or an error pointer if an error occurred.
> + *
> + * This is the ia64 generic version of this routine. Other platforms
> + * are free to override it with a machine vector.
> + */
> + char *mips_pci_get_legacy_mem(struct pci_bus *bus)
> + {
> + return (char *) 0;
> + }
> +
> + /**
> + * pci_mmap_legacy_page_range - map legacy memory space to userland
> + * @bus: bus whose legacy space we're mapping
> + * @vma: vma passed in by mmap
> + *
> + * Map legacy memory space for this device back to userspace using a
> machine
> + * vector to get the base address.
> + */
> + int
> + pci_mmap_legacy_page_range(struct pci_bus *bus, struct vm_area_struct
> *vma)
> + {
> + unsigned long size = vma->vm_end - vma->vm_start;
> + pgprot_t prot;
> + char *addr;
> +
> + addr = pci_get_legacy_mem(bus);
> + if (IS_ERR(addr))
> + return PTR_ERR(addr);
> +
> + vma->vm_pgoff += (unsigned long)addr >> PAGE_SHIFT;
> +
> + if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
> + size, vma->vm_page_prot))
> + return -EAGAIN;
> +
> + return 0;
> + }
> +
> + /**
> + * mips_pci_legacy_read - read from legacy I/O space
> + * @bus: bus to read
> + * @port: legacy port value
> + * @val: caller allocated storage for returned value
> + * @size: number of bytes to read
> + *
> + * Simply reads @size bytes from @port and puts the result in @val.
> + *
> + * Again, this (and the write routine) are generic versions that can be
> + * overridden by the platform. This is necessary on platforms that
> don't
> + * support legacy I/O routing or that hard fail on legacy I/O timeouts.
> + */
> + int mips_pci_legacy_read(struct pci_bus *bus, u16 port, u32 *val, u8
> size)
> + {
> + int ret = size;
> +
> + switch (size) {
> + case 1:
> + *val = inb(port);
> + break;
> + case 2:
> + *val = inw(port);
> + break;
> + case 4:
> + *val = inl(port);
> + break;
> + default:
> + ret = -EINVAL;
> + break;
> + }
> +
> + return ret;
> + }
> +
> + /**
> + * mips_pci_legacy_write - perform a legacy I/O write
> + * @bus: bus pointer
> + * @port: port to write
> + * @val: value to write
> + * @size: number of bytes to write from @val
> + *
> + * Simply writes @size bytes of @val to @port.
> + */
> + int mips_pci_legacy_write(struct pci_bus *bus, u16 port, u32 val, u8
> size)
> + {
> + int ret = size;
> +
> + switch (size) {
> + case 1:
> + outb(val, port);
> + break;
> + case 2:
> + outw(val, port);
> + break;
> + case 4:
> + outl(val, port);
> + break;
> + default:
> + ret = -EINVAL;
> + break;
> + }
> +
> + return ret;
> +}
> +
> diff -uprN -X linux-2.6.21.3/Documentation/dontdiff
> linux-2.6.21.3/include/asm-mips/pci.h
> linux-2.6.21.3_patch/include/asm-mips/pci.h
> --- linux-2.6.21.3/include/asm-mips/pci.h 2007-05-29
> 09:15:01.000000000 -0400
> +++ linux-2.6.21.3_patch/include/asm-mips/pci.h 2007-06-05
> 23:34:13.000000000 -0400
> @@ -195,3 +195,22 @@ static inline int pci_get_legacy_ide_irq
> }
>
> #endif /* _ASM_PCI_H */
> +
> +#define HAVE_PCI_MMAP
> +extern int pci_mmap_page_range (struct pci_dev *dev, struct
> vm_area_struct *vma,
> + enum pci_mmap_state mmap_state, int
> write_combine);
> +#define HAVE_PCI_LEGACY
> +extern int pci_mmap_legacy_page_range(struct pci_bus *bus,
> + struct vm_area_struct *vma);
> +extern ssize_t pci_read_legacy_io(struct kobject *kobj, char *buf, loff_t
> off,
> + size_t count);
> +extern ssize_t pci_write_legacy_io(struct kobject *kobj, char *buf,
> loff_t off,
> + size_t count);
> +extern int pci_mmap_legacy_mem(struct kobject *kobj,
> + struct bin_attribute *attr,
> + struct vm_area_struct *vma);
> +
> +#define pci_get_legacy_mem mips_pci_get_legacy_mem
> +#define pci_legacy_read mips_pci_legacy_read
> +#define pci_legacy_write mips_pci_legacy_write
> +
> diff -uprN -X linux-2.6.21.3/Documentation/dontdiff
> linux-2.6.21.3/include/asm-mips/pgtable.h
> linux-2.6.21.3_patch/include/asm-mips/pgtable.h
> --- linux-2.6.21.3/include/asm-mips/pgtable.h 2007-05-29
> 09:15:01.000000000 -0400
> +++ linux-2.6.21.3_patch/include/asm-mips/pgtable.h 2007-06-06
> 00:09:59.000000000 -0400
> @@ -58,6 +58,10 @@ struct vm_area_struct;
> #define __S110 PAGE_SHARED
> #define __S111 PAGE_SHARED
>
> +#define _PAGE_MA_WC (0x6 << 2) /* write coalescing
> memory attribute */
> +#define _PAGE_MA_MASK (0x7 << 2)
> +
> +
> /*
> * ZERO_PAGE is a global shared page that is always zero; used
> * for zero-mapped memory areas etc..
> @@ -323,6 +327,7 @@ static inline pte_t pte_mkyoung(pte_t pt
> * bits as well.
> */
> #define pgprot_noncached pgprot_noncached
> +#define pgprot_writecombine(prot) __pgprot((pgprot_val(prot) &
> ~_PAGE_MA_MASK) | _PAGE_MA_WC)
>
> static inline pgprot_t pgprot_noncached(pgprot_t _prot)
> {
> Binary files linux-2.6.21.3/vmlinux.32 and linux-2.6.21.3_patch/vmlinux.32
> differ
>
>
>
>
>
|