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

Commit 28ae79f5 authored by Olof Johansson's avatar Olof Johansson Committed by David S. Miller
Browse files

pasemi_mac: Software-based LRO support



pasemi_mac: Software-based LRO support

Implement LRO for pasemi_mac. Pretty straightforward.

Signed-off-by: default avatarOlof Johansson <olof@lixom.net>
Signed-off-by: default avatarJeff Garzik <jeff@garzik.org>
parent 906674ab
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -2572,6 +2572,7 @@ config PASEMI_MAC
	tristate "PA Semi 1/10Gbit MAC"
	tristate "PA Semi 1/10Gbit MAC"
	depends on PPC64 && PCI
	depends on PPC64 && PCI
	select PHYLIB
	select PHYLIB
	select INET_LRO
	help
	help
	  This driver supports the on-chip 1/10Gbit Ethernet controller on
	  This driver supports the on-chip 1/10Gbit Ethernet controller on
	  PA Semi's PWRficient line of chips.
	  PA Semi's PWRficient line of chips.
+49 −4
Original line number Original line Diff line number Diff line
@@ -32,6 +32,7 @@
#include <linux/ip.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/tcp.h>
#include <net/checksum.h>
#include <net/checksum.h>
#include <linux/inet_lro.h>


#include <asm/irq.h>
#include <asm/irq.h>
#include <asm/firmware.h>
#include <asm/firmware.h>
@@ -56,9 +57,11 @@




/* Must be a power of two */
/* Must be a power of two */
#define RX_RING_SIZE 1024
#define RX_RING_SIZE 2048
#define TX_RING_SIZE 4096
#define TX_RING_SIZE 4096


#define LRO_MAX_AGGR 64

#define DEFAULT_MSG_ENABLE	  \
#define DEFAULT_MSG_ENABLE	  \
	(NETIF_MSG_DRV		| \
	(NETIF_MSG_DRV		| \
	 NETIF_MSG_PROBE	| \
	 NETIF_MSG_PROBE	| \
@@ -206,7 +209,6 @@ static int pasemi_get_mac_addr(struct pasemi_mac *mac)
		return -ENOENT;
		return -ENOENT;
	}
	}



	if (sscanf(maddr, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &addr[0],
	if (sscanf(maddr, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &addr[0],
		   &addr[1], &addr[2], &addr[3], &addr[4], &addr[5]) != 6) {
		   &addr[1], &addr[2], &addr[3], &addr[4], &addr[5]) != 6) {
		dev_warn(&pdev->dev,
		dev_warn(&pdev->dev,
@@ -219,6 +221,37 @@ static int pasemi_get_mac_addr(struct pasemi_mac *mac)
	return 0;
	return 0;
}
}


static int get_skb_hdr(struct sk_buff *skb, void **iphdr,
		       void **tcph, u64 *hdr_flags, void *data)
{
	u64 macrx = (u64) data;
	unsigned int ip_len;
	struct iphdr *iph;

	/* IPv4 header checksum failed */
	if ((macrx & XCT_MACRX_HTY_M) != XCT_MACRX_HTY_IPV4_OK)
		return -1;

	/* non tcp packet */
	skb_reset_network_header(skb);
	iph = ip_hdr(skb);
	if (iph->protocol != IPPROTO_TCP)
		return -1;

	ip_len = ip_hdrlen(skb);
	skb_set_transport_header(skb, ip_len);
	*tcph = tcp_hdr(skb);

	/* check if ip header and tcp header are complete */
	if (iph->tot_len < ip_len + tcp_hdrlen(skb))
		return -1;

	*hdr_flags = LRO_IPV4 | LRO_TCP;
	*iphdr = iph;

	return 0;
}

static int pasemi_mac_unmap_tx_skb(struct pasemi_mac *mac,
static int pasemi_mac_unmap_tx_skb(struct pasemi_mac *mac,
				    struct sk_buff *skb,
				    struct sk_buff *skb,
				    const dma_addr_t *dmas)
				    const dma_addr_t *dmas)
@@ -662,7 +695,7 @@ static int pasemi_mac_clean_rx(struct pasemi_mac_rxring *rx,
		skb_put(skb, len-4);
		skb_put(skb, len-4);


		skb->protocol = eth_type_trans(skb, mac->netdev);
		skb->protocol = eth_type_trans(skb, mac->netdev);
		netif_receive_skb(skb);
		lro_receive_skb(&mac->lro_mgr, skb, (void *)macrx);


next:
next:
		RX_DESC(rx, n) = 0;
		RX_DESC(rx, n) = 0;
@@ -684,6 +717,8 @@ static int pasemi_mac_clean_rx(struct pasemi_mac_rxring *rx,


	rx_ring(mac)->next_to_clean = n;
	rx_ring(mac)->next_to_clean = n;


	lro_flush_all(&mac->lro_mgr);

	/* Increase is in number of 16-byte entries, and since each descriptor
	/* Increase is in number of 16-byte entries, and since each descriptor
	 * with an 8BRES takes up 3x8 bytes (padded to 4x8), increase with
	 * with an 8BRES takes up 3x8 bytes (padded to 4x8), increase with
	 * count*2.
	 * count*2.
@@ -988,7 +1023,7 @@ static int pasemi_mac_open(struct net_device *dev)
		      PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(0x3ff));
		      PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(0x3ff));


	write_iob_reg(PAS_IOB_DMA_RXCH_CFG(mac->rx->chan.chno),
	write_iob_reg(PAS_IOB_DMA_RXCH_CFG(mac->rx->chan.chno),
		      PAS_IOB_DMA_RXCH_CFG_CNTTH(128));
		      PAS_IOB_DMA_RXCH_CFG_CNTTH(256));


	write_iob_reg(PAS_IOB_DMA_TXCH_CFG(mac->tx->chan.chno),
	write_iob_reg(PAS_IOB_DMA_TXCH_CFG(mac->tx->chan.chno),
		      PAS_IOB_DMA_TXCH_CFG_CNTTH(32));
		      PAS_IOB_DMA_TXCH_CFG_CNTTH(32));
@@ -1368,6 +1403,16 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
	dev->features = NETIF_F_IP_CSUM | NETIF_F_LLTX | NETIF_F_SG |
	dev->features = NETIF_F_IP_CSUM | NETIF_F_LLTX | NETIF_F_SG |
			NETIF_F_HIGHDMA;
			NETIF_F_HIGHDMA;


	mac->lro_mgr.max_aggr = LRO_MAX_AGGR;
	mac->lro_mgr.max_desc = MAX_LRO_DESCRIPTORS;
	mac->lro_mgr.lro_arr = mac->lro_desc;
	mac->lro_mgr.get_skb_header = get_skb_hdr;
	mac->lro_mgr.features = LRO_F_NAPI | LRO_F_EXTRACT_VLAN_ID;
	mac->lro_mgr.dev = mac->netdev;
	mac->lro_mgr.ip_summed = CHECKSUM_UNNECESSARY;
	mac->lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY;


	mac->dma_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa007, NULL);
	mac->dma_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa007, NULL);
	if (!mac->dma_pdev) {
	if (!mac->dma_pdev) {
		dev_err(&mac->pdev->dev, "Can't find DMA Controller\n");
		dev_err(&mac->pdev->dev, "Can't find DMA Controller\n");
+5 −0
Original line number Original line Diff line number Diff line
@@ -26,6 +26,8 @@
#include <linux/spinlock.h>
#include <linux/spinlock.h>
#include <linux/phy.h>
#include <linux/phy.h>


#define MAX_LRO_DESCRIPTORS 8

struct pasemi_mac_txring {
struct pasemi_mac_txring {
	struct pasemi_dmachan chan; /* Must be first */
	struct pasemi_dmachan chan; /* Must be first */
	spinlock_t	 lock;
	spinlock_t	 lock;
@@ -64,7 +66,10 @@ struct pasemi_mac {


	u8		mac_addr[6];
	u8		mac_addr[6];


	struct net_lro_mgr	lro_mgr;
	struct net_lro_desc	lro_desc[MAX_LRO_DESCRIPTORS];
	struct timer_list	rxtimer;
	struct timer_list	rxtimer;
	unsigned int		lro_max_aggr;


	struct pasemi_mac_txring *tx;
	struct pasemi_mac_txring *tx;
	struct pasemi_mac_rxring *rx;
	struct pasemi_mac_rxring *rx;