1/*
2 * Copyright (c) 2007-2011, ETH Zurich.
3 * All rights reserved.
4 *
5 * This file is distributed under the terms in the attached LICENSE file.
6 * If you do not find this file, copies can be found by writing to:
7 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
8 */
9
10#include <stdbool.h>
11#include <stdio.h>
12
13#include <barrelfish/barrelfish.h>
14
15#include "sleep.h"
16#include "e10k.h"
17
18//#define DEBUG(x...) printf("e10k: " x)
19#define DEBUG(x...) do {} while (0)
20
21
22/** Acquire SWFW semaphore */
23static bool e10k_swfwsem_acquire(e10k_t* d)
24{
25    while (e10k_swsm_smbi_rdf(d) != 0); // TODO: Timeout
26    e10k_swsm_swesmbi_wrf(d, 1);
27    while (e10k_swsm_swesmbi_rdf(d) == 0); // TODO: Timeout
28    return true;
29}
30
31/** Release SWFW semaphore */
32static void e10k_swfwsem_release(e10k_t* d)
33{
34    e10k_swsm_swesmbi_wrf(d, 0);
35    e10k_swsm_smbi_wrf(d, 0);
36}
37
38
39static bool e10k_swfwlock_phy(e10k_t* d)
40{
41    bool good = false;
42
43    // See 10.5.4
44again:
45    if (!e10k_swfwsem_acquire(d)) {
46        return false;
47    }
48
49    if ((e10k_status_lan_id_rdf(d) == 0) &&
50        (e10k_swfw_sync_sw_physm0_rdf(d) == 0) &&
51        (e10k_swfw_sync_fw_physm0_rdf(d) == 0))
52    {
53        e10k_swfw_sync_sw_physm0_wrf(d, 1);
54        good = true;
55    } else if ((e10k_swfw_sync_sw_physm1_rdf(d) == 0) &&
56        (e10k_swfw_sync_fw_physm1_rdf(d) == 0))
57    {
58        e10k_swfw_sync_sw_physm1_wrf(d, 1);
59        good = true;
60    }
61    e10k_swfwsem_release(d);
62
63    if (!good) {
64        DEBUG("Failed, try again\n");
65        milli_sleep(20);
66        goto again;
67    }
68
69    return true;
70}
71
72static bool e10k_swfwunlock_phy(e10k_t* d)
73{
74    if (!e10k_swfwsem_acquire(d)) {
75        return false;
76    }
77
78    if (e10k_status_lan_id_rdf(d) == 0) {
79        e10k_swfw_sync_sw_physm0_wrf(d, 0);
80    } else {
81        e10k_swfw_sync_sw_physm1_wrf(d, 0);
82    }
83
84    e10k_swfwsem_release(d);
85
86    // Technically this is only necessary in the case that the semaphore is
87    // acquired again.
88    milli_sleep(10);
89    return true;
90}
91
92#if 0
93static bool e10k_mdi_command(uint16_t mdi, uint8_t dev, uint8_t phy,
94    e10k_mdi_opcode_t op)
95{
96    e10k_msca_t msca = e10k_msca_default;
97
98    msca = e10k_msca_mdiadd_insert(msca, mdi);
99    msca = e10k_msca_devadd_insert(msca, dev);
100    msca = e10k_msca_phyadd_insert(msca, phy);
101    msca = e10k_msca_opcode_insert(msca, op);
102    msca = e10k_msca_stcode_insert(msca, e10k_new_proto);
103    msca = e10k_msca_mdicmd_insert(msca, 1);
104
105
106    // Issue command
107    e10k_msca_wr(d, msca);
108
109    // Wait for completion
110    while (e10k_msca_mdicmd_rdf(d) != 0); // TODO: Timeout
111
112    return true;
113}
114
115static bool e10k_phy_readreg(uint16_t mdi, uint8_t dev, uint8_t phy,
116    uint16_t* value)
117{
118    bool success = true;
119
120    if (!e10k_swfwlock_phy()) {
121        return false;
122    }
123
124    if (!e10k_mdi_command(mdi, dev, phy, e10k_addr_cycle)) {
125        success = false;
126        goto out;
127    }
128
129    if (!e10k_mdi_command(mdi, dev, phy, e10k_read_op)) {
130        success = false;
131        goto out;
132    }
133    *value = e10k_msrwd_mdirddata_rdf(d);
134
135out:
136    e10k_swfwunlock_phy();
137    return success;
138}
139
140static bool e10k_phy_writereg(uint16_t mdi, uint8_t dev, uint8_t phy,
141    uint16_t value)
142{
143    bool success = true;
144
145    if (!e10k_swfwlock_phy()) {
146        return false;
147    }
148
149    if (!e10k_mdi_command(mdi, dev, phy, e10k_addr_cycle)) {
150        success = false;
151        goto out;
152    }
153
154    e10k_msrwd_mdiwrdata_wrf(d, value);
155    if (!e10k_mdi_command(mdi, dev, phy, e10k_read_op)) {
156        success = false;
157        goto out;
158    }
159
160out:
161    e10k_swfwunlock_phy();
162    return success;
163}
164
165static bool e10k_phy_validate_address(uint8_t phy)
166{
167    bool success;
168    uint16_t value;
169    uint16_t v;
170
171    /* IXGBE_MDIO_PHY_ID_HIGH */ /* IXGBE_MDIO_PMA_PMD_DEV_TYPE */
172    success = e10k_phy_readreg(0x2, 0x1, phy, &value);
173    if (!success) {
174        DEBUG("Error reading\n");
175    }
176
177    uint8_t i;
178
179    for (i = 0; i < 32; i++) {
180        e10k_phy_readreg(i, 0x1, phy, &v);
181        DEBUG("    [%x][%x] %x\n", phy, i, v);
182    }
183
184    return success && (value != 0xFFFF) && (value != 0x0);
185}
186
187static bool e10k_phy_read_id(uint8_t phy, uint16_t* id)
188{
189    /* IXGBE_MDIO_PHY_ID_HIGH */ /* IXGBE_MDIO_PMA_PMD_DEV_TYPE */
190    return e10k_phy_readreg(0x2, 0x1, phy, id);
191}
192
193static bool e10k_phy_identify(void)
194{
195    uint8_t i;
196    uint16_t id;
197    for (i = 0; i < 32; i++) {
198        if (e10k_phy_validate_address(i)) {
199            if (!e10k_phy_read_id(i, &id)) {
200                return false;
201            }
202            DEBUG("Found PHY addr=%x id=%x\n", i, id);
203            return true;
204        }
205    }
206    return false;
207}
208#endif
209
210static uint16_t e10k_eeprom_read(e10k_t* d, uint16_t offset)
211{
212    e10k_eerd_t eerd = e10k_eerd_default;
213
214    eerd = e10k_eerd_start_insert(eerd, 1);
215    eerd = e10k_eerd_addr_insert(eerd, offset);
216    e10k_eerd_wr(d, eerd);
217
218    while (e10k_eerd_done_rdf(d) == 0); // TODO: Timeout
219
220    return e10k_eerd_data_rdf(d);
221}
222
223void e10k_phy_init(e10k_t* d)
224{
225    /* IXGBE_PHY_INIT_OFFSET_NL */
226    uint16_t list_offset;
227    uint16_t data_offset = 0x0;
228    uint16_t data_value;
229    uint16_t sfp_id;
230    uint16_t sfp_type = 0x4; /* SPF_DA_CORE1 */
231    e10k_autoc_t autoc;
232
233    list_offset = e10k_eeprom_read(d, 0x002B);
234    DEBUG("list_offset=%x\n", list_offset);
235    if ((list_offset == 0x0) || (list_offset == 0xFFFF)) {
236        return;
237    }
238
239    list_offset++;
240
241    sfp_id = e10k_eeprom_read(d, list_offset);
242    DEBUG("sfp_id = %x\n", sfp_id);
243    while (sfp_id != 0xFFFF) {
244        if (sfp_id == sfp_type) {
245            list_offset++;
246            data_offset = e10k_eeprom_read(d, list_offset);
247            if ((data_offset == 0x0) || (data_offset == 0xFFFF)) {
248                DEBUG("sfp init failed\n");
249                return;
250            } else {
251                break;
252            }
253        } else {
254            list_offset += 2;
255            sfp_id = e10k_eeprom_read(d, list_offset);
256        }
257        list_offset++;
258    }
259
260    if (sfp_id == 0xFFFF) {
261        DEBUG("sfp init failed\n");
262        return;
263    }
264
265    DEBUG("data_offset=%x\n", data_offset);
266
267    e10k_swfwlock_phy(d);
268    data_value = e10k_eeprom_read(d, ++data_offset);
269    while (data_value != 0xFFFF) {
270        DEBUG(" v=%x\n", data_value);
271        e10k_corectl_wr(d, data_value);
272        data_value = e10k_eeprom_read(d, ++data_offset);
273    }
274    e10k_swfwunlock_phy(d);
275
276    milli_sleep(50);
277
278
279    autoc = e10k_autoc_rd(d);
280    autoc = e10k_autoc_lms_insert(autoc, 0x0);
281    autoc = e10k_autoc_restart_an_insert(autoc, 1);
282    e10k_autoc_wr(d, autoc);
283    while (e10k_anlp1_anas_rdf(d) != 0); // TODO: Timeout
284
285
286    autoc = e10k_autoc_rd(d);
287    autoc = e10k_autoc_lms_insert(autoc, e10k_l10g_sfi);
288    autoc = e10k_autoc_restart_an_insert(autoc, 1);
289    e10k_autoc_wr(d, autoc);
290    while (e10k_autoc_restart_an_rdf(d) != 0); // TODO: Timeout
291
292    DEBUG("PHY init done\n");
293}
294
295
296