Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 87122cfb authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: emac: multiple interrupt support for RSS feature"

parents 1f95d8db ee03bfe5
Loading
Loading
Loading
Loading
+18 −2
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@
#define _MSM_EMAC_H_

#include <asm/byteorder.h>
#include <linux/interrupt.h>
#include <linux/netdevice.h>

/* Device IDs */
@@ -28,6 +29,8 @@
#define EMAC_DMA_ADDR_LO(_addr) \
		((u32)((u64)(_addr) & DMA_ADDR_LO_MASK))

#define EMAC_NUM_CORE_IRQ     4

#define EMAC_LINK_SPEED_UNKNOWN         0x0
#define EMAC_LINK_SPEED_10_HALF         0x0001
#define EMAC_LINK_SPEED_10_FULL         0x0002
@@ -161,7 +164,6 @@ struct emac_hw {

	u16     devid;
	u16     revid;
	u32     intr_mask;

	/* ring parameter */
	u8      tpd_burst;
@@ -449,6 +451,19 @@ union emac_sw_tpdesc {
#define EMAC_TPD_LAST_FRAGMENT  0x80000000
#define EMAC_TPD_TSTAMP_SAVE    0x80000000

struct emac_irq_info {
	unsigned int irq;
	char *name;
	irq_handler_t handler;

	u32 status_reg;
	u32 mask_reg;
	u32 mask;

	struct emac_rx_queue *rxque;
	struct emac_adapter  *adpt;
};

/* emac_ring_header represents a single, contiguous block of DMA space
 * mapped for the three descriptor rings (tpd, rfd, rrd)
 */
@@ -512,6 +527,7 @@ struct emac_rx_queue {
	u8 consume_shft;

	u32 intr;
	struct emac_irq_info *irq_info;
};

#define GET_RFD_BUFFER(_rque, _i)    (&((_rque)->rfd.rfbuff[(_i)]))
@@ -551,7 +567,7 @@ struct emac_tx_queue {
struct emac_adapter {
	struct net_device *netdev;

	unsigned int irq;
	struct emac_irq_info *irq_info;

	/* dma parameters */
	u64                             dma_mask;
+19 −4
Original line number Diff line number Diff line
@@ -331,15 +331,30 @@ int emac_check_phy_link(struct emac_hw *hw, u32 *speed, bool *link_up)
/* INTR */
void emac_hw_enable_intr(struct emac_hw *hw)
{
	emac_reg_w32(hw, EMAC, EMAC_INT_STATUS, ~DIS_INT);
	emac_reg_w32(hw, EMAC, EMAC_INT_MASK, hw->intr_mask);
	struct emac_adapter *adpt = hw->adpt;
	struct emac_irq_info *irq_info;
	int i;

	for (i = 0; i < EMAC_NUM_CORE_IRQ; i++) {
		irq_info = &adpt->irq_info[i];
		emac_reg_w32(hw, EMAC, irq_info->status_reg, ~DIS_INT);
		emac_reg_w32(hw, EMAC, irq_info->mask_reg, irq_info->mask);
	}
	wmb();
}

void emac_hw_disable_intr(struct emac_hw *hw)
{
	emac_reg_w32(hw, EMAC, EMAC_INT_STATUS, DIS_INT);
	emac_reg_w32(hw, EMAC, EMAC_INT_MASK, 0);
	struct emac_adapter *adpt = hw->adpt;
	struct emac_irq_info *irq_info;
	int i;

	for (i = 0; i < EMAC_NUM_CORE_IRQ; i++) {
		irq_info = &adpt->irq_info[i];
		emac_reg_w32(hw, EMAC, irq_info->status_reg, DIS_INT);
		emac_reg_w32(hw, EMAC, irq_info->mask_reg, 0);
	}

	emac_reg_w32(hw, EMAC_1588, EMAC_P1588_PTP_EXPANDED_INT_MASK, 0);
	wmb();
}
+1 −7
Original line number Diff line number Diff line
@@ -71,14 +71,8 @@ extern void emac_hw_set_mac_addr(struct emac_hw *hw, u8 *addr);
		ISR_ERROR       |\
		ISR_GPHY_LINK   |\
		ISR_TX_PKT      |\
		ISR_RX_PKT      |\
		GPHY_WAKEUP_INT)

#define ISR_RX_PKT      (\
		RX_PKT_INT0     |\
	RX_PKT_INT1     |\
	RX_PKT_INT2     |\
	RX_PKT_INT3)
		GPHY_WAKEUP_INT)

#define ISR_TX_PKT      (\
	TX_PKT_INT      |\
+68 −46
Original line number Diff line number Diff line
@@ -38,9 +38,6 @@ const char emac_drv_version[] = DRV_VERSION;
		NETIF_MSG_INTR | NETIF_MSG_TX_DONE | NETIF_MSG_RX_STATUS |    \
		NETIF_MSG_PKTDATA | NETIF_MSG_HW | NETIF_MSG_WOL)

/* irq numbers should come from device tree */
#define EMAC_CORE0_IRQ        0

#define EMAC_RRDESC_SIZE      4
#define EMAC_TS_RRDESC_SIZE   6
#define EMAC_TPDESC_SIZE      4
@@ -53,6 +50,26 @@ module_param_named(msglvl, msm_emac_msglvl, int, S_IRUGO | S_IWUSR | S_IWGRP);

static int emac_up(struct emac_adapter *adpt);
static void emac_down(struct emac_adapter *adpt, u32 ctrl);
static irqreturn_t emac_interrupt(int irq, void *data);

/* EMAC HW has an issue with interrupt assignment because of which
   following receive rss queue to interrupt mapping is used.
   intr      rss-queue
   core0       0, 1
   core1       2
   core2       3
   core3       x (unsigned)
*/
static struct emac_irq_info emac_irq[EMAC_NUM_CORE_IRQ] = {
	{ 0, "emac_core0_irq", emac_interrupt, EMAC_INT_STATUS,
	  EMAC_INT_MASK, IMR_NORMAL_MASK | RX_PKT_INT1, NULL, NULL },
	{ 0, "emac_core1_irq", emac_interrupt, EMAC_INT1_STATUS,
	  EMAC_INT1_MASK, RX_PKT_INT2, NULL, NULL },
	{ 0, "emac_core2_irq", emac_interrupt, EMAC_INT2_STATUS,
	  EMAC_INT2_MASK, RX_PKT_INT3, NULL, NULL },
	{ 0, "emac_core3_irq", emac_interrupt, EMAC_INT3_STATUS,
	  EMAC_INT3_MASK, 0, NULL, NULL },
};

/* reinitialize */
void emac_reinit_locked(struct emac_adapter *adpt)
@@ -526,6 +543,7 @@ static int emac_napi_rtx(struct napi_struct *napi, int budget)
	struct emac_rx_queue *rxque = container_of(napi, struct emac_rx_queue,
						   napi);
	struct emac_adapter *adpt = netdev_priv(rxque->netdev);
	struct emac_irq_info *irq_info = rxque->irq_info;
	struct emac_hw *hw = &adpt->hw;
	int work_done = 0;

@@ -538,8 +556,9 @@ static int emac_napi_rtx(struct napi_struct *napi, int budget)
	if (work_done < budget) {
quit_polling:
		napi_complete(napi);
		adpt->hw.intr_mask |= rxque->intr;
		emac_reg_w32(hw, EMAC, EMAC_INT_MASK, hw->intr_mask);

		irq_info->mask |= rxque->intr;
		emac_reg_w32(hw, EMAC, irq_info->mask_reg, irq_info->mask);
		wmb();
	}

@@ -801,19 +820,18 @@ static int emac_start_xmit(struct sk_buff *skb,
/* ISR */
static irqreturn_t emac_interrupt(int irq, void *data)
{
	struct net_device *netdev = data;
	struct emac_adapter *adpt = netdev_priv(netdev);
	struct emac_irq_info *irq_info = data;
	struct emac_adapter *adpt = irq_info->adpt;
	struct emac_hw *hw = &adpt->hw;
	int max_ints = EMAC_MAX_HANDLED_INTRS;
	u32 isr, status;
	u8 i;

	do {
		isr = emac_reg_r32(hw, EMAC, EMAC_INT_STATUS);
		status = isr & hw->intr_mask;
		isr = emac_reg_r32(hw, EMAC, irq_info->status_reg);
		status = isr & irq_info->mask;

		if (status == 0) {
			emac_reg_w32(hw, EMAC, EMAC_INT_STATUS, 0);
			emac_reg_w32(hw, EMAC, irq_info->status_reg, 0);
			wmb();
			if (max_ints != EMAC_MAX_HANDLED_INTRS)
				return IRQ_HANDLED;
@@ -825,7 +843,7 @@ static irqreturn_t emac_interrupt(int irq, void *data)
			emac_hw_ack_phy_intr(hw);

		/* Ack MAC interrupt and disable the interrupt */
		emac_reg_w32(hw, EMAC, EMAC_INT_STATUS, status | DIS_INT);
		emac_reg_w32(hw, EMAC, irq_info->status_reg, status | DIS_INT);
		wmb();

		if (status & ISR_ERROR) {
@@ -834,21 +852,17 @@ static irqreturn_t emac_interrupt(int irq, void *data)
			/* reset MAC */
			SET_ADPT_FLAG(TASK_REINIT_REQ);
			emac_task_schedule(adpt);
			return IRQ_HANDLED;
		}

		/* Schedule the napi for receive queue with interrupt
		 * status bit set
		 */
		for (i = 0; i < adpt->num_rxques; i++) {
			if (!(status & adpt->rx_queue[i].intr))
				continue;

			if (napi_schedule_prep(&adpt->rx_queue[i].napi)) {
				hw->intr_mask &= ~adpt->rx_queue[i].intr;
				emac_reg_w32(hw, EMAC, EMAC_INT_MASK,
					     hw->intr_mask);
				__napi_schedule(&adpt->rx_queue[i].napi);
		if ((status & irq_info->rxque->intr)) {
			if (napi_schedule_prep(&irq_info->rxque->napi)) {
				irq_info->mask &= ~irq_info->rxque->intr;
				emac_reg_w32(hw, EMAC, irq_info->mask_reg,
					     irq_info->mask);
				__napi_schedule(&irq_info->rxque->napi);
			}
		}

@@ -877,7 +891,7 @@ static irqreturn_t emac_interrupt(int irq, void *data)
	} while (--max_ints > 0);

	/* enable the interrupt */
	emac_reg_w32(hw, EMAC, EMAC_INT_STATUS, 0);
	emac_reg_w32(hw, EMAC, irq_info->status_reg, 0);
	wmb();
	return IRQ_HANDLED;
}
@@ -894,9 +908,11 @@ static inline void emac_enable_intr(struct emac_adapter *adpt)
static inline void emac_disable_intr(struct emac_adapter *adpt)
{
	struct emac_hw *hw = &adpt->hw;
	int i;

	emac_hw_disable_intr(hw);
	synchronize_irq(adpt->irq);
	for (i = 0; i < EMAC_NUM_CORE_IRQ; i++)
		synchronize_irq(adpt->irq_info[i].irq);
}

/* Configure VLAN tag strip/insert feature */
@@ -1301,6 +1317,7 @@ static void emac_config_rss(struct emac_adapter *adpt)
		for (i = 0, j = 0; i < EMAC_RSS_IDT_SIZE; i++, j++) {
			if (j == adpt->num_rxques)
				j = 0;
			if (j > 1)
				reta |= (j << ((i & 7) * 4));
			if ((i & 7) == 7) {
				hw->rss_idt[i>>3] = reta;
@@ -1338,18 +1355,6 @@ static int emac_change_mtu(struct net_device *netdev, int new_mtu)
	return 0;
}

static inline int emac_request_irq(unsigned int irq, irq_handler_t handler,
				   unsigned long flags, const char *name,
				   void *dev)
{
	return request_irq(irq, handler, flags, name, dev);
}

static inline void emac_free_irq(unsigned int irq, void *dev)
{
	free_irq(irq, dev);
}

/* Bringup the interface/HW */
static int emac_up(struct emac_adapter *adpt)
{
@@ -1367,12 +1372,19 @@ static int emac_up(struct emac_adapter *adpt)
	for (i = 0; i < adpt->num_rxques; i++)
		emac_refresh_rx_buffer(&adpt->rx_queue[i]);

	retval = emac_request_irq(adpt->irq, emac_interrupt, IRQF_SHARED,
				  netdev->name, netdev);
	for (i = 0; i < EMAC_NUM_CORE_IRQ; i++) {
		struct emac_irq_info *irq_info = &adpt->irq_info[i];
		retval = request_irq(irq_info->irq, irq_info->handler,
				     0, irq_info->name, irq_info);
		if (retval) {
		emac_err(adpt, "Unable to allocate interrupt (%d)\n", retval);
			emac_err(adpt, "Unable to allocate interrupt %d: %d\n",
				 irq_info->irq, retval);
			while (--i >= 0)
				free_irq(adpt->irq_info[i].irq,
					 &adpt->irq_info[i]);
			goto err_request_irq;
		}
	}

	emac_napi_enable_all(adpt);
	emac_enable_intr(adpt);
@@ -1397,6 +1409,7 @@ static void emac_down(struct emac_adapter *adpt, u32 ctrl)
{
	struct net_device *netdev = adpt->netdev;
	struct emac_hw *hw = &adpt->hw;
	int i;

	SET_ADPT_FLAG(STATE_DOWN);
	netif_stop_queue(netdev);
@@ -1405,7 +1418,8 @@ static void emac_down(struct emac_adapter *adpt, u32 ctrl)

	emac_disable_intr(adpt);
	emac_napi_disable_all(adpt);
	emac_free_irq(adpt->irq, netdev);
	for (i = 0; i < EMAC_NUM_CORE_IRQ; i++)
		free_irq(adpt->irq_info[i].irq, &adpt->irq_info[i]);

	CLI_ADPT_FLAG(TASK_LSC_REQ);
	CLI_ADPT_FLAG(TASK_REINIT_REQ);
@@ -1782,6 +1796,7 @@ static void emac_init_rtx_queues(struct platform_device *pdev,
		adpt->rx_queue[3].consume_shft = RFD3_CONS_IDX_SHFT;

		adpt->rx_queue[3].intr = RX_PKT_INT3;
		adpt->rx_queue[3].irq_info = &adpt->irq_info[3];
	case 3:
		adpt->rx_queue[2].produce_reg = EMAC_MAILBOX_6;
		adpt->rx_queue[2].produce_mask = RFD2_PROD_IDX_BMSK;
@@ -1796,6 +1811,7 @@ static void emac_init_rtx_queues(struct platform_device *pdev,
		adpt->rx_queue[2].consume_shft = RFD2_CONS_IDX_SHFT;

		adpt->rx_queue[2].intr = RX_PKT_INT2;
		adpt->rx_queue[2].irq_info = &adpt->irq_info[2];
	case 2:
		adpt->rx_queue[1].produce_reg = EMAC_MAILBOX_5;
		adpt->rx_queue[1].produce_mask = RFD1_PROD_IDX_BMSK;
@@ -1810,6 +1826,7 @@ static void emac_init_rtx_queues(struct platform_device *pdev,
		adpt->rx_queue[1].consume_shft = RFD1_CONS_IDX_SHFT;

		adpt->rx_queue[1].intr = RX_PKT_INT1;
		adpt->rx_queue[1].irq_info = &adpt->irq_info[1];
	case 1:
		adpt->rx_queue[0].produce_reg = EMAC_MAILBOX_0;
		adpt->rx_queue[0].produce_mask = RFD0_PROD_IDX_BMSK;
@@ -1824,6 +1841,7 @@ static void emac_init_rtx_queues(struct platform_device *pdev,
		adpt->rx_queue[0].consume_shft = RFD0_CONS_IDX_SHFT;

		adpt->rx_queue[0].intr = RX_PKT_INT0;
		adpt->rx_queue[0].irq_info = &adpt->irq_info[0];
		break;
	}

@@ -1915,7 +1933,6 @@ static void emac_init_adapter(struct emac_adapter *adpt)

	/* others */
	hw->preamble = EMAC_PREAMBLE_DEF;
	hw->intr_mask = IMR_NORMAL_MASK;
	adpt->wol = EMAC_WOL_MAGIC | EMAC_WOL_PHY;

	/* phy */
@@ -2080,7 +2097,6 @@ static int emac_get_resources(struct platform_device *pdev,
			adpt->hw.reg_addr[i] = reg_base[i];

		netdev->base_addr = (unsigned long)adpt->hw.reg_addr[EMAC];
		adpt->irq = EMAC_CORE0_IRQ;
	}

	return retval;
@@ -2136,10 +2152,16 @@ static int emac_probe(struct platform_device *pdev)
	if (retval)
		goto err_res;

	adpt->irq_info = emac_irq;
	for (i = 0; i < EMAC_NUM_CORE_IRQ; i++) {
		adpt->irq_info[i].adpt = adpt;
		adpt->irq_info[i].rxque = &adpt->rx_queue[i];
	}

	hw_ver = emac_reg_r32(hw, EMAC, EMAC_CORE_HW_VERSION);

	netdev->watchdog_timeo = EMAC_WATCHDOG_TIME;
	netdev->irq = adpt->irq;
	netdev->irq = adpt->irq_info[0].irq;

	if (adpt->tstamp_en)
		adpt->rrdesc_size = EMAC_TS_RRDESC_SIZE;
+6 −0
Original line number Diff line number Diff line
@@ -103,6 +103,12 @@
#define EMAC_TXMAC_STATC_REG25                   0x001bd0
#define EMAC_MAILBOX_15                          0x001bd4
#define EMAC_MAILBOX_16                          0x001bd8
#define EMAC_INT1_MASK                           0x001bf0
#define EMAC_INT1_STATUS                         0x001bf4
#define EMAC_INT2_MASK                           0x001bf8
#define EMAC_INT2_STATUS                         0x001bfc
#define EMAC_INT3_MASK                           0x001c00
#define EMAC_INT3_STATUS                         0x001c04

/* EMAC_CSR register offsets */
#define EMAC_EMAC_WRAPPER_CSR1                   0x000000