@ -565,40 +565,82 @@ static inline u32 fe_empty_txd(struct fe_tx_ring *ring)
( ring - > tx_ring_size - 1 ) ) ) ;
}
static int fe_tx_dma_map_page ( struct device * dev , struct fe_tx_buf * tx_buf ,
struct fe_tx_dma * txd , int idx ,
struct page * page , size_t offset , size_t size )
struct fe_map_state {
struct device * dev ;
struct fe_tx_dma txd ;
u32 def_txd4 ;
int ring_idx ;
int i ;
} ;
static void fe_tx_dma_write_desc ( struct fe_tx_ring * ring , struct fe_map_state * st )
{
fe_set_txd ( & st - > txd , & ring - > tx_dma [ st - > ring_idx ] ) ;
memset ( & st - > txd , 0 , sizeof ( st - > txd ) ) ;
st - > txd . txd4 = st - > def_txd4 ;
st - > ring_idx = NEXT_TX_DESP_IDX ( st - > ring_idx ) ;
}
static int __fe_tx_dma_map_page ( struct fe_tx_ring * ring , struct fe_map_state * st ,
struct page * page , size_t offset , size_t size )
{
struct device * dev = st - > dev ;
struct fe_tx_buf * tx_buf ;
dma_addr_t mapped_addr ;
mapped_addr = dma_map_page ( dev , page , offset , size , DMA_TO_DEVICE ) ;
if ( unlikely ( dma_mapping_error ( dev , mapped_addr ) ) )
return - EIO ;
if ( idx & 1 ) {
txd - > txd3 = mapped_addr ;
txd - > txd2 | = TX_DMA_PLEN1 ( size ) ;
if ( st - > i & & ! ( st - > i & 1 ) )
fe_tx_dma_write_desc ( ring , st ) ;
tx_buf = & ring - > tx_buf [ st - > ring_idx ] ;
if ( st - > i & 1 ) {
st - > txd . txd3 = mapped_addr ;
st - > txd . txd2 | = TX_DMA_PLEN1 ( size ) ;
dma_unmap_addr_set ( tx_buf , dma_addr1 , mapped_addr ) ;
dma_unmap_len_set ( tx_buf , dma_len1 , size ) ;
} else {
tx_buf - > skb = ( struct sk_buff * ) DMA_DUMMY_DESC ;
txd - > txd1 = mapped_addr ;
txd - > txd2 = TX_DMA_PLEN0 ( size ) ;
s t- > txd . txd1 = mapped_addr ;
s t- > txd . txd2 = TX_DMA_PLEN0 ( size ) ;
dma_unmap_addr_set ( tx_buf , dma_addr0 , mapped_addr ) ;
dma_unmap_len_set ( tx_buf , dma_len0 , size ) ;
}
st - > i + + ;
return 0 ;
}
static int fe_tx_dma_map_skb ( struct device * dev , struct fe_tx_buf * tx_buf ,
struct fe_tx_dma * txd , int idx ,
static int fe_tx_dma_map_page ( struct fe_tx_ring * ring , struct fe_map_state * st ,
struct page * page , size_t offset , size_t size )
{
int cur_size ;
int ret ;
while ( size > 0 ) {
cur_size = min_t ( size_t , size , TX_DMA_BUF_LEN ) ;
ret = __fe_tx_dma_map_page ( ring , st , page , offset , cur_size ) ;
if ( ret )
return ret ;
size - = cur_size ;
offset + = cur_size ;
}
return 0 ;
}
static int fe_tx_dma_map_skb ( struct fe_tx_ring * ring , struct fe_map_state * st ,
struct sk_buff * skb )
{
struct page * page = virt_to_page ( skb - > data ) ;
size_t offset = offset_in_page ( skb - > data ) ;
size_t size = skb_headlen ( skb ) ;
return fe_tx_dma_map_page ( dev , tx_buf , txd , idx , page , offset , size ) ;
return fe_tx_dma_map_page ( ring , st , page , offset , size ) ;
}
static inline struct sk_buff *
@ -613,41 +655,39 @@ fe_next_frag(struct sk_buff *head, struct sk_buff *skb)
return NULL ;
}
static int fe_tx_map_dma ( struct sk_buff * skb , struct net_device * dev ,
int tx_num , struct fe_tx_ring * ring )
{
struct fe_priv * priv = netdev_priv ( dev ) ;
struct skb_frag_struct * frag ;
struct fe_tx_dma txd , * ptxd ;
struct fe_tx_buf * tx_buf ;
struct fe_map_state st = {
. dev = & dev - > dev ,
. ring_idx = ring - > tx_next_idx ,
} ;
struct sk_buff * head = skb ;
struct fe_tx_buf * tx_buf ;
unsigned int nr_frags ;
u32 def_txd4 ;
int i , j , k , frag_size , frag_map_size , offset ;
tx_buf = & ring - > tx_buf [ ring - > tx_next_idx ] ;
memset ( tx_buf , 0 , sizeof ( * tx_buf ) ) ;
memset ( & txd , 0 , sizeof ( txd ) ) ;
int i , j ;
/* init tx descriptor */
if ( priv - > soc - > tx_dma )
priv - > soc - > tx_dma ( & txd ) ;
priv - > soc - > tx_dma ( & st . txd ) ;
else
txd . txd4 = TX_DMA_DESP4_DEF ;
def_txd4 = txd . txd4 ;
st . txd . txd4 = TX_DMA_DESP4_DEF ;
st . def_txd4 = st . txd . txd4 ;
/* TX Checksum offload */
if ( skb - > ip_summed = = CHECKSUM_PARTIAL )
txd . txd4 | = TX_DMA_CHKSUM ;
st . txd . txd4 | = TX_DMA_CHKSUM ;
/* VLAN header offload */
if ( skb_vlan_tag_present ( skb ) ) {
u16 tag = skb_vlan_tag_get ( skb ) ;
if ( IS_ENABLED ( CONFIG_SOC_MT7621 ) )
txd . txd4 | = TX_DMA_INS_VLAN_MT7621 | tag ;
st . txd . txd4 | = TX_DMA_INS_VLAN_MT7621 | tag ;
else
txd . txd4 | = TX_DMA_INS_VLAN |
st . txd . txd4 | = TX_DMA_INS_VLAN |
( ( tag > > VLAN_PRIO_SHIFT ) < < 4 ) |
( tag & 0xF ) ;
}
@ -661,75 +701,46 @@ static int fe_tx_map_dma(struct sk_buff *skb, struct net_device *dev,
}
if ( skb_shinfo ( skb ) - > gso_type &
( SKB_GSO_TCPV4 | SKB_GSO_TCPV6 ) ) {
txd . txd4 | = TX_DMA_TSO ;
st . txd . txd4 | = TX_DMA_TSO ;
tcp_hdr ( skb ) - > check = htons ( skb_shinfo ( skb ) - > gso_size ) ;
}
}
k = 0 ;
j = ring - > tx_next_idx ;
next_frag :
if ( skb_headlen ( skb ) ) {
if ( fe_tx_dma_map_skb ( & dev - > dev , tx_buf , & txd , k + + , skb ) )
goto err_dma ;
}
if ( skb_headlen ( skb ) & & fe_tx_dma_map_skb ( ring , & st , skb ) )
goto err_dma ;
/* TX SG offload */
nr_frags = skb_shinfo ( skb ) - > nr_frags ;
for ( i = 0 ; i < nr_frags ; i + + ) {
struct page * page ;
struct skb_frag_struct * frag ;
frag = & skb_shinfo ( skb ) - > frags [ i ] ;
frag_size = skb_frag_size ( frag ) ;
offset = frag - > page_offset ;
page = skb_frag_page ( frag ) ;
while ( frag_size > 0 ) {
frag_map_size = min ( frag_size , TX_DMA_BUF_LEN ) ;
if ( ! ( k & 0x1 ) ) {
fe_set_txd ( & txd , & ring - > tx_dma [ j ] ) ;
memset ( & txd , 0 , sizeof ( txd ) ) ;
txd . txd4 = def_txd4 ;
j = NEXT_TX_DESP_IDX ( j ) ;
tx_buf = & ring - > tx_buf [ j ] ;
}
if ( fe_tx_dma_map_page ( & dev - > dev , tx_buf , & txd , k + + ,
page , offset , frag_map_size ) )
goto err_dma ;
frag_size - = frag_map_size ;
offset + = frag_map_size ;
}
if ( fe_tx_dma_map_page ( ring , & st , skb_frag_page ( frag ) ,
frag - > page_offset , skb_frag_size ( frag ) ) )
goto err_dma ;
}
skb = fe_next_frag ( head , skb ) ;
if ( skb ) {
if ( ! ( k & 0x1 ) ) {
fe_set_txd ( & txd , & ring - > tx_dma [ j ] ) ;
memset ( & txd , 0 , sizeof ( txd ) ) ;
txd . txd4 = def_txd4 ;
j = NEXT_TX_DESP_IDX ( j ) ;
tx_buf = & ring - > tx_buf [ j ] ;
}
if ( skb )
goto next_frag ;
}
/* set last segment */
if ( k & 0x1 )
txd . txd2 | = TX_DMA_LS0 ;
if ( st . i & 0x1 )
st . txd . txd2 | = TX_DMA_LS0 ;
else
txd . txd2 | = TX_DMA_LS1 ;
fe_set_txd ( & txd , & ring - > tx_dma [ j ] ) ;
st . txd . txd2 | = TX_DMA_LS1 ;
/* store skb to cleanup */
tx_buf = & ring - > tx_buf [ st . ring_idx ] ;
tx_buf - > skb = head ;
netdev_sent_queue ( dev , head - > len ) ;
skb_tx_timestamp ( head ) ;
ring - > tx_next_idx = NEXT_TX_DESP_IDX ( j ) ;
fe_tx_dma_write_desc ( ring , & st ) ;
ring - > tx_next_idx = st . ring_idx ;
/* make sure that all changes to the dma ring are flushed before we
* continue
*/
@ -749,13 +760,10 @@ next_frag:
err_dma :
j = ring - > tx_next_idx ;
for ( i = 0 ; i < tx_num ; i + + ) {
ptxd = & ring - > tx_dma [ j ] ;
tx_buf = & ring - > tx_buf [ j ] ;
/* unmap dma */
fe_txd_unmap ( & dev - > dev , tx_buf ) ;
fe_txd_unmap ( & dev - > dev , & ring - > tx_buf [ j ] ) ;
ring - > tx_dma [ j ] . txd2 = TX_DMA_DESP2_DEF ;
ptxd - > txd2 = TX_DMA_DESP2_DEF ;
j = NEXT_TX_DESP_IDX ( j ) ;
}
/* make sure that all changes to the dma ring are flushed before we