lkml.org 
[lkml]   [2003]   [Dec]   [14]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    SubjectPCI Express support for 2.4 kernel
    Hi,
    PCI-Express platforms will soon appear on the market. It is worth to
    support it.

    Following is patch for 2.4.23 kernel. I tested it on my host, it works
    properly.
    I did it for i386 only, I have no other architecture to test.

    It was patch on the same subject from* Seshadri, Harinarayanan*
    (/harinarayanan.seshadri@intel.com/
    <mailto:harinarayanan.seshadri@intel.com>)
    http://www.cs.helsinki.fi/linux/linux-kernel/2003-17/0247.html
    My version differ in several aspects: it is for 2.4 (vs. 2.6); it do not
    ioremap/unmap page for each transaction.

    How about inclusion in 2.4.24?

    I am not subscribed to lkml, thus please CC me
    (Vladimir Kondratiev <vladimir.kondratiev@intel.com>) in replies.

    Vladimir.
    Enable PCI Express access method for configuration space
    This path includes:
    * access routines itself
    * command line argument "pci=exp" to force PCI Express, similar to "conf1" and "conf2"
    * full 4k config accessed through /proc/bus/pci/...

    How it works:

    With PCI-E, config space accessed through memory. Each device gets its own 4k memory mapped config,
    total 256M for all devices.

    At init time, I map whole region to not spent time for mapping later.

    For /proc/bus/pci/..., I changed PCI_CFG_SPACE_SIZE to variable and changed it to 4k for PCI-E.

    It is tested on 1 platform.

    Author: "Vladimir Kondratiev" <vladimir.kondratiev@intel.com>

    diff -bBdur linux-2.4.23/arch/i386/kernel/pci-i386.h linux-2.4.23-pciexp/arch/i386/kernel/pci-i386.h
    --- linux-2.4.23/arch/i386/kernel/pci-i386.h 2003-11-28 20:26:19.000000000 +0200
    +++ linux-2.4.23-pciexp/arch/i386/kernel/pci-i386.h 2003-12-14 11:08:17.000000000 +0200
    @@ -15,6 +15,7 @@
    #define PCI_PROBE_BIOS 0x0001
    #define PCI_PROBE_CONF1 0x0002
    #define PCI_PROBE_CONF2 0x0004
    +#define PCI_PROBE_EXP 0x0008
    #define PCI_NO_SORT 0x0100
    #define PCI_BIOS_SORT 0x0200
    #define PCI_NO_CHECKS 0x0400
    diff -bBdur linux-2.4.23/arch/i386/kernel/pci-pc.c linux-2.4.23-pciexp/arch/i386/kernel/pci-pc.c
    --- linux-2.4.23/arch/i386/kernel/pci-pc.c 2003-11-28 20:26:19.000000000 +0200
    +++ linux-2.4.23-pciexp/arch/i386/kernel/pci-pc.c 2003-12-14 18:30:52.000000000 +0200
    @@ -20,7 +20,7 @@

    #include "pci-i386.h"

    -unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2;
    +unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2 | PCI_PROBE_EXP;

    int pcibios_last_bus = -1;
    struct pci_bus *pci_root_bus = NULL;
    @@ -427,6 +427,169 @@
    pci_conf2_write_config_dword
    };

    +/**
    + * PCI Express routines
    + * "Vladimir Kondratiev" <vladimir.kondratiev@intel.com>
    + */
    +/**
    + * RRBAR (memory base for PCI-E config space) resides here.
    + * Initialized to default address. Actually, it is platform specific, and
    + * value may vary.
    + * I don't know how to detect it properly, it is chipset specific.
    + */
    +static u32 rrbar_phys=0xe0000000UL;
    +/**
    + * RRBAR is always 256M
    + */
    +static u32 rrbar_size=0x10000000UL;
    +/**
    + * Virtual address for RRBAR
    + */
    +static void* rrbar_virt=NULL;
    +/**
    + * It used to be #define, but I am going to change it.
    + */
    +extern int PCI_CFG_SPACE_SIZE;
    +
    +union pci_exp_data {
    + u32 l;
    + u16 w[2];
    + u8 b[4];
    +} __attribute__((packed));
    +
    +/**
    + * Initializes PCI Express method for config space access.
    + *
    + * There is no standard method to recognize presence of PCI Express,
    + * thus we will assume it is PCI-E, and rely on sanity check to
    + * deassert PCI-E presense. If PCI-E not present,
    + * there is no physical RAM on RRBAR address, and we should read
    + * something like 0xff.
    + *
    + * Creates mapping for whole 256M area.
    + *
    + * @return 1 if OK, 0 if error
    + */
    +static int pci_express_init(void)
    +{
    + /* TODO: check PCI-Ex presense */
    + rrbar_virt=ioremap(rrbar_phys,rrbar_size);
    + if (!rrbar_virt) return 0;
    + return 1;
    +}
    +
    +/**
    + * Shuts down PCI-E resources.
    + */
    +static void pci_express_fini(void)
    +{
    + if (rrbar_virt) {
    + iounmap(rrbar_virt);
    + }
    +}
    +
    +static int pci_exp_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value)
    +{
    + union pci_exp_data d;
    + void* addr=rrbar_virt+(bus << 20)+(dev << 15)+(fn << 12)+(reg &~ 3);
    + d.l=readl(addr);
    + switch (len) {
    + case 1:
    + *value=d.b[reg & 3];
    + break;
    + case 2:
    + *value=d.w[(reg & 2)>>1];
    + break;
    + case 4:
    + *value=d.l;
    + break;
    + }
    + return 0;
    +}
    +
    +static int pci_exp_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value)
    +{
    + void* addr=rrbar_virt+(bus << 20)+(dev << 15)+(fn << 12)+(reg &~ 3);
    + switch (len) {
    + case 1:
    + case 2:
    + {
    + unsigned long flags;
    + union pci_exp_data d;
    + spin_lock_irqsave(&pci_config_lock, flags);
    + switch (len) {
    + case 1:
    + d.l=readl(addr);
    + d.b[reg & 3]=value;
    + break;
    + case 2:
    + d.l=readl(addr);
    + d.w[(reg & 2)>>1]=value;
    + break;
    + }
    + writel(d.l,addr);
    + spin_unlock_irqrestore(&pci_config_lock, flags);
    + }
    + break;
    + case 4:
    + writel(value,addr);
    + break;
    + }
    + return 0;
    +}
    +
    +static int pci_exp_read_config_byte(struct pci_dev *dev, int where, u8 *value)
    +{
    + int result;
    + u32 data;
    + result = pci_exp_read(0, dev->bus->number, PCI_SLOT(dev->devfn),
    + PCI_FUNC(dev->devfn), where, 1, &data);
    + *value = (u8)data;
    + return result;
    +}
    +
    +static int pci_exp_read_config_word(struct pci_dev *dev, int where, u16 *value)
    +{
    + int result;
    + u32 data;
    + result = pci_exp_read(0, dev->bus->number, PCI_SLOT(dev->devfn),
    + PCI_FUNC(dev->devfn), where, 2, &data);
    + *value = (u16)data;
    + return result;
    +}
    +
    +static int pci_exp_read_config_dword(struct pci_dev *dev, int where, u32 *value)
    +{
    + return pci_exp_read(0, dev->bus->number, PCI_SLOT(dev->devfn),
    + PCI_FUNC(dev->devfn), where, 4, value);
    +}
    +
    +static int pci_exp_write_config_byte(struct pci_dev *dev, int where, u8 value)
    +{
    + return pci_exp_write(0, dev->bus->number, PCI_SLOT(dev->devfn),
    + PCI_FUNC(dev->devfn), where, 1, value);
    +}
    +
    +static int pci_exp_write_config_word(struct pci_dev *dev, int where, u16 value)
    +{
    + return pci_exp_write(0, dev->bus->number, PCI_SLOT(dev->devfn),
    + PCI_FUNC(dev->devfn), where, 2, value);
    +}
    +
    +static int pci_exp_write_config_dword(struct pci_dev *dev, int where, u32 value)
    +{
    + return pci_exp_write(0, dev->bus->number, PCI_SLOT(dev->devfn),
    + PCI_FUNC(dev->devfn), where, 4, value);
    +}
    +
    +static struct pci_ops pci_express_conf = {
    + pci_exp_read_config_byte,
    + pci_exp_read_config_word,
    + pci_exp_read_config_dword,
    + pci_exp_write_config_byte,
    + pci_exp_write_config_word,
    + pci_exp_write_config_dword
    +};

    /*
    * Before we decide to use direct hardware access mechanisms, we try to do some
    @@ -465,6 +628,21 @@

    __save_flags(flags); __cli();

    + /**
    + * Check if PCI-express access work
    + */
    + if (pci_express_init()) {
    + if (pci_sanity_check(&pci_express_conf)) {
    + PCI_CFG_SPACE_SIZE=4096;
    + __restore_flags(flags);
    + printk(KERN_INFO "PCI: Using configuration type PCI Express\n");
    + request_mem_region(rrbar_phys, rrbar_size, "PCI-Express config space");
    + return &pci_express_conf;
    + } else {
    + pci_express_fini();
    + }
    + }
    +
    /*
    * Check if configuration type 1 works.
    */
    @@ -1398,16 +1576,18 @@
    #endif

    #ifdef CONFIG_PCI_DIRECT
    - if ((pci_probe & (PCI_PROBE_CONF1 | PCI_PROBE_CONF2))
    + if ((pci_probe & (PCI_PROBE_CONF1 | PCI_PROBE_CONF2 | PCI_PROBE_EXP))
    && (tmp = pci_check_direct())) {
    pci_root_ops = tmp;
    if (pci_root_ops == &pci_direct_conf1) {
    pci_config_read = pci_conf1_read;
    pci_config_write = pci_conf1_write;
    - }
    - else {
    + } else if (pci_root_ops == &pci_direct_conf2) {
    pci_config_read = pci_conf2_read;
    pci_config_write = pci_conf2_write;
    + } else if (pci_root_ops == &pci_express_conf) {
    + pci_config_read = pci_exp_read;
    + pci_config_write = pci_exp_write;
    }
    }
    #endif
    @@ -1489,6 +1669,10 @@
    pci_probe = PCI_PROBE_CONF2 | PCI_NO_CHECKS;
    return NULL;
    }
    + else if (!strcmp(str, "exp")) {
    + pci_probe = PCI_PROBE_EXP | PCI_NO_CHECKS;
    + return NULL;
    + }
    #endif
    else if (!strcmp(str, "rom")) {
    pci_probe |= PCI_ASSIGN_ROMS;
    diff -bBdur linux-2.4.23/drivers/pci/proc.c linux-2.4.23-pciexp/drivers/pci/proc.c
    --- linux-2.4.23/drivers/pci/proc.c 2002-11-29 01:53:14.000000000 +0200
    +++ linux-2.4.23-pciexp/drivers/pci/proc.c 2003-12-14 14:18:58.000000000 +0200
    @@ -16,7 +16,7 @@
    #include <asm/uaccess.h>
    #include <asm/byteorder.h>

    -#define PCI_CFG_SPACE_SIZE 256
    +int PCI_CFG_SPACE_SIZE=256;

    static loff_t
    proc_bus_pci_lseek(struct file *file, loff_t off, int whence)
    \
     
     \ /
      Last update: 2005-03-22 13:59    [W:5.743 / U:0.024 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site