This is a resend of some improvements to the ucc_geth driver that was
previously sent together with bug fixes, which have by now been
applied.
Li Yang, if you don't speak up, I'm going to assume you're fine with
2,3,4 being taken through the net tree?
v2: rebase to net/master; address minor style issues; don't introduce
a use-after-free in patch "don't statically allocate eight
ucc_geth_info".
Rasmus Villemoes (17):
ethernet: ucc_geth: remove unused read of temoder field
soc: fsl: qe: make cpm_muram_offset take a const void* argument
soc: fsl: qe: store muram_vbase as a void pointer instead of u8
soc: fsl: qe: add cpm_muram_free_addr() helper
ethernet: ucc_geth: use qe_muram_free_addr()
ethernet: ucc_geth: remove unnecessary memset_io() calls
ethernet: ucc_geth: replace kmalloc+memset by kzalloc
ethernet: ucc_geth: remove {rx,tx}_glbl_pram_offset from struct
ucc_geth_private
ethernet: ucc_geth: factor out parsing of {rx,tx}-clock{,-name}
properties
ethernet: ucc_geth: constify ugeth_primary_info
ethernet: ucc_geth: don't statically allocate eight ucc_geth_info
ethernet: ucc_geth: use UCC_GETH_{RX,TX}_BD_RING_ALIGNMENT macros
directly
ethernet: ucc_geth: remove bd_mem_part and all associated code
ethernet: ucc_geth: replace kmalloc_array()+for loop by kcalloc()
ethernet: ucc_geth: add helper to replace repeated switch statements
ethernet: ucc_geth: inform the compiler that numQueues is always 1
ethernet: ucc_geth: simplify rx/tx allocations
drivers/net/ethernet/freescale/ucc_geth.c | 549 ++++++++--------------
drivers/net/ethernet/freescale/ucc_geth.h | 6 -
drivers/soc/fsl/qe/qe_common.c | 20 +-
include/soc/fsl/qe/qe.h | 15 +-
include/soc/fsl/qe/ucc_fast.h | 1 -
5 files changed, 209 insertions(+), 382 deletions(-)
--
2.23.0
The two functions cpm_muram_offset() and cpm_muram_dma() both need a
cast currently, one casts muram_vbase to do the pointer arithmetic on
void pointers, the other casts the passed-in address u8*.
It's simpler and more consistent to just always use void* and drop all
the casting.
Signed-off-by: Rasmus Villemoes <redacted>
---
drivers/soc/fsl/qe/qe_common.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
Since kmalloc() is nowadays [1] guaranteed to return naturally
aligned (i.e., aligned to the size itself) memory for power-of-2
sizes, we don't need to over-allocate the align amount, compute an
aligned address within the allocation, and (for later freeing) also
storing the original pointer [2].
Instead, just round up the length we want to allocate to the alignment
requirements, then round that up to the next power of 2. In theory,
this could allocate up to about twice as much memory as we needed. In
practice, (a) kmalloc() would in most cases anyway return a
power-of-2-sized allocation and (b) with the default values of the
bdRingLen[RT]x fields, the length is already itself a power of 2
greater than the alignment.
So we actually end up saving memory compared to the current
situtation (e.g. for tx, we currently allocate 128+32 bytes, which
kmalloc() likely rounds up to 192 or 256; with this patch, we just
allocate 128 bytes.) Also struct ucc_geth_private becomes a little
smaller.
[1] 59bb47985c1d ("mm, sl[aou]b: guarantee natural alignment for
kmalloc(power-of-two)")
[2] That storing was anyway done in a u32, which works on 32 bit
machines, but is not very elegant and certainly makes a reader of the
code pause for a while.
Signed-off-by: Rasmus Villemoes <redacted>
---
drivers/net/ethernet/freescale/ucc_geth.c | 50 ++++++++---------------
drivers/net/ethernet/freescale/ucc_geth.h | 2 -
2 files changed, 17 insertions(+), 35 deletions(-)
@@ -2150,25 +2148,15 @@ static int ucc_geth_alloc_tx(struct ucc_geth_private *ugeth)/* Allocate Tx bds */for(j=0;j<ucc_geth_tx_queues(ug_info);j++){-u32align=UCC_GETH_TX_BD_RING_ALIGNMENT;--/* Allocate in multiple of-UCC_GETH_TX_BD_RING_SIZE_MEMORY_ALIGNMENT,-accordingtospec*/-length=((ug_info->bdRingLenTx[j]*sizeof(structqe_bd))-/UCC_GETH_TX_BD_RING_SIZE_MEMORY_ALIGNMENT)-*UCC_GETH_TX_BD_RING_SIZE_MEMORY_ALIGNMENT;-if((ug_info->bdRingLenTx[j]*sizeof(structqe_bd))%-UCC_GETH_TX_BD_RING_SIZE_MEMORY_ALIGNMENT)-length+=UCC_GETH_TX_BD_RING_SIZE_MEMORY_ALIGNMENT;--ugeth->tx_bd_ring_offset[j]=-(u32)kmalloc((u32)(length+align),GFP_KERNEL);--if(ugeth->tx_bd_ring_offset[j]!=0)-ugeth->p_tx_bd_ring[j]=-(u8__iomem*)((ugeth->tx_bd_ring_offset[j]+-align)&~(align-1));+u32align=max(UCC_GETH_TX_BD_RING_ALIGNMENT,+UCC_GETH_TX_BD_RING_SIZE_MEMORY_ALIGNMENT);+u32alloc;++length=ug_info->bdRingLenTx[j]*sizeof(structqe_bd);+alloc=round_up(length,align);+alloc=roundup_pow_of_two(alloc);++ugeth->p_tx_bd_ring[j]=kmalloc(alloc,GFP_KERNEL);if(!ugeth->p_tx_bd_ring[j]){if(netif_msg_ifup(ugeth))
@@ -2176,9 +2164,7 @@ static int ucc_geth_alloc_tx(struct ucc_geth_private *ugeth)return-ENOMEM;}/* Zero unused end of bd ring, according to spec */-memset_io((void__iomem*)(ugeth->p_tx_bd_ring[j]+-ug_info->bdRingLenTx[j]*sizeof(structqe_bd)),0,-length-ug_info->bdRingLenTx[j]*sizeof(structqe_bd));+memset(ugeth->p_tx_bd_ring[j]+length,0,alloc-length);}/* Init Tx bds */
@@ -2225,15 +2211,13 @@ static int ucc_geth_alloc_rx(struct ucc_geth_private *ugeth)/* Allocate Rx bds */for(j=0;j<ucc_geth_rx_queues(ug_info);j++){u32align=UCC_GETH_RX_BD_RING_ALIGNMENT;+u32alloc;length=ug_info->bdRingLenRx[j]*sizeof(structqe_bd);-ugeth->rx_bd_ring_offset[j]=-(u32)kmalloc((u32)(length+align),GFP_KERNEL);-if(ugeth->rx_bd_ring_offset[j]!=0)-ugeth->p_rx_bd_ring[j]=-(u8__iomem*)((ugeth->rx_bd_ring_offset[j]+-align)&~(align-1));+alloc=round_up(length,align);+alloc=roundup_pow_of_two(alloc);+ugeth->p_rx_bd_ring[j]=kmalloc(alloc,GFP_KERNEL);if(!ugeth->p_rx_bd_ring[j]){if(netif_msg_ifup(ugeth))pr_err("Can not allocate memory for Rx bd rings\n");
The numQueuesTx and numQueuesRx members of struct ucc_geth_info are
never set to anything but 1, and never have been. It's unclear how
well the code supporting multiple queues would work. Until somebody
wants to play with enabling that, help the compiler eliminate a lot of
dead code and loops that are not really loops by creating static
inline helpers. If and when the numQueuesTx/numQueuesRx fields are
re-introduced, it suffices to update those helper to return the
appropriate field.
This cuts the .text segment of ucc_geth.o by 8%.
Signed-off-by: Rasmus Villemoes <redacted>
---
drivers/net/ethernet/freescale/ucc_geth.c | 76 +++++++++++++----------
drivers/net/ethernet/freescale/ucc_geth.h | 2 -
2 files changed, 42 insertions(+), 36 deletions(-)
@@ -2035,7 +2043,7 @@ static int ucc_struct_init(struct ucc_geth_private *ugeth)}/* Tx BD lengths */-for(i=0;i<ug_info->numQueuesTx;i++){+for(i=0;i<ucc_geth_tx_queues(ug_info);i++){if(ug_info->bdRingLenTx[i]<UCC_GETH_TX_BD_RING_SIZE_MIN){if(netif_msg_probe(ugeth))pr_err("Tx BD ring length must be no smaller than 2\n");
@@ -2052,14 +2060,14 @@ static int ucc_struct_init(struct ucc_geth_private *ugeth)}/* num Tx queues */-if(ug_info->numQueuesTx>NUM_TX_QUEUES){+if(ucc_geth_tx_queues(ug_info)>NUM_TX_QUEUES){if(netif_msg_probe(ugeth))pr_err("number of tx queues too large\n");return-EINVAL;}/* num Rx queues */-if(ug_info->numQueuesRx>NUM_RX_QUEUES){+if(ucc_geth_rx_queues(ug_info)>NUM_RX_QUEUES){if(netif_msg_probe(ugeth))pr_err("number of rx queues too large\n");return-EINVAL;
@@ -2067,7 +2075,7 @@ static int ucc_struct_init(struct ucc_geth_private *ugeth)/* l2qt */for(i=0;i<UCC_GETH_VLAN_PRIORITY_MAX;i++){-if(ug_info->l2qt[i]>=ug_info->numQueuesRx){+if(ug_info->l2qt[i]>=ucc_geth_rx_queues(ug_info)){if(netif_msg_probe(ugeth))pr_err("VLAN priority table entry must not be larger than number of Rx queues\n");return-EINVAL;
@@ -2076,7 +2084,7 @@ static int ucc_struct_init(struct ucc_geth_private *ugeth)/* l3qt */for(i=0;i<UCC_GETH_IP_PRIORITY_MAX;i++){-if(ug_info->l3qt[i]>=ug_info->numQueuesRx){+if(ug_info->l3qt[i]>=ucc_geth_rx_queues(ug_info)){if(netif_msg_probe(ugeth))pr_err("IP priority table entry must not be larger than number of Rx queues\n");return-EINVAL;
@@ -2099,10 +2107,10 @@ static int ucc_struct_init(struct ucc_geth_private *ugeth)/* Generate uccm_mask for receive */uf_info->uccm_mask=ug_info->eventRegMask&UCCE_OTHER;/* Errors */-for(i=0;i<ug_info->numQueuesRx;i++)+for(i=0;i<ucc_geth_rx_queues(ug_info);i++)uf_info->uccm_mask|=(UCC_GETH_UCCE_RXF0<<i);-for(i=0;i<ug_info->numQueuesTx;i++)+for(i=0;i<ucc_geth_tx_queues(ug_info);i++)uf_info->uccm_mask|=(UCC_GETH_UCCE_TXB0<<i);/* Initialize the general fast UCC block. */if(ucc_fast_init(uf_info,&ugeth->uccf)){
@@ -2141,7 +2149,7 @@ static int ucc_geth_alloc_tx(struct ucc_geth_private *ugeth)uf_info=&ug_info->uf_info;/* Allocate Tx bds */-for(j=0;j<ug_info->numQueuesTx;j++){+for(j=0;j<ucc_geth_tx_queues(ug_info);j++){u32align=UCC_GETH_TX_BD_RING_ALIGNMENT;/* Allocate in multiple of
@@ -2174,7 +2182,7 @@ static int ucc_geth_alloc_tx(struct ucc_geth_private *ugeth)}/* Init Tx bds */-for(j=0;j<ug_info->numQueuesTx;j++){+for(j=0;j<ucc_geth_tx_queues(ug_info);j++){/* Setup the skbuff rings */ugeth->tx_skbuff[j]=kcalloc(ugeth->ug_info->bdRingLenTx[j],
@@ -2234,7 +2242,7 @@ static int ucc_geth_alloc_rx(struct ucc_geth_private *ugeth)}/* Init Rx bds */-for(j=0;j<ug_info->numQueuesRx;j++){+for(j=0;j<ucc_geth_rx_queues(ug_info);j++){/* Setup the skbuff rings */ugeth->rx_skbuff[j]=kcalloc(ugeth->ug_info->bdRingLenRx[j],
@@ -2437,7 +2445,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)/* SQPTR *//* Size varies with number of Tx queues */ugeth->send_q_mem_reg_offset=-qe_muram_alloc(ug_info->numQueuesTx*+qe_muram_alloc(ucc_geth_tx_queues(ug_info)*sizeof(structucc_geth_send_queue_qd),UCC_GETH_SEND_QUEUE_QUEUE_DESCRIPTOR_ALIGNMENT);if(IS_ERR_VALUE(ugeth->send_q_mem_reg_offset)){
@@ -2453,7 +2461,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)/* Setup the table *//* Assume BD rings are already established */-for(i=0;i<ug_info->numQueuesTx;i++){+for(i=0;i<ucc_geth_tx_queues(ug_info);i++){endOfRing=ugeth->p_tx_bd_ring[i]+(ug_info->bdRingLenTx[i]-1)*sizeof(structqe_bd);
@@ -2466,7 +2474,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)/* schedulerbasepointer */-if(ug_info->numQueuesTx>1){+if(ucc_geth_tx_queues(ug_info)>1){/* scheduler exists only if more than 1 tx queue */ugeth->scheduler_offset=qe_muram_alloc(sizeof(structucc_geth_scheduler),
@@ -2529,11 +2537,11 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)/* temoder *//* Already has speed set */-if(ug_info->numQueuesTx>1)+if(ucc_geth_tx_queues(ug_info)>1)temoder|=TEMODER_SCHEDULER_ENABLE;if(ug_info->ipCheckSumGenerate)temoder|=TEMODER_IP_CHECKSUM_GENERATE;-temoder|=((ug_info->numQueuesTx-1)<<TEMODER_NUM_OF_QUEUES_SHIFT);+temoder|=((ucc_geth_tx_queues(ug_info)-1)<<TEMODER_NUM_OF_QUEUES_SHIFT);out_be16(&ugeth->p_tx_glbl_pram->temoder,temoder);/* Function code register value to be used later */
@@ -2597,7 +2605,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)/* Size varies with number of Rx queues */ugeth->rx_irq_coalescing_tbl_offset=-qe_muram_alloc(ug_info->numQueuesRx*+qe_muram_alloc(ucc_geth_rx_queues(ug_info)*sizeof(structucc_geth_rx_interrupt_coalescing_entry)+4,UCC_GETH_RX_INTERRUPT_COALESCING_ALIGNMENT);if(IS_ERR_VALUE(ugeth->rx_irq_coalescing_tbl_offset)){
@@ -2613,7 +2621,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)ugeth->rx_irq_coalescing_tbl_offset);/* Fill interrupt coalescing table */-for(i=0;i<ug_info->numQueuesRx;i++){+for(i=0;i<ucc_geth_rx_queues(ug_info);i++){out_be32(&ugeth->p_rx_irq_coalescing_tbl->coalescingentry[i].interruptcoalescingmaxvalue,ug_info->interruptcoalescingmaxvalue[i]);
@@ -2662,7 +2670,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)/* RBDQPTR *//* Size varies with number of Rx queues */ugeth->rx_bd_qs_tbl_offset=-qe_muram_alloc(ug_info->numQueuesRx*+qe_muram_alloc(ucc_geth_rx_queues(ug_info)*(sizeof(structucc_geth_rx_bd_queues_entry)+sizeof(structucc_geth_rx_prefetched_bds)),UCC_GETH_RX_BD_QUEUES_ALIGNMENT);
@@ -2679,7 +2687,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)/* Setup the table *//* Assume BD rings are already established */-for(i=0;i<ug_info->numQueuesRx;i++){+for(i=0;i<ucc_geth_rx_queues(ug_info);i++){out_be32(&ugeth->p_rx_bd_qs_tbl[i].externalbdbaseptr,(u32)virt_to_phys(ugeth->p_rx_bd_ring[i]));/* rest of fields handled by QE */
@@ -2702,7 +2710,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)ug_info->vlanOperationNonTagged<<REMODER_VLAN_OPERATION_NON_TAGGED_SHIFT;remoder|=ug_info->rxQoSMode<<REMODER_RX_QOS_MODE_SHIFT;-remoder|=((ug_info->numQueuesRx-1)<<REMODER_NUM_OF_QUEUES_SHIFT);+remoder|=((ucc_geth_rx_queues(ug_info)-1)<<REMODER_NUM_OF_QUEUES_SHIFT);if(ug_info->ipCheckSumCheck)remoder|=REMODER_IP_CHECKSUM_CHECK;if(ug_info->ipAddressAlignment)
@@ -2861,7 +2869,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)}/* Load Rx bds with buffers */-for(i=0;i<ug_info->numQueuesRx;i++){+for(i=0;i<ucc_geth_rx_queues(ug_info);i++){if((ret_val=rx_bd_buffer_set(ugeth,(u8)i))!=0){if(netif_msg_ifup(ugeth))pr_err("Can not fill Rx bds with buffers\n");
@@ -3132,12 +3140,12 @@ static int ucc_geth_poll(struct napi_struct *napi, int budget)/* Tx event processing */spin_lock(&ugeth->lock);-for(i=0;i<ug_info->numQueuesTx;i++)+for(i=0;i<ucc_geth_tx_queues(ug_info);i++)ucc_geth_tx(ugeth->ndev,i);spin_unlock(&ugeth->lock);howmany=0;-for(i=0;i<ug_info->numQueuesRx;i++)+for(i=0;i<ucc_geth_rx_queues(ug_info);i++)howmany+=ucc_geth_rx(ugeth,i,budget-howmany);if(howmany<budget){
The translation from the ucc_geth_num_of_threads enum value to the
actual count can be written somewhat more compactly with a small
lookup table, allowing us to replace the four switch statements.
Signed-off-by: Rasmus Villemoes <redacted>
---
drivers/net/ethernet/freescale/ucc_geth.c | 100 +++++-----------------
1 file changed, 22 insertions(+), 78 deletions(-)
@@ -668,32 +682,12 @@ static void dump_regs(struct ucc_geth_private *ugeth)in_be32(&ugeth->ug_regs->scam));if(ugeth->p_thread_data_tx){-intnumThreadsTxNumerical;-switch(ugeth->ug_info->numThreadsTx){-caseUCC_GETH_NUM_OF_THREADS_1:-numThreadsTxNumerical=1;-break;-caseUCC_GETH_NUM_OF_THREADS_2:-numThreadsTxNumerical=2;-break;-caseUCC_GETH_NUM_OF_THREADS_4:-numThreadsTxNumerical=4;-break;-caseUCC_GETH_NUM_OF_THREADS_6:-numThreadsTxNumerical=6;-break;-caseUCC_GETH_NUM_OF_THREADS_8:-numThreadsTxNumerical=8;-break;-default:-numThreadsTxNumerical=0;-break;-}+intcount=ucc_geth_thread_count(ugeth->ug_info->numThreadsTx);pr_info("Thread data TXs:\n");pr_info("Base address: 0x%08x\n",(u32)ugeth->p_thread_data_tx);-for(i=0;i<numThreadsTxNumerical;i++){+for(i=0;i<count;i++){pr_info("Thread data TX[%d]:\n",i);pr_info("Base address: 0x%08x\n",(u32)&ugeth->p_thread_data_tx[i]);
@@ -702,32 +696,12 @@ static void dump_regs(struct ucc_geth_private *ugeth)}}if(ugeth->p_thread_data_rx){-intnumThreadsRxNumerical;-switch(ugeth->ug_info->numThreadsRx){-caseUCC_GETH_NUM_OF_THREADS_1:-numThreadsRxNumerical=1;-break;-caseUCC_GETH_NUM_OF_THREADS_2:-numThreadsRxNumerical=2;-break;-caseUCC_GETH_NUM_OF_THREADS_4:-numThreadsRxNumerical=4;-break;-caseUCC_GETH_NUM_OF_THREADS_6:-numThreadsRxNumerical=6;-break;-caseUCC_GETH_NUM_OF_THREADS_8:-numThreadsRxNumerical=8;-break;-default:-numThreadsRxNumerical=0;-break;-}+intcount=ucc_geth_thread_count(ugeth->ug_info->numThreadsRx);pr_info("Thread data RX:\n");pr_info("Base address: 0x%08x\n",(u32)ugeth->p_thread_data_rx);-for(i=0;i<numThreadsRxNumerical;i++){+for(i=0;i<count;i++){pr_info("Thread data RX[%d]:\n",i);pr_info("Base address: 0x%08x\n",(u32)&ugeth->p_thread_data_rx[i]);
@@ -2315,45 +2289,15 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)uf_regs=uccf->uf_regs;ug_regs=ugeth->ug_regs;-switch(ug_info->numThreadsRx){-caseUCC_GETH_NUM_OF_THREADS_1:-numThreadsRxNumerical=1;-break;-caseUCC_GETH_NUM_OF_THREADS_2:-numThreadsRxNumerical=2;-break;-caseUCC_GETH_NUM_OF_THREADS_4:-numThreadsRxNumerical=4;-break;-caseUCC_GETH_NUM_OF_THREADS_6:-numThreadsRxNumerical=6;-break;-caseUCC_GETH_NUM_OF_THREADS_8:-numThreadsRxNumerical=8;-break;-default:+numThreadsRxNumerical=ucc_geth_thread_count(ug_info->numThreadsRx);+if(!numThreadsRxNumerical){if(netif_msg_ifup(ugeth))pr_err("Bad number of Rx threads value\n");return-EINVAL;}-switch(ug_info->numThreadsTx){-caseUCC_GETH_NUM_OF_THREADS_1:-numThreadsTxNumerical=1;-break;-caseUCC_GETH_NUM_OF_THREADS_2:-numThreadsTxNumerical=2;-break;-caseUCC_GETH_NUM_OF_THREADS_4:-numThreadsTxNumerical=4;-break;-caseUCC_GETH_NUM_OF_THREADS_6:-numThreadsTxNumerical=6;-break;-caseUCC_GETH_NUM_OF_THREADS_8:-numThreadsTxNumerical=8;-break;-default:+numThreadsTxNumerical=ucc_geth_thread_count(ug_info->numThreadsTx);+if(!numThreadsTxNumerical){if(netif_msg_ifup(ugeth))pr_err("Bad number of Tx threads value\n");return-EINVAL;
Add a helper that takes a virtual address rather than the muram
offset. This will be used in a couple of places to avoid having to
store both the offset and the virtual address, as well as removing
NULL checks from the callers.
Signed-off-by: Rasmus Villemoes <redacted>
---
drivers/soc/fsl/qe/qe_common.c | 12 ++++++++++++
include/soc/fsl/qe/qe.h | 5 +++++
2 files changed, 17 insertions(+)
struct ucc_geth_info is somewhat large, and on systems with only one
or two UCC instances, that just wastes a few KB of memory. So
allocate and populate a chunk of memory at probe time instead of
initializing them all during driver init.
Note that the existing "ug_info == NULL" check was dead code, as the
address of some static array element can obviously never be NULL.
Signed-off-by: Rasmus Villemoes <redacted>
---
drivers/net/ethernet/freescale/ucc_geth.c | 32 +++++++++--------------
1 file changed, 12 insertions(+), 20 deletions(-)
The bd_mem_part member of ucc_geth_info always has the value
MEM_PART_SYSTEM, and AFAICT, there has never been any code setting it
to any other value. Moreover, muram is a somewhat precious resource,
so there's no point using that when normal memory serves just as well.
Apart from removing a lot of dead code, this is also motivated by
wanting to clean up the "store result from kmalloc() in a u32" mess.
Signed-off-by: Rasmus Villemoes <redacted>
---
drivers/net/ethernet/freescale/ucc_geth.c | 108 ++++++----------------
include/soc/fsl/qe/qe.h | 6 --
include/soc/fsl/qe/ucc_fast.h | 1 -
3 files changed, 29 insertions(+), 86 deletions(-)
@@ -2786,14 +2742,8 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)/* Setup the table *//* Assume BD rings are already established */for(i=0;i<ug_info->numQueuesRx;i++){-if(ugeth->ug_info->uf_info.bd_mem_part==MEM_PART_SYSTEM){-out_be32(&ugeth->p_rx_bd_qs_tbl[i].externalbdbaseptr,-(u32)virt_to_phys(ugeth->p_rx_bd_ring[i]));-}elseif(ugeth->ug_info->uf_info.bd_mem_part==-MEM_PART_MURAM){-out_be32(&ugeth->p_rx_bd_qs_tbl[i].externalbdbaseptr,-(u32)qe_muram_dma(ugeth->p_rx_bd_ring[i]));-}+out_be32(&ugeth->p_rx_bd_qs_tbl[i].externalbdbaseptr,+(u32)virt_to_phys(ugeth->p_rx_bd_ring[i]));/* rest of fields handled by QE */}
These buffers have all just been handed out from qe_muram_alloc(), aka
cpm_muram_alloc(), and the helper cpm_muram_alloc_common() already
does
memset_io(cpm_muram_addr(start), 0, size);
Signed-off-by: Rasmus Villemoes <redacted>
---
drivers/net/ethernet/freescale/ucc_geth.c | 19 -------------------
1 file changed, 19 deletions(-)
@@ -2506,9 +2506,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)ugeth->p_tx_glbl_pram=(structucc_geth_tx_global_pram__iomem*)qe_muram_addr(ugeth->tx_glbl_pram_offset);-/* Zero out p_tx_glbl_pram */-memset_io((void__iomem*)ugeth->p_tx_glbl_pram,0,sizeof(structucc_geth_tx_global_pram));-/* Fill global PRAM *//* TQPTR */
@@ -2596,8 +2593,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)scheduler_offset);out_be32(&ugeth->p_tx_glbl_pram->schedulerbasepointer,ugeth->scheduler_offset);-/* Zero out p_scheduler */-memset_io((void__iomem*)ugeth->p_scheduler,0,sizeof(structucc_geth_scheduler));/* Set values in scheduler */out_be32(&ugeth->p_scheduler->mblinterval,
@@ -2640,9 +2635,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)ugeth->p_tx_fw_statistics_pram=(structucc_geth_tx_firmware_statistics_pram__iomem*)qe_muram_addr(ugeth->tx_fw_statistics_pram_offset);-/* Zero out p_tx_fw_statistics_pram */-memset_io((void__iomem*)ugeth->p_tx_fw_statistics_pram,-0,sizeof(structucc_geth_tx_firmware_statistics_pram));}/* temoder */
@@ -2675,9 +2667,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)ugeth->p_rx_glbl_pram=(structucc_geth_rx_global_pram__iomem*)qe_muram_addr(ugeth->rx_glbl_pram_offset);-/* Zero out p_rx_glbl_pram */-memset_io((void__iomem*)ugeth->p_rx_glbl_pram,0,sizeof(structucc_geth_rx_global_pram));-/* Fill global PRAM *//* RQPTR */
@@ -2715,9 +2704,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)ugeth->p_rx_fw_statistics_pram=(structucc_geth_rx_firmware_statistics_pram__iomem*)qe_muram_addr(ugeth->rx_fw_statistics_pram_offset);-/* Zero out p_rx_fw_statistics_pram */-memset_io((void__iomem*)ugeth->p_rx_fw_statistics_pram,0,-sizeof(structucc_geth_rx_firmware_statistics_pram));}/* intCoalescingPtr */
@@ -2803,11 +2789,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)(structucc_geth_rx_bd_queues_entry__iomem*)qe_muram_addr(ugeth->rx_bd_qs_tbl_offset);out_be32(&ugeth->p_rx_glbl_pram->rbdqptr,ugeth->rx_bd_qs_tbl_offset);-/* Zero out p_rx_bd_qs_tbl */-memset_io((void__iomem*)ugeth->p_rx_bd_qs_tbl,-0,-ug_info->numQueuesRx*(sizeof(structucc_geth_rx_bd_queues_entry)+-sizeof(structucc_geth_rx_prefetched_bds)));/* Setup the table *//* Assume BD rings are already established */
This removes the explicit NULL checks, and allows us to stop storing
at least some of the _offset values separately.
Signed-off-by: Rasmus Villemoes <redacted>
---
drivers/net/ethernet/freescale/ucc_geth.c | 77 ++++++++++-------------
1 file changed, 33 insertions(+), 44 deletions(-)
These macros both have the value 32, there's no point first
initializing align to a lower value.
If anything, one could throw in a
BUILD_BUG_ON(UCC_GETH_TX_BD_RING_ALIGNMENT < 4), but it's not worth it
- lots of code depends on named constants having sensible values.
Signed-off-by: Rasmus Villemoes <redacted>
---
drivers/net/ethernet/freescale/ucc_geth.c | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
Reduce the code duplication a bit by moving the parsing of
rx-clock-name and the fallback handling to a helper function.
Signed-off-by: Rasmus Villemoes <redacted>
---
drivers/net/ethernet/freescale/ucc_geth.c | 80 ++++++++++-------------
1 file changed, 36 insertions(+), 44 deletions(-)
@@ -2904,14 +2904,11 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)*allocatedresourcescanbereleasedwhenthechannelisfreed.*/if(!(ugeth->p_init_enet_param_shadow=-kmalloc(sizeof(structucc_geth_init_pram),GFP_KERNEL))){+kzalloc(sizeof(structucc_geth_init_pram),GFP_KERNEL))){if(netif_msg_ifup(ugeth))pr_err("Can not allocate memory for p_UccInitEnetParamShadows\n");return-ENOMEM;}-/* Zero out *p_init_enet_param_shadow */-memset((char*)ugeth->p_init_enet_param_shadow,-0,sizeof(structucc_geth_init_pram));/* Fill shadow InitEnet command parameter structure */
-----Original Message-----
From: Rasmus Villemoes <redacted>
Sent: Tuesday, January 19, 2021 9:08 AM
To: netdev@vger.kernel.org
Cc: Leo Li <redacted>; David S . Miller <davem@davemloft.net>;
Qiang Zhao [off-list ref]; Andrew Lunn [off-list ref];
Christophe Leroy [off-list ref]; Jakub Kicinski
[off-list ref]; jocke@infinera.com [off-list ref];
Rasmus Villemoes [off-list ref]
Subject: [PATCH net-next v2 00/17] ucc_geth improvements
This is a resend of some improvements to the ucc_geth driver that was
previously sent together with bug fixes, which have by now been applied.
Li Yang, if you don't speak up, I'm going to assume you're fine with
2,3,4 being taken through the net tree?
I'm fine with them going through the net tree.
v2: rebase to net/master; address minor style issues; don't introduce a use-
after-free in patch "don't statically allocate eight ucc_geth_info".
Rasmus Villemoes (17):
ethernet: ucc_geth: remove unused read of temoder field
soc: fsl: qe: make cpm_muram_offset take a const void* argument
soc: fsl: qe: store muram_vbase as a void pointer instead of u8
soc: fsl: qe: add cpm_muram_free_addr() helper
ethernet: ucc_geth: use qe_muram_free_addr()
ethernet: ucc_geth: remove unnecessary memset_io() calls
ethernet: ucc_geth: replace kmalloc+memset by kzalloc
ethernet: ucc_geth: remove {rx,tx}_glbl_pram_offset from struct
ucc_geth_private
ethernet: ucc_geth: factor out parsing of {rx,tx}-clock{,-name}
properties
ethernet: ucc_geth: constify ugeth_primary_info
ethernet: ucc_geth: don't statically allocate eight ucc_geth_info
ethernet: ucc_geth: use UCC_GETH_{RX,TX}_BD_RING_ALIGNMENT
macros
directly
ethernet: ucc_geth: remove bd_mem_part and all associated code
ethernet: ucc_geth: replace kmalloc_array()+for loop by kcalloc()
ethernet: ucc_geth: add helper to replace repeated switch statements
ethernet: ucc_geth: inform the compiler that numQueues is always 1
ethernet: ucc_geth: simplify rx/tx allocations
drivers/net/ethernet/freescale/ucc_geth.c | 549 ++++++++--------------
drivers/net/ethernet/freescale/ucc_geth.h | 6 -
drivers/soc/fsl/qe/qe_common.c | 20 +-
include/soc/fsl/qe/qe.h | 15 +-
include/soc/fsl/qe/ucc_fast.h | 1 -
5 files changed, 209 insertions(+), 382 deletions(-)
--
2.23.0
On Tue, Jan 19, 2021 at 9:21 AM Rasmus Villemoes
[off-list ref] wrote:
Add a helper that takes a virtual address rather than the muram
offset. This will be used in a couple of places to avoid having to
store both the offset and the virtual address, as well as removing
NULL checks from the callers.
Signed-off-by: Rasmus Villemoes <redacted>
On Tue, Jan 19, 2021 at 9:16 AM Rasmus Villemoes
[off-list ref] wrote:
The two functions cpm_muram_offset() and cpm_muram_dma() both need a
cast currently, one casts muram_vbase to do the pointer arithmetic on
void pointers, the other casts the passed-in address u8*.
It's simpler and more consistent to just always use void* and drop all
the casting.
Signed-off-by: Rasmus Villemoes <redacted>
-----Original Message-----
From: Rasmus Villemoes <redacted>
Sent: Tuesday, January 19, 2021 9:08 AM
To: netdev@vger.kernel.org
Cc: Leo Li <redacted>; David S . Miller <davem@davemloft.net>;
Qiang Zhao [off-list ref]; Andrew Lunn [off-list ref];
Christophe Leroy [off-list ref]; Jakub Kicinski
[off-list ref]; jocke@infinera.com [off-list ref];
Rasmus Villemoes [off-list ref]
Subject: [PATCH net-next v2 02/17] soc: fsl: qe: make cpm_muram_offset
take a const void* argument
Allow passing const-qualified pointers without requiring a cast in the
caller.
In theory, such a read-after-write might be required by the hardware,
but nothing in the data sheet suggests that to be the case. The name
test also suggests that it's some debug leftover.
Signed-off-by: Rasmus Villemoes <redacted>
---
drivers/net/ethernet/freescale/ucc_geth.c | 3 ---
1 file changed, 3 deletions(-)
@@ -2359,7 +2359,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)u32init_enet_pram_offset,cecr_subblock,command;u32ifstat,i,j,size,l2qt,l3qt;u16temoder=UCC_GETH_TEMODER_INIT;-u16test;u8function_code=0;u8__iomem*endOfRing;u8numThreadsRxNumerical,numThreadsTxNumerical;
@@ -2667,8 +2666,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)temoder|=((ug_info->numQueuesTx-1)<<TEMODER_NUM_OF_QUEUES_SHIFT);out_be16(&ugeth->p_tx_glbl_pram->temoder,temoder);-test=in_be16(&ugeth->p_tx_glbl_pram->temoder);-/* Function code register value to be used later */function_code=UCC_BMR_BO_BE|UCC_BMR_GBL;/* Required for QE */
These fields are only used within ucc_geth_startup(), so they might as
well be local variables in that function rather than being stashed in
struct ucc_geth_private.
Aside from making that struct a tiny bit smaller, it also shortens
some lines (getting rid of pointless casts while here), and fixes the
problems with using IS_ERR_VALUE() on a u32 as explained in commit
800cd6fb76f0 ("soc: fsl: qe: change return type of cpm_muram_alloc()
to s32").
Signed-off-by: Rasmus Villemoes <redacted>
---
drivers/net/ethernet/freescale/ucc_geth.c | 21 +++++++++------------
drivers/net/ethernet/freescale/ucc_geth.h | 2 --
2 files changed, 9 insertions(+), 14 deletions(-)
@@ -2351,6 +2351,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)u8function_code=0;u8__iomem*endOfRing;u8numThreadsRxNumerical,numThreadsTxNumerical;+s32rx_glbl_pram_offset,tx_glbl_pram_offset;ugeth_vdbg("%s: IN",__func__);uccf=ugeth->uccf;
@@ -2495,17 +2496,15 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)*//* Tx global PRAM *//* Allocate global tx parameter RAM page */-ugeth->tx_glbl_pram_offset=+tx_glbl_pram_offset=qe_muram_alloc(sizeof(structucc_geth_tx_global_pram),UCC_GETH_TX_GLOBAL_PRAM_ALIGNMENT);-if(IS_ERR_VALUE(ugeth->tx_glbl_pram_offset)){+if(tx_glbl_pram_offset<0){if(netif_msg_ifup(ugeth))pr_err("Can not allocate DPRAM memory for p_tx_glbl_pram\n");return-ENOMEM;}-ugeth->p_tx_glbl_pram=-(structucc_geth_tx_global_pram__iomem*)qe_muram_addr(ugeth->-tx_glbl_pram_offset);+ugeth->p_tx_glbl_pram=qe_muram_addr(tx_glbl_pram_offset);/* Fill global PRAM *//* TQPTR */
@@ -2656,17 +2655,15 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)/* Rx global PRAM *//* Allocate global rx parameter RAM page */-ugeth->rx_glbl_pram_offset=+rx_glbl_pram_offset=qe_muram_alloc(sizeof(structucc_geth_rx_global_pram),UCC_GETH_RX_GLOBAL_PRAM_ALIGNMENT);-if(IS_ERR_VALUE(ugeth->rx_glbl_pram_offset)){+if(rx_glbl_pram_offset<0){if(netif_msg_ifup(ugeth))pr_err("Can not allocate DPRAM memory for p_rx_glbl_pram\n");return-ENOMEM;}-ugeth->p_rx_glbl_pram=-(structucc_geth_rx_global_pram__iomem*)qe_muram_addr(ugeth->-rx_glbl_pram_offset);+ugeth->p_rx_glbl_pram=qe_muram_addr(rx_glbl_pram_offset);/* Fill global PRAM *//* RQPTR */
@@ -2928,7 +2925,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)((u32)ug_info->numThreadsTx)<<ENET_INIT_PARAM_TGF_SHIFT;ugeth->p_init_enet_param_shadow->rgftgfrxglobal|=-ugeth->rx_glbl_pram_offset|ug_info->riscRx;+rx_glbl_pram_offset|ug_info->riscRx;if((ug_info->largestexternallookupkeysize!=QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_NONE)&&(ug_info->largestexternallookupkeysize!=
@@ -2966,7 +2963,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)}ugeth->p_init_enet_param_shadow->txglobal=-ugeth->tx_glbl_pram_offset|ug_info->riscTx;+tx_glbl_pram_offset|ug_info->riscTx;if((ret_val=fill_init_enet_entries(ugeth,&(ugeth->p_init_enet_param_shadow->
These fields are only used within ucc_geth_startup(), so they might as
well be local variables in that function rather than being stashed in
struct ucc_geth_private.
Aside from making that struct a tiny bit smaller, it also shortens
some lines (getting rid of pointless casts while here), and fixes the
problems with using IS_ERR_VALUE() on a u32 as explained in commit
800cd6fb76f0 ("soc: fsl: qe: change return type of cpm_muram_alloc()
to s32").
Signed-off-by: Rasmus Villemoes <redacted>
---
drivers/net/ethernet/freescale/ucc_geth.c | 21 +++++++++------------
drivers/net/ethernet/freescale/ucc_geth.h | 2 --
2 files changed, 9 insertions(+), 14 deletions(-)
@@ -2351,6 +2351,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)u8function_code=0;u8__iomem*endOfRing;u8numThreadsRxNumerical,numThreadsTxNumerical;+s32rx_glbl_pram_offset,tx_glbl_pram_offset;
That's still a quite long name for a local variable. Kernel Codying Style says:
LOCAL variable names should be short, and to the point. If you have some random integer loop
counter, it should probably be called i. Calling it loop_counter is non-productive, if there is no
chance of it being mis-understood. Similarly, tmp can be just about any type of variable that is
used to hold a temporary value.
If you are afraid to mix up your local variable names, you have another problem, which is called the
function-growth-hormone-imbalance syndrome. See chapter 6 (Functions).
struct ucc_geth_info is somewhat large, and on systems with only one
or two UCC instances, that just wastes a few KB of memory. So
allocate and populate a chunk of memory at probe time instead of
initializing them all during driver init.
Note that the existing "ug_info == NULL" check was dead code, as the
address of some static array element can obviously never be NULL.
Signed-off-by: Rasmus Villemoes <redacted>
---
drivers/net/ethernet/freescale/ucc_geth.c | 32 +++++++++--------------
1 file changed, 12 insertions(+), 20 deletions(-)
The bd_mem_part member of ucc_geth_info always has the value
MEM_PART_SYSTEM, and AFAICT, there has never been any code setting it
to any other value. Moreover, muram is a somewhat precious resource,
so there's no point using that when normal memory serves just as well.
Apart from removing a lot of dead code, this is also motivated by
wanting to clean up the "store result from kmalloc() in a u32" mess.
Signed-off-by: Rasmus Villemoes <redacted>
---
drivers/net/ethernet/freescale/ucc_geth.c | 108 ++++++----------------
include/soc/fsl/qe/qe.h | 6 --
include/soc/fsl/qe/ucc_fast.h | 1 -
3 files changed, 29 insertions(+), 86 deletions(-)
Can you detail a bit the change ?
At least tell that the loop was a zeroising loop and that kcalloc() already zeroises the allocated
memory ?
Le 19/01/2021 à 16:07, Rasmus Villemoes a écrit :
What about using devm_kmalloc() and avoid those kfree and associated goto ?
I already replied to that: I'd rather not mix kmalloc() and
devm_kmalloc() as that makes it much harder to reason about the order in
which stuff gets deallocated. But sure, if you insist.
Rasmus
These fields are only used within ucc_geth_startup(), so they might as
well be local variables in that function rather than being stashed in
struct ucc_geth_private.
Aside from making that struct a tiny bit smaller, it also shortens
some lines (getting rid of pointless casts while here), and fixes the
problems with using IS_ERR_VALUE() on a u32 as explained in commit
800cd6fb76f0 ("soc: fsl: qe: change return type of cpm_muram_alloc()
to s32").
Signed-off-by: Rasmus Villemoes <redacted>
---
drivers/net/ethernet/freescale/ucc_geth.c | 21 +++++++++------------
drivers/net/ethernet/freescale/ucc_geth.h | 2 --
2 files changed, 9 insertions(+), 14 deletions(-)
That's still a quite long name for a local variable.
True, but I wanted to keep this mechanical and easy to verify. If
somebody wants to clean up the local variable names
(numThreads[RT]xNumerical also stand out), that can be done later.
Rasmus
The bd_mem_part member of ucc_geth_info always has the value
MEM_PART_SYSTEM, and AFAICT, there has never been any code setting it
to any other value. Moreover, muram is a somewhat precious resource,
so there's no point using that when normal memory serves just as well.
Apart from removing a lot of dead code, this is also motivated by
wanting to clean up the "store result from kmalloc() in a u32" mess.
@@ -2195,25 +2179,15 @@ static int ucc_geth_alloc_tx(struct
This is all deliberate: Verifying that this patch merely removes the
dead branch (and thus outdenting the always-taken branch) is easily done
by using "git show -w". That shows hunks like
@@ -2554,20 +2519,11 @@ static int ucc_geth_startup(struct
ucc_geth_private *ugeth)
endOfRing =
ugeth->p_tx_bd_ring[i] + (ug_info->bdRingLenTx[i] -
1) * sizeof(struct qe_bd);
- if (ugeth->ug_info->uf_info.bd_mem_part ==
MEM_PART_SYSTEM) {
out_be32(&ugeth->p_send_q_mem_reg->sqqd[i].bd_ring_base,
(u32) virt_to_phys(ugeth->p_tx_bd_ring[i]));
out_be32(&ugeth->p_send_q_mem_reg->sqqd[i].
last_bd_completed_address,
(u32) virt_to_phys(endOfRing));
- } else if (ugeth->ug_info->uf_info.bd_mem_part ==
- MEM_PART_MURAM) {
-
out_be32(&ugeth->p_send_q_mem_reg->sqqd[i].bd_ring_base,
- (u32)qe_muram_dma(ugeth->p_tx_bd_ring[i]));
- out_be32(&ugeth->p_send_q_mem_reg->sqqd[i].
- last_bd_completed_address,
- (u32)qe_muram_dma(endOfRing));
- }
}
So I didn't want to rewrap any of the lines.
Rasmus
What about using devm_kmalloc() and avoid those kfree and associated goto ?
I already replied to that: I'd rather not mix kmalloc() and
devm_kmalloc() as that makes it much harder to reason about the order in
which stuff gets deallocated. But sure, if you insist.
I didn't remember I already did the same comment, sorry.
Christophe
Hello:
This series was applied to netdev/net-next.git (refs/heads/master):
On Tue, 19 Jan 2021 16:07:45 +0100 you wrote:
This is a resend of some improvements to the ucc_geth driver that was
previously sent together with bug fixes, which have by now been
applied.
Li Yang, if you don't speak up, I'm going to assume you're fine with
2,3,4 being taken through the net tree?
[...]