From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from e36.co.us.ibm.com (e36.co.us.ibm.com [32.97.110.154]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client CN "e36.co.us.ibm.com", Issuer "Equifax" (verified OK)) by ozlabs.org (Postfix) with ESMTPS id A5608DF971 for ; Fri, 13 Jun 2008 08:24:46 +1000 (EST) Received: from d03relay02.boulder.ibm.com (d03relay02.boulder.ibm.com [9.17.195.227]) by e36.co.us.ibm.com (8.13.8/8.13.8) with ESMTP id m5CMOgjQ009053 for ; Thu, 12 Jun 2008 18:24:42 -0400 Received: from d03av02.boulder.ibm.com (d03av02.boulder.ibm.com [9.17.195.168]) by d03relay02.boulder.ibm.com (8.13.8/8.13.8/NCO v9.0) with ESMTP id m5CMOgVb176454 for ; Thu, 12 Jun 2008 16:24:42 -0600 Received: from d03av02.boulder.ibm.com (loopback [127.0.0.1]) by d03av02.boulder.ibm.com (8.12.11.20060308/8.13.3) with ESMTP id m5CMOfTf022508 for ; Thu, 12 Jun 2008 16:24:42 -0600 Date: Thu, 12 Jun 2008 17:23:11 -0500 From: Robert Jennings To: paulus@samba.org Subject: [PATCH 17/19] ibmveth: enable driver for CMO Message-ID: <20080612222311.GY30916@linux.vnet.ibm.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii In-Reply-To: <20080612215312.GF30916@linux.vnet.ibm.com> Cc: netdev@vger.kernel.org, linuxppc-dev@ozlabs.org, David Darrington , Brian King List-Id: Linux on PowerPC Developers Mail List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , =46rom: Robert Jennings Enable ibmveth for Cooperative Memory Overcommitment (CMO). For this driver it means calculating a desired amount of IO memory based on the current MTU and updating this value with the bus when MTU changes occur. Because DMA mappings can fail, we have added a bounce buffer for temporary cases where the driver can not map IO memory for the buffer pool. The following changes are made to enable the driver for CMO: * DMA mapping errors will not result in error messages if entitlement has been exceeded and resources were not available. * DMA mapping errors are handled gracefully, ibmveth_replenish_buffer_pool= () is corrected to check the return from dma_map_single and fail gracefully. * The driver will have a get_io_entitlement function defined to function in a CMO environment. * When the MTU is changed, the driver will update the device IO entitlement Signed-off-by: Robert Jennings Signed-off-by: Brian King Signed-off-by: Santiago Leon --- drivers/net/ibmveth.c | 169 ++++++++++++++++++++++++++++++++++++++++-----= ----- drivers/net/ibmveth.h | 5 + 2 files changed, 140 insertions(+), 34 deletions(-) Index: b/drivers/net/ibmveth.c =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -33,6 +33,7 @@ */ =20 #include +#include #include #include #include @@ -52,7 +53,9 @@ #include #include #include +#include #include +#include #include =20 #include "ibmveth.h" @@ -94,8 +97,10 @@ static void ibmveth_proc_register_adapte static void ibmveth_proc_unregister_adapter(struct ibmveth_adapter *adapte= r); static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance); static void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter); +static unsigned long ibmveth_get_io_entitlement(struct vio_dev *vdev); static struct kobj_type ktype_veth_pool; =20 + #ifdef CONFIG_PROC_FS #define IBMVETH_PROC_DIR "ibmveth" static struct proc_dir_entry *ibmveth_proc_dir; @@ -226,16 +231,16 @@ static void ibmveth_replenish_buffer_poo u32 i; u32 count =3D pool->size - atomic_read(&pool->available); u32 buffers_added =3D 0; + struct sk_buff *skb; + unsigned int free_index, index; + u64 correlator; + unsigned long lpar_rc; + dma_addr_t dma_addr; =20 mb(); =20 for(i =3D 0; i < count; ++i) { - struct sk_buff *skb; - unsigned int free_index, index; - u64 correlator; union ibmveth_buf_desc desc; - unsigned long lpar_rc; - dma_addr_t dma_addr; =20 skb =3D alloc_skb(pool->buff_size, GFP_ATOMIC); =20 @@ -255,6 +260,9 @@ static void ibmveth_replenish_buffer_poo dma_addr =3D dma_map_single(&adapter->vdev->dev, skb->data, pool->buff_size, DMA_FROM_DEVICE); =20 + if (dma_mapping_error(dma_addr)) + goto failure; + pool->free_map[free_index] =3D IBM_VETH_INVALID_MAP; pool->dma_addr[index] =3D dma_addr; pool->skbuff[index] =3D skb; @@ -267,20 +275,9 @@ static void ibmveth_replenish_buffer_poo =20 lpar_rc =3D h_add_logical_lan_buffer(adapter->vdev->unit_address, desc.d= esc); =20 - if(lpar_rc !=3D H_SUCCESS) { - pool->free_map[free_index] =3D index; - pool->skbuff[index] =3D NULL; - if (pool->consumer_index =3D=3D 0) - pool->consumer_index =3D pool->size - 1; - else - pool->consumer_index--; - dma_unmap_single(&adapter->vdev->dev, - pool->dma_addr[index], pool->buff_size, - DMA_FROM_DEVICE); - dev_kfree_skb_any(skb); - adapter->replenish_add_buff_failure++; - break; - } else { + if (lpar_rc !=3D H_SUCCESS) + goto failure; + else { buffers_added++; adapter->replenish_add_buff_success++; } @@ -288,6 +285,24 @@ static void ibmveth_replenish_buffer_poo =20 mb(); atomic_add(buffers_added, &(pool->available)); + return; + +failure: + pool->free_map[free_index] =3D index; + pool->skbuff[index] =3D NULL; + if (pool->consumer_index =3D=3D 0) + pool->consumer_index =3D pool->size - 1; + else + pool->consumer_index--; + if (!dma_mapping_error(dma_addr)) + dma_unmap_single(&adapter->vdev->dev, + pool->dma_addr[index], pool->buff_size, + DMA_FROM_DEVICE); + dev_kfree_skb_any(skb); + adapter->replenish_add_buff_failure++; + + mb(); + atomic_add(buffers_added, &(pool->available)); } =20 /* replenish routine */ @@ -297,7 +312,7 @@ static void ibmveth_replenish_task(struc =20 adapter->replenish_task_cycles++; =20 - for(i =3D 0; i < IbmVethNumBufferPools; i++) + for (i =3D (IbmVethNumBufferPools - 1); i >=3D 0; i--) if(adapter->rx_buff_pool[i].active) ibmveth_replenish_buffer_pool(adapter, &adapter->rx_buff_pool[i]); @@ -472,6 +487,18 @@ static void ibmveth_cleanup(struct ibmve if (adapter->rx_buff_pool[i].active) ibmveth_free_buffer_pool(adapter, &adapter->rx_buff_pool[i]); + + if(adapter->bounce_buffer !=3D NULL) { + if(!dma_mapping_error(adapter->bounce_buffer_dma)) { + dma_unmap_single(&adapter->vdev->dev, + adapter->bounce_buffer_dma, + adapter->netdev->mtu + IBMVETH_BUFF_OH, + DMA_BIDIRECTIONAL); + adapter->bounce_buffer_dma =3D DMA_ERROR_CODE; + } + kfree(adapter->bounce_buffer); + adapter->bounce_buffer =3D NULL; + } } =20 static int ibmveth_register_logical_lan(struct ibmveth_adapter *adapter, @@ -607,6 +634,24 @@ static int ibmveth_open(struct net_devic return rc; } =20 + adapter->bounce_buffer =3D + 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 =3D + dma_map_single(&adapter->vdev->dev, adapter->bounce_buffer, + netdev->mtu + IBMVETH_BUFF_OH, DMA_BIDIRECTIONAL); + if(dma_mapping_error(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); =20 @@ -853,10 +898,12 @@ static int ibmveth_start_xmit(struct sk_ unsigned int tx_packets =3D 0; unsigned int tx_send_failed =3D 0; unsigned int tx_map_failed =3D 0; + int used_bounce =3D 0; + unsigned long data_dma_addr; =20 desc.fields.flags_len =3D IBMVETH_BUF_VALID | skb->len; - desc.fields.address =3D dma_map_single(&adapter->vdev->dev, skb->data, - skb->len, DMA_TO_DEVICE); + data_dma_addr =3D dma_map_single(&adapter->vdev->dev, skb->data, + skb->len, DMA_TO_DEVICE); =20 if (skb->ip_summed =3D=3D CHECKSUM_PARTIAL && ip_hdr(skb)->protocol !=3D IPPROTO_TCP && skb_checksum_help(skb)) { @@ -875,12 +922,16 @@ static int ibmveth_start_xmit(struct sk_ buf[1] =3D 0; } =20 - if (dma_mapping_error(desc.fields.address)) { - ibmveth_error_printk("tx: unable to map xmit buffer\n"); + if (dma_mapping_error(data_dma_addr)) { + if (!firmware_has_feature(FW_FEATURE_CMO)) + ibmveth_error_printk("tx: unable to map xmit buffer\n"); + skb_copy_from_linear_data(skb, adapter->bounce_buffer, + skb->len); + desc.fields.address =3D adapter->bounce_buffer_dma; tx_map_failed++; - tx_dropped++; - goto out; - } + used_bounce =3D 1; + } else + desc.fields.address =3D data_dma_addr; =20 /* send the frame. Arbitrarily set retrycount to 1024 */ correlator =3D 0; @@ -904,8 +955,9 @@ static int ibmveth_start_xmit(struct sk_ netdev->trans_start =3D jiffies; } =20 - dma_unmap_single(&adapter->vdev->dev, desc.fields.address, - skb->len, DMA_TO_DEVICE); + if (!used_bounce) + dma_unmap_single(&adapter->vdev->dev, data_dma_addr, + skb->len, DMA_TO_DEVICE); =20 out: spin_lock_irqsave(&adapter->stats_lock, flags); netdev->stats.tx_dropped +=3D tx_dropped; @@ -1053,8 +1105,9 @@ static void ibmveth_set_multicast_list(s static int ibmveth_change_mtu(struct net_device *dev, int new_mtu) { struct ibmveth_adapter *adapter =3D dev->priv; + struct vio_dev *viodev =3D adapter->vdev; int new_mtu_oh =3D new_mtu + IBMVETH_BUFF_OH; - int i, rc; + int i; =20 if (new_mtu < IBMVETH_MAX_MTU) return -EINVAL; @@ -1085,10 +1138,15 @@ static int ibmveth_change_mtu(struct net ibmveth_close(adapter->netdev); adapter->pool_config =3D 0; dev->mtu =3D new_mtu; - if ((rc =3D ibmveth_open(adapter->netdev))) - return rc; - } else - dev->mtu =3D new_mtu; + vio_cmo_set_dev_desired(viodev, + ibmveth_get_io_entitlement + (viodev)); + return ibmveth_open(adapter->netdev); + } + dev->mtu =3D new_mtu; + vio_cmo_set_dev_desired(viodev, + ibmveth_get_io_entitlement + (viodev)); return 0; } } @@ -1103,6 +1161,46 @@ static void ibmveth_poll_controller(stru } #endif =20 +/** + * ibmveth_get_io_entitlement - Calculate IO entitlement needed by the dri= ver + * + * @vdev: struct vio_dev for the device whose entitlement is to be returned + * + * Return value: + * Number of bytes of IO data the driver will need to perform well. + */ +static unsigned long ibmveth_get_io_entitlement(struct vio_dev *vdev) +{ + struct net_device *netdev =3D dev_get_drvdata(&vdev->dev); + struct ibmveth_adapter *adapter; + unsigned long ret; + int i; + int rxqentries =3D 1; + + /* netdev inits at probe time along with the structures we need below*/ + if (netdev =3D=3D NULL) + return IOMMU_PAGE_ALIGN(IBMVETH_IO_ENTITLEMENT_DEFAULT); + + adapter =3D netdev_priv(netdev); + + ret =3D IBMVETH_BUFF_LIST_SIZE + IBMVETH_FILT_LIST_SIZE; + ret +=3D IOMMU_PAGE_ALIGN(netdev->mtu); + + for (i =3D 0; i < IbmVethNumBufferPools; i++) { + /* add the size of the active receive buffers */ + if (adapter->rx_buff_pool[i].active) + ret +=3D + adapter->rx_buff_pool[i].size * + IOMMU_PAGE_ALIGN(adapter->rx_buff_pool[i]. + buff_size); + rxqentries +=3D adapter->rx_buff_pool[i].size; + } + /* add the size of the receive queue entries */ + ret +=3D IOMMU_PAGE_ALIGN(rxqentries * sizeof(struct ibmveth_rx_q_entry)); + + return ret; +} + static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_d= evice_id *id) { int rc, i; @@ -1247,6 +1345,8 @@ static int __devexit ibmveth_remove(stru ibmveth_proc_unregister_adapter(adapter); =20 free_netdev(netdev); + dev_set_drvdata(&dev->dev, NULL); + return 0; } =20 @@ -1491,6 +1591,7 @@ static struct vio_driver ibmveth_driver=20 .id_table =3D ibmveth_device_table, .probe =3D ibmveth_probe, .remove =3D ibmveth_remove, + .get_io_entitlement =3D ibmveth_get_io_entitlement, .driver =3D { .name =3D ibmveth_driver_name, .owner =3D THIS_MODULE, Index: b/drivers/net/ibmveth.h =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- a/drivers/net/ibmveth.h +++ b/drivers/net/ibmveth.h @@ -93,9 +93,12 @@ static inline long h_illan_attributes(un plpar_hcall_norets(H_CHANGE_LOGICAL_LAN_MAC, ua, mac) =20 #define IbmVethNumBufferPools 5 +#define IBMVETH_IO_ENTITLEMENT_DEFAULT 4243456 /* MTU of 1500 needs 4.2Mb = */ #define IBMVETH_BUFF_OH 22 /* Overhead: 14 ethernet header + 8 opaque hand= le */ #define IBMVETH_MAX_MTU 68 #define IBMVETH_MAX_POOL_COUNT 4096 +#define IBMVETH_BUFF_LIST_SIZE 4096 +#define IBMVETH_FILT_LIST_SIZE 4096 #define IBMVETH_MAX_BUF_SIZE (1024 * 128) =20 static int pool_size[] =3D { 512, 1024 * 2, 1024 * 16, 1024 * 32, 1024 * 6= 4 }; @@ -143,6 +146,8 @@ struct ibmveth_adapter { struct ibmveth_rx_q rx_queue; int pool_config; int rx_csum; + void * bounce_buffer; + dma_addr_t bounce_buffer_dma; =20 /* adapter specific stats */ u64 replenish_task_cycles;