Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/bus/pci/pciintel/pci.c

    rc90aed4 r92d5279  
    5151#include <ddf/log.h>
    5252#include <ipc/dev_iface.h>
    53 #include <ipc/irc.h>
    54 #include <ns.h>
    55 #include <ipc/services.h>
    56 #include <sysinfo.h>
     53#include <irc.h>
    5754#include <ops/hw_res.h>
    5855#include <device/hw_res.h>
     56#include <ops/pio_window.h>
     57#include <device/pio_window.h>
    5958#include <ddi.h>
    6059#include <pci_dev_iface.h>
     
    6463#define NAME "pciintel"
    6564
     65#define CONF_ADDR_ENABLE        (1 << 31)
    6666#define CONF_ADDR(bus, dev, fn, reg) \
    67         ((1 << 31) | (bus << 16) | (dev << 11) | (fn << 8) | (reg & ~3))
     67        ((bus << 16) | (dev << 11) | (fn << 8) | (reg & ~3))
    6868
    6969/** Obtain PCI function soft-state from DDF function node */
     
    104104        assert(fnode);
    105105        pci_fun_t *dev_data = pci_fun(fnode);
    106        
    107         sysarg_t apic;
    108         sysarg_t i8259;
    109        
    110         async_sess_t *irc_sess = NULL;
    111        
    112         if (((sysinfo_get_value("apic", &apic) == EOK) && (apic))
    113             || ((sysinfo_get_value("i8259", &i8259) == EOK) && (i8259))) {
    114                 irc_sess = service_connect_blocking(EXCHANGE_SERIALIZE,
    115                     SERVICE_IRC, 0, 0);
    116         }
    117        
    118         if (!irc_sess)
    119                 return false;
    120106       
    121107        size_t i = 0;
     
    123109        for (; i < res->count; i++) {
    124110                if (res->resources[i].type == INTERRUPT) {
    125                         const int irq = res->resources[i].res.interrupt.irq;
     111                        int rc = irc_enable_interrupt(
     112                            res->resources[i].res.interrupt.irq);
    126113                       
    127                         async_exch_t *exch = async_exchange_begin(irc_sess);
    128                         const int rc =
    129                             async_req_1_0(exch, IRC_ENABLE_INTERRUPT, irq);
    130                         async_exchange_end(exch);
    131                        
    132                         if (rc != EOK) {
    133                                 async_hangup(irc_sess);
     114                        if (rc != EOK)
    134115                                return false;
    135                         }
    136116                }
    137117        }
    138118       
    139         async_hangup(irc_sess);
    140119        return true;
    141120}
    142121
    143 static int pci_config_space_write_32(ddf_fun_t *fun, uint32_t address,
     122static pio_window_t *pciintel_get_pio_window(ddf_fun_t *fnode)
     123{
     124        pci_fun_t *fun = pci_fun(fnode);
     125       
     126        if (fun == NULL)
     127                return NULL;
     128        return &fun->pio_window;
     129}
     130
     131
     132static int config_space_write_32(ddf_fun_t *fun, uint32_t address,
    144133    uint32_t data)
    145134{
     
    150139}
    151140
    152 static int pci_config_space_write_16(
     141static int config_space_write_16(
    153142    ddf_fun_t *fun, uint32_t address, uint16_t data)
    154143{
     
    159148}
    160149
    161 static int pci_config_space_write_8(
     150static int config_space_write_8(
    162151    ddf_fun_t *fun, uint32_t address, uint8_t data)
    163152{
     
    168157}
    169158
    170 static int pci_config_space_read_32(
     159static int config_space_read_32(
    171160    ddf_fun_t *fun, uint32_t address, uint32_t *data)
    172161{
     
    177166}
    178167
    179 static int pci_config_space_read_16(
     168static int config_space_read_16(
    180169    ddf_fun_t *fun, uint32_t address, uint16_t *data)
    181170{
     
    186175}
    187176
    188 static int pci_config_space_read_8(
     177static int config_space_read_8(
    189178    ddf_fun_t *fun, uint32_t address, uint8_t *data)
    190179{
     
    200189};
    201190
     191static pio_window_ops_t pciintel_pio_window_ops = {
     192        .get_pio_window = &pciintel_get_pio_window
     193};
     194
    202195static pci_dev_iface_t pci_dev_ops = {
    203         .config_space_read_8 = &pci_config_space_read_8,
    204         .config_space_read_16 = &pci_config_space_read_16,
    205         .config_space_read_32 = &pci_config_space_read_32,
    206         .config_space_write_8 = &pci_config_space_write_8,
    207         .config_space_write_16 = &pci_config_space_write_16,
    208         .config_space_write_32 = &pci_config_space_write_32
     196        .config_space_read_8 = &config_space_read_8,
     197        .config_space_read_16 = &config_space_read_16,
     198        .config_space_read_32 = &config_space_read_32,
     199        .config_space_write_8 = &config_space_write_8,
     200        .config_space_write_16 = &config_space_write_16,
     201        .config_space_write_32 = &config_space_write_32
    209202};
    210203
    211204static ddf_dev_ops_t pci_fun_ops = {
    212205        .interfaces[HW_RES_DEV_IFACE] = &pciintel_hw_res_ops,
     206        .interfaces[PIO_WINDOW_DEV_IFACE] = &pciintel_pio_window_ops,
    213207        .interfaces[PCI_DEV_IFACE] = &pci_dev_ops
    214208};
     
    233227static void pci_conf_read(pci_fun_t *fun, int reg, uint8_t *buf, size_t len)
    234228{
     229        const uint32_t conf_addr = CONF_ADDR(fun->bus, fun->dev, fun->fn, reg);
    235230        pci_bus_t *bus = pci_bus_from_fun(fun);
     231        uint32_t val;
    236232       
    237233        fibril_mutex_lock(&bus->conf_mutex);
    238        
    239         const uint32_t conf_addr = CONF_ADDR(fun->bus, fun->dev, fun->fn, reg);
    240         void *addr = bus->conf_data_port + (reg & 3);
    241        
    242         pio_write_32(bus->conf_addr_port, host2uint32_t_le(conf_addr));
    243        
     234
     235        if (bus->conf_addr_reg) {
     236                pio_write_32(bus->conf_addr_reg,
     237                    host2uint32_t_le(CONF_ADDR_ENABLE | conf_addr));
     238                /*
     239                 * Always read full 32-bits from the PCI conf_data_port
     240                 * register and get the desired portion of it afterwards. Some
     241                 * architectures do not support shorter PIO reads offset from
     242                 * this register.
     243                 */
     244                val = uint32_t_le2host(pio_read_32(bus->conf_data_reg));
     245        } else {
     246                val = uint32_t_le2host(pio_read_32(
     247                    &bus->conf_space[conf_addr / sizeof(ioport32_t)]));
     248        }
     249
    244250        switch (len) {
    245251        case 1:
    246                 /* No endianness change for 1 byte */
    247                 buf[0] = pio_read_8(addr);
     252                *buf = (uint8_t) (val >> ((reg & 3) * 8));
    248253                break;
    249254        case 2:
    250                 ((uint16_t *) buf)[0] = uint16_t_le2host(pio_read_16(addr));
     255                *((uint16_t *) buf) = (uint16_t) (val >> ((reg & 3)) * 8);
    251256                break;
    252257        case 4:
    253                 ((uint32_t *) buf)[0] = uint32_t_le2host(pio_read_32(addr));
     258                *((uint32_t *) buf) = (uint32_t) val;
    254259                break;
    255260        }
     
    260265static void pci_conf_write(pci_fun_t *fun, int reg, uint8_t *buf, size_t len)
    261266{
     267        const uint32_t conf_addr = CONF_ADDR(fun->bus, fun->dev, fun->fn, reg);
    262268        pci_bus_t *bus = pci_bus_from_fun(fun);
     269        uint32_t val;
    263270       
    264271        fibril_mutex_lock(&bus->conf_mutex);
    265        
    266         const uint32_t conf_addr = CONF_ADDR(fun->bus, fun->dev, fun->fn, reg);
    267         void *addr = bus->conf_data_port + (reg & 3);
    268        
    269         pio_write_32(bus->conf_addr_port, host2uint32_t_le(conf_addr));
     272
     273        /*
     274         * Prepare to write full 32-bits to the PCI conf_data_port register.
     275         * Some architectures do not support shorter PIO writes offset from this
     276         * register.
     277         */
     278
     279        if (len < 4) {
     280                /*
     281                 * We have fewer than full 32-bits, so we need to read the
     282                 * missing bits first.
     283                 */
     284                if (bus->conf_addr_reg) {
     285                        pio_write_32(bus->conf_addr_reg,
     286                            host2uint32_t_le(CONF_ADDR_ENABLE | conf_addr));
     287                        val = uint32_t_le2host(pio_read_32(bus->conf_data_reg));
     288                } else {
     289                        val = uint32_t_le2host(pio_read_32(
     290                            &bus->conf_space[conf_addr / sizeof(ioport32_t)]));
     291                }
     292        }
    270293       
    271294        switch (len) {
    272295        case 1:
    273                 /* No endianness change for 1 byte */
    274                 pio_write_8(addr, buf[0]);
     296                val &= ~(0xffU << ((reg & 3) * 8));
     297                val |= *buf << ((reg & 3) * 8);
    275298                break;
    276299        case 2:
    277                 pio_write_16(addr, host2uint16_t_le(((uint16_t *) buf)[0]));
     300                val &= ~(0xffffU << ((reg & 3) * 8));
     301                val |= *((uint16_t *) buf) << ((reg & 3) * 8);
    278302                break;
    279303        case 4:
    280                 pio_write_32(addr, host2uint32_t_le(((uint32_t *) buf)[0]));
     304                val = *((uint32_t *) buf);
    281305                break;
     306        }
     307
     308        if (bus->conf_addr_reg) {
     309                pio_write_32(bus->conf_addr_reg,
     310                    host2uint32_t_le(CONF_ADDR_ENABLE | conf_addr));
     311                pio_write_32(bus->conf_data_reg, host2uint32_t_le(val));
     312        } else {
     313                pio_write_32(&bus->conf_space[conf_addr / sizeof(ioport32_t)],
     314                    host2uint32_t_le(val));
    282315        }
    283316       
     
    411444                hw_resources[count].res.io_range.address = range_addr;
    412445                hw_resources[count].res.io_range.size = range_size;
     446                hw_resources[count].res.io_range.relative = true;
    413447                hw_resources[count].res.io_range.endianness = LITTLE_ENDIAN;
    414448        } else {
     
    416450                hw_resources[count].res.mem_range.address = range_addr;
    417451                hw_resources[count].res.mem_range.size = range_size;
     452                hw_resources[count].res.mem_range.relative = false;
    418453                hw_resources[count].res.mem_range.endianness = LITTLE_ENDIAN;
    419454        }
     
    433468{
    434469        /* Value of the BAR */
    435         uint32_t val, mask;
     470        uint32_t val;
     471        uint32_t bar;
     472        uint32_t mask;
     473
    436474        /* IO space address */
    437475        bool io;
     
    471509        /* Get the address mask. */
    472510        pci_conf_write_32(fun, addr, 0xffffffff);
    473         mask &= pci_conf_read_32(fun, addr);
    474        
     511        bar = pci_conf_read_32(fun, addr);
     512
     513        /*
     514         * Unimplemented BARs read back as all 0's.
     515         */
     516        if (!bar)
     517                return addr + (addrw64 ? 8 : 4);
     518
     519        mask &= bar;   
     520
    475521        /* Restore the original value. */
    476522        pci_conf_write_32(fun, addr, val);
     
    520566{
    521567        uint8_t irq = pci_conf_read_8(fun, PCI_BRIDGE_INT_LINE);
    522         if (irq != 0xff)
     568        uint8_t pin = pci_conf_read_8(fun, PCI_BRIDGE_INT_PIN);
     569
     570        if (pin != 0 && irq != 0xff)
    523571                pci_add_interrupt(fun, irq);
    524572}
     
    583631                        pci_read_bars(fun);
    584632                        pci_read_interrupt(fun);
     633
     634                        /* Propagate the PIO window to the function. */
     635                        fun->pio_window = bus->pio_win;
    585636                       
    586637                        ddf_fun_set_ops(fun->fnode, &pci_fun_ops);
     
    588639                        ddf_msg(LVL_DEBUG, "Adding new function %s.",
    589640                            ddf_fun_get_name(fun->fnode));
    590                        
     641
    591642                        pci_fun_create_match_ids(fun);
    592643                       
     
    613664static int pci_dev_add(ddf_dev_t *dnode)
    614665{
     666        hw_resource_list_t hw_resources;
    615667        pci_bus_t *bus = NULL;
    616668        ddf_fun_t *ctl = NULL;
     
    631683        bus->dnode = dnode;
    632684       
    633         sess = ddf_dev_parent_sess_create(dnode, EXCHANGE_SERIALIZE);
     685        sess = ddf_dev_parent_sess_create(dnode);
    634686        if (sess == NULL) {
    635687                ddf_msg(LVL_ERROR, "pci_dev_add failed to connect to the "
     
    638690                goto fail;
    639691        }
    640        
    641         hw_resource_list_t hw_resources;
     692
     693        rc = pio_window_get(sess, &bus->pio_win);
     694        if (rc != EOK) {
     695                ddf_msg(LVL_ERROR, "pci_dev_add failed to get PIO window "
     696                    "for the device.");
     697                goto fail;
     698        }
    642699       
    643700        rc = hw_res_get_resource_list(sess, &hw_resources);
     
    650707       
    651708       
    652         assert(hw_resources.count > 1);
    653         assert(hw_resources.resources[0].type == IO_RANGE);
    654         assert(hw_resources.resources[0].res.io_range.size >= 4);
    655        
    656         assert(hw_resources.resources[1].type == IO_RANGE);
    657         assert(hw_resources.resources[1].res.io_range.size >= 4);
    658        
    659         ddf_msg(LVL_DEBUG, "conf_addr = %" PRIx64 ".",
    660             hw_resources.resources[0].res.io_range.address);
    661         ddf_msg(LVL_DEBUG, "data_addr = %" PRIx64 ".",
    662             hw_resources.resources[1].res.io_range.address);
    663        
    664         bus->conf_io_addr =
    665             (uint32_t) hw_resources.resources[0].res.io_range.address;
    666         bus->conf_io_data =
    667             (uint32_t) hw_resources.resources[1].res.io_range.address;
    668        
    669         if (pio_enable((void *)(uintptr_t)bus->conf_io_addr, 4,
    670             &bus->conf_addr_port)) {
    671                 ddf_msg(LVL_ERROR, "Failed to enable configuration ports.");
    672                 rc = EADDRNOTAVAIL;
    673                 goto fail;
    674         }
    675         if (pio_enable((void *)(uintptr_t)bus->conf_io_data, 4,
    676             &bus->conf_data_port)) {
    677                 ddf_msg(LVL_ERROR, "Failed to enable configuration ports.");
    678                 rc = EADDRNOTAVAIL;
    679                 goto fail;
     709        assert(hw_resources.count >= 1);
     710
     711        if (hw_resources.count == 1) {
     712                assert(hw_resources.resources[0].type == MEM_RANGE);
     713
     714                ddf_msg(LVL_DEBUG, "conf_addr_space = %" PRIx64 ".",
     715                    hw_resources.resources[0].res.mem_range.address);
     716
     717                if (pio_enable_resource(&bus->pio_win,
     718                    &hw_resources.resources[0],
     719                    (void **) &bus->conf_space)) {
     720                        ddf_msg(LVL_ERROR,
     721                            "Failed to map configuration space.");
     722                        rc = EADDRNOTAVAIL;
     723                        goto fail;
     724                }
     725               
     726        } else {
     727                assert(hw_resources.resources[0].type == IO_RANGE);
     728                assert(hw_resources.resources[0].res.io_range.size >= 4);
     729       
     730                assert(hw_resources.resources[1].type == IO_RANGE);
     731                assert(hw_resources.resources[1].res.io_range.size >= 4);
     732       
     733                ddf_msg(LVL_DEBUG, "conf_addr = %" PRIx64 ".",
     734                    hw_resources.resources[0].res.io_range.address);
     735                ddf_msg(LVL_DEBUG, "data_addr = %" PRIx64 ".",
     736                    hw_resources.resources[1].res.io_range.address);
     737       
     738                if (pio_enable_resource(&bus->pio_win,
     739                    &hw_resources.resources[0],
     740                    (void **) &bus->conf_addr_reg)) {
     741                        ddf_msg(LVL_ERROR,
     742                            "Failed to enable configuration ports.");
     743                        rc = EADDRNOTAVAIL;
     744                        goto fail;
     745                }
     746                if (pio_enable_resource(&bus->pio_win,
     747                    &hw_resources.resources[1],
     748                    (void **) &bus->conf_data_reg)) {
     749                        ddf_msg(LVL_ERROR,
     750                            "Failed to enable configuration ports.");
     751                        rc = EADDRNOTAVAIL;
     752                        goto fail;
     753                }
    680754        }
    681755       
     
    729803{
    730804        ddf_log_init(NAME);
    731         pci_fun_ops.interfaces[HW_RES_DEV_IFACE] = &pciintel_hw_res_ops;
    732         pci_fun_ops.interfaces[PCI_DEV_IFACE] = &pci_dev_ops;
    733805}
    734806
Note: See TracChangeset for help on using the changeset viewer.