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