xref: /onnv-gate/usr/src/uts/common/io/e1000g/e1000_manage.c (revision 4919:b6b235c6e23b)
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 - 2007 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 2007 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: HSD_2343720b_DragonLake3 v2007-06-14_HSD_2343720b_DragonLake3
30  */
31 #include "e1000_api.h"
32 #include "e1000_manage.h"
33 
34 static u8 e1000_calculate_checksum(u8 *buffer, u32 length);
35 
36 /*
37  * e1000_calculate_checksum - Calculate checksum for buffer
38  * @buffer: pointer to EEPROM
39  * @length: size of EEPROM to calculate a checksum for
40  *
41  * Calculates the checksum for some buffer on a specified length.  The
42  * checksum calculated is returned.
43  */
44 static u8
45 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 operaton
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
72 e1000_mng_enable_host_if_generic(struct e1000_hw *hw)
73 {
74 	u32 hicr;
75 	s32 ret_val = E1000_SUCCESS;
76 	u8 i;
77 
78 	DEBUGFUNC("e1000_mng_enable_host_if_generic");
79 
80 	/* Check that the host interface is enabled. */
81 	hicr = E1000_READ_REG(hw, E1000_HICR);
82 	if ((hicr & E1000_HICR_EN) == 0) {
83 		DEBUGOUT("E1000_HOST_EN bit disabled.\n");
84 		ret_val = -E1000_ERR_HOST_INTERFACE_COMMAND;
85 		goto out;
86 	}
87 	/* check the previous command is completed */
88 	for (i = 0; i < E1000_MNG_DHCP_COMMAND_TIMEOUT; i++) {
89 		hicr = E1000_READ_REG(hw, E1000_HICR);
90 		if (!(hicr & E1000_HICR_C))
91 			break;
92 		msec_delay_irq(1);
93 	}
94 
95 	if (i == E1000_MNG_DHCP_COMMAND_TIMEOUT) {
96 		DEBUGOUT("Previous command timeout failed .\n");
97 		ret_val = -E1000_ERR_HOST_INTERFACE_COMMAND;
98 		goto out;
99 	}
100 out:
101 	return (ret_val);
102 }
103 
104 /*
105  * e1000_check_mng_mode_generic - Generic check managament mode
106  * @hw: pointer to the HW structure
107  *
108  * Reads the firmware semaphore register and returns true (>0) if
109  * manageability is enabled, else false (0).
110  */
111 boolean_t
112 e1000_check_mng_mode_generic(struct e1000_hw *hw)
113 {
114 	u32 fwsm;
115 
116 	DEBUGFUNC("e1000_check_mng_mode_generic");
117 
118 	fwsm = E1000_READ_REG(hw, E1000_FWSM);
119 
120 	return ((fwsm & E1000_FWSM_MODE_MASK) ==
121 	    (E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT));
122 }
123 
124 /*
125  * e1000_enable_tx_pkt_filtering_generic - Enable packet filtering on TX
126  * @hw: pointer to the HW structure
127  *
128  * Enables packet filtering on transmit packets if manageability is enabled
129  * and host interface is enabled.
130  */
131 boolean_t
132 e1000_enable_tx_pkt_filtering_generic(struct e1000_hw *hw)
133 {
134 	struct e1000_host_mng_dhcp_cookie *hdr = &hw->mng_cookie;
135 	u32 *buffer = (u32 *)&hw->mng_cookie;
136 	u32 offset;
137 	s32 ret_val, hdr_csum, csum;
138 	u8 i, len;
139 	boolean_t tx_filter = TRUE;
140 
141 	DEBUGFUNC("e1000_enable_tx_pkt_filtering_generic");
142 
143 	/* No manageability, no filtering */
144 	if (!e1000_check_mng_mode(hw)) {
145 		tx_filter = FALSE;
146 		goto out;
147 	}
148 
149 	/*
150 	 * If we can't read from the host interface for whatever reason,
151 	 * disable filtering.
152 	 */
153 	ret_val = e1000_mng_enable_host_if(hw);
154 	if (ret_val != E1000_SUCCESS) {
155 		tx_filter = FALSE;
156 		goto out;
157 	}
158 
159 	/* Read in the header.  Length and offset are in dwords. */
160 	len = E1000_MNG_DHCP_COOKIE_LENGTH >> 2;
161 	offset = E1000_MNG_DHCP_COOKIE_OFFSET >> 2;
162 	for (i = 0; i < len; i++) {
163 		*(buffer + i) = E1000_READ_REG_ARRAY_DWORD(hw,
164 		    E1000_HOST_IF,
165 		    offset + i);
166 	}
167 	hdr_csum = hdr->checksum;
168 	hdr->checksum = 0;
169 	csum = e1000_calculate_checksum((u8 *)hdr,
170 	    E1000_MNG_DHCP_COOKIE_LENGTH);
171 	/*
172 	 * If either the checksums or signature don't match, then the cookie
173 	 * area isn't considered valid, in which case we take the safe route
174 	 * of assuming Tx filtering is enabled.
175 	 */
176 	if (hdr_csum != csum)
177 		goto out;
178 	if (hdr->signature != E1000_IAMT_SIGNATURE)
179 		goto out;
180 
181 	/* Cookie area is valid, make the final check for filtering. */
182 	if (!(hdr->status & E1000_MNG_DHCP_COOKIE_STATUS_PARSING))
183 		tx_filter = FALSE;
184 
185 out:
186 	hw->mac.tx_pkt_filtering = tx_filter;
187 	return (tx_filter);
188 }
189 
190 /*
191  * e1000_mng_write_dhcp_info_generic - Writes DHCP info to host interface
192  * @hw: pointer to the HW structure
193  * @buffer: pointer to the host interface
194  * @length: size of the buffer
195  *
196  * Writes the DHCP information to the host interface.
197  */
198 s32
199 e1000_mng_write_dhcp_info_generic(struct e1000_hw *hw, u8 *buffer,
200     u16 length)
201 {
202 	struct e1000_host_mng_command_header hdr;
203 	s32 ret_val;
204 	u32 hicr;
205 
206 	DEBUGFUNC("e1000_mng_write_dhcp_info_generic");
207 
208 	hdr.command_id = E1000_MNG_DHCP_TX_PAYLOAD_CMD;
209 	hdr.command_length = length;
210 	hdr.reserved1 = 0;
211 	hdr.reserved2 = 0;
212 	hdr.checksum = 0;
213 
214 	/* Enable the host interface */
215 	ret_val = e1000_mng_enable_host_if(hw);
216 	if (ret_val)
217 		goto out;
218 
219 	/* Populate the host interface with the contents of "buffer". */
220 	ret_val = e1000_mng_host_if_write(hw, buffer, length,
221 	    sizeof (hdr), &(hdr.checksum));
222 	if (ret_val)
223 		goto out;
224 
225 	/* Write the manageability command header */
226 	ret_val = e1000_mng_write_cmd_header(hw, &hdr);
227 	if (ret_val)
228 		goto out;
229 
230 	/* Tell the ARC a new command is pending. */
231 	hicr = E1000_READ_REG(hw, E1000_HICR);
232 	E1000_WRITE_REG(hw, E1000_HICR, hicr | E1000_HICR_C);
233 
234 out:
235 	return (ret_val);
236 }
237 
238 /*
239  * e1000_mng_write_cmd_header_generic - Writes manageability command header
240  * @hw: pointer to the HW structure
241  * @hdr: pointer to the host interface command header
242  *
243  * Writes the command header after does the checksum calculation.
244  */
245 s32
246 e1000_mng_write_cmd_header_generic(struct e1000_hw *hw,
247     struct e1000_host_mng_command_header *hdr)
248 {
249 	u16 i, length = sizeof (struct e1000_host_mng_command_header);
250 
251 	DEBUGFUNC("e1000_mng_write_cmd_header_generic");
252 
253 	/* Write the whole command header structure with new checksum. */
254 
255 	hdr->checksum = e1000_calculate_checksum((u8 *)hdr, length);
256 
257 	length >>= 2;
258 	/* Write the relevant command block into the ram area. */
259 	for (i = 0; i < length; i++) {
260 		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, i,
261 		    *((u32 *) hdr + i));
262 		E1000_WRITE_FLUSH(hw);
263 	}
264 
265 	return (E1000_SUCCESS);
266 }
267 
268 /*
269  * e1000_mng_host_if_write_generic - Writes to the manageability host interface
270  * @hw: pointer to the HW structure
271  * @buffer: pointer to the host interface buffer
272  * @length: size of the buffer
273  * @offset: location in the buffer to write to
274  * @sum: sum of the data (not checksum)
275  *
276  * This function writes the buffer content at the offset given on the host if.
277  * It also does alignment considerations to do the writes in most efficient
278  * way.  Also fills up the sum of the buffer in *buffer parameter.
279  */
280 s32
281 e1000_mng_host_if_write_generic(struct e1000_hw *hw, u8 *buffer,
282     u16 length, u16 offset, u8 *sum)
283 {
284 	u8 *tmp;
285 	u8 *bufptr = buffer;
286 	u32 data = 0;
287 	s32 ret_val = E1000_SUCCESS;
288 	u16 remaining, i, j, prev_bytes;
289 
290 	DEBUGFUNC("e1000_mng_host_if_write_generic");
291 
292 	/* sum = only sum of the data and it is not checksum */
293 
294 	if (length == 0 || offset + length > E1000_HI_MAX_MNG_DATA_LENGTH) {
295 		ret_val = -E1000_ERR_PARAM;
296 		goto out;
297 	}
298 
299 	tmp = (u8 *)&data;
300 	prev_bytes = offset & 0x3;
301 	offset >>= 2;
302 
303 	if (prev_bytes) {
304 		data = E1000_READ_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset);
305 		for (j = prev_bytes; j < sizeof (u32); j++) {
306 			*(tmp + j) = *bufptr++;
307 			*sum += *(tmp + j);
308 		}
309 		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset, data);
310 		length -= j - prev_bytes;
311 		offset++;
312 	}
313 
314 	remaining = length & 0x3;
315 	length -= remaining;
316 
317 	/* Calculate length in DWORDs */
318 	length >>= 2;
319 
320 	/*
321 	 * The device driver writes the relevant command block into the ram
322 	 * area.
323 	 */
324 	for (i = 0; i < length; i++) {
325 		for (j = 0; j < sizeof (u32); j++) {
326 			*(tmp + j) = *bufptr++;
327 			*sum += *(tmp + j);
328 		}
329 
330 		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF,
331 		    offset + i, data);
332 	}
333 	if (remaining) {
334 		for (j = 0; j < sizeof (u32); j++) {
335 			if (j < remaining)
336 				*(tmp + j) = *bufptr++;
337 			else
338 				*(tmp + j) = 0;
339 
340 			*sum += *(tmp + j);
341 		}
342 		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF,
343 		    offset + i, data);
344 	}
345 out:
346 	return (ret_val);
347 }
348 
349 /*
350  * e1000_enable_mng_pass_thru - Enable processing of ARP's
351  * @hw: pointer to the HW structure
352  *
353  * Verifies the hardware needs to allow ARPs to be processed by the host.
354  */
355 boolean_t
356 e1000_enable_mng_pass_thru(struct e1000_hw *hw)
357 {
358 	u32 manc;
359 	u32 fwsm, factps;
360 	boolean_t ret_val = FALSE;
361 
362 	DEBUGFUNC("e1000_enable_mng_pass_thru");
363 
364 	if (!hw->mac.asf_firmware_present)
365 		goto out;
366 
367 	manc = E1000_READ_REG(hw, E1000_MANC);
368 
369 	if (!(manc & E1000_MANC_RCV_TCO_EN) ||
370 	    !(manc & E1000_MANC_EN_MAC_ADDR_FILTER))
371 		goto out;
372 
373 	if (hw->mac.arc_subsystem_valid) {
374 		fwsm = E1000_READ_REG(hw, E1000_FWSM);
375 		factps = E1000_READ_REG(hw, E1000_FACTPS);
376 
377 		if (!(factps & E1000_FACTPS_MNGCG) &&
378 		    ((fwsm & E1000_FWSM_MODE_MASK) ==
379 		    (e1000_mng_mode_pt << E1000_FWSM_MODE_SHIFT))) {
380 			ret_val = TRUE;
381 			goto out;
382 		}
383 	} else {
384 		if ((manc & E1000_MANC_SMBUS_EN) &&
385 		    !(manc & E1000_MANC_ASF_EN)) {
386 			ret_val = TRUE;
387 			goto out;
388 		}
389 	}
390 
391 out:
392 	return (ret_val);
393 }
394