From afea3278f73c14271ee60ca7593ad74b7a946486 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Wed, 5 Mar 2008 12:11:48 -0600 Subject: pasemi_mac: Move RX/TX section enablement to dma_lib Also stop both rx and tx sections before changing the configuration of the dma device during init. Signed-off-by: Olof Johansson Acked-by: Jeff Garzik --- drivers/net/pasemi_mac.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/net/pasemi_mac.c') diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index 2e39e0285d8f..6ea822addde5 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -1043,12 +1043,6 @@ static int pasemi_mac_open(struct net_device *dev) unsigned int flags; int ret; - /* enable rx section */ - write_dma_reg(PAS_DMA_COM_RXCMD, PAS_DMA_COM_RXCMD_EN); - - /* enable tx section */ - write_dma_reg(PAS_DMA_COM_TXCMD, PAS_DMA_COM_TXCMD_EN); - flags = PAS_MAC_CFG_TXP_FCE | PAS_MAC_CFG_TXP_FPC(3) | PAS_MAC_CFG_TXP_SL(3) | PAS_MAC_CFG_TXP_COB(0xf) | PAS_MAC_CFG_TXP_TIFT(8) | PAS_MAC_CFG_TXP_TIFG(12); -- cgit v1.2.3-59-g8ed1b From 8d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Wed, 5 Mar 2008 16:34:16 -0600 Subject: pasemi_mac: jumbo frame support First cut at jumbo frame support. To support large MTU, one or several separate channels must be allocated to calculate the TCP/UDP checksum separately, since the mac lacks enough buffers to hold a whole packet while it's being calculated. Furthermore, it seems that a single function channel is not quite enough to feed one of the 10Gig links, so allocate two channels for XAUI interfaces. Signed-off-by: Olof Johansson Acked-by: Jeff Garzik --- drivers/net/pasemi_mac.c | 294 ++++++++++++++++++++++++++++++++++----- drivers/net/pasemi_mac.h | 15 +- include/asm-powerpc/pasemi_dma.h | 60 +++++++- 3 files changed, 333 insertions(+), 36 deletions(-) (limited to 'drivers/net/pasemi_mac.c') diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index 6ea822addde5..54904ad29ea7 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -59,11 +59,12 @@ /* Must be a power of two */ #define RX_RING_SIZE 2048 #define TX_RING_SIZE 4096 +#define CS_RING_SIZE (TX_RING_SIZE*2) #define LRO_MAX_AGGR 64 #define PE_MIN_MTU 64 -#define PE_MAX_MTU 1500 +#define PE_MAX_MTU 9000 #define PE_DEF_MTU ETH_DATA_LEN #define DEFAULT_MSG_ENABLE \ @@ -81,6 +82,7 @@ #define RX_DESC(rx, num) ((rx)->chan.ring_virt[(num) & (RX_RING_SIZE-1)]) #define RX_DESC_INFO(rx, num) ((rx)->ring_info[(num) & (RX_RING_SIZE-1)]) #define RX_BUFF(rx, num) ((rx)->buffers[(num) & (RX_RING_SIZE-1)]) +#define CS_DESC(cs, num) ((cs)->chan.ring_virt[(num) & (CS_RING_SIZE-1)]) #define RING_USED(ring) (((ring)->next_to_fill - (ring)->next_to_clean) \ & ((ring)->size - 1)) @@ -322,6 +324,103 @@ static int pasemi_mac_unmap_tx_skb(struct pasemi_mac *mac, return (nfrags + 3) & ~1; } +static struct pasemi_mac_csring *pasemi_mac_setup_csring(struct pasemi_mac *mac) +{ + struct pasemi_mac_csring *ring; + u32 val; + unsigned int cfg; + int chno; + + ring = pasemi_dma_alloc_chan(TXCHAN, sizeof(struct pasemi_mac_csring), + offsetof(struct pasemi_mac_csring, chan)); + + if (!ring) { + dev_err(&mac->pdev->dev, "Can't allocate checksum channel\n"); + goto out_chan; + } + + chno = ring->chan.chno; + + ring->size = CS_RING_SIZE; + ring->next_to_fill = 0; + + /* Allocate descriptors */ + if (pasemi_dma_alloc_ring(&ring->chan, CS_RING_SIZE)) + goto out_ring_desc; + + write_dma_reg(PAS_DMA_TXCHAN_BASEL(chno), + PAS_DMA_TXCHAN_BASEL_BRBL(ring->chan.ring_dma)); + val = PAS_DMA_TXCHAN_BASEU_BRBH(ring->chan.ring_dma >> 32); + val |= PAS_DMA_TXCHAN_BASEU_SIZ(CS_RING_SIZE >> 3); + + write_dma_reg(PAS_DMA_TXCHAN_BASEU(chno), val); + + ring->events[0] = pasemi_dma_alloc_flag(); + ring->events[1] = pasemi_dma_alloc_flag(); + if (ring->events[0] < 0 || ring->events[1] < 0) + goto out_flags; + + pasemi_dma_clear_flag(ring->events[0]); + pasemi_dma_clear_flag(ring->events[1]); + + ring->fun = pasemi_dma_alloc_fun(); + if (ring->fun < 0) + goto out_fun; + + cfg = PAS_DMA_TXCHAN_CFG_TY_FUNC | PAS_DMA_TXCHAN_CFG_UP | + PAS_DMA_TXCHAN_CFG_TATTR(ring->fun) | + PAS_DMA_TXCHAN_CFG_LPSQ | PAS_DMA_TXCHAN_CFG_LPDQ; + + if (translation_enabled()) + cfg |= PAS_DMA_TXCHAN_CFG_TRD | PAS_DMA_TXCHAN_CFG_TRR; + + write_dma_reg(PAS_DMA_TXCHAN_CFG(chno), cfg); + + /* enable channel */ + pasemi_dma_start_chan(&ring->chan, PAS_DMA_TXCHAN_TCMDSTA_SZ | + PAS_DMA_TXCHAN_TCMDSTA_DB | + PAS_DMA_TXCHAN_TCMDSTA_DE | + PAS_DMA_TXCHAN_TCMDSTA_DA); + + return ring; + +out_fun: +out_flags: + if (ring->events[0] >= 0) + pasemi_dma_free_flag(ring->events[0]); + if (ring->events[1] >= 0) + pasemi_dma_free_flag(ring->events[1]); + pasemi_dma_free_ring(&ring->chan); +out_ring_desc: + pasemi_dma_free_chan(&ring->chan); +out_chan: + + return NULL; +} + +static void pasemi_mac_setup_csrings(struct pasemi_mac *mac) +{ + int i; + mac->cs[0] = pasemi_mac_setup_csring(mac); + if (mac->type == MAC_TYPE_XAUI) + mac->cs[1] = pasemi_mac_setup_csring(mac); + else + mac->cs[1] = 0; + + for (i = 0; i < MAX_CS; i++) + if (mac->cs[i]) + mac->num_cs++; +} + +static void pasemi_mac_free_csring(struct pasemi_mac_csring *csring) +{ + pasemi_dma_stop_chan(&csring->chan); + pasemi_dma_free_flag(csring->events[0]); + pasemi_dma_free_flag(csring->events[1]); + pasemi_dma_free_ring(&csring->chan); + pasemi_dma_free_chan(&csring->chan); +} + static int pasemi_mac_setup_rx_resources(const struct net_device *dev) { struct pasemi_mac_rxring *ring; @@ -445,7 +544,7 @@ pasemi_mac_setup_tx_resources(const struct net_device *dev) cfg = PAS_DMA_TXCHAN_CFG_TY_IFACE | PAS_DMA_TXCHAN_CFG_TATTR(mac->dma_if) | PAS_DMA_TXCHAN_CFG_UP | - PAS_DMA_TXCHAN_CFG_WT(2); + PAS_DMA_TXCHAN_CFG_WT(4); if (translation_enabled()) cfg |= PAS_DMA_TXCHAN_CFG_TRD | PAS_DMA_TXCHAN_CFG_TRR; @@ -810,13 +909,21 @@ restart: u64 mactx = TX_DESC(txring, i); struct sk_buff *skb; - skb = TX_DESC_INFO(txring, i+1).skb; - nr_frags = TX_DESC_INFO(txring, i).dma; - if ((mactx & XCT_MACTX_E) || (*chan->status & PAS_STATUS_ERROR)) pasemi_mac_tx_error(mac, mactx); + /* Skip over control descriptors */ + if (!(mactx & XCT_MACTX_LLEN_M)) { + TX_DESC(txring, i) = 0; + TX_DESC(txring, i+1) = 0; + buf_count = 2; + continue; + } + + skb = TX_DESC_INFO(txring, i+1).skb; + nr_frags = TX_DESC_INFO(txring, i).dma; + if (unlikely(mactx & XCT_MACTX_O)) /* Not yet transmitted */ break; @@ -1058,6 +1165,12 @@ static int pasemi_mac_open(struct net_device *dev) if (!mac->tx) goto out_tx_ring; + if (dev->mtu > 1500) { + pasemi_mac_setup_csrings(mac); + if (!mac->num_cs) + goto out_tx_ring; + } + /* 0x3ff with 33MHz clock is about 31us */ write_iob_reg(PAS_IOB_DMA_COM_TIMEOUTCFG, PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(0x3ff)); @@ -1241,7 +1354,7 @@ static int pasemi_mac_close(struct net_device *dev) { struct pasemi_mac *mac = netdev_priv(dev); unsigned int sta; - int rxch, txch; + int rxch, txch, i; rxch = rx_ring(mac)->chan.chno; txch = tx_ring(mac)->chan.chno; @@ -1286,6 +1399,9 @@ static int pasemi_mac_close(struct net_device *dev) free_irq(mac->tx->chan.irq, mac->tx); free_irq(mac->rx->chan.irq, mac->rx); + for (i = 0; i < mac->num_cs; i++) + pasemi_mac_free_csring(mac->cs[i]); + /* Free resources */ pasemi_mac_free_rx_resources(mac); pasemi_mac_free_tx_resources(mac); @@ -1293,35 +1409,113 @@ static int pasemi_mac_close(struct net_device *dev) return 0; } +static void pasemi_mac_queue_csdesc(const struct sk_buff *skb, + const dma_addr_t *map, + const unsigned int *map_size, + struct pasemi_mac_txring *txring, + struct pasemi_mac_csring *csring) +{ + u64 fund; + dma_addr_t cs_dest; + const int nh_off = skb_network_offset(skb); + const int nh_len = skb_network_header_len(skb); + const int nfrags = skb_shinfo(skb)->nr_frags; + int cs_size, i, fill, hdr, cpyhdr, evt; + dma_addr_t csdma; + + fund = XCT_FUN_ST | XCT_FUN_RR_8BRES | + XCT_FUN_O | XCT_FUN_FUN(csring->fun) | + XCT_FUN_CRM_SIG | XCT_FUN_LLEN(skb->len - nh_off) | + XCT_FUN_SHL(nh_len >> 2) | XCT_FUN_SE; + + switch (ip_hdr(skb)->protocol) { + case IPPROTO_TCP: + fund |= XCT_FUN_SIG_TCP4; + /* TCP checksum is 16 bytes into the header */ + cs_dest = map[0] + skb_transport_offset(skb) + 16; + break; + case IPPROTO_UDP: + fund |= XCT_FUN_SIG_UDP4; + /* UDP checksum is 6 bytes into the header */ + cs_dest = map[0] + skb_transport_offset(skb) + 6; + break; + default: + BUG(); + } + + /* Do the checksum offloaded */ + fill = csring->next_to_fill; + hdr = fill; + + CS_DESC(csring, fill++) = fund; + /* Room for 8BRES. Checksum result is really 2 bytes into it */ + csdma = csring->chan.ring_dma + (fill & (CS_RING_SIZE-1)) * 8 + 2; + CS_DESC(csring, fill++) = 0; + + CS_DESC(csring, fill) = XCT_PTR_LEN(map_size[0]-nh_off) | XCT_PTR_ADDR(map[0]+nh_off); + for (i = 1; i <= nfrags; i++) + CS_DESC(csring, fill+i) = XCT_PTR_LEN(map_size[i]) | XCT_PTR_ADDR(map[i]); + + fill += i; + if (fill & 1) + fill++; + + /* Copy the result into the TCP packet */ + cpyhdr = fill; + CS_DESC(csring, fill++) = XCT_FUN_O | XCT_FUN_FUN(csring->fun) | + XCT_FUN_LLEN(2) | XCT_FUN_SE; + CS_DESC(csring, fill++) = XCT_PTR_LEN(2) | XCT_PTR_ADDR(cs_dest) | XCT_PTR_T; + CS_DESC(csring, fill++) = XCT_PTR_LEN(2) | XCT_PTR_ADDR(csdma); + fill++; + + evt = !csring->last_event; + csring->last_event = evt; + + /* Event handshaking with MAC TX */ + CS_DESC(csring, fill++) = CTRL_CMD_T | CTRL_CMD_META_EVT | CTRL_CMD_O | + CTRL_CMD_ETYPE_SET | CTRL_CMD_REG(csring->events[evt]); + CS_DESC(csring, fill++) = 0; + CS_DESC(csring, fill++) = CTRL_CMD_T | CTRL_CMD_META_EVT | CTRL_CMD_O | + CTRL_CMD_ETYPE_WCLR | CTRL_CMD_REG(csring->events[!evt]); + CS_DESC(csring, fill++) = 0; + csring->next_to_fill = fill & (CS_RING_SIZE-1); + + cs_size = fill - hdr; + write_dma_reg(PAS_DMA_TXCHAN_INCR(csring->chan.chno), (cs_size) >> 1); + + /* TX-side event handshaking */ + fill = txring->next_to_fill; + TX_DESC(txring, fill++) = CTRL_CMD_T | CTRL_CMD_META_EVT | CTRL_CMD_O | + CTRL_CMD_ETYPE_WSET | CTRL_CMD_REG(csring->events[evt]); + TX_DESC(txring, fill++) = 0; + TX_DESC(txring, fill++) = CTRL_CMD_T | CTRL_CMD_META_EVT | CTRL_CMD_O | + CTRL_CMD_ETYPE_CLR | CTRL_CMD_REG(csring->events[!evt]); + TX_DESC(txring, fill++) = 0; + txring->next_to_fill = fill; + + write_dma_reg(PAS_DMA_TXCHAN_INCR(txring->chan.chno), 2); + + return; +} + static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev) { - struct pasemi_mac *mac = netdev_priv(dev); - struct pasemi_mac_txring *txring; - u64 dflags, mactx; + struct pasemi_mac * const mac = netdev_priv(dev); + struct pasemi_mac_txring * const txring = tx_ring(mac); + struct pasemi_mac_csring *csring; + u64 dflags = 0; + u64 mactx; dma_addr_t map[MAX_SKB_FRAGS+1]; unsigned int map_size[MAX_SKB_FRAGS+1]; unsigned long flags; int i, nfrags; int fill; + const int nh_off = skb_network_offset(skb); + const int nh_len = skb_network_header_len(skb); - dflags = XCT_MACTX_O | XCT_MACTX_ST | XCT_MACTX_CRC_PAD; - - if (skb->ip_summed == CHECKSUM_PARTIAL) { - const unsigned char *nh = skb_network_header(skb); + prefetch(&txring->ring_info); - switch (ip_hdr(skb)->protocol) { - case IPPROTO_TCP: - dflags |= XCT_MACTX_CSUM_TCP; - dflags |= XCT_MACTX_IPH(skb_network_header_len(skb) >> 2); - dflags |= XCT_MACTX_IPO(nh - skb->data); - break; - case IPPROTO_UDP: - dflags |= XCT_MACTX_CSUM_UDP; - dflags |= XCT_MACTX_IPH(skb_network_header_len(skb) >> 2); - dflags |= XCT_MACTX_IPO(nh - skb->data); - break; - } - } + dflags = XCT_MACTX_O | XCT_MACTX_ST | XCT_MACTX_CRC_PAD; nfrags = skb_shinfo(skb)->nr_frags; @@ -1344,24 +1538,46 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev) } } - mactx = dflags | XCT_MACTX_LLEN(skb->len); + if (skb->ip_summed == CHECKSUM_PARTIAL && skb->len <= 1540) { + switch (ip_hdr(skb)->protocol) { + case IPPROTO_TCP: + dflags |= XCT_MACTX_CSUM_TCP; + dflags |= XCT_MACTX_IPH(nh_len >> 2); + dflags |= XCT_MACTX_IPO(nh_off); + break; + case IPPROTO_UDP: + dflags |= XCT_MACTX_CSUM_UDP; + dflags |= XCT_MACTX_IPH(nh_len >> 2); + dflags |= XCT_MACTX_IPO(nh_off); + break; + default: + WARN_ON(1); + } + } - txring = tx_ring(mac); + mactx = dflags | XCT_MACTX_LLEN(skb->len); spin_lock_irqsave(&txring->lock, flags); - fill = txring->next_to_fill; - /* Avoid stepping on the same cache line that the DMA controller * is currently about to send, so leave at least 8 words available. * Total free space needed is mactx + fragments + 8 */ - if (RING_AVAIL(txring) < nfrags + 10) { + if (RING_AVAIL(txring) < nfrags + 14) { /* no room -- stop the queue and wait for tx intr */ netif_stop_queue(dev); goto out_err; } + /* Queue up checksum + event descriptors, if needed */ + if (mac->num_cs && skb->ip_summed == CHECKSUM_PARTIAL && skb->len > 1540) { + csring = mac->cs[mac->last_cs]; + mac->last_cs = (mac->last_cs + 1) % mac->num_cs; + + pasemi_mac_queue_csdesc(skb, map, map_size, txring, csring); + } + + fill = txring->next_to_fill; TX_DESC(txring, fill) = mactx; TX_DESC_INFO(txring, fill).dma = nfrags; fill++; @@ -1439,8 +1655,9 @@ 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; + unsigned int rcmdsta = 0; int running; + int ret = 0; if (new_mtu < PE_MIN_MTU || new_mtu > PE_MAX_MTU) return -EINVAL; @@ -1462,6 +1679,16 @@ static int pasemi_mac_change_mtu(struct net_device *dev, int new_mtu) pasemi_mac_pause_rxint(mac); pasemi_mac_clean_rx(rx_ring(mac), RX_RING_SIZE); pasemi_mac_free_rx_buffers(mac); + + } + + /* Setup checksum channels if large MTU and none already allocated */ + if (new_mtu > 1500 && !mac->num_cs) { + pasemi_mac_setup_csrings(mac); + if (!mac->num_cs) { + ret = -ENOMEM; + goto out; + } } /* Change maxf, i.e. what size frames are accepted. @@ -1476,6 +1703,7 @@ static int pasemi_mac_change_mtu(struct net_device *dev, int new_mtu) /* MTU + ETH_HLEN + VLAN_HLEN + 2 64B cachelines */ mac->bufsz = new_mtu + ETH_HLEN + ETH_FCS_LEN + LOCAL_SKB_ALIGN + 128; +out: if (running) { write_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if), rcmdsta | PAS_DMA_RXINT_RCMDSTA_EN); @@ -1488,7 +1716,7 @@ static int pasemi_mac_change_mtu(struct net_device *dev, int new_mtu) pasemi_mac_intf_enable(mac); } - return 0; + return ret; } static int __devinit diff --git a/drivers/net/pasemi_mac.h b/drivers/net/pasemi_mac.h index 99e7b9329a6f..90c51670a1e7 100644 --- a/drivers/net/pasemi_mac.h +++ b/drivers/net/pasemi_mac.h @@ -27,6 +27,7 @@ #include #define MAX_LRO_DESCRIPTORS 8 +#define MAX_CS 2 struct pasemi_mac_txring { struct pasemi_dmachan chan; /* Must be first */ @@ -51,6 +52,15 @@ struct pasemi_mac_rxring { struct pasemi_mac *mac; /* Needed in intr handler */ }; +struct pasemi_mac_csring { + struct pasemi_dmachan chan; + unsigned int size; + unsigned int next_to_fill; + int events[2]; + int last_event; + int fun; +}; + struct pasemi_mac { struct net_device *netdev; struct pci_dev *pdev; @@ -60,10 +70,12 @@ struct pasemi_mac { struct napi_struct napi; int bufsz; /* RX ring buffer size */ + int last_cs; + int num_cs; + u32 dma_if; u8 type; #define MAC_TYPE_GMAC 1 #define MAC_TYPE_XAUI 2 - u32 dma_if; u8 mac_addr[6]; @@ -74,6 +86,7 @@ struct pasemi_mac { struct pasemi_mac_txring *tx; struct pasemi_mac_rxring *rx; + struct pasemi_mac_csring *cs[MAX_CS]; char tx_irq_name[10]; /* "eth%d tx" */ char rx_irq_name[10]; /* "eth%d rx" */ int link; diff --git a/include/asm-powerpc/pasemi_dma.h b/include/asm-powerpc/pasemi_dma.h index facb2bdea45c..19fd7933e2d9 100644 --- a/include/asm-powerpc/pasemi_dma.h +++ b/include/asm-powerpc/pasemi_dma.h @@ -128,11 +128,16 @@ enum { #define PAS_DMA_TXCHAN_TCMDSTA_DA 0x00000100 #define PAS_DMA_TXCHAN_CFG(c) (0x304+(c)*_PAS_DMA_TXCHAN_STRIDE) #define PAS_DMA_TXCHAN_CFG_TY_IFACE 0x00000000 /* Type = interface */ +#define PAS_DMA_TXCHAN_CFG_TY_COPY 0x00000001 /* Type = copy only */ +#define PAS_DMA_TXCHAN_CFG_TY_FUNC 0x00000002 /* Type = function */ +#define PAS_DMA_TXCHAN_CFG_TY_XOR 0x00000003 /* Type = xor only */ #define PAS_DMA_TXCHAN_CFG_TATTR_M 0x0000003c #define PAS_DMA_TXCHAN_CFG_TATTR_S 2 #define PAS_DMA_TXCHAN_CFG_TATTR(x) (((x) << PAS_DMA_TXCHAN_CFG_TATTR_S) & \ PAS_DMA_TXCHAN_CFG_TATTR_M) -#define PAS_DMA_TXCHAN_CFG_WT_M 0x000001c0 +#define PAS_DMA_TXCHAN_CFG_LPDQ 0x00000800 +#define PAS_DMA_TXCHAN_CFG_LPSQ 0x00000400 +#define PAS_DMA_TXCHAN_CFG_WT_M 0x000003c0 #define PAS_DMA_TXCHAN_CFG_WT_S 6 #define PAS_DMA_TXCHAN_CFG_WT(x) (((x) << PAS_DMA_TXCHAN_CFG_WT_S) & \ PAS_DMA_TXCHAN_CFG_WT_M) @@ -399,11 +404,62 @@ enum { XCT_COPY_LLEN_M) #define XCT_COPY_SE 0x0000000000000001ull +/* Function descriptor fields */ +#define XCT_FUN_T 0x8000000000000000ull +#define XCT_FUN_ST 0x4000000000000000ull +#define XCT_FUN_RR_M 0x3000000000000000ull +#define XCT_FUN_RR_NORES 0x0000000000000000ull +#define XCT_FUN_RR_8BRES 0x1000000000000000ull +#define XCT_FUN_RR_24BRES 0x2000000000000000ull +#define XCT_FUN_RR_40BRES 0x3000000000000000ull +#define XCT_FUN_I 0x0800000000000000ull +#define XCT_FUN_O 0x0400000000000000ull +#define XCT_FUN_E 0x0200000000000000ull +#define XCT_FUN_FUN_M 0x01c0000000000000ull +#define XCT_FUN_FUN_S 54 +#define XCT_FUN_FUN(x) ((((long)(x)) << XCT_FUN_FUN_S) & XCT_FUN_FUN_M) +#define XCT_FUN_CRM_M 0x0038000000000000ull +#define XCT_FUN_CRM_NOP 0x0000000000000000ull +#define XCT_FUN_CRM_SIG 0x0008000000000000ull +#define XCT_FUN_LLEN_M 0x0007ffff00000000ull +#define XCT_FUN_LLEN_S 32 +#define XCT_FUN_LLEN(x) ((((long)(x)) << XCT_FUN_LLEN_S) & XCT_FUN_LLEN_M) +#define XCT_FUN_SHL_M 0x00000000f8000000ull +#define XCT_FUN_SHL_S 27 +#define XCT_FUN_SHL(x) ((((long)(x)) << XCT_FUN_SHL_S) & XCT_FUN_SHL_M) +#define XCT_FUN_CHL_M 0x0000000007c00000ull +#define XCT_FUN_HSZ_M 0x00000000003c0000ull +#define XCT_FUN_ALG_M 0x0000000000038000ull +#define XCT_FUN_HP 0x0000000000004000ull +#define XCT_FUN_BCM_M 0x0000000000003800ull +#define XCT_FUN_BCP_M 0x0000000000000600ull +#define XCT_FUN_SIG_M 0x00000000000001f0ull +#define XCT_FUN_SIG_TCP4 0x0000000000000140ull +#define XCT_FUN_SIG_TCP6 0x0000000000000150ull +#define XCT_FUN_SIG_UDP4 0x0000000000000160ull +#define XCT_FUN_SIG_UDP6 0x0000000000000170ull +#define XCT_FUN_A 0x0000000000000008ull +#define XCT_FUN_C 0x0000000000000004ull +#define XCT_FUN_AL2 0x0000000000000002ull +#define XCT_FUN_SE 0x0000000000000001ull + +/* Function descriptor 8byte result fields */ +#define XCT_FUNRES_8B_CS_M 0x0000ffff00000000ull +#define XCT_FUNRES_8B_CS_S 32 +#define XCT_FUNRES_8B_CRC_M 0x00000000ffffffffull +#define XCT_FUNRES_8B_CRC_S 0 + /* Control descriptor fields */ #define CTRL_CMD_T 0x8000000000000000ull #define CTRL_CMD_META_EVT 0x2000000000000000ull #define CTRL_CMD_O 0x0400000000000000ull -#define CTRL_CMD_REG_M 0x000000000000000full +#define CTRL_CMD_ETYPE_M 0x0038000000000000ull +#define CTRL_CMD_ETYPE_EXT 0x0000000000000000ull +#define CTRL_CMD_ETYPE_WSET 0x0020000000000000ull +#define CTRL_CMD_ETYPE_WCLR 0x0028000000000000ull +#define CTRL_CMD_ETYPE_SET 0x0030000000000000ull +#define CTRL_CMD_ETYPE_CLR 0x0038000000000000ull +#define CTRL_CMD_REG_M 0x000000000000007full #define CTRL_CMD_REG_S 0 #define CTRL_CMD_REG(x) ((((long)(x)) << CTRL_CMD_REG_S) & \ CTRL_CMD_REG_M) -- cgit v1.2.3-59-g8ed1b From 251567848f2f446f4356f969329a8188faf1fe90 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Wed, 20 Feb 2008 20:57:58 -0600 Subject: pasemi_mac: Enable GSO by default Ethtool support will handle the runtime toggling, but we do quite a bit better with it on by default so just leave it on for now. Signed-off-by: Olof Johansson Acked-by: Jeff Garzik --- drivers/net/pasemi_mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/pasemi_mac.c') diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index 54904ad29ea7..5ee7e4a73ae0 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -1750,7 +1750,7 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netif_napi_add(dev, &mac->napi, pasemi_mac_poll, 64); dev->features = NETIF_F_IP_CSUM | NETIF_F_LLTX | NETIF_F_SG | - NETIF_F_HIGHDMA; + NETIF_F_HIGHDMA | NETIF_F_GSO; mac->lro_mgr.max_aggr = LRO_MAX_AGGR; mac->lro_mgr.max_desc = MAX_LRO_DESCRIPTORS; -- cgit v1.2.3-59-g8ed1b From e37c772e36a7943b2e0bd8f48312e78474c0df15 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Wed, 20 Feb 2008 20:57:59 -0600 Subject: pasemi_mac: basic ethtool support First cut at ethtool support, to be completed over time. Signed-off-by: Olof Johansson Acked-by: Jeff Garzik --- drivers/net/Makefile | 3 +- drivers/net/pasemi_mac.c | 26 ++----- drivers/net/pasemi_mac.h | 20 +++++ drivers/net/pasemi_mac_ethtool.c | 159 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 189 insertions(+), 19 deletions(-) create mode 100644 drivers/net/pasemi_mac_ethtool.c (limited to 'drivers/net/pasemi_mac.c') diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 3b1ea321dc05..4b442739e7bf 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -218,7 +218,8 @@ obj-$(CONFIG_SMC911X) += smc911x.o obj-$(CONFIG_BFIN_MAC) += bfin_mac.o obj-$(CONFIG_DM9000) += dm9000.o obj-$(CONFIG_FEC_8XX) += fec_8xx/ -obj-$(CONFIG_PASEMI_MAC) += pasemi_mac.o +obj-$(CONFIG_PASEMI_MAC) += pasemi_mac_driver.o +pasemi_mac_driver-objs := pasemi_mac.o pasemi_mac_ethtool.o obj-$(CONFIG_MLX4_CORE) += mlx4/ obj-$(CONFIG_ENC28J60) += enc28j60.o diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index 5ee7e4a73ae0..c50f0f4de6d8 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -55,12 +55,6 @@ * - Multiqueue RX/TX */ - -/* Must be a power of two */ -#define RX_RING_SIZE 2048 -#define TX_RING_SIZE 4096 -#define CS_RING_SIZE (TX_RING_SIZE*2) - #define LRO_MAX_AGGR 64 #define PE_MIN_MTU 64 @@ -77,17 +71,6 @@ NETIF_MSG_RX_ERR | \ NETIF_MSG_TX_ERR) -#define TX_DESC(tx, num) ((tx)->chan.ring_virt[(num) & (TX_RING_SIZE-1)]) -#define TX_DESC_INFO(tx, num) ((tx)->ring_info[(num) & (TX_RING_SIZE-1)]) -#define RX_DESC(rx, num) ((rx)->chan.ring_virt[(num) & (RX_RING_SIZE-1)]) -#define RX_DESC_INFO(rx, num) ((rx)->ring_info[(num) & (RX_RING_SIZE-1)]) -#define RX_BUFF(rx, num) ((rx)->buffers[(num) & (RX_RING_SIZE-1)]) -#define CS_DESC(cs, num) ((cs)->chan.ring_virt[(num) & (CS_RING_SIZE-1)]) - -#define RING_USED(ring) (((ring)->next_to_fill - (ring)->next_to_clean) \ - & ((ring)->size - 1)) -#define RING_AVAIL(ring) ((ring->size) - RING_USED(ring)) - MODULE_LICENSE("GPL"); MODULE_AUTHOR ("Olof Johansson "); MODULE_DESCRIPTION("PA Semi PWRficient Ethernet driver"); @@ -96,6 +79,8 @@ static int debug = -1; /* -1 == use DEFAULT_MSG_ENABLE as value */ module_param(debug, int, 0); MODULE_PARM_DESC(debug, "PA Semi MAC bitmapped debugging message enable value"); +extern const struct ethtool_ops pasemi_mac_ethtool_ops; + static int translation_enabled(void) { #if defined(CONFIG_PPC_PASEMI_IOMMU_DMA_FORCE) @@ -1148,7 +1133,7 @@ static int pasemi_mac_open(struct net_device *dev) { struct pasemi_mac *mac = netdev_priv(dev); unsigned int flags; - int ret; + int i, ret; flags = PAS_MAC_CFG_TXP_FCE | PAS_MAC_CFG_TXP_FPC(3) | PAS_MAC_CFG_TXP_SL(3) | PAS_MAC_CFG_TXP_COB(0xf) | @@ -1171,6 +1156,10 @@ static int pasemi_mac_open(struct net_device *dev) goto out_tx_ring; } + /* Zero out rmon counters */ + for (i = 0; i < 32; i++) + write_mac_reg(mac, PAS_MAC_RMON(i), 0); + /* 0x3ff with 33MHz clock is about 31us */ write_iob_reg(PAS_IOB_DMA_COM_TIMEOUTCFG, PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(0x3ff)); @@ -1812,6 +1801,7 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) mac->bufsz = dev->mtu + ETH_HLEN + ETH_FCS_LEN + LOCAL_SKB_ALIGN + 128; dev->change_mtu = pasemi_mac_change_mtu; + dev->ethtool_ops = &pasemi_mac_ethtool_ops; if (err) goto out; diff --git a/drivers/net/pasemi_mac.h b/drivers/net/pasemi_mac.h index 90c51670a1e7..1a115ec60b53 100644 --- a/drivers/net/pasemi_mac.h +++ b/drivers/net/pasemi_mac.h @@ -26,6 +26,12 @@ #include #include +/* Must be a power of two */ +#define RX_RING_SIZE 2048 +#define TX_RING_SIZE 4096 +#define CS_RING_SIZE (TX_RING_SIZE*2) + + #define MAX_LRO_DESCRIPTORS 8 #define MAX_CS 2 @@ -103,6 +109,16 @@ struct pasemi_mac_buffer { dma_addr_t dma; }; +#define TX_DESC(tx, num) ((tx)->chan.ring_virt[(num) & (TX_RING_SIZE-1)]) +#define TX_DESC_INFO(tx, num) ((tx)->ring_info[(num) & (TX_RING_SIZE-1)]) +#define RX_DESC(rx, num) ((rx)->chan.ring_virt[(num) & (RX_RING_SIZE-1)]) +#define RX_DESC_INFO(rx, num) ((rx)->ring_info[(num) & (RX_RING_SIZE-1)]) +#define RX_BUFF(rx, num) ((rx)->buffers[(num) & (RX_RING_SIZE-1)]) +#define CS_DESC(cs, num) ((cs)->chan.ring_virt[(num) & (CS_RING_SIZE-1)]) + +#define RING_USED(ring) (((ring)->next_to_fill - (ring)->next_to_clean) \ + & ((ring)->size - 1)) +#define RING_AVAIL(ring) ((ring->size) - RING_USED(ring)) /* PCI register offsets and formats */ @@ -114,6 +130,7 @@ enum { PAS_MAC_CFG_ADR0 = 0x8c, PAS_MAC_CFG_ADR1 = 0x90, PAS_MAC_CFG_TXP = 0x98, + PAS_MAC_CFG_RMON = 0x100, PAS_MAC_IPC_CHNL = 0x208, }; @@ -185,6 +202,8 @@ enum { #define PAS_MAC_CFG_TXP_TIFG(x) (((x) << PAS_MAC_CFG_TXP_TIFG_S) & \ PAS_MAC_CFG_TXP_TIFG_M) +#define PAS_MAC_RMON(r) (0x100+(r)*4) + #define PAS_MAC_IPC_CHNL_DCHNO_M 0x003f0000 #define PAS_MAC_IPC_CHNL_DCHNO_S 16 #define PAS_MAC_IPC_CHNL_DCHNO(x) (((x) << PAS_MAC_IPC_CHNL_DCHNO_S) & \ @@ -194,4 +213,5 @@ enum { #define PAS_MAC_IPC_CHNL_BCH(x) (((x) << PAS_MAC_IPC_CHNL_BCH_S) & \ PAS_MAC_IPC_CHNL_BCH_M) + #endif /* PASEMI_MAC_H */ diff --git a/drivers/net/pasemi_mac_ethtool.c b/drivers/net/pasemi_mac_ethtool.c new file mode 100644 index 000000000000..5e8df3afea64 --- /dev/null +++ b/drivers/net/pasemi_mac_ethtool.c @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2006-2008 PA Semi, Inc + * + * Ethtool hooks for the PA Semi PWRficient onchip 1G/10G Ethernet MACs + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include +#include +#include +#include + +#include +#include "pasemi_mac.h" + +static struct { + const char str[ETH_GSTRING_LEN]; +} ethtool_stats_keys[] = { + { "rx-drops" }, + { "rx-bytes" }, + { "rx-packets" }, + { "rx-broadcast-packets" }, + { "rx-multicast-packets" }, + { "rx-crc-errors" }, + { "rx-undersize-errors" }, + { "rx-oversize-errors" }, + { "rx-short-fragment-errors" }, + { "rx-jabber-errors" }, + { "rx-64-byte-packets" }, + { "rx-65-127-byte-packets" }, + { "rx-128-255-byte-packets" }, + { "rx-256-511-byte-packets" }, + { "rx-512-1023-byte-packets" }, + { "rx-1024-1518-byte-packets" }, + { "rx-pause-frames" }, + { "tx-bytes" }, + { "tx-packets" }, + { "tx-broadcast-packets" }, + { "tx-multicast-packets" }, + { "tx-collisions" }, + { "tx-late-collisions" }, + { "tx-excessive-collisions" }, + { "tx-crc-errors" }, + { "tx-undersize-errors" }, + { "tx-oversize-errors" }, + { "tx-64-byte-packets" }, + { "tx-65-127-byte-packets" }, + { "tx-128-255-byte-packets" }, + { "tx-256-511-byte-packets" }, + { "tx-512-1023-byte-packets" }, + { "tx-1024-1518-byte-packets" }, +}; + +static int +pasemi_mac_ethtool_get_settings(struct net_device *netdev, + struct ethtool_cmd *cmd) +{ + struct pasemi_mac *mac = netdev_priv(netdev); + struct phy_device *phydev = mac->phydev; + + return phy_ethtool_gset(phydev, cmd); +} + +static void +pasemi_mac_ethtool_get_drvinfo(struct net_device *netdev, + struct ethtool_drvinfo *drvinfo) +{ + struct pasemi_mac *mac; + mac = netdev_priv(netdev); + + /* clear and fill out info */ + memset(drvinfo, 0, sizeof(struct ethtool_drvinfo)); + strncpy(drvinfo->driver, "pasemi_mac", 12); + strcpy(drvinfo->version, "N/A"); + strcpy(drvinfo->fw_version, "N/A"); + strncpy(drvinfo->bus_info, pci_name(mac->pdev), 32); +} + +static u32 +pasemi_mac_ethtool_get_msglevel(struct net_device *netdev) +{ + struct pasemi_mac *mac = netdev_priv(netdev); + return mac->msg_enable; +} + +static void +pasemi_mac_ethtool_set_msglevel(struct net_device *netdev, + u32 level) +{ + struct pasemi_mac *mac = netdev_priv(netdev); + mac->msg_enable = level; +} + + +static void +pasemi_mac_ethtool_get_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ering) +{ + struct pasemi_mac *mac = netdev->priv; + + ering->tx_max_pending = TX_RING_SIZE/2; + ering->tx_pending = RING_USED(mac->tx)/2; + ering->rx_max_pending = RX_RING_SIZE/4; + ering->rx_pending = RING_USED(mac->rx)/4; +} + +static int pasemi_mac_get_sset_count(struct net_device *netdev, int sset) +{ + switch (sset) { + case ETH_SS_STATS: + return ARRAY_SIZE(ethtool_stats_keys); + default: + return -EOPNOTSUPP; + } +} + +static void pasemi_mac_get_ethtool_stats(struct net_device *netdev, + struct ethtool_stats *stats, u64 *data) +{ + struct pasemi_mac *mac = netdev->priv; + int i; + + data[0] = pasemi_read_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if)) + >> PAS_DMA_RXINT_RCMDSTA_DROPS_S; + for (i = 0; i < 32; i++) + data[1+i] = pasemi_read_mac_reg(mac->dma_if, PAS_MAC_RMON(i)); +} + +static void pasemi_mac_get_strings(struct net_device *netdev, u32 stringset, + u8 *data) +{ + memcpy(data, ethtool_stats_keys, sizeof(ethtool_stats_keys)); +} + +const struct ethtool_ops pasemi_mac_ethtool_ops = { + .get_settings = pasemi_mac_ethtool_get_settings, + .get_drvinfo = pasemi_mac_ethtool_get_drvinfo, + .get_msglevel = pasemi_mac_ethtool_get_msglevel, + .set_msglevel = pasemi_mac_ethtool_set_msglevel, + .get_link = ethtool_op_get_link, + .get_ringparam = pasemi_mac_ethtool_get_ringparam, + .get_strings = pasemi_mac_get_strings, + .get_sset_count = pasemi_mac_get_sset_count, + .get_ethtool_stats = pasemi_mac_get_ethtool_stats, +}; + -- cgit v1.2.3-59-g8ed1b From 1724ac2ef1caf5b4f764d4b86a85d552a7d7c8fb Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Tue, 25 Mar 2008 09:58:40 -0500 Subject: pasemi_mac: Jumbo frame bugfixes Fix a couple of corner cases around interface up/down when jumbo frames are configured. Resources weren't always freed and reallocated properly. Signed-off-by: Olof Johansson Acked-by: Jeff Garzik --- drivers/net/pasemi_mac.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers/net/pasemi_mac.c') diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index c50f0f4de6d8..abb1dc4592f7 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -404,6 +404,7 @@ static void pasemi_mac_free_csring(struct pasemi_mac_csring *csring) pasemi_dma_free_flag(csring->events[1]); pasemi_dma_free_ring(&csring->chan); pasemi_dma_free_chan(&csring->chan); + pasemi_dma_free_fun(csring->fun); } static int pasemi_mac_setup_rx_resources(const struct net_device *dev) @@ -1150,7 +1151,10 @@ static int pasemi_mac_open(struct net_device *dev) if (!mac->tx) goto out_tx_ring; - if (dev->mtu > 1500) { + /* We might already have allocated rings in case mtu was changed + * before interface was brought up. + */ + if (dev->mtu > 1500 && !mac->num_cs) { pasemi_mac_setup_csrings(mac); if (!mac->num_cs) goto out_tx_ring; @@ -1388,8 +1392,12 @@ static int pasemi_mac_close(struct net_device *dev) free_irq(mac->tx->chan.irq, mac->tx); free_irq(mac->rx->chan.irq, mac->rx); - for (i = 0; i < mac->num_cs; i++) + for (i = 0; i < mac->num_cs; i++) { pasemi_mac_free_csring(mac->cs[i]); + mac->cs[i] = NULL; + } + + mac->num_cs = 0; /* Free resources */ pasemi_mac_free_rx_resources(mac); -- cgit v1.2.3-59-g8ed1b From 6e62040c5533a385b90fcb2e33235ad7d351d3e0 Mon Sep 17 00:00:00 2001 From: Nate Case Date: Fri, 21 Mar 2008 17:02:42 -0500 Subject: pasemi_mac: Netpoll support Add netpoll support to allow use of netconsole. Signed-off-by: Nate Case Signed-off-by: Olof Johansson Acked-by: Jeff Garzik --- drivers/net/pasemi_mac.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'drivers/net/pasemi_mac.c') diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index abb1dc4592f7..965f2e4b3452 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -1648,6 +1648,26 @@ static int pasemi_mac_poll(struct napi_struct *napi, int budget) return pkts; } +#ifdef CONFIG_NET_POLL_CONTROLLER +/* + * Polling 'interrupt' - used by things like netconsole to send skbs + * without having to re-enable interrupts. It's not called while + * the interrupt routine is executing. + */ +static void pasemi_mac_netpoll(struct net_device *dev) +{ + const struct pasemi_mac *mac = netdev_priv(dev); + + disable_irq(mac->tx->chan.irq); + pasemi_mac_tx_intr(mac->tx->chan.irq, mac->tx); + enable_irq(mac->tx->chan.irq); + + disable_irq(mac->rx->chan.irq); + pasemi_mac_rx_intr(mac->rx->chan.irq, mac->rx); + enable_irq(mac->rx->chan.irq); +} +#endif + static int pasemi_mac_change_mtu(struct net_device *dev, int new_mtu) { struct pasemi_mac *mac = netdev_priv(dev); @@ -1807,6 +1827,9 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 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; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = pasemi_mac_netpoll; +#endif dev->change_mtu = pasemi_mac_change_mtu; dev->ethtool_ops = &pasemi_mac_ethtool_ops; -- cgit v1.2.3-59-g8ed1b