xref: /onnv-gate/usr/src/uts/common/io/e1000g/e1000_manage.c (revision 6735:ba4d622bb38a)
1 /*
2  * This file is provided under a CDDLv1 license.  When using or
3  * redistributing this file, you may do so under this license.
4  * In redistributing this file this license must be included
5  * and no other modification of this header file is permitted.
6  *
7  * CDDL LICENSE SUMMARY
8  *
9  * Copyright(c) 1999 - 2008 Intel Corporation. All rights reserved.
10  *
11  * The contents of this file are subject to the terms of Version
12  * 1.0 of the Common Development and Distribution License (the "License").
13  *
14  * You should have received a copy of the License with this software.
15  * You can obtain a copy of the License at
16  *	http://www.opensolaris.org/os/licensing.
17  * See the License for the specific language governing permissions
18  * and limitations under the License.
19  */
20 
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms of the CDDLv1.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * IntelVersion: 1.21 v2008-02-29
30  */
31 
32 #include "e1000_api.h"
33 #include "e1000_manage.h"
34 
35 static u8 e1000_calculate_checksum(u8 *buffer, u32 length);
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 static u8
46 e1000_calculate_checksum(u8 *buffer, u32 length)
47 {
48 	u32 i;
49 	u8 sum = 0;
50 
51 	DEBUGFUNC("e1000_calculate_checksum");
52 
53 	if (!buffer)
54 		return (0);
55 
56 	for (i = 0; i < length; i++)
57 		sum += buffer[i];
58 
59 	return (u8)(0 - sum);
60 }
61 
62 /*
63  * e1000_mng_enable_host_if_generic - Checks host interface is enabled
64  * @hw: pointer to the HW structure
65  *
66  * Returns E1000_success upon success, else E1000_ERR_HOST_INTERFACE_COMMAND
67  *
68  * This function checks whether the HOST IF is enabled for command operation
69  * and also checks whether the previous command is completed.  It busy waits
70  * in case of previous command is not completed.
71  */
72 s32
73 e1000_mng_enable_host_if_generic(struct e1000_hw *hw)
74 {
75 	u32 hicr;
76 	s32 ret_val = E1000_SUCCESS;
77 	u8 i;
78 
79 	DEBUGFUNC("e1000_mng_enable_host_if_generic");
80 
81 	/* Check that the host interface is enabled. */
82 	hicr = E1000_READ_REG(hw, E1000_HICR);
83 	if ((hicr & E1000_HICR_EN) == 0) {
84 		DEBUGOUT("E1000_HOST_EN bit disabled.\n");
85 		ret_val = -E1000_ERR_HOST_INTERFACE_COMMAND;
86 		goto out;
87 	}
88 	/* check the previous command is completed */
89 	for (i = 0; i < E1000_MNG_DHCP_COMMAND_TIMEOUT; i++) {
90 		hicr = E1000_READ_REG(hw, E1000_HICR);
91 		if (!(hicr & E1000_HICR_C))
92 			break;
93 		msec_delay_irq(1);
94 	}
95 
96 	if (i == E1000_MNG_DHCP_COMMAND_TIMEOUT) {
97 		DEBUGOUT("Previous command timeout failed .\n");
98 		ret_val = -E1000_ERR_HOST_INTERFACE_COMMAND;
99 		goto out;
100 	}
101 out:
102 	return (ret_val);
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
113 e1000_check_mng_mode_generic(struct e1000_hw *hw)
114 {
115 	u32 fwsm;
116 
117 	DEBUGFUNC("e1000_check_mng_mode_generic");
118 
119 	fwsm = E1000_READ_REG(hw, E1000_FWSM);
120 
121 	return ((fwsm & E1000_FWSM_MODE_MASK) ==
122 	    (E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT));
123 }
124 
125 /*
126  * e1000_enable_tx_pkt_filtering_generic - Enable packet filtering on TX
127  * @hw: pointer to the HW structure
128  *
129  * Enables packet filtering on transmit packets if manageability is enabled
130  * and host interface is enabled.
131  */
132 bool
133 e1000_enable_tx_pkt_filtering_generic(struct e1000_hw *hw)
134 {
135 	struct e1000_host_mng_dhcp_cookie *hdr = &hw->mng_cookie;
136 	u32 *buffer = (u32 *)&hw->mng_cookie;
137 	u32 offset;
138 	s32 ret_val, hdr_csum, csum;
139 	u8 i, len;
140 	bool tx_filter = TRUE;
141 
142 	DEBUGFUNC("e1000_enable_tx_pkt_filtering_generic");
143 
144 	/* No manageability, no filtering */
145 	if (!hw->mac.ops.check_mng_mode(hw)) {
146 		tx_filter = FALSE;
147 		goto out;
148 	}
149 
150 	/*
151 	 * If we can't read from the host interface for whatever reason,
152 	 * disable filtering.
153 	 */
154 	ret_val = hw->mac.ops.mng_enable_host_if(hw);
155 	if (ret_val != E1000_SUCCESS) {
156 		tx_filter = FALSE;
157 		goto out;
158 	}
159 
160 	/* Read in the header.  Length and offset are in dwords. */
161 	len = E1000_MNG_DHCP_COOKIE_LENGTH >> 2;
162 	offset = E1000_MNG_DHCP_COOKIE_OFFSET >> 2;
163 	for (i = 0; i < len; i++) {
164 		*(buffer + i) = E1000_READ_REG_ARRAY_DWORD(hw,
165 		    E1000_HOST_IF,
166 		    offset + i);
167 	}
168 	hdr_csum = hdr->checksum;
169 	hdr->checksum = 0;
170 	csum = e1000_calculate_checksum((u8 *)hdr,
171 	    E1000_MNG_DHCP_COOKIE_LENGTH);
172 	/*
173 	 * If either the checksums or signature don't match, then the cookie
174 	 * area isn't considered valid, in which case we take the safe route
175 	 * of assuming Tx filtering is enabled.
176 	 */
177 	if (hdr_csum != csum)
178 		goto out;
179 	if (hdr->signature != E1000_IAMT_SIGNATURE)
180 		goto out;
181 
182 	/* Cookie area is valid, make the final check for filtering. */
183 	if (!(hdr->status & E1000_MNG_DHCP_COOKIE_STATUS_PARSING))
184 		tx_filter = FALSE;
185 
186 out:
187 	hw->mac.tx_pkt_filtering = tx_filter;
188 	return (tx_filter);
189 }
190 
191 /*
192  * e1000_mng_write_dhcp_info_generic - Writes DHCP info to host interface
193  * @hw: pointer to the HW structure
194  * @buffer: pointer to the host interface
195  * @length: size of the buffer
196  *
197  * Writes the DHCP information to the host interface.
198  */
199 s32
200 e1000_mng_write_dhcp_info_generic(struct e1000_hw *hw, u8 *buffer,
201     u16 length)
202 {
203 	struct e1000_host_mng_command_header hdr;
204 	s32 ret_val;
205 	u32 hicr;
206 
207 	DEBUGFUNC("e1000_mng_write_dhcp_info_generic");
208 
209 	hdr.command_id = E1000_MNG_DHCP_TX_PAYLOAD_CMD;
210 	hdr.command_length = length;
211 	hdr.reserved1 = 0;
212 	hdr.reserved2 = 0;
213 	hdr.checksum = 0;
214 
215 	/* Enable the host interface */
216 	ret_val = hw->mac.ops.mng_enable_host_if(hw);
217 	if (ret_val)
218 		goto out;
219 
220 	/* Populate the host interface with the contents of "buffer". */
221 	ret_val = hw->mac.ops.mng_host_if_write(hw, buffer, length,
222 	    sizeof (hdr), &(hdr.checksum));
223 	if (ret_val)
224 		goto out;
225 
226 	/* Write the manageability command header */
227 	ret_val = hw->mac.ops.mng_write_cmd_header(hw, &hdr);
228 	if (ret_val)
229 		goto out;
230 
231 	/* Tell the ARC a new command is pending. */
232 	hicr = E1000_READ_REG(hw, E1000_HICR);
233 	E1000_WRITE_REG(hw, E1000_HICR, hicr | E1000_HICR_C);
234 
235 out:
236 	return (ret_val);
237 }
238 
239 /*
240  * e1000_mng_write_cmd_header_generic - Writes manageability command header
241  * @hw: pointer to the HW structure
242  * @hdr: pointer to the host interface command header
243  *
244  * Writes the command header after does the checksum calculation.
245  */
246 s32
247 e1000_mng_write_cmd_header_generic(struct e1000_hw *hw,
248     struct e1000_host_mng_command_header *hdr)
249 {
250 	u16 i, length = sizeof (struct e1000_host_mng_command_header);
251 
252 	DEBUGFUNC("e1000_mng_write_cmd_header_generic");
253 
254 	/* Write the whole command header structure with new checksum. */
255 
256 	hdr->checksum = e1000_calculate_checksum((u8 *)hdr, length);
257 
258 	length >>= 2;
259 	/* Write the relevant command block into the ram area. */
260 	for (i = 0; i < length; i++) {
261 		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, i,
262 		    *((u32 *) hdr + i));
263 		E1000_WRITE_FLUSH(hw);
264 	}
265 
266 	return (E1000_SUCCESS);
267 }
268 
269 /*
270  * e1000_mng_host_if_write_generic - Write to the manageability host interface
271  * @hw: pointer to the HW structure
272  * @buffer: pointer to the host interface buffer
273  * @length: size of the buffer
274  * @offset: location in the buffer to write to
275  * @sum: sum of the data (not checksum)
276  *
277  * This function writes the buffer content at the offset given on the host if.
278  * It also does alignment considerations to do the writes in most efficient
279  * way.  Also fills up the sum of the buffer in *buffer parameter.
280  */
281 s32
282 e1000_mng_host_if_write_generic(struct e1000_hw *hw, u8 *buffer,
283     u16 length, u16 offset, u8 *sum)
284 {
285 	u8 *tmp;
286 	u8 *bufptr = buffer;
287 	u32 data = 0;
288 	s32 ret_val = E1000_SUCCESS;
289 	u16 remaining, i, j, prev_bytes;
290 
291 	DEBUGFUNC("e1000_mng_host_if_write_generic");
292 
293 	/* sum = only sum of the data and it is not checksum */
294 
295 	if (length == 0 || offset + length > E1000_HI_MAX_MNG_DATA_LENGTH) {
296 		ret_val = -E1000_ERR_PARAM;
297 		goto out;
298 	}
299 
300 	tmp = (u8 *)&data;
301 	prev_bytes = offset & 0x3;
302 	offset >>= 2;
303 
304 	if (prev_bytes) {
305 		data = E1000_READ_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset);
306 		for (j = prev_bytes; j < sizeof (u32); j++) {
307 			*(tmp + j) = *bufptr++;
308 			*sum += *(tmp + j);
309 		}
310 		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset, data);
311 		length -= j - prev_bytes;
312 		offset++;
313 	}
314 
315 	remaining = length & 0x3;
316 	length -= remaining;
317 
318 	/* Calculate length in DWORDs */
319 	length >>= 2;
320 
321 	/*
322 	 * The device driver writes the relevant command block into the ram
323 	 * area.
324 	 */
325 	for (i = 0; i < length; i++) {
326 		for (j = 0; j < sizeof (u32); j++) {
327 			*(tmp + j) = *bufptr++;
328 			*sum += *(tmp + j);
329 		}
330 
331 		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF,
332 		    offset + i, data);
333 	}
334 	if (remaining) {
335 		for (j = 0; j < sizeof (u32); j++) {
336 			if (j < remaining)
337 				*(tmp + j) = *bufptr++;
338 			else
339 				*(tmp + j) = 0;
340 
341 			*sum += *(tmp + j);
342 		}
343 		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF,
344 		    offset + i, data);
345 	}
346 out:
347 	return (ret_val);
348 }
349 
350 /*
351  * e1000_enable_mng_pass_thru - Enable processing of ARP's
352  * @hw: pointer to the HW structure
353  *
354  * Verifies the hardware needs to allow ARPs to be processed by the host.
355  */
356 bool
357 e1000_enable_mng_pass_thru(struct e1000_hw *hw)
358 {
359 	u32 manc;
360 	u32 fwsm, factps;
361 	bool ret_val = FALSE;
362 
363 	DEBUGFUNC("e1000_enable_mng_pass_thru");
364 
365 	if (!hw->mac.asf_firmware_present)
366 		goto out;
367 
368 	manc = E1000_READ_REG(hw, E1000_MANC);
369 
370 	if (!(manc & E1000_MANC_RCV_TCO_EN) ||
371 	    !(manc & E1000_MANC_EN_MAC_ADDR_FILTER))
372 		goto out;
373 
374 	if (hw->mac.arc_subsystem_valid) {
375 		fwsm = E1000_READ_REG(hw, E1000_FWSM);
376 		factps = E1000_READ_REG(hw, E1000_FACTPS);
377 
378 		if (!(factps & E1000_FACTPS_MNGCG) &&
379 		    ((fwsm & E1000_FWSM_MODE_MASK) ==
380 		    (e1000_mng_mode_pt << E1000_FWSM_MODE_SHIFT))) {
381 			ret_val = TRUE;
382 			goto out;
383 		}
384 	} else {
385 		if ((manc & E1000_MANC_SMBUS_EN) &&
386 		    !(manc & E1000_MANC_ASF_EN)) {
387 			ret_val = TRUE;
388 			goto out;
389 		}
390 	}
391 
392 out:
393 	return (ret_val);
394 }
395