1*c2e0c6b5SAndroid Build Coastguard Worker /*
2*c2e0c6b5SAndroid Build Coastguard Worker * The PCI Utilities -- Obtain the margin information of the Link
3*c2e0c6b5SAndroid Build Coastguard Worker *
4*c2e0c6b5SAndroid Build Coastguard Worker * Copyright (c) 2023-2024 KNS Group LLC (YADRO)
5*c2e0c6b5SAndroid Build Coastguard Worker *
6*c2e0c6b5SAndroid Build Coastguard Worker * Can be freely distributed and used under the terms of the GNU GPL v2+.
7*c2e0c6b5SAndroid Build Coastguard Worker *
8*c2e0c6b5SAndroid Build Coastguard Worker * SPDX-License-Identifier: GPL-2.0-or-later
9*c2e0c6b5SAndroid Build Coastguard Worker */
10*c2e0c6b5SAndroid Build Coastguard Worker
11*c2e0c6b5SAndroid Build Coastguard Worker #include <errno.h>
12*c2e0c6b5SAndroid Build Coastguard Worker #include <stdlib.h>
13*c2e0c6b5SAndroid Build Coastguard Worker #include <time.h>
14*c2e0c6b5SAndroid Build Coastguard Worker
15*c2e0c6b5SAndroid Build Coastguard Worker #include "lmr.h"
16*c2e0c6b5SAndroid Build Coastguard Worker
17*c2e0c6b5SAndroid Build Coastguard Worker #ifdef PCI_OS_DJGPP
18*c2e0c6b5SAndroid Build Coastguard Worker #include <unistd.h>
19*c2e0c6b5SAndroid Build Coastguard Worker #endif
20*c2e0c6b5SAndroid Build Coastguard Worker
21*c2e0c6b5SAndroid Build Coastguard Worker /* Macro helpers for Margining command parsing */
22*c2e0c6b5SAndroid Build Coastguard Worker
23*c2e0c6b5SAndroid Build Coastguard Worker typedef u16 margin_cmd;
24*c2e0c6b5SAndroid Build Coastguard Worker
25*c2e0c6b5SAndroid Build Coastguard Worker /* Margining command parsing */
26*c2e0c6b5SAndroid Build Coastguard Worker
27*c2e0c6b5SAndroid Build Coastguard Worker #define LMR_CMD_RECVN MASK(2, 0)
28*c2e0c6b5SAndroid Build Coastguard Worker #define LMR_CMD_TYPE MASK(5, 3)
29*c2e0c6b5SAndroid Build Coastguard Worker #define LMR_CMD_PAYLOAD MASK(15, 8)
30*c2e0c6b5SAndroid Build Coastguard Worker
31*c2e0c6b5SAndroid Build Coastguard Worker // Payload parsing
32*c2e0c6b5SAndroid Build Coastguard Worker
33*c2e0c6b5SAndroid Build Coastguard Worker // Report Capabilities
34*c2e0c6b5SAndroid Build Coastguard Worker #define LMR_PLD_VOLT_SUPPORT BIT(8)
35*c2e0c6b5SAndroid Build Coastguard Worker #define LMR_PLD_IND_U_D_VOLT BIT(9)
36*c2e0c6b5SAndroid Build Coastguard Worker #define LMR_PLD_IND_L_R_TIM BIT(10)
37*c2e0c6b5SAndroid Build Coastguard Worker #define LMR_PLD_SAMPLE_REPORT_METHOD BIT(11)
38*c2e0c6b5SAndroid Build Coastguard Worker #define LMR_PLD_IND_ERR_SAMPLER BIT(12)
39*c2e0c6b5SAndroid Build Coastguard Worker
40*c2e0c6b5SAndroid Build Coastguard Worker #define LMR_PLD_MAX_T_STEPS MASK(13, 8)
41*c2e0c6b5SAndroid Build Coastguard Worker #define LMR_PLD_MAX_V_STEPS MASK(14, 8)
42*c2e0c6b5SAndroid Build Coastguard Worker #define LMR_PLD_MAX_OFFSET MASK(14, 8)
43*c2e0c6b5SAndroid Build Coastguard Worker #define LMR_PLD_MAX_LANES MASK(12, 8)
44*c2e0c6b5SAndroid Build Coastguard Worker #define LMR_PLD_SAMPLE_RATE MASK(13, 8)
45*c2e0c6b5SAndroid Build Coastguard Worker
46*c2e0c6b5SAndroid Build Coastguard Worker // Timing Step
47*c2e0c6b5SAndroid Build Coastguard Worker #define LMR_PLD_MARGIN_T_STEPS MASK(13, 8)
48*c2e0c6b5SAndroid Build Coastguard Worker #define LMR_PLD_T_GO_LEFT BIT(14)
49*c2e0c6b5SAndroid Build Coastguard Worker
50*c2e0c6b5SAndroid Build Coastguard Worker // Voltage Timing
51*c2e0c6b5SAndroid Build Coastguard Worker #define LMR_PLD_MARGIN_V_STEPS MASK(14, 8)
52*c2e0c6b5SAndroid Build Coastguard Worker #define LMR_PLD_V_GO_DOWN BIT(15)
53*c2e0c6b5SAndroid Build Coastguard Worker
54*c2e0c6b5SAndroid Build Coastguard Worker // Step Response
55*c2e0c6b5SAndroid Build Coastguard Worker #define LMR_PLD_ERR_CNT MASK(13, 8)
56*c2e0c6b5SAndroid Build Coastguard Worker #define LMR_PLD_MARGIN_STS MASK(15, 14)
57*c2e0c6b5SAndroid Build Coastguard Worker
58*c2e0c6b5SAndroid Build Coastguard Worker /* Address calc macro for Lanes Margining registers */
59*c2e0c6b5SAndroid Build Coastguard Worker
60*c2e0c6b5SAndroid Build Coastguard Worker #define LMR_LANE_CTRL(lmr_cap_addr, lane) ((lmr_cap_addr) + 8 + 4 * (lane))
61*c2e0c6b5SAndroid Build Coastguard Worker #define LMR_LANE_STATUS(lmr_cap_addr, lane) ((lmr_cap_addr) + 10 + 4 * (lane))
62*c2e0c6b5SAndroid Build Coastguard Worker
63*c2e0c6b5SAndroid Build Coastguard Worker /* Margining Commands */
64*c2e0c6b5SAndroid Build Coastguard Worker
65*c2e0c6b5SAndroid Build Coastguard Worker #define MARG_TIM(go_left, step, recvn) margin_make_cmd(((go_left) << 6) | (step), 3, recvn)
66*c2e0c6b5SAndroid Build Coastguard Worker #define MARG_VOLT(go_down, step, recvn) margin_make_cmd(((go_down) << 7) | (step), 4, recvn)
67*c2e0c6b5SAndroid Build Coastguard Worker
68*c2e0c6b5SAndroid Build Coastguard Worker // Report commands
69*c2e0c6b5SAndroid Build Coastguard Worker #define REPORT_CAPS(recvn) margin_make_cmd(0x88, 1, recvn)
70*c2e0c6b5SAndroid Build Coastguard Worker #define REPORT_VOL_STEPS(recvn) margin_make_cmd(0x89, 1, recvn)
71*c2e0c6b5SAndroid Build Coastguard Worker #define REPORT_TIM_STEPS(recvn) margin_make_cmd(0x8A, 1, recvn)
72*c2e0c6b5SAndroid Build Coastguard Worker #define REPORT_TIM_OFFSET(recvn) margin_make_cmd(0x8B, 1, recvn)
73*c2e0c6b5SAndroid Build Coastguard Worker #define REPORT_VOL_OFFSET(recvn) margin_make_cmd(0x8C, 1, recvn)
74*c2e0c6b5SAndroid Build Coastguard Worker #define REPORT_SAMPL_RATE_V(recvn) margin_make_cmd(0x8D, 1, recvn)
75*c2e0c6b5SAndroid Build Coastguard Worker #define REPORT_SAMPL_RATE_T(recvn) margin_make_cmd(0x8E, 1, recvn)
76*c2e0c6b5SAndroid Build Coastguard Worker #define REPORT_SAMPLE_CNT(recvn) margin_make_cmd(0x8F, 1, recvn)
77*c2e0c6b5SAndroid Build Coastguard Worker #define REPORT_MAX_LANES(recvn) margin_make_cmd(0x90, 1, recvn)
78*c2e0c6b5SAndroid Build Coastguard Worker
79*c2e0c6b5SAndroid Build Coastguard Worker // Set commands
80*c2e0c6b5SAndroid Build Coastguard Worker #define NO_COMMAND margin_make_cmd(0x9C, 7, 0)
81*c2e0c6b5SAndroid Build Coastguard Worker #define CLEAR_ERROR_LOG(recvn) margin_make_cmd(0x55, 2, recvn)
82*c2e0c6b5SAndroid Build Coastguard Worker #define GO_TO_NORMAL_SETTINGS(recvn) margin_make_cmd(0xF, 2, recvn)
83*c2e0c6b5SAndroid Build Coastguard Worker #define SET_ERROR_LIMIT(error_limit, recvn) margin_make_cmd(0xC0 | (error_limit), 2, recvn)
84*c2e0c6b5SAndroid Build Coastguard Worker
85*c2e0c6b5SAndroid Build Coastguard Worker static int
msleep(long msec)86*c2e0c6b5SAndroid Build Coastguard Worker msleep(long msec)
87*c2e0c6b5SAndroid Build Coastguard Worker {
88*c2e0c6b5SAndroid Build Coastguard Worker #if defined(PCI_OS_WINDOWS)
89*c2e0c6b5SAndroid Build Coastguard Worker Sleep(msec);
90*c2e0c6b5SAndroid Build Coastguard Worker return 0;
91*c2e0c6b5SAndroid Build Coastguard Worker #elif defined(PCI_OS_DJGPP)
92*c2e0c6b5SAndroid Build Coastguard Worker if (msec * 1000 < 11264)
93*c2e0c6b5SAndroid Build Coastguard Worker usleep(11264);
94*c2e0c6b5SAndroid Build Coastguard Worker else
95*c2e0c6b5SAndroid Build Coastguard Worker usleep(msec * 1000);
96*c2e0c6b5SAndroid Build Coastguard Worker return 0;
97*c2e0c6b5SAndroid Build Coastguard Worker #else
98*c2e0c6b5SAndroid Build Coastguard Worker struct timespec ts;
99*c2e0c6b5SAndroid Build Coastguard Worker int res;
100*c2e0c6b5SAndroid Build Coastguard Worker
101*c2e0c6b5SAndroid Build Coastguard Worker if (msec < 0)
102*c2e0c6b5SAndroid Build Coastguard Worker {
103*c2e0c6b5SAndroid Build Coastguard Worker errno = EINVAL;
104*c2e0c6b5SAndroid Build Coastguard Worker return -1;
105*c2e0c6b5SAndroid Build Coastguard Worker }
106*c2e0c6b5SAndroid Build Coastguard Worker
107*c2e0c6b5SAndroid Build Coastguard Worker ts.tv_sec = msec / 1000;
108*c2e0c6b5SAndroid Build Coastguard Worker ts.tv_nsec = (msec % 1000) * 1000000;
109*c2e0c6b5SAndroid Build Coastguard Worker
110*c2e0c6b5SAndroid Build Coastguard Worker do
111*c2e0c6b5SAndroid Build Coastguard Worker {
112*c2e0c6b5SAndroid Build Coastguard Worker res = nanosleep(&ts, &ts);
113*c2e0c6b5SAndroid Build Coastguard Worker } while (res && errno == EINTR);
114*c2e0c6b5SAndroid Build Coastguard Worker
115*c2e0c6b5SAndroid Build Coastguard Worker return res;
116*c2e0c6b5SAndroid Build Coastguard Worker #endif
117*c2e0c6b5SAndroid Build Coastguard Worker }
118*c2e0c6b5SAndroid Build Coastguard Worker
119*c2e0c6b5SAndroid Build Coastguard Worker static margin_cmd
margin_make_cmd(u8 payload,u8 type,u8 recvn)120*c2e0c6b5SAndroid Build Coastguard Worker margin_make_cmd(u8 payload, u8 type, u8 recvn)
121*c2e0c6b5SAndroid Build Coastguard Worker {
122*c2e0c6b5SAndroid Build Coastguard Worker return SET_REG_MASK(0, LMR_CMD_PAYLOAD, payload) | SET_REG_MASK(0, LMR_CMD_TYPE, type)
123*c2e0c6b5SAndroid Build Coastguard Worker | SET_REG_MASK(0, LMR_CMD_RECVN, recvn);
124*c2e0c6b5SAndroid Build Coastguard Worker }
125*c2e0c6b5SAndroid Build Coastguard Worker
126*c2e0c6b5SAndroid Build Coastguard Worker static bool
margin_set_cmd(struct margin_dev * dev,u8 lane,margin_cmd cmd)127*c2e0c6b5SAndroid Build Coastguard Worker margin_set_cmd(struct margin_dev *dev, u8 lane, margin_cmd cmd)
128*c2e0c6b5SAndroid Build Coastguard Worker {
129*c2e0c6b5SAndroid Build Coastguard Worker pci_write_word(dev->dev, LMR_LANE_CTRL(dev->lmr_cap_addr, lane), cmd);
130*c2e0c6b5SAndroid Build Coastguard Worker msleep(10);
131*c2e0c6b5SAndroid Build Coastguard Worker return pci_read_word(dev->dev, LMR_LANE_STATUS(dev->lmr_cap_addr, lane)) == cmd;
132*c2e0c6b5SAndroid Build Coastguard Worker }
133*c2e0c6b5SAndroid Build Coastguard Worker
134*c2e0c6b5SAndroid Build Coastguard Worker static bool
margin_report_cmd(struct margin_dev * dev,u8 lane,margin_cmd cmd,margin_cmd * result)135*c2e0c6b5SAndroid Build Coastguard Worker margin_report_cmd(struct margin_dev *dev, u8 lane, margin_cmd cmd, margin_cmd *result)
136*c2e0c6b5SAndroid Build Coastguard Worker {
137*c2e0c6b5SAndroid Build Coastguard Worker pci_write_word(dev->dev, LMR_LANE_CTRL(dev->lmr_cap_addr, lane), cmd);
138*c2e0c6b5SAndroid Build Coastguard Worker msleep(10);
139*c2e0c6b5SAndroid Build Coastguard Worker *result = pci_read_word(dev->dev, LMR_LANE_STATUS(dev->lmr_cap_addr, lane));
140*c2e0c6b5SAndroid Build Coastguard Worker return GET_REG_MASK(*result, LMR_CMD_TYPE) == GET_REG_MASK(cmd, LMR_CMD_TYPE)
141*c2e0c6b5SAndroid Build Coastguard Worker && GET_REG_MASK(*result, LMR_CMD_RECVN) == GET_REG_MASK(cmd, LMR_CMD_RECVN)
142*c2e0c6b5SAndroid Build Coastguard Worker && margin_set_cmd(dev, lane, NO_COMMAND);
143*c2e0c6b5SAndroid Build Coastguard Worker }
144*c2e0c6b5SAndroid Build Coastguard Worker
145*c2e0c6b5SAndroid Build Coastguard Worker static void
margin_apply_hw_quirks(struct margin_recv * recv,struct margin_link_args * args)146*c2e0c6b5SAndroid Build Coastguard Worker margin_apply_hw_quirks(struct margin_recv *recv, struct margin_link_args *args)
147*c2e0c6b5SAndroid Build Coastguard Worker {
148*c2e0c6b5SAndroid Build Coastguard Worker switch (recv->dev->hw)
149*c2e0c6b5SAndroid Build Coastguard Worker {
150*c2e0c6b5SAndroid Build Coastguard Worker case MARGIN_ICE_LAKE_RC:
151*c2e0c6b5SAndroid Build Coastguard Worker if (recv->recvn == 1)
152*c2e0c6b5SAndroid Build Coastguard Worker {
153*c2e0c6b5SAndroid Build Coastguard Worker recv->params->volt_offset = 12;
154*c2e0c6b5SAndroid Build Coastguard Worker args->recv_args[recv->recvn - 1].t.one_side_is_whole = true;
155*c2e0c6b5SAndroid Build Coastguard Worker args->recv_args[recv->recvn - 1].t.valid = true;
156*c2e0c6b5SAndroid Build Coastguard Worker }
157*c2e0c6b5SAndroid Build Coastguard Worker break;
158*c2e0c6b5SAndroid Build Coastguard Worker default:
159*c2e0c6b5SAndroid Build Coastguard Worker break;
160*c2e0c6b5SAndroid Build Coastguard Worker }
161*c2e0c6b5SAndroid Build Coastguard Worker }
162*c2e0c6b5SAndroid Build Coastguard Worker
163*c2e0c6b5SAndroid Build Coastguard Worker static bool
read_params_internal(struct margin_dev * dev,u8 recvn,bool lane_reversal,struct margin_params * params)164*c2e0c6b5SAndroid Build Coastguard Worker read_params_internal(struct margin_dev *dev, u8 recvn, bool lane_reversal,
165*c2e0c6b5SAndroid Build Coastguard Worker struct margin_params *params)
166*c2e0c6b5SAndroid Build Coastguard Worker {
167*c2e0c6b5SAndroid Build Coastguard Worker margin_cmd resp;
168*c2e0c6b5SAndroid Build Coastguard Worker u8 lane = lane_reversal ? dev->max_width - 1 : 0;
169*c2e0c6b5SAndroid Build Coastguard Worker margin_set_cmd(dev, lane, NO_COMMAND);
170*c2e0c6b5SAndroid Build Coastguard Worker bool status = margin_report_cmd(dev, lane, REPORT_CAPS(recvn), &resp);
171*c2e0c6b5SAndroid Build Coastguard Worker if (status)
172*c2e0c6b5SAndroid Build Coastguard Worker {
173*c2e0c6b5SAndroid Build Coastguard Worker params->volt_support = GET_REG_MASK(resp, LMR_PLD_VOLT_SUPPORT);
174*c2e0c6b5SAndroid Build Coastguard Worker params->ind_up_down_volt = GET_REG_MASK(resp, LMR_PLD_IND_U_D_VOLT);
175*c2e0c6b5SAndroid Build Coastguard Worker params->ind_left_right_tim = GET_REG_MASK(resp, LMR_PLD_IND_L_R_TIM);
176*c2e0c6b5SAndroid Build Coastguard Worker params->sample_report_method = GET_REG_MASK(resp, LMR_PLD_SAMPLE_REPORT_METHOD);
177*c2e0c6b5SAndroid Build Coastguard Worker params->ind_error_sampler = GET_REG_MASK(resp, LMR_PLD_IND_ERR_SAMPLER);
178*c2e0c6b5SAndroid Build Coastguard Worker status = margin_report_cmd(dev, lane, REPORT_VOL_STEPS(recvn), &resp);
179*c2e0c6b5SAndroid Build Coastguard Worker }
180*c2e0c6b5SAndroid Build Coastguard Worker if (status)
181*c2e0c6b5SAndroid Build Coastguard Worker {
182*c2e0c6b5SAndroid Build Coastguard Worker params->volt_steps = GET_REG_MASK(resp, LMR_PLD_MAX_V_STEPS);
183*c2e0c6b5SAndroid Build Coastguard Worker status = margin_report_cmd(dev, lane, REPORT_TIM_STEPS(recvn), &resp);
184*c2e0c6b5SAndroid Build Coastguard Worker }
185*c2e0c6b5SAndroid Build Coastguard Worker if (status)
186*c2e0c6b5SAndroid Build Coastguard Worker {
187*c2e0c6b5SAndroid Build Coastguard Worker params->timing_steps = GET_REG_MASK(resp, LMR_PLD_MAX_T_STEPS);
188*c2e0c6b5SAndroid Build Coastguard Worker status = margin_report_cmd(dev, lane, REPORT_TIM_OFFSET(recvn), &resp);
189*c2e0c6b5SAndroid Build Coastguard Worker }
190*c2e0c6b5SAndroid Build Coastguard Worker if (status)
191*c2e0c6b5SAndroid Build Coastguard Worker {
192*c2e0c6b5SAndroid Build Coastguard Worker params->timing_offset = GET_REG_MASK(resp, LMR_PLD_MAX_OFFSET);
193*c2e0c6b5SAndroid Build Coastguard Worker status = margin_report_cmd(dev, lane, REPORT_VOL_OFFSET(recvn), &resp);
194*c2e0c6b5SAndroid Build Coastguard Worker }
195*c2e0c6b5SAndroid Build Coastguard Worker if (status)
196*c2e0c6b5SAndroid Build Coastguard Worker {
197*c2e0c6b5SAndroid Build Coastguard Worker params->volt_offset = GET_REG_MASK(resp, LMR_PLD_MAX_OFFSET);
198*c2e0c6b5SAndroid Build Coastguard Worker status = margin_report_cmd(dev, lane, REPORT_SAMPL_RATE_V(recvn), &resp);
199*c2e0c6b5SAndroid Build Coastguard Worker }
200*c2e0c6b5SAndroid Build Coastguard Worker if (status)
201*c2e0c6b5SAndroid Build Coastguard Worker {
202*c2e0c6b5SAndroid Build Coastguard Worker params->sample_rate_v = GET_REG_MASK(resp, LMR_PLD_SAMPLE_RATE);
203*c2e0c6b5SAndroid Build Coastguard Worker status = margin_report_cmd(dev, lane, REPORT_SAMPL_RATE_T(recvn), &resp);
204*c2e0c6b5SAndroid Build Coastguard Worker }
205*c2e0c6b5SAndroid Build Coastguard Worker if (status)
206*c2e0c6b5SAndroid Build Coastguard Worker {
207*c2e0c6b5SAndroid Build Coastguard Worker params->sample_rate_t = GET_REG_MASK(resp, LMR_PLD_SAMPLE_RATE);
208*c2e0c6b5SAndroid Build Coastguard Worker status = margin_report_cmd(dev, lane, REPORT_MAX_LANES(recvn), &resp);
209*c2e0c6b5SAndroid Build Coastguard Worker }
210*c2e0c6b5SAndroid Build Coastguard Worker if (status)
211*c2e0c6b5SAndroid Build Coastguard Worker params->max_lanes = GET_REG_MASK(resp, LMR_PLD_MAX_LANES);
212*c2e0c6b5SAndroid Build Coastguard Worker return status;
213*c2e0c6b5SAndroid Build Coastguard Worker }
214*c2e0c6b5SAndroid Build Coastguard Worker
215*c2e0c6b5SAndroid Build Coastguard Worker /* Margin all lanes_n lanes simultaneously */
216*c2e0c6b5SAndroid Build Coastguard Worker static void
margin_test_lanes(struct margin_lanes_data arg)217*c2e0c6b5SAndroid Build Coastguard Worker margin_test_lanes(struct margin_lanes_data arg)
218*c2e0c6b5SAndroid Build Coastguard Worker {
219*c2e0c6b5SAndroid Build Coastguard Worker u8 steps_done = 0;
220*c2e0c6b5SAndroid Build Coastguard Worker margin_cmd lane_status;
221*c2e0c6b5SAndroid Build Coastguard Worker u8 marg_type;
222*c2e0c6b5SAndroid Build Coastguard Worker margin_cmd step_cmd;
223*c2e0c6b5SAndroid Build Coastguard Worker bool timing = (arg.dir == TIM_LEFT || arg.dir == TIM_RIGHT);
224*c2e0c6b5SAndroid Build Coastguard Worker
225*c2e0c6b5SAndroid Build Coastguard Worker if (timing)
226*c2e0c6b5SAndroid Build Coastguard Worker {
227*c2e0c6b5SAndroid Build Coastguard Worker marg_type = 3;
228*c2e0c6b5SAndroid Build Coastguard Worker step_cmd = MARG_TIM(arg.dir == TIM_LEFT, steps_done, arg.recv->recvn);
229*c2e0c6b5SAndroid Build Coastguard Worker }
230*c2e0c6b5SAndroid Build Coastguard Worker else
231*c2e0c6b5SAndroid Build Coastguard Worker {
232*c2e0c6b5SAndroid Build Coastguard Worker marg_type = 4;
233*c2e0c6b5SAndroid Build Coastguard Worker step_cmd = MARG_VOLT(arg.dir == VOLT_DOWN, steps_done, arg.recv->recvn);
234*c2e0c6b5SAndroid Build Coastguard Worker }
235*c2e0c6b5SAndroid Build Coastguard Worker
236*c2e0c6b5SAndroid Build Coastguard Worker bool failed_lanes[32] = { 0 };
237*c2e0c6b5SAndroid Build Coastguard Worker u8 alive_lanes = arg.lanes_n;
238*c2e0c6b5SAndroid Build Coastguard Worker
239*c2e0c6b5SAndroid Build Coastguard Worker for (int i = 0; i < arg.lanes_n; i++)
240*c2e0c6b5SAndroid Build Coastguard Worker {
241*c2e0c6b5SAndroid Build Coastguard Worker margin_set_cmd(arg.recv->dev, arg.results[i].lane, NO_COMMAND);
242*c2e0c6b5SAndroid Build Coastguard Worker margin_set_cmd(arg.recv->dev, arg.results[i].lane,
243*c2e0c6b5SAndroid Build Coastguard Worker SET_ERROR_LIMIT(arg.recv->error_limit, arg.recv->recvn));
244*c2e0c6b5SAndroid Build Coastguard Worker margin_set_cmd(arg.recv->dev, arg.results[i].lane, NO_COMMAND);
245*c2e0c6b5SAndroid Build Coastguard Worker arg.results[i].steps[arg.dir] = arg.steps_lane_total;
246*c2e0c6b5SAndroid Build Coastguard Worker arg.results[i].statuses[arg.dir] = MARGIN_THR;
247*c2e0c6b5SAndroid Build Coastguard Worker }
248*c2e0c6b5SAndroid Build Coastguard Worker
249*c2e0c6b5SAndroid Build Coastguard Worker while (alive_lanes > 0 && steps_done < arg.steps_lane_total)
250*c2e0c6b5SAndroid Build Coastguard Worker {
251*c2e0c6b5SAndroid Build Coastguard Worker alive_lanes = 0;
252*c2e0c6b5SAndroid Build Coastguard Worker steps_done++;
253*c2e0c6b5SAndroid Build Coastguard Worker if (timing)
254*c2e0c6b5SAndroid Build Coastguard Worker step_cmd = SET_REG_MASK(step_cmd, LMR_PLD_MARGIN_T_STEPS, steps_done);
255*c2e0c6b5SAndroid Build Coastguard Worker else
256*c2e0c6b5SAndroid Build Coastguard Worker step_cmd = SET_REG_MASK(step_cmd, LMR_PLD_MARGIN_V_STEPS, steps_done);
257*c2e0c6b5SAndroid Build Coastguard Worker
258*c2e0c6b5SAndroid Build Coastguard Worker for (int i = 0; i < arg.lanes_n; i++)
259*c2e0c6b5SAndroid Build Coastguard Worker {
260*c2e0c6b5SAndroid Build Coastguard Worker if (!failed_lanes[i])
261*c2e0c6b5SAndroid Build Coastguard Worker {
262*c2e0c6b5SAndroid Build Coastguard Worker alive_lanes++;
263*c2e0c6b5SAndroid Build Coastguard Worker int ctrl_addr = LMR_LANE_CTRL(arg.recv->dev->lmr_cap_addr, arg.results[i].lane);
264*c2e0c6b5SAndroid Build Coastguard Worker pci_write_word(arg.recv->dev->dev, ctrl_addr, step_cmd);
265*c2e0c6b5SAndroid Build Coastguard Worker }
266*c2e0c6b5SAndroid Build Coastguard Worker }
267*c2e0c6b5SAndroid Build Coastguard Worker msleep(arg.recv->dwell_time * 1000);
268*c2e0c6b5SAndroid Build Coastguard Worker
269*c2e0c6b5SAndroid Build Coastguard Worker for (int i = 0; i < arg.lanes_n; i++)
270*c2e0c6b5SAndroid Build Coastguard Worker {
271*c2e0c6b5SAndroid Build Coastguard Worker if (!failed_lanes[i])
272*c2e0c6b5SAndroid Build Coastguard Worker {
273*c2e0c6b5SAndroid Build Coastguard Worker int status_addr = LMR_LANE_STATUS(arg.recv->dev->lmr_cap_addr, arg.results[i].lane);
274*c2e0c6b5SAndroid Build Coastguard Worker lane_status = pci_read_word(arg.recv->dev->dev, status_addr);
275*c2e0c6b5SAndroid Build Coastguard Worker u8 step_status = GET_REG_MASK(lane_status, LMR_PLD_MARGIN_STS);
276*c2e0c6b5SAndroid Build Coastguard Worker if (!(GET_REG_MASK(lane_status, LMR_CMD_TYPE) == marg_type
277*c2e0c6b5SAndroid Build Coastguard Worker && GET_REG_MASK(lane_status, LMR_CMD_RECVN) == arg.recv->recvn
278*c2e0c6b5SAndroid Build Coastguard Worker && step_status == 2
279*c2e0c6b5SAndroid Build Coastguard Worker && GET_REG_MASK(lane_status, LMR_PLD_ERR_CNT) <= arg.recv->error_limit
280*c2e0c6b5SAndroid Build Coastguard Worker && margin_set_cmd(arg.recv->dev, arg.results[i].lane, NO_COMMAND)))
281*c2e0c6b5SAndroid Build Coastguard Worker {
282*c2e0c6b5SAndroid Build Coastguard Worker alive_lanes--;
283*c2e0c6b5SAndroid Build Coastguard Worker failed_lanes[i] = true;
284*c2e0c6b5SAndroid Build Coastguard Worker arg.results[i].steps[arg.dir] = steps_done - 1;
285*c2e0c6b5SAndroid Build Coastguard Worker arg.results[i].statuses[arg.dir]
286*c2e0c6b5SAndroid Build Coastguard Worker = (step_status == 3 || step_status == 1 ? MARGIN_NAK : MARGIN_LIM);
287*c2e0c6b5SAndroid Build Coastguard Worker }
288*c2e0c6b5SAndroid Build Coastguard Worker }
289*c2e0c6b5SAndroid Build Coastguard Worker }
290*c2e0c6b5SAndroid Build Coastguard Worker
291*c2e0c6b5SAndroid Build Coastguard Worker arg.steps_lane_done = steps_done;
292*c2e0c6b5SAndroid Build Coastguard Worker margin_log_margining(arg);
293*c2e0c6b5SAndroid Build Coastguard Worker }
294*c2e0c6b5SAndroid Build Coastguard Worker
295*c2e0c6b5SAndroid Build Coastguard Worker for (int i = 0; i < arg.lanes_n; i++)
296*c2e0c6b5SAndroid Build Coastguard Worker {
297*c2e0c6b5SAndroid Build Coastguard Worker margin_set_cmd(arg.recv->dev, arg.results[i].lane, NO_COMMAND);
298*c2e0c6b5SAndroid Build Coastguard Worker margin_set_cmd(arg.recv->dev, arg.results[i].lane, CLEAR_ERROR_LOG(arg.recv->recvn));
299*c2e0c6b5SAndroid Build Coastguard Worker margin_set_cmd(arg.recv->dev, arg.results[i].lane, NO_COMMAND);
300*c2e0c6b5SAndroid Build Coastguard Worker margin_set_cmd(arg.recv->dev, arg.results[i].lane, GO_TO_NORMAL_SETTINGS(arg.recv->recvn));
301*c2e0c6b5SAndroid Build Coastguard Worker margin_set_cmd(arg.recv->dev, arg.results[i].lane, NO_COMMAND);
302*c2e0c6b5SAndroid Build Coastguard Worker }
303*c2e0c6b5SAndroid Build Coastguard Worker }
304*c2e0c6b5SAndroid Build Coastguard Worker
305*c2e0c6b5SAndroid Build Coastguard Worker /* Awaits that Receiver is prepared through prep_dev function */
306*c2e0c6b5SAndroid Build Coastguard Worker static bool
margin_test_receiver(struct margin_dev * dev,u8 recvn,struct margin_link_args * args,struct margin_results * results)307*c2e0c6b5SAndroid Build Coastguard Worker margin_test_receiver(struct margin_dev *dev, u8 recvn, struct margin_link_args *args,
308*c2e0c6b5SAndroid Build Coastguard Worker struct margin_results *results)
309*c2e0c6b5SAndroid Build Coastguard Worker {
310*c2e0c6b5SAndroid Build Coastguard Worker u8 *lanes_to_margin = args->lanes;
311*c2e0c6b5SAndroid Build Coastguard Worker u8 lanes_n = args->lanes_n;
312*c2e0c6b5SAndroid Build Coastguard Worker
313*c2e0c6b5SAndroid Build Coastguard Worker struct margin_params params;
314*c2e0c6b5SAndroid Build Coastguard Worker struct margin_recv recv = { .dev = dev,
315*c2e0c6b5SAndroid Build Coastguard Worker .recvn = recvn,
316*c2e0c6b5SAndroid Build Coastguard Worker .lane_reversal = false,
317*c2e0c6b5SAndroid Build Coastguard Worker .params = ¶ms,
318*c2e0c6b5SAndroid Build Coastguard Worker .parallel_lanes = args->parallel_lanes ? args->parallel_lanes : 1,
319*c2e0c6b5SAndroid Build Coastguard Worker .error_limit = args->common->error_limit,
320*c2e0c6b5SAndroid Build Coastguard Worker .dwell_time = args->common->dwell_time };
321*c2e0c6b5SAndroid Build Coastguard Worker
322*c2e0c6b5SAndroid Build Coastguard Worker results->recvn = recvn;
323*c2e0c6b5SAndroid Build Coastguard Worker results->lanes_n = lanes_n;
324*c2e0c6b5SAndroid Build Coastguard Worker margin_log_recvn(&recv);
325*c2e0c6b5SAndroid Build Coastguard Worker
326*c2e0c6b5SAndroid Build Coastguard Worker if (!margin_check_ready_bit(dev->dev))
327*c2e0c6b5SAndroid Build Coastguard Worker {
328*c2e0c6b5SAndroid Build Coastguard Worker margin_log("\nMargining Ready bit is Clear.\n");
329*c2e0c6b5SAndroid Build Coastguard Worker results->test_status = MARGIN_TEST_READY_BIT;
330*c2e0c6b5SAndroid Build Coastguard Worker return false;
331*c2e0c6b5SAndroid Build Coastguard Worker }
332*c2e0c6b5SAndroid Build Coastguard Worker
333*c2e0c6b5SAndroid Build Coastguard Worker if (!read_params_internal(dev, recvn, recv.lane_reversal, ¶ms))
334*c2e0c6b5SAndroid Build Coastguard Worker {
335*c2e0c6b5SAndroid Build Coastguard Worker recv.lane_reversal = true;
336*c2e0c6b5SAndroid Build Coastguard Worker if (!read_params_internal(dev, recvn, recv.lane_reversal, ¶ms))
337*c2e0c6b5SAndroid Build Coastguard Worker {
338*c2e0c6b5SAndroid Build Coastguard Worker margin_log("\nError during caps reading.\n");
339*c2e0c6b5SAndroid Build Coastguard Worker results->test_status = MARGIN_TEST_CAPS;
340*c2e0c6b5SAndroid Build Coastguard Worker return false;
341*c2e0c6b5SAndroid Build Coastguard Worker }
342*c2e0c6b5SAndroid Build Coastguard Worker }
343*c2e0c6b5SAndroid Build Coastguard Worker
344*c2e0c6b5SAndroid Build Coastguard Worker results->params = params;
345*c2e0c6b5SAndroid Build Coastguard Worker
346*c2e0c6b5SAndroid Build Coastguard Worker if (recv.parallel_lanes > params.max_lanes + 1)
347*c2e0c6b5SAndroid Build Coastguard Worker recv.parallel_lanes = params.max_lanes + 1;
348*c2e0c6b5SAndroid Build Coastguard Worker margin_apply_hw_quirks(&recv, args);
349*c2e0c6b5SAndroid Build Coastguard Worker margin_log_hw_quirks(&recv);
350*c2e0c6b5SAndroid Build Coastguard Worker
351*c2e0c6b5SAndroid Build Coastguard Worker results->tim_off_reported = params.timing_offset != 0;
352*c2e0c6b5SAndroid Build Coastguard Worker results->volt_off_reported = params.volt_offset != 0;
353*c2e0c6b5SAndroid Build Coastguard Worker double tim_offset = results->tim_off_reported ? (double)params.timing_offset : 50.0;
354*c2e0c6b5SAndroid Build Coastguard Worker double volt_offset = results->volt_off_reported ? (double)params.volt_offset : 50.0;
355*c2e0c6b5SAndroid Build Coastguard Worker
356*c2e0c6b5SAndroid Build Coastguard Worker results->tim_coef = tim_offset / (double)params.timing_steps;
357*c2e0c6b5SAndroid Build Coastguard Worker results->volt_coef = volt_offset / (double)params.volt_steps * 10.0;
358*c2e0c6b5SAndroid Build Coastguard Worker
359*c2e0c6b5SAndroid Build Coastguard Worker results->lane_reversal = recv.lane_reversal;
360*c2e0c6b5SAndroid Build Coastguard Worker results->link_speed = dev->link_speed;
361*c2e0c6b5SAndroid Build Coastguard Worker results->test_status = MARGIN_TEST_OK;
362*c2e0c6b5SAndroid Build Coastguard Worker
363*c2e0c6b5SAndroid Build Coastguard Worker margin_log_receiver(&recv);
364*c2e0c6b5SAndroid Build Coastguard Worker
365*c2e0c6b5SAndroid Build Coastguard Worker results->lanes = xmalloc(sizeof(struct margin_res_lane) * lanes_n);
366*c2e0c6b5SAndroid Build Coastguard Worker for (int i = 0; i < lanes_n; i++)
367*c2e0c6b5SAndroid Build Coastguard Worker {
368*c2e0c6b5SAndroid Build Coastguard Worker results->lanes[i].lane
369*c2e0c6b5SAndroid Build Coastguard Worker = recv.lane_reversal ? dev->max_width - lanes_to_margin[i] - 1 : lanes_to_margin[i];
370*c2e0c6b5SAndroid Build Coastguard Worker }
371*c2e0c6b5SAndroid Build Coastguard Worker
372*c2e0c6b5SAndroid Build Coastguard Worker if (args->common->run_margin)
373*c2e0c6b5SAndroid Build Coastguard Worker {
374*c2e0c6b5SAndroid Build Coastguard Worker if (args->common->verbosity > 0)
375*c2e0c6b5SAndroid Build Coastguard Worker margin_log("\n");
376*c2e0c6b5SAndroid Build Coastguard Worker struct margin_lanes_data lanes_data = { .recv = &recv,
377*c2e0c6b5SAndroid Build Coastguard Worker .verbosity = args->common->verbosity,
378*c2e0c6b5SAndroid Build Coastguard Worker .steps_utility = &args->common->steps_utility };
379*c2e0c6b5SAndroid Build Coastguard Worker
380*c2e0c6b5SAndroid Build Coastguard Worker enum margin_dir dir[] = { TIM_LEFT, TIM_RIGHT, VOLT_UP, VOLT_DOWN };
381*c2e0c6b5SAndroid Build Coastguard Worker
382*c2e0c6b5SAndroid Build Coastguard Worker u8 lanes_done = 0;
383*c2e0c6b5SAndroid Build Coastguard Worker u8 use_lanes = 0;
384*c2e0c6b5SAndroid Build Coastguard Worker u8 steps_t = args->steps_t ? args->steps_t : params.timing_steps;
385*c2e0c6b5SAndroid Build Coastguard Worker u8 steps_v = args->steps_v ? args->steps_v : params.volt_steps;
386*c2e0c6b5SAndroid Build Coastguard Worker
387*c2e0c6b5SAndroid Build Coastguard Worker while (lanes_done != lanes_n)
388*c2e0c6b5SAndroid Build Coastguard Worker {
389*c2e0c6b5SAndroid Build Coastguard Worker use_lanes = (lanes_done + recv.parallel_lanes > lanes_n) ? lanes_n - lanes_done :
390*c2e0c6b5SAndroid Build Coastguard Worker recv.parallel_lanes;
391*c2e0c6b5SAndroid Build Coastguard Worker lanes_data.lanes_numbers = lanes_to_margin + lanes_done;
392*c2e0c6b5SAndroid Build Coastguard Worker lanes_data.lanes_n = use_lanes;
393*c2e0c6b5SAndroid Build Coastguard Worker lanes_data.results = results->lanes + lanes_done;
394*c2e0c6b5SAndroid Build Coastguard Worker
395*c2e0c6b5SAndroid Build Coastguard Worker for (int i = 0; i < 4; i++)
396*c2e0c6b5SAndroid Build Coastguard Worker {
397*c2e0c6b5SAndroid Build Coastguard Worker bool timing = dir[i] == TIM_LEFT || dir[i] == TIM_RIGHT;
398*c2e0c6b5SAndroid Build Coastguard Worker if (!timing && !params.volt_support)
399*c2e0c6b5SAndroid Build Coastguard Worker continue;
400*c2e0c6b5SAndroid Build Coastguard Worker if (dir[i] == TIM_RIGHT && !params.ind_left_right_tim)
401*c2e0c6b5SAndroid Build Coastguard Worker continue;
402*c2e0c6b5SAndroid Build Coastguard Worker if (dir[i] == VOLT_DOWN && !params.ind_up_down_volt)
403*c2e0c6b5SAndroid Build Coastguard Worker continue;
404*c2e0c6b5SAndroid Build Coastguard Worker
405*c2e0c6b5SAndroid Build Coastguard Worker lanes_data.ind = timing ? params.ind_left_right_tim : params.ind_up_down_volt;
406*c2e0c6b5SAndroid Build Coastguard Worker lanes_data.dir = dir[i];
407*c2e0c6b5SAndroid Build Coastguard Worker lanes_data.steps_lane_total = timing ? steps_t : steps_v;
408*c2e0c6b5SAndroid Build Coastguard Worker if (args->common->steps_utility >= lanes_data.steps_lane_total)
409*c2e0c6b5SAndroid Build Coastguard Worker args->common->steps_utility -= lanes_data.steps_lane_total;
410*c2e0c6b5SAndroid Build Coastguard Worker else
411*c2e0c6b5SAndroid Build Coastguard Worker args->common->steps_utility = 0;
412*c2e0c6b5SAndroid Build Coastguard Worker margin_test_lanes(lanes_data);
413*c2e0c6b5SAndroid Build Coastguard Worker }
414*c2e0c6b5SAndroid Build Coastguard Worker lanes_done += use_lanes;
415*c2e0c6b5SAndroid Build Coastguard Worker }
416*c2e0c6b5SAndroid Build Coastguard Worker if (args->common->verbosity > 0)
417*c2e0c6b5SAndroid Build Coastguard Worker margin_log("\n");
418*c2e0c6b5SAndroid Build Coastguard Worker if (recv.lane_reversal)
419*c2e0c6b5SAndroid Build Coastguard Worker {
420*c2e0c6b5SAndroid Build Coastguard Worker for (int i = 0; i < lanes_n; i++)
421*c2e0c6b5SAndroid Build Coastguard Worker results->lanes[i].lane = lanes_to_margin[i];
422*c2e0c6b5SAndroid Build Coastguard Worker }
423*c2e0c6b5SAndroid Build Coastguard Worker }
424*c2e0c6b5SAndroid Build Coastguard Worker
425*c2e0c6b5SAndroid Build Coastguard Worker return true;
426*c2e0c6b5SAndroid Build Coastguard Worker }
427*c2e0c6b5SAndroid Build Coastguard Worker
428*c2e0c6b5SAndroid Build Coastguard Worker bool
margin_read_params(struct pci_access * pacc,struct pci_dev * dev,u8 recvn,struct margin_params * params)429*c2e0c6b5SAndroid Build Coastguard Worker margin_read_params(struct pci_access *pacc, struct pci_dev *dev, u8 recvn,
430*c2e0c6b5SAndroid Build Coastguard Worker struct margin_params *params)
431*c2e0c6b5SAndroid Build Coastguard Worker {
432*c2e0c6b5SAndroid Build Coastguard Worker struct pci_cap *cap = pci_find_cap(dev, PCI_CAP_ID_EXP, PCI_CAP_NORMAL);
433*c2e0c6b5SAndroid Build Coastguard Worker if (!cap)
434*c2e0c6b5SAndroid Build Coastguard Worker return false;
435*c2e0c6b5SAndroid Build Coastguard Worker
436*c2e0c6b5SAndroid Build Coastguard Worker bool dev_down = margin_port_is_down(dev);
437*c2e0c6b5SAndroid Build Coastguard Worker
438*c2e0c6b5SAndroid Build Coastguard Worker if (recvn == 0)
439*c2e0c6b5SAndroid Build Coastguard Worker {
440*c2e0c6b5SAndroid Build Coastguard Worker if (dev_down)
441*c2e0c6b5SAndroid Build Coastguard Worker recvn = 1;
442*c2e0c6b5SAndroid Build Coastguard Worker else
443*c2e0c6b5SAndroid Build Coastguard Worker recvn = 6;
444*c2e0c6b5SAndroid Build Coastguard Worker }
445*c2e0c6b5SAndroid Build Coastguard Worker
446*c2e0c6b5SAndroid Build Coastguard Worker if (recvn > 6)
447*c2e0c6b5SAndroid Build Coastguard Worker return false;
448*c2e0c6b5SAndroid Build Coastguard Worker if (dev_down && recvn == 6)
449*c2e0c6b5SAndroid Build Coastguard Worker return false;
450*c2e0c6b5SAndroid Build Coastguard Worker if (!dev_down && recvn != 6)
451*c2e0c6b5SAndroid Build Coastguard Worker return false;
452*c2e0c6b5SAndroid Build Coastguard Worker
453*c2e0c6b5SAndroid Build Coastguard Worker struct pci_dev *down = NULL;
454*c2e0c6b5SAndroid Build Coastguard Worker struct pci_dev *up = NULL;
455*c2e0c6b5SAndroid Build Coastguard Worker struct margin_link link;
456*c2e0c6b5SAndroid Build Coastguard Worker
457*c2e0c6b5SAndroid Build Coastguard Worker if (!margin_find_pair(pacc, dev, &down, &up))
458*c2e0c6b5SAndroid Build Coastguard Worker return false;
459*c2e0c6b5SAndroid Build Coastguard Worker
460*c2e0c6b5SAndroid Build Coastguard Worker if (!margin_fill_link(down, up, &link))
461*c2e0c6b5SAndroid Build Coastguard Worker return false;
462*c2e0c6b5SAndroid Build Coastguard Worker
463*c2e0c6b5SAndroid Build Coastguard Worker struct margin_dev *dut = (dev_down ? &link.down_port : &link.up_port);
464*c2e0c6b5SAndroid Build Coastguard Worker if (!margin_check_ready_bit(dut->dev))
465*c2e0c6b5SAndroid Build Coastguard Worker return false;
466*c2e0c6b5SAndroid Build Coastguard Worker
467*c2e0c6b5SAndroid Build Coastguard Worker if (!margin_prep_link(&link))
468*c2e0c6b5SAndroid Build Coastguard Worker return false;
469*c2e0c6b5SAndroid Build Coastguard Worker
470*c2e0c6b5SAndroid Build Coastguard Worker bool status;
471*c2e0c6b5SAndroid Build Coastguard Worker bool lane_reversal = false;
472*c2e0c6b5SAndroid Build Coastguard Worker status = read_params_internal(dut, recvn, lane_reversal, params);
473*c2e0c6b5SAndroid Build Coastguard Worker if (!status)
474*c2e0c6b5SAndroid Build Coastguard Worker {
475*c2e0c6b5SAndroid Build Coastguard Worker lane_reversal = true;
476*c2e0c6b5SAndroid Build Coastguard Worker status = read_params_internal(dut, recvn, lane_reversal, params);
477*c2e0c6b5SAndroid Build Coastguard Worker }
478*c2e0c6b5SAndroid Build Coastguard Worker
479*c2e0c6b5SAndroid Build Coastguard Worker margin_restore_link(&link);
480*c2e0c6b5SAndroid Build Coastguard Worker
481*c2e0c6b5SAndroid Build Coastguard Worker return status;
482*c2e0c6b5SAndroid Build Coastguard Worker }
483*c2e0c6b5SAndroid Build Coastguard Worker
484*c2e0c6b5SAndroid Build Coastguard Worker enum margin_test_status
margin_process_args(struct margin_link * link)485*c2e0c6b5SAndroid Build Coastguard Worker margin_process_args(struct margin_link *link)
486*c2e0c6b5SAndroid Build Coastguard Worker {
487*c2e0c6b5SAndroid Build Coastguard Worker struct margin_dev *dev = &link->down_port;
488*c2e0c6b5SAndroid Build Coastguard Worker struct margin_link_args *args = &link->args;
489*c2e0c6b5SAndroid Build Coastguard Worker
490*c2e0c6b5SAndroid Build Coastguard Worker u8 receivers_n = 2 + 2 * dev->retimers_n;
491*c2e0c6b5SAndroid Build Coastguard Worker
492*c2e0c6b5SAndroid Build Coastguard Worker if (!args->recvs_n)
493*c2e0c6b5SAndroid Build Coastguard Worker {
494*c2e0c6b5SAndroid Build Coastguard Worker for (int i = 1; i < receivers_n; i++)
495*c2e0c6b5SAndroid Build Coastguard Worker args->recvs[i - 1] = i;
496*c2e0c6b5SAndroid Build Coastguard Worker args->recvs[receivers_n - 1] = 6;
497*c2e0c6b5SAndroid Build Coastguard Worker args->recvs_n = receivers_n;
498*c2e0c6b5SAndroid Build Coastguard Worker }
499*c2e0c6b5SAndroid Build Coastguard Worker else
500*c2e0c6b5SAndroid Build Coastguard Worker {
501*c2e0c6b5SAndroid Build Coastguard Worker for (int i = 0; i < args->recvs_n; i++)
502*c2e0c6b5SAndroid Build Coastguard Worker {
503*c2e0c6b5SAndroid Build Coastguard Worker u8 recvn = args->recvs[i];
504*c2e0c6b5SAndroid Build Coastguard Worker if (recvn < 1 || recvn > 6 || (recvn != 6 && recvn > receivers_n - 1))
505*c2e0c6b5SAndroid Build Coastguard Worker {
506*c2e0c6b5SAndroid Build Coastguard Worker return MARGIN_TEST_ARGS_RECVS;
507*c2e0c6b5SAndroid Build Coastguard Worker }
508*c2e0c6b5SAndroid Build Coastguard Worker }
509*c2e0c6b5SAndroid Build Coastguard Worker }
510*c2e0c6b5SAndroid Build Coastguard Worker
511*c2e0c6b5SAndroid Build Coastguard Worker if (!args->lanes_n)
512*c2e0c6b5SAndroid Build Coastguard Worker {
513*c2e0c6b5SAndroid Build Coastguard Worker args->lanes_n = dev->neg_width;
514*c2e0c6b5SAndroid Build Coastguard Worker for (int i = 0; i < args->lanes_n; i++)
515*c2e0c6b5SAndroid Build Coastguard Worker args->lanes[i] = i;
516*c2e0c6b5SAndroid Build Coastguard Worker }
517*c2e0c6b5SAndroid Build Coastguard Worker else
518*c2e0c6b5SAndroid Build Coastguard Worker {
519*c2e0c6b5SAndroid Build Coastguard Worker for (int i = 0; i < args->lanes_n; i++)
520*c2e0c6b5SAndroid Build Coastguard Worker {
521*c2e0c6b5SAndroid Build Coastguard Worker if (args->lanes[i] >= dev->neg_width)
522*c2e0c6b5SAndroid Build Coastguard Worker {
523*c2e0c6b5SAndroid Build Coastguard Worker return MARGIN_TEST_ARGS_LANES;
524*c2e0c6b5SAndroid Build Coastguard Worker }
525*c2e0c6b5SAndroid Build Coastguard Worker }
526*c2e0c6b5SAndroid Build Coastguard Worker }
527*c2e0c6b5SAndroid Build Coastguard Worker
528*c2e0c6b5SAndroid Build Coastguard Worker return MARGIN_TEST_OK;
529*c2e0c6b5SAndroid Build Coastguard Worker }
530*c2e0c6b5SAndroid Build Coastguard Worker
531*c2e0c6b5SAndroid Build Coastguard Worker struct margin_results *
margin_test_link(struct margin_link * link,u8 * recvs_n)532*c2e0c6b5SAndroid Build Coastguard Worker margin_test_link(struct margin_link *link, u8 *recvs_n)
533*c2e0c6b5SAndroid Build Coastguard Worker {
534*c2e0c6b5SAndroid Build Coastguard Worker struct margin_link_args *args = &link->args;
535*c2e0c6b5SAndroid Build Coastguard Worker
536*c2e0c6b5SAndroid Build Coastguard Worker bool status = margin_prep_link(link);
537*c2e0c6b5SAndroid Build Coastguard Worker
538*c2e0c6b5SAndroid Build Coastguard Worker u8 receivers_n = status ? args->recvs_n : 1;
539*c2e0c6b5SAndroid Build Coastguard Worker u8 *receivers = args->recvs;
540*c2e0c6b5SAndroid Build Coastguard Worker
541*c2e0c6b5SAndroid Build Coastguard Worker margin_log_link(link);
542*c2e0c6b5SAndroid Build Coastguard Worker
543*c2e0c6b5SAndroid Build Coastguard Worker struct margin_results *results = xmalloc(sizeof(*results) * receivers_n);
544*c2e0c6b5SAndroid Build Coastguard Worker
545*c2e0c6b5SAndroid Build Coastguard Worker if (!status)
546*c2e0c6b5SAndroid Build Coastguard Worker {
547*c2e0c6b5SAndroid Build Coastguard Worker results[0].test_status = MARGIN_TEST_ASPM;
548*c2e0c6b5SAndroid Build Coastguard Worker margin_log("\nCouldn't disable ASPM on the given Link.\n");
549*c2e0c6b5SAndroid Build Coastguard Worker }
550*c2e0c6b5SAndroid Build Coastguard Worker
551*c2e0c6b5SAndroid Build Coastguard Worker if (status)
552*c2e0c6b5SAndroid Build Coastguard Worker {
553*c2e0c6b5SAndroid Build Coastguard Worker struct margin_dev *dut;
554*c2e0c6b5SAndroid Build Coastguard Worker for (int i = 0; i < receivers_n; i++)
555*c2e0c6b5SAndroid Build Coastguard Worker {
556*c2e0c6b5SAndroid Build Coastguard Worker dut = receivers[i] == 6 ? &link->up_port : &link->down_port;
557*c2e0c6b5SAndroid Build Coastguard Worker margin_test_receiver(dut, receivers[i], args, &results[i]);
558*c2e0c6b5SAndroid Build Coastguard Worker }
559*c2e0c6b5SAndroid Build Coastguard Worker
560*c2e0c6b5SAndroid Build Coastguard Worker margin_restore_link(link);
561*c2e0c6b5SAndroid Build Coastguard Worker }
562*c2e0c6b5SAndroid Build Coastguard Worker
563*c2e0c6b5SAndroid Build Coastguard Worker *recvs_n = receivers_n;
564*c2e0c6b5SAndroid Build Coastguard Worker return results;
565*c2e0c6b5SAndroid Build Coastguard Worker }
566*c2e0c6b5SAndroid Build Coastguard Worker
567*c2e0c6b5SAndroid Build Coastguard Worker void
margin_free_results(struct margin_results * results,u8 results_n)568*c2e0c6b5SAndroid Build Coastguard Worker margin_free_results(struct margin_results *results, u8 results_n)
569*c2e0c6b5SAndroid Build Coastguard Worker {
570*c2e0c6b5SAndroid Build Coastguard Worker for (int i = 0; i < results_n; i++)
571*c2e0c6b5SAndroid Build Coastguard Worker {
572*c2e0c6b5SAndroid Build Coastguard Worker if (results[i].test_status == MARGIN_TEST_OK)
573*c2e0c6b5SAndroid Build Coastguard Worker free(results[i].lanes);
574*c2e0c6b5SAndroid Build Coastguard Worker }
575*c2e0c6b5SAndroid Build Coastguard Worker free(results);
576*c2e0c6b5SAndroid Build Coastguard Worker }
577