@@ -0,0 +1,459 @@+/*+*AppliedMicroX-GeneSoCEthernetv2Driver+*+*Copyright(c)2017,AppliedMicroCircuitsCorporation+*Author(s):IyappanSubramanian<isubramanian@apm.com>+*KeyurChudgar<kchudgar@apm.com>+*+*Thisprogramisfreesoftware;youcanredistributeitand/ormodifyit+*underthetermsoftheGNUGeneralPublicLicenseaspublishedbythe+*FreeSoftwareFoundation;eitherversion2oftheLicense,or(atyour+*option)anylaterversion.+*+*Thisprogramisdistributedinthehopethatitwillbeuseful,+*butWITHOUTANYWARRANTY;withouteventheimpliedwarrantyof+*MERCHANTABILITYorFITNESSFORAPARTICULARPURPOSE.Seethe+*GNUGeneralPublicLicenseformoredetails.+*+*YoushouldhavereceivedacopyoftheGNUGeneralPublicLicense+*alongwiththisprogram.Ifnot,see<http://www.gnu.org/licenses/>.+*/++#include"main.h"++staticconststructacpi_device_idxge_acpi_match[];++staticintxge_get_resources(structxge_pdata*pdata)+{+structplatform_device*pdev;+structnet_device*ndev;+structdevice*dev;+structresource*res;+intphy_mode,ret=0;++pdev=pdata->pdev;+dev=&pdev->dev;+ndev=pdata->ndev;++res=platform_get_resource(pdev,IORESOURCE_MEM,0);+if(!res){+dev_err(dev,"Resource enet_csr not defined\n");+return-ENODEV;+}++pdata->resources.base_addr=devm_ioremap(dev,res->start,+resource_size(res));+if(!pdata->resources.base_addr){+dev_err(dev,"Unable to retrieve ENET Port CSR region\n");+return-ENOMEM;+}++if(!device_get_mac_address(dev,ndev->dev_addr,ETH_ALEN))+eth_hw_addr_random(ndev);++memcpy(ndev->perm_addr,ndev->dev_addr,ndev->addr_len);++phy_mode=device_get_phy_mode(dev);+if(phy_mode<0){+dev_err(dev,"Unable to get phy-connection-type\n");+returnphy_mode;+}+pdata->resources.phy_mode=phy_mode;++if(pdata->resources.phy_mode!=PHY_INTERFACE_MODE_RGMII){+dev_err(dev,"Incorrect phy-connection-type specified\n");+return-ENODEV;+}++ret=platform_get_irq(pdev,0);+if(ret<=0){+dev_err(dev,"Unable to get ENET IRQ\n");+ret=ret?:-ENXIO;+returnret;+}+pdata->resources.irq=ret;++return0;+}++staticvoidxge_delete_desc_rings(structnet_device*ndev)+{+structxge_pdata*pdata=netdev_priv(ndev);+structdevice*dev=&pdata->pdev->dev;+structxge_desc_ring*ring;++ring=pdata->tx_ring;+if(ring){+if(ring->skbs)+devm_kfree(dev,ring->skbs);+if(ring->pkt_bufs)+devm_kfree(dev,ring->pkt_bufs);+devm_kfree(dev,ring);+}++ring=pdata->rx_ring;+if(ring){+if(ring->skbs)+devm_kfree(dev,ring->skbs);+devm_kfree(dev,ring);+}+}++staticstructxge_desc_ring*xge_create_desc_ring(structnet_device*ndev)+{+structxge_pdata*pdata=netdev_priv(ndev);+structdevice*dev=&pdata->pdev->dev;+structxge_desc_ring*ring;+u16size;++ring=devm_kzalloc(dev,sizeof(structxge_desc_ring),GFP_KERNEL);+if(!ring)+returnNULL;++ring->ndev=ndev;++size=XGENE_ENET_DESC_SIZE*XGENE_ENET_NUM_DESC;+ring->desc_addr=dmam_alloc_coherent(dev,size,&ring->dma_addr,+GFP_KERNEL|__GFP_ZERO);+if(!ring->desc_addr){+devm_kfree(dev,ring);+returnNULL;+}++xge_setup_desc(ring);++returnring;+}++staticintxge_refill_buffers(structnet_device*ndev,u32nbuf)+{+structxge_pdata*pdata=netdev_priv(ndev);+structxge_desc_ring*ring=pdata->rx_ring;+constu8slots=XGENE_ENET_NUM_DESC-1;+structdevice*dev=&pdata->pdev->dev;+structxge_raw_desc*raw_desc;+u64addr_lo,addr_hi;+u8tail=ring->tail;+structsk_buff*skb;+dma_addr_tdma_addr;+u16len;+inti;++for(i=0;i<nbuf;i++){+raw_desc=&ring->raw_desc[tail];++len=XGENE_ENET_STD_MTU;+skb=netdev_alloc_skb(ndev,len);+if(unlikely(!skb))+return-ENOMEM;++dma_addr=dma_map_single(dev,skb->data,len,DMA_FROM_DEVICE);+if(dma_mapping_error(dev,dma_addr)){+netdev_err(ndev,"DMA mapping error\n");+dev_kfree_skb_any(skb);+return-EINVAL;+}++addr_hi=GET_BITS(NEXT_DESC_ADDRH,le64_to_cpu(raw_desc->m1));+addr_lo=GET_BITS(NEXT_DESC_ADDRL,le64_to_cpu(raw_desc->m1));+raw_desc->m1=cpu_to_le64(SET_BITS(NEXT_DESC_ADDRL,addr_lo)|+SET_BITS(NEXT_DESC_ADDRH,addr_hi)|+SET_BITS(PKT_ADDRH,+dma_addr>>PKT_ADDRL_LEN));++dma_wmb();+raw_desc->m0=cpu_to_le64(SET_BITS(PKT_ADDRL,dma_addr)|+SET_BITS(E,1));+ring->skbs[tail]=skb;+tail=(tail+1)&slots;+}++ring->tail=tail;++return0;+}++staticintxge_create_desc_rings(structnet_device*ndev)+{+structxge_pdata*pdata=netdev_priv(ndev);+structdevice*dev=&pdata->pdev->dev;+structxge_desc_ring*ring;+intret;++/* create tx ring */+ring=xge_create_desc_ring(ndev);+if(!ring)+return-ENOMEM;++ring->skbs=devm_kcalloc(dev,XGENE_ENET_NUM_DESC,+sizeof(structsk_buff*),GFP_KERNEL);+if(!ring->skbs)+gotoerr;++ring->pkt_bufs=devm_kcalloc(dev,XGENE_ENET_NUM_DESC,+sizeof(void*),GFP_KERNEL);+if(!ring->pkt_bufs)+gotoerr;++pdata->tx_ring=ring;+xge_update_tx_desc_addr(pdata);++/* create rx ring */+ring=xge_create_desc_ring(ndev);+if(!ring)+gotoerr;++ring->skbs=devm_kcalloc(dev,XGENE_ENET_NUM_DESC,+sizeof(structsk_buff*),GFP_KERNEL);+if(!ring->skbs)+gotoerr;++pdata->rx_ring=ring;+xge_update_rx_desc_addr(pdata);++ret=xge_refill_buffers(ndev,XGENE_ENET_NUM_DESC);+if(!ret)+return0;++err:+xge_delete_desc_rings(ndev);++return-ENOMEM;+}++staticintxge_init_hw(structnet_device*ndev)+{+structxge_pdata*pdata=netdev_priv(ndev);+intret;++ret=xge_port_reset(ndev);+if(ret)+returnret;++xge_create_desc_rings(ndev);+xge_port_init(ndev);+pdata->nbufs=NUM_BUFS;++return0;+}++staticirqreturn_txge_irq(constintirq,void*data)+{+structxge_pdata*pdata=data;++if(napi_schedule_prep(&pdata->napi)){+xge_intr_disable(pdata);+__napi_schedule(&pdata->napi);+}++returnIRQ_HANDLED;+}++staticintxge_request_irq(structnet_device*ndev)+{+structxge_pdata*pdata=netdev_priv(ndev);+structdevice*dev=&pdata->pdev->dev;+intret;++snprintf(pdata->irq_name,IRQ_ID_SIZE,"%s",ndev->name);++ret=devm_request_irq(dev,pdata->resources.irq,xge_irq,+0,pdata->irq_name,pdata);+if(ret)+netdev_err(ndev,"Failed to request irq %s\n",pdata->irq_name);++returnret;+}++staticvoidxge_free_irq(structnet_device*ndev)+{+structxge_pdata*pdata=netdev_priv(ndev);+structdevice*dev=&pdata->pdev->dev;++devm_free_irq(dev,pdata->resources.irq,pdata);+}++staticintxge_open(structnet_device*ndev)+{+structxge_pdata*pdata=netdev_priv(ndev);+intret;++ret=xge_request_irq(ndev);+if(ret)+returnret;++xge_intr_enable(pdata);++xge_wr_csr(pdata,DMARXCTRL,1);+xge_mac_enable(pdata);+netif_start_queue(ndev);++return0;+}++staticintxge_close(structnet_device*ndev)+{+structxge_pdata*pdata=netdev_priv(ndev);++netif_stop_queue(ndev);+xge_mac_disable(pdata);++xge_free_irq(ndev);++return0;+}++staticintxge_set_mac_addr(structnet_device*ndev,void*addr)+{+structxge_pdata*pdata=netdev_priv(ndev);+intret;++ret=eth_mac_addr(ndev,addr);+if(ret)+returnret;++xge_mac_set_station_addr(pdata);++return0;+}++staticvoidxge_timeout(structnet_device*ndev)+{+structxge_pdata*pdata=netdev_priv(ndev);+structnetdev_queue*txq;++xge_mac_reset(pdata);++txq=netdev_get_tx_queue(ndev,0);+txq->trans_start=jiffies;+netif_tx_start_queue(txq);+}++staticvoidxge_get_stats64(structnet_device*ndev,+structrtnl_link_stats64*storage)+{+structxge_pdata*pdata=netdev_priv(ndev);+structxge_stats*stats=&pdata->stats;++storage->tx_packets+=stats->tx_packets;+storage->tx_bytes+=stats->tx_bytes;++storage->rx_packets+=stats->rx_packets;+storage->rx_bytes+=stats->rx_bytes;+}++staticconststructnet_device_opsxgene_ndev_ops={+.ndo_open=xge_open,+.ndo_stop=xge_close,+.ndo_set_mac_address=xge_set_mac_addr,+.ndo_tx_timeout=xge_timeout,+.ndo_get_stats64=xge_get_stats64,+};++staticintxge_probe(structplatform_device*pdev)+{+structdevice*dev=&pdev->dev;+structnet_device*ndev;+structxge_pdata*pdata;+intret;++ndev=alloc_etherdev(sizeof(structxge_pdata));+if(!ndev)+return-ENOMEM;++pdata=netdev_priv(ndev);++pdata->pdev=pdev;+pdata->ndev=ndev;+SET_NETDEV_DEV(ndev,dev);+platform_set_drvdata(pdev,pdata);+ndev->netdev_ops=&xgene_ndev_ops;++ndev->features|=NETIF_F_GSO|+NETIF_F_GRO;++ret=xge_get_resources(pdata);+if(ret)+gotoerr;++ndev->hw_features=ndev->features;++ret=dma_coerce_mask_and_coherent(dev,DMA_BIT_MASK(64));+if(ret){+netdev_err(ndev,"No usable DMA configuration\n");+gotoerr;+}++ret=xge_init_hw(ndev);+if(ret)+gotoerr;++ret=register_netdev(ndev);+if(ret){+netdev_err(ndev,"Failed to register netdev\n");+gotoerr;+}++return0;++err:+free_netdev(ndev);++returnret;+}++staticintxge_remove(structplatform_device*pdev)+{+structxge_pdata*pdata;+structnet_device*ndev;++pdata=platform_get_drvdata(pdev);+ndev=pdata->ndev;++rtnl_lock();+if(netif_running(ndev))+dev_close(ndev);+rtnl_unlock();++unregister_netdev(ndev);+xge_delete_desc_rings(ndev);+free_netdev(ndev);++return0;+}++staticvoidxge_shutdown(structplatform_device*pdev)+{+structxge_pdata*pdata;++pdata=platform_get_drvdata(pdev);+if(!pdata)+return;++if(!pdata->ndev)+return;++xge_remove(pdev);+}++staticconststructacpi_device_idxge_acpi_match[]={+{"APMC0D80"},+{}+};+MODULE_DEVICE_TABLE(acpi,xge_acpi_match);++staticstructplatform_driverxge_driver={+.driver={+.name="xgene-enet-v2",+.acpi_match_table=ACPI_PTR(xge_acpi_match),+},+.probe=xge_probe,+.remove=xge_remove,+.shutdown=xge_shutdown,+};+module_platform_driver(xge_driver);++MODULE_DESCRIPTION("APM X-Gene SoC Ethernet v2 driver");+MODULE_AUTHOR("Iyappan Subramanian <isubramanian@apm.com>");+MODULE_VERSION(XGENE_ENET_V2_VERSION);+MODULE_LICENSE("GPL");
@@ -278,13 +280,14 @@ static int xge_open(struct net_device *ndev)structxge_pdata*pdata=netdev_priv(ndev);intret;+napi_enable(&pdata->napi);+ret=xge_request_irq(ndev);if(ret)returnret;xge_intr_enable(pdata);-xge_wr_csr(pdata,DMARXCTRL,1);xge_mac_enable(pdata);netif_start_queue(ndev);
@@ -298,11 +301,204 @@ static int xge_close(struct net_device *ndev)netif_stop_queue(ndev);xge_mac_disable(pdata);+xge_intr_disable(pdata);xge_free_irq(ndev);+napi_disable(&pdata->napi);return0;}+staticnetdev_tx_txge_start_xmit(structsk_buff*skb,structnet_device*ndev)+{+structxge_pdata*pdata=netdev_priv(ndev);+structdevice*dev=&pdata->pdev->dev;+staticdma_addr_tdma_addr;+structxge_desc_ring*tx_ring;+structxge_raw_desc*raw_desc;+u64addr_lo,addr_hi;+void*pkt_buf;+u8tail;+u16len;++tx_ring=pdata->tx_ring;+tail=tx_ring->tail;+len=skb_headlen(skb);+raw_desc=&tx_ring->raw_desc[tail];++/* Tx descriptor not available */+if(!GET_BITS(E,le64_to_cpu(raw_desc->m0))||+GET_BITS(PKT_SIZE,le64_to_cpu(raw_desc->m0)))+returnNETDEV_TX_BUSY;++/* Packet buffers should be 64B aligned */+pkt_buf=dma_alloc_coherent(dev,XGENE_ENET_STD_MTU,&dma_addr,+GFP_ATOMIC);+if(unlikely(!pkt_buf))+gotoout;++memcpy(pkt_buf,skb->data,len);++addr_hi=GET_BITS(NEXT_DESC_ADDRH,le64_to_cpu(raw_desc->m1));+addr_lo=GET_BITS(NEXT_DESC_ADDRL,le64_to_cpu(raw_desc->m1));+raw_desc->m1=cpu_to_le64(SET_BITS(NEXT_DESC_ADDRL,addr_lo)|+SET_BITS(NEXT_DESC_ADDRH,addr_hi)|+SET_BITS(PKT_ADDRH,+dma_addr>>PKT_ADDRL_LEN));++dma_wmb();++raw_desc->m0=cpu_to_le64(SET_BITS(PKT_ADDRL,dma_addr)|+SET_BITS(PKT_SIZE,len)|+SET_BITS(E,0));++skb_tx_timestamp(skb);+xge_wr_csr(pdata,DMATXCTRL,1);++pdata->stats.tx_packets++;+pdata->stats.tx_bytes+=skb->len;++tx_ring->skbs[tail]=skb;+tx_ring->pkt_bufs[tail]=pkt_buf;+tx_ring->tail=(tail+1)&(XGENE_ENET_NUM_DESC-1);++out:+dev_kfree_skb_any(skb);++returnNETDEV_TX_OK;+}++staticvoidxge_txc_poll(structnet_device*ndev,unsignedintbudget)+{+structxge_pdata*pdata=netdev_priv(ndev);+structdevice*dev=&pdata->pdev->dev;+structxge_desc_ring*tx_ring;+structxge_raw_desc*raw_desc;+u64addr_lo,addr_hi;+dma_addr_tdma_addr;+void*pkt_buf;+boolpktsent;+u32data;+u8head;+inti;++tx_ring=pdata->tx_ring;+head=tx_ring->head;++data=xge_rd_csr(pdata,DMATXSTATUS);+pktsent=data&TX_PKT_SENT;+if(unlikely(!pktsent))+return;++for(i=0;i<budget;i++){+raw_desc=&tx_ring->raw_desc[head];++if(!GET_BITS(E,le64_to_cpu(raw_desc->m0)))+break;++dma_rmb();++addr_hi=GET_BITS(PKT_ADDRH,le64_to_cpu(raw_desc->m1));+addr_lo=GET_BITS(PKT_ADDRL,le64_to_cpu(raw_desc->m0));+dma_addr=(addr_hi<<PKT_ADDRL_LEN)|addr_lo;++pkt_buf=tx_ring->pkt_bufs[head];++/* clear pktstart address and pktsize */+raw_desc->m0=cpu_to_le64(SET_BITS(E,1)|+SET_BITS(PKT_SIZE,0));+xge_wr_csr(pdata,DMATXSTATUS,1);++dma_free_coherent(dev,XGENE_ENET_STD_MTU,pkt_buf,dma_addr);++head=(head+1)&(XGENE_ENET_NUM_DESC-1);+}++tx_ring->head=head;+}++staticintxge_rx_poll(structnet_device*ndev,unsignedintbudget)+{+structxge_pdata*pdata=netdev_priv(ndev);+structdevice*dev=&pdata->pdev->dev;+dma_addr_taddr_hi,addr_lo,dma_addr;+structxge_desc_ring*rx_ring;+structxge_raw_desc*raw_desc;+structsk_buff*skb;+inti,npkts,ret=0;+boolpktrcvd;+u32data;+u8head;+u16len;++rx_ring=pdata->rx_ring;+head=rx_ring->head;++data=xge_rd_csr(pdata,DMARXSTATUS);+pktrcvd=data&RXSTATUS_RXPKTRCVD;++if(unlikely(!pktrcvd))+return0;++npkts=0;+for(i=0;i<budget;i++){+raw_desc=&rx_ring->raw_desc[head];++if(GET_BITS(E,le64_to_cpu(raw_desc->m0)))+break;++dma_rmb();++addr_hi=GET_BITS(PKT_ADDRH,le64_to_cpu(raw_desc->m1));+addr_lo=GET_BITS(PKT_ADDRL,le64_to_cpu(raw_desc->m0));+dma_addr=(addr_hi<<PKT_ADDRL_LEN)|addr_lo;+len=GET_BITS(PKT_SIZE,le64_to_cpu(raw_desc->m0));++dma_unmap_single(dev,dma_addr,XGENE_ENET_STD_MTU,+DMA_FROM_DEVICE);++skb=rx_ring->skbs[head];+skb_put(skb,len);++skb->protocol=eth_type_trans(skb,ndev);++pdata->stats.rx_packets++;+pdata->stats.rx_bytes+=len;+napi_gro_receive(&pdata->napi,skb);+npkts++;++ret=xge_refill_buffers(ndev,1);+xge_wr_csr(pdata,DMARXSTATUS,1);++if(ret)+break;++head=(head+1)&(XGENE_ENET_NUM_DESC-1);+}++rx_ring->head=head;++returnnpkts;+}++staticintxge_napi(structnapi_struct*napi,constintbudget)+{+structnet_device*ndev=napi->dev;+structxge_pdata*pdata=netdev_priv(ndev);+intprocessed;++pdata=netdev_priv(ndev);++xge_txc_poll(ndev,budget);+processed=xge_rx_poll(ndev,budget);++if(processed<budget){+napi_complete(napi);+xge_intr_enable(pdata);+}++returnprocessed;+}+staticintxge_set_mac_addr(structnet_device*ndev,void*addr){structxge_pdata*pdata=netdev_priv(ndev);
This patch adds a MAINTAINERS entry for the ethernet driver for
the on-chip ethernet interface which uses a linked list of DMA
descriptor architecture (v2) for APM X-Gene SoCs.
Signed-off-by: Iyappan Subramanian <redacted>
Signed-off-by: Keyur Chudgar <redacted>
---
MAINTAINERS | 6 ++++++
1 file changed, 6 insertions(+)
This seems a bit limiting. What if you need to use:
PHY_INTERFACE_MODE_RGMII_ID,
PHY_INTERFACE_MODE_RGMII_RXID,
PHY_INTERFACE_MODE_RGMII_TXID,
in order to set the RGMII delays.
Andrew
The very fact that you have to do the devm_kfree suggests that the way
you manage the lifetime of the ring is not appropriate, and in fact, if
we look at how xge_create_desc_ring() is called, in the driver's probe
function indicates that if the network interface is never openeded, we
are just wasting memory sitting there and doing nothing. You should
consider moving this to the ndo_open(), resp. ndo_close() functions to
optimize memory consumption wrt. the network interface state.
This is both racy and incorrect. Racy because after you wrote DMATXCTRL,
your TX completion can run, and it can do that while interrupting your
CPU presumably, and free the SKB, therefore making you access a freed
SKB (or it should, if it does not), it's also incorrect, because before
you get signaled a TX completion, there is no guarantee that the packets
did actually make it through, you must update your stats in the TX
completion handler.
So pktrcvd is not an indication of the produced number of packets, just
that there are packets, that's not very convenient, and it's redundant
with the very fact of being interrupted.
From: kbuild test robot <hidden> Date: 2017-01-31 20:49:58
Hi Iyappan,
[auto build test WARNING on net-next/master]
url: https://github.com/0day-ci/linux/commits/Iyappan-Subramanian/drivers-net-xgene-v2-Add-RGMII-based-1G-driver/20170201-034317
config: parisc-allyesconfig (attached as .config)
compiler: hppa-linux-gnu-gcc (Debian 6.1.1-9) 6.1.1 20160705
reproduce:
wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
make.cross ARCH=parisc
All warnings (new ones prefixed by >>):
In file included from include/linux/swab.h:4:0,
from include/uapi/linux/byteorder/big_endian.h:12,
from include/linux/byteorder/big_endian.h:4,
from arch/parisc/include/uapi/asm/byteorder.h:4,
from arch/parisc/include/asm/bitops.h:10,
from include/linux/bitops.h:36,
from include/linux/kernel.h:10,
from include/linux/list.h:8,
from include/linux/resource_ext.h:17,
from include/linux/acpi.h:26,
from drivers/net/ethernet/apm/xgene-v2/main.h:25,
from drivers/net/ethernet/apm/xgene-v2/main.c:22:
drivers/net/ethernet/apm/xgene-v2/main.c: In function 'xge_refill_buffers':
drivers/net/ethernet/apm/xgene-v2/main.c:162:20: warning: right shift count >= width of type [-Wshift-count-overflow]
dma_addr >> PKT_ADDRL_LEN));
^
include/uapi/linux/swab.h:129:32: note: in definition of macro '__swab64'
(__builtin_constant_p((__u64)(x)) ? \
^
quoted
include/linux/byteorder/generic.h:85:21: note: in expansion of macro '__cpu_to_le64'
#define cpu_to_le64 __cpu_to_le64
^~~~~~~~~~~~~
drivers/net/ethernet/apm/xgene-v2/main.c:161:9: note: in expansion of macro 'SET_BITS'
SET_BITS(PKT_ADDRH,
^~~~~~~~
drivers/net/ethernet/apm/xgene-v2/main.c:162:20: warning: right shift count >= width of type [-Wshift-count-overflow]
dma_addr >> PKT_ADDRL_LEN));
^
include/uapi/linux/swab.h:131:12: note: in definition of macro '__swab64'
__fswab64(x))
^
quoted
include/linux/byteorder/generic.h:85:21: note: in expansion of macro '__cpu_to_le64'
#define cpu_to_le64 __cpu_to_le64
^~~~~~~~~~~~~
drivers/net/ethernet/apm/xgene-v2/main.c:161:9: note: in expansion of macro 'SET_BITS'
SET_BITS(PKT_ADDRH,
^~~~~~~~
drivers/net/ethernet/apm/xgene-v2/main.c: In function 'xge_start_xmit':
drivers/net/ethernet/apm/xgene-v2/main.c:346:19: warning: right shift count >= width of type [-Wshift-count-overflow]
dma_addr >> PKT_ADDRL_LEN));
^
include/uapi/linux/swab.h:129:32: note: in definition of macro '__swab64'
(__builtin_constant_p((__u64)(x)) ? \
^
quoted
include/linux/byteorder/generic.h:85:21: note: in expansion of macro '__cpu_to_le64'
#define cpu_to_le64 __cpu_to_le64
^~~~~~~~~~~~~
drivers/net/ethernet/apm/xgene-v2/main.c:345:8: note: in expansion of macro 'SET_BITS'
SET_BITS(PKT_ADDRH,
^~~~~~~~
drivers/net/ethernet/apm/xgene-v2/main.c:346:19: warning: right shift count >= width of type [-Wshift-count-overflow]
dma_addr >> PKT_ADDRL_LEN));
^
include/uapi/linux/swab.h:131:12: note: in definition of macro '__swab64'
__fswab64(x))
^
quoted
include/linux/byteorder/generic.h:85:21: note: in expansion of macro '__cpu_to_le64'
#define cpu_to_le64 __cpu_to_le64
^~~~~~~~~~~~~
drivers/net/ethernet/apm/xgene-v2/main.c:345:8: note: in expansion of macro 'SET_BITS'
SET_BITS(PKT_ADDRH,
^~~~~~~~
drivers/net/ethernet/apm/xgene-v2/main.c: In function 'xge_rx_poll':
drivers/net/ethernet/apm/xgene-v2/main.c:453:23: warning: left shift count >= width of type [-Wshift-count-overflow]
dma_addr = (addr_hi << PKT_ADDRL_LEN) | addr_lo;
^~
vim +/__cpu_to_le64 +85 include/linux/byteorder/generic.h
^1da177e Linus Torvalds 2005-04-16 69 * cpu_to_[bl]eXX(__uXX x)
^1da177e Linus Torvalds 2005-04-16 70 * [bl]eXX_to_cpu(__uXX x)
^1da177e Linus Torvalds 2005-04-16 71 *
^1da177e Linus Torvalds 2005-04-16 72 * The same, but takes a pointer to the value to convert
^1da177e Linus Torvalds 2005-04-16 73 * cpu_to_[bl]eXXp(__uXX x)
^1da177e Linus Torvalds 2005-04-16 74 * [bl]eXX_to_cpup(__uXX x)
^1da177e Linus Torvalds 2005-04-16 75 *
^1da177e Linus Torvalds 2005-04-16 76 * The same, but change in situ
^1da177e Linus Torvalds 2005-04-16 77 * cpu_to_[bl]eXXs(__uXX x)
^1da177e Linus Torvalds 2005-04-16 78 * [bl]eXX_to_cpus(__uXX x)
^1da177e Linus Torvalds 2005-04-16 79 *
^1da177e Linus Torvalds 2005-04-16 80 * See asm-foo/byteorder.h for examples of how to provide
^1da177e Linus Torvalds 2005-04-16 81 * architecture-optimized versions
^1da177e Linus Torvalds 2005-04-16 82 *
^1da177e Linus Torvalds 2005-04-16 83 */
^1da177e Linus Torvalds 2005-04-16 84
^1da177e Linus Torvalds 2005-04-16 @85 #define cpu_to_le64 __cpu_to_le64
^1da177e Linus Torvalds 2005-04-16 86 #define le64_to_cpu __le64_to_cpu
^1da177e Linus Torvalds 2005-04-16 87 #define cpu_to_le32 __cpu_to_le32
^1da177e Linus Torvalds 2005-04-16 88 #define le32_to_cpu __le32_to_cpu
^1da177e Linus Torvalds 2005-04-16 89 #define cpu_to_le16 __cpu_to_le16
^1da177e Linus Torvalds 2005-04-16 90 #define le16_to_cpu __le16_to_cpu
^1da177e Linus Torvalds 2005-04-16 91 #define cpu_to_be64 __cpu_to_be64
^1da177e Linus Torvalds 2005-04-16 92 #define be64_to_cpu __be64_to_cpu
^1da177e Linus Torvalds 2005-04-16 93 #define cpu_to_be32 __cpu_to_be32
:::::: The code at line 85 was first introduced by commit
:::::: 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 Linux-2.6.12-rc2
:::::: TO: Linus Torvalds [off-list ref]
:::::: CC: Linus Torvalds [off-list ref]
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
-------------- next part --------------
A non-text attachment was scrubbed...
Name: .config.gz
Type: application/gzip
Size: 48442 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20170201/7498852d/attachment-0001.gz>
Can't you obtain a DMA-API mapping for skb->data and pass it down to the
hardware? This copy here is inefficient.
quoted
+
+ memcpy(pkt_buf, skb->data, len);
You really need to verify that the len <= XGENE_ENET_STD_MTU.
Isn't this code only transmitting the 'head' of the packet?
What about the fragments??
...
David
This seems a bit limiting. What if you need to use:
PHY_INTERFACE_MODE_RGMII_ID,
PHY_INTERFACE_MODE_RGMII_RXID,
PHY_INTERFACE_MODE_RGMII_TXID,
in order to set the RGMII delays.
This version of the driver doesn't support setting delays. The delay
support will be added in the future.
The very fact that you have to do the devm_kfree suggests that the way
you manage the lifetime of the ring is not appropriate, and in fact, if
we look at how xge_create_desc_ring() is called, in the driver's probe
function indicates that if the network interface is never openeded, we
are just wasting memory sitting there and doing nothing. You should
consider moving this to the ndo_open(), resp. ndo_close() functions to
optimize memory consumption wrt. the network interface state.
I will move these to open and close functions and will use dma_zalloc() APIs.
This is both racy and incorrect. Racy because after you wrote DMATXCTRL,
your TX completion can run, and it can do that while interrupting your
CPU presumably, and free the SKB, therefore making you access a freed
SKB (or it should, if it does not), it's also incorrect, because before
you get signaled a TX completion, there is no guarantee that the packets
did actually make it through, you must update your stats in the TX
completion handler.
Thanks. I'll move the tx stats part to Tx completion.
So pktrcvd is not an indication of the produced number of packets, just
that there are packets, that's not very convenient, and it's redundant
with the very fact of being interrupted.
Agree, but the interrupt is common for Tx completion and Rx, this
check is still required.