static int islpci_upload_fw(islpci_private *priv) { islpci_state_t old_state; u32 rc; old_state = islpci_set_state(priv, PRV_STATE_BOOT); printk(KERN_DEBUG "%s: uploading firmware...\n", priv->ndev->name); rc = isl_upload_firmware(priv); if (rc) { /* error uploading the firmware */ printk(KERN_ERR "%s: could not upload firmware ('%s')\n", priv->ndev->name, priv->firmware); islpci_set_state(priv, old_state); return rc; } printk(KERN_DEBUG "%s: firmware upload complete\n", priv->ndev->name); islpci_set_state(priv, PRV_STATE_POSTBOOT); return 0; }
/* this one removes one(!!) instance only */ static void prism54_remove(struct pci_dev *pdev) { struct net_device *ndev = pci_get_drvdata(pdev); islpci_private *priv = ndev ? netdev_priv(ndev) : NULL; BUG_ON(!priv); if (!__in_cleanup_module) { printk(KERN_DEBUG "%s: hot unplug detected\n", ndev->name); islpci_set_state(priv, PRV_STATE_OFF); } printk(KERN_DEBUG "%s: removing device\n", ndev->name); unregister_netdev(ndev); /* free the interrupt request */ if (islpci_get_state(priv) != PRV_STATE_OFF) { isl38xx_disable_interrupts(priv->device_base); islpci_set_state(priv, PRV_STATE_OFF); /* This bellow causes a lockup at rmmod time. It might be * because some interrupts still linger after rmmod time, * see bug #17 */ /* pci_set_power_state(pdev, 3);*/ /* try to power-off */ } free_irq(pdev->irq, priv); /* free the PCI memory and unmap the remapped page */ islpci_free_memory(priv); pci_set_drvdata(pdev, NULL); free_netdev(ndev); priv = NULL; pci_clear_mwi(pdev); pci_release_regions(pdev); pci_disable_device(pdev); }
static void prism54_remove(struct pci_dev *pdev) { struct net_device *ndev = pci_get_drvdata(pdev); islpci_private *priv = ndev ? netdev_priv(ndev) : NULL; BUG_ON(!priv); if (!__in_cleanup_module) { printk(KERN_DEBUG "%s: hot unplug detected\n", ndev->name); islpci_set_state(priv, PRV_STATE_OFF); } printk(KERN_DEBUG "%s: removing device\n", ndev->name); unregister_netdev(ndev); if (islpci_get_state(priv) != PRV_STATE_OFF) { isl38xx_disable_interrupts(priv->device_base); islpci_set_state(priv, PRV_STATE_OFF); } free_irq(pdev->irq, priv); islpci_free_memory(priv); pci_set_drvdata(pdev, NULL); free_netdev(ndev); priv = NULL; pci_clear_mwi(pdev); pci_release_regions(pdev); pci_disable_device(pdev); }
static int prism54_suspend(struct pci_dev *pdev, pm_message_t state) { struct net_device *ndev = pci_get_drvdata(pdev); islpci_private *priv = ndev ? netdev_priv(ndev) : NULL; BUG_ON(!priv); pci_save_state(pdev); isl38xx_disable_interrupts(priv->device_base); islpci_set_state(priv, PRV_STATE_OFF); netif_stop_queue(ndev); netif_device_detach(ndev); return 0; }
static int prism54_bring_down(islpci_private *priv) { void __iomem *device_base = priv->device_base; u32 reg; /* we are going to shutdown the device */ islpci_set_state(priv, PRV_STATE_PREBOOT); /* disable all device interrupts in case they weren't */ isl38xx_disable_interrupts(priv->device_base); /* For safety reasons, we may want to ensure that no DMA transfer is * currently in progress by emptying the TX and RX queues. */ /* wait until interrupts have finished executing on other CPUs */ synchronize_irq(priv->pdev->irq); reg = readl(device_base + ISL38XX_CTRL_STAT_REG); reg &= ~(ISL38XX_CTRL_STAT_RESET | ISL38XX_CTRL_STAT_RAMBOOT); writel(reg, device_base + ISL38XX_CTRL_STAT_REG); wmb(); udelay(ISL38XX_WRITEIO_DELAY); reg |= ISL38XX_CTRL_STAT_RESET; writel(reg, device_base + ISL38XX_CTRL_STAT_REG); wmb(); udelay(ISL38XX_WRITEIO_DELAY); /* clear the Reset bit */ reg &= ~ISL38XX_CTRL_STAT_RESET; writel(reg, device_base + ISL38XX_CTRL_STAT_REG); wmb(); /* wait a while for the device to reset */ set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(50*HZ/1000); return 0; }
static int prism54_suspend(struct pci_dev *pdev, pm_message_t state) { struct net_device *ndev = pci_get_drvdata(pdev); islpci_private *priv = ndev ? netdev_priv(ndev) : NULL; BUG_ON(!priv); pci_save_state(pdev); /* tell the device not to trigger interrupts for now... */ isl38xx_disable_interrupts(priv->device_base); /* from now on assume the hardware was already powered down and don't touch it anymore */ islpci_set_state(priv, PRV_STATE_OFF); netif_stop_queue(ndev); netif_device_detach(ndev); return 0; }
int islpci_reset(islpci_private *priv, int reload_firmware) { isl38xx_control_block *cb = /* volatile not needed */ (isl38xx_control_block *) priv->control_block; unsigned counter; int rc; if (reload_firmware) islpci_set_state(priv, PRV_STATE_PREBOOT); else islpci_set_state(priv, PRV_STATE_POSTBOOT); printk(KERN_DEBUG "%s: resetting device...\n", priv->ndev->name); /* disable all device interrupts in case they weren't */ isl38xx_disable_interrupts(priv->device_base); /* flush all management queues */ priv->index_mgmt_tx = 0; priv->index_mgmt_rx = 0; /* clear the indexes in the frame pointer */ for (counter = 0; counter < ISL38XX_CB_QCOUNT; counter++) { cb->driver_curr_frag[counter] = cpu_to_le32(0); cb->device_curr_frag[counter] = cpu_to_le32(0); } /* reset the mgmt receive queue */ for (counter = 0; counter < ISL38XX_CB_MGMT_QSIZE; counter++) { isl38xx_fragment *frag = &cb->rx_data_mgmt[counter]; frag->size = cpu_to_le16(MGMT_FRAME_SIZE); frag->flags = 0; frag->address = cpu_to_le32(priv->mgmt_rx[counter].pci_addr); } for (counter = 0; counter < ISL38XX_CB_RX_QSIZE; counter++) { cb->rx_data_low[counter].address = cpu_to_le32((u32) priv->pci_map_rx_address[counter]); } /* since the receive queues are filled with empty fragments, now we can * set the corresponding indexes in the Control Block */ priv->control_block->driver_curr_frag[ISL38XX_CB_RX_DATA_LQ] = cpu_to_le32(ISL38XX_CB_RX_QSIZE); priv->control_block->driver_curr_frag[ISL38XX_CB_RX_MGMTQ] = cpu_to_le32(ISL38XX_CB_MGMT_QSIZE); /* reset the remaining real index registers and full flags */ priv->free_data_rx = 0; priv->free_data_tx = 0; priv->data_low_tx_full = 0; if (reload_firmware) { /* Should we load the firmware ? */ /* now that the data structures are cleaned up, upload * firmware and reset interface */ rc = islpci_upload_fw(priv); if (rc) { printk(KERN_ERR "%s: islpci_reset: failure\n", priv->ndev->name); return rc; } } /* finally reset interface */ rc = islpci_reset_if(priv); if (rc) printk(KERN_ERR "prism54: Your card/socket may be faulty, or IRQ line too busy :(\n"); return rc; }
static int islpci_reset_if(islpci_private *priv) { long remaining; int result = -ETIME; int count; DEFINE_WAIT(wait); prepare_to_wait(&priv->reset_done, &wait, TASK_UNINTERRUPTIBLE); /* now the last step is to reset the interface */ isl38xx_interface_reset(priv->device_base, priv->device_host_address); islpci_set_state(priv, PRV_STATE_PREINIT); for(count = 0; count < 2 && result; count++) { /* The software reset acknowledge needs about 220 msec here. * Be conservative and wait for up to one second. */ remaining = schedule_timeout_uninterruptible(HZ); if(remaining > 0) { result = 0; break; } /* If we're here it's because our IRQ hasn't yet gone through. * Retry a bit more... */ printk(KERN_ERR "%s: no 'reset complete' IRQ seen - retrying\n", priv->ndev->name); } finish_wait(&priv->reset_done, &wait); if (result) { printk(KERN_ERR "%s: interface reset failure\n", priv->ndev->name); return result; } islpci_set_state(priv, PRV_STATE_INIT); /* Now that the device is 100% up, let's allow * for the other interrupts -- * NOTE: this is not *yet* true since we've only allowed the * INIT interrupt on the IRQ line. We can perhaps poll * the IRQ line until we know for sure the reset went through */ isl38xx_enable_common_interrupts(priv->device_base); down_write(&priv->mib_sem); result = mgt_commit(priv); if (result) { printk(KERN_ERR "%s: interface reset failure\n", priv->ndev->name); up_write(&priv->mib_sem); return result; } up_write(&priv->mib_sem); islpci_set_state(priv, PRV_STATE_READY); printk(KERN_DEBUG "%s: interface reset complete\n", priv->ndev->name); return 0; }
irqreturn_t islpci_interrupt(int irq, void *config) { u32 reg; islpci_private *priv = config; struct net_device *ndev = priv->ndev; void __iomem *device = priv->device_base; int powerstate = ISL38XX_PSM_POWERSAVE_STATE; /* lock the interrupt handler */ spin_lock(&priv->slock); /* received an interrupt request on a shared IRQ line * first check whether the device is in sleep mode */ reg = readl(device + ISL38XX_CTRL_STAT_REG); if (reg & ISL38XX_CTRL_STAT_SLEEPMODE) /* device is in sleep mode, IRQ was generated by someone else */ { #if VERBOSE > SHOW_ERROR_MESSAGES DEBUG(SHOW_TRACING, "Assuming someone else called the IRQ\n"); #endif spin_unlock(&priv->slock); return IRQ_NONE; } /* check whether there is any source of interrupt on the device */ reg = readl(device + ISL38XX_INT_IDENT_REG); /* also check the contents of the Interrupt Enable Register, because this * will filter out interrupt sources from other devices on the same irq ! */ reg &= readl(device + ISL38XX_INT_EN_REG); reg &= ISL38XX_INT_SOURCES; if (reg != 0) { if (islpci_get_state(priv) != PRV_STATE_SLEEP) powerstate = ISL38XX_PSM_ACTIVE_STATE; /* reset the request bits in the Identification register */ isl38xx_w32_flush(device, reg, ISL38XX_INT_ACK_REG); #if VERBOSE > SHOW_ERROR_MESSAGES DEBUG(SHOW_FUNCTION_CALLS, "IRQ: Identification register 0x%p 0x%x \n", device, reg); #endif /* check for each bit in the register separately */ if (reg & ISL38XX_INT_IDENT_UPDATE) { #if VERBOSE > SHOW_ERROR_MESSAGES /* Queue has been updated */ DEBUG(SHOW_TRACING, "IRQ: Update flag \n"); DEBUG(SHOW_QUEUE_INDEXES, "CB drv Qs: [%i][%i][%i][%i][%i][%i]\n", le32_to_cpu(priv->control_block-> driver_curr_frag[0]), le32_to_cpu(priv->control_block-> driver_curr_frag[1]), le32_to_cpu(priv->control_block-> driver_curr_frag[2]), le32_to_cpu(priv->control_block-> driver_curr_frag[3]), le32_to_cpu(priv->control_block-> driver_curr_frag[4]), le32_to_cpu(priv->control_block-> driver_curr_frag[5]) ); DEBUG(SHOW_QUEUE_INDEXES, "CB dev Qs: [%i][%i][%i][%i][%i][%i]\n", le32_to_cpu(priv->control_block-> device_curr_frag[0]), le32_to_cpu(priv->control_block-> device_curr_frag[1]), le32_to_cpu(priv->control_block-> device_curr_frag[2]), le32_to_cpu(priv->control_block-> device_curr_frag[3]), le32_to_cpu(priv->control_block-> device_curr_frag[4]), le32_to_cpu(priv->control_block-> device_curr_frag[5]) ); #endif /* cleanup the data low transmit queue */ islpci_eth_cleanup_transmit(priv, priv->control_block); /* device is in active state, update the * powerstate flag if necessary */ powerstate = ISL38XX_PSM_ACTIVE_STATE; /* check all three queues in priority order * call the PIMFOR receive function until the * queue is empty */ if (isl38xx_in_queue(priv->control_block, ISL38XX_CB_RX_MGMTQ) != 0) { #if VERBOSE > SHOW_ERROR_MESSAGES DEBUG(SHOW_TRACING, "Received frame in Management Queue\n"); #endif islpci_mgt_receive(ndev); islpci_mgt_cleanup_transmit(ndev); /* Refill slots in receive queue */ islpci_mgmt_rx_fill(ndev); /* no need to trigger the device, next islpci_mgt_transaction does it */ } while (isl38xx_in_queue(priv->control_block, ISL38XX_CB_RX_DATA_LQ) != 0) { #if VERBOSE > SHOW_ERROR_MESSAGES DEBUG(SHOW_TRACING, "Received frame in Data Low Queue \n"); #endif islpci_eth_receive(priv); } /* check whether the data transmit queues were full */ if (priv->data_low_tx_full) { /* check whether the transmit is not full anymore */ if (ISL38XX_CB_TX_QSIZE - isl38xx_in_queue(priv->control_block, ISL38XX_CB_TX_DATA_LQ) >= ISL38XX_MIN_QTHRESHOLD) { /* nope, the driver is ready for more network frames */ netif_wake_queue(priv->ndev); /* reset the full flag */ priv->data_low_tx_full = 0; } } } if (reg & ISL38XX_INT_IDENT_INIT) { /* Device has been initialized */ #if VERBOSE > SHOW_ERROR_MESSAGES DEBUG(SHOW_TRACING, "IRQ: Init flag, device initialized \n"); #endif wake_up(&priv->reset_done); } if (reg & ISL38XX_INT_IDENT_SLEEP) { /* Device intends to move to powersave state */ #if VERBOSE > SHOW_ERROR_MESSAGES DEBUG(SHOW_TRACING, "IRQ: Sleep flag \n"); #endif isl38xx_handle_sleep_request(priv->control_block, &powerstate, priv->device_base); } if (reg & ISL38XX_INT_IDENT_WAKEUP) { /* Device has been woken up to active state */ #if VERBOSE > SHOW_ERROR_MESSAGES DEBUG(SHOW_TRACING, "IRQ: Wakeup flag \n"); #endif isl38xx_handle_wakeup(priv->control_block, &powerstate, priv->device_base); } } else { #if VERBOSE > SHOW_ERROR_MESSAGES DEBUG(SHOW_TRACING, "Assuming someone else called the IRQ\n"); #endif spin_unlock(&priv->slock); return IRQ_NONE; } /* sleep -> ready */ if (islpci_get_state(priv) == PRV_STATE_SLEEP && powerstate == ISL38XX_PSM_ACTIVE_STATE) islpci_set_state(priv, PRV_STATE_READY); /* !sleep -> sleep */ if (islpci_get_state(priv) != PRV_STATE_SLEEP && powerstate == ISL38XX_PSM_POWERSAVE_STATE) islpci_set_state(priv, PRV_STATE_SLEEP); /* unlock the interrupt handler */ spin_unlock(&priv->slock); return IRQ_HANDLED; }
static int prism54_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct net_device *ndev; u8 latency_tmr; u32 mem_addr; islpci_private *priv; int rvalue; /* Enable the pci device */ if (pci_enable_device(pdev)) { printk(KERN_ERR "%s: pci_enable_device() failed.\n", DRV_NAME); return -ENODEV; } /* check whether the latency timer is set correctly */ pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency_tmr); #if VERBOSE > SHOW_ERROR_MESSAGES DEBUG(SHOW_TRACING, "latency timer: %x\n", latency_tmr); #endif if (latency_tmr < PCIDEVICE_LATENCY_TIMER_MIN) { /* set the latency timer */ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, PCIDEVICE_LATENCY_TIMER_VAL); } /* enable PCI DMA */ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) { printk(KERN_ERR "%s: 32-bit PCI DMA not supported", DRV_NAME); goto do_pci_disable_device; } /* 0x40 is the programmable timer to configure the response timeout (TRDY_TIMEOUT) * 0x41 is the programmable timer to configure the retry timeout (RETRY_TIMEOUT) * The RETRY_TIMEOUT is used to set the number of retries that the core, as a * Master, will perform before abandoning a cycle. The default value for * RETRY_TIMEOUT is 0x80, which far exceeds the PCI 2.1 requirement for new * devices. A write of zero to the RETRY_TIMEOUT register disables this * function to allow use with any non-compliant legacy devices that may * execute more retries. * * Writing zero to both these two registers will disable both timeouts and * *can* solve problems caused by devices that are slow to respond. * Make this configurable - MSW */ if ( init_pcitm >= 0 ) { pci_write_config_byte(pdev, 0x40, (u8)init_pcitm); pci_write_config_byte(pdev, 0x41, (u8)init_pcitm); } else { printk(KERN_INFO "PCI TRDY/RETRY unchanged\n"); } /* request the pci device I/O regions */ rvalue = pci_request_regions(pdev, DRV_NAME); if (rvalue) { printk(KERN_ERR "%s: pci_request_regions failure (rc=%d)\n", DRV_NAME, rvalue); goto do_pci_disable_device; } /* check if the memory window is indeed set */ rvalue = pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &mem_addr); if (rvalue || !mem_addr) { printk(KERN_ERR "%s: PCI device memory region not configured; fix your BIOS or CardBus bridge/drivers\n", DRV_NAME); goto do_pci_release_regions; } /* enable PCI bus-mastering */ DEBUG(SHOW_TRACING, "%s: pci_set_master(pdev)\n", DRV_NAME); pci_set_master(pdev); /* enable MWI */ pci_try_set_mwi(pdev); /* setup the network device interface and its structure */ if (!(ndev = islpci_setup(pdev))) { /* error configuring the driver as a network device */ printk(KERN_ERR "%s: could not configure network device\n", DRV_NAME); goto do_pci_clear_mwi; } priv = netdev_priv(ndev); islpci_set_state(priv, PRV_STATE_PREBOOT); /* we are attempting to boot */ /* card is in unknown state yet, might have some interrupts pending */ isl38xx_disable_interrupts(priv->device_base); /* request for the interrupt before uploading the firmware */ rvalue = request_irq(pdev->irq, islpci_interrupt, IRQF_SHARED, ndev->name, priv); if (rvalue) { /* error, could not hook the handler to the irq */ printk(KERN_ERR "%s: could not install IRQ handler\n", ndev->name); goto do_unregister_netdev; } /* firmware upload is triggered in islpci_open */ return 0; do_unregister_netdev: unregister_netdev(ndev); islpci_free_memory(priv); pci_set_drvdata(pdev, NULL); free_netdev(ndev); priv = NULL; do_pci_clear_mwi: pci_clear_mwi(pdev); do_pci_release_regions: pci_release_regions(pdev); do_pci_disable_device: pci_disable_device(pdev); return -EIO; }
static int prism54_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct net_device *ndev; u8 latency_tmr; u32 mem_addr; islpci_private *priv; int rvalue; if (pci_enable_device(pdev)) { printk(KERN_ERR "%s: pci_enable_device() failed.\n", DRV_NAME); return -ENODEV; } pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency_tmr); #if VERBOSE > SHOW_ERROR_MESSAGES DEBUG(SHOW_TRACING, "latency timer: %x\n", latency_tmr); #endif if (latency_tmr < PCIDEVICE_LATENCY_TIMER_MIN) { pci_write_config_byte(pdev, PCI_LATENCY_TIMER, PCIDEVICE_LATENCY_TIMER_VAL); } if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) { printk(KERN_ERR "%s: 32-bit PCI DMA not supported", DRV_NAME); goto do_pci_disable_device; } if ( init_pcitm >= 0 ) { pci_write_config_byte(pdev, 0x40, (u8)init_pcitm); pci_write_config_byte(pdev, 0x41, (u8)init_pcitm); } else { printk(KERN_INFO "PCI TRDY/RETRY unchanged\n"); } rvalue = pci_request_regions(pdev, DRV_NAME); if (rvalue) { printk(KERN_ERR "%s: pci_request_regions failure (rc=%d)\n", DRV_NAME, rvalue); goto do_pci_disable_device; } rvalue = pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &mem_addr); if (rvalue || !mem_addr) { printk(KERN_ERR "%s: PCI device memory region not configured; fix your BIOS or CardBus bridge/drivers\n", DRV_NAME); goto do_pci_release_regions; } DEBUG(SHOW_TRACING, "%s: pci_set_master(pdev)\n", DRV_NAME); pci_set_master(pdev); pci_try_set_mwi(pdev); if (!(ndev = islpci_setup(pdev))) { printk(KERN_ERR "%s: could not configure network device\n", DRV_NAME); goto do_pci_clear_mwi; } priv = netdev_priv(ndev); islpci_set_state(priv, PRV_STATE_PREBOOT); isl38xx_disable_interrupts(priv->device_base); rvalue = request_irq(pdev->irq, &islpci_interrupt, IRQF_SHARED, ndev->name, priv); if (rvalue) { printk(KERN_ERR "%s: could not install IRQ handler\n", ndev->name); goto do_unregister_netdev; } return 0; do_unregister_netdev: unregister_netdev(ndev); islpci_free_memory(priv); pci_set_drvdata(pdev, NULL); free_netdev(ndev); priv = NULL; do_pci_clear_mwi: pci_clear_mwi(pdev); do_pci_release_regions: pci_release_regions(pdev); do_pci_disable_device: pci_disable_device(pdev); return -EIO; }