On 10/1/25 08:28, Xu Yilun wrote:
On Thu, Jan 09, 2025 at 01:35:58PM +1100, Alexey Kardashevskiy wrote:
On 8/1/25 07:00, Xu Yilun wrote:
+static void __pci_ide_stream_setup(struct pci_dev *pdev, struct
pci_ide *ide)
+{
+ int pos;
+ u32 val;
+
+ pos = sel_ide_offset(pdev->sel_ide_cap, ide->stream_id,
+ pdev->nr_ide_mem);
+
+ val = FIELD_PREP(PCI_IDE_SEL_RID_1_LIMIT_MASK, ide->devid_end);
+ pci_write_config_dword(pdev, pos + PCI_IDE_SEL_RID_1, val);
+
+ val = FIELD_PREP(PCI_IDE_SEL_RID_2_VALID, 1) |
+ FIELD_PREP(PCI_IDE_SEL_RID_2_BASE_MASK, ide->devid_start) |
+ FIELD_PREP(PCI_IDE_SEL_RID_2_SEG_MASK, ide->domain);
+ pci_write_config_dword(pdev, pos + PCI_IDE_SEL_RID_2, val);
+
+ for (int i = 0; i < ide->nr_mem; i++) {
This needs to test that (pdev->nr_ide_mem >= ide->nr_mem), easy to miss
especially when PCI_IDE_SETUP_ROOT_PORT. Thanks,
Yes, but nr_ide_mem is limited HW resource and may easily smaller than
device memory region number.
My rootport does not have any range (instead, it relies on C-bit in MMIO
It seems strange, then how the RP decide which stream id to use.
Oh I thought I replied :-/ The RP gets the stream id from an RMP entry
corresponding to the MMIO page.
access to set T-bit). The device got just one (which is no use here as I
understand).
I also have no idea from SPEC how to use the IDE register blocks on EP,
except stream ENABLE bit.
And no matter how I program the RID/ADDR association registers, it
always work...
Call for help.
+1.
In this case, maybe we have to merge the
memory regions into one big range.
+ 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);
Oh, when we do this, the root port gets the same devid_start/end as the
device which is not correct, what should be there, the rootport bdfn? Need
"Indicates the lowest/highest value RID in the range
associated with this Stream ID at the IDE *Partner* Port"
My understanding is that device should fill the RP bdfn, and the RP
should fill the device bdfn for RID association registers. Same for Addr
association registers.
Oh. Yeah, this sounds right. So most of the setup needs to be done on the
root port and not on the device (which only needs to enable the stream),
which is not what the patch does. Or I got it wrong? Thanks,
I don't get you. This patch does IDE setup for 2 partners:
__pci_ide_stream_setup(pdev, ide); This is the setup on RP
__pci_ide_stream_setup(rp, ide); This is the setup on device
Nah, it is the oppositve.
unless AMD setup IDE by firmware, and didn't set the PCI_IDE_SETUP_ROOT_PORT flag.
The AMD firmware does not access the config space at all, relies on the
host os instead. Thanks,
Thanks,
Yilun
Thanks,
Yilun
to dig that but PCI_IDE_SETUP_ROOT_PORT should detect that it is a root
port. Thanks,
--
Alexey
--
Alexey