xref: /dragonfly/sys/dev/netif/ig_hal/e1000_manage.c (revision 1f2824e8)
1 /******************************************************************************
2 
3   Copyright (c) 2001-2011, Intel Corporation
4   All rights reserved.
5 
6   Redistribution and use in source and binary forms, with or without
7   modification, are permitted provided that the following conditions are met:
8 
9    1. Redistributions of source code must retain the above copyright notice,
10       this list of conditions and the following disclaimer.
11 
12    2. Redistributions in binary form must reproduce the above copyright
13       notice, this list of conditions and the following disclaimer in the
14       documentation and/or other materials provided with the distribution.
15 
16    3. Neither the name of the Intel Corporation nor the names of its
17       contributors may be used to endorse or promote products derived from
18       this software without specific prior written permission.
19 
20   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30   POSSIBILITY OF SUCH DAMAGE.
31 
32 ******************************************************************************/
33 /*$FreeBSD$*/
34 
35 #include "e1000_api.h"
36 
37 /**
38  *  e1000_calculate_checksum - Calculate checksum for buffer
39  *  @buffer: pointer to EEPROM
40  *  @length: size of EEPROM to calculate a checksum for
41  *
42  *  Calculates the checksum for some buffer on a specified length.  The
43  *  checksum calculated is returned.
44  **/
45 u8 e1000_calculate_checksum(u8 *buffer, u32 length)
46 {
47 	u32 i;
48 	u8 sum = 0;
49 
50 	DEBUGFUNC("e1000_calculate_checksum");
51 
52 	if (!buffer)
53 		return 0;
54 
55 	for (i = 0; i < length; i++)
56 		sum += buffer[i];
57 
58 	return (u8) (0 - sum);
59 }
60 
61 /**
62  *  e1000_mng_enable_host_if_generic - Checks host interface is enabled
63  *  @hw: pointer to the HW structure
64  *
65  *  Returns E1000_success upon success, else E1000_ERR_HOST_INTERFACE_COMMAND
66  *
67  *  This function checks whether the HOST IF is enabled for command operation
68  *  and also checks whether the previous command is completed.  It busy waits
69  *  in case of previous command is not completed.
70  **/
71 s32 e1000_mng_enable_host_if_generic(struct e1000_hw *hw)
72 {
73 	u32 hicr;
74 	u8 i;
75 
76 	DEBUGFUNC("e1000_mng_enable_host_if_generic");
77 
78 	if (!hw->mac.arc_subsystem_valid) {
79 		DEBUGOUT("ARC subsystem not valid.\n");
80 		return -E1000_ERR_HOST_INTERFACE_COMMAND;
81 	}
82 
83 	/* Check that the host interface is enabled. */
84 	hicr = E1000_READ_REG(hw, E1000_HICR);
85 	if (!(hicr & E1000_HICR_EN)) {
86 		DEBUGOUT("E1000_HOST_EN bit disabled.\n");
87 		return -E1000_ERR_HOST_INTERFACE_COMMAND;
88 	}
89 	/* check the previous command is completed */
90 	for (i = 0; i < E1000_MNG_DHCP_COMMAND_TIMEOUT; i++) {
91 		hicr = E1000_READ_REG(hw, E1000_HICR);
92 		if (!(hicr & E1000_HICR_C))
93 			break;
94 		msec_delay_irq(1);
95 	}
96 
97 	if (i == E1000_MNG_DHCP_COMMAND_TIMEOUT) {
98 		DEBUGOUT("Previous command timeout failed .\n");
99 		return -E1000_ERR_HOST_INTERFACE_COMMAND;
100 	}
101 
102 	return E1000_SUCCESS;
103 }
104 
105 /**
106  *  e1000_check_mng_mode_generic - Generic check management mode
107  *  @hw: pointer to the HW structure
108  *
109  *  Reads the firmware semaphore register and returns TRUE (>0) if
110  *  manageability is enabled, else FALSE (0).
111  **/
112 bool e1000_check_mng_mode_generic(struct e1000_hw *hw)
113 {
114 	u32 fwsm = E1000_READ_REG(hw, E1000_FWSM);
115 
116 	DEBUGFUNC("e1000_check_mng_mode_generic");
117 
118 
119 	return (fwsm & E1000_FWSM_MODE_MASK) ==
120 		(E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT);
121 }
122 
123 /**
124  *  e1000_enable_tx_pkt_filtering_generic - Enable packet filtering on Tx
125  *  @hw: pointer to the HW structure
126  *
127  *  Enables packet filtering on transmit packets if manageability is enabled
128  *  and host interface is enabled.
129  **/
130 bool e1000_enable_tx_pkt_filtering_generic(struct e1000_hw *hw)
131 {
132 	struct e1000_host_mng_dhcp_cookie *hdr = &hw->mng_cookie;
133 	u32 *buffer = (u32 *)&hw->mng_cookie;
134 	u32 offset;
135 	s32 ret_val, hdr_csum, csum;
136 	u8 i, len;
137 
138 	DEBUGFUNC("e1000_enable_tx_pkt_filtering_generic");
139 
140 	hw->mac.tx_pkt_filtering = TRUE;
141 
142 	/* No manageability, no filtering */
143 	if (!hw->mac.ops.check_mng_mode(hw)) {
144 		hw->mac.tx_pkt_filtering = FALSE;
145 		return hw->mac.tx_pkt_filtering;
146 	}
147 
148 	/*
149 	 * If we can't read from the host interface for whatever
150 	 * reason, disable filtering.
151 	 */
152 	ret_val = hw->mac.ops.mng_enable_host_if(hw);
153 	if (ret_val != E1000_SUCCESS) {
154 		hw->mac.tx_pkt_filtering = FALSE;
155 		return hw->mac.tx_pkt_filtering;
156 	}
157 
158 	/* Read in the header.  Length and offset are in dwords. */
159 	len    = E1000_MNG_DHCP_COOKIE_LENGTH >> 2;
160 	offset = E1000_MNG_DHCP_COOKIE_OFFSET >> 2;
161 	for (i = 0; i < len; i++)
162 		*(buffer + i) = E1000_READ_REG_ARRAY_DWORD(hw, E1000_HOST_IF,
163 							   offset + i);
164 	hdr_csum = hdr->checksum;
165 	hdr->checksum = 0;
166 	csum = e1000_calculate_checksum((u8 *)hdr,
167 					E1000_MNG_DHCP_COOKIE_LENGTH);
168 	/*
169 	 * If either the checksums or signature don't match, then
170 	 * the cookie area isn't considered valid, in which case we
171 	 * take the safe route of assuming Tx filtering is enabled.
172 	 */
173 	if ((hdr_csum != csum) || (hdr->signature != E1000_IAMT_SIGNATURE)) {
174 		hw->mac.tx_pkt_filtering = TRUE;
175 		return hw->mac.tx_pkt_filtering;
176 	}
177 
178 	/* Cookie area is valid, make the final check for filtering. */
179 	if (!(hdr->status & E1000_MNG_DHCP_COOKIE_STATUS_PARSING))
180 		hw->mac.tx_pkt_filtering = FALSE;
181 
182 	return hw->mac.tx_pkt_filtering;
183 }
184 
185 /**
186  *  e1000_mng_write_cmd_header_generic - Writes manageability command header
187  *  @hw: pointer to the HW structure
188  *  @hdr: pointer to the host interface command header
189  *
190  *  Writes the command header after does the checksum calculation.
191  **/
192 s32 e1000_mng_write_cmd_header_generic(struct e1000_hw *hw,
193 				      struct e1000_host_mng_command_header *hdr)
194 {
195 	u16 i, length = sizeof(struct e1000_host_mng_command_header);
196 
197 	DEBUGFUNC("e1000_mng_write_cmd_header_generic");
198 
199 	/* Write the whole command header structure with new checksum. */
200 
201 	hdr->checksum = e1000_calculate_checksum((u8 *)hdr, length);
202 
203 	length >>= 2;
204 	/* Write the relevant command block into the ram area. */
205 	for (i = 0; i < length; i++) {
206 		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, i,
207 					    *((u32 *) hdr + i));
208 		E1000_WRITE_FLUSH(hw);
209 	}
210 
211 	return E1000_SUCCESS;
212 }
213 
214 /**
215  *  e1000_mng_host_if_write_generic - Write to the manageability host interface
216  *  @hw: pointer to the HW structure
217  *  @buffer: pointer to the host interface buffer
218  *  @length: size of the buffer
219  *  @offset: location in the buffer to write to
220  *  @sum: sum of the data (not checksum)
221  *
222  *  This function writes the buffer content at the offset given on the host if.
223  *  It also does alignment considerations to do the writes in most efficient
224  *  way.  Also fills up the sum of the buffer in *buffer parameter.
225  **/
226 s32 e1000_mng_host_if_write_generic(struct e1000_hw *hw, u8 *buffer,
227 				    u16 length, u16 offset, u8 *sum)
228 {
229 	u8 *tmp;
230 	u8 *bufptr = buffer;
231 	u32 data = 0;
232 	u16 remaining, i, j, prev_bytes;
233 
234 	DEBUGFUNC("e1000_mng_host_if_write_generic");
235 
236 	/* sum = only sum of the data and it is not checksum */
237 
238 	if (length == 0 || offset + length > E1000_HI_MAX_MNG_DATA_LENGTH)
239 		return -E1000_ERR_PARAM;
240 
241 	tmp = (u8 *)&data;
242 	prev_bytes = offset & 0x3;
243 	offset >>= 2;
244 
245 	if (prev_bytes) {
246 		data = E1000_READ_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset);
247 		for (j = prev_bytes; j < sizeof(u32); j++) {
248 			*(tmp + j) = *bufptr++;
249 			*sum += *(tmp + j);
250 		}
251 		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset, data);
252 		length -= j - prev_bytes;
253 		offset++;
254 	}
255 
256 	remaining = length & 0x3;
257 	length -= remaining;
258 
259 	/* Calculate length in DWORDs */
260 	length >>= 2;
261 
262 	/*
263 	 * The device driver writes the relevant command block into the
264 	 * ram area.
265 	 */
266 	for (i = 0; i < length; i++) {
267 		for (j = 0; j < sizeof(u32); j++) {
268 			*(tmp + j) = *bufptr++;
269 			*sum += *(tmp + j);
270 		}
271 
272 		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset + i,
273 					    data);
274 	}
275 	if (remaining) {
276 		for (j = 0; j < sizeof(u32); j++) {
277 			if (j < remaining)
278 				*(tmp + j) = *bufptr++;
279 			else
280 				*(tmp + j) = 0;
281 
282 			*sum += *(tmp + j);
283 		}
284 		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset + i,
285 					    data);
286 	}
287 
288 	return E1000_SUCCESS;
289 }
290 
291 /**
292  *  e1000_mng_write_dhcp_info_generic - Writes DHCP info to host interface
293  *  @hw: pointer to the HW structure
294  *  @buffer: pointer to the host interface
295  *  @length: size of the buffer
296  *
297  *  Writes the DHCP information to the host interface.
298  **/
299 s32 e1000_mng_write_dhcp_info_generic(struct e1000_hw *hw, u8 *buffer,
300 				      u16 length)
301 {
302 	struct e1000_host_mng_command_header hdr;
303 	s32 ret_val;
304 	u32 hicr;
305 
306 	DEBUGFUNC("e1000_mng_write_dhcp_info_generic");
307 
308 	hdr.command_id = E1000_MNG_DHCP_TX_PAYLOAD_CMD;
309 	hdr.command_length = length;
310 	hdr.reserved1 = 0;
311 	hdr.reserved2 = 0;
312 	hdr.checksum = 0;
313 
314 	/* Enable the host interface */
315 	ret_val = hw->mac.ops.mng_enable_host_if(hw);
316 	if (ret_val)
317 		return ret_val;
318 
319 	/* Populate the host interface with the contents of "buffer". */
320 	ret_val = hw->mac.ops.mng_host_if_write(hw, buffer, length,
321 						sizeof(hdr), &(hdr.checksum));
322 	if (ret_val)
323 		return ret_val;
324 
325 	/* Write the manageability command header */
326 	ret_val = hw->mac.ops.mng_write_cmd_header(hw, &hdr);
327 	if (ret_val)
328 		return ret_val;
329 
330 	/* Tell the ARC a new command is pending. */
331 	hicr = E1000_READ_REG(hw, E1000_HICR);
332 	E1000_WRITE_REG(hw, E1000_HICR, hicr | E1000_HICR_C);
333 
334 	return E1000_SUCCESS;
335 }
336 
337 /**
338  *  e1000_enable_mng_pass_thru - Check if management passthrough is needed
339  *  @hw: pointer to the HW structure
340  *
341  *  Verifies the hardware needs to leave interface enabled so that frames can
342  *  be directed to and from the management interface.
343  **/
344 bool e1000_enable_mng_pass_thru(struct e1000_hw *hw)
345 {
346 	u32 manc;
347 	u32 fwsm, factps;
348 
349 	DEBUGFUNC("e1000_enable_mng_pass_thru");
350 
351 	if (!hw->mac.asf_firmware_present)
352 		return FALSE;
353 
354 	manc = E1000_READ_REG(hw, E1000_MANC);
355 
356 	if (!(manc & E1000_MANC_RCV_TCO_EN))
357 		return FALSE;
358 
359 	if (hw->mac.has_fwsm) {
360 		fwsm = E1000_READ_REG(hw, E1000_FWSM);
361 		factps = E1000_READ_REG(hw, E1000_FACTPS);
362 
363 		if (!(factps & E1000_FACTPS_MNGCG) &&
364 		    ((fwsm & E1000_FWSM_MODE_MASK) ==
365 		     (e1000_mng_mode_pt << E1000_FWSM_MODE_SHIFT)))
366 			return TRUE;
367 	} else if ((hw->mac.type == e1000_82574) ||
368 		   (hw->mac.type == e1000_82583)) {
369 		u16 data;
370 
371 		factps = E1000_READ_REG(hw, E1000_FACTPS);
372 		e1000_read_nvm(hw, NVM_INIT_CONTROL2_REG, 1, &data);
373 
374 		if (!(factps & E1000_FACTPS_MNGCG) &&
375 		    ((data & E1000_NVM_INIT_CTRL2_MNGM) ==
376 		     (e1000_mng_mode_pt << 13)))
377 			return TRUE;
378 	} else if ((manc & E1000_MANC_SMBUS_EN) &&
379 		   !(manc & E1000_MANC_ASF_EN)) {
380 			return TRUE;
381 	}
382 
383 	return FALSE;
384 }
385 
386 /**
387  *  e1000_host_interface_command - Writes buffer to host interface
388  *  @hw: pointer to the HW structure
389  *  @buffer: contains a command to write
390  *  @length: the byte length of the buffer, must be multiple of 4 bytes
391  *
392  *  Writes a buffer to the Host Interface.  Upon success, returns E1000_SUCCESS
393  *  else returns E1000_ERR_HOST_INTERFACE_COMMAND.
394  **/
395 s32 e1000_host_interface_command(struct e1000_hw *hw, u8 *buffer, u32 length)
396 {
397 	u32 hicr, i;
398 
399 	DEBUGFUNC("e1000_host_interface_command");
400 
401 	if (!(hw->mac.arc_subsystem_valid)) {
402 		DEBUGOUT("Hardware doesn't support host interface command.\n");
403 		return E1000_SUCCESS;
404 	}
405 
406 	if (!hw->mac.asf_firmware_present) {
407 		DEBUGOUT("Firmware is not present.\n");
408 		return E1000_SUCCESS;
409 	}
410 
411 	if (length == 0 || length & 0x3 ||
412 	    length > E1000_HI_MAX_BLOCK_BYTE_LENGTH) {
413 		DEBUGOUT("Buffer length failure.\n");
414 		return -E1000_ERR_HOST_INTERFACE_COMMAND;
415 	}
416 
417 	/* Check that the host interface is enabled. */
418 	hicr = E1000_READ_REG(hw, E1000_HICR);
419 	if (!(hicr & E1000_HICR_EN)) {
420 		DEBUGOUT("E1000_HOST_EN bit disabled.\n");
421 		return -E1000_ERR_HOST_INTERFACE_COMMAND;
422 	}
423 
424 	/* Calculate length in DWORDs */
425 	length >>= 2;
426 
427 	/*
428 	 * The device driver writes the relevant command block
429 	 * into the ram area.
430 	 */
431 	for (i = 0; i < length; i++)
432 		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, i,
433 					    *((u32 *)buffer + i));
434 
435 	/* Setting this bit tells the ARC that a new command is pending. */
436 	E1000_WRITE_REG(hw, E1000_HICR, hicr | E1000_HICR_C);
437 
438 	for (i = 0; i < E1000_HI_COMMAND_TIMEOUT; i++) {
439 		hicr = E1000_READ_REG(hw, E1000_HICR);
440 		if (!(hicr & E1000_HICR_C))
441 			break;
442 		msec_delay(1);
443 	}
444 
445 	/* Check command successful completion. */
446 	if (i == E1000_HI_COMMAND_TIMEOUT ||
447 	    (!(E1000_READ_REG(hw, E1000_HICR) & E1000_HICR_SV))) {
448 		DEBUGOUT("Command has failed with no status valid.\n");
449 		return -E1000_ERR_HOST_INTERFACE_COMMAND;
450 	}
451 
452 	for (i = 0; i < length; i++)
453 		*((u32 *)buffer + i) = E1000_READ_REG_ARRAY_DWORD(hw,
454 								  E1000_HOST_IF,
455 								  i);
456 
457 	return E1000_SUCCESS;
458 }
459 /**
460  *  e1000_load_firmware - Writes proxy FW code buffer to host interface
461  *                        and execute.
462  *  @hw: pointer to the HW structure
463  *  @buffer: contains a firmware to write
464  *  @length: the byte length of the buffer, must be multiple of 4 bytes
465  *
466  *  Upon success returns E1000_SUCCESS, returns E1000_ERR_CONFIG if not enabled
467  *  in HW else returns E1000_ERR_HOST_INTERFACE_COMMAND.
468  **/
469 s32 e1000_load_firmware(struct e1000_hw *hw, u8 *buffer, u32 length)
470 {
471 	u32 hicr, hibba, fwsm, icr, i;
472 
473 	DEBUGFUNC("e1000_load_firmware");
474 
475 	if (hw->mac.type < e1000_i210) {
476 		DEBUGOUT("Hardware doesn't support loading FW by the driver\n");
477 		return -E1000_ERR_CONFIG;
478 	}
479 
480 	/* Check that the host interface is enabled. */
481 	hicr = E1000_READ_REG(hw, E1000_HICR);
482 	if (!(hicr & E1000_HICR_EN)) {
483 		DEBUGOUT("E1000_HOST_EN bit disabled.\n");
484 		return -E1000_ERR_CONFIG;
485 	}
486 	if (!(hicr & E1000_HICR_MEMORY_BASE_EN)) {
487 		DEBUGOUT("E1000_HICR_MEMORY_BASE_EN bit disabled.\n");
488 		return -E1000_ERR_CONFIG;
489 	}
490 
491 	if (length == 0 || length & 0x3 || length > E1000_HI_FW_MAX_LENGTH) {
492 		DEBUGOUT("Buffer length failure.\n");
493 		return -E1000_ERR_INVALID_ARGUMENT;
494 	}
495 
496 	/* Clear notification from ROM-FW by reading ICR register */
497 	icr = E1000_READ_REG(hw, E1000_ICR_V2);
498 
499 	/* Reset ROM-FW */
500 	hicr = E1000_READ_REG(hw, E1000_HICR);
501 	hicr |= E1000_HICR_FW_RESET_ENABLE;
502 	E1000_WRITE_REG(hw, E1000_HICR, hicr);
503 	hicr |= E1000_HICR_FW_RESET;
504 	E1000_WRITE_REG(hw, E1000_HICR, hicr);
505 	E1000_WRITE_FLUSH(hw);
506 
507 	/* Wait till MAC notifies about its readiness after ROM-FW reset */
508 	for (i = 0; i < (E1000_HI_COMMAND_TIMEOUT * 2); i++) {
509 		icr = E1000_READ_REG(hw, E1000_ICR_V2);
510 		if (icr & E1000_ICR_MNG)
511 			break;
512 		msec_delay(1);
513 	}
514 
515 	/* Check for timeout */
516 	if (i == E1000_HI_COMMAND_TIMEOUT) {
517 		DEBUGOUT("FW reset failed.\n");
518 		return -E1000_ERR_HOST_INTERFACE_COMMAND;
519 	}
520 
521 	/* Wait till MAC is ready to accept new FW code */
522 	for (i = 0; i < E1000_HI_COMMAND_TIMEOUT; i++) {
523 		fwsm = E1000_READ_REG(hw, E1000_FWSM);
524 		if ((fwsm & E1000_FWSM_FW_VALID) &&
525 		    ((fwsm & E1000_FWSM_MODE_MASK) >> E1000_FWSM_MODE_SHIFT ==
526 		    E1000_FWSM_HI_EN_ONLY_MODE))
527 			break;
528 		msec_delay(1);
529 	}
530 
531 	/* Check for timeout */
532 	if (i == E1000_HI_COMMAND_TIMEOUT) {
533 		DEBUGOUT("FW reset failed.\n");
534 		return -E1000_ERR_HOST_INTERFACE_COMMAND;
535 	}
536 
537 	/* Calculate length in DWORDs */
538 	length >>= 2;
539 
540 	/*
541 	 * The device driver writes the relevant FW code block
542 	 * into the ram area in DWORDs via 1kB ram addressing window.
543 	 */
544 	for (i = 0; i < length; i++) {
545 		if (!(i % E1000_HI_FW_BLOCK_DWORD_LENGTH)) {
546 			/* Point to correct 1kB ram window */
547 			hibba = E1000_HI_FW_BASE_ADDRESS +
548 				((E1000_HI_FW_BLOCK_DWORD_LENGTH << 2) *
549 				(i / E1000_HI_FW_BLOCK_DWORD_LENGTH));
550 
551 			E1000_WRITE_REG(hw, E1000_HIBBA, hibba);
552 		}
553 
554 		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF,
555 					    i % E1000_HI_FW_BLOCK_DWORD_LENGTH,
556 					    *((u32 *)buffer + i));
557 	}
558 
559 	/* Setting this bit tells the ARC that a new FW is ready to execute. */
560 	hicr = E1000_READ_REG(hw, E1000_HICR);
561 	E1000_WRITE_REG(hw, E1000_HICR, hicr | E1000_HICR_C);
562 
563 	for (i = 0; i < E1000_HI_COMMAND_TIMEOUT; i++) {
564 		hicr = E1000_READ_REG(hw, E1000_HICR);
565 		if (!(hicr & E1000_HICR_C))
566 			break;
567 		msec_delay(1);
568 	}
569 
570 	/* Check for successful FW start. */
571 	if (i == E1000_HI_COMMAND_TIMEOUT) {
572 		DEBUGOUT("New FW did not start within timeout period.\n");
573 		return -E1000_ERR_HOST_INTERFACE_COMMAND;
574 	}
575 
576 	return E1000_SUCCESS;
577 }
578 
579 
580