Thread (10 messages) flat view 10 messages, 4 authors, 2012-09-05
DORMANTno replies

[PATCH 1/4] net: mvneta: driver for Marvell Armada 370/XP network unit

From: florian@openwrt.org (Florian Fainelli)
Date: 2012-09-05 15:25:33
Also in: netdev

Hello Thomas,

The overall driver looks very nice, my biggest concern with this driver being 
that it does not implement phylib and therefore reimplements a bit of existing 
code. I am not commentin on how to represent this MDIO/PHY devices using 
Device Tree since this has been addressed already.

Once you register a MDIO bus for your interface, please make sure that you 
give it a unique name in the system (<pdev->name>-<pdev->id>).

Other comments inline.

On Tuesday 04 September 2012 15:06:41 Thomas Petazzoni wrote:
[snip]
+
+/* Increment txq get counter */
+static void mvneta_inc_get(struct mvneta_tx_queue *txq)
+{
+	txq->txq_get_index++;
+	if (txq->txq_get_index == txq->size)
+		txq->txq_get_index = 0;
+}
+
+/* Increment txq put counter */
+static void mvneta_inc_put(struct mvneta_tx_queue *txq)
+{
+	txq->txq_put_index++;
+	if (txq->txq_put_index == txq->size)
+		txq->txq_put_index = 0;
+}
I would make it clear that these helpers operate on the txq, and suffix it with 
_txq.
+
+
+/* Clear all MIB counters */
+static void mvneta_mib_counters_clear(struct mvneta_port *pp)
+{
+	int i;
+	u32 dummy;
+
+	/* Perform dummy reads from MIB counters */
+	for (i = 0; i < MVNETA_MIB_LATE_COLLISION; i += 4)
+		dummy = mvreg_read(pp, (MVNETA_MIB_COUNTERS_BASE + i));
+}
+
+/* Read speed, duplex, and flow control from port status register */
+static int mvneta_link_status(struct mvneta_port *pp,
+			      struct mvneta_lnk_status *status)
+{
+	u32 val;
+
+	val = mvreg_read(pp, MVNETA_GMAC_STATUS);
+
+	if (val & MVNETA_GMAC_SPEED_1000_MASK)
+		status->speed = MVNETA_SPEED_1000;
+	else if (val & MVNETA_GMAC_SPEED_100_MASK)
+		status->speed = MVNETA_SPEED_100;
+	else
+		status->speed = MVNETA_SPEED_10;
+
+	if (val & MVNETA_GMAC_LINK_UP_MASK)
+		status->linkup = 1;
+	else
+		status->linkup = 0;
+
+	if (val & MVNETA_GMAC_FULL_DUPLEX_MASK)
+		status->duplex = MVNETA_DUPLEX_FULL;
+	else
+		status->duplex = MVNETA_DUPLEX_HALF;
+
+	if (val & MVNETA_GMAC_TX_FLOW_CTRL_ACTIVE_MASK)
+		status->tx_fc = MVNETA_FC_ACTIVE;
+	else if (val & MVNETA_GMAC_TX_FLOW_CTRL_ENABLE_MASK)
+		status->tx_fc = MVNETA_FC_ENABLE;
+	else
+		status->tx_fc = MVNETA_FC_DISABLE;
+
+	if (val & MVNETA_GMAC_RX_FLOW_CTRL_ACTIVE_MASK)
+		status->rx_fc = MVNETA_FC_ACTIVE;
+	else if (val & MVNETA_GMAC_RX_FLOW_CTRL_ENABLE_MASK)
+		status->rx_fc = MVNETA_FC_ENABLE;
+	else
+		status->rx_fc = MVNETA_FC_DISABLE;
+
I would rather see you use a struct phy_device and update its properties 
instead of keeping a local copy of it. This would allow you to have consistent 
reporting through ethtool, I have more comments on this later on as well.

+static void mvneta_rxq_non_occup_desc_add(struct mvneta_port *pp,
+					  struct mvneta_rx_queue *rxq,
+					  int rx_desc)
+{
+	u32 val;
+
+	/* Only 255 descriptors can be added at once */
+	while (rx_desc > 0xff) {
+		val = (0xff << MVNETA_RXQ_ADD_NON_OCCUPIED_OFFS);
+		mvreg_write(pp, MVNETA_RXQ_STATUS_UPDATE_REG(rxq->id), val);
+		rx_desc = rx_desc - 0xff;
+	}
You could probably use a define here for 255/0xff.

[snip]
+	m_delay = 0;
This does not look like an useful name, count would be better
+	do {
+		if (m_delay >= MVNETA_RX_DISABLE_TIMEOUT_MSEC) {
+			netdev_info(pp->dev,
+				"TIMEOUT for RX stopped ! rx_queue_cmd: 0x08%x\n",
+				val);
Please use a different logging level such as netdev_err() or netdev_warn() for 
instance.
+			break;
+		}
+		mdelay(1);
+		m_delay++;
What about using msleep() instead here?
+
+		val = mvreg_read(pp, MVNETA_RXQ_CMD);
+	} while (val & 0xff);
+
+	/* Stop Tx port activity. Check port Tx activity. Issue stop
+	   command for active channels only  */
+	val = (mvreg_read(pp, MVNETA_TXQ_CMD)) & MVNETA_TXQ_ENABLE_MASK;
+
+	if (val != 0)
+		mvreg_write(pp, MVNETA_TXQ_CMD,
+			(val << MVNETA_TXQ_DISABLE_OFFS));
+
+	/* Wait for all Tx activity to terminate. */
+	m_delay = 0;
+	do {
+		if (m_delay >= MVNETA_TX_DISABLE_TIMEOUT_MSEC) {
+			netdev_info(pp->dev,
+				"TIMEOUT for TX stopped tx_queue_cmd - 0x%08x\n",
+				val);
+			break;
+		}
+		mdelay(1);
+		m_delay++;
+
+		/* Check TX Command reg that all Txqs are stopped */
+		val = mvreg_read(pp, MVNETA_TXQ_CMD);
Ditto
+
+	} while (val & 0xff);
+	tx_fifo_empty_mask |= MVNETA_TX_FIFO_EMPTY_MASK;
+	tx_in_prog_mask    |= MVNETA_TX_IN_PRGRS_MASK;
+
+	/* Double check to verify that TX FIFO is empty */
+	m_delay = 0;
+	while (1) {
+		do {
+			if (m_delay >= MVNETA_TX_FIFO_EMPTY_TIMEOUT) {
+				netdev_info(pp->dev,
+					    "TX FIFO empty timeout status=0x08%x, 
empty=%x, in_prog=%x",
+					    val, tx_fifo_empty_mask,
+					    tx_in_prog_mask);
+				break;
+			}
+			mdelay(1);
+			m_delay++;
Ditto
+
+			val = mvreg_read(pp, MVNETA_PORT_STATUS);
+		} while (((val & tx_fifo_empty_mask) != tx_fifo_empty_mask)
+			 || ((val & tx_in_prog_mask) != 0));
+
+		if (m_delay >= MVNETA_TX_FIFO_EMPTY_TIMEOUT)
+			break;
+
+		val = mvreg_read(pp, MVNETA_PORT_STATUS);
+		if (((val & tx_fifo_empty_mask) == tx_fifo_empty_mask) &&
+		    ((val & tx_in_prog_mask) == 0))
+			break;
+		else
+			netdev_info(pp->dev, "TX FIFO Empty double check failed. %d 
msec status=0x%x, empty=0x%x, in_prog=0x%x\n",
+				    m_delay, val, tx_fifo_empty_mask,
+				    tx_in_prog_mask);
+	}
+
+	udelay(200);
+}
[snip]
+
+/* This method sets defaults to the NETA port:
+ *	Clears interrupt Cause and Mask registers.
+ *	Clears all MAC tables.
+ *	Sets defaults to all registers.
+ *	Resets RX and TX descriptor rings.
+ *	Resets PHY.
+ * This method can be called after mvneta_port_down() to return the port
+ *	settings to defaults.
+ */
Please use standard kernel-doc style comments.

[snip]
+/* Read the Link Up bit (LinkUp) in port MAC control register */
+static int mvneta_link_is_up(struct mvneta_port *pp)
+{
+	u32 val;
+	val = mvreg_read(pp, MVNETA_GMAC_STATUS);
+	if (val & MVNETA_GMAC_LINK_UP_MASK)
+		return 1;
	return mvreg_read(pp, MVNETA_GMAC_STATUS) & MVNETA_GMAC_LINK_UP_MASK;
and make it static inline.
+
+	return 0;
+}
+
+/* Get phy address */
+static int mvneta_phy_addr_get(struct mvneta_port *pp)
+{
+	unsigned int val;
+
+	val = mvreg_read(pp, MVNETA_PHY_ADDR);
+	val &= 0x1f;
Use PHY_MAX_ADDR - 1 instead here.
+	return val;
+}
+
[snip]
+/* Display status (link, duplex, speed) of the port */
+void mvneta_link_status_print(struct mvneta_port *pp)
+{
+	struct mvneta_lnk_status link;
+	char *speedstr, *duplexstr;
+
+	mvneta_link_status(pp, &link);
+
+	if (link.linkup) {
+		if (link.speed == MVNETA_SPEED_1000)
+			speedstr = "1 Gbps";
+		else if (link.speed == MVNETA_SPEED_100)
+			speedstr = "100 Mbps";
+		else
+			speedstr = "10 Mbps";
+
+		if (link.duplex == MVNETA_DUPLEX_FULL)
+			duplexstr = "full";
+		else
+			duplexstr = "half";
+
+		netdev_info(pp->dev,
+			    "link up, %s duplex, speed %s\n",
+			    duplexstr, speedstr);
+	} else
+		netdev_info(pp->dev, "link down\n");
+}
You should rather define a phylib adjust_link callback to do this. Otherwise 
please reduce the indentation by handling the case when the link is down first.
+
+/* Display more error info */
+static void mvneta_rx_error(struct mvneta_port *pp,
+			    struct mvneta_rx_desc *rx_desc)
+{
+	u32 status = rx_desc->status;
+
+	if (pp->dev)
+		pp->dev->stats.rx_errors++;
Please do this outside of this function and just let it print the error.
+
+	if ((status & MVNETA_RXD_FIRST_LAST_DESC_MASK)
+	    != MVNETA_RXD_FIRST_LAST_DESC_MASK) {
+		netdev_err(pp->dev,
+			   "bad rx status %08x (buffer oversize), size=%d\n",
+			   rx_desc->status, rx_desc->data_size);
+		return;
+	}
[snip]
+
+/* Refill processing */
+static int mvneta_rx_refill(struct mvneta_port *pp,
+			    struct mvneta_rx_desc *rx_desc)
+
+{
+	unsigned long phys_addr;
+	struct sk_buff *skb;
+
+	skb = netdev_alloc_skb(pp->dev, pp->pkt_size);
+	if (!skb) {
+		mvneta_add_cleanup_timer(pp);
+		return 1;
+	}
+
+	phys_addr = dma_map_single(pp->dev->dev.parent, skb->head,
+				   MVNETA_RX_BUF_SIZE(pp->pkt_size),
+				   DMA_FROM_DEVICE);
Check that your phys_addr cookie has been successfully mapped using 
dma_mapping_error().

[snip]
+/* Main tx processing */
+static int mvneta_tx(struct sk_buff *skb, struct net_device *dev)
+{
+	struct mvneta_port *pp = netdev_priv(dev);
+
+	int frags = 0;
+	int res = NETDEV_TX_OK;
+	u32 tx_cmd;
+	struct mvneta_tx_queue *txq = NULL;
+	struct mvneta_tx_desc *tx_desc;
+
+	if (!test_bit(MVNETA_F_STARTED_BIT, &pp->flags))
+		goto out;
Is not this equivalent to !netif_running(dev)? At least print some message so 
we know that this is not supposed to happen.
+
+	txq = &pp->txqs[mvneta_txq_def];
+
+	frags = skb_shinfo(skb)->nr_frags + 1;
+
+	tx_desc = mvneta_tx_desc_get(pp, txq, frags);
+	if (tx_desc == NULL) {
+		frags = 0;
+		dev->stats.tx_dropped++;
+		res = NETDEV_TX_BUSY;
+		goto out;
+	}
+
+	tx_cmd = mvneta_skb_tx_csum(pp, skb);
+
+	tx_desc->data_size = skb_headlen(skb);
+
+	tx_desc->buf_phys_addr = dma_map_single(dev->dev.parent, skb->data,
+						tx_desc->data_size,
+						DMA_TO_DEVICE);
Please check this dma_map_single() return value too.

[snip]
+static int mvneta_addr_crc(unsigned char *addr)
+{
+	int crc = 0;
+	int i;
+
+	for (i = 0; i < 6; i++) {
ETH_ALEN instead of 6 to make it clear it operates on addresses.
+		int j;
+
+		crc = (crc ^ addr[i]) << 8;
+		for (j = 7; j >= 0; j--) {
+			if (crc & (0x100 << j))
+				crc ^= 0x107 << j;
+		}
+	}
+
+	return crc;
+}
[snip]
+
+/* Interrupt handling - the callback for request_irq() */
+static irqreturn_t mvneta_isr(int irq, void *dev_id)
+{
+	struct mvneta_port *pp = (struct mvneta_port *)dev_id;
+
+	/* Mask all interrupts */
+	mvreg_write(pp, MVNETA_INTR_NEW_MASK, 0);
+
+	/* Verify that the device not already on the polling list */
+	if (napi_schedule_prep(&pp->napi))
+		__napi_schedule(&pp->napi);
Does not the hardware generate interrupts for tx completion, PHY interrupts 
etc ...?
+
+	return IRQ_HANDLED;
+}
+
+/* Handle link event */
+static void mvneta_link_event(struct mvneta_port *pp)
+{
+	struct net_device *dev = pp->dev;
+
+	/* Check Link status on ethernet port */
+
+	if (mvneta_link_is_up(pp)) {
+		mvneta_port_up(pp);
+		set_bit(MVNETA_F_LINK_UP_BIT, &pp->flags);
+
+		if (dev) {
+			netif_carrier_on(dev);
+			netif_tx_wake_all_queues(dev);
+		}
+	} else {
+		if (dev) {
+			netif_carrier_off(dev);
+			netif_tx_stop_all_queues(dev);
+		}
+		mvneta_port_down(pp);
+		clear_bit(MVNETA_F_LINK_UP_BIT, &pp->flags);
+	}
+
+	mvneta_link_status_print(pp);
Again, this is taken care of by phylib nicely, and does not require you to 
have this F_LINK_UP_BIT.

[snip]
+
+/* Handle rxq fill: allocates rxq skbs; called when initializing a port */
+static int mvneta_rxq_fill(struct mvneta_port *pp, struct mvneta_rx_queue 
*rxq,
+			   int num)
+{
+	int i;
+	struct sk_buff *skb;
+	struct mvneta_rx_desc *rx_desc;
+	unsigned long phys_addr;
+	struct net_device *dev = pp->dev;
+
+	for (i = 0; i < num; i++) {
+		skb = dev_alloc_skb(pp->pkt_size);
+		if (!skb) {
+			netdev_err(pp->dev, "%s:rxq %d, %d of %d buffs filled\n",
+				   __func__, rxq->id, i, num);
+			break;
+		}
+
+		rx_desc = rxq->descs + i;
+		memset(rx_desc, 0, sizeof(struct mvneta_rx_desc));
+		phys_addr = dma_map_single(dev->dev.parent, skb->head,
+					   MVNETA_RX_BUF_SIZE(pp->pkt_size),
+					   DMA_FROM_DEVICE);
Here again, check phys_addr.
+		mvneta_rx_desc_fill(rx_desc, phys_addr, (u32)skb);
+	}
+
+	/* add this num of RX descriptors as non occupied (ready to get pkts) */
+	mvneta_rxq_non_occup_desc_add(pp, rxq, i);
+
+	return i;
+}
+
[snip]
+
+/* Create a specified RX queue */
+static int mvneta_rxq_init(struct mvneta_port *pp,
+			   struct mvneta_rx_queue *rxq)
+
+{
+	rxq->size = pp->rx_ring_size;
+
+	/* Allocate DMA descriptors array */
+	rxq->descs_orig = dma_alloc_coherent(pp->dev->dev.parent,
+					     MVNETA_RX_TOTAL_DESCS_SIZE(rxq),
+					     &rxq->descs_phys_orig,
+					     GFP_KERNEL);
+	if (rxq->descs_orig == NULL) {
Use dma_mapping_error() instead.
+		netdev_err(pp->dev, "rxQ=%d: Can't allocate %d bytes for %d RX 
descr\n",
+			   rxq->id, MVNETA_RX_TOTAL_DESCS_SIZE(rxq), rxq->size);
+		return -ENOMEM;
+	}
+
+	/* Make sure descriptor address is cache line size aligned  */
+	rxq->descs = PTR_ALIGN(rxq->descs_orig, MVNETA_CPU_D_CACHE_LINE_SIZE);
+	rxq->descs_phys = ALIGN(rxq->descs_phys_orig,
+				MVNETA_CPU_D_CACHE_LINE_SIZE);
+
+	rxq->last_desc = rxq->size - 1;
Don't you need some kind of barrier here? I do not know exactly how coherent 
your peripherals and memory are, just wondering.
+
+	/* Set Rx descriptors queue starting address */
+	mvreg_write(pp, MVNETA_RXQ_BASE_ADDR_REG(rxq->id), rxq->descs_phys);
+	mvreg_write(pp, MVNETA_RXQ_SIZE_REG(rxq->id), rxq->size);
+
+	/* Set Offset */
+	mvneta_rxq_offset_set(pp, rxq, NET_SKB_PAD);
+
+	/* Set coalescing pkts and time */
+	mvneta_rx_pkts_coal_set(pp, rxq, rxq->pkts_coal);
+	mvneta_rx_time_coal_set(pp, rxq, rxq->time_coal);
+
+	/* Fill RXQ with buffers from RX pool */
+	mvneta_rxq_buf_size_set(pp, rxq, MVNETA_RX_BUF_SIZE(pp->pkt_size));
+	mvneta_rxq_bm_disable(pp, rxq);
+	mvneta_rxq_fill(pp, rxq, rxq->size);
+
+	return 0;
+}
+
[snip]
+static int mvneta_txq_init(struct mvneta_port *pp,
+			   struct mvneta_tx_queue *txq)
+{
+	txq->size = pp->tx_ring_size;
+
+	/* Allocate DMA descriptors array */
+	txq->descs_orig = dma_alloc_coherent(pp->dev->dev.parent,
+					     MVNETA_TX_TOTAL_DESCS_SIZE(txq),
+					     &txq->descs_phys_orig,
+					     GFP_KERNEL);
+	if (txq->descs_orig == NULL) {
Use dma_mapping_error().
+		netdev_err(pp->dev, "txQ=%d: Can't allocate %d bytes for %d TX 
descr\n",
+			   txq->id, MVNETA_TX_TOTAL_DESCS_SIZE(txq), txq->size);
+		return -ENOMEM;
+	}
+
[snip]
+/* Fill rx buffers, start Rx/Tx activity, set coalesing,
+*  clear and unmask interrupt bits
+*/
+static int mvneta_start_internals(struct mvneta_port *pp, int mtu)
+{
+	int err = 0;
+
+	pp->pkt_size = MVNETA_RX_PKT_SIZE(mtu);
+	if (test_bit(MVNETA_F_STARTED_BIT, &pp->flags))
+		return -EINVAL;
You probably mean -EBUSY here instead?
+
+	if (mvneta_max_rx_size_set(pp, MVNETA_RX_PKT_SIZE(mtu))) {
+		netdev_err(pp->dev,
+			   "%s: can't set maxRxSize=%d mtu=%d\n",
+			   __func__, MVNETA_RX_PKT_SIZE(mtu), mtu);
+		return -EINVAL;
+	}
+
+	err = mvneta_setup_rxqs(pp);
+	if (unlikely(err))
+		return err;
+
+	err = mvneta_setup_txqs(pp);
+	if (unlikely(err)) {
+		mvneta_cleanup_rxqs(pp);
+		return err;
+	}
+
+	mvneta_txq_max_tx_size_set(pp, MVNETA_RX_PKT_SIZE(mtu));
+
+	/* start the Rx/Tx activity */
+	mvneta_port_enable(pp);
+
+	set_bit(MVNETA_F_LINK_UP_BIT, &pp->flags);
+	set_bit(MVNETA_F_STARTED_BIT, &pp->flags);
+
+	return 0;
+}
+
+/* Stop port Rx/Tx activity, free skb's from Rx/Tx rings */
+static int mvneta_stop_internals(struct mvneta_port *pp)
+{
+	clear_bit(MVNETA_F_STARTED_BIT, &pp->flags);
+
+	/* Stop the port activity */
+	mvneta_port_disable(pp);
+
+	/* Clear all ethernet port interrupts */
+	mvreg_write(pp, MVNETA_INTR_MISC_CAUSE, 0);
+	mvreg_write(pp, MVNETA_INTR_OLD_CAUSE, 0);
+
+	/* Mask all interrupts */
+	mvneta_interrupts_mask(pp);
+	smp_call_function_many(cpu_online_mask, mvneta_interrupts_mask,
+			       pp, 1);
+
+	/* Reset TX port here. */
+	mvneta_tx_reset(pp);
+
+	mvneta_cleanup_rxqs(pp);
+	mvneta_cleanup_txqs(pp);
+
+	return 0;
+
+}
+
+/* Start the port, connect to port interrupt line, unmask interrupts  */
+static int mvneta_start(struct net_device *dev)
+{
+	struct mvneta_port *pp = netdev_priv(dev);
+
+	/* In default link is down */
+	netif_carrier_off(dev);
+	netif_tx_stop_all_queues(dev);
+
+	/* Fill rx buffers, start Rx/Tx activity, set coalescing */
+	if (mvneta_start_internals(pp, dev->mtu) != 0) {
+		netdev_err(dev, "start internals failed\n");
+		return -ENODEV;
+	}
+
+	/* Enable polling on the port, must be used after netif_poll_disable */
+	napi_enable(&pp->napi);
+
+	if (pp->flags & MVNETA_F_LINK_UP) {
+		netif_carrier_on(dev);
+		netif_tx_wake_all_queues(dev);
+	} else {
+		netdev_info(dev, "%s: NOT MVNETA_F_LINK_UP\n", __func__);
+	}
Remove this message as well.
+
+	/* Connect to port interrupt line */
+	if (request_irq(dev->irq, mvneta_isr, (IRQF_DISABLED), "mv_eth", pp)) {
+		netdev_err(dev, "cannot request irq %d\n", dev->irq);
+		napi_disable(&pp->napi);
+		goto error;
+	}
You should probably request the interrupt prior to calling napi_enable()
+
+	/* Unmask interrupts */
+	mvneta_interrupts_unmask(pp);
+	smp_call_function_many(cpu_online_mask,
+			       mvneta_interrupts_unmask,
+			       pp, 1);
+
+	netdev_info(dev, "started\n");
Remove this please.
+	return 0;
+
+error:
+	netdev_err(dev, "start failed\n");
+	mvneta_cleanup_rxqs(pp);
+	mvneta_cleanup_txqs(pp);
+
+	return -ENODEV;
+}
+
+	if (dev->irq != 0)
+		free_irq(dev->irq, pp);
This looks superfluous, you refuse to bring up the interface if the interrupt 
requesting fails.
+
+	netdev_info(dev, "stopped\n");
+
+	return 0;
+}
+
+
+/* tx timeout callback - display a message and stop/start the network 
device */
+static void mvneta_tx_timeout(struct net_device *dev)
+{
+	netdev_info(dev, "tx timeout\n");
+	if (netif_running(dev)) {
+		mvneta_stop(dev);
+		mvneta_start(dev);
+	}
You should never end-up with the case where the interface is not running and 
you face a transmit timeout.

[snip]
+/* Change the device mtu */
+static int mvneta_change_mtu(struct net_device *dev, int mtu)
+{
+	int old_mtu = dev->mtu;
+
+	mtu = mvneta_check_mtu_valid(dev, mtu);
+	if (mtu < 0)
+		return -EINVAL;
+
+	dev->mtu = mtu;
+
+	if (!netif_running(dev)) {
+		netdev_info(dev, "change mtu %d (buffer-size %d) to %d (buffer-size 
%d)\n",
+			old_mtu, MVNETA_RX_PKT_SIZE(old_mtu),
+			dev->mtu, MVNETA_RX_PKT_SIZE(dev->mtu));
+		return 0;
Remove this message.
+	}
+
+	if (mvneta_stop(dev)) {
+		netdev_err(dev, "stop interface failed\n");
+		goto error;
+	}
+
+	if (mvneta_start(dev)) {
+		netdev_err(dev, "start interface failed\n");
+		goto error;
+	}
Propagate the returned error codes back to the caller.
+
+	netdev_info(dev, "change mtu %d (buffer-size %d) to %d (buffer-size %d)\n",
+		old_mtu, MVNETA_RX_PKT_SIZE(old_mtu),
+		dev->mtu, MVNETA_RX_PKT_SIZE(dev->mtu));
Remove this message too.
+
+	return 0;
+
+error:
+	netdev_info(dev, "change mtu failed\n");
+	return -EINVAL;
+}
+
+/* Handle setting mac address (low level) */
+static int mvneta_set_mac_addr_internals(struct net_device *dev, void 
*addr)
+{
+	struct mvneta_port *pp = netdev_priv(dev);
+	u8 *mac = addr + 2;
+	int i;
+
+	/* Remove previous address table entry */
+	if (mvneta_mac_addr_set(pp, dev->dev_addr, -1) != 0) {
+		netdev_err(dev, "mvneta_mac_addr_set failed\n");
+		return -EINVAL;
+	}
+
+	/* Set new addr in hw */
+	if (mvneta_mac_addr_set(pp, mac, mvneta_rxq_def) != 0) {
+		netdev_err(dev, "mvneta_mac_addr_set failed\n");
+		return -EINVAL;
+	}
+
+	/* Set addr in the device */
+	for (i = 0; i < MVNETA_MAC_ADDR_SIZE; i++)
+		dev->dev_addr[i] = mac[i];
ETH_ALEN.
+
+	netdev_info(dev, "mac address changed\n");
Remove this please.
+
+	return 0;
+}
+
+/* Handle setting mac address */
+static int mvneta_set_mac_addr(struct net_device *dev, void *addr)
+{
+	if (!netif_running(dev)) {
+		if (mvneta_set_mac_addr_internals(dev, addr) == -1)
+			goto error;
+		return 0;
+	}
Usually you just check if the interface is running, and if it is return 
something like -EBUSY.
+
+	if (mvneta_stop(dev)) {
+		netdev_err(dev, "stop interface failed\n");
+		goto error;
+	}
+
+	if (mvneta_set_mac_addr_internals(dev, addr) == -1)
+		goto error;
+
+	if (mvneta_start(dev)) {
+		netdev_err(dev, "start interface failed\n");
+		goto error;
+	}
Propagate error codes here too please.
+
+	return 0;
+
+error:
+	netdev_err(dev, "set mac addr failed\n");
+	return -EINVAL;
+}
+
+/*
+ * Called when a network interface is made active.
+ * Returns 0 on success, -EINVAL or =ENODEV on failure
+ * mvneta_open() is called when a network interface is made
+ * active by the system (IFF_UP). We set the mac address and
+ * invoke mvneta_start() to start the device.
+ */
+static int mvneta_open(struct net_device *dev)
+{
+	struct mvneta_port *pp = netdev_priv(dev);
+	int queue = mvneta_rxq_def;
+
+	if (mvneta_mac_addr_set(pp, dev->dev_addr, queue) != 0) {
+		netdev_err(dev, "mvneta_mac_addr_set failed\n");
+		return -EINVAL;
+	}
+
+	if (mvneta_start(dev)) {
+		netdev_err(dev, "start interface failed\n");
+		return -ENODEV;
+	}
+
+	return 0;
Propagate the error code here too.

[snip]
+static void mvneta_ethtool_get_drvinfo(struct net_device *dev,
+				    struct ethtool_drvinfo *drvinfo)
+{
+	strlcpy(drvinfo->driver, mvneta_driver_name,
+		sizeof(drvinfo->driver));
+	strlcpy(drvinfo->version, mvneta_driver_version,
+		sizeof(drvinfo->version));
You can probably also provide informations about the firmware version, bus_info 
at least.

[snip]
+/* Device initialization routine */
+static int __devinit mvneta_probe(struct platform_device *pdev)
+{
+	int err = -EINVAL;
+	struct mvneta_port *pp;
+	struct net_device *dev;
+	u32 phy_addr, clk;
+	int phy_mode;
+	const char *mac_addr;
+	const struct mbus_dram_target_info *dram_target_info;
+	struct device_node *dn = pdev->dev.of_node;
+
+	dev = alloc_etherdev_mq(sizeof(struct mvneta_port), 8);
+	if (!dev)
+		return -ENOMEM;
+
+	dev->irq = irq_of_parse_and_map(dn, 0);
+	if (dev->irq == 0) {
+		err = -EINVAL;
+		goto err_irq;
+	}
+
+	if (of_property_read_u32(dn, "phy-addr", &phy_addr) != 0) {
+		dev_err(&pdev->dev, "could not read phy_addr\n");
+		err = -ENODEV;
+		goto err_node;
+	}
+
+	phy_mode = of_get_phy_mode(dn);
+	if (phy_mode < 0) {
+		dev_err(&pdev->dev, "wrong phy-mode\n");
+		err = -EINVAL;
+		goto err_node;
+	}
+
+	if (of_property_read_u32(dn, "clock-frequency", &clk) != 0) {
+		dev_err(&pdev->dev, "could not read clock-frequency\n");
+		err = -EINVAL;
+		goto err_node;
+	}
+
+	mac_addr = of_get_mac_address(dn);
+
+	if (!mac_addr || !is_valid_ether_addr(mac_addr))
+		eth_hw_addr_random(dev);
+	else
+		memcpy(dev->dev_addr, mac_addr, 6);
+
+	dev->tx_queue_len = MVNETA_MAX_TXD;
+	dev->watchdog_timeo = 5 * HZ;
+	dev->netdev_ops = &mvneta_netdev_ops;
+
+	SET_ETHTOOL_OPS(dev, &mvneta_eth_tool_ops);
+
+	pp = netdev_priv(dev);
+
+	pp->tx_done_timer.function = mvneta_tx_done_timer_callback;
+	init_timer(&pp->tx_done_timer);
+	clear_bit(MVNETA_F_TX_DONE_TIMER_BIT, &pp->flags);
+	pp->cleanup_timer.function = mvneta_cleanup_timer_callback;
+	init_timer(&pp->cleanup_timer);
+	clear_bit(MVNETA_F_CLEANUP_TIMER_BIT, &pp->flags);
+
+	pp->weight = MVNETA_RX_POLL_WEIGHT;
+	pp->clk = clk;
Rename this clk_freq so make it less ambiguous, because this is not a proper 
struct clk pointer.
+
+	pp->base = of_iomap(dn, 0);
+	if (pp->base == NULL) {
+		err = -ENOMEM;
+		goto err_node;
+	}
+
+	pp->tx_done_timer.data = (unsigned long)dev;
+	pp->cleanup_timer.data = (unsigned long)dev;
+
+	pp->tx_ring_size = MVNETA_MAX_TXD;
+	pp->rx_ring_size = MVNETA_MAX_RXD;
+
+	pp->dev = dev;
+
+	if (mvneta_init(pp, phy_addr)) {
+		dev_err(&pdev->dev, "can't init eth hal\n");
+		err = -ENODEV;
+		goto err_base;
+	}
+	mvneta_port_power_up(pp, phy_mode);
+
+	dram_target_info = mv_mbus_dram_info();
+	if (dram_target_info)
+		mvneta_conf_mbus_windows(pp, dram_target_info);
+
+	netif_napi_add(dev, &pp->napi, mvneta_poll, pp->weight);
+
+	SET_NETDEV_DEV(dev, &pdev->dev);
+
+	if (register_netdev(dev)) {
+		dev_err(&pdev->dev, "failed to register\n");
+		err = ENOMEM;
+		goto err_base;
+	}
+
+	dev->features = NETIF_F_SG;
+	dev->hw_features =  NETIF_F_SG;
+	dev->priv_flags |= IFF_UNICAST_FLT;
+
+	if (dev->mtu <= MVNETA_TX_CSUM_MAX_SIZE) {
+		dev->features |= NETIF_F_IP_CSUM;
+		dev->hw_features |= NETIF_F_IP_CSUM;
+	}
At this point, the condition is always true, so just set these features and 
update them when the MTU changes.
+
+	dev_info(&pdev->dev, "%s, mac: %pM pp->base=%p\n", dev->name,
+		 dev->dev_addr, pp->base);
+
+	platform_set_drvdata(pdev, pp->dev);
+
+	return 0;
+err_base:
+	iounmap(pp->base);
+err_node:
+	irq_dispose_mapping(dev->irq);
+err_irq:
+	free_netdev(dev);
+	return err;
+}
+
+/* Device removal routine */
+static int __devexit mvneta_remove(struct platform_device *pdev)
+{
+	struct net_device  *dev = platform_get_drvdata(pdev);
+	struct mvneta_port *pp = netdev_priv(dev);
+
+	dev_info(&pdev->dev, "Removing Marvell Ethernet Driver\n");
I would remove this message.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help