1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2023 Oxide Computer Company
14 */
15
16 /*
17 * A collection of utility functions for interacting with fabric IDs.
18 */
19
20 #include <amdzen_client.h>
21
22 /*
23 * Validate whether a fabric ID actually represents a valid ID for a given data
24 * fabric.
25 */
26 boolean_t
zen_fabric_id_valid_fabid(const df_fabric_decomp_t * decomp,const uint32_t fabid)27 zen_fabric_id_valid_fabid(const df_fabric_decomp_t *decomp,
28 const uint32_t fabid)
29 {
30 uint32_t mask = decomp->dfd_node_mask | decomp->dfd_comp_mask;
31 return ((fabid & ~mask) == 0);
32 }
33
34 /*
35 * Validate whether the parts of a fabric ID (e.g. the socket, die, and
36 * component) are in fact valid for a given data fabric.
37 */
38 boolean_t
zen_fabric_id_valid_parts(const df_fabric_decomp_t * decomp,const uint32_t sock,const uint32_t die,const uint32_t comp)39 zen_fabric_id_valid_parts(const df_fabric_decomp_t *decomp, const uint32_t sock,
40 const uint32_t die, const uint32_t comp)
41 {
42 uint32_t node;
43
44 if (((sock << decomp->dfd_sock_shift) & ~decomp->dfd_sock_mask) != 0) {
45 return (B_FALSE);
46 }
47 if (((die << decomp->dfd_die_shift) & ~decomp->dfd_die_mask) != 0) {
48 return (B_FALSE);
49 }
50 if ((comp & ~decomp->dfd_comp_mask) != 0) {
51 return (B_FALSE);
52 }
53
54 node = die << decomp->dfd_die_shift;
55 node |= sock << decomp->dfd_sock_shift;
56
57 if (((node << decomp->dfd_node_shift) & ~decomp->dfd_node_mask) != 0) {
58 return (B_FALSE);
59 }
60
61 return (B_TRUE);
62 }
63
64 /*
65 * Take apart a fabric ID into its constituent parts. The decomposition
66 * information has the die and socket information relative to the node ID.
67 */
68 void
zen_fabric_id_decompose(const df_fabric_decomp_t * decomp,const uint32_t fabid,uint32_t * sockp,uint32_t * diep,uint32_t * compp)69 zen_fabric_id_decompose(const df_fabric_decomp_t *decomp, const uint32_t fabid,
70 uint32_t *sockp, uint32_t *diep, uint32_t *compp)
71 {
72 uint32_t node;
73
74 ASSERT(zen_fabric_id_valid_fabid(decomp, fabid));
75
76 *compp = (fabid & decomp->dfd_comp_mask) >> decomp->dfd_comp_shift;
77 node = (fabid & decomp->dfd_node_mask) >> decomp->dfd_node_shift;
78 *diep = (node & decomp->dfd_die_mask) >> decomp->dfd_die_shift;
79 *sockp = (node & decomp->dfd_sock_mask) >> decomp->dfd_sock_shift;
80 }
81
82 /*
83 * Compose a fabric ID from its constituent parts: the socket, die, and fabric.
84 */
85 void
zen_fabric_id_compose(const df_fabric_decomp_t * decomp,const uint32_t sock,const uint32_t die,const uint32_t comp,uint32_t * fabidp)86 zen_fabric_id_compose(const df_fabric_decomp_t *decomp, const uint32_t sock,
87 const uint32_t die, const uint32_t comp, uint32_t *fabidp)
88 {
89 uint32_t node;
90
91 ASSERT(zen_fabric_id_valid_parts(decomp, sock, die, comp));
92
93 node = die << decomp->dfd_die_shift;
94 node |= sock << decomp->dfd_sock_shift;
95 *fabidp = (node << decomp->dfd_node_shift) |
96 (comp << decomp->dfd_comp_shift);
97 }
98
99 #ifdef DEBUG
100 static boolean_t
zen_apic_id_valid_parts(const amdzen_apic_decomp_t * decomp,const uint32_t sock,const uint32_t die,const uint32_t ccd,const uint32_t ccx,const uint32_t core,const uint32_t thread)101 zen_apic_id_valid_parts(const amdzen_apic_decomp_t *decomp, const uint32_t sock,
102 const uint32_t die, const uint32_t ccd, const uint32_t ccx,
103 const uint32_t core, const uint32_t thread)
104 {
105 ASSERT3U(decomp->aad_sock_shift, <, 32);
106 ASSERT3U(decomp->aad_die_shift, <, 32);
107 ASSERT3U(decomp->aad_ccd_shift, <, 32);
108 ASSERT3U(decomp->aad_ccx_shift, <, 32);
109 ASSERT3U(decomp->aad_core_shift, <, 32);
110 ASSERT3U(decomp->aad_thread_shift, <, 32);
111
112 if (((sock << decomp->aad_sock_shift) & ~decomp->aad_sock_mask) != 0) {
113 return (B_FALSE);
114 }
115
116 if (((die << decomp->aad_die_shift) & ~decomp->aad_die_mask) != 0) {
117 return (B_FALSE);
118 }
119
120 if (((ccd << decomp->aad_ccd_shift) & ~decomp->aad_ccd_mask) != 0) {
121 return (B_FALSE);
122 }
123
124 if (((ccx << decomp->aad_ccx_shift) & ~decomp->aad_ccx_mask) != 0) {
125 return (B_FALSE);
126 }
127
128 if (((core << decomp->aad_core_shift) & ~decomp->aad_core_mask) != 0) {
129 return (B_FALSE);
130 }
131
132 if (((thread << decomp->aad_thread_shift) &
133 ~decomp->aad_thread_mask) != 0) {
134 return (B_FALSE);
135 }
136 return (B_TRUE);
137 }
138 #endif /* DEBUG */
139
140 /*
141 * Compose an APIC ID from its constituent parts.
142 */
143 void
zen_apic_id_compose(const amdzen_apic_decomp_t * decomp,const uint32_t sock,const uint32_t die,const uint32_t ccd,const uint32_t ccx,const uint32_t core,const uint32_t thread,uint32_t * apicid)144 zen_apic_id_compose(const amdzen_apic_decomp_t *decomp, const uint32_t sock,
145 const uint32_t die, const uint32_t ccd, const uint32_t ccx,
146 const uint32_t core, const uint32_t thread, uint32_t *apicid)
147 {
148 uint32_t id;
149
150 ASSERT(zen_apic_id_valid_parts(decomp, sock, die, ccd, ccx, core,
151 thread));
152 id = thread << decomp->aad_thread_shift;
153 id |= core << decomp->aad_core_shift;
154 id |= ccx << decomp->aad_ccx_shift;
155 id |= ccd << decomp->aad_ccd_shift;
156 id |= die << decomp->aad_die_shift;
157 id |= sock << decomp->aad_sock_shift;
158
159 *apicid = id;
160 }
161