]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/sfxge/sfxge_mcdi.c
Update compiler-rt to trunk r228651. This enables using Address
[FreeBSD/FreeBSD.git] / sys / dev / sfxge / sfxge_mcdi.c
1 /*-
2  * Copyright (c) 2010-2011 Solarflare Communications, Inc.
3  * All rights reserved.
4  *
5  * This software was developed in part by Philip Paeps under contract for
6  * Solarflare Communications, Inc.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include <sys/param.h>
34 #include <sys/condvar.h>
35 #include <sys/lock.h>
36 #include <sys/mutex.h>
37 #include <sys/proc.h>
38 #include <sys/syslog.h>
39 #include <sys/taskqueue.h>
40
41 #include "common/efx.h"
42 #include "common/efx_mcdi.h"
43 #include "common/efx_regs_mcdi.h"
44
45 #include "sfxge.h"
46
47 #define SFXGE_MCDI_POLL_INTERVAL_MIN 10         /* 10us in 1us units */
48 #define SFXGE_MCDI_POLL_INTERVAL_MAX 100000     /* 100ms in 1us units */
49 #define SFXGE_MCDI_WATCHDOG_INTERVAL 10000000   /* 10s in 1us units */
50
51 /* Acquire exclusive access to MCDI for the duration of a request. */
52 static void
53 sfxge_mcdi_acquire(struct sfxge_mcdi *mcdi)
54 {
55         SFXGE_MCDI_LOCK(mcdi);
56         KASSERT(mcdi->state != SFXGE_MCDI_UNINITIALIZED,
57             ("MCDI not initialized"));
58
59         while (mcdi->state != SFXGE_MCDI_INITIALIZED)
60                 (void)cv_wait_sig(&mcdi->cv, &mcdi->lock);
61         mcdi->state = SFXGE_MCDI_BUSY;
62
63         SFXGE_MCDI_UNLOCK(mcdi);
64 }
65
66 /* Release ownership of MCDI on request completion. */
67 static void
68 sfxge_mcdi_release(struct sfxge_mcdi *mcdi)
69 {
70         SFXGE_MCDI_LOCK(mcdi);
71         KASSERT((mcdi->state == SFXGE_MCDI_BUSY ||
72             mcdi->state == SFXGE_MCDI_COMPLETED),
73             ("MCDI not busy or task not completed"));
74
75         mcdi->state = SFXGE_MCDI_INITIALIZED;
76         cv_broadcast(&mcdi->cv);
77
78         SFXGE_MCDI_UNLOCK(mcdi);
79 }
80
81 static void
82 sfxge_mcdi_timeout(struct sfxge_softc *sc)
83 {
84         device_t dev = sc->dev;
85
86         log(LOG_WARNING, "[%s%d] MC_TIMEOUT", device_get_name(dev),
87                 device_get_unit(dev));
88
89         EFSYS_PROBE(mcdi_timeout);
90         sfxge_schedule_reset(sc);
91 }
92
93 static void
94 sfxge_mcdi_poll(struct sfxge_softc *sc)
95 {
96         efx_nic_t *enp;
97         clock_t delay_total;
98         clock_t delay_us;
99         boolean_t aborted;
100
101         delay_total = 0;
102         delay_us = SFXGE_MCDI_POLL_INTERVAL_MIN;
103         enp = sc->enp;
104
105         do {
106                 if (efx_mcdi_request_poll(enp)) {
107                         EFSYS_PROBE1(mcdi_delay, clock_t, delay_total);
108                         return;
109                 }
110
111                 if (delay_total > SFXGE_MCDI_WATCHDOG_INTERVAL) {
112                         aborted = efx_mcdi_request_abort(enp);
113                         KASSERT(aborted, ("abort failed"));
114                         sfxge_mcdi_timeout(sc);
115                         return;
116                 }
117
118                 /* Spin or block depending on delay interval. */
119                 if (delay_us < 1000000)
120                         DELAY(delay_us);
121                 else
122                         pause("mcdi wait", delay_us * hz / 1000000);
123
124                 delay_total += delay_us;
125
126                 /* Exponentially back off the poll frequency. */
127                 delay_us = delay_us * 2;
128                 if (delay_us > SFXGE_MCDI_POLL_INTERVAL_MAX)
129                         delay_us = SFXGE_MCDI_POLL_INTERVAL_MAX;
130
131         } while (1);
132 }
133
134 static void
135 sfxge_mcdi_execute(void *arg, efx_mcdi_req_t *emrp)
136 {
137         struct sfxge_softc *sc;
138         struct sfxge_mcdi *mcdi;
139
140         sc = (struct sfxge_softc *)arg;
141         mcdi = &sc->mcdi;
142
143         sfxge_mcdi_acquire(mcdi);
144
145         /* Issue request and poll for completion. */
146         efx_mcdi_request_start(sc->enp, emrp, B_FALSE);
147         sfxge_mcdi_poll(sc);
148
149         sfxge_mcdi_release(mcdi);
150 }
151
152 static void
153 sfxge_mcdi_ev_cpl(void *arg)
154 {
155         struct sfxge_softc *sc;
156         struct sfxge_mcdi *mcdi;
157
158         sc = (struct sfxge_softc *)arg;
159         mcdi = &sc->mcdi;
160
161         SFXGE_MCDI_LOCK(mcdi);
162         KASSERT(mcdi->state == SFXGE_MCDI_BUSY, ("MCDI not busy"));
163         mcdi->state = SFXGE_MCDI_COMPLETED;
164         cv_broadcast(&mcdi->cv);
165         SFXGE_MCDI_UNLOCK(mcdi);
166 }
167
168 static void
169 sfxge_mcdi_exception(void *arg, efx_mcdi_exception_t eme)
170 {
171         struct sfxge_softc *sc;
172         device_t dev;
173
174         sc = (struct sfxge_softc *)arg;
175         dev = sc->dev;
176
177         log(LOG_WARNING, "[%s%d] MC_%s", device_get_name(dev),
178             device_get_unit(dev),
179             (eme == EFX_MCDI_EXCEPTION_MC_REBOOT)
180             ? "REBOOT"
181             : (eme == EFX_MCDI_EXCEPTION_MC_BADASSERT)
182             ? "BADASSERT" : "UNKNOWN");
183
184         EFSYS_PROBE(mcdi_exception);
185
186         sfxge_schedule_reset(sc);
187 }
188
189 int
190 sfxge_mcdi_init(struct sfxge_softc *sc)
191 {
192         efx_nic_t *enp;
193         struct sfxge_mcdi *mcdi;
194         efx_mcdi_transport_t *emtp;
195         int rc;
196
197         enp = sc->enp;
198         mcdi = &sc->mcdi;
199         emtp = &mcdi->transport;
200
201         KASSERT(mcdi->state == SFXGE_MCDI_UNINITIALIZED,
202             ("MCDI already initialized"));
203
204         SFXGE_MCDI_LOCK_INIT(mcdi, device_get_nameunit(sc->dev));
205
206         mcdi->state = SFXGE_MCDI_INITIALIZED;
207
208         emtp->emt_context = sc;
209         emtp->emt_execute = sfxge_mcdi_execute;
210         emtp->emt_ev_cpl = sfxge_mcdi_ev_cpl;
211         emtp->emt_exception = sfxge_mcdi_exception;
212
213         cv_init(&mcdi->cv, "sfxge_mcdi");
214
215         if ((rc = efx_mcdi_init(enp, emtp)) != 0)
216                 goto fail;
217
218         return (0);
219
220 fail:
221         SFXGE_MCDI_LOCK_DESTROY(mcdi);
222         mcdi->state = SFXGE_MCDI_UNINITIALIZED;
223         return (rc);
224 }
225
226 void
227 sfxge_mcdi_fini(struct sfxge_softc *sc)
228 {
229         struct sfxge_mcdi *mcdi;
230         efx_nic_t *enp;
231         efx_mcdi_transport_t *emtp;
232
233         enp = sc->enp;
234         mcdi = &sc->mcdi;
235         emtp = &mcdi->transport;
236
237         SFXGE_MCDI_LOCK(mcdi);
238         KASSERT(mcdi->state == SFXGE_MCDI_INITIALIZED,
239             ("MCDI not initialized"));
240
241         efx_mcdi_fini(enp);
242         bzero(emtp, sizeof(*emtp));
243
244         cv_destroy(&mcdi->cv);
245         SFXGE_MCDI_UNLOCK(mcdi);
246
247         SFXGE_MCDI_LOCK_DESTROY(mcdi);
248 }