11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Copyright (C) 2002 Intersil Americas Inc.
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Copyright (C) 2003-2004 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu>_
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  This program is free software; you can redistribute it and/or modify
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  it under the terms of the GNU General Public License as published by
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  the Free Software Foundation; either version 2 of the License
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  This program is distributed in the hope that it will be useful,
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  but WITHOUT ANY WARRANTY; without even the implied warranty of
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  GNU General Public License for more details.
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  You should have received a copy of the GNU General Public License
154280db9d00f96d51789b5b77980173f0491fa594Jeff Kirsher *  along with this program; if not, see <http://www.gnu.org/licenses/>.
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h>
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h>
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "prismcompat.h"
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "isl_38xx.h"
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "islpci_dev.h"
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "islpci_mgt.h"
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/******************************************************************************
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Device Interface & Control functions
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds******************************************************************************/
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * isl38xx_disable_interrupts - disable all interrupts
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @device: pci memory base address
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
3993b2dd12049d1adb0d76fb918fcd4c1030445433Dmitry Torokhov *  Instructs the device to disable all interrupt reporting by asserting
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  the IRQ line. New events may still show up in the interrupt identification
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  register located at offset %ISL38XX_INT_IDENT_REG.
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsisl38xx_disable_interrupts(void __iomem *device)
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	isl38xx_w32_flush(device, 0x00000000, ISL38XX_INT_EN_REG);
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(ISL38XX_WRITEIO_DELAY);
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsisl38xx_handle_sleep_request(isl38xx_control_block *control_block,
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     int *powerstate, void __iomem *device_base)
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* device requests to go into sleep mode
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * check whether the transmit queues for data and management are empty */
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (isl38xx_in_queue(control_block, ISL38XX_CB_TX_DATA_LQ))
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* data tx queue not empty */
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (isl38xx_in_queue(control_block, ISL38XX_CB_TX_MGMTQ))
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* management tx queue not empty */
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* check also whether received frames are pending */
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (isl38xx_in_queue(control_block, ISL38XX_CB_RX_DATA_LQ))
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* data rx queue not empty */
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (isl38xx_in_queue(control_block, ISL38XX_CB_RX_MGMTQ))
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* management rx queue not empty */
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if VERBOSE > SHOW_ERROR_MESSAGES
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DEBUG(SHOW_TRACING, "Device going to sleep mode\n");
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* all queues are empty, allow the device to go into sleep mode */
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*powerstate = ISL38XX_PSM_POWERSAVE_STATE;
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* assert the Sleep interrupt in the Device Interrupt Register */
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_SLEEP,
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  ISL38XX_DEV_INT_REG);
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(ISL38XX_WRITEIO_DELAY);
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsisl38xx_handle_wakeup(isl38xx_control_block *control_block,
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      int *powerstate, void __iomem *device_base)
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* device is in active state, update the powerstate flag */
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*powerstate = ISL38XX_PSM_ACTIVE_STATE;
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* now check whether there are frames pending for the card */
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!isl38xx_in_queue(control_block, ISL38XX_CB_TX_DATA_LQ)
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    && !isl38xx_in_queue(control_block, ISL38XX_CB_TX_MGMTQ))
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if VERBOSE > SHOW_ERROR_MESSAGES
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DEBUG(SHOW_ANYTHING, "Wake up handler trigger the device\n");
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* either data or management transmit queue has a frame pending
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * trigger the device by setting the Update bit in the Device Int reg */
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_UPDATE,
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  ISL38XX_DEV_INT_REG);
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(ISL38XX_WRITEIO_DELAY);
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsisl38xx_trigger_device(int asleep, void __iomem *device_base)
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
112de7fe963b123365a27f82330689806226a48d088Roger While	u32 reg;
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if VERBOSE > SHOW_ERROR_MESSAGES
115de7fe963b123365a27f82330689806226a48d088Roger While	u32 counter = 0;
11605ab195c9803946931390faa6cfb714bd1c1e3dcOlaf Hering	struct timeval current_time;
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DEBUG(SHOW_FUNCTION_CALLS, "isl38xx trigger device\n");
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* check whether the device is in power save mode */
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (asleep) {
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* device is in powersave, trigger the device for wakeup */
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if VERBOSE > SHOW_ERROR_MESSAGES
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		do_gettimeofday(&current_time);
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DEBUG(SHOW_TRACING, "%08li.%08li Device wakeup triggered\n",
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      current_time.tv_sec, (long)current_time.tv_usec);
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DEBUG(SHOW_TRACING, "%08li.%08li Device register read %08x\n",
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      current_time.tv_sec, (long)current_time.tv_usec,
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      readl(device_base + ISL38XX_CTRL_STAT_REG));
13105ab195c9803946931390faa6cfb714bd1c1e3dcOlaf Hering#endif
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		reg = readl(device_base + ISL38XX_INT_IDENT_REG);
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (reg == 0xabadface) {
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if VERBOSE > SHOW_ERROR_MESSAGES
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			do_gettimeofday(&current_time);
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			DEBUG(SHOW_TRACING,
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "%08li.%08li Device register abadface\n",
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      current_time.tv_sec, (long)current_time.tv_usec);
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* read the Device Status Register until Sleepmode bit is set */
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			while (reg = readl(device_base + ISL38XX_CTRL_STAT_REG),
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       (reg & ISL38XX_CTRL_STAT_SLEEPMODE) == 0) {
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				udelay(ISL38XX_WRITEIO_DELAY);
145de7fe963b123365a27f82330689806226a48d088Roger While#if VERBOSE > SHOW_ERROR_MESSAGES
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				counter++;
147de7fe963b123365a27f82330689806226a48d088Roger While#endif
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15005ab195c9803946931390faa6cfb714bd1c1e3dcOlaf Hering#if VERBOSE > SHOW_ERROR_MESSAGES
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			DEBUG(SHOW_TRACING,
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "%08li.%08li Device register read %08x\n",
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      current_time.tv_sec, (long)current_time.tv_usec,
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      readl(device_base + ISL38XX_CTRL_STAT_REG));
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			do_gettimeofday(&current_time);
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			DEBUG(SHOW_TRACING,
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "%08li.%08li Device asleep counter %i\n",
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      current_time.tv_sec, (long)current_time.tv_usec,
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      counter);
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* assert the Wakeup interrupt in the Device Interrupt Register */
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_WAKEUP,
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  ISL38XX_DEV_INT_REG);
165cbf7c42b727826770a44c0a10ef3663da08e64bcRoger While
166cbf7c42b727826770a44c0a10ef3663da08e64bcRoger While#if VERBOSE > SHOW_ERROR_MESSAGES
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		udelay(ISL38XX_WRITEIO_DELAY);
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* perform another read on the Device Status Register */
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		reg = readl(device_base + ISL38XX_CTRL_STAT_REG);
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		do_gettimeofday(&current_time);
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DEBUG(SHOW_TRACING, "%08li.%08li Device register read %08x\n",
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      current_time.tv_sec, (long)current_time.tv_usec, reg);
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* device is (still) awake  */
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if VERBOSE > SHOW_ERROR_MESSAGES
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DEBUG(SHOW_TRACING, "Device is in active state\n");
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* trigger the device by setting the Update bit in the Device Int reg */
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_UPDATE,
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  ISL38XX_DEV_INT_REG);
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsisl38xx_interface_reset(void __iomem *device_base, dma_addr_t host_address)
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if VERBOSE > SHOW_ERROR_MESSAGES
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DEBUG(SHOW_FUNCTION_CALLS, "isl38xx_interface_reset\n");
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* load the address of the control block in the device */
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	isl38xx_w32_flush(device_base, host_address, ISL38XX_CTRL_BLK_BASE_REG);
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(ISL38XX_WRITEIO_DELAY);
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set the reset bit in the Device Interrupt Register */
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_RESET, ISL38XX_DEV_INT_REG);
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(ISL38XX_WRITEIO_DELAY);
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* enable the interrupt for detecting initialization */
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Note: Do not enable other interrupts here. We want the
20593b2dd12049d1adb0d76fb918fcd4c1030445433Dmitry Torokhov	 * device to have come up first 100% before allowing any other
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * interrupts. */
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	isl38xx_w32_flush(device_base, ISL38XX_INT_IDENT_INIT, ISL38XX_INT_EN_REG);
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(ISL38XX_WRITEIO_DELAY);  /* allow complete full reset */
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
21293b2dd12049d1adb0d76fb918fcd4c1030445433Dmitry Torokhovisl38xx_enable_common_interrupts(void __iomem *device_base)
21393b2dd12049d1adb0d76fb918fcd4c1030445433Dmitry Torokhov{
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 reg;
21593b2dd12049d1adb0d76fb918fcd4c1030445433Dmitry Torokhov
21693b2dd12049d1adb0d76fb918fcd4c1030445433Dmitry Torokhov	reg = ISL38XX_INT_IDENT_UPDATE | ISL38XX_INT_IDENT_SLEEP |
21793b2dd12049d1adb0d76fb918fcd4c1030445433Dmitry Torokhov	      ISL38XX_INT_IDENT_WAKEUP;
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	isl38xx_w32_flush(device_base, reg, ISL38XX_INT_EN_REG);
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(ISL38XX_WRITEIO_DELAY);
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsisl38xx_in_queue(isl38xx_control_block *cb, int queue)
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const s32 delta = (le32_to_cpu(cb->driver_curr_frag[queue]) -
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   le32_to_cpu(cb->device_curr_frag[queue]));
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* determine the amount of fragments in the queue depending on the type
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * of the queue, either transmit or receive */
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BUG_ON(delta < 0);	/* driver ptr must be ahead of device ptr */
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (queue) {
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* send queues */
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ISL38XX_CB_TX_MGMTQ:
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		BUG_ON(delta > ISL38XX_CB_MGMT_QSIZE);
23793b2dd12049d1adb0d76fb918fcd4c1030445433Dmitry Torokhov
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ISL38XX_CB_TX_DATA_LQ:
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ISL38XX_CB_TX_DATA_HQ:
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		BUG_ON(delta > ISL38XX_CB_TX_QSIZE);
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return delta;
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* receive queues */
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ISL38XX_CB_RX_MGMTQ:
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		BUG_ON(delta > ISL38XX_CB_MGMT_QSIZE);
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ISL38XX_CB_MGMT_QSIZE - delta;
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ISL38XX_CB_RX_DATA_LQ:
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ISL38XX_CB_RX_DATA_HQ:
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		BUG_ON(delta > ISL38XX_CB_RX_QSIZE);
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ISL38XX_CB_RX_QSIZE - delta;
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BUG();
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
256