1*4882a593Smuzhiyun /* hermes.c
2*4882a593Smuzhiyun *
3*4882a593Smuzhiyun * Driver core for the "Hermes" wireless MAC controller, as used in
4*4882a593Smuzhiyun * the Lucent Orinoco and Cabletron RoamAbout cards. It should also
5*4882a593Smuzhiyun * work on the hfa3841 and hfa3842 MAC controller chips used in the
6*4882a593Smuzhiyun * Prism II chipsets.
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * This is not a complete driver, just low-level access routines for
9*4882a593Smuzhiyun * the MAC controller itself.
10*4882a593Smuzhiyun *
11*4882a593Smuzhiyun * Based on the prism2 driver from Absolute Value Systems' linux-wlan
12*4882a593Smuzhiyun * project, the Linux wvlan_cs driver, Lucent's HCF-Light
13*4882a593Smuzhiyun * (wvlan_hcf.c) library, and the NetBSD wireless driver (in no
14*4882a593Smuzhiyun * particular order).
15*4882a593Smuzhiyun *
16*4882a593Smuzhiyun * Copyright (C) 2000, David Gibson, Linuxcare Australia.
17*4882a593Smuzhiyun * (C) Copyright David Gibson, IBM Corp. 2001-2003.
18*4882a593Smuzhiyun *
19*4882a593Smuzhiyun * The contents of this file are subject to the Mozilla Public License
20*4882a593Smuzhiyun * Version 1.1 (the "License"); you may not use this file except in
21*4882a593Smuzhiyun * compliance with the License. You may obtain a copy of the License
22*4882a593Smuzhiyun * at http://www.mozilla.org/MPL/
23*4882a593Smuzhiyun *
24*4882a593Smuzhiyun * Software distributed under the License is distributed on an "AS IS"
25*4882a593Smuzhiyun * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
26*4882a593Smuzhiyun * the License for the specific language governing rights and
27*4882a593Smuzhiyun * limitations under the License.
28*4882a593Smuzhiyun *
29*4882a593Smuzhiyun * Alternatively, the contents of this file may be used under the
30*4882a593Smuzhiyun * terms of the GNU General Public License version 2 (the "GPL"), in
31*4882a593Smuzhiyun * which case the provisions of the GPL are applicable instead of the
32*4882a593Smuzhiyun * above. If you wish to allow the use of your version of this file
33*4882a593Smuzhiyun * only under the terms of the GPL and not to allow others to use your
34*4882a593Smuzhiyun * version of this file under the MPL, indicate your decision by
35*4882a593Smuzhiyun * deleting the provisions above and replace them with the notice and
36*4882a593Smuzhiyun * other provisions required by the GPL. If you do not delete the
37*4882a593Smuzhiyun * provisions above, a recipient may use your version of this file
38*4882a593Smuzhiyun * under either the MPL or the GPL.
39*4882a593Smuzhiyun */
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun #include <linux/module.h>
42*4882a593Smuzhiyun #include <linux/kernel.h>
43*4882a593Smuzhiyun #include <linux/delay.h>
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun #include "hermes.h"
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun /* These are maximum timeouts. Most often, card wil react much faster */
48*4882a593Smuzhiyun #define CMD_BUSY_TIMEOUT (100) /* In iterations of ~1us */
49*4882a593Smuzhiyun #define CMD_INIT_TIMEOUT (50000) /* in iterations of ~10us */
50*4882a593Smuzhiyun #define CMD_COMPL_TIMEOUT (20000) /* in iterations of ~10us */
51*4882a593Smuzhiyun #define ALLOC_COMPL_TIMEOUT (1000) /* in iterations of ~10us */
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun /*
54*4882a593Smuzhiyun * AUX port access. To unlock the AUX port write the access keys to the
55*4882a593Smuzhiyun * PARAM0-2 registers, then write HERMES_AUX_ENABLE to the HERMES_CONTROL
56*4882a593Smuzhiyun * register. Then read it and make sure it's HERMES_AUX_ENABLED.
57*4882a593Smuzhiyun */
58*4882a593Smuzhiyun #define HERMES_AUX_ENABLE 0x8000 /* Enable auxiliary port access */
59*4882a593Smuzhiyun #define HERMES_AUX_DISABLE 0x4000 /* Disable to auxiliary port access */
60*4882a593Smuzhiyun #define HERMES_AUX_ENABLED 0xC000 /* Auxiliary port is open */
61*4882a593Smuzhiyun #define HERMES_AUX_DISABLED 0x0000 /* Auxiliary port is closed */
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun #define HERMES_AUX_PW0 0xFE01
64*4882a593Smuzhiyun #define HERMES_AUX_PW1 0xDC23
65*4882a593Smuzhiyun #define HERMES_AUX_PW2 0xBA45
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun /* HERMES_CMD_DOWNLD */
68*4882a593Smuzhiyun #define HERMES_PROGRAM_DISABLE (0x0000 | HERMES_CMD_DOWNLD)
69*4882a593Smuzhiyun #define HERMES_PROGRAM_ENABLE_VOLATILE (0x0100 | HERMES_CMD_DOWNLD)
70*4882a593Smuzhiyun #define HERMES_PROGRAM_ENABLE_NON_VOLATILE (0x0200 | HERMES_CMD_DOWNLD)
71*4882a593Smuzhiyun #define HERMES_PROGRAM_NON_VOLATILE (0x0300 | HERMES_CMD_DOWNLD)
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun /*
74*4882a593Smuzhiyun * Debugging helpers
75*4882a593Smuzhiyun */
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun #define DMSG(stuff...) do {printk(KERN_DEBUG "hermes @ %p: " , hw->iobase); \
78*4882a593Smuzhiyun printk(stuff); } while (0)
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun #undef HERMES_DEBUG
81*4882a593Smuzhiyun #ifdef HERMES_DEBUG
82*4882a593Smuzhiyun #include <stdarg.h>
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun #define DEBUG(lvl, stuff...) if ((lvl) <= HERMES_DEBUG) DMSG(stuff)
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun #else /* ! HERMES_DEBUG */
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun #define DEBUG(lvl, stuff...) do { } while (0)
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun #endif /* ! HERMES_DEBUG */
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun static const struct hermes_ops hermes_ops_local;
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun /*
95*4882a593Smuzhiyun * Internal functions
96*4882a593Smuzhiyun */
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun /* Issue a command to the chip. Waiting for it to complete is the caller's
99*4882a593Smuzhiyun problem.
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun Returns -EBUSY if the command register is busy, 0 on success.
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun Callable from any context.
104*4882a593Smuzhiyun */
hermes_issue_cmd(struct hermes * hw,u16 cmd,u16 param0,u16 param1,u16 param2)105*4882a593Smuzhiyun static int hermes_issue_cmd(struct hermes *hw, u16 cmd, u16 param0,
106*4882a593Smuzhiyun u16 param1, u16 param2)
107*4882a593Smuzhiyun {
108*4882a593Smuzhiyun int k = CMD_BUSY_TIMEOUT;
109*4882a593Smuzhiyun u16 reg;
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun /* First wait for the command register to unbusy */
112*4882a593Smuzhiyun reg = hermes_read_regn(hw, CMD);
113*4882a593Smuzhiyun while ((reg & HERMES_CMD_BUSY) && k) {
114*4882a593Smuzhiyun k--;
115*4882a593Smuzhiyun udelay(1);
116*4882a593Smuzhiyun reg = hermes_read_regn(hw, CMD);
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun if (reg & HERMES_CMD_BUSY)
119*4882a593Smuzhiyun return -EBUSY;
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun hermes_write_regn(hw, PARAM2, param2);
122*4882a593Smuzhiyun hermes_write_regn(hw, PARAM1, param1);
123*4882a593Smuzhiyun hermes_write_regn(hw, PARAM0, param0);
124*4882a593Smuzhiyun hermes_write_regn(hw, CMD, cmd);
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun return 0;
127*4882a593Smuzhiyun }
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun /*
130*4882a593Smuzhiyun * Function definitions
131*4882a593Smuzhiyun */
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun /* For doing cmds that wipe the magic constant in SWSUPPORT0 */
hermes_doicmd_wait(struct hermes * hw,u16 cmd,u16 parm0,u16 parm1,u16 parm2,struct hermes_response * resp)134*4882a593Smuzhiyun static int hermes_doicmd_wait(struct hermes *hw, u16 cmd,
135*4882a593Smuzhiyun u16 parm0, u16 parm1, u16 parm2,
136*4882a593Smuzhiyun struct hermes_response *resp)
137*4882a593Smuzhiyun {
138*4882a593Smuzhiyun int err = 0;
139*4882a593Smuzhiyun int k;
140*4882a593Smuzhiyun u16 status, reg;
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun err = hermes_issue_cmd(hw, cmd, parm0, parm1, parm2);
143*4882a593Smuzhiyun if (err)
144*4882a593Smuzhiyun return err;
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun reg = hermes_read_regn(hw, EVSTAT);
147*4882a593Smuzhiyun k = CMD_INIT_TIMEOUT;
148*4882a593Smuzhiyun while ((!(reg & HERMES_EV_CMD)) && k) {
149*4882a593Smuzhiyun k--;
150*4882a593Smuzhiyun udelay(10);
151*4882a593Smuzhiyun reg = hermes_read_regn(hw, EVSTAT);
152*4882a593Smuzhiyun }
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun hermes_write_regn(hw, SWSUPPORT0, HERMES_MAGIC);
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun if (!hermes_present(hw)) {
157*4882a593Smuzhiyun DEBUG(0, "hermes @ 0x%x: Card removed during reset.\n",
158*4882a593Smuzhiyun hw->iobase);
159*4882a593Smuzhiyun err = -ENODEV;
160*4882a593Smuzhiyun goto out;
161*4882a593Smuzhiyun }
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun if (!(reg & HERMES_EV_CMD)) {
164*4882a593Smuzhiyun printk(KERN_ERR "hermes @ %p: "
165*4882a593Smuzhiyun "Timeout waiting for card to reset (reg=0x%04x)!\n",
166*4882a593Smuzhiyun hw->iobase, reg);
167*4882a593Smuzhiyun err = -ETIMEDOUT;
168*4882a593Smuzhiyun goto out;
169*4882a593Smuzhiyun }
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun status = hermes_read_regn(hw, STATUS);
172*4882a593Smuzhiyun if (resp) {
173*4882a593Smuzhiyun resp->status = status;
174*4882a593Smuzhiyun resp->resp0 = hermes_read_regn(hw, RESP0);
175*4882a593Smuzhiyun resp->resp1 = hermes_read_regn(hw, RESP1);
176*4882a593Smuzhiyun resp->resp2 = hermes_read_regn(hw, RESP2);
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun hermes_write_regn(hw, EVACK, HERMES_EV_CMD);
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun if (status & HERMES_STATUS_RESULT)
182*4882a593Smuzhiyun err = -EIO;
183*4882a593Smuzhiyun out:
184*4882a593Smuzhiyun return err;
185*4882a593Smuzhiyun }
186*4882a593Smuzhiyun
hermes_struct_init(struct hermes * hw,void __iomem * address,int reg_spacing)187*4882a593Smuzhiyun void hermes_struct_init(struct hermes *hw, void __iomem *address,
188*4882a593Smuzhiyun int reg_spacing)
189*4882a593Smuzhiyun {
190*4882a593Smuzhiyun hw->iobase = address;
191*4882a593Smuzhiyun hw->reg_spacing = reg_spacing;
192*4882a593Smuzhiyun hw->inten = 0x0;
193*4882a593Smuzhiyun hw->eeprom_pda = false;
194*4882a593Smuzhiyun hw->ops = &hermes_ops_local;
195*4882a593Smuzhiyun }
196*4882a593Smuzhiyun EXPORT_SYMBOL(hermes_struct_init);
197*4882a593Smuzhiyun
hermes_init(struct hermes * hw)198*4882a593Smuzhiyun static int hermes_init(struct hermes *hw)
199*4882a593Smuzhiyun {
200*4882a593Smuzhiyun u16 reg;
201*4882a593Smuzhiyun int err = 0;
202*4882a593Smuzhiyun int k;
203*4882a593Smuzhiyun
204*4882a593Smuzhiyun /* We don't want to be interrupted while resetting the chipset */
205*4882a593Smuzhiyun hw->inten = 0x0;
206*4882a593Smuzhiyun hermes_write_regn(hw, INTEN, 0);
207*4882a593Smuzhiyun hermes_write_regn(hw, EVACK, 0xffff);
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun /* Normally it's a "can't happen" for the command register to
210*4882a593Smuzhiyun be busy when we go to issue a command because we are
211*4882a593Smuzhiyun serializing all commands. However we want to have some
212*4882a593Smuzhiyun chance of resetting the card even if it gets into a stupid
213*4882a593Smuzhiyun state, so we actually wait to see if the command register
214*4882a593Smuzhiyun will unbusy itself here. */
215*4882a593Smuzhiyun k = CMD_BUSY_TIMEOUT;
216*4882a593Smuzhiyun reg = hermes_read_regn(hw, CMD);
217*4882a593Smuzhiyun while (k && (reg & HERMES_CMD_BUSY)) {
218*4882a593Smuzhiyun if (reg == 0xffff) /* Special case - the card has probably been
219*4882a593Smuzhiyun removed, so don't wait for the timeout */
220*4882a593Smuzhiyun return -ENODEV;
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun k--;
223*4882a593Smuzhiyun udelay(1);
224*4882a593Smuzhiyun reg = hermes_read_regn(hw, CMD);
225*4882a593Smuzhiyun }
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun /* No need to explicitly handle the timeout - if we've timed
228*4882a593Smuzhiyun out hermes_issue_cmd() will probably return -EBUSY below */
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun /* According to the documentation, EVSTAT may contain
231*4882a593Smuzhiyun obsolete event occurrence information. We have to acknowledge
232*4882a593Smuzhiyun it by writing EVACK. */
233*4882a593Smuzhiyun reg = hermes_read_regn(hw, EVSTAT);
234*4882a593Smuzhiyun hermes_write_regn(hw, EVACK, reg);
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun /* We don't use hermes_docmd_wait here, because the reset wipes
237*4882a593Smuzhiyun the magic constant in SWSUPPORT0 away, and it gets confused */
238*4882a593Smuzhiyun err = hermes_doicmd_wait(hw, HERMES_CMD_INIT, 0, 0, 0, NULL);
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun return err;
241*4882a593Smuzhiyun }
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun /* Issue a command to the chip, and (busy!) wait for it to
244*4882a593Smuzhiyun * complete.
245*4882a593Smuzhiyun *
246*4882a593Smuzhiyun * Returns:
247*4882a593Smuzhiyun * < 0 on internal error
248*4882a593Smuzhiyun * 0 on success
249*4882a593Smuzhiyun * > 0 on error returned by the firmware
250*4882a593Smuzhiyun *
251*4882a593Smuzhiyun * Callable from any context, but locking is your problem. */
hermes_docmd_wait(struct hermes * hw,u16 cmd,u16 parm0,struct hermes_response * resp)252*4882a593Smuzhiyun static int hermes_docmd_wait(struct hermes *hw, u16 cmd, u16 parm0,
253*4882a593Smuzhiyun struct hermes_response *resp)
254*4882a593Smuzhiyun {
255*4882a593Smuzhiyun int err;
256*4882a593Smuzhiyun int k;
257*4882a593Smuzhiyun u16 reg;
258*4882a593Smuzhiyun u16 status;
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun err = hermes_issue_cmd(hw, cmd, parm0, 0, 0);
261*4882a593Smuzhiyun if (err) {
262*4882a593Smuzhiyun if (!hermes_present(hw)) {
263*4882a593Smuzhiyun if (net_ratelimit())
264*4882a593Smuzhiyun printk(KERN_WARNING "hermes @ %p: "
265*4882a593Smuzhiyun "Card removed while issuing command "
266*4882a593Smuzhiyun "0x%04x.\n", hw->iobase, cmd);
267*4882a593Smuzhiyun err = -ENODEV;
268*4882a593Smuzhiyun } else
269*4882a593Smuzhiyun if (net_ratelimit())
270*4882a593Smuzhiyun printk(KERN_ERR "hermes @ %p: "
271*4882a593Smuzhiyun "Error %d issuing command 0x%04x.\n",
272*4882a593Smuzhiyun hw->iobase, err, cmd);
273*4882a593Smuzhiyun goto out;
274*4882a593Smuzhiyun }
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun reg = hermes_read_regn(hw, EVSTAT);
277*4882a593Smuzhiyun k = CMD_COMPL_TIMEOUT;
278*4882a593Smuzhiyun while ((!(reg & HERMES_EV_CMD)) && k) {
279*4882a593Smuzhiyun k--;
280*4882a593Smuzhiyun udelay(10);
281*4882a593Smuzhiyun reg = hermes_read_regn(hw, EVSTAT);
282*4882a593Smuzhiyun }
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun if (!hermes_present(hw)) {
285*4882a593Smuzhiyun printk(KERN_WARNING "hermes @ %p: Card removed "
286*4882a593Smuzhiyun "while waiting for command 0x%04x completion.\n",
287*4882a593Smuzhiyun hw->iobase, cmd);
288*4882a593Smuzhiyun err = -ENODEV;
289*4882a593Smuzhiyun goto out;
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun
292*4882a593Smuzhiyun if (!(reg & HERMES_EV_CMD)) {
293*4882a593Smuzhiyun printk(KERN_ERR "hermes @ %p: Timeout waiting for "
294*4882a593Smuzhiyun "command 0x%04x completion.\n", hw->iobase, cmd);
295*4882a593Smuzhiyun err = -ETIMEDOUT;
296*4882a593Smuzhiyun goto out;
297*4882a593Smuzhiyun }
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun status = hermes_read_regn(hw, STATUS);
300*4882a593Smuzhiyun if (resp) {
301*4882a593Smuzhiyun resp->status = status;
302*4882a593Smuzhiyun resp->resp0 = hermes_read_regn(hw, RESP0);
303*4882a593Smuzhiyun resp->resp1 = hermes_read_regn(hw, RESP1);
304*4882a593Smuzhiyun resp->resp2 = hermes_read_regn(hw, RESP2);
305*4882a593Smuzhiyun }
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun hermes_write_regn(hw, EVACK, HERMES_EV_CMD);
308*4882a593Smuzhiyun
309*4882a593Smuzhiyun if (status & HERMES_STATUS_RESULT)
310*4882a593Smuzhiyun err = -EIO;
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun out:
313*4882a593Smuzhiyun return err;
314*4882a593Smuzhiyun }
315*4882a593Smuzhiyun
hermes_allocate(struct hermes * hw,u16 size,u16 * fid)316*4882a593Smuzhiyun static int hermes_allocate(struct hermes *hw, u16 size, u16 *fid)
317*4882a593Smuzhiyun {
318*4882a593Smuzhiyun int err = 0;
319*4882a593Smuzhiyun int k;
320*4882a593Smuzhiyun u16 reg;
321*4882a593Smuzhiyun
322*4882a593Smuzhiyun if ((size < HERMES_ALLOC_LEN_MIN) || (size > HERMES_ALLOC_LEN_MAX))
323*4882a593Smuzhiyun return -EINVAL;
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun err = hermes_docmd_wait(hw, HERMES_CMD_ALLOC, size, NULL);
326*4882a593Smuzhiyun if (err)
327*4882a593Smuzhiyun return err;
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun reg = hermes_read_regn(hw, EVSTAT);
330*4882a593Smuzhiyun k = ALLOC_COMPL_TIMEOUT;
331*4882a593Smuzhiyun while ((!(reg & HERMES_EV_ALLOC)) && k) {
332*4882a593Smuzhiyun k--;
333*4882a593Smuzhiyun udelay(10);
334*4882a593Smuzhiyun reg = hermes_read_regn(hw, EVSTAT);
335*4882a593Smuzhiyun }
336*4882a593Smuzhiyun
337*4882a593Smuzhiyun if (!hermes_present(hw)) {
338*4882a593Smuzhiyun printk(KERN_WARNING "hermes @ %p: "
339*4882a593Smuzhiyun "Card removed waiting for frame allocation.\n",
340*4882a593Smuzhiyun hw->iobase);
341*4882a593Smuzhiyun return -ENODEV;
342*4882a593Smuzhiyun }
343*4882a593Smuzhiyun
344*4882a593Smuzhiyun if (!(reg & HERMES_EV_ALLOC)) {
345*4882a593Smuzhiyun printk(KERN_ERR "hermes @ %p: "
346*4882a593Smuzhiyun "Timeout waiting for frame allocation\n",
347*4882a593Smuzhiyun hw->iobase);
348*4882a593Smuzhiyun return -ETIMEDOUT;
349*4882a593Smuzhiyun }
350*4882a593Smuzhiyun
351*4882a593Smuzhiyun *fid = hermes_read_regn(hw, ALLOCFID);
352*4882a593Smuzhiyun hermes_write_regn(hw, EVACK, HERMES_EV_ALLOC);
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun return 0;
355*4882a593Smuzhiyun }
356*4882a593Smuzhiyun
357*4882a593Smuzhiyun /* Set up a BAP to read a particular chunk of data from card's internal buffer.
358*4882a593Smuzhiyun *
359*4882a593Smuzhiyun * Returns:
360*4882a593Smuzhiyun * < 0 on internal failure (errno)
361*4882a593Smuzhiyun * 0 on success
362*4882a593Smuzhiyun * > 0 on error
363*4882a593Smuzhiyun * from firmware
364*4882a593Smuzhiyun *
365*4882a593Smuzhiyun * Callable from any context */
hermes_bap_seek(struct hermes * hw,int bap,u16 id,u16 offset)366*4882a593Smuzhiyun static int hermes_bap_seek(struct hermes *hw, int bap, u16 id, u16 offset)
367*4882a593Smuzhiyun {
368*4882a593Smuzhiyun int sreg = bap ? HERMES_SELECT1 : HERMES_SELECT0;
369*4882a593Smuzhiyun int oreg = bap ? HERMES_OFFSET1 : HERMES_OFFSET0;
370*4882a593Smuzhiyun int k;
371*4882a593Smuzhiyun u16 reg;
372*4882a593Smuzhiyun
373*4882a593Smuzhiyun /* Paranoia.. */
374*4882a593Smuzhiyun if ((offset > HERMES_BAP_OFFSET_MAX) || (offset % 2))
375*4882a593Smuzhiyun return -EINVAL;
376*4882a593Smuzhiyun
377*4882a593Smuzhiyun k = HERMES_BAP_BUSY_TIMEOUT;
378*4882a593Smuzhiyun reg = hermes_read_reg(hw, oreg);
379*4882a593Smuzhiyun while ((reg & HERMES_OFFSET_BUSY) && k) {
380*4882a593Smuzhiyun k--;
381*4882a593Smuzhiyun udelay(1);
382*4882a593Smuzhiyun reg = hermes_read_reg(hw, oreg);
383*4882a593Smuzhiyun }
384*4882a593Smuzhiyun
385*4882a593Smuzhiyun if (reg & HERMES_OFFSET_BUSY)
386*4882a593Smuzhiyun return -ETIMEDOUT;
387*4882a593Smuzhiyun
388*4882a593Smuzhiyun /* Now we actually set up the transfer */
389*4882a593Smuzhiyun hermes_write_reg(hw, sreg, id);
390*4882a593Smuzhiyun hermes_write_reg(hw, oreg, offset);
391*4882a593Smuzhiyun
392*4882a593Smuzhiyun /* Wait for the BAP to be ready */
393*4882a593Smuzhiyun k = HERMES_BAP_BUSY_TIMEOUT;
394*4882a593Smuzhiyun reg = hermes_read_reg(hw, oreg);
395*4882a593Smuzhiyun while ((reg & (HERMES_OFFSET_BUSY | HERMES_OFFSET_ERR)) && k) {
396*4882a593Smuzhiyun k--;
397*4882a593Smuzhiyun udelay(1);
398*4882a593Smuzhiyun reg = hermes_read_reg(hw, oreg);
399*4882a593Smuzhiyun }
400*4882a593Smuzhiyun
401*4882a593Smuzhiyun if (reg != offset) {
402*4882a593Smuzhiyun printk(KERN_ERR "hermes @ %p: BAP%d offset %s: "
403*4882a593Smuzhiyun "reg=0x%x id=0x%x offset=0x%x\n", hw->iobase, bap,
404*4882a593Smuzhiyun (reg & HERMES_OFFSET_BUSY) ? "timeout" : "error",
405*4882a593Smuzhiyun reg, id, offset);
406*4882a593Smuzhiyun
407*4882a593Smuzhiyun if (reg & HERMES_OFFSET_BUSY)
408*4882a593Smuzhiyun return -ETIMEDOUT;
409*4882a593Smuzhiyun
410*4882a593Smuzhiyun return -EIO; /* error or wrong offset */
411*4882a593Smuzhiyun }
412*4882a593Smuzhiyun
413*4882a593Smuzhiyun return 0;
414*4882a593Smuzhiyun }
415*4882a593Smuzhiyun
416*4882a593Smuzhiyun /* Read a block of data from the chip's buffer, via the
417*4882a593Smuzhiyun * BAP. Synchronization/serialization is the caller's problem. len
418*4882a593Smuzhiyun * must be even.
419*4882a593Smuzhiyun *
420*4882a593Smuzhiyun * Returns:
421*4882a593Smuzhiyun * < 0 on internal failure (errno)
422*4882a593Smuzhiyun * 0 on success
423*4882a593Smuzhiyun * > 0 on error from firmware
424*4882a593Smuzhiyun */
hermes_bap_pread(struct hermes * hw,int bap,void * buf,int len,u16 id,u16 offset)425*4882a593Smuzhiyun static int hermes_bap_pread(struct hermes *hw, int bap, void *buf, int len,
426*4882a593Smuzhiyun u16 id, u16 offset)
427*4882a593Smuzhiyun {
428*4882a593Smuzhiyun int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
429*4882a593Smuzhiyun int err = 0;
430*4882a593Smuzhiyun
431*4882a593Smuzhiyun if ((len < 0) || (len % 2))
432*4882a593Smuzhiyun return -EINVAL;
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun err = hermes_bap_seek(hw, bap, id, offset);
435*4882a593Smuzhiyun if (err)
436*4882a593Smuzhiyun goto out;
437*4882a593Smuzhiyun
438*4882a593Smuzhiyun /* Actually do the transfer */
439*4882a593Smuzhiyun hermes_read_words(hw, dreg, buf, len / 2);
440*4882a593Smuzhiyun
441*4882a593Smuzhiyun out:
442*4882a593Smuzhiyun return err;
443*4882a593Smuzhiyun }
444*4882a593Smuzhiyun
445*4882a593Smuzhiyun /* Write a block of data to the chip's buffer, via the
446*4882a593Smuzhiyun * BAP. Synchronization/serialization is the caller's problem.
447*4882a593Smuzhiyun *
448*4882a593Smuzhiyun * Returns:
449*4882a593Smuzhiyun * < 0 on internal failure (errno)
450*4882a593Smuzhiyun * 0 on success
451*4882a593Smuzhiyun * > 0 on error from firmware
452*4882a593Smuzhiyun */
hermes_bap_pwrite(struct hermes * hw,int bap,const void * buf,int len,u16 id,u16 offset)453*4882a593Smuzhiyun static int hermes_bap_pwrite(struct hermes *hw, int bap, const void *buf,
454*4882a593Smuzhiyun int len, u16 id, u16 offset)
455*4882a593Smuzhiyun {
456*4882a593Smuzhiyun int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
457*4882a593Smuzhiyun int err = 0;
458*4882a593Smuzhiyun
459*4882a593Smuzhiyun if (len < 0)
460*4882a593Smuzhiyun return -EINVAL;
461*4882a593Smuzhiyun
462*4882a593Smuzhiyun err = hermes_bap_seek(hw, bap, id, offset);
463*4882a593Smuzhiyun if (err)
464*4882a593Smuzhiyun goto out;
465*4882a593Smuzhiyun
466*4882a593Smuzhiyun /* Actually do the transfer */
467*4882a593Smuzhiyun hermes_write_bytes(hw, dreg, buf, len);
468*4882a593Smuzhiyun
469*4882a593Smuzhiyun out:
470*4882a593Smuzhiyun return err;
471*4882a593Smuzhiyun }
472*4882a593Smuzhiyun
473*4882a593Smuzhiyun /* Read a Length-Type-Value record from the card.
474*4882a593Smuzhiyun *
475*4882a593Smuzhiyun * If length is NULL, we ignore the length read from the card, and
476*4882a593Smuzhiyun * read the entire buffer regardless. This is useful because some of
477*4882a593Smuzhiyun * the configuration records appear to have incorrect lengths in
478*4882a593Smuzhiyun * practice.
479*4882a593Smuzhiyun *
480*4882a593Smuzhiyun * Callable from user or bh context. */
hermes_read_ltv(struct hermes * hw,int bap,u16 rid,unsigned bufsize,u16 * length,void * buf)481*4882a593Smuzhiyun static int hermes_read_ltv(struct hermes *hw, int bap, u16 rid,
482*4882a593Smuzhiyun unsigned bufsize, u16 *length, void *buf)
483*4882a593Smuzhiyun {
484*4882a593Smuzhiyun int err = 0;
485*4882a593Smuzhiyun int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
486*4882a593Smuzhiyun u16 rlength, rtype;
487*4882a593Smuzhiyun unsigned nwords;
488*4882a593Smuzhiyun
489*4882a593Smuzhiyun if (bufsize % 2)
490*4882a593Smuzhiyun return -EINVAL;
491*4882a593Smuzhiyun
492*4882a593Smuzhiyun err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS, rid, NULL);
493*4882a593Smuzhiyun if (err)
494*4882a593Smuzhiyun return err;
495*4882a593Smuzhiyun
496*4882a593Smuzhiyun err = hermes_bap_seek(hw, bap, rid, 0);
497*4882a593Smuzhiyun if (err)
498*4882a593Smuzhiyun return err;
499*4882a593Smuzhiyun
500*4882a593Smuzhiyun rlength = hermes_read_reg(hw, dreg);
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun if (!rlength)
503*4882a593Smuzhiyun return -ENODATA;
504*4882a593Smuzhiyun
505*4882a593Smuzhiyun rtype = hermes_read_reg(hw, dreg);
506*4882a593Smuzhiyun
507*4882a593Smuzhiyun if (length)
508*4882a593Smuzhiyun *length = rlength;
509*4882a593Smuzhiyun
510*4882a593Smuzhiyun if (rtype != rid)
511*4882a593Smuzhiyun printk(KERN_WARNING "hermes @ %p: %s(): "
512*4882a593Smuzhiyun "rid (0x%04x) does not match type (0x%04x)\n",
513*4882a593Smuzhiyun hw->iobase, __func__, rid, rtype);
514*4882a593Smuzhiyun if (HERMES_RECLEN_TO_BYTES(rlength) > bufsize)
515*4882a593Smuzhiyun printk(KERN_WARNING "hermes @ %p: "
516*4882a593Smuzhiyun "Truncating LTV record from %d to %d bytes. "
517*4882a593Smuzhiyun "(rid=0x%04x, len=0x%04x)\n", hw->iobase,
518*4882a593Smuzhiyun HERMES_RECLEN_TO_BYTES(rlength), bufsize, rid, rlength);
519*4882a593Smuzhiyun
520*4882a593Smuzhiyun nwords = min((unsigned)rlength - 1, bufsize / 2);
521*4882a593Smuzhiyun hermes_read_words(hw, dreg, buf, nwords);
522*4882a593Smuzhiyun
523*4882a593Smuzhiyun return 0;
524*4882a593Smuzhiyun }
525*4882a593Smuzhiyun
hermes_write_ltv(struct hermes * hw,int bap,u16 rid,u16 length,const void * value)526*4882a593Smuzhiyun static int hermes_write_ltv(struct hermes *hw, int bap, u16 rid,
527*4882a593Smuzhiyun u16 length, const void *value)
528*4882a593Smuzhiyun {
529*4882a593Smuzhiyun int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
530*4882a593Smuzhiyun int err = 0;
531*4882a593Smuzhiyun unsigned count;
532*4882a593Smuzhiyun
533*4882a593Smuzhiyun if (length == 0)
534*4882a593Smuzhiyun return -EINVAL;
535*4882a593Smuzhiyun
536*4882a593Smuzhiyun err = hermes_bap_seek(hw, bap, rid, 0);
537*4882a593Smuzhiyun if (err)
538*4882a593Smuzhiyun return err;
539*4882a593Smuzhiyun
540*4882a593Smuzhiyun hermes_write_reg(hw, dreg, length);
541*4882a593Smuzhiyun hermes_write_reg(hw, dreg, rid);
542*4882a593Smuzhiyun
543*4882a593Smuzhiyun count = length - 1;
544*4882a593Smuzhiyun
545*4882a593Smuzhiyun hermes_write_bytes(hw, dreg, value, count << 1);
546*4882a593Smuzhiyun
547*4882a593Smuzhiyun err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE,
548*4882a593Smuzhiyun rid, NULL);
549*4882a593Smuzhiyun
550*4882a593Smuzhiyun return err;
551*4882a593Smuzhiyun }
552*4882a593Smuzhiyun
553*4882a593Smuzhiyun /*** Hermes AUX control ***/
554*4882a593Smuzhiyun
555*4882a593Smuzhiyun static inline void
hermes_aux_setaddr(struct hermes * hw,u32 addr)556*4882a593Smuzhiyun hermes_aux_setaddr(struct hermes *hw, u32 addr)
557*4882a593Smuzhiyun {
558*4882a593Smuzhiyun hermes_write_reg(hw, HERMES_AUXPAGE, (u16) (addr >> 7));
559*4882a593Smuzhiyun hermes_write_reg(hw, HERMES_AUXOFFSET, (u16) (addr & 0x7F));
560*4882a593Smuzhiyun }
561*4882a593Smuzhiyun
562*4882a593Smuzhiyun static inline int
hermes_aux_control(struct hermes * hw,int enabled)563*4882a593Smuzhiyun hermes_aux_control(struct hermes *hw, int enabled)
564*4882a593Smuzhiyun {
565*4882a593Smuzhiyun int desired_state = enabled ? HERMES_AUX_ENABLED : HERMES_AUX_DISABLED;
566*4882a593Smuzhiyun int action = enabled ? HERMES_AUX_ENABLE : HERMES_AUX_DISABLE;
567*4882a593Smuzhiyun int i;
568*4882a593Smuzhiyun
569*4882a593Smuzhiyun /* Already open? */
570*4882a593Smuzhiyun if (hermes_read_reg(hw, HERMES_CONTROL) == desired_state)
571*4882a593Smuzhiyun return 0;
572*4882a593Smuzhiyun
573*4882a593Smuzhiyun hermes_write_reg(hw, HERMES_PARAM0, HERMES_AUX_PW0);
574*4882a593Smuzhiyun hermes_write_reg(hw, HERMES_PARAM1, HERMES_AUX_PW1);
575*4882a593Smuzhiyun hermes_write_reg(hw, HERMES_PARAM2, HERMES_AUX_PW2);
576*4882a593Smuzhiyun hermes_write_reg(hw, HERMES_CONTROL, action);
577*4882a593Smuzhiyun
578*4882a593Smuzhiyun for (i = 0; i < 20; i++) {
579*4882a593Smuzhiyun udelay(10);
580*4882a593Smuzhiyun if (hermes_read_reg(hw, HERMES_CONTROL) ==
581*4882a593Smuzhiyun desired_state)
582*4882a593Smuzhiyun return 0;
583*4882a593Smuzhiyun }
584*4882a593Smuzhiyun
585*4882a593Smuzhiyun return -EBUSY;
586*4882a593Smuzhiyun }
587*4882a593Smuzhiyun
588*4882a593Smuzhiyun /*** Hermes programming ***/
589*4882a593Smuzhiyun
590*4882a593Smuzhiyun /* About to start programming data (Hermes I)
591*4882a593Smuzhiyun * offset is the entry point
592*4882a593Smuzhiyun *
593*4882a593Smuzhiyun * Spectrum_cs' Symbol fw does not require this
594*4882a593Smuzhiyun * wl_lkm Agere fw does
595*4882a593Smuzhiyun * Don't know about intersil
596*4882a593Smuzhiyun */
hermesi_program_init(struct hermes * hw,u32 offset)597*4882a593Smuzhiyun static int hermesi_program_init(struct hermes *hw, u32 offset)
598*4882a593Smuzhiyun {
599*4882a593Smuzhiyun int err;
600*4882a593Smuzhiyun
601*4882a593Smuzhiyun /* Disable interrupts?*/
602*4882a593Smuzhiyun /*hw->inten = 0x0;*/
603*4882a593Smuzhiyun /*hermes_write_regn(hw, INTEN, 0);*/
604*4882a593Smuzhiyun /*hermes_set_irqmask(hw, 0);*/
605*4882a593Smuzhiyun
606*4882a593Smuzhiyun /* Acknowledge any outstanding command */
607*4882a593Smuzhiyun hermes_write_regn(hw, EVACK, 0xFFFF);
608*4882a593Smuzhiyun
609*4882a593Smuzhiyun /* Using init_cmd_wait rather than cmd_wait */
610*4882a593Smuzhiyun err = hw->ops->init_cmd_wait(hw,
611*4882a593Smuzhiyun 0x0100 | HERMES_CMD_INIT,
612*4882a593Smuzhiyun 0, 0, 0, NULL);
613*4882a593Smuzhiyun if (err)
614*4882a593Smuzhiyun return err;
615*4882a593Smuzhiyun
616*4882a593Smuzhiyun err = hw->ops->init_cmd_wait(hw,
617*4882a593Smuzhiyun 0x0000 | HERMES_CMD_INIT,
618*4882a593Smuzhiyun 0, 0, 0, NULL);
619*4882a593Smuzhiyun if (err)
620*4882a593Smuzhiyun return err;
621*4882a593Smuzhiyun
622*4882a593Smuzhiyun err = hermes_aux_control(hw, 1);
623*4882a593Smuzhiyun pr_debug("AUX enable returned %d\n", err);
624*4882a593Smuzhiyun
625*4882a593Smuzhiyun if (err)
626*4882a593Smuzhiyun return err;
627*4882a593Smuzhiyun
628*4882a593Smuzhiyun pr_debug("Enabling volatile, EP 0x%08x\n", offset);
629*4882a593Smuzhiyun err = hw->ops->init_cmd_wait(hw,
630*4882a593Smuzhiyun HERMES_PROGRAM_ENABLE_VOLATILE,
631*4882a593Smuzhiyun offset & 0xFFFFu,
632*4882a593Smuzhiyun offset >> 16,
633*4882a593Smuzhiyun 0,
634*4882a593Smuzhiyun NULL);
635*4882a593Smuzhiyun pr_debug("PROGRAM_ENABLE returned %d\n", err);
636*4882a593Smuzhiyun
637*4882a593Smuzhiyun return err;
638*4882a593Smuzhiyun }
639*4882a593Smuzhiyun
640*4882a593Smuzhiyun /* Done programming data (Hermes I)
641*4882a593Smuzhiyun *
642*4882a593Smuzhiyun * Spectrum_cs' Symbol fw does not require this
643*4882a593Smuzhiyun * wl_lkm Agere fw does
644*4882a593Smuzhiyun * Don't know about intersil
645*4882a593Smuzhiyun */
hermesi_program_end(struct hermes * hw)646*4882a593Smuzhiyun static int hermesi_program_end(struct hermes *hw)
647*4882a593Smuzhiyun {
648*4882a593Smuzhiyun struct hermes_response resp;
649*4882a593Smuzhiyun int rc = 0;
650*4882a593Smuzhiyun int err;
651*4882a593Smuzhiyun
652*4882a593Smuzhiyun rc = hw->ops->cmd_wait(hw, HERMES_PROGRAM_DISABLE, 0, &resp);
653*4882a593Smuzhiyun
654*4882a593Smuzhiyun pr_debug("PROGRAM_DISABLE returned %d, "
655*4882a593Smuzhiyun "r0 0x%04x, r1 0x%04x, r2 0x%04x\n",
656*4882a593Smuzhiyun rc, resp.resp0, resp.resp1, resp.resp2);
657*4882a593Smuzhiyun
658*4882a593Smuzhiyun if ((rc == 0) &&
659*4882a593Smuzhiyun ((resp.status & HERMES_STATUS_CMDCODE) != HERMES_CMD_DOWNLD))
660*4882a593Smuzhiyun rc = -EIO;
661*4882a593Smuzhiyun
662*4882a593Smuzhiyun err = hermes_aux_control(hw, 0);
663*4882a593Smuzhiyun pr_debug("AUX disable returned %d\n", err);
664*4882a593Smuzhiyun
665*4882a593Smuzhiyun /* Acknowledge any outstanding command */
666*4882a593Smuzhiyun hermes_write_regn(hw, EVACK, 0xFFFF);
667*4882a593Smuzhiyun
668*4882a593Smuzhiyun /* Reinitialise, ignoring return */
669*4882a593Smuzhiyun (void) hw->ops->init_cmd_wait(hw, 0x0000 | HERMES_CMD_INIT,
670*4882a593Smuzhiyun 0, 0, 0, NULL);
671*4882a593Smuzhiyun
672*4882a593Smuzhiyun return rc ? rc : err;
673*4882a593Smuzhiyun }
674*4882a593Smuzhiyun
hermes_program_bytes(struct hermes * hw,const char * data,u32 addr,u32 len)675*4882a593Smuzhiyun static int hermes_program_bytes(struct hermes *hw, const char *data,
676*4882a593Smuzhiyun u32 addr, u32 len)
677*4882a593Smuzhiyun {
678*4882a593Smuzhiyun /* wl lkm splits the programming into chunks of 2000 bytes.
679*4882a593Smuzhiyun * This restriction appears to come from USB. The PCMCIA
680*4882a593Smuzhiyun * adapters can program the whole lot in one go */
681*4882a593Smuzhiyun hermes_aux_setaddr(hw, addr);
682*4882a593Smuzhiyun hermes_write_bytes(hw, HERMES_AUXDATA, data, len);
683*4882a593Smuzhiyun return 0;
684*4882a593Smuzhiyun }
685*4882a593Smuzhiyun
686*4882a593Smuzhiyun /* Read PDA from the adapter */
hermes_read_pda(struct hermes * hw,__le16 * pda,u32 pda_addr,u16 pda_len)687*4882a593Smuzhiyun static int hermes_read_pda(struct hermes *hw, __le16 *pda, u32 pda_addr,
688*4882a593Smuzhiyun u16 pda_len)
689*4882a593Smuzhiyun {
690*4882a593Smuzhiyun int ret;
691*4882a593Smuzhiyun u16 pda_size;
692*4882a593Smuzhiyun u16 data_len = pda_len;
693*4882a593Smuzhiyun __le16 *data = pda;
694*4882a593Smuzhiyun
695*4882a593Smuzhiyun if (hw->eeprom_pda) {
696*4882a593Smuzhiyun /* PDA of spectrum symbol is in eeprom */
697*4882a593Smuzhiyun
698*4882a593Smuzhiyun /* Issue command to read EEPROM */
699*4882a593Smuzhiyun ret = hw->ops->cmd_wait(hw, HERMES_CMD_READMIF, 0, NULL);
700*4882a593Smuzhiyun if (ret)
701*4882a593Smuzhiyun return ret;
702*4882a593Smuzhiyun } else {
703*4882a593Smuzhiyun /* wl_lkm does not include PDA size in the PDA area.
704*4882a593Smuzhiyun * We will pad the information into pda, so other routines
705*4882a593Smuzhiyun * don't have to be modified */
706*4882a593Smuzhiyun pda[0] = cpu_to_le16(pda_len - 2);
707*4882a593Smuzhiyun /* Includes CFG_PROD_DATA but not itself */
708*4882a593Smuzhiyun pda[1] = cpu_to_le16(0x0800); /* CFG_PROD_DATA */
709*4882a593Smuzhiyun data_len = pda_len - 4;
710*4882a593Smuzhiyun data = pda + 2;
711*4882a593Smuzhiyun }
712*4882a593Smuzhiyun
713*4882a593Smuzhiyun /* Open auxiliary port */
714*4882a593Smuzhiyun ret = hermes_aux_control(hw, 1);
715*4882a593Smuzhiyun pr_debug("AUX enable returned %d\n", ret);
716*4882a593Smuzhiyun if (ret)
717*4882a593Smuzhiyun return ret;
718*4882a593Smuzhiyun
719*4882a593Smuzhiyun /* Read PDA */
720*4882a593Smuzhiyun hermes_aux_setaddr(hw, pda_addr);
721*4882a593Smuzhiyun hermes_read_words(hw, HERMES_AUXDATA, data, data_len / 2);
722*4882a593Smuzhiyun
723*4882a593Smuzhiyun /* Close aux port */
724*4882a593Smuzhiyun ret = hermes_aux_control(hw, 0);
725*4882a593Smuzhiyun pr_debug("AUX disable returned %d\n", ret);
726*4882a593Smuzhiyun
727*4882a593Smuzhiyun /* Check PDA length */
728*4882a593Smuzhiyun pda_size = le16_to_cpu(pda[0]);
729*4882a593Smuzhiyun pr_debug("Actual PDA length %d, Max allowed %d\n",
730*4882a593Smuzhiyun pda_size, pda_len);
731*4882a593Smuzhiyun if (pda_size > pda_len)
732*4882a593Smuzhiyun return -EINVAL;
733*4882a593Smuzhiyun
734*4882a593Smuzhiyun return 0;
735*4882a593Smuzhiyun }
736*4882a593Smuzhiyun
hermes_lock_irqsave(spinlock_t * lock,unsigned long * flags)737*4882a593Smuzhiyun static void hermes_lock_irqsave(spinlock_t *lock,
738*4882a593Smuzhiyun unsigned long *flags) __acquires(lock)
739*4882a593Smuzhiyun {
740*4882a593Smuzhiyun spin_lock_irqsave(lock, *flags);
741*4882a593Smuzhiyun }
742*4882a593Smuzhiyun
hermes_unlock_irqrestore(spinlock_t * lock,unsigned long * flags)743*4882a593Smuzhiyun static void hermes_unlock_irqrestore(spinlock_t *lock,
744*4882a593Smuzhiyun unsigned long *flags) __releases(lock)
745*4882a593Smuzhiyun {
746*4882a593Smuzhiyun spin_unlock_irqrestore(lock, *flags);
747*4882a593Smuzhiyun }
748*4882a593Smuzhiyun
hermes_lock_irq(spinlock_t * lock)749*4882a593Smuzhiyun static void hermes_lock_irq(spinlock_t *lock) __acquires(lock)
750*4882a593Smuzhiyun {
751*4882a593Smuzhiyun spin_lock_irq(lock);
752*4882a593Smuzhiyun }
753*4882a593Smuzhiyun
hermes_unlock_irq(spinlock_t * lock)754*4882a593Smuzhiyun static void hermes_unlock_irq(spinlock_t *lock) __releases(lock)
755*4882a593Smuzhiyun {
756*4882a593Smuzhiyun spin_unlock_irq(lock);
757*4882a593Smuzhiyun }
758*4882a593Smuzhiyun
759*4882a593Smuzhiyun /* Hermes operations for local buses */
760*4882a593Smuzhiyun static const struct hermes_ops hermes_ops_local = {
761*4882a593Smuzhiyun .init = hermes_init,
762*4882a593Smuzhiyun .cmd_wait = hermes_docmd_wait,
763*4882a593Smuzhiyun .init_cmd_wait = hermes_doicmd_wait,
764*4882a593Smuzhiyun .allocate = hermes_allocate,
765*4882a593Smuzhiyun .read_ltv = hermes_read_ltv,
766*4882a593Smuzhiyun .write_ltv = hermes_write_ltv,
767*4882a593Smuzhiyun .bap_pread = hermes_bap_pread,
768*4882a593Smuzhiyun .bap_pwrite = hermes_bap_pwrite,
769*4882a593Smuzhiyun .read_pda = hermes_read_pda,
770*4882a593Smuzhiyun .program_init = hermesi_program_init,
771*4882a593Smuzhiyun .program_end = hermesi_program_end,
772*4882a593Smuzhiyun .program = hermes_program_bytes,
773*4882a593Smuzhiyun .lock_irqsave = hermes_lock_irqsave,
774*4882a593Smuzhiyun .unlock_irqrestore = hermes_unlock_irqrestore,
775*4882a593Smuzhiyun .lock_irq = hermes_lock_irq,
776*4882a593Smuzhiyun .unlock_irq = hermes_unlock_irq,
777*4882a593Smuzhiyun };
778