Commit dfe76a36 authored by David S. Miller's avatar David S. Miller

Merge branch 'mvpp2-Add-big-endian-support'

Maxime Chevallier says:

====================
net: mvpp2: Add big-endian support

This series allows to use PPv2 on system built as big endian.

The first patch fixes the way we represent TX and RX descriptors, so that
they used fixed little endianness as expected by the PPv2 controller.

The second reworks the way we handle the software representation of the
Header Parser entries, so that we don't use a union of arrays.

The last two patches fixes some incorrect byte swapping logic, that wen't
un-noticed on little-endian.

This whole series doesn't fix any existing bug for little-endian systems, and
since big-endian never worked for this driver, I didn't include 'fixes' tags.

This was tested on MacchiatoBin (Armada 8040).
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents ea5d0c32 dc734dbe
...@@ -553,6 +553,8 @@ ...@@ -553,6 +553,8 @@
((total_size) - NET_SKB_PAD - MVPP2_SKB_SHINFO_SIZE) ((total_size) - NET_SKB_PAD - MVPP2_SKB_SHINFO_SIZE)
#define MVPP2_BIT_TO_BYTE(bit) ((bit) / 8) #define MVPP2_BIT_TO_BYTE(bit) ((bit) / 8)
#define MVPP2_BIT_TO_WORD(bit) ((bit) / 32)
#define MVPP2_BIT_IN_WORD(bit) ((bit) % 32)
/* IPv6 max L3 address size */ /* IPv6 max L3 address size */
#define MVPP2_MAX_L3_ADDR_SIZE 16 #define MVPP2_MAX_L3_ADDR_SIZE 16
...@@ -831,52 +833,52 @@ struct mvpp2_port { ...@@ -831,52 +833,52 @@ struct mvpp2_port {
/* HW TX descriptor for PPv2.1 */ /* HW TX descriptor for PPv2.1 */
struct mvpp21_tx_desc { struct mvpp21_tx_desc {
u32 command; /* Options used by HW for packet transmitting.*/ __le32 command; /* Options used by HW for packet transmitting.*/
u8 packet_offset; /* the offset from the buffer beginning */ u8 packet_offset; /* the offset from the buffer beginning */
u8 phys_txq; /* destination queue ID */ u8 phys_txq; /* destination queue ID */
u16 data_size; /* data size of transmitted packet in bytes */ __le16 data_size; /* data size of transmitted packet in bytes */
u32 buf_dma_addr; /* physical addr of transmitted buffer */ __le32 buf_dma_addr; /* physical addr of transmitted buffer */
u32 buf_cookie; /* cookie for access to TX buffer in tx path */ __le32 buf_cookie; /* cookie for access to TX buffer in tx path */
u32 reserved1[3]; /* hw_cmd (for future use, BM, PON, PNC) */ __le32 reserved1[3]; /* hw_cmd (for future use, BM, PON, PNC) */
u32 reserved2; /* reserved (for future use) */ __le32 reserved2; /* reserved (for future use) */
}; };
/* HW RX descriptor for PPv2.1 */ /* HW RX descriptor for PPv2.1 */
struct mvpp21_rx_desc { struct mvpp21_rx_desc {
u32 status; /* info about received packet */ __le32 status; /* info about received packet */
u16 reserved1; /* parser_info (for future use, PnC) */ __le16 reserved1; /* parser_info (for future use, PnC) */
u16 data_size; /* size of received packet in bytes */ __le16 data_size; /* size of received packet in bytes */
u32 buf_dma_addr; /* physical address of the buffer */ __le32 buf_dma_addr; /* physical address of the buffer */
u32 buf_cookie; /* cookie for access to RX buffer in rx path */ __le32 buf_cookie; /* cookie for access to RX buffer in rx path */
u16 reserved2; /* gem_port_id (for future use, PON) */ __le16 reserved2; /* gem_port_id (for future use, PON) */
u16 reserved3; /* csum_l4 (for future use, PnC) */ __le16 reserved3; /* csum_l4 (for future use, PnC) */
u8 reserved4; /* bm_qset (for future use, BM) */ u8 reserved4; /* bm_qset (for future use, BM) */
u8 reserved5; u8 reserved5;
u16 reserved6; /* classify_info (for future use, PnC) */ __le16 reserved6; /* classify_info (for future use, PnC) */
u32 reserved7; /* flow_id (for future use, PnC) */ __le32 reserved7; /* flow_id (for future use, PnC) */
u32 reserved8; __le32 reserved8;
}; };
/* HW TX descriptor for PPv2.2 */ /* HW TX descriptor for PPv2.2 */
struct mvpp22_tx_desc { struct mvpp22_tx_desc {
u32 command; __le32 command;
u8 packet_offset; u8 packet_offset;
u8 phys_txq; u8 phys_txq;
u16 data_size; __le16 data_size;
u64 reserved1; __le64 reserved1;
u64 buf_dma_addr_ptp; __le64 buf_dma_addr_ptp;
u64 buf_cookie_misc; __le64 buf_cookie_misc;
}; };
/* HW RX descriptor for PPv2.2 */ /* HW RX descriptor for PPv2.2 */
struct mvpp22_rx_desc { struct mvpp22_rx_desc {
u32 status; __le32 status;
u16 reserved1; __le16 reserved1;
u16 data_size; __le16 data_size;
u32 reserved2; __le32 reserved2;
u32 reserved3; __le32 reserved3;
u64 buf_dma_addr_key_hash; __le64 buf_dma_addr_key_hash;
u64 buf_cookie_misc; __le64 buf_cookie_misc;
}; };
/* Opaque type used by the driver to manipulate the HW TX and RX /* Opaque type used by the driver to manipulate the HW TX and RX
......
...@@ -151,9 +151,10 @@ static dma_addr_t mvpp2_txdesc_dma_addr_get(struct mvpp2_port *port, ...@@ -151,9 +151,10 @@ static dma_addr_t mvpp2_txdesc_dma_addr_get(struct mvpp2_port *port,
struct mvpp2_tx_desc *tx_desc) struct mvpp2_tx_desc *tx_desc)
{ {
if (port->priv->hw_version == MVPP21) if (port->priv->hw_version == MVPP21)
return tx_desc->pp21.buf_dma_addr; return le32_to_cpu(tx_desc->pp21.buf_dma_addr);
else else
return tx_desc->pp22.buf_dma_addr_ptp & MVPP2_DESC_DMA_MASK; return le64_to_cpu(tx_desc->pp22.buf_dma_addr_ptp) &
MVPP2_DESC_DMA_MASK;
} }
static void mvpp2_txdesc_dma_addr_set(struct mvpp2_port *port, static void mvpp2_txdesc_dma_addr_set(struct mvpp2_port *port,
...@@ -166,12 +167,12 @@ static void mvpp2_txdesc_dma_addr_set(struct mvpp2_port *port, ...@@ -166,12 +167,12 @@ static void mvpp2_txdesc_dma_addr_set(struct mvpp2_port *port,
offset = dma_addr & MVPP2_TX_DESC_ALIGN; offset = dma_addr & MVPP2_TX_DESC_ALIGN;
if (port->priv->hw_version == MVPP21) { if (port->priv->hw_version == MVPP21) {
tx_desc->pp21.buf_dma_addr = addr; tx_desc->pp21.buf_dma_addr = cpu_to_le32(addr);
tx_desc->pp21.packet_offset = offset; tx_desc->pp21.packet_offset = offset;
} else { } else {
u64 val = (u64)addr; __le64 val = cpu_to_le64(addr);
tx_desc->pp22.buf_dma_addr_ptp &= ~MVPP2_DESC_DMA_MASK; tx_desc->pp22.buf_dma_addr_ptp &= ~cpu_to_le64(MVPP2_DESC_DMA_MASK);
tx_desc->pp22.buf_dma_addr_ptp |= val; tx_desc->pp22.buf_dma_addr_ptp |= val;
tx_desc->pp22.packet_offset = offset; tx_desc->pp22.packet_offset = offset;
} }
...@@ -181,9 +182,9 @@ static size_t mvpp2_txdesc_size_get(struct mvpp2_port *port, ...@@ -181,9 +182,9 @@ static size_t mvpp2_txdesc_size_get(struct mvpp2_port *port,
struct mvpp2_tx_desc *tx_desc) struct mvpp2_tx_desc *tx_desc)
{ {
if (port->priv->hw_version == MVPP21) if (port->priv->hw_version == MVPP21)
return tx_desc->pp21.data_size; return le16_to_cpu(tx_desc->pp21.data_size);
else else
return tx_desc->pp22.data_size; return le16_to_cpu(tx_desc->pp22.data_size);
} }
static void mvpp2_txdesc_size_set(struct mvpp2_port *port, static void mvpp2_txdesc_size_set(struct mvpp2_port *port,
...@@ -191,9 +192,9 @@ static void mvpp2_txdesc_size_set(struct mvpp2_port *port, ...@@ -191,9 +192,9 @@ static void mvpp2_txdesc_size_set(struct mvpp2_port *port,
size_t size) size_t size)
{ {
if (port->priv->hw_version == MVPP21) if (port->priv->hw_version == MVPP21)
tx_desc->pp21.data_size = size; tx_desc->pp21.data_size = cpu_to_le16(size);
else else
tx_desc->pp22.data_size = size; tx_desc->pp22.data_size = cpu_to_le16(size);
} }
static void mvpp2_txdesc_txq_set(struct mvpp2_port *port, static void mvpp2_txdesc_txq_set(struct mvpp2_port *port,
...@@ -211,9 +212,9 @@ static void mvpp2_txdesc_cmd_set(struct mvpp2_port *port, ...@@ -211,9 +212,9 @@ static void mvpp2_txdesc_cmd_set(struct mvpp2_port *port,
unsigned int command) unsigned int command)
{ {
if (port->priv->hw_version == MVPP21) if (port->priv->hw_version == MVPP21)
tx_desc->pp21.command = command; tx_desc->pp21.command = cpu_to_le32(command);
else else
tx_desc->pp22.command = command; tx_desc->pp22.command = cpu_to_le32(command);
} }
static unsigned int mvpp2_txdesc_offset_get(struct mvpp2_port *port, static unsigned int mvpp2_txdesc_offset_get(struct mvpp2_port *port,
...@@ -229,36 +230,38 @@ static dma_addr_t mvpp2_rxdesc_dma_addr_get(struct mvpp2_port *port, ...@@ -229,36 +230,38 @@ static dma_addr_t mvpp2_rxdesc_dma_addr_get(struct mvpp2_port *port,
struct mvpp2_rx_desc *rx_desc) struct mvpp2_rx_desc *rx_desc)
{ {
if (port->priv->hw_version == MVPP21) if (port->priv->hw_version == MVPP21)
return rx_desc->pp21.buf_dma_addr; return le32_to_cpu(rx_desc->pp21.buf_dma_addr);
else else
return rx_desc->pp22.buf_dma_addr_key_hash & MVPP2_DESC_DMA_MASK; return le64_to_cpu(rx_desc->pp22.buf_dma_addr_key_hash) &
MVPP2_DESC_DMA_MASK;
} }
static unsigned long mvpp2_rxdesc_cookie_get(struct mvpp2_port *port, static unsigned long mvpp2_rxdesc_cookie_get(struct mvpp2_port *port,
struct mvpp2_rx_desc *rx_desc) struct mvpp2_rx_desc *rx_desc)
{ {
if (port->priv->hw_version == MVPP21) if (port->priv->hw_version == MVPP21)
return rx_desc->pp21.buf_cookie; return le32_to_cpu(rx_desc->pp21.buf_cookie);
else else
return rx_desc->pp22.buf_cookie_misc & MVPP2_DESC_DMA_MASK; return le64_to_cpu(rx_desc->pp22.buf_cookie_misc) &
MVPP2_DESC_DMA_MASK;
} }
static size_t mvpp2_rxdesc_size_get(struct mvpp2_port *port, static size_t mvpp2_rxdesc_size_get(struct mvpp2_port *port,
struct mvpp2_rx_desc *rx_desc) struct mvpp2_rx_desc *rx_desc)
{ {
if (port->priv->hw_version == MVPP21) if (port->priv->hw_version == MVPP21)
return rx_desc->pp21.data_size; return le16_to_cpu(rx_desc->pp21.data_size);
else else
return rx_desc->pp22.data_size; return le16_to_cpu(rx_desc->pp22.data_size);
} }
static u32 mvpp2_rxdesc_status_get(struct mvpp2_port *port, static u32 mvpp2_rxdesc_status_get(struct mvpp2_port *port,
struct mvpp2_rx_desc *rx_desc) struct mvpp2_rx_desc *rx_desc)
{ {
if (port->priv->hw_version == MVPP21) if (port->priv->hw_version == MVPP21)
return rx_desc->pp21.status; return le32_to_cpu(rx_desc->pp21.status);
else else
return rx_desc->pp22.status; return le32_to_cpu(rx_desc->pp22.status);
} }
static void mvpp2_txq_inc_get(struct mvpp2_txq_pcpu *txq_pcpu) static void mvpp2_txq_inc_get(struct mvpp2_txq_pcpu *txq_pcpu)
...@@ -1735,7 +1738,7 @@ static u32 mvpp2_txq_desc_csum(int l3_offs, int l3_proto, ...@@ -1735,7 +1738,7 @@ static u32 mvpp2_txq_desc_csum(int l3_offs, int l3_proto,
command |= (ip_hdr_len << MVPP2_TXD_IP_HLEN_SHIFT); command |= (ip_hdr_len << MVPP2_TXD_IP_HLEN_SHIFT);
command |= MVPP2_TXD_IP_CSUM_DISABLE; command |= MVPP2_TXD_IP_CSUM_DISABLE;
if (l3_proto == swab16(ETH_P_IP)) { if (l3_proto == htons(ETH_P_IP)) {
command &= ~MVPP2_TXD_IP_CSUM_DISABLE; /* enable IPv4 csum */ command &= ~MVPP2_TXD_IP_CSUM_DISABLE; /* enable IPv4 csum */
command &= ~MVPP2_TXD_L3_IP6; /* enable IPv4 */ command &= ~MVPP2_TXD_L3_IP6; /* enable IPv4 */
} else { } else {
......
...@@ -30,17 +30,17 @@ static int mvpp2_prs_hw_write(struct mvpp2 *priv, struct mvpp2_prs_entry *pe) ...@@ -30,17 +30,17 @@ static int mvpp2_prs_hw_write(struct mvpp2 *priv, struct mvpp2_prs_entry *pe)
return -EINVAL; return -EINVAL;
/* Clear entry invalidation bit */ /* Clear entry invalidation bit */
pe->tcam.word[MVPP2_PRS_TCAM_INV_WORD] &= ~MVPP2_PRS_TCAM_INV_MASK; pe->tcam[MVPP2_PRS_TCAM_INV_WORD] &= ~MVPP2_PRS_TCAM_INV_MASK;
/* Write tcam index - indirect access */ /* Write tcam index - indirect access */
mvpp2_write(priv, MVPP2_PRS_TCAM_IDX_REG, pe->index); mvpp2_write(priv, MVPP2_PRS_TCAM_IDX_REG, pe->index);
for (i = 0; i < MVPP2_PRS_TCAM_WORDS; i++) for (i = 0; i < MVPP2_PRS_TCAM_WORDS; i++)
mvpp2_write(priv, MVPP2_PRS_TCAM_DATA_REG(i), pe->tcam.word[i]); mvpp2_write(priv, MVPP2_PRS_TCAM_DATA_REG(i), pe->tcam[i]);
/* Write sram index - indirect access */ /* Write sram index - indirect access */
mvpp2_write(priv, MVPP2_PRS_SRAM_IDX_REG, pe->index); mvpp2_write(priv, MVPP2_PRS_SRAM_IDX_REG, pe->index);
for (i = 0; i < MVPP2_PRS_SRAM_WORDS; i++) for (i = 0; i < MVPP2_PRS_SRAM_WORDS; i++)
mvpp2_write(priv, MVPP2_PRS_SRAM_DATA_REG(i), pe->sram.word[i]); mvpp2_write(priv, MVPP2_PRS_SRAM_DATA_REG(i), pe->sram[i]);
return 0; return 0;
} }
...@@ -60,18 +60,18 @@ static int mvpp2_prs_init_from_hw(struct mvpp2 *priv, ...@@ -60,18 +60,18 @@ static int mvpp2_prs_init_from_hw(struct mvpp2 *priv,
/* Write tcam index - indirect access */ /* Write tcam index - indirect access */
mvpp2_write(priv, MVPP2_PRS_TCAM_IDX_REG, pe->index); mvpp2_write(priv, MVPP2_PRS_TCAM_IDX_REG, pe->index);
pe->tcam.word[MVPP2_PRS_TCAM_INV_WORD] = mvpp2_read(priv, pe->tcam[MVPP2_PRS_TCAM_INV_WORD] = mvpp2_read(priv,
MVPP2_PRS_TCAM_DATA_REG(MVPP2_PRS_TCAM_INV_WORD)); MVPP2_PRS_TCAM_DATA_REG(MVPP2_PRS_TCAM_INV_WORD));
if (pe->tcam.word[MVPP2_PRS_TCAM_INV_WORD] & MVPP2_PRS_TCAM_INV_MASK) if (pe->tcam[MVPP2_PRS_TCAM_INV_WORD] & MVPP2_PRS_TCAM_INV_MASK)
return MVPP2_PRS_TCAM_ENTRY_INVALID; return MVPP2_PRS_TCAM_ENTRY_INVALID;
for (i = 0; i < MVPP2_PRS_TCAM_WORDS; i++) for (i = 0; i < MVPP2_PRS_TCAM_WORDS; i++)
pe->tcam.word[i] = mvpp2_read(priv, MVPP2_PRS_TCAM_DATA_REG(i)); pe->tcam[i] = mvpp2_read(priv, MVPP2_PRS_TCAM_DATA_REG(i));
/* Write sram index - indirect access */ /* Write sram index - indirect access */
mvpp2_write(priv, MVPP2_PRS_SRAM_IDX_REG, pe->index); mvpp2_write(priv, MVPP2_PRS_SRAM_IDX_REG, pe->index);
for (i = 0; i < MVPP2_PRS_SRAM_WORDS; i++) for (i = 0; i < MVPP2_PRS_SRAM_WORDS; i++)
pe->sram.word[i] = mvpp2_read(priv, MVPP2_PRS_SRAM_DATA_REG(i)); pe->sram[i] = mvpp2_read(priv, MVPP2_PRS_SRAM_DATA_REG(i));
return 0; return 0;
} }
...@@ -103,42 +103,35 @@ static void mvpp2_prs_shadow_ri_set(struct mvpp2 *priv, int index, ...@@ -103,42 +103,35 @@ static void mvpp2_prs_shadow_ri_set(struct mvpp2 *priv, int index,
/* Update lookup field in tcam sw entry */ /* Update lookup field in tcam sw entry */
static void mvpp2_prs_tcam_lu_set(struct mvpp2_prs_entry *pe, unsigned int lu) static void mvpp2_prs_tcam_lu_set(struct mvpp2_prs_entry *pe, unsigned int lu)
{ {
int enable_off = MVPP2_PRS_TCAM_EN_OFFS(MVPP2_PRS_TCAM_LU_BYTE); pe->tcam[MVPP2_PRS_TCAM_LU_WORD] &= ~MVPP2_PRS_TCAM_LU(MVPP2_PRS_LU_MASK);
pe->tcam[MVPP2_PRS_TCAM_LU_WORD] &= ~MVPP2_PRS_TCAM_LU_EN(MVPP2_PRS_LU_MASK);
pe->tcam.byte[MVPP2_PRS_TCAM_LU_BYTE] = lu; pe->tcam[MVPP2_PRS_TCAM_LU_WORD] |= MVPP2_PRS_TCAM_LU(lu & MVPP2_PRS_LU_MASK);
pe->tcam.byte[enable_off] = MVPP2_PRS_LU_MASK; pe->tcam[MVPP2_PRS_TCAM_LU_WORD] |= MVPP2_PRS_TCAM_LU_EN(MVPP2_PRS_LU_MASK);
} }
/* Update mask for single port in tcam sw entry */ /* Update mask for single port in tcam sw entry */
static void mvpp2_prs_tcam_port_set(struct mvpp2_prs_entry *pe, static void mvpp2_prs_tcam_port_set(struct mvpp2_prs_entry *pe,
unsigned int port, bool add) unsigned int port, bool add)
{ {
int enable_off = MVPP2_PRS_TCAM_EN_OFFS(MVPP2_PRS_TCAM_PORT_BYTE);
if (add) if (add)
pe->tcam.byte[enable_off] &= ~(1 << port); pe->tcam[MVPP2_PRS_TCAM_PORT_WORD] &= ~MVPP2_PRS_TCAM_PORT_EN(BIT(port));
else else
pe->tcam.byte[enable_off] |= 1 << port; pe->tcam[MVPP2_PRS_TCAM_PORT_WORD] |= MVPP2_PRS_TCAM_PORT_EN(BIT(port));
} }
/* Update port map in tcam sw entry */ /* Update port map in tcam sw entry */
static void mvpp2_prs_tcam_port_map_set(struct mvpp2_prs_entry *pe, static void mvpp2_prs_tcam_port_map_set(struct mvpp2_prs_entry *pe,
unsigned int ports) unsigned int ports)
{ {
unsigned char port_mask = MVPP2_PRS_PORT_MASK; pe->tcam[MVPP2_PRS_TCAM_PORT_WORD] &= ~MVPP2_PRS_TCAM_PORT(MVPP2_PRS_PORT_MASK);
int enable_off = MVPP2_PRS_TCAM_EN_OFFS(MVPP2_PRS_TCAM_PORT_BYTE); pe->tcam[MVPP2_PRS_TCAM_PORT_WORD] &= ~MVPP2_PRS_TCAM_PORT_EN(MVPP2_PRS_PORT_MASK);
pe->tcam[MVPP2_PRS_TCAM_PORT_WORD] |= MVPP2_PRS_TCAM_PORT_EN(~ports & MVPP2_PRS_PORT_MASK);
pe->tcam.byte[MVPP2_PRS_TCAM_PORT_BYTE] = 0;
pe->tcam.byte[enable_off] &= ~port_mask;
pe->tcam.byte[enable_off] |= ~ports & MVPP2_PRS_PORT_MASK;
} }
/* Obtain port map from tcam sw entry */ /* Obtain port map from tcam sw entry */
static unsigned int mvpp2_prs_tcam_port_map_get(struct mvpp2_prs_entry *pe) static unsigned int mvpp2_prs_tcam_port_map_get(struct mvpp2_prs_entry *pe)
{ {
int enable_off = MVPP2_PRS_TCAM_EN_OFFS(MVPP2_PRS_TCAM_PORT_BYTE); return (~pe->tcam[MVPP2_PRS_TCAM_PORT_WORD] >> 24) & MVPP2_PRS_PORT_MASK;
return ~(pe->tcam.byte[enable_off]) & MVPP2_PRS_PORT_MASK;
} }
/* Set byte of data and its enable bits in tcam sw entry */ /* Set byte of data and its enable bits in tcam sw entry */
...@@ -146,8 +139,12 @@ static void mvpp2_prs_tcam_data_byte_set(struct mvpp2_prs_entry *pe, ...@@ -146,8 +139,12 @@ static void mvpp2_prs_tcam_data_byte_set(struct mvpp2_prs_entry *pe,
unsigned int offs, unsigned char byte, unsigned int offs, unsigned char byte,
unsigned char enable) unsigned char enable)
{ {
pe->tcam.byte[MVPP2_PRS_TCAM_DATA_BYTE(offs)] = byte; int pos = MVPP2_PRS_BYTE_IN_WORD(offs) * BITS_PER_BYTE;
pe->tcam.byte[MVPP2_PRS_TCAM_DATA_BYTE_EN(offs)] = enable;
pe->tcam[MVPP2_PRS_BYTE_TO_WORD(offs)] &= ~(0xff << pos);
pe->tcam[MVPP2_PRS_BYTE_TO_WORD(offs)] &= ~(MVPP2_PRS_TCAM_EN(0xff) << pos);
pe->tcam[MVPP2_PRS_BYTE_TO_WORD(offs)] |= byte << pos;
pe->tcam[MVPP2_PRS_BYTE_TO_WORD(offs)] |= MVPP2_PRS_TCAM_EN(enable << pos);
} }
/* Get byte of data and its enable bits from tcam sw entry */ /* Get byte of data and its enable bits from tcam sw entry */
...@@ -155,46 +152,45 @@ static void mvpp2_prs_tcam_data_byte_get(struct mvpp2_prs_entry *pe, ...@@ -155,46 +152,45 @@ static void mvpp2_prs_tcam_data_byte_get(struct mvpp2_prs_entry *pe,
unsigned int offs, unsigned char *byte, unsigned int offs, unsigned char *byte,
unsigned char *enable) unsigned char *enable)
{ {
*byte = pe->tcam.byte[MVPP2_PRS_TCAM_DATA_BYTE(offs)]; int pos = MVPP2_PRS_BYTE_IN_WORD(offs) * BITS_PER_BYTE;
*enable = pe->tcam.byte[MVPP2_PRS_TCAM_DATA_BYTE_EN(offs)];
*byte = (pe->tcam[MVPP2_PRS_BYTE_TO_WORD(offs)] >> pos) & 0xff;
*enable = (pe->tcam[MVPP2_PRS_BYTE_TO_WORD(offs)] >> (pos + 16)) & 0xff;
} }
/* Compare tcam data bytes with a pattern */ /* Compare tcam data bytes with a pattern */
static bool mvpp2_prs_tcam_data_cmp(struct mvpp2_prs_entry *pe, int offs, static bool mvpp2_prs_tcam_data_cmp(struct mvpp2_prs_entry *pe, int offs,
u16 data) u16 data)
{ {
int off = MVPP2_PRS_TCAM_DATA_BYTE(offs);
u16 tcam_data; u16 tcam_data;
tcam_data = (pe->tcam.byte[off + 1] << 8) | pe->tcam.byte[off]; tcam_data = pe->tcam[MVPP2_PRS_BYTE_TO_WORD(offs)] & 0xffff;
if (tcam_data != data) return tcam_data == data;
return false;
return true;
} }
/* Update ai bits in tcam sw entry */ /* Update ai bits in tcam sw entry */
static void mvpp2_prs_tcam_ai_update(struct mvpp2_prs_entry *pe, static void mvpp2_prs_tcam_ai_update(struct mvpp2_prs_entry *pe,
unsigned int bits, unsigned int enable) unsigned int bits, unsigned int enable)
{ {
int i, ai_idx = MVPP2_PRS_TCAM_AI_BYTE; int i;
for (i = 0; i < MVPP2_PRS_AI_BITS; i++) { for (i = 0; i < MVPP2_PRS_AI_BITS; i++) {
if (!(enable & BIT(i))) if (!(enable & BIT(i)))
continue; continue;
if (bits & BIT(i)) if (bits & BIT(i))
pe->tcam.byte[ai_idx] |= 1 << i; pe->tcam[MVPP2_PRS_TCAM_AI_WORD] |= BIT(i);
else else
pe->tcam.byte[ai_idx] &= ~(1 << i); pe->tcam[MVPP2_PRS_TCAM_AI_WORD] &= ~BIT(i);
} }
pe->tcam.byte[MVPP2_PRS_TCAM_EN_OFFS(ai_idx)] |= enable; pe->tcam[MVPP2_PRS_TCAM_AI_WORD] |= MVPP2_PRS_TCAM_AI_EN(enable);
} }
/* Get ai bits from tcam sw entry */ /* Get ai bits from tcam sw entry */
static int mvpp2_prs_tcam_ai_get(struct mvpp2_prs_entry *pe) static int mvpp2_prs_tcam_ai_get(struct mvpp2_prs_entry *pe)
{ {
return pe->tcam.byte[MVPP2_PRS_TCAM_AI_BYTE]; return pe->tcam[MVPP2_PRS_TCAM_AI_WORD] & MVPP2_PRS_AI_MASK;
} }
/* Set ethertype in tcam sw entry */ /* Set ethertype in tcam sw entry */
...@@ -215,16 +211,16 @@ static void mvpp2_prs_match_vid(struct mvpp2_prs_entry *pe, int offset, ...@@ -215,16 +211,16 @@ static void mvpp2_prs_match_vid(struct mvpp2_prs_entry *pe, int offset,
/* Set bits in sram sw entry */ /* Set bits in sram sw entry */
static void mvpp2_prs_sram_bits_set(struct mvpp2_prs_entry *pe, int bit_num, static void mvpp2_prs_sram_bits_set(struct mvpp2_prs_entry *pe, int bit_num,
int val) u32 val)
{ {
pe->sram.byte[MVPP2_BIT_TO_BYTE(bit_num)] |= (val << (bit_num % 8)); pe->sram[MVPP2_BIT_TO_WORD(bit_num)] |= (val << (MVPP2_BIT_IN_WORD(bit_num)));
} }
/* Clear bits in sram sw entry */ /* Clear bits in sram sw entry */
static void mvpp2_prs_sram_bits_clear(struct mvpp2_prs_entry *pe, int bit_num, static void mvpp2_prs_sram_bits_clear(struct mvpp2_prs_entry *pe, int bit_num,
int val) u32 val)
{ {
pe->sram.byte[MVPP2_BIT_TO_BYTE(bit_num)] &= ~(val << (bit_num % 8)); pe->sram[MVPP2_BIT_TO_WORD(bit_num)] &= ~(val << (MVPP2_BIT_IN_WORD(bit_num)));
} }
/* Update ri bits in sram sw entry */ /* Update ri bits in sram sw entry */
...@@ -234,15 +230,16 @@ static void mvpp2_prs_sram_ri_update(struct mvpp2_prs_entry *pe, ...@@ -234,15 +230,16 @@ static void mvpp2_prs_sram_ri_update(struct mvpp2_prs_entry *pe,
unsigned int i; unsigned int i;
for (i = 0; i < MVPP2_PRS_SRAM_RI_CTRL_BITS; i++) { for (i = 0; i < MVPP2_PRS_SRAM_RI_CTRL_BITS; i++) {
int ri_off = MVPP2_PRS_SRAM_RI_OFFS;
if (!(mask & BIT(i))) if (!(mask & BIT(i)))
continue; continue;
if (bits & BIT(i)) if (bits & BIT(i))
mvpp2_prs_sram_bits_set(pe, ri_off + i, 1); mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_RI_OFFS + i,
1);
else else
mvpp2_prs_sram_bits_clear(pe, ri_off + i, 1); mvpp2_prs_sram_bits_clear(pe,
MVPP2_PRS_SRAM_RI_OFFS + i,
1);
mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_RI_CTRL_OFFS + i, 1); mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_RI_CTRL_OFFS + i, 1);
} }
...@@ -251,7 +248,7 @@ static void mvpp2_prs_sram_ri_update(struct mvpp2_prs_entry *pe, ...@@ -251,7 +248,7 @@ static void mvpp2_prs_sram_ri_update(struct mvpp2_prs_entry *pe,
/* Obtain ri bits from sram sw entry */ /* Obtain ri bits from sram sw entry */
static int mvpp2_prs_sram_ri_get(struct mvpp2_prs_entry *pe) static int mvpp2_prs_sram_ri_get(struct mvpp2_prs_entry *pe)
{ {
return pe->sram.word[MVPP2_PRS_SRAM_RI_WORD]; return pe->sram[MVPP2_PRS_SRAM_RI_WORD];
} }
/* Update ai bits in sram sw entry */ /* Update ai bits in sram sw entry */
...@@ -259,16 +256,18 @@ static void mvpp2_prs_sram_ai_update(struct mvpp2_prs_entry *pe, ...@@ -259,16 +256,18 @@ static void mvpp2_prs_sram_ai_update(struct mvpp2_prs_entry *pe,
unsigned int bits, unsigned int mask) unsigned int bits, unsigned int mask)
{ {
unsigned int i; unsigned int i;
int ai_off = MVPP2_PRS_SRAM_AI_OFFS;
for (i = 0; i < MVPP2_PRS_SRAM_AI_CTRL_BITS; i++) { for (i = 0; i < MVPP2_PRS_SRAM_AI_CTRL_BITS; i++) {
if (!(mask & BIT(i))) if (!(mask & BIT(i)))
continue; continue;
if (bits & BIT(i)) if (bits & BIT(i))
mvpp2_prs_sram_bits_set(pe, ai_off + i, 1); mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_AI_OFFS + i,
1);
else else
mvpp2_prs_sram_bits_clear(pe, ai_off + i, 1); mvpp2_prs_sram_bits_clear(pe,
MVPP2_PRS_SRAM_AI_OFFS + i,
1);
mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_AI_CTRL_OFFS + i, 1); mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_AI_CTRL_OFFS + i, 1);
} }
...@@ -278,12 +277,12 @@ static void mvpp2_prs_sram_ai_update(struct mvpp2_prs_entry *pe, ...@@ -278,12 +277,12 @@ static void mvpp2_prs_sram_ai_update(struct mvpp2_prs_entry *pe,
static int mvpp2_prs_sram_ai_get(struct mvpp2_prs_entry *pe) static int mvpp2_prs_sram_ai_get(struct mvpp2_prs_entry *pe)
{ {
u8 bits; u8 bits;
int ai_off = MVPP2_BIT_TO_BYTE(MVPP2_PRS_SRAM_AI_OFFS); /* ai is stored on bits 90->97; so it spreads across two u32 */
int ai_en_off = ai_off + 1; int ai_off = MVPP2_BIT_TO_WORD(MVPP2_PRS_SRAM_AI_OFFS);
int ai_shift = MVPP2_PRS_SRAM_AI_OFFS % 8; int ai_shift = MVPP2_BIT_IN_WORD(MVPP2_PRS_SRAM_AI_OFFS);
bits = (pe->sram.byte[ai_off] >> ai_shift) | bits = (pe->sram[ai_off] >> ai_shift) |
(pe->sram.byte[ai_en_off] << (8 - ai_shift)); (pe->sram[ai_off + 1] << (32 - ai_shift));
return bits; return bits;
} }
...@@ -316,8 +315,7 @@ static void mvpp2_prs_sram_shift_set(struct mvpp2_prs_entry *pe, int shift, ...@@ -316,8 +315,7 @@ static void mvpp2_prs_sram_shift_set(struct mvpp2_prs_entry *pe, int shift,
} }
/* Set value */ /* Set value */
pe->sram.byte[MVPP2_BIT_TO_BYTE(MVPP2_PRS_SRAM_SHIFT_OFFS)] = pe->sram[MVPP2_BIT_TO_WORD(MVPP2_PRS_SRAM_SHIFT_OFFS)] = shift & MVPP2_PRS_SRAM_SHIFT_MASK;
(unsigned char)shift;
/* Reset and set operation */ /* Reset and set operation */
mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_OP_SEL_SHIFT_OFFS, mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_OP_SEL_SHIFT_OFFS,
...@@ -346,13 +344,8 @@ static void mvpp2_prs_sram_offset_set(struct mvpp2_prs_entry *pe, ...@@ -346,13 +344,8 @@ static void mvpp2_prs_sram_offset_set(struct mvpp2_prs_entry *pe,
/* Set value */ /* Set value */
mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_UDF_OFFS, mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_UDF_OFFS,
MVPP2_PRS_SRAM_UDF_MASK); MVPP2_PRS_SRAM_UDF_MASK);
mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_UDF_OFFS, offset); mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_UDF_OFFS,
pe->sram.byte[MVPP2_BIT_TO_BYTE(MVPP2_PRS_SRAM_UDF_OFFS + offset & MVPP2_PRS_SRAM_UDF_MASK);
MVPP2_PRS_SRAM_UDF_BITS)] &=
~(MVPP2_PRS_SRAM_UDF_MASK >> (8 - (MVPP2_PRS_SRAM_UDF_OFFS % 8)));
pe->sram.byte[MVPP2_BIT_TO_BYTE(MVPP2_PRS_SRAM_UDF_OFFS +
MVPP2_PRS_SRAM_UDF_BITS)] |=
(offset >> (8 - (MVPP2_PRS_SRAM_UDF_OFFS % 8)));
/* Set offset type */ /* Set offset type */
mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_UDF_TYPE_OFFS, mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_UDF_TYPE_OFFS,
...@@ -362,16 +355,8 @@ static void mvpp2_prs_sram_offset_set(struct mvpp2_prs_entry *pe, ...@@ -362,16 +355,8 @@ static void mvpp2_prs_sram_offset_set(struct mvpp2_prs_entry *pe,
/* Set offset operation */ /* Set offset operation */
mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_OP_SEL_UDF_OFFS, mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_OP_SEL_UDF_OFFS,
MVPP2_PRS_SRAM_OP_SEL_UDF_MASK); MVPP2_PRS_SRAM_OP_SEL_UDF_MASK);
mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_OP_SEL_UDF_OFFS, op); mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_OP_SEL_UDF_OFFS,
op & MVPP2_PRS_SRAM_OP_SEL_UDF_MASK);
pe->sram.byte[MVPP2_BIT_TO_BYTE(MVPP2_PRS_SRAM_OP_SEL_UDF_OFFS +
MVPP2_PRS_SRAM_OP_SEL_UDF_BITS)] &=
~(MVPP2_PRS_SRAM_OP_SEL_UDF_MASK >>
(8 - (MVPP2_PRS_SRAM_OP_SEL_UDF_OFFS % 8)));
pe->sram.byte[MVPP2_BIT_TO_BYTE(MVPP2_PRS_SRAM_OP_SEL_UDF_OFFS +
MVPP2_PRS_SRAM_OP_SEL_UDF_BITS)] |=
(op >> (8 - (MVPP2_PRS_SRAM_OP_SEL_UDF_OFFS % 8)));
/* Set base offset as current */ /* Set base offset as current */
mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_OP_SEL_BASE_OFFS, 1); mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_OP_SEL_BASE_OFFS, 1);
...@@ -662,7 +647,7 @@ static int mvpp2_prs_vlan_find(struct mvpp2 *priv, unsigned short tpid, int ai) ...@@ -662,7 +647,7 @@ static int mvpp2_prs_vlan_find(struct mvpp2 *priv, unsigned short tpid, int ai)
continue; continue;
mvpp2_prs_init_from_hw(priv, &pe, tid); mvpp2_prs_init_from_hw(priv, &pe, tid);
match = mvpp2_prs_tcam_data_cmp(&pe, 0, swab16(tpid)); match = mvpp2_prs_tcam_data_cmp(&pe, 0, tpid);
if (!match) if (!match)
continue; continue;
...@@ -790,8 +775,8 @@ static int mvpp2_prs_double_vlan_find(struct mvpp2 *priv, unsigned short tpid1, ...@@ -790,8 +775,8 @@ static int mvpp2_prs_double_vlan_find(struct mvpp2 *priv, unsigned short tpid1,
mvpp2_prs_init_from_hw(priv, &pe, tid); mvpp2_prs_init_from_hw(priv, &pe, tid);
match = mvpp2_prs_tcam_data_cmp(&pe, 0, swab16(tpid1)) && match = mvpp2_prs_tcam_data_cmp(&pe, 0, tpid1) &&
mvpp2_prs_tcam_data_cmp(&pe, 4, swab16(tpid2)); mvpp2_prs_tcam_data_cmp(&pe, 4, tpid2);
if (!match) if (!match)
continue; continue;
...@@ -932,8 +917,8 @@ static int mvpp2_prs_ip4_proto(struct mvpp2 *priv, unsigned short proto, ...@@ -932,8 +917,8 @@ static int mvpp2_prs_ip4_proto(struct mvpp2 *priv, unsigned short proto,
pe.index = tid; pe.index = tid;
/* Clear ri before updating */ /* Clear ri before updating */
pe.sram.word[MVPP2_PRS_SRAM_RI_WORD] = 0x0; pe.sram[MVPP2_PRS_SRAM_RI_WORD] = 0x0;
pe.sram.word[MVPP2_PRS_SRAM_RI_CTRL_WORD] = 0x0; pe.sram[MVPP2_PRS_SRAM_RI_CTRL_WORD] = 0x0;
mvpp2_prs_sram_ri_update(&pe, ri, ri_mask); mvpp2_prs_sram_ri_update(&pe, ri, ri_mask);
mvpp2_prs_sram_ri_update(&pe, ri | MVPP2_PRS_RI_IP_FRAG_TRUE, mvpp2_prs_sram_ri_update(&pe, ri | MVPP2_PRS_RI_IP_FRAG_TRUE,
...@@ -1433,17 +1418,13 @@ static int mvpp2_prs_etype_init(struct mvpp2 *priv) ...@@ -1433,17 +1418,13 @@ static int mvpp2_prs_etype_init(struct mvpp2 *priv)
pe.index = tid; pe.index = tid;
/* Clear tcam data before updating */
pe.tcam.byte[MVPP2_PRS_TCAM_DATA_BYTE(MVPP2_ETH_TYPE_LEN)] = 0x0;
pe.tcam.byte[MVPP2_PRS_TCAM_DATA_BYTE_EN(MVPP2_ETH_TYPE_LEN)] = 0x0;
mvpp2_prs_tcam_data_byte_set(&pe, MVPP2_ETH_TYPE_LEN, mvpp2_prs_tcam_data_byte_set(&pe, MVPP2_ETH_TYPE_LEN,
MVPP2_PRS_IPV4_HEAD, MVPP2_PRS_IPV4_HEAD,
MVPP2_PRS_IPV4_HEAD_MASK); MVPP2_PRS_IPV4_HEAD_MASK);
/* Clear ri before updating */ /* Clear ri before updating */
pe.sram.word[MVPP2_PRS_SRAM_RI_WORD] = 0x0; pe.sram[MVPP2_PRS_SRAM_RI_WORD] = 0x0;
pe.sram.word[MVPP2_PRS_SRAM_RI_CTRL_WORD] = 0x0; pe.sram[MVPP2_PRS_SRAM_RI_CTRL_WORD] = 0x0;
mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_IP4_OPT, mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_IP4_OPT,
MVPP2_PRS_RI_L3_PROTO_MASK); MVPP2_PRS_RI_L3_PROTO_MASK);
...@@ -1644,8 +1625,8 @@ static int mvpp2_prs_pppoe_init(struct mvpp2 *priv) ...@@ -1644,8 +1625,8 @@ static int mvpp2_prs_pppoe_init(struct mvpp2 *priv)
MVPP2_PRS_IPV4_IHL_MASK); MVPP2_PRS_IPV4_IHL_MASK);
/* Clear ri before updating */ /* Clear ri before updating */
pe.sram.word[MVPP2_PRS_SRAM_RI_WORD] = 0x0; pe.sram[MVPP2_PRS_SRAM_RI_WORD] = 0x0;
pe.sram.word[MVPP2_PRS_SRAM_RI_CTRL_WORD] = 0x0; pe.sram[MVPP2_PRS_SRAM_RI_CTRL_WORD] = 0x0;
mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_IP4, mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_IP4,
MVPP2_PRS_RI_L3_PROTO_MASK); MVPP2_PRS_RI_L3_PROTO_MASK);
......
...@@ -50,17 +50,25 @@ ...@@ -50,17 +50,25 @@
* The fields are represented by MVPP2_PRS_TCAM_DATA_REG(5)->(0). * The fields are represented by MVPP2_PRS_TCAM_DATA_REG(5)->(0).
*/ */
#define MVPP2_PRS_AI_BITS 8 #define MVPP2_PRS_AI_BITS 8
#define MVPP2_PRS_AI_MASK 0xff
#define MVPP2_PRS_PORT_MASK 0xff #define MVPP2_PRS_PORT_MASK 0xff
#define MVPP2_PRS_LU_MASK 0xf #define MVPP2_PRS_LU_MASK 0xf
#define MVPP2_PRS_TCAM_DATA_BYTE(offs) \
(((offs) - ((offs) % 2)) * 2 + ((offs) % 2)) /* TCAM entries in registers are accessed using 16 data bits + 16 enable bits */
#define MVPP2_PRS_TCAM_DATA_BYTE_EN(offs) \ #define MVPP2_PRS_BYTE_TO_WORD(byte) ((byte) / 2)
(((offs) * 2) - ((offs) % 2) + 2) #define MVPP2_PRS_BYTE_IN_WORD(byte) ((byte) % 2)
#define MVPP2_PRS_TCAM_AI_BYTE 16
#define MVPP2_PRS_TCAM_PORT_BYTE 17 #define MVPP2_PRS_TCAM_EN(data) ((data) << 16)
#define MVPP2_PRS_TCAM_LU_BYTE 20 #define MVPP2_PRS_TCAM_AI_WORD 4
#define MVPP2_PRS_TCAM_EN_OFFS(offs) ((offs) + 2) #define MVPP2_PRS_TCAM_AI(ai) (ai)
#define MVPP2_PRS_TCAM_INV_WORD 5 #define MVPP2_PRS_TCAM_AI_EN(ai) MVPP2_PRS_TCAM_EN(MVPP2_PRS_TCAM_AI(ai))
#define MVPP2_PRS_TCAM_PORT_WORD 4
#define MVPP2_PRS_TCAM_PORT(p) ((p) << 8)
#define MVPP2_PRS_TCAM_PORT_EN(p) MVPP2_PRS_TCAM_EN(MVPP2_PRS_TCAM_PORT(p))
#define MVPP2_PRS_TCAM_LU_WORD 5
#define MVPP2_PRS_TCAM_LU(lu) (lu)
#define MVPP2_PRS_TCAM_LU_EN(lu) MVPP2_PRS_TCAM_EN(MVPP2_PRS_TCAM_LU(lu))
#define MVPP2_PRS_TCAM_INV_WORD 5
#define MVPP2_PRS_VID_TCAM_BYTE 2 #define MVPP2_PRS_VID_TCAM_BYTE 2
...@@ -146,6 +154,7 @@ ...@@ -146,6 +154,7 @@
#define MVPP2_PRS_SRAM_RI_CTRL_BITS 32 #define MVPP2_PRS_SRAM_RI_CTRL_BITS 32
#define MVPP2_PRS_SRAM_SHIFT_OFFS 64 #define MVPP2_PRS_SRAM_SHIFT_OFFS 64
#define MVPP2_PRS_SRAM_SHIFT_SIGN_BIT 72 #define MVPP2_PRS_SRAM_SHIFT_SIGN_BIT 72
#define MVPP2_PRS_SRAM_SHIFT_MASK 0xff
#define MVPP2_PRS_SRAM_UDF_OFFS 73 #define MVPP2_PRS_SRAM_UDF_OFFS 73
#define MVPP2_PRS_SRAM_UDF_BITS 8 #define MVPP2_PRS_SRAM_UDF_BITS 8
#define MVPP2_PRS_SRAM_UDF_MASK 0xff #define MVPP2_PRS_SRAM_UDF_MASK 0xff
...@@ -255,20 +264,10 @@ enum mvpp2_prs_lookup { ...@@ -255,20 +264,10 @@ enum mvpp2_prs_lookup {
MVPP2_PRS_LU_LAST, MVPP2_PRS_LU_LAST,
}; };
union mvpp2_prs_tcam_entry {
u32 word[MVPP2_PRS_TCAM_WORDS];
u8 byte[MVPP2_PRS_TCAM_WORDS * 4];
};
union mvpp2_prs_sram_entry {
u32 word[MVPP2_PRS_SRAM_WORDS];
u8 byte[MVPP2_PRS_SRAM_WORDS * 4];
};
struct mvpp2_prs_entry { struct mvpp2_prs_entry {
u32 index; u32 index;
union mvpp2_prs_tcam_entry tcam; u32 tcam[MVPP2_PRS_TCAM_WORDS];
union mvpp2_prs_sram_entry sram; u32 sram[MVPP2_PRS_SRAM_WORDS];
}; };
struct mvpp2_prs_shadow { struct mvpp2_prs_shadow {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment