lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <CAErSpo6_gV1XKJ1jsDSvHo+BEORL_5wLC2YRyVG+OjVNDYbHgw@mail.gmail.com>
Date:	Mon, 9 Apr 2012 18:01:59 -0600
From:	Bjorn Helgaas <bhelgaas@...gle.com>
To:	Chris Metcalf <cmetcalf@...era.com>
Cc:	linux-kernel@...r.kernel.org, linux-pci@...r.kernel.org,
	Jesse Barnes <jbarnes@...tuousgeek.org>,
	"Michael S. Tsirkin" <mst@...hat.com>,
	Myron Stowe <myron.stowe@...hat.com>,
	Arnd Bergmann <arnd@...db.de>, Jiri Kosina <jkosina@...e.cz>,
	Joe Perches <joe@...ches.com>,
	David Howells <dhowells@...hat.com>
Subject: Re: [PATCH 3/3] arch/tile: tilegx PCI root complex support

On Sat, Apr 7, 2012 at 3:10 PM, Chris Metcalf <cmetcalf@...era.com> wrote:
> This change implements PCIe root complex support for tilegx using
> the kernel support layer for accessing the TRIO hardware shim.

> +static void __devinit fixup_read_and_payload_sizes(struct pci_controller *
> +                                               controller)
> +{
> +       gxio_trio_context_t *trio_context = controller->trio;
> +       TRIO_PCIE_RC_DEVICE_CONTROL_t dev_control;
> +       TRIO_PCIE_RC_DEVICE_CAP_t rc_dev_cap;
> +       unsigned int smallest_max_payload;
> +       struct pci_dev *dev = NULL;
> +       unsigned int reg_offset;
> +       u16 new_values;
> +       int mac;
> +       int err;
> +
> +       mac = controller->mac;
> +
> +       /*
> +        * Set our max read request size to be 4KB.
> +        */
> +       reg_offset =
> +               (TRIO_PCIE_RC_DEVICE_CONTROL <<
> +                       TRIO_CFG_REGION_ADDR__REG_SHIFT) |
> +               (TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_STANDARD <<
> +                       TRIO_CFG_REGION_ADDR__INTFC_SHIFT ) |
> +               (mac << TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT);
> +
> +       dev_control.word = __gxio_mmio_read32(trio_context->mmio_base_mac +
> +                                               reg_offset);
> +       dev_control.max_read_req_sz = 5;
> +       __gxio_mmio_write32(trio_context->mmio_base_mac + reg_offset,
> +                                               dev_control.word);
> +
> +       /*
> +        * Set the max payload size supported by this Gx PCIe MAC.
> +        * Though Gx PCIe supports Max Payload Size of up to 1024 bytes,
> +        * experiments have shown that setting MPS to 256 yields the
> +        * best performance.
> +        */
> +       reg_offset =
> +               (TRIO_PCIE_RC_DEVICE_CAP <<
> +                       TRIO_CFG_REGION_ADDR__REG_SHIFT) |
> +               (TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_STANDARD <<
> +                       TRIO_CFG_REGION_ADDR__INTFC_SHIFT ) |
> +               (mac << TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT);
> +
> +       rc_dev_cap.word = __gxio_mmio_read32(trio_context->mmio_base_mac +
> +                                               reg_offset);
> +       rc_dev_cap.mps_sup = 1;
> +       __gxio_mmio_write32(trio_context->mmio_base_mac + reg_offset,
> +                                               rc_dev_cap.word);
> +
> +       smallest_max_payload = rc_dev_cap.mps_sup;
> +
> +       /* Scan for the smallest maximum payload size. */
> +       while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {

Can this be done with the generic pcie_bus_configure_settings() or is
there something tilegx-specific about this?

> +               int pcie_caps_offset;
> +               u32 devcap;
> +               int max_payload;
> +
> +               /* Skip device that is not in this PCIe domain. */
> +               if ((struct pci_controller *)dev->sysdata != controller)
> +                       continue;
> +
> +               pcie_caps_offset = pci_find_capability(dev, PCI_CAP_ID_EXP);
> +               if (pcie_caps_offset == 0)
> +                       continue;
> +
> +               pci_read_config_dword(dev, pcie_caps_offset + PCI_EXP_DEVCAP,
> +                                     &devcap);
> +               max_payload = devcap & PCI_EXP_DEVCAP_PAYLOAD;
> +               if (max_payload < smallest_max_payload)
> +                       smallest_max_payload = max_payload;
> +       }
> +
> +       /* Now, set the max_payload_size for all devices to that value. */
> +       new_values = smallest_max_payload << 5;
> +       while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
> +               int pcie_caps_offset;
> +               u16 devctl;
> +
> +               /* Skip device that is not in this PCIe domain. */
> +               if ((struct pci_controller *)dev->sysdata != controller)
> +                       continue;
> +
> +               pcie_caps_offset = pci_find_capability(dev, PCI_CAP_ID_EXP);
> +               if (pcie_caps_offset == 0)
> +                       continue;
> +
> +               pci_read_config_word(dev, pcie_caps_offset + PCI_EXP_DEVCTL,
> +                                    &devctl);
> +               devctl &= ~PCI_EXP_DEVCTL_PAYLOAD;
> +               devctl |= new_values;
> +               pci_write_config_word(dev, pcie_caps_offset + PCI_EXP_DEVCTL,
> +                                     devctl);
> +       }
> +
> +       /*
> +        * Set the mac_config register in trio based on the MPS/MRS of the link.
> +        */
> +        err = gxio_trio_set_mps_mrs(trio_context,
> +                        smallest_max_payload,
> +                        dev_control.max_read_req_sz,
> +                        mac);
> +        if (err < 0) {
> +               pr_err("PCI: PCIE_CONFIGURE_MAC_MPS_MRS failure, "
> +                       "MAC %d on TRIO %d\n",
> +                       mac, controller->trio_index);
> +       }
> +}
> +
> +
> +/*
> + * Second PCI initialization entry point, called by subsys_initcall.
> + *
> + * The controllers have been set up by the time we get here, by a call to
> + * tile_pci_init.
> + */
> +int __devinit pcibios_init(void)
> +{
> +       resource_size_t offset;
> +       int i;
> +
> +        if (num_rc_controllers == 0 && num_ep_controllers == 0)
> +               return 0;
> +
> +       pr_info("PCI: Probing PCI hardware\n");
> +
> +       /*
> +        * We loop over all the TRIO shims and set up the MMIO mappings.
> +        * This step can't be done in tile_pci_init because the MM subsystem
> +        * hasn't been initialized then.
> +        */
> +       for (i = 0; i < TILEGX_NUM_TRIO; i++) {
> +               gxio_trio_context_t *context = &trio_contexts[i];
> +
> +               if (context->fd < 0)
> +                       continue;
> +
> +               /*
> +                * Map in the MMIO space for the MAC.
> +                 */
> +               offset = 0;
> +               context->mmio_base_mac =
> +                       iorpc_ioremap(context->fd, offset,
> +                                     HV_TRIO_CONFIG_IOREMAP_SIZE);
> +               if (context->mmio_base_mac == NULL) {
> +                       pr_err("PCI: MAC map failure on TRIO %d\n", i);
> +
> +                       hv_dev_close(context->fd);
> +                       context->fd = -1;
> +                       continue;
> +               }
> +       }
> +
> +       /*
> +        * Delay a bit in case devices aren't ready.  Some devices are
> +        * known to require at least 20ms here, but we use a more
> +        * conservative value.
> +        */
> +       mdelay(250);
> +
> +       /* Scan all of the recorded PCI controllers.  */
> +       for (i = 0; i < num_rc_controllers; i++) {
> +               struct pci_controller *controller = &pci_controllers[i];
> +               gxio_trio_context_t *trio_context = controller->trio;
> +               TRIO_PCIE_INTFC_PORT_CONFIG_t port_config;
> +               TRIO_PCIE_INTFC_PORT_STATUS_t port_status;
> +               TRIO_PCIE_INTFC_TX_FIFO_CTL_t tx_fifo_ctl;
> +               struct pci_bus *bus;
> +               unsigned int reg_offset;
> +               unsigned int class_code_revision;
> +               int mac;
> +#ifndef USE_SHARED_PCIE_CONFIG_REGION
> +               int ret;
> +#endif
> +
> +               if (trio_context->fd < 0)
> +                       continue;
> +
> +               mac = controller->mac;
> +
> +               /*
> +                * Check the port strap state which will override the BIB
> +                * setting.
> +                */
> +
> +               reg_offset =
> +                       (TRIO_PCIE_INTFC_PORT_CONFIG <<
> +                               TRIO_CFG_REGION_ADDR__REG_SHIFT) |
> +                       (TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_INTERFACE <<
> +                               TRIO_CFG_REGION_ADDR__INTFC_SHIFT ) |
> +                       (mac << TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT);
> +
> +               port_config.word =
> +                       __gxio_mmio_read(trio_context->mmio_base_mac +
> +                                        reg_offset);
> +
> +               if ((port_config.strap_state !=
> +                       TRIO_PCIE_INTFC_PORT_CONFIG__STRAP_STATE_VAL_AUTO_CONFIG_RC) &&
> +                       (port_config.strap_state !=
> +                       TRIO_PCIE_INTFC_PORT_CONFIG__STRAP_STATE_VAL_AUTO_CONFIG_RC_G1)) {
> +                       /*
> +                        * If this is really intended to be an EP port,
> +                        * record it so that the endpoint driver will know about it.
> +                        */
> +                       if (port_config.strap_state ==
> +                       TRIO_PCIE_INTFC_PORT_CONFIG__STRAP_STATE_VAL_AUTO_CONFIG_ENDPOINT ||
> +                       port_config.strap_state ==
> +                       TRIO_PCIE_INTFC_PORT_CONFIG__STRAP_STATE_VAL_AUTO_CONFIG_ENDPOINT_G1)
> +                               pcie_ports[controller->trio_index][mac].allow_ep = 1;
> +
> +                       continue;
> +               }
> +
> +               ret = gxio_trio_force_link_up(trio_context, mac);
> +               if (ret < 0)
> +                       pr_err("PCI: PCIE_FORCE_LINK_UP failure, "
> +                               "MAC %d on TRIO %d\n",
> +                               mac, controller->trio_index);
> +
> +               pr_info("PCI: Found PCI controller #%d on TRIO %d MAC %d\n", i,
> +                       controller->trio_index, controller->mac);
> +
> +               /*
> +                * Wait a bit here because some EP devices take longer to come up.
> +                */
> +               mdelay(1000);
> +
> +               /*
> +                * Check for PCIe link-up status.
> +                */
> +
> +               reg_offset =
> +                       (TRIO_PCIE_INTFC_PORT_STATUS <<
> +                               TRIO_CFG_REGION_ADDR__REG_SHIFT) |
> +                       (TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_INTERFACE <<
> +                               TRIO_CFG_REGION_ADDR__INTFC_SHIFT ) |
> +                       (mac << TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT);
> +
> +               port_status.word =
> +                       __gxio_mmio_read(trio_context->mmio_base_mac +
> +                                        reg_offset);
> +               if (!port_status.dl_up) {
> +                       pr_err("PCI: link is down, MAC %d on TRIO %d\n",
> +                               mac, controller->trio_index);
> +                       continue;
> +               }
> +
> +               /*
> +                * Ensure that the link can come out of L1 power down state.
> +                * Strictly speaking, this is needed only in the case of
> +                * heavy RC-initiated DMAs.
> +                */
> +               reg_offset =
> +                       (TRIO_PCIE_INTFC_TX_FIFO_CTL <<
> +                               TRIO_CFG_REGION_ADDR__REG_SHIFT) |
> +                       (TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_INTERFACE <<
> +                               TRIO_CFG_REGION_ADDR__INTFC_SHIFT ) |
> +                       (mac << TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT);
> +               tx_fifo_ctl.word =
> +                       __gxio_mmio_read(trio_context->mmio_base_mac +
> +                                        reg_offset);
> +               tx_fifo_ctl.min_p_credits = 0;
> +               __gxio_mmio_write(trio_context->mmio_base_mac + reg_offset,
> +                                 tx_fifo_ctl.word);
> +
> +               /*
> +                * Change the device ID so that Linux bus crawl doesn't confuse
> +                * the internal bridge with any Tilera endpoints.
> +                */
> +
> +               reg_offset =
> +                       (TRIO_PCIE_RC_DEVICE_ID_VEN_ID <<
> +                               TRIO_CFG_REGION_ADDR__REG_SHIFT) |
> +                       (TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_STANDARD <<
> +                               TRIO_CFG_REGION_ADDR__INTFC_SHIFT ) |
> +                       (mac << TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT);
> +
> +               __gxio_mmio_write32(trio_context->mmio_base_mac + reg_offset,
> +                                   (TILERA_GX36_RC_DEV_ID <<
> +                                   TRIO_PCIE_RC_DEVICE_ID_VEN_ID__DEV_ID_SHIFT) |
> +                                   TILERA_VENDOR_ID);
> +
> +               /*
> +                * Set the internal P2P bridge class code.
> +                */
> +
> +               reg_offset =
> +                       (TRIO_PCIE_RC_REVISION_ID <<
> +                               TRIO_CFG_REGION_ADDR__REG_SHIFT) |
> +                       (TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_STANDARD <<
> +                               TRIO_CFG_REGION_ADDR__INTFC_SHIFT ) |
> +                       (mac << TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT);
> +
> +               class_code_revision =
> +                       __gxio_mmio_read32(trio_context->mmio_base_mac +
> +                                          reg_offset);
> +               class_code_revision = (class_code_revision & 0xff ) |
> +                                       (PCI_CLASS_BRIDGE_PCI << 16);
> +
> +               __gxio_mmio_write32(trio_context->mmio_base_mac +
> +                                   reg_offset, class_code_revision);
> +
> +#ifdef USE_SHARED_PCIE_CONFIG_REGION
> +
> +               /*
> +                * Map in the MMIO space for the PIO region.
> +                 */
> +               offset = HV_TRIO_PIO_OFFSET(trio_context->pio_cfg_index) |
> +                       (((unsigned long long)mac) <<
> +                       TRIO_TILE_PIO_REGION_SETUP_CFG_ADDR__MAC_SHIFT);
> +
> +#else
> +
> +               /*
> +                * Alloc a PIO region for PCI config access per MAC.
> +                */
> +               ret = gxio_trio_alloc_pio_regions(trio_context, 1, 0, 0);
> +               if (ret < 0) {
> +                       pr_err("PCI: PCI CFG PIO alloc failure for mac %d "
> +                               "on TRIO %d, give up\n",
> +                               mac, controller->trio_index);
> +
> +                       /* TBD: cleanup ... */
> +
> +                       continue;
> +               }
> +
> +               trio_context->pio_cfg_index[mac] = ret;
> +
> +               /*
> +                * For PIO CFG, the bus_address_hi parameter is 0.
> +                */
> +               ret = gxio_trio_init_pio_region_aux(trio_context,
> +                       trio_context->pio_cfg_index[mac],
> +                       mac, 0, HV_TRIO_PIO_FLAG_CONFIG_SPACE);
> +               if (ret < 0) {
> +                       pr_err("PCI: PCI CFG PIO init failure for mac %d "
> +                               "on TRIO %d, give up\n",
> +                               mac, controller->trio_index);
> +
> +                       /* TBD: cleanup ... */
> +
> +                       continue;
> +               }
> +
> +               offset = HV_TRIO_PIO_OFFSET(trio_context->pio_cfg_index[mac]) |
> +                       (((unsigned long long)mac) <<
> +                       TRIO_TILE_PIO_REGION_SETUP_CFG_ADDR__MAC_SHIFT);
> +
> +#endif
> +
> +               trio_context->mmio_base_pio_cfg[mac] =
> +                       iorpc_ioremap(trio_context->fd, offset,
> +                       (1 << TRIO_TILE_PIO_REGION_SETUP_CFG_ADDR__MAC_SHIFT));
> +               if (trio_context->mmio_base_pio_cfg[mac] == NULL) {
> +                       pr_err("PCI: PIO map failure for mac %d on TRIO %d\n",
> +                               mac, controller->trio_index);
> +
> +                       /* TBD: cleanup ... */
> +
> +                       continue;
> +               }
> +
> +               /*
> +                * Initialize the PCIe interrupts.
> +                 */
> +               if (tile_init_irqs(controller)) {
> +                       pr_err("PCI: IRQs init failure for mac %d on TRIO %d\n",
> +                               mac, controller->trio_index);
> +
> +                       continue;
> +               }
> +
> +               /*
> +                * This comes from the generic Linux PCI driver.
> +                *
> +                * It reads the PCI tree for this bus into the Linux
> +                * data structures.
> +                *
> +                * This is inlined in linux/pci.h and calls into
> +                * pci_scan_bus_parented() in probe.c.
> +                */
> +               bus = pci_scan_bus(0, controller->ops, controller);

If at all possible, you should use pci_scan_root_bus() here instead,
so you can tell PCI what the host bridge apertures are.

You do fill in pci_controllers[].mem_resources[] below, which looks
like they might be apertures, but I don't see anywhere that the PCI
core would learn about those.

> +               controller->root_bus = bus;
> +               controller->last_busno = bus->subordinate;
> +
> +       }
> +
> +       /* Do machine dependent PCI interrupt routing */
> +       pci_fixup_irqs(pci_common_swizzle, tile_map_irq);
> +
> +       /*
> +        * This comes from the generic Linux PCI driver.
> +        *
> +        * It allocates all of the resources (I/O memory, etc)
> +        * associated with the devices read in above.
> +        */
> +
> +       pci_assign_unassigned_resources();
> +
> +       /* Record the I/O resources in the PCI controller structure. */
> +       for (i = 0; i < num_rc_controllers; i++) {
> +               struct pci_controller *controller = &pci_controllers[i];
> +               gxio_trio_context_t *trio_context = controller->trio;
> +               struct pci_bus *root_bus = pci_controllers[i].root_bus;
> +               struct pci_bus *next_bus;
> +               uint32_t bus_address_hi;
> +               struct pci_dev *dev;
> +               int ret;
> +               int j;
> +
> +               /*
> +                * Skip controllers that are not properly initialized or
> +                * have down links.
> +                */
> +               if (root_bus == NULL)
> +                       continue;
> +
> +               /* Configure the max_payload_size values for this domain. */
> +               fixup_read_and_payload_sizes(controller);
> +
> +               list_for_each_entry(dev, &root_bus->devices, bus_list) {
> +                       /* Find the PCI host controller, ie. the 1st bridge. */
> +                       if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI &&
> +                               (PCI_SLOT(dev->devfn) == 0)) {
> +                               next_bus = dev->subordinate;
> +                               pci_controllers[i].mem_resources[0] =
> +                                       *next_bus->resource[0];
> +                               pci_controllers[i].mem_resources[1] =
> +                                        *next_bus->resource[1];
> +                               pci_controllers[i].mem_resources[2] =
> +                                        *next_bus->resource[2];
> +
> +                               break;
> +                       }
> +               }
> +
> +               if (pci_controllers[i].mem_resources[1].flags & IORESOURCE_MEM)
> +                       bus_address_hi =
> +                               pci_controllers[i].mem_resources[1].start >> 32;
> +               else if (pci_controllers[i].mem_resources[2].flags & IORESOURCE_PREFETCH)
> +                       bus_address_hi =
> +                               pci_controllers[i].mem_resources[2].start >> 32;
> +               else {
> +                       /* This is unlikely. */
> +                       pr_err("PCI: no memory resources on TRIO %d mac %d\n",
> +                               controller->trio_index, controller->mac);
> +                       continue;
> +               }
> +
> +               /*
> +                * We always assign 32-bit PCI bus BAR ranges.
> +                 */
> +               BUG_ON(bus_address_hi != 0);
> +
> +               /*
> +                * Alloc a PIO region for PCI memory access for each RC port.
> +                */
> +               ret = gxio_trio_alloc_pio_regions(trio_context, 1, 0, 0);
> +               if (ret < 0) {
> +                       pr_err("PCI: MEM PIO alloc failure on TRIO %d mac %d, "
> +                               "give up\n", controller->trio_index,
> +                               controller->mac);
> +
> +                       /* TBD: cleanup ... */
> +
> +                       continue;
> +               }
> +
> +               controller->pio_mem_index = ret;
> +
> +               /*
> +                * For PIO MEM, the bus_address_hi parameter is hard-coded 0
> +                * because we always assign 32-bit PCI bus BAR ranges.
> +                 */
> +               ret = gxio_trio_init_pio_region_aux(trio_context,
> +                                                   controller->pio_mem_index,
> +                                                   controller->mac,
> +                                                   bus_address_hi,
> +                                                   0);
> +               if (ret < 0) {
> +                       pr_err("PCI: MEM PIO init failure on TRIO %d mac %d, "
> +                               "give up\n", controller->trio_index,
> +                               controller->mac);
> +
> +                       /* TBD: cleanup ... */
> +
> +                       continue;
> +               }
> +
> +               /*
> +                * Configure a Mem-Map region for each memory controller so
> +                * that Linux can map all of its PA space to the PCI bus.
> +                * Use the IOMMU to handle hash-for-home memory.
> +                 */
> +               for_each_online_node(j) {
> +                       unsigned long start_pfn = node_start_pfn[j];
> +                       unsigned long end_pfn = node_end_pfn[j];
> +                       unsigned long nr_pages = end_pfn - start_pfn;
> +
> +                       ret = gxio_trio_alloc_memory_maps(trio_context, 1, 0,
> +                                                         0);
> +                       if (ret < 0) {
> +                               pr_err("PCI: Mem-Map alloc failure on TRIO %d "
> +                                       "mac %d for MC %d, give up\n",
> +                                       controller->trio_index,
> +                                       controller->mac, j);
> +
> +                               /* TBD: cleanup ... */
> +
> +                               goto alloc_mem_map_failed;
> +                       }
> +
> +                       controller->mem_maps[j] = ret;
> +
> +                       /*
> +                        * Initialize the Mem-Map and the I/O MMU so that all
> +                        * the physical memory can be accessed by the endpoint
> +                        * devices. The base bus address is set to the base CPA
> +                        * of this memory controller, so is the base VA. The
> +                        * I/O MMU table essentially translates the CPA to
> +                        * the real PA.
> +                         */
> +                       ret = gxio_trio_init_memory_map_mmu_aux(trio_context,
> +                               controller->mem_maps[j],
> +                               start_pfn << PAGE_SHIFT,
> +                               nr_pages << PAGE_SHIFT,
> +                               trio_context->asid,
> +                               controller->mac,
> +                               start_pfn << PAGE_SHIFT,
> +                               j,
> +                               GXIO_TRIO_ORDER_MODE_UNORDERED);
> +                       if (ret < 0) {
> +                               pr_err("PCI: Mem-Map init failure on TRIO %d "
> +                                       "mac %d for MC %d, give up\n",
> +                                       controller->trio_index,
> +                                       controller->mac, j);
> +
> +                               /* TBD: cleanup ... */
> +
> +                               goto alloc_mem_map_failed;
> +                       }
> +
> +                       continue;
> +
> +alloc_mem_map_failed:
> +                       break;
> +               }
> +
> +       }
> +
> +       return 0;
> +}
> +subsys_initcall(pcibios_init);

> +int pcibios_enable_device(struct pci_dev *dev, int mask)
> +{
> +       u16 cmd, old_cmd;
> +       u8 header_type;
> +       int i;
> +       struct resource *r;
> +
> +       pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type);
> +
> +       pci_read_config_word(dev, PCI_COMMAND, &cmd);
> +       old_cmd = cmd;
> +       if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
> +               /*
> +                * For bridges, we enable both memory and I/O decoding
> +                * in call cases.
> +                */
> +               cmd |= PCI_COMMAND_IO;
> +               cmd |= PCI_COMMAND_MEMORY;
> +       } else {
> +               /*
> +                * For endpoints, we enable memory and/or I/O decoding
> +                * only if they have a memory resource of that type.
> +                */
> +               for (i = 0; i < 6; i++) {
> +                       r = &dev->resource[i];
> +                       if (r->flags & IORESOURCE_UNSET) {
> +                               pr_err("PCI: Device %s not available "
> +                                      "because of resource collisions\n",
> +                                      pci_name(dev));
> +                               return -EINVAL;
> +                       }
> +                       if (r->flags & IORESOURCE_IO)
> +                               cmd |= PCI_COMMAND_IO;
> +                       if (r->flags & IORESOURCE_MEM)
> +                               cmd |= PCI_COMMAND_MEMORY;
> +               }

It would be nice if you could use pci_enable_resources() here, though
you use IORESOURCE_UNSET here, while pci_enable_resources() does not.
But you could at least use PCI_NUM_RESOURCES and "mask."  There's
nothing fundamentally architecture-dependent here, so I'd like to move
toward a generic implementation.

> +       }
> +
> +       /*
> +        * We only write the command if it changed.
> +        */
> +       if (cmd != old_cmd)
> +               pci_write_config_word(dev, PCI_COMMAND, cmd);
> +       return 0;
> +}

> +static int __devinit tile_cfg_read(struct pci_bus *bus,
> +                                  unsigned int devfn,
> +                                  int offset,
> +                                  int size,
> +                                  u32 *val)
> +{
> +       struct pci_controller *controller = bus->sysdata;
> +       gxio_trio_context_t *trio_context = controller->trio;
> +       int busnum = bus->number & 0xff;
> +       int device = (devfn >> 3) & 0x1f;
> +       int function = devfn & 0x7;

Could use PCI_SLOT() and PCI_FUNC() here and below.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ