1283514Sarybchik/*-
2300607Sarybchik * Copyright (c) 2010-2016 Solarflare Communications, Inc.
3283514Sarybchik * All rights reserved.
4283514Sarybchik *
5283514Sarybchik * This software was developed in part by OKTET Labs Ltd. under contract for
6283514Sarybchik * Solarflare Communications, Inc.
7283514Sarybchik *
8283514Sarybchik * Redistribution and use in source and binary forms, with or without
9283514Sarybchik * modification, are permitted provided that the following conditions
10283514Sarybchik * are met:
11283514Sarybchik * 1. Redistributions of source code must retain the above copyright
12283514Sarybchik *    notice, this list of conditions and the following disclaimer.
13283514Sarybchik * 2. Redistributions in binary form must reproduce the above copyright
14283514Sarybchik *    notice, this list of conditions and the following disclaimer in the
15283514Sarybchik *    documentation and/or other materials provided with the distribution.
16283514Sarybchik *
17283514Sarybchik * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18283514Sarybchik * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19283514Sarybchik * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20283514Sarybchik * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21283514Sarybchik * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22283514Sarybchik * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23283514Sarybchik * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24283514Sarybchik * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25283514Sarybchik * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26283514Sarybchik * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27283514Sarybchik * SUCH DAMAGE.
28283514Sarybchik */
29283514Sarybchik
30283514Sarybchik#include <sys/cdefs.h>
31283514Sarybchik__FBSDID("$FreeBSD: releng/11.0/sys/dev/sfxge/sfxge_nvram.c 300607 2016-05-24 12:16:57Z arybchik $");
32283514Sarybchik
33283514Sarybchik
34283514Sarybchik#include <sys/types.h>
35283514Sarybchik#include <sys/malloc.h>
36283514Sarybchik
37283514Sarybchik#include "common/efx.h"
38283514Sarybchik#include "sfxge.h"
39283514Sarybchik
40283514Sarybchik/* These data make no real sense, they are here just to make sfupdate happy.
41283514Sarybchik * Any code that would rely on it is broken.
42283514Sarybchik */
43283514Sarybchikstatic const uint8_t fake_dynamic_cfg_nvram[] = {
44283514Sarybchik	0x7a, 0xda, 0x10, 0xef, 0x0c, 0x00, 0x00, 0x00,
45283514Sarybchik	0x00, 0x05, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
46283514Sarybchik	0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x10,
47283514Sarybchik	0x08, 0x00, 0x00, 0x00, 0x90, 0x04, 0x00, 0x52,
48283514Sarybchik	0x56, 0x01, 0xc3, 0x78, 0x01, 0x00, 0x03, 0x10,
49283514Sarybchik	0x08, 0x00, 0x00, 0x00, 0x90, 0x04, 0x00, 0x52,
50283514Sarybchik	0x56, 0x01, 0xc3, 0x78, 0x57, 0x1a, 0x10, 0xef,
51283514Sarybchik	0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
52283514Sarybchik	0x02, 0x0b, 0x64, 0x7d, 0xee, 0xee, 0xee, 0xee
53283514Sarybchik};
54283514Sarybchik
55283514Sarybchikstatic int
56283514Sarybchiksfxge_nvram_rw(struct sfxge_softc *sc, sfxge_ioc_t *ip, efx_nvram_type_t type,
57283514Sarybchik	       boolean_t write)
58283514Sarybchik{
59283514Sarybchik	efx_nic_t *enp = sc->enp;
60283514Sarybchik	size_t total_size = ip->u.nvram.size;
61283514Sarybchik	size_t chunk_size;
62283514Sarybchik	off_t off;
63283514Sarybchik	int rc = 0;
64283514Sarybchik	uint8_t *buf;
65283514Sarybchik
66283514Sarybchik	if (type == EFX_NVRAM_DYNAMIC_CFG && sc->family == EFX_FAMILY_SIENA) {
67283514Sarybchik		if (write)
68283514Sarybchik			return (0);
69283514Sarybchik		rc = copyout(fake_dynamic_cfg_nvram, ip->u.nvram.data,
70283514Sarybchik			     MIN(total_size, sizeof(fake_dynamic_cfg_nvram)));
71283514Sarybchik		return (rc);
72283514Sarybchik	}
73283514Sarybchik
74283514Sarybchik	if ((rc = efx_nvram_rw_start(enp, type, &chunk_size)) != 0)
75283514Sarybchik		goto fail1;
76283514Sarybchik
77283514Sarybchik	buf = malloc(chunk_size, M_TEMP, M_WAITOK);
78283514Sarybchik
79283514Sarybchik	off = 0;
80283514Sarybchik	while (total_size) {
81283514Sarybchik		size_t len = MIN(chunk_size, total_size);
82283514Sarybchik
83283514Sarybchik		if (write) {
84283514Sarybchik			rc = copyin(ip->u.nvram.data + off, buf, len);
85283514Sarybchik			if (rc != 0)
86283514Sarybchik				goto fail3;
87283514Sarybchik			rc = efx_nvram_write_chunk(enp, type,
88283514Sarybchik						   ip->u.nvram.offset + off, buf, len);
89283514Sarybchik			if (rc != 0)
90283514Sarybchik				goto fail3;
91283514Sarybchik		} else {
92283514Sarybchik			rc = efx_nvram_read_chunk(enp, type,
93283514Sarybchik						  ip->u.nvram.offset + off, buf, len);
94283514Sarybchik			if (rc != 0)
95283514Sarybchik				goto fail3;
96283514Sarybchik			rc = copyout(buf, ip->u.nvram.data + off, len);
97283514Sarybchik			if (rc != 0)
98283514Sarybchik				goto fail3;
99283514Sarybchik		}
100283514Sarybchik
101283514Sarybchik		total_size -= len;
102283514Sarybchik		off += len;
103283514Sarybchik	}
104283514Sarybchik
105283514Sarybchikfail3:
106283514Sarybchik	free(buf, M_TEMP);
107283514Sarybchik	efx_nvram_rw_finish(enp, type);
108283514Sarybchikfail1:
109283514Sarybchik	return (rc);
110283514Sarybchik}
111283514Sarybchik
112283514Sarybchik
113283514Sarybchikstatic int
114283514Sarybchiksfxge_nvram_erase(struct sfxge_softc *sc, efx_nvram_type_t type)
115283514Sarybchik{
116283514Sarybchik	efx_nic_t *enp = sc->enp;
117283514Sarybchik	size_t chunk_size;
118283514Sarybchik	int rc = 0;
119283514Sarybchik
120283514Sarybchik	if (type == EFX_NVRAM_DYNAMIC_CFG && sc->family == EFX_FAMILY_SIENA)
121283514Sarybchik		return (0);
122283514Sarybchik
123283514Sarybchik	if ((rc = efx_nvram_rw_start(enp, type, &chunk_size)) != 0)
124283514Sarybchik		return (rc);
125283514Sarybchik
126283514Sarybchik	rc = efx_nvram_erase(enp, type);
127283514Sarybchik
128283514Sarybchik	efx_nvram_rw_finish(enp, type);
129283514Sarybchik	return (rc);
130283514Sarybchik}
131283514Sarybchik
132283514Sarybchikint
133283514Sarybchiksfxge_nvram_ioctl(struct sfxge_softc *sc, sfxge_ioc_t *ip)
134283514Sarybchik{
135283514Sarybchik	static const efx_nvram_type_t nvram_types[] = {
136283514Sarybchik		[SFXGE_NVRAM_TYPE_BOOTROM]  = EFX_NVRAM_BOOTROM,
137283514Sarybchik		[SFXGE_NVRAM_TYPE_BOOTROM_CFG]  = EFX_NVRAM_BOOTROM_CFG,
138283514Sarybchik		[SFXGE_NVRAM_TYPE_MC]  = EFX_NVRAM_MC_FIRMWARE,
139283514Sarybchik		[SFXGE_NVRAM_TYPE_MC_GOLDEN]  = EFX_NVRAM_MC_GOLDEN,
140283514Sarybchik		[SFXGE_NVRAM_TYPE_PHY]  = EFX_NVRAM_PHY,
141283514Sarybchik		[SFXGE_NVRAM_TYPE_NULL_PHY]  = EFX_NVRAM_NULLPHY,
142283514Sarybchik		[SFXGE_NVRAM_TYPE_FPGA]  = EFX_NVRAM_FPGA,
143283514Sarybchik		[SFXGE_NVRAM_TYPE_FCFW]  = EFX_NVRAM_FCFW,
144283514Sarybchik		[SFXGE_NVRAM_TYPE_CPLD]  = EFX_NVRAM_CPLD,
145283514Sarybchik		[SFXGE_NVRAM_TYPE_FPGA_BACKUP]  = EFX_NVRAM_FPGA_BACKUP,
146283514Sarybchik		[SFXGE_NVRAM_TYPE_DYNAMIC_CFG]  = EFX_NVRAM_DYNAMIC_CFG,
147283514Sarybchik	};
148283514Sarybchik
149283514Sarybchik	efx_nic_t *enp = sc->enp;
150283514Sarybchik	efx_nvram_type_t type;
151283514Sarybchik	int rc = 0;
152283514Sarybchik
153283514Sarybchik	if (ip->u.nvram.type > SFXGE_NVRAM_TYPE_DYNAMIC_CFG)
154283514Sarybchik		return (EINVAL);
155283514Sarybchik	type = nvram_types[ip->u.nvram.type];
156283514Sarybchik	if (type == EFX_NVRAM_MC_GOLDEN &&
157283514Sarybchik	    (ip->u.nvram.op == SFXGE_NVRAM_OP_WRITE ||
158283514Sarybchik	     ip->u.nvram.op == SFXGE_NVRAM_OP_ERASE ||
159283514Sarybchik	     ip->u.nvram.op == SFXGE_NVRAM_OP_SET_VER))
160283514Sarybchik		return (EOPNOTSUPP);
161283514Sarybchik
162283514Sarybchik	switch (ip->u.nvram.op) {
163283514Sarybchik	case SFXGE_NVRAM_OP_SIZE:
164283514Sarybchik	{
165283514Sarybchik		size_t size;
166283514Sarybchik
167283514Sarybchik		if (type == EFX_NVRAM_DYNAMIC_CFG && sc->family == EFX_FAMILY_SIENA) {
168283514Sarybchik			ip->u.nvram.size = sizeof(fake_dynamic_cfg_nvram);
169283514Sarybchik		} else {
170283514Sarybchik			if ((rc = efx_nvram_size(enp, type, &size)) != 0)
171283514Sarybchik				return (rc);
172283514Sarybchik			ip->u.nvram.size = size;
173283514Sarybchik		}
174283514Sarybchik		break;
175283514Sarybchik	}
176283514Sarybchik	case SFXGE_NVRAM_OP_READ:
177283514Sarybchik		rc = sfxge_nvram_rw(sc, ip, type, B_FALSE);
178283514Sarybchik		break;
179283514Sarybchik	case SFXGE_NVRAM_OP_WRITE:
180283514Sarybchik		rc = sfxge_nvram_rw(sc, ip, type, B_TRUE);
181283514Sarybchik		break;
182283514Sarybchik	case SFXGE_NVRAM_OP_ERASE:
183283514Sarybchik		rc = sfxge_nvram_erase(sc, type);
184283514Sarybchik		break;
185283514Sarybchik	case SFXGE_NVRAM_OP_GET_VER:
186283514Sarybchik		rc = efx_nvram_get_version(enp, type, &ip->u.nvram.subtype,
187283514Sarybchik					   &ip->u.nvram.version[0]);
188283514Sarybchik		break;
189283514Sarybchik	case SFXGE_NVRAM_OP_SET_VER:
190283514Sarybchik		rc = efx_nvram_set_version(enp, type, &ip->u.nvram.version[0]);
191283514Sarybchik		break;
192283514Sarybchik	default:
193283514Sarybchik		rc = EOPNOTSUPP;
194283514Sarybchik		break;
195283514Sarybchik	}
196283514Sarybchik
197283514Sarybchik	return (rc);
198283514Sarybchik}
199