[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20220510172910.kthpd7kokb2qk27l@skbuf>
Date: Tue, 10 May 2022 20:29:10 +0300
From: Vladimir Oltean <olteanv@...il.com>
To: Hauke Mehrtens <hauke@...ke-m.de>
Cc: davem@...emloft.net, kuba@...nel.org, linus.walleij@...aro.org,
alsi@...g-olufsen.dk, andrew@...n.ch, vivien.didelot@...il.com,
f.fainelli@...il.com, netdev@...r.kernel.org
Subject: Re: [PATCH 4/4] net: dsa: realtek: rtl8365mb: Add SGMII and HSGMII
support
On Mon, May 09, 2022 at 12:48:48AM +0200, Hauke Mehrtens wrote:
> This adds support for SGMII and HSGMII on RTL8367S switches.
> HSGMII is configured using the 2500BASEX mode.
> This is baed on the rtl8367c driver found in OpenWrt.
>
> For (H)SGMII mode we have to load a firmware into some memory which gets
> executed on the integrated 8051. The firmware binary was added as a
> array into the driver with a GPL license notice on top.
>
> This was tested on RTL8367S (ver=0x00a0, opt=0x0001).
>
> Signed-off-by: Hauke Mehrtens <hauke@...ke-m.de>
> ---
> drivers/net/dsa/realtek/rtl8365mb.c | 356 +++++++++++++++++++++++++++-
> 1 file changed, 345 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/net/dsa/realtek/rtl8365mb.c b/drivers/net/dsa/realtek/rtl8365mb.c
> index f9b690251155..5504a34fffeb 100644
> --- a/drivers/net/dsa/realtek/rtl8365mb.c
> +++ b/drivers/net/dsa/realtek/rtl8365mb.c
> @@ -3,6 +3,7 @@
> *
> * Copyright (C) 2021 Alvin Šipraga <alsi@...g-olufsen.dk>
> * Copyright (C) 2021 Michael Rasmussen <mir@...g-olufsen.dk>
> + * Copyright (C) 2022 Hauke Mehrtens <hauke@...ke-m.de>
> *
> * The RTL8365MB-VC is a 4+1 port 10/100/1000M switch controller. It includes 4
> * integrated PHYs for the user facing ports, and an extension interface which
> @@ -98,6 +99,7 @@
> #include <linux/of_irq.h>
> #include <linux/regmap.h>
> #include <linux/if_bridge.h>
> +#include <linux/firmware.h>
>
> #include "realtek.h"
>
> @@ -135,6 +137,7 @@ static const int rtl8365mb_extint_port_map[] = { -1, -1, -1, -1, -1, -1, 1, 2,
>
> /* Chip reset register */
> #define RTL8365MB_CHIP_RESET_REG 0x1322
> +#define RTL8365MB_CHIP_RESET_DW8051 BIT(4)
> #define RTL8365MB_CHIP_RESET_SW_MASK 0x0002
> #define RTL8365MB_CHIP_RESET_HW_MASK 0x0001
>
> @@ -278,6 +281,29 @@ static const int rtl8365mb_extint_port_map[] = { -1, -1, -1, -1, -1, -1, 1, 2,
> #define RTL8365MB_DIGITAL_INTERFACE_FORCE_DUPLEX_MASK 0x0004
> #define RTL8365MB_DIGITAL_INTERFACE_FORCE_SPEED_MASK 0x0003
>
> +#define RTL8365MB_SDS_MISC 0x1d11
> +#define RTL8365MB_CFG_SGMII_RXFC 0x4000
> +#define RTL8365MB_CFG_SGMII_TXFC 0x2000
> +#define RTL8365MB_INB_ARB 0x1000
> +#define RTL8365MB_CFG_MAC8_SEL_HSGMII 0x0800
> +#define RTL8365MB_CFG_SGMII_FDUP 0x0400
> +#define RTL8365MB_CFG_SGMII_LINK 0x0200
> +#define RTL8365MB_CFG_SGMII_SPD 0x0180
> +#define RTL8365MB_CFG_MAC8_SEL_SGMII 0x0040
> +#define RTL8365MB_CFG_INB_SEL 0x0038
> +#define RTL8365MB_CFG_SDS_MODE_18C 0x0007
> +
> +#define RTL8365MB_SDS_INDACS_CMD 0x6600
> +#define RTL8365MB_SDS_INDACS_ADR 0x6601
> +#define RTL8365MB_SDS_INDACS_DATA 0x6602
> +
> +#define RTL8365MB_MISC_CFG0 0x130c
> +#define RTL8365MB_MISC_CFG0_DW8051_EN BIT(5)
> +
> +#define RTL8365MB_DW8051_RDY 0x1336
> +#define RTL8365MB_DW8051_RDY_IROM_MSB BIT(2)
> +#define RTL8365MB_DW8051_RDY_ACS_IROM_EN BIT(1)
> +
> /* CPU port mask register - controls which ports are treated as CPU ports */
> #define RTL8365MB_CPU_PORT_MASK_REG 0x1219
> #define RTL8365MB_CPU_PORT_MASK_MASK 0x07FF
> @@ -296,6 +322,8 @@ static const int rtl8365mb_extint_port_map[] = { -1, -1, -1, -1, -1, -1, 1, 2,
> #define RTL8365MB_CFG0_MAX_LEN_REG 0x088C
> #define RTL8365MB_CFG0_MAX_LEN_MASK 0x3FFF
>
> +#define RTL8365MB_BYPASS_LINE_RATE 0x03f7
> +
> /* Port learning limit registers */
> #define RTL8365MB_LUT_PORT_LEARN_LIMIT_BASE 0x0A20
> #define RTL8365MB_LUT_PORT_LEARN_LIMIT_REG(_physport) \
> @@ -493,6 +521,39 @@ static const struct rtl8365mb_jam_tbl_entry rtl8365mb_init_jam_common[] = {
> { 0x1D32, 0x0002 },
> };
>
> +struct rtl8365mb_sds_init {
> + unsigned int data;
> + unsigned int addr;
> +};
> +
> +static const struct rtl8365mb_sds_init redData[] = {
> + {0x04D7, 0x0480}, {0xF994, 0x0481}, {0x21A2, 0x0482}, {0x6960, 0x0483},
> + {0x9728, 0x0484}, {0x9D85, 0x0423}, {0xD810, 0x0424}, {0x83F2, 0x002E}
> +};
> +
> +static const struct rtl8365mb_sds_init redDataSB[] = {
> + {0x04D7, 0x0480}, {0xF994, 0x0481}, {0x31A2, 0x0482}, {0x6960, 0x0483},
> + {0x9728, 0x0484}, {0x9D85, 0x0423}, {0xD810, 0x0424}, {0x83F2, 0x002E}
> +};
> +
> +static const struct rtl8365mb_sds_init redData1_5_6[] = {
> + {0x82F1, 0x0500}, {0xF195, 0x0501}, {0x31A2, 0x0502}, {0x796C, 0x0503},
> + {0x9728, 0x0504}, {0x9D85, 0x0423}, {0xD810, 0x0424}, {0x0F80, 0x0001},
> + {0x83F2, 0x002E}
> +};
> +
> +static const struct rtl8365mb_sds_init redData8_9[] = {
> + {0x82F1, 0x0500}, {0xF995, 0x0501}, {0x31A2, 0x0502}, {0x796C, 0x0503},
> + {0x9728, 0x0504}, {0x9D85, 0x0423}, {0xD810, 0x0424}, {0x0F80, 0x0001},
> + {0x83F2, 0x002E}
> +};
> +
> +static const struct rtl8365mb_sds_init redDataHB[] = {
> + {0x82F0, 0x0500}, {0xF195, 0x0501}, {0x31A2, 0x0502}, {0x7960, 0x0503},
> + {0x9728, 0x0504}, {0x9D85, 0x0423}, {0xD810, 0x0424}, {0x0F80, 0x0001},
> + {0x83F2, 0x002E}
> +};
> +
> enum rtl8365mb_stp_state {
> RTL8365MB_STP_STATE_DISABLED = 0,
> RTL8365MB_STP_STATE_BLOCKING = 1,
> @@ -801,6 +862,232 @@ rtl8365mb_get_tag_protocol(struct dsa_switch *ds, int port,
> return DSA_TAG_PROTO_RTL8_4;
> }
>
> +static int rtl8365mb_sds_indacs_write(struct realtek_priv *priv, unsigned int addr,
> + unsigned int data)
> +{
> + int ret;
> +
> + ret = regmap_write(priv->map, RTL8365MB_SDS_INDACS_DATA, data);
> + if (ret)
> + return ret;
> +
> + ret = regmap_write(priv->map, RTL8365MB_SDS_INDACS_ADR, addr);
> + if (ret)
> + return ret;
> +
> + return regmap_write(priv->map, RTL8365MB_SDS_INDACS_CMD, 0x00C0);
> +}
> +
> +static int rtl8365mb_sds_indacs_read(struct realtek_priv *priv, unsigned int addr,
> + unsigned int *data)
> +{
> + int ret;
> +
> + ret = regmap_write(priv->map, RTL8365MB_SDS_INDACS_ADR, addr);
> + if (ret)
> + return ret;
> +
> + ret = regmap_write(priv->map, RTL8365MB_SDS_INDACS_CMD, 0x00C0);
> + if (ret)
> + return ret;
> +
> + return regmap_write(priv->map, RTL8365MB_SDS_INDACS_DATA, *data);
> +}
> +
> +static int rtl8365mb_ext_init_sgmii_fw(struct realtek_priv *priv)
> +{
> + struct device *dev = priv->dev;
> + const struct firmware *fw;
> + int ret;
> + int i;
> +
> + ret = request_firmware(&fw, "rtl_switch/rtl8367s-sgmii.bin", dev);
> + if (ret) {
> + dev_err(dev, "failed to load firmware rtl_switch/rtl8367s-sgmii.bin, error: %i\n",
Can you put the firmware name here and in the MODULE_FIRMWARE definition
behind a common macro?
> + ret);
> + return ret;
> + }
> +
> + ret = regmap_update_bits(priv->map, RTL8365MB_CHIP_RESET_REG,
> + RTL8365MB_CHIP_RESET_DW8051,
> + FIELD_PREP(RTL8365MB_CHIP_RESET_DW8051, 1));
> + if (ret)
> + goto release_fw;
> +
> + ret = regmap_update_bits(priv->map, RTL8365MB_MISC_CFG0,
> + RTL8365MB_MISC_CFG0_DW8051_EN,
> + FIELD_PREP(RTL8365MB_MISC_CFG0_DW8051_EN, 1));
> + if (ret)
> + goto release_fw;
> +
> + ret = regmap_update_bits(priv->map, RTL8365MB_DW8051_RDY,
> + RTL8365MB_DW8051_RDY_ACS_IROM_EN,
> + FIELD_PREP(RTL8365MB_DW8051_RDY_ACS_IROM_EN, 1));
> + if (ret)
> + goto release_fw;
> +
> + ret = regmap_update_bits(priv->map, RTL8365MB_DW8051_RDY,
> + RTL8365MB_DW8051_RDY_IROM_MSB,
> + FIELD_PREP(RTL8365MB_DW8051_RDY_IROM_MSB, 0));
> + if (ret)
> + goto release_fw;
> +
> + for (i = 0; i < fw->size; i++) {
> + ret = regmap_write(priv->map, 0xE000 + i, fw->data[i]);
> + if (ret)
> + goto release_fw;
> + }
> +
> + ret = regmap_update_bits(priv->map, RTL8365MB_DW8051_RDY,
> + RTL8365MB_DW8051_RDY_IROM_MSB,
> + FIELD_PREP(RTL8365MB_DW8051_RDY_IROM_MSB, 0));
> + if (ret)
> + goto release_fw;
> +
> + ret = regmap_update_bits(priv->map, RTL8365MB_DW8051_RDY,
> + RTL8365MB_DW8051_RDY_ACS_IROM_EN,
> + FIELD_PREP(RTL8365MB_DW8051_RDY_ACS_IROM_EN, 0));
> + if (ret)
> + goto release_fw;
> +
> + ret = regmap_update_bits(priv->map, RTL8365MB_CHIP_RESET_REG,
> + RTL8365MB_CHIP_RESET_DW8051,
> + FIELD_PREP(RTL8365MB_CHIP_RESET_DW8051, 0));
> +
> +release_fw:
> + release_firmware(fw);
> + return ret;
> +}
> +
> +static int rtl8365mb_ext_init_sgmii(struct realtek_priv *priv, int port, phy_interface_t interface)
> +{
> + struct rtl8365mb *mb;
> + int interface_mode;
> + int sds_mode;
> + const struct rtl8365mb_sds_init *sds_init;
> + size_t sds_init_len;
> + int ext_int;
> + int ret;
> + int i;
> + int val;
> + int mask;
Please keep variables sorted longest to shortest.
> +
> + mb = priv->chip_data;
> +
> + if (mb->chip_id != RTL8365MB_CHIP_ID_8365MB_VC)
> + return -EINVAL;
> +
> + ext_int = rtl8365mb_extint_port_map[port];
> + if (ext_int != 1)
> + return -EINVAL;
> +
> + if (interface == PHY_INTERFACE_MODE_SGMII) {
> + sds_mode = FIELD_PREP(RTL8365MB_CFG_MAC8_SEL_SGMII, 1);
> + interface_mode = RTL8365MB_EXT_PORT_MODE_SGMII;
> +
> + if (mb->chip_option == 0) {
> + sds_init = redData;
> + sds_init_len = ARRAY_SIZE(redData);
> + } else {
> + sds_init = redDataSB;
> + sds_init_len = ARRAY_SIZE(redDataSB);
> + }
> + } else if (interface == PHY_INTERFACE_MODE_2500BASEX) {
> + sds_mode = FIELD_PREP(RTL8365MB_CFG_MAC8_SEL_HSGMII, 1);
> + interface_mode = RTL8365MB_EXT_PORT_MODE_HSGMII;
> +
> + if (mb->chip_option == 0) {
> + switch (mb->chip_ver & 0x00F0) {
> + case 0x0010:
> + case 0x0050:
> + case 0x0060:
> + sds_init = redData1_5_6;
> + sds_init_len = ARRAY_SIZE(redData1_5_6);
> + break;
> + case 0x0080:
> + case 0x0090:
> + sds_init = redData8_9;
> + sds_init_len = ARRAY_SIZE(redData8_9);
> + break;
> + default:
> + return -EINVAL;
> + }
> + } else {
> + sds_init = redDataHB;
> + sds_init_len = ARRAY_SIZE(redDataHB);
> + }
> + } else {
> + return -EINVAL;
> + }
> +
> + for (i = 0; i < sds_init_len; i++) {
> + ret = rtl8365mb_sds_indacs_write(priv, sds_init[i].addr, sds_init[i].data);
> + if (ret)
> + return ret;
> + }
> +
> + mask = RTL8365MB_CFG_MAC8_SEL_SGMII | RTL8365MB_CFG_MAC8_SEL_HSGMII;
> + ret = regmap_update_bits(priv->map,
> + RTL8365MB_SDS_MISC,
> + mask,
> + sds_mode);
> + if (ret)
> + return ret;
> +
> + mask = RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_MASK(ext_int);
> + val = interface_mode << RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_OFFSET(ext_int);
> + ret = regmap_update_bits(priv->map,
> + RTL8365MB_DIGITAL_INTERFACE_SELECT_REG(ext_int),
> + mask,
> + val);
> + if (ret)
> + return ret;
> +
> + ret = regmap_write(priv->map, RTL8365MB_BYPASS_LINE_RATE, 0x0);
> + if (ret)
> + return ret;
> +
> + /* Serdes not reset */
> + ret = rtl8365mb_sds_indacs_write(priv, 0x0003, 0x7106);
> + if (ret)
> + return ret;
> +
> + return rtl8365mb_ext_init_sgmii_fw(priv);
> +}
> +
> +static int rtl8365mb_ext_sgmii_nway(struct realtek_priv *priv, bool state)
What is "nway"? In-band autoneg by any chance? If so, could you pass
"phylink_autoneg_inband(mode)" rather than "false" as "state"?
> +{
> + u32 running;
> + u32 regValue;
> + int ret;
> +
> + ret = regmap_read(priv->map, RTL8365MB_MISC_CFG0, &running);
> + if (running & RTL8365MB_MISC_CFG0_DW8051_EN) {
> + ret = regmap_update_bits(priv->map, RTL8365MB_MISC_CFG0,
> + RTL8365MB_MISC_CFG0_DW8051_EN,
> + FIELD_PREP(RTL8365MB_MISC_CFG0_DW8051_EN, 0));
> + if (ret)
> + return ret;
> + }
> +
> + ret = rtl8365mb_sds_indacs_read(priv, 0x0002, ®Value);
> + if (ret)
> + return ret;
> +
> + if (state)
> + regValue |= 0x0200;
> + else
> + regValue &= ~0x0200;
No camelCase please.
> + regValue |= 0x0100;
> +
> + ret = rtl8365mb_sds_indacs_write(priv, 0x0002, regValue);
Any idea what the magic numbers are? At least 0x0200 looks like BIT(9).
> + if (ret)
> + return ret;
> + return regmap_update_bits(priv->map, RTL8365MB_MISC_CFG0,
> + RTL8365MB_MISC_CFG0_DW8051_EN,
> + FIELD_PREP(RTL8365MB_MISC_CFG0_DW8051_EN, 1));
> +}
> +
> static int rtl8365mb_ext_config_rgmii(struct realtek_priv *priv, int port,
> phy_interface_t interface)
> {
> @@ -886,6 +1173,7 @@ static int rtl8365mb_ext_config_rgmii(struct realtek_priv *priv, int port,
> }
>
> static int rtl8365mb_ext_config_forcemode(struct realtek_priv *priv, int port,
> + phy_interface_t interface,
> bool link, int speed, int duplex,
> bool tx_pause, bool rx_pause)
> {
> @@ -911,7 +1199,7 @@ static int rtl8365mb_ext_config_forcemode(struct realtek_priv *priv, int port,
> r_rx_pause = rx_pause ? 1 : 0;
> r_tx_pause = tx_pause ? 1 : 0;
>
> - if (speed == SPEED_1000) {
> + if (speed == SPEED_1000 || speed == SPEED_2500) {
> r_speed = RTL8365MB_PORT_SPEED_1000M;
> } else if (speed == SPEED_100) {
> r_speed = RTL8365MB_PORT_SPEED_100M;
> @@ -941,6 +1229,25 @@ static int rtl8365mb_ext_config_forcemode(struct realtek_priv *priv, int port,
> r_duplex = 0;
> }
>
> + if (interface == PHY_INTERFACE_MODE_SGMII ||
> + interface == PHY_INTERFACE_MODE_2500BASEX) {
> + val = FIELD_PREP(RTL8365MB_CFG_SGMII_FDUP, r_duplex) |
> + FIELD_PREP(RTL8365MB_CFG_SGMII_SPD, r_speed) |
> + FIELD_PREP(RTL8365MB_CFG_SGMII_LINK, r_link) |
> + FIELD_PREP(RTL8365MB_CFG_SGMII_TXFC, r_tx_pause) |
> + FIELD_PREP(RTL8365MB_CFG_SGMII_RXFC, r_rx_pause);
> + ret = regmap_update_bits(priv->map,
> + RTL8365MB_SDS_MISC,
> + RTL8365MB_CFG_SGMII_FDUP |
> + RTL8365MB_CFG_SGMII_SPD |
> + RTL8365MB_CFG_SGMII_LINK |
> + RTL8365MB_CFG_SGMII_TXFC |
> + RTL8365MB_CFG_SGMII_RXFC,
> + val);
> + if (ret)
> + return ret;
> + }
> +
> val = FIELD_PREP(RTL8365MB_DIGITAL_INTERFACE_FORCE_EN_MASK, 1) |
> FIELD_PREP(RTL8365MB_DIGITAL_INTERFACE_FORCE_TXPAUSE_MASK,
> r_tx_pause) |
> @@ -972,10 +1279,15 @@ static bool rtl8365mb_phy_mode_supported(struct dsa_switch *ds, int port,
> interface == PHY_INTERFACE_MODE_GMII))
> /* Internal PHY */
> return true;
> - else if ((ext_int >= 1) &&
> - phy_interface_mode_is_rgmii(interface))
> + else if ((ext_int == 1) &&
> + (phy_interface_mode_is_rgmii(interface) ||
> + interface == PHY_INTERFACE_MODE_SGMII ||
> + interface == PHY_INTERFACE_MODE_2500BASEX))
> /* Extension MAC */
> return true;
> + else if ((ext_int >= 2) &&
> + phy_interface_mode_is_rgmii(interface))
> + return true;
>
> return false;
> }
> @@ -983,14 +1295,25 @@ static bool rtl8365mb_phy_mode_supported(struct dsa_switch *ds, int port,
> static void rtl8365mb_phylink_get_caps(struct dsa_switch *ds, int port,
> struct phylink_config *config)
> {
> - if (dsa_is_user_port(ds, port))
> + int ext_int = rtl8365mb_extint_port_map[port];
> +
> + config->mac_capabilities = MAC_SYM_PAUSE | MAC_ASYM_PAUSE |
> + MAC_10 | MAC_100 | MAC_1000FD;
> +
> + if (dsa_is_user_port(ds, port)) {
> __set_bit(PHY_INTERFACE_MODE_INTERNAL,
> config->supported_interfaces);
> - else if (dsa_is_cpu_port(ds, port))
> + } else if (dsa_is_cpu_port(ds, port)) {
What does the quality of being a user port or a CPU port have to do with
which interfaces are supported?
> + if (ext_int == 1) {
> + __set_bit(PHY_INTERFACE_MODE_SGMII,
> + config->supported_interfaces);
> + __set_bit(PHY_INTERFACE_MODE_2500BASEX,
> + config->supported_interfaces);
> + config->mac_capabilities |= MAC_2500FD;
> + }
> phy_interface_set_rgmii(config->supported_interfaces);
> + }
>
> - config->mac_capabilities = MAC_SYM_PAUSE | MAC_ASYM_PAUSE |
> - MAC_10 | MAC_100 | MAC_1000FD;
> }
>
> static void rtl8365mb_phylink_mac_config(struct dsa_switch *ds, int port,
> @@ -1020,6 +1343,10 @@ static void rtl8365mb_phylink_mac_config(struct dsa_switch *ds, int port,
> "failed to configure RGMII mode on port %d: %d\n",
> port, ret);
> return;
> + } else if (state->interface == PHY_INTERFACE_MODE_SGMII ||
> + state->interface == PHY_INTERFACE_MODE_2500BASEX) {
> + rtl8365mb_ext_init_sgmii(priv, port, state->interface);
> + rtl8365mb_ext_sgmii_nway(priv, false);
> }
>
> /* TODO: Implement MII and RMII modes, which the RTL8365MB-VC also
> @@ -1040,8 +1367,11 @@ static void rtl8365mb_phylink_mac_link_down(struct dsa_switch *ds, int port,
> p = &mb->ports[port];
> cancel_delayed_work_sync(&p->mib_work);
>
> - if (phy_interface_mode_is_rgmii(interface)) {
> - ret = rtl8365mb_ext_config_forcemode(priv, port, false, 0, 0,
> + if (phy_interface_mode_is_rgmii(interface) ||
> + interface == PHY_INTERFACE_MODE_SGMII ||
> + interface == PHY_INTERFACE_MODE_2500BASEX) {
If in-band autoneg is possible, there will have to be an additional
condition here, to only force the mode if it is disabled (which it now is)
> + ret = rtl8365mb_ext_config_forcemode(priv, port, interface,
> + false, 0, 0,
> false, false);
> if (ret)
> dev_err(priv->dev,
> @@ -1068,8 +1398,11 @@ static void rtl8365mb_phylink_mac_link_up(struct dsa_switch *ds, int port,
> p = &mb->ports[port];
> schedule_delayed_work(&p->mib_work, 0);
>
> - if (phy_interface_mode_is_rgmii(interface)) {
> - ret = rtl8365mb_ext_config_forcemode(priv, port, true, speed,
> + if (phy_interface_mode_is_rgmii(interface) ||
> + interface == PHY_INTERFACE_MODE_SGMII ||
> + interface == PHY_INTERFACE_MODE_2500BASEX) {
> + ret = rtl8365mb_ext_config_forcemode(priv, port, interface,
> + true, speed,
> duplex, tx_pause,
> rx_pause);
> if (ret)
> @@ -2156,6 +2489,7 @@ const struct realtek_variant rtl8365mb_variant = {
> };
> EXPORT_SYMBOL_GPL(rtl8365mb_variant);
>
> +MODULE_FIRMWARE("rtl_switch/rtl8367s-sgmii.bin");
> MODULE_AUTHOR("Alvin Šipraga <alsi@...g-olufsen.dk>");
> MODULE_DESCRIPTION("Driver for RTL8365MB-VC ethernet switch");
> MODULE_LICENSE("GPL");
> --
> 2.30.2
>
Powered by blists - more mailing lists