Author: blueswirl Date: 2009-07-11 14:23:24 +0200 (Sat, 11 Jul 2009) New Revision: 507
Modified: trunk/openbios-devel/drivers/pci.c trunk/openbios-devel/drivers/pci.h Log: Improve PCI BAR handling (Igor Kovalenko)
Signed-off-by: igor.v.kovalenko@gmail.com
Modified: trunk/openbios-devel/drivers/pci.c =================================================================== --- trunk/openbios-devel/drivers/pci.c 2009-07-11 12:20:20 UTC (rev 506) +++ trunk/openbios-devel/drivers/pci.c 2009-07-11 12:23:24 UTC (rev 507) @@ -323,7 +323,7 @@ ncells * sizeof(cell)); }
-static void pci_set_assigned_addresses(const pci_config_t *config) +static void pci_set_assigned_addresses(const pci_config_t *config, int num_bars) { phandle_t dev = get_cur_dev(); u32 props[32]; @@ -333,7 +333,7 @@ int flags, space_code;
ncells = 0; - for (i = 0; i < 6; i++) { + for (i = 0; i < num_bars; i++) { if (!config->assigned[i] || !config->sizes[i]) continue; pci_decode_pci_addr(config->assigned[i], @@ -353,7 +353,7 @@ ncells * sizeof(props[0])); }
-static void pci_set_reg(const pci_config_t *config) +static void pci_set_reg(const pci_config_t *config, int num_bars) { phandle_t dev = get_cur_dev(); u32 props[38]; @@ -370,7 +370,7 @@ props[ncells++] = 0x00000000; props[ncells++] = 0x00000000;
- for (i = 0; i < 6; i++) { + for (i = 0; i < num_bars; i++) { if (!config->assigned[i] || !config->sizes[i]) continue;
@@ -474,7 +474,7 @@ }
static void ob_pci_add_properties(pci_addr addr, const pci_dev_t *pci_dev, - const pci_config_t *config) + const pci_config_t *config, int num_bars) { phandle_t dev=get_cur_dev(); int status,id; @@ -553,8 +553,8 @@ pci_dev->icells); }
- pci_set_reg(config); - pci_set_assigned_addresses(config); + pci_set_reg(config, num_bars); + pci_set_assigned_addresses(config, num_bars); OLDWORLD(pci_set_AAPL_address(config));
#ifdef CONFIG_DEBUG_PCI @@ -604,91 +604,112 @@ } #endif
-static void -ob_pci_configure(pci_addr addr, pci_config_t *config, unsigned long *mem_base, - unsigned long *io_base) - +static void ob_pci_configure_bar(pci_addr addr, pci_config_t *config, + int reg, int config_addr, + uint32_t *p_omask, + unsigned long *mem_base, + unsigned long *io_base) { - uint32_t smask, omask, amask, size, reloc, min_align; + uint32_t smask, amask, size, reloc, min_align; unsigned long base; - pci_addr config_addr; - int reg; - uint8_t irq_pin, irq_line;
- irq_pin = pci_config_read8(addr, PCI_INTERRUPT_PIN); - if (irq_pin) { - config->irq_pin = irq_pin; - irq_pin = (((config->dev >> 11) & 0x1F) + irq_pin - 1) & 3; - irq_line = arch->irqs[irq_pin]; - pci_config_write8(addr, PCI_INTERRUPT_LINE, irq_line); - config->irq_line = irq_line; - } else - config->irq_line = -1; + config->assigned[reg] = 0x00000000; + config->sizes[reg] = 0x00000000;
- omask = 0x00000000; - for (reg = 0; reg < 7; reg++) { + if ((*p_omask & 0x0000000f) == 0x4) { + /* 64 bits memory mapping */ + return; + }
- config->assigned[reg] = 0x00000000; - config->sizes[reg] = 0x00000000; + config->regions[reg] = pci_config_read32(addr, config_addr);
- if ((omask & 0x0000000f) == 0x4) { - /* 64 bits memory mapping */ - continue; - } + /* get region size */
- if (reg == 6) - config_addr = PCI_ROM_ADDRESS; - else - config_addr = PCI_BASE_ADDR_0 + reg * 4; + pci_config_write32(addr, config_addr, 0xffffffff); + smask = pci_config_read32(addr, config_addr); + if (smask == 0x00000000 || smask == 0xffffffff) + return;
- config->regions[reg] = pci_config_read32(addr, config_addr); + if (smask & 0x00000001 && reg != 6) { + /* I/O space */ + base = *io_base; + min_align = 1 << 7; + amask = 0x00000001; + pci_config_write16(addr, PCI_COMMAND, + pci_config_read16(addr, + PCI_COMMAND) | + PCI_COMMAND_IO); + } else { + /* Memory Space */ + base = *mem_base; + min_align = 1 << 16; + amask = 0x0000000F; + if (reg == 6) { + smask |= 1; /* ROM */ + } + pci_config_write16(addr, PCI_COMMAND, + pci_config_read16(addr, + PCI_COMMAND) | + PCI_COMMAND_MEMORY); + } + *p_omask = smask & amask; + smask &= ~amask; + size = (~smask) + 1; + config->sizes[reg] = size; + reloc = base; + if (size < min_align) + size = min_align; + reloc = (reloc + size -1) & ~(size - 1); + if (*io_base == base) { + *io_base = reloc + size; + reloc -= arch->io_base; + } else { + *mem_base = reloc + size; + } + pci_config_write32(addr, config_addr, reloc | *p_omask); + config->assigned[reg] = reloc | *p_omask; +}
- /* get region size */ +static void ob_pci_configure_irq(pci_addr addr, pci_config_t *config) +{ + uint8_t irq_pin, irq_line;
- pci_config_write32(addr, config_addr, 0xffffffff); - smask = pci_config_read32(addr, config_addr); - if (smask == 0x00000000 || smask == 0xffffffff) - continue; + irq_pin = pci_config_read8(addr, PCI_INTERRUPT_PIN); + if (irq_pin) { + config->irq_pin = irq_pin; + irq_pin = (((config->dev >> 11) & 0x1F) + irq_pin - 1) & 3; + irq_line = arch->irqs[irq_pin]; + pci_config_write8(addr, PCI_INTERRUPT_LINE, irq_line); + config->irq_line = irq_line; + } else + config->irq_line = -1; +}
- if (smask & 0x00000001 && reg != 6) { - /* I/O space */ - base = *io_base; - min_align = 1 << 7; - amask = 0x00000001; - pci_config_write16(addr, PCI_COMMAND, - pci_config_read16(addr, - PCI_COMMAND) | - PCI_COMMAND_IO); - } else { - /* Memory Space */ - base = *mem_base; - min_align = 1 << 16; - amask = 0x0000000F; - if (reg == 6) { - smask |= 1; /* ROM */ - } - pci_config_write16(addr, PCI_COMMAND, - pci_config_read16(addr, - PCI_COMMAND) | - PCI_COMMAND_MEMORY); - } - omask = smask & amask; - smask &= ~amask; - size = (~smask) + 1; - config->sizes[reg] = size; - reloc = base; - if (size < min_align) - size = min_align; - reloc = (reloc + size -1) & ~(size - 1); - if (*io_base == base) { - *io_base = reloc + size; - reloc -= arch->io_base; - } else { - *mem_base = reloc + size; - } - pci_config_write32(addr, config_addr, reloc | omask); - config->assigned[reg] = reloc | omask; - } +static void +ob_pci_configure(pci_addr addr, pci_config_t *config, int num_regs, int rom_bar, + unsigned long *mem_base, unsigned long *io_base) + +{ + uint32_t omask; + int reg; + pci_addr config_addr; + + ob_pci_configure_irq(addr, config); + + omask = 0x00000000; + for (reg = 0; reg < num_regs; ++reg) { + config_addr = PCI_BASE_ADDR_0 + reg * 4; + + ob_pci_configure_bar(addr, config, reg, config_addr, + &omask, mem_base, + io_base); + } + + if (rom_bar) { + config_addr = rom_bar; + ob_pci_configure_bar(addr, config, reg, config_addr, + &omask, mem_base, io_base); + } }
static void ob_scan_pci_bus(int bus, unsigned long *mem_base, @@ -701,6 +722,7 @@ const pci_dev_t *pci_dev; uint32_t ccode; uint8_t class, subclass, iface, rev; + int num_bars, rom_bar;
activate_device("/"); for (devnum = 0; devnum < 32; devnum++) { @@ -754,9 +776,18 @@
activate_device(config.path);
- ob_pci_configure(addr, &config, mem_base, io_base); - ob_pci_add_properties(addr, pci_dev, &config); + if (htype & PCI_HEADER_TYPE_BRIDGE) { + num_bars = 2; + rom_bar = PCI_ROM_ADDRESS1; + } else { + num_bars = 6; + rom_bar = PCI_ROM_ADDRESS; + }
+ ob_pci_configure(addr, &config, num_bars, rom_bar, + mem_base, io_base); + ob_pci_add_properties(addr, pci_dev, &config, num_bars); + if (class == PCI_BASE_CLASS_BRIDGE && (subclass == PCI_SUBCLASS_BRIDGE_HOST || subclass == PCI_SUBCLASS_BRIDGE_PCI)) {
Modified: trunk/openbios-devel/drivers/pci.h =================================================================== --- trunk/openbios-devel/drivers/pci.h 2009-07-11 12:20:20 UTC (rev 506) +++ trunk/openbios-devel/drivers/pci.h 2009-07-11 12:23:24 UTC (rev 507) @@ -48,6 +48,7 @@ #define PCI_ROM_ADDRESS 0x30 /* Bits 31..11 are address, 10..1 reserved */ #define PCI_ROM_ADDRESS_ENABLE 0x01 #define PCI_ROM_ADDRESS_MASK (~0x7ffUL) +#define PCI_ROM_ADDRESS1 0x38 /* ROM_ADDRESS in bridge header */
#define PCI_INTERRUPT_LINE 0x3c /* 8 bits */ #define PCI_INTERRUPT_PIN 0x3d /* 8 bits */