xref: /freebsd/sys/dev/e1000/e1000_manage.c (revision eb6d21b4ca6d668cf89afd99eef7baeafa712197)
1 /******************************************************************************
2 
3   Copyright (c) 2001-2009, 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 static u8 e1000_calculate_checksum(u8 *buffer, u32 length);
38 
39 /**
40  *  e1000_calculate_checksum - Calculate checksum for buffer
41  *  @buffer: pointer to EEPROM
42  *  @length: size of EEPROM to calculate a checksum for
43  *
44  *  Calculates the checksum for some buffer on a specified length.  The
45  *  checksum calculated is returned.
46  **/
47 static u8 e1000_calculate_checksum(u8 *buffer, u32 length)
48 {
49 	u32 i;
50 	u8  sum = 0;
51 
52 	DEBUGFUNC("e1000_calculate_checksum");
53 
54 	if (!buffer)
55 		return 0;
56 
57 	for (i = 0; i < length; i++)
58 		sum += buffer[i];
59 
60 	return (u8) (0 - sum);
61 }
62 
63 /**
64  *  e1000_mng_enable_host_if_generic - Checks host interface is enabled
65  *  @hw: pointer to the HW structure
66  *
67  *  Returns E1000_success upon success, else E1000_ERR_HOST_INTERFACE_COMMAND
68  *
69  *  This function checks whether the HOST IF is enabled for command operation
70  *  and also checks whether the previous command is completed.  It busy waits
71  *  in case of previous command is not completed.
72  **/
73 s32 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 
102 out:
103 	return ret_val;
104 }
105 
106 /**
107  *  e1000_check_mng_mode_generic - Generic check management mode
108  *  @hw: pointer to the HW structure
109  *
110  *  Reads the firmware semaphore register and returns TRUE (>0) if
111  *  manageability is enabled, else FALSE (0).
112  **/
113 bool 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 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 	bool tx_filter = TRUE;
140 
141 	DEBUGFUNC("e1000_enable_tx_pkt_filtering_generic");
142 
143 	/* No manageability, no filtering */
144 	if (!hw->mac.ops.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
151 	 * reason, disable filtering.
152 	 */
153 	ret_val = hw->mac.ops.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, E1000_HOST_IF,
164 		                                           offset + i);
165 	hdr_csum = hdr->checksum;
166 	hdr->checksum = 0;
167 	csum = e1000_calculate_checksum((u8 *)hdr,
168 	                                E1000_MNG_DHCP_COOKIE_LENGTH);
169 	/*
170 	 * If either the checksums or signature don't match, then
171 	 * the cookie area isn't considered valid, in which case we
172 	 * take the safe route of assuming Tx filtering is enabled.
173 	 */
174 	if (hdr_csum != csum)
175 		goto out;
176 	if (hdr->signature != E1000_IAMT_SIGNATURE)
177 		goto out;
178 
179 	/* Cookie area is valid, make the final check for filtering. */
180 	if (!(hdr->status & E1000_MNG_DHCP_COOKIE_STATUS_PARSING))
181 		tx_filter = FALSE;
182 
183 out:
184 	hw->mac.tx_pkt_filtering = tx_filter;
185 	return tx_filter;
186 }
187 
188 /**
189  *  e1000_mng_write_dhcp_info_generic - Writes DHCP info to host interface
190  *  @hw: pointer to the HW structure
191  *  @buffer: pointer to the host interface
192  *  @length: size of the buffer
193  *
194  *  Writes the DHCP information to the host interface.
195  **/
196 s32 e1000_mng_write_dhcp_info_generic(struct e1000_hw *hw, u8 *buffer,
197                                       u16 length)
198 {
199 	struct e1000_host_mng_command_header hdr;
200 	s32 ret_val;
201 	u32 hicr;
202 
203 	DEBUGFUNC("e1000_mng_write_dhcp_info_generic");
204 
205 	hdr.command_id = E1000_MNG_DHCP_TX_PAYLOAD_CMD;
206 	hdr.command_length = length;
207 	hdr.reserved1 = 0;
208 	hdr.reserved2 = 0;
209 	hdr.checksum = 0;
210 
211 	/* Enable the host interface */
212 	ret_val = hw->mac.ops.mng_enable_host_if(hw);
213 	if (ret_val)
214 		goto out;
215 
216 	/* Populate the host interface with the contents of "buffer". */
217 	ret_val = hw->mac.ops.mng_host_if_write(hw, buffer, length,
218 	                                  sizeof(hdr), &(hdr.checksum));
219 	if (ret_val)
220 		goto out;
221 
222 	/* Write the manageability command header */
223 	ret_val = hw->mac.ops.mng_write_cmd_header(hw, &hdr);
224 	if (ret_val)
225 		goto out;
226 
227 	/* Tell the ARC a new command is pending. */
228 	hicr = E1000_READ_REG(hw, E1000_HICR);
229 	E1000_WRITE_REG(hw, E1000_HICR, hicr | E1000_HICR_C);
230 
231 out:
232 	return ret_val;
233 }
234 
235 /**
236  *  e1000_mng_write_cmd_header_generic - Writes manageability command header
237  *  @hw: pointer to the HW structure
238  *  @hdr: pointer to the host interface command header
239  *
240  *  Writes the command header after does the checksum calculation.
241  **/
242 s32 e1000_mng_write_cmd_header_generic(struct e1000_hw *hw,
243                                     struct e1000_host_mng_command_header *hdr)
244 {
245 	u16 i, length = sizeof(struct e1000_host_mng_command_header);
246 
247 	DEBUGFUNC("e1000_mng_write_cmd_header_generic");
248 
249 	/* Write the whole command header structure with new checksum. */
250 
251 	hdr->checksum = e1000_calculate_checksum((u8 *)hdr, length);
252 
253 	length >>= 2;
254 	/* Write the relevant command block into the ram area. */
255 	for (i = 0; i < length; i++) {
256 		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, i,
257 		                            *((u32 *) hdr + i));
258 		E1000_WRITE_FLUSH(hw);
259 	}
260 
261 	return E1000_SUCCESS;
262 }
263 
264 /**
265  *  e1000_mng_host_if_write_generic - Write to the manageability host interface
266  *  @hw: pointer to the HW structure
267  *  @buffer: pointer to the host interface buffer
268  *  @length: size of the buffer
269  *  @offset: location in the buffer to write to
270  *  @sum: sum of the data (not checksum)
271  *
272  *  This function writes the buffer content at the offset given on the host if.
273  *  It also does alignment considerations to do the writes in most efficient
274  *  way.  Also fills up the sum of the buffer in *buffer parameter.
275  **/
276 s32 e1000_mng_host_if_write_generic(struct e1000_hw *hw, u8 *buffer,
277                                     u16 length, u16 offset, u8 *sum)
278 {
279 	u8 *tmp;
280 	u8 *bufptr = buffer;
281 	u32 data = 0;
282 	s32 ret_val = E1000_SUCCESS;
283 	u16 remaining, i, j, prev_bytes;
284 
285 	DEBUGFUNC("e1000_mng_host_if_write_generic");
286 
287 	/* sum = only sum of the data and it is not checksum */
288 
289 	if (length == 0 || offset + length > E1000_HI_MAX_MNG_DATA_LENGTH) {
290 		ret_val = -E1000_ERR_PARAM;
291 		goto out;
292 	}
293 
294 	tmp = (u8 *)&data;
295 	prev_bytes = offset & 0x3;
296 	offset >>= 2;
297 
298 	if (prev_bytes) {
299 		data = E1000_READ_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset);
300 		for (j = prev_bytes; j < sizeof(u32); j++) {
301 			*(tmp + j) = *bufptr++;
302 			*sum += *(tmp + j);
303 		}
304 		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset, data);
305 		length -= j - prev_bytes;
306 		offset++;
307 	}
308 
309 	remaining = length & 0x3;
310 	length -= remaining;
311 
312 	/* Calculate length in DWORDs */
313 	length >>= 2;
314 
315 	/*
316 	 * The device driver writes the relevant command block into the
317 	 * ram area.
318 	 */
319 	for (i = 0; i < length; i++) {
320 		for (j = 0; j < sizeof(u32); j++) {
321 			*(tmp + j) = *bufptr++;
322 			*sum += *(tmp + j);
323 		}
324 
325 		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset + i,
326 		                            data);
327 	}
328 	if (remaining) {
329 		for (j = 0; j < sizeof(u32); j++) {
330 			if (j < remaining)
331 				*(tmp + j) = *bufptr++;
332 			else
333 				*(tmp + j) = 0;
334 
335 			*sum += *(tmp + j);
336 		}
337 		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset + i, data);
338 	}
339 
340 out:
341 	return ret_val;
342 }
343 
344 /**
345  *  e1000_enable_mng_pass_thru - Enable processing of ARP's
346  *  @hw: pointer to the HW structure
347  *
348  *  Verifies the hardware needs to allow ARPs to be processed by the host.
349  **/
350 bool e1000_enable_mng_pass_thru(struct e1000_hw *hw)
351 {
352 	u32 manc;
353 	u32 fwsm, factps;
354 	bool ret_val = FALSE;
355 
356 	DEBUGFUNC("e1000_enable_mng_pass_thru");
357 
358 	if (!hw->mac.asf_firmware_present)
359 		goto out;
360 
361 	manc = E1000_READ_REG(hw, E1000_MANC);
362 
363 	if (!(manc & E1000_MANC_RCV_TCO_EN) ||
364 	    !(manc & E1000_MANC_EN_MAC_ADDR_FILTER))
365 		goto out;
366 
367 	if (hw->mac.arc_subsystem_valid) {
368 		fwsm = E1000_READ_REG(hw, E1000_FWSM);
369 		factps = E1000_READ_REG(hw, E1000_FACTPS);
370 
371 		if (!(factps & E1000_FACTPS_MNGCG) &&
372 		    ((fwsm & E1000_FWSM_MODE_MASK) ==
373 		     (e1000_mng_mode_pt << E1000_FWSM_MODE_SHIFT))) {
374 			ret_val = TRUE;
375 			goto out;
376 		}
377 	} else {
378 		if ((manc & E1000_MANC_SMBUS_EN) &&
379 		    !(manc & E1000_MANC_ASF_EN)) {
380 			ret_val = TRUE;
381 			goto out;
382 		}
383 	}
384 
385 out:
386 	return ret_val;
387 }
388 
389