xref: /dpdk/drivers/net/txgbe/base/txgbe_eeprom.c (revision 75c85e39)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2015-2020 Beijing WangXun Technology Co., Ltd.
3  * Copyright(c) 2010-2017 Intel Corporation
4  */
5 
6 #include "txgbe_hw.h"
7 #include "txgbe_mng.h"
8 #include "txgbe_eeprom.h"
9 
10 /**
11  *  txgbe_init_eeprom_params - Initialize EEPROM params
12  *  @hw: pointer to hardware structure
13  *
14  *  Initializes the EEPROM parameters txgbe_rom_info within the
15  *  txgbe_hw struct in order to set up EEPROM access.
16  **/
txgbe_init_eeprom_params(struct txgbe_hw * hw)17 s32 txgbe_init_eeprom_params(struct txgbe_hw *hw)
18 {
19 	struct txgbe_rom_info *eeprom = &hw->rom;
20 	u32 eec;
21 	u16 eeprom_size;
22 	int err = 0;
23 
24 	if (eeprom->type != txgbe_eeprom_unknown)
25 		return 0;
26 
27 	eeprom->type = txgbe_eeprom_none;
28 	/* Set default semaphore delay to 10ms which is a well
29 	 * tested value
30 	 */
31 	eeprom->semaphore_delay = 10; /*ms*/
32 	/* Clear EEPROM page size, it will be initialized as needed */
33 	eeprom->word_page_size = 0;
34 
35 	/*
36 	 * Check for EEPROM present first.
37 	 * If not present leave as none
38 	 */
39 	eec = rd32(hw, TXGBE_SPISTAT);
40 	if (!(eec & TXGBE_SPISTAT_BPFLASH)) {
41 		eeprom->type = txgbe_eeprom_flash;
42 
43 		/*
44 		 * SPI EEPROM is assumed here.  This code would need to
45 		 * change if a future EEPROM is not SPI.
46 		 */
47 		eeprom_size = 4096;
48 		eeprom->word_size = eeprom_size >> 1;
49 	}
50 
51 	eeprom->address_bits = 16;
52 
53 	err = eeprom->read32(hw, TXGBE_SW_REGION_PTR << 1, &eeprom->sw_addr);
54 	if (err) {
55 		DEBUGOUT("EEPROM read failed.");
56 		return err;
57 	}
58 
59 	DEBUGOUT("eeprom params: type = %d, size = %d, address bits: %d %d",
60 		  eeprom->type, eeprom->word_size,
61 		  eeprom->address_bits, eeprom->sw_addr);
62 
63 	return 0;
64 }
65 
66 /**
67  *  txgbe_get_eeprom_semaphore - Get hardware semaphore
68  *  @hw: pointer to hardware structure
69  *
70  *  Sets the hardware semaphores so EEPROM access can occur for bit-bang method
71  **/
txgbe_get_eeprom_semaphore(struct txgbe_hw * hw)72 s32 txgbe_get_eeprom_semaphore(struct txgbe_hw *hw)
73 {
74 	s32 status = TXGBE_ERR_EEPROM;
75 	u32 timeout = 2000;
76 	u32 i;
77 	u32 swsm;
78 
79 	/* Get SMBI software semaphore between device drivers first */
80 	for (i = 0; i < timeout; i++) {
81 		/*
82 		 * If the SMBI bit is 0 when we read it, then the bit will be
83 		 * set and we have the semaphore
84 		 */
85 		swsm = rd32(hw, TXGBE_SWSEM);
86 		if (!(swsm & TXGBE_SWSEM_PF)) {
87 			status = 0;
88 			break;
89 		}
90 		usec_delay(50);
91 	}
92 
93 	if (i == timeout) {
94 		DEBUGOUT("Driver can't access the eeprom - SMBI Semaphore not granted.");
95 		/*
96 		 * this release is particularly important because our attempts
97 		 * above to get the semaphore may have succeeded, and if there
98 		 * was a timeout, we should unconditionally clear the semaphore
99 		 * bits to free the driver to make progress
100 		 */
101 		txgbe_release_eeprom_semaphore(hw);
102 
103 		usec_delay(50);
104 		/*
105 		 * one last try
106 		 * If the SMBI bit is 0 when we read it, then the bit will be
107 		 * set and we have the semaphore
108 		 */
109 		swsm = rd32(hw, TXGBE_SWSEM);
110 		if (!(swsm & TXGBE_SWSEM_PF))
111 			status = 0;
112 	}
113 
114 	/* Now get the semaphore between SW/FW through the SWESMBI bit */
115 	if (status == 0) {
116 		for (i = 0; i < timeout; i++) {
117 			/* Set the SW EEPROM semaphore bit to request access */
118 			wr32m(hw, TXGBE_MNGSWSYNC,
119 				TXGBE_MNGSWSYNC_REQ, TXGBE_MNGSWSYNC_REQ);
120 
121 			/*
122 			 * If we set the bit successfully then we got the
123 			 * semaphore.
124 			 */
125 			swsm = rd32(hw, TXGBE_MNGSWSYNC);
126 			if (swsm & TXGBE_MNGSWSYNC_REQ)
127 				break;
128 
129 			usec_delay(50);
130 		}
131 
132 		/*
133 		 * Release semaphores and return error if SW EEPROM semaphore
134 		 * was not granted because we don't have access to the EEPROM
135 		 */
136 		if (i >= timeout) {
137 			DEBUGOUT("SWESMBI Software EEPROM semaphore not granted.");
138 			txgbe_release_eeprom_semaphore(hw);
139 			status = TXGBE_ERR_EEPROM;
140 		}
141 	} else {
142 		DEBUGOUT("Software semaphore SMBI between device drivers not granted.");
143 	}
144 
145 	return status;
146 }
147 
148 /**
149  *  txgbe_release_eeprom_semaphore - Release hardware semaphore
150  *  @hw: pointer to hardware structure
151  *
152  *  This function clears hardware semaphore bits.
153  **/
txgbe_release_eeprom_semaphore(struct txgbe_hw * hw)154 void txgbe_release_eeprom_semaphore(struct txgbe_hw *hw)
155 {
156 	wr32m(hw, TXGBE_MNGSWSYNC, TXGBE_MNGSWSYNC_REQ, 0);
157 	wr32m(hw, TXGBE_SWSEM, TXGBE_SWSEM_PF, 0);
158 	txgbe_flush(hw);
159 }
160 
161 /**
162  *  txgbe_ee_read - Read EEPROM word using a host interface cmd
163  *  @hw: pointer to hardware structure
164  *  @offset: offset of  word in the EEPROM to read
165  *  @data: word read from the EEPROM
166  *
167  *  Reads a 16 bit word from the EEPROM using the hostif.
168  **/
txgbe_ee_read16(struct txgbe_hw * hw,u32 offset,u16 * data)169 s32 txgbe_ee_read16(struct txgbe_hw *hw, u32 offset,
170 			      u16 *data)
171 {
172 	const u32 mask = TXGBE_MNGSEM_SWMBX | TXGBE_MNGSEM_SWFLASH;
173 	u32 addr = (offset << 1);
174 	int err;
175 
176 	err = hw->mac.acquire_swfw_sync(hw, mask);
177 	if (err)
178 		return err;
179 
180 	err = txgbe_hic_sr_read(hw, addr, (u8 *)data, 2);
181 
182 	hw->mac.release_swfw_sync(hw, mask);
183 
184 	return err;
185 }
186 
187 /**
188  *  txgbe_ee_readw_buffer- Read EEPROM word(s) using hostif
189  *  @hw: pointer to hardware structure
190  *  @offset: offset of  word in the EEPROM to read
191  *  @words: number of words
192  *  @data: word(s) read from the EEPROM
193  *
194  *  Reads a 16 bit word(s) from the EEPROM using the hostif.
195  **/
txgbe_ee_readw_buffer(struct txgbe_hw * hw,u32 offset,u32 words,void * data)196 s32 txgbe_ee_readw_buffer(struct txgbe_hw *hw,
197 				     u32 offset, u32 words, void *data)
198 {
199 	const u32 mask = TXGBE_MNGSEM_SWMBX | TXGBE_MNGSEM_SWFLASH;
200 	u32 addr = (offset << 1);
201 	u32 len = (words << 1);
202 	u8 *buf = (u8 *)data;
203 	int err;
204 
205 	err = hw->mac.acquire_swfw_sync(hw, mask);
206 	if (err)
207 		return err;
208 
209 	while (len) {
210 		u32 seg = (len <= TXGBE_PMMBX_DATA_SIZE
211 				? len : TXGBE_PMMBX_DATA_SIZE);
212 
213 		err = txgbe_hic_sr_read(hw, addr, buf, seg);
214 		if (err)
215 			break;
216 
217 		len -= seg;
218 		addr += seg;
219 		buf += seg;
220 	}
221 
222 	hw->mac.release_swfw_sync(hw, mask);
223 	return err;
224 }
225 
226 
txgbe_ee_readw_sw(struct txgbe_hw * hw,u32 offset,u16 * data)227 s32 txgbe_ee_readw_sw(struct txgbe_hw *hw, u32 offset,
228 			      u16 *data)
229 {
230 	const u32 mask = TXGBE_MNGSEM_SWMBX | TXGBE_MNGSEM_SWFLASH;
231 	u32 addr = hw->rom.sw_addr + (offset << 1);
232 	int err;
233 
234 	err = hw->mac.acquire_swfw_sync(hw, mask);
235 	if (err)
236 		return err;
237 
238 	err = txgbe_hic_sr_read(hw, addr, (u8 *)data, 2);
239 
240 	hw->mac.release_swfw_sync(hw, mask);
241 
242 	return err;
243 }
244 
245 /**
246  *  txgbe_ee_read32 - Read EEPROM word using a host interface cmd
247  *  @hw: pointer to hardware structure
248  *  @offset: offset of  word in the EEPROM to read
249  *  @data: word read from the EEPROM
250  *
251  *  Reads a 32 bit word from the EEPROM using the hostif.
252  **/
txgbe_ee_read32(struct txgbe_hw * hw,u32 addr,u32 * data)253 s32 txgbe_ee_read32(struct txgbe_hw *hw, u32 addr, u32 *data)
254 {
255 	const u32 mask = TXGBE_MNGSEM_SWMBX | TXGBE_MNGSEM_SWFLASH;
256 	int err;
257 
258 	err = hw->mac.acquire_swfw_sync(hw, mask);
259 	if (err)
260 		return err;
261 
262 	err = txgbe_hic_sr_read(hw, addr, (u8 *)data, 4);
263 
264 	hw->mac.release_swfw_sync(hw, mask);
265 
266 	return err;
267 }
268 
269 /**
270  *  txgbe_ee_write - Write EEPROM word using hostif
271  *  @hw: pointer to hardware structure
272  *  @offset: offset of  word in the EEPROM to write
273  *  @data: word write to the EEPROM
274  *
275  *  Write a 16 bit word to the EEPROM using the hostif.
276  **/
txgbe_ee_write16(struct txgbe_hw * hw,u32 offset,u16 data)277 s32 txgbe_ee_write16(struct txgbe_hw *hw, u32 offset,
278 			       u16 data)
279 {
280 	const u32 mask = TXGBE_MNGSEM_SWMBX | TXGBE_MNGSEM_SWFLASH;
281 	u32 addr = (offset << 1);
282 	int err;
283 
284 	err = hw->mac.acquire_swfw_sync(hw, mask);
285 	if (err)
286 		return err;
287 
288 	err = txgbe_hic_sr_write(hw, addr, (u8 *)&data, 2);
289 
290 	hw->mac.release_swfw_sync(hw, mask);
291 
292 	return err;
293 }
294 
295 /**
296  *  txgbe_ee_writew_buffer - Write EEPROM word(s) using hostif
297  *  @hw: pointer to hardware structure
298  *  @offset: offset of  word in the EEPROM to write
299  *  @words: number of words
300  *  @data: word(s) write to the EEPROM
301  *
302  *  Write a 16 bit word(s) to the EEPROM using the hostif.
303  **/
txgbe_ee_writew_buffer(struct txgbe_hw * hw,u32 offset,u32 words,void * data)304 s32 txgbe_ee_writew_buffer(struct txgbe_hw *hw,
305 				      u32 offset, u32 words, void *data)
306 {
307 	const u32 mask = TXGBE_MNGSEM_SWMBX | TXGBE_MNGSEM_SWFLASH;
308 	u32 addr = (offset << 1);
309 	u32 len = (words << 1);
310 	u8 *buf = (u8 *)data;
311 	int err;
312 
313 	err = hw->mac.acquire_swfw_sync(hw, mask);
314 	if (err)
315 		return err;
316 
317 	while (len) {
318 		u32 seg = (len <= TXGBE_PMMBX_DATA_SIZE
319 				? len : TXGBE_PMMBX_DATA_SIZE);
320 
321 		err = txgbe_hic_sr_write(hw, addr, buf, seg);
322 		if (err)
323 			break;
324 
325 		len -= seg;
326 		buf += seg;
327 	}
328 
329 	hw->mac.release_swfw_sync(hw, mask);
330 	return err;
331 }
332 
txgbe_ee_writew_sw(struct txgbe_hw * hw,u32 offset,u16 data)333 s32 txgbe_ee_writew_sw(struct txgbe_hw *hw, u32 offset,
334 			       u16 data)
335 {
336 	const u32 mask = TXGBE_MNGSEM_SWMBX | TXGBE_MNGSEM_SWFLASH;
337 	u32 addr = hw->rom.sw_addr + (offset << 1);
338 	int err;
339 
340 	err = hw->mac.acquire_swfw_sync(hw, mask);
341 	if (err)
342 		return err;
343 
344 	err = txgbe_hic_sr_write(hw, addr, (u8 *)&data, 2);
345 
346 	hw->mac.release_swfw_sync(hw, mask);
347 
348 	return err;
349 }
350 
351 /**
352  *  txgbe_ee_write32 - Read EEPROM word using a host interface cmd
353  *  @hw: pointer to hardware structure
354  *  @offset: offset of  word in the EEPROM to read
355  *  @data: word read from the EEPROM
356  *
357  *  Reads a 32 bit word from the EEPROM using the hostif.
358  **/
txgbe_ee_write32(struct txgbe_hw * hw,u32 addr,u32 data)359 s32 txgbe_ee_write32(struct txgbe_hw *hw, u32 addr, u32 data)
360 {
361 	const u32 mask = TXGBE_MNGSEM_SWMBX | TXGBE_MNGSEM_SWFLASH;
362 	int err;
363 
364 	err = hw->mac.acquire_swfw_sync(hw, mask);
365 	if (err)
366 		return err;
367 
368 	err = txgbe_hic_sr_write(hw, addr, (u8 *)&data, 4);
369 
370 	hw->mac.release_swfw_sync(hw, mask);
371 
372 	return err;
373 }
374 
375 /**
376  *  txgbe_calc_eeprom_checksum - Calculates and returns the checksum
377  *  @hw: pointer to hardware structure
378  *
379  *  Returns a negative error code on error, or the 16-bit checksum
380  **/
381 #define BUFF_SIZE  64
txgbe_calc_eeprom_checksum(struct txgbe_hw * hw)382 s32 txgbe_calc_eeprom_checksum(struct txgbe_hw *hw)
383 {
384 	u16 checksum = 0, read_checksum = 0;
385 	int i, j, seg;
386 	int err;
387 	u16 buffer[BUFF_SIZE];
388 
389 	err = hw->rom.readw_sw(hw, TXGBE_EEPROM_CHECKSUM, &read_checksum);
390 	if (err) {
391 		DEBUGOUT("EEPROM read failed");
392 		return err;
393 	}
394 
395 	for (i = 0; i < TXGBE_EE_CSUM_MAX; i += seg) {
396 		seg = (i + BUFF_SIZE < TXGBE_EE_CSUM_MAX
397 		       ? BUFF_SIZE : TXGBE_EE_CSUM_MAX - i);
398 		err = hw->rom.readw_buffer(hw, i, seg, buffer);
399 		if (err)
400 			return err;
401 		for (j = 0; j < seg; j++)
402 			checksum += buffer[j];
403 	}
404 
405 	checksum = (u16)TXGBE_EEPROM_SUM - checksum + read_checksum;
406 
407 	return (s32)checksum;
408 }
409 
410 /**
411  *  txgbe_validate_eeprom_checksum - Validate EEPROM checksum
412  *  @hw: pointer to hardware structure
413  *  @checksum_val: calculated checksum
414  *
415  *  Performs checksum calculation and validates the EEPROM checksum.  If the
416  *  caller does not need checksum_val, the value can be NULL.
417  **/
txgbe_validate_eeprom_checksum(struct txgbe_hw * hw,u16 * checksum_val)418 s32 txgbe_validate_eeprom_checksum(struct txgbe_hw *hw,
419 					   u16 *checksum_val)
420 {
421 	u16 checksum;
422 	u16 read_checksum = 0;
423 	int err;
424 
425 	/* Read the first word from the EEPROM. If this times out or fails, do
426 	 * not continue or we could be in for a very long wait while every
427 	 * EEPROM read fails
428 	 */
429 	err = hw->rom.read16(hw, 0, &checksum);
430 	if (err) {
431 		DEBUGOUT("EEPROM read failed");
432 		return err;
433 	}
434 
435 	err = hw->rom.calc_checksum(hw);
436 	if (err < 0)
437 		return err;
438 
439 	checksum = (u16)(err & 0xffff);
440 
441 	err = hw->rom.readw_sw(hw, TXGBE_EEPROM_CHECKSUM, &read_checksum);
442 	if (err) {
443 		DEBUGOUT("EEPROM read failed");
444 		return err;
445 	}
446 
447 	/* Verify read checksum from EEPROM is the same as
448 	 * calculated checksum
449 	 */
450 	if (read_checksum != checksum) {
451 		err = TXGBE_ERR_EEPROM_CHECKSUM;
452 		DEBUGOUT("EEPROM checksum error");
453 	}
454 
455 	/* If the user cares, return the calculated checksum */
456 	if (checksum_val)
457 		*checksum_val = checksum;
458 
459 	return err;
460 }
461 
462 /**
463  *  txgbe_update_eeprom_checksum - Updates the EEPROM checksum
464  *  @hw: pointer to hardware structure
465  **/
txgbe_update_eeprom_checksum(struct txgbe_hw * hw)466 s32 txgbe_update_eeprom_checksum(struct txgbe_hw *hw)
467 {
468 	s32 status;
469 	u16 checksum;
470 
471 	/* Read the first word from the EEPROM. If this times out or fails, do
472 	 * not continue or we could be in for a very long wait while every
473 	 * EEPROM read fails
474 	 */
475 	status = hw->rom.read16(hw, 0, &checksum);
476 	if (status) {
477 		DEBUGOUT("EEPROM read failed");
478 		return status;
479 	}
480 
481 	status = hw->rom.calc_checksum(hw);
482 	if (status < 0)
483 		return status;
484 
485 	checksum = (u16)(status & 0xffff);
486 
487 	status = hw->rom.writew_sw(hw, TXGBE_EEPROM_CHECKSUM, checksum);
488 
489 	return status;
490 }
491 
492