root/drivers/net/wireless/intersil/prism54/isl_38xx.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. isl38xx_disable_interrupts
  2. isl38xx_handle_sleep_request
  3. isl38xx_handle_wakeup
  4. isl38xx_trigger_device
  5. isl38xx_interface_reset
  6. isl38xx_enable_common_interrupts
  7. isl38xx_in_queue

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

/* [<][>][^][v][top][bottom][index][help] */