e1000 - Literally import e1000 driver from FreeBSD
[dragonfly.git] / sys / dev / netif / e1000 / e1000_manage.c
1 /******************************************************************************
2
3   Copyright (c) 2001-2010, 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 = E1000_READ_REG(hw, E1000_FWSM);
116
117         DEBUGFUNC("e1000_check_mng_mode_generic");
118
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 bool e1000_enable_tx_pkt_filtering_generic(struct e1000_hw *hw)
132 {
133         struct e1000_host_mng_dhcp_cookie *hdr = &hw->mng_cookie;
134         u32 *buffer = (u32 *)&hw->mng_cookie;
135         u32 offset;
136         s32 ret_val, hdr_csum, csum;
137         u8 i, len;
138
139         DEBUGFUNC("e1000_enable_tx_pkt_filtering_generic");
140
141         hw->mac.tx_pkt_filtering = TRUE;
142
143         /* No manageability, no filtering */
144         if (!hw->mac.ops.check_mng_mode(hw)) {
145                 hw->mac.tx_pkt_filtering = 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                 hw->mac.tx_pkt_filtering = 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) || (hdr->signature != E1000_IAMT_SIGNATURE)) {
175                 hw->mac.tx_pkt_filtering = TRUE;
176                 goto out;
177         }
178
179         /* Cookie area is valid, make the final check for filtering. */
180         if (!(hdr->status & E1000_MNG_DHCP_COOKIE_STATUS_PARSING)) {
181                 hw->mac.tx_pkt_filtering = FALSE;
182                 goto out;
183         }
184
185 out:
186         return hw->mac.tx_pkt_filtering;
187 }
188
189 /**
190  *  e1000_mng_write_dhcp_info_generic - Writes DHCP info to host interface
191  *  @hw: pointer to the HW structure
192  *  @buffer: pointer to the host interface
193  *  @length: size of the buffer
194  *
195  *  Writes the DHCP information to the host interface.
196  **/
197 s32 e1000_mng_write_dhcp_info_generic(struct e1000_hw *hw, u8 *buffer,
198                                       u16 length)
199 {
200         struct e1000_host_mng_command_header hdr;
201         s32 ret_val;
202         u32 hicr;
203
204         DEBUGFUNC("e1000_mng_write_dhcp_info_generic");
205
206         hdr.command_id = E1000_MNG_DHCP_TX_PAYLOAD_CMD;
207         hdr.command_length = length;
208         hdr.reserved1 = 0;
209         hdr.reserved2 = 0;
210         hdr.checksum = 0;
211
212         /* Enable the host interface */
213         ret_val = hw->mac.ops.mng_enable_host_if(hw);
214         if (ret_val)
215                 goto out;
216
217         /* Populate the host interface with the contents of "buffer". */
218         ret_val = hw->mac.ops.mng_host_if_write(hw, buffer, length,
219                                           sizeof(hdr), &(hdr.checksum));
220         if (ret_val)
221                 goto out;
222
223         /* Write the manageability command header */
224         ret_val = hw->mac.ops.mng_write_cmd_header(hw, &hdr);
225         if (ret_val)
226                 goto out;
227
228         /* Tell the ARC a new command is pending. */
229         hicr = E1000_READ_REG(hw, E1000_HICR);
230         E1000_WRITE_REG(hw, E1000_HICR, hicr | E1000_HICR_C);
231
232 out:
233         return ret_val;
234 }
235
236 /**
237  *  e1000_mng_write_cmd_header_generic - Writes manageability command header
238  *  @hw: pointer to the HW structure
239  *  @hdr: pointer to the host interface command header
240  *
241  *  Writes the command header after does the checksum calculation.
242  **/
243 s32 e1000_mng_write_cmd_header_generic(struct e1000_hw *hw,
244                                     struct e1000_host_mng_command_header *hdr)
245 {
246         u16 i, length = sizeof(struct e1000_host_mng_command_header);
247
248         DEBUGFUNC("e1000_mng_write_cmd_header_generic");
249
250         /* Write the whole command header structure with new checksum. */
251
252         hdr->checksum = e1000_calculate_checksum((u8 *)hdr, length);
253
254         length >>= 2;
255         /* Write the relevant command block into the ram area. */
256         for (i = 0; i < length; i++) {
257                 E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, i,
258                                             *((u32 *) hdr + i));
259                 E1000_WRITE_FLUSH(hw);
260         }
261
262         return E1000_SUCCESS;
263 }
264
265 /**
266  *  e1000_mng_host_if_write_generic - Write to the manageability host interface
267  *  @hw: pointer to the HW structure
268  *  @buffer: pointer to the host interface buffer
269  *  @length: size of the buffer
270  *  @offset: location in the buffer to write to
271  *  @sum: sum of the data (not checksum)
272  *
273  *  This function writes the buffer content at the offset given on the host if.
274  *  It also does alignment considerations to do the writes in most efficient
275  *  way.  Also fills up the sum of the buffer in *buffer parameter.
276  **/
277 s32 e1000_mng_host_if_write_generic(struct e1000_hw *hw, u8 *buffer,
278                                     u16 length, u16 offset, u8 *sum)
279 {
280         u8 *tmp;
281         u8 *bufptr = buffer;
282         u32 data = 0;
283         s32 ret_val = E1000_SUCCESS;
284         u16 remaining, i, j, prev_bytes;
285
286         DEBUGFUNC("e1000_mng_host_if_write_generic");
287
288         /* sum = only sum of the data and it is not checksum */
289
290         if (length == 0 || offset + length > E1000_HI_MAX_MNG_DATA_LENGTH) {
291                 ret_val = -E1000_ERR_PARAM;
292                 goto out;
293         }
294
295         tmp = (u8 *)&data;
296         prev_bytes = offset & 0x3;
297         offset >>= 2;
298
299         if (prev_bytes) {
300                 data = E1000_READ_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset);
301                 for (j = prev_bytes; j < sizeof(u32); j++) {
302                         *(tmp + j) = *bufptr++;
303                         *sum += *(tmp + j);
304                 }
305                 E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset, data);
306                 length -= j - prev_bytes;
307                 offset++;
308         }
309
310         remaining = length & 0x3;
311         length -= remaining;
312
313         /* Calculate length in DWORDs */
314         length >>= 2;
315
316         /*
317          * The device driver writes the relevant command block into the
318          * ram area.
319          */
320         for (i = 0; i < length; i++) {
321                 for (j = 0; j < sizeof(u32); j++) {
322                         *(tmp + j) = *bufptr++;
323                         *sum += *(tmp + j);
324                 }
325
326                 E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset + i,
327                                             data);
328         }
329         if (remaining) {
330                 for (j = 0; j < sizeof(u32); j++) {
331                         if (j < remaining)
332                                 *(tmp + j) = *bufptr++;
333                         else
334                                 *(tmp + j) = 0;
335
336                         *sum += *(tmp + j);
337                 }
338                 E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset + i, data);
339         }
340
341 out:
342         return ret_val;
343 }
344
345 /**
346  *  e1000_enable_mng_pass_thru - Check if management passthrough is needed
347  *  @hw: pointer to the HW structure
348  *
349  *  Verifies the hardware needs to leave interface enabled so that frames can
350  *  be directed to and from the management interface.
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                 goto out;
367
368         if (hw->mac.arc_subsystem_valid) {
369                 fwsm = E1000_READ_REG(hw, E1000_FWSM);
370                 factps = E1000_READ_REG(hw, E1000_FACTPS);
371
372                 if (!(factps & E1000_FACTPS_MNGCG) &&
373                     ((fwsm & E1000_FWSM_MODE_MASK) ==
374                      (e1000_mng_mode_pt << E1000_FWSM_MODE_SHIFT))) {
375                         ret_val = TRUE;
376                         goto out;
377                 }
378         } else {
379                 if ((manc & E1000_MANC_SMBUS_EN) &&
380                     !(manc & E1000_MANC_ASF_EN)) {
381                         ret_val = TRUE;
382                         goto out;
383                 }
384         }
385
386 out:
387         return ret_val;
388 }
389