Skip to contentSkip to conversation

A few more pasemi_mac patches for 2.6.25

PATCH In review Olof Johansson 2 participants 5 messages Jan 23, 2008 – Feb 1, 2008

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

cover A few more pasemi_mac patches for 2.6.25

Hi,

This should be the last of my updates for 2.6.25:

1/3: pasemi_mac: Add support for changing mac address 2/3: pasemi_mac: add support for setting MTU 3/3: pasemi_mac: Disable interface on close

Thanks,

Olof

#1 lore raw

PATCH 1/3 pasemi_mac: Add support for changing mac address

Straightforward. It used to be hardcoded and impossible to override with ifconfig.

drivers/net/pasemi_mac.c +28 -0
index bb88a41..59dea3f 100644
@@ -221,6 +221,33 @@ static int pasemi_get_mac_addr(struct pasemi_mac *mac)
 	return 0;
 }
 
+static int pasemi_mac_set_mac_addr(struct net_device *dev, void *p)
+{
+	struct pasemi_mac *mac = netdev_priv(dev);
+	struct sockaddr *addr = p;
+	unsigned int adr0, adr1;
+
+	if (!is_valid_ether_addr(addr->sa_data))
+		return -EINVAL;
+
+	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+	adr0 = dev->dev_addr[2] << 24 |
+	       dev->dev_addr[3] << 16 |
+	       dev->dev_addr[4] << 8 |
+	       dev->dev_addr[5];
+	adr1 = read_mac_reg(mac, PAS_MAC_CFG_ADR1);
+	adr1 &= ~0xffff;
+	adr1 |= dev->dev_addr[0] << 8 | dev->dev_addr[1];
+
+	pasemi_mac_intf_disable(mac);
+	write_mac_reg(mac, PAS_MAC_CFG_ADR0, adr0);
+	write_mac_reg(mac, PAS_MAC_CFG_ADR1, adr1);
+	pasemi_mac_intf_enable(mac);
+
+	return 0;
+}
+
 static int get_skb_hdr(struct sk_buff *skb, void **iphdr,
 		       void **tcph, u64 *hdr_flags, void *data)
 {
@@ -1475,6 +1502,7 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	dev->stop = pasemi_mac_close;
 	dev->hard_start_xmit = pasemi_mac_start_tx;
 	dev->set_multicast_list = pasemi_mac_set_rx_mode;
+	dev->set_mac_address = pasemi_mac_set_mac_addr;
 
 	if (err)
 		goto out;
drivers/net/pasemi_mac.h +2 -0
index 8bee2a6..39d3259 100644
@@ -96,6 +96,8 @@ struct pasemi_mac_buffer {
 /* MAC CFG register offsets */
 enum {
 	PAS_MAC_CFG_PCFG = 0x80,
+	PAS_MAC_CFG_ADR0 = 0x8c,
+	PAS_MAC_CFG_ADR1 = 0x90,
 	PAS_MAC_CFG_TXP = 0x98,
 	PAS_MAC_IPC_CHNL = 0x208,
 };
#2 lore raw

Re: [PATCH 1/3] pasemi_mac: Add support for changing mac address

Quoted 4 lines · Olof Johansson

Straightforward. It used to be hardcoded and impossible to override with ifconfig.

applied 1-3

#3 lore raw

PATCH 2/3 pasemi_mac: add support for setting MTU

In reply to Olof Johansson

Currently keeping it at 1500 bytes or below since jumbo frames need special checksum offload on TX.

drivers/net/pasemi_mac.c +158 -72
index 59dea3f..059c6b0 100644
@@ -62,6 +62,10 @@
 
 #define LRO_MAX_AGGR 64
 
+#define PE_MIN_MTU	64
+#define PE_MAX_MTU	1500
+#define PE_DEF_MTU	ETH_DATA_LEN
+
 #define DEFAULT_MSG_ENABLE	  \
 	(NETIF_MSG_DRV		| \
 	 NETIF_MSG_PROBE	| \
@@ -82,8 +86,6 @@
 				 & ((ring)->size - 1))
 #define RING_AVAIL(ring)	((ring->size) - RING_USED(ring))
 
-#define BUF_SIZE 1646 /* 1500 MTU + ETH_HLEN + VLAN_HLEN + 2 64B cachelines */
-
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR ("Olof Johansson <[email protected]>");
 MODULE_DESCRIPTION("PA Semi PWRficient Ethernet driver");
@@ -175,6 +177,24 @@ static int mac_to_intf(struct pasemi_mac *mac)
 	return -1;
 }
 
+static void pasemi_mac_intf_disable(struct pasemi_mac *mac)
+{
+	unsigned int flags;
+
+	flags = read_mac_reg(mac, PAS_MAC_CFG_PCFG);
+	flags &= ~PAS_MAC_CFG_PCFG_PE;
+	write_mac_reg(mac, PAS_MAC_CFG_PCFG, flags);
+}
+
+static void pasemi_mac_intf_enable(struct pasemi_mac *mac)
+{
+	unsigned int flags;
+
+	flags = read_mac_reg(mac, PAS_MAC_CFG_PCFG);
+	flags |= PAS_MAC_CFG_PCFG_PE;
+	write_mac_reg(mac, PAS_MAC_CFG_PCFG, flags);
+}
+
 static int pasemi_get_mac_addr(struct pasemi_mac *mac)
 {
 	struct pci_dev *pdev = mac->pdev;
@@ -480,7 +500,7 @@ static void pasemi_mac_free_tx_resources(struct pasemi_mac *mac)
 
 }
 
-static void pasemi_mac_free_rx_resources(struct pasemi_mac *mac)
+static void pasemi_mac_free_rx_buffers(struct pasemi_mac *mac)
 {
 	struct pasemi_mac_rxring *rx = rx_ring(mac);
 	unsigned int i;
@@ -500,7 +520,12 @@ static void pasemi_mac_free_rx_resources(struct pasemi_mac *mac)
 	}
 
 	for (i = 0; i < RX_RING_SIZE; i++)
-		RX_DESC(rx, i) = 0;
+		RX_BUFF(rx, i) = 0;
+}
+
+static void pasemi_mac_free_rx_resources(struct pasemi_mac *mac)
+{
+	pasemi_mac_free_rx_buffers(mac);
 
 	dma_free_coherent(&mac->dma_pdev->dev, RX_RING_SIZE * sizeof(u64),
 			  rx_ring(mac)->buffers, rx_ring(mac)->buf_dma);
@@ -530,14 +555,14 @@ static void pasemi_mac_replenish_rx_ring(const struct net_device *dev,
 		/* Entry in use? */
 		WARN_ON(*buff);
 
-		skb = dev_alloc_skb(BUF_SIZE);
+		skb = dev_alloc_skb(mac->bufsz);
 		skb_reserve(skb, LOCAL_SKB_ALIGN);
 
 		if (unlikely(!skb))
 			break;
 
 		dma = pci_map_single(mac->dma_pdev, skb->data,
-				     BUF_SIZE - LOCAL_SKB_ALIGN,
+				     mac->bufsz - LOCAL_SKB_ALIGN,
 				     PCI_DMA_FROMDEVICE);
 
 		if (unlikely(dma_mapping_error(dma))) {
@@ -547,7 +572,7 @@ static void pasemi_mac_replenish_rx_ring(const struct net_device *dev,
 
 		info->skb = skb;
 		info->dma = dma;
-		*buff = XCT_RXB_LEN(BUF_SIZE) | XCT_RXB_ADDR(dma);
+		*buff = XCT_RXB_LEN(mac->bufsz) | XCT_RXB_ADDR(dma);
 		fill++;
 	}
 
@@ -677,7 +702,7 @@ static int pasemi_mac_clean_rx(struct pasemi_mac_rxring *rx,
 
 		len = (macrx & XCT_MACRX_LLEN_M) >> XCT_MACRX_LLEN_S;
 
-		pci_unmap_single(pdev, dma, BUF_SIZE-LOCAL_SKB_ALIGN,
+		pci_unmap_single(pdev, dma, mac->bufsz - LOCAL_SKB_ALIGN,
 				 PCI_DMA_FROMDEVICE);
 
 		if (macrx & XCT_MACRX_CRC) {
@@ -901,24 +926,6 @@ static irqreturn_t pasemi_mac_tx_intr(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
-static void pasemi_mac_intf_disable(struct pasemi_mac *mac)
-{
-	unsigned int flags;
-
-	flags = read_mac_reg(mac, PAS_MAC_CFG_PCFG);
-	flags &= ~PAS_MAC_CFG_PCFG_PE;
-	write_mac_reg(mac, PAS_MAC_CFG_PCFG, flags);
-}
-
-static void pasemi_mac_intf_enable(struct pasemi_mac *mac)
-{
-	unsigned int flags;
-
-	flags = read_mac_reg(mac, PAS_MAC_CFG_PCFG);
-	flags |= PAS_MAC_CFG_PCFG_PE;
-	write_mac_reg(mac, PAS_MAC_CFG_PCFG, flags);
-}
-
 static void pasemi_adjust_link(struct net_device *dev)
 {
 	struct pasemi_mac *mac = netdev_priv(dev);
@@ -1175,11 +1182,71 @@ out_rx_resources:
 
 #define MAX_RETRIES 5000
 
+static void pasemi_mac_pause_txchan(struct pasemi_mac *mac)
+{
+	unsigned int sta, retries;
+	int txch = tx_ring(mac)->chan.chno;
+
+	write_dma_reg(PAS_DMA_TXCHAN_TCMDSTA(txch),
+		      PAS_DMA_TXCHAN_TCMDSTA_ST);
+
+	for (retries = 0; retries < MAX_RETRIES; retries++) {
+		sta = read_dma_reg(PAS_DMA_TXCHAN_TCMDSTA(txch));
+		if (!(sta & PAS_DMA_TXCHAN_TCMDSTA_ACT))
+			break;
+		cond_resched();
+	}
+
+	if (sta & PAS_DMA_TXCHAN_TCMDSTA_ACT)
+		dev_err(&mac->dma_pdev->dev,
+			"Failed to stop tx channel, tcmdsta %08x\n", sta);
+
+	write_dma_reg(PAS_DMA_TXCHAN_TCMDSTA(txch), 0);
+}
+
+static void pasemi_mac_pause_rxchan(struct pasemi_mac *mac)
+{
+	unsigned int sta, retries;
+	int rxch = rx_ring(mac)->chan.chno;
+
+	write_dma_reg(PAS_DMA_RXCHAN_CCMDSTA(rxch),
+		      PAS_DMA_RXCHAN_CCMDSTA_ST);
+	for (retries = 0; retries < MAX_RETRIES; retries++) {
+		sta = read_dma_reg(PAS_DMA_RXCHAN_CCMDSTA(rxch));
+		if (!(sta & PAS_DMA_RXCHAN_CCMDSTA_ACT))
+			break;
+		cond_resched();
+	}
+
+	if (sta & PAS_DMA_RXCHAN_CCMDSTA_ACT)
+		dev_err(&mac->dma_pdev->dev,
+			"Failed to stop rx channel, ccmdsta 08%x\n", sta);
+	write_dma_reg(PAS_DMA_RXCHAN_CCMDSTA(rxch), 0);
+}
+
+static void pasemi_mac_pause_rxint(struct pasemi_mac *mac)
+{
+	unsigned int sta, retries;
+
+	write_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if),
+		      PAS_DMA_RXINT_RCMDSTA_ST);
+	for (retries = 0; retries < MAX_RETRIES; retries++) {
+		sta = read_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if));
+		if (!(sta & PAS_DMA_RXINT_RCMDSTA_ACT))
+			break;
+		cond_resched();
+	}
+
+	if (sta & PAS_DMA_RXINT_RCMDSTA_ACT)
+		dev_err(&mac->dma_pdev->dev,
+			"Failed to stop rx interface, rcmdsta %08x\n", sta);
+	write_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if), 0);
+}
+
 static int pasemi_mac_close(struct net_device *dev)
 {
 	struct pasemi_mac *mac = netdev_priv(dev);
 	unsigned int sta;
-	int retries;
 	int rxch, txch;
 
 	rxch = rx_ring(mac)->chan.chno;
@@ -1217,51 +1284,9 @@ static int pasemi_mac_close(struct net_device *dev)
 	pasemi_mac_clean_tx(tx_ring(mac));
 	pasemi_mac_clean_rx(rx_ring(mac), RX_RING_SIZE);
 
-	/* Disable interface */
-	write_dma_reg(PAS_DMA_TXCHAN_TCMDSTA(txch),
-		      PAS_DMA_TXCHAN_TCMDSTA_ST);
-	write_dma_reg( PAS_DMA_RXINT_RCMDSTA(mac->dma_if),
-		      PAS_DMA_RXINT_RCMDSTA_ST);
-	write_dma_reg(PAS_DMA_RXCHAN_CCMDSTA(rxch),
-		      PAS_DMA_RXCHAN_CCMDSTA_ST);
-
-	for (retries = 0; retries < MAX_RETRIES; retries++) {
-		sta = read_dma_reg(PAS_DMA_TXCHAN_TCMDSTA(rxch));
-		if (!(sta & PAS_DMA_TXCHAN_TCMDSTA_ACT))
-			break;
-		cond_resched();
-	}
-
-	if (sta & PAS_DMA_TXCHAN_TCMDSTA_ACT)
-		dev_err(&mac->dma_pdev->dev, "Failed to stop tx channel\n");
-
-	for (retries = 0; retries < MAX_RETRIES; retries++) {
-		sta = read_dma_reg(PAS_DMA_RXCHAN_CCMDSTA(rxch));
-		if (!(sta & PAS_DMA_RXCHAN_CCMDSTA_ACT))
-			break;
-		cond_resched();
-	}
-
-	if (sta & PAS_DMA_RXCHAN_CCMDSTA_ACT)
-		dev_err(&mac->dma_pdev->dev, "Failed to stop rx channel\n");
-
-	for (retries = 0; retries < MAX_RETRIES; retries++) {
-		sta = read_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if));
-		if (!(sta & PAS_DMA_RXINT_RCMDSTA_ACT))
-			break;
-		cond_resched();
-	}
-
-	if (sta & PAS_DMA_RXINT_RCMDSTA_ACT)
-		dev_err(&mac->dma_pdev->dev, "Failed to stop rx interface\n");
-
-	/* Then, disable the channel. This must be done separately from
-	 * stopping, since you can't disable when active.
-	 */
-
-	write_dma_reg(PAS_DMA_TXCHAN_TCMDSTA(txch), 0);
-	write_dma_reg(PAS_DMA_RXCHAN_CCMDSTA(rxch), 0);
-	write_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if), 0);
+	pasemi_mac_pause_txchan(mac);
+	pasemi_mac_pause_rxint(mac);
+	pasemi_mac_pause_rxchan(mac);
 
 	free_irq(mac->tx->chan.irq, mac->tx);
 	free_irq(mac->rx->chan.irq, mac->rx);
@@ -1415,6 +1440,62 @@ static int pasemi_mac_poll(struct napi_struct *napi, int budget)
 	return pkts;
 }
 
+static int pasemi_mac_change_mtu(struct net_device *dev, int new_mtu)
+{
+	struct pasemi_mac *mac = netdev_priv(dev);
+	unsigned int reg;
+	unsigned int rcmdsta;
+	int running;
+
+	if (new_mtu < PE_MIN_MTU || new_mtu > PE_MAX_MTU)
+		return -EINVAL;
+
+	running = netif_running(dev);
+
+	if (running) {
+		/* Need to stop the interface, clean out all already
+		 * received buffers, free all unused buffers on the RX
+		 * interface ring, then finally re-fill the rx ring with
+		 * the new-size buffers and restart.
+		 */
+
+		napi_disable(&mac->napi);
+		netif_tx_disable(dev);
+		pasemi_mac_intf_disable(mac);
+
+		rcmdsta = read_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if));
+		pasemi_mac_pause_rxint(mac);
+		pasemi_mac_clean_rx(rx_ring(mac), RX_RING_SIZE);
+		pasemi_mac_free_rx_buffers(mac);
+	}
+
+	/* Change maxf, i.e. what size frames are accepted.
+	 * Need room for ethernet header and CRC word
+	 */
+	reg = read_mac_reg(mac, PAS_MAC_CFG_MACCFG);
+	reg &= ~PAS_MAC_CFG_MACCFG_MAXF_M;
+	reg |= PAS_MAC_CFG_MACCFG_MAXF(new_mtu + ETH_HLEN + 4);
+	write_mac_reg(mac, PAS_MAC_CFG_MACCFG, reg);
+
+	dev->mtu = new_mtu;
+	/* MTU + ETH_HLEN + VLAN_HLEN + 2 64B cachelines */
+	mac->bufsz = new_mtu + ETH_HLEN + ETH_FCS_LEN + LOCAL_SKB_ALIGN + 128;
+
+	if (running) {
+		write_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if),
+			      rcmdsta | PAS_DMA_RXINT_RCMDSTA_EN);
+
+		rx_ring(mac)->next_to_fill = 0;
+		pasemi_mac_replenish_rx_ring(dev, RX_RING_SIZE-1);
+
+		napi_enable(&mac->napi);
+		netif_start_queue(dev);
+		pasemi_mac_intf_enable(mac);
+	}
+
+	return 0;
+}
+
 static int __devinit
 pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
@@ -1503,6 +1584,11 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	dev->hard_start_xmit = pasemi_mac_start_tx;
 	dev->set_multicast_list = pasemi_mac_set_rx_mode;
 	dev->set_mac_address = pasemi_mac_set_mac_addr;
+	dev->mtu = PE_DEF_MTU;
+	/* 1500 MTU + ETH_HLEN + VLAN_HLEN + 2 64B cachelines */
+	mac->bufsz = dev->mtu + ETH_HLEN + ETH_FCS_LEN + LOCAL_SKB_ALIGN + 128;
+
+	dev->change_mtu = pasemi_mac_change_mtu;
 
 	if (err)
 		goto out;
drivers/net/pasemi_mac.h +14 -0
index 39d3259..99e7b93 100644
@@ -59,6 +59,7 @@ struct pasemi_mac {
 	struct phy_device *phydev;
 	struct napi_struct napi;
 
+	int		bufsz; /* RX ring buffer size */
 	u8		type;
 #define MAC_TYPE_GMAC	1
 #define MAC_TYPE_XAUI	2
@@ -96,6 +97,7 @@ struct pasemi_mac_buffer {
 /* MAC CFG register offsets */
 enum {
 	PAS_MAC_CFG_PCFG = 0x80,
+	PAS_MAC_CFG_MACCFG = 0x84,
 	PAS_MAC_CFG_ADR0 = 0x8c,
 	PAS_MAC_CFG_ADR1 = 0x90,
 	PAS_MAC_CFG_TXP = 0x98,
@@ -132,6 +134,18 @@ enum {
 #define PAS_MAC_CFG_PCFG_SPD_100M	0x00000001
 #define PAS_MAC_CFG_PCFG_SPD_1G		0x00000002
 #define PAS_MAC_CFG_PCFG_SPD_10G	0x00000003
+
+#define PAS_MAC_CFG_MACCFG_TXT_M	0x70000000
+#define PAS_MAC_CFG_MACCFG_TXT_S	28
+#define PAS_MAC_CFG_MACCFG_PRES_M	0x0f000000
+#define PAS_MAC_CFG_MACCFG_PRES_S	24
+#define PAS_MAC_CFG_MACCFG_MAXF_M	0x00ffff00
+#define PAS_MAC_CFG_MACCFG_MAXF_S	8
+#define PAS_MAC_CFG_MACCFG_MAXF(x)	(((x) << PAS_MAC_CFG_MACCFG_MAXF_S) & \
+					 PAS_MAC_CFG_MACCFG_MAXF_M)
+#define PAS_MAC_CFG_MACCFG_MINF_M	0x000000ff
+#define PAS_MAC_CFG_MACCFG_MINF_S	0
+
 #define PAS_MAC_CFG_TXP_FCF		0x01000000
 #define PAS_MAC_CFG_TXP_FCE		0x00800000
 #define PAS_MAC_CFG_TXP_FC		0x00400000
#4 lore raw

PATCH 3/3 pasemi_mac: Disable interface on close

In reply to Olof Johansson

Turns out we never disable the interface. It doesn't really cause any problems since the channel is off, but it's still better to do it this way.

drivers/net/pasemi_mac.c +1 -0
index 059c6b0..2e39e02 100644
@@ -1287,6 +1287,7 @@ static int pasemi_mac_close(struct net_device *dev)
 	pasemi_mac_pause_txchan(mac);
 	pasemi_mac_pause_rxint(mac);
 	pasemi_mac_pause_rxchan(mac);
+	pasemi_mac_intf_disable(mac);
 
 	free_irq(mac->tx->chan.irq, mac->tx);
 	free_irq(mac->rx->chan.irq, mac->rx);