void isl38xx_interface_reset(void *device_base, dma_addr_t host_address) { u32 reg; #if VERBOSE > SHOW_ERROR_MESSAGES DEBUG(SHOW_FUNCTION_CALLS, "isl38xx_interface_reset \n"); #endif /* load the address of the control block in the device */ isl38xx_w32_flush(device_base, host_address, ISL38XX_CTRL_BLK_BASE_REG); udelay(ISL38XX_WRITEIO_DELAY); /* set the reset bit in the Device Interrupt Register */ isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_RESET, ISL38XX_DEV_INT_REG); udelay(ISL38XX_WRITEIO_DELAY); /* enable the interrupt for detecting initialization */ /* Note: Do not enable other interrupts here. We want the * device to have come up first 100% before allowing any other * interrupts. */ reg = ISL38XX_INT_IDENT_INIT; isl38xx_w32_flush(device_base, reg, ISL38XX_INT_EN_REG); udelay(ISL38XX_WRITEIO_DELAY); /* allow complete full reset */ }
void isl38xx_handle_sleep_request(isl38xx_control_block *control_block, int *powerstate, void __iomem *device_base) { if (isl38xx_in_queue(control_block, ISL38XX_CB_TX_DATA_LQ)) return; if (isl38xx_in_queue(control_block, ISL38XX_CB_TX_MGMTQ)) return; if (isl38xx_in_queue(control_block, ISL38XX_CB_RX_DATA_LQ)) return; if (isl38xx_in_queue(control_block, ISL38XX_CB_RX_MGMTQ)) return; #if VERBOSE > SHOW_ERROR_MESSAGES DEBUG(SHOW_TRACING, "Device going to sleep mode\n"); #endif *powerstate = ISL38XX_PSM_POWERSAVE_STATE; isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_SLEEP, ISL38XX_DEV_INT_REG); udelay(ISL38XX_WRITEIO_DELAY); }
void isl38xx_handle_sleep_request(isl38xx_control_block *control_block, int *powerstate, void __iomem *device_base) { /* device requests to go into sleep mode * check whether the transmit queues for data and management are empty */ if (isl38xx_in_queue(control_block, ISL38XX_CB_TX_DATA_LQ)) /* data tx queue not empty */ return; if (isl38xx_in_queue(control_block, ISL38XX_CB_TX_MGMTQ)) /* management tx queue not empty */ return; /* check also whether received frames are pending */ if (isl38xx_in_queue(control_block, ISL38XX_CB_RX_DATA_LQ)) /* data rx queue not empty */ return; if (isl38xx_in_queue(control_block, ISL38XX_CB_RX_MGMTQ)) /* management rx queue not empty */ return; #if VERBOSE > SHOW_ERROR_MESSAGES DEBUG(SHOW_TRACING, "Device going to sleep mode\n"); #endif /* all queues are empty, allow the device to go into sleep mode */ *powerstate = ISL38XX_PSM_POWERSAVE_STATE; /* assert the Sleep interrupt in the Device Interrupt Register */ isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_SLEEP, ISL38XX_DEV_INT_REG); udelay(ISL38XX_WRITEIO_DELAY); }
void isl38xx_enable_common_interrupts(void *device_base) { u32 reg; reg = ( ISL38XX_INT_IDENT_UPDATE | ISL38XX_INT_IDENT_SLEEP | ISL38XX_INT_IDENT_WAKEUP); isl38xx_w32_flush(device_base, reg, ISL38XX_INT_EN_REG); udelay(ISL38XX_WRITEIO_DELAY); }
void isl38xx_interface_reset(void __iomem *device_base, dma_addr_t host_address) { #if VERBOSE > SHOW_ERROR_MESSAGES DEBUG(SHOW_FUNCTION_CALLS, "isl38xx_interface_reset\n"); #endif isl38xx_w32_flush(device_base, host_address, ISL38XX_CTRL_BLK_BASE_REG); udelay(ISL38XX_WRITEIO_DELAY); isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_RESET, ISL38XX_DEV_INT_REG); udelay(ISL38XX_WRITEIO_DELAY); isl38xx_w32_flush(device_base, ISL38XX_INT_IDENT_INIT, ISL38XX_INT_EN_REG); udelay(ISL38XX_WRITEIO_DELAY); }
void isl38xx_handle_wakeup(isl38xx_control_block *control_block, int *powerstate, void __iomem *device_base) { *powerstate = ISL38XX_PSM_ACTIVE_STATE; if (!isl38xx_in_queue(control_block, ISL38XX_CB_TX_DATA_LQ) && !isl38xx_in_queue(control_block, ISL38XX_CB_TX_MGMTQ)) return; #if VERBOSE > SHOW_ERROR_MESSAGES DEBUG(SHOW_ANYTHING, "Wake up handler trigger the device\n"); #endif isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_UPDATE, ISL38XX_DEV_INT_REG); udelay(ISL38XX_WRITEIO_DELAY); }
void isl38xx_handle_wakeup(isl38xx_control_block *control_block, int *powerstate, void __iomem *device_base) { /* device is in active state, update the powerstate flag */ *powerstate = ISL38XX_PSM_ACTIVE_STATE; /* now check whether there are frames pending for the card */ if (!isl38xx_in_queue(control_block, ISL38XX_CB_TX_DATA_LQ) && !isl38xx_in_queue(control_block, ISL38XX_CB_TX_MGMTQ)) return; #if VERBOSE > SHOW_ERROR_MESSAGES DEBUG(SHOW_ANYTHING, "Wake up handler trigger the device\n"); #endif /* either data or management transmit queue has a frame pending * trigger the device by setting the Update bit in the Device Int reg */ isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_UPDATE, ISL38XX_DEV_INT_REG); udelay(ISL38XX_WRITEIO_DELAY); }
void isl38xx_trigger_device(int asleep, void __iomem *device_base) { u32 reg; #if VERBOSE > SHOW_ERROR_MESSAGES u32 counter = 0; struct timeval current_time; DEBUG(SHOW_FUNCTION_CALLS, "isl38xx trigger device\n"); #endif if (asleep) { #if VERBOSE > SHOW_ERROR_MESSAGES do_gettimeofday(¤t_time); DEBUG(SHOW_TRACING, "%08li.%08li Device wakeup triggered\n", current_time.tv_sec, (long)current_time.tv_usec); DEBUG(SHOW_TRACING, "%08li.%08li Device register read %08x\n", current_time.tv_sec, (long)current_time.tv_usec, readl(device_base + ISL38XX_CTRL_STAT_REG)); #endif reg = readl(device_base + ISL38XX_INT_IDENT_REG); if (reg == 0xabadface) { #if VERBOSE > SHOW_ERROR_MESSAGES do_gettimeofday(¤t_time); DEBUG(SHOW_TRACING, "%08li.%08li Device register abadface\n", current_time.tv_sec, (long)current_time.tv_usec); #endif while (reg = readl(device_base + ISL38XX_CTRL_STAT_REG), (reg & ISL38XX_CTRL_STAT_SLEEPMODE) == 0) { udelay(ISL38XX_WRITEIO_DELAY); #if VERBOSE > SHOW_ERROR_MESSAGES counter++; #endif } #if VERBOSE > SHOW_ERROR_MESSAGES DEBUG(SHOW_TRACING, "%08li.%08li Device register read %08x\n", current_time.tv_sec, (long)current_time.tv_usec, readl(device_base + ISL38XX_CTRL_STAT_REG)); do_gettimeofday(¤t_time); DEBUG(SHOW_TRACING, "%08li.%08li Device asleep counter %i\n", current_time.tv_sec, (long)current_time.tv_usec, counter); #endif } isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_WAKEUP, ISL38XX_DEV_INT_REG); #if VERBOSE > SHOW_ERROR_MESSAGES udelay(ISL38XX_WRITEIO_DELAY); reg = readl(device_base + ISL38XX_CTRL_STAT_REG); do_gettimeofday(¤t_time); DEBUG(SHOW_TRACING, "%08li.%08li Device register read %08x\n", current_time.tv_sec, (long)current_time.tv_usec, reg); #endif } else { #if VERBOSE > SHOW_ERROR_MESSAGES DEBUG(SHOW_TRACING, "Device is in active state\n"); #endif isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_UPDATE, ISL38XX_DEV_INT_REG); } }
void isl38xx_disable_interrupts(void __iomem *device) { isl38xx_w32_flush(device, 0x00000000, ISL38XX_INT_EN_REG); udelay(ISL38XX_WRITEIO_DELAY); }
static int isl_upload_firmware(islpci_private *priv) { u32 reg, rc; void __iomem *device_base = priv->device_base; /* clear the RAMBoot and the Reset bit */ reg = readl(device_base + ISL38XX_CTRL_STAT_REG); reg &= ~ISL38XX_CTRL_STAT_RESET; reg &= ~ISL38XX_CTRL_STAT_RAMBOOT; writel(reg, device_base + ISL38XX_CTRL_STAT_REG); wmb(); udelay(ISL38XX_WRITEIO_DELAY); /* set the Reset bit without reading the register ! */ 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 reboot */ mdelay(50); { const struct firmware *fw_entry = NULL; long fw_len; const u32 *fw_ptr; rc = request_firmware(&fw_entry, priv->firmware, PRISM_FW_PDEV); if (rc) { printk(KERN_ERR "%s: request_firmware() failed for '%s'\n", "prism54", priv->firmware); return rc; } /* prepare the Direct Memory Base register */ reg = ISL38XX_DEV_FIRMWARE_ADDRES; fw_ptr = (u32 *) fw_entry->data; fw_len = fw_entry->size; if (fw_len % 4) { printk(KERN_ERR "%s: firmware '%s' size is not multiple of 32bit, aborting!\n", "prism54", priv->firmware); release_firmware(fw_entry); return -EILSEQ; /* Illegal byte sequence */; } while (fw_len > 0) { long _fw_len = (fw_len > ISL38XX_MEMORY_WINDOW_SIZE) ? ISL38XX_MEMORY_WINDOW_SIZE : fw_len; u32 __iomem *dev_fw_ptr = device_base + ISL38XX_DIRECT_MEM_WIN; /* set the card's base address for writing the data */ isl38xx_w32_flush(device_base, reg, ISL38XX_DIR_MEM_BASE_REG); wmb(); /* be paranoid */ /* increment the write address for next iteration */ reg += _fw_len; fw_len -= _fw_len; /* write the data to the Direct Memory Window 32bit-wise */ /* memcpy_toio() doesn't guarantee 32bit writes :-| */ while (_fw_len > 0) { /* use non-swapping writel() */ __raw_writel(*fw_ptr, dev_fw_ptr); fw_ptr++, dev_fw_ptr++; _fw_len -= 4; } /* flush PCI posting */ (void) readl(device_base + ISL38XX_PCI_POSTING_FLUSH); wmb(); /* be paranoid again */ BUG_ON(_fw_len != 0); } BUG_ON(fw_len != 0); /* Firmware version is at offset 40 (also for "newmac") */ printk(KERN_DEBUG "%s: firmware version: %.8s\n", priv->ndev->name, fw_entry->data + 40); release_firmware(fw_entry); } /* now reset the device * clear the Reset & ClkRun bit, set the RAMBoot bit */ reg = readl(device_base + ISL38XX_CTRL_STAT_REG); reg &= ~ISL38XX_CTRL_STAT_CLKRUN; reg &= ~ISL38XX_CTRL_STAT_RESET; reg |= ISL38XX_CTRL_STAT_RAMBOOT; isl38xx_w32_flush(device_base, reg, ISL38XX_CTRL_STAT_REG); wmb(); udelay(ISL38XX_WRITEIO_DELAY); /* set the reset bit latches the host override and RAMBoot bits * into the device for operation when the reset bit is reset */ reg |= ISL38XX_CTRL_STAT_RESET; writel(reg, device_base + ISL38XX_CTRL_STAT_REG); /* don't do flush PCI posting here! */ wmb(); udelay(ISL38XX_WRITEIO_DELAY); /* clear the reset bit should start the whole circus */ reg &= ~ISL38XX_CTRL_STAT_RESET; writel(reg, device_base + ISL38XX_CTRL_STAT_REG); /* don't do flush PCI posting here! */ wmb(); udelay(ISL38XX_WRITEIO_DELAY); 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; }
void isl38xx_trigger_device(int asleep, void __iomem *device_base) { u32 reg; #if VERBOSE > SHOW_ERROR_MESSAGES u32 counter = 0; struct timeval current_time; DEBUG(SHOW_FUNCTION_CALLS, "isl38xx trigger device\n"); #endif /* check whether the device is in power save mode */ if (asleep) { /* device is in powersave, trigger the device for wakeup */ #if VERBOSE > SHOW_ERROR_MESSAGES do_gettimeofday(¤t_time); DEBUG(SHOW_TRACING, "%08li.%08li Device wakeup triggered\n", current_time.tv_sec, (long)current_time.tv_usec); DEBUG(SHOW_TRACING, "%08li.%08li Device register read %08x\n", current_time.tv_sec, (long)current_time.tv_usec, readl(device_base + ISL38XX_CTRL_STAT_REG)); #endif reg = readl(device_base + ISL38XX_INT_IDENT_REG); if (reg == 0xabadface) { #if VERBOSE > SHOW_ERROR_MESSAGES do_gettimeofday(¤t_time); DEBUG(SHOW_TRACING, "%08li.%08li Device register abadface\n", current_time.tv_sec, (long)current_time.tv_usec); #endif /* read the Device Status Register until Sleepmode bit is set */ while (reg = readl(device_base + ISL38XX_CTRL_STAT_REG), (reg & ISL38XX_CTRL_STAT_SLEEPMODE) == 0) { udelay(ISL38XX_WRITEIO_DELAY); #if VERBOSE > SHOW_ERROR_MESSAGES counter++; #endif } #if VERBOSE > SHOW_ERROR_MESSAGES DEBUG(SHOW_TRACING, "%08li.%08li Device register read %08x\n", current_time.tv_sec, (long)current_time.tv_usec, readl(device_base + ISL38XX_CTRL_STAT_REG)); do_gettimeofday(¤t_time); DEBUG(SHOW_TRACING, "%08li.%08li Device asleep counter %i\n", current_time.tv_sec, (long)current_time.tv_usec, counter); #endif } /* assert the Wakeup interrupt in the Device Interrupt Register */ isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_WAKEUP, ISL38XX_DEV_INT_REG); #if VERBOSE > SHOW_ERROR_MESSAGES udelay(ISL38XX_WRITEIO_DELAY); /* perform another read on the Device Status Register */ reg = readl(device_base + ISL38XX_CTRL_STAT_REG); do_gettimeofday(¤t_time); DEBUG(SHOW_TRACING, "%08li.%08li Device register read %08x\n", current_time.tv_sec, (long)current_time.tv_usec, reg); #endif } else { /* device is (still) awake */ #if VERBOSE > SHOW_ERROR_MESSAGES DEBUG(SHOW_TRACING, "Device is in active state\n"); #endif /* trigger the device by setting the Update bit in the Device Int reg */ isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_UPDATE, ISL38XX_DEV_INT_REG); } }
int islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev) { islpci_private *priv = netdev_priv(ndev); isl38xx_control_block *cb = priv->control_block; u32 index; dma_addr_t pci_map_address; int frame_size; isl38xx_fragment *fragment; int offset; struct sk_buff *newskb; int newskb_offset; unsigned long flags; unsigned char wds_mac[6]; u32 curr_frag; int err = 0; #if VERBOSE > SHOW_ERROR_MESSAGES DEBUG(SHOW_FUNCTION_CALLS, "islpci_eth_transmit \n"); #endif /* lock the driver code */ spin_lock_irqsave(&priv->slock, flags); /* check whether the destination queue has enough fragments for the frame */ curr_frag = le32_to_cpu(cb->driver_curr_frag[ISL38XX_CB_TX_DATA_LQ]); if (unlikely(curr_frag - priv->free_data_tx >= ISL38XX_CB_TX_QSIZE)) { printk(KERN_ERR "%s: transmit device queue full when awake\n", ndev->name); netif_stop_queue(ndev); /* trigger the device */ isl38xx_w32_flush(priv->device_base, ISL38XX_DEV_INT_UPDATE, ISL38XX_DEV_INT_REG); udelay(ISL38XX_WRITEIO_DELAY); err = -EBUSY; goto drop_free; } /* Check alignment and WDS frame formatting. The start of the packet should * be aligned on a 4-byte boundary. If WDS is enabled add another 6 bytes * and add WDS address information */ if (likely(((long) skb->data & 0x03) | init_wds)) { /* get the number of bytes to add and re-allign */ offset = (4 - (long) skb->data) & 0x03; offset += init_wds ? 6 : 0; /* check whether the current skb can be used */ if (!skb_cloned(skb) && (skb_tailroom(skb) >= offset)) { unsigned char *src = skb->data; #if VERBOSE > SHOW_ERROR_MESSAGES DEBUG(SHOW_TRACING, "skb offset %i wds %i\n", offset, init_wds); #endif /* align the buffer on 4-byte boundary */ skb_reserve(skb, (4 - (long) skb->data) & 0x03); if (init_wds) { /* wds requires an additional address field of 6 bytes */ skb_put(skb, 6); #ifdef ISLPCI_ETH_DEBUG printk("islpci_eth_transmit:wds_mac\n"); #endif memmove(skb->data + 6, src, skb->len); memcpy(skb->data, wds_mac, 6); } else { memmove(skb->data, src, skb->len); } #if VERBOSE > SHOW_ERROR_MESSAGES DEBUG(SHOW_TRACING, "memmove %p %p %i \n", skb->data, src, skb->len); #endif } else { newskb = dev_alloc_skb(init_wds ? skb->len + 6 : skb->len); if (unlikely(newskb == NULL)) { printk(KERN_ERR "%s: Cannot allocate skb\n", ndev->name); err = -ENOMEM; goto drop_free; } newskb_offset = (4 - (long) newskb->data) & 0x03; /* Check if newskb->data is aligned */ if (newskb_offset) skb_reserve(newskb, newskb_offset); skb_put(newskb, init_wds ? skb->len + 6 : skb->len); if (init_wds) { memcpy(newskb->data + 6, skb->data, skb->len); memcpy(newskb->data, wds_mac, 6); #ifdef ISLPCI_ETH_DEBUG printk("islpci_eth_transmit:wds_mac\n"); #endif } else memcpy(newskb->data, skb->data, skb->len); #if VERBOSE > SHOW_ERROR_MESSAGES DEBUG(SHOW_TRACING, "memcpy %p %p %i wds %i\n", newskb->data, skb->data, skb->len, init_wds); #endif newskb->dev = skb->dev; dev_kfree_skb_irq(skb); skb = newskb; } } /* display the buffer contents for debugging */ #if VERBOSE > SHOW_ERROR_MESSAGES DEBUG(SHOW_BUFFER_CONTENTS, "\ntx %p ", skb->data); display_buffer((char *) skb->data, skb->len); #endif /* map the skb buffer to pci memory for DMA operation */ pci_map_address = pci_map_single(priv->pdev, (void *) skb->data, skb->len, PCI_DMA_TODEVICE); if (unlikely(pci_map_address == 0)) { printk(KERN_WARNING "%s: cannot map buffer to PCI\n", ndev->name); err = -EIO; goto drop_free; } /* Place the fragment in the control block structure. */ index = curr_frag % ISL38XX_CB_TX_QSIZE; fragment = &cb->tx_data_low[index]; priv->pci_map_tx_address[index] = pci_map_address; /* store the skb address for future freeing */ priv->data_low_tx[index] = skb; /* set the proper fragment start address and size information */ frame_size = skb->len; fragment->size = cpu_to_le16(frame_size); fragment->flags = cpu_to_le16(0); /* set to 1 if more fragments */ fragment->address = cpu_to_le32(pci_map_address); curr_frag++; /* The fragment address in the control block must have been * written before announcing the frame buffer to device. */ wmb(); cb->driver_curr_frag[ISL38XX_CB_TX_DATA_LQ] = cpu_to_le32(curr_frag); if (curr_frag - priv->free_data_tx + ISL38XX_MIN_QTHRESHOLD > ISL38XX_CB_TX_QSIZE) { /* stop sends from upper layers */ netif_stop_queue(ndev); /* set the full flag for the transmission queue */ priv->data_low_tx_full = 1; } /* set the transmission time */ ndev->trans_start = jiffies; priv->statistics.tx_packets++; priv->statistics.tx_bytes += skb->len; /* trigger the device */ islpci_trigger(priv); /* unlock the driver code */ spin_unlock_irqrestore(&priv->slock, flags); return 0; drop_free: priv->statistics.tx_dropped++; spin_unlock_irqrestore(&priv->slock, flags); dev_kfree_skb(skb); return err; }