2
* This file is provided under a dual BSD/GPLv2 license. When using or
3
* redistributing this file, you may do so under either license.
7
* Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
9
* This program is free software; you can redistribute it and/or modify
10
* it under the terms of version 2 of the GNU General Public License as
11
* published by the Free Software Foundation.
13
* This program is distributed in the hope that it will be useful, but
14
* WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
* General Public License for more details.
18
* You should have received a copy of the GNU General Public License
19
* along with this program; if not, write to the Free Software
20
* Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
21
* The full GNU General Public License is included in this distribution
22
* in the file called LICENSE.GPL.
26
* Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
27
* All rights reserved.
29
* Redistribution and use in source and binary forms, with or without
30
* modification, are permitted provided that the following conditions
33
* * Redistributions of source code must retain the above copyright
34
* notice, this list of conditions and the following disclaimer.
35
* * Redistributions in binary form must reproduce the above copyright
36
* notice, this list of conditions and the following disclaimer in
37
* the documentation and/or other materials provided with the
39
* * Neither the name of Intel Corporation nor the names of its
40
* contributors may be used to endorse or promote products derived
41
* from this software without specific prior written permission.
43
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
44
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
45
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
46
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
47
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
48
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
49
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
50
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
51
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
52
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
53
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
58
#define SCIC_SDS_MPC_RECONFIGURATION_TIMEOUT (10)
59
#define SCIC_SDS_APC_RECONFIGURATION_TIMEOUT (10)
60
#define SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION (100)
62
enum SCIC_SDS_APC_ACTIVITY {
63
SCIC_SDS_APC_SKIP_PHY,
65
SCIC_SDS_APC_START_TIMER,
67
SCIC_SDS_APC_ACTIVITY_MAX
71
* ******************************************************************************
72
* General port configuration agent routines
73
* ****************************************************************************** */
77
* @address_one: A SAS Address to be compared.
78
* @address_two: A SAS Address to be compared.
80
* Compare the two SAS Address and if SAS Address One is greater than SAS
81
* Address Two then return > 0 else if SAS Address One is less than SAS Address
82
* Two return < 0 Otherwise they are the same return 0 A signed value of x > 0
83
* > y where x is returned for Address One > Address Two y is returned for
84
* Address One < Address Two 0 is returned ofr Address One = Address Two
86
static s32 sci_sas_address_compare(
87
struct sci_sas_address address_one,
88
struct sci_sas_address address_two)
90
if (address_one.high > address_two.high) {
92
} else if (address_one.high < address_two.high) {
94
} else if (address_one.low > address_two.low) {
96
} else if (address_one.low < address_two.low) {
100
/* The two SAS Address must be identical */
106
* @controller: The controller object used for the port search.
107
* @phy: The phy object to match.
109
* This routine will find a matching port for the phy. This means that the
110
* port and phy both have the same broadcast sas address and same received sas
111
* address. The port address or the NULL if there is no matching
112
* port. port address if the port can be found to match the phy.
113
* NULL if there is no matching port for the phy.
115
static struct isci_port *sci_port_configuration_agent_find_port(
116
struct isci_host *ihost,
117
struct isci_phy *iphy)
120
struct sci_sas_address port_sas_address;
121
struct sci_sas_address port_attached_device_address;
122
struct sci_sas_address phy_sas_address;
123
struct sci_sas_address phy_attached_device_address;
126
* Since this phy can be a member of a wide port check to see if one or
127
* more phys match the sent and received SAS address as this phy in which
128
* case it should participate in the same port.
130
sci_phy_get_sas_address(iphy, &phy_sas_address);
131
sci_phy_get_attached_sas_address(iphy, &phy_attached_device_address);
133
for (i = 0; i < ihost->logical_port_entries; i++) {
134
struct isci_port *iport = &ihost->ports[i];
136
sci_port_get_sas_address(iport, &port_sas_address);
137
sci_port_get_attached_sas_address(iport, &port_attached_device_address);
139
if (sci_sas_address_compare(port_sas_address, phy_sas_address) == 0 &&
140
sci_sas_address_compare(port_attached_device_address, phy_attached_device_address) == 0)
149
* @controller: This is the controller object that contains the port agent
150
* @port_agent: This is the port configruation agent for the controller.
152
* This routine will validate the port configuration is correct for the SCU
153
* hardware. The SCU hardware allows for port configurations as follows. LP0
154
* -> (PE0), (PE0, PE1), (PE0, PE1, PE2, PE3) LP1 -> (PE1) LP2 -> (PE2), (PE2,
155
* PE3) LP3 -> (PE3) enum sci_status SCI_SUCCESS the port configuration is valid for
156
* this port configuration agent. SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION
157
* the port configuration is not valid for this port configuration agent.
159
static enum sci_status sci_port_configuration_agent_validate_ports(
160
struct isci_host *ihost,
161
struct sci_port_configuration_agent *port_agent)
163
struct sci_sas_address first_address;
164
struct sci_sas_address second_address;
167
* Sanity check the max ranges for all the phys the max index
168
* is always equal to the port range index */
169
if (port_agent->phy_valid_port_range[0].max_index != 0 ||
170
port_agent->phy_valid_port_range[1].max_index != 1 ||
171
port_agent->phy_valid_port_range[2].max_index != 2 ||
172
port_agent->phy_valid_port_range[3].max_index != 3)
173
return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION;
176
* This is a request to configure a single x4 port or at least attempt
177
* to make all the phys into a single port */
178
if (port_agent->phy_valid_port_range[0].min_index == 0 &&
179
port_agent->phy_valid_port_range[1].min_index == 0 &&
180
port_agent->phy_valid_port_range[2].min_index == 0 &&
181
port_agent->phy_valid_port_range[3].min_index == 0)
185
* This is a degenerate case where phy 1 and phy 2 are assigned
186
* to the same port this is explicitly disallowed by the hardware
187
* unless they are part of the same x4 port and this condition was
188
* already checked above. */
189
if (port_agent->phy_valid_port_range[2].min_index == 1) {
190
return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION;
194
* PE0 and PE3 can never have the same SAS Address unless they
195
* are part of the same x4 wide port and we have already checked
196
* for this condition. */
197
sci_phy_get_sas_address(&ihost->phys[0], &first_address);
198
sci_phy_get_sas_address(&ihost->phys[3], &second_address);
200
if (sci_sas_address_compare(first_address, second_address) == 0) {
201
return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION;
205
* PE0 and PE1 are configured into a 2x1 ports make sure that the
206
* SAS Address for PE0 and PE2 are different since they can not be
207
* part of the same port. */
208
if (port_agent->phy_valid_port_range[0].min_index == 0 &&
209
port_agent->phy_valid_port_range[1].min_index == 1) {
210
sci_phy_get_sas_address(&ihost->phys[0], &first_address);
211
sci_phy_get_sas_address(&ihost->phys[2], &second_address);
213
if (sci_sas_address_compare(first_address, second_address) == 0) {
214
return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION;
219
* PE2 and PE3 are configured into a 2x1 ports make sure that the
220
* SAS Address for PE1 and PE3 are different since they can not be
221
* part of the same port. */
222
if (port_agent->phy_valid_port_range[2].min_index == 2 &&
223
port_agent->phy_valid_port_range[3].min_index == 3) {
224
sci_phy_get_sas_address(&ihost->phys[1], &first_address);
225
sci_phy_get_sas_address(&ihost->phys[3], &second_address);
227
if (sci_sas_address_compare(first_address, second_address) == 0) {
228
return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION;
236
* ******************************************************************************
237
* Manual port configuration agent routines
238
* ****************************************************************************** */
240
/* verify all of the phys in the same port are using the same SAS address */
241
static enum sci_status
242
sci_mpc_agent_validate_phy_configuration(struct isci_host *ihost,
243
struct sci_port_configuration_agent *port_agent)
246
u32 assigned_phy_mask;
247
struct sci_sas_address sas_address;
248
struct sci_sas_address phy_assigned_address;
252
assigned_phy_mask = 0;
253
sas_address.high = 0;
256
for (port_index = 0; port_index < SCI_MAX_PORTS; port_index++) {
257
phy_mask = ihost->oem_parameters.ports[port_index].phy_mask;
262
* Make sure that one or more of the phys were not already assinged to
263
* a different port. */
264
if ((phy_mask & ~assigned_phy_mask) == 0) {
265
return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION;
268
/* Find the starting phy index for this round through the loop */
269
for (phy_index = 0; phy_index < SCI_MAX_PHYS; phy_index++) {
270
if ((phy_mask & (1 << phy_index)) == 0)
272
sci_phy_get_sas_address(&ihost->phys[phy_index],
276
* The phy_index can be used as the starting point for the
277
* port range since the hardware starts all logical ports
278
* the same as the PE index. */
279
port_agent->phy_valid_port_range[phy_index].min_index = port_index;
280
port_agent->phy_valid_port_range[phy_index].max_index = phy_index;
282
if (phy_index != port_index) {
283
return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION;
290
* See how many additional phys are being added to this logical port.
291
* Note: We have not moved the current phy_index so we will actually
292
* compare the startting phy with itself.
293
* This is expected and required to add the phy to the port. */
294
while (phy_index < SCI_MAX_PHYS) {
295
if ((phy_mask & (1 << phy_index)) == 0)
297
sci_phy_get_sas_address(&ihost->phys[phy_index],
298
&phy_assigned_address);
300
if (sci_sas_address_compare(sas_address, phy_assigned_address) != 0) {
302
* The phy mask specified that this phy is part of the same port
303
* as the starting phy and it is not so fail this configuration */
304
return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION;
307
port_agent->phy_valid_port_range[phy_index].min_index = port_index;
308
port_agent->phy_valid_port_range[phy_index].max_index = phy_index;
310
sci_port_add_phy(&ihost->ports[port_index],
311
&ihost->phys[phy_index]);
313
assigned_phy_mask |= (1 << phy_index);
319
return sci_port_configuration_agent_validate_ports(ihost, port_agent);
322
static void mpc_agent_timeout(unsigned long data)
325
struct sci_timer *tmr = (struct sci_timer *)data;
326
struct sci_port_configuration_agent *port_agent;
327
struct isci_host *ihost;
329
u16 configure_phy_mask;
331
port_agent = container_of(tmr, typeof(*port_agent), timer);
332
ihost = container_of(port_agent, typeof(*ihost), port_agent);
334
spin_lock_irqsave(&ihost->scic_lock, flags);
339
port_agent->timer_pending = false;
341
/* Find the mask of phys that are reported read but as yet unconfigured into a port */
342
configure_phy_mask = ~port_agent->phy_configured_mask & port_agent->phy_ready_mask;
344
for (index = 0; index < SCI_MAX_PHYS; index++) {
345
struct isci_phy *iphy = &ihost->phys[index];
347
if (configure_phy_mask & (1 << index)) {
348
port_agent->link_up_handler(ihost, port_agent,
349
phy_get_non_dummy_port(iphy),
355
spin_unlock_irqrestore(&ihost->scic_lock, flags);
358
static void sci_mpc_agent_link_up(struct isci_host *ihost,
359
struct sci_port_configuration_agent *port_agent,
360
struct isci_port *iport,
361
struct isci_phy *iphy)
363
/* If the port is NULL then the phy was not assigned to a port.
364
* This is because the phy was not given the same SAS Address as
365
* the other PHYs in the port.
370
port_agent->phy_ready_mask |= (1 << iphy->phy_index);
371
sci_port_link_up(iport, iphy);
372
if ((iport->active_phy_mask & (1 << iphy->phy_index)))
373
port_agent->phy_configured_mask |= (1 << iphy->phy_index);
378
* @controller: This is the controller object that receives the link down
380
* @port: This is the port object associated with the phy. If the is no
381
* associated port this is an NULL. The port is an invalid
382
* handle only if the phy was never port of this port. This happens when
383
* the phy is not broadcasting the same SAS address as the other phys in the
385
* @phy: This is the phy object which has gone link down.
387
* This function handles the manual port configuration link down notifications.
388
* Since all ports and phys are associated at initialization time we just turn
389
* around and notifiy the port object of the link down event. If this PHY is
390
* not associated with a port there is no action taken. Is it possible to get a
391
* link down notification from a phy that has no assocoated port?
393
static void sci_mpc_agent_link_down(
394
struct isci_host *ihost,
395
struct sci_port_configuration_agent *port_agent,
396
struct isci_port *iport,
397
struct isci_phy *iphy)
401
* If we can form a new port from the remainder of the phys
402
* then we want to start the timer to allow the SCI User to
403
* cleanup old devices and rediscover the port before
404
* rebuilding the port with the phys that remain in the ready
407
port_agent->phy_ready_mask &= ~(1 << iphy->phy_index);
408
port_agent->phy_configured_mask &= ~(1 << iphy->phy_index);
411
* Check to see if there are more phys waiting to be
412
* configured into a port. If there are allow the SCI User
413
* to tear down this port, if necessary, and then reconstruct
414
* the port after the timeout.
416
if ((port_agent->phy_configured_mask == 0x0000) &&
417
(port_agent->phy_ready_mask != 0x0000) &&
418
!port_agent->timer_pending) {
419
port_agent->timer_pending = true;
421
sci_mod_timer(&port_agent->timer,
422
SCIC_SDS_MPC_RECONFIGURATION_TIMEOUT);
425
sci_port_link_down(iport, iphy);
429
/* verify phys are assigned a valid SAS address for automatic port
430
* configuration mode.
432
static enum sci_status
433
sci_apc_agent_validate_phy_configuration(struct isci_host *ihost,
434
struct sci_port_configuration_agent *port_agent)
438
struct sci_sas_address sas_address;
439
struct sci_sas_address phy_assigned_address;
443
while (phy_index < SCI_MAX_PHYS) {
444
port_index = phy_index;
446
/* Get the assigned SAS Address for the first PHY on the controller. */
447
sci_phy_get_sas_address(&ihost->phys[phy_index],
450
while (++phy_index < SCI_MAX_PHYS) {
451
sci_phy_get_sas_address(&ihost->phys[phy_index],
452
&phy_assigned_address);
454
/* Verify each of the SAS address are all the same for every PHY */
455
if (sci_sas_address_compare(sas_address, phy_assigned_address) == 0) {
456
port_agent->phy_valid_port_range[phy_index].min_index = port_index;
457
port_agent->phy_valid_port_range[phy_index].max_index = phy_index;
459
port_agent->phy_valid_port_range[phy_index].min_index = phy_index;
460
port_agent->phy_valid_port_range[phy_index].max_index = phy_index;
466
return sci_port_configuration_agent_validate_ports(ihost, port_agent);
469
static void sci_apc_agent_configure_ports(struct isci_host *ihost,
470
struct sci_port_configuration_agent *port_agent,
471
struct isci_phy *iphy,
475
enum sci_status status;
476
struct isci_port *iport;
477
enum SCIC_SDS_APC_ACTIVITY apc_activity = SCIC_SDS_APC_SKIP_PHY;
479
iport = sci_port_configuration_agent_find_port(ihost, iphy);
482
if (sci_port_is_valid_phy_assignment(iport, iphy->phy_index))
483
apc_activity = SCIC_SDS_APC_ADD_PHY;
485
apc_activity = SCIC_SDS_APC_SKIP_PHY;
488
* There is no matching Port for this PHY so lets search through the
489
* Ports and see if we can add the PHY to its own port or maybe start
490
* the timer and wait to see if a wider port can be made.
492
* Note the break when we reach the condition of the port id == phy id */
493
for (port_index = port_agent->phy_valid_port_range[iphy->phy_index].min_index;
494
port_index <= port_agent->phy_valid_port_range[iphy->phy_index].max_index;
497
iport = &ihost->ports[port_index];
499
/* First we must make sure that this PHY can be added to this Port. */
500
if (sci_port_is_valid_phy_assignment(iport, iphy->phy_index)) {
502
* Port contains a PHY with a greater PHY ID than the current
503
* PHY that has gone link up. This phy can not be part of any
504
* port so skip it and move on. */
505
if (iport->active_phy_mask > (1 << iphy->phy_index)) {
506
apc_activity = SCIC_SDS_APC_SKIP_PHY;
511
* We have reached the end of our Port list and have not found
512
* any reason why we should not either add the PHY to the port
513
* or wait for more phys to become active. */
514
if (iport->physical_port_index == iphy->phy_index) {
516
* The Port either has no active PHYs.
517
* Consider that if the port had any active PHYs we would have
518
* or active PHYs with
519
* a lower PHY Id than this PHY. */
520
if (apc_activity != SCIC_SDS_APC_START_TIMER) {
521
apc_activity = SCIC_SDS_APC_ADD_PHY;
528
* The current Port has no active PHYs and this PHY could be part
529
* of this Port. Since we dont know as yet setup to start the
530
* timer and see if there is a better configuration. */
531
if (iport->active_phy_mask == 0) {
532
apc_activity = SCIC_SDS_APC_START_TIMER;
534
} else if (iport->active_phy_mask != 0) {
536
* The Port has an active phy and the current Phy can not
537
* participate in this port so skip the PHY and see if
538
* there is a better configuration. */
539
apc_activity = SCIC_SDS_APC_SKIP_PHY;
545
* Check to see if the start timer operations should instead map to an
546
* add phy operation. This is caused because we have been waiting to
547
* add a phy to a port but could not becuase the automatic port
548
* configuration engine had a choice of possible ports for the phy.
549
* Since we have gone through a timeout we are going to restrict the
550
* choice to the smallest possible port. */
552
(start_timer == false)
553
&& (apc_activity == SCIC_SDS_APC_START_TIMER)
555
apc_activity = SCIC_SDS_APC_ADD_PHY;
558
switch (apc_activity) {
559
case SCIC_SDS_APC_ADD_PHY:
560
status = sci_port_add_phy(iport, iphy);
562
if (status == SCI_SUCCESS) {
563
port_agent->phy_configured_mask |= (1 << iphy->phy_index);
567
case SCIC_SDS_APC_START_TIMER:
569
* This can occur for either a link down event, or a link
570
* up event where we cannot yet tell the port to which a
573
if (port_agent->timer_pending)
574
sci_del_timer(&port_agent->timer);
576
port_agent->timer_pending = true;
577
sci_mod_timer(&port_agent->timer,
578
SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION);
581
case SCIC_SDS_APC_SKIP_PHY:
583
/* do nothing the PHY can not be made part of a port at this time. */
589
* sci_apc_agent_link_up - handle apc link up events
590
* @scic: This is the controller object that receives the link up
592
* @sci_port: This is the port object associated with the phy. If the is no
593
* associated port this is an NULL.
594
* @sci_phy: This is the phy object which has gone link up.
596
* This method handles the automatic port configuration for link up
597
* notifications. Is it possible to get a link down notification from a phy
598
* that has no assocoated port?
600
static void sci_apc_agent_link_up(struct isci_host *ihost,
601
struct sci_port_configuration_agent *port_agent,
602
struct isci_port *iport,
603
struct isci_phy *iphy)
605
u8 phy_index = iphy->phy_index;
608
/* the phy is not the part of this port */
609
port_agent->phy_ready_mask |= 1 << phy_index;
610
sci_apc_agent_configure_ports(ihost, port_agent, iphy, true);
612
/* the phy is already the part of the port */
613
u32 port_state = iport->sm.current_state_id;
615
/* if the PORT'S state is resetting then the link up is from
616
* port hard reset in this case, we need to tell the port
617
* that link up is recieved
619
BUG_ON(port_state != SCI_PORT_RESETTING);
620
port_agent->phy_ready_mask |= 1 << phy_index;
621
sci_port_link_up(iport, iphy);
627
* @controller: This is the controller object that receives the link down
629
* @iport: This is the port object associated with the phy. If the is no
630
* associated port this is an NULL.
631
* @iphy: This is the phy object which has gone link down.
633
* This method handles the automatic port configuration link down
634
* notifications. not associated with a port there is no action taken. Is it
635
* possible to get a link down notification from a phy that has no assocoated
638
static void sci_apc_agent_link_down(
639
struct isci_host *ihost,
640
struct sci_port_configuration_agent *port_agent,
641
struct isci_port *iport,
642
struct isci_phy *iphy)
644
port_agent->phy_ready_mask &= ~(1 << iphy->phy_index);
648
if (port_agent->phy_configured_mask & (1 << iphy->phy_index)) {
649
enum sci_status status;
651
status = sci_port_remove_phy(iport, iphy);
653
if (status == SCI_SUCCESS)
654
port_agent->phy_configured_mask &= ~(1 << iphy->phy_index);
658
/* configure the phys into ports when the timer fires */
659
static void apc_agent_timeout(unsigned long data)
662
struct sci_timer *tmr = (struct sci_timer *)data;
663
struct sci_port_configuration_agent *port_agent;
664
struct isci_host *ihost;
666
u16 configure_phy_mask;
668
port_agent = container_of(tmr, typeof(*port_agent), timer);
669
ihost = container_of(port_agent, typeof(*ihost), port_agent);
671
spin_lock_irqsave(&ihost->scic_lock, flags);
676
port_agent->timer_pending = false;
678
configure_phy_mask = ~port_agent->phy_configured_mask & port_agent->phy_ready_mask;
680
if (!configure_phy_mask)
683
for (index = 0; index < SCI_MAX_PHYS; index++) {
684
if ((configure_phy_mask & (1 << index)) == 0)
687
sci_apc_agent_configure_ports(ihost, port_agent,
688
&ihost->phys[index], false);
692
spin_unlock_irqrestore(&ihost->scic_lock, flags);
696
* ******************************************************************************
697
* Public port configuration agent routines
698
* ****************************************************************************** */
703
* This method will construct the port configuration agent for operation. This
704
* call is universal for both manual port configuration and automatic port
705
* configuration modes.
707
void sci_port_configuration_agent_construct(
708
struct sci_port_configuration_agent *port_agent)
712
port_agent->phy_configured_mask = 0x00;
713
port_agent->phy_ready_mask = 0x00;
715
port_agent->link_up_handler = NULL;
716
port_agent->link_down_handler = NULL;
718
port_agent->timer_pending = false;
720
for (index = 0; index < SCI_MAX_PORTS; index++) {
721
port_agent->phy_valid_port_range[index].min_index = 0;
722
port_agent->phy_valid_port_range[index].max_index = 0;
726
enum sci_status sci_port_configuration_agent_initialize(
727
struct isci_host *ihost,
728
struct sci_port_configuration_agent *port_agent)
730
enum sci_status status;
731
enum sci_port_configuration_mode mode;
733
mode = ihost->oem_parameters.controller.mode_type;
735
if (mode == SCIC_PORT_MANUAL_CONFIGURATION_MODE) {
736
status = sci_mpc_agent_validate_phy_configuration(
739
port_agent->link_up_handler = sci_mpc_agent_link_up;
740
port_agent->link_down_handler = sci_mpc_agent_link_down;
742
sci_init_timer(&port_agent->timer, mpc_agent_timeout);
744
status = sci_apc_agent_validate_phy_configuration(
747
port_agent->link_up_handler = sci_apc_agent_link_up;
748
port_agent->link_down_handler = sci_apc_agent_link_down;
750
sci_init_timer(&port_agent->timer, apc_agent_timeout);