Skip to content

Commit f86e513

Browse files
Xu Yilundjbw
authored andcommitted
PCI/IDE: Add Address Association Register setup for downstream MMIO
The address ranges for downstream Address Association Registers need to cover memory addresses for all functions (PFs/VFs/downstream devices) managed by a Device Security Manager (DSM). The proposed solution is get the memory (32-bit only) range and prefetchable-memory (64-bit capable) range from the immediate ancestor downstream port (either the direct-attach RP or deepest switch port when switch attached). Similar to RID association, address associations will be set by default if hardware sets 'Number of Address Association Register Blocks' in the 'Selective IDE Stream Capability Register' to a non-zero value. TSM drivers can opt-out of the settings by zero'ing out unwanted / unsupported address ranges. E.g. TDX Connect only supports prefetachable (64-bit capable) memory ranges for the Address Association setting. If the immediate downstream port provides both a memory range and prefetchable-memory range, but the IDE partner port only provides 1 Address Association Register block then the TSM driver can pick which range to associate, or let the PCI core prioritize memory. Note, the Address Association Register setup for upstream requests is still uncertain so is not included. Co-developed-by: Aneesh Kumar K.V <aneesh.kumar@kernel.org> Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@kernel.org> Co-developed-by: Arto Merilainen <amerilainen@nvidia.com> Signed-off-by: Arto Merilainen <amerilainen@nvidia.com> Signed-off-by: Xu Yilun <yilun.xu@linux.intel.com> Co-developed-by: Dan Williams <dan.j.williams@intel.com> Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com> Link: https://patch.msgid.link/20251114010227.567693-1-dan.j.williams@intel.com Signed-off-by: Dan Williams <dan.j.williams@intel.com>
1 parent c16af01 commit f86e513

3 files changed

Lines changed: 145 additions & 9 deletions

File tree

drivers/pci/ide.c

Lines changed: 108 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,11 @@ struct pci_ide *pci_ide_stream_alloc(struct pci_dev *pdev)
155155
{
156156
/* EP, RP, + HB Stream allocation */
157157
struct stream_index __stream[PCI_IDE_HB + 1];
158+
struct pci_bus_region pref_assoc = { 0, -1 };
159+
struct pci_bus_region mem_assoc = { 0, -1 };
160+
struct resource *mem, *pref;
158161
struct pci_host_bridge *hb;
159-
struct pci_dev *rp;
162+
struct pci_dev *rp, *br;
160163
int num_vf, rid_end;
161164

162165
if (!pci_is_pcie(pdev))
@@ -197,18 +200,38 @@ struct pci_ide *pci_ide_stream_alloc(struct pci_dev *pdev)
197200
else
198201
rid_end = pci_dev_id(pdev);
199202

203+
br = pci_upstream_bridge(pdev);
204+
if (!br)
205+
return NULL;
206+
207+
/*
208+
* Check if the device consumes memory and/or prefetch-memory. Setup
209+
* downstream address association ranges for each.
210+
*/
211+
mem = pci_resource_n(br, PCI_BRIDGE_MEM_WINDOW);
212+
pref = pci_resource_n(br, PCI_BRIDGE_PREF_MEM_WINDOW);
213+
if (resource_assigned(mem))
214+
pcibios_resource_to_bus(br->bus, &mem_assoc, mem);
215+
if (resource_assigned(pref))
216+
pcibios_resource_to_bus(br->bus, &pref_assoc, pref);
217+
200218
*ide = (struct pci_ide) {
201219
.pdev = pdev,
202220
.partner = {
203221
[PCI_IDE_EP] = {
204222
.rid_start = pci_dev_id(rp),
205223
.rid_end = pci_dev_id(rp),
206224
.stream_index = no_free_ptr(ep_stream)->stream_index,
225+
/* Disable upstream address association */
226+
.mem_assoc = { 0, -1 },
227+
.pref_assoc = { 0, -1 },
207228
},
208229
[PCI_IDE_RP] = {
209230
.rid_start = pci_dev_id(pdev),
210231
.rid_end = rid_end,
211232
.stream_index = no_free_ptr(rp_stream)->stream_index,
233+
.mem_assoc = mem_assoc,
234+
.pref_assoc = pref_assoc,
212235
},
213236
},
214237
.host_bridge_stream = no_free_ptr(hb_stream)->stream_index,
@@ -385,6 +408,63 @@ static void set_ide_sel_ctl(struct pci_dev *pdev, struct pci_ide *ide,
385408
pci_write_config_dword(pdev, pos + PCI_IDE_SEL_CTL, val);
386409
}
387410

411+
#define SEL_ADDR1_LOWER GENMASK(31, 20)
412+
#define SEL_ADDR_UPPER GENMASK_ULL(63, 32)
413+
#define PREP_PCI_IDE_SEL_ADDR1(base, limit) \
414+
(FIELD_PREP(PCI_IDE_SEL_ADDR_1_VALID, 1) | \
415+
FIELD_PREP(PCI_IDE_SEL_ADDR_1_BASE_LOW, \
416+
FIELD_GET(SEL_ADDR1_LOWER, (base))) | \
417+
FIELD_PREP(PCI_IDE_SEL_ADDR_1_LIMIT_LOW, \
418+
FIELD_GET(SEL_ADDR1_LOWER, (limit))))
419+
420+
static void mem_assoc_to_regs(struct pci_bus_region *region,
421+
struct pci_ide_regs *regs, int idx)
422+
{
423+
/* convert to u64 range for bitfield size checks */
424+
struct range r = { region->start, region->end };
425+
426+
regs->addr[idx].assoc1 = PREP_PCI_IDE_SEL_ADDR1(r.start, r.end);
427+
regs->addr[idx].assoc2 = FIELD_GET(SEL_ADDR_UPPER, r.end);
428+
regs->addr[idx].assoc3 = FIELD_GET(SEL_ADDR_UPPER, r.start);
429+
}
430+
431+
/**
432+
* pci_ide_stream_to_regs() - convert IDE settings to association register values
433+
* @pdev: PCIe device object for either a Root Port or Endpoint Partner Port
434+
* @ide: registered IDE settings descriptor
435+
* @regs: output register values
436+
*/
437+
static void pci_ide_stream_to_regs(struct pci_dev *pdev, struct pci_ide *ide,
438+
struct pci_ide_regs *regs)
439+
{
440+
struct pci_ide_partner *settings = pci_ide_to_settings(pdev, ide);
441+
int assoc_idx = 0;
442+
443+
memset(regs, 0, sizeof(*regs));
444+
445+
if (!settings)
446+
return;
447+
448+
regs->rid1 = FIELD_PREP(PCI_IDE_SEL_RID_1_LIMIT, settings->rid_end);
449+
450+
regs->rid2 = FIELD_PREP(PCI_IDE_SEL_RID_2_VALID, 1) |
451+
FIELD_PREP(PCI_IDE_SEL_RID_2_BASE, settings->rid_start) |
452+
FIELD_PREP(PCI_IDE_SEL_RID_2_SEG, pci_ide_domain(pdev));
453+
454+
if (pdev->nr_ide_mem && pci_bus_region_size(&settings->mem_assoc)) {
455+
mem_assoc_to_regs(&settings->mem_assoc, regs, assoc_idx);
456+
assoc_idx++;
457+
}
458+
459+
if (pdev->nr_ide_mem > assoc_idx &&
460+
pci_bus_region_size(&settings->pref_assoc)) {
461+
mem_assoc_to_regs(&settings->pref_assoc, regs, assoc_idx);
462+
assoc_idx++;
463+
}
464+
465+
regs->nr_addr = assoc_idx;
466+
}
467+
388468
/**
389469
* pci_ide_stream_setup() - program settings to Selective IDE Stream registers
390470
* @pdev: PCIe device object for either a Root Port or Endpoint Partner Port
@@ -398,22 +478,34 @@ static void set_ide_sel_ctl(struct pci_dev *pdev, struct pci_ide *ide,
398478
void pci_ide_stream_setup(struct pci_dev *pdev, struct pci_ide *ide)
399479
{
400480
struct pci_ide_partner *settings = pci_ide_to_settings(pdev, ide);
481+
struct pci_ide_regs regs;
401482
int pos;
402-
u32 val;
403483

404484
if (!settings)
405485
return;
406486

487+
pci_ide_stream_to_regs(pdev, ide, &regs);
488+
407489
pos = sel_ide_offset(pdev, settings);
408490

409-
val = FIELD_PREP(PCI_IDE_SEL_RID_1_LIMIT, settings->rid_end);
410-
pci_write_config_dword(pdev, pos + PCI_IDE_SEL_RID_1, val);
491+
pci_write_config_dword(pdev, pos + PCI_IDE_SEL_RID_1, regs.rid1);
492+
pci_write_config_dword(pdev, pos + PCI_IDE_SEL_RID_2, regs.rid2);
411493

412-
val = FIELD_PREP(PCI_IDE_SEL_RID_2_VALID, 1) |
413-
FIELD_PREP(PCI_IDE_SEL_RID_2_BASE, settings->rid_start) |
414-
FIELD_PREP(PCI_IDE_SEL_RID_2_SEG, pci_ide_domain(pdev));
494+
for (int i = 0; i < regs.nr_addr; i++) {
495+
pci_write_config_dword(pdev, pos + PCI_IDE_SEL_ADDR_1(i),
496+
regs.addr[i].assoc1);
497+
pci_write_config_dword(pdev, pos + PCI_IDE_SEL_ADDR_2(i),
498+
regs.addr[i].assoc2);
499+
pci_write_config_dword(pdev, pos + PCI_IDE_SEL_ADDR_3(i),
500+
regs.addr[i].assoc3);
501+
}
415502

416-
pci_write_config_dword(pdev, pos + PCI_IDE_SEL_RID_2, val);
503+
/* clear extra unused address association blocks */
504+
for (int i = regs.nr_addr; i < pdev->nr_ide_mem; i++) {
505+
pci_write_config_dword(pdev, pos + PCI_IDE_SEL_ADDR_1(i), 0);
506+
pci_write_config_dword(pdev, pos + PCI_IDE_SEL_ADDR_2(i), 0);
507+
pci_write_config_dword(pdev, pos + PCI_IDE_SEL_ADDR_3(i), 0);
508+
}
417509

418510
/*
419511
* Setup control register early for devices that expect
@@ -436,14 +528,21 @@ EXPORT_SYMBOL_GPL(pci_ide_stream_setup);
436528
void pci_ide_stream_teardown(struct pci_dev *pdev, struct pci_ide *ide)
437529
{
438530
struct pci_ide_partner *settings = pci_ide_to_settings(pdev, ide);
439-
int pos;
531+
int pos, i;
440532

441533
if (!settings)
442534
return;
443535

444536
pos = sel_ide_offset(pdev, settings);
445537

446538
pci_write_config_dword(pdev, pos + PCI_IDE_SEL_CTL, 0);
539+
540+
for (i = 0; i < pdev->nr_ide_mem; i++) {
541+
pci_write_config_dword(pdev, pos + PCI_IDE_SEL_ADDR_1(i), 0);
542+
pci_write_config_dword(pdev, pos + PCI_IDE_SEL_ADDR_2(i), 0);
543+
pci_write_config_dword(pdev, pos + PCI_IDE_SEL_ADDR_3(i), 0);
544+
}
545+
447546
pci_write_config_dword(pdev, pos + PCI_IDE_SEL_RID_2, 0);
448547
pci_write_config_dword(pdev, pos + PCI_IDE_SEL_RID_1, 0);
449548
settings->setup = 0;

include/linux/pci-ide.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,21 +28,53 @@ enum pci_ide_partner_select {
2828
* @rid_start: Partner Port Requester ID range start
2929
* @rid_end: Partner Port Requester ID range end
3030
* @stream_index: Selective IDE Stream Register Block selection
31+
* @mem_assoc: PCI bus memory address association for targeting peer partner
32+
* @pref_assoc: PCI bus prefetchable memory address association for
33+
* targeting peer partner
3134
* @default_stream: Endpoint uses this stream for all upstream TLPs regardless of
3235
* address and RID association registers
3336
* @setup: flag to track whether to run pci_ide_stream_teardown() for this
3437
* partner slot
3538
* @enable: flag whether to run pci_ide_stream_disable() for this partner slot
39+
*
40+
* By default, pci_ide_stream_alloc() initializes @mem_assoc and @pref_assoc
41+
* with the immediate ancestor downstream port memory ranges (i.e. Type 1
42+
* Configuration Space Header values). Caller may zero size ({0, -1}) the range
43+
* to drop it from consideration at pci_ide_stream_setup() time.
3644
*/
3745
struct pci_ide_partner {
3846
u16 rid_start;
3947
u16 rid_end;
4048
u8 stream_index;
49+
struct pci_bus_region mem_assoc;
50+
struct pci_bus_region pref_assoc;
4151
unsigned int default_stream:1;
4252
unsigned int setup:1;
4353
unsigned int enable:1;
4454
};
4555

56+
/**
57+
* struct pci_ide_regs - Hardware register association settings for Selective
58+
* IDE Streams
59+
* @rid1: IDE RID Association Register 1
60+
* @rid2: IDE RID Association Register 2
61+
* @addr: Up to two address association blocks (IDE Address Association Register
62+
* 1 through 3) for MMIO and prefetchable MMIO
63+
* @nr_addr: Number of address association blocks initialized
64+
*
65+
* See pci_ide_stream_to_regs()
66+
*/
67+
struct pci_ide_regs {
68+
u32 rid1;
69+
u32 rid2;
70+
struct {
71+
u32 assoc1;
72+
u32 assoc2;
73+
u32 assoc3;
74+
} addr[2];
75+
int nr_addr;
76+
};
77+
4678
/**
4779
* struct pci_ide - PCIe Selective IDE Stream descriptor
4880
* @pdev: PCIe Endpoint in the pci_ide_partner pair

include/linux/pci.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -870,6 +870,11 @@ struct pci_bus_region {
870870
pci_bus_addr_t end;
871871
};
872872

873+
static inline pci_bus_addr_t pci_bus_region_size(const struct pci_bus_region *region)
874+
{
875+
return region->end - region->start + 1;
876+
}
877+
873878
struct pci_dynids {
874879
spinlock_t lock; /* Protects list, index */
875880
struct list_head list; /* For IDs added at runtime */

0 commit comments

Comments
 (0)