aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/sfc/mcdi.c
diff options
context:
space:
mode:
authorBen Hutchings <bhutchings@solarflare.com>2012-09-17 21:33:56 -0400
committerBen Hutchings <bhutchings@solarflare.com>2013-08-21 14:43:27 -0400
commitf3ad50034425692965a0f2becdd9c45ecb45cd66 (patch)
tree0ada5470ce0cc43c1589ebd619bba22716b4844f /drivers/net/ethernet/sfc/mcdi.c
parentf073dde03b3e8d11050d82f52caaf75fd924e069 (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.c87
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
45static inline struct efx_mcdi_iface *efx_mcdi(struct efx_nic *efx) 38static 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
53int efx_mcdi_init(struct efx_nic *efx) 44int 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
64void 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
69static void efx_mcdi_copyin(struct efx_nic *efx, unsigned cmd, 71static 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
108static void 97static void
109efx_mcdi_copyout(struct efx_nic *efx, efx_dword_t *outbuf, size_t outlen) 98efx_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
123static int efx_mcdi_poll(struct efx_nic *efx) 108static 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, &reg, 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, &reg, 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, &reg, pdu + 4); 161 efx->type->mcdi_read_response(efx, &reg, 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 */
216int efx_mcdi_poll_reboot(struct efx_nic *efx) 195int 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, &reg, 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, &reg, addr);
238
239 if (value == MC_STATUS_DWORD_ASSERT)
240 return -EINTR;
241 else
242 return -EIO;
243} 212}
244 213
245static void efx_mcdi_acquire(struct efx_mcdi_iface *mcdi) 214static 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);