1f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson/*
2f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson * Copyright (C) 2006-2007 PA Semi, Inc
3f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson *
4f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson * Driver for the PA Semi PWRficient onchip 1G/10G Ethernet MACs
5f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson *
6f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson * This program is free software; you can redistribute it and/or modify
7f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson * it under the terms of the GNU General Public License version 2 as
8f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson * published by the Free Software Foundation.
9f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson *
10f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson * This program is distributed in the hope that it will be useful,
11f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson * but WITHOUT ANY WARRANTY; without even the implied warranty of
12f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson * GNU General Public License for more details.
14f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson *
15f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson * You should have received a copy of the GNU General Public License
16f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson * along with this program; if not, write to the Free Software
17f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
18f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson */
19f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
20f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson#include <linux/init.h>
21f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson#include <linux/module.h>
22f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson#include <linux/pci.h>
235a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
24f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson#include <linux/interrupt.h>
25f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson#include <linux/dmaengine.h>
26f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson#include <linux/delay.h>
27f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson#include <linux/netdevice.h>
281dd2d06c0459a2f1bffc56765e3cc57427818867Grant Likely#include <linux/of_mdio.h>
29f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson#include <linux/etherdevice.h>
30f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson#include <asm/dma-mapping.h>
31f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson#include <linux/in.h>
32f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson#include <linux/skbuff.h>
33f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
34f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson#include <linux/ip.h>
35f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson#include <linux/tcp.h>
36f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson#include <net/checksum.h>
3728ae79f531014bb3ad95b6efa0e0603069087bc5Olof Johansson#include <linux/inet_lro.h>
3870c71606190e9115e5f8363bfcd164c582eb314aPaul Gortmaker#include <linux/prefetch.h>
39f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
40771f7404a9deca902594823d616cd7a84f827982Olof Johansson#include <asm/irq.h>
41af289e803fdf2fcd19cf4a57c3c896dba146c756Olof Johansson#include <asm/firmware.h>
4240afa5315823761b174926235dc38be24dc3ea63Olof Johansson#include <asm/pasemi_dma.h>
43771f7404a9deca902594823d616cd7a84f827982Olof Johansson
44f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson#include "pasemi_mac.h"
45f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
468dc121a4b620090e594945fd36f878836fc5a14aOlof Johansson/* We have our own align, since ppc64 in general has it at 0 because
478dc121a4b620090e594945fd36f878836fc5a14aOlof Johansson * of design flaws in some of the server bridge chips. However, for
488dc121a4b620090e594945fd36f878836fc5a14aOlof Johansson * PWRficient doing the unaligned copies is more expensive than doing
498dc121a4b620090e594945fd36f878836fc5a14aOlof Johansson * unaligned DMA, so make sure the data is aligned instead.
508dc121a4b620090e594945fd36f878836fc5a14aOlof Johansson */
518dc121a4b620090e594945fd36f878836fc5a14aOlof Johansson#define LOCAL_SKB_ALIGN	2
52f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
53f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson/* TODO list
54f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson *
55f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson * - Multicast support
56f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson * - Large MTU support
577ddeae2c6ceed7f786344731dda27d4277957780Olof Johansson * - SW LRO
587ddeae2c6ceed7f786344731dda27d4277957780Olof Johansson * - Multiqueue RX/TX
59f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson */
60f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
6128ae79f531014bb3ad95b6efa0e0603069087bc5Olof Johansson#define LRO_MAX_AGGR 64
6228ae79f531014bb3ad95b6efa0e0603069087bc5Olof Johansson
63ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson#define PE_MIN_MTU	64
648d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson#define PE_MAX_MTU	9000
65ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson#define PE_DEF_MTU	ETH_DATA_LEN
66ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson
67ceb51361370c003e13f782edb7171a8383e5c849Olof Johansson#define DEFAULT_MSG_ENABLE	  \
68ceb51361370c003e13f782edb7171a8383e5c849Olof Johansson	(NETIF_MSG_DRV		| \
69ceb51361370c003e13f782edb7171a8383e5c849Olof Johansson	 NETIF_MSG_PROBE	| \
70ceb51361370c003e13f782edb7171a8383e5c849Olof Johansson	 NETIF_MSG_LINK		| \
71ceb51361370c003e13f782edb7171a8383e5c849Olof Johansson	 NETIF_MSG_TIMER	| \
72ceb51361370c003e13f782edb7171a8383e5c849Olof Johansson	 NETIF_MSG_IFDOWN	| \
73ceb51361370c003e13f782edb7171a8383e5c849Olof Johansson	 NETIF_MSG_IFUP		| \
74ceb51361370c003e13f782edb7171a8383e5c849Olof Johansson	 NETIF_MSG_RX_ERR	| \
75ceb51361370c003e13f782edb7171a8383e5c849Olof Johansson	 NETIF_MSG_TX_ERR)
76ceb51361370c003e13f782edb7171a8383e5c849Olof Johansson
77ceb51361370c003e13f782edb7171a8383e5c849Olof JohanssonMODULE_LICENSE("GPL");
78ceb51361370c003e13f782edb7171a8383e5c849Olof JohanssonMODULE_AUTHOR ("Olof Johansson <olof@lixom.net>");
79ceb51361370c003e13f782edb7171a8383e5c849Olof JohanssonMODULE_DESCRIPTION("PA Semi PWRficient Ethernet driver");
80ceb51361370c003e13f782edb7171a8383e5c849Olof Johansson
81ceb51361370c003e13f782edb7171a8383e5c849Olof Johanssonstatic int debug = -1;	/* -1 == use DEFAULT_MSG_ENABLE as value */
82ceb51361370c003e13f782edb7171a8383e5c849Olof Johanssonmodule_param(debug, int, 0);
83ceb51361370c003e13f782edb7171a8383e5c849Olof JohanssonMODULE_PARM_DESC(debug, "PA Semi MAC bitmapped debugging message enable value");
84f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
85e37c772e36a7943b2e0bd8f48312e78474c0df15Olof Johanssonextern const struct ethtool_ops pasemi_mac_ethtool_ops;
86e37c772e36a7943b2e0bd8f48312e78474c0df15Olof Johansson
87af289e803fdf2fcd19cf4a57c3c896dba146c756Olof Johanssonstatic int translation_enabled(void)
88af289e803fdf2fcd19cf4a57c3c896dba146c756Olof Johansson{
89af289e803fdf2fcd19cf4a57c3c896dba146c756Olof Johansson#if defined(CONFIG_PPC_PASEMI_IOMMU_DMA_FORCE)
90af289e803fdf2fcd19cf4a57c3c896dba146c756Olof Johansson	return 1;
91af289e803fdf2fcd19cf4a57c3c896dba146c756Olof Johansson#else
92af289e803fdf2fcd19cf4a57c3c896dba146c756Olof Johansson	return firmware_has_feature(FW_FEATURE_LPAR);
93af289e803fdf2fcd19cf4a57c3c896dba146c756Olof Johansson#endif
94af289e803fdf2fcd19cf4a57c3c896dba146c756Olof Johansson}
95af289e803fdf2fcd19cf4a57c3c896dba146c756Olof Johansson
9634c20624ce541f8a7ff937f474af51f9044cedd7Olof Johanssonstatic void write_iob_reg(unsigned int reg, unsigned int val)
97a85b94222d8b95e184941183f28b06b637cc4deeOlof Johansson{
9834c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	pasemi_write_iob_reg(reg, val);
99a85b94222d8b95e184941183f28b06b637cc4deeOlof Johansson}
100a85b94222d8b95e184941183f28b06b637cc4deeOlof Johansson
1015c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johanssonstatic unsigned int read_mac_reg(const struct pasemi_mac *mac, unsigned int reg)
102a85b94222d8b95e184941183f28b06b637cc4deeOlof Johansson{
10334c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	return pasemi_read_mac_reg(mac->dma_if, reg);
104a85b94222d8b95e184941183f28b06b637cc4deeOlof Johansson}
105a85b94222d8b95e184941183f28b06b637cc4deeOlof Johansson
1065c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johanssonstatic void write_mac_reg(const struct pasemi_mac *mac, unsigned int reg,
107a85b94222d8b95e184941183f28b06b637cc4deeOlof Johansson			  unsigned int val)
108a85b94222d8b95e184941183f28b06b637cc4deeOlof Johansson{
10934c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	pasemi_write_mac_reg(mac->dma_if, reg, val);
110a85b94222d8b95e184941183f28b06b637cc4deeOlof Johansson}
111a85b94222d8b95e184941183f28b06b637cc4deeOlof Johansson
11234c20624ce541f8a7ff937f474af51f9044cedd7Olof Johanssonstatic unsigned int read_dma_reg(unsigned int reg)
113a85b94222d8b95e184941183f28b06b637cc4deeOlof Johansson{
11434c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	return pasemi_read_dma_reg(reg);
115a85b94222d8b95e184941183f28b06b637cc4deeOlof Johansson}
116a85b94222d8b95e184941183f28b06b637cc4deeOlof Johansson
11734c20624ce541f8a7ff937f474af51f9044cedd7Olof Johanssonstatic void write_dma_reg(unsigned int reg, unsigned int val)
118a85b94222d8b95e184941183f28b06b637cc4deeOlof Johansson{
11934c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	pasemi_write_dma_reg(reg, val);
120a85b94222d8b95e184941183f28b06b637cc4deeOlof Johansson}
121a85b94222d8b95e184941183f28b06b637cc4deeOlof Johansson
1225c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johanssonstatic struct pasemi_mac_rxring *rx_ring(const struct pasemi_mac *mac)
12372b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson{
12472b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson	return mac->rx;
12572b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson}
12672b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson
1275c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johanssonstatic struct pasemi_mac_txring *tx_ring(const struct pasemi_mac *mac)
12872b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson{
12972b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson	return mac->tx;
13072b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson}
13172b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson
1325c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johanssonstatic inline void prefetch_skb(const struct sk_buff *skb)
1335c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johansson{
1345c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johansson	const void *d = skb;
1355c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johansson
1365c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johansson	prefetch(d);
1375c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johansson	prefetch(d+64);
1385c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johansson	prefetch(d+128);
1395c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johansson	prefetch(d+192);
1405c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johansson}
1415c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johansson
14234c20624ce541f8a7ff937f474af51f9044cedd7Olof Johanssonstatic int mac_to_intf(struct pasemi_mac *mac)
14334c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson{
14434c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	struct pci_dev *pdev = mac->pdev;
14534c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	u32 tmp;
14634c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	int nintf, off, i, j;
14734c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	int devfn = pdev->devfn;
14834c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson
14934c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	tmp = read_dma_reg(PAS_DMA_CAP_IFI);
15034c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	nintf = (tmp & PAS_DMA_CAP_IFI_NIN_M) >> PAS_DMA_CAP_IFI_NIN_S;
15134c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	off = (tmp & PAS_DMA_CAP_IFI_IOFF_M) >> PAS_DMA_CAP_IFI_IOFF_S;
15234c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson
15334c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	/* IOFF contains the offset to the registers containing the
15434c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	 * DMA interface-to-MAC-pci-id mappings, and NIN contains number
15534c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	 * of total interfaces. Each register contains 4 devfns.
15634c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	 * Just do a linear search until we find the devfn of the MAC
15734c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	 * we're trying to look up.
15834c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	 */
15934c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson
16034c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	for (i = 0; i < (nintf+3)/4; i++) {
16134c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson		tmp = read_dma_reg(off+4*i);
16234c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson		for (j = 0; j < 4; j++) {
16334c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson			if (((tmp >> (8*j)) & 0xff) == devfn)
16434c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson				return i*4 + j;
16534c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson		}
16634c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	}
16734c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	return -1;
16834c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson}
16934c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson
170ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johanssonstatic void pasemi_mac_intf_disable(struct pasemi_mac *mac)
171ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson{
172ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	unsigned int flags;
173ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson
174ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	flags = read_mac_reg(mac, PAS_MAC_CFG_PCFG);
175ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	flags &= ~PAS_MAC_CFG_PCFG_PE;
176ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	write_mac_reg(mac, PAS_MAC_CFG_PCFG, flags);
177ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson}
178ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson
179ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johanssonstatic void pasemi_mac_intf_enable(struct pasemi_mac *mac)
180ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson{
181ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	unsigned int flags;
182ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson
183ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	flags = read_mac_reg(mac, PAS_MAC_CFG_PCFG);
184ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	flags |= PAS_MAC_CFG_PCFG_PE;
185ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	write_mac_reg(mac, PAS_MAC_CFG_PCFG, flags);
186ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson}
187ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson
188f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johanssonstatic int pasemi_get_mac_addr(struct pasemi_mac *mac)
189f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson{
190f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	struct pci_dev *pdev = mac->pdev;
191f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	struct device_node *dn = pci_device_to_OF_node(pdev);
1921af7f05628fab81fdf4412d757676412ba5db660olof@lixom.net	int len;
193f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	const u8 *maddr;
194f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	u8 addr[6];
195f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
196f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	if (!dn) {
197f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson		dev_dbg(&pdev->dev,
198f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson			  "No device node for mac, not configuring\n");
199f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson		return -ENOENT;
200f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	}
201f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
2021af7f05628fab81fdf4412d757676412ba5db660olof@lixom.net	maddr = of_get_property(dn, "local-mac-address", &len);
2031af7f05628fab81fdf4412d757676412ba5db660olof@lixom.net
2041af7f05628fab81fdf4412d757676412ba5db660olof@lixom.net	if (maddr && len == 6) {
2051af7f05628fab81fdf4412d757676412ba5db660olof@lixom.net		memcpy(mac->mac_addr, maddr, 6);
2061af7f05628fab81fdf4412d757676412ba5db660olof@lixom.net		return 0;
2071af7f05628fab81fdf4412d757676412ba5db660olof@lixom.net	}
2081af7f05628fab81fdf4412d757676412ba5db660olof@lixom.net
2091af7f05628fab81fdf4412d757676412ba5db660olof@lixom.net	/* Some old versions of firmware mistakenly uses mac-address
2101af7f05628fab81fdf4412d757676412ba5db660olof@lixom.net	 * (and as a string) instead of a byte array in local-mac-address.
2111af7f05628fab81fdf4412d757676412ba5db660olof@lixom.net	 */
212a5fd22ebc71eecb7b61e542d34ac50a417b3031bOlof Johansson
213a5fd22ebc71eecb7b61e542d34ac50a417b3031bOlof Johansson	if (maddr == NULL)
2149028780a3e6d2c3dd940e89b377765cca008b6dfLinus Torvalds		maddr = of_get_property(dn, "mac-address", NULL);
215a5fd22ebc71eecb7b61e542d34ac50a417b3031bOlof Johansson
216f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	if (maddr == NULL) {
217f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson		dev_warn(&pdev->dev,
218f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson			 "no mac address in device tree, not configuring\n");
219f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson		return -ENOENT;
220f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	}
221f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
222f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	if (sscanf(maddr, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &addr[0],
223f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson		   &addr[1], &addr[2], &addr[3], &addr[4], &addr[5]) != 6) {
224f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson		dev_warn(&pdev->dev,
225f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson			 "can't parse mac address, not configuring\n");
226f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson		return -EINVAL;
227f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	}
228f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
2291af7f05628fab81fdf4412d757676412ba5db660olof@lixom.net	memcpy(mac->mac_addr, addr, 6);
2301af7f05628fab81fdf4412d757676412ba5db660olof@lixom.net
231f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	return 0;
232f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson}
233f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
2345cea73b0f7d4d49e276b0c4842465890d00de861Olof Johanssonstatic int pasemi_mac_set_mac_addr(struct net_device *dev, void *p)
2355cea73b0f7d4d49e276b0c4842465890d00de861Olof Johansson{
2365cea73b0f7d4d49e276b0c4842465890d00de861Olof Johansson	struct pasemi_mac *mac = netdev_priv(dev);
2375cea73b0f7d4d49e276b0c4842465890d00de861Olof Johansson	struct sockaddr *addr = p;
2385cea73b0f7d4d49e276b0c4842465890d00de861Olof Johansson	unsigned int adr0, adr1;
2395cea73b0f7d4d49e276b0c4842465890d00de861Olof Johansson
2405cea73b0f7d4d49e276b0c4842465890d00de861Olof Johansson	if (!is_valid_ether_addr(addr->sa_data))
241504f9b5a6bb5336ad434438d0cdd61a16db80129Danny Kukawka		return -EADDRNOTAVAIL;
2425cea73b0f7d4d49e276b0c4842465890d00de861Olof Johansson
2435cea73b0f7d4d49e276b0c4842465890d00de861Olof Johansson	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
2445cea73b0f7d4d49e276b0c4842465890d00de861Olof Johansson
2455cea73b0f7d4d49e276b0c4842465890d00de861Olof Johansson	adr0 = dev->dev_addr[2] << 24 |
2465cea73b0f7d4d49e276b0c4842465890d00de861Olof Johansson	       dev->dev_addr[3] << 16 |
2475cea73b0f7d4d49e276b0c4842465890d00de861Olof Johansson	       dev->dev_addr[4] << 8 |
2485cea73b0f7d4d49e276b0c4842465890d00de861Olof Johansson	       dev->dev_addr[5];
2495cea73b0f7d4d49e276b0c4842465890d00de861Olof Johansson	adr1 = read_mac_reg(mac, PAS_MAC_CFG_ADR1);
2505cea73b0f7d4d49e276b0c4842465890d00de861Olof Johansson	adr1 &= ~0xffff;
2515cea73b0f7d4d49e276b0c4842465890d00de861Olof Johansson	adr1 |= dev->dev_addr[0] << 8 | dev->dev_addr[1];
2525cea73b0f7d4d49e276b0c4842465890d00de861Olof Johansson
2535cea73b0f7d4d49e276b0c4842465890d00de861Olof Johansson	pasemi_mac_intf_disable(mac);
2545cea73b0f7d4d49e276b0c4842465890d00de861Olof Johansson	write_mac_reg(mac, PAS_MAC_CFG_ADR0, adr0);
2555cea73b0f7d4d49e276b0c4842465890d00de861Olof Johansson	write_mac_reg(mac, PAS_MAC_CFG_ADR1, adr1);
2565cea73b0f7d4d49e276b0c4842465890d00de861Olof Johansson	pasemi_mac_intf_enable(mac);
2575cea73b0f7d4d49e276b0c4842465890d00de861Olof Johansson
2585cea73b0f7d4d49e276b0c4842465890d00de861Olof Johansson	return 0;
2595cea73b0f7d4d49e276b0c4842465890d00de861Olof Johansson}
2605cea73b0f7d4d49e276b0c4842465890d00de861Olof Johansson
26128ae79f531014bb3ad95b6efa0e0603069087bc5Olof Johanssonstatic int get_skb_hdr(struct sk_buff *skb, void **iphdr,
26228ae79f531014bb3ad95b6efa0e0603069087bc5Olof Johansson		       void **tcph, u64 *hdr_flags, void *data)
26328ae79f531014bb3ad95b6efa0e0603069087bc5Olof Johansson{
26428ae79f531014bb3ad95b6efa0e0603069087bc5Olof Johansson	u64 macrx = (u64) data;
26528ae79f531014bb3ad95b6efa0e0603069087bc5Olof Johansson	unsigned int ip_len;
26628ae79f531014bb3ad95b6efa0e0603069087bc5Olof Johansson	struct iphdr *iph;
26728ae79f531014bb3ad95b6efa0e0603069087bc5Olof Johansson
26828ae79f531014bb3ad95b6efa0e0603069087bc5Olof Johansson	/* IPv4 header checksum failed */
26928ae79f531014bb3ad95b6efa0e0603069087bc5Olof Johansson	if ((macrx & XCT_MACRX_HTY_M) != XCT_MACRX_HTY_IPV4_OK)
27028ae79f531014bb3ad95b6efa0e0603069087bc5Olof Johansson		return -1;
27128ae79f531014bb3ad95b6efa0e0603069087bc5Olof Johansson
27228ae79f531014bb3ad95b6efa0e0603069087bc5Olof Johansson	/* non tcp packet */
27328ae79f531014bb3ad95b6efa0e0603069087bc5Olof Johansson	skb_reset_network_header(skb);
27428ae79f531014bb3ad95b6efa0e0603069087bc5Olof Johansson	iph = ip_hdr(skb);
27528ae79f531014bb3ad95b6efa0e0603069087bc5Olof Johansson	if (iph->protocol != IPPROTO_TCP)
27628ae79f531014bb3ad95b6efa0e0603069087bc5Olof Johansson		return -1;
27728ae79f531014bb3ad95b6efa0e0603069087bc5Olof Johansson
27828ae79f531014bb3ad95b6efa0e0603069087bc5Olof Johansson	ip_len = ip_hdrlen(skb);
27928ae79f531014bb3ad95b6efa0e0603069087bc5Olof Johansson	skb_set_transport_header(skb, ip_len);
28028ae79f531014bb3ad95b6efa0e0603069087bc5Olof Johansson	*tcph = tcp_hdr(skb);
28128ae79f531014bb3ad95b6efa0e0603069087bc5Olof Johansson
28228ae79f531014bb3ad95b6efa0e0603069087bc5Olof Johansson	/* check if ip header and tcp header are complete */
283773212337941c5e26a05989532943877d72a2c83Roland Dreier	if (ntohs(iph->tot_len) < ip_len + tcp_hdrlen(skb))
28428ae79f531014bb3ad95b6efa0e0603069087bc5Olof Johansson		return -1;
28528ae79f531014bb3ad95b6efa0e0603069087bc5Olof Johansson
28628ae79f531014bb3ad95b6efa0e0603069087bc5Olof Johansson	*hdr_flags = LRO_IPV4 | LRO_TCP;
28728ae79f531014bb3ad95b6efa0e0603069087bc5Olof Johansson	*iphdr = iph;
28828ae79f531014bb3ad95b6efa0e0603069087bc5Olof Johansson
28928ae79f531014bb3ad95b6efa0e0603069087bc5Olof Johansson	return 0;
29028ae79f531014bb3ad95b6efa0e0603069087bc5Olof Johansson}
29128ae79f531014bb3ad95b6efa0e0603069087bc5Olof Johansson
292ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johanssonstatic int pasemi_mac_unmap_tx_skb(struct pasemi_mac *mac,
2937e9916e9ddf23cd08107ed1a7fac429eea619313Olof Johansson				    const int nfrags,
294ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson				    struct sk_buff *skb,
2955c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johansson				    const dma_addr_t *dmas)
296ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson{
297ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson	int f;
2985c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johansson	struct pci_dev *pdev = mac->dma_pdev;
299ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson
3005c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johansson	pci_unmap_single(pdev, dmas[0], skb_headlen(skb), PCI_DMA_TODEVICE);
301ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson
302ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson	for (f = 0; f < nfrags; f++) {
3039e903e085262ffbf1fc44a17ac06058aca03524aEric Dumazet		const skb_frag_t *frag = &skb_shinfo(skb)->frags[f];
304ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson
3059e903e085262ffbf1fc44a17ac06058aca03524aEric Dumazet		pci_unmap_page(pdev, dmas[f+1], skb_frag_size(frag), PCI_DMA_TODEVICE);
306ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson	}
307ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson	dev_kfree_skb_irq(skb);
308ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson
309ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson	/* Freed descriptor slot + main SKB ptr + nfrags additional ptrs,
310ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson	 * aligned up to a power of 2
311ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson	 */
312ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson	return (nfrags + 3) & ~1;
313ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson}
314ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson
3158d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johanssonstatic struct pasemi_mac_csring *pasemi_mac_setup_csring(struct pasemi_mac *mac)
3168d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson{
3178d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	struct pasemi_mac_csring *ring;
3188d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	u32 val;
3198d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	unsigned int cfg;
3208d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	int chno;
3218d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson
3228d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	ring = pasemi_dma_alloc_chan(TXCHAN, sizeof(struct pasemi_mac_csring),
3238d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson				       offsetof(struct pasemi_mac_csring, chan));
3248d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson
3258d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	if (!ring) {
3268d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson		dev_err(&mac->pdev->dev, "Can't allocate checksum channel\n");
3278d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson		goto out_chan;
3288d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	}
3298d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson
3308d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	chno = ring->chan.chno;
3318d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson
3328d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	ring->size = CS_RING_SIZE;
3338d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	ring->next_to_fill = 0;
3348d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson
3358d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	/* Allocate descriptors */
3368d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	if (pasemi_dma_alloc_ring(&ring->chan, CS_RING_SIZE))
3378d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson		goto out_ring_desc;
3388d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson
3398d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	write_dma_reg(PAS_DMA_TXCHAN_BASEL(chno),
3408d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson		      PAS_DMA_TXCHAN_BASEL_BRBL(ring->chan.ring_dma));
3418d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	val = PAS_DMA_TXCHAN_BASEU_BRBH(ring->chan.ring_dma >> 32);
3428d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	val |= PAS_DMA_TXCHAN_BASEU_SIZ(CS_RING_SIZE >> 3);
3438d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson
3448d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	write_dma_reg(PAS_DMA_TXCHAN_BASEU(chno), val);
3458d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson
3468d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	ring->events[0] = pasemi_dma_alloc_flag();
3478d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	ring->events[1] = pasemi_dma_alloc_flag();
3488d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	if (ring->events[0] < 0 || ring->events[1] < 0)
3498d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson		goto out_flags;
3508d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson
3518d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	pasemi_dma_clear_flag(ring->events[0]);
3528d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	pasemi_dma_clear_flag(ring->events[1]);
3538d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson
3548d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	ring->fun = pasemi_dma_alloc_fun();
3558d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	if (ring->fun < 0)
3568d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson		goto out_fun;
3578d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson
3588d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	cfg = PAS_DMA_TXCHAN_CFG_TY_FUNC | PAS_DMA_TXCHAN_CFG_UP |
3598d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	      PAS_DMA_TXCHAN_CFG_TATTR(ring->fun) |
3608d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	      PAS_DMA_TXCHAN_CFG_LPSQ | PAS_DMA_TXCHAN_CFG_LPDQ;
3618d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson
3628d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	if (translation_enabled())
3638d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson		cfg |= PAS_DMA_TXCHAN_CFG_TRD | PAS_DMA_TXCHAN_CFG_TRR;
3648d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson
3658d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	write_dma_reg(PAS_DMA_TXCHAN_CFG(chno), cfg);
3668d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson
3678d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	/* enable channel */
3688d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	pasemi_dma_start_chan(&ring->chan, PAS_DMA_TXCHAN_TCMDSTA_SZ |
3698d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson					   PAS_DMA_TXCHAN_TCMDSTA_DB |
3708d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson					   PAS_DMA_TXCHAN_TCMDSTA_DE |
3718d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson					   PAS_DMA_TXCHAN_TCMDSTA_DA);
3728d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson
3738d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	return ring;
3748d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson
3758d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johanssonout_fun:
3768d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johanssonout_flags:
3778d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	if (ring->events[0] >= 0)
3788d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson		pasemi_dma_free_flag(ring->events[0]);
3798d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	if (ring->events[1] >= 0)
3808d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson		pasemi_dma_free_flag(ring->events[1]);
3818d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	pasemi_dma_free_ring(&ring->chan);
3828d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johanssonout_ring_desc:
3838d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	pasemi_dma_free_chan(&ring->chan);
3848d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johanssonout_chan:
3858d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson
3868d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	return NULL;
3878d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson}
3888d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson
3898d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johanssonstatic void pasemi_mac_setup_csrings(struct pasemi_mac *mac)
3908d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson{
3918d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	int i;
3928d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	mac->cs[0] = pasemi_mac_setup_csring(mac);
3938d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	if (mac->type == MAC_TYPE_XAUI)
3948d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson		mac->cs[1] = pasemi_mac_setup_csring(mac);
3958d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	else
3968d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson		mac->cs[1] = 0;
3978d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson
3988d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	for (i = 0; i < MAX_CS; i++)
3998d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson		if (mac->cs[i])
4008d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson			mac->num_cs++;
4018d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson}
4028d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson
4038d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johanssonstatic void pasemi_mac_free_csring(struct pasemi_mac_csring *csring)
4048d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson{
4058d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	pasemi_dma_stop_chan(&csring->chan);
4068d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	pasemi_dma_free_flag(csring->events[0]);
4078d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	pasemi_dma_free_flag(csring->events[1]);
4088d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	pasemi_dma_free_ring(&csring->chan);
4098d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	pasemi_dma_free_chan(&csring->chan);
4101724ac2ef1caf5b4f764d4b86a85d552a7d7c8fbOlof Johansson	pasemi_dma_free_fun(csring->fun);
4118d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson}
4128d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson
4135c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johanssonstatic int pasemi_mac_setup_rx_resources(const struct net_device *dev)
414f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson{
415f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	struct pasemi_mac_rxring *ring;
416f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	struct pasemi_mac *mac = netdev_priv(dev);
41734c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	int chno;
418af289e803fdf2fcd19cf4a57c3c896dba146c756Olof Johansson	unsigned int cfg;
419f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
42034c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	ring = pasemi_dma_alloc_chan(RXCHAN, sizeof(struct pasemi_mac_rxring),
42134c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson				     offsetof(struct pasemi_mac_rxring, chan));
422f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
42334c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	if (!ring) {
42434c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson		dev_err(&mac->pdev->dev, "Can't allocate RX channel\n");
42534c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson		goto out_chan;
42634c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	}
42734c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	chno = ring->chan.chno;
428f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
429f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	spin_lock_init(&ring->lock);
430f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
431021fa22e01d3d0425d3d15df48f523b69a3a11c4Olof Johansson	ring->size = RX_RING_SIZE;
432fc9e4d2a93dab4a995e2e75725577b9a60154cbcOlof Johansson	ring->ring_info = kzalloc(sizeof(struct pasemi_mac_buffer) *
433f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson				  RX_RING_SIZE, GFP_KERNEL);
434f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
435fc9e4d2a93dab4a995e2e75725577b9a60154cbcOlof Johansson	if (!ring->ring_info)
436fc9e4d2a93dab4a995e2e75725577b9a60154cbcOlof Johansson		goto out_ring_info;
437f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
438f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	/* Allocate descriptors */
43934c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	if (pasemi_dma_alloc_ring(&ring->chan, RX_RING_SIZE))
440fc9e4d2a93dab4a995e2e75725577b9a60154cbcOlof Johansson		goto out_ring_desc;
441f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
442f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	ring->buffers = dma_alloc_coherent(&mac->dma_pdev->dev,
443f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson					   RX_RING_SIZE * sizeof(u64),
444f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson					   &ring->buf_dma, GFP_KERNEL);
445f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	if (!ring->buffers)
44634c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson		goto out_ring_desc;
447f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
448f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	memset(ring->buffers, 0, RX_RING_SIZE * sizeof(u64));
449f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
45034c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	write_dma_reg(PAS_DMA_RXCHAN_BASEL(chno),
45134c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson		      PAS_DMA_RXCHAN_BASEL_BRBL(ring->chan.ring_dma));
452f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
45334c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	write_dma_reg(PAS_DMA_RXCHAN_BASEU(chno),
45434c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson		      PAS_DMA_RXCHAN_BASEU_BRBH(ring->chan.ring_dma >> 32) |
45534c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson		      PAS_DMA_RXCHAN_BASEU_SIZ(RX_RING_SIZE >> 3));
456f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
4575c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johansson	cfg = PAS_DMA_RXCHAN_CFG_HBU(2);
458af289e803fdf2fcd19cf4a57c3c896dba146c756Olof Johansson
459af289e803fdf2fcd19cf4a57c3c896dba146c756Olof Johansson	if (translation_enabled())
460af289e803fdf2fcd19cf4a57c3c896dba146c756Olof Johansson		cfg |= PAS_DMA_RXCHAN_CFG_CTR;
461af289e803fdf2fcd19cf4a57c3c896dba146c756Olof Johansson
46234c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	write_dma_reg(PAS_DMA_RXCHAN_CFG(chno), cfg);
463f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
46434c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	write_dma_reg(PAS_DMA_RXINT_BASEL(mac->dma_if),
46534c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson		      PAS_DMA_RXINT_BASEL_BRBL(ring->buf_dma));
466f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
46734c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	write_dma_reg(PAS_DMA_RXINT_BASEU(mac->dma_if),
46834c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson		      PAS_DMA_RXINT_BASEU_BRBH(ring->buf_dma >> 32) |
46934c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson		      PAS_DMA_RXINT_BASEU_SIZ(RX_RING_SIZE >> 3));
470f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
4715c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johansson	cfg = PAS_DMA_RXINT_CFG_DHL(2) | PAS_DMA_RXINT_CFG_L2 |
472af289e803fdf2fcd19cf4a57c3c896dba146c756Olof Johansson	      PAS_DMA_RXINT_CFG_LW | PAS_DMA_RXINT_CFG_RBP |
473af289e803fdf2fcd19cf4a57c3c896dba146c756Olof Johansson	      PAS_DMA_RXINT_CFG_HEN;
474af289e803fdf2fcd19cf4a57c3c896dba146c756Olof Johansson
475af289e803fdf2fcd19cf4a57c3c896dba146c756Olof Johansson	if (translation_enabled())
476af289e803fdf2fcd19cf4a57c3c896dba146c756Olof Johansson		cfg |= PAS_DMA_RXINT_CFG_ITRR | PAS_DMA_RXINT_CFG_ITR;
477af289e803fdf2fcd19cf4a57c3c896dba146c756Olof Johansson
47834c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	write_dma_reg(PAS_DMA_RXINT_CFG(mac->dma_if), cfg);
479c0efd52b8b1951c20878208fdcbab0468f816804Olof Johansson
480f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	ring->next_to_fill = 0;
481f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	ring->next_to_clean = 0;
48272b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson	ring->mac = mac;
483f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	mac->rx = ring;
484f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
485f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	return 0;
486f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
487fc9e4d2a93dab4a995e2e75725577b9a60154cbcOlof Johanssonout_ring_desc:
488fc9e4d2a93dab4a995e2e75725577b9a60154cbcOlof Johansson	kfree(ring->ring_info);
489fc9e4d2a93dab4a995e2e75725577b9a60154cbcOlof Johanssonout_ring_info:
49034c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	pasemi_dma_free_chan(&ring->chan);
49134c20624ce541f8a7ff937f474af51f9044cedd7Olof Johanssonout_chan:
492f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	return -ENOMEM;
493f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson}
494f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
49572b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johanssonstatic struct pasemi_mac_txring *
4965c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johanssonpasemi_mac_setup_tx_resources(const struct net_device *dev)
497f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson{
498f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	struct pasemi_mac *mac = netdev_priv(dev);
499f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	u32 val;
500f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	struct pasemi_mac_txring *ring;
501af289e803fdf2fcd19cf4a57c3c896dba146c756Olof Johansson	unsigned int cfg;
50234c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	int chno;
503f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
50434c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	ring = pasemi_dma_alloc_chan(TXCHAN, sizeof(struct pasemi_mac_txring),
50534c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson				     offsetof(struct pasemi_mac_txring, chan));
50634c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson
50734c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	if (!ring) {
50834c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson		dev_err(&mac->pdev->dev, "Can't allocate TX channel\n");
50934c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson		goto out_chan;
51034c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	}
51134c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson
51234c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	chno = ring->chan.chno;
513f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
514f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	spin_lock_init(&ring->lock);
515f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
516021fa22e01d3d0425d3d15df48f523b69a3a11c4Olof Johansson	ring->size = TX_RING_SIZE;
517fc9e4d2a93dab4a995e2e75725577b9a60154cbcOlof Johansson	ring->ring_info = kzalloc(sizeof(struct pasemi_mac_buffer) *
518f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson				  TX_RING_SIZE, GFP_KERNEL);
519fc9e4d2a93dab4a995e2e75725577b9a60154cbcOlof Johansson	if (!ring->ring_info)
520fc9e4d2a93dab4a995e2e75725577b9a60154cbcOlof Johansson		goto out_ring_info;
521f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
522f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	/* Allocate descriptors */
52334c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	if (pasemi_dma_alloc_ring(&ring->chan, TX_RING_SIZE))
524fc9e4d2a93dab4a995e2e75725577b9a60154cbcOlof Johansson		goto out_ring_desc;
525f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
52634c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	write_dma_reg(PAS_DMA_TXCHAN_BASEL(chno),
52734c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson		      PAS_DMA_TXCHAN_BASEL_BRBL(ring->chan.ring_dma));
52834c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	val = PAS_DMA_TXCHAN_BASEU_BRBH(ring->chan.ring_dma >> 32);
529fc9e4d2a93dab4a995e2e75725577b9a60154cbcOlof Johansson	val |= PAS_DMA_TXCHAN_BASEU_SIZ(TX_RING_SIZE >> 3);
530f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
53134c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	write_dma_reg(PAS_DMA_TXCHAN_BASEU(chno), val);
532f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
533af289e803fdf2fcd19cf4a57c3c896dba146c756Olof Johansson	cfg = PAS_DMA_TXCHAN_CFG_TY_IFACE |
534af289e803fdf2fcd19cf4a57c3c896dba146c756Olof Johansson	      PAS_DMA_TXCHAN_CFG_TATTR(mac->dma_if) |
535af289e803fdf2fcd19cf4a57c3c896dba146c756Olof Johansson	      PAS_DMA_TXCHAN_CFG_UP |
5368d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	      PAS_DMA_TXCHAN_CFG_WT(4);
537af289e803fdf2fcd19cf4a57c3c896dba146c756Olof Johansson
538af289e803fdf2fcd19cf4a57c3c896dba146c756Olof Johansson	if (translation_enabled())
539af289e803fdf2fcd19cf4a57c3c896dba146c756Olof Johansson		cfg |= PAS_DMA_TXCHAN_CFG_TRD | PAS_DMA_TXCHAN_CFG_TRR;
540af289e803fdf2fcd19cf4a57c3c896dba146c756Olof Johansson
54134c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	write_dma_reg(PAS_DMA_TXCHAN_CFG(chno), cfg);
542f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
543021fa22e01d3d0425d3d15df48f523b69a3a11c4Olof Johansson	ring->next_to_fill = 0;
544f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	ring->next_to_clean = 0;
54572b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson	ring->mac = mac;
546f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
54772b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson	return ring;
548f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
549fc9e4d2a93dab4a995e2e75725577b9a60154cbcOlof Johanssonout_ring_desc:
550fc9e4d2a93dab4a995e2e75725577b9a60154cbcOlof Johansson	kfree(ring->ring_info);
551fc9e4d2a93dab4a995e2e75725577b9a60154cbcOlof Johanssonout_ring_info:
55234c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	pasemi_dma_free_chan(&ring->chan);
55334c20624ce541f8a7ff937f474af51f9044cedd7Olof Johanssonout_chan:
55472b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson	return NULL;
555f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson}
556f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
55772b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johanssonstatic void pasemi_mac_free_tx_resources(struct pasemi_mac *mac)
558f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson{
55972b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson	struct pasemi_mac_txring *txring = tx_ring(mac);
560ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson	unsigned int i, j;
561f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	struct pasemi_mac_buffer *info;
562ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson	dma_addr_t dmas[MAX_SKB_FRAGS+1];
5637e9916e9ddf23cd08107ed1a7fac429eea619313Olof Johansson	int freed, nfrags;
564ad5da10a64bdca1ed39b25946727a1ce2659f3d4Olof Johansson	int start, limit;
565fc9e4d2a93dab4a995e2e75725577b9a60154cbcOlof Johansson
56672b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson	start = txring->next_to_clean;
56772b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson	limit = txring->next_to_fill;
568ad5da10a64bdca1ed39b25946727a1ce2659f3d4Olof Johansson
569ad5da10a64bdca1ed39b25946727a1ce2659f3d4Olof Johansson	/* Compensate for when fill has wrapped and clean has not */
570ad5da10a64bdca1ed39b25946727a1ce2659f3d4Olof Johansson	if (start > limit)
571ad5da10a64bdca1ed39b25946727a1ce2659f3d4Olof Johansson		limit += TX_RING_SIZE;
572ad5da10a64bdca1ed39b25946727a1ce2659f3d4Olof Johansson
573ad5da10a64bdca1ed39b25946727a1ce2659f3d4Olof Johansson	for (i = start; i < limit; i += freed) {
57472b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson		info = &txring->ring_info[(i+1) & (TX_RING_SIZE-1)];
575fc9e4d2a93dab4a995e2e75725577b9a60154cbcOlof Johansson		if (info->dma && info->skb) {
5767e9916e9ddf23cd08107ed1a7fac429eea619313Olof Johansson			nfrags = skb_shinfo(info->skb)->nr_frags;
5777e9916e9ddf23cd08107ed1a7fac429eea619313Olof Johansson			for (j = 0; j <= nfrags; j++)
57872b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson				dmas[j] = txring->ring_info[(i+1+j) &
57972b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson						(TX_RING_SIZE-1)].dma;
5807e9916e9ddf23cd08107ed1a7fac429eea619313Olof Johansson			freed = pasemi_mac_unmap_tx_skb(mac, nfrags,
5817e9916e9ddf23cd08107ed1a7fac429eea619313Olof Johansson							info->skb, dmas);
582ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson		} else
583ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson			freed = 2;
584f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	}
585f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
58672b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson	kfree(txring->ring_info);
58734c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	pasemi_dma_free_chan(&txring->chan);
58834c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson
589f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson}
590f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
591ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johanssonstatic void pasemi_mac_free_rx_buffers(struct pasemi_mac *mac)
592f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson{
59372b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson	struct pasemi_mac_rxring *rx = rx_ring(mac);
594f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	unsigned int i;
595f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	struct pasemi_mac_buffer *info;
596f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
597f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	for (i = 0; i < RX_RING_SIZE; i++) {
59872b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson		info = &RX_DESC_INFO(rx, i);
599fc9e4d2a93dab4a995e2e75725577b9a60154cbcOlof Johansson		if (info->skb && info->dma) {
600fc9e4d2a93dab4a995e2e75725577b9a60154cbcOlof Johansson			pci_unmap_single(mac->dma_pdev,
601fc9e4d2a93dab4a995e2e75725577b9a60154cbcOlof Johansson					 info->dma,
602fc9e4d2a93dab4a995e2e75725577b9a60154cbcOlof Johansson					 info->skb->len,
603fc9e4d2a93dab4a995e2e75725577b9a60154cbcOlof Johansson					 PCI_DMA_FROMDEVICE);
604fc9e4d2a93dab4a995e2e75725577b9a60154cbcOlof Johansson			dev_kfree_skb_any(info->skb);
605f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson		}
606fc9e4d2a93dab4a995e2e75725577b9a60154cbcOlof Johansson		info->dma = 0;
607fc9e4d2a93dab4a995e2e75725577b9a60154cbcOlof Johansson		info->skb = NULL;
608f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	}
609f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
610fc9e4d2a93dab4a995e2e75725577b9a60154cbcOlof Johansson	for (i = 0; i < RX_RING_SIZE; i++)
611ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson		RX_BUFF(rx, i) = 0;
612ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson}
613ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson
614ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johanssonstatic void pasemi_mac_free_rx_resources(struct pasemi_mac *mac)
615ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson{
616ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	pasemi_mac_free_rx_buffers(mac);
617fc9e4d2a93dab4a995e2e75725577b9a60154cbcOlof Johansson
618f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	dma_free_coherent(&mac->dma_pdev->dev, RX_RING_SIZE * sizeof(u64),
61972b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson			  rx_ring(mac)->buffers, rx_ring(mac)->buf_dma);
620f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
62172b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson	kfree(rx_ring(mac)->ring_info);
62234c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	pasemi_dma_free_chan(&rx_ring(mac)->chan);
623f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	mac->rx = NULL;
624f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson}
625f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
6265c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johanssonstatic void pasemi_mac_replenish_rx_ring(const struct net_device *dev,
6275c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johansson					 const int limit)
628f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson{
6295c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johansson	const struct pasemi_mac *mac = netdev_priv(dev);
63072b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson	struct pasemi_mac_rxring *rx = rx_ring(mac);
631b5254eee7994ba0a44ba7386cb66c2ce2f30fcc6Olof Johansson	int fill, count;
632f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
633cd4ceb245be7926e94558e2b6cd279bfaa775908Olof Johansson	if (limit <= 0)
634f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson		return;
635f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
63672b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson	fill = rx_ring(mac)->next_to_fill;
637928773c23a4cf053a34ad480439448f75efa350cOlof Johansson	for (count = 0; count < limit; count++) {
63872b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson		struct pasemi_mac_buffer *info = &RX_DESC_INFO(rx, fill);
63972b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson		u64 *buff = &RX_BUFF(rx, fill);
640f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson		struct sk_buff *skb;
641f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson		dma_addr_t dma;
642f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
643fc9e4d2a93dab4a995e2e75725577b9a60154cbcOlof Johansson		/* Entry in use? */
644fc9e4d2a93dab4a995e2e75725577b9a60154cbcOlof Johansson		WARN_ON(*buff);
645fc9e4d2a93dab4a995e2e75725577b9a60154cbcOlof Johansson
646dae2e9f430c46c29e3f771110094bd3da3625aa4Pradeep A. Dalvi		skb = netdev_alloc_skb(dev, mac->bufsz);
6475d8949448b68b3b355036c8061e3282388826ec5Olof Johansson		skb_reserve(skb, LOCAL_SKB_ALIGN);
648f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
6499f05cfe250498791cd24707aea3b728b52d886d5Olof Johansson		if (unlikely(!skb))
650f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson			break;
651f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
6528dc121a4b620090e594945fd36f878836fc5a14aOlof Johansson		dma = pci_map_single(mac->dma_pdev, skb->data,
653ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson				     mac->bufsz - LOCAL_SKB_ALIGN,
654f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson				     PCI_DMA_FROMDEVICE);
655f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
6568d8bb39b9eba32dd70e87fd5ad5c5dd4ba118e06FUJITA Tomonori		if (unlikely(pci_dma_mapping_error(mac->dma_pdev, dma))) {
657f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson			dev_kfree_skb_irq(info->skb);
658f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson			break;
659f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson		}
660f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
661f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson		info->skb = skb;
662f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson		info->dma = dma;
663ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson		*buff = XCT_RXB_LEN(mac->bufsz) | XCT_RXB_ADDR(dma);
664fc9e4d2a93dab4a995e2e75725577b9a60154cbcOlof Johansson		fill++;
665f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	}
666f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
667f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	wmb();
668f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
66934c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	write_dma_reg(PAS_DMA_RXINT_INCR(mac->dma_if), count);
670f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
67172b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson	rx_ring(mac)->next_to_fill = (rx_ring(mac)->next_to_fill + count) &
672b5254eee7994ba0a44ba7386cb66c2ce2f30fcc6Olof Johansson				(RX_RING_SIZE - 1);
673f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson}
674f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
6755c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johanssonstatic void pasemi_mac_restart_rx_intr(const struct pasemi_mac *mac)
6761b0335ea30bf85eecffd21be64b7653407d6259aOlof Johansson{
677906674abab0424b466a2db4bb6a890a8c477b10aOlof Johansson	struct pasemi_mac_rxring *rx = rx_ring(mac);
67852a9435183f961e1bb3c146a62bfbecf93d15d58Olof Johansson	unsigned int reg, pcnt;
6791b0335ea30bf85eecffd21be64b7653407d6259aOlof Johansson	/* Re-enable packet count interrupts: finally
6801b0335ea30bf85eecffd21be64b7653407d6259aOlof Johansson	 * ack the packet count interrupt we got in rx_intr.
6811b0335ea30bf85eecffd21be64b7653407d6259aOlof Johansson	 */
6821b0335ea30bf85eecffd21be64b7653407d6259aOlof Johansson
683906674abab0424b466a2db4bb6a890a8c477b10aOlof Johansson	pcnt = *rx->chan.status & PAS_STATUS_PCNT_M;
6841b0335ea30bf85eecffd21be64b7653407d6259aOlof Johansson
68552a9435183f961e1bb3c146a62bfbecf93d15d58Olof Johansson	reg = PAS_IOB_DMA_RXCH_RESET_PCNT(pcnt) | PAS_IOB_DMA_RXCH_RESET_PINTC;
6861b0335ea30bf85eecffd21be64b7653407d6259aOlof Johansson
687906674abab0424b466a2db4bb6a890a8c477b10aOlof Johansson	if (*rx->chan.status & PAS_STATUS_TIMER)
688906674abab0424b466a2db4bb6a890a8c477b10aOlof Johansson		reg |= PAS_IOB_DMA_RXCH_RESET_TINTC;
689906674abab0424b466a2db4bb6a890a8c477b10aOlof Johansson
69034c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	write_iob_reg(PAS_IOB_DMA_RXCH_RESET(mac->rx->chan.chno), reg);
6911b0335ea30bf85eecffd21be64b7653407d6259aOlof Johansson}
6921b0335ea30bf85eecffd21be64b7653407d6259aOlof Johansson
6935c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johanssonstatic void pasemi_mac_restart_tx_intr(const struct pasemi_mac *mac)
6941b0335ea30bf85eecffd21be64b7653407d6259aOlof Johansson{
69552a9435183f961e1bb3c146a62bfbecf93d15d58Olof Johansson	unsigned int reg, pcnt;
6961b0335ea30bf85eecffd21be64b7653407d6259aOlof Johansson
6971b0335ea30bf85eecffd21be64b7653407d6259aOlof Johansson	/* Re-enable packet count interrupts */
69834c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	pcnt = *tx_ring(mac)->chan.status & PAS_STATUS_PCNT_M;
6991b0335ea30bf85eecffd21be64b7653407d6259aOlof Johansson
70052a9435183f961e1bb3c146a62bfbecf93d15d58Olof Johansson	reg = PAS_IOB_DMA_TXCH_RESET_PCNT(pcnt) | PAS_IOB_DMA_TXCH_RESET_PINTC;
7011b0335ea30bf85eecffd21be64b7653407d6259aOlof Johansson
70234c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	write_iob_reg(PAS_IOB_DMA_TXCH_RESET(tx_ring(mac)->chan.chno), reg);
7031b0335ea30bf85eecffd21be64b7653407d6259aOlof Johansson}
7041b0335ea30bf85eecffd21be64b7653407d6259aOlof Johansson
7051b0335ea30bf85eecffd21be64b7653407d6259aOlof Johansson
7065c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johanssonstatic inline void pasemi_mac_rx_error(const struct pasemi_mac *mac,
7075c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johansson				       const u64 macrx)
70869c29d89185dc1de7224f5f98588ddc061f1fad2Olof Johansson{
70969c29d89185dc1de7224f5f98588ddc061f1fad2Olof Johansson	unsigned int rcmdsta, ccmdsta;
71034c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	struct pasemi_dmachan *chan = &rx_ring(mac)->chan;
71169c29d89185dc1de7224f5f98588ddc061f1fad2Olof Johansson
71269c29d89185dc1de7224f5f98588ddc061f1fad2Olof Johansson	if (!netif_msg_rx_err(mac))
71369c29d89185dc1de7224f5f98588ddc061f1fad2Olof Johansson		return;
71469c29d89185dc1de7224f5f98588ddc061f1fad2Olof Johansson
71534c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	rcmdsta = read_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if));
71634c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	ccmdsta = read_dma_reg(PAS_DMA_RXCHAN_CCMDSTA(chan->chno));
71769c29d89185dc1de7224f5f98588ddc061f1fad2Olof Johansson
718fe333321e2a71f706b794d55b6a3dcb5ab240f65Ingo Molnar	printk(KERN_ERR "pasemi_mac: rx error. macrx %016llx, rx status %llx\n",
71934c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson		macrx, *chan->status);
72069c29d89185dc1de7224f5f98588ddc061f1fad2Olof Johansson
72169c29d89185dc1de7224f5f98588ddc061f1fad2Olof Johansson	printk(KERN_ERR "pasemi_mac: rcmdsta %08x ccmdsta %08x\n",
72269c29d89185dc1de7224f5f98588ddc061f1fad2Olof Johansson		rcmdsta, ccmdsta);
72369c29d89185dc1de7224f5f98588ddc061f1fad2Olof Johansson}
72469c29d89185dc1de7224f5f98588ddc061f1fad2Olof Johansson
7255c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johanssonstatic inline void pasemi_mac_tx_error(const struct pasemi_mac *mac,
7265c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johansson				       const u64 mactx)
72769c29d89185dc1de7224f5f98588ddc061f1fad2Olof Johansson{
72869c29d89185dc1de7224f5f98588ddc061f1fad2Olof Johansson	unsigned int cmdsta;
72934c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	struct pasemi_dmachan *chan = &tx_ring(mac)->chan;
73069c29d89185dc1de7224f5f98588ddc061f1fad2Olof Johansson
73169c29d89185dc1de7224f5f98588ddc061f1fad2Olof Johansson	if (!netif_msg_tx_err(mac))
73269c29d89185dc1de7224f5f98588ddc061f1fad2Olof Johansson		return;
73369c29d89185dc1de7224f5f98588ddc061f1fad2Olof Johansson
73434c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	cmdsta = read_dma_reg(PAS_DMA_TXCHAN_TCMDSTA(chan->chno));
73569c29d89185dc1de7224f5f98588ddc061f1fad2Olof Johansson
736fe333321e2a71f706b794d55b6a3dcb5ab240f65Ingo Molnar	printk(KERN_ERR "pasemi_mac: tx error. mactx 0x%016llx, "\
737fe333321e2a71f706b794d55b6a3dcb5ab240f65Ingo Molnar		"tx status 0x%016llx\n", mactx, *chan->status);
73869c29d89185dc1de7224f5f98588ddc061f1fad2Olof Johansson
73969c29d89185dc1de7224f5f98588ddc061f1fad2Olof Johansson	printk(KERN_ERR "pasemi_mac: tcmdsta 0x%08x\n", cmdsta);
74069c29d89185dc1de7224f5f98588ddc061f1fad2Olof Johansson}
74169c29d89185dc1de7224f5f98588ddc061f1fad2Olof Johansson
7425c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johanssonstatic int pasemi_mac_clean_rx(struct pasemi_mac_rxring *rx,
7435c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johansson			       const int limit)
744f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson{
7455c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johansson	const struct pasemi_dmachan *chan = &rx->chan;
74672b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson	struct pasemi_mac *mac = rx->mac;
7475c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johansson	struct pci_dev *pdev = mac->dma_pdev;
748cd4ceb245be7926e94558e2b6cd279bfaa775908Olof Johansson	unsigned int n;
7495c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johansson	int count, buf_index, tot_bytes, packets;
750cd4ceb245be7926e94558e2b6cd279bfaa775908Olof Johansson	struct pasemi_mac_buffer *info;
751cd4ceb245be7926e94558e2b6cd279bfaa775908Olof Johansson	struct sk_buff *skb;
752b5254eee7994ba0a44ba7386cb66c2ce2f30fcc6Olof Johansson	unsigned int len;
7535c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johansson	u64 macrx, eval;
754cd4ceb245be7926e94558e2b6cd279bfaa775908Olof Johansson	dma_addr_t dma;
7555c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johansson
7565c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johansson	tot_bytes = 0;
7575c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johansson	packets = 0;
758f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
75972b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson	spin_lock(&rx->lock);
760f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
76172b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson	n = rx->next_to_clean;
762f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
76372b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson	prefetch(&RX_DESC(rx, n));
764b5254eee7994ba0a44ba7386cb66c2ce2f30fcc6Olof Johansson
765b5254eee7994ba0a44ba7386cb66c2ce2f30fcc6Olof Johansson	for (count = 0; count < limit; count++) {
76672b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson		macrx = RX_DESC(rx, n);
7675c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johansson		prefetch(&RX_DESC(rx, n+4));
768f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
76969c29d89185dc1de7224f5f98588ddc061f1fad2Olof Johansson		if ((macrx & XCT_MACRX_E) ||
77034c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson		    (*chan->status & PAS_STATUS_ERROR))
77169c29d89185dc1de7224f5f98588ddc061f1fad2Olof Johansson			pasemi_mac_rx_error(mac, macrx);
77269c29d89185dc1de7224f5f98588ddc061f1fad2Olof Johansson
773cd4ceb245be7926e94558e2b6cd279bfaa775908Olof Johansson		if (!(macrx & XCT_MACRX_O))
774f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson			break;
775f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
776f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson		info = NULL;
777f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
778b5254eee7994ba0a44ba7386cb66c2ce2f30fcc6Olof Johansson		BUG_ON(!(macrx & XCT_MACRX_RR_8BRES));
779f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
78072b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson		eval = (RX_DESC(rx, n+1) & XCT_RXRES_8B_EVAL_M) >>
781b5254eee7994ba0a44ba7386cb66c2ce2f30fcc6Olof Johansson			XCT_RXRES_8B_EVAL_S;
782b5254eee7994ba0a44ba7386cb66c2ce2f30fcc6Olof Johansson		buf_index = eval-1;
783b5254eee7994ba0a44ba7386cb66c2ce2f30fcc6Olof Johansson
78472b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson		dma = (RX_DESC(rx, n+2) & XCT_PTR_ADDR_M);
78572b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson		info = &RX_DESC_INFO(rx, buf_index);
786fc9e4d2a93dab4a995e2e75725577b9a60154cbcOlof Johansson
7879f05cfe250498791cd24707aea3b728b52d886d5Olof Johansson		skb = info->skb;
788f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
7895c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johansson		prefetch_skb(skb);
790f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
791cd4ceb245be7926e94558e2b6cd279bfaa775908Olof Johansson		len = (macrx & XCT_MACRX_LLEN_M) >> XCT_MACRX_LLEN_S;
792f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
793ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson		pci_unmap_single(pdev, dma, mac->bufsz - LOCAL_SKB_ALIGN,
7945c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johansson				 PCI_DMA_FROMDEVICE);
79532bee776533eea839f9499d985c1490b5ac98512Olof Johansson
79632bee776533eea839f9499d985c1490b5ac98512Olof Johansson		if (macrx & XCT_MACRX_CRC) {
79732bee776533eea839f9499d985c1490b5ac98512Olof Johansson			/* CRC error flagged */
79832bee776533eea839f9499d985c1490b5ac98512Olof Johansson			mac->netdev->stats.rx_errors++;
79932bee776533eea839f9499d985c1490b5ac98512Olof Johansson			mac->netdev->stats.rx_crc_errors++;
8004352d82647f679fb8dd9440b34400fa49beedb2cOlof Johansson			/* No need to free skb, it'll be reused */
80132bee776533eea839f9499d985c1490b5ac98512Olof Johansson			goto next;
80232bee776533eea839f9499d985c1490b5ac98512Olof Johansson		}
80332bee776533eea839f9499d985c1490b5ac98512Olof Johansson
8045d8949448b68b3b355036c8061e3282388826ec5Olof Johansson		info->skb = NULL;
805ad5da10a64bdca1ed39b25946727a1ce2659f3d4Olof Johansson		info->dma = 0;
806fc9e4d2a93dab4a995e2e75725577b9a60154cbcOlof Johansson
80726fcfa95aef980cab4ff1ea55979c30e772dd0ddOlof Johansson		if (likely((macrx & XCT_MACRX_HTY_M) == XCT_MACRX_HTY_IPV4_OK)) {
80838bf3184e8c4b8cd4285a24b6f69a300b32f0062Olof Johansson			skb->ip_summed = CHECKSUM_UNNECESSARY;
809cd4ceb245be7926e94558e2b6cd279bfaa775908Olof Johansson			skb->csum = (macrx & XCT_MACRX_CSUM_M) >>
810f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson					   XCT_MACRX_CSUM_S;
811f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson		} else
812bc8acf2c8c3e43fcc192762a9f964b3e9a17748bEric Dumazet			skb_checksum_none_assert(skb);
813f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
8145c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johansson		packets++;
8155c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johansson		tot_bytes += len;
8165c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johansson
8175c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johansson		/* Don't include CRC */
8185c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johansson		skb_put(skb, len-4);
819f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
82026fcfa95aef980cab4ff1ea55979c30e772dd0ddOlof Johansson		skb->protocol = eth_type_trans(skb, mac->netdev);
82128ae79f531014bb3ad95b6efa0e0603069087bc5Olof Johansson		lro_receive_skb(&mac->lro_mgr, skb, (void *)macrx);
822f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
82332bee776533eea839f9499d985c1490b5ac98512Olof Johanssonnext:
82472b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson		RX_DESC(rx, n) = 0;
82572b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson		RX_DESC(rx, n+1) = 0;
826cd4ceb245be7926e94558e2b6cd279bfaa775908Olof Johansson
827ad5da10a64bdca1ed39b25946727a1ce2659f3d4Olof Johansson		/* Need to zero it out since hardware doesn't, since the
828ad5da10a64bdca1ed39b25946727a1ce2659f3d4Olof Johansson		 * replenish loop uses it to tell when it's done.
829ad5da10a64bdca1ed39b25946727a1ce2659f3d4Olof Johansson		 */
83072b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson		RX_BUFF(rx, buf_index) = 0;
831ad5da10a64bdca1ed39b25946727a1ce2659f3d4Olof Johansson
832b5254eee7994ba0a44ba7386cb66c2ce2f30fcc6Olof Johansson		n += 4;
833f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	}
834f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
8359a50bebda95745d312c69d3bb6d788067cbefb84Olof Johansson	if (n > RX_RING_SIZE) {
8369a50bebda95745d312c69d3bb6d788067cbefb84Olof Johansson		/* Errata 5971 workaround: L2 target of headers */
83734c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson		write_iob_reg(PAS_IOB_COM_PKTHDRCNT, 0);
8389a50bebda95745d312c69d3bb6d788067cbefb84Olof Johansson		n &= (RX_RING_SIZE-1);
8399a50bebda95745d312c69d3bb6d788067cbefb84Olof Johansson	}
840b5254eee7994ba0a44ba7386cb66c2ce2f30fcc6Olof Johansson
84172b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson	rx_ring(mac)->next_to_clean = n;
842b5254eee7994ba0a44ba7386cb66c2ce2f30fcc6Olof Johansson
84328ae79f531014bb3ad95b6efa0e0603069087bc5Olof Johansson	lro_flush_all(&mac->lro_mgr);
84428ae79f531014bb3ad95b6efa0e0603069087bc5Olof Johansson
845b5254eee7994ba0a44ba7386cb66c2ce2f30fcc6Olof Johansson	/* Increase is in number of 16-byte entries, and since each descriptor
846b5254eee7994ba0a44ba7386cb66c2ce2f30fcc6Olof Johansson	 * with an 8BRES takes up 3x8 bytes (padded to 4x8), increase with
847b5254eee7994ba0a44ba7386cb66c2ce2f30fcc6Olof Johansson	 * count*2.
848b5254eee7994ba0a44ba7386cb66c2ce2f30fcc6Olof Johansson	 */
84934c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	write_dma_reg(PAS_DMA_RXCHAN_INCR(mac->rx->chan.chno), count << 1);
850b5254eee7994ba0a44ba7386cb66c2ce2f30fcc6Olof Johansson
851b5254eee7994ba0a44ba7386cb66c2ce2f30fcc6Olof Johansson	pasemi_mac_replenish_rx_ring(mac->netdev, count);
852f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
8535c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johansson	mac->netdev->stats.rx_bytes += tot_bytes;
8545c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johansson	mac->netdev->stats.rx_packets += packets;
8555c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johansson
85672b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson	spin_unlock(&rx_ring(mac)->lock);
857f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
858f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	return count;
859f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson}
860f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
861ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson/* Can't make this too large or we blow the kernel stack limits */
862ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson#define TX_CLEAN_BATCHSIZE (128/MAX_SKB_FRAGS)
863ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson
86472b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johanssonstatic int pasemi_mac_clean_tx(struct pasemi_mac_txring *txring)
865f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson{
86634c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	struct pasemi_dmachan *chan = &txring->chan;
86772b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson	struct pasemi_mac *mac = txring->mac;
868ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson	int i, j;
869ad5da10a64bdca1ed39b25946727a1ce2659f3d4Olof Johansson	unsigned int start, descr_count, buf_count, batch_limit;
870ad5da10a64bdca1ed39b25946727a1ce2659f3d4Olof Johansson	unsigned int ring_limit;
87102df6cfa09c2ccebe685bfd54a708e1f50b00a81Olof Johansson	unsigned int total_count;
872ca7e235f5eb960d83b45cef4384b490672538cd9Olof Johansson	unsigned long flags;
873ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson	struct sk_buff *skbs[TX_CLEAN_BATCHSIZE];
874ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson	dma_addr_t dmas[TX_CLEAN_BATCHSIZE][MAX_SKB_FRAGS+1];
8757e9916e9ddf23cd08107ed1a7fac429eea619313Olof Johansson	int nf[TX_CLEAN_BATCHSIZE];
8767e9916e9ddf23cd08107ed1a7fac429eea619313Olof Johansson	int nr_frags;
877f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
87802df6cfa09c2ccebe685bfd54a708e1f50b00a81Olof Johansson	total_count = 0;
879ad5da10a64bdca1ed39b25946727a1ce2659f3d4Olof Johansson	batch_limit = TX_CLEAN_BATCHSIZE;
88002df6cfa09c2ccebe685bfd54a708e1f50b00a81Olof Johanssonrestart:
88172b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson	spin_lock_irqsave(&txring->lock, flags);
882f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
88372b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson	start = txring->next_to_clean;
88472b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson	ring_limit = txring->next_to_fill;
885ad5da10a64bdca1ed39b25946727a1ce2659f3d4Olof Johansson
8867e9916e9ddf23cd08107ed1a7fac429eea619313Olof Johansson	prefetch(&TX_DESC_INFO(txring, start+1).skb);
8877e9916e9ddf23cd08107ed1a7fac429eea619313Olof Johansson
888ad5da10a64bdca1ed39b25946727a1ce2659f3d4Olof Johansson	/* Compensate for when fill has wrapped but clean has not */
889ad5da10a64bdca1ed39b25946727a1ce2659f3d4Olof Johansson	if (start > ring_limit)
890ad5da10a64bdca1ed39b25946727a1ce2659f3d4Olof Johansson		ring_limit += TX_RING_SIZE;
89102df6cfa09c2ccebe685bfd54a708e1f50b00a81Olof Johansson
892ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson	buf_count = 0;
893ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson	descr_count = 0;
894f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
895ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson	for (i = start;
896ad5da10a64bdca1ed39b25946727a1ce2659f3d4Olof Johansson	     descr_count < batch_limit && i < ring_limit;
897ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson	     i += buf_count) {
89872b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson		u64 mactx = TX_DESC(txring, i);
899ad5da10a64bdca1ed39b25946727a1ce2659f3d4Olof Johansson		struct sk_buff *skb;
900ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson
901fc9e4d2a93dab4a995e2e75725577b9a60154cbcOlof Johansson		if ((mactx  & XCT_MACTX_E) ||
90234c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson		    (*chan->status & PAS_STATUS_ERROR))
903fc9e4d2a93dab4a995e2e75725577b9a60154cbcOlof Johansson			pasemi_mac_tx_error(mac, mactx);
90469c29d89185dc1de7224f5f98588ddc061f1fad2Olof Johansson
9058d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson		/* Skip over control descriptors */
9068d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson		if (!(mactx & XCT_MACTX_LLEN_M)) {
9078d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson			TX_DESC(txring, i) = 0;
9088d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson			TX_DESC(txring, i+1) = 0;
9098d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson			buf_count = 2;
9108d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson			continue;
9118d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson		}
9128d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson
9138d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson		skb = TX_DESC_INFO(txring, i+1).skb;
9148d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson		nr_frags = TX_DESC_INFO(txring, i).dma;
9158d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson
916fc9e4d2a93dab4a995e2e75725577b9a60154cbcOlof Johansson		if (unlikely(mactx & XCT_MACTX_O))
91702df6cfa09c2ccebe685bfd54a708e1f50b00a81Olof Johansson			/* Not yet transmitted */
918f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson			break;
919f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
9207e9916e9ddf23cd08107ed1a7fac429eea619313Olof Johansson		buf_count = 2 + nr_frags;
9217e9916e9ddf23cd08107ed1a7fac429eea619313Olof Johansson		/* Since we always fill with an even number of entries, make
9227e9916e9ddf23cd08107ed1a7fac429eea619313Olof Johansson		 * sure we skip any unused one at the end as well.
9237e9916e9ddf23cd08107ed1a7fac429eea619313Olof Johansson		 */
9247e9916e9ddf23cd08107ed1a7fac429eea619313Olof Johansson		if (buf_count & 1)
9257e9916e9ddf23cd08107ed1a7fac429eea619313Olof Johansson			buf_count++;
926ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson
9277e9916e9ddf23cd08107ed1a7fac429eea619313Olof Johansson		for (j = 0; j <= nr_frags; j++)
92872b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson			dmas[descr_count][j] = TX_DESC_INFO(txring, i+1+j).dma;
929ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson
9307e9916e9ddf23cd08107ed1a7fac429eea619313Olof Johansson		skbs[descr_count] = skb;
9317e9916e9ddf23cd08107ed1a7fac429eea619313Olof Johansson		nf[descr_count] = nr_frags;
9327e9916e9ddf23cd08107ed1a7fac429eea619313Olof Johansson
93372b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson		TX_DESC(txring, i) = 0;
93472b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson		TX_DESC(txring, i+1) = 0;
935fc9e4d2a93dab4a995e2e75725577b9a60154cbcOlof Johansson
936ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson		descr_count++;
937f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	}
93872b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson	txring->next_to_clean = i & (TX_RING_SIZE-1);
939ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson
94072b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson	spin_unlock_irqrestore(&txring->lock, flags);
9410ce68c74162ce288cfd214dd126b8d03b8b7a8edOlof Johansson	netif_wake_queue(mac->netdev);
9420ce68c74162ce288cfd214dd126b8d03b8b7a8edOlof Johansson
943ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson	for (i = 0; i < descr_count; i++)
9447e9916e9ddf23cd08107ed1a7fac429eea619313Olof Johansson		pasemi_mac_unmap_tx_skb(mac, nf[i], skbs[i], dmas[i]);
94502df6cfa09c2ccebe685bfd54a708e1f50b00a81Olof Johansson
946ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson	total_count += descr_count;
94702df6cfa09c2ccebe685bfd54a708e1f50b00a81Olof Johansson
94802df6cfa09c2ccebe685bfd54a708e1f50b00a81Olof Johansson	/* If the batch was full, try to clean more */
949ad5da10a64bdca1ed39b25946727a1ce2659f3d4Olof Johansson	if (descr_count == batch_limit)
95002df6cfa09c2ccebe685bfd54a708e1f50b00a81Olof Johansson		goto restart;
95102df6cfa09c2ccebe685bfd54a708e1f50b00a81Olof Johansson
95202df6cfa09c2ccebe685bfd54a708e1f50b00a81Olof Johansson	return total_count;
953f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson}
954f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
955f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
956f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johanssonstatic irqreturn_t pasemi_mac_rx_intr(int irq, void *data)
957f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson{
9585c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johansson	const struct pasemi_mac_rxring *rxring = data;
95934c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	struct pasemi_mac *mac = rxring->mac;
9605c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johansson	const struct pasemi_dmachan *chan = &rxring->chan;
961f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	unsigned int reg;
962f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
96334c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	if (!(*chan->status & PAS_STATUS_CAUSE_M))
964f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson		return IRQ_NONE;
965f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
9666dfa7522d8b08c887bf9f4cb2600b89232f132f5Olof Johansson	/* Don't reset packet count so it won't fire again but clear
9676dfa7522d8b08c887bf9f4cb2600b89232f132f5Olof Johansson	 * all others.
9686dfa7522d8b08c887bf9f4cb2600b89232f132f5Olof Johansson	 */
9696dfa7522d8b08c887bf9f4cb2600b89232f132f5Olof Johansson
9706dfa7522d8b08c887bf9f4cb2600b89232f132f5Olof Johansson	reg = 0;
97134c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	if (*chan->status & PAS_STATUS_SOFT)
9726dfa7522d8b08c887bf9f4cb2600b89232f132f5Olof Johansson		reg |= PAS_IOB_DMA_RXCH_RESET_SINTC;
97334c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	if (*chan->status & PAS_STATUS_ERROR)
9746dfa7522d8b08c887bf9f4cb2600b89232f132f5Olof Johansson		reg |= PAS_IOB_DMA_RXCH_RESET_DINTC;
975f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
976288379f050284087578b77e04f040b57db3db3f8Ben Hutchings	napi_schedule(&mac->napi);
9776dfa7522d8b08c887bf9f4cb2600b89232f132f5Olof Johansson
97834c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	write_iob_reg(PAS_IOB_DMA_RXCH_RESET(chan->chno), reg);
979f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
980f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	return IRQ_HANDLED;
981f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson}
982f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
98361cec3bddc79373a246e2f8eb13e5acdc106f46aOlof Johansson#define TX_CLEAN_INTERVAL HZ
98461cec3bddc79373a246e2f8eb13e5acdc106f46aOlof Johansson
98561cec3bddc79373a246e2f8eb13e5acdc106f46aOlof Johanssonstatic void pasemi_mac_tx_timer(unsigned long data)
98661cec3bddc79373a246e2f8eb13e5acdc106f46aOlof Johansson{
98761cec3bddc79373a246e2f8eb13e5acdc106f46aOlof Johansson	struct pasemi_mac_txring *txring = (struct pasemi_mac_txring *)data;
98861cec3bddc79373a246e2f8eb13e5acdc106f46aOlof Johansson	struct pasemi_mac *mac = txring->mac;
98961cec3bddc79373a246e2f8eb13e5acdc106f46aOlof Johansson
99061cec3bddc79373a246e2f8eb13e5acdc106f46aOlof Johansson	pasemi_mac_clean_tx(txring);
99161cec3bddc79373a246e2f8eb13e5acdc106f46aOlof Johansson
99261cec3bddc79373a246e2f8eb13e5acdc106f46aOlof Johansson	mod_timer(&txring->clean_timer, jiffies + TX_CLEAN_INTERVAL);
99361cec3bddc79373a246e2f8eb13e5acdc106f46aOlof Johansson
99461cec3bddc79373a246e2f8eb13e5acdc106f46aOlof Johansson	pasemi_mac_restart_tx_intr(mac);
99561cec3bddc79373a246e2f8eb13e5acdc106f46aOlof Johansson}
99661cec3bddc79373a246e2f8eb13e5acdc106f46aOlof Johansson
997f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johanssonstatic irqreturn_t pasemi_mac_tx_intr(int irq, void *data)
998f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson{
99972b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson	struct pasemi_mac_txring *txring = data;
10005c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johansson	const struct pasemi_dmachan *chan = &txring->chan;
100161cec3bddc79373a246e2f8eb13e5acdc106f46aOlof Johansson	struct pasemi_mac *mac = txring->mac;
100261cec3bddc79373a246e2f8eb13e5acdc106f46aOlof Johansson	unsigned int reg;
1003f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
100434c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	if (!(*chan->status & PAS_STATUS_CAUSE_M))
1005f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson		return IRQ_NONE;
1006f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
100761cec3bddc79373a246e2f8eb13e5acdc106f46aOlof Johansson	reg = 0;
10086dfa7522d8b08c887bf9f4cb2600b89232f132f5Olof Johansson
100934c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	if (*chan->status & PAS_STATUS_SOFT)
10106dfa7522d8b08c887bf9f4cb2600b89232f132f5Olof Johansson		reg |= PAS_IOB_DMA_TXCH_RESET_SINTC;
101134c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	if (*chan->status & PAS_STATUS_ERROR)
10126dfa7522d8b08c887bf9f4cb2600b89232f132f5Olof Johansson		reg |= PAS_IOB_DMA_TXCH_RESET_DINTC;
1013f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
101461cec3bddc79373a246e2f8eb13e5acdc106f46aOlof Johansson	mod_timer(&txring->clean_timer, jiffies + (TX_CLEAN_INTERVAL)*2);
101561cec3bddc79373a246e2f8eb13e5acdc106f46aOlof Johansson
1016288379f050284087578b77e04f040b57db3db3f8Ben Hutchings	napi_schedule(&mac->napi);
101761cec3bddc79373a246e2f8eb13e5acdc106f46aOlof Johansson
101861cec3bddc79373a246e2f8eb13e5acdc106f46aOlof Johansson	if (reg)
101961cec3bddc79373a246e2f8eb13e5acdc106f46aOlof Johansson		write_iob_reg(PAS_IOB_DMA_TXCH_RESET(chan->chno), reg);
1020f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1021f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	return IRQ_HANDLED;
1022f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson}
1023f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1024bb6e9590792834f905a92e439a083254649c985cOlof Johanssonstatic void pasemi_adjust_link(struct net_device *dev)
1025bb6e9590792834f905a92e439a083254649c985cOlof Johansson{
1026bb6e9590792834f905a92e439a083254649c985cOlof Johansson	struct pasemi_mac *mac = netdev_priv(dev);
1027bb6e9590792834f905a92e439a083254649c985cOlof Johansson	int msg;
1028bb6e9590792834f905a92e439a083254649c985cOlof Johansson	unsigned int flags;
1029bb6e9590792834f905a92e439a083254649c985cOlof Johansson	unsigned int new_flags;
1030bb6e9590792834f905a92e439a083254649c985cOlof Johansson
1031bb6e9590792834f905a92e439a083254649c985cOlof Johansson	if (!mac->phydev->link) {
1032bb6e9590792834f905a92e439a083254649c985cOlof Johansson		/* If no link, MAC speed settings don't matter. Just report
1033bb6e9590792834f905a92e439a083254649c985cOlof Johansson		 * link down and return.
1034bb6e9590792834f905a92e439a083254649c985cOlof Johansson		 */
1035bb6e9590792834f905a92e439a083254649c985cOlof Johansson		if (mac->link && netif_msg_link(mac))
1036bb6e9590792834f905a92e439a083254649c985cOlof Johansson			printk(KERN_INFO "%s: Link is down.\n", dev->name);
1037bb6e9590792834f905a92e439a083254649c985cOlof Johansson
1038bb6e9590792834f905a92e439a083254649c985cOlof Johansson		netif_carrier_off(dev);
1039b0cd2f9016f75eb8a9fdc45d32f9b41fb16d48c9Olof Johansson		pasemi_mac_intf_disable(mac);
1040bb6e9590792834f905a92e439a083254649c985cOlof Johansson		mac->link = 0;
1041bb6e9590792834f905a92e439a083254649c985cOlof Johansson
1042bb6e9590792834f905a92e439a083254649c985cOlof Johansson		return;
1043b0cd2f9016f75eb8a9fdc45d32f9b41fb16d48c9Olof Johansson	} else {
1044b0cd2f9016f75eb8a9fdc45d32f9b41fb16d48c9Olof Johansson		pasemi_mac_intf_enable(mac);
1045bb6e9590792834f905a92e439a083254649c985cOlof Johansson		netif_carrier_on(dev);
1046b0cd2f9016f75eb8a9fdc45d32f9b41fb16d48c9Olof Johansson	}
1047bb6e9590792834f905a92e439a083254649c985cOlof Johansson
1048a85b94222d8b95e184941183f28b06b637cc4deeOlof Johansson	flags = read_mac_reg(mac, PAS_MAC_CFG_PCFG);
1049bb6e9590792834f905a92e439a083254649c985cOlof Johansson	new_flags = flags & ~(PAS_MAC_CFG_PCFG_HD | PAS_MAC_CFG_PCFG_SPD_M |
1050bb6e9590792834f905a92e439a083254649c985cOlof Johansson			      PAS_MAC_CFG_PCFG_TSR_M);
1051bb6e9590792834f905a92e439a083254649c985cOlof Johansson
1052bb6e9590792834f905a92e439a083254649c985cOlof Johansson	if (!mac->phydev->duplex)
1053bb6e9590792834f905a92e439a083254649c985cOlof Johansson		new_flags |= PAS_MAC_CFG_PCFG_HD;
1054bb6e9590792834f905a92e439a083254649c985cOlof Johansson
1055bb6e9590792834f905a92e439a083254649c985cOlof Johansson	switch (mac->phydev->speed) {
1056bb6e9590792834f905a92e439a083254649c985cOlof Johansson	case 1000:
1057bb6e9590792834f905a92e439a083254649c985cOlof Johansson		new_flags |= PAS_MAC_CFG_PCFG_SPD_1G |
1058bb6e9590792834f905a92e439a083254649c985cOlof Johansson			     PAS_MAC_CFG_PCFG_TSR_1G;
1059bb6e9590792834f905a92e439a083254649c985cOlof Johansson		break;
1060bb6e9590792834f905a92e439a083254649c985cOlof Johansson	case 100:
1061bb6e9590792834f905a92e439a083254649c985cOlof Johansson		new_flags |= PAS_MAC_CFG_PCFG_SPD_100M |
1062bb6e9590792834f905a92e439a083254649c985cOlof Johansson			     PAS_MAC_CFG_PCFG_TSR_100M;
1063bb6e9590792834f905a92e439a083254649c985cOlof Johansson		break;
1064bb6e9590792834f905a92e439a083254649c985cOlof Johansson	case 10:
1065bb6e9590792834f905a92e439a083254649c985cOlof Johansson		new_flags |= PAS_MAC_CFG_PCFG_SPD_10M |
1066bb6e9590792834f905a92e439a083254649c985cOlof Johansson			     PAS_MAC_CFG_PCFG_TSR_10M;
1067bb6e9590792834f905a92e439a083254649c985cOlof Johansson		break;
1068bb6e9590792834f905a92e439a083254649c985cOlof Johansson	default:
1069bb6e9590792834f905a92e439a083254649c985cOlof Johansson		printk("Unsupported speed %d\n", mac->phydev->speed);
1070bb6e9590792834f905a92e439a083254649c985cOlof Johansson	}
1071bb6e9590792834f905a92e439a083254649c985cOlof Johansson
1072bb6e9590792834f905a92e439a083254649c985cOlof Johansson	/* Print on link or speed/duplex change */
1073bb6e9590792834f905a92e439a083254649c985cOlof Johansson	msg = mac->link != mac->phydev->link || flags != new_flags;
1074bb6e9590792834f905a92e439a083254649c985cOlof Johansson
1075bb6e9590792834f905a92e439a083254649c985cOlof Johansson	mac->duplex = mac->phydev->duplex;
1076bb6e9590792834f905a92e439a083254649c985cOlof Johansson	mac->speed = mac->phydev->speed;
1077bb6e9590792834f905a92e439a083254649c985cOlof Johansson	mac->link = mac->phydev->link;
1078bb6e9590792834f905a92e439a083254649c985cOlof Johansson
1079bb6e9590792834f905a92e439a083254649c985cOlof Johansson	if (new_flags != flags)
1080a85b94222d8b95e184941183f28b06b637cc4deeOlof Johansson		write_mac_reg(mac, PAS_MAC_CFG_PCFG, new_flags);
1081bb6e9590792834f905a92e439a083254649c985cOlof Johansson
1082bb6e9590792834f905a92e439a083254649c985cOlof Johansson	if (msg && netif_msg_link(mac))
1083bb6e9590792834f905a92e439a083254649c985cOlof Johansson		printk(KERN_INFO "%s: Link is up at %d Mbps, %s duplex.\n",
1084bb6e9590792834f905a92e439a083254649c985cOlof Johansson		       dev->name, mac->speed, mac->duplex ? "full" : "half");
1085bb6e9590792834f905a92e439a083254649c985cOlof Johansson}
1086bb6e9590792834f905a92e439a083254649c985cOlof Johansson
1087bb6e9590792834f905a92e439a083254649c985cOlof Johanssonstatic int pasemi_mac_phy_init(struct net_device *dev)
1088bb6e9590792834f905a92e439a083254649c985cOlof Johansson{
1089bb6e9590792834f905a92e439a083254649c985cOlof Johansson	struct pasemi_mac *mac = netdev_priv(dev);
1090bb6e9590792834f905a92e439a083254649c985cOlof Johansson	struct device_node *dn, *phy_dn;
1091bb6e9590792834f905a92e439a083254649c985cOlof Johansson	struct phy_device *phydev;
1092bb6e9590792834f905a92e439a083254649c985cOlof Johansson
1093bb6e9590792834f905a92e439a083254649c985cOlof Johansson	dn = pci_device_to_OF_node(mac->pdev);
10941dd2d06c0459a2f1bffc56765e3cc57427818867Grant Likely	phy_dn = of_parse_phandle(dn, "phy-handle", 0);
1095bb6e9590792834f905a92e439a083254649c985cOlof Johansson	of_node_put(phy_dn);
1096bb6e9590792834f905a92e439a083254649c985cOlof Johansson
1097bb6e9590792834f905a92e439a083254649c985cOlof Johansson	mac->link = 0;
1098bb6e9590792834f905a92e439a083254649c985cOlof Johansson	mac->speed = 0;
1099bb6e9590792834f905a92e439a083254649c985cOlof Johansson	mac->duplex = -1;
1100bb6e9590792834f905a92e439a083254649c985cOlof Johansson
11011dd2d06c0459a2f1bffc56765e3cc57427818867Grant Likely	phydev = of_phy_connect(dev, phy_dn, &pasemi_adjust_link, 0,
11021dd2d06c0459a2f1bffc56765e3cc57427818867Grant Likely				PHY_INTERFACE_MODE_SGMII);
1103bb6e9590792834f905a92e439a083254649c985cOlof Johansson
1104bb6e9590792834f905a92e439a083254649c985cOlof Johansson	if (IS_ERR(phydev)) {
1105bb6e9590792834f905a92e439a083254649c985cOlof Johansson		printk(KERN_ERR "%s: Could not attach to phy\n", dev->name);
1106bb6e9590792834f905a92e439a083254649c985cOlof Johansson		return PTR_ERR(phydev);
1107bb6e9590792834f905a92e439a083254649c985cOlof Johansson	}
1108bb6e9590792834f905a92e439a083254649c985cOlof Johansson
1109bb6e9590792834f905a92e439a083254649c985cOlof Johansson	mac->phydev = phydev;
1110bb6e9590792834f905a92e439a083254649c985cOlof Johansson
1111bb6e9590792834f905a92e439a083254649c985cOlof Johansson	return 0;
1112bb6e9590792834f905a92e439a083254649c985cOlof Johansson}
1113bb6e9590792834f905a92e439a083254649c985cOlof Johansson
1114bb6e9590792834f905a92e439a083254649c985cOlof Johansson
1115f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johanssonstatic int pasemi_mac_open(struct net_device *dev)
1116f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson{
1117f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	struct pasemi_mac *mac = netdev_priv(dev);
1118f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	unsigned int flags;
1119e37c772e36a7943b2e0bd8f48312e78474c0df15Olof Johansson	int i, ret;
1120f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1121f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	flags = PAS_MAC_CFG_TXP_FCE | PAS_MAC_CFG_TXP_FPC(3) |
1122f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson		PAS_MAC_CFG_TXP_SL(3) | PAS_MAC_CFG_TXP_COB(0xf) |
1123f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson		PAS_MAC_CFG_TXP_TIFT(8) | PAS_MAC_CFG_TXP_TIFG(12);
1124f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1125a85b94222d8b95e184941183f28b06b637cc4deeOlof Johansson	write_mac_reg(mac, PAS_MAC_CFG_TXP, flags);
1126f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1127f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	ret = pasemi_mac_setup_rx_resources(dev);
1128f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	if (ret)
1129f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson		goto out_rx_resources;
1130f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
113134c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	mac->tx = pasemi_mac_setup_tx_resources(dev);
113272b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson
113372b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson	if (!mac->tx)
113472b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson		goto out_tx_ring;
1135f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
11361724ac2ef1caf5b4f764d4b86a85d552a7d7c8fbOlof Johansson	/* We might already have allocated rings in case mtu was changed
11371724ac2ef1caf5b4f764d4b86a85d552a7d7c8fbOlof Johansson	 * before interface was brought up.
11381724ac2ef1caf5b4f764d4b86a85d552a7d7c8fbOlof Johansson	 */
11391724ac2ef1caf5b4f764d4b86a85d552a7d7c8fbOlof Johansson	if (dev->mtu > 1500 && !mac->num_cs) {
11408d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson		pasemi_mac_setup_csrings(mac);
11418d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson		if (!mac->num_cs)
11428d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson			goto out_tx_ring;
11438d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	}
11448d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson
1145e37c772e36a7943b2e0bd8f48312e78474c0df15Olof Johansson	/* Zero out rmon counters */
1146e37c772e36a7943b2e0bd8f48312e78474c0df15Olof Johansson	for (i = 0; i < 32; i++)
1147e37c772e36a7943b2e0bd8f48312e78474c0df15Olof Johansson		write_mac_reg(mac, PAS_MAC_RMON(i), 0);
1148e37c772e36a7943b2e0bd8f48312e78474c0df15Olof Johansson
1149906674abab0424b466a2db4bb6a890a8c477b10aOlof Johansson	/* 0x3ff with 33MHz clock is about 31us */
1150906674abab0424b466a2db4bb6a890a8c477b10aOlof Johansson	write_iob_reg(PAS_IOB_DMA_COM_TIMEOUTCFG,
1151906674abab0424b466a2db4bb6a890a8c477b10aOlof Johansson		      PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(0x3ff));
1152906674abab0424b466a2db4bb6a890a8c477b10aOlof Johansson
115334c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	write_iob_reg(PAS_IOB_DMA_RXCH_CFG(mac->rx->chan.chno),
115428ae79f531014bb3ad95b6efa0e0603069087bc5Olof Johansson		      PAS_IOB_DMA_RXCH_CFG_CNTTH(256));
115534c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson
115634c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	write_iob_reg(PAS_IOB_DMA_TXCH_CFG(mac->tx->chan.chno),
115761cec3bddc79373a246e2f8eb13e5acdc106f46aOlof Johansson		      PAS_IOB_DMA_TXCH_CFG_CNTTH(32));
115834c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson
1159a85b94222d8b95e184941183f28b06b637cc4deeOlof Johansson	write_mac_reg(mac, PAS_MAC_IPC_CHNL,
116034c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson		      PAS_MAC_IPC_CHNL_DCHNO(mac->rx->chan.chno) |
116134c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson		      PAS_MAC_IPC_CHNL_BCH(mac->rx->chan.chno));
1162f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1163f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	/* enable rx if */
116434c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	write_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if),
116534c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson		      PAS_DMA_RXINT_RCMDSTA_EN |
116634c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson		      PAS_DMA_RXINT_RCMDSTA_DROPS_M |
116734c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson		      PAS_DMA_RXINT_RCMDSTA_BP |
116834c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson		      PAS_DMA_RXINT_RCMDSTA_OO |
116934c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson		      PAS_DMA_RXINT_RCMDSTA_BT);
1170f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1171f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	/* enable rx channel */
117234c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	pasemi_dma_start_chan(&rx_ring(mac)->chan, PAS_DMA_RXCHAN_CCMDSTA_DU |
117334c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson						   PAS_DMA_RXCHAN_CCMDSTA_OD |
117434c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson						   PAS_DMA_RXCHAN_CCMDSTA_FD |
117534c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson						   PAS_DMA_RXCHAN_CCMDSTA_DT);
1176f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1177f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	/* enable tx channel */
117834c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	pasemi_dma_start_chan(&tx_ring(mac)->chan, PAS_DMA_TXCHAN_TCMDSTA_SZ |
117934c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson						   PAS_DMA_TXCHAN_TCMDSTA_DB |
118034c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson						   PAS_DMA_TXCHAN_TCMDSTA_DE |
118134c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson						   PAS_DMA_TXCHAN_TCMDSTA_DA);
1182f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1183928773c23a4cf053a34ad480439448f75efa350cOlof Johansson	pasemi_mac_replenish_rx_ring(dev, RX_RING_SIZE);
1184f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
118534c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	write_dma_reg(PAS_DMA_RXCHAN_INCR(rx_ring(mac)->chan.chno),
118634c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson		      RX_RING_SIZE>>1);
1187b5254eee7994ba0a44ba7386cb66c2ce2f30fcc6Olof Johansson
118872b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson	/* Clear out any residual packet count state from firmware */
118972b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson	pasemi_mac_restart_rx_intr(mac);
119072b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson	pasemi_mac_restart_tx_intr(mac);
119172b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson
1192b0cd2f9016f75eb8a9fdc45d32f9b41fb16d48c9Olof Johansson	flags = PAS_MAC_CFG_PCFG_S1 | PAS_MAC_CFG_PCFG_PR | PAS_MAC_CFG_PCFG_CE;
119336033766533176d61ba15793d8ef219775499c2fOlof Johansson
119436033766533176d61ba15793d8ef219775499c2fOlof Johansson	if (mac->type == MAC_TYPE_GMAC)
119536033766533176d61ba15793d8ef219775499c2fOlof Johansson		flags |= PAS_MAC_CFG_PCFG_TSR_1G | PAS_MAC_CFG_PCFG_SPD_1G;
119636033766533176d61ba15793d8ef219775499c2fOlof Johansson	else
119736033766533176d61ba15793d8ef219775499c2fOlof Johansson		flags |= PAS_MAC_CFG_PCFG_TSR_10G | PAS_MAC_CFG_PCFG_SPD_10G;
119836033766533176d61ba15793d8ef219775499c2fOlof Johansson
119936033766533176d61ba15793d8ef219775499c2fOlof Johansson	/* Enable interface in MAC */
120036033766533176d61ba15793d8ef219775499c2fOlof Johansson	write_mac_reg(mac, PAS_MAC_CFG_PCFG, flags);
120136033766533176d61ba15793d8ef219775499c2fOlof Johansson
1202bb6e9590792834f905a92e439a083254649c985cOlof Johansson	ret = pasemi_mac_phy_init(dev);
1203b0cd2f9016f75eb8a9fdc45d32f9b41fb16d48c9Olof Johansson	if (ret) {
1204b0cd2f9016f75eb8a9fdc45d32f9b41fb16d48c9Olof Johansson		/* Since we won't get link notification, just enable RX */
1205b0cd2f9016f75eb8a9fdc45d32f9b41fb16d48c9Olof Johansson		pasemi_mac_intf_enable(mac);
1206b0cd2f9016f75eb8a9fdc45d32f9b41fb16d48c9Olof Johansson		if (mac->type == MAC_TYPE_GMAC) {
1207b0cd2f9016f75eb8a9fdc45d32f9b41fb16d48c9Olof Johansson			/* Warn for missing PHY on SGMII (1Gig) ports */
1208b0cd2f9016f75eb8a9fdc45d32f9b41fb16d48c9Olof Johansson			dev_warn(&mac->pdev->dev,
1209b0cd2f9016f75eb8a9fdc45d32f9b41fb16d48c9Olof Johansson				 "PHY init failed: %d.\n", ret);
1210b0cd2f9016f75eb8a9fdc45d32f9b41fb16d48c9Olof Johansson			dev_warn(&mac->pdev->dev,
1211b0cd2f9016f75eb8a9fdc45d32f9b41fb16d48c9Olof Johansson				 "Defaulting to 1Gbit full duplex\n");
1212b0cd2f9016f75eb8a9fdc45d32f9b41fb16d48c9Olof Johansson		}
12138304b633c5e8c9ba34d3cc7f24f52434d3a3b93bOlof Johansson	}
1214bb6e9590792834f905a92e439a083254649c985cOlof Johansson
1215f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	netif_start_queue(dev);
1216bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger	napi_enable(&mac->napi);
1217f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
121872b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson	snprintf(mac->tx_irq_name, sizeof(mac->tx_irq_name), "%s tx",
121972b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson		 dev->name);
1220771f7404a9deca902594823d616cd7a84f827982Olof Johansson
1221a0607fd3a25ba1848a63a0d925e36d914735ab47Joe Perches	ret = request_irq(mac->tx->chan.irq, pasemi_mac_tx_intr, IRQF_DISABLED,
122272b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson			  mac->tx_irq_name, mac->tx);
1223f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	if (ret) {
1224f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson		dev_err(&mac->pdev->dev, "request_irq of irq %d failed: %d\n",
122534c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson			mac->tx->chan.irq, ret);
1226f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson		goto out_tx_int;
1227f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	}
1228f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
122972b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson	snprintf(mac->rx_irq_name, sizeof(mac->rx_irq_name), "%s rx",
123072b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson		 dev->name);
123172b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson
1232a0607fd3a25ba1848a63a0d925e36d914735ab47Joe Perches	ret = request_irq(mac->rx->chan.irq, pasemi_mac_rx_intr, IRQF_DISABLED,
123334c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson			  mac->rx_irq_name, mac->rx);
1234f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	if (ret) {
1235f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson		dev_err(&mac->pdev->dev, "request_irq of irq %d failed: %d\n",
123634c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson			mac->rx->chan.irq, ret);
1237f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson		goto out_rx_int;
1238f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	}
1239f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1240bb6e9590792834f905a92e439a083254649c985cOlof Johansson	if (mac->phydev)
1241bb6e9590792834f905a92e439a083254649c985cOlof Johansson		phy_start(mac->phydev);
1242bb6e9590792834f905a92e439a083254649c985cOlof Johansson
124361cec3bddc79373a246e2f8eb13e5acdc106f46aOlof Johansson	init_timer(&mac->tx->clean_timer);
124461cec3bddc79373a246e2f8eb13e5acdc106f46aOlof Johansson	mac->tx->clean_timer.function = pasemi_mac_tx_timer;
124561cec3bddc79373a246e2f8eb13e5acdc106f46aOlof Johansson	mac->tx->clean_timer.data = (unsigned long)mac->tx;
124661cec3bddc79373a246e2f8eb13e5acdc106f46aOlof Johansson	mac->tx->clean_timer.expires = jiffies+HZ;
124761cec3bddc79373a246e2f8eb13e5acdc106f46aOlof Johansson	add_timer(&mac->tx->clean_timer);
124861cec3bddc79373a246e2f8eb13e5acdc106f46aOlof Johansson
1249f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	return 0;
1250f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1251f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johanssonout_rx_int:
125234c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	free_irq(mac->tx->chan.irq, mac->tx);
1253f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johanssonout_tx_int:
1254bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger	napi_disable(&mac->napi);
1255f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	netif_stop_queue(dev);
125672b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johanssonout_tx_ring:
125772b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson	if (mac->tx)
125872b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson		pasemi_mac_free_tx_resources(mac);
125972b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson	pasemi_mac_free_rx_resources(mac);
1260f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johanssonout_rx_resources:
1261f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1262f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	return ret;
1263f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson}
1264f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1265f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson#define MAX_RETRIES 5000
1266f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1267ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johanssonstatic void pasemi_mac_pause_txchan(struct pasemi_mac *mac)
1268ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson{
1269ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	unsigned int sta, retries;
1270ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	int txch = tx_ring(mac)->chan.chno;
1271ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson
1272ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	write_dma_reg(PAS_DMA_TXCHAN_TCMDSTA(txch),
1273ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson		      PAS_DMA_TXCHAN_TCMDSTA_ST);
1274ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson
1275ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	for (retries = 0; retries < MAX_RETRIES; retries++) {
1276ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson		sta = read_dma_reg(PAS_DMA_TXCHAN_TCMDSTA(txch));
1277ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson		if (!(sta & PAS_DMA_TXCHAN_TCMDSTA_ACT))
1278ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson			break;
1279ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson		cond_resched();
1280ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	}
1281ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson
1282ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	if (sta & PAS_DMA_TXCHAN_TCMDSTA_ACT)
1283ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson		dev_err(&mac->dma_pdev->dev,
1284ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson			"Failed to stop tx channel, tcmdsta %08x\n", sta);
1285ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson
1286ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	write_dma_reg(PAS_DMA_TXCHAN_TCMDSTA(txch), 0);
1287ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson}
1288ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson
1289ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johanssonstatic void pasemi_mac_pause_rxchan(struct pasemi_mac *mac)
1290ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson{
1291ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	unsigned int sta, retries;
1292ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	int rxch = rx_ring(mac)->chan.chno;
1293ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson
1294ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	write_dma_reg(PAS_DMA_RXCHAN_CCMDSTA(rxch),
1295ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson		      PAS_DMA_RXCHAN_CCMDSTA_ST);
1296ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	for (retries = 0; retries < MAX_RETRIES; retries++) {
1297ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson		sta = read_dma_reg(PAS_DMA_RXCHAN_CCMDSTA(rxch));
1298ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson		if (!(sta & PAS_DMA_RXCHAN_CCMDSTA_ACT))
1299ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson			break;
1300ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson		cond_resched();
1301ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	}
1302ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson
1303ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	if (sta & PAS_DMA_RXCHAN_CCMDSTA_ACT)
1304ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson		dev_err(&mac->dma_pdev->dev,
1305ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson			"Failed to stop rx channel, ccmdsta 08%x\n", sta);
1306ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	write_dma_reg(PAS_DMA_RXCHAN_CCMDSTA(rxch), 0);
1307ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson}
1308ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson
1309ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johanssonstatic void pasemi_mac_pause_rxint(struct pasemi_mac *mac)
1310ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson{
1311ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	unsigned int sta, retries;
1312ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson
1313ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	write_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if),
1314ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson		      PAS_DMA_RXINT_RCMDSTA_ST);
1315ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	for (retries = 0; retries < MAX_RETRIES; retries++) {
1316ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson		sta = read_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if));
1317ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson		if (!(sta & PAS_DMA_RXINT_RCMDSTA_ACT))
1318ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson			break;
1319ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson		cond_resched();
1320ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	}
1321ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson
1322ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	if (sta & PAS_DMA_RXINT_RCMDSTA_ACT)
1323ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson		dev_err(&mac->dma_pdev->dev,
1324ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson			"Failed to stop rx interface, rcmdsta %08x\n", sta);
1325ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	write_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if), 0);
1326ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson}
1327ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson
1328f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johanssonstatic int pasemi_mac_close(struct net_device *dev)
1329f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson{
1330f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	struct pasemi_mac *mac = netdev_priv(dev);
13319e81d331f2ec65695e4366ce592e14f9700bae8bOlof Johansson	unsigned int sta;
13328d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	int rxch, txch, i;
133334c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson
133434c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	rxch = rx_ring(mac)->chan.chno;
133534c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	txch = tx_ring(mac)->chan.chno;
1336f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1337bb6e9590792834f905a92e439a083254649c985cOlof Johansson	if (mac->phydev) {
1338bb6e9590792834f905a92e439a083254649c985cOlof Johansson		phy_stop(mac->phydev);
1339bb6e9590792834f905a92e439a083254649c985cOlof Johansson		phy_disconnect(mac->phydev);
1340bb6e9590792834f905a92e439a083254649c985cOlof Johansson	}
1341bb6e9590792834f905a92e439a083254649c985cOlof Johansson
134261cec3bddc79373a246e2f8eb13e5acdc106f46aOlof Johansson	del_timer_sync(&mac->tx->clean_timer);
134361cec3bddc79373a246e2f8eb13e5acdc106f46aOlof Johansson
1344f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	netif_stop_queue(dev);
1345bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger	napi_disable(&mac->napi);
1346f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
134734c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	sta = read_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if));
13489e81d331f2ec65695e4366ce592e14f9700bae8bOlof Johansson	if (sta & (PAS_DMA_RXINT_RCMDSTA_BP |
13499e81d331f2ec65695e4366ce592e14f9700bae8bOlof Johansson		      PAS_DMA_RXINT_RCMDSTA_OO |
13509e81d331f2ec65695e4366ce592e14f9700bae8bOlof Johansson		      PAS_DMA_RXINT_RCMDSTA_BT))
13519e81d331f2ec65695e4366ce592e14f9700bae8bOlof Johansson		printk(KERN_DEBUG "pasemi_mac: rcmdsta error: 0x%08x\n", sta);
13529e81d331f2ec65695e4366ce592e14f9700bae8bOlof Johansson
135334c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	sta = read_dma_reg(PAS_DMA_RXCHAN_CCMDSTA(rxch));
13549e81d331f2ec65695e4366ce592e14f9700bae8bOlof Johansson	if (sta & (PAS_DMA_RXCHAN_CCMDSTA_DU |
13559e81d331f2ec65695e4366ce592e14f9700bae8bOlof Johansson		     PAS_DMA_RXCHAN_CCMDSTA_OD |
13569e81d331f2ec65695e4366ce592e14f9700bae8bOlof Johansson		     PAS_DMA_RXCHAN_CCMDSTA_FD |
13579e81d331f2ec65695e4366ce592e14f9700bae8bOlof Johansson		     PAS_DMA_RXCHAN_CCMDSTA_DT))
13589e81d331f2ec65695e4366ce592e14f9700bae8bOlof Johansson		printk(KERN_DEBUG "pasemi_mac: ccmdsta error: 0x%08x\n", sta);
13599e81d331f2ec65695e4366ce592e14f9700bae8bOlof Johansson
136034c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	sta = read_dma_reg(PAS_DMA_TXCHAN_TCMDSTA(txch));
136172b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson	if (sta & (PAS_DMA_TXCHAN_TCMDSTA_SZ | PAS_DMA_TXCHAN_TCMDSTA_DB |
136272b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson		      PAS_DMA_TXCHAN_TCMDSTA_DE | PAS_DMA_TXCHAN_TCMDSTA_DA))
13639e81d331f2ec65695e4366ce592e14f9700bae8bOlof Johansson		printk(KERN_DEBUG "pasemi_mac: tcmdsta error: 0x%08x\n", sta);
13649e81d331f2ec65695e4366ce592e14f9700bae8bOlof Johansson
1365f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	/* Clean out any pending buffers */
136672b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson	pasemi_mac_clean_tx(tx_ring(mac));
136772b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson	pasemi_mac_clean_rx(rx_ring(mac), RX_RING_SIZE);
1368f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1369ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	pasemi_mac_pause_txchan(mac);
1370ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	pasemi_mac_pause_rxint(mac);
1371ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	pasemi_mac_pause_rxchan(mac);
13721145d954a51df9362d7eaa2c68405fc226418f34Olof Johansson	pasemi_mac_intf_disable(mac);
1373f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
137434c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	free_irq(mac->tx->chan.irq, mac->tx);
137534c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	free_irq(mac->rx->chan.irq, mac->rx);
1376f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
13771724ac2ef1caf5b4f764d4b86a85d552a7d7c8fbOlof Johansson	for (i = 0; i < mac->num_cs; i++) {
13788d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson		pasemi_mac_free_csring(mac->cs[i]);
13791724ac2ef1caf5b4f764d4b86a85d552a7d7c8fbOlof Johansson		mac->cs[i] = NULL;
13801724ac2ef1caf5b4f764d4b86a85d552a7d7c8fbOlof Johansson	}
13811724ac2ef1caf5b4f764d4b86a85d552a7d7c8fbOlof Johansson
13821724ac2ef1caf5b4f764d4b86a85d552a7d7c8fbOlof Johansson	mac->num_cs = 0;
13838d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson
1384f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	/* Free resources */
138572b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson	pasemi_mac_free_rx_resources(mac);
138672b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson	pasemi_mac_free_tx_resources(mac);
1387f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1388f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	return 0;
1389f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson}
1390f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
13918d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johanssonstatic void pasemi_mac_queue_csdesc(const struct sk_buff *skb,
13928d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson				    const dma_addr_t *map,
13938d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson				    const unsigned int *map_size,
13948d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson				    struct pasemi_mac_txring *txring,
13958d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson				    struct pasemi_mac_csring *csring)
13968d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson{
13978d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	u64 fund;
13988d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	dma_addr_t cs_dest;
13998d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	const int nh_off = skb_network_offset(skb);
14008d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	const int nh_len = skb_network_header_len(skb);
14018d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	const int nfrags = skb_shinfo(skb)->nr_frags;
14028d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	int cs_size, i, fill, hdr, cpyhdr, evt;
14038d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	dma_addr_t csdma;
14048d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson
14058d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	fund = XCT_FUN_ST | XCT_FUN_RR_8BRES |
14068d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	       XCT_FUN_O | XCT_FUN_FUN(csring->fun) |
14078d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	       XCT_FUN_CRM_SIG | XCT_FUN_LLEN(skb->len - nh_off) |
14088d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	       XCT_FUN_SHL(nh_len >> 2) | XCT_FUN_SE;
14098d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson
14108d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	switch (ip_hdr(skb)->protocol) {
14118d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	case IPPROTO_TCP:
14128d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson		fund |= XCT_FUN_SIG_TCP4;
14138d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson		/* TCP checksum is 16 bytes into the header */
14148d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson		cs_dest = map[0] + skb_transport_offset(skb) + 16;
14158d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson		break;
14168d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	case IPPROTO_UDP:
14178d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson		fund |= XCT_FUN_SIG_UDP4;
14188d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson		/* UDP checksum is 6 bytes into the header */
14198d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson		cs_dest = map[0] + skb_transport_offset(skb) + 6;
14208d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson		break;
14218d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	default:
14228d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson		BUG();
14238d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	}
14248d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson
14258d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	/* Do the checksum offloaded */
14268d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	fill = csring->next_to_fill;
14278d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	hdr = fill;
14288d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson
14298d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	CS_DESC(csring, fill++) = fund;
14308d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	/* Room for 8BRES. Checksum result is really 2 bytes into it */
14318d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	csdma = csring->chan.ring_dma + (fill & (CS_RING_SIZE-1)) * 8 + 2;
14328d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	CS_DESC(csring, fill++) = 0;
14338d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson
14348d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	CS_DESC(csring, fill) = XCT_PTR_LEN(map_size[0]-nh_off) | XCT_PTR_ADDR(map[0]+nh_off);
14358d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	for (i = 1; i <= nfrags; i++)
14368d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson		CS_DESC(csring, fill+i) = XCT_PTR_LEN(map_size[i]) | XCT_PTR_ADDR(map[i]);
14378d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson
14388d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	fill += i;
14398d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	if (fill & 1)
14408d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson		fill++;
14418d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson
14428d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	/* Copy the result into the TCP packet */
14438d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	cpyhdr = fill;
14448d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	CS_DESC(csring, fill++) = XCT_FUN_O | XCT_FUN_FUN(csring->fun) |
14458d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson				  XCT_FUN_LLEN(2) | XCT_FUN_SE;
14468d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	CS_DESC(csring, fill++) = XCT_PTR_LEN(2) | XCT_PTR_ADDR(cs_dest) | XCT_PTR_T;
14478d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	CS_DESC(csring, fill++) = XCT_PTR_LEN(2) | XCT_PTR_ADDR(csdma);
14488d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	fill++;
14498d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson
14508d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	evt = !csring->last_event;
14518d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	csring->last_event = evt;
14528d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson
14538d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	/* Event handshaking with MAC TX */
14548d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	CS_DESC(csring, fill++) = CTRL_CMD_T | CTRL_CMD_META_EVT | CTRL_CMD_O |
14558d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson				  CTRL_CMD_ETYPE_SET | CTRL_CMD_REG(csring->events[evt]);
14568d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	CS_DESC(csring, fill++) = 0;
14578d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	CS_DESC(csring, fill++) = CTRL_CMD_T | CTRL_CMD_META_EVT | CTRL_CMD_O |
14588d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson				  CTRL_CMD_ETYPE_WCLR | CTRL_CMD_REG(csring->events[!evt]);
14598d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	CS_DESC(csring, fill++) = 0;
14608d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	csring->next_to_fill = fill & (CS_RING_SIZE-1);
14618d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson
14628d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	cs_size = fill - hdr;
14638d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	write_dma_reg(PAS_DMA_TXCHAN_INCR(csring->chan.chno), (cs_size) >> 1);
14648d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson
14658d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	/* TX-side event handshaking */
14668d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	fill = txring->next_to_fill;
14678d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	TX_DESC(txring, fill++) = CTRL_CMD_T | CTRL_CMD_META_EVT | CTRL_CMD_O |
14688d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson				  CTRL_CMD_ETYPE_WSET | CTRL_CMD_REG(csring->events[evt]);
14698d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	TX_DESC(txring, fill++) = 0;
14708d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	TX_DESC(txring, fill++) = CTRL_CMD_T | CTRL_CMD_META_EVT | CTRL_CMD_O |
14718d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson				  CTRL_CMD_ETYPE_CLR | CTRL_CMD_REG(csring->events[!evt]);
14728d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	TX_DESC(txring, fill++) = 0;
14738d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	txring->next_to_fill = fill;
14748d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson
14758d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	write_dma_reg(PAS_DMA_TXCHAN_INCR(txring->chan.chno), 2);
14768d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson}
14778d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson
1478f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johanssonstatic int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev)
1479f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson{
14808d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	struct pasemi_mac * const mac = netdev_priv(dev);
14818d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	struct pasemi_mac_txring * const txring = tx_ring(mac);
14828d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	struct pasemi_mac_csring *csring;
14838d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	u64 dflags = 0;
14848d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	u64 mactx;
1485ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson	dma_addr_t map[MAX_SKB_FRAGS+1];
1486ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson	unsigned int map_size[MAX_SKB_FRAGS+1];
1487ca7e235f5eb960d83b45cef4384b490672538cd9Olof Johansson	unsigned long flags;
1488ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson	int i, nfrags;
14895c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johansson	int fill;
14908d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	const int nh_off = skb_network_offset(skb);
14918d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	const int nh_len = skb_network_header_len(skb);
1492f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
14938d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	prefetch(&txring->ring_info);
1494d56f90a7c96da5187f0cdf07ee7434fe6aa78bbcArnaldo Carvalho de Melo
14958d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	dflags = XCT_MACTX_O | XCT_MACTX_ST | XCT_MACTX_CRC_PAD;
1496f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1497ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson	nfrags = skb_shinfo(skb)->nr_frags;
1498ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson
1499ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson	map[0] = pci_map_single(mac->dma_pdev, skb->data, skb_headlen(skb),
1500ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson				PCI_DMA_TODEVICE);
1501ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson	map_size[0] = skb_headlen(skb);
15028d8bb39b9eba32dd70e87fd5ad5c5dd4ba118e06FUJITA Tomonori	if (pci_dma_mapping_error(mac->dma_pdev, map[0]))
1503ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson		goto out_err_nolock;
1504ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson
1505ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson	for (i = 0; i < nfrags; i++) {
1506ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson		skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
1507f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
15084bb97cae662ea6e2a5aa5982d0b289a8c48d64c6Ian Campbell		map[i + 1] = skb_frag_dma_map(&mac->dma_pdev->dev, frag, 0,
15099e903e085262ffbf1fc44a17ac06058aca03524aEric Dumazet					      skb_frag_size(frag), DMA_TO_DEVICE);
15109e903e085262ffbf1fc44a17ac06058aca03524aEric Dumazet		map_size[i+1] = skb_frag_size(frag);
15115d6bcdfe38ce883946aebf751a64695471ce1ab5Ian Campbell		if (dma_mapping_error(&mac->dma_pdev->dev, map[i + 1])) {
1512ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson			nfrags = i;
1513ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson			goto out_err_nolock;
1514ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson		}
1515ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson	}
1516f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
15178d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	if (skb->ip_summed == CHECKSUM_PARTIAL && skb->len <= 1540) {
15188d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson		switch (ip_hdr(skb)->protocol) {
15198d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson		case IPPROTO_TCP:
15208d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson			dflags |= XCT_MACTX_CSUM_TCP;
15218d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson			dflags |= XCT_MACTX_IPH(nh_len >> 2);
15228d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson			dflags |= XCT_MACTX_IPO(nh_off);
15238d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson			break;
15248d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson		case IPPROTO_UDP:
15258d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson			dflags |= XCT_MACTX_CSUM_UDP;
15268d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson			dflags |= XCT_MACTX_IPH(nh_len >> 2);
15278d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson			dflags |= XCT_MACTX_IPO(nh_off);
15288d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson			break;
15298d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson		default:
15308d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson			WARN_ON(1);
15318d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson		}
15328d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	}
153326fcfa95aef980cab4ff1ea55979c30e772dd0ddOlof Johansson
15348d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	mactx = dflags | XCT_MACTX_LLEN(skb->len);
1535f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1536f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	spin_lock_irqsave(&txring->lock, flags);
1537f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1538ad5da10a64bdca1ed39b25946727a1ce2659f3d4Olof Johansson	/* Avoid stepping on the same cache line that the DMA controller
1539ad5da10a64bdca1ed39b25946727a1ce2659f3d4Olof Johansson	 * is currently about to send, so leave at least 8 words available.
1540ad5da10a64bdca1ed39b25946727a1ce2659f3d4Olof Johansson	 * Total free space needed is mactx + fragments + 8
1541ad5da10a64bdca1ed39b25946727a1ce2659f3d4Olof Johansson	 */
15428d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	if (RING_AVAIL(txring) < nfrags + 14) {
1543ad5da10a64bdca1ed39b25946727a1ce2659f3d4Olof Johansson		/* no room -- stop the queue and wait for tx intr */
1544ad5da10a64bdca1ed39b25946727a1ce2659f3d4Olof Johansson		netif_stop_queue(dev);
1545ad5da10a64bdca1ed39b25946727a1ce2659f3d4Olof Johansson		goto out_err;
1546f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	}
1547f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
15488d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	/* Queue up checksum + event descriptors, if needed */
15498d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	if (mac->num_cs && skb->ip_summed == CHECKSUM_PARTIAL && skb->len > 1540) {
15508d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson		csring = mac->cs[mac->last_cs];
15518d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson		mac->last_cs = (mac->last_cs + 1) % mac->num_cs;
15528d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson
15538d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson		pasemi_mac_queue_csdesc(skb, map, map_size, txring, csring);
15548d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	}
15558d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson
15568d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	fill = txring->next_to_fill;
15575c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johansson	TX_DESC(txring, fill) = mactx;
15587e9916e9ddf23cd08107ed1a7fac429eea619313Olof Johansson	TX_DESC_INFO(txring, fill).dma = nfrags;
15595c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johansson	fill++;
15605c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johansson	TX_DESC_INFO(txring, fill).skb = skb;
1561ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson	for (i = 0; i <= nfrags; i++) {
15625c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johansson		TX_DESC(txring, fill+i) =
156372b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson			XCT_PTR_LEN(map_size[i]) | XCT_PTR_ADDR(map[i]);
15645c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johansson		TX_DESC_INFO(txring, fill+i).dma = map[i];
1565ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson	}
1566ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson
1567ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson	/* We have to add an even number of 8-byte entries to the ring
1568ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson	 * even if the last one is unused. That means always an odd number
1569ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson	 * of pointers + one mactx descriptor.
1570ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson	 */
1571ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson	if (nfrags & 1)
1572ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson		nfrags++;
1573fc9e4d2a93dab4a995e2e75725577b9a60154cbcOlof Johansson
15745c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johansson	txring->next_to_fill = (fill + nfrags + 1) & (TX_RING_SIZE-1);
1575f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
157609f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik	dev->stats.tx_packets++;
157709f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik	dev->stats.tx_bytes += skb->len;
1578f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1579f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	spin_unlock_irqrestore(&txring->lock, flags);
1580f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
158134c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	write_dma_reg(PAS_DMA_TXCHAN_INCR(txring->chan.chno), (nfrags+2) >> 1);
1582f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1583f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	return NETDEV_TX_OK;
1584f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1585f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johanssonout_err:
1586f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	spin_unlock_irqrestore(&txring->lock, flags);
1587ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johanssonout_err_nolock:
1588ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson	while (nfrags--)
1589ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson		pci_unmap_single(mac->dma_pdev, map[nfrags], map_size[nfrags],
1590ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson				 PCI_DMA_TODEVICE);
1591ad3c20d1ab586884f1815c315e3f303a8b8a7d7dOlof Johansson
1592f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	return NETDEV_TX_BUSY;
1593f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson}
1594f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1595f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johanssonstatic void pasemi_mac_set_rx_mode(struct net_device *dev)
1596f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson{
15975c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johansson	const struct pasemi_mac *mac = netdev_priv(dev);
1598f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	unsigned int flags;
1599f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1600a85b94222d8b95e184941183f28b06b637cc4deeOlof Johansson	flags = read_mac_reg(mac, PAS_MAC_CFG_PCFG);
1601f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1602f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	/* Set promiscuous */
1603f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	if (dev->flags & IFF_PROMISC)
1604f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson		flags |= PAS_MAC_CFG_PCFG_PR;
1605f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	else
1606f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson		flags &= ~PAS_MAC_CFG_PCFG_PR;
1607f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1608a85b94222d8b95e184941183f28b06b637cc4deeOlof Johansson	write_mac_reg(mac, PAS_MAC_CFG_PCFG, flags);
1609f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson}
1610f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1611f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1612bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemmingerstatic int pasemi_mac_poll(struct napi_struct *napi, int budget)
1613f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson{
1614bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger	struct pasemi_mac *mac = container_of(napi, struct pasemi_mac, napi);
1615bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger	int pkts;
1616f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
161772b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson	pasemi_mac_clean_tx(tx_ring(mac));
161872b05b9940f00fbfd71a1cb8ea80eb2cc1f90255Olof Johansson	pkts = pasemi_mac_clean_rx(rx_ring(mac), budget);
1619bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger	if (pkts < budget) {
1620f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson		/* all done, no more packets present */
1621288379f050284087578b77e04f040b57db3db3f8Ben Hutchings		napi_complete(napi);
1622f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
16231b0335ea30bf85eecffd21be64b7653407d6259aOlof Johansson		pasemi_mac_restart_rx_intr(mac);
162461cec3bddc79373a246e2f8eb13e5acdc106f46aOlof Johansson		pasemi_mac_restart_tx_intr(mac);
1625f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	}
1626bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger	return pkts;
1627f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson}
1628f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
16296e62040c5533a385b90fcb2e33235ad7d351d3e0Nate Case#ifdef CONFIG_NET_POLL_CONTROLLER
16306e62040c5533a385b90fcb2e33235ad7d351d3e0Nate Case/*
16316e62040c5533a385b90fcb2e33235ad7d351d3e0Nate Case * Polling 'interrupt' - used by things like netconsole to send skbs
16326e62040c5533a385b90fcb2e33235ad7d351d3e0Nate Case * without having to re-enable interrupts. It's not called while
16336e62040c5533a385b90fcb2e33235ad7d351d3e0Nate Case * the interrupt routine is executing.
16346e62040c5533a385b90fcb2e33235ad7d351d3e0Nate Case */
16356e62040c5533a385b90fcb2e33235ad7d351d3e0Nate Casestatic void pasemi_mac_netpoll(struct net_device *dev)
16366e62040c5533a385b90fcb2e33235ad7d351d3e0Nate Case{
16376e62040c5533a385b90fcb2e33235ad7d351d3e0Nate Case	const struct pasemi_mac *mac = netdev_priv(dev);
16386e62040c5533a385b90fcb2e33235ad7d351d3e0Nate Case
16396e62040c5533a385b90fcb2e33235ad7d351d3e0Nate Case	disable_irq(mac->tx->chan.irq);
16406e62040c5533a385b90fcb2e33235ad7d351d3e0Nate Case	pasemi_mac_tx_intr(mac->tx->chan.irq, mac->tx);
16416e62040c5533a385b90fcb2e33235ad7d351d3e0Nate Case	enable_irq(mac->tx->chan.irq);
16426e62040c5533a385b90fcb2e33235ad7d351d3e0Nate Case
16436e62040c5533a385b90fcb2e33235ad7d351d3e0Nate Case	disable_irq(mac->rx->chan.irq);
16446e62040c5533a385b90fcb2e33235ad7d351d3e0Nate Case	pasemi_mac_rx_intr(mac->rx->chan.irq, mac->rx);
16456e62040c5533a385b90fcb2e33235ad7d351d3e0Nate Case	enable_irq(mac->rx->chan.irq);
16466e62040c5533a385b90fcb2e33235ad7d351d3e0Nate Case}
16476e62040c5533a385b90fcb2e33235ad7d351d3e0Nate Case#endif
16486e62040c5533a385b90fcb2e33235ad7d351d3e0Nate Case
1649ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johanssonstatic int pasemi_mac_change_mtu(struct net_device *dev, int new_mtu)
1650ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson{
1651ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	struct pasemi_mac *mac = netdev_priv(dev);
1652ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	unsigned int reg;
16538d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	unsigned int rcmdsta = 0;
1654ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	int running;
16558d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	int ret = 0;
1656ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson
1657ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	if (new_mtu < PE_MIN_MTU || new_mtu > PE_MAX_MTU)
1658ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson		return -EINVAL;
1659ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson
1660ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	running = netif_running(dev);
1661ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson
1662ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	if (running) {
1663ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson		/* Need to stop the interface, clean out all already
1664ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson		 * received buffers, free all unused buffers on the RX
1665ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson		 * interface ring, then finally re-fill the rx ring with
1666ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson		 * the new-size buffers and restart.
1667ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson		 */
1668ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson
1669ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson		napi_disable(&mac->napi);
1670ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson		netif_tx_disable(dev);
1671ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson		pasemi_mac_intf_disable(mac);
1672ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson
1673ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson		rcmdsta = read_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if));
1674ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson		pasemi_mac_pause_rxint(mac);
1675ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson		pasemi_mac_clean_rx(rx_ring(mac), RX_RING_SIZE);
1676ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson		pasemi_mac_free_rx_buffers(mac);
16778d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson
16788d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	}
16798d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson
16808d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	/* Setup checksum channels if large MTU and none already allocated */
16818d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	if (new_mtu > 1500 && !mac->num_cs) {
16828d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson		pasemi_mac_setup_csrings(mac);
16838d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson		if (!mac->num_cs) {
16848d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson			ret = -ENOMEM;
16858d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson			goto out;
16868d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson		}
1687ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	}
1688ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson
1689ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	/* Change maxf, i.e. what size frames are accepted.
1690ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	 * Need room for ethernet header and CRC word
1691ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	 */
1692ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	reg = read_mac_reg(mac, PAS_MAC_CFG_MACCFG);
1693ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	reg &= ~PAS_MAC_CFG_MACCFG_MAXF_M;
1694ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	reg |= PAS_MAC_CFG_MACCFG_MAXF(new_mtu + ETH_HLEN + 4);
1695ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	write_mac_reg(mac, PAS_MAC_CFG_MACCFG, reg);
1696ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson
1697ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	dev->mtu = new_mtu;
1698ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	/* MTU + ETH_HLEN + VLAN_HLEN + 2 64B cachelines */
1699ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	mac->bufsz = new_mtu + ETH_HLEN + ETH_FCS_LEN + LOCAL_SKB_ALIGN + 128;
1700ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson
17018d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johanssonout:
1702ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	if (running) {
1703ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson		write_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if),
1704ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson			      rcmdsta | PAS_DMA_RXINT_RCMDSTA_EN);
1705ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson
1706ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson		rx_ring(mac)->next_to_fill = 0;
1707ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson		pasemi_mac_replenish_rx_ring(dev, RX_RING_SIZE-1);
1708ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson
1709ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson		napi_enable(&mac->napi);
1710ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson		netif_start_queue(dev);
1711ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson		pasemi_mac_intf_enable(mac);
1712ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	}
1713ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson
17148d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41Olof Johansson	return ret;
1715ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson}
1716ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson
17179e0ac841f42df4e7acdab7dc1620de0933ed56d7Alexander Beregalovstatic const struct net_device_ops pasemi_netdev_ops = {
17189e0ac841f42df4e7acdab7dc1620de0933ed56d7Alexander Beregalov	.ndo_open		= pasemi_mac_open,
17199e0ac841f42df4e7acdab7dc1620de0933ed56d7Alexander Beregalov	.ndo_stop		= pasemi_mac_close,
17209e0ac841f42df4e7acdab7dc1620de0933ed56d7Alexander Beregalov	.ndo_start_xmit		= pasemi_mac_start_tx,
1721afc4b13df143122f99a0eb10bfefb216c2806de0Jiri Pirko	.ndo_set_rx_mode	= pasemi_mac_set_rx_mode,
17229e0ac841f42df4e7acdab7dc1620de0933ed56d7Alexander Beregalov	.ndo_set_mac_address	= pasemi_mac_set_mac_addr,
17239e0ac841f42df4e7acdab7dc1620de0933ed56d7Alexander Beregalov	.ndo_change_mtu		= pasemi_mac_change_mtu,
17249e0ac841f42df4e7acdab7dc1620de0933ed56d7Alexander Beregalov	.ndo_validate_addr	= eth_validate_addr,
17259e0ac841f42df4e7acdab7dc1620de0933ed56d7Alexander Beregalov#ifdef CONFIG_NET_POLL_CONTROLLER
17269e0ac841f42df4e7acdab7dc1620de0933ed56d7Alexander Beregalov	.ndo_poll_controller	= pasemi_mac_netpoll,
17279e0ac841f42df4e7acdab7dc1620de0933ed56d7Alexander Beregalov#endif
17289e0ac841f42df4e7acdab7dc1620de0933ed56d7Alexander Beregalov};
17299e0ac841f42df4e7acdab7dc1620de0933ed56d7Alexander Beregalov
1730f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johanssonstatic int __devinit
1731f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johanssonpasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
1732f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson{
1733f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	struct net_device *dev;
1734f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	struct pasemi_mac *mac;
173515b8e19131486856373592e45793a79aefb6fbe7roel kluin	int err, ret;
1736f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1737f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	err = pci_enable_device(pdev);
1738f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	if (err)
1739f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson		return err;
1740f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1741f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	dev = alloc_etherdev(sizeof(struct pasemi_mac));
1742f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	if (dev == NULL) {
1743f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson		err = -ENOMEM;
1744f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson		goto out_disable_device;
1745f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	}
1746f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1747f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	pci_set_drvdata(pdev, dev);
1748f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	SET_NETDEV_DEV(dev, &pdev->dev);
1749f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1750f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	mac = netdev_priv(dev);
1751f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1752f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	mac->pdev = pdev;
1753f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	mac->netdev = dev;
1754f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1755bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger	netif_napi_add(dev, &mac->napi, pasemi_mac_poll, 64);
1756bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger
17575c15332bed4c59fff6423f08ef6bd6894af38a99Olof Johansson	dev->features = NETIF_F_IP_CSUM | NETIF_F_LLTX | NETIF_F_SG |
1758251567848f2f446f4356f969329a8188faf1fe90Olof Johansson			NETIF_F_HIGHDMA | NETIF_F_GSO;
1759bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger
176028ae79f531014bb3ad95b6efa0e0603069087bc5Olof Johansson	mac->lro_mgr.max_aggr = LRO_MAX_AGGR;
176128ae79f531014bb3ad95b6efa0e0603069087bc5Olof Johansson	mac->lro_mgr.max_desc = MAX_LRO_DESCRIPTORS;
176228ae79f531014bb3ad95b6efa0e0603069087bc5Olof Johansson	mac->lro_mgr.lro_arr = mac->lro_desc;
176328ae79f531014bb3ad95b6efa0e0603069087bc5Olof Johansson	mac->lro_mgr.get_skb_header = get_skb_hdr;
176428ae79f531014bb3ad95b6efa0e0603069087bc5Olof Johansson	mac->lro_mgr.features = LRO_F_NAPI | LRO_F_EXTRACT_VLAN_ID;
176528ae79f531014bb3ad95b6efa0e0603069087bc5Olof Johansson	mac->lro_mgr.dev = mac->netdev;
176628ae79f531014bb3ad95b6efa0e0603069087bc5Olof Johansson	mac->lro_mgr.ip_summed = CHECKSUM_UNNECESSARY;
176728ae79f531014bb3ad95b6efa0e0603069087bc5Olof Johansson	mac->lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY;
176828ae79f531014bb3ad95b6efa0e0603069087bc5Olof Johansson
176928ae79f531014bb3ad95b6efa0e0603069087bc5Olof Johansson
177034c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	mac->dma_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa007, NULL);
177134c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	if (!mac->dma_pdev) {
177234c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson		dev_err(&mac->pdev->dev, "Can't find DMA Controller\n");
177334c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson		err = -ENODEV;
177434c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson		goto out;
177534c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	}
1776f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
177734c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	mac->iob_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa001, NULL);
177834c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	if (!mac->iob_pdev) {
177934c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson		dev_err(&mac->pdev->dev, "Can't find I/O Bridge\n");
178034c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson		err = -ENODEV;
178134c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson		goto out;
178234c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	}
178334c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson
178434c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	/* get mac addr from device tree */
178534c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	if (pasemi_get_mac_addr(mac) || !is_valid_ether_addr(mac->mac_addr)) {
178634c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson		err = -ENODEV;
178734c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson		goto out;
178834c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	}
178934c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	memcpy(dev->dev_addr, mac->mac_addr, sizeof(mac->mac_addr));
179034c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson
179115b8e19131486856373592e45793a79aefb6fbe7roel kluin	ret = mac_to_intf(mac);
179215b8e19131486856373592e45793a79aefb6fbe7roel kluin	if (ret < 0) {
179334c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson		dev_err(&mac->pdev->dev, "Can't map DMA interface\n");
179434c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson		err = -ENODEV;
179534c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson		goto out;
179634c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	}
179715b8e19131486856373592e45793a79aefb6fbe7roel kluin	mac->dma_if = ret;
1798f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1799f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	switch (pdev->device) {
1800f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	case 0xa005:
1801f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson		mac->type = MAC_TYPE_GMAC;
1802f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson		break;
1803f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	case 0xa006:
1804f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson		mac->type = MAC_TYPE_XAUI;
1805f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson		break;
1806f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	default:
1807f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson		err = -ENODEV;
1808f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson		goto out;
1809f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	}
1810f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
18119e0ac841f42df4e7acdab7dc1620de0933ed56d7Alexander Beregalov	dev->netdev_ops = &pasemi_netdev_ops;
1812ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	dev->mtu = PE_DEF_MTU;
1813ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	/* 1500 MTU + ETH_HLEN + VLAN_HLEN + 2 64B cachelines */
1814ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson	mac->bufsz = dev->mtu + ETH_HLEN + ETH_FCS_LEN + LOCAL_SKB_ALIGN + 128;
1815ef1ea0b424d09452b27f5cb1a0c108b645cb25e0Olof Johansson
1816e37c772e36a7943b2e0bd8f48312e78474c0df15Olof Johansson	dev->ethtool_ops = &pasemi_mac_ethtool_ops;
1817f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1818b6e05a1b67a4b2e122d78a3f0b7ec7c779bd903cOlof Johansson	if (err)
1819b6e05a1b67a4b2e122d78a3f0b7ec7c779bd903cOlof Johansson		goto out;
1820f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1821ceb51361370c003e13f782edb7171a8383e5c849Olof Johansson	mac->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE);
1822ceb51361370c003e13f782edb7171a8383e5c849Olof Johansson
1823bb6e9590792834f905a92e439a083254649c985cOlof Johansson	/* Enable most messages by default */
1824bb6e9590792834f905a92e439a083254649c985cOlof Johansson	mac->msg_enable = (NETIF_MSG_IFUP << 1 ) - 1;
1825bb6e9590792834f905a92e439a083254649c985cOlof Johansson
1826f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	err = register_netdev(dev);
1827f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1828f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	if (err) {
1829f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson		dev_err(&mac->pdev->dev, "register_netdev failed with error %d\n",
1830f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson			err);
1831f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson		goto out;
183269c29d89185dc1de7224f5f98588ddc061f1fad2Olof Johansson	} else if netif_msg_probe(mac)
1833e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg		printk(KERN_INFO "%s: PA Semi %s: intf %d, hw addr %pM\n",
1834f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson		       dev->name, mac->type == MAC_TYPE_GMAC ? "GMAC" : "XAUI",
1835e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg		       mac->dma_if, dev->dev_addr);
1836f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1837f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	return err;
1838f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1839f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johanssonout:
1840b6e05a1b67a4b2e122d78a3f0b7ec7c779bd903cOlof Johansson	if (mac->iob_pdev)
1841b6e05a1b67a4b2e122d78a3f0b7ec7c779bd903cOlof Johansson		pci_dev_put(mac->iob_pdev);
1842b6e05a1b67a4b2e122d78a3f0b7ec7c779bd903cOlof Johansson	if (mac->dma_pdev)
1843b6e05a1b67a4b2e122d78a3f0b7ec7c779bd903cOlof Johansson		pci_dev_put(mac->dma_pdev);
1844b6e05a1b67a4b2e122d78a3f0b7ec7c779bd903cOlof Johansson
1845f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	free_netdev(dev);
1846f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johanssonout_disable_device:
1847f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	pci_disable_device(pdev);
1848f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	return err;
1849f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1850f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson}
1851f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1852f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johanssonstatic void __devexit pasemi_mac_remove(struct pci_dev *pdev)
1853f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson{
1854f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	struct net_device *netdev = pci_get_drvdata(pdev);
1855f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	struct pasemi_mac *mac;
1856f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1857f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	if (!netdev)
1858f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson		return;
1859f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1860f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	mac = netdev_priv(netdev);
1861f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1862f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	unregister_netdev(netdev);
1863f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1864f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	pci_disable_device(pdev);
1865f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	pci_dev_put(mac->dma_pdev);
1866f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	pci_dev_put(mac->iob_pdev);
1867f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
186834c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	pasemi_dma_free_chan(&mac->tx->chan);
186934c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	pasemi_dma_free_chan(&mac->rx->chan);
1870b6e05a1b67a4b2e122d78a3f0b7ec7c779bd903cOlof Johansson
1871f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	pci_set_drvdata(pdev, NULL);
1872f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	free_netdev(netdev);
1873f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson}
1874f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1875a3aa18842a5303fc28fcc4d57dbd16618bd830a0Alexey Dobriyanstatic DEFINE_PCI_DEVICE_TABLE(pasemi_mac_pci_tbl) = {
1876f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	{ PCI_DEVICE(PCI_VENDOR_ID_PASEMI, 0xa005) },
1877f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	{ PCI_DEVICE(PCI_VENDOR_ID_PASEMI, 0xa006) },
1878fd17825480b2de3076727c677f8e257623705963olof@lixom.net	{ },
1879f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson};
1880f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1881f5cd7872768d5856b1b409a33f516e5ac7798f75Olof JohanssonMODULE_DEVICE_TABLE(pci, pasemi_mac_pci_tbl);
1882f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1883f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johanssonstatic struct pci_driver pasemi_mac_driver = {
1884f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	.name		= "pasemi_mac",
1885f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	.id_table	= pasemi_mac_pci_tbl,
1886f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	.probe		= pasemi_mac_probe,
1887f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	.remove		= __devexit_p(pasemi_mac_remove),
1888f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson};
1889f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1890f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johanssonstatic void __exit pasemi_mac_cleanup_module(void)
1891f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson{
1892f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	pci_unregister_driver(&pasemi_mac_driver);
1893f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson}
1894f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1895f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johanssonint pasemi_mac_init_module(void)
1896f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson{
189734c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	int err;
189834c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson
189934c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	err = pasemi_dma_init();
190034c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson	if (err)
190134c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson		return err;
190234c20624ce541f8a7ff937f474af51f9044cedd7Olof Johansson
1903f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson	return pci_register_driver(&pasemi_mac_driver);
1904f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson}
1905f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johansson
1906f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johanssonmodule_init(pasemi_mac_init_module);
1907f5cd7872768d5856b1b409a33f516e5ac7798f75Olof Johanssonmodule_exit(pasemi_mac_cleanup_module);
1908