diff options
author | Ben Hutchings <bhutchings@solarflare.com> | 2012-09-17 21:33:56 -0400 |
---|---|---|
committer | Ben Hutchings <bhutchings@solarflare.com> | 2013-08-21 14:43:27 -0400 |
commit | f3ad50034425692965a0f2becdd9c45ecb45cd66 (patch) | |
tree | 0ada5470ce0cc43c1589ebd619bba22716b4844f /drivers/net/ethernet/sfc/mcdi.c | |
parent | f073dde03b3e8d11050d82f52caaf75fd924e069 (diff) |
sfc: Make MCDI independent of Siena
Move the lowest layer (transport) of the current MCDI code to
per-NIC-type operations.
Introduce a new structure and efx_nic member for MCDI-specific data.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Diffstat (limited to 'drivers/net/ethernet/sfc/mcdi.c')
-rw-r--r-- | drivers/net/ethernet/sfc/mcdi.c | 87 |
1 files changed, 26 insertions, 61 deletions
diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c index 2b9ef282ae8c..d7d3a8a9cd15 100644 --- a/drivers/net/ethernet/sfc/mcdi.c +++ b/drivers/net/ethernet/sfc/mcdi.c | |||
@@ -24,13 +24,6 @@ | |||
24 | 24 | ||
25 | #define MCDI_RPC_TIMEOUT (10 * HZ) | 25 | #define MCDI_RPC_TIMEOUT (10 * HZ) |
26 | 26 | ||
27 | #define MCDI_PDU(efx) \ | ||
28 | (efx_port_num(efx) ? MC_SMEM_P1_PDU_OFST : MC_SMEM_P0_PDU_OFST) | ||
29 | #define MCDI_DOORBELL(efx) \ | ||
30 | (efx_port_num(efx) ? MC_SMEM_P1_DOORBELL_OFST : MC_SMEM_P0_DOORBELL_OFST) | ||
31 | #define MCDI_STATUS(efx) \ | ||
32 | (efx_port_num(efx) ? MC_SMEM_P1_STATUS_OFST : MC_SMEM_P0_STATUS_OFST) | ||
33 | |||
34 | /* A reboot/assertion causes the MCDI status word to be set after the | 27 | /* A reboot/assertion causes the MCDI status word to be set after the |
35 | * command word is set or a REBOOT event is sent. If we notice a reboot | 28 | * command word is set or a REBOOT event is sent. If we notice a reboot |
36 | * via these mechanisms then wait 10ms for the status word to be set. */ | 29 | * via these mechanisms then wait 10ms for the status word to be set. */ |
@@ -44,16 +37,18 @@ | |||
44 | 37 | ||
45 | static inline struct efx_mcdi_iface *efx_mcdi(struct efx_nic *efx) | 38 | static inline struct efx_mcdi_iface *efx_mcdi(struct efx_nic *efx) |
46 | { | 39 | { |
47 | struct siena_nic_data *nic_data; | 40 | EFX_BUG_ON_PARANOID(!efx->mcdi); |
48 | EFX_BUG_ON_PARANOID(efx_nic_rev(efx) < EFX_REV_SIENA_A0); | 41 | return &efx->mcdi->iface; |
49 | nic_data = efx->nic_data; | ||
50 | return &nic_data->mcdi; | ||
51 | } | 42 | } |
52 | 43 | ||
53 | int efx_mcdi_init(struct efx_nic *efx) | 44 | int efx_mcdi_init(struct efx_nic *efx) |
54 | { | 45 | { |
55 | struct efx_mcdi_iface *mcdi; | 46 | struct efx_mcdi_iface *mcdi; |
56 | 47 | ||
48 | efx->mcdi = kzalloc(sizeof(*efx->mcdi), GFP_KERNEL); | ||
49 | if (!efx->mcdi) | ||
50 | return -ENOMEM; | ||
51 | |||
57 | mcdi = efx_mcdi(efx); | 52 | mcdi = efx_mcdi(efx); |
58 | init_waitqueue_head(&mcdi->wq); | 53 | init_waitqueue_head(&mcdi->wq); |
59 | spin_lock_init(&mcdi->iface_lock); | 54 | spin_lock_init(&mcdi->iface_lock); |
@@ -66,16 +61,19 @@ int efx_mcdi_init(struct efx_nic *efx) | |||
66 | return efx_mcdi_handle_assertion(efx); | 61 | return efx_mcdi_handle_assertion(efx); |
67 | } | 62 | } |
68 | 63 | ||
64 | void efx_mcdi_fini(struct efx_nic *efx) | ||
65 | { | ||
66 | BUG_ON(efx->mcdi && | ||
67 | atomic_read(&efx->mcdi->iface.state) != MCDI_STATE_QUIESCENT); | ||
68 | kfree(efx->mcdi); | ||
69 | } | ||
70 | |||
69 | static void efx_mcdi_copyin(struct efx_nic *efx, unsigned cmd, | 71 | static void efx_mcdi_copyin(struct efx_nic *efx, unsigned cmd, |
70 | const efx_dword_t *inbuf, size_t inlen) | 72 | const efx_dword_t *inbuf, size_t inlen) |
71 | { | 73 | { |
72 | struct efx_mcdi_iface *mcdi = efx_mcdi(efx); | 74 | struct efx_mcdi_iface *mcdi = efx_mcdi(efx); |
73 | unsigned pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx); | ||
74 | unsigned doorbell = FR_CZ_MC_TREG_SMEM + MCDI_DOORBELL(efx); | ||
75 | unsigned int i; | ||
76 | efx_dword_t hdr; | 75 | efx_dword_t hdr; |
77 | u32 xflags, seqno; | 76 | u32 xflags, seqno; |
78 | unsigned int inlen_dw = DIV_ROUND_UP(inlen, 4); | ||
79 | 77 | ||
80 | BUG_ON(atomic_read(&mcdi->state) == MCDI_STATE_QUIESCENT); | 78 | BUG_ON(atomic_read(&mcdi->state) == MCDI_STATE_QUIESCENT); |
81 | BUG_ON(inlen > MCDI_CTL_SDU_LEN_MAX_V1); | 79 | BUG_ON(inlen > MCDI_CTL_SDU_LEN_MAX_V1); |
@@ -93,31 +91,18 @@ static void efx_mcdi_copyin(struct efx_nic *efx, unsigned cmd, | |||
93 | MCDI_HEADER_SEQ, seqno, | 91 | MCDI_HEADER_SEQ, seqno, |
94 | MCDI_HEADER_XFLAGS, xflags); | 92 | MCDI_HEADER_XFLAGS, xflags); |
95 | 93 | ||
96 | efx_writed(efx, &hdr, pdu); | 94 | efx->type->mcdi_request(efx, &hdr, 4, inbuf, inlen); |
97 | |||
98 | for (i = 0; i < inlen_dw; i++) | ||
99 | efx_writed(efx, &inbuf[i], pdu + 4 + 4 * i); | ||
100 | |||
101 | /* Ensure the payload is written out before the header */ | ||
102 | wmb(); | ||
103 | |||
104 | /* ring the doorbell with a distinctive value */ | ||
105 | _efx_writed(efx, (__force __le32) 0x45789abc, doorbell); | ||
106 | } | 95 | } |
107 | 96 | ||
108 | static void | 97 | static void |
109 | efx_mcdi_copyout(struct efx_nic *efx, efx_dword_t *outbuf, size_t outlen) | 98 | efx_mcdi_copyout(struct efx_nic *efx, efx_dword_t *outbuf, size_t outlen) |
110 | { | 99 | { |
111 | struct efx_mcdi_iface *mcdi = efx_mcdi(efx); | 100 | struct efx_mcdi_iface *mcdi = efx_mcdi(efx); |
112 | unsigned int pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx); | ||
113 | unsigned int outlen_dw = DIV_ROUND_UP(outlen, 4); | ||
114 | int i; | ||
115 | 101 | ||
116 | BUG_ON(atomic_read(&mcdi->state) == MCDI_STATE_QUIESCENT); | 102 | BUG_ON(atomic_read(&mcdi->state) == MCDI_STATE_QUIESCENT); |
117 | BUG_ON(outlen > MCDI_CTL_SDU_LEN_MAX_V1); | 103 | BUG_ON(outlen > MCDI_CTL_SDU_LEN_MAX_V1); |
118 | 104 | ||
119 | for (i = 0; i < outlen_dw; i++) | 105 | efx->type->mcdi_read_response(efx, outbuf, 4, outlen); |
120 | efx_readd(efx, &outbuf[i], pdu + 4 + 4 * i); | ||
121 | } | 106 | } |
122 | 107 | ||
123 | static int efx_mcdi_poll(struct efx_nic *efx) | 108 | static int efx_mcdi_poll(struct efx_nic *efx) |
@@ -125,7 +110,6 @@ static int efx_mcdi_poll(struct efx_nic *efx) | |||
125 | struct efx_mcdi_iface *mcdi = efx_mcdi(efx); | 110 | struct efx_mcdi_iface *mcdi = efx_mcdi(efx); |
126 | unsigned long time, finish; | 111 | unsigned long time, finish; |
127 | unsigned int respseq, respcmd, error; | 112 | unsigned int respseq, respcmd, error; |
128 | unsigned int pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx); | ||
129 | unsigned int rc, spins; | 113 | unsigned int rc, spins; |
130 | efx_dword_t reg; | 114 | efx_dword_t reg; |
131 | 115 | ||
@@ -152,19 +136,14 @@ static int efx_mcdi_poll(struct efx_nic *efx) | |||
152 | time = jiffies; | 136 | time = jiffies; |
153 | 137 | ||
154 | rmb(); | 138 | rmb(); |
155 | efx_readd(efx, ®, pdu); | 139 | if (efx->type->mcdi_poll_response(efx)) |
156 | |||
157 | /* All 1's indicates that shared memory is in reset (and is | ||
158 | * not a valid header). Wait for it to come out reset before | ||
159 | * completing the command */ | ||
160 | if (EFX_DWORD_FIELD(reg, EFX_DWORD_0) != 0xffffffff && | ||
161 | EFX_DWORD_FIELD(reg, MCDI_HEADER_RESPONSE)) | ||
162 | break; | 140 | break; |
163 | 141 | ||
164 | if (time_after(time, finish)) | 142 | if (time_after(time, finish)) |
165 | return -ETIMEDOUT; | 143 | return -ETIMEDOUT; |
166 | } | 144 | } |
167 | 145 | ||
146 | efx->type->mcdi_read_response(efx, ®, 0, 4); | ||
168 | mcdi->resplen = EFX_DWORD_FIELD(reg, MCDI_HEADER_DATALEN); | 147 | mcdi->resplen = EFX_DWORD_FIELD(reg, MCDI_HEADER_DATALEN); |
169 | respseq = EFX_DWORD_FIELD(reg, MCDI_HEADER_SEQ); | 148 | respseq = EFX_DWORD_FIELD(reg, MCDI_HEADER_SEQ); |
170 | respcmd = EFX_DWORD_FIELD(reg, MCDI_HEADER_CODE); | 149 | respcmd = EFX_DWORD_FIELD(reg, MCDI_HEADER_CODE); |
@@ -179,7 +158,7 @@ static int efx_mcdi_poll(struct efx_nic *efx) | |||
179 | respseq, mcdi->seqno); | 158 | respseq, mcdi->seqno); |
180 | rc = EIO; | 159 | rc = EIO; |
181 | } else if (error) { | 160 | } else if (error) { |
182 | efx_readd(efx, ®, pdu + 4); | 161 | efx->type->mcdi_read_response(efx, ®, 4, 4); |
183 | switch (EFX_DWORD_FIELD(reg, EFX_DWORD_0)) { | 162 | switch (EFX_DWORD_FIELD(reg, EFX_DWORD_0)) { |
184 | #define TRANSLATE_ERROR(name) \ | 163 | #define TRANSLATE_ERROR(name) \ |
185 | case MC_CMD_ERR_ ## name: \ | 164 | case MC_CMD_ERR_ ## name: \ |
@@ -215,17 +194,13 @@ out: | |||
215 | */ | 194 | */ |
216 | int efx_mcdi_poll_reboot(struct efx_nic *efx) | 195 | int efx_mcdi_poll_reboot(struct efx_nic *efx) |
217 | { | 196 | { |
218 | unsigned int addr = FR_CZ_MC_TREG_SMEM + MCDI_STATUS(efx); | 197 | int rc; |
219 | efx_dword_t reg; | ||
220 | uint32_t value; | ||
221 | |||
222 | if (efx_nic_rev(efx) < EFX_REV_SIENA_A0) | ||
223 | return false; | ||
224 | 198 | ||
225 | efx_readd(efx, ®, addr); | 199 | if (!efx->mcdi) |
226 | value = EFX_DWORD_FIELD(reg, EFX_DWORD_0); | 200 | return 0; |
227 | 201 | ||
228 | if (value == 0) | 202 | rc = efx->type->mcdi_poll_reboot(efx); |
203 | if (!rc) | ||
229 | return 0; | 204 | return 0; |
230 | 205 | ||
231 | /* MAC statistics have been cleared on the NIC; clear our copy | 206 | /* MAC statistics have been cleared on the NIC; clear our copy |
@@ -233,13 +208,7 @@ int efx_mcdi_poll_reboot(struct efx_nic *efx) | |||
233 | */ | 208 | */ |
234 | memset(&efx->mac_stats, 0, sizeof(efx->mac_stats)); | 209 | memset(&efx->mac_stats, 0, sizeof(efx->mac_stats)); |
235 | 210 | ||
236 | EFX_ZERO_DWORD(reg); | 211 | return rc; |
237 | efx_writed(efx, ®, addr); | ||
238 | |||
239 | if (value == MC_STATUS_DWORD_ASSERT) | ||
240 | return -EINTR; | ||
241 | else | ||
242 | return -EIO; | ||
243 | } | 212 | } |
244 | 213 | ||
245 | static void efx_mcdi_acquire(struct efx_mcdi_iface *mcdi) | 214 | static void efx_mcdi_acquire(struct efx_mcdi_iface *mcdi) |
@@ -345,8 +314,6 @@ void efx_mcdi_rpc_start(struct efx_nic *efx, unsigned cmd, | |||
345 | { | 314 | { |
346 | struct efx_mcdi_iface *mcdi = efx_mcdi(efx); | 315 | struct efx_mcdi_iface *mcdi = efx_mcdi(efx); |
347 | 316 | ||
348 | BUG_ON(efx_nic_rev(efx) < EFX_REV_SIENA_A0); | ||
349 | |||
350 | efx_mcdi_acquire(mcdi); | 317 | efx_mcdi_acquire(mcdi); |
351 | 318 | ||
352 | /* Serialise with efx_mcdi_ev_cpl() and efx_mcdi_ev_death() */ | 319 | /* Serialise with efx_mcdi_ev_cpl() and efx_mcdi_ev_death() */ |
@@ -364,8 +331,6 @@ int efx_mcdi_rpc_finish(struct efx_nic *efx, unsigned cmd, size_t inlen, | |||
364 | struct efx_mcdi_iface *mcdi = efx_mcdi(efx); | 331 | struct efx_mcdi_iface *mcdi = efx_mcdi(efx); |
365 | int rc; | 332 | int rc; |
366 | 333 | ||
367 | BUG_ON(efx_nic_rev(efx) < EFX_REV_SIENA_A0); | ||
368 | |||
369 | if (mcdi->mode == MCDI_MODE_POLL) | 334 | if (mcdi->mode == MCDI_MODE_POLL) |
370 | rc = efx_mcdi_poll(efx); | 335 | rc = efx_mcdi_poll(efx); |
371 | else | 336 | else |
@@ -426,7 +391,7 @@ void efx_mcdi_mode_poll(struct efx_nic *efx) | |||
426 | { | 391 | { |
427 | struct efx_mcdi_iface *mcdi; | 392 | struct efx_mcdi_iface *mcdi; |
428 | 393 | ||
429 | if (efx_nic_rev(efx) < EFX_REV_SIENA_A0) | 394 | if (!efx->mcdi) |
430 | return; | 395 | return; |
431 | 396 | ||
432 | mcdi = efx_mcdi(efx); | 397 | mcdi = efx_mcdi(efx); |
@@ -450,7 +415,7 @@ void efx_mcdi_mode_event(struct efx_nic *efx) | |||
450 | { | 415 | { |
451 | struct efx_mcdi_iface *mcdi; | 416 | struct efx_mcdi_iface *mcdi; |
452 | 417 | ||
453 | if (efx_nic_rev(efx) < EFX_REV_SIENA_A0) | 418 | if (!efx->mcdi) |
454 | return; | 419 | return; |
455 | 420 | ||
456 | mcdi = efx_mcdi(efx); | 421 | mcdi = efx_mcdi(efx); |