123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931 |
- /*
- * Copyright (c) 2006-2022, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2022-10-24 GuEe-GUI first version
- */
- #include <rtthread.h>
- #define DBG_TAG "pci.probe"
- #define DBG_LVL DBG_INFO
- #include <rtdbg.h>
- #include <drivers/pci.h>
- #include <drivers/core/bus.h>
- #include "procfs.h"
- rt_inline void spin_lock(struct rt_spinlock *spinlock)
- {
- rt_hw_spin_lock(&spinlock->lock);
- }
- rt_inline void spin_unlock(struct rt_spinlock *spinlock)
- {
- rt_hw_spin_unlock(&spinlock->lock);
- }
- struct rt_pci_host_bridge *rt_pci_host_bridge_alloc(rt_size_t priv_size)
- {
- struct rt_pci_host_bridge *bridge = rt_calloc(1, sizeof(*bridge) + priv_size);
- return bridge;
- }
- rt_err_t rt_pci_host_bridge_free(struct rt_pci_host_bridge *bridge)
- {
- if (!bridge)
- {
- return -RT_EINVAL;
- }
- if (bridge->bus_regions)
- {
- rt_free(bridge->bus_regions);
- }
- if (bridge->dma_regions)
- {
- rt_free(bridge->dma_regions);
- }
- rt_free(bridge);
- return RT_EOK;
- }
- rt_err_t rt_pci_host_bridge_init(struct rt_pci_host_bridge *host_bridge)
- {
- rt_err_t err = RT_EOK;
- if (host_bridge->parent.ofw_node)
- {
- err = rt_pci_ofw_host_bridge_init(host_bridge->parent.ofw_node, host_bridge);
- }
- return err;
- }
- struct rt_pci_device *rt_pci_alloc_device(struct rt_pci_bus *bus)
- {
- struct rt_pci_device *pdev = rt_calloc(1, sizeof(*pdev));
- if (!pdev)
- {
- return RT_NULL;
- }
- rt_list_init(&pdev->list);
- pdev->bus = bus;
- if (bus)
- {
- spin_lock(&bus->lock);
- rt_list_insert_before(&bus->devices_nodes, &pdev->list);
- spin_unlock(&bus->lock);
- }
- pdev->subsystem_vendor = PCI_ANY_ID;
- pdev->subsystem_device = PCI_ANY_ID;
- pdev->irq = -1;
- for (int i = 0; i < RT_ARRAY_SIZE(pdev->resource); ++i)
- {
- pdev->resource[i].flags = PCI_BUS_REGION_F_NONE;
- }
- #ifdef RT_PCI_MSI
- rt_list_init(&pdev->msi_desc_nodes);
- rt_spin_lock_init(&pdev->msi_lock);
- #endif
- return pdev;
- }
- struct rt_pci_device *rt_pci_scan_single_device(struct rt_pci_bus *bus, rt_uint32_t devfn)
- {
- rt_err_t err;
- struct rt_pci_device *pdev = RT_NULL;
- rt_uint16_t vendor = PCI_ANY_ID, device = PCI_ANY_ID;
- if (!bus)
- {
- goto _end;
- }
- err = rt_pci_bus_read_config_u16(bus, devfn, PCIR_VENDOR, &vendor);
- rt_pci_bus_read_config_u16(bus, devfn, PCIR_DEVICE, &device);
- if (vendor == (typeof(vendor))PCI_ANY_ID ||
- vendor == (typeof(vendor))0x0000 || err)
- {
- goto _end;
- }
- if (!(pdev = rt_pci_alloc_device(bus)))
- {
- goto _end;
- }
- pdev->devfn = devfn;
- pdev->vendor = vendor;
- pdev->device = device;
- rt_dm_dev_set_name(&pdev->parent, "%04x:%02x:%02x.%u",
- rt_pci_domain(pdev), pdev->bus->number,
- RT_PCI_SLOT(pdev->devfn), RT_PCI_FUNC(pdev->devfn));
- if (rt_pci_setup_device(pdev))
- {
- rt_free(pdev);
- pdev = RT_NULL;
- goto _end;
- }
- pci_procfs_attach(pdev);
- rt_pci_device_register(pdev);
- _end:
- return pdev;
- }
- static rt_bool_t pci_intx_mask_broken(struct rt_pci_device *pdev)
- {
- rt_bool_t res = RT_FALSE;
- rt_uint16_t orig, toggle, new;
- rt_pci_read_config_u16(pdev, PCIR_COMMAND, &orig);
- toggle = orig ^ PCIM_CMD_INTxDIS;
- rt_pci_write_config_u16(pdev, PCIR_COMMAND, toggle);
- rt_pci_read_config_u16(pdev, PCIR_COMMAND, &new);
- rt_pci_write_config_u16(pdev, PCIR_COMMAND, orig);
- if (new != toggle)
- {
- res = RT_TRUE;
- }
- return res;
- }
- static void pci_read_irq(struct rt_pci_device *pdev)
- {
- rt_uint8_t irq = 0;
- rt_pci_read_config_u8(pdev, PCIR_INTPIN, &irq);
- pdev->pin = irq;
- if (irq)
- {
- rt_pci_read_config_u8(pdev, PCIR_INTLINE, &irq);
- }
- pdev->irq = irq;
- }
- static void pcie_set_port_type(struct rt_pci_device *pdev)
- {
- int pos;
- if (!(pos = rt_pci_find_capability(pdev, PCIY_EXPRESS)))
- {
- return;
- }
- pdev->pcie_cap = pos;
- }
- static void pci_configure_ari(struct rt_pci_device *pdev)
- {
- rt_uint32_t cap, ctl2_ari;
- struct rt_pci_device *bridge;
- if (!rt_pci_is_pcie(pdev) || pdev->devfn)
- {
- return;
- }
- bridge = pdev->bus->self;
- if (rt_pci_is_root_bus(pdev->bus) || !bridge)
- {
- return;
- }
- rt_pci_read_config_u32(bridge, bridge->pcie_cap + PCIER_DEVICE_CAP2, &cap);
- if (!(cap & PCIEM_CAP2_ARI))
- {
- return;
- }
- rt_pci_read_config_u32(bridge, bridge->pcie_cap + PCIER_DEVICE_CTL2, &ctl2_ari);
- if (rt_pci_find_ext_capability(pdev, PCIZ_ARI))
- {
- ctl2_ari |= PCIEM_CTL2_ARI;
- bridge->ari_enabled = RT_TRUE;
- }
- else
- {
- ctl2_ari &= ~PCIEM_CTL2_ARI;
- bridge->ari_enabled = RT_FALSE;
- }
- rt_pci_write_config_u32(bridge, bridge->pcie_cap + PCIER_DEVICE_CTL2, ctl2_ari);
- }
- static rt_uint16_t pci_cfg_space_size_ext(struct rt_pci_device *pdev)
- {
- rt_uint32_t status;
- if (rt_pci_read_config_u32(pdev, PCI_REGMAX + 1, &status))
- {
- return PCI_REGMAX + 1;
- }
- return PCIE_REGMAX + 1;
- }
- static rt_uint16_t pci_cfg_space_size(struct rt_pci_device *pdev)
- {
- int pos;
- rt_uint32_t status;
- rt_uint16_t class = pdev->class >> 8;
- if (class == PCIS_BRIDGE_HOST)
- {
- return pci_cfg_space_size_ext(pdev);
- }
- if (rt_pci_is_pcie(pdev))
- {
- return pci_cfg_space_size_ext(pdev);
- }
- pos = rt_pci_find_capability(pdev, PCIY_PCIX);
- if (!pos)
- {
- return PCI_REGMAX + 1;
- }
- rt_pci_read_config_u32(pdev, pos + PCIXR_STATUS, &status);
- if (status & (PCIXM_STATUS_266CAP | PCIXM_STATUS_533CAP))
- {
- return pci_cfg_space_size_ext(pdev);
- }
- return PCI_REGMAX + 1;
- }
- static void pci_init_capabilities(struct rt_pci_device *pdev)
- {
- rt_pci_pme_init(pdev);
- #ifdef RT_PCI_MSI
- rt_pci_msi_init(pdev); /* Disable MSI */
- rt_pci_msix_init(pdev); /* Disable MSI-X */
- #endif
- pcie_set_port_type(pdev);
- pdev->cfg_size = pci_cfg_space_size(pdev);
- pci_configure_ari(pdev);
- pdev->no_msi = RT_FALSE;
- pdev->msi_enabled = RT_FALSE;
- pdev->msix_enabled = RT_FALSE;
- }
- rt_err_t rt_pci_setup_device(struct rt_pci_device *pdev)
- {
- rt_uint8_t pos;
- rt_uint32_t class = 0;
- struct rt_pci_host_bridge *host_bridge;
- if (!pdev)
- {
- return -RT_EINVAL;
- }
- if (!(host_bridge = rt_pci_find_host_bridge(pdev->bus)))
- {
- return -RT_EINVAL;
- }
- rt_pci_ofw_device_init(pdev);
- rt_pci_read_config_u32(pdev, PCIR_REVID, &class);
- pdev->revision = class & 0xff;
- pdev->class = class >> 8; /* Upper 3 bytes */
- rt_pci_read_config_u8(pdev, PCIR_HDRTYPE, &pdev->hdr_type);
- /* Clear errors left from system firmware */
- rt_pci_write_config_u16(pdev, PCIR_STATUS, 0xffff);
- if (pdev->hdr_type & 0x80)
- {
- pdev->multi_function = RT_TRUE;
- }
- pdev->hdr_type &= PCIM_HDRTYPE;
- if (pci_intx_mask_broken(pdev))
- {
- pdev->broken_intx_masking = RT_TRUE;
- }
- rt_dm_dev_set_name(&pdev->parent, "%04x:%02x:%02x.%u", rt_pci_domain(pdev),
- pdev->bus->number, RT_PCI_SLOT(pdev->devfn), RT_PCI_FUNC(pdev->devfn));
- switch (pdev->hdr_type)
- {
- case PCIM_HDRTYPE_NORMAL:
- if (class == PCIS_BRIDGE_PCI)
- {
- goto error;
- }
- pci_read_irq(pdev);
- rt_pci_device_alloc_resource(host_bridge, pdev);
- rt_pci_read_config_u16(pdev, PCIR_SUBVEND_0, &pdev->subsystem_vendor);
- rt_pci_read_config_u16(pdev, PCIR_SUBDEV_0, &pdev->subsystem_device);
- break;
- case PCIM_HDRTYPE_BRIDGE:
- pci_read_irq(pdev);
- rt_pci_device_alloc_resource(host_bridge, pdev);
- pos = rt_pci_find_capability(pdev, PCIY_SUBVENDOR);
- if (pos)
- {
- rt_pci_read_config_u16(pdev, PCIR_SUBVENDCAP, &pdev->subsystem_vendor);
- rt_pci_read_config_u16(pdev, PCIR_SUBDEVCAP, &pdev->subsystem_device);
- }
- break;
- case PCIM_HDRTYPE_CARDBUS:
- if (class != PCIS_BRIDGE_CARDBUS)
- {
- goto error;
- }
- pci_read_irq(pdev);
- rt_pci_device_alloc_resource(host_bridge, pdev);
- rt_pci_read_config_u16(pdev, PCIR_SUBVEND_2, &pdev->subsystem_vendor);
- rt_pci_read_config_u16(pdev, PCIR_SUBDEV_2, &pdev->subsystem_device);
- break;
- default:
- LOG_E("Ignoring device unknown header type %02x", pdev->hdr_type);
- return -RT_EIO;
- error:
- LOG_E("Ignoring class %08x (doesn't match header type %02x)", pdev->class, pdev->hdr_type);
- pdev->class = PCIC_NOT_DEFINED << 8;
- }
- pci_init_capabilities(pdev);
- if (rt_pci_is_pcie(pdev))
- {
- rt_pci_read_config_u16(pdev, pdev->pcie_cap + PCIER_FLAGS, &pdev->exp_flags);
- }
- return RT_EOK;
- }
- static struct rt_pci_bus *pci_alloc_bus(struct rt_pci_bus *parent);
- static rt_err_t pci_child_bus_init(struct rt_pci_bus *bus, rt_uint32_t bus_no,
- struct rt_pci_host_bridge *host_bridge, struct rt_pci_device *pdev)
- {
- rt_err_t err;
- struct rt_pci_bus *parent_bus = bus->parent;
- bus->sysdata = parent_bus->sysdata;
- bus->self = pdev;
- bus->ops = host_bridge->child_ops ? : parent_bus->ops;
- bus->number = bus_no;
- rt_sprintf(bus->name, "%04x:%02x", host_bridge->domain, bus_no);
- rt_pci_ofw_bus_init(bus);
- if (bus->ops->add)
- {
- if ((err = bus->ops->add(bus)))
- {
- rt_pci_ofw_bus_free(bus);
- LOG_E("PCI-Bus<%s> add bus failed with err = %s",
- bus->name, rt_strerror(err));
- return err;
- }
- }
- return RT_EOK;
- }
- static rt_bool_t pci_ea_fixed_busnrs(struct rt_pci_device *pdev,
- rt_uint8_t *sec, rt_uint8_t *sub)
- {
- int pos, offset;
- rt_uint32_t dw;
- rt_uint8_t ea_sec, ea_sub;
- pos = rt_pci_find_capability(pdev, PCIY_EA);
- if (!pos)
- {
- return RT_FALSE;
- }
- offset = pos + PCIR_EA_FIRST_ENT;
- rt_pci_read_config_u32(pdev, offset, &dw);
- ea_sec = PCIM_EA_SEC_NR(dw);
- ea_sub = PCIM_EA_SUB_NR(dw);
- if (ea_sec == 0 || ea_sub < ea_sec)
- {
- return RT_FALSE;
- }
- *sec = ea_sec;
- *sub = ea_sub;
- return RT_TRUE;
- }
- static void pcie_fixup_link(struct rt_pci_device *pdev)
- {
- int pos = pdev->pcie_cap;
- rt_uint16_t exp_lnkctl, exp_lnkctl2, exp_lnksta;
- rt_uint16_t exp_type = pdev->exp_flags & PCIEM_FLAGS_TYPE;
- if ((pdev->exp_flags & PCIEM_FLAGS_VERSION) < 2)
- {
- return;
- }
- if (exp_type != PCIEM_TYPE_ROOT_PORT &&
- exp_type != PCIEM_TYPE_DOWNSTREAM_PORT &&
- exp_type != PCIEM_TYPE_PCIE_BRIDGE)
- {
- return;
- }
- rt_pci_read_config_u16(pdev, pos + PCIER_LINK_CTL, &exp_lnkctl);
- rt_pci_read_config_u16(pdev, pos + PCIER_LINK_CTL2, &exp_lnkctl2);
- rt_pci_write_config_u16(pdev, pos + PCIER_LINK_CTL2,
- (exp_lnkctl2 & ~PCIEM_LNKCTL2_TLS) | PCIEM_LNKCTL2_TLS_2_5GT);
- rt_pci_write_config_u16(pdev, pos + PCIER_LINK_CTL,
- exp_lnkctl | PCIEM_LINK_CTL_RETRAIN_LINK);
- for (int i = 0; i < 20; ++i)
- {
- rt_pci_read_config_u16(pdev, pos + PCIER_LINK_STA, &exp_lnksta);
- if (!!(exp_lnksta & PCIEM_LINK_STA_DL_ACTIVE))
- {
- goto _status_sync;
- }
- rt_thread_mdelay(10);
- }
- /* Fail, restore */
- rt_pci_write_config_u16(pdev, pos + PCIER_LINK_CTL2, exp_lnkctl2);
- rt_pci_write_config_u16(pdev, pos + PCIER_LINK_CTL,
- exp_lnkctl | PCIEM_LINK_CTL_RETRAIN_LINK);
- _status_sync:
- /* Wait a while for success or failure */
- rt_thread_mdelay(100);
- }
- static rt_uint32_t pci_scan_bridge_extend(struct rt_pci_bus *bus, struct rt_pci_device *pdev,
- rt_uint32_t bus_no_start, rt_uint32_t buses, rt_bool_t reconfigured)
- {
- rt_bool_t fixed_buses;
- rt_uint8_t fixed_sub, fixed_sec;
- rt_uint8_t primary, secondary, subordinate;
- rt_uint32_t value, bus_no = bus_no_start;
- struct rt_pci_bus *next_bus;
- struct rt_pci_host_bridge *host_bridge;
- /* We not supported init CardBus, it always used in the PC servers. */
- if (pdev->hdr_type == PCIM_HDRTYPE_CARDBUS)
- {
- LOG_E("CardBus is not supported in system");
- goto _end;
- }
- rt_pci_read_config_u32(pdev, PCIR_PRIBUS_1, &value);
- primary = value & 0xff;
- secondary = (value >> 8) & 0xff;
- subordinate = (value >> 16) & 0xff;
- if (primary == bus->number && bus->number > secondary && secondary > subordinate)
- {
- if (!reconfigured)
- {
- goto _end;
- }
- LOG_I("Bridge configuration: primary(%02x) secondary(%02x) subordinate(%02x)",
- primary, secondary, subordinate);
- }
- if (pdev->pcie_cap)
- {
- pcie_fixup_link(pdev);
- }
- ++bus_no;
- /* Count of subordinate */
- buses -= !!buses;
- host_bridge = rt_pci_find_host_bridge(bus);
- RT_ASSERT(host_bridge != RT_NULL);
- /* Clear errors */
- rt_pci_write_config_u16(pdev, PCIR_STATUS, RT_UINT16_MAX);
- fixed_buses = pci_ea_fixed_busnrs(pdev, &fixed_sec, &fixed_sub);
- if (!(next_bus = pci_alloc_bus(bus)))
- {
- goto _end;
- }
- /* Clear bus info */
- rt_pci_write_config_u32(pdev, PCIR_PRIBUS_1, value & ~0xffffff);
- if (!(next_bus = pci_alloc_bus(bus)))
- {
- LOG_E("Alloc bus(%02x) fail", bus_no);
- goto _end;
- }
- if (pci_child_bus_init(next_bus, bus_no, host_bridge, pdev))
- {
- goto _end;
- }
- /* Fill primary, secondary */
- value = (buses & 0xff000000) | (bus->number << 0) | (next_bus->number << 8);
- rt_pci_write_config_u32(pdev, PCIR_PRIBUS_1, value);
- bus_no = rt_pci_scan_child_buses(next_bus, buses);
- /* Fill subordinate */
- value |= next_bus->number + rt_list_len(&next_bus->children_nodes);
- rt_pci_write_config_u32(pdev, PCIR_PRIBUS_1, value);
- if (fixed_buses)
- {
- bus_no = fixed_sub;
- }
- rt_pci_write_config_u8(pdev, PCIR_SUBBUS_1, bus_no);
- _end:
- return bus_no;
- }
- rt_uint32_t rt_pci_scan_bridge(struct rt_pci_bus *bus, struct rt_pci_device *pdev,
- rt_uint32_t bus_no_start, rt_bool_t reconfigured)
- {
- if (!bus || !pdev)
- {
- return RT_UINT32_MAX;
- }
- return pci_scan_bridge_extend(bus, pdev, bus_no_start, 0, reconfigured);
- }
- rt_inline rt_bool_t only_one_child(struct rt_pci_bus *bus)
- {
- struct rt_pci_device *pdev;
- if (rt_pci_is_root_bus(bus))
- {
- return RT_FALSE;
- }
- pdev = bus->self;
- if (rt_pci_is_pcie(pdev))
- {
- rt_uint16_t exp_type = pdev->exp_flags & PCIEM_FLAGS_TYPE;
- if (exp_type == PCIEM_TYPE_ROOT_PORT ||
- exp_type == PCIEM_TYPE_DOWNSTREAM_PORT ||
- exp_type == PCIEM_TYPE_PCIE_BRIDGE)
- {
- return RT_TRUE;
- }
- }
- return RT_FALSE;
- }
- static int next_fn(struct rt_pci_bus *bus, struct rt_pci_device *pdev, int fn)
- {
- if (!rt_pci_is_root_bus(bus) && bus->self->ari_enabled)
- {
- int pos, next_fn;
- rt_uint16_t cap = 0;
- if (!pdev)
- {
- return -RT_EINVAL;
- }
- pos = rt_pci_find_ext_capability(pdev, PCIZ_ARI);
- if (!pos)
- {
- return -RT_EINVAL;
- }
- rt_pci_read_config_u16(pdev, pos + PCIR_ARI_CAP, &cap);
- next_fn = PCIM_ARI_CAP_NFN(cap);
- if (next_fn <= fn)
- {
- return -RT_EINVAL;
- }
- return next_fn;
- }
- if (fn >= RT_PCI_FUNCTION_MAX - 1)
- {
- return -RT_EINVAL;
- }
- if (pdev && !pdev->multi_function)
- {
- return -RT_EINVAL;
- }
- return fn + 1;
- }
- rt_size_t rt_pci_scan_slot(struct rt_pci_bus *bus, rt_uint32_t devfn)
- {
- rt_size_t nr = 0;
- struct rt_pci_device *pdev = RT_NULL;
- if (!bus)
- {
- return nr;
- }
- if (devfn > 0 && only_one_child(bus))
- {
- return nr;
- }
- for (int func = 0; func >= 0; func = next_fn(bus, pdev, func))
- {
- pdev = rt_pci_scan_single_device(bus, devfn + func);
- if (pdev)
- {
- ++nr;
- if (func > 0)
- {
- pdev->multi_function = RT_TRUE;
- }
- }
- else if (func == 0)
- {
- break;
- }
- }
- return nr;
- }
- rt_uint32_t rt_pci_scan_child_buses(struct rt_pci_bus *bus, rt_size_t buses)
- {
- rt_uint32_t bus_no;
- struct rt_pci_device *pdev = RT_NULL;
- if (!bus)
- {
- bus_no = RT_UINT32_MAX;
- goto _end;
- }
- bus_no = bus->number;
- for (rt_uint32_t devfn = 0;
- devfn < RT_PCI_DEVFN(RT_PCI_DEVICE_MAX - 1, RT_PCI_FUNCTION_MAX - 1);
- devfn += RT_PCI_FUNCTION_MAX)
- {
- rt_pci_scan_slot(bus, devfn);
- }
- rt_pci_foreach_bridge(pdev, bus)
- {
- int offset;
- bus_no = pci_scan_bridge_extend(bus, pdev, bus_no, buses, RT_TRUE);
- offset = bus_no - bus->number;
- if (buses > offset)
- {
- buses -= offset;
- }
- else
- {
- break;
- }
- }
- _end:
- return bus_no;
- }
- rt_uint32_t rt_pci_scan_child_bus(struct rt_pci_bus *bus)
- {
- return rt_pci_scan_child_buses(bus, 0);
- }
- static struct rt_pci_bus *pci_alloc_bus(struct rt_pci_bus *parent)
- {
- struct rt_pci_bus *bus = rt_calloc(1, sizeof(*bus));
- if (!bus)
- {
- return RT_NULL;
- }
- bus->parent = parent;
- rt_list_init(&bus->list);
- rt_list_init(&bus->children_nodes);
- rt_list_init(&bus->devices_nodes);
- rt_spin_lock_init(&bus->lock);
- return bus;
- }
- rt_err_t rt_pci_host_bridge_register(struct rt_pci_host_bridge *host_bridge)
- {
- struct rt_pci_bus *bus = pci_alloc_bus(RT_NULL);
- if (!bus)
- {
- return -RT_ENOMEM;
- }
- host_bridge->root_bus = bus;
- bus->sysdata = host_bridge->sysdata;
- bus->host_bridge = host_bridge;
- bus->ops = host_bridge->ops;
- bus->number = host_bridge->bus_range[0];
- rt_sprintf(bus->name, "%04x:%02x", host_bridge->domain, bus->number);
- if (bus->ops->add)
- {
- rt_err_t err = bus->ops->add(bus);
- if (err)
- {
- LOG_E("PCI-Bus<%s> add bus failed with err = %s", bus->name, rt_strerror(err));
- }
- }
- return RT_EOK;
- }
- rt_err_t rt_pci_scan_root_bus_bridge(struct rt_pci_host_bridge *host_bridge)
- {
- rt_err_t err;
- if ((err = rt_pci_host_bridge_register(host_bridge)))
- {
- return err;
- }
- rt_pci_scan_child_bus(host_bridge->root_bus);
- return err;
- }
- rt_err_t rt_pci_host_bridge_probe(struct rt_pci_host_bridge *host_bridge)
- {
- rt_err_t err;
- err = rt_pci_scan_root_bus_bridge(host_bridge);
- return err;
- }
- static rt_bool_t pci_remove_bus_device(struct rt_pci_device *pdev, void *data)
- {
- /* Bus will free if this is the last device */
- rt_bus_remove_device(&pdev->parent);
- /* To find all devices, always return false */
- return RT_FALSE;
- }
- rt_err_t rt_pci_host_bridge_remove(struct rt_pci_host_bridge *host_bridge)
- {
- rt_err_t err = RT_EOK;
- if (host_bridge && host_bridge->root_bus)
- {
- rt_pci_enum_device(host_bridge->root_bus, pci_remove_bus_device, RT_NULL);
- host_bridge->root_bus = RT_NULL;
- }
- else
- {
- err = -RT_EINVAL;
- }
- return err;
- }
- rt_err_t rt_pci_bus_remove(struct rt_pci_bus *bus)
- {
- rt_err_t err = RT_EOK;
- if (bus)
- {
- spin_lock(&bus->lock);
- if (rt_list_isempty(&bus->children_nodes) &&
- rt_list_isempty(&bus->devices_nodes))
- {
- rt_list_remove(&bus->list);
- spin_unlock(&bus->lock);
- if (bus->ops->remove)
- {
- bus->ops->remove(bus);
- }
- rt_pci_ofw_bus_free(bus);
- rt_free(bus);
- }
- else
- {
- spin_unlock(&bus->lock);
- err = -RT_EBUSY;
- }
- }
- else
- {
- err = -RT_EINVAL;
- }
- return err;
- }
- rt_err_t rt_pci_device_remove(struct rt_pci_device *pdev)
- {
- rt_err_t err = RT_EOK;
- if (pdev)
- {
- struct rt_pci_bus *bus = pdev->bus;
- pci_procfs_detach(pdev);
- spin_lock(&bus->lock);
- while (pdev->parent.ref_count > 1)
- {
- spin_unlock(&bus->lock);
- rt_thread_yield();
- spin_lock(&bus->lock);
- }
- rt_list_remove(&pdev->list);
- spin_unlock(&bus->lock);
- rt_free(pdev);
- }
- else
- {
- err = -RT_EINVAL;
- }
- return err;
- }
|