[PATCH v5 12/14] net: pch_gbe: Fix TX RX descriptor accesses for big endian systems
From: Hassan Naveed Fix pch_gbe driver for ethernet operations for a big endian CPU. Values written to and read from transmit and receive descriptors in the pch_gbe driver are byte swapped from the perspective of a big endian CPU, since the ethernet controller always operates in little endian mode. Rectify this by appropriately byte swapping these descriptor field values in the driver software. Signed-off-by: Hassan Naveed Signed-off-by: Paul Burton Reviewed-by: Paul Burton Reviewed-by: Matt Redfearn Cc: David S. Miller Cc: linux-m...@linux-mips.org Cc: netdev@vger.kernel.org --- Changes in v5: - Newly included in this series. Changes in v4: None Changes in v3: None Changes in v2: - Use __le{16,32} for field types, checked with sparse. drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe.h| 22 .../net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c | 66 -- 2 files changed, 46 insertions(+), 42 deletions(-) diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe.h b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe.h index 8ba9ced2d1fd..7159e39b4685 100644 --- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe.h +++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe.h @@ -431,13 +431,13 @@ struct pch_gbe_hw { * @reserved2: Reserved */ struct pch_gbe_rx_desc { - u32 buffer_addr; - u32 tcp_ip_status; - u16 rx_words_eob; - u16 gbec_status; + __le32 buffer_addr; + __le32 tcp_ip_status; + __le16 rx_words_eob; + __le16 gbec_status; u8 dma_status; u8 reserved1; - u16 reserved2; + __le16 reserved2; }; /** @@ -452,14 +452,14 @@ struct pch_gbe_rx_desc { * @gbec_status: GMAC Status */ struct pch_gbe_tx_desc { - u32 buffer_addr; - u16 length; - u16 reserved1; - u16 tx_words_eob; - u16 tx_frame_ctrl; + __le32 buffer_addr; + __le16 length; + __le16 reserved1; + __le16 tx_words_eob; + __le16 tx_frame_ctrl; u8 dma_status; u8 reserved2; - u16 gbec_status; + __le16 gbec_status; }; diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c index 8e3ad7dcef0b..a0b8c8f4b4c9 100644 --- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c +++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c @@ -1254,11 +1254,11 @@ static void pch_gbe_tx_queue(struct pch_gbe_adapter *adapter, /*-- Set Tx descriptor --*/ tx_desc = PCH_GBE_TX_DESC(*tx_ring, ring_num); - tx_desc->buffer_addr = (buffer_info->dma); - tx_desc->length = (skb->len); - tx_desc->tx_words_eob = ((skb->len + 3)); - tx_desc->tx_frame_ctrl = (frame_ctrl); - tx_desc->gbec_status = (DSC_INIT16); + tx_desc->buffer_addr = cpu_to_le32(buffer_info->dma); + tx_desc->length = cpu_to_le16(skb->len); + tx_desc->tx_words_eob = cpu_to_le16(skb->len + 3); + tx_desc->tx_frame_ctrl = cpu_to_le16(frame_ctrl); + tx_desc->gbec_status = cpu_to_le16(DSC_INIT16); /* Ensure writes to descriptors complete before DMA begins */ mmiowb(); @@ -1447,8 +1447,8 @@ pch_gbe_alloc_rx_buffers(struct pch_gbe_adapter *adapter, } buffer_info->mapped = true; rx_desc = PCH_GBE_RX_DESC(*rx_ring, i); - rx_desc->buffer_addr = (buffer_info->dma); - rx_desc->gbec_status = DSC_INIT16; + rx_desc->buffer_addr = cpu_to_le32(buffer_info->dma); + rx_desc->gbec_status = cpu_to_le16(DSC_INIT16); netdev_dbg(netdev, "i = %d buffer_info->dma = 0x08%llx buffer_info->length = 0x%x\n", @@ -1520,7 +1520,7 @@ static void pch_gbe_alloc_tx_buffers(struct pch_gbe_adapter *adapter, skb_reserve(skb, PCH_GBE_DMA_ALIGN); buffer_info->skb = skb; tx_desc = PCH_GBE_TX_DESC(*tx_ring, i); - tx_desc->gbec_status = (DSC_INIT16); + tx_desc->gbec_status = cpu_to_le16(DSC_INIT16); } return; } @@ -1551,11 +1551,12 @@ pch_gbe_clean_tx(struct pch_gbe_adapter *adapter, i = tx_ring->next_to_clean; tx_desc = PCH_GBE_TX_DESC(*tx_ring, i); netdev_dbg(adapter->netdev, "gbec_status:0x%04x dma_status:0x%04x\n", - tx_desc->gbec_status, tx_desc->dma_status); + le16_to_cpu(tx_desc->gbec_status), tx_desc->dma_status); unused = PCH_GBE_DESC_UNUSED(tx_ring); thresh = tx_ring->count - PCH_GBE_TX_WEIGHT; - if ((tx_desc->gbec_status == DSC_INIT16) && (unused < thresh)) + if ((le16_to_cpu(tx_desc->gbec_status) == DSC_INIT16) && + (unused < thresh)) { /* current marked clean, tx queue filling up, do extra clean */ int j, k; if (unused < 8) { /* tx queue nearly full */ @@ -1570,47 +1571,49 @@ pch_gbe_clean_t
Re: [PATCH v5 12/14] net: pch_gbe: Fix TX RX descriptor accesses for big endian systems
Hi Hassan, Thank you for the patch! Perhaps something to improve: [auto build test WARNING on net-next/master] [also build test WARNING on v4.16-rc1 next-20180216] [if your patch is applied to the wrong git tree, please drop us a note to help improve the system] url: https://github.com/0day-ci/linux/commits/Paul-Burton/net-pch_gbe-Fixes-MIPS-support/20180218-213023 reproduce: # apt-get install sparse make ARCH=x86_64 allmodconfig make C=1 CF=-D__CHECK_ENDIAN__ sparse warnings: (new ones prefixed by >>) drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c:177:33: sparse: incorrect type in argument 2 (different base types) @@ expected unsigned short uid_hi @@ got short uid_hi @@ drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c:177:33: expected unsigned short uid_hi drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c:177:33: got restricted __be16 drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c:177:45: sparse: incorrect type in argument 3 (different base types) @@ expected unsigned int uid_lo @@ got ed int uid_lo @@ drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c:177:45: expected unsigned int uid_lo drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c:177:45: got restricted __be32 drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c:177:56: sparse: incorrect type in argument 4 (different base types) @@ expected unsigned short seqid @@ got short seqid @@ drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c:177:56: expected unsigned short seqid drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c:177:56: got restricted __be16 drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c:325:15: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile @@ got @@ drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c:325:15: expected void const volatile drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c:325:15: got void drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c:325:15: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const volatile @@ got @@ drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c:325:15: expected void const volatile drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c:325:15: got void drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c:354:33: sparse: incorrect type in argument 1 (different address spaces) @@ expected void @@ got unsigned int > drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c:1587:17: sparse: cast >> from restricted __le16 >> drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c:1587:17: sparse: >> restricted __le16 degrades to integer vim +1587 drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c 1527 1528 /** 1529 * pch_gbe_clean_tx - Reclaim resources after transmit completes 1530 * @adapter: Board private structure 1531 * @tx_ring: Tx descriptor ring 1532 * Returns: 1533 * true: Cleaned the descriptor 1534 * false: Not cleaned the descriptor 1535 */ 1536 static bool 1537 pch_gbe_clean_tx(struct pch_gbe_adapter *adapter, 1538 struct pch_gbe_tx_ring *tx_ring) 1539 { 1540 struct pch_gbe_tx_desc *tx_desc; 1541 struct pch_gbe_buffer *buffer_info; 1542 struct sk_buff *skb; 1543 unsigned int i; 1544 unsigned int cleaned_count = 0; 1545 bool cleaned = false; 1546 int unused, thresh; 1547 1548 netdev_dbg(adapter->netdev, "next_to_clean : %d\n", 1549 tx_ring->next_to_clean); 1550 1551 i = tx_ring->next_to_clean; 1552 tx_desc = PCH_GBE_TX_DESC(*tx_ring, i); 1553 netdev_dbg(adapter->netdev, "gbec_status:0x%04x dma_status:0x%04x\n", 1554 le16_to_cpu(tx_desc->gbec_status), tx_desc->dma_status); 1555 1556 unused = PCH_GBE_DESC_UNUSED(tx_ring); 1557 thresh = tx_ring->count - PCH_GBE_TX_WEIGHT; 1558 if ((le16_to_cpu(tx_desc->gbec_status) == DSC_INIT16) && 1559 (unused < thresh)) 1560 { /* current marked clean, tx queue filling up, do extra clean */ 1561 int j, k; 1562 if (unused < 8) { /* tx queue nearly full */ 1563 netdev_dbg(adapter->netdev, 1564 "clean_tx: transmit queue warning (%x,%x) unused=%d\n", 1565 tx_ring->next_to_clean, tx_ring->next_to_use, 1566 unused); 1567 } 1568 1569 /* current marked clean, scan for more that need cleaning. */ 1570 k = i; 1571 for (j = 0; j < PCH_GBE_TX_WEIGHT; j++) 1572 { 1573 tx_desc = PCH_GBE_TX_DESC(*tx_ring, k); 1574