static int ibmveth_open(struct net_device *netdev) { struct ibmveth_adapter *adapter = netdev_priv(netdev); u64 mac_address = 0; int rxq_entries = 1; unsigned long lpar_rc; int rc; union ibmveth_buf_desc rxq_desc; int i; struct device *dev; ibmveth_debug_printk("open starting\n"); napi_enable(&adapter->napi); for(i = 0; i<IbmVethNumBufferPools; i++) rxq_entries += adapter->rx_buff_pool[i].size; adapter->buffer_list_addr = (void*) get_zeroed_page(GFP_KERNEL); adapter->filter_list_addr = (void*) get_zeroed_page(GFP_KERNEL); if(!adapter->buffer_list_addr || !adapter->filter_list_addr) { ibmveth_error_printk("unable to allocate filter or buffer list pages\n"); ibmveth_cleanup(adapter); napi_disable(&adapter->napi); return -ENOMEM; } adapter->rx_queue.queue_len = sizeof(struct ibmveth_rx_q_entry) * rxq_entries; adapter->rx_queue.queue_addr = kmalloc(adapter->rx_queue.queue_len, GFP_KERNEL); if(!adapter->rx_queue.queue_addr) { ibmveth_error_printk("unable to allocate rx queue pages\n"); ibmveth_cleanup(adapter); napi_disable(&adapter->napi); return -ENOMEM; } dev = &adapter->vdev->dev; adapter->buffer_list_dma = dma_map_single(dev, adapter->buffer_list_addr, 4096, DMA_BIDIRECTIONAL); adapter->filter_list_dma = dma_map_single(dev, adapter->filter_list_addr, 4096, DMA_BIDIRECTIONAL); adapter->rx_queue.queue_dma = dma_map_single(dev, adapter->rx_queue.queue_addr, adapter->rx_queue.queue_len, DMA_BIDIRECTIONAL); if ((dma_mapping_error(dev, adapter->buffer_list_dma)) || (dma_mapping_error(dev, adapter->filter_list_dma)) || (dma_mapping_error(dev, adapter->rx_queue.queue_dma))) { ibmveth_error_printk("unable to map filter or buffer list pages\n"); ibmveth_cleanup(adapter); napi_disable(&adapter->napi); return -ENOMEM; } adapter->rx_queue.index = 0; adapter->rx_queue.num_slots = rxq_entries; adapter->rx_queue.toggle = 1; memcpy(&mac_address, netdev->dev_addr, netdev->addr_len); mac_address = mac_address >> 16; rxq_desc.fields.flags_len = IBMVETH_BUF_VALID | adapter->rx_queue.queue_len; rxq_desc.fields.address = adapter->rx_queue.queue_dma; ibmveth_debug_printk("buffer list @ 0x%p\n", adapter->buffer_list_addr); ibmveth_debug_printk("filter list @ 0x%p\n", adapter->filter_list_addr); ibmveth_debug_printk("receive q @ 0x%p\n", adapter->rx_queue.queue_addr); h_vio_signal(adapter->vdev->unit_address, VIO_IRQ_DISABLE); lpar_rc = ibmveth_register_logical_lan(adapter, rxq_desc, mac_address); if(lpar_rc != H_SUCCESS) { ibmveth_error_printk("h_register_logical_lan failed with %ld\n", lpar_rc); ibmveth_error_printk("buffer TCE:0x%llx filter TCE:0x%llx rxq desc:0x%llx MAC:0x%llx\n", adapter->buffer_list_dma, adapter->filter_list_dma, rxq_desc.desc, mac_address); ibmveth_cleanup(adapter); napi_disable(&adapter->napi); return -ENONET; } for(i = 0; i<IbmVethNumBufferPools; i++) { if(!adapter->rx_buff_pool[i].active) continue; if (ibmveth_alloc_buffer_pool(&adapter->rx_buff_pool[i])) { ibmveth_error_printk("unable to alloc pool\n"); adapter->rx_buff_pool[i].active = 0; ibmveth_cleanup(adapter); napi_disable(&adapter->napi); return -ENOMEM ; } } ibmveth_debug_printk("registering irq 0x%x\n", netdev->irq); if((rc = request_irq(netdev->irq, &ibmveth_interrupt, 0, netdev->name, netdev)) != 0) { ibmveth_error_printk("unable to request irq 0x%x, rc %d\n", netdev->irq, rc); do { rc = h_free_logical_lan(adapter->vdev->unit_address); } while (H_IS_LONG_BUSY(rc) || (rc == H_BUSY)); ibmveth_cleanup(adapter); napi_disable(&adapter->napi); return rc; } adapter->bounce_buffer = kmalloc(netdev->mtu + IBMVETH_BUFF_OH, GFP_KERNEL); if (!adapter->bounce_buffer) { ibmveth_error_printk("unable to allocate bounce buffer\n"); ibmveth_cleanup(adapter); napi_disable(&adapter->napi); return -ENOMEM; } adapter->bounce_buffer_dma = dma_map_single(&adapter->vdev->dev, adapter->bounce_buffer, netdev->mtu + IBMVETH_BUFF_OH, DMA_BIDIRECTIONAL); if (dma_mapping_error(dev, adapter->bounce_buffer_dma)) { ibmveth_error_printk("unable to map bounce buffer\n"); ibmveth_cleanup(adapter); napi_disable(&adapter->napi); return -ENOMEM; } ibmveth_debug_printk("initial replenish cycle\n"); ibmveth_interrupt(netdev->irq, netdev); netif_start_queue(netdev); ibmveth_debug_printk("open complete\n"); return 0; }
static ssize_t veth_pool_store(struct kobject * kobj, struct attribute * attr, const char * buf, size_t count) { struct ibmveth_buff_pool *pool = container_of(kobj, struct ibmveth_buff_pool, kobj); struct net_device *netdev = dev_get_drvdata( container_of(kobj->parent, struct device, kobj)); struct ibmveth_adapter *adapter = netdev_priv(netdev); long value = simple_strtol(buf, NULL, 10); long rc; if (attr == &veth_active_attr) { if (value && !pool->active) { if (netif_running(netdev)) { if(ibmveth_alloc_buffer_pool(pool)) { ibmveth_error_printk("unable to alloc pool\n"); return -ENOMEM; } pool->active = 1; adapter->pool_config = 1; ibmveth_close(netdev); adapter->pool_config = 0; if ((rc = ibmveth_open(netdev))) return rc; } else pool->active = 1; } else if (!value && pool->active) { int mtu = netdev->mtu + IBMVETH_BUFF_OH; int i; for (i = 0; i < IbmVethNumBufferPools; i++) { if (pool == &adapter->rx_buff_pool[i]) continue; if (!adapter->rx_buff_pool[i].active) continue; if (mtu <= adapter->rx_buff_pool[i].buff_size) break; } if (i == IbmVethNumBufferPools) { ibmveth_error_printk("no active pool >= MTU\n"); return -EPERM; } if (netif_running(netdev)) { adapter->pool_config = 1; ibmveth_close(netdev); pool->active = 0; adapter->pool_config = 0; if ((rc = ibmveth_open(netdev))) return rc; } pool->active = 0; } } else if (attr == &veth_num_attr) { if (value <= 0 || value > IBMVETH_MAX_POOL_COUNT) return -EINVAL; else { if (netif_running(netdev)) { adapter->pool_config = 1; ibmveth_close(netdev); adapter->pool_config = 0; pool->size = value; if ((rc = ibmveth_open(netdev))) return rc; } else pool->size = value; } } else if (attr == &veth_size_attr) { if (value <= IBMVETH_BUFF_OH || value > IBMVETH_MAX_BUF_SIZE) return -EINVAL; else { if (netif_running(netdev)) { adapter->pool_config = 1; ibmveth_close(netdev); adapter->pool_config = 0; pool->buff_size = value; if ((rc = ibmveth_open(netdev))) return rc; } else pool->buff_size = value; } } ibmveth_interrupt(netdev->irq, netdev); return count; }
static int ibmveth_resume(struct device *dev) { struct net_device *netdev = dev_get_drvdata(dev); ibmveth_interrupt(netdev->irq, netdev); return 0; }
static void ibmveth_poll_controller(struct net_device *dev) { ibmveth_replenish_task(netdev_priv(dev)); ibmveth_interrupt(dev->irq, dev); }
static ssize_t veth_pool_store(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count) { struct ibmveth_buff_pool *pool = container_of(kobj, struct ibmveth_buff_pool, kobj); struct net_device *netdev = dev_get_drvdata( container_of(kobj->parent, struct device, kobj)); struct ibmveth_adapter *adapter = netdev_priv(netdev); long value = simple_strtol(buf, NULL, 10); long rc; if (attr == &veth_active_attr) { if (value && !pool->active) { if (netif_running(netdev)) { if (ibmveth_alloc_buffer_pool(pool)) { netdev_err(netdev, "unable to alloc pool\n"); return -ENOMEM; } pool->active = 1; adapter->pool_config = 1; ibmveth_close(netdev); adapter->pool_config = 0; if ((rc = ibmveth_open(netdev))) return rc; } else { pool->active = 1; } } else if (!value && pool->active) { int mtu = netdev->mtu + IBMVETH_BUFF_OH; int i; /* Make sure there is a buffer pool with buffers that can hold a packet of the size of the MTU */ for (i = 0; i < IBMVETH_NUM_BUFF_POOLS; i++) { if (pool == &adapter->rx_buff_pool[i]) continue; if (!adapter->rx_buff_pool[i].active) continue; if (mtu <= adapter->rx_buff_pool[i].buff_size) break; } if (i == IBMVETH_NUM_BUFF_POOLS) { netdev_err(netdev, "no active pool >= MTU\n"); return -EPERM; } if (netif_running(netdev)) { adapter->pool_config = 1; ibmveth_close(netdev); pool->active = 0; adapter->pool_config = 0; if ((rc = ibmveth_open(netdev))) return rc; } pool->active = 0; } } else if (attr == &veth_num_attr) { if (value <= 0 || value > IBMVETH_MAX_POOL_COUNT) { return -EINVAL; } else { if (netif_running(netdev)) { adapter->pool_config = 1; ibmveth_close(netdev); adapter->pool_config = 0; pool->size = value; if ((rc = ibmveth_open(netdev))) return rc; } else { pool->size = value; } } } else if (attr == &veth_size_attr) { if (value <= IBMVETH_BUFF_OH || value > IBMVETH_MAX_BUF_SIZE) { return -EINVAL; } else { if (netif_running(netdev)) { adapter->pool_config = 1; ibmveth_close(netdev); adapter->pool_config = 0; pool->buff_size = value; if ((rc = ibmveth_open(netdev))) return rc; } else { pool->buff_size = value; } } } /* kick the interrupt handler to allocate/deallocate pools */ ibmveth_interrupt(netdev->irq, netdev); return count; }