diff options
-rw-r--r-- | drivers/net/ethernet/sfc/mcdi.c | 87 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/mcdi.h | 21 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/net_driver.h | 20 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/nic.h | 16 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/siena.c | 90 |
5 files changed, 157 insertions, 77 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); |
diff --git a/drivers/net/ethernet/sfc/mcdi.h b/drivers/net/ethernet/sfc/mcdi.h index 6c58dbd7f581..0bfed2a64399 100644 --- a/drivers/net/ethernet/sfc/mcdi.h +++ b/drivers/net/ethernet/sfc/mcdi.h | |||
@@ -65,7 +65,28 @@ struct efx_mcdi_mon { | |||
65 | unsigned int n_attrs; | 65 | unsigned int n_attrs; |
66 | }; | 66 | }; |
67 | 67 | ||
68 | /** | ||
69 | * struct efx_mcdi_data - extra state for NICs that implement MCDI | ||
70 | * @iface: Interface/protocol state | ||
71 | * @hwmon: Hardware monitor state | ||
72 | */ | ||
73 | struct efx_mcdi_data { | ||
74 | struct efx_mcdi_iface iface; | ||
75 | #ifdef CONFIG_SFC_MCDI_MON | ||
76 | struct efx_mcdi_mon hwmon; | ||
77 | #endif | ||
78 | }; | ||
79 | |||
80 | #ifdef CONFIG_SFC_MCDI_MON | ||
81 | static inline struct efx_mcdi_mon *efx_mcdi_mon(struct efx_nic *efx) | ||
82 | { | ||
83 | EFX_BUG_ON_PARANOID(!efx->mcdi); | ||
84 | return &efx->mcdi->hwmon; | ||
85 | } | ||
86 | #endif | ||
87 | |||
68 | extern int efx_mcdi_init(struct efx_nic *efx); | 88 | extern int efx_mcdi_init(struct efx_nic *efx); |
89 | extern void efx_mcdi_fini(struct efx_nic *efx); | ||
69 | 90 | ||
70 | extern int efx_mcdi_rpc(struct efx_nic *efx, unsigned cmd, | 91 | extern int efx_mcdi_rpc(struct efx_nic *efx, unsigned cmd, |
71 | const efx_dword_t *inbuf, size_t inlen, | 92 | const efx_dword_t *inbuf, size_t inlen, |
diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index bdded38cbf12..fb9361f384de 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h | |||
@@ -718,6 +718,7 @@ struct vfdi_status; | |||
718 | * @selftest_work: Work item for asynchronous self-test | 718 | * @selftest_work: Work item for asynchronous self-test |
719 | * @mtd_list: List of MTDs attached to the NIC | 719 | * @mtd_list: List of MTDs attached to the NIC |
720 | * @nic_data: Hardware dependent state | 720 | * @nic_data: Hardware dependent state |
721 | * @mcdi: Management-Controller-to-Driver Interface state | ||
721 | * @mac_lock: MAC access lock. Protects @port_enabled, @phy_mode, | 722 | * @mac_lock: MAC access lock. Protects @port_enabled, @phy_mode, |
722 | * efx_monitor() and efx_reconfigure_port() | 723 | * efx_monitor() and efx_reconfigure_port() |
723 | * @port_enabled: Port enabled indicator. | 724 | * @port_enabled: Port enabled indicator. |
@@ -847,6 +848,7 @@ struct efx_nic { | |||
847 | #endif | 848 | #endif |
848 | 849 | ||
849 | void *nic_data; | 850 | void *nic_data; |
851 | struct efx_mcdi_data *mcdi; | ||
850 | 852 | ||
851 | struct mutex mac_lock; | 853 | struct mutex mac_lock; |
852 | struct work_struct mac_work; | 854 | struct work_struct mac_work; |
@@ -956,6 +958,17 @@ static inline unsigned int efx_port_num(struct efx_nic *efx) | |||
956 | * @test_chip: Test registers. Should use efx_nic_test_registers(), and is | 958 | * @test_chip: Test registers. Should use efx_nic_test_registers(), and is |
957 | * expected to reset the NIC. | 959 | * expected to reset the NIC. |
958 | * @test_nvram: Test validity of NVRAM contents | 960 | * @test_nvram: Test validity of NVRAM contents |
961 | * @mcdi_request: Send an MCDI request with the given header and SDU. | ||
962 | * The SDU length may be any value from 0 up to the protocol- | ||
963 | * defined maximum, but its buffer will be padded to a multiple | ||
964 | * of 4 bytes. | ||
965 | * @mcdi_poll_response: Test whether an MCDI response is available. | ||
966 | * @mcdi_read_response: Read the MCDI response PDU. The offset will | ||
967 | * be a multiple of 4. The length may not be, but the buffer | ||
968 | * will be padded so it is safe to round up. | ||
969 | * @mcdi_poll_reboot: Test whether the MCDI has rebooted. If so, | ||
970 | * return an appropriate error code for aborting any current | ||
971 | * request; otherwise return 0. | ||
959 | * @revision: Hardware architecture revision | 972 | * @revision: Hardware architecture revision |
960 | * @mem_map_size: Memory BAR mapped size | 973 | * @mem_map_size: Memory BAR mapped size |
961 | * @txd_ptr_tbl_base: TX descriptor ring base address | 974 | * @txd_ptr_tbl_base: TX descriptor ring base address |
@@ -1004,6 +1017,13 @@ struct efx_nic_type { | |||
1004 | void (*resume_wol)(struct efx_nic *efx); | 1017 | void (*resume_wol)(struct efx_nic *efx); |
1005 | int (*test_chip)(struct efx_nic *efx, struct efx_self_tests *tests); | 1018 | int (*test_chip)(struct efx_nic *efx, struct efx_self_tests *tests); |
1006 | int (*test_nvram)(struct efx_nic *efx); | 1019 | int (*test_nvram)(struct efx_nic *efx); |
1020 | void (*mcdi_request)(struct efx_nic *efx, | ||
1021 | const efx_dword_t *hdr, size_t hdr_len, | ||
1022 | const efx_dword_t *sdu, size_t sdu_len); | ||
1023 | bool (*mcdi_poll_response)(struct efx_nic *efx); | ||
1024 | void (*mcdi_read_response)(struct efx_nic *efx, efx_dword_t *pdu, | ||
1025 | size_t pdu_offset, size_t pdu_len); | ||
1026 | int (*mcdi_poll_reboot)(struct efx_nic *efx); | ||
1007 | 1027 | ||
1008 | int revision; | 1028 | int revision; |
1009 | unsigned int mem_map_size; | 1029 | unsigned int mem_map_size; |
diff --git a/drivers/net/ethernet/sfc/nic.h b/drivers/net/ethernet/sfc/nic.h index 0d38cc2e96aa..c699203a210b 100644 --- a/drivers/net/ethernet/sfc/nic.h +++ b/drivers/net/ethernet/sfc/nic.h | |||
@@ -140,28 +140,12 @@ static inline struct falcon_board *falcon_board(struct efx_nic *efx) | |||
140 | 140 | ||
141 | /** | 141 | /** |
142 | * struct siena_nic_data - Siena NIC state | 142 | * struct siena_nic_data - Siena NIC state |
143 | * @mcdi: Management-Controller-to-Driver Interface | ||
144 | * @wol_filter_id: Wake-on-LAN packet filter id | 143 | * @wol_filter_id: Wake-on-LAN packet filter id |
145 | * @hwmon: Hardware monitor state | ||
146 | */ | 144 | */ |
147 | struct siena_nic_data { | 145 | struct siena_nic_data { |
148 | struct efx_mcdi_iface mcdi; | ||
149 | int wol_filter_id; | 146 | int wol_filter_id; |
150 | #ifdef CONFIG_SFC_MCDI_MON | ||
151 | struct efx_mcdi_mon hwmon; | ||
152 | #endif | ||
153 | }; | 147 | }; |
154 | 148 | ||
155 | #ifdef CONFIG_SFC_MCDI_MON | ||
156 | static inline struct efx_mcdi_mon *efx_mcdi_mon(struct efx_nic *efx) | ||
157 | { | ||
158 | struct siena_nic_data *nic_data; | ||
159 | EFX_BUG_ON_PARANOID(efx_nic_rev(efx) < EFX_REV_SIENA_A0); | ||
160 | nic_data = efx->nic_data; | ||
161 | return &nic_data->hwmon; | ||
162 | } | ||
163 | #endif | ||
164 | |||
165 | /* | 149 | /* |
166 | * On the SFC9000 family each port is associated with 1 PCI physical | 150 | * On the SFC9000 family each port is associated with 1 PCI physical |
167 | * function (PF) handled by sfc and a configurable number of virtual | 151 | * function (PF) handled by sfc and a configurable number of virtual |
diff --git a/drivers/net/ethernet/sfc/siena.c b/drivers/net/ethernet/sfc/siena.c index 3dca771938f0..73b511af33f9 100644 --- a/drivers/net/ethernet/sfc/siena.c +++ b/drivers/net/ethernet/sfc/siena.c | |||
@@ -274,6 +274,7 @@ fail4: | |||
274 | fail3: | 274 | fail3: |
275 | efx_mcdi_drv_attach(efx, false, NULL); | 275 | efx_mcdi_drv_attach(efx, false, NULL); |
276 | fail2: | 276 | fail2: |
277 | efx_mcdi_fini(efx); | ||
277 | fail1: | 278 | fail1: |
278 | kfree(efx->nic_data); | 279 | kfree(efx->nic_data); |
279 | return rc; | 280 | return rc; |
@@ -367,6 +368,8 @@ static void siena_remove_nic(struct efx_nic *efx) | |||
367 | /* Tear down the private nic state */ | 368 | /* Tear down the private nic state */ |
368 | kfree(efx->nic_data); | 369 | kfree(efx->nic_data); |
369 | efx->nic_data = NULL; | 370 | efx->nic_data = NULL; |
371 | |||
372 | efx_mcdi_fini(efx); | ||
370 | } | 373 | } |
371 | 374 | ||
372 | static int siena_try_update_nic_stats(struct efx_nic *efx) | 375 | static int siena_try_update_nic_stats(struct efx_nic *efx) |
@@ -574,6 +577,89 @@ static void siena_init_wol(struct efx_nic *efx) | |||
574 | } | 577 | } |
575 | } | 578 | } |
576 | 579 | ||
580 | /************************************************************************** | ||
581 | * | ||
582 | * MCDI | ||
583 | * | ||
584 | ************************************************************************** | ||
585 | */ | ||
586 | |||
587 | #define MCDI_PDU(efx) \ | ||
588 | (efx_port_num(efx) ? MC_SMEM_P1_PDU_OFST : MC_SMEM_P0_PDU_OFST) | ||
589 | #define MCDI_DOORBELL(efx) \ | ||
590 | (efx_port_num(efx) ? MC_SMEM_P1_DOORBELL_OFST : MC_SMEM_P0_DOORBELL_OFST) | ||
591 | #define MCDI_STATUS(efx) \ | ||
592 | (efx_port_num(efx) ? MC_SMEM_P1_STATUS_OFST : MC_SMEM_P0_STATUS_OFST) | ||
593 | |||
594 | static void siena_mcdi_request(struct efx_nic *efx, | ||
595 | const efx_dword_t *hdr, size_t hdr_len, | ||
596 | const efx_dword_t *sdu, size_t sdu_len) | ||
597 | { | ||
598 | unsigned pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx); | ||
599 | unsigned doorbell = FR_CZ_MC_TREG_SMEM + MCDI_DOORBELL(efx); | ||
600 | unsigned int i; | ||
601 | unsigned int inlen_dw = DIV_ROUND_UP(sdu_len, 4); | ||
602 | |||
603 | EFX_BUG_ON_PARANOID(hdr_len != 4); | ||
604 | |||
605 | efx_writed(efx, hdr, pdu); | ||
606 | |||
607 | for (i = 0; i < inlen_dw; i++) | ||
608 | efx_writed(efx, &sdu[i], pdu + hdr_len + 4 * i); | ||
609 | |||
610 | /* Ensure the request is written out before the doorbell */ | ||
611 | wmb(); | ||
612 | |||
613 | /* ring the doorbell with a distinctive value */ | ||
614 | _efx_writed(efx, (__force __le32) 0x45789abc, doorbell); | ||
615 | } | ||
616 | |||
617 | static bool siena_mcdi_poll_response(struct efx_nic *efx) | ||
618 | { | ||
619 | unsigned int pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx); | ||
620 | efx_dword_t hdr; | ||
621 | |||
622 | efx_readd(efx, &hdr, pdu); | ||
623 | |||
624 | /* All 1's indicates that shared memory is in reset (and is | ||
625 | * not a valid hdr). Wait for it to come out reset before | ||
626 | * completing the command | ||
627 | */ | ||
628 | return EFX_DWORD_FIELD(hdr, EFX_DWORD_0) != 0xffffffff && | ||
629 | EFX_DWORD_FIELD(hdr, MCDI_HEADER_RESPONSE); | ||
630 | } | ||
631 | |||
632 | static void siena_mcdi_read_response(struct efx_nic *efx, efx_dword_t *outbuf, | ||
633 | size_t offset, size_t outlen) | ||
634 | { | ||
635 | unsigned int pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx); | ||
636 | unsigned int outlen_dw = DIV_ROUND_UP(outlen, 4); | ||
637 | int i; | ||
638 | |||
639 | for (i = 0; i < outlen_dw; i++) | ||
640 | efx_readd(efx, &outbuf[i], pdu + offset + 4 * i); | ||
641 | } | ||
642 | |||
643 | static int siena_mcdi_poll_reboot(struct efx_nic *efx) | ||
644 | { | ||
645 | unsigned int addr = FR_CZ_MC_TREG_SMEM + MCDI_STATUS(efx); | ||
646 | efx_dword_t reg; | ||
647 | u32 value; | ||
648 | |||
649 | efx_readd(efx, ®, addr); | ||
650 | value = EFX_DWORD_FIELD(reg, EFX_DWORD_0); | ||
651 | |||
652 | if (value == 0) | ||
653 | return 0; | ||
654 | |||
655 | EFX_ZERO_DWORD(reg); | ||
656 | efx_writed(efx, ®, addr); | ||
657 | |||
658 | if (value == MC_STATUS_DWORD_ASSERT) | ||
659 | return -EINTR; | ||
660 | else | ||
661 | return -EIO; | ||
662 | } | ||
577 | 663 | ||
578 | /************************************************************************** | 664 | /************************************************************************** |
579 | * | 665 | * |
@@ -613,6 +699,10 @@ const struct efx_nic_type siena_a0_nic_type = { | |||
613 | .resume_wol = siena_init_wol, | 699 | .resume_wol = siena_init_wol, |
614 | .test_chip = siena_test_chip, | 700 | .test_chip = siena_test_chip, |
615 | .test_nvram = efx_mcdi_nvram_test_all, | 701 | .test_nvram = efx_mcdi_nvram_test_all, |
702 | .mcdi_request = siena_mcdi_request, | ||
703 | .mcdi_poll_response = siena_mcdi_poll_response, | ||
704 | .mcdi_read_response = siena_mcdi_read_response, | ||
705 | .mcdi_poll_reboot = siena_mcdi_poll_reboot, | ||
616 | 706 | ||
617 | .revision = EFX_REV_SIENA_A0, | 707 | .revision = EFX_REV_SIENA_A0, |
618 | .mem_map_size = (FR_CZ_MC_TREG_SMEM + | 708 | .mem_map_size = (FR_CZ_MC_TREG_SMEM + |