aboutsummaryrefslogtreecommitdiffstats
Commit message (Collapse)AuthorAge
...
| | * | | | | | | | | | [media] nuvoton-cir: make idle timeout more saneJarod Wilson2011-07-11
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The nuvoton-cir inherited an insanely low idle timeout value from the mceusb driver. We're fixing mceusb, should fix this driver too. Signed-off-by: Jarod Wilson <jarod@redhat.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
| | * | | | | | | | | | [media] mceusb: increase default timeout to 100msRafi Rubin2011-07-11
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This matches the typical timeout advertised by hardware, once we're actually interpreting it correctly. Signed-off-by: Rafi Rubin <rafi@seas.upenn.edu> Signed-off-by: Jarod Wilson <jarod@redhat.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
| | * | | | | | | | | | [media] mceusb: Timeout unit correctionsRafi Rubin2011-07-11
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Unit missmatch in mceusb_handle_command. It should be converting to us, not 1/10th of ms. mceusb_dev_printdata 100us/ms -> 1000us/ms Alter format of fix slightly and update comment to match proper reality. Signed-off-by: Rafi Rubin <rafi@seas.upenn.edu> Signed-off-by: Jarod Wilson <jarod@redhat.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
| | * | | | | | | | | | [media] Revert "V4L/DVB: cx23885: Enable Message Signaled Interrupts(MSI)"Jarod Wilson2011-07-11
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This reverts commit e38030f3ff02684eb9e25e983a03ad318a10a2ea. MSI flat-out doesn't work right on cx2388x devices yet. There are now multiple reports of cards that hard-lock systems when MSI is enabled, including my own HVR-1250 when trying to use its built-in IR receiver. Disable MSI and it works just fine. Similar for another user's HVR-1270. Issues have also been reported with the HVR-1850 when MSI is enabled, and the 1850 behavior sounds similar to an as-yet-undiagnosed issue I've seen with an 1800. CC: stable@kernel.org CC: Steven Toth <stoth@kernellabs.com> CC: Kusanagi Kouichi <slash@ac.auone-net.jp> Signed-off-by: Jarod Wilson <jarod@redhat.com> Acked-by: Andy Walls <awalls@md.metrocast.net> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
| * | | | | | | | | | | Merge branch 'release' of ↵Linus Torvalds2011-07-17
| |\ \ \ \ \ \ \ \ \ \ \ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6 * 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6: ACPI: Fixes device power states array overflow ACPI, APEI, HEST, Detect duplicated hardware error source ID ACPI: Fix lockdep false positives in acpi_power_off()
| | | \ \ \ \ \ \ \ \ \ \
| | | \ \ \ \ \ \ \ \ \ \
| | *-. \ \ \ \ \ \ \ \ \ \ Merge branches 'd3cold', 'bugzilla-37412' and 'bugzilla-38152' into releaseLen Brown2011-07-14
| | |\ \ \ \ \ \ \ \ \ \ \ \
| | | | * | | | | | | | | | | ACPI: Fix lockdep false positives in acpi_power_off()Rafael J. Wysocki2011-07-13
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | All ACPICA locks are allocated by the same function, acpi_os_create_lock(), with the help of a local variable called "lock". Thus, when lockdep is enabled, it uses "lock" as the name of all those locks and regards them as instances of the same lock, which causes it to report possible locking problems with them when there aren't any. To work around this problem, define acpi_os_create_lock() as a macro and make it pass its argument to spin_lock_init(), so that lockdep uses it as the name of the new lock. Define this macron in a Linux-specific file, to minimize the resulting modifications of the OS-independent ACPICA parts. This change is based on an earlier patch from Andrea Righi and it addresses a regression from 2.6.39 tracked as https://bugzilla.kernel.org/show_bug.cgi?id=38152 Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Reported-and-tested-by: Borislav Petkov <bp@alien8.de> Tested-by: Andrea Righi <andrea@betterlinux.com> Reviewed-by: Florian Mickler <florian@mickler.org> Signed-off-by: Len Brown <len.brown@intel.com>
| | | * | | | | | | | | | | | ACPI, APEI, HEST, Detect duplicated hardware error source IDHuang Ying2011-07-13
| | | |/ / / / / / / / / / / | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The firmware on some machine will report duplicated hardware error source ID in HEST. This is considered a firmware bug. To provide better warning message, this patch adds duplicated hardware error source ID detecting and corresponding printk. This patch fixes #37412 on kernel bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=37412 Reported-by: marconifabio@ubuntu-it.org Signed-off-by: Huang Ying <ying.huang@intel.com> Tested-by: Mathias <janedo.spam@gmail.com> Signed-off-by: Len Brown <len.brown@intel.com>
| | * / / / / / / / / / / / ACPI: Fixes device power states array overflowLin Ming2011-07-13
| | |/ / / / / / / / / / / | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Commit 28c2103 added new state ACPI_STATE_D3_COLD, so the device power states array must be expanded by one also. v2: Use ACPI_D_STATE_COUNT instead of number 5 for the array size. Reported-by: Dan Carpenter <error27@gmail.com> Suggested-by: Oldřich Jedlička <oldium.pro@seznam.cz> Signed-off-by: Lin Ming <ming.m.lin@intel.com> Signed-off-by: Len Brown <len.brown@intel.com>
| * | | | | | | | | | | | Merge branch 'pm-fixes' of ↵Linus Torvalds2011-07-17
| |\ \ \ \ \ \ \ \ \ \ \ \ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | git://git.kernel.org/pub/scm/linux/kernel/git/rafael/suspend-2.6 * 'pm-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/suspend-2.6: PM / MIPS: Convert i8259.c to using syscore_ops
| | * | | | | | | | | | | | PM / MIPS: Convert i8259.c to using syscore_opsRafael J. Wysocki2011-07-15
| | | |_|_|_|_|/ / / / / / | | |/| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The code in arch/mips/kernel/i8259.c still hasn't been converted to using struct syscore_ops instead of a sysdev for resume and shutdown. As a result, this code doesn't build any more after suspend, resume and shutdown callbacks have been removed from struct sysdev_class. Fix this problem by converting i8259.c to using syscore_ops. Reported-and-tested-by: Roland Vossen <rvossen@broadcom.com> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Acked-by: Ralf Baechle <ralf@linux-mips.org>
| * | | | | | | | | | | | Merge branch 's5p-fixes-for-linus' of ↵Linus Torvalds2011-07-17
| |\ \ \ \ \ \ \ \ \ \ \ \ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | git://git.kernel.org/pub/scm/linux/kernel/git/kgene/linux-samsung * 's5p-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/kgene/linux-samsung: ARM: SAMSUNG: DMA Cleanup as per sparse ARM: SAMSUNG: Check NULL return from irq_alloc_generic_chip
| | * | | | | | | | | | | | ARM: SAMSUNG: DMA Cleanup as per sparseSangwook Lee2011-07-16
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Function declaration differs between file: dma.c and file:dma.h and SPARSE (Documentation/sparse.txt) gives error messages All dma channels are members of 'enum dma_ch' and not 'unsigned int' Please have a look at channel definitions in: arch/arm/mach-s3c64xx/include/mach/dma.h arch/arm/plat-samsung/include/plat/s3c-dma-pl330.h arch/arm/mach-s3c2410/include/mach/dma.h So all arguments should be of type 'enum dma_ch' Signed-off-by: Sangwook Lee <sangwook.lee@linaro.org> Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
| | * | | | | | | | | | | | ARM: SAMSUNG: Check NULL return from irq_alloc_generic_chipTodd Poynor2011-07-15
| | | |_|_|_|_|/ / / / / / | | |/| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Signed-off-by: Todd Poynor <toddpoynor@google.com> Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
| * | | | | | | | | | | | Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6Linus Torvalds2011-07-17
| |\ \ \ \ \ \ \ \ \ \ \ \ | | |_|_|_|_|/ / / / / / / | |/| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6: sparc: sun4m SMP: fix wrong shift instruction in IPI handler sparc32,leon: Added __init declaration to leon_flush_needed() sparc/irqs: Do not trace arch_local_{*,irq_*} functions
| | * | | | | | | | | | | sparc: sun4m SMP: fix wrong shift instruction in IPI handlerWill Simoneau2011-07-16
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This shift instruction appears to be shifting in the wrong direction. Without this change, my SparcStation-20MP hangs just after bringing up the second CPU: Entering SMP Mode... Starting CPU 2 at f02b4e90 Brought up 2 CPUs Total of 2 processors activated (99.52 BogoMIPS). *** stuck *** Signed-off-by: Will Simoneau <simoneau@ele.uri.edu> Signed-off-by: David S. Miller <davem@davemloft.net>
| | * | | | | | | | | | | sparc32,leon: Added __init declaration to leon_flush_needed()Matthias Rosenfelder2011-07-06
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The function leon_flush_needed() is called only during bootup from another __init function. Therefore, we can also add __init to leon_flush_needed(). Signed-off-by: Matthias Rosenfelder <rosenfelder.lkml@googlemail.com> Acked-by: Daniel Hellstrom <daniel@gaisler.com> Signed-off-by: David S. Miller <davem@davemloft.net>
| | * | | | | | | | | | | sparc/irqs: Do not trace arch_local_{*,irq_*} functionsSteven Rostedt2011-07-06
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Do not trace arch_local_save_flags(), arch_local_irq_*() and friends. Although they are marked inline, gcc may still make a function out of them and add it to the pool of functions that are traced by the function tracer. This can cause undesirable results (kernel panic, triple faults, etc). Add the notrace notation to prevent them from ever being traced. Signed-off-by: Steven Rostedt <rostedt@goodmis.org> Signed-off-by: David S. Miller <davem@davemloft.net>
| * | | | | | | | | | | | Merge branch 'gpio/merge' of git://git.secretlab.ca/git/linux-2.6Linus Torvalds2011-07-15
| |\ \ \ \ \ \ \ \ \ \ \ \ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * 'gpio/merge' of git://git.secretlab.ca/git/linux-2.6: gpio: wm831x: add a missing break in wm831x_gpio_dbg_show
| | * | | | | | | | | | | | gpio: wm831x: add a missing break in wm831x_gpio_dbg_showAxel Lin2011-07-15
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Signed-off-by: Axel Lin <axel.lin@gmail.com> Acked-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
| * | | | | | | | | | | | | ARM: fix regression in IXP4xx clocksourceRichard Cochran2011-07-15
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Commit 234b6ceddb4fc2a4bc5b9a7670f070f6e69e0868 clocksource: convert ARM 32-bit up counting clocksources broke the build for ixp4xx and made big endian operation impossible. This commit restores the original behaviour. Signed-off-by: Richard Cochran <richard.cochran@omicron.at> Signed-off-by: Krzysztof Hałasa <khc@pm.waw.pl> [ Thomas says that we might want to have generic BE accessor functions to the MMIO clock source, but that hasn't happened yet, so in the meantime this seems to be the short-term fix for the particular problem - Linus ] Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
| * | | | | | | | | | | | | Merge branch 'for-linus' of ↵Linus Torvalds2011-07-15
| |\ \ \ \ \ \ \ \ \ \ \ \ \ | | |_|_|_|/ / / / / / / / / | |/| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | git://git.kernel.org/pub/scm/linux/kernel/git/ryusuke/nilfs2 * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ryusuke/nilfs2: nilfs2: remove resize from unsupported features list
| | * | | | | | | | | | | | nilfs2: remove resize from unsupported features listRyusuke Konishi2011-07-13
| | | |_|/ / / / / / / / / | | |/| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Resize feature was supported by the commit 4e33f9eab07e but it was not reflected to the list of unsupported features in nilfs2.txt file. This updates the list to fix discrepancy. Signed-off-by: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
| * | | | | | | | | | | | Merge branch 'hwmon-for-linus' of ↵Linus Torvalds2011-07-15
| |\ \ \ \ \ \ \ \ \ \ \ \ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | git://git.kernel.org/pub/scm/linux/kernel/git/groeck/staging * 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/staging: hwmon: (adm1275) Fix coefficients per datasheet revision B hwmon: (pmbus) Use long variables for register to data conversions
| | * | | | | | | | | | | | hwmon: (adm1275) Fix coefficients per datasheet revision BGuenter Roeck2011-07-15
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Coefficients to convert chip register values to voltage/current have been slightly changed in revision B of the chip datasheet. Update driver coefficients to match the coefficients in the datasheet. Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com> Acked-by: Jean Delvare <khali@linux-fr.org>
| | * | | | | | | | | | | | hwmon: (pmbus) Use long variables for register to data conversionsGuenter Roeck2011-07-12
| | |/ / / / / / / / / / / | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Using integer variable types for register to data conversions can cause overflows especially for power calculations, which are in microwatt. Use long variables instead. Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com> Acked-by: Jean Delvare <khali@linux-fr.org> Cc: stable@kernel.org # 2.6.39+
| * | | | | | | | | | | | Merge branch 'drm-fixes' of ↵Linus Torvalds2011-07-15
| |\ \ \ \ \ \ \ \ \ \ \ \ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6 * 'drm-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6: drm/radeon/kms: add new NI pci ids
| | * | | | | | | | | | | | drm/radeon/kms: add new NI pci idsAlex Deucher2011-07-15
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Signed-off-by: Alex Deucher <alexander.deucher@amd.com> Cc: stable@kernel.org Signed-off-by: Dave Airlie <airlied@redhat.com>
| * | | | | | | | | | | | | Merge branch 'for-linus' of ↵Linus Torvalds2011-07-15
| |\ \ \ \ \ \ \ \ \ \ \ \ \ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6 * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6: fix loop checks in d_materialise_unique() Fix ->d_lock locking order in unlazy_walk()
| | * | | | | | | | | | | | | fix loop checks in d_materialise_unique()Al Viro2011-07-14
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Both __d_unalias() and __d_materialise_dentry() need loop prevention. Grab rename_lock in caller, check for loops there... As a side benefit, we have dentry_lock_for_move() called only under rename_lock, which seriously reduces deadlock potential of the execrable "locking order" used for ->d_lock. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
| | * | | | | | | | | | | | | Fix ->d_lock locking order in unlazy_walk()Al Viro2011-07-12
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Make sure that child is still a child of parent before nested locking of child->d_lock in unlazy_walk(); otherwise we are risking a violation of locking order and deadlocks. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
| * | | | | | | | | | | | | | Merge branch 'rcu/urgent' of ↵Linus Torvalds2011-07-15
| |\ \ \ \ \ \ \ \ \ \ \ \ \ \ | | | |_|_|_|_|_|_|_|_|_|_|/ / | | |/| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-2.6-rcu * 'rcu/urgent' of git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-2.6-rcu: rcu: Prevent RCU callbacks from executing before scheduler initialized
| | * | | | | | | | | | | | | rcu: Prevent RCU callbacks from executing before scheduler initializedPaul E. McKenney2011-07-13
| | | |_|/ / / / / / / / / / | | |/| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Under some rare but real combinations of configuration parameters, RCU callbacks are posted during early boot that use kernel facilities that are not yet initialized. Therefore, when these callbacks are invoked, hard hangs and crashes ensue. This commit therefore prevents RCU callbacks from being invoked until after the scheduler is fully up and running, as in after multiple tasks have been spawned. It might well turn out that a better approach is to identify the specific RCU callbacks that are causing this problem, but that discussion will wait until such time as someone really needs an RCU callback to be invoked (as opposed to merely registered) during early boot. Reported-by: julie Sullivan <kernelmail.jms@gmail.com> Reported-by: RKK <kulkarni.ravi4@gmail.com> Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Tested-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> Tested-by: julie Sullivan <kernelmail.jms@gmail.com> Tested-by: RKK <kulkarni.ravi4@gmail.com>
| * | | | | | | | | | | | | sched: Fix 32bit racePeter Zijlstra2011-07-15
| | |_|/ / / / / / / / / / | |/| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Commit 3fe1698b7fe0 ("sched: Deal with non-atomic min_vruntime reads on 32bit") forgot to initialize min_vruntime_copy which could lead to an infinite while loop in task_waking_fair() under some circumstances (early boot, lucky timing). [ This bug was also reported by others that blamed it on the RCU initialization problems ] Reported-and-tested-by: Bruno Wolff III <bruno@wolff.to> Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> Reviewed-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
| * | | | | | | | | | | | Merge git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-2.6-fixesLinus Torvalds2011-07-14
| |\ \ \ \ \ \ \ \ \ \ \ \ | | |_|_|_|_|_|_|/ / / / / | |/| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-2.6-fixes: GFS2: Resolve inode eviction and ail list interaction bug GFS2: Fix race during filesystem mount GFS2: force a log flush when invalidating the rindex glock
| | * | | | | | | | | | | GFS2: Resolve inode eviction and ail list interaction bugSteven Whitehouse2011-07-14
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This patch contains a few misc fixes which resolve a recently reported issue. This patch has been a real team effort and has received a lot of testing. The first issue is that the ail lock needs to be held over a few more operations. The lock thats added into gfs2_releasepage() may possibly be a candidate for replacing with RCU at some future point, but at this stage we've gone for the obvious fix. The second issue is that gfs2_write_inode() can end up calling a glock recursively when called from gfs2_evict_inode() via the syncing code, so it needs a guard added. The third issue is that we either need to not truncate the metadata pages of inodes which have zero link count, but which we cannot deallocate due to them still being in use by other nodes, or we need to ensure that those pages have all made it through the journal and ail lists first. This patch takes the former approach, but the latter has also been tested and there is nothing to choose between them performance-wise. So again, we could revise that decision in the future. Also, the inode eviction process is now better documented. Signed-off-by: Steven Whitehouse <swhiteho@redhat.com> Tested-by: Bob Peterson <rpeterso@redhat.com> Tested-by: Abhijith Das <adas@redhat.com> Reported-by: Barry J. Marson <bmarson@redhat.com> Reported-by: David Teigland <teigland@redhat.com>
| | * | | | | | | | | | | GFS2: Fix race during filesystem mountSteven Whitehouse2011-07-12
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | There is a potential race during filesystem mounting which has recently been reported. It occurs when the userland gfs_controld is able to process requests fast enough that it tries to use the sysfs interface before the lock module is properly initialised. This is a pretty unusual case as normally the lock module initialisation is very quick compared with gfs_controld. This patch adds an interruptible completion which is used to ensure that userland will wait for the initialisation of the lock module to complete. There are other potential solutions to this problem, but this is the quickest at this stage and has been tested both with and without mount.gfs2 present in the system. Signed-off-by: Steven Whitehouse <swhiteho@redhat.com> Reported-by: David Booher <dbooher@adams.net>
| | * | | | | | | | | | | GFS2: force a log flush when invalidating the rindex glockBenjamin Marzinski2011-07-12
| | |/ / / / / / / / / / | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Right now, there is nothing that forces the log to get flushed when a node drops its rindex glock so that another node can grow the filesystem. If the log doesn't get flushed, GFS2 can corrupt the sd_log_le_rg list in the following way. A node puts an rgd on the list in rg_lo_add(), and then the rindex glock is dropped so the other node can grow the filesystem. When the node reacquires the rindex glock, that rgd gets deleted in clear_rgrpdi() before ever being removed from the list by gfs2_log_flush(). This code simply forces a log flush when the rindex glock is invalidated, solving the problem. Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com> Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
| * | | | | | | | | | | Merge branch 'for-linus' of ↵Linus Torvalds2011-07-13
| |\ \ \ \ \ \ \ \ \ \ \ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc: mmc: core: Bus width testing needs to handle suspend/resume
| | * | | | | | | | | | | mmc: core: Bus width testing needs to handle suspend/resumePhilip Rakity2011-07-13
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | On reading the ext_csd for the first time (in 1 bit mode), save the ext_csd information needed for bus width compare. On every pass we make re-reading the ext_csd, compare the data against the saved ext_csd data. This fixes a regression introduced in 3.0-rc1 by 08ee80cc397ac1a3 ("mmc: core: eMMC bus width may not work on all platforms"), which incorrectly assumed we would be re-reading the ext_csd at resume- time. Signed-off-by: Philip Rakity <prakity@marvell.com> Tested-by: Jaehoon Chung <jh80.chung@samsung.com> Signed-off-by: Chris Ball <cjb@laptop.org>
| * | | | | | | | | | | | Merge branch 'bugfixes' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6Linus Torvalds2011-07-13
| |\ \ \ \ \ \ \ \ \ \ \ \ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * 'bugfixes' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6: SUNRPC: Fix use of static variable in rpcb_getport_async NFSv4.1: update nfs4_fattr_bitmap_maxsz SUNRPC: Fix a race between work-queue and rpc_killall_tasks pnfs: write: Set mds_offset in the generic layer - it is needed by all LDs
| | * | | | | | | | | | | | SUNRPC: Fix use of static variable in rpcb_getport_asyncBen Greear2011-07-12
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Because struct rpcbind_args *map was declared static, if two threads entered this method at the same time, the values assigned to map could be sent two two differen tasks. This could cause all sorts of problems, include use-after-free and double-free of memory. Fix this by removing the static declaration so that the map pointer is on the stack. Signed-off-by: Ben Greear <greearb@candelatech.com> Cc: stable@kernel.org Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
| | * | | | | | | | | | | | NFSv4.1: update nfs4_fattr_bitmap_maxszAndy Adamson2011-07-11
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Attribute IDs assigned in RFC 5661 now require three bitmaps. Fixes hitting a BUG_ON in xdr_shrink_bufhead when getting ACLs. Signed-off-by: Andy Adamson <andros@netapp.com> Cc:stable@kernel.org [2.6.39] Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
| | * | | | | | | | | | | | SUNRPC: Fix a race between work-queue and rpc_killall_tasksTrond Myklebust2011-07-07
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Since rpc_killall_tasks may modify the rpc_task's tk_action field without any locking, we need to be careful when dereferencing it. Reported-by: Ben Greear <greearb@candelatech.com> Tested-by: Ben Greear <greearb@candelatech.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> Cc: stable@kernel.org
| | * | | | | | | | | | | | pnfs: write: Set mds_offset in the generic layer - it is needed by all LDsBoaz Harrosh2011-06-28
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | In current pnfs tree, all the layouts set mds_offset in their .write_pagelist member. mds_offset is only used by generic layer and should be handled by it. This patch is for upstream. It is needed in this -rc series to fix a bug in objects layout_commit. I'll send patches for objects and blocks to be squashed into current pnfs tree. TODO: It looks like the read path needs the same patch. Signed-off-by: Boaz Harrosh <bharrosh@panasas.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
| * | | | | | | | | | | | | Merge branch 'rc-fixes' of ↵Linus Torvalds2011-07-13
| |\ \ \ \ \ \ \ \ \ \ \ \ \ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | git://git.kernel.org/pub/scm/linux/kernel/git/mmarek/kbuild-2.6 * 'rc-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/mmarek/kbuild-2.6: kbuild: Do not write to builddir in modules_install
| | * | | | | | | | | | | | | kbuild: Do not write to builddir in modules_installMichal Marek2011-07-12
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Let depmod.sh create a temporary directory in /tmp instead of writing to the build directory as root. The mktemp utility should be available on any recent system (and there is already scripts/gen_initramfs_list.sh relying on it). Reported-by: Christian Kujau <lists@nerdbynature.de> Signed-off-by: Michal Marek <mmarek@suse.cz>
| * | | | | | | | | | | | | | Merge branch 'drm-fixes' of ↵Linus Torvalds2011-07-13
| |\ \ \ \ \ \ \ \ \ \ \ \ \ \ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6 * 'drm-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6: drm/radeon/kms/evergreen: emit SQ_LDS_RESOURCE_MGMT for blits agp/intel: Fix typo in G4x_GMCH_SIZE_VT_2M drm/radeon/kms: fix typo in read_disabled vbios code drm/radeon/kms: use correct BUS_CNTL reg on rs600 drm/radeon/kms: fix backend map typo on juniper drm/radeon/kms: fix regression in hotplug
| | * | | | | | | | | | | | | | drm/radeon/kms/evergreen: emit SQ_LDS_RESOURCE_MGMT for blitsAlex Deucher2011-07-13
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Compute drivers may change this, so make sure to emit it to avoid errors in bo blits. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=39119 Signed-off-by: Alex Deucher <alexdeucher@gmail.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
| | * | | | | | | | | | | | | | agp/intel: Fix typo in G4x_GMCH_SIZE_VT_2MChris Wilson2011-07-13
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Konstantin Belousov found an error in the define of G4x_GMCH_SIZE_VT_2M relative to the GMCH specs, and confirmed that indeed one of his users with a Q45 reports 0xb not 0xc for a 2/2MiB GATT. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Konstantin Belousov <kostikbel@gmail.com> Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Dave Airlie <airlied@redhat.com>
"hl opt">.gen.tx_packets = bp->xmt_total_frames; bp->stats.gen.rx_bytes = bp->rcv_total_bytes; bp->stats.gen.tx_bytes = bp->xmt_total_bytes; bp->stats.gen.rx_errors = bp->rcv_crc_errors + bp->rcv_frame_status_errors + bp->rcv_length_errors; bp->stats.gen.tx_errors = bp->xmt_length_errors; bp->stats.gen.rx_dropped = bp->rcv_discards; bp->stats.gen.tx_dropped = bp->xmt_discards; bp->stats.gen.multicast = bp->rcv_multicast_frames; bp->stats.gen.collisions = 0; /* always zero (0) for FDDI */ /* Get FDDI SMT MIB objects */ bp->cmd_req_virt->cmd_type = PI_CMD_K_SMT_MIB_GET; if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS) return (struct net_device_stats *)&bp->stats; /* Fill the bp->stats structure with the SMT MIB object values */ memcpy(bp->stats.smt_station_id, &bp->cmd_rsp_virt->smt_mib_get.smt_station_id, sizeof(bp->cmd_rsp_virt->smt_mib_get.smt_station_id)); bp->stats.smt_op_version_id = bp->cmd_rsp_virt->smt_mib_get.smt_op_version_id; bp->stats.smt_hi_version_id = bp->cmd_rsp_virt->smt_mib_get.smt_hi_version_id; bp->stats.smt_lo_version_id = bp->cmd_rsp_virt->smt_mib_get.smt_lo_version_id; memcpy(bp->stats.smt_user_data, &bp->cmd_rsp_virt->smt_mib_get.smt_user_data, sizeof(bp->cmd_rsp_virt->smt_mib_get.smt_user_data)); bp->stats.smt_mib_version_id = bp->cmd_rsp_virt->smt_mib_get.smt_mib_version_id; bp->stats.smt_mac_cts = bp->cmd_rsp_virt->smt_mib_get.smt_mac_ct; bp->stats.smt_non_master_cts = bp->cmd_rsp_virt->smt_mib_get.smt_non_master_ct; bp->stats.smt_master_cts = bp->cmd_rsp_virt->smt_mib_get.smt_master_ct; bp->stats.smt_available_paths = bp->cmd_rsp_virt->smt_mib_get.smt_available_paths; bp->stats.smt_config_capabilities = bp->cmd_rsp_virt->smt_mib_get.smt_config_capabilities; bp->stats.smt_config_policy = bp->cmd_rsp_virt->smt_mib_get.smt_config_policy; bp->stats.smt_connection_policy = bp->cmd_rsp_virt->smt_mib_get.smt_connection_policy; bp->stats.smt_t_notify = bp->cmd_rsp_virt->smt_mib_get.smt_t_notify; bp->stats.smt_stat_rpt_policy = bp->cmd_rsp_virt->smt_mib_get.smt_stat_rpt_policy; bp->stats.smt_trace_max_expiration = bp->cmd_rsp_virt->smt_mib_get.smt_trace_max_expiration; bp->stats.smt_bypass_present = bp->cmd_rsp_virt->smt_mib_get.smt_bypass_present; bp->stats.smt_ecm_state = bp->cmd_rsp_virt->smt_mib_get.smt_ecm_state; bp->stats.smt_cf_state = bp->cmd_rsp_virt->smt_mib_get.smt_cf_state; bp->stats.smt_remote_disconnect_flag = bp->cmd_rsp_virt->smt_mib_get.smt_remote_disconnect_flag; bp->stats.smt_station_status = bp->cmd_rsp_virt->smt_mib_get.smt_station_status; bp->stats.smt_peer_wrap_flag = bp->cmd_rsp_virt->smt_mib_get.smt_peer_wrap_flag; bp->stats.smt_time_stamp = bp->cmd_rsp_virt->smt_mib_get.smt_msg_time_stamp.ls; bp->stats.smt_transition_time_stamp = bp->cmd_rsp_virt->smt_mib_get.smt_transition_time_stamp.ls; bp->stats.mac_frame_status_functions = bp->cmd_rsp_virt->smt_mib_get.mac_frame_status_functions; bp->stats.mac_t_max_capability = bp->cmd_rsp_virt->smt_mib_get.mac_t_max_capability; bp->stats.mac_tvx_capability = bp->cmd_rsp_virt->smt_mib_get.mac_tvx_capability; bp->stats.mac_available_paths = bp->cmd_rsp_virt->smt_mib_get.mac_available_paths; bp->stats.mac_current_path = bp->cmd_rsp_virt->smt_mib_get.mac_current_path; memcpy(bp->stats.mac_upstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_upstream_nbr, FDDI_K_ALEN); memcpy(bp->stats.mac_downstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_downstream_nbr, FDDI_K_ALEN); memcpy(bp->stats.mac_old_upstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_old_upstream_nbr, FDDI_K_ALEN); memcpy(bp->stats.mac_old_downstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_old_downstream_nbr, FDDI_K_ALEN); bp->stats.mac_dup_address_test = bp->cmd_rsp_virt->smt_mib_get.mac_dup_address_test; bp->stats.mac_requested_paths = bp->cmd_rsp_virt->smt_mib_get.mac_requested_paths; bp->stats.mac_downstream_port_type = bp->cmd_rsp_virt->smt_mib_get.mac_downstream_port_type; memcpy(bp->stats.mac_smt_address, &bp->cmd_rsp_virt->smt_mib_get.mac_smt_address, FDDI_K_ALEN); bp->stats.mac_t_req = bp->cmd_rsp_virt->smt_mib_get.mac_t_req; bp->stats.mac_t_neg = bp->cmd_rsp_virt->smt_mib_get.mac_t_neg; bp->stats.mac_t_max = bp->cmd_rsp_virt->smt_mib_get.mac_t_max; bp->stats.mac_tvx_value = bp->cmd_rsp_virt->smt_mib_get.mac_tvx_value; bp->stats.mac_frame_error_threshold = bp->cmd_rsp_virt->smt_mib_get.mac_frame_error_threshold; bp->stats.mac_frame_error_ratio = bp->cmd_rsp_virt->smt_mib_get.mac_frame_error_ratio; bp->stats.mac_rmt_state = bp->cmd_rsp_virt->smt_mib_get.mac_rmt_state; bp->stats.mac_da_flag = bp->cmd_rsp_virt->smt_mib_get.mac_da_flag; bp->stats.mac_una_da_flag = bp->cmd_rsp_virt->smt_mib_get.mac_unda_flag; bp->stats.mac_frame_error_flag = bp->cmd_rsp_virt->smt_mib_get.mac_frame_error_flag; bp->stats.mac_ma_unitdata_available = bp->cmd_rsp_virt->smt_mib_get.mac_ma_unitdata_available; bp->stats.mac_hardware_present = bp->cmd_rsp_virt->smt_mib_get.mac_hardware_present; bp->stats.mac_ma_unitdata_enable = bp->cmd_rsp_virt->smt_mib_get.mac_ma_unitdata_enable; bp->stats.path_tvx_lower_bound = bp->cmd_rsp_virt->smt_mib_get.path_tvx_lower_bound; bp->stats.path_t_max_lower_bound = bp->cmd_rsp_virt->smt_mib_get.path_t_max_lower_bound; bp->stats.path_max_t_req = bp->cmd_rsp_virt->smt_mib_get.path_max_t_req; memcpy(bp->stats.path_configuration, &bp->cmd_rsp_virt->smt_mib_get.path_configuration, sizeof(bp->cmd_rsp_virt->smt_mib_get.path_configuration)); bp->stats.port_my_type[0] = bp->cmd_rsp_virt->smt_mib_get.port_my_type[0]; bp->stats.port_my_type[1] = bp->cmd_rsp_virt->smt_mib_get.port_my_type[1]; bp->stats.port_neighbor_type[0] = bp->cmd_rsp_virt->smt_mib_get.port_neighbor_type[0]; bp->stats.port_neighbor_type[1] = bp->cmd_rsp_virt->smt_mib_get.port_neighbor_type[1]; bp->stats.port_connection_policies[0] = bp->cmd_rsp_virt->smt_mib_get.port_connection_policies[0]; bp->stats.port_connection_policies[1] = bp->cmd_rsp_virt->smt_mib_get.port_connection_policies[1]; bp->stats.port_mac_indicated[0] = bp->cmd_rsp_virt->smt_mib_get.port_mac_indicated[0]; bp->stats.port_mac_indicated[1] = bp->cmd_rsp_virt->smt_mib_get.port_mac_indicated[1]; bp->stats.port_current_path[0] = bp->cmd_rsp_virt->smt_mib_get.port_current_path[0]; bp->stats.port_current_path[1] = bp->cmd_rsp_virt->smt_mib_get.port_current_path[1]; memcpy(&bp->stats.port_requested_paths[0*3], &bp->cmd_rsp_virt->smt_mib_get.port_requested_paths[0], 3); memcpy(&bp->stats.port_requested_paths[1*3], &bp->cmd_rsp_virt->smt_mib_get.port_requested_paths[1], 3); bp->stats.port_mac_placement[0] = bp->cmd_rsp_virt->smt_mib_get.port_mac_placement[0]; bp->stats.port_mac_placement[1] = bp->cmd_rsp_virt->smt_mib_get.port_mac_placement[1]; bp->stats.port_available_paths[0] = bp->cmd_rsp_virt->smt_mib_get.port_available_paths[0]; bp->stats.port_available_paths[1] = bp->cmd_rsp_virt->smt_mib_get.port_available_paths[1]; bp->stats.port_pmd_class[0] = bp->cmd_rsp_virt->smt_mib_get.port_pmd_class[0]; bp->stats.port_pmd_class[1] = bp->cmd_rsp_virt->smt_mib_get.port_pmd_class[1]; bp->stats.port_connection_capabilities[0] = bp->cmd_rsp_virt->smt_mib_get.port_connection_capabilities[0]; bp->stats.port_connection_capabilities[1] = bp->cmd_rsp_virt->smt_mib_get.port_connection_capabilities[1]; bp->stats.port_bs_flag[0] = bp->cmd_rsp_virt->smt_mib_get.port_bs_flag[0]; bp->stats.port_bs_flag[1] = bp->cmd_rsp_virt->smt_mib_get.port_bs_flag[1]; bp->stats.port_ler_estimate[0] = bp->cmd_rsp_virt->smt_mib_get.port_ler_estimate[0]; bp->stats.port_ler_estimate[1] = bp->cmd_rsp_virt->smt_mib_get.port_ler_estimate[1]; bp->stats.port_ler_cutoff[0] = bp->cmd_rsp_virt->smt_mib_get.port_ler_cutoff[0]; bp->stats.port_ler_cutoff[1] = bp->cmd_rsp_virt->smt_mib_get.port_ler_cutoff[1]; bp->stats.port_ler_alarm[0] = bp->cmd_rsp_virt->smt_mib_get.port_ler_alarm[0]; bp->stats.port_ler_alarm[1] = bp->cmd_rsp_virt->smt_mib_get.port_ler_alarm[1]; bp->stats.port_connect_state[0] = bp->cmd_rsp_virt->smt_mib_get.port_connect_state[0]; bp->stats.port_connect_state[1] = bp->cmd_rsp_virt->smt_mib_get.port_connect_state[1]; bp->stats.port_pcm_state[0] = bp->cmd_rsp_virt->smt_mib_get.port_pcm_state[0]; bp->stats.port_pcm_state[1] = bp->cmd_rsp_virt->smt_mib_get.port_pcm_state[1]; bp->stats.port_pc_withhold[0] = bp->cmd_rsp_virt->smt_mib_get.port_pc_withhold[0]; bp->stats.port_pc_withhold[1] = bp->cmd_rsp_virt->smt_mib_get.port_pc_withhold[1]; bp->stats.port_ler_flag[0] = bp->cmd_rsp_virt->smt_mib_get.port_ler_flag[0]; bp->stats.port_ler_flag[1] = bp->cmd_rsp_virt->smt_mib_get.port_ler_flag[1]; bp->stats.port_hardware_present[0] = bp->cmd_rsp_virt->smt_mib_get.port_hardware_present[0]; bp->stats.port_hardware_present[1] = bp->cmd_rsp_virt->smt_mib_get.port_hardware_present[1]; /* Get FDDI counters */ bp->cmd_req_virt->cmd_type = PI_CMD_K_CNTRS_GET; if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS) return (struct net_device_stats *)&bp->stats; /* Fill the bp->stats structure with the FDDI counter values */ bp->stats.mac_frame_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.frame_cnt.ls; bp->stats.mac_copied_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.copied_cnt.ls; bp->stats.mac_transmit_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.transmit_cnt.ls; bp->stats.mac_error_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.error_cnt.ls; bp->stats.mac_lost_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.lost_cnt.ls; bp->stats.port_lct_fail_cts[0] = bp->cmd_rsp_virt->cntrs_get.cntrs.lct_rejects[0].ls; bp->stats.port_lct_fail_cts[1] = bp->cmd_rsp_virt->cntrs_get.cntrs.lct_rejects[1].ls; bp->stats.port_lem_reject_cts[0] = bp->cmd_rsp_virt->cntrs_get.cntrs.lem_rejects[0].ls; bp->stats.port_lem_reject_cts[1] = bp->cmd_rsp_virt->cntrs_get.cntrs.lem_rejects[1].ls; bp->stats.port_lem_cts[0] = bp->cmd_rsp_virt->cntrs_get.cntrs.link_errors[0].ls; bp->stats.port_lem_cts[1] = bp->cmd_rsp_virt->cntrs_get.cntrs.link_errors[1].ls; return (struct net_device_stats *)&bp->stats; } /* * ============================== * = dfx_ctl_set_multicast_list = * ============================== * * Overview: * Enable/Disable LLC frame promiscuous mode reception * on the adapter and/or update multicast address table. * * Returns: * None * * Arguments: * dev - pointer to device information * * Functional Description: * This routine follows a fairly simple algorithm for setting the * adapter filters and CAM: * * if IFF_PROMISC flag is set * enable LLC individual/group promiscuous mode * else * disable LLC individual/group promiscuous mode * if number of incoming multicast addresses > * (CAM max size - number of unicast addresses in CAM) * enable LLC group promiscuous mode * set driver-maintained multicast address count to zero * else * disable LLC group promiscuous mode * set driver-maintained multicast address count to incoming count * update adapter CAM * update adapter filters * * Return Codes: * None * * Assumptions: * Multicast addresses are presented in canonical (LSB) format. * * Side Effects: * On-board adapter CAM and filters are updated. */ static void dfx_ctl_set_multicast_list(struct net_device *dev) { DFX_board_t *bp = netdev_priv(dev); int i; /* used as index in for loop */ struct netdev_hw_addr *ha; /* Enable LLC frame promiscuous mode, if necessary */ if (dev->flags & IFF_PROMISC) bp->ind_group_prom = PI_FSTATE_K_PASS; /* Enable LLC ind/group prom mode */ /* Else, update multicast address table */ else { bp->ind_group_prom = PI_FSTATE_K_BLOCK; /* Disable LLC ind/group prom mode */ /* * Check whether incoming multicast address count exceeds table size * * Note: The adapters utilize an on-board 64 entry CAM for * supporting perfect filtering of multicast packets * and bridge functions when adding unicast addresses. * There is no hash function available. To support * additional multicast addresses, the all multicast * filter (LLC group promiscuous mode) must be enabled. * * The firmware reserves two CAM entries for SMT-related * multicast addresses, which leaves 62 entries available. * The following code ensures that we're not being asked * to add more than 62 addresses to the CAM. If we are, * the driver will enable the all multicast filter. * Should the number of multicast addresses drop below * the high water mark, the filter will be disabled and * perfect filtering will be used. */ if (netdev_mc_count(dev) > (PI_CMD_ADDR_FILTER_K_SIZE - bp->uc_count)) { bp->group_prom = PI_FSTATE_K_PASS; /* Enable LLC group prom mode */ bp->mc_count = 0; /* Don't add mc addrs to CAM */ } else { bp->group_prom = PI_FSTATE_K_BLOCK; /* Disable LLC group prom mode */ bp->mc_count = netdev_mc_count(dev); /* Add mc addrs to CAM */ } /* Copy addresses to multicast address table, then update adapter CAM */ i = 0; netdev_for_each_mc_addr(ha, dev) memcpy(&bp->mc_table[i++ * FDDI_K_ALEN], ha->addr, FDDI_K_ALEN); if (dfx_ctl_update_cam(bp) != DFX_K_SUCCESS) { DBG_printk("%s: Could not update multicast address table!\n", dev->name); } else { DBG_printk("%s: Multicast address table updated! Added %d addresses.\n", dev->name, bp->mc_count); } } /* Update adapter filters */ if (dfx_ctl_update_filters(bp) != DFX_K_SUCCESS) { DBG_printk("%s: Could not update adapter filters!\n", dev->name); } else { DBG_printk("%s: Adapter filters updated!\n", dev->name); } } /* * =========================== * = dfx_ctl_set_mac_address = * =========================== * * Overview: * Add node address override (unicast address) to adapter * CAM and update dev_addr field in device table. * * Returns: * None * * Arguments: * dev - pointer to device information * addr - pointer to sockaddr structure containing unicast address to add * * Functional Description: * The adapter supports node address overrides by adding one or more * unicast addresses to the adapter CAM. This is similar to adding * multicast addresses. In this routine we'll update the driver and * device structures with the new address, then update the adapter CAM * to ensure that the adapter will copy and strip frames destined and * sourced by that address. * * Return Codes: * Always returns zero. * * Assumptions: * The address pointed to by addr->sa_data is a valid unicast * address and is presented in canonical (LSB) format. * * Side Effects: * On-board adapter CAM is updated. On-board adapter filters * may be updated. */ static int dfx_ctl_set_mac_address(struct net_device *dev, void *addr) { struct sockaddr *p_sockaddr = (struct sockaddr *)addr; DFX_board_t *bp = netdev_priv(dev); /* Copy unicast address to driver-maintained structs and update count */ memcpy(dev->dev_addr, p_sockaddr->sa_data, FDDI_K_ALEN); /* update device struct */ memcpy(&bp->uc_table[0], p_sockaddr->sa_data, FDDI_K_ALEN); /* update driver struct */ bp->uc_count = 1; /* * Verify we're not exceeding the CAM size by adding unicast address * * Note: It's possible that before entering this routine we've * already filled the CAM with 62 multicast addresses. * Since we need to place the node address override into * the CAM, we have to check to see that we're not * exceeding the CAM size. If we are, we have to enable * the LLC group (multicast) promiscuous mode filter as * in dfx_ctl_set_multicast_list. */ if ((bp->uc_count + bp->mc_count) > PI_CMD_ADDR_FILTER_K_SIZE) { bp->group_prom = PI_FSTATE_K_PASS; /* Enable LLC group prom mode */ bp->mc_count = 0; /* Don't add mc addrs to CAM */ /* Update adapter filters */ if (dfx_ctl_update_filters(bp) != DFX_K_SUCCESS) { DBG_printk("%s: Could not update adapter filters!\n", dev->name); } else { DBG_printk("%s: Adapter filters updated!\n", dev->name); } } /* Update adapter CAM with new unicast address */ if (dfx_ctl_update_cam(bp) != DFX_K_SUCCESS) { DBG_printk("%s: Could not set new MAC address!\n", dev->name); } else { DBG_printk("%s: Adapter CAM updated with new MAC address\n", dev->name); } return 0; /* always return zero */ } /* * ====================== * = dfx_ctl_update_cam = * ====================== * * Overview: * Procedure to update adapter CAM (Content Addressable Memory) * with desired unicast and multicast address entries. * * Returns: * Condition code * * Arguments: * bp - pointer to board information * * Functional Description: * Updates adapter CAM with current contents of board structure * unicast and multicast address tables. Since there are only 62 * free entries in CAM, this routine ensures that the command * request buffer is not overrun. * * Return Codes: * DFX_K_SUCCESS - Request succeeded * DFX_K_FAILURE - Request failed * * Assumptions: * All addresses being added (unicast and multicast) are in canonical * order. * * Side Effects: * On-board adapter CAM is updated. */ static int dfx_ctl_update_cam(DFX_board_t *bp) { int i; /* used as index */ PI_LAN_ADDR *p_addr; /* pointer to CAM entry */ /* * Fill in command request information * * Note: Even though both the unicast and multicast address * table entries are stored as contiguous 6 byte entries, * the firmware address filter set command expects each * entry to be two longwords (8 bytes total). We must be * careful to only copy the six bytes of each unicast and * multicast table entry into each command entry. This * is also why we must first clear the entire command * request buffer. */ memset(bp->cmd_req_virt, 0, PI_CMD_REQ_K_SIZE_MAX); /* first clear buffer */ bp->cmd_req_virt->cmd_type = PI_CMD_K_ADDR_FILTER_SET; p_addr = &bp->cmd_req_virt->addr_filter_set.entry[0]; /* Now add unicast addresses to command request buffer, if any */ for (i=0; i < (int)bp->uc_count; i++) { if (i < PI_CMD_ADDR_FILTER_K_SIZE) { memcpy(p_addr, &bp->uc_table[i*FDDI_K_ALEN], FDDI_K_ALEN); p_addr++; /* point to next command entry */ } } /* Now add multicast addresses to command request buffer, if any */ for (i=0; i < (int)bp->mc_count; i++) { if ((i + bp->uc_count) < PI_CMD_ADDR_FILTER_K_SIZE) { memcpy(p_addr, &bp->mc_table[i*FDDI_K_ALEN], FDDI_K_ALEN); p_addr++; /* point to next command entry */ } } /* Issue command to update adapter CAM, then return */ if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS) return DFX_K_FAILURE; return DFX_K_SUCCESS; } /* * ========================== * = dfx_ctl_update_filters = * ========================== * * Overview: * Procedure to update adapter filters with desired * filter settings. * * Returns: * Condition code * * Arguments: * bp - pointer to board information * * Functional Description: * Enables or disables filter using current filter settings. * * Return Codes: * DFX_K_SUCCESS - Request succeeded. * DFX_K_FAILURE - Request failed. * * Assumptions: * We must always pass up packets destined to the broadcast * address (FF-FF-FF-FF-FF-FF), so we'll always keep the * broadcast filter enabled. * * Side Effects: * On-board adapter filters are updated. */ static int dfx_ctl_update_filters(DFX_board_t *bp) { int i = 0; /* used as index */ /* Fill in command request information */ bp->cmd_req_virt->cmd_type = PI_CMD_K_FILTERS_SET; /* Initialize Broadcast filter - * ALWAYS ENABLED * */ bp->cmd_req_virt->filter_set.item[i].item_code = PI_ITEM_K_BROADCAST; bp->cmd_req_virt->filter_set.item[i++].value = PI_FSTATE_K_PASS; /* Initialize LLC Individual/Group Promiscuous filter */ bp->cmd_req_virt->filter_set.item[i].item_code = PI_ITEM_K_IND_GROUP_PROM; bp->cmd_req_virt->filter_set.item[i++].value = bp->ind_group_prom; /* Initialize LLC Group Promiscuous filter */ bp->cmd_req_virt->filter_set.item[i].item_code = PI_ITEM_K_GROUP_PROM; bp->cmd_req_virt->filter_set.item[i++].value = bp->group_prom; /* Terminate the item code list */ bp->cmd_req_virt->filter_set.item[i].item_code = PI_ITEM_K_EOL; /* Issue command to update adapter filters, then return */ if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS) return DFX_K_FAILURE; return DFX_K_SUCCESS; } /* * ====================== * = dfx_hw_dma_cmd_req = * ====================== * * Overview: * Sends PDQ DMA command to adapter firmware * * Returns: * Condition code * * Arguments: * bp - pointer to board information * * Functional Description: * The command request and response buffers are posted to the adapter in the manner * described in the PDQ Port Specification: * * 1. Command Response Buffer is posted to adapter. * 2. Command Request Buffer is posted to adapter. * 3. Command Request consumer index is polled until it indicates that request * buffer has been DMA'd to adapter. * 4. Command Response consumer index is polled until it indicates that response * buffer has been DMA'd from adapter. * * This ordering ensures that a response buffer is already available for the firmware * to use once it's done processing the request buffer. * * Return Codes: * DFX_K_SUCCESS - DMA command succeeded * DFX_K_OUTSTATE - Adapter is NOT in proper state * DFX_K_HW_TIMEOUT - DMA command timed out * * Assumptions: * Command request buffer has already been filled with desired DMA command. * * Side Effects: * None */ static int dfx_hw_dma_cmd_req(DFX_board_t *bp) { int status; /* adapter status */ int timeout_cnt; /* used in for loops */ /* Make sure the adapter is in a state that we can issue the DMA command in */ status = dfx_hw_adap_state_rd(bp); if ((status == PI_STATE_K_RESET) || (status == PI_STATE_K_HALTED) || (status == PI_STATE_K_DMA_UNAVAIL) || (status == PI_STATE_K_UPGRADE)) return DFX_K_OUTSTATE; /* Put response buffer on the command response queue */ bp->descr_block_virt->cmd_rsp[bp->cmd_rsp_reg.index.prod].long_0 = (u32) (PI_RCV_DESCR_M_SOP | ((PI_CMD_RSP_K_SIZE_MAX / PI_ALIGN_K_CMD_RSP_BUFF) << PI_RCV_DESCR_V_SEG_LEN)); bp->descr_block_virt->cmd_rsp[bp->cmd_rsp_reg.index.prod].long_1 = bp->cmd_rsp_phys; /* Bump (and wrap) the producer index and write out to register */ bp->cmd_rsp_reg.index.prod += 1; bp->cmd_rsp_reg.index.prod &= PI_CMD_RSP_K_NUM_ENTRIES-1; dfx_port_write_long(bp, PI_PDQ_K_REG_CMD_RSP_PROD, bp->cmd_rsp_reg.lword); /* Put request buffer on the command request queue */ bp->descr_block_virt->cmd_req[bp->cmd_req_reg.index.prod].long_0 = (u32) (PI_XMT_DESCR_M_SOP | PI_XMT_DESCR_M_EOP | (PI_CMD_REQ_K_SIZE_MAX << PI_XMT_DESCR_V_SEG_LEN)); bp->descr_block_virt->cmd_req[bp->cmd_req_reg.index.prod].long_1 = bp->cmd_req_phys; /* Bump (and wrap) the producer index and write out to register */ bp->cmd_req_reg.index.prod += 1; bp->cmd_req_reg.index.prod &= PI_CMD_REQ_K_NUM_ENTRIES-1; dfx_port_write_long(bp, PI_PDQ_K_REG_CMD_REQ_PROD, bp->cmd_req_reg.lword); /* * Here we wait for the command request consumer index to be equal * to the producer, indicating that the adapter has DMAed the request. */ for (timeout_cnt = 20000; timeout_cnt > 0; timeout_cnt--) { if (bp->cmd_req_reg.index.prod == (u8)(bp->cons_block_virt->cmd_req)) break; udelay(100); /* wait for 100 microseconds */ } if (timeout_cnt == 0) return DFX_K_HW_TIMEOUT; /* Bump (and wrap) the completion index and write out to register */ bp->cmd_req_reg.index.comp += 1; bp->cmd_req_reg.index.comp &= PI_CMD_REQ_K_NUM_ENTRIES-1; dfx_port_write_long(bp, PI_PDQ_K_REG_CMD_REQ_PROD, bp->cmd_req_reg.lword); /* * Here we wait for the command response consumer index to be equal * to the producer, indicating that the adapter has DMAed the response. */ for (timeout_cnt = 20000; timeout_cnt > 0; timeout_cnt--) { if (bp->cmd_rsp_reg.index.prod == (u8)(bp->cons_block_virt->cmd_rsp)) break; udelay(100); /* wait for 100 microseconds */ } if (timeout_cnt == 0) return DFX_K_HW_TIMEOUT; /* Bump (and wrap) the completion index and write out to register */ bp->cmd_rsp_reg.index.comp += 1; bp->cmd_rsp_reg.index.comp &= PI_CMD_RSP_K_NUM_ENTRIES-1; dfx_port_write_long(bp, PI_PDQ_K_REG_CMD_RSP_PROD, bp->cmd_rsp_reg.lword); return DFX_K_SUCCESS; } /* * ======================== * = dfx_hw_port_ctrl_req = * ======================== * * Overview: * Sends PDQ port control command to adapter firmware * * Returns: * Host data register value in host_data if ptr is not NULL * * Arguments: * bp - pointer to board information * command - port control command * data_a - port data A register value * data_b - port data B register value * host_data - ptr to host data register value * * Functional Description: * Send generic port control command to adapter by writing * to various PDQ port registers, then polling for completion. * * Return Codes: * DFX_K_SUCCESS - port control command succeeded * DFX_K_HW_TIMEOUT - port control command timed out * * Assumptions: * None * * Side Effects: * None */ static int dfx_hw_port_ctrl_req( DFX_board_t *bp, PI_UINT32 command, PI_UINT32 data_a, PI_UINT32 data_b, PI_UINT32 *host_data ) { PI_UINT32 port_cmd; /* Port Control command register value */ int timeout_cnt; /* used in for loops */ /* Set Command Error bit in command longword */ port_cmd = (PI_UINT32) (command | PI_PCTRL_M_CMD_ERROR); /* Issue port command to the adapter */ dfx_port_write_long(bp, PI_PDQ_K_REG_PORT_DATA_A, data_a); dfx_port_write_long(bp, PI_PDQ_K_REG_PORT_DATA_B, data_b); dfx_port_write_long(bp, PI_PDQ_K_REG_PORT_CTRL, port_cmd); /* Now wait for command to complete */ if (command == PI_PCTRL_M_BLAST_FLASH) timeout_cnt = 600000; /* set command timeout count to 60 seconds */ else timeout_cnt = 20000; /* set command timeout count to 2 seconds */ for (; timeout_cnt > 0; timeout_cnt--) { dfx_port_read_long(bp, PI_PDQ_K_REG_PORT_CTRL, &port_cmd); if (!(port_cmd & PI_PCTRL_M_CMD_ERROR)) break; udelay(100); /* wait for 100 microseconds */ } if (timeout_cnt == 0) return DFX_K_HW_TIMEOUT; /* * If the address of host_data is non-zero, assume caller has supplied a * non NULL pointer, and return the contents of the HOST_DATA register in * it. */ if (host_data != NULL) dfx_port_read_long(bp, PI_PDQ_K_REG_HOST_DATA, host_data); return DFX_K_SUCCESS; } /* * ===================== * = dfx_hw_adap_reset = * ===================== * * Overview: * Resets adapter * * Returns: * None * * Arguments: * bp - pointer to board information * type - type of reset to perform * * Functional Description: * Issue soft reset to adapter by writing to PDQ Port Reset * register. Use incoming reset type to tell adapter what * kind of reset operation to perform. * * Return Codes: * None * * Assumptions: * This routine merely issues a soft reset to the adapter. * It is expected that after this routine returns, the caller * will appropriately poll the Port Status register for the * adapter to enter the proper state. * * Side Effects: * Internal adapter registers are cleared. */ static void dfx_hw_adap_reset( DFX_board_t *bp, PI_UINT32 type ) { /* Set Reset type and assert reset */ dfx_port_write_long(bp, PI_PDQ_K_REG_PORT_DATA_A, type); /* tell adapter type of reset */ dfx_port_write_long(bp, PI_PDQ_K_REG_PORT_RESET, PI_RESET_M_ASSERT_RESET); /* Wait for at least 1 Microsecond according to the spec. We wait 20 just to be safe */ udelay(20); /* Deassert reset */ dfx_port_write_long(bp, PI_PDQ_K_REG_PORT_RESET, 0); } /* * ======================== * = dfx_hw_adap_state_rd = * ======================== * * Overview: * Returns current adapter state * * Returns: * Adapter state per PDQ Port Specification * * Arguments: * bp - pointer to board information * * Functional Description: * Reads PDQ Port Status register and returns adapter state. * * Return Codes: * None * * Assumptions: * None * * Side Effects: * None */ static int dfx_hw_adap_state_rd(DFX_board_t *bp) { PI_UINT32 port_status; /* Port Status register value */ dfx_port_read_long(bp, PI_PDQ_K_REG_PORT_STATUS, &port_status); return (port_status & PI_PSTATUS_M_STATE) >> PI_PSTATUS_V_STATE; } /* * ===================== * = dfx_hw_dma_uninit = * ===================== * * Overview: * Brings adapter to DMA_UNAVAILABLE state * * Returns: * Condition code * * Arguments: * bp - pointer to board information * type - type of reset to perform * * Functional Description: * Bring adapter to DMA_UNAVAILABLE state by performing the following: * 1. Set reset type bit in Port Data A Register then reset adapter. * 2. Check that adapter is in DMA_UNAVAILABLE state. * * Return Codes: * DFX_K_SUCCESS - adapter is in DMA_UNAVAILABLE state * DFX_K_HW_TIMEOUT - adapter did not reset properly * * Assumptions: * None * * Side Effects: * Internal adapter registers are cleared. */ static int dfx_hw_dma_uninit(DFX_board_t *bp, PI_UINT32 type) { int timeout_cnt; /* used in for loops */ /* Set reset type bit and reset adapter */ dfx_hw_adap_reset(bp, type); /* Now wait for adapter to enter DMA_UNAVAILABLE state */ for (timeout_cnt = 100000; timeout_cnt > 0; timeout_cnt--) { if (dfx_hw_adap_state_rd(bp) == PI_STATE_K_DMA_UNAVAIL) break; udelay(100); /* wait for 100 microseconds */ } if (timeout_cnt == 0) return DFX_K_HW_TIMEOUT; return DFX_K_SUCCESS; } /* * Align an sk_buff to a boundary power of 2 * */ static void my_skb_align(struct sk_buff *skb, int n) { unsigned long x = (unsigned long)skb->data; unsigned long v; v = ALIGN(x, n); /* Where we want to be */ skb_reserve(skb, v - x); } /* * ================ * = dfx_rcv_init = * ================ * * Overview: * Produces buffers to adapter LLC Host receive descriptor block * * Returns: * None * * Arguments: * bp - pointer to board information * get_buffers - non-zero if buffers to be allocated * * Functional Description: * This routine can be called during dfx_adap_init() or during an adapter * reset. It initializes the descriptor block and produces all allocated * LLC Host queue receive buffers. * * Return Codes: * Return 0 on success or -ENOMEM if buffer allocation failed (when using * dynamic buffer allocation). If the buffer allocation failed, the * already allocated buffers will not be released and the caller should do * this. * * Assumptions: * The PDQ has been reset and the adapter and driver maintained Type 2 * register indices are cleared. * * Side Effects: * Receive buffers are posted to the adapter LLC queue and the adapter * is notified. */ static int dfx_rcv_init(DFX_board_t *bp, int get_buffers) { int i, j; /* used in for loop */ /* * Since each receive buffer is a single fragment of same length, initialize * first longword in each receive descriptor for entire LLC Host descriptor * block. Also initialize second longword in each receive descriptor with * physical address of receive buffer. We'll always allocate receive * buffers in powers of 2 so that we can easily fill the 256 entry descriptor * block and produce new receive buffers by simply updating the receive * producer index. * * Assumptions: * To support all shipping versions of PDQ, the receive buffer size * must be mod 128 in length and the physical address must be 128 byte * aligned. In other words, bits 0-6 of the length and address must * be zero for the following descriptor field entries to be correct on * all PDQ-based boards. We guaranteed both requirements during * driver initialization when we allocated memory for the receive buffers. */ if (get_buffers) { #ifdef DYNAMIC_BUFFERS for (i = 0; i < (int)(bp->rcv_bufs_to_post); i++) for (j = 0; (i + j) < (int)PI_RCV_DATA_K_NUM_ENTRIES; j += bp->rcv_bufs_to_post) { struct sk_buff *newskb = __netdev_alloc_skb(bp->dev, NEW_SKB_SIZE, GFP_NOIO); if (!newskb) return -ENOMEM; bp->descr_block_virt->rcv_data[i+j].long_0 = (u32) (PI_RCV_DESCR_M_SOP | ((PI_RCV_DATA_K_SIZE_MAX / PI_ALIGN_K_RCV_DATA_BUFF) << PI_RCV_DESCR_V_SEG_LEN)); /* * align to 128 bytes for compatibility with * the old EISA boards. */ my_skb_align(newskb, 128); bp->descr_block_virt->rcv_data[i + j].long_1 = (u32)dma_map_single(bp->bus_dev, newskb->data, NEW_SKB_SIZE, DMA_FROM_DEVICE); /* * p_rcv_buff_va is only used inside the * kernel so we put the skb pointer here. */ bp->p_rcv_buff_va[i+j] = (char *) newskb; } #else for (i=0; i < (int)(bp->rcv_bufs_to_post); i++) for (j=0; (i + j) < (int)PI_RCV_DATA_K_NUM_ENTRIES; j += bp->rcv_bufs_to_post) { bp->descr_block_virt->rcv_data[i+j].long_0 = (u32) (PI_RCV_DESCR_M_SOP | ((PI_RCV_DATA_K_SIZE_MAX / PI_ALIGN_K_RCV_DATA_BUFF) << PI_RCV_DESCR_V_SEG_LEN)); bp->descr_block_virt->rcv_data[i+j].long_1 = (u32) (bp->rcv_block_phys + (i * PI_RCV_DATA_K_SIZE_MAX)); bp->p_rcv_buff_va[i+j] = (char *) (bp->rcv_block_virt + (i * PI_RCV_DATA_K_SIZE_MAX)); } #endif } /* Update receive producer and Type 2 register */ bp->rcv_xmt_reg.index.rcv_prod = bp->rcv_bufs_to_post; dfx_port_write_long(bp, PI_PDQ_K_REG_TYPE_2_PROD, bp->rcv_xmt_reg.lword); return 0; } /* * ========================= * = dfx_rcv_queue_process = * ========================= * * Overview: * Process received LLC frames. * * Returns: * None * * Arguments: * bp - pointer to board information * * Functional Description: * Received LLC frames are processed until there are no more consumed frames. * Once all frames are processed, the receive buffers are returned to the * adapter. Note that this algorithm fixes the length of time that can be spent * in this routine, because there are a fixed number of receive buffers to * process and buffers are not produced until this routine exits and returns * to the ISR. * * Return Codes: * None * * Assumptions: * None * * Side Effects: * None */ static void dfx_rcv_queue_process( DFX_board_t *bp ) { PI_TYPE_2_CONSUMER *p_type_2_cons; /* ptr to rcv/xmt consumer block register */ char *p_buff; /* ptr to start of packet receive buffer (FMC descriptor) */ u32 descr, pkt_len; /* FMC descriptor field and packet length */ struct sk_buff *skb; /* pointer to a sk_buff to hold incoming packet data */ /* Service all consumed LLC receive frames */ p_type_2_cons = (PI_TYPE_2_CONSUMER *)(&bp->cons_block_virt->xmt_rcv_data); while (bp->rcv_xmt_reg.index.rcv_comp != p_type_2_cons->index.rcv_cons) { /* Process any errors */ int entry; entry = bp->rcv_xmt_reg.index.rcv_comp; #ifdef DYNAMIC_BUFFERS p_buff = (char *) (((struct sk_buff *)bp->p_rcv_buff_va[entry])->data); #else p_buff = (char *) bp->p_rcv_buff_va[entry]; #endif memcpy(&descr, p_buff + RCV_BUFF_K_DESCR, sizeof(u32)); if (descr & PI_FMC_DESCR_M_RCC_FLUSH) { if (descr & PI_FMC_DESCR_M_RCC_CRC) bp->rcv_crc_errors++; else bp->rcv_frame_status_errors++; } else { int rx_in_place = 0; /* The frame was received without errors - verify packet length */ pkt_len = (u32)((descr & PI_FMC_DESCR_M_LEN) >> PI_FMC_DESCR_V_LEN); pkt_len -= 4; /* subtract 4 byte CRC */ if (!IN_RANGE(pkt_len, FDDI_K_LLC_ZLEN, FDDI_K_LLC_LEN)) bp->rcv_length_errors++; else{ #ifdef DYNAMIC_BUFFERS if (pkt_len > SKBUFF_RX_COPYBREAK) { struct sk_buff *newskb; newskb = dev_alloc_skb(NEW_SKB_SIZE); if (newskb){ rx_in_place = 1; my_skb_align(newskb, 128); skb = (struct sk_buff *)bp->p_rcv_buff_va[entry]; dma_unmap_single(bp->bus_dev, bp->descr_block_virt->rcv_data[entry].long_1, NEW_SKB_SIZE, DMA_FROM_DEVICE); skb_reserve(skb, RCV_BUFF_K_PADDING); bp->p_rcv_buff_va[entry] = (char *)newskb; bp->descr_block_virt->rcv_data[entry].long_1 = (u32)dma_map_single(bp->bus_dev, newskb->data, NEW_SKB_SIZE, DMA_FROM_DEVICE); } else skb = NULL; } else #endif skb = dev_alloc_skb(pkt_len+3); /* alloc new buffer to pass up, add room for PRH */ if (skb == NULL) { printk("%s: Could not allocate receive buffer. Dropping packet.\n", bp->dev->name); bp->rcv_discards++; break; } else { #ifndef DYNAMIC_BUFFERS if (! rx_in_place) #endif { /* Receive buffer allocated, pass receive packet up */ skb_copy_to_linear_data(skb, p_buff + RCV_BUFF_K_PADDING, pkt_len + 3); } skb_reserve(skb,3); /* adjust data field so that it points to FC byte */ skb_put(skb, pkt_len); /* pass up packet length, NOT including CRC */ skb->protocol = fddi_type_trans(skb, bp->dev); bp->rcv_total_bytes += skb->len; netif_rx(skb); /* Update the rcv counters */ bp->rcv_total_frames++; if (*(p_buff + RCV_BUFF_K_DA) & 0x01) bp->rcv_multicast_frames++; } } } /* * Advance the producer (for recycling) and advance the completion * (for servicing received frames). Note that it is okay to * advance the producer without checking that it passes the * completion index because they are both advanced at the same * rate. */ bp->rcv_xmt_reg.index.rcv_prod += 1; bp->rcv_xmt_reg.index.rcv_comp += 1; } } /* * ===================== * = dfx_xmt_queue_pkt = * ===================== * * Overview: * Queues packets for transmission * * Returns: * Condition code * * Arguments: * skb - pointer to sk_buff to queue for transmission * dev - pointer to device information * * Functional Description: * Here we assume that an incoming skb transmit request * is contained in a single physically contiguous buffer * in which the virtual address of the start of packet * (skb->data) can be converted to a physical address * by using pci_map_single(). * * Since the adapter architecture requires a three byte * packet request header to prepend the start of packet, * we'll write the three byte field immediately prior to * the FC byte. This assumption is valid because we've * ensured that dev->hard_header_len includes three pad * bytes. By posting a single fragment to the adapter, * we'll reduce the number of descriptor fetches and * bus traffic needed to send the request. * * Also, we can't free the skb until after it's been DMA'd * out by the adapter, so we'll queue it in the driver and * return it in dfx_xmt_done. * * Return Codes: * 0 - driver queued packet, link is unavailable, or skbuff was bad * 1 - caller should requeue the sk_buff for later transmission * * Assumptions: * First and foremost, we assume the incoming skb pointer * is NOT NULL and is pointing to a valid sk_buff structure. * * The outgoing packet is complete, starting with the * frame control byte including the last byte of data, * but NOT including the 4 byte CRC. We'll let the * adapter hardware generate and append the CRC. * * The entire packet is stored in one physically * contiguous buffer which is not cached and whose * 32-bit physical address can be determined. * * It's vital that this routine is NOT reentered for the * same board and that the OS is not in another section of * code (eg. dfx_int_common) for the same board on a * different thread. * * Side Effects: * None */ static netdev_tx_t dfx_xmt_queue_pkt(struct sk_buff *skb, struct net_device *dev) { DFX_board_t *bp = netdev_priv(dev); u8 prod; /* local transmit producer index */ PI_XMT_DESCR *p_xmt_descr; /* ptr to transmit descriptor block entry */ XMT_DRIVER_DESCR *p_xmt_drv_descr; /* ptr to transmit driver descriptor */ unsigned long flags; netif_stop_queue(dev); /* * Verify that incoming transmit request is OK * * Note: The packet size check is consistent with other * Linux device drivers, although the correct packet * size should be verified before calling the * transmit routine. */ if (!IN_RANGE(skb->len, FDDI_K_LLC_ZLEN, FDDI_K_LLC_LEN)) { printk("%s: Invalid packet length - %u bytes\n", dev->name, skb->len); bp->xmt_length_errors++; /* bump error counter */ netif_wake_queue(dev); dev_kfree_skb(skb); return NETDEV_TX_OK; /* return "success" */ } /* * See if adapter link is available, if not, free buffer * * Note: If the link isn't available, free buffer and return 0 * rather than tell the upper layer to requeue the packet. * The methodology here is that by the time the link * becomes available, the packet to be sent will be * fairly stale. By simply dropping the packet, the * higher layer protocols will eventually time out * waiting for response packets which it won't receive. */ if (bp->link_available == PI_K_FALSE) { if (dfx_hw_adap_state_rd(bp) == PI_STATE_K_LINK_AVAIL) /* is link really available? */ bp->link_available = PI_K_TRUE; /* if so, set flag and continue */ else { bp->xmt_discards++; /* bump error counter */ dev_kfree_skb(skb); /* free sk_buff now */ netif_wake_queue(dev); return NETDEV_TX_OK; /* return "success" */ } } spin_lock_irqsave(&bp->lock, flags); /* Get the current producer and the next free xmt data descriptor */ prod = bp->rcv_xmt_reg.index.xmt_prod; p_xmt_descr = &(bp->descr_block_virt->xmt_data[prod]); /* * Get pointer to auxiliary queue entry to contain information * for this packet. * * Note: The current xmt producer index will become the * current xmt completion index when we complete this * packet later on. So, we'll get the pointer to the * next auxiliary queue entry now before we bump the * producer index. */ p_xmt_drv_descr = &(bp->xmt_drv_descr_blk[prod++]); /* also bump producer index */ /* Write the three PRH bytes immediately before the FC byte */ skb_push(skb,3); skb->data[0] = DFX_PRH0_BYTE; /* these byte values are defined */ skb->data[1] = DFX_PRH1_BYTE; /* in the Motorola FDDI MAC chip */ skb->data[2] = DFX_PRH2_BYTE; /* specification */ /* * Write the descriptor with buffer info and bump producer * * Note: Since we need to start DMA from the packet request * header, we'll add 3 bytes to the DMA buffer length, * and we'll determine the physical address of the * buffer from the PRH, not skb->data. * * Assumptions: * 1. Packet starts with the frame control (FC) byte * at skb->data. * 2. The 4-byte CRC is not appended to the buffer or * included in the length. * 3. Packet length (skb->len) is from FC to end of * data, inclusive. * 4. The packet length does not exceed the maximum * FDDI LLC frame length of 4491 bytes. * 5. The entire packet is contained in a physically * contiguous, non-cached, locked memory space * comprised of a single buffer pointed to by * skb->data. * 6. The physical address of the start of packet * can be determined from the virtual address * by using pci_map_single() and is only 32-bits * wide. */ p_xmt_descr->long_0 = (u32) (PI_XMT_DESCR_M_SOP | PI_XMT_DESCR_M_EOP | ((skb->len) << PI_XMT_DESCR_V_SEG_LEN)); p_xmt_descr->long_1 = (u32)dma_map_single(bp->bus_dev, skb->data, skb->len, DMA_TO_DEVICE); /* * Verify that descriptor is actually available * * Note: If descriptor isn't available, return 1 which tells * the upper layer to requeue the packet for later * transmission. * * We need to ensure that the producer never reaches the * completion, except to indicate that the queue is empty. */ if (prod == bp->rcv_xmt_reg.index.xmt_comp) { skb_pull(skb,3); spin_unlock_irqrestore(&bp->lock, flags); return NETDEV_TX_BUSY; /* requeue packet for later */ } /* * Save info for this packet for xmt done indication routine * * Normally, we'd save the producer index in the p_xmt_drv_descr * structure so that we'd have it handy when we complete this * packet later (in dfx_xmt_done). However, since the current * transmit architecture guarantees a single fragment for the * entire packet, we can simply bump the completion index by * one (1) for each completed packet. * * Note: If this assumption changes and we're presented with * an inconsistent number of transmit fragments for packet * data, we'll need to modify this code to save the current * transmit producer index. */ p_xmt_drv_descr->p_skb = skb; /* Update Type 2 register */ bp->rcv_xmt_reg.index.xmt_prod = prod; dfx_port_write_long(bp, PI_PDQ_K_REG_TYPE_2_PROD, bp->rcv_xmt_reg.lword); spin_unlock_irqrestore(&bp->lock, flags); netif_wake_queue(dev); return NETDEV_TX_OK; /* packet queued to adapter */ } /* * ================ * = dfx_xmt_done = * ================ * * Overview: * Processes all frames that have been transmitted. * * Returns: * None * * Arguments: * bp - pointer to board information * * Functional Description: * For all consumed transmit descriptors that have not * yet been completed, we'll free the skb we were holding * onto using dev_kfree_skb and bump the appropriate * counters. * * Return Codes: * None * * Assumptions: * The Type 2 register is not updated in this routine. It is * assumed that it will be updated in the ISR when dfx_xmt_done * returns. * * Side Effects: * None */ static int dfx_xmt_done(DFX_board_t *bp) { XMT_DRIVER_DESCR *p_xmt_drv_descr; /* ptr to transmit driver descriptor */ PI_TYPE_2_CONSUMER *p_type_2_cons; /* ptr to rcv/xmt consumer block register */ u8 comp; /* local transmit completion index */ int freed = 0; /* buffers freed */ /* Service all consumed transmit frames */ p_type_2_cons = (PI_TYPE_2_CONSUMER *)(&bp->cons_block_virt->xmt_rcv_data); while (bp->rcv_xmt_reg.index.xmt_comp != p_type_2_cons->index.xmt_cons) { /* Get pointer to the transmit driver descriptor block information */ p_xmt_drv_descr = &(bp->xmt_drv_descr_blk[bp->rcv_xmt_reg.index.xmt_comp]); /* Increment transmit counters */ bp->xmt_total_frames++; bp->xmt_total_bytes += p_xmt_drv_descr->p_skb->len; /* Return skb to operating system */ comp = bp->rcv_xmt_reg.index.xmt_comp; dma_unmap_single(bp->bus_dev, bp->descr_block_virt->xmt_data[comp].long_1, p_xmt_drv_descr->p_skb->len, DMA_TO_DEVICE); dev_kfree_skb_irq(p_xmt_drv_descr->p_skb); /* * Move to start of next packet by updating completion index * * Here we assume that a transmit packet request is always * serviced by posting one fragment. We can therefore * simplify the completion code by incrementing the * completion index by one. This code will need to be * modified if this assumption changes. See comments * in dfx_xmt_queue_pkt for more details. */ bp->rcv_xmt_reg.index.xmt_comp += 1; freed++; } return freed; } /* * ================= * = dfx_rcv_flush = * ================= * * Overview: * Remove all skb's in the receive ring. * * Returns: * None * * Arguments: * bp - pointer to board information * * Functional Description: * Free's all the dynamically allocated skb's that are * currently attached to the device receive ring. This * function is typically only used when the device is * initialized or reinitialized. * * Return Codes: * None * * Side Effects: * None */ #ifdef DYNAMIC_BUFFERS static void dfx_rcv_flush( DFX_board_t *bp ) { int i, j; for (i = 0; i < (int)(bp->rcv_bufs_to_post); i++) for (j = 0; (i + j) < (int)PI_RCV_DATA_K_NUM_ENTRIES; j += bp->rcv_bufs_to_post) { struct sk_buff *skb; skb = (struct sk_buff *)bp->p_rcv_buff_va[i+j]; if (skb) dev_kfree_skb(skb); bp->p_rcv_buff_va[i+j] = NULL; } } #else static inline void dfx_rcv_flush( DFX_board_t *bp ) { } #endif /* DYNAMIC_BUFFERS */ /* * ================= * = dfx_xmt_flush = * ================= * * Overview: * Processes all frames whether they've been transmitted * or not. * * Returns: * None * * Arguments: * bp - pointer to board information * * Functional Description: * For all produced transmit descriptors that have not * yet been completed, we'll free the skb we were holding * onto using dev_kfree_skb and bump the appropriate * counters. Of course, it's possible that some of * these transmit requests actually did go out, but we * won't make that distinction here. Finally, we'll * update the consumer index to match the producer. * * Return Codes: * None * * Assumptions: * This routine does NOT update the Type 2 register. It * is assumed that this routine is being called during a * transmit flush interrupt, or a shutdown or close routine. * * Side Effects: * None */ static void dfx_xmt_flush( DFX_board_t *bp ) { u32 prod_cons; /* rcv/xmt consumer block longword */ XMT_DRIVER_DESCR *p_xmt_drv_descr; /* ptr to transmit driver descriptor */ u8 comp; /* local transmit completion index */ /* Flush all outstanding transmit frames */ while (bp->rcv_xmt_reg.index.xmt_comp != bp->rcv_xmt_reg.index.xmt_prod) { /* Get pointer to the transmit driver descriptor block information */ p_xmt_drv_descr = &(bp->xmt_drv_descr_blk[bp->rcv_xmt_reg.index.xmt_comp]); /* Return skb to operating system */ comp = bp->rcv_xmt_reg.index.xmt_comp; dma_unmap_single(bp->bus_dev, bp->descr_block_virt->xmt_data[comp].long_1, p_xmt_drv_descr->p_skb->len, DMA_TO_DEVICE); dev_kfree_skb(p_xmt_drv_descr->p_skb); /* Increment transmit error counter */ bp->xmt_discards++; /* * Move to start of next packet by updating completion index * * Here we assume that a transmit packet request is always * serviced by posting one fragment. We can therefore * simplify the completion code by incrementing the * completion index by one. This code will need to be * modified if this assumption changes. See comments * in dfx_xmt_queue_pkt for more details. */ bp->rcv_xmt_reg.index.xmt_comp += 1; } /* Update the transmit consumer index in the consumer block */ prod_cons = (u32)(bp->cons_block_virt->xmt_rcv_data & ~PI_CONS_M_XMT_INDEX); prod_cons |= (u32)(bp->rcv_xmt_reg.index.xmt_prod << PI_CONS_V_XMT_INDEX); bp->cons_block_virt->xmt_rcv_data = prod_cons; } /* * ================== * = dfx_unregister = * ================== * * Overview: * Shuts down an FDDI controller * * Returns: * Condition code * * Arguments: * bdev - pointer to device information * * Functional Description: * * Return Codes: * None * * Assumptions: * It compiles so it should work :-( (PCI cards do :-) * * Side Effects: * Device structures for FDDI adapters (fddi0, fddi1, etc) are * freed. */ static void __devexit dfx_unregister(struct device *bdev) { struct net_device *dev = dev_get_drvdata(bdev); DFX_board_t *bp = netdev_priv(dev); int dfx_bus_pci = DFX_BUS_PCI(bdev); int dfx_bus_tc = DFX_BUS_TC(bdev); int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; resource_size_t bar_start = 0; /* pointer to port */ resource_size_t bar_len = 0; /* resource length */ int alloc_size; /* total buffer size used */ unregister_netdev(dev); alloc_size = sizeof(PI_DESCR_BLOCK) + PI_CMD_REQ_K_SIZE_MAX + PI_CMD_RSP_K_SIZE_MAX + #ifndef DYNAMIC_BUFFERS (bp->rcv_bufs_to_post * PI_RCV_DATA_K_SIZE_MAX) + #endif sizeof(PI_CONSUMER_BLOCK) + (PI_ALIGN_K_DESC_BLK - 1); if (bp->kmalloced) dma_free_coherent(bdev, alloc_size, bp->kmalloced, bp->kmalloced_dma); dfx_bus_uninit(dev); dfx_get_bars(bdev, &bar_start, &bar_len); if (dfx_use_mmio) { iounmap(bp->base.mem); release_mem_region(bar_start, bar_len); } else release_region(bar_start, bar_len); if (dfx_bus_pci) pci_disable_device(to_pci_dev(bdev)); free_netdev(dev); } static int __devinit __maybe_unused dfx_dev_register(struct device *); static int __devexit __maybe_unused dfx_dev_unregister(struct device *); #ifdef CONFIG_PCI static int __devinit dfx_pci_register(struct pci_dev *, const struct pci_device_id *); static void __devexit dfx_pci_unregister(struct pci_dev *); static DEFINE_PCI_DEVICE_TABLE(dfx_pci_table) = { { PCI_DEVICE(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_FDDI) }, { } }; MODULE_DEVICE_TABLE(pci, dfx_pci_table); static struct pci_driver dfx_pci_driver = { .name = "defxx", .id_table = dfx_pci_table, .probe = dfx_pci_register, .remove = __devexit_p(dfx_pci_unregister), }; static __devinit int dfx_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent) { return dfx_register(&pdev->dev); } static void __devexit dfx_pci_unregister(struct pci_dev *pdev) { dfx_unregister(&pdev->dev); } #endif /* CONFIG_PCI */ #ifdef CONFIG_EISA static struct eisa_device_id dfx_eisa_table[] = { { "DEC3001", DEFEA_PROD_ID_1 }, { "DEC3002", DEFEA_PROD_ID_2 }, { "DEC3003", DEFEA_PROD_ID_3 }, { "DEC3004", DEFEA_PROD_ID_4 }, { } }; MODULE_DEVICE_TABLE(eisa, dfx_eisa_table); static struct eisa_driver dfx_eisa_driver = { .id_table = dfx_eisa_table, .driver = { .name = "defxx", .bus = &eisa_bus_type, .probe = dfx_dev_register, .remove = __devexit_p(dfx_dev_unregister), }, }; #endif /* CONFIG_EISA */ #ifdef CONFIG_TC static struct tc_device_id const dfx_tc_table[] = { { "DEC ", "PMAF-FA " }, { "DEC ", "PMAF-FD " }, { "DEC ", "PMAF-FS " }, { "DEC ", "PMAF-FU " }, { } }; MODULE_DEVICE_TABLE(tc, dfx_tc_table); static struct tc_driver dfx_tc_driver = { .id_table = dfx_tc_table, .driver = { .name = "defxx", .bus = &tc_bus_type, .probe = dfx_dev_register, .remove = __devexit_p(dfx_dev_unregister), }, }; #endif /* CONFIG_TC */ static int __devinit __maybe_unused dfx_dev_register(struct device *dev) { int status; status = dfx_register(dev); if (!status) get_device(dev); return status; } static int __devexit __maybe_unused dfx_dev_unregister(struct device *dev) { put_device(dev); dfx_unregister(dev); return 0; } static int __devinit dfx_init(void) { int status; status = pci_register_driver(&dfx_pci_driver); if (!status) status = eisa_driver_register(&dfx_eisa_driver); if (!status) status = tc_register_driver(&dfx_tc_driver); return status; } static void __devexit dfx_cleanup(void) { tc_unregister_driver(&dfx_tc_driver); eisa_driver_unregister(&dfx_eisa_driver); pci_unregister_driver(&dfx_pci_driver); } module_init(dfx_init); module_exit(dfx_cleanup); MODULE_AUTHOR("Lawrence V. Stefani"); MODULE_DESCRIPTION("DEC FDDIcontroller TC/EISA/PCI (DEFTA/DEFEA/DEFPA) driver " DRV_VERSION " " DRV_RELDATE); MODULE_LICENSE("GPL");