Merge ~paelzer/ubuntu/+source/ipxe:merge-upstream-disco into ubuntu/+source/ipxe:ubuntu/disco-devel
- Git
- lp:~paelzer/ubuntu/+source/ipxe
- merge-upstream-disco
- Merge into ubuntu/disco-devel
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) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Andreas Hasenack | Approve | ||
Canonical Server | Pending | ||
git-ubuntu developers | Pending | ||
Review via email:
|
Commit message
Description of the change
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Christian Ehrhardt (paelzer) wrote : | # |
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
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.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
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.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
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
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Christian Ehrhardt (paelzer) wrote : | # |
Building, I'm tracking migration - thakns
Preview Diff
1 | diff --git a/.travis.yml b/.travis.yml |
2 | deleted file mode 100644 |
3 | index 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 |
61 | diff --git a/debian/changelog b/debian/changelog |
62 | index 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 |
106 | diff --git a/debian/patches/fix-elf2efi-plt-relocation.diff b/debian/patches/fix-elf2efi-plt-relocation.diff |
107 | deleted file mode 100644 |
108 | index 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 ) : |
139 | diff --git a/debian/patches/series b/debian/patches/series |
140 | index 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 |
149 | diff --git a/src/Makefile.housekeeping b/src/Makefile.housekeeping |
150 | index 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 | # |
181 | diff --git a/src/arch/x86/core/dumpregs.c b/src/arch/x86/core/dumpregs.c |
182 | index 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" |
194 | diff --git a/src/arch/x86/drivers/net/undinet.c b/src/arch/x86/drivers/net/undinet.c |
195 | index 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 */ |
286 | diff --git a/src/arch/x86/include/bits/errfile.h b/src/arch/x86/include/bits/errfile.h |
287 | index 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 ) |
298 | diff --git a/src/arch/x86/include/ipxe/rtc_entropy.h b/src/arch/x86/include/ipxe/rtc_entropy.h |
299 | index 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 ); |
320 | diff --git a/src/arch/x86/include/librm.h b/src/arch/x86/include/librm.h |
321 | index 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 */ |
397 | diff --git a/src/arch/x86/interface/pcbios/acpi_timer.c b/src/arch/x86/interface/pcbios/acpi_timer.c |
398 | new file mode 100644 |
399 | index 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 | +}; |
539 | diff --git a/src/arch/x86/interface/pcbios/bios_console.c b/src/arch/x86/interface/pcbios/bios_console.c |
540 | index 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 ), |
558 | diff --git a/src/arch/x86/interface/pcbios/bios_reboot.c b/src/arch/x86/interface/pcbios/bios_reboot.c |
559 | index 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 | /** |
571 | diff --git a/src/arch/x86/interface/syslinux/comboot_call.c b/src/arch/x86/interface/syslinux/comboot_call.c |
572 | index 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 | } |
602 | diff --git a/src/arch/x86/transitions/librm.S b/src/arch/x86/transitions/librm.S |
603 | index 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 |
686 | diff --git a/src/arch/x86/transitions/librm_mgmt.c b/src/arch/x86/transitions/librm_mgmt.c |
687 | index 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" |
810 | diff --git a/src/arch/x86/transitions/librm_test.c b/src/arch/x86/transitions/librm_test.c |
811 | index 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 | |
823 | diff --git a/src/arch/x86_64/Makefile b/src/arch/x86_64/Makefile |
824 | index 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 |
838 | diff --git a/src/arch/x86_64/include/bits/hyperv.h b/src/arch/x86_64/include/bits/hyperv.h |
839 | index 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 | |
852 | diff --git a/src/config/config_timer.c b/src/config/config_timer.c |
853 | index 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 |
863 | diff --git a/src/config/crypto.h b/src/config/crypto.h |
864 | index 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> |
882 | diff --git a/src/core/netbios.c b/src/core/netbios.c |
883 | new file mode 100644 |
884 | index 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 | +} |
948 | diff --git a/src/core/profile.c b/src/core/profile.c |
949 | index 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 |
972 | diff --git a/src/crypto/entropy.c b/src/crypto/entropy.c |
973 | index 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 */ |
995 | diff --git a/src/crypto/x509.c b/src/crypto/x509.c |
996 | index 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; |
1017 | diff --git a/src/drivers/bitbash/mii_bit.c b/src/drivers/bitbash/mii_bit.c |
1018 | new file mode 100644 |
1019 | index 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 | +}; |
1185 | diff --git a/src/drivers/infiniband/CIB_PRM.h b/src/drivers/infiniband/CIB_PRM.h |
1186 | index 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]; |
1208 | diff --git a/src/drivers/infiniband/golan.c b/src/drivers/infiniband/golan.c |
1209 | index 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; |
1249 | diff --git a/src/drivers/net/efi/nii.c b/src/drivers/net/efi/nii.c |
1250 | index 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 | |
1466 | diff --git a/src/drivers/net/ena.c b/src/drivers/net/ena.c |
1467 | index 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 ); |
1478 | diff --git a/src/drivers/net/icplus.c b/src/drivers/net/icplus.c |
1479 | new file mode 100644 |
1480 | index 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 | +}; |
2293 | diff --git a/src/drivers/net/icplus.h b/src/drivers/net/icplus.h |
2294 | new file mode 100644 |
2295 | index 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 */ |
2505 | diff --git a/src/drivers/net/intel.c b/src/drivers/net/intel.c |
2506 | index 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 | }; |
2564 | diff --git a/src/drivers/net/intel.h b/src/drivers/net/intel.h |
2565 | index 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 | * |
2593 | diff --git a/src/drivers/net/intelx.c b/src/drivers/net/intelx.c |
2594 | index 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 */ |
2606 | diff --git a/src/drivers/net/intelxl.c b/src/drivers/net/intelxl.c |
2607 | new file mode 100644 |
2608 | index 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 | +}; |
4137 | diff --git a/src/drivers/net/intelxl.h b/src/drivers/net/intelxl.h |
4138 | new file mode 100644 |
4139 | index 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 */ |
4933 | diff --git a/src/drivers/net/mii.c b/src/drivers/net/mii.c |
4934 | index 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", |
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.