aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorBen Hutchings <bhutchings@solarflare.com>2011-05-11 12:41:18 -0400
committerBen Hutchings <bhutchings@solarflare.com>2011-05-12 10:16:32 -0400
commit747df2258b1b9a2e25929ef496262c339c380009 (patch)
tree7f0ff222afed691599f24473e0b8d10b36f48cf2 /drivers
parentff538818f4a82c4cf02d2d6bd6ac5c7360b9d41d (diff)
sfc: Always map MCDI shared memory as uncacheable
We enabled write-combining for memory-mapped registers in commit 65f0b417dee94f779ce9b77102b7d73c93723b39, but inhibited it for the MCDI shared memory where this is not supported. However, write-combining mappings also allow read-reordering, which may also be a problem. I found that when an SFC9000-family controller is connected to an Intel 3000 chipset, and write-combining is enabled, the controller stops responding to PCIe read requests during driver initialisation while the driver is polling for completion of an MCDI command. This results in an NMI and system hang. Adding read memory barriers between all reads to the shared memory area appears to reduce but not eliminate the probability of this. We have not yet established whether this is a bug in our BIU or in the PCIe bridge. For now, work around by mapping the shared memory area separately. Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/sfc/mcdi.c49
-rw-r--r--drivers/net/sfc/nic.h2
-rw-r--r--drivers/net/sfc/siena.c25
3 files changed, 53 insertions, 23 deletions
diff --git a/drivers/net/sfc/mcdi.c b/drivers/net/sfc/mcdi.c
index d98479030ef2..3dd45ed61f0a 100644
--- a/drivers/net/sfc/mcdi.c
+++ b/drivers/net/sfc/mcdi.c
@@ -50,6 +50,20 @@ static inline struct efx_mcdi_iface *efx_mcdi(struct efx_nic *efx)
50 return &nic_data->mcdi; 50 return &nic_data->mcdi;
51} 51}
52 52
53static inline void
54efx_mcdi_readd(struct efx_nic *efx, efx_dword_t *value, unsigned reg)
55{
56 struct siena_nic_data *nic_data = efx->nic_data;
57 value->u32[0] = (__force __le32)__raw_readl(nic_data->mcdi_smem + reg);
58}
59
60static inline void
61efx_mcdi_writed(struct efx_nic *efx, const efx_dword_t *value, unsigned reg)
62{
63 struct siena_nic_data *nic_data = efx->nic_data;
64 __raw_writel((__force u32)value->u32[0], nic_data->mcdi_smem + reg);
65}
66
53void efx_mcdi_init(struct efx_nic *efx) 67void efx_mcdi_init(struct efx_nic *efx)
54{ 68{
55 struct efx_mcdi_iface *mcdi; 69 struct efx_mcdi_iface *mcdi;
@@ -70,8 +84,8 @@ static void efx_mcdi_copyin(struct efx_nic *efx, unsigned cmd,
70 const u8 *inbuf, size_t inlen) 84 const u8 *inbuf, size_t inlen)
71{ 85{
72 struct efx_mcdi_iface *mcdi = efx_mcdi(efx); 86 struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
73 unsigned pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx); 87 unsigned pdu = MCDI_PDU(efx);
74 unsigned doorbell = FR_CZ_MC_TREG_SMEM + MCDI_DOORBELL(efx); 88 unsigned doorbell = MCDI_DOORBELL(efx);
75 unsigned int i; 89 unsigned int i;
76 efx_dword_t hdr; 90 efx_dword_t hdr;
77 u32 xflags, seqno; 91 u32 xflags, seqno;
@@ -92,30 +106,28 @@ static void efx_mcdi_copyin(struct efx_nic *efx, unsigned cmd,
92 MCDI_HEADER_SEQ, seqno, 106 MCDI_HEADER_SEQ, seqno,
93 MCDI_HEADER_XFLAGS, xflags); 107 MCDI_HEADER_XFLAGS, xflags);
94 108
95 efx_writed(efx, &hdr, pdu); 109 efx_mcdi_writed(efx, &hdr, pdu);
96 110
97 for (i = 0; i < inlen; i += 4) { 111 for (i = 0; i < inlen; i += 4)
98 _efx_writed(efx, *((__le32 *)(inbuf + i)), pdu + 4 + i); 112 efx_mcdi_writed(efx, (const efx_dword_t *)(inbuf + i),
99 /* use wmb() within loop to inhibit write combining */ 113 pdu + 4 + i);
100 wmb();
101 }
102 114
103 /* ring the doorbell with a distinctive value */ 115 /* ring the doorbell with a distinctive value */
104 _efx_writed(efx, (__force __le32) 0x45789abc, doorbell); 116 EFX_POPULATE_DWORD_1(hdr, EFX_DWORD_0, 0x45789abc);
105 wmb(); 117 efx_mcdi_writed(efx, &hdr, doorbell);
106} 118}
107 119
108static void efx_mcdi_copyout(struct efx_nic *efx, u8 *outbuf, size_t outlen) 120static void efx_mcdi_copyout(struct efx_nic *efx, u8 *outbuf, size_t outlen)
109{ 121{
110 struct efx_mcdi_iface *mcdi = efx_mcdi(efx); 122 struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
111 unsigned int pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx); 123 unsigned int pdu = MCDI_PDU(efx);
112 int i; 124 int i;
113 125
114 BUG_ON(atomic_read(&mcdi->state) == MCDI_STATE_QUIESCENT); 126 BUG_ON(atomic_read(&mcdi->state) == MCDI_STATE_QUIESCENT);
115 BUG_ON(outlen & 3 || outlen >= 0x100); 127 BUG_ON(outlen & 3 || outlen >= 0x100);
116 128
117 for (i = 0; i < outlen; i += 4) 129 for (i = 0; i < outlen; i += 4)
118 *((__le32 *)(outbuf + i)) = _efx_readd(efx, pdu + 4 + i); 130 efx_mcdi_readd(efx, (efx_dword_t *)(outbuf + i), pdu + 4 + i);
119} 131}
120 132
121static int efx_mcdi_poll(struct efx_nic *efx) 133static int efx_mcdi_poll(struct efx_nic *efx)
@@ -123,7 +135,7 @@ static int efx_mcdi_poll(struct efx_nic *efx)
123 struct efx_mcdi_iface *mcdi = efx_mcdi(efx); 135 struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
124 unsigned int time, finish; 136 unsigned int time, finish;
125 unsigned int respseq, respcmd, error; 137 unsigned int respseq, respcmd, error;
126 unsigned int pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx); 138 unsigned int pdu = MCDI_PDU(efx);
127 unsigned int rc, spins; 139 unsigned int rc, spins;
128 efx_dword_t reg; 140 efx_dword_t reg;
129 141
@@ -149,8 +161,7 @@ static int efx_mcdi_poll(struct efx_nic *efx)
149 161
150 time = get_seconds(); 162 time = get_seconds();
151 163
152 rmb(); 164 efx_mcdi_readd(efx, &reg, pdu);
153 efx_readd(efx, &reg, pdu);
154 165
155 /* All 1's indicates that shared memory is in reset (and is 166 /* All 1's indicates that shared memory is in reset (and is
156 * not a valid header). Wait for it to come out reset before 167 * not a valid header). Wait for it to come out reset before
@@ -177,7 +188,7 @@ static int efx_mcdi_poll(struct efx_nic *efx)
177 respseq, mcdi->seqno); 188 respseq, mcdi->seqno);
178 rc = EIO; 189 rc = EIO;
179 } else if (error) { 190 } else if (error) {
180 efx_readd(efx, &reg, pdu + 4); 191 efx_mcdi_readd(efx, &reg, pdu + 4);
181 switch (EFX_DWORD_FIELD(reg, EFX_DWORD_0)) { 192 switch (EFX_DWORD_FIELD(reg, EFX_DWORD_0)) {
182#define TRANSLATE_ERROR(name) \ 193#define TRANSLATE_ERROR(name) \
183 case MC_CMD_ERR_ ## name: \ 194 case MC_CMD_ERR_ ## name: \
@@ -211,21 +222,21 @@ out:
211/* Test and clear MC-rebooted flag for this port/function */ 222/* Test and clear MC-rebooted flag for this port/function */
212int efx_mcdi_poll_reboot(struct efx_nic *efx) 223int efx_mcdi_poll_reboot(struct efx_nic *efx)
213{ 224{
214 unsigned int addr = FR_CZ_MC_TREG_SMEM + MCDI_REBOOT_FLAG(efx); 225 unsigned int addr = MCDI_REBOOT_FLAG(efx);
215 efx_dword_t reg; 226 efx_dword_t reg;
216 uint32_t value; 227 uint32_t value;
217 228
218 if (efx_nic_rev(efx) < EFX_REV_SIENA_A0) 229 if (efx_nic_rev(efx) < EFX_REV_SIENA_A0)
219 return false; 230 return false;
220 231
221 efx_readd(efx, &reg, addr); 232 efx_mcdi_readd(efx, &reg, addr);
222 value = EFX_DWORD_FIELD(reg, EFX_DWORD_0); 233 value = EFX_DWORD_FIELD(reg, EFX_DWORD_0);
223 234
224 if (value == 0) 235 if (value == 0)
225 return 0; 236 return 0;
226 237
227 EFX_ZERO_DWORD(reg); 238 EFX_ZERO_DWORD(reg);
228 efx_writed(efx, &reg, addr); 239 efx_mcdi_writed(efx, &reg, addr);
229 240
230 if (value == MC_STATUS_DWORD_ASSERT) 241 if (value == MC_STATUS_DWORD_ASSERT)
231 return -EINTR; 242 return -EINTR;
diff --git a/drivers/net/sfc/nic.h b/drivers/net/sfc/nic.h
index a42db6e35be3..d91701abd331 100644
--- a/drivers/net/sfc/nic.h
+++ b/drivers/net/sfc/nic.h
@@ -143,10 +143,12 @@ static inline struct falcon_board *falcon_board(struct efx_nic *efx)
143/** 143/**
144 * struct siena_nic_data - Siena NIC state 144 * struct siena_nic_data - Siena NIC state
145 * @mcdi: Management-Controller-to-Driver Interface 145 * @mcdi: Management-Controller-to-Driver Interface
146 * @mcdi_smem: MCDI shared memory mapping. The mapping is always uncacheable.
146 * @wol_filter_id: Wake-on-LAN packet filter id 147 * @wol_filter_id: Wake-on-LAN packet filter id
147 */ 148 */
148struct siena_nic_data { 149struct siena_nic_data {
149 struct efx_mcdi_iface mcdi; 150 struct efx_mcdi_iface mcdi;
151 void __iomem *mcdi_smem;
150 int wol_filter_id; 152 int wol_filter_id;
151}; 153};
152 154
diff --git a/drivers/net/sfc/siena.c b/drivers/net/sfc/siena.c
index e4dd8986b1fe..837869b71db9 100644
--- a/drivers/net/sfc/siena.c
+++ b/drivers/net/sfc/siena.c
@@ -220,12 +220,26 @@ static int siena_probe_nic(struct efx_nic *efx)
220 efx_reado(efx, &reg, FR_AZ_CS_DEBUG); 220 efx_reado(efx, &reg, FR_AZ_CS_DEBUG);
221 efx->net_dev->dev_id = EFX_OWORD_FIELD(reg, FRF_CZ_CS_PORT_NUM) - 1; 221 efx->net_dev->dev_id = EFX_OWORD_FIELD(reg, FRF_CZ_CS_PORT_NUM) - 1;
222 222
223 /* Initialise MCDI */
224 nic_data->mcdi_smem = ioremap_nocache(efx->membase_phys +
225 FR_CZ_MC_TREG_SMEM,
226 FR_CZ_MC_TREG_SMEM_STEP *
227 FR_CZ_MC_TREG_SMEM_ROWS);
228 if (!nic_data->mcdi_smem) {
229 netif_err(efx, probe, efx->net_dev,
230 "could not map MCDI at %llx+%x\n",
231 (unsigned long long)efx->membase_phys +
232 FR_CZ_MC_TREG_SMEM,
233 FR_CZ_MC_TREG_SMEM_STEP * FR_CZ_MC_TREG_SMEM_ROWS);
234 rc = -ENOMEM;
235 goto fail1;
236 }
223 efx_mcdi_init(efx); 237 efx_mcdi_init(efx);
224 238
225 /* Recover from a failed assertion before probing */ 239 /* Recover from a failed assertion before probing */
226 rc = efx_mcdi_handle_assertion(efx); 240 rc = efx_mcdi_handle_assertion(efx);
227 if (rc) 241 if (rc)
228 goto fail1; 242 goto fail2;
229 243
230 /* Let the BMC know that the driver is now in charge of link and 244 /* Let the BMC know that the driver is now in charge of link and
231 * filter settings. We must do this before we reset the NIC */ 245 * filter settings. We must do this before we reset the NIC */
@@ -280,6 +294,7 @@ fail4:
280fail3: 294fail3:
281 efx_mcdi_drv_attach(efx, false, NULL); 295 efx_mcdi_drv_attach(efx, false, NULL);
282fail2: 296fail2:
297 iounmap(nic_data->mcdi_smem);
283fail1: 298fail1:
284 kfree(efx->nic_data); 299 kfree(efx->nic_data);
285 return rc; 300 return rc;
@@ -359,6 +374,8 @@ static int siena_init_nic(struct efx_nic *efx)
359 374
360static void siena_remove_nic(struct efx_nic *efx) 375static void siena_remove_nic(struct efx_nic *efx)
361{ 376{
377 struct siena_nic_data *nic_data = efx->nic_data;
378
362 efx_nic_free_buffer(efx, &efx->irq_status); 379 efx_nic_free_buffer(efx, &efx->irq_status);
363 380
364 siena_reset_hw(efx, RESET_TYPE_ALL); 381 siena_reset_hw(efx, RESET_TYPE_ALL);
@@ -368,7 +385,8 @@ static void siena_remove_nic(struct efx_nic *efx)
368 efx_mcdi_drv_attach(efx, false, NULL); 385 efx_mcdi_drv_attach(efx, false, NULL);
369 386
370 /* Tear down the private nic state */ 387 /* Tear down the private nic state */
371 kfree(efx->nic_data); 388 iounmap(nic_data->mcdi_smem);
389 kfree(nic_data);
372 efx->nic_data = NULL; 390 efx->nic_data = NULL;
373} 391}
374 392
@@ -606,8 +624,7 @@ struct efx_nic_type siena_a0_nic_type = {
606 .default_mac_ops = &efx_mcdi_mac_operations, 624 .default_mac_ops = &efx_mcdi_mac_operations,
607 625
608 .revision = EFX_REV_SIENA_A0, 626 .revision = EFX_REV_SIENA_A0,
609 .mem_map_size = (FR_CZ_MC_TREG_SMEM + 627 .mem_map_size = FR_CZ_MC_TREG_SMEM, /* MC_TREG_SMEM mapped separately */
610 FR_CZ_MC_TREG_SMEM_STEP * FR_CZ_MC_TREG_SMEM_ROWS),
611 .txd_ptr_tbl_base = FR_BZ_TX_DESC_PTR_TBL, 628 .txd_ptr_tbl_base = FR_BZ_TX_DESC_PTR_TBL,
612 .rxd_ptr_tbl_base = FR_BZ_RX_DESC_PTR_TBL, 629 .rxd_ptr_tbl_base = FR_BZ_RX_DESC_PTR_TBL,
613 .buf_tbl_base = FR_BZ_BUF_FULL_TBL, 630 .buf_tbl_base = FR_BZ_BUF_FULL_TBL,