]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/dev/e1000/e1000_manage.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sys / dev / e1000 / e1000_manage.c
1 /******************************************************************************
2
3   Copyright (c) 2001-2008, 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,
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
173          * the cookie area isn't considered valid, in which case we
174          * take the safe route 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 e1000_mng_write_dhcp_info_generic(struct e1000_hw *hw, u8 *buffer,
199                                       u16 length)
200 {
201         struct e1000_host_mng_command_header hdr;
202         s32 ret_val;
203         u32 hicr;
204
205         DEBUGFUNC("e1000_mng_write_dhcp_info_generic");
206
207         hdr.command_id = E1000_MNG_DHCP_TX_PAYLOAD_CMD;
208         hdr.command_length = length;
209         hdr.reserved1 = 0;
210         hdr.reserved2 = 0;
211         hdr.checksum = 0;
212
213         /* Enable the host interface */
214         ret_val = hw->mac.ops.mng_enable_host_if(hw);
215         if (ret_val)
216                 goto out;
217
218         /* Populate the host interface with the contents of "buffer". */
219         ret_val = hw->mac.ops.mng_host_if_write(hw, buffer, length,
220                                           sizeof(hdr), &(hdr.checksum));
221         if (ret_val)
222                 goto out;
223
224         /* Write the manageability command header */
225         ret_val = hw->mac.ops.mng_write_cmd_header(hw, &hdr);
226         if (ret_val)
227                 goto out;
228
229         /* Tell the ARC a new command is pending. */
230         hicr = E1000_READ_REG(hw, E1000_HICR);
231         E1000_WRITE_REG(hw, E1000_HICR, hicr | E1000_HICR_C);
232
233 out:
234         return ret_val;
235 }
236
237 /**
238  *  e1000_mng_write_cmd_header_generic - Writes manageability command header
239  *  @hw: pointer to the HW structure
240  *  @hdr: pointer to the host interface command header
241  *
242  *  Writes the command header after does the checksum calculation.
243  **/
244 s32 e1000_mng_write_cmd_header_generic(struct e1000_hw *hw,
245                                     struct e1000_host_mng_command_header *hdr)
246 {
247         u16 i, length = sizeof(struct e1000_host_mng_command_header);
248
249         DEBUGFUNC("e1000_mng_write_cmd_header_generic");
250
251         /* Write the whole command header structure with new checksum. */
252
253         hdr->checksum = e1000_calculate_checksum((u8 *)hdr, length);
254
255         length >>= 2;
256         /* Write the relevant command block into the ram area. */
257         for (i = 0; i < length; i++) {
258                 E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, i,
259                                             *((u32 *) hdr + i));
260                 E1000_WRITE_FLUSH(hw);
261         }
262
263         return E1000_SUCCESS;
264 }
265
266 /**
267  *  e1000_mng_host_if_write_generic - Write to the manageability host interface
268  *  @hw: pointer to the HW structure
269  *  @buffer: pointer to the host interface buffer
270  *  @length: size of the buffer
271  *  @offset: location in the buffer to write to
272  *  @sum: sum of the data (not checksum)
273  *
274  *  This function writes the buffer content at the offset given on the host if.
275  *  It also does alignment considerations to do the writes in most efficient
276  *  way.  Also fills up the sum of the buffer in *buffer parameter.
277  **/
278 s32 e1000_mng_host_if_write_generic(struct e1000_hw *hw, u8 *buffer,
279                                     u16 length, u16 offset, u8 *sum)
280 {
281         u8 *tmp;
282         u8 *bufptr = buffer;
283         u32 data = 0;
284         s32 ret_val = E1000_SUCCESS;
285         u16 remaining, i, j, prev_bytes;
286
287         DEBUGFUNC("e1000_mng_host_if_write_generic");
288
289         /* sum = only sum of the data and it is not checksum */
290
291         if (length == 0 || offset + length > E1000_HI_MAX_MNG_DATA_LENGTH) {
292                 ret_val = -E1000_ERR_PARAM;
293                 goto out;
294         }
295
296         tmp = (u8 *)&data;
297         prev_bytes = offset & 0x3;
298         offset >>= 2;
299
300         if (prev_bytes) {
301                 data = E1000_READ_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset);
302                 for (j = prev_bytes; j < sizeof(u32); j++) {
303                         *(tmp + j) = *bufptr++;
304                         *sum += *(tmp + j);
305                 }
306                 E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset, data);
307                 length -= j - prev_bytes;
308                 offset++;
309         }
310
311         remaining = length & 0x3;
312         length -= remaining;
313
314         /* Calculate length in DWORDs */
315         length >>= 2;
316
317         /*
318          * The device driver writes the relevant command block into the
319          * ram area.
320          */
321         for (i = 0; i < length; i++) {
322                 for (j = 0; j < sizeof(u32); j++) {
323                         *(tmp + j) = *bufptr++;
324                         *sum += *(tmp + j);
325                 }
326
327                 E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset + i,
328                                             data);
329         }
330         if (remaining) {
331                 for (j = 0; j < sizeof(u32); j++) {
332                         if (j < remaining)
333                                 *(tmp + j) = *bufptr++;
334                         else
335                                 *(tmp + j) = 0;
336
337                         *sum += *(tmp + j);
338                 }
339                 E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset + i, data);
340         }
341
342 out:
343         return ret_val;
344 }
345
346 /**
347  *  e1000_enable_mng_pass_thru - Enable processing of ARP's
348  *  @hw: pointer to the HW structure
349  *
350  *  Verifies the hardware needs to allow ARPs to be processed by the host.
351  **/
352 bool e1000_enable_mng_pass_thru(struct e1000_hw *hw)
353 {
354         u32 manc;
355         u32 fwsm, factps;
356         bool ret_val = FALSE;
357
358         DEBUGFUNC("e1000_enable_mng_pass_thru");
359
360         if (!hw->mac.asf_firmware_present)
361                 goto out;
362
363         manc = E1000_READ_REG(hw, E1000_MANC);
364
365         if (!(manc & E1000_MANC_RCV_TCO_EN) ||
366             !(manc & E1000_MANC_EN_MAC_ADDR_FILTER))
367                 goto out;
368
369         if (hw->mac.arc_subsystem_valid) {
370                 fwsm = E1000_READ_REG(hw, E1000_FWSM);
371                 factps = E1000_READ_REG(hw, E1000_FACTPS);
372
373                 if (!(factps & E1000_FACTPS_MNGCG) &&
374                     ((fwsm & E1000_FWSM_MODE_MASK) ==
375                      (e1000_mng_mode_pt << E1000_FWSM_MODE_SHIFT))) {
376                         ret_val = TRUE;
377                         goto out;
378                 }
379         } else {
380                 if ((manc & E1000_MANC_SMBUS_EN) &&
381                     !(manc & E1000_MANC_ASF_EN)) {
382                         ret_val = TRUE;
383                         goto out;
384                 }
385         }
386
387 out:
388         return ret_val;
389 }
390