X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fnet%2Fibmveth.c;h=99343b5836b87bfce57e48046570c61ecc4ffc0b;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=ceb98fd398afa35c4cd8a997325e197001a82b92;hpb=76828883507a47dae78837ab5dec5a5b4513c667;p=linux-2.6.git diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index ceb98fd39..99343b583 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -24,7 +24,7 @@ /* for use with IBM i/pSeries LPAR Linux. It utilizes the logical LAN */ /* option of the RS/6000 Platform Architechture to interface with virtual */ /* ethernet NICs that are presented to the partition by the hypervisor. */ -/* */ +/* */ /**************************************************************************/ /* TODO: @@ -33,7 +33,6 @@ - possibly remove procfs support */ -#include #include #include #include @@ -51,7 +50,6 @@ #include #include #include -#include #include #include #include @@ -61,7 +59,7 @@ #undef DEBUG #define ibmveth_printk(fmt, args...) \ - printk(KERN_INFO "%s: " fmt, __FILE__, ## args) + printk(KERN_DEBUG "%s: " fmt, __FILE__, ## args) #define ibmveth_error_printk(fmt, args...) \ printk(KERN_ERR "(%s:%3.3d ua:%x) ERROR: " fmt, __FILE__, __LINE__ , adapter->vdev->unit_address, ## args) @@ -79,7 +77,7 @@ #else #define ibmveth_debug_printk_no_adapter(fmt, args...) #define ibmveth_debug_printk(fmt, args...) -#define ibmveth_assert(expr) +#define ibmveth_assert(expr) #endif static int ibmveth_open(struct net_device *dev); @@ -94,8 +92,9 @@ static void ibmveth_proc_register_driver(void); static void ibmveth_proc_unregister_driver(void); static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter); static void ibmveth_proc_unregister_adapter(struct ibmveth_adapter *adapter); -static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance, struct pt_regs *regs); +static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance); static inline void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter); +static struct kobj_type ktype_veth_pool; #ifdef CONFIG_PROC_FS #define IBMVETH_PROC_DIR "net/ibmveth" @@ -133,12 +132,13 @@ static inline int ibmveth_rxq_frame_length(struct ibmveth_adapter *adapter) } /* setup the initial settings for a buffer pool */ -static void ibmveth_init_buffer_pool(struct ibmveth_buff_pool *pool, u32 pool_index, u32 pool_size, u32 buff_size) +static void ibmveth_init_buffer_pool(struct ibmveth_buff_pool *pool, u32 pool_index, u32 pool_size, u32 buff_size, u32 pool_active) { pool->size = pool_size; pool->index = pool_index; pool->buff_size = buff_size; pool->threshold = pool_size / 2; + pool->active = pool_active; } /* allocate and setup an buffer pool - called during open */ @@ -146,13 +146,13 @@ static int ibmveth_alloc_buffer_pool(struct ibmveth_buff_pool *pool) { int i; - pool->free_map = kmalloc(sizeof(u16) * pool->size, GFP_KERNEL); + pool->free_map = kmalloc(sizeof(u16) * pool->size, GFP_KERNEL); if(!pool->free_map) { return -1; } - pool->dma_addr = kmalloc(sizeof(dma_addr_t) * pool->size, GFP_KERNEL); + pool->dma_addr = kmalloc(sizeof(dma_addr_t) * pool->size, GFP_KERNEL); if(!pool->dma_addr) { kfree(pool->free_map); pool->free_map = NULL; @@ -180,7 +180,6 @@ static int ibmveth_alloc_buffer_pool(struct ibmveth_buff_pool *pool) atomic_set(&pool->available, 0); pool->producer_index = 0; pool->consumer_index = 0; - pool->active = 0; return 0; } @@ -212,9 +211,10 @@ static void ibmveth_replenish_buffer_pool(struct ibmveth_adapter *adapter, struc break; } - free_index = pool->consumer_index++ % pool->size; + free_index = pool->consumer_index; + pool->consumer_index = (pool->consumer_index + 1) % pool->size; index = pool->free_map[free_index]; - + ibmveth_assert(index != IBM_VETH_INVALID_MAP); ibmveth_assert(pool->skbuff[index] == NULL); @@ -231,14 +231,17 @@ static void ibmveth_replenish_buffer_pool(struct ibmveth_adapter *adapter, struc desc.desc = 0; desc.fields.valid = 1; desc.fields.length = pool->buff_size; - desc.fields.address = dma_addr; + desc.fields.address = dma_addr; lpar_rc = h_add_logical_lan_buffer(adapter->vdev->unit_address, desc.desc); - - if(lpar_rc != H_Success) { + + if(lpar_rc != H_SUCCESS) { pool->free_map[free_index] = index; pool->skbuff[index] = NULL; - pool->consumer_index--; + if (pool->consumer_index == 0) + pool->consumer_index = pool->size - 1; + else + pool->consumer_index--; dma_unmap_single(&adapter->vdev->dev, pool->dma_addr[index], pool->buff_size, DMA_FROM_DEVICE); @@ -250,13 +253,13 @@ static void ibmveth_replenish_buffer_pool(struct ibmveth_adapter *adapter, struc adapter->replenish_add_buff_success++; } } - + mb(); atomic_add(buffers_added, &(pool->available)); } /* replenish routine */ -static void ibmveth_replenish_task(struct ibmveth_adapter *adapter) +static void ibmveth_replenish_task(struct ibmveth_adapter *adapter) { int i; @@ -264,7 +267,7 @@ static void ibmveth_replenish_task(struct ibmveth_adapter *adapter) for(i = 0; i < IbmVethNumBufferPools; i++) if(adapter->rx_buff_pool[i].active) - ibmveth_replenish_buffer_pool(adapter, + ibmveth_replenish_buffer_pool(adapter, &adapter->rx_buff_pool[i]); adapter->rx_no_buffer = *(u64*)(((char*)adapter->buffer_list_addr) + 4096 - 8); @@ -301,7 +304,6 @@ static void ibmveth_free_buffer_pool(struct ibmveth_adapter *adapter, struct ibm kfree(pool->skbuff); pool->skbuff = NULL; } - pool->active = 0; } /* remove a buffer from a pool */ @@ -326,7 +328,10 @@ static void ibmveth_remove_buffer_from_pool(struct ibmveth_adapter *adapter, u64 adapter->rx_buff_pool[pool].buff_size, DMA_FROM_DEVICE); - free_index = adapter->rx_buff_pool[pool].producer_index++ % adapter->rx_buff_pool[pool].size; + free_index = adapter->rx_buff_pool[pool].producer_index; + adapter->rx_buff_pool[pool].producer_index + = (adapter->rx_buff_pool[pool].producer_index + 1) + % adapter->rx_buff_pool[pool].size; adapter->rx_buff_pool[pool].free_map[free_index] = index; mb(); @@ -372,8 +377,8 @@ static void ibmveth_rxq_recycle_buffer(struct ibmveth_adapter *adapter) desc.fields.address = adapter->rx_buff_pool[pool].dma_addr[index]; lpar_rc = h_add_logical_lan_buffer(adapter->vdev->unit_address, desc.desc); - - if(lpar_rc != H_Success) { + + if(lpar_rc != H_SUCCESS) { ibmveth_debug_printk("h_add_logical_lan_buffer failed during recycle rc=%ld", lpar_rc); ibmveth_remove_buffer_from_pool(adapter, adapter->rx_queue.queue_addr[adapter->rx_queue.index].correlator); } @@ -407,7 +412,7 @@ static void ibmveth_cleanup(struct ibmveth_adapter *adapter) } free_page((unsigned long)adapter->buffer_list_addr); adapter->buffer_list_addr = NULL; - } + } if(adapter->filter_list_addr != NULL) { if(!dma_mapping_error(adapter->filter_list_dma)) { @@ -433,7 +438,34 @@ static void ibmveth_cleanup(struct ibmveth_adapter *adapter) } for(i = 0; irx_buff_pool[i]); + if (adapter->rx_buff_pool[i].active) + ibmveth_free_buffer_pool(adapter, + &adapter->rx_buff_pool[i]); +} + +static int ibmveth_register_logical_lan(struct ibmveth_adapter *adapter, + union ibmveth_buf_desc rxq_desc, u64 mac_address) +{ + int rc, try_again = 1; + + /* After a kexec the adapter will still be open, so our attempt to + * open it will fail. So if we get a failure we free the adapter and + * try again, but only once. */ +retry: + rc = h_register_logical_lan(adapter->vdev->unit_address, + adapter->buffer_list_dma, rxq_desc.desc, + adapter->filter_list_dma, mac_address); + + if (rc != H_SUCCESS && try_again) { + do { + rc = h_free_logical_lan(adapter->vdev->unit_address); + } while (H_IS_LONG_BUSY(rc) || (rc == H_BUSY)); + + try_again = 0; + goto retry; + } + + return rc; } static int ibmveth_open(struct net_device *netdev) @@ -450,10 +482,10 @@ static int ibmveth_open(struct net_device *netdev) for(i = 0; irx_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); @@ -489,9 +521,6 @@ static int ibmveth_open(struct net_device *netdev) adapter->rx_queue.num_slots = rxq_entries; adapter->rx_queue.toggle = 1; - /* call change_mtu to init the buffer pools based in initial mtu */ - ibmveth_change_mtu(netdev, netdev->mtu); - memcpy(&mac_address, netdev->dev_addr, netdev->addr_len); mac_address = mac_address >> 16; @@ -504,14 +533,11 @@ static int ibmveth_open(struct net_device *netdev) 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); - - lpar_rc = h_register_logical_lan(adapter->vdev->unit_address, - adapter->buffer_list_dma, - rxq_desc.desc, - adapter->filter_list_dma, - mac_address); + h_vio_signal(adapter->vdev->unit_address, VIO_IRQ_DISABLE); - if(lpar_rc != H_Success) { + 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%lx filter TCE:0x%lx rxq desc:0x%lx MAC:0x%lx\n", adapter->buffer_list_dma, @@ -519,7 +545,18 @@ static int ibmveth_open(struct net_device *netdev) rxq_desc.desc, mac_address); ibmveth_cleanup(adapter); - return -ENONET; + return -ENONET; + } + + for(i = 0; irx_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); + return -ENOMEM ; + } } ibmveth_debug_printk("registering irq 0x%x\n", netdev->irq); @@ -527,14 +564,14 @@ static int ibmveth_open(struct net_device *netdev) 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_isLongBusy(rc) || (rc == H_Busy)); + } while (H_IS_LONG_BUSY(rc) || (rc == H_BUSY)); ibmveth_cleanup(adapter); return rc; } ibmveth_debug_printk("initial replenish cycle\n"); - ibmveth_interrupt(netdev->irq, netdev, NULL); + ibmveth_interrupt(netdev->irq, netdev); netif_start_queue(netdev); @@ -547,18 +584,19 @@ static int ibmveth_close(struct net_device *netdev) { struct ibmveth_adapter *adapter = netdev->priv; long lpar_rc; - + ibmveth_debug_printk("close starting\n"); - netif_stop_queue(netdev); + if (!adapter->pool_config) + netif_stop_queue(netdev); free_irq(netdev->irq, netdev); do { lpar_rc = h_free_logical_lan(adapter->vdev->unit_address); - } while (H_isLongBusy(lpar_rc) || (lpar_rc == H_Busy)); + } while (H_IS_LONG_BUSY(lpar_rc) || (lpar_rc == H_BUSY)); - if(lpar_rc != H_Success) + if(lpar_rc != H_SUCCESS) { ibmveth_error_printk("h_free_logical_lan failed with %lx, continuing with close\n", lpar_rc); @@ -596,7 +634,7 @@ static u32 netdev_get_link(struct net_device *dev) { return 1; } -static struct ethtool_ops netdev_ethtool_ops = { +static const struct ethtool_ops netdev_ethtool_ops = { .get_drvinfo = netdev_get_drvinfo, .get_settings = netdev_get_settings, .get_link = netdev_get_link, @@ -692,10 +730,11 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) desc[3].desc, desc[4].desc, desc[5].desc, - correlator); - } while ((lpar_rc == H_Busy) && (retry_count--)); - - if(lpar_rc != H_Success && lpar_rc != H_Dropped) { + correlator, + &correlator); + } while ((lpar_rc == H_BUSY) && (retry_count--)); + + if(lpar_rc != H_SUCCESS && lpar_rc != H_DROPPED) { int i; ibmveth_error_printk("tx: h_send_logical_lan failed with rc=%ld\n", lpar_rc); for(i = 0; i < 6; i++) { @@ -780,20 +819,20 @@ static int ibmveth_poll(struct net_device *netdev, int *budget) /* more work to do - return that we are not done yet */ netdev->quota -= frames_processed; *budget -= frames_processed; - return 1; + return 1; } /* we think we are done - reenable interrupts, then check once more to make sure we are done */ lpar_rc = h_vio_signal(adapter->vdev->unit_address, VIO_IRQ_ENABLE); - ibmveth_assert(lpar_rc == H_Success); + ibmveth_assert(lpar_rc == H_SUCCESS); netif_rx_complete(netdev); if(ibmveth_rxq_pending_buffer(adapter) && netif_rx_reschedule(netdev, frames_processed)) { lpar_rc = h_vio_signal(adapter->vdev->unit_address, VIO_IRQ_DISABLE); - ibmveth_assert(lpar_rc == H_Success); + ibmveth_assert(lpar_rc == H_SUCCESS); more_work = 1; goto restart_poll; } @@ -805,15 +844,15 @@ static int ibmveth_poll(struct net_device *netdev, int *budget) return 0; } -static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance, struct pt_regs *regs) -{ +static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance) +{ struct net_device *netdev = dev_instance; struct ibmveth_adapter *adapter = netdev->priv; unsigned long lpar_rc; if(netif_rx_schedule_prep(netdev)) { lpar_rc = h_vio_signal(adapter->vdev->unit_address, VIO_IRQ_DISABLE); - ibmveth_assert(lpar_rc == H_Success); + ibmveth_assert(lpar_rc == H_SUCCESS); __netif_rx_schedule(netdev); } return IRQ_HANDLED; @@ -835,7 +874,7 @@ static void ibmveth_set_multicast_list(struct net_device *netdev) IbmVethMcastEnableRecv | IbmVethMcastDisableFiltering, 0); - if(lpar_rc != H_Success) { + if(lpar_rc != H_SUCCESS) { ibmveth_error_printk("h_multicast_ctrl rc=%ld when entering promisc mode\n", lpar_rc); } } else { @@ -847,7 +886,7 @@ static void ibmveth_set_multicast_list(struct net_device *netdev) IbmVethMcastDisableFiltering | IbmVethMcastClearFilterTable, 0); - if(lpar_rc != H_Success) { + if(lpar_rc != H_SUCCESS) { ibmveth_error_printk("h_multicast_ctrl rc=%ld when attempting to clear filter table\n", lpar_rc); } /* add the addresses to the filter table */ @@ -858,16 +897,16 @@ static void ibmveth_set_multicast_list(struct net_device *netdev) lpar_rc = h_multicast_ctrl(adapter->vdev->unit_address, IbmVethMcastAddFilter, mcast_addr); - if(lpar_rc != H_Success) { + if(lpar_rc != H_SUCCESS) { ibmveth_error_printk("h_multicast_ctrl rc=%ld when adding an entry to the filter table\n", lpar_rc); } } - + /* re-enable filtering */ lpar_rc = h_multicast_ctrl(adapter->vdev->unit_address, IbmVethMcastEnableFiltering, 0); - if(lpar_rc != H_Success) { + if(lpar_rc != H_SUCCESS) { ibmveth_error_printk("h_multicast_ctrl rc=%ld when enabling filtering\n", lpar_rc); } } @@ -876,47 +915,31 @@ static void ibmveth_set_multicast_list(struct net_device *netdev) static int ibmveth_change_mtu(struct net_device *dev, int new_mtu) { struct ibmveth_adapter *adapter = dev->priv; + int new_mtu_oh = new_mtu + IBMVETH_BUFF_OH; int i; - int prev_smaller = 1; - if ((new_mtu < 68) || - (new_mtu > (pool_size[IbmVethNumBufferPools-1]) - IBMVETH_BUFF_OH)) + if (new_mtu < IBMVETH_MAX_MTU) return -EINVAL; + /* Look for an active buffer pool that can hold the new MTU */ for(i = 0; i (pool_size[i] - IBMVETH_BUFF_OH)) { - activate = 1; - prev_smaller= 1; - } else { - if (prev_smaller) - activate = 1; - prev_smaller= 0; + if (!adapter->rx_buff_pool[i].active) + continue; + if (new_mtu_oh < adapter->rx_buff_pool[i].buff_size) { + dev->mtu = new_mtu; + return 0; } - - if (activate && !adapter->rx_buff_pool[i].active) { - struct ibmveth_buff_pool *pool = - &adapter->rx_buff_pool[i]; - if(ibmveth_alloc_buffer_pool(pool)) { - ibmveth_error_printk("unable to alloc pool\n"); - return -ENOMEM; - } - adapter->rx_buff_pool[i].active = 1; - } else if (!activate && adapter->rx_buff_pool[i].active) { - adapter->rx_buff_pool[i].active = 0; - h_free_logical_lan_buffer(adapter->vdev->unit_address, - (u64)pool_size[i]); - } - } + return -EINVAL; +} - /* kick the interrupt handler so that the new buffer pools get - replenished or deallocated */ - ibmveth_interrupt(dev->irq, dev, NULL); - - dev->mtu = new_mtu; - return 0; +#ifdef CONFIG_NET_POLL_CONTROLLER +static void ibmveth_poll_controller(struct net_device *dev) +{ + ibmveth_replenish_task(dev->priv); + ibmveth_interrupt(dev->irq, dev); } +#endif static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id) { @@ -928,7 +951,7 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ unsigned int *mcastFilterSize_p; - ibmveth_debug_printk_no_adapter("entering ibmveth_probe for UA 0x%x\n", + ibmveth_debug_printk_no_adapter("entering ibmveth_probe for UA 0x%x\n", dev->unit_address); mac_addr_p = (unsigned char *) vio_get_attribute(dev, VETH_MAC_ADDR, 0); @@ -937,7 +960,7 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ "attribute\n", __FILE__, __LINE__); return 0; } - + mcastFilterSize_p= (unsigned int *) vio_get_attribute(dev, VETH_MCAST_FILTER_SIZE, 0); if(!mcastFilterSize_p) { printk(KERN_ERR "(%s:%3.3d) ERROR: Can't find " @@ -945,7 +968,7 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ __FILE__, __LINE__); return 0; } - + netdev = alloc_etherdev(sizeof(struct ibmveth_adapter)); if(!netdev) @@ -960,13 +983,14 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ adapter->vdev = dev; adapter->netdev = netdev; adapter->mcastFilterSize= *mcastFilterSize_p; - + adapter->pool_config = 0; + /* Some older boxes running PHYP non-natively have an OF that - returns a 8-byte local-mac-address field (and the first + returns a 8-byte local-mac-address field (and the first 2 bytes have to be ignored) while newer boxes' OF return - a 6-byte field. Note that IEEE 1275 specifies that + a 6-byte field. Note that IEEE 1275 specifies that local-mac-address must be a 6-byte field. - The RPA doc specifies that the first byte must be 10b, so + The RPA doc specifies that the first byte must be 10b, so we'll just look for it to solve this 8 vs. 6 byte field issue */ if ((*mac_addr_p & 0x3) != 0x02) @@ -975,8 +999,6 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ adapter->mac_addr = 0; memcpy(&adapter->mac_addr, mac_addr_p, 6); - adapter->liobn = dev->iommu_table->it_index; - netdev->irq = dev->irq; netdev->open = ibmveth_open; netdev->poll = ibmveth_poll; @@ -989,14 +1011,24 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ netdev->ethtool_ops = &netdev_ethtool_ops; netdev->change_mtu = ibmveth_change_mtu; SET_NETDEV_DEV(netdev, &dev->dev); - netdev->features |= NETIF_F_LLTX; +#ifdef CONFIG_NET_POLL_CONTROLLER + netdev->poll_controller = ibmveth_poll_controller; +#endif + netdev->features |= NETIF_F_LLTX; spin_lock_init(&adapter->stats_lock); memcpy(&netdev->dev_addr, &adapter->mac_addr, netdev->addr_len); - for(i = 0; irx_buff_pool[i], i, - pool_count[i], pool_size[i]); + for(i = 0; irx_buff_pool[i].kobj; + ibmveth_init_buffer_pool(&adapter->rx_buff_pool[i], i, + pool_count[i], pool_size[i], + pool_active[i]); + kobj->parent = &dev->dev.kobj; + sprintf(kobj->name, "pool%d", i); + kobj->ktype = &ktype_veth_pool; + kobject_register(kobj); + } ibmveth_debug_printk("adapter @ 0x%p\n", adapter); @@ -1025,6 +1057,10 @@ static int __devexit ibmveth_remove(struct vio_dev *dev) { struct net_device *netdev = dev->dev.driver_data; struct ibmveth_adapter *adapter = netdev->priv; + int i; + + for(i = 0; irx_buff_pool[i].kobj); unregister_netdev(netdev); @@ -1048,7 +1084,7 @@ static void ibmveth_proc_unregister_driver(void) remove_proc_entry(IBMVETH_PROC_DIR, NULL); } -static void *ibmveth_seq_start(struct seq_file *seq, loff_t *pos) +static void *ibmveth_seq_start(struct seq_file *seq, loff_t *pos) { if (*pos == 0) { return (void *)1; @@ -1063,27 +1099,26 @@ static void *ibmveth_seq_next(struct seq_file *seq, void *v, loff_t *pos) return NULL; } -static void ibmveth_seq_stop(struct seq_file *seq, void *v) +static void ibmveth_seq_stop(struct seq_file *seq, void *v) { } -static int ibmveth_seq_show(struct seq_file *seq, void *v) +static int ibmveth_seq_show(struct seq_file *seq, void *v) { struct ibmveth_adapter *adapter = seq->private; char *current_mac = ((char*) &adapter->netdev->dev_addr); char *firmware_mac = ((char*) &adapter->mac_addr) ; seq_printf(seq, "%s %s\n\n", ibmveth_driver_string, ibmveth_driver_version); - + seq_printf(seq, "Unit Address: 0x%x\n", adapter->vdev->unit_address); - seq_printf(seq, "LIOBN: 0x%lx\n", adapter->liobn); seq_printf(seq, "Current MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", current_mac[0], current_mac[1], current_mac[2], current_mac[3], current_mac[4], current_mac[5]); seq_printf(seq, "Firmware MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", firmware_mac[0], firmware_mac[1], firmware_mac[2], firmware_mac[3], firmware_mac[4], firmware_mac[5]); - + seq_printf(seq, "\nAdapter Statistics:\n"); seq_printf(seq, " TX: skbuffs linearized: %ld\n", adapter->tx_linearized); seq_printf(seq, " multi-descriptor sends: %ld\n", adapter->tx_multidesc_send); @@ -1095,7 +1130,7 @@ static int ibmveth_seq_show(struct seq_file *seq, void *v) seq_printf(seq, " add buffer failures: %ld\n", adapter->replenish_add_buff_failure); seq_printf(seq, " invalid buffers: %ld\n", adapter->rx_invalid_buffer); seq_printf(seq, " no buffers: %ld\n", adapter->rx_no_buffer); - + return 0; } static struct seq_operations ibmveth_seq_ops = { @@ -1133,7 +1168,9 @@ static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter) { struct proc_dir_entry *entry; if (ibmveth_proc_dir) { - entry = create_proc_entry(adapter->netdev->name, S_IFREG, ibmveth_proc_dir); + char u_addr[10]; + sprintf(u_addr, "%x", adapter->vdev->unit_address); + entry = create_proc_entry(u_addr, S_IFREG, ibmveth_proc_dir); if (!entry) { ibmveth_error_printk("Cannot create adapter proc entry"); } else { @@ -1148,16 +1185,18 @@ static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter) static void ibmveth_proc_unregister_adapter(struct ibmveth_adapter *adapter) { if (ibmveth_proc_dir) { - remove_proc_entry(adapter->netdev->name, ibmveth_proc_dir); + char u_addr[10]; + sprintf(u_addr, "%x", adapter->vdev->unit_address); + remove_proc_entry(u_addr, ibmveth_proc_dir); } } #else /* CONFIG_PROC_FS */ -static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter) +static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter) { } -static void ibmveth_proc_unregister_adapter(struct ibmveth_adapter *adapter) +static void ibmveth_proc_unregister_adapter(struct ibmveth_adapter *adapter) { } static void ibmveth_proc_register_driver(void) @@ -1169,6 +1208,132 @@ static void ibmveth_proc_unregister_driver(void) } #endif /* CONFIG_PROC_FS */ +static struct attribute veth_active_attr; +static struct attribute veth_num_attr; +static struct attribute veth_size_attr; + +static ssize_t veth_pool_show(struct kobject * kobj, + struct attribute * attr, char * buf) +{ + struct ibmveth_buff_pool *pool = container_of(kobj, + struct ibmveth_buff_pool, + kobj); + + if (attr == &veth_active_attr) + return sprintf(buf, "%d\n", pool->active); + else if (attr == &veth_num_attr) + return sprintf(buf, "%d\n", pool->size); + else if (attr == &veth_size_attr) + return sprintf(buf, "%d\n", pool->buff_size); + 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 = + container_of(kobj->parent, struct device, kobj)->driver_data; + struct ibmveth_adapter *adapter = netdev->priv; + long value = simple_strtol(buf, NULL, 10); + long rc; + + if (attr == &veth_active_attr) { + if (value && !pool->active) { + 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 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; irx_buff_pool[i]) + continue; + if (!adapter->rx_buff_pool[i].active) + continue; + if (mtu < adapter->rx_buff_pool[i].buff_size) { + pool->active = 0; + h_free_logical_lan_buffer(adapter-> + vdev-> + unit_address, + pool-> + buff_size); + } + } + if (pool->active) { + ibmveth_error_printk("no active pool >= MTU\n"); + return -EPERM; + } + } + } else if (attr == &veth_num_attr) { + if (value <= 0 || value > IBMVETH_MAX_POOL_COUNT) + return -EINVAL; + else { + adapter->pool_config = 1; + ibmveth_close(netdev); + adapter->pool_config = 0; + pool->size = value; + if ((rc = ibmveth_open(netdev))) + return rc; + } + } else if (attr == &veth_size_attr) { + if (value <= IBMVETH_BUFF_OH || value > IBMVETH_MAX_BUF_SIZE) + return -EINVAL; + else { + adapter->pool_config = 1; + ibmveth_close(netdev); + adapter->pool_config = 0; + pool->buff_size = value; + if ((rc = ibmveth_open(netdev))) + return rc; + } + } + + /* kick the interrupt handler to allocate/deallocate pools */ + ibmveth_interrupt(netdev->irq, netdev); + return count; +} + + +#define ATTR(_name, _mode) \ + struct attribute veth_##_name##_attr = { \ + .name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE \ + }; + +static ATTR(active, 0644); +static ATTR(num, 0644); +static ATTR(size, 0644); + +static struct attribute * veth_pool_attrs[] = { + &veth_active_attr, + &veth_num_attr, + &veth_size_attr, + NULL, +}; + +static struct sysfs_ops veth_pool_ops = { + .show = veth_pool_show, + .store = veth_pool_store, +}; + +static struct kobj_type ktype_veth_pool = { + .release = NULL, + .sysfs_ops = &veth_pool_ops, + .default_attrs = veth_pool_attrs, +}; + + static struct vio_device_id ibmveth_device_table[] __devinitdata= { { "network", "IBM,l-lan"}, { "", "" } @@ -1198,7 +1363,7 @@ static void __exit ibmveth_module_exit(void) { vio_unregister_driver(&ibmveth_driver); ibmveth_proc_unregister_driver(); -} +} module_init(ibmveth_module_init); module_exit(ibmveth_module_exit);