From 2e6fd648b6b87e6a2289c875c6067acc3bd88b3e Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Mon, 21 Sep 2015 11:24:26 +0200 Subject: mrf24j40: add device-tree support This patch adds devicetree support to mrf24j40 with proper devicetree compatible strings. Reviewed-by: Stefan Schmidt Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) (limited to 'MAINTAINERS') diff --git a/MAINTAINERS b/MAINTAINERS index 310da4295c70..6790ecc65e6b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6958,6 +6958,7 @@ M: Alan Ott L: linux-wpan@vger.kernel.org S: Maintained F: drivers/net/ieee802154/mrf24j40.c +F: Documentation/devicetree/bindings/net/ieee802154/mrf24j40.txt MSI LAPTOP SUPPORT M: "Lee, Chun-Yi" -- cgit v1.2.3 From 26c6d281688e8bb8154fa78c60e551d024f5d0b8 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 5 May 2015 10:06:03 -0700 Subject: arcnet: Move files out of include/linux These #include files don't need to be in the include/linux directory as they can be local to drivers/net/arcnet/ Move them and update the #include statements. Update the MAINTAINERS file pattern by deleting arcdevice from the NETWORKING block as arcnet is currently unmaintained. Signed-off-by: Joe Perches Signed-off-by: Michael Grzeschik --- MAINTAINERS | 1 - drivers/net/arcnet/arc-rawmode.c | 3 +- drivers/net/arcnet/arc-rimi.c | 3 +- drivers/net/arcnet/arcdevice.h | 346 ++++++++++++++++++++++++++++++++++++++ drivers/net/arcnet/arcnet.c | 3 +- drivers/net/arcnet/capmode.c | 3 +- drivers/net/arcnet/com20020-isa.c | 6 +- drivers/net/arcnet/com20020-pci.c | 6 +- drivers/net/arcnet/com20020.c | 6 +- drivers/net/arcnet/com20020.h | 145 ++++++++++++++++ drivers/net/arcnet/com20020_cs.c | 7 +- drivers/net/arcnet/com90io.c | 3 +- drivers/net/arcnet/com90xx.c | 3 +- drivers/net/arcnet/rfc1051.c | 3 +- drivers/net/arcnet/rfc1201.c | 3 +- include/linux/arcdevice.h | 346 -------------------------------------- include/linux/com20020.h | 145 ---------------- 17 files changed, 519 insertions(+), 513 deletions(-) create mode 100644 drivers/net/arcnet/arcdevice.h create mode 100644 drivers/net/arcnet/com20020.h delete mode 100644 include/linux/arcdevice.h delete mode 100644 include/linux/com20020.h (limited to 'MAINTAINERS') diff --git a/MAINTAINERS b/MAINTAINERS index 310da4295c70..c978a257f4aa 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7292,7 +7292,6 @@ S: Odd Fixes F: drivers/net/ F: include/linux/if_* F: include/linux/netdevice.h -F: include/linux/arcdevice.h F: include/linux/etherdevice.h F: include/linux/fcdevice.h F: include/linux/fddidevice.h diff --git a/drivers/net/arcnet/arc-rawmode.c b/drivers/net/arcnet/arc-rawmode.c index 59b3083c19f9..35a747a7329e 100644 --- a/drivers/net/arcnet/arc-rawmode.c +++ b/drivers/net/arcnet/arc-rawmode.c @@ -33,7 +33,8 @@ #include #include #include -#include + +#include "arcdevice.h" static void rx(struct net_device *dev, int bufnum, struct archdr *pkthdr, int length); diff --git a/drivers/net/arcnet/arc-rimi.c b/drivers/net/arcnet/arc-rimi.c index 8fa5eb43f308..37406fffc001 100644 --- a/drivers/net/arcnet/arc-rimi.c +++ b/drivers/net/arcnet/arc-rimi.c @@ -37,7 +37,8 @@ #include #include #include -#include + +#include "arcdevice.h" /* Internal function declarations */ diff --git a/drivers/net/arcnet/arcdevice.h b/drivers/net/arcnet/arcdevice.h new file mode 100644 index 000000000000..9ca135d0f114 --- /dev/null +++ b/drivers/net/arcnet/arcdevice.h @@ -0,0 +1,346 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. NET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Definitions used by the ARCnet driver. + * + * Authors: Avery Pennarun and David Woodhouse + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ +#ifndef _LINUX_ARCDEVICE_H +#define _LINUX_ARCDEVICE_H + +#include +#include + +#ifdef __KERNEL__ +#include + +/* + * RECON_THRESHOLD is the maximum number of RECON messages to receive + * within one minute before printing a "cabling problem" warning. The + * default value should be fine. + * + * After that, a "cabling restored" message will be printed on the next IRQ + * if no RECON messages have been received for 10 seconds. + * + * Do not define RECON_THRESHOLD at all if you want to disable this feature. + */ +#define RECON_THRESHOLD 30 + +/* + * Define this to the minimum "timeout" value. If a transmit takes longer + * than TX_TIMEOUT jiffies, Linux will abort the TX and retry. On a large + * network, or one with heavy network traffic, this timeout may need to be + * increased. The larger it is, though, the longer it will be between + * necessary transmits - don't set this too high. + */ +#define TX_TIMEOUT (HZ * 200 / 1000) + +/* Display warnings about the driver being an ALPHA version. */ +#undef ALPHA_WARNING + +/* + * Debugging bitflags: each option can be enabled individually. + * + * Note: only debug flags included in the ARCNET_DEBUG_MAX define will + * actually be available. GCC will (at least, GCC 2.7.0 will) notice + * lines using a BUGLVL not in ARCNET_DEBUG_MAX and automatically optimize + * them out. + */ +#define D_NORMAL 1 /* important operational info */ +#define D_EXTRA 2 /* useful, but non-vital information */ +#define D_INIT 4 /* show init/probe messages */ +#define D_INIT_REASONS 8 /* show reasons for discarding probes */ +#define D_RECON 32 /* print a message whenever token is lost */ +#define D_PROTO 64 /* debug auto-protocol support */ +/* debug levels below give LOTS of output during normal operation! */ +#define D_DURING 128 /* trace operations (including irq's) */ +#define D_TX 256 /* show tx packets */ +#define D_RX 512 /* show rx packets */ +#define D_SKB 1024 /* show skb's */ +#define D_SKB_SIZE 2048 /* show skb sizes */ +#define D_TIMING 4096 /* show time needed to copy buffers to card */ +#define D_DEBUG 8192 /* Very detailed debug line for line */ + +#ifndef ARCNET_DEBUG_MAX +#define ARCNET_DEBUG_MAX (127) /* change to ~0 if you want detailed debugging */ +#endif + +#ifndef ARCNET_DEBUG +#define ARCNET_DEBUG (D_NORMAL | D_EXTRA) +#endif +extern int arcnet_debug; + +#define BUGLVL(x) ((x) & ARCNET_DEBUG_MAX & arcnet_debug) + +/* macros to simplify debug checking */ +#define arc_printk(x, dev, fmt, ...) \ +do { \ + if (BUGLVL(x)) { \ + if ((x) == D_NORMAL) \ + netdev_warn(dev, fmt, ##__VA_ARGS__); \ + else if ((x) < D_DURING) \ + netdev_info(dev, fmt, ##__VA_ARGS__); \ + else \ + netdev_dbg(dev, fmt, ##__VA_ARGS__); \ + } \ +} while (0) + +#define arc_cont(x, fmt, ...) \ +do { \ + if (BUGLVL(x)) \ + pr_cont(fmt, ##__VA_ARGS__); \ +} while (0) + +/* see how long a function call takes to run, expressed in CPU cycles */ +#define TIME(dev, name, bytes, call) \ +do { \ + if (BUGLVL(D_TIMING)) { \ + unsigned long _x, _y; \ + _x = get_cycles(); \ + call; \ + _y = get_cycles(); \ + arc_printk(D_TIMING, dev, \ + "%s: %d bytes in %lu cycles == %lu Kbytes/100Mcycle\n", \ + name, bytes, _y - _x, \ + 100000000 / 1024 * bytes / (_y - _x + 1)); \ + } else { \ + call; \ + } \ +} while (0) + +/* + * Time needed to reset the card - in ms (milliseconds). This works on my + * SMC PC100. I can't find a reference that tells me just how long I + * should wait. + */ +#define RESETtime (300) + +/* + * These are the max/min lengths of packet payload, not including the + * arc_hardware header, but definitely including the soft header. + * + * Note: packet sizes 254, 255, 256 are impossible because of the way + * ARCnet registers work That's why RFC1201 defines "exception" packets. + * In non-RFC1201 protocols, we have to just tack some extra bytes on the + * end. + */ +#define MTU 253 /* normal packet max size */ +#define MinTU 257 /* extended packet min size */ +#define XMTU 508 /* extended packet max size */ + +/* status/interrupt mask bit fields */ +#define TXFREEflag 0x01 /* transmitter available */ +#define TXACKflag 0x02 /* transmitted msg. ackd */ +#define RECONflag 0x04 /* network reconfigured */ +#define TESTflag 0x08 /* test flag */ +#define EXCNAKflag 0x08 /* excesive nak flag */ +#define RESETflag 0x10 /* power-on-reset */ +#define RES1flag 0x20 /* reserved - usually set by jumper */ +#define RES2flag 0x40 /* reserved - usually set by jumper */ +#define NORXflag 0x80 /* receiver inhibited */ + +/* Flags used for IO-mapped memory operations */ +#define AUTOINCflag 0x40 /* Increase location with each access */ +#define IOMAPflag 0x02 /* (for 90xx) Use IO mapped memory, not mmap */ +#define ENABLE16flag 0x80 /* (for 90xx) Enable 16-bit mode */ + +/* in the command register, the following bits have these meanings: + * 0-2 command + * 3-4 page number (for enable rcv/xmt command) + * 7 receive broadcasts + */ +#define NOTXcmd 0x01 /* disable transmitter */ +#define NORXcmd 0x02 /* disable receiver */ +#define TXcmd 0x03 /* enable transmitter */ +#define RXcmd 0x04 /* enable receiver */ +#define CONFIGcmd 0x05 /* define configuration */ +#define CFLAGScmd 0x06 /* clear flags */ +#define TESTcmd 0x07 /* load test flags */ + +/* flags for "clear flags" command */ +#define RESETclear 0x08 /* power-on-reset */ +#define CONFIGclear 0x10 /* system reconfigured */ + +#define EXCNAKclear 0x0E /* Clear and acknowledge the excive nak bit */ + +/* flags for "load test flags" command */ +#define TESTload 0x08 /* test flag (diagnostic) */ + +/* byte deposited into first address of buffers on reset */ +#define TESTvalue 0321 /* that's octal for 0xD1 :) */ + +/* for "enable receiver" command */ +#define RXbcasts 0x80 /* receive broadcasts */ + +/* flags for "define configuration" command */ +#define NORMALconf 0x00 /* 1-249 byte packets */ +#define EXTconf 0x08 /* 250-504 byte packets */ + +/* card feature flags, set during auto-detection. + * (currently only used by com20020pci) + */ +#define ARC_IS_5MBIT 1 /* card default speed is 5MBit */ +#define ARC_CAN_10MBIT 2 /* card uses COM20022, supporting 10MBit, + but default is 2.5MBit. */ + +/* information needed to define an encapsulation driver */ +struct ArcProto { + char suffix; /* a for RFC1201, e for ether-encap, etc. */ + int mtu; /* largest possible packet */ + int is_ip; /* This is a ip plugin - not a raw thing */ + + void (*rx)(struct net_device *dev, int bufnum, + struct archdr *pkthdr, int length); + int (*build_header)(struct sk_buff *skb, struct net_device *dev, + unsigned short ethproto, uint8_t daddr); + + /* these functions return '1' if the skb can now be freed */ + int (*prepare_tx)(struct net_device *dev, struct archdr *pkt, + int length, int bufnum); + int (*continue_tx)(struct net_device *dev, int bufnum); + int (*ack_tx)(struct net_device *dev, int acked); +}; + +extern struct ArcProto *arc_proto_map[256], *arc_proto_default, + *arc_bcast_proto, *arc_raw_proto; + +/* + * "Incoming" is information needed for each address that could be sending + * to us. Mostly for partially-received split packets. + */ +struct Incoming { + struct sk_buff *skb; /* packet data buffer */ + __be16 sequence; /* sequence number of assembly */ + uint8_t lastpacket, /* number of last packet (from 1) */ + numpackets; /* number of packets in split */ +}; + +/* only needed for RFC1201 */ +struct Outgoing { + struct ArcProto *proto; /* protocol driver that owns this: + * if NULL, no packet is pending. + */ + struct sk_buff *skb; /* buffer from upper levels */ + struct archdr *pkt; /* a pointer into the skb */ + uint16_t length, /* bytes total */ + dataleft, /* bytes left */ + segnum, /* segment being sent */ + numsegs; /* number of segments */ +}; + +struct arcnet_local { + uint8_t config, /* current value of CONFIG register */ + timeout, /* Extended timeout for COM20020 */ + backplane, /* Backplane flag for COM20020 */ + clockp, /* COM20020 clock divider */ + clockm, /* COM20020 clock multiplier flag */ + setup, /* Contents of setup1 register */ + setup2, /* Contents of setup2 register */ + intmask; /* current value of INTMASK register */ + uint8_t default_proto[256]; /* default encap to use for each host */ + int cur_tx, /* buffer used by current transmit, or -1 */ + next_tx, /* buffer where a packet is ready to send */ + cur_rx; /* current receive buffer */ + int lastload_dest, /* can last loaded packet be acked? */ + lasttrans_dest; /* can last TX'd packet be acked? */ + int timed_out; /* need to process TX timeout and drop packet */ + unsigned long last_timeout; /* time of last reported timeout */ + char *card_name; /* card ident string */ + int card_flags; /* special card features */ + + /* On preemtive and SMB a lock is needed */ + spinlock_t lock; + + /* + * Buffer management: an ARCnet card has 4 x 512-byte buffers, each of + * which can be used for either sending or receiving. The new dynamic + * buffer management routines use a simple circular queue of available + * buffers, and take them as they're needed. This way, we simplify + * situations in which we (for example) want to pre-load a transmit + * buffer, or start receiving while we copy a received packet to + * memory. + * + * The rules: only the interrupt handler is allowed to _add_ buffers to + * the queue; thus, this doesn't require a lock. Both the interrupt + * handler and the transmit function will want to _remove_ buffers, so + * we need to handle the situation where they try to do it at the same + * time. + * + * If next_buf == first_free_buf, the queue is empty. Since there are + * only four possible buffers, the queue should never be full. + */ + atomic_t buf_lock; + int buf_queue[5]; + int next_buf, first_free_buf; + + /* network "reconfiguration" handling */ + unsigned long first_recon; /* time of "first" RECON message to count */ + unsigned long last_recon; /* time of most recent RECON */ + int num_recons; /* number of RECONs between first and last. */ + int network_down; /* do we think the network is down? */ + + int excnak_pending; /* We just got an excesive nak interrupt */ + + struct { + uint16_t sequence; /* sequence number (incs with each packet) */ + __be16 aborted_seq; + + struct Incoming incoming[256]; /* one from each address */ + } rfc1201; + + /* really only used by rfc1201, but we'll pretend it's not */ + struct Outgoing outgoing; /* packet currently being sent */ + + /* hardware-specific functions */ + struct { + struct module *owner; + void (*command)(struct net_device *dev, int cmd); + int (*status)(struct net_device *dev); + void (*intmask)(struct net_device *dev, int mask); + int (*reset)(struct net_device *dev, int really_reset); + void (*open)(struct net_device *dev); + void (*close)(struct net_device *dev); + + void (*copy_to_card)(struct net_device *dev, int bufnum, + int offset, void *buf, int count); + void (*copy_from_card)(struct net_device *dev, int bufnum, + int offset, void *buf, int count); + } hw; + + void __iomem *mem_start; /* pointer to ioremap'ed MMIO */ +}; + +#define ARCRESET(x) (lp->hw.reset(dev, (x))) +#define ACOMMAND(x) (lp->hw.command(dev, (x))) +#define ASTATUS() (lp->hw.status(dev)) +#define AINTMASK(x) (lp->hw.intmask(dev, (x))) + +#if ARCNET_DEBUG_MAX & D_SKB +void arcnet_dump_skb(struct net_device *dev, struct sk_buff *skb, char *desc); +#else +static inline +void arcnet_dump_skb(struct net_device *dev, struct sk_buff *skb, char *desc) +{ +} +#endif + +void arcnet_unregister_proto(struct ArcProto *proto); +irqreturn_t arcnet_interrupt(int irq, void *dev_id); +struct net_device *alloc_arcdev(const char *name); + +int arcnet_open(struct net_device *dev); +int arcnet_close(struct net_device *dev); +netdev_tx_t arcnet_send_packet(struct sk_buff *skb, + struct net_device *dev); +void arcnet_timeout(struct net_device *dev); + +#endif /* __KERNEL__ */ +#endif /* _LINUX_ARCDEVICE_H */ diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c index 00074e781353..c8423ee24e71 100644 --- a/drivers/net/arcnet/arcnet.c +++ b/drivers/net/arcnet/arcnet.c @@ -50,9 +50,10 @@ #include #include #include -#include #include +#include "arcdevice.h" + /* "do nothing" functions for protocol drivers */ static void null_rx(struct net_device *dev, int bufnum, struct archdr *pkthdr, int length); diff --git a/drivers/net/arcnet/capmode.c b/drivers/net/arcnet/capmode.c index 46a76dcc21aa..2f2d0d94a80d 100644 --- a/drivers/net/arcnet/capmode.c +++ b/drivers/net/arcnet/capmode.c @@ -35,7 +35,8 @@ #include #include #include -#include + +#include "arcdevice.h" /* packet receiver */ static void rx(struct net_device *dev, int bufnum, diff --git a/drivers/net/arcnet/com20020-isa.c b/drivers/net/arcnet/com20020-isa.c index 352500b8d875..ab5202b506a6 100644 --- a/drivers/net/arcnet/com20020-isa.c +++ b/drivers/net/arcnet/com20020-isa.c @@ -39,11 +39,11 @@ #include #include #include -#include -#include - #include +#include "arcdevice.h" +#include "com20020.h" + /* We cannot (yet) probe for an IO mapped card, although we can check that * it's where we were told it was, and even do autoirq. */ diff --git a/drivers/net/arcnet/com20020-pci.c b/drivers/net/arcnet/com20020-pci.c index a28887dfcc9e..1a75a6982031 100644 --- a/drivers/net/arcnet/com20020-pci.c +++ b/drivers/net/arcnet/com20020-pci.c @@ -39,12 +39,12 @@ #include #include #include -#include -#include #include - #include +#include "arcdevice.h" +#include "com20020.h" + /* Module parameters */ static int node; diff --git a/drivers/net/arcnet/com20020.c b/drivers/net/arcnet/com20020.c index 00f910cf7b81..f46e22093c54 100644 --- a/drivers/net/arcnet/com20020.c +++ b/drivers/net/arcnet/com20020.c @@ -37,11 +37,11 @@ #include #include #include -#include -#include - #include +#include "arcdevice.h" +#include "com20020.h" + static char *clockrates[] = { "XXXXXXX", "XXXXXXXX", "XXXXXX", "2.5 Mb/s", "1.25Mb/s", "625 Kb/s", "312.5 Kb/s", diff --git a/drivers/net/arcnet/com20020.h b/drivers/net/arcnet/com20020.h new file mode 100644 index 000000000000..85898995b234 --- /dev/null +++ b/drivers/net/arcnet/com20020.h @@ -0,0 +1,145 @@ +/* + * Linux ARCnet driver - COM20020 chipset support - function declarations + * + * Written 1997 by David Woodhouse. + * Written 1994-1999 by Avery Pennarun. + * Derived from skeleton.c by Donald Becker. + * + * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com) + * for sponsoring the further development of this driver. + * + * ********************** + * + * The original copyright of skeleton.c was as follows: + * + * skeleton.c Written 1993 by Donald Becker. + * Copyright 1993 United States Government as represented by the + * Director, National Security Agency. This software may only be used + * and distributed according to the terms of the GNU General Public License as + * modified by SRC, incorporated herein by reference. + * + * ********************** + * + * For more details, see drivers/net/arcnet.c + * + * ********************** + */ +#ifndef __COM20020_H +#define __COM20020_H + +int com20020_check(struct net_device *dev); +int com20020_found(struct net_device *dev, int shared); +extern const struct net_device_ops com20020_netdev_ops; + +/* The number of low I/O ports used by the card. */ +#define ARCNET_TOTAL_SIZE 8 + +/* various register addresses */ +#ifdef CONFIG_SA1100_CT6001 +#define BUS_ALIGN 2 /* 8 bit device on a 16 bit bus - needs padding */ +#else +#define BUS_ALIGN 1 +#endif + +#define PLX_PCI_MAX_CARDS 2 + +struct com20020_pci_channel_map { + u32 bar; + u32 offset; + u32 size; /* 0x00 - auto, e.g. length of entire bar */ +}; + +struct com20020_pci_card_info { + const char *name; + int devcount; + + struct com20020_pci_channel_map chan_map_tbl[PLX_PCI_MAX_CARDS]; + + unsigned int flags; +}; + +struct com20020_priv { + struct com20020_pci_card_info *ci; + struct list_head list_dev; +}; + +struct com20020_dev { + struct list_head list; + struct net_device *dev; + + struct com20020_priv *pci_priv; + int index; +}; + +#define _INTMASK (ioaddr+BUS_ALIGN*0) /* writable */ +#define _STATUS (ioaddr+BUS_ALIGN*0) /* readable */ +#define _COMMAND (ioaddr+BUS_ALIGN*1) /* standard arcnet commands */ +#define _DIAGSTAT (ioaddr+BUS_ALIGN*1) /* diagnostic status register */ +#define _ADDR_HI (ioaddr+BUS_ALIGN*2) /* control registers for IO-mapped memory */ +#define _ADDR_LO (ioaddr+BUS_ALIGN*3) +#define _MEMDATA (ioaddr+BUS_ALIGN*4) /* data port for IO-mapped memory */ +#define _SUBADR (ioaddr+BUS_ALIGN*5) /* the extended port _XREG refers to */ +#define _CONFIG (ioaddr+BUS_ALIGN*6) /* configuration register */ +#define _XREG (ioaddr+BUS_ALIGN*7) /* extra registers (indexed by _CONFIG + or _SUBADR) */ + +/* in the ADDR_HI register */ +#define RDDATAflag 0x80 /* next access is a read (not a write) */ + +/* in the DIAGSTAT register */ +#define NEWNXTIDflag 0x02 /* ID to which token is passed has changed */ + +/* in the CONFIG register */ +#define RESETcfg 0x80 /* put card in reset state */ +#define TXENcfg 0x20 /* enable TX */ + +/* in SETUP register */ +#define PROMISCset 0x10 /* enable RCV_ALL */ +#define P1MODE 0x80 /* enable P1-MODE for Backplane */ +#define SLOWARB 0x01 /* enable Slow Arbitration for >=5Mbps */ + +/* COM2002x */ +#define SUB_TENTATIVE 0 /* tentative node ID */ +#define SUB_NODE 1 /* node ID */ +#define SUB_SETUP1 2 /* various options */ +#define SUB_TEST 3 /* test/diag register */ + +/* COM20022 only */ +#define SUB_SETUP2 4 /* sundry options */ +#define SUB_BUSCTL 5 /* bus control options */ +#define SUB_DMACOUNT 6 /* DMA count options */ + +#define SET_SUBADR(x) do { \ + if ((x) < 4) \ + { \ + lp->config = (lp->config & ~0x03) | (x); \ + SETCONF; \ + } \ + else \ + { \ + outb(x, _SUBADR); \ + } \ +} while (0) + +#undef ARCRESET +#undef ASTATUS +#undef ACOMMAND +#undef AINTMASK + +#define ARCRESET { outb(lp->config | 0x80, _CONFIG); \ + udelay(5); \ + outb(lp->config , _CONFIG); \ + } +#define ARCRESET0 { outb(0x18 | 0x80, _CONFIG); \ + udelay(5); \ + outb(0x18 , _CONFIG); \ + } + +#define ASTATUS() inb(_STATUS) +#define ADIAGSTATUS() inb(_DIAGSTAT) +#define ACOMMAND(cmd) outb((cmd),_COMMAND) +#define AINTMASK(msk) outb((msk),_INTMASK) + +#define SETCONF outb(lp->config, _CONFIG) + +#endif /* __COM20020_H */ diff --git a/drivers/net/arcnet/com20020_cs.c b/drivers/net/arcnet/com20020_cs.c index 854169489b68..5fdde6946427 100644 --- a/drivers/net/arcnet/com20020_cs.c +++ b/drivers/net/arcnet/com20020_cs.c @@ -42,13 +42,12 @@ #include #include #include -#include -#include - +#include #include #include -#include +#include "arcdevice.h" +#include "com20020.h" static void regdump(struct net_device *dev) { diff --git a/drivers/net/arcnet/com90io.c b/drivers/net/arcnet/com90io.c index 9e779a53035d..ce15d1911048 100644 --- a/drivers/net/arcnet/com90io.c +++ b/drivers/net/arcnet/com90io.c @@ -38,7 +38,8 @@ #include #include #include -#include + +#include "arcdevice.h" /* Internal function declarations */ diff --git a/drivers/net/arcnet/com90xx.c b/drivers/net/arcnet/com90xx.c index 62100acfb6a7..b672795acaa7 100644 --- a/drivers/net/arcnet/com90xx.c +++ b/drivers/net/arcnet/com90xx.c @@ -36,7 +36,8 @@ #include #include #include -#include + +#include "arcdevice.h" /* Define this to speed up the autoprobe by assuming if only one io port and * shmem are left in the list at Stage 5, they must correspond to each diff --git a/drivers/net/arcnet/rfc1051.c b/drivers/net/arcnet/rfc1051.c index 691bee5bcd42..4b1a75469cb1 100644 --- a/drivers/net/arcnet/rfc1051.c +++ b/drivers/net/arcnet/rfc1051.c @@ -33,7 +33,8 @@ #include #include #include -#include + +#include "arcdevice.h" static __be16 type_trans(struct sk_buff *skb, struct net_device *dev); static void rx(struct net_device *dev, int bufnum, diff --git a/drivers/net/arcnet/rfc1201.c b/drivers/net/arcnet/rfc1201.c index aaa1966593aa..566da5ecdc9d 100644 --- a/drivers/net/arcnet/rfc1201.c +++ b/drivers/net/arcnet/rfc1201.c @@ -32,7 +32,8 @@ #include #include #include -#include + +#include "arcdevice.h" MODULE_LICENSE("GPL"); diff --git a/include/linux/arcdevice.h b/include/linux/arcdevice.h deleted file mode 100644 index 9ca135d0f114..000000000000 --- a/include/linux/arcdevice.h +++ /dev/null @@ -1,346 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. NET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Definitions used by the ARCnet driver. - * - * Authors: Avery Pennarun and David Woodhouse - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - */ -#ifndef _LINUX_ARCDEVICE_H -#define _LINUX_ARCDEVICE_H - -#include -#include - -#ifdef __KERNEL__ -#include - -/* - * RECON_THRESHOLD is the maximum number of RECON messages to receive - * within one minute before printing a "cabling problem" warning. The - * default value should be fine. - * - * After that, a "cabling restored" message will be printed on the next IRQ - * if no RECON messages have been received for 10 seconds. - * - * Do not define RECON_THRESHOLD at all if you want to disable this feature. - */ -#define RECON_THRESHOLD 30 - -/* - * Define this to the minimum "timeout" value. If a transmit takes longer - * than TX_TIMEOUT jiffies, Linux will abort the TX and retry. On a large - * network, or one with heavy network traffic, this timeout may need to be - * increased. The larger it is, though, the longer it will be between - * necessary transmits - don't set this too high. - */ -#define TX_TIMEOUT (HZ * 200 / 1000) - -/* Display warnings about the driver being an ALPHA version. */ -#undef ALPHA_WARNING - -/* - * Debugging bitflags: each option can be enabled individually. - * - * Note: only debug flags included in the ARCNET_DEBUG_MAX define will - * actually be available. GCC will (at least, GCC 2.7.0 will) notice - * lines using a BUGLVL not in ARCNET_DEBUG_MAX and automatically optimize - * them out. - */ -#define D_NORMAL 1 /* important operational info */ -#define D_EXTRA 2 /* useful, but non-vital information */ -#define D_INIT 4 /* show init/probe messages */ -#define D_INIT_REASONS 8 /* show reasons for discarding probes */ -#define D_RECON 32 /* print a message whenever token is lost */ -#define D_PROTO 64 /* debug auto-protocol support */ -/* debug levels below give LOTS of output during normal operation! */ -#define D_DURING 128 /* trace operations (including irq's) */ -#define D_TX 256 /* show tx packets */ -#define D_RX 512 /* show rx packets */ -#define D_SKB 1024 /* show skb's */ -#define D_SKB_SIZE 2048 /* show skb sizes */ -#define D_TIMING 4096 /* show time needed to copy buffers to card */ -#define D_DEBUG 8192 /* Very detailed debug line for line */ - -#ifndef ARCNET_DEBUG_MAX -#define ARCNET_DEBUG_MAX (127) /* change to ~0 if you want detailed debugging */ -#endif - -#ifndef ARCNET_DEBUG -#define ARCNET_DEBUG (D_NORMAL | D_EXTRA) -#endif -extern int arcnet_debug; - -#define BUGLVL(x) ((x) & ARCNET_DEBUG_MAX & arcnet_debug) - -/* macros to simplify debug checking */ -#define arc_printk(x, dev, fmt, ...) \ -do { \ - if (BUGLVL(x)) { \ - if ((x) == D_NORMAL) \ - netdev_warn(dev, fmt, ##__VA_ARGS__); \ - else if ((x) < D_DURING) \ - netdev_info(dev, fmt, ##__VA_ARGS__); \ - else \ - netdev_dbg(dev, fmt, ##__VA_ARGS__); \ - } \ -} while (0) - -#define arc_cont(x, fmt, ...) \ -do { \ - if (BUGLVL(x)) \ - pr_cont(fmt, ##__VA_ARGS__); \ -} while (0) - -/* see how long a function call takes to run, expressed in CPU cycles */ -#define TIME(dev, name, bytes, call) \ -do { \ - if (BUGLVL(D_TIMING)) { \ - unsigned long _x, _y; \ - _x = get_cycles(); \ - call; \ - _y = get_cycles(); \ - arc_printk(D_TIMING, dev, \ - "%s: %d bytes in %lu cycles == %lu Kbytes/100Mcycle\n", \ - name, bytes, _y - _x, \ - 100000000 / 1024 * bytes / (_y - _x + 1)); \ - } else { \ - call; \ - } \ -} while (0) - -/* - * Time needed to reset the card - in ms (milliseconds). This works on my - * SMC PC100. I can't find a reference that tells me just how long I - * should wait. - */ -#define RESETtime (300) - -/* - * These are the max/min lengths of packet payload, not including the - * arc_hardware header, but definitely including the soft header. - * - * Note: packet sizes 254, 255, 256 are impossible because of the way - * ARCnet registers work That's why RFC1201 defines "exception" packets. - * In non-RFC1201 protocols, we have to just tack some extra bytes on the - * end. - */ -#define MTU 253 /* normal packet max size */ -#define MinTU 257 /* extended packet min size */ -#define XMTU 508 /* extended packet max size */ - -/* status/interrupt mask bit fields */ -#define TXFREEflag 0x01 /* transmitter available */ -#define TXACKflag 0x02 /* transmitted msg. ackd */ -#define RECONflag 0x04 /* network reconfigured */ -#define TESTflag 0x08 /* test flag */ -#define EXCNAKflag 0x08 /* excesive nak flag */ -#define RESETflag 0x10 /* power-on-reset */ -#define RES1flag 0x20 /* reserved - usually set by jumper */ -#define RES2flag 0x40 /* reserved - usually set by jumper */ -#define NORXflag 0x80 /* receiver inhibited */ - -/* Flags used for IO-mapped memory operations */ -#define AUTOINCflag 0x40 /* Increase location with each access */ -#define IOMAPflag 0x02 /* (for 90xx) Use IO mapped memory, not mmap */ -#define ENABLE16flag 0x80 /* (for 90xx) Enable 16-bit mode */ - -/* in the command register, the following bits have these meanings: - * 0-2 command - * 3-4 page number (for enable rcv/xmt command) - * 7 receive broadcasts - */ -#define NOTXcmd 0x01 /* disable transmitter */ -#define NORXcmd 0x02 /* disable receiver */ -#define TXcmd 0x03 /* enable transmitter */ -#define RXcmd 0x04 /* enable receiver */ -#define CONFIGcmd 0x05 /* define configuration */ -#define CFLAGScmd 0x06 /* clear flags */ -#define TESTcmd 0x07 /* load test flags */ - -/* flags for "clear flags" command */ -#define RESETclear 0x08 /* power-on-reset */ -#define CONFIGclear 0x10 /* system reconfigured */ - -#define EXCNAKclear 0x0E /* Clear and acknowledge the excive nak bit */ - -/* flags for "load test flags" command */ -#define TESTload 0x08 /* test flag (diagnostic) */ - -/* byte deposited into first address of buffers on reset */ -#define TESTvalue 0321 /* that's octal for 0xD1 :) */ - -/* for "enable receiver" command */ -#define RXbcasts 0x80 /* receive broadcasts */ - -/* flags for "define configuration" command */ -#define NORMALconf 0x00 /* 1-249 byte packets */ -#define EXTconf 0x08 /* 250-504 byte packets */ - -/* card feature flags, set during auto-detection. - * (currently only used by com20020pci) - */ -#define ARC_IS_5MBIT 1 /* card default speed is 5MBit */ -#define ARC_CAN_10MBIT 2 /* card uses COM20022, supporting 10MBit, - but default is 2.5MBit. */ - -/* information needed to define an encapsulation driver */ -struct ArcProto { - char suffix; /* a for RFC1201, e for ether-encap, etc. */ - int mtu; /* largest possible packet */ - int is_ip; /* This is a ip plugin - not a raw thing */ - - void (*rx)(struct net_device *dev, int bufnum, - struct archdr *pkthdr, int length); - int (*build_header)(struct sk_buff *skb, struct net_device *dev, - unsigned short ethproto, uint8_t daddr); - - /* these functions return '1' if the skb can now be freed */ - int (*prepare_tx)(struct net_device *dev, struct archdr *pkt, - int length, int bufnum); - int (*continue_tx)(struct net_device *dev, int bufnum); - int (*ack_tx)(struct net_device *dev, int acked); -}; - -extern struct ArcProto *arc_proto_map[256], *arc_proto_default, - *arc_bcast_proto, *arc_raw_proto; - -/* - * "Incoming" is information needed for each address that could be sending - * to us. Mostly for partially-received split packets. - */ -struct Incoming { - struct sk_buff *skb; /* packet data buffer */ - __be16 sequence; /* sequence number of assembly */ - uint8_t lastpacket, /* number of last packet (from 1) */ - numpackets; /* number of packets in split */ -}; - -/* only needed for RFC1201 */ -struct Outgoing { - struct ArcProto *proto; /* protocol driver that owns this: - * if NULL, no packet is pending. - */ - struct sk_buff *skb; /* buffer from upper levels */ - struct archdr *pkt; /* a pointer into the skb */ - uint16_t length, /* bytes total */ - dataleft, /* bytes left */ - segnum, /* segment being sent */ - numsegs; /* number of segments */ -}; - -struct arcnet_local { - uint8_t config, /* current value of CONFIG register */ - timeout, /* Extended timeout for COM20020 */ - backplane, /* Backplane flag for COM20020 */ - clockp, /* COM20020 clock divider */ - clockm, /* COM20020 clock multiplier flag */ - setup, /* Contents of setup1 register */ - setup2, /* Contents of setup2 register */ - intmask; /* current value of INTMASK register */ - uint8_t default_proto[256]; /* default encap to use for each host */ - int cur_tx, /* buffer used by current transmit, or -1 */ - next_tx, /* buffer where a packet is ready to send */ - cur_rx; /* current receive buffer */ - int lastload_dest, /* can last loaded packet be acked? */ - lasttrans_dest; /* can last TX'd packet be acked? */ - int timed_out; /* need to process TX timeout and drop packet */ - unsigned long last_timeout; /* time of last reported timeout */ - char *card_name; /* card ident string */ - int card_flags; /* special card features */ - - /* On preemtive and SMB a lock is needed */ - spinlock_t lock; - - /* - * Buffer management: an ARCnet card has 4 x 512-byte buffers, each of - * which can be used for either sending or receiving. The new dynamic - * buffer management routines use a simple circular queue of available - * buffers, and take them as they're needed. This way, we simplify - * situations in which we (for example) want to pre-load a transmit - * buffer, or start receiving while we copy a received packet to - * memory. - * - * The rules: only the interrupt handler is allowed to _add_ buffers to - * the queue; thus, this doesn't require a lock. Both the interrupt - * handler and the transmit function will want to _remove_ buffers, so - * we need to handle the situation where they try to do it at the same - * time. - * - * If next_buf == first_free_buf, the queue is empty. Since there are - * only four possible buffers, the queue should never be full. - */ - atomic_t buf_lock; - int buf_queue[5]; - int next_buf, first_free_buf; - - /* network "reconfiguration" handling */ - unsigned long first_recon; /* time of "first" RECON message to count */ - unsigned long last_recon; /* time of most recent RECON */ - int num_recons; /* number of RECONs between first and last. */ - int network_down; /* do we think the network is down? */ - - int excnak_pending; /* We just got an excesive nak interrupt */ - - struct { - uint16_t sequence; /* sequence number (incs with each packet) */ - __be16 aborted_seq; - - struct Incoming incoming[256]; /* one from each address */ - } rfc1201; - - /* really only used by rfc1201, but we'll pretend it's not */ - struct Outgoing outgoing; /* packet currently being sent */ - - /* hardware-specific functions */ - struct { - struct module *owner; - void (*command)(struct net_device *dev, int cmd); - int (*status)(struct net_device *dev); - void (*intmask)(struct net_device *dev, int mask); - int (*reset)(struct net_device *dev, int really_reset); - void (*open)(struct net_device *dev); - void (*close)(struct net_device *dev); - - void (*copy_to_card)(struct net_device *dev, int bufnum, - int offset, void *buf, int count); - void (*copy_from_card)(struct net_device *dev, int bufnum, - int offset, void *buf, int count); - } hw; - - void __iomem *mem_start; /* pointer to ioremap'ed MMIO */ -}; - -#define ARCRESET(x) (lp->hw.reset(dev, (x))) -#define ACOMMAND(x) (lp->hw.command(dev, (x))) -#define ASTATUS() (lp->hw.status(dev)) -#define AINTMASK(x) (lp->hw.intmask(dev, (x))) - -#if ARCNET_DEBUG_MAX & D_SKB -void arcnet_dump_skb(struct net_device *dev, struct sk_buff *skb, char *desc); -#else -static inline -void arcnet_dump_skb(struct net_device *dev, struct sk_buff *skb, char *desc) -{ -} -#endif - -void arcnet_unregister_proto(struct ArcProto *proto); -irqreturn_t arcnet_interrupt(int irq, void *dev_id); -struct net_device *alloc_arcdev(const char *name); - -int arcnet_open(struct net_device *dev); -int arcnet_close(struct net_device *dev); -netdev_tx_t arcnet_send_packet(struct sk_buff *skb, - struct net_device *dev); -void arcnet_timeout(struct net_device *dev); - -#endif /* __KERNEL__ */ -#endif /* _LINUX_ARCDEVICE_H */ diff --git a/include/linux/com20020.h b/include/linux/com20020.h deleted file mode 100644 index 85898995b234..000000000000 --- a/include/linux/com20020.h +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Linux ARCnet driver - COM20020 chipset support - function declarations - * - * Written 1997 by David Woodhouse. - * Written 1994-1999 by Avery Pennarun. - * Derived from skeleton.c by Donald Becker. - * - * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com) - * for sponsoring the further development of this driver. - * - * ********************** - * - * The original copyright of skeleton.c was as follows: - * - * skeleton.c Written 1993 by Donald Becker. - * Copyright 1993 United States Government as represented by the - * Director, National Security Agency. This software may only be used - * and distributed according to the terms of the GNU General Public License as - * modified by SRC, incorporated herein by reference. - * - * ********************** - * - * For more details, see drivers/net/arcnet.c - * - * ********************** - */ -#ifndef __COM20020_H -#define __COM20020_H - -int com20020_check(struct net_device *dev); -int com20020_found(struct net_device *dev, int shared); -extern const struct net_device_ops com20020_netdev_ops; - -/* The number of low I/O ports used by the card. */ -#define ARCNET_TOTAL_SIZE 8 - -/* various register addresses */ -#ifdef CONFIG_SA1100_CT6001 -#define BUS_ALIGN 2 /* 8 bit device on a 16 bit bus - needs padding */ -#else -#define BUS_ALIGN 1 -#endif - -#define PLX_PCI_MAX_CARDS 2 - -struct com20020_pci_channel_map { - u32 bar; - u32 offset; - u32 size; /* 0x00 - auto, e.g. length of entire bar */ -}; - -struct com20020_pci_card_info { - const char *name; - int devcount; - - struct com20020_pci_channel_map chan_map_tbl[PLX_PCI_MAX_CARDS]; - - unsigned int flags; -}; - -struct com20020_priv { - struct com20020_pci_card_info *ci; - struct list_head list_dev; -}; - -struct com20020_dev { - struct list_head list; - struct net_device *dev; - - struct com20020_priv *pci_priv; - int index; -}; - -#define _INTMASK (ioaddr+BUS_ALIGN*0) /* writable */ -#define _STATUS (ioaddr+BUS_ALIGN*0) /* readable */ -#define _COMMAND (ioaddr+BUS_ALIGN*1) /* standard arcnet commands */ -#define _DIAGSTAT (ioaddr+BUS_ALIGN*1) /* diagnostic status register */ -#define _ADDR_HI (ioaddr+BUS_ALIGN*2) /* control registers for IO-mapped memory */ -#define _ADDR_LO (ioaddr+BUS_ALIGN*3) -#define _MEMDATA (ioaddr+BUS_ALIGN*4) /* data port for IO-mapped memory */ -#define _SUBADR (ioaddr+BUS_ALIGN*5) /* the extended port _XREG refers to */ -#define _CONFIG (ioaddr+BUS_ALIGN*6) /* configuration register */ -#define _XREG (ioaddr+BUS_ALIGN*7) /* extra registers (indexed by _CONFIG - or _SUBADR) */ - -/* in the ADDR_HI register */ -#define RDDATAflag 0x80 /* next access is a read (not a write) */ - -/* in the DIAGSTAT register */ -#define NEWNXTIDflag 0x02 /* ID to which token is passed has changed */ - -/* in the CONFIG register */ -#define RESETcfg 0x80 /* put card in reset state */ -#define TXENcfg 0x20 /* enable TX */ - -/* in SETUP register */ -#define PROMISCset 0x10 /* enable RCV_ALL */ -#define P1MODE 0x80 /* enable P1-MODE for Backplane */ -#define SLOWARB 0x01 /* enable Slow Arbitration for >=5Mbps */ - -/* COM2002x */ -#define SUB_TENTATIVE 0 /* tentative node ID */ -#define SUB_NODE 1 /* node ID */ -#define SUB_SETUP1 2 /* various options */ -#define SUB_TEST 3 /* test/diag register */ - -/* COM20022 only */ -#define SUB_SETUP2 4 /* sundry options */ -#define SUB_BUSCTL 5 /* bus control options */ -#define SUB_DMACOUNT 6 /* DMA count options */ - -#define SET_SUBADR(x) do { \ - if ((x) < 4) \ - { \ - lp->config = (lp->config & ~0x03) | (x); \ - SETCONF; \ - } \ - else \ - { \ - outb(x, _SUBADR); \ - } \ -} while (0) - -#undef ARCRESET -#undef ASTATUS -#undef ACOMMAND -#undef AINTMASK - -#define ARCRESET { outb(lp->config | 0x80, _CONFIG); \ - udelay(5); \ - outb(lp->config , _CONFIG); \ - } -#define ARCRESET0 { outb(0x18 | 0x80, _CONFIG); \ - udelay(5); \ - outb(0x18 , _CONFIG); \ - } - -#define ASTATUS() inb(_STATUS) -#define ADIAGSTATUS() inb(_DIAGSTAT) -#define ACOMMAND(cmd) outb((cmd),_COMMAND) -#define AINTMASK(msk) outb((msk),_INTMASK) - -#define SETCONF outb(lp->config, _CONFIG) - -#endif /* __COM20020_H */ -- cgit v1.2.3 From 1b69c6d0ae90b7f1a4f61d5c8209d5cb7a55f849 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Tue, 29 Sep 2015 20:07:11 -0700 Subject: net: Introduce L3 Master device abstraction L3 master devices allow users of the abstraction to influence FIB lookups for enslaved devices. Current API provides a means for the master device to return a specific FIB table for an enslaved device, to return an rtable/custom dst and influence the OIF used for fib lookups. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- MAINTAINERS | 7 +++ include/linux/netdevice.h | 3 ++ include/net/l3mdev.h | 125 ++++++++++++++++++++++++++++++++++++++++++++++ net/Kconfig | 1 + net/Makefile | 3 ++ net/l3mdev/Kconfig | 10 ++++ net/l3mdev/Makefile | 5 ++ net/l3mdev/l3mdev.c | 92 ++++++++++++++++++++++++++++++++++ 8 files changed, 246 insertions(+) create mode 100644 include/net/l3mdev.h create mode 100644 net/l3mdev/Kconfig create mode 100644 net/l3mdev/Makefile create mode 100644 net/l3mdev/l3mdev.c (limited to 'MAINTAINERS') diff --git a/MAINTAINERS b/MAINTAINERS index bcd263de4827..3f2d7a9d0bbf 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6095,6 +6095,13 @@ F: Documentation/auxdisplay/ks0108 F: drivers/auxdisplay/ks0108.c F: include/linux/ks0108.h +L3MDEV +M: David Ahern +L: netdev@vger.kernel.org +S: Maintained +F: net/l3mdev +F: include/net/l3mdev.h + LAPB module L: linux-x25@vger.kernel.org S: Orphan diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 99c33e83822f..c7f14794fe14 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1587,6 +1587,9 @@ struct net_device { #ifdef CONFIG_NET_SWITCHDEV const struct switchdev_ops *switchdev_ops; #endif +#ifdef CONFIG_NET_L3_MASTER_DEV + const struct l3mdev_ops *l3mdev_ops; +#endif const struct header_ops *header_ops; diff --git a/include/net/l3mdev.h b/include/net/l3mdev.h new file mode 100644 index 000000000000..e382c777bab8 --- /dev/null +++ b/include/net/l3mdev.h @@ -0,0 +1,125 @@ +/* + * include/net/l3mdev.h - L3 master device API + * Copyright (c) 2015 Cumulus Networks + * Copyright (c) 2015 David Ahern + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ +#ifndef _NET_L3MDEV_H_ +#define _NET_L3MDEV_H_ + +/** + * struct l3mdev_ops - l3mdev operations + * + * @l3mdev_fib_table: Get FIB table id to use for lookups + * + * @l3mdev_get_rtable: Get cached IPv4 rtable (dst_entry) for device + */ + +struct l3mdev_ops { + u32 (*l3mdev_fib_table)(const struct net_device *dev); + struct rtable * (*l3mdev_get_rtable)(const struct net_device *dev, + const struct flowi4 *fl4); +}; + +#ifdef CONFIG_NET_L3_MASTER_DEV + +int l3mdev_master_ifindex_rcu(struct net_device *dev); +static inline int l3mdev_master_ifindex(struct net_device *dev) +{ + int ifindex; + + rcu_read_lock(); + ifindex = l3mdev_master_ifindex_rcu(dev); + rcu_read_unlock(); + + return ifindex; +} + +/* get index of an interface to use for FIB lookups. For devices + * enslaved to an L3 master device FIB lookups are based on the + * master index + */ +static inline int l3mdev_fib_oif_rcu(struct net_device *dev) +{ + return l3mdev_master_ifindex_rcu(dev) ? : dev->ifindex; +} + +static inline int l3mdev_fib_oif(struct net_device *dev) +{ + int oif; + + rcu_read_lock(); + oif = l3mdev_fib_oif_rcu(dev); + rcu_read_unlock(); + + return oif; +} + +u32 l3mdev_fib_table_rcu(const struct net_device *dev); +u32 l3mdev_fib_table_by_index(struct net *net, int ifindex); +static inline u32 l3mdev_fib_table(const struct net_device *dev) +{ + u32 tb_id; + + rcu_read_lock(); + tb_id = l3mdev_fib_table_rcu(dev); + rcu_read_unlock(); + + return tb_id; +} + +static inline struct rtable *l3mdev_get_rtable(const struct net_device *dev, + const struct flowi4 *fl4) +{ + if (netif_is_l3_master(dev) && dev->l3mdev_ops->l3mdev_get_rtable) + return dev->l3mdev_ops->l3mdev_get_rtable(dev, fl4); + + return NULL; +} + +#else + +static inline int l3mdev_master_ifindex_rcu(struct net_device *dev) +{ + return 0; +} +static inline int l3mdev_master_ifindex(struct net_device *dev) +{ + return 0; +} + +static inline int l3mdev_fib_oif_rcu(struct net_device *dev) +{ + return dev ? dev->ifindex : 0; +} +static inline int l3mdev_fib_oif(struct net_device *dev) +{ + return dev ? dev->ifindex : 0; +} + +static inline u32 l3mdev_fib_table_rcu(const struct net_device *dev) +{ + return 0; +} +static inline u32 l3mdev_fib_table(const struct net_device *dev) +{ + return 0; +} +static inline u32 l3mdev_fib_table_by_index(struct net *net, int ifindex) +{ + return 0; +} + +static inline struct rtable *l3mdev_get_rtable(const struct net_device *dev, + const struct flowi4 *fl4) +{ + return NULL; +} + +#endif + +#endif /* _NET_L3MDEV_H_ */ diff --git a/net/Kconfig b/net/Kconfig index 7021c1bf44d6..127da94ae25e 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -232,6 +232,7 @@ source "net/netlink/Kconfig" source "net/mpls/Kconfig" source "net/hsr/Kconfig" source "net/switchdev/Kconfig" +source "net/l3mdev/Kconfig" config RPS bool diff --git a/net/Makefile b/net/Makefile index 3995613e5510..a5d04098dfce 100644 --- a/net/Makefile +++ b/net/Makefile @@ -74,3 +74,6 @@ obj-$(CONFIG_HSR) += hsr/ ifneq ($(CONFIG_NET_SWITCHDEV),) obj-y += switchdev/ endif +ifneq ($(CONFIG_NET_L3_MASTER_DEV),) +obj-y += l3mdev/ +endif diff --git a/net/l3mdev/Kconfig b/net/l3mdev/Kconfig new file mode 100644 index 000000000000..5d47325037bc --- /dev/null +++ b/net/l3mdev/Kconfig @@ -0,0 +1,10 @@ +# +# Configuration for L3 master device support +# + +config NET_L3_MASTER_DEV + bool "L3 Master device support" + depends on INET || IPV6 + ---help--- + This module provides glue between core networking code and device + drivers to support L3 master devices like VRF. diff --git a/net/l3mdev/Makefile b/net/l3mdev/Makefile new file mode 100644 index 000000000000..84a53a6f609a --- /dev/null +++ b/net/l3mdev/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the L3 device API +# + +obj-$(CONFIG_NET_L3_MASTER_DEV) += l3mdev.o diff --git a/net/l3mdev/l3mdev.c b/net/l3mdev/l3mdev.c new file mode 100644 index 000000000000..ddf75ad41713 --- /dev/null +++ b/net/l3mdev/l3mdev.c @@ -0,0 +1,92 @@ +/* + * net/l3mdev/l3mdev.c - L3 master device implementation + * Copyright (c) 2015 Cumulus Networks + * Copyright (c) 2015 David Ahern + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include + +/** + * l3mdev_master_ifindex - get index of L3 master device + * @dev: targeted interface + */ + +int l3mdev_master_ifindex_rcu(struct net_device *dev) +{ + int ifindex = 0; + + if (!dev) + return 0; + + if (netif_is_l3_master(dev)) { + ifindex = dev->ifindex; + } else if (dev->flags & IFF_SLAVE) { + struct net_device *master; + + master = netdev_master_upper_dev_get_rcu(dev); + if (master && netif_is_l3_master(master)) + ifindex = master->ifindex; + } + + return ifindex; +} +EXPORT_SYMBOL_GPL(l3mdev_master_ifindex_rcu); + +/** + * l3mdev_fib_table - get FIB table id associated with an L3 + * master interface + * @dev: targeted interface + */ + +u32 l3mdev_fib_table_rcu(const struct net_device *dev) +{ + u32 tb_id = 0; + + if (!dev) + return 0; + + if (netif_is_l3_master(dev)) { + if (dev->l3mdev_ops->l3mdev_fib_table) + tb_id = dev->l3mdev_ops->l3mdev_fib_table(dev); + } else if (dev->flags & IFF_SLAVE) { + /* Users of netdev_master_upper_dev_get_rcu need non-const, + * but current inet_*type functions take a const + */ + struct net_device *_dev = (struct net_device *) dev; + const struct net_device *master; + + master = netdev_master_upper_dev_get_rcu(_dev); + if (master && netif_is_l3_master(master) && + master->l3mdev_ops->l3mdev_fib_table) + tb_id = master->l3mdev_ops->l3mdev_fib_table(master); + } + + return tb_id; +} +EXPORT_SYMBOL_GPL(l3mdev_fib_table_rcu); + +u32 l3mdev_fib_table_by_index(struct net *net, int ifindex) +{ + struct net_device *dev; + u32 tb_id = 0; + + if (!ifindex) + return 0; + + rcu_read_lock(); + + dev = dev_get_by_index_rcu(net, ifindex); + if (dev) + tb_id = l3mdev_fib_table_rcu(dev); + + rcu_read_unlock(); + + return tb_id; +} +EXPORT_SYMBOL_GPL(l3mdev_fib_table_by_index); -- cgit v1.2.3 From ec539514e56284b21c47468f23f7d01ff882f51b Mon Sep 17 00:00:00 2001 From: David Ahern Date: Tue, 29 Sep 2015 20:07:17 -0700 Subject: net: Remove vrf header file Move remaining structs to VRF driver and delete the vrf header file. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- MAINTAINERS | 1 - drivers/net/vrf.c | 16 +++++++++++++++- include/net/vrf.h | 29 ----------------------------- 3 files changed, 15 insertions(+), 31 deletions(-) delete mode 100644 include/net/vrf.h (limited to 'MAINTAINERS') diff --git a/MAINTAINERS b/MAINTAINERS index 3f2d7a9d0bbf..fa43fa2f30e4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11273,7 +11273,6 @@ M: Shrijeet Mukherjee L: netdev@vger.kernel.org S: Maintained F: drivers/net/vrf.c -F: include/net/vrf.h F: Documentation/networking/vrf.txt VT1211 HARDWARE MONITOR DRIVER diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c index df872f4efb0d..64f2ab663ffe 100644 --- a/drivers/net/vrf.c +++ b/drivers/net/vrf.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #define DRV_NAME "vrf" @@ -45,6 +44,21 @@ #define vrf_master_get_rcu(dev) \ ((struct net_device *)rcu_dereference(dev->rx_handler_data)) +struct slave { + struct list_head list; + struct net_device *dev; +}; + +struct slave_queue { + struct list_head all_slaves; +}; + +struct net_vrf { + struct slave_queue queue; + struct rtable *rth; + u32 tb_id; +}; + struct pcpu_dstats { u64 tx_pkts; u64 tx_bytes; diff --git a/include/net/vrf.h b/include/net/vrf.h deleted file mode 100644 index e83fc38770dd..000000000000 --- a/include/net/vrf.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * include/net/net_vrf.h - adds vrf dev structure definitions - * Copyright (c) 2015 Cumulus Networks - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#ifndef __LINUX_NET_VRF_H -#define __LINUX_NET_VRF_H - -struct slave { - struct list_head list; - struct net_device *dev; -}; - -struct slave_queue { - struct list_head all_slaves; -}; - -struct net_vrf { - struct slave_queue queue; - struct rtable *rth; - u32 tb_id; -}; - -#endif /* __LINUX_NET_VRF_H */ -- cgit v1.2.3 From 7b9aebf0e507108daba3516f28cfd78fce80c176 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 8 Sep 2015 17:03:20 +0200 Subject: MAINTAINERS: iwlwifi: update contact email The ilw@linux.intel.com address is being phased out, replace it with the new address. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'MAINTAINERS') diff --git a/MAINTAINERS b/MAINTAINERS index 310da4295c70..77b2728ca506 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5541,7 +5541,7 @@ F: drivers/net/wireless/iwlegacy/ INTEL WIRELESS WIFI LINK (iwlwifi) M: Johannes Berg M: Emmanuel Grumbach -M: Intel Linux Wireless +M: Intel Linux Wireless L: linux-wireless@vger.kernel.org W: http://intellinuxwireless.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi.git -- cgit v1.2.3 From 26f1fad29ad973b0fb26a9ca3dcb2a73dde781aa Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Wed, 14 Oct 2015 20:44:51 -0400 Subject: New driver: rtl8xxxu (mac80211) This is an alternate driver for a number of Realtek WiFi USB devices, including RTL8723AU, RTL8188CU, RTL8188RU, RTL8191CU, and RTL8192CU. It was written from scratch utilizing the Linux mac80211 stack. After spending months cleaning up the vendor provided rtl8723au driver, which comes with it's own 802.11 stack included, I decided to rewrite this driver from the bottom up. Many thanks to Johannes Berg for 802.11 insights and help and Larry Finger for help with the vendor driver. The full git log for the development of this driver can be found here: git git://git.kernel.org/pub/scm/linux/kernel/git/jes/linux.git branch rtl8723au-mac80211 This driver is still under development, but has proven to be very stable for me. It currently supports station mode only. It has support for OFDM and CCK rates. It does lack certain features found in the staging driver, such as power management, AMPDU, and 40MHz channel support. In addition it does not support AD-HOC, AP, and monitor mode support at this point. The driver is known to work with the following devices: Lenovo Yoga (rtl8723au) TP-Link TL-WN823N (rtl8192cu) Etekcity 6R (rtl8188cu) Daffodil LAN03 (rtl8188cu) Alfa AWUS036NHR (rtl8188ru) Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- MAINTAINERS | 7 + drivers/net/wireless/Kconfig | 1 + drivers/net/wireless/realtek/Makefile | 1 + drivers/net/wireless/realtek/rtl8xxxu/Kconfig | 34 + drivers/net/wireless/realtek/rtl8xxxu/Makefile | 1 + drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 5976 ++++++++++++++++++++ drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 676 +++ .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h | 981 ++++ 8 files changed, 7677 insertions(+) create mode 100644 drivers/net/wireless/realtek/rtl8xxxu/Kconfig create mode 100644 drivers/net/wireless/realtek/rtl8xxxu/Makefile create mode 100644 drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c create mode 100644 drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h create mode 100644 drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h (limited to 'MAINTAINERS') diff --git a/MAINTAINERS b/MAINTAINERS index 9bf8683defd9..e4126012adc6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8877,6 +8877,13 @@ S: Maintained F: drivers/net/wireless/rtlwifi/ F: drivers/net/wireless/rtlwifi/rtl8192ce/ +RTL8XXXU WIRELESS DRIVER (rtl8xxxu) +M: Jes Sorensen +L: linux-wireless@vger.kernel.org +T: git git://git.kernel.org/pub/scm/linux/kernel/git/jes/linux.git rtl8723au-mac80211 +S: Maintained +F: drivers/net/wireless/realtek/rtl8xxxu/ + S3 SAVAGE FRAMEBUFFER DRIVER M: Antonino Daplas L: linux-fbdev@vger.kernel.org diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 91907c4b8bcf..f9f94229bf1b 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -279,6 +279,7 @@ source "drivers/net/wireless/p54/Kconfig" source "drivers/net/wireless/rt2x00/Kconfig" source "drivers/net/wireless/mediatek/Kconfig" source "drivers/net/wireless/realtek/rtlwifi/Kconfig" +source "drivers/net/wireless/realtek/rtl8xxxu/Kconfig" source "drivers/net/wireless/ti/Kconfig" source "drivers/net/wireless/zd1211rw/Kconfig" source "drivers/net/wireless/mwifiex/Kconfig" diff --git a/drivers/net/wireless/realtek/Makefile b/drivers/net/wireless/realtek/Makefile index 3489b98979f8..9c78deb5eea9 100644 --- a/drivers/net/wireless/realtek/Makefile +++ b/drivers/net/wireless/realtek/Makefile @@ -5,4 +5,5 @@ obj-$(CONFIG_RTL8180) += rtl818x/ obj-$(CONFIG_RTL8187) += rtl818x/ obj-$(CONFIG_RTLWIFI) += rtlwifi/ +obj-$(CONFIG_RTL8XXXU) += rtl8xxxu/ diff --git a/drivers/net/wireless/realtek/rtl8xxxu/Kconfig b/drivers/net/wireless/realtek/rtl8xxxu/Kconfig new file mode 100644 index 000000000000..dd4d626aecbc --- /dev/null +++ b/drivers/net/wireless/realtek/rtl8xxxu/Kconfig @@ -0,0 +1,34 @@ +# +# RTL8XXXU Wireless LAN device configuration +# +config RTL8XXXU + tristate "RTL8723AU/RTL8188[CR]U/RTL819[12]CU (mac80211) support" + depends on MAC80211 && USB + ---help--- + This is an alternative driver for various Realtek RTL8XXX + parts written to utilize the Linux mac80211 stack. + The driver is known to work with a number of RTL8723AU, + RL8188CU, RTL8188RU, RTL8191CU, and RTL8192CU devices + + This driver is under development and has a limited feature + set. In particular it does not yet support 40MHz channels + and power management. However it should have a smaller + memory footprint than the vendor drivers and benetifs + from the in kernel mac80211 stack. + + It can coexist with drivers from drivers/staging/rtl8723au, + drivers/staging/rtl8192u, and drivers/net/wireless/rtlwifi, + but you will need to control which module you wish to load. + + To compile this driver as a module, choose M here: the module will + be called r8xxxu. If unsure, say N. + +config RTL8XXXU_UNTESTED + bool "Include support for untested Realtek 8xxx USB devices (EXPERIMENTAL)" + depends on RTL8XXXU + ---help--- + This option enables detection of Realtek 8723/8188/8191/8192 WiFi + USB devices which have not been tested directly by the driver + author or reported to be working by third parties. + + Please report your results! diff --git a/drivers/net/wireless/realtek/rtl8xxxu/Makefile b/drivers/net/wireless/realtek/rtl8xxxu/Makefile new file mode 100644 index 000000000000..5dea3bb93069 --- /dev/null +++ b/drivers/net/wireless/realtek/rtl8xxxu/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_RTL8XXXU) += rtl8xxxu.o diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c new file mode 100644 index 000000000000..47e52ad56144 --- /dev/null +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c @@ -0,0 +1,5976 @@ +/* + * RTL8XXXU mac80211 USB driver + * + * Copyright (c) 2014 - 2015 Jes Sorensen + * + * Portions, notably calibration code: + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This driver was written as a replacement for the vendor provided + * rtl8723au driver. As the Realtek 8xxx chips are very similar in + * their programming interface, I have started adding support for + * additional 8xxx chips like the 8192cu, 8188cus, etc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rtl8xxxu.h" +#include "rtl8xxxu_regs.h" + +#define DRIVER_NAME "rtl8xxxu" + +static int rtl8xxxu_debug; +static bool rtl8xxxu_ht40_2g; + +MODULE_AUTHOR("Jes Sorensen "); +MODULE_DESCRIPTION("RTL8XXXu USB mac80211 Wireless LAN Driver"); +MODULE_LICENSE("GPL"); +MODULE_FIRMWARE("rtlwifi/rtl8723aufw_A.bin"); +MODULE_FIRMWARE("rtlwifi/rtl8723aufw_B.bin"); +MODULE_FIRMWARE("rtlwifi/rtl8723aufw_B_NoBT.bin"); +MODULE_FIRMWARE("rtlwifi/rtl8192cufw_A.bin"); +MODULE_FIRMWARE("rtlwifi/rtl8192cufw_B.bin"); +MODULE_FIRMWARE("rtlwifi/rtl8192cufw_TMSC.bin"); + +module_param_named(debug, rtl8xxxu_debug, int, 0600); +MODULE_PARM_DESC(debug, "Set debug mask"); +module_param_named(ht40_2g, rtl8xxxu_ht40_2g, bool, 0600); +MODULE_PARM_DESC(ht40_2g, "Enable HT40 support on the 2.4GHz band"); + +#define USB_VENDOR_ID_REALTEK 0x0bda +/* Minimum IEEE80211_MAX_FRAME_LEN */ +#define RTL_RX_BUFFER_SIZE IEEE80211_MAX_FRAME_LEN +#define RTL8XXXU_RX_URBS 32 +#define RTL8XXXU_RX_URB_PENDING_WATER 8 +#define RTL8XXXU_TX_URBS 64 +#define RTL8XXXU_TX_URB_LOW_WATER 25 +#define RTL8XXXU_TX_URB_HIGH_WATER 32 + +static int rtl8xxxu_submit_rx_urb(struct rtl8xxxu_priv *priv, + struct rtl8xxxu_rx_urb *rx_urb); + +static struct ieee80211_rate rtl8xxxu_rates[] = { + { .bitrate = 10, .hw_value = DESC_RATE_1M, .flags = 0 }, + { .bitrate = 20, .hw_value = DESC_RATE_2M, .flags = 0 }, + { .bitrate = 55, .hw_value = DESC_RATE_5_5M, .flags = 0 }, + { .bitrate = 110, .hw_value = DESC_RATE_11M, .flags = 0 }, + { .bitrate = 60, .hw_value = DESC_RATE_6M, .flags = 0 }, + { .bitrate = 90, .hw_value = DESC_RATE_9M, .flags = 0 }, + { .bitrate = 120, .hw_value = DESC_RATE_12M, .flags = 0 }, + { .bitrate = 180, .hw_value = DESC_RATE_18M, .flags = 0 }, + { .bitrate = 240, .hw_value = DESC_RATE_24M, .flags = 0 }, + { .bitrate = 360, .hw_value = DESC_RATE_36M, .flags = 0 }, + { .bitrate = 480, .hw_value = DESC_RATE_48M, .flags = 0 }, + { .bitrate = 540, .hw_value = DESC_RATE_54M, .flags = 0 }, +}; + +static struct ieee80211_channel rtl8xxxu_channels_2g[] = { + { .band = IEEE80211_BAND_2GHZ, .center_freq = 2412, + .hw_value = 1, .max_power = 30 }, + { .band = IEEE80211_BAND_2GHZ, .center_freq = 2417, + .hw_value = 2, .max_power = 30 }, + { .band = IEEE80211_BAND_2GHZ, .center_freq = 2422, + .hw_value = 3, .max_power = 30 }, + { .band = IEEE80211_BAND_2GHZ, .center_freq = 2427, + .hw_value = 4, .max_power = 30 }, + { .band = IEEE80211_BAND_2GHZ, .center_freq = 2432, + .hw_value = 5, .max_power = 30 }, + { .band = IEEE80211_BAND_2GHZ, .center_freq = 2437, + .hw_value = 6, .max_power = 30 }, + { .band = IEEE80211_BAND_2GHZ, .center_freq = 2442, + .hw_value = 7, .max_power = 30 }, + { .band = IEEE80211_BAND_2GHZ, .center_freq = 2447, + .hw_value = 8, .max_power = 30 }, + { .band = IEEE80211_BAND_2GHZ, .center_freq = 2452, + .hw_value = 9, .max_power = 30 }, + { .band = IEEE80211_BAND_2GHZ, .center_freq = 2457, + .hw_value = 10, .max_power = 30 }, + { .band = IEEE80211_BAND_2GHZ, .center_freq = 2462, + .hw_value = 11, .max_power = 30 }, + { .band = IEEE80211_BAND_2GHZ, .center_freq = 2467, + .hw_value = 12, .max_power = 30 }, + { .band = IEEE80211_BAND_2GHZ, .center_freq = 2472, + .hw_value = 13, .max_power = 30 }, + { .band = IEEE80211_BAND_2GHZ, .center_freq = 2484, + .hw_value = 14, .max_power = 30 } +}; + +static struct ieee80211_supported_band rtl8xxxu_supported_band = { + .channels = rtl8xxxu_channels_2g, + .n_channels = ARRAY_SIZE(rtl8xxxu_channels_2g), + .bitrates = rtl8xxxu_rates, + .n_bitrates = ARRAY_SIZE(rtl8xxxu_rates), +}; + +static struct rtl8xxxu_reg8val rtl8723a_mac_init_table[] = { + {0x420, 0x80}, {0x423, 0x00}, {0x430, 0x00}, {0x431, 0x00}, + {0x432, 0x00}, {0x433, 0x01}, {0x434, 0x04}, {0x435, 0x05}, + {0x436, 0x06}, {0x437, 0x07}, {0x438, 0x00}, {0x439, 0x00}, + {0x43a, 0x00}, {0x43b, 0x01}, {0x43c, 0x04}, {0x43d, 0x05}, + {0x43e, 0x06}, {0x43f, 0x07}, {0x440, 0x5d}, {0x441, 0x01}, + {0x442, 0x00}, {0x444, 0x15}, {0x445, 0xf0}, {0x446, 0x0f}, + {0x447, 0x00}, {0x458, 0x41}, {0x459, 0xa8}, {0x45a, 0x72}, + {0x45b, 0xb9}, {0x460, 0x66}, {0x461, 0x66}, {0x462, 0x08}, + {0x463, 0x03}, {0x4c8, 0xff}, {0x4c9, 0x08}, {0x4cc, 0xff}, + {0x4cd, 0xff}, {0x4ce, 0x01}, {0x500, 0x26}, {0x501, 0xa2}, + {0x502, 0x2f}, {0x503, 0x00}, {0x504, 0x28}, {0x505, 0xa3}, + {0x506, 0x5e}, {0x507, 0x00}, {0x508, 0x2b}, {0x509, 0xa4}, + {0x50a, 0x5e}, {0x50b, 0x00}, {0x50c, 0x4f}, {0x50d, 0xa4}, + {0x50e, 0x00}, {0x50f, 0x00}, {0x512, 0x1c}, {0x514, 0x0a}, + {0x515, 0x10}, {0x516, 0x0a}, {0x517, 0x10}, {0x51a, 0x16}, + {0x524, 0x0f}, {0x525, 0x4f}, {0x546, 0x40}, {0x547, 0x00}, + {0x550, 0x10}, {0x551, 0x10}, {0x559, 0x02}, {0x55a, 0x02}, + {0x55d, 0xff}, {0x605, 0x30}, {0x608, 0x0e}, {0x609, 0x2a}, + {0x652, 0x20}, {0x63c, 0x0a}, {0x63d, 0x0a}, {0x63e, 0x0e}, + {0x63f, 0x0e}, {0x66e, 0x05}, {0x700, 0x21}, {0x701, 0x43}, + {0x702, 0x65}, {0x703, 0x87}, {0x708, 0x21}, {0x709, 0x43}, + {0x70a, 0x65}, {0x70b, 0x87}, {0xffff, 0xff}, +}; + +static struct rtl8xxxu_reg32val rtl8723a_phy_1t_init_table[] = { + {0x800, 0x80040000}, {0x804, 0x00000003}, + {0x808, 0x0000fc00}, {0x80c, 0x0000000a}, + {0x810, 0x10001331}, {0x814, 0x020c3d10}, + {0x818, 0x02200385}, {0x81c, 0x00000000}, + {0x820, 0x01000100}, {0x824, 0x00390004}, + {0x828, 0x00000000}, {0x82c, 0x00000000}, + {0x830, 0x00000000}, {0x834, 0x00000000}, + {0x838, 0x00000000}, {0x83c, 0x00000000}, + {0x840, 0x00010000}, {0x844, 0x00000000}, + {0x848, 0x00000000}, {0x84c, 0x00000000}, + {0x850, 0x00000000}, {0x854, 0x00000000}, + {0x858, 0x569a569a}, {0x85c, 0x001b25a4}, + {0x860, 0x66f60110}, {0x864, 0x061f0130}, + {0x868, 0x00000000}, {0x86c, 0x32323200}, + {0x870, 0x07000760}, {0x874, 0x22004000}, + {0x878, 0x00000808}, {0x87c, 0x00000000}, + {0x880, 0xc0083070}, {0x884, 0x000004d5}, + {0x888, 0x00000000}, {0x88c, 0xccc000c0}, + {0x890, 0x00000800}, {0x894, 0xfffffffe}, + {0x898, 0x40302010}, {0x89c, 0x00706050}, + {0x900, 0x00000000}, {0x904, 0x00000023}, + {0x908, 0x00000000}, {0x90c, 0x81121111}, + {0xa00, 0x00d047c8}, {0xa04, 0x80ff000c}, + {0xa08, 0x8c838300}, {0xa0c, 0x2e68120f}, + {0xa10, 0x9500bb78}, {0xa14, 0x11144028}, + {0xa18, 0x00881117}, {0xa1c, 0x89140f00}, + {0xa20, 0x1a1b0000}, {0xa24, 0x090e1317}, + {0xa28, 0x00000204}, {0xa2c, 0x00d30000}, + {0xa70, 0x101fbf00}, {0xa74, 0x00000007}, + {0xa78, 0x00000900}, + {0xc00, 0x48071d40}, {0xc04, 0x03a05611}, + {0xc08, 0x000000e4}, {0xc0c, 0x6c6c6c6c}, + {0xc10, 0x08800000}, {0xc14, 0x40000100}, + {0xc18, 0x08800000}, {0xc1c, 0x40000100}, + {0xc20, 0x00000000}, {0xc24, 0x00000000}, + {0xc28, 0x00000000}, {0xc2c, 0x00000000}, + {0xc30, 0x69e9ac44}, {0xc34, 0x469652af}, + {0xc38, 0x49795994}, {0xc3c, 0x0a97971c}, + {0xc40, 0x1f7c403f}, {0xc44, 0x000100b7}, + {0xc48, 0xec020107}, {0xc4c, 0x007f037f}, + {0xc50, 0x69543420}, {0xc54, 0x43bc0094}, + {0xc58, 0x69543420}, {0xc5c, 0x433c0094}, + {0xc60, 0x00000000}, {0xc64, 0x7112848b}, + {0xc68, 0x47c00bff}, {0xc6c, 0x00000036}, + {0xc70, 0x2c7f000d}, {0xc74, 0x018610db}, + {0xc78, 0x0000001f}, {0xc7c, 0x00b91612}, + {0xc80, 0x40000100}, {0xc84, 0x20f60000}, + {0xc88, 0x40000100}, {0xc8c, 0x20200000}, + {0xc90, 0x00121820}, {0xc94, 0x00000000}, + {0xc98, 0x00121820}, {0xc9c, 0x00007f7f}, + {0xca0, 0x00000000}, {0xca4, 0x00000080}, + {0xca8, 0x00000000}, {0xcac, 0x00000000}, + {0xcb0, 0x00000000}, {0xcb4, 0x00000000}, + {0xcb8, 0x00000000}, {0xcbc, 0x28000000}, + {0xcc0, 0x00000000}, {0xcc4, 0x00000000}, + {0xcc8, 0x00000000}, {0xccc, 0x00000000}, + {0xcd0, 0x00000000}, {0xcd4, 0x00000000}, + {0xcd8, 0x64b22427}, {0xcdc, 0x00766932}, + {0xce0, 0x00222222}, {0xce4, 0x00000000}, + {0xce8, 0x37644302}, {0xcec, 0x2f97d40c}, + {0xd00, 0x00080740}, {0xd04, 0x00020401}, + {0xd08, 0x0000907f}, {0xd0c, 0x20010201}, + {0xd10, 0xa0633333}, {0xd14, 0x3333bc43}, + {0xd18, 0x7a8f5b6b}, {0xd2c, 0xcc979975}, + {0xd30, 0x00000000}, {0xd34, 0x80608000}, + {0xd38, 0x00000000}, {0xd3c, 0x00027293}, + {0xd40, 0x00000000}, {0xd44, 0x00000000}, + {0xd48, 0x00000000}, {0xd4c, 0x00000000}, + {0xd50, 0x6437140a}, {0xd54, 0x00000000}, + {0xd58, 0x00000000}, {0xd5c, 0x30032064}, + {0xd60, 0x4653de68}, {0xd64, 0x04518a3c}, + {0xd68, 0x00002101}, {0xd6c, 0x2a201c16}, + {0xd70, 0x1812362e}, {0xd74, 0x322c2220}, + {0xd78, 0x000e3c24}, {0xe00, 0x2a2a2a2a}, + {0xe04, 0x2a2a2a2a}, {0xe08, 0x03902a2a}, + {0xe10, 0x2a2a2a2a}, {0xe14, 0x2a2a2a2a}, + {0xe18, 0x2a2a2a2a}, {0xe1c, 0x2a2a2a2a}, + {0xe28, 0x00000000}, {0xe30, 0x1000dc1f}, + {0xe34, 0x10008c1f}, {0xe38, 0x02140102}, + {0xe3c, 0x681604c2}, {0xe40, 0x01007c00}, + {0xe44, 0x01004800}, {0xe48, 0xfb000000}, + {0xe4c, 0x000028d1}, {0xe50, 0x1000dc1f}, + {0xe54, 0x10008c1f}, {0xe58, 0x02140102}, + {0xe5c, 0x28160d05}, {0xe60, 0x00000008}, + {0xe68, 0x001b25a4}, {0xe6c, 0x631b25a0}, + {0xe70, 0x631b25a0}, {0xe74, 0x081b25a0}, + {0xe78, 0x081b25a0}, {0xe7c, 0x081b25a0}, + {0xe80, 0x081b25a0}, {0xe84, 0x631b25a0}, + {0xe88, 0x081b25a0}, {0xe8c, 0x631b25a0}, + {0xed0, 0x631b25a0}, {0xed4, 0x631b25a0}, + {0xed8, 0x631b25a0}, {0xedc, 0x001b25a0}, + {0xee0, 0x001b25a0}, {0xeec, 0x6b1b25a0}, + {0xf14, 0x00000003}, {0xf4c, 0x00000000}, + {0xf00, 0x00000300}, + {0xffff, 0xffffffff}, +}; + +static struct rtl8xxxu_reg32val rtl8192cu_phy_2t_init_table[] = { + {0x024, 0x0011800f}, {0x028, 0x00ffdb83}, + {0x800, 0x80040002}, {0x804, 0x00000003}, + {0x808, 0x0000fc00}, {0x80c, 0x0000000a}, + {0x810, 0x10000330}, {0x814, 0x020c3d10}, + {0x818, 0x02200385}, {0x81c, 0x00000000}, + {0x820, 0x01000100}, {0x824, 0x00390004}, + {0x828, 0x01000100}, {0x82c, 0x00390004}, + {0x830, 0x27272727}, {0x834, 0x27272727}, + {0x838, 0x27272727}, {0x83c, 0x27272727}, + {0x840, 0x00010000}, {0x844, 0x00010000}, + {0x848, 0x27272727}, {0x84c, 0x27272727}, + {0x850, 0x00000000}, {0x854, 0x00000000}, + {0x858, 0x569a569a}, {0x85c, 0x0c1b25a4}, + {0x860, 0x66e60230}, {0x864, 0x061f0130}, + {0x868, 0x27272727}, {0x86c, 0x2b2b2b27}, + {0x870, 0x07000700}, {0x874, 0x22184000}, + {0x878, 0x08080808}, {0x87c, 0x00000000}, + {0x880, 0xc0083070}, {0x884, 0x000004d5}, + {0x888, 0x00000000}, {0x88c, 0xcc0000c0}, + {0x890, 0x00000800}, {0x894, 0xfffffffe}, + {0x898, 0x40302010}, {0x89c, 0x00706050}, + {0x900, 0x00000000}, {0x904, 0x00000023}, + {0x908, 0x00000000}, {0x90c, 0x81121313}, + {0xa00, 0x00d047c8}, {0xa04, 0x80ff000c}, + {0xa08, 0x8c838300}, {0xa0c, 0x2e68120f}, + {0xa10, 0x9500bb78}, {0xa14, 0x11144028}, + {0xa18, 0x00881117}, {0xa1c, 0x89140f00}, + {0xa20, 0x1a1b0000}, {0xa24, 0x090e1317}, + {0xa28, 0x00000204}, {0xa2c, 0x00d30000}, + {0xa70, 0x101fbf00}, {0xa74, 0x00000007}, + {0xc00, 0x48071d40}, {0xc04, 0x03a05633}, + {0xc08, 0x000000e4}, {0xc0c, 0x6c6c6c6c}, + {0xc10, 0x08800000}, {0xc14, 0x40000100}, + {0xc18, 0x08800000}, {0xc1c, 0x40000100}, + {0xc20, 0x00000000}, {0xc24, 0x00000000}, + {0xc28, 0x00000000}, {0xc2c, 0x00000000}, + {0xc30, 0x69e9ac44}, {0xc34, 0x469652cf}, + {0xc38, 0x49795994}, {0xc3c, 0x0a97971c}, + {0xc40, 0x1f7c403f}, {0xc44, 0x000100b7}, + {0xc48, 0xec020107}, {0xc4c, 0x007f037f}, + {0xc50, 0x69543420}, {0xc54, 0x43bc0094}, + {0xc58, 0x69543420}, {0xc5c, 0x433c0094}, + {0xc60, 0x00000000}, {0xc64, 0x5116848b}, + {0xc68, 0x47c00bff}, {0xc6c, 0x00000036}, + {0xc70, 0x2c7f000d}, {0xc74, 0x2186115b}, + {0xc78, 0x0000001f}, {0xc7c, 0x00b99612}, + {0xc80, 0x40000100}, {0xc84, 0x20f60000}, + {0xc88, 0x40000100}, {0xc8c, 0xa0e40000}, + {0xc90, 0x00121820}, {0xc94, 0x00000000}, + {0xc98, 0x00121820}, {0xc9c, 0x00007f7f}, + {0xca0, 0x00000000}, {0xca4, 0x00000080}, + {0xca8, 0x00000000}, {0xcac, 0x00000000}, + {0xcb0, 0x00000000}, {0xcb4, 0x00000000}, + {0xcb8, 0x00000000}, {0xcbc, 0x28000000}, + {0xcc0, 0x00000000}, {0xcc4, 0x00000000}, + {0xcc8, 0x00000000}, {0xccc, 0x00000000}, + {0xcd0, 0x00000000}, {0xcd4, 0x00000000}, + {0xcd8, 0x64b22427}, {0xcdc, 0x00766932}, + {0xce0, 0x00222222}, {0xce4, 0x00000000}, + {0xce8, 0x37644302}, {0xcec, 0x2f97d40c}, + {0xd00, 0x00080740}, {0xd04, 0x00020403}, + {0xd08, 0x0000907f}, {0xd0c, 0x20010201}, + {0xd10, 0xa0633333}, {0xd14, 0x3333bc43}, + {0xd18, 0x7a8f5b6b}, {0xd2c, 0xcc979975}, + {0xd30, 0x00000000}, {0xd34, 0x80608000}, + {0xd38, 0x00000000}, {0xd3c, 0x00027293}, + {0xd40, 0x00000000}, {0xd44, 0x00000000}, + {0xd48, 0x00000000}, {0xd4c, 0x00000000}, + {0xd50, 0x6437140a}, {0xd54, 0x00000000}, + {0xd58, 0x00000000}, {0xd5c, 0x30032064}, + {0xd60, 0x4653de68}, {0xd64, 0x04518a3c}, + {0xd68, 0x00002101}, {0xd6c, 0x2a201c16}, + {0xd70, 0x1812362e}, {0xd74, 0x322c2220}, + {0xd78, 0x000e3c24}, {0xe00, 0x2a2a2a2a}, + {0xe04, 0x2a2a2a2a}, {0xe08, 0x03902a2a}, + {0xe10, 0x2a2a2a2a}, {0xe14, 0x2a2a2a2a}, + {0xe18, 0x2a2a2a2a}, {0xe1c, 0x2a2a2a2a}, + {0xe28, 0x00000000}, {0xe30, 0x1000dc1f}, + {0xe34, 0x10008c1f}, {0xe38, 0x02140102}, + {0xe3c, 0x681604c2}, {0xe40, 0x01007c00}, + {0xe44, 0x01004800}, {0xe48, 0xfb000000}, + {0xe4c, 0x000028d1}, {0xe50, 0x1000dc1f}, + {0xe54, 0x10008c1f}, {0xe58, 0x02140102}, + {0xe5c, 0x28160d05}, {0xe60, 0x00000010}, + {0xe68, 0x001b25a4}, {0xe6c, 0x63db25a4}, + {0xe70, 0x63db25a4}, {0xe74, 0x0c1b25a4}, + {0xe78, 0x0c1b25a4}, {0xe7c, 0x0c1b25a4}, + {0xe80, 0x0c1b25a4}, {0xe84, 0x63db25a4}, + {0xe88, 0x0c1b25a4}, {0xe8c, 0x63db25a4}, + {0xed0, 0x63db25a4}, {0xed4, 0x63db25a4}, + {0xed8, 0x63db25a4}, {0xedc, 0x001b25a4}, + {0xee0, 0x001b25a4}, {0xeec, 0x6fdb25a4}, + {0xf14, 0x00000003}, {0xf4c, 0x00000000}, + {0xf00, 0x00000300}, + {0xffff, 0xffffffff}, +}; + +static struct rtl8xxxu_reg32val rtl8188ru_phy_1t_highpa_table[] = { + {0x024, 0x0011800f}, {0x028, 0x00ffdb83}, + {0x040, 0x000c0004}, {0x800, 0x80040000}, + {0x804, 0x00000001}, {0x808, 0x0000fc00}, + {0x80c, 0x0000000a}, {0x810, 0x10005388}, + {0x814, 0x020c3d10}, {0x818, 0x02200385}, + {0x81c, 0x00000000}, {0x820, 0x01000100}, + {0x824, 0x00390204}, {0x828, 0x00000000}, + {0x82c, 0x00000000}, {0x830, 0x00000000}, + {0x834, 0x00000000}, {0x838, 0x00000000}, + {0x83c, 0x00000000}, {0x840, 0x00010000}, + {0x844, 0x00000000}, {0x848, 0x00000000}, + {0x84c, 0x00000000}, {0x850, 0x00000000}, + {0x854, 0x00000000}, {0x858, 0x569a569a}, + {0x85c, 0x001b25a4}, {0x860, 0x66e60230}, + {0x864, 0x061f0130}, {0x868, 0x00000000}, + {0x86c, 0x20202000}, {0x870, 0x03000300}, + {0x874, 0x22004000}, {0x878, 0x00000808}, + {0x87c, 0x00ffc3f1}, {0x880, 0xc0083070}, + {0x884, 0x000004d5}, {0x888, 0x00000000}, + {0x88c, 0xccc000c0}, {0x890, 0x00000800}, + {0x894, 0xfffffffe}, {0x898, 0x40302010}, + {0x89c, 0x00706050}, {0x900, 0x00000000}, + {0x904, 0x00000023}, {0x908, 0x00000000}, + {0x90c, 0x81121111}, {0xa00, 0x00d047c8}, + {0xa04, 0x80ff000c}, {0xa08, 0x8c838300}, + {0xa0c, 0x2e68120f}, {0xa10, 0x9500bb78}, + {0xa14, 0x11144028}, {0xa18, 0x00881117}, + {0xa1c, 0x89140f00}, {0xa20, 0x15160000}, + {0xa24, 0x070b0f12}, {0xa28, 0x00000104}, + {0xa2c, 0x00d30000}, {0xa70, 0x101fbf00}, + {0xa74, 0x00000007}, {0xc00, 0x48071d40}, + {0xc04, 0x03a05611}, {0xc08, 0x000000e4}, + {0xc0c, 0x6c6c6c6c}, {0xc10, 0x08800000}, + {0xc14, 0x40000100}, {0xc18, 0x08800000}, + {0xc1c, 0x40000100}, {0xc20, 0x00000000}, + {0xc24, 0x00000000}, {0xc28, 0x00000000}, + {0xc2c, 0x00000000}, {0xc30, 0x69e9ac44}, + {0xc34, 0x469652cf}, {0xc38, 0x49795994}, + {0xc3c, 0x0a97971c}, {0xc40, 0x1f7c403f}, + {0xc44, 0x000100b7}, {0xc48, 0xec020107}, + {0xc4c, 0x007f037f}, {0xc50, 0x6954342e}, + {0xc54, 0x43bc0094}, {0xc58, 0x6954342f}, + {0xc5c, 0x433c0094}, {0xc60, 0x00000000}, + {0xc64, 0x5116848b}, {0xc68, 0x47c00bff}, + {0xc6c, 0x00000036}, {0xc70, 0x2c46000d}, + {0xc74, 0x018610db}, {0xc78, 0x0000001f}, + {0xc7c, 0x00b91612}, {0xc80, 0x24000090}, + {0xc84, 0x20f60000}, {0xc88, 0x24000090}, + {0xc8c, 0x20200000}, {0xc90, 0x00121820}, + {0xc94, 0x00000000}, {0xc98, 0x00121820}, + {0xc9c, 0x00007f7f}, {0xca0, 0x00000000}, + {0xca4, 0x00000080}, {0xca8, 0x00000000}, + {0xcac, 0x00000000}, {0xcb0, 0x00000000}, + {0xcb4, 0x00000000}, {0xcb8, 0x00000000}, + {0xcbc, 0x28000000}, {0xcc0, 0x00000000}, + {0xcc4, 0x00000000}, {0xcc8, 0x00000000}, + {0xccc, 0x00000000}, {0xcd0, 0x00000000}, + {0xcd4, 0x00000000}, {0xcd8, 0x64b22427}, + {0xcdc, 0x00766932}, {0xce0, 0x00222222}, + {0xce4, 0x00000000}, {0xce8, 0x37644302}, + {0xcec, 0x2f97d40c}, {0xd00, 0x00080740}, + {0xd04, 0x00020401}, {0xd08, 0x0000907f}, + {0xd0c, 0x20010201}, {0xd10, 0xa0633333}, + {0xd14, 0x3333bc43}, {0xd18, 0x7a8f5b6b}, + {0xd2c, 0xcc979975}, {0xd30, 0x00000000}, + {0xd34, 0x80608000}, {0xd38, 0x00000000}, + {0xd3c, 0x00027293}, {0xd40, 0x00000000}, + {0xd44, 0x00000000}, {0xd48, 0x00000000}, + {0xd4c, 0x00000000}, {0xd50, 0x6437140a}, + {0xd54, 0x00000000}, {0xd58, 0x00000000}, + {0xd5c, 0x30032064}, {0xd60, 0x4653de68}, + {0xd64, 0x04518a3c}, {0xd68, 0x00002101}, + {0xd6c, 0x2a201c16}, {0xd70, 0x1812362e}, + {0xd74, 0x322c2220}, {0xd78, 0x000e3c24}, + {0xe00, 0x24242424}, {0xe04, 0x24242424}, + {0xe08, 0x03902024}, {0xe10, 0x24242424}, + {0xe14, 0x24242424}, {0xe18, 0x24242424}, + {0xe1c, 0x24242424}, {0xe28, 0x00000000}, + {0xe30, 0x1000dc1f}, {0xe34, 0x10008c1f}, + {0xe38, 0x02140102}, {0xe3c, 0x681604c2}, + {0xe40, 0x01007c00}, {0xe44, 0x01004800}, + {0xe48, 0xfb000000}, {0xe4c, 0x000028d1}, + {0xe50, 0x1000dc1f}, {0xe54, 0x10008c1f}, + {0xe58, 0x02140102}, {0xe5c, 0x28160d05}, + {0xe60, 0x00000008}, {0xe68, 0x001b25a4}, + {0xe6c, 0x631b25a0}, {0xe70, 0x631b25a0}, + {0xe74, 0x081b25a0}, {0xe78, 0x081b25a0}, + {0xe7c, 0x081b25a0}, {0xe80, 0x081b25a0}, + {0xe84, 0x631b25a0}, {0xe88, 0x081b25a0}, + {0xe8c, 0x631b25a0}, {0xed0, 0x631b25a0}, + {0xed4, 0x631b25a0}, {0xed8, 0x631b25a0}, + {0xedc, 0x001b25a0}, {0xee0, 0x001b25a0}, + {0xeec, 0x6b1b25a0}, {0xee8, 0x31555448}, + {0xf14, 0x00000003}, {0xf4c, 0x00000000}, + {0xf00, 0x00000300}, + {0xffff, 0xffffffff}, +}; + +static struct rtl8xxxu_reg32val rtl8xxx_agc_standard_table[] = { + {0xc78, 0x7b000001}, {0xc78, 0x7b010001}, + {0xc78, 0x7b020001}, {0xc78, 0x7b030001}, + {0xc78, 0x7b040001}, {0xc78, 0x7b050001}, + {0xc78, 0x7a060001}, {0xc78, 0x79070001}, + {0xc78, 0x78080001}, {0xc78, 0x77090001}, + {0xc78, 0x760a0001}, {0xc78, 0x750b0001}, + {0xc78, 0x740c0001}, {0xc78, 0x730d0001}, + {0xc78, 0x720e0001}, {0xc78, 0x710f0001}, + {0xc78, 0x70100001}, {0xc78, 0x6f110001}, + {0xc78, 0x6e120001}, {0xc78, 0x6d130001}, + {0xc78, 0x6c140001}, {0xc78, 0x6b150001}, + {0xc78, 0x6a160001}, {0xc78, 0x69170001}, + {0xc78, 0x68180001}, {0xc78, 0x67190001}, + {0xc78, 0x661a0001}, {0xc78, 0x651b0001}, + {0xc78, 0x641c0001}, {0xc78, 0x631d0001}, + {0xc78, 0x621e0001}, {0xc78, 0x611f0001}, + {0xc78, 0x60200001}, {0xc78, 0x49210001}, + {0xc78, 0x48220001}, {0xc78, 0x47230001}, + {0xc78, 0x46240001}, {0xc78, 0x45250001}, + {0xc78, 0x44260001}, {0xc78, 0x43270001}, + {0xc78, 0x42280001}, {0xc78, 0x41290001}, + {0xc78, 0x402a0001}, {0xc78, 0x262b0001}, + {0xc78, 0x252c0001}, {0xc78, 0x242d0001}, + {0xc78, 0x232e0001}, {0xc78, 0x222f0001}, + {0xc78, 0x21300001}, {0xc78, 0x20310001}, + {0xc78, 0x06320001}, {0xc78, 0x05330001}, + {0xc78, 0x04340001}, {0xc78, 0x03350001}, + {0xc78, 0x02360001}, {0xc78, 0x01370001}, + {0xc78, 0x00380001}, {0xc78, 0x00390001}, + {0xc78, 0x003a0001}, {0xc78, 0x003b0001}, + {0xc78, 0x003c0001}, {0xc78, 0x003d0001}, + {0xc78, 0x003e0001}, {0xc78, 0x003f0001}, + {0xc78, 0x7b400001}, {0xc78, 0x7b410001}, + {0xc78, 0x7b420001}, {0xc78, 0x7b430001}, + {0xc78, 0x7b440001}, {0xc78, 0x7b450001}, + {0xc78, 0x7a460001}, {0xc78, 0x79470001}, + {0xc78, 0x78480001}, {0xc78, 0x77490001}, + {0xc78, 0x764a0001}, {0xc78, 0x754b0001}, + {0xc78, 0x744c0001}, {0xc78, 0x734d0001}, + {0xc78, 0x724e0001}, {0xc78, 0x714f0001}, + {0xc78, 0x70500001}, {0xc78, 0x6f510001}, + {0xc78, 0x6e520001}, {0xc78, 0x6d530001}, + {0xc78, 0x6c540001}, {0xc78, 0x6b550001}, + {0xc78, 0x6a560001}, {0xc78, 0x69570001}, + {0xc78, 0x68580001}, {0xc78, 0x67590001}, + {0xc78, 0x665a0001}, {0xc78, 0x655b0001}, + {0xc78, 0x645c0001}, {0xc78, 0x635d0001}, + {0xc78, 0x625e0001}, {0xc78, 0x615f0001}, + {0xc78, 0x60600001}, {0xc78, 0x49610001}, + {0xc78, 0x48620001}, {0xc78, 0x47630001}, + {0xc78, 0x46640001}, {0xc78, 0x45650001}, + {0xc78, 0x44660001}, {0xc78, 0x43670001}, + {0xc78, 0x42680001}, {0xc78, 0x41690001}, + {0xc78, 0x406a0001}, {0xc78, 0x266b0001}, + {0xc78, 0x256c0001}, {0xc78, 0x246d0001}, + {0xc78, 0x236e0001}, {0xc78, 0x226f0001}, + {0xc78, 0x21700001}, {0xc78, 0x20710001}, + {0xc78, 0x06720001}, {0xc78, 0x05730001}, + {0xc78, 0x04740001}, {0xc78, 0x03750001}, + {0xc78, 0x02760001}, {0xc78, 0x01770001}, + {0xc78, 0x00780001}, {0xc78, 0x00790001}, + {0xc78, 0x007a0001}, {0xc78, 0x007b0001}, + {0xc78, 0x007c0001}, {0xc78, 0x007d0001}, + {0xc78, 0x007e0001}, {0xc78, 0x007f0001}, + {0xc78, 0x3800001e}, {0xc78, 0x3801001e}, + {0xc78, 0x3802001e}, {0xc78, 0x3803001e}, + {0xc78, 0x3804001e}, {0xc78, 0x3805001e}, + {0xc78, 0x3806001e}, {0xc78, 0x3807001e}, + {0xc78, 0x3808001e}, {0xc78, 0x3c09001e}, + {0xc78, 0x3e0a001e}, {0xc78, 0x400b001e}, + {0xc78, 0x440c001e}, {0xc78, 0x480d001e}, + {0xc78, 0x4c0e001e}, {0xc78, 0x500f001e}, + {0xc78, 0x5210001e}, {0xc78, 0x5611001e}, + {0xc78, 0x5a12001e}, {0xc78, 0x5e13001e}, + {0xc78, 0x6014001e}, {0xc78, 0x6015001e}, + {0xc78, 0x6016001e}, {0xc78, 0x6217001e}, + {0xc78, 0x6218001e}, {0xc78, 0x6219001e}, + {0xc78, 0x621a001e}, {0xc78, 0x621b001e}, + {0xc78, 0x621c001e}, {0xc78, 0x621d001e}, + {0xc78, 0x621e001e}, {0xc78, 0x621f001e}, + {0xffff, 0xffffffff} +}; + +static struct rtl8xxxu_reg32val rtl8xxx_agc_highpa_table[] = { + {0xc78, 0x7b000001}, {0xc78, 0x7b010001}, + {0xc78, 0x7b020001}, {0xc78, 0x7b030001}, + {0xc78, 0x7b040001}, {0xc78, 0x7b050001}, + {0xc78, 0x7b060001}, {0xc78, 0x7b070001}, + {0xc78, 0x7b080001}, {0xc78, 0x7a090001}, + {0xc78, 0x790a0001}, {0xc78, 0x780b0001}, + {0xc78, 0x770c0001}, {0xc78, 0x760d0001}, + {0xc78, 0x750e0001}, {0xc78, 0x740f0001}, + {0xc78, 0x73100001}, {0xc78, 0x72110001}, + {0xc78, 0x71120001}, {0xc78, 0x70130001}, + {0xc78, 0x6f140001}, {0xc78, 0x6e150001}, + {0xc78, 0x6d160001}, {0xc78, 0x6c170001}, + {0xc78, 0x6b180001}, {0xc78, 0x6a190001}, + {0xc78, 0x691a0001}, {0xc78, 0x681b0001}, + {0xc78, 0x671c0001}, {0xc78, 0x661d0001}, + {0xc78, 0x651e0001}, {0xc78, 0x641f0001}, + {0xc78, 0x63200001}, {0xc78, 0x62210001}, + {0xc78, 0x61220001}, {0xc78, 0x60230001}, + {0xc78, 0x46240001}, {0xc78, 0x45250001}, + {0xc78, 0x44260001}, {0xc78, 0x43270001}, + {0xc78, 0x42280001}, {0xc78, 0x41290001}, + {0xc78, 0x402a0001}, {0xc78, 0x262b0001}, + {0xc78, 0x252c0001}, {0xc78, 0x242d0001}, + {0xc78, 0x232e0001}, {0xc78, 0x222f0001}, + {0xc78, 0x21300001}, {0xc78, 0x20310001}, + {0xc78, 0x06320001}, {0xc78, 0x05330001}, + {0xc78, 0x04340001}, {0xc78, 0x03350001}, + {0xc78, 0x02360001}, {0xc78, 0x01370001}, + {0xc78, 0x00380001}, {0xc78, 0x00390001}, + {0xc78, 0x003a0001}, {0xc78, 0x003b0001}, + {0xc78, 0x003c0001}, {0xc78, 0x003d0001}, + {0xc78, 0x003e0001}, {0xc78, 0x003f0001}, + {0xc78, 0x7b400001}, {0xc78, 0x7b410001}, + {0xc78, 0x7b420001}, {0xc78, 0x7b430001}, + {0xc78, 0x7b440001}, {0xc78, 0x7b450001}, + {0xc78, 0x7b460001}, {0xc78, 0x7b470001}, + {0xc78, 0x7b480001}, {0xc78, 0x7a490001}, + {0xc78, 0x794a0001}, {0xc78, 0x784b0001}, + {0xc78, 0x774c0001}, {0xc78, 0x764d0001}, + {0xc78, 0x754e0001}, {0xc78, 0x744f0001}, + {0xc78, 0x73500001}, {0xc78, 0x72510001}, + {0xc78, 0x71520001}, {0xc78, 0x70530001}, + {0xc78, 0x6f540001}, {0xc78, 0x6e550001}, + {0xc78, 0x6d560001}, {0xc78, 0x6c570001}, + {0xc78, 0x6b580001}, {0xc78, 0x6a590001}, + {0xc78, 0x695a0001}, {0xc78, 0x685b0001}, + {0xc78, 0x675c0001}, {0xc78, 0x665d0001}, + {0xc78, 0x655e0001}, {0xc78, 0x645f0001}, + {0xc78, 0x63600001}, {0xc78, 0x62610001}, + {0xc78, 0x61620001}, {0xc78, 0x60630001}, + {0xc78, 0x46640001}, {0xc78, 0x45650001}, + {0xc78, 0x44660001}, {0xc78, 0x43670001}, + {0xc78, 0x42680001}, {0xc78, 0x41690001}, + {0xc78, 0x406a0001}, {0xc78, 0x266b0001}, + {0xc78, 0x256c0001}, {0xc78, 0x246d0001}, + {0xc78, 0x236e0001}, {0xc78, 0x226f0001}, + {0xc78, 0x21700001}, {0xc78, 0x20710001}, + {0xc78, 0x06720001}, {0xc78, 0x05730001}, + {0xc78, 0x04740001}, {0xc78, 0x03750001}, + {0xc78, 0x02760001}, {0xc78, 0x01770001}, + {0xc78, 0x00780001}, {0xc78, 0x00790001}, + {0xc78, 0x007a0001}, {0xc78, 0x007b0001}, + {0xc78, 0x007c0001}, {0xc78, 0x007d0001}, + {0xc78, 0x007e0001}, {0xc78, 0x007f0001}, + {0xc78, 0x3800001e}, {0xc78, 0x3801001e}, + {0xc78, 0x3802001e}, {0xc78, 0x3803001e}, + {0xc78, 0x3804001e}, {0xc78, 0x3805001e}, + {0xc78, 0x3806001e}, {0xc78, 0x3807001e}, + {0xc78, 0x3808001e}, {0xc78, 0x3c09001e}, + {0xc78, 0x3e0a001e}, {0xc78, 0x400b001e}, + {0xc78, 0x440c001e}, {0xc78, 0x480d001e}, + {0xc78, 0x4c0e001e}, {0xc78, 0x500f001e}, + {0xc78, 0x5210001e}, {0xc78, 0x5611001e}, + {0xc78, 0x5a12001e}, {0xc78, 0x5e13001e}, + {0xc78, 0x6014001e}, {0xc78, 0x6015001e}, + {0xc78, 0x6016001e}, {0xc78, 0x6217001e}, + {0xc78, 0x6218001e}, {0xc78, 0x6219001e}, + {0xc78, 0x621a001e}, {0xc78, 0x621b001e}, + {0xc78, 0x621c001e}, {0xc78, 0x621d001e}, + {0xc78, 0x621e001e}, {0xc78, 0x621f001e}, + {0xffff, 0xffffffff} +}; + +static struct rtl8xxxu_rfregval rtl8723au_radioa_1t_init_table[] = { + {0x00, 0x00030159}, {0x01, 0x00031284}, + {0x02, 0x00098000}, {0x03, 0x00039c63}, + {0x04, 0x000210e7}, {0x09, 0x0002044f}, + {0x0a, 0x0001a3f1}, {0x0b, 0x00014787}, + {0x0c, 0x000896fe}, {0x0d, 0x0000e02c}, + {0x0e, 0x00039ce7}, {0x0f, 0x00000451}, + {0x19, 0x00000000}, {0x1a, 0x00030355}, + {0x1b, 0x00060a00}, {0x1c, 0x000fc378}, + {0x1d, 0x000a1250}, {0x1e, 0x0000024f}, + {0x1f, 0x00000000}, {0x20, 0x0000b614}, + {0x21, 0x0006c000}, {0x22, 0x00000000}, + {0x23, 0x00001558}, {0x24, 0x00000060}, + {0x25, 0x00000483}, {0x26, 0x0004f000}, + {0x27, 0x000ec7d9}, {0x28, 0x00057730}, + {0x29, 0x00004783}, {0x2a, 0x00000001}, + {0x2b, 0x00021334}, {0x2a, 0x00000000}, + {0x2b, 0x00000054}, {0x2a, 0x00000001}, + {0x2b, 0x00000808}, {0x2b, 0x00053333}, + {0x2c, 0x0000000c}, {0x2a, 0x00000002}, + {0x2b, 0x00000808}, {0x2b, 0x0005b333}, + {0x2c, 0x0000000d}, {0x2a, 0x00000003}, + {0x2b, 0x00000808}, {0x2b, 0x00063333}, + {0x2c, 0x0000000d}, {0x2a, 0x00000004}, + {0x2b, 0x00000808}, {0x2b, 0x0006b333}, + {0x2c, 0x0000000d}, {0x2a, 0x00000005}, + {0x2b, 0x00000808}, {0x2b, 0x00073333}, + {0x2c, 0x0000000d}, {0x2a, 0x00000006}, + {0x2b, 0x00000709}, {0x2b, 0x0005b333}, + {0x2c, 0x0000000d}, {0x2a, 0x00000007}, + {0x2b, 0x00000709}, {0x2b, 0x00063333}, + {0x2c, 0x0000000d}, {0x2a, 0x00000008}, + {0x2b, 0x0000060a}, {0x2b, 0x0004b333}, + {0x2c, 0x0000000d}, {0x2a, 0x00000009}, + {0x2b, 0x0000060a}, {0x2b, 0x00053333}, + {0x2c, 0x0000000d}, {0x2a, 0x0000000a}, + {0x2b, 0x0000060a}, {0x2b, 0x0005b333}, + {0x2c, 0x0000000d}, {0x2a, 0x0000000b}, + {0x2b, 0x0000060a}, {0x2b, 0x00063333}, + {0x2c, 0x0000000d}, {0x2a, 0x0000000c}, + {0x2b, 0x0000060a}, {0x2b, 0x0006b333}, + {0x2c, 0x0000000d}, {0x2a, 0x0000000d}, + {0x2b, 0x0000060a}, {0x2b, 0x00073333}, + {0x2c, 0x0000000d}, {0x2a, 0x0000000e}, + {0x2b, 0x0000050b}, {0x2b, 0x00066666}, + {0x2c, 0x0000001a}, {0x2a, 0x000e0000}, + {0x10, 0x0004000f}, {0x11, 0x000e31fc}, + {0x10, 0x0006000f}, {0x11, 0x000ff9f8}, + {0x10, 0x0002000f}, {0x11, 0x000203f9}, + {0x10, 0x0003000f}, {0x11, 0x000ff500}, + {0x10, 0x00000000}, {0x11, 0x00000000}, + {0x10, 0x0008000f}, {0x11, 0x0003f100}, + {0x10, 0x0009000f}, {0x11, 0x00023100}, + {0x12, 0x00032000}, {0x12, 0x00071000}, + {0x12, 0x000b0000}, {0x12, 0x000fc000}, + {0x13, 0x000287b3}, {0x13, 0x000244b7}, + {0x13, 0x000204ab}, {0x13, 0x0001c49f}, + {0x13, 0x00018493}, {0x13, 0x0001429b}, + {0x13, 0x00010299}, {0x13, 0x0000c29c}, + {0x13, 0x000081a0}, {0x13, 0x000040ac}, + {0x13, 0x00000020}, {0x14, 0x0001944c}, + {0x14, 0x00059444}, {0x14, 0x0009944c}, + {0x14, 0x000d9444}, {0x15, 0x0000f474}, + {0x15, 0x0004f477}, {0x15, 0x0008f455}, + {0x15, 0x000cf455}, {0x16, 0x00000339}, + {0x16, 0x00040339}, {0x16, 0x00080339}, + {0x16, 0x000c0366}, {0x00, 0x00010159}, + {0x18, 0x0000f401}, {0xfe, 0x00000000}, + {0xfe, 0x00000000}, {0x1f, 0x00000003}, + {0xfe, 0x00000000}, {0xfe, 0x00000000}, + {0x1e, 0x00000247}, {0x1f, 0x00000000}, + {0x00, 0x00030159}, + {0xff, 0xffffffff} +}; + +static struct rtl8xxxu_rfregval rtl8192cu_radioa_2t_init_table[] = { + {0x00, 0x00030159}, {0x01, 0x00031284}, + {0x02, 0x00098000}, {0x03, 0x00018c63}, + {0x04, 0x000210e7}, {0x09, 0x0002044f}, + {0x0a, 0x0001adb1}, {0x0b, 0x00054867}, + {0x0c, 0x0008992e}, {0x0d, 0x0000e52c}, + {0x0e, 0x00039ce7}, {0x0f, 0x00000451}, + {0x19, 0x00000000}, {0x1a, 0x00010255}, + {0x1b, 0x00060a00}, {0x1c, 0x000fc378}, + {0x1d, 0x000a1250}, {0x1e, 0x0004445f}, + {0x1f, 0x00080001}, {0x20, 0x0000b614}, + {0x21, 0x0006c000}, {0x22, 0x00000000}, + {0x23, 0x00001558}, {0x24, 0x00000060}, + {0x25, 0x00000483}, {0x26, 0x0004f000}, + {0x27, 0x000ec7d9}, {0x28, 0x000577c0}, + {0x29, 0x00004783}, {0x2a, 0x00000001}, + {0x2b, 0x00021334}, {0x2a, 0x00000000}, + {0x2b, 0x00000054}, {0x2a, 0x00000001}, + {0x2b, 0x00000808}, {0x2b, 0x00053333}, + {0x2c, 0x0000000c}, {0x2a, 0x00000002}, + {0x2b, 0x00000808}, {0x2b, 0x0005b333}, + {0x2c, 0x0000000d}, {0x2a, 0x00000003}, + {0x2b, 0x00000808}, {0x2b, 0x00063333}, + {0x2c, 0x0000000d}, {0x2a, 0x00000004}, + {0x2b, 0x00000808}, {0x2b, 0x0006b333}, + {0x2c, 0x0000000d}, {0x2a, 0x00000005}, + {0x2b, 0x00000808}, {0x2b, 0x00073333}, + {0x2c, 0x0000000d}, {0x2a, 0x00000006}, + {0x2b, 0x00000709}, {0x2b, 0x0005b333}, + {0x2c, 0x0000000d}, {0x2a, 0x00000007}, + {0x2b, 0x00000709}, {0x2b, 0x00063333}, + {0x2c, 0x0000000d}, {0x2a, 0x00000008}, + {0x2b, 0x0000060a}, {0x2b, 0x0004b333}, + {0x2c, 0x0000000d}, {0x2a, 0x00000009}, + {0x2b, 0x0000060a}, {0x2b, 0x00053333}, + {0x2c, 0x0000000d}, {0x2a, 0x0000000a}, + {0x2b, 0x0000060a}, {0x2b, 0x0005b333}, + {0x2c, 0x0000000d}, {0x2a, 0x0000000b}, + {0x2b, 0x0000060a}, {0x2b, 0x00063333}, + {0x2c, 0x0000000d}, {0x2a, 0x0000000c}, + {0x2b, 0x0000060a}, {0x2b, 0x0006b333}, + {0x2c, 0x0000000d}, {0x2a, 0x0000000d}, + {0x2b, 0x0000060a}, {0x2b, 0x00073333}, + {0x2c, 0x0000000d}, {0x2a, 0x0000000e}, + {0x2b, 0x0000050b}, {0x2b, 0x00066666}, + {0x2c, 0x0000001a}, {0x2a, 0x000e0000}, + {0x10, 0x0004000f}, {0x11, 0x000e31fc}, + {0x10, 0x0006000f}, {0x11, 0x000ff9f8}, + {0x10, 0x0002000f}, {0x11, 0x000203f9}, + {0x10, 0x0003000f}, {0x11, 0x000ff500}, + {0x10, 0x00000000}, {0x11, 0x00000000}, + {0x10, 0x0008000f}, {0x11, 0x0003f100}, + {0x10, 0x0009000f}, {0x11, 0x00023100}, + {0x12, 0x00032000}, {0x12, 0x00071000}, + {0x12, 0x000b0000}, {0x12, 0x000fc000}, + {0x13, 0x000287b3}, {0x13, 0x000244b7}, + {0x13, 0x000204ab}, {0x13, 0x0001c49f}, + {0x13, 0x00018493}, {0x13, 0x0001429b}, + {0x13, 0x00010299}, {0x13, 0x0000c29c}, + {0x13, 0x000081a0}, {0x13, 0x000040ac}, + {0x13, 0x00000020}, {0x14, 0x0001944c}, + {0x14, 0x00059444}, {0x14, 0x0009944c}, + {0x14, 0x000d9444}, {0x15, 0x0000f424}, + {0x15, 0x0004f424}, {0x15, 0x0008f424}, + {0x15, 0x000cf424}, {0x16, 0x000e0330}, + {0x16, 0x000a0330}, {0x16, 0x00060330}, + {0x16, 0x00020330}, {0x00, 0x00010159}, + {0x18, 0x0000f401}, {0xfe, 0x00000000}, + {0xfe, 0x00000000}, {0x1f, 0x00080003}, + {0xfe, 0x00000000}, {0xfe, 0x00000000}, + {0x1e, 0x00044457}, {0x1f, 0x00080000}, + {0x00, 0x00030159}, + {0xff, 0xffffffff} +}; + +static struct rtl8xxxu_rfregval rtl8192cu_radiob_2t_init_table[] = { + {0x00, 0x00030159}, {0x01, 0x00031284}, + {0x02, 0x00098000}, {0x03, 0x00018c63}, + {0x04, 0x000210e7}, {0x09, 0x0002044f}, + {0x0a, 0x0001adb1}, {0x0b, 0x00054867}, + {0x0c, 0x0008992e}, {0x0d, 0x0000e52c}, + {0x0e, 0x00039ce7}, {0x0f, 0x00000451}, + {0x12, 0x00032000}, {0x12, 0x00071000}, + {0x12, 0x000b0000}, {0x12, 0x000fc000}, + {0x13, 0x000287af}, {0x13, 0x000244b7}, + {0x13, 0x000204ab}, {0x13, 0x0001c49f}, + {0x13, 0x00018493}, {0x13, 0x00014297}, + {0x13, 0x00010295}, {0x13, 0x0000c298}, + {0x13, 0x0000819c}, {0x13, 0x000040a8}, + {0x13, 0x0000001c}, {0x14, 0x0001944c}, + {0x14, 0x00059444}, {0x14, 0x0009944c}, + {0x14, 0x000d9444}, {0x15, 0x0000f424}, + {0x15, 0x0004f424}, {0x15, 0x0008f424}, + {0x15, 0x000cf424}, {0x16, 0x000e0330}, + {0x16, 0x000a0330}, {0x16, 0x00060330}, + {0x16, 0x00020330}, + {0xff, 0xffffffff} +}; + +static struct rtl8xxxu_rfregval rtl8192cu_radioa_1t_init_table[] = { + {0x00, 0x00030159}, {0x01, 0x00031284}, + {0x02, 0x00098000}, {0x03, 0x00018c63}, + {0x04, 0x000210e7}, {0x09, 0x0002044f}, + {0x0a, 0x0001adb1}, {0x0b, 0x00054867}, + {0x0c, 0x0008992e}, {0x0d, 0x0000e52c}, + {0x0e, 0x00039ce7}, {0x0f, 0x00000451}, + {0x19, 0x00000000}, {0x1a, 0x00010255}, + {0x1b, 0x00060a00}, {0x1c, 0x000fc378}, + {0x1d, 0x000a1250}, {0x1e, 0x0004445f}, + {0x1f, 0x00080001}, {0x20, 0x0000b614}, + {0x21, 0x0006c000}, {0x22, 0x00000000}, + {0x23, 0x00001558}, {0x24, 0x00000060}, + {0x25, 0x00000483}, {0x26, 0x0004f000}, + {0x27, 0x000ec7d9}, {0x28, 0x000577c0}, + {0x29, 0x00004783}, {0x2a, 0x00000001}, + {0x2b, 0x00021334}, {0x2a, 0x00000000}, + {0x2b, 0x00000054}, {0x2a, 0x00000001}, + {0x2b, 0x00000808}, {0x2b, 0x00053333}, + {0x2c, 0x0000000c}, {0x2a, 0x00000002}, + {0x2b, 0x00000808}, {0x2b, 0x0005b333}, + {0x2c, 0x0000000d}, {0x2a, 0x00000003}, + {0x2b, 0x00000808}, {0x2b, 0x00063333}, + {0x2c, 0x0000000d}, {0x2a, 0x00000004}, + {0x2b, 0x00000808}, {0x2b, 0x0006b333}, + {0x2c, 0x0000000d}, {0x2a, 0x00000005}, + {0x2b, 0x00000808}, {0x2b, 0x00073333}, + {0x2c, 0x0000000d}, {0x2a, 0x00000006}, + {0x2b, 0x00000709}, {0x2b, 0x0005b333}, + {0x2c, 0x0000000d}, {0x2a, 0x00000007}, + {0x2b, 0x00000709}, {0x2b, 0x00063333}, + {0x2c, 0x0000000d}, {0x2a, 0x00000008}, + {0x2b, 0x0000060a}, {0x2b, 0x0004b333}, + {0x2c, 0x0000000d}, {0x2a, 0x00000009}, + {0x2b, 0x0000060a}, {0x2b, 0x00053333}, + {0x2c, 0x0000000d}, {0x2a, 0x0000000a}, + {0x2b, 0x0000060a}, {0x2b, 0x0005b333}, + {0x2c, 0x0000000d}, {0x2a, 0x0000000b}, + {0x2b, 0x0000060a}, {0x2b, 0x00063333}, + {0x2c, 0x0000000d}, {0x2a, 0x0000000c}, + {0x2b, 0x0000060a}, {0x2b, 0x0006b333}, + {0x2c, 0x0000000d}, {0x2a, 0x0000000d}, + {0x2b, 0x0000060a}, {0x2b, 0x00073333}, + {0x2c, 0x0000000d}, {0x2a, 0x0000000e}, + {0x2b, 0x0000050b}, {0x2b, 0x00066666}, + {0x2c, 0x0000001a}, {0x2a, 0x000e0000}, + {0x10, 0x0004000f}, {0x11, 0x000e31fc}, + {0x10, 0x0006000f}, {0x11, 0x000ff9f8}, + {0x10, 0x0002000f}, {0x11, 0x000203f9}, + {0x10, 0x0003000f}, {0x11, 0x000ff500}, + {0x10, 0x00000000}, {0x11, 0x00000000}, + {0x10, 0x0008000f}, {0x11, 0x0003f100}, + {0x10, 0x0009000f}, {0x11, 0x00023100}, + {0x12, 0x00032000}, {0x12, 0x00071000}, + {0x12, 0x000b0000}, {0x12, 0x000fc000}, + {0x13, 0x000287b3}, {0x13, 0x000244b7}, + {0x13, 0x000204ab}, {0x13, 0x0001c49f}, + {0x13, 0x00018493}, {0x13, 0x0001429b}, + {0x13, 0x00010299}, {0x13, 0x0000c29c}, + {0x13, 0x000081a0}, {0x13, 0x000040ac}, + {0x13, 0x00000020}, {0x14, 0x0001944c}, + {0x14, 0x00059444}, {0x14, 0x0009944c}, + {0x14, 0x000d9444}, {0x15, 0x0000f405}, + {0x15, 0x0004f405}, {0x15, 0x0008f405}, + {0x15, 0x000cf405}, {0x16, 0x000e0330}, + {0x16, 0x000a0330}, {0x16, 0x00060330}, + {0x16, 0x00020330}, {0x00, 0x00010159}, + {0x18, 0x0000f401}, {0xfe, 0x00000000}, + {0xfe, 0x00000000}, {0x1f, 0x00080003}, + {0xfe, 0x00000000}, {0xfe, 0x00000000}, + {0x1e, 0x00044457}, {0x1f, 0x00080000}, + {0x00, 0x00030159}, + {0xff, 0xffffffff} +}; + +static struct rtl8xxxu_rfregval rtl8188ru_radioa_1t_highpa_table[] = { + {0x00, 0x00030159}, {0x01, 0x00031284}, + {0x02, 0x00098000}, {0x03, 0x00018c63}, + {0x04, 0x000210e7}, {0x09, 0x0002044f}, + {0x0a, 0x0001adb0}, {0x0b, 0x00054867}, + {0x0c, 0x0008992e}, {0x0d, 0x0000e529}, + {0x0e, 0x00039ce7}, {0x0f, 0x00000451}, + {0x19, 0x00000000}, {0x1a, 0x00000255}, + {0x1b, 0x00060a00}, {0x1c, 0x000fc378}, + {0x1d, 0x000a1250}, {0x1e, 0x0004445f}, + {0x1f, 0x00080001}, {0x20, 0x0000b614}, + {0x21, 0x0006c000}, {0x22, 0x0000083c}, + {0x23, 0x00001558}, {0x24, 0x00000060}, + {0x25, 0x00000483}, {0x26, 0x0004f000}, + {0x27, 0x000ec7d9}, {0x28, 0x000977c0}, + {0x29, 0x00004783}, {0x2a, 0x00000001}, + {0x2b, 0x00021334}, {0x2a, 0x00000000}, + {0x2b, 0x00000054}, {0x2a, 0x00000001}, + {0x2b, 0x00000808}, {0x2b, 0x00053333}, + {0x2c, 0x0000000c}, {0x2a, 0x00000002}, + {0x2b, 0x00000808}, {0x2b, 0x0005b333}, + {0x2c, 0x0000000d}, {0x2a, 0x00000003}, + {0x2b, 0x00000808}, {0x2b, 0x00063333}, + {0x2c, 0x0000000d}, {0x2a, 0x00000004}, + {0x2b, 0x00000808}, {0x2b, 0x0006b333}, + {0x2c, 0x0000000d}, {0x2a, 0x00000005}, + {0x2b, 0x00000808}, {0x2b, 0x00073333}, + {0x2c, 0x0000000d}, {0x2a, 0x00000006}, + {0x2b, 0x00000709}, {0x2b, 0x0005b333}, + {0x2c, 0x0000000d}, {0x2a, 0x00000007}, + {0x2b, 0x00000709}, {0x2b, 0x00063333}, + {0x2c, 0x0000000d}, {0x2a, 0x00000008}, + {0x2b, 0x0000060a}, {0x2b, 0x0004b333}, + {0x2c, 0x0000000d}, {0x2a, 0x00000009}, + {0x2b, 0x0000060a}, {0x2b, 0x00053333}, + {0x2c, 0x0000000d}, {0x2a, 0x0000000a}, + {0x2b, 0x0000060a}, {0x2b, 0x0005b333}, + {0x2c, 0x0000000d}, {0x2a, 0x0000000b}, + {0x2b, 0x0000060a}, {0x2b, 0x00063333}, + {0x2c, 0x0000000d}, {0x2a, 0x0000000c}, + {0x2b, 0x0000060a}, {0x2b, 0x0006b333}, + {0x2c, 0x0000000d}, {0x2a, 0x0000000d}, + {0x2b, 0x0000060a}, {0x2b, 0x00073333}, + {0x2c, 0x0000000d}, {0x2a, 0x0000000e}, + {0x2b, 0x0000050b}, {0x2b, 0x00066666}, + {0x2c, 0x0000001a}, {0x2a, 0x000e0000}, + {0x10, 0x0004000f}, {0x11, 0x000e31fc}, + {0x10, 0x0006000f}, {0x11, 0x000ff9f8}, + {0x10, 0x0002000f}, {0x11, 0x000203f9}, + {0x10, 0x0003000f}, {0x11, 0x000ff500}, + {0x10, 0x00000000}, {0x11, 0x00000000}, + {0x10, 0x0008000f}, {0x11, 0x0003f100}, + {0x10, 0x0009000f}, {0x11, 0x00023100}, + {0x12, 0x000d8000}, {0x12, 0x00090000}, + {0x12, 0x00051000}, {0x12, 0x00012000}, + {0x13, 0x00028fb4}, {0x13, 0x00024fa8}, + {0x13, 0x000207a4}, {0x13, 0x0001c3b0}, + {0x13, 0x000183a4}, {0x13, 0x00014398}, + {0x13, 0x000101a4}, {0x13, 0x0000c198}, + {0x13, 0x000080a4}, {0x13, 0x00004098}, + {0x13, 0x00000000}, {0x14, 0x0001944c}, + {0x14, 0x00059444}, {0x14, 0x0009944c}, + {0x14, 0x000d9444}, {0x15, 0x0000f405}, + {0x15, 0x0004f405}, {0x15, 0x0008f405}, + {0x15, 0x000cf405}, {0x16, 0x000e0330}, + {0x16, 0x000a0330}, {0x16, 0x00060330}, + {0x16, 0x00020330}, {0x00, 0x00010159}, + {0x18, 0x0000f401}, {0xfe, 0x00000000}, + {0xfe, 0x00000000}, {0x1f, 0x00080003}, + {0xfe, 0x00000000}, {0xfe, 0x00000000}, + {0x1e, 0x00044457}, {0x1f, 0x00080000}, + {0x00, 0x00030159}, + {0xff, 0xffffffff} +}; + +static struct rtl8xxxu_rfregs rtl8xxxu_rfregs[] = { + { /* RF_A */ + .hssiparm1 = REG_FPGA0_XA_HSSI_PARM1, + .hssiparm2 = REG_FPGA0_XA_HSSI_PARM2, + .lssiparm = REG_FPGA0_XA_LSSI_PARM, + .hspiread = REG_HSPI_XA_READBACK, + .lssiread = REG_FPGA0_XA_LSSI_READBACK, + .rf_sw_ctrl = REG_FPGA0_XA_RF_SW_CTRL, + }, + { /* RF_B */ + .hssiparm1 = REG_FPGA0_XB_HSSI_PARM1, + .hssiparm2 = REG_FPGA0_XB_HSSI_PARM2, + .lssiparm = REG_FPGA0_XB_LSSI_PARM, + .hspiread = REG_HSPI_XB_READBACK, + .lssiread = REG_FPGA0_XB_LSSI_READBACK, + .rf_sw_ctrl = REG_FPGA0_XB_RF_SW_CTRL, + }, +}; + +static const u32 rtl8723au_iqk_phy_iq_bb_reg[RTL8XXXU_BB_REGS] = { + REG_OFDM0_XA_RX_IQ_IMBALANCE, + REG_OFDM0_XB_RX_IQ_IMBALANCE, + REG_OFDM0_ENERGY_CCA_THRES, + REG_OFDM0_AGCR_SSI_TABLE, + REG_OFDM0_XA_TX_IQ_IMBALANCE, + REG_OFDM0_XB_TX_IQ_IMBALANCE, + REG_OFDM0_XC_TX_AFE, + REG_OFDM0_XD_TX_AFE, + REG_OFDM0_RX_IQ_EXT_ANTA +}; + +static u8 rtl8xxxu_read8(struct rtl8xxxu_priv *priv, u16 addr) +{ + struct usb_device *udev = priv->udev; + int len; + u8 data; + + mutex_lock(&priv->usb_buf_mutex); + len = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + REALTEK_USB_CMD_REQ, REALTEK_USB_READ, + addr, 0, &priv->usb_buf.val8, sizeof(u8), + RTW_USB_CONTROL_MSG_TIMEOUT); + data = priv->usb_buf.val8; + mutex_unlock(&priv->usb_buf_mutex); + + if (rtl8xxxu_debug & RTL8XXXU_DEBUG_REG_READ) + dev_info(&udev->dev, "%s(%04x) = 0x%02x, len %i\n", + __func__, addr, data, len); + return data; +} + +static u16 rtl8xxxu_read16(struct rtl8xxxu_priv *priv, u16 addr) +{ + struct usb_device *udev = priv->udev; + int len; + u16 data; + + mutex_lock(&priv->usb_buf_mutex); + len = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + REALTEK_USB_CMD_REQ, REALTEK_USB_READ, + addr, 0, &priv->usb_buf.val16, sizeof(u16), + RTW_USB_CONTROL_MSG_TIMEOUT); + data = le16_to_cpu(priv->usb_buf.val16); + mutex_unlock(&priv->usb_buf_mutex); + + if (rtl8xxxu_debug & RTL8XXXU_DEBUG_REG_READ) + dev_info(&udev->dev, "%s(%04x) = 0x%04x, len %i\n", + __func__, addr, data, len); + return data; +} + +static u32 rtl8xxxu_read32(struct rtl8xxxu_priv *priv, u16 addr) +{ + struct usb_device *udev = priv->udev; + int len; + u32 data; + + mutex_lock(&priv->usb_buf_mutex); + len = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + REALTEK_USB_CMD_REQ, REALTEK_USB_READ, + addr, 0, &priv->usb_buf.val32, sizeof(u32), + RTW_USB_CONTROL_MSG_TIMEOUT); + data = le32_to_cpu(priv->usb_buf.val32); + mutex_unlock(&priv->usb_buf_mutex); + + if (rtl8xxxu_debug & RTL8XXXU_DEBUG_REG_READ) + dev_info(&udev->dev, "%s(%04x) = 0x%08x, len %i\n", + __func__, addr, data, len); + return data; +} + +static int rtl8xxxu_write8(struct rtl8xxxu_priv *priv, u16 addr, u8 val) +{ + struct usb_device *udev = priv->udev; + int ret; + + mutex_lock(&priv->usb_buf_mutex); + priv->usb_buf.val8 = val; + ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + REALTEK_USB_CMD_REQ, REALTEK_USB_WRITE, + addr, 0, &priv->usb_buf.val8, sizeof(u8), + RTW_USB_CONTROL_MSG_TIMEOUT); + + mutex_unlock(&priv->usb_buf_mutex); + + if (rtl8xxxu_debug & RTL8XXXU_DEBUG_REG_WRITE) + dev_info(&udev->dev, "%s(%04x) = 0x%02x\n", + __func__, addr, val); + return ret; +} + +static int rtl8xxxu_write16(struct rtl8xxxu_priv *priv, u16 addr, u16 val) +{ + struct usb_device *udev = priv->udev; + int ret; + + mutex_lock(&priv->usb_buf_mutex); + priv->usb_buf.val16 = cpu_to_le16(val); + ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + REALTEK_USB_CMD_REQ, REALTEK_USB_WRITE, + addr, 0, &priv->usb_buf.val16, sizeof(u16), + RTW_USB_CONTROL_MSG_TIMEOUT); + mutex_unlock(&priv->usb_buf_mutex); + + if (rtl8xxxu_debug & RTL8XXXU_DEBUG_REG_WRITE) + dev_info(&udev->dev, "%s(%04x) = 0x%04x\n", + __func__, addr, val); + return ret; +} + +static int rtl8xxxu_write32(struct rtl8xxxu_priv *priv, u16 addr, u32 val) +{ + struct usb_device *udev = priv->udev; + int ret; + + mutex_lock(&priv->usb_buf_mutex); + priv->usb_buf.val32 = cpu_to_le32(val); + ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + REALTEK_USB_CMD_REQ, REALTEK_USB_WRITE, + addr, 0, &priv->usb_buf.val32, sizeof(u32), + RTW_USB_CONTROL_MSG_TIMEOUT); + mutex_unlock(&priv->usb_buf_mutex); + + if (rtl8xxxu_debug & RTL8XXXU_DEBUG_REG_WRITE) + dev_info(&udev->dev, "%s(%04x) = 0x%08x\n", + __func__, addr, val); + return ret; +} + +static int +rtl8xxxu_writeN(struct rtl8xxxu_priv *priv, u16 addr, u8 *buf, u16 len) +{ + struct usb_device *udev = priv->udev; + int blocksize = priv->fops->writeN_block_size; + int ret, i, count, remainder; + + count = len / blocksize; + remainder = len % blocksize; + + for (i = 0; i < count; i++) { + ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + REALTEK_USB_CMD_REQ, REALTEK_USB_WRITE, + addr, 0, buf, blocksize, + RTW_USB_CONTROL_MSG_TIMEOUT); + if (ret != blocksize) + goto write_error; + + addr += blocksize; + buf += blocksize; + } + + if (remainder) { + ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + REALTEK_USB_CMD_REQ, REALTEK_USB_WRITE, + addr, 0, buf, remainder, + RTW_USB_CONTROL_MSG_TIMEOUT); + if (ret != remainder) + goto write_error; + } + + return len; + +write_error: + dev_info(&udev->dev, + "%s: Failed to write block at addr: %04x size: %04x\n", + __func__, addr, blocksize); + return -EAGAIN; +} + +static u32 rtl8xxxu_read_rfreg(struct rtl8xxxu_priv *priv, + enum rtl8xxxu_rfpath path, u8 reg) +{ + u32 hssia, val32, retval; + + hssia = rtl8xxxu_read32(priv, REG_FPGA0_XA_HSSI_PARM2); + if (path != RF_A) + val32 = rtl8xxxu_read32(priv, rtl8xxxu_rfregs[path].hssiparm2); + else + val32 = hssia; + + val32 &= ~FPGA0_HSSI_PARM2_ADDR_MASK; + val32 |= (reg << FPGA0_HSSI_PARM2_ADDR_SHIFT); + val32 |= FPGA0_HSSI_PARM2_EDGE_READ; + hssia &= ~FPGA0_HSSI_PARM2_EDGE_READ; + rtl8xxxu_write32(priv, REG_FPGA0_XA_HSSI_PARM2, hssia); + + udelay(10); + + rtl8xxxu_write32(priv, rtl8xxxu_rfregs[path].hssiparm2, val32); + udelay(100); + + hssia |= FPGA0_HSSI_PARM2_EDGE_READ; + rtl8xxxu_write32(priv, REG_FPGA0_XA_HSSI_PARM2, hssia); + udelay(10); + + val32 = rtl8xxxu_read32(priv, rtl8xxxu_rfregs[path].hssiparm1); + if (val32 & FPGA0_HSSI_PARM1_PI) + retval = rtl8xxxu_read32(priv, rtl8xxxu_rfregs[path].hspiread); + else + retval = rtl8xxxu_read32(priv, rtl8xxxu_rfregs[path].lssiread); + + retval &= 0xfffff; + + if (rtl8xxxu_debug & RTL8XXXU_DEBUG_RFREG_READ) + dev_info(&priv->udev->dev, "%s(%02x) = 0x%06x\n", + __func__, reg, retval); + return retval; +} + +static int rtl8xxxu_write_rfreg(struct rtl8xxxu_priv *priv, + enum rtl8xxxu_rfpath path, u8 reg, u32 data) +{ + int ret, retval; + u32 dataaddr; + + if (rtl8xxxu_debug & RTL8XXXU_DEBUG_RFREG_WRITE) + dev_info(&priv->udev->dev, "%s(%02x) = 0x%06x\n", + __func__, reg, data); + + data &= FPGA0_LSSI_PARM_DATA_MASK; + dataaddr = (reg << FPGA0_LSSI_PARM_ADDR_SHIFT) | data; + + /* Use XB for path B */ + ret = rtl8xxxu_write32(priv, rtl8xxxu_rfregs[path].lssiparm, dataaddr); + if (ret != sizeof(dataaddr)) + retval = -EIO; + else + retval = 0; + + udelay(1); + + return retval; +} + +static int rtl8723a_h2c_cmd(struct rtl8xxxu_priv *priv, struct h2c_cmd *h2c) +{ + struct device *dev = &priv->udev->dev; + int mbox_nr, retry, retval = 0; + int mbox_reg, mbox_ext_reg; + u8 val8; + + mutex_lock(&priv->h2c_mutex); + + mbox_nr = priv->next_mbox; + mbox_reg = REG_HMBOX_0 + (mbox_nr * 4); + mbox_ext_reg = REG_HMBOX_EXT_0 + (mbox_nr * 2); + + /* + * MBOX ready? + */ + retry = 100; + do { + val8 = rtl8xxxu_read8(priv, REG_HMTFR); + if (!(val8 & BIT(mbox_nr))) + break; + } while (retry--); + + if (!retry) { + dev_dbg(dev, "%s: Mailbox busy\n", __func__); + retval = -EBUSY; + goto error; + } + + /* + * Need to swap as it's being swapped again by rtl8xxxu_write16/32() + */ + if (h2c->cmd.cmd & H2C_EXT) { + rtl8xxxu_write16(priv, mbox_ext_reg, + le16_to_cpu(h2c->raw.ext)); + if (rtl8xxxu_debug & RTL8XXXU_DEBUG_H2C) + dev_info(dev, "H2C_EXT %04x\n", + le16_to_cpu(h2c->raw.ext)); + } + rtl8xxxu_write32(priv, mbox_reg, le32_to_cpu(h2c->raw.data)); + if (rtl8xxxu_debug & RTL8XXXU_DEBUG_H2C) + dev_info(dev, "H2C %08x\n", le32_to_cpu(h2c->raw.data)); + + priv->next_mbox = (mbox_nr + 1) % H2C_MAX_MBOX; + +error: + mutex_unlock(&priv->h2c_mutex); + return retval; +} + +static void rtl8723a_enable_rf(struct rtl8xxxu_priv *priv) +{ + u8 val8; + u32 val32; + + val8 = rtl8xxxu_read8(priv, REG_SPS0_CTRL); + val8 |= BIT(0) | BIT(3); + rtl8xxxu_write8(priv, REG_SPS0_CTRL, val8); + + val32 = rtl8xxxu_read32(priv, REG_FPGA0_XAB_RF_PARM); + val32 &= ~(BIT(4) | BIT(5)); + val32 |= BIT(3); + if (priv->rf_paths == 2) { + val32 &= ~(BIT(20) | BIT(21)); + val32 |= BIT(19); + } + rtl8xxxu_write32(priv, REG_FPGA0_XAB_RF_PARM, val32); + + val32 = rtl8xxxu_read32(priv, REG_OFDM0_TRX_PATH_ENABLE); + val32 &= ~OFDM_RF_PATH_TX_MASK; + if (priv->tx_paths == 2) + val32 |= OFDM_RF_PATH_TX_A | OFDM_RF_PATH_TX_B; + else if (priv->rtlchip == 0x8192c || priv->rtlchip == 0x8191c) + val32 |= OFDM_RF_PATH_TX_B; + else + val32 |= OFDM_RF_PATH_TX_A; + rtl8xxxu_write32(priv, REG_OFDM0_TRX_PATH_ENABLE, val32); + + val32 = rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE); + val32 &= ~FPGA_RF_MODE_JAPAN; + rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32); + + if (priv->rf_paths == 2) + rtl8xxxu_write32(priv, REG_RX_WAIT_CCA, 0x63db25a0); + else + rtl8xxxu_write32(priv, REG_RX_WAIT_CCA, 0x631b25a0); + + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_AC, 0x32d95); + if (priv->rf_paths == 2) + rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_AC, 0x32d95); + + rtl8xxxu_write8(priv, REG_TXPAUSE, 0x00); +} + +static void rtl8723a_disable_rf(struct rtl8xxxu_priv *priv) +{ + u8 sps0; + u32 val32; + + rtl8xxxu_write8(priv, REG_TXPAUSE, 0xff); + + sps0 = rtl8xxxu_read8(priv, REG_SPS0_CTRL); + + /* RF RX code for preamble power saving */ + val32 = rtl8xxxu_read32(priv, REG_FPGA0_XAB_RF_PARM); + val32 &= ~(BIT(3) | BIT(4) | BIT(5)); + if (priv->rf_paths == 2) + val32 &= ~(BIT(19) | BIT(20) | BIT(21)); + rtl8xxxu_write32(priv, REG_FPGA0_XAB_RF_PARM, val32); + + /* Disable TX for four paths */ + val32 = rtl8xxxu_read32(priv, REG_OFDM0_TRX_PATH_ENABLE); + val32 &= ~OFDM_RF_PATH_TX_MASK; + rtl8xxxu_write32(priv, REG_OFDM0_TRX_PATH_ENABLE, val32); + + /* Enable power saving */ + val32 = rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE); + val32 |= FPGA_RF_MODE_JAPAN; + rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32); + + /* AFE control register to power down bits [30:22] */ + if (priv->rf_paths == 2) + rtl8xxxu_write32(priv, REG_RX_WAIT_CCA, 0x00db25a0); + else + rtl8xxxu_write32(priv, REG_RX_WAIT_CCA, 0x001b25a0); + + /* Power down RF module */ + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_AC, 0); + if (priv->rf_paths == 2) + rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_AC, 0); + + sps0 &= ~(BIT(0) | BIT(3)); + rtl8xxxu_write8(priv, REG_SPS0_CTRL, sps0); +} + + +static void rtl8723a_stop_tx_beacon(struct rtl8xxxu_priv *priv) +{ + u8 val8; + + val8 = rtl8xxxu_read8(priv, REG_FWHW_TXQ_CTRL + 2); + val8 &= ~BIT(6); + rtl8xxxu_write8(priv, REG_FWHW_TXQ_CTRL + 2, val8); + + rtl8xxxu_write8(priv, REG_TBTT_PROHIBIT + 1, 0x64); + val8 = rtl8xxxu_read8(priv, REG_TBTT_PROHIBIT + 2); + val8 &= ~BIT(0); + rtl8xxxu_write8(priv, REG_TBTT_PROHIBIT + 2, val8); +} + + +/* + * The rtl8723a has 3 channel groups for it's efuse settings. It only + * supports the 2.4GHz band, so channels 1 - 14: + * group 0: channels 1 - 3 + * group 1: channels 4 - 9 + * group 2: channels 10 - 14 + * + * Note: We index from 0 in the code + */ +static int rtl8723a_channel_to_group(int channel) +{ + int group; + + if (channel < 4) + group = 0; + else if (channel < 10) + group = 1; + else + group = 2; + + return group; +} + +static void rtl8723au_config_channel(struct ieee80211_hw *hw) +{ + struct rtl8xxxu_priv *priv = hw->priv; + u32 val32, rsr; + u8 val8, opmode; + bool ht = true; + int sec_ch_above, channel; + int i; + + opmode = rtl8xxxu_read8(priv, REG_BW_OPMODE); + rsr = rtl8xxxu_read32(priv, REG_RESPONSE_RATE_SET); + channel = hw->conf.chandef.chan->hw_value; + + switch (hw->conf.chandef.width) { + case NL80211_CHAN_WIDTH_20_NOHT: + ht = false; + case NL80211_CHAN_WIDTH_20: + opmode |= BW_OPMODE_20MHZ; + rtl8xxxu_write8(priv, REG_BW_OPMODE, opmode); + + val32 = rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE); + val32 &= ~FPGA_RF_MODE; + rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32); + + val32 = rtl8xxxu_read32(priv, REG_FPGA1_RF_MODE); + val32 &= ~FPGA_RF_MODE; + rtl8xxxu_write32(priv, REG_FPGA1_RF_MODE, val32); + + val32 = rtl8xxxu_read32(priv, REG_FPGA0_ANALOG2); + val32 |= FPGA0_ANALOG2_20MHZ; + rtl8xxxu_write32(priv, REG_FPGA0_ANALOG2, val32); + break; + case NL80211_CHAN_WIDTH_40: + if (hw->conf.chandef.center_freq1 > + hw->conf.chandef.chan->center_freq) { + sec_ch_above = 1; + channel += 2; + } else { + sec_ch_above = 0; + channel -= 2; + } + + opmode &= ~BW_OPMODE_20MHZ; + rtl8xxxu_write8(priv, REG_BW_OPMODE, opmode); + rsr &= ~RSR_RSC_BANDWIDTH_40M; + if (sec_ch_above) + rsr |= RSR_RSC_UPPER_SUB_CHANNEL; + else + rsr |= RSR_RSC_LOWER_SUB_CHANNEL; + rtl8xxxu_write32(priv, REG_RESPONSE_RATE_SET, rsr); + + val32 = rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE); + val32 |= FPGA_RF_MODE; + rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32); + + val32 = rtl8xxxu_read32(priv, REG_FPGA1_RF_MODE); + val32 |= FPGA_RF_MODE; + rtl8xxxu_write32(priv, REG_FPGA1_RF_MODE, val32); + + /* + * Set Control channel to upper or lower. These settings + * are required only for 40MHz + */ + val32 = rtl8xxxu_read32(priv, REG_CCK0_SYSTEM); + val32 &= ~CCK0_SIDEBAND; + if (!sec_ch_above) + val32 |= CCK0_SIDEBAND; + rtl8xxxu_write32(priv, REG_CCK0_SYSTEM, val32); + + val32 = rtl8xxxu_read32(priv, REG_OFDM1_LSTF); + val32 &= ~OFDM_LSTF_PRIME_CH_MASK; /* 0xc00 */ + if (sec_ch_above) + val32 |= OFDM_LSTF_PRIME_CH_LOW; + else + val32 |= OFDM_LSTF_PRIME_CH_HIGH; + rtl8xxxu_write32(priv, REG_OFDM1_LSTF, val32); + + val32 = rtl8xxxu_read32(priv, REG_FPGA0_ANALOG2); + val32 &= ~FPGA0_ANALOG2_20MHZ; + rtl8xxxu_write32(priv, REG_FPGA0_ANALOG2, val32); + + val32 = rtl8xxxu_read32(priv, REG_FPGA0_POWER_SAVE); + val32 &= ~(FPGA0_PS_LOWER_CHANNEL | FPGA0_PS_UPPER_CHANNEL); + if (sec_ch_above) + val32 |= FPGA0_PS_UPPER_CHANNEL; + else + val32 |= FPGA0_PS_LOWER_CHANNEL; + rtl8xxxu_write32(priv, REG_FPGA0_POWER_SAVE, val32); + break; + + default: + break; + } + + for (i = RF_A; i < priv->rf_paths; i++) { + val32 = rtl8xxxu_read_rfreg(priv, i, RF6052_REG_MODE_AG); + val32 &= ~MODE_AG_CHANNEL_MASK; + val32 |= channel; + rtl8xxxu_write_rfreg(priv, i, RF6052_REG_MODE_AG, val32); + } + + if (ht) + val8 = 0x0e; + else + val8 = 0x0a; + + rtl8xxxu_write8(priv, REG_SIFS_CCK + 1, val8); + rtl8xxxu_write8(priv, REG_SIFS_OFDM + 1, val8); + + rtl8xxxu_write16(priv, REG_R2T_SIFS, 0x0808); + rtl8xxxu_write16(priv, REG_T2T_SIFS, 0x0a0a); + + for (i = RF_A; i < priv->rf_paths; i++) { + val32 = rtl8xxxu_read_rfreg(priv, i, RF6052_REG_MODE_AG); + if (hw->conf.chandef.width == NL80211_CHAN_WIDTH_40) + val32 &= ~MODE_AG_CHANNEL_20MHZ; + else + val32 |= MODE_AG_CHANNEL_20MHZ; + rtl8xxxu_write_rfreg(priv, i, RF6052_REG_MODE_AG, val32); + } +} + +static void +rtl8723a_set_tx_power(struct rtl8xxxu_priv *priv, int channel, bool ht40) +{ + u8 cck[RTL8723A_MAX_RF_PATHS], ofdm[RTL8723A_MAX_RF_PATHS]; + u8 ofdmbase[RTL8723A_MAX_RF_PATHS], mcsbase[RTL8723A_MAX_RF_PATHS]; + u32 val32, ofdm_a, ofdm_b, mcs_a, mcs_b; + u8 val8; + int group, i; + + group = rtl8723a_channel_to_group(channel); + + cck[0] = priv->cck_tx_power_index_A[group]; + cck[1] = priv->cck_tx_power_index_B[group]; + + ofdm[0] = priv->ht40_1s_tx_power_index_A[group]; + ofdm[1] = priv->ht40_1s_tx_power_index_B[group]; + + ofdmbase[0] = ofdm[0] + priv->ofdm_tx_power_index_diff[group].a; + ofdmbase[1] = ofdm[1] + priv->ofdm_tx_power_index_diff[group].b; + + mcsbase[0] = ofdm[0]; + mcsbase[1] = ofdm[1]; + if (!ht40) { + mcsbase[0] += priv->ht20_tx_power_index_diff[group].a; + mcsbase[1] += priv->ht20_tx_power_index_diff[group].b; + } + + if (priv->tx_paths > 1) { + if (ofdm[0] > priv->ht40_2s_tx_power_index_diff[group].a) + ofdm[0] -= priv->ht40_2s_tx_power_index_diff[group].a; + if (ofdm[1] > priv->ht40_2s_tx_power_index_diff[group].b) + ofdm[1] -= priv->ht40_2s_tx_power_index_diff[group].b; + } + + if (rtl8xxxu_debug & RTL8XXXU_DEBUG_CHANNEL) + dev_info(&priv->udev->dev, + "%s: Setting TX power CCK A: %02x, " + "CCK B: %02x, OFDM A: %02x, OFDM B: %02x\n", + __func__, cck[0], cck[1], ofdm[0], ofdm[1]); + + for (i = 0; i < RTL8723A_MAX_RF_PATHS; i++) { + if (cck[i] > RF6052_MAX_TX_PWR) + cck[i] = RF6052_MAX_TX_PWR; + if (ofdm[i] > RF6052_MAX_TX_PWR) + ofdm[i] = RF6052_MAX_TX_PWR; + } + + val32 = rtl8xxxu_read32(priv, REG_TX_AGC_A_CCK1_MCS32); + val32 &= 0xffff00ff; + val32 |= (cck[0] << 8); + rtl8xxxu_write32(priv, REG_TX_AGC_A_CCK1_MCS32, val32); + + val32 = rtl8xxxu_read32(priv, REG_TX_AGC_B_CCK11_A_CCK2_11); + val32 &= 0xff; + val32 |= ((cck[0] << 8) | (cck[0] << 16) | (cck[0] << 24)); + rtl8xxxu_write32(priv, REG_TX_AGC_B_CCK11_A_CCK2_11, val32); + + val32 = rtl8xxxu_read32(priv, REG_TX_AGC_B_CCK11_A_CCK2_11); + val32 &= 0xffffff00; + val32 |= cck[1]; + rtl8xxxu_write32(priv, REG_TX_AGC_B_CCK11_A_CCK2_11, val32); + + val32 = rtl8xxxu_read32(priv, REG_TX_AGC_B_CCK1_55_MCS32); + val32 &= 0xff; + val32 |= ((cck[1] << 8) | (cck[1] << 16) | (cck[1] << 24)); + rtl8xxxu_write32(priv, REG_TX_AGC_B_CCK1_55_MCS32, val32); + + ofdm_a = ofdmbase[0] | ofdmbase[0] << 8 | + ofdmbase[0] << 16 | ofdmbase[0] << 24; + ofdm_b = ofdmbase[1] | ofdmbase[1] << 8 | + ofdmbase[1] << 16 | ofdmbase[1] << 24; + rtl8xxxu_write32(priv, REG_TX_AGC_A_RATE18_06, ofdm_a); + rtl8xxxu_write32(priv, REG_TX_AGC_B_RATE18_06, ofdm_b); + + rtl8xxxu_write32(priv, REG_TX_AGC_A_RATE54_24, ofdm_a); + rtl8xxxu_write32(priv, REG_TX_AGC_B_RATE54_24, ofdm_b); + + mcs_a = mcsbase[0] | mcsbase[0] << 8 | + mcsbase[0] << 16 | mcsbase[0] << 24; + mcs_b = mcsbase[1] | mcsbase[1] << 8 | + mcsbase[1] << 16 | mcsbase[1] << 24; + + rtl8xxxu_write32(priv, REG_TX_AGC_A_MCS03_MCS00, mcs_a); + rtl8xxxu_write32(priv, REG_TX_AGC_B_MCS03_MCS00, mcs_b); + + rtl8xxxu_write32(priv, REG_TX_AGC_A_MCS07_MCS04, mcs_a); + rtl8xxxu_write32(priv, REG_TX_AGC_B_MCS07_MCS04, mcs_b); + + rtl8xxxu_write32(priv, REG_TX_AGC_A_MCS11_MCS08, mcs_a); + rtl8xxxu_write32(priv, REG_TX_AGC_B_MCS11_MCS08, mcs_b); + + rtl8xxxu_write32(priv, REG_TX_AGC_A_MCS15_MCS12, mcs_a); + for (i = 0; i < 3; i++) { + if (i != 2) + val8 = (mcsbase[0] > 8) ? (mcsbase[0] - 8) : 0; + else + val8 = (mcsbase[0] > 6) ? (mcsbase[0] - 6) : 0; + rtl8xxxu_write8(priv, REG_OFDM0_XC_TX_IQ_IMBALANCE + i, val8); + } + rtl8xxxu_write32(priv, REG_TX_AGC_B_MCS15_MCS12, mcs_b); + for (i = 0; i < 3; i++) { + if (i != 2) + val8 = (mcsbase[1] > 8) ? (mcsbase[1] - 8) : 0; + else + val8 = (mcsbase[1] > 6) ? (mcsbase[1] - 6) : 0; + rtl8xxxu_write8(priv, REG_OFDM0_XD_TX_IQ_IMBALANCE + i, val8); + } +} + +static void rtl8xxxu_set_linktype(struct rtl8xxxu_priv *priv, + enum nl80211_iftype linktype) +{ + u16 val8; + + val8 = rtl8xxxu_read16(priv, REG_MSR); + val8 &= ~MSR_LINKTYPE_MASK; + + switch (linktype) { + case NL80211_IFTYPE_UNSPECIFIED: + val8 |= MSR_LINKTYPE_NONE; + break; + case NL80211_IFTYPE_ADHOC: + val8 |= MSR_LINKTYPE_ADHOC; + break; + case NL80211_IFTYPE_STATION: + val8 |= MSR_LINKTYPE_STATION; + break; + case NL80211_IFTYPE_AP: + val8 |= MSR_LINKTYPE_AP; + break; + default: + goto out; + } + + rtl8xxxu_write8(priv, REG_MSR, val8); +out: + return; +} + +static void +rtl8xxxu_set_retry(struct rtl8xxxu_priv *priv, u16 short_retry, u16 long_retry) +{ + u16 val16; + + val16 = ((short_retry << RETRY_LIMIT_SHORT_SHIFT) & + RETRY_LIMIT_SHORT_MASK) | + ((long_retry << RETRY_LIMIT_LONG_SHIFT) & + RETRY_LIMIT_LONG_MASK); + + rtl8xxxu_write16(priv, REG_RETRY_LIMIT, val16); +} + +static void +rtl8xxxu_set_spec_sifs(struct rtl8xxxu_priv *priv, u16 cck, u16 ofdm) +{ + u16 val16; + + val16 = ((cck << SPEC_SIFS_CCK_SHIFT) & SPEC_SIFS_CCK_MASK) | + ((ofdm << SPEC_SIFS_OFDM_SHIFT) & SPEC_SIFS_OFDM_MASK); + + rtl8xxxu_write16(priv, REG_SPEC_SIFS, val16); +} + +static void rtl8xxxu_print_chipinfo(struct rtl8xxxu_priv *priv) +{ + struct device *dev = &priv->udev->dev; + char *cut; + + switch (priv->chip_cut) { + case 0: + cut = "A"; + break; + case 1: + cut = "B"; + break; + default: + cut = "unknown"; + } + + dev_info(dev, + "RTL%s rev %s (%s) %iT%iR, TX queues %i, WiFi=%i, BT=%i, GPS=%i, HI PA=%i\n", + priv->chip_name, cut, priv->vendor_umc ? "UMC" : "TSMC", + priv->tx_paths, priv->rx_paths, priv->ep_tx_count, + priv->has_wifi, priv->has_bluetooth, priv->has_gps, + priv->hi_pa); + + dev_info(dev, "RTL%s MAC: %pM\n", priv->chip_name, priv->mac_addr); +} + +static int rtl8xxxu_identify_chip(struct rtl8xxxu_priv *priv) +{ + struct device *dev = &priv->udev->dev; + u32 val32, bonding; + u16 val16; + + val32 = rtl8xxxu_read32(priv, REG_SYS_CFG); + priv->chip_cut = (val32 & SYS_CFG_CHIP_VERSION_MASK) >> + SYS_CFG_CHIP_VERSION_SHIFT; + if (val32 & SYS_CFG_TRP_VAUX_EN) { + dev_info(dev, "Unsupported test chip\n"); + return -ENOTSUPP; + } + + if (val32 & SYS_CFG_BT_FUNC) { + sprintf(priv->chip_name, "8723AU"); + priv->rf_paths = 1; + priv->rx_paths = 1; + priv->tx_paths = 1; + priv->rtlchip = 0x8723a; + + val32 = rtl8xxxu_read32(priv, REG_MULTI_FUNC_CTRL); + if (val32 & MULTI_WIFI_FUNC_EN) + priv->has_wifi = 1; + if (val32 & MULTI_BT_FUNC_EN) + priv->has_bluetooth = 1; + if (val32 & MULTI_GPS_FUNC_EN) + priv->has_gps = 1; + } else if (val32 & SYS_CFG_TYPE_ID) { + bonding = rtl8xxxu_read32(priv, REG_HPON_FSM); + bonding &= HPON_FSM_BONDING_MASK; + if (bonding == HPON_FSM_BONDING_1T2R) { + sprintf(priv->chip_name, "8191CU"); + priv->rf_paths = 2; + priv->rx_paths = 2; + priv->tx_paths = 1; + priv->rtlchip = 0x8191c; + } else { + sprintf(priv->chip_name, "8192CU"); + priv->rf_paths = 2; + priv->rx_paths = 2; + priv->tx_paths = 2; + priv->rtlchip = 0x8192c; + } + priv->has_wifi = 1; + } else { + sprintf(priv->chip_name, "8188CU"); + priv->rf_paths = 1; + priv->rx_paths = 1; + priv->tx_paths = 1; + priv->rtlchip = 0x8188c; + priv->has_wifi = 1; + } + + if (val32 & SYS_CFG_VENDOR_ID) + priv->vendor_umc = 1; + + val32 = rtl8xxxu_read32(priv, REG_GPIO_OUTSTS); + priv->rom_rev = (val32 & GPIO_RF_RL_ID) >> 28; + + val16 = rtl8xxxu_read16(priv, REG_NORMAL_SIE_EP_TX); + if (val16 & NORMAL_SIE_EP_TX_HIGH_MASK) { + priv->ep_tx_high_queue = 1; + priv->ep_tx_count++; + } + + if (val16 & NORMAL_SIE_EP_TX_NORMAL_MASK) { + priv->ep_tx_normal_queue = 1; + priv->ep_tx_count++; + } + + if (val16 & NORMAL_SIE_EP_TX_LOW_MASK) { + priv->ep_tx_low_queue = 1; + priv->ep_tx_count++; + } + + /* + * Fallback for devices that do not provide REG_NORMAL_SIE_EP_TX + */ + if (!priv->ep_tx_count) { + switch (priv->nr_out_eps) { + case 3: + priv->ep_tx_low_queue = 1; + priv->ep_tx_count++; + case 2: + priv->ep_tx_normal_queue = 1; + priv->ep_tx_count++; + case 1: + priv->ep_tx_high_queue = 1; + priv->ep_tx_count++; + break; + default: + dev_info(dev, "Unsupported USB TX end-points\n"); + return -ENOTSUPP; + } + } + + return 0; +} + +static int rtl8723au_parse_efuse(struct rtl8xxxu_priv *priv) +{ + if (priv->efuse_wifi.efuse8723.rtl_id != cpu_to_le16(0x8129)) + return -EINVAL; + + ether_addr_copy(priv->mac_addr, priv->efuse_wifi.efuse8723.mac_addr); + + memcpy(priv->cck_tx_power_index_A, + priv->efuse_wifi.efuse8723.cck_tx_power_index_A, + sizeof(priv->cck_tx_power_index_A)); + memcpy(priv->cck_tx_power_index_B, + priv->efuse_wifi.efuse8723.cck_tx_power_index_B, + sizeof(priv->cck_tx_power_index_B)); + + memcpy(priv->ht40_1s_tx_power_index_A, + priv->efuse_wifi.efuse8723.ht40_1s_tx_power_index_A, + sizeof(priv->ht40_1s_tx_power_index_A)); + memcpy(priv->ht40_1s_tx_power_index_B, + priv->efuse_wifi.efuse8723.ht40_1s_tx_power_index_B, + sizeof(priv->ht40_1s_tx_power_index_B)); + + memcpy(priv->ht20_tx_power_index_diff, + priv->efuse_wifi.efuse8723.ht20_tx_power_index_diff, + sizeof(priv->ht20_tx_power_index_diff)); + memcpy(priv->ofdm_tx_power_index_diff, + priv->efuse_wifi.efuse8723.ofdm_tx_power_index_diff, + sizeof(priv->ofdm_tx_power_index_diff)); + + memcpy(priv->ht40_max_power_offset, + priv->efuse_wifi.efuse8723.ht40_max_power_offset, + sizeof(priv->ht40_max_power_offset)); + memcpy(priv->ht20_max_power_offset, + priv->efuse_wifi.efuse8723.ht20_max_power_offset, + sizeof(priv->ht20_max_power_offset)); + + dev_info(&priv->udev->dev, "Vendor: %.7s\n", + priv->efuse_wifi.efuse8723.vendor_name); + dev_info(&priv->udev->dev, "Product: %.41s\n", + priv->efuse_wifi.efuse8723.device_name); + return 0; +} + +static int rtl8192cu_parse_efuse(struct rtl8xxxu_priv *priv) +{ + int i; + + if (priv->efuse_wifi.efuse8192.rtl_id != cpu_to_le16(0x8129)) + return -EINVAL; + + ether_addr_copy(priv->mac_addr, priv->efuse_wifi.efuse8192.mac_addr); + + memcpy(priv->cck_tx_power_index_A, + priv->efuse_wifi.efuse8192.cck_tx_power_index_A, + sizeof(priv->cck_tx_power_index_A)); + memcpy(priv->cck_tx_power_index_B, + priv->efuse_wifi.efuse8192.cck_tx_power_index_B, + sizeof(priv->cck_tx_power_index_B)); + + memcpy(priv->ht40_1s_tx_power_index_A, + priv->efuse_wifi.efuse8192.ht40_1s_tx_power_index_A, + sizeof(priv->ht40_1s_tx_power_index_A)); + memcpy(priv->ht40_1s_tx_power_index_B, + priv->efuse_wifi.efuse8192.ht40_1s_tx_power_index_B, + sizeof(priv->ht40_1s_tx_power_index_B)); + memcpy(priv->ht40_2s_tx_power_index_diff, + priv->efuse_wifi.efuse8192.ht40_2s_tx_power_index_diff, + sizeof(priv->ht40_2s_tx_power_index_diff)); + + memcpy(priv->ht20_tx_power_index_diff, + priv->efuse_wifi.efuse8192.ht20_tx_power_index_diff, + sizeof(priv->ht20_tx_power_index_diff)); + memcpy(priv->ofdm_tx_power_index_diff, + priv->efuse_wifi.efuse8192.ofdm_tx_power_index_diff, + sizeof(priv->ofdm_tx_power_index_diff)); + + memcpy(priv->ht40_max_power_offset, + priv->efuse_wifi.efuse8192.ht40_max_power_offset, + sizeof(priv->ht40_max_power_offset)); + memcpy(priv->ht20_max_power_offset, + priv->efuse_wifi.efuse8192.ht20_max_power_offset, + sizeof(priv->ht20_max_power_offset)); + + dev_info(&priv->udev->dev, "Vendor: %.7s\n", + priv->efuse_wifi.efuse8192.vendor_name); + dev_info(&priv->udev->dev, "Product: %.20s\n", + priv->efuse_wifi.efuse8192.device_name); + + if (priv->efuse_wifi.efuse8192.rf_regulatory & 0x20) { + sprintf(priv->chip_name, "8188RU"); + priv->hi_pa = 1; + } + + if (rtl8xxxu_debug & RTL8XXXU_DEBUG_EFUSE) { + unsigned char *raw = priv->efuse_wifi.raw; + + dev_info(&priv->udev->dev, + "%s: dumping efuse (0x%02zx bytes):\n", + __func__, sizeof(struct rtl8192cu_efuse)); + for (i = 0; i < sizeof(struct rtl8192cu_efuse); i += 8) { + dev_info(&priv->udev->dev, "%02x: " + "%02x %02x %02x %02x %02x %02x %02x %02x\n", i, + raw[i], raw[i + 1], raw[i + 2], + raw[i + 3], raw[i + 4], raw[i + 5], + raw[i + 6], raw[i + 7]); + } + } + return 0; +} + +static int +rtl8xxxu_read_efuse8(struct rtl8xxxu_priv *priv, u16 offset, u8 *data) +{ + int i; + u8 val8; + u32 val32; + + /* Write Address */ + rtl8xxxu_write8(priv, REG_EFUSE_CTRL + 1, offset & 0xff); + val8 = rtl8xxxu_read8(priv, REG_EFUSE_CTRL + 2); + val8 &= 0xfc; + val8 |= (offset >> 8) & 0x03; + rtl8xxxu_write8(priv, REG_EFUSE_CTRL + 2, val8); + + val8 = rtl8xxxu_read8(priv, REG_EFUSE_CTRL + 3); + rtl8xxxu_write8(priv, REG_EFUSE_CTRL + 3, val8 & 0x7f); + + /* Poll for data read */ + val32 = rtl8xxxu_read32(priv, REG_EFUSE_CTRL); + for (i = 0; i < RTL8XXXU_MAX_REG_POLL; i++) { + val32 = rtl8xxxu_read32(priv, REG_EFUSE_CTRL); + if (val32 & BIT(31)) + break; + } + + if (i == RTL8XXXU_MAX_REG_POLL) + return -EIO; + + udelay(50); + val32 = rtl8xxxu_read32(priv, REG_EFUSE_CTRL); + + *data = val32 & 0xff; + return 0; +} + +static int rtl8xxxu_read_efuse(struct rtl8xxxu_priv *priv) +{ + struct device *dev = &priv->udev->dev; + int i, ret = 0; + u8 val8, word_mask, header, extheader; + u16 val16, efuse_addr, offset; + u32 val32; + + val16 = rtl8xxxu_read16(priv, REG_9346CR); + if (val16 & EEPROM_ENABLE) + priv->has_eeprom = 1; + if (val16 & EEPROM_BOOT) + priv->boot_eeprom = 1; + + val32 = rtl8xxxu_read32(priv, REG_EFUSE_TEST); + val32 = (val32 & ~EFUSE_SELECT_MASK) | EFUSE_WIFI_SELECT; + rtl8xxxu_write32(priv, REG_EFUSE_TEST, val32); + + dev_dbg(dev, "Booting from %s\n", + priv->boot_eeprom ? "EEPROM" : "EFUSE"); + + rtl8xxxu_write8(priv, REG_EFUSE_ACCESS, EFUSE_ACCESS_ENABLE); + + /* 1.2V Power: From VDDON with Power Cut(0x0000[15]), default valid */ + val16 = rtl8xxxu_read16(priv, REG_SYS_ISO_CTRL); + if (!(val16 & SYS_ISO_PWC_EV12V)) { + val16 |= SYS_ISO_PWC_EV12V; + rtl8xxxu_write16(priv, REG_SYS_ISO_CTRL, val16); + } + /* Reset: 0x0000[28], default valid */ + val16 = rtl8xxxu_read16(priv, REG_SYS_FUNC); + if (!(val16 & SYS_FUNC_ELDR)) { + val16 |= SYS_FUNC_ELDR; + rtl8xxxu_write16(priv, REG_SYS_FUNC, val16); + } + + /* + * Clock: Gated(0x0008[5]) 8M(0x0008[1]) clock from ANA, default valid + */ + val16 = rtl8xxxu_read16(priv, REG_SYS_CLKR); + if (!(val16 & SYS_CLK_LOADER_ENABLE) || !(val16 & SYS_CLK_ANA8M)) { + val16 |= (SYS_CLK_LOADER_ENABLE | SYS_CLK_ANA8M); + rtl8xxxu_write16(priv, REG_SYS_CLKR, val16); + } + + /* Default value is 0xff */ + memset(priv->efuse_wifi.raw, 0xff, EFUSE_MAP_LEN_8723A); + + efuse_addr = 0; + while (efuse_addr < EFUSE_REAL_CONTENT_LEN_8723A) { + ret = rtl8xxxu_read_efuse8(priv, efuse_addr++, &header); + if (ret || header == 0xff) + goto exit; + + if ((header & 0x1f) == 0x0f) { /* extended header */ + offset = (header & 0xe0) >> 5; + + ret = rtl8xxxu_read_efuse8(priv, efuse_addr++, + &extheader); + if (ret) + goto exit; + /* All words disabled */ + if ((extheader & 0x0f) == 0x0f) + continue; + + offset |= ((extheader & 0xf0) >> 1); + word_mask = extheader & 0x0f; + } else { + offset = (header >> 4) & 0x0f; + word_mask = header & 0x0f; + } + + if (offset < EFUSE_MAX_SECTION_8723A) { + u16 map_addr; + /* Get word enable value from PG header */ + + /* We have 8 bits to indicate validity */ + map_addr = offset * 8; + if (map_addr >= EFUSE_MAP_LEN_8723A) { + dev_warn(dev, "%s: Illegal map_addr (%04x), " + "efuse corrupt!\n", + __func__, map_addr); + ret = -EINVAL; + goto exit; + } + for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) { + /* Check word enable condition in the section */ + if (!(word_mask & BIT(i))) { + ret = rtl8xxxu_read_efuse8(priv, + efuse_addr++, + &val8); + if (ret) + goto exit; + priv->efuse_wifi.raw[map_addr++] = val8; + + ret = rtl8xxxu_read_efuse8(priv, + efuse_addr++, + &val8); + if (ret) + goto exit; + priv->efuse_wifi.raw[map_addr++] = val8; + } else + map_addr += 2; + } + } else { + dev_warn(dev, + "%s: Illegal offset (%04x), efuse corrupt!\n", + __func__, offset); + ret = -EINVAL; + goto exit; + } + } + +exit: + rtl8xxxu_write8(priv, REG_EFUSE_ACCESS, EFUSE_ACCESS_DISABLE); + + return ret; +} + +static int rtl8xxxu_start_firmware(struct rtl8xxxu_priv *priv) +{ + struct device *dev = &priv->udev->dev; + int ret = 0, i; + u32 val32; + + /* Poll checksum report */ + for (i = 0; i < RTL8XXXU_FIRMWARE_POLL_MAX; i++) { + val32 = rtl8xxxu_read32(priv, REG_MCU_FW_DL); + if (val32 & MCU_FW_DL_CSUM_REPORT) + break; + } + + if (i == RTL8XXXU_FIRMWARE_POLL_MAX) { + dev_warn(dev, "Firmware checksum poll timed out\n"); + ret = -EAGAIN; + goto exit; + } + + val32 = rtl8xxxu_read32(priv, REG_MCU_FW_DL); + val32 |= MCU_FW_DL_READY; + val32 &= ~MCU_WINT_INIT_READY; + rtl8xxxu_write32(priv, REG_MCU_FW_DL, val32); + + /* Wait for firmware to become ready */ + for (i = 0; i < RTL8XXXU_FIRMWARE_POLL_MAX; i++) { + val32 = rtl8xxxu_read32(priv, REG_MCU_FW_DL); + if (val32 & MCU_WINT_INIT_READY) + break; + + udelay(100); + } + + if (i == RTL8XXXU_FIRMWARE_POLL_MAX) { + dev_warn(dev, "Firmware failed to start\n"); + ret = -EAGAIN; + goto exit; + } + +exit: + return ret; +} + +static int rtl8xxxu_download_firmware(struct rtl8xxxu_priv *priv) +{ + int pages, remainder, i, ret; + u8 val8; + u16 val16; + u32 val32; + u8 *fwptr; + + val8 = rtl8xxxu_read8(priv, REG_SYS_FUNC + 1); + val8 |= 4; + rtl8xxxu_write8(priv, REG_SYS_FUNC + 1, val8); + + /* 8051 enable */ + val16 = rtl8xxxu_read16(priv, REG_SYS_FUNC); + rtl8xxxu_write16(priv, REG_SYS_FUNC, val16 | SYS_FUNC_CPU_ENABLE); + + /* MCU firmware download enable */ + val8 = rtl8xxxu_read8(priv, REG_MCU_FW_DL); + rtl8xxxu_write8(priv, REG_MCU_FW_DL, val8 | MCU_FW_DL_ENABLE); + + /* 8051 reset */ + val32 = rtl8xxxu_read32(priv, REG_MCU_FW_DL); + rtl8xxxu_write32(priv, REG_MCU_FW_DL, val32 & ~BIT(19)); + + /* Reset firmware download checksum */ + val8 = rtl8xxxu_read8(priv, REG_MCU_FW_DL); + rtl8xxxu_write8(priv, REG_MCU_FW_DL, val8 | MCU_FW_DL_CSUM_REPORT); + + pages = priv->fw_size / RTL_FW_PAGE_SIZE; + remainder = priv->fw_size % RTL_FW_PAGE_SIZE; + + fwptr = priv->fw_data->data; + + for (i = 0; i < pages; i++) { + val8 = rtl8xxxu_read8(priv, REG_MCU_FW_DL + 2) & 0xF8; + rtl8xxxu_write8(priv, REG_MCU_FW_DL + 2, val8 | i); + + ret = rtl8xxxu_writeN(priv, REG_FW_START_ADDRESS, + fwptr, RTL_FW_PAGE_SIZE); + if (ret != RTL_FW_PAGE_SIZE) { + ret = -EAGAIN; + goto fw_abort; + } + + fwptr += RTL_FW_PAGE_SIZE; + } + + if (remainder) { + val8 = rtl8xxxu_read8(priv, REG_MCU_FW_DL + 2) & 0xF8; + rtl8xxxu_write8(priv, REG_MCU_FW_DL + 2, val8 | i); + ret = rtl8xxxu_writeN(priv, REG_FW_START_ADDRESS, + fwptr, remainder); + if (ret != remainder) { + ret = -EAGAIN; + goto fw_abort; + } + } + + ret = 0; +fw_abort: + /* MCU firmware download disable */ + val16 = rtl8xxxu_read16(priv, REG_MCU_FW_DL); + rtl8xxxu_write16(priv, REG_MCU_FW_DL, + val16 & (~MCU_FW_DL_ENABLE & 0xff)); + + return ret; +} + +static int rtl8xxxu_load_firmware(struct rtl8xxxu_priv *priv, char *fw_name) +{ + struct device *dev = &priv->udev->dev; + const struct firmware *fw; + int ret = 0; + u16 signature; + + dev_info(dev, "%s: Loading firmware %s\n", DRIVER_NAME, fw_name); + if (request_firmware(&fw, fw_name, &priv->udev->dev)) { + dev_warn(dev, "request_firmware(%s) failed\n", fw_name); + ret = -EAGAIN; + goto exit; + } + if (!fw) { + dev_warn(dev, "Firmware data not available\n"); + ret = -EINVAL; + goto exit; + } + + priv->fw_data = kmemdup(fw->data, fw->size, GFP_KERNEL); + priv->fw_size = fw->size - sizeof(struct rtl8xxxu_firmware_header); + + signature = le16_to_cpu(priv->fw_data->signature); + switch (signature & 0xfff0) { + case 0x92c0: + case 0x88c0: + case 0x2300: + break; + default: + ret = -EINVAL; + dev_warn(dev, "%s: Invalid firmware signature: 0x%04x\n", + __func__, signature); + } + + dev_info(dev, "Firmware revision %i.%i (signature 0x%04x)\n", + le16_to_cpu(priv->fw_data->major_version), + priv->fw_data->minor_version, signature); + +exit: + release_firmware(fw); + return ret; +} + +static int rtl8723au_load_firmware(struct rtl8xxxu_priv *priv) +{ + char *fw_name; + int ret; + + switch (priv->chip_cut) { + case 0: + fw_name = "rtlwifi/rtl8723aufw_A.bin"; + break; + case 1: + if (priv->enable_bluetooth) + fw_name = "rtlwifi/rtl8723aufw_B.bin"; + else + fw_name = "rtlwifi/rtl8723aufw_B_NoBT.bin"; + + break; + default: + return -EINVAL; + } + + ret = rtl8xxxu_load_firmware(priv, fw_name); + return ret; +} + +static int rtl8192cu_load_firmware(struct rtl8xxxu_priv *priv) +{ + char *fw_name; + int ret; + + if (!priv->vendor_umc) + fw_name = "rtlwifi/rtl8192cufw_TMSC.bin"; + else if (priv->chip_cut || priv->rtlchip == 0x8192c) + fw_name = "rtlwifi/rtl8192cufw_B.bin"; + else + fw_name = "rtlwifi/rtl8192cufw_A.bin"; + + ret = rtl8xxxu_load_firmware(priv, fw_name); + + return ret; +} + +static void rtl8xxxu_firmware_self_reset(struct rtl8xxxu_priv *priv) +{ + u16 val16; + int i = 100; + + /* Inform 8051 to perform reset */ + rtl8xxxu_write8(priv, REG_HMTFR + 3, 0x20); + + for (i = 100; i > 0; i--) { + val16 = rtl8xxxu_read16(priv, REG_SYS_FUNC); + + if (!(val16 & SYS_FUNC_CPU_ENABLE)) { + dev_dbg(&priv->udev->dev, + "%s: Firmware self reset success!\n", __func__); + break; + } + udelay(50); + } + + if (!i) { + /* Force firmware reset */ + val16 = rtl8xxxu_read16(priv, REG_SYS_FUNC); + val16 &= ~SYS_FUNC_CPU_ENABLE; + rtl8xxxu_write16(priv, REG_SYS_FUNC, val16); + } +} + +static int +rtl8xxxu_init_mac(struct rtl8xxxu_priv *priv, struct rtl8xxxu_reg8val *array) +{ + int i, ret; + u16 reg; + u8 val; + + for (i = 0; ; i++) { + reg = array[i].reg; + val = array[i].val; + + if (reg == 0xffff && val == 0xff) + break; + + ret = rtl8xxxu_write8(priv, reg, val); + if (ret != 1) { + dev_warn(&priv->udev->dev, + "Failed to initialize MAC\n"); + return -EAGAIN; + } + } + + rtl8xxxu_write8(priv, REG_MAX_AGGR_NUM, 0x0a); + + return 0; +} + +static int rtl8xxxu_init_phy_regs(struct rtl8xxxu_priv *priv, + struct rtl8xxxu_reg32val *array) +{ + int i, ret; + u16 reg; + u32 val; + + for (i = 0; ; i++) { + reg = array[i].reg; + val = array[i].val; + + if (reg == 0xffff && val == 0xffffffff) + break; + + ret = rtl8xxxu_write32(priv, reg, val); + if (ret != sizeof(val)) { + dev_warn(&priv->udev->dev, + "Failed to initialize PHY\n"); + return -EAGAIN; + } + udelay(1); + } + + return 0; +} + +/* + * Most of this is black magic retrieved from the old rtl8723au driver + */ +static int rtl8xxxu_init_phy_bb(struct rtl8xxxu_priv *priv) +{ + u8 val8, ldoa15, ldov12d, lpldo, ldohci12; + u32 val32; + + /* + * Todo: The vendor driver maintains a table of PHY register + * addresses, which is initialized here. Do we need this? + */ + + val8 = rtl8xxxu_read8(priv, REG_AFE_PLL_CTRL); + udelay(2); + val8 |= AFE_PLL_320_ENABLE; + rtl8xxxu_write8(priv, REG_AFE_PLL_CTRL, val8); + udelay(2); + + rtl8xxxu_write8(priv, REG_AFE_PLL_CTRL + 1, 0xff); + udelay(2); + + val8 = rtl8xxxu_read8(priv, REG_SYS_FUNC); + val8 |= SYS_FUNC_BB_GLB_RSTN | SYS_FUNC_BBRSTB; + rtl8xxxu_write8(priv, REG_SYS_FUNC, val8); + + /* AFE_XTAL_RF_GATE (bit 14) if addressing as 32 bit register */ + val32 = rtl8xxxu_read32(priv, REG_AFE_XTAL_CTRL); + val32 &= ~AFE_XTAL_RF_GATE; + if (priv->has_bluetooth) + val32 &= ~AFE_XTAL_BT_GATE; + rtl8xxxu_write32(priv, REG_AFE_XTAL_CTRL, val32); + + /* 6. 0x1f[7:0] = 0x07 */ + val8 = RF_ENABLE | RF_RSTB | RF_SDMRSTB; + rtl8xxxu_write8(priv, REG_RF_CTRL, val8); + + if (priv->hi_pa) + rtl8xxxu_init_phy_regs(priv, rtl8188ru_phy_1t_highpa_table); + else if (priv->tx_paths == 2) + rtl8xxxu_init_phy_regs(priv, rtl8192cu_phy_2t_init_table); + else + rtl8xxxu_init_phy_regs(priv, rtl8723a_phy_1t_init_table); + + + if (priv->rtlchip == 0x8188c && priv->hi_pa && + priv->vendor_umc && priv->chip_cut == 1) + rtl8xxxu_write8(priv, REG_OFDM0_AGC_PARM1 + 2, 0x50); + + if (priv->tx_paths == 1 && priv->rx_paths == 2) { + /* + * For 1T2R boards, patch the registers. + * + * It looks like 8191/2 1T2R boards use path B for TX + */ + val32 = rtl8xxxu_read32(priv, REG_FPGA0_TX_INFO); + val32 &= ~(BIT(0) | BIT(1)); + val32 |= BIT(1); + rtl8xxxu_write32(priv, REG_FPGA0_TX_INFO, val32); + + val32 = rtl8xxxu_read32(priv, REG_FPGA1_TX_INFO); + val32 &= ~0x300033; + val32 |= 0x200022; + rtl8xxxu_write32(priv, REG_FPGA1_TX_INFO, val32); + + val32 = rtl8xxxu_read32(priv, REG_CCK0_AFE_SETTING); + val32 &= 0xff000000; + val32 |= 0x45000000; + rtl8xxxu_write32(priv, REG_CCK0_AFE_SETTING, val32); + + val32 = rtl8xxxu_read32(priv, REG_OFDM0_TRX_PATH_ENABLE); + val32 &= ~(OFDM_RF_PATH_RX_MASK | OFDM_RF_PATH_TX_MASK); + val32 |= (OFDM_RF_PATH_RX_A | OFDM_RF_PATH_RX_B | + OFDM_RF_PATH_TX_B); + rtl8xxxu_write32(priv, REG_OFDM0_TRX_PATH_ENABLE, val32); + + val32 = rtl8xxxu_read32(priv, REG_OFDM0_AGC_PARM1); + val32 &= ~(BIT(4) | BIT(5)); + val32 |= BIT(4); + rtl8xxxu_write32(priv, REG_OFDM0_AGC_PARM1, val32); + + val32 = rtl8xxxu_read32(priv, REG_TX_CCK_RFON); + val32 &= ~(BIT(27) | BIT(26)); + val32 |= BIT(27); + rtl8xxxu_write32(priv, REG_TX_CCK_RFON, val32); + + val32 = rtl8xxxu_read32(priv, REG_TX_CCK_BBON); + val32 &= ~(BIT(27) | BIT(26)); + val32 |= BIT(27); + rtl8xxxu_write32(priv, REG_TX_CCK_BBON, val32); + + val32 = rtl8xxxu_read32(priv, REG_TX_OFDM_RFON); + val32 &= ~(BIT(27) | BIT(26)); + val32 |= BIT(27); + rtl8xxxu_write32(priv, REG_TX_OFDM_RFON, val32); + + val32 = rtl8xxxu_read32(priv, REG_TX_OFDM_BBON); + val32 &= ~(BIT(27) | BIT(26)); + val32 |= BIT(27); + rtl8xxxu_write32(priv, REG_TX_OFDM_BBON, val32); + + val32 = rtl8xxxu_read32(priv, REG_TX_TO_TX); + val32 &= ~(BIT(27) | BIT(26)); + val32 |= BIT(27); + rtl8xxxu_write32(priv, REG_TX_TO_TX, val32); + } + + if (priv->hi_pa) + rtl8xxxu_init_phy_regs(priv, rtl8xxx_agc_highpa_table); + else + rtl8xxxu_init_phy_regs(priv, rtl8xxx_agc_standard_table); + + if (priv->rtlchip == 0x8723a && + priv->efuse_wifi.efuse8723.version >= 0x01) { + val32 = rtl8xxxu_read32(priv, REG_MAC_PHY_CTRL); + + val8 = priv->efuse_wifi.efuse8723.xtal_k & 0x3f; + val32 &= 0xff000fff; + val32 |= ((val8 | (val8 << 6)) << 12); + + rtl8xxxu_write32(priv, REG_MAC_PHY_CTRL, val32); + } + + ldoa15 = LDOA15_ENABLE | LDOA15_OBUF; + ldov12d = LDOV12D_ENABLE | BIT(2) | (2 << LDOV12D_VADJ_SHIFT); + ldohci12 = 0x57; + lpldo = 1; + val32 = (lpldo << 24) | (ldohci12 << 16) | (ldov12d << 8) | ldoa15; + + rtl8xxxu_write32(priv, REG_LDOA15_CTRL, val32); + + return 0; +} + +static int rtl8xxxu_init_rf_regs(struct rtl8xxxu_priv *priv, + struct rtl8xxxu_rfregval *array, + enum rtl8xxxu_rfpath path) +{ + int i, ret; + u8 reg; + u32 val; + + for (i = 0; ; i++) { + reg = array[i].reg; + val = array[i].val; + + if (reg == 0xff && val == 0xffffffff) + break; + + switch (reg) { + case 0xfe: + msleep(50); + continue; + case 0xfd: + mdelay(5); + continue; + case 0xfc: + mdelay(1); + continue; + case 0xfb: + udelay(50); + continue; + case 0xfa: + udelay(5); + continue; + case 0xf9: + udelay(1); + continue; + } + + reg &= 0x3f; + + ret = rtl8xxxu_write_rfreg(priv, path, reg, val); + if (ret) { + dev_warn(&priv->udev->dev, + "Failed to initialize RF\n"); + return -EAGAIN; + } + udelay(1); + } + + return 0; +} + +static int rtl8xxxu_init_phy_rf(struct rtl8xxxu_priv *priv, + struct rtl8xxxu_rfregval *table, + enum rtl8xxxu_rfpath path) +{ + u32 val32; + u16 val16, rfsi_rfenv; + u16 reg_sw_ctrl, reg_int_oe, reg_hssi_parm2; + + switch (path) { + case RF_A: + reg_sw_ctrl = REG_FPGA0_XA_RF_SW_CTRL; + reg_int_oe = REG_FPGA0_XA_RF_INT_OE; + reg_hssi_parm2 = REG_FPGA0_XA_HSSI_PARM2; + break; + case RF_B: + reg_sw_ctrl = REG_FPGA0_XB_RF_SW_CTRL; + reg_int_oe = REG_FPGA0_XB_RF_INT_OE; + reg_hssi_parm2 = REG_FPGA0_XB_HSSI_PARM2; + break; + default: + dev_err(&priv->udev->dev, "%s:Unsupported RF path %c\n", + __func__, path + 'A'); + return -EINVAL; + } + /* For path B, use XB */ + rfsi_rfenv = rtl8xxxu_read16(priv, reg_sw_ctrl); + rfsi_rfenv &= FPGA0_RF_RFENV; + + /* + * These two we might be able to optimize into one + */ + val32 = rtl8xxxu_read32(priv, reg_int_oe); + val32 |= BIT(20); /* 0x10 << 16 */ + rtl8xxxu_write32(priv, reg_int_oe, val32); + udelay(1); + + val32 = rtl8xxxu_read32(priv, reg_int_oe); + val32 |= BIT(4); + rtl8xxxu_write32(priv, reg_int_oe, val32); + udelay(1); + + /* + * These two we might be able to optimize into one + */ + val32 = rtl8xxxu_read32(priv, reg_hssi_parm2); + val32 &= ~FPGA0_HSSI_3WIRE_ADDR_LEN; + rtl8xxxu_write32(priv, reg_hssi_parm2, val32); + udelay(1); + + val32 = rtl8xxxu_read32(priv, reg_hssi_parm2); + val32 &= ~FPGA0_HSSI_3WIRE_DATA_LEN; + rtl8xxxu_write32(priv, reg_hssi_parm2, val32); + udelay(1); + + rtl8xxxu_init_rf_regs(priv, table, path); + + /* For path B, use XB */ + val16 = rtl8xxxu_read16(priv, reg_sw_ctrl); + val16 &= ~FPGA0_RF_RFENV; + val16 |= rfsi_rfenv; + rtl8xxxu_write16(priv, reg_sw_ctrl, val16); + + return 0; +} + +static int rtl8xxxu_llt_write(struct rtl8xxxu_priv *priv, u8 address, u8 data) +{ + int ret = -EBUSY; + int count = 0; + u32 value; + + value = LLT_OP_WRITE | address << 8 | data; + + rtl8xxxu_write32(priv, REG_LLT_INIT, value); + + do { + value = rtl8xxxu_read32(priv, REG_LLT_INIT); + if ((value & LLT_OP_MASK) == LLT_OP_INACTIVE) { + ret = 0; + break; + } + } while (count++ < 20); + + return ret; +} + +static int rtl8xxxu_init_llt_table(struct rtl8xxxu_priv *priv, u8 last_tx_page) +{ + int ret; + int i; + + for (i = 0; i < last_tx_page; i++) { + ret = rtl8xxxu_llt_write(priv, i, i + 1); + if (ret) + goto exit; + } + + ret = rtl8xxxu_llt_write(priv, last_tx_page, 0xff); + if (ret) + goto exit; + + /* Mark remaining pages as a ring buffer */ + for (i = last_tx_page + 1; i < 0xff; i++) { + ret = rtl8xxxu_llt_write(priv, i, (i + 1)); + if (ret) + goto exit; + } + + /* Let last entry point to the start entry of ring buffer */ + ret = rtl8xxxu_llt_write(priv, 0xff, last_tx_page + 1); + if (ret) + goto exit; + +exit: + return ret; +} + +static int rtl8xxxu_init_queue_priority(struct rtl8xxxu_priv *priv) +{ + u16 val16, hi, lo; + u16 hiq, mgq, bkq, beq, viq, voq; + int hip, mgp, bkp, bep, vip, vop; + int ret = 0; + + switch (priv->ep_tx_count) { + case 1: + if (priv->ep_tx_high_queue) { + hi = TRXDMA_QUEUE_HIGH; + } else if (priv->ep_tx_low_queue) { + hi = TRXDMA_QUEUE_LOW; + } else if (priv->ep_tx_normal_queue) { + hi = TRXDMA_QUEUE_NORMAL; + } else { + hi = 0; + ret = -EINVAL; + } + + hiq = hi; + mgq = hi; + bkq = hi; + beq = hi; + viq = hi; + voq = hi; + + hip = 0; + mgp = 0; + bkp = 0; + bep = 0; + vip = 0; + vop = 0; + break; + case 2: + if (priv->ep_tx_high_queue && priv->ep_tx_low_queue) { + hi = TRXDMA_QUEUE_HIGH; + lo = TRXDMA_QUEUE_LOW; + } else if (priv->ep_tx_normal_queue && priv->ep_tx_low_queue) { + hi = TRXDMA_QUEUE_NORMAL; + lo = TRXDMA_QUEUE_LOW; + } else if (priv->ep_tx_high_queue && priv->ep_tx_normal_queue) { + hi = TRXDMA_QUEUE_HIGH; + lo = TRXDMA_QUEUE_NORMAL; + } else { + ret = -EINVAL; + hi = 0; + lo = 0; + } + + hiq = hi; + mgq = hi; + bkq = lo; + beq = lo; + viq = hi; + voq = hi; + + hip = 0; + mgp = 0; + bkp = 1; + bep = 1; + vip = 0; + vop = 0; + break; + case 3: + beq = TRXDMA_QUEUE_LOW; + bkq = TRXDMA_QUEUE_LOW; + viq = TRXDMA_QUEUE_NORMAL; + voq = TRXDMA_QUEUE_HIGH; + mgq = TRXDMA_QUEUE_HIGH; + hiq = TRXDMA_QUEUE_HIGH; + + hip = hiq ^ 3; + mgp = mgq ^ 3; + bkp = bkq ^ 3; + bep = beq ^ 3; + vip = viq ^ 3; + vop = viq ^ 3; + break; + default: + ret = -EINVAL; + } + + /* + * None of the vendor drivers are configuring the beacon + * queue here .... why? + */ + if (!ret) { + val16 = rtl8xxxu_read16(priv, REG_TRXDMA_CTRL); + val16 &= 0x7; + val16 |= (voq << TRXDMA_CTRL_VOQ_SHIFT) | + (viq << TRXDMA_CTRL_VIQ_SHIFT) | + (beq << TRXDMA_CTRL_BEQ_SHIFT) | + (bkq << TRXDMA_CTRL_BKQ_SHIFT) | + (mgq << TRXDMA_CTRL_MGQ_SHIFT) | + (hiq << TRXDMA_CTRL_HIQ_SHIFT); + rtl8xxxu_write16(priv, REG_TRXDMA_CTRL, val16); + + priv->pipe_out[TXDESC_QUEUE_VO] = + usb_sndbulkpipe(priv->udev, priv->out_ep[vop]); + priv->pipe_out[TXDESC_QUEUE_VI] = + usb_sndbulkpipe(priv->udev, priv->out_ep[vip]); + priv->pipe_out[TXDESC_QUEUE_BE] = + usb_sndbulkpipe(priv->udev, priv->out_ep[bep]); + priv->pipe_out[TXDESC_QUEUE_BK] = + usb_sndbulkpipe(priv->udev, priv->out_ep[bkp]); + priv->pipe_out[TXDESC_QUEUE_BEACON] = + usb_sndbulkpipe(priv->udev, priv->out_ep[0]); + priv->pipe_out[TXDESC_QUEUE_MGNT] = + usb_sndbulkpipe(priv->udev, priv->out_ep[mgp]); + priv->pipe_out[TXDESC_QUEUE_HIGH] = + usb_sndbulkpipe(priv->udev, priv->out_ep[hip]); + priv->pipe_out[TXDESC_QUEUE_CMD] = + usb_sndbulkpipe(priv->udev, priv->out_ep[0]); + } + + return ret; +} + +static void rtl8xxxu_fill_iqk_matrix_a(struct rtl8xxxu_priv *priv, + bool iqk_ok, int result[][8], + int candidate, bool tx_only) +{ + u32 oldval, x, tx0_a, reg; + int y, tx0_c; + u32 val32; + + if (!iqk_ok) + return; + + val32 = rtl8xxxu_read32(priv, REG_OFDM0_XA_TX_IQ_IMBALANCE); + oldval = val32 >> 22; + + x = result[candidate][0]; + if ((x & 0x00000200) != 0) + x = x | 0xfffffc00; + tx0_a = (x * oldval) >> 8; + + val32 = rtl8xxxu_read32(priv, REG_OFDM0_XA_TX_IQ_IMBALANCE); + val32 &= ~0x3ff; + val32 |= tx0_a; + rtl8xxxu_write32(priv, REG_OFDM0_XA_TX_IQ_IMBALANCE, val32); + + val32 = rtl8xxxu_read32(priv, REG_OFDM0_ENERGY_CCA_THRES); + val32 &= ~BIT(31); + if ((x * oldval >> 7) & 0x1) + val32 |= BIT(31); + rtl8xxxu_write32(priv, REG_OFDM0_ENERGY_CCA_THRES, val32); + + y = result[candidate][1]; + if ((y & 0x00000200) != 0) + y = y | 0xfffffc00; + tx0_c = (y * oldval) >> 8; + + val32 = rtl8xxxu_read32(priv, REG_OFDM0_XC_TX_AFE); + val32 &= ~0xf0000000; + val32 |= (((tx0_c & 0x3c0) >> 6) << 28); + rtl8xxxu_write32(priv, REG_OFDM0_XC_TX_AFE, val32); + + val32 = rtl8xxxu_read32(priv, REG_OFDM0_XA_TX_IQ_IMBALANCE); + val32 &= ~0x003f0000; + val32 |= ((tx0_c & 0x3f) << 16); + rtl8xxxu_write32(priv, REG_OFDM0_XA_TX_IQ_IMBALANCE, val32); + + val32 = rtl8xxxu_read32(priv, REG_OFDM0_ENERGY_CCA_THRES); + val32 &= ~BIT(29); + if ((y * oldval >> 7) & 0x1) + val32 |= BIT(29); + rtl8xxxu_write32(priv, REG_OFDM0_ENERGY_CCA_THRES, val32); + + if (tx_only) { + dev_dbg(&priv->udev->dev, "%s: only TX\n", __func__); + return; + } + + reg = result[candidate][2]; + + val32 = rtl8xxxu_read32(priv, REG_OFDM0_XA_RX_IQ_IMBALANCE); + val32 &= ~0x3ff; + val32 |= (reg & 0x3ff); + rtl8xxxu_write32(priv, REG_OFDM0_XA_RX_IQ_IMBALANCE, val32); + + reg = result[candidate][3] & 0x3F; + + val32 = rtl8xxxu_read32(priv, REG_OFDM0_XA_RX_IQ_IMBALANCE); + val32 &= ~0xfc00; + val32 |= ((reg << 10) & 0xfc00); + rtl8xxxu_write32(priv, REG_OFDM0_XA_RX_IQ_IMBALANCE, val32); + + reg = (result[candidate][3] >> 6) & 0xF; + + val32 = rtl8xxxu_read32(priv, REG_OFDM0_RX_IQ_EXT_ANTA); + val32 &= ~0xf0000000; + val32 |= (reg << 28); + rtl8xxxu_write32(priv, REG_OFDM0_RX_IQ_EXT_ANTA, val32); +} + +static void rtl8xxxu_fill_iqk_matrix_b(struct rtl8xxxu_priv *priv, + bool iqk_ok, int result[][8], + int candidate, bool tx_only) +{ + u32 oldval, x, tx1_a, reg; + int y, tx1_c; + u32 val32; + + if (!iqk_ok) + return; + + val32 = rtl8xxxu_read32(priv, REG_OFDM0_XB_TX_IQ_IMBALANCE); + oldval = val32 >> 22; + + x = result[candidate][4]; + if ((x & 0x00000200) != 0) + x = x | 0xfffffc00; + tx1_a = (x * oldval) >> 8; + + val32 = rtl8xxxu_read32(priv, REG_OFDM0_XB_TX_IQ_IMBALANCE); + val32 &= ~0x3ff; + val32 |= tx1_a; + rtl8xxxu_write32(priv, REG_OFDM0_XB_TX_IQ_IMBALANCE, val32); + + val32 = rtl8xxxu_read32(priv, REG_OFDM0_ENERGY_CCA_THRES); + val32 &= ~BIT(27); + if ((x * oldval >> 7) & 0x1) + val32 |= BIT(27); + rtl8xxxu_write32(priv, REG_OFDM0_ENERGY_CCA_THRES, val32); + + y = result[candidate][5]; + if ((y & 0x00000200) != 0) + y = y | 0xfffffc00; + tx1_c = (y * oldval) >> 8; + + val32 = rtl8xxxu_read32(priv, REG_OFDM0_XD_TX_AFE); + val32 &= ~0xf0000000; + val32 |= (((tx1_c & 0x3c0) >> 6) << 28); + rtl8xxxu_write32(priv, REG_OFDM0_XD_TX_AFE, val32); + + val32 = rtl8xxxu_read32(priv, REG_OFDM0_XB_TX_IQ_IMBALANCE); + val32 &= ~0x003f0000; + val32 |= ((tx1_c & 0x3f) << 16); + rtl8xxxu_write32(priv, REG_OFDM0_XB_TX_IQ_IMBALANCE, val32); + + val32 = rtl8xxxu_read32(priv, REG_OFDM0_ENERGY_CCA_THRES); + val32 &= ~BIT(25); + if ((y * oldval >> 7) & 0x1) + val32 |= BIT(25); + rtl8xxxu_write32(priv, REG_OFDM0_ENERGY_CCA_THRES, val32); + + if (tx_only) { + dev_dbg(&priv->udev->dev, "%s: only TX\n", __func__); + return; + } + + reg = result[candidate][6]; + + val32 = rtl8xxxu_read32(priv, REG_OFDM0_XB_RX_IQ_IMBALANCE); + val32 &= ~0x3ff; + val32 |= (reg & 0x3ff); + rtl8xxxu_write32(priv, REG_OFDM0_XB_RX_IQ_IMBALANCE, val32); + + reg = result[candidate][7] & 0x3f; + + val32 = rtl8xxxu_read32(priv, REG_OFDM0_XB_RX_IQ_IMBALANCE); + val32 &= ~0xfc00; + val32 |= ((reg << 10) & 0xfc00); + rtl8xxxu_write32(priv, REG_OFDM0_XB_RX_IQ_IMBALANCE, val32); + + reg = (result[candidate][7] >> 6) & 0xf; + + val32 = rtl8xxxu_read32(priv, REG_OFDM0_AGCR_SSI_TABLE); + val32 &= ~0x0000f000; + val32 |= (reg << 12); + rtl8xxxu_write32(priv, REG_OFDM0_AGCR_SSI_TABLE, val32); +} + +#define MAX_TOLERANCE 5 + +static bool rtl8xxxu_simularity_compare(struct rtl8xxxu_priv *priv, + int result[][8], int c1, int c2) +{ + u32 i, j, diff, simubitmap, bound = 0; + int candidate[2] = {-1, -1}; /* for path A and path B */ + bool retval = true; + + if (priv->tx_paths > 1) + bound = 8; + else + bound = 4; + + simubitmap = 0; + + for (i = 0; i < bound; i++) { + diff = (result[c1][i] > result[c2][i]) ? + (result[c1][i] - result[c2][i]) : + (result[c2][i] - result[c1][i]); + if (diff > MAX_TOLERANCE) { + if ((i == 2 || i == 6) && !simubitmap) { + if (result[c1][i] + result[c1][i + 1] == 0) + candidate[(i / 4)] = c2; + else if (result[c2][i] + result[c2][i + 1] == 0) + candidate[(i / 4)] = c1; + else + simubitmap = simubitmap | (1 << i); + } else { + simubitmap = simubitmap | (1 << i); + } + } + } + + if (simubitmap == 0) { + for (i = 0; i < (bound / 4); i++) { + if (candidate[i] >= 0) { + for (j = i * 4; j < (i + 1) * 4 - 2; j++) + result[3][j] = result[candidate[i]][j]; + retval = false; + } + } + return retval; + } else if (!(simubitmap & 0x0f)) { + /* path A OK */ + for (i = 0; i < 4; i++) + result[3][i] = result[c1][i]; + } else if (!(simubitmap & 0xf0) && priv->tx_paths > 1) { + /* path B OK */ + for (i = 4; i < 8; i++) + result[3][i] = result[c1][i]; + } + + return false; +} + +static void +rtl8xxxu_save_mac_regs(struct rtl8xxxu_priv *priv, const u32 *reg, u32 *backup) +{ + int i; + + for (i = 0; i < (RTL8XXXU_MAC_REGS - 1); i++) + backup[i] = rtl8xxxu_read8(priv, reg[i]); + + backup[i] = rtl8xxxu_read32(priv, reg[i]); +} + +static void rtl8xxxu_restore_mac_regs(struct rtl8xxxu_priv *priv, + const u32 *reg, u32 *backup) +{ + int i; + + for (i = 0; i < (RTL8XXXU_MAC_REGS - 1); i++) + rtl8xxxu_write8(priv, reg[i], backup[i]); + + rtl8xxxu_write32(priv, reg[i], backup[i]); +} + +static void rtl8xxxu_save_regs(struct rtl8xxxu_priv *priv, const u32 *regs, + u32 *backup, int count) +{ + int i; + + for (i = 0; i < count; i++) + backup[i] = rtl8xxxu_read32(priv, regs[i]); +} + +static void rtl8xxxu_restore_regs(struct rtl8xxxu_priv *priv, const u32 *regs, + u32 *backup, int count) +{ + int i; + + for (i = 0; i < count; i++) + rtl8xxxu_write32(priv, regs[i], backup[i]); +} + + +static void rtl8xxxu_path_adda_on(struct rtl8xxxu_priv *priv, const u32 *regs, + bool path_a_on) +{ + u32 path_on; + int i; + + path_on = path_a_on ? 0x04db25a4 : 0x0b1b25a4; + if (priv->tx_paths == 1) { + path_on = 0x0bdb25a0; + rtl8xxxu_write32(priv, regs[0], 0x0b1b25a0); + } else { + rtl8xxxu_write32(priv, regs[0], path_on); + } + + for (i = 1 ; i < RTL8XXXU_ADDA_REGS ; i++) + rtl8xxxu_write32(priv, regs[i], path_on); +} + +static void rtl8xxxu_mac_calibration(struct rtl8xxxu_priv *priv, + const u32 *regs, u32 *backup) +{ + int i = 0; + + rtl8xxxu_write8(priv, regs[i], 0x3f); + + for (i = 1 ; i < (RTL8XXXU_MAC_REGS - 1); i++) + rtl8xxxu_write8(priv, regs[i], (u8)(backup[i] & ~BIT(3))); + + rtl8xxxu_write8(priv, regs[i], (u8)(backup[i] & ~BIT(5))); +} + +static int rtl8xxxu_iqk_path_a(struct rtl8xxxu_priv *priv) +{ + u32 reg_eac, reg_e94, reg_e9c, reg_ea4, val32; + int result = 0; + + /* path-A IQK setting */ + rtl8xxxu_write32(priv, REG_TX_IQK_TONE_A, 0x10008c1f); + rtl8xxxu_write32(priv, REG_RX_IQK_TONE_A, 0x10008c1f); + rtl8xxxu_write32(priv, REG_TX_IQK_PI_A, 0x82140102); + + val32 = (priv->rf_paths > 1) ? 0x28160202 : + /*IS_81xxC_VENDOR_UMC_B_CUT(pHalData->VersionID)?0x28160202: */ + 0x28160502; + rtl8xxxu_write32(priv, REG_RX_IQK_PI_A, val32); + + /* path-B IQK setting */ + if (priv->rf_paths > 1) { + rtl8xxxu_write32(priv, REG_TX_IQK_TONE_B, 0x10008c22); + rtl8xxxu_write32(priv, REG_RX_IQK_TONE_B, 0x10008c22); + rtl8xxxu_write32(priv, REG_TX_IQK_PI_B, 0x82140102); + rtl8xxxu_write32(priv, REG_RX_IQK_PI_B, 0x28160202); + } + + /* LO calibration setting */ + rtl8xxxu_write32(priv, REG_IQK_AGC_RSP, 0x001028d1); + + /* One shot, path A LOK & IQK */ + rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf9000000); + rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf8000000); + + mdelay(1); + + /* Check failed */ + reg_eac = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_A_2); + reg_e94 = rtl8xxxu_read32(priv, REG_TX_POWER_BEFORE_IQK_A); + reg_e9c = rtl8xxxu_read32(priv, REG_TX_POWER_AFTER_IQK_A); + reg_ea4 = rtl8xxxu_read32(priv, REG_RX_POWER_BEFORE_IQK_A_2); + + if (!(reg_eac & BIT(28)) && + ((reg_e94 & 0x03ff0000) != 0x01420000) && + ((reg_e9c & 0x03ff0000) != 0x00420000)) + result |= 0x01; + else /* If TX not OK, ignore RX */ + goto out; + + /* If TX is OK, check whether RX is OK */ + if (!(reg_eac & BIT(27)) && + ((reg_ea4 & 0x03ff0000) != 0x01320000) && + ((reg_eac & 0x03ff0000) != 0x00360000)) + result |= 0x02; + else + dev_warn(&priv->udev->dev, "%s: Path A RX IQK failed!\n", + __func__); +out: + return result; +} + +static int rtl8xxxu_iqk_path_b(struct rtl8xxxu_priv *priv) +{ + u32 reg_eac, reg_eb4, reg_ebc, reg_ec4, reg_ecc; + int result = 0; + + /* One shot, path B LOK & IQK */ + rtl8xxxu_write32(priv, REG_IQK_AGC_CONT, 0x00000002); + rtl8xxxu_write32(priv, REG_IQK_AGC_CONT, 0x00000000); + + mdelay(1); + + /* Check failed */ + reg_eac = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_A_2); + reg_eb4 = rtl8xxxu_read32(priv, REG_TX_POWER_BEFORE_IQK_B); + reg_ebc = rtl8xxxu_read32(priv, REG_TX_POWER_AFTER_IQK_B); + reg_ec4 = rtl8xxxu_read32(priv, REG_RX_POWER_BEFORE_IQK_B_2); + reg_ecc = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_B_2); + + if (!(reg_eac & BIT(31)) && + ((reg_eb4 & 0x03ff0000) != 0x01420000) && + ((reg_ebc & 0x03ff0000) != 0x00420000)) + result |= 0x01; + else + goto out; + + if (!(reg_eac & BIT(30)) && + (((reg_ec4 & 0x03ff0000) >> 16) != 0x132) && + (((reg_ecc & 0x03ff0000) >> 16) != 0x36)) + result |= 0x02; + else + dev_warn(&priv->udev->dev, "%s: Path B RX IQK failed!\n", + __func__); +out: + return result; +} + +static void rtl8xxxu_phy_iqcalibrate(struct rtl8xxxu_priv *priv, + int result[][8], int t) +{ + struct device *dev = &priv->udev->dev; + u32 i, val32; + int path_a_ok, path_b_ok; + int retry = 2; + const u32 adda_regs[RTL8XXXU_ADDA_REGS] = { + REG_FPGA0_XCD_SWITCH_CTRL, REG_BLUETOOTH, + REG_RX_WAIT_CCA, REG_TX_CCK_RFON, + REG_TX_CCK_BBON, REG_TX_OFDM_RFON, + REG_TX_OFDM_BBON, REG_TX_TO_RX, + REG_TX_TO_TX, REG_RX_CCK, + REG_RX_OFDM, REG_RX_WAIT_RIFS, + REG_RX_TO_RX, REG_STANDBY, + REG_SLEEP, REG_PMPD_ANAEN + }; + const u32 iqk_mac_regs[RTL8XXXU_MAC_REGS] = { + REG_TXPAUSE, REG_BEACON_CTRL, + REG_BEACON_CTRL_1, REG_GPIO_MUXCFG + }; + const u32 iqk_bb_regs[RTL8XXXU_BB_REGS] = { + REG_OFDM0_TRX_PATH_ENABLE, REG_OFDM0_TR_MUX_PAR, + REG_FPGA0_XCD_RF_SW_CTRL, REG_CONFIG_ANT_A, REG_CONFIG_ANT_B, + REG_FPGA0_XAB_RF_SW_CTRL, REG_FPGA0_XA_RF_INT_OE, + REG_FPGA0_XB_RF_INT_OE, REG_FPGA0_RF_MODE + }; + + /* + * Note: IQ calibration must be performed after loading + * PHY_REG.txt , and radio_a, radio_b.txt + */ + + if (t == 0) { + /* Save ADDA parameters, turn Path A ADDA on */ + rtl8xxxu_save_regs(priv, adda_regs, priv->adda_backup, + RTL8XXXU_ADDA_REGS); + rtl8xxxu_save_mac_regs(priv, iqk_mac_regs, priv->mac_backup); + rtl8xxxu_save_regs(priv, iqk_bb_regs, + priv->bb_backup, RTL8XXXU_BB_REGS); + } + + rtl8xxxu_path_adda_on(priv, adda_regs, true); + + if (t == 0) { + val32 = rtl8xxxu_read32(priv, REG_FPGA0_XA_HSSI_PARM1); + if (val32 & FPGA0_HSSI_PARM1_PI) + priv->pi_enabled = 1; + } + + if (!priv->pi_enabled) { + /* Switch BB to PI mode to do IQ Calibration. */ + rtl8xxxu_write32(priv, REG_FPGA0_XA_HSSI_PARM1, 0x01000100); + rtl8xxxu_write32(priv, REG_FPGA0_XB_HSSI_PARM1, 0x01000100); + } + + val32 = rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE); + val32 &= ~FPGA_RF_MODE_CCK; + rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32); + + rtl8xxxu_write32(priv, REG_OFDM0_TRX_PATH_ENABLE, 0x03a05600); + rtl8xxxu_write32(priv, REG_OFDM0_TR_MUX_PAR, 0x000800e4); + rtl8xxxu_write32(priv, REG_FPGA0_XCD_RF_SW_CTRL, 0x22204000); + + val32 = rtl8xxxu_read32(priv, REG_FPGA0_XAB_RF_SW_CTRL); + val32 |= (FPGA0_RF_PAPE | (FPGA0_RF_PAPE << FPGA0_RF_BD_CTRL_SHIFT)); + rtl8xxxu_write32(priv, REG_FPGA0_XAB_RF_SW_CTRL, val32); + + val32 = rtl8xxxu_read32(priv, REG_FPGA0_XA_RF_INT_OE); + val32 &= ~BIT(10); + rtl8xxxu_write32(priv, REG_FPGA0_XA_RF_INT_OE, val32); + val32 = rtl8xxxu_read32(priv, REG_FPGA0_XB_RF_INT_OE); + val32 &= ~BIT(10); + rtl8xxxu_write32(priv, REG_FPGA0_XB_RF_INT_OE, val32); + + if (priv->tx_paths > 1) { + rtl8xxxu_write32(priv, REG_FPGA0_XA_LSSI_PARM, 0x00010000); + rtl8xxxu_write32(priv, REG_FPGA0_XB_LSSI_PARM, 0x00010000); + } + + /* MAC settings */ + rtl8xxxu_mac_calibration(priv, iqk_mac_regs, priv->mac_backup); + + /* Page B init */ + rtl8xxxu_write32(priv, REG_CONFIG_ANT_A, 0x00080000); + + if (priv->tx_paths > 1) + rtl8xxxu_write32(priv, REG_CONFIG_ANT_B, 0x00080000); + + /* IQ calibration setting */ + rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x80800000); + rtl8xxxu_write32(priv, REG_TX_IQK, 0x01007c00); + rtl8xxxu_write32(priv, REG_RX_IQK, 0x01004800); + + for (i = 0; i < retry; i++) { + path_a_ok = rtl8xxxu_iqk_path_a(priv); + if (path_a_ok == 0x03) { + val32 = rtl8xxxu_read32(priv, + REG_TX_POWER_BEFORE_IQK_A); + result[t][0] = (val32 >> 16) & 0x3ff; + val32 = rtl8xxxu_read32(priv, + REG_TX_POWER_AFTER_IQK_A); + result[t][1] = (val32 >> 16) & 0x3ff; + val32 = rtl8xxxu_read32(priv, + REG_RX_POWER_BEFORE_IQK_A_2); + result[t][2] = (val32 >> 16) & 0x3ff; + val32 = rtl8xxxu_read32(priv, + REG_RX_POWER_AFTER_IQK_A_2); + result[t][3] = (val32 >> 16) & 0x3ff; + break; + } else if (i == (retry - 1) && path_a_ok == 0x01) { + /* TX IQK OK */ + dev_dbg(dev, "%s: Path A IQK Only Tx Success!!\n", + __func__); + + val32 = rtl8xxxu_read32(priv, + REG_TX_POWER_BEFORE_IQK_A); + result[t][0] = (val32 >> 16) & 0x3ff; + val32 = rtl8xxxu_read32(priv, + REG_TX_POWER_AFTER_IQK_A); + result[t][1] = (val32 >> 16) & 0x3ff; + } + } + + if (!path_a_ok) + dev_dbg(dev, "%s: Path A IQK failed!\n", __func__); + + if (priv->tx_paths > 1) { + /* + * Path A into standby + */ + rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x0); + rtl8xxxu_write32(priv, REG_FPGA0_XA_LSSI_PARM, 0x00010000); + rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x80800000); + + /* Turn Path B ADDA on */ + rtl8xxxu_path_adda_on(priv, adda_regs, false); + + for (i = 0; i < retry; i++) { + path_b_ok = rtl8xxxu_iqk_path_b(priv); + if (path_b_ok == 0x03) { + val32 = rtl8xxxu_read32(priv, REG_TX_POWER_BEFORE_IQK_B); + result[t][4] = (val32 >> 16) & 0x3ff; + val32 = rtl8xxxu_read32(priv, REG_TX_POWER_AFTER_IQK_B); + result[t][5] = (val32 >> 16) & 0x3ff; + val32 = rtl8xxxu_read32(priv, REG_RX_POWER_BEFORE_IQK_B_2); + result[t][6] = (val32 >> 16) & 0x3ff; + val32 = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_B_2); + result[t][7] = (val32 >> 16) & 0x3ff; + break; + } else if (i == (retry - 1) && path_b_ok == 0x01) { + /* TX IQK OK */ + val32 = rtl8xxxu_read32(priv, REG_TX_POWER_BEFORE_IQK_B); + result[t][4] = (val32 >> 16) & 0x3ff; + val32 = rtl8xxxu_read32(priv, REG_TX_POWER_AFTER_IQK_B); + result[t][5] = (val32 >> 16) & 0x3ff; + } + } + + if (!path_b_ok) + dev_dbg(dev, "%s: Path B IQK failed!\n", __func__); + } + + /* Back to BB mode, load original value */ + rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0); + + if (t) { + if (!priv->pi_enabled) { + /* + * Switch back BB to SI mode after finishing + * IQ Calibration + */ + val32 = 0x01000000; + rtl8xxxu_write32(priv, REG_FPGA0_XA_HSSI_PARM1, val32); + rtl8xxxu_write32(priv, REG_FPGA0_XB_HSSI_PARM1, val32); + } + + /* Reload ADDA power saving parameters */ + rtl8xxxu_restore_regs(priv, adda_regs, priv->adda_backup, + RTL8XXXU_ADDA_REGS); + + /* Reload MAC parameters */ + rtl8xxxu_restore_mac_regs(priv, iqk_mac_regs, priv->mac_backup); + + /* Reload BB parameters */ + rtl8xxxu_restore_regs(priv, iqk_bb_regs, + priv->bb_backup, RTL8XXXU_BB_REGS); + + /* Restore RX initial gain */ + rtl8xxxu_write32(priv, REG_FPGA0_XA_LSSI_PARM, 0x00032ed3); + + if (priv->tx_paths > 1) { + rtl8xxxu_write32(priv, REG_FPGA0_XB_LSSI_PARM, + 0x00032ed3); + } + + /* Load 0xe30 IQC default value */ + rtl8xxxu_write32(priv, REG_TX_IQK_TONE_A, 0x01008c00); + rtl8xxxu_write32(priv, REG_RX_IQK_TONE_A, 0x01008c00); + } +} + +static void rtl8723a_phy_iq_calibrate(struct rtl8xxxu_priv *priv) +{ + struct device *dev = &priv->udev->dev; + int result[4][8]; /* last is final result */ + int i, candidate; + bool path_a_ok, path_b_ok; + u32 reg_e94, reg_e9c, reg_ea4, reg_eac; + u32 reg_eb4, reg_ebc, reg_ec4, reg_ecc; + s32 reg_tmp = 0; + bool simu; + + memset(result, 0, sizeof(result)); + candidate = -1; + + path_a_ok = false; + path_b_ok = false; + + rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE); + + for (i = 0; i < 3; i++) { + rtl8xxxu_phy_iqcalibrate(priv, result, i); + + if (i == 1) { + simu = rtl8xxxu_simularity_compare(priv, result, 0, 1); + if (simu) { + candidate = 0; + break; + } + } + + if (i == 2) { + simu = rtl8xxxu_simularity_compare(priv, result, 0, 2); + if (simu) { + candidate = 0; + break; + } + + simu = rtl8xxxu_simularity_compare(priv, result, 1, 2); + if (simu) { + candidate = 1; + } else { + for (i = 0; i < 8; i++) + reg_tmp += result[3][i]; + + if (reg_tmp) + candidate = 3; + else + candidate = -1; + } + } + } + + for (i = 0; i < 4; i++) { + reg_e94 = result[i][0]; + reg_e9c = result[i][1]; + reg_ea4 = result[i][2]; + reg_eac = result[i][3]; + reg_eb4 = result[i][4]; + reg_ebc = result[i][5]; + reg_ec4 = result[i][6]; + reg_ecc = result[i][7]; + } + + if (candidate >= 0) { + reg_e94 = result[candidate][0]; + priv->rege94 = reg_e94; + reg_e9c = result[candidate][1]; + priv->rege9c = reg_e9c; + reg_ea4 = result[candidate][2]; + reg_eac = result[candidate][3]; + reg_eb4 = result[candidate][4]; + priv->regeb4 = reg_eb4; + reg_ebc = result[candidate][5]; + priv->regebc = reg_ebc; + reg_ec4 = result[candidate][6]; + reg_ecc = result[candidate][7]; + dev_dbg(dev, "%s: candidate is %x\n", __func__, candidate); + dev_dbg(dev, + "%s: e94 =%x e9c=%x ea4=%x eac=%x eb4=%x ebc=%x ec4=%x " + "ecc=%x\n ", __func__, reg_e94, reg_e9c, + reg_ea4, reg_eac, reg_eb4, reg_ebc, reg_ec4, reg_ecc); + path_a_ok = true; + path_b_ok = true; + } else { + reg_e94 = reg_eb4 = priv->rege94 = priv->regeb4 = 0x100; + reg_e9c = reg_ebc = priv->rege9c = priv->regebc = 0x0; + } + + if (reg_e94 && candidate >= 0) + rtl8xxxu_fill_iqk_matrix_a(priv, path_a_ok, result, + candidate, (reg_ea4 == 0)); + + if (priv->tx_paths > 1 && reg_eb4) + rtl8xxxu_fill_iqk_matrix_b(priv, path_b_ok, result, + candidate, (reg_ec4 == 0)); + + rtl8xxxu_save_regs(priv, rtl8723au_iqk_phy_iq_bb_reg, + priv->bb_recovery_backup, RTL8XXXU_BB_REGS); +} + +static void rtl8723a_phy_lc_calibrate(struct rtl8xxxu_priv *priv) +{ + u32 val32; + u32 rf_amode, rf_bmode = 0, lstf; + + /* Check continuous TX and Packet TX */ + lstf = rtl8xxxu_read32(priv, REG_OFDM1_LSTF); + + if (lstf & OFDM_LSTF_MASK) { + /* Disable all continuous TX */ + val32 = lstf & ~OFDM_LSTF_MASK; + rtl8xxxu_write32(priv, REG_OFDM1_LSTF, val32); + + /* Read original RF mode Path A */ + rf_amode = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_AC); + + /* Set RF mode to standby Path A */ + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_AC, + (rf_amode & 0x8ffff) | 0x10000); + + /* Path-B */ + if (priv->tx_paths > 1) { + rf_bmode = rtl8xxxu_read_rfreg(priv, RF_B, + RF6052_REG_AC); + + rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_AC, + (rf_bmode & 0x8ffff) | 0x10000); + } + } else { + /* Deal with Packet TX case */ + /* block all queues */ + rtl8xxxu_write8(priv, REG_TXPAUSE, 0xff); + } + + /* Start LC calibration */ + val32 = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_MODE_AG); + val32 |= 0x08000; + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_MODE_AG, val32); + + msleep(100); + + /* Restore original parameters */ + if (lstf & OFDM_LSTF_MASK) { + /* Path-A */ + rtl8xxxu_write32(priv, REG_OFDM1_LSTF, lstf); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_AC, rf_amode); + + /* Path-B */ + if (priv->tx_paths > 1) + rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_AC, + rf_bmode); + } else /* Deal with Packet TX case */ + rtl8xxxu_write8(priv, REG_TXPAUSE, 0x00); +} + +static int rtl8xxxu_set_mac(struct rtl8xxxu_priv *priv) +{ + int i; + u16 reg; + + reg = REG_MACID; + + for (i = 0; i < ETH_ALEN; i++) + rtl8xxxu_write8(priv, reg + i, priv->mac_addr[i]); + + return 0; +} + +static int rtl8xxxu_set_bssid(struct rtl8xxxu_priv *priv, const u8 *bssid) +{ + int i; + u16 reg; + + dev_dbg(&priv->udev->dev, "%s: (%pM)\n", __func__, bssid); + + reg = REG_BSSID; + + for (i = 0; i < ETH_ALEN; i++) + rtl8xxxu_write8(priv, reg + i, bssid[i]); + + return 0; +} + +static void +rtl8xxxu_set_ampdu_factor(struct rtl8xxxu_priv *priv, u8 ampdu_factor) +{ + u8 vals[4] = { 0x41, 0xa8, 0x72, 0xb9 }; + u8 max_agg = 0xf; + int i; + + ampdu_factor = 1 << (ampdu_factor + 2); + if (ampdu_factor > max_agg) + ampdu_factor = max_agg; + + for (i = 0; i < 4; i++) { + if ((vals[i] & 0xf0) > (ampdu_factor << 4)) + vals[i] = (vals[i] & 0x0f) | (ampdu_factor << 4); + + if ((vals[i] & 0x0f) > ampdu_factor) + vals[i] = (vals[i] & 0xf0) | ampdu_factor; + + rtl8xxxu_write8(priv, REG_AGGLEN_LMT + i, vals[i]); + } +} + +static void rtl8xxxu_set_ampdu_min_space(struct rtl8xxxu_priv *priv, u8 density) +{ + u8 val8; + + val8 = rtl8xxxu_read8(priv, REG_AMPDU_MIN_SPACE); + val8 &= 0xf8; + val8 |= density; + rtl8xxxu_write8(priv, REG_AMPDU_MIN_SPACE, val8); +} + +static int rtl8xxxu_active_to_emu(struct rtl8xxxu_priv *priv) +{ + u8 val8; + int count, ret; + + /* Start of rtl8723AU_card_enable_flow */ + /* Act to Cardemu sequence*/ + /* Turn off RF */ + rtl8xxxu_write8(priv, REG_RF_CTRL, 0); + + /* 0x004E[7] = 0, switch DPDT_SEL_P output from register 0x0065[2] */ + val8 = rtl8xxxu_read8(priv, REG_LEDCFG2); + val8 &= ~LEDCFG2_DPDT_SELECT; + rtl8xxxu_write8(priv, REG_LEDCFG2, val8); + + /* 0x0005[1] = 1 turn off MAC by HW state machine*/ + val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1); + val8 |= BIT(1); + rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8); + + for (count = RTL8XXXU_MAX_REG_POLL; count; count--) { + val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1); + if ((val8 & BIT(1)) == 0) + break; + udelay(10); + } + + if (!count) { + dev_warn(&priv->udev->dev, "%s: Disabling MAC timed out\n", + __func__); + ret = -EBUSY; + goto exit; + } + + /* 0x0000[5] = 1 analog Ips to digital, 1:isolation */ + val8 = rtl8xxxu_read8(priv, REG_SYS_ISO_CTRL); + val8 |= SYS_ISO_ANALOG_IPS; + rtl8xxxu_write8(priv, REG_SYS_ISO_CTRL, val8); + + /* 0x0020[0] = 0 disable LDOA12 MACRO block*/ + val8 = rtl8xxxu_read8(priv, REG_LDOA15_CTRL); + val8 &= ~LDOA15_ENABLE; + rtl8xxxu_write8(priv, REG_LDOA15_CTRL, val8); + +exit: + return ret; +} + +static int rtl8xxxu_active_to_lps(struct rtl8xxxu_priv *priv) +{ + u8 val8; + u8 val32; + int count, ret; + + rtl8xxxu_write8(priv, REG_TXPAUSE, 0xff); + + /* + * Poll - wait for RX packet to complete + */ + for (count = RTL8XXXU_MAX_REG_POLL; count; count--) { + val32 = rtl8xxxu_read32(priv, 0x5f8); + if (!val32) + break; + udelay(10); + } + + if (!count) { + dev_warn(&priv->udev->dev, + "%s: RX poll timed out (0x05f8)\n", __func__); + ret = -EBUSY; + goto exit; + } + + /* Disable CCK and OFDM, clock gated */ + val8 = rtl8xxxu_read8(priv, REG_SYS_FUNC); + val8 &= ~SYS_FUNC_BBRSTB; + rtl8xxxu_write8(priv, REG_SYS_FUNC, val8); + + udelay(2); + + /* Reset baseband */ + val8 = rtl8xxxu_read8(priv, REG_SYS_FUNC); + val8 &= ~SYS_FUNC_BB_GLB_RSTN; + rtl8xxxu_write8(priv, REG_SYS_FUNC, val8); + + /* Reset MAC TRX */ + val8 = rtl8xxxu_read8(priv, REG_CR); + val8 = CR_HCI_TXDMA_ENABLE | CR_HCI_RXDMA_ENABLE; + rtl8xxxu_write8(priv, REG_CR, val8); + + /* Reset MAC TRX */ + val8 = rtl8xxxu_read8(priv, REG_CR + 1); + val8 &= ~BIT(1); /* CR_SECURITY_ENABLE */ + rtl8xxxu_write8(priv, REG_CR + 1, val8); + + /* Respond TX OK to scheduler */ + val8 = rtl8xxxu_read8(priv, REG_DUAL_TSF_RST); + val8 |= DUAL_TSF_TX_OK; + rtl8xxxu_write8(priv, REG_DUAL_TSF_RST, val8); + +exit: + return ret; +} + +static void rtl8xxxu_disabled_to_emu(struct rtl8xxxu_priv *priv) +{ + u8 val8; + + /* Clear suspend enable and power down enable*/ + val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1); + val8 &= ~(BIT(3) | BIT(7)); + rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8); + + /* 0x48[16] = 0 to disable GPIO9 as EXT WAKEUP*/ + val8 = rtl8xxxu_read8(priv, REG_GPIO_INTM + 2); + val8 &= ~BIT(0); + rtl8xxxu_write8(priv, REG_GPIO_INTM + 2, val8); + + /* 0x04[12:11] = 11 enable WL suspend*/ + val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1); + val8 &= ~(BIT(3) | BIT(4)); + rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8); +} + +static int rtl8xxxu_emu_to_active(struct rtl8xxxu_priv *priv) +{ + u8 val8; + u32 val32; + int count, ret = 0; + + /* 0x20[0] = 1 enable LDOA12 MACRO block for all interface*/ + val8 = rtl8xxxu_read8(priv, REG_LDOA15_CTRL); + val8 |= LDOA15_ENABLE; + rtl8xxxu_write8(priv, REG_LDOA15_CTRL, val8); + + /* 0x67[0] = 0 to disable BT_GPS_SEL pins*/ + val8 = rtl8xxxu_read8(priv, 0x0067); + val8 &= ~BIT(4); + rtl8xxxu_write8(priv, 0x0067, val8); + + mdelay(1); + + /* 0x00[5] = 0 release analog Ips to digital, 1:isolation */ + val8 = rtl8xxxu_read8(priv, REG_SYS_ISO_CTRL); + val8 &= ~SYS_ISO_ANALOG_IPS; + rtl8xxxu_write8(priv, REG_SYS_ISO_CTRL, val8); + + /* disable SW LPS 0x04[10]= 0 */ + val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1); + val8 &= ~BIT(2); + rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8); + + /* wait till 0x04[17] = 1 power ready*/ + for (count = RTL8XXXU_MAX_REG_POLL; count; count--) { + val32 = rtl8xxxu_read32(priv, REG_APS_FSMCO); + if (val32 & BIT(17)) + break; + + udelay(10); + } + + if (!count) { + ret = -EBUSY; + goto exit; + } + + /* We should be able to optimize the following three entries into one */ + + /* release WLON reset 0x04[16]= 1*/ + val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 2); + val8 |= BIT(0); + rtl8xxxu_write8(priv, REG_APS_FSMCO + 2, val8); + + /* disable HWPDN 0x04[15]= 0*/ + val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1); + val8 &= ~BIT(7); + rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8); + + /* disable WL suspend*/ + val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1); + val8 &= ~(BIT(3) | BIT(4)); + rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8); + + /* set, then poll until 0 */ + val32 = rtl8xxxu_read32(priv, REG_APS_FSMCO); + val32 |= APS_FSMCO_MAC_ENABLE; + rtl8xxxu_write32(priv, REG_APS_FSMCO, val32); + + for (count = RTL8XXXU_MAX_REG_POLL; count; count--) { + val32 = rtl8xxxu_read32(priv, REG_APS_FSMCO); + if ((val32 & APS_FSMCO_MAC_ENABLE) == 0) { + ret = 0; + break; + } + udelay(10); + } + + if (!count) { + ret = -EBUSY; + goto exit; + } + + /* 0x4C[23] = 0x4E[7] = 1, switch DPDT_SEL_P output from WL BB */ + /* + * Note: Vendor driver actually clears this bit, despite the + * documentation claims it's being set! + */ + val8 = rtl8xxxu_read8(priv, REG_LEDCFG2); + val8 |= LEDCFG2_DPDT_SELECT; + val8 &= ~LEDCFG2_DPDT_SELECT; + rtl8xxxu_write8(priv, REG_LEDCFG2, val8); + +exit: + return ret; +} + +static int rtl8xxxu_emu_to_disabled(struct rtl8xxxu_priv *priv) +{ + u8 val8; + + /* 0x0007[7:0] = 0x20 SOP option to disable BG/MB */ + rtl8xxxu_write8(priv, REG_APS_FSMCO + 3, 0x20); + + /* 0x04[12:11] = 01 enable WL suspend */ + val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1); + val8 &= ~BIT(4); + val8 |= BIT(3); + rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8); + + val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1); + val8 |= BIT(7); + rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8); + + /* 0x48[16] = 1 to enable GPIO9 as EXT wakeup */ + val8 = rtl8xxxu_read8(priv, REG_GPIO_INTM + 2); + val8 |= BIT(0); + rtl8xxxu_write8(priv, REG_GPIO_INTM + 2, val8); + + return 0; +} + +static int rtl8723au_power_on(struct rtl8xxxu_priv *priv) +{ + u8 val8; + u16 val16; + u32 val32; + int ret; + + /* + * RSV_CTRL 0x001C[7:0] = 0x00, unlock ISO/CLK/Power control register + */ + rtl8xxxu_write8(priv, REG_RSV_CTRL, 0x0); + + rtl8xxxu_disabled_to_emu(priv); + + ret = rtl8xxxu_emu_to_active(priv); + if (ret) + goto exit; + + /* + * 0x0004[19] = 1, reset 8051 + */ + val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 2); + val8 |= BIT(3); + rtl8xxxu_write8(priv, REG_APS_FSMCO + 2, val8); + + /* + * Enable MAC DMA/WMAC/SCHEDULE/SEC block + * Set CR bit10 to enable 32k calibration. + */ + val16 = rtl8xxxu_read16(priv, REG_CR); + val16 |= (CR_HCI_TXDMA_ENABLE | CR_HCI_RXDMA_ENABLE | + CR_TXDMA_ENABLE | CR_RXDMA_ENABLE | + CR_PROTOCOL_ENABLE | CR_SCHEDULE_ENABLE | + CR_MAC_TX_ENABLE | CR_MAC_RX_ENABLE | + CR_SECURITY_ENABLE | CR_CALTIMER_ENABLE); + rtl8xxxu_write16(priv, REG_CR, val16); + + /* For EFuse PG */ + val32 = rtl8xxxu_read32(priv, REG_EFUSE_CTRL); + val32 &= ~(BIT(28) | BIT(29) | BIT(30)); + val32 |= (0x06 << 28); + rtl8xxxu_write32(priv, REG_EFUSE_CTRL, val32); +exit: + return ret; +} + +static int rtl8192cu_power_on(struct rtl8xxxu_priv *priv) +{ + u8 val8; + u16 val16; + u32 val32; + int i; + + for (i = 100; i; i--) { + val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO); + if (val8 & APS_FSMCO_PFM_ALDN) + break; + } + + if (!i) { + pr_info("%s: Poll failed\n", __func__); + return -ENODEV; + } + + /* + * RSV_CTRL 0x001C[7:0] = 0x00, unlock ISO/CLK/Power control register + */ + rtl8xxxu_write8(priv, REG_RSV_CTRL, 0x0); + rtl8xxxu_write8(priv, REG_SPS0_CTRL, 0x2b); + udelay(100); + + val8 = rtl8xxxu_read8(priv, REG_LDOV12D_CTRL); + if (!(val8 & LDOV12D_ENABLE)) { + pr_info("%s: Enabling LDOV12D (%02x)\n", __func__, val8); + val8 |= LDOV12D_ENABLE; + rtl8xxxu_write8(priv, REG_LDOV12D_CTRL, val8); + + udelay(100); + + val8 = rtl8xxxu_read8(priv, REG_SYS_ISO_CTRL); + val8 &= ~SYS_ISO_MD2PP; + rtl8xxxu_write8(priv, REG_SYS_ISO_CTRL, val8); + } + + /* + * Auto enable WLAN + */ + val16 = rtl8xxxu_read16(priv, REG_APS_FSMCO); + val16 |= APS_FSMCO_MAC_ENABLE; + rtl8xxxu_write16(priv, REG_APS_FSMCO, val16); + + for (i = 1000; i; i--) { + val16 = rtl8xxxu_read16(priv, REG_APS_FSMCO); + if (!(val16 & APS_FSMCO_MAC_ENABLE)) + break; + } + if (!i) { + pr_info("%s: FSMCO_MAC_ENABLE poll failed\n", __func__); + return -EBUSY; + } + + /* + * Enable radio, GPIO, LED + */ + val16 = APS_FSMCO_HW_SUSPEND | APS_FSMCO_ENABLE_POWERDOWN | + APS_FSMCO_PFM_ALDN; + rtl8xxxu_write16(priv, REG_APS_FSMCO, val16); + + /* + * Release RF digital isolation + */ + val16 = rtl8xxxu_read16(priv, REG_SYS_ISO_CTRL); + val16 &= ~SYS_ISO_DIOR; + rtl8xxxu_write16(priv, REG_SYS_ISO_CTRL, val16); + + val8 = rtl8xxxu_read8(priv, REG_APSD_CTRL); + val8 &= ~APSD_CTRL_OFF; + rtl8xxxu_write8(priv, REG_APSD_CTRL, val8); + for (i = 200; i; i--) { + val8 = rtl8xxxu_read8(priv, REG_APSD_CTRL); + if (!(val8 & APSD_CTRL_OFF_STATUS)) + break; + } + + if (!i) { + pr_info("%s: APSD_CTRL poll failed\n", __func__); + return -EBUSY; + } + + /* + * Enable MAC DMA/WMAC/SCHEDULE/SEC block + */ + val16 = rtl8xxxu_read16(priv, REG_CR); + val16 |= CR_HCI_TXDMA_ENABLE | CR_HCI_RXDMA_ENABLE | + CR_TXDMA_ENABLE | CR_RXDMA_ENABLE | CR_PROTOCOL_ENABLE | + CR_SCHEDULE_ENABLE | CR_MAC_TX_ENABLE | CR_MAC_RX_ENABLE; + rtl8xxxu_write16(priv, REG_CR, val16); + + /* + * Workaround for 8188RU LNA power leakage problem. + */ + if (priv->rtlchip == 0x8188c && priv->hi_pa) { + val32 = rtl8xxxu_read32(priv, REG_FPGA0_XCD_RF_PARM); + val32 &= ~BIT(1); + rtl8xxxu_write32(priv, REG_FPGA0_XCD_RF_PARM, val32); + } + return 0; +} + +static void rtl8xxxu_power_off(struct rtl8xxxu_priv *priv) +{ + u8 val8; + u16 val16; + u32 val32; + + /* + * Workaround for 8188RU LNA power leakage problem. + */ + if (priv->rtlchip == 0x8188c && priv->hi_pa) { + val32 = rtl8xxxu_read32(priv, REG_FPGA0_XCD_RF_PARM); + val32 |= BIT(1); + rtl8xxxu_write32(priv, REG_FPGA0_XCD_RF_PARM, val32); + } + + rtl8xxxu_active_to_lps(priv); + + /* Turn off RF */ + rtl8xxxu_write8(priv, REG_RF_CTRL, 0x00); + + /* Reset Firmware if running in RAM */ + if (rtl8xxxu_read8(priv, REG_MCU_FW_DL) & MCU_FW_RAM_SEL) + rtl8xxxu_firmware_self_reset(priv); + + /* Reset MCU */ + val16 = rtl8xxxu_read16(priv, REG_SYS_FUNC); + val16 &= ~SYS_FUNC_CPU_ENABLE; + rtl8xxxu_write16(priv, REG_SYS_FUNC, val16); + + /* Reset MCU ready status */ + rtl8xxxu_write8(priv, REG_MCU_FW_DL, 0x00); + + rtl8xxxu_active_to_emu(priv); + rtl8xxxu_emu_to_disabled(priv); + + /* Reset MCU IO Wrapper */ + val8 = rtl8xxxu_read8(priv, REG_RSV_CTRL + 1); + val8 &= ~BIT(0); + rtl8xxxu_write8(priv, REG_RSV_CTRL + 1, val8); + + val8 = rtl8xxxu_read8(priv, REG_RSV_CTRL + 1); + val8 |= BIT(0); + rtl8xxxu_write8(priv, REG_RSV_CTRL + 1, val8); + + /* RSV_CTRL 0x1C[7:0] = 0x0e lock ISO/CLK/Power control register */ + rtl8xxxu_write8(priv, REG_RSV_CTRL, 0x0e); +} + +static void rtl8xxxu_init_bt(struct rtl8xxxu_priv *priv) +{ + if (!priv->has_bluetooth) + return; +} + +static int rtl8xxxu_init_device(struct ieee80211_hw *hw) +{ + struct rtl8xxxu_priv *priv = hw->priv; + struct device *dev = &priv->udev->dev; + struct rtl8xxxu_rfregval *rftable; + bool macpower; + int ret; + u8 val8; + u16 val16; + u32 val32; + + /* Check if MAC is already powered on */ + val8 = rtl8xxxu_read8(priv, REG_CR); + + /* + * Fix 92DU-VC S3 hang with the reason is that secondary mac is not + * initialized. First MAC returns 0xea, second MAC returns 0x00 + */ + if (val8 == 0xea) + macpower = false; + else + macpower = true; + + ret = priv->fops->power_on(priv); + if (ret < 0) { + dev_warn(dev, "%s: Failed power on\n", __func__); + goto exit; + } + + dev_dbg(dev, "%s: macpower %i\n", __func__, macpower); + if (!macpower) { + ret = rtl8xxxu_init_llt_table(priv, TX_TOTAL_PAGE_NUM); + if (ret) { + dev_warn(dev, "%s: LLT table init failed\n", __func__); + goto exit; + } + } + + ret = rtl8xxxu_download_firmware(priv); + dev_dbg(dev, "%s: download_fiwmare %i\n", __func__, ret); + if (ret) + goto exit; + ret = rtl8xxxu_start_firmware(priv); + dev_dbg(dev, "%s: start_fiwmare %i\n", __func__, ret); + if (ret) + goto exit; + + ret = rtl8xxxu_init_mac(priv, rtl8723a_mac_init_table); + dev_dbg(dev, "%s: init_mac %i\n", __func__, ret); + if (ret) + goto exit; + + ret = rtl8xxxu_init_phy_bb(priv); + dev_dbg(dev, "%s: init_phy_bb %i\n", __func__, ret); + if (ret) + goto exit; + + switch(priv->rtlchip) { + case 0x8723a: + rftable = rtl8723au_radioa_1t_init_table; + ret = rtl8xxxu_init_phy_rf(priv, rftable, RF_A); + break; + case 0x8188c: + if (priv->hi_pa) + rftable = rtl8188ru_radioa_1t_highpa_table; + else + rftable = rtl8192cu_radioa_1t_init_table; + ret = rtl8xxxu_init_phy_rf(priv, rftable, RF_A); + break; + case 0x8191c: + rftable = rtl8192cu_radioa_1t_init_table; + ret = rtl8xxxu_init_phy_rf(priv, rftable, RF_A); + break; + case 0x8192c: + rftable = rtl8192cu_radioa_2t_init_table; + ret = rtl8xxxu_init_phy_rf(priv, rftable, RF_A); + if (ret) + break; + rftable = rtl8192cu_radiob_2t_init_table; + ret = rtl8xxxu_init_phy_rf(priv, rftable, RF_B); + break; + default: + ret = -EINVAL; + } + + if (ret) + goto exit; + + /* Reduce 80M spur */ + rtl8xxxu_write32(priv, REG_AFE_XTAL_CTRL, 0x0381808d); + rtl8xxxu_write32(priv, REG_AFE_PLL_CTRL, 0xf0ffff83); + rtl8xxxu_write32(priv, REG_AFE_PLL_CTRL, 0xf0ffff82); + rtl8xxxu_write32(priv, REG_AFE_PLL_CTRL, 0xf0ffff83); + + /* RFSW Control - clear bit 14 ?? */ + rtl8xxxu_write32(priv, REG_FPGA0_TX_INFO, 0x00000003); + /* 0x07000760 */ + val32 = FPGA0_RF_TRSW | FPGA0_RF_TRSWB | FPGA0_RF_ANTSW | + FPGA0_RF_ANTSWB | FPGA0_RF_PAPE | + ((FPGA0_RF_ANTSW | FPGA0_RF_ANTSWB | FPGA0_RF_PAPE) << + FPGA0_RF_BD_CTRL_SHIFT); + rtl8xxxu_write32(priv, REG_FPGA0_XAB_RF_SW_CTRL, val32); + /* 0x860[6:5]= 00 - why? - this sets antenna B */ + rtl8xxxu_write32(priv, REG_FPGA0_XA_RF_INT_OE, 0x66F60210); + + priv->rf_mode_ag[0] = rtl8xxxu_read_rfreg(priv, RF_A, + RF6052_REG_MODE_AG); + + dev_dbg(dev, "%s: macpower %i\n", __func__, macpower); + if (!macpower) { + if (priv->ep_tx_normal_queue) + val8 = TX_PAGE_NUM_NORM_PQ; + else + val8 = 0; + + rtl8xxxu_write8(priv, REG_RQPN_NPQ, val8); + + val32 = (TX_PAGE_NUM_PUBQ << RQPN_NORM_PQ_SHIFT) | RQPN_LOAD; + + if (priv->ep_tx_high_queue) + val32 |= (TX_PAGE_NUM_HI_PQ << RQPN_HI_PQ_SHIFT); + if (priv->ep_tx_low_queue) + val32 |= (TX_PAGE_NUM_LO_PQ << RQPN_LO_PQ_SHIFT); + + rtl8xxxu_write32(priv, REG_RQPN, val32); + + /* + * Set TX buffer boundary + */ + val8 = TX_TOTAL_PAGE_NUM + 1; + rtl8xxxu_write8(priv, REG_TXPKTBUF_BCNQ_BDNY, val8); + rtl8xxxu_write8(priv, REG_TXPKTBUF_MGQ_BDNY, val8); + rtl8xxxu_write8(priv, REG_TXPKTBUF_WMAC_LBK_BF_HD, val8); + rtl8xxxu_write8(priv, REG_TRXFF_BNDY, val8); + rtl8xxxu_write8(priv, REG_TDECTRL + 1, val8); + } + + ret = rtl8xxxu_init_queue_priority(priv); + dev_dbg(dev, "%s: init_queue_priority %i\n", __func__, ret); + if (ret) + goto exit; + + /* + * Set RX page boundary + */ + rtl8xxxu_write16(priv, REG_TRXFF_BNDY + 2, 0x27ff); + /* + * Transfer page size is always 128 + */ + val8 = (PBP_PAGE_SIZE_128 << PBP_PAGE_SIZE_RX_SHIFT) | + (PBP_PAGE_SIZE_128 << PBP_PAGE_SIZE_TX_SHIFT); + rtl8xxxu_write8(priv, REG_PBP, val8); + + /* + * Unit in 8 bytes, not obvious what it is used for + */ + rtl8xxxu_write8(priv, REG_RX_DRVINFO_SZ, 4); + + /* + * Enable all interrupts - not obvious USB needs to do this + */ + rtl8xxxu_write32(priv, REG_HISR, 0xffffffff); + rtl8xxxu_write32(priv, REG_HIMR, 0xffffffff); + + rtl8xxxu_set_mac(priv); + rtl8xxxu_set_linktype(priv, NL80211_IFTYPE_STATION); + + /* + * Configure initial WMAC settings + */ + val32 = RCR_ACCEPT_PHYS_MATCH | RCR_ACCEPT_MCAST | RCR_ACCEPT_BCAST | + /* RCR_CHECK_BSSID_MATCH | RCR_CHECK_BSSID_BEACON | */ + RCR_ACCEPT_MGMT_FRAME | RCR_HTC_LOC_CTRL | + RCR_APPEND_PHYSTAT | RCR_APPEND_ICV | RCR_APPEND_MIC; + rtl8xxxu_write32(priv, REG_RCR, val32); + + /* + * Accept all multicast + */ + rtl8xxxu_write32(priv, REG_MAR, 0xffffffff); + rtl8xxxu_write32(priv, REG_MAR + 4, 0xffffffff); + + /* + * Init adaptive controls + */ + val32 = rtl8xxxu_read32(priv, REG_RESPONSE_RATE_SET); + val32 &= ~RESPONSE_RATE_BITMAP_ALL; + val32 |= RESPONSE_RATE_RRSR_CCK_ONLY_1M; + rtl8xxxu_write32(priv, REG_RESPONSE_RATE_SET, val32); + + /* CCK = 0x0a, OFDM = 0x10 */ + rtl8xxxu_set_spec_sifs(priv, 0x10, 0x10); + rtl8xxxu_set_retry(priv, 0x30, 0x30); + rtl8xxxu_set_spec_sifs(priv, 0x0a, 0x10); + + /* + * Init EDCA + */ + rtl8xxxu_write16(priv, REG_MAC_SPEC_SIFS, 0x100a); + + /* Set CCK SIFS */ + rtl8xxxu_write16(priv, REG_SIFS_CCK, 0x100a); + + /* Set OFDM SIFS */ + rtl8xxxu_write16(priv, REG_SIFS_OFDM, 0x100a); + + /* TXOP */ + rtl8xxxu_write32(priv, REG_EDCA_BE_PARAM, 0x005ea42b); + rtl8xxxu_write32(priv, REG_EDCA_BK_PARAM, 0x0000a44f); + rtl8xxxu_write32(priv, REG_EDCA_VI_PARAM, 0x005ea324); + rtl8xxxu_write32(priv, REG_EDCA_VO_PARAM, 0x002fa226); + + /* Set data auto rate fallback retry count */ + rtl8xxxu_write32(priv, REG_DARFRC, 0x00000000); + rtl8xxxu_write32(priv, REG_DARFRC + 4, 0x10080404); + rtl8xxxu_write32(priv, REG_RARFRC, 0x04030201); + rtl8xxxu_write32(priv, REG_RARFRC + 4, 0x08070605); + + val8 = rtl8xxxu_read8(priv, REG_FWHW_TXQ_CTRL); + val8 |= FWHW_TXQ_CTRL_AMPDU_RETRY; + rtl8xxxu_write8(priv, REG_FWHW_TXQ_CTRL, val8); + + /* Set ACK timeout */ + rtl8xxxu_write8(priv, REG_ACKTO, 0x40); + + /* + * Initialize beacon parameters + */ + val16 = BEACON_DISABLE_TSF_UPDATE | (BEACON_DISABLE_TSF_UPDATE << 8); + rtl8xxxu_write16(priv, REG_BEACON_CTRL, val16); + rtl8xxxu_write16(priv, REG_TBTT_PROHIBIT, 0x6404); + rtl8xxxu_write8(priv, REG_DRIVER_EARLY_INT, DRIVER_EARLY_INT_TIME); + rtl8xxxu_write8(priv, REG_BEACON_DMA_TIME, BEACON_DMA_ATIME_INT_TIME); + rtl8xxxu_write16(priv, REG_BEACON_TCFG, 0x660F); + + /* + * Enable CCK and OFDM block + */ + val32 = rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE); + val32 |= (FPGA_RF_MODE_CCK | FPGA_RF_MODE_OFDM); + rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32); + + /* + * Invalidate all CAM entries - bit 30 is undocumented + */ + rtl8xxxu_write32(priv, REG_CAM_CMD, CAM_CMD_POLLING | BIT(30)); + + /* + * Start out with default power levels for channel 6, 20MHz + */ + rtl8723a_set_tx_power(priv, 1, false); + + /* Let the 8051 take control of antenna setting */ + val8 = rtl8xxxu_read8(priv, REG_LEDCFG2); + val8 |= LEDCFG2_DPDT_SELECT; + rtl8xxxu_write8(priv, REG_LEDCFG2, val8); + + rtl8xxxu_write8(priv, REG_HWSEQ_CTRL, 0xff); + + /* Disable BAR - not sure if this has any effect on USB */ + rtl8xxxu_write32(priv, REG_BAR_MODE_CTRL, 0x0201ffff); + + rtl8xxxu_write16(priv, REG_FAST_EDCA_CTRL, 0); + + /* + * Not sure if we should get into this at all + */ + if (priv->iqk_initialized) { + rtl8xxxu_restore_regs(priv, rtl8723au_iqk_phy_iq_bb_reg, + priv->bb_recovery_backup, + RTL8XXXU_BB_REGS); + } else { + rtl8723a_phy_iq_calibrate(priv); + priv->iqk_initialized = true; + } + + /* + * This should enable thermal meter + */ + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_T_METER, 0x60); + + rtl8723a_phy_lc_calibrate(priv); + + /* fix USB interface interference issue */ + rtl8xxxu_write8(priv, 0xfe40, 0xe0); + rtl8xxxu_write8(priv, 0xfe41, 0x8d); + rtl8xxxu_write8(priv, 0xfe42, 0x80); + rtl8xxxu_write32(priv, REG_TXDMA_OFFSET_CHK, 0xfd0320); + + /* Solve too many protocol error on USB bus */ + /* Can't do this for 8188/8192 UMC A cut parts */ + rtl8xxxu_write8(priv, 0xfe40, 0xe6); + rtl8xxxu_write8(priv, 0xfe41, 0x94); + rtl8xxxu_write8(priv, 0xfe42, 0x80); + + rtl8xxxu_write8(priv, 0xfe40, 0xe0); + rtl8xxxu_write8(priv, 0xfe41, 0x19); + rtl8xxxu_write8(priv, 0xfe42, 0x80); + + rtl8xxxu_write8(priv, 0xfe40, 0xe5); + rtl8xxxu_write8(priv, 0xfe41, 0x91); + rtl8xxxu_write8(priv, 0xfe42, 0x80); + + rtl8xxxu_write8(priv, 0xfe40, 0xe2); + rtl8xxxu_write8(priv, 0xfe41, 0x81); + rtl8xxxu_write8(priv, 0xfe42, 0x80); + + /* Init BT hw config. */ + rtl8xxxu_init_bt(priv); + + /* + * Not sure if we really need to save these parameters, but the + * vendor driver does + */ + val32 = rtl8xxxu_read32(priv, REG_FPGA0_XA_HSSI_PARM2); + if (val32 & FPGA0_HSSI_PARM2_CCK_HIGH_PWR) + priv->path_a_hi_power = 1; + + val32 = rtl8xxxu_read32(priv, REG_OFDM0_TRX_PATH_ENABLE); + priv->path_a_rf_paths = val32 & OFDM_RF_PATH_RX_MASK; + + val32 = rtl8xxxu_read32(priv, REG_OFDM0_XA_AGC_CORE1); + priv->path_a_ig_value = val32 & OFDM0_X_AGC_CORE1_IGI_MASK; + + /* Set NAV_UPPER to 30000us */ + val8 = ((30000 + NAV_UPPER_UNIT - 1) / NAV_UPPER_UNIT); + rtl8xxxu_write8(priv, REG_NAV_UPPER, val8); + + /* + * 2011/03/09 MH debug only, UMC-B cut pass 2500 S5 test, + * but we need to fin root cause. + */ + val32 = rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE); + if ((val32 & 0xff000000) != 0x83000000) { + val32 |= FPGA_RF_MODE_CCK; + rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32); + } + + val32 = rtl8xxxu_read32(priv, REG_FWHW_TXQ_CTRL); + val32 |= FWHW_TXQ_CTRL_XMIT_MGMT_ACK; + /* ack for xmit mgmt frames. */ + rtl8xxxu_write32(priv, REG_FWHW_TXQ_CTRL, val32); + +exit: + return ret; +} + +static void rtl8xxxu_disable_device(struct ieee80211_hw *hw) +{ + struct rtl8xxxu_priv *priv = hw->priv; + + rtl8xxxu_power_off(priv); +} + +static void rtl8xxxu_cam_write(struct rtl8xxxu_priv *priv, + struct ieee80211_key_conf *key, const u8 *mac) +{ + u32 cmd, val32, addr, ctrl; + int j, i, tmp_debug; + + tmp_debug = rtl8xxxu_debug; + if (rtl8xxxu_debug & RTL8XXXU_DEBUG_KEY) + rtl8xxxu_debug |= RTL8XXXU_DEBUG_REG_WRITE; + + /* + * This is a bit of a hack - the lower bits of the cipher + * suite selector happens to match the cipher index in the CAM + */ + addr = key->keyidx << CAM_CMD_KEY_SHIFT; + ctrl = (key->cipher & 0x0f) << 2 | key->keyidx | CAM_WRITE_VALID; + + for (j = 5; j >= 0; j--) { + switch (j) { + case 0: + val32 = ctrl | (mac[0] << 16) | (mac[1] << 24); + break; + case 1: + val32 = mac[2] | (mac[3] << 8) | + (mac[4] << 16) | (mac[5] << 24); + break; + default: + i = (j - 2) << 2; + val32 = key->key[i] | (key->key[i + 1] << 8) | + key->key[i + 2] << 16 | key->key[i + 3] << 24; + break; + } + + rtl8xxxu_write32(priv, REG_CAM_WRITE, val32); + cmd = CAM_CMD_POLLING | CAM_CMD_WRITE | (addr + j); + rtl8xxxu_write32(priv, REG_CAM_CMD, cmd); + udelay(100); + } + + rtl8xxxu_debug = tmp_debug; +} + +static void rtl8xxxu_sw_scan_start(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, const u8* mac) +{ + struct rtl8xxxu_priv *priv = hw->priv; + u8 val8; + + val8 = rtl8xxxu_read8(priv, REG_BEACON_CTRL); + val8 |= BEACON_DISABLE_TSF_UPDATE; + rtl8xxxu_write8(priv, REG_BEACON_CTRL, val8); +} + +static void rtl8xxxu_sw_scan_complete(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct rtl8xxxu_priv *priv = hw->priv; + u8 val8; + + val8 = rtl8xxxu_read8(priv, REG_BEACON_CTRL); + val8 &= ~BEACON_DISABLE_TSF_UPDATE; + rtl8xxxu_write8(priv, REG_BEACON_CTRL, val8); +} + +static void rtl8xxxu_update_rate_mask(struct rtl8xxxu_priv *priv, + u32 ramask, int sgi) +{ + struct h2c_cmd h2c; + + h2c.ramask.cmd = H2C_SET_RATE_MASK; + h2c.ramask.mask_lo = cpu_to_le16(ramask & 0xffff); + h2c.ramask.mask_hi = cpu_to_le16(ramask >> 16); + + h2c.ramask.arg = 0x80; + if (sgi) + h2c.ramask.arg |= 0x20; + + dev_dbg(&priv->udev->dev, "%s: rate mask %08x, arg %02x\n", __func__, + ramask, h2c.ramask.arg); + rtl8723a_h2c_cmd(priv, &h2c); +} + +static void rtl8xxxu_set_basic_rates(struct rtl8xxxu_priv *priv, u32 rate_cfg) +{ + u32 val32; + u8 rate_idx = 0; + + rate_cfg &= RESPONSE_RATE_BITMAP_ALL; + + val32 = rtl8xxxu_read32(priv, REG_RESPONSE_RATE_SET); + val32 &= ~RESPONSE_RATE_BITMAP_ALL; + val32 |= rate_cfg; + rtl8xxxu_write32(priv, REG_RESPONSE_RATE_SET, val32); + + dev_dbg(&priv->udev->dev, "%s: rates %08x\n", __func__, rate_cfg); + + while (rate_cfg) { + rate_cfg = (rate_cfg >> 1); + rate_idx++; + } + rtl8xxxu_write8(priv, REG_INIRTS_RATE_SEL, rate_idx); +} + +static void +rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, u32 changed) +{ + struct rtl8xxxu_priv *priv = hw->priv; + struct device *dev = &priv->udev->dev; + struct ieee80211_sta *sta; + u32 val32; + u8 val8; + + if (changed & BSS_CHANGED_ASSOC) { + struct h2c_cmd h2c; + + dev_dbg(dev, "Changed ASSOC: %i!\n", bss_conf->assoc); + + memset(&h2c, 0, sizeof(struct h2c_cmd)); + rtl8xxxu_set_linktype(priv, vif->type); + + if (bss_conf->assoc) { + u32 ramask; + int sgi = 0; + + rcu_read_lock(); + sta = ieee80211_find_sta(vif, bss_conf->bssid); + if (!sta) { + dev_info(dev, "%s: ASSOC no sta found\n", + __func__); + rcu_read_unlock(); + goto error; + } + + if (sta->ht_cap.ht_supported) + dev_info(dev, "%s: HT supported\n", __func__); + if (sta->vht_cap.vht_supported) + dev_info(dev, "%s: VHT supported\n", __func__); + + /* TODO: Set bits 28-31 for rate adaptive id */ + ramask = (sta->supp_rates[0] & 0xfff) | + sta->ht_cap.mcs.rx_mask[0] << 12 | + sta->ht_cap.mcs.rx_mask[1] << 20; + if (sta->ht_cap.cap & + (IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_SGI_20)) + sgi = 1; + rcu_read_unlock(); + + rtl8xxxu_update_rate_mask(priv, ramask, sgi); + + val32 = rtl8xxxu_read32(priv, REG_RCR); + val32 |= RCR_CHECK_BSSID_MATCH | RCR_CHECK_BSSID_BEACON; + rtl8xxxu_write32(priv, REG_RCR, val32); + + /* Enable RX of data frames */ + rtl8xxxu_write16(priv, REG_RXFLTMAP2, 0xffff); + + rtl8xxxu_write8(priv, REG_BCN_MAX_ERR, 0xff); + + rtl8723a_stop_tx_beacon(priv); + + /* joinbss sequence */ + rtl8xxxu_write16(priv, REG_BCN_PSR_RPT, + 0xc000 | bss_conf->aid); + + h2c.joinbss.data = H2C_JOIN_BSS_CONNECT; + } else { + val32 = rtl8xxxu_read32(priv, REG_RCR); + val32 &= ~(RCR_CHECK_BSSID_MATCH | + RCR_CHECK_BSSID_BEACON); + rtl8xxxu_write32(priv, REG_RCR, val32); + + val8 = rtl8xxxu_read8(priv, REG_BEACON_CTRL); + val8 |= BEACON_DISABLE_TSF_UPDATE; + rtl8xxxu_write8(priv, REG_BEACON_CTRL, val8); + + /* Disable RX of data frames */ + rtl8xxxu_write16(priv, REG_RXFLTMAP2, 0x0000); + h2c.joinbss.data = H2C_JOIN_BSS_DISCONNECT; + } + h2c.joinbss.cmd = H2C_JOIN_BSS_REPORT; + rtl8723a_h2c_cmd(priv, &h2c); + } + + if (changed & BSS_CHANGED_ERP_PREAMBLE) { + dev_dbg(dev, "Changed ERP_PREAMBLE: Use short preamble %i\n", + bss_conf->use_short_preamble); + val32 = rtl8xxxu_read32(priv, REG_RESPONSE_RATE_SET); + if (bss_conf->use_short_preamble) + val32 |= RSR_ACK_SHORT_PREAMBLE; + else + val32 &= ~RSR_ACK_SHORT_PREAMBLE; + rtl8xxxu_write32(priv, REG_RESPONSE_RATE_SET, val32); + } + + if (changed & BSS_CHANGED_ERP_SLOT) { + dev_dbg(dev, "Changed ERP_SLOT: short_slot_time %i\n", + bss_conf->use_short_slot); + + if (bss_conf->use_short_slot) + val8 = 9; + else + val8 = 20; + rtl8xxxu_write8(priv, REG_SLOT, val8); + } + + if (changed & BSS_CHANGED_BSSID) { + dev_dbg(dev, "Changed BSSID!\n"); + rtl8xxxu_set_bssid(priv, bss_conf->bssid); + } + + if (changed & BSS_CHANGED_BASIC_RATES) { + dev_dbg(dev, "Changed BASIC_RATES!\n"); + rtl8xxxu_set_basic_rates(priv, bss_conf->basic_rates); + } +error: + return; +} + +static u32 rtl8xxxu_80211_to_rtl_queue(u32 queue) +{ + u32 rtlqueue; + + switch (queue) { + case IEEE80211_AC_VO: + rtlqueue = TXDESC_QUEUE_VO; + break; + case IEEE80211_AC_VI: + rtlqueue = TXDESC_QUEUE_VI; + break; + case IEEE80211_AC_BE: + rtlqueue = TXDESC_QUEUE_BE; + break; + case IEEE80211_AC_BK: + rtlqueue = TXDESC_QUEUE_BK; + break; + default: + rtlqueue = TXDESC_QUEUE_BE; + } + + return rtlqueue; +} + +static u32 rtl8xxxu_queue_select(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + u32 queue; + + if (ieee80211_is_mgmt(hdr->frame_control)) + queue = TXDESC_QUEUE_MGNT; + else + queue = rtl8xxxu_80211_to_rtl_queue(skb_get_queue_mapping(skb)); + + return queue; +} + +static void rtl8xxxu_calc_tx_desc_csum(struct rtl8xxxu_tx_desc *tx_desc) +{ + __le16 *ptr = (__le16 *)tx_desc; + u16 csum = 0; + int i; + + /* + * Clear csum field before calculation, as the csum field is + * in the middle of the struct. + */ + tx_desc->csum = cpu_to_le16(0); + + for (i = 0; i < (sizeof(struct rtl8xxxu_tx_desc) / sizeof(u16)); i++) + csum = csum ^ le16_to_cpu(ptr[i]); + + tx_desc->csum |= cpu_to_le16(csum); +} + +static void rtl8xxxu_free_tx_resources(struct rtl8xxxu_priv *priv) +{ + struct rtl8xxxu_tx_urb *tx_urb, *tmp; + unsigned long flags; + + spin_lock_irqsave(&priv->tx_urb_lock, flags); + list_for_each_entry_safe(tx_urb, tmp, &priv->tx_urb_free_list, list) { + list_del(&tx_urb->list); + priv->tx_urb_free_count--; + usb_free_urb(&tx_urb->urb); + } + spin_unlock_irqrestore(&priv->tx_urb_lock, flags); +} + +static struct rtl8xxxu_tx_urb * +rtl8xxxu_alloc_tx_urb(struct rtl8xxxu_priv *priv) +{ + struct rtl8xxxu_tx_urb *tx_urb; + unsigned long flags; + + spin_lock_irqsave(&priv->tx_urb_lock, flags); + tx_urb = list_first_entry_or_null(&priv->tx_urb_free_list, + struct rtl8xxxu_tx_urb, list); + if (tx_urb) { + list_del(&tx_urb->list); + priv->tx_urb_free_count--; + if (priv->tx_urb_free_count < RTL8XXXU_TX_URB_LOW_WATER && + !priv->tx_stopped) { + priv->tx_stopped = true; + ieee80211_stop_queues(priv->hw); + } + } + + spin_unlock_irqrestore(&priv->tx_urb_lock, flags); + + return tx_urb; +} + +static void rtl8xxxu_free_tx_urb(struct rtl8xxxu_priv *priv, + struct rtl8xxxu_tx_urb *tx_urb) +{ + unsigned long flags; + + INIT_LIST_HEAD(&tx_urb->list); + + spin_lock_irqsave(&priv->tx_urb_lock, flags); + + list_add(&tx_urb->list, &priv->tx_urb_free_list); + priv->tx_urb_free_count++; + if (priv->tx_urb_free_count > RTL8XXXU_TX_URB_HIGH_WATER && + priv->tx_stopped) { + priv->tx_stopped = false; + ieee80211_wake_queues(priv->hw); + } + + spin_unlock_irqrestore(&priv->tx_urb_lock, flags); +} + +static void rtl8xxxu_tx_complete(struct urb *urb) +{ + struct sk_buff *skb = (struct sk_buff *)urb->context; + struct ieee80211_tx_info *tx_info; + struct ieee80211_hw *hw; + struct rtl8xxxu_tx_urb *tx_urb = + container_of(urb, struct rtl8xxxu_tx_urb, urb); + + tx_info = IEEE80211_SKB_CB(skb); + hw = tx_info->rate_driver_data[0]; + + skb_pull(skb, sizeof(struct rtl8xxxu_tx_desc)); + + ieee80211_tx_info_clear_status(tx_info); + tx_info->status.rates[0].idx = -1; + tx_info->status.rates[0].count = 0; + + if (!urb->status) + tx_info->flags |= IEEE80211_TX_STAT_ACK; + + ieee80211_tx_status_irqsafe(hw, skb); + + rtl8xxxu_free_tx_urb(hw->priv, tx_urb); +} + +static void rtl8xxxu_dump_action(struct device *dev, + struct ieee80211_hdr *hdr) +{ + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)hdr; + u16 cap, timeout; + + if (!(rtl8xxxu_debug & RTL8XXXU_DEBUG_ACTION)) + return; + + switch (mgmt->u.action.u.addba_resp.action_code) { + case WLAN_ACTION_ADDBA_RESP: + cap = le16_to_cpu(mgmt->u.action.u.addba_resp.capab); + timeout = le16_to_cpu(mgmt->u.action.u.addba_resp.timeout); + dev_info(dev, "WLAN_ACTION_ADDBA_RESP: " + "timeout %i, tid %02x, buf_size %02x, policy %02x, " + "status %02x\n", + timeout, + (cap & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2, + (cap & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6, + (cap >> 1) & 0x1, + le16_to_cpu(mgmt->u.action.u.addba_resp.status)); + break; + case WLAN_ACTION_ADDBA_REQ: + cap = le16_to_cpu(mgmt->u.action.u.addba_req.capab); + timeout = le16_to_cpu(mgmt->u.action.u.addba_req.timeout); + dev_info(dev, "WLAN_ACTION_ADDBA_REQ: " + "timeout %i, tid %02x, buf_size %02x, policy %02x\n", + timeout, + (cap & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2, + (cap & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6, + (cap >> 1) & 0x1); + break; + default: + dev_info(dev, "action frame %02x\n", + mgmt->u.action.u.addba_resp.action_code); + break; + } +} + +static void rtl8xxxu_tx(struct ieee80211_hw *hw, + struct ieee80211_tx_control *control, + struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ieee80211_rate *tx_rate = ieee80211_get_tx_rate(hw, tx_info); + struct rtl8xxxu_priv *priv = hw->priv; + struct rtl8xxxu_tx_desc *tx_desc; + struct rtl8xxxu_tx_urb *tx_urb; + struct ieee80211_sta *sta = NULL; + struct ieee80211_vif *vif = tx_info->control.vif; + struct device *dev = &priv->udev->dev; + u32 queue, rate; + u16 pktlen = skb->len; + u16 seq_number; + u16 rate_flag = tx_info->control.rates[0].flags; + int ret; + + if (skb_headroom(skb) < sizeof(struct rtl8xxxu_tx_desc)) { + dev_warn(dev, + "%s: Not enough headroom (%i) for tx descriptor\n", + __func__, skb_headroom(skb)); + goto error; + } + + if (unlikely(skb->len > (65535 - sizeof(struct rtl8xxxu_tx_desc)))) { + dev_warn(dev, "%s: Trying to send over-sized skb (%i)\n", + __func__, skb->len); + goto error; + } + + tx_urb = rtl8xxxu_alloc_tx_urb(priv); + if (!tx_urb) { + dev_warn(dev, "%s: Unable to allocate tx urb\n", __func__); + goto error; + } + + if (rtl8xxxu_debug & RTL8XXXU_DEBUG_TX) + dev_info(dev, "%s: TX rate: %d (%d), pkt size %d\n", + __func__, tx_rate->bitrate, tx_rate->hw_value, pktlen); + + if (ieee80211_is_action(hdr->frame_control)) + rtl8xxxu_dump_action(dev, hdr); + + tx_info->rate_driver_data[0] = hw; + + if (control && control->sta) + sta = control->sta; + + tx_desc = (struct rtl8xxxu_tx_desc *) + skb_push(skb, sizeof(struct rtl8xxxu_tx_desc)); + + memset(tx_desc, 0, sizeof(struct rtl8xxxu_tx_desc)); + tx_desc->pkt_size = cpu_to_le16(pktlen); + tx_desc->pkt_offset = sizeof(struct rtl8xxxu_tx_desc); + + tx_desc->txdw0 = + TXDESC_OWN | TXDESC_FIRST_SEGMENT | TXDESC_LAST_SEGMENT; + if (is_multicast_ether_addr(ieee80211_get_DA(hdr)) || + is_broadcast_ether_addr(ieee80211_get_DA(hdr))) + tx_desc->txdw0 |= TXDESC_BROADMULTICAST; + + queue = rtl8xxxu_queue_select(hw, skb); + tx_desc->txdw1 = cpu_to_le32(queue << TXDESC_QUEUE_SHIFT); + + if (tx_info->control.hw_key) { + switch (tx_info->control.hw_key->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + case WLAN_CIPHER_SUITE_TKIP: + tx_desc->txdw1 |= cpu_to_le32(TXDESC_SEC_RC4); + break; + case WLAN_CIPHER_SUITE_CCMP: + tx_desc->txdw1 |= cpu_to_le32(TXDESC_SEC_AES); + break; + default: + break; + } + } + + seq_number = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); + tx_desc->txdw3 = cpu_to_le32((u32)seq_number << TXDESC_SEQ_SHIFT); + + if (rate_flag & IEEE80211_TX_RC_MCS) + rate = tx_info->control.rates[0].idx + DESC_RATE_MCS0; + else + rate = tx_rate->hw_value; + tx_desc->txdw5 = cpu_to_le32(rate); + + if (ieee80211_is_data(hdr->frame_control)) + tx_desc->txdw5 |= cpu_to_le32(0x0001ff00); + + /* (tx_info->flags & IEEE80211_TX_CTL_AMPDU) && */ + if (ieee80211_is_data_qos(hdr->frame_control) && sta) { + if (sta->ht_cap.ht_supported) { + u32 ampdu, val32; + + ampdu = (u32)sta->ht_cap.ampdu_density; + val32 = ampdu << TXDESC_AMPDU_DENSITY_SHIFT; + tx_desc->txdw2 |= cpu_to_le32(val32); + tx_desc->txdw1 |= cpu_to_le32(TXDESC_AGG_ENABLE); + } else + tx_desc->txdw1 |= cpu_to_le32(TXDESC_BK); + } else + tx_desc->txdw1 |= cpu_to_le32(TXDESC_BK); + + if (ieee80211_is_data_qos(hdr->frame_control)) + tx_desc->txdw4 |= cpu_to_le32(TXDESC_QOS); + if (rate_flag & IEEE80211_TX_RC_USE_SHORT_PREAMBLE || + (sta && vif && vif->bss_conf.use_short_preamble)) + tx_desc->txdw4 |= cpu_to_le32(TXDESC_SHORT_PREAMBLE); + if (rate_flag & IEEE80211_TX_RC_SHORT_GI || + (ieee80211_is_data_qos(hdr->frame_control) && + sta && sta->ht_cap.cap & + (IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_SGI_20))) { + tx_desc->txdw5 |= cpu_to_le32(TXDESC_SHORT_GI); + } + if (ieee80211_is_mgmt(hdr->frame_control)) { + tx_desc->txdw5 = cpu_to_le32(tx_rate->hw_value); + tx_desc->txdw4 |= cpu_to_le32(TXDESC_USE_DRIVER_RATE); + tx_desc->txdw5 |= cpu_to_le32(6 << TXDESC_RETRY_LIMIT_SHIFT); + tx_desc->txdw5 |= cpu_to_le32(TXDESC_RETRY_LIMIT_ENABLE); + } + + if (rate_flag & IEEE80211_TX_RC_USE_RTS_CTS) { + /* Use RTS rate 24M - does the mac80211 tell us which to use? */ + tx_desc->txdw4 |= cpu_to_le32(DESC_RATE_24M); + tx_desc->txdw4 |= cpu_to_le32(TXDESC_RTS_CTS_ENABLE); + tx_desc->txdw4 |= cpu_to_le32(TXDESC_HW_RTS_ENABLE); + } + + rtl8xxxu_calc_tx_desc_csum(tx_desc); + + usb_fill_bulk_urb(&tx_urb->urb, priv->udev, priv->pipe_out[queue], + skb->data, skb->len, rtl8xxxu_tx_complete, skb); + + usb_anchor_urb(&tx_urb->urb, &priv->tx_anchor); + ret = usb_submit_urb(&tx_urb->urb, GFP_ATOMIC); + if (ret) { + usb_unanchor_urb(&tx_urb->urb); + rtl8xxxu_free_tx_urb(priv, tx_urb); + goto error; + } + return; +error: + dev_kfree_skb(skb); +} + +static void rtl8xxxu_rx_parse_phystats(struct rtl8xxxu_priv *priv, + struct ieee80211_rx_status *rx_status, + struct rtl8xxxu_rx_desc *rx_desc, + struct rtl8723au_phy_stats *phy_stats) +{ + if (phy_stats->sgi_en) + rx_status->flag |= RX_FLAG_SHORT_GI; + + if (rx_desc->rxmcs < DESC_RATE_6M) { + /* + * Handle PHY stats for CCK rates + */ + u8 cck_agc_rpt = phy_stats->cck_agc_rpt_ofdm_cfosho_a; + + switch (cck_agc_rpt & 0xc0) { + case 0xc0: + rx_status->signal = -46 - (cck_agc_rpt & 0x3e); + break; + case 0x80: + rx_status->signal = -26 - (cck_agc_rpt & 0x3e); + break; + case 0x40: + rx_status->signal = -12 - (cck_agc_rpt & 0x3e); + break; + case 0x00: + rx_status->signal = 16 - (cck_agc_rpt & 0x3e); + break; + } + } else { + rx_status->signal = + (phy_stats->cck_sig_qual_ofdm_pwdb_all >> 1) - 110; + } +} + +static void rtl8xxxu_free_rx_resources(struct rtl8xxxu_priv *priv) +{ + struct rtl8xxxu_rx_urb *rx_urb, *tmp; + unsigned long flags; + + spin_lock_irqsave(&priv->rx_urb_lock, flags); + + list_for_each_entry_safe(rx_urb, tmp, + &priv->rx_urb_pending_list, list) { + list_del(&rx_urb->list); + priv->rx_urb_pending_count--; + usb_free_urb(&rx_urb->urb); + } + + spin_unlock_irqrestore(&priv->rx_urb_lock, flags); +} + +static void rtl8xxxu_queue_rx_urb(struct rtl8xxxu_priv *priv, + struct rtl8xxxu_rx_urb *rx_urb) +{ + struct sk_buff *skb; + unsigned long flags; + int pending = 0; + + spin_lock_irqsave(&priv->rx_urb_lock, flags); + + if (!priv->shutdown) { + list_add_tail(&rx_urb->list, &priv->rx_urb_pending_list); + priv->rx_urb_pending_count++; + pending = priv->rx_urb_pending_count; + } else { + skb = (struct sk_buff *)rx_urb->urb.context; + dev_kfree_skb(skb); + usb_free_urb(&rx_urb->urb); + } + + spin_unlock_irqrestore(&priv->rx_urb_lock, flags); + + if (pending > RTL8XXXU_RX_URB_PENDING_WATER) + schedule_work(&priv->rx_urb_wq); +} + +static void rtl8xxxu_rx_urb_work(struct work_struct *work) +{ + struct rtl8xxxu_priv *priv; + struct rtl8xxxu_rx_urb *rx_urb, *tmp; + struct list_head local; + struct sk_buff *skb; + unsigned long flags; + int ret; + + priv = container_of(work, struct rtl8xxxu_priv, rx_urb_wq); + INIT_LIST_HEAD(&local); + + spin_lock_irqsave(&priv->rx_urb_lock, flags); + + list_splice_init(&priv->rx_urb_pending_list, &local); + priv->rx_urb_pending_count = 0; + + spin_unlock_irqrestore(&priv->rx_urb_lock, flags); + + list_for_each_entry_safe(rx_urb, tmp, &local, list) { + list_del_init(&rx_urb->list); + ret = rtl8xxxu_submit_rx_urb(priv, rx_urb); + /* + * If out of memory or temporary error, put it back on the + * queue and try again. Otherwise the device is dead/gone + * and we should drop it. + */ + switch (ret) { + case 0: + break; + case -ENOMEM: + case -EAGAIN: + rtl8xxxu_queue_rx_urb(priv, rx_urb); + break; + default: + pr_info("failed to requeue urb %i\n", ret); + skb = (struct sk_buff *)rx_urb->urb.context; + dev_kfree_skb(skb); + usb_free_urb(&rx_urb->urb); + } + } +} + +static void rtl8xxxu_rx_complete(struct urb *urb) +{ + struct rtl8xxxu_rx_urb *rx_urb = + container_of(urb, struct rtl8xxxu_rx_urb, urb); + struct ieee80211_hw *hw = rx_urb->hw; + struct rtl8xxxu_priv *priv = hw->priv; + struct sk_buff *skb = (struct sk_buff *)urb->context; + struct rtl8xxxu_rx_desc *rx_desc = (struct rtl8xxxu_rx_desc *)skb->data; + struct rtl8723au_phy_stats *phy_stats; + struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); + struct ieee80211_mgmt *mgmt; + struct device *dev = &priv->udev->dev; + __le32 *_rx_desc_le = (__le32 *)skb->data; + u32 *_rx_desc = (u32 *)skb->data; + int cnt, len, drvinfo_sz, desc_shift, i; + + for (i = 0; i < (sizeof(struct rtl8xxxu_rx_desc) / sizeof(u32)); i++) + _rx_desc[i] = le32_to_cpu(_rx_desc_le[i]); + + cnt = rx_desc->frag; + len = rx_desc->pktlen; + drvinfo_sz = rx_desc->drvinfo_sz * 8; + desc_shift = rx_desc->shift; + skb_put(skb, urb->actual_length); + + if (urb->status == 0) { + skb_pull(skb, sizeof(struct rtl8xxxu_rx_desc)); + phy_stats = (struct rtl8723au_phy_stats *)skb->data; + + skb_pull(skb, drvinfo_sz + desc_shift); + + mgmt = (struct ieee80211_mgmt *)skb->data; + + memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); + + if (rx_desc->phy_stats) + rtl8xxxu_rx_parse_phystats(priv, rx_status, + rx_desc, phy_stats); + + rx_status->freq = hw->conf.chandef.chan->center_freq; + rx_status->band = hw->conf.chandef.chan->band; + + rx_status->mactime = le32_to_cpu(rx_desc->tsfl); + rx_status->flag |= RX_FLAG_MACTIME_START; + + if (!rx_desc->swdec) + rx_status->flag |= RX_FLAG_DECRYPTED; + if (rx_desc->crc32) + rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; + if (rx_desc->bw) + rx_status->flag |= RX_FLAG_40MHZ; + + if (rx_desc->rxht) { + rx_status->flag |= RX_FLAG_HT; + rx_status->rate_idx = rx_desc->rxmcs - DESC_RATE_MCS0; + } else { + rx_status->rate_idx = rx_desc->rxmcs; + } + + ieee80211_rx_irqsafe(hw, skb); + skb = NULL; + rx_urb->urb.context = NULL; + rtl8xxxu_queue_rx_urb(priv, rx_urb); + } else { + dev_dbg(dev, "%s: status %i\n", __func__, urb->status); + goto cleanup; + } + return; + +cleanup: + usb_free_urb(urb); + dev_kfree_skb(skb); + return; +} + +static int rtl8xxxu_submit_rx_urb(struct rtl8xxxu_priv *priv, + struct rtl8xxxu_rx_urb *rx_urb) +{ + struct sk_buff *skb; + int skb_size; + int ret; + + skb_size = sizeof(struct rtl8xxxu_rx_desc) + RTL_RX_BUFFER_SIZE; + skb = __netdev_alloc_skb(NULL, skb_size, GFP_KERNEL); + if (!skb) + return -ENOMEM; + + memset(skb->data, 0, sizeof(struct rtl8xxxu_rx_desc)); + usb_fill_bulk_urb(&rx_urb->urb, priv->udev, priv->pipe_in, skb->data, + skb_size, rtl8xxxu_rx_complete, skb); + usb_anchor_urb(&rx_urb->urb, &priv->rx_anchor); + ret = usb_submit_urb(&rx_urb->urb, GFP_ATOMIC); + if (ret) + usb_unanchor_urb(&rx_urb->urb); + return ret; +} + +static void rtl8xxxu_int_complete(struct urb *urb) +{ + struct rtl8xxxu_priv *priv = (struct rtl8xxxu_priv *)urb->context; + struct device *dev = &priv->udev->dev; + int ret; + + dev_dbg(dev, "%s: status %i\n", __func__, urb->status); + if (urb->status == 0) { + usb_anchor_urb(urb, &priv->int_anchor); + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret) + usb_unanchor_urb(urb); + } else { + dev_info(dev, "%s: Error %i\n", __func__, urb->status); + } +} + + +static int rtl8xxxu_submit_int_urb(struct ieee80211_hw *hw) +{ + struct rtl8xxxu_priv *priv = hw->priv; + struct urb *urb; + u32 val32; + int ret; + + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) + return -ENOMEM; + + usb_fill_int_urb(urb, priv->udev, priv->pipe_interrupt, + priv->int_buf, USB_INTR_CONTENT_LENGTH, + rtl8xxxu_int_complete, priv, 1); + usb_anchor_urb(urb, &priv->int_anchor); + ret = usb_submit_urb(urb, GFP_KERNEL); + if (ret) { + usb_unanchor_urb(urb); + goto error; + } + + val32 = rtl8xxxu_read32(priv, REG_USB_HIMR); + val32 |= USB_HIMR_CPWM; + rtl8xxxu_write32(priv, REG_USB_HIMR, val32); + +error: + return ret; +} + +static int rtl8xxxu_add_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct rtl8xxxu_priv *priv = hw->priv; + int ret; + u8 val8; + + switch (vif->type) { + case NL80211_IFTYPE_STATION: + rtl8723a_stop_tx_beacon(priv); + + val8 = rtl8xxxu_read8(priv, REG_BEACON_CTRL); + val8 |= BEACON_ATIM | BEACON_FUNCTION_ENABLE | + BEACON_DISABLE_TSF_UPDATE; + rtl8xxxu_write8(priv, REG_BEACON_CTRL, val8); + ret = 0; + break; + default: + ret = -EOPNOTSUPP; + } + + rtl8xxxu_set_linktype(priv, vif->type); + + return ret; +} + +static void rtl8xxxu_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct rtl8xxxu_priv *priv = hw->priv; + + dev_dbg(&priv->udev->dev, "%s\n", __func__); +} + +static int rtl8xxxu_config(struct ieee80211_hw *hw, u32 changed) +{ + struct rtl8xxxu_priv *priv = hw->priv; + struct device *dev = &priv->udev->dev; + u16 val16; + int ret = 0, channel; + bool ht40; + + if (rtl8xxxu_debug & RTL8XXXU_DEBUG_CHANNEL) + dev_info(dev, + "%s: channel: %i (changed %08x chandef.width %02x)\n", + __func__, hw->conf.chandef.chan->hw_value, + changed, hw->conf.chandef.width); + + if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) { + val16 = ((hw->conf.long_frame_max_tx_count << + RETRY_LIMIT_LONG_SHIFT) & RETRY_LIMIT_LONG_MASK) | + ((hw->conf.short_frame_max_tx_count << + RETRY_LIMIT_SHORT_SHIFT) & RETRY_LIMIT_SHORT_MASK); + rtl8xxxu_write16(priv, REG_RETRY_LIMIT, val16); + } + + if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { + switch (hw->conf.chandef.width) { + case NL80211_CHAN_WIDTH_20_NOHT: + case NL80211_CHAN_WIDTH_20: + ht40 = false; + break; + case NL80211_CHAN_WIDTH_40: + ht40 = true; + break; + default: + ret = -ENOTSUPP; + goto exit; + } + + channel = hw->conf.chandef.chan->hw_value; + + rtl8723a_set_tx_power(priv, channel, ht40); + + rtl8723au_config_channel(hw); + } + +exit: + return ret; +} + +static int rtl8xxxu_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, + const struct ieee80211_tx_queue_params *param) +{ + struct rtl8xxxu_priv *priv = hw->priv; + struct device *dev = &priv->udev->dev; + u32 val32; + u8 aifs, acm_ctrl, acm_bit; + + aifs = param->aifs; + + val32 = aifs | + fls(param->cw_min) << EDCA_PARAM_ECW_MIN_SHIFT | + fls(param->cw_max) << EDCA_PARAM_ECW_MAX_SHIFT | + (u32)param->txop << EDCA_PARAM_TXOP_SHIFT; + + acm_ctrl = rtl8xxxu_read8(priv, REG_ACM_HW_CTRL); + dev_dbg(dev, + "%s: IEEE80211 queue %02x val %08x, acm %i, acm_ctrl %02x\n", + __func__, queue, val32, param->acm, acm_ctrl); + + switch (queue) { + case IEEE80211_AC_VO: + acm_bit = ACM_HW_CTRL_VO; + rtl8xxxu_write32(priv, REG_EDCA_VO_PARAM, val32); + break; + case IEEE80211_AC_VI: + acm_bit = ACM_HW_CTRL_VI; + rtl8xxxu_write32(priv, REG_EDCA_VI_PARAM, val32); + break; + case IEEE80211_AC_BE: + acm_bit = ACM_HW_CTRL_BE; + rtl8xxxu_write32(priv, REG_EDCA_BE_PARAM, val32); + break; + case IEEE80211_AC_BK: + acm_bit = ACM_HW_CTRL_BK; + rtl8xxxu_write32(priv, REG_EDCA_BK_PARAM, val32); + break; + default: + acm_bit = 0; + break; + } + + if (param->acm) + acm_ctrl |= acm_bit; + else + acm_ctrl &= ~acm_bit; + rtl8xxxu_write8(priv, REG_ACM_HW_CTRL, acm_ctrl); + + return 0; +} + +static void rtl8xxxu_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, u64 multicast) +{ + struct rtl8xxxu_priv *priv = hw->priv; + + dev_dbg(&priv->udev->dev, "%s: changed_flags %08x, total_flags %08x\n", + __func__, changed_flags, *total_flags); + + *total_flags &= (FIF_ALLMULTI | FIF_CONTROL | FIF_BCN_PRBRESP_PROMISC); +} + +static int rtl8xxxu_set_rts_threshold(struct ieee80211_hw *hw, u32 rts) +{ + if (rts > 2347) + return -EINVAL; + + return 0; +} + +static int rtl8xxxu_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key) +{ + struct rtl8xxxu_priv *priv = hw->priv; + struct device *dev = &priv->udev->dev; + u8 mac_addr[ETH_ALEN]; + u8 val8; + u16 val16; + u32 val32; + int retval = -EOPNOTSUPP; + + dev_dbg(dev, "%s: cmd %02x, cipher %08x, index %i\n", + __func__, cmd, key->cipher, key->keyidx); + + if (vif->type != NL80211_IFTYPE_STATION) + return -EOPNOTSUPP; + + if (key->keyidx > 3) + return -EOPNOTSUPP; + + switch (key->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + + break; + case WLAN_CIPHER_SUITE_CCMP: + key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX; + break; + case WLAN_CIPHER_SUITE_TKIP: + key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; + default: + return -EOPNOTSUPP; + } + + if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) { + dev_dbg(dev, "%s: pairwise key\n", __func__); + ether_addr_copy(mac_addr, sta->addr); + } else { + dev_dbg(dev, "%s: group key\n", __func__); + eth_broadcast_addr(mac_addr); + } + + val16 = rtl8xxxu_read16(priv, REG_CR); + val16 |= CR_SECURITY_ENABLE; + rtl8xxxu_write16(priv, REG_CR, val16); + + val8 = SEC_CFG_TX_SEC_ENABLE | SEC_CFG_TXBC_USE_DEFKEY | + SEC_CFG_RX_SEC_ENABLE | SEC_CFG_RXBC_USE_DEFKEY; + val8 |= SEC_CFG_TX_USE_DEFKEY | SEC_CFG_RX_USE_DEFKEY; + rtl8xxxu_write8(priv, REG_SECURITY_CFG, val8); + + switch (cmd) { + case SET_KEY: + key->hw_key_idx = key->keyidx; + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + rtl8xxxu_cam_write(priv, key, mac_addr); + retval = 0; + break; + case DISABLE_KEY: + rtl8xxxu_write32(priv, REG_CAM_WRITE, 0x00000000); + val32 = CAM_CMD_POLLING | CAM_CMD_WRITE | + key->keyidx << CAM_CMD_KEY_SHIFT; + rtl8xxxu_write32(priv, REG_CAM_CMD, val32); + retval = 0; + break; + default: + dev_warn(dev, "%s: Unsupported command %02x\n", __func__, cmd); + } + + return retval; +} + +static int +rtl8xxxu_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + enum ieee80211_ampdu_mlme_action action, + struct ieee80211_sta *sta, u16 tid, u16 *ssn, u8 buf_size, + bool amsdu) +{ + struct rtl8xxxu_priv *priv = hw->priv; + struct device *dev = &priv->udev->dev; + u8 ampdu_factor, ampdu_density; + + switch (action) { + case IEEE80211_AMPDU_TX_START: + dev_info(dev, "%s: IEEE80211_AMPDU_TX_START\n", __func__); + ampdu_factor = sta->ht_cap.ampdu_factor; + ampdu_density = sta->ht_cap.ampdu_density; + rtl8xxxu_set_ampdu_factor(priv, ampdu_factor); + rtl8xxxu_set_ampdu_min_space(priv, ampdu_density); + dev_dbg(dev, + "Changed HT: ampdu_factor %02x, ampdu_density %02x\n", + ampdu_factor, ampdu_density); + break; + case IEEE80211_AMPDU_TX_STOP_FLUSH: + dev_info(dev, "%s: IEEE80211_AMPDU_TX_STOP_FLUSH\n", __func__); + rtl8xxxu_set_ampdu_factor(priv, 0); + rtl8xxxu_set_ampdu_min_space(priv, 0); + break; + case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: + dev_info(dev, "%s: IEEE80211_AMPDU_TX_STOP_FLUSH_CONT\n", + __func__); + rtl8xxxu_set_ampdu_factor(priv, 0); + rtl8xxxu_set_ampdu_min_space(priv, 0); + break; + case IEEE80211_AMPDU_RX_START: + dev_info(dev, "%s: IEEE80211_AMPDU_RX_START\n", __func__); + break; + case IEEE80211_AMPDU_RX_STOP: + dev_info(dev, "%s: IEEE80211_AMPDU_RX_STOP\n", __func__); + break; + default: + break; + } + return 0; +} + +static int rtl8xxxu_start(struct ieee80211_hw *hw) +{ + struct rtl8xxxu_priv *priv = hw->priv; + struct rtl8xxxu_rx_urb *rx_urb; + struct rtl8xxxu_tx_urb *tx_urb; + unsigned long flags; + int ret, i; + + ret = 0; + + init_usb_anchor(&priv->rx_anchor); + init_usb_anchor(&priv->tx_anchor); + init_usb_anchor(&priv->int_anchor); + + rtl8723a_enable_rf(priv); + ret = rtl8xxxu_submit_int_urb(hw); + if (ret) + goto exit; + + for (i = 0; i < RTL8XXXU_TX_URBS; i++) { + tx_urb = kmalloc(sizeof(struct rtl8xxxu_tx_urb), GFP_KERNEL); + if (!tx_urb) { + if (!i) + ret = -ENOMEM; + + goto error_out; + } + usb_init_urb(&tx_urb->urb); + INIT_LIST_HEAD(&tx_urb->list); + tx_urb->hw = hw; + list_add(&tx_urb->list, &priv->tx_urb_free_list); + priv->tx_urb_free_count++; + } + + priv->tx_stopped = false; + + spin_lock_irqsave(&priv->rx_urb_lock, flags); + priv->shutdown = false; + spin_unlock_irqrestore(&priv->rx_urb_lock, flags); + + for (i = 0; i < RTL8XXXU_RX_URBS; i++) { + rx_urb = kmalloc(sizeof(struct rtl8xxxu_rx_urb), GFP_KERNEL); + if (!rx_urb) { + if (!i) + ret = -ENOMEM; + + goto error_out; + } + usb_init_urb(&rx_urb->urb); + INIT_LIST_HEAD(&rx_urb->list); + rx_urb->hw = hw; + + ret = rtl8xxxu_submit_rx_urb(priv, rx_urb); + } +exit: + /* + * Disable all data frames + */ + rtl8xxxu_write16(priv, REG_RXFLTMAP2, 0x0000); + /* + * Accept all mgmt frames + */ + rtl8xxxu_write16(priv, REG_RXFLTMAP0, 0xffff); + + rtl8xxxu_write32(priv, REG_OFDM0_XA_AGC_CORE1, 0x6954341e); + + return ret; + +error_out: + rtl8xxxu_free_tx_resources(priv); + /* + * Disable all data and mgmt frames + */ + rtl8xxxu_write16(priv, REG_RXFLTMAP2, 0x0000); + rtl8xxxu_write16(priv, REG_RXFLTMAP0, 0x0000); + + return ret; +} + +static void rtl8xxxu_stop(struct ieee80211_hw *hw) +{ + struct rtl8xxxu_priv *priv = hw->priv; + unsigned long flags; + + rtl8xxxu_write8(priv, REG_TXPAUSE, 0xff); + + rtl8xxxu_write16(priv, REG_RXFLTMAP0, 0x0000); + rtl8xxxu_write16(priv, REG_RXFLTMAP2, 0x0000); + + spin_lock_irqsave(&priv->rx_urb_lock, flags); + priv->shutdown = true; + spin_unlock_irqrestore(&priv->rx_urb_lock, flags); + + usb_kill_anchored_urbs(&priv->rx_anchor); + usb_kill_anchored_urbs(&priv->tx_anchor); + usb_kill_anchored_urbs(&priv->int_anchor); + + rtl8723a_disable_rf(priv); + + /* + * Disable interrupts + */ + rtl8xxxu_write32(priv, REG_USB_HIMR, 0); + + rtl8xxxu_free_rx_resources(priv); + rtl8xxxu_free_tx_resources(priv); +} + +static const struct ieee80211_ops rtl8xxxu_ops = { + .tx = rtl8xxxu_tx, + .add_interface = rtl8xxxu_add_interface, + .remove_interface = rtl8xxxu_remove_interface, + .config = rtl8xxxu_config, + .conf_tx = rtl8xxxu_conf_tx, + .bss_info_changed = rtl8xxxu_bss_info_changed, + .configure_filter = rtl8xxxu_configure_filter, + .set_rts_threshold = rtl8xxxu_set_rts_threshold, + .start = rtl8xxxu_start, + .stop = rtl8xxxu_stop, + .sw_scan_start = rtl8xxxu_sw_scan_start, + .sw_scan_complete = rtl8xxxu_sw_scan_complete, + .set_key = rtl8xxxu_set_key, + .ampdu_action = rtl8xxxu_ampdu_action, +}; + +static int rtl8xxxu_parse_usb(struct rtl8xxxu_priv *priv, + struct usb_interface *interface) +{ + struct usb_interface_descriptor *interface_desc; + struct usb_host_interface *host_interface; + struct usb_endpoint_descriptor *endpoint; + struct device *dev = &priv->udev->dev; + int i, j = 0, endpoints; + u8 dir, xtype, num; + int ret = 0; + + host_interface = &interface->altsetting[0]; + interface_desc = &host_interface->desc; + endpoints = interface_desc->bNumEndpoints; + + for (i = 0; i < endpoints; i++) { + endpoint = &host_interface->endpoint[i].desc; + + dir = endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK; + num = usb_endpoint_num(endpoint); + xtype = usb_endpoint_type(endpoint); + if (rtl8xxxu_debug & RTL8XXXU_DEBUG_USB) + dev_dbg(dev, + "%s: endpoint: dir %02x, # %02x, type %02x\n", + __func__, dir, num, xtype); + if (usb_endpoint_dir_in(endpoint) && + usb_endpoint_xfer_bulk(endpoint)) { + if (rtl8xxxu_debug & RTL8XXXU_DEBUG_USB) + dev_dbg(dev, "%s: in endpoint num %i\n", + __func__, num); + + if (priv->pipe_in) { + dev_warn(dev, + "%s: Too many IN pipes\n", __func__); + ret = -EINVAL; + goto exit; + } + + priv->pipe_in = usb_rcvbulkpipe(priv->udev, num); + } + + if (usb_endpoint_dir_in(endpoint) && + usb_endpoint_xfer_int(endpoint)) { + if (rtl8xxxu_debug & RTL8XXXU_DEBUG_USB) + dev_dbg(dev, "%s: interrupt endpoint num %i\n", + __func__, num); + + if (priv->pipe_interrupt) { + dev_warn(dev, "%s: Too many INTERRUPT pipes\n", + __func__); + ret = -EINVAL; + goto exit; + } + + priv->pipe_interrupt = usb_rcvintpipe(priv->udev, num); + } + + if (usb_endpoint_dir_out(endpoint) && + usb_endpoint_xfer_bulk(endpoint)) { + if (rtl8xxxu_debug & RTL8XXXU_DEBUG_USB) + dev_dbg(dev, "%s: out endpoint num %i\n", + __func__, num); + if (j >= RTL8XXXU_OUT_ENDPOINTS) { + dev_warn(dev, + "%s: Too many OUT pipes\n", __func__); + ret = -EINVAL; + goto exit; + } + priv->out_ep[j++] = num; + } + } +exit: + priv->nr_out_eps = j; + return ret; +} + +static int rtl8xxxu_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + struct rtl8xxxu_priv *priv; + struct ieee80211_hw *hw; + struct usb_device *udev; + struct ieee80211_supported_band *sband; + int ret = 0; + int untested = 1; + + udev = usb_get_dev(interface_to_usbdev(interface)); + + switch (id->idVendor) { + case USB_VENDOR_ID_REALTEK: + switch(id->idProduct) { + case 0x1724: + case 0x8176: + case 0x8178: + case 0x817f: + untested = 0; + break; + } + break; + case 0x7392: + if (id->idProduct == 0x7811) + untested = 0; + break; + default: + break; + } + + if (untested) { + rtl8xxxu_debug = RTL8XXXU_DEBUG_EFUSE; + dev_info(&udev->dev, + "This Realtek USB WiFi dongle (0x%04x:0x%04x) is untested!\n", + id->idVendor, id->idProduct); + dev_info(&udev->dev, + "Please report results to Jes.Sorensen@gmail.com\n"); + } + + hw = ieee80211_alloc_hw(sizeof(struct rtl8xxxu_priv), &rtl8xxxu_ops); + if (!hw) { + ret = -ENOMEM; + goto exit; + } + + priv = hw->priv; + priv->hw = hw; + priv->udev = udev; + priv->fops = (struct rtl8xxxu_fileops *)id->driver_info; + mutex_init(&priv->usb_buf_mutex); + mutex_init(&priv->h2c_mutex); + INIT_LIST_HEAD(&priv->tx_urb_free_list); + spin_lock_init(&priv->tx_urb_lock); + INIT_LIST_HEAD(&priv->rx_urb_pending_list); + spin_lock_init(&priv->rx_urb_lock); + INIT_WORK(&priv->rx_urb_wq, rtl8xxxu_rx_urb_work); + + usb_set_intfdata(interface, hw); + + ret = rtl8xxxu_parse_usb(priv, interface); + if (ret) + goto exit; + + ret = rtl8xxxu_identify_chip(priv); + if (ret) { + dev_err(&udev->dev, "Fatal - failed to identify chip\n"); + goto exit; + } + + ret = rtl8xxxu_read_efuse(priv); + if (ret) { + dev_err(&udev->dev, "Fatal - failed to read EFuse\n"); + goto exit; + } + + ret = priv->fops->parse_efuse(priv); + if (ret) { + dev_err(&udev->dev, "Fatal - failed to parse EFuse\n"); + goto exit; + } + + rtl8xxxu_print_chipinfo(priv); + + ret = priv->fops->load_firmware(priv); + if (ret) { + dev_err(&udev->dev, "Fatal - failed to load firmware\n"); + goto exit; + } + + ret = rtl8xxxu_init_device(hw); + + hw->wiphy->max_scan_ssids = 1; + hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; + hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); + hw->queues = 4; + + sband = &rtl8xxxu_supported_band; + sband->ht_cap.ht_supported = true; + sband->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; + sband->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16; + sband->ht_cap.cap = IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40; + memset(&sband->ht_cap.mcs, 0, sizeof(sband->ht_cap.mcs)); + sband->ht_cap.mcs.rx_mask[0] = 0xff; + sband->ht_cap.mcs.rx_mask[4] = 0x01; + if (priv->rf_paths > 1) { + sband->ht_cap.mcs.rx_mask[1] = 0xff; + sband->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40; + } + sband->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; + /* + * Some APs will negotiate HT20_40 in a noisy environment leading + * to miserable performance. Rather than defaulting to this, only + * enable it if explicitly requested at module load time. + */ + if (rtl8xxxu_ht40_2g) { + dev_info(&udev->dev, "Enabling HT_20_40 on the 2.4GHz band\n"); + sband->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; + } + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband; + + hw->wiphy->rts_threshold = 2347; + + SET_IEEE80211_DEV(priv->hw, &interface->dev); + SET_IEEE80211_PERM_ADDR(hw, priv->mac_addr); + + hw->extra_tx_headroom = sizeof(struct rtl8xxxu_tx_desc); + ieee80211_hw_set(hw, SIGNAL_DBM); + /* + * The firmware handles rate control + */ + ieee80211_hw_set(hw, HAS_RATE_CONTROL); + ieee80211_hw_set(hw, AMPDU_AGGREGATION); + + ret = ieee80211_register_hw(priv->hw); + if (ret) { + dev_err(&udev->dev, "%s: Failed to register: %i\n", + __func__, ret); + goto exit; + } + +exit: + if (ret < 0) + usb_put_dev(udev); + return ret; +} + +static void rtl8xxxu_disconnect(struct usb_interface *interface) +{ + struct rtl8xxxu_priv *priv; + struct ieee80211_hw *hw; + + hw = usb_get_intfdata(interface); + priv = hw->priv; + + rtl8xxxu_disable_device(hw); + usb_set_intfdata(interface, NULL); + + dev_info(&priv->udev->dev, "disconnecting\n"); + + ieee80211_unregister_hw(hw); + + kfree(priv->fw_data); + mutex_destroy(&priv->usb_buf_mutex); + mutex_destroy(&priv->h2c_mutex); + + usb_put_dev(priv->udev); + ieee80211_free_hw(hw); +} + +static struct rtl8xxxu_fileops rtl8723au_fops = { + .parse_efuse = rtl8723au_parse_efuse, + .load_firmware = rtl8723au_load_firmware, + .power_on = rtl8723au_power_on, + .writeN_block_size = 1024, +}; + +static struct rtl8xxxu_fileops rtl8192cu_fops = { + .parse_efuse = rtl8192cu_parse_efuse, + .load_firmware = rtl8192cu_load_firmware, + .power_on = rtl8192cu_power_on, + .writeN_block_size = 128, +}; + +static struct usb_device_id dev_table[] = { +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x8724, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8723au_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x1724, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8723au_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x0724, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8723au_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x8176, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x8178, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x817f, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +/* Tested by Larry Finger */ +{USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0x7811, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +#ifdef CONFIG_RTL8XXXU_UNTESTED +/* Currently untested 8188 series devices */ +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x8191, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x8170, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x8177, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x817a, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x817b, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x817d, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x817e, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x818a, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x317f, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x1058, 0x0631, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x04bb, 0x094c, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x050d, 0x1102, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x06f8, 0xe033, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x07b8, 0x8189, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x0846, 0x9041, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x0b05, 0x17ba, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x1e1e, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x5088, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x0df6, 0x0052, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x0df6, 0x005c, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x0eb0, 0x9071, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x103c, 0x1629, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x13d3, 0x3357, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x3308, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x330b, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x2019, 0x4902, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x2019, 0xab2a, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x2019, 0xab2e, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x2019, 0xed17, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x20f4, 0x648b, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x4855, 0x0090, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x4856, 0x0091, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0xcdab, 0x8010, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x317f, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, /* Netcore 8188RU */ +{USB_DEVICE_AND_INTERFACE_INFO(0x04f2, 0xaff7, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x04f2, 0xaff9, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x04f2, 0xaffa, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x04f2, 0xaff8, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x04f2, 0xaffb, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x04f2, 0xaffc, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x2019, 0x1201, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +/* Currently untested 8192 series devices */ +{USB_DEVICE_AND_INTERFACE_INFO(0x04bb, 0x0950, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x050d, 0x1004, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x050d, 0x2102, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x050d, 0x2103, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x0586, 0x341f, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x06f8, 0xe035, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x0b05, 0x17ab, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x0df6, 0x0061, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x0df6, 0x0070, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x0789, 0x016d, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x07aa, 0x0056, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x07b8, 0x8178, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x0846, 0x9021, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x0846, 0xf001, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x2e2e, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x0e66, 0x0019, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x0e66, 0x0020, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x3307, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x3309, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x330a, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x2019, 0xab2b, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x20f4, 0x624d, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x0100, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x4855, 0x0091, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0x7822, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, +#endif +{ } +}; + +static struct usb_driver rtl8xxxu_driver = { + .name = DRIVER_NAME, + .probe = rtl8xxxu_probe, + .disconnect = rtl8xxxu_disconnect, + .id_table = dev_table, + .disable_hub_initiated_lpm = 1, +}; + +static int __init rtl8xxxu_module_init(void) +{ + int res; + + res = usb_register(&rtl8xxxu_driver); + if (res < 0) + pr_err(DRIVER_NAME ": usb_register() failed (%i)\n", res); + + return res; +} + +static void __exit rtl8xxxu_module_exit(void) +{ + usb_deregister(&rtl8xxxu_driver); +} + + +MODULE_DEVICE_TABLE(usb, dev_table); + +module_init(rtl8xxxu_module_init); +module_exit(rtl8xxxu_module_exit); diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h new file mode 100644 index 000000000000..f2a1bac6c8ec --- /dev/null +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -0,0 +1,676 @@ +/* + * Copyright (c) 2014 - 2015 Jes Sorensen + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * Register definitions taken from original Realtek rtl8723au driver + */ + +#include + +#define RTL8XXXU_DEBUG_REG_WRITE 0x01 +#define RTL8XXXU_DEBUG_REG_READ 0x02 +#define RTL8XXXU_DEBUG_RFREG_WRITE 0x04 +#define RTL8XXXU_DEBUG_RFREG_READ 0x08 +#define RTL8XXXU_DEBUG_CHANNEL 0x10 +#define RTL8XXXU_DEBUG_TX 0x20 +#define RTL8XXXU_DEBUG_TX_DUMP 0x40 +#define RTL8XXXU_DEBUG_RX 0x80 +#define RTL8XXXU_DEBUG_RX_DUMP 0x100 +#define RTL8XXXU_DEBUG_USB 0x200 +#define RTL8XXXU_DEBUG_KEY 0x400 +#define RTL8XXXU_DEBUG_H2C 0x800 +#define RTL8XXXU_DEBUG_ACTION 0x1000 +#define RTL8XXXU_DEBUG_EFUSE 0x2000 + +#define RTW_USB_CONTROL_MSG_TIMEOUT 500 +#define RTL8XXXU_MAX_REG_POLL 500 +#define USB_INTR_CONTENT_LENGTH 56 + +#define RTL8XXXU_OUT_ENDPOINTS 3 + +#define REALTEK_USB_READ 0xc0 +#define REALTEK_USB_WRITE 0x40 +#define REALTEK_USB_CMD_REQ 0x05 +#define REALTEK_USB_CMD_IDX 0x00 + +#define TX_TOTAL_PAGE_NUM 0xf8 +/* (HPQ + LPQ + NPQ + PUBQ) = TX_TOTAL_PAGE_NUM */ +#define TX_PAGE_NUM_PUBQ 0xe7 +#define TX_PAGE_NUM_HI_PQ 0x0c +#define TX_PAGE_NUM_LO_PQ 0x02 +#define TX_PAGE_NUM_NORM_PQ 0x02 + +#define RTL_FW_PAGE_SIZE 4096 +#define RTL8XXXU_FIRMWARE_POLL_MAX 1000 + +#define RTL8723A_CHANNEL_GROUPS 3 +#define RTL8723A_MAX_RF_PATHS 2 +#define RF6052_MAX_TX_PWR 0x3f + +#define EFUSE_MAP_LEN_8723A 256 +#define EFUSE_MAX_SECTION_8723A 32 +#define EFUSE_REAL_CONTENT_LEN_8723A 512 +#define EFUSE_BT_MAP_LEN_8723A 1024 +#define EFUSE_MAX_WORD_UNIT 4 + +struct rtl8xxxu_rx_desc { +#ifdef __LITTLE_ENDIAN + u32 pktlen:14; + u32 crc32:1; + u32 icverr:1; + u32 drvinfo_sz:4; + u32 security:3; + u32 qos:1; + u32 shift:2; + u32 phy_stats:1; + u32 swdec:1; + u32 ls:1; + u32 fs:1; + u32 eor:1; + u32 own:1; + + u32 macid:5; + u32 tid:4; + u32 hwrsvd:4; + u32 amsdu:1; + u32 paggr:1; + u32 faggr:1; + u32 a1fit:4; + u32 a2fit:4; + u32 pam:1; + u32 pwr:1; + u32 md:1; + u32 mf:1; + u32 type:2; + u32 mc:1; + u32 bc:1; + + u32 seq:12; + u32 frag:4; + u32 nextpktlen:14; + u32 nextind:1; + u32 reserved0:1; + + u32 rxmcs:6; + u32 rxht:1; + u32 gf:1; + u32 splcp:1; + u32 bw:1; + u32 htc:1; + u32 eosp:1; + u32 bssidfit:2; + u32 reserved1:16; + u32 unicastwake:1; + u32 magicwake:1; + + u32 pattern0match:1; + u32 pattern1match:1; + u32 pattern2match:1; + u32 pattern3match:1; + u32 pattern4match:1; + u32 pattern5match:1; + u32 pattern6match:1; + u32 pattern7match:1; + u32 pattern8match:1; + u32 pattern9match:1; + u32 patternamatch:1; + u32 patternbmatch:1; + u32 patterncmatch:1; + u32 reserved2:19; +#else + u32 own:1; + u32 eor:1; + u32 fs:1; + u32 ls:1; + u32 swdec:1; + u32 phy_stats:1; + u32 shift:2; + u32 qos:1; + u32 security:3; + u32 drvinfo_sz:4; + u32 icverr:1; + u32 crc32:1; + u32 pktlen:14; + + u32 bc:1; + u32 mc:1; + u32 type:2; + u32 mf:1; + u32 md:1; + u32 pwr:1; + u32 pam:1; + u32 a2fit:4; + u32 a1fit:4; + u32 faggr:1; + u32 paggr:1; + u32 amsdu:1; + u32 hwrsvd:4; + u32 tid:4; + u32 macid:5; + + u32 reserved0:1; + u32 nextind:1; + u32 nextpktlen:14; + u32 frag:4; + u32 seq:12; + + u32 magicwake:1; + u32 unicastwake:1; + u32 reserved1:16; + u32 bssidfit:2; + u32 eosp:1; + u32 htc:1; + u32 bw:1; + u32 splcp:1; + u32 gf:1; + u32 rxht:1; + u32 rxmcs:6; + + u32 reserved2:19; + u32 patterncmatch:1; + u32 patternbmatch:1; + u32 patternamatch:1; + u32 pattern9match:1; + u32 pattern8match:1; + u32 pattern7match:1; + u32 pattern6match:1; + u32 pattern5match:1; + u32 pattern4match:1; + u32 pattern3match:1; + u32 pattern2match:1; + u32 pattern1match:1; + u32 pattern0match:1; +#endif + __le32 tsfl; +#if 0 + u32 bassn:12; + u32 bavld:1; + u32 reserved3:19; +#endif +}; + +struct rtl8xxxu_tx_desc { + __le16 pkt_size; + u8 pkt_offset; + u8 txdw0; + __le32 txdw1; + __le32 txdw2; + __le32 txdw3; + __le32 txdw4; + __le32 txdw5; + __le32 txdw6; + __le16 csum; + __le16 txdw7; +}; + +/* CCK Rates, TxHT = 0 */ +#define DESC_RATE_1M 0x00 +#define DESC_RATE_2M 0x01 +#define DESC_RATE_5_5M 0x02 +#define DESC_RATE_11M 0x03 + +/* OFDM Rates, TxHT = 0 */ +#define DESC_RATE_6M 0x04 +#define DESC_RATE_9M 0x05 +#define DESC_RATE_12M 0x06 +#define DESC_RATE_18M 0x07 +#define DESC_RATE_24M 0x08 +#define DESC_RATE_36M 0x09 +#define DESC_RATE_48M 0x0a +#define DESC_RATE_54M 0x0b + +/* MCS Rates, TxHT = 1 */ +#define DESC_RATE_MCS0 0x0c +#define DESC_RATE_MCS1 0x0d +#define DESC_RATE_MCS2 0x0e +#define DESC_RATE_MCS3 0x0f +#define DESC_RATE_MCS4 0x10 +#define DESC_RATE_MCS5 0x11 +#define DESC_RATE_MCS6 0x12 +#define DESC_RATE_MCS7 0x13 +#define DESC_RATE_MCS8 0x14 +#define DESC_RATE_MCS9 0x15 +#define DESC_RATE_MCS10 0x16 +#define DESC_RATE_MCS11 0x17 +#define DESC_RATE_MCS12 0x18 +#define DESC_RATE_MCS13 0x19 +#define DESC_RATE_MCS14 0x1a +#define DESC_RATE_MCS15 0x1b +#define DESC_RATE_MCS15_SG 0x1c +#define DESC_RATE_MCS32 0x20 + +#define TXDESC_OFFSET_SZ 0 +#define TXDESC_OFFSET_SHT 16 +#if 0 +#define TXDESC_BMC BIT(24) +#define TXDESC_LSG BIT(26) +#define TXDESC_FSG BIT(27) +#define TXDESC_OWN BIT(31) +#else +#define TXDESC_BROADMULTICAST BIT(0) +#define TXDESC_LAST_SEGMENT BIT(2) +#define TXDESC_FIRST_SEGMENT BIT(3) +#define TXDESC_OWN BIT(7) +#endif + +/* Word 1 */ +#define TXDESC_PKT_OFFSET_SZ 0 +#define TXDESC_AGG_ENABLE BIT(5) +#define TXDESC_BK BIT(6) +#define TXDESC_QUEUE_SHIFT 8 +#define TXDESC_QUEUE_MASK 0x1f00 +#define TXDESC_QUEUE_BK 0x2 +#define TXDESC_QUEUE_BE 0x0 +#define TXDESC_QUEUE_VI 0x5 +#define TXDESC_QUEUE_VO 0x7 +#define TXDESC_QUEUE_BEACON 0x10 +#define TXDESC_QUEUE_HIGH 0x11 +#define TXDESC_QUEUE_MGNT 0x12 +#define TXDESC_QUEUE_CMD 0x13 +#define TXDESC_QUEUE_MAX (TXDESC_QUEUE_CMD + 1) + +#define DESC_RATE_ID_SHIFT 16 +#define DESC_RATE_ID_MASK 0xf +#define TXDESC_NAVUSEHDR BIT(20) +#define TXDESC_SEC_RC4 0x00400000 +#define TXDESC_SEC_AES 0x00c00000 +#define TXDESC_PKT_OFFSET_SHIFT 26 +#define TXDESC_AGG_EN BIT(29) +#define TXDESC_HWPC BIT(31) + +/* Word 2 */ +#define TXDESC_ACK_REPORT BIT(19) +#define TXDESC_AMPDU_DENSITY_SHIFT 20 + +/* Word 3 */ +#define TXDESC_SEQ_SHIFT 16 +#define TXDESC_SEQ_MASK 0x0fff0000 + +/* Word 4 */ +#define TXDESC_QOS BIT(6) +#define TXDESC_HW_SEQ_ENABLE BIT(7) +#define TXDESC_USE_DRIVER_RATE BIT(8) +#define TXDESC_DISABLE_DATA_FB BIT(10) +#define TXDESC_CTS_SELF_ENABLE BIT(11) +#define TXDESC_RTS_CTS_ENABLE BIT(12) +#define TXDESC_HW_RTS_ENABLE BIT(13) +#define TXDESC_PRIME_CH_OFF_LOWER BIT(20) +#define TXDESC_PRIME_CH_OFF_UPPER BIT(21) +#define TXDESC_SHORT_PREAMBLE BIT(24) +#define TXDESC_DATA_BW BIT(25) +#define TXDESC_RTS_DATA_BW BIT(27) +#define TXDESC_RTS_PRIME_CH_OFF_LOWER BIT(28) +#define TXDESC_RTS_PRIME_CH_OFF_UPPER BIT(29) + +/* Word 5 */ +#define TXDESC_RTS_RATE_SHIFT 0 +#define TXDESC_RTS_RATE_MASK 0x3f +#define TXDESC_SHORT_GI BIT(6) +#define TXDESC_CCX_TAG BIT(7) +#define TXDESC_RETRY_LIMIT_ENABLE BIT(17) +#define TXDESC_RETRY_LIMIT_SHIFT 18 +#define TXDESC_RETRY_LIMIT_MASK 0x00fc0000 + +/* Word 6 */ +#define TXDESC_MAX_AGG_SHIFT 11 + +struct phy_rx_agc_info { +#ifdef __LITTLE_ENDIAN + u8 gain:7, trsw:1; +#else + u8 trsw:1, gain:7; +#endif +}; + +struct rtl8723au_phy_stats { + struct phy_rx_agc_info path_agc[RTL8723A_MAX_RF_PATHS]; + u8 ch_corr[RTL8723A_MAX_RF_PATHS]; + u8 cck_sig_qual_ofdm_pwdb_all; + u8 cck_agc_rpt_ofdm_cfosho_a; + u8 cck_rpt_b_ofdm_cfosho_b; + u8 reserved_1; + u8 noise_power_db_msb; + u8 path_cfotail[RTL8723A_MAX_RF_PATHS]; + u8 pcts_mask[RTL8723A_MAX_RF_PATHS]; + s8 stream_rxevm[RTL8723A_MAX_RF_PATHS]; + u8 path_rxsnr[RTL8723A_MAX_RF_PATHS]; + u8 noise_power_db_lsb; + u8 reserved_2[3]; + u8 stream_csi[RTL8723A_MAX_RF_PATHS]; + u8 stream_target_csi[RTL8723A_MAX_RF_PATHS]; + s8 sig_evm; + u8 reserved_3; + +#ifdef __LITTLE_ENDIAN + u8 antsel_rx_keep_2:1; /* ex_intf_flg:1; */ + u8 sgi_en:1; + u8 rxsc:2; + u8 idle_long:1; + u8 r_ant_train_en:1; + u8 antenna_select_b:1; + u8 antenna_select:1; +#else /* _BIG_ENDIAN_ */ + u8 antenna_select:1; + u8 antenna_select_b:1; + u8 r_ant_train_en:1; + u8 idle_long:1; + u8 rxsc:2; + u8 sgi_en:1; + u8 antsel_rx_keep_2:1; /* ex_intf_flg:1; */ +#endif +}; + +/* + * Regs to backup + */ +#define RTL8XXXU_ADDA_REGS 16 +#define RTL8XXXU_MAC_REGS 4 +#define RTL8XXXU_BB_REGS 9 + +struct rtl8xxxu_firmware_header { + __le16 signature; /* 92C0: test chip; 92C, + 88C0: test chip; + 88C1: MP A-cut; + 92C1: MP A-cut */ + u8 category; /* AP/NIC and USB/PCI */ + u8 function; + + __le16 major_version; /* FW Version */ + u8 minor_version; /* FW Subversion, default 0x00 */ + u8 reserved1; + + u8 month; /* Release time Month field */ + u8 date; /* Release time Date field */ + u8 hour; /* Release time Hour field */ + u8 minute; /* Release time Minute field */ + + __le16 ramcodesize; /* Size of RAM code */ + u16 reserved2; + + __le32 svn_idx; /* SVN entry index */ + u32 reserved3; + + u32 reserved4; + u32 reserved5; + + u8 data[0]; +}; + +/* + * The 8723au has 3 channel groups: 1-3, 4-9, and 10-14 + */ +struct rtl8723au_idx { +#ifdef __LITTLE_ENDIAN + int a:4; + int b:4; +#else + int b:4; + int a:4; +#endif +} __attribute__((packed)); + +struct rtl8723au_efuse { + __le16 rtl_id; + u8 res0[0xe]; + u8 cck_tx_power_index_A[3]; /* 0x10 */ + u8 cck_tx_power_index_B[3]; + u8 ht40_1s_tx_power_index_A[3]; /* 0x16 */ + u8 ht40_1s_tx_power_index_B[3]; + /* + * The following entries are half-bytes split as: + * bits 0-3: path A, bits 4-7: path B, all values 4 bits signed + */ + struct rtl8723au_idx ht20_tx_power_index_diff[3]; + struct rtl8723au_idx ofdm_tx_power_index_diff[3]; + struct rtl8723au_idx ht40_max_power_offset[3]; + struct rtl8723au_idx ht20_max_power_offset[3]; + u8 channel_plan; /* 0x28 */ + u8 tssi_a; + u8 thermal_meter; + u8 rf_regulatory; + u8 rf_option_2; + u8 rf_option_3; + u8 rf_option_4; + u8 res7; + u8 version /* 0x30 */; + u8 customer_id_major; + u8 customer_id_minor; + u8 xtal_k; + u8 chipset; /* 0x34 */ + u8 res8[0x82]; + u8 vid; /* 0xb7 */ + u8 res9; + u8 pid; /* 0xb9 */ + u8 res10[0x0c]; + u8 mac_addr[ETH_ALEN]; /* 0xc6 */ + u8 res11[2]; + u8 vendor_name[7]; + u8 res12[2]; + u8 device_name[0x29]; /* 0xd7 */ +}; + +struct rtl8192cu_efuse { + __le16 rtl_id; + __le16 hpon; + u8 res0[2]; + __le16 clk; + __le16 testr; + __le16 vid; + __le16 did; + __le16 svid; + __le16 smid; /* 0x10 */ + u8 res1[4]; + u8 mac_addr[ETH_ALEN]; /* 0x16 */ + u8 res2[2]; + u8 vendor_name[7]; + u8 res3[3]; + u8 device_name[0x14]; /* 0x28 */ + u8 res4[0x1e]; /* 0x3c */ + u8 cck_tx_power_index_A[3]; /* 0x5a */ + u8 cck_tx_power_index_B[3]; + u8 ht40_1s_tx_power_index_A[3]; /* 0x60 */ + u8 ht40_1s_tx_power_index_B[3]; + /* + * The following entries are half-bytes split as: + * bits 0-3: path A, bits 4-7: path B, all values 4 bits signed + */ + struct rtl8723au_idx ht40_2s_tx_power_index_diff[3]; + struct rtl8723au_idx ht20_tx_power_index_diff[3]; /* 0x69 */ + struct rtl8723au_idx ofdm_tx_power_index_diff[3]; + struct rtl8723au_idx ht40_max_power_offset[3]; /* 0x6f */ + struct rtl8723au_idx ht20_max_power_offset[3]; + u8 channel_plan; /* 0x75 */ + u8 tssi_a; + u8 tssi_b; + u8 thermal_meter; /* xtal_k */ /* 0x78 */ + u8 rf_regulatory; + u8 rf_option_2; + u8 rf_option_3; + u8 rf_option_4; + u8 res5[1]; /* 0x7d */ + u8 version; + u8 customer_id; +}; + +struct rtl8xxxu_reg8val { + u16 reg; + u8 val; +}; + +struct rtl8xxxu_reg32val { + u16 reg; + u32 val; +}; + +struct rtl8xxxu_rfregval { + u8 reg; + u32 val; +}; + +enum rtl8xxxu_rfpath { + RF_A = 0, + RF_B = 1, +}; + +struct rtl8xxxu_rfregs { + u16 hssiparm1; + u16 hssiparm2; + u16 lssiparm; + u16 hspiread; + u16 lssiread; + u16 rf_sw_ctrl; +}; + +#define H2C_MAX_MBOX 4 +#define H2C_EXT BIT(7) +#define H2C_SET_POWER_MODE 1 +#define H2C_JOIN_BSS_REPORT 2 +#define H2C_JOIN_BSS_DISCONNECT 0 +#define H2C_JOIN_BSS_CONNECT 1 +#define H2C_SET_RSSI 5 +#define H2C_SET_RATE_MASK (6 | H2C_EXT) + +struct h2c_cmd { + union { + struct { + u8 cmd; + u8 data[5]; + } __packed cmd; + struct { + __le32 data; + __le16 ext; + } __packed raw; + struct { + u8 cmd; + u8 data; + u8 pad[4]; + } __packed joinbss; + struct { + u8 cmd; + __le16 mask_hi; + u8 arg; + __le16 mask_lo; + } __packed ramask; + }; +}; + +struct rtl8xxxu_fileops; + +struct rtl8xxxu_priv { + struct ieee80211_hw *hw; + struct usb_device *udev; + struct rtl8xxxu_fileops *fops; + + spinlock_t tx_urb_lock; + struct list_head tx_urb_free_list; + int tx_urb_free_count; + bool tx_stopped; + + spinlock_t rx_urb_lock; + struct list_head rx_urb_pending_list; + int rx_urb_pending_count; + bool shutdown; + struct work_struct rx_urb_wq; + + u8 mac_addr[ETH_ALEN]; + char chip_name[8]; + u8 cck_tx_power_index_A[3]; /* 0x10 */ + u8 cck_tx_power_index_B[3]; + u8 ht40_1s_tx_power_index_A[3]; /* 0x16 */ + u8 ht40_1s_tx_power_index_B[3]; + /* + * The following entries are half-bytes split as: + * bits 0-3: path A, bits 4-7: path B, all values 4 bits signed + */ + struct rtl8723au_idx ht40_2s_tx_power_index_diff[3]; + struct rtl8723au_idx ht20_tx_power_index_diff[3]; + struct rtl8723au_idx ofdm_tx_power_index_diff[3]; + struct rtl8723au_idx ht40_max_power_offset[3]; + struct rtl8723au_idx ht20_max_power_offset[3]; + u32 chip_cut:4; + u32 rom_rev:4; + u32 has_wifi:1; + u32 has_bluetooth:1; + u32 enable_bluetooth:1; + u32 has_gps:1; + u32 hi_pa:1; + u32 vendor_umc:1; + u32 has_polarity_ctrl:1; + u32 has_eeprom:1; + u32 boot_eeprom:1; + u32 ep_tx_high_queue:1; + u32 ep_tx_normal_queue:1; + u32 ep_tx_low_queue:1; + u32 path_a_hi_power:1; + u32 path_a_rf_paths:4; + unsigned int pipe_interrupt; + unsigned int pipe_in; + unsigned int pipe_out[TXDESC_QUEUE_MAX]; + u8 out_ep[RTL8XXXU_OUT_ENDPOINTS]; + u8 path_a_ig_value; + u8 ep_tx_count; + u8 rf_paths; + u8 rx_paths; + u8 tx_paths; + u32 rf_mode_ag[2]; + u32 rege94; + u32 rege9c; + u32 regeb4; + u32 regebc; + int next_mbox; + int nr_out_eps; + + struct mutex h2c_mutex; + + struct usb_anchor rx_anchor; + struct usb_anchor tx_anchor; + struct usb_anchor int_anchor; + struct rtl8xxxu_firmware_header *fw_data; + size_t fw_size; + struct mutex usb_buf_mutex; + union { + __le32 val32; + __le16 val16; + u8 val8; + } usb_buf; + union { + u8 raw[EFUSE_MAP_LEN_8723A]; + struct rtl8723au_efuse efuse8723; + struct rtl8192cu_efuse efuse8192; + } efuse_wifi; + u32 adda_backup[RTL8XXXU_ADDA_REGS]; + u32 mac_backup[RTL8XXXU_MAC_REGS]; + u32 bb_backup[RTL8XXXU_BB_REGS]; + u32 bb_recovery_backup[RTL8XXXU_BB_REGS]; + u32 rtlchip; + u8 pi_enabled:1; + u8 iqk_initialized:1; + u8 int_buf[USB_INTR_CONTENT_LENGTH]; +}; + +struct rtl8xxxu_rx_urb { + struct urb urb; + struct ieee80211_hw *hw; + struct list_head list; +}; + +struct rtl8xxxu_tx_urb { + struct urb urb; + struct ieee80211_hw *hw; + struct list_head list; +}; + +struct rtl8xxxu_fileops { + int (*parse_efuse) (struct rtl8xxxu_priv *priv); + int (*load_firmware) (struct rtl8xxxu_priv *priv); + int (*power_on) (struct rtl8xxxu_priv *priv); + int writeN_block_size; +}; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h new file mode 100644 index 000000000000..23208f79b97c --- /dev/null +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h @@ -0,0 +1,981 @@ +/* + * Copyright (c) 2014 - 2015 Jes Sorensen + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * Register definitions taken from original Realtek rtl8723au driver + */ + +/* 0x0000 ~ 0x00FF System Configuration */ +#define REG_SYS_ISO_CTRL 0x0000 +#define SYS_ISO_MD2PP BIT(0) +#define SYS_ISO_ANALOG_IPS BIT(5) +#define SYS_ISO_DIOR BIT(9) +#define SYS_ISO_PWC_EV25V BIT(14) +#define SYS_ISO_PWC_EV12V BIT(15) + +#define REG_SYS_FUNC 0x0002 +#define SYS_FUNC_BBRSTB BIT(0) +#define SYS_FUNC_BB_GLB_RSTN BIT(1) +#define SYS_FUNC_USBA BIT(2) +#define SYS_FUNC_UPLL BIT(3) +#define SYS_FUNC_USBD BIT(4) +#define SYS_FUNC_DIO_PCIE BIT(5) +#define SYS_FUNC_PCIEA BIT(6) +#define SYS_FUNC_PPLL BIT(7) +#define SYS_FUNC_PCIED BIT(8) +#define SYS_FUNC_DIOE BIT(9) +#define SYS_FUNC_CPU_ENABLE BIT(10) +#define SYS_FUNC_DCORE BIT(11) +#define SYS_FUNC_ELDR BIT(12) +#define SYS_FUNC_DIO_RF BIT(13) +#define SYS_FUNC_HWPDN BIT(14) +#define SYS_FUNC_MREGEN BIT(15) + +#define REG_APS_FSMCO 0x0004 +#define APS_FSMCO_PFM_ALDN BIT(1) +#define APS_FSMCO_PFM_WOWL BIT(3) +#define APS_FSMCO_ENABLE_POWERDOWN BIT(4) +#define APS_FSMCO_MAC_ENABLE BIT(8) +#define APS_FSMCO_MAC_OFF BIT(9) +#define APS_FSMCO_HW_SUSPEND BIT(11) +#define APS_FSMCO_PCIE BIT(12) +#define APS_FSMCO_HW_POWERDOWN BIT(15) +#define APS_FSMCO_WLON_RESET BIT(16) + +#define REG_SYS_CLKR 0x0008 +#define SYS_CLK_ANAD16V_ENABLE BIT(0) +#define SYS_CLK_ANA8M BIT(1) +#define SYS_CLK_MACSLP BIT(4) +#define SYS_CLK_LOADER_ENABLE BIT(5) +#define SYS_CLK_80M_SSC_DISABLE BIT(7) +#define SYS_CLK_80M_SSC_ENABLE_HO BIT(8) +#define SYS_CLK_PHY_SSC_RSTB BIT(9) +#define SYS_CLK_SEC_CLK_ENABLE BIT(10) +#define SYS_CLK_MAC_CLK_ENABLE BIT(11) +#define SYS_CLK_ENABLE BIT(12) +#define SYS_CLK_RING_CLK_ENABLE BIT(13) + +#define REG_9346CR 0x000a +#define EEPROM_BOOT BIT(4) +#define EEPROM_ENABLE BIT(5) + +#define REG_EE_VPD 0x000c +#define REG_AFE_MISC 0x0010 +#define REG_SPS0_CTRL 0x0011 +#define REG_SPS_OCP_CFG 0x0018 +#define REG_RSV_CTRL 0x001c + +#define REG_RF_CTRL 0x001f +#define RF_ENABLE BIT(0) +#define RF_RSTB BIT(1) +#define RF_SDMRSTB BIT(2) + +#define REG_LDOA15_CTRL 0x0020 +#define LDOA15_ENABLE BIT(0) +#define LDOA15_STANDBY BIT(1) +#define LDOA15_OBUF BIT(2) +#define LDOA15_REG_VOS BIT(3) +#define LDOA15_VOADJ_SHIFT 4 + +#define REG_LDOV12D_CTRL 0x0021 +#define LDOV12D_ENABLE BIT(0) +#define LDOV12D_STANDBY BIT(1) +#define LDOV12D_VADJ_SHIFT 4 + +#define REG_LDOHCI12_CTRL 0x0022 + +#define REG_LPLDO_CTRL 0x0023 +#define LPLDO_HSM BIT(2) +#define LPLDO_LSM_DIS BIT(3) + +#define REG_AFE_XTAL_CTRL 0x0024 +#define AFE_XTAL_ENABLE BIT(0) +#define AFE_XTAL_B_SELECT BIT(1) +#define AFE_XTAL_GATE_USB BIT(8) +#define AFE_XTAL_GATE_AFE BIT(11) +#define AFE_XTAL_RF_GATE BIT(14) +#define AFE_XTAL_GATE_DIG BIT(17) +#define AFE_XTAL_BT_GATE BIT(20) + +#define REG_AFE_PLL_CTRL 0x0028 +#define AFE_PLL_ENABLE BIT(0) +#define AFE_PLL_320_ENABLE BIT(1) +#define APE_PLL_FREF_SELECT BIT(2) +#define AFE_PLL_EDGE_SELECT BIT(3) +#define AFE_PLL_WDOGB BIT(4) +#define AFE_PLL_LPF_ENABLE BIT(5) + +#define REG_MAC_PHY_CTRL 0x002c + +#define REG_EFUSE_CTRL 0x0030 +#define REG_EFUSE_TEST 0x0034 +#define EFUSE_TRPT BIT(7) + /* 00: Wifi Efuse, 01: BT Efuse0, 10: BT Efuse1, 11: BT Efuse2 */ +#define EFUSE_CELL_SEL (BIT(8) | BIT(9)) +#define EFUSE_LDOE25_ENABLE BIT(31) +#define EFUSE_SELECT_MASK 0x0300 +#define EFUSE_WIFI_SELECT 0x0000 +#define EFUSE_BT0_SELECT 0x0100 +#define EFUSE_BT1_SELECT 0x0200 +#define EFUSE_BT2_SELECT 0x0300 + +#define EFUSE_ACCESS_ENABLE 0x69 /* RTL8723 only */ +#define EFUSE_ACCESS_DISABLE 0x00 /* RTL8723 only */ + +#define REG_PWR_DATA 0x0038 +#define REG_CAL_TIMER 0x003c +#define REG_ACLK_MON 0x003e +#define REG_GPIO_MUXCFG 0x0040 +#define REG_GPIO_IO_SEL 0x0042 +#define REG_MAC_PINMUX_CFG 0x0043 +#define REG_GPIO_PIN_CTRL 0x0044 +#define REG_GPIO_INTM 0x0048 +#define REG_LEDCFG0 0x004c +#define REG_LEDCFG1 0x004d +#define REG_LEDCFG2 0x004e +#define LEDCFG2_DPDT_SELECT BIT(7) +#define REG_LEDCFG3 0x004f +#define REG_LEDCFG REG_LEDCFG2 +#define REG_FSIMR 0x0050 +#define REG_FSISR 0x0054 +#define REG_HSIMR 0x0058 +#define REG_HSISR 0x005c +/* RTL8723 WIFI/BT/GPS Multi-Function GPIO Pin Control. */ +#define REG_GPIO_PIN_CTRL_2 0x0060 +/* RTL8723 WIFI/BT/GPS Multi-Function GPIO Select. */ +#define REG_GPIO_IO_SEL_2 0x0062 + +/* RTL8723 only WIFI/BT/GPS Multi-Function control source. */ +#define REG_MULTI_FUNC_CTRL 0x0068 + +#define MULTI_FN_WIFI_HW_PWRDOWN_EN BIT(0) /* Enable GPIO[9] as WiFi HW + powerdown source */ +#define MULTI_FN_WIFI_HW_PWRDOWN_SL BIT(1) /* WiFi HW powerdown polarity + control */ +#define MULTI_WIFI_FUNC_EN BIT(2) /* WiFi function enable */ + +#define MULTI_WIFI_HW_ROF_EN BIT(3) /* Enable GPIO[9] as WiFi RF HW + powerdown source */ +#define MULTI_BT_HW_PWRDOWN_EN BIT(16) /* Enable GPIO[11] as BT HW + powerdown source */ +#define MULTI_BT_HW_PWRDOWN_SL BIT(17) /* BT HW powerdown polarity + control */ +#define MULTI_BT_FUNC_EN BIT(18) /* BT function enable */ +#define MULTI_BT_HW_ROF_EN BIT(19) /* Enable GPIO[11] as BT/GPS + RF HW powerdown source */ +#define MULTI_GPS_HW_PWRDOWN_EN BIT(20) /* Enable GPIO[10] as GPS HW + powerdown source */ +#define MULTI_GPS_HW_PWRDOWN_SL BIT(21) /* GPS HW powerdown polarity + control */ +#define MULTI_GPS_FUNC_EN BIT(22) /* GPS function enable */ + +#define REG_MCU_FW_DL 0x0080 +#define MCU_FW_DL_ENABLE BIT(0) +#define MCU_FW_DL_READY BIT(1) +#define MCU_FW_DL_CSUM_REPORT BIT(2) +#define MCU_MAC_INIT_READY BIT(3) +#define MCU_BB_INIT_READY BIT(4) +#define MCU_RF_INIT_READY BIT(5) +#define MCU_WINT_INIT_READY BIT(6) +#define MCU_FW_RAM_SEL BIT(7) /* 1: RAM, 0:ROM */ +#define MCU_CP_RESET BIT(23) + +#define REG_HMBOX_EXT_0 0x0088 +#define REG_HMBOX_EXT_1 0x008a +#define REG_HMBOX_EXT_2 0x008c +#define REG_HMBOX_EXT_3 0x008e +/* Host suspend counter on FPGA platform */ +#define REG_HOST_SUSP_CNT 0x00bc +/* Efuse access protection for RTL8723 */ +#define REG_EFUSE_ACCESS 0x00cf +#define REG_BIST_SCAN 0x00d0 +#define REG_BIST_RPT 0x00d4 +#define REG_BIST_ROM_RPT 0x00d8 +#define REG_USB_SIE_INTF 0x00e0 +#define REG_PCIE_MIO_INTF 0x00e4 +#define REG_PCIE_MIO_INTD 0x00e8 +#define REG_HPON_FSM 0x00ec +#define HPON_FSM_BONDING_MASK (BIT(22) | BIT(23)) +#define HPON_FSM_BONDING_1T2R BIT(22) +#define REG_SYS_CFG 0x00f0 +#define SYS_CFG_XCLK_VLD BIT(0) +#define SYS_CFG_ACLK_VLD BIT(1) +#define SYS_CFG_UCLK_VLD BIT(2) +#define SYS_CFG_PCLK_VLD BIT(3) +#define SYS_CFG_PCIRSTB BIT(4) +#define SYS_CFG_V15_VLD BIT(5) +#define SYS_CFG_TRP_B15V_EN BIT(7) +#define SYS_CFG_SIC_IDLE BIT(8) +#define SYS_CFG_BD_MAC2 BIT(9) +#define SYS_CFG_BD_MAC1 BIT(10) +#define SYS_CFG_IC_MACPHY_MODE BIT(11) +#define SYS_CFG_CHIP_VER (BIT(12) | BIT(13) | BIT(14) | BIT(15)) +#define SYS_CFG_BT_FUNC BIT(16) +#define SYS_CFG_VENDOR_ID BIT(19) +#define SYS_CFG_PAD_HWPD_IDN BIT(22) +#define SYS_CFG_TRP_VAUX_EN BIT(23) +#define SYS_CFG_TRP_BT_EN BIT(24) +#define SYS_CFG_BD_PKG_SEL BIT(25) +#define SYS_CFG_BD_HCI_SEL BIT(26) +#define SYS_CFG_TYPE_ID BIT(27) +#define SYS_CFG_RTL_ID BIT(23) /* TestChip ID, + 1:Test(RLE); 0:MP(RL) */ +#define SYS_CFG_SPS_SEL BIT(24) /* 1:LDO regulator mode; + 0:Switching regulator mode*/ +#define SYS_CFG_CHIP_VERSION_MASK 0xf000 /* Bit 12 - 15 */ +#define SYS_CFG_CHIP_VERSION_SHIFT 12 + +#define REG_GPIO_OUTSTS 0x00f4 /* For RTL8723 only. */ +#define GPIO_EFS_HCI_SEL (BIT(0) | BIT(1)) +#define GPIO_PAD_HCI_SEL (BIT(2) | BIT(3)) +#define GPIO_HCI_SEL (BIT(4) | BIT(5)) +#define GPIO_PKG_SEL_HCI BIT(6) +#define GPIO_FEN_GPS BIT(7) +#define GPIO_FEN_BT BIT(8) +#define GPIO_FEN_WL BIT(9) +#define GPIO_FEN_PCI BIT(10) +#define GPIO_FEN_USB BIT(11) +#define GPIO_BTRF_HWPDN_N BIT(12) +#define GPIO_WLRF_HWPDN_N BIT(13) +#define GPIO_PDN_BT_N BIT(14) +#define GPIO_PDN_GPS_N BIT(15) +#define GPIO_BT_CTL_HWPDN BIT(16) +#define GPIO_GPS_CTL_HWPDN BIT(17) +#define GPIO_PPHY_SUSB BIT(20) +#define GPIO_UPHY_SUSB BIT(21) +#define GPIO_PCI_SUSEN BIT(22) +#define GPIO_USB_SUSEN BIT(23) +#define GPIO_RF_RL_ID (BIT(31) | BIT(30) | BIT(29) | BIT(28)) + +/* 0x0100 ~ 0x01FF MACTOP General Configuration */ +#define REG_CR 0x0100 +#define CR_HCI_TXDMA_ENABLE BIT(0) +#define CR_HCI_RXDMA_ENABLE BIT(1) +#define CR_TXDMA_ENABLE BIT(2) +#define CR_RXDMA_ENABLE BIT(3) +#define CR_PROTOCOL_ENABLE BIT(4) +#define CR_SCHEDULE_ENABLE BIT(5) +#define CR_MAC_TX_ENABLE BIT(6) +#define CR_MAC_RX_ENABLE BIT(7) +#define CR_SW_BEACON_ENABLE BIT(8) +#define CR_SECURITY_ENABLE BIT(9) +#define CR_CALTIMER_ENABLE BIT(10) + +/* Media Status Register */ +#define REG_MSR 0x0102 +#define MSR_LINKTYPE_MASK 0x3 +#define MSR_LINKTYPE_NONE 0x0 +#define MSR_LINKTYPE_ADHOC 0x1 +#define MSR_LINKTYPE_STATION 0x2 +#define MSR_LINKTYPE_AP 0x3 + +#define REG_PBP 0x0104 +#define PBP_PAGE_SIZE_RX_SHIFT 0 +#define PBP_PAGE_SIZE_TX_SHIFT 4 +#define PBP_PAGE_SIZE_64 0x0 +#define PBP_PAGE_SIZE_128 0x1 +#define PBP_PAGE_SIZE_256 0x2 +#define PBP_PAGE_SIZE_512 0x3 +#define PBP_PAGE_SIZE_1024 0x4 + +#define REG_TRXDMA_CTRL 0x010c +#define TRXDMA_CTRL_VOQ_SHIFT 4 +#define TRXDMA_CTRL_VIQ_SHIFT 6 +#define TRXDMA_CTRL_BEQ_SHIFT 8 +#define TRXDMA_CTRL_BKQ_SHIFT 10 +#define TRXDMA_CTRL_MGQ_SHIFT 12 +#define TRXDMA_CTRL_HIQ_SHIFT 14 +#define TRXDMA_QUEUE_LOW 1 +#define TRXDMA_QUEUE_NORMAL 2 +#define TRXDMA_QUEUE_HIGH 3 + +#define REG_TRXFF_BNDY 0x0114 +#define REG_TRXFF_STATUS 0x0118 +#define REG_RXFF_PTR 0x011c +#define REG_HIMR 0x0120 +#define REG_HISR 0x0124 +#define REG_HIMRE 0x0128 +#define REG_HISRE 0x012c +#define REG_CPWM 0x012f +#define REG_FWIMR 0x0130 +#define REG_FWISR 0x0134 +#define REG_PKTBUF_DBG_CTRL 0x0140 +#define REG_PKTBUF_DBG_DATA_L 0x0144 +#define REG_PKTBUF_DBG_DATA_H 0x0148 + +#define REG_TC0_CTRL 0x0150 +#define REG_TC1_CTRL 0x0154 +#define REG_TC2_CTRL 0x0158 +#define REG_TC3_CTRL 0x015c +#define REG_TC4_CTRL 0x0160 +#define REG_TCUNIT_BASE 0x0164 +#define REG_MBIST_START 0x0174 +#define REG_MBIST_DONE 0x0178 +#define REG_MBIST_FAIL 0x017c +#define REG_C2HEVT_MSG_NORMAL 0x01a0 +#define REG_C2HEVT_CLEAR 0x01af +#define REG_C2HEVT_MSG_TEST 0x01b8 +#define REG_MCUTST_1 0x01c0 +#define REG_FMTHR 0x01c8 +#define REG_HMTFR 0x01cc +#define REG_HMBOX_0 0x01d0 +#define REG_HMBOX_1 0x01d4 +#define REG_HMBOX_2 0x01d8 +#define REG_HMBOX_3 0x01dc + +#define REG_LLT_INIT 0x01e0 +#define LLT_OP_INACTIVE 0x0 +#define LLT_OP_WRITE (0x1 << 30) +#define LLT_OP_READ (0x2 << 30) +#define LLT_OP_MASK (0x3 << 30) + +#define REG_BB_ACCEESS_CTRL 0x01e8 +#define REG_BB_ACCESS_DATA 0x01ec + +/* 0x0200 ~ 0x027F TXDMA Configuration */ +#define REG_RQPN 0x0200 +#define RQPN_HI_PQ_SHIFT 0 +#define RQPN_LO_PQ_SHIFT 8 +#define RQPN_NORM_PQ_SHIFT 16 +#define RQPN_LOAD BIT(31) + +#define REG_FIFOPAGE 0x0204 +#define REG_TDECTRL 0x0208 +#define REG_TXDMA_OFFSET_CHK 0x020c +#define REG_TXDMA_STATUS 0x0210 +#define REG_RQPN_NPQ 0x0214 + +/* 0x0280 ~ 0x02FF RXDMA Configuration */ +#define REG_RXDMA_AGG_PG_TH 0x0280 +#define REG_RXPKT_NUM 0x0284 +#define REG_RXDMA_STATUS 0x0288 + +#define REG_RF_BB_CMD_ADDR 0x02c0 +#define REG_RF_BB_CMD_DATA 0x02c4 + +/* spec version 11 */ +/* 0x0400 ~ 0x047F Protocol Configuration */ +#define REG_VOQ_INFORMATION 0x0400 +#define REG_VIQ_INFORMATION 0x0404 +#define REG_BEQ_INFORMATION 0x0408 +#define REG_BKQ_INFORMATION 0x040c +#define REG_MGQ_INFORMATION 0x0410 +#define REG_HGQ_INFORMATION 0x0414 +#define REG_BCNQ_INFORMATION 0x0418 + +#define REG_CPU_MGQ_INFORMATION 0x041c +#define REG_FWHW_TXQ_CTRL 0x0420 +#define FWHW_TXQ_CTRL_AMPDU_RETRY BIT(7) +#define FWHW_TXQ_CTRL_XMIT_MGMT_ACK BIT(12) + +#define REG_HWSEQ_CTRL 0x0423 +#define REG_TXPKTBUF_BCNQ_BDNY 0x0424 +#define REG_TXPKTBUF_MGQ_BDNY 0x0425 +#define REG_LIFETIME_EN 0x0426 +#define REG_MULTI_BCNQ_OFFSET 0x0427 + +#define REG_SPEC_SIFS 0x0428 +#define SPEC_SIFS_CCK_MASK 0x00ff +#define SPEC_SIFS_CCK_SHIFT 0 +#define SPEC_SIFS_OFDM_MASK 0xff00 +#define SPEC_SIFS_OFDM_SHIFT 8 + +#define REG_RETRY_LIMIT 0x042a +#define RETRY_LIMIT_LONG_SHIFT 0 +#define RETRY_LIMIT_LONG_MASK 0x003f +#define RETRY_LIMIT_SHORT_SHIFT 8 +#define RETRY_LIMIT_SHORT_MASK 0x3f00 + +#define REG_DARFRC 0x0430 +#define REG_RARFRC 0x0438 +#define REG_RESPONSE_RATE_SET 0x0440 +#define RESPONSE_RATE_BITMAP_ALL 0xfffff +#define RESPONSE_RATE_RRSR_CCK_ONLY_1M 0xffff1 +#define RSR_1M BIT(0) +#define RSR_2M BIT(1) +#define RSR_5_5M BIT(2) +#define RSR_11M BIT(3) +#define RSR_6M BIT(4) +#define RSR_9M BIT(5) +#define RSR_12M BIT(6) +#define RSR_18M BIT(7) +#define RSR_24M BIT(8) +#define RSR_36M BIT(9) +#define RSR_48M BIT(10) +#define RSR_54M BIT(11) +#define RSR_MCS0 BIT(12) +#define RSR_MCS1 BIT(13) +#define RSR_MCS2 BIT(14) +#define RSR_MCS3 BIT(15) +#define RSR_MCS4 BIT(16) +#define RSR_MCS5 BIT(17) +#define RSR_MCS6 BIT(18) +#define RSR_MCS7 BIT(19) +#define RSR_RSC_LOWER_SUB_CHANNEL BIT(21) /* 0x200000 */ +#define RSR_RSC_UPPER_SUB_CHANNEL BIT(22) /* 0x400000 */ +#define RSR_RSC_BANDWIDTH_40M (RSR_RSC_UPPER_SUB_CHANNEL | \ + RSR_RSC_LOWER_SUB_CHANNEL) +#define RSR_ACK_SHORT_PREAMBLE BIT(23) + +#define REG_ARFR0 0x0444 +#define REG_ARFR1 0x0448 +#define REG_ARFR2 0x044c +#define REG_ARFR3 0x0450 +#define REG_AGGLEN_LMT 0x0458 +#define REG_AMPDU_MIN_SPACE 0x045c +#define REG_TXPKTBUF_WMAC_LBK_BF_HD 0x045d +#define REG_FAST_EDCA_CTRL 0x0460 +#define REG_RD_RESP_PKT_TH 0x0463 +#define REG_INIRTS_RATE_SEL 0x0480 +#define REG_INIDATA_RATE_SEL 0x0484 + +#define REG_POWER_STATUS 0x04a4 +#define REG_POWER_STAGE1 0x04b4 +#define REG_POWER_STAGE2 0x04b8 +#define REG_PKT_VO_VI_LIFE_TIME 0x04c0 +#define REG_PKT_BE_BK_LIFE_TIME 0x04c2 +#define REG_STBC_SETTING 0x04c4 +#define REG_PROT_MODE_CTRL 0x04c8 +#define REG_MAX_AGGR_NUM 0x04ca +#define REG_RTS_MAX_AGGR_NUM 0x04cb +#define REG_BAR_MODE_CTRL 0x04cc +#define REG_RA_TRY_RATE_AGG_LMT 0x04cf +#define REG_NQOS_SEQ 0x04dc +#define REG_QOS_SEQ 0x04de +#define REG_NEED_CPU_HANDLE 0x04e0 +#define REG_PKT_LOSE_RPT 0x04e1 +#define REG_PTCL_ERR_STATUS 0x04e2 +#define REG_DUMMY 0x04fc + +/* 0x0500 ~ 0x05FF EDCA Configuration */ +#define REG_EDCA_VO_PARAM 0x0500 +#define REG_EDCA_VI_PARAM 0x0504 +#define REG_EDCA_BE_PARAM 0x0508 +#define REG_EDCA_BK_PARAM 0x050c +#define EDCA_PARAM_ECW_MIN_SHIFT 8 +#define EDCA_PARAM_ECW_MAX_SHIFT 12 +#define EDCA_PARAM_TXOP_SHIFT 16 +#define REG_BEACON_TCFG 0x0510 +#define REG_PIFS 0x0512 +#define REG_RDG_PIFS 0x0513 +#define REG_SIFS_CCK 0x0514 +#define REG_SIFS_OFDM 0x0516 +#define REG_TSFTR_SYN_OFFSET 0x0518 +#define REG_AGGR_BREAK_TIME 0x051a +#define REG_SLOT 0x051b +#define REG_TX_PTCL_CTRL 0x0520 +#define REG_TXPAUSE 0x0522 +#define REG_DIS_TXREQ_CLR 0x0523 +#define REG_RD_CTRL 0x0524 +#define REG_TBTT_PROHIBIT 0x0540 +#define REG_RD_NAV_NXT 0x0544 +#define REG_NAV_PROT_LEN 0x0546 + +#define REG_BEACON_CTRL 0x0550 +#define REG_BEACON_CTRL_1 0x0551 +#define BEACON_ATIM BIT(0) +#define BEACON_CTRL_MBSSID BIT(1) +#define BEACON_CTRL_TX_BEACON_RPT BIT(2) +#define BEACON_FUNCTION_ENABLE BIT(3) +#define BEACON_DISABLE_TSF_UPDATE BIT(4) + +#define REG_MBID_NUM 0x0552 +#define REG_DUAL_TSF_RST 0x0553 +#define DUAL_TSF_RESET_TSF0 BIT(0) +#define DUAL_TSF_RESET_TSF1 BIT(1) +#define DUAL_TSF_RESET_P2P BIT(4) +#define DUAL_TSF_TX_OK BIT(5) + +/* The same as REG_MBSSID_BCN_SPACE */ +#define REG_BCN_INTERVAL 0x0554 +#define REG_MBSSID_BCN_SPACE 0x0554 + +#define REG_DRIVER_EARLY_INT 0x0558 +#define DRIVER_EARLY_INT_TIME 5 + +#define REG_BEACON_DMA_TIME 0x0559 +#define BEACON_DMA_ATIME_INT_TIME 2 + +#define REG_ATIMWND 0x055a +#define REG_BCN_MAX_ERR 0x055d +#define REG_RXTSF_OFFSET_CCK 0x055e +#define REG_RXTSF_OFFSET_OFDM 0x055f +#define REG_TSFTR 0x0560 +#define REG_TSFTR1 0x0568 +#define REG_INIT_TSFTR 0x0564 +#define REG_ATIMWND_1 0x0570 +#define REG_PSTIMER 0x0580 +#define REG_TIMER0 0x0584 +#define REG_TIMER1 0x0588 +#define REG_ACM_HW_CTRL 0x05c0 +#define ACM_HW_CTRL_BK BIT(0) +#define ACM_HW_CTRL_BE BIT(1) +#define ACM_HW_CTRL_VI BIT(2) +#define ACM_HW_CTRL_VO BIT(3) +#define REG_ACM_RST_CTRL 0x05c1 +#define REG_ACMAVG 0x05c2 +#define REG_VO_ADMTIME 0x05c4 +#define REG_VI_ADMTIME 0x05c6 +#define REG_BE_ADMTIME 0x05c8 +#define REG_EDCA_RANDOM_GEN 0x05cc +#define REG_SCH_TXCMD 0x05d0 + +/* define REG_FW_TSF_SYNC_CNT 0x04a0 */ +#define REG_FW_RESET_TSF_CNT_1 0x05fc +#define REG_FW_RESET_TSF_CNT_0 0x05fd +#define REG_FW_BCN_DIS_CNT 0x05fe + +/* 0x0600 ~ 0x07FF WMAC Configuration */ +#define REG_APSD_CTRL 0x0600 +#define APSD_CTRL_OFF BIT(6) +#define APSD_CTRL_OFF_STATUS BIT(7) +#define REG_BW_OPMODE 0x0603 +#define BW_OPMODE_20MHZ BIT(2) +#define BW_OPMODE_5G BIT(1) +#define BW_OPMODE_11J BIT(0) + +#define REG_TCR 0x0604 + +/* Receive Configuration Register */ +#define REG_RCR 0x0608 +#define RCR_ACCEPT_AP BIT(0) /* Accept all unicast packet */ +#define RCR_ACCEPT_PHYS_MATCH BIT(1) /* Accept phys match packet */ +#define RCR_ACCEPT_MCAST BIT(2) +#define RCR_ACCEPT_BCAST BIT(3) +#define RCR_ACCEPT_ADDR3 BIT(4) /* Accept address 3 match + packet */ +#define RCR_ACCEPT_PM BIT(5) /* Accept power management + packet */ +#define RCR_CHECK_BSSID_MATCH BIT(6) /* Accept BSSID match packet */ +#define RCR_CHECK_BSSID_BEACON BIT(7) /* Accept BSSID match packet + (Rx beacon, probe rsp) */ +#define RCR_ACCEPT_CRC32 BIT(8) /* Accept CRC32 error packet */ +#define RCR_ACCEPT_ICV BIT(9) /* Accept ICV error packet */ +#define RCR_ACCEPT_DATA_FRAME BIT(11) +#define RCR_ACCEPT_CTRL_FRAME BIT(12) +#define RCR_ACCEPT_MGMT_FRAME BIT(13) +#define RCR_HTC_LOC_CTRL BIT(14) /* MFC<--HTC=1 MFC-->HTC=0 */ +#define RCR_MFBEN BIT(22) +#define RCR_LSIGEN BIT(23) +#define RCR_MULTI_BSSID_ENABLE BIT(24) /* Enable Multiple BssId */ +#define RCR_ACCEPT_BA_SSN BIT(27) /* Accept BA SSN */ +#define RCR_APPEND_PHYSTAT BIT(28) +#define RCR_APPEND_ICV BIT(29) +#define RCR_APPEND_MIC BIT(30) +#define RCR_APPEND_FCS BIT(31) /* WMAC append FCS after */ + +#define REG_RX_PKT_LIMIT 0x060c +#define REG_RX_DLK_TIME 0x060d +#define REG_RX_DRVINFO_SZ 0x060f + +#define REG_MACID 0x0610 +#define REG_BSSID 0x0618 +#define REG_MAR 0x0620 +#define REG_MBIDCAMCFG 0x0628 + +#define REG_USTIME_EDCA 0x0638 +#define REG_MAC_SPEC_SIFS 0x063a + +/* 20100719 Joseph: Hardware register definition change. (HW datasheet v54) */ + /* [15:8]SIFS_R2T_OFDM, [7:0]SIFS_R2T_CCK */ +#define REG_R2T_SIFS 0x063c + /* [15:8]SIFS_T2T_OFDM, [7:0]SIFS_T2T_CCK */ +#define REG_T2T_SIFS 0x063e +#define REG_ACKTO 0x0640 +#define REG_CTS2TO 0x0641 +#define REG_EIFS 0x0642 + +/* WMA, BA, CCX */ +#define REG_NAV_CTRL 0x0650 +/* In units of 128us */ +#define REG_NAV_UPPER 0x0652 +#define NAV_UPPER_UNIT 128 + +#define REG_BACAMCMD 0x0654 +#define REG_BACAMCONTENT 0x0658 +#define REG_LBDLY 0x0660 +#define REG_FWDLY 0x0661 +#define REG_RXERR_RPT 0x0664 +#define REG_WMAC_TRXPTCL_CTL 0x0668 + +/* Security */ +#define REG_CAM_CMD 0x0670 +#define CAM_CMD_POLLING BIT(31) +#define CAM_CMD_WRITE BIT(16) +#define CAM_CMD_KEY_SHIFT 3 +#define REG_CAM_WRITE 0x0674 +#define CAM_WRITE_VALID BIT(15) +#define REG_CAM_READ 0x0678 +#define REG_CAM_DEBUG 0x067c +#define REG_SECURITY_CFG 0x0680 +#define SEC_CFG_TX_USE_DEFKEY BIT(0) +#define SEC_CFG_RX_USE_DEFKEY BIT(1) +#define SEC_CFG_TX_SEC_ENABLE BIT(2) +#define SEC_CFG_RX_SEC_ENABLE BIT(3) +#define SEC_CFG_SKBYA2 BIT(4) +#define SEC_CFG_NO_SKMC BIT(5) +#define SEC_CFG_TXBC_USE_DEFKEY BIT(6) +#define SEC_CFG_RXBC_USE_DEFKEY BIT(7) + +/* Power */ +#define REG_WOW_CTRL 0x0690 +#define REG_PSSTATUS 0x0691 +#define REG_PS_RX_INFO 0x0692 +#define REG_LPNAV_CTRL 0x0694 +#define REG_WKFMCAM_CMD 0x0698 +#define REG_WKFMCAM_RWD 0x069c +#define REG_RXFLTMAP0 0x06a0 +#define REG_RXFLTMAP1 0x06a2 +#define REG_RXFLTMAP2 0x06a4 +#define REG_BCN_PSR_RPT 0x06a8 +#define REG_CALB32K_CTRL 0x06ac +#define REG_PKT_MON_CTRL 0x06b4 +#define REG_BT_COEX_TABLE 0x06c0 +#define REG_WMAC_RESP_TXINFO 0x06d8 + +#define REG_MACID1 0x0700 +#define REG_BSSID1 0x0708 + +#define REG_FPGA0_RF_MODE 0x0800 +#define FPGA_RF_MODE BIT(0) +#define FPGA_RF_MODE_JAPAN BIT(1) +#define FPGA_RF_MODE_CCK BIT(24) +#define FPGA_RF_MODE_OFDM BIT(25) + +#define REG_FPGA0_TX_INFO 0x0804 +#define REG_FPGA0_PSD_FUNC 0x0808 +#define REG_FPGA0_TX_GAIN 0x080c +#define REG_FPGA0_RF_TIMING1 0x0810 +#define REG_FPGA0_RF_TIMING2 0x0814 +#define REG_FPGA0_POWER_SAVE 0x0818 +#define FPGA0_PS_LOWER_CHANNEL BIT(26) +#define FPGA0_PS_UPPER_CHANNEL BIT(27) + +#define REG_FPGA0_XA_HSSI_PARM1 0x0820 /* RF 3 wire register */ +#define FPGA0_HSSI_PARM1_PI BIT(8) +#define REG_FPGA0_XA_HSSI_PARM2 0x0824 +#define REG_FPGA0_XB_HSSI_PARM1 0x0828 +#define REG_FPGA0_XB_HSSI_PARM2 0x082c +#define FPGA0_HSSI_3WIRE_DATA_LEN 0x800 +#define FPGA0_HSSI_3WIRE_ADDR_LEN 0x400 +#define FPGA0_HSSI_PARM2_ADDR_SHIFT 23 +#define FPGA0_HSSI_PARM2_ADDR_MASK 0x7f800000 /* 0xff << 23 */ +#define FPGA0_HSSI_PARM2_CCK_HIGH_PWR BIT(9) +#define FPGA0_HSSI_PARM2_EDGE_READ BIT(31) + +#define REG_TX_AGC_B_RATE18_06 0x0830 +#define REG_TX_AGC_B_RATE54_24 0x0834 +#define REG_TX_AGC_B_CCK1_55_MCS32 0x0838 +#define REG_TX_AGC_B_MCS03_MCS00 0x083c + +#define REG_FPGA0_XA_LSSI_PARM 0x0840 +#define REG_FPGA0_XB_LSSI_PARM 0x0844 +#define FPGA0_LSSI_PARM_ADDR_SHIFT 20 +#define FPGA0_LSSI_PARM_ADDR_MASK 0x0ff00000 +#define FPGA0_LSSI_PARM_DATA_MASK 0x000fffff + +#define REG_TX_AGC_B_MCS07_MCS04 0x0848 +#define REG_TX_AGC_B_MCS11_MCS08 0x084c + +#define REG_FPGA0_XCD_SWITCH_CTRL 0x085c + +#define REG_FPGA0_XA_RF_INT_OE 0x0860 /* RF Channel switch */ +#define REG_FPGA0_XB_RF_INT_OE 0x0864 +#define FPGA0_INT_OE_ANTENNA_AB_OPEN 0x000 +#define FPGA0_INT_OE_ANTENNA_A BIT(8) +#define FPGA0_INT_OE_ANTENNA_B BIT(9) +#define FPGA0_INT_OE_ANTENNA_MASK (FPGA0_INT_OE_ANTENNA_A | \ + FPGA0_INT_OE_ANTENNA_B) + +#define REG_TX_AGC_B_MCS15_MCS12 0x0868 +#define REG_TX_AGC_B_CCK11_A_CCK2_11 0x086c + +#define REG_FPGA0_XAB_RF_SW_CTRL 0x0870 +#define REG_FPGA0_XA_RF_SW_CTRL 0x0870 /* 16 bit */ +#define REG_FPGA0_XB_RF_SW_CTRL 0x0872 /* 16 bit */ +#define REG_FPGA0_XCD_RF_SW_CTRL 0x0874 +#define REG_FPGA0_XC_RF_SW_CTRL 0x0874 /* 16 bit */ +#define REG_FPGA0_XD_RF_SW_CTRL 0x0876 /* 16 bit */ +#define FPGA0_RF_3WIRE_DATA BIT(0) +#define FPGA0_RF_3WIRE_CLOC BIT(1) +#define FPGA0_RF_3WIRE_LOAD BIT(2) +#define FPGA0_RF_3WIRE_RW BIT(3) +#define FPGA0_RF_3WIRE_MASK 0xf +#define FPGA0_RF_RFENV BIT(4) +#define FPGA0_RF_TRSW BIT(5) /* Useless now */ +#define FPGA0_RF_TRSWB BIT(6) +#define FPGA0_RF_ANTSW BIT(8) +#define FPGA0_RF_ANTSWB BIT(9) +#define FPGA0_RF_PAPE BIT(10) +#define FPGA0_RF_PAPE5G BIT(11) +#define FPGA0_RF_BD_CTRL_SHIFT 16 + +#define REG_FPGA0_XAB_RF_PARM 0x0878 /* Antenna select path in ODM */ +#define REG_FPGA0_XA_RF_PARM 0x0878 /* 16 bit */ +#define REG_FPGA0_XB_RF_PARM 0x087a /* 16 bit */ +#define REG_FPGA0_XCD_RF_PARM 0x087c +#define REG_FPGA0_XC_RF_PARM 0x087c /* 16 bit */ +#define REG_FPGA0_XD_RF_PARM 0x087e /* 16 bit */ +#define FPGA0_RF_PARM_RFA_ENABLE BIT(1) +#define FPGA0_RF_PARM_RFB_ENABLE BIT(17) +#define FPGA0_RF_PARM_CLK_GATE BIT(31) + +#define REG_FPGA0_ANALOG1 0x0880 +#define REG_FPGA0_ANALOG2 0x0884 +#define FPGA0_ANALOG2_20MHZ BIT(10) +#define REG_FPGA0_ANALOG3 0x0888 +#define REG_FPGA0_ANALOG4 0x088c + +#define REG_FPGA0_XA_LSSI_READBACK 0x08a0 /* Tranceiver LSSI Readback */ +#define REG_FPGA0_XB_LSSI_READBACK 0x08a4 +#define REG_HSPI_XA_READBACK 0x08b8 /* Transceiver A HSPI read */ +#define REG_HSPI_XB_READBACK 0x08bc /* Transceiver B HSPI read */ + +#define REG_FPGA1_RF_MODE 0x0900 + +#define REG_FPGA1_TX_INFO 0x090c + +#define REG_CCK0_SYSTEM 0x0a00 +#define CCK0_SIDEBAND BIT(4) + +#define REG_CCK0_AFE_SETTING 0x0a04 + +#define REG_CONFIG_ANT_A 0x0b68 +#define REG_CONFIG_ANT_B 0x0b6c + +#define REG_OFDM0_TRX_PATH_ENABLE 0x0c04 +#define OFDM_RF_PATH_RX_MASK 0x0f +#define OFDM_RF_PATH_RX_A BIT(0) +#define OFDM_RF_PATH_RX_B BIT(1) +#define OFDM_RF_PATH_RX_C BIT(2) +#define OFDM_RF_PATH_RX_D BIT(3) +#define OFDM_RF_PATH_TX_MASK 0xf0 +#define OFDM_RF_PATH_TX_A BIT(4) +#define OFDM_RF_PATH_TX_B BIT(5) +#define OFDM_RF_PATH_TX_C BIT(6) +#define OFDM_RF_PATH_TX_D BIT(7) + +#define REG_OFDM0_TR_MUX_PAR 0x0c08 + +#define REG_OFDM0_XA_RX_IQ_IMBALANCE 0x0c14 +#define REG_OFDM0_XB_RX_IQ_IMBALANCE 0x0c1c + +#define REG_OFDM0_ENERGY_CCA_THRES 0x0c4c + +#define REG_OFDM0_XA_AGC_CORE1 0x0c50 +#define REG_OFDM0_XA_AGC_CORE2 0x0c54 +#define REG_OFDM0_XB_AGC_CORE1 0x0c58 +#define REG_OFDM0_XB_AGC_CORE2 0x0c5c +#define REG_OFDM0_XC_AGC_CORE1 0x0c60 +#define REG_OFDM0_XC_AGC_CORE2 0x0c64 +#define REG_OFDM0_XD_AGC_CORE1 0x0c68 +#define REG_OFDM0_XD_AGC_CORE2 0x0c6c +#define OFDM0_X_AGC_CORE1_IGI_MASK 0x0000007F + +#define REG_OFDM0_AGC_PARM1 0x0c70 + +#define REG_OFDM0_AGCR_SSI_TABLE 0x0c78 + +#define REG_OFDM0_XA_TX_IQ_IMBALANCE 0x0c80 +#define REG_OFDM0_XB_TX_IQ_IMBALANCE 0x0c88 +#define REG_OFDM0_XC_TX_IQ_IMBALANCE 0x0c90 +#define REG_OFDM0_XD_TX_IQ_IMBALANCE 0x0c98 + +#define REG_OFDM0_XC_TX_AFE 0x0c94 +#define REG_OFDM0_XD_TX_AFE 0x0c9c + +#define REG_OFDM0_RX_IQ_EXT_ANTA 0x0ca0 + +#define REG_OFDM1_LSTF 0x0d00 +#define OFDM_LSTF_PRIME_CH_LOW BIT(10) +#define OFDM_LSTF_PRIME_CH_HIGH BIT(11) +#define OFDM_LSTF_PRIME_CH_MASK (OFDM_LSTF_PRIME_CH_LOW | \ + OFDM_LSTF_PRIME_CH_HIGH) +#define OFDM_LSTF_CONTINUE_TX BIT(28) +#define OFDM_LSTF_SINGLE_CARRIER BIT(29) +#define OFDM_LSTF_SINGLE_TONE BIT(30) +#define OFDM_LSTF_MASK 0x70000000 + +#define REG_OFDM1_TRX_PATH_ENABLE 0x0d04 + +#define REG_TX_AGC_A_RATE18_06 0x0e00 +#define REG_TX_AGC_A_RATE54_24 0x0e04 +#define REG_TX_AGC_A_CCK1_MCS32 0x0e08 +#define REG_TX_AGC_A_MCS03_MCS00 0x0e10 +#define REG_TX_AGC_A_MCS07_MCS04 0x0e14 +#define REG_TX_AGC_A_MCS11_MCS08 0x0e18 +#define REG_TX_AGC_A_MCS15_MCS12 0x0e1c + +#define REG_FPGA0_IQK 0x0e28 + +#define REG_TX_IQK_TONE_A 0x0e30 +#define REG_RX_IQK_TONE_A 0x0e34 +#define REG_TX_IQK_PI_A 0x0e38 +#define REG_RX_IQK_PI_A 0x0e3c + +#define REG_TX_IQK 0x0e40 +#define REG_RX_IQK 0x0e44 +#define REG_IQK_AGC_PTS 0x0e48 +#define REG_IQK_AGC_RSP 0x0e4c +#define REG_TX_IQK_TONE_B 0x0e50 +#define REG_RX_IQK_TONE_B 0x0e54 +#define REG_TX_IQK_PI_B 0x0e58 +#define REG_RX_IQK_PI_B 0x0e5c +#define REG_IQK_AGC_CONT 0x0e60 + +#define REG_BLUETOOTH 0x0e6c +#define REG_RX_WAIT_CCA 0x0e70 +#define REG_TX_CCK_RFON 0x0e74 +#define REG_TX_CCK_BBON 0x0e78 +#define REG_TX_OFDM_RFON 0x0e7c +#define REG_TX_OFDM_BBON 0x0e80 +#define REG_TX_TO_RX 0x0e84 +#define REG_TX_TO_TX 0x0e88 +#define REG_RX_CCK 0x0e8c + +#define REG_TX_POWER_BEFORE_IQK_A 0x0e94 +#define REG_TX_POWER_AFTER_IQK_A 0x0e9c + +#define REG_RX_POWER_BEFORE_IQK_A 0x0ea0 +#define REG_RX_POWER_BEFORE_IQK_A_2 0x0ea4 +#define REG_RX_POWER_AFTER_IQK_A 0x0ea8 +#define REG_RX_POWER_AFTER_IQK_A_2 0x0eac + +#define REG_TX_POWER_BEFORE_IQK_B 0x0eb4 +#define REG_TX_POWER_AFTER_IQK_B 0x0ebc + +#define REG_RX_POWER_BEFORE_IQK_B 0x0ec0 +#define REG_RX_POWER_BEFORE_IQK_B_2 0x0ec4 +#define REG_RX_POWER_AFTER_IQK_B 0x0ec8 +#define REG_RX_POWER_AFTER_IQK_B_2 0x0ecc + +#define REG_RX_OFDM 0x0ed0 +#define REG_RX_WAIT_RIFS 0x0ed4 +#define REG_RX_TO_RX 0x0ed8 +#define REG_STANDBY 0x0edc +#define REG_SLEEP 0x0ee0 +#define REG_PMPD_ANAEN 0x0eec + +#define REG_FW_START_ADDRESS 0x1000 + +#define REG_USB_INFO 0xfe17 +#define REG_USB_HIMR 0xfe38 +#define USB_HIMR_TIMEOUT2 BIT(31) +#define USB_HIMR_TIMEOUT1 BIT(30) +#define USB_HIMR_PSTIMEOUT BIT(29) +#define USB_HIMR_GTINT4 BIT(28) +#define USB_HIMR_GTINT3 BIT(27) +#define USB_HIMR_TXBCNERR BIT(26) +#define USB_HIMR_TXBCNOK BIT(25) +#define USB_HIMR_TSF_BIT32_TOGGLE BIT(24) +#define USB_HIMR_BCNDMAINT3 BIT(23) +#define USB_HIMR_BCNDMAINT2 BIT(22) +#define USB_HIMR_BCNDMAINT1 BIT(21) +#define USB_HIMR_BCNDMAINT0 BIT(20) +#define USB_HIMR_BCNDOK3 BIT(19) +#define USB_HIMR_BCNDOK2 BIT(18) +#define USB_HIMR_BCNDOK1 BIT(17) +#define USB_HIMR_BCNDOK0 BIT(16) +#define USB_HIMR_HSISR_IND BIT(15) +#define USB_HIMR_BCNDMAINT_E BIT(14) +/* RSVD BIT(13) */ +#define USB_HIMR_CTW_END BIT(12) +/* RSVD BIT(11) */ +#define USB_HIMR_C2HCMD BIT(10) +#define USB_HIMR_CPWM2 BIT(9) +#define USB_HIMR_CPWM BIT(8) +#define USB_HIMR_HIGHDOK BIT(7) /* High Queue DMA OK + Interrupt */ +#define USB_HIMR_MGNTDOK BIT(6) /* Management Queue DMA OK + Interrupt */ +#define USB_HIMR_BKDOK BIT(5) /* AC_BK DMA OK Interrupt */ +#define USB_HIMR_BEDOK BIT(4) /* AC_BE DMA OK Interrupt */ +#define USB_HIMR_VIDOK BIT(3) /* AC_VI DMA OK Interrupt */ +#define USB_HIMR_VODOK BIT(2) /* AC_VO DMA Interrupt */ +#define USB_HIMR_RDU BIT(1) /* Receive Descriptor + Unavailable */ +#define USB_HIMR_ROK BIT(0) /* Receive DMA OK Interrupt */ + +#define REG_USB_SPECIAL_OPTION 0xfe55 +#define REG_USB_DMA_AGG_TO 0xfe5b +#define REG_USB_AGG_TO 0xfe5c +#define REG_USB_AGG_TH 0xfe5d + +#define REG_NORMAL_SIE_VID 0xfe60 /* 0xfe60 - 0xfe61 */ +#define REG_NORMAL_SIE_PID 0xfe62 /* 0xfe62 - 0xfe63 */ +#define REG_NORMAL_SIE_OPTIONAL 0xfe64 +#define REG_NORMAL_SIE_EP 0xfe65 /* 0xfe65 - 0xfe67 */ +#define REG_NORMAL_SIE_EP_TX 0xfe66 +#define NORMAL_SIE_EP_TX_HIGH_MASK 0x000f +#define NORMAL_SIE_EP_TX_NORMAL_MASK 0x00f0 +#define NORMAL_SIE_EP_TX_LOW_MASK 0x0f00 + +#define REG_NORMAL_SIE_PHY 0xfe68 /* 0xfe68 - 0xfe6b */ +#define REG_NORMAL_SIE_OPTIONAL2 0xfe6c +#define REG_NORMAL_SIE_GPS_EP 0xfe6d /* RTL8723 only */ +#define REG_NORMAL_SIE_MAC_ADDR 0xfe70 /* 0xfe70 - 0xfe75 */ +#define REG_NORMAL_SIE_STRING 0xfe80 /* 0xfe80 - 0xfedf */ + +/* RF6052 registers */ +#define RF6052_REG_AC 0x00 +#define RF6052_REG_IQADJ_G1 0x01 +#define RF6052_REG_IQADJ_G2 0x02 +#define RF6052_REG_BS_PA_APSET_G1_G4 0x03 +#define RF6052_REG_BS_PA_APSET_G5_G8 0x04 +#define RF6052_REG_POW_TRSW 0x05 +#define RF6052_REG_GAIN_RX 0x06 +#define RF6052_REG_GAIN_TX 0x07 +#define RF6052_REG_TXM_IDAC 0x08 +#define RF6052_REG_IPA_G 0x09 +#define RF6052_REG_TXBIAS_G 0x0a +#define RF6052_REG_TXPA_AG 0x0b +#define RF6052_REG_IPA_A 0x0c +#define RF6052_REG_TXBIAS_A 0x0d +#define RF6052_REG_BS_PA_APSET_G9_G11 0x0e +#define RF6052_REG_BS_IQGEN 0x0f +#define RF6052_REG_MODE1 0x10 +#define RF6052_REG_MODE2 0x11 +#define RF6052_REG_RX_AGC_HP 0x12 +#define RF6052_REG_TX_AGC 0x13 +#define RF6052_REG_BIAS 0x14 +#define RF6052_REG_IPA 0x15 +#define RF6052_REG_TXBIAS 0x16 +#define RF6052_REG_POW_ABILITY 0x17 +#define RF6052_REG_MODE_AG 0x18 /* RF channel and BW switch */ +#define MODE_AG_CHANNEL_MASK 0x3ff +#define MODE_AG_CHANNEL_20MHZ BIT(10) + +#define RF6052_REG_TOP 0x19 +#define RF6052_REG_RX_G1 0x1a +#define RF6052_REG_RX_G2 0x1b +#define RF6052_REG_RX_BB2 0x1c +#define RF6052_REG_RX_BB1 0x1d +#define RF6052_REG_RCK1 0x1e +#define RF6052_REG_RCK2 0x1f +#define RF6052_REG_TX_G1 0x20 +#define RF6052_REG_TX_G2 0x21 +#define RF6052_REG_TX_G3 0x22 +#define RF6052_REG_TX_BB1 0x23 +#define RF6052_REG_T_METER 0x24 +#define RF6052_REG_SYN_G1 0x25 /* RF TX Power control */ +#define RF6052_REG_SYN_G2 0x26 /* RF TX Power control */ +#define RF6052_REG_SYN_G3 0x27 /* RF TX Power control */ +#define RF6052_REG_SYN_G4 0x28 /* RF TX Power control */ +#define RF6052_REG_SYN_G5 0x29 /* RF TX Power control */ +#define RF6052_REG_SYN_G6 0x2a /* RF TX Power control */ +#define RF6052_REG_SYN_G7 0x2b /* RF TX Power control */ +#define RF6052_REG_SYN_G8 0x2c /* RF TX Power control */ + +#define RF6052_REG_RCK_OS 0x30 /* RF TX PA control */ + +#define RF6052_REG_TXPA_G1 0x31 /* RF TX PA control */ +#define RF6052_REG_TXPA_G2 0x32 /* RF TX PA control */ +#define RF6052_REG_TXPA_G3 0x33 /* RF TX PA control */ -- cgit v1.2.3 From fe56b9e6a8d957d6a20729d626027f800c17a2da Mon Sep 17 00:00:00 2001 From: Yuval Mintz Date: Mon, 26 Oct 2015 11:02:25 +0200 Subject: qed: Add module with basic common support The Qlogic Everest Driver is the backend module for the QL4xxx ethernet products by Qlogic. This module serves two main purposes: 1. It's responsible to contain all the common code that will be shared between the various drivers that would be used with said line of products. Flows such as chip initialization and de-initialization fall under this category. 2. It would abstract the protocol-specific HW & FW components, allowing the protocol drivers to have a clean APIs which is detached in its slowpath configuration from the actual HSI. This adds a very basic module without any protocol-specific bits. I.e., this adds a basic implementation that almost entirely falls under the first category. Signed-off-by: Yuval Mintz Signed-off-by: Ariel Elior Signed-off-by: David S. Miller --- MAINTAINERS | 10 + drivers/net/ethernet/qlogic/Kconfig | 6 + drivers/net/ethernet/qlogic/Makefile | 1 + drivers/net/ethernet/qlogic/qed/Makefile | 4 + drivers/net/ethernet/qlogic/qed/qed.h | 448 ++ drivers/net/ethernet/qlogic/qed/qed_cxt.c | 847 ++++ drivers/net/ethernet/qlogic/qed/qed_cxt.h | 139 + drivers/net/ethernet/qlogic/qed/qed_dev.c | 1277 +++++ drivers/net/ethernet/qlogic/qed/qed_dev_api.h | 222 + drivers/net/ethernet/qlogic/qed/qed_hsi.h | 4966 ++++++++++++++++++++ drivers/net/ethernet/qlogic/qed/qed_hw.c | 776 +++ drivers/net/ethernet/qlogic/qed/qed_hw.h | 263 ++ .../net/ethernet/qlogic/qed/qed_init_fw_funcs.c | 798 ++++ drivers/net/ethernet/qlogic/qed/qed_init_ops.c | 531 +++ drivers/net/ethernet/qlogic/qed/qed_init_ops.h | 110 + drivers/net/ethernet/qlogic/qed/qed_int.c | 802 ++++ drivers/net/ethernet/qlogic/qed/qed_int.h | 391 ++ drivers/net/ethernet/qlogic/qed/qed_main.c | 948 ++++ drivers/net/ethernet/qlogic/qed/qed_mcp.c | 549 +++ drivers/net/ethernet/qlogic/qed/qed_mcp.h | 232 + drivers/net/ethernet/qlogic/qed/qed_reg_addr.h | 366 ++ drivers/net/ethernet/qlogic/qed/qed_sp.h | 333 ++ drivers/net/ethernet/qlogic/qed/qed_sp_commands.c | 170 + drivers/net/ethernet/qlogic/qed/qed_spq.c | 831 ++++ include/linux/qed/common_hsi.h | 607 +++ include/linux/qed/qed_chain.h | 539 +++ include/linux/qed/qed_if.h | 498 ++ 27 files changed, 16664 insertions(+) create mode 100644 drivers/net/ethernet/qlogic/qed/Makefile create mode 100644 drivers/net/ethernet/qlogic/qed/qed.h create mode 100644 drivers/net/ethernet/qlogic/qed/qed_cxt.c create mode 100644 drivers/net/ethernet/qlogic/qed/qed_cxt.h create mode 100644 drivers/net/ethernet/qlogic/qed/qed_dev.c create mode 100644 drivers/net/ethernet/qlogic/qed/qed_dev_api.h create mode 100644 drivers/net/ethernet/qlogic/qed/qed_hsi.h create mode 100644 drivers/net/ethernet/qlogic/qed/qed_hw.c create mode 100644 drivers/net/ethernet/qlogic/qed/qed_hw.h create mode 100644 drivers/net/ethernet/qlogic/qed/qed_init_fw_funcs.c create mode 100644 drivers/net/ethernet/qlogic/qed/qed_init_ops.c create mode 100644 drivers/net/ethernet/qlogic/qed/qed_init_ops.h create mode 100644 drivers/net/ethernet/qlogic/qed/qed_int.c create mode 100644 drivers/net/ethernet/qlogic/qed/qed_int.h create mode 100644 drivers/net/ethernet/qlogic/qed/qed_main.c create mode 100644 drivers/net/ethernet/qlogic/qed/qed_mcp.c create mode 100644 drivers/net/ethernet/qlogic/qed/qed_mcp.h create mode 100644 drivers/net/ethernet/qlogic/qed/qed_reg_addr.h create mode 100644 drivers/net/ethernet/qlogic/qed/qed_sp.h create mode 100644 drivers/net/ethernet/qlogic/qed/qed_sp_commands.c create mode 100644 drivers/net/ethernet/qlogic/qed/qed_spq.c create mode 100644 include/linux/qed/common_hsi.h create mode 100644 include/linux/qed/qed_chain.h create mode 100644 include/linux/qed/qed_if.h (limited to 'MAINTAINERS') diff --git a/MAINTAINERS b/MAINTAINERS index fb8603e2a3f3..219c789aff27 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8540,6 +8540,16 @@ L: netdev@vger.kernel.org S: Supported F: drivers/net/ethernet/qlogic/qlge/ +QLOGIC QL4xxx ETHERNET DRIVER +M: Yuval Mintz +M: Ariel Elior +M: everest-linux-l2@qlogic.com +L: netdev@vger.kernel.org +S: Supported +F: drivers/net/ethernet/qlogic/qed/ +F: include/linux/qed/ +F: drivers/net/ethernet/qlogic/qede/ + QNX4 FILESYSTEM M: Anders Larsen W: http://www.alarsen.net/linux/qnx4fs/ diff --git a/drivers/net/ethernet/qlogic/Kconfig b/drivers/net/ethernet/qlogic/Kconfig index f1f0108c275d..58c3fb388f46 100644 --- a/drivers/net/ethernet/qlogic/Kconfig +++ b/drivers/net/ethernet/qlogic/Kconfig @@ -91,4 +91,10 @@ config NETXEN_NIC ---help--- This enables the support for NetXen's Gigabit Ethernet card. +config QED + tristate "QLogic QED 25/40/100Gb core driver" + depends on PCI + ---help--- + This enables the support for ... + endif # NET_VENDOR_QLOGIC diff --git a/drivers/net/ethernet/qlogic/Makefile b/drivers/net/ethernet/qlogic/Makefile index b2a283d9ae60..7600138268ee 100644 --- a/drivers/net/ethernet/qlogic/Makefile +++ b/drivers/net/ethernet/qlogic/Makefile @@ -6,3 +6,4 @@ obj-$(CONFIG_QLA3XXX) += qla3xxx.o obj-$(CONFIG_QLCNIC) += qlcnic/ obj-$(CONFIG_QLGE) += qlge/ obj-$(CONFIG_NETXEN_NIC) += netxen/ +obj-$(CONFIG_QED) += qed/ diff --git a/drivers/net/ethernet/qlogic/qed/Makefile b/drivers/net/ethernet/qlogic/qed/Makefile new file mode 100644 index 000000000000..6969b5c66929 --- /dev/null +++ b/drivers/net/ethernet/qlogic/qed/Makefile @@ -0,0 +1,4 @@ +obj-$(CONFIG_QED) := qed.o + +qed-y := qed_cxt.o qed_dev.o qed_hw.o qed_init_fw_funcs.o qed_init_ops.o \ + qed_int.o qed_main.o qed_mcp.o qed_sp_commands.o qed_spq.o diff --git a/drivers/net/ethernet/qlogic/qed/qed.h b/drivers/net/ethernet/qlogic/qed/qed.h new file mode 100644 index 000000000000..a63ef3120d78 --- /dev/null +++ b/drivers/net/ethernet/qlogic/qed/qed.h @@ -0,0 +1,448 @@ +/* QLogic qed NIC Driver + * Copyright (c) 2015 QLogic Corporation + * + * This software is available under the terms of the GNU General Public License + * (GPL) Version 2, available from the file COPYING in the main directory of + * this source tree. + */ + +#ifndef _QED_H +#define _QED_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "qed_hsi.h" + +#define DRV_MODULE_VERSION "8.4.0.0" + +#define MAX_HWFNS_PER_DEVICE (4) +#define NAME_SIZE 16 +#define VER_SIZE 16 + +/* cau states */ +enum qed_coalescing_mode { + QED_COAL_MODE_DISABLE, + QED_COAL_MODE_ENABLE +}; + +struct qed_eth_cb_ops; +struct qed_dev_info; + +/* helpers */ +static inline u32 qed_db_addr(u32 cid, u32 DEMS) +{ + u32 db_addr = FIELD_VALUE(DB_LEGACY_ADDR_DEMS, DEMS) | + FIELD_VALUE(DB_LEGACY_ADDR_ICID, cid); + + return db_addr; +} + +#define ALIGNED_TYPE_SIZE(type_name, p_hwfn) \ + ((sizeof(type_name) + (u32)(1 << (p_hwfn->cdev->cache_shift)) - 1) & \ + ~((1 << (p_hwfn->cdev->cache_shift)) - 1)) + +#define for_each_hwfn(cdev, i) for (i = 0; i < cdev->num_hwfns; i++) + +#define D_TRINE(val, cond1, cond2, true1, true2, def) \ + (val == (cond1) ? true1 : \ + (val == (cond2) ? true2 : def)) + +/* forward */ +struct qed_ptt_pool; +struct qed_spq; +struct qed_sb_info; +struct qed_sb_attn_info; +struct qed_cxt_mngr; +struct qed_sb_sp_info; +struct qed_mcp_info; + +struct qed_rt_data { + u32 init_val; + bool b_valid; +}; + +/* The PCI personality is not quite synonymous to protocol ID: + * 1. All personalities need CORE connections + * 2. The Ethernet personality may support also the RoCE protocol + */ +enum qed_pci_personality { + QED_PCI_ETH, + QED_PCI_DEFAULT /* default in shmem */ +}; + +/* All VFs are symmetric, all counters are PF + all VFs */ +struct qed_qm_iids { + u32 cids; + u32 vf_cids; + u32 tids; +}; + +enum QED_RESOURCES { + QED_SB, + QED_VPORT, + QED_PQ, + QED_RL, + QED_ILT, + QED_MAX_RESC, +}; + +struct qed_hw_info { + /* PCI personality */ + enum qed_pci_personality personality; + + /* Resource Allocation scheme results */ + u32 resc_start[QED_MAX_RESC]; + u32 resc_num[QED_MAX_RESC]; + +#define RESC_START(_p_hwfn, resc) ((_p_hwfn)->hw_info.resc_start[resc]) +#define RESC_NUM(_p_hwfn, resc) ((_p_hwfn)->hw_info.resc_num[resc]) +#define FEAT_NUM(_p_hwfn, resc) ((_p_hwfn)->hw_info.feat_num[resc]) + + u8 num_tc; + u8 offload_tc; + u8 non_offload_tc; + + u32 concrete_fid; + u16 opaque_fid; + u16 ovlan; + u32 part_num[4]; + + u32 vendor_id; + u32 device_id; + + unsigned char hw_mac_addr[ETH_ALEN]; + + struct qed_igu_info *p_igu_info; + + u32 port_mode; + u32 hw_mode; +}; + +struct qed_hw_cid_data { + u32 cid; + bool b_cid_allocated; + + /* Additional identifiers */ + u16 opaque_fid; + u8 vport_id; +}; + +/* maximun size of read/write commands (HW limit) */ +#define DMAE_MAX_RW_SIZE 0x2000 + +struct qed_dmae_info { + /* Mutex for synchronizing access to functions */ + struct mutex mutex; + + u8 channel; + + dma_addr_t completion_word_phys_addr; + + /* The memory location where the DMAE writes the completion + * value when an operation is finished on this context. + */ + u32 *p_completion_word; + + dma_addr_t intermediate_buffer_phys_addr; + + /* An intermediate buffer for DMAE operations that use virtual + * addresses - data is DMA'd to/from this buffer and then + * memcpy'd to/from the virtual address + */ + u32 *p_intermediate_buffer; + + dma_addr_t dmae_cmd_phys_addr; + struct dmae_cmd *p_dmae_cmd; +}; + +struct qed_qm_info { + struct init_qm_pq_params *qm_pq_params; + struct init_qm_vport_params *qm_vport_params; + struct init_qm_port_params *qm_port_params; + u16 start_pq; + u8 start_vport; + u8 pure_lb_pq; + u8 offload_pq; + u8 pure_ack_pq; + u8 vf_queues_offset; + u16 num_pqs; + u16 num_vf_pqs; + u8 num_vports; + u8 max_phys_tcs_per_port; + bool pf_rl_en; + bool pf_wfq_en; + bool vport_rl_en; + bool vport_wfq_en; + u8 pf_wfq; + u32 pf_rl; +}; + +struct qed_fw_data { + const u8 *modes_tree_buf; + union init_op *init_ops; + const u32 *arr_data; + u32 init_ops_size; +}; + +struct qed_simd_fp_handler { + void *token; + void (*func)(void *); +}; + +struct qed_hwfn { + struct qed_dev *cdev; + u8 my_id; /* ID inside the PF */ +#define IS_LEAD_HWFN(edev) (!((edev)->my_id)) + u8 rel_pf_id; /* Relative to engine*/ + u8 abs_pf_id; +#define QED_PATH_ID(_p_hwfn) ((_p_hwfn)->abs_pf_id & 1) + u8 port_id; + bool b_active; + + u32 dp_module; + u8 dp_level; + char name[NAME_SIZE]; + + bool first_on_engine; + bool hw_init_done; + + /* BAR access */ + void __iomem *regview; + void __iomem *doorbells; + u64 db_phys_addr; + unsigned long db_size; + + /* PTT pool */ + struct qed_ptt_pool *p_ptt_pool; + + /* HW info */ + struct qed_hw_info hw_info; + + /* rt_array (for init-tool) */ + struct qed_rt_data *rt_data; + + /* SPQ */ + struct qed_spq *p_spq; + + /* EQ */ + struct qed_eq *p_eq; + + /* Consolidate Q*/ + struct qed_consq *p_consq; + + /* Slow-Path definitions */ + struct tasklet_struct *sp_dpc; + bool b_sp_dpc_enabled; + + struct qed_ptt *p_main_ptt; + struct qed_ptt *p_dpc_ptt; + + struct qed_sb_sp_info *p_sp_sb; + struct qed_sb_attn_info *p_sb_attn; + + /* Protocol related */ + struct qed_pf_params pf_params; + + /* Array of sb_info of all status blocks */ + struct qed_sb_info *sbs_info[MAX_SB_PER_PF_MIMD]; + u16 num_sbs; + + struct qed_cxt_mngr *p_cxt_mngr; + + /* Flag indicating whether interrupts are enabled or not*/ + bool b_int_enabled; + + struct qed_mcp_info *mcp_info; + + struct qed_dmae_info dmae_info; + + /* QM init */ + struct qed_qm_info qm_info; + + /* Buffer for unzipping firmware data */ + void *unzip_buf; + + struct qed_simd_fp_handler simd_proto_handler[64]; + + struct z_stream_s *stream; +}; + +struct pci_params { + int pm_cap; + + unsigned long mem_start; + unsigned long mem_end; + unsigned int irq; + u8 pf_num; +}; + +struct qed_int_param { + u32 int_mode; + u8 num_vectors; + u8 min_msix_cnt; /* for minimal functionality */ +}; + +struct qed_int_params { + struct qed_int_param in; + struct qed_int_param out; + struct msix_entry *msix_table; + bool fp_initialized; + u8 fp_msix_base; + u8 fp_msix_cnt; +}; + +struct qed_dev { + u32 dp_module; + u8 dp_level; + char name[NAME_SIZE]; + + u8 type; +#define QED_DEV_TYPE_BB_A0 (0 << 0) +#define QED_DEV_TYPE_MASK (0x3) +#define QED_DEV_TYPE_SHIFT (0) + + u16 chip_num; +#define CHIP_NUM_MASK 0xffff +#define CHIP_NUM_SHIFT 16 + + u16 chip_rev; +#define CHIP_REV_MASK 0xf +#define CHIP_REV_SHIFT 12 + + u16 chip_metal; +#define CHIP_METAL_MASK 0xff +#define CHIP_METAL_SHIFT 4 + + u16 chip_bond_id; +#define CHIP_BOND_ID_MASK 0xf +#define CHIP_BOND_ID_SHIFT 0 + + u8 num_engines; + u8 num_ports_in_engines; + u8 num_funcs_in_port; + + u8 path_id; + enum mf_mode mf_mode; +#define IS_MF(_p_hwfn) (((_p_hwfn)->cdev)->mf_mode != SF) +#define IS_MF_SI(_p_hwfn) (((_p_hwfn)->cdev)->mf_mode == MF_NPAR) +#define IS_MF_SD(_p_hwfn) (((_p_hwfn)->cdev)->mf_mode == MF_OVLAN) + + int pcie_width; + int pcie_speed; + u8 ver_str[VER_SIZE]; + + /* Add MF related configuration */ + u8 mcp_rev; + u8 boot_mode; + + u8 wol; + + u32 int_mode; + enum qed_coalescing_mode int_coalescing_mode; + u8 rx_coalesce_usecs; + u8 tx_coalesce_usecs; + + /* Start Bar offset of first hwfn */ + void __iomem *regview; + void __iomem *doorbells; + u64 db_phys_addr; + unsigned long db_size; + + /* PCI */ + u8 cache_shift; + + /* Init */ + const struct iro *iro_arr; +#define IRO (p_hwfn->cdev->iro_arr) + + /* HW functions */ + u8 num_hwfns; + struct qed_hwfn hwfns[MAX_HWFNS_PER_DEVICE]; + + u32 drv_type; + + struct qed_eth_stats *reset_stats; + struct qed_fw_data *fw_data; + + u32 mcp_nvm_resp; + + /* Linux specific here */ + struct qede_dev *edev; + struct pci_dev *pdev; + int msg_enable; + + struct pci_params pci_params; + + struct qed_int_params int_params; + + u8 protocol; +#define IS_QED_ETH_IF(cdev) ((cdev)->protocol == QED_PROTOCOL_ETH) + + const struct firmware *firmware; +}; + +#define QED_GET_TYPE(dev) (((dev)->type & QED_DEV_TYPE_MASK) >> \ + QED_DEV_TYPE_SHIFT) +#define QED_IS_BB_A0(dev) (QED_GET_TYPE(dev) == QED_DEV_TYPE_BB_A0) +#define QED_IS_BB(dev) (QED_IS_BB_A0(dev)) + +#define NUM_OF_SBS(dev) MAX_SB_PER_PATH_BB +#define NUM_OF_ENG_PFS(dev) MAX_NUM_PFS_BB + +/** + * @brief qed_concrete_to_sw_fid - get the sw function id from + * the concrete value. + * + * @param concrete_fid + * + * @return inline u8 + */ +static inline u8 qed_concrete_to_sw_fid(struct qed_dev *cdev, + u32 concrete_fid) +{ + u8 pfid = GET_FIELD(concrete_fid, PXP_CONCRETE_FID_PFID); + + return pfid; +} + +#define PURE_LB_TC 8 + +#define QED_LEADING_HWFN(dev) (&dev->hwfns[0]) + +/* Other Linux specific common definitions */ +#define DP_NAME(cdev) ((cdev)->name) + +#define REG_ADDR(cdev, offset) (void __iomem *)((u8 __iomem *)\ + (cdev->regview) + \ + (offset)) + +#define REG_RD(cdev, offset) readl(REG_ADDR(cdev, offset)) +#define REG_WR(cdev, offset, val) writel((u32)val, REG_ADDR(cdev, offset)) +#define REG_WR16(cdev, offset, val) writew((u16)val, REG_ADDR(cdev, offset)) + +#define DOORBELL(cdev, db_addr, val) \ + writel((u32)val, (void __iomem *)((u8 __iomem *)\ + (cdev->doorbells) + (db_addr))) + +/* Prototypes */ +int qed_fill_dev_info(struct qed_dev *cdev, + struct qed_dev_info *dev_info); +u32 qed_unzip_data(struct qed_hwfn *p_hwfn, + u32 input_len, u8 *input_buf, + u32 max_size, u8 *unzip_buf); + +#define QED_ETH_INTERFACE_VERSION 300 + +#endif /* _QED_H */ diff --git a/drivers/net/ethernet/qlogic/qed/qed_cxt.c b/drivers/net/ethernet/qlogic/qed/qed_cxt.c new file mode 100644 index 000000000000..7ccdb46c6764 --- /dev/null +++ b/drivers/net/ethernet/qlogic/qed/qed_cxt.c @@ -0,0 +1,847 @@ +/* QLogic qed NIC Driver + * Copyright (c) 2015 QLogic Corporation + * + * This software is available under the terms of the GNU General Public License + * (GPL) Version 2, available from the file COPYING in the main directory of + * this source tree. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "qed.h" +#include "qed_cxt.h" +#include "qed_dev_api.h" +#include "qed_hsi.h" +#include "qed_hw.h" +#include "qed_init_ops.h" +#include "qed_reg_addr.h" + +/* Max number of connection types in HW (DQ/CDU etc.) */ +#define MAX_CONN_TYPES PROTOCOLID_COMMON +#define NUM_TASK_TYPES 2 +#define NUM_TASK_PF_SEGMENTS 4 + +/* QM constants */ +#define QM_PQ_ELEMENT_SIZE 4 /* in bytes */ + +/* Doorbell-Queue constants */ +#define DQ_RANGE_SHIFT 4 +#define DQ_RANGE_ALIGN BIT(DQ_RANGE_SHIFT) + +/* ILT constants */ +#define ILT_DEFAULT_HW_P_SIZE 3 +#define ILT_PAGE_IN_BYTES(hw_p_size) (1U << ((hw_p_size) + 12)) +#define ILT_CFG_REG(cli, reg) PSWRQ2_REG_ ## cli ## _ ## reg ## _RT_OFFSET + +/* ILT entry structure */ +#define ILT_ENTRY_PHY_ADDR_MASK 0x000FFFFFFFFFFFULL +#define ILT_ENTRY_PHY_ADDR_SHIFT 0 +#define ILT_ENTRY_VALID_MASK 0x1ULL +#define ILT_ENTRY_VALID_SHIFT 52 +#define ILT_ENTRY_IN_REGS 2 +#define ILT_REG_SIZE_IN_BYTES 4 + +/* connection context union */ +union conn_context { + struct core_conn_context core_ctx; + struct eth_conn_context eth_ctx; +}; + +#define CONN_CXT_SIZE(p_hwfn) \ + ALIGNED_TYPE_SIZE(union conn_context, p_hwfn) + +/* PF per protocl configuration object */ +struct qed_conn_type_cfg { + u32 cid_count; + u32 cid_start; +}; + +/* ILT Client configuration, Per connection type (protocol) resources. */ +#define ILT_CLI_PF_BLOCKS (1 + NUM_TASK_PF_SEGMENTS * 2) +#define CDUC_BLK (0) + +enum ilt_clients { + ILT_CLI_CDUC, + ILT_CLI_QM, + ILT_CLI_MAX +}; + +struct ilt_cfg_pair { + u32 reg; + u32 val; +}; + +struct qed_ilt_cli_blk { + u32 total_size; /* 0 means not active */ + u32 real_size_in_page; + u32 start_line; +}; + +struct qed_ilt_client_cfg { + bool active; + + /* ILT boundaries */ + struct ilt_cfg_pair first; + struct ilt_cfg_pair last; + struct ilt_cfg_pair p_size; + + /* ILT client blocks for PF */ + struct qed_ilt_cli_blk pf_blks[ILT_CLI_PF_BLOCKS]; + u32 pf_total_lines; +}; + +/* Per Path - + * ILT shadow table + * Protocol acquired CID lists + * PF start line in ILT + */ +struct qed_dma_mem { + dma_addr_t p_phys; + void *p_virt; + size_t size; +}; + +struct qed_cid_acquired_map { + u32 start_cid; + u32 max_count; + unsigned long *cid_map; +}; + +struct qed_cxt_mngr { + /* Per protocl configuration */ + struct qed_conn_type_cfg conn_cfg[MAX_CONN_TYPES]; + + /* computed ILT structure */ + struct qed_ilt_client_cfg clients[ILT_CLI_MAX]; + + /* Acquired CIDs */ + struct qed_cid_acquired_map acquired[MAX_CONN_TYPES]; + + /* ILT shadow table */ + struct qed_dma_mem *ilt_shadow; + u32 pf_start_line; +}; + +static u32 qed_cxt_cdu_iids(struct qed_cxt_mngr *p_mngr) +{ + u32 type, pf_cids = 0; + + for (type = 0; type < MAX_CONN_TYPES; type++) + pf_cids += p_mngr->conn_cfg[type].cid_count; + + return pf_cids; +} + +static void qed_cxt_qm_iids(struct qed_hwfn *p_hwfn, + struct qed_qm_iids *iids) +{ + struct qed_cxt_mngr *p_mngr = p_hwfn->p_cxt_mngr; + int type; + + for (type = 0; type < MAX_CONN_TYPES; type++) + iids->cids += p_mngr->conn_cfg[type].cid_count; + + DP_VERBOSE(p_hwfn, QED_MSG_ILT, "iids: CIDS %08x\n", iids->cids); +} + +/* set the iids count per protocol */ +static void qed_cxt_set_proto_cid_count(struct qed_hwfn *p_hwfn, + enum protocol_type type, + u32 cid_count) +{ + struct qed_cxt_mngr *p_mgr = p_hwfn->p_cxt_mngr; + struct qed_conn_type_cfg *p_conn = &p_mgr->conn_cfg[type]; + + p_conn->cid_count = roundup(cid_count, DQ_RANGE_ALIGN); +} + +static void qed_ilt_cli_blk_fill(struct qed_ilt_client_cfg *p_cli, + struct qed_ilt_cli_blk *p_blk, + u32 start_line, u32 total_size, + u32 elem_size) +{ + u32 ilt_size = ILT_PAGE_IN_BYTES(p_cli->p_size.val); + + /* verify thatits called only once for each block */ + if (p_blk->total_size) + return; + + p_blk->total_size = total_size; + p_blk->real_size_in_page = 0; + if (elem_size) + p_blk->real_size_in_page = (ilt_size / elem_size) * elem_size; + p_blk->start_line = start_line; +} + +static void qed_ilt_cli_adv_line(struct qed_hwfn *p_hwfn, + struct qed_ilt_client_cfg *p_cli, + struct qed_ilt_cli_blk *p_blk, + u32 *p_line, enum ilt_clients client_id) +{ + if (!p_blk->total_size) + return; + + if (!p_cli->active) + p_cli->first.val = *p_line; + + p_cli->active = true; + *p_line += DIV_ROUND_UP(p_blk->total_size, + p_blk->real_size_in_page); + p_cli->last.val = *p_line - 1; + + DP_VERBOSE(p_hwfn, QED_MSG_ILT, + "ILT[Client %d] - Lines: [%08x - %08x]. Block - Size %08x [Real %08x] Start line %d\n", + client_id, p_cli->first.val, + p_cli->last.val, p_blk->total_size, + p_blk->real_size_in_page, p_blk->start_line); +} + +int qed_cxt_cfg_ilt_compute(struct qed_hwfn *p_hwfn) +{ + struct qed_cxt_mngr *p_mngr = p_hwfn->p_cxt_mngr; + struct qed_ilt_client_cfg *p_cli; + struct qed_ilt_cli_blk *p_blk; + u32 curr_line, total, pf_cids; + struct qed_qm_iids qm_iids; + + memset(&qm_iids, 0, sizeof(qm_iids)); + + p_mngr->pf_start_line = RESC_START(p_hwfn, QED_ILT); + + DP_VERBOSE(p_hwfn, QED_MSG_ILT, + "hwfn [%d] - Set context manager starting line to be 0x%08x\n", + p_hwfn->my_id, p_hwfn->p_cxt_mngr->pf_start_line); + + /* CDUC */ + p_cli = &p_mngr->clients[ILT_CLI_CDUC]; + curr_line = p_mngr->pf_start_line; + p_cli->pf_total_lines = 0; + + /* get the counters for the CDUC and QM clients */ + pf_cids = qed_cxt_cdu_iids(p_mngr); + + p_blk = &p_cli->pf_blks[CDUC_BLK]; + + total = pf_cids * CONN_CXT_SIZE(p_hwfn); + + qed_ilt_cli_blk_fill(p_cli, p_blk, curr_line, + total, CONN_CXT_SIZE(p_hwfn)); + + qed_ilt_cli_adv_line(p_hwfn, p_cli, p_blk, &curr_line, ILT_CLI_CDUC); + p_cli->pf_total_lines = curr_line - p_blk->start_line; + + /* QM */ + p_cli = &p_mngr->clients[ILT_CLI_QM]; + p_blk = &p_cli->pf_blks[0]; + + qed_cxt_qm_iids(p_hwfn, &qm_iids); + total = qed_qm_pf_mem_size(p_hwfn->rel_pf_id, qm_iids.cids, 0, 0, + p_hwfn->qm_info.num_pqs, 0); + + DP_VERBOSE(p_hwfn, QED_MSG_ILT, + "QM ILT Info, (cids=%d, num_pqs=%d, memory_size=%d)\n", + qm_iids.cids, p_hwfn->qm_info.num_pqs, total); + + qed_ilt_cli_blk_fill(p_cli, p_blk, + curr_line, total * 0x1000, + QM_PQ_ELEMENT_SIZE); + + qed_ilt_cli_adv_line(p_hwfn, p_cli, p_blk, &curr_line, ILT_CLI_QM); + p_cli->pf_total_lines = curr_line - p_blk->start_line; + + if (curr_line - p_hwfn->p_cxt_mngr->pf_start_line > + RESC_NUM(p_hwfn, QED_ILT)) { + DP_ERR(p_hwfn, "too many ilt lines...#lines=%d\n", + curr_line - p_hwfn->p_cxt_mngr->pf_start_line); + return -EINVAL; + } + + return 0; +} + +#define for_each_ilt_valid_client(pos, clients) \ + for (pos = 0; pos < ILT_CLI_MAX; pos++) + +/* Total number of ILT lines used by this PF */ +static u32 qed_cxt_ilt_shadow_size(struct qed_ilt_client_cfg *ilt_clients) +{ + u32 size = 0; + u32 i; + + for_each_ilt_valid_client(i, ilt_clients) { + if (!ilt_clients[i].active) + continue; + size += (ilt_clients[i].last.val - + ilt_clients[i].first.val + 1); + } + + return size; +} + +static void qed_ilt_shadow_free(struct qed_hwfn *p_hwfn) +{ + struct qed_ilt_client_cfg *p_cli = p_hwfn->p_cxt_mngr->clients; + struct qed_cxt_mngr *p_mngr = p_hwfn->p_cxt_mngr; + u32 ilt_size, i; + + ilt_size = qed_cxt_ilt_shadow_size(p_cli); + + for (i = 0; p_mngr->ilt_shadow && i < ilt_size; i++) { + struct qed_dma_mem *p_dma = &p_mngr->ilt_shadow[i]; + + if (p_dma->p_virt) + dma_free_coherent(&p_hwfn->cdev->pdev->dev, + p_dma->size, p_dma->p_virt, + p_dma->p_phys); + p_dma->p_virt = NULL; + } + kfree(p_mngr->ilt_shadow); +} + +static int qed_ilt_blk_alloc(struct qed_hwfn *p_hwfn, + struct qed_ilt_cli_blk *p_blk, + enum ilt_clients ilt_client, + u32 start_line_offset) +{ + struct qed_dma_mem *ilt_shadow = p_hwfn->p_cxt_mngr->ilt_shadow; + u32 lines, line, sz_left; + + if (!p_blk->total_size) + return 0; + + sz_left = p_blk->total_size; + lines = DIV_ROUND_UP(sz_left, p_blk->real_size_in_page); + line = p_blk->start_line + start_line_offset - + p_hwfn->p_cxt_mngr->pf_start_line; + + for (; lines; lines--) { + dma_addr_t p_phys; + void *p_virt; + u32 size; + + size = min_t(u32, sz_left, + p_blk->real_size_in_page); + p_virt = dma_alloc_coherent(&p_hwfn->cdev->pdev->dev, + size, + &p_phys, + GFP_KERNEL); + if (!p_virt) + return -ENOMEM; + memset(p_virt, 0, size); + + ilt_shadow[line].p_phys = p_phys; + ilt_shadow[line].p_virt = p_virt; + ilt_shadow[line].size = size; + + DP_VERBOSE(p_hwfn, QED_MSG_ILT, + "ILT shadow: Line [%d] Physical 0x%llx Virtual %p Size %d\n", + line, (u64)p_phys, p_virt, size); + + sz_left -= size; + line++; + } + + return 0; +} + +static int qed_ilt_shadow_alloc(struct qed_hwfn *p_hwfn) +{ + struct qed_cxt_mngr *p_mngr = p_hwfn->p_cxt_mngr; + struct qed_ilt_client_cfg *clients = p_mngr->clients; + struct qed_ilt_cli_blk *p_blk; + u32 size, i, j; + int rc; + + size = qed_cxt_ilt_shadow_size(clients); + p_mngr->ilt_shadow = kcalloc(size, sizeof(struct qed_dma_mem), + GFP_KERNEL); + if (!p_mngr->ilt_shadow) { + DP_NOTICE(p_hwfn, "Failed to allocate ilt shadow table\n"); + rc = -ENOMEM; + goto ilt_shadow_fail; + } + + DP_VERBOSE(p_hwfn, QED_MSG_ILT, + "Allocated 0x%x bytes for ilt shadow\n", + (u32)(size * sizeof(struct qed_dma_mem))); + + for_each_ilt_valid_client(i, clients) { + if (!clients[i].active) + continue; + for (j = 0; j < ILT_CLI_PF_BLOCKS; j++) { + p_blk = &clients[i].pf_blks[j]; + rc = qed_ilt_blk_alloc(p_hwfn, p_blk, i, 0); + if (rc != 0) + goto ilt_shadow_fail; + } + } + + return 0; + +ilt_shadow_fail: + qed_ilt_shadow_free(p_hwfn); + return rc; +} + +static void qed_cid_map_free(struct qed_hwfn *p_hwfn) +{ + struct qed_cxt_mngr *p_mngr = p_hwfn->p_cxt_mngr; + u32 type; + + for (type = 0; type < MAX_CONN_TYPES; type++) { + kfree(p_mngr->acquired[type].cid_map); + p_mngr->acquired[type].max_count = 0; + p_mngr->acquired[type].start_cid = 0; + } +} + +static int qed_cid_map_alloc(struct qed_hwfn *p_hwfn) +{ + struct qed_cxt_mngr *p_mngr = p_hwfn->p_cxt_mngr; + u32 start_cid = 0; + u32 type; + + for (type = 0; type < MAX_CONN_TYPES; type++) { + u32 cid_cnt = p_hwfn->p_cxt_mngr->conn_cfg[type].cid_count; + u32 size; + + if (cid_cnt == 0) + continue; + + size = DIV_ROUND_UP(cid_cnt, + sizeof(unsigned long) * BITS_PER_BYTE) * + sizeof(unsigned long); + p_mngr->acquired[type].cid_map = kzalloc(size, GFP_KERNEL); + if (!p_mngr->acquired[type].cid_map) + goto cid_map_fail; + + p_mngr->acquired[type].max_count = cid_cnt; + p_mngr->acquired[type].start_cid = start_cid; + + p_hwfn->p_cxt_mngr->conn_cfg[type].cid_start = start_cid; + + DP_VERBOSE(p_hwfn, QED_MSG_CXT, + "Type %08x start: %08x count %08x\n", + type, p_mngr->acquired[type].start_cid, + p_mngr->acquired[type].max_count); + start_cid += cid_cnt; + } + + return 0; + +cid_map_fail: + qed_cid_map_free(p_hwfn); + return -ENOMEM; +} + +int qed_cxt_mngr_alloc(struct qed_hwfn *p_hwfn) +{ + struct qed_cxt_mngr *p_mngr; + u32 i; + + p_mngr = kzalloc(sizeof(*p_mngr), GFP_ATOMIC); + if (!p_mngr) { + DP_NOTICE(p_hwfn, "Failed to allocate `struct qed_cxt_mngr'\n"); + return -ENOMEM; + } + + /* Initialize ILT client registers */ + p_mngr->clients[ILT_CLI_CDUC].first.reg = ILT_CFG_REG(CDUC, FIRST_ILT); + p_mngr->clients[ILT_CLI_CDUC].last.reg = ILT_CFG_REG(CDUC, LAST_ILT); + p_mngr->clients[ILT_CLI_CDUC].p_size.reg = ILT_CFG_REG(CDUC, P_SIZE); + + p_mngr->clients[ILT_CLI_QM].first.reg = ILT_CFG_REG(QM, FIRST_ILT); + p_mngr->clients[ILT_CLI_QM].last.reg = ILT_CFG_REG(QM, LAST_ILT); + p_mngr->clients[ILT_CLI_QM].p_size.reg = ILT_CFG_REG(QM, P_SIZE); + + /* default ILT page size for all clients is 32K */ + for (i = 0; i < ILT_CLI_MAX; i++) + p_mngr->clients[i].p_size.val = ILT_DEFAULT_HW_P_SIZE; + + /* Set the cxt mangr pointer priori to further allocations */ + p_hwfn->p_cxt_mngr = p_mngr; + + return 0; +} + +int qed_cxt_tables_alloc(struct qed_hwfn *p_hwfn) +{ + int rc; + + /* Allocate the ILT shadow table */ + rc = qed_ilt_shadow_alloc(p_hwfn); + if (rc) { + DP_NOTICE(p_hwfn, "Failed to allocate ilt memory\n"); + goto tables_alloc_fail; + } + + /* Allocate and initialize the acquired cids bitmaps */ + rc = qed_cid_map_alloc(p_hwfn); + if (rc) { + DP_NOTICE(p_hwfn, "Failed to allocate cid maps\n"); + goto tables_alloc_fail; + } + + return 0; + +tables_alloc_fail: + qed_cxt_mngr_free(p_hwfn); + return rc; +} + +void qed_cxt_mngr_free(struct qed_hwfn *p_hwfn) +{ + if (!p_hwfn->p_cxt_mngr) + return; + + qed_cid_map_free(p_hwfn); + qed_ilt_shadow_free(p_hwfn); + kfree(p_hwfn->p_cxt_mngr); + + p_hwfn->p_cxt_mngr = NULL; +} + +void qed_cxt_mngr_setup(struct qed_hwfn *p_hwfn) +{ + struct qed_cxt_mngr *p_mngr = p_hwfn->p_cxt_mngr; + int type; + + /* Reset acquired cids */ + for (type = 0; type < MAX_CONN_TYPES; type++) { + u32 cid_cnt = p_hwfn->p_cxt_mngr->conn_cfg[type].cid_count; + + if (cid_cnt == 0) + continue; + + memset(p_mngr->acquired[type].cid_map, 0, + DIV_ROUND_UP(cid_cnt, + sizeof(unsigned long) * BITS_PER_BYTE) * + sizeof(unsigned long)); + } +} + +/* CDU Common */ +#define CDUC_CXT_SIZE_SHIFT \ + CDU_REG_CID_ADDR_PARAMS_CONTEXT_SIZE_SHIFT + +#define CDUC_CXT_SIZE_MASK \ + (CDU_REG_CID_ADDR_PARAMS_CONTEXT_SIZE >> CDUC_CXT_SIZE_SHIFT) + +#define CDUC_BLOCK_WASTE_SHIFT \ + CDU_REG_CID_ADDR_PARAMS_BLOCK_WASTE_SHIFT + +#define CDUC_BLOCK_WASTE_MASK \ + (CDU_REG_CID_ADDR_PARAMS_BLOCK_WASTE >> CDUC_BLOCK_WASTE_SHIFT) + +#define CDUC_NCIB_SHIFT \ + CDU_REG_CID_ADDR_PARAMS_NCIB_SHIFT + +#define CDUC_NCIB_MASK \ + (CDU_REG_CID_ADDR_PARAMS_NCIB >> CDUC_NCIB_SHIFT) + +static void qed_cdu_init_common(struct qed_hwfn *p_hwfn) +{ + u32 page_sz, elems_per_page, block_waste, cxt_size, cdu_params = 0; + + /* CDUC - connection configuration */ + page_sz = p_hwfn->p_cxt_mngr->clients[ILT_CLI_CDUC].p_size.val; + cxt_size = CONN_CXT_SIZE(p_hwfn); + elems_per_page = ILT_PAGE_IN_BYTES(page_sz) / cxt_size; + block_waste = ILT_PAGE_IN_BYTES(page_sz) - elems_per_page * cxt_size; + + SET_FIELD(cdu_params, CDUC_CXT_SIZE, cxt_size); + SET_FIELD(cdu_params, CDUC_BLOCK_WASTE, block_waste); + SET_FIELD(cdu_params, CDUC_NCIB, elems_per_page); + STORE_RT_REG(p_hwfn, CDU_REG_CID_ADDR_PARAMS_RT_OFFSET, cdu_params); +} + +void qed_qm_init_pf(struct qed_hwfn *p_hwfn) +{ + struct qed_qm_pf_rt_init_params params; + struct qed_qm_info *qm_info = &p_hwfn->qm_info; + struct qed_qm_iids iids; + + memset(&iids, 0, sizeof(iids)); + qed_cxt_qm_iids(p_hwfn, &iids); + + memset(¶ms, 0, sizeof(params)); + params.port_id = p_hwfn->port_id; + params.pf_id = p_hwfn->rel_pf_id; + params.max_phys_tcs_per_port = qm_info->max_phys_tcs_per_port; + params.is_first_pf = p_hwfn->first_on_engine; + params.num_pf_cids = iids.cids; + params.start_pq = qm_info->start_pq; + params.num_pf_pqs = qm_info->num_pqs; + params.start_vport = qm_info->num_vports; + params.pf_wfq = qm_info->pf_wfq; + params.pf_rl = qm_info->pf_rl; + params.pq_params = qm_info->qm_pq_params; + params.vport_params = qm_info->qm_vport_params; + + qed_qm_pf_rt_init(p_hwfn, p_hwfn->p_main_ptt, ¶ms); +} + +/* CM PF */ +static int qed_cm_init_pf(struct qed_hwfn *p_hwfn) +{ + union qed_qm_pq_params pq_params; + u16 pq; + + /* XCM pure-LB queue */ + memset(&pq_params, 0, sizeof(pq_params)); + pq_params.core.tc = LB_TC; + pq = qed_get_qm_pq(p_hwfn, PROTOCOLID_CORE, &pq_params); + STORE_RT_REG(p_hwfn, XCM_REG_CON_PHY_Q3_RT_OFFSET, pq); + + return 0; +} + +/* DQ PF */ +static void qed_dq_init_pf(struct qed_hwfn *p_hwfn) +{ + struct qed_cxt_mngr *p_mngr = p_hwfn->p_cxt_mngr; + u32 dq_pf_max_cid = 0; + + dq_pf_max_cid += (p_mngr->conn_cfg[0].cid_count >> DQ_RANGE_SHIFT); + STORE_RT_REG(p_hwfn, DORQ_REG_PF_MAX_ICID_0_RT_OFFSET, dq_pf_max_cid); + + dq_pf_max_cid += (p_mngr->conn_cfg[1].cid_count >> DQ_RANGE_SHIFT); + STORE_RT_REG(p_hwfn, DORQ_REG_PF_MAX_ICID_1_RT_OFFSET, dq_pf_max_cid); + + dq_pf_max_cid += (p_mngr->conn_cfg[2].cid_count >> DQ_RANGE_SHIFT); + STORE_RT_REG(p_hwfn, DORQ_REG_PF_MAX_ICID_2_RT_OFFSET, dq_pf_max_cid); + + dq_pf_max_cid += (p_mngr->conn_cfg[3].cid_count >> DQ_RANGE_SHIFT); + STORE_RT_REG(p_hwfn, DORQ_REG_PF_MAX_ICID_3_RT_OFFSET, dq_pf_max_cid); + + dq_pf_max_cid += (p_mngr->conn_cfg[4].cid_count >> DQ_RANGE_SHIFT); + STORE_RT_REG(p_hwfn, DORQ_REG_PF_MAX_ICID_4_RT_OFFSET, dq_pf_max_cid); + + /* 5 - PF */ + dq_pf_max_cid += (p_mngr->conn_cfg[5].cid_count >> DQ_RANGE_SHIFT); + STORE_RT_REG(p_hwfn, DORQ_REG_PF_MAX_ICID_5_RT_OFFSET, dq_pf_max_cid); +} + +static void qed_ilt_bounds_init(struct qed_hwfn *p_hwfn) +{ + struct qed_ilt_client_cfg *ilt_clients; + int i; + + ilt_clients = p_hwfn->p_cxt_mngr->clients; + for_each_ilt_valid_client(i, ilt_clients) { + if (!ilt_clients[i].active) + continue; + STORE_RT_REG(p_hwfn, + ilt_clients[i].first.reg, + ilt_clients[i].first.val); + STORE_RT_REG(p_hwfn, + ilt_clients[i].last.reg, + ilt_clients[i].last.val); + STORE_RT_REG(p_hwfn, + ilt_clients[i].p_size.reg, + ilt_clients[i].p_size.val); + } +} + +/* ILT (PSWRQ2) PF */ +static void qed_ilt_init_pf(struct qed_hwfn *p_hwfn) +{ + struct qed_ilt_client_cfg *clients; + struct qed_cxt_mngr *p_mngr; + struct qed_dma_mem *p_shdw; + u32 line, rt_offst, i; + + qed_ilt_bounds_init(p_hwfn); + + p_mngr = p_hwfn->p_cxt_mngr; + p_shdw = p_mngr->ilt_shadow; + clients = p_hwfn->p_cxt_mngr->clients; + + for_each_ilt_valid_client(i, clients) { + if (!clients[i].active) + continue; + + /** Client's 1st val and RT array are absolute, ILT shadows' + * lines are relative. + */ + line = clients[i].first.val - p_mngr->pf_start_line; + rt_offst = PSWRQ2_REG_ILT_MEMORY_RT_OFFSET + + clients[i].first.val * ILT_ENTRY_IN_REGS; + + for (; line <= clients[i].last.val - p_mngr->pf_start_line; + line++, rt_offst += ILT_ENTRY_IN_REGS) { + u64 ilt_hw_entry = 0; + + /** p_virt could be NULL incase of dynamic + * allocation + */ + if (p_shdw[line].p_virt) { + SET_FIELD(ilt_hw_entry, ILT_ENTRY_VALID, 1ULL); + SET_FIELD(ilt_hw_entry, ILT_ENTRY_PHY_ADDR, + (p_shdw[line].p_phys >> 12)); + + DP_VERBOSE(p_hwfn, QED_MSG_ILT, + "Setting RT[0x%08x] from ILT[0x%08x] [Client is %d] to Physical addr: 0x%llx\n", + rt_offst, line, i, + (u64)(p_shdw[line].p_phys >> 12)); + } + + STORE_RT_REG_AGG(p_hwfn, rt_offst, ilt_hw_entry); + } + } +} + +void qed_cxt_hw_init_common(struct qed_hwfn *p_hwfn) +{ + qed_cdu_init_common(p_hwfn); +} + +void qed_cxt_hw_init_pf(struct qed_hwfn *p_hwfn) +{ + qed_qm_init_pf(p_hwfn); + qed_cm_init_pf(p_hwfn); + qed_dq_init_pf(p_hwfn); + qed_ilt_init_pf(p_hwfn); +} + +int qed_cxt_acquire_cid(struct qed_hwfn *p_hwfn, + enum protocol_type type, + u32 *p_cid) +{ + struct qed_cxt_mngr *p_mngr = p_hwfn->p_cxt_mngr; + u32 rel_cid; + + if (type >= MAX_CONN_TYPES || !p_mngr->acquired[type].cid_map) { + DP_NOTICE(p_hwfn, "Invalid protocol type %d", type); + return -EINVAL; + } + + rel_cid = find_first_zero_bit(p_mngr->acquired[type].cid_map, + p_mngr->acquired[type].max_count); + + if (rel_cid >= p_mngr->acquired[type].max_count) { + DP_NOTICE(p_hwfn, "no CID available for protocol %d\n", + type); + return -EINVAL; + } + + __set_bit(rel_cid, p_mngr->acquired[type].cid_map); + + *p_cid = rel_cid + p_mngr->acquired[type].start_cid; + + return 0; +} + +static bool qed_cxt_test_cid_acquired(struct qed_hwfn *p_hwfn, + u32 cid, + enum protocol_type *p_type) +{ + struct qed_cxt_mngr *p_mngr = p_hwfn->p_cxt_mngr; + struct qed_cid_acquired_map *p_map; + enum protocol_type p; + u32 rel_cid; + + /* Iterate over protocols and find matching cid range */ + for (p = 0; p < MAX_CONN_TYPES; p++) { + p_map = &p_mngr->acquired[p]; + + if (!p_map->cid_map) + continue; + if (cid >= p_map->start_cid && + cid < p_map->start_cid + p_map->max_count) + break; + } + *p_type = p; + + if (p == MAX_CONN_TYPES) { + DP_NOTICE(p_hwfn, "Invalid CID %d", cid); + return false; + } + + rel_cid = cid - p_map->start_cid; + if (!test_bit(rel_cid, p_map->cid_map)) { + DP_NOTICE(p_hwfn, "CID %d not acquired", cid); + return false; + } + return true; +} + +void qed_cxt_release_cid(struct qed_hwfn *p_hwfn, + u32 cid) +{ + struct qed_cxt_mngr *p_mngr = p_hwfn->p_cxt_mngr; + enum protocol_type type; + bool b_acquired; + u32 rel_cid; + + /* Test acquired and find matching per-protocol map */ + b_acquired = qed_cxt_test_cid_acquired(p_hwfn, cid, &type); + + if (!b_acquired) + return; + + rel_cid = cid - p_mngr->acquired[type].start_cid; + __clear_bit(rel_cid, p_mngr->acquired[type].cid_map); +} + +int qed_cxt_get_cid_info(struct qed_hwfn *p_hwfn, + struct qed_cxt_info *p_info) +{ + struct qed_cxt_mngr *p_mngr = p_hwfn->p_cxt_mngr; + u32 conn_cxt_size, hw_p_size, cxts_per_p, line; + enum protocol_type type; + bool b_acquired; + + /* Test acquired and find matching per-protocol map */ + b_acquired = qed_cxt_test_cid_acquired(p_hwfn, p_info->iid, &type); + + if (!b_acquired) + return -EINVAL; + + /* set the protocl type */ + p_info->type = type; + + /* compute context virtual pointer */ + hw_p_size = p_hwfn->p_cxt_mngr->clients[ILT_CLI_CDUC].p_size.val; + + conn_cxt_size = CONN_CXT_SIZE(p_hwfn); + cxts_per_p = ILT_PAGE_IN_BYTES(hw_p_size) / conn_cxt_size; + line = p_info->iid / cxts_per_p; + + /* Make sure context is allocated (dynamic allocation) */ + if (!p_mngr->ilt_shadow[line].p_virt) + return -EINVAL; + + p_info->p_cxt = p_mngr->ilt_shadow[line].p_virt + + p_info->iid % cxts_per_p * conn_cxt_size; + + DP_VERBOSE(p_hwfn, (QED_MSG_ILT | QED_MSG_CXT), + "Accessing ILT shadow[%d]: CXT pointer is at %p (for iid %d)\n", + p_info->iid / cxts_per_p, p_info->p_cxt, p_info->iid); + + return 0; +} + +int qed_cxt_set_pf_params(struct qed_hwfn *p_hwfn) +{ + struct qed_eth_pf_params *p_params = &p_hwfn->pf_params.eth_pf_params; + + /* Set the number of required CORE connections */ + u32 core_cids = 1; /* SPQ */ + + qed_cxt_set_proto_cid_count(p_hwfn, PROTOCOLID_CORE, core_cids); + + qed_cxt_set_proto_cid_count(p_hwfn, PROTOCOLID_ETH, + p_params->num_cons); + + return 0; +} diff --git a/drivers/net/ethernet/qlogic/qed/qed_cxt.h b/drivers/net/ethernet/qlogic/qed/qed_cxt.h new file mode 100644 index 000000000000..c8e1f5e5c42b --- /dev/null +++ b/drivers/net/ethernet/qlogic/qed/qed_cxt.h @@ -0,0 +1,139 @@ +/* QLogic qed NIC Driver + * Copyright (c) 2015 QLogic Corporation + * + * This software is available under the terms of the GNU General Public License + * (GPL) Version 2, available from the file COPYING in the main directory of + * this source tree. + */ + +#ifndef _QED_CXT_H +#define _QED_CXT_H + +#include +#include +#include +#include "qed_hsi.h" +#include "qed.h" + +struct qed_cxt_info { + void *p_cxt; + u32 iid; + enum protocol_type type; +}; + +/** + * @brief qed_cxt_acquire - Acquire a new cid of a specific protocol type + * + * @param p_hwfn + * @param type + * @param p_cid + * + * @return int + */ +int qed_cxt_acquire_cid(struct qed_hwfn *p_hwfn, + enum protocol_type type, + u32 *p_cid); + +/** + * @brief qedo_cid_get_cxt_info - Returns the context info for a specific cid + * + * + * @param p_hwfn + * @param p_info in/out + * + * @return int + */ +int qed_cxt_get_cid_info(struct qed_hwfn *p_hwfn, + struct qed_cxt_info *p_info); + +enum qed_cxt_elem_type { + QED_ELEM_CXT, + QED_ELEM_TASK +}; + +/** + * @brief qed_cxt_set_pf_params - Set the PF params for cxt init + * + * @param p_hwfn + * + * @return int + */ +int qed_cxt_set_pf_params(struct qed_hwfn *p_hwfn); + +/** + * @brief qed_cxt_cfg_ilt_compute - compute ILT init parameters + * + * @param p_hwfn + * + * @return int + */ +int qed_cxt_cfg_ilt_compute(struct qed_hwfn *p_hwfn); + +/** + * @brief qed_cxt_mngr_alloc - Allocate and init the context manager struct + * + * @param p_hwfn + * + * @return int + */ +int qed_cxt_mngr_alloc(struct qed_hwfn *p_hwfn); + +/** + * @brief qed_cxt_mngr_free + * + * @param p_hwfn + */ +void qed_cxt_mngr_free(struct qed_hwfn *p_hwfn); + +/** + * @brief qed_cxt_tables_alloc - Allocate ILT shadow, Searcher T2, acquired map + * + * @param p_hwfn + * + * @return int + */ +int qed_cxt_tables_alloc(struct qed_hwfn *p_hwfn); + +/** + * @brief qed_cxt_mngr_setup - Reset the acquired CIDs + * + * @param p_hwfn + */ +void qed_cxt_mngr_setup(struct qed_hwfn *p_hwfn); + +/** + * @brief qed_cxt_hw_init_common - Initailze ILT and DQ, common phase, per path. + * + * + * + * @param p_hwfn + */ +void qed_cxt_hw_init_common(struct qed_hwfn *p_hwfn); + +/** + * @brief qed_cxt_hw_init_pf - Initailze ILT and DQ, PF phase, per path. + * + * + * + * @param p_hwfn + */ +void qed_cxt_hw_init_pf(struct qed_hwfn *p_hwfn); + +/** + * @brief qed_qm_init_pf - Initailze the QM PF phase, per path + * + * @param p_hwfn + */ + +void qed_qm_init_pf(struct qed_hwfn *p_hwfn); + +/** + * @brief qed_cxt_release - Release a cid + * + * @param p_hwfn + * @param cid + */ +void qed_cxt_release_cid(struct qed_hwfn *p_hwfn, + u32 cid); + +#endif diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c new file mode 100644 index 000000000000..5b845220ae8c --- /dev/null +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c @@ -0,0 +1,1277 @@ +/* QLogic qed NIC Driver + * Copyright (c) 2015 QLogic Corporation + * + * This software is available under the terms of the GNU General Public License + * (GPL) Version 2, available from the file COPYING in the main directory of + * this source tree. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "qed.h" +#include "qed_cxt.h" +#include "qed_dev_api.h" +#include "qed_hsi.h" +#include "qed_hw.h" +#include "qed_init_ops.h" +#include "qed_int.h" +#include "qed_mcp.h" +#include "qed_reg_addr.h" +#include "qed_sp.h" + +/* API common to all protocols */ +void qed_init_dp(struct qed_dev *cdev, + u32 dp_module, u8 dp_level) +{ + u32 i; + + cdev->dp_level = dp_level; + cdev->dp_module = dp_module; + for (i = 0; i < MAX_HWFNS_PER_DEVICE; i++) { + struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; + + p_hwfn->dp_level = dp_level; + p_hwfn->dp_module = dp_module; + } +} + +void qed_init_struct(struct qed_dev *cdev) +{ + u8 i; + + for (i = 0; i < MAX_HWFNS_PER_DEVICE; i++) { + struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; + + p_hwfn->cdev = cdev; + p_hwfn->my_id = i; + p_hwfn->b_active = false; + + mutex_init(&p_hwfn->dmae_info.mutex); + } + + /* hwfn 0 is always active */ + cdev->hwfns[0].b_active = true; + + /* set the default cache alignment to 128 */ + cdev->cache_shift = 7; +} + +static void qed_qm_info_free(struct qed_hwfn *p_hwfn) +{ + struct qed_qm_info *qm_info = &p_hwfn->qm_info; + + kfree(qm_info->qm_pq_params); + qm_info->qm_pq_params = NULL; + kfree(qm_info->qm_vport_params); + qm_info->qm_vport_params = NULL; + kfree(qm_info->qm_port_params); + qm_info->qm_port_params = NULL; +} + +void qed_resc_free(struct qed_dev *cdev) +{ + int i; + + kfree(cdev->fw_data); + cdev->fw_data = NULL; + + kfree(cdev->reset_stats); + + for_each_hwfn(cdev, i) { + struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; + + qed_cxt_mngr_free(p_hwfn); + qed_qm_info_free(p_hwfn); + qed_spq_free(p_hwfn); + qed_eq_free(p_hwfn, p_hwfn->p_eq); + qed_consq_free(p_hwfn, p_hwfn->p_consq); + qed_int_free(p_hwfn); + qed_dmae_info_free(p_hwfn); + } +} + +static int qed_init_qm_info(struct qed_hwfn *p_hwfn) +{ + struct qed_qm_info *qm_info = &p_hwfn->qm_info; + struct init_qm_port_params *p_qm_port; + u8 num_vports, i, vport_id, num_ports; + u16 num_pqs, multi_cos_tcs = 1; + + memset(qm_info, 0, sizeof(*qm_info)); + + num_pqs = multi_cos_tcs + 1; /* The '1' is for pure-LB */ + num_vports = (u8)RESC_NUM(p_hwfn, QED_VPORT); + + /* Sanity checking that setup requires legal number of resources */ + if (num_pqs > RESC_NUM(p_hwfn, QED_PQ)) { + DP_ERR(p_hwfn, + "Need too many Physical queues - 0x%04x when only %04x are available\n", + num_pqs, RESC_NUM(p_hwfn, QED_PQ)); + return -EINVAL; + } + + /* PQs will be arranged as follows: First per-TC PQ then pure-LB quete. + */ + qm_info->qm_pq_params = kzalloc(sizeof(*qm_info->qm_pq_params) * + num_pqs, GFP_ATOMIC); + if (!qm_info->qm_pq_params) + goto alloc_err; + + qm_info->qm_vport_params = kzalloc(sizeof(*qm_info->qm_vport_params) * + num_vports, GFP_ATOMIC); + if (!qm_info->qm_vport_params) + goto alloc_err; + + qm_info->qm_port_params = kzalloc(sizeof(*qm_info->qm_port_params) * + MAX_NUM_PORTS, GFP_ATOMIC); + if (!qm_info->qm_port_params) + goto alloc_err; + + vport_id = (u8)RESC_START(p_hwfn, QED_VPORT); + + /* First init per-TC PQs */ + for (i = 0; i < multi_cos_tcs; i++) { + struct init_qm_pq_params *params = &qm_info->qm_pq_params[i]; + + params->vport_id = vport_id; + params->tc_id = p_hwfn->hw_info.non_offload_tc; + params->wrr_group = 1; + } + + /* Then init pure-LB PQ */ + qm_info->pure_lb_pq = i; + qm_info->qm_pq_params[i].vport_id = (u8)RESC_START(p_hwfn, QED_VPORT); + qm_info->qm_pq_params[i].tc_id = PURE_LB_TC; + qm_info->qm_pq_params[i].wrr_group = 1; + i++; + + qm_info->offload_pq = 0; + qm_info->num_pqs = num_pqs; + qm_info->num_vports = num_vports; + + /* Initialize qm port parameters */ + num_ports = p_hwfn->cdev->num_ports_in_engines; + for (i = 0; i < num_ports; i++) { + p_qm_port = &qm_info->qm_port_params[i]; + p_qm_port->active = 1; + p_qm_port->num_active_phys_tcs = 4; + p_qm_port->num_pbf_cmd_lines = PBF_MAX_CMD_LINES / num_ports; + p_qm_port->num_btb_blocks = BTB_MAX_BLOCKS / num_ports; + } + + qm_info->max_phys_tcs_per_port = NUM_OF_PHYS_TCS; + + qm_info->start_pq = (u16)RESC_START(p_hwfn, QED_PQ); + + qm_info->start_vport = (u8)RESC_START(p_hwfn, QED_VPORT); + + qm_info->pf_wfq = 0; + qm_info->pf_rl = 0; + qm_info->vport_rl_en = 1; + + return 0; + +alloc_err: + DP_NOTICE(p_hwfn, "Failed to allocate memory for QM params\n"); + kfree(qm_info->qm_pq_params); + kfree(qm_info->qm_vport_params); + kfree(qm_info->qm_port_params); + + return -ENOMEM; +} + +int qed_resc_alloc(struct qed_dev *cdev) +{ + struct qed_consq *p_consq; + struct qed_eq *p_eq; + int i, rc = 0; + + cdev->fw_data = kzalloc(sizeof(*cdev->fw_data), GFP_KERNEL); + if (!cdev->fw_data) + return -ENOMEM; + + for_each_hwfn(cdev, i) { + struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; + + /* First allocate the context manager structure */ + rc = qed_cxt_mngr_alloc(p_hwfn); + if (rc) + goto alloc_err; + + /* Set the HW cid/tid numbers (in the contest manager) + * Must be done prior to any further computations. + */ + rc = qed_cxt_set_pf_params(p_hwfn); + if (rc) + goto alloc_err; + + /* Prepare and process QM requirements */ + rc = qed_init_qm_info(p_hwfn); + if (rc) + goto alloc_err; + + /* Compute the ILT client partition */ + rc = qed_cxt_cfg_ilt_compute(p_hwfn); + if (rc) + goto alloc_err; + + /* CID map / ILT shadow table / T2 + * The talbes sizes are determined by the computations above + */ + rc = qed_cxt_tables_alloc(p_hwfn); + if (rc) + goto alloc_err; + + /* SPQ, must follow ILT because initializes SPQ context */ + rc = qed_spq_alloc(p_hwfn); + if (rc) + goto alloc_err; + + /* SP status block allocation */ + p_hwfn->p_dpc_ptt = qed_get_reserved_ptt(p_hwfn, + RESERVED_PTT_DPC); + + rc = qed_int_alloc(p_hwfn, p_hwfn->p_main_ptt); + if (rc) + goto alloc_err; + + /* EQ */ + p_eq = qed_eq_alloc(p_hwfn, 256); + + if (!p_eq) + goto alloc_err; + p_hwfn->p_eq = p_eq; + + p_consq = qed_consq_alloc(p_hwfn); + if (!p_consq) + goto alloc_err; + p_hwfn->p_consq = p_consq; + + /* DMA info initialization */ + rc = qed_dmae_info_alloc(p_hwfn); + if (rc) { + DP_NOTICE(p_hwfn, + "Failed to allocate memory for dmae_info structure\n"); + goto alloc_err; + } + } + + cdev->reset_stats = kzalloc(sizeof(*cdev->reset_stats), GFP_KERNEL); + if (!cdev->reset_stats) { + DP_NOTICE(cdev, "Failed to allocate reset statistics\n"); + goto alloc_err; + } + + return 0; + +alloc_err: + qed_resc_free(cdev); + return rc; +} + +void qed_resc_setup(struct qed_dev *cdev) +{ + int i; + + for_each_hwfn(cdev, i) { + struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; + + qed_cxt_mngr_setup(p_hwfn); + qed_spq_setup(p_hwfn); + qed_eq_setup(p_hwfn, p_hwfn->p_eq); + qed_consq_setup(p_hwfn, p_hwfn->p_consq); + + /* Read shadow of current MFW mailbox */ + qed_mcp_read_mb(p_hwfn, p_hwfn->p_main_ptt); + memcpy(p_hwfn->mcp_info->mfw_mb_shadow, + p_hwfn->mcp_info->mfw_mb_cur, + p_hwfn->mcp_info->mfw_mb_length); + + qed_int_setup(p_hwfn, p_hwfn->p_main_ptt); + } +} + +#define FINAL_CLEANUP_CMD_OFFSET (0) +#define FINAL_CLEANUP_CMD (0x1) +#define FINAL_CLEANUP_VALID_OFFSET (6) +#define FINAL_CLEANUP_VFPF_ID_SHIFT (7) +#define FINAL_CLEANUP_COMP (0x2) +#define FINAL_CLEANUP_POLL_CNT (100) +#define FINAL_CLEANUP_POLL_TIME (10) +int qed_final_cleanup(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u16 id) +{ + u32 command = 0, addr, count = FINAL_CLEANUP_POLL_CNT; + int rc = -EBUSY; + + addr = GTT_BAR0_MAP_REG_USDM_RAM + USTORM_FLR_FINAL_ACK_OFFSET; + + command |= FINAL_CLEANUP_CMD << FINAL_CLEANUP_CMD_OFFSET; + command |= 1 << FINAL_CLEANUP_VALID_OFFSET; + command |= id << FINAL_CLEANUP_VFPF_ID_SHIFT; + command |= FINAL_CLEANUP_COMP << SDM_OP_GEN_COMP_TYPE_SHIFT; + + /* Make sure notification is not set before initiating final cleanup */ + if (REG_RD(p_hwfn, addr)) { + DP_NOTICE( + p_hwfn, + "Unexpected; Found final cleanup notification before initiating final cleanup\n"); + REG_WR(p_hwfn, addr, 0); + } + + DP_VERBOSE(p_hwfn, QED_MSG_IOV, + "Sending final cleanup for PFVF[%d] [Command %08x\n]", + id, command); + + qed_wr(p_hwfn, p_ptt, XSDM_REG_OPERATION_GEN, command); + + /* Poll until completion */ + while (!REG_RD(p_hwfn, addr) && count--) + msleep(FINAL_CLEANUP_POLL_TIME); + + if (REG_RD(p_hwfn, addr)) + rc = 0; + else + DP_NOTICE(p_hwfn, + "Failed to receive FW final cleanup notification\n"); + + /* Cleanup afterwards */ + REG_WR(p_hwfn, addr, 0); + + return rc; +} + +static void qed_calc_hw_mode(struct qed_hwfn *p_hwfn) +{ + int hw_mode = 0; + + hw_mode = (1 << MODE_BB_A0); + + switch (p_hwfn->cdev->num_ports_in_engines) { + case 1: + hw_mode |= 1 << MODE_PORTS_PER_ENG_1; + break; + case 2: + hw_mode |= 1 << MODE_PORTS_PER_ENG_2; + break; + case 4: + hw_mode |= 1 << MODE_PORTS_PER_ENG_4; + break; + default: + DP_NOTICE(p_hwfn, "num_ports_in_engine = %d not supported\n", + p_hwfn->cdev->num_ports_in_engines); + return; + } + + switch (p_hwfn->cdev->mf_mode) { + case SF: + hw_mode |= 1 << MODE_SF; + break; + case MF_OVLAN: + hw_mode |= 1 << MODE_MF_SD; + break; + case MF_NPAR: + hw_mode |= 1 << MODE_MF_SI; + break; + default: + DP_NOTICE(p_hwfn, "Unsupported MF mode, init as SF\n"); + hw_mode |= 1 << MODE_SF; + } + + hw_mode |= 1 << MODE_ASIC; + + p_hwfn->hw_info.hw_mode = hw_mode; +} + +/* Init run time data for all PFs on an engine. */ +static void qed_init_cau_rt_data(struct qed_dev *cdev) +{ + u32 offset = CAU_REG_SB_VAR_MEMORY_RT_OFFSET; + int i, sb_id; + + for_each_hwfn(cdev, i) { + struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; + struct qed_igu_info *p_igu_info; + struct qed_igu_block *p_block; + struct cau_sb_entry sb_entry; + + p_igu_info = p_hwfn->hw_info.p_igu_info; + + for (sb_id = 0; sb_id < QED_MAPPING_MEMORY_SIZE(cdev); + sb_id++) { + p_block = &p_igu_info->igu_map.igu_blocks[sb_id]; + if (!p_block->is_pf) + continue; + + qed_init_cau_sb_entry(p_hwfn, &sb_entry, + p_block->function_id, + 0, 0); + STORE_RT_REG_AGG(p_hwfn, offset + sb_id * 2, + sb_entry); + } + } +} + +static int qed_hw_init_common(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + int hw_mode) +{ + struct qed_qm_info *qm_info = &p_hwfn->qm_info; + struct qed_qm_common_rt_init_params params; + struct qed_dev *cdev = p_hwfn->cdev; + int rc = 0; + + qed_init_cau_rt_data(cdev); + + /* Program GTT windows */ + qed_gtt_init(p_hwfn); + + if (p_hwfn->mcp_info) { + if (p_hwfn->mcp_info->func_info.bandwidth_max) + qm_info->pf_rl_en = 1; + if (p_hwfn->mcp_info->func_info.bandwidth_min) + qm_info->pf_wfq_en = 1; + } + + memset(¶ms, 0, sizeof(params)); + params.max_ports_per_engine = p_hwfn->cdev->num_ports_in_engines; + params.max_phys_tcs_per_port = qm_info->max_phys_tcs_per_port; + params.pf_rl_en = qm_info->pf_rl_en; + params.pf_wfq_en = qm_info->pf_wfq_en; + params.vport_rl_en = qm_info->vport_rl_en; + params.vport_wfq_en = qm_info->vport_wfq_en; + params.port_params = qm_info->qm_port_params; + + qed_qm_common_rt_init(p_hwfn, ¶ms); + + qed_cxt_hw_init_common(p_hwfn); + + /* Close gate from NIG to BRB/Storm; By default they are open, but + * we close them to prevent NIG from passing data to reset blocks. + * Should have been done in the ENGINE phase, but init-tool lacks + * proper port-pretend capabilities. + */ + qed_wr(p_hwfn, p_ptt, NIG_REG_RX_BRB_OUT_EN, 0); + qed_wr(p_hwfn, p_ptt, NIG_REG_STORM_OUT_EN, 0); + qed_port_pretend(p_hwfn, p_ptt, p_hwfn->port_id ^ 1); + qed_wr(p_hwfn, p_ptt, NIG_REG_RX_BRB_OUT_EN, 0); + qed_wr(p_hwfn, p_ptt, NIG_REG_STORM_OUT_EN, 0); + qed_port_unpretend(p_hwfn, p_ptt); + + rc = qed_init_run(p_hwfn, p_ptt, PHASE_ENGINE, ANY_PHASE_ID, hw_mode); + if (rc != 0) + return rc; + + qed_wr(p_hwfn, p_ptt, PSWRQ2_REG_L2P_VALIDATE_VFID, 0); + qed_wr(p_hwfn, p_ptt, PGLUE_B_REG_USE_CLIENTID_IN_TAG, 1); + + /* Disable relaxed ordering in the PCI config space */ + qed_wr(p_hwfn, p_ptt, 0x20b4, + qed_rd(p_hwfn, p_ptt, 0x20b4) & ~0x10); + + return rc; +} + +static int qed_hw_init_port(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + int hw_mode) +{ + int rc = 0; + + rc = qed_init_run(p_hwfn, p_ptt, PHASE_PORT, p_hwfn->port_id, + hw_mode); + return rc; +} + +static int qed_hw_init_pf(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + int hw_mode, + bool b_hw_start, + enum qed_int_mode int_mode, + bool allow_npar_tx_switch) +{ + u8 rel_pf_id = p_hwfn->rel_pf_id; + int rc = 0; + + if (p_hwfn->mcp_info) { + struct qed_mcp_function_info *p_info; + + p_info = &p_hwfn->mcp_info->func_info; + if (p_info->bandwidth_min) + p_hwfn->qm_info.pf_wfq = p_info->bandwidth_min; + + /* Update rate limit once we'll actually have a link */ + p_hwfn->qm_info.pf_rl = 100; + } + + qed_cxt_hw_init_pf(p_hwfn); + + qed_int_igu_init_rt(p_hwfn); + + /* Set VLAN in NIG if needed */ + if (hw_mode & (1 << MODE_MF_SD)) { + DP_VERBOSE(p_hwfn, NETIF_MSG_HW, "Configuring LLH_FUNC_TAG\n"); + STORE_RT_REG(p_hwfn, NIG_REG_LLH_FUNC_TAG_EN_RT_OFFSET, 1); + STORE_RT_REG(p_hwfn, NIG_REG_LLH_FUNC_TAG_VALUE_RT_OFFSET, + p_hwfn->hw_info.ovlan); + } + + /* Enable classification by MAC if needed */ + if (hw_mode & MODE_MF_SI) { + DP_VERBOSE(p_hwfn, NETIF_MSG_HW, + "Configuring TAGMAC_CLS_TYPE\n"); + STORE_RT_REG(p_hwfn, + NIG_REG_LLH_FUNC_TAGMAC_CLS_TYPE_RT_OFFSET, 1); + } + + /* Protocl Configuration */ + STORE_RT_REG(p_hwfn, PRS_REG_SEARCH_TCP_RT_OFFSET, 0); + STORE_RT_REG(p_hwfn, PRS_REG_SEARCH_FCOE_RT_OFFSET, 0); + STORE_RT_REG(p_hwfn, PRS_REG_SEARCH_ROCE_RT_OFFSET, 0); + + /* Cleanup chip from previous driver if such remains exist */ + rc = qed_final_cleanup(p_hwfn, p_ptt, rel_pf_id); + if (rc != 0) + return rc; + + /* PF Init sequence */ + rc = qed_init_run(p_hwfn, p_ptt, PHASE_PF, rel_pf_id, hw_mode); + if (rc) + return rc; + + /* QM_PF Init sequence (may be invoked separately e.g. for DCB) */ + rc = qed_init_run(p_hwfn, p_ptt, PHASE_QM_PF, rel_pf_id, hw_mode); + if (rc) + return rc; + + /* Pure runtime initializations - directly to the HW */ + qed_int_igu_init_pure_rt(p_hwfn, p_ptt, true, true); + + if (b_hw_start) { + /* enable interrupts */ + qed_int_igu_enable(p_hwfn, p_ptt, int_mode); + + /* send function start command */ + rc = qed_sp_pf_start(p_hwfn, p_hwfn->cdev->mf_mode); + if (rc) + DP_NOTICE(p_hwfn, "Function start ramrod failed\n"); + } + return rc; +} + +static int qed_change_pci_hwfn(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u8 enable) +{ + u32 delay_idx = 0, val, set_val = enable ? 1 : 0; + + /* Change PF in PXP */ + qed_wr(p_hwfn, p_ptt, + PGLUE_B_REG_INTERNAL_PFID_ENABLE_MASTER, set_val); + + /* wait until value is set - try for 1 second every 50us */ + for (delay_idx = 0; delay_idx < 20000; delay_idx++) { + val = qed_rd(p_hwfn, p_ptt, + PGLUE_B_REG_INTERNAL_PFID_ENABLE_MASTER); + if (val == set_val) + break; + + usleep_range(50, 60); + } + + if (val != set_val) { + DP_NOTICE(p_hwfn, + "PFID_ENABLE_MASTER wasn't changed after a second\n"); + return -EAGAIN; + } + + return 0; +} + +static void qed_reset_mb_shadow(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_main_ptt) +{ + /* Read shadow of current MFW mailbox */ + qed_mcp_read_mb(p_hwfn, p_main_ptt); + memcpy(p_hwfn->mcp_info->mfw_mb_shadow, + p_hwfn->mcp_info->mfw_mb_cur, + p_hwfn->mcp_info->mfw_mb_length); +} + +int qed_hw_init(struct qed_dev *cdev, + bool b_hw_start, + enum qed_int_mode int_mode, + bool allow_npar_tx_switch, + const u8 *bin_fw_data) +{ + u32 load_code, param; + int rc, mfw_rc, i; + + rc = qed_init_fw_data(cdev, bin_fw_data); + if (rc != 0) + return rc; + + for_each_hwfn(cdev, i) { + struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; + + /* Enable DMAE in PXP */ + rc = qed_change_pci_hwfn(p_hwfn, p_hwfn->p_main_ptt, true); + + qed_calc_hw_mode(p_hwfn); + + rc = qed_mcp_load_req(p_hwfn, p_hwfn->p_main_ptt, + &load_code); + if (rc) { + DP_NOTICE(p_hwfn, "Failed sending LOAD_REQ command\n"); + return rc; + } + + qed_reset_mb_shadow(p_hwfn, p_hwfn->p_main_ptt); + + DP_VERBOSE(p_hwfn, QED_MSG_SP, + "Load request was sent. Resp:0x%x, Load code: 0x%x\n", + rc, load_code); + + p_hwfn->first_on_engine = (load_code == + FW_MSG_CODE_DRV_LOAD_ENGINE); + + switch (load_code) { + case FW_MSG_CODE_DRV_LOAD_ENGINE: + rc = qed_hw_init_common(p_hwfn, p_hwfn->p_main_ptt, + p_hwfn->hw_info.hw_mode); + if (rc) + break; + /* Fall into */ + case FW_MSG_CODE_DRV_LOAD_PORT: + rc = qed_hw_init_port(p_hwfn, p_hwfn->p_main_ptt, + p_hwfn->hw_info.hw_mode); + if (rc) + break; + + /* Fall into */ + case FW_MSG_CODE_DRV_LOAD_FUNCTION: + rc = qed_hw_init_pf(p_hwfn, p_hwfn->p_main_ptt, + p_hwfn->hw_info.hw_mode, + b_hw_start, int_mode, + allow_npar_tx_switch); + break; + default: + rc = -EINVAL; + break; + } + + if (rc) + DP_NOTICE(p_hwfn, + "init phase failed for loadcode 0x%x (rc %d)\n", + load_code, rc); + + /* ACK mfw regardless of success or failure of initialization */ + mfw_rc = qed_mcp_cmd(p_hwfn, p_hwfn->p_main_ptt, + DRV_MSG_CODE_LOAD_DONE, + 0, &load_code, ¶m); + if (rc) + return rc; + if (mfw_rc) { + DP_NOTICE(p_hwfn, "Failed sending LOAD_DONE command\n"); + return mfw_rc; + } + + p_hwfn->hw_init_done = true; + } + + return 0; +} + +#define QED_HW_STOP_RETRY_LIMIT (10) +int qed_hw_stop(struct qed_dev *cdev) +{ + int rc = 0, t_rc; + int i, j; + + for_each_hwfn(cdev, j) { + struct qed_hwfn *p_hwfn = &cdev->hwfns[j]; + struct qed_ptt *p_ptt = p_hwfn->p_main_ptt; + + DP_VERBOSE(p_hwfn, NETIF_MSG_IFDOWN, "Stopping hw/fw\n"); + + /* mark the hw as uninitialized... */ + p_hwfn->hw_init_done = false; + + rc = qed_sp_pf_stop(p_hwfn); + if (rc) + return rc; + + qed_wr(p_hwfn, p_ptt, + NIG_REG_RX_LLH_BRB_GATE_DNTFWD_PERPF, 0x1); + + qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_TCP, 0x0); + qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_UDP, 0x0); + qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_FCOE, 0x0); + qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_ROCE, 0x0); + qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_OPENFLOW, 0x0); + + qed_wr(p_hwfn, p_ptt, TM_REG_PF_ENABLE_CONN, 0x0); + qed_wr(p_hwfn, p_ptt, TM_REG_PF_ENABLE_TASK, 0x0); + for (i = 0; i < QED_HW_STOP_RETRY_LIMIT; i++) { + if ((!qed_rd(p_hwfn, p_ptt, + TM_REG_PF_SCAN_ACTIVE_CONN)) && + (!qed_rd(p_hwfn, p_ptt, + TM_REG_PF_SCAN_ACTIVE_TASK))) + break; + + usleep_range(1000, 2000); + } + if (i == QED_HW_STOP_RETRY_LIMIT) + DP_NOTICE(p_hwfn, + "Timers linear scans are not over [Connection %02x Tasks %02x]\n", + (u8)qed_rd(p_hwfn, p_ptt, + TM_REG_PF_SCAN_ACTIVE_CONN), + (u8)qed_rd(p_hwfn, p_ptt, + TM_REG_PF_SCAN_ACTIVE_TASK)); + + /* Disable Attention Generation */ + qed_int_igu_disable_int(p_hwfn, p_ptt); + + qed_wr(p_hwfn, p_ptt, IGU_REG_LEADING_EDGE_LATCH, 0); + qed_wr(p_hwfn, p_ptt, IGU_REG_TRAILING_EDGE_LATCH, 0); + + qed_int_igu_init_pure_rt(p_hwfn, p_ptt, false, true); + + /* Need to wait 1ms to guarantee SBs are cleared */ + usleep_range(1000, 2000); + } + + /* Disable DMAE in PXP - in CMT, this should only be done for + * first hw-function, and only after all transactions have + * stopped for all active hw-functions. + */ + t_rc = qed_change_pci_hwfn(&cdev->hwfns[0], + cdev->hwfns[0].p_main_ptt, + false); + if (t_rc != 0) + rc = t_rc; + + return rc; +} + +static int qed_reg_assert(struct qed_hwfn *hwfn, + struct qed_ptt *ptt, u32 reg, + bool expected) +{ + u32 assert_val = qed_rd(hwfn, ptt, reg); + + if (assert_val != expected) { + DP_NOTICE(hwfn, "Value at address 0x%x != 0x%08x\n", + reg, expected); + return -EINVAL; + } + + return 0; +} + +int qed_hw_reset(struct qed_dev *cdev) +{ + int rc = 0; + u32 unload_resp, unload_param; + int i; + + for_each_hwfn(cdev, i) { + struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; + + DP_VERBOSE(p_hwfn, NETIF_MSG_IFDOWN, "Resetting hw/fw\n"); + + /* Check for incorrect states */ + qed_reg_assert(p_hwfn, p_hwfn->p_main_ptt, + QM_REG_USG_CNT_PF_TX, 0); + qed_reg_assert(p_hwfn, p_hwfn->p_main_ptt, + QM_REG_USG_CNT_PF_OTHER, 0); + + /* Disable PF in HW blocks */ + qed_wr(p_hwfn, p_hwfn->p_main_ptt, DORQ_REG_PF_DB_ENABLE, 0); + qed_wr(p_hwfn, p_hwfn->p_main_ptt, QM_REG_PF_EN, 0); + qed_wr(p_hwfn, p_hwfn->p_main_ptt, + TCFC_REG_STRONG_ENABLE_PF, 0); + qed_wr(p_hwfn, p_hwfn->p_main_ptt, + CCFC_REG_STRONG_ENABLE_PF, 0); + + /* Send unload command to MCP */ + rc = qed_mcp_cmd(p_hwfn, p_hwfn->p_main_ptt, + DRV_MSG_CODE_UNLOAD_REQ, + DRV_MB_PARAM_UNLOAD_WOL_MCP, + &unload_resp, &unload_param); + if (rc) { + DP_NOTICE(p_hwfn, "qed_hw_reset: UNLOAD_REQ failed\n"); + unload_resp = FW_MSG_CODE_DRV_UNLOAD_ENGINE; + } + + rc = qed_mcp_cmd(p_hwfn, p_hwfn->p_main_ptt, + DRV_MSG_CODE_UNLOAD_DONE, + 0, &unload_resp, &unload_param); + if (rc) { + DP_NOTICE(p_hwfn, "qed_hw_reset: UNLOAD_DONE failed\n"); + return rc; + } + } + + return rc; +} + +/* Free hwfn memory and resources acquired in hw_hwfn_prepare */ +static void qed_hw_hwfn_free(struct qed_hwfn *p_hwfn) +{ + qed_ptt_pool_free(p_hwfn); + kfree(p_hwfn->hw_info.p_igu_info); +} + +/* Setup bar access */ +static int qed_hw_hwfn_prepare(struct qed_hwfn *p_hwfn) +{ + int rc; + + /* Allocate PTT pool */ + rc = qed_ptt_pool_alloc(p_hwfn); + if (rc) + return rc; + + /* Allocate the main PTT */ + p_hwfn->p_main_ptt = qed_get_reserved_ptt(p_hwfn, RESERVED_PTT_MAIN); + + /* clear indirect access */ + qed_wr(p_hwfn, p_hwfn->p_main_ptt, PGLUE_B_REG_PGL_ADDR_88_F0, 0); + qed_wr(p_hwfn, p_hwfn->p_main_ptt, PGLUE_B_REG_PGL_ADDR_8C_F0, 0); + qed_wr(p_hwfn, p_hwfn->p_main_ptt, PGLUE_B_REG_PGL_ADDR_90_F0, 0); + qed_wr(p_hwfn, p_hwfn->p_main_ptt, PGLUE_B_REG_PGL_ADDR_94_F0, 0); + + /* Clean Previous errors if such exist */ + qed_wr(p_hwfn, p_hwfn->p_main_ptt, + PGLUE_B_REG_WAS_ERROR_PF_31_0_CLR, + 1 << p_hwfn->abs_pf_id); + + /* enable internal target-read */ + qed_wr(p_hwfn, p_hwfn->p_main_ptt, + PGLUE_B_REG_INTERNAL_PFID_ENABLE_TARGET_READ, 1); + + return 0; +} + +static void get_function_id(struct qed_hwfn *p_hwfn) +{ + /* ME Register */ + p_hwfn->hw_info.opaque_fid = (u16)REG_RD(p_hwfn, PXP_PF_ME_OPAQUE_ADDR); + + p_hwfn->hw_info.concrete_fid = REG_RD(p_hwfn, PXP_PF_ME_CONCRETE_ADDR); + + p_hwfn->abs_pf_id = (p_hwfn->hw_info.concrete_fid >> 16) & 0xf; + p_hwfn->rel_pf_id = GET_FIELD(p_hwfn->hw_info.concrete_fid, + PXP_CONCRETE_FID_PFID); + p_hwfn->port_id = GET_FIELD(p_hwfn->hw_info.concrete_fid, + PXP_CONCRETE_FID_PORT); +} + +static void qed_hw_get_resc(struct qed_hwfn *p_hwfn) +{ + u32 *resc_start = p_hwfn->hw_info.resc_start; + u32 *resc_num = p_hwfn->hw_info.resc_num; + int num_funcs, i; + + num_funcs = IS_MF(p_hwfn) ? MAX_NUM_PFS_BB + : p_hwfn->cdev->num_ports_in_engines; + + resc_num[QED_SB] = min_t(u32, + (MAX_SB_PER_PATH_BB / num_funcs), + qed_int_get_num_sbs(p_hwfn, NULL)); + resc_num[QED_VPORT] = MAX_NUM_VPORTS_BB / num_funcs; + resc_num[QED_PQ] = MAX_QM_TX_QUEUES_BB / num_funcs; + resc_num[QED_RL] = 8; + resc_num[QED_ILT] = 950; + + for (i = 0; i < QED_MAX_RESC; i++) + resc_start[i] = resc_num[i] * p_hwfn->rel_pf_id; + + DP_VERBOSE(p_hwfn, NETIF_MSG_PROBE, + "The numbers for each resource are:\n" + "SB = %d start = %d\n" + "VPORT = %d start = %d\n" + "PQ = %d start = %d\n" + "RL = %d start = %d\n" + "ILT = %d start = %d\n", + p_hwfn->hw_info.resc_num[QED_SB], + p_hwfn->hw_info.resc_start[QED_SB], + p_hwfn->hw_info.resc_num[QED_VPORT], + p_hwfn->hw_info.resc_start[QED_VPORT], + p_hwfn->hw_info.resc_num[QED_PQ], + p_hwfn->hw_info.resc_start[QED_PQ], + p_hwfn->hw_info.resc_num[QED_RL], + p_hwfn->hw_info.resc_start[QED_RL], + p_hwfn->hw_info.resc_num[QED_ILT], + p_hwfn->hw_info.resc_start[QED_ILT]); +} + +static int qed_hw_get_nvm_info(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt) +{ + u32 nvm_cfg1_offset, mf_mode, addr, generic_cont0, nvm_cfg_addr; + u32 val; + + /* Read global nvm_cfg address */ + nvm_cfg_addr = qed_rd(p_hwfn, p_ptt, MISC_REG_GEN_PURP_CR0); + + /* Verify MCP has initialized it */ + if (!nvm_cfg_addr) { + DP_NOTICE(p_hwfn, "Shared memory not initialized\n"); + return -EINVAL; + } + + /* Read nvm_cfg1 (Notice this is just offset, and not offsize (TBD) */ + nvm_cfg1_offset = qed_rd(p_hwfn, p_ptt, nvm_cfg_addr + 4); + + /* Read Vendor Id / Device Id */ + addr = MCP_REG_SCRATCH + nvm_cfg1_offset + + offsetof(struct nvm_cfg1, glob) + + offsetof(struct nvm_cfg1_glob, pci_id); + p_hwfn->hw_info.vendor_id = qed_rd(p_hwfn, p_ptt, addr) & + NVM_CFG1_GLOB_VENDOR_ID_MASK; + addr = MCP_REG_SCRATCH + nvm_cfg1_offset + + offsetof(struct nvm_cfg1, func[MCP_PF_ID(p_hwfn)]) + + offsetof(struct nvm_cfg1_func, device_id); + val = qed_rd(p_hwfn, p_ptt, addr); + + if (IS_MF(p_hwfn)) { + p_hwfn->hw_info.device_id = + (val & NVM_CFG1_FUNC_MF_VENDOR_DEVICE_ID_MASK) >> + NVM_CFG1_FUNC_MF_VENDOR_DEVICE_ID_OFFSET; + } else { + p_hwfn->hw_info.device_id = + (val & NVM_CFG1_FUNC_VENDOR_DEVICE_ID_MASK) >> + NVM_CFG1_FUNC_VENDOR_DEVICE_ID_OFFSET; + } + + /* Read Multi-function information from shmem */ + addr = MCP_REG_SCRATCH + nvm_cfg1_offset + + offsetof(struct nvm_cfg1, glob) + + offsetof(struct nvm_cfg1_glob, generic_cont0); + + generic_cont0 = qed_rd(p_hwfn, p_ptt, addr); + + mf_mode = (generic_cont0 & NVM_CFG1_GLOB_MF_MODE_MASK) >> + NVM_CFG1_GLOB_MF_MODE_OFFSET; + + switch (mf_mode) { + case NVM_CFG1_GLOB_MF_MODE_MF_ALLOWED: + p_hwfn->cdev->mf_mode = MF_OVLAN; + break; + case NVM_CFG1_GLOB_MF_MODE_NPAR1_0: + p_hwfn->cdev->mf_mode = MF_NPAR; + break; + case NVM_CFG1_GLOB_MF_MODE_FORCED_SF: + p_hwfn->cdev->mf_mode = SF; + break; + } + DP_INFO(p_hwfn, "Multi function mode is %08x\n", + p_hwfn->cdev->mf_mode); + + return qed_mcp_fill_shmem_func_info(p_hwfn, p_ptt); +} + +static int +qed_get_hw_info(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + enum qed_pci_personality personality) +{ + u32 port_mode; + int rc; + + /* Read the port mode */ + port_mode = qed_rd(p_hwfn, p_ptt, + CNIG_REG_NW_PORT_MODE_BB_B0); + + if (port_mode < 3) { + p_hwfn->cdev->num_ports_in_engines = 1; + } else if (port_mode <= 5) { + p_hwfn->cdev->num_ports_in_engines = 2; + } else { + DP_NOTICE(p_hwfn, "PORT MODE: %d not supported\n", + p_hwfn->cdev->num_ports_in_engines); + + /* Default num_ports_in_engines to something */ + p_hwfn->cdev->num_ports_in_engines = 1; + } + + qed_hw_get_nvm_info(p_hwfn, p_ptt); + + rc = qed_int_igu_read_cam(p_hwfn, p_ptt); + if (rc) + return rc; + + if (qed_mcp_is_init(p_hwfn)) + ether_addr_copy(p_hwfn->hw_info.hw_mac_addr, + p_hwfn->mcp_info->func_info.mac); + else + eth_random_addr(p_hwfn->hw_info.hw_mac_addr); + + if (qed_mcp_is_init(p_hwfn)) { + if (p_hwfn->mcp_info->func_info.ovlan != QED_MCP_VLAN_UNSET) + p_hwfn->hw_info.ovlan = + p_hwfn->mcp_info->func_info.ovlan; + + qed_mcp_cmd_port_init(p_hwfn, p_ptt); + } + + if (qed_mcp_is_init(p_hwfn)) { + enum qed_pci_personality protocol; + + protocol = p_hwfn->mcp_info->func_info.protocol; + p_hwfn->hw_info.personality = protocol; + } + + qed_hw_get_resc(p_hwfn); + + return rc; +} + +static void qed_get_dev_info(struct qed_dev *cdev) +{ + u32 tmp; + + cdev->chip_num = (u16)qed_rd(cdev->hwfns, cdev->hwfns[0].p_main_ptt, + MISCS_REG_CHIP_NUM); + cdev->chip_rev = (u16)qed_rd(cdev->hwfns, cdev->hwfns[0].p_main_ptt, + MISCS_REG_CHIP_REV); + MASK_FIELD(CHIP_REV, cdev->chip_rev); + + /* Learn number of HW-functions */ + tmp = qed_rd(cdev->hwfns, cdev->hwfns[0].p_main_ptt, + MISCS_REG_CMT_ENABLED_FOR_PAIR); + + if (tmp & (1 << cdev->hwfns[0].rel_pf_id)) { + DP_NOTICE(cdev->hwfns, "device in CMT mode\n"); + cdev->num_hwfns = 2; + } else { + cdev->num_hwfns = 1; + } + + cdev->chip_bond_id = qed_rd(cdev->hwfns, cdev->hwfns[0].p_main_ptt, + MISCS_REG_CHIP_TEST_REG) >> 4; + MASK_FIELD(CHIP_BOND_ID, cdev->chip_bond_id); + cdev->chip_metal = (u16)qed_rd(cdev->hwfns, cdev->hwfns[0].p_main_ptt, + MISCS_REG_CHIP_METAL); + MASK_FIELD(CHIP_METAL, cdev->chip_metal); + + DP_INFO(cdev->hwfns, + "Chip details - Num: %04x Rev: %04x Bond id: %04x Metal: %04x\n", + cdev->chip_num, cdev->chip_rev, + cdev->chip_bond_id, cdev->chip_metal); +} + +static int qed_hw_prepare_single(struct qed_hwfn *p_hwfn, + void __iomem *p_regview, + void __iomem *p_doorbells, + enum qed_pci_personality personality) +{ + int rc = 0; + + /* Split PCI bars evenly between hwfns */ + p_hwfn->regview = p_regview; + p_hwfn->doorbells = p_doorbells; + + /* Validate that chip access is feasible */ + if (REG_RD(p_hwfn, PXP_PF_ME_OPAQUE_ADDR) == 0xffffffff) { + DP_ERR(p_hwfn, + "Reading the ME register returns all Fs; Preventing further chip access\n"); + return -EINVAL; + } + + get_function_id(p_hwfn); + + rc = qed_hw_hwfn_prepare(p_hwfn); + if (rc) { + DP_NOTICE(p_hwfn, "Failed to prepare hwfn's hw\n"); + goto err0; + } + + /* First hwfn learns basic information, e.g., number of hwfns */ + if (!p_hwfn->my_id) + qed_get_dev_info(p_hwfn->cdev); + + /* Initialize MCP structure */ + rc = qed_mcp_cmd_init(p_hwfn, p_hwfn->p_main_ptt); + if (rc) { + DP_NOTICE(p_hwfn, "Failed initializing mcp command\n"); + goto err1; + } + + /* Read the device configuration information from the HW and SHMEM */ + rc = qed_get_hw_info(p_hwfn, p_hwfn->p_main_ptt, personality); + if (rc) { + DP_NOTICE(p_hwfn, "Failed to get HW information\n"); + goto err2; + } + + /* Allocate the init RT array and initialize the init-ops engine */ + rc = qed_init_alloc(p_hwfn); + if (rc) { + DP_NOTICE(p_hwfn, "Failed to allocate the init array\n"); + goto err2; + } + + return rc; +err2: + qed_mcp_free(p_hwfn); +err1: + qed_hw_hwfn_free(p_hwfn); +err0: + return rc; +} + +static u32 qed_hw_bar_size(struct qed_dev *cdev, + u8 bar_id) +{ + u32 size = pci_resource_len(cdev->pdev, (bar_id > 0) ? 2 : 0); + + return size / cdev->num_hwfns; +} + +int qed_hw_prepare(struct qed_dev *cdev, + int personality) +{ + int rc, i; + + /* Store the precompiled init data ptrs */ + qed_init_iro_array(cdev); + + /* Initialize the first hwfn - will learn number of hwfns */ + rc = qed_hw_prepare_single(&cdev->hwfns[0], cdev->regview, + cdev->doorbells, personality); + if (rc) + return rc; + + personality = cdev->hwfns[0].hw_info.personality; + + /* Initialize the rest of the hwfns */ + for (i = 1; i < cdev->num_hwfns; i++) { + void __iomem *p_regview, *p_doorbell; + + p_regview = cdev->regview + + i * qed_hw_bar_size(cdev, 0); + p_doorbell = cdev->doorbells + + i * qed_hw_bar_size(cdev, 1); + rc = qed_hw_prepare_single(&cdev->hwfns[i], p_regview, + p_doorbell, personality); + if (rc) { + /* Cleanup previously initialized hwfns */ + while (--i >= 0) { + qed_init_free(&cdev->hwfns[i]); + qed_mcp_free(&cdev->hwfns[i]); + qed_hw_hwfn_free(&cdev->hwfns[i]); + } + return rc; + } + } + + return 0; +} + +void qed_hw_remove(struct qed_dev *cdev) +{ + int i; + + for_each_hwfn(cdev, i) { + struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; + + qed_init_free(p_hwfn); + qed_hw_hwfn_free(p_hwfn); + qed_mcp_free(p_hwfn); + } +} + +int qed_chain_alloc(struct qed_dev *cdev, + enum qed_chain_use_mode intended_use, + enum qed_chain_mode mode, + u16 num_elems, + size_t elem_size, + struct qed_chain *p_chain) +{ + dma_addr_t p_pbl_phys = 0; + void *p_pbl_virt = NULL; + dma_addr_t p_phys = 0; + void *p_virt = NULL; + u16 page_cnt = 0; + size_t size; + + if (mode == QED_CHAIN_MODE_SINGLE) + page_cnt = 1; + else + page_cnt = QED_CHAIN_PAGE_CNT(num_elems, elem_size, mode); + + size = page_cnt * QED_CHAIN_PAGE_SIZE; + p_virt = dma_alloc_coherent(&cdev->pdev->dev, + size, &p_phys, GFP_KERNEL); + if (!p_virt) { + DP_NOTICE(cdev, "Failed to allocate chain mem\n"); + goto nomem; + } + + if (mode == QED_CHAIN_MODE_PBL) { + size = page_cnt * QED_CHAIN_PBL_ENTRY_SIZE; + p_pbl_virt = dma_alloc_coherent(&cdev->pdev->dev, + size, &p_pbl_phys, + GFP_KERNEL); + if (!p_pbl_virt) { + DP_NOTICE(cdev, "Failed to allocate chain pbl mem\n"); + goto nomem; + } + + qed_chain_pbl_init(p_chain, p_virt, p_phys, page_cnt, + (u8)elem_size, intended_use, + p_pbl_phys, p_pbl_virt); + } else { + qed_chain_init(p_chain, p_virt, p_phys, page_cnt, + (u8)elem_size, intended_use, mode); + } + + return 0; + +nomem: + dma_free_coherent(&cdev->pdev->dev, + page_cnt * QED_CHAIN_PAGE_SIZE, + p_virt, p_phys); + dma_free_coherent(&cdev->pdev->dev, + page_cnt * QED_CHAIN_PBL_ENTRY_SIZE, + p_pbl_virt, p_pbl_phys); + + return -ENOMEM; +} + +void qed_chain_free(struct qed_dev *cdev, + struct qed_chain *p_chain) +{ + size_t size; + + if (!p_chain->p_virt_addr) + return; + + if (p_chain->mode == QED_CHAIN_MODE_PBL) { + size = p_chain->page_cnt * QED_CHAIN_PBL_ENTRY_SIZE; + dma_free_coherent(&cdev->pdev->dev, size, + p_chain->pbl.p_virt_table, + p_chain->pbl.p_phys_table); + } + + size = p_chain->page_cnt * QED_CHAIN_PAGE_SIZE; + dma_free_coherent(&cdev->pdev->dev, size, + p_chain->p_virt_addr, + p_chain->p_phys_addr); +} diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev_api.h b/drivers/net/ethernet/qlogic/qed/qed_dev_api.h new file mode 100644 index 000000000000..5051af5f378e --- /dev/null +++ b/drivers/net/ethernet/qlogic/qed/qed_dev_api.h @@ -0,0 +1,222 @@ +/* QLogic qed NIC Driver + * Copyright (c) 2015 QLogic Corporation + * + * This software is available under the terms of the GNU General Public License + * (GPL) Version 2, available from the file COPYING in the main directory of + * this source tree. + */ + +#ifndef _QED_DEV_API_H +#define _QED_DEV_API_H + +#include +#include +#include +#include +#include +#include "qed_int.h" + +/** + * @brief qed_init_dp - initialize the debug level + * + * @param cdev + * @param dp_module + * @param dp_level + */ +void qed_init_dp(struct qed_dev *cdev, + u32 dp_module, + u8 dp_level); + +/** + * @brief qed_init_struct - initialize the device structure to + * its defaults + * + * @param cdev + */ +void qed_init_struct(struct qed_dev *cdev); + +/** + * @brief qed_resc_free - + * + * @param cdev + */ +void qed_resc_free(struct qed_dev *cdev); + +/** + * @brief qed_resc_alloc - + * + * @param cdev + * + * @return int + */ +int qed_resc_alloc(struct qed_dev *cdev); + +/** + * @brief qed_resc_setup - + * + * @param cdev + */ +void qed_resc_setup(struct qed_dev *cdev); + +/** + * @brief qed_hw_init - + * + * @param cdev + * @param b_hw_start + * @param int_mode - interrupt mode [msix, inta, etc.] to use. + * @param allow_npar_tx_switch - npar tx switching to be used + * for vports configured for tx-switching. + * @param bin_fw_data - binary fw data pointer in binary fw file. + * Pass NULL if not using binary fw file. + * + * @return int + */ +int qed_hw_init(struct qed_dev *cdev, + bool b_hw_start, + enum qed_int_mode int_mode, + bool allow_npar_tx_switch, + const u8 *bin_fw_data); + +/** + * @brief qed_hw_stop - + * + * @param cdev + * + * @return int + */ +int qed_hw_stop(struct qed_dev *cdev); + +/** + * @brief qed_hw_reset - + * + * @param cdev + * + * @return int + */ +int qed_hw_reset(struct qed_dev *cdev); + +/** + * @brief qed_hw_prepare - + * + * @param cdev + * @param personality - personality to initialize + * + * @return int + */ +int qed_hw_prepare(struct qed_dev *cdev, + int personality); + +/** + * @brief qed_hw_remove - + * + * @param cdev + */ +void qed_hw_remove(struct qed_dev *cdev); + +/** + * @brief qed_ptt_acquire - Allocate a PTT window + * + * Should be called at the entry point to the driver (at the beginning of an + * exported function) + * + * @param p_hwfn + * + * @return struct qed_ptt + */ +struct qed_ptt *qed_ptt_acquire(struct qed_hwfn *p_hwfn); + +/** + * @brief qed_ptt_release - Release PTT Window + * + * Should be called at the end of a flow - at the end of the function that + * acquired the PTT. + * + * + * @param p_hwfn + * @param p_ptt + */ +void qed_ptt_release(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt); + +enum qed_dmae_address_type_t { + QED_DMAE_ADDRESS_HOST_VIRT, + QED_DMAE_ADDRESS_HOST_PHYS, + QED_DMAE_ADDRESS_GRC +}; + +/* value of flags If QED_DMAE_FLAG_RW_REPL_SRC flag is set and the + * source is a block of length DMAE_MAX_RW_SIZE and the + * destination is larger, the source block will be duplicated as + * many times as required to fill the destination block. This is + * used mostly to write a zeroed buffer to destination address + * using DMA + */ +#define QED_DMAE_FLAG_RW_REPL_SRC 0x00000001 +#define QED_DMAE_FLAG_COMPLETION_DST 0x00000008 + +struct qed_dmae_params { + u32 flags; /* consists of QED_DMAE_FLAG_* values */ +}; + +/** + * @brief qed_dmae_host2grc - copy data from source addr to + * dmae registers using the given ptt + * + * @param p_hwfn + * @param p_ptt + * @param source_addr + * @param grc_addr (dmae_data_offset) + * @param size_in_dwords + * @param flags (one of the flags defined above) + */ +int +qed_dmae_host2grc(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u64 source_addr, + u32 grc_addr, + u32 size_in_dwords, + u32 flags); + +/** + * @brief qed_chain_alloc - Allocate and initialize a chain + * + * @param p_hwfn + * @param intended_use + * @param mode + * @param num_elems + * @param elem_size + * @param p_chain + * + * @return int + */ +int +qed_chain_alloc(struct qed_dev *cdev, + enum qed_chain_use_mode intended_use, + enum qed_chain_mode mode, + u16 num_elems, + size_t elem_size, + struct qed_chain *p_chain); + +/** + * @brief qed_chain_free - Free chain DMA memory + * + * @param p_hwfn + * @param p_chain + */ +void qed_chain_free(struct qed_dev *cdev, + struct qed_chain *p_chain); + +/** + * *@brief Cleanup of previous driver remains prior to load + * + * @param p_hwfn + * @param p_ptt + * @param id - For PF, engine-relative. For VF, PF-relative. + * + * @return int + */ +int qed_final_cleanup(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u16 id); + +#endif diff --git a/drivers/net/ethernet/qlogic/qed/qed_hsi.h b/drivers/net/ethernet/qlogic/qed/qed_hsi.h new file mode 100644 index 000000000000..61c15a57c267 --- /dev/null +++ b/drivers/net/ethernet/qlogic/qed/qed_hsi.h @@ -0,0 +1,4966 @@ +/* QLogic qed NIC Driver + * Copyright (c) 2015 QLogic Corporation + * + * This software is available under the terms of the GNU General Public License + * (GPL) Version 2, available from the file COPYING in the main directory of + * this source tree. + */ + +#ifndef _QED_HSI_H +#define _QED_HSI_H + +#include +#include +#include +#include +#include +#include +#include +#include + +struct qed_hwfn; +struct qed_ptt; +/********************************/ +/* Add include to common target */ +/********************************/ + +/* opcodes for the event ring */ +enum common_event_opcode { + COMMON_EVENT_PF_START, + COMMON_EVENT_PF_STOP, + COMMON_EVENT_RESERVED, + COMMON_EVENT_RESERVED2, + COMMON_EVENT_RESERVED3, + COMMON_EVENT_RESERVED4, + COMMON_EVENT_RESERVED5, + MAX_COMMON_EVENT_OPCODE +}; + +/* Common Ramrod Command IDs */ +enum common_ramrod_cmd_id { + COMMON_RAMROD_UNUSED, + COMMON_RAMROD_PF_START /* PF Function Start Ramrod */, + COMMON_RAMROD_PF_STOP /* PF Function Stop Ramrod */, + COMMON_RAMROD_RESERVED, + COMMON_RAMROD_RESERVED2, + COMMON_RAMROD_RESERVED3, + MAX_COMMON_RAMROD_CMD_ID +}; + +/* The core storm context for the Ystorm */ +struct ystorm_core_conn_st_ctx { + __le32 reserved[4]; +}; + +/* The core storm context for the Pstorm */ +struct pstorm_core_conn_st_ctx { + __le32 reserved[4]; +}; + +/* Core Slowpath Connection storm context of Xstorm */ +struct xstorm_core_conn_st_ctx { + __le32 spq_base_lo /* SPQ Ring Base Address low dword */; + __le32 spq_base_hi /* SPQ Ring Base Address high dword */; + struct regpair consolid_base_addr; + __le16 spq_cons /* SPQ Ring Consumer */; + __le16 consolid_cons /* Consolidation Ring Consumer */; + __le32 reserved0[55] /* Pad to 15 cycles */; +}; + +struct xstorm_core_conn_ag_ctx { + u8 reserved0 /* cdu_validation */; + u8 core_state /* state */; + u8 flags0; +#define XSTORM_CORE_CONN_AG_CTX_EXIST_IN_QM0_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_EXIST_IN_QM0_SHIFT 0 +#define XSTORM_CORE_CONN_AG_CTX_RESERVED1_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_RESERVED1_SHIFT 1 +#define XSTORM_CORE_CONN_AG_CTX_RESERVED2_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_RESERVED2_SHIFT 2 +#define XSTORM_CORE_CONN_AG_CTX_EXIST_IN_QM3_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_EXIST_IN_QM3_SHIFT 3 +#define XSTORM_CORE_CONN_AG_CTX_RESERVED3_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_RESERVED3_SHIFT 4 +#define XSTORM_CORE_CONN_AG_CTX_RESERVED4_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_RESERVED4_SHIFT 5 +#define XSTORM_CORE_CONN_AG_CTX_RESERVED5_MASK 0x1 /* bit6 */ +#define XSTORM_CORE_CONN_AG_CTX_RESERVED5_SHIFT 6 +#define XSTORM_CORE_CONN_AG_CTX_RESERVED6_MASK 0x1 /* bit7 */ +#define XSTORM_CORE_CONN_AG_CTX_RESERVED6_SHIFT 7 + u8 flags1; +#define XSTORM_CORE_CONN_AG_CTX_RESERVED7_MASK 0x1 /* bit8 */ +#define XSTORM_CORE_CONN_AG_CTX_RESERVED7_SHIFT 0 +#define XSTORM_CORE_CONN_AG_CTX_RESERVED8_MASK 0x1 /* bit9 */ +#define XSTORM_CORE_CONN_AG_CTX_RESERVED8_SHIFT 1 +#define XSTORM_CORE_CONN_AG_CTX_RESERVED9_MASK 0x1 /* bit10 */ +#define XSTORM_CORE_CONN_AG_CTX_RESERVED9_SHIFT 2 +#define XSTORM_CORE_CONN_AG_CTX_BIT11_MASK 0x1 /* bit11 */ +#define XSTORM_CORE_CONN_AG_CTX_BIT11_SHIFT 3 +#define XSTORM_CORE_CONN_AG_CTX_BIT12_MASK 0x1 /* bit12 */ +#define XSTORM_CORE_CONN_AG_CTX_BIT12_SHIFT 4 +#define XSTORM_CORE_CONN_AG_CTX_BIT13_MASK 0x1 /* bit13 */ +#define XSTORM_CORE_CONN_AG_CTX_BIT13_SHIFT 5 +#define XSTORM_CORE_CONN_AG_CTX_TX_RULE_ACTIVE_MASK 0x1 /* bit14 */ +#define XSTORM_CORE_CONN_AG_CTX_TX_RULE_ACTIVE_SHIFT 6 +#define XSTORM_CORE_CONN_AG_CTX_DQ_CF_ACTIVE_MASK 0x1 /* bit15 */ +#define XSTORM_CORE_CONN_AG_CTX_DQ_CF_ACTIVE_SHIFT 7 + u8 flags2; +#define XSTORM_CORE_CONN_AG_CTX_CF0_MASK 0x3 /* timer0cf */ +#define XSTORM_CORE_CONN_AG_CTX_CF0_SHIFT 0 +#define XSTORM_CORE_CONN_AG_CTX_CF1_MASK 0x3 /* timer1cf */ +#define XSTORM_CORE_CONN_AG_CTX_CF1_SHIFT 2 +#define XSTORM_CORE_CONN_AG_CTX_CF2_MASK 0x3 /* timer2cf */ +#define XSTORM_CORE_CONN_AG_CTX_CF2_SHIFT 4 +#define XSTORM_CORE_CONN_AG_CTX_CF3_MASK 0x3 +#define XSTORM_CORE_CONN_AG_CTX_CF3_SHIFT 6 + u8 flags3; +#define XSTORM_CORE_CONN_AG_CTX_CF4_MASK 0x3 /* cf4 */ +#define XSTORM_CORE_CONN_AG_CTX_CF4_SHIFT 0 +#define XSTORM_CORE_CONN_AG_CTX_CF5_MASK 0x3 /* cf5 */ +#define XSTORM_CORE_CONN_AG_CTX_CF5_SHIFT 2 +#define XSTORM_CORE_CONN_AG_CTX_CF6_MASK 0x3 /* cf6 */ +#define XSTORM_CORE_CONN_AG_CTX_CF6_SHIFT 4 +#define XSTORM_CORE_CONN_AG_CTX_CF7_MASK 0x3 /* cf7 */ +#define XSTORM_CORE_CONN_AG_CTX_CF7_SHIFT 6 + u8 flags4; +#define XSTORM_CORE_CONN_AG_CTX_CF8_MASK 0x3 /* cf8 */ +#define XSTORM_CORE_CONN_AG_CTX_CF8_SHIFT 0 +#define XSTORM_CORE_CONN_AG_CTX_CF9_MASK 0x3 /* cf9 */ +#define XSTORM_CORE_CONN_AG_CTX_CF9_SHIFT 2 +#define XSTORM_CORE_CONN_AG_CTX_CF10_MASK 0x3 /* cf10 */ +#define XSTORM_CORE_CONN_AG_CTX_CF10_SHIFT 4 +#define XSTORM_CORE_CONN_AG_CTX_CF11_MASK 0x3 /* cf11 */ +#define XSTORM_CORE_CONN_AG_CTX_CF11_SHIFT 6 + u8 flags5; +#define XSTORM_CORE_CONN_AG_CTX_CF12_MASK 0x3 /* cf12 */ +#define XSTORM_CORE_CONN_AG_CTX_CF12_SHIFT 0 +#define XSTORM_CORE_CONN_AG_CTX_CF13_MASK 0x3 /* cf13 */ +#define XSTORM_CORE_CONN_AG_CTX_CF13_SHIFT 2 +#define XSTORM_CORE_CONN_AG_CTX_CF14_MASK 0x3 /* cf14 */ +#define XSTORM_CORE_CONN_AG_CTX_CF14_SHIFT 4 +#define XSTORM_CORE_CONN_AG_CTX_CF15_MASK 0x3 /* cf15 */ +#define XSTORM_CORE_CONN_AG_CTX_CF15_SHIFT 6 + u8 flags6; +#define XSTORM_CORE_CONN_AG_CTX_CONSOLID_PROD_CF_MASK 0x3 /* cf16 */ +#define XSTORM_CORE_CONN_AG_CTX_CONSOLID_PROD_CF_SHIFT 0 +#define XSTORM_CORE_CONN_AG_CTX_CF17_MASK 0x3 +#define XSTORM_CORE_CONN_AG_CTX_CF17_SHIFT 2 +#define XSTORM_CORE_CONN_AG_CTX_DQ_CF_MASK 0x3 /* cf18 */ +#define XSTORM_CORE_CONN_AG_CTX_DQ_CF_SHIFT 4 +#define XSTORM_CORE_CONN_AG_CTX_TERMINATE_CF_MASK 0x3 /* cf19 */ +#define XSTORM_CORE_CONN_AG_CTX_TERMINATE_CF_SHIFT 6 + u8 flags7; +#define XSTORM_CORE_CONN_AG_CTX_FLUSH_Q0_MASK 0x3 /* cf20 */ +#define XSTORM_CORE_CONN_AG_CTX_FLUSH_Q0_SHIFT 0 +#define XSTORM_CORE_CONN_AG_CTX_RESERVED10_MASK 0x3 /* cf21 */ +#define XSTORM_CORE_CONN_AG_CTX_RESERVED10_SHIFT 2 +#define XSTORM_CORE_CONN_AG_CTX_SLOW_PATH_MASK 0x3 /* cf22 */ +#define XSTORM_CORE_CONN_AG_CTX_SLOW_PATH_SHIFT 4 +#define XSTORM_CORE_CONN_AG_CTX_CF0EN_MASK 0x1 /* cf0en */ +#define XSTORM_CORE_CONN_AG_CTX_CF0EN_SHIFT 6 +#define XSTORM_CORE_CONN_AG_CTX_CF1EN_MASK 0x1 /* cf1en */ +#define XSTORM_CORE_CONN_AG_CTX_CF1EN_SHIFT 7 + u8 flags8; +#define XSTORM_CORE_CONN_AG_CTX_CF2EN_MASK 0x1 /* cf2en */ +#define XSTORM_CORE_CONN_AG_CTX_CF2EN_SHIFT 0 +#define XSTORM_CORE_CONN_AG_CTX_CF3EN_MASK 0x1 /* cf3en */ +#define XSTORM_CORE_CONN_AG_CTX_CF3EN_SHIFT 1 +#define XSTORM_CORE_CONN_AG_CTX_CF4EN_MASK 0x1 /* cf4en */ +#define XSTORM_CORE_CONN_AG_CTX_CF4EN_SHIFT 2 +#define XSTORM_CORE_CONN_AG_CTX_CF5EN_MASK 0x1 /* cf5en */ +#define XSTORM_CORE_CONN_AG_CTX_CF5EN_SHIFT 3 +#define XSTORM_CORE_CONN_AG_CTX_CF6EN_MASK 0x1 /* cf6en */ +#define XSTORM_CORE_CONN_AG_CTX_CF6EN_SHIFT 4 +#define XSTORM_CORE_CONN_AG_CTX_CF7EN_MASK 0x1 /* cf7en */ +#define XSTORM_CORE_CONN_AG_CTX_CF7EN_SHIFT 5 +#define XSTORM_CORE_CONN_AG_CTX_CF8EN_MASK 0x1 /* cf8en */ +#define XSTORM_CORE_CONN_AG_CTX_CF8EN_SHIFT 6 +#define XSTORM_CORE_CONN_AG_CTX_CF9EN_MASK 0x1 /* cf9en */ +#define XSTORM_CORE_CONN_AG_CTX_CF9EN_SHIFT 7 + u8 flags9; +#define XSTORM_CORE_CONN_AG_CTX_CF10EN_MASK 0x1 /* cf10en */ +#define XSTORM_CORE_CONN_AG_CTX_CF10EN_SHIFT 0 +#define XSTORM_CORE_CONN_AG_CTX_CF11EN_MASK 0x1 /* cf11en */ +#define XSTORM_CORE_CONN_AG_CTX_CF11EN_SHIFT 1 +#define XSTORM_CORE_CONN_AG_CTX_CF12EN_MASK 0x1 /* cf12en */ +#define XSTORM_CORE_CONN_AG_CTX_CF12EN_SHIFT 2 +#define XSTORM_CORE_CONN_AG_CTX_CF13EN_MASK 0x1 /* cf13en */ +#define XSTORM_CORE_CONN_AG_CTX_CF13EN_SHIFT 3 +#define XSTORM_CORE_CONN_AG_CTX_CF14EN_MASK 0x1 /* cf14en */ +#define XSTORM_CORE_CONN_AG_CTX_CF14EN_SHIFT 4 +#define XSTORM_CORE_CONN_AG_CTX_CF15EN_MASK 0x1 /* cf15en */ +#define XSTORM_CORE_CONN_AG_CTX_CF15EN_SHIFT 5 +#define XSTORM_CORE_CONN_AG_CTX_CONSOLID_PROD_CF_EN_MASK 0x1 /* cf16en */ +#define XSTORM_CORE_CONN_AG_CTX_CONSOLID_PROD_CF_EN_SHIFT 6 +#define XSTORM_CORE_CONN_AG_CTX_CF17EN_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_CF17EN_SHIFT 7 + u8 flags10; +#define XSTORM_CORE_CONN_AG_CTX_DQ_CF_EN_MASK 0x1 /* cf18en */ +#define XSTORM_CORE_CONN_AG_CTX_DQ_CF_EN_SHIFT 0 +#define XSTORM_CORE_CONN_AG_CTX_TERMINATE_CF_EN_MASK 0x1 /* cf19en */ +#define XSTORM_CORE_CONN_AG_CTX_TERMINATE_CF_EN_SHIFT 1 +#define XSTORM_CORE_CONN_AG_CTX_FLUSH_Q0_EN_MASK 0x1 /* cf20en */ +#define XSTORM_CORE_CONN_AG_CTX_FLUSH_Q0_EN_SHIFT 2 +#define XSTORM_CORE_CONN_AG_CTX_RESERVED11_MASK 0x1 /* cf21en */ +#define XSTORM_CORE_CONN_AG_CTX_RESERVED11_SHIFT 3 +#define XSTORM_CORE_CONN_AG_CTX_SLOW_PATH_EN_MASK 0x1 /* cf22en */ +#define XSTORM_CORE_CONN_AG_CTX_SLOW_PATH_EN_SHIFT 4 +#define XSTORM_CORE_CONN_AG_CTX_CF23EN_MASK 0x1 /* cf23en */ +#define XSTORM_CORE_CONN_AG_CTX_CF23EN_SHIFT 5 +#define XSTORM_CORE_CONN_AG_CTX_RESERVED12_MASK 0x1 /* rule0en */ +#define XSTORM_CORE_CONN_AG_CTX_RESERVED12_SHIFT 6 +#define XSTORM_CORE_CONN_AG_CTX_RESERVED13_MASK 0x1 /* rule1en */ +#define XSTORM_CORE_CONN_AG_CTX_RESERVED13_SHIFT 7 + u8 flags11; +#define XSTORM_CORE_CONN_AG_CTX_RESERVED14_MASK 0x1 /* rule2en */ +#define XSTORM_CORE_CONN_AG_CTX_RESERVED14_SHIFT 0 +#define XSTORM_CORE_CONN_AG_CTX_RESERVED15_MASK 0x1 /* rule3en */ +#define XSTORM_CORE_CONN_AG_CTX_RESERVED15_SHIFT 1 +#define XSTORM_CORE_CONN_AG_CTX_TX_DEC_RULE_EN_MASK 0x1 /* rule4en */ +#define XSTORM_CORE_CONN_AG_CTX_TX_DEC_RULE_EN_SHIFT 2 +#define XSTORM_CORE_CONN_AG_CTX_RULE5EN_MASK 0x1 /* rule5en */ +#define XSTORM_CORE_CONN_AG_CTX_RULE5EN_SHIFT 3 +#define XSTORM_CORE_CONN_AG_CTX_RULE6EN_MASK 0x1 /* rule6en */ +#define XSTORM_CORE_CONN_AG_CTX_RULE6EN_SHIFT 4 +#define XSTORM_CORE_CONN_AG_CTX_RULE7EN_MASK 0x1 /* rule7en */ +#define XSTORM_CORE_CONN_AG_CTX_RULE7EN_SHIFT 5 +#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED1_MASK 0x1 /* rule8en */ +#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED1_SHIFT 6 +#define XSTORM_CORE_CONN_AG_CTX_RULE9EN_MASK 0x1 /* rule9en */ +#define XSTORM_CORE_CONN_AG_CTX_RULE9EN_SHIFT 7 + u8 flags12; +#define XSTORM_CORE_CONN_AG_CTX_RULE10EN_MASK 0x1 /* rule10en */ +#define XSTORM_CORE_CONN_AG_CTX_RULE10EN_SHIFT 0 +#define XSTORM_CORE_CONN_AG_CTX_RULE11EN_MASK 0x1 /* rule11en */ +#define XSTORM_CORE_CONN_AG_CTX_RULE11EN_SHIFT 1 +#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED2_MASK 0x1 /* rule12en */ +#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED2_SHIFT 2 +#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED3_MASK 0x1 /* rule13en */ +#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED3_SHIFT 3 +#define XSTORM_CORE_CONN_AG_CTX_RULE14EN_MASK 0x1 /* rule14en */ +#define XSTORM_CORE_CONN_AG_CTX_RULE14EN_SHIFT 4 +#define XSTORM_CORE_CONN_AG_CTX_RULE15EN_MASK 0x1 /* rule15en */ +#define XSTORM_CORE_CONN_AG_CTX_RULE15EN_SHIFT 5 +#define XSTORM_CORE_CONN_AG_CTX_RULE16EN_MASK 0x1 /* rule16en */ +#define XSTORM_CORE_CONN_AG_CTX_RULE16EN_SHIFT 6 +#define XSTORM_CORE_CONN_AG_CTX_RULE17EN_MASK 0x1 /* rule17en */ +#define XSTORM_CORE_CONN_AG_CTX_RULE17EN_SHIFT 7 + u8 flags13; +#define XSTORM_CORE_CONN_AG_CTX_RULE18EN_MASK 0x1 /* rule18en */ +#define XSTORM_CORE_CONN_AG_CTX_RULE18EN_SHIFT 0 +#define XSTORM_CORE_CONN_AG_CTX_RULE19EN_MASK 0x1 /* rule19en */ +#define XSTORM_CORE_CONN_AG_CTX_RULE19EN_SHIFT 1 +#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED4_MASK 0x1 /* rule20en */ +#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED4_SHIFT 2 +#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED5_MASK 0x1 /* rule21en */ +#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED5_SHIFT 3 +#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED6_MASK 0x1 /* rule22en */ +#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED6_SHIFT 4 +#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED7_MASK 0x1 /* rule23en */ +#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED7_SHIFT 5 +#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED8_MASK 0x1 /* rule24en */ +#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED8_SHIFT 6 +#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED9_MASK 0x1 /* rule25en */ +#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED9_SHIFT 7 + u8 flags14; +#define XSTORM_CORE_CONN_AG_CTX_BIT16_MASK 0x1 /* bit16 */ +#define XSTORM_CORE_CONN_AG_CTX_BIT16_SHIFT 0 +#define XSTORM_CORE_CONN_AG_CTX_BIT17_MASK 0x1 /* bit17 */ +#define XSTORM_CORE_CONN_AG_CTX_BIT17_SHIFT 1 +#define XSTORM_CORE_CONN_AG_CTX_BIT18_MASK 0x1 /* bit18 */ +#define XSTORM_CORE_CONN_AG_CTX_BIT18_SHIFT 2 +#define XSTORM_CORE_CONN_AG_CTX_BIT19_MASK 0x1 /* bit19 */ +#define XSTORM_CORE_CONN_AG_CTX_BIT19_SHIFT 3 +#define XSTORM_CORE_CONN_AG_CTX_BIT20_MASK 0x1 /* bit20 */ +#define XSTORM_CORE_CONN_AG_CTX_BIT20_SHIFT 4 +#define XSTORM_CORE_CONN_AG_CTX_BIT21_MASK 0x1 /* bit21 */ +#define XSTORM_CORE_CONN_AG_CTX_BIT21_SHIFT 5 +#define XSTORM_CORE_CONN_AG_CTX_CF23_MASK 0x3 /* cf23 */ +#define XSTORM_CORE_CONN_AG_CTX_CF23_SHIFT 6 + u8 byte2 /* byte2 */; + __le16 physical_q0 /* physical_q0 */; + __le16 consolid_prod /* physical_q1 */; + __le16 reserved16 /* physical_q2 */; + __le16 tx_bd_cons /* word3 */; + __le16 tx_bd_or_spq_prod /* word4 */; + __le16 word5 /* word5 */; + __le16 conn_dpi /* conn_dpi */; + u8 byte3 /* byte3 */; + u8 byte4 /* byte4 */; + u8 byte5 /* byte5 */; + u8 byte6 /* byte6 */; + __le32 reg0 /* reg0 */; + __le32 reg1 /* reg1 */; + __le32 reg2 /* reg2 */; + __le32 reg3 /* reg3 */; + __le32 reg4 /* reg4 */; + __le32 reg5 /* cf_array0 */; + __le32 reg6 /* cf_array1 */; + __le16 word7 /* word7 */; + __le16 word8 /* word8 */; + __le16 word9 /* word9 */; + __le16 word10 /* word10 */; + __le32 reg7 /* reg7 */; + __le32 reg8 /* reg8 */; + __le32 reg9 /* reg9 */; + u8 byte7 /* byte7 */; + u8 byte8 /* byte8 */; + u8 byte9 /* byte9 */; + u8 byte10 /* byte10 */; + u8 byte11 /* byte11 */; + u8 byte12 /* byte12 */; + u8 byte13 /* byte13 */; + u8 byte14 /* byte14 */; + u8 byte15 /* byte15 */; + u8 byte16 /* byte16 */; + __le16 word11 /* word11 */; + __le32 reg10 /* reg10 */; + __le32 reg11 /* reg11 */; + __le32 reg12 /* reg12 */; + __le32 reg13 /* reg13 */; + __le32 reg14 /* reg14 */; + __le32 reg15 /* reg15 */; + __le32 reg16 /* reg16 */; + __le32 reg17 /* reg17 */; + __le32 reg18 /* reg18 */; + __le32 reg19 /* reg19 */; + __le16 word12 /* word12 */; + __le16 word13 /* word13 */; + __le16 word14 /* word14 */; + __le16 word15 /* word15 */; +}; + +/* The core storm context for the Mstorm */ +struct mstorm_core_conn_st_ctx { + __le32 reserved[24]; +}; + +/* The core storm context for the Ustorm */ +struct ustorm_core_conn_st_ctx { + __le32 reserved[4]; +}; + +/* core connection context */ +struct core_conn_context { + struct ystorm_core_conn_st_ctx ystorm_st_context; + struct regpair ystorm_st_padding[2] /* padding */; + struct pstorm_core_conn_st_ctx pstorm_st_context; + struct regpair pstorm_st_padding[2]; + struct xstorm_core_conn_st_ctx xstorm_st_context; + struct xstorm_core_conn_ag_ctx xstorm_ag_context; + struct mstorm_core_conn_st_ctx mstorm_st_context; + struct regpair mstorm_st_padding[2]; + struct ustorm_core_conn_st_ctx ustorm_st_context; + struct regpair ustorm_st_padding[2] /* padding */; +}; + +/* Event Ring Next Page Address */ +struct event_ring_next_addr { + struct regpair addr /* Next Page Address */; + __le32 reserved[2] /* Reserved */; +}; + +union event_ring_element { + struct event_ring_entry entry /* Event Ring Entry */; + struct event_ring_next_addr next_addr; +}; + +enum personality_type { + PERSONALITY_RESERVED, + PERSONALITY_RESERVED2, + PERSONALITY_RDMA_AND_ETH /* Roce or Iwarp */, + PERSONALITY_RESERVED3, + PERSONALITY_ETH /* Ethernet */, + PERSONALITY_RESERVED4, + MAX_PERSONALITY_TYPE +}; + +struct pf_start_tunnel_config { + u8 set_vxlan_udp_port_flg; + u8 set_geneve_udp_port_flg; + u8 tx_enable_vxlan /* If set, enable VXLAN tunnel in TX path. */; + u8 tx_enable_l2geneve; + u8 tx_enable_ipgeneve; + u8 tx_enable_l2gre /* If set, enable l2 GRE tunnel in TX path. */; + u8 tx_enable_ipgre /* If set, enable IP GRE tunnel in TX path. */; + u8 tunnel_clss_vxlan /* Classification scheme for VXLAN tunnel. */; + u8 tunnel_clss_l2geneve; + u8 tunnel_clss_ipgeneve; + u8 tunnel_clss_l2gre; + u8 tunnel_clss_ipgre; + __le16 vxlan_udp_port /* VXLAN tunnel UDP destination port. */; + __le16 geneve_udp_port /* GENEVE tunnel UDP destination port. */; +}; + +/* Ramrod data for PF start ramrod */ +struct pf_start_ramrod_data { + struct regpair event_ring_pbl_addr; + struct regpair consolid_q_pbl_addr; + struct pf_start_tunnel_config tunnel_config; + __le16 event_ring_sb_id; + u8 base_vf_id; + u8 num_vfs; + u8 event_ring_num_pages; + u8 event_ring_sb_index; + u8 path_id; + u8 warning_as_error; + u8 dont_log_ramrods; + u8 personality; + __le16 log_type_mask; + u8 mf_mode /* Multi function mode */; + u8 integ_phase /* Integration phase */; + u8 allow_npar_tx_switching; + u8 inner_to_outer_pri_map[8]; + u8 pri_map_valid; + u32 outer_tag; + u8 reserved0[4]; +}; + +enum ports_mode { + ENGX2_PORTX1 /* 2 engines x 1 port */, + ENGX2_PORTX2 /* 2 engines x 2 ports */, + ENGX1_PORTX1 /* 1 engine x 1 port */, + ENGX1_PORTX2 /* 1 engine x 2 ports */, + ENGX1_PORTX4 /* 1 engine x 4 ports */, + MAX_PORTS_MODE +}; + +/* Ramrod Header of SPQE */ +struct ramrod_header { + __le32 cid /* Slowpath Connection CID */; + u8 cmd_id /* Ramrod Cmd (Per Protocol Type) */; + u8 protocol_id /* Ramrod Protocol ID */; + __le16 echo /* Ramrod echo */; +}; + +/* Slowpath Element (SPQE) */ +struct slow_path_element { + struct ramrod_header hdr /* Ramrod Header */; + struct regpair data_ptr; +}; + +struct tstorm_per_port_stat { + struct regpair trunc_error_discard; + struct regpair mac_error_discard; + struct regpair mftag_filter_discard; + struct regpair eth_mac_filter_discard; + struct regpair ll2_mac_filter_discard; + struct regpair ll2_conn_disabled_discard; + struct regpair iscsi_irregular_pkt; + struct regpair fcoe_irregular_pkt; + struct regpair roce_irregular_pkt; + struct regpair eth_irregular_pkt; + struct regpair toe_irregular_pkt; + struct regpair preroce_irregular_pkt; +}; + +struct atten_status_block { + __le32 atten_bits; + __le32 atten_ack; + __le16 reserved0; + __le16 sb_index /* status block running index */; + __le32 reserved1; +}; + +enum block_addr { + GRCBASE_GRC = 0x50000, + GRCBASE_MISCS = 0x9000, + GRCBASE_MISC = 0x8000, + GRCBASE_DBU = 0xa000, + GRCBASE_PGLUE_B = 0x2a8000, + GRCBASE_CNIG = 0x218000, + GRCBASE_CPMU = 0x30000, + GRCBASE_NCSI = 0x40000, + GRCBASE_OPTE = 0x53000, + GRCBASE_BMB = 0x540000, + GRCBASE_PCIE = 0x54000, + GRCBASE_MCP = 0xe00000, + GRCBASE_MCP2 = 0x52000, + GRCBASE_PSWHST = 0x2a0000, + GRCBASE_PSWHST2 = 0x29e000, + GRCBASE_PSWRD = 0x29c000, + GRCBASE_PSWRD2 = 0x29d000, + GRCBASE_PSWWR = 0x29a000, + GRCBASE_PSWWR2 = 0x29b000, + GRCBASE_PSWRQ = 0x280000, + GRCBASE_PSWRQ2 = 0x240000, + GRCBASE_PGLCS = 0x0, + GRCBASE_PTU = 0x560000, + GRCBASE_DMAE = 0xc000, + GRCBASE_TCM = 0x1180000, + GRCBASE_MCM = 0x1200000, + GRCBASE_UCM = 0x1280000, + GRCBASE_XCM = 0x1000000, + GRCBASE_YCM = 0x1080000, + GRCBASE_PCM = 0x1100000, + GRCBASE_QM = 0x2f0000, + GRCBASE_TM = 0x2c0000, + GRCBASE_DORQ = 0x100000, + GRCBASE_BRB = 0x340000, + GRCBASE_SRC = 0x238000, + GRCBASE_PRS = 0x1f0000, + GRCBASE_TSDM = 0xfb0000, + GRCBASE_MSDM = 0xfc0000, + GRCBASE_USDM = 0xfd0000, + GRCBASE_XSDM = 0xf80000, + GRCBASE_YSDM = 0xf90000, + GRCBASE_PSDM = 0xfa0000, + GRCBASE_TSEM = 0x1700000, + GRCBASE_MSEM = 0x1800000, + GRCBASE_USEM = 0x1900000, + GRCBASE_XSEM = 0x1400000, + GRCBASE_YSEM = 0x1500000, + GRCBASE_PSEM = 0x1600000, + GRCBASE_RSS = 0x238800, + GRCBASE_TMLD = 0x4d0000, + GRCBASE_MULD = 0x4e0000, + GRCBASE_YULD = 0x4c8000, + GRCBASE_XYLD = 0x4c0000, + GRCBASE_PRM = 0x230000, + GRCBASE_PBF_PB1 = 0xda0000, + GRCBASE_PBF_PB2 = 0xda4000, + GRCBASE_RPB = 0x23c000, + GRCBASE_BTB = 0xdb0000, + GRCBASE_PBF = 0xd80000, + GRCBASE_RDIF = 0x300000, + GRCBASE_TDIF = 0x310000, + GRCBASE_CDU = 0x580000, + GRCBASE_CCFC = 0x2e0000, + GRCBASE_TCFC = 0x2d0000, + GRCBASE_IGU = 0x180000, + GRCBASE_CAU = 0x1c0000, + GRCBASE_UMAC = 0x51000, + GRCBASE_XMAC = 0x210000, + GRCBASE_DBG = 0x10000, + GRCBASE_NIG = 0x500000, + GRCBASE_WOL = 0x600000, + GRCBASE_BMBN = 0x610000, + GRCBASE_IPC = 0x20000, + GRCBASE_NWM = 0x800000, + GRCBASE_NWS = 0x700000, + GRCBASE_MS = 0x6a0000, + GRCBASE_PHY_PCIE = 0x618000, + GRCBASE_MISC_AEU = 0x8000, + GRCBASE_BAR0_MAP = 0x1c00000, + MAX_BLOCK_ADDR +}; + +enum block_id { + BLOCK_GRC, + BLOCK_MISCS, + BLOCK_MISC, + BLOCK_DBU, + BLOCK_PGLUE_B, + BLOCK_CNIG, + BLOCK_CPMU, + BLOCK_NCSI, + BLOCK_OPTE, + BLOCK_BMB, + BLOCK_PCIE, + BLOCK_MCP, + BLOCK_MCP2, + BLOCK_PSWHST, + BLOCK_PSWHST2, + BLOCK_PSWRD, + BLOCK_PSWRD2, + BLOCK_PSWWR, + BLOCK_PSWWR2, + BLOCK_PSWRQ, + BLOCK_PSWRQ2, + BLOCK_PGLCS, + BLOCK_PTU, + BLOCK_DMAE, + BLOCK_TCM, + BLOCK_MCM, + BLOCK_UCM, + BLOCK_XCM, + BLOCK_YCM, + BLOCK_PCM, + BLOCK_QM, + BLOCK_TM, + BLOCK_DORQ, + BLOCK_BRB, + BLOCK_SRC, + BLOCK_PRS, + BLOCK_TSDM, + BLOCK_MSDM, + BLOCK_USDM, + BLOCK_XSDM, + BLOCK_YSDM, + BLOCK_PSDM, + BLOCK_TSEM, + BLOCK_MSEM, + BLOCK_USEM, + BLOCK_XSEM, + BLOCK_YSEM, + BLOCK_PSEM, + BLOCK_RSS, + BLOCK_TMLD, + BLOCK_MULD, + BLOCK_YULD, + BLOCK_XYLD, + BLOCK_PRM, + BLOCK_PBF_PB1, + BLOCK_PBF_PB2, + BLOCK_RPB, + BLOCK_BTB, + BLOCK_PBF, + BLOCK_RDIF, + BLOCK_TDIF, + BLOCK_CDU, + BLOCK_CCFC, + BLOCK_TCFC, + BLOCK_IGU, + BLOCK_CAU, + BLOCK_UMAC, + BLOCK_XMAC, + BLOCK_DBG, + BLOCK_NIG, + BLOCK_WOL, + BLOCK_BMBN, + BLOCK_IPC, + BLOCK_NWM, + BLOCK_NWS, + BLOCK_MS, + BLOCK_PHY_PCIE, + BLOCK_MISC_AEU, + BLOCK_BAR0_MAP, + MAX_BLOCK_ID +}; + +enum command_type_bit { + IGU_COMMAND_TYPE_NOP = 0, + IGU_COMMAND_TYPE_SET = 1, + MAX_COMMAND_TYPE_BIT +}; + +struct dmae_cmd { + __le32 opcode; +#define DMAE_CMD_SRC_MASK 0x1 +#define DMAE_CMD_SRC_SHIFT 0 +#define DMAE_CMD_DST_MASK 0x3 +#define DMAE_CMD_DST_SHIFT 1 +#define DMAE_CMD_C_DST_MASK 0x1 +#define DMAE_CMD_C_DST_SHIFT 3 +#define DMAE_CMD_CRC_RESET_MASK 0x1 +#define DMAE_CMD_CRC_RESET_SHIFT 4 +#define DMAE_CMD_SRC_ADDR_RESET_MASK 0x1 +#define DMAE_CMD_SRC_ADDR_RESET_SHIFT 5 +#define DMAE_CMD_DST_ADDR_RESET_MASK 0x1 +#define DMAE_CMD_DST_ADDR_RESET_SHIFT 6 +#define DMAE_CMD_COMP_FUNC_MASK 0x1 +#define DMAE_CMD_COMP_FUNC_SHIFT 7 +#define DMAE_CMD_COMP_WORD_EN_MASK 0x1 +#define DMAE_CMD_COMP_WORD_EN_SHIFT 8 +#define DMAE_CMD_COMP_CRC_EN_MASK 0x1 +#define DMAE_CMD_COMP_CRC_EN_SHIFT 9 +#define DMAE_CMD_COMP_CRC_OFFSET_MASK 0x7 +#define DMAE_CMD_COMP_CRC_OFFSET_SHIFT 10 +#define DMAE_CMD_RESERVED1_MASK 0x1 +#define DMAE_CMD_RESERVED1_SHIFT 13 +#define DMAE_CMD_ENDIANITY_MODE_MASK 0x3 +#define DMAE_CMD_ENDIANITY_MODE_SHIFT 14 +#define DMAE_CMD_ERR_HANDLING_MASK 0x3 +#define DMAE_CMD_ERR_HANDLING_SHIFT 16 +#define DMAE_CMD_PORT_ID_MASK 0x3 +#define DMAE_CMD_PORT_ID_SHIFT 18 +#define DMAE_CMD_SRC_PF_ID_MASK 0xF +#define DMAE_CMD_SRC_PF_ID_SHIFT 20 +#define DMAE_CMD_DST_PF_ID_MASK 0xF +#define DMAE_CMD_DST_PF_ID_SHIFT 24 +#define DMAE_CMD_SRC_VF_ID_VALID_MASK 0x1 +#define DMAE_CMD_SRC_VF_ID_VALID_SHIFT 28 +#define DMAE_CMD_DST_VF_ID_VALID_MASK 0x1 +#define DMAE_CMD_DST_VF_ID_VALID_SHIFT 29 +#define DMAE_CMD_RESERVED2_MASK 0x3 +#define DMAE_CMD_RESERVED2_SHIFT 30 + __le32 src_addr_lo; + __le32 src_addr_hi; + __le32 dst_addr_lo; + __le32 dst_addr_hi; + __le16 length /* Length in DW */; + __le16 opcode_b; +#define DMAE_CMD_SRC_VF_ID_MASK 0xFF /* Source VF id */ +#define DMAE_CMD_SRC_VF_ID_SHIFT 0 +#define DMAE_CMD_DST_VF_ID_MASK 0xFF /* Destination VF id */ +#define DMAE_CMD_DST_VF_ID_SHIFT 8 + __le32 comp_addr_lo /* PCIe completion address low or grc address */; + __le32 comp_addr_hi; + __le32 comp_val /* Value to write to copmletion address */; + __le32 crc32 /* crc16 result */; + __le32 crc_32_c /* crc32_c result */; + __le16 crc16 /* crc16 result */; + __le16 crc16_c /* crc16_c result */; + __le16 crc10 /* crc_t10 result */; + __le16 reserved; + __le16 xsum16 /* checksum16 result */; + __le16 xsum8 /* checksum8 result */; +}; + +struct igu_cleanup { + __le32 sb_id_and_flags; +#define IGU_CLEANUP_RESERVED0_MASK 0x7FFFFFF +#define IGU_CLEANUP_RESERVED0_SHIFT 0 +#define IGU_CLEANUP_CLEANUP_SET_MASK 0x1 /* cleanup clear - 0, set - 1 */ +#define IGU_CLEANUP_CLEANUP_SET_SHIFT 27 +#define IGU_CLEANUP_CLEANUP_TYPE_MASK 0x7 +#define IGU_CLEANUP_CLEANUP_TYPE_SHIFT 28 +#define IGU_CLEANUP_COMMAND_TYPE_MASK 0x1 +#define IGU_CLEANUP_COMMAND_TYPE_SHIFT 31 + __le32 reserved1; +}; + +union igu_command { + struct igu_prod_cons_update prod_cons_update; + struct igu_cleanup cleanup; +}; + +struct igu_command_reg_ctrl { + __le16 opaque_fid; + __le16 igu_command_reg_ctrl_fields; +#define IGU_COMMAND_REG_CTRL_PXP_BAR_ADDR_MASK 0xFFF +#define IGU_COMMAND_REG_CTRL_PXP_BAR_ADDR_SHIFT 0 +#define IGU_COMMAND_REG_CTRL_RESERVED_MASK 0x7 +#define IGU_COMMAND_REG_CTRL_RESERVED_SHIFT 12 +#define IGU_COMMAND_REG_CTRL_COMMAND_TYPE_MASK 0x1 +#define IGU_COMMAND_REG_CTRL_COMMAND_TYPE_SHIFT 15 +}; + +struct igu_mapping_line { + __le32 igu_mapping_line_fields; +#define IGU_MAPPING_LINE_VALID_MASK 0x1 +#define IGU_MAPPING_LINE_VALID_SHIFT 0 +#define IGU_MAPPING_LINE_VECTOR_NUMBER_MASK 0xFF +#define IGU_MAPPING_LINE_VECTOR_NUMBER_SHIFT 1 +#define IGU_MAPPING_LINE_FUNCTION_NUMBER_MASK 0xFF +#define IGU_MAPPING_LINE_FUNCTION_NUMBER_SHIFT 9 +#define IGU_MAPPING_LINE_PF_VALID_MASK 0x1 /* PF-1, VF-0 */ +#define IGU_MAPPING_LINE_PF_VALID_SHIFT 17 +#define IGU_MAPPING_LINE_IPS_GROUP_MASK 0x3F +#define IGU_MAPPING_LINE_IPS_GROUP_SHIFT 18 +#define IGU_MAPPING_LINE_RESERVED_MASK 0xFF +#define IGU_MAPPING_LINE_RESERVED_SHIFT 24 +}; + +struct igu_msix_vector { + struct regpair address; + __le32 data; + __le32 msix_vector_fields; +#define IGU_MSIX_VECTOR_MASK_BIT_MASK 0x1 +#define IGU_MSIX_VECTOR_MASK_BIT_SHIFT 0 +#define IGU_MSIX_VECTOR_RESERVED0_MASK 0x7FFF +#define IGU_MSIX_VECTOR_RESERVED0_SHIFT 1 +#define IGU_MSIX_VECTOR_STEERING_TAG_MASK 0xFF +#define IGU_MSIX_VECTOR_STEERING_TAG_SHIFT 16 +#define IGU_MSIX_VECTOR_RESERVED1_MASK 0xFF +#define IGU_MSIX_VECTOR_RESERVED1_SHIFT 24 +}; + +enum init_modes { + MODE_BB_A0, + MODE_RESERVED, + MODE_RESERVED2, + MODE_ASIC, + MODE_RESERVED3, + MODE_RESERVED4, + MODE_RESERVED5, + MODE_SF, + MODE_MF_SD, + MODE_MF_SI, + MODE_PORTS_PER_ENG_1, + MODE_PORTS_PER_ENG_2, + MODE_PORTS_PER_ENG_4, + MODE_40G, + MODE_100G, + MODE_EAGLE_ENG1_WORKAROUND, + MAX_INIT_MODES +}; + +enum init_phases { + PHASE_ENGINE, + PHASE_PORT, + PHASE_PF, + PHASE_RESERVED, + PHASE_QM_PF, + MAX_INIT_PHASES +}; + +struct mstorm_core_conn_ag_ctx { + u8 byte0 /* cdu_validation */; + u8 byte1 /* state */; + u8 flags0; +#define MSTORM_CORE_CONN_AG_CTX_BIT0_MASK 0x1 /* exist_in_qm0 */ +#define MSTORM_CORE_CONN_AG_CTX_BIT0_SHIFT 0 +#define MSTORM_CORE_CONN_AG_CTX_BIT1_MASK 0x1 /* exist_in_qm1 */ +#define MSTORM_CORE_CONN_AG_CTX_BIT1_SHIFT 1 +#define MSTORM_CORE_CONN_AG_CTX_CF0_MASK 0x3 /* cf0 */ +#define MSTORM_CORE_CONN_AG_CTX_CF0_SHIFT 2 +#define MSTORM_CORE_CONN_AG_CTX_CF1_MASK 0x3 /* cf1 */ +#define MSTORM_CORE_CONN_AG_CTX_CF1_SHIFT 4 +#define MSTORM_CORE_CONN_AG_CTX_CF2_MASK 0x3 /* cf2 */ +#define MSTORM_CORE_CONN_AG_CTX_CF2_SHIFT 6 + u8 flags1; +#define MSTORM_CORE_CONN_AG_CTX_CF0EN_MASK 0x1 /* cf0en */ +#define MSTORM_CORE_CONN_AG_CTX_CF0EN_SHIFT 0 +#define MSTORM_CORE_CONN_AG_CTX_CF1EN_MASK 0x1 /* cf1en */ +#define MSTORM_CORE_CONN_AG_CTX_CF1EN_SHIFT 1 +#define MSTORM_CORE_CONN_AG_CTX_CF2EN_MASK 0x1 /* cf2en */ +#define MSTORM_CORE_CONN_AG_CTX_CF2EN_SHIFT 2 +#define MSTORM_CORE_CONN_AG_CTX_RULE0EN_MASK 0x1 /* rule0en */ +#define MSTORM_CORE_CONN_AG_CTX_RULE0EN_SHIFT 3 +#define MSTORM_CORE_CONN_AG_CTX_RULE1EN_MASK 0x1 /* rule1en */ +#define MSTORM_CORE_CONN_AG_CTX_RULE1EN_SHIFT 4 +#define MSTORM_CORE_CONN_AG_CTX_RULE2EN_MASK 0x1 /* rule2en */ +#define MSTORM_CORE_CONN_AG_CTX_RULE2EN_SHIFT 5 +#define MSTORM_CORE_CONN_AG_CTX_RULE3EN_MASK 0x1 /* rule3en */ +#define MSTORM_CORE_CONN_AG_CTX_RULE3EN_SHIFT 6 +#define MSTORM_CORE_CONN_AG_CTX_RULE4EN_MASK 0x1 /* rule4en */ +#define MSTORM_CORE_CONN_AG_CTX_RULE4EN_SHIFT 7 + __le16 word0 /* word0 */; + __le16 word1 /* word1 */; + __le32 reg0 /* reg0 */; + __le32 reg1 /* reg1 */; +}; + +/* per encapsulation type enabling flags */ +struct prs_reg_encapsulation_type_en { + u8 flags; +#define PRS_REG_ENCAPSULATION_TYPE_EN_ETH_OVER_GRE_ENABLE_MASK 0x1 +#define PRS_REG_ENCAPSULATION_TYPE_EN_ETH_OVER_GRE_ENABLE_SHIFT 0 +#define PRS_REG_ENCAPSULATION_TYPE_EN_IP_OVER_GRE_ENABLE_MASK 0x1 +#define PRS_REG_ENCAPSULATION_TYPE_EN_IP_OVER_GRE_ENABLE_SHIFT 1 +#define PRS_REG_ENCAPSULATION_TYPE_EN_VXLAN_ENABLE_MASK 0x1 +#define PRS_REG_ENCAPSULATION_TYPE_EN_VXLAN_ENABLE_SHIFT 2 +#define PRS_REG_ENCAPSULATION_TYPE_EN_T_TAG_ENABLE_MASK 0x1 +#define PRS_REG_ENCAPSULATION_TYPE_EN_T_TAG_ENABLE_SHIFT 3 +#define PRS_REG_ENCAPSULATION_TYPE_EN_ETH_OVER_GENEVE_ENABLE_MASK 0x1 +#define PRS_REG_ENCAPSULATION_TYPE_EN_ETH_OVER_GENEVE_ENABLE_SHIFT 4 +#define PRS_REG_ENCAPSULATION_TYPE_EN_IP_OVER_GENEVE_ENABLE_MASK 0x1 +#define PRS_REG_ENCAPSULATION_TYPE_EN_IP_OVER_GENEVE_ENABLE_SHIFT 5 +#define PRS_REG_ENCAPSULATION_TYPE_EN_RESERVED_MASK 0x3 +#define PRS_REG_ENCAPSULATION_TYPE_EN_RESERVED_SHIFT 6 +}; + +enum pxp_tph_st_hint { + TPH_ST_HINT_BIDIR /* Read/Write access by Host and Device */, + TPH_ST_HINT_REQUESTER /* Read/Write access by Device */, + TPH_ST_HINT_TARGET, + TPH_ST_HINT_TARGET_PRIO, + MAX_PXP_TPH_ST_HINT +}; + +/* QM hardware structure of enable bypass credit mask */ +struct qm_rf_bypass_mask { + u8 flags; +#define QM_RF_BYPASS_MASK_LINEVOQ_MASK 0x1 +#define QM_RF_BYPASS_MASK_LINEVOQ_SHIFT 0 +#define QM_RF_BYPASS_MASK_RESERVED0_MASK 0x1 +#define QM_RF_BYPASS_MASK_RESERVED0_SHIFT 1 +#define QM_RF_BYPASS_MASK_PFWFQ_MASK 0x1 +#define QM_RF_BYPASS_MASK_PFWFQ_SHIFT 2 +#define QM_RF_BYPASS_MASK_VPWFQ_MASK 0x1 +#define QM_RF_BYPASS_MASK_VPWFQ_SHIFT 3 +#define QM_RF_BYPASS_MASK_PFRL_MASK 0x1 +#define QM_RF_BYPASS_MASK_PFRL_SHIFT 4 +#define QM_RF_BYPASS_MASK_VPQCNRL_MASK 0x1 +#define QM_RF_BYPASS_MASK_VPQCNRL_SHIFT 5 +#define QM_RF_BYPASS_MASK_FWPAUSE_MASK 0x1 +#define QM_RF_BYPASS_MASK_FWPAUSE_SHIFT 6 +#define QM_RF_BYPASS_MASK_RESERVED1_MASK 0x1 +#define QM_RF_BYPASS_MASK_RESERVED1_SHIFT 7 +}; + +/* QM hardware structure of opportunistic credit mask */ +struct qm_rf_opportunistic_mask { + __le16 flags; +#define QM_RF_OPPORTUNISTIC_MASK_LINEVOQ_MASK 0x1 +#define QM_RF_OPPORTUNISTIC_MASK_LINEVOQ_SHIFT 0 +#define QM_RF_OPPORTUNISTIC_MASK_BYTEVOQ_MASK 0x1 +#define QM_RF_OPPORTUNISTIC_MASK_BYTEVOQ_SHIFT 1 +#define QM_RF_OPPORTUNISTIC_MASK_PFWFQ_MASK 0x1 +#define QM_RF_OPPORTUNISTIC_MASK_PFWFQ_SHIFT 2 +#define QM_RF_OPPORTUNISTIC_MASK_VPWFQ_MASK 0x1 +#define QM_RF_OPPORTUNISTIC_MASK_VPWFQ_SHIFT 3 +#define QM_RF_OPPORTUNISTIC_MASK_PFRL_MASK 0x1 +#define QM_RF_OPPORTUNISTIC_MASK_PFRL_SHIFT 4 +#define QM_RF_OPPORTUNISTIC_MASK_VPQCNRL_MASK 0x1 +#define QM_RF_OPPORTUNISTIC_MASK_VPQCNRL_SHIFT 5 +#define QM_RF_OPPORTUNISTIC_MASK_FWPAUSE_MASK 0x1 +#define QM_RF_OPPORTUNISTIC_MASK_FWPAUSE_SHIFT 6 +#define QM_RF_OPPORTUNISTIC_MASK_RESERVED0_MASK 0x1 +#define QM_RF_OPPORTUNISTIC_MASK_RESERVED0_SHIFT 7 +#define QM_RF_OPPORTUNISTIC_MASK_QUEUEEMPTY_MASK 0x1 +#define QM_RF_OPPORTUNISTIC_MASK_QUEUEEMPTY_SHIFT 8 +#define QM_RF_OPPORTUNISTIC_MASK_RESERVED1_MASK 0x7F +#define QM_RF_OPPORTUNISTIC_MASK_RESERVED1_SHIFT 9 +}; + +/* QM hardware structure of QM map memory */ +struct qm_rf_pq_map { + u32 reg; +#define QM_RF_PQ_MAP_PQ_VALID_MASK 0x1 /* PQ active */ +#define QM_RF_PQ_MAP_PQ_VALID_SHIFT 0 +#define QM_RF_PQ_MAP_RL_ID_MASK 0xFF /* RL ID */ +#define QM_RF_PQ_MAP_RL_ID_SHIFT 1 +#define QM_RF_PQ_MAP_VP_PQ_ID_MASK 0x1FF +#define QM_RF_PQ_MAP_VP_PQ_ID_SHIFT 9 +#define QM_RF_PQ_MAP_VOQ_MASK 0x1F /* VOQ */ +#define QM_RF_PQ_MAP_VOQ_SHIFT 18 +#define QM_RF_PQ_MAP_WRR_WEIGHT_GROUP_MASK 0x3 /* WRR weight */ +#define QM_RF_PQ_MAP_WRR_WEIGHT_GROUP_SHIFT 23 +#define QM_RF_PQ_MAP_RL_VALID_MASK 0x1 /* RL active */ +#define QM_RF_PQ_MAP_RL_VALID_SHIFT 25 +#define QM_RF_PQ_MAP_RESERVED_MASK 0x3F +#define QM_RF_PQ_MAP_RESERVED_SHIFT 26 +}; + +/* SDM operation gen command (generate aggregative interrupt) */ +struct sdm_op_gen { + __le32 command; +#define SDM_OP_GEN_COMP_PARAM_MASK 0xFFFF /* completion parameters 0-15 */ +#define SDM_OP_GEN_COMP_PARAM_SHIFT 0 +#define SDM_OP_GEN_COMP_TYPE_MASK 0xF /* completion type 16-19 */ +#define SDM_OP_GEN_COMP_TYPE_SHIFT 16 +#define SDM_OP_GEN_RESERVED_MASK 0xFFF /* reserved 20-31 */ +#define SDM_OP_GEN_RESERVED_SHIFT 20 +}; + +struct tstorm_core_conn_ag_ctx { + u8 byte0 /* cdu_validation */; + u8 byte1 /* state */; + u8 flags0; +#define TSTORM_CORE_CONN_AG_CTX_BIT0_MASK 0x1 /* exist_in_qm0 */ +#define TSTORM_CORE_CONN_AG_CTX_BIT0_SHIFT 0 +#define TSTORM_CORE_CONN_AG_CTX_BIT1_MASK 0x1 /* exist_in_qm1 */ +#define TSTORM_CORE_CONN_AG_CTX_BIT1_SHIFT 1 +#define TSTORM_CORE_CONN_AG_CTX_BIT2_MASK 0x1 /* bit2 */ +#define TSTORM_CORE_CONN_AG_CTX_BIT2_SHIFT 2 +#define TSTORM_CORE_CONN_AG_CTX_BIT3_MASK 0x1 /* bit3 */ +#define TSTORM_CORE_CONN_AG_CTX_BIT3_SHIFT 3 +#define TSTORM_CORE_CONN_AG_CTX_BIT4_MASK 0x1 /* bit4 */ +#define TSTORM_CORE_CONN_AG_CTX_BIT4_SHIFT 4 +#define TSTORM_CORE_CONN_AG_CTX_BIT5_MASK 0x1 /* bit5 */ +#define TSTORM_CORE_CONN_AG_CTX_BIT5_SHIFT 5 +#define TSTORM_CORE_CONN_AG_CTX_CF0_MASK 0x3 /* timer0cf */ +#define TSTORM_CORE_CONN_AG_CTX_CF0_SHIFT 6 + u8 flags1; +#define TSTORM_CORE_CONN_AG_CTX_CF1_MASK 0x3 /* timer1cf */ +#define TSTORM_CORE_CONN_AG_CTX_CF1_SHIFT 0 +#define TSTORM_CORE_CONN_AG_CTX_CF2_MASK 0x3 /* timer2cf */ +#define TSTORM_CORE_CONN_AG_CTX_CF2_SHIFT 2 +#define TSTORM_CORE_CONN_AG_CTX_CF3_MASK 0x3 /* timer_stop_all */ +#define TSTORM_CORE_CONN_AG_CTX_CF3_SHIFT 4 +#define TSTORM_CORE_CONN_AG_CTX_CF4_MASK 0x3 /* cf4 */ +#define TSTORM_CORE_CONN_AG_CTX_CF4_SHIFT 6 + u8 flags2; +#define TSTORM_CORE_CONN_AG_CTX_CF5_MASK 0x3 /* cf5 */ +#define TSTORM_CORE_CONN_AG_CTX_CF5_SHIFT 0 +#define TSTORM_CORE_CONN_AG_CTX_CF6_MASK 0x3 /* cf6 */ +#define TSTORM_CORE_CONN_AG_CTX_CF6_SHIFT 2 +#define TSTORM_CORE_CONN_AG_CTX_CF7_MASK 0x3 /* cf7 */ +#define TSTORM_CORE_CONN_AG_CTX_CF7_SHIFT 4 +#define TSTORM_CORE_CONN_AG_CTX_CF8_MASK 0x3 /* cf8 */ +#define TSTORM_CORE_CONN_AG_CTX_CF8_SHIFT 6 + u8 flags3; +#define TSTORM_CORE_CONN_AG_CTX_CF9_MASK 0x3 /* cf9 */ +#define TSTORM_CORE_CONN_AG_CTX_CF9_SHIFT 0 +#define TSTORM_CORE_CONN_AG_CTX_CF10_MASK 0x3 /* cf10 */ +#define TSTORM_CORE_CONN_AG_CTX_CF10_SHIFT 2 +#define TSTORM_CORE_CONN_AG_CTX_CF0EN_MASK 0x1 /* cf0en */ +#define TSTORM_CORE_CONN_AG_CTX_CF0EN_SHIFT 4 +#define TSTORM_CORE_CONN_AG_CTX_CF1EN_MASK 0x1 /* cf1en */ +#define TSTORM_CORE_CONN_AG_CTX_CF1EN_SHIFT 5 +#define TSTORM_CORE_CONN_AG_CTX_CF2EN_MASK 0x1 /* cf2en */ +#define TSTORM_CORE_CONN_AG_CTX_CF2EN_SHIFT 6 +#define TSTORM_CORE_CONN_AG_CTX_CF3EN_MASK 0x1 /* cf3en */ +#define TSTORM_CORE_CONN_AG_CTX_CF3EN_SHIFT 7 + u8 flags4; +#define TSTORM_CORE_CONN_AG_CTX_CF4EN_MASK 0x1 /* cf4en */ +#define TSTORM_CORE_CONN_AG_CTX_CF4EN_SHIFT 0 +#define TSTORM_CORE_CONN_AG_CTX_CF5EN_MASK 0x1 /* cf5en */ +#define TSTORM_CORE_CONN_AG_CTX_CF5EN_SHIFT 1 +#define TSTORM_CORE_CONN_AG_CTX_CF6EN_MASK 0x1 /* cf6en */ +#define TSTORM_CORE_CONN_AG_CTX_CF6EN_SHIFT 2 +#define TSTORM_CORE_CONN_AG_CTX_CF7EN_MASK 0x1 /* cf7en */ +#define TSTORM_CORE_CONN_AG_CTX_CF7EN_SHIFT 3 +#define TSTORM_CORE_CONN_AG_CTX_CF8EN_MASK 0x1 /* cf8en */ +#define TSTORM_CORE_CONN_AG_CTX_CF8EN_SHIFT 4 +#define TSTORM_CORE_CONN_AG_CTX_CF9EN_MASK 0x1 /* cf9en */ +#define TSTORM_CORE_CONN_AG_CTX_CF9EN_SHIFT 5 +#define TSTORM_CORE_CONN_AG_CTX_CF10EN_MASK 0x1 /* cf10en */ +#define TSTORM_CORE_CONN_AG_CTX_CF10EN_SHIFT 6 +#define TSTORM_CORE_CONN_AG_CTX_RULE0EN_MASK 0x1 /* rule0en */ +#define TSTORM_CORE_CONN_AG_CTX_RULE0EN_SHIFT 7 + u8 flags5; +#define TSTORM_CORE_CONN_AG_CTX_RULE1EN_MASK 0x1 /* rule1en */ +#define TSTORM_CORE_CONN_AG_CTX_RULE1EN_SHIFT 0 +#define TSTORM_CORE_CONN_AG_CTX_RULE2EN_MASK 0x1 /* rule2en */ +#define TSTORM_CORE_CONN_AG_CTX_RULE2EN_SHIFT 1 +#define TSTORM_CORE_CONN_AG_CTX_RULE3EN_MASK 0x1 /* rule3en */ +#define TSTORM_CORE_CONN_AG_CTX_RULE3EN_SHIFT 2 +#define TSTORM_CORE_CONN_AG_CTX_RULE4EN_MASK 0x1 /* rule4en */ +#define TSTORM_CORE_CONN_AG_CTX_RULE4EN_SHIFT 3 +#define TSTORM_CORE_CONN_AG_CTX_RULE5EN_MASK 0x1 /* rule5en */ +#define TSTORM_CORE_CONN_AG_CTX_RULE5EN_SHIFT 4 +#define TSTORM_CORE_CONN_AG_CTX_RULE6EN_MASK 0x1 /* rule6en */ +#define TSTORM_CORE_CONN_AG_CTX_RULE6EN_SHIFT 5 +#define TSTORM_CORE_CONN_AG_CTX_RULE7EN_MASK 0x1 /* rule7en */ +#define TSTORM_CORE_CONN_AG_CTX_RULE7EN_SHIFT 6 +#define TSTORM_CORE_CONN_AG_CTX_RULE8EN_MASK 0x1 /* rule8en */ +#define TSTORM_CORE_CONN_AG_CTX_RULE8EN_SHIFT 7 + __le32 reg0 /* reg0 */; + __le32 reg1 /* reg1 */; + __le32 reg2 /* reg2 */; + __le32 reg3 /* reg3 */; + __le32 reg4 /* reg4 */; + __le32 reg5 /* reg5 */; + __le32 reg6 /* reg6 */; + __le32 reg7 /* reg7 */; + __le32 reg8 /* reg8 */; + u8 byte2 /* byte2 */; + u8 byte3 /* byte3 */; + __le16 word0 /* word0 */; + u8 byte4 /* byte4 */; + u8 byte5 /* byte5 */; + __le16 word1 /* word1 */; + __le16 word2 /* conn_dpi */; + __le16 word3 /* word3 */; + __le32 reg9 /* reg9 */; + __le32 reg10 /* reg10 */; +}; + +struct ustorm_core_conn_ag_ctx { + u8 reserved /* cdu_validation */; + u8 byte1 /* state */; + u8 flags0; +#define USTORM_CORE_CONN_AG_CTX_BIT0_MASK 0x1 /* exist_in_qm0 */ +#define USTORM_CORE_CONN_AG_CTX_BIT0_SHIFT 0 +#define USTORM_CORE_CONN_AG_CTX_BIT1_MASK 0x1 /* exist_in_qm1 */ +#define USTORM_CORE_CONN_AG_CTX_BIT1_SHIFT 1 +#define USTORM_CORE_CONN_AG_CTX_CF0_MASK 0x3 /* timer0cf */ +#define USTORM_CORE_CONN_AG_CTX_CF0_SHIFT 2 +#define USTORM_CORE_CONN_AG_CTX_CF1_MASK 0x3 /* timer1cf */ +#define USTORM_CORE_CONN_AG_CTX_CF1_SHIFT 4 +#define USTORM_CORE_CONN_AG_CTX_CF2_MASK 0x3 /* timer2cf */ +#define USTORM_CORE_CONN_AG_CTX_CF2_SHIFT 6 + u8 flags1; +#define USTORM_CORE_CONN_AG_CTX_CF3_MASK 0x3 /* timer_stop_all */ +#define USTORM_CORE_CONN_AG_CTX_CF3_SHIFT 0 +#define USTORM_CORE_CONN_AG_CTX_CF4_MASK 0x3 /* cf4 */ +#define USTORM_CORE_CONN_AG_CTX_CF4_SHIFT 2 +#define USTORM_CORE_CONN_AG_CTX_CF5_MASK 0x3 /* cf5 */ +#define USTORM_CORE_CONN_AG_CTX_CF5_SHIFT 4 +#define USTORM_CORE_CONN_AG_CTX_CF6_MASK 0x3 /* cf6 */ +#define USTORM_CORE_CONN_AG_CTX_CF6_SHIFT 6 + u8 flags2; +#define USTORM_CORE_CONN_AG_CTX_CF0EN_MASK 0x1 /* cf0en */ +#define USTORM_CORE_CONN_AG_CTX_CF0EN_SHIFT 0 +#define USTORM_CORE_CONN_AG_CTX_CF1EN_MASK 0x1 /* cf1en */ +#define USTORM_CORE_CONN_AG_CTX_CF1EN_SHIFT 1 +#define USTORM_CORE_CONN_AG_CTX_CF2EN_MASK 0x1 /* cf2en */ +#define USTORM_CORE_CONN_AG_CTX_CF2EN_SHIFT 2 +#define USTORM_CORE_CONN_AG_CTX_CF3EN_MASK 0x1 /* cf3en */ +#define USTORM_CORE_CONN_AG_CTX_CF3EN_SHIFT 3 +#define USTORM_CORE_CONN_AG_CTX_CF4EN_MASK 0x1 /* cf4en */ +#define USTORM_CORE_CONN_AG_CTX_CF4EN_SHIFT 4 +#define USTORM_CORE_CONN_AG_CTX_CF5EN_MASK 0x1 /* cf5en */ +#define USTORM_CORE_CONN_AG_CTX_CF5EN_SHIFT 5 +#define USTORM_CORE_CONN_AG_CTX_CF6EN_MASK 0x1 /* cf6en */ +#define USTORM_CORE_CONN_AG_CTX_CF6EN_SHIFT 6 +#define USTORM_CORE_CONN_AG_CTX_RULE0EN_MASK 0x1 /* rule0en */ +#define USTORM_CORE_CONN_AG_CTX_RULE0EN_SHIFT 7 + u8 flags3; +#define USTORM_CORE_CONN_AG_CTX_RULE1EN_MASK 0x1 /* rule1en */ +#define USTORM_CORE_CONN_AG_CTX_RULE1EN_SHIFT 0 +#define USTORM_CORE_CONN_AG_CTX_RULE2EN_MASK 0x1 /* rule2en */ +#define USTORM_CORE_CONN_AG_CTX_RULE2EN_SHIFT 1 +#define USTORM_CORE_CONN_AG_CTX_RULE3EN_MASK 0x1 /* rule3en */ +#define USTORM_CORE_CONN_AG_CTX_RULE3EN_SHIFT 2 +#define USTORM_CORE_CONN_AG_CTX_RULE4EN_MASK 0x1 /* rule4en */ +#define USTORM_CORE_CONN_AG_CTX_RULE4EN_SHIFT 3 +#define USTORM_CORE_CONN_AG_CTX_RULE5EN_MASK 0x1 /* rule5en */ +#define USTORM_CORE_CONN_AG_CTX_RULE5EN_SHIFT 4 +#define USTORM_CORE_CONN_AG_CTX_RULE6EN_MASK 0x1 /* rule6en */ +#define USTORM_CORE_CONN_AG_CTX_RULE6EN_SHIFT 5 +#define USTORM_CORE_CONN_AG_CTX_RULE7EN_MASK 0x1 /* rule7en */ +#define USTORM_CORE_CONN_AG_CTX_RULE7EN_SHIFT 6 +#define USTORM_CORE_CONN_AG_CTX_RULE8EN_MASK 0x1 /* rule8en */ +#define USTORM_CORE_CONN_AG_CTX_RULE8EN_SHIFT 7 + u8 byte2 /* byte2 */; + u8 byte3 /* byte3 */; + __le16 word0 /* conn_dpi */; + __le16 word1 /* word1 */; + __le32 rx_producers /* reg0 */; + __le32 reg1 /* reg1 */; + __le32 reg2 /* reg2 */; + __le32 reg3 /* reg3 */; + __le16 word2 /* word2 */; + __le16 word3 /* word3 */; +}; + +struct ystorm_core_conn_ag_ctx { + u8 byte0 /* cdu_validation */; + u8 byte1 /* state */; + u8 flags0; +#define YSTORM_CORE_CONN_AG_CTX_BIT0_MASK 0x1 /* exist_in_qm0 */ +#define YSTORM_CORE_CONN_AG_CTX_BIT0_SHIFT 0 +#define YSTORM_CORE_CONN_AG_CTX_BIT1_MASK 0x1 /* exist_in_qm1 */ +#define YSTORM_CORE_CONN_AG_CTX_BIT1_SHIFT 1 +#define YSTORM_CORE_CONN_AG_CTX_CF0_MASK 0x3 /* cf0 */ +#define YSTORM_CORE_CONN_AG_CTX_CF0_SHIFT 2 +#define YSTORM_CORE_CONN_AG_CTX_CF1_MASK 0x3 /* cf1 */ +#define YSTORM_CORE_CONN_AG_CTX_CF1_SHIFT 4 +#define YSTORM_CORE_CONN_AG_CTX_CF2_MASK 0x3 /* cf2 */ +#define YSTORM_CORE_CONN_AG_CTX_CF2_SHIFT 6 + u8 flags1; +#define YSTORM_CORE_CONN_AG_CTX_CF0EN_MASK 0x1 /* cf0en */ +#define YSTORM_CORE_CONN_AG_CTX_CF0EN_SHIFT 0 +#define YSTORM_CORE_CONN_AG_CTX_CF1EN_MASK 0x1 /* cf1en */ +#define YSTORM_CORE_CONN_AG_CTX_CF1EN_SHIFT 1 +#define YSTORM_CORE_CONN_AG_CTX_CF2EN_MASK 0x1 /* cf2en */ +#define YSTORM_CORE_CONN_AG_CTX_CF2EN_SHIFT 2 +#define YSTORM_CORE_CONN_AG_CTX_RULE0EN_MASK 0x1 /* rule0en */ +#define YSTORM_CORE_CONN_AG_CTX_RULE0EN_SHIFT 3 +#define YSTORM_CORE_CONN_AG_CTX_RULE1EN_MASK 0x1 /* rule1en */ +#define YSTORM_CORE_CONN_AG_CTX_RULE1EN_SHIFT 4 +#define YSTORM_CORE_CONN_AG_CTX_RULE2EN_MASK 0x1 /* rule2en */ +#define YSTORM_CORE_CONN_AG_CTX_RULE2EN_SHIFT 5 +#define YSTORM_CORE_CONN_AG_CTX_RULE3EN_MASK 0x1 /* rule3en */ +#define YSTORM_CORE_CONN_AG_CTX_RULE3EN_SHIFT 6 +#define YSTORM_CORE_CONN_AG_CTX_RULE4EN_MASK 0x1 /* rule4en */ +#define YSTORM_CORE_CONN_AG_CTX_RULE4EN_SHIFT 7 + u8 byte2 /* byte2 */; + u8 byte3 /* byte3 */; + __le16 word0 /* word0 */; + __le32 reg0 /* reg0 */; + __le32 reg1 /* reg1 */; + __le16 word1 /* word1 */; + __le16 word2 /* word2 */; + __le16 word3 /* word3 */; + __le16 word4 /* word4 */; + __le32 reg2 /* reg2 */; + __le32 reg3 /* reg3 */; +}; + +/*********************************** Init ************************************/ + +/* Width of GRC address in bits (addresses are specified in dwords) */ +#define GRC_ADDR_BITS 23 +#define MAX_GRC_ADDR ((1 << GRC_ADDR_BITS) - 1) + +/* indicates an init that should be applied to any phase ID */ +#define ANY_PHASE_ID 0xffff + +/* init pattern size in bytes */ +#define INIT_PATTERN_SIZE_BITS 4 +#define MAX_INIT_PATTERN_SIZE BIT(INIT_PATTERN_SIZE_BITS) + +/* Max size in dwords of a zipped array */ +#define MAX_ZIPPED_SIZE 8192 + +/* Global PXP window */ +#define NUM_OF_PXP_WIN 19 +#define PXP_WIN_DWORD_SIZE_BITS 10 +#define PXP_WIN_DWORD_SIZE BIT(PXP_WIN_DWORD_SIZE_BITS) +#define PXP_WIN_BYTE_SIZE_BITS (PXP_WIN_DWORD_SIZE_BITS + 2) +#define PXP_WIN_BYTE_SIZE (PXP_WIN_DWORD_SIZE * 4) + +/********************************* GRC Dump **********************************/ + +/* width of GRC dump register sequence length in bits */ +#define DUMP_SEQ_LEN_BITS 8 +#define DUMP_SEQ_LEN_MAX_VAL ((1 << DUMP_SEQ_LEN_BITS) - 1) + +/* width of GRC dump memory length in bits */ +#define DUMP_MEM_LEN_BITS 18 +#define DUMP_MEM_LEN_MAX_VAL ((1 << DUMP_MEM_LEN_BITS) - 1) + +/* width of register type ID in bits */ +#define REG_TYPE_ID_BITS 6 +#define REG_TYPE_ID_MAX_VAL ((1 << REG_TYPE_ID_BITS) - 1) + +/* width of block ID in bits */ +#define BLOCK_ID_BITS 8 +#define BLOCK_ID_MAX_VAL ((1 << BLOCK_ID_BITS) - 1) + +/******************************** Idle Check *********************************/ + +/* max number of idle check predicate immediates */ +#define MAX_IDLE_CHK_PRED_IMM 3 + +/* max number of idle check argument registers */ +#define MAX_IDLE_CHK_READ_REGS 3 + +/* max number of idle check loops */ +#define MAX_IDLE_CHK_LOOPS 0x10000 + +/* max idle check address increment */ +#define MAX_IDLE_CHK_INCREMENT 0x10000 + +/* inicates an undefined idle check line index */ +#define IDLE_CHK_UNDEFINED_LINE_IDX 0xffffff + +/* max number of register values following the idle check header */ +#define IDLE_CHK_MAX_DUMP_REGS 2 + +/* arguments for IDLE_CHK_MACRO_TYPE_QM_RD_WR */ +#define IDLE_CHK_QM_RD_WR_PTR 0 +#define IDLE_CHK_QM_RD_WR_BANK 1 + +/**************************************/ +/* HSI Functions constants and macros */ +/**************************************/ + +/* Number of VLAN priorities */ +#define NUM_OF_VLAN_PRIORITIES 8 + +/* the MCP Trace meta data signautre is duplicated in the perl script that + * generats the NVRAM images. + */ +#define MCP_TRACE_META_IMAGE_SIGNATURE 0x669955aa + +/* Binary buffer header */ +struct bin_buffer_hdr { + u32 offset; + u32 length /* buffer length in bytes */; +}; + +/* binary buffer types */ +enum bin_buffer_type { + BIN_BUF_FW_VER_INFO /* fw_ver_info struct */, + BIN_BUF_INIT_CMD /* init commands */, + BIN_BUF_INIT_VAL /* init data */, + BIN_BUF_INIT_MODE_TREE /* init modes tree */, + BIN_BUF_IRO /* internal RAM offsets array */, + MAX_BIN_BUFFER_TYPE +}; + +/* Chip IDs */ +enum chip_ids { + CHIP_BB_A0 /* BB A0 chip ID */, + CHIP_BB_B0 /* BB B0 chip ID */, + CHIP_K2 /* AH chip ID */, + MAX_CHIP_IDS +}; + +enum idle_chk_severity_types { + IDLE_CHK_SEVERITY_ERROR /* idle check failure should cause an error */, + IDLE_CHK_SEVERITY_ERROR_NO_TRAFFIC, + IDLE_CHK_SEVERITY_WARNING, + MAX_IDLE_CHK_SEVERITY_TYPES +}; + +struct init_array_raw_hdr { + __le32 data; +#define INIT_ARRAY_RAW_HDR_TYPE_MASK 0xF +#define INIT_ARRAY_RAW_HDR_TYPE_SHIFT 0 +#define INIT_ARRAY_RAW_HDR_PARAMS_MASK 0xFFFFFFF /* init array params */ +#define INIT_ARRAY_RAW_HDR_PARAMS_SHIFT 4 +}; + +struct init_array_standard_hdr { + __le32 data; +#define INIT_ARRAY_STANDARD_HDR_TYPE_MASK 0xF +#define INIT_ARRAY_STANDARD_HDR_TYPE_SHIFT 0 +#define INIT_ARRAY_STANDARD_HDR_SIZE_MASK 0xFFFFFFF +#define INIT_ARRAY_STANDARD_HDR_SIZE_SHIFT 4 +}; + +struct init_array_zipped_hdr { + __le32 data; +#define INIT_ARRAY_ZIPPED_HDR_TYPE_MASK 0xF +#define INIT_ARRAY_ZIPPED_HDR_TYPE_SHIFT 0 +#define INIT_ARRAY_ZIPPED_HDR_ZIPPED_SIZE_MASK 0xFFFFFFF +#define INIT_ARRAY_ZIPPED_HDR_ZIPPED_SIZE_SHIFT 4 +}; + +struct init_array_pattern_hdr { + __le32 data; +#define INIT_ARRAY_PATTERN_HDR_TYPE_MASK 0xF +#define INIT_ARRAY_PATTERN_HDR_TYPE_SHIFT 0 +#define INIT_ARRAY_PATTERN_HDR_PATTERN_SIZE_MASK 0xF +#define INIT_ARRAY_PATTERN_HDR_PATTERN_SIZE_SHIFT 4 +#define INIT_ARRAY_PATTERN_HDR_REPETITIONS_MASK 0xFFFFFF +#define INIT_ARRAY_PATTERN_HDR_REPETITIONS_SHIFT 8 +}; + +union init_array_hdr { + struct init_array_raw_hdr raw /* raw init array header */; + struct init_array_standard_hdr standard; + struct init_array_zipped_hdr zipped /* zipped init array header */; + struct init_array_pattern_hdr pattern /* pattern init array header */; +}; + +enum init_array_types { + INIT_ARR_STANDARD /* standard init array */, + INIT_ARR_ZIPPED /* zipped init array */, + INIT_ARR_PATTERN /* a repeated pattern */, + MAX_INIT_ARRAY_TYPES +}; + +/* init operation: callback */ +struct init_callback_op { + __le32 op_data; +#define INIT_CALLBACK_OP_OP_MASK 0xF +#define INIT_CALLBACK_OP_OP_SHIFT 0 +#define INIT_CALLBACK_OP_RESERVED_MASK 0xFFFFFFF +#define INIT_CALLBACK_OP_RESERVED_SHIFT 4 + __le16 callback_id /* Callback ID */; + __le16 block_id /* Blocks ID */; +}; + +/* init comparison types */ +enum init_comparison_types { + INIT_COMPARISON_EQ /* init value is included in the init command */, + INIT_COMPARISON_OR /* init value is all zeros */, + INIT_COMPARISON_AND /* init value is an array of values */, + MAX_INIT_COMPARISON_TYPES +}; + +/* init operation: delay */ +struct init_delay_op { + __le32 op_data; +#define INIT_DELAY_OP_OP_MASK 0xF +#define INIT_DELAY_OP_OP_SHIFT 0 +#define INIT_DELAY_OP_RESERVED_MASK 0xFFFFFFF +#define INIT_DELAY_OP_RESERVED_SHIFT 4 + __le32 delay /* delay in us */; +}; + +/* init operation: if_mode */ +struct init_if_mode_op { + __le32 op_data; +#define INIT_IF_MODE_OP_OP_MASK 0xF +#define INIT_IF_MODE_OP_OP_SHIFT 0 +#define INIT_IF_MODE_OP_RESERVED1_MASK 0xFFF +#define INIT_IF_MODE_OP_RESERVED1_SHIFT 4 +#define INIT_IF_MODE_OP_CMD_OFFSET_MASK 0xFFFF +#define INIT_IF_MODE_OP_CMD_OFFSET_SHIFT 16 + __le16 reserved2; + __le16 modes_buf_offset; +}; + +/* init operation: if_phase */ +struct init_if_phase_op { + __le32 op_data; +#define INIT_IF_PHASE_OP_OP_MASK 0xF +#define INIT_IF_PHASE_OP_OP_SHIFT 0 +#define INIT_IF_PHASE_OP_DMAE_ENABLE_MASK 0x1 +#define INIT_IF_PHASE_OP_DMAE_ENABLE_SHIFT 4 +#define INIT_IF_PHASE_OP_RESERVED1_MASK 0x7FF +#define INIT_IF_PHASE_OP_RESERVED1_SHIFT 5 +#define INIT_IF_PHASE_OP_CMD_OFFSET_MASK 0xFFFF +#define INIT_IF_PHASE_OP_CMD_OFFSET_SHIFT 16 + __le32 phase_data; +#define INIT_IF_PHASE_OP_PHASE_MASK 0xFF /* Init phase */ +#define INIT_IF_PHASE_OP_PHASE_SHIFT 0 +#define INIT_IF_PHASE_OP_RESERVED2_MASK 0xFF +#define INIT_IF_PHASE_OP_RESERVED2_SHIFT 8 +#define INIT_IF_PHASE_OP_PHASE_ID_MASK 0xFFFF /* Init phase ID */ +#define INIT_IF_PHASE_OP_PHASE_ID_SHIFT 16 +}; + +/* init mode operators */ +enum init_mode_ops { + INIT_MODE_OP_NOT /* init mode not operator */, + INIT_MODE_OP_OR /* init mode or operator */, + INIT_MODE_OP_AND /* init mode and operator */, + MAX_INIT_MODE_OPS +}; + +/* init operation: raw */ +struct init_raw_op { + __le32 op_data; +#define INIT_RAW_OP_OP_MASK 0xF +#define INIT_RAW_OP_OP_SHIFT 0 +#define INIT_RAW_OP_PARAM1_MASK 0xFFFFFFF /* init param 1 */ +#define INIT_RAW_OP_PARAM1_SHIFT 4 + __le32 param2 /* Init param 2 */; +}; + +/* init array params */ +struct init_op_array_params { + __le16 size /* array size in dwords */; + __le16 offset /* array start offset in dwords */; +}; + +/* Write init operation arguments */ +union init_write_args { + __le32 inline_val; + __le32 zeros_count; + __le32 array_offset; + struct init_op_array_params runtime; +}; + +/* init operation: write */ +struct init_write_op { + __le32 data; +#define INIT_WRITE_OP_OP_MASK 0xF +#define INIT_WRITE_OP_OP_SHIFT 0 +#define INIT_WRITE_OP_SOURCE_MASK 0x7 +#define INIT_WRITE_OP_SOURCE_SHIFT 4 +#define INIT_WRITE_OP_RESERVED_MASK 0x1 +#define INIT_WRITE_OP_RESERVED_SHIFT 7 +#define INIT_WRITE_OP_WIDE_BUS_MASK 0x1 +#define INIT_WRITE_OP_WIDE_BUS_SHIFT 8 +#define INIT_WRITE_OP_ADDRESS_MASK 0x7FFFFF +#define INIT_WRITE_OP_ADDRESS_SHIFT 9 + union init_write_args args /* Write init operation arguments */; +}; + +/* init operation: read */ +struct init_read_op { + __le32 op_data; +#define INIT_READ_OP_OP_MASK 0xF +#define INIT_READ_OP_OP_SHIFT 0 +#define INIT_READ_OP_POLL_COMP_MASK 0x7 +#define INIT_READ_OP_POLL_COMP_SHIFT 4 +#define INIT_READ_OP_RESERVED_MASK 0x1 +#define INIT_READ_OP_RESERVED_SHIFT 7 +#define INIT_READ_OP_POLL_MASK 0x1 +#define INIT_READ_OP_POLL_SHIFT 8 +#define INIT_READ_OP_ADDRESS_MASK 0x7FFFFF +#define INIT_READ_OP_ADDRESS_SHIFT 9 + __le32 expected_val; +}; + +/* Init operations union */ +union init_op { + struct init_raw_op raw /* raw init operation */; + struct init_write_op write /* write init operation */; + struct init_read_op read /* read init operation */; + struct init_if_mode_op if_mode /* if_mode init operation */; + struct init_if_phase_op if_phase /* if_phase init operation */; + struct init_callback_op callback /* callback init operation */; + struct init_delay_op delay /* delay init operation */; +}; + +/* Init command operation types */ +enum init_op_types { + INIT_OP_READ /* GRC read init command */, + INIT_OP_WRITE /* GRC write init command */, + INIT_OP_IF_MODE, + INIT_OP_IF_PHASE, + INIT_OP_DELAY /* delay init command */, + INIT_OP_CALLBACK /* callback init command */, + MAX_INIT_OP_TYPES +}; + +/* init source types */ +enum init_source_types { + INIT_SRC_INLINE /* init value is included in the init command */, + INIT_SRC_ZEROS /* init value is all zeros */, + INIT_SRC_ARRAY /* init value is an array of values */, + INIT_SRC_RUNTIME /* init value is provided during runtime */, + MAX_INIT_SOURCE_TYPES +}; + +/* Internal RAM Offsets macro data */ +struct iro { + u32 base /* RAM field offset */; + u16 m1 /* multiplier 1 */; + u16 m2 /* multiplier 2 */; + u16 m3 /* multiplier 3 */; + u16 size /* RAM field size */; +}; + +/* QM per-port init parameters */ +struct init_qm_port_params { + u8 active /* Indicates if this port is active */; + u8 num_active_phys_tcs; + u16 num_pbf_cmd_lines; + u16 num_btb_blocks; + __le16 reserved; +}; + +/* QM per-PQ init parameters */ +struct init_qm_pq_params { + u8 vport_id /* VPORT ID */; + u8 tc_id /* TC ID */; + u8 wrr_group /* WRR group */; + u8 reserved; +}; + +/* QM per-vport init parameters */ +struct init_qm_vport_params { + u32 vport_rl; + u16 vport_wfq; + u16 first_tx_pq_id[NUM_OF_TCS]; +}; + +/* Win 2 */ +#define GTT_BAR0_MAP_REG_IGU_CMD \ + 0x00f000UL +/* Win 3 */ +#define GTT_BAR0_MAP_REG_TSDM_RAM \ + 0x010000UL +/* Win 4 */ +#define GTT_BAR0_MAP_REG_MSDM_RAM \ + 0x011000UL +/* Win 5 */ +#define GTT_BAR0_MAP_REG_MSDM_RAM_1024 \ + 0x012000UL +/* Win 6 */ +#define GTT_BAR0_MAP_REG_USDM_RAM \ + 0x013000UL +/* Win 7 */ +#define GTT_BAR0_MAP_REG_USDM_RAM_1024 \ + 0x014000UL +/* Win 8 */ +#define GTT_BAR0_MAP_REG_USDM_RAM_2048 \ + 0x015000UL +/* Win 9 */ +#define GTT_BAR0_MAP_REG_XSDM_RAM \ + 0x016000UL +/* Win 10 */ +#define GTT_BAR0_MAP_REG_YSDM_RAM \ + 0x017000UL +/* Win 11 */ +#define GTT_BAR0_MAP_REG_PSDM_RAM \ + 0x018000UL + +/** + * @brief qed_qm_pf_mem_size - prepare QM ILT sizes + * + * Returns the required host memory size in 4KB units. + * Must be called before all QM init HSI functions. + * + * @param pf_id - physical function ID + * @param num_pf_cids - number of connections used by this PF + * @param num_vf_cids - number of connections used by VFs of this PF + * @param num_tids - number of tasks used by this PF + * @param num_pf_pqs - number of PQs used by this PF + * @param num_vf_pqs - number of PQs used by VFs of this PF + * + * @return The required host memory size in 4KB units. + */ +u32 qed_qm_pf_mem_size(u8 pf_id, + u32 num_pf_cids, + u32 num_vf_cids, + u32 num_tids, + u16 num_pf_pqs, + u16 num_vf_pqs); + +struct qed_qm_common_rt_init_params { + u8 max_ports_per_engine; + u8 max_phys_tcs_per_port; + bool pf_rl_en; + bool pf_wfq_en; + bool vport_rl_en; + bool vport_wfq_en; + struct init_qm_port_params *port_params; +}; + +/** + * @brief qed_qm_common_rt_init - Prepare QM runtime init values for the + * engine phase. + * + * @param p_hwfn + * @param max_ports_per_engine - max number of ports per engine in HW + * @param max_phys_tcs_per_port - max number of physical TCs per port in HW + * @param pf_rl_en - enable per-PF rate limiters + * @param pf_wfq_en - enable per-PF WFQ + * @param vport_rl_en - enable per-VPORT rate limiters + * @param vport_wfq_en - enable per-VPORT WFQ + * @param port_params - array of size MAX_NUM_PORTS with + * arameters for each port + * + * @return 0 on success, -1 on error. + */ +int qed_qm_common_rt_init( + struct qed_hwfn *p_hwfn, + struct qed_qm_common_rt_init_params *p_params); + +struct qed_qm_pf_rt_init_params { + u8 port_id; + u8 pf_id; + u8 max_phys_tcs_per_port; + bool is_first_pf; + u32 num_pf_cids; + u32 num_vf_cids; + u32 num_tids; + u16 start_pq; + u16 num_pf_pqs; + u16 num_vf_pqs; + u8 start_vport; + u8 num_vports; + u8 pf_wfq; + u32 pf_rl; + struct init_qm_pq_params *pq_params; + struct init_qm_vport_params *vport_params; +}; + +int qed_qm_pf_rt_init(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + struct qed_qm_pf_rt_init_params *p_params); + +/** + * @brief qed_init_pf_rl Initializes the rate limit of the specified PF + * + * @param p_hwfn + * @param p_ptt - ptt window used for writing the registers + * @param pf_id - PF ID + * @param pf_rl - rate limit in Mb/sec units + * + * @return 0 on success, -1 on error. + */ +int qed_init_pf_rl(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u8 pf_id, + u32 pf_rl); + +/** + * @brief qed_init_vport_rl Initializes the rate limit of the specified VPORT + * + * @param p_hwfn + * @param p_ptt - ptt window used for writing the registers + * @param vport_id - VPORT ID + * @param vport_rl - rate limit in Mb/sec units + * + * @return 0 on success, -1 on error. + */ + +int qed_init_vport_rl(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u8 vport_id, + u32 vport_rl); +/** + * @brief qed_send_qm_stop_cmd Sends a stop command to the QM + * + * @param p_hwfn + * @param p_ptt - ptt window used for writing the registers + * @param is_release_cmd - true for release, false for stop. + * @param is_tx_pq - true for Tx PQs, false for Other PQs. + * @param start_pq - first PQ ID to stop + * @param num_pqs - Number of PQs to stop, starting from start_pq. + * + * @return bool, true if successful, false if timeout occurred while waiting + * for QM command done. + */ + +bool qed_send_qm_stop_cmd(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + bool is_release_cmd, + bool is_tx_pq, + u16 start_pq, + u16 num_pqs); + +/* Ystorm flow control mode. Use enum fw_flow_ctrl_mode */ +#define YSTORM_FLOW_CONTROL_MODE_OFFSET (IRO[0].base) +#define YSTORM_FLOW_CONTROL_MODE_SIZE (IRO[0].size) +/* Tstorm port statistics */ +#define TSTORM_PORT_STAT_OFFSET(port_id) (IRO[1].base + \ + ((port_id) * \ + IRO[1].m1)) +#define TSTORM_PORT_STAT_SIZE (IRO[1].size) +/* Ustorm VF-PF Channel ready flag */ +#define USTORM_VF_PF_CHANNEL_READY_OFFSET(vf_id) (IRO[2].base + \ + ((vf_id) * \ + IRO[2].m1)) +#define USTORM_VF_PF_CHANNEL_READY_SIZE (IRO[2].size) +/* Ustorm Final flr cleanup ack */ +#define USTORM_FLR_FINAL_ACK_OFFSET (IRO[3].base) +#define USTORM_FLR_FINAL_ACK_SIZE (IRO[3].size) +/* Ustorm Event ring consumer */ +#define USTORM_EQE_CONS_OFFSET(pf_id) (IRO[4].base + \ + ((pf_id) * \ + IRO[4].m1)) +#define USTORM_EQE_CONS_SIZE (IRO[4].size) +/* Ustorm Completion ring consumer */ +#define USTORM_CQ_CONS_OFFSET(global_queue_id) (IRO[5].base + \ + ((global_queue_id) * \ + IRO[5].m1)) +#define USTORM_CQ_CONS_SIZE (IRO[5].size) +/* Xstorm Integration Test Data */ +#define XSTORM_INTEG_TEST_DATA_OFFSET (IRO[6].base) +#define XSTORM_INTEG_TEST_DATA_SIZE (IRO[6].size) +/* Ystorm Integration Test Data */ +#define YSTORM_INTEG_TEST_DATA_OFFSET (IRO[7].base) +#define YSTORM_INTEG_TEST_DATA_SIZE (IRO[7].size) +/* Pstorm Integration Test Data */ +#define PSTORM_INTEG_TEST_DATA_OFFSET (IRO[8].base) +#define PSTORM_INTEG_TEST_DATA_SIZE (IRO[8].size) +/* Tstorm Integration Test Data */ +#define TSTORM_INTEG_TEST_DATA_OFFSET (IRO[9].base) +#define TSTORM_INTEG_TEST_DATA_SIZE (IRO[9].size) +/* Mstorm Integration Test Data */ +#define MSTORM_INTEG_TEST_DATA_OFFSET (IRO[10].base) +#define MSTORM_INTEG_TEST_DATA_SIZE (IRO[10].size) +/* Ustorm Integration Test Data */ +#define USTORM_INTEG_TEST_DATA_OFFSET (IRO[11].base) +#define USTORM_INTEG_TEST_DATA_SIZE (IRO[11].size) +/* Tstorm producers */ +#define TSTORM_LL2_RX_PRODS_OFFSET(core_rx_queue_id) (IRO[12].base + \ + ((core_rx_queue_id) * \ + IRO[12].m1)) +#define TSTORM_LL2_RX_PRODS_SIZE (IRO[12].size) +/* Tstorm LiteL2 queue statistics */ +#define CORE_LL2_TSTORM_PER_QUEUE_STAT_OFFSET(core_rx_q_id) (IRO[13].base + \ + ((core_rx_q_id) * \ + IRO[13].m1)) +#define CORE_LL2_TSTORM_PER_QUEUE_STAT_SIZE (IRO[13].size) +/* Ustorm LiteL2 queue statistics */ +#define CORE_LL2_USTORM_PER_QUEUE_STAT_OFFSET(core_rx_q_id) (IRO[14].base + \ + ((core_rx_q_id) * \ + IRO[14].m1)) +#define CORE_LL2_USTORM_PER_QUEUE_STAT_SIZE (IRO[14].size) +/* Pstorm LiteL2 queue statistics */ +#define CORE_LL2_PSTORM_PER_QUEUE_STAT_OFFSET(core_txst_id) (IRO[15].base + \ + ((core_txst_id) * \ + IRO[15].m1)) +#define CORE_LL2_PSTORM_PER_QUEUE_STAT_SIZE (IRO[15].size) +/* Mstorm queue statistics */ +#define MSTORM_QUEUE_STAT_OFFSET(stat_counter_id) (IRO[16].base + \ + ((stat_counter_id) * \ + IRO[16].m1)) +#define MSTORM_QUEUE_STAT_SIZE (IRO[16].size) +/* Mstorm producers */ +#define MSTORM_PRODS_OFFSET(queue_id) (IRO[17].base + \ + ((queue_id) * \ + IRO[17].m1)) +#define MSTORM_PRODS_SIZE (IRO[17].size) +/* TPA agregation timeout in us resolution (on ASIC) */ +#define MSTORM_TPA_TIMEOUT_US_OFFSET (IRO[18].base) +#define MSTORM_TPA_TIMEOUT_US_SIZE (IRO[18].size) +/* Ustorm queue statistics */ +#define USTORM_QUEUE_STAT_OFFSET(stat_counter_id) (IRO[19].base + \ + ((stat_counter_id) * \ + IRO[19].m1)) +#define USTORM_QUEUE_STAT_SIZE (IRO[19].size) +/* Ustorm queue zone */ +#define USTORM_ETH_QUEUE_ZONE_OFFSET(queue_id) (IRO[20].base + \ + ((queue_id) * \ + IRO[20].m1)) +#define USTORM_ETH_QUEUE_ZONE_SIZE (IRO[20].size) +/* Pstorm queue statistics */ +#define PSTORM_QUEUE_STAT_OFFSET(stat_counter_id) (IRO[21].base + \ + ((stat_counter_id) * \ + IRO[21].m1)) +#define PSTORM_QUEUE_STAT_SIZE (IRO[21].size) +/* Tstorm last parser message */ +#define TSTORM_ETH_PRS_INPUT_OFFSET(pf_id) (IRO[22].base + \ + ((pf_id) * \ + IRO[22].m1)) +#define TSTORM_ETH_PRS_INPUT_SIZE (IRO[22].size) +/* Ystorm queue zone */ +#define YSTORM_ETH_QUEUE_ZONE_OFFSET(queue_id) (IRO[23].base + \ + ((queue_id) * \ + IRO[23].m1)) +#define YSTORM_ETH_QUEUE_ZONE_SIZE (IRO[23].size) +/* Ystorm cqe producer */ +#define YSTORM_TOE_CQ_PROD_OFFSET(rss_id) (IRO[24].base + \ + ((rss_id) * \ + IRO[24].m1)) +#define YSTORM_TOE_CQ_PROD_SIZE (IRO[24].size) +/* Ustorm cqe producer */ +#define USTORM_TOE_CQ_PROD_OFFSET(rss_id) (IRO[25].base + \ + ((rss_id) * \ + IRO[25].m1)) +#define USTORM_TOE_CQ_PROD_SIZE (IRO[25].size) +/* Ustorm grq producer */ +#define USTORM_TOE_GRQ_PROD_OFFSET(pf_id) (IRO[26].base + \ + ((pf_id) * \ + IRO[26].m1)) +#define USTORM_TOE_GRQ_PROD_SIZE (IRO[26].size) +/* Tstorm cmdq-cons of given command queue-id */ +#define TSTORM_SCSI_CMDQ_CONS_OFFSET(cmdq_queue_id) (IRO[27].base + \ + ((cmdq_queue_id) * \ + IRO[27].m1)) +#define TSTORM_SCSI_CMDQ_CONS_SIZE (IRO[27].size) +/* Mstorm rq-cons of given queue-id */ +#define MSTORM_SCSI_RQ_CONS_OFFSET(rq_queue_id) (IRO[28].base + \ + ((rq_queue_id) * \ + IRO[28].m1)) +#define MSTORM_SCSI_RQ_CONS_SIZE (IRO[28].size) +/* Pstorm RoCE statistics */ +#define PSTORM_ROCE_STAT_OFFSET(stat_counter_id) (IRO[29].base + \ + ((stat_counter_id) * \ + IRO[29].m1)) +#define PSTORM_ROCE_STAT_SIZE (IRO[29].size) +/* Tstorm RoCE statistics */ +#define TSTORM_ROCE_STAT_OFFSET(stat_counter_id) (IRO[30].base + \ + ((stat_counter_id) * \ + IRO[30].m1)) +#define TSTORM_ROCE_STAT_SIZE (IRO[30].size) + +static const struct iro iro_arr[31] = { + { 0x10, 0x0, 0x0, 0x0, 0x8 }, + { 0x4448, 0x60, 0x0, 0x0, 0x60 }, + { 0x498, 0x8, 0x0, 0x0, 0x4 }, + { 0x494, 0x0, 0x0, 0x0, 0x4 }, + { 0x10, 0x8, 0x0, 0x0, 0x2 }, + { 0x90, 0x8, 0x0, 0x0, 0x2 }, + { 0x4540, 0x0, 0x0, 0x0, 0xf8 }, + { 0x39e0, 0x0, 0x0, 0x0, 0xf8 }, + { 0x2598, 0x0, 0x0, 0x0, 0xf8 }, + { 0x4350, 0x0, 0x0, 0x0, 0xf8 }, + { 0x52d0, 0x0, 0x0, 0x0, 0xf8 }, + { 0x7a48, 0x0, 0x0, 0x0, 0xf8 }, + { 0x100, 0x8, 0x0, 0x0, 0x8 }, + { 0x5808, 0x10, 0x0, 0x0, 0x10 }, + { 0xb100, 0x30, 0x0, 0x0, 0x30 }, + { 0x95c0, 0x30, 0x0, 0x0, 0x30 }, + { 0x54f8, 0x40, 0x0, 0x0, 0x40 }, + { 0x200, 0x10, 0x0, 0x0, 0x8 }, + { 0x9e70, 0x0, 0x0, 0x0, 0x4 }, + { 0x7ca0, 0x40, 0x0, 0x0, 0x30 }, + { 0xd00, 0x8, 0x0, 0x0, 0x8 }, + { 0x2790, 0x80, 0x0, 0x0, 0x38 }, + { 0xa520, 0xf0, 0x0, 0x0, 0xf0 }, + { 0x80, 0x8, 0x0, 0x0, 0x8 }, + { 0xac0, 0x8, 0x0, 0x0, 0x8 }, + { 0x2580, 0x8, 0x0, 0x0, 0x8 }, + { 0x2500, 0x8, 0x0, 0x0, 0x8 }, + { 0x440, 0x8, 0x0, 0x0, 0x2 }, + { 0x1800, 0x8, 0x0, 0x0, 0x2 }, + { 0x27c8, 0x80, 0x0, 0x0, 0x10 }, + { 0x4710, 0x10, 0x0, 0x0, 0x10 }, +}; + +/* Runtime array offsets */ +#define DORQ_REG_PF_MAX_ICID_0_RT_OFFSET 0 +#define DORQ_REG_PF_MAX_ICID_1_RT_OFFSET 1 +#define DORQ_REG_PF_MAX_ICID_2_RT_OFFSET 2 +#define DORQ_REG_PF_MAX_ICID_3_RT_OFFSET 3 +#define DORQ_REG_PF_MAX_ICID_4_RT_OFFSET 4 +#define DORQ_REG_PF_MAX_ICID_5_RT_OFFSET 5 +#define DORQ_REG_PF_MAX_ICID_6_RT_OFFSET 6 +#define DORQ_REG_PF_MAX_ICID_7_RT_OFFSET 7 +#define DORQ_REG_VF_MAX_ICID_0_RT_OFFSET 8 +#define DORQ_REG_VF_MAX_ICID_1_RT_OFFSET 9 +#define DORQ_REG_VF_MAX_ICID_2_RT_OFFSET 10 +#define DORQ_REG_VF_MAX_ICID_3_RT_OFFSET 11 +#define DORQ_REG_VF_MAX_ICID_4_RT_OFFSET 12 +#define DORQ_REG_VF_MAX_ICID_5_RT_OFFSET 13 +#define DORQ_REG_VF_MAX_ICID_6_RT_OFFSET 14 +#define DORQ_REG_VF_MAX_ICID_7_RT_OFFSET 15 +#define DORQ_REG_PF_WAKE_ALL_RT_OFFSET 16 +#define IGU_REG_PF_CONFIGURATION_RT_OFFSET 17 +#define IGU_REG_VF_CONFIGURATION_RT_OFFSET 18 +#define IGU_REG_ATTN_MSG_ADDR_L_RT_OFFSET 19 +#define IGU_REG_ATTN_MSG_ADDR_H_RT_OFFSET 20 +#define IGU_REG_LEADING_EDGE_LATCH_RT_OFFSET 21 +#define IGU_REG_TRAILING_EDGE_LATCH_RT_OFFSET 22 +#define CAU_REG_CQE_AGG_UNIT_SIZE_RT_OFFSET 23 +#define CAU_REG_SB_VAR_MEMORY_RT_OFFSET 760 +#define CAU_REG_SB_VAR_MEMORY_RT_SIZE 736 +#define CAU_REG_SB_VAR_MEMORY_RT_OFFSET 760 +#define CAU_REG_SB_VAR_MEMORY_RT_SIZE 736 +#define CAU_REG_SB_ADDR_MEMORY_RT_OFFSET 1496 +#define CAU_REG_SB_ADDR_MEMORY_RT_SIZE 736 +#define CAU_REG_PI_MEMORY_RT_OFFSET 2232 +#define CAU_REG_PI_MEMORY_RT_SIZE 4416 +#define PRS_REG_SEARCH_RESP_INITIATOR_TYPE_RT_OFFSET 6648 +#define PRS_REG_TASK_ID_MAX_INITIATOR_PF_RT_OFFSET 6649 +#define PRS_REG_TASK_ID_MAX_INITIATOR_VF_RT_OFFSET 6650 +#define PRS_REG_TASK_ID_MAX_TARGET_PF_RT_OFFSET 6651 +#define PRS_REG_TASK_ID_MAX_TARGET_VF_RT_OFFSET 6652 +#define PRS_REG_SEARCH_TCP_RT_OFFSET 6653 +#define PRS_REG_SEARCH_FCOE_RT_OFFSET 6654 +#define PRS_REG_SEARCH_ROCE_RT_OFFSET 6655 +#define PRS_REG_ROCE_DEST_QP_MAX_VF_RT_OFFSET 6656 +#define PRS_REG_ROCE_DEST_QP_MAX_PF_RT_OFFSET 6657 +#define PRS_REG_SEARCH_OPENFLOW_RT_OFFSET 6658 +#define PRS_REG_SEARCH_NON_IP_AS_OPENFLOW_RT_OFFSET 6659 +#define PRS_REG_OPENFLOW_SUPPORT_ONLY_KNOWN_OVER_IP_RT_OFFSET 6660 +#define PRS_REG_OPENFLOW_SEARCH_KEY_MASK_RT_OFFSET 6661 +#define PRS_REG_LIGHT_L2_ETHERTYPE_EN_RT_OFFSET 6662 +#define SRC_REG_FIRSTFREE_RT_OFFSET 6663 +#define SRC_REG_FIRSTFREE_RT_SIZE 2 +#define SRC_REG_LASTFREE_RT_OFFSET 6665 +#define SRC_REG_LASTFREE_RT_SIZE 2 +#define SRC_REG_COUNTFREE_RT_OFFSET 6667 +#define SRC_REG_NUMBER_HASH_BITS_RT_OFFSET 6668 +#define PSWRQ2_REG_CDUT_P_SIZE_RT_OFFSET 6669 +#define PSWRQ2_REG_CDUC_P_SIZE_RT_OFFSET 6670 +#define PSWRQ2_REG_TM_P_SIZE_RT_OFFSET 6671 +#define PSWRQ2_REG_QM_P_SIZE_RT_OFFSET 6672 +#define PSWRQ2_REG_SRC_P_SIZE_RT_OFFSET 6673 +#define PSWRQ2_REG_TM_FIRST_ILT_RT_OFFSET 6674 +#define PSWRQ2_REG_TM_LAST_ILT_RT_OFFSET 6675 +#define PSWRQ2_REG_QM_FIRST_ILT_RT_OFFSET 6676 +#define PSWRQ2_REG_QM_LAST_ILT_RT_OFFSET 6677 +#define PSWRQ2_REG_SRC_FIRST_ILT_RT_OFFSET 6678 +#define PSWRQ2_REG_SRC_LAST_ILT_RT_OFFSET 6679 +#define PSWRQ2_REG_CDUC_FIRST_ILT_RT_OFFSET 6680 +#define PSWRQ2_REG_CDUC_LAST_ILT_RT_OFFSET 6681 +#define PSWRQ2_REG_CDUT_FIRST_ILT_RT_OFFSET 6682 +#define PSWRQ2_REG_CDUT_LAST_ILT_RT_OFFSET 6683 +#define PSWRQ2_REG_TSDM_FIRST_ILT_RT_OFFSET 6684 +#define PSWRQ2_REG_TSDM_LAST_ILT_RT_OFFSET 6685 +#define PSWRQ2_REG_TM_NUMBER_OF_PF_BLOCKS_RT_OFFSET 6686 +#define PSWRQ2_REG_CDUT_NUMBER_OF_PF_BLOCKS_RT_OFFSET 6687 +#define PSWRQ2_REG_CDUC_NUMBER_OF_PF_BLOCKS_RT_OFFSET 6688 +#define PSWRQ2_REG_TM_VF_BLOCKS_RT_OFFSET 6689 +#define PSWRQ2_REG_CDUT_VF_BLOCKS_RT_OFFSET 6690 +#define PSWRQ2_REG_CDUC_VF_BLOCKS_RT_OFFSET 6691 +#define PSWRQ2_REG_TM_BLOCKS_FACTOR_RT_OFFSET 6692 +#define PSWRQ2_REG_CDUT_BLOCKS_FACTOR_RT_OFFSET 6693 +#define PSWRQ2_REG_CDUC_BLOCKS_FACTOR_RT_OFFSET 6694 +#define PSWRQ2_REG_VF_BASE_RT_OFFSET 6695 +#define PSWRQ2_REG_VF_LAST_ILT_RT_OFFSET 6696 +#define PSWRQ2_REG_WR_MBS0_RT_OFFSET 6697 +#define PSWRQ2_REG_RD_MBS0_RT_OFFSET 6698 +#define PSWRQ2_REG_DRAM_ALIGN_WR_RT_OFFSET 6699 +#define PSWRQ2_REG_DRAM_ALIGN_RD_RT_OFFSET 6700 +#define PSWRQ2_REG_ILT_MEMORY_RT_OFFSET 6701 +#define PSWRQ2_REG_ILT_MEMORY_RT_SIZE 22000 +#define PGLUE_REG_B_VF_BASE_RT_OFFSET 28701 +#define PGLUE_REG_B_CACHE_LINE_SIZE_RT_OFFSET 28702 +#define PGLUE_REG_B_PF_BAR0_SIZE_RT_OFFSET 28703 +#define PGLUE_REG_B_PF_BAR1_SIZE_RT_OFFSET 28704 +#define PGLUE_REG_B_VF_BAR1_SIZE_RT_OFFSET 28705 +#define TM_REG_VF_ENABLE_CONN_RT_OFFSET 28706 +#define TM_REG_PF_ENABLE_CONN_RT_OFFSET 28707 +#define TM_REG_PF_ENABLE_TASK_RT_OFFSET 28708 +#define TM_REG_GROUP_SIZE_RESOLUTION_CONN_RT_OFFSET 28709 +#define TM_REG_GROUP_SIZE_RESOLUTION_TASK_RT_OFFSET 28710 +#define TM_REG_CONFIG_CONN_MEM_RT_OFFSET 28711 +#define TM_REG_CONFIG_CONN_MEM_RT_SIZE 416 +#define TM_REG_CONFIG_TASK_MEM_RT_OFFSET 29127 +#define TM_REG_CONFIG_TASK_MEM_RT_SIZE 512 +#define QM_REG_MAXPQSIZE_0_RT_OFFSET 29639 +#define QM_REG_MAXPQSIZE_1_RT_OFFSET 29640 +#define QM_REG_MAXPQSIZE_2_RT_OFFSET 29641 +#define QM_REG_MAXPQSIZETXSEL_0_RT_OFFSET 29642 +#define QM_REG_MAXPQSIZETXSEL_1_RT_OFFSET 29643 +#define QM_REG_MAXPQSIZETXSEL_2_RT_OFFSET 29644 +#define QM_REG_MAXPQSIZETXSEL_3_RT_OFFSET 29645 +#define QM_REG_MAXPQSIZETXSEL_4_RT_OFFSET 29646 +#define QM_REG_MAXPQSIZETXSEL_5_RT_OFFSET 29647 +#define QM_REG_MAXPQSIZETXSEL_6_RT_OFFSET 29648 +#define QM_REG_MAXPQSIZETXSEL_7_RT_OFFSET 29649 +#define QM_REG_MAXPQSIZETXSEL_8_RT_OFFSET 29650 +#define QM_REG_MAXPQSIZETXSEL_9_RT_OFFSET 29651 +#define QM_REG_MAXPQSIZETXSEL_10_RT_OFFSET 29652 +#define QM_REG_MAXPQSIZETXSEL_11_RT_OFFSET 29653 +#define QM_REG_MAXPQSIZETXSEL_12_RT_OFFSET 29654 +#define QM_REG_MAXPQSIZETXSEL_13_RT_OFFSET 29655 +#define QM_REG_MAXPQSIZETXSEL_14_RT_OFFSET 29656 +#define QM_REG_MAXPQSIZETXSEL_15_RT_OFFSET 29657 +#define QM_REG_MAXPQSIZETXSEL_16_RT_OFFSET 29658 +#define QM_REG_MAXPQSIZETXSEL_17_RT_OFFSET 29659 +#define QM_REG_MAXPQSIZETXSEL_18_RT_OFFSET 29660 +#define QM_REG_MAXPQSIZETXSEL_19_RT_OFFSET 29661 +#define QM_REG_MAXPQSIZETXSEL_20_RT_OFFSET 29662 +#define QM_REG_MAXPQSIZETXSEL_21_RT_OFFSET 29663 +#define QM_REG_MAXPQSIZETXSEL_22_RT_OFFSET 29664 +#define QM_REG_MAXPQSIZETXSEL_23_RT_OFFSET 29665 +#define QM_REG_MAXPQSIZETXSEL_24_RT_OFFSET 29666 +#define QM_REG_MAXPQSIZETXSEL_25_RT_OFFSET 29667 +#define QM_REG_MAXPQSIZETXSEL_26_RT_OFFSET 29668 +#define QM_REG_MAXPQSIZETXSEL_27_RT_OFFSET 29669 +#define QM_REG_MAXPQSIZETXSEL_28_RT_OFFSET 29670 +#define QM_REG_MAXPQSIZETXSEL_29_RT_OFFSET 29671 +#define QM_REG_MAXPQSIZETXSEL_30_RT_OFFSET 29672 +#define QM_REG_MAXPQSIZETXSEL_31_RT_OFFSET 29673 +#define QM_REG_MAXPQSIZETXSEL_32_RT_OFFSET 29674 +#define QM_REG_MAXPQSIZETXSEL_33_RT_OFFSET 29675 +#define QM_REG_MAXPQSIZETXSEL_34_RT_OFFSET 29676 +#define QM_REG_MAXPQSIZETXSEL_35_RT_OFFSET 29677 +#define QM_REG_MAXPQSIZETXSEL_36_RT_OFFSET 29678 +#define QM_REG_MAXPQSIZETXSEL_37_RT_OFFSET 29679 +#define QM_REG_MAXPQSIZETXSEL_38_RT_OFFSET 29680 +#define QM_REG_MAXPQSIZETXSEL_39_RT_OFFSET 29681 +#define QM_REG_MAXPQSIZETXSEL_40_RT_OFFSET 29682 +#define QM_REG_MAXPQSIZETXSEL_41_RT_OFFSET 29683 +#define QM_REG_MAXPQSIZETXSEL_42_RT_OFFSET 29684 +#define QM_REG_MAXPQSIZETXSEL_43_RT_OFFSET 29685 +#define QM_REG_MAXPQSIZETXSEL_44_RT_OFFSET 29686 +#define QM_REG_MAXPQSIZETXSEL_45_RT_OFFSET 29687 +#define QM_REG_MAXPQSIZETXSEL_46_RT_OFFSET 29688 +#define QM_REG_MAXPQSIZETXSEL_47_RT_OFFSET 29689 +#define QM_REG_MAXPQSIZETXSEL_48_RT_OFFSET 29690 +#define QM_REG_MAXPQSIZETXSEL_49_RT_OFFSET 29691 +#define QM_REG_MAXPQSIZETXSEL_50_RT_OFFSET 29692 +#define QM_REG_MAXPQSIZETXSEL_51_RT_OFFSET 29693 +#define QM_REG_MAXPQSIZETXSEL_52_RT_OFFSET 29694 +#define QM_REG_MAXPQSIZETXSEL_53_RT_OFFSET 29695 +#define QM_REG_MAXPQSIZETXSEL_54_RT_OFFSET 29696 +#define QM_REG_MAXPQSIZETXSEL_55_RT_OFFSET 29697 +#define QM_REG_MAXPQSIZETXSEL_56_RT_OFFSET 29698 +#define QM_REG_MAXPQSIZETXSEL_57_RT_OFFSET 29699 +#define QM_REG_MAXPQSIZETXSEL_58_RT_OFFSET 29700 +#define QM_REG_MAXPQSIZETXSEL_59_RT_OFFSET 29701 +#define QM_REG_MAXPQSIZETXSEL_60_RT_OFFSET 29702 +#define QM_REG_MAXPQSIZETXSEL_61_RT_OFFSET 29703 +#define QM_REG_MAXPQSIZETXSEL_62_RT_OFFSET 29704 +#define QM_REG_MAXPQSIZETXSEL_63_RT_OFFSET 29705 +#define QM_REG_BASEADDROTHERPQ_RT_OFFSET 29706 +#define QM_REG_BASEADDROTHERPQ_RT_SIZE 128 +#define QM_REG_VOQCRDLINE_RT_OFFSET 29834 +#define QM_REG_VOQCRDLINE_RT_SIZE 20 +#define QM_REG_VOQINITCRDLINE_RT_OFFSET 29854 +#define QM_REG_VOQINITCRDLINE_RT_SIZE 20 +#define QM_REG_AFULLQMBYPTHRPFWFQ_RT_OFFSET 29874 +#define QM_REG_AFULLQMBYPTHRVPWFQ_RT_OFFSET 29875 +#define QM_REG_AFULLQMBYPTHRPFRL_RT_OFFSET 29876 +#define QM_REG_AFULLQMBYPTHRGLBLRL_RT_OFFSET 29877 +#define QM_REG_AFULLOPRTNSTCCRDMASK_RT_OFFSET 29878 +#define QM_REG_WRROTHERPQGRP_0_RT_OFFSET 29879 +#define QM_REG_WRROTHERPQGRP_1_RT_OFFSET 29880 +#define QM_REG_WRROTHERPQGRP_2_RT_OFFSET 29881 +#define QM_REG_WRROTHERPQGRP_3_RT_OFFSET 29882 +#define QM_REG_WRROTHERPQGRP_4_RT_OFFSET 29883 +#define QM_REG_WRROTHERPQGRP_5_RT_OFFSET 29884 +#define QM_REG_WRROTHERPQGRP_6_RT_OFFSET 29885 +#define QM_REG_WRROTHERPQGRP_7_RT_OFFSET 29886 +#define QM_REG_WRROTHERPQGRP_8_RT_OFFSET 29887 +#define QM_REG_WRROTHERPQGRP_9_RT_OFFSET 29888 +#define QM_REG_WRROTHERPQGRP_10_RT_OFFSET 29889 +#define QM_REG_WRROTHERPQGRP_11_RT_OFFSET 29890 +#define QM_REG_WRROTHERPQGRP_12_RT_OFFSET 29891 +#define QM_REG_WRROTHERPQGRP_13_RT_OFFSET 29892 +#define QM_REG_WRROTHERPQGRP_14_RT_OFFSET 29893 +#define QM_REG_WRROTHERPQGRP_15_RT_OFFSET 29894 +#define QM_REG_WRROTHERGRPWEIGHT_0_RT_OFFSET 29895 +#define QM_REG_WRROTHERGRPWEIGHT_1_RT_OFFSET 29896 +#define QM_REG_WRROTHERGRPWEIGHT_2_RT_OFFSET 29897 +#define QM_REG_WRROTHERGRPWEIGHT_3_RT_OFFSET 29898 +#define QM_REG_WRRTXGRPWEIGHT_0_RT_OFFSET 29899 +#define QM_REG_WRRTXGRPWEIGHT_1_RT_OFFSET 29900 +#define QM_REG_PQTX2PF_0_RT_OFFSET 29901 +#define QM_REG_PQTX2PF_1_RT_OFFSET 29902 +#define QM_REG_PQTX2PF_2_RT_OFFSET 29903 +#define QM_REG_PQTX2PF_3_RT_OFFSET 29904 +#define QM_REG_PQTX2PF_4_RT_OFFSET 29905 +#define QM_REG_PQTX2PF_5_RT_OFFSET 29906 +#define QM_REG_PQTX2PF_6_RT_OFFSET 29907 +#define QM_REG_PQTX2PF_7_RT_OFFSET 29908 +#define QM_REG_PQTX2PF_8_RT_OFFSET 29909 +#define QM_REG_PQTX2PF_9_RT_OFFSET 29910 +#define QM_REG_PQTX2PF_10_RT_OFFSET 29911 +#define QM_REG_PQTX2PF_11_RT_OFFSET 29912 +#define QM_REG_PQTX2PF_12_RT_OFFSET 29913 +#define QM_REG_PQTX2PF_13_RT_OFFSET 29914 +#define QM_REG_PQTX2PF_14_RT_OFFSET 29915 +#define QM_REG_PQTX2PF_15_RT_OFFSET 29916 +#define QM_REG_PQTX2PF_16_RT_OFFSET 29917 +#define QM_REG_PQTX2PF_17_RT_OFFSET 29918 +#define QM_REG_PQTX2PF_18_RT_OFFSET 29919 +#define QM_REG_PQTX2PF_19_RT_OFFSET 29920 +#define QM_REG_PQTX2PF_20_RT_OFFSET 29921 +#define QM_REG_PQTX2PF_21_RT_OFFSET 29922 +#define QM_REG_PQTX2PF_22_RT_OFFSET 29923 +#define QM_REG_PQTX2PF_23_RT_OFFSET 29924 +#define QM_REG_PQTX2PF_24_RT_OFFSET 29925 +#define QM_REG_PQTX2PF_25_RT_OFFSET 29926 +#define QM_REG_PQTX2PF_26_RT_OFFSET 29927 +#define QM_REG_PQTX2PF_27_RT_OFFSET 29928 +#define QM_REG_PQTX2PF_28_RT_OFFSET 29929 +#define QM_REG_PQTX2PF_29_RT_OFFSET 29930 +#define QM_REG_PQTX2PF_30_RT_OFFSET 29931 +#define QM_REG_PQTX2PF_31_RT_OFFSET 29932 +#define QM_REG_PQTX2PF_32_RT_OFFSET 29933 +#define QM_REG_PQTX2PF_33_RT_OFFSET 29934 +#define QM_REG_PQTX2PF_34_RT_OFFSET 29935 +#define QM_REG_PQTX2PF_35_RT_OFFSET 29936 +#define QM_REG_PQTX2PF_36_RT_OFFSET 29937 +#define QM_REG_PQTX2PF_37_RT_OFFSET 29938 +#define QM_REG_PQTX2PF_38_RT_OFFSET 29939 +#define QM_REG_PQTX2PF_39_RT_OFFSET 29940 +#define QM_REG_PQTX2PF_40_RT_OFFSET 29941 +#define QM_REG_PQTX2PF_41_RT_OFFSET 29942 +#define QM_REG_PQTX2PF_42_RT_OFFSET 29943 +#define QM_REG_PQTX2PF_43_RT_OFFSET 29944 +#define QM_REG_PQTX2PF_44_RT_OFFSET 29945 +#define QM_REG_PQTX2PF_45_RT_OFFSET 29946 +#define QM_REG_PQTX2PF_46_RT_OFFSET 29947 +#define QM_REG_PQTX2PF_47_RT_OFFSET 29948 +#define QM_REG_PQTX2PF_48_RT_OFFSET 29949 +#define QM_REG_PQTX2PF_49_RT_OFFSET 29950 +#define QM_REG_PQTX2PF_50_RT_OFFSET 29951 +#define QM_REG_PQTX2PF_51_RT_OFFSET 29952 +#define QM_REG_PQTX2PF_52_RT_OFFSET 29953 +#define QM_REG_PQTX2PF_53_RT_OFFSET 29954 +#define QM_REG_PQTX2PF_54_RT_OFFSET 29955 +#define QM_REG_PQTX2PF_55_RT_OFFSET 29956 +#define QM_REG_PQTX2PF_56_RT_OFFSET 29957 +#define QM_REG_PQTX2PF_57_RT_OFFSET 29958 +#define QM_REG_PQTX2PF_58_RT_OFFSET 29959 +#define QM_REG_PQTX2PF_59_RT_OFFSET 29960 +#define QM_REG_PQTX2PF_60_RT_OFFSET 29961 +#define QM_REG_PQTX2PF_61_RT_OFFSET 29962 +#define QM_REG_PQTX2PF_62_RT_OFFSET 29963 +#define QM_REG_PQTX2PF_63_RT_OFFSET 29964 +#define QM_REG_PQOTHER2PF_0_RT_OFFSET 29965 +#define QM_REG_PQOTHER2PF_1_RT_OFFSET 29966 +#define QM_REG_PQOTHER2PF_2_RT_OFFSET 29967 +#define QM_REG_PQOTHER2PF_3_RT_OFFSET 29968 +#define QM_REG_PQOTHER2PF_4_RT_OFFSET 29969 +#define QM_REG_PQOTHER2PF_5_RT_OFFSET 29970 +#define QM_REG_PQOTHER2PF_6_RT_OFFSET 29971 +#define QM_REG_PQOTHER2PF_7_RT_OFFSET 29972 +#define QM_REG_PQOTHER2PF_8_RT_OFFSET 29973 +#define QM_REG_PQOTHER2PF_9_RT_OFFSET 29974 +#define QM_REG_PQOTHER2PF_10_RT_OFFSET 29975 +#define QM_REG_PQOTHER2PF_11_RT_OFFSET 29976 +#define QM_REG_PQOTHER2PF_12_RT_OFFSET 29977 +#define QM_REG_PQOTHER2PF_13_RT_OFFSET 29978 +#define QM_REG_PQOTHER2PF_14_RT_OFFSET 29979 +#define QM_REG_PQOTHER2PF_15_RT_OFFSET 29980 +#define QM_REG_RLGLBLPERIOD_0_RT_OFFSET 29981 +#define QM_REG_RLGLBLPERIOD_1_RT_OFFSET 29982 +#define QM_REG_RLGLBLPERIODTIMER_0_RT_OFFSET 29983 +#define QM_REG_RLGLBLPERIODTIMER_1_RT_OFFSET 29984 +#define QM_REG_RLGLBLPERIODSEL_0_RT_OFFSET 29985 +#define QM_REG_RLGLBLPERIODSEL_1_RT_OFFSET 29986 +#define QM_REG_RLGLBLPERIODSEL_2_RT_OFFSET 29987 +#define QM_REG_RLGLBLPERIODSEL_3_RT_OFFSET 29988 +#define QM_REG_RLGLBLPERIODSEL_4_RT_OFFSET 29989 +#define QM_REG_RLGLBLPERIODSEL_5_RT_OFFSET 29990 +#define QM_REG_RLGLBLPERIODSEL_6_RT_OFFSET 29991 +#define QM_REG_RLGLBLPERIODSEL_7_RT_OFFSET 29992 +#define QM_REG_RLGLBLINCVAL_RT_OFFSET 29993 +#define QM_REG_RLGLBLINCVAL_RT_SIZE 256 +#define QM_REG_RLGLBLUPPERBOUND_RT_OFFSET 30249 +#define QM_REG_RLGLBLUPPERBOUND_RT_SIZE 256 +#define QM_REG_RLGLBLCRD_RT_OFFSET 30505 +#define QM_REG_RLGLBLCRD_RT_SIZE 256 +#define QM_REG_RLGLBLENABLE_RT_OFFSET 30761 +#define QM_REG_RLPFPERIOD_RT_OFFSET 30762 +#define QM_REG_RLPFPERIODTIMER_RT_OFFSET 30763 +#define QM_REG_RLPFINCVAL_RT_OFFSET 30764 +#define QM_REG_RLPFINCVAL_RT_SIZE 16 +#define QM_REG_RLPFUPPERBOUND_RT_OFFSET 30780 +#define QM_REG_RLPFUPPERBOUND_RT_SIZE 16 +#define QM_REG_RLPFCRD_RT_OFFSET 30796 +#define QM_REG_RLPFCRD_RT_SIZE 16 +#define QM_REG_RLPFENABLE_RT_OFFSET 30812 +#define QM_REG_RLPFVOQENABLE_RT_OFFSET 30813 +#define QM_REG_WFQPFWEIGHT_RT_OFFSET 30814 +#define QM_REG_WFQPFWEIGHT_RT_SIZE 16 +#define QM_REG_WFQPFUPPERBOUND_RT_OFFSET 30830 +#define QM_REG_WFQPFUPPERBOUND_RT_SIZE 16 +#define QM_REG_WFQPFCRD_RT_OFFSET 30846 +#define QM_REG_WFQPFCRD_RT_SIZE 160 +#define QM_REG_WFQPFENABLE_RT_OFFSET 31006 +#define QM_REG_WFQVPENABLE_RT_OFFSET 31007 +#define QM_REG_BASEADDRTXPQ_RT_OFFSET 31008 +#define QM_REG_BASEADDRTXPQ_RT_SIZE 512 +#define QM_REG_TXPQMAP_RT_OFFSET 31520 +#define QM_REG_TXPQMAP_RT_SIZE 512 +#define QM_REG_WFQVPWEIGHT_RT_OFFSET 32032 +#define QM_REG_WFQVPWEIGHT_RT_SIZE 512 +#define QM_REG_WFQVPUPPERBOUND_RT_OFFSET 32544 +#define QM_REG_WFQVPUPPERBOUND_RT_SIZE 512 +#define QM_REG_WFQVPCRD_RT_OFFSET 33056 +#define QM_REG_WFQVPCRD_RT_SIZE 512 +#define QM_REG_WFQVPMAP_RT_OFFSET 33568 +#define QM_REG_WFQVPMAP_RT_SIZE 512 +#define QM_REG_WFQPFCRD_MSB_RT_OFFSET 34080 +#define QM_REG_WFQPFCRD_MSB_RT_SIZE 160 +#define NIG_REG_LLH_CLS_TYPE_DUALMODE_RT_OFFSET 34240 +#define NIG_REG_OUTER_TAG_VALUE_LIST0_RT_OFFSET 34241 +#define NIG_REG_OUTER_TAG_VALUE_LIST1_RT_OFFSET 34242 +#define NIG_REG_OUTER_TAG_VALUE_LIST2_RT_OFFSET 34243 +#define NIG_REG_OUTER_TAG_VALUE_LIST3_RT_OFFSET 34244 +#define NIG_REG_OUTER_TAG_VALUE_MASK_RT_OFFSET 34245 +#define NIG_REG_LLH_FUNC_TAGMAC_CLS_TYPE_RT_OFFSET 34246 +#define NIG_REG_LLH_FUNC_TAG_EN_RT_OFFSET 34247 +#define NIG_REG_LLH_FUNC_TAG_EN_RT_SIZE 4 +#define NIG_REG_LLH_FUNC_TAG_HDR_SEL_RT_OFFSET 34251 +#define NIG_REG_LLH_FUNC_TAG_HDR_SEL_RT_SIZE 4 +#define NIG_REG_LLH_FUNC_TAG_VALUE_RT_OFFSET 34255 +#define NIG_REG_LLH_FUNC_TAG_VALUE_RT_SIZE 4 +#define NIG_REG_LLH_FUNC_NO_TAG_RT_OFFSET 34259 +#define NIG_REG_LLH_FUNC_FILTER_VALUE_RT_OFFSET 34260 +#define NIG_REG_LLH_FUNC_FILTER_VALUE_RT_SIZE 32 +#define NIG_REG_LLH_FUNC_FILTER_EN_RT_OFFSET 34292 +#define NIG_REG_LLH_FUNC_FILTER_EN_RT_SIZE 16 +#define NIG_REG_LLH_FUNC_FILTER_MODE_RT_OFFSET 34308 +#define NIG_REG_LLH_FUNC_FILTER_MODE_RT_SIZE 16 +#define NIG_REG_LLH_FUNC_FILTER_PROTOCOL_TYPE_RT_OFFSET 34324 +#define NIG_REG_LLH_FUNC_FILTER_PROTOCOL_TYPE_RT_SIZE 16 +#define NIG_REG_LLH_FUNC_FILTER_HDR_SEL_RT_OFFSET 34340 +#define NIG_REG_LLH_FUNC_FILTER_HDR_SEL_RT_SIZE 16 +#define NIG_REG_TX_EDPM_CTRL_RT_OFFSET 34356 +#define CDU_REG_CID_ADDR_PARAMS_RT_OFFSET 34357 +#define CDU_REG_SEGMENT0_PARAMS_RT_OFFSET 34358 +#define CDU_REG_SEGMENT1_PARAMS_RT_OFFSET 34359 +#define CDU_REG_PF_SEG0_TYPE_OFFSET_RT_OFFSET 34360 +#define CDU_REG_PF_SEG1_TYPE_OFFSET_RT_OFFSET 34361 +#define CDU_REG_PF_SEG2_TYPE_OFFSET_RT_OFFSET 34362 +#define CDU_REG_PF_SEG3_TYPE_OFFSET_RT_OFFSET 34363 +#define CDU_REG_PF_FL_SEG0_TYPE_OFFSET_RT_OFFSET 34364 +#define CDU_REG_PF_FL_SEG1_TYPE_OFFSET_RT_OFFSET 34365 +#define CDU_REG_PF_FL_SEG2_TYPE_OFFSET_RT_OFFSET 34366 +#define CDU_REG_PF_FL_SEG3_TYPE_OFFSET_RT_OFFSET 34367 +#define CDU_REG_VF_SEG_TYPE_OFFSET_RT_OFFSET 34368 +#define CDU_REG_VF_FL_SEG_TYPE_OFFSET_RT_OFFSET 34369 +#define PBF_REG_BTB_SHARED_AREA_SIZE_RT_OFFSET 34370 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ0_RT_OFFSET 34371 +#define PBF_REG_BTB_GUARANTEED_VOQ0_RT_OFFSET 34372 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ0_RT_OFFSET 34373 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ1_RT_OFFSET 34374 +#define PBF_REG_BTB_GUARANTEED_VOQ1_RT_OFFSET 34375 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ1_RT_OFFSET 34376 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ2_RT_OFFSET 34377 +#define PBF_REG_BTB_GUARANTEED_VOQ2_RT_OFFSET 34378 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ2_RT_OFFSET 34379 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ3_RT_OFFSET 34380 +#define PBF_REG_BTB_GUARANTEED_VOQ3_RT_OFFSET 34381 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ3_RT_OFFSET 34382 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ4_RT_OFFSET 34383 +#define PBF_REG_BTB_GUARANTEED_VOQ4_RT_OFFSET 34384 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ4_RT_OFFSET 34385 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ5_RT_OFFSET 34386 +#define PBF_REG_BTB_GUARANTEED_VOQ5_RT_OFFSET 34387 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ5_RT_OFFSET 34388 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ6_RT_OFFSET 34389 +#define PBF_REG_BTB_GUARANTEED_VOQ6_RT_OFFSET 34390 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ6_RT_OFFSET 34391 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ7_RT_OFFSET 34392 +#define PBF_REG_BTB_GUARANTEED_VOQ7_RT_OFFSET 34393 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ7_RT_OFFSET 34394 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ8_RT_OFFSET 34395 +#define PBF_REG_BTB_GUARANTEED_VOQ8_RT_OFFSET 34396 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ8_RT_OFFSET 34397 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ9_RT_OFFSET 34398 +#define PBF_REG_BTB_GUARANTEED_VOQ9_RT_OFFSET 34399 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ9_RT_OFFSET 34400 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ10_RT_OFFSET 34401 +#define PBF_REG_BTB_GUARANTEED_VOQ10_RT_OFFSET 34402 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ10_RT_OFFSET 34403 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ11_RT_OFFSET 34404 +#define PBF_REG_BTB_GUARANTEED_VOQ11_RT_OFFSET 34405 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ11_RT_OFFSET 34406 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ12_RT_OFFSET 34407 +#define PBF_REG_BTB_GUARANTEED_VOQ12_RT_OFFSET 34408 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ12_RT_OFFSET 34409 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ13_RT_OFFSET 34410 +#define PBF_REG_BTB_GUARANTEED_VOQ13_RT_OFFSET 34411 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ13_RT_OFFSET 34412 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ14_RT_OFFSET 34413 +#define PBF_REG_BTB_GUARANTEED_VOQ14_RT_OFFSET 34414 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ14_RT_OFFSET 34415 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ15_RT_OFFSET 34416 +#define PBF_REG_BTB_GUARANTEED_VOQ15_RT_OFFSET 34417 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ15_RT_OFFSET 34418 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ16_RT_OFFSET 34419 +#define PBF_REG_BTB_GUARANTEED_VOQ16_RT_OFFSET 34420 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ16_RT_OFFSET 34421 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ17_RT_OFFSET 34422 +#define PBF_REG_BTB_GUARANTEED_VOQ17_RT_OFFSET 34423 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ17_RT_OFFSET 34424 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ18_RT_OFFSET 34425 +#define PBF_REG_BTB_GUARANTEED_VOQ18_RT_OFFSET 34426 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ18_RT_OFFSET 34427 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ19_RT_OFFSET 34428 +#define PBF_REG_BTB_GUARANTEED_VOQ19_RT_OFFSET 34429 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ19_RT_OFFSET 34430 +#define XCM_REG_CON_PHY_Q3_RT_OFFSET 34431 + +#define RUNTIME_ARRAY_SIZE 34432 + +/* The eth storm context for the Ystorm */ +struct ystorm_eth_conn_st_ctx { + __le32 reserved[4]; +}; + +/* The eth storm context for the Pstorm */ +struct pstorm_eth_conn_st_ctx { + __le32 reserved[8]; +}; + +/* The eth storm context for the Xstorm */ +struct xstorm_eth_conn_st_ctx { + __le32 reserved[60]; +}; + +struct xstorm_eth_conn_ag_ctx { + u8 reserved0 /* cdu_validation */; + u8 eth_state /* state */; + u8 flags0; +#define XSTORM_ETH_CONN_AG_CTX_EXIST_IN_QM0_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_EXIST_IN_QM0_SHIFT 0 +#define XSTORM_ETH_CONN_AG_CTX_RESERVED1_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_RESERVED1_SHIFT 1 +#define XSTORM_ETH_CONN_AG_CTX_RESERVED2_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_RESERVED2_SHIFT 2 +#define XSTORM_ETH_CONN_AG_CTX_EXIST_IN_QM3_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_EXIST_IN_QM3_SHIFT 3 +#define XSTORM_ETH_CONN_AG_CTX_RESERVED3_MASK 0x1 /* bit4 */ +#define XSTORM_ETH_CONN_AG_CTX_RESERVED3_SHIFT 4 +#define XSTORM_ETH_CONN_AG_CTX_RESERVED4_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_RESERVED4_SHIFT 5 +#define XSTORM_ETH_CONN_AG_CTX_RESERVED5_MASK 0x1 /* bit6 */ +#define XSTORM_ETH_CONN_AG_CTX_RESERVED5_SHIFT 6 +#define XSTORM_ETH_CONN_AG_CTX_RESERVED6_MASK 0x1 /* bit7 */ +#define XSTORM_ETH_CONN_AG_CTX_RESERVED6_SHIFT 7 + u8 flags1; +#define XSTORM_ETH_CONN_AG_CTX_RESERVED7_MASK 0x1 /* bit8 */ +#define XSTORM_ETH_CONN_AG_CTX_RESERVED7_SHIFT 0 +#define XSTORM_ETH_CONN_AG_CTX_RESERVED8_MASK 0x1 /* bit9 */ +#define XSTORM_ETH_CONN_AG_CTX_RESERVED8_SHIFT 1 +#define XSTORM_ETH_CONN_AG_CTX_RESERVED9_MASK 0x1 /* bit10 */ +#define XSTORM_ETH_CONN_AG_CTX_RESERVED9_SHIFT 2 +#define XSTORM_ETH_CONN_AG_CTX_BIT11_MASK 0x1 /* bit11 */ +#define XSTORM_ETH_CONN_AG_CTX_BIT11_SHIFT 3 +#define XSTORM_ETH_CONN_AG_CTX_BIT12_MASK 0x1 /* bit12 */ +#define XSTORM_ETH_CONN_AG_CTX_BIT12_SHIFT 4 +#define XSTORM_ETH_CONN_AG_CTX_BIT13_MASK 0x1 /* bit13 */ +#define XSTORM_ETH_CONN_AG_CTX_BIT13_SHIFT 5 +#define XSTORM_ETH_CONN_AG_CTX_TX_RULE_ACTIVE_MASK 0x1 /* bit14 */ +#define XSTORM_ETH_CONN_AG_CTX_TX_RULE_ACTIVE_SHIFT 6 +#define XSTORM_ETH_CONN_AG_CTX_DQ_CF_ACTIVE_MASK 0x1 /* bit15 */ +#define XSTORM_ETH_CONN_AG_CTX_DQ_CF_ACTIVE_SHIFT 7 + u8 flags2; +#define XSTORM_ETH_CONN_AG_CTX_CF0_MASK 0x3 /* timer0cf */ +#define XSTORM_ETH_CONN_AG_CTX_CF0_SHIFT 0 +#define XSTORM_ETH_CONN_AG_CTX_CF1_MASK 0x3 /* timer1cf */ +#define XSTORM_ETH_CONN_AG_CTX_CF1_SHIFT 2 +#define XSTORM_ETH_CONN_AG_CTX_CF2_MASK 0x3 /* timer2cf */ +#define XSTORM_ETH_CONN_AG_CTX_CF2_SHIFT 4 +#define XSTORM_ETH_CONN_AG_CTX_CF3_MASK 0x3 +#define XSTORM_ETH_CONN_AG_CTX_CF3_SHIFT 6 + u8 flags3; +#define XSTORM_ETH_CONN_AG_CTX_CF4_MASK 0x3 /* cf4 */ +#define XSTORM_ETH_CONN_AG_CTX_CF4_SHIFT 0 +#define XSTORM_ETH_CONN_AG_CTX_CF5_MASK 0x3 /* cf5 */ +#define XSTORM_ETH_CONN_AG_CTX_CF5_SHIFT 2 +#define XSTORM_ETH_CONN_AG_CTX_CF6_MASK 0x3 /* cf6 */ +#define XSTORM_ETH_CONN_AG_CTX_CF6_SHIFT 4 +#define XSTORM_ETH_CONN_AG_CTX_CF7_MASK 0x3 /* cf7 */ +#define XSTORM_ETH_CONN_AG_CTX_CF7_SHIFT 6 + u8 flags4; +#define XSTORM_ETH_CONN_AG_CTX_CF8_MASK 0x3 /* cf8 */ +#define XSTORM_ETH_CONN_AG_CTX_CF8_SHIFT 0 +#define XSTORM_ETH_CONN_AG_CTX_CF9_MASK 0x3 /* cf9 */ +#define XSTORM_ETH_CONN_AG_CTX_CF9_SHIFT 2 +#define XSTORM_ETH_CONN_AG_CTX_CF10_MASK 0x3 /* cf10 */ +#define XSTORM_ETH_CONN_AG_CTX_CF10_SHIFT 4 +#define XSTORM_ETH_CONN_AG_CTX_CF11_MASK 0x3 /* cf11 */ +#define XSTORM_ETH_CONN_AG_CTX_CF11_SHIFT 6 + u8 flags5; +#define XSTORM_ETH_CONN_AG_CTX_CF12_MASK 0x3 /* cf12 */ +#define XSTORM_ETH_CONN_AG_CTX_CF12_SHIFT 0 +#define XSTORM_ETH_CONN_AG_CTX_CF13_MASK 0x3 /* cf13 */ +#define XSTORM_ETH_CONN_AG_CTX_CF13_SHIFT 2 +#define XSTORM_ETH_CONN_AG_CTX_CF14_MASK 0x3 /* cf14 */ +#define XSTORM_ETH_CONN_AG_CTX_CF14_SHIFT 4 +#define XSTORM_ETH_CONN_AG_CTX_CF15_MASK 0x3 /* cf15 */ +#define XSTORM_ETH_CONN_AG_CTX_CF15_SHIFT 6 + u8 flags6; +#define XSTORM_ETH_CONN_AG_CTX_GO_TO_BD_CONS_CF_MASK 0x3 /* cf16 */ +#define XSTORM_ETH_CONN_AG_CTX_GO_TO_BD_CONS_CF_SHIFT 0 +#define XSTORM_ETH_CONN_AG_CTX_MULTI_UNICAST_CF_MASK 0x3 +#define XSTORM_ETH_CONN_AG_CTX_MULTI_UNICAST_CF_SHIFT 2 +#define XSTORM_ETH_CONN_AG_CTX_DQ_CF_MASK 0x3 /* cf18 */ +#define XSTORM_ETH_CONN_AG_CTX_DQ_CF_SHIFT 4 +#define XSTORM_ETH_CONN_AG_CTX_TERMINATE_CF_MASK 0x3 /* cf19 */ +#define XSTORM_ETH_CONN_AG_CTX_TERMINATE_CF_SHIFT 6 + u8 flags7; +#define XSTORM_ETH_CONN_AG_CTX_FLUSH_Q0_MASK 0x3 /* cf20 */ +#define XSTORM_ETH_CONN_AG_CTX_FLUSH_Q0_SHIFT 0 +#define XSTORM_ETH_CONN_AG_CTX_RESERVED10_MASK 0x3 /* cf21 */ +#define XSTORM_ETH_CONN_AG_CTX_RESERVED10_SHIFT 2 +#define XSTORM_ETH_CONN_AG_CTX_SLOW_PATH_MASK 0x3 /* cf22 */ +#define XSTORM_ETH_CONN_AG_CTX_SLOW_PATH_SHIFT 4 +#define XSTORM_ETH_CONN_AG_CTX_CF0EN_MASK 0x1 /* cf0en */ +#define XSTORM_ETH_CONN_AG_CTX_CF0EN_SHIFT 6 +#define XSTORM_ETH_CONN_AG_CTX_CF1EN_MASK 0x1 /* cf1en */ +#define XSTORM_ETH_CONN_AG_CTX_CF1EN_SHIFT 7 + u8 flags8; +#define XSTORM_ETH_CONN_AG_CTX_CF2EN_MASK 0x1 /* cf2en */ +#define XSTORM_ETH_CONN_AG_CTX_CF2EN_SHIFT 0 +#define XSTORM_ETH_CONN_AG_CTX_CF3EN_MASK 0x1 /* cf3en */ +#define XSTORM_ETH_CONN_AG_CTX_CF3EN_SHIFT 1 +#define XSTORM_ETH_CONN_AG_CTX_CF4EN_MASK 0x1 /* cf4en */ +#define XSTORM_ETH_CONN_AG_CTX_CF4EN_SHIFT 2 +#define XSTORM_ETH_CONN_AG_CTX_CF5EN_MASK 0x1 /* cf5en */ +#define XSTORM_ETH_CONN_AG_CTX_CF5EN_SHIFT 3 +#define XSTORM_ETH_CONN_AG_CTX_CF6EN_MASK 0x1 /* cf6en */ +#define XSTORM_ETH_CONN_AG_CTX_CF6EN_SHIFT 4 +#define XSTORM_ETH_CONN_AG_CTX_CF7EN_MASK 0x1 /* cf7en */ +#define XSTORM_ETH_CONN_AG_CTX_CF7EN_SHIFT 5 +#define XSTORM_ETH_CONN_AG_CTX_CF8EN_MASK 0x1 /* cf8en */ +#define XSTORM_ETH_CONN_AG_CTX_CF8EN_SHIFT 6 +#define XSTORM_ETH_CONN_AG_CTX_CF9EN_MASK 0x1 /* cf9en */ +#define XSTORM_ETH_CONN_AG_CTX_CF9EN_SHIFT 7 + u8 flags9; +#define XSTORM_ETH_CONN_AG_CTX_CF10EN_MASK 0x1 /* cf10en */ +#define XSTORM_ETH_CONN_AG_CTX_CF10EN_SHIFT 0 +#define XSTORM_ETH_CONN_AG_CTX_CF11EN_MASK 0x1 /* cf11en */ +#define XSTORM_ETH_CONN_AG_CTX_CF11EN_SHIFT 1 +#define XSTORM_ETH_CONN_AG_CTX_CF12EN_MASK 0x1 /* cf12en */ +#define XSTORM_ETH_CONN_AG_CTX_CF12EN_SHIFT 2 +#define XSTORM_ETH_CONN_AG_CTX_CF13EN_MASK 0x1 /* cf13en */ +#define XSTORM_ETH_CONN_AG_CTX_CF13EN_SHIFT 3 +#define XSTORM_ETH_CONN_AG_CTX_CF14EN_MASK 0x1 /* cf14en */ +#define XSTORM_ETH_CONN_AG_CTX_CF14EN_SHIFT 4 +#define XSTORM_ETH_CONN_AG_CTX_CF15EN_MASK 0x1 /* cf15en */ +#define XSTORM_ETH_CONN_AG_CTX_CF15EN_SHIFT 5 +#define XSTORM_ETH_CONN_AG_CTX_GO_TO_BD_CONS_CF_EN_MASK 0x1 /* cf16en */ +#define XSTORM_ETH_CONN_AG_CTX_GO_TO_BD_CONS_CF_EN_SHIFT 6 +#define XSTORM_ETH_CONN_AG_CTX_MULTI_UNICAST_CF_EN_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_MULTI_UNICAST_CF_EN_SHIFT 7 + u8 flags10; +#define XSTORM_ETH_CONN_AG_CTX_DQ_CF_EN_MASK 0x1 /* cf18en */ +#define XSTORM_ETH_CONN_AG_CTX_DQ_CF_EN_SHIFT 0 +#define XSTORM_ETH_CONN_AG_CTX_TERMINATE_CF_EN_MASK 0x1 /* cf19en */ +#define XSTORM_ETH_CONN_AG_CTX_TERMINATE_CF_EN_SHIFT 1 +#define XSTORM_ETH_CONN_AG_CTX_FLUSH_Q0_EN_MASK 0x1 /* cf20en */ +#define XSTORM_ETH_CONN_AG_CTX_FLUSH_Q0_EN_SHIFT 2 +#define XSTORM_ETH_CONN_AG_CTX_RESERVED11_MASK 0x1 /* cf21en */ +#define XSTORM_ETH_CONN_AG_CTX_RESERVED11_SHIFT 3 +#define XSTORM_ETH_CONN_AG_CTX_SLOW_PATH_EN_MASK 0x1 /* cf22en */ +#define XSTORM_ETH_CONN_AG_CTX_SLOW_PATH_EN_SHIFT 4 +#define XSTORM_ETH_CONN_AG_CTX_TPH_ENABLE_EN_RESERVED_MASK 0x1 /* cf23en */ +#define XSTORM_ETH_CONN_AG_CTX_TPH_ENABLE_EN_RESERVED_SHIFT 5 +#define XSTORM_ETH_CONN_AG_CTX_RESERVED12_MASK 0x1 /* rule0en */ +#define XSTORM_ETH_CONN_AG_CTX_RESERVED12_SHIFT 6 +#define XSTORM_ETH_CONN_AG_CTX_RESERVED13_MASK 0x1 /* rule1en */ +#define XSTORM_ETH_CONN_AG_CTX_RESERVED13_SHIFT 7 + u8 flags11; +#define XSTORM_ETH_CONN_AG_CTX_RESERVED14_MASK 0x1 /* rule2en */ +#define XSTORM_ETH_CONN_AG_CTX_RESERVED14_SHIFT 0 +#define XSTORM_ETH_CONN_AG_CTX_RESERVED15_MASK 0x1 /* rule3en */ +#define XSTORM_ETH_CONN_AG_CTX_RESERVED15_SHIFT 1 +#define XSTORM_ETH_CONN_AG_CTX_TX_DEC_RULE_EN_MASK 0x1 /* rule4en */ +#define XSTORM_ETH_CONN_AG_CTX_TX_DEC_RULE_EN_SHIFT 2 +#define XSTORM_ETH_CONN_AG_CTX_RULE5EN_MASK 0x1 /* rule5en */ +#define XSTORM_ETH_CONN_AG_CTX_RULE5EN_SHIFT 3 +#define XSTORM_ETH_CONN_AG_CTX_RULE6EN_MASK 0x1 /* rule6en */ +#define XSTORM_ETH_CONN_AG_CTX_RULE6EN_SHIFT 4 +#define XSTORM_ETH_CONN_AG_CTX_RULE7EN_MASK 0x1 /* rule7en */ +#define XSTORM_ETH_CONN_AG_CTX_RULE7EN_SHIFT 5 +#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED1_MASK 0x1 /* rule8en */ +#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED1_SHIFT 6 +#define XSTORM_ETH_CONN_AG_CTX_RULE9EN_MASK 0x1 /* rule9en */ +#define XSTORM_ETH_CONN_AG_CTX_RULE9EN_SHIFT 7 + u8 flags12; +#define XSTORM_ETH_CONN_AG_CTX_RULE10EN_MASK 0x1 /* rule10en */ +#define XSTORM_ETH_CONN_AG_CTX_RULE10EN_SHIFT 0 +#define XSTORM_ETH_CONN_AG_CTX_RULE11EN_MASK 0x1 /* rule11en */ +#define XSTORM_ETH_CONN_AG_CTX_RULE11EN_SHIFT 1 +#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED2_MASK 0x1 /* rule12en */ +#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED2_SHIFT 2 +#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED3_MASK 0x1 /* rule13en */ +#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED3_SHIFT 3 +#define XSTORM_ETH_CONN_AG_CTX_RULE14EN_MASK 0x1 /* rule14en */ +#define XSTORM_ETH_CONN_AG_CTX_RULE14EN_SHIFT 4 +#define XSTORM_ETH_CONN_AG_CTX_RULE15EN_MASK 0x1 /* rule15en */ +#define XSTORM_ETH_CONN_AG_CTX_RULE15EN_SHIFT 5 +#define XSTORM_ETH_CONN_AG_CTX_RULE16EN_MASK 0x1 /* rule16en */ +#define XSTORM_ETH_CONN_AG_CTX_RULE16EN_SHIFT 6 +#define XSTORM_ETH_CONN_AG_CTX_RULE17EN_MASK 0x1 /* rule17en */ +#define XSTORM_ETH_CONN_AG_CTX_RULE17EN_SHIFT 7 + u8 flags13; +#define XSTORM_ETH_CONN_AG_CTX_RULE18EN_MASK 0x1 /* rule18en */ +#define XSTORM_ETH_CONN_AG_CTX_RULE18EN_SHIFT 0 +#define XSTORM_ETH_CONN_AG_CTX_RULE19EN_MASK 0x1 /* rule19en */ +#define XSTORM_ETH_CONN_AG_CTX_RULE19EN_SHIFT 1 +#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED4_MASK 0x1 /* rule20en */ +#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED4_SHIFT 2 +#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED5_MASK 0x1 /* rule21en */ +#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED5_SHIFT 3 +#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED6_MASK 0x1 /* rule22en */ +#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED6_SHIFT 4 +#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED7_MASK 0x1 /* rule23en */ +#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED7_SHIFT 5 +#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED8_MASK 0x1 /* rule24en */ +#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED8_SHIFT 6 +#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED9_MASK 0x1 /* rule25en */ +#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED9_SHIFT 7 + u8 flags14; +#define XSTORM_ETH_CONN_AG_CTX_EDPM_USE_EXT_HDR_MASK 0x1 /* bit16 */ +#define XSTORM_ETH_CONN_AG_CTX_EDPM_USE_EXT_HDR_SHIFT 0 +#define XSTORM_ETH_CONN_AG_CTX_EDPM_SEND_RAW_L3L4_MASK 0x1 /* bit17 */ +#define XSTORM_ETH_CONN_AG_CTX_EDPM_SEND_RAW_L3L4_SHIFT 1 +#define XSTORM_ETH_CONN_AG_CTX_EDPM_INBAND_PROP_HDR_MASK 0x1 /* bit18 */ +#define XSTORM_ETH_CONN_AG_CTX_EDPM_INBAND_PROP_HDR_SHIFT 2 +#define XSTORM_ETH_CONN_AG_CTX_EDPM_SEND_EXT_TUNNEL_MASK 0x1 /* bit19 */ +#define XSTORM_ETH_CONN_AG_CTX_EDPM_SEND_EXT_TUNNEL_SHIFT 3 +#define XSTORM_ETH_CONN_AG_CTX_L2_EDPM_ENABLE_MASK 0x1 /* bit20 */ +#define XSTORM_ETH_CONN_AG_CTX_L2_EDPM_ENABLE_SHIFT 4 +#define XSTORM_ETH_CONN_AG_CTX_ROCE_EDPM_ENABLE_MASK 0x1 /* bit21 */ +#define XSTORM_ETH_CONN_AG_CTX_ROCE_EDPM_ENABLE_SHIFT 5 +#define XSTORM_ETH_CONN_AG_CTX_TPH_ENABLE_MASK 0x3 /* cf23 */ +#define XSTORM_ETH_CONN_AG_CTX_TPH_ENABLE_SHIFT 6 + u8 edpm_event_id /* byte2 */; + __le16 physical_q0 /* physical_q0 */; + __le16 word1 /* physical_q1 */; + __le16 edpm_num_bds /* physical_q2 */; + __le16 tx_bd_cons /* word3 */; + __le16 tx_bd_prod /* word4 */; + __le16 go_to_bd_cons /* word5 */; + __le16 conn_dpi /* conn_dpi */; + u8 byte3 /* byte3 */; + u8 byte4 /* byte4 */; + u8 byte5 /* byte5 */; + u8 byte6 /* byte6 */; + __le32 reg0 /* reg0 */; + __le32 reg1 /* reg1 */; + __le32 reg2 /* reg2 */; + __le32 reg3 /* reg3 */; + __le32 reg4 /* reg4 */; + __le32 reg5 /* cf_array0 */; + __le32 reg6 /* cf_array1 */; + __le16 word7 /* word7 */; + __le16 word8 /* word8 */; + __le16 word9 /* word9 */; + __le16 word10 /* word10 */; + __le32 reg7 /* reg7 */; + __le32 reg8 /* reg8 */; + __le32 reg9 /* reg9 */; + u8 byte7 /* byte7 */; + u8 byte8 /* byte8 */; + u8 byte9 /* byte9 */; + u8 byte10 /* byte10 */; + u8 byte11 /* byte11 */; + u8 byte12 /* byte12 */; + u8 byte13 /* byte13 */; + u8 byte14 /* byte14 */; + u8 byte15 /* byte15 */; + u8 byte16 /* byte16 */; + __le16 word11 /* word11 */; + __le32 reg10 /* reg10 */; + __le32 reg11 /* reg11 */; + __le32 reg12 /* reg12 */; + __le32 reg13 /* reg13 */; + __le32 reg14 /* reg14 */; + __le32 reg15 /* reg15 */; + __le32 reg16 /* reg16 */; + __le32 reg17 /* reg17 */; + __le32 reg18 /* reg18 */; + __le32 reg19 /* reg19 */; + __le16 word12 /* word12 */; + __le16 word13 /* word13 */; + __le16 word14 /* word14 */; + __le16 word15 /* word15 */; +}; + +/* The eth storm context for the Tstorm */ +struct tstorm_eth_conn_st_ctx { + __le32 reserved[4]; +}; + +/* The eth storm context for the Mstorm */ +struct mstorm_eth_conn_st_ctx { + __le32 reserved[8]; +}; + +/* The eth storm context for the Ustorm */ +struct ustorm_eth_conn_st_ctx { + __le32 reserved[40]; +}; + +/* eth connection context */ +struct eth_conn_context { + struct ystorm_eth_conn_st_ctx ystorm_st_context; + struct regpair ystorm_st_padding[2] /* padding */; + struct pstorm_eth_conn_st_ctx pstorm_st_context; + struct regpair pstorm_st_padding[2] /* padding */; + struct xstorm_eth_conn_st_ctx xstorm_st_context; + struct xstorm_eth_conn_ag_ctx xstorm_ag_context; + struct tstorm_eth_conn_st_ctx tstorm_st_context; + struct regpair tstorm_st_padding[2] /* padding */; + struct mstorm_eth_conn_st_ctx mstorm_st_context; + struct ustorm_eth_conn_st_ctx ustorm_st_context; +}; + +struct mstorm_eth_conn_ag_ctx { + u8 byte0 /* cdu_validation */; + u8 byte1 /* state */; + u8 flags0; +#define MSTORM_ETH_CONN_AG_CTX_EXIST_IN_QM0_MASK 0x1 /* exist_in_qm0 */ +#define MSTORM_ETH_CONN_AG_CTX_EXIST_IN_QM0_SHIFT 0 +#define MSTORM_ETH_CONN_AG_CTX_BIT1_MASK 0x1 /* exist_in_qm1 */ +#define MSTORM_ETH_CONN_AG_CTX_BIT1_SHIFT 1 +#define MSTORM_ETH_CONN_AG_CTX_CF0_MASK 0x3 /* cf0 */ +#define MSTORM_ETH_CONN_AG_CTX_CF0_SHIFT 2 +#define MSTORM_ETH_CONN_AG_CTX_CF1_MASK 0x3 /* cf1 */ +#define MSTORM_ETH_CONN_AG_CTX_CF1_SHIFT 4 +#define MSTORM_ETH_CONN_AG_CTX_CF2_MASK 0x3 /* cf2 */ +#define MSTORM_ETH_CONN_AG_CTX_CF2_SHIFT 6 + u8 flags1; +#define MSTORM_ETH_CONN_AG_CTX_CF0EN_MASK 0x1 /* cf0en */ +#define MSTORM_ETH_CONN_AG_CTX_CF0EN_SHIFT 0 +#define MSTORM_ETH_CONN_AG_CTX_CF1EN_MASK 0x1 /* cf1en */ +#define MSTORM_ETH_CONN_AG_CTX_CF1EN_SHIFT 1 +#define MSTORM_ETH_CONN_AG_CTX_CF2EN_MASK 0x1 /* cf2en */ +#define MSTORM_ETH_CONN_AG_CTX_CF2EN_SHIFT 2 +#define MSTORM_ETH_CONN_AG_CTX_RULE0EN_MASK 0x1 /* rule0en */ +#define MSTORM_ETH_CONN_AG_CTX_RULE0EN_SHIFT 3 +#define MSTORM_ETH_CONN_AG_CTX_RULE1EN_MASK 0x1 /* rule1en */ +#define MSTORM_ETH_CONN_AG_CTX_RULE1EN_SHIFT 4 +#define MSTORM_ETH_CONN_AG_CTX_RULE2EN_MASK 0x1 /* rule2en */ +#define MSTORM_ETH_CONN_AG_CTX_RULE2EN_SHIFT 5 +#define MSTORM_ETH_CONN_AG_CTX_RULE3EN_MASK 0x1 /* rule3en */ +#define MSTORM_ETH_CONN_AG_CTX_RULE3EN_SHIFT 6 +#define MSTORM_ETH_CONN_AG_CTX_RULE4EN_MASK 0x1 /* rule4en */ +#define MSTORM_ETH_CONN_AG_CTX_RULE4EN_SHIFT 7 + __le16 word0 /* word0 */; + __le16 word1 /* word1 */; + __le32 reg0 /* reg0 */; + __le32 reg1 /* reg1 */; +}; + +struct tstorm_eth_conn_ag_ctx { + u8 byte0 /* cdu_validation */; + u8 byte1 /* state */; + u8 flags0; +#define TSTORM_ETH_CONN_AG_CTX_BIT0_MASK 0x1 /* exist_in_qm0 */ +#define TSTORM_ETH_CONN_AG_CTX_BIT0_SHIFT 0 +#define TSTORM_ETH_CONN_AG_CTX_BIT1_MASK 0x1 /* exist_in_qm1 */ +#define TSTORM_ETH_CONN_AG_CTX_BIT1_SHIFT 1 +#define TSTORM_ETH_CONN_AG_CTX_BIT2_MASK 0x1 /* bit2 */ +#define TSTORM_ETH_CONN_AG_CTX_BIT2_SHIFT 2 +#define TSTORM_ETH_CONN_AG_CTX_BIT3_MASK 0x1 /* bit3 */ +#define TSTORM_ETH_CONN_AG_CTX_BIT3_SHIFT 3 +#define TSTORM_ETH_CONN_AG_CTX_BIT4_MASK 0x1 /* bit4 */ +#define TSTORM_ETH_CONN_AG_CTX_BIT4_SHIFT 4 +#define TSTORM_ETH_CONN_AG_CTX_BIT5_MASK 0x1 /* bit5 */ +#define TSTORM_ETH_CONN_AG_CTX_BIT5_SHIFT 5 +#define TSTORM_ETH_CONN_AG_CTX_CF0_MASK 0x3 /* timer0cf */ +#define TSTORM_ETH_CONN_AG_CTX_CF0_SHIFT 6 + u8 flags1; +#define TSTORM_ETH_CONN_AG_CTX_CF1_MASK 0x3 /* timer1cf */ +#define TSTORM_ETH_CONN_AG_CTX_CF1_SHIFT 0 +#define TSTORM_ETH_CONN_AG_CTX_CF2_MASK 0x3 /* timer2cf */ +#define TSTORM_ETH_CONN_AG_CTX_CF2_SHIFT 2 +#define TSTORM_ETH_CONN_AG_CTX_CF3_MASK 0x3 /* timer_stop_all */ +#define TSTORM_ETH_CONN_AG_CTX_CF3_SHIFT 4 +#define TSTORM_ETH_CONN_AG_CTX_CF4_MASK 0x3 /* cf4 */ +#define TSTORM_ETH_CONN_AG_CTX_CF4_SHIFT 6 + u8 flags2; +#define TSTORM_ETH_CONN_AG_CTX_CF5_MASK 0x3 /* cf5 */ +#define TSTORM_ETH_CONN_AG_CTX_CF5_SHIFT 0 +#define TSTORM_ETH_CONN_AG_CTX_CF6_MASK 0x3 /* cf6 */ +#define TSTORM_ETH_CONN_AG_CTX_CF6_SHIFT 2 +#define TSTORM_ETH_CONN_AG_CTX_CF7_MASK 0x3 /* cf7 */ +#define TSTORM_ETH_CONN_AG_CTX_CF7_SHIFT 4 +#define TSTORM_ETH_CONN_AG_CTX_CF8_MASK 0x3 /* cf8 */ +#define TSTORM_ETH_CONN_AG_CTX_CF8_SHIFT 6 + u8 flags3; +#define TSTORM_ETH_CONN_AG_CTX_CF9_MASK 0x3 /* cf9 */ +#define TSTORM_ETH_CONN_AG_CTX_CF9_SHIFT 0 +#define TSTORM_ETH_CONN_AG_CTX_CF10_MASK 0x3 /* cf10 */ +#define TSTORM_ETH_CONN_AG_CTX_CF10_SHIFT 2 +#define TSTORM_ETH_CONN_AG_CTX_CF0EN_MASK 0x1 /* cf0en */ +#define TSTORM_ETH_CONN_AG_CTX_CF0EN_SHIFT 4 +#define TSTORM_ETH_CONN_AG_CTX_CF1EN_MASK 0x1 /* cf1en */ +#define TSTORM_ETH_CONN_AG_CTX_CF1EN_SHIFT 5 +#define TSTORM_ETH_CONN_AG_CTX_CF2EN_MASK 0x1 /* cf2en */ +#define TSTORM_ETH_CONN_AG_CTX_CF2EN_SHIFT 6 +#define TSTORM_ETH_CONN_AG_CTX_CF3EN_MASK 0x1 /* cf3en */ +#define TSTORM_ETH_CONN_AG_CTX_CF3EN_SHIFT 7 + u8 flags4; +#define TSTORM_ETH_CONN_AG_CTX_CF4EN_MASK 0x1 /* cf4en */ +#define TSTORM_ETH_CONN_AG_CTX_CF4EN_SHIFT 0 +#define TSTORM_ETH_CONN_AG_CTX_CF5EN_MASK 0x1 /* cf5en */ +#define TSTORM_ETH_CONN_AG_CTX_CF5EN_SHIFT 1 +#define TSTORM_ETH_CONN_AG_CTX_CF6EN_MASK 0x1 /* cf6en */ +#define TSTORM_ETH_CONN_AG_CTX_CF6EN_SHIFT 2 +#define TSTORM_ETH_CONN_AG_CTX_CF7EN_MASK 0x1 /* cf7en */ +#define TSTORM_ETH_CONN_AG_CTX_CF7EN_SHIFT 3 +#define TSTORM_ETH_CONN_AG_CTX_CF8EN_MASK 0x1 /* cf8en */ +#define TSTORM_ETH_CONN_AG_CTX_CF8EN_SHIFT 4 +#define TSTORM_ETH_CONN_AG_CTX_CF9EN_MASK 0x1 /* cf9en */ +#define TSTORM_ETH_CONN_AG_CTX_CF9EN_SHIFT 5 +#define TSTORM_ETH_CONN_AG_CTX_CF10EN_MASK 0x1 /* cf10en */ +#define TSTORM_ETH_CONN_AG_CTX_CF10EN_SHIFT 6 +#define TSTORM_ETH_CONN_AG_CTX_RULE0EN_MASK 0x1 /* rule0en */ +#define TSTORM_ETH_CONN_AG_CTX_RULE0EN_SHIFT 7 + u8 flags5; +#define TSTORM_ETH_CONN_AG_CTX_RULE1EN_MASK 0x1 /* rule1en */ +#define TSTORM_ETH_CONN_AG_CTX_RULE1EN_SHIFT 0 +#define TSTORM_ETH_CONN_AG_CTX_RULE2EN_MASK 0x1 /* rule2en */ +#define TSTORM_ETH_CONN_AG_CTX_RULE2EN_SHIFT 1 +#define TSTORM_ETH_CONN_AG_CTX_RULE3EN_MASK 0x1 /* rule3en */ +#define TSTORM_ETH_CONN_AG_CTX_RULE3EN_SHIFT 2 +#define TSTORM_ETH_CONN_AG_CTX_RULE4EN_MASK 0x1 /* rule4en */ +#define TSTORM_ETH_CONN_AG_CTX_RULE4EN_SHIFT 3 +#define TSTORM_ETH_CONN_AG_CTX_RULE5EN_MASK 0x1 /* rule5en */ +#define TSTORM_ETH_CONN_AG_CTX_RULE5EN_SHIFT 4 +#define TSTORM_ETH_CONN_AG_CTX_RX_BD_EN_MASK 0x1 /* rule6en */ +#define TSTORM_ETH_CONN_AG_CTX_RX_BD_EN_SHIFT 5 +#define TSTORM_ETH_CONN_AG_CTX_RULE7EN_MASK 0x1 /* rule7en */ +#define TSTORM_ETH_CONN_AG_CTX_RULE7EN_SHIFT 6 +#define TSTORM_ETH_CONN_AG_CTX_RULE8EN_MASK 0x1 /* rule8en */ +#define TSTORM_ETH_CONN_AG_CTX_RULE8EN_SHIFT 7 + __le32 reg0 /* reg0 */; + __le32 reg1 /* reg1 */; + __le32 reg2 /* reg2 */; + __le32 reg3 /* reg3 */; + __le32 reg4 /* reg4 */; + __le32 reg5 /* reg5 */; + __le32 reg6 /* reg6 */; + __le32 reg7 /* reg7 */; + __le32 reg8 /* reg8 */; + u8 byte2 /* byte2 */; + u8 byte3 /* byte3 */; + __le16 rx_bd_cons /* word0 */; + u8 byte4 /* byte4 */; + u8 byte5 /* byte5 */; + __le16 rx_bd_prod /* word1 */; + __le16 word2 /* conn_dpi */; + __le16 word3 /* word3 */; + __le32 reg9 /* reg9 */; + __le32 reg10 /* reg10 */; +}; + +struct ustorm_eth_conn_ag_ctx { + u8 byte0 /* cdu_validation */; + u8 byte1 /* state */; + u8 flags0; +#define USTORM_ETH_CONN_AG_CTX_BIT0_MASK 0x1 +#define USTORM_ETH_CONN_AG_CTX_BIT0_SHIFT 0 +#define USTORM_ETH_CONN_AG_CTX_BIT1_MASK 0x1 +#define USTORM_ETH_CONN_AG_CTX_BIT1_SHIFT 1 +#define USTORM_ETH_CONN_AG_CTX_CF0_MASK 0x3 /* timer0cf */ +#define USTORM_ETH_CONN_AG_CTX_CF0_SHIFT 2 +#define USTORM_ETH_CONN_AG_CTX_CF1_MASK 0x3 /* timer1cf */ +#define USTORM_ETH_CONN_AG_CTX_CF1_SHIFT 4 +#define USTORM_ETH_CONN_AG_CTX_CF2_MASK 0x3 /* timer2cf */ +#define USTORM_ETH_CONN_AG_CTX_CF2_SHIFT 6 + u8 flags1; +#define USTORM_ETH_CONN_AG_CTX_CF3_MASK 0x3 +#define USTORM_ETH_CONN_AG_CTX_CF3_SHIFT 0 +#define USTORM_ETH_CONN_AG_CTX_TX_ARM_CF_MASK 0x3 /* cf4 */ +#define USTORM_ETH_CONN_AG_CTX_TX_ARM_CF_SHIFT 2 +#define USTORM_ETH_CONN_AG_CTX_RX_ARM_CF_MASK 0x3 /* cf5 */ +#define USTORM_ETH_CONN_AG_CTX_RX_ARM_CF_SHIFT 4 +#define USTORM_ETH_CONN_AG_CTX_TX_BD_CONS_UPD_CF_MASK 0x3 /* cf6 */ +#define USTORM_ETH_CONN_AG_CTX_TX_BD_CONS_UPD_CF_SHIFT 6 + u8 flags2; +#define USTORM_ETH_CONN_AG_CTX_CF0EN_MASK 0x1 /* cf0en */ +#define USTORM_ETH_CONN_AG_CTX_CF0EN_SHIFT 0 +#define USTORM_ETH_CONN_AG_CTX_CF1EN_MASK 0x1 /* cf1en */ +#define USTORM_ETH_CONN_AG_CTX_CF1EN_SHIFT 1 +#define USTORM_ETH_CONN_AG_CTX_CF2EN_MASK 0x1 /* cf2en */ +#define USTORM_ETH_CONN_AG_CTX_CF2EN_SHIFT 2 +#define USTORM_ETH_CONN_AG_CTX_CF3EN_MASK 0x1 /* cf3en */ +#define USTORM_ETH_CONN_AG_CTX_CF3EN_SHIFT 3 +#define USTORM_ETH_CONN_AG_CTX_TX_ARM_CF_EN_MASK 0x1 /* cf4en */ +#define USTORM_ETH_CONN_AG_CTX_TX_ARM_CF_EN_SHIFT 4 +#define USTORM_ETH_CONN_AG_CTX_RX_ARM_CF_EN_MASK 0x1 /* cf5en */ +#define USTORM_ETH_CONN_AG_CTX_RX_ARM_CF_EN_SHIFT 5 +#define USTORM_ETH_CONN_AG_CTX_TX_BD_CONS_UPD_CF_EN_MASK 0x1 /* cf6en */ +#define USTORM_ETH_CONN_AG_CTX_TX_BD_CONS_UPD_CF_EN_SHIFT 6 +#define USTORM_ETH_CONN_AG_CTX_RULE0EN_MASK 0x1 /* rule0en */ +#define USTORM_ETH_CONN_AG_CTX_RULE0EN_SHIFT 7 + u8 flags3; +#define USTORM_ETH_CONN_AG_CTX_RULE1EN_MASK 0x1 /* rule1en */ +#define USTORM_ETH_CONN_AG_CTX_RULE1EN_SHIFT 0 +#define USTORM_ETH_CONN_AG_CTX_RULE2EN_MASK 0x1 /* rule2en */ +#define USTORM_ETH_CONN_AG_CTX_RULE2EN_SHIFT 1 +#define USTORM_ETH_CONN_AG_CTX_RULE3EN_MASK 0x1 /* rule3en */ +#define USTORM_ETH_CONN_AG_CTX_RULE3EN_SHIFT 2 +#define USTORM_ETH_CONN_AG_CTX_RULE4EN_MASK 0x1 /* rule4en */ +#define USTORM_ETH_CONN_AG_CTX_RULE4EN_SHIFT 3 +#define USTORM_ETH_CONN_AG_CTX_RULE5EN_MASK 0x1 /* rule5en */ +#define USTORM_ETH_CONN_AG_CTX_RULE5EN_SHIFT 4 +#define USTORM_ETH_CONN_AG_CTX_RULE6EN_MASK 0x1 /* rule6en */ +#define USTORM_ETH_CONN_AG_CTX_RULE6EN_SHIFT 5 +#define USTORM_ETH_CONN_AG_CTX_RULE7EN_MASK 0x1 /* rule7en */ +#define USTORM_ETH_CONN_AG_CTX_RULE7EN_SHIFT 6 +#define USTORM_ETH_CONN_AG_CTX_RULE8EN_MASK 0x1 /* rule8en */ +#define USTORM_ETH_CONN_AG_CTX_RULE8EN_SHIFT 7 + u8 byte2 /* byte2 */; + u8 byte3 /* byte3 */; + __le16 word0 /* conn_dpi */; + __le16 tx_bd_cons /* word1 */; + __le32 reg0 /* reg0 */; + __le32 reg1 /* reg1 */; + __le32 reg2 /* reg2 */; + __le32 reg3 /* reg3 */; + __le16 tx_drv_bd_cons /* word2 */; + __le16 rx_drv_cqe_cons /* word3 */; +}; + +struct xstorm_eth_hw_conn_ag_ctx { + u8 reserved0 /* cdu_validation */; + u8 eth_state /* state */; + u8 flags0; +#define XSTORM_ETH_HW_CONN_AG_CTX_EXIST_IN_QM0_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_EXIST_IN_QM0_SHIFT 0 +#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED1_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED1_SHIFT 1 +#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED2_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED2_SHIFT 2 +#define XSTORM_ETH_HW_CONN_AG_CTX_EXIST_IN_QM3_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_EXIST_IN_QM3_SHIFT 3 +#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED3_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED3_SHIFT 4 +#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED4_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED4_SHIFT 5 +#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED5_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED5_SHIFT 6 +#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED6_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED6_SHIFT 7 + u8 flags1; +#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED7_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED7_SHIFT 0 +#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED8_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED8_SHIFT 1 +#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED9_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED9_SHIFT 2 +#define XSTORM_ETH_HW_CONN_AG_CTX_BIT11_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_BIT11_SHIFT 3 +#define XSTORM_ETH_HW_CONN_AG_CTX_BIT12_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_BIT12_SHIFT 4 +#define XSTORM_ETH_HW_CONN_AG_CTX_BIT13_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_BIT13_SHIFT 5 +#define XSTORM_ETH_HW_CONN_AG_CTX_TX_RULE_ACTIVE_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_TX_RULE_ACTIVE_SHIFT 6 +#define XSTORM_ETH_HW_CONN_AG_CTX_DQ_CF_ACTIVE_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_DQ_CF_ACTIVE_SHIFT 7 + u8 flags2; +#define XSTORM_ETH_HW_CONN_AG_CTX_CF0_MASK 0x3 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF0_SHIFT 0 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF1_MASK 0x3 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF1_SHIFT 2 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF2_MASK 0x3 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF2_SHIFT 4 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF3_MASK 0x3 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF3_SHIFT 6 + u8 flags3; +#define XSTORM_ETH_HW_CONN_AG_CTX_CF4_MASK 0x3 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF4_SHIFT 0 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF5_MASK 0x3 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF5_SHIFT 2 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF6_MASK 0x3 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF6_SHIFT 4 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF7_MASK 0x3 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF7_SHIFT 6 + u8 flags4; +#define XSTORM_ETH_HW_CONN_AG_CTX_CF8_MASK 0x3 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF8_SHIFT 0 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF9_MASK 0x3 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF9_SHIFT 2 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF10_MASK 0x3 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF10_SHIFT 4 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF11_MASK 0x3 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF11_SHIFT 6 + u8 flags5; +#define XSTORM_ETH_HW_CONN_AG_CTX_CF12_MASK 0x3 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF12_SHIFT 0 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF13_MASK 0x3 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF13_SHIFT 2 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF14_MASK 0x3 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF14_SHIFT 4 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF15_MASK 0x3 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF15_SHIFT 6 + u8 flags6; +#define XSTORM_ETH_HW_CONN_AG_CTX_GO_TO_BD_CONS_CF_MASK 0x3 +#define XSTORM_ETH_HW_CONN_AG_CTX_GO_TO_BD_CONS_CF_SHIFT 0 +#define XSTORM_ETH_HW_CONN_AG_CTX_MULTI_UNICAST_CF_MASK 0x3 +#define XSTORM_ETH_HW_CONN_AG_CTX_MULTI_UNICAST_CF_SHIFT 2 +#define XSTORM_ETH_HW_CONN_AG_CTX_DQ_CF_MASK 0x3 +#define XSTORM_ETH_HW_CONN_AG_CTX_DQ_CF_SHIFT 4 +#define XSTORM_ETH_HW_CONN_AG_CTX_TERMINATE_CF_MASK 0x3 +#define XSTORM_ETH_HW_CONN_AG_CTX_TERMINATE_CF_SHIFT 6 + u8 flags7; +#define XSTORM_ETH_HW_CONN_AG_CTX_FLUSH_Q0_MASK 0x3 +#define XSTORM_ETH_HW_CONN_AG_CTX_FLUSH_Q0_SHIFT 0 +#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED10_MASK 0x3 +#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED10_SHIFT 2 +#define XSTORM_ETH_HW_CONN_AG_CTX_SLOW_PATH_MASK 0x3 +#define XSTORM_ETH_HW_CONN_AG_CTX_SLOW_PATH_SHIFT 4 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF0EN_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF0EN_SHIFT 6 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF1EN_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF1EN_SHIFT 7 + u8 flags8; +#define XSTORM_ETH_HW_CONN_AG_CTX_CF2EN_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF2EN_SHIFT 0 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF3EN_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF3EN_SHIFT 1 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF4EN_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF4EN_SHIFT 2 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF5EN_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF5EN_SHIFT 3 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF6EN_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF6EN_SHIFT 4 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF7EN_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF7EN_SHIFT 5 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF8EN_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF8EN_SHIFT 6 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF9EN_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF9EN_SHIFT 7 + u8 flags9; +#define XSTORM_ETH_HW_CONN_AG_CTX_CF10EN_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF10EN_SHIFT 0 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF11EN_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF11EN_SHIFT 1 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF12EN_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF12EN_SHIFT 2 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF13EN_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF13EN_SHIFT 3 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF14EN_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF14EN_SHIFT 4 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF15EN_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_CF15EN_SHIFT 5 +#define XSTORM_ETH_HW_CONN_AG_CTX_GO_TO_BD_CONS_CF_EN_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_GO_TO_BD_CONS_CF_EN_SHIFT 6 +#define XSTORM_ETH_HW_CONN_AG_CTX_MULTI_UNICAST_CF_EN_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_MULTI_UNICAST_CF_EN_SHIFT 7 + u8 flags10; +#define XSTORM_ETH_HW_CONN_AG_CTX_DQ_CF_EN_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_DQ_CF_EN_SHIFT 0 +#define XSTORM_ETH_HW_CONN_AG_CTX_TERMINATE_CF_EN_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_TERMINATE_CF_EN_SHIFT 1 +#define XSTORM_ETH_HW_CONN_AG_CTX_FLUSH_Q0_EN_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_FLUSH_Q0_EN_SHIFT 2 +#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED11_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED11_SHIFT 3 +#define XSTORM_ETH_HW_CONN_AG_CTX_SLOW_PATH_EN_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_SLOW_PATH_EN_SHIFT 4 +#define XSTORM_ETH_HW_CONN_AG_CTX_TPH_ENABLE_EN_RESERVED_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_TPH_ENABLE_EN_RESERVED_SHIFT 5 +#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED12_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED12_SHIFT 6 +#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED13_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED13_SHIFT 7 + u8 flags11; +#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED14_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED14_SHIFT 0 +#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED15_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED15_SHIFT 1 +#define XSTORM_ETH_HW_CONN_AG_CTX_TX_DEC_RULE_EN_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_TX_DEC_RULE_EN_SHIFT 2 +#define XSTORM_ETH_HW_CONN_AG_CTX_RULE5EN_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_RULE5EN_SHIFT 3 +#define XSTORM_ETH_HW_CONN_AG_CTX_RULE6EN_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_RULE6EN_SHIFT 4 +#define XSTORM_ETH_HW_CONN_AG_CTX_RULE7EN_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_RULE7EN_SHIFT 5 +#define XSTORM_ETH_HW_CONN_AG_CTX_A0_RESERVED1_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_A0_RESERVED1_SHIFT 6 +#define XSTORM_ETH_HW_CONN_AG_CTX_RULE9EN_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_RULE9EN_SHIFT 7 + u8 flags12; +#define XSTORM_ETH_HW_CONN_AG_CTX_RULE10EN_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_RULE10EN_SHIFT 0 +#define XSTORM_ETH_HW_CONN_AG_CTX_RULE11EN_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_RULE11EN_SHIFT 1 +#define XSTORM_ETH_HW_CONN_AG_CTX_A0_RESERVED2_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_A0_RESERVED2_SHIFT 2 +#define XSTORM_ETH_HW_CONN_AG_CTX_A0_RESERVED3_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_A0_RESERVED3_SHIFT 3 +#define XSTORM_ETH_HW_CONN_AG_CTX_RULE14EN_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_RULE14EN_SHIFT 4 +#define XSTORM_ETH_HW_CONN_AG_CTX_RULE15EN_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_RULE15EN_SHIFT 5 +#define XSTORM_ETH_HW_CONN_AG_CTX_RULE16EN_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_RULE16EN_SHIFT 6 +#define XSTORM_ETH_HW_CONN_AG_CTX_RULE17EN_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_RULE17EN_SHIFT 7 + u8 flags13; +#define XSTORM_ETH_HW_CONN_AG_CTX_RULE18EN_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_RULE18EN_SHIFT 0 +#define XSTORM_ETH_HW_CONN_AG_CTX_RULE19EN_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_RULE19EN_SHIFT 1 +#define XSTORM_ETH_HW_CONN_AG_CTX_A0_RESERVED4_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_A0_RESERVED4_SHIFT 2 +#define XSTORM_ETH_HW_CONN_AG_CTX_A0_RESERVED5_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_A0_RESERVED5_SHIFT 3 +#define XSTORM_ETH_HW_CONN_AG_CTX_A0_RESERVED6_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_A0_RESERVED6_SHIFT 4 +#define XSTORM_ETH_HW_CONN_AG_CTX_A0_RESERVED7_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_A0_RESERVED7_SHIFT 5 +#define XSTORM_ETH_HW_CONN_AG_CTX_A0_RESERVED8_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_A0_RESERVED8_SHIFT 6 +#define XSTORM_ETH_HW_CONN_AG_CTX_A0_RESERVED9_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_A0_RESERVED9_SHIFT 7 + u8 flags14; +#define XSTORM_ETH_HW_CONN_AG_CTX_EDPM_USE_EXT_HDR_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_EDPM_USE_EXT_HDR_SHIFT 0 +#define XSTORM_ETH_HW_CONN_AG_CTX_EDPM_SEND_RAW_L3L4_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_EDPM_SEND_RAW_L3L4_SHIFT 1 +#define XSTORM_ETH_HW_CONN_AG_CTX_EDPM_INBAND_PROP_HDR_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_EDPM_INBAND_PROP_HDR_SHIFT 2 +#define XSTORM_ETH_HW_CONN_AG_CTX_EDPM_SEND_EXT_TUNNEL_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_EDPM_SEND_EXT_TUNNEL_SHIFT 3 +#define XSTORM_ETH_HW_CONN_AG_CTX_L2_EDPM_ENABLE_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_L2_EDPM_ENABLE_SHIFT 4 +#define XSTORM_ETH_HW_CONN_AG_CTX_ROCE_EDPM_ENABLE_MASK 0x1 +#define XSTORM_ETH_HW_CONN_AG_CTX_ROCE_EDPM_ENABLE_SHIFT 5 +#define XSTORM_ETH_HW_CONN_AG_CTX_TPH_ENABLE_MASK 0x3 +#define XSTORM_ETH_HW_CONN_AG_CTX_TPH_ENABLE_SHIFT 6 + u8 edpm_event_id /* byte2 */; + __le16 physical_q0 /* physical_q0 */; + __le16 word1 /* physical_q1 */; + __le16 edpm_num_bds /* physical_q2 */; + __le16 tx_bd_cons /* word3 */; + __le16 tx_bd_prod /* word4 */; + __le16 go_to_bd_cons /* word5 */; + __le16 conn_dpi /* conn_dpi */; +}; + +#define VF_MAX_STATIC 192 /* In case of K2 */ + +#define MCP_GLOB_PATH_MAX 2 +#define MCP_PORT_MAX 2 /* Global */ +#define MCP_GLOB_PORT_MAX 4 /* Global */ +#define MCP_GLOB_FUNC_MAX 16 /* Global */ + +typedef u32 offsize_t; /* In DWORDS !!! */ +/* Offset from the beginning of the MCP scratchpad */ +#define OFFSIZE_OFFSET_SHIFT 0 +#define OFFSIZE_OFFSET_MASK 0x0000ffff +/* Size of specific element (not the whole array if any) */ +#define OFFSIZE_SIZE_SHIFT 16 +#define OFFSIZE_SIZE_MASK 0xffff0000 + +/* SECTION_OFFSET is calculating the offset in bytes out of offsize */ +#define SECTION_OFFSET(_offsize) ((((_offsize & \ + OFFSIZE_OFFSET_MASK) >> \ + OFFSIZE_OFFSET_SHIFT) << 2)) + +/* QED_SECTION_SIZE is calculating the size in bytes out of offsize */ +#define QED_SECTION_SIZE(_offsize) (((_offsize & \ + OFFSIZE_SIZE_MASK) >> \ + OFFSIZE_SIZE_SHIFT) << 2) + +/* SECTION_ADDR returns the GRC addr of a section, given offsize and index + * within section. + */ +#define SECTION_ADDR(_offsize, idx) (MCP_REG_SCRATCH + \ + SECTION_OFFSET(_offsize) + \ + (QED_SECTION_SIZE(_offsize) * idx)) + +/* SECTION_OFFSIZE_ADDR returns the GRC addr to the offsize address. + * Use offsetof, since the OFFSETUP collide with the firmware definition + */ +#define SECTION_OFFSIZE_ADDR(_pub_base, _section) (_pub_base + \ + offsetof(struct \ + mcp_public_data, \ + sections[_section])) +/* PHY configuration */ +struct pmm_phy_cfg { + u32 speed; +#define PMM_SPEED_AUTONEG 0 + + u32 pause; /* bitmask */ +#define PMM_PAUSE_NONE 0x0 +#define PMM_PAUSE_AUTONEG 0x1 +#define PMM_PAUSE_RX 0x2 +#define PMM_PAUSE_TX 0x4 + + u32 adv_speed; /* Default should be the speed_cap_mask */ + u32 loopback_mode; +#define PMM_LOOPBACK_NONE 0 +#define PMM_LOOPBACK_INT_PHY 1 +#define PMM_LOOPBACK_EXT_PHY 2 +#define PMM_LOOPBACK_EXT 3 +#define PMM_LOOPBACK_MAC 4 + + /* features */ + u32 feature_config_flags; +}; + +struct port_mf_cfg { + u32 dynamic_cfg; /* device control channel */ +#define PORT_MF_CFG_OV_TAG_MASK 0x0000ffff +#define PORT_MF_CFG_OV_TAG_SHIFT 0 +#define PORT_MF_CFG_OV_TAG_DEFAULT PORT_MF_CFG_OV_TAG_MASK + + u32 reserved[1]; +}; + +/* DO NOT add new fields in the middle + * MUST be synced with struct pmm_stats_map + */ +struct pmm_stats { + u64 r64; /* 0x00 (Offset 0x00 ) RX 64-byte frame counter*/ + u64 r127; /* 0x01 (Offset 0x08 ) RX 65 to 127 byte frame counter*/ + u64 r255; + u64 r511; + u64 r1023; + u64 r1518; + u64 r1522; + u64 r2047; + u64 r4095; + u64 r9216; + u64 r16383; + u64 rfcs; /* 0x0F (Offset 0x58 ) RX FCS error frame counter*/ + u64 rxcf; /* 0x10 (Offset 0x60 ) RX control frame counter*/ + u64 rxpf; /* 0x11 (Offset 0x68 ) RX pause frame counter*/ + u64 rxpp; /* 0x12 (Offset 0x70 ) RX PFC frame counter*/ + u64 raln; /* 0x16 (Offset 0x78 ) RX alignment error counter*/ + u64 rfcr; /* 0x19 (Offset 0x80 ) RX false carrier counter */ + u64 rovr; /* 0x1A (Offset 0x88 ) RX oversized frame counter*/ + u64 rjbr; /* 0x1B (Offset 0x90 ) RX jabber frame counter */ + u64 rund; /* 0x34 (Offset 0x98 ) RX undersized frame counter */ + u64 rfrg; /* 0x35 (Offset 0xa0 ) RX fragment counter */ + u64 t64; /* 0x40 (Offset 0xa8 ) TX 64-byte frame counter */ + u64 t127; + u64 t255; + u64 t511; + u64 t1023; + u64 t1518; + u64 t2047; + u64 t4095; + u64 t9216; + u64 t16383; + u64 txpf; /* 0x50 (Offset 0xf8 ) TX pause frame counter */ + u64 txpp; /* 0x51 (Offset 0x100) TX PFC frame counter */ + u64 tlpiec; + u64 tncl; + u64 rbyte; /* 0x3d (Offset 0x118) RX byte counter */ + u64 rxuca; /* 0x0c (Offset 0x120) RX UC frame counter */ + u64 rxmca; /* 0x0d (Offset 0x128) RX MC frame counter */ + u64 rxbca; /* 0x0e (Offset 0x130) RX BC frame counter */ + u64 rxpok; + u64 tbyte; /* 0x6f (Offset 0x140) TX byte counter */ + u64 txuca; /* 0x4d (Offset 0x148) TX UC frame counter */ + u64 txmca; /* 0x4e (Offset 0x150) TX MC frame counter */ + u64 txbca; /* 0x4f (Offset 0x158) TX BC frame counter */ + u64 txcf; /* 0x54 (Offset 0x160) TX control frame counter */ +}; + +struct brb_stats { + u64 brb_truncate[8]; + u64 brb_discard[8]; +}; + +struct port_stats { + struct brb_stats brb; + struct pmm_stats pmm; +}; + +#define CMT_TEAM0 0 +#define CMT_TEAM1 1 +#define CMT_TEAM_MAX 2 + +struct couple_mode_teaming { + u8 port_cmt[MCP_GLOB_PORT_MAX]; +#define PORT_CMT_IN_TEAM BIT(0) + +#define PORT_CMT_PORT_ROLE BIT(1) +#define PORT_CMT_PORT_INACTIVE (0 << 1) +#define PORT_CMT_PORT_ACTIVE BIT(1) + +#define PORT_CMT_TEAM_MASK BIT(2) +#define PORT_CMT_TEAM0 (0 << 2) +#define PORT_CMT_TEAM1 BIT(2) +}; + +/************************************** +* LLDP and DCBX HSI structures +**************************************/ +#define LLDP_CHASSIS_ID_STAT_LEN 4 +#define LLDP_PORT_ID_STAT_LEN 4 +#define DCBX_MAX_APP_PROTOCOL 32 +#define MAX_SYSTEM_LLDP_TLV_DATA 32 + +enum lldp_agent_e { + LLDP_NEAREST_BRIDGE = 0, + LLDP_NEAREST_NON_TPMR_BRIDGE, + LLDP_NEAREST_CUSTOMER_BRIDGE, + LLDP_MAX_LLDP_AGENTS +}; + +struct lldp_config_params_s { + u32 config; +#define LLDP_CONFIG_TX_INTERVAL_MASK 0x000000ff +#define LLDP_CONFIG_TX_INTERVAL_SHIFT 0 +#define LLDP_CONFIG_HOLD_MASK 0x00000f00 +#define LLDP_CONFIG_HOLD_SHIFT 8 +#define LLDP_CONFIG_MAX_CREDIT_MASK 0x0000f000 +#define LLDP_CONFIG_MAX_CREDIT_SHIFT 12 +#define LLDP_CONFIG_ENABLE_RX_MASK 0x40000000 +#define LLDP_CONFIG_ENABLE_RX_SHIFT 30 +#define LLDP_CONFIG_ENABLE_TX_MASK 0x80000000 +#define LLDP_CONFIG_ENABLE_TX_SHIFT 31 + u32 local_chassis_id[LLDP_CHASSIS_ID_STAT_LEN]; + u32 local_port_id[LLDP_PORT_ID_STAT_LEN]; +}; + +struct lldp_status_params_s { + u32 prefix_seq_num; + u32 status; /* TBD */ + + /* Holds remote Chassis ID TLV header, subtype and 9B of payload. */ + u32 peer_chassis_id[LLDP_CHASSIS_ID_STAT_LEN]; + + /* Holds remote Port ID TLV header, subtype and 9B of payload. */ + u32 peer_port_id[LLDP_PORT_ID_STAT_LEN]; + u32 suffix_seq_num; +}; + +struct dcbx_ets_feature { + u32 flags; +#define DCBX_ETS_ENABLED_MASK 0x00000001 +#define DCBX_ETS_ENABLED_SHIFT 0 +#define DCBX_ETS_WILLING_MASK 0x00000002 +#define DCBX_ETS_WILLING_SHIFT 1 +#define DCBX_ETS_ERROR_MASK 0x00000004 +#define DCBX_ETS_ERROR_SHIFT 2 +#define DCBX_ETS_CBS_MASK 0x00000008 +#define DCBX_ETS_CBS_SHIFT 3 +#define DCBX_ETS_MAX_TCS_MASK 0x000000f0 +#define DCBX_ETS_MAX_TCS_SHIFT 4 + u32 pri_tc_tbl[1]; +#define DCBX_ISCSI_OOO_TC 4 +#define NIG_ETS_ISCSI_OOO_CLIENT_OFFSET (DCBX_ISCSI_OOO_TC + 1) + u32 tc_bw_tbl[2]; + u32 tc_tsa_tbl[2]; +#define DCBX_ETS_TSA_STRICT 0 +#define DCBX_ETS_TSA_CBS 1 +#define DCBX_ETS_TSA_ETS 2 +}; + +struct dcbx_app_priority_entry { + u32 entry; +#define DCBX_APP_PRI_MAP_MASK 0x000000ff +#define DCBX_APP_PRI_MAP_SHIFT 0 +#define DCBX_APP_PRI_0 0x01 +#define DCBX_APP_PRI_1 0x02 +#define DCBX_APP_PRI_2 0x04 +#define DCBX_APP_PRI_3 0x08 +#define DCBX_APP_PRI_4 0x10 +#define DCBX_APP_PRI_5 0x20 +#define DCBX_APP_PRI_6 0x40 +#define DCBX_APP_PRI_7 0x80 +#define DCBX_APP_SF_MASK 0x00000300 +#define DCBX_APP_SF_SHIFT 8 +#define DCBX_APP_SF_ETHTYPE 0 +#define DCBX_APP_SF_PORT 1 +#define DCBX_APP_PROTOCOL_ID_MASK 0xffff0000 +#define DCBX_APP_PROTOCOL_ID_SHIFT 16 +}; + +/* FW structure in BE */ +struct dcbx_app_priority_feature { + u32 flags; +#define DCBX_APP_ENABLED_MASK 0x00000001 +#define DCBX_APP_ENABLED_SHIFT 0 +#define DCBX_APP_WILLING_MASK 0x00000002 +#define DCBX_APP_WILLING_SHIFT 1 +#define DCBX_APP_ERROR_MASK 0x00000004 +#define DCBX_APP_ERROR_SHIFT 2 +/* Not in use + * #define DCBX_APP_DEFAULT_PRI_MASK 0x00000f00 + * #define DCBX_APP_DEFAULT_PRI_SHIFT 8 + */ +#define DCBX_APP_MAX_TCS_MASK 0x0000f000 +#define DCBX_APP_MAX_TCS_SHIFT 12 +#define DCBX_APP_NUM_ENTRIES_MASK 0x00ff0000 +#define DCBX_APP_NUM_ENTRIES_SHIFT 16 + struct dcbx_app_priority_entry app_pri_tbl[DCBX_MAX_APP_PROTOCOL]; +}; + +/* FW structure in BE */ +struct dcbx_features { + /* PG feature */ + struct dcbx_ets_feature ets; + + /* PFC feature */ + u32 pfc; +#define DCBX_PFC_PRI_EN_BITMAP_MASK 0x000000ff +#define DCBX_PFC_PRI_EN_BITMAP_SHIFT 0 +#define DCBX_PFC_PRI_EN_BITMAP_PRI_0 0x01 +#define DCBX_PFC_PRI_EN_BITMAP_PRI_1 0x02 +#define DCBX_PFC_PRI_EN_BITMAP_PRI_2 0x04 +#define DCBX_PFC_PRI_EN_BITMAP_PRI_3 0x08 +#define DCBX_PFC_PRI_EN_BITMAP_PRI_4 0x10 +#define DCBX_PFC_PRI_EN_BITMAP_PRI_5 0x20 +#define DCBX_PFC_PRI_EN_BITMAP_PRI_6 0x40 +#define DCBX_PFC_PRI_EN_BITMAP_PRI_7 0x80 + +#define DCBX_PFC_FLAGS_MASK 0x0000ff00 +#define DCBX_PFC_FLAGS_SHIFT 8 +#define DCBX_PFC_CAPS_MASK 0x00000f00 +#define DCBX_PFC_CAPS_SHIFT 8 +#define DCBX_PFC_MBC_MASK 0x00004000 +#define DCBX_PFC_MBC_SHIFT 14 +#define DCBX_PFC_WILLING_MASK 0x00008000 +#define DCBX_PFC_WILLING_SHIFT 15 +#define DCBX_PFC_ENABLED_MASK 0x00010000 +#define DCBX_PFC_ENABLED_SHIFT 16 +#define DCBX_PFC_ERROR_MASK 0x00020000 +#define DCBX_PFC_ERROR_SHIFT 17 + + /* APP feature */ + struct dcbx_app_priority_feature app; +}; + +struct dcbx_local_params { + u32 config; +#define DCBX_CONFIG_VERSION_MASK 0x00000003 +#define DCBX_CONFIG_VERSION_SHIFT 0 +#define DCBX_CONFIG_VERSION_DISABLED 0 +#define DCBX_CONFIG_VERSION_IEEE 1 +#define DCBX_CONFIG_VERSION_CEE 2 + + u32 flags; + struct dcbx_features features; +}; + +struct dcbx_mib { + u32 prefix_seq_num; + u32 flags; + struct dcbx_features features; + u32 suffix_seq_num; +}; + +struct lldp_system_tlvs_buffer_s { + u16 valid; + u16 length; + u32 data[MAX_SYSTEM_LLDP_TLV_DATA]; +}; + +/**************************************/ +/* */ +/* P U B L I C G L O B A L */ +/* */ +/**************************************/ +struct public_global { + u32 max_path; +#define MAX_PATH_BIG_BEAR 2 +#define MAX_PATH_K2 1 + u32 max_ports; +#define MODE_1P 1 +#define MODE_2P 2 +#define MODE_3P 3 +#define MODE_4P 4 + u32 debug_mb_offset; + u32 phymod_dbg_mb_offset; + struct couple_mode_teaming cmt; + s32 internal_temperature; + u32 mfw_ver; + u32 running_bundle_id; +}; + +/**************************************/ +/* */ +/* P U B L I C P A T H */ +/* */ +/**************************************/ + +/**************************************************************************** +* Shared Memory 2 Region * +****************************************************************************/ +/* The fw_flr_ack is actually built in the following way: */ +/* 8 bit: PF ack */ +/* 128 bit: VF ack */ +/* 8 bit: ios_dis_ack */ +/* In order to maintain endianity in the mailbox hsi, we want to keep using */ +/* u32. The fw must have the VF right after the PF since this is how it */ +/* access arrays(it expects always the VF to reside after the PF, and that */ +/* makes the calculation much easier for it. ) */ +/* In order to answer both limitations, and keep the struct small, the code */ +/* will abuse the structure defined here to achieve the actual partition */ +/* above */ +/****************************************************************************/ +struct fw_flr_mb { + u32 aggint; + u32 opgen_addr; + u32 accum_ack; /* 0..15:PF, 16..207:VF, 256..271:IOV_DIS */ +#define ACCUM_ACK_PF_BASE 0 +#define ACCUM_ACK_PF_SHIFT 0 + +#define ACCUM_ACK_VF_BASE 8 +#define ACCUM_ACK_VF_SHIFT 3 + +#define ACCUM_ACK_IOV_DIS_BASE 256 +#define ACCUM_ACK_IOV_DIS_SHIFT 8 +}; + +struct public_path { + struct fw_flr_mb flr_mb; + u32 mcp_vf_disabled[VF_MAX_STATIC / 32]; + + u32 process_kill; +#define PROCESS_KILL_COUNTER_MASK 0x0000ffff +#define PROCESS_KILL_COUNTER_SHIFT 0 +#define PROCESS_KILL_GLOB_AEU_BIT_MASK 0xffff0000 +#define PROCESS_KILL_GLOB_AEU_BIT_SHIFT 16 +#define GLOBAL_AEU_BIT(aeu_reg_id, aeu_bit) (aeu_reg_id * 32 + aeu_bit) +}; + +/**************************************/ +/* */ +/* P U B L I C P O R T */ +/* */ +/**************************************/ + +/**************************************************************************** +* Driver <-> FW Mailbox * +****************************************************************************/ + +struct public_port { + u32 validity_map; /* 0x0 (4*2 = 0x8) */ + + /* validity bits */ +#define MCP_VALIDITY_PCI_CFG 0x00100000 +#define MCP_VALIDITY_MB 0x00200000 +#define MCP_VALIDITY_DEV_INFO 0x00400000 +#define MCP_VALIDITY_RESERVED 0x00000007 + + /* One licensing bit should be set */ +#define MCP_VALIDITY_LIC_KEY_IN_EFFECT_MASK 0x00000038 +#define MCP_VALIDITY_LIC_MANUF_KEY_IN_EFFECT 0x00000008 +#define MCP_VALIDITY_LIC_UPGRADE_KEY_IN_EFFECT 0x00000010 +#define MCP_VALIDITY_LIC_NO_KEY_IN_EFFECT 0x00000020 + + /* Active MFW */ +#define MCP_VALIDITY_ACTIVE_MFW_UNKNOWN 0x00000000 +#define MCP_VALIDITY_ACTIVE_MFW_MASK 0x000001c0 +#define MCP_VALIDITY_ACTIVE_MFW_NCSI 0x00000040 +#define MCP_VALIDITY_ACTIVE_MFW_NONE 0x000001c0 + + u32 link_status; +#define LINK_STATUS_LINK_UP \ + 0x00000001 +#define LINK_STATUS_SPEED_AND_DUPLEX_MASK 0x0000001e +#define LINK_STATUS_SPEED_AND_DUPLEX_1000THD BIT(1) +#define LINK_STATUS_SPEED_AND_DUPLEX_1000TFD (2 << 1) +#define LINK_STATUS_SPEED_AND_DUPLEX_10G (3 << 1) +#define LINK_STATUS_SPEED_AND_DUPLEX_20G (4 << 1) +#define LINK_STATUS_SPEED_AND_DUPLEX_40G (5 << 1) +#define LINK_STATUS_SPEED_AND_DUPLEX_50G (6 << 1) +#define LINK_STATUS_SPEED_AND_DUPLEX_100G (7 << 1) +#define LINK_STATUS_SPEED_AND_DUPLEX_25G (8 << 1) + +#define LINK_STATUS_AUTO_NEGOTIATE_ENABLED 0x00000020 + +#define LINK_STATUS_AUTO_NEGOTIATE_COMPLETE 0x00000040 +#define LINK_STATUS_PARALLEL_DETECTION_USED 0x00000080 + +#define LINK_STATUS_PFC_ENABLED \ + 0x00000100 +#define LINK_STATUS_LINK_PARTNER_1000TFD_CAPABLE 0x00000200 +#define LINK_STATUS_LINK_PARTNER_1000THD_CAPABLE 0x00000400 +#define LINK_STATUS_LINK_PARTNER_10G_CAPABLE 0x00000800 +#define LINK_STATUS_LINK_PARTNER_20G_CAPABLE 0x00001000 +#define LINK_STATUS_LINK_PARTNER_40G_CAPABLE 0x00002000 +#define LINK_STATUS_LINK_PARTNER_50G_CAPABLE 0x00004000 +#define LINK_STATUS_LINK_PARTNER_100G_CAPABLE 0x00008000 +#define LINK_STATUS_LINK_PARTNER_25G_CAPABLE 0x00010000 + +#define LINK_STATUS_LINK_PARTNER_FLOW_CONTROL_MASK 0x000C0000 +#define LINK_STATUS_LINK_PARTNER_NOT_PAUSE_CAPABLE (0 << 18) +#define LINK_STATUS_LINK_PARTNER_SYMMETRIC_PAUSE BIT(18) +#define LINK_STATUS_LINK_PARTNER_ASYMMETRIC_PAUSE (2 << 18) +#define LINK_STATUS_LINK_PARTNER_BOTH_PAUSE (3 << 18) + +#define LINK_STATUS_SFP_TX_FAULT \ + 0x00100000 +#define LINK_STATUS_TX_FLOW_CONTROL_ENABLED 0x00200000 +#define LINK_STATUS_RX_FLOW_CONTROL_ENABLED 0x00400000 + + u32 link_status1; + u32 ext_phy_fw_version; + u32 drv_phy_cfg_addr; + + u32 port_stx; + + u32 stat_nig_timer; + + struct port_mf_cfg port_mf_config; + struct port_stats stats; + + u32 media_type; +#define MEDIA_UNSPECIFIED 0x0 +#define MEDIA_SFPP_10G_FIBER 0x1 +#define MEDIA_XFP_FIBER 0x2 +#define MEDIA_DA_TWINAX 0x3 +#define MEDIA_BASE_T 0x4 +#define MEDIA_SFP_1G_FIBER 0x5 +#define MEDIA_KR 0xf0 +#define MEDIA_NOT_PRESENT 0xff + + u32 lfa_status; +#define LFA_LINK_FLAP_REASON_OFFSET 0 +#define LFA_LINK_FLAP_REASON_MASK 0x000000ff +#define LFA_NO_REASON (0 << 0) +#define LFA_LINK_DOWN BIT(0) +#define LFA_FORCE_INIT BIT(1) +#define LFA_LOOPBACK_MISMATCH BIT(2) +#define LFA_SPEED_MISMATCH BIT(3) +#define LFA_FLOW_CTRL_MISMATCH BIT(4) +#define LFA_ADV_SPEED_MISMATCH BIT(5) +#define LINK_FLAP_AVOIDANCE_COUNT_OFFSET 8 +#define LINK_FLAP_AVOIDANCE_COUNT_MASK 0x0000ff00 +#define LINK_FLAP_COUNT_OFFSET 16 +#define LINK_FLAP_COUNT_MASK 0x00ff0000 + + u32 link_change_count; + + /* LLDP params */ + struct lldp_config_params_s lldp_config_params[ + LLDP_MAX_LLDP_AGENTS]; + struct lldp_status_params_s lldp_status_params[ + LLDP_MAX_LLDP_AGENTS]; + struct lldp_system_tlvs_buffer_s system_lldp_tlvs_buf; + + /* DCBX related MIB */ + struct dcbx_local_params local_admin_dcbx_mib; + struct dcbx_mib remote_dcbx_mib; + struct dcbx_mib operational_dcbx_mib; +}; + +/**************************************/ +/* */ +/* P U B L I C F U N C */ +/* */ +/**************************************/ + +struct public_func { + u32 iscsi_boot_signature; + u32 iscsi_boot_block_offset; + + u32 reserved[8]; + + u32 config; + + /* E/R/I/D */ + /* function 0 of each port cannot be hidden */ +#define FUNC_MF_CFG_FUNC_HIDE 0x00000001 +#define FUNC_MF_CFG_PAUSE_ON_HOST_RING 0x00000002 +#define FUNC_MF_CFG_PAUSE_ON_HOST_RING_SHIFT 0x00000001 + +#define FUNC_MF_CFG_PROTOCOL_MASK 0x000000f0 +#define FUNC_MF_CFG_PROTOCOL_SHIFT 4 +#define FUNC_MF_CFG_PROTOCOL_ETHERNET 0x00000000 +#define FUNC_MF_CFG_PROTOCOL_ISCSI 0x00000010 +#define FUNC_MF_CFG_PROTOCOL_FCOE 0x00000020 +#define FUNC_MF_CFG_PROTOCOL_ROCE 0x00000030 +#define FUNC_MF_CFG_PROTOCOL_MAX 0x00000030 + + /* MINBW, MAXBW */ + /* value range - 0..100, increments in 1 % */ +#define FUNC_MF_CFG_MIN_BW_MASK 0x0000ff00 +#define FUNC_MF_CFG_MIN_BW_SHIFT 8 +#define FUNC_MF_CFG_MIN_BW_DEFAULT 0x00000000 +#define FUNC_MF_CFG_MAX_BW_MASK 0x00ff0000 +#define FUNC_MF_CFG_MAX_BW_SHIFT 16 +#define FUNC_MF_CFG_MAX_BW_DEFAULT 0x00640000 + + u32 status; +#define FUNC_STATUS_VLINK_DOWN 0x00000001 + + u32 mac_upper; /* MAC */ +#define FUNC_MF_CFG_UPPERMAC_MASK 0x0000ffff +#define FUNC_MF_CFG_UPPERMAC_SHIFT 0 +#define FUNC_MF_CFG_UPPERMAC_DEFAULT FUNC_MF_CFG_UPPERMAC_MASK + u32 mac_lower; +#define FUNC_MF_CFG_LOWERMAC_DEFAULT 0xffffffff + + u32 fcoe_wwn_port_name_upper; + u32 fcoe_wwn_port_name_lower; + + u32 fcoe_wwn_node_name_upper; + u32 fcoe_wwn_node_name_lower; + + u32 ovlan_stag; /* tags */ +#define FUNC_MF_CFG_OV_STAG_MASK 0x0000ffff +#define FUNC_MF_CFG_OV_STAG_SHIFT 0 +#define FUNC_MF_CFG_OV_STAG_DEFAULT FUNC_MF_CFG_OV_STAG_MASK + + u32 pf_allocation; /* vf per pf */ + + u32 preserve_data; /* Will be used bt CCM */ + + u32 driver_last_activity_ts; + + u32 drv_ack_vf_disabled[VF_MAX_STATIC / 32]; /* 0x0044 */ + + u32 drv_id; +#define DRV_ID_PDA_COMP_VER_MASK 0x0000ffff +#define DRV_ID_PDA_COMP_VER_SHIFT 0 + +#define DRV_ID_MCP_HSI_VER_MASK 0x00ff0000 +#define DRV_ID_MCP_HSI_VER_SHIFT 16 +#define DRV_ID_MCP_HSI_VER_CURRENT BIT(DRV_ID_MCP_HSI_VER_SHIFT) + +#define DRV_ID_DRV_TYPE_MASK 0xff000000 +#define DRV_ID_DRV_TYPE_SHIFT 24 +#define DRV_ID_DRV_TYPE_UNKNOWN (0 << DRV_ID_DRV_TYPE_SHIFT) +#define DRV_ID_DRV_TYPE_LINUX BIT(DRV_ID_DRV_TYPE_SHIFT) +#define DRV_ID_DRV_TYPE_WINDOWS (2 << DRV_ID_DRV_TYPE_SHIFT) +#define DRV_ID_DRV_TYPE_DIAG (3 << DRV_ID_DRV_TYPE_SHIFT) +#define DRV_ID_DRV_TYPE_PREBOOT (4 << DRV_ID_DRV_TYPE_SHIFT) +#define DRV_ID_DRV_TYPE_SOLARIS (5 << DRV_ID_DRV_TYPE_SHIFT) +#define DRV_ID_DRV_TYPE_VMWARE (6 << DRV_ID_DRV_TYPE_SHIFT) +#define DRV_ID_DRV_TYPE_FREEBSD (7 << DRV_ID_DRV_TYPE_SHIFT) +#define DRV_ID_DRV_TYPE_AIX (8 << DRV_ID_DRV_TYPE_SHIFT) +}; + +/**************************************/ +/* */ +/* P U B L I C M B */ +/* */ +/**************************************/ +/* This is the only section that the driver can write to, and each */ +/* Basically each driver request to set feature parameters, + * will be done using a different command, which will be linked + * to a specific data structure from the union below. + * For huge strucuture, the common blank structure should be used. + */ + +struct mcp_mac { + u32 mac_upper; /* Upper 16 bits are always zeroes */ + u32 mac_lower; +}; + +struct mcp_val64 { + u32 lo; + u32 hi; +}; + +struct mcp_file_att { + u32 nvm_start_addr; + u32 len; +}; + +#define MCP_DRV_VER_STR_SIZE 16 +#define MCP_DRV_VER_STR_SIZE_DWORD (MCP_DRV_VER_STR_SIZE / sizeof(u32)) +#define MCP_DRV_NVM_BUF_LEN 32 +struct drv_version_stc { + u32 version; + u8 name[MCP_DRV_VER_STR_SIZE - 4]; +}; + +union drv_union_data { + u32 ver_str[MCP_DRV_VER_STR_SIZE_DWORD]; + struct mcp_mac wol_mac; + + struct pmm_phy_cfg drv_phy_cfg; + + struct mcp_val64 val64; /* For PHY / AVS commands */ + + u8 raw_data[MCP_DRV_NVM_BUF_LEN]; + + struct mcp_file_att file_att; + + u32 ack_vf_disabled[VF_MAX_STATIC / 32]; + + struct drv_version_stc drv_version; +}; + +struct public_drv_mb { + u32 drv_mb_header; +#define DRV_MSG_CODE_MASK 0xffff0000 +#define DRV_MSG_CODE_LOAD_REQ 0x10000000 +#define DRV_MSG_CODE_LOAD_DONE 0x11000000 +#define DRV_MSG_CODE_UNLOAD_REQ 0x20000000 +#define DRV_MSG_CODE_UNLOAD_DONE 0x21000000 +#define DRV_MSG_CODE_INIT_PHY 0x22000000 + /* Params - FORCE - Reinitialize the link regardless of LFA */ + /* - DONT_CARE - Don't flap the link if up */ +#define DRV_MSG_CODE_LINK_RESET 0x23000000 + +#define DRV_MSG_CODE_SET_LLDP 0x24000000 +#define DRV_MSG_CODE_SET_DCBX 0x25000000 + +#define DRV_MSG_CODE_NIG_DRAIN 0x30000000 + +#define DRV_MSG_CODE_INITIATE_FLR 0x02000000 +#define DRV_MSG_CODE_VF_DISABLED_DONE 0xc0000000 +#define DRV_MSG_CODE_CFG_VF_MSIX 0xc0010000 +#define DRV_MSG_CODE_NVM_PUT_FILE_BEGIN 0x00010000 +#define DRV_MSG_CODE_NVM_PUT_FILE_DATA 0x00020000 +#define DRV_MSG_CODE_NVM_GET_FILE_ATT 0x00030000 +#define DRV_MSG_CODE_NVM_READ_NVRAM 0x00050000 +#define DRV_MSG_CODE_NVM_WRITE_NVRAM 0x00060000 +#define DRV_MSG_CODE_NVM_DEL_FILE 0x00080000 +#define DRV_MSG_CODE_MCP_RESET 0x00090000 +#define DRV_MSG_CODE_SET_SECURE_MODE 0x000a0000 +#define DRV_MSG_CODE_PHY_RAW_READ 0x000b0000 +#define DRV_MSG_CODE_PHY_RAW_WRITE 0x000c0000 +#define DRV_MSG_CODE_PHY_CORE_READ 0x000d0000 +#define DRV_MSG_CODE_PHY_CORE_WRITE 0x000e0000 +#define DRV_MSG_CODE_SET_VERSION 0x000f0000 + +#define DRV_MSG_SEQ_NUMBER_MASK 0x0000ffff + + u32 drv_mb_param; + + /* UNLOAD_REQ params */ +#define DRV_MB_PARAM_UNLOAD_WOL_UNKNOWN 0x00000000 +#define DRV_MB_PARAM_UNLOAD_WOL_MCP 0x00000001 +#define DRV_MB_PARAM_UNLOAD_WOL_DISABLED 0x00000002 +#define DRV_MB_PARAM_UNLOAD_WOL_ENABLED 0x00000003 + + /* UNLOAD_DONE_params */ +#define DRV_MB_PARAM_UNLOAD_NON_D3_POWER 0x00000001 + + /* INIT_PHY params */ +#define DRV_MB_PARAM_INIT_PHY_FORCE 0x00000001 +#define DRV_MB_PARAM_INIT_PHY_DONT_CARE 0x00000002 + + /* LLDP / DCBX params*/ +#define DRV_MB_PARAM_LLDP_SEND_MASK 0x00000001 +#define DRV_MB_PARAM_LLDP_SEND_SHIFT 0 +#define DRV_MB_PARAM_LLDP_AGENT_MASK 0x00000006 +#define DRV_MB_PARAM_LLDP_AGENT_SHIFT 1 +#define DRV_MB_PARAM_DCBX_NOTIFY_MASK 0x00000008 +#define DRV_MB_PARAM_DCBX_NOTIFY_SHIFT 3 + +#define DRV_MB_PARAM_NIG_DRAIN_PERIOD_MS_MASK 0x000000FF +#define DRV_MB_PARAM_NIG_DRAIN_PERIOD_MS_SHIFT 0 + +#define DRV_MB_PARAM_NVM_PUT_FILE_BEGIN_MFW 0x1 +#define DRV_MB_PARAM_NVM_PUT_FILE_BEGIN_IMAGE 0x2 + +#define DRV_MB_PARAM_NVM_OFFSET_SHIFT 0 +#define DRV_MB_PARAM_NVM_OFFSET_MASK 0x00FFFFFF +#define DRV_MB_PARAM_NVM_LEN_SHIFT 24 +#define DRV_MB_PARAM_NVM_LEN_MASK 0xFF000000 + +#define DRV_MB_PARAM_PHY_ADDR_SHIFT 0 +#define DRV_MB_PARAM_PHY_ADDR_MASK 0x1FF0FFFF +#define DRV_MB_PARAM_PHY_LANE_SHIFT 16 +#define DRV_MB_PARAM_PHY_LANE_MASK 0x000F0000 +#define DRV_MB_PARAM_PHY_SELECT_PORT_SHIFT 29 +#define DRV_MB_PARAM_PHY_SELECT_PORT_MASK 0x20000000 +#define DRV_MB_PARAM_PHY_PORT_SHIFT 30 +#define DRV_MB_PARAM_PHY_PORT_MASK 0xc0000000 + +/* configure vf MSIX params*/ +#define DRV_MB_PARAM_CFG_VF_MSIX_VF_ID_SHIFT 0 +#define DRV_MB_PARAM_CFG_VF_MSIX_VF_ID_MASK 0x000000FF +#define DRV_MB_PARAM_CFG_VF_MSIX_SB_NUM_SHIFT 8 +#define DRV_MB_PARAM_CFG_VF_MSIX_SB_NUM_MASK 0x0000FF00 + + u32 fw_mb_header; +#define FW_MSG_CODE_MASK 0xffff0000 +#define FW_MSG_CODE_DRV_LOAD_ENGINE 0x10100000 +#define FW_MSG_CODE_DRV_LOAD_PORT 0x10110000 +#define FW_MSG_CODE_DRV_LOAD_FUNCTION 0x10120000 +#define FW_MSG_CODE_DRV_LOAD_REFUSED_PDA 0x10200000 +#define FW_MSG_CODE_DRV_LOAD_REFUSED_HSI 0x10210000 +#define FW_MSG_CODE_DRV_LOAD_REFUSED_DIAG 0x10220000 +#define FW_MSG_CODE_DRV_LOAD_DONE 0x11100000 +#define FW_MSG_CODE_DRV_UNLOAD_ENGINE 0x20110000 +#define FW_MSG_CODE_DRV_UNLOAD_PORT 0x20120000 +#define FW_MSG_CODE_DRV_UNLOAD_FUNCTION 0x20130000 +#define FW_MSG_CODE_DRV_UNLOAD_DONE 0x21100000 +#define FW_MSG_CODE_INIT_PHY_DONE 0x21200000 +#define FW_MSG_CODE_INIT_PHY_ERR_INVALID_ARGS 0x21300000 +#define FW_MSG_CODE_LINK_RESET_DONE 0x23000000 +#define FW_MSG_CODE_SET_LLDP_DONE 0x24000000 +#define FW_MSG_CODE_SET_LLDP_UNSUPPORTED_AGENT 0x24010000 +#define FW_MSG_CODE_SET_DCBX_DONE 0x25000000 +#define FW_MSG_CODE_NIG_DRAIN_DONE 0x30000000 +#define FW_MSG_CODE_VF_DISABLED_DONE 0xb0000000 +#define FW_MSG_CODE_DRV_CFG_VF_MSIX_DONE 0xb0010000 +#define FW_MSG_CODE_FLR_ACK 0x02000000 +#define FW_MSG_CODE_FLR_NACK 0x02100000 + +#define FW_MSG_CODE_NVM_OK 0x00010000 +#define FW_MSG_CODE_NVM_INVALID_MODE 0x00020000 +#define FW_MSG_CODE_NVM_PREV_CMD_WAS_NOT_FINISHED 0x00030000 +#define FW_MSG_CODE_NVM_FAILED_TO_ALLOCATE_PAGE 0x00040000 +#define FW_MSG_CODE_NVM_INVALID_DIR_FOUND 0x00050000 +#define FW_MSG_CODE_NVM_PAGE_NOT_FOUND 0x00060000 +#define FW_MSG_CODE_NVM_FAILED_PARSING_BNDLE_HEADER 0x00070000 +#define FW_MSG_CODE_NVM_FAILED_PARSING_IMAGE_HEADER 0x00080000 +#define FW_MSG_CODE_NVM_PARSING_OUT_OF_SYNC 0x00090000 +#define FW_MSG_CODE_NVM_FAILED_UPDATING_DIR 0x000a0000 +#define FW_MSG_CODE_NVM_FAILED_TO_FREE_PAGE 0x000b0000 +#define FW_MSG_CODE_NVM_FILE_NOT_FOUND 0x000c0000 +#define FW_MSG_CODE_NVM_OPERATION_FAILED 0x000d0000 +#define FW_MSG_CODE_NVM_FAILED_UNALIGNED 0x000e0000 +#define FW_MSG_CODE_NVM_BAD_OFFSET 0x000f0000 +#define FW_MSG_CODE_NVM_BAD_SIGNATURE 0x00100000 +#define FW_MSG_CODE_NVM_FILE_READ_ONLY 0x00200000 +#define FW_MSG_CODE_NVM_UNKNOWN_FILE 0x00300000 +#define FW_MSG_CODE_NVM_PUT_FILE_FINISH_OK 0x00400000 +#define FW_MSG_CODE_MCP_RESET_REJECT 0x00600000 +#define FW_MSG_CODE_PHY_OK 0x00110000 +#define FW_MSG_CODE_PHY_ERROR 0x00120000 +#define FW_MSG_CODE_SET_SECURE_MODE_ERROR 0x00130000 +#define FW_MSG_CODE_SET_SECURE_MODE_OK 0x00140000 +#define FW_MSG_MODE_PHY_PRIVILEGE_ERROR 0x00150000 + +#define FW_MSG_SEQ_NUMBER_MASK 0x0000ffff + + u32 fw_mb_param; + + u32 drv_pulse_mb; +#define DRV_PULSE_SEQ_MASK 0x00007fff +#define DRV_PULSE_SYSTEM_TIME_MASK 0xffff0000 +#define DRV_PULSE_ALWAYS_ALIVE 0x00008000 + u32 mcp_pulse_mb; +#define MCP_PULSE_SEQ_MASK 0x00007fff +#define MCP_PULSE_ALWAYS_ALIVE 0x00008000 +#define MCP_EVENT_MASK 0xffff0000 +#define MCP_EVENT_OTHER_DRIVER_RESET_REQ 0x00010000 + + union drv_union_data union_data; +}; + +/* MFW - DRV MB */ +/********************************************************************** +* Description +* Incremental Aggregative +* 8-bit MFW counter per message +* 8-bit ack-counter per message +* Capabilities +* Provides up to 256 aggregative message per type +* Provides 4 message types in dword +* Message type pointers to byte offset +* Backward Compatibility by using sizeof for the counters. +* No lock requires for 32bit messages +* Limitations: +* In case of messages greater than 32bit, a dedicated mechanism(e.g lock) +* is required to prevent data corruption. +**********************************************************************/ +enum MFW_DRV_MSG_TYPE { + MFW_DRV_MSG_LINK_CHANGE, + MFW_DRV_MSG_FLR_FW_ACK_FAILED, + MFW_DRV_MSG_VF_DISABLED, + MFW_DRV_MSG_LLDP_DATA_UPDATED, + MFW_DRV_MSG_DCBX_REMOTE_MIB_UPDATED, + MFW_DRV_MSG_DCBX_OPERATIONAL_MIB_UPDATED, + MFW_DRV_MSG_ERROR_RECOVERY, + MFW_DRV_MSG_MAX +}; + +#define MFW_DRV_MSG_MAX_DWORDS(msgs) (((msgs - 1) >> 2) + 1) +#define MFW_DRV_MSG_DWORD(msg_id) (msg_id >> 2) +#define MFW_DRV_MSG_OFFSET(msg_id) ((msg_id & 0x3) << 3) +#define MFW_DRV_MSG_MASK(msg_id) (0xff << MFW_DRV_MSG_OFFSET(msg_id)) + +struct public_mfw_mb { + u32 sup_msgs; + u32 msg[MFW_DRV_MSG_MAX_DWORDS(MFW_DRV_MSG_MAX)]; + u32 ack[MFW_DRV_MSG_MAX_DWORDS(MFW_DRV_MSG_MAX)]; +}; + +/**************************************/ +/* */ +/* P U B L I C D A T A */ +/* */ +/**************************************/ +enum public_sections { + PUBLIC_DRV_MB, /* Points to the first drv_mb of path0 */ + PUBLIC_MFW_MB, /* Points to the first mfw_mb of path0 */ + PUBLIC_GLOBAL, + PUBLIC_PATH, + PUBLIC_PORT, + PUBLIC_FUNC, + PUBLIC_MAX_SECTIONS +}; + +struct drv_ver_info_stc { + u32 ver; + u8 name[32]; +}; + +struct mcp_public_data { + /* The sections fields is an array */ + u32 num_sections; + offsize_t sections[PUBLIC_MAX_SECTIONS]; + struct public_drv_mb drv_mb[MCP_GLOB_FUNC_MAX]; + struct public_mfw_mb mfw_mb[MCP_GLOB_FUNC_MAX]; + struct public_global global; + struct public_path path[MCP_GLOB_PATH_MAX]; + struct public_port port[MCP_GLOB_PORT_MAX]; + struct public_func func[MCP_GLOB_FUNC_MAX]; + struct drv_ver_info_stc drv_info; +}; + +struct nvm_cfg_mac_address { + u32 mac_addr_hi; +#define NVM_CFG_MAC_ADDRESS_HI_MASK 0x0000FFFF +#define NVM_CFG_MAC_ADDRESS_HI_OFFSET 0 + + u32 mac_addr_lo; +}; + +/****************************************** +* nvm_cfg1 structs +******************************************/ + +struct nvm_cfg1_glob { + u32 generic_cont0; /* 0x0 */ +#define NVM_CFG1_GLOB_BOARD_SWAP_MASK 0x0000000F +#define NVM_CFG1_GLOB_BOARD_SWAP_OFFSET 0 +#define NVM_CFG1_GLOB_BOARD_SWAP_NONE 0x0 +#define NVM_CFG1_GLOB_BOARD_SWAP_PATH 0x1 +#define NVM_CFG1_GLOB_BOARD_SWAP_PORT 0x2 +#define NVM_CFG1_GLOB_BOARD_SWAP_BOTH 0x3 +#define NVM_CFG1_GLOB_MF_MODE_MASK 0x00000FF0 +#define NVM_CFG1_GLOB_MF_MODE_OFFSET 4 +#define NVM_CFG1_GLOB_MF_MODE_MF_ALLOWED 0x0 +#define NVM_CFG1_GLOB_MF_MODE_FORCED_SF 0x1 +#define NVM_CFG1_GLOB_MF_MODE_SPIO4 0x2 +#define NVM_CFG1_GLOB_MF_MODE_NPAR1_0 0x3 +#define NVM_CFG1_GLOB_MF_MODE_NPAR1_5 0x4 +#define NVM_CFG1_GLOB_MF_MODE_NPAR2_0 0x5 +#define NVM_CFG1_GLOB_MF_MODE_BD 0x6 +#define NVM_CFG1_GLOB_MF_MODE_UFP 0x7 +#define NVM_CFG1_GLOB_FAN_FAILURE_ENFORCEMENT_MASK 0x00001000 +#define NVM_CFG1_GLOB_FAN_FAILURE_ENFORCEMENT_OFFSET 12 +#define NVM_CFG1_GLOB_FAN_FAILURE_ENFORCEMENT_DISABLED 0x0 +#define NVM_CFG1_GLOB_FAN_FAILURE_ENFORCEMENT_ENABLED 0x1 +#define NVM_CFG1_GLOB_AVS_MARGIN_LOW_MASK 0x001FE000 +#define NVM_CFG1_GLOB_AVS_MARGIN_LOW_OFFSET 13 +#define NVM_CFG1_GLOB_AVS_MARGIN_HIGH_MASK 0x1FE00000 +#define NVM_CFG1_GLOB_AVS_MARGIN_HIGH_OFFSET 21 +#define NVM_CFG1_GLOB_ENABLE_SRIOV_MASK 0x20000000 +#define NVM_CFG1_GLOB_ENABLE_SRIOV_OFFSET 29 +#define NVM_CFG1_GLOB_ENABLE_SRIOV_DISABLED 0x0 +#define NVM_CFG1_GLOB_ENABLE_SRIOV_ENABLED 0x1 +#define NVM_CFG1_GLOB_ENABLE_ATC_MASK 0x40000000 +#define NVM_CFG1_GLOB_ENABLE_ATC_OFFSET 30 +#define NVM_CFG1_GLOB_ENABLE_ATC_DISABLED 0x0 +#define NVM_CFG1_GLOB_ENABLE_ATC_ENABLED 0x1 +#define NVM_CFG1_GLOB_CLOCK_SLOWDOWN_MASK 0x80000000 +#define NVM_CFG1_GLOB_CLOCK_SLOWDOWN_OFFSET 31 +#define NVM_CFG1_GLOB_CLOCK_SLOWDOWN_DISABLED 0x0 +#define NVM_CFG1_GLOB_CLOCK_SLOWDOWN_ENABLED 0x1 + + u32 engineering_change[3]; /* 0x4 */ + + u32 manufacturing_id; /* 0x10 */ + + u32 serial_number[4]; /* 0x14 */ + + u32 pcie_cfg; /* 0x24 */ +#define NVM_CFG1_GLOB_PCI_GEN_MASK 0x00000003 +#define NVM_CFG1_GLOB_PCI_GEN_OFFSET 0 +#define NVM_CFG1_GLOB_PCI_GEN_PCI_GEN1 0x0 +#define NVM_CFG1_GLOB_PCI_GEN_PCI_GEN2 0x1 +#define NVM_CFG1_GLOB_PCI_GEN_PCI_GEN3 0x2 +#define NVM_CFG1_GLOB_BEACON_WOL_ENABLED_MASK 0x00000004 +#define NVM_CFG1_GLOB_BEACON_WOL_ENABLED_OFFSET 2 +#define NVM_CFG1_GLOB_BEACON_WOL_ENABLED_DISABLED 0x0 +#define NVM_CFG1_GLOB_BEACON_WOL_ENABLED_ENABLED 0x1 +#define NVM_CFG1_GLOB_ASPM_SUPPORT_MASK 0x00000018 +#define NVM_CFG1_GLOB_ASPM_SUPPORT_OFFSET 3 +#define NVM_CFG1_GLOB_ASPM_SUPPORT_L0S_L1_ENABLED 0x0 +#define NVM_CFG1_GLOB_ASPM_SUPPORT_L0S_DISABLED 0x1 +#define NVM_CFG1_GLOB_ASPM_SUPPORT_L1_DISABLED 0x2 +#define NVM_CFG1_GLOB_ASPM_SUPPORT_L0S_L1_DISABLED 0x3 +#define NVM_CFG1_GLOB_PREVENT_PCIE_L1_MENTRY_MASK 0x00000020 +#define NVM_CFG1_GLOB_PREVENT_PCIE_L1_MENTRY_OFFSET 5 +#define NVM_CFG1_GLOB_PREVENT_PCIE_L1_MENTRY_DISABLED 0x0 +#define NVM_CFG1_GLOB_PREVENT_PCIE_L1_MENTRY_ENABLED 0x1 +#define NVM_CFG1_GLOB_PCIE_G2_TX_AMPLITUDE_MASK 0x000003C0 +#define NVM_CFG1_GLOB_PCIE_G2_TX_AMPLITUDE_OFFSET 6 +#define NVM_CFG1_GLOB_PCIE_PREEMPHASIS_MASK 0x00001C00 +#define NVM_CFG1_GLOB_PCIE_PREEMPHASIS_OFFSET 10 +#define NVM_CFG1_GLOB_PCIE_PREEMPHASIS_HW 0x0 +#define NVM_CFG1_GLOB_PCIE_PREEMPHASIS_0DB 0x1 +#define NVM_CFG1_GLOB_PCIE_PREEMPHASIS_3_5DB 0x2 +#define NVM_CFG1_GLOB_PCIE_PREEMPHASIS_6_0DB 0x3 +#define NVM_CFG1_GLOB_WWN_NODE_PREFIX0_MASK 0x001FE000 +#define NVM_CFG1_GLOB_WWN_NODE_PREFIX0_OFFSET 13 +#define NVM_CFG1_GLOB_WWN_NODE_PREFIX1_MASK 0x1FE00000 +#define NVM_CFG1_GLOB_WWN_NODE_PREFIX1_OFFSET 21 +#define NVM_CFG1_GLOB_NCSI_PACKAGE_ID_MASK 0x60000000 +#define NVM_CFG1_GLOB_NCSI_PACKAGE_ID_OFFSET 29 + + u32 mgmt_traffic; /* 0x28 */ +#define NVM_CFG1_GLOB_RESERVED60_MASK 0x00000001 +#define NVM_CFG1_GLOB_RESERVED60_OFFSET 0 +#define NVM_CFG1_GLOB_RESERVED60_100KHZ 0x0 +#define NVM_CFG1_GLOB_RESERVED60_400KHZ 0x1 +#define NVM_CFG1_GLOB_WWN_PORT_PREFIX0_MASK 0x000001FE +#define NVM_CFG1_GLOB_WWN_PORT_PREFIX0_OFFSET 1 +#define NVM_CFG1_GLOB_WWN_PORT_PREFIX1_MASK 0x0001FE00 +#define NVM_CFG1_GLOB_WWN_PORT_PREFIX1_OFFSET 9 +#define NVM_CFG1_GLOB_SMBUS_ADDRESS_MASK 0x01FE0000 +#define NVM_CFG1_GLOB_SMBUS_ADDRESS_OFFSET 17 +#define NVM_CFG1_GLOB_SIDEBAND_MODE_MASK 0x06000000 +#define NVM_CFG1_GLOB_SIDEBAND_MODE_OFFSET 25 +#define NVM_CFG1_GLOB_SIDEBAND_MODE_DISABLED 0x0 +#define NVM_CFG1_GLOB_SIDEBAND_MODE_RMII 0x1 +#define NVM_CFG1_GLOB_SIDEBAND_MODE_SGMII 0x2 + + u32 core_cfg; /* 0x2C */ +#define NVM_CFG1_GLOB_NETWORK_PORT_MODE_MASK 0x000000FF +#define NVM_CFG1_GLOB_NETWORK_PORT_MODE_OFFSET 0 +#define NVM_CFG1_GLOB_NETWORK_PORT_MODE_DE_2X40G 0x0 +#define NVM_CFG1_GLOB_NETWORK_PORT_MODE_DE_2X50G 0x1 +#define NVM_CFG1_GLOB_NETWORK_PORT_MODE_DE_1X100G 0x2 +#define NVM_CFG1_GLOB_NETWORK_PORT_MODE_DE_4X10G_F 0x3 +#define NVM_CFG1_GLOB_NETWORK_PORT_MODE_DE_4X10G_E 0x4 +#define NVM_CFG1_GLOB_NETWORK_PORT_MODE_DE_4X20G 0x5 +#define NVM_CFG1_GLOB_NETWORK_PORT_MODE_DE_1X40G 0xB +#define NVM_CFG1_GLOB_NETWORK_PORT_MODE_DE_2X25G 0xC +#define NVM_CFG1_GLOB_NETWORK_PORT_MODE_DE_1X25G 0xD +#define NVM_CFG1_GLOB_EAGLE_ENFORCE_TX_FIR_CFG_MASK 0x00000100 +#define NVM_CFG1_GLOB_EAGLE_ENFORCE_TX_FIR_CFG_OFFSET 8 +#define NVM_CFG1_GLOB_EAGLE_ENFORCE_TX_FIR_CFG_DISABLED 0x0 +#define NVM_CFG1_GLOB_EAGLE_ENFORCE_TX_FIR_CFG_ENABLED 0x1 +#define NVM_CFG1_GLOB_FALCON_ENFORCE_TX_FIR_CFG_MASK 0x00000200 +#define NVM_CFG1_GLOB_FALCON_ENFORCE_TX_FIR_CFG_OFFSET 9 +#define NVM_CFG1_GLOB_FALCON_ENFORCE_TX_FIR_CFG_DISABLED 0x0 +#define NVM_CFG1_GLOB_FALCON_ENFORCE_TX_FIR_CFG_ENABLED 0x1 +#define NVM_CFG1_GLOB_EAGLE_CORE_ADDR_MASK 0x0003FC00 +#define NVM_CFG1_GLOB_EAGLE_CORE_ADDR_OFFSET 10 +#define NVM_CFG1_GLOB_FALCON_CORE_ADDR_MASK 0x03FC0000 +#define NVM_CFG1_GLOB_FALCON_CORE_ADDR_OFFSET 18 +#define NVM_CFG1_GLOB_AVS_MODE_MASK 0x1C000000 +#define NVM_CFG1_GLOB_AVS_MODE_OFFSET 26 +#define NVM_CFG1_GLOB_AVS_MODE_CLOSE_LOOP 0x0 +#define NVM_CFG1_GLOB_AVS_MODE_OPEN_LOOP 0x1 +#define NVM_CFG1_GLOB_AVS_MODE_DISABLED 0x3 +#define NVM_CFG1_GLOB_OVERRIDE_SECURE_MODE_MASK 0x60000000 +#define NVM_CFG1_GLOB_OVERRIDE_SECURE_MODE_OFFSET 29 +#define NVM_CFG1_GLOB_OVERRIDE_SECURE_MODE_DISABLED 0x0 +#define NVM_CFG1_GLOB_OVERRIDE_SECURE_MODE_ENABLED 0x1 + + u32 e_lane_cfg1; /* 0x30 */ +#define NVM_CFG1_GLOB_RX_LANE0_SWAP_MASK 0x0000000F +#define NVM_CFG1_GLOB_RX_LANE0_SWAP_OFFSET 0 +#define NVM_CFG1_GLOB_RX_LANE1_SWAP_MASK 0x000000F0 +#define NVM_CFG1_GLOB_RX_LANE1_SWAP_OFFSET 4 +#define NVM_CFG1_GLOB_RX_LANE2_SWAP_MASK 0x00000F00 +#define NVM_CFG1_GLOB_RX_LANE2_SWAP_OFFSET 8 +#define NVM_CFG1_GLOB_RX_LANE3_SWAP_MASK 0x0000F000 +#define NVM_CFG1_GLOB_RX_LANE3_SWAP_OFFSET 12 +#define NVM_CFG1_GLOB_TX_LANE0_SWAP_MASK 0x000F0000 +#define NVM_CFG1_GLOB_TX_LANE0_SWAP_OFFSET 16 +#define NVM_CFG1_GLOB_TX_LANE1_SWAP_MASK 0x00F00000 +#define NVM_CFG1_GLOB_TX_LANE1_SWAP_OFFSET 20 +#define NVM_CFG1_GLOB_TX_LANE2_SWAP_MASK 0x0F000000 +#define NVM_CFG1_GLOB_TX_LANE2_SWAP_OFFSET 24 +#define NVM_CFG1_GLOB_TX_LANE3_SWAP_MASK 0xF0000000 +#define NVM_CFG1_GLOB_TX_LANE3_SWAP_OFFSET 28 + + u32 e_lane_cfg2; /* 0x34 */ +#define NVM_CFG1_GLOB_RX_LANE0_POL_FLIP_MASK 0x00000001 +#define NVM_CFG1_GLOB_RX_LANE0_POL_FLIP_OFFSET 0 +#define NVM_CFG1_GLOB_RX_LANE1_POL_FLIP_MASK 0x00000002 +#define NVM_CFG1_GLOB_RX_LANE1_POL_FLIP_OFFSET 1 +#define NVM_CFG1_GLOB_RX_LANE2_POL_FLIP_MASK 0x00000004 +#define NVM_CFG1_GLOB_RX_LANE2_POL_FLIP_OFFSET 2 +#define NVM_CFG1_GLOB_RX_LANE3_POL_FLIP_MASK 0x00000008 +#define NVM_CFG1_GLOB_RX_LANE3_POL_FLIP_OFFSET 3 +#define NVM_CFG1_GLOB_TX_LANE0_POL_FLIP_MASK 0x00000010 +#define NVM_CFG1_GLOB_TX_LANE0_POL_FLIP_OFFSET 4 +#define NVM_CFG1_GLOB_TX_LANE1_POL_FLIP_MASK 0x00000020 +#define NVM_CFG1_GLOB_TX_LANE1_POL_FLIP_OFFSET 5 +#define NVM_CFG1_GLOB_TX_LANE2_POL_FLIP_MASK 0x00000040 +#define NVM_CFG1_GLOB_TX_LANE2_POL_FLIP_OFFSET 6 +#define NVM_CFG1_GLOB_TX_LANE3_POL_FLIP_MASK 0x00000080 +#define NVM_CFG1_GLOB_TX_LANE3_POL_FLIP_OFFSET 7 +#define NVM_CFG1_GLOB_SMBUS_MODE_MASK 0x00000F00 +#define NVM_CFG1_GLOB_SMBUS_MODE_OFFSET 8 +#define NVM_CFG1_GLOB_SMBUS_MODE_DISABLED 0x0 +#define NVM_CFG1_GLOB_SMBUS_MODE_100KHZ 0x1 +#define NVM_CFG1_GLOB_SMBUS_MODE_400KHZ 0x2 +#define NVM_CFG1_GLOB_NCSI_MASK 0x0000F000 +#define NVM_CFG1_GLOB_NCSI_OFFSET 12 +#define NVM_CFG1_GLOB_NCSI_DISABLED 0x0 +#define NVM_CFG1_GLOB_NCSI_ENABLED 0x1 + + u32 f_lane_cfg1; /* 0x38 */ +#define NVM_CFG1_GLOB_RX_LANE0_SWAP_MASK 0x0000000F +#define NVM_CFG1_GLOB_RX_LANE0_SWAP_OFFSET 0 +#define NVM_CFG1_GLOB_RX_LANE1_SWAP_MASK 0x000000F0 +#define NVM_CFG1_GLOB_RX_LANE1_SWAP_OFFSET 4 +#define NVM_CFG1_GLOB_RX_LANE2_SWAP_MASK 0x00000F00 +#define NVM_CFG1_GLOB_RX_LANE2_SWAP_OFFSET 8 +#define NVM_CFG1_GLOB_RX_LANE3_SWAP_MASK 0x0000F000 +#define NVM_CFG1_GLOB_RX_LANE3_SWAP_OFFSET 12 +#define NVM_CFG1_GLOB_TX_LANE0_SWAP_MASK 0x000F0000 +#define NVM_CFG1_GLOB_TX_LANE0_SWAP_OFFSET 16 +#define NVM_CFG1_GLOB_TX_LANE1_SWAP_MASK 0x00F00000 +#define NVM_CFG1_GLOB_TX_LANE1_SWAP_OFFSET 20 +#define NVM_CFG1_GLOB_TX_LANE2_SWAP_MASK 0x0F000000 +#define NVM_CFG1_GLOB_TX_LANE2_SWAP_OFFSET 24 +#define NVM_CFG1_GLOB_TX_LANE3_SWAP_MASK 0xF0000000 +#define NVM_CFG1_GLOB_TX_LANE3_SWAP_OFFSET 28 + + u32 f_lane_cfg2; /* 0x3C */ +#define NVM_CFG1_GLOB_RX_LANE0_POL_FLIP_MASK 0x00000001 +#define NVM_CFG1_GLOB_RX_LANE0_POL_FLIP_OFFSET 0 +#define NVM_CFG1_GLOB_RX_LANE1_POL_FLIP_MASK 0x00000002 +#define NVM_CFG1_GLOB_RX_LANE1_POL_FLIP_OFFSET 1 +#define NVM_CFG1_GLOB_RX_LANE2_POL_FLIP_MASK 0x00000004 +#define NVM_CFG1_GLOB_RX_LANE2_POL_FLIP_OFFSET 2 +#define NVM_CFG1_GLOB_RX_LANE3_POL_FLIP_MASK 0x00000008 +#define NVM_CFG1_GLOB_RX_LANE3_POL_FLIP_OFFSET 3 +#define NVM_CFG1_GLOB_TX_LANE0_POL_FLIP_MASK 0x00000010 +#define NVM_CFG1_GLOB_TX_LANE0_POL_FLIP_OFFSET 4 +#define NVM_CFG1_GLOB_TX_LANE1_POL_FLIP_MASK 0x00000020 +#define NVM_CFG1_GLOB_TX_LANE1_POL_FLIP_OFFSET 5 +#define NVM_CFG1_GLOB_TX_LANE2_POL_FLIP_MASK 0x00000040 +#define NVM_CFG1_GLOB_TX_LANE2_POL_FLIP_OFFSET 6 +#define NVM_CFG1_GLOB_TX_LANE3_POL_FLIP_MASK 0x00000080 +#define NVM_CFG1_GLOB_TX_LANE3_POL_FLIP_OFFSET 7 + + u32 eagle_preemphasis; /* 0x40 */ +#define NVM_CFG1_GLOB_LANE0_PREEMP_MASK 0x000000FF +#define NVM_CFG1_GLOB_LANE0_PREEMP_OFFSET 0 +#define NVM_CFG1_GLOB_LANE1_PREEMP_MASK 0x0000FF00 +#define NVM_CFG1_GLOB_LANE1_PREEMP_OFFSET 8 +#define NVM_CFG1_GLOB_LANE2_PREEMP_MASK 0x00FF0000 +#define NVM_CFG1_GLOB_LANE2_PREEMP_OFFSET 16 +#define NVM_CFG1_GLOB_LANE3_PREEMP_MASK 0xFF000000 +#define NVM_CFG1_GLOB_LANE3_PREEMP_OFFSET 24 + + u32 eagle_driver_current; /* 0x44 */ +#define NVM_CFG1_GLOB_LANE0_AMP_MASK 0x000000FF +#define NVM_CFG1_GLOB_LANE0_AMP_OFFSET 0 +#define NVM_CFG1_GLOB_LANE1_AMP_MASK 0x0000FF00 +#define NVM_CFG1_GLOB_LANE1_AMP_OFFSET 8 +#define NVM_CFG1_GLOB_LANE2_AMP_MASK 0x00FF0000 +#define NVM_CFG1_GLOB_LANE2_AMP_OFFSET 16 +#define NVM_CFG1_GLOB_LANE3_AMP_MASK 0xFF000000 +#define NVM_CFG1_GLOB_LANE3_AMP_OFFSET 24 + + u32 falcon_preemphasis; /* 0x48 */ +#define NVM_CFG1_GLOB_LANE0_PREEMP_MASK 0x000000FF +#define NVM_CFG1_GLOB_LANE0_PREEMP_OFFSET 0 +#define NVM_CFG1_GLOB_LANE1_PREEMP_MASK 0x0000FF00 +#define NVM_CFG1_GLOB_LANE1_PREEMP_OFFSET 8 +#define NVM_CFG1_GLOB_LANE2_PREEMP_MASK 0x00FF0000 +#define NVM_CFG1_GLOB_LANE2_PREEMP_OFFSET 16 +#define NVM_CFG1_GLOB_LANE3_PREEMP_MASK 0xFF000000 +#define NVM_CFG1_GLOB_LANE3_PREEMP_OFFSET 24 + + u32 falcon_driver_current; /* 0x4C */ +#define NVM_CFG1_GLOB_LANE0_AMP_MASK 0x000000FF +#define NVM_CFG1_GLOB_LANE0_AMP_OFFSET 0 +#define NVM_CFG1_GLOB_LANE1_AMP_MASK 0x0000FF00 +#define NVM_CFG1_GLOB_LANE1_AMP_OFFSET 8 +#define NVM_CFG1_GLOB_LANE2_AMP_MASK 0x00FF0000 +#define NVM_CFG1_GLOB_LANE2_AMP_OFFSET 16 +#define NVM_CFG1_GLOB_LANE3_AMP_MASK 0xFF000000 +#define NVM_CFG1_GLOB_LANE3_AMP_OFFSET 24 + + u32 pci_id; /* 0x50 */ +#define NVM_CFG1_GLOB_VENDOR_ID_MASK 0x0000FFFF +#define NVM_CFG1_GLOB_VENDOR_ID_OFFSET 0 + + u32 pci_subsys_id; /* 0x54 */ +#define NVM_CFG1_GLOB_SUBSYSTEM_VENDOR_ID_MASK 0x0000FFFF +#define NVM_CFG1_GLOB_SUBSYSTEM_VENDOR_ID_OFFSET 0 +#define NVM_CFG1_GLOB_SUBSYSTEM_DEVICE_ID_MASK 0xFFFF0000 +#define NVM_CFG1_GLOB_SUBSYSTEM_DEVICE_ID_OFFSET 16 + + u32 bar; /* 0x58 */ +#define NVM_CFG1_GLOB_EXPANSION_ROM_SIZE_MASK 0x0000000F +#define NVM_CFG1_GLOB_EXPANSION_ROM_SIZE_OFFSET 0 +#define NVM_CFG1_GLOB_EXPANSION_ROM_SIZE_DISABLED 0x0 +#define NVM_CFG1_GLOB_EXPANSION_ROM_SIZE_2K 0x1 +#define NVM_CFG1_GLOB_EXPANSION_ROM_SIZE_4K 0x2 +#define NVM_CFG1_GLOB_EXPANSION_ROM_SIZE_8K 0x3 +#define NVM_CFG1_GLOB_EXPANSION_ROM_SIZE_16K 0x4 +#define NVM_CFG1_GLOB_EXPANSION_ROM_SIZE_32K 0x5 +#define NVM_CFG1_GLOB_EXPANSION_ROM_SIZE_64K 0x6 +#define NVM_CFG1_GLOB_EXPANSION_ROM_SIZE_128K 0x7 +#define NVM_CFG1_GLOB_EXPANSION_ROM_SIZE_256K 0x8 +#define NVM_CFG1_GLOB_EXPANSION_ROM_SIZE_512K 0x9 +#define NVM_CFG1_GLOB_EXPANSION_ROM_SIZE_1M 0xA +#define NVM_CFG1_GLOB_EXPANSION_ROM_SIZE_2M 0xB +#define NVM_CFG1_GLOB_EXPANSION_ROM_SIZE_4M 0xC +#define NVM_CFG1_GLOB_EXPANSION_ROM_SIZE_8M 0xD +#define NVM_CFG1_GLOB_EXPANSION_ROM_SIZE_16M 0xE +#define NVM_CFG1_GLOB_EXPANSION_ROM_SIZE_32M 0xF +#define NVM_CFG1_GLOB_VF_PCI_BAR2_SIZE_MASK 0x000000F0 +#define NVM_CFG1_GLOB_VF_PCI_BAR2_SIZE_OFFSET 4 +#define NVM_CFG1_GLOB_VF_PCI_BAR2_SIZE_DISABLED 0x0 +#define NVM_CFG1_GLOB_VF_PCI_BAR2_SIZE_4K 0x1 +#define NVM_CFG1_GLOB_VF_PCI_BAR2_SIZE_8K 0x2 +#define NVM_CFG1_GLOB_VF_PCI_BAR2_SIZE_16K 0x3 +#define NVM_CFG1_GLOB_VF_PCI_BAR2_SIZE_32K 0x4 +#define NVM_CFG1_GLOB_VF_PCI_BAR2_SIZE_64K 0x5 +#define NVM_CFG1_GLOB_VF_PCI_BAR2_SIZE_128K 0x6 +#define NVM_CFG1_GLOB_VF_PCI_BAR2_SIZE_256K 0x7 +#define NVM_CFG1_GLOB_VF_PCI_BAR2_SIZE_512K 0x8 +#define NVM_CFG1_GLOB_VF_PCI_BAR2_SIZE_1M 0x9 +#define NVM_CFG1_GLOB_VF_PCI_BAR2_SIZE_2M 0xA +#define NVM_CFG1_GLOB_VF_PCI_BAR2_SIZE_4M 0xB +#define NVM_CFG1_GLOB_VF_PCI_BAR2_SIZE_8M 0xC +#define NVM_CFG1_GLOB_VF_PCI_BAR2_SIZE_16M 0xD +#define NVM_CFG1_GLOB_VF_PCI_BAR2_SIZE_32M 0xE +#define NVM_CFG1_GLOB_VF_PCI_BAR2_SIZE_64M 0xF +#define NVM_CFG1_GLOB_BAR2_SIZE_MASK 0x00000F00 +#define NVM_CFG1_GLOB_BAR2_SIZE_OFFSET 8 +#define NVM_CFG1_GLOB_BAR2_SIZE_DISABLED 0x0 +#define NVM_CFG1_GLOB_BAR2_SIZE_64K 0x1 +#define NVM_CFG1_GLOB_BAR2_SIZE_128K 0x2 +#define NVM_CFG1_GLOB_BAR2_SIZE_256K 0x3 +#define NVM_CFG1_GLOB_BAR2_SIZE_512K 0x4 +#define NVM_CFG1_GLOB_BAR2_SIZE_1M 0x5 +#define NVM_CFG1_GLOB_BAR2_SIZE_2M 0x6 +#define NVM_CFG1_GLOB_BAR2_SIZE_4M 0x7 +#define NVM_CFG1_GLOB_BAR2_SIZE_8M 0x8 +#define NVM_CFG1_GLOB_BAR2_SIZE_16M 0x9 +#define NVM_CFG1_GLOB_BAR2_SIZE_32M 0xA +#define NVM_CFG1_GLOB_BAR2_SIZE_64M 0xB +#define NVM_CFG1_GLOB_BAR2_SIZE_128M 0xC +#define NVM_CFG1_GLOB_BAR2_SIZE_256M 0xD +#define NVM_CFG1_GLOB_BAR2_SIZE_512M 0xE +#define NVM_CFG1_GLOB_BAR2_SIZE_1G 0xF + + u32 eagle_txfir_main; /* 0x5C */ +#define NVM_CFG1_GLOB_LANE0_TXFIR_MAIN_MASK 0x000000FF +#define NVM_CFG1_GLOB_LANE0_TXFIR_MAIN_OFFSET 0 +#define NVM_CFG1_GLOB_LANE1_TXFIR_MAIN_MASK 0x0000FF00 +#define NVM_CFG1_GLOB_LANE1_TXFIR_MAIN_OFFSET 8 +#define NVM_CFG1_GLOB_LANE2_TXFIR_MAIN_MASK 0x00FF0000 +#define NVM_CFG1_GLOB_LANE2_TXFIR_MAIN_OFFSET 16 +#define NVM_CFG1_GLOB_LANE3_TXFIR_MAIN_MASK 0xFF000000 +#define NVM_CFG1_GLOB_LANE3_TXFIR_MAIN_OFFSET 24 + + u32 eagle_txfir_post; /* 0x60 */ +#define NVM_CFG1_GLOB_LANE0_TXFIR_POST_MASK 0x000000FF +#define NVM_CFG1_GLOB_LANE0_TXFIR_POST_OFFSET 0 +#define NVM_CFG1_GLOB_LANE1_TXFIR_POST_MASK 0x0000FF00 +#define NVM_CFG1_GLOB_LANE1_TXFIR_POST_OFFSET 8 +#define NVM_CFG1_GLOB_LANE2_TXFIR_POST_MASK 0x00FF0000 +#define NVM_CFG1_GLOB_LANE2_TXFIR_POST_OFFSET 16 +#define NVM_CFG1_GLOB_LANE3_TXFIR_POST_MASK 0xFF000000 +#define NVM_CFG1_GLOB_LANE3_TXFIR_POST_OFFSET 24 + + u32 falcon_txfir_main; /* 0x64 */ +#define NVM_CFG1_GLOB_LANE0_TXFIR_MAIN_MASK 0x000000FF +#define NVM_CFG1_GLOB_LANE0_TXFIR_MAIN_OFFSET 0 +#define NVM_CFG1_GLOB_LANE1_TXFIR_MAIN_MASK 0x0000FF00 +#define NVM_CFG1_GLOB_LANE1_TXFIR_MAIN_OFFSET 8 +#define NVM_CFG1_GLOB_LANE2_TXFIR_MAIN_MASK 0x00FF0000 +#define NVM_CFG1_GLOB_LANE2_TXFIR_MAIN_OFFSET 16 +#define NVM_CFG1_GLOB_LANE3_TXFIR_MAIN_MASK 0xFF000000 +#define NVM_CFG1_GLOB_LANE3_TXFIR_MAIN_OFFSET 24 + + u32 falcon_txfir_post; /* 0x68 */ +#define NVM_CFG1_GLOB_LANE0_TXFIR_POST_MASK 0x000000FF +#define NVM_CFG1_GLOB_LANE0_TXFIR_POST_OFFSET 0 +#define NVM_CFG1_GLOB_LANE1_TXFIR_POST_MASK 0x0000FF00 +#define NVM_CFG1_GLOB_LANE1_TXFIR_POST_OFFSET 8 +#define NVM_CFG1_GLOB_LANE2_TXFIR_POST_MASK 0x00FF0000 +#define NVM_CFG1_GLOB_LANE2_TXFIR_POST_OFFSET 16 +#define NVM_CFG1_GLOB_LANE3_TXFIR_POST_MASK 0xFF000000 +#define NVM_CFG1_GLOB_LANE3_TXFIR_POST_OFFSET 24 + + u32 manufacture_ver; /* 0x6C */ +#define NVM_CFG1_GLOB_MANUF0_VER_MASK 0x0000003F +#define NVM_CFG1_GLOB_MANUF0_VER_OFFSET 0 +#define NVM_CFG1_GLOB_MANUF1_VER_MASK 0x00000FC0 +#define NVM_CFG1_GLOB_MANUF1_VER_OFFSET 6 +#define NVM_CFG1_GLOB_MANUF2_VER_MASK 0x0003F000 +#define NVM_CFG1_GLOB_MANUF2_VER_OFFSET 12 +#define NVM_CFG1_GLOB_MANUF3_VER_MASK 0x00FC0000 +#define NVM_CFG1_GLOB_MANUF3_VER_OFFSET 18 +#define NVM_CFG1_GLOB_MANUF4_VER_MASK 0x3F000000 +#define NVM_CFG1_GLOB_MANUF4_VER_OFFSET 24 + + u32 manufacture_time; /* 0x70 */ +#define NVM_CFG1_GLOB_MANUF0_TIME_MASK 0x0000003F +#define NVM_CFG1_GLOB_MANUF0_TIME_OFFSET 0 +#define NVM_CFG1_GLOB_MANUF1_TIME_MASK 0x00000FC0 +#define NVM_CFG1_GLOB_MANUF1_TIME_OFFSET 6 +#define NVM_CFG1_GLOB_MANUF2_TIME_MASK 0x0003F000 +#define NVM_CFG1_GLOB_MANUF2_TIME_OFFSET 12 + + u32 led_global_settings; /* 0x74 */ +#define NVM_CFG1_GLOB_LED_SWAP_0_MASK 0x0000000F +#define NVM_CFG1_GLOB_LED_SWAP_0_OFFSET 0 +#define NVM_CFG1_GLOB_LED_SWAP_1_MASK 0x000000F0 +#define NVM_CFG1_GLOB_LED_SWAP_1_OFFSET 4 +#define NVM_CFG1_GLOB_LED_SWAP_2_MASK 0x00000F00 +#define NVM_CFG1_GLOB_LED_SWAP_2_OFFSET 8 +#define NVM_CFG1_GLOB_LED_SWAP_3_MASK 0x0000F000 +#define NVM_CFG1_GLOB_LED_SWAP_3_OFFSET 12 + + u32 generic_cont1; /* 0x78 */ +#define NVM_CFG1_GLOB_AVS_DAC_CODE_MASK 0x000003FF +#define NVM_CFG1_GLOB_AVS_DAC_CODE_OFFSET 0 + + u32 mbi_version; /* 0x7C */ +#define NVM_CFG1_GLOB_MBI_VERSION_0_MASK 0x000000FF +#define NVM_CFG1_GLOB_MBI_VERSION_0_OFFSET 0 +#define NVM_CFG1_GLOB_MBI_VERSION_1_MASK 0x0000FF00 +#define NVM_CFG1_GLOB_MBI_VERSION_1_OFFSET 8 +#define NVM_CFG1_GLOB_MBI_VERSION_2_MASK 0x00FF0000 +#define NVM_CFG1_GLOB_MBI_VERSION_2_OFFSET 16 + + u32 mbi_date; /* 0x80 */ + + u32 misc_sig; /* 0x84 */ + + /* Define the GPIO mapping to switch i2c mux */ +#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO_0_MASK 0x000000FF +#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO_0_OFFSET 0 +#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO_1_MASK 0x0000FF00 +#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO_1_OFFSET 8 +#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__NA 0x0 +#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO0 0x1 +#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO1 0x2 +#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO2 0x3 +#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO3 0x4 +#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO4 0x5 +#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO5 0x6 +#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO6 0x7 +#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO7 0x8 +#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO8 0x9 +#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO9 0xA +#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO10 0xB +#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO11 0xC +#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO12 0xD +#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO13 0xE +#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO14 0xF +#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO15 0x10 +#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO16 0x11 +#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO17 0x12 +#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO18 0x13 +#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO19 0x14 +#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO20 0x15 +#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO21 0x16 +#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO22 0x17 +#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO23 0x18 +#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO24 0x19 +#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO25 0x1A +#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO26 0x1B +#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO27 0x1C +#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO28 0x1D +#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO29 0x1E +#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO30 0x1F +#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO31 0x20 + + u32 reserved[46]; /* 0x88 */ +}; + +struct nvm_cfg1_path { + u32 reserved[30]; /* 0x0 */ +}; + +struct nvm_cfg1_port { + u32 power_dissipated; /* 0x0 */ +#define NVM_CFG1_PORT_POWER_DIS_D0_MASK 0x000000FF +#define NVM_CFG1_PORT_POWER_DIS_D0_OFFSET 0 +#define NVM_CFG1_PORT_POWER_DIS_D1_MASK 0x0000FF00 +#define NVM_CFG1_PORT_POWER_DIS_D1_OFFSET 8 +#define NVM_CFG1_PORT_POWER_DIS_D2_MASK 0x00FF0000 +#define NVM_CFG1_PORT_POWER_DIS_D2_OFFSET 16 +#define NVM_CFG1_PORT_POWER_DIS_D3_MASK 0xFF000000 +#define NVM_CFG1_PORT_POWER_DIS_D3_OFFSET 24 + + u32 power_consumed; /* 0x4 */ +#define NVM_CFG1_PORT_POWER_CONS_D0_MASK 0x000000FF +#define NVM_CFG1_PORT_POWER_CONS_D0_OFFSET 0 +#define NVM_CFG1_PORT_POWER_CONS_D1_MASK 0x0000FF00 +#define NVM_CFG1_PORT_POWER_CONS_D1_OFFSET 8 +#define NVM_CFG1_PORT_POWER_CONS_D2_MASK 0x00FF0000 +#define NVM_CFG1_PORT_POWER_CONS_D2_OFFSET 16 +#define NVM_CFG1_PORT_POWER_CONS_D3_MASK 0xFF000000 +#define NVM_CFG1_PORT_POWER_CONS_D3_OFFSET 24 + + u32 generic_cont0; /* 0x8 */ +#define NVM_CFG1_PORT_LED_MODE_MASK 0x000000FF +#define NVM_CFG1_PORT_LED_MODE_OFFSET 0 +#define NVM_CFG1_PORT_LED_MODE_MAC1 0x0 +#define NVM_CFG1_PORT_LED_MODE_PHY1 0x1 +#define NVM_CFG1_PORT_LED_MODE_PHY2 0x2 +#define NVM_CFG1_PORT_LED_MODE_PHY3 0x3 +#define NVM_CFG1_PORT_LED_MODE_MAC2 0x4 +#define NVM_CFG1_PORT_LED_MODE_PHY4 0x5 +#define NVM_CFG1_PORT_LED_MODE_PHY5 0x6 +#define NVM_CFG1_PORT_LED_MODE_PHY6 0x7 +#define NVM_CFG1_PORT_LED_MODE_MAC3 0x8 +#define NVM_CFG1_PORT_LED_MODE_PHY7 0x9 +#define NVM_CFG1_PORT_LED_MODE_PHY8 0xA +#define NVM_CFG1_PORT_LED_MODE_PHY9 0xB +#define NVM_CFG1_PORT_LED_MODE_MAC4 0xC +#define NVM_CFG1_PORT_LED_MODE_PHY10 0xD +#define NVM_CFG1_PORT_LED_MODE_PHY11 0xE +#define NVM_CFG1_PORT_LED_MODE_PHY12 0xF +#define NVM_CFG1_PORT_ROCE_PRIORITY_MASK 0x0000FF00 +#define NVM_CFG1_PORT_ROCE_PRIORITY_OFFSET 8 +#define NVM_CFG1_PORT_DCBX_MODE_MASK 0x000F0000 +#define NVM_CFG1_PORT_DCBX_MODE_OFFSET 16 +#define NVM_CFG1_PORT_DCBX_MODE_DISABLED 0x0 +#define NVM_CFG1_PORT_DCBX_MODE_IEEE 0x1 +#define NVM_CFG1_PORT_DCBX_MODE_CEE 0x2 +#define NVM_CFG1_PORT_DCBX_MODE_DYNAMIC 0x3 + + u32 pcie_cfg; /* 0xC */ +#define NVM_CFG1_PORT_RESERVED15_MASK 0x00000007 +#define NVM_CFG1_PORT_RESERVED15_OFFSET 0 + + u32 features; /* 0x10 */ +#define NVM_CFG1_PORT_ENABLE_WOL_ON_ACPI_PATTERN_MASK 0x00000001 +#define NVM_CFG1_PORT_ENABLE_WOL_ON_ACPI_PATTERN_OFFSET 0 +#define NVM_CFG1_PORT_ENABLE_WOL_ON_ACPI_PATTERN_DISABLED 0x0 +#define NVM_CFG1_PORT_ENABLE_WOL_ON_ACPI_PATTERN_ENABLED 0x1 +#define NVM_CFG1_PORT_MAGIC_PACKET_WOL_MASK 0x00000002 +#define NVM_CFG1_PORT_MAGIC_PACKET_WOL_OFFSET 1 +#define NVM_CFG1_PORT_MAGIC_PACKET_WOL_DISABLED 0x0 +#define NVM_CFG1_PORT_MAGIC_PACKET_WOL_ENABLED 0x1 + + u32 speed_cap_mask; /* 0x14 */ +#define NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_MASK 0x0000FFFF +#define NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_OFFSET 0 +#define NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G 0x1 +#define NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G 0x2 +#define NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G 0x8 +#define NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G 0x10 +#define NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G 0x20 +#define NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_100G 0x40 +#define NVM_CFG1_PORT_MFW_SPEED_CAPABILITY_MASK_MASK 0xFFFF0000 +#define NVM_CFG1_PORT_MFW_SPEED_CAPABILITY_MASK_OFFSET 16 +#define NVM_CFG1_PORT_MFW_SPEED_CAPABILITY_MASK_1G 0x1 +#define NVM_CFG1_PORT_MFW_SPEED_CAPABILITY_MASK_10G 0x2 +#define NVM_CFG1_PORT_MFW_SPEED_CAPABILITY_MASK_25G 0x8 +#define NVM_CFG1_PORT_MFW_SPEED_CAPABILITY_MASK_40G 0x10 +#define NVM_CFG1_PORT_MFW_SPEED_CAPABILITY_MASK_50G 0x20 +#define NVM_CFG1_PORT_MFW_SPEED_CAPABILITY_MASK_100G 0x40 + + u32 link_settings; /* 0x18 */ +#define NVM_CFG1_PORT_DRV_LINK_SPEED_MASK 0x0000000F +#define NVM_CFG1_PORT_DRV_LINK_SPEED_OFFSET 0 +#define NVM_CFG1_PORT_DRV_LINK_SPEED_AUTONEG 0x0 +#define NVM_CFG1_PORT_DRV_LINK_SPEED_1G 0x1 +#define NVM_CFG1_PORT_DRV_LINK_SPEED_10G 0x2 +#define NVM_CFG1_PORT_DRV_LINK_SPEED_25G 0x4 +#define NVM_CFG1_PORT_DRV_LINK_SPEED_40G 0x5 +#define NVM_CFG1_PORT_DRV_LINK_SPEED_50G 0x6 +#define NVM_CFG1_PORT_DRV_LINK_SPEED_100G 0x7 +#define NVM_CFG1_PORT_DRV_FLOW_CONTROL_MASK 0x00000070 +#define NVM_CFG1_PORT_DRV_FLOW_CONTROL_OFFSET 4 +#define NVM_CFG1_PORT_DRV_FLOW_CONTROL_AUTONEG 0x1 +#define NVM_CFG1_PORT_DRV_FLOW_CONTROL_RX 0x2 +#define NVM_CFG1_PORT_DRV_FLOW_CONTROL_TX 0x4 +#define NVM_CFG1_PORT_MFW_LINK_SPEED_MASK 0x00000780 +#define NVM_CFG1_PORT_MFW_LINK_SPEED_OFFSET 7 +#define NVM_CFG1_PORT_MFW_LINK_SPEED_AUTONEG 0x0 +#define NVM_CFG1_PORT_MFW_LINK_SPEED_1G 0x1 +#define NVM_CFG1_PORT_MFW_LINK_SPEED_10G 0x2 +#define NVM_CFG1_PORT_MFW_LINK_SPEED_25G 0x4 +#define NVM_CFG1_PORT_MFW_LINK_SPEED_40G 0x5 +#define NVM_CFG1_PORT_MFW_LINK_SPEED_50G 0x6 +#define NVM_CFG1_PORT_MFW_LINK_SPEED_100G 0x7 +#define NVM_CFG1_PORT_MFW_FLOW_CONTROL_MASK 0x00003800 +#define NVM_CFG1_PORT_MFW_FLOW_CONTROL_OFFSET 11 +#define NVM_CFG1_PORT_MFW_FLOW_CONTROL_AUTONEG 0x1 +#define NVM_CFG1_PORT_MFW_FLOW_CONTROL_RX 0x2 +#define NVM_CFG1_PORT_MFW_FLOW_CONTROL_TX 0x4 +#define NVM_CFG1_PORT_OPTIC_MODULE_VENDOR_ENFORCEMENT_MASK 0x00004000 +#define NVM_CFG1_PORT_OPTIC_MODULE_VENDOR_ENFORCEMENT_OFFSET 14 +#define NVM_CFG1_PORT_OPTIC_MODULE_VENDOR_ENFORCEMENT_DISABLED 0x0 +#define NVM_CFG1_PORT_OPTIC_MODULE_VENDOR_ENFORCEMENT_ENABLED 0x1 + + u32 phy_cfg; /* 0x1C */ +#define NVM_CFG1_PORT_OPTIONAL_LINK_MODES_MASK 0x0000FFFF +#define NVM_CFG1_PORT_OPTIONAL_LINK_MODES_OFFSET 0 +#define NVM_CFG1_PORT_OPTIONAL_LINK_MODES_HIGIG 0x1 +#define NVM_CFG1_PORT_OPTIONAL_LINK_MODES_SCRAMBLER 0x2 +#define NVM_CFG1_PORT_OPTIONAL_LINK_MODES_FIBER 0x4 +#define NVM_CFG1_PORT_OPTIONAL_LINK_MODES_DISABLE_CL72_AN 0x8 +#define NVM_CFG1_PORT_OPTIONAL_LINK_MODES_DISABLE_FEC_AN 0x10 +#define NVM_CFG1_PORT_SERDES_NET_INTERFACE_MASK 0x00FF0000 +#define NVM_CFG1_PORT_SERDES_NET_INTERFACE_OFFSET 16 +#define NVM_CFG1_PORT_SERDES_NET_INTERFACE_BYPASS 0x0 +#define NVM_CFG1_PORT_SERDES_NET_INTERFACE_KR 0x2 +#define NVM_CFG1_PORT_SERDES_NET_INTERFACE_KR2 0x3 +#define NVM_CFG1_PORT_SERDES_NET_INTERFACE_KR4 0x4 +#define NVM_CFG1_PORT_SERDES_NET_INTERFACE_XFI 0x8 +#define NVM_CFG1_PORT_SERDES_NET_INTERFACE_SFI 0x9 +#define NVM_CFG1_PORT_SERDES_NET_INTERFACE_1000X 0xB +#define NVM_CFG1_PORT_SERDES_NET_INTERFACE_SGMII 0xC +#define NVM_CFG1_PORT_SERDES_NET_INTERFACE_XLAUI 0xD +#define NVM_CFG1_PORT_SERDES_NET_INTERFACE_CAUI 0xE +#define NVM_CFG1_PORT_SERDES_NET_INTERFACE_XLPPI 0xF +#define NVM_CFG1_PORT_SERDES_NET_INTERFACE_CPPI 0x10 +#define NVM_CFG1_PORT_AN_MODE_MASK 0xFF000000 +#define NVM_CFG1_PORT_AN_MODE_OFFSET 24 +#define NVM_CFG1_PORT_AN_MODE_NONE 0x0 +#define NVM_CFG1_PORT_AN_MODE_CL73 0x1 +#define NVM_CFG1_PORT_AN_MODE_CL37 0x2 +#define NVM_CFG1_PORT_AN_MODE_CL73_BAM 0x3 +#define NVM_CFG1_PORT_AN_MODE_CL37_BAM 0x4 +#define NVM_CFG1_PORT_AN_MODE_HPAM 0x5 +#define NVM_CFG1_PORT_AN_MODE_SGMII 0x6 + + u32 mgmt_traffic; /* 0x20 */ +#define NVM_CFG1_PORT_RESERVED61_MASK 0x0000000F +#define NVM_CFG1_PORT_RESERVED61_OFFSET 0 +#define NVM_CFG1_PORT_RESERVED61_DISABLED 0x0 +#define NVM_CFG1_PORT_RESERVED61_NCSI_OVER_RMII 0x1 +#define NVM_CFG1_PORT_RESERVED61_NCSI_OVER_SMBUS 0x2 + + u32 ext_phy; /* 0x24 */ +#define NVM_CFG1_PORT_EXTERNAL_PHY_TYPE_MASK 0x000000FF +#define NVM_CFG1_PORT_EXTERNAL_PHY_TYPE_OFFSET 0 +#define NVM_CFG1_PORT_EXTERNAL_PHY_TYPE_NONE 0x0 +#define NVM_CFG1_PORT_EXTERNAL_PHY_TYPE_BCM84844 0x1 +#define NVM_CFG1_PORT_EXTERNAL_PHY_ADDRESS_MASK 0x0000FF00 +#define NVM_CFG1_PORT_EXTERNAL_PHY_ADDRESS_OFFSET 8 + + u32 mba_cfg1; /* 0x28 */ +#define NVM_CFG1_PORT_MBA_MASK 0x00000001 +#define NVM_CFG1_PORT_MBA_OFFSET 0 +#define NVM_CFG1_PORT_MBA_DISABLED 0x0 +#define NVM_CFG1_PORT_MBA_ENABLED 0x1 +#define NVM_CFG1_PORT_MBA_BOOT_TYPE_MASK 0x00000006 +#define NVM_CFG1_PORT_MBA_BOOT_TYPE_OFFSET 1 +#define NVM_CFG1_PORT_MBA_BOOT_TYPE_AUTO 0x0 +#define NVM_CFG1_PORT_MBA_BOOT_TYPE_BBS 0x1 +#define NVM_CFG1_PORT_MBA_BOOT_TYPE_INT18H 0x2 +#define NVM_CFG1_PORT_MBA_BOOT_TYPE_INT19H 0x3 +#define NVM_CFG1_PORT_MBA_DELAY_TIME_MASK 0x00000078 +#define NVM_CFG1_PORT_MBA_DELAY_TIME_OFFSET 3 +#define NVM_CFG1_PORT_MBA_SETUP_HOT_KEY_MASK 0x00000080 +#define NVM_CFG1_PORT_MBA_SETUP_HOT_KEY_OFFSET 7 +#define NVM_CFG1_PORT_MBA_SETUP_HOT_KEY_CTRL_S 0x0 +#define NVM_CFG1_PORT_MBA_SETUP_HOT_KEY_CTRL_B 0x1 +#define NVM_CFG1_PORT_MBA_HIDE_SETUP_PROMPT_MASK 0x00000100 +#define NVM_CFG1_PORT_MBA_HIDE_SETUP_PROMPT_OFFSET 8 +#define NVM_CFG1_PORT_MBA_HIDE_SETUP_PROMPT_DISABLED 0x0 +#define NVM_CFG1_PORT_MBA_HIDE_SETUP_PROMPT_ENABLED 0x1 +#define NVM_CFG1_PORT_RESERVED5_MASK 0x0001FE00 +#define NVM_CFG1_PORT_RESERVED5_OFFSET 9 +#define NVM_CFG1_PORT_RESERVED5_DISABLED 0x0 +#define NVM_CFG1_PORT_RESERVED5_2K 0x1 +#define NVM_CFG1_PORT_RESERVED5_4K 0x2 +#define NVM_CFG1_PORT_RESERVED5_8K 0x3 +#define NVM_CFG1_PORT_RESERVED5_16K 0x4 +#define NVM_CFG1_PORT_RESERVED5_32K 0x5 +#define NVM_CFG1_PORT_RESERVED5_64K 0x6 +#define NVM_CFG1_PORT_RESERVED5_128K 0x7 +#define NVM_CFG1_PORT_RESERVED5_256K 0x8 +#define NVM_CFG1_PORT_RESERVED5_512K 0x9 +#define NVM_CFG1_PORT_RESERVED5_1M 0xA +#define NVM_CFG1_PORT_RESERVED5_2M 0xB +#define NVM_CFG1_PORT_RESERVED5_4M 0xC +#define NVM_CFG1_PORT_RESERVED5_8M 0xD +#define NVM_CFG1_PORT_RESERVED5_16M 0xE +#define NVM_CFG1_PORT_RESERVED5_32M 0xF +#define NVM_CFG1_PORT_MBA_LINK_SPEED_MASK 0x001E0000 +#define NVM_CFG1_PORT_MBA_LINK_SPEED_OFFSET 17 +#define NVM_CFG1_PORT_MBA_LINK_SPEED_AUTONEG 0x0 +#define NVM_CFG1_PORT_MBA_LINK_SPEED_1G 0x1 +#define NVM_CFG1_PORT_MBA_LINK_SPEED_10G 0x2 +#define NVM_CFG1_PORT_MBA_LINK_SPEED_25G 0x4 +#define NVM_CFG1_PORT_MBA_LINK_SPEED_40G 0x5 +#define NVM_CFG1_PORT_MBA_LINK_SPEED_50G 0x6 +#define NVM_CFG1_PORT_MBA_LINK_SPEED_100G 0x7 +#define NVM_CFG1_PORT_MBA_BOOT_RETRY_COUNT_MASK 0x00E00000 +#define NVM_CFG1_PORT_MBA_BOOT_RETRY_COUNT_OFFSET 21 + + u32 mba_cfg2; /* 0x2C */ +#define NVM_CFG1_PORT_MBA_VLAN_VALUE_MASK 0x0000FFFF +#define NVM_CFG1_PORT_MBA_VLAN_VALUE_OFFSET 0 +#define NVM_CFG1_PORT_MBA_VLAN_MASK 0x00010000 +#define NVM_CFG1_PORT_MBA_VLAN_OFFSET 16 + + u32 vf_cfg; /* 0x30 */ +#define NVM_CFG1_PORT_RESERVED8_MASK 0x0000FFFF +#define NVM_CFG1_PORT_RESERVED8_OFFSET 0 +#define NVM_CFG1_PORT_RESERVED6_MASK 0x000F0000 +#define NVM_CFG1_PORT_RESERVED6_OFFSET 16 +#define NVM_CFG1_PORT_RESERVED6_DISABLED 0x0 +#define NVM_CFG1_PORT_RESERVED6_4K 0x1 +#define NVM_CFG1_PORT_RESERVED6_8K 0x2 +#define NVM_CFG1_PORT_RESERVED6_16K 0x3 +#define NVM_CFG1_PORT_RESERVED6_32K 0x4 +#define NVM_CFG1_PORT_RESERVED6_64K 0x5 +#define NVM_CFG1_PORT_RESERVED6_128K 0x6 +#define NVM_CFG1_PORT_RESERVED6_256K 0x7 +#define NVM_CFG1_PORT_RESERVED6_512K 0x8 +#define NVM_CFG1_PORT_RESERVED6_1M 0x9 +#define NVM_CFG1_PORT_RESERVED6_2M 0xA +#define NVM_CFG1_PORT_RESERVED6_4M 0xB +#define NVM_CFG1_PORT_RESERVED6_8M 0xC +#define NVM_CFG1_PORT_RESERVED6_16M 0xD +#define NVM_CFG1_PORT_RESERVED6_32M 0xE +#define NVM_CFG1_PORT_RESERVED6_64M 0xF + + struct nvm_cfg_mac_address lldp_mac_address; /* 0x34 */ + + u32 led_port_settings; /* 0x3C */ +#define NVM_CFG1_PORT_LANE_LED_SPD_0_SEL_MASK 0x000000FF +#define NVM_CFG1_PORT_LANE_LED_SPD_0_SEL_OFFSET 0 +#define NVM_CFG1_PORT_LANE_LED_SPD_1_SEL_MASK 0x0000FF00 +#define NVM_CFG1_PORT_LANE_LED_SPD_1_SEL_OFFSET 8 +#define NVM_CFG1_PORT_LANE_LED_SPD_2_SEL_MASK 0x00FF0000 +#define NVM_CFG1_PORT_LANE_LED_SPD_2_SEL_OFFSET 16 +#define NVM_CFG1_PORT_LANE_LED_SPD__SEL_1G 0x1 +#define NVM_CFG1_PORT_LANE_LED_SPD__SEL_10G 0x2 +#define NVM_CFG1_PORT_LANE_LED_SPD__SEL_25G 0x8 +#define NVM_CFG1_PORT_LANE_LED_SPD__SEL_40G 0x10 +#define NVM_CFG1_PORT_LANE_LED_SPD__SEL_50G 0x20 +#define NVM_CFG1_PORT_LANE_LED_SPD__SEL_100G 0x40 + + u32 transceiver_00; /* 0x40 */ + + /* Define for mapping of transceiver signal module absent */ +#define NVM_CFG1_PORT_TRANS_MODULE_ABS_MASK 0x000000FF +#define NVM_CFG1_PORT_TRANS_MODULE_ABS_OFFSET 0 +#define NVM_CFG1_PORT_TRANS_MODULE_ABS_NA 0x0 +#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO0 0x1 +#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO1 0x2 +#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO2 0x3 +#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO3 0x4 +#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO4 0x5 +#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO5 0x6 +#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO6 0x7 +#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO7 0x8 +#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO8 0x9 +#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO9 0xA +#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO10 0xB +#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO11 0xC +#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO12 0xD +#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO13 0xE +#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO14 0xF +#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO15 0x10 +#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO16 0x11 +#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO17 0x12 +#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO18 0x13 +#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO19 0x14 +#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO20 0x15 +#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO21 0x16 +#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO22 0x17 +#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO23 0x18 +#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO24 0x19 +#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO25 0x1A +#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO26 0x1B +#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO27 0x1C +#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO28 0x1D +#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO29 0x1E +#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO30 0x1F +#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO31 0x20 + /* Define the GPIO mux settings to switch i2c mux to this port */ +#define NVM_CFG1_PORT_I2C_MUX_SEL_VALUE_0_MASK 0x00000F00 +#define NVM_CFG1_PORT_I2C_MUX_SEL_VALUE_0_OFFSET 8 +#define NVM_CFG1_PORT_I2C_MUX_SEL_VALUE_1_MASK 0x0000F000 +#define NVM_CFG1_PORT_I2C_MUX_SEL_VALUE_1_OFFSET 12 + + u32 reserved[133]; /* 0x44 */ +}; + +struct nvm_cfg1_func { + struct nvm_cfg_mac_address mac_address; /* 0x0 */ + + u32 rsrv1; /* 0x8 */ +#define NVM_CFG1_FUNC_RESERVED1_MASK 0x0000FFFF +#define NVM_CFG1_FUNC_RESERVED1_OFFSET 0 +#define NVM_CFG1_FUNC_RESERVED2_MASK 0xFFFF0000 +#define NVM_CFG1_FUNC_RESERVED2_OFFSET 16 + + u32 rsrv2; /* 0xC */ +#define NVM_CFG1_FUNC_RESERVED3_MASK 0x0000FFFF +#define NVM_CFG1_FUNC_RESERVED3_OFFSET 0 +#define NVM_CFG1_FUNC_RESERVED4_MASK 0xFFFF0000 +#define NVM_CFG1_FUNC_RESERVED4_OFFSET 16 + + u32 device_id; /* 0x10 */ +#define NVM_CFG1_FUNC_MF_VENDOR_DEVICE_ID_MASK 0x0000FFFF +#define NVM_CFG1_FUNC_MF_VENDOR_DEVICE_ID_OFFSET 0 +#define NVM_CFG1_FUNC_VENDOR_DEVICE_ID_MASK 0xFFFF0000 +#define NVM_CFG1_FUNC_VENDOR_DEVICE_ID_OFFSET 16 + + u32 cmn_cfg; /* 0x14 */ +#define NVM_CFG1_FUNC_MBA_BOOT_PROTOCOL_MASK 0x00000007 +#define NVM_CFG1_FUNC_MBA_BOOT_PROTOCOL_OFFSET 0 +#define NVM_CFG1_FUNC_MBA_BOOT_PROTOCOL_PXE 0x0 +#define NVM_CFG1_FUNC_MBA_BOOT_PROTOCOL_RPL 0x1 +#define NVM_CFG1_FUNC_MBA_BOOT_PROTOCOL_BOOTP 0x2 +#define NVM_CFG1_FUNC_MBA_BOOT_PROTOCOL_ISCSI_BOOT 0x3 +#define NVM_CFG1_FUNC_MBA_BOOT_PROTOCOL_FCOE_BOOT 0x4 +#define NVM_CFG1_FUNC_MBA_BOOT_PROTOCOL_NONE 0x7 +#define NVM_CFG1_FUNC_VF_PCI_DEVICE_ID_MASK 0x0007FFF8 +#define NVM_CFG1_FUNC_VF_PCI_DEVICE_ID_OFFSET 3 +#define NVM_CFG1_FUNC_PERSONALITY_MASK 0x00780000 +#define NVM_CFG1_FUNC_PERSONALITY_OFFSET 19 +#define NVM_CFG1_FUNC_PERSONALITY_ETHERNET 0x0 +#define NVM_CFG1_FUNC_PERSONALITY_ISCSI 0x1 +#define NVM_CFG1_FUNC_PERSONALITY_FCOE 0x2 +#define NVM_CFG1_FUNC_PERSONALITY_ROCE 0x3 +#define NVM_CFG1_FUNC_BANDWIDTH_WEIGHT_MASK 0x7F800000 +#define NVM_CFG1_FUNC_BANDWIDTH_WEIGHT_OFFSET 23 +#define NVM_CFG1_FUNC_PAUSE_ON_HOST_RING_MASK 0x80000000 +#define NVM_CFG1_FUNC_PAUSE_ON_HOST_RING_OFFSET 31 +#define NVM_CFG1_FUNC_PAUSE_ON_HOST_RING_DISABLED 0x0 +#define NVM_CFG1_FUNC_PAUSE_ON_HOST_RING_ENABLED 0x1 + + u32 pci_cfg; /* 0x18 */ +#define NVM_CFG1_FUNC_NUMBER_OF_VFS_PER_PF_MASK 0x0000007F +#define NVM_CFG1_FUNC_NUMBER_OF_VFS_PER_PF_OFFSET 0 +#define NVM_CFG1_FUNC_RESERVESD12_MASK 0x00003F80 +#define NVM_CFG1_FUNC_RESERVESD12_OFFSET 7 +#define NVM_CFG1_FUNC_BAR1_SIZE_MASK 0x0003C000 +#define NVM_CFG1_FUNC_BAR1_SIZE_OFFSET 14 +#define NVM_CFG1_FUNC_BAR1_SIZE_DISABLED 0x0 +#define NVM_CFG1_FUNC_BAR1_SIZE_64K 0x1 +#define NVM_CFG1_FUNC_BAR1_SIZE_128K 0x2 +#define NVM_CFG1_FUNC_BAR1_SIZE_256K 0x3 +#define NVM_CFG1_FUNC_BAR1_SIZE_512K 0x4 +#define NVM_CFG1_FUNC_BAR1_SIZE_1M 0x5 +#define NVM_CFG1_FUNC_BAR1_SIZE_2M 0x6 +#define NVM_CFG1_FUNC_BAR1_SIZE_4M 0x7 +#define NVM_CFG1_FUNC_BAR1_SIZE_8M 0x8 +#define NVM_CFG1_FUNC_BAR1_SIZE_16M 0x9 +#define NVM_CFG1_FUNC_BAR1_SIZE_32M 0xA +#define NVM_CFG1_FUNC_BAR1_SIZE_64M 0xB +#define NVM_CFG1_FUNC_BAR1_SIZE_128M 0xC +#define NVM_CFG1_FUNC_BAR1_SIZE_256M 0xD +#define NVM_CFG1_FUNC_BAR1_SIZE_512M 0xE +#define NVM_CFG1_FUNC_BAR1_SIZE_1G 0xF +#define NVM_CFG1_FUNC_MAX_BANDWIDTH_MASK 0x03FC0000 +#define NVM_CFG1_FUNC_MAX_BANDWIDTH_OFFSET 18 + + struct nvm_cfg_mac_address fcoe_node_wwn_mac_addr; /* 0x1C */ + + struct nvm_cfg_mac_address fcoe_port_wwn_mac_addr; /* 0x24 */ + + u32 reserved[9]; /* 0x2C */ +}; + +struct nvm_cfg1 { + struct nvm_cfg1_glob glob; /* 0x0 */ + + struct nvm_cfg1_path path[MCP_GLOB_PATH_MAX]; /* 0x140 */ + + struct nvm_cfg1_port port[MCP_GLOB_PORT_MAX]; /* 0x230 */ + + struct nvm_cfg1_func func[MCP_GLOB_FUNC_MAX]; /* 0xB90 */ +}; + +/****************************************** +* nvm_cfg structs +******************************************/ + +enum nvm_cfg_sections { + NVM_CFG_SECTION_NVM_CFG1, + NVM_CFG_SECTION_MAX +}; + +struct nvm_cfg { + u32 num_sections; + u32 sections_offset[NVM_CFG_SECTION_MAX]; + struct nvm_cfg1 cfg1; +}; + +#define PORT_0 0 +#define PORT_1 1 +#define PORT_2 2 +#define PORT_3 3 + +extern struct spad_layout g_spad; + +#define MCP_SPAD_SIZE 0x00028000 /* 160 KB */ + +#define SPAD_OFFSET(addr) (((u32)addr - (u32)CPU_SPAD_BASE)) + +#define TO_OFFSIZE(_offset, _size) \ + (u32)((((u32)(_offset) >> 2) << OFFSIZE_OFFSET_SHIFT) | \ + (((u32)(_size) >> 2) << OFFSIZE_SIZE_SHIFT)) + +enum spad_sections { + SPAD_SECTION_TRACE, + SPAD_SECTION_NVM_CFG, + SPAD_SECTION_PUBLIC, + SPAD_SECTION_PRIVATE, + SPAD_SECTION_MAX +}; + +struct spad_layout { + struct nvm_cfg nvm_cfg; + struct mcp_public_data public_data; +}; + +#define CRC_MAGIC_VALUE 0xDEBB20E3 +#define CRC32_POLYNOMIAL 0xEDB88320 +#define NVM_CRC_SIZE (sizeof(u32)) + +enum nvm_sw_arbitrator { + NVM_SW_ARB_HOST, + NVM_SW_ARB_MCP, + NVM_SW_ARB_UART, + NVM_SW_ARB_RESERVED +}; + +/**************************************************************************** +* Boot Strap Region * +****************************************************************************/ +struct legacy_bootstrap_region { + u32 magic_value; +#define NVM_MAGIC_VALUE 0x669955aa + u32 sram_start_addr; + u32 code_len; /* boot code length (in dwords) */ + u32 code_start_addr; + u32 crc; /* 32-bit CRC */ +}; + +/**************************************************************************** +* Directories Region * +****************************************************************************/ +struct nvm_code_entry { + u32 image_type; /* Image type */ + u32 nvm_start_addr; /* NVM address of the image */ + u32 len; /* Include CRC */ + u32 sram_start_addr; + u32 sram_run_addr; /* Relevant in case of MIM only */ +}; + +enum nvm_image_type { + NVM_TYPE_TIM1 = 0x01, + NVM_TYPE_TIM2 = 0x02, + NVM_TYPE_MIM1 = 0x03, + NVM_TYPE_MIM2 = 0x04, + NVM_TYPE_MBA = 0x05, + NVM_TYPE_MODULES_PN = 0x06, + NVM_TYPE_VPD = 0x07, + NVM_TYPE_MFW_TRACE1 = 0x08, + NVM_TYPE_MFW_TRACE2 = 0x09, + NVM_TYPE_NVM_CFG1 = 0x0a, + NVM_TYPE_L2B = 0x0b, + NVM_TYPE_DIR1 = 0x0c, + NVM_TYPE_EAGLE_FW1 = 0x0d, + NVM_TYPE_FALCON_FW1 = 0x0e, + NVM_TYPE_PCIE_FW1 = 0x0f, + NVM_TYPE_HW_SET = 0x10, + NVM_TYPE_LIM = 0x11, + NVM_TYPE_AVS_FW1 = 0x12, + NVM_TYPE_DIR2 = 0x13, + NVM_TYPE_CCM = 0x14, + NVM_TYPE_EAGLE_FW2 = 0x15, + NVM_TYPE_FALCON_FW2 = 0x16, + NVM_TYPE_PCIE_FW2 = 0x17, + NVM_TYPE_AVS_FW2 = 0x18, + + NVM_TYPE_MAX, +}; + +#define MAX_NVM_DIR_ENTRIES 200 + +struct nvm_dir { + s32 seq; +#define NVM_DIR_NEXT_MFW_MASK 0x00000001 +#define NVM_DIR_SEQ_MASK 0xfffffffe +#define NVM_DIR_NEXT_MFW(seq) ((seq) & NVM_DIR_NEXT_MFW_MASK) + +#define IS_DIR_SEQ_VALID(seq) ((seq & NVM_DIR_SEQ_MASK) != NVM_DIR_SEQ_MASK) + + u32 num_images; + u32 rsrv; + struct nvm_code_entry code[1]; /* Up to MAX_NVM_DIR_ENTRIES */ +}; + +#define NVM_DIR_SIZE(_num_images) (sizeof(struct nvm_dir) + \ + (_num_images - \ + 1) * sizeof(struct nvm_code_entry) + \ + NVM_CRC_SIZE) + +struct nvm_vpd_image { + u32 format_revision; +#define VPD_IMAGE_VERSION 1 + + /* This array length depends on the number of VPD fields */ + u8 vpd_data[1]; +}; + +/**************************************************************************** +* NVRAM FULL MAP * +****************************************************************************/ +#define DIR_ID_1 (0) +#define DIR_ID_2 (1) +#define MAX_DIR_IDS (2) + +#define MFW_BUNDLE_1 (0) +#define MFW_BUNDLE_2 (1) +#define MAX_MFW_BUNDLES (2) + +#define FLASH_PAGE_SIZE 0x1000 +#define NVM_DIR_MAX_SIZE (FLASH_PAGE_SIZE) /* 4Kb */ +#define ASIC_MIM_MAX_SIZE (300 * FLASH_PAGE_SIZE) /* 1.2Mb */ +#define FPGA_MIM_MAX_SIZE (25 * FLASH_PAGE_SIZE) /* 60Kb */ + +#define LIM_MAX_SIZE ((2 * \ + FLASH_PAGE_SIZE) - \ + sizeof(struct legacy_bootstrap_region) - \ + NVM_RSV_SIZE) +#define LIM_OFFSET (NVM_OFFSET(lim_image)) +#define NVM_RSV_SIZE (44) +#define MIM_MAX_SIZE(is_asic) ((is_asic) ? ASIC_MIM_MAX_SIZE : \ + FPGA_MIM_MAX_SIZE) +#define MIM_OFFSET(idx, is_asic) (NVM_OFFSET(dir[MAX_MFW_BUNDLES]) + \ + ((idx == \ + NVM_TYPE_MIM2) ? MIM_MAX_SIZE(is_asic) : 0)) +#define NVM_FIXED_AREA_SIZE(is_asic) (sizeof(struct nvm_image) + \ + MIM_MAX_SIZE(is_asic) * 2) + +union nvm_dir_union { + struct nvm_dir dir; + u8 page[FLASH_PAGE_SIZE]; +}; + +/* Address + * +-------------------+ 0x000000 + * | Bootstrap: | + * | magic_number | + * | sram_start_addr | + * | code_len | + * | code_start_addr | + * | crc | + * +-------------------+ 0x000014 + * | rsrv | + * +-------------------+ 0x000040 + * | LIM | + * +-------------------+ 0x002000 + * | Dir1 | + * +-------------------+ 0x003000 + * | Dir2 | + * +-------------------+ 0x004000 + * | MIM1 | + * +-------------------+ 0x130000 + * | MIM2 | + * +-------------------+ 0x25C000 + * | Rest Images: | + * | TIM1/2 | + * | MFW_TRACE1/2 | + * | Eagle/Falcon FW | + * | PCIE/AVS FW | + * | MBA/CCM/L2B | + * | VPD | + * | optic_modules | + * | ... | + * +-------------------+ 0x400000 + */ +struct nvm_image { +/*********** !!! FIXED SECTIONS !!! DO NOT MODIFY !!! **********************/ + /* NVM Offset (size) */ + struct legacy_bootstrap_region bootstrap; + u8 rsrv[NVM_RSV_SIZE]; + u8 lim_image[LIM_MAX_SIZE]; + union nvm_dir_union dir[MAX_MFW_BUNDLES]; + + /* MIM1_IMAGE 0x004000 (0x12c000) */ + /* MIM2_IMAGE 0x130000 (0x12c000) */ +/*********** !!! FIXED SECTIONS !!! DO NOT MODIFY !!! **********************/ +}; /* 0x134 */ + +#define NVM_OFFSET(f) ((u32_t)((int_ptr_t)(&(((struct nvm_image *)0)->f)))) + +struct hw_set_info { + u32 reg_type; +#define GRC_REG_TYPE 1 +#define PHY_REG_TYPE 2 +#define PCI_REG_TYPE 4 + + u32 bank_num; + u32 pf_num; + u32 operation; +#define READ_OP 1 +#define WRITE_OP 2 +#define RMW_SET_OP 3 +#define RMW_CLR_OP 4 + + u32 reg_addr; + u32 reg_data; + + u32 reset_type; +#define POR_RESET_TYPE BIT(0) +#define HARD_RESET_TYPE BIT(1) +#define CORE_RESET_TYPE BIT(2) +#define MCP_RESET_TYPE BIT(3) +#define PERSET_ASSERT BIT(4) +#define PERSET_DEASSERT BIT(5) +}; + +struct hw_set_image { + u32 format_version; +#define HW_SET_IMAGE_VERSION 1 + u32 no_hw_sets; + + /* This array length depends on the no_hw_sets */ + struct hw_set_info hw_sets[1]; +}; + +#endif diff --git a/drivers/net/ethernet/qlogic/qed/qed_hw.c b/drivers/net/ethernet/qlogic/qed/qed_hw.c new file mode 100644 index 000000000000..ffa99273b353 --- /dev/null +++ b/drivers/net/ethernet/qlogic/qed/qed_hw.c @@ -0,0 +1,776 @@ +/* QLogic qed NIC Driver + * Copyright (c) 2015 QLogic Corporation + * + * This software is available under the terms of the GNU General Public License + * (GPL) Version 2, available from the file COPYING in the main directory of + * this source tree. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "qed.h" +#include "qed_hsi.h" +#include "qed_hw.h" +#include "qed_reg_addr.h" + +#define QED_BAR_ACQUIRE_TIMEOUT 1000 + +/* Invalid values */ +#define QED_BAR_INVALID_OFFSET (cpu_to_le32(-1)) + +struct qed_ptt { + struct list_head list_entry; + unsigned int idx; + struct pxp_ptt_entry pxp; +}; + +struct qed_ptt_pool { + struct list_head free_list; + spinlock_t lock; /* ptt synchronized access */ + struct qed_ptt ptts[PXP_EXTERNAL_BAR_PF_WINDOW_NUM]; +}; + +int qed_ptt_pool_alloc(struct qed_hwfn *p_hwfn) +{ + struct qed_ptt_pool *p_pool = kmalloc(sizeof(*p_pool), + GFP_ATOMIC); + int i; + + if (!p_pool) + return -ENOMEM; + + INIT_LIST_HEAD(&p_pool->free_list); + for (i = 0; i < PXP_EXTERNAL_BAR_PF_WINDOW_NUM; i++) { + p_pool->ptts[i].idx = i; + p_pool->ptts[i].pxp.offset = QED_BAR_INVALID_OFFSET; + p_pool->ptts[i].pxp.pretend.control = 0; + if (i >= RESERVED_PTT_MAX) + list_add(&p_pool->ptts[i].list_entry, + &p_pool->free_list); + } + + p_hwfn->p_ptt_pool = p_pool; + spin_lock_init(&p_pool->lock); + + return 0; +} + +void qed_ptt_invalidate(struct qed_hwfn *p_hwfn) +{ + struct qed_ptt *p_ptt; + int i; + + for (i = 0; i < PXP_EXTERNAL_BAR_PF_WINDOW_NUM; i++) { + p_ptt = &p_hwfn->p_ptt_pool->ptts[i]; + p_ptt->pxp.offset = QED_BAR_INVALID_OFFSET; + } +} + +void qed_ptt_pool_free(struct qed_hwfn *p_hwfn) +{ + kfree(p_hwfn->p_ptt_pool); + p_hwfn->p_ptt_pool = NULL; +} + +struct qed_ptt *qed_ptt_acquire(struct qed_hwfn *p_hwfn) +{ + struct qed_ptt *p_ptt; + unsigned int i; + + /* Take the free PTT from the list */ + for (i = 0; i < QED_BAR_ACQUIRE_TIMEOUT; i++) { + spin_lock_bh(&p_hwfn->p_ptt_pool->lock); + + if (!list_empty(&p_hwfn->p_ptt_pool->free_list)) { + p_ptt = list_first_entry(&p_hwfn->p_ptt_pool->free_list, + struct qed_ptt, list_entry); + list_del(&p_ptt->list_entry); + + spin_unlock_bh(&p_hwfn->p_ptt_pool->lock); + + DP_VERBOSE(p_hwfn, NETIF_MSG_HW, + "allocated ptt %d\n", p_ptt->idx); + return p_ptt; + } + + spin_unlock_bh(&p_hwfn->p_ptt_pool->lock); + usleep_range(1000, 2000); + } + + DP_NOTICE(p_hwfn, "PTT acquire timeout - failed to allocate PTT\n"); + return NULL; +} + +void qed_ptt_release(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt) +{ + spin_lock_bh(&p_hwfn->p_ptt_pool->lock); + list_add(&p_ptt->list_entry, &p_hwfn->p_ptt_pool->free_list); + spin_unlock_bh(&p_hwfn->p_ptt_pool->lock); +} + +u32 qed_ptt_get_hw_addr(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt) +{ + /* The HW is using DWORDS and we need to translate it to Bytes */ + return le32_to_cpu(p_ptt->pxp.offset) << 2; +} + +static u32 qed_ptt_config_addr(struct qed_ptt *p_ptt) +{ + return PXP_PF_WINDOW_ADMIN_PER_PF_START + + p_ptt->idx * sizeof(struct pxp_ptt_entry); +} + +u32 qed_ptt_get_bar_addr(struct qed_ptt *p_ptt) +{ + return PXP_EXTERNAL_BAR_PF_WINDOW_START + + p_ptt->idx * PXP_EXTERNAL_BAR_PF_WINDOW_SINGLE_SIZE; +} + +void qed_ptt_set_win(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u32 new_hw_addr) +{ + u32 prev_hw_addr; + + prev_hw_addr = qed_ptt_get_hw_addr(p_hwfn, p_ptt); + + if (new_hw_addr == prev_hw_addr) + return; + + /* Update PTT entery in admin window */ + DP_VERBOSE(p_hwfn, NETIF_MSG_HW, + "Updating PTT entry %d to offset 0x%x\n", + p_ptt->idx, new_hw_addr); + + /* The HW is using DWORDS and the address is in Bytes */ + p_ptt->pxp.offset = cpu_to_le32(new_hw_addr >> 2); + + REG_WR(p_hwfn, + qed_ptt_config_addr(p_ptt) + + offsetof(struct pxp_ptt_entry, offset), + le32_to_cpu(p_ptt->pxp.offset)); +} + +static u32 qed_set_ptt(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u32 hw_addr) +{ + u32 win_hw_addr = qed_ptt_get_hw_addr(p_hwfn, p_ptt); + u32 offset; + + offset = hw_addr - win_hw_addr; + + /* Verify the address is within the window */ + if (hw_addr < win_hw_addr || + offset >= PXP_EXTERNAL_BAR_PF_WINDOW_SINGLE_SIZE) { + qed_ptt_set_win(p_hwfn, p_ptt, hw_addr); + offset = 0; + } + + return qed_ptt_get_bar_addr(p_ptt) + offset; +} + +struct qed_ptt *qed_get_reserved_ptt(struct qed_hwfn *p_hwfn, + enum reserved_ptts ptt_idx) +{ + if (ptt_idx >= RESERVED_PTT_MAX) { + DP_NOTICE(p_hwfn, + "Requested PTT %d is out of range\n", ptt_idx); + return NULL; + } + + return &p_hwfn->p_ptt_pool->ptts[ptt_idx]; +} + +void qed_wr(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u32 hw_addr, u32 val) +{ + u32 bar_addr = qed_set_ptt(p_hwfn, p_ptt, hw_addr); + + REG_WR(p_hwfn, bar_addr, val); + DP_VERBOSE(p_hwfn, NETIF_MSG_HW, + "bar_addr 0x%x, hw_addr 0x%x, val 0x%x\n", + bar_addr, hw_addr, val); +} + +u32 qed_rd(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u32 hw_addr) +{ + u32 bar_addr = qed_set_ptt(p_hwfn, p_ptt, hw_addr); + u32 val = REG_RD(p_hwfn, bar_addr); + + DP_VERBOSE(p_hwfn, NETIF_MSG_HW, + "bar_addr 0x%x, hw_addr 0x%x, val 0x%x\n", + bar_addr, hw_addr, val); + + return val; +} + +static void qed_memcpy_hw(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + void *addr, + u32 hw_addr, + size_t n, + bool to_device) +{ + u32 dw_count, *host_addr, hw_offset; + size_t quota, done = 0; + u32 __iomem *reg_addr; + + while (done < n) { + quota = min_t(size_t, n - done, + PXP_EXTERNAL_BAR_PF_WINDOW_SINGLE_SIZE); + + qed_ptt_set_win(p_hwfn, p_ptt, hw_addr + done); + hw_offset = qed_ptt_get_bar_addr(p_ptt); + + dw_count = quota / 4; + host_addr = (u32 *)((u8 *)addr + done); + reg_addr = (u32 __iomem *)REG_ADDR(p_hwfn, hw_offset); + if (to_device) + while (dw_count--) + DIRECT_REG_WR(reg_addr++, *host_addr++); + else + while (dw_count--) + *host_addr++ = DIRECT_REG_RD(reg_addr++); + + done += quota; + } +} + +void qed_memcpy_from(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + void *dest, u32 hw_addr, size_t n) +{ + DP_VERBOSE(p_hwfn, NETIF_MSG_HW, + "hw_addr 0x%x, dest %p hw_addr 0x%x, size %lu\n", + hw_addr, dest, hw_addr, (unsigned long)n); + + qed_memcpy_hw(p_hwfn, p_ptt, dest, hw_addr, n, false); +} + +void qed_memcpy_to(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u32 hw_addr, void *src, size_t n) +{ + DP_VERBOSE(p_hwfn, NETIF_MSG_HW, + "hw_addr 0x%x, hw_addr 0x%x, src %p size %lu\n", + hw_addr, hw_addr, src, (unsigned long)n); + + qed_memcpy_hw(p_hwfn, p_ptt, src, hw_addr, n, true); +} + +void qed_fid_pretend(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u16 fid) +{ + u16 control = 0; + + SET_FIELD(control, PXP_PRETEND_CMD_IS_CONCRETE, 1); + SET_FIELD(control, PXP_PRETEND_CMD_PRETEND_FUNCTION, 1); + + /* Every pretend undos previous pretends, including + * previous port pretend. + */ + SET_FIELD(control, PXP_PRETEND_CMD_PORT, 0); + SET_FIELD(control, PXP_PRETEND_CMD_USE_PORT, 0); + SET_FIELD(control, PXP_PRETEND_CMD_PRETEND_PORT, 1); + + if (!GET_FIELD(fid, PXP_CONCRETE_FID_VFVALID)) + fid = GET_FIELD(fid, PXP_CONCRETE_FID_PFID); + + p_ptt->pxp.pretend.control = cpu_to_le16(control); + p_ptt->pxp.pretend.fid.concrete_fid.fid = cpu_to_le16(fid); + + REG_WR(p_hwfn, + qed_ptt_config_addr(p_ptt) + + offsetof(struct pxp_ptt_entry, pretend), + *(u32 *)&p_ptt->pxp.pretend); +} + +void qed_port_pretend(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u8 port_id) +{ + u16 control = 0; + + SET_FIELD(control, PXP_PRETEND_CMD_PORT, port_id); + SET_FIELD(control, PXP_PRETEND_CMD_USE_PORT, 1); + SET_FIELD(control, PXP_PRETEND_CMD_PRETEND_PORT, 1); + + p_ptt->pxp.pretend.control = cpu_to_le16(control); + + REG_WR(p_hwfn, + qed_ptt_config_addr(p_ptt) + + offsetof(struct pxp_ptt_entry, pretend), + *(u32 *)&p_ptt->pxp.pretend); +} + +void qed_port_unpretend(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt) +{ + u16 control = 0; + + SET_FIELD(control, PXP_PRETEND_CMD_PORT, 0); + SET_FIELD(control, PXP_PRETEND_CMD_USE_PORT, 0); + SET_FIELD(control, PXP_PRETEND_CMD_PRETEND_PORT, 1); + + p_ptt->pxp.pretend.control = cpu_to_le16(control); + + REG_WR(p_hwfn, + qed_ptt_config_addr(p_ptt) + + offsetof(struct pxp_ptt_entry, pretend), + *(u32 *)&p_ptt->pxp.pretend); +} + +/* DMAE */ +static void qed_dmae_opcode(struct qed_hwfn *p_hwfn, + const u8 is_src_type_grc, + const u8 is_dst_type_grc, + struct qed_dmae_params *p_params) +{ + u32 opcode = 0; + u16 opcodeB = 0; + + /* Whether the source is the PCIe or the GRC. + * 0- The source is the PCIe + * 1- The source is the GRC. + */ + opcode |= (is_src_type_grc ? DMAE_CMD_SRC_MASK_GRC + : DMAE_CMD_SRC_MASK_PCIE) << + DMAE_CMD_SRC_SHIFT; + opcode |= ((p_hwfn->rel_pf_id & DMAE_CMD_SRC_PF_ID_MASK) << + DMAE_CMD_SRC_PF_ID_SHIFT); + + /* The destination of the DMA can be: 0-None 1-PCIe 2-GRC 3-None */ + opcode |= (is_dst_type_grc ? DMAE_CMD_DST_MASK_GRC + : DMAE_CMD_DST_MASK_PCIE) << + DMAE_CMD_DST_SHIFT; + opcode |= ((p_hwfn->rel_pf_id & DMAE_CMD_DST_PF_ID_MASK) << + DMAE_CMD_DST_PF_ID_SHIFT); + + /* Whether to write a completion word to the completion destination: + * 0-Do not write a completion word + * 1-Write the completion word + */ + opcode |= (DMAE_CMD_COMP_WORD_EN_MASK << DMAE_CMD_COMP_WORD_EN_SHIFT); + opcode |= (DMAE_CMD_SRC_ADDR_RESET_MASK << + DMAE_CMD_SRC_ADDR_RESET_SHIFT); + + if (p_params->flags & QED_DMAE_FLAG_COMPLETION_DST) + opcode |= (1 << DMAE_CMD_COMP_FUNC_SHIFT); + + opcode |= (DMAE_CMD_ENDIANITY << DMAE_CMD_ENDIANITY_MODE_SHIFT); + + opcode |= ((p_hwfn->port_id) << DMAE_CMD_PORT_ID_SHIFT); + + /* reset source address in next go */ + opcode |= (DMAE_CMD_SRC_ADDR_RESET_MASK << + DMAE_CMD_SRC_ADDR_RESET_SHIFT); + + /* reset dest address in next go */ + opcode |= (DMAE_CMD_DST_ADDR_RESET_MASK << + DMAE_CMD_DST_ADDR_RESET_SHIFT); + + opcodeB |= (DMAE_CMD_SRC_VF_ID_MASK << + DMAE_CMD_SRC_VF_ID_SHIFT); + + opcodeB |= (DMAE_CMD_DST_VF_ID_MASK << + DMAE_CMD_DST_VF_ID_SHIFT); + + p_hwfn->dmae_info.p_dmae_cmd->opcode = cpu_to_le32(opcode); + p_hwfn->dmae_info.p_dmae_cmd->opcode_b = cpu_to_le16(opcodeB); +} + +u32 qed_dmae_idx_to_go_cmd(u8 idx) +{ + /* All the DMAE 'go' registers form an array in internal memory */ + return DMAE_REG_GO_C0 + (idx << 2); +} + +static int +qed_dmae_post_command(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt) +{ + struct dmae_cmd *command = p_hwfn->dmae_info.p_dmae_cmd; + u8 idx_cmd = p_hwfn->dmae_info.channel, i; + int qed_status = 0; + + /* verify address is not NULL */ + if ((((command->dst_addr_lo == 0) && (command->dst_addr_hi == 0)) || + ((command->src_addr_lo == 0) && (command->src_addr_hi == 0)))) { + DP_NOTICE(p_hwfn, + "source or destination address 0 idx_cmd=%d\n" + "opcode = [0x%08x,0x%04x] len=0x%x src=0x%x:%x dst=0x%x:%x\n", + idx_cmd, + le32_to_cpu(command->opcode), + le16_to_cpu(command->opcode_b), + le16_to_cpu(command->length), + le32_to_cpu(command->src_addr_hi), + le32_to_cpu(command->src_addr_lo), + le32_to_cpu(command->dst_addr_hi), + le32_to_cpu(command->dst_addr_lo)); + + return -EINVAL; + } + + DP_VERBOSE(p_hwfn, + NETIF_MSG_HW, + "Posting DMAE command [idx %d]: opcode = [0x%08x,0x%04x] len=0x%x src=0x%x:%x dst=0x%x:%x\n", + idx_cmd, + le32_to_cpu(command->opcode), + le16_to_cpu(command->opcode_b), + le16_to_cpu(command->length), + le32_to_cpu(command->src_addr_hi), + le32_to_cpu(command->src_addr_lo), + le32_to_cpu(command->dst_addr_hi), + le32_to_cpu(command->dst_addr_lo)); + + /* Copy the command to DMAE - need to do it before every call + * for source/dest address no reset. + * The first 9 DWs are the command registers, the 10 DW is the + * GO register, and the rest are result registers + * (which are read only by the client). + */ + for (i = 0; i < DMAE_CMD_SIZE; i++) { + u32 data = (i < DMAE_CMD_SIZE_TO_FILL) ? + *(((u32 *)command) + i) : 0; + + qed_wr(p_hwfn, p_ptt, + DMAE_REG_CMD_MEM + + (idx_cmd * DMAE_CMD_SIZE * sizeof(u32)) + + (i * sizeof(u32)), data); + } + + qed_wr(p_hwfn, p_ptt, + qed_dmae_idx_to_go_cmd(idx_cmd), + DMAE_GO_VALUE); + + return qed_status; +} + +int qed_dmae_info_alloc(struct qed_hwfn *p_hwfn) +{ + dma_addr_t *p_addr = &p_hwfn->dmae_info.completion_word_phys_addr; + struct dmae_cmd **p_cmd = &p_hwfn->dmae_info.p_dmae_cmd; + u32 **p_buff = &p_hwfn->dmae_info.p_intermediate_buffer; + u32 **p_comp = &p_hwfn->dmae_info.p_completion_word; + + *p_comp = dma_alloc_coherent(&p_hwfn->cdev->pdev->dev, + sizeof(u32), + p_addr, + GFP_KERNEL); + if (!*p_comp) { + DP_NOTICE(p_hwfn, "Failed to allocate `p_completion_word'\n"); + goto err; + } + + p_addr = &p_hwfn->dmae_info.dmae_cmd_phys_addr; + *p_cmd = dma_alloc_coherent(&p_hwfn->cdev->pdev->dev, + sizeof(struct dmae_cmd), + p_addr, GFP_KERNEL); + if (!*p_cmd) { + DP_NOTICE(p_hwfn, "Failed to allocate `struct dmae_cmd'\n"); + goto err; + } + + p_addr = &p_hwfn->dmae_info.intermediate_buffer_phys_addr; + *p_buff = dma_alloc_coherent(&p_hwfn->cdev->pdev->dev, + sizeof(u32) * DMAE_MAX_RW_SIZE, + p_addr, GFP_KERNEL); + if (!*p_buff) { + DP_NOTICE(p_hwfn, "Failed to allocate `intermediate_buffer'\n"); + goto err; + } + + p_hwfn->dmae_info.channel = p_hwfn->rel_pf_id; + + return 0; +err: + qed_dmae_info_free(p_hwfn); + return -ENOMEM; +} + +void qed_dmae_info_free(struct qed_hwfn *p_hwfn) +{ + dma_addr_t p_phys; + + /* Just make sure no one is in the middle */ + mutex_lock(&p_hwfn->dmae_info.mutex); + + if (p_hwfn->dmae_info.p_completion_word) { + p_phys = p_hwfn->dmae_info.completion_word_phys_addr; + dma_free_coherent(&p_hwfn->cdev->pdev->dev, + sizeof(u32), + p_hwfn->dmae_info.p_completion_word, + p_phys); + p_hwfn->dmae_info.p_completion_word = NULL; + } + + if (p_hwfn->dmae_info.p_dmae_cmd) { + p_phys = p_hwfn->dmae_info.dmae_cmd_phys_addr; + dma_free_coherent(&p_hwfn->cdev->pdev->dev, + sizeof(struct dmae_cmd), + p_hwfn->dmae_info.p_dmae_cmd, + p_phys); + p_hwfn->dmae_info.p_dmae_cmd = NULL; + } + + if (p_hwfn->dmae_info.p_intermediate_buffer) { + p_phys = p_hwfn->dmae_info.intermediate_buffer_phys_addr; + dma_free_coherent(&p_hwfn->cdev->pdev->dev, + sizeof(u32) * DMAE_MAX_RW_SIZE, + p_hwfn->dmae_info.p_intermediate_buffer, + p_phys); + p_hwfn->dmae_info.p_intermediate_buffer = NULL; + } + + mutex_unlock(&p_hwfn->dmae_info.mutex); +} + +static int qed_dmae_operation_wait(struct qed_hwfn *p_hwfn) +{ + u32 wait_cnt = 0; + u32 wait_cnt_limit = 10000; + + int qed_status = 0; + + barrier(); + while (*p_hwfn->dmae_info.p_completion_word != DMAE_COMPLETION_VAL) { + udelay(DMAE_MIN_WAIT_TIME); + if (++wait_cnt > wait_cnt_limit) { + DP_NOTICE(p_hwfn->cdev, + "Timed-out waiting for operation to complete. Completion word is 0x%08x expected 0x%08x.\n", + *p_hwfn->dmae_info.p_completion_word, + DMAE_COMPLETION_VAL); + qed_status = -EBUSY; + break; + } + + /* to sync the completion_word since we are not + * using the volatile keyword for p_completion_word + */ + barrier(); + } + + if (qed_status == 0) + *p_hwfn->dmae_info.p_completion_word = 0; + + return qed_status; +} + +static int qed_dmae_execute_sub_operation(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u64 src_addr, + u64 dst_addr, + u8 src_type, + u8 dst_type, + u32 length) +{ + dma_addr_t phys = p_hwfn->dmae_info.intermediate_buffer_phys_addr; + struct dmae_cmd *cmd = p_hwfn->dmae_info.p_dmae_cmd; + int qed_status = 0; + + switch (src_type) { + case QED_DMAE_ADDRESS_GRC: + case QED_DMAE_ADDRESS_HOST_PHYS: + cmd->src_addr_hi = cpu_to_le32(upper_32_bits(src_addr)); + cmd->src_addr_lo = cpu_to_le32(lower_32_bits(src_addr)); + break; + /* for virtual source addresses we use the intermediate buffer. */ + case QED_DMAE_ADDRESS_HOST_VIRT: + cmd->src_addr_hi = cpu_to_le32(upper_32_bits(phys)); + cmd->src_addr_lo = cpu_to_le32(lower_32_bits(phys)); + memcpy(&p_hwfn->dmae_info.p_intermediate_buffer[0], + (void *)(uintptr_t)src_addr, + length * sizeof(u32)); + break; + default: + return -EINVAL; + } + + switch (dst_type) { + case QED_DMAE_ADDRESS_GRC: + case QED_DMAE_ADDRESS_HOST_PHYS: + cmd->dst_addr_hi = cpu_to_le32(upper_32_bits(dst_addr)); + cmd->dst_addr_lo = cpu_to_le32(lower_32_bits(dst_addr)); + break; + /* for virtual source addresses we use the intermediate buffer. */ + case QED_DMAE_ADDRESS_HOST_VIRT: + cmd->dst_addr_hi = cpu_to_le32(upper_32_bits(phys)); + cmd->dst_addr_lo = cpu_to_le32(lower_32_bits(phys)); + break; + default: + return -EINVAL; + } + + cmd->length = cpu_to_le16((u16)length); + + qed_dmae_post_command(p_hwfn, p_ptt); + + qed_status = qed_dmae_operation_wait(p_hwfn); + + if (qed_status) { + DP_NOTICE(p_hwfn, + "qed_dmae_host2grc: Wait Failed. source_addr 0x%llx, grc_addr 0x%llx, size_in_dwords 0x%x\n", + src_addr, + dst_addr, + length); + return qed_status; + } + + if (dst_type == QED_DMAE_ADDRESS_HOST_VIRT) + memcpy((void *)(uintptr_t)(dst_addr), + &p_hwfn->dmae_info.p_intermediate_buffer[0], + length * sizeof(u32)); + + return 0; +} + +static int qed_dmae_execute_command(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u64 src_addr, u64 dst_addr, + u8 src_type, u8 dst_type, + u32 size_in_dwords, + struct qed_dmae_params *p_params) +{ + dma_addr_t phys = p_hwfn->dmae_info.completion_word_phys_addr; + u16 length_cur = 0, i = 0, cnt_split = 0, length_mod = 0; + struct dmae_cmd *cmd = p_hwfn->dmae_info.p_dmae_cmd; + u64 src_addr_split = 0, dst_addr_split = 0; + u16 length_limit = DMAE_MAX_RW_SIZE; + int qed_status = 0; + u32 offset = 0; + + qed_dmae_opcode(p_hwfn, + (src_type == QED_DMAE_ADDRESS_GRC), + (dst_type == QED_DMAE_ADDRESS_GRC), + p_params); + + cmd->comp_addr_lo = cpu_to_le32(lower_32_bits(phys)); + cmd->comp_addr_hi = cpu_to_le32(upper_32_bits(phys)); + cmd->comp_val = cpu_to_le32(DMAE_COMPLETION_VAL); + + /* Check if the grc_addr is valid like < MAX_GRC_OFFSET */ + cnt_split = size_in_dwords / length_limit; + length_mod = size_in_dwords % length_limit; + + src_addr_split = src_addr; + dst_addr_split = dst_addr; + + for (i = 0; i <= cnt_split; i++) { + offset = length_limit * i; + + if (!(p_params->flags & QED_DMAE_FLAG_RW_REPL_SRC)) { + if (src_type == QED_DMAE_ADDRESS_GRC) + src_addr_split = src_addr + offset; + else + src_addr_split = src_addr + (offset * 4); + } + + if (dst_type == QED_DMAE_ADDRESS_GRC) + dst_addr_split = dst_addr + offset; + else + dst_addr_split = dst_addr + (offset * 4); + + length_cur = (cnt_split == i) ? length_mod : length_limit; + + /* might be zero on last iteration */ + if (!length_cur) + continue; + + qed_status = qed_dmae_execute_sub_operation(p_hwfn, + p_ptt, + src_addr_split, + dst_addr_split, + src_type, + dst_type, + length_cur); + if (qed_status) { + DP_NOTICE(p_hwfn, + "qed_dmae_execute_sub_operation Failed with error 0x%x. source_addr 0x%llx, destination addr 0x%llx, size_in_dwords 0x%x\n", + qed_status, + src_addr, + dst_addr, + length_cur); + break; + } + } + + return qed_status; +} + +int qed_dmae_host2grc(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u64 source_addr, + u32 grc_addr, + u32 size_in_dwords, + u32 flags) +{ + u32 grc_addr_in_dw = grc_addr / sizeof(u32); + struct qed_dmae_params params; + int rc; + + memset(¶ms, 0, sizeof(struct qed_dmae_params)); + params.flags = flags; + + mutex_lock(&p_hwfn->dmae_info.mutex); + + rc = qed_dmae_execute_command(p_hwfn, p_ptt, source_addr, + grc_addr_in_dw, + QED_DMAE_ADDRESS_HOST_VIRT, + QED_DMAE_ADDRESS_GRC, + size_in_dwords, ¶ms); + + mutex_unlock(&p_hwfn->dmae_info.mutex); + + return rc; +} + +u16 qed_get_qm_pq(struct qed_hwfn *p_hwfn, + enum protocol_type proto, + union qed_qm_pq_params *p_params) +{ + u16 pq_id = 0; + + if ((proto == PROTOCOLID_CORE || proto == PROTOCOLID_ETH) && + !p_params) { + DP_NOTICE(p_hwfn, + "Protocol %d received NULL PQ params\n", + proto); + return 0; + } + + switch (proto) { + case PROTOCOLID_CORE: + if (p_params->core.tc == LB_TC) + pq_id = p_hwfn->qm_info.pure_lb_pq; + else + pq_id = p_hwfn->qm_info.offload_pq; + break; + case PROTOCOLID_ETH: + pq_id = p_params->eth.tc; + break; + default: + pq_id = 0; + } + + pq_id = CM_TX_PQ_BASE + pq_id + RESC_START(p_hwfn, QED_PQ); + + return pq_id; +} diff --git a/drivers/net/ethernet/qlogic/qed/qed_hw.h b/drivers/net/ethernet/qlogic/qed/qed_hw.h new file mode 100644 index 000000000000..e56d433793be --- /dev/null +++ b/drivers/net/ethernet/qlogic/qed/qed_hw.h @@ -0,0 +1,263 @@ +/* QLogic qed NIC Driver + * Copyright (c) 2015 QLogic Corporation + * + * This software is available under the terms of the GNU General Public License + * (GPL) Version 2, available from the file COPYING in the main directory of + * this source tree. + */ + +#ifndef _QED_HW_H +#define _QED_HW_H + +#include +#include +#include +#include +#include "qed.h" +#include "qed_dev_api.h" + +/* Forward decleration */ +struct qed_ptt; + +enum reserved_ptts { + RESERVED_PTT_EDIAG, + RESERVED_PTT_USER_SPACE, + RESERVED_PTT_MAIN, + RESERVED_PTT_DPC, + RESERVED_PTT_MAX +}; + +enum _dmae_cmd_dst_mask { + DMAE_CMD_DST_MASK_NONE = 0, + DMAE_CMD_DST_MASK_PCIE = 1, + DMAE_CMD_DST_MASK_GRC = 2 +}; + +enum _dmae_cmd_src_mask { + DMAE_CMD_SRC_MASK_PCIE = 0, + DMAE_CMD_SRC_MASK_GRC = 1 +}; + +enum _dmae_cmd_crc_mask { + DMAE_CMD_COMP_CRC_EN_MASK_NONE = 0, + DMAE_CMD_COMP_CRC_EN_MASK_SET = 1 +}; + +/* definitions for DMA constants */ +#define DMAE_GO_VALUE 0x1 + +#define DMAE_COMPLETION_VAL 0xD1AE +#define DMAE_CMD_ENDIANITY 0x2 + +#define DMAE_CMD_SIZE 14 +#define DMAE_CMD_SIZE_TO_FILL (DMAE_CMD_SIZE - 5) +#define DMAE_MIN_WAIT_TIME 0x2 +#define DMAE_MAX_CLIENTS 32 + +/** + * @brief qed_gtt_init - Initialize GTT windows + * + * @param p_hwfn + */ +void qed_gtt_init(struct qed_hwfn *p_hwfn); + +/** + * @brief qed_ptt_invalidate - Forces all ptt entries to be re-configured + * + * @param p_hwfn + */ +void qed_ptt_invalidate(struct qed_hwfn *p_hwfn); + +/** + * @brief qed_ptt_pool_alloc - Allocate and initialize PTT pool + * + * @param p_hwfn + * + * @return struct _qed_status - success (0), negative - error. + */ +int qed_ptt_pool_alloc(struct qed_hwfn *p_hwfn); + +/** + * @brief qed_ptt_pool_free - + * + * @param p_hwfn + */ +void qed_ptt_pool_free(struct qed_hwfn *p_hwfn); + +/** + * @brief qed_ptt_get_hw_addr - Get PTT's GRC/HW address + * + * @param p_hwfn + * @param p_ptt + * + * @return u32 + */ +u32 qed_ptt_get_hw_addr(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt); + +/** + * @brief qed_ptt_get_bar_addr - Get PPT's external BAR address + * + * @param p_hwfn + * @param p_ptt + * + * @return u32 + */ +u32 qed_ptt_get_bar_addr(struct qed_ptt *p_ptt); + +/** + * @brief qed_ptt_set_win - Set PTT Window's GRC BAR address + * + * @param p_hwfn + * @param new_hw_addr + * @param p_ptt + */ +void qed_ptt_set_win(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u32 new_hw_addr); + +/** + * @brief qed_get_reserved_ptt - Get a specific reserved PTT + * + * @param p_hwfn + * @param ptt_idx + * + * @return struct qed_ptt * + */ +struct qed_ptt *qed_get_reserved_ptt(struct qed_hwfn *p_hwfn, + enum reserved_ptts ptt_idx); + +/** + * @brief qed_wr - Write value to BAR using the given ptt + * + * @param p_hwfn + * @param p_ptt + * @param val + * @param hw_addr + */ +void qed_wr(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u32 hw_addr, + u32 val); + +/** + * @brief qed_rd - Read value from BAR using the given ptt + * + * @param p_hwfn + * @param p_ptt + * @param val + * @param hw_addr + */ +u32 qed_rd(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u32 hw_addr); + +/** + * @brief qed_memcpy_from - copy n bytes from BAR using the given + * ptt + * + * @param p_hwfn + * @param p_ptt + * @param dest + * @param hw_addr + * @param n + */ +void qed_memcpy_from(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + void *dest, + u32 hw_addr, + size_t n); + +/** + * @brief qed_memcpy_to - copy n bytes to BAR using the given + * ptt + * + * @param p_hwfn + * @param p_ptt + * @param hw_addr + * @param src + * @param n + */ +void qed_memcpy_to(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u32 hw_addr, + void *src, + size_t n); +/** + * @brief qed_fid_pretend - pretend to another function when + * accessing the ptt window. There is no way to unpretend + * a function. The only way to cancel a pretend is to + * pretend back to the original function. + * + * @param p_hwfn + * @param p_ptt + * @param fid - fid field of pxp_pretend structure. Can contain + * either pf / vf, port/path fields are don't care. + */ +void qed_fid_pretend(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u16 fid); + +/** + * @brief qed_port_pretend - pretend to another port when + * accessing the ptt window + * + * @param p_hwfn + * @param p_ptt + * @param port_id - the port to pretend to + */ +void qed_port_pretend(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u8 port_id); + +/** + * @brief qed_port_unpretend - cancel any previously set port + * pretend + * + * @param p_hwfn + * @param p_ptt + */ +void qed_port_unpretend(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt); + +/** + * @brief qed_dmae_idx_to_go_cmd - map the idx to dmae cmd + * this is declared here since other files will require it. + * @param idx + */ +u32 qed_dmae_idx_to_go_cmd(u8 idx); + +/** + * @brief qed_dmae_info_alloc - Init the dmae_info structure + * which is part of p_hwfn. + * @param p_hwfn + */ +int qed_dmae_info_alloc(struct qed_hwfn *p_hwfn); + +/** + * @brief qed_dmae_info_free - Free the dmae_info structure + * which is part of p_hwfn + * + * @param p_hwfn + */ +void qed_dmae_info_free(struct qed_hwfn *p_hwfn); + +union qed_qm_pq_params { + struct { + u8 tc; + } core; + + struct { + u8 is_vf; + u8 vf_id; + u8 tc; + } eth; +}; + +u16 qed_get_qm_pq(struct qed_hwfn *p_hwfn, + enum protocol_type proto, + union qed_qm_pq_params *params); + +int qed_init_fw_data(struct qed_dev *cdev, + const u8 *fw_data); +#endif diff --git a/drivers/net/ethernet/qlogic/qed/qed_init_fw_funcs.c b/drivers/net/ethernet/qlogic/qed/qed_init_fw_funcs.c new file mode 100644 index 000000000000..0b21a553cc7d --- /dev/null +++ b/drivers/net/ethernet/qlogic/qed/qed_init_fw_funcs.c @@ -0,0 +1,798 @@ +/* QLogic qed NIC Driver + * Copyright (c) 2015 QLogic Corporation + * + * This software is available under the terms of the GNU General Public License + * (GPL) Version 2, available from the file COPYING in the main directory of + * this source tree. + */ + +#include +#include +#include +#include +#include +#include "qed_hsi.h" +#include "qed_hw.h" +#include "qed_init_ops.h" +#include "qed_reg_addr.h" + +enum cminterface { + MCM_SEC, + MCM_PRI, + UCM_SEC, + UCM_PRI, + TCM_SEC, + TCM_PRI, + YCM_SEC, + YCM_PRI, + XCM_SEC, + XCM_PRI, + NUM_OF_CM_INTERFACES +}; + +/* general constants */ +#define QM_PQ_ELEMENT_SIZE 4 /* in bytes */ +#define QM_PQ_MEM_4KB(pq_size) (pq_size ? DIV_ROUND_UP((pq_size + 1) * \ + QM_PQ_ELEMENT_SIZE, \ + 0x1000) : 0) +#define QM_PQ_SIZE_256B(pq_size) (pq_size ? DIV_ROUND_UP(pq_size, \ + 0x100) - 1 : 0) +#define QM_INVALID_PQ_ID 0xffff +/* feature enable */ +#define QM_BYPASS_EN 1 +#define QM_BYTE_CRD_EN 1 +/* other PQ constants */ +#define QM_OTHER_PQS_PER_PF 4 +/* WFQ constants */ +#define QM_WFQ_UPPER_BOUND 6250000 +#define QM_WFQ_VP_PQ_VOQ_SHIFT 0 +#define QM_WFQ_VP_PQ_PF_SHIFT 5 +#define QM_WFQ_INC_VAL(weight) ((weight) * 0x9000) +#define QM_WFQ_MAX_INC_VAL 4375000 +#define QM_WFQ_INIT_CRD(inc_val) (2 * (inc_val)) +/* RL constants */ +#define QM_RL_UPPER_BOUND 6250000 +#define QM_RL_PERIOD 5 /* in us */ +#define QM_RL_PERIOD_CLK_25M (25 * QM_RL_PERIOD) +#define QM_RL_INC_VAL(rate) max_t(u32, \ + (((rate ? rate : 1000000) \ + * QM_RL_PERIOD) / 8), 1) +#define QM_RL_MAX_INC_VAL 4375000 +/* AFullOprtnstcCrdMask constants */ +#define QM_OPPOR_LINE_VOQ_DEF 1 +#define QM_OPPOR_FW_STOP_DEF 0 +#define QM_OPPOR_PQ_EMPTY_DEF 1 +#define EAGLE_WORKAROUND_TC 7 +/* Command Queue constants */ +#define PBF_CMDQ_PURE_LB_LINES 150 +#define PBF_CMDQ_EAGLE_WORKAROUND_LINES 8 +#define PBF_CMDQ_LINES_RT_OFFSET(voq) ( \ + PBF_REG_YCMD_QS_NUM_LINES_VOQ0_RT_OFFSET + voq * \ + (PBF_REG_YCMD_QS_NUM_LINES_VOQ1_RT_OFFSET - \ + PBF_REG_YCMD_QS_NUM_LINES_VOQ0_RT_OFFSET)) +#define PBF_BTB_GUARANTEED_RT_OFFSET(voq) ( \ + PBF_REG_BTB_GUARANTEED_VOQ0_RT_OFFSET + voq * \ + (PBF_REG_BTB_GUARANTEED_VOQ1_RT_OFFSET - \ + PBF_REG_BTB_GUARANTEED_VOQ0_RT_OFFSET)) +#define QM_VOQ_LINE_CRD(pbf_cmd_lines) ((((pbf_cmd_lines) - \ + 4) * \ + 2) | QM_LINE_CRD_REG_SIGN_BIT) +/* BTB: blocks constants (block size = 256B) */ +#define BTB_JUMBO_PKT_BLOCKS 38 +#define BTB_HEADROOM_BLOCKS BTB_JUMBO_PKT_BLOCKS +#define BTB_EAGLE_WORKAROUND_BLOCKS 4 +#define BTB_PURE_LB_FACTOR 10 +#define BTB_PURE_LB_RATIO 7 +/* QM stop command constants */ +#define QM_STOP_PQ_MASK_WIDTH 32 +#define QM_STOP_CMD_ADDR 0x2 +#define QM_STOP_CMD_STRUCT_SIZE 2 +#define QM_STOP_CMD_PAUSE_MASK_OFFSET 0 +#define QM_STOP_CMD_PAUSE_MASK_SHIFT 0 +#define QM_STOP_CMD_PAUSE_MASK_MASK -1 +#define QM_STOP_CMD_GROUP_ID_OFFSET 1 +#define QM_STOP_CMD_GROUP_ID_SHIFT 16 +#define QM_STOP_CMD_GROUP_ID_MASK 15 +#define QM_STOP_CMD_PQ_TYPE_OFFSET 1 +#define QM_STOP_CMD_PQ_TYPE_SHIFT 24 +#define QM_STOP_CMD_PQ_TYPE_MASK 1 +#define QM_STOP_CMD_MAX_POLL_COUNT 100 +#define QM_STOP_CMD_POLL_PERIOD_US 500 +/* QM command macros */ +#define QM_CMD_STRUCT_SIZE(cmd) cmd ## \ + _STRUCT_SIZE +#define QM_CMD_SET_FIELD(var, cmd, field, \ + value) SET_FIELD(var[cmd ## _ ## field ## \ + _OFFSET], \ + cmd ## _ ## field, \ + value) +/* QM: VOQ macros */ +#define PHYS_VOQ(port, tc, max_phy_tcs_pr_port) ((port) * \ + (max_phy_tcs_pr_port) \ + + (tc)) +#define LB_VOQ(port) ( \ + MAX_PHYS_VOQS + (port)) +#define VOQ(port, tc, max_phy_tcs_pr_port) \ + ((tc) < \ + LB_TC ? PHYS_VOQ(port, \ + tc, \ + max_phy_tcs_pr_port) \ + : LB_VOQ(port)) +/******************** INTERNAL IMPLEMENTATION *********************/ +/* Prepare PF RL enable/disable runtime init values */ +static void qed_enable_pf_rl(struct qed_hwfn *p_hwfn, + bool pf_rl_en) +{ + STORE_RT_REG(p_hwfn, QM_REG_RLPFENABLE_RT_OFFSET, pf_rl_en ? 1 : 0); + if (pf_rl_en) { + /* enable RLs for all VOQs */ + STORE_RT_REG(p_hwfn, QM_REG_RLPFVOQENABLE_RT_OFFSET, + (1 << MAX_NUM_VOQS) - 1); + /* write RL period */ + STORE_RT_REG(p_hwfn, + QM_REG_RLPFPERIOD_RT_OFFSET, + QM_RL_PERIOD_CLK_25M); + STORE_RT_REG(p_hwfn, + QM_REG_RLPFPERIODTIMER_RT_OFFSET, + QM_RL_PERIOD_CLK_25M); + /* set credit threshold for QM bypass flow */ + if (QM_BYPASS_EN) + STORE_RT_REG(p_hwfn, + QM_REG_AFULLQMBYPTHRPFRL_RT_OFFSET, + QM_RL_UPPER_BOUND); + } +} + +/* Prepare PF WFQ enable/disable runtime init values */ +static void qed_enable_pf_wfq(struct qed_hwfn *p_hwfn, + bool pf_wfq_en) +{ + STORE_RT_REG(p_hwfn, QM_REG_WFQPFENABLE_RT_OFFSET, pf_wfq_en ? 1 : 0); + /* set credit threshold for QM bypass flow */ + if (pf_wfq_en && QM_BYPASS_EN) + STORE_RT_REG(p_hwfn, + QM_REG_AFULLQMBYPTHRPFWFQ_RT_OFFSET, + QM_WFQ_UPPER_BOUND); +} + +/* Prepare VPORT RL enable/disable runtime init values */ +static void qed_enable_vport_rl(struct qed_hwfn *p_hwfn, + bool vport_rl_en) +{ + STORE_RT_REG(p_hwfn, QM_REG_RLGLBLENABLE_RT_OFFSET, + vport_rl_en ? 1 : 0); + if (vport_rl_en) { + /* write RL period (use timer 0 only) */ + STORE_RT_REG(p_hwfn, + QM_REG_RLGLBLPERIOD_0_RT_OFFSET, + QM_RL_PERIOD_CLK_25M); + STORE_RT_REG(p_hwfn, + QM_REG_RLGLBLPERIODTIMER_0_RT_OFFSET, + QM_RL_PERIOD_CLK_25M); + /* set credit threshold for QM bypass flow */ + if (QM_BYPASS_EN) + STORE_RT_REG(p_hwfn, + QM_REG_AFULLQMBYPTHRGLBLRL_RT_OFFSET, + QM_RL_UPPER_BOUND); + } +} + +/* Prepare VPORT WFQ enable/disable runtime init values */ +static void qed_enable_vport_wfq(struct qed_hwfn *p_hwfn, + bool vport_wfq_en) +{ + STORE_RT_REG(p_hwfn, QM_REG_WFQVPENABLE_RT_OFFSET, + vport_wfq_en ? 1 : 0); + /* set credit threshold for QM bypass flow */ + if (vport_wfq_en && QM_BYPASS_EN) + STORE_RT_REG(p_hwfn, + QM_REG_AFULLQMBYPTHRVPWFQ_RT_OFFSET, + QM_WFQ_UPPER_BOUND); +} + +/* Prepare runtime init values to allocate PBF command queue lines for + * the specified VOQ + */ +static void qed_cmdq_lines_voq_rt_init(struct qed_hwfn *p_hwfn, + u8 voq, + u16 cmdq_lines) +{ + u32 qm_line_crd; + + /* In A0 - Limit the size of pbf queue so that only 511 commands with + * the minimum size of 4 (FCoE minimum size) + */ + bool is_bb_a0 = QED_IS_BB_A0(p_hwfn->cdev); + + if (is_bb_a0) + cmdq_lines = min_t(u32, cmdq_lines, 1022); + qm_line_crd = QM_VOQ_LINE_CRD(cmdq_lines); + OVERWRITE_RT_REG(p_hwfn, PBF_CMDQ_LINES_RT_OFFSET(voq), + (u32)cmdq_lines); + STORE_RT_REG(p_hwfn, QM_REG_VOQCRDLINE_RT_OFFSET + voq, qm_line_crd); + STORE_RT_REG(p_hwfn, QM_REG_VOQINITCRDLINE_RT_OFFSET + voq, + qm_line_crd); +} + +/* Prepare runtime init values to allocate PBF command queue lines. */ +static void qed_cmdq_lines_rt_init( + struct qed_hwfn *p_hwfn, + u8 max_ports_per_engine, + u8 max_phys_tcs_per_port, + struct init_qm_port_params port_params[MAX_NUM_PORTS]) +{ + u8 tc, voq, port_id; + + /* clear PBF lines for all VOQs */ + for (voq = 0; voq < MAX_NUM_VOQS; voq++) + STORE_RT_REG(p_hwfn, PBF_CMDQ_LINES_RT_OFFSET(voq), 0); + for (port_id = 0; port_id < max_ports_per_engine; port_id++) { + if (port_params[port_id].active) { + u16 phys_lines, phys_lines_per_tc; + u8 phys_tcs = port_params[port_id].num_active_phys_tcs; + + /* find #lines to divide between the active + * physical TCs. + */ + phys_lines = port_params[port_id].num_pbf_cmd_lines - + PBF_CMDQ_PURE_LB_LINES; + /* find #lines per active physical TC */ + phys_lines_per_tc = phys_lines / phys_tcs; + /* init registers per active TC */ + for (tc = 0; tc < phys_tcs; tc++) { + voq = PHYS_VOQ(port_id, tc, + max_phys_tcs_per_port); + qed_cmdq_lines_voq_rt_init(p_hwfn, voq, + phys_lines_per_tc); + } + /* init registers for pure LB TC */ + qed_cmdq_lines_voq_rt_init(p_hwfn, LB_VOQ(port_id), + PBF_CMDQ_PURE_LB_LINES); + } + } +} + +static void qed_btb_blocks_rt_init( + struct qed_hwfn *p_hwfn, + u8 max_ports_per_engine, + u8 max_phys_tcs_per_port, + struct init_qm_port_params port_params[MAX_NUM_PORTS]) +{ + u32 usable_blocks, pure_lb_blocks, phys_blocks; + u8 tc, voq, port_id; + + for (port_id = 0; port_id < max_ports_per_engine; port_id++) { + u32 temp; + u8 phys_tcs; + + if (!port_params[port_id].active) + continue; + + phys_tcs = port_params[port_id].num_active_phys_tcs; + + /* subtract headroom blocks */ + usable_blocks = port_params[port_id].num_btb_blocks - + BTB_HEADROOM_BLOCKS; + + /* find blocks per physical TC. use factor to avoid + * floating arithmethic. + */ + pure_lb_blocks = (usable_blocks * BTB_PURE_LB_FACTOR) / + (phys_tcs * BTB_PURE_LB_FACTOR + + BTB_PURE_LB_RATIO); + pure_lb_blocks = max_t(u32, BTB_JUMBO_PKT_BLOCKS, + pure_lb_blocks / BTB_PURE_LB_FACTOR); + phys_blocks = (usable_blocks - pure_lb_blocks) / phys_tcs; + + /* init physical TCs */ + for (tc = 0; tc < phys_tcs; tc++) { + voq = PHYS_VOQ(port_id, tc, max_phys_tcs_per_port); + STORE_RT_REG(p_hwfn, PBF_BTB_GUARANTEED_RT_OFFSET(voq), + phys_blocks); + } + + /* init pure LB TC */ + temp = LB_VOQ(port_id); + STORE_RT_REG(p_hwfn, PBF_BTB_GUARANTEED_RT_OFFSET(temp), + pure_lb_blocks); + } +} + +/* Prepare Tx PQ mapping runtime init values for the specified PF */ +static void qed_tx_pq_map_rt_init( + struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + struct qed_qm_pf_rt_init_params *p_params, + u32 base_mem_addr_4kb) +{ + struct init_qm_vport_params *vport_params = p_params->vport_params; + u16 num_pqs = p_params->num_pf_pqs + p_params->num_vf_pqs; + u16 first_pq_group = p_params->start_pq / QM_PF_QUEUE_GROUP_SIZE; + u16 last_pq_group = (p_params->start_pq + num_pqs - 1) / + QM_PF_QUEUE_GROUP_SIZE; + bool is_bb_a0 = QED_IS_BB_A0(p_hwfn->cdev); + u16 i, pq_id, pq_group; + + /* a bit per Tx PQ indicating if the PQ is associated with a VF */ + u32 tx_pq_vf_mask[MAX_QM_TX_QUEUES / QM_PF_QUEUE_GROUP_SIZE] = { 0 }; + u32 tx_pq_vf_mask_width = is_bb_a0 ? 32 : QM_PF_QUEUE_GROUP_SIZE; + u32 num_tx_pq_vf_masks = MAX_QM_TX_QUEUES / tx_pq_vf_mask_width; + u32 pq_mem_4kb = QM_PQ_MEM_4KB(p_params->num_pf_cids); + u32 vport_pq_mem_4kb = QM_PQ_MEM_4KB(p_params->num_vf_cids); + u32 mem_addr_4kb = base_mem_addr_4kb; + + /* set mapping from PQ group to PF */ + for (pq_group = first_pq_group; pq_group <= last_pq_group; pq_group++) + STORE_RT_REG(p_hwfn, QM_REG_PQTX2PF_0_RT_OFFSET + pq_group, + (u32)(p_params->pf_id)); + /* set PQ sizes */ + STORE_RT_REG(p_hwfn, QM_REG_MAXPQSIZE_0_RT_OFFSET, + QM_PQ_SIZE_256B(p_params->num_pf_cids)); + STORE_RT_REG(p_hwfn, QM_REG_MAXPQSIZE_1_RT_OFFSET, + QM_PQ_SIZE_256B(p_params->num_vf_cids)); + + /* go over all Tx PQs */ + for (i = 0, pq_id = p_params->start_pq; i < num_pqs; i++, pq_id++) { + u8 voq = VOQ(p_params->port_id, p_params->pq_params[i].tc_id, + p_params->max_phys_tcs_per_port); + bool is_vf_pq = (i >= p_params->num_pf_pqs); + struct qm_rf_pq_map tx_pq_map; + + /* update first Tx PQ of VPORT/TC */ + u8 vport_id_in_pf = p_params->pq_params[i].vport_id - + p_params->start_vport; + u16 *pq_ids = &vport_params[vport_id_in_pf].first_tx_pq_id[0]; + u16 first_tx_pq_id = pq_ids[p_params->pq_params[i].tc_id]; + + if (first_tx_pq_id == QM_INVALID_PQ_ID) { + /* create new VP PQ */ + pq_ids[p_params->pq_params[i].tc_id] = pq_id; + first_tx_pq_id = pq_id; + /* map VP PQ to VOQ and PF */ + STORE_RT_REG(p_hwfn, + QM_REG_WFQVPMAP_RT_OFFSET + + first_tx_pq_id, + (voq << QM_WFQ_VP_PQ_VOQ_SHIFT) | + (p_params->pf_id << + QM_WFQ_VP_PQ_PF_SHIFT)); + } + /* fill PQ map entry */ + memset(&tx_pq_map, 0, sizeof(tx_pq_map)); + SET_FIELD(tx_pq_map.reg, QM_RF_PQ_MAP_PQ_VALID, 1); + SET_FIELD(tx_pq_map.reg, QM_RF_PQ_MAP_RL_VALID, + is_vf_pq ? 1 : 0); + SET_FIELD(tx_pq_map.reg, QM_RF_PQ_MAP_VP_PQ_ID, first_tx_pq_id); + SET_FIELD(tx_pq_map.reg, QM_RF_PQ_MAP_RL_ID, + is_vf_pq ? p_params->pq_params[i].vport_id : 0); + SET_FIELD(tx_pq_map.reg, QM_RF_PQ_MAP_VOQ, voq); + SET_FIELD(tx_pq_map.reg, QM_RF_PQ_MAP_WRR_WEIGHT_GROUP, + p_params->pq_params[i].wrr_group); + /* write PQ map entry to CAM */ + STORE_RT_REG(p_hwfn, QM_REG_TXPQMAP_RT_OFFSET + pq_id, + *((u32 *)&tx_pq_map)); + /* set base address */ + STORE_RT_REG(p_hwfn, + QM_REG_BASEADDRTXPQ_RT_OFFSET + pq_id, + mem_addr_4kb); + /* check if VF PQ */ + if (is_vf_pq) { + /* if PQ is associated with a VF, add indication + * to PQ VF mask + */ + tx_pq_vf_mask[pq_id / tx_pq_vf_mask_width] |= + (1 << (pq_id % tx_pq_vf_mask_width)); + mem_addr_4kb += vport_pq_mem_4kb; + } else { + mem_addr_4kb += pq_mem_4kb; + } + } + + /* store Tx PQ VF mask to size select register */ + for (i = 0; i < num_tx_pq_vf_masks; i++) { + if (tx_pq_vf_mask[i]) { + if (is_bb_a0) { + u32 curr_mask = 0, addr; + + addr = QM_REG_MAXPQSIZETXSEL_0 + (i * 4); + if (!p_params->is_first_pf) + curr_mask = qed_rd(p_hwfn, p_ptt, + addr); + + addr = QM_REG_MAXPQSIZETXSEL_0_RT_OFFSET + i; + + STORE_RT_REG(p_hwfn, addr, + curr_mask | tx_pq_vf_mask[i]); + } else { + u32 addr; + + addr = QM_REG_MAXPQSIZETXSEL_0_RT_OFFSET + i; + STORE_RT_REG(p_hwfn, addr, + tx_pq_vf_mask[i]); + } + } + } +} + +/* Prepare Other PQ mapping runtime init values for the specified PF */ +static void qed_other_pq_map_rt_init(struct qed_hwfn *p_hwfn, + u8 port_id, + u8 pf_id, + u32 num_pf_cids, + u32 num_tids, + u32 base_mem_addr_4kb) +{ + u16 i, pq_id; + + /* a single other PQ group is used in each PF, + * where PQ group i is used in PF i. + */ + u16 pq_group = pf_id; + u32 pq_size = num_pf_cids + num_tids; + u32 pq_mem_4kb = QM_PQ_MEM_4KB(pq_size); + u32 mem_addr_4kb = base_mem_addr_4kb; + + /* map PQ group to PF */ + STORE_RT_REG(p_hwfn, QM_REG_PQOTHER2PF_0_RT_OFFSET + pq_group, + (u32)(pf_id)); + /* set PQ sizes */ + STORE_RT_REG(p_hwfn, QM_REG_MAXPQSIZE_2_RT_OFFSET, + QM_PQ_SIZE_256B(pq_size)); + /* set base address */ + for (i = 0, pq_id = pf_id * QM_PF_QUEUE_GROUP_SIZE; + i < QM_OTHER_PQS_PER_PF; i++, pq_id++) { + STORE_RT_REG(p_hwfn, + QM_REG_BASEADDROTHERPQ_RT_OFFSET + pq_id, + mem_addr_4kb); + mem_addr_4kb += pq_mem_4kb; + } +} + +/* Prepare PF WFQ runtime init values for the specified PF. + * Return -1 on error. + */ +static int qed_pf_wfq_rt_init(struct qed_hwfn *p_hwfn, + struct qed_qm_pf_rt_init_params *p_params) +{ + u16 num_tx_pqs = p_params->num_pf_pqs + p_params->num_vf_pqs; + u32 crd_reg_offset; + u32 inc_val; + u16 i; + + if (p_params->pf_id < MAX_NUM_PFS_BB) + crd_reg_offset = QM_REG_WFQPFCRD_RT_OFFSET; + else + crd_reg_offset = QM_REG_WFQPFCRD_MSB_RT_OFFSET + + (p_params->pf_id % MAX_NUM_PFS_BB); + + inc_val = QM_WFQ_INC_VAL(p_params->pf_wfq); + if (inc_val > QM_WFQ_MAX_INC_VAL) { + DP_NOTICE(p_hwfn, "Invalid PF WFQ weight configuration"); + return -1; + } + STORE_RT_REG(p_hwfn, QM_REG_WFQPFWEIGHT_RT_OFFSET + p_params->pf_id, + inc_val); + STORE_RT_REG(p_hwfn, + QM_REG_WFQPFUPPERBOUND_RT_OFFSET + p_params->pf_id, + QM_WFQ_UPPER_BOUND | QM_WFQ_CRD_REG_SIGN_BIT); + + for (i = 0; i < num_tx_pqs; i++) { + u8 voq = VOQ(p_params->port_id, p_params->pq_params[i].tc_id, + p_params->max_phys_tcs_per_port); + + OVERWRITE_RT_REG(p_hwfn, + crd_reg_offset + voq * MAX_NUM_PFS_BB, + QM_WFQ_INIT_CRD(inc_val) | + QM_WFQ_CRD_REG_SIGN_BIT); + } + + return 0; +} + +/* Prepare PF RL runtime init values for the specified PF. + * Return -1 on error. + */ +static int qed_pf_rl_rt_init(struct qed_hwfn *p_hwfn, + u8 pf_id, + u32 pf_rl) +{ + u32 inc_val = QM_RL_INC_VAL(pf_rl); + + if (inc_val > QM_RL_MAX_INC_VAL) { + DP_NOTICE(p_hwfn, "Invalid PF rate limit configuration"); + return -1; + } + STORE_RT_REG(p_hwfn, QM_REG_RLPFCRD_RT_OFFSET + pf_id, + QM_RL_CRD_REG_SIGN_BIT); + STORE_RT_REG(p_hwfn, QM_REG_RLPFUPPERBOUND_RT_OFFSET + pf_id, + QM_RL_UPPER_BOUND | QM_RL_CRD_REG_SIGN_BIT); + STORE_RT_REG(p_hwfn, QM_REG_RLPFINCVAL_RT_OFFSET + pf_id, inc_val); + return 0; +} + +/* Prepare VPORT WFQ runtime init values for the specified VPORTs. + * Return -1 on error. + */ +static int qed_vp_wfq_rt_init(struct qed_hwfn *p_hwfn, + u8 start_vport, + u8 num_vports, + struct init_qm_vport_params *vport_params) +{ + u8 tc, i, vport_id; + u32 inc_val; + + /* go over all PF VPORTs */ + for (i = 0, vport_id = start_vport; i < num_vports; i++, vport_id++) { + u32 temp = QM_REG_WFQVPUPPERBOUND_RT_OFFSET; + u16 *pq_ids = &vport_params[i].first_tx_pq_id[0]; + + if (!vport_params[i].vport_wfq) + continue; + + inc_val = QM_WFQ_INC_VAL(vport_params[i].vport_wfq); + if (inc_val > QM_WFQ_MAX_INC_VAL) { + DP_NOTICE(p_hwfn, + "Invalid VPORT WFQ weight configuration"); + return -1; + } + + /* each VPORT can have several VPORT PQ IDs for + * different TCs + */ + for (tc = 0; tc < NUM_OF_TCS; tc++) { + u16 vport_pq_id = pq_ids[tc]; + + if (vport_pq_id != QM_INVALID_PQ_ID) { + STORE_RT_REG(p_hwfn, + QM_REG_WFQVPWEIGHT_RT_OFFSET + + vport_pq_id, inc_val); + STORE_RT_REG(p_hwfn, temp + vport_pq_id, + QM_WFQ_UPPER_BOUND | + QM_WFQ_CRD_REG_SIGN_BIT); + STORE_RT_REG(p_hwfn, + QM_REG_WFQVPCRD_RT_OFFSET + + vport_pq_id, + QM_WFQ_INIT_CRD(inc_val) | + QM_WFQ_CRD_REG_SIGN_BIT); + } + } + } + + return 0; +} + +static int qed_vport_rl_rt_init(struct qed_hwfn *p_hwfn, + u8 start_vport, + u8 num_vports, + struct init_qm_vport_params *vport_params) +{ + u8 i, vport_id; + + /* go over all PF VPORTs */ + for (i = 0, vport_id = start_vport; i < num_vports; i++, vport_id++) { + u32 inc_val = QM_RL_INC_VAL(vport_params[i].vport_rl); + + if (inc_val > QM_RL_MAX_INC_VAL) { + DP_NOTICE(p_hwfn, + "Invalid VPORT rate-limit configuration"); + return -1; + } + + STORE_RT_REG(p_hwfn, + QM_REG_RLGLBLCRD_RT_OFFSET + vport_id, + QM_RL_CRD_REG_SIGN_BIT); + STORE_RT_REG(p_hwfn, + QM_REG_RLGLBLUPPERBOUND_RT_OFFSET + vport_id, + QM_RL_UPPER_BOUND | QM_RL_CRD_REG_SIGN_BIT); + STORE_RT_REG(p_hwfn, + QM_REG_RLGLBLINCVAL_RT_OFFSET + vport_id, + inc_val); + } + + return 0; +} + +static bool qed_poll_on_qm_cmd_ready(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt) +{ + u32 reg_val, i; + + for (i = 0, reg_val = 0; i < QM_STOP_CMD_MAX_POLL_COUNT && reg_val == 0; + i++) { + udelay(QM_STOP_CMD_POLL_PERIOD_US); + reg_val = qed_rd(p_hwfn, p_ptt, QM_REG_SDMCMDREADY); + } + + /* check if timeout while waiting for SDM command ready */ + if (i == QM_STOP_CMD_MAX_POLL_COUNT) { + DP_VERBOSE(p_hwfn, NETIF_MSG_HW, + "Timeout when waiting for QM SDM command ready signal\n"); + return false; + } + + return true; +} + +static bool qed_send_qm_cmd(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u32 cmd_addr, + u32 cmd_data_lsb, + u32 cmd_data_msb) +{ + if (!qed_poll_on_qm_cmd_ready(p_hwfn, p_ptt)) + return false; + + qed_wr(p_hwfn, p_ptt, QM_REG_SDMCMDADDR, cmd_addr); + qed_wr(p_hwfn, p_ptt, QM_REG_SDMCMDDATALSB, cmd_data_lsb); + qed_wr(p_hwfn, p_ptt, QM_REG_SDMCMDDATAMSB, cmd_data_msb); + qed_wr(p_hwfn, p_ptt, QM_REG_SDMCMDGO, 1); + qed_wr(p_hwfn, p_ptt, QM_REG_SDMCMDGO, 0); + + return qed_poll_on_qm_cmd_ready(p_hwfn, p_ptt); +} + +/******************** INTERFACE IMPLEMENTATION *********************/ +u32 qed_qm_pf_mem_size(u8 pf_id, + u32 num_pf_cids, + u32 num_vf_cids, + u32 num_tids, + u16 num_pf_pqs, + u16 num_vf_pqs) +{ + return QM_PQ_MEM_4KB(num_pf_cids) * num_pf_pqs + + QM_PQ_MEM_4KB(num_vf_cids) * num_vf_pqs + + QM_PQ_MEM_4KB(num_pf_cids + num_tids) * QM_OTHER_PQS_PER_PF; +} + +int qed_qm_common_rt_init( + struct qed_hwfn *p_hwfn, + struct qed_qm_common_rt_init_params *p_params) +{ + /* init AFullOprtnstcCrdMask */ + u32 mask = (QM_OPPOR_LINE_VOQ_DEF << + QM_RF_OPPORTUNISTIC_MASK_LINEVOQ_SHIFT) | + (QM_BYTE_CRD_EN << QM_RF_OPPORTUNISTIC_MASK_BYTEVOQ_SHIFT) | + (p_params->pf_wfq_en << + QM_RF_OPPORTUNISTIC_MASK_PFWFQ_SHIFT) | + (p_params->vport_wfq_en << + QM_RF_OPPORTUNISTIC_MASK_VPWFQ_SHIFT) | + (p_params->pf_rl_en << + QM_RF_OPPORTUNISTIC_MASK_PFRL_SHIFT) | + (p_params->vport_rl_en << + QM_RF_OPPORTUNISTIC_MASK_VPQCNRL_SHIFT) | + (QM_OPPOR_FW_STOP_DEF << + QM_RF_OPPORTUNISTIC_MASK_FWPAUSE_SHIFT) | + (QM_OPPOR_PQ_EMPTY_DEF << + QM_RF_OPPORTUNISTIC_MASK_QUEUEEMPTY_SHIFT); + + STORE_RT_REG(p_hwfn, QM_REG_AFULLOPRTNSTCCRDMASK_RT_OFFSET, mask); + qed_enable_pf_rl(p_hwfn, p_params->pf_rl_en); + qed_enable_pf_wfq(p_hwfn, p_params->pf_wfq_en); + qed_enable_vport_rl(p_hwfn, p_params->vport_rl_en); + qed_enable_vport_wfq(p_hwfn, p_params->vport_wfq_en); + qed_cmdq_lines_rt_init(p_hwfn, + p_params->max_ports_per_engine, + p_params->max_phys_tcs_per_port, + p_params->port_params); + qed_btb_blocks_rt_init(p_hwfn, + p_params->max_ports_per_engine, + p_params->max_phys_tcs_per_port, + p_params->port_params); + return 0; +} + +int qed_qm_pf_rt_init(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + struct qed_qm_pf_rt_init_params *p_params) +{ + struct init_qm_vport_params *vport_params = p_params->vport_params; + u32 other_mem_size_4kb = QM_PQ_MEM_4KB(p_params->num_pf_cids + + p_params->num_tids) * + QM_OTHER_PQS_PER_PF; + u8 tc, i; + + /* clear first Tx PQ ID array for each VPORT */ + for (i = 0; i < p_params->num_vports; i++) + for (tc = 0; tc < NUM_OF_TCS; tc++) + vport_params[i].first_tx_pq_id[tc] = QM_INVALID_PQ_ID; + + /* map Other PQs (if any) */ + qed_other_pq_map_rt_init(p_hwfn, p_params->port_id, p_params->pf_id, + p_params->num_pf_cids, p_params->num_tids, 0); + + /* map Tx PQs */ + qed_tx_pq_map_rt_init(p_hwfn, p_ptt, p_params, other_mem_size_4kb); + + if (p_params->pf_wfq) + if (qed_pf_wfq_rt_init(p_hwfn, p_params)) + return -1; + + if (qed_pf_rl_rt_init(p_hwfn, p_params->pf_id, p_params->pf_rl)) + return -1; + + if (qed_vp_wfq_rt_init(p_hwfn, p_params->start_vport, + p_params->num_vports, vport_params)) + return -1; + + if (qed_vport_rl_rt_init(p_hwfn, p_params->start_vport, + p_params->num_vports, vport_params)) + return -1; + + return 0; +} + +int qed_init_pf_rl(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u8 pf_id, + u32 pf_rl) +{ + u32 inc_val = QM_RL_INC_VAL(pf_rl); + + if (inc_val > QM_RL_MAX_INC_VAL) { + DP_NOTICE(p_hwfn, "Invalid PF rate limit configuration"); + return -1; + } + + qed_wr(p_hwfn, p_ptt, + QM_REG_RLPFCRD + pf_id * 4, + QM_RL_CRD_REG_SIGN_BIT); + qed_wr(p_hwfn, p_ptt, QM_REG_RLPFINCVAL + pf_id * 4, inc_val); + + return 0; +} + +int qed_init_vport_rl(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u8 vport_id, + u32 vport_rl) +{ + u32 inc_val = QM_RL_INC_VAL(vport_rl); + + if (inc_val > QM_RL_MAX_INC_VAL) { + DP_NOTICE(p_hwfn, "Invalid VPORT rate-limit configuration"); + return -1; + } + + qed_wr(p_hwfn, p_ptt, + QM_REG_RLGLBLCRD + vport_id * 4, + QM_RL_CRD_REG_SIGN_BIT); + qed_wr(p_hwfn, p_ptt, QM_REG_RLGLBLINCVAL + vport_id * 4, inc_val); + + return 0; +} + +bool qed_send_qm_stop_cmd(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + bool is_release_cmd, + bool is_tx_pq, + u16 start_pq, + u16 num_pqs) +{ + u32 cmd_arr[QM_CMD_STRUCT_SIZE(QM_STOP_CMD)] = { 0 }; + u32 pq_mask = 0, last_pq = start_pq + num_pqs - 1, pq_id; + + /* set command's PQ type */ + QM_CMD_SET_FIELD(cmd_arr, QM_STOP_CMD, PQ_TYPE, is_tx_pq ? 0 : 1); + + for (pq_id = start_pq; pq_id <= last_pq; pq_id++) { + /* set PQ bit in mask (stop command only) */ + if (!is_release_cmd) + pq_mask |= (1 << (pq_id % QM_STOP_PQ_MASK_WIDTH)); + + /* if last PQ or end of PQ mask, write command */ + if ((pq_id == last_pq) || + (pq_id % QM_STOP_PQ_MASK_WIDTH == + (QM_STOP_PQ_MASK_WIDTH - 1))) { + QM_CMD_SET_FIELD(cmd_arr, QM_STOP_CMD, + PAUSE_MASK, pq_mask); + QM_CMD_SET_FIELD(cmd_arr, QM_STOP_CMD, + GROUP_ID, + pq_id / QM_STOP_PQ_MASK_WIDTH); + if (!qed_send_qm_cmd(p_hwfn, p_ptt, QM_STOP_CMD_ADDR, + cmd_arr[0], cmd_arr[1])) + return false; + pq_mask = 0; + } + } + + return true; +} diff --git a/drivers/net/ethernet/qlogic/qed/qed_init_ops.c b/drivers/net/ethernet/qlogic/qed/qed_init_ops.c new file mode 100644 index 000000000000..796f1390e598 --- /dev/null +++ b/drivers/net/ethernet/qlogic/qed/qed_init_ops.c @@ -0,0 +1,531 @@ +/* QLogic qed NIC Driver + * Copyright (c) 2015 QLogic Corporation + * + * This software is available under the terms of the GNU General Public License + * (GPL) Version 2, available from the file COPYING in the main directory of + * this source tree. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "qed.h" +#include "qed_hsi.h" +#include "qed_hw.h" +#include "qed_init_ops.h" +#include "qed_reg_addr.h" + +#define QED_INIT_MAX_POLL_COUNT 100 +#define QED_INIT_POLL_PERIOD_US 500 + +static u32 pxp_global_win[] = { + 0, + 0, + 0x1c02, /* win 2: addr=0x1c02000, size=4096 bytes */ + 0x1c80, /* win 3: addr=0x1c80000, size=4096 bytes */ + 0x1d00, /* win 4: addr=0x1d00000, size=4096 bytes */ + 0x1d01, /* win 5: addr=0x1d01000, size=4096 bytes */ + 0x1d80, /* win 6: addr=0x1d80000, size=4096 bytes */ + 0x1d81, /* win 7: addr=0x1d81000, size=4096 bytes */ + 0x1d82, /* win 8: addr=0x1d82000, size=4096 bytes */ + 0x1e00, /* win 9: addr=0x1e00000, size=4096 bytes */ + 0x1e80, /* win 10: addr=0x1e80000, size=4096 bytes */ + 0x1f00, /* win 11: addr=0x1f00000, size=4096 bytes */ + 0, + 0, + 0, + 0, + 0, + 0, + 0, +}; + +void qed_init_iro_array(struct qed_dev *cdev) +{ + cdev->iro_arr = iro_arr; +} + +/* Runtime configuration helpers */ +void qed_init_clear_rt_data(struct qed_hwfn *p_hwfn) +{ + int i; + + for (i = 0; i < RUNTIME_ARRAY_SIZE; i++) + p_hwfn->rt_data[i].b_valid = false; +} + +void qed_init_store_rt_reg(struct qed_hwfn *p_hwfn, + u32 rt_offset, + u32 val) +{ + p_hwfn->rt_data[rt_offset].init_val = val; + p_hwfn->rt_data[rt_offset].b_valid = true; +} + +void qed_init_store_rt_agg(struct qed_hwfn *p_hwfn, + u32 rt_offset, + u32 *val, + size_t size) +{ + size_t i; + + for (i = 0; i < size / sizeof(u32); i++) { + p_hwfn->rt_data[rt_offset + i].init_val = val[i]; + p_hwfn->rt_data[rt_offset + i].b_valid = true; + } +} + +static void qed_init_rt(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u32 addr, + u32 rt_offset, + u32 size) +{ + struct qed_rt_data *rt_data = p_hwfn->rt_data + rt_offset; + u32 i; + + for (i = 0; i < size; i++) { + if (!rt_data[i].b_valid) + continue; + qed_wr(p_hwfn, p_ptt, addr + (i << 2), rt_data[i].init_val); + } +} + +int qed_init_alloc(struct qed_hwfn *p_hwfn) +{ + struct qed_rt_data *rt_data; + + rt_data = kzalloc(sizeof(*rt_data) * RUNTIME_ARRAY_SIZE, GFP_ATOMIC); + if (!rt_data) + return -ENOMEM; + + p_hwfn->rt_data = rt_data; + + return 0; +} + +void qed_init_free(struct qed_hwfn *p_hwfn) +{ + kfree(p_hwfn->rt_data); + p_hwfn->rt_data = NULL; +} + +static int qed_init_array_dmae(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u32 addr, + u32 dmae_data_offset, + u32 size, + const u32 *buf, + bool b_must_dmae, + bool b_can_dmae) +{ + int rc = 0; + + /* Perform DMAE only for lengthy enough sections or for wide-bus */ + if (!b_can_dmae || (!b_must_dmae && (size < 16))) { + const u32 *data = buf + dmae_data_offset; + u32 i; + + for (i = 0; i < size; i++) + qed_wr(p_hwfn, p_ptt, addr + (i << 2), data[i]); + } else { + rc = qed_dmae_host2grc(p_hwfn, p_ptt, + (uintptr_t)(buf + dmae_data_offset), + addr, size, 0); + } + + return rc; +} + +static int qed_init_fill_dmae(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u32 addr, + u32 fill, + u32 fill_count) +{ + static u32 zero_buffer[DMAE_MAX_RW_SIZE]; + + memset(zero_buffer, 0, sizeof(u32) * DMAE_MAX_RW_SIZE); + + /* invoke the DMAE virtual/physical buffer API with + * 1. DMAE init channel + * 2. addr, + * 3. p_hwfb->temp_data, + * 4. fill_count + */ + + return qed_dmae_host2grc(p_hwfn, p_ptt, + (uintptr_t)(&zero_buffer[0]), + addr, fill_count, + QED_DMAE_FLAG_RW_REPL_SRC); +} + +static void qed_init_fill(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u32 addr, + u32 fill, + u32 fill_count) +{ + u32 i; + + for (i = 0; i < fill_count; i++, addr += sizeof(u32)) + qed_wr(p_hwfn, p_ptt, addr, fill); +} + +static int qed_init_cmd_array(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + struct init_write_op *cmd, + bool b_must_dmae, + bool b_can_dmae) +{ + u32 data = le32_to_cpu(cmd->data); + u32 addr = GET_FIELD(data, INIT_WRITE_OP_ADDRESS) << 2; + u32 dmae_array_offset = le32_to_cpu(cmd->args.array_offset); + u32 offset, output_len, input_len, max_size; + struct qed_dev *cdev = p_hwfn->cdev; + union init_array_hdr *hdr; + const u32 *array_data; + int rc = 0; + u32 size; + + array_data = cdev->fw_data->arr_data; + + hdr = (union init_array_hdr *)(array_data + + dmae_array_offset); + data = le32_to_cpu(hdr->raw.data); + switch (GET_FIELD(data, INIT_ARRAY_RAW_HDR_TYPE)) { + case INIT_ARR_ZIPPED: + offset = dmae_array_offset + 1; + input_len = GET_FIELD(data, + INIT_ARRAY_ZIPPED_HDR_ZIPPED_SIZE); + max_size = MAX_ZIPPED_SIZE * 4; + memset(p_hwfn->unzip_buf, 0, max_size); + + output_len = qed_unzip_data(p_hwfn, input_len, + (u8 *)&array_data[offset], + max_size, (u8 *)p_hwfn->unzip_buf); + if (output_len) { + rc = qed_init_array_dmae(p_hwfn, p_ptt, addr, 0, + output_len, + p_hwfn->unzip_buf, + b_must_dmae, b_can_dmae); + } else { + DP_NOTICE(p_hwfn, "Failed to unzip dmae data\n"); + rc = -EINVAL; + } + break; + case INIT_ARR_PATTERN: + { + u32 repeats = GET_FIELD(data, + INIT_ARRAY_PATTERN_HDR_REPETITIONS); + u32 i; + + size = GET_FIELD(data, INIT_ARRAY_PATTERN_HDR_PATTERN_SIZE); + + for (i = 0; i < repeats; i++, addr += size << 2) { + rc = qed_init_array_dmae(p_hwfn, p_ptt, addr, + dmae_array_offset + 1, + size, array_data, + b_must_dmae, b_can_dmae); + if (rc) + break; + } + break; + } + case INIT_ARR_STANDARD: + size = GET_FIELD(data, INIT_ARRAY_STANDARD_HDR_SIZE); + rc = qed_init_array_dmae(p_hwfn, p_ptt, addr, + dmae_array_offset + 1, + size, array_data, + b_must_dmae, b_can_dmae); + break; + } + + return rc; +} + +/* init_ops write command */ +static int qed_init_cmd_wr(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + struct init_write_op *cmd, + bool b_can_dmae) +{ + u32 data = le32_to_cpu(cmd->data); + u32 addr = GET_FIELD(data, INIT_WRITE_OP_ADDRESS) << 2; + bool b_must_dmae = GET_FIELD(data, INIT_WRITE_OP_WIDE_BUS); + union init_write_args *arg = &cmd->args; + int rc = 0; + + /* Sanitize */ + if (b_must_dmae && !b_can_dmae) { + DP_NOTICE(p_hwfn, + "Need to write to %08x for Wide-bus but DMAE isn't allowed\n", + addr); + return -EINVAL; + } + + switch (GET_FIELD(data, INIT_WRITE_OP_SOURCE)) { + case INIT_SRC_INLINE: + qed_wr(p_hwfn, p_ptt, addr, + le32_to_cpu(arg->inline_val)); + break; + case INIT_SRC_ZEROS: + if (b_must_dmae || + (b_can_dmae && (le32_to_cpu(arg->zeros_count) >= 64))) + rc = qed_init_fill_dmae(p_hwfn, p_ptt, addr, 0, + le32_to_cpu(arg->zeros_count)); + else + qed_init_fill(p_hwfn, p_ptt, addr, 0, + le32_to_cpu(arg->zeros_count)); + break; + case INIT_SRC_ARRAY: + rc = qed_init_cmd_array(p_hwfn, p_ptt, cmd, + b_must_dmae, b_can_dmae); + break; + case INIT_SRC_RUNTIME: + qed_init_rt(p_hwfn, p_ptt, addr, + le16_to_cpu(arg->runtime.offset), + le16_to_cpu(arg->runtime.size)); + break; + } + + return rc; +} + +static inline bool comp_eq(u32 val, u32 expected_val) +{ + return val == expected_val; +} + +static inline bool comp_and(u32 val, u32 expected_val) +{ + return (val & expected_val) == expected_val; +} + +static inline bool comp_or(u32 val, u32 expected_val) +{ + return (val | expected_val) > 0; +} + +/* init_ops read/poll commands */ +static void qed_init_cmd_rd(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + struct init_read_op *cmd) +{ + u32 data = le32_to_cpu(cmd->op_data); + u32 addr = GET_FIELD(data, INIT_READ_OP_ADDRESS) << 2; + + bool (*comp_check)(u32 val, + u32 expected_val); + u32 delay = QED_INIT_POLL_PERIOD_US, val; + + val = qed_rd(p_hwfn, p_ptt, addr); + + data = le32_to_cpu(cmd->op_data); + if (GET_FIELD(data, INIT_READ_OP_POLL)) { + int i; + + switch (GET_FIELD(data, INIT_READ_OP_POLL_COMP)) { + case INIT_COMPARISON_EQ: + comp_check = comp_eq; + break; + case INIT_COMPARISON_OR: + comp_check = comp_or; + break; + case INIT_COMPARISON_AND: + comp_check = comp_and; + break; + default: + comp_check = NULL; + DP_ERR(p_hwfn, "Invalid poll comparison type %08x\n", + data); + return; + } + + for (i = 0; + i < QED_INIT_MAX_POLL_COUNT && + !comp_check(val, le32_to_cpu(cmd->expected_val)); + i++) { + udelay(delay); + val = qed_rd(p_hwfn, p_ptt, addr); + } + + if (i == QED_INIT_MAX_POLL_COUNT) + DP_ERR(p_hwfn, + "Timeout when polling reg: 0x%08x [ Waiting-for: %08x Got: %08x (comparsion %08x)]\n", + addr, le32_to_cpu(cmd->expected_val), + val, data); + } +} + +/* init_ops callbacks entry point */ +static void qed_init_cmd_cb(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + struct init_callback_op *p_cmd) +{ + DP_NOTICE(p_hwfn, "Currently init values have no need of callbacks\n"); +} + +static u8 qed_init_cmd_mode_match(struct qed_hwfn *p_hwfn, + u16 *offset, + int modes) +{ + struct qed_dev *cdev = p_hwfn->cdev; + const u8 *modes_tree_buf; + u8 arg1, arg2, tree_val; + + modes_tree_buf = cdev->fw_data->modes_tree_buf; + tree_val = modes_tree_buf[(*offset)++]; + switch (tree_val) { + case INIT_MODE_OP_NOT: + return qed_init_cmd_mode_match(p_hwfn, offset, modes) ^ 1; + case INIT_MODE_OP_OR: + arg1 = qed_init_cmd_mode_match(p_hwfn, offset, modes); + arg2 = qed_init_cmd_mode_match(p_hwfn, offset, modes); + return arg1 | arg2; + case INIT_MODE_OP_AND: + arg1 = qed_init_cmd_mode_match(p_hwfn, offset, modes); + arg2 = qed_init_cmd_mode_match(p_hwfn, offset, modes); + return arg1 & arg2; + default: + tree_val -= MAX_INIT_MODE_OPS; + return (modes & (1 << tree_val)) ? 1 : 0; + } +} + +static u32 qed_init_cmd_mode(struct qed_hwfn *p_hwfn, + struct init_if_mode_op *p_cmd, + int modes) +{ + u16 offset = le16_to_cpu(p_cmd->modes_buf_offset); + + if (qed_init_cmd_mode_match(p_hwfn, &offset, modes)) + return 0; + else + return GET_FIELD(le32_to_cpu(p_cmd->op_data), + INIT_IF_MODE_OP_CMD_OFFSET); +} + +static u32 qed_init_cmd_phase(struct qed_hwfn *p_hwfn, + struct init_if_phase_op *p_cmd, + u32 phase, + u32 phase_id) +{ + u32 data = le32_to_cpu(p_cmd->phase_data); + u32 op_data = le32_to_cpu(p_cmd->op_data); + + if (!(GET_FIELD(data, INIT_IF_PHASE_OP_PHASE) == phase && + (GET_FIELD(data, INIT_IF_PHASE_OP_PHASE_ID) == ANY_PHASE_ID || + GET_FIELD(data, INIT_IF_PHASE_OP_PHASE_ID) == phase_id))) + return GET_FIELD(op_data, INIT_IF_PHASE_OP_CMD_OFFSET); + else + return 0; +} + +int qed_init_run(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + int phase, + int phase_id, + int modes) +{ + struct qed_dev *cdev = p_hwfn->cdev; + u32 cmd_num, num_init_ops; + union init_op *init_ops; + bool b_dmae = false; + int rc = 0; + + num_init_ops = cdev->fw_data->init_ops_size; + init_ops = cdev->fw_data->init_ops; + + p_hwfn->unzip_buf = kzalloc(MAX_ZIPPED_SIZE * 4, GFP_ATOMIC); + if (!p_hwfn->unzip_buf) { + DP_NOTICE(p_hwfn, "Failed to allocate unzip buffer\n"); + return -ENOMEM; + } + + for (cmd_num = 0; cmd_num < num_init_ops; cmd_num++) { + union init_op *cmd = &init_ops[cmd_num]; + u32 data = le32_to_cpu(cmd->raw.op_data); + + switch (GET_FIELD(data, INIT_CALLBACK_OP_OP)) { + case INIT_OP_WRITE: + rc = qed_init_cmd_wr(p_hwfn, p_ptt, &cmd->write, + b_dmae); + break; + case INIT_OP_READ: + qed_init_cmd_rd(p_hwfn, p_ptt, &cmd->read); + break; + case INIT_OP_IF_MODE: + cmd_num += qed_init_cmd_mode(p_hwfn, &cmd->if_mode, + modes); + break; + case INIT_OP_IF_PHASE: + cmd_num += qed_init_cmd_phase(p_hwfn, &cmd->if_phase, + phase, phase_id); + b_dmae = GET_FIELD(data, INIT_IF_PHASE_OP_DMAE_ENABLE); + break; + case INIT_OP_DELAY: + /* qed_init_run is always invoked from + * sleep-able context + */ + udelay(le32_to_cpu(cmd->delay.delay)); + break; + + case INIT_OP_CALLBACK: + qed_init_cmd_cb(p_hwfn, p_ptt, &cmd->callback); + break; + } + + if (rc) + break; + } + + kfree(p_hwfn->unzip_buf); + return rc; +} + +void qed_gtt_init(struct qed_hwfn *p_hwfn) +{ + u32 gtt_base; + u32 i; + + /* Set the global windows */ + gtt_base = PXP_PF_WINDOW_ADMIN_START + PXP_PF_WINDOW_ADMIN_GLOBAL_START; + + for (i = 0; i < ARRAY_SIZE(pxp_global_win); i++) + if (pxp_global_win[i]) + REG_WR(p_hwfn, gtt_base + i * PXP_GLOBAL_ENTRY_SIZE, + pxp_global_win[i]); +} + +int qed_init_fw_data(struct qed_dev *cdev, + const u8 *data) +{ + struct qed_fw_data *fw = cdev->fw_data; + struct bin_buffer_hdr *buf_hdr; + u32 offset, len; + + if (!data) { + DP_NOTICE(cdev, "Invalid fw data\n"); + return -EINVAL; + } + + buf_hdr = (struct bin_buffer_hdr *)data; + + offset = buf_hdr[BIN_BUF_INIT_CMD].offset; + fw->init_ops = (union init_op *)(data + offset); + + offset = buf_hdr[BIN_BUF_INIT_VAL].offset; + fw->arr_data = (u32 *)(data + offset); + + offset = buf_hdr[BIN_BUF_INIT_MODE_TREE].offset; + fw->modes_tree_buf = (u8 *)(data + offset); + len = buf_hdr[BIN_BUF_INIT_CMD].length; + fw->init_ops_size = len / sizeof(struct init_raw_op); + + return 0; +} diff --git a/drivers/net/ethernet/qlogic/qed/qed_init_ops.h b/drivers/net/ethernet/qlogic/qed/qed_init_ops.h new file mode 100644 index 000000000000..1e832049983d --- /dev/null +++ b/drivers/net/ethernet/qlogic/qed/qed_init_ops.h @@ -0,0 +1,110 @@ +/* QLogic qed NIC Driver + * Copyright (c) 2015 QLogic Corporation + * + * This software is available under the terms of the GNU General Public License + * (GPL) Version 2, available from the file COPYING in the main directory of + * this source tree. + */ + +#ifndef _QED_INIT_OPS_H +#define _QED_INIT_OPS_H + +#include +#include +#include "qed.h" + +/** + * @brief qed_init_iro_array - init iro_arr. + * + * + * @param cdev + */ +void qed_init_iro_array(struct qed_dev *cdev); + +/** + * @brief qed_init_run - Run the init-sequence. + * + * + * @param p_hwfn + * @param p_ptt + * @param phase + * @param phase_id + * @param modes + * @return _qed_status_t + */ +int qed_init_run(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + int phase, + int phase_id, + int modes); + +/** + * @brief qed_init_hwfn_allocate - Allocate RT array, Store 'values' ptrs. + * + * + * @param p_hwfn + * + * @return _qed_status_t + */ +int qed_init_alloc(struct qed_hwfn *p_hwfn); + +/** + * @brief qed_init_hwfn_deallocate + * + * + * @param p_hwfn + */ +void qed_init_free(struct qed_hwfn *p_hwfn); + +/** + * @brief qed_init_clear_rt_data - Clears the runtime init array. + * + * + * @param p_hwfn + */ +void qed_init_clear_rt_data(struct qed_hwfn *p_hwfn); + +/** + * @brief qed_init_store_rt_reg - Store a configuration value in the RT array. + * + * + * @param p_hwfn + * @param rt_offset + * @param val + */ +void qed_init_store_rt_reg(struct qed_hwfn *p_hwfn, + u32 rt_offset, + u32 val); + +#define STORE_RT_REG(hwfn, offset, val) \ + qed_init_store_rt_reg(hwfn, offset, val) + +#define OVERWRITE_RT_REG(hwfn, offset, val) \ + qed_init_store_rt_reg(hwfn, offset, val) + +/** + * @brief + * + * + * @param p_hwfn + * @param rt_offset + * @param val + * @param size + */ +void qed_init_store_rt_agg(struct qed_hwfn *p_hwfn, + u32 rt_offset, + u32 *val, + size_t size); + +#define STORE_RT_REG_AGG(hwfn, offset, val) \ + qed_init_store_rt_agg(hwfn, offset, (u32 *)&val, sizeof(val)) + +/** + * @brief + * Initialize GTT global windows and set admin window + * related params of GTT/PTT to default values. + * + * @param p_hwfn + */ +void qed_gtt_init(struct qed_hwfn *p_hwfn); +#endif diff --git a/drivers/net/ethernet/qlogic/qed/qed_int.c b/drivers/net/ethernet/qlogic/qed/qed_int.c new file mode 100644 index 000000000000..37d926a5fae5 --- /dev/null +++ b/drivers/net/ethernet/qlogic/qed/qed_int.c @@ -0,0 +1,802 @@ +/* QLogic qed NIC Driver + * Copyright (c) 2015 QLogic Corporation + * + * This software is available under the terms of the GNU General Public License + * (GPL) Version 2, available from the file COPYING in the main directory of + * this source tree. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "qed.h" +#include "qed_hsi.h" +#include "qed_hw.h" +#include "qed_init_ops.h" +#include "qed_int.h" +#include "qed_mcp.h" +#include "qed_reg_addr.h" +#include "qed_sp.h" + +struct qed_pi_info { + qed_int_comp_cb_t comp_cb; + void *cookie; +}; + +struct qed_sb_sp_info { + struct qed_sb_info sb_info; + + /* per protocol index data */ + struct qed_pi_info pi_info_arr[PIS_PER_SB]; +}; + +void qed_int_sp_dpc(unsigned long hwfn_cookie) +{ + struct qed_hwfn *p_hwfn = (struct qed_hwfn *)hwfn_cookie; + struct qed_pi_info *pi_info = NULL; + struct qed_sb_info *sb_info; + int arr_size; + u16 rc = 0; + + if (!p_hwfn) { + DP_ERR(p_hwfn->cdev, "DPC called - no hwfn!\n"); + return; + } + + if (!p_hwfn->p_sp_sb) { + DP_ERR(p_hwfn->cdev, "DPC called - no p_sp_sb\n"); + return; + } + + sb_info = &p_hwfn->p_sp_sb->sb_info; + arr_size = ARRAY_SIZE(p_hwfn->p_sp_sb->pi_info_arr); + if (!sb_info) { + DP_ERR(p_hwfn->cdev, + "Status block is NULL - cannot ack interrupts\n"); + return; + } + + DP_VERBOSE(p_hwfn, NETIF_MSG_INTR, "DPC Called! (hwfn %p %d)\n", + p_hwfn, p_hwfn->my_id); + + /* Disable ack for def status block. Required both for msix + + * inta in non-mask mode, in inta does no harm. + */ + qed_sb_ack(sb_info, IGU_INT_DISABLE, 0); + + /* Gather Interrupts/Attentions information */ + if (!sb_info->sb_virt) { + DP_ERR( + p_hwfn->cdev, + "Interrupt Status block is NULL - cannot check for new interrupts!\n"); + } else { + u32 tmp_index = sb_info->sb_ack; + + rc = qed_sb_update_sb_idx(sb_info); + DP_VERBOSE(p_hwfn->cdev, NETIF_MSG_INTR, + "Interrupt indices: 0x%08x --> 0x%08x\n", + tmp_index, sb_info->sb_ack); + } + + /* Check if we expect interrupts at this time. if not just ack them */ + if (!(rc & QED_SB_EVENT_MASK)) { + qed_sb_ack(sb_info, IGU_INT_ENABLE, 1); + return; + } + + /* Check the validity of the DPC ptt. If not ack interrupts and fail */ + if (!p_hwfn->p_dpc_ptt) { + DP_NOTICE(p_hwfn->cdev, "Failed to allocate PTT\n"); + qed_sb_ack(sb_info, IGU_INT_ENABLE, 1); + return; + } + + if (rc & QED_SB_IDX) { + int pi; + + /* Look for a free index */ + for (pi = 0; pi < arr_size; pi++) { + pi_info = &p_hwfn->p_sp_sb->pi_info_arr[pi]; + if (pi_info->comp_cb) + pi_info->comp_cb(p_hwfn, pi_info->cookie); + } + } + + qed_sb_ack(sb_info, IGU_INT_ENABLE, 1); +} + +/* coalescing timeout = timeset << (timer_res + 1) */ +#define QED_CAU_DEF_RX_USECS 24 +#define QED_CAU_DEF_TX_USECS 48 + +void qed_init_cau_sb_entry(struct qed_hwfn *p_hwfn, + struct cau_sb_entry *p_sb_entry, + u8 pf_id, + u16 vf_number, + u8 vf_valid) +{ + u32 cau_state; + + memset(p_sb_entry, 0, sizeof(*p_sb_entry)); + + SET_FIELD(p_sb_entry->params, CAU_SB_ENTRY_PF_NUMBER, pf_id); + SET_FIELD(p_sb_entry->params, CAU_SB_ENTRY_VF_NUMBER, vf_number); + SET_FIELD(p_sb_entry->params, CAU_SB_ENTRY_VF_VALID, vf_valid); + SET_FIELD(p_sb_entry->params, CAU_SB_ENTRY_SB_TIMESET0, 0x7F); + SET_FIELD(p_sb_entry->params, CAU_SB_ENTRY_SB_TIMESET1, 0x7F); + + /* setting the time resultion to a fixed value ( = 1) */ + SET_FIELD(p_sb_entry->params, CAU_SB_ENTRY_TIMER_RES0, + QED_CAU_DEF_RX_TIMER_RES); + SET_FIELD(p_sb_entry->params, CAU_SB_ENTRY_TIMER_RES1, + QED_CAU_DEF_TX_TIMER_RES); + + cau_state = CAU_HC_DISABLE_STATE; + + if (p_hwfn->cdev->int_coalescing_mode == QED_COAL_MODE_ENABLE) { + cau_state = CAU_HC_ENABLE_STATE; + if (!p_hwfn->cdev->rx_coalesce_usecs) + p_hwfn->cdev->rx_coalesce_usecs = + QED_CAU_DEF_RX_USECS; + if (!p_hwfn->cdev->tx_coalesce_usecs) + p_hwfn->cdev->tx_coalesce_usecs = + QED_CAU_DEF_TX_USECS; + } + + SET_FIELD(p_sb_entry->data, CAU_SB_ENTRY_STATE0, cau_state); + SET_FIELD(p_sb_entry->data, CAU_SB_ENTRY_STATE1, cau_state); +} + +void qed_int_cau_conf_sb(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + dma_addr_t sb_phys, + u16 igu_sb_id, + u16 vf_number, + u8 vf_valid) +{ + struct cau_sb_entry sb_entry; + u32 val; + + qed_init_cau_sb_entry(p_hwfn, &sb_entry, p_hwfn->rel_pf_id, + vf_number, vf_valid); + + if (p_hwfn->hw_init_done) { + val = CAU_REG_SB_ADDR_MEMORY + igu_sb_id * sizeof(u64); + qed_wr(p_hwfn, p_ptt, val, lower_32_bits(sb_phys)); + qed_wr(p_hwfn, p_ptt, val + sizeof(u32), + upper_32_bits(sb_phys)); + + val = CAU_REG_SB_VAR_MEMORY + igu_sb_id * sizeof(u64); + qed_wr(p_hwfn, p_ptt, val, sb_entry.data); + qed_wr(p_hwfn, p_ptt, val + sizeof(u32), sb_entry.params); + } else { + /* Initialize Status Block Address */ + STORE_RT_REG_AGG(p_hwfn, + CAU_REG_SB_ADDR_MEMORY_RT_OFFSET + + igu_sb_id * 2, + sb_phys); + + STORE_RT_REG_AGG(p_hwfn, + CAU_REG_SB_VAR_MEMORY_RT_OFFSET + + igu_sb_id * 2, + sb_entry); + } + + /* Configure pi coalescing if set */ + if (p_hwfn->cdev->int_coalescing_mode == QED_COAL_MODE_ENABLE) { + u8 timeset = p_hwfn->cdev->rx_coalesce_usecs >> + (QED_CAU_DEF_RX_TIMER_RES + 1); + u8 num_tc = 1, i; + + qed_int_cau_conf_pi(p_hwfn, p_ptt, igu_sb_id, RX_PI, + QED_COAL_RX_STATE_MACHINE, + timeset); + + timeset = p_hwfn->cdev->tx_coalesce_usecs >> + (QED_CAU_DEF_TX_TIMER_RES + 1); + + for (i = 0; i < num_tc; i++) { + qed_int_cau_conf_pi(p_hwfn, p_ptt, + igu_sb_id, TX_PI(i), + QED_COAL_TX_STATE_MACHINE, + timeset); + } + } +} + +void qed_int_cau_conf_pi(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u16 igu_sb_id, + u32 pi_index, + enum qed_coalescing_fsm coalescing_fsm, + u8 timeset) +{ + struct cau_pi_entry pi_entry; + u32 sb_offset; + u32 pi_offset; + + sb_offset = igu_sb_id * PIS_PER_SB; + memset(&pi_entry, 0, sizeof(struct cau_pi_entry)); + + SET_FIELD(pi_entry.prod, CAU_PI_ENTRY_PI_TIMESET, timeset); + if (coalescing_fsm == QED_COAL_RX_STATE_MACHINE) + SET_FIELD(pi_entry.prod, CAU_PI_ENTRY_FSM_SEL, 0); + else + SET_FIELD(pi_entry.prod, CAU_PI_ENTRY_FSM_SEL, 1); + + pi_offset = sb_offset + pi_index; + if (p_hwfn->hw_init_done) { + qed_wr(p_hwfn, p_ptt, + CAU_REG_PI_MEMORY + pi_offset * sizeof(u32), + *((u32 *)&(pi_entry))); + } else { + STORE_RT_REG(p_hwfn, + CAU_REG_PI_MEMORY_RT_OFFSET + pi_offset, + *((u32 *)&(pi_entry))); + } +} + +void qed_int_sb_setup(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + struct qed_sb_info *sb_info) +{ + /* zero status block and ack counter */ + sb_info->sb_ack = 0; + memset(sb_info->sb_virt, 0, sizeof(*sb_info->sb_virt)); + + qed_int_cau_conf_sb(p_hwfn, p_ptt, sb_info->sb_phys, + sb_info->igu_sb_id, 0, 0); +} + +/** + * @brief qed_get_igu_sb_id - given a sw sb_id return the + * igu_sb_id + * + * @param p_hwfn + * @param sb_id + * + * @return u16 + */ +static u16 qed_get_igu_sb_id(struct qed_hwfn *p_hwfn, + u16 sb_id) +{ + u16 igu_sb_id; + + /* Assuming continuous set of IGU SBs dedicated for given PF */ + if (sb_id == QED_SP_SB_ID) + igu_sb_id = p_hwfn->hw_info.p_igu_info->igu_dsb_id; + else + igu_sb_id = sb_id + p_hwfn->hw_info.p_igu_info->igu_base_sb; + + DP_VERBOSE(p_hwfn, NETIF_MSG_INTR, "SB [%s] index is 0x%04x\n", + (sb_id == QED_SP_SB_ID) ? "DSB" : "non-DSB", igu_sb_id); + + return igu_sb_id; +} + +int qed_int_sb_init(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + struct qed_sb_info *sb_info, + void *sb_virt_addr, + dma_addr_t sb_phy_addr, + u16 sb_id) +{ + sb_info->sb_virt = sb_virt_addr; + sb_info->sb_phys = sb_phy_addr; + + sb_info->igu_sb_id = qed_get_igu_sb_id(p_hwfn, sb_id); + + if (sb_id != QED_SP_SB_ID) { + p_hwfn->sbs_info[sb_id] = sb_info; + p_hwfn->num_sbs++; + } + + sb_info->cdev = p_hwfn->cdev; + + /* The igu address will hold the absolute address that needs to be + * written to for a specific status block + */ + sb_info->igu_addr = (u8 __iomem *)p_hwfn->regview + + GTT_BAR0_MAP_REG_IGU_CMD + + (sb_info->igu_sb_id << 3); + + sb_info->flags |= QED_SB_INFO_INIT; + + qed_int_sb_setup(p_hwfn, p_ptt, sb_info); + + return 0; +} + +int qed_int_sb_release(struct qed_hwfn *p_hwfn, + struct qed_sb_info *sb_info, + u16 sb_id) +{ + if (sb_id == QED_SP_SB_ID) { + DP_ERR(p_hwfn, "Do Not free sp sb using this function"); + return -EINVAL; + } + + /* zero status block and ack counter */ + sb_info->sb_ack = 0; + memset(sb_info->sb_virt, 0, sizeof(*sb_info->sb_virt)); + + p_hwfn->sbs_info[sb_id] = NULL; + p_hwfn->num_sbs--; + + return 0; +} + +static void qed_int_sp_sb_free(struct qed_hwfn *p_hwfn) +{ + struct qed_sb_sp_info *p_sb = p_hwfn->p_sp_sb; + + if (p_sb) { + if (p_sb->sb_info.sb_virt) + dma_free_coherent(&p_hwfn->cdev->pdev->dev, + SB_ALIGNED_SIZE(p_hwfn), + p_sb->sb_info.sb_virt, + p_sb->sb_info.sb_phys); + kfree(p_sb); + } +} + +static int qed_int_sp_sb_alloc(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt) +{ + struct qed_sb_sp_info *p_sb; + dma_addr_t p_phys = 0; + void *p_virt; + + /* SB struct */ + p_sb = kmalloc(sizeof(*p_sb), GFP_ATOMIC); + if (!p_sb) { + DP_NOTICE(p_hwfn, "Failed to allocate `struct qed_sb_info'\n"); + return -ENOMEM; + } + + /* SB ring */ + p_virt = dma_alloc_coherent(&p_hwfn->cdev->pdev->dev, + SB_ALIGNED_SIZE(p_hwfn), + &p_phys, GFP_KERNEL); + if (!p_virt) { + DP_NOTICE(p_hwfn, "Failed to allocate status block\n"); + kfree(p_sb); + return -ENOMEM; + } + + /* Status Block setup */ + p_hwfn->p_sp_sb = p_sb; + qed_int_sb_init(p_hwfn, p_ptt, &p_sb->sb_info, p_virt, + p_phys, QED_SP_SB_ID); + + memset(p_sb->pi_info_arr, 0, sizeof(p_sb->pi_info_arr)); + + return 0; +} + +static void qed_int_sp_sb_setup(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt) +{ + if (!p_hwfn) + return; + + if (p_hwfn->p_sp_sb) + qed_int_sb_setup(p_hwfn, p_ptt, &p_hwfn->p_sp_sb->sb_info); + else + DP_NOTICE(p_hwfn->cdev, + "Failed to setup Slow path status block - NULL pointer\n"); +} + +int qed_int_register_cb(struct qed_hwfn *p_hwfn, + qed_int_comp_cb_t comp_cb, + void *cookie, + u8 *sb_idx, + __le16 **p_fw_cons) +{ + struct qed_sb_sp_info *p_sp_sb = p_hwfn->p_sp_sb; + int qed_status = -ENOMEM; + u8 pi; + + /* Look for a free index */ + for (pi = 0; pi < ARRAY_SIZE(p_sp_sb->pi_info_arr); pi++) { + if (!p_sp_sb->pi_info_arr[pi].comp_cb) { + p_sp_sb->pi_info_arr[pi].comp_cb = comp_cb; + p_sp_sb->pi_info_arr[pi].cookie = cookie; + *sb_idx = pi; + *p_fw_cons = &p_sp_sb->sb_info.sb_virt->pi_array[pi]; + qed_status = 0; + break; + } + } + + return qed_status; +} + +int qed_int_unregister_cb(struct qed_hwfn *p_hwfn, u8 pi) +{ + struct qed_sb_sp_info *p_sp_sb = p_hwfn->p_sp_sb; + int qed_status = -ENOMEM; + + if (p_sp_sb->pi_info_arr[pi].comp_cb) { + p_sp_sb->pi_info_arr[pi].comp_cb = NULL; + p_sp_sb->pi_info_arr[pi].cookie = NULL; + qed_status = 0; + } + + return qed_status; +} + +u16 qed_int_get_sp_sb_id(struct qed_hwfn *p_hwfn) +{ + return p_hwfn->p_sp_sb->sb_info.igu_sb_id; +} + +void qed_int_igu_enable_int(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + enum qed_int_mode int_mode) +{ + u32 igu_pf_conf = IGU_PF_CONF_FUNC_EN; + + p_hwfn->cdev->int_mode = int_mode; + switch (p_hwfn->cdev->int_mode) { + case QED_INT_MODE_INTA: + igu_pf_conf |= IGU_PF_CONF_INT_LINE_EN; + igu_pf_conf |= IGU_PF_CONF_SINGLE_ISR_EN; + break; + + case QED_INT_MODE_MSI: + igu_pf_conf |= IGU_PF_CONF_MSI_MSIX_EN; + igu_pf_conf |= IGU_PF_CONF_SINGLE_ISR_EN; + break; + + case QED_INT_MODE_MSIX: + igu_pf_conf |= IGU_PF_CONF_MSI_MSIX_EN; + break; + case QED_INT_MODE_POLL: + break; + } + + qed_wr(p_hwfn, p_ptt, IGU_REG_PF_CONFIGURATION, igu_pf_conf); +} + +void qed_int_igu_enable(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + enum qed_int_mode int_mode) +{ + int i; + + p_hwfn->b_int_enabled = 1; + + /* Mask non-link attentions */ + for (i = 0; i < 9; i++) + qed_wr(p_hwfn, p_ptt, + MISC_REG_AEU_ENABLE1_IGU_OUT_0 + (i << 2), 0); + + /* Enable interrupt Generation */ + qed_int_igu_enable_int(p_hwfn, p_ptt, int_mode); + + /* Flush the writes to IGU */ + mmiowb(); +} + +void qed_int_igu_disable_int(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt) +{ + p_hwfn->b_int_enabled = 0; + + qed_wr(p_hwfn, p_ptt, IGU_REG_PF_CONFIGURATION, 0); +} + +#define IGU_CLEANUP_SLEEP_LENGTH (1000) +void qed_int_igu_cleanup_sb(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u32 sb_id, + bool cleanup_set, + u16 opaque_fid + ) +{ + u32 pxp_addr = IGU_CMD_INT_ACK_BASE + sb_id; + u32 sleep_cnt = IGU_CLEANUP_SLEEP_LENGTH; + u32 data = 0; + u32 cmd_ctrl = 0; + u32 val = 0; + u32 sb_bit = 0; + u32 sb_bit_addr = 0; + + /* Set the data field */ + SET_FIELD(data, IGU_CLEANUP_CLEANUP_SET, cleanup_set ? 1 : 0); + SET_FIELD(data, IGU_CLEANUP_CLEANUP_TYPE, 0); + SET_FIELD(data, IGU_CLEANUP_COMMAND_TYPE, IGU_COMMAND_TYPE_SET); + + /* Set the control register */ + SET_FIELD(cmd_ctrl, IGU_CTRL_REG_PXP_ADDR, pxp_addr); + SET_FIELD(cmd_ctrl, IGU_CTRL_REG_FID, opaque_fid); + SET_FIELD(cmd_ctrl, IGU_CTRL_REG_TYPE, IGU_CTRL_CMD_TYPE_WR); + + qed_wr(p_hwfn, p_ptt, IGU_REG_COMMAND_REG_32LSB_DATA, data); + + barrier(); + + qed_wr(p_hwfn, p_ptt, IGU_REG_COMMAND_REG_CTRL, cmd_ctrl); + + /* Flush the write to IGU */ + mmiowb(); + + /* calculate where to read the status bit from */ + sb_bit = 1 << (sb_id % 32); + sb_bit_addr = sb_id / 32 * sizeof(u32); + + sb_bit_addr += IGU_REG_CLEANUP_STATUS_0; + + /* Now wait for the command to complete */ + do { + val = qed_rd(p_hwfn, p_ptt, sb_bit_addr); + + if ((val & sb_bit) == (cleanup_set ? sb_bit : 0)) + break; + + usleep_range(5000, 10000); + } while (--sleep_cnt); + + if (!sleep_cnt) + DP_NOTICE(p_hwfn, + "Timeout waiting for clear status 0x%08x [for sb %d]\n", + val, sb_id); +} + +void qed_int_igu_init_pure_rt_single(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u32 sb_id, + u16 opaque, + bool b_set) +{ + int pi; + + /* Set */ + if (b_set) + qed_int_igu_cleanup_sb(p_hwfn, p_ptt, sb_id, 1, opaque); + + /* Clear */ + qed_int_igu_cleanup_sb(p_hwfn, p_ptt, sb_id, 0, opaque); + + /* Clear the CAU for the SB */ + for (pi = 0; pi < 12; pi++) + qed_wr(p_hwfn, p_ptt, + CAU_REG_PI_MEMORY + (sb_id * 12 + pi) * 4, 0); +} + +void qed_int_igu_init_pure_rt(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + bool b_set, + bool b_slowpath) +{ + u32 igu_base_sb = p_hwfn->hw_info.p_igu_info->igu_base_sb; + u32 igu_sb_cnt = p_hwfn->hw_info.p_igu_info->igu_sb_cnt; + u32 sb_id = 0; + u32 val = 0; + + val = qed_rd(p_hwfn, p_ptt, IGU_REG_BLOCK_CONFIGURATION); + val |= IGU_REG_BLOCK_CONFIGURATION_VF_CLEANUP_EN; + val &= ~IGU_REG_BLOCK_CONFIGURATION_PXP_TPH_INTERFACE_EN; + qed_wr(p_hwfn, p_ptt, IGU_REG_BLOCK_CONFIGURATION, val); + + DP_VERBOSE(p_hwfn, NETIF_MSG_INTR, + "IGU cleaning SBs [%d,...,%d]\n", + igu_base_sb, igu_base_sb + igu_sb_cnt - 1); + + for (sb_id = igu_base_sb; sb_id < igu_base_sb + igu_sb_cnt; sb_id++) + qed_int_igu_init_pure_rt_single(p_hwfn, p_ptt, sb_id, + p_hwfn->hw_info.opaque_fid, + b_set); + + if (b_slowpath) { + sb_id = p_hwfn->hw_info.p_igu_info->igu_dsb_id; + DP_VERBOSE(p_hwfn, NETIF_MSG_INTR, + "IGU cleaning slowpath SB [%d]\n", sb_id); + qed_int_igu_init_pure_rt_single(p_hwfn, p_ptt, sb_id, + p_hwfn->hw_info.opaque_fid, + b_set); + } +} + +int qed_int_igu_read_cam(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt) +{ + struct qed_igu_info *p_igu_info; + struct qed_igu_block *blk; + u32 val; + u16 sb_id; + u16 prev_sb_id = 0xFF; + + p_hwfn->hw_info.p_igu_info = kzalloc(sizeof(*p_igu_info), GFP_ATOMIC); + + if (!p_hwfn->hw_info.p_igu_info) + return -ENOMEM; + + p_igu_info = p_hwfn->hw_info.p_igu_info; + + /* Initialize base sb / sb cnt for PFs */ + p_igu_info->igu_base_sb = 0xffff; + p_igu_info->igu_sb_cnt = 0; + p_igu_info->igu_dsb_id = 0xffff; + p_igu_info->igu_base_sb_iov = 0xffff; + + for (sb_id = 0; sb_id < QED_MAPPING_MEMORY_SIZE(p_hwfn->cdev); + sb_id++) { + blk = &p_igu_info->igu_map.igu_blocks[sb_id]; + + val = qed_rd(p_hwfn, p_ptt, + IGU_REG_MAPPING_MEMORY + sizeof(u32) * sb_id); + + /* stop scanning when hit first invalid PF entry */ + if (!GET_FIELD(val, IGU_MAPPING_LINE_VALID) && + GET_FIELD(val, IGU_MAPPING_LINE_PF_VALID)) + break; + + blk->status = QED_IGU_STATUS_VALID; + blk->function_id = GET_FIELD(val, + IGU_MAPPING_LINE_FUNCTION_NUMBER); + blk->is_pf = GET_FIELD(val, IGU_MAPPING_LINE_PF_VALID); + blk->vector_number = GET_FIELD(val, + IGU_MAPPING_LINE_VECTOR_NUMBER); + + DP_VERBOSE(p_hwfn, NETIF_MSG_INTR, + "IGU_BLOCK[sb_id]:%x:func_id = %d is_pf = %d vector_num = 0x%x\n", + val, blk->function_id, blk->is_pf, + blk->vector_number); + + if (blk->is_pf) { + if (blk->function_id == p_hwfn->rel_pf_id) { + blk->status |= QED_IGU_STATUS_PF; + + if (blk->vector_number == 0) { + if (p_igu_info->igu_dsb_id == 0xffff) + p_igu_info->igu_dsb_id = sb_id; + } else { + if (p_igu_info->igu_base_sb == + 0xffff) { + p_igu_info->igu_base_sb = sb_id; + } else if (prev_sb_id != sb_id - 1) { + DP_NOTICE(p_hwfn->cdev, + "consecutive igu vectors for HWFN %x broken", + p_hwfn->rel_pf_id); + break; + } + prev_sb_id = sb_id; + /* we don't count the default */ + (p_igu_info->igu_sb_cnt)++; + } + } + } + } + + DP_VERBOSE(p_hwfn, NETIF_MSG_INTR, + "IGU igu_base_sb=0x%x igu_sb_cnt=%d igu_dsb_id=0x%x\n", + p_igu_info->igu_base_sb, + p_igu_info->igu_sb_cnt, + p_igu_info->igu_dsb_id); + + if (p_igu_info->igu_base_sb == 0xffff || + p_igu_info->igu_dsb_id == 0xffff || + p_igu_info->igu_sb_cnt == 0) { + DP_NOTICE(p_hwfn, + "IGU CAM returned invalid values igu_base_sb=0x%x igu_sb_cnt=%d igu_dsb_id=0x%x\n", + p_igu_info->igu_base_sb, + p_igu_info->igu_sb_cnt, + p_igu_info->igu_dsb_id); + return -EINVAL; + } + + return 0; +} + +/** + * @brief Initialize igu runtime registers + * + * @param p_hwfn + */ +void qed_int_igu_init_rt(struct qed_hwfn *p_hwfn) +{ + u32 igu_pf_conf = 0; + + igu_pf_conf |= IGU_PF_CONF_FUNC_EN; + + STORE_RT_REG(p_hwfn, IGU_REG_PF_CONFIGURATION_RT_OFFSET, igu_pf_conf); +} + +u64 qed_int_igu_read_sisr_reg(struct qed_hwfn *p_hwfn) +{ + u64 intr_status = 0; + u32 intr_status_lo = 0; + u32 intr_status_hi = 0; + u32 lsb_igu_cmd_addr = IGU_REG_SISR_MDPC_WMASK_LSB_UPPER - + IGU_CMD_INT_ACK_BASE; + u32 msb_igu_cmd_addr = IGU_REG_SISR_MDPC_WMASK_MSB_UPPER - + IGU_CMD_INT_ACK_BASE; + + intr_status_lo = REG_RD(p_hwfn, + GTT_BAR0_MAP_REG_IGU_CMD + + lsb_igu_cmd_addr * 8); + intr_status_hi = REG_RD(p_hwfn, + GTT_BAR0_MAP_REG_IGU_CMD + + msb_igu_cmd_addr * 8); + intr_status = ((u64)intr_status_hi << 32) + (u64)intr_status_lo; + + return intr_status; +} + +static void qed_int_sp_dpc_setup(struct qed_hwfn *p_hwfn) +{ + tasklet_init(p_hwfn->sp_dpc, + qed_int_sp_dpc, (unsigned long)p_hwfn); + p_hwfn->b_sp_dpc_enabled = true; +} + +static int qed_int_sp_dpc_alloc(struct qed_hwfn *p_hwfn) +{ + p_hwfn->sp_dpc = kmalloc(sizeof(*p_hwfn->sp_dpc), GFP_ATOMIC); + if (!p_hwfn->sp_dpc) + return -ENOMEM; + + return 0; +} + +static void qed_int_sp_dpc_free(struct qed_hwfn *p_hwfn) +{ + kfree(p_hwfn->sp_dpc); +} + +int qed_int_alloc(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt) +{ + int rc = 0; + + rc = qed_int_sp_dpc_alloc(p_hwfn); + if (rc) { + DP_ERR(p_hwfn->cdev, "Failed to allocate sp dpc mem\n"); + return rc; + } + rc = qed_int_sp_sb_alloc(p_hwfn, p_ptt); + if (rc) { + DP_ERR(p_hwfn->cdev, "Failed to allocate sp sb mem\n"); + return rc; + } + + return rc; +} + +void qed_int_free(struct qed_hwfn *p_hwfn) +{ + qed_int_sp_sb_free(p_hwfn); + qed_int_sp_dpc_free(p_hwfn); +} + +void qed_int_setup(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt) +{ + qed_int_sp_sb_setup(p_hwfn, p_ptt); + qed_int_sp_dpc_setup(p_hwfn); +} + +int qed_int_get_num_sbs(struct qed_hwfn *p_hwfn, + int *p_iov_blks) +{ + struct qed_igu_info *info = p_hwfn->hw_info.p_igu_info; + + if (!info) + return 0; + + if (p_iov_blks) + *p_iov_blks = info->free_blks; + + return info->igu_sb_cnt; +} diff --git a/drivers/net/ethernet/qlogic/qed/qed_int.h b/drivers/net/ethernet/qlogic/qed/qed_int.h new file mode 100644 index 000000000000..16b57518e706 --- /dev/null +++ b/drivers/net/ethernet/qlogic/qed/qed_int.h @@ -0,0 +1,391 @@ +/* QLogic qed NIC Driver + * Copyright (c) 2015 QLogic Corporation + * + * This software is available under the terms of the GNU General Public License + * (GPL) Version 2, available from the file COPYING in the main directory of + * this source tree. + */ + +#ifndef _QED_INT_H +#define _QED_INT_H + +#include +#include +#include "qed.h" + +/* Fields of IGU PF CONFIGRATION REGISTER */ +#define IGU_PF_CONF_FUNC_EN (0x1 << 0) /* function enable */ +#define IGU_PF_CONF_MSI_MSIX_EN (0x1 << 1) /* MSI/MSIX enable */ +#define IGU_PF_CONF_INT_LINE_EN (0x1 << 2) /* INT enable */ +#define IGU_PF_CONF_ATTN_BIT_EN (0x1 << 3) /* attention enable */ +#define IGU_PF_CONF_SINGLE_ISR_EN (0x1 << 4) /* single ISR mode enable */ +#define IGU_PF_CONF_SIMD_MODE (0x1 << 5) /* simd all ones mode */ + +/* Igu control commands + */ +enum igu_ctrl_cmd { + IGU_CTRL_CMD_TYPE_RD, + IGU_CTRL_CMD_TYPE_WR, + MAX_IGU_CTRL_CMD +}; + +/* Control register for the IGU command register + */ +struct igu_ctrl_reg { + u32 ctrl_data; +#define IGU_CTRL_REG_FID_MASK 0xFFFF /* Opaque_FID */ +#define IGU_CTRL_REG_FID_SHIFT 0 +#define IGU_CTRL_REG_PXP_ADDR_MASK 0xFFF /* Command address */ +#define IGU_CTRL_REG_PXP_ADDR_SHIFT 16 +#define IGU_CTRL_REG_RESERVED_MASK 0x1 +#define IGU_CTRL_REG_RESERVED_SHIFT 28 +#define IGU_CTRL_REG_TYPE_MASK 0x1 /* use enum igu_ctrl_cmd */ +#define IGU_CTRL_REG_TYPE_SHIFT 31 +}; + +enum qed_coalescing_fsm { + QED_COAL_RX_STATE_MACHINE, + QED_COAL_TX_STATE_MACHINE +}; + +/** + * @brief qed_int_cau_conf_pi - configure cau for a given + * status block + * + * @param p_hwfn + * @param p_ptt + * @param igu_sb_id + * @param pi_index + * @param state + * @param timeset + */ +void qed_int_cau_conf_pi(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u16 igu_sb_id, + u32 pi_index, + enum qed_coalescing_fsm coalescing_fsm, + u8 timeset); + +/** + * @brief qed_int_igu_enable_int - enable device interrupts + * + * @param p_hwfn + * @param p_ptt + * @param int_mode - interrupt mode to use + */ +void qed_int_igu_enable_int(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + enum qed_int_mode int_mode); + +/** + * @brief qed_int_igu_disable_int - disable device interrupts + * + * @param p_hwfn + * @param p_ptt + */ +void qed_int_igu_disable_int(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt); + +/** + * @brief qed_int_igu_read_sisr_reg - Reads the single isr multiple dpc + * register from igu. + * + * @param p_hwfn + * + * @return u64 + */ +u64 qed_int_igu_read_sisr_reg(struct qed_hwfn *p_hwfn); + +#define QED_SP_SB_ID 0xffff +/** + * @brief qed_int_sb_init - Initializes the sb_info structure. + * + * once the structure is initialized it can be passed to sb related functions. + * + * @param p_hwfn + * @param p_ptt + * @param sb_info points to an uninitialized (but + * allocated) sb_info structure + * @param sb_virt_addr + * @param sb_phy_addr + * @param sb_id the sb_id to be used (zero based in driver) + * should use QED_SP_SB_ID for SP Status block + * + * @return int + */ +int qed_int_sb_init(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + struct qed_sb_info *sb_info, + void *sb_virt_addr, + dma_addr_t sb_phy_addr, + u16 sb_id); +/** + * @brief qed_int_sb_setup - Setup the sb. + * + * @param p_hwfn + * @param p_ptt + * @param sb_info initialized sb_info structure + */ +void qed_int_sb_setup(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + struct qed_sb_info *sb_info); + +/** + * @brief qed_int_sb_release - releases the sb_info structure. + * + * once the structure is released, it's memory can be freed + * + * @param p_hwfn + * @param sb_info points to an allocated sb_info structure + * @param sb_id the sb_id to be used (zero based in driver) + * should never be equal to QED_SP_SB_ID + * (SP Status block) + * + * @return int + */ +int qed_int_sb_release(struct qed_hwfn *p_hwfn, + struct qed_sb_info *sb_info, + u16 sb_id); + +/** + * @brief qed_int_sp_dpc - To be called when an interrupt is received on the + * default status block. + * + * @param p_hwfn - pointer to hwfn + * + */ +void qed_int_sp_dpc(unsigned long hwfn_cookie); + +/** + * @brief qed_int_get_num_sbs - get the number of status + * blocks configured for this funciton in the igu. + * + * @param p_hwfn + * @param p_iov_blks - configured free blks for vfs + * + * @return int - number of status blocks configured + */ +int qed_int_get_num_sbs(struct qed_hwfn *p_hwfn, + int *p_iov_blks); + +/** + * @file + * + * @brief Interrupt handler + */ + +#define QED_CAU_DEF_RX_TIMER_RES 0 +#define QED_CAU_DEF_TX_TIMER_RES 0 + +#define QED_SB_ATT_IDX 0x0001 +#define QED_SB_EVENT_MASK 0x0003 + +#define SB_ALIGNED_SIZE(p_hwfn) \ + ALIGNED_TYPE_SIZE(struct status_block, p_hwfn) + +struct qed_igu_block { + u8 status; +#define QED_IGU_STATUS_FREE 0x01 +#define QED_IGU_STATUS_VALID 0x02 +#define QED_IGU_STATUS_PF 0x04 + + u8 vector_number; + u8 function_id; + u8 is_pf; +}; + +struct qed_igu_map { + struct qed_igu_block igu_blocks[MAX_TOT_SB_PER_PATH]; +}; + +struct qed_igu_info { + struct qed_igu_map igu_map; + u16 igu_dsb_id; + u16 igu_base_sb; + u16 igu_base_sb_iov; + u16 igu_sb_cnt; + u16 igu_sb_cnt_iov; + u16 free_blks; +}; + +/* TODO Names of function may change... */ +void qed_int_igu_init_pure_rt(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + bool b_set, + bool b_slowpath); + +void qed_int_igu_init_rt(struct qed_hwfn *p_hwfn); + +/** + * @brief qed_int_igu_read_cam - Reads the IGU CAM. + * This function needs to be called during hardware + * prepare. It reads the info from igu cam to know which + * status block is the default / base status block etc. + * + * @param p_hwfn + * @param p_ptt + * + * @return int + */ +int qed_int_igu_read_cam(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt); + +typedef int (*qed_int_comp_cb_t)(struct qed_hwfn *p_hwfn, + void *cookie); +/** + * @brief qed_int_register_cb - Register callback func for + * slowhwfn statusblock. + * + * Every protocol that uses the slowhwfn status block + * should register a callback function that will be called + * once there is an update of the sp status block. + * + * @param p_hwfn + * @param comp_cb - function to be called when there is an + * interrupt on the sp sb + * + * @param cookie - passed to the callback function + * @param sb_idx - OUT parameter which gives the chosen index + * for this protocol. + * @param p_fw_cons - pointer to the actual address of the + * consumer for this protocol. + * + * @return int + */ +int qed_int_register_cb(struct qed_hwfn *p_hwfn, + qed_int_comp_cb_t comp_cb, + void *cookie, + u8 *sb_idx, + __le16 **p_fw_cons); + +/** + * @brief qed_int_unregister_cb - Unregisters callback + * function from sp sb. + * Partner of qed_int_register_cb -> should be called + * when no longer required. + * + * @param p_hwfn + * @param pi + * + * @return int + */ +int qed_int_unregister_cb(struct qed_hwfn *p_hwfn, + u8 pi); + +/** + * @brief qed_int_get_sp_sb_id - Get the slowhwfn sb id. + * + * @param p_hwfn + * + * @return u16 + */ +u16 qed_int_get_sp_sb_id(struct qed_hwfn *p_hwfn); + +/** + * @brief Status block cleanup. Should be called for each status + * block that will be used -> both PF / VF + * + * @param p_hwfn + * @param p_ptt + * @param sb_id - igu status block id + * @param cleanup_set - set(1) / clear(0) + * @param opaque_fid - the function for which to perform + * cleanup, for example a PF on behalf of + * its VFs. + */ +void qed_int_igu_cleanup_sb(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u32 sb_id, + bool cleanup_set, + u16 opaque_fid); + +/** + * @brief Status block cleanup. Should be called for each status + * block that will be used -> both PF / VF + * + * @param p_hwfn + * @param p_ptt + * @param sb_id - igu status block id + * @param opaque - opaque fid of the sb owner. + * @param cleanup_set - set(1) / clear(0) + */ +void qed_int_igu_init_pure_rt_single(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u32 sb_id, + u16 opaque, + bool b_set); + +/** + * @brief qed_int_cau_conf - configure cau for a given status + * block + * + * @param p_hwfn + * @param ptt + * @param sb_phys + * @param igu_sb_id + * @param vf_number + * @param vf_valid + */ +void qed_int_cau_conf_sb(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + dma_addr_t sb_phys, + u16 igu_sb_id, + u16 vf_number, + u8 vf_valid); + +/** + * @brief qed_int_alloc + * + * @param p_hwfn + * @param p_ptt + * + * @return int + */ +int qed_int_alloc(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt); + +/** + * @brief qed_int_free + * + * @param p_hwfn + */ +void qed_int_free(struct qed_hwfn *p_hwfn); + +/** + * @brief qed_int_setup + * + * @param p_hwfn + * @param p_ptt + */ +void qed_int_setup(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt); + +/** + * @brief - Enable Interrupt & Attention for hw function + * + * @param p_hwfn + * @param p_ptt + * @param int_mode + */ +void qed_int_igu_enable(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + enum qed_int_mode int_mode); + +/** + * @brief - Initialize CAU status block entry + * + * @param p_hwfn + * @param p_sb_entry + * @param pf_id + * @param vf_number + * @param vf_valid + */ +void qed_init_cau_sb_entry(struct qed_hwfn *p_hwfn, + struct cau_sb_entry *p_sb_entry, + u8 pf_id, + u16 vf_number, + u8 vf_valid); + +#define QED_MAPPING_MEMORY_SIZE(dev) (NUM_OF_SBS(dev)) + +#endif diff --git a/drivers/net/ethernet/qlogic/qed/qed_main.c b/drivers/net/ethernet/qlogic/qed/qed_main.c new file mode 100644 index 000000000000..d0b1ff0ca3c8 --- /dev/null +++ b/drivers/net/ethernet/qlogic/qed/qed_main.c @@ -0,0 +1,948 @@ +/* QLogic qed NIC Driver + * Copyright (c) 2015 QLogic Corporation + * + * This software is available under the terms of the GNU General Public License + * (GPL) Version 2, available from the file COPYING in the main directory of + * this source tree. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "qed.h" +#include "qed_sp.h" +#include "qed_dev_api.h" +#include "qed_mcp.h" +#include "qed_hw.h" + +static const char version[] = + "QLogic QL4xxx 40G/100G Ethernet Driver qed " DRV_MODULE_VERSION "\n"; + +MODULE_DESCRIPTION("QLogic 25G/40G/50G/100G Core Module"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_MODULE_VERSION); + +#define FW_FILE_VERSION \ + __stringify(FW_MAJOR_VERSION) "." \ + __stringify(FW_MINOR_VERSION) "." \ + __stringify(FW_REVISION_VERSION) "." \ + __stringify(FW_ENGINEERING_VERSION) + +#define QED_FW_FILE_NAME \ + "qed/qed_init_values_zipped-" FW_FILE_VERSION ".bin" + +static int __init qed_init(void) +{ + pr_notice("qed_init called\n"); + + pr_info("%s", version); + + return 0; +} + +static void __exit qed_cleanup(void) +{ + pr_notice("qed_cleanup called\n"); +} + +module_init(qed_init); +module_exit(qed_cleanup); + +/* Check if the DMA controller on the machine can properly handle the DMA + * addressing required by the device. +*/ +static int qed_set_coherency_mask(struct qed_dev *cdev) +{ + struct device *dev = &cdev->pdev->dev; + + if (dma_set_mask(dev, DMA_BIT_MASK(64)) == 0) { + if (dma_set_coherent_mask(dev, DMA_BIT_MASK(64)) != 0) { + DP_NOTICE(cdev, + "Can't request 64-bit consistent allocations\n"); + return -EIO; + } + } else if (dma_set_mask(dev, DMA_BIT_MASK(32)) != 0) { + DP_NOTICE(cdev, "Can't request 64b/32b DMA addresses\n"); + return -EIO; + } + + return 0; +} + +static void qed_free_pci(struct qed_dev *cdev) +{ + struct pci_dev *pdev = cdev->pdev; + + if (cdev->doorbells) + iounmap(cdev->doorbells); + if (cdev->regview) + iounmap(cdev->regview); + if (atomic_read(&pdev->enable_cnt) == 1) + pci_release_regions(pdev); + + pci_disable_device(pdev); +} + +/* Performs PCI initializations as well as initializing PCI-related parameters + * in the device structrue. Returns 0 in case of success. + */ +static int qed_init_pci(struct qed_dev *cdev, + struct pci_dev *pdev) +{ + int rc; + + cdev->pdev = pdev; + + rc = pci_enable_device(pdev); + if (rc) { + DP_NOTICE(cdev, "Cannot enable PCI device\n"); + goto err0; + } + + if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { + DP_NOTICE(cdev, "No memory region found in bar #0\n"); + rc = -EIO; + goto err1; + } + + if (!(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) { + DP_NOTICE(cdev, "No memory region found in bar #2\n"); + rc = -EIO; + goto err1; + } + + if (atomic_read(&pdev->enable_cnt) == 1) { + rc = pci_request_regions(pdev, "qed"); + if (rc) { + DP_NOTICE(cdev, + "Failed to request PCI memory resources\n"); + goto err1; + } + pci_set_master(pdev); + pci_save_state(pdev); + } + + if (!pci_is_pcie(pdev)) { + DP_NOTICE(cdev, "The bus is not PCI Express\n"); + rc = -EIO; + goto err2; + } + + cdev->pci_params.pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM); + if (cdev->pci_params.pm_cap == 0) + DP_NOTICE(cdev, "Cannot find power management capability\n"); + + rc = qed_set_coherency_mask(cdev); + if (rc) + goto err2; + + cdev->pci_params.mem_start = pci_resource_start(pdev, 0); + cdev->pci_params.mem_end = pci_resource_end(pdev, 0); + cdev->pci_params.irq = pdev->irq; + + cdev->regview = pci_ioremap_bar(pdev, 0); + if (!cdev->regview) { + DP_NOTICE(cdev, "Cannot map register space, aborting\n"); + rc = -ENOMEM; + goto err2; + } + + cdev->db_phys_addr = pci_resource_start(cdev->pdev, 2); + cdev->db_size = pci_resource_len(cdev->pdev, 2); + cdev->doorbells = ioremap_wc(cdev->db_phys_addr, cdev->db_size); + if (!cdev->doorbells) { + DP_NOTICE(cdev, "Cannot map doorbell space\n"); + return -ENOMEM; + } + + return 0; + +err2: + pci_release_regions(pdev); +err1: + pci_disable_device(pdev); +err0: + return rc; +} + +int qed_fill_dev_info(struct qed_dev *cdev, + struct qed_dev_info *dev_info) +{ + memset(dev_info, 0, sizeof(struct qed_dev_info)); + + dev_info->num_hwfns = cdev->num_hwfns; + dev_info->pci_mem_start = cdev->pci_params.mem_start; + dev_info->pci_mem_end = cdev->pci_params.mem_end; + dev_info->pci_irq = cdev->pci_params.irq; + dev_info->is_mf = IS_MF(&cdev->hwfns[0]); + ether_addr_copy(dev_info->hw_mac, cdev->hwfns[0].hw_info.hw_mac_addr); + + dev_info->fw_major = FW_MAJOR_VERSION; + dev_info->fw_minor = FW_MINOR_VERSION; + dev_info->fw_rev = FW_REVISION_VERSION; + dev_info->fw_eng = FW_ENGINEERING_VERSION; + dev_info->mf_mode = cdev->mf_mode; + + qed_mcp_get_mfw_ver(cdev, &dev_info->mfw_rev); + + return 0; +} + +static void qed_free_cdev(struct qed_dev *cdev) +{ + kfree((void *)cdev); +} + +static struct qed_dev *qed_alloc_cdev(struct pci_dev *pdev) +{ + struct qed_dev *cdev; + + cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); + if (!cdev) + return cdev; + + qed_init_struct(cdev); + + return cdev; +} + +/* Sets the requested power state */ +static int qed_set_power_state(struct qed_dev *cdev, + pci_power_t state) +{ + if (!cdev) + return -ENODEV; + + DP_VERBOSE(cdev, NETIF_MSG_DRV, "Omitting Power state change\n"); + return 0; +} + +/* probing */ +static struct qed_dev *qed_probe(struct pci_dev *pdev, + enum qed_protocol protocol, + u32 dp_module, + u8 dp_level) +{ + struct qed_dev *cdev; + int rc; + + cdev = qed_alloc_cdev(pdev); + if (!cdev) + goto err0; + + cdev->protocol = protocol; + + qed_init_dp(cdev, dp_module, dp_level); + + rc = qed_init_pci(cdev, pdev); + if (rc) { + DP_ERR(cdev, "init pci failed\n"); + goto err1; + } + DP_INFO(cdev, "PCI init completed successfully\n"); + + rc = qed_hw_prepare(cdev, QED_PCI_DEFAULT); + if (rc) { + DP_ERR(cdev, "hw prepare failed\n"); + goto err2; + } + + DP_INFO(cdev, "qed_probe completed successffuly\n"); + + return cdev; + +err2: + qed_free_pci(cdev); +err1: + qed_free_cdev(cdev); +err0: + return NULL; +} + +static void qed_remove(struct qed_dev *cdev) +{ + if (!cdev) + return; + + qed_hw_remove(cdev); + + qed_free_pci(cdev); + + qed_set_power_state(cdev, PCI_D3hot); + + qed_free_cdev(cdev); +} + +static void qed_disable_msix(struct qed_dev *cdev) +{ + if (cdev->int_params.out.int_mode == QED_INT_MODE_MSIX) { + pci_disable_msix(cdev->pdev); + kfree(cdev->int_params.msix_table); + } else if (cdev->int_params.out.int_mode == QED_INT_MODE_MSI) { + pci_disable_msi(cdev->pdev); + } + + memset(&cdev->int_params.out, 0, sizeof(struct qed_int_param)); +} + +static int qed_enable_msix(struct qed_dev *cdev, + struct qed_int_params *int_params) +{ + int i, rc, cnt; + + cnt = int_params->in.num_vectors; + + for (i = 0; i < cnt; i++) + int_params->msix_table[i].entry = i; + + rc = pci_enable_msix_range(cdev->pdev, int_params->msix_table, + int_params->in.min_msix_cnt, cnt); + if (rc < cnt && rc >= int_params->in.min_msix_cnt && + (rc % cdev->num_hwfns)) { + pci_disable_msix(cdev->pdev); + + /* If fastpath is initialized, we need at least one interrupt + * per hwfn [and the slow path interrupts]. New requested number + * should be a multiple of the number of hwfns. + */ + cnt = (rc / cdev->num_hwfns) * cdev->num_hwfns; + DP_NOTICE(cdev, + "Trying to enable MSI-X with less vectors (%d out of %d)\n", + cnt, int_params->in.num_vectors); + rc = pci_enable_msix_exact(cdev->pdev, + int_params->msix_table, cnt); + if (!rc) + rc = cnt; + } + + if (rc > 0) { + /* MSI-x configuration was achieved */ + int_params->out.int_mode = QED_INT_MODE_MSIX; + int_params->out.num_vectors = rc; + rc = 0; + } else { + DP_NOTICE(cdev, + "Failed to enable MSI-X [Requested %d vectors][rc %d]\n", + cnt, rc); + } + + return rc; +} + +/* This function outputs the int mode and the number of enabled msix vector */ +static int qed_set_int_mode(struct qed_dev *cdev, bool force_mode) +{ + struct qed_int_params *int_params = &cdev->int_params; + struct msix_entry *tbl; + int rc = 0, cnt; + + switch (int_params->in.int_mode) { + case QED_INT_MODE_MSIX: + /* Allocate MSIX table */ + cnt = int_params->in.num_vectors; + int_params->msix_table = kcalloc(cnt, sizeof(*tbl), GFP_KERNEL); + if (!int_params->msix_table) { + rc = -ENOMEM; + goto out; + } + + /* Enable MSIX */ + rc = qed_enable_msix(cdev, int_params); + if (!rc) + goto out; + + DP_NOTICE(cdev, "Failed to enable MSI-X\n"); + kfree(int_params->msix_table); + if (force_mode) + goto out; + /* Fallthrough */ + + case QED_INT_MODE_MSI: + rc = pci_enable_msi(cdev->pdev); + if (!rc) { + int_params->out.int_mode = QED_INT_MODE_MSI; + goto out; + } + + DP_NOTICE(cdev, "Failed to enable MSI\n"); + if (force_mode) + goto out; + /* Fallthrough */ + + case QED_INT_MODE_INTA: + int_params->out.int_mode = QED_INT_MODE_INTA; + rc = 0; + goto out; + default: + DP_NOTICE(cdev, "Unknown int_mode value %d\n", + int_params->in.int_mode); + rc = -EINVAL; + } + +out: + cdev->int_coalescing_mode = QED_COAL_MODE_ENABLE; + + return rc; +} + +static void qed_simd_handler_config(struct qed_dev *cdev, void *token, + int index, void(*handler)(void *)) +{ + struct qed_hwfn *hwfn = &cdev->hwfns[index % cdev->num_hwfns]; + int relative_idx = index / cdev->num_hwfns; + + hwfn->simd_proto_handler[relative_idx].func = handler; + hwfn->simd_proto_handler[relative_idx].token = token; +} + +static void qed_simd_handler_clean(struct qed_dev *cdev, int index) +{ + struct qed_hwfn *hwfn = &cdev->hwfns[index % cdev->num_hwfns]; + int relative_idx = index / cdev->num_hwfns; + + memset(&hwfn->simd_proto_handler[relative_idx], 0, + sizeof(struct qed_simd_fp_handler)); +} + +static irqreturn_t qed_msix_sp_int(int irq, void *tasklet) +{ + tasklet_schedule((struct tasklet_struct *)tasklet); + return IRQ_HANDLED; +} + +static irqreturn_t qed_single_int(int irq, void *dev_instance) +{ + struct qed_dev *cdev = (struct qed_dev *)dev_instance; + struct qed_hwfn *hwfn; + irqreturn_t rc = IRQ_NONE; + u64 status; + int i, j; + + for (i = 0; i < cdev->num_hwfns; i++) { + status = qed_int_igu_read_sisr_reg(&cdev->hwfns[i]); + + if (!status) + continue; + + hwfn = &cdev->hwfns[i]; + + /* Slowpath interrupt */ + if (unlikely(status & 0x1)) { + tasklet_schedule(hwfn->sp_dpc); + status &= ~0x1; + rc = IRQ_HANDLED; + } + + /* Fastpath interrupts */ + for (j = 0; j < 64; j++) { + if ((0x2ULL << j) & status) { + hwfn->simd_proto_handler[j].func( + hwfn->simd_proto_handler[j].token); + status &= ~(0x2ULL << j); + rc = IRQ_HANDLED; + } + } + + if (unlikely(status)) + DP_VERBOSE(hwfn, NETIF_MSG_INTR, + "got an unknown interrupt status 0x%llx\n", + status); + } + + return rc; +} + +static int qed_slowpath_irq_req(struct qed_dev *cdev) +{ + int i = 0, rc = 0; + + if (cdev->int_params.out.int_mode == QED_INT_MODE_MSIX) { + /* Request all the slowpath MSI-X vectors */ + for (i = 0; i < cdev->num_hwfns; i++) { + snprintf(cdev->hwfns[i].name, NAME_SIZE, + "sp-%d-%02x:%02x.%02x", + i, cdev->pdev->bus->number, + PCI_SLOT(cdev->pdev->devfn), + cdev->hwfns[i].abs_pf_id); + + rc = request_irq(cdev->int_params.msix_table[i].vector, + qed_msix_sp_int, 0, + cdev->hwfns[i].name, + cdev->hwfns[i].sp_dpc); + if (rc) + break; + + DP_VERBOSE(&cdev->hwfns[i], + (NETIF_MSG_INTR | QED_MSG_SP), + "Requested slowpath MSI-X\n"); + } + + if (i != cdev->num_hwfns) { + /* Free already request MSI-X vectors */ + for (i--; i >= 0; i--) { + unsigned int vec = + cdev->int_params.msix_table[i].vector; + synchronize_irq(vec); + free_irq(cdev->int_params.msix_table[i].vector, + cdev->hwfns[i].sp_dpc); + } + } + } else { + unsigned long flags = 0; + + snprintf(cdev->name, NAME_SIZE, "%02x:%02x.%02x", + cdev->pdev->bus->number, PCI_SLOT(cdev->pdev->devfn), + PCI_FUNC(cdev->pdev->devfn)); + + if (cdev->int_params.out.int_mode == QED_INT_MODE_INTA) + flags |= IRQF_SHARED; + + rc = request_irq(cdev->pdev->irq, qed_single_int, + flags, cdev->name, cdev); + } + + return rc; +} + +static void qed_slowpath_irq_free(struct qed_dev *cdev) +{ + int i; + + if (cdev->int_params.out.int_mode == QED_INT_MODE_MSIX) { + for_each_hwfn(cdev, i) { + synchronize_irq(cdev->int_params.msix_table[i].vector); + free_irq(cdev->int_params.msix_table[i].vector, + cdev->hwfns[i].sp_dpc); + } + } else { + free_irq(cdev->pdev->irq, cdev); + } +} + +static int qed_nic_stop(struct qed_dev *cdev) +{ + int i, rc; + + rc = qed_hw_stop(cdev); + + for (i = 0; i < cdev->num_hwfns; i++) { + struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; + + if (p_hwfn->b_sp_dpc_enabled) { + tasklet_disable(p_hwfn->sp_dpc); + p_hwfn->b_sp_dpc_enabled = false; + DP_VERBOSE(cdev, NETIF_MSG_IFDOWN, + "Disabled sp taskelt [hwfn %d] at %p\n", + i, p_hwfn->sp_dpc); + } + } + + return rc; +} + +static int qed_nic_reset(struct qed_dev *cdev) +{ + int rc; + + rc = qed_hw_reset(cdev); + if (rc) + return rc; + + qed_resc_free(cdev); + + return 0; +} + +static int qed_nic_setup(struct qed_dev *cdev) +{ + int rc; + + rc = qed_resc_alloc(cdev); + if (rc) + return rc; + + DP_INFO(cdev, "Allocated qed resources\n"); + + qed_resc_setup(cdev); + + return rc; +} + +static int qed_set_int_fp(struct qed_dev *cdev, u16 cnt) +{ + int limit = 0; + + /* Mark the fastpath as free/used */ + cdev->int_params.fp_initialized = cnt ? true : false; + + if (cdev->int_params.out.int_mode != QED_INT_MODE_MSIX) + limit = cdev->num_hwfns * 63; + else if (cdev->int_params.fp_msix_cnt) + limit = cdev->int_params.fp_msix_cnt; + + if (!limit) + return -ENOMEM; + + return min_t(int, cnt, limit); +} + +static int qed_get_int_fp(struct qed_dev *cdev, struct qed_int_info *info) +{ + memset(info, 0, sizeof(struct qed_int_info)); + + if (!cdev->int_params.fp_initialized) { + DP_INFO(cdev, + "Protocol driver requested interrupt information, but its support is not yet configured\n"); + return -EINVAL; + } + + /* Need to expose only MSI-X information; Single IRQ is handled solely + * by qed. + */ + if (cdev->int_params.out.int_mode == QED_INT_MODE_MSIX) { + int msix_base = cdev->int_params.fp_msix_base; + + info->msix_cnt = cdev->int_params.fp_msix_cnt; + info->msix = &cdev->int_params.msix_table[msix_base]; + } + + return 0; +} + +static int qed_slowpath_setup_int(struct qed_dev *cdev, + enum qed_int_mode int_mode) +{ + int rc, i; + u8 num_vectors = 0; + + memset(&cdev->int_params, 0, sizeof(struct qed_int_params)); + + cdev->int_params.in.int_mode = int_mode; + for_each_hwfn(cdev, i) + num_vectors += qed_int_get_num_sbs(&cdev->hwfns[i], NULL) + 1; + cdev->int_params.in.num_vectors = num_vectors; + + /* We want a minimum of one slowpath and one fastpath vector per hwfn */ + cdev->int_params.in.min_msix_cnt = cdev->num_hwfns * 2; + + rc = qed_set_int_mode(cdev, false); + if (rc) { + DP_ERR(cdev, "qed_slowpath_setup_int ERR\n"); + return rc; + } + + cdev->int_params.fp_msix_base = cdev->num_hwfns; + cdev->int_params.fp_msix_cnt = cdev->int_params.out.num_vectors - + cdev->num_hwfns; + + return 0; +} + +u32 qed_unzip_data(struct qed_hwfn *p_hwfn, u32 input_len, + u8 *input_buf, u32 max_size, u8 *unzip_buf) +{ + int rc; + + p_hwfn->stream->next_in = input_buf; + p_hwfn->stream->avail_in = input_len; + p_hwfn->stream->next_out = unzip_buf; + p_hwfn->stream->avail_out = max_size; + + rc = zlib_inflateInit2(p_hwfn->stream, MAX_WBITS); + + if (rc != Z_OK) { + DP_VERBOSE(p_hwfn, NETIF_MSG_DRV, "zlib init failed, rc = %d\n", + rc); + return 0; + } + + rc = zlib_inflate(p_hwfn->stream, Z_FINISH); + zlib_inflateEnd(p_hwfn->stream); + + if (rc != Z_OK && rc != Z_STREAM_END) { + DP_VERBOSE(p_hwfn, NETIF_MSG_DRV, "FW unzip error: %s, rc=%d\n", + p_hwfn->stream->msg, rc); + return 0; + } + + return p_hwfn->stream->total_out / 4; +} + +static int qed_alloc_stream_mem(struct qed_dev *cdev) +{ + int i; + void *workspace; + + for_each_hwfn(cdev, i) { + struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; + + p_hwfn->stream = kzalloc(sizeof(*p_hwfn->stream), GFP_KERNEL); + if (!p_hwfn->stream) + return -ENOMEM; + + workspace = vzalloc(zlib_inflate_workspacesize()); + if (!workspace) + return -ENOMEM; + p_hwfn->stream->workspace = workspace; + } + + return 0; +} + +static void qed_free_stream_mem(struct qed_dev *cdev) +{ + int i; + + for_each_hwfn(cdev, i) { + struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; + + if (!p_hwfn->stream) + return; + + vfree(p_hwfn->stream->workspace); + kfree(p_hwfn->stream); + } +} + +static void qed_update_pf_params(struct qed_dev *cdev, + struct qed_pf_params *params) +{ + int i; + + for (i = 0; i < cdev->num_hwfns; i++) { + struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; + + p_hwfn->pf_params = *params; + } +} + +static int qed_slowpath_start(struct qed_dev *cdev, + struct qed_slowpath_params *params) +{ + struct qed_mcp_drv_version drv_version; + const u8 *data = NULL; + struct qed_hwfn *hwfn; + int rc; + + rc = request_firmware(&cdev->firmware, QED_FW_FILE_NAME, + &cdev->pdev->dev); + if (rc) { + DP_NOTICE(cdev, + "Failed to find fw file - /lib/firmware/%s\n", + QED_FW_FILE_NAME); + goto err; + } + + rc = qed_nic_setup(cdev); + if (rc) + goto err; + + rc = qed_slowpath_setup_int(cdev, params->int_mode); + if (rc) + goto err1; + + /* Request the slowpath IRQ */ + rc = qed_slowpath_irq_req(cdev); + if (rc) + goto err2; + + /* Allocate stream for unzipping */ + rc = qed_alloc_stream_mem(cdev); + if (rc) { + DP_NOTICE(cdev, "Failed to allocate stream memory\n"); + goto err3; + } + + /* Start the slowpath */ + data = cdev->firmware->data; + + rc = qed_hw_init(cdev, true, cdev->int_params.out.int_mode, + true, data); + if (rc) + goto err3; + + DP_INFO(cdev, + "HW initialization and function start completed successfully\n"); + + hwfn = QED_LEADING_HWFN(cdev); + drv_version.version = (params->drv_major << 24) | + (params->drv_minor << 16) | + (params->drv_rev << 8) | + (params->drv_eng); + strlcpy(drv_version.name, params->name, + MCP_DRV_VER_STR_SIZE - 4); + rc = qed_mcp_send_drv_version(hwfn, hwfn->p_main_ptt, + &drv_version); + if (rc) { + DP_NOTICE(cdev, "Failed sending drv version command\n"); + return rc; + } + + return 0; + +err3: + qed_free_stream_mem(cdev); + qed_slowpath_irq_free(cdev); +err2: + qed_disable_msix(cdev); +err1: + qed_resc_free(cdev); +err: + release_firmware(cdev->firmware); + + return rc; +} + +static int qed_slowpath_stop(struct qed_dev *cdev) +{ + if (!cdev) + return -ENODEV; + + qed_free_stream_mem(cdev); + + qed_nic_stop(cdev); + qed_slowpath_irq_free(cdev); + + qed_disable_msix(cdev); + qed_nic_reset(cdev); + + release_firmware(cdev->firmware); + + return 0; +} + +static void qed_set_id(struct qed_dev *cdev, char name[NAME_SIZE], + char ver_str[VER_SIZE]) +{ + int i; + + memcpy(cdev->name, name, NAME_SIZE); + for_each_hwfn(cdev, i) + snprintf(cdev->hwfns[i].name, NAME_SIZE, "%s-%d", name, i); + + memcpy(cdev->ver_str, ver_str, VER_SIZE); + cdev->drv_type = DRV_ID_DRV_TYPE_LINUX; +} + +static u32 qed_sb_init(struct qed_dev *cdev, + struct qed_sb_info *sb_info, + void *sb_virt_addr, + dma_addr_t sb_phy_addr, u16 sb_id, + enum qed_sb_type type) +{ + struct qed_hwfn *p_hwfn; + int hwfn_index; + u16 rel_sb_id; + u8 n_hwfns; + u32 rc; + + /* RoCE uses single engine and CMT uses two engines. When using both + * we force only a single engine. Storage uses only engine 0 too. + */ + if (type == QED_SB_TYPE_L2_QUEUE) + n_hwfns = cdev->num_hwfns; + else + n_hwfns = 1; + + hwfn_index = sb_id % n_hwfns; + p_hwfn = &cdev->hwfns[hwfn_index]; + rel_sb_id = sb_id / n_hwfns; + + DP_VERBOSE(cdev, NETIF_MSG_INTR, + "hwfn [%d] <--[init]-- SB %04x [0x%04x upper]\n", + hwfn_index, rel_sb_id, sb_id); + + rc = qed_int_sb_init(p_hwfn, p_hwfn->p_main_ptt, sb_info, + sb_virt_addr, sb_phy_addr, rel_sb_id); + + return rc; +} + +static u32 qed_sb_release(struct qed_dev *cdev, + struct qed_sb_info *sb_info, + u16 sb_id) +{ + struct qed_hwfn *p_hwfn; + int hwfn_index; + u16 rel_sb_id; + u32 rc; + + hwfn_index = sb_id % cdev->num_hwfns; + p_hwfn = &cdev->hwfns[hwfn_index]; + rel_sb_id = sb_id / cdev->num_hwfns; + + DP_VERBOSE(cdev, NETIF_MSG_INTR, + "hwfn [%d] <--[init]-- SB %04x [0x%04x upper]\n", + hwfn_index, rel_sb_id, sb_id); + + rc = qed_int_sb_release(p_hwfn, sb_info, rel_sb_id); + + return rc; +} + +static int qed_drain(struct qed_dev *cdev) +{ + struct qed_hwfn *hwfn; + struct qed_ptt *ptt; + int i, rc; + + for_each_hwfn(cdev, i) { + hwfn = &cdev->hwfns[i]; + ptt = qed_ptt_acquire(hwfn); + if (!ptt) { + DP_NOTICE(hwfn, "Failed to drain NIG; No PTT\n"); + return -EBUSY; + } + rc = qed_mcp_drain(hwfn, ptt); + if (rc) + return rc; + qed_ptt_release(hwfn, ptt); + } + + return 0; +} + +const struct qed_common_ops qed_common_ops_pass = { + .probe = &qed_probe, + .remove = &qed_remove, + .set_power_state = &qed_set_power_state, + .set_id = &qed_set_id, + .update_pf_params = &qed_update_pf_params, + .slowpath_start = &qed_slowpath_start, + .slowpath_stop = &qed_slowpath_stop, + .set_fp_int = &qed_set_int_fp, + .get_fp_int = &qed_get_int_fp, + .sb_init = &qed_sb_init, + .sb_release = &qed_sb_release, + .simd_handler_config = &qed_simd_handler_config, + .simd_handler_clean = &qed_simd_handler_clean, + .drain = &qed_drain, + .update_msglvl = &qed_init_dp, + .chain_alloc = &qed_chain_alloc, + .chain_free = &qed_chain_free, +}; + +u32 qed_get_protocol_version(enum qed_protocol protocol) +{ + switch (protocol) { + case QED_PROTOCOL_ETH: + return QED_ETH_INTERFACE_VERSION; + default: + return 0; + } +} +EXPORT_SYMBOL(qed_get_protocol_version); diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.c b/drivers/net/ethernet/qlogic/qed/qed_mcp.c new file mode 100644 index 000000000000..601d3f5daf13 --- /dev/null +++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.c @@ -0,0 +1,549 @@ +/* QLogic qed NIC Driver + * Copyright (c) 2015 QLogic Corporation + * + * This software is available under the terms of the GNU General Public License + * (GPL) Version 2, available from the file COPYING in the main directory of + * this source tree. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "qed.h" +#include "qed_hsi.h" +#include "qed_hw.h" +#include "qed_mcp.h" +#include "qed_reg_addr.h" +#define CHIP_MCP_RESP_ITER_US 10 + +#define QED_DRV_MB_MAX_RETRIES (500 * 1000) /* Account for 5 sec */ +#define QED_MCP_RESET_RETRIES (50 * 1000) /* Account for 500 msec */ + +#define DRV_INNER_WR(_p_hwfn, _p_ptt, _ptr, _offset, _val) \ + qed_wr(_p_hwfn, _p_ptt, (_p_hwfn->mcp_info->_ptr + _offset), \ + _val) + +#define DRV_INNER_RD(_p_hwfn, _p_ptt, _ptr, _offset) \ + qed_rd(_p_hwfn, _p_ptt, (_p_hwfn->mcp_info->_ptr + _offset)) + +#define DRV_MB_WR(_p_hwfn, _p_ptt, _field, _val) \ + DRV_INNER_WR(p_hwfn, _p_ptt, drv_mb_addr, \ + offsetof(struct public_drv_mb, _field), _val) + +#define DRV_MB_RD(_p_hwfn, _p_ptt, _field) \ + DRV_INNER_RD(_p_hwfn, _p_ptt, drv_mb_addr, \ + offsetof(struct public_drv_mb, _field)) + +#define PDA_COMP (((FW_MAJOR_VERSION) + (FW_MINOR_VERSION << 8)) << \ + DRV_ID_PDA_COMP_VER_SHIFT) + +#define MCP_BYTES_PER_MBIT_SHIFT 17 + +bool qed_mcp_is_init(struct qed_hwfn *p_hwfn) +{ + if (!p_hwfn->mcp_info || !p_hwfn->mcp_info->public_base) + return false; + return true; +} + +void qed_mcp_cmd_port_init(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt) +{ + u32 addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base, + PUBLIC_PORT); + u32 mfw_mb_offsize = qed_rd(p_hwfn, p_ptt, addr); + + p_hwfn->mcp_info->port_addr = SECTION_ADDR(mfw_mb_offsize, + MFW_PORT(p_hwfn)); + DP_VERBOSE(p_hwfn, QED_MSG_SP, + "port_addr = 0x%x, port_id 0x%02x\n", + p_hwfn->mcp_info->port_addr, MFW_PORT(p_hwfn)); +} + +void qed_mcp_read_mb(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt) +{ + u32 length = MFW_DRV_MSG_MAX_DWORDS(p_hwfn->mcp_info->mfw_mb_length); + u32 tmp, i; + + if (!p_hwfn->mcp_info->public_base) + return; + + for (i = 0; i < length; i++) { + tmp = qed_rd(p_hwfn, p_ptt, + p_hwfn->mcp_info->mfw_mb_addr + + (i << 2) + sizeof(u32)); + + /* The MB data is actually BE; Need to force it to cpu */ + ((u32 *)p_hwfn->mcp_info->mfw_mb_cur)[i] = + be32_to_cpu((__force __be32)tmp); + } +} + +int qed_mcp_free(struct qed_hwfn *p_hwfn) +{ + if (p_hwfn->mcp_info) { + kfree(p_hwfn->mcp_info->mfw_mb_cur); + kfree(p_hwfn->mcp_info->mfw_mb_shadow); + } + kfree(p_hwfn->mcp_info); + + return 0; +} + +static int qed_load_mcp_offsets(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt) +{ + struct qed_mcp_info *p_info = p_hwfn->mcp_info; + u32 drv_mb_offsize, mfw_mb_offsize; + u32 mcp_pf_id = MCP_PF_ID(p_hwfn); + + p_info->public_base = qed_rd(p_hwfn, p_ptt, MISC_REG_SHARED_MEM_ADDR); + if (!p_info->public_base) + return 0; + + p_info->public_base |= GRCBASE_MCP; + + /* Calculate the driver and MFW mailbox address */ + drv_mb_offsize = qed_rd(p_hwfn, p_ptt, + SECTION_OFFSIZE_ADDR(p_info->public_base, + PUBLIC_DRV_MB)); + p_info->drv_mb_addr = SECTION_ADDR(drv_mb_offsize, mcp_pf_id); + DP_VERBOSE(p_hwfn, QED_MSG_SP, + "drv_mb_offsiz = 0x%x, drv_mb_addr = 0x%x mcp_pf_id = 0x%x\n", + drv_mb_offsize, p_info->drv_mb_addr, mcp_pf_id); + + /* Set the MFW MB address */ + mfw_mb_offsize = qed_rd(p_hwfn, p_ptt, + SECTION_OFFSIZE_ADDR(p_info->public_base, + PUBLIC_MFW_MB)); + p_info->mfw_mb_addr = SECTION_ADDR(mfw_mb_offsize, mcp_pf_id); + p_info->mfw_mb_length = (u16)qed_rd(p_hwfn, p_ptt, p_info->mfw_mb_addr); + + /* Get the current driver mailbox sequence before sending + * the first command + */ + p_info->drv_mb_seq = DRV_MB_RD(p_hwfn, p_ptt, drv_mb_header) & + DRV_MSG_SEQ_NUMBER_MASK; + + /* Get current FW pulse sequence */ + p_info->drv_pulse_seq = DRV_MB_RD(p_hwfn, p_ptt, drv_pulse_mb) & + DRV_PULSE_SEQ_MASK; + + p_info->mcp_hist = (u16)qed_rd(p_hwfn, p_ptt, MISCS_REG_GENERIC_POR_0); + + return 0; +} + +int qed_mcp_cmd_init(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt) +{ + struct qed_mcp_info *p_info; + u32 size; + + /* Allocate mcp_info structure */ + p_hwfn->mcp_info = kzalloc(sizeof(*p_hwfn->mcp_info), GFP_ATOMIC); + if (!p_hwfn->mcp_info) + goto err; + p_info = p_hwfn->mcp_info; + + if (qed_load_mcp_offsets(p_hwfn, p_ptt) != 0) { + DP_NOTICE(p_hwfn, "MCP is not initialized\n"); + /* Do not free mcp_info here, since public_base indicate that + * the MCP is not initialized + */ + return 0; + } + + size = MFW_DRV_MSG_MAX_DWORDS(p_info->mfw_mb_length) * sizeof(u32); + p_info->mfw_mb_cur = kzalloc(size, GFP_ATOMIC); + p_info->mfw_mb_shadow = + kzalloc(sizeof(u32) * MFW_DRV_MSG_MAX_DWORDS( + p_info->mfw_mb_length), GFP_ATOMIC); + if (!p_info->mfw_mb_shadow || !p_info->mfw_mb_addr) + goto err; + + /* Initialize the MFW mutex */ + mutex_init(&p_info->mutex); + + return 0; + +err: + DP_NOTICE(p_hwfn, "Failed to allocate mcp memory\n"); + qed_mcp_free(p_hwfn); + return -ENOMEM; +} + +int qed_mcp_reset(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt) +{ + u32 seq = ++p_hwfn->mcp_info->drv_mb_seq; + u8 delay = CHIP_MCP_RESP_ITER_US; + u32 org_mcp_reset_seq, cnt = 0; + int rc = 0; + + /* Set drv command along with the updated sequence */ + org_mcp_reset_seq = qed_rd(p_hwfn, p_ptt, MISCS_REG_GENERIC_POR_0); + DRV_MB_WR(p_hwfn, p_ptt, drv_mb_header, + (DRV_MSG_CODE_MCP_RESET | seq)); + + do { + /* Wait for MFW response */ + udelay(delay); + /* Give the FW up to 500 second (50*1000*10usec) */ + } while ((org_mcp_reset_seq == qed_rd(p_hwfn, p_ptt, + MISCS_REG_GENERIC_POR_0)) && + (cnt++ < QED_MCP_RESET_RETRIES)); + + if (org_mcp_reset_seq != + qed_rd(p_hwfn, p_ptt, MISCS_REG_GENERIC_POR_0)) { + DP_VERBOSE(p_hwfn, QED_MSG_SP, + "MCP was reset after %d usec\n", cnt * delay); + } else { + DP_ERR(p_hwfn, "Failed to reset MCP\n"); + rc = -EAGAIN; + } + + return rc; +} + +static int qed_do_mcp_cmd(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u32 cmd, + u32 param, + u32 *o_mcp_resp, + u32 *o_mcp_param) +{ + u8 delay = CHIP_MCP_RESP_ITER_US; + u32 seq, cnt = 1, actual_mb_seq; + int rc = 0; + + /* Get actual driver mailbox sequence */ + actual_mb_seq = DRV_MB_RD(p_hwfn, p_ptt, drv_mb_header) & + DRV_MSG_SEQ_NUMBER_MASK; + + /* Use MCP history register to check if MCP reset occurred between + * init time and now. + */ + if (p_hwfn->mcp_info->mcp_hist != + qed_rd(p_hwfn, p_ptt, MISCS_REG_GENERIC_POR_0)) { + DP_VERBOSE(p_hwfn, QED_MSG_SP, "Rereading MCP offsets\n"); + qed_load_mcp_offsets(p_hwfn, p_ptt); + qed_mcp_cmd_port_init(p_hwfn, p_ptt); + } + seq = ++p_hwfn->mcp_info->drv_mb_seq; + + /* Set drv param */ + DRV_MB_WR(p_hwfn, p_ptt, drv_mb_param, param); + + /* Set drv command along with the updated sequence */ + DRV_MB_WR(p_hwfn, p_ptt, drv_mb_header, (cmd | seq)); + + DP_VERBOSE(p_hwfn, QED_MSG_SP, + "wrote command (%x) to MFW MB param 0x%08x\n", + (cmd | seq), param); + + do { + /* Wait for MFW response */ + udelay(delay); + *o_mcp_resp = DRV_MB_RD(p_hwfn, p_ptt, fw_mb_header); + + /* Give the FW up to 5 second (500*10ms) */ + } while ((seq != (*o_mcp_resp & FW_MSG_SEQ_NUMBER_MASK)) && + (cnt++ < QED_DRV_MB_MAX_RETRIES)); + + DP_VERBOSE(p_hwfn, QED_MSG_SP, + "[after %d ms] read (%x) seq is (%x) from FW MB\n", + cnt * delay, *o_mcp_resp, seq); + + /* Is this a reply to our command? */ + if (seq == (*o_mcp_resp & FW_MSG_SEQ_NUMBER_MASK)) { + *o_mcp_resp &= FW_MSG_CODE_MASK; + /* Get the MCP param */ + *o_mcp_param = DRV_MB_RD(p_hwfn, p_ptt, fw_mb_param); + } else { + /* FW BUG! */ + DP_ERR(p_hwfn, "MFW failed to respond!\n"); + *o_mcp_resp = 0; + rc = -EAGAIN; + } + return rc; +} + +int qed_mcp_cmd(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u32 cmd, + u32 param, + u32 *o_mcp_resp, + u32 *o_mcp_param) +{ + int rc = 0; + + /* MCP not initialized */ + if (!qed_mcp_is_init(p_hwfn)) { + DP_NOTICE(p_hwfn, "MFW is not initialized !\n"); + return -EBUSY; + } + + /* Lock Mutex to ensure only single thread is + * accessing the MCP at one time + */ + mutex_lock(&p_hwfn->mcp_info->mutex); + rc = qed_do_mcp_cmd(p_hwfn, p_ptt, cmd, param, + o_mcp_resp, o_mcp_param); + /* Release Mutex */ + mutex_unlock(&p_hwfn->mcp_info->mutex); + + return rc; +} + +static void qed_mcp_set_drv_ver(struct qed_dev *cdev, + struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt) +{ + u32 i; + + /* Copy version string to MCP */ + for (i = 0; i < MCP_DRV_VER_STR_SIZE_DWORD; i++) + DRV_MB_WR(p_hwfn, p_ptt, union_data.ver_str[i], + *(u32 *)&cdev->ver_str[i * sizeof(u32)]); +} + +int qed_mcp_load_req(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u32 *p_load_code) +{ + struct qed_dev *cdev = p_hwfn->cdev; + u32 param; + int rc; + + if (!qed_mcp_is_init(p_hwfn)) { + DP_NOTICE(p_hwfn, "MFW is not initialized !\n"); + return -EBUSY; + } + + /* Save driver's version to shmem */ + qed_mcp_set_drv_ver(cdev, p_hwfn, p_ptt); + + DP_VERBOSE(p_hwfn, QED_MSG_SP, "fw_seq 0x%08x, drv_pulse 0x%x\n", + p_hwfn->mcp_info->drv_mb_seq, + p_hwfn->mcp_info->drv_pulse_seq); + + /* Load Request */ + rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_LOAD_REQ, + (PDA_COMP | DRV_ID_MCP_HSI_VER_CURRENT | + cdev->drv_type), + p_load_code, ¶m); + + /* if mcp fails to respond we must abort */ + if (rc) { + DP_ERR(p_hwfn, "MCP response failure, aborting\n"); + return rc; + } + + /* If MFW refused (e.g. other port is in diagnostic mode) we + * must abort. This can happen in the following cases: + * - Other port is in diagnostic mode + * - Previously loaded function on the engine is not compliant with + * the requester. + * - MFW cannot cope with the requester's DRV_MFW_HSI_VERSION. + * - + */ + if (!(*p_load_code) || + ((*p_load_code) == FW_MSG_CODE_DRV_LOAD_REFUSED_HSI) || + ((*p_load_code) == FW_MSG_CODE_DRV_LOAD_REFUSED_PDA) || + ((*p_load_code) == FW_MSG_CODE_DRV_LOAD_REFUSED_DIAG)) { + DP_ERR(p_hwfn, "MCP refused load request, aborting\n"); + return -EBUSY; + } + + return 0; +} + +int qed_mcp_get_mfw_ver(struct qed_dev *cdev, + u32 *p_mfw_ver) +{ + struct qed_hwfn *p_hwfn = &cdev->hwfns[0]; + struct qed_ptt *p_ptt; + u32 global_offsize; + + p_ptt = qed_ptt_acquire(p_hwfn); + if (!p_ptt) + return -EBUSY; + + global_offsize = qed_rd(p_hwfn, p_ptt, + SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info-> + public_base, + PUBLIC_GLOBAL)); + *p_mfw_ver = qed_rd(p_hwfn, p_ptt, + SECTION_ADDR(global_offsize, 0) + + offsetof(struct public_global, mfw_ver)); + + qed_ptt_release(p_hwfn, p_ptt); + + return 0; +} + +static u32 qed_mcp_get_shmem_func(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + struct public_func *p_data, + int pfid) +{ + u32 addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base, + PUBLIC_FUNC); + u32 mfw_path_offsize = qed_rd(p_hwfn, p_ptt, addr); + u32 func_addr = SECTION_ADDR(mfw_path_offsize, pfid); + u32 i, size; + + memset(p_data, 0, sizeof(*p_data)); + + size = min_t(u32, sizeof(*p_data), + QED_SECTION_SIZE(mfw_path_offsize)); + for (i = 0; i < size / sizeof(u32); i++) + ((u32 *)p_data)[i] = qed_rd(p_hwfn, p_ptt, + func_addr + (i << 2)); + + return size; +} + +static int +qed_mcp_get_shmem_proto(struct qed_hwfn *p_hwfn, + struct public_func *p_info, + enum qed_pci_personality *p_proto) +{ + int rc = 0; + + switch (p_info->config & FUNC_MF_CFG_PROTOCOL_MASK) { + case FUNC_MF_CFG_PROTOCOL_ETHERNET: + *p_proto = QED_PCI_ETH; + break; + default: + rc = -EINVAL; + } + + return rc; +} + +int qed_mcp_fill_shmem_func_info(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt) +{ + struct qed_mcp_function_info *info; + struct public_func shmem_info; + + qed_mcp_get_shmem_func(p_hwfn, p_ptt, &shmem_info, + MCP_PF_ID(p_hwfn)); + info = &p_hwfn->mcp_info->func_info; + + info->pause_on_host = (shmem_info.config & + FUNC_MF_CFG_PAUSE_ON_HOST_RING) ? 1 : 0; + + if (qed_mcp_get_shmem_proto(p_hwfn, &shmem_info, + &info->protocol)) { + DP_ERR(p_hwfn, "Unknown personality %08x\n", + (u32)(shmem_info.config & FUNC_MF_CFG_PROTOCOL_MASK)); + return -EINVAL; + } + + if (p_hwfn->cdev->mf_mode != SF) { + info->bandwidth_min = (shmem_info.config & + FUNC_MF_CFG_MIN_BW_MASK) >> + FUNC_MF_CFG_MIN_BW_SHIFT; + if (info->bandwidth_min < 1 || info->bandwidth_min > 100) { + DP_INFO(p_hwfn, + "bandwidth minimum out of bounds [%02x]. Set to 1\n", + info->bandwidth_min); + info->bandwidth_min = 1; + } + + info->bandwidth_max = (shmem_info.config & + FUNC_MF_CFG_MAX_BW_MASK) >> + FUNC_MF_CFG_MAX_BW_SHIFT; + if (info->bandwidth_max < 1 || info->bandwidth_max > 100) { + DP_INFO(p_hwfn, + "bandwidth maximum out of bounds [%02x]. Set to 100\n", + info->bandwidth_max); + info->bandwidth_max = 100; + } + } + + if (shmem_info.mac_upper || shmem_info.mac_lower) { + info->mac[0] = (u8)(shmem_info.mac_upper >> 8); + info->mac[1] = (u8)(shmem_info.mac_upper); + info->mac[2] = (u8)(shmem_info.mac_lower >> 24); + info->mac[3] = (u8)(shmem_info.mac_lower >> 16); + info->mac[4] = (u8)(shmem_info.mac_lower >> 8); + info->mac[5] = (u8)(shmem_info.mac_lower); + } else { + DP_NOTICE(p_hwfn, "MAC is 0 in shmem\n"); + } + + info->wwn_port = (u64)shmem_info.fcoe_wwn_port_name_upper | + (((u64)shmem_info.fcoe_wwn_port_name_lower) << 32); + info->wwn_node = (u64)shmem_info.fcoe_wwn_node_name_upper | + (((u64)shmem_info.fcoe_wwn_node_name_lower) << 32); + + info->ovlan = (u16)(shmem_info.ovlan_stag & FUNC_MF_CFG_OV_STAG_MASK); + + DP_VERBOSE(p_hwfn, (QED_MSG_SP | NETIF_MSG_IFUP), + "Read configuration from shmem: pause_on_host %02x protocol %02x BW [%02x - %02x] MAC %02x:%02x:%02x:%02x:%02x:%02x wwn port %llx node %llx ovlan %04x\n", + info->pause_on_host, info->protocol, + info->bandwidth_min, info->bandwidth_max, + info->mac[0], info->mac[1], info->mac[2], + info->mac[3], info->mac[4], info->mac[5], + info->wwn_port, info->wwn_node, info->ovlan); + + return 0; +} + +int qed_mcp_drain(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt) +{ + u32 resp = 0, param = 0; + int rc; + + rc = qed_mcp_cmd(p_hwfn, p_ptt, + DRV_MSG_CODE_NIG_DRAIN, 100, + &resp, ¶m); + + /* Wait for the drain to complete before returning */ + msleep(120); + + return rc; +} + +int +qed_mcp_send_drv_version(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + struct qed_mcp_drv_version *p_ver) +{ + int rc = 0; + u32 param = 0, reply = 0, i; + + if (!qed_mcp_is_init(p_hwfn)) { + DP_NOTICE(p_hwfn, "MFW is not initialized !\n"); + return -EBUSY; + } + + DRV_MB_WR(p_hwfn, p_ptt, union_data.drv_version.version, + p_ver->version); + /* Copy version string to shmem */ + for (i = 0; i < (MCP_DRV_VER_STR_SIZE - 4) / 4; i++) { + DRV_MB_WR(p_hwfn, p_ptt, + union_data.drv_version.name[i * sizeof(u32)], + *(u32 *)&p_ver->name[i * sizeof(u32)]); + } + + rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_SET_VERSION, 0, &reply, + ¶m); + if (rc) { + DP_ERR(p_hwfn, "MCP response failure, aborting\n"); + return rc; + } + + return 0; +} diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.h b/drivers/net/ethernet/qlogic/qed/qed_mcp.h new file mode 100644 index 000000000000..230c2550dc89 --- /dev/null +++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.h @@ -0,0 +1,232 @@ +/* QLogic qed NIC Driver + * Copyright (c) 2015 QLogic Corporation + * + * This software is available under the terms of the GNU General Public License + * (GPL) Version 2, available from the file COPYING in the main directory of + * this source tree. + */ + +#ifndef _QED_MCP_H +#define _QED_MCP_H + +#include +#include +#include +#include +#include "qed_hsi.h" + +struct qed_mcp_function_info { + u8 pause_on_host; + + enum qed_pci_personality protocol; + + u8 bandwidth_min; + u8 bandwidth_max; + + u8 mac[ETH_ALEN]; + + u64 wwn_port; + u64 wwn_node; + +#define QED_MCP_VLAN_UNSET (0xffff) + u16 ovlan; +}; + +struct qed_mcp_nvm_common { + u32 offset; + u32 param; + u32 resp; + u32 cmd; +}; + +struct qed_mcp_drv_version { + u32 version; + u8 name[MCP_DRV_VER_STR_SIZE - 4]; +}; + +/** + * @brief Get the management firmware version value + * + * @param cdev - qed dev pointer + * @param mfw_ver - mfw version value + * + * @return int - 0 - operation was successul. + */ +int qed_mcp_get_mfw_ver(struct qed_dev *cdev, + u32 *mfw_ver); + +/** + * @brief General function for sending commands to the MCP + * mailbox. It acquire mutex lock for the entire + * operation, from sending the request until the MCP + * response. Waiting for MCP response will be checked up + * to 5 seconds every 5ms. + * + * @param p_hwfn - hw function + * @param p_ptt - PTT required for register access + * @param cmd - command to be sent to the MCP. + * @param param - Optional param + * @param o_mcp_resp - The MCP response code (exclude sequence). + * @param o_mcp_param- Optional parameter provided by the MCP + * response + * @return int - 0 - operation + * was successul. + */ +int qed_mcp_cmd(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u32 cmd, + u32 param, + u32 *o_mcp_resp, + u32 *o_mcp_param); + +/** + * @brief - drains the nig, allowing completion to pass in case of pauses. + * (Should be called only from sleepable context) + * + * @param p_hwfn + * @param p_ptt + */ +int qed_mcp_drain(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt); + +/** + * @brief Send driver version to MFW + * + * @param p_hwfn + * @param p_ptt + * @param version - Version value + * @param name - Protocol driver name + * + * @return int - 0 - operation was successul. + */ +int +qed_mcp_send_drv_version(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + struct qed_mcp_drv_version *p_ver); + +/* Using hwfn number (and not pf_num) is required since in CMT mode, + * same pf_num may be used by two different hwfn + * TODO - this shouldn't really be in .h file, but until all fields + * required during hw-init will be placed in their correct place in shmem + * we need it in qed_dev.c [for readin the nvram reflection in shmem]. + */ +#define MCP_PF_ID_BY_REL(p_hwfn, rel_pfid) (QED_IS_BB((p_hwfn)->cdev) ? \ + ((rel_pfid) | \ + ((p_hwfn)->abs_pf_id & 1) << 3) : \ + rel_pfid) +#define MCP_PF_ID(p_hwfn) MCP_PF_ID_BY_REL(p_hwfn, (p_hwfn)->rel_pf_id) + +/* TODO - this is only correct as long as only BB is supported, and + * no port-swapping is implemented; Afterwards we'll need to fix it. + */ +#define MFW_PORT(_p_hwfn) ((_p_hwfn)->abs_pf_id % \ + ((_p_hwfn)->cdev->num_ports_in_engines * 2)) +struct qed_mcp_info { + struct mutex mutex; /* MCP access lock */ + u32 public_base; + u32 drv_mb_addr; + u32 mfw_mb_addr; + u32 port_addr; + u16 drv_mb_seq; + u16 drv_pulse_seq; + struct qed_mcp_function_info func_info; + + u8 *mfw_mb_cur; + u8 *mfw_mb_shadow; + u16 mfw_mb_length; + u16 mcp_hist; +}; + +/** + * @brief Initialize the interface with the MCP + * + * @param p_hwfn - HW func + * @param p_ptt - PTT required for register access + * + * @return int + */ +int qed_mcp_cmd_init(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt); + +/** + * @brief Initialize the port interface with the MCP + * + * @param p_hwfn + * @param p_ptt + * Can only be called after `num_ports_in_engines' is set + */ +void qed_mcp_cmd_port_init(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt); +/** + * @brief Releases resources allocated during the init process. + * + * @param p_hwfn - HW func + * @param p_ptt - PTT required for register access + * + * @return int + */ + +int qed_mcp_free(struct qed_hwfn *p_hwfn); + +/** + * @brief Sends a LOAD_REQ to the MFW, and in case operation + * succeed, returns whether this PF is the first on the + * chip/engine/port or function. This function should be + * called when driver is ready to accept MFW events after + * Storms initializations are done. + * + * @param p_hwfn - hw function + * @param p_ptt - PTT required for register access + * @param p_load_code - The MCP response param containing one + * of the following: + * FW_MSG_CODE_DRV_LOAD_ENGINE + * FW_MSG_CODE_DRV_LOAD_PORT + * FW_MSG_CODE_DRV_LOAD_FUNCTION + * @return int - + * 0 - Operation was successul. + * -EBUSY - Operation failed + */ +int qed_mcp_load_req(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u32 *p_load_code); + +/** + * @brief Read the MFW mailbox into Current buffer. + * + * @param p_hwfn + * @param p_ptt + */ +void qed_mcp_read_mb(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt); + +/** + * @brief - calls during init to read shmem of all function-related info. + * + * @param p_hwfn + * + * @param return 0 upon success. + */ +int qed_mcp_fill_shmem_func_info(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt); + +/** + * @brief - Reset the MCP using mailbox command. + * + * @param p_hwfn + * @param p_ptt + * + * @param return 0 upon success. + */ +int qed_mcp_reset(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt); + +/** + * @brief indicates whether the MFW objects [under mcp_info] are accessible + * + * @param p_hwfn + * + * @return true iff MFW is running and mcp_info is initialized + */ +bool qed_mcp_is_init(struct qed_hwfn *p_hwfn); + +#endif diff --git a/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h b/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h new file mode 100644 index 000000000000..7a5ce5914ace --- /dev/null +++ b/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h @@ -0,0 +1,366 @@ +/* QLogic qed NIC Driver + * Copyright (c) 2015 QLogic Corporation + * + * This software is available under the terms of the GNU General Public License + * (GPL) Version 2, available from the file COPYING in the main directory of + * this source tree. + */ + +#ifndef REG_ADDR_H +#define REG_ADDR_H + +#define CDU_REG_CID_ADDR_PARAMS_CONTEXT_SIZE_SHIFT \ + 0 + +#define CDU_REG_CID_ADDR_PARAMS_CONTEXT_SIZE ( \ + 0xfff << 0) + +#define CDU_REG_CID_ADDR_PARAMS_BLOCK_WASTE_SHIFT \ + 12 + +#define CDU_REG_CID_ADDR_PARAMS_BLOCK_WASTE ( \ + 0xfff << 12) + +#define CDU_REG_CID_ADDR_PARAMS_NCIB_SHIFT \ + 24 + +#define CDU_REG_CID_ADDR_PARAMS_NCIB ( \ + 0xff << 24) + +#define XSDM_REG_OPERATION_GEN \ + 0xf80408UL +#define NIG_REG_RX_BRB_OUT_EN \ + 0x500e18UL +#define NIG_REG_STORM_OUT_EN \ + 0x500e08UL +#define PSWRQ2_REG_L2P_VALIDATE_VFID \ + 0x240c50UL +#define PGLUE_B_REG_USE_CLIENTID_IN_TAG \ + 0x2aae04UL +#define PGLUE_B_REG_INTERNAL_PFID_ENABLE_MASTER \ + 0x2aa16cUL +#define BAR0_MAP_REG_MSDM_RAM \ + 0x1d00000UL +#define BAR0_MAP_REG_USDM_RAM \ + 0x1d80000UL +#define BAR0_MAP_REG_PSDM_RAM \ + 0x1f00000UL +#define BAR0_MAP_REG_TSDM_RAM \ + 0x1c80000UL +#define NIG_REG_RX_LLH_BRB_GATE_DNTFWD_PERPF \ + 0x5011f4UL +#define PRS_REG_SEARCH_TCP \ + 0x1f0400UL +#define PRS_REG_SEARCH_UDP \ + 0x1f0404UL +#define PRS_REG_SEARCH_FCOE \ + 0x1f0408UL +#define PRS_REG_SEARCH_ROCE \ + 0x1f040cUL +#define PRS_REG_SEARCH_OPENFLOW \ + 0x1f0434UL +#define TM_REG_PF_ENABLE_CONN \ + 0x2c043cUL +#define TM_REG_PF_ENABLE_TASK \ + 0x2c0444UL +#define TM_REG_PF_SCAN_ACTIVE_CONN \ + 0x2c04fcUL +#define TM_REG_PF_SCAN_ACTIVE_TASK \ + 0x2c0500UL +#define IGU_REG_LEADING_EDGE_LATCH \ + 0x18082cUL +#define IGU_REG_TRAILING_EDGE_LATCH \ + 0x180830UL +#define QM_REG_USG_CNT_PF_TX \ + 0x2f2eacUL +#define QM_REG_USG_CNT_PF_OTHER \ + 0x2f2eb0UL +#define DORQ_REG_PF_DB_ENABLE \ + 0x100508UL +#define QM_REG_PF_EN \ + 0x2f2ea4UL +#define TCFC_REG_STRONG_ENABLE_PF \ + 0x2d0708UL +#define CCFC_REG_STRONG_ENABLE_PF \ + 0x2e0708UL +#define PGLUE_B_REG_PGL_ADDR_88_F0 \ + 0x2aa404UL +#define PGLUE_B_REG_PGL_ADDR_8C_F0 \ + 0x2aa408UL +#define PGLUE_B_REG_PGL_ADDR_90_F0 \ + 0x2aa40cUL +#define PGLUE_B_REG_PGL_ADDR_94_F0 \ + 0x2aa410UL +#define PGLUE_B_REG_WAS_ERROR_PF_31_0_CLR \ + 0x2aa138UL +#define PGLUE_B_REG_INTERNAL_PFID_ENABLE_TARGET_READ \ + 0x2aa174UL +#define MISC_REG_GEN_PURP_CR0 \ + 0x008c80UL +#define MCP_REG_SCRATCH \ + 0xe20000UL +#define CNIG_REG_NW_PORT_MODE_BB_B0 \ + 0x218200UL +#define MISCS_REG_CHIP_NUM \ + 0x00976cUL +#define MISCS_REG_CHIP_REV \ + 0x009770UL +#define MISCS_REG_CMT_ENABLED_FOR_PAIR \ + 0x00971cUL +#define MISCS_REG_CHIP_TEST_REG \ + 0x009778UL +#define MISCS_REG_CHIP_METAL \ + 0x009774UL +#define BRB_REG_HEADER_SIZE \ + 0x340804UL +#define BTB_REG_HEADER_SIZE \ + 0xdb0804UL +#define CAU_REG_LONG_TIMEOUT_THRESHOLD \ + 0x1c0708UL +#define CCFC_REG_ACTIVITY_COUNTER \ + 0x2e8800UL +#define CDU_REG_CID_ADDR_PARAMS \ + 0x580900UL +#define DBG_REG_CLIENT_ENABLE \ + 0x010004UL +#define DMAE_REG_INIT \ + 0x00c000UL +#define DORQ_REG_IFEN \ + 0x100040UL +#define GRC_REG_TIMEOUT_EN \ + 0x050404UL +#define IGU_REG_BLOCK_CONFIGURATION \ + 0x180040UL +#define MCM_REG_INIT \ + 0x1200000UL +#define MCP2_REG_DBG_DWORD_ENABLE \ + 0x052404UL +#define MISC_REG_PORT_MODE \ + 0x008c00UL +#define MISCS_REG_CLK_100G_MODE \ + 0x009070UL +#define MSDM_REG_ENABLE_IN1 \ + 0xfc0004UL +#define MSEM_REG_ENABLE_IN \ + 0x1800004UL +#define NIG_REG_CM_HDR \ + 0x500840UL +#define NCSI_REG_CONFIG \ + 0x040200UL +#define PBF_REG_INIT \ + 0xd80000UL +#define PTU_REG_ATC_INIT_ARRAY \ + 0x560000UL +#define PCM_REG_INIT \ + 0x1100000UL +#define PGLUE_B_REG_ADMIN_PER_PF_REGION \ + 0x2a9000UL +#define PRM_REG_DISABLE_PRM \ + 0x230000UL +#define PRS_REG_SOFT_RST \ + 0x1f0000UL +#define PSDM_REG_ENABLE_IN1 \ + 0xfa0004UL +#define PSEM_REG_ENABLE_IN \ + 0x1600004UL +#define PSWRQ_REG_DBG_SELECT \ + 0x280020UL +#define PSWRQ2_REG_CDUT_P_SIZE \ + 0x24000cUL +#define PSWHST_REG_DISCARD_INTERNAL_WRITES \ + 0x2a0040UL +#define PSWHST2_REG_DBGSYN_ALMOST_FULL_THR \ + 0x29e050UL +#define PSWRD_REG_DBG_SELECT \ + 0x29c040UL +#define PSWRD2_REG_CONF11 \ + 0x29d064UL +#define PSWWR_REG_USDM_FULL_TH \ + 0x29a040UL +#define PSWWR2_REG_CDU_FULL_TH2 \ + 0x29b040UL +#define QM_REG_MAXPQSIZE_0 \ + 0x2f0434UL +#define RSS_REG_RSS_INIT_EN \ + 0x238804UL +#define RDIF_REG_STOP_ON_ERROR \ + 0x300040UL +#define SRC_REG_SOFT_RST \ + 0x23874cUL +#define TCFC_REG_ACTIVITY_COUNTER \ + 0x2d8800UL +#define TCM_REG_INIT \ + 0x1180000UL +#define TM_REG_PXP_READ_DATA_FIFO_INIT \ + 0x2c0014UL +#define TSDM_REG_ENABLE_IN1 \ + 0xfb0004UL +#define TSEM_REG_ENABLE_IN \ + 0x1700004UL +#define TDIF_REG_STOP_ON_ERROR \ + 0x310040UL +#define UCM_REG_INIT \ + 0x1280000UL +#define UMAC_REG_IPG_HD_BKP_CNTL_BB_B0 \ + 0x051004UL +#define USDM_REG_ENABLE_IN1 \ + 0xfd0004UL +#define USEM_REG_ENABLE_IN \ + 0x1900004UL +#define XCM_REG_INIT \ + 0x1000000UL +#define XSDM_REG_ENABLE_IN1 \ + 0xf80004UL +#define XSEM_REG_ENABLE_IN \ + 0x1400004UL +#define YCM_REG_INIT \ + 0x1080000UL +#define YSDM_REG_ENABLE_IN1 \ + 0xf90004UL +#define YSEM_REG_ENABLE_IN \ + 0x1500004UL +#define XYLD_REG_SCBD_STRICT_PRIO \ + 0x4c0000UL +#define TMLD_REG_SCBD_STRICT_PRIO \ + 0x4d0000UL +#define MULD_REG_SCBD_STRICT_PRIO \ + 0x4e0000UL +#define YULD_REG_SCBD_STRICT_PRIO \ + 0x4c8000UL +#define MISC_REG_SHARED_MEM_ADDR \ + 0x008c20UL +#define DMAE_REG_GO_C0 \ + 0x00c048UL +#define DMAE_REG_GO_C1 \ + 0x00c04cUL +#define DMAE_REG_GO_C2 \ + 0x00c050UL +#define DMAE_REG_GO_C3 \ + 0x00c054UL +#define DMAE_REG_GO_C4 \ + 0x00c058UL +#define DMAE_REG_GO_C5 \ + 0x00c05cUL +#define DMAE_REG_GO_C6 \ + 0x00c060UL +#define DMAE_REG_GO_C7 \ + 0x00c064UL +#define DMAE_REG_GO_C8 \ + 0x00c068UL +#define DMAE_REG_GO_C9 \ + 0x00c06cUL +#define DMAE_REG_GO_C10 \ + 0x00c070UL +#define DMAE_REG_GO_C11 \ + 0x00c074UL +#define DMAE_REG_GO_C12 \ + 0x00c078UL +#define DMAE_REG_GO_C13 \ + 0x00c07cUL +#define DMAE_REG_GO_C14 \ + 0x00c080UL +#define DMAE_REG_GO_C15 \ + 0x00c084UL +#define DMAE_REG_GO_C16 \ + 0x00c088UL +#define DMAE_REG_GO_C17 \ + 0x00c08cUL +#define DMAE_REG_GO_C18 \ + 0x00c090UL +#define DMAE_REG_GO_C19 \ + 0x00c094UL +#define DMAE_REG_GO_C20 \ + 0x00c098UL +#define DMAE_REG_GO_C21 \ + 0x00c09cUL +#define DMAE_REG_GO_C22 \ + 0x00c0a0UL +#define DMAE_REG_GO_C23 \ + 0x00c0a4UL +#define DMAE_REG_GO_C24 \ + 0x00c0a8UL +#define DMAE_REG_GO_C25 \ + 0x00c0acUL +#define DMAE_REG_GO_C26 \ + 0x00c0b0UL +#define DMAE_REG_GO_C27 \ + 0x00c0b4UL +#define DMAE_REG_GO_C28 \ + 0x00c0b8UL +#define DMAE_REG_GO_C29 \ + 0x00c0bcUL +#define DMAE_REG_GO_C30 \ + 0x00c0c0UL +#define DMAE_REG_GO_C31 \ + 0x00c0c4UL +#define DMAE_REG_CMD_MEM \ + 0x00c800UL +#define QM_REG_MAXPQSIZETXSEL_0 \ + 0x2f0440UL +#define QM_REG_SDMCMDREADY \ + 0x2f1e10UL +#define QM_REG_SDMCMDADDR \ + 0x2f1e04UL +#define QM_REG_SDMCMDDATALSB \ + 0x2f1e08UL +#define QM_REG_SDMCMDDATAMSB \ + 0x2f1e0cUL +#define QM_REG_SDMCMDGO \ + 0x2f1e14UL +#define QM_REG_RLPFCRD \ + 0x2f4d80UL +#define QM_REG_RLPFINCVAL \ + 0x2f4c80UL +#define QM_REG_RLGLBLCRD \ + 0x2f4400UL +#define QM_REG_RLGLBLINCVAL \ + 0x2f3400UL +#define IGU_REG_ATTENTION_ENABLE \ + 0x18083cUL +#define IGU_REG_ATTN_MSG_ADDR_L \ + 0x180820UL +#define IGU_REG_ATTN_MSG_ADDR_H \ + 0x180824UL +#define MISC_REG_AEU_GENERAL_ATTN_0 \ + 0x008400UL +#define CAU_REG_SB_ADDR_MEMORY \ + 0x1c8000UL +#define CAU_REG_SB_VAR_MEMORY \ + 0x1c6000UL +#define CAU_REG_PI_MEMORY \ + 0x1d0000UL +#define IGU_REG_PF_CONFIGURATION \ + 0x180800UL +#define MISC_REG_AEU_ENABLE1_IGU_OUT_0 \ + 0x00849cUL +#define MISC_REG_AEU_MASK_ATTN_IGU \ + 0x008494UL +#define IGU_REG_CLEANUP_STATUS_0 \ + 0x180980UL +#define IGU_REG_CLEANUP_STATUS_1 \ + 0x180a00UL +#define IGU_REG_CLEANUP_STATUS_2 \ + 0x180a80UL +#define IGU_REG_CLEANUP_STATUS_3 \ + 0x180b00UL +#define IGU_REG_CLEANUP_STATUS_4 \ + 0x180b80UL +#define IGU_REG_COMMAND_REG_32LSB_DATA \ + 0x180840UL +#define IGU_REG_COMMAND_REG_CTRL \ + 0x180848UL +#define IGU_REG_BLOCK_CONFIGURATION_VF_CLEANUP_EN ( \ + 0x1 << 1) +#define IGU_REG_BLOCK_CONFIGURATION_PXP_TPH_INTERFACE_EN ( \ + 0x1 << 0) +#define IGU_REG_MAPPING_MEMORY \ + 0x184000UL +#define MISCS_REG_GENERIC_POR_0 \ + 0x0096d4UL +#define MCP_REG_NVM_CFG4 \ + 0xe0642cUL +#define MCP_REG_NVM_CFG4_FLASH_SIZE ( \ + 0x7 << 0) +#define MCP_REG_NVM_CFG4_FLASH_SIZE_SHIFT \ + 0 +#endif diff --git a/drivers/net/ethernet/qlogic/qed/qed_sp.h b/drivers/net/ethernet/qlogic/qed/qed_sp.h new file mode 100644 index 000000000000..74657d227583 --- /dev/null +++ b/drivers/net/ethernet/qlogic/qed/qed_sp.h @@ -0,0 +1,333 @@ +/* QLogic qed NIC Driver + * Copyright (c) 2015 QLogic Corporation + * + * This software is available under the terms of the GNU General Public License + * (GPL) Version 2, available from the file COPYING in the main directory of + * this source tree. + */ + +#ifndef _QED_SP_H +#define _QED_SP_H + +#include +#include +#include +#include +#include +#include +#include "qed.h" +#include "qed_hsi.h" + +enum spq_mode { + QED_SPQ_MODE_BLOCK, /* Client will poll a designated mem. address */ + QED_SPQ_MODE_CB, /* Client supplies a callback */ + QED_SPQ_MODE_EBLOCK, /* QED should block until completion */ +}; + +struct qed_spq_comp_cb { + void (*function)(struct qed_hwfn *, + void *, + union event_ring_data *, + u8 fw_return_code); + void *cookie; +}; + +union ramrod_data { + struct pf_start_ramrod_data pf_start; +}; + +#define EQ_MAX_CREDIT 0xffffffff + +enum spq_priority { + QED_SPQ_PRIORITY_NORMAL, + QED_SPQ_PRIORITY_HIGH, +}; + +union qed_spq_req_comp { + struct qed_spq_comp_cb cb; + u64 *done_addr; +}; + +struct qed_spq_comp_done { + u64 done; + u8 fw_return_code; +}; + +struct qed_spq_entry { + struct list_head list; + + u8 flags; + + /* HSI slow path element */ + struct slow_path_element elem; + + union ramrod_data ramrod; + + enum spq_priority priority; + + /* pending queue for this entry */ + struct list_head *queue; + + enum spq_mode comp_mode; + struct qed_spq_comp_cb comp_cb; + struct qed_spq_comp_done comp_done; /* SPQ_MODE_EBLOCK */ +}; + +struct qed_eq { + struct qed_chain chain; + u8 eq_sb_index; /* index within the SB */ + __le16 *p_fw_cons; /* ptr to index value */ +}; + +struct qed_consq { + struct qed_chain chain; +}; + +struct qed_spq { + spinlock_t lock; /* SPQ lock */ + + struct list_head unlimited_pending; + struct list_head pending; + struct list_head completion_pending; + struct list_head free_pool; + + struct qed_chain chain; + + /* allocated dma-able memory for spq entries (+ramrod data) */ + dma_addr_t p_phys; + struct qed_spq_entry *p_virt; + + /* Used as index for completions (returns on EQ by FW) */ + u16 echo_idx; + + /* Statistics */ + u32 unlimited_pending_count; + u32 normal_count; + u32 high_count; + u32 comp_sent_count; + u32 comp_count; + + u32 cid; +}; + +/** + * @brief qed_spq_post - Posts a Slow hwfn request to FW, or lacking that + * Pends it to the future list. + * + * @param p_hwfn + * @param p_req + * + * @return int + */ +int qed_spq_post(struct qed_hwfn *p_hwfn, + struct qed_spq_entry *p_ent, + u8 *fw_return_code); + +/** + * @brief qed_spq_allocate - Alloocates & initializes the SPQ and EQ. + * + * @param p_hwfn + * + * @return int + */ +int qed_spq_alloc(struct qed_hwfn *p_hwfn); + +/** + * @brief qed_spq_setup - Reset the SPQ to its start state. + * + * @param p_hwfn + */ +void qed_spq_setup(struct qed_hwfn *p_hwfn); + +/** + * @brief qed_spq_deallocate - Deallocates the given SPQ struct. + * + * @param p_hwfn + */ +void qed_spq_free(struct qed_hwfn *p_hwfn); + +/** + * @brief qed_spq_get_entry - Obtain an entrry from the spq + * free pool list. + * + * + * + * @param p_hwfn + * @param pp_ent + * + * @return int + */ +int +qed_spq_get_entry(struct qed_hwfn *p_hwfn, + struct qed_spq_entry **pp_ent); + +/** + * @brief qed_spq_return_entry - Return an entry to spq free + * pool list + * + * @param p_hwfn + * @param p_ent + */ +void qed_spq_return_entry(struct qed_hwfn *p_hwfn, + struct qed_spq_entry *p_ent); +/** + * @brief qed_eq_allocate - Allocates & initializes an EQ struct + * + * @param p_hwfn + * @param num_elem number of elements in the eq + * + * @return struct qed_eq* - a newly allocated structure; NULL upon error. + */ +struct qed_eq *qed_eq_alloc(struct qed_hwfn *p_hwfn, + u16 num_elem); + +/** + * @brief qed_eq_setup - Reset the SPQ to its start state. + * + * @param p_hwfn + * @param p_eq + */ +void qed_eq_setup(struct qed_hwfn *p_hwfn, + struct qed_eq *p_eq); + +/** + * @brief qed_eq_deallocate - deallocates the given EQ struct. + * + * @param p_hwfn + * @param p_eq + */ +void qed_eq_free(struct qed_hwfn *p_hwfn, + struct qed_eq *p_eq); + +/** + * @brief qed_eq_prod_update - update the FW with default EQ producer + * + * @param p_hwfn + * @param prod + */ +void qed_eq_prod_update(struct qed_hwfn *p_hwfn, + u16 prod); + +/** + * @brief qed_eq_completion - Completes currently pending EQ elements + * + * @param p_hwfn + * @param cookie + * + * @return int + */ +int qed_eq_completion(struct qed_hwfn *p_hwfn, + void *cookie); + +/** + * @brief qed_spq_completion - Completes a single event + * + * @param p_hwfn + * @param echo - echo value from cookie (used for determining completion) + * @param p_data - data from cookie (used in callback function if applicable) + * + * @return int + */ +int qed_spq_completion(struct qed_hwfn *p_hwfn, + __le16 echo, + u8 fw_return_code, + union event_ring_data *p_data); + +/** + * @brief qed_spq_get_cid - Given p_hwfn, return cid for the hwfn's SPQ + * + * @param p_hwfn + * + * @return u32 - SPQ CID + */ +u32 qed_spq_get_cid(struct qed_hwfn *p_hwfn); + +/** + * @brief qed_consq_alloc - Allocates & initializes an ConsQ + * struct + * + * @param p_hwfn + * + * @return struct qed_eq* - a newly allocated structure; NULL upon error. + */ +struct qed_consq *qed_consq_alloc(struct qed_hwfn *p_hwfn); + +/** + * @brief qed_consq_setup - Reset the ConsQ to its start + * state. + * + * @param p_hwfn + * @param p_eq + */ +void qed_consq_setup(struct qed_hwfn *p_hwfn, + struct qed_consq *p_consq); + +/** + * @brief qed_consq_free - deallocates the given ConsQ struct. + * + * @param p_hwfn + * @param p_eq + */ +void qed_consq_free(struct qed_hwfn *p_hwfn, + struct qed_consq *p_consq); + +/** + * @file + * + * @brief Slow-hwfn low-level commands (Ramrods) function definitions. + */ + +#define QED_SP_EQ_COMPLETION 0x01 +#define QED_SP_CQE_COMPLETION 0x02 + +struct qed_sp_init_request_params { + size_t ramrod_data_size; + enum spq_mode comp_mode; + struct qed_spq_comp_cb *p_comp_data; +}; + +int qed_sp_init_request(struct qed_hwfn *p_hwfn, + struct qed_spq_entry **pp_ent, + u32 cid, + u16 opaque_fid, + u8 cmd, + u8 protocol, + struct qed_sp_init_request_params *p_params); + +/** + * @brief qed_sp_pf_start - PF Function Start Ramrod + * + * This ramrod is sent to initialize a physical function (PF). It will + * configure the function related parameters and write its completion to the + * event ring specified in the parameters. + * + * Ramrods complete on the common event ring for the PF. This ring is + * allocated by the driver on host memory and its parameters are written + * to the internal RAM of the UStorm by the Function Start Ramrod. + * + * @param p_hwfn + * @param mode + * + * @return int + */ + +int qed_sp_pf_start(struct qed_hwfn *p_hwfn, + enum mf_mode mode); + +/** + * @brief qed_sp_pf_stop - PF Function Stop Ramrod + * + * This ramrod is sent to close a Physical Function (PF). It is the last ramrod + * sent and the last completion written to the PFs Event Ring. This ramrod also + * deletes the context for the Slowhwfn connection on this PF. + * + * @note Not required for first packet. + * + * @param p_hwfn + * + * @return int + */ + +int qed_sp_pf_stop(struct qed_hwfn *p_hwfn); + +#endif diff --git a/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c b/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c new file mode 100644 index 000000000000..6f7879136633 --- /dev/null +++ b/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c @@ -0,0 +1,170 @@ +/* QLogic qed NIC Driver + * Copyright (c) 2015 QLogic Corporation + * + * This software is available under the terms of the GNU General Public License + * (GPL) Version 2, available from the file COPYING in the main directory of + * this source tree. + */ + +#include +#include +#include +#include +#include +#include +#include "qed.h" +#include +#include "qed_cxt.h" +#include "qed_hsi.h" +#include "qed_hw.h" +#include "qed_int.h" +#include "qed_reg_addr.h" +#include "qed_sp.h" + +int qed_sp_init_request(struct qed_hwfn *p_hwfn, + struct qed_spq_entry **pp_ent, + u32 cid, + u16 opaque_fid, + u8 cmd, + u8 protocol, + struct qed_sp_init_request_params *p_params) +{ + int rc = -EINVAL; + struct qed_spq_entry *p_ent = NULL; + u32 opaque_cid = opaque_fid << 16 | cid; + + if (!pp_ent) + return -ENOMEM; + + rc = qed_spq_get_entry(p_hwfn, pp_ent); + + if (rc != 0) + return rc; + + p_ent = *pp_ent; + + p_ent->elem.hdr.cid = cpu_to_le32(opaque_cid); + p_ent->elem.hdr.cmd_id = cmd; + p_ent->elem.hdr.protocol_id = protocol; + + p_ent->priority = QED_SPQ_PRIORITY_NORMAL; + p_ent->comp_mode = p_params->comp_mode; + p_ent->comp_done.done = 0; + + switch (p_ent->comp_mode) { + case QED_SPQ_MODE_EBLOCK: + p_ent->comp_cb.cookie = &p_ent->comp_done; + break; + + case QED_SPQ_MODE_BLOCK: + if (!p_params->p_comp_data) + return -EINVAL; + + p_ent->comp_cb.cookie = p_params->p_comp_data->cookie; + break; + + case QED_SPQ_MODE_CB: + if (!p_params->p_comp_data) + p_ent->comp_cb.function = NULL; + else + p_ent->comp_cb = *p_params->p_comp_data; + break; + + default: + DP_NOTICE(p_hwfn, "Unknown SPQE completion mode %d\n", + p_ent->comp_mode); + return -EINVAL; + } + + DP_VERBOSE(p_hwfn, QED_MSG_SPQ, + "Initialized: CID %08x cmd %02x protocol %02x data_addr %lu comp_mode [%s]\n", + opaque_cid, cmd, protocol, + (unsigned long)&p_ent->ramrod, + D_TRINE(p_ent->comp_mode, QED_SPQ_MODE_EBLOCK, + QED_SPQ_MODE_BLOCK, "MODE_EBLOCK", "MODE_BLOCK", + "MODE_CB")); + if (p_params->ramrod_data_size) + memset(&p_ent->ramrod, 0, p_params->ramrod_data_size); + + return 0; +} + +int qed_sp_pf_start(struct qed_hwfn *p_hwfn, + enum mf_mode mode) +{ + struct qed_sp_init_request_params params; + struct pf_start_ramrod_data *p_ramrod = NULL; + u16 sb = qed_int_get_sp_sb_id(p_hwfn); + u8 sb_index = p_hwfn->p_eq->eq_sb_index; + struct qed_spq_entry *p_ent = NULL; + int rc = -EINVAL; + + /* update initial eq producer */ + qed_eq_prod_update(p_hwfn, + qed_chain_get_prod_idx(&p_hwfn->p_eq->chain)); + + memset(¶ms, 0, sizeof(params)); + params.ramrod_data_size = sizeof(*p_ramrod); + params.comp_mode = QED_SPQ_MODE_EBLOCK; + + rc = qed_sp_init_request(p_hwfn, + &p_ent, + qed_spq_get_cid(p_hwfn), + p_hwfn->hw_info.opaque_fid, + COMMON_RAMROD_PF_START, + PROTOCOLID_COMMON, + ¶ms); + if (rc) + return rc; + + p_ramrod = &p_ent->ramrod.pf_start; + + p_ramrod->event_ring_sb_id = cpu_to_le16(sb); + p_ramrod->event_ring_sb_index = sb_index; + p_ramrod->path_id = QED_PATH_ID(p_hwfn); + p_ramrod->dont_log_ramrods = 0; + p_ramrod->log_type_mask = cpu_to_le16(0xf); + p_ramrod->mf_mode = mode; + p_ramrod->outer_tag = p_hwfn->hw_info.ovlan; + + /* Place EQ address in RAMROD */ + p_ramrod->event_ring_pbl_addr.hi = + DMA_HI_LE(p_hwfn->p_eq->chain.pbl.p_phys_table); + p_ramrod->event_ring_pbl_addr.lo = + DMA_LO_LE(p_hwfn->p_eq->chain.pbl.p_phys_table); + p_ramrod->event_ring_num_pages = (u8)p_hwfn->p_eq->chain.page_cnt; + + p_ramrod->consolid_q_pbl_addr.hi = + DMA_HI_LE(p_hwfn->p_consq->chain.pbl.p_phys_table); + p_ramrod->consolid_q_pbl_addr.lo = + DMA_LO_LE(p_hwfn->p_consq->chain.pbl.p_phys_table); + + p_hwfn->hw_info.personality = PERSONALITY_ETH; + + DP_VERBOSE(p_hwfn, QED_MSG_SPQ, + "Setting event_ring_sb [id %04x index %02x], mf [%s] outer_tag [%d]\n", + sb, sb_index, + (p_ramrod->mf_mode == SF) ? "SF" : "Multi-Pf", + p_ramrod->outer_tag); + + return qed_spq_post(p_hwfn, p_ent, NULL); +} + +int qed_sp_pf_stop(struct qed_hwfn *p_hwfn) +{ + struct qed_sp_init_request_params params; + struct qed_spq_entry *p_ent = NULL; + int rc = -EINVAL; + + memset(¶ms, 0, sizeof(params)); + params.comp_mode = QED_SPQ_MODE_EBLOCK; + + rc = qed_sp_init_request(p_hwfn, &p_ent, qed_spq_get_cid(p_hwfn), + p_hwfn->hw_info.opaque_fid, + COMMON_RAMROD_PF_STOP, PROTOCOLID_COMMON, + ¶ms); + if (rc) + return rc; + + return qed_spq_post(p_hwfn, p_ent, NULL); +} diff --git a/drivers/net/ethernet/qlogic/qed/qed_spq.c b/drivers/net/ethernet/qlogic/qed/qed_spq.c new file mode 100644 index 000000000000..f28ecb197309 --- /dev/null +++ b/drivers/net/ethernet/qlogic/qed/qed_spq.c @@ -0,0 +1,831 @@ +/* QLogic qed NIC Driver + * Copyright (c) 2015 QLogic Corporation + * + * This software is available under the terms of the GNU General Public License + * (GPL) Version 2, available from the file COPYING in the main directory of + * this source tree. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "qed.h" +#include "qed_cxt.h" +#include "qed_dev_api.h" +#include "qed_hsi.h" +#include "qed_hw.h" +#include "qed_int.h" +#include "qed_mcp.h" +#include "qed_reg_addr.h" +#include "qed_sp.h" + +/*************************************************************************** +* Structures & Definitions +***************************************************************************/ + +#define SPQ_HIGH_PRI_RESERVE_DEFAULT (1) +#define SPQ_BLOCK_SLEEP_LENGTH (1000) + +/*************************************************************************** +* Blocking Imp. (BLOCK/EBLOCK mode) +***************************************************************************/ +static void qed_spq_blocking_cb(struct qed_hwfn *p_hwfn, + void *cookie, + union event_ring_data *data, + u8 fw_return_code) +{ + struct qed_spq_comp_done *comp_done; + + comp_done = (struct qed_spq_comp_done *)cookie; + + comp_done->done = 0x1; + comp_done->fw_return_code = fw_return_code; + + /* make update visible to waiting thread */ + smp_wmb(); +} + +static int qed_spq_block(struct qed_hwfn *p_hwfn, + struct qed_spq_entry *p_ent, + u8 *p_fw_ret) +{ + int sleep_count = SPQ_BLOCK_SLEEP_LENGTH; + struct qed_spq_comp_done *comp_done; + int rc; + + comp_done = (struct qed_spq_comp_done *)p_ent->comp_cb.cookie; + while (sleep_count) { + /* validate we receive completion update */ + smp_rmb(); + if (comp_done->done == 1) { + if (p_fw_ret) + *p_fw_ret = comp_done->fw_return_code; + return 0; + } + usleep_range(5000, 10000); + sleep_count--; + } + + DP_INFO(p_hwfn, "Ramrod is stuck, requesting MCP drain\n"); + rc = qed_mcp_drain(p_hwfn, p_hwfn->p_main_ptt); + if (rc != 0) + DP_NOTICE(p_hwfn, "MCP drain failed\n"); + + /* Retry after drain */ + sleep_count = SPQ_BLOCK_SLEEP_LENGTH; + while (sleep_count) { + /* validate we receive completion update */ + smp_rmb(); + if (comp_done->done == 1) { + if (p_fw_ret) + *p_fw_ret = comp_done->fw_return_code; + return 0; + } + usleep_range(5000, 10000); + sleep_count--; + } + + if (comp_done->done == 1) { + if (p_fw_ret) + *p_fw_ret = comp_done->fw_return_code; + return 0; + } + + DP_NOTICE(p_hwfn, "Ramrod is stuck, MCP drain failed\n"); + + return -EBUSY; +} + +/*************************************************************************** +* SPQ entries inner API +***************************************************************************/ +static int +qed_spq_fill_entry(struct qed_hwfn *p_hwfn, + struct qed_spq_entry *p_ent) +{ + p_ent->elem.hdr.echo = 0; + p_hwfn->p_spq->echo_idx++; + p_ent->flags = 0; + + switch (p_ent->comp_mode) { + case QED_SPQ_MODE_EBLOCK: + case QED_SPQ_MODE_BLOCK: + p_ent->comp_cb.function = qed_spq_blocking_cb; + break; + case QED_SPQ_MODE_CB: + break; + default: + DP_NOTICE(p_hwfn, "Unknown SPQE completion mode %d\n", + p_ent->comp_mode); + return -EINVAL; + } + + DP_VERBOSE(p_hwfn, QED_MSG_SPQ, + "Ramrod header: [CID 0x%08x CMD 0x%02x protocol 0x%02x] Data pointer: [%08x:%08x] Completion Mode: %s\n", + p_ent->elem.hdr.cid, + p_ent->elem.hdr.cmd_id, + p_ent->elem.hdr.protocol_id, + p_ent->elem.data_ptr.hi, + p_ent->elem.data_ptr.lo, + D_TRINE(p_ent->comp_mode, QED_SPQ_MODE_EBLOCK, + QED_SPQ_MODE_BLOCK, "MODE_EBLOCK", "MODE_BLOCK", + "MODE_CB")); + + return 0; +} + +/*************************************************************************** +* HSI access +***************************************************************************/ +static void qed_spq_hw_initialize(struct qed_hwfn *p_hwfn, + struct qed_spq *p_spq) +{ + u16 pq; + struct qed_cxt_info cxt_info; + struct core_conn_context *p_cxt; + union qed_qm_pq_params pq_params; + int rc; + + cxt_info.iid = p_spq->cid; + + rc = qed_cxt_get_cid_info(p_hwfn, &cxt_info); + + if (rc < 0) { + DP_NOTICE(p_hwfn, "Cannot find context info for cid=%d\n", + p_spq->cid); + return; + } + + p_cxt = cxt_info.p_cxt; + + SET_FIELD(p_cxt->xstorm_ag_context.flags10, + XSTORM_CORE_CONN_AG_CTX_DQ_CF_EN, 1); + SET_FIELD(p_cxt->xstorm_ag_context.flags1, + XSTORM_CORE_CONN_AG_CTX_DQ_CF_ACTIVE, 1); + SET_FIELD(p_cxt->xstorm_ag_context.flags9, + XSTORM_CORE_CONN_AG_CTX_CONSOLID_PROD_CF_EN, 1); + + /* QM physical queue */ + memset(&pq_params, 0, sizeof(pq_params)); + pq_params.core.tc = LB_TC; + pq = qed_get_qm_pq(p_hwfn, PROTOCOLID_CORE, &pq_params); + p_cxt->xstorm_ag_context.physical_q0 = cpu_to_le16(pq); + + p_cxt->xstorm_st_context.spq_base_lo = + DMA_LO_LE(p_spq->chain.p_phys_addr); + p_cxt->xstorm_st_context.spq_base_hi = + DMA_HI_LE(p_spq->chain.p_phys_addr); + + p_cxt->xstorm_st_context.consolid_base_addr.lo = + DMA_LO_LE(p_hwfn->p_consq->chain.p_phys_addr); + p_cxt->xstorm_st_context.consolid_base_addr.hi = + DMA_HI_LE(p_hwfn->p_consq->chain.p_phys_addr); +} + +static int qed_spq_hw_post(struct qed_hwfn *p_hwfn, + struct qed_spq *p_spq, + struct qed_spq_entry *p_ent) +{ + struct qed_chain *p_chain = &p_hwfn->p_spq->chain; + struct slow_path_element *elem; + struct core_db_data db; + + elem = qed_chain_produce(p_chain); + if (!elem) { + DP_NOTICE(p_hwfn, "Failed to produce from SPQ chain\n"); + return -EINVAL; + } + + *elem = p_ent->elem; /* struct assignment */ + + /* send a doorbell on the slow hwfn session */ + memset(&db, 0, sizeof(db)); + SET_FIELD(db.params, CORE_DB_DATA_DEST, DB_DEST_XCM); + SET_FIELD(db.params, CORE_DB_DATA_AGG_CMD, DB_AGG_CMD_SET); + SET_FIELD(db.params, CORE_DB_DATA_AGG_VAL_SEL, + DQ_XCM_CORE_SPQ_PROD_CMD); + db.agg_flags = DQ_XCM_CORE_DQ_CF_CMD; + + /* validate producer is up to-date */ + rmb(); + + db.spq_prod = cpu_to_le16(qed_chain_get_prod_idx(p_chain)); + + /* do not reorder */ + barrier(); + + DOORBELL(p_hwfn, qed_db_addr(p_spq->cid, DQ_DEMS_LEGACY), *(u32 *)&db); + + /* make sure doorbell is rang */ + mmiowb(); + + DP_VERBOSE(p_hwfn, QED_MSG_SPQ, + "Doorbelled [0x%08x, CID 0x%08x] with Flags: %02x agg_params: %02x, prod: %04x\n", + qed_db_addr(p_spq->cid, DQ_DEMS_LEGACY), + p_spq->cid, db.params, db.agg_flags, + qed_chain_get_prod_idx(p_chain)); + + return 0; +} + +/*************************************************************************** +* Asynchronous events +***************************************************************************/ +static int +qed_async_event_completion(struct qed_hwfn *p_hwfn, + struct event_ring_entry *p_eqe) +{ + DP_NOTICE(p_hwfn, + "Unknown Async completion for protocol: %d\n", + p_eqe->protocol_id); + return -EINVAL; +} + +/*************************************************************************** +* EQ API +***************************************************************************/ +void qed_eq_prod_update(struct qed_hwfn *p_hwfn, + u16 prod) +{ + u32 addr = GTT_BAR0_MAP_REG_USDM_RAM + + USTORM_EQE_CONS_OFFSET(p_hwfn->rel_pf_id); + + REG_WR16(p_hwfn, addr, prod); + + /* keep prod updates ordered */ + mmiowb(); +} + +int qed_eq_completion(struct qed_hwfn *p_hwfn, + void *cookie) + +{ + struct qed_eq *p_eq = cookie; + struct qed_chain *p_chain = &p_eq->chain; + int rc = 0; + + /* take a snapshot of the FW consumer */ + u16 fw_cons_idx = le16_to_cpu(*p_eq->p_fw_cons); + + DP_VERBOSE(p_hwfn, QED_MSG_SPQ, "fw_cons_idx %x\n", fw_cons_idx); + + /* Need to guarantee the fw_cons index we use points to a usuable + * element (to comply with our chain), so our macros would comply + */ + if ((fw_cons_idx & qed_chain_get_usable_per_page(p_chain)) == + qed_chain_get_usable_per_page(p_chain)) + fw_cons_idx += qed_chain_get_unusable_per_page(p_chain); + + /* Complete current segment of eq entries */ + while (fw_cons_idx != qed_chain_get_cons_idx(p_chain)) { + struct event_ring_entry *p_eqe = qed_chain_consume(p_chain); + + if (!p_eqe) { + rc = -EINVAL; + break; + } + + DP_VERBOSE(p_hwfn, QED_MSG_SPQ, + "op %x prot %x res0 %x echo %x fwret %x flags %x\n", + p_eqe->opcode, + p_eqe->protocol_id, + p_eqe->reserved0, + le16_to_cpu(p_eqe->echo), + p_eqe->fw_return_code, + p_eqe->flags); + + if (GET_FIELD(p_eqe->flags, EVENT_RING_ENTRY_ASYNC)) { + if (qed_async_event_completion(p_hwfn, p_eqe)) + rc = -EINVAL; + } else if (qed_spq_completion(p_hwfn, + p_eqe->echo, + p_eqe->fw_return_code, + &p_eqe->data)) { + rc = -EINVAL; + } + + qed_chain_recycle_consumed(p_chain); + } + + qed_eq_prod_update(p_hwfn, qed_chain_get_prod_idx(p_chain)); + + return rc; +} + +struct qed_eq *qed_eq_alloc(struct qed_hwfn *p_hwfn, + u16 num_elem) +{ + struct qed_eq *p_eq; + + /* Allocate EQ struct */ + p_eq = kzalloc(sizeof(*p_eq), GFP_ATOMIC); + if (!p_eq) { + DP_NOTICE(p_hwfn, "Failed to allocate `struct qed_eq'\n"); + return NULL; + } + + /* Allocate and initialize EQ chain*/ + if (qed_chain_alloc(p_hwfn->cdev, + QED_CHAIN_USE_TO_PRODUCE, + QED_CHAIN_MODE_PBL, + num_elem, + sizeof(union event_ring_element), + &p_eq->chain)) { + DP_NOTICE(p_hwfn, "Failed to allocate eq chain\n"); + goto eq_allocate_fail; + } + + /* register EQ completion on the SP SB */ + qed_int_register_cb(p_hwfn, + qed_eq_completion, + p_eq, + &p_eq->eq_sb_index, + &p_eq->p_fw_cons); + + return p_eq; + +eq_allocate_fail: + qed_eq_free(p_hwfn, p_eq); + return NULL; +} + +void qed_eq_setup(struct qed_hwfn *p_hwfn, + struct qed_eq *p_eq) +{ + qed_chain_reset(&p_eq->chain); +} + +void qed_eq_free(struct qed_hwfn *p_hwfn, + struct qed_eq *p_eq) +{ + if (!p_eq) + return; + qed_chain_free(p_hwfn->cdev, &p_eq->chain); + kfree(p_eq); +} + +/*************************************************************************** +* Slow hwfn Queue (spq) +***************************************************************************/ +void qed_spq_setup(struct qed_hwfn *p_hwfn) +{ + struct qed_spq *p_spq = p_hwfn->p_spq; + struct qed_spq_entry *p_virt = NULL; + dma_addr_t p_phys = 0; + unsigned int i = 0; + + INIT_LIST_HEAD(&p_spq->pending); + INIT_LIST_HEAD(&p_spq->completion_pending); + INIT_LIST_HEAD(&p_spq->free_pool); + INIT_LIST_HEAD(&p_spq->unlimited_pending); + spin_lock_init(&p_spq->lock); + + /* SPQ empty pool */ + p_phys = p_spq->p_phys + offsetof(struct qed_spq_entry, ramrod); + p_virt = p_spq->p_virt; + + for (i = 0; i < p_spq->chain.capacity; i++) { + p_virt->elem.data_ptr.hi = DMA_HI_LE(p_phys); + p_virt->elem.data_ptr.lo = DMA_LO_LE(p_phys); + + list_add_tail(&p_virt->list, &p_spq->free_pool); + + p_virt++; + p_phys += sizeof(struct qed_spq_entry); + } + + /* Statistics */ + p_spq->normal_count = 0; + p_spq->comp_count = 0; + p_spq->comp_sent_count = 0; + p_spq->unlimited_pending_count = 0; + p_spq->echo_idx = 0; + + /* SPQ cid, cannot fail */ + qed_cxt_acquire_cid(p_hwfn, PROTOCOLID_CORE, &p_spq->cid); + qed_spq_hw_initialize(p_hwfn, p_spq); + + /* reset the chain itself */ + qed_chain_reset(&p_spq->chain); +} + +int qed_spq_alloc(struct qed_hwfn *p_hwfn) +{ + struct qed_spq *p_spq = NULL; + dma_addr_t p_phys = 0; + struct qed_spq_entry *p_virt = NULL; + + /* SPQ struct */ + p_spq = + kzalloc(sizeof(struct qed_spq), GFP_ATOMIC); + if (!p_spq) { + DP_NOTICE(p_hwfn, "Failed to allocate `struct qed_spq'\n"); + return -ENOMEM; + } + + /* SPQ ring */ + if (qed_chain_alloc(p_hwfn->cdev, + QED_CHAIN_USE_TO_PRODUCE, + QED_CHAIN_MODE_SINGLE, + 0, /* N/A when the mode is SINGLE */ + sizeof(struct slow_path_element), + &p_spq->chain)) { + DP_NOTICE(p_hwfn, "Failed to allocate spq chain\n"); + goto spq_allocate_fail; + } + + /* allocate and fill the SPQ elements (incl. ramrod data list) */ + p_virt = dma_alloc_coherent(&p_hwfn->cdev->pdev->dev, + p_spq->chain.capacity * + sizeof(struct qed_spq_entry), + &p_phys, + GFP_KERNEL); + + if (!p_virt) + goto spq_allocate_fail; + + p_spq->p_virt = p_virt; + p_spq->p_phys = p_phys; + p_hwfn->p_spq = p_spq; + + return 0; + +spq_allocate_fail: + qed_chain_free(p_hwfn->cdev, &p_spq->chain); + kfree(p_spq); + return -ENOMEM; +} + +void qed_spq_free(struct qed_hwfn *p_hwfn) +{ + struct qed_spq *p_spq = p_hwfn->p_spq; + + if (!p_spq) + return; + + if (p_spq->p_virt) + dma_free_coherent(&p_hwfn->cdev->pdev->dev, + p_spq->chain.capacity * + sizeof(struct qed_spq_entry), + p_spq->p_virt, + p_spq->p_phys); + + qed_chain_free(p_hwfn->cdev, &p_spq->chain); + ; + kfree(p_spq); +} + +int +qed_spq_get_entry(struct qed_hwfn *p_hwfn, + struct qed_spq_entry **pp_ent) +{ + struct qed_spq *p_spq = p_hwfn->p_spq; + struct qed_spq_entry *p_ent = NULL; + int rc = 0; + + spin_lock_bh(&p_spq->lock); + + if (list_empty(&p_spq->free_pool)) { + p_ent = kzalloc(sizeof(*p_ent), GFP_ATOMIC); + if (!p_ent) { + rc = -ENOMEM; + goto out_unlock; + } + p_ent->queue = &p_spq->unlimited_pending; + } else { + p_ent = list_first_entry(&p_spq->free_pool, + struct qed_spq_entry, + list); + list_del(&p_ent->list); + p_ent->queue = &p_spq->pending; + } + + *pp_ent = p_ent; + +out_unlock: + spin_unlock_bh(&p_spq->lock); + return rc; +} + +/* Locked variant; Should be called while the SPQ lock is taken */ +static void __qed_spq_return_entry(struct qed_hwfn *p_hwfn, + struct qed_spq_entry *p_ent) +{ + list_add_tail(&p_ent->list, &p_hwfn->p_spq->free_pool); +} + +void qed_spq_return_entry(struct qed_hwfn *p_hwfn, + struct qed_spq_entry *p_ent) +{ + spin_lock_bh(&p_hwfn->p_spq->lock); + __qed_spq_return_entry(p_hwfn, p_ent); + spin_unlock_bh(&p_hwfn->p_spq->lock); +} + +/** + * @brief qed_spq_add_entry - adds a new entry to the pending + * list. Should be used while lock is being held. + * + * Addes an entry to the pending list is there is room (en empty + * element is available in the free_pool), or else places the + * entry in the unlimited_pending pool. + * + * @param p_hwfn + * @param p_ent + * @param priority + * + * @return int + */ +static int +qed_spq_add_entry(struct qed_hwfn *p_hwfn, + struct qed_spq_entry *p_ent, + enum spq_priority priority) +{ + struct qed_spq *p_spq = p_hwfn->p_spq; + + if (p_ent->queue == &p_spq->unlimited_pending) { + struct qed_spq_entry *p_en2; + + if (list_empty(&p_spq->free_pool)) { + list_add_tail(&p_ent->list, &p_spq->unlimited_pending); + p_spq->unlimited_pending_count++; + + return 0; + } + + p_en2 = list_first_entry(&p_spq->free_pool, + struct qed_spq_entry, + list); + list_del(&p_en2->list); + + /* Strcut assignment */ + *p_en2 = *p_ent; + + kfree(p_ent); + + p_ent = p_en2; + } + + /* entry is to be placed in 'pending' queue */ + switch (priority) { + case QED_SPQ_PRIORITY_NORMAL: + list_add_tail(&p_ent->list, &p_spq->pending); + p_spq->normal_count++; + break; + case QED_SPQ_PRIORITY_HIGH: + list_add(&p_ent->list, &p_spq->pending); + p_spq->high_count++; + break; + default: + return -EINVAL; + } + + return 0; +} + +/*************************************************************************** +* Accessor +***************************************************************************/ +u32 qed_spq_get_cid(struct qed_hwfn *p_hwfn) +{ + if (!p_hwfn->p_spq) + return 0xffffffff; /* illegal */ + return p_hwfn->p_spq->cid; +} + +/*************************************************************************** +* Posting new Ramrods +***************************************************************************/ +static int qed_spq_post_list(struct qed_hwfn *p_hwfn, + struct list_head *head, + u32 keep_reserve) +{ + struct qed_spq *p_spq = p_hwfn->p_spq; + int rc; + + while (qed_chain_get_elem_left(&p_spq->chain) > keep_reserve && + !list_empty(head)) { + struct qed_spq_entry *p_ent = + list_first_entry(head, struct qed_spq_entry, list); + list_del(&p_ent->list); + list_add_tail(&p_ent->list, &p_spq->completion_pending); + p_spq->comp_sent_count++; + + rc = qed_spq_hw_post(p_hwfn, p_spq, p_ent); + if (rc) { + list_del(&p_ent->list); + __qed_spq_return_entry(p_hwfn, p_ent); + return rc; + } + } + + return 0; +} + +static int qed_spq_pend_post(struct qed_hwfn *p_hwfn) +{ + struct qed_spq *p_spq = p_hwfn->p_spq; + struct qed_spq_entry *p_ent = NULL; + + while (!list_empty(&p_spq->free_pool)) { + if (list_empty(&p_spq->unlimited_pending)) + break; + + p_ent = list_first_entry(&p_spq->unlimited_pending, + struct qed_spq_entry, + list); + if (!p_ent) + return -EINVAL; + + list_del(&p_ent->list); + + qed_spq_add_entry(p_hwfn, p_ent, p_ent->priority); + } + + return qed_spq_post_list(p_hwfn, &p_spq->pending, + SPQ_HIGH_PRI_RESERVE_DEFAULT); +} + +int qed_spq_post(struct qed_hwfn *p_hwfn, + struct qed_spq_entry *p_ent, + u8 *fw_return_code) +{ + int rc = 0; + struct qed_spq *p_spq = p_hwfn ? p_hwfn->p_spq : NULL; + bool b_ret_ent = true; + + if (!p_hwfn) + return -EINVAL; + + if (!p_ent) { + DP_NOTICE(p_hwfn, "Got a NULL pointer\n"); + return -EINVAL; + } + + /* Complete the entry */ + rc = qed_spq_fill_entry(p_hwfn, p_ent); + + spin_lock_bh(&p_spq->lock); + + /* Check return value after LOCK is taken for cleaner error flow */ + if (rc) + goto spq_post_fail; + + /* Add the request to the pending queue */ + rc = qed_spq_add_entry(p_hwfn, p_ent, p_ent->priority); + if (rc) + goto spq_post_fail; + + rc = qed_spq_pend_post(p_hwfn); + if (rc) { + /* Since it's possible that pending failed for a different + * entry [although unlikely], the failed entry was already + * dealt with; No need to return it here. + */ + b_ret_ent = false; + goto spq_post_fail; + } + + spin_unlock_bh(&p_spq->lock); + + if (p_ent->comp_mode == QED_SPQ_MODE_EBLOCK) { + /* For entries in QED BLOCK mode, the completion code cannot + * perform the necessary cleanup - if it did, we couldn't + * access p_ent here to see whether it's successful or not. + * Thus, after gaining the answer perform the cleanup here. + */ + rc = qed_spq_block(p_hwfn, p_ent, fw_return_code); + if (rc) + goto spq_post_fail2; + + /* return to pool */ + qed_spq_return_entry(p_hwfn, p_ent); + } + return rc; + +spq_post_fail2: + spin_lock_bh(&p_spq->lock); + list_del(&p_ent->list); + qed_chain_return_produced(&p_spq->chain); + +spq_post_fail: + /* return to the free pool */ + if (b_ret_ent) + __qed_spq_return_entry(p_hwfn, p_ent); + spin_unlock_bh(&p_spq->lock); + + return rc; +} + +int qed_spq_completion(struct qed_hwfn *p_hwfn, + __le16 echo, + u8 fw_return_code, + union event_ring_data *p_data) +{ + struct qed_spq *p_spq; + struct qed_spq_entry *p_ent = NULL; + struct qed_spq_entry *tmp; + struct qed_spq_entry *found = NULL; + int rc; + + if (!p_hwfn) + return -EINVAL; + + p_spq = p_hwfn->p_spq; + if (!p_spq) + return -EINVAL; + + spin_lock_bh(&p_spq->lock); + list_for_each_entry_safe(p_ent, tmp, &p_spq->completion_pending, + list) { + if (p_ent->elem.hdr.echo == echo) { + list_del(&p_ent->list); + + qed_chain_return_produced(&p_spq->chain); + p_spq->comp_count++; + found = p_ent; + break; + } + } + + /* Release lock before callback, as callback may post + * an additional ramrod. + */ + spin_unlock_bh(&p_spq->lock); + + if (!found) { + DP_NOTICE(p_hwfn, + "Failed to find an entry this EQE completes\n"); + return -EEXIST; + } + + DP_VERBOSE(p_hwfn, QED_MSG_SPQ, "Complete: func %p cookie %p)\n", + p_ent->comp_cb.function, p_ent->comp_cb.cookie); + if (found->comp_cb.function) + found->comp_cb.function(p_hwfn, found->comp_cb.cookie, p_data, + fw_return_code); + + if (found->comp_mode != QED_SPQ_MODE_EBLOCK) + /* EBLOCK is responsible for freeing its own entry */ + qed_spq_return_entry(p_hwfn, found); + + /* Attempt to post pending requests */ + spin_lock_bh(&p_spq->lock); + rc = qed_spq_pend_post(p_hwfn); + spin_unlock_bh(&p_spq->lock); + + return rc; +} + +struct qed_consq *qed_consq_alloc(struct qed_hwfn *p_hwfn) +{ + struct qed_consq *p_consq; + + /* Allocate ConsQ struct */ + p_consq = kzalloc(sizeof(*p_consq), GFP_ATOMIC); + if (!p_consq) { + DP_NOTICE(p_hwfn, "Failed to allocate `struct qed_consq'\n"); + return NULL; + } + + /* Allocate and initialize EQ chain*/ + if (qed_chain_alloc(p_hwfn->cdev, + QED_CHAIN_USE_TO_PRODUCE, + QED_CHAIN_MODE_PBL, + QED_CHAIN_PAGE_SIZE / 0x80, + 0x80, + &p_consq->chain)) { + DP_NOTICE(p_hwfn, "Failed to allocate consq chain"); + goto consq_allocate_fail; + } + + return p_consq; + +consq_allocate_fail: + qed_consq_free(p_hwfn, p_consq); + return NULL; +} + +void qed_consq_setup(struct qed_hwfn *p_hwfn, + struct qed_consq *p_consq) +{ + qed_chain_reset(&p_consq->chain); +} + +void qed_consq_free(struct qed_hwfn *p_hwfn, + struct qed_consq *p_consq) +{ + if (!p_consq) + return; + qed_chain_free(p_hwfn->cdev, &p_consq->chain); + kfree(p_consq); +} diff --git a/include/linux/qed/common_hsi.h b/include/linux/qed/common_hsi.h new file mode 100644 index 000000000000..6a4347639c03 --- /dev/null +++ b/include/linux/qed/common_hsi.h @@ -0,0 +1,607 @@ +/* QLogic qed NIC Driver + * Copyright (c) 2015 QLogic Corporation + * + * This software is available under the terms of the GNU General Public License + * (GPL) Version 2, available from the file COPYING in the main directory of + * this source tree. + */ + +#ifndef __COMMON_HSI__ +#define __COMMON_HSI__ + +#define FW_MAJOR_VERSION 8 +#define FW_MINOR_VERSION 4 +#define FW_REVISION_VERSION 2 +#define FW_ENGINEERING_VERSION 0 + +/***********************/ +/* COMMON HW CONSTANTS */ +/***********************/ + +/* PCI functions */ +#define MAX_NUM_PORTS_K2 (4) +#define MAX_NUM_PORTS_BB (2) +#define MAX_NUM_PORTS (MAX_NUM_PORTS_K2) + +#define MAX_NUM_PFS_K2 (16) +#define MAX_NUM_PFS_BB (8) +#define MAX_NUM_PFS (MAX_NUM_PFS_K2) +#define MAX_NUM_OF_PFS_IN_CHIP (16) /* On both engines */ + +#define MAX_NUM_VFS_K2 (192) +#define MAX_NUM_VFS_BB (120) +#define MAX_NUM_VFS (MAX_NUM_VFS_K2) + +#define MAX_NUM_FUNCTIONS_BB (MAX_NUM_PFS_BB + MAX_NUM_VFS_BB) +#define MAX_NUM_FUNCTIONS (MAX_NUM_PFS + MAX_NUM_VFS) + +#define MAX_FUNCTION_NUMBER_BB (MAX_NUM_PFS + MAX_NUM_VFS_BB) +#define MAX_FUNCTION_NUMBER (MAX_NUM_PFS + MAX_NUM_VFS) + +#define MAX_NUM_VPORTS_K2 (208) +#define MAX_NUM_VPORTS_BB (160) +#define MAX_NUM_VPORTS (MAX_NUM_VPORTS_K2) + +#define MAX_NUM_L2_QUEUES_K2 (320) +#define MAX_NUM_L2_QUEUES_BB (256) +#define MAX_NUM_L2_QUEUES (MAX_NUM_L2_QUEUES_K2) + +/* Traffic classes in network-facing blocks (PBF, BTB, NIG, BRB, PRS and QM) */ +#define NUM_PHYS_TCS_4PORT_K2 (4) +#define NUM_OF_PHYS_TCS (8) + +#define NUM_TCS_4PORT_K2 (NUM_PHYS_TCS_4PORT_K2 + 1) +#define NUM_OF_TCS (NUM_OF_PHYS_TCS + 1) + +#define LB_TC (NUM_OF_PHYS_TCS) + +/* Num of possible traffic priority values */ +#define NUM_OF_PRIO (8) + +#define MAX_NUM_VOQS_K2 (NUM_TCS_4PORT_K2 * MAX_NUM_PORTS_K2) +#define MAX_NUM_VOQS_BB (NUM_OF_TCS * MAX_NUM_PORTS_BB) +#define MAX_NUM_VOQS (MAX_NUM_VOQS_K2) +#define MAX_PHYS_VOQS (NUM_OF_PHYS_TCS * MAX_NUM_PORTS_BB) + +/* CIDs */ +#define NUM_OF_CONNECTION_TYPES (8) +#define NUM_OF_LCIDS (320) +#define NUM_OF_LTIDS (320) + +/*****************/ +/* CDU CONSTANTS */ +/*****************/ + +#define CDU_SEG_TYPE_OFFSET_REG_TYPE_SHIFT (17) +#define CDU_SEG_TYPE_OFFSET_REG_OFFSET_MASK (0x1ffff) + +/*****************/ +/* DQ CONSTANTS */ +/*****************/ + +/* DEMS */ +#define DQ_DEMS_LEGACY 0 + +/* XCM agg val selection */ +#define DQ_XCM_AGG_VAL_SEL_WORD2 0 +#define DQ_XCM_AGG_VAL_SEL_WORD3 1 +#define DQ_XCM_AGG_VAL_SEL_WORD4 2 +#define DQ_XCM_AGG_VAL_SEL_WORD5 3 +#define DQ_XCM_AGG_VAL_SEL_REG3 4 +#define DQ_XCM_AGG_VAL_SEL_REG4 5 +#define DQ_XCM_AGG_VAL_SEL_REG5 6 +#define DQ_XCM_AGG_VAL_SEL_REG6 7 + +/* XCM agg val selection */ +#define DQ_XCM_ETH_EDPM_NUM_BDS_CMD \ + DQ_XCM_AGG_VAL_SEL_WORD2 +#define DQ_XCM_ETH_TX_BD_CONS_CMD \ + DQ_XCM_AGG_VAL_SEL_WORD3 +#define DQ_XCM_CORE_TX_BD_CONS_CMD \ + DQ_XCM_AGG_VAL_SEL_WORD3 +#define DQ_XCM_ETH_TX_BD_PROD_CMD \ + DQ_XCM_AGG_VAL_SEL_WORD4 +#define DQ_XCM_CORE_TX_BD_PROD_CMD \ + DQ_XCM_AGG_VAL_SEL_WORD4 +#define DQ_XCM_CORE_SPQ_PROD_CMD \ + DQ_XCM_AGG_VAL_SEL_WORD4 +#define DQ_XCM_ETH_GO_TO_BD_CONS_CMD DQ_XCM_AGG_VAL_SEL_WORD5 + +/* XCM agg counter flag selection */ +#define DQ_XCM_AGG_FLG_SHIFT_BIT14 0 +#define DQ_XCM_AGG_FLG_SHIFT_BIT15 1 +#define DQ_XCM_AGG_FLG_SHIFT_CF12 2 +#define DQ_XCM_AGG_FLG_SHIFT_CF13 3 +#define DQ_XCM_AGG_FLG_SHIFT_CF18 4 +#define DQ_XCM_AGG_FLG_SHIFT_CF19 5 +#define DQ_XCM_AGG_FLG_SHIFT_CF22 6 +#define DQ_XCM_AGG_FLG_SHIFT_CF23 7 + +/* XCM agg counter flag selection */ +#define DQ_XCM_ETH_DQ_CF_CMD (1 << \ + DQ_XCM_AGG_FLG_SHIFT_CF18) +#define DQ_XCM_CORE_DQ_CF_CMD (1 << \ + DQ_XCM_AGG_FLG_SHIFT_CF18) +#define DQ_XCM_ETH_TERMINATE_CMD (1 << \ + DQ_XCM_AGG_FLG_SHIFT_CF19) +#define DQ_XCM_CORE_TERMINATE_CMD (1 << \ + DQ_XCM_AGG_FLG_SHIFT_CF19) +#define DQ_XCM_ETH_SLOW_PATH_CMD (1 << \ + DQ_XCM_AGG_FLG_SHIFT_CF22) +#define DQ_XCM_CORE_SLOW_PATH_CMD (1 << \ + DQ_XCM_AGG_FLG_SHIFT_CF22) +#define DQ_XCM_ETH_TPH_EN_CMD (1 << \ + DQ_XCM_AGG_FLG_SHIFT_CF23) + +/*****************/ +/* QM CONSTANTS */ +/*****************/ + +/* number of TX queues in the QM */ +#define MAX_QM_TX_QUEUES_K2 512 +#define MAX_QM_TX_QUEUES_BB 448 +#define MAX_QM_TX_QUEUES MAX_QM_TX_QUEUES_K2 + +/* number of Other queues in the QM */ +#define MAX_QM_OTHER_QUEUES_BB 64 +#define MAX_QM_OTHER_QUEUES_K2 128 +#define MAX_QM_OTHER_QUEUES MAX_QM_OTHER_QUEUES_K2 + +/* number of queues in a PF queue group */ +#define QM_PF_QUEUE_GROUP_SIZE 8 + +/* base number of Tx PQs in the CM PQ representation. + * should be used when storing PQ IDs in CM PQ registers and context + */ +#define CM_TX_PQ_BASE 0x200 + +/* QM registers data */ +#define QM_LINE_CRD_REG_WIDTH 16 +#define QM_LINE_CRD_REG_SIGN_BIT (1 << (QM_LINE_CRD_REG_WIDTH - 1)) +#define QM_BYTE_CRD_REG_WIDTH 24 +#define QM_BYTE_CRD_REG_SIGN_BIT (1 << (QM_BYTE_CRD_REG_WIDTH - 1)) +#define QM_WFQ_CRD_REG_WIDTH 32 +#define QM_WFQ_CRD_REG_SIGN_BIT (1 << (QM_WFQ_CRD_REG_WIDTH - 1)) +#define QM_RL_CRD_REG_WIDTH 32 +#define QM_RL_CRD_REG_SIGN_BIT (1 << (QM_RL_CRD_REG_WIDTH - 1)) + +/*****************/ +/* CAU CONSTANTS */ +/*****************/ + +#define CAU_FSM_ETH_RX 0 +#define CAU_FSM_ETH_TX 1 + +/* Number of Protocol Indices per Status Block */ +#define PIS_PER_SB 12 + +#define CAU_HC_STOPPED_STATE 3 +#define CAU_HC_DISABLE_STATE 4 +#define CAU_HC_ENABLE_STATE 0 + +/*****************/ +/* IGU CONSTANTS */ +/*****************/ + +#define MAX_SB_PER_PATH_K2 (368) +#define MAX_SB_PER_PATH_BB (288) +#define MAX_TOT_SB_PER_PATH \ + MAX_SB_PER_PATH_K2 + +#define MAX_SB_PER_PF_MIMD 129 +#define MAX_SB_PER_PF_SIMD 64 +#define MAX_SB_PER_VF 64 + +/* Memory addresses on the BAR for the IGU Sub Block */ +#define IGU_MEM_BASE 0x0000 + +#define IGU_MEM_MSIX_BASE 0x0000 +#define IGU_MEM_MSIX_UPPER 0x0101 +#define IGU_MEM_MSIX_RESERVED_UPPER 0x01ff + +#define IGU_MEM_PBA_MSIX_BASE 0x0200 +#define IGU_MEM_PBA_MSIX_UPPER 0x0202 +#define IGU_MEM_PBA_MSIX_RESERVED_UPPER 0x03ff + +#define IGU_CMD_INT_ACK_BASE 0x0400 +#define IGU_CMD_INT_ACK_UPPER (IGU_CMD_INT_ACK_BASE + \ + MAX_TOT_SB_PER_PATH - \ + 1) +#define IGU_CMD_INT_ACK_RESERVED_UPPER 0x05ff + +#define IGU_CMD_ATTN_BIT_UPD_UPPER 0x05f0 +#define IGU_CMD_ATTN_BIT_SET_UPPER 0x05f1 +#define IGU_CMD_ATTN_BIT_CLR_UPPER 0x05f2 + +#define IGU_REG_SISR_MDPC_WMASK_UPPER 0x05f3 +#define IGU_REG_SISR_MDPC_WMASK_LSB_UPPER 0x05f4 +#define IGU_REG_SISR_MDPC_WMASK_MSB_UPPER 0x05f5 +#define IGU_REG_SISR_MDPC_WOMASK_UPPER 0x05f6 + +#define IGU_CMD_PROD_UPD_BASE 0x0600 +#define IGU_CMD_PROD_UPD_UPPER (IGU_CMD_PROD_UPD_BASE +\ + MAX_TOT_SB_PER_PATH - \ + 1) +#define IGU_CMD_PROD_UPD_RESERVED_UPPER 0x07ff + +/*****************/ +/* PXP CONSTANTS */ +/*****************/ + +/* PTT and GTT */ +#define PXP_NUM_PF_WINDOWS 12 +#define PXP_PER_PF_ENTRY_SIZE 8 +#define PXP_NUM_GLOBAL_WINDOWS 243 +#define PXP_GLOBAL_ENTRY_SIZE 4 +#define PXP_ADMIN_WINDOW_ALLOWED_LENGTH 4 +#define PXP_PF_WINDOW_ADMIN_START 0 +#define PXP_PF_WINDOW_ADMIN_LENGTH 0x1000 +#define PXP_PF_WINDOW_ADMIN_END (PXP_PF_WINDOW_ADMIN_START + \ + PXP_PF_WINDOW_ADMIN_LENGTH - 1) +#define PXP_PF_WINDOW_ADMIN_PER_PF_START 0 +#define PXP_PF_WINDOW_ADMIN_PER_PF_LENGTH (PXP_NUM_PF_WINDOWS * \ + PXP_PER_PF_ENTRY_SIZE) +#define PXP_PF_WINDOW_ADMIN_PER_PF_END (PXP_PF_WINDOW_ADMIN_PER_PF_START + \ + PXP_PF_WINDOW_ADMIN_PER_PF_LENGTH - 1) +#define PXP_PF_WINDOW_ADMIN_GLOBAL_START 0x200 +#define PXP_PF_WINDOW_ADMIN_GLOBAL_LENGTH (PXP_NUM_GLOBAL_WINDOWS * \ + PXP_GLOBAL_ENTRY_SIZE) +#define PXP_PF_WINDOW_ADMIN_GLOBAL_END \ + (PXP_PF_WINDOW_ADMIN_GLOBAL_START + \ + PXP_PF_WINDOW_ADMIN_GLOBAL_LENGTH - 1) +#define PXP_PF_GLOBAL_PRETEND_ADDR 0x1f0 +#define PXP_PF_ME_OPAQUE_MASK_ADDR 0xf4 +#define PXP_PF_ME_OPAQUE_ADDR 0x1f8 +#define PXP_PF_ME_CONCRETE_ADDR 0x1fc + +#define PXP_EXTERNAL_BAR_PF_WINDOW_START 0x1000 +#define PXP_EXTERNAL_BAR_PF_WINDOW_NUM PXP_NUM_PF_WINDOWS +#define PXP_EXTERNAL_BAR_PF_WINDOW_SINGLE_SIZE 0x1000 +#define PXP_EXTERNAL_BAR_PF_WINDOW_LENGTH \ + (PXP_EXTERNAL_BAR_PF_WINDOW_NUM * \ + PXP_EXTERNAL_BAR_PF_WINDOW_SINGLE_SIZE) +#define PXP_EXTERNAL_BAR_PF_WINDOW_END \ + (PXP_EXTERNAL_BAR_PF_WINDOW_START + \ + PXP_EXTERNAL_BAR_PF_WINDOW_LENGTH - 1) + +#define PXP_EXTERNAL_BAR_GLOBAL_WINDOW_START \ + (PXP_EXTERNAL_BAR_PF_WINDOW_END + 1) +#define PXP_EXTERNAL_BAR_GLOBAL_WINDOW_NUM PXP_NUM_GLOBAL_WINDOWS +#define PXP_EXTERNAL_BAR_GLOBAL_WINDOW_SINGLE_SIZE 0x1000 +#define PXP_EXTERNAL_BAR_GLOBAL_WINDOW_LENGTH \ + (PXP_EXTERNAL_BAR_GLOBAL_WINDOW_NUM * \ + PXP_EXTERNAL_BAR_GLOBAL_WINDOW_SINGLE_SIZE) +#define PXP_EXTERNAL_BAR_GLOBAL_WINDOW_END \ + (PXP_EXTERNAL_BAR_GLOBAL_WINDOW_START + \ + PXP_EXTERNAL_BAR_GLOBAL_WINDOW_LENGTH - 1) + +#define PXP_ILT_PAGE_SIZE_NUM_BITS_MIN 12 +#define PXP_ILT_BLOCK_FACTOR_MULTIPLIER 1024 + +/* ILT Records */ +#define PXP_NUM_ILT_RECORDS_BB 7600 +#define PXP_NUM_ILT_RECORDS_K2 11000 +#define MAX_NUM_ILT_RECORDS MAX(PXP_NUM_ILT_RECORDS_BB, PXP_NUM_ILT_RECORDS_K2) + +/******************/ +/* PBF CONSTANTS */ +/******************/ + +/* Number of PBF command queue lines. Each line is 32B. */ +#define PBF_MAX_CMD_LINES 3328 + +/* Number of BTB blocks. Each block is 256B. */ +#define BTB_MAX_BLOCKS 1440 + +/*****************/ +/* PRS CONSTANTS */ +/*****************/ + +/* Async data KCQ CQE */ +struct async_data { + __le32 cid; + __le16 itid; + u8 error_code; + u8 fw_debug_param; +}; + +struct regpair { + __le32 lo; + __le32 hi; +}; + +/* Event Data Union */ +union event_ring_data { + u8 bytes[8]; + struct async_data async_info; +}; + +/* Event Ring Entry */ +struct event_ring_entry { + u8 protocol_id; + u8 opcode; + __le16 reserved0; + __le16 echo; + u8 fw_return_code; + u8 flags; +#define EVENT_RING_ENTRY_ASYNC_MASK 0x1 +#define EVENT_RING_ENTRY_ASYNC_SHIFT 0 +#define EVENT_RING_ENTRY_RESERVED1_MASK 0x7F +#define EVENT_RING_ENTRY_RESERVED1_SHIFT 1 + union event_ring_data data; +}; + +/* Multi function mode */ +enum mf_mode { + SF, + MF_OVLAN, + MF_NPAR, + MAX_MF_MODE +}; + +/* Per-protocol connection types */ +enum protocol_type { + PROTOCOLID_RESERVED1, + PROTOCOLID_RESERVED2, + PROTOCOLID_RESERVED3, + PROTOCOLID_CORE, + PROTOCOLID_ETH, + PROTOCOLID_RESERVED4, + PROTOCOLID_RESERVED5, + PROTOCOLID_PREROCE, + PROTOCOLID_COMMON, + PROTOCOLID_RESERVED6, + MAX_PROTOCOL_TYPE +}; + +/* status block structure */ +struct cau_pi_entry { + u32 prod; +#define CAU_PI_ENTRY_PROD_VAL_MASK 0xFFFF +#define CAU_PI_ENTRY_PROD_VAL_SHIFT 0 +#define CAU_PI_ENTRY_PI_TIMESET_MASK 0x7F +#define CAU_PI_ENTRY_PI_TIMESET_SHIFT 16 +#define CAU_PI_ENTRY_FSM_SEL_MASK 0x1 +#define CAU_PI_ENTRY_FSM_SEL_SHIFT 23 +#define CAU_PI_ENTRY_RESERVED_MASK 0xFF +#define CAU_PI_ENTRY_RESERVED_SHIFT 24 +}; + +/* status block structure */ +struct cau_sb_entry { + u32 data; +#define CAU_SB_ENTRY_SB_PROD_MASK 0xFFFFFF +#define CAU_SB_ENTRY_SB_PROD_SHIFT 0 +#define CAU_SB_ENTRY_STATE0_MASK 0xF +#define CAU_SB_ENTRY_STATE0_SHIFT 24 +#define CAU_SB_ENTRY_STATE1_MASK 0xF +#define CAU_SB_ENTRY_STATE1_SHIFT 28 + u32 params; +#define CAU_SB_ENTRY_SB_TIMESET0_MASK 0x7F +#define CAU_SB_ENTRY_SB_TIMESET0_SHIFT 0 +#define CAU_SB_ENTRY_SB_TIMESET1_MASK 0x7F +#define CAU_SB_ENTRY_SB_TIMESET1_SHIFT 7 +#define CAU_SB_ENTRY_TIMER_RES0_MASK 0x3 +#define CAU_SB_ENTRY_TIMER_RES0_SHIFT 14 +#define CAU_SB_ENTRY_TIMER_RES1_MASK 0x3 +#define CAU_SB_ENTRY_TIMER_RES1_SHIFT 16 +#define CAU_SB_ENTRY_VF_NUMBER_MASK 0xFF +#define CAU_SB_ENTRY_VF_NUMBER_SHIFT 18 +#define CAU_SB_ENTRY_VF_VALID_MASK 0x1 +#define CAU_SB_ENTRY_VF_VALID_SHIFT 26 +#define CAU_SB_ENTRY_PF_NUMBER_MASK 0xF +#define CAU_SB_ENTRY_PF_NUMBER_SHIFT 27 +#define CAU_SB_ENTRY_TPH_MASK 0x1 +#define CAU_SB_ENTRY_TPH_SHIFT 31 +}; + +/* core doorbell data */ +struct core_db_data { + u8 params; +#define CORE_DB_DATA_DEST_MASK 0x3 +#define CORE_DB_DATA_DEST_SHIFT 0 +#define CORE_DB_DATA_AGG_CMD_MASK 0x3 +#define CORE_DB_DATA_AGG_CMD_SHIFT 2 +#define CORE_DB_DATA_BYPASS_EN_MASK 0x1 +#define CORE_DB_DATA_BYPASS_EN_SHIFT 4 +#define CORE_DB_DATA_RESERVED_MASK 0x1 +#define CORE_DB_DATA_RESERVED_SHIFT 5 +#define CORE_DB_DATA_AGG_VAL_SEL_MASK 0x3 +#define CORE_DB_DATA_AGG_VAL_SEL_SHIFT 6 + u8 agg_flags; + __le16 spq_prod; +}; + +/* Enum of doorbell aggregative command selection */ +enum db_agg_cmd_sel { + DB_AGG_CMD_NOP, + DB_AGG_CMD_SET, + DB_AGG_CMD_ADD, + DB_AGG_CMD_MAX, + MAX_DB_AGG_CMD_SEL +}; + +/* Enum of doorbell destination */ +enum db_dest { + DB_DEST_XCM, + DB_DEST_UCM, + DB_DEST_TCM, + DB_NUM_DESTINATIONS, + MAX_DB_DEST +}; + +/* Structure for doorbell address, in legacy mode */ +struct db_legacy_addr { + __le32 addr; +#define DB_LEGACY_ADDR_RESERVED0_MASK 0x3 +#define DB_LEGACY_ADDR_RESERVED0_SHIFT 0 +#define DB_LEGACY_ADDR_DEMS_MASK 0x7 +#define DB_LEGACY_ADDR_DEMS_SHIFT 2 +#define DB_LEGACY_ADDR_ICID_MASK 0x7FFFFFF +#define DB_LEGACY_ADDR_ICID_SHIFT 5 +}; + +/* Igu interrupt command */ +enum igu_int_cmd { + IGU_INT_ENABLE = 0, + IGU_INT_DISABLE = 1, + IGU_INT_NOP = 2, + IGU_INT_NOP2 = 3, + MAX_IGU_INT_CMD +}; + +/* IGU producer or consumer update command */ +struct igu_prod_cons_update { + u32 sb_id_and_flags; +#define IGU_PROD_CONS_UPDATE_SB_INDEX_MASK 0xFFFFFF +#define IGU_PROD_CONS_UPDATE_SB_INDEX_SHIFT 0 +#define IGU_PROD_CONS_UPDATE_UPDATE_FLAG_MASK 0x1 +#define IGU_PROD_CONS_UPDATE_UPDATE_FLAG_SHIFT 24 +#define IGU_PROD_CONS_UPDATE_ENABLE_INT_MASK 0x3 +#define IGU_PROD_CONS_UPDATE_ENABLE_INT_SHIFT 25 +#define IGU_PROD_CONS_UPDATE_SEGMENT_ACCESS_MASK 0x1 +#define IGU_PROD_CONS_UPDATE_SEGMENT_ACCESS_SHIFT 27 +#define IGU_PROD_CONS_UPDATE_TIMER_MASK_MASK 0x1 +#define IGU_PROD_CONS_UPDATE_TIMER_MASK_SHIFT 28 +#define IGU_PROD_CONS_UPDATE_RESERVED0_MASK 0x3 +#define IGU_PROD_CONS_UPDATE_RESERVED0_SHIFT 29 +#define IGU_PROD_CONS_UPDATE_COMMAND_TYPE_MASK 0x1 +#define IGU_PROD_CONS_UPDATE_COMMAND_TYPE_SHIFT 31 + u32 reserved1; +}; + +/* Igu segments access for default status block only */ +enum igu_seg_access { + IGU_SEG_ACCESS_REG = 0, + IGU_SEG_ACCESS_ATTN = 1, + MAX_IGU_SEG_ACCESS +}; + +struct parsing_and_err_flags { + __le16 flags; +#define PARSING_AND_ERR_FLAGS_L3TYPE_MASK 0x3 +#define PARSING_AND_ERR_FLAGS_L3TYPE_SHIFT 0 +#define PARSING_AND_ERR_FLAGS_L4PROTOCOL_MASK 0x3 +#define PARSING_AND_ERR_FLAGS_L4PROTOCOL_SHIFT 2 +#define PARSING_AND_ERR_FLAGS_IPV4FRAG_MASK 0x1 +#define PARSING_AND_ERR_FLAGS_IPV4FRAG_SHIFT 4 +#define PARSING_AND_ERR_FLAGS_TAG8021QEXIST_MASK 0x1 +#define PARSING_AND_ERR_FLAGS_TAG8021QEXIST_SHIFT 5 +#define PARSING_AND_ERR_FLAGS_L4CHKSMWASCALCULATED_MASK 0x1 +#define PARSING_AND_ERR_FLAGS_L4CHKSMWASCALCULATED_SHIFT 6 +#define PARSING_AND_ERR_FLAGS_TIMESYNCPKT_MASK 0x1 +#define PARSING_AND_ERR_FLAGS_TIMESYNCPKT_SHIFT 7 +#define PARSING_AND_ERR_FLAGS_TIMESTAMPRECORDED_MASK 0x1 +#define PARSING_AND_ERR_FLAGS_TIMESTAMPRECORDED_SHIFT 8 +#define PARSING_AND_ERR_FLAGS_IPHDRERROR_MASK 0x1 +#define PARSING_AND_ERR_FLAGS_IPHDRERROR_SHIFT 9 +#define PARSING_AND_ERR_FLAGS_L4CHKSMERROR_MASK 0x1 +#define PARSING_AND_ERR_FLAGS_L4CHKSMERROR_SHIFT 10 +#define PARSING_AND_ERR_FLAGS_TUNNELEXIST_MASK 0x1 +#define PARSING_AND_ERR_FLAGS_TUNNELEXIST_SHIFT 11 +#define PARSING_AND_ERR_FLAGS_TUNNEL8021QTAGEXIST_MASK 0x1 +#define PARSING_AND_ERR_FLAGS_TUNNEL8021QTAGEXIST_SHIFT 12 +#define PARSING_AND_ERR_FLAGS_TUNNELIPHDRERROR_MASK 0x1 +#define PARSING_AND_ERR_FLAGS_TUNNELIPHDRERROR_SHIFT 13 +#define PARSING_AND_ERR_FLAGS_TUNNELL4CHKSMWASCALCULATED_MASK 0x1 +#define PARSING_AND_ERR_FLAGS_TUNNELL4CHKSMWASCALCULATED_SHIFT 14 +#define PARSING_AND_ERR_FLAGS_TUNNELL4CHKSMERROR_MASK 0x1 +#define PARSING_AND_ERR_FLAGS_TUNNELL4CHKSMERROR_SHIFT 15 +}; + +/* Concrete Function ID. */ +struct pxp_concrete_fid { + __le16 fid; +#define PXP_CONCRETE_FID_PFID_MASK 0xF +#define PXP_CONCRETE_FID_PFID_SHIFT 0 +#define PXP_CONCRETE_FID_PORT_MASK 0x3 +#define PXP_CONCRETE_FID_PORT_SHIFT 4 +#define PXP_CONCRETE_FID_PATH_MASK 0x1 +#define PXP_CONCRETE_FID_PATH_SHIFT 6 +#define PXP_CONCRETE_FID_VFVALID_MASK 0x1 +#define PXP_CONCRETE_FID_VFVALID_SHIFT 7 +#define PXP_CONCRETE_FID_VFID_MASK 0xFF +#define PXP_CONCRETE_FID_VFID_SHIFT 8 +}; + +struct pxp_pretend_concrete_fid { + __le16 fid; +#define PXP_PRETEND_CONCRETE_FID_PFID_MASK 0xF +#define PXP_PRETEND_CONCRETE_FID_PFID_SHIFT 0 +#define PXP_PRETEND_CONCRETE_FID_RESERVED_MASK 0x7 +#define PXP_PRETEND_CONCRETE_FID_RESERVED_SHIFT 4 +#define PXP_PRETEND_CONCRETE_FID_VFVALID_MASK 0x1 +#define PXP_PRETEND_CONCRETE_FID_VFVALID_SHIFT 7 +#define PXP_PRETEND_CONCRETE_FID_VFID_MASK 0xFF +#define PXP_PRETEND_CONCRETE_FID_VFID_SHIFT 8 +}; + +union pxp_pretend_fid { + struct pxp_pretend_concrete_fid concrete_fid; + __le16 opaque_fid; +}; + +/* Pxp Pretend Command Register. */ +struct pxp_pretend_cmd { + union pxp_pretend_fid fid; + __le16 control; +#define PXP_PRETEND_CMD_PATH_MASK 0x1 +#define PXP_PRETEND_CMD_PATH_SHIFT 0 +#define PXP_PRETEND_CMD_USE_PORT_MASK 0x1 +#define PXP_PRETEND_CMD_USE_PORT_SHIFT 1 +#define PXP_PRETEND_CMD_PORT_MASK 0x3 +#define PXP_PRETEND_CMD_PORT_SHIFT 2 +#define PXP_PRETEND_CMD_RESERVED0_MASK 0xF +#define PXP_PRETEND_CMD_RESERVED0_SHIFT 4 +#define PXP_PRETEND_CMD_RESERVED1_MASK 0xF +#define PXP_PRETEND_CMD_RESERVED1_SHIFT 8 +#define PXP_PRETEND_CMD_PRETEND_PATH_MASK 0x1 +#define PXP_PRETEND_CMD_PRETEND_PATH_SHIFT 12 +#define PXP_PRETEND_CMD_PRETEND_PORT_MASK 0x1 +#define PXP_PRETEND_CMD_PRETEND_PORT_SHIFT 13 +#define PXP_PRETEND_CMD_PRETEND_FUNCTION_MASK 0x1 +#define PXP_PRETEND_CMD_PRETEND_FUNCTION_SHIFT 14 +#define PXP_PRETEND_CMD_IS_CONCRETE_MASK 0x1 +#define PXP_PRETEND_CMD_IS_CONCRETE_SHIFT 15 +}; + +/* PTT Record in PXP Admin Window. */ +struct pxp_ptt_entry { + __le32 offset; +#define PXP_PTT_ENTRY_OFFSET_MASK 0x7FFFFF +#define PXP_PTT_ENTRY_OFFSET_SHIFT 0 +#define PXP_PTT_ENTRY_RESERVED0_MASK 0x1FF +#define PXP_PTT_ENTRY_RESERVED0_SHIFT 23 + struct pxp_pretend_cmd pretend; +}; + +/* RSS hash type */ +enum rss_hash_type { + RSS_HASH_TYPE_DEFAULT = 0, + RSS_HASH_TYPE_IPV4 = 1, + RSS_HASH_TYPE_TCP_IPV4 = 2, + RSS_HASH_TYPE_IPV6 = 3, + RSS_HASH_TYPE_TCP_IPV6 = 4, + RSS_HASH_TYPE_UDP_IPV4 = 5, + RSS_HASH_TYPE_UDP_IPV6 = 6, + MAX_RSS_HASH_TYPE +}; + +/* status block structure */ +struct status_block { + __le16 pi_array[PIS_PER_SB]; + __le32 sb_num; +#define STATUS_BLOCK_SB_NUM_MASK 0x1FF +#define STATUS_BLOCK_SB_NUM_SHIFT 0 +#define STATUS_BLOCK_ZERO_PAD_MASK 0x7F +#define STATUS_BLOCK_ZERO_PAD_SHIFT 9 +#define STATUS_BLOCK_ZERO_PAD2_MASK 0xFFFF +#define STATUS_BLOCK_ZERO_PAD2_SHIFT 16 + __le32 prod_index; +#define STATUS_BLOCK_PROD_INDEX_MASK 0xFFFFFF +#define STATUS_BLOCK_PROD_INDEX_SHIFT 0 +#define STATUS_BLOCK_ZERO_PAD3_MASK 0xFF +#define STATUS_BLOCK_ZERO_PAD3_SHIFT 24 +}; + +#endif /* __COMMON_HSI__ */ diff --git a/include/linux/qed/qed_chain.h b/include/linux/qed/qed_chain.h new file mode 100644 index 000000000000..b920c3605c46 --- /dev/null +++ b/include/linux/qed/qed_chain.h @@ -0,0 +1,539 @@ +/* QLogic qed NIC Driver + * Copyright (c) 2015 QLogic Corporation + * + * This software is available under the terms of the GNU General Public License + * (GPL) Version 2, available from the file COPYING in the main directory of + * this source tree. + */ + +#ifndef _QED_CHAIN_H +#define _QED_CHAIN_H + +#include +#include +#include +#include +#include +#include + +/* dma_addr_t manip */ +#define DMA_LO_LE(x) cpu_to_le32(lower_32_bits(x)) +#define DMA_HI_LE(x) cpu_to_le32(upper_32_bits(x)) + +#define HILO_GEN(hi, lo, type) ((((type)(hi)) << 32) + (lo)) +#define HILO_DMA(hi, lo) HILO_GEN(hi, lo, dma_addr_t) +#define HILO_64(hi, lo) HILO_GEN((le32_to_cpu(hi)), (le32_to_cpu(lo)), u64) +#define HILO_DMA_REGPAIR(regpair) (HILO_DMA(regpair.hi, regpair.lo)) +#define HILO_64_REGPAIR(regpair) (HILO_64(regpair.hi, regpair.lo)) + +enum qed_chain_mode { + /* Each Page contains a next pointer at its end */ + QED_CHAIN_MODE_NEXT_PTR, + + /* Chain is a single page (next ptr) is unrequired */ + QED_CHAIN_MODE_SINGLE, + + /* Page pointers are located in a side list */ + QED_CHAIN_MODE_PBL, +}; + +enum qed_chain_use_mode { + QED_CHAIN_USE_TO_PRODUCE, /* Chain starts empty */ + QED_CHAIN_USE_TO_CONSUME, /* Chain starts full */ + QED_CHAIN_USE_TO_CONSUME_PRODUCE, /* Chain starts empty */ +}; + +struct qed_chain_next { + struct regpair next_phys; + void *next_virt; +}; + +struct qed_chain_pbl { + dma_addr_t p_phys_table; + void *p_virt_table; + u16 prod_page_idx; + u16 cons_page_idx; +}; + +struct qed_chain { + void *p_virt_addr; + dma_addr_t p_phys_addr; + void *p_prod_elem; + void *p_cons_elem; + u16 page_cnt; + enum qed_chain_mode mode; + enum qed_chain_use_mode intended_use; /* used to produce/consume */ + u16 capacity; /*< number of _usable_ elements */ + u16 size; /* number of elements */ + u16 prod_idx; + u16 cons_idx; + u16 elem_per_page; + u16 elem_per_page_mask; + u16 elem_unusable; + u16 usable_per_page; + u16 elem_size; + u16 next_page_mask; + struct qed_chain_pbl pbl; +}; + +#define QED_CHAIN_PBL_ENTRY_SIZE (8) +#define QED_CHAIN_PAGE_SIZE (0x1000) +#define ELEMS_PER_PAGE(elem_size) (QED_CHAIN_PAGE_SIZE / (elem_size)) + +#define UNUSABLE_ELEMS_PER_PAGE(elem_size, mode) \ + ((mode == QED_CHAIN_MODE_NEXT_PTR) ? \ + (1 + ((sizeof(struct qed_chain_next) - 1) / \ + (elem_size))) : 0) + +#define USABLE_ELEMS_PER_PAGE(elem_size, mode) \ + ((u32)(ELEMS_PER_PAGE(elem_size) - \ + UNUSABLE_ELEMS_PER_PAGE(elem_size, mode))) + +#define QED_CHAIN_PAGE_CNT(elem_cnt, elem_size, mode) \ + DIV_ROUND_UP(elem_cnt, USABLE_ELEMS_PER_PAGE(elem_size, mode)) + +/* Accessors */ +static inline u16 qed_chain_get_prod_idx(struct qed_chain *p_chain) +{ + return p_chain->prod_idx; +} + +static inline u16 qed_chain_get_cons_idx(struct qed_chain *p_chain) +{ + return p_chain->cons_idx; +} + +static inline u16 qed_chain_get_elem_left(struct qed_chain *p_chain) +{ + u16 used; + + /* we don't need to trancate upon assignmet, as we assign u32->u16 */ + used = ((u32)0x10000u + (u32)(p_chain->prod_idx)) - + (u32)p_chain->cons_idx; + if (p_chain->mode == QED_CHAIN_MODE_NEXT_PTR) + used -= (used / p_chain->elem_per_page); + + return p_chain->capacity - used; +} + +static inline u8 qed_chain_is_full(struct qed_chain *p_chain) +{ + return qed_chain_get_elem_left(p_chain) == p_chain->capacity; +} + +static inline u8 qed_chain_is_empty(struct qed_chain *p_chain) +{ + return qed_chain_get_elem_left(p_chain) == 0; +} + +static inline u16 qed_chain_get_elem_per_page( + struct qed_chain *p_chain) +{ + return p_chain->elem_per_page; +} + +static inline u16 qed_chain_get_usable_per_page( + struct qed_chain *p_chain) +{ + return p_chain->usable_per_page; +} + +static inline u16 qed_chain_get_unusable_per_page( + struct qed_chain *p_chain) +{ + return p_chain->elem_unusable; +} + +static inline u16 qed_chain_get_size(struct qed_chain *p_chain) +{ + return p_chain->size; +} + +static inline dma_addr_t +qed_chain_get_pbl_phys(struct qed_chain *p_chain) +{ + return p_chain->pbl.p_phys_table; +} + +/** + * @brief qed_chain_advance_page - + * + * Advance the next element accros pages for a linked chain + * + * @param p_chain + * @param p_next_elem + * @param idx_to_inc + * @param page_to_inc + */ +static inline void +qed_chain_advance_page(struct qed_chain *p_chain, + void **p_next_elem, + u16 *idx_to_inc, + u16 *page_to_inc) + +{ + switch (p_chain->mode) { + case QED_CHAIN_MODE_NEXT_PTR: + { + struct qed_chain_next *p_next = *p_next_elem; + *p_next_elem = p_next->next_virt; + *idx_to_inc += p_chain->elem_unusable; + break; + } + case QED_CHAIN_MODE_SINGLE: + *p_next_elem = p_chain->p_virt_addr; + break; + + case QED_CHAIN_MODE_PBL: + /* It is assumed pages are sequential, next element needs + * to change only when passing going back to first from last. + */ + if (++(*page_to_inc) == p_chain->page_cnt) { + *page_to_inc = 0; + *p_next_elem = p_chain->p_virt_addr; + } + } +} + +#define is_unusable_idx(p, idx) \ + (((p)->idx & (p)->elem_per_page_mask) == (p)->usable_per_page) + +#define is_unusable_next_idx(p, idx) \ + ((((p)->idx + 1) & (p)->elem_per_page_mask) == (p)->usable_per_page) + +#define test_ans_skip(p, idx) \ + do { \ + if (is_unusable_idx(p, idx)) { \ + (p)->idx += (p)->elem_unusable; \ + } \ + } while (0) + +/** + * @brief qed_chain_return_multi_produced - + * + * A chain in which the driver "Produces" elements should use this API + * to indicate previous produced elements are now consumed. + * + * @param p_chain + * @param num + */ +static inline void +qed_chain_return_multi_produced(struct qed_chain *p_chain, + u16 num) +{ + p_chain->cons_idx += num; + test_ans_skip(p_chain, cons_idx); +} + +/** + * @brief qed_chain_return_produced - + * + * A chain in which the driver "Produces" elements should use this API + * to indicate previous produced elements are now consumed. + * + * @param p_chain + */ +static inline void qed_chain_return_produced(struct qed_chain *p_chain) +{ + p_chain->cons_idx++; + test_ans_skip(p_chain, cons_idx); +} + +/** + * @brief qed_chain_produce - + * + * A chain in which the driver "Produces" elements should use this to get + * a pointer to the next element which can be "Produced". It's driver + * responsibility to validate that the chain has room for new element. + * + * @param p_chain + * + * @return void*, a pointer to next element + */ +static inline void *qed_chain_produce(struct qed_chain *p_chain) +{ + void *ret = NULL; + + if ((p_chain->prod_idx & p_chain->elem_per_page_mask) == + p_chain->next_page_mask) { + qed_chain_advance_page(p_chain, &p_chain->p_prod_elem, + &p_chain->prod_idx, + &p_chain->pbl.prod_page_idx); + } + + ret = p_chain->p_prod_elem; + p_chain->prod_idx++; + p_chain->p_prod_elem = (void *)(((u8 *)p_chain->p_prod_elem) + + p_chain->elem_size); + + return ret; +} + +/** + * @brief qed_chain_get_capacity - + * + * Get the maximum number of BDs in chain + * + * @param p_chain + * @param num + * + * @return u16, number of unusable BDs + */ +static inline u16 qed_chain_get_capacity(struct qed_chain *p_chain) +{ + return p_chain->capacity; +} + +/** + * @brief qed_chain_recycle_consumed - + * + * Returns an element which was previously consumed; + * Increments producers so they could be written to FW. + * + * @param p_chain + */ +static inline void +qed_chain_recycle_consumed(struct qed_chain *p_chain) +{ + test_ans_skip(p_chain, prod_idx); + p_chain->prod_idx++; +} + +/** + * @brief qed_chain_consume - + * + * A Chain in which the driver utilizes data written by a different source + * (i.e., FW) should use this to access passed buffers. + * + * @param p_chain + * + * @return void*, a pointer to the next buffer written + */ +static inline void *qed_chain_consume(struct qed_chain *p_chain) +{ + void *ret = NULL; + + if ((p_chain->cons_idx & p_chain->elem_per_page_mask) == + p_chain->next_page_mask) { + qed_chain_advance_page(p_chain, &p_chain->p_cons_elem, + &p_chain->cons_idx, + &p_chain->pbl.cons_page_idx); + } + + ret = p_chain->p_cons_elem; + p_chain->cons_idx++; + p_chain->p_cons_elem = (void *)(((u8 *)p_chain->p_cons_elem) + + p_chain->elem_size); + + return ret; +} + +/** + * @brief qed_chain_reset - Resets the chain to its start state + * + * @param p_chain pointer to a previously allocted chain + */ +static inline void qed_chain_reset(struct qed_chain *p_chain) +{ + int i; + + p_chain->prod_idx = 0; + p_chain->cons_idx = 0; + p_chain->p_cons_elem = p_chain->p_virt_addr; + p_chain->p_prod_elem = p_chain->p_virt_addr; + + if (p_chain->mode == QED_CHAIN_MODE_PBL) { + p_chain->pbl.prod_page_idx = p_chain->page_cnt - 1; + p_chain->pbl.cons_page_idx = p_chain->page_cnt - 1; + } + + switch (p_chain->intended_use) { + case QED_CHAIN_USE_TO_CONSUME_PRODUCE: + case QED_CHAIN_USE_TO_PRODUCE: + /* Do nothing */ + break; + + case QED_CHAIN_USE_TO_CONSUME: + /* produce empty elements */ + for (i = 0; i < p_chain->capacity; i++) + qed_chain_recycle_consumed(p_chain); + break; + } +} + +/** + * @brief qed_chain_init - Initalizes a basic chain struct + * + * @param p_chain + * @param p_virt_addr + * @param p_phys_addr physical address of allocated buffer's beginning + * @param page_cnt number of pages in the allocated buffer + * @param elem_size size of each element in the chain + * @param intended_use + * @param mode + */ +static inline void qed_chain_init(struct qed_chain *p_chain, + void *p_virt_addr, + dma_addr_t p_phys_addr, + u16 page_cnt, + u8 elem_size, + enum qed_chain_use_mode intended_use, + enum qed_chain_mode mode) +{ + /* chain fixed parameters */ + p_chain->p_virt_addr = p_virt_addr; + p_chain->p_phys_addr = p_phys_addr; + p_chain->elem_size = elem_size; + p_chain->page_cnt = page_cnt; + p_chain->mode = mode; + + p_chain->intended_use = intended_use; + p_chain->elem_per_page = ELEMS_PER_PAGE(elem_size); + p_chain->usable_per_page = + USABLE_ELEMS_PER_PAGE(elem_size, mode); + p_chain->capacity = p_chain->usable_per_page * page_cnt; + p_chain->size = p_chain->elem_per_page * page_cnt; + p_chain->elem_per_page_mask = p_chain->elem_per_page - 1; + + p_chain->elem_unusable = UNUSABLE_ELEMS_PER_PAGE(elem_size, mode); + + p_chain->next_page_mask = (p_chain->usable_per_page & + p_chain->elem_per_page_mask); + + if (mode == QED_CHAIN_MODE_NEXT_PTR) { + struct qed_chain_next *p_next; + u16 i; + + for (i = 0; i < page_cnt - 1; i++) { + /* Increment mem_phy to the next page. */ + p_phys_addr += QED_CHAIN_PAGE_SIZE; + + /* Initialize the physical address of the next page. */ + p_next = (struct qed_chain_next *)((u8 *)p_virt_addr + + elem_size * + p_chain-> + usable_per_page); + + p_next->next_phys.lo = DMA_LO_LE(p_phys_addr); + p_next->next_phys.hi = DMA_HI_LE(p_phys_addr); + + /* Initialize the virtual address of the next page. */ + p_next->next_virt = (void *)((u8 *)p_virt_addr + + QED_CHAIN_PAGE_SIZE); + + /* Move to the next page. */ + p_virt_addr = p_next->next_virt; + } + + /* Last page's next should point to beginning of the chain */ + p_next = (struct qed_chain_next *)((u8 *)p_virt_addr + + elem_size * + p_chain->usable_per_page); + + p_next->next_phys.lo = DMA_LO_LE(p_chain->p_phys_addr); + p_next->next_phys.hi = DMA_HI_LE(p_chain->p_phys_addr); + p_next->next_virt = p_chain->p_virt_addr; + } + qed_chain_reset(p_chain); +} + +/** + * @brief qed_chain_pbl_init - Initalizes a basic pbl chain + * struct + * @param p_chain + * @param p_virt_addr virtual address of allocated buffer's beginning + * @param p_phys_addr physical address of allocated buffer's beginning + * @param page_cnt number of pages in the allocated buffer + * @param elem_size size of each element in the chain + * @param use_mode + * @param p_phys_pbl pointer to a pre-allocated side table + * which will hold physical page addresses. + * @param p_virt_pbl pointer to a pre allocated side table + * which will hold virtual page addresses. + */ +static inline void +qed_chain_pbl_init(struct qed_chain *p_chain, + void *p_virt_addr, + dma_addr_t p_phys_addr, + u16 page_cnt, + u8 elem_size, + enum qed_chain_use_mode use_mode, + dma_addr_t p_phys_pbl, + dma_addr_t *p_virt_pbl) +{ + dma_addr_t *p_pbl_dma = p_virt_pbl; + int i; + + qed_chain_init(p_chain, p_virt_addr, p_phys_addr, page_cnt, + elem_size, use_mode, QED_CHAIN_MODE_PBL); + + p_chain->pbl.p_phys_table = p_phys_pbl; + p_chain->pbl.p_virt_table = p_virt_pbl; + + /* Fill the PBL with physical addresses*/ + for (i = 0; i < page_cnt; i++) { + *p_pbl_dma = p_phys_addr; + p_phys_addr += QED_CHAIN_PAGE_SIZE; + p_pbl_dma++; + } +} + +/** + * @brief qed_chain_set_prod - sets the prod to the given + * value + * + * @param prod_idx + * @param p_prod_elem + */ +static inline void qed_chain_set_prod(struct qed_chain *p_chain, + u16 prod_idx, + void *p_prod_elem) +{ + p_chain->prod_idx = prod_idx; + p_chain->p_prod_elem = p_prod_elem; +} + +/** + * @brief qed_chain_get_elem - + * + * get a pointer to an element represented by absolute idx + * + * @param p_chain + * @assumption p_chain->size is a power of 2 + * + * @return void*, a pointer to next element + */ +static inline void *qed_chain_sge_get_elem(struct qed_chain *p_chain, + u16 idx) +{ + void *ret = NULL; + + if (idx >= p_chain->size) + return NULL; + + ret = (u8 *)p_chain->p_virt_addr + p_chain->elem_size * idx; + + return ret; +} + +/** + * @brief qed_chain_sge_inc_cons_prod + * + * for sge chains, producer isn't increased serially, the ring + * is expected to be full at all times. Once elements are + * consumed, they are immediately produced. + * + * @param p_chain + * @param cnt + * + * @return inline void + */ +static inline void +qed_chain_sge_inc_cons_prod(struct qed_chain *p_chain, + u16 cnt) +{ + p_chain->prod_idx += cnt; + p_chain->cons_idx += cnt; +} + +#endif diff --git a/include/linux/qed/qed_if.h b/include/linux/qed/qed_if.h new file mode 100644 index 000000000000..dc9a1353f971 --- /dev/null +++ b/include/linux/qed/qed_if.h @@ -0,0 +1,498 @@ +/* QLogic qed NIC Driver + * + * Copyright (c) 2015 QLogic Corporation + * + * This software is available under the terms of the GNU General Public License + * (GPL) Version 2, available from the file COPYING in the main directory of + * this source tree. + */ + +#ifndef _QED_IF_H +#define _QED_IF_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DIRECT_REG_WR(reg_addr, val) writel((u32)val, \ + (void __iomem *)(reg_addr)) + +#define DIRECT_REG_RD(reg_addr) readl((void __iomem *)(reg_addr)) + +#define QED_COALESCE_MAX 0xFF + +/* forward */ +struct qed_dev; + +struct qed_eth_pf_params { + /* The following parameters are used during HW-init + * and these parameters need to be passed as arguments + * to update_pf_params routine invoked before slowpath start + */ + u16 num_cons; +}; + +struct qed_pf_params { + struct qed_eth_pf_params eth_pf_params; +}; + +enum qed_int_mode { + QED_INT_MODE_INTA, + QED_INT_MODE_MSIX, + QED_INT_MODE_MSI, + QED_INT_MODE_POLL, +}; + +struct qed_sb_info { + struct status_block *sb_virt; + dma_addr_t sb_phys; + u32 sb_ack; /* Last given ack */ + u16 igu_sb_id; + void __iomem *igu_addr; + u8 flags; +#define QED_SB_INFO_INIT 0x1 +#define QED_SB_INFO_SETUP 0x2 + + struct qed_dev *cdev; +}; + +struct qed_dev_info { + unsigned long pci_mem_start; + unsigned long pci_mem_end; + unsigned int pci_irq; + u8 num_hwfns; + + u8 hw_mac[ETH_ALEN]; + bool is_mf; + + /* FW version */ + u16 fw_major; + u16 fw_minor; + u16 fw_rev; + u16 fw_eng; + + /* MFW version */ + u32 mfw_rev; + + u32 flash_size; + u8 mf_mode; +}; + +enum qed_sb_type { + QED_SB_TYPE_L2_QUEUE, +}; + +enum qed_protocol { + QED_PROTOCOL_ETH, +}; + +struct qed_link_params { + bool link_up; + +#define QED_LINK_OVERRIDE_SPEED_AUTONEG BIT(0) +#define QED_LINK_OVERRIDE_SPEED_ADV_SPEEDS BIT(1) +#define QED_LINK_OVERRIDE_SPEED_FORCED_SPEED BIT(2) +#define QED_LINK_OVERRIDE_PAUSE_CONFIG BIT(3) + u32 override_flags; + bool autoneg; + u32 adv_speeds; + u32 forced_speed; +#define QED_LINK_PAUSE_AUTONEG_ENABLE BIT(0) +#define QED_LINK_PAUSE_RX_ENABLE BIT(1) +#define QED_LINK_PAUSE_TX_ENABLE BIT(2) + u32 pause_config; +}; + +struct qed_link_output { + bool link_up; + + u32 supported_caps; /* In SUPPORTED defs */ + u32 advertised_caps; /* In ADVERTISED defs */ + u32 lp_caps; /* In ADVERTISED defs */ + u32 speed; /* In Mb/s */ + u8 duplex; /* In DUPLEX defs */ + u8 port; /* In PORT defs */ + bool autoneg; + u32 pause_config; +}; + +#define QED_DRV_VER_STR_SIZE 12 +struct qed_slowpath_params { + u32 int_mode; + u8 drv_major; + u8 drv_minor; + u8 drv_rev; + u8 drv_eng; + u8 name[QED_DRV_VER_STR_SIZE]; +}; + +#define ILT_PAGE_SIZE_TCFC 0x8000 /* 32KB */ + +struct qed_int_info { + struct msix_entry *msix; + u8 msix_cnt; + + /* This should be updated by the protocol driver */ + u8 used_cnt; +}; + +struct qed_common_cb_ops { + void (*link_update)(void *dev, + struct qed_link_output *link); +}; + +struct qed_common_ops { + struct qed_dev* (*probe)(struct pci_dev *dev, + enum qed_protocol protocol, + u32 dp_module, u8 dp_level); + + void (*remove)(struct qed_dev *cdev); + + int (*set_power_state)(struct qed_dev *cdev, + pci_power_t state); + + void (*set_id)(struct qed_dev *cdev, + char name[], + char ver_str[]); + + /* Client drivers need to make this call before slowpath_start. + * PF params required for the call before slowpath_start is + * documented within the qed_pf_params structure definition. + */ + void (*update_pf_params)(struct qed_dev *cdev, + struct qed_pf_params *params); + int (*slowpath_start)(struct qed_dev *cdev, + struct qed_slowpath_params *params); + + int (*slowpath_stop)(struct qed_dev *cdev); + + /* Requests to use `cnt' interrupts for fastpath. + * upon success, returns number of interrupts allocated for fastpath. + */ + int (*set_fp_int)(struct qed_dev *cdev, + u16 cnt); + + /* Fills `info' with pointers required for utilizing interrupts */ + int (*get_fp_int)(struct qed_dev *cdev, + struct qed_int_info *info); + + u32 (*sb_init)(struct qed_dev *cdev, + struct qed_sb_info *sb_info, + void *sb_virt_addr, + dma_addr_t sb_phy_addr, + u16 sb_id, + enum qed_sb_type type); + + u32 (*sb_release)(struct qed_dev *cdev, + struct qed_sb_info *sb_info, + u16 sb_id); + + void (*simd_handler_config)(struct qed_dev *cdev, + void *token, + int index, + void (*handler)(void *)); + + void (*simd_handler_clean)(struct qed_dev *cdev, + int index); +/** + * @brief set_link - set links according to params + * + * @param cdev + * @param params - values used to override the default link configuration + * + * @return 0 on success, error otherwise. + */ + int (*set_link)(struct qed_dev *cdev, + struct qed_link_params *params); + +/** + * @brief get_link - returns the current link state. + * + * @param cdev + * @param if_link - structure to be filled with current link configuration. + */ + void (*get_link)(struct qed_dev *cdev, + struct qed_link_output *if_link); + +/** + * @brief - drains chip in case Tx completions fail to arrive due to pause. + * + * @param cdev + */ + int (*drain)(struct qed_dev *cdev); + +/** + * @brief update_msglvl - update module debug level + * + * @param cdev + * @param dp_module + * @param dp_level + */ + void (*update_msglvl)(struct qed_dev *cdev, + u32 dp_module, + u8 dp_level); + + int (*chain_alloc)(struct qed_dev *cdev, + enum qed_chain_use_mode intended_use, + enum qed_chain_mode mode, + u16 num_elems, + size_t elem_size, + struct qed_chain *p_chain); + + void (*chain_free)(struct qed_dev *cdev, + struct qed_chain *p_chain); +}; + +/** + * @brief qed_get_protocol_version + * + * @param protocol + * + * @return version supported by qed for given protocol driver + */ +u32 qed_get_protocol_version(enum qed_protocol protocol); + +#define MASK_FIELD(_name, _value) \ + ((_value) &= (_name ## _MASK)) + +#define FIELD_VALUE(_name, _value) \ + ((_value & _name ## _MASK) << _name ## _SHIFT) + +#define SET_FIELD(value, name, flag) \ + do { \ + (value) &= ~(name ## _MASK << name ## _SHIFT); \ + (value) |= (((u64)flag) << (name ## _SHIFT)); \ + } while (0) + +#define GET_FIELD(value, name) \ + (((value) >> (name ## _SHIFT)) & name ## _MASK) + +/* Debug print definitions */ +#define DP_ERR(cdev, fmt, ...) \ + pr_err("[%s:%d(%s)]" fmt, \ + __func__, __LINE__, \ + DP_NAME(cdev) ? DP_NAME(cdev) : "", \ + ## __VA_ARGS__) \ + +#define DP_NOTICE(cdev, fmt, ...) \ + do { \ + if (unlikely((cdev)->dp_level <= QED_LEVEL_NOTICE)) { \ + pr_notice("[%s:%d(%s)]" fmt, \ + __func__, __LINE__, \ + DP_NAME(cdev) ? DP_NAME(cdev) : "", \ + ## __VA_ARGS__); \ + \ + } \ + } while (0) + +#define DP_INFO(cdev, fmt, ...) \ + do { \ + if (unlikely((cdev)->dp_level <= QED_LEVEL_INFO)) { \ + pr_notice("[%s:%d(%s)]" fmt, \ + __func__, __LINE__, \ + DP_NAME(cdev) ? DP_NAME(cdev) : "", \ + ## __VA_ARGS__); \ + } \ + } while (0) + +#define DP_VERBOSE(cdev, module, fmt, ...) \ + do { \ + if (unlikely(((cdev)->dp_level <= QED_LEVEL_VERBOSE) && \ + ((cdev)->dp_module & module))) { \ + pr_notice("[%s:%d(%s)]" fmt, \ + __func__, __LINE__, \ + DP_NAME(cdev) ? DP_NAME(cdev) : "", \ + ## __VA_ARGS__); \ + } \ + } while (0) + +enum DP_LEVEL { + QED_LEVEL_VERBOSE = 0x0, + QED_LEVEL_INFO = 0x1, + QED_LEVEL_NOTICE = 0x2, + QED_LEVEL_ERR = 0x3, +}; + +#define QED_LOG_LEVEL_SHIFT (30) +#define QED_LOG_VERBOSE_MASK (0x3fffffff) +#define QED_LOG_INFO_MASK (0x40000000) +#define QED_LOG_NOTICE_MASK (0x80000000) + +enum DP_MODULE { + QED_MSG_SPQ = 0x10000, + QED_MSG_STATS = 0x20000, + QED_MSG_DCB = 0x40000, + QED_MSG_IOV = 0x80000, + QED_MSG_SP = 0x100000, + QED_MSG_STORAGE = 0x200000, + QED_MSG_CXT = 0x800000, + QED_MSG_ILT = 0x2000000, + QED_MSG_ROCE = 0x4000000, + QED_MSG_DEBUG = 0x8000000, + /* to be added...up to 0x8000000 */ +}; + +struct qed_eth_stats { + u64 no_buff_discards; + u64 packet_too_big_discard; + u64 ttl0_discard; + u64 rx_ucast_bytes; + u64 rx_mcast_bytes; + u64 rx_bcast_bytes; + u64 rx_ucast_pkts; + u64 rx_mcast_pkts; + u64 rx_bcast_pkts; + u64 mftag_filter_discards; + u64 mac_filter_discards; + u64 tx_ucast_bytes; + u64 tx_mcast_bytes; + u64 tx_bcast_bytes; + u64 tx_ucast_pkts; + u64 tx_mcast_pkts; + u64 tx_bcast_pkts; + u64 tx_err_drop_pkts; + u64 tpa_coalesced_pkts; + u64 tpa_coalesced_events; + u64 tpa_aborts_num; + u64 tpa_not_coalesced_pkts; + u64 tpa_coalesced_bytes; + + /* port */ + u64 rx_64_byte_packets; + u64 rx_127_byte_packets; + u64 rx_255_byte_packets; + u64 rx_511_byte_packets; + u64 rx_1023_byte_packets; + u64 rx_1518_byte_packets; + u64 rx_1522_byte_packets; + u64 rx_2047_byte_packets; + u64 rx_4095_byte_packets; + u64 rx_9216_byte_packets; + u64 rx_16383_byte_packets; + u64 rx_crc_errors; + u64 rx_mac_crtl_frames; + u64 rx_pause_frames; + u64 rx_pfc_frames; + u64 rx_align_errors; + u64 rx_carrier_errors; + u64 rx_oversize_packets; + u64 rx_jabbers; + u64 rx_undersize_packets; + u64 rx_fragments; + u64 tx_64_byte_packets; + u64 tx_65_to_127_byte_packets; + u64 tx_128_to_255_byte_packets; + u64 tx_256_to_511_byte_packets; + u64 tx_512_to_1023_byte_packets; + u64 tx_1024_to_1518_byte_packets; + u64 tx_1519_to_2047_byte_packets; + u64 tx_2048_to_4095_byte_packets; + u64 tx_4096_to_9216_byte_packets; + u64 tx_9217_to_16383_byte_packets; + u64 tx_pause_frames; + u64 tx_pfc_frames; + u64 tx_lpi_entry_count; + u64 tx_total_collisions; + u64 brb_truncates; + u64 brb_discards; + u64 rx_mac_bytes; + u64 rx_mac_uc_packets; + u64 rx_mac_mc_packets; + u64 rx_mac_bc_packets; + u64 rx_mac_frames_ok; + u64 tx_mac_bytes; + u64 tx_mac_uc_packets; + u64 tx_mac_mc_packets; + u64 tx_mac_bc_packets; + u64 tx_mac_ctrl_frames; +}; + +#define QED_SB_IDX 0x0002 + +#define RX_PI 0 +#define TX_PI(tc) (RX_PI + 1 + tc) + +static inline u16 qed_sb_update_sb_idx(struct qed_sb_info *sb_info) +{ + u32 prod = 0; + u16 rc = 0; + + prod = le32_to_cpu(sb_info->sb_virt->prod_index) & + STATUS_BLOCK_PROD_INDEX_MASK; + if (sb_info->sb_ack != prod) { + sb_info->sb_ack = prod; + rc |= QED_SB_IDX; + } + + /* Let SB update */ + mmiowb(); + return rc; +} + +/** + * + * @brief This function creates an update command for interrupts that is + * written to the IGU. + * + * @param sb_info - This is the structure allocated and + * initialized per status block. Assumption is + * that it was initialized using qed_sb_init + * @param int_cmd - Enable/Disable/Nop + * @param upd_flg - whether igu consumer should be + * updated. + * + * @return inline void + */ +static inline void qed_sb_ack(struct qed_sb_info *sb_info, + enum igu_int_cmd int_cmd, + u8 upd_flg) +{ + struct igu_prod_cons_update igu_ack = { 0 }; + + igu_ack.sb_id_and_flags = + ((sb_info->sb_ack << IGU_PROD_CONS_UPDATE_SB_INDEX_SHIFT) | + (upd_flg << IGU_PROD_CONS_UPDATE_UPDATE_FLAG_SHIFT) | + (int_cmd << IGU_PROD_CONS_UPDATE_ENABLE_INT_SHIFT) | + (IGU_SEG_ACCESS_REG << + IGU_PROD_CONS_UPDATE_SEGMENT_ACCESS_SHIFT)); + + DIRECT_REG_WR(sb_info->igu_addr, igu_ack.sb_id_and_flags); + + /* Both segments (interrupts & acks) are written to same place address; + * Need to guarantee all commands will be received (in-order) by HW. + */ + mmiowb(); + barrier(); +} + +static inline void __internal_ram_wr(void *p_hwfn, + void __iomem *addr, + int size, + u32 *data) + +{ + unsigned int i; + + for (i = 0; i < size / sizeof(*data); i++) + DIRECT_REG_WR(&((u32 __iomem *)addr)[i], data[i]); +} + +static inline void internal_ram_wr(void __iomem *addr, + int size, + u32 *data) +{ + __internal_ram_wr(NULL, addr, size, data); +} + +#endif -- cgit v1.2.3