Merge ~paelzer/ubuntu/+source/ipxe:merge-upstream-disco into ubuntu/+source/ipxe:ubuntu/disco-devel

Proposed by Christian Ehrhardt 
Status: Merged
Approved by: Christian Ehrhardt 
Approved revision: 06a0b972d7d3af3990b39c16d73d21b7b8e1d94c
Merge reported by: Christian Ehrhardt 
Merged at revision: 06a0b972d7d3af3990b39c16d73d21b7b8e1d94c
Proposed branch: ~paelzer/ubuntu/+source/ipxe:merge-upstream-disco
Merge into: ubuntu/+source/ipxe:ubuntu/disco-devel
Diff against target: 8144 lines (+5072/-466)
84 files modified
debian/changelog (+37/-0)
debian/patches/series (+0/-1)
dev/null (+0/-27)
src/Makefile.housekeeping (+10/-2)
src/arch/x86/core/dumpregs.c (+1/-1)
src/arch/x86/drivers/net/undinet.c (+29/-10)
src/arch/x86/include/bits/errfile.h (+1/-0)
src/arch/x86/include/ipxe/rtc_entropy.h (+2/-2)
src/arch/x86/include/librm.h (+49/-0)
src/arch/x86/interface/pcbios/acpi_timer.c (+136/-0)
src/arch/x86/interface/pcbios/bios_console.c (+2/-2)
src/arch/x86/interface/pcbios/bios_reboot.c (+1/-1)
src/arch/x86/interface/syslinux/comboot_call.c (+3/-3)
src/arch/x86/transitions/librm.S (+27/-6)
src/arch/x86/transitions/librm_mgmt.c (+91/-1)
src/arch/x86/transitions/librm_test.c (+1/-1)
src/arch/x86_64/Makefile (+4/-0)
src/arch/x86_64/include/bits/hyperv.h (+1/-2)
src/config/config_timer.c (+3/-0)
src/config/crypto.h (+8/-0)
src/core/netbios.c (+60/-0)
src/core/profile.c (+4/-2)
src/crypto/entropy.c (+3/-2)
src/crypto/x509.c (+2/-2)
src/drivers/bitbash/mii_bit.c (+162/-0)
src/drivers/infiniband/CIB_PRM.h (+2/-3)
src/drivers/infiniband/golan.c (+3/-6)
src/drivers/net/efi/nii.c (+163/-0)
src/drivers/net/ena.c (+1/-0)
src/drivers/net/icplus.c (+809/-0)
src/drivers/net/icplus.h (+206/-0)
src/drivers/net/intel.c (+23/-9)
src/drivers/net/intel.h (+9/-0)
src/drivers/net/intelx.c (+2/-0)
src/drivers/net/intelxl.c (+1525/-0)
src/drivers/net/intelxl.h (+790/-0)
src/drivers/net/mii.c (+32/-7)
src/drivers/net/realtek.c (+15/-8)
src/drivers/net/realtek.h (+3/-1)
src/drivers/net/rhine.c (+13/-9)
src/drivers/net/rhine.h (+3/-1)
src/drivers/net/sfc/efx_common.c (+9/-3)
src/drivers/net/sfc/sfc_hunt.c (+2/-0)
src/drivers/net/smscusb.c (+10/-6)
src/drivers/net/smscusb.h (+5/-2)
src/drivers/net/velocity.c (+16/-11)
src/drivers/net/velocity.h (+3/-1)
src/drivers/net/virtio-net.c (+1/-0)
src/drivers/usb/xhci.c (+34/-27)
src/include/ipxe/acpi.h (+7/-0)
src/include/ipxe/efi/efi_entropy.h (+2/-2)
src/include/ipxe/entropy.h (+23/-3)
src/include/ipxe/errfile.h (+2/-0)
src/include/ipxe/eth_slow.h (+6/-0)
src/include/ipxe/linux/linux_entropy.h (+2/-2)
src/include/ipxe/list.h (+22/-0)
src/include/ipxe/mii.h (+52/-19)
src/include/ipxe/mii_bit.h (+55/-0)
src/include/ipxe/netbios.h (+30/-0)
src/include/ipxe/null_entropy.h (+2/-2)
src/include/ipxe/ocsp.h (+27/-0)
src/include/ipxe/process.h (+7/-2)
src/include/ipxe/tcp.h (+1/-1)
src/include/ipxe/tls.h (+2/-2)
src/interface/efi/efi_block.c (+4/-0)
src/interface/efi/efi_driver.c (+12/-0)
src/interface/efi/efi_entropy.c (+6/-0)
src/interface/efi/efi_snp.c (+94/-13)
src/interface/efi/efi_timer.c (+35/-6)
src/interface/efi/efi_usb.c (+43/-52)
src/interface/hyperv/vmbus.c (+2/-8)
src/net/eth_slow.c (+23/-1)
src/net/ethernet.c (+1/-0)
src/net/rndis.c (+61/-41)
src/net/tcp/httpconn.c (+7/-2)
src/net/tcp/httpcore.c (+12/-0)
src/net/tcp/httpntlm.c (+22/-3)
src/net/tcp/iscsi.c (+6/-1)
src/net/tls.c (+133/-124)
src/net/udp/tftp.c (+2/-0)
src/net/validator.c (+1/-2)
src/tests/list_test.c (+21/-0)
src/util/elf2efi.c (+2/-0)
src/util/niclist.pl (+29/-21)
Reviewer Review Type Date Requested Status
Andreas Hasenack Approve
Canonical Server Pending
git-ubuntu developers Pending
Review via email: mp+361624@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Christian Ehrhardt  (paelzer) wrote :

Hi,
Heads up - this is a merge which is none - therefore the MP might look odd.

We are already ahead of Debian, this puts us ahead even more.
Therefore this MP has:
- no old/new Debian
- plenty of changes ouside of debian/*
- you need the tarball from the PPA

PPA: https://launchpad.net/~ci-train-ppa-service/+archive/ubuntu/3566/+packages

It has no own tests and no reasonable depending dep8 tests.
But I'll push it through the automated virt stack testing before an upload - so consider that done.

Revision history for this message
Christian Ehrhardt  (paelzer) wrote :

FYI I realized my deadlines is rather short since this is one of the first I'd want/need to upload.
Therefore a review today would be great.

Revision history for this message
Andreas Hasenack (ahasenack) wrote :

There is only one change in debian/, which is a delta drop, that was easy to check. Regarding the source code changes, well, it's a new upstream version, just like any other package. It's ok too, tests will tell.

I'm checking d/changelog, since that has to be manually reconstructed. A couple of comments inline about that, easy to fix if I'm correct, so preemptive +1.

review: Approve
Revision history for this message
Christian Ehrhardt  (paelzer) wrote :

Thanks Andreas.
Catch one is right - I added the line
Catch two was intentional - the rom size change that I added is now logically part of the general "add checks on rom size changes"

Adapting and tag+upload

Revision history for this message
Christian Ehrhardt  (paelzer) wrote :

Building, I'm tracking migration - thakns

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/.travis.yml b/.travis.yml
2deleted file mode 100644
3index 0e75158..0000000
4--- a/.travis.yml
5+++ /dev/null
6@@ -1,54 +0,0 @@
7-dist: trusty
8-
9-sudo: false
10-
11-language: c
12-
13-cache: ccache
14-
15-compiler:
16- - gcc
17-
18-addons:
19- apt:
20- packages:
21- - binutils-dev
22- - liblzma-dev
23- - syslinux
24- - genisoimage
25- coverity_scan:
26- project:
27- name: "ipxe/ipxe"
28- version: $TRAVIS_COMMIT
29- build_command_prepend: "make -C src bin/deps"
30- build_command: "make -C src bin/blib.a"
31- branch_pattern: coverity_scan
32-
33-env:
34- global:
35- - MAKEFLAGS="-j 4"
36-
37-script:
38- - make -C src bin/blib.a
39- - make -C src bin/ipxe.pxe
40- - make -C src bin/ipxe.usb
41- - make -C src bin/ipxe.iso
42- - make -C src bin/8086100e.mrom
43- - make -C src bin-x86_64-pcbios/blib.a
44- - make -C src bin-x86_64-pcbios/ipxe.pxe
45- - make -C src bin-x86_64-pcbios/ipxe.usb
46- - make -C src bin-x86_64-pcbios/ipxe.iso
47- - make -C src bin-x86_64-pcbios/8086100e.mrom
48- - make -C src bin-x86_64-efi/blib.a
49- - make -C src bin-x86_64-efi/ipxe.efi
50- - make -C src bin-x86_64-efi/intel.efidrv
51- - make -C src bin-x86_64-efi/intel.efirom
52- - make -C src bin-i386-efi/blib.a
53- - make -C src bin-i386-efi/ipxe.efi
54- - make -C src bin-i386-efi/intel.efidrv
55- - make -C src bin-i386-efi/intel.efirom
56- - make -C src bin-x86_64-linux/blib.a
57- - make -C src bin-x86_64-linux/tap.linux
58- - make -C src bin-x86_64-linux/af_packet.linux
59- - make -C src bin-x86_64-linux/tests.linux
60- - ./src/bin-x86_64-linux/tests.linux
61diff --git a/debian/changelog b/debian/changelog
62index 724c673..fd4106b 100644
63--- a/debian/changelog
64+++ b/debian/changelog
65@@ -1,3 +1,40 @@
66+ipxe (1.0.0+git-20190109.133f4c4-0ubuntu1) disco; urgency=medium
67+
68+ * Merge new upstream release 1.0.0+git-20190109.133f4c4
69+ Remaining Changes:
70+ - d/p/enable-https.patch: Enable HTTPS support.
71+ - Split grub integration from ipxe->grub-ipxe.
72+ - d/control: add package and adapt dependencies
73+ - d/[grub-]ipxe.install: move some files to grub-ipxe
74+ - rename d/ipxe.post* to d/grub-ipxe-post*
75+ - Install ne.rom as pxe-ne2k_isa.rom
76+ - d/ipxe-qemu.install: Install ne.rom as pxe-ne2k_isa.rom.
77+ - d/ipxe-qemu.links: compat link for ne.rom
78+ - d/ipxe-qemu.links: Add compat links from /usr/share/qemu
79+ to /usr/lib/ipxe/qemu.
80+ - d/util/check-rom-sizes, d/rules: check sizes of generated roms to avoid
81+ accidentially breaking KVM live migration on updates/fixes.
82+ - handling of efi rom size changes in Bionic (LP 1713490)
83+ - d/util/check-rom-sizes: bump efi rom sizes
84+ - d/control: break older qemu versions to ensure the new sized roms
85+ - debian/patches/handle-dhcp-nack.patch: Handle DHCP NAK and send a
86+ re-discover. (LP 1707999)
87+ - updated debian/patches/util-elf2efi-GNU_SOURCE.patch to match latest
88+ upstream.
89+ - add new rom for vmxnet3 (LP 1737211)
90+ - d/ipxe-qemu.install: install new rom
91+ are only associated with new qemu versions.
92+ - Build ROMs for QEMU with CONFIG=qemu (LP: 1789319)
93+ - d/p/0005-strip-802.1Q-VLAN-0-priority-tags.patch: Strip 802.1Q VLAN 0
94+ priority tags; Fixes PXE when VLAN tag is 0. (LP: 1805920)
95+ - debian/copyright: update copyright information to satisfy lintian
96+ dep5 checks (LP: 1747071)
97+ * Dropped changes (upstream):
98+ - debian/patches/fix-elf2efi-plt-relocation.diff: Cherry-pick fix from
99+ ipxe devel mailing list to handle R_X86_64_PLT32 relocations.
100+
101+ -- Christian Ehrhardt <christian.ehrhardt@canonical.com> Wed, 09 Jan 2019 11:09:29 +0100
102+
103 ipxe (1.0.0+git-20180124.fbe8c52d-0ubuntu5) disco; urgency=medium
104
105 * d/p/0005-strip-802.1Q-VLAN-0-priority-tags.patch: Strip 802.1Q VLAN 0
106diff --git a/debian/patches/fix-elf2efi-plt-relocation.diff b/debian/patches/fix-elf2efi-plt-relocation.diff
107deleted file mode 100644
108index 6ff9351..0000000
109--- a/debian/patches/fix-elf2efi-plt-relocation.diff
110+++ /dev/null
111@@ -1,27 +0,0 @@
112-Description: Fix elf2efi to recognize R_X86_64_PLT32 relocation type
113- Recent changes in GNU build tools causes a build failure with ipxe.efi
114- during the elf2efi64 conversion:
115- .
116- ./util/elf2efi64 --subsystem=10 bin-x86_64-efi/ipxe.efi.tmp bin-x86_64-efi/ipxe.efi
117- Unrecognised relocation type 4
118- make: *** [Makefile.efi:26: bin-x86_64-efi/ipxe.efi] Error 1
119- .
120- The relocation type 4 is defined in elf.h as R_X86_64_PLT32 and is now
121- being used by the GNU linker. This is currently not supported by the
122- elf2efi.c source found in ipxe.
123- .
124- This error is resolved by adding R_X86_64_PLT32 to the list of
125- recognized relocation headers types for elf2efi.
126-Author: John Jolly <***@suse.com>
127-Origin: vendor, http://ipxe-devel.ipxe.narkive.com/XVJMK4BP/fix-elf2efi-to-recognize-r-x86-64-plt32-relocation-type
128-
129---- a/src/util/elf2efi.c
130-+++ b/src/util/elf2efi.c
131-@@ -635,6 +635,7 @@ static void process_reloc ( struct elf_f
132- case ELF_MREL ( EM_ARM, R_ARM_THM_JUMP24 ) :
133- case ELF_MREL ( EM_ARM, R_ARM_V4BX ):
134- case ELF_MREL ( EM_X86_64, R_X86_64_PC32 ) :
135-+ case ELF_MREL ( EM_X86_64, R_X86_64_PLT32 ) :
136- case ELF_MREL ( EM_AARCH64, R_AARCH64_CALL26 ) :
137- case ELF_MREL ( EM_AARCH64, R_AARCH64_JUMP26 ) :
138- case ELF_MREL ( EM_AARCH64, R_AARCH64_ADR_PREL_LO21 ) :
139diff --git a/debian/patches/series b/debian/patches/series
140index db818d1..c66db88 100644
141--- a/debian/patches/series
142+++ b/debian/patches/series
143@@ -2,5 +2,4 @@
144 util-elf2efi-GNU_SOURCE.patch
145 enable-https.patch
146 handle-dhcp-nack.patch
147-fix-elf2efi-plt-relocation.diff
148 0005-strip-802.1Q-VLAN-0-priority-tags.patch
149diff --git a/src/Makefile.housekeeping b/src/Makefile.housekeeping
150index 00b0792..f833492 100644
151--- a/src/Makefile.housekeeping
152+++ b/src/Makefile.housekeeping
153@@ -174,9 +174,17 @@ endif
154 # Inhibit this.
155 #
156 ifeq ($(CCTYPE),gcc)
157-WNA_TEST = $(CC) -Wno-address -x c -c /dev/null -o /dev/null >/dev/null 2>&1
158+WNA_TEST = $(CC) -Waddress -x c -c /dev/null -o /dev/null >/dev/null 2>&1
159 WNA_FLAGS := $(shell $(WNA_TEST) && $(ECHO) '-Wno-address')
160 WORKAROUND_CFLAGS += $(WNA_FLAGS)
161+
162+# gcc 8.0 generates warnings for certain suspect string operations. Our
163+# sources have been vetted for correct usage. Turn off these warnings.
164+#
165+WNST_TEST = $(CC) -Wstringop-truncation -x c -c /dev/null -o /dev/null \
166+ >/dev/null 2>&1
167+WNST_FLAGS := $(shell $(WNST_TEST) && $(ECHO) '-Wno-stringop-truncation')
168+WORKAROUND_CFLAGS += $(WNST_FLAGS)
169 endif
170
171 # Some versions of gas choke on division operators, treating them as
172@@ -437,7 +445,7 @@ endif
173 CFLAGS += $(WORKAROUND_CFLAGS) $(EXTRA_CFLAGS)
174 ASFLAGS += $(WORKAROUND_ASFLAGS) $(EXTRA_ASFLAGS)
175 LDFLAGS += $(WORKAROUND_LDFLAGS) $(EXTRA_LDFLAGS)
176-HOST_CFLAGS += -O2 -g
177+HOST_CFLAGS += $(WORKAROUND_CFLAGS) -O2 -g
178
179 # Inhibit -Werror if NO_WERROR is specified on make command line
180 #
181diff --git a/src/arch/x86/core/dumpregs.c b/src/arch/x86/core/dumpregs.c
182index 37d62a7..a5108ea 100644
183--- a/src/arch/x86/core/dumpregs.c
184+++ b/src/arch/x86/core/dumpregs.c
185@@ -7,7 +7,7 @@ void __asmcall _dump_regs ( struct i386_all_regs *ix86 ) {
186 TEXT16_CODE ( ".globl dump_regs\n\t"
187 "\ndump_regs:\n\t"
188 VIRT_CALL ( _dump_regs )
189- "ret\n\t" ) );
190+ "ret\n\t" ) : );
191
192 printf ( "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n"
193 "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n"
194diff --git a/src/arch/x86/drivers/net/undinet.c b/src/arch/x86/drivers/net/undinet.c
195index 7819118..9b7d6d8 100644
196--- a/src/arch/x86/drivers/net/undinet.c
197+++ b/src/arch/x86/drivers/net/undinet.c
198@@ -33,6 +33,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
199 #include <ipxe/netdevice.h>
200 #include <ipxe/if_ether.h>
201 #include <ipxe/ethernet.h>
202+#include <ipxe/pci.h>
203 #include <ipxe/profile.h>
204 #include <undi.h>
205 #include <undinet.h>
206@@ -807,6 +808,10 @@ struct undinet_irq_broken {
207 uint16_t pci_vendor;
208 /** PCI device ID */
209 uint16_t pci_device;
210+ /** PCI subsystem vendor ID */
211+ uint16_t pci_subsys_vendor;
212+ /** PCI subsystem ID */
213+ uint16_t pci_subsys;
214 };
215
216 /**
217@@ -822,10 +827,10 @@ struct undinet_irq_broken {
218 */
219 static const struct undinet_irq_broken undinet_irq_broken_list[] = {
220 /* HP XX70x laptops */
221- { .pci_vendor = 0x8086, .pci_device = 0x1502 },
222- { .pci_vendor = 0x8086, .pci_device = 0x1503 },
223+ { 0x8086, 0x1502, PCI_ANY_ID, PCI_ANY_ID },
224+ { 0x8086, 0x1503, PCI_ANY_ID, PCI_ANY_ID },
225 /* HP 745 G3 laptop */
226- { .pci_vendor = 0x14e4, .pci_device = 0x1687 },
227+ { 0x14e4, 0x1687, PCI_ANY_ID, PCI_ANY_ID },
228 };
229
230 /**
231@@ -836,14 +841,30 @@ static const struct undinet_irq_broken undinet_irq_broken_list[] = {
232 */
233 static int undinet_irq_is_broken ( struct device_description *desc ) {
234 const struct undinet_irq_broken *broken;
235+ struct pci_device pci;
236+ uint16_t subsys_vendor;
237+ uint16_t subsys;
238 unsigned int i;
239
240+ /* Ignore non-PCI devices */
241+ if ( desc->bus_type != BUS_TYPE_PCI )
242+ return 0;
243+
244+ /* Read subsystem IDs */
245+ pci_init ( &pci, desc->location );
246+ pci_read_config_word ( &pci, PCI_SUBSYSTEM_VENDOR_ID, &subsys_vendor );
247+ pci_read_config_word ( &pci, PCI_SUBSYSTEM_ID, &subsys );
248+
249+ /* Check for a match against the broken device list */
250 for ( i = 0 ; i < ( sizeof ( undinet_irq_broken_list ) /
251 sizeof ( undinet_irq_broken_list[0] ) ) ; i++ ) {
252 broken = &undinet_irq_broken_list[i];
253- if ( ( desc->bus_type == BUS_TYPE_PCI ) &&
254- ( desc->vendor == broken->pci_vendor ) &&
255- ( desc->device == broken->pci_device ) ) {
256+ if ( ( broken->pci_vendor == desc->vendor ) &&
257+ ( broken->pci_device == desc->device ) &&
258+ ( ( broken->pci_subsys_vendor == subsys_vendor ) ||
259+ ( broken->pci_subsys_vendor == PCI_ANY_ID ) ) &&
260+ ( ( broken->pci_subsys == subsys ) ||
261+ ( broken->pci_subsys == PCI_ANY_ID ) ) ) {
262 return 1;
263 }
264 }
265@@ -938,10 +959,9 @@ int undinet_probe ( struct undi_device *undi, struct device *dev ) {
266 memcpy ( netdev->ll_addr, undi_info.CurrentNodeAddress, ETH_ALEN );
267 undinic->irq = undi_info.IntNumber;
268 if ( undinic->irq > IRQ_MAX ) {
269- DBGC ( undinic, "UNDINIC %p has invalid IRQ %d\n",
270+ DBGC ( undinic, "UNDINIC %p ignoring invalid IRQ %d\n",
271 undinic, undinic->irq );
272- rc = -EINVAL;
273- goto err_bad_irq;
274+ undinic->irq = 0;
275 }
276 DBGC ( undinic, "UNDINIC %p has MAC address %s and IRQ %d\n",
277 undinic, eth_ntoa ( netdev->hw_addr ), undinic->irq );
278@@ -984,7 +1004,6 @@ int undinet_probe ( struct undi_device *undi, struct device *dev ) {
279
280 err_register:
281 err_undi_get_iface_info:
282- err_bad_irq:
283 err_undi_get_information:
284 err_undi_initialize:
285 /* Shut down UNDI stack */
286diff --git a/src/arch/x86/include/bits/errfile.h b/src/arch/x86/include/bits/errfile.h
287index 9d1fed7..b0ae1ab 100644
288--- a/src/arch/x86/include/bits/errfile.h
289+++ b/src/arch/x86/include/bits/errfile.h
290@@ -27,6 +27,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
291 #define ERRFILE_acpipwr ( ERRFILE_ARCH | ERRFILE_CORE | 0x00100000 )
292 #define ERRFILE_cpuid ( ERRFILE_ARCH | ERRFILE_CORE | 0x00110000 )
293 #define ERRFILE_rdtsc_timer ( ERRFILE_ARCH | ERRFILE_CORE | 0x00120000 )
294+#define ERRFILE_acpi_timer ( ERRFILE_ARCH | ERRFILE_CORE | 0x00130000 )
295
296 #define ERRFILE_bootsector ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00000000 )
297 #define ERRFILE_bzimage ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00010000 )
298diff --git a/src/arch/x86/include/ipxe/rtc_entropy.h b/src/arch/x86/include/ipxe/rtc_entropy.h
299index e214745..581abcd 100644
300--- a/src/arch/x86/include/ipxe/rtc_entropy.h
301+++ b/src/arch/x86/include/ipxe/rtc_entropy.h
302@@ -22,7 +22,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
303 *
304 * @ret min_entropy min-entropy of each sample
305 */
306-static inline __always_inline double
307+static inline __always_inline min_entropy_t
308 ENTROPY_INLINE ( rtc, min_entropy_per_sample ) ( void ) {
309
310 /* The min-entropy has been measured on several platforms
311@@ -38,7 +38,7 @@ ENTROPY_INLINE ( rtc, min_entropy_per_sample ) ( void ) {
312 * safety margin to allow for some potential non-independence
313 * of samples.
314 */
315- return 1.3;
316+ return MIN_ENTROPY ( 1.3 );
317 }
318
319 extern uint8_t rtc_sample ( void );
320diff --git a/src/arch/x86/include/librm.h b/src/arch/x86/include/librm.h
321index 311748b..5196d39 100644
322--- a/src/arch/x86/include/librm.h
323+++ b/src/arch/x86/include/librm.h
324@@ -254,9 +254,13 @@ extern void remove_user_from_rm_stack ( userptr_t data, size_t size );
325 #define CODE_DEFAULT ".code32"
326 #endif
327
328+/* LINE_SYMBOL: declare a symbol for the current source code line */
329+#define LINE_SYMBOL _S2 ( OBJECT ) "__line_" _S2 ( __LINE__ ) "__%=:"
330+
331 /* TEXT16_CODE: declare a fragment of code that resides in .text16 */
332 #define TEXT16_CODE( asm_code_str ) \
333 ".section \".text16\", \"ax\", @progbits\n\t" \
334+ "\n" LINE_SYMBOL "\n\t" \
335 ".code16\n\t" \
336 asm_code_str "\n\t" \
337 CODE_DEFAULT "\n\t" \
338@@ -276,6 +280,7 @@ extern void remove_user_from_rm_stack ( userptr_t data, size_t size );
339 "push $1f\n\t" \
340 "call phys_call\n\t" \
341 ".section \".text.phys\", \"ax\", @progbits\n\t"\
342+ "\n" LINE_SYMBOL "\n\t" \
343 ".code32\n\t" \
344 "\n1:\n\t" \
345 asm_code_str \
346@@ -376,6 +381,50 @@ struct interrupt_vector {
347 /** "jmp" instruction */
348 #define JMP_INSN 0xe9
349
350+/** 32-bit interrupt wrapper stack frame */
351+struct interrupt_frame32 {
352+ uint32_t esp;
353+ uint32_t ss;
354+ uint32_t gs;
355+ uint32_t fs;
356+ uint32_t es;
357+ uint32_t ds;
358+ uint32_t ebp;
359+ uint32_t edi;
360+ uint32_t esi;
361+ uint32_t edx;
362+ uint32_t ecx;
363+ uint32_t ebx;
364+ uint32_t eax;
365+ uint32_t eip;
366+ uint32_t cs;
367+ uint32_t eflags;
368+} __attribute__ (( packed ));
369+
370+/** 64-bit interrupt wrapper stack frame */
371+struct interrupt_frame64 {
372+ uint64_t r15;
373+ uint64_t r14;
374+ uint64_t r13;
375+ uint64_t r12;
376+ uint64_t r11;
377+ uint64_t r10;
378+ uint64_t r9;
379+ uint64_t r8;
380+ uint64_t rbp;
381+ uint64_t rdi;
382+ uint64_t rsi;
383+ uint64_t rdx;
384+ uint64_t rcx;
385+ uint64_t rbx;
386+ uint64_t rax;
387+ uint64_t rip;
388+ uint64_t cs;
389+ uint64_t rflags;
390+ uint64_t rsp;
391+ uint64_t ss;
392+} __attribute__ (( packed ));
393+
394 extern void set_interrupt_vector ( unsigned int intr, void *vector );
395
396 /** A page table */
397diff --git a/src/arch/x86/interface/pcbios/acpi_timer.c b/src/arch/x86/interface/pcbios/acpi_timer.c
398new file mode 100644
399index 0000000..82e85a0
400--- /dev/null
401+++ b/src/arch/x86/interface/pcbios/acpi_timer.c
402@@ -0,0 +1,136 @@
403+/*
404+ * Copyright (C) 2018 Michael Brown <mbrown@fensystems.co.uk>.
405+ *
406+ * This program is free software; you can redistribute it and/or
407+ * modify it under the terms of the GNU General Public License as
408+ * published by the Free Software Foundation; either version 2 of the
409+ * License, or any later version.
410+ *
411+ * This program is distributed in the hope that it will be useful, but
412+ * WITHOUT ANY WARRANTY; without even the implied warranty of
413+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
414+ * General Public License for more details.
415+ *
416+ * You should have received a copy of the GNU General Public License
417+ * along with this program; if not, write to the Free Software
418+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
419+ * 02110-1301, USA.
420+ *
421+ * You can also choose to distribute this program under the terms of
422+ * the Unmodified Binary Distribution Licence (as given in the file
423+ * COPYING.UBDL), provided that you have satisfied its requirements.
424+ */
425+
426+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
427+
428+#include <unistd.h>
429+#include <errno.h>
430+#include <assert.h>
431+#include <byteswap.h>
432+#include <ipxe/io.h>
433+#include <ipxe/acpi.h>
434+
435+/** @file
436+ *
437+ * ACPI power management timer
438+ *
439+ */
440+
441+/** ACPI timer frequency (fixed 3.579545MHz) */
442+#define ACPI_TIMER_HZ 3579545
443+
444+/** ACPI timer mask
445+ *
446+ * Timers may be implemented as either 24-bit or 32-bit counters. We
447+ * simplify the code by pessimistically assuming that the timer has
448+ * only 24 bits.
449+ */
450+#define ACPI_TIMER_MASK 0x00ffffffUL
451+
452+/** Power management timer register address */
453+static unsigned int pm_tmr;
454+
455+struct timer acpi_timer __timer ( TIMER_PREFERRED );
456+
457+/**
458+ * Get current system time in ticks
459+ *
460+ * @ret ticks Current time, in ticks
461+ */
462+static unsigned long acpi_currticks ( void ) {
463+ static unsigned long offset;
464+ static uint32_t prev;
465+ uint32_t now;
466+
467+ /* Read timer and account for wraparound */
468+ now = ( inl ( pm_tmr ) & ACPI_TIMER_MASK );
469+ if ( now < prev ) {
470+ offset += ( ( ACPI_TIMER_MASK + 1 ) /
471+ ( ACPI_TIMER_HZ / TICKS_PER_SEC ) );
472+ }
473+ prev = now;
474+
475+ /* Convert to timer ticks */
476+ return ( offset + ( now / ( ACPI_TIMER_HZ / TICKS_PER_SEC ) ) );
477+}
478+
479+/**
480+ * Delay for a fixed number of microseconds
481+ *
482+ * @v usecs Number of microseconds for which to delay
483+ */
484+static void acpi_udelay ( unsigned long usecs ) {
485+ uint32_t start;
486+ uint32_t elapsed;
487+ uint32_t threshold;
488+
489+ /* Delay until a suitable number of ticks have elapsed. We do
490+ * not need to allow for multiple wraparound, since the
491+ * wraparound period for a 24-bit timer at 3.579545MHz is
492+ * around 4700000us.
493+ */
494+ start = inl ( pm_tmr );
495+ threshold = ( ( usecs * ACPI_TIMER_HZ ) / 1000000 );
496+ do {
497+ elapsed = ( ( inl ( pm_tmr ) - start ) & ACPI_TIMER_MASK );
498+ } while ( elapsed < threshold );
499+}
500+
501+/**
502+ * Probe ACPI power management timer
503+ *
504+ * @ret rc Return status code
505+ */
506+static int acpi_timer_probe ( void ) {
507+ struct acpi_fadt fadtab;
508+ userptr_t fadt;
509+ unsigned int pm_tmr_blk;
510+
511+ /* Locate FADT */
512+ fadt = acpi_find ( FADT_SIGNATURE, 0 );
513+ if ( ! fadt ) {
514+ DBGC ( &acpi_timer, "ACPI could not find FADT\n" );
515+ return -ENOENT;
516+ }
517+
518+ /* Read FADT */
519+ copy_from_user ( &fadtab, fadt, 0, sizeof ( fadtab ) );
520+ pm_tmr_blk = le32_to_cpu ( fadtab.pm_tmr_blk );
521+ if ( ! pm_tmr_blk ) {
522+ DBGC ( &acpi_timer, "ACPI has no timer\n" );
523+ return -ENOENT;
524+ }
525+
526+ /* Record power management timer register address */
527+ pm_tmr = ( pm_tmr_blk + ACPI_PM_TMR );
528+
529+ return 0;
530+}
531+
532+/** ACPI timer */
533+struct timer acpi_timer __timer ( TIMER_PREFERRED ) = {
534+ .name = "acpi",
535+ .probe = acpi_timer_probe,
536+ .currticks = acpi_currticks,
537+ .udelay = acpi_udelay,
538+};
539diff --git a/src/arch/x86/interface/pcbios/bios_console.c b/src/arch/x86/interface/pcbios/bios_console.c
540index 81e3a7d..08fa6d0 100644
541--- a/src/arch/x86/interface/pcbios/bios_console.c
542+++ b/src/arch/x86/interface/pcbios/bios_console.c
543@@ -521,12 +521,12 @@ static void bios_inject_startup ( void ) {
544 __asm__ __volatile__ (
545 TEXT16_CODE ( "\nint16_wrapper:\n\t"
546 "pushfw\n\t"
547- "cmpb $0, %cs:bios_inject_lock\n\t"
548+ "cmpb $0, %%cs:bios_inject_lock\n\t"
549 "jnz 1f\n\t"
550 VIRT_CALL ( bios_inject )
551 "\n1:\n\t"
552 "popfw\n\t"
553- "ljmp *%cs:int16_vector\n\t" ) );
554+ "ljmp *%%cs:int16_vector\n\t" ) : );
555
556 /* Hook INT 16 */
557 hook_bios_interrupt ( 0x16, ( ( intptr_t ) int16_wrapper ),
558diff --git a/src/arch/x86/interface/pcbios/bios_reboot.c b/src/arch/x86/interface/pcbios/bios_reboot.c
559index c6c5a5a..071173f 100644
560--- a/src/arch/x86/interface/pcbios/bios_reboot.c
561+++ b/src/arch/x86/interface/pcbios/bios_reboot.c
562@@ -48,7 +48,7 @@ static void bios_reboot ( int warm ) {
563 put_real ( flag, BDA_SEG, BDA_REBOOT );
564
565 /* Jump to system reset vector */
566- __asm__ __volatile__ ( REAL_CODE ( "ljmp $0xf000, $0xfff0" ) );
567+ __asm__ __volatile__ ( REAL_CODE ( "ljmp $0xf000, $0xfff0" ) : );
568 }
569
570 /**
571diff --git a/src/arch/x86/interface/syslinux/comboot_call.c b/src/arch/x86/interface/syslinux/comboot_call.c
572index 2f5c252..e70f200 100644
573--- a/src/arch/x86/interface/syslinux/comboot_call.c
574+++ b/src/arch/x86/interface/syslinux/comboot_call.c
575@@ -663,7 +663,7 @@ void hook_comboot_interrupts ( ) {
576 VIRT_CALL ( int20 )
577 "clc\n\t"
578 "call patch_cf\n\t"
579- "iret\n\t" ) );
580+ "iret\n\t" ) : );
581
582 hook_bios_interrupt ( 0x20, ( intptr_t ) int20_wrapper, &int20_vector );
583
584@@ -672,7 +672,7 @@ void hook_comboot_interrupts ( ) {
585 VIRT_CALL ( int21 )
586 "clc\n\t"
587 "call patch_cf\n\t"
588- "iret\n\t" ) );
589+ "iret\n\t" ) : );
590
591 hook_bios_interrupt ( 0x21, ( intptr_t ) int21_wrapper, &int21_vector );
592
593@@ -681,7 +681,7 @@ void hook_comboot_interrupts ( ) {
594 VIRT_CALL ( int22 )
595 "clc\n\t"
596 "call patch_cf\n\t"
597- "iret\n\t" ) );
598+ "iret\n\t" ) : );
599
600 hook_bios_interrupt ( 0x22, ( intptr_t ) int22_wrapper, &int22_vector );
601 }
602diff --git a/src/arch/x86/transitions/librm.S b/src/arch/x86/transitions/librm.S
603index c31daad..9d3eff9 100644
604--- a/src/arch/x86/transitions/librm.S
605+++ b/src/arch/x86/transitions/librm.S
606@@ -1363,20 +1363,19 @@ flatten_dummy:
607 .code32
608 .globl interrupt_wrapper
609 interrupt_wrapper:
610- /* Preserve registers (excluding already-saved %eax and
611- * otherwise unused registers which are callee-save for both
612- * 32-bit and 64-bit ABIs).
613- */
614+ /* Preserve registers (excluding already-saved %eax) */
615 pushl %ebx
616 pushl %ecx
617 pushl %edx
618 pushl %esi
619 pushl %edi
620+ pushl %ebp
621
622 /* Expand IRQ number to whole %eax register */
623 movzbl %al, %eax
624
625 .if64 ; /* Skip transition to long mode, if applicable */
626+ xorl %edx, %edx
627 movw %cs, %bx
628 cmpw $LONG_CS, %bx
629 je 1f
630@@ -1391,24 +1390,45 @@ interrupt_wrapper:
631
632 /* Switch to virtual addressing */
633 call intr_to_prot
634+
635+ /* Pass 32-bit interrupt frame pointer in %edx */
636+ movl %esp, %edx
637+ xorl %ecx, %ecx
638 .if64
639 /* Switch to long mode */
640 call prot_to_long
641 .code64
642
643-1: /* Preserve long-mode caller-save registers */
644+1: /* Preserve long-mode registers */
645 pushq %r8
646 pushq %r9
647 pushq %r10
648 pushq %r11
649+ pushq %r12
650+ pushq %r13
651+ pushq %r14
652+ pushq %r15
653
654 /* Expand IRQ number to whole %rdi register */
655 movl %eax, %edi
656+
657+ /* Pass 32-bit interrupt frame pointer (if applicable) in %rsi */
658+ testl %edx, %edx
659+ je 1f
660+ movl %edx, %esi
661+ addl virt_offset, %esi
662+1:
663+ /* Pass 64-bit interrupt frame pointer in %rdx */
664+ movq %rsp, %rdx
665 .endif
666 /* Call interrupt handler */
667 call interrupt
668 .if64
669- /* Restore long-mode caller-save registers */
670+ /* Restore long-mode registers */
671+ popq %r15
672+ popq %r14
673+ popq %r13
674+ popq %r12
675 popq %r11
676 popq %r10
677 popq %r9
678@@ -1432,6 +1452,7 @@ interrupt_wrapper:
679 popl %ds
680
681 1: /* Restore registers */
682+ popl %ebp
683 popl %edi
684 popl %esi
685 popl %edx
686diff --git a/src/arch/x86/transitions/librm_mgmt.c b/src/arch/x86/transitions/librm_mgmt.c
687index 8144e76..f9e1d26 100644
688--- a/src/arch/x86/transitions/librm_mgmt.c
689+++ b/src/arch/x86/transitions/librm_mgmt.c
690@@ -13,6 +13,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
691 #include <ipxe/profile.h>
692 #include <realmode.h>
693 #include <pic8259.h>
694+#include <ipxe/shell.h>
695
696 /*
697 * This file provides functions for managing librm.
698@@ -43,6 +44,9 @@ struct idtr64 idtr64 = {
699 .limit = ( sizeof ( idt64 ) - 1 ),
700 };
701
702+/** Length of stack dump */
703+#define STACK_DUMP_LEN 128
704+
705 /** Timer interrupt profiler */
706 static struct profiler timer_irq_profiler __profiler = { .name = "irq.timer" };
707
708@@ -160,14 +164,100 @@ static struct profiler * interrupt_profiler ( int intr ) {
709 }
710
711 /**
712+ * Display interrupt stack dump (for debugging)
713+ *
714+ * @v intr Interrupt number
715+ * @v frame32 32-bit interrupt wrapper stack frame (or NULL)
716+ * @v frame64 64-bit interrupt wrapper stack frame (or NULL)
717+ */
718+static __attribute__ (( unused )) void
719+interrupt_dump ( int intr, struct interrupt_frame32 *frame32,
720+ struct interrupt_frame64 *frame64 ) {
721+ unsigned long sp;
722+ void *stack;
723+
724+ /* Do nothing unless debugging is enabled */
725+ if ( ! DBG_LOG )
726+ return;
727+
728+ /* Print register dump */
729+ if ( ( sizeof ( physaddr_t ) <= sizeof ( uint32_t ) ) || frame32 ) {
730+ sp = ( frame32->esp + sizeof ( *frame32 ) -
731+ offsetof ( typeof ( *frame32 ), esp ) );
732+ DBGC ( &intr, "INT%d at %04x:%08x (stack %04x:%08lx):\n",
733+ intr, frame32->cs, frame32->eip, frame32->ss, sp );
734+ DBGC ( &intr, "cs = %04x ds = %04x es = %04x fs = %04x "
735+ "gs = %04x ss = %04x\n", frame32->cs, frame32->ds,
736+ frame32->es, frame32->fs, frame32->gs, frame32->ss );
737+ DBGC ( &intr, "eax = %08x ebx = %08x ecx = %08x "
738+ "edx = %08x flg = %08x\n", frame32->eax, frame32->ebx,
739+ frame32->ecx, frame32->edx, frame32->eflags );
740+ DBGC ( &intr, "esi = %08x edi = %08x ebp = %08x "
741+ "esp = %08lx eip = %08x\n", frame32->esi, frame32->edi,
742+ frame32->ebp, sp, frame32->eip );
743+ stack = ( ( ( void * ) frame32 ) + sizeof ( *frame32 ) );
744+ } else {
745+ DBGC ( &intr, "INT%d at %04llx:%016llx (stack "
746+ "%04llx:%016llx):\n", intr,
747+ ( ( unsigned long long ) frame64->cs ),
748+ ( ( unsigned long long ) frame64->rip ),
749+ ( ( unsigned long long ) frame64->ss ),
750+ ( ( unsigned long long ) frame64->rsp ) );
751+ DBGC ( &intr, "rax = %016llx rbx = %016llx rcx = %016llx\n",
752+ ( ( unsigned long long ) frame64->rax ),
753+ ( ( unsigned long long ) frame64->rbx ),
754+ ( ( unsigned long long ) frame64->rcx ) );
755+ DBGC ( &intr, "rdx = %016llx rsi = %016llx rdi = %016llx\n",
756+ ( ( unsigned long long ) frame64->rdx ),
757+ ( ( unsigned long long ) frame64->rsi ),
758+ ( ( unsigned long long ) frame64->rdi ) );
759+ DBGC ( &intr, "rbp = %016llx rsp = %016llx flg = %016llx\n",
760+ ( ( unsigned long long ) frame64->rbp ),
761+ ( ( unsigned long long ) frame64->rsp ),
762+ ( ( unsigned long long ) frame64->rflags ) );
763+ DBGC ( &intr, "r8 = %016llx r9 = %016llx r10 = %016llx\n",
764+ ( ( unsigned long long ) frame64->r8 ),
765+ ( ( unsigned long long ) frame64->r9 ),
766+ ( ( unsigned long long ) frame64->r10 ) );
767+ DBGC ( &intr, "r11 = %016llx r12 = %016llx r13 = %016llx\n",
768+ ( ( unsigned long long ) frame64->r11 ),
769+ ( ( unsigned long long ) frame64->r12 ),
770+ ( ( unsigned long long ) frame64->r13 ) );
771+ DBGC ( &intr, "r14 = %016llx r15 = %016llx\n",
772+ ( ( unsigned long long ) frame64->r14 ),
773+ ( ( unsigned long long ) frame64->r15 ) );
774+ sp = frame64->rsp;
775+ stack = phys_to_virt ( sp );
776+ }
777+
778+ /* Print stack dump */
779+ DBGC_HDA ( &intr, sp, stack, STACK_DUMP_LEN );
780+}
781+
782+/**
783 * Interrupt handler
784 *
785 * @v intr Interrupt number
786+ * @v frame32 32-bit interrupt wrapper stack frame (or NULL)
787+ * @v frame64 64-bit interrupt wrapper stack frame (or NULL)
788+ * @v frame Interrupt wrapper stack frame
789 */
790-void __attribute__ (( regparm ( 1 ) )) interrupt ( int intr ) {
791+void __attribute__ (( regparm ( 3 ) ))
792+interrupt ( int intr, struct interrupt_frame32 *frame32,
793+ struct interrupt_frame64 *frame64 ) {
794 struct profiler *profiler = interrupt_profiler ( intr );
795 uint32_t discard_eax;
796
797+ /* Trap CPU exceptions if debugging is enabled. Note that we
798+ * cannot treat INT8+ as exceptions, since we are not
799+ * permitted to rebase the PIC.
800+ */
801+ if ( DBG_LOG && ( intr < IRQ_INT ( 0 ) ) ) {
802+ interrupt_dump ( intr, frame32, frame64 );
803+ DBG ( "CPU exception: dropping to emergency shell\n" );
804+ shell();
805+ }
806+
807 /* Reissue interrupt in real mode */
808 profile_start ( profiler );
809 __asm__ __volatile__ ( REAL_CODE ( "movb %%al, %%cs:(1f + 1)\n\t"
810diff --git a/src/arch/x86/transitions/librm_test.c b/src/arch/x86/transitions/librm_test.c
811index ba4254f..77cf802 100644
812--- a/src/arch/x86/transitions/librm_test.c
813+++ b/src/arch/x86/transitions/librm_test.c
814@@ -97,7 +97,7 @@ static void librm_test_exec ( void ) {
815 /* Profile complete real-mode call cycle */
816 for ( i = 0 ; i < PROFILE_COUNT ; i++ ) {
817 profile_start ( &real_call_profiler );
818- __asm__ __volatile__ ( REAL_CODE ( "" ) );
819+ __asm__ __volatile__ ( REAL_CODE ( "" ) : );
820 profile_stop ( &real_call_profiler );
821 }
822
823diff --git a/src/arch/x86_64/Makefile b/src/arch/x86_64/Makefile
824index 246905c..b3064b7 100644
825--- a/src/arch/x86_64/Makefile
826+++ b/src/arch/x86_64/Makefile
827@@ -13,6 +13,10 @@ CFLAGS += -m64
828 ASFLAGS += --64
829 LDFLAGS += -m elf_x86_64
830
831+# Prevent use of MMX and SSE registers
832+#
833+CFLAGS += -mno-mmx -mno-sse
834+
835 # EFI requires -fshort-wchar, and nothing else currently uses wchar_t
836 #
837 CFLAGS += -fshort-wchar
838diff --git a/src/arch/x86_64/include/bits/hyperv.h b/src/arch/x86_64/include/bits/hyperv.h
839index 975b1ee..fa8bb3f 100644
840--- a/src/arch/x86_64/include/bits/hyperv.h
841+++ b/src/arch/x86_64/include/bits/hyperv.h
842@@ -44,8 +44,7 @@ hv_call ( struct hv_hypervisor *hv, unsigned int code, const void *in,
843 : "=a" ( result ), "+r" ( rcx ), "+r" ( rdx ),
844 "+r" ( r8 )
845 : "m" ( hypercall )
846- : "r9", "r10", "r11", "xmm0", "xmm1", "xmm2",
847- "xmm3", "xmm4", "xmm5" );
848+ : "r9", "r10", "r11" );
849 return result;
850 }
851
852diff --git a/src/config/config_timer.c b/src/config/config_timer.c
853index a462970..d53c399 100644
854--- a/src/config/config_timer.c
855+++ b/src/config/config_timer.c
856@@ -46,3 +46,6 @@ REQUIRE_OBJECT ( efi_timer );
857 #ifdef TIMER_LINUX
858 REQUIRE_OBJECT ( linux_timer );
859 #endif
860+#ifdef TIMER_ACPI
861+REQUIRE_OBJECT ( acpi_timer );
862+#endif
863diff --git a/src/config/crypto.h b/src/config/crypto.h
864index 8f885c5..1edcdce 100644
865--- a/src/config/crypto.h
866+++ b/src/config/crypto.h
867@@ -58,6 +58,14 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
868 */
869 #define CROSSCERT "http://ca.ipxe.org/auto"
870
871+/** Perform OCSP checks when applicable
872+ *
873+ * Some CAs provide non-functional OCSP servers, and some clients are
874+ * forced to operate on networks without access to the OCSP servers.
875+ * Allow the user to explicitly disable the use of OCSP checks.
876+ */
877+#define OCSP_CHECK
878+
879 #include <config/named.h>
880 #include NAMED_CONFIG(crypto.h)
881 #include <config/local/crypto.h>
882diff --git a/src/core/netbios.c b/src/core/netbios.c
883new file mode 100644
884index 0000000..0d4e208
885--- /dev/null
886+++ b/src/core/netbios.c
887@@ -0,0 +1,60 @@
888+/*
889+ * Copyright (C) 2018 Michael Brown <mbrown@fensystems.co.uk>.
890+ *
891+ * This program is free software; you can redistribute it and/or
892+ * modify it under the terms of the GNU General Public License as
893+ * published by the Free Software Foundation; either version 2 of the
894+ * License, or any later version.
895+ *
896+ * This program is distributed in the hope that it will be useful, but
897+ * WITHOUT ANY WARRANTY; without even the implied warranty of
898+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
899+ * General Public License for more details.
900+ *
901+ * You should have received a copy of the GNU General Public License
902+ * along with this program; if not, write to the Free Software
903+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
904+ * 02110-1301, USA.
905+ *
906+ * You can also choose to distribute this program under the terms of
907+ * the Unmodified Binary Distribution Licence (as given in the file
908+ * COPYING.UBDL), provided that you have satisfied its requirements.
909+ */
910+
911+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
912+
913+/** @file
914+ *
915+ * NetBIOS user names
916+ *
917+ */
918+
919+#include <stddef.h>
920+#include <string.h>
921+#include <ipxe/netbios.h>
922+
923+/**
924+ * Split NetBIOS [domain\]username into separate domain and username fields
925+ *
926+ * @v username NetBIOS [domain\]username string
927+ * @ret domain Domain portion of string, or NULL if no domain present
928+ *
929+ * This function modifies the original string by removing the
930+ * separator. The caller may restore the string using
931+ * netbios_domain_undo().
932+ */
933+const char * netbios_domain ( char **username ) {
934+ char *domain_username = *username;
935+ char *sep;
936+
937+ /* Find separator, if present */
938+ sep = strchr ( domain_username, '\\' );
939+ if ( ! sep )
940+ return NULL;
941+
942+ /* Overwrite separator with NUL terminator and update username string */
943+ *sep = '\0';
944+ *username = ( sep + 1 );
945+
946+ return domain_username;
947+}
948diff --git a/src/core/profile.c b/src/core/profile.c
949index 1075047..3655108 100644
950--- a/src/core/profile.c
951+++ b/src/core/profile.c
952@@ -26,6 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
953 #include <stdint.h>
954 #include <stdio.h>
955 #include <strings.h>
956+#include <limits.h>
957 #include <assert.h>
958 #include <ipxe/isqrt.h>
959 #include <ipxe/profile.h>
960@@ -122,8 +123,9 @@ void profile_update ( struct profiler *profiler, unsigned long sample ) {
961 */
962 assert ( ( ( signed ) sample ) >= 0 );
963
964- /* Update sample count */
965- profiler->count++;
966+ /* Update sample count, limiting to avoid signed overflow */
967+ if ( profiler->count < INT_MAX )
968+ profiler->count++;
969
970 /* Adjust mean sample value scale if necessary. Skip if
971 * sample is zero (in which case flsl(sample)-1 would
972diff --git a/src/crypto/entropy.c b/src/crypto/entropy.c
973index 5acbc02..ced6fd9 100644
974--- a/src/crypto/entropy.c
975+++ b/src/crypto/entropy.c
976@@ -70,7 +70,8 @@ repetition_count_cutoff ( void ) {
977 * where W is set at 2^(-30) (in ANS X9.82 Part 2 (October
978 * 2011 Draft) Section 8.5.2.1.3.1).
979 */
980- max_repetitions = ( 1 + ( 30 / min_entropy_per_sample() ) );
981+ max_repetitions = ( 1 + ( MIN_ENTROPY ( 30 ) /
982+ min_entropy_per_sample() ) );
983
984 /* Round up to a whole number of repetitions. We don't have
985 * the ceil() function available, so do the rounding by hand.
986@@ -237,7 +238,7 @@ adaptive_proportion_cutoff ( void ) {
987
988 /* Look up cutoff value in cutoff table */
989 n = ADAPTIVE_PROPORTION_WINDOW_SIZE;
990- h = min_entropy_per_sample();
991+ h = ( min_entropy_per_sample() / MIN_ENTROPY_SCALE );
992 cutoff = adaptive_proportion_cutoff_lookup ( n, h );
993
994 /* Fail unless cutoff value is a build-time constant */
995diff --git a/src/crypto/x509.c b/src/crypto/x509.c
996index 76ace03..feb7e4a 100644
997--- a/src/crypto/x509.c
998+++ b/src/crypto/x509.c
999@@ -40,6 +40,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
1000 #include <ipxe/socket.h>
1001 #include <ipxe/in.h>
1002 #include <ipxe/image.h>
1003+#include <ipxe/ocsp.h>
1004 #include <ipxe/x509.h>
1005 #include <config/crypto.h>
1006
1007@@ -1362,8 +1363,7 @@ int x509_validate ( struct x509_certificate *cert,
1008 }
1009
1010 /* Fail if OCSP is required */
1011- if ( cert->extensions.auth_info.ocsp.uri.len &&
1012- ( ! cert->extensions.auth_info.ocsp.good ) ) {
1013+ if ( ocsp_required ( cert ) ) {
1014 DBGC ( cert, "X509 %p \"%s\" requires an OCSP check\n",
1015 cert, x509_name ( cert ) );
1016 return -EACCES_OCSP_REQUIRED;
1017diff --git a/src/drivers/bitbash/mii_bit.c b/src/drivers/bitbash/mii_bit.c
1018new file mode 100644
1019index 0000000..5f0ec04
1020--- /dev/null
1021+++ b/src/drivers/bitbash/mii_bit.c
1022@@ -0,0 +1,162 @@
1023+/*
1024+ * Copyright (C) 2018 Sylvie Barlow <sylvie.c.barlow@gmail.com>.
1025+ *
1026+ * This program is free software; you can redistribute it and/or
1027+ * modify it under the terms of the GNU General Public License as
1028+ * published by the Free Software Foundation; either version 2 of the
1029+ * License, or any later version.
1030+ *
1031+ * This program is distributed in the hope that it will be useful, but
1032+ * WITHOUT ANY WARRANTY; without even the implied warranty of
1033+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1034+ * General Public License for more details.
1035+ *
1036+ * You should have received a copy of the GNU General Public License
1037+ * along with this program; if not, write to the Free Software
1038+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
1039+ * 02110-1301, USA.
1040+ *
1041+ * You can also choose to distribute this program under the terms of
1042+ * the Unmodified Binary Distribution Licence (as given in the file
1043+ * COPYING.UBDL), provided that you have satisfied its requirements.
1044+ */
1045+
1046+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
1047+
1048+#include <stdint.h>
1049+#include <unistd.h>
1050+#include <ipxe/bitbash.h>
1051+#include <ipxe/mii_bit.h>
1052+
1053+/**
1054+ * Transfer bits over MII bit-bashing interface
1055+ *
1056+ * @v basher Bit basher
1057+ * @v mask Mask
1058+ * @v write Data to write
1059+ * @ret read Data read
1060+ */
1061+static uint32_t mii_bit_xfer ( struct bit_basher *basher,
1062+ uint32_t mask, uint32_t write ) {
1063+ uint32_t read = 0;
1064+ int bit;
1065+
1066+ for ( ; mask ; mask >>= 1 ) {
1067+
1068+ /* Delay */
1069+ udelay ( 1 );
1070+
1071+ /* Write bit to basher */
1072+ write_bit ( basher, MII_BIT_MDIO, ( write & mask ) );
1073+
1074+ /* Read bit from basher */
1075+ bit = read_bit ( basher, MII_BIT_MDIO );
1076+ read <<= 1;
1077+ read |= ( bit & 1 );
1078+
1079+ /* Set clock high */
1080+ write_bit ( basher, MII_BIT_MDC, 1 );
1081+
1082+ /* Delay */
1083+ udelay ( 1 );
1084+
1085+ /* Set clock low */
1086+ write_bit ( basher, MII_BIT_MDC, 0 );
1087+ }
1088+ return read;
1089+}
1090+
1091+/**
1092+ * Read or write via MII bit-bashing interface
1093+ *
1094+ * @v basher Bit basher
1095+ * @v phy PHY address
1096+ * @v reg Register address
1097+ * @v data Data to write
1098+ * @v cmd Command
1099+ * @ret data Data read
1100+ */
1101+static unsigned int mii_bit_rw ( struct bit_basher *basher,
1102+ unsigned int phy, unsigned int reg,
1103+ unsigned int data, unsigned int cmd ) {
1104+
1105+ /* Initiate drive for write */
1106+ write_bit ( basher, MII_BIT_DRIVE, 1 );
1107+
1108+ /* Write start */
1109+ mii_bit_xfer ( basher, MII_BIT_START_MASK, MII_BIT_START );
1110+
1111+ /* Write command */
1112+ mii_bit_xfer ( basher, MII_BIT_CMD_MASK, cmd );
1113+
1114+ /* Write PHY address */
1115+ mii_bit_xfer ( basher, MII_BIT_PHY_MASK, phy );
1116+
1117+ /* Write register address */
1118+ mii_bit_xfer ( basher, MII_BIT_REG_MASK, reg );
1119+
1120+ /* Switch drive to read if applicable */
1121+ write_bit ( basher, MII_BIT_DRIVE, ( cmd & MII_BIT_CMD_RW ) );
1122+
1123+ /* Allow space for turnaround */
1124+ mii_bit_xfer ( basher, MII_BIT_SWITCH_MASK, MII_BIT_SWITCH );
1125+
1126+ /* Read or write data */
1127+ data = mii_bit_xfer (basher, MII_BIT_DATA_MASK, data );
1128+
1129+ /* Initiate drive for read */
1130+ write_bit ( basher, MII_BIT_DRIVE, 0 );
1131+
1132+ return data;
1133+}
1134+
1135+/**
1136+ * Read from MII register
1137+ *
1138+ * @v mdio MII interface
1139+ * @v phy PHY address
1140+ * @v reg Register address
1141+ * @ret data Data read, or negative error
1142+ */
1143+static int mii_bit_read ( struct mii_interface *mdio, unsigned int phy,
1144+ unsigned int reg ) {
1145+ struct mii_bit_basher *miibit =
1146+ container_of ( mdio, struct mii_bit_basher, mdio );
1147+ struct bit_basher *basher = &miibit->basher;
1148+
1149+ return mii_bit_rw ( basher, phy, reg, 0, MII_BIT_CMD_READ );
1150+}
1151+
1152+/**
1153+ * Write to MII register
1154+ *
1155+ * @v mdio MII interface
1156+ * @v phy PHY address
1157+ * @v reg Register address
1158+ * @v data Data to write
1159+ * @ret rc Return status code
1160+ */
1161+static int mii_bit_write ( struct mii_interface *mdio, unsigned int phy,
1162+ unsigned int reg, unsigned int data ) {
1163+ struct mii_bit_basher *miibit =
1164+ container_of ( mdio, struct mii_bit_basher, mdio );
1165+ struct bit_basher *basher = &miibit->basher;
1166+
1167+ mii_bit_rw ( basher, phy, reg, data, MII_BIT_CMD_WRITE );
1168+ return 0;
1169+}
1170+
1171+/** MII bit basher operations */
1172+static struct mii_operations mii_bit_op = {
1173+ .read = mii_bit_read,
1174+ .write = mii_bit_write,
1175+};
1176+
1177+/**
1178+ * Initialise bit-bashing interface
1179+ *
1180+ * @v miibit MII bit basher
1181+ */
1182+void init_mii_bit_basher ( struct mii_bit_basher *miibit ) {
1183+ mdio_init ( &miibit->mdio, &mii_bit_op );
1184+};
1185diff --git a/src/drivers/infiniband/CIB_PRM.h b/src/drivers/infiniband/CIB_PRM.h
1186index 6d07c01..d578f9b 100755
1187--- a/src/drivers/infiniband/CIB_PRM.h
1188+++ b/src/drivers/infiniband/CIB_PRM.h
1189@@ -33,7 +33,7 @@ typedef uint16_t __be16;
1190
1191 #define GOLAN_PCI_CMD_XPORT 7
1192 #define CMD_OWNER_HW 0x1
1193-
1194+#define GOLAN_LOG_MAX_QP 0x1
1195 #define IB_NUM_PKEYS 0x20
1196
1197 struct health_buffer {
1198@@ -229,8 +229,7 @@ struct golan_hca_cap {
1199 u8 rsvd1[16];
1200 u8 log_max_srq_sz;
1201 u8 log_max_qp_sz;
1202- u8 rsvd2;
1203- u8 log_max_qp;
1204+ __be16 log_max_qp;
1205 u8 log_max_strq_sz;
1206 u8 log_max_srqs;
1207 u8 rsvd4[2];
1208diff --git a/src/drivers/infiniband/golan.c b/src/drivers/infiniband/golan.c
1209index 61331d4..18ebfb1 100755
1210--- a/src/drivers/infiniband/golan.c
1211+++ b/src/drivers/infiniband/golan.c
1212@@ -363,7 +363,7 @@ static inline int golan_set_hca_cap(struct golan *golan)
1213 DBGC( golan , "%s caps.log_pg_sz = %d\n", __FUNCTION__, golan->caps.log_pg_sz);
1214 DBGC( golan , "%s caps.log_uar_sz = %d\n", __FUNCTION__, be32_to_cpu(golan->caps.uar_page_sz));
1215 golan->caps.uar_page_sz = 0;
1216-
1217+ golan->caps.log_max_qp = GOLAN_LOG_MAX_QP;
1218
1219 memcpy(((struct golan_hca_cap *)GET_INBOX(golan, GEN_MBOX)),
1220 &(golan->caps),
1221@@ -2586,8 +2586,6 @@ struct flexboot_nodnic_callbacks shomron_nodnic_callbacks = {
1222 .tx_uar_send_doorbell_fn = shomron_tx_uar_send_db,
1223 };
1224
1225-static int shomron_nodnic_supported = 0;
1226-
1227 static int shomron_nodnic_is_supported ( struct pci_device *pci ) {
1228 if ( DEVICE_IS_CIB ( pci->device ) )
1229 return 0;
1230@@ -2607,8 +2605,7 @@ static int golan_probe ( struct pci_device *pci ) {
1231 goto probe_done;
1232 }
1233
1234- shomron_nodnic_supported = shomron_nodnic_is_supported ( pci );
1235- if ( shomron_nodnic_supported ) {
1236+ if ( shomron_nodnic_is_supported ( pci ) ) {
1237 DBG ( "%s: Using NODNIC driver\n", __FUNCTION__ );
1238 rc = flexboot_nodnic_probe ( pci, &shomron_nodnic_callbacks, NULL );
1239 } else {
1240@@ -2624,7 +2621,7 @@ probe_done:
1241 static void golan_remove ( struct pci_device *pci ) {
1242 DBG ( "%s: start\n", __FUNCTION__ );
1243
1244- if ( ! shomron_nodnic_supported ) {
1245+ if ( ! shomron_nodnic_is_supported ( pci ) ) {
1246 DBG ( "%s: Using normal driver remove\n", __FUNCTION__ );
1247 golan_remove_normal ( pci );
1248 return;
1249diff --git a/src/drivers/net/efi/nii.c b/src/drivers/net/efi/nii.c
1250index 1700b4b..2d87e0c 100644
1251--- a/src/drivers/net/efi/nii.c
1252+++ b/src/drivers/net/efi/nii.c
1253@@ -25,6 +25,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
1254
1255 #include <string.h>
1256 #include <strings.h>
1257+#include <stdlib.h>
1258 #include <unistd.h>
1259 #include <errno.h>
1260 #include <ipxe/netdevice.h>
1261@@ -137,6 +138,16 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
1262 */
1263 #define PCI_MAX_BAR 6
1264
1265+/** An NII memory mapping */
1266+struct nii_mapping {
1267+ /** List of mappings */
1268+ struct list_head list;
1269+ /** Mapped address */
1270+ UINT64 addr;
1271+ /** Mapping cookie created by PCI I/O protocol */
1272+ VOID *mapping;
1273+};
1274+
1275 /** An NII NIC */
1276 struct nii_nic {
1277 /** EFI device */
1278@@ -179,6 +190,9 @@ struct nii_nic {
1279 struct io_buffer *txbuf;
1280 /** Current receive buffer */
1281 struct io_buffer *rxbuf;
1282+
1283+ /** Mapping list */
1284+ struct list_head mappings;
1285 };
1286
1287 /** Maximum number of received packets per poll */
1288@@ -280,7 +294,19 @@ static int nii_pci_open ( struct nii_nic *nii ) {
1289 */
1290 static void nii_pci_close ( struct nii_nic *nii ) {
1291 EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
1292+ struct nii_mapping *map;
1293+ struct nii_mapping *tmp;
1294+
1295+ /* Remove any stale mappings */
1296+ list_for_each_entry_safe ( map, tmp, &nii->mappings, list ) {
1297+ DBGC ( nii, "NII %s removing stale mapping %#llx\n",
1298+ nii->dev.name, ( ( unsigned long long ) map->addr ) );
1299+ nii->pci_io->Unmap ( nii->pci_io, map->mapping );
1300+ list_del ( &map->list );
1301+ free ( map );
1302+ }
1303
1304+ /* Close protocols */
1305 bs->CloseProtocol ( nii->pci_device, &efi_pci_io_protocol_guid,
1306 efi_image_handle, nii->efidev->device );
1307 }
1308@@ -332,6 +358,139 @@ static EFIAPI VOID nii_io ( UINT64 unique_id, UINT8 op, UINT8 len, UINT64 addr,
1309 }
1310
1311 /**
1312+ * Map callback
1313+ *
1314+ * @v unique_id NII NIC
1315+ * @v addr Address of memory to be mapped
1316+ * @v len Length of memory to be mapped
1317+ * @v dir Direction of data flow
1318+ * @v mapped Device mapped address to fill in
1319+ */
1320+static EFIAPI VOID nii_map ( UINT64 unique_id, UINT64 addr, UINT32 len,
1321+ UINT32 dir, UINT64 mapped ) {
1322+ struct nii_nic *nii = ( ( void * ) ( intptr_t ) unique_id );
1323+ EFI_PHYSICAL_ADDRESS *phys = ( ( void * ) ( intptr_t ) mapped );
1324+ EFI_PCI_IO_PROTOCOL_OPERATION op;
1325+ struct nii_mapping *map;
1326+ UINTN count = len;
1327+ EFI_STATUS efirc;
1328+ int rc;
1329+
1330+ /* Return a zero mapped address on failure */
1331+ *phys = 0;
1332+
1333+ /* Determine PCI mapping operation */
1334+ switch ( dir ) {
1335+ case TO_AND_FROM_DEVICE:
1336+ op = EfiPciIoOperationBusMasterCommonBuffer;
1337+ break;
1338+ case FROM_DEVICE:
1339+ op = EfiPciIoOperationBusMasterWrite;
1340+ break;
1341+ case TO_DEVICE:
1342+ op = EfiPciIoOperationBusMasterRead;
1343+ break;
1344+ default:
1345+ DBGC ( nii, "NII %s unsupported mapping direction %d\n",
1346+ nii->dev.name, dir );
1347+ goto err_dir;
1348+ }
1349+
1350+ /* Allocate a mapping record */
1351+ map = zalloc ( sizeof ( *map ) );
1352+ if ( ! map )
1353+ goto err_alloc;
1354+ map->addr = addr;
1355+
1356+ /* Create map */
1357+ if ( ( efirc = nii->pci_io->Map ( nii->pci_io, op,
1358+ ( ( void * ) ( intptr_t ) addr ),
1359+ &count, phys, &map->mapping ) ) != 0){
1360+ rc = -EEFI ( efirc );
1361+ DBGC ( nii, "NII %s map operation failed: %s\n",
1362+ nii->dev.name, strerror ( rc ) );
1363+ goto err_map;
1364+ }
1365+
1366+ /* Add to list of mappings */
1367+ list_add ( &map->list, &nii->mappings );
1368+ DBGC2 ( nii, "NII %s mapped %#llx+%#x->%#llx\n",
1369+ nii->dev.name, ( ( unsigned long long ) addr ),
1370+ len, ( ( unsigned long long ) *phys ) );
1371+ return;
1372+
1373+ list_del ( &map->list );
1374+ err_map:
1375+ free ( map );
1376+ err_alloc:
1377+ err_dir:
1378+ return;
1379+}
1380+
1381+/**
1382+ * Unmap callback
1383+ *
1384+ * @v unique_id NII NIC
1385+ * @v addr Address of mapped memory
1386+ * @v len Length of mapped memory
1387+ * @v dir Direction of data flow
1388+ * @v mapped Device mapped address
1389+ */
1390+static EFIAPI VOID nii_unmap ( UINT64 unique_id, UINT64 addr, UINT32 len,
1391+ UINT32 dir __unused, UINT64 mapped ) {
1392+ struct nii_nic *nii = ( ( void * ) ( intptr_t ) unique_id );
1393+ struct nii_mapping *map;
1394+
1395+ /* Locate mapping record */
1396+ list_for_each_entry ( map, &nii->mappings, list ) {
1397+ if ( map->addr == addr ) {
1398+ nii->pci_io->Unmap ( nii->pci_io, map->mapping );
1399+ list_del ( &map->list );
1400+ free ( map );
1401+ DBGC2 ( nii, "NII %s unmapped %#llx+%#x->%#llx\n",
1402+ nii->dev.name, ( ( unsigned long long ) addr ),
1403+ len, ( ( unsigned long long ) mapped ) );
1404+ return;
1405+ }
1406+ }
1407+
1408+ DBGC ( nii, "NII %s non-existent mapping %#llx+%#x->%#llx\n",
1409+ nii->dev.name, ( ( unsigned long long ) addr ),
1410+ len, ( ( unsigned long long ) mapped ) );
1411+}
1412+
1413+/**
1414+ * Sync callback
1415+ *
1416+ * @v unique_id NII NIC
1417+ * @v addr Address of mapped memory
1418+ * @v len Length of mapped memory
1419+ * @v dir Direction of data flow
1420+ * @v mapped Device mapped address
1421+ */
1422+static EFIAPI VOID nii_sync ( UINT64 unique_id __unused, UINT64 addr,
1423+ UINT32 len, UINT32 dir, UINT64 mapped ) {
1424+ const void *src;
1425+ void *dst;
1426+
1427+ /* Do nothing if this is an identity mapping */
1428+ if ( addr == mapped )
1429+ return;
1430+
1431+ /* Determine direction */
1432+ if ( dir == FROM_DEVICE ) {
1433+ src = ( ( void * ) ( intptr_t ) mapped );
1434+ dst = ( ( void * ) ( intptr_t ) addr );
1435+ } else {
1436+ src = ( ( void * ) ( intptr_t ) addr );
1437+ dst = ( ( void * ) ( intptr_t ) mapped );
1438+ }
1439+
1440+ /* Copy data */
1441+ memcpy ( dst, src, len );
1442+}
1443+
1444+/**
1445 * Delay callback
1446 *
1447 * @v unique_id NII NIC
1448@@ -499,6 +658,9 @@ static int nii_start_undi ( struct nii_nic *nii ) {
1449 cpb.Delay = ( ( intptr_t ) nii_delay );
1450 cpb.Block = ( ( intptr_t ) nii_block );
1451 cpb.Mem_IO = ( ( intptr_t ) nii_io );
1452+ cpb.Map_Mem = ( ( intptr_t ) nii_map );
1453+ cpb.UnMap_Mem = ( ( intptr_t ) nii_unmap );
1454+ cpb.Sync_Mem = ( ( intptr_t ) nii_sync );
1455 cpb.Unique_ID = ( ( intptr_t ) nii );
1456
1457 /* Issue command */
1458@@ -1063,6 +1225,7 @@ int nii_start ( struct efi_device *efidev ) {
1459 netdev_init ( netdev, &nii_operations );
1460 nii = netdev->priv;
1461 nii->efidev = efidev;
1462+ INIT_LIST_HEAD ( &nii->mappings );
1463 netdev->ll_broadcast = nii->broadcast;
1464 efidev_set_drvdata ( efidev, netdev );
1465
1466diff --git a/src/drivers/net/ena.c b/src/drivers/net/ena.c
1467index 8d29979..0f25c0b 100644
1468--- a/src/drivers/net/ena.c
1469+++ b/src/drivers/net/ena.c
1470@@ -565,6 +565,7 @@ static int ena_get_device_attributes ( struct net_device *netdev ) {
1471 feature = &rsp->get_feature.feature;
1472 memcpy ( netdev->hw_addr, feature->device.mac, ETH_ALEN );
1473 netdev->max_pkt_len = le32_to_cpu ( feature->device.mtu );
1474+ netdev->mtu = ( netdev->max_pkt_len - ETH_HLEN );
1475
1476 DBGC ( ena, "ENA %p MAC %s MTU %zd\n",
1477 ena, eth_ntoa ( netdev->hw_addr ), netdev->max_pkt_len );
1478diff --git a/src/drivers/net/icplus.c b/src/drivers/net/icplus.c
1479new file mode 100644
1480index 0000000..4bed924
1481--- /dev/null
1482+++ b/src/drivers/net/icplus.c
1483@@ -0,0 +1,809 @@
1484+/*
1485+ * Copyright (C) 2018 Sylvie Barlow <sylvie.c.barlow@gmail.com>.
1486+ *
1487+ * This program is free software; you can redistribute it and/or
1488+ * modify it under the terms of the GNU General Public License as
1489+ * published by the Free Software Foundation; either version 2 of the
1490+ * License, or (at your option) any later version.
1491+ *
1492+ * This program is distributed in the hope that it will be useful, but
1493+ * WITHOUT ANY WARRANTY; without even the implied warranty of
1494+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1495+ * General Public License for more details.
1496+ *
1497+ * You should have received a copy of the GNU General Public License
1498+ * along with this program; if not, write to the Free Software
1499+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
1500+ * 02110-1301, USA.
1501+ *
1502+ * You can also choose to distribute this program under the terms of
1503+ * the Unmodified Binary Distribution Licence (as given in the file
1504+ * COPYING.UBDL), provided that you have satisfied its requirements.
1505+ */
1506+
1507+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
1508+
1509+#include <stdint.h>
1510+#include <string.h>
1511+#include <unistd.h>
1512+#include <errno.h>
1513+#include <byteswap.h>
1514+#include <ipxe/netdevice.h>
1515+#include <ipxe/ethernet.h>
1516+#include <ipxe/if_ether.h>
1517+#include <ipxe/iobuf.h>
1518+#include <ipxe/malloc.h>
1519+#include <ipxe/pci.h>
1520+#include "icplus.h"
1521+
1522+/** @file
1523+ *
1524+ * IC+ network driver
1525+ *
1526+ */
1527+
1528+/******************************************************************************
1529+ *
1530+ * Device reset
1531+ *
1532+ ******************************************************************************
1533+ */
1534+
1535+/**
1536+ * Reset hardware
1537+ *
1538+ * @v icp IC+ device
1539+ * @ret rc Return status code
1540+ */
1541+static int icplus_reset ( struct icplus_nic *icp ) {
1542+ uint32_t asicctrl;
1543+ unsigned int i;
1544+
1545+ /* Trigger reset */
1546+ writel ( ( ICP_ASICCTRL_GLOBALRESET | ICP_ASICCTRL_DMA |
1547+ ICP_ASICCTRL_FIFO | ICP_ASICCTRL_NETWORK | ICP_ASICCTRL_HOST |
1548+ ICP_ASICCTRL_AUTOINIT ), ( icp->regs + ICP_ASICCTRL ) );
1549+
1550+ /* Wait for reset to complete */
1551+ for ( i = 0 ; i < ICP_RESET_MAX_WAIT_MS ; i++ ) {
1552+
1553+ /* Check if device is ready */
1554+ asicctrl = readl ( icp->regs + ICP_ASICCTRL );
1555+ if ( ! ( asicctrl & ICP_ASICCTRL_RESETBUSY ) )
1556+ return 0;
1557+
1558+ /* Delay */
1559+ mdelay ( 1 );
1560+ }
1561+
1562+ DBGC ( icp, "ICPLUS %p timed out waiting for reset (asicctrl %#08x)\n",
1563+ icp, asicctrl );
1564+ return -ETIMEDOUT;
1565+}
1566+
1567+/******************************************************************************
1568+ *
1569+ * EEPROM interface
1570+ *
1571+ ******************************************************************************
1572+ */
1573+
1574+/**
1575+ * Read data from EEPROM
1576+ *
1577+ * @v nvs NVS device
1578+ * @v address Address from which to read
1579+ * @v data Data buffer
1580+ * @v len Length of data buffer
1581+ * @ret rc Return status code
1582+ */
1583+static int icplus_read_eeprom ( struct nvs_device *nvs, unsigned int address,
1584+ void *data, size_t len ) {
1585+ struct icplus_nic *icp =
1586+ container_of ( nvs, struct icplus_nic, eeprom );
1587+ unsigned int i;
1588+ uint16_t eepromctrl;
1589+ uint16_t *data_word = data;
1590+
1591+ /* Sanity check. We advertise a blocksize of one word, so
1592+ * should only ever receive single-word requests.
1593+ */
1594+ assert ( len == sizeof ( *data_word ) );
1595+
1596+ /* Initiate read */
1597+ writew ( ( ICP_EEPROMCTRL_OPCODE_READ |
1598+ ICP_EEPROMCTRL_ADDRESS ( address ) ),
1599+ ( icp->regs + ICP_EEPROMCTRL ) );
1600+
1601+ /* Wait for read to complete */
1602+ for ( i = 0 ; i < ICP_EEPROM_MAX_WAIT_MS ; i++ ) {
1603+
1604+ /* If read is not complete, delay 1ms and retry */
1605+ eepromctrl = readw ( icp->regs + ICP_EEPROMCTRL );
1606+ if ( eepromctrl & ICP_EEPROMCTRL_BUSY ) {
1607+ mdelay ( 1 );
1608+ continue;
1609+ }
1610+
1611+ /* Extract data */
1612+ *data_word = cpu_to_le16 ( readw ( icp->regs + ICP_EEPROMDATA ));
1613+ return 0;
1614+ }
1615+
1616+ DBGC ( icp, "ICPLUS %p timed out waiting for EEPROM read\n", icp );
1617+ return -ETIMEDOUT;
1618+}
1619+
1620+/**
1621+ * Write data to EEPROM
1622+ *
1623+ * @v nvs NVS device
1624+ * @v address Address to which to write
1625+ * @v data Data buffer
1626+ * @v len Length of data buffer
1627+ * @ret rc Return status code
1628+ */
1629+static int icplus_write_eeprom ( struct nvs_device *nvs,
1630+ unsigned int address __unused,
1631+ const void *data __unused,
1632+ size_t len __unused ) {
1633+ struct icplus_nic *icp =
1634+ container_of ( nvs, struct icplus_nic, eeprom );
1635+
1636+ DBGC ( icp, "ICPLUS %p EEPROM write not supported\n", icp );
1637+ return -ENOTSUP;
1638+}
1639+
1640+/**
1641+ * Initialise EEPROM
1642+ *
1643+ * @v icp IC+ device
1644+ */
1645+static void icplus_init_eeprom ( struct icplus_nic *icp ) {
1646+
1647+ /* The hardware supports only single-word reads */
1648+ icp->eeprom.word_len_log2 = ICP_EEPROM_WORD_LEN_LOG2;
1649+ icp->eeprom.size = ICP_EEPROM_MIN_SIZE_WORDS;
1650+ icp->eeprom.block_size = 1;
1651+ icp->eeprom.read = icplus_read_eeprom;
1652+ icp->eeprom.write = icplus_write_eeprom;
1653+}
1654+
1655+/******************************************************************************
1656+ *
1657+ * MII interface
1658+ *
1659+ ******************************************************************************
1660+ */
1661+
1662+/** Pin mapping for MII bit-bashing interface */
1663+static const uint8_t icplus_mii_bits[] = {
1664+ [MII_BIT_MDC] = ICP_PHYCTRL_MGMTCLK,
1665+ [MII_BIT_MDIO] = ICP_PHYCTRL_MGMTDATA,
1666+ [MII_BIT_DRIVE] = ICP_PHYCTRL_MGMTDIR,
1667+};
1668+
1669+/**
1670+ * Read input bit
1671+ *
1672+ * @v basher Bit-bashing interface
1673+ * @v bit_id Bit number
1674+ * @ret zero Input is a logic 0
1675+ * @ret non-zero Input is a logic 1
1676+ */
1677+static int icplus_mii_read_bit ( struct bit_basher *basher,
1678+ unsigned int bit_id ) {
1679+ struct icplus_nic *icp = container_of ( basher, struct icplus_nic,
1680+ miibit.basher );
1681+ uint8_t mask = icplus_mii_bits[bit_id];
1682+ uint8_t reg;
1683+
1684+ DBG_DISABLE ( DBGLVL_IO );
1685+ reg = readb ( icp->regs + ICP_PHYCTRL );
1686+ DBG_ENABLE ( DBGLVL_IO );
1687+ return ( reg & mask );
1688+}
1689+
1690+/**
1691+ * Set/clear output bit
1692+ *
1693+ * @v basher Bit-bashing interface
1694+ * @v bit_id Bit number
1695+ * @v data Value to write
1696+ */
1697+static void icplus_mii_write_bit ( struct bit_basher *basher,
1698+ unsigned int bit_id, unsigned long data ) {
1699+ struct icplus_nic *icp = container_of ( basher, struct icplus_nic,
1700+ miibit.basher );
1701+ uint8_t mask = icplus_mii_bits[bit_id];
1702+ uint8_t reg;
1703+
1704+ DBG_DISABLE ( DBGLVL_IO );
1705+ reg = readb ( icp->regs + ICP_PHYCTRL );
1706+ reg &= ~mask;
1707+ reg |= ( data & mask );
1708+ writeb ( reg, icp->regs + ICP_PHYCTRL );
1709+ readb ( icp->regs + ICP_PHYCTRL ); /* Ensure write reaches chip */
1710+ DBG_ENABLE ( DBGLVL_IO );
1711+}
1712+
1713+/** MII bit-bashing interface */
1714+static struct bit_basher_operations icplus_basher_ops = {
1715+ .read = icplus_mii_read_bit,
1716+ .write = icplus_mii_write_bit,
1717+};
1718+
1719+/******************************************************************************
1720+ *
1721+ * Link state
1722+ *
1723+ ******************************************************************************
1724+ */
1725+
1726+/**
1727+ * Configure PHY
1728+ *
1729+ * @v icp IC+ device
1730+ * @ret rc Return status code
1731+ */
1732+static int icplus_init_phy ( struct icplus_nic *icp ) {
1733+ uint32_t asicctrl;
1734+ int rc;
1735+
1736+ /* Find PHY address */
1737+ if ( ( rc = mii_find ( &icp->mii ) ) != 0 ) {
1738+ DBGC ( icp, "ICPLUS %p could not find PHY address: %s\n",
1739+ icp, strerror ( rc ) );
1740+ return rc;
1741+ }
1742+
1743+ /* Configure PHY to advertise 1000Mbps if applicable */
1744+ asicctrl = readl ( icp->regs + ICP_ASICCTRL );
1745+ if ( asicctrl & ICP_ASICCTRL_PHYSPEED1000 ) {
1746+ if ( ( rc = mii_write ( &icp->mii, MII_CTRL1000,
1747+ ADVERTISE_1000FULL ) ) != 0 ) {
1748+ DBGC ( icp, "ICPLUS %p could not advertise 1000Mbps: "
1749+ "%s\n", icp, strerror ( rc ) );
1750+ return rc;
1751+ }
1752+ }
1753+
1754+ /* Reset PHY */
1755+ if ( ( rc = mii_reset ( &icp->mii ) ) != 0 ) {
1756+ DBGC ( icp, "ICPLUS %p could not reset PHY: %s\n",
1757+ icp, strerror ( rc ) );
1758+ return rc;
1759+ }
1760+
1761+ return 0;
1762+}
1763+
1764+/**
1765+ * Check link state
1766+ *
1767+ * @v netdev Network device
1768+ */
1769+static void icplus_check_link ( struct net_device *netdev ) {
1770+ struct icplus_nic *icp = netdev->priv;
1771+ uint8_t phyctrl;
1772+
1773+ /* Read link status */
1774+ phyctrl = readb ( icp->regs + ICP_PHYCTRL );
1775+ DBGC ( icp, "ICPLUS %p PHY control is %02x\n", icp, phyctrl );
1776+
1777+ /* Update network device */
1778+ if ( phyctrl & ICP_PHYCTRL_LINKSPEED ) {
1779+ netdev_link_up ( netdev );
1780+ } else {
1781+ netdev_link_down ( netdev );
1782+ }
1783+}
1784+
1785+/******************************************************************************
1786+ *
1787+ * Network device interface
1788+ *
1789+ ******************************************************************************
1790+ */
1791+
1792+/**
1793+ * Set descriptor ring base address
1794+ *
1795+ * @v icp IC+ device
1796+ * @v offset Register offset
1797+ * @v address Base address
1798+ */
1799+static inline void icplus_set_base ( struct icplus_nic *icp, unsigned int offset,
1800+ void *base ) {
1801+ physaddr_t phys = virt_to_bus ( base );
1802+
1803+ /* Program base address registers */
1804+ writel ( ( phys & 0xffffffffUL ),
1805+ ( icp->regs + offset + ICP_BASE_LO ) );
1806+ if ( sizeof ( phys ) > sizeof ( uint32_t ) ) {
1807+ writel ( ( ( ( uint64_t ) phys ) >> 32 ),
1808+ ( icp->regs + offset + ICP_BASE_HI ) );
1809+ } else {
1810+ writel ( 0, ( icp->regs + offset + ICP_BASE_HI ) );
1811+ }
1812+}
1813+
1814+/**
1815+ * Create descriptor ring
1816+ *
1817+ * @v icp IC+ device
1818+ * @v ring Descriptor ring
1819+ * @ret rc Return status code
1820+ */
1821+static int icplus_create_ring ( struct icplus_nic *icp, struct icplus_ring *ring ) {
1822+ size_t len = ( sizeof ( ring->entry[0] ) * ICP_NUM_DESC );
1823+ int rc;
1824+ unsigned int i;
1825+ struct icplus_descriptor *desc;
1826+ struct icplus_descriptor *next;
1827+
1828+ /* Allocate descriptor ring */
1829+ ring->entry = malloc_dma ( len, ICP_ALIGN );
1830+ if ( ! ring->entry ) {
1831+ rc = -ENOMEM;
1832+ goto err_alloc;
1833+ }
1834+
1835+ /* Initialise descriptor ring */
1836+ memset ( ring->entry, 0, len );
1837+ for ( i = 0 ; i < ICP_NUM_DESC ; i++ ) {
1838+ desc = &ring->entry[i];
1839+ next = &ring->entry[ ( i + 1 ) % ICP_NUM_DESC ];
1840+ desc->next = cpu_to_le64 ( virt_to_bus ( next ) );
1841+ desc->flags = ( ICP_TX_UNALIGN | ICP_TX_INDICATE );
1842+ desc->control = ( ICP_TX_SOLE_FRAG | ICP_DONE );
1843+ }
1844+
1845+ /* Reset transmit producer & consumer counters */
1846+ ring->prod = 0;
1847+ ring->cons = 0;
1848+
1849+ DBGC ( icp, "ICP %p %s ring at [%#08lx,%#08lx)\n",
1850+ icp, ( ( ring->listptr == ICP_TFDLISTPTR ) ? "TX" : "RX" ),
1851+ virt_to_bus ( ring->entry ),
1852+ ( virt_to_bus ( ring->entry ) + len ) );
1853+ return 0;
1854+
1855+ free_dma ( ring->entry, len );
1856+ ring->entry = NULL;
1857+ err_alloc:
1858+ return rc;
1859+}
1860+
1861+/**
1862+ * Destroy descriptor ring
1863+ *
1864+ * @v icp IC+ device
1865+ * @v ring Descriptor ring
1866+ */
1867+static void icplus_destroy_ring ( struct icplus_nic *icp __unused,
1868+ struct icplus_ring *ring ) {
1869+ size_t len = ( sizeof ( ring->entry[0] ) * ICP_NUM_DESC );
1870+
1871+ /* Free descriptor ring */
1872+ free_dma ( ring->entry, len );
1873+ ring->entry = NULL;
1874+}
1875+
1876+/**
1877+ * Refill receive descriptor ring
1878+ *
1879+ * @v icp IC+ device
1880+ */
1881+void icplus_refill_rx ( struct icplus_nic *icp ) {
1882+ struct icplus_descriptor *desc;
1883+ struct io_buffer *iobuf;
1884+ unsigned int rx_idx;
1885+ physaddr_t address;
1886+ unsigned int refilled = 0;
1887+
1888+ /* Refill ring */
1889+ while ( ( icp->rx.prod - icp->rx.cons ) < ICP_NUM_DESC ) {
1890+
1891+ /* Allocate I/O buffer */
1892+ iobuf = alloc_iob ( ICP_RX_MAX_LEN );
1893+ if ( ! iobuf ) {
1894+ /* Wait for next refill */
1895+ break;
1896+ }
1897+
1898+ /* Get next receive descriptor */
1899+ rx_idx = ( icp->rx.prod++ % ICP_NUM_DESC );
1900+ desc = &icp->rx.entry[rx_idx];
1901+
1902+ /* Populate receive descriptor */
1903+ address = virt_to_bus ( iobuf->data );
1904+ desc->data.address = cpu_to_le64 ( address );
1905+ desc->data.len = cpu_to_le16 ( ICP_RX_MAX_LEN );
1906+ wmb();
1907+ desc->control = 0;
1908+
1909+ /* Record I/O buffer */
1910+ assert ( icp->rx_iobuf[rx_idx] == NULL );
1911+ icp->rx_iobuf[rx_idx] = iobuf;
1912+
1913+ DBGC2 ( icp, "ICP %p RX %d is [%llx,%llx)\n", icp, rx_idx,
1914+ ( ( unsigned long long ) address ),
1915+ ( ( unsigned long long ) address + ICP_RX_MAX_LEN ) );
1916+ refilled++;
1917+ }
1918+
1919+ /* Push descriptors to card, if applicable */
1920+ if ( refilled ) {
1921+ wmb();
1922+ writew ( ICP_DMACTRL_RXPOLLNOW, icp->regs + ICP_DMACTRL );
1923+ }
1924+}
1925+
1926+/**
1927+ * Open network device
1928+ *
1929+ * @v netdev Network device
1930+ * @ret rc Return status code
1931+ */
1932+static int icplus_open ( struct net_device *netdev ) {
1933+ struct icplus_nic *icp = netdev->priv;
1934+ int rc;
1935+
1936+ /* Create transmit descriptor ring */
1937+ if ( ( rc = icplus_create_ring ( icp, &icp->tx ) ) != 0 )
1938+ goto err_create_tx;
1939+
1940+ /* Create receive descriptor ring */
1941+ if ( ( rc = icplus_create_ring ( icp, &icp->rx ) ) != 0 )
1942+ goto err_create_rx;
1943+
1944+ /* Program descriptor base address */
1945+ icplus_set_base ( icp, icp->tx.listptr, icp->tx.entry );
1946+ icplus_set_base ( icp, icp->rx.listptr, icp->rx.entry );
1947+
1948+ /* Enable receive mode */
1949+ writew ( ( ICP_RXMODE_UNICAST | ICP_RXMODE_MULTICAST |
1950+ ICP_RXMODE_BROADCAST | ICP_RXMODE_ALLFRAMES ),
1951+ icp->regs + ICP_RXMODE );
1952+
1953+ /* Enable transmitter and receiver */
1954+ writel ( ( ICP_MACCTRL_TXENABLE | ICP_MACCTRL_RXENABLE |
1955+ ICP_MACCTRL_DUPLEX ), icp->regs + ICP_MACCTRL );
1956+
1957+ /* Fill receive ring */
1958+ icplus_refill_rx ( icp );
1959+
1960+ /* Check link state */
1961+ icplus_check_link ( netdev );
1962+
1963+ return 0;
1964+
1965+ icplus_reset ( icp );
1966+ icplus_destroy_ring ( icp, &icp->rx );
1967+ err_create_rx:
1968+ icplus_destroy_ring ( icp, &icp->tx );
1969+ err_create_tx:
1970+ return rc;
1971+}
1972+
1973+/**
1974+ * Close network device
1975+ *
1976+ * @v netdev Network device
1977+ */
1978+static void icplus_close ( struct net_device *netdev ) {
1979+ struct icplus_nic *icp = netdev->priv;
1980+ unsigned int i;
1981+
1982+ /* Perform global reset */
1983+ icplus_reset ( icp );
1984+
1985+ /* Destroy receive descriptor ring */
1986+ icplus_destroy_ring ( icp, &icp->rx );
1987+
1988+ /* Destroy transmit descriptor ring */
1989+ icplus_destroy_ring ( icp, &icp->tx );
1990+
1991+ /* Discard any unused receive buffers */
1992+ for ( i = 0 ; i < ICP_NUM_DESC ; i++ ) {
1993+ if ( icp->rx_iobuf[i] )
1994+ free_iob ( icp->rx_iobuf[i] );
1995+ icp->rx_iobuf[i] = NULL;
1996+ }
1997+}
1998+
1999+/**
2000+ * Transmit packet
2001+ *
2002+ * @v netdev Network device
2003+ * @v iobuf I/O buffer
2004+ * @ret rc Return status code
2005+ */
2006+static int icplus_transmit ( struct net_device *netdev,
2007+ struct io_buffer *iobuf ) {
2008+ struct icplus_nic *icp = netdev->priv;
2009+ struct icplus_descriptor *desc;
2010+ unsigned int tx_idx;
2011+ physaddr_t address;
2012+
2013+ /* Check if ring is full */
2014+ if ( ( icp->tx.prod - icp->tx.cons ) >= ICP_NUM_DESC ) {
2015+ DBGC ( icp, "ICP %p out of transmit descriptors\n", icp );
2016+ return -ENOBUFS;
2017+ }
2018+
2019+ /* Find TX descriptor entry to use */
2020+ tx_idx = ( icp->tx.prod++ % ICP_NUM_DESC );
2021+ desc = &icp->tx.entry[tx_idx];
2022+
2023+ /* Fill in TX descriptor */
2024+ address = virt_to_bus ( iobuf->data );
2025+ desc->data.address = cpu_to_le64 ( address );
2026+ desc->data.len = cpu_to_le16 ( iob_len ( iobuf ) );
2027+ wmb();
2028+ desc->control = ICP_TX_SOLE_FRAG;
2029+ wmb();
2030+
2031+ /* Ring doorbell */
2032+ writew ( ICP_DMACTRL_TXPOLLNOW, icp->regs + ICP_DMACTRL );
2033+
2034+ DBGC2 ( icp, "ICP %p TX %d is [%llx,%llx)\n", icp, tx_idx,
2035+ ( ( unsigned long long ) address ),
2036+ ( ( unsigned long long ) address + iob_len ( iobuf ) ) );
2037+ DBGC2_HDA ( icp, virt_to_phys ( desc ), desc, sizeof ( *desc ) );
2038+ return 0;
2039+}
2040+
2041+/**
2042+ * Poll for completed packets
2043+ *
2044+ * @v netdev Network device
2045+ */
2046+static void icplus_poll_tx ( struct net_device *netdev ) {
2047+ struct icplus_nic *icp = netdev->priv;
2048+ struct icplus_descriptor *desc;
2049+ unsigned int tx_idx;
2050+
2051+ /* Check for completed packets */
2052+ while ( icp->tx.cons != icp->tx.prod ) {
2053+
2054+ /* Get next transmit descriptor */
2055+ tx_idx = ( icp->tx.cons % ICP_NUM_DESC );
2056+ desc = &icp->tx.entry[tx_idx];
2057+
2058+ /* Stop if descriptor is still in use */
2059+ if ( ! ( desc->control & ICP_DONE ) )
2060+ return;
2061+
2062+ /* Complete TX descriptor */
2063+ DBGC2 ( icp, "ICP %p TX %d complete\n", icp, tx_idx );
2064+ netdev_tx_complete_next ( netdev );
2065+ icp->tx.cons++;
2066+ }
2067+}
2068+
2069+/**
2070+ * Poll for received packets
2071+ *
2072+ * @v netdev Network device
2073+ */
2074+static void icplus_poll_rx ( struct net_device *netdev ) {
2075+ struct icplus_nic *icp = netdev->priv;
2076+ struct icplus_descriptor *desc;
2077+ struct io_buffer *iobuf;
2078+ unsigned int rx_idx;
2079+ size_t len;
2080+
2081+ /* Check for received packets */
2082+ while ( icp->rx.cons != icp->rx.prod ) {
2083+
2084+ /* Get next transmit descriptor */
2085+ rx_idx = ( icp->rx.cons % ICP_NUM_DESC );
2086+ desc = &icp->rx.entry[rx_idx];
2087+
2088+ /* Stop if descriptor is still in use */
2089+ if ( ! ( desc->control & ICP_DONE ) )
2090+ return;
2091+
2092+ /* Populate I/O buffer */
2093+ iobuf = icp->rx_iobuf[rx_idx];
2094+ icp->rx_iobuf[rx_idx] = NULL;
2095+ len = le16_to_cpu ( desc->len );
2096+ iob_put ( iobuf, len );
2097+
2098+ /* Hand off to network stack */
2099+ if ( desc->flags & ( ICP_RX_ERR_OVERRUN | ICP_RX_ERR_RUNT |
2100+ ICP_RX_ERR_ALIGN | ICP_RX_ERR_FCS |
2101+ ICP_RX_ERR_OVERSIZED | ICP_RX_ERR_LEN ) ) {
2102+ DBGC ( icp, "ICP %p RX %d error (length %zd, "
2103+ "flags %02x)\n", icp, rx_idx, len, desc->flags );
2104+ netdev_rx_err ( netdev, iobuf, -EIO );
2105+ } else {
2106+ DBGC2 ( icp, "ICP %p RX %d complete (length "
2107+ "%zd)\n", icp, rx_idx, len );
2108+ netdev_rx ( netdev, iobuf );
2109+ }
2110+ icp->rx.cons++;
2111+ }
2112+}
2113+
2114+/**
2115+ * Poll for completed and received packets
2116+ *
2117+ * @v netdev Network device
2118+ */
2119+static void icplus_poll ( struct net_device *netdev ) {
2120+ struct icplus_nic *icp = netdev->priv;
2121+ uint16_t intstatus;
2122+ uint32_t txstatus;
2123+
2124+ /* Check for interrupts */
2125+ intstatus = readw ( icp->regs + ICP_INTSTATUS );
2126+
2127+ /* Poll for TX completions, if applicable */
2128+ if ( intstatus & ICP_INTSTATUS_TXCOMPLETE ) {
2129+ txstatus = readl ( icp->regs + ICP_TXSTATUS );
2130+ if ( txstatus & ICP_TXSTATUS_ERROR )
2131+ DBGC ( icp, "ICP %p TX error: %08x\n", icp, txstatus );
2132+ icplus_poll_tx ( netdev );
2133+ }
2134+
2135+ /* Poll for RX completions, if applicable */
2136+ if ( intstatus & ICP_INTSTATUS_RXDMACOMPLETE ) {
2137+ writew ( ICP_INTSTATUS_RXDMACOMPLETE, icp->regs + ICP_INTSTATUS );
2138+ icplus_poll_rx ( netdev );
2139+ }
2140+
2141+ /* Check link state, if applicable */
2142+ if ( intstatus & ICP_INTSTATUS_LINKEVENT ) {
2143+ writew ( ICP_INTSTATUS_LINKEVENT, icp->regs + ICP_INTSTATUS );
2144+ icplus_check_link ( netdev );
2145+ }
2146+
2147+ /* Refill receive ring */
2148+ icplus_refill_rx ( icp );
2149+}
2150+
2151+/**
2152+ * Enable or disable interrupts
2153+ *
2154+ * @v netdev Network device
2155+ * @v enable Interrupts should be enabled
2156+ */
2157+static void icplus_irq ( struct net_device *netdev, int enable ) {
2158+ struct icplus_nic *icp = netdev->priv;
2159+
2160+ DBGC ( icp, "ICPLUS %p does not yet support interrupts\n", icp );
2161+ ( void ) enable;
2162+}
2163+
2164+/** IC+ network device operations */
2165+static struct net_device_operations icplus_operations = {
2166+ .open = icplus_open,
2167+ .close = icplus_close,
2168+ .transmit = icplus_transmit,
2169+ .poll = icplus_poll,
2170+ .irq = icplus_irq,
2171+};
2172+
2173+/******************************************************************************
2174+ *
2175+ * PCI interface
2176+ *
2177+ ******************************************************************************
2178+ */
2179+
2180+/**
2181+ * Probe PCI device
2182+ *
2183+ * @v pci PCI device
2184+ * @ret rc Return status code
2185+ */
2186+static int icplus_probe ( struct pci_device *pci ) {
2187+ struct net_device *netdev;
2188+ struct icplus_nic *icp;
2189+ int rc;
2190+
2191+ /* Allocate and initialise net device */
2192+ netdev = alloc_etherdev ( sizeof ( *icp ) );
2193+ if ( ! netdev ) {
2194+ rc = -ENOMEM;
2195+ goto err_alloc;
2196+ }
2197+ netdev_init ( netdev, &icplus_operations );
2198+ icp = netdev->priv;
2199+ pci_set_drvdata ( pci, netdev );
2200+ netdev->dev = &pci->dev;
2201+ memset ( icp, 0, sizeof ( *icp ) );
2202+ icp->miibit.basher.op = &icplus_basher_ops;
2203+ init_mii_bit_basher ( &icp->miibit );
2204+ mii_init ( &icp->mii, &icp->miibit.mdio, 0 );
2205+ icp->tx.listptr = ICP_TFDLISTPTR;
2206+ icp->rx.listptr = ICP_RFDLISTPTR;
2207+
2208+ /* Fix up PCI device */
2209+ adjust_pci_device ( pci );
2210+
2211+ /* Map registers */
2212+ icp->regs = ioremap ( pci->membase, ICP_BAR_SIZE );
2213+ if ( ! icp->regs ) {
2214+ rc = -ENODEV;
2215+ goto err_ioremap;
2216+ }
2217+
2218+ /* Reset the NIC */
2219+ if ( ( rc = icplus_reset ( icp ) ) != 0 )
2220+ goto err_reset;
2221+
2222+ /* Initialise EEPROM */
2223+ icplus_init_eeprom ( icp );
2224+
2225+ /* Read EEPROM MAC address */
2226+ if ( ( rc = nvs_read ( &icp->eeprom, ICP_EEPROM_MAC,
2227+ netdev->hw_addr, ETH_ALEN ) ) != 0 ) {
2228+ DBGC ( icp, "ICPLUS %p could not read EEPROM MAC address: %s\n",
2229+ icp, strerror ( rc ) );
2230+ goto err_eeprom;
2231+ }
2232+
2233+ /* Configure PHY */
2234+ if ( ( rc = icplus_init_phy ( icp ) ) != 0 )
2235+ goto err_phy;
2236+
2237+ /* Register network device */
2238+ if ( ( rc = register_netdev ( netdev ) ) != 0 )
2239+ goto err_register_netdev;
2240+
2241+ /* Set initial link state */
2242+ icplus_check_link ( netdev );
2243+
2244+ return 0;
2245+
2246+ unregister_netdev ( netdev );
2247+ err_register_netdev:
2248+ err_phy:
2249+ err_eeprom:
2250+ icplus_reset ( icp );
2251+ err_reset:
2252+ iounmap ( icp->regs );
2253+ err_ioremap:
2254+ netdev_nullify ( netdev );
2255+ netdev_put ( netdev );
2256+ err_alloc:
2257+ return rc;
2258+}
2259+
2260+/**
2261+ * Remove PCI device
2262+ *
2263+ * @v pci PCI device
2264+ */
2265+static void icplus_remove ( struct pci_device *pci ) {
2266+ struct net_device *netdev = pci_get_drvdata ( pci );
2267+ struct icplus_nic *icp = netdev->priv;
2268+
2269+ /* Unregister network device */
2270+ unregister_netdev ( netdev );
2271+
2272+ /* Reset card */
2273+ icplus_reset ( icp );
2274+
2275+ /* Free network device */
2276+ iounmap ( icp->regs );
2277+ netdev_nullify ( netdev );
2278+ netdev_put ( netdev );
2279+}
2280+
2281+/** IC+ PCI device IDs */
2282+static struct pci_device_id icplus_nics[] = {
2283+ PCI_ROM ( 0x13f0, 0x1023, "ip1000a", "IP1000A", 0 ),
2284+};
2285+
2286+/** IC+ PCI driver */
2287+struct pci_driver icplus_driver __pci_driver = {
2288+ .ids = icplus_nics,
2289+ .id_count = ( sizeof ( icplus_nics ) / sizeof ( icplus_nics[0] ) ),
2290+ .probe = icplus_probe,
2291+ .remove = icplus_remove,
2292+};
2293diff --git a/src/drivers/net/icplus.h b/src/drivers/net/icplus.h
2294new file mode 100644
2295index 0000000..35fa422
2296--- /dev/null
2297+++ b/src/drivers/net/icplus.h
2298@@ -0,0 +1,206 @@
2299+#ifndef _ICPLUS_H
2300+#define _ICPLUS_H
2301+
2302+/** @file
2303+ *
2304+ * IC+ network driver
2305+ *
2306+ */
2307+
2308+#include <ipxe/nvs.h>
2309+#include <ipxe/mii_bit.h>
2310+
2311+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
2312+
2313+/** BAR size */
2314+#define ICP_BAR_SIZE 0x200
2315+
2316+/** Alignment requirement */
2317+#define ICP_ALIGN 0x8
2318+
2319+/** Base address low register offset */
2320+#define ICP_BASE_LO 0x0
2321+
2322+/** Base address high register offset */
2323+#define ICP_BASE_HI 0x4
2324+
2325+/** ASIC control register (double word) */
2326+#define ICP_ASICCTRL 0x30
2327+#define ICP_ASICCTRL_PHYSPEED1000 0x00000040UL /**< PHY speed 1000 */
2328+#define ICP_ASICCTRL_GLOBALRESET 0x00010000UL /**< Global reset */
2329+#define ICP_ASICCTRL_DMA 0x00080000UL /**< DMA */
2330+#define ICP_ASICCTRL_FIFO 0x00100000UL /**< FIFO */
2331+#define ICP_ASICCTRL_NETWORK 0x00200000UL /**< Network */
2332+#define ICP_ASICCTRL_HOST 0x00400000UL /**< Host */
2333+#define ICP_ASICCTRL_AUTOINIT 0x00800000UL /**< Auto init */
2334+#define ICP_ASICCTRL_RESETBUSY 0x04000000UL /**< Reset busy */
2335+
2336+/** Maximum time to wait for reset */
2337+#define ICP_RESET_MAX_WAIT_MS 1000
2338+
2339+/** DMA control register (word/double word) */
2340+#define ICP_DMACTRL 0x00
2341+#define ICP_DMACTRL_RXPOLLNOW 0x0010 /**< Receive poll now */
2342+#define ICP_DMACTRL_TXPOLLNOW 0x1000 /**< Transmit poll now */
2343+
2344+/** EEPROM control register (word) */
2345+#define ICP_EEPROMCTRL 0x4a
2346+#define ICP_EEPROMCTRL_ADDRESS( x ) ( (x) << 0 ) /**< Address */
2347+#define ICP_EEPROMCTRL_OPCODE( x ) ( (x) << 8 ) /**< Opcode */
2348+#define ICP_EEPROMCTRL_OPCODE_READ \
2349+ ICP_EEPROMCTRL_OPCODE ( 2 ) /**< Read register */
2350+#define ICP_EEPROMCTRL_BUSY 0x8000 /**< EEPROM busy */
2351+
2352+/** Maximum time to wait for reading EEPROM */
2353+#define ICP_EEPROM_MAX_WAIT_MS 1000
2354+
2355+/** EEPROM word length */
2356+#define ICP_EEPROM_WORD_LEN_LOG2 1
2357+
2358+/** Minimum EEPROM size, in words */
2359+#define ICP_EEPROM_MIN_SIZE_WORDS 0x20
2360+
2361+/** Address of MAC address within EEPROM */
2362+#define ICP_EEPROM_MAC 0x10
2363+
2364+/** EEPROM data register (word) */
2365+#define ICP_EEPROMDATA 0x48
2366+
2367+/** Interupt status register (word) */
2368+#define ICP_INTSTATUS 0x5e
2369+#define ICP_INTSTATUS_TXCOMPLETE 0x0004 /**< TX complete */
2370+#define ICP_INTSTATUS_LINKEVENT 0x0100 /**< Link event */
2371+#define ICP_INTSTATUS_RXDMACOMPLETE 0x0400 /**< RX DMA complete */
2372+
2373+/** MAC control register (double word) */
2374+#define ICP_MACCTRL 0x6c
2375+#define ICP_MACCTRL_DUPLEX 0x00000020UL /**< Duplex select */
2376+#define ICP_MACCTRL_TXENABLE 0x01000000UL /**< TX enable */
2377+#define ICP_MACCTRL_TXDISABLE 0x02000000UL /**< TX disable */
2378+#define ICP_MACCTRL_RXENABLE 0x08000000UL /**< RX enable */
2379+#define ICP_MACCTRL_RXDISABLE 0x10000000UL /**< RX disable */
2380+
2381+/** PHY control register (byte) */
2382+#define ICP_PHYCTRL 0x76
2383+#define ICP_PHYCTRL_MGMTCLK 0x01 /**< Management clock */
2384+#define ICP_PHYCTRL_MGMTDATA 0x02 /**< Management data */
2385+#define ICP_PHYCTRL_MGMTDIR 0x04 /**< Management direction */
2386+#define ICP_PHYCTRL_LINKSPEED 0xc0 /**< Link speed */
2387+
2388+/** Receive mode register (word) */
2389+#define ICP_RXMODE 0x88
2390+#define ICP_RXMODE_UNICAST 0x0001 /**< Receive unicast */
2391+#define ICP_RXMODE_MULTICAST 0x0002 /**< Receice multicast */
2392+#define ICP_RXMODE_BROADCAST 0x0004 /**< Receive broadcast */
2393+#define ICP_RXMODE_ALLFRAMES 0x0008 /**< Receive all frames */
2394+
2395+/** List pointer receive register */
2396+#define ICP_RFDLISTPTR 0x1c
2397+
2398+/** List pointer transmit register */
2399+#define ICP_TFDLISTPTR 0x10
2400+
2401+/** Transmit status register */
2402+#define ICP_TXSTATUS 0x60
2403+#define ICP_TXSTATUS_ERROR 0x00000001UL /**< TX error */
2404+
2405+/** Data fragment */
2406+union icplus_fragment {
2407+ /** Address of data */
2408+ uint64_t address;
2409+ /** Length */
2410+ struct {
2411+ /** Reserved */
2412+ uint8_t reserved[6];
2413+ /** Length of data */
2414+ uint16_t len;
2415+ };
2416+};
2417+
2418+/** Transmit or receive descriptor */
2419+struct icplus_descriptor {
2420+ /** Address of next descriptor */
2421+ uint64_t next;
2422+ /** Actual length */
2423+ uint16_t len;
2424+ /** Flags */
2425+ uint8_t flags;
2426+ /** Control */
2427+ uint8_t control;
2428+ /** VLAN */
2429+ uint16_t vlan;
2430+ /** Reserved */
2431+ uint16_t reserved_a;
2432+ /** Data buffer */
2433+ union icplus_fragment data;
2434+ /** Reserved */
2435+ uint8_t reserved_b[8];
2436+};
2437+
2438+/** Descriptor complete */
2439+#define ICP_DONE 0x80
2440+
2441+/** Transmit alignment disabled */
2442+#define ICP_TX_UNALIGN 0x01
2443+
2444+/** Request transmit completion */
2445+#define ICP_TX_INDICATE 0x40
2446+
2447+/** Sole transmit fragment */
2448+#define ICP_TX_SOLE_FRAG 0x01
2449+
2450+/** Recieve frame overrun error */
2451+#define ICP_RX_ERR_OVERRUN 0x01
2452+
2453+/** Receive runt frame error */
2454+#define ICP_RX_ERR_RUNT 0x02
2455+
2456+/** Receive alignment error */
2457+#define ICP_RX_ERR_ALIGN 0x04
2458+
2459+/** Receive FCS error */
2460+#define ICP_RX_ERR_FCS 0x08
2461+
2462+/** Receive oversized frame error */
2463+#define ICP_RX_ERR_OVERSIZED 0x10
2464+
2465+/** Recieve length error */
2466+#define ICP_RX_ERR_LEN 0x20
2467+
2468+/** Descriptor ring */
2469+struct icplus_ring {
2470+ /** Producer counter */
2471+ unsigned int prod;
2472+ /** Consumer counter */
2473+ unsigned int cons;
2474+ /** Ring entries */
2475+ struct icplus_descriptor *entry;
2476+ /* List pointer register */
2477+ unsigned int listptr;
2478+};
2479+
2480+/** Number of descriptors */
2481+#define ICP_NUM_DESC 4
2482+
2483+/** Maximum receive packet length */
2484+#define ICP_RX_MAX_LEN ETH_FRAME_LEN
2485+
2486+/** An IC+ network card */
2487+struct icplus_nic {
2488+ /** Registers */
2489+ void *regs;
2490+ /** EEPROM */
2491+ struct nvs_device eeprom;
2492+ /** MII bit bashing interface */
2493+ struct mii_bit_basher miibit;
2494+ /** MII device */
2495+ struct mii_device mii;
2496+ /** Transmit descriptor ring */
2497+ struct icplus_ring tx;
2498+ /** Receive descriptor ring */
2499+ struct icplus_ring rx;
2500+ /** Receive I/O buffers */
2501+ struct io_buffer *rx_iobuf[ICP_NUM_DESC];
2502+};
2503+
2504+#endif /* _ICPLUS_H */
2505diff --git a/src/drivers/net/intel.c b/src/drivers/net/intel.c
2506index dc511b8..a2e6d53 100644
2507--- a/src/drivers/net/intel.c
2508+++ b/src/drivers/net/intel.c
2509@@ -635,10 +635,23 @@ void intel_empty_rx ( struct intel_nic *intel ) {
2510 static int intel_open ( struct net_device *netdev ) {
2511 struct intel_nic *intel = netdev->priv;
2512 union intel_receive_address mac;
2513+ uint32_t fextnvm11;
2514 uint32_t tctl;
2515 uint32_t rctl;
2516 int rc;
2517
2518+ /* Set undocumented bit in FEXTNVM11 to work around an errata
2519+ * in i219 devices that will otherwise cause a complete
2520+ * datapath hang at the next device reset.
2521+ */
2522+ if ( intel->flags & INTEL_RST_HANG ) {
2523+ DBGC ( intel, "INTEL %p WARNING: applying reset hang "
2524+ "workaround\n", intel );
2525+ fextnvm11 = readl ( intel->regs + INTEL_FEXTNVM11 );
2526+ fextnvm11 |= INTEL_FEXTNVM11_WTF;
2527+ writel ( fextnvm11, intel->regs + INTEL_FEXTNVM11 );
2528+ }
2529+
2530 /* Create transmit descriptor ring */
2531 if ( ( rc = intel_create_ring ( intel, &intel->tx ) ) != 0 )
2532 goto err_create_tx;
2533@@ -1123,20 +1136,21 @@ static struct pci_device_id intel_nics[] = {
2534 PCI_ROM ( 0x8086, 0x153b, "i217v", "I217-V", 0 ),
2535 PCI_ROM ( 0x8086, 0x1559, "i218v", "I218-V", 0),
2536 PCI_ROM ( 0x8086, 0x155a, "i218lm", "I218-LM", 0),
2537- PCI_ROM ( 0x8086, 0x156f, "i219lm", "I219-LM", 0 ),
2538- PCI_ROM ( 0x8086, 0x1570, "i219v", "I219-V", INTEL_NO_PHY_RST ),
2539+ PCI_ROM ( 0x8086, 0x156f, "i219lm", "I219-LM", INTEL_I219 ),
2540+ PCI_ROM ( 0x8086, 0x1570, "i219v", "I219-V", INTEL_I219 ),
2541 PCI_ROM ( 0x8086, 0x157b, "i210-2", "I210", 0 ),
2542 PCI_ROM ( 0x8086, 0x15a0, "i218lm-2", "I218-LM", INTEL_NO_PHY_RST ),
2543 PCI_ROM ( 0x8086, 0x15a1, "i218v-2", "I218-V", 0 ),
2544 PCI_ROM ( 0x8086, 0x15a2, "i218lm-3", "I218-LM", INTEL_NO_PHY_RST ),
2545 PCI_ROM ( 0x8086, 0x15a3, "i218v-3", "I218-V", INTEL_NO_PHY_RST ),
2546- PCI_ROM ( 0x8086, 0x15b7, "i219lm-2", "I219-LM (2)", INTEL_NO_PHY_RST ),
2547- PCI_ROM ( 0x8086, 0x15b8, "i219v-2", "I219-V (2)", 0 ),
2548- PCI_ROM ( 0x8086, 0x15b9, "i219lm-3", "I219-LM (3)", INTEL_NO_PHY_RST ),
2549- PCI_ROM ( 0x8086, 0x15d6, "i219v-5", "I219-V (5)", INTEL_NO_PHY_RST ),
2550- PCI_ROM ( 0x8086, 0x15d7, "i219lm-4", "I219-LM (4)", INTEL_NO_PHY_RST ),
2551- PCI_ROM ( 0x8086, 0x15d8, "i219v-4", "I219-V (4)", INTEL_NO_PHY_RST ),
2552- PCI_ROM ( 0x8086, 0x15e3, "i219lm-5", "I219-LM (5)", INTEL_NO_PHY_RST ),
2553+ PCI_ROM ( 0x8086, 0x15b7, "i219lm-2", "I219-LM (2)", INTEL_I219 ),
2554+ PCI_ROM ( 0x8086, 0x15b8, "i219v-2", "I219-V (2)", INTEL_I219 ),
2555+ PCI_ROM ( 0x8086, 0x15b9, "i219lm-3", "I219-LM (3)", INTEL_I219 ),
2556+ PCI_ROM ( 0x8086, 0x15d6, "i219v-5", "I219-V (5)", INTEL_I219 ),
2557+ PCI_ROM ( 0x8086, 0x15d7, "i219lm-4", "I219-LM (4)", INTEL_I219 ),
2558+ PCI_ROM ( 0x8086, 0x15d8, "i219v-4", "I219-V (4)", INTEL_I219 ),
2559+ PCI_ROM ( 0x8086, 0x15e3, "i219lm-5", "I219-LM (5)", INTEL_I219 ),
2560+ PCI_ROM ( 0x8086, 0x1f41, "i354", "I354", INTEL_NO_ASDE ),
2561 PCI_ROM ( 0x8086, 0x294c, "82566dc-2", "82566DC-2", 0 ),
2562 PCI_ROM ( 0x8086, 0x2e6e, "cemedia", "CE Media Processor", 0 ),
2563 };
2564diff --git a/src/drivers/net/intel.h b/src/drivers/net/intel.h
2565index 1487768..9d740ef 100644
2566--- a/src/drivers/net/intel.h
2567+++ b/src/drivers/net/intel.h
2568@@ -195,6 +195,10 @@ struct intel_descriptor {
2569 #define INTEL_RAH0 0x05404UL
2570 #define INTEL_RAH0_AV 0x80000000UL /**< Address valid */
2571
2572+/** Future Extended NVM register 11 */
2573+#define INTEL_FEXTNVM11 0x05bbcUL
2574+#define INTEL_FEXTNVM11_WTF 0x00002000UL /**< Don't ask */
2575+
2576 /** Receive address */
2577 union intel_receive_address {
2578 struct {
2579@@ -308,8 +312,13 @@ enum intel_flags {
2580 INTEL_NO_PHY_RST = 0x0004,
2581 /** ASDE is broken */
2582 INTEL_NO_ASDE = 0x0008,
2583+ /** Reset may cause a complete device hang */
2584+ INTEL_RST_HANG = 0x0010,
2585 };
2586
2587+/** The i219 has a seriously broken reset mechanism */
2588+#define INTEL_I219 ( INTEL_NO_PHY_RST | INTEL_RST_HANG )
2589+
2590 /**
2591 * Dump diagnostic information
2592 *
2593diff --git a/src/drivers/net/intelx.c b/src/drivers/net/intelx.c
2594index 0d5fb25..47de90c 100644
2595--- a/src/drivers/net/intelx.c
2596+++ b/src/drivers/net/intelx.c
2597@@ -474,6 +474,8 @@ static struct pci_device_id intelx_nics[] = {
2598 PCI_ROM ( 0x8086, 0x1557, "82599en-sfp", "82599 (Single Port SFI Only)", 0 ),
2599 PCI_ROM ( 0x8086, 0x1560, "x540t1", "X540-AT2/X540-BT2 (with single port NVM)", 0 ),
2600 PCI_ROM ( 0x8086, 0x1563, "x550t2", "X550-T2", 0 ),
2601+ PCI_ROM ( 0x8086, 0x15ab, "x552", "X552", 0 ),
2602+ PCI_ROM ( 0x8086, 0x15e5, "x553", "X553", 0 ),
2603 };
2604
2605 /** PCI driver */
2606diff --git a/src/drivers/net/intelxl.c b/src/drivers/net/intelxl.c
2607new file mode 100644
2608index 0000000..3e40fa4
2609--- /dev/null
2610+++ b/src/drivers/net/intelxl.c
2611@@ -0,0 +1,1525 @@
2612+/*
2613+ * Copyright (C) 2018 Michael Brown <mbrown@fensystems.co.uk>.
2614+ *
2615+ * This program is free software; you can redistribute it and/or
2616+ * modify it under the terms of the GNU General Public License as
2617+ * published by the Free Software Foundation; either version 2 of the
2618+ * License, or (at your option) any later version.
2619+ *
2620+ * This program is distributed in the hope that it will be useful, but
2621+ * WITHOUT ANY WARRANTY; without even the implied warranty of
2622+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2623+ * General Public License for more details.
2624+ *
2625+ * You should have received a copy of the GNU General Public License
2626+ * along with this program; if not, write to the Free Software
2627+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
2628+ * 02110-1301, USA.
2629+ *
2630+ * You can also choose to distribute this program under the terms of
2631+ * the Unmodified Binary Distribution Licence (as given in the file
2632+ * COPYING.UBDL), provided that you have satisfied its requirements.
2633+ */
2634+
2635+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
2636+
2637+#include <stdint.h>
2638+#include <string.h>
2639+#include <stdio.h>
2640+#include <unistd.h>
2641+#include <errno.h>
2642+#include <byteswap.h>
2643+#include <ipxe/netdevice.h>
2644+#include <ipxe/ethernet.h>
2645+#include <ipxe/if_ether.h>
2646+#include <ipxe/iobuf.h>
2647+#include <ipxe/malloc.h>
2648+#include <ipxe/pci.h>
2649+#include <ipxe/version.h>
2650+#include "intelxl.h"
2651+
2652+/** @file
2653+ *
2654+ * Intel 40 Gigabit Ethernet network card driver
2655+ *
2656+ */
2657+
2658+/******************************************************************************
2659+ *
2660+ * Device reset
2661+ *
2662+ ******************************************************************************
2663+ */
2664+
2665+/**
2666+ * Reset hardware
2667+ *
2668+ * @v intelxl Intel device
2669+ * @ret rc Return status code
2670+ */
2671+static int intelxl_reset ( struct intelxl_nic *intelxl ) {
2672+ uint32_t pfgen_ctrl;
2673+
2674+ /* Perform a global software reset */
2675+ pfgen_ctrl = readl ( intelxl->regs + INTELXL_PFGEN_CTRL );
2676+ writel ( ( pfgen_ctrl | INTELXL_PFGEN_CTRL_PFSWR ),
2677+ intelxl->regs + INTELXL_PFGEN_CTRL );
2678+ mdelay ( INTELXL_RESET_DELAY_MS );
2679+
2680+ return 0;
2681+}
2682+
2683+/******************************************************************************
2684+ *
2685+ * MAC address
2686+ *
2687+ ******************************************************************************
2688+ */
2689+
2690+/**
2691+ * Fetch initial MAC address and maximum frame size
2692+ *
2693+ * @v intelxl Intel device
2694+ * @v netdev Network device
2695+ * @ret rc Return status code
2696+ */
2697+static int intelxl_fetch_mac ( struct intelxl_nic *intelxl,
2698+ struct net_device *netdev ) {
2699+ union intelxl_receive_address mac;
2700+ uint32_t prtgl_sal;
2701+ uint32_t prtgl_sah;
2702+ size_t mfs;
2703+
2704+ /* Read NVM-loaded address */
2705+ prtgl_sal = readl ( intelxl->regs + INTELXL_PRTGL_SAL );
2706+ prtgl_sah = readl ( intelxl->regs + INTELXL_PRTGL_SAH );
2707+ mac.reg.low = cpu_to_le32 ( prtgl_sal );
2708+ mac.reg.high = cpu_to_le32 ( prtgl_sah );
2709+
2710+ /* Check that address is valid */
2711+ if ( ! is_valid_ether_addr ( mac.raw ) ) {
2712+ DBGC ( intelxl, "INTELXL %p has invalid MAC address (%s)\n",
2713+ intelxl, eth_ntoa ( mac.raw ) );
2714+ return -ENOENT;
2715+ }
2716+
2717+ /* Copy MAC address */
2718+ DBGC ( intelxl, "INTELXL %p has autoloaded MAC address %s\n",
2719+ intelxl, eth_ntoa ( mac.raw ) );
2720+ memcpy ( netdev->hw_addr, mac.raw, ETH_ALEN );
2721+
2722+ /* Get maximum frame size */
2723+ mfs = INTELXL_PRTGL_SAH_MFS_GET ( prtgl_sah );
2724+ netdev->max_pkt_len = ( mfs - 4 /* CRC */ );
2725+
2726+ return 0;
2727+}
2728+
2729+/******************************************************************************
2730+ *
2731+ * Admin queue
2732+ *
2733+ ******************************************************************************
2734+ */
2735+
2736+/**
2737+ * Create admin queue
2738+ *
2739+ * @v intelxl Intel device
2740+ * @v admin Admin queue
2741+ * @ret rc Return status code
2742+ */
2743+static int intelxl_create_admin ( struct intelxl_nic *intelxl,
2744+ struct intelxl_admin *admin ) {
2745+ size_t len = ( sizeof ( admin->desc[0] ) * INTELXL_ADMIN_NUM_DESC );
2746+ void *admin_regs = ( intelxl->regs + admin->reg );
2747+ physaddr_t address;
2748+
2749+ /* Allocate admin queue */
2750+ admin->desc = malloc_dma ( ( len + sizeof ( *admin->buffer ) ),
2751+ INTELXL_ALIGN );
2752+ if ( ! admin->desc )
2753+ return -ENOMEM;
2754+ admin->buffer = ( ( ( void * ) admin->desc ) + len );
2755+
2756+ /* Initialise admin queue */
2757+ memset ( admin->desc, 0, len );
2758+
2759+ /* Reset head and tail registers */
2760+ writel ( 0, admin_regs + INTELXL_ADMIN_HEAD );
2761+ writel ( 0, admin_regs + INTELXL_ADMIN_TAIL );
2762+
2763+ /* Reset queue index */
2764+ admin->index = 0;
2765+
2766+ /* Program queue address */
2767+ address = virt_to_bus ( admin->desc );
2768+ writel ( ( address & 0xffffffffUL ), admin_regs + INTELXL_ADMIN_BAL );
2769+ if ( sizeof ( physaddr_t ) > sizeof ( uint32_t ) ) {
2770+ writel ( ( ( ( uint64_t ) address ) >> 32 ),
2771+ admin_regs + INTELXL_ADMIN_BAH );
2772+ } else {
2773+ writel ( 0, admin_regs + INTELXL_ADMIN_BAH );
2774+ }
2775+
2776+ /* Program queue length and enable queue */
2777+ writel ( ( INTELXL_ADMIN_LEN_LEN ( INTELXL_ADMIN_NUM_DESC ) |
2778+ INTELXL_ADMIN_LEN_ENABLE ),
2779+ admin_regs + INTELXL_ADMIN_LEN );
2780+
2781+ DBGC ( intelxl, "INTELXL %p A%cQ is at [%08llx,%08llx) buf "
2782+ "[%08llx,%08llx)\n", intelxl,
2783+ ( ( admin->reg == INTELXL_ADMIN_CMD ) ? 'T' : 'R' ),
2784+ ( ( unsigned long long ) address ),
2785+ ( ( unsigned long long ) address + len ),
2786+ ( ( unsigned long long ) virt_to_bus ( admin->buffer ) ),
2787+ ( ( unsigned long long ) ( virt_to_bus ( admin->buffer ) +
2788+ sizeof ( admin->buffer[0] ) ) ) );
2789+ return 0;
2790+}
2791+
2792+/**
2793+ * Destroy admin queue
2794+ *
2795+ * @v intelxl Intel device
2796+ * @v admin Admin queue
2797+ */
2798+static void intelxl_destroy_admin ( struct intelxl_nic *intelxl,
2799+ struct intelxl_admin *admin ) {
2800+ size_t len = ( sizeof ( admin->desc[0] ) * INTELXL_ADMIN_NUM_DESC );
2801+ void *admin_regs = ( intelxl->regs + admin->reg );
2802+
2803+ /* Disable queue */
2804+ writel ( 0, admin_regs + INTELXL_ADMIN_LEN );
2805+
2806+ /* Free queue */
2807+ free_dma ( admin->desc, ( len + sizeof ( *admin->buffer ) ) );
2808+}
2809+
2810+/**
2811+ * Issue admin queue command
2812+ *
2813+ * @v intelxl Intel device
2814+ * @v cmd Command descriptor
2815+ * @ret rc Return status code
2816+ */
2817+static int intelxl_admin_command ( struct intelxl_nic *intelxl,
2818+ struct intelxl_admin_descriptor *cmd ) {
2819+ struct intelxl_admin *admin = &intelxl->command;
2820+ void *admin_regs = ( intelxl->regs + admin->reg );
2821+ struct intelxl_admin_descriptor *desc;
2822+ uint64_t buffer;
2823+ unsigned int index;
2824+ unsigned int tail;
2825+ unsigned int i;
2826+ int rc;
2827+
2828+ /* Get next queue entry */
2829+ index = admin->index++;
2830+ tail = ( admin->index % INTELXL_ADMIN_NUM_DESC );
2831+ desc = &admin->desc[index % INTELXL_ADMIN_NUM_DESC];
2832+
2833+ /* Clear must-be-zero flags */
2834+ cmd->flags &= ~cpu_to_le16 ( INTELXL_ADMIN_FL_DD |
2835+ INTELXL_ADMIN_FL_CMP |
2836+ INTELXL_ADMIN_FL_ERR );
2837+
2838+ /* Clear return value */
2839+ cmd->ret = 0;
2840+
2841+ /* Populate cookie */
2842+ cmd->cookie = cpu_to_le32 ( index );
2843+
2844+ /* Populate data buffer address if applicable */
2845+ if ( cmd->flags & cpu_to_le16 ( INTELXL_ADMIN_FL_BUF ) ) {
2846+ buffer = virt_to_bus ( admin->buffer );
2847+ cmd->params.buffer.high = cpu_to_le32 ( buffer >> 32 );
2848+ cmd->params.buffer.low = cpu_to_le32 ( buffer & 0xffffffffUL );
2849+ }
2850+
2851+ /* Copy command descriptor to queue entry */
2852+ memcpy ( desc, cmd, sizeof ( *desc ) );
2853+ DBGC2 ( intelxl, "INTELXL %p admin command %#x:\n", intelxl, index );
2854+ DBGC2_HDA ( intelxl, virt_to_phys ( desc ), desc, sizeof ( *desc ) );
2855+
2856+ /* Post command descriptor */
2857+ wmb();
2858+ writel ( tail, admin_regs + INTELXL_ADMIN_TAIL );
2859+
2860+ /* Wait for completion */
2861+ for ( i = 0 ; i < INTELXL_ADMIN_MAX_WAIT_MS ; i++ ) {
2862+
2863+ /* If response is not complete, delay 1ms and retry */
2864+ if ( ! ( desc->flags & INTELXL_ADMIN_FL_DD ) ) {
2865+ mdelay ( 1 );
2866+ continue;
2867+ }
2868+ DBGC2 ( intelxl, "INTELXL %p admin command %#x response:\n",
2869+ intelxl, index );
2870+ DBGC2_HDA ( intelxl, virt_to_phys ( desc ), desc,
2871+ sizeof ( *desc ) );
2872+
2873+ /* Check for cookie mismatch */
2874+ if ( desc->cookie != cmd->cookie ) {
2875+ DBGC ( intelxl, "INTELXL %p admin command %#x bad "
2876+ "cookie %#x\n", intelxl, index,
2877+ le32_to_cpu ( desc->cookie ) );
2878+ rc = -EPROTO;
2879+ goto err;
2880+ }
2881+
2882+ /* Check for errors */
2883+ if ( desc->ret != 0 ) {
2884+ DBGC ( intelxl, "INTELXL %p admin command %#x error "
2885+ "%d\n", intelxl, index,
2886+ le16_to_cpu ( desc->ret ) );
2887+ rc = -EIO;
2888+ goto err;
2889+ }
2890+
2891+ /* Copy response back to command descriptor */
2892+ memcpy ( cmd, desc, sizeof ( *cmd ) );
2893+
2894+ /* Success */
2895+ return 0;
2896+ }
2897+
2898+ rc = -ETIMEDOUT;
2899+ DBGC ( intelxl, "INTELXL %p timed out waiting for admin command %#x:\n",
2900+ intelxl, index );
2901+ err:
2902+ DBGC_HDA ( intelxl, virt_to_phys ( desc ), cmd, sizeof ( *cmd ) );
2903+ DBGC_HDA ( intelxl, virt_to_phys ( desc ), desc, sizeof ( *desc ) );
2904+ return rc;
2905+}
2906+
2907+/**
2908+ * Get firmware version
2909+ *
2910+ * @v intelxl Intel device
2911+ * @ret rc Return status code
2912+ */
2913+static int intelxl_admin_version ( struct intelxl_nic *intelxl ) {
2914+ struct intelxl_admin_descriptor cmd;
2915+ struct intelxl_admin_version_params *version = &cmd.params.version;
2916+ unsigned int api;
2917+ int rc;
2918+
2919+ /* Populate descriptor */
2920+ memset ( &cmd, 0, sizeof ( cmd ) );
2921+ cmd.opcode = cpu_to_le16 ( INTELXL_ADMIN_VERSION );
2922+
2923+ /* Issue command */
2924+ if ( ( rc = intelxl_admin_command ( intelxl, &cmd ) ) != 0 )
2925+ return rc;
2926+ api = le16_to_cpu ( version->api.major );
2927+ DBGC ( intelxl, "INTELXL %p firmware v%d.%d API v%d.%d\n",
2928+ intelxl, le16_to_cpu ( version->firmware.major ),
2929+ le16_to_cpu ( version->firmware.minor ),
2930+ api, le16_to_cpu ( version->api.minor ) );
2931+
2932+ /* Check for API compatibility */
2933+ if ( api > INTELXL_ADMIN_API_MAJOR ) {
2934+ DBGC ( intelxl, "INTELXL %p unsupported API v%d\n",
2935+ intelxl, api );
2936+ return -ENOTSUP;
2937+ }
2938+
2939+ return 0;
2940+}
2941+
2942+/**
2943+ * Report driver version
2944+ *
2945+ * @v intelxl Intel device
2946+ * @ret rc Return status code
2947+ */
2948+static int intelxl_admin_driver ( struct intelxl_nic *intelxl ) {
2949+ struct intelxl_admin_descriptor cmd;
2950+ struct intelxl_admin_driver_params *driver = &cmd.params.driver;
2951+ struct intelxl_admin_driver_buffer *buf =
2952+ &intelxl->command.buffer->driver;
2953+ int rc;
2954+
2955+ /* Populate descriptor */
2956+ memset ( &cmd, 0, sizeof ( cmd ) );
2957+ cmd.opcode = cpu_to_le16 ( INTELXL_ADMIN_DRIVER );
2958+ cmd.flags = cpu_to_le16 ( INTELXL_ADMIN_FL_RD | INTELXL_ADMIN_FL_BUF );
2959+ cmd.len = cpu_to_le16 ( sizeof ( *buf ) );
2960+ driver->major = product_major_version;
2961+ driver->minor = product_minor_version;
2962+ snprintf ( buf->name, sizeof ( buf->name ), "%s",
2963+ ( product_name[0] ? product_name : product_short_name ) );
2964+
2965+ /* Issue command */
2966+ if ( ( rc = intelxl_admin_command ( intelxl, &cmd ) ) != 0 )
2967+ return rc;
2968+
2969+ return 0;
2970+}
2971+
2972+/**
2973+ * Shutdown admin queues
2974+ *
2975+ * @v intelxl Intel device
2976+ * @ret rc Return status code
2977+ */
2978+static int intelxl_admin_shutdown ( struct intelxl_nic *intelxl ) {
2979+ struct intelxl_admin_descriptor cmd;
2980+ struct intelxl_admin_shutdown_params *shutdown = &cmd.params.shutdown;
2981+ int rc;
2982+
2983+ /* Populate descriptor */
2984+ memset ( &cmd, 0, sizeof ( cmd ) );
2985+ cmd.opcode = cpu_to_le16 ( INTELXL_ADMIN_SHUTDOWN );
2986+ shutdown->unloading = INTELXL_ADMIN_SHUTDOWN_UNLOADING;
2987+
2988+ /* Issue command */
2989+ if ( ( rc = intelxl_admin_command ( intelxl, &cmd ) ) != 0 )
2990+ return rc;
2991+
2992+ return 0;
2993+}
2994+
2995+/**
2996+ * Get switch configuration
2997+ *
2998+ * @v intelxl Intel device
2999+ * @ret rc Return status code
3000+ */
3001+static int intelxl_admin_switch ( struct intelxl_nic *intelxl ) {
3002+ struct intelxl_admin_descriptor cmd;
3003+ struct intelxl_admin_switch_params *sw = &cmd.params.sw;
3004+ struct intelxl_admin_switch_buffer *buf = &intelxl->command.buffer->sw;
3005+ struct intelxl_admin_switch_config *cfg = &buf->cfg;
3006+ int rc;
3007+
3008+ /* Populate descriptor */
3009+ memset ( &cmd, 0, sizeof ( cmd ) );
3010+ cmd.opcode = cpu_to_le16 ( INTELXL_ADMIN_SWITCH );
3011+ cmd.flags = cpu_to_le16 ( INTELXL_ADMIN_FL_BUF );
3012+ cmd.len = cpu_to_le16 ( sizeof ( *buf ) );
3013+
3014+ /* Get each configuration in turn */
3015+ do {
3016+ /* Issue command */
3017+ if ( ( rc = intelxl_admin_command ( intelxl, &cmd ) ) != 0 )
3018+ return rc;
3019+
3020+ /* Dump raw configuration */
3021+ DBGC2 ( intelxl, "INTELXL %p SEID %#04x:\n",
3022+ intelxl, le16_to_cpu ( cfg->seid ) );
3023+ DBGC2_HDA ( intelxl, 0, cfg, sizeof ( *cfg ) );
3024+
3025+ /* Parse response */
3026+ if ( cfg->type == INTELXL_ADMIN_SWITCH_TYPE_VSI ) {
3027+ intelxl->vsi = le16_to_cpu ( cfg->seid );
3028+ DBGC ( intelxl, "INTELXL %p VSI %#04x uplink %#04x "
3029+ "downlink %#04x conn %#02x\n", intelxl,
3030+ intelxl->vsi, le16_to_cpu ( cfg->uplink ),
3031+ le16_to_cpu ( cfg->downlink ), cfg->connection );
3032+ }
3033+
3034+ } while ( sw->next );
3035+
3036+ /* Check that we found a VSI */
3037+ if ( ! intelxl->vsi ) {
3038+ DBGC ( intelxl, "INTELXL %p has no VSI\n", intelxl );
3039+ return -ENOENT;
3040+ }
3041+
3042+ return 0;
3043+}
3044+
3045+/**
3046+ * Get VSI parameters
3047+ *
3048+ * @v intelxl Intel device
3049+ * @ret rc Return status code
3050+ */
3051+static int intelxl_admin_vsi ( struct intelxl_nic *intelxl ) {
3052+ struct intelxl_admin_descriptor cmd;
3053+ struct intelxl_admin_vsi_params *vsi = &cmd.params.vsi;
3054+ struct intelxl_admin_vsi_buffer *buf = &intelxl->command.buffer->vsi;
3055+ int rc;
3056+
3057+ /* Populate descriptor */
3058+ memset ( &cmd, 0, sizeof ( cmd ) );
3059+ cmd.opcode = cpu_to_le16 ( INTELXL_ADMIN_VSI );
3060+ cmd.flags = cpu_to_le16 ( INTELXL_ADMIN_FL_BUF );
3061+ cmd.len = cpu_to_le16 ( sizeof ( *buf ) );
3062+ vsi->vsi = cpu_to_le16 ( intelxl->vsi );
3063+
3064+ /* Issue command */
3065+ if ( ( rc = intelxl_admin_command ( intelxl, &cmd ) ) != 0 )
3066+ return rc;
3067+
3068+ /* Parse response */
3069+ intelxl->queue = le16_to_cpu ( buf->queue[0] );
3070+ intelxl->qset = le16_to_cpu ( buf->qset[0] );
3071+ DBGC ( intelxl, "INTELXL %p VSI %#04x queue %#04x qset %#04x\n",
3072+ intelxl, intelxl->vsi, intelxl->queue, intelxl->qset );
3073+
3074+ return 0;
3075+}
3076+
3077+/**
3078+ * Set VSI promiscuous modes
3079+ *
3080+ * @v intelxl Intel device
3081+ * @ret rc Return status code
3082+ */
3083+static int intelxl_admin_promisc ( struct intelxl_nic *intelxl ) {
3084+ struct intelxl_admin_descriptor cmd;
3085+ struct intelxl_admin_promisc_params *promisc = &cmd.params.promisc;
3086+ uint16_t flags;
3087+ int rc;
3088+
3089+ /* Populate descriptor */
3090+ memset ( &cmd, 0, sizeof ( cmd ) );
3091+ cmd.opcode = cpu_to_le16 ( INTELXL_ADMIN_PROMISC );
3092+ flags = ( INTELXL_ADMIN_PROMISC_FL_UNICAST |
3093+ INTELXL_ADMIN_PROMISC_FL_MULTICAST |
3094+ INTELXL_ADMIN_PROMISC_FL_BROADCAST |
3095+ INTELXL_ADMIN_PROMISC_FL_VLAN );
3096+ promisc->flags = cpu_to_le16 ( flags );
3097+ promisc->valid = cpu_to_le16 ( flags );
3098+ promisc->vsi = cpu_to_le16 ( intelxl->vsi );
3099+
3100+ /* Issue command */
3101+ if ( ( rc = intelxl_admin_command ( intelxl, &cmd ) ) != 0 )
3102+ return rc;
3103+
3104+ return 0;
3105+}
3106+
3107+/**
3108+ * Restart autonegotiation
3109+ *
3110+ * @v intelxl Intel device
3111+ * @ret rc Return status code
3112+ */
3113+static int intelxl_admin_autoneg ( struct intelxl_nic *intelxl ) {
3114+ struct intelxl_admin_descriptor cmd;
3115+ struct intelxl_admin_autoneg_params *autoneg = &cmd.params.autoneg;
3116+ int rc;
3117+
3118+ /* Populate descriptor */
3119+ memset ( &cmd, 0, sizeof ( cmd ) );
3120+ cmd.opcode = cpu_to_le16 ( INTELXL_ADMIN_AUTONEG );
3121+ autoneg->flags = ( INTELXL_ADMIN_AUTONEG_FL_RESTART |
3122+ INTELXL_ADMIN_AUTONEG_FL_ENABLE );
3123+
3124+ /* Issue command */
3125+ if ( ( rc = intelxl_admin_command ( intelxl, &cmd ) ) != 0 )
3126+ return rc;
3127+
3128+ return 0;
3129+}
3130+
3131+/**
3132+ * Get link status
3133+ *
3134+ * @v netdev Network device
3135+ * @ret rc Return status code
3136+ */
3137+static int intelxl_admin_link ( struct net_device *netdev ) {
3138+ struct intelxl_nic *intelxl = netdev->priv;
3139+ struct intelxl_admin_descriptor cmd;
3140+ struct intelxl_admin_link_params *link = &cmd.params.link;
3141+ int rc;
3142+
3143+ /* Populate descriptor */
3144+ memset ( &cmd, 0, sizeof ( cmd ) );
3145+ cmd.opcode = cpu_to_le16 ( INTELXL_ADMIN_LINK );
3146+ link->notify = INTELXL_ADMIN_LINK_NOTIFY;
3147+
3148+ /* Issue command */
3149+ if ( ( rc = intelxl_admin_command ( intelxl, &cmd ) ) != 0 )
3150+ return rc;
3151+ DBGC ( intelxl, "INTELXL %p PHY %#02x speed %#02x status %#02x\n",
3152+ intelxl, link->phy, link->speed, link->status );
3153+
3154+ /* Update network device */
3155+ if ( link->status & INTELXL_ADMIN_LINK_UP ) {
3156+ netdev_link_up ( netdev );
3157+ } else {
3158+ netdev_link_down ( netdev );
3159+ }
3160+
3161+ return 0;
3162+}
3163+
3164+/**
3165+ * Refill admin event queue
3166+ *
3167+ * @v intelxl Intel device
3168+ */
3169+static void intelxl_refill_admin ( struct intelxl_nic *intelxl ) {
3170+ struct intelxl_admin *admin = &intelxl->event;
3171+ void *admin_regs = ( intelxl->regs + admin->reg );
3172+ unsigned int tail;
3173+
3174+ /* Update tail pointer */
3175+ tail = ( ( admin->index + INTELXL_ADMIN_NUM_DESC - 1 ) %
3176+ INTELXL_ADMIN_NUM_DESC );
3177+ writel ( tail, admin_regs + INTELXL_ADMIN_TAIL );
3178+}
3179+
3180+/**
3181+ * Poll admin event queue
3182+ *
3183+ * @v netdev Network device
3184+ */
3185+static void intelxl_poll_admin ( struct net_device *netdev ) {
3186+ struct intelxl_nic *intelxl = netdev->priv;
3187+ struct intelxl_admin *admin = &intelxl->event;
3188+ struct intelxl_admin_descriptor *desc;
3189+
3190+ /* Check for events */
3191+ while ( 1 ) {
3192+
3193+ /* Get next event descriptor */
3194+ desc = &admin->desc[admin->index % INTELXL_ADMIN_NUM_DESC];
3195+
3196+ /* Stop if descriptor is not yet completed */
3197+ if ( ! ( desc->flags & INTELXL_ADMIN_FL_DD ) )
3198+ return;
3199+ DBGC2 ( intelxl, "INTELXL %p admin event %#x:\n",
3200+ intelxl, admin->index );
3201+ DBGC2_HDA ( intelxl, virt_to_phys ( desc ), desc,
3202+ sizeof ( *desc ) );
3203+
3204+ /* Handle event */
3205+ switch ( desc->opcode ) {
3206+ case cpu_to_le16 ( INTELXL_ADMIN_LINK ):
3207+ intelxl_admin_link ( netdev );
3208+ break;
3209+ default:
3210+ DBGC ( intelxl, "INTELXL %p admin event %#x "
3211+ "unrecognised opcode %#04x\n", intelxl,
3212+ admin->index, le16_to_cpu ( desc->opcode ) );
3213+ break;
3214+ }
3215+
3216+ /* Clear event completion flag */
3217+ desc->flags = 0;
3218+ wmb();
3219+
3220+ /* Update index and refill queue */
3221+ admin->index++;
3222+ intelxl_refill_admin ( intelxl );
3223+ }
3224+}
3225+
3226+/**
3227+ * Open admin queues
3228+ *
3229+ * @v intelxl Intel device
3230+ * @ret rc Return status code
3231+ */
3232+static int intelxl_open_admin ( struct intelxl_nic *intelxl ) {
3233+ int rc;
3234+
3235+ /* Create admin event queue */
3236+ if ( ( rc = intelxl_create_admin ( intelxl, &intelxl->event ) ) != 0 )
3237+ goto err_create_event;
3238+
3239+ /* Create admin command queue */
3240+ if ( ( rc = intelxl_create_admin ( intelxl, &intelxl->command ) ) != 0 )
3241+ goto err_create_command;
3242+
3243+ /* Post all descriptors to event queue */
3244+ intelxl_refill_admin ( intelxl );
3245+
3246+ /* Get firmware version */
3247+ if ( ( rc = intelxl_admin_version ( intelxl ) ) != 0 )
3248+ goto err_version;
3249+
3250+ /* Report driver version */
3251+ if ( ( rc = intelxl_admin_driver ( intelxl ) ) != 0 )
3252+ goto err_driver;
3253+
3254+ return 0;
3255+
3256+ err_driver:
3257+ err_version:
3258+ intelxl_destroy_admin ( intelxl, &intelxl->command );
3259+ err_create_command:
3260+ intelxl_destroy_admin ( intelxl, &intelxl->event );
3261+ err_create_event:
3262+ return rc;
3263+}
3264+
3265+/**
3266+ * Close admin queues
3267+ *
3268+ * @v intelxl Intel device
3269+ */
3270+static void intelxl_close_admin ( struct intelxl_nic *intelxl ) {
3271+
3272+ /* Shut down admin queues */
3273+ intelxl_admin_shutdown ( intelxl );
3274+
3275+ /* Destroy admin command queue */
3276+ intelxl_destroy_admin ( intelxl, &intelxl->command );
3277+
3278+ /* Destroy admin event queue */
3279+ intelxl_destroy_admin ( intelxl, &intelxl->event );
3280+}
3281+
3282+/******************************************************************************
3283+ *
3284+ * Descriptor rings
3285+ *
3286+ ******************************************************************************
3287+ */
3288+
3289+/**
3290+ * Dump queue context (for debugging)
3291+ *
3292+ * @v intelxl Intel device
3293+ * @v op Context operation
3294+ * @v len Size of context
3295+ */
3296+static __attribute__ (( unused )) void
3297+intelxl_context_dump ( struct intelxl_nic *intelxl, uint32_t op, size_t len ) {
3298+ struct intelxl_context_line line;
3299+ uint32_t pfcm_lanctxctl;
3300+ uint32_t pfcm_lanctxstat;
3301+ unsigned int queue;
3302+ unsigned int index;
3303+ unsigned int i;
3304+
3305+ /* Do nothing unless debug output is enabled */
3306+ if ( ! DBG_EXTRA )
3307+ return;
3308+
3309+ /* Dump context */
3310+ DBGC2 ( intelxl, "INTELXL %p context %#08x:\n", intelxl, op );
3311+ for ( index = 0 ; ( sizeof ( line ) * index ) < len ; index++ ) {
3312+
3313+ /* Start context operation */
3314+ queue = ( intelxl->base + intelxl->queue );
3315+ pfcm_lanctxctl =
3316+ ( INTELXL_PFCM_LANCTXCTL_QUEUE_NUM ( queue ) |
3317+ INTELXL_PFCM_LANCTXCTL_SUB_LINE ( index ) |
3318+ INTELXL_PFCM_LANCTXCTL_OP_CODE_READ | op );
3319+ writel ( pfcm_lanctxctl,
3320+ intelxl->regs + INTELXL_PFCM_LANCTXCTL );
3321+
3322+ /* Wait for operation to complete */
3323+ for ( i = 0 ; i < INTELXL_CTX_MAX_WAIT_MS ; i++ ) {
3324+
3325+ /* Check if operation is complete */
3326+ pfcm_lanctxstat = readl ( intelxl->regs +
3327+ INTELXL_PFCM_LANCTXSTAT );
3328+ if ( pfcm_lanctxstat & INTELXL_PFCM_LANCTXSTAT_DONE )
3329+ break;
3330+
3331+ /* Delay */
3332+ mdelay ( 1 );
3333+ }
3334+
3335+ /* Read context data */
3336+ for ( i = 0 ; i < ( sizeof ( line ) /
3337+ sizeof ( line.raw[0] ) ) ; i++ ) {
3338+ line.raw[i] = readl ( intelxl->regs +
3339+ INTELXL_PFCM_LANCTXDATA ( i ) );
3340+ }
3341+ DBGC2_HDA ( intelxl, ( sizeof ( line ) * index ),
3342+ &line, sizeof ( line ) );
3343+ }
3344+}
3345+
3346+/**
3347+ * Program queue context line
3348+ *
3349+ * @v intelxl Intel device
3350+ * @v line Queue context line
3351+ * @v index Line number
3352+ * @v op Context operation
3353+ * @ret rc Return status code
3354+ */
3355+static int intelxl_context_line ( struct intelxl_nic *intelxl,
3356+ struct intelxl_context_line *line,
3357+ unsigned int index, uint32_t op ) {
3358+ uint32_t pfcm_lanctxctl;
3359+ uint32_t pfcm_lanctxstat;
3360+ unsigned int queue;
3361+ unsigned int i;
3362+
3363+ /* Write context data */
3364+ for ( i = 0; i < ( sizeof ( *line ) / sizeof ( line->raw[0] ) ); i++ ) {
3365+ writel ( le32_to_cpu ( line->raw[i] ),
3366+ intelxl->regs + INTELXL_PFCM_LANCTXDATA ( i ) );
3367+ }
3368+
3369+ /* Start context operation */
3370+ queue = ( intelxl->base + intelxl->queue );
3371+ pfcm_lanctxctl = ( INTELXL_PFCM_LANCTXCTL_QUEUE_NUM ( queue ) |
3372+ INTELXL_PFCM_LANCTXCTL_SUB_LINE ( index ) |
3373+ INTELXL_PFCM_LANCTXCTL_OP_CODE_WRITE | op );
3374+ writel ( pfcm_lanctxctl, intelxl->regs + INTELXL_PFCM_LANCTXCTL );
3375+
3376+ /* Wait for operation to complete */
3377+ for ( i = 0 ; i < INTELXL_CTX_MAX_WAIT_MS ; i++ ) {
3378+
3379+ /* Check if operation is complete */
3380+ pfcm_lanctxstat = readl ( intelxl->regs +
3381+ INTELXL_PFCM_LANCTXSTAT );
3382+ if ( pfcm_lanctxstat & INTELXL_PFCM_LANCTXSTAT_DONE )
3383+ return 0;
3384+
3385+ /* Delay */
3386+ mdelay ( 1 );
3387+ }
3388+
3389+ DBGC ( intelxl, "INTELXL %p timed out waiting for context: %#08x\n",
3390+ intelxl, pfcm_lanctxctl );
3391+ return -ETIMEDOUT;
3392+}
3393+
3394+/**
3395+ * Program queue context
3396+ *
3397+ * @v intelxl Intel device
3398+ * @v line Queue context lines
3399+ * @v len Size of context
3400+ * @v op Context operation
3401+ * @ret rc Return status code
3402+ */
3403+static int intelxl_context ( struct intelxl_nic *intelxl,
3404+ struct intelxl_context_line *line,
3405+ size_t len, uint32_t op ) {
3406+ unsigned int index;
3407+ int rc;
3408+
3409+ DBGC2 ( intelxl, "INTELXL %p context %#08x len %#zx:\n",
3410+ intelxl, op, len );
3411+ DBGC2_HDA ( intelxl, 0, line, len );
3412+
3413+ /* Program one line at a time */
3414+ for ( index = 0 ; ( sizeof ( *line ) * index ) < len ; index++ ) {
3415+ if ( ( rc = intelxl_context_line ( intelxl, line++, index,
3416+ op ) ) != 0 )
3417+ return rc;
3418+ }
3419+
3420+ return 0;
3421+}
3422+
3423+/**
3424+ * Program transmit queue context
3425+ *
3426+ * @v intelxl Intel device
3427+ * @v address Descriptor ring base address
3428+ * @ret rc Return status code
3429+ */
3430+static int intelxl_context_tx ( struct intelxl_nic *intelxl,
3431+ physaddr_t address ) {
3432+ union {
3433+ struct intelxl_context_tx tx;
3434+ struct intelxl_context_line line;
3435+ } ctx;
3436+ int rc;
3437+
3438+ /* Initialise context */
3439+ memset ( &ctx, 0, sizeof ( ctx ) );
3440+ ctx.tx.flags = cpu_to_le16 ( INTELXL_CTX_TX_FL_NEW );
3441+ ctx.tx.base = cpu_to_le64 ( INTELXL_CTX_TX_BASE ( address ) );
3442+ ctx.tx.count =
3443+ cpu_to_le16 ( INTELXL_CTX_TX_COUNT ( INTELXL_TX_NUM_DESC ) );
3444+ ctx.tx.qset = INTELXL_CTX_TX_QSET ( intelxl->qset );
3445+
3446+ /* Program context */
3447+ if ( ( rc = intelxl_context ( intelxl, &ctx.line, sizeof ( ctx ),
3448+ INTELXL_PFCM_LANCTXCTL_TYPE_TX ) ) != 0 )
3449+ return rc;
3450+
3451+ return 0;
3452+}
3453+
3454+/**
3455+ * Program receive queue context
3456+ *
3457+ * @v intelxl Intel device
3458+ * @v address Descriptor ring base address
3459+ * @ret rc Return status code
3460+ */
3461+static int intelxl_context_rx ( struct intelxl_nic *intelxl,
3462+ physaddr_t address ) {
3463+ union {
3464+ struct intelxl_context_rx rx;
3465+ struct intelxl_context_line line;
3466+ } ctx;
3467+ uint64_t base_count;
3468+ int rc;
3469+
3470+ /* Initialise context */
3471+ memset ( &ctx, 0, sizeof ( ctx ) );
3472+ base_count = INTELXL_CTX_RX_BASE_COUNT ( address, INTELXL_RX_NUM_DESC );
3473+ ctx.rx.base_count = cpu_to_le64 ( base_count );
3474+ ctx.rx.len = cpu_to_le16 ( INTELXL_CTX_RX_LEN ( intelxl->mfs ) );
3475+ ctx.rx.flags = INTELXL_CTX_RX_FL_CRCSTRIP;
3476+ ctx.rx.mfs = cpu_to_le16 ( INTELXL_CTX_RX_MFS ( intelxl->mfs ) );
3477+
3478+ /* Program context */
3479+ if ( ( rc = intelxl_context ( intelxl, &ctx.line, sizeof ( ctx ),
3480+ INTELXL_PFCM_LANCTXCTL_TYPE_RX ) ) != 0 )
3481+ return rc;
3482+
3483+ return 0;
3484+}
3485+
3486+/**
3487+ * Enable descriptor ring
3488+ *
3489+ * @v intelxl Intel device
3490+ * @v ring Descriptor ring
3491+ * @ret rc Return status code
3492+ */
3493+static int intelxl_enable_ring ( struct intelxl_nic *intelxl,
3494+ struct intelxl_ring *ring ) {
3495+ void *ring_regs = ( intelxl->regs + ring->reg );
3496+ uint32_t qxx_ena;
3497+
3498+ /* Enable ring */
3499+ writel ( INTELXL_QXX_ENA_REQ, ( ring_regs + INTELXL_QXX_ENA ) );
3500+ udelay ( INTELXL_QUEUE_ENABLE_DELAY_US );
3501+ qxx_ena = readl ( ring_regs + INTELXL_QXX_ENA );
3502+ if ( ! ( qxx_ena & INTELXL_QXX_ENA_STAT ) ) {
3503+ DBGC ( intelxl, "INTELXL %p ring %06x failed to enable: "
3504+ "%#08x\n", intelxl, ring->reg, qxx_ena );
3505+ return -EIO;
3506+ }
3507+
3508+ return 0;
3509+}
3510+
3511+/**
3512+ * Disable descriptor ring
3513+ *
3514+ * @v intelxl Intel device
3515+ * @v ring Descriptor ring
3516+ * @ret rc Return status code
3517+ */
3518+static int intelxl_disable_ring ( struct intelxl_nic *intelxl,
3519+ struct intelxl_ring *ring ) {
3520+ void *ring_regs = ( intelxl->regs + ring->reg );
3521+ uint32_t qxx_ena;
3522+ unsigned int i;
3523+
3524+ /* Disable ring */
3525+ writel ( 0, ( ring_regs + INTELXL_QXX_ENA ) );
3526+
3527+ /* Wait for ring to be disabled */
3528+ for ( i = 0 ; i < INTELXL_QUEUE_DISABLE_MAX_WAIT_MS ; i++ ) {
3529+
3530+ /* Check if ring is disabled */
3531+ qxx_ena = readl ( ring_regs + INTELXL_QXX_ENA );
3532+ if ( ! ( qxx_ena & INTELXL_QXX_ENA_STAT ) )
3533+ return 0;
3534+
3535+ /* Delay */
3536+ mdelay ( 1 );
3537+ }
3538+
3539+ DBGC ( intelxl, "INTELXL %p ring %06x timed out waiting for disable: "
3540+ "%#08x\n", intelxl, ring->reg, qxx_ena );
3541+ return -ETIMEDOUT;
3542+}
3543+
3544+/**
3545+ * Create descriptor ring
3546+ *
3547+ * @v intelxl Intel device
3548+ * @v ring Descriptor ring
3549+ * @ret rc Return status code
3550+ */
3551+static int intelxl_create_ring ( struct intelxl_nic *intelxl,
3552+ struct intelxl_ring *ring ) {
3553+ void *ring_regs = ( intelxl->regs + ring->reg );
3554+ physaddr_t address;
3555+ int rc;
3556+
3557+ /* Allocate descriptor ring */
3558+ ring->desc = malloc_dma ( ring->len, INTELXL_ALIGN );
3559+ if ( ! ring->desc ) {
3560+ rc = -ENOMEM;
3561+ goto err_alloc;
3562+ }
3563+
3564+ /* Initialise descriptor ring */
3565+ memset ( ring->desc, 0, ring->len );
3566+
3567+ /* Reset tail pointer */
3568+ writel ( 0, ( ring_regs + INTELXL_QXX_TAIL ) );
3569+
3570+ /* Program queue context */
3571+ address = virt_to_bus ( ring->desc );
3572+ if ( ( rc = ring->context ( intelxl, address ) ) != 0 )
3573+ goto err_context;
3574+
3575+ /* Enable ring */
3576+ if ( ( rc = intelxl_enable_ring ( intelxl, ring ) ) != 0 )
3577+ goto err_enable;
3578+
3579+ /* Reset counters */
3580+ ring->prod = 0;
3581+ ring->cons = 0;
3582+
3583+ DBGC ( intelxl, "INTELXL %p ring %06x is at [%08llx,%08llx)\n",
3584+ intelxl, ring->reg, ( ( unsigned long long ) address ),
3585+ ( ( unsigned long long ) address + ring->len ) );
3586+
3587+ return 0;
3588+
3589+ intelxl_disable_ring ( intelxl, ring );
3590+ err_enable:
3591+ err_context:
3592+ free_dma ( ring->desc, ring->len );
3593+ err_alloc:
3594+ return rc;
3595+}
3596+
3597+/**
3598+ * Destroy descriptor ring
3599+ *
3600+ * @v intelxl Intel device
3601+ * @v ring Descriptor ring
3602+ */
3603+static void intelxl_destroy_ring ( struct intelxl_nic *intelxl,
3604+ struct intelxl_ring *ring ) {
3605+ int rc;
3606+
3607+ /* Disable ring */
3608+ if ( ( rc = intelxl_disable_ring ( intelxl, ring ) ) != 0 ) {
3609+ /* Leak memory; there's nothing else we can do */
3610+ return;
3611+ }
3612+
3613+ /* Free descriptor ring */
3614+ free_dma ( ring->desc, ring->len );
3615+ ring->desc = NULL;
3616+}
3617+
3618+/**
3619+ * Refill receive descriptor ring
3620+ *
3621+ * @v intelxl Intel device
3622+ */
3623+static void intelxl_refill_rx ( struct intelxl_nic *intelxl ) {
3624+ struct intelxl_rx_data_descriptor *rx;
3625+ struct io_buffer *iobuf;
3626+ unsigned int rx_idx;
3627+ unsigned int rx_tail;
3628+ physaddr_t address;
3629+ unsigned int refilled = 0;
3630+
3631+ /* Refill ring */
3632+ while ( ( intelxl->rx.prod - intelxl->rx.cons ) < INTELXL_RX_FILL ) {
3633+
3634+ /* Allocate I/O buffer */
3635+ iobuf = alloc_iob ( intelxl->mfs );
3636+ if ( ! iobuf ) {
3637+ /* Wait for next refill */
3638+ break;
3639+ }
3640+
3641+ /* Get next receive descriptor */
3642+ rx_idx = ( intelxl->rx.prod++ % INTELXL_RX_NUM_DESC );
3643+ rx = &intelxl->rx.desc[rx_idx].rx;
3644+
3645+ /* Populate receive descriptor */
3646+ address = virt_to_bus ( iobuf->data );
3647+ rx->address = cpu_to_le64 ( address );
3648+ rx->flags = 0;
3649+
3650+ /* Record I/O buffer */
3651+ assert ( intelxl->rx_iobuf[rx_idx] == NULL );
3652+ intelxl->rx_iobuf[rx_idx] = iobuf;
3653+
3654+ DBGC2 ( intelxl, "INTELXL %p RX %d is [%llx,%llx)\n", intelxl,
3655+ rx_idx, ( ( unsigned long long ) address ),
3656+ ( ( unsigned long long ) address + intelxl->mfs ) );
3657+ refilled++;
3658+ }
3659+
3660+ /* Push descriptors to card, if applicable */
3661+ if ( refilled ) {
3662+ wmb();
3663+ rx_tail = ( intelxl->rx.prod % INTELXL_RX_NUM_DESC );
3664+ writel ( rx_tail,
3665+ ( intelxl->regs + intelxl->rx.reg + INTELXL_QXX_TAIL));
3666+ }
3667+}
3668+
3669+/******************************************************************************
3670+ *
3671+ * Network device interface
3672+ *
3673+ ******************************************************************************
3674+ */
3675+
3676+/**
3677+ * Open network device
3678+ *
3679+ * @v netdev Network device
3680+ * @ret rc Return status code
3681+ */
3682+static int intelxl_open ( struct net_device *netdev ) {
3683+ struct intelxl_nic *intelxl = netdev->priv;
3684+ union intelxl_receive_address mac;
3685+ unsigned int queue;
3686+ uint32_t prtgl_sal;
3687+ uint32_t prtgl_sah;
3688+ int rc;
3689+
3690+ /* Calculate maximum frame size */
3691+ intelxl->mfs = ( ( ETH_HLEN + netdev->mtu + 4 /* CRC */ +
3692+ INTELXL_ALIGN - 1 ) & ~( INTELXL_ALIGN - 1 ) );
3693+
3694+ /* Program MAC address and maximum frame size */
3695+ memset ( &mac, 0, sizeof ( mac ) );
3696+ memcpy ( mac.raw, netdev->ll_addr, sizeof ( mac.raw ) );
3697+ prtgl_sal = le32_to_cpu ( mac.reg.low );
3698+ prtgl_sah = ( le32_to_cpu ( mac.reg.high ) |
3699+ INTELXL_PRTGL_SAH_MFS_SET ( intelxl->mfs ) );
3700+ writel ( prtgl_sal, intelxl->regs + INTELXL_PRTGL_SAL );
3701+ writel ( prtgl_sah, intelxl->regs + INTELXL_PRTGL_SAH );
3702+
3703+ /* Associate transmit queue to PF */
3704+ writel ( ( INTELXL_QXX_CTL_PFVF_Q_PF |
3705+ INTELXL_QXX_CTL_PFVF_PF_INDX ( intelxl->pf ) ),
3706+ ( intelxl->regs + intelxl->tx.reg + INTELXL_QXX_CTL ) );
3707+
3708+ /* Clear transmit pre queue disable */
3709+ queue = ( intelxl->base + intelxl->queue );
3710+ writel ( ( INTELXL_GLLAN_TXPRE_QDIS_CLEAR_QDIS |
3711+ INTELXL_GLLAN_TXPRE_QDIS_QINDX ( queue ) ),
3712+ ( intelxl->regs + INTELXL_GLLAN_TXPRE_QDIS ( queue ) ) );
3713+
3714+ /* Reset transmit queue head */
3715+ writel ( 0, ( intelxl->regs + INTELXL_QTX_HEAD ( intelxl->queue ) ) );
3716+
3717+ /* Create receive descriptor ring */
3718+ if ( ( rc = intelxl_create_ring ( intelxl, &intelxl->rx ) ) != 0 )
3719+ goto err_create_rx;
3720+
3721+ /* Create transmit descriptor ring */
3722+ if ( ( rc = intelxl_create_ring ( intelxl, &intelxl->tx ) ) != 0 )
3723+ goto err_create_tx;
3724+
3725+ /* Fill receive ring */
3726+ intelxl_refill_rx ( intelxl );
3727+
3728+ /* Restart autonegotiation */
3729+ intelxl_admin_autoneg ( intelxl );
3730+
3731+ /* Update link state */
3732+ intelxl_admin_link ( netdev );
3733+
3734+ return 0;
3735+
3736+ writel ( ( INTELXL_GLLAN_TXPRE_QDIS_SET_QDIS |
3737+ INTELXL_GLLAN_TXPRE_QDIS_QINDX ( queue ) ),
3738+ ( intelxl->regs + INTELXL_GLLAN_TXPRE_QDIS ( queue ) ) );
3739+ udelay ( INTELXL_QUEUE_PRE_DISABLE_DELAY_US );
3740+ intelxl_destroy_ring ( intelxl, &intelxl->tx );
3741+ err_create_tx:
3742+ intelxl_destroy_ring ( intelxl, &intelxl->rx );
3743+ err_create_rx:
3744+ return rc;
3745+}
3746+
3747+/**
3748+ * Close network device
3749+ *
3750+ * @v netdev Network device
3751+ */
3752+static void intelxl_close ( struct net_device *netdev ) {
3753+ struct intelxl_nic *intelxl = netdev->priv;
3754+ unsigned int queue;
3755+ unsigned int i;
3756+
3757+ /* Dump contexts (for debugging) */
3758+ intelxl_context_dump ( intelxl, INTELXL_PFCM_LANCTXCTL_TYPE_TX,
3759+ sizeof ( struct intelxl_context_tx ) );
3760+ intelxl_context_dump ( intelxl, INTELXL_PFCM_LANCTXCTL_TYPE_RX,
3761+ sizeof ( struct intelxl_context_rx ) );
3762+
3763+ /* Pre-disable transmit queue */
3764+ queue = ( intelxl->base + intelxl->queue );
3765+ writel ( ( INTELXL_GLLAN_TXPRE_QDIS_SET_QDIS |
3766+ INTELXL_GLLAN_TXPRE_QDIS_QINDX ( queue ) ),
3767+ ( intelxl->regs + INTELXL_GLLAN_TXPRE_QDIS ( queue ) ) );
3768+ udelay ( INTELXL_QUEUE_PRE_DISABLE_DELAY_US );
3769+
3770+ /* Destroy transmit descriptor ring */
3771+ intelxl_destroy_ring ( intelxl, &intelxl->tx );
3772+
3773+ /* Destroy receive descriptor ring */
3774+ intelxl_destroy_ring ( intelxl, &intelxl->rx );
3775+
3776+ /* Discard any unused receive buffers */
3777+ for ( i = 0 ; i < INTELXL_RX_NUM_DESC ; i++ ) {
3778+ if ( intelxl->rx_iobuf[i] )
3779+ free_iob ( intelxl->rx_iobuf[i] );
3780+ intelxl->rx_iobuf[i] = NULL;
3781+ }
3782+}
3783+
3784+/**
3785+ * Transmit packet
3786+ *
3787+ * @v netdev Network device
3788+ * @v iobuf I/O buffer
3789+ * @ret rc Return status code
3790+ */
3791+static int intelxl_transmit ( struct net_device *netdev,
3792+ struct io_buffer *iobuf ) {
3793+ struct intelxl_nic *intelxl = netdev->priv;
3794+ struct intelxl_tx_data_descriptor *tx;
3795+ unsigned int tx_idx;
3796+ unsigned int tx_tail;
3797+ physaddr_t address;
3798+ size_t len;
3799+
3800+ /* Get next transmit descriptor */
3801+ if ( ( intelxl->tx.prod - intelxl->tx.cons ) >= INTELXL_TX_FILL ) {
3802+ DBGC ( intelxl, "INTELXL %p out of transmit descriptors\n",
3803+ intelxl );
3804+ return -ENOBUFS;
3805+ }
3806+ tx_idx = ( intelxl->tx.prod++ % INTELXL_TX_NUM_DESC );
3807+ tx_tail = ( intelxl->tx.prod % INTELXL_TX_NUM_DESC );
3808+ tx = &intelxl->tx.desc[tx_idx].tx;
3809+
3810+ /* Populate transmit descriptor */
3811+ address = virt_to_bus ( iobuf->data );
3812+ len = iob_len ( iobuf );
3813+ tx->address = cpu_to_le64 ( address );
3814+ tx->len = cpu_to_le32 ( INTELXL_TX_DATA_LEN ( len ) );
3815+ tx->flags = cpu_to_le32 ( INTELXL_TX_DATA_DTYP | INTELXL_TX_DATA_EOP |
3816+ INTELXL_TX_DATA_RS | INTELXL_TX_DATA_JFDI );
3817+ wmb();
3818+
3819+ /* Notify card that there are packets ready to transmit */
3820+ writel ( tx_tail,
3821+ ( intelxl->regs + intelxl->tx.reg + INTELXL_QXX_TAIL ) );
3822+
3823+ DBGC2 ( intelxl, "INTELXL %p TX %d is [%llx,%llx)\n", intelxl, tx_idx,
3824+ ( ( unsigned long long ) address ),
3825+ ( ( unsigned long long ) address + len ) );
3826+ return 0;
3827+}
3828+
3829+/**
3830+ * Poll for completed packets
3831+ *
3832+ * @v netdev Network device
3833+ */
3834+static void intelxl_poll_tx ( struct net_device *netdev ) {
3835+ struct intelxl_nic *intelxl = netdev->priv;
3836+ struct intelxl_tx_writeback_descriptor *tx_wb;
3837+ unsigned int tx_idx;
3838+
3839+ /* Check for completed packets */
3840+ while ( intelxl->tx.cons != intelxl->tx.prod ) {
3841+
3842+ /* Get next transmit descriptor */
3843+ tx_idx = ( intelxl->tx.cons % INTELXL_TX_NUM_DESC );
3844+ tx_wb = &intelxl->tx.desc[tx_idx].tx_wb;
3845+
3846+ /* Stop if descriptor is still in use */
3847+ if ( ! ( tx_wb->flags & INTELXL_TX_WB_FL_DD ) )
3848+ return;
3849+ DBGC2 ( intelxl, "INTELXL %p TX %d complete\n",
3850+ intelxl, tx_idx );
3851+
3852+ /* Complete TX descriptor */
3853+ netdev_tx_complete_next ( netdev );
3854+ intelxl->tx.cons++;
3855+ }
3856+}
3857+
3858+/**
3859+ * Poll for received packets
3860+ *
3861+ * @v netdev Network device
3862+ */
3863+static void intelxl_poll_rx ( struct net_device *netdev ) {
3864+ struct intelxl_nic *intelxl = netdev->priv;
3865+ struct intelxl_rx_writeback_descriptor *rx_wb;
3866+ struct io_buffer *iobuf;
3867+ unsigned int rx_idx;
3868+ size_t len;
3869+
3870+ /* Check for received packets */
3871+ while ( intelxl->rx.cons != intelxl->rx.prod ) {
3872+
3873+ /* Get next receive descriptor */
3874+ rx_idx = ( intelxl->rx.cons % INTELXL_RX_NUM_DESC );
3875+ rx_wb = &intelxl->rx.desc[rx_idx].rx_wb;
3876+
3877+ /* Stop if descriptor is still in use */
3878+ if ( ! ( rx_wb->flags & cpu_to_le32 ( INTELXL_RX_WB_FL_DD ) ) )
3879+ return;
3880+
3881+ /* Populate I/O buffer */
3882+ iobuf = intelxl->rx_iobuf[rx_idx];
3883+ intelxl->rx_iobuf[rx_idx] = NULL;
3884+ len = INTELXL_RX_WB_LEN ( le32_to_cpu ( rx_wb->len ) );
3885+ iob_put ( iobuf, len );
3886+
3887+ /* Hand off to network stack */
3888+ if ( rx_wb->flags & cpu_to_le32 ( INTELXL_RX_WB_FL_RXE ) ) {
3889+ DBGC ( intelxl, "INTELXL %p RX %d error (length %zd, "
3890+ "flags %08x)\n", intelxl, rx_idx, len,
3891+ le32_to_cpu ( rx_wb->flags ) );
3892+ netdev_rx_err ( netdev, iobuf, -EIO );
3893+ } else {
3894+ DBGC2 ( intelxl, "INTELXL %p RX %d complete (length "
3895+ "%zd)\n", intelxl, rx_idx, len );
3896+ netdev_rx ( netdev, iobuf );
3897+ }
3898+ intelxl->rx.cons++;
3899+ }
3900+}
3901+
3902+/**
3903+ * Poll for completed and received packets
3904+ *
3905+ * @v netdev Network device
3906+ */
3907+static void intelxl_poll ( struct net_device *netdev ) {
3908+ struct intelxl_nic *intelxl = netdev->priv;
3909+
3910+ /* Acknowledge interrupts, if applicable */
3911+ if ( netdev_irq_enabled ( netdev ) ) {
3912+ writel ( ( INTELXL_PFINT_DYN_CTL0_CLEARPBA |
3913+ INTELXL_PFINT_DYN_CTL0_INTENA_MASK ),
3914+ intelxl->regs + INTELXL_PFINT_DYN_CTL0 );
3915+ }
3916+
3917+ /* Poll for completed packets */
3918+ intelxl_poll_tx ( netdev );
3919+
3920+ /* Poll for received packets */
3921+ intelxl_poll_rx ( netdev );
3922+
3923+ /* Poll for admin events */
3924+ intelxl_poll_admin ( netdev );
3925+
3926+ /* Refill RX ring */
3927+ intelxl_refill_rx ( intelxl );
3928+}
3929+
3930+/**
3931+ * Enable or disable interrupts
3932+ *
3933+ * @v netdev Network device
3934+ * @v enable Interrupts should be enabled
3935+ */
3936+static void intelxl_irq ( struct net_device *netdev, int enable ) {
3937+ struct intelxl_nic *intelxl = netdev->priv;
3938+
3939+ if ( enable ) {
3940+ writel ( INTELXL_PFINT_DYN_CTL0_INTENA,
3941+ intelxl->regs + INTELXL_PFINT_DYN_CTL0 );
3942+ } else {
3943+ writel ( 0, intelxl->regs + INTELXL_PFINT_DYN_CTL0 );
3944+ }
3945+}
3946+
3947+/** Network device operations */
3948+static struct net_device_operations intelxl_operations = {
3949+ .open = intelxl_open,
3950+ .close = intelxl_close,
3951+ .transmit = intelxl_transmit,
3952+ .poll = intelxl_poll,
3953+ .irq = intelxl_irq,
3954+};
3955+
3956+/******************************************************************************
3957+ *
3958+ * PCI interface
3959+ *
3960+ ******************************************************************************
3961+ */
3962+
3963+/**
3964+ * Probe PCI device
3965+ *
3966+ * @v pci PCI device
3967+ * @ret rc Return status code
3968+ */
3969+static int intelxl_probe ( struct pci_device *pci ) {
3970+ struct net_device *netdev;
3971+ struct intelxl_nic *intelxl;
3972+ uint32_t pfgen_portnum;
3973+ uint32_t pflan_qalloc;
3974+ int rc;
3975+
3976+ /* Allocate and initialise net device */
3977+ netdev = alloc_etherdev ( sizeof ( *intelxl ) );
3978+ if ( ! netdev ) {
3979+ rc = -ENOMEM;
3980+ goto err_alloc;
3981+ }
3982+ netdev_init ( netdev, &intelxl_operations );
3983+ intelxl = netdev->priv;
3984+ pci_set_drvdata ( pci, netdev );
3985+ netdev->dev = &pci->dev;
3986+ memset ( intelxl, 0, sizeof ( *intelxl ) );
3987+ intelxl->pf = PCI_FUNC ( pci->busdevfn );
3988+ intelxl_init_admin ( &intelxl->command, INTELXL_ADMIN_CMD );
3989+ intelxl_init_admin ( &intelxl->event, INTELXL_ADMIN_EVT );
3990+ intelxl_init_ring ( &intelxl->tx, INTELXL_TX_NUM_DESC,
3991+ intelxl_context_tx );
3992+ intelxl_init_ring ( &intelxl->rx, INTELXL_RX_NUM_DESC,
3993+ intelxl_context_rx );
3994+
3995+ /* Fix up PCI device */
3996+ adjust_pci_device ( pci );
3997+
3998+ /* Map registers */
3999+ intelxl->regs = ioremap ( pci->membase, INTELXL_BAR_SIZE );
4000+ if ( ! intelxl->regs ) {
4001+ rc = -ENODEV;
4002+ goto err_ioremap;
4003+ }
4004+
4005+ /* Reset the NIC */
4006+ if ( ( rc = intelxl_reset ( intelxl ) ) != 0 )
4007+ goto err_reset;
4008+
4009+ /* Get port number and base queue number */
4010+ pfgen_portnum = readl ( intelxl->regs + INTELXL_PFGEN_PORTNUM );
4011+ intelxl->port = INTELXL_PFGEN_PORTNUM_PORT_NUM ( pfgen_portnum );
4012+ pflan_qalloc = readl ( intelxl->regs + INTELXL_PFLAN_QALLOC );
4013+ intelxl->base = INTELXL_PFLAN_QALLOC_FIRSTQ ( pflan_qalloc );
4014+ DBGC ( intelxl, "INTELXL %p PF %d using port %d queues [%#04x-%#04x]\n",
4015+ intelxl, intelxl->pf, intelxl->port, intelxl->base,
4016+ INTELXL_PFLAN_QALLOC_LASTQ ( pflan_qalloc ) );
4017+
4018+ /* Fetch MAC address and maximum frame size */
4019+ if ( ( rc = intelxl_fetch_mac ( intelxl, netdev ) ) != 0 )
4020+ goto err_fetch_mac;
4021+
4022+ /* Open admin queues */
4023+ if ( ( rc = intelxl_open_admin ( intelxl ) ) != 0 )
4024+ goto err_open_admin;
4025+
4026+ /* Get switch configuration */
4027+ if ( ( rc = intelxl_admin_switch ( intelxl ) ) != 0 )
4028+ goto err_admin_switch;
4029+
4030+ /* Get VSI configuration */
4031+ if ( ( rc = intelxl_admin_vsi ( intelxl ) ) != 0 )
4032+ goto err_admin_vsi;
4033+
4034+ /* Configure switch for promiscuous mode */
4035+ if ( ( rc = intelxl_admin_promisc ( intelxl ) ) != 0 )
4036+ goto err_admin_promisc;
4037+
4038+ /* Configure queue register addresses */
4039+ intelxl->tx.reg = INTELXL_QTX ( intelxl->queue );
4040+ intelxl->rx.reg = INTELXL_QRX ( intelxl->queue );
4041+
4042+ /* Configure interrupt causes */
4043+ writel ( ( INTELXL_QINT_TQCTL_NEXTQ_INDX_NONE |
4044+ INTELXL_QINT_TQCTL_CAUSE_ENA ),
4045+ intelxl->regs + INTELXL_QINT_TQCTL ( intelxl->queue ) );
4046+ writel ( ( INTELXL_QINT_RQCTL_NEXTQ_INDX ( intelxl->queue ) |
4047+ INTELXL_QINT_RQCTL_NEXTQ_TYPE_TX |
4048+ INTELXL_QINT_RQCTL_CAUSE_ENA ),
4049+ intelxl->regs + INTELXL_QINT_RQCTL ( intelxl->queue ) );
4050+ writel ( ( INTELXL_PFINT_LNKLST0_FIRSTQ_INDX ( intelxl->queue ) |
4051+ INTELXL_PFINT_LNKLST0_FIRSTQ_TYPE_RX ),
4052+ intelxl->regs + INTELXL_PFINT_LNKLST0 );
4053+ writel ( INTELXL_PFINT_ICR0_ENA_ADMINQ,
4054+ intelxl->regs + INTELXL_PFINT_ICR0_ENA );
4055+
4056+ /* Register network device */
4057+ if ( ( rc = register_netdev ( netdev ) ) != 0 )
4058+ goto err_register_netdev;
4059+
4060+ /* Set initial link state */
4061+ intelxl_admin_link ( netdev );
4062+
4063+ return 0;
4064+
4065+ unregister_netdev ( netdev );
4066+ err_register_netdev:
4067+ err_admin_promisc:
4068+ err_admin_vsi:
4069+ err_admin_switch:
4070+ intelxl_close_admin ( intelxl );
4071+ err_open_admin:
4072+ err_fetch_mac:
4073+ intelxl_reset ( intelxl );
4074+ err_reset:
4075+ iounmap ( intelxl->regs );
4076+ err_ioremap:
4077+ netdev_nullify ( netdev );
4078+ netdev_put ( netdev );
4079+ err_alloc:
4080+ return rc;
4081+}
4082+
4083+/**
4084+ * Remove PCI device
4085+ *
4086+ * @v pci PCI device
4087+ */
4088+static void intelxl_remove ( struct pci_device *pci ) {
4089+ struct net_device *netdev = pci_get_drvdata ( pci );
4090+ struct intelxl_nic *intelxl = netdev->priv;
4091+
4092+ /* Unregister network device */
4093+ unregister_netdev ( netdev );
4094+
4095+ /* Close admin queues */
4096+ intelxl_close_admin ( intelxl );
4097+
4098+ /* Reset the NIC */
4099+ intelxl_reset ( intelxl );
4100+
4101+ /* Free network device */
4102+ iounmap ( intelxl->regs );
4103+ netdev_nullify ( netdev );
4104+ netdev_put ( netdev );
4105+}
4106+
4107+/** PCI device IDs */
4108+static struct pci_device_id intelxl_nics[] = {
4109+ PCI_ROM ( 0x8086, 0x1572, "x710-sfp", "X710 10GbE SFP+", 0 ),
4110+ PCI_ROM ( 0x8086, 0x1574, "xl710-qemu", "Virtual XL710", 0 ),
4111+ PCI_ROM ( 0x8086, 0x1580, "xl710-kx-b", "XL710 40GbE backplane", 0 ),
4112+ PCI_ROM ( 0x8086, 0x1581, "xl710-kx-c", "XL710 10GbE backplane", 0 ),
4113+ PCI_ROM ( 0x8086, 0x1583, "xl710-qda2", "XL710 40GbE QSFP+", 0 ),
4114+ PCI_ROM ( 0x8086, 0x1584, "xl710-qda1", "XL710 40GbE QSFP+", 0 ),
4115+ PCI_ROM ( 0x8086, 0x1585, "x710-qsfp", "X710 10GbE QSFP+", 0 ),
4116+ PCI_ROM ( 0x8086, 0x1586, "x710-10gt", "X710 10GBASE-T", 0 ),
4117+ PCI_ROM ( 0x8086, 0x1587, "x710-kr2", "XL710 20GbE backplane", 0 ),
4118+ PCI_ROM ( 0x8086, 0x1588, "x710-kr2-a", "XL710 20GbE backplane", 0 ),
4119+ PCI_ROM ( 0x8086, 0x1589, "x710-10gt4", "X710 10GBASE-T4", 0 ),
4120+ PCI_ROM ( 0x8086, 0x158a, "xxv710", "XXV710 25GbE backplane", 0 ),
4121+ PCI_ROM ( 0x8086, 0x158b, "xxv710-sfp28", "XXV710 25GbE SFP28", 0 ),
4122+ PCI_ROM ( 0x8086, 0x37ce, "x722-kx", "X722 10GbE backplane", 0 ),
4123+ PCI_ROM ( 0x8086, 0x37cf, "x722-qsfp", "X722 10GbE QSFP+", 0 ),
4124+ PCI_ROM ( 0x8086, 0x37d0, "x722-sfp", "X722 10GbE SFP+", 0 ),
4125+ PCI_ROM ( 0x8086, 0x37d1, "x722-1gt", "X722 1GBASE-T", 0 ),
4126+ PCI_ROM ( 0x8086, 0x37d2, "x722-10gt", "X722 10GBASE-T", 0 ),
4127+ PCI_ROM ( 0x8086, 0x37d3, "x722-sfp-i", "X722 10GbE SFP+", 0 ),
4128+};
4129+
4130+/** PCI driver */
4131+struct pci_driver intelxl_driver __pci_driver = {
4132+ .ids = intelxl_nics,
4133+ .id_count = ( sizeof ( intelxl_nics ) / sizeof ( intelxl_nics[0] ) ),
4134+ .probe = intelxl_probe,
4135+ .remove = intelxl_remove,
4136+};
4137diff --git a/src/drivers/net/intelxl.h b/src/drivers/net/intelxl.h
4138new file mode 100644
4139index 0000000..02d9b98
4140--- /dev/null
4141+++ b/src/drivers/net/intelxl.h
4142@@ -0,0 +1,790 @@
4143+#ifndef _INTELX_H
4144+#define _INTELX_H
4145+
4146+/** @file
4147+ *
4148+ * Intel 40 Gigabit Ethernet network card driver
4149+ *
4150+ */
4151+
4152+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
4153+
4154+#include <stdint.h>
4155+#include <ipxe/if_ether.h>
4156+
4157+struct intelxl_nic;
4158+
4159+/** BAR size */
4160+#define INTELXL_BAR_SIZE 0x200000
4161+
4162+/** Alignment
4163+ *
4164+ * No data structure requires greater than 128 byte alignment.
4165+ */
4166+#define INTELXL_ALIGN 128
4167+
4168+/******************************************************************************
4169+ *
4170+ * Admin queue
4171+ *
4172+ ******************************************************************************
4173+ */
4174+
4175+/** PF Admin Command Queue register block */
4176+#define INTELXL_ADMIN_CMD 0x080000
4177+
4178+/** PF Admin Event Queue register block */
4179+#define INTELXL_ADMIN_EVT 0x080080
4180+
4181+/** Admin Queue Base Address Low Register (offset) */
4182+#define INTELXL_ADMIN_BAL 0x000
4183+
4184+/** Admin Queue Base Address High Register (offset) */
4185+#define INTELXL_ADMIN_BAH 0x100
4186+
4187+/** Admin Queue Length Register (offset) */
4188+#define INTELXL_ADMIN_LEN 0x200
4189+#define INTELXL_ADMIN_LEN_LEN(x) ( (x) << 0 ) /**< Queue length */
4190+#define INTELXL_ADMIN_LEN_ENABLE 0x80000000UL /**< Queue enable */
4191+
4192+/** Admin Queue Head Register (offset) */
4193+#define INTELXL_ADMIN_HEAD 0x300
4194+
4195+/** Admin Queue Tail Register (offset) */
4196+#define INTELXL_ADMIN_TAIL 0x400
4197+
4198+/** Admin queue data buffer command parameters */
4199+struct intelxl_admin_buffer_params {
4200+ /** Reserved */
4201+ uint8_t reserved[8];
4202+ /** Buffer address high */
4203+ uint32_t high;
4204+ /** Buffer address low */
4205+ uint32_t low;
4206+} __attribute__ (( packed ));
4207+
4208+/** Admin queue Get Version command */
4209+#define INTELXL_ADMIN_VERSION 0x0001
4210+
4211+/** Admin queue version number */
4212+struct intelxl_admin_version {
4213+ /** Major version number */
4214+ uint16_t major;
4215+ /** Minor version number */
4216+ uint16_t minor;
4217+} __attribute__ (( packed ));
4218+
4219+/** Admin queue Get Version command parameters */
4220+struct intelxl_admin_version_params {
4221+ /** ROM version */
4222+ uint32_t rom;
4223+ /** Firmware build ID */
4224+ uint32_t build;
4225+ /** Firmware version */
4226+ struct intelxl_admin_version firmware;
4227+ /** API version */
4228+ struct intelxl_admin_version api;
4229+} __attribute__ (( packed ));
4230+
4231+/** Admin queue Driver Version command */
4232+#define INTELXL_ADMIN_DRIVER 0x0002
4233+
4234+/** Admin queue Driver Version command parameters */
4235+struct intelxl_admin_driver_params {
4236+ /** Driver version */
4237+ uint8_t major;
4238+ /** Minor version */
4239+ uint8_t minor;
4240+ /** Build version */
4241+ uint8_t build;
4242+ /** Sub-build version */
4243+ uint8_t sub;
4244+ /** Reserved */
4245+ uint8_t reserved[4];
4246+ /** Data buffer address */
4247+ uint64_t address;
4248+} __attribute__ (( packed ));
4249+
4250+/** Admin queue Driver Version data buffer */
4251+struct intelxl_admin_driver_buffer {
4252+ /** Driver name */
4253+ char name[32];
4254+} __attribute__ (( packed ));
4255+
4256+/** Admin queue Shutdown command */
4257+#define INTELXL_ADMIN_SHUTDOWN 0x0003
4258+
4259+/** Admin queue Shutdown command parameters */
4260+struct intelxl_admin_shutdown_params {
4261+ /** Driver unloading */
4262+ uint8_t unloading;
4263+ /** Reserved */
4264+ uint8_t reserved[15];
4265+} __attribute__ (( packed ));
4266+
4267+/** Driver is unloading */
4268+#define INTELXL_ADMIN_SHUTDOWN_UNLOADING 0x01
4269+
4270+/** Admin queue Get Switch Configuration command */
4271+#define INTELXL_ADMIN_SWITCH 0x0200
4272+
4273+/** Switching element configuration */
4274+struct intelxl_admin_switch_config {
4275+ /** Switching element type */
4276+ uint8_t type;
4277+ /** Revision */
4278+ uint8_t revision;
4279+ /** Switching element ID */
4280+ uint16_t seid;
4281+ /** Uplink switching element ID */
4282+ uint16_t uplink;
4283+ /** Downlink switching element ID */
4284+ uint16_t downlink;
4285+ /** Reserved */
4286+ uint8_t reserved_b[3];
4287+ /** Connection type */
4288+ uint8_t connection;
4289+ /** Reserved */
4290+ uint8_t reserved_c[2];
4291+ /** Element specific information */
4292+ uint16_t info;
4293+} __attribute__ (( packed ));
4294+
4295+/** Virtual Station Inferface element type */
4296+#define INTELXL_ADMIN_SWITCH_TYPE_VSI 19
4297+
4298+/** Admin queue Get Switch Configuration command parameters */
4299+struct intelxl_admin_switch_params {
4300+ /** Starting switching element identifier */
4301+ uint16_t next;
4302+ /** Reserved */
4303+ uint8_t reserved[6];
4304+ /** Data buffer address */
4305+ uint64_t address;
4306+} __attribute__ (( packed ));
4307+
4308+/** Admin queue Get Switch Configuration data buffer */
4309+struct intelxl_admin_switch_buffer {
4310+ /** Number of switching elements reported */
4311+ uint16_t count;
4312+ /** Total number of switching elements */
4313+ uint16_t total;
4314+ /** Reserved */
4315+ uint8_t reserved_a[12];
4316+ /** Switch configuration */
4317+ struct intelxl_admin_switch_config cfg;
4318+} __attribute__ (( packed ));
4319+
4320+/** Admin queue Get VSI Parameters command */
4321+#define INTELXL_ADMIN_VSI 0x0212
4322+
4323+/** Admin queue Get VSI Parameters command parameters */
4324+struct intelxl_admin_vsi_params {
4325+ /** VSI switching element ID */
4326+ uint16_t vsi;
4327+ /** Reserved */
4328+ uint8_t reserved[6];
4329+ /** Data buffer address */
4330+ uint64_t address;
4331+} __attribute__ (( packed ));
4332+
4333+/** Admin queue Get VSI Parameters data buffer */
4334+struct intelxl_admin_vsi_buffer {
4335+ /** Reserved */
4336+ uint8_t reserved_a[30];
4337+ /** Queue numbers */
4338+ uint16_t queue[16];
4339+ /** Reserved */
4340+ uint8_t reserved_b[34];
4341+ /** Queue set handles for each traffic class */
4342+ uint16_t qset[8];
4343+ /** Reserved */
4344+ uint8_t reserved_c[16];
4345+} __attribute__ (( packed ));
4346+
4347+/** Admin queue Set VSI Promiscuous Modes command */
4348+#define INTELXL_ADMIN_PROMISC 0x0254
4349+
4350+/** Admin queue Set VSI Promiscuous Modes command parameters */
4351+struct intelxl_admin_promisc_params {
4352+ /** Flags */
4353+ uint16_t flags;
4354+ /** Valid flags */
4355+ uint16_t valid;
4356+ /** VSI switching element ID */
4357+ uint16_t vsi;
4358+ /** Reserved */
4359+ uint8_t reserved[10];
4360+} __attribute__ (( packed ));
4361+
4362+/** Promiscuous unicast mode */
4363+#define INTELXL_ADMIN_PROMISC_FL_UNICAST 0x0001
4364+
4365+/** Promiscuous multicast mode */
4366+#define INTELXL_ADMIN_PROMISC_FL_MULTICAST 0x0002
4367+
4368+/** Promiscuous broadcast mode */
4369+#define INTELXL_ADMIN_PROMISC_FL_BROADCAST 0x0004
4370+
4371+/** Promiscuous VLAN mode */
4372+#define INTELXL_ADMIN_PROMISC_FL_VLAN 0x0010
4373+
4374+/** Admin queue Restart Autonegotiation command */
4375+#define INTELXL_ADMIN_AUTONEG 0x0605
4376+
4377+/** Admin queue Restart Autonegotiation command parameters */
4378+struct intelxl_admin_autoneg_params {
4379+ /** Flags */
4380+ uint8_t flags;
4381+ /** Reserved */
4382+ uint8_t reserved[15];
4383+} __attribute__ (( packed ));
4384+
4385+/** Restart autonegotiation */
4386+#define INTELXL_ADMIN_AUTONEG_FL_RESTART 0x02
4387+
4388+/** Enable link */
4389+#define INTELXL_ADMIN_AUTONEG_FL_ENABLE 0x04
4390+
4391+/** Admin queue Get Link Status command */
4392+#define INTELXL_ADMIN_LINK 0x0607
4393+
4394+/** Admin queue Get Link Status command parameters */
4395+struct intelxl_admin_link_params {
4396+ /** Link status notification */
4397+ uint8_t notify;
4398+ /** Reserved */
4399+ uint8_t reserved_a;
4400+ /** PHY type */
4401+ uint8_t phy;
4402+ /** Link speed */
4403+ uint8_t speed;
4404+ /** Link status */
4405+ uint8_t status;
4406+ /** Reserved */
4407+ uint8_t reserved_b[11];
4408+} __attribute__ (( packed ));
4409+
4410+/** Notify driver of link status changes */
4411+#define INTELXL_ADMIN_LINK_NOTIFY 0x03
4412+
4413+/** Link is up */
4414+#define INTELXL_ADMIN_LINK_UP 0x01
4415+
4416+/** Admin queue command parameters */
4417+union intelxl_admin_params {
4418+ /** Additional data buffer command parameters */
4419+ struct intelxl_admin_buffer_params buffer;
4420+ /** Get Version command parameters */
4421+ struct intelxl_admin_version_params version;
4422+ /** Driver Version command parameters */
4423+ struct intelxl_admin_driver_params driver;
4424+ /** Shutdown command parameters */
4425+ struct intelxl_admin_shutdown_params shutdown;
4426+ /** Get Switch Configuration command parameters */
4427+ struct intelxl_admin_switch_params sw;
4428+ /** Get VSI Parameters command parameters */
4429+ struct intelxl_admin_vsi_params vsi;
4430+ /** Set VSI Promiscuous Modes command parameters */
4431+ struct intelxl_admin_promisc_params promisc;
4432+ /** Restart Autonegotiation command parameters */
4433+ struct intelxl_admin_autoneg_params autoneg;
4434+ /** Get Link Status command parameters */
4435+ struct intelxl_admin_link_params link;
4436+} __attribute__ (( packed ));
4437+
4438+/** Admin queue data buffer */
4439+union intelxl_admin_buffer {
4440+ /** Driver Version data buffer */
4441+ struct intelxl_admin_driver_buffer driver;
4442+ /** Get Switch Configuration data buffer */
4443+ struct intelxl_admin_switch_buffer sw;
4444+ /** Get VSI Parameters data buffer */
4445+ struct intelxl_admin_vsi_buffer vsi;
4446+} __attribute__ (( packed ));
4447+
4448+/** Admin queue descriptor */
4449+struct intelxl_admin_descriptor {
4450+ /** Flags */
4451+ uint16_t flags;
4452+ /** Opcode */
4453+ uint16_t opcode;
4454+ /** Data length */
4455+ uint16_t len;
4456+ /** Return value */
4457+ uint16_t ret;
4458+ /** Cookie */
4459+ uint32_t cookie;
4460+ /** Reserved */
4461+ uint32_t reserved;
4462+ /** Parameters */
4463+ union intelxl_admin_params params;
4464+} __attribute__ (( packed ));
4465+
4466+/** Admin descriptor done */
4467+#define INTELXL_ADMIN_FL_DD 0x0001
4468+
4469+/** Admin descriptor contains a completion */
4470+#define INTELXL_ADMIN_FL_CMP 0x0002
4471+
4472+/** Admin descriptor completed in error */
4473+#define INTELXL_ADMIN_FL_ERR 0x0004
4474+
4475+/** Admin descriptor uses data buffer for command parameters */
4476+#define INTELXL_ADMIN_FL_RD 0x0400
4477+
4478+/** Admin descriptor uses data buffer */
4479+#define INTELXL_ADMIN_FL_BUF 0x1000
4480+
4481+/** Admin queue */
4482+struct intelxl_admin {
4483+ /** Descriptors */
4484+ struct intelxl_admin_descriptor *desc;
4485+ /** Queue index */
4486+ unsigned int index;
4487+
4488+ /** Register block */
4489+ unsigned int reg;
4490+ /** Data buffer */
4491+ union intelxl_admin_buffer *buffer;
4492+};
4493+
4494+/**
4495+ * Initialise admin queue
4496+ *
4497+ * @v admin Admin queue
4498+ * @v reg Register block
4499+ */
4500+static inline __attribute__ (( always_inline )) void
4501+intelxl_init_admin ( struct intelxl_admin *admin, unsigned int reg ) {
4502+
4503+ admin->reg = reg;
4504+}
4505+
4506+/** Number of admin queue descriptors */
4507+#define INTELXL_ADMIN_NUM_DESC 4
4508+
4509+/** Maximum time to wait for an admin request to complete */
4510+#define INTELXL_ADMIN_MAX_WAIT_MS 100
4511+
4512+/** Admin queue API major version */
4513+#define INTELXL_ADMIN_API_MAJOR 1
4514+
4515+/******************************************************************************
4516+ *
4517+ * Transmit and receive queue context
4518+ *
4519+ ******************************************************************************
4520+ */
4521+
4522+/** CMLAN Context Data Register */
4523+#define INTELXL_PFCM_LANCTXDATA(x) ( 0x10c100 + ( 0x80 * (x) ) )
4524+
4525+/** CMLAN Context Control Register */
4526+#define INTELXL_PFCM_LANCTXCTL 0x10c300
4527+#define INTELXL_PFCM_LANCTXCTL_QUEUE_NUM(x) \
4528+ ( (x) << 0 ) /**< Queue number */
4529+#define INTELXL_PFCM_LANCTXCTL_SUB_LINE(x) \
4530+ ( (x) << 12 ) /**< Sub-line */
4531+#define INTELXL_PFCM_LANCTXCTL_TYPE(x) \
4532+ ( (x) << 15 ) /**< Queue type */
4533+#define INTELXL_PFCM_LANCTXCTL_TYPE_RX \
4534+ INTELXL_PFCM_LANCTXCTL_TYPE ( 0x0 ) /**< RX queue type */
4535+#define INTELXL_PFCM_LANCTXCTL_TYPE_TX \
4536+ INTELXL_PFCM_LANCTXCTL_TYPE ( 0x1 ) /**< TX queue type */
4537+#define INTELXL_PFCM_LANCTXCTL_OP_CODE(x) \
4538+ ( (x) << 17 ) /**< Op code */
4539+#define INTELXL_PFCM_LANCTXCTL_OP_CODE_READ \
4540+ INTELXL_PFCM_LANCTXCTL_OP_CODE ( 0x0 ) /**< Read context */
4541+#define INTELXL_PFCM_LANCTXCTL_OP_CODE_WRITE \
4542+ INTELXL_PFCM_LANCTXCTL_OP_CODE ( 0x1 ) /**< Write context */
4543+
4544+/** CMLAN Context Status Register */
4545+#define INTELXL_PFCM_LANCTXSTAT 0x10c380
4546+#define INTELXL_PFCM_LANCTXSTAT_DONE 0x00000001UL /**< Complete */
4547+
4548+/** Queue context line */
4549+struct intelxl_context_line {
4550+ /** Raw data */
4551+ uint32_t raw[4];
4552+} __attribute__ (( packed ));
4553+
4554+/** Transmit queue context */
4555+struct intelxl_context_tx {
4556+ /** Head pointer */
4557+ uint16_t head;
4558+ /** Flags */
4559+ uint16_t flags;
4560+ /** Base address */
4561+ uint64_t base;
4562+ /** Reserved */
4563+ uint8_t reserved_a[8];
4564+ /** Queue count */
4565+ uint16_t count;
4566+ /** Reserved */
4567+ uint8_t reserved_b[100];
4568+ /** Queue set */
4569+ uint16_t qset;
4570+ /** Reserved */
4571+ uint8_t reserved_c[4];
4572+} __attribute__ (( packed ));
4573+
4574+/** New transmit queue context */
4575+#define INTELXL_CTX_TX_FL_NEW 0x4000
4576+
4577+/** Transmit queue base address */
4578+#define INTELXL_CTX_TX_BASE( base ) ( (base) >> 7 )
4579+
4580+/** Transmit queue count */
4581+#define INTELXL_CTX_TX_COUNT( count ) ( (count) << 1 )
4582+
4583+/** Transmit queue set */
4584+#define INTELXL_CTX_TX_QSET( qset) ( (qset) << 4 )
4585+
4586+/** Receive queue context */
4587+struct intelxl_context_rx {
4588+ /** Head pointer */
4589+ uint16_t head;
4590+ /** Reserved */
4591+ uint8_t reserved_a[2];
4592+ /** Base address and queue count */
4593+ uint64_t base_count;
4594+ /** Data buffer length */
4595+ uint16_t len;
4596+ /** Flags */
4597+ uint8_t flags;
4598+ /** Reserved */
4599+ uint8_t reserved_b[7];
4600+ /** Maximum frame size */
4601+ uint16_t mfs;
4602+} __attribute__ (( packed ));
4603+
4604+/** Receive queue base address and queue count */
4605+#define INTELXL_CTX_RX_BASE_COUNT( base, count ) \
4606+ ( ( (base) >> 7 ) | ( ( ( uint64_t ) (count) ) << 57 ) )
4607+
4608+/** Receive queue data buffer length */
4609+#define INTELXL_CTX_RX_LEN( len ) ( (len) >> 1 )
4610+
4611+/** Strip CRC from received packets */
4612+#define INTELXL_CTX_RX_FL_CRCSTRIP 0x20
4613+
4614+/** Receive queue maximum frame size */
4615+#define INTELXL_CTX_RX_MFS( mfs ) ( (mfs) >> 2 )
4616+
4617+/** Maximum time to wait for a context operation to complete */
4618+#define INTELXL_CTX_MAX_WAIT_MS 100
4619+
4620+/** Time to wait for a queue to become enabled */
4621+#define INTELXL_QUEUE_ENABLE_DELAY_US 20
4622+
4623+/** Time to wait for a transmit queue to become pre-disabled */
4624+#define INTELXL_QUEUE_PRE_DISABLE_DELAY_US 400
4625+
4626+/** Maximum time to wait for a queue to become disabled */
4627+#define INTELXL_QUEUE_DISABLE_MAX_WAIT_MS 1000
4628+
4629+/******************************************************************************
4630+ *
4631+ * Transmit and receive descriptors
4632+ *
4633+ ******************************************************************************
4634+ */
4635+
4636+/** Global Transmit Queue Head register */
4637+#define INTELXL_QTX_HEAD(x) ( 0x0e4000 + ( 0x4 * (x) ) )
4638+
4639+/** Global Transmit Pre Queue Disable register */
4640+#define INTELXL_GLLAN_TXPRE_QDIS(x) ( 0x0e6500 + ( 0x4 * ( (x) / 0x80 ) ) )
4641+#define INTELXL_GLLAN_TXPRE_QDIS_QINDX(x) \
4642+ ( (x) << 0 ) /**< Queue index */
4643+#define INTELXL_GLLAN_TXPRE_QDIS_SET_QDIS \
4644+ 0x40000000UL /**< Set disable */
4645+#define INTELXL_GLLAN_TXPRE_QDIS_CLEAR_QDIS \
4646+ 0x80000000UL /**< Clear disable */
4647+
4648+/** Global Transmit Queue register block */
4649+#define INTELXL_QTX(x) ( 0x100000 + ( 0x4 * (x) ) )
4650+
4651+/** Global Receive Queue register block */
4652+#define INTELXL_QRX(x) ( 0x120000 + ( 0x4 * (x) ) )
4653+
4654+/** Queue Enable Register (offset) */
4655+#define INTELXL_QXX_ENA 0x0000
4656+#define INTELXL_QXX_ENA_REQ 0x00000001UL /**< Enable request */
4657+#define INTELXL_QXX_ENA_STAT 0x00000004UL /**< Enabled status */
4658+
4659+/** Queue Control Register (offset) */
4660+#define INTELXL_QXX_CTL 0x4000
4661+#define INTELXL_QXX_CTL_PFVF_Q(x) ( (x) << 0 ) /**< PF/VF queue */
4662+#define INTELXL_QXX_CTL_PFVF_Q_PF \
4663+ INTELXL_QXX_CTL_PFVF_Q ( 0x2 ) /**< PF queue */
4664+#define INTELXL_QXX_CTL_PFVF_PF_INDX(x) ( (x) << 2 ) /**< PF index */
4665+
4666+/** Queue Tail Pointer Register (offset) */
4667+#define INTELXL_QXX_TAIL 0x8000
4668+
4669+/** Transmit data descriptor */
4670+struct intelxl_tx_data_descriptor {
4671+ /** Buffer address */
4672+ uint64_t address;
4673+ /** Flags */
4674+ uint32_t flags;
4675+ /** Length */
4676+ uint32_t len;
4677+} __attribute__ (( packed ));
4678+
4679+/** Transmit data descriptor type */
4680+#define INTELXL_TX_DATA_DTYP 0x0
4681+
4682+/** Transmit data descriptor end of packet */
4683+#define INTELXL_TX_DATA_EOP 0x10
4684+
4685+/** Transmit data descriptor report status */
4686+#define INTELXL_TX_DATA_RS 0x20
4687+
4688+/** Transmit data descriptor pretty please
4689+ *
4690+ * This bit is completely missing from older versions of the XL710
4691+ * datasheet. Later versions describe it innocuously as "reserved,
4692+ * must be 1". Without this bit, everything will appear to work (up
4693+ * to and including the port "transmit good octets" counter), but no
4694+ * packet will actually be sent.
4695+ */
4696+#define INTELXL_TX_DATA_JFDI 0x40
4697+
4698+/** Transmit data descriptor length */
4699+#define INTELXL_TX_DATA_LEN( len ) ( (len) << 2 )
4700+
4701+/** Transmit writeback descriptor */
4702+struct intelxl_tx_writeback_descriptor {
4703+ /** Reserved */
4704+ uint8_t reserved_a[8];
4705+ /** Flags */
4706+ uint8_t flags;
4707+ /** Reserved */
4708+ uint8_t reserved_b[7];
4709+} __attribute__ (( packed ));
4710+
4711+/** Transmit writeback descriptor complete */
4712+#define INTELXL_TX_WB_FL_DD 0x01
4713+
4714+/** Receive data descriptor */
4715+struct intelxl_rx_data_descriptor {
4716+ /** Buffer address */
4717+ uint64_t address;
4718+ /** Flags */
4719+ uint32_t flags;
4720+ /** Reserved */
4721+ uint8_t reserved[4];
4722+} __attribute__ (( packed ));
4723+
4724+/** Receive writeback descriptor */
4725+struct intelxl_rx_writeback_descriptor {
4726+ /** Reserved */
4727+ uint8_t reserved[8];
4728+ /** Flags */
4729+ uint32_t flags;
4730+ /** Length */
4731+ uint32_t len;
4732+} __attribute__ (( packed ));
4733+
4734+/** Receive writeback descriptor complete */
4735+#define INTELXL_RX_WB_FL_DD 0x00000001UL
4736+
4737+/** Receive writeback descriptor error */
4738+#define INTELXL_RX_WB_FL_RXE 0x00080000UL
4739+
4740+/** Receive writeback descriptor length */
4741+#define INTELXL_RX_WB_LEN(len) ( ( (len) >> 6 ) & 0x3fff )
4742+
4743+/** Packet descriptor */
4744+union intelxl_descriptor {
4745+ /** Transmit data descriptor */
4746+ struct intelxl_tx_data_descriptor tx;
4747+ /** Transmit writeback descriptor */
4748+ struct intelxl_tx_writeback_descriptor tx_wb;
4749+ /** Receive data descriptor */
4750+ struct intelxl_rx_data_descriptor rx;
4751+ /** Receive writeback descriptor */
4752+ struct intelxl_rx_writeback_descriptor rx_wb;
4753+};
4754+
4755+/** Descriptor ring */
4756+struct intelxl_ring {
4757+ /** Descriptors */
4758+ union intelxl_descriptor *desc;
4759+ /** Producer index */
4760+ unsigned int prod;
4761+ /** Consumer index */
4762+ unsigned int cons;
4763+
4764+ /** Register block */
4765+ unsigned int reg;
4766+ /** Length (in bytes) */
4767+ size_t len;
4768+ /** Program queue context
4769+ *
4770+ * @v intelxl Intel device
4771+ * @v address Descriptor ring base address
4772+ */
4773+ int ( * context ) ( struct intelxl_nic *intelxl, physaddr_t address );
4774+};
4775+
4776+/**
4777+ * Initialise descriptor ring
4778+ *
4779+ * @v ring Descriptor ring
4780+ * @v count Number of descriptors
4781+ * @v context Method to program queue context
4782+ */
4783+static inline __attribute__ (( always_inline)) void
4784+intelxl_init_ring ( struct intelxl_ring *ring, unsigned int count,
4785+ int ( * context ) ( struct intelxl_nic *intelxl,
4786+ physaddr_t address ) ) {
4787+
4788+ ring->len = ( count * sizeof ( ring->desc[0] ) );
4789+ ring->context = context;
4790+}
4791+
4792+/** Number of transmit descriptors */
4793+#define INTELXL_TX_NUM_DESC 16
4794+
4795+/** Transmit descriptor ring maximum fill level */
4796+#define INTELXL_TX_FILL ( INTELXL_TX_NUM_DESC - 1 )
4797+
4798+/** Number of receive descriptors
4799+ *
4800+ * In PXE mode (i.e. able to post single receive descriptors), 8
4801+ * descriptors is the only permitted value covering all possible
4802+ * numbers of PFs.
4803+ */
4804+#define INTELXL_RX_NUM_DESC 8
4805+
4806+/** Receive descriptor ring fill level */
4807+#define INTELXL_RX_FILL ( INTELXL_RX_NUM_DESC - 1 )
4808+
4809+/******************************************************************************
4810+ *
4811+ * Top level
4812+ *
4813+ ******************************************************************************
4814+ */
4815+
4816+/** PF Interrupt Zero Dynamic Control Register */
4817+#define INTELXL_PFINT_DYN_CTL0 0x038480
4818+#define INTELXL_PFINT_DYN_CTL0_INTENA 0x00000001UL /**< Enable */
4819+#define INTELXL_PFINT_DYN_CTL0_CLEARPBA 0x00000002UL /**< Acknowledge */
4820+#define INTELXL_PFINT_DYN_CTL0_INTENA_MASK 0x80000000UL /**< Ignore enable */
4821+
4822+/** PF Interrupt Zero Linked List Register */
4823+#define INTELXL_PFINT_LNKLST0 0x038500
4824+#define INTELXL_PFINT_LNKLST0_FIRSTQ_INDX(x) \
4825+ ( (x) << 0 ) /**< Queue index */
4826+#define INTELXL_PFINT_LNKLST0_FIRSTQ_INDX_NONE \
4827+ INTELXL_PFINT_LNKLST0_FIRSTQ_INDX ( 0x7ff ) /**< End of list */
4828+#define INTELXL_PFINT_LNKLST0_FIRSTQ_TYPE(x) \
4829+ ( (x) << 11 ) /**< Queue type */
4830+#define INTELXL_PFINT_LNKLST0_FIRSTQ_TYPE_RX \
4831+ INTELXL_PFINT_LNKLST0_FIRSTQ_TYPE ( 0x0 ) /**< Receive queue */
4832+#define INTELXL_PFINT_LNKLST0_FIRSTQ_TYPE_TX \
4833+ INTELXL_PFINT_LNKLST0_FIRSTQ_TYPE ( 0x1 ) /**< Transmit queue */
4834+
4835+/** PF Interrupt Zero Cause Enablement Register */
4836+#define INTELXL_PFINT_ICR0_ENA 0x038800
4837+#define INTELXL_PFINT_ICR0_ENA_ADMINQ 0x40000000UL /**< Admin event */
4838+
4839+/** Receive Queue Interrupt Cause Control Register */
4840+#define INTELXL_QINT_RQCTL(x) ( 0x03a000 + ( 0x4 * (x) ) )
4841+#define INTELXL_QINT_RQCTL_NEXTQ_INDX(x) ( (x) << 16 ) /**< Queue index */
4842+#define INTELXL_QINT_RQCTL_NEXTQ_INDX_NONE \
4843+ INTELXL_QINT_RQCTL_NEXTQ_INDX ( 0x7ff ) /**< End of list */
4844+#define INTELXL_QINT_RQCTL_NEXTQ_TYPE(x) ( (x) << 27 ) /**< Queue type */
4845+#define INTELXL_QINT_RQCTL_NEXTQ_TYPE_RX \
4846+ INTELXL_QINT_RQCTL_NEXTQ_TYPE ( 0x0 ) /**< Receive queue */
4847+#define INTELXL_QINT_RQCTL_NEXTQ_TYPE_TX \
4848+ INTELXL_QINT_RQCTL_NEXTQ_TYPE ( 0x1 ) /**< Transmit queue */
4849+#define INTELXL_QINT_RQCTL_CAUSE_ENA 0x40000000UL /**< Enable */
4850+
4851+/** Transmit Queue Interrupt Cause Control Register */
4852+#define INTELXL_QINT_TQCTL(x) ( 0x03c000 + ( 0x4 * (x) ) )
4853+#define INTELXL_QINT_TQCTL_NEXTQ_INDX(x) ( (x) << 16 ) /**< Queue index */
4854+#define INTELXL_QINT_TQCTL_NEXTQ_INDX_NONE \
4855+ INTELXL_QINT_TQCTL_NEXTQ_INDX ( 0x7ff ) /**< End of list */
4856+#define INTELXL_QINT_TQCTL_NEXTQ_TYPE(x) ( (x) << 27 ) /**< Queue type */
4857+#define INTELXL_QINT_TQCTL_NEXTQ_TYPE_RX \
4858+ INTELXL_QINT_TQCTL_NEXTQ_TYPE ( 0x0 ) /**< Receive queue */
4859+#define INTELXL_QINT_TQCTL_NEXTQ_TYPE_TX \
4860+ INTELXL_QINT_TQCTL_NEXTQ_TYPE ( 0x1 ) /**< Transmit queue */
4861+#define INTELXL_QINT_TQCTL_CAUSE_ENA 0x40000000UL /**< Enable */
4862+
4863+/** PF Control Register */
4864+#define INTELXL_PFGEN_CTRL 0x092400
4865+#define INTELXL_PFGEN_CTRL_PFSWR 0x00000001UL /**< Software Reset */
4866+
4867+/** Time to delay for device reset, in milliseconds */
4868+#define INTELXL_RESET_DELAY_MS 100
4869+
4870+/** PF Queue Allocation Register */
4871+#define INTELXL_PFLAN_QALLOC 0x1c0400
4872+#define INTELXL_PFLAN_QALLOC_FIRSTQ(x) \
4873+ ( ( (x) >> 0 ) & 0x7ff ) /**< First queue */
4874+#define INTELXL_PFLAN_QALLOC_LASTQ(x) \
4875+ ( ( (x) >> 16 ) & 0x7ff ) /**< Last queue */
4876+
4877+/** PF LAN Port Number Register */
4878+#define INTELXL_PFGEN_PORTNUM 0x1c0480
4879+#define INTELXL_PFGEN_PORTNUM_PORT_NUM(x) \
4880+ ( ( (x) >> 0 ) & 0x3 ) /**< Port number */
4881+
4882+/** Port MAC Address Low Register */
4883+#define INTELXL_PRTGL_SAL 0x1e2120
4884+
4885+/** Port MAC Address High Register */
4886+#define INTELXL_PRTGL_SAH 0x1e2140
4887+#define INTELXL_PRTGL_SAH_MFS_GET(x) ( (x) >> 16 ) /**< Max frame size */
4888+#define INTELXL_PRTGL_SAH_MFS_SET(x) ( (x) << 16 ) /**< Max frame size */
4889+
4890+/** Receive address */
4891+union intelxl_receive_address {
4892+ struct {
4893+ uint32_t low;
4894+ uint32_t high;
4895+ } __attribute__ (( packed )) reg;
4896+ uint8_t raw[ETH_ALEN];
4897+};
4898+
4899+/** An Intel 40Gigabit network card */
4900+struct intelxl_nic {
4901+ /** Registers */
4902+ void *regs;
4903+ /** Maximum frame size */
4904+ size_t mfs;
4905+
4906+ /** Physical function number */
4907+ unsigned int pf;
4908+ /** Absolute queue number base */
4909+ unsigned int base;
4910+ /** Port number */
4911+ unsigned int port;
4912+ /** Queue number */
4913+ unsigned int queue;
4914+ /** Virtual Station Interface switching element ID */
4915+ unsigned int vsi;
4916+ /** Queue set handle */
4917+ unsigned int qset;
4918+
4919+ /** Admin command queue */
4920+ struct intelxl_admin command;
4921+ /** Admin event queue */
4922+ struct intelxl_admin event;
4923+
4924+ /** Transmit descriptor ring */
4925+ struct intelxl_ring tx;
4926+ /** Receive descriptor ring */
4927+ struct intelxl_ring rx;
4928+ /** Receive I/O buffers */
4929+ struct io_buffer *rx_iobuf[INTELXL_RX_NUM_DESC];
4930+};
4931+
4932+#endif /* _INTELXL_H */
4933diff --git a/src/drivers/net/mii.c b/src/drivers/net/mii.c
4934index 9b29702..87605f0 100644
4935--- a/src/drivers/net/mii.c
4936+++ b/src/drivers/net/mii.c
4937@@ -37,10 +37,10 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
4938 /**
4939 * Restart autonegotiation
4940 *
4941- * @v mii MII interface
4942+ * @v mii MII device
4943 * @ret rc Return status code
4944 */
4945-int mii_restart ( struct mii_interface *mii ) {
4946+int mii_restart ( struct mii_device *mii ) {
4947 int bmcr;
4948 int rc;
4949
4950@@ -66,12 +66,12 @@ int mii_restart ( struct mii_interface *mii ) {
4951 }
4952
4953 /**
4954- * Reset MII interface
4955+ * Reset MII device
4956 *
4957- * @v mii MII interface
4958+ * @v mii MII device
4959 * @ret rc Return status code
4960 */
4961-int mii_reset ( struct mii_interface *mii ) {
4962+int mii_reset ( struct mii_device *mii ) {
4963 unsigned int i;
4964 int bmcr;
4965 int rc;
4966@@ -119,11 +119,11 @@ int mii_reset ( struct mii_interface *mii ) {
4967 /**
4968 * Update link status via MII
4969 *
4970- * @v mii MII interface
4971+ * @v mii MII device
4972 * @v netdev Network device
4973 * @ret rc Return status code
4974 */
4975-int mii_check_link ( struct mii_interface *mii, struct net_device *netdev ) {
4976+int mii_check_link ( struct mii_device *mii, struct net_device *netdev ) {
4977 int bmsr;
4978 int link;
4979 int rc;
4980@@ -147,3 +147,28 @@ int mii_check_link ( struct mii_interface *mii, struct net_device *netdev ) {
4981
4982 return 0;
4983 }
4984+
4985+/**
4986+ * Find PHY address
4987+ *
4988+ * @v mii MII device
4989+ * @ret rc Return status code
4990+ */
4991+int mii_find ( struct mii_device *mii ) {
4992+ unsigned int address;
4993+ int id;
4994+
4995+ /* Try all possible PHY addresses */
4996+ for ( address = 0 ; address <= MII_MAX_PHY_ADDRESS ; address++ ) {
4997+ mii->address = address;
4998+ id = mii_read ( mii, MII_PHYSID1 );
4999+ if ( ( id > 0x0000 ) && ( id < 0xffff ) ) {
5000+ DBGC ( mii, "MII %p found PHY at address %d\n",
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches