1f482eb797a391a098046a934f55af8bd785a4494David Kilroy/*
2f90d8d4789eba79b0a715e41aba4c09403088847David Kilroy * Hermes download helper.
3f482eb797a391a098046a934f55af8bd785a4494David Kilroy *
4f90d8d4789eba79b0a715e41aba4c09403088847David Kilroy * This helper:
5f482eb797a391a098046a934f55af8bd785a4494David Kilroy *  - is capable of writing to the volatile area of the hermes device
6f482eb797a391a098046a934f55af8bd785a4494David Kilroy *  - is currently not capable of writing to non-volatile areas
7f482eb797a391a098046a934f55af8bd785a4494David Kilroy *  - provide helpers to identify and update plugin data
8f482eb797a391a098046a934f55af8bd785a4494David Kilroy *  - is not capable of interpreting a fw image directly. That is up to
9f482eb797a391a098046a934f55af8bd785a4494David Kilroy *    the main card driver.
10f482eb797a391a098046a934f55af8bd785a4494David Kilroy *  - deals with Hermes I devices. It can probably be modified to deal
11f482eb797a391a098046a934f55af8bd785a4494David Kilroy *    with Hermes II devices
12f482eb797a391a098046a934f55af8bd785a4494David Kilroy *
13f482eb797a391a098046a934f55af8bd785a4494David Kilroy * Copyright (C) 2007, David Kilroy
14f482eb797a391a098046a934f55af8bd785a4494David Kilroy *
15f482eb797a391a098046a934f55af8bd785a4494David Kilroy * Plug data code slightly modified from spectrum_cs driver
16f482eb797a391a098046a934f55af8bd785a4494David Kilroy *    Copyright (C) 2002-2005 Pavel Roskin <proski@gnu.org>
17f482eb797a391a098046a934f55af8bd785a4494David Kilroy * Portions based on information in wl_lkm_718 Agere driver
18f482eb797a391a098046a934f55af8bd785a4494David Kilroy *    COPYRIGHT (C) 2001-2004 by Agere Systems Inc. All Rights Reserved
19f482eb797a391a098046a934f55af8bd785a4494David Kilroy *
20f482eb797a391a098046a934f55af8bd785a4494David Kilroy * The contents of this file are subject to the Mozilla Public License
21f482eb797a391a098046a934f55af8bd785a4494David Kilroy * Version 1.1 (the "License"); you may not use this file except in
22f482eb797a391a098046a934f55af8bd785a4494David Kilroy * compliance with the License. You may obtain a copy of the License
23f482eb797a391a098046a934f55af8bd785a4494David Kilroy * at http://www.mozilla.org/MPL/
24f482eb797a391a098046a934f55af8bd785a4494David Kilroy *
25f482eb797a391a098046a934f55af8bd785a4494David Kilroy * Software distributed under the License is distributed on an "AS IS"
26f482eb797a391a098046a934f55af8bd785a4494David Kilroy * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
27f482eb797a391a098046a934f55af8bd785a4494David Kilroy * the License for the specific language governing rights and
28f482eb797a391a098046a934f55af8bd785a4494David Kilroy * limitations under the License.
29f482eb797a391a098046a934f55af8bd785a4494David Kilroy *
30f482eb797a391a098046a934f55af8bd785a4494David Kilroy * Alternatively, the contents of this file may be used under the
31f482eb797a391a098046a934f55af8bd785a4494David Kilroy * terms of the GNU General Public License version 2 (the "GPL"), in
32f482eb797a391a098046a934f55af8bd785a4494David Kilroy * which case the provisions of the GPL are applicable instead of the
33f482eb797a391a098046a934f55af8bd785a4494David Kilroy * above.  If you wish to allow the use of your version of this file
34f482eb797a391a098046a934f55af8bd785a4494David Kilroy * only under the terms of the GPL and not to allow others to use your
35f482eb797a391a098046a934f55af8bd785a4494David Kilroy * version of this file under the MPL, indicate your decision by
36f482eb797a391a098046a934f55af8bd785a4494David Kilroy * deleting the provisions above and replace them with the notice and
37f482eb797a391a098046a934f55af8bd785a4494David Kilroy * other provisions required by the GPL.  If you do not delete the
38f482eb797a391a098046a934f55af8bd785a4494David Kilroy * provisions above, a recipient may use your version of this file
39f482eb797a391a098046a934f55af8bd785a4494David Kilroy * under either the MPL or the GPL.
40f482eb797a391a098046a934f55af8bd785a4494David Kilroy */
41f482eb797a391a098046a934f55af8bd785a4494David Kilroy
42f482eb797a391a098046a934f55af8bd785a4494David Kilroy#include <linux/module.h>
43f482eb797a391a098046a934f55af8bd785a4494David Kilroy#include <linux/delay.h>
44f482eb797a391a098046a934f55af8bd785a4494David Kilroy#include "hermes.h"
45f482eb797a391a098046a934f55af8bd785a4494David Kilroy#include "hermes_dld.h"
46f482eb797a391a098046a934f55af8bd785a4494David Kilroy
47f482eb797a391a098046a934f55af8bd785a4494David Kilroy#define PFX "hermes_dld: "
48f482eb797a391a098046a934f55af8bd785a4494David Kilroy
49e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy/* End markers used in dblocks */
50f482eb797a391a098046a934f55af8bd785a4494David Kilroy#define PDI_END		0x00000000	/* End of PDA */
51f482eb797a391a098046a934f55af8bd785a4494David Kilroy#define BLOCK_END	0xFFFFFFFF	/* Last image block */
52e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy#define TEXT_END	0x1A		/* End of text header */
53e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy
54f482eb797a391a098046a934f55af8bd785a4494David Kilroy/*
55f482eb797a391a098046a934f55af8bd785a4494David Kilroy * The following structures have little-endian fields denoted by
56f482eb797a391a098046a934f55af8bd785a4494David Kilroy * the leading underscore.  Don't access them directly - use inline
57f482eb797a391a098046a934f55af8bd785a4494David Kilroy * functions defined below.
58f482eb797a391a098046a934f55af8bd785a4494David Kilroy */
59f482eb797a391a098046a934f55af8bd785a4494David Kilroy
60f482eb797a391a098046a934f55af8bd785a4494David Kilroy/*
61f482eb797a391a098046a934f55af8bd785a4494David Kilroy * The binary image to be downloaded consists of series of data blocks.
62f482eb797a391a098046a934f55af8bd785a4494David Kilroy * Each block has the following structure.
63f482eb797a391a098046a934f55af8bd785a4494David Kilroy */
64f482eb797a391a098046a934f55af8bd785a4494David Kilroystruct dblock {
65f482eb797a391a098046a934f55af8bd785a4494David Kilroy	__le32 addr;		/* adapter address where to write the block */
66f482eb797a391a098046a934f55af8bd785a4494David Kilroy	__le16 len;		/* length of the data only, in bytes */
67f482eb797a391a098046a934f55af8bd785a4494David Kilroy	char data[0];		/* data to be written */
68ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed;
69f482eb797a391a098046a934f55af8bd785a4494David Kilroy
70f482eb797a391a098046a934f55af8bd785a4494David Kilroy/*
7177c2061d10a408d0220c2b0e7faefe52d9c41008Walter Goldens * Plug Data References are located in the image after the last data
72f482eb797a391a098046a934f55af8bd785a4494David Kilroy * block.  They refer to areas in the adapter memory where the plug data
73f482eb797a391a098046a934f55af8bd785a4494David Kilroy * items with matching ID should be written.
74f482eb797a391a098046a934f55af8bd785a4494David Kilroy */
75f482eb797a391a098046a934f55af8bd785a4494David Kilroystruct pdr {
76f482eb797a391a098046a934f55af8bd785a4494David Kilroy	__le32 id;		/* record ID */
77f482eb797a391a098046a934f55af8bd785a4494David Kilroy	__le32 addr;		/* adapter address where to write the data */
78f482eb797a391a098046a934f55af8bd785a4494David Kilroy	__le32 len;		/* expected length of the data, in bytes */
79f482eb797a391a098046a934f55af8bd785a4494David Kilroy	char next[0];		/* next PDR starts here */
80ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed;
81f482eb797a391a098046a934f55af8bd785a4494David Kilroy
82f482eb797a391a098046a934f55af8bd785a4494David Kilroy/*
83f482eb797a391a098046a934f55af8bd785a4494David Kilroy * Plug Data Items are located in the EEPROM read from the adapter by
84f482eb797a391a098046a934f55af8bd785a4494David Kilroy * primary firmware.  They refer to the device-specific data that should
85f482eb797a391a098046a934f55af8bd785a4494David Kilroy * be plugged into the secondary firmware.
86f482eb797a391a098046a934f55af8bd785a4494David Kilroy */
87f482eb797a391a098046a934f55af8bd785a4494David Kilroystruct pdi {
88f482eb797a391a098046a934f55af8bd785a4494David Kilroy	__le16 len;		/* length of ID and data, in words */
89f482eb797a391a098046a934f55af8bd785a4494David Kilroy	__le16 id;		/* record ID */
90f482eb797a391a098046a934f55af8bd785a4494David Kilroy	char data[0];		/* plug data */
91ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed;
92f482eb797a391a098046a934f55af8bd785a4494David Kilroy
93e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy/*** FW data block access functions ***/
94e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy
95f482eb797a391a098046a934f55af8bd785a4494David Kilroystatic inline u32
96f482eb797a391a098046a934f55af8bd785a4494David Kilroydblock_addr(const struct dblock *blk)
97f482eb797a391a098046a934f55af8bd785a4494David Kilroy{
98f482eb797a391a098046a934f55af8bd785a4494David Kilroy	return le32_to_cpu(blk->addr);
99f482eb797a391a098046a934f55af8bd785a4494David Kilroy}
100f482eb797a391a098046a934f55af8bd785a4494David Kilroy
101f482eb797a391a098046a934f55af8bd785a4494David Kilroystatic inline u32
102f482eb797a391a098046a934f55af8bd785a4494David Kilroydblock_len(const struct dblock *blk)
103f482eb797a391a098046a934f55af8bd785a4494David Kilroy{
104f482eb797a391a098046a934f55af8bd785a4494David Kilroy	return le16_to_cpu(blk->len);
105f482eb797a391a098046a934f55af8bd785a4494David Kilroy}
106f482eb797a391a098046a934f55af8bd785a4494David Kilroy
107e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy/*** PDR Access functions ***/
108e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy
109f482eb797a391a098046a934f55af8bd785a4494David Kilroystatic inline u32
110f482eb797a391a098046a934f55af8bd785a4494David Kilroypdr_id(const struct pdr *pdr)
111f482eb797a391a098046a934f55af8bd785a4494David Kilroy{
112f482eb797a391a098046a934f55af8bd785a4494David Kilroy	return le32_to_cpu(pdr->id);
113f482eb797a391a098046a934f55af8bd785a4494David Kilroy}
114f482eb797a391a098046a934f55af8bd785a4494David Kilroy
115f482eb797a391a098046a934f55af8bd785a4494David Kilroystatic inline u32
116f482eb797a391a098046a934f55af8bd785a4494David Kilroypdr_addr(const struct pdr *pdr)
117f482eb797a391a098046a934f55af8bd785a4494David Kilroy{
118f482eb797a391a098046a934f55af8bd785a4494David Kilroy	return le32_to_cpu(pdr->addr);
119f482eb797a391a098046a934f55af8bd785a4494David Kilroy}
120f482eb797a391a098046a934f55af8bd785a4494David Kilroy
121f482eb797a391a098046a934f55af8bd785a4494David Kilroystatic inline u32
122f482eb797a391a098046a934f55af8bd785a4494David Kilroypdr_len(const struct pdr *pdr)
123f482eb797a391a098046a934f55af8bd785a4494David Kilroy{
124f482eb797a391a098046a934f55af8bd785a4494David Kilroy	return le32_to_cpu(pdr->len);
125f482eb797a391a098046a934f55af8bd785a4494David Kilroy}
126f482eb797a391a098046a934f55af8bd785a4494David Kilroy
127e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy/*** PDI Access functions ***/
128e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy
129f482eb797a391a098046a934f55af8bd785a4494David Kilroystatic inline u32
130f482eb797a391a098046a934f55af8bd785a4494David Kilroypdi_id(const struct pdi *pdi)
131f482eb797a391a098046a934f55af8bd785a4494David Kilroy{
132f482eb797a391a098046a934f55af8bd785a4494David Kilroy	return le16_to_cpu(pdi->id);
133f482eb797a391a098046a934f55af8bd785a4494David Kilroy}
134f482eb797a391a098046a934f55af8bd785a4494David Kilroy
135f482eb797a391a098046a934f55af8bd785a4494David Kilroy/* Return length of the data only, in bytes */
136f482eb797a391a098046a934f55af8bd785a4494David Kilroystatic inline u32
137f482eb797a391a098046a934f55af8bd785a4494David Kilroypdi_len(const struct pdi *pdi)
138f482eb797a391a098046a934f55af8bd785a4494David Kilroy{
139f482eb797a391a098046a934f55af8bd785a4494David Kilroy	return 2 * (le16_to_cpu(pdi->len) - 1);
140f482eb797a391a098046a934f55af8bd785a4494David Kilroy}
141f482eb797a391a098046a934f55af8bd785a4494David Kilroy
142e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy/*** Plug Data Functions ***/
143e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy
144f482eb797a391a098046a934f55af8bd785a4494David Kilroy/*
145f482eb797a391a098046a934f55af8bd785a4494David Kilroy * Scan PDR for the record with the specified RECORD_ID.
146f482eb797a391a098046a934f55af8bd785a4494David Kilroy * If it's not found, return NULL.
147f482eb797a391a098046a934f55af8bd785a4494David Kilroy */
1483faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroystatic const struct pdr *
1493faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroyhermes_find_pdr(const struct pdr *first_pdr, u32 record_id, const void *end)
150f482eb797a391a098046a934f55af8bd785a4494David Kilroy{
1513faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy	const struct pdr *pdr = first_pdr;
152f482eb797a391a098046a934f55af8bd785a4494David Kilroy
1533faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy	end -= sizeof(struct pdr);
1543faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy
1553faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy	while (((void *) pdr <= end) &&
156e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy	       (pdr_id(pdr) != PDI_END)) {
157f482eb797a391a098046a934f55af8bd785a4494David Kilroy		/*
158f482eb797a391a098046a934f55af8bd785a4494David Kilroy		 * PDR area is currently not terminated by PDI_END.
159f482eb797a391a098046a934f55af8bd785a4494David Kilroy		 * It's followed by CRC records, which have the type
160f482eb797a391a098046a934f55af8bd785a4494David Kilroy		 * field where PDR has length.  The type can be 0 or 1.
161f482eb797a391a098046a934f55af8bd785a4494David Kilroy		 */
162f482eb797a391a098046a934f55af8bd785a4494David Kilroy		if (pdr_len(pdr) < 2)
163f482eb797a391a098046a934f55af8bd785a4494David Kilroy			return NULL;
164f482eb797a391a098046a934f55af8bd785a4494David Kilroy
165f482eb797a391a098046a934f55af8bd785a4494David Kilroy		/* If the record ID matches, we are done */
166f482eb797a391a098046a934f55af8bd785a4494David Kilroy		if (pdr_id(pdr) == record_id)
167f482eb797a391a098046a934f55af8bd785a4494David Kilroy			return pdr;
168f482eb797a391a098046a934f55af8bd785a4494David Kilroy
169f482eb797a391a098046a934f55af8bd785a4494David Kilroy		pdr = (struct pdr *) pdr->next;
170f482eb797a391a098046a934f55af8bd785a4494David Kilroy	}
171f482eb797a391a098046a934f55af8bd785a4494David Kilroy	return NULL;
172f482eb797a391a098046a934f55af8bd785a4494David Kilroy}
173f482eb797a391a098046a934f55af8bd785a4494David Kilroy
1748f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy/* Scan production data items for a particular entry */
1753faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroystatic const struct pdi *
1763faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroyhermes_find_pdi(const struct pdi *first_pdi, u32 record_id, const void *end)
1778f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy{
1783faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy	const struct pdi *pdi = first_pdi;
1793faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy
1803faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy	end -= sizeof(struct pdi);
1818f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy
1823faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy	while (((void *) pdi <= end) &&
1833faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy	       (pdi_id(pdi) != PDI_END)) {
1848f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy
1858f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		/* If the record ID matches, we are done */
1868f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		if (pdi_id(pdi) == record_id)
1878f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy			return pdi;
1888f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy
1898f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		pdi = (struct pdi *) &pdi->data[pdi_len(pdi)];
1908f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy	}
1918f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy	return NULL;
1928f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy}
1938f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy
194f482eb797a391a098046a934f55af8bd785a4494David Kilroy/* Process one Plug Data Item - find corresponding PDR and plug it */
195f482eb797a391a098046a934f55af8bd785a4494David Kilroystatic int
196933d594313a5928ffc5325d7bbb6e2383d79622ePavel Roskinhermes_plug_pdi(struct hermes *hw, const struct pdr *first_pdr,
1973faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy		const struct pdi *pdi, const void *pdr_end)
198f482eb797a391a098046a934f55af8bd785a4494David Kilroy{
1993faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy	const struct pdr *pdr;
200f482eb797a391a098046a934f55af8bd785a4494David Kilroy
201e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy	/* Find the PDR corresponding to this PDI */
2023faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy	pdr = hermes_find_pdr(first_pdr, pdi_id(pdi), pdr_end);
203f482eb797a391a098046a934f55af8bd785a4494David Kilroy
204f482eb797a391a098046a934f55af8bd785a4494David Kilroy	/* No match is found, safe to ignore */
205f482eb797a391a098046a934f55af8bd785a4494David Kilroy	if (!pdr)
206f482eb797a391a098046a934f55af8bd785a4494David Kilroy		return 0;
207f482eb797a391a098046a934f55af8bd785a4494David Kilroy
208f482eb797a391a098046a934f55af8bd785a4494David Kilroy	/* Lengths of the data in PDI and PDR must match */
209f482eb797a391a098046a934f55af8bd785a4494David Kilroy	if (pdi_len(pdi) != pdr_len(pdr))
210f482eb797a391a098046a934f55af8bd785a4494David Kilroy		return -EINVAL;
211f482eb797a391a098046a934f55af8bd785a4494David Kilroy
212f482eb797a391a098046a934f55af8bd785a4494David Kilroy	/* do the actual plugging */
21307cefe7ac983374ee4c369f1d4aee3093bf3b44fDavid Kilroy	hw->ops->program(hw, pdi->data, pdr_addr(pdr), pdi_len(pdi));
214f482eb797a391a098046a934f55af8bd785a4494David Kilroy
215f482eb797a391a098046a934f55af8bd785a4494David Kilroy	return 0;
216f482eb797a391a098046a934f55af8bd785a4494David Kilroy}
217f482eb797a391a098046a934f55af8bd785a4494David Kilroy
218e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy/* Parse PDA and write the records into the adapter
219e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy *
220e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy * Attempt to write every records that is in the specified pda
221e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy * which also has a valid production data record for the firmware.
222e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy */
223933d594313a5928ffc5325d7bbb6e2383d79622ePavel Roskinint hermes_apply_pda(struct hermes *hw,
224e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy		     const char *first_pdr,
2253faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy		     const void *pdr_end,
2263faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy		     const __le16 *pda,
2273faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy		     const void *pda_end)
228f482eb797a391a098046a934f55af8bd785a4494David Kilroy{
229f482eb797a391a098046a934f55af8bd785a4494David Kilroy	int ret;
230e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy	const struct pdi *pdi;
2313faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy	const struct pdr *pdr;
232f482eb797a391a098046a934f55af8bd785a4494David Kilroy
2333faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy	pdr = (const struct pdr *) first_pdr;
2343faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy	pda_end -= sizeof(struct pdi);
235f482eb797a391a098046a934f55af8bd785a4494David Kilroy
236f482eb797a391a098046a934f55af8bd785a4494David Kilroy	/* Go through every PDI and plug them into the adapter */
237e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy	pdi = (const struct pdi *) (pda + 2);
2383faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy	while (((void *) pdi <= pda_end) &&
2393faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy	       (pdi_id(pdi) != PDI_END)) {
2403faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy		ret = hermes_plug_pdi(hw, pdr, pdi, pdr_end);
241f482eb797a391a098046a934f55af8bd785a4494David Kilroy		if (ret)
242f482eb797a391a098046a934f55af8bd785a4494David Kilroy			return ret;
243f482eb797a391a098046a934f55af8bd785a4494David Kilroy
244f482eb797a391a098046a934f55af8bd785a4494David Kilroy		/* Increment to the next PDI */
245e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy		pdi = (const struct pdi *) &pdi->data[pdi_len(pdi)];
246f482eb797a391a098046a934f55af8bd785a4494David Kilroy	}
247f482eb797a391a098046a934f55af8bd785a4494David Kilroy	return 0;
248f482eb797a391a098046a934f55af8bd785a4494David Kilroy}
249e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy
250e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy/* Identify the total number of bytes in all blocks
251e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy * including the header data.
252e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy */
253e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroysize_t
2543faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroyhermes_blocks_length(const char *first_block, const void *end)
255e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy{
256e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy	const struct dblock *blk = (const struct dblock *) first_block;
257e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy	int total_len = 0;
258e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy	int len;
259e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy
2603faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy	end -= sizeof(*blk);
2613faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy
262e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy	/* Skip all blocks to locate Plug Data References
263e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy	 * (Spectrum CS) */
2643faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy	while (((void *) blk <= end) &&
2653faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy	       (dblock_addr(blk) != BLOCK_END)) {
266e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy		len = dblock_len(blk);
267e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy		total_len += sizeof(*blk) + len;
268e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy		blk = (struct dblock *) &blk->data[len];
269e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy	}
270e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy
271e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy	return total_len;
272e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy}
273e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy
274e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy/*** Hermes programming ***/
275f482eb797a391a098046a934f55af8bd785a4494David Kilroy
276e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy/* Program the data blocks */
277933d594313a5928ffc5325d7bbb6e2383d79622ePavel Roskinint hermes_program(struct hermes *hw, const char *first_block, const void *end)
278f482eb797a391a098046a934f55af8bd785a4494David Kilroy{
279f482eb797a391a098046a934f55af8bd785a4494David Kilroy	const struct dblock *blk;
280f482eb797a391a098046a934f55af8bd785a4494David Kilroy	u32 blkaddr;
281f482eb797a391a098046a934f55af8bd785a4494David Kilroy	u32 blklen;
28207cefe7ac983374ee4c369f1d4aee3093bf3b44fDavid Kilroy	int err = 0;
283e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy
284e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy	blk = (const struct dblock *) first_block;
285e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy
2863faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy	if ((void *) blk > (end - sizeof(*blk)))
287e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy		return -EIO;
288f482eb797a391a098046a934f55af8bd785a4494David Kilroy
289f482eb797a391a098046a934f55af8bd785a4494David Kilroy	blkaddr = dblock_addr(blk);
290f482eb797a391a098046a934f55af8bd785a4494David Kilroy	blklen = dblock_len(blk);
291f482eb797a391a098046a934f55af8bd785a4494David Kilroy
292e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy	while ((blkaddr != BLOCK_END) &&
2933faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy	       (((void *) blk + blklen) <= end)) {
29435832c50d1d1552618f55aa5457a251df9e63b26David Kilroy		pr_debug(PFX "Programming block of length %d "
29535832c50d1d1552618f55aa5457a251df9e63b26David Kilroy			 "to address 0x%08x\n", blklen, blkaddr);
296e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy
29707cefe7ac983374ee4c369f1d4aee3093bf3b44fDavid Kilroy		err = hw->ops->program(hw, blk->data, blkaddr, blklen);
29807cefe7ac983374ee4c369f1d4aee3093bf3b44fDavid Kilroy		if (err)
29907cefe7ac983374ee4c369f1d4aee3093bf3b44fDavid Kilroy			break;
30007cefe7ac983374ee4c369f1d4aee3093bf3b44fDavid Kilroy
301e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy		blk = (const struct dblock *) &blk->data[blklen];
302e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy
3033faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy		if ((void *) blk > (end - sizeof(*blk)))
304e23341809b7b60981d14a368155cd1f0724fb8d5David Kilroy			return -EIO;
305f482eb797a391a098046a934f55af8bd785a4494David Kilroy
306f482eb797a391a098046a934f55af8bd785a4494David Kilroy		blkaddr = dblock_addr(blk);
307f482eb797a391a098046a934f55af8bd785a4494David Kilroy		blklen = dblock_len(blk);
308f482eb797a391a098046a934f55af8bd785a4494David Kilroy	}
30907cefe7ac983374ee4c369f1d4aee3093bf3b44fDavid Kilroy	return err;
310f482eb797a391a098046a934f55af8bd785a4494David Kilroy}
3118f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy
3128f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy/*** Default plugging data for Hermes I ***/
3138f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy/* Values from wl_lkm_718/hcf/dhf.c */
3148f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy
3158f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy#define DEFINE_DEFAULT_PDR(pid, length, data)				\
3168f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroystatic const struct {							\
3178f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy	__le16 len;							\
3188f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy	__le16 id;							\
3198f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy	u8 val[length];							\
320ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed default_pdr_data_##pid = {			\
3213faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy	cpu_to_le16((sizeof(default_pdr_data_##pid)/			\
3228f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy				sizeof(__le16)) - 1),			\
3233faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy	cpu_to_le16(pid),						\
3248f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy	data								\
3258f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy}
3268f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy
3278f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy#define DEFAULT_PDR(pid) default_pdr_data_##pid
3288f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy
32906fe9fb4182177fb046e6d934f80254dd90956eaDirk Hohndel/*  HWIF Compatibility */
3308f5ae73c5366128d3800cf9765507422bcf1ef96David KilroyDEFINE_DEFAULT_PDR(0x0005, 10, "\x00\x00\x06\x00\x01\x00\x01\x00\x01\x00");
3318f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy
3328f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy/* PPPPSign */
3338f5ae73c5366128d3800cf9765507422bcf1ef96David KilroyDEFINE_DEFAULT_PDR(0x0108, 4, "\x00\x00\x00\x00");
3348f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy
3358f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy/* PPPPProf */
3368f5ae73c5366128d3800cf9765507422bcf1ef96David KilroyDEFINE_DEFAULT_PDR(0x0109, 10, "\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00");
3378f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy
3388f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy/* Antenna diversity */
3398f5ae73c5366128d3800cf9765507422bcf1ef96David KilroyDEFINE_DEFAULT_PDR(0x0150, 2, "\x00\x3F");
3408f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy
3418f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy/* Modem VCO band Set-up */
3428f5ae73c5366128d3800cf9765507422bcf1ef96David KilroyDEFINE_DEFAULT_PDR(0x0160, 28,
3438f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		   "\x00\x00\x00\x00\x00\x00\x00\x00"
3448f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		   "\x00\x00\x00\x00\x00\x00\x00\x00"
3458f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		   "\x00\x00\x00\x00\x00\x00\x00\x00"
3468f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		   "\x00\x00\x00\x00");
3478f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy
3488f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy/* Modem Rx Gain Table Values */
3498f5ae73c5366128d3800cf9765507422bcf1ef96David KilroyDEFINE_DEFAULT_PDR(0x0161, 256,
3508f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		   "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
3518f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		   "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
3528f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		   "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
3538f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		   "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
3548f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		   "\x3F\x01\x3E\01\x3E\x01\x3D\x01"
3558f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		   "\x3D\x01\x3C\01\x3C\x01\x3B\x01"
3568f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		   "\x3B\x01\x3A\01\x3A\x01\x39\x01"
3578f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		   "\x39\x01\x38\01\x38\x01\x37\x01"
3588f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		   "\x37\x01\x36\01\x36\x01\x35\x01"
3598f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		   "\x35\x01\x34\01\x34\x01\x33\x01"
3608f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		   "\x33\x01\x32\x01\x32\x01\x31\x01"
3618f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		   "\x31\x01\x30\x01\x30\x01\x7B\x01"
3628f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		   "\x7B\x01\x7A\x01\x7A\x01\x79\x01"
3638f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		   "\x79\x01\x78\x01\x78\x01\x77\x01"
3648f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		   "\x77\x01\x76\x01\x76\x01\x75\x01"
3658f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		   "\x75\x01\x74\x01\x74\x01\x73\x01"
3668f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		   "\x73\x01\x72\x01\x72\x01\x71\x01"
3678f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		   "\x71\x01\x70\x01\x70\x01\x68\x01"
3688f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		   "\x68\x01\x67\x01\x67\x01\x66\x01"
3698f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		   "\x66\x01\x65\x01\x65\x01\x57\x01"
3708f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		   "\x57\x01\x56\x01\x56\x01\x55\x01"
3718f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		   "\x55\x01\x54\x01\x54\x01\x53\x01"
3728f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		   "\x53\x01\x52\x01\x52\x01\x51\x01"
3738f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		   "\x51\x01\x50\x01\x50\x01\x48\x01"
3748f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		   "\x48\x01\x47\x01\x47\x01\x46\x01"
3758f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		   "\x46\x01\x45\x01\x45\x01\x44\x01"
3768f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		   "\x44\x01\x43\x01\x43\x01\x42\x01"
3778f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		   "\x42\x01\x41\x01\x41\x01\x40\x01"
3788f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		   "\x40\x01\x40\x01\x40\x01\x40\x01"
3798f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		   "\x40\x01\x40\x01\x40\x01\x40\x01"
3808f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		   "\x40\x01\x40\x01\x40\x01\x40\x01"
3818f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		   "\x40\x01\x40\x01\x40\x01\x40\x01");
3828f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy
3838f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy/* Write PDA according to certain rules.
3848f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy *
3858f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy * For every production data record, look for a previous setting in
3868f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy * the pda, and use that.
3878f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy *
3888f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy * For certain records, use defaults if they are not found in pda.
3898f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy */
390933d594313a5928ffc5325d7bbb6e2383d79622ePavel Roskinint hermes_apply_pda_with_defaults(struct hermes *hw,
3918f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy				   const char *first_pdr,
3923faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy				   const void *pdr_end,
3933faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy				   const __le16 *pda,
3943faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy				   const void *pda_end)
3958f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy{
3968f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy	const struct pdr *pdr = (const struct pdr *) first_pdr;
3973faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy	const struct pdi *first_pdi = (const struct pdi *) &pda[2];
3983faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy	const struct pdi *pdi;
3993faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy	const struct pdi *default_pdi = NULL;
4003faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy	const struct pdi *outdoor_pdi;
4018f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy	int record_id;
4028f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy
4033faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy	pdr_end -= sizeof(struct pdr);
4043faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy
4053faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy	while (((void *) pdr <= pdr_end) &&
4068f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy	       (pdr_id(pdr) != PDI_END)) {
4078f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		/*
4088f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		 * For spectrum_cs firmwares,
4098f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		 * PDR area is currently not terminated by PDI_END.
4108f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		 * It's followed by CRC records, which have the type
4118f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		 * field where PDR has length.  The type can be 0 or 1.
4128f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		 */
4138f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		if (pdr_len(pdr) < 2)
4148f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy			break;
4158f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		record_id = pdr_id(pdr);
4168f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy
4173faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy		pdi = hermes_find_pdi(first_pdi, record_id, pda_end);
4188f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		if (pdi)
41935832c50d1d1552618f55aa5457a251df9e63b26David Kilroy			pr_debug(PFX "Found record 0x%04x at %p\n",
42035832c50d1d1552618f55aa5457a251df9e63b26David Kilroy				 record_id, pdi);
4218f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy
4228f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		switch (record_id) {
4238f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		case 0x110: /* Modem REFDAC values */
4248f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		case 0x120: /* Modem VGDAC values */
4253faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy			outdoor_pdi = hermes_find_pdi(first_pdi, record_id + 1,
4263faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy						      pda_end);
4278f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy			default_pdi = NULL;
4288f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy			if (outdoor_pdi) {
4298f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy				pdi = outdoor_pdi;
43035832c50d1d1552618f55aa5457a251df9e63b26David Kilroy				pr_debug(PFX
43135832c50d1d1552618f55aa5457a251df9e63b26David Kilroy					 "Using outdoor record 0x%04x at %p\n",
43235832c50d1d1552618f55aa5457a251df9e63b26David Kilroy					 record_id + 1, pdi);
4338f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy			}
4348f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy			break;
43506fe9fb4182177fb046e6d934f80254dd90956eaDirk Hohndel		case 0x5: /*  HWIF Compatibility */
4368f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy			default_pdi = (struct pdi *) &DEFAULT_PDR(0x0005);
4378f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy			break;
4388f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		case 0x108: /* PPPPSign */
4398f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy			default_pdi = (struct pdi *) &DEFAULT_PDR(0x0108);
4408f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy			break;
4418f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		case 0x109: /* PPPPProf */
4428f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy			default_pdi = (struct pdi *) &DEFAULT_PDR(0x0109);
4438f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy			break;
4448f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		case 0x150: /* Antenna diversity */
4458f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy			default_pdi = (struct pdi *) &DEFAULT_PDR(0x0150);
4468f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy			break;
4478f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		case 0x160: /* Modem VCO band Set-up */
4488f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy			default_pdi = (struct pdi *) &DEFAULT_PDR(0x0160);
4498f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy			break;
4508f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		case 0x161: /* Modem Rx Gain Table Values */
4518f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy			default_pdi = (struct pdi *) &DEFAULT_PDR(0x0161);
4528f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy			break;
4538f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		default:
4548f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy			default_pdi = NULL;
4558f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy			break;
4568f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		}
4578f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		if (!pdi && default_pdi) {
4588f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy			/* Use default */
4598f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy			pdi = default_pdi;
46035832c50d1d1552618f55aa5457a251df9e63b26David Kilroy			pr_debug(PFX "Using default record 0x%04x at %p\n",
46135832c50d1d1552618f55aa5457a251df9e63b26David Kilroy				 record_id, pdi);
4628f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		}
4638f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy
4648f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		if (pdi) {
4658f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy			/* Lengths of the data in PDI and PDR must match */
4663faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy			if ((pdi_len(pdi) == pdr_len(pdr)) &&
4673faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy			    ((void *) pdi->data + pdi_len(pdi) < pda_end)) {
4688f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy				/* do the actual plugging */
46907cefe7ac983374ee4c369f1d4aee3093bf3b44fDavid Kilroy				hw->ops->program(hw, pdi->data, pdr_addr(pdr),
47007cefe7ac983374ee4c369f1d4aee3093bf3b44fDavid Kilroy						 pdi_len(pdi));
4718f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy			}
4728f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		}
4738f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy
4748f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy		pdr++;
4758f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy	}
4768f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy	return 0;
4778f5ae73c5366128d3800cf9765507422bcf1ef96David Kilroy}
478