Hello everyone,
This is version two of my series that adds support for a Gigabit Ethernet
controller featured in the Renesas r9a06g032 SoC, of the RZ/N1 family. This
GMAC device is based on a Synopsys IP and is compatible with the stmmac driver.
My former colleague Clément Léger originally sent a series for this driver,
but an issue in bringing up the PCS clock had blocked the upstreaming
process. This issue has since been resolved by the following series:
https://lore.kernel.org/all/[email protected]/
This series consists of a devicetree binding describing the RZN1 GMAC
controller IP, a node for the GMAC1 device in the r9a06g032 SoC device
tree, and the GMAC driver itself which is a glue layer in stmmac.
There are also two patches by Russell that improve pcs initialization handling
in stmmac.
Best Regards,
Romain Gantois
---
Changes in v2:
- Add pcs_init/exit callbacks in stmmac to solve race condition
- Use pcs_init/exit callbacks in dwmac_socfpga glue layer
- Miscellaneous device tree binding corrections
- Link to v1: https://lore.kernel.org/r/[email protected]
---
Clément Léger (3):
dt-bindings: net: renesas,rzn1-gmac: Document RZ/N1 GMAC support
net: stmmac: add support for RZ/N1 GMAC
ARM: dts: r9a06g032: describe GMAC1
Russell King (Oracle) (2):
net: stmmac: introduce pcs_init/pcs_exit stmmac operations
net: stmmac: dwmac-socfpga: use pcs_init/pcs_exit
.../devicetree/bindings/net/renesas,rzn1-gmac.yaml | 66 +++++++++++++
MAINTAINERS | 6 ++
arch/arm/boot/dts/renesas/r9a06g032.dtsi | 19 ++++
drivers/net/ethernet/stmicro/stmmac/Kconfig | 12 +++
drivers/net/ethernet/stmicro/stmmac/Makefile | 1 +
drivers/net/ethernet/stmicro/stmmac/dwmac-rzn1.c | 88 +++++++++++++++++
.../net/ethernet/stmicro/stmmac/dwmac-socfpga.c | 109 +++++++++++----------
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 14 +++
include/linux/stmmac.h | 2 +
9 files changed, 263 insertions(+), 54 deletions(-)
---
base-commit: 87c33315af380ca12a2e59ac94edad4fe0481b4c
change-id: 20240402-rzn1-gmac1-685cf8793d0e
Best regards,
--
Romain Gantois <[email protected]>
From: "Russell King (Oracle)" <[email protected]>
Use the newly introduced pcs_init() and pcs_exit() operations to
create and destroy the PCS instance at a more appropriate moment during
the driver lifecycle, thereby avoiding publishing a network device to
userspace that has not yet finished its PCS initialisation.
There are other similar issues with this driver which remain
unaddressed, but these are out of scope for this patch.
Signed-off-by: Russell King (Oracle) <[email protected]>
Reviewed-by: Maxime Chevallier <[email protected]>
Signed-off-by: Romain Gantois <[email protected]>
---
.../net/ethernet/stmicro/stmmac/dwmac-socfpga.c | 109 +++++++++++----------
1 file changed, 55 insertions(+), 54 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
index 12b4a80ea3aa..67ca163936c8 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
@@ -379,6 +379,58 @@ static int socfpga_gen10_set_phy_mode(struct socfpga_dwmac *dwmac)
return 0;
}
+static int socfpga_dwmac_pcs_init(struct stmmac_priv *priv,
+ struct mac_device_info *hw)
+{
+ struct socfpga_dwmac *dwmac = priv->plat->bsp_priv;
+ struct regmap_config pcs_regmap_cfg = {
+ .reg_bits = 16,
+ .val_bits = 16,
+ .reg_shift = regmap_upshift(1),
+ };
+ struct mdio_regmap_config mrc;
+ struct regmap *pcs_regmap;
+ struct phylink_pcs *pcs;
+ struct mii_bus *pcs_bus;
+
+ if (!dwmac->tse_pcs_base)
+ return 0;
+
+ pcs_regmap = devm_regmap_init_mmio(priv->device, dwmac->tse_pcs_base,
+ &pcs_regmap_cfg);
+ if (IS_ERR(pcs_regmap))
+ return PTR_ERR(pcs_regmap);
+
+ memset(&mrc, 0, sizeof(mrc));
+ mrc.regmap = pcs_regmap;
+ mrc.parent = priv->device;
+ mrc.valid_addr = 0x0;
+ mrc.autoscan = false;
+
+ /* Can't use ndev->name here because it will not have been initialised,
+ * and in any case, the user can rename network interfaces at runtime.
+ */
+ snprintf(mrc.name, MII_BUS_ID_SIZE, "%s-pcs-mii",
+ dev_name(priv->device));
+ pcs_bus = devm_mdio_regmap_register(priv->device, &mrc);
+ if (IS_ERR(pcs_bus))
+ return PTR_ERR(pcs_bus);
+
+ pcs = lynx_pcs_create_mdiodev(pcs_bus, 0);
+ if (IS_ERR(pcs))
+ return PTR_ERR(pcs);
+
+ hw->phylink_pcs = pcs;
+ return 0;
+}
+
+static void socfpga_dwmac_pcs_exit(struct stmmac_priv *priv,
+ struct mac_device_info *hw)
+{
+ if (hw->phylink_pcs)
+ lynx_pcs_destroy(hw->phylink_pcs);
+}
+
static int socfpga_dwmac_probe(struct platform_device *pdev)
{
struct plat_stmmacenet_data *plat_dat;
@@ -426,6 +478,8 @@ static int socfpga_dwmac_probe(struct platform_device *pdev)
dwmac->ops = ops;
plat_dat->bsp_priv = dwmac;
plat_dat->fix_mac_speed = socfpga_dwmac_fix_mac_speed;
+ plat_dat->pcs_init = socfpga_dwmac_pcs_init;
+ plat_dat->pcs_exit = socfpga_dwmac_pcs_exit;
ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
if (ret)
@@ -444,48 +498,6 @@ static int socfpga_dwmac_probe(struct platform_device *pdev)
if (ret)
goto err_dvr_remove;
- /* Create a regmap for the PCS so that it can be used by the PCS driver,
- * if we have such a PCS
- */
- if (dwmac->tse_pcs_base) {
- struct regmap_config pcs_regmap_cfg;
- struct mdio_regmap_config mrc;
- struct regmap *pcs_regmap;
- struct mii_bus *pcs_bus;
-
- memset(&pcs_regmap_cfg, 0, sizeof(pcs_regmap_cfg));
- memset(&mrc, 0, sizeof(mrc));
-
- pcs_regmap_cfg.reg_bits = 16;
- pcs_regmap_cfg.val_bits = 16;
- pcs_regmap_cfg.reg_shift = REGMAP_UPSHIFT(1);
-
- pcs_regmap = devm_regmap_init_mmio(&pdev->dev, dwmac->tse_pcs_base,
- &pcs_regmap_cfg);
- if (IS_ERR(pcs_regmap)) {
- ret = PTR_ERR(pcs_regmap);
- goto err_dvr_remove;
- }
-
- mrc.regmap = pcs_regmap;
- mrc.parent = &pdev->dev;
- mrc.valid_addr = 0x0;
- mrc.autoscan = false;
-
- snprintf(mrc.name, MII_BUS_ID_SIZE, "%s-pcs-mii", ndev->name);
- pcs_bus = devm_mdio_regmap_register(&pdev->dev, &mrc);
- if (IS_ERR(pcs_bus)) {
- ret = PTR_ERR(pcs_bus);
- goto err_dvr_remove;
- }
-
- stpriv->hw->phylink_pcs = lynx_pcs_create_mdiodev(pcs_bus, 0);
- if (IS_ERR(stpriv->hw->phylink_pcs)) {
- ret = PTR_ERR(stpriv->hw->phylink_pcs);
- goto err_dvr_remove;
- }
- }
-
return 0;
err_dvr_remove:
@@ -494,17 +506,6 @@ static int socfpga_dwmac_probe(struct platform_device *pdev)
return ret;
}
-static void socfpga_dwmac_remove(struct platform_device *pdev)
-{
- struct net_device *ndev = platform_get_drvdata(pdev);
- struct stmmac_priv *priv = netdev_priv(ndev);
- struct phylink_pcs *pcs = priv->hw->phylink_pcs;
-
- stmmac_pltfr_remove(pdev);
-
- lynx_pcs_destroy(pcs);
-}
-
#ifdef CONFIG_PM_SLEEP
static int socfpga_dwmac_resume(struct device *dev)
{
@@ -576,7 +577,7 @@ MODULE_DEVICE_TABLE(of, socfpga_dwmac_match);
static struct platform_driver socfpga_dwmac_driver = {
.probe = socfpga_dwmac_probe,
- .remove_new = socfpga_dwmac_remove,
+ .remove_new = stmmac_pltfr_remove,
.driver = {
.name = "socfpga-dwmac",
.pm = &socfpga_dwmac_pm_ops,
--
2.44.0
From: Clément Léger <[email protected]>
Add support for the Renesas RZ/N1 GMAC. This support can make use of a
custom RZ/N1 PCS which is fetched by parsing the pcs-handle device tree
property.
Signed-off-by: "Clément Léger" <[email protected]>
Co-developed-by: Romain Gantois <[email protected]>
Signed-off-by: Romain Gantois <[email protected]>
---
MAINTAINERS | 6 ++
drivers/net/ethernet/stmicro/stmmac/Kconfig | 12 ++++
drivers/net/ethernet/stmicro/stmmac/Makefile | 1 +
drivers/net/ethernet/stmicro/stmmac/dwmac-rzn1.c | 88 ++++++++++++++++++++++++
4 files changed, 107 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 4745ea94d463..40bd3eb355fd 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -18848,6 +18848,12 @@ F: include/dt-bindings/net/pcs-rzn1-miic.h
F: include/linux/pcs-rzn1-miic.h
F: net/dsa/tag_rzn1_a5psw.c
+RENESAS RZ/N1 DWMAC GLUE LAYER
+M: Romain Gantois <[email protected]>
+S: Maintained
+F: Documentation/devicetree/bindings/net/renesas,rzn1-gmac.yaml
+F: drivers/net/ethernet/stmicro/stmmac/dwmac-rzn1.c
+
RENESAS RZ/N1 RTC CONTROLLER DRIVER
M: Miquel Raynal <[email protected]>
L: [email protected]
diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig
index 4ec61f1ee71a..05cc07b8f48c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
+++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
@@ -142,6 +142,18 @@ config DWMAC_ROCKCHIP
This selects the Rockchip RK3288 SoC glue layer support for
the stmmac device driver.
+config DWMAC_RZN1
+ tristate "Renesas RZ/N1 dwmac support"
+ default ARCH_RZN1
+ depends on OF && (ARCH_RZN1 || COMPILE_TEST)
+ select PCS_RZN1_MIIC
+ help
+ Support for Ethernet controller on Renesas RZ/N1 SoC family.
+
+ This selects the Renesas RZ/N1 SoC glue layer support for
+ the stmmac device driver. This support can make use of a custom MII
+ converter PCS device.
+
config DWMAC_SOCFPGA
tristate "SOCFPGA dwmac support"
default ARCH_INTEL_SOCFPGA
diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile
index 26cad4344701..c2f0e91f6bf8 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
@@ -21,6 +21,7 @@ obj-$(CONFIG_DWMAC_MEDIATEK) += dwmac-mediatek.o
obj-$(CONFIG_DWMAC_MESON) += dwmac-meson.o dwmac-meson8b.o
obj-$(CONFIG_DWMAC_QCOM_ETHQOS) += dwmac-qcom-ethqos.o
obj-$(CONFIG_DWMAC_ROCKCHIP) += dwmac-rk.o
+obj-$(CONFIG_DWMAC_RZN1) += dwmac-rzn1.o
obj-$(CONFIG_DWMAC_SOCFPGA) += dwmac-altr-socfpga.o
obj-$(CONFIG_DWMAC_STARFIVE) += dwmac-starfive.o
obj-$(CONFIG_DWMAC_STI) += dwmac-sti.o
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rzn1.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rzn1.c
new file mode 100644
index 000000000000..e85524c2017c
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rzn1.c
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2024 Schneider-Electric
+ *
+ * Clément Léger <[email protected]>
+ */
+
+#include <linux/of.h>
+#include <linux/pcs-rzn1-miic.h>
+#include <linux/phylink.h>
+#include <linux/platform_device.h>
+
+#include "stmmac_platform.h"
+#include "stmmac.h"
+
+static int rzn1_dwmac_pcs_init(struct stmmac_priv *priv,
+ struct mac_device_info *hw)
+{
+ struct device_node *np = priv->device->of_node;
+ struct device_node *pcs_node;
+ struct phylink_pcs *pcs;
+
+ pcs_node = of_parse_phandle(np, "pcs-handle", 0);
+
+ if (pcs_node) {
+ pcs = miic_create(priv->device, pcs_node);
+ of_node_put(pcs_node);
+ if (IS_ERR(pcs))
+ return PTR_ERR(pcs);
+
+ priv->hw->phylink_pcs = pcs;
+ }
+
+ return 0;
+}
+
+static void rzn1_dwmac_pcs_exit(struct stmmac_priv *priv,
+ struct mac_device_info *hw)
+{
+ if (priv->hw->phylink_pcs)
+ miic_destroy(priv->hw->phylink_pcs);
+}
+
+static int rzn1_dwmac_probe(struct platform_device *pdev)
+{
+ struct plat_stmmacenet_data *plat_dat;
+ struct stmmac_resources stmmac_res;
+ struct device *dev = &pdev->dev;
+ int ret;
+
+ ret = stmmac_get_platform_resources(pdev, &stmmac_res);
+ if (ret)
+ return ret;
+
+ plat_dat = devm_stmmac_probe_config_dt(pdev, stmmac_res.mac);
+ if (IS_ERR(plat_dat))
+ return PTR_ERR(plat_dat);
+
+ plat_dat->bsp_priv = plat_dat;
+ plat_dat->pcs_init = rzn1_dwmac_pcs_init;
+ plat_dat->pcs_exit = rzn1_dwmac_pcs_exit;
+
+ ret = stmmac_dvr_probe(dev, plat_dat, &stmmac_res);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static const struct of_device_id rzn1_dwmac_match[] = {
+ { .compatible = "renesas,rzn1-gmac" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, rzn1_dwmac_match);
+
+static struct platform_driver rzn1_dwmac_driver = {
+ .probe = rzn1_dwmac_probe,
+ .remove_new = stmmac_pltfr_remove,
+ .driver = {
+ .name = "rzn1-dwmac",
+ .of_match_table = rzn1_dwmac_match,
+ },
+};
+module_platform_driver(rzn1_dwmac_driver);
+
+MODULE_AUTHOR("Clément Léger <[email protected]>");
+MODULE_DESCRIPTION("Renesas RZN1 DWMAC specific glue layer");
+MODULE_LICENSE("GPL");
--
2.44.0
From: Clément Léger <[email protected]>
The r9a06g032 SoC of the RZ/N1 family features two GMAC devices named
GMAC1/2, that are based on Synopsys cores. GMAC1 is connected to a
RGMII/RMII converter that is already described in this device tree.
Signed-off-by: "Clément Léger" <[email protected]>
[rgantois: commit log]
Signed-off-by: Romain Gantois <[email protected]>
---
arch/arm/boot/dts/renesas/r9a06g032.dtsi | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/arch/arm/boot/dts/renesas/r9a06g032.dtsi b/arch/arm/boot/dts/renesas/r9a06g032.dtsi
index fa63e1afc4ef..cab7a641f95b 100644
--- a/arch/arm/boot/dts/renesas/r9a06g032.dtsi
+++ b/arch/arm/boot/dts/renesas/r9a06g032.dtsi
@@ -316,6 +316,25 @@ dma1: dma-controller@40105000 {
data-width = <8>;
};
+ gmac1: ethernet@44000000 {
+ compatible = "renesas,r9a06g032-gmac", "renesas,rzn1-gmac", "snps,dwmac";
+ reg = <0x44000000 0x2000>;
+ interrupt-parent = <&gic>;
+ interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "macirq", "eth_wake_irq", "eth_lpi";
+ clocks = <&sysctrl R9A06G032_HCLK_GMAC0>;
+ clock-names = "stmmaceth";
+ power-domains = <&sysctrl>;
+ snps,multicast-filter-bins = <256>;
+ snps,perfect-filter-entries = <128>;
+ tx-fifo-depth = <2048>;
+ rx-fifo-depth = <4096>;
+ pcs-handle = <&mii_conv1>;
+ status = "disabled";
+ };
+
gmac2: ethernet@44002000 {
compatible = "renesas,r9a06g032-gmac", "renesas,rzn1-gmac", "snps,dwmac";
reg = <0x44002000 0x2000>;
--
2.44.0
Hi Romain,
On Tue, Apr 9, 2024 at 11:21 AM Romain Gantois
<[email protected]> wrote:
> From: Clément Léger <[email protected]>
>
> Add support for the Renesas RZ/N1 GMAC. This support can make use of a
> custom RZ/N1 PCS which is fetched by parsing the pcs-handle device tree
> property.
>
> Signed-off-by: "Clément Léger" <[email protected]>
> Co-developed-by: Romain Gantois <[email protected]>
> Signed-off-by: Romain Gantois <[email protected]>
Thanks for your patch!
> --- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
> +++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
> @@ -142,6 +142,18 @@ config DWMAC_ROCKCHIP
> This selects the Rockchip RK3288 SoC glue layer support for
> the stmmac device driver.
>
> +config DWMAC_RZN1
> + tristate "Renesas RZ/N1 dwmac support"
> + default ARCH_RZN1
Why default to enabled?
> + depends on OF && (ARCH_RZN1 || COMPILE_TEST)
> + select PCS_RZN1_MIIC
> + help
> + Support for Ethernet controller on Renesas RZ/N1 SoC family.
> +
> + This selects the Renesas RZ/N1 SoC glue layer support for
> + the stmmac device driver. This support can make use of a custom MII
> + converter PCS device.
> +
> config DWMAC_SOCFPGA
> tristate "SOCFPGA dwmac support"
> default ARCH_INTEL_SOCFPGA
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68korg
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
On Tue, 09 Apr 2024 11:21:46 +0200 Romain Gantois wrote:
> + struct regmap_config pcs_regmap_cfg = {
> + .reg_bits = 16,
> + .val_bits = 16,
> + .reg_shift = regmap_upshift(1),
This appears to displease the compiler:
drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c:389:16: error: call to undeclared function 'regmap_upshift'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
389 | .reg_shift = regmap_upshift(1),
| ^
--
pw-bot: cr
Hi Geert,
On Tue, 9 Apr 2024, Geert Uytterhoeven wrote:
> > +config DWMAC_RZN1
> > + tristate "Renesas RZ/N1 dwmac support"
> > + default ARCH_RZN1
>
> Why default to enabled?
>
> > + depends on OF && (ARCH_RZN1 || COMPILE_TEST)
The kernel doc states this as one of the possible cases where setting default
y/m makes sense:
```
Sub-driver behavior or similar options for a driver that is “default n”. This
allows you to provide sane defaults.
```
In the case of DWMAC_RZN1, it is a suboption of stmmac which is "default n", and
I think it makes sense to enable the RZN1 ethernet controller driver if both the
stmmac driver and the RZN1 architecture were explicitely selected.
Best Regards,
--
Romain Gantois, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
On Tue, Apr 09, 2024 at 06:34:04PM -0700, Jakub Kicinski wrote:
> On Tue, 09 Apr 2024 11:21:46 +0200 Romain Gantois wrote:
> > + struct regmap_config pcs_regmap_cfg = {
> > + .reg_bits = 16,
> > + .val_bits = 16,
> > + .reg_shift = regmap_upshift(1),
>
> This appears to displease the compiler:
>
> drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c:389:16: error: call to undeclared function 'regmap_upshift'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
> 389 | .reg_shift = regmap_upshift(1),
> | ^
Yes, annoyingly I accidentally it 'u' instead of 'y' in vi which
lower-cased the entire function, and didn't realise before sending the
patch as a theoretical solution to Romain. After build-testing it locally
I did notice it. I would've thought that Romain would've build-tested
before sending out his patch set and would've fixed it up... I didn't
have time to properly fix up my patch (essentially would've ment
redoing the edits from scratch to ensure that it was correct.) Still
don't have time to do that. Sorry.
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!
Hello Russell,
On Wed, 10 Apr 2024, Russell King (Oracle) wrote:
> patch as a theoretical solution to Romain. After build-testing it locally
> I did notice it. I would've thought that Romain would've build-tested
> before sending out his patch set and would've fixed it up... I didn't
> have time to properly fix up my patch (essentially would've ment
I build-tested the patches but didn't realize that CONFIG_DWMAC_SOCFPGA was not
enabled in my configuration. So that's my bad, sorry.
Best Regards,
--
Romain Gantois, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
Hi Romain,
On Wed, Apr 10, 2024 at 2:24 PM Romain Gantois
<[email protected]> wrote:
> On Tue, 9 Apr 2024, Geert Uytterhoeven wrote:
> > > +config DWMAC_RZN1
> > > + tristate "Renesas RZ/N1 dwmac support"
> > > + default ARCH_RZN1
> >
> > Why default to enabled?
> >
> > > + depends on OF && (ARCH_RZN1 || COMPILE_TEST)
>
> The kernel doc states this as one of the possible cases where setting default
> y/m makes sense:
>
> ```
> Sub-driver behavior or similar options for a driver that is “default n”. This
> allows you to provide sane defaults.
> ```
>
> In the case of DWMAC_RZN1, it is a suboption of stmmac which is "default n", and
> I think it makes sense to enable the RZN1 ethernet controller driver if both the
> stmmac driver and the RZN1 architecture were explicitely selected.
Thanks for your answer, that makes perfect sense!
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68korg
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds