+ val = FIELD_PREP(PCI_IDE_SEL_ADDR_1_VALID, 1) |
+ FIELD_PREP(PCI_IDE_SEL_ADDR_1_BASE_LOW_MASK,
+ lower_32_bits(ide->mem[i].start) >>
+ PCI_IDE_SEL_ADDR_1_BASE_LOW_SHIFT) |
+ FIELD_PREP(PCI_IDE_SEL_ADDR_1_LIMIT_LOW_MASK,
+ lower_32_bits(ide->mem[i].end) >>
+ PCI_IDE_SEL_ADDR_1_LIMIT_LOW_SHIFT);
+ pci_write_config_dword(pdev, pos + PCI_IDE_SEL_ADDR_1(i), val);
+
+ val = upper_32_bits(ide->mem[i].end);
+ pci_write_config_dword(pdev, pos + PCI_IDE_SEL_ADDR_2(i), val);
+
+ val = upper_32_bits(ide->mem[i].start);
+ pci_write_config_dword(pdev, pos + PCI_IDE_SEL_ADDR_3(i), val);
+ }
+}
+
+/*
+ * Establish IDE stream parameters in @pdev and, optionally, its
root port
+ */
+int pci_ide_stream_setup(struct pci_dev *pdev, struct pci_ide *ide,
+ enum pci_ide_flags flags)
+{
+ struct pci_host_bridge *hb = pci_find_host_bridge(pdev->bus);
+ struct pci_dev *rp = pcie_find_root_port(pdev);
+ int mem = 0, rc;
+
+ if (ide->stream_id < 0 || ide->stream_id > U8_MAX) {
+ pci_err(pdev, "Setup fail: Invalid stream id: %d\n",
ide->stream_id);
+ return -ENXIO;
+ }
+
+ if (test_and_set_bit_lock(ide->stream_id, hb->ide_stream_ids)) {
+ pci_err(pdev, "Setup fail: Busy stream id: %d\n",
+ ide->stream_id);
+ return -EBUSY;
+ }
+
+ ide->name = kasprintf(GFP_KERNEL, "stream%d:%s", ide->stream_id,
+ dev_name(&pdev->dev));
+ if (!ide->name) {
+ rc = -ENOMEM;
+ goto err_name;
+ }
+
+ rc = sysfs_create_link(&hb->dev.kobj, &pdev->dev.kobj, ide->name);
+ if (rc)
+ goto err_link;
+
+ for (mem = 0; mem < ide->nr_mem; mem++)
+ if (!__request_region(&hb->ide_stream_res, ide->mem[mem].start,
+ range_len(&ide->mem[mem]), ide->name,
+ 0)) {
+ pci_err(pdev,
+ "Setup fail: stream%d: address association conflict
[%#llx-%#llx]\n",
+ ide->stream_id, ide->mem[mem].start,
+ ide->mem[mem].end);
+
+ rc = -EBUSY;
+ goto err;
+ }
+
+ __pci_ide_stream_setup(pdev, ide);
+ if (flags & PCI_IDE_SETUP_ROOT_PORT)
+ __pci_ide_stream_setup(rp, ide);