xref: /OK3568_Linux_fs/kernel/drivers/scsi/isci/probe_roms.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * This file is provided under a dual BSD/GPLv2 license.  When using or
3*4882a593Smuzhiyun  * redistributing this file, you may do so under either license.
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * GPL LICENSE SUMMARY
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * This program is free software; you can redistribute it and/or modify
10*4882a593Smuzhiyun  * it under the terms of version 2 of the GNU General Public License as
11*4882a593Smuzhiyun  * published by the Free Software Foundation.
12*4882a593Smuzhiyun  *
13*4882a593Smuzhiyun  * This program is distributed in the hope that it will be useful, but
14*4882a593Smuzhiyun  * WITHOUT ANY WARRANTY; without even the implied warranty of
15*4882a593Smuzhiyun  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16*4882a593Smuzhiyun  * General Public License for more details.
17*4882a593Smuzhiyun  *
18*4882a593Smuzhiyun  * You should have received a copy of the GNU General Public License
19*4882a593Smuzhiyun  * along with this program; if not, write to the Free Software
20*4882a593Smuzhiyun  * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
21*4882a593Smuzhiyun  * The full GNU General Public License is included in this distribution
22*4882a593Smuzhiyun  * in the file called LICENSE.GPL.
23*4882a593Smuzhiyun  */
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun /* probe_roms - scan for oem parameters */
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun #include <linux/kernel.h>
28*4882a593Smuzhiyun #include <linux/firmware.h>
29*4882a593Smuzhiyun #include <linux/uaccess.h>
30*4882a593Smuzhiyun #include <linux/efi.h>
31*4882a593Smuzhiyun #include <asm/probe_roms.h>
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun #include "isci.h"
34*4882a593Smuzhiyun #include "task.h"
35*4882a593Smuzhiyun #include "probe_roms.h"
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun static efi_char16_t isci_efivar_name[] = {
38*4882a593Smuzhiyun 	'R', 's', 't', 'S', 'c', 'u', 'O'
39*4882a593Smuzhiyun };
40*4882a593Smuzhiyun 
isci_request_oprom(struct pci_dev * pdev)41*4882a593Smuzhiyun struct isci_orom *isci_request_oprom(struct pci_dev *pdev)
42*4882a593Smuzhiyun {
43*4882a593Smuzhiyun 	void __iomem *oprom = pci_map_biosrom(pdev);
44*4882a593Smuzhiyun 	struct isci_orom *rom = NULL;
45*4882a593Smuzhiyun 	size_t len, i;
46*4882a593Smuzhiyun 	int j;
47*4882a593Smuzhiyun 	char oem_sig[4];
48*4882a593Smuzhiyun 	struct isci_oem_hdr oem_hdr;
49*4882a593Smuzhiyun 	u8 *tmp, sum;
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun 	if (!oprom)
52*4882a593Smuzhiyun 		return NULL;
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun 	len = pci_biosrom_size(pdev);
55*4882a593Smuzhiyun 	rom = devm_kzalloc(&pdev->dev, sizeof(*rom), GFP_KERNEL);
56*4882a593Smuzhiyun 	if (!rom) {
57*4882a593Smuzhiyun 		pci_unmap_biosrom(oprom);
58*4882a593Smuzhiyun 		dev_warn(&pdev->dev,
59*4882a593Smuzhiyun 			 "Unable to allocate memory for orom\n");
60*4882a593Smuzhiyun 		return NULL;
61*4882a593Smuzhiyun 	}
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun 	for (i = 0; i < len && rom; i += ISCI_OEM_SIG_SIZE) {
64*4882a593Smuzhiyun 		memcpy_fromio(oem_sig, oprom + i, ISCI_OEM_SIG_SIZE);
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun 		/* we think we found the OEM table */
67*4882a593Smuzhiyun 		if (memcmp(oem_sig, ISCI_OEM_SIG, ISCI_OEM_SIG_SIZE) == 0) {
68*4882a593Smuzhiyun 			size_t copy_len;
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun 			memcpy_fromio(&oem_hdr, oprom + i, sizeof(oem_hdr));
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun 			copy_len = min(oem_hdr.len - sizeof(oem_hdr),
73*4882a593Smuzhiyun 				       sizeof(*rom));
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun 			memcpy_fromio(rom,
76*4882a593Smuzhiyun 				      oprom + i + sizeof(oem_hdr),
77*4882a593Smuzhiyun 				      copy_len);
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun 			/* calculate checksum */
80*4882a593Smuzhiyun 			tmp = (u8 *)&oem_hdr;
81*4882a593Smuzhiyun 			for (j = 0, sum = 0; j < sizeof(oem_hdr); j++, tmp++)
82*4882a593Smuzhiyun 				sum += *tmp;
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun 			tmp = (u8 *)rom;
85*4882a593Smuzhiyun 			for (j = 0; j < sizeof(*rom); j++, tmp++)
86*4882a593Smuzhiyun 				sum += *tmp;
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun 			if (sum != 0) {
89*4882a593Smuzhiyun 				dev_warn(&pdev->dev,
90*4882a593Smuzhiyun 					 "OEM table checksum failed\n");
91*4882a593Smuzhiyun 				continue;
92*4882a593Smuzhiyun 			}
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 			/* keep going if that's not the oem param table */
95*4882a593Smuzhiyun 			if (memcmp(rom->hdr.signature,
96*4882a593Smuzhiyun 				   ISCI_ROM_SIG,
97*4882a593Smuzhiyun 				   ISCI_ROM_SIG_SIZE) != 0)
98*4882a593Smuzhiyun 				continue;
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun 			dev_info(&pdev->dev,
101*4882a593Smuzhiyun 				 "OEM parameter table found in OROM\n");
102*4882a593Smuzhiyun 			break;
103*4882a593Smuzhiyun 		}
104*4882a593Smuzhiyun 	}
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun 	if (i >= len) {
107*4882a593Smuzhiyun 		dev_err(&pdev->dev, "oprom parse error\n");
108*4882a593Smuzhiyun 		rom = NULL;
109*4882a593Smuzhiyun 	}
110*4882a593Smuzhiyun 	pci_unmap_biosrom(oprom);
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun 	return rom;
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun 
isci_request_firmware(struct pci_dev * pdev,const struct firmware * fw)115*4882a593Smuzhiyun struct isci_orom *isci_request_firmware(struct pci_dev *pdev, const struct firmware *fw)
116*4882a593Smuzhiyun {
117*4882a593Smuzhiyun 	struct isci_orom *orom = NULL, *data;
118*4882a593Smuzhiyun 	int i, j;
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 	if (request_firmware(&fw, ISCI_FW_NAME, &pdev->dev) != 0)
121*4882a593Smuzhiyun 		return NULL;
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 	if (fw->size < sizeof(*orom))
124*4882a593Smuzhiyun 		goto out;
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun 	data = (struct isci_orom *)fw->data;
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun 	if (strncmp(ISCI_ROM_SIG, data->hdr.signature,
129*4882a593Smuzhiyun 		    strlen(ISCI_ROM_SIG)) != 0)
130*4882a593Smuzhiyun 		goto out;
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun 	orom = devm_kzalloc(&pdev->dev, fw->size, GFP_KERNEL);
133*4882a593Smuzhiyun 	if (!orom)
134*4882a593Smuzhiyun 		goto out;
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 	memcpy(orom, fw->data, fw->size);
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 	if (is_c0(pdev) || is_c1(pdev))
139*4882a593Smuzhiyun 		goto out;
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	/*
142*4882a593Smuzhiyun 	 * deprecated: override default amp_control for pre-preproduction
143*4882a593Smuzhiyun 	 * silicon revisions
144*4882a593Smuzhiyun 	 */
145*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(orom->ctrl); i++)
146*4882a593Smuzhiyun 		for (j = 0; j < ARRAY_SIZE(orom->ctrl[i].phys); j++) {
147*4882a593Smuzhiyun 			orom->ctrl[i].phys[j].afe_tx_amp_control0 = 0xe7c03;
148*4882a593Smuzhiyun 			orom->ctrl[i].phys[j].afe_tx_amp_control1 = 0xe7c03;
149*4882a593Smuzhiyun 			orom->ctrl[i].phys[j].afe_tx_amp_control2 = 0xe7c03;
150*4882a593Smuzhiyun 			orom->ctrl[i].phys[j].afe_tx_amp_control3 = 0xe7c03;
151*4882a593Smuzhiyun 		}
152*4882a593Smuzhiyun  out:
153*4882a593Smuzhiyun 	release_firmware(fw);
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 	return orom;
156*4882a593Smuzhiyun }
157*4882a593Smuzhiyun 
get_efi(void)158*4882a593Smuzhiyun static struct efi *get_efi(void)
159*4882a593Smuzhiyun {
160*4882a593Smuzhiyun #ifdef CONFIG_EFI
161*4882a593Smuzhiyun 	return &efi;
162*4882a593Smuzhiyun #else
163*4882a593Smuzhiyun 	return NULL;
164*4882a593Smuzhiyun #endif
165*4882a593Smuzhiyun }
166*4882a593Smuzhiyun 
isci_get_efi_var(struct pci_dev * pdev)167*4882a593Smuzhiyun struct isci_orom *isci_get_efi_var(struct pci_dev *pdev)
168*4882a593Smuzhiyun {
169*4882a593Smuzhiyun 	efi_status_t status;
170*4882a593Smuzhiyun 	struct isci_orom *rom;
171*4882a593Smuzhiyun 	struct isci_oem_hdr *oem_hdr;
172*4882a593Smuzhiyun 	u8 *tmp, sum;
173*4882a593Smuzhiyun 	int j;
174*4882a593Smuzhiyun 	unsigned long data_len;
175*4882a593Smuzhiyun 	u8 *efi_data;
176*4882a593Smuzhiyun 	u32 efi_attrib = 0;
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun 	data_len = 1024;
179*4882a593Smuzhiyun 	efi_data = devm_kzalloc(&pdev->dev, data_len, GFP_KERNEL);
180*4882a593Smuzhiyun 	if (!efi_data) {
181*4882a593Smuzhiyun 		dev_warn(&pdev->dev,
182*4882a593Smuzhiyun 			 "Unable to allocate memory for EFI data\n");
183*4882a593Smuzhiyun 		return NULL;
184*4882a593Smuzhiyun 	}
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun 	rom = (struct isci_orom *)(efi_data + sizeof(struct isci_oem_hdr));
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 	if (get_efi())
189*4882a593Smuzhiyun 		status = get_efi()->get_variable(isci_efivar_name,
190*4882a593Smuzhiyun 						 &ISCI_EFI_VENDOR_GUID,
191*4882a593Smuzhiyun 						 &efi_attrib,
192*4882a593Smuzhiyun 						 &data_len,
193*4882a593Smuzhiyun 						 efi_data);
194*4882a593Smuzhiyun 	else
195*4882a593Smuzhiyun 		status = EFI_NOT_FOUND;
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun 	if (status != EFI_SUCCESS) {
198*4882a593Smuzhiyun 		dev_warn(&pdev->dev,
199*4882a593Smuzhiyun 			 "Unable to obtain EFI var data for OEM parms\n");
200*4882a593Smuzhiyun 		return NULL;
201*4882a593Smuzhiyun 	}
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 	oem_hdr = (struct isci_oem_hdr *)efi_data;
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun 	if (memcmp(oem_hdr->sig, ISCI_OEM_SIG, ISCI_OEM_SIG_SIZE) != 0) {
206*4882a593Smuzhiyun 		dev_warn(&pdev->dev,
207*4882a593Smuzhiyun 			 "Invalid OEM header signature\n");
208*4882a593Smuzhiyun 		return NULL;
209*4882a593Smuzhiyun 	}
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun 	/* calculate checksum */
212*4882a593Smuzhiyun 	tmp = (u8 *)efi_data;
213*4882a593Smuzhiyun 	for (j = 0, sum = 0; j < (sizeof(*oem_hdr) + sizeof(*rom)); j++, tmp++)
214*4882a593Smuzhiyun 		sum += *tmp;
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun 	if (sum != 0) {
217*4882a593Smuzhiyun 		dev_warn(&pdev->dev,
218*4882a593Smuzhiyun 			 "OEM table checksum failed\n");
219*4882a593Smuzhiyun 		return NULL;
220*4882a593Smuzhiyun 	}
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun 	if (memcmp(rom->hdr.signature,
223*4882a593Smuzhiyun 		   ISCI_ROM_SIG,
224*4882a593Smuzhiyun 		   ISCI_ROM_SIG_SIZE) != 0) {
225*4882a593Smuzhiyun 		dev_warn(&pdev->dev,
226*4882a593Smuzhiyun 			 "Invalid OEM table signature\n");
227*4882a593Smuzhiyun 		return NULL;
228*4882a593Smuzhiyun 	}
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 	return rom;
231*4882a593Smuzhiyun }
232