|
@@ -131,7 +131,7 @@ static unsigned int xgbe_usec_to_riwt(struct xgbe_prv_data *pdata,
|
|
|
|
|
|
DBGPR("-->xgbe_usec_to_riwt\n");
|
|
DBGPR("-->xgbe_usec_to_riwt\n");
|
|
|
|
|
|
- rate = clk_get_rate(pdata->sysclock);
|
|
|
|
|
|
+ rate = clk_get_rate(pdata->sysclk);
|
|
|
|
|
|
/*
|
|
/*
|
|
* Convert the input usec value to the watchdog timer value. Each
|
|
* Convert the input usec value to the watchdog timer value. Each
|
|
@@ -154,7 +154,7 @@ static unsigned int xgbe_riwt_to_usec(struct xgbe_prv_data *pdata,
|
|
|
|
|
|
DBGPR("-->xgbe_riwt_to_usec\n");
|
|
DBGPR("-->xgbe_riwt_to_usec\n");
|
|
|
|
|
|
- rate = clk_get_rate(pdata->sysclock);
|
|
|
|
|
|
+ rate = clk_get_rate(pdata->sysclk);
|
|
|
|
|
|
/*
|
|
/*
|
|
* Convert the input watchdog timer value to the usec value. Each
|
|
* Convert the input watchdog timer value to the usec value. Each
|
|
@@ -247,7 +247,7 @@ static int xgbe_config_rsf_mode(struct xgbe_prv_data *pdata, unsigned int val)
|
|
{
|
|
{
|
|
unsigned int i;
|
|
unsigned int i;
|
|
|
|
|
|
- for (i = 0; i < pdata->hw_feat.rx_q_cnt; i++)
|
|
|
|
|
|
+ for (i = 0; i < pdata->rx_q_count; i++)
|
|
XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_RQOMR, RSF, val);
|
|
XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_RQOMR, RSF, val);
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
@@ -257,7 +257,7 @@ static int xgbe_config_tsf_mode(struct xgbe_prv_data *pdata, unsigned int val)
|
|
{
|
|
{
|
|
unsigned int i;
|
|
unsigned int i;
|
|
|
|
|
|
- for (i = 0; i < pdata->hw_feat.tx_q_cnt; i++)
|
|
|
|
|
|
+ for (i = 0; i < pdata->tx_q_count; i++)
|
|
XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_TQOMR, TSF, val);
|
|
XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_TQOMR, TSF, val);
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
@@ -268,7 +268,7 @@ static int xgbe_config_rx_threshold(struct xgbe_prv_data *pdata,
|
|
{
|
|
{
|
|
unsigned int i;
|
|
unsigned int i;
|
|
|
|
|
|
- for (i = 0; i < pdata->hw_feat.rx_q_cnt; i++)
|
|
|
|
|
|
+ for (i = 0; i < pdata->rx_q_count; i++)
|
|
XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_RQOMR, RTC, val);
|
|
XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_RQOMR, RTC, val);
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
@@ -279,7 +279,7 @@ static int xgbe_config_tx_threshold(struct xgbe_prv_data *pdata,
|
|
{
|
|
{
|
|
unsigned int i;
|
|
unsigned int i;
|
|
|
|
|
|
- for (i = 0; i < pdata->hw_feat.tx_q_cnt; i++)
|
|
|
|
|
|
+ for (i = 0; i < pdata->tx_q_count; i++)
|
|
XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_TQOMR, TTC, val);
|
|
XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_TQOMR, TTC, val);
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
@@ -343,12 +343,12 @@ static int xgbe_disable_tx_flow_control(struct xgbe_prv_data *pdata)
|
|
unsigned int i;
|
|
unsigned int i;
|
|
|
|
|
|
/* Clear MTL flow control */
|
|
/* Clear MTL flow control */
|
|
- for (i = 0; i < pdata->hw_feat.rx_q_cnt; i++)
|
|
|
|
|
|
+ for (i = 0; i < pdata->rx_q_count; i++)
|
|
XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_RQOMR, EHFC, 0);
|
|
XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_RQOMR, EHFC, 0);
|
|
|
|
|
|
/* Clear MAC flow control */
|
|
/* Clear MAC flow control */
|
|
max_q_count = XGMAC_MAX_FLOW_CONTROL_QUEUES;
|
|
max_q_count = XGMAC_MAX_FLOW_CONTROL_QUEUES;
|
|
- q_count = min_t(unsigned int, pdata->hw_feat.rx_q_cnt, max_q_count);
|
|
|
|
|
|
+ q_count = min_t(unsigned int, pdata->rx_q_count, max_q_count);
|
|
reg = MAC_Q0TFCR;
|
|
reg = MAC_Q0TFCR;
|
|
for (i = 0; i < q_count; i++) {
|
|
for (i = 0; i < q_count; i++) {
|
|
reg_val = XGMAC_IOREAD(pdata, reg);
|
|
reg_val = XGMAC_IOREAD(pdata, reg);
|
|
@@ -368,12 +368,12 @@ static int xgbe_enable_tx_flow_control(struct xgbe_prv_data *pdata)
|
|
unsigned int i;
|
|
unsigned int i;
|
|
|
|
|
|
/* Set MTL flow control */
|
|
/* Set MTL flow control */
|
|
- for (i = 0; i < pdata->hw_feat.rx_q_cnt; i++)
|
|
|
|
|
|
+ for (i = 0; i < pdata->rx_q_count; i++)
|
|
XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_RQOMR, EHFC, 1);
|
|
XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_RQOMR, EHFC, 1);
|
|
|
|
|
|
/* Set MAC flow control */
|
|
/* Set MAC flow control */
|
|
max_q_count = XGMAC_MAX_FLOW_CONTROL_QUEUES;
|
|
max_q_count = XGMAC_MAX_FLOW_CONTROL_QUEUES;
|
|
- q_count = min_t(unsigned int, pdata->hw_feat.rx_q_cnt, max_q_count);
|
|
|
|
|
|
+ q_count = min_t(unsigned int, pdata->rx_q_count, max_q_count);
|
|
reg = MAC_Q0TFCR;
|
|
reg = MAC_Q0TFCR;
|
|
for (i = 0; i < q_count; i++) {
|
|
for (i = 0; i < q_count; i++) {
|
|
reg_val = XGMAC_IOREAD(pdata, reg);
|
|
reg_val = XGMAC_IOREAD(pdata, reg);
|
|
@@ -407,7 +407,9 @@ static int xgbe_enable_rx_flow_control(struct xgbe_prv_data *pdata)
|
|
|
|
|
|
static int xgbe_config_tx_flow_control(struct xgbe_prv_data *pdata)
|
|
static int xgbe_config_tx_flow_control(struct xgbe_prv_data *pdata)
|
|
{
|
|
{
|
|
- if (pdata->tx_pause)
|
|
|
|
|
|
+ struct ieee_pfc *pfc = pdata->pfc;
|
|
|
|
+
|
|
|
|
+ if (pdata->tx_pause || (pfc && pfc->pfc_en))
|
|
xgbe_enable_tx_flow_control(pdata);
|
|
xgbe_enable_tx_flow_control(pdata);
|
|
else
|
|
else
|
|
xgbe_disable_tx_flow_control(pdata);
|
|
xgbe_disable_tx_flow_control(pdata);
|
|
@@ -417,7 +419,9 @@ static int xgbe_config_tx_flow_control(struct xgbe_prv_data *pdata)
|
|
|
|
|
|
static int xgbe_config_rx_flow_control(struct xgbe_prv_data *pdata)
|
|
static int xgbe_config_rx_flow_control(struct xgbe_prv_data *pdata)
|
|
{
|
|
{
|
|
- if (pdata->rx_pause)
|
|
|
|
|
|
+ struct ieee_pfc *pfc = pdata->pfc;
|
|
|
|
+
|
|
|
|
+ if (pdata->rx_pause || (pfc && pfc->pfc_en))
|
|
xgbe_enable_rx_flow_control(pdata);
|
|
xgbe_enable_rx_flow_control(pdata);
|
|
else
|
|
else
|
|
xgbe_disable_rx_flow_control(pdata);
|
|
xgbe_disable_rx_flow_control(pdata);
|
|
@@ -427,8 +431,13 @@ static int xgbe_config_rx_flow_control(struct xgbe_prv_data *pdata)
|
|
|
|
|
|
static void xgbe_config_flow_control(struct xgbe_prv_data *pdata)
|
|
static void xgbe_config_flow_control(struct xgbe_prv_data *pdata)
|
|
{
|
|
{
|
|
|
|
+ struct ieee_pfc *pfc = pdata->pfc;
|
|
|
|
+
|
|
xgbe_config_tx_flow_control(pdata);
|
|
xgbe_config_tx_flow_control(pdata);
|
|
xgbe_config_rx_flow_control(pdata);
|
|
xgbe_config_rx_flow_control(pdata);
|
|
|
|
+
|
|
|
|
+ XGMAC_IOWRITE_BITS(pdata, MAC_RFCR, PFCE,
|
|
|
|
+ (pfc && pfc->pfc_en) ? 1 : 0);
|
|
}
|
|
}
|
|
|
|
|
|
static void xgbe_enable_dma_interrupts(struct xgbe_prv_data *pdata)
|
|
static void xgbe_enable_dma_interrupts(struct xgbe_prv_data *pdata)
|
|
@@ -492,8 +501,12 @@ static void xgbe_enable_mtl_interrupts(struct xgbe_prv_data *pdata)
|
|
|
|
|
|
static void xgbe_enable_mac_interrupts(struct xgbe_prv_data *pdata)
|
|
static void xgbe_enable_mac_interrupts(struct xgbe_prv_data *pdata)
|
|
{
|
|
{
|
|
- /* No MAC interrupts to be enabled */
|
|
|
|
- XGMAC_IOWRITE(pdata, MAC_IER, 0);
|
|
|
|
|
|
+ unsigned int mac_ier = 0;
|
|
|
|
+
|
|
|
|
+ /* Enable Timestamp interrupt */
|
|
|
|
+ XGMAC_SET_BITS(mac_ier, MAC_IER, TSIE, 1);
|
|
|
|
+
|
|
|
|
+ XGMAC_IOWRITE(pdata, MAC_IER, mac_ier);
|
|
|
|
|
|
/* Enable all counter interrupts */
|
|
/* Enable all counter interrupts */
|
|
XGMAC_IOWRITE_BITS(pdata, MMC_RIER, ALL_INTERRUPTS, 0xff);
|
|
XGMAC_IOWRITE_BITS(pdata, MMC_RIER, ALL_INTERRUPTS, 0xff);
|
|
@@ -1012,6 +1025,180 @@ static void xgbe_rx_desc_init(struct xgbe_channel *channel)
|
|
DBGPR("<--rx_desc_init\n");
|
|
DBGPR("<--rx_desc_init\n");
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static void xgbe_update_tstamp_addend(struct xgbe_prv_data *pdata,
|
|
|
|
+ unsigned int addend)
|
|
|
|
+{
|
|
|
|
+ /* Set the addend register value and tell the device */
|
|
|
|
+ XGMAC_IOWRITE(pdata, MAC_TSAR, addend);
|
|
|
|
+ XGMAC_IOWRITE_BITS(pdata, MAC_TSCR, TSADDREG, 1);
|
|
|
|
+
|
|
|
|
+ /* Wait for addend update to complete */
|
|
|
|
+ while (XGMAC_IOREAD_BITS(pdata, MAC_TSCR, TSADDREG))
|
|
|
|
+ udelay(5);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void xgbe_set_tstamp_time(struct xgbe_prv_data *pdata, unsigned int sec,
|
|
|
|
+ unsigned int nsec)
|
|
|
|
+{
|
|
|
|
+ /* Set the time values and tell the device */
|
|
|
|
+ XGMAC_IOWRITE(pdata, MAC_STSUR, sec);
|
|
|
|
+ XGMAC_IOWRITE(pdata, MAC_STNUR, nsec);
|
|
|
|
+ XGMAC_IOWRITE_BITS(pdata, MAC_TSCR, TSINIT, 1);
|
|
|
|
+
|
|
|
|
+ /* Wait for time update to complete */
|
|
|
|
+ while (XGMAC_IOREAD_BITS(pdata, MAC_TSCR, TSINIT))
|
|
|
|
+ udelay(5);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static u64 xgbe_get_tstamp_time(struct xgbe_prv_data *pdata)
|
|
|
|
+{
|
|
|
|
+ u64 nsec;
|
|
|
|
+
|
|
|
|
+ nsec = XGMAC_IOREAD(pdata, MAC_STSR);
|
|
|
|
+ nsec *= NSEC_PER_SEC;
|
|
|
|
+ nsec += XGMAC_IOREAD(pdata, MAC_STNR);
|
|
|
|
+
|
|
|
|
+ return nsec;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static u64 xgbe_get_tx_tstamp(struct xgbe_prv_data *pdata)
|
|
|
|
+{
|
|
|
|
+ unsigned int tx_snr;
|
|
|
|
+ u64 nsec;
|
|
|
|
+
|
|
|
|
+ tx_snr = XGMAC_IOREAD(pdata, MAC_TXSNR);
|
|
|
|
+ if (XGMAC_GET_BITS(tx_snr, MAC_TXSNR, TXTSSTSMIS))
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+ nsec = XGMAC_IOREAD(pdata, MAC_TXSSR);
|
|
|
|
+ nsec *= NSEC_PER_SEC;
|
|
|
|
+ nsec += tx_snr;
|
|
|
|
+
|
|
|
|
+ return nsec;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void xgbe_get_rx_tstamp(struct xgbe_packet_data *packet,
|
|
|
|
+ struct xgbe_ring_desc *rdesc)
|
|
|
|
+{
|
|
|
|
+ u64 nsec;
|
|
|
|
+
|
|
|
|
+ if (XGMAC_GET_BITS_LE(rdesc->desc3, RX_CONTEXT_DESC3, TSA) &&
|
|
|
|
+ !XGMAC_GET_BITS_LE(rdesc->desc3, RX_CONTEXT_DESC3, TSD)) {
|
|
|
|
+ nsec = le32_to_cpu(rdesc->desc1);
|
|
|
|
+ nsec <<= 32;
|
|
|
|
+ nsec |= le32_to_cpu(rdesc->desc0);
|
|
|
|
+ if (nsec != 0xffffffffffffffffULL) {
|
|
|
|
+ packet->rx_tstamp = nsec;
|
|
|
|
+ XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES,
|
|
|
|
+ RX_TSTAMP, 1);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int xgbe_config_tstamp(struct xgbe_prv_data *pdata,
|
|
|
|
+ unsigned int mac_tscr)
|
|
|
|
+{
|
|
|
|
+ /* Set one nano-second accuracy */
|
|
|
|
+ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSCTRLSSR, 1);
|
|
|
|
+
|
|
|
|
+ /* Set fine timestamp update */
|
|
|
|
+ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSCFUPDT, 1);
|
|
|
|
+
|
|
|
|
+ /* Overwrite earlier timestamps */
|
|
|
|
+ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TXTSSTSM, 1);
|
|
|
|
+
|
|
|
|
+ XGMAC_IOWRITE(pdata, MAC_TSCR, mac_tscr);
|
|
|
|
+
|
|
|
|
+ /* Exit if timestamping is not enabled */
|
|
|
|
+ if (!XGMAC_GET_BITS(mac_tscr, MAC_TSCR, TSENA))
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+ /* Initialize time registers */
|
|
|
|
+ XGMAC_IOWRITE_BITS(pdata, MAC_SSIR, SSINC, XGBE_TSTAMP_SSINC);
|
|
|
|
+ XGMAC_IOWRITE_BITS(pdata, MAC_SSIR, SNSINC, XGBE_TSTAMP_SNSINC);
|
|
|
|
+ xgbe_update_tstamp_addend(pdata, pdata->tstamp_addend);
|
|
|
|
+ xgbe_set_tstamp_time(pdata, 0, 0);
|
|
|
|
+
|
|
|
|
+ /* Initialize the timecounter */
|
|
|
|
+ timecounter_init(&pdata->tstamp_tc, &pdata->tstamp_cc,
|
|
|
|
+ ktime_to_ns(ktime_get_real()));
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void xgbe_config_dcb_tc(struct xgbe_prv_data *pdata)
|
|
|
|
+{
|
|
|
|
+ struct ieee_ets *ets = pdata->ets;
|
|
|
|
+ unsigned int total_weight, min_weight, weight;
|
|
|
|
+ unsigned int i;
|
|
|
|
+
|
|
|
|
+ if (!ets)
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ /* Set Tx to deficit weighted round robin scheduling algorithm (when
|
|
|
|
+ * traffic class is using ETS algorithm)
|
|
|
|
+ */
|
|
|
|
+ XGMAC_IOWRITE_BITS(pdata, MTL_OMR, ETSALG, MTL_ETSALG_DWRR);
|
|
|
|
+
|
|
|
|
+ /* Set Traffic Class algorithms */
|
|
|
|
+ total_weight = pdata->netdev->mtu * pdata->hw_feat.tc_cnt;
|
|
|
|
+ min_weight = total_weight / 100;
|
|
|
|
+ if (!min_weight)
|
|
|
|
+ min_weight = 1;
|
|
|
|
+
|
|
|
|
+ for (i = 0; i < pdata->hw_feat.tc_cnt; i++) {
|
|
|
|
+ switch (ets->tc_tsa[i]) {
|
|
|
|
+ case IEEE_8021QAZ_TSA_STRICT:
|
|
|
|
+ DBGPR(" TC%u using SP\n", i);
|
|
|
|
+ XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_TC_ETSCR, TSA,
|
|
|
|
+ MTL_TSA_SP);
|
|
|
|
+ break;
|
|
|
|
+ case IEEE_8021QAZ_TSA_ETS:
|
|
|
|
+ weight = total_weight * ets->tc_tx_bw[i] / 100;
|
|
|
|
+ weight = clamp(weight, min_weight, total_weight);
|
|
|
|
+
|
|
|
|
+ DBGPR(" TC%u using DWRR (weight %u)\n", i, weight);
|
|
|
|
+ XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_TC_ETSCR, TSA,
|
|
|
|
+ MTL_TSA_ETS);
|
|
|
|
+ XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_TC_QWR, QW,
|
|
|
|
+ weight);
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void xgbe_config_dcb_pfc(struct xgbe_prv_data *pdata)
|
|
|
|
+{
|
|
|
|
+ struct ieee_pfc *pfc = pdata->pfc;
|
|
|
|
+ struct ieee_ets *ets = pdata->ets;
|
|
|
|
+ unsigned int mask, reg, reg_val;
|
|
|
|
+ unsigned int tc, prio;
|
|
|
|
+
|
|
|
|
+ if (!pfc || !ets)
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ for (tc = 0; tc < pdata->hw_feat.tc_cnt; tc++) {
|
|
|
|
+ mask = 0;
|
|
|
|
+ for (prio = 0; prio < IEEE_8021QAZ_MAX_TCS; prio++) {
|
|
|
|
+ if ((pfc->pfc_en & (1 << prio)) &&
|
|
|
|
+ (ets->prio_tc[prio] == tc))
|
|
|
|
+ mask |= (1 << prio);
|
|
|
|
+ }
|
|
|
|
+ mask &= 0xff;
|
|
|
|
+
|
|
|
|
+ DBGPR(" TC%u PFC mask=%#x\n", tc, mask);
|
|
|
|
+ reg = MTL_TCPM0R + (MTL_TCPM_INC * (tc / MTL_TCPM_TC_PER_REG));
|
|
|
|
+ reg_val = XGMAC_IOREAD(pdata, reg);
|
|
|
|
+
|
|
|
|
+ reg_val &= ~(0xff << ((tc % MTL_TCPM_TC_PER_REG) << 3));
|
|
|
|
+ reg_val |= (mask << ((tc % MTL_TCPM_TC_PER_REG) << 3));
|
|
|
|
+
|
|
|
|
+ XGMAC_IOWRITE(pdata, reg, reg_val);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ xgbe_config_flow_control(pdata);
|
|
|
|
+}
|
|
|
|
+
|
|
static void xgbe_pre_xmit(struct xgbe_channel *channel)
|
|
static void xgbe_pre_xmit(struct xgbe_channel *channel)
|
|
{
|
|
{
|
|
struct xgbe_prv_data *pdata = channel->pdata;
|
|
struct xgbe_prv_data *pdata = channel->pdata;
|
|
@@ -1110,6 +1297,10 @@ static void xgbe_pre_xmit(struct xgbe_channel *channel)
|
|
XGMAC_SET_BITS_LE(rdesc->desc2, TX_NORMAL_DESC2, VTIR,
|
|
XGMAC_SET_BITS_LE(rdesc->desc2, TX_NORMAL_DESC2, VTIR,
|
|
TX_NORMAL_DESC2_VLAN_INSERT);
|
|
TX_NORMAL_DESC2_VLAN_INSERT);
|
|
|
|
|
|
|
|
+ /* Timestamp enablement check */
|
|
|
|
+ if (XGMAC_GET_BITS(packet->attributes, TX_PACKET_ATTRIBUTES, PTP))
|
|
|
|
+ XGMAC_SET_BITS_LE(rdesc->desc2, TX_NORMAL_DESC2, TTSE, 1);
|
|
|
|
+
|
|
/* Set IC bit based on Tx coalescing settings */
|
|
/* Set IC bit based on Tx coalescing settings */
|
|
XGMAC_SET_BITS_LE(rdesc->desc2, TX_NORMAL_DESC2, IC, 1);
|
|
XGMAC_SET_BITS_LE(rdesc->desc2, TX_NORMAL_DESC2, IC, 1);
|
|
if (tx_coalesce && (!tx_frames ||
|
|
if (tx_coalesce && (!tx_frames ||
|
|
@@ -1245,6 +1436,25 @@ static int xgbe_dev_read(struct xgbe_channel *channel)
|
|
xgbe_dump_rx_desc(ring, rdesc, ring->cur);
|
|
xgbe_dump_rx_desc(ring, rdesc, ring->cur);
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
+ if (XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, CTXT)) {
|
|
|
|
+ /* Timestamp Context Descriptor */
|
|
|
|
+ xgbe_get_rx_tstamp(packet, rdesc);
|
|
|
|
+
|
|
|
|
+ XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES,
|
|
|
|
+ CONTEXT, 1);
|
|
|
|
+ XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES,
|
|
|
|
+ CONTEXT_NEXT, 0);
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Normal Descriptor, be sure Context Descriptor bit is off */
|
|
|
|
+ XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES, CONTEXT, 0);
|
|
|
|
+
|
|
|
|
+ /* Indicate if a Context Descriptor is next */
|
|
|
|
+ if (XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, CDA))
|
|
|
|
+ XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES,
|
|
|
|
+ CONTEXT_NEXT, 1);
|
|
|
|
+
|
|
/* Get the packet length */
|
|
/* Get the packet length */
|
|
rdata->len = XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, PL);
|
|
rdata->len = XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, PL);
|
|
|
|
|
|
@@ -1423,11 +1633,11 @@ static int xgbe_flush_tx_queues(struct xgbe_prv_data *pdata)
|
|
{
|
|
{
|
|
unsigned int i, count;
|
|
unsigned int i, count;
|
|
|
|
|
|
- for (i = 0; i < pdata->hw_feat.tx_q_cnt; i++)
|
|
|
|
|
|
+ for (i = 0; i < pdata->tx_q_count; i++)
|
|
XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_TQOMR, FTQ, 1);
|
|
XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_TQOMR, FTQ, 1);
|
|
|
|
|
|
/* Poll Until Poll Condition */
|
|
/* Poll Until Poll Condition */
|
|
- for (i = 0; i < pdata->hw_feat.tx_q_cnt; i++) {
|
|
|
|
|
|
+ for (i = 0; i < pdata->tx_q_count; i++) {
|
|
count = 2000;
|
|
count = 2000;
|
|
while (count-- && XGMAC_MTL_IOREAD_BITS(pdata, i,
|
|
while (count-- && XGMAC_MTL_IOREAD_BITS(pdata, i,
|
|
MTL_Q_TQOMR, FTQ))
|
|
MTL_Q_TQOMR, FTQ))
|
|
@@ -1479,14 +1689,15 @@ static void xgbe_config_mtl_mode(struct xgbe_prv_data *pdata)
|
|
{
|
|
{
|
|
unsigned int i;
|
|
unsigned int i;
|
|
|
|
|
|
- /* Set Tx to weighted round robin scheduling algorithm (when
|
|
|
|
- * traffic class is using ETS algorithm)
|
|
|
|
- */
|
|
|
|
|
|
+ /* Set Tx to weighted round robin scheduling algorithm */
|
|
XGMAC_IOWRITE_BITS(pdata, MTL_OMR, ETSALG, MTL_ETSALG_WRR);
|
|
XGMAC_IOWRITE_BITS(pdata, MTL_OMR, ETSALG, MTL_ETSALG_WRR);
|
|
|
|
|
|
- /* Set Tx traffic classes to strict priority algorithm */
|
|
|
|
- for (i = 0; i < XGBE_TC_CNT; i++)
|
|
|
|
- XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_TC_ETSCR, TSA, MTL_TSA_SP);
|
|
|
|
|
|
+ /* Set Tx traffic classes to use WRR algorithm with equal weights */
|
|
|
|
+ for (i = 0; i < pdata->hw_feat.tc_cnt; i++) {
|
|
|
|
+ XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_TC_ETSCR, TSA,
|
|
|
|
+ MTL_TSA_ETS);
|
|
|
|
+ XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_TC_QWR, QW, 1);
|
|
|
|
+ }
|
|
|
|
|
|
/* Set Rx to strict priority algorithm */
|
|
/* Set Rx to strict priority algorithm */
|
|
XGMAC_IOWRITE_BITS(pdata, MTL_OMR, RAA, MTL_RAA_SP);
|
|
XGMAC_IOWRITE_BITS(pdata, MTL_OMR, RAA, MTL_RAA_SP);
|
|
@@ -1572,13 +1783,13 @@ static void xgbe_config_tx_fifo_size(struct xgbe_prv_data *pdata)
|
|
unsigned int i;
|
|
unsigned int i;
|
|
|
|
|
|
fifo_size = xgbe_calculate_per_queue_fifo(pdata->hw_feat.tx_fifo_size,
|
|
fifo_size = xgbe_calculate_per_queue_fifo(pdata->hw_feat.tx_fifo_size,
|
|
- pdata->hw_feat.tx_q_cnt);
|
|
|
|
|
|
+ pdata->tx_q_count);
|
|
|
|
|
|
- for (i = 0; i < pdata->hw_feat.tx_q_cnt; i++)
|
|
|
|
|
|
+ for (i = 0; i < pdata->tx_q_count; i++)
|
|
XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_TQOMR, TQS, fifo_size);
|
|
XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_TQOMR, TQS, fifo_size);
|
|
|
|
|
|
netdev_notice(pdata->netdev, "%d Tx queues, %d byte fifo per queue\n",
|
|
netdev_notice(pdata->netdev, "%d Tx queues, %d byte fifo per queue\n",
|
|
- pdata->hw_feat.tx_q_cnt, ((fifo_size + 1) * 256));
|
|
|
|
|
|
+ pdata->tx_q_count, ((fifo_size + 1) * 256));
|
|
}
|
|
}
|
|
|
|
|
|
static void xgbe_config_rx_fifo_size(struct xgbe_prv_data *pdata)
|
|
static void xgbe_config_rx_fifo_size(struct xgbe_prv_data *pdata)
|
|
@@ -1587,27 +1798,84 @@ static void xgbe_config_rx_fifo_size(struct xgbe_prv_data *pdata)
|
|
unsigned int i;
|
|
unsigned int i;
|
|
|
|
|
|
fifo_size = xgbe_calculate_per_queue_fifo(pdata->hw_feat.rx_fifo_size,
|
|
fifo_size = xgbe_calculate_per_queue_fifo(pdata->hw_feat.rx_fifo_size,
|
|
- pdata->hw_feat.rx_q_cnt);
|
|
|
|
|
|
+ pdata->rx_q_count);
|
|
|
|
|
|
- for (i = 0; i < pdata->hw_feat.rx_q_cnt; i++)
|
|
|
|
|
|
+ for (i = 0; i < pdata->rx_q_count; i++)
|
|
XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_RQOMR, RQS, fifo_size);
|
|
XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_RQOMR, RQS, fifo_size);
|
|
|
|
|
|
netdev_notice(pdata->netdev, "%d Rx queues, %d byte fifo per queue\n",
|
|
netdev_notice(pdata->netdev, "%d Rx queues, %d byte fifo per queue\n",
|
|
- pdata->hw_feat.rx_q_cnt, ((fifo_size + 1) * 256));
|
|
|
|
|
|
+ pdata->rx_q_count, ((fifo_size + 1) * 256));
|
|
}
|
|
}
|
|
|
|
|
|
-static void xgbe_config_rx_queue_mapping(struct xgbe_prv_data *pdata)
|
|
|
|
|
|
+static void xgbe_config_queue_mapping(struct xgbe_prv_data *pdata)
|
|
{
|
|
{
|
|
- unsigned int i, reg, reg_val;
|
|
|
|
- unsigned int q_count = pdata->hw_feat.rx_q_cnt;
|
|
|
|
|
|
+ unsigned int qptc, qptc_extra, queue;
|
|
|
|
+ unsigned int prio_queues;
|
|
|
|
+ unsigned int ppq, ppq_extra, prio;
|
|
|
|
+ unsigned int mask;
|
|
|
|
+ unsigned int i, j, reg, reg_val;
|
|
|
|
+
|
|
|
|
+ /* Map the MTL Tx Queues to Traffic Classes
|
|
|
|
+ * Note: Tx Queues >= Traffic Classes
|
|
|
|
+ */
|
|
|
|
+ qptc = pdata->tx_q_count / pdata->hw_feat.tc_cnt;
|
|
|
|
+ qptc_extra = pdata->tx_q_count % pdata->hw_feat.tc_cnt;
|
|
|
|
+
|
|
|
|
+ for (i = 0, queue = 0; i < pdata->hw_feat.tc_cnt; i++) {
|
|
|
|
+ for (j = 0; j < qptc; j++) {
|
|
|
|
+ DBGPR(" TXq%u mapped to TC%u\n", queue, i);
|
|
|
|
+ XGMAC_MTL_IOWRITE_BITS(pdata, queue, MTL_Q_TQOMR,
|
|
|
|
+ Q2TCMAP, i);
|
|
|
|
+ pdata->q2tc_map[queue++] = i;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (i < qptc_extra) {
|
|
|
|
+ DBGPR(" TXq%u mapped to TC%u\n", queue, i);
|
|
|
|
+ XGMAC_MTL_IOWRITE_BITS(pdata, queue, MTL_Q_TQOMR,
|
|
|
|
+ Q2TCMAP, i);
|
|
|
|
+ pdata->q2tc_map[queue++] = i;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Map the 8 VLAN priority values to available MTL Rx queues */
|
|
|
|
+ prio_queues = min_t(unsigned int, IEEE_8021QAZ_MAX_TCS,
|
|
|
|
+ pdata->rx_q_count);
|
|
|
|
+ ppq = IEEE_8021QAZ_MAX_TCS / prio_queues;
|
|
|
|
+ ppq_extra = IEEE_8021QAZ_MAX_TCS % prio_queues;
|
|
|
|
+
|
|
|
|
+ reg = MAC_RQC2R;
|
|
|
|
+ reg_val = 0;
|
|
|
|
+ for (i = 0, prio = 0; i < prio_queues;) {
|
|
|
|
+ mask = 0;
|
|
|
|
+ for (j = 0; j < ppq; j++) {
|
|
|
|
+ DBGPR(" PRIO%u mapped to RXq%u\n", prio, i);
|
|
|
|
+ mask |= (1 << prio);
|
|
|
|
+ pdata->prio2q_map[prio++] = i;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (i < ppq_extra) {
|
|
|
|
+ DBGPR(" PRIO%u mapped to RXq%u\n", prio, i);
|
|
|
|
+ mask |= (1 << prio);
|
|
|
|
+ pdata->prio2q_map[prio++] = i;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ reg_val |= (mask << ((i++ % MAC_RQC2_Q_PER_REG) << 3));
|
|
|
|
+
|
|
|
|
+ if ((i % MAC_RQC2_Q_PER_REG) && (i != prio_queues))
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ XGMAC_IOWRITE(pdata, reg, reg_val);
|
|
|
|
+ reg += MAC_RQC2_INC;
|
|
|
|
+ reg_val = 0;
|
|
|
|
+ }
|
|
|
|
|
|
/* Select dynamic mapping of MTL Rx queue to DMA Rx channel */
|
|
/* Select dynamic mapping of MTL Rx queue to DMA Rx channel */
|
|
reg = MTL_RQDCM0R;
|
|
reg = MTL_RQDCM0R;
|
|
reg_val = 0;
|
|
reg_val = 0;
|
|
- for (i = 0; i < q_count;) {
|
|
|
|
|
|
+ for (i = 0; i < pdata->rx_q_count;) {
|
|
reg_val |= (0x80 << ((i++ % MTL_RQDCM_Q_PER_REG) << 3));
|
|
reg_val |= (0x80 << ((i++ % MTL_RQDCM_Q_PER_REG) << 3));
|
|
|
|
|
|
- if ((i % MTL_RQDCM_Q_PER_REG) && (i != q_count))
|
|
|
|
|
|
+ if ((i % MTL_RQDCM_Q_PER_REG) && (i != pdata->rx_q_count))
|
|
continue;
|
|
continue;
|
|
|
|
|
|
XGMAC_IOWRITE(pdata, reg, reg_val);
|
|
XGMAC_IOWRITE(pdata, reg, reg_val);
|
|
@@ -1621,7 +1889,7 @@ static void xgbe_config_flow_control_threshold(struct xgbe_prv_data *pdata)
|
|
{
|
|
{
|
|
unsigned int i;
|
|
unsigned int i;
|
|
|
|
|
|
- for (i = 0; i < pdata->hw_feat.rx_q_cnt; i++) {
|
|
|
|
|
|
+ for (i = 0; i < pdata->rx_q_count; i++) {
|
|
/* Activate flow control when less than 4k left in fifo */
|
|
/* Activate flow control when less than 4k left in fifo */
|
|
XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_RQOMR, RFA, 2);
|
|
XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_RQOMR, RFA, 2);
|
|
|
|
|
|
@@ -2013,7 +2281,7 @@ static void xgbe_enable_tx(struct xgbe_prv_data *pdata)
|
|
}
|
|
}
|
|
|
|
|
|
/* Enable each Tx queue */
|
|
/* Enable each Tx queue */
|
|
- for (i = 0; i < pdata->hw_feat.tx_q_cnt; i++)
|
|
|
|
|
|
+ for (i = 0; i < pdata->tx_q_count; i++)
|
|
XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_TQOMR, TXQEN,
|
|
XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_TQOMR, TXQEN,
|
|
MTL_Q_ENABLED);
|
|
MTL_Q_ENABLED);
|
|
|
|
|
|
@@ -2030,7 +2298,7 @@ static void xgbe_disable_tx(struct xgbe_prv_data *pdata)
|
|
XGMAC_IOWRITE_BITS(pdata, MAC_TCR, TE, 0);
|
|
XGMAC_IOWRITE_BITS(pdata, MAC_TCR, TE, 0);
|
|
|
|
|
|
/* Disable each Tx queue */
|
|
/* Disable each Tx queue */
|
|
- for (i = 0; i < pdata->hw_feat.tx_q_cnt; i++)
|
|
|
|
|
|
+ for (i = 0; i < pdata->tx_q_count; i++)
|
|
XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_TQOMR, TXQEN, 0);
|
|
XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_TQOMR, TXQEN, 0);
|
|
|
|
|
|
/* Disable each Tx DMA channel */
|
|
/* Disable each Tx DMA channel */
|
|
@@ -2059,7 +2327,7 @@ static void xgbe_enable_rx(struct xgbe_prv_data *pdata)
|
|
|
|
|
|
/* Enable each Rx queue */
|
|
/* Enable each Rx queue */
|
|
reg_val = 0;
|
|
reg_val = 0;
|
|
- for (i = 0; i < pdata->hw_feat.rx_q_cnt; i++)
|
|
|
|
|
|
+ for (i = 0; i < pdata->rx_q_count; i++)
|
|
reg_val |= (0x02 << (i << 1));
|
|
reg_val |= (0x02 << (i << 1));
|
|
XGMAC_IOWRITE(pdata, MAC_RQC0R, reg_val);
|
|
XGMAC_IOWRITE(pdata, MAC_RQC0R, reg_val);
|
|
|
|
|
|
@@ -2193,9 +2461,7 @@ static int xgbe_init(struct xgbe_prv_data *pdata)
|
|
* Initialize MTL related features
|
|
* Initialize MTL related features
|
|
*/
|
|
*/
|
|
xgbe_config_mtl_mode(pdata);
|
|
xgbe_config_mtl_mode(pdata);
|
|
- xgbe_config_rx_queue_mapping(pdata);
|
|
|
|
- /*TODO: Program the priorities mapped to the Selected Traffic Classes
|
|
|
|
- in MTL_TC_Prty_Map0-3 registers */
|
|
|
|
|
|
+ xgbe_config_queue_mapping(pdata);
|
|
xgbe_config_tsf_mode(pdata, pdata->tx_sf_mode);
|
|
xgbe_config_tsf_mode(pdata, pdata->tx_sf_mode);
|
|
xgbe_config_rsf_mode(pdata, pdata->rx_sf_mode);
|
|
xgbe_config_rsf_mode(pdata, pdata->rx_sf_mode);
|
|
xgbe_config_tx_threshold(pdata, pdata->tx_threshold);
|
|
xgbe_config_tx_threshold(pdata, pdata->tx_threshold);
|
|
@@ -2203,15 +2469,13 @@ static int xgbe_init(struct xgbe_prv_data *pdata)
|
|
xgbe_config_tx_fifo_size(pdata);
|
|
xgbe_config_tx_fifo_size(pdata);
|
|
xgbe_config_rx_fifo_size(pdata);
|
|
xgbe_config_rx_fifo_size(pdata);
|
|
xgbe_config_flow_control_threshold(pdata);
|
|
xgbe_config_flow_control_threshold(pdata);
|
|
- /*TODO: Queue to Traffic Class Mapping (Q2TCMAP) */
|
|
|
|
/*TODO: Error Packet and undersized good Packet forwarding enable
|
|
/*TODO: Error Packet and undersized good Packet forwarding enable
|
|
(FEP and FUP)
|
|
(FEP and FUP)
|
|
*/
|
|
*/
|
|
|
|
+ xgbe_config_dcb_tc(pdata);
|
|
|
|
+ xgbe_config_dcb_pfc(pdata);
|
|
xgbe_enable_mtl_interrupts(pdata);
|
|
xgbe_enable_mtl_interrupts(pdata);
|
|
|
|
|
|
- /* Transmit Class Weight */
|
|
|
|
- XGMAC_IOWRITE_BITS(pdata, MTL_Q_TCQWR, QW, 0x10);
|
|
|
|
-
|
|
|
|
/*
|
|
/*
|
|
* Initialize MAC related features
|
|
* Initialize MAC related features
|
|
*/
|
|
*/
|
|
@@ -2313,5 +2577,16 @@ void xgbe_init_function_ptrs_dev(struct xgbe_hw_if *hw_if)
|
|
hw_if->rx_mmc_int = xgbe_rx_mmc_int;
|
|
hw_if->rx_mmc_int = xgbe_rx_mmc_int;
|
|
hw_if->read_mmc_stats = xgbe_read_mmc_stats;
|
|
hw_if->read_mmc_stats = xgbe_read_mmc_stats;
|
|
|
|
|
|
|
|
+ /* For PTP config */
|
|
|
|
+ hw_if->config_tstamp = xgbe_config_tstamp;
|
|
|
|
+ hw_if->update_tstamp_addend = xgbe_update_tstamp_addend;
|
|
|
|
+ hw_if->set_tstamp_time = xgbe_set_tstamp_time;
|
|
|
|
+ hw_if->get_tstamp_time = xgbe_get_tstamp_time;
|
|
|
|
+ hw_if->get_tx_tstamp = xgbe_get_tx_tstamp;
|
|
|
|
+
|
|
|
|
+ /* For Data Center Bridging config */
|
|
|
|
+ hw_if->config_dcb_tc = xgbe_config_dcb_tc;
|
|
|
|
+ hw_if->config_dcb_pfc = xgbe_config_dcb_pfc;
|
|
|
|
+
|
|
DBGPR("<--xgbe_init_function_ptrs\n");
|
|
DBGPR("<--xgbe_init_function_ptrs\n");
|
|
}
|
|
}
|