xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/intersil/prism54/isl_38xx.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  *  Copyright (C) 2002 Intersil Americas Inc.
4*4882a593Smuzhiyun  *  Copyright (C) 2003-2004 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu>_
5*4882a593Smuzhiyun  */
6*4882a593Smuzhiyun 
7*4882a593Smuzhiyun #include <linux/module.h>
8*4882a593Smuzhiyun #include <linux/types.h>
9*4882a593Smuzhiyun #include <linux/delay.h>
10*4882a593Smuzhiyun #include <linux/ktime.h>
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #include <linux/uaccess.h>
13*4882a593Smuzhiyun #include <asm/io.h>
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun #include "prismcompat.h"
16*4882a593Smuzhiyun #include "isl_38xx.h"
17*4882a593Smuzhiyun #include "islpci_dev.h"
18*4882a593Smuzhiyun #include "islpci_mgt.h"
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun /******************************************************************************
21*4882a593Smuzhiyun     Device Interface & Control functions
22*4882a593Smuzhiyun ******************************************************************************/
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun /**
25*4882a593Smuzhiyun  * isl38xx_disable_interrupts - disable all interrupts
26*4882a593Smuzhiyun  * @device: pci memory base address
27*4882a593Smuzhiyun  *
28*4882a593Smuzhiyun  *  Instructs the device to disable all interrupt reporting by asserting
29*4882a593Smuzhiyun  *  the IRQ line. New events may still show up in the interrupt identification
30*4882a593Smuzhiyun  *  register located at offset %ISL38XX_INT_IDENT_REG.
31*4882a593Smuzhiyun  */
32*4882a593Smuzhiyun void
isl38xx_disable_interrupts(void __iomem * device)33*4882a593Smuzhiyun isl38xx_disable_interrupts(void __iomem *device)
34*4882a593Smuzhiyun {
35*4882a593Smuzhiyun 	isl38xx_w32_flush(device, 0x00000000, ISL38XX_INT_EN_REG);
36*4882a593Smuzhiyun 	udelay(ISL38XX_WRITEIO_DELAY);
37*4882a593Smuzhiyun }
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun void
isl38xx_handle_sleep_request(isl38xx_control_block * control_block,int * powerstate,void __iomem * device_base)40*4882a593Smuzhiyun isl38xx_handle_sleep_request(isl38xx_control_block *control_block,
41*4882a593Smuzhiyun 			     int *powerstate, void __iomem *device_base)
42*4882a593Smuzhiyun {
43*4882a593Smuzhiyun 	/* device requests to go into sleep mode
44*4882a593Smuzhiyun 	 * check whether the transmit queues for data and management are empty */
45*4882a593Smuzhiyun 	if (isl38xx_in_queue(control_block, ISL38XX_CB_TX_DATA_LQ))
46*4882a593Smuzhiyun 		/* data tx queue not empty */
47*4882a593Smuzhiyun 		return;
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun 	if (isl38xx_in_queue(control_block, ISL38XX_CB_TX_MGMTQ))
50*4882a593Smuzhiyun 		/* management tx queue not empty */
51*4882a593Smuzhiyun 		return;
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun 	/* check also whether received frames are pending */
54*4882a593Smuzhiyun 	if (isl38xx_in_queue(control_block, ISL38XX_CB_RX_DATA_LQ))
55*4882a593Smuzhiyun 		/* data rx queue not empty */
56*4882a593Smuzhiyun 		return;
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun 	if (isl38xx_in_queue(control_block, ISL38XX_CB_RX_MGMTQ))
59*4882a593Smuzhiyun 		/* management rx queue not empty */
60*4882a593Smuzhiyun 		return;
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun #if VERBOSE > SHOW_ERROR_MESSAGES
63*4882a593Smuzhiyun 	DEBUG(SHOW_TRACING, "Device going to sleep mode\n");
64*4882a593Smuzhiyun #endif
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun 	/* all queues are empty, allow the device to go into sleep mode */
67*4882a593Smuzhiyun 	*powerstate = ISL38XX_PSM_POWERSAVE_STATE;
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun 	/* assert the Sleep interrupt in the Device Interrupt Register */
70*4882a593Smuzhiyun 	isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_SLEEP,
71*4882a593Smuzhiyun 			  ISL38XX_DEV_INT_REG);
72*4882a593Smuzhiyun 	udelay(ISL38XX_WRITEIO_DELAY);
73*4882a593Smuzhiyun }
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun void
isl38xx_handle_wakeup(isl38xx_control_block * control_block,int * powerstate,void __iomem * device_base)76*4882a593Smuzhiyun isl38xx_handle_wakeup(isl38xx_control_block *control_block,
77*4882a593Smuzhiyun 		      int *powerstate, void __iomem *device_base)
78*4882a593Smuzhiyun {
79*4882a593Smuzhiyun 	/* device is in active state, update the powerstate flag */
80*4882a593Smuzhiyun 	*powerstate = ISL38XX_PSM_ACTIVE_STATE;
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun 	/* now check whether there are frames pending for the card */
83*4882a593Smuzhiyun 	if (!isl38xx_in_queue(control_block, ISL38XX_CB_TX_DATA_LQ)
84*4882a593Smuzhiyun 	    && !isl38xx_in_queue(control_block, ISL38XX_CB_TX_MGMTQ))
85*4882a593Smuzhiyun 		return;
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun #if VERBOSE > SHOW_ERROR_MESSAGES
88*4882a593Smuzhiyun 	DEBUG(SHOW_ANYTHING, "Wake up handler trigger the device\n");
89*4882a593Smuzhiyun #endif
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun 	/* either data or management transmit queue has a frame pending
92*4882a593Smuzhiyun 	 * trigger the device by setting the Update bit in the Device Int reg */
93*4882a593Smuzhiyun 	isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_UPDATE,
94*4882a593Smuzhiyun 			  ISL38XX_DEV_INT_REG);
95*4882a593Smuzhiyun 	udelay(ISL38XX_WRITEIO_DELAY);
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun void
isl38xx_trigger_device(int asleep,void __iomem * device_base)99*4882a593Smuzhiyun isl38xx_trigger_device(int asleep, void __iomem *device_base)
100*4882a593Smuzhiyun {
101*4882a593Smuzhiyun 	u32 reg;
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun #if VERBOSE > SHOW_ERROR_MESSAGES
104*4882a593Smuzhiyun 	u32 counter = 0;
105*4882a593Smuzhiyun 	struct timespec64 current_ts64;
106*4882a593Smuzhiyun 	DEBUG(SHOW_FUNCTION_CALLS, "isl38xx trigger device\n");
107*4882a593Smuzhiyun #endif
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	/* check whether the device is in power save mode */
110*4882a593Smuzhiyun 	if (asleep) {
111*4882a593Smuzhiyun 		/* device is in powersave, trigger the device for wakeup */
112*4882a593Smuzhiyun #if VERBOSE > SHOW_ERROR_MESSAGES
113*4882a593Smuzhiyun 		ktime_get_real_ts64(&current_ts64);
114*4882a593Smuzhiyun 		DEBUG(SHOW_TRACING, "%lld.%09ld Device wakeup triggered\n",
115*4882a593Smuzhiyun 		      (s64)current_ts64.tv_sec, current_ts64.tv_nsec);
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 		DEBUG(SHOW_TRACING, "%lld.%09ld Device register read %08x\n",
118*4882a593Smuzhiyun 		      (s64)current_ts64.tv_sec, current_ts64.tv_nsec,
119*4882a593Smuzhiyun 		      readl(device_base + ISL38XX_CTRL_STAT_REG));
120*4882a593Smuzhiyun #endif
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 		reg = readl(device_base + ISL38XX_INT_IDENT_REG);
123*4882a593Smuzhiyun 		if (reg == 0xabadface) {
124*4882a593Smuzhiyun #if VERBOSE > SHOW_ERROR_MESSAGES
125*4882a593Smuzhiyun 			ktime_get_real_ts64(&current_ts64);
126*4882a593Smuzhiyun 			DEBUG(SHOW_TRACING,
127*4882a593Smuzhiyun 			      "%lld.%09ld Device register abadface\n",
128*4882a593Smuzhiyun 			      (s64)current_ts64.tv_sec, current_ts64.tv_nsec);
129*4882a593Smuzhiyun #endif
130*4882a593Smuzhiyun 			/* read the Device Status Register until Sleepmode bit is set */
131*4882a593Smuzhiyun 			while (reg = readl(device_base + ISL38XX_CTRL_STAT_REG),
132*4882a593Smuzhiyun 			       (reg & ISL38XX_CTRL_STAT_SLEEPMODE) == 0) {
133*4882a593Smuzhiyun 				udelay(ISL38XX_WRITEIO_DELAY);
134*4882a593Smuzhiyun #if VERBOSE > SHOW_ERROR_MESSAGES
135*4882a593Smuzhiyun 				counter++;
136*4882a593Smuzhiyun #endif
137*4882a593Smuzhiyun 			}
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun #if VERBOSE > SHOW_ERROR_MESSAGES
140*4882a593Smuzhiyun 			DEBUG(SHOW_TRACING,
141*4882a593Smuzhiyun 			      "%lld.%09ld Device register read %08x\n",
142*4882a593Smuzhiyun 			      (s64)current_ts64.tv_sec, current_ts64.tv_nsec,
143*4882a593Smuzhiyun 			      readl(device_base + ISL38XX_CTRL_STAT_REG));
144*4882a593Smuzhiyun 			ktime_get_real_ts64(&current_ts64);
145*4882a593Smuzhiyun 			DEBUG(SHOW_TRACING,
146*4882a593Smuzhiyun 			      "%lld.%09ld Device asleep counter %i\n",
147*4882a593Smuzhiyun 			      (s64)current_ts64.tv_sec, current_ts64.tv_nsec,
148*4882a593Smuzhiyun 			      counter);
149*4882a593Smuzhiyun #endif
150*4882a593Smuzhiyun 		}
151*4882a593Smuzhiyun 		/* assert the Wakeup interrupt in the Device Interrupt Register */
152*4882a593Smuzhiyun 		isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_WAKEUP,
153*4882a593Smuzhiyun 				  ISL38XX_DEV_INT_REG);
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun #if VERBOSE > SHOW_ERROR_MESSAGES
156*4882a593Smuzhiyun 		udelay(ISL38XX_WRITEIO_DELAY);
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 		/* perform another read on the Device Status Register */
159*4882a593Smuzhiyun 		reg = readl(device_base + ISL38XX_CTRL_STAT_REG);
160*4882a593Smuzhiyun 		ktime_get_real_ts64(&current_ts64);
161*4882a593Smuzhiyun 		DEBUG(SHOW_TRACING, "%lld.%00ld Device register read %08x\n",
162*4882a593Smuzhiyun 		      (s64)current_ts64.tv_sec, current_ts64.tv_nsec, reg);
163*4882a593Smuzhiyun #endif
164*4882a593Smuzhiyun 	} else {
165*4882a593Smuzhiyun 		/* device is (still) awake  */
166*4882a593Smuzhiyun #if VERBOSE > SHOW_ERROR_MESSAGES
167*4882a593Smuzhiyun 		DEBUG(SHOW_TRACING, "Device is in active state\n");
168*4882a593Smuzhiyun #endif
169*4882a593Smuzhiyun 		/* trigger the device by setting the Update bit in the Device Int reg */
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun 		isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_UPDATE,
172*4882a593Smuzhiyun 				  ISL38XX_DEV_INT_REG);
173*4882a593Smuzhiyun 	}
174*4882a593Smuzhiyun }
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun void
isl38xx_interface_reset(void __iomem * device_base,dma_addr_t host_address)177*4882a593Smuzhiyun isl38xx_interface_reset(void __iomem *device_base, dma_addr_t host_address)
178*4882a593Smuzhiyun {
179*4882a593Smuzhiyun #if VERBOSE > SHOW_ERROR_MESSAGES
180*4882a593Smuzhiyun 	DEBUG(SHOW_FUNCTION_CALLS, "isl38xx_interface_reset\n");
181*4882a593Smuzhiyun #endif
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun 	/* load the address of the control block in the device */
184*4882a593Smuzhiyun 	isl38xx_w32_flush(device_base, host_address, ISL38XX_CTRL_BLK_BASE_REG);
185*4882a593Smuzhiyun 	udelay(ISL38XX_WRITEIO_DELAY);
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	/* set the reset bit in the Device Interrupt Register */
188*4882a593Smuzhiyun 	isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_RESET, ISL38XX_DEV_INT_REG);
189*4882a593Smuzhiyun 	udelay(ISL38XX_WRITEIO_DELAY);
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 	/* enable the interrupt for detecting initialization */
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun 	/* Note: Do not enable other interrupts here. We want the
194*4882a593Smuzhiyun 	 * device to have come up first 100% before allowing any other
195*4882a593Smuzhiyun 	 * interrupts. */
196*4882a593Smuzhiyun 	isl38xx_w32_flush(device_base, ISL38XX_INT_IDENT_INIT, ISL38XX_INT_EN_REG);
197*4882a593Smuzhiyun 	udelay(ISL38XX_WRITEIO_DELAY);  /* allow complete full reset */
198*4882a593Smuzhiyun }
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun void
isl38xx_enable_common_interrupts(void __iomem * device_base)201*4882a593Smuzhiyun isl38xx_enable_common_interrupts(void __iomem *device_base)
202*4882a593Smuzhiyun {
203*4882a593Smuzhiyun 	u32 reg;
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun 	reg = ISL38XX_INT_IDENT_UPDATE | ISL38XX_INT_IDENT_SLEEP |
206*4882a593Smuzhiyun 	      ISL38XX_INT_IDENT_WAKEUP;
207*4882a593Smuzhiyun 	isl38xx_w32_flush(device_base, reg, ISL38XX_INT_EN_REG);
208*4882a593Smuzhiyun 	udelay(ISL38XX_WRITEIO_DELAY);
209*4882a593Smuzhiyun }
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun int
isl38xx_in_queue(isl38xx_control_block * cb,int queue)212*4882a593Smuzhiyun isl38xx_in_queue(isl38xx_control_block *cb, int queue)
213*4882a593Smuzhiyun {
214*4882a593Smuzhiyun 	const s32 delta = (le32_to_cpu(cb->driver_curr_frag[queue]) -
215*4882a593Smuzhiyun 			   le32_to_cpu(cb->device_curr_frag[queue]));
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun 	/* determine the amount of fragments in the queue depending on the type
218*4882a593Smuzhiyun 	 * of the queue, either transmit or receive */
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun 	BUG_ON(delta < 0);	/* driver ptr must be ahead of device ptr */
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun 	switch (queue) {
223*4882a593Smuzhiyun 		/* send queues */
224*4882a593Smuzhiyun 	case ISL38XX_CB_TX_MGMTQ:
225*4882a593Smuzhiyun 		BUG_ON(delta > ISL38XX_CB_MGMT_QSIZE);
226*4882a593Smuzhiyun 		fallthrough;
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun 	case ISL38XX_CB_TX_DATA_LQ:
229*4882a593Smuzhiyun 	case ISL38XX_CB_TX_DATA_HQ:
230*4882a593Smuzhiyun 		BUG_ON(delta > ISL38XX_CB_TX_QSIZE);
231*4882a593Smuzhiyun 		return delta;
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun 		/* receive queues */
234*4882a593Smuzhiyun 	case ISL38XX_CB_RX_MGMTQ:
235*4882a593Smuzhiyun 		BUG_ON(delta > ISL38XX_CB_MGMT_QSIZE);
236*4882a593Smuzhiyun 		return ISL38XX_CB_MGMT_QSIZE - delta;
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun 	case ISL38XX_CB_RX_DATA_LQ:
239*4882a593Smuzhiyun 	case ISL38XX_CB_RX_DATA_HQ:
240*4882a593Smuzhiyun 		BUG_ON(delta > ISL38XX_CB_RX_QSIZE);
241*4882a593Smuzhiyun 		return ISL38XX_CB_RX_QSIZE - delta;
242*4882a593Smuzhiyun 	}
243*4882a593Smuzhiyun 	BUG();
244*4882a593Smuzhiyun 	return 0;
245*4882a593Smuzhiyun }
246