mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-19 05:38:00 +00:00
kernel: remove linux 4.4 support
No targets are using it anymore Signed-off-by: Koen Vandeputte <koen.vandeputte@ncentric.com>
This commit is contained in:
parent
e3ab280e47
commit
4017c528ca
@ -2,11 +2,9 @@
|
||||
|
||||
LINUX_RELEASE?=1
|
||||
|
||||
LINUX_VERSION-4.4 = .121
|
||||
LINUX_VERSION-4.9 = .117
|
||||
LINUX_VERSION-4.14 = .60
|
||||
|
||||
LINUX_KERNEL_HASH-4.4.121 = 44a88268b5088dc326b30c9b9133ac35a9a200b636b7268d08f32abeae6ca729
|
||||
LINUX_KERNEL_HASH-4.9.117 = 8232ea326ac5784d71baa09c0cd7806a2674f8449c0be73e2ae341e6880279b0
|
||||
LINUX_KERNEL_HASH-4.14.60 = 6ce143258fba2e1f543ff56802e047d7d3a741f746b9c947dd088d4a2873b295
|
||||
|
||||
|
@ -51,7 +51,7 @@ else
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq ($(filter 4.4 4.9,$(KERNEL_PATCHVER)),)
|
||||
ifneq ($(filter 4.9,$(KERNEL_PATCHVER)),)
|
||||
DEFAULT_PACKAGES.router:=$(filter-out kmod-ipt-offload,$(DEFAULT_PACKAGES.router))
|
||||
endif
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,153 +0,0 @@
|
||||
--- a/drivers/mtd/mtdsplit/mtdsplit_brnimage.c
|
||||
+++ b/drivers/mtd/mtdsplit/mtdsplit_brnimage.c
|
||||
@@ -27,7 +27,7 @@
|
||||
#define BRNIMAGE_MAX_OVERHEAD (BRNIMAGE_ALIGN_BYTES + BRNIMAGE_FOOTER_SIZE)
|
||||
|
||||
static int mtdsplit_parse_brnimage(struct mtd_info *master,
|
||||
- const struct mtd_partition **pparts,
|
||||
+ struct mtd_partition **pparts,
|
||||
struct mtd_part_parser_data *data)
|
||||
{
|
||||
struct mtd_partition *parts;
|
||||
--- a/drivers/mtd/mtdsplit/mtdsplit_eva.c
|
||||
+++ b/drivers/mtd/mtdsplit/mtdsplit_eva.c
|
||||
@@ -29,7 +29,7 @@ struct eva_image_header {
|
||||
};
|
||||
|
||||
static int mtdsplit_parse_eva(struct mtd_info *master,
|
||||
- const struct mtd_partition **pparts,
|
||||
+ struct mtd_partition **pparts,
|
||||
struct mtd_part_parser_data *data)
|
||||
{
|
||||
struct mtd_partition *parts;
|
||||
--- a/drivers/mtd/mtdsplit/mtdsplit_fit.c
|
||||
+++ b/drivers/mtd/mtdsplit/mtdsplit_fit.c
|
||||
@@ -45,8 +45,7 @@ struct fdt_header {
|
||||
};
|
||||
|
||||
static int
|
||||
-mtdsplit_fit_parse(struct mtd_info *mtd,
|
||||
- const struct mtd_partition **pparts,
|
||||
+mtdsplit_fit_parse(struct mtd_info *mtd, struct mtd_partition **pparts,
|
||||
struct mtd_part_parser_data *data)
|
||||
{
|
||||
struct fdt_header hdr;
|
||||
--- a/drivers/mtd/mtdsplit/mtdsplit_lzma.c
|
||||
+++ b/drivers/mtd/mtdsplit/mtdsplit_lzma.c
|
||||
@@ -28,7 +28,7 @@ struct lzma_header {
|
||||
};
|
||||
|
||||
static int mtdsplit_parse_lzma(struct mtd_info *master,
|
||||
- const struct mtd_partition **pparts,
|
||||
+ struct mtd_partition **pparts,
|
||||
struct mtd_part_parser_data *data)
|
||||
{
|
||||
struct lzma_header hdr;
|
||||
--- a/drivers/mtd/mtdsplit/mtdsplit_seama.c
|
||||
+++ b/drivers/mtd/mtdsplit/mtdsplit_seama.c
|
||||
@@ -30,7 +30,7 @@ struct seama_header {
|
||||
};
|
||||
|
||||
static int mtdsplit_parse_seama(struct mtd_info *master,
|
||||
- const struct mtd_partition **pparts,
|
||||
+ struct mtd_partition **pparts,
|
||||
struct mtd_part_parser_data *data)
|
||||
{
|
||||
struct seama_header hdr;
|
||||
--- a/drivers/mtd/mtdsplit/mtdsplit_squashfs.c
|
||||
+++ b/drivers/mtd/mtdsplit/mtdsplit_squashfs.c
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
static int
|
||||
mtdsplit_parse_squashfs(struct mtd_info *master,
|
||||
- const struct mtd_partition **pparts,
|
||||
+ struct mtd_partition **pparts,
|
||||
struct mtd_part_parser_data *data)
|
||||
{
|
||||
struct mtd_partition *part;
|
||||
--- a/drivers/mtd/mtdsplit/mtdsplit_tplink.c
|
||||
+++ b/drivers/mtd/mtdsplit/mtdsplit_tplink.c
|
||||
@@ -83,8 +83,8 @@ struct tplink_fw_header {
|
||||
};
|
||||
|
||||
static int mtdsplit_parse_tplink(struct mtd_info *master,
|
||||
- const struct mtd_partition **pparts,
|
||||
- struct mtd_part_parser_data *data)
|
||||
+ struct mtd_partition **pparts,
|
||||
+ struct mtd_part_parser_data *data)
|
||||
{
|
||||
struct tplink_fw_header hdr;
|
||||
size_t hdr_len, retlen, kernel_size;
|
||||
--- a/drivers/mtd/mtdsplit/mtdsplit_trx.c
|
||||
+++ b/drivers/mtd/mtdsplit/mtdsplit_trx.c
|
||||
@@ -56,7 +56,7 @@ read_trx_header(struct mtd_info *mtd, si
|
||||
|
||||
static int
|
||||
mtdsplit_parse_trx(struct mtd_info *master,
|
||||
- const struct mtd_partition **pparts,
|
||||
+ struct mtd_partition **pparts,
|
||||
struct mtd_part_parser_data *data)
|
||||
{
|
||||
struct mtd_partition *parts;
|
||||
--- a/drivers/mtd/mtdsplit/mtdsplit_uimage.c
|
||||
+++ b/drivers/mtd/mtdsplit/mtdsplit_uimage.c
|
||||
@@ -81,7 +81,7 @@ read_uimage_header(struct mtd_info *mtd,
|
||||
* of a valid uImage header if found
|
||||
*/
|
||||
static int __mtdsplit_parse_uimage(struct mtd_info *master,
|
||||
- const struct mtd_partition **pparts,
|
||||
+ struct mtd_partition **pparts,
|
||||
struct mtd_part_parser_data *data,
|
||||
ssize_t (*find_header)(u_char *buf, size_t len))
|
||||
{
|
||||
@@ -232,7 +232,7 @@ static ssize_t uimage_verify_default(u_c
|
||||
|
||||
static int
|
||||
mtdsplit_uimage_parse_generic(struct mtd_info *master,
|
||||
- const struct mtd_partition **pparts,
|
||||
+ struct mtd_partition **pparts,
|
||||
struct mtd_part_parser_data *data)
|
||||
{
|
||||
return __mtdsplit_parse_uimage(master, pparts, data,
|
||||
@@ -289,7 +289,7 @@ static ssize_t uimage_verify_wndr3700(u_
|
||||
|
||||
static int
|
||||
mtdsplit_uimage_parse_netgear(struct mtd_info *master,
|
||||
- const struct mtd_partition **pparts,
|
||||
+ struct mtd_partition **pparts,
|
||||
struct mtd_part_parser_data *data)
|
||||
{
|
||||
return __mtdsplit_parse_uimage(master, pparts, data,
|
||||
@@ -331,7 +331,7 @@ static ssize_t uimage_find_edimax(u_char
|
||||
|
||||
static int
|
||||
mtdsplit_uimage_parse_edimax(struct mtd_info *master,
|
||||
- const struct mtd_partition **pparts,
|
||||
+ struct mtd_partition **pparts,
|
||||
struct mtd_part_parser_data *data)
|
||||
{
|
||||
return __mtdsplit_parse_uimage(master, pparts, data,
|
||||
--- a/drivers/mtd/mtdsplit/mtdsplit_wrgg.c
|
||||
+++ b/drivers/mtd/mtdsplit/mtdsplit_wrgg.c
|
||||
@@ -51,8 +51,8 @@ struct wrg_header {
|
||||
|
||||
|
||||
static int mtdsplit_parse_wrgg(struct mtd_info *master,
|
||||
- const struct mtd_partition **pparts,
|
||||
- struct mtd_part_parser_data *data)
|
||||
+ struct mtd_partition **pparts,
|
||||
+ struct mtd_part_parser_data *data)
|
||||
{
|
||||
struct wrgg03_header hdr;
|
||||
size_t hdr_len, retlen, kernel_ent_size;
|
||||
--- a/drivers/mtd/mtdsplit/mtdsplit_minor.c
|
||||
+++ b/drivers/mtd/mtdsplit/mtdsplit_minor.c
|
||||
@@ -49,7 +49,7 @@ struct minor_header {
|
||||
};
|
||||
|
||||
static int mtdsplit_parse_minor(struct mtd_info *master,
|
||||
- const struct mtd_partition **pparts,
|
||||
+ struct mtd_partition **pparts,
|
||||
struct mtd_part_parser_data *data)
|
||||
{
|
||||
struct minor_header hdr;
|
@ -1,640 +0,0 @@
|
||||
--- a/drivers/net/phy/adm6996.c
|
||||
+++ b/drivers/net/phy/adm6996.c
|
||||
@@ -289,7 +289,7 @@ static u16
|
||||
adm6996_read_mii_reg(struct adm6996_priv *priv, enum admreg reg)
|
||||
{
|
||||
struct phy_device *phydev = priv->priv;
|
||||
- struct mii_bus *bus = phydev->mdio.bus;
|
||||
+ struct mii_bus *bus = phydev->bus;
|
||||
|
||||
return bus->read(bus, PHYADDR(reg));
|
||||
}
|
||||
@@ -298,7 +298,7 @@ static void
|
||||
adm6996_write_mii_reg(struct adm6996_priv *priv, enum admreg reg, u16 val)
|
||||
{
|
||||
struct phy_device *phydev = priv->priv;
|
||||
- struct mii_bus *bus = phydev->mdio.bus;
|
||||
+ struct mii_bus *bus = phydev->bus;
|
||||
|
||||
bus->write(bus, PHYADDR(reg), val);
|
||||
}
|
||||
@@ -1050,13 +1050,13 @@ static int adm6996_config_init(struct ph
|
||||
pdev->supported = ADVERTISED_100baseT_Full;
|
||||
pdev->advertising = ADVERTISED_100baseT_Full;
|
||||
|
||||
- if (pdev->mdio.addr != 0) {
|
||||
+ if (pdev->addr != 0) {
|
||||
pr_info ("%s: PHY overlaps ADM6996, providing fixed PHY 0x%x.\n"
|
||||
- , pdev->attached_dev->name, pdev->mdio.addr);
|
||||
+ , pdev->attached_dev->name, pdev->addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
- priv = devm_kzalloc(&pdev->mdio.dev, sizeof(struct adm6996_priv), GFP_KERNEL);
|
||||
+ priv = devm_kzalloc(&pdev->dev, sizeof(struct adm6996_priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -1076,7 +1076,7 @@ static int adm6996_config_init(struct ph
|
||||
}
|
||||
|
||||
/*
|
||||
- * Warning: phydev->priv is NULL if phydev->mdio.addr != 0
|
||||
+ * Warning: phydev->priv is NULL if phydev->addr != 0
|
||||
*/
|
||||
static int adm6996_read_status(struct phy_device *phydev)
|
||||
{
|
||||
@@ -1092,7 +1092,7 @@ static int adm6996_read_status(struct ph
|
||||
}
|
||||
|
||||
/*
|
||||
- * Warning: phydev->priv is NULL if phydev->mdio.addr != 0
|
||||
+ * Warning: phydev->priv is NULL if phydev->addr != 0
|
||||
*/
|
||||
static int adm6996_config_aneg(struct phy_device *phydev)
|
||||
{
|
||||
@@ -1101,11 +1101,11 @@ static int adm6996_config_aneg(struct ph
|
||||
|
||||
static int adm6996_fixup(struct phy_device *dev)
|
||||
{
|
||||
- struct mii_bus *bus = dev->mdio.bus;
|
||||
+ struct mii_bus *bus = dev->bus;
|
||||
u16 reg;
|
||||
|
||||
/* Our custom registers are at PHY addresses 0-10. Claim those. */
|
||||
- if (dev->mdio.addr > 10)
|
||||
+ if (dev->addr > 10)
|
||||
return 0;
|
||||
|
||||
/* look for the switch on the bus */
|
||||
@@ -1152,6 +1152,7 @@ static struct phy_driver adm6996_phy_dri
|
||||
.config_aneg = &adm6996_config_aneg,
|
||||
.read_status = &adm6996_read_status,
|
||||
.soft_reset = adm6996_soft_reset,
|
||||
+ .driver = { .owner = THIS_MODULE,},
|
||||
};
|
||||
|
||||
static int adm6996_gpio_probe(struct platform_device *pdev)
|
||||
@@ -1220,7 +1221,7 @@ static int __init adm6996_init(void)
|
||||
int err;
|
||||
|
||||
phy_register_fixup_for_id(PHY_ANY_ID, adm6996_fixup);
|
||||
- err = phy_driver_register(&adm6996_phy_driver, THIS_MODULE);
|
||||
+ err = phy_driver_register(&adm6996_phy_driver);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
--- a/drivers/net/phy/ar8216.c
|
||||
+++ b/drivers/net/phy/ar8216.c
|
||||
@@ -177,7 +177,7 @@ ar8xxx_phy_check_aneg(struct phy_device
|
||||
if (ret & BMCR_ANENABLE)
|
||||
return 0;
|
||||
|
||||
- dev_info(&phydev->mdio.dev, "ANEG disabled, re-enabling ...\n");
|
||||
+ dev_info(&phydev->dev, "ANEG disabled, re-enabling ...\n");
|
||||
ret |= BMCR_ANENABLE | BMCR_ANRESTART;
|
||||
return phy_write(phydev, MII_BMCR, ret);
|
||||
}
|
||||
@@ -2007,7 +2007,7 @@ ar8xxx_phy_config_init(struct phy_device
|
||||
|
||||
priv->phy = phydev;
|
||||
|
||||
- if (phydev->mdio.addr != 0) {
|
||||
+ if (phydev->addr != 0) {
|
||||
if (chip_is_ar8316(priv)) {
|
||||
/* switch device has been initialized, reinit */
|
||||
priv->dev.ports = (AR8216_NUM_PORTS - 1);
|
||||
@@ -2055,7 +2055,7 @@ ar8xxx_check_link_states(struct ar8xxx_p
|
||||
/* flush ARL entries for this port if it went down*/
|
||||
if (!link_new)
|
||||
priv->chip->atu_flush_port(priv, i);
|
||||
- dev_info(&priv->phy->mdio.dev, "Port %d is %s\n",
|
||||
+ dev_info(&priv->phy->dev, "Port %d is %s\n",
|
||||
i, link_new ? "up" : "down");
|
||||
}
|
||||
|
||||
@@ -2074,10 +2074,10 @@ ar8xxx_phy_read_status(struct phy_device
|
||||
if (phydev->state == PHY_CHANGELINK)
|
||||
ar8xxx_check_link_states(priv);
|
||||
|
||||
- if (phydev->mdio.addr != 0)
|
||||
+ if (phydev->addr != 0)
|
||||
return genphy_read_status(phydev);
|
||||
|
||||
- ar8216_read_port_link(priv, phydev->mdio.addr, &link);
|
||||
+ ar8216_read_port_link(priv, phydev->addr, &link);
|
||||
phydev->link = !!link.link;
|
||||
if (!phydev->link)
|
||||
return 0;
|
||||
@@ -2107,7 +2107,7 @@ ar8xxx_phy_read_status(struct phy_device
|
||||
static int
|
||||
ar8xxx_phy_config_aneg(struct phy_device *phydev)
|
||||
{
|
||||
- if (phydev->mdio.addr == 0)
|
||||
+ if (phydev->addr == 0)
|
||||
return 0;
|
||||
|
||||
return genphy_config_aneg(phydev);
|
||||
@@ -2162,15 +2162,15 @@ ar8xxx_phy_probe(struct phy_device *phyd
|
||||
int ret;
|
||||
|
||||
/* skip PHYs at unused adresses */
|
||||
- if (phydev->mdio.addr != 0 && phydev->mdio.addr != 4)
|
||||
+ if (phydev->addr != 0 && phydev->addr != 4)
|
||||
return -ENODEV;
|
||||
|
||||
- if (!ar8xxx_is_possible(phydev->mdio.bus))
|
||||
+ if (!ar8xxx_is_possible(phydev->bus))
|
||||
return -ENODEV;
|
||||
|
||||
mutex_lock(&ar8xxx_dev_list_lock);
|
||||
list_for_each_entry(priv, &ar8xxx_dev_list, list)
|
||||
- if (priv->mii_bus == phydev->mdio.bus)
|
||||
+ if (priv->mii_bus == phydev->bus)
|
||||
goto found;
|
||||
|
||||
priv = ar8xxx_create();
|
||||
@@ -2179,7 +2179,7 @@ ar8xxx_phy_probe(struct phy_device *phyd
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
- priv->mii_bus = phydev->mdio.bus;
|
||||
+ priv->mii_bus = phydev->bus;
|
||||
|
||||
ret = ar8xxx_probe_switch(priv);
|
||||
if (ret)
|
||||
@@ -2200,7 +2200,7 @@ ar8xxx_phy_probe(struct phy_device *phyd
|
||||
found:
|
||||
priv->use_count++;
|
||||
|
||||
- if (phydev->mdio.addr == 0) {
|
||||
+ if (phydev->addr == 0) {
|
||||
if (ar8xxx_has_gige(priv)) {
|
||||
phydev->supported = SUPPORTED_1000baseT_Full;
|
||||
phydev->advertising = ADVERTISED_1000baseT_Full;
|
||||
@@ -2288,21 +2288,33 @@ ar8xxx_phy_soft_reset(struct phy_device
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static struct phy_driver ar8xxx_phy_driver[] = {
|
||||
- {
|
||||
- .phy_id = 0x004d0000,
|
||||
- .name = "Atheros AR8216/AR8236/AR8316",
|
||||
- .phy_id_mask = 0xffff0000,
|
||||
- .features = PHY_BASIC_FEATURES,
|
||||
- .probe = ar8xxx_phy_probe,
|
||||
- .remove = ar8xxx_phy_remove,
|
||||
- .detach = ar8xxx_phy_detach,
|
||||
- .config_init = ar8xxx_phy_config_init,
|
||||
- .config_aneg = ar8xxx_phy_config_aneg,
|
||||
- .read_status = ar8xxx_phy_read_status,
|
||||
- .soft_reset = ar8xxx_phy_soft_reset,
|
||||
- }
|
||||
+static struct phy_driver ar8xxx_phy_driver = {
|
||||
+ .phy_id = 0x004d0000,
|
||||
+ .name = "Atheros AR8216/AR8236/AR8316",
|
||||
+ .phy_id_mask = 0xffff0000,
|
||||
+ .features = PHY_BASIC_FEATURES,
|
||||
+ .probe = ar8xxx_phy_probe,
|
||||
+ .remove = ar8xxx_phy_remove,
|
||||
+ .detach = ar8xxx_phy_detach,
|
||||
+ .config_init = ar8xxx_phy_config_init,
|
||||
+ .config_aneg = ar8xxx_phy_config_aneg,
|
||||
+ .read_status = ar8xxx_phy_read_status,
|
||||
+ .soft_reset = ar8xxx_phy_soft_reset,
|
||||
+ .driver = { .owner = THIS_MODULE },
|
||||
};
|
||||
|
||||
-module_phy_driver(ar8xxx_phy_driver);
|
||||
+int __init
|
||||
+ar8xxx_init(void)
|
||||
+{
|
||||
+ return phy_driver_register(&ar8xxx_phy_driver);
|
||||
+}
|
||||
+
|
||||
+void __exit
|
||||
+ar8xxx_exit(void)
|
||||
+{
|
||||
+ phy_driver_unregister(&ar8xxx_phy_driver);
|
||||
+}
|
||||
+
|
||||
+module_init(ar8xxx_init);
|
||||
+module_exit(ar8xxx_exit);
|
||||
MODULE_LICENSE("GPL");
|
||||
--- a/drivers/net/phy/ar8327.c
|
||||
+++ b/drivers/net/phy/ar8327.c
|
||||
@@ -627,11 +627,11 @@ ar8327_hw_init(struct ar8xxx_priv *priv)
|
||||
if (!priv->chip_data)
|
||||
return -ENOMEM;
|
||||
|
||||
- if (priv->phy->mdio.dev.of_node)
|
||||
- ret = ar8327_hw_config_of(priv, priv->phy->mdio.dev.of_node);
|
||||
+ if (priv->phy->dev.of_node)
|
||||
+ ret = ar8327_hw_config_of(priv, priv->phy->dev.of_node);
|
||||
else
|
||||
ret = ar8327_hw_config_pdata(priv,
|
||||
- priv->phy->mdio.dev.platform_data);
|
||||
+ priv->phy->dev.platform_data);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
--- a/drivers/net/phy/ip17xx.c
|
||||
+++ b/drivers/net/phy/ip17xx.c
|
||||
@@ -1273,7 +1273,7 @@ static int ip17xx_probe(struct phy_devic
|
||||
int err;
|
||||
|
||||
/* We only attach to PHY 0, but use all available PHYs */
|
||||
- if (pdev->mdio.addr != 0)
|
||||
+ if (pdev->addr != 0)
|
||||
return -ENODEV;
|
||||
|
||||
state = kzalloc(sizeof(*state), GFP_KERNEL);
|
||||
@@ -1283,7 +1283,7 @@ static int ip17xx_probe(struct phy_devic
|
||||
dev = &state->dev;
|
||||
|
||||
pdev->priv = state;
|
||||
- state->mii_bus = pdev->mdio.bus;
|
||||
+ state->mii_bus = pdev->bus;
|
||||
|
||||
err = get_model(state);
|
||||
if (err < 0)
|
||||
@@ -1295,7 +1295,7 @@ static int ip17xx_probe(struct phy_devic
|
||||
dev->name = state->regs->NAME;
|
||||
dev->ops = &ip17xx_ops;
|
||||
|
||||
- pr_info("IP17xx: Found %s at %s\n", dev->name, dev_name(&pdev->mdio.dev));
|
||||
+ pr_info("IP17xx: Found %s at %s\n", dev->name, dev_name(&pdev->dev));
|
||||
return 0;
|
||||
|
||||
error:
|
||||
@@ -1353,25 +1353,58 @@ static int ip17xx_read_status(struct phy
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static struct phy_driver ip17xx_driver[] = {
|
||||
- {
|
||||
- .name = "IC+ IP17xx",
|
||||
- .phy_id = 0x02430c00,
|
||||
- .phy_id_mask = 0x0ffffc00,
|
||||
- .features = PHY_BASIC_FEATURES,
|
||||
- .probe = ip17xx_probe,
|
||||
- .remove = ip17xx_remove,
|
||||
- .config_init = ip17xx_config_init,
|
||||
- .config_aneg = ip17xx_config_aneg,
|
||||
- .aneg_done = ip17xx_aneg_done,
|
||||
- .update_link = ip17xx_update_link,
|
||||
- .read_status = ip17xx_read_status,
|
||||
- }
|
||||
+static struct phy_driver ip17xx_driver = {
|
||||
+ .name = "IC+ IP17xx",
|
||||
+ .phy_id = 0x02430c00,
|
||||
+ .phy_id_mask = 0x0ffffc00,
|
||||
+ .features = PHY_BASIC_FEATURES,
|
||||
+ .probe = ip17xx_probe,
|
||||
+ .remove = ip17xx_remove,
|
||||
+ .config_init = ip17xx_config_init,
|
||||
+ .config_aneg = ip17xx_config_aneg,
|
||||
+ .aneg_done = ip17xx_aneg_done,
|
||||
+ .update_link = ip17xx_update_link,
|
||||
+ .read_status = ip17xx_read_status,
|
||||
+ .driver = { .owner = THIS_MODULE },
|
||||
};
|
||||
|
||||
-module_phy_driver(ip17xx_driver);
|
||||
+static struct phy_driver ip175a_driver = {
|
||||
+ .name = "IC+ IP175A",
|
||||
+ .phy_id = 0x02430c50,
|
||||
+ .phy_id_mask = 0x0ffffff0,
|
||||
+ .features = PHY_BASIC_FEATURES,
|
||||
+ .probe = ip17xx_probe,
|
||||
+ .remove = ip17xx_remove,
|
||||
+ .config_init = ip17xx_config_init,
|
||||
+ .config_aneg = ip17xx_config_aneg,
|
||||
+ .aneg_done = ip17xx_aneg_done,
|
||||
+ .update_link = ip17xx_update_link,
|
||||
+ .read_status = ip17xx_read_status,
|
||||
+ .driver = { .owner = THIS_MODULE },
|
||||
+};
|
||||
+
|
||||
+
|
||||
+int __init ip17xx_init(void)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = phy_driver_register(&ip175a_driver);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+
|
||||
+ return phy_driver_register(&ip17xx_driver);
|
||||
+}
|
||||
+
|
||||
+void __exit ip17xx_exit(void)
|
||||
+{
|
||||
+ phy_driver_unregister(&ip17xx_driver);
|
||||
+ phy_driver_unregister(&ip175a_driver);
|
||||
+}
|
||||
|
||||
MODULE_AUTHOR("Patrick Horn <patrick.horn@gmail.com>");
|
||||
MODULE_AUTHOR("Felix Fietkau <nbd@nbd.name>");
|
||||
MODULE_AUTHOR("Martin Mares <mj@ucw.cz>");
|
||||
MODULE_LICENSE("GPL");
|
||||
+
|
||||
+module_init(ip17xx_init);
|
||||
+module_exit(ip17xx_exit);
|
||||
--- a/drivers/net/phy/mvswitch.c
|
||||
+++ b/drivers/net/phy/mvswitch.c
|
||||
@@ -50,17 +50,13 @@ struct mvswitch_priv {
|
||||
static inline u16
|
||||
r16(struct phy_device *phydev, int addr, int reg)
|
||||
{
|
||||
- struct mii_bus *bus = phydev->mdio.bus;
|
||||
-
|
||||
- return bus->read(bus, addr, reg);
|
||||
+ return phydev->bus->read(phydev->bus, addr, reg);
|
||||
}
|
||||
|
||||
static inline void
|
||||
w16(struct phy_device *phydev, int addr, int reg, u16 val)
|
||||
{
|
||||
- struct mii_bus *bus = phydev->mdio.bus;
|
||||
-
|
||||
- bus->write(bus, addr, reg, val);
|
||||
+ phydev->bus->write(phydev->bus, addr, reg, val);
|
||||
}
|
||||
|
||||
|
||||
@@ -398,13 +394,12 @@ mvswitch_probe(struct phy_device *pdev)
|
||||
static int
|
||||
mvswitch_fixup(struct phy_device *dev)
|
||||
{
|
||||
- struct mii_bus *bus = dev->mdio.bus;
|
||||
u16 reg;
|
||||
|
||||
- if (dev->mdio.addr != 0x10)
|
||||
+ if (dev->addr != 0x10)
|
||||
return 0;
|
||||
|
||||
- reg = bus->read(bus, MV_PORTREG(IDENT, 0)) & MV_IDENT_MASK;
|
||||
+ reg = dev->bus->read(dev->bus, MV_PORTREG(IDENT, 0)) & MV_IDENT_MASK;
|
||||
if (reg != MV_IDENT_VALUE)
|
||||
return 0;
|
||||
|
||||
@@ -425,13 +420,14 @@ static struct phy_driver mvswitch_driver
|
||||
.config_aneg = &mvswitch_config_aneg,
|
||||
.aneg_done = &mvswitch_aneg_done,
|
||||
.read_status = &mvswitch_read_status,
|
||||
+ .driver = { .owner = THIS_MODULE,},
|
||||
};
|
||||
|
||||
static int __init
|
||||
mvswitch_init(void)
|
||||
{
|
||||
phy_register_fixup_for_id(PHY_ANY_ID, mvswitch_fixup);
|
||||
- return phy_driver_register(&mvswitch_driver, THIS_MODULE);
|
||||
+ return phy_driver_register(&mvswitch_driver);
|
||||
}
|
||||
|
||||
static void __exit
|
||||
--- a/drivers/net/phy/psb6970.c
|
||||
+++ b/drivers/net/phy/psb6970.c
|
||||
@@ -70,16 +70,12 @@ struct psb6970_priv {
|
||||
|
||||
static u16 psb6970_mii_read(struct phy_device *phydev, int reg)
|
||||
{
|
||||
- struct mii_bus *bus = phydev->mdio.bus;
|
||||
-
|
||||
- return bus->read(bus, PHYADDR(reg));
|
||||
+ return phydev->bus->read(phydev->bus, PHYADDR(reg));
|
||||
}
|
||||
|
||||
static void psb6970_mii_write(struct phy_device *phydev, int reg, u16 val)
|
||||
{
|
||||
- struct mii_bus *bus = phydev->mdio.bus;
|
||||
-
|
||||
- bus->write(bus, PHYADDR(reg), val);
|
||||
+ phydev->bus->write(phydev->bus, PHYADDR(reg), val);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -316,11 +312,11 @@ static int psb6970_config_init(struct ph
|
||||
|
||||
priv->phy = pdev;
|
||||
|
||||
- if (pdev->mdio.addr == 0)
|
||||
+ if (pdev->addr == 0)
|
||||
printk(KERN_INFO "%s: psb6970 switch driver attached.\n",
|
||||
pdev->attached_dev->name);
|
||||
|
||||
- if (pdev->mdio.addr != 0) {
|
||||
+ if (pdev->addr != 0) {
|
||||
kfree(priv);
|
||||
return 0;
|
||||
}
|
||||
@@ -388,14 +384,14 @@ static void psb6970_remove(struct phy_de
|
||||
if (!priv)
|
||||
return;
|
||||
|
||||
- if (pdev->mdio.addr == 0)
|
||||
+ if (pdev->addr == 0)
|
||||
unregister_switch(&priv->dev);
|
||||
kfree(priv);
|
||||
}
|
||||
|
||||
static int psb6970_fixup(struct phy_device *dev)
|
||||
{
|
||||
- struct mii_bus *bus = dev->mdio.bus;
|
||||
+ struct mii_bus *bus = dev->bus;
|
||||
u16 reg;
|
||||
|
||||
/* look for the switch on the bus */
|
||||
@@ -419,12 +415,13 @@ static struct phy_driver psb6970_driver
|
||||
.config_init = &psb6970_config_init,
|
||||
.config_aneg = &psb6970_config_aneg,
|
||||
.read_status = &psb6970_read_status,
|
||||
+ .driver = {.owner = THIS_MODULE},
|
||||
};
|
||||
|
||||
int __init psb6970_init(void)
|
||||
{
|
||||
phy_register_fixup_for_id(PHY_ANY_ID, psb6970_fixup);
|
||||
- return phy_driver_register(&psb6970_driver, THIS_MODULE);
|
||||
+ return phy_driver_register(&psb6970_driver);
|
||||
}
|
||||
|
||||
module_init(psb6970_init);
|
||||
--- a/drivers/net/phy/rtl8306.c
|
||||
+++ b/drivers/net/phy/rtl8306.c
|
||||
@@ -877,7 +877,7 @@ rtl8306_config_init(struct phy_device *p
|
||||
int err;
|
||||
|
||||
/* Only init the switch for the primary PHY */
|
||||
- if (pdev->mdio.addr != 0)
|
||||
+ if (pdev->addr != 0)
|
||||
return 0;
|
||||
|
||||
val.value.i = 1;
|
||||
@@ -887,7 +887,7 @@ rtl8306_config_init(struct phy_device *p
|
||||
priv->dev.ops = &rtl8306_ops;
|
||||
priv->do_cpu = 0;
|
||||
priv->page = -1;
|
||||
- priv->bus = pdev->mdio.bus;
|
||||
+ priv->bus = pdev->bus;
|
||||
|
||||
chipid = rtl_get(dev, RTL_REG_CHIPID);
|
||||
chipver = rtl_get(dev, RTL_REG_CHIPVER);
|
||||
@@ -933,13 +933,13 @@ rtl8306_fixup(struct phy_device *pdev)
|
||||
u16 chipid;
|
||||
|
||||
/* Attach to primary LAN port and WAN port */
|
||||
- if (pdev->mdio.addr != 0 && pdev->mdio.addr != 4)
|
||||
+ if (pdev->addr != 0 && pdev->addr != 4)
|
||||
return 0;
|
||||
|
||||
memset(&priv, 0, sizeof(priv));
|
||||
priv.fixup = true;
|
||||
priv.page = -1;
|
||||
- priv.bus = pdev->mdio.bus;
|
||||
+ priv.bus = pdev->bus;
|
||||
chipid = rtl_get(&priv.dev, RTL_REG_CHIPID);
|
||||
if (chipid == 0x5988)
|
||||
pdev->phy_id = RTL8306_MAGIC;
|
||||
@@ -957,14 +957,14 @@ rtl8306_probe(struct phy_device *pdev)
|
||||
* share one rtl_priv instance between virtual phy
|
||||
* devices on the same bus
|
||||
*/
|
||||
- if (priv->bus == pdev->mdio.bus)
|
||||
+ if (priv->bus == pdev->bus)
|
||||
goto found;
|
||||
}
|
||||
priv = kzalloc(sizeof(struct rtl_priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
- priv->bus = pdev->mdio.bus;
|
||||
+ priv->bus = pdev->bus;
|
||||
|
||||
found:
|
||||
pdev->priv = priv;
|
||||
@@ -985,7 +985,7 @@ rtl8306_config_aneg(struct phy_device *p
|
||||
struct rtl_priv *priv = pdev->priv;
|
||||
|
||||
/* Only for WAN */
|
||||
- if (pdev->mdio.addr == 0)
|
||||
+ if (pdev->addr == 0)
|
||||
return 0;
|
||||
|
||||
/* Restart autonegotiation */
|
||||
@@ -1001,7 +1001,7 @@ rtl8306_read_status(struct phy_device *p
|
||||
struct rtl_priv *priv = pdev->priv;
|
||||
struct switch_dev *dev = &priv->dev;
|
||||
|
||||
- if (pdev->mdio.addr == 4) {
|
||||
+ if (pdev->addr == 4) {
|
||||
/* WAN */
|
||||
pdev->speed = rtl_get(dev, RTL_PORT_REG(4, SPEED)) ? SPEED_100 : SPEED_10;
|
||||
pdev->duplex = rtl_get(dev, RTL_PORT_REG(4, DUPLEX)) ? DUPLEX_FULL : DUPLEX_HALF;
|
||||
@@ -1044,6 +1044,7 @@ static struct phy_driver rtl8306_driver
|
||||
.config_init = &rtl8306_config_init,
|
||||
.config_aneg = &rtl8306_config_aneg,
|
||||
.read_status = &rtl8306_read_status,
|
||||
+ .driver = { .owner = THIS_MODULE,},
|
||||
};
|
||||
|
||||
|
||||
@@ -1051,7 +1052,7 @@ static int __init
|
||||
rtl_init(void)
|
||||
{
|
||||
phy_register_fixup_for_id(PHY_ANY_ID, rtl8306_fixup);
|
||||
- return phy_driver_register(&rtl8306_driver, THIS_MODULE);
|
||||
+ return phy_driver_register(&rtl8306_driver);
|
||||
}
|
||||
|
||||
static void __exit
|
||||
--- a/drivers/net/phy/b53/b53_mdio.c
|
||||
+++ b/drivers/net/phy/b53/b53_mdio.c
|
||||
@@ -277,11 +277,11 @@ static int b53_phy_probe(struct phy_devi
|
||||
int ret;
|
||||
|
||||
/* allow the generic phy driver to take over */
|
||||
- if (phydev->mdio.addr != B53_PSEUDO_PHY && phydev->mdio.addr != 0)
|
||||
+ if (phydev->addr != B53_PSEUDO_PHY && phydev->addr != 0)
|
||||
return -ENODEV;
|
||||
|
||||
dev.current_page = 0xff;
|
||||
- dev.priv = phydev->mdio.bus;
|
||||
+ dev.priv = phydev->bus;
|
||||
dev.ops = &b53_mdio_ops;
|
||||
dev.pdata = NULL;
|
||||
mutex_init(&dev.reg_mutex);
|
||||
@@ -305,7 +305,7 @@ static int b53_phy_config_init(struct ph
|
||||
struct b53_device *dev;
|
||||
int ret;
|
||||
|
||||
- dev = b53_switch_alloc(&phydev->mdio.dev, &b53_mdio_ops, phydev->mdio.bus);
|
||||
+ dev = b53_switch_alloc(&phydev->dev, &b53_mdio_ops, phydev->bus);
|
||||
if (!dev)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -372,6 +372,9 @@ static struct phy_driver b53_phy_driver_
|
||||
.config_aneg = b53_phy_config_aneg,
|
||||
.config_init = b53_phy_config_init,
|
||||
.read_status = b53_phy_read_status,
|
||||
+ .driver = {
|
||||
+ .owner = THIS_MODULE,
|
||||
+ },
|
||||
};
|
||||
|
||||
/* BCM53125, BCM53128 */
|
||||
@@ -385,6 +388,9 @@ static struct phy_driver b53_phy_driver_
|
||||
.config_aneg = b53_phy_config_aneg,
|
||||
.config_init = b53_phy_config_init,
|
||||
.read_status = b53_phy_read_status,
|
||||
+ .driver = {
|
||||
+ .owner = THIS_MODULE,
|
||||
+ },
|
||||
};
|
||||
|
||||
/* BCM5365 */
|
||||
@@ -398,21 +404,24 @@ static struct phy_driver b53_phy_driver_
|
||||
.config_aneg = b53_phy_config_aneg,
|
||||
.config_init = b53_phy_config_init,
|
||||
.read_status = b53_phy_read_status,
|
||||
+ .driver = {
|
||||
+ .owner = THIS_MODULE,
|
||||
+ },
|
||||
};
|
||||
|
||||
int __init b53_phy_driver_register(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
- ret = phy_driver_register(&b53_phy_driver_id1, THIS_MODULE);
|
||||
+ ret = phy_driver_register(&b53_phy_driver_id1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
- ret = phy_driver_register(&b53_phy_driver_id2, THIS_MODULE);
|
||||
+ ret = phy_driver_register(&b53_phy_driver_id2);
|
||||
if (ret)
|
||||
goto err1;
|
||||
|
||||
- ret = phy_driver_register(&b53_phy_driver_id3, THIS_MODULE);
|
||||
+ ret = phy_driver_register(&b53_phy_driver_id3);
|
||||
if (!ret)
|
||||
return 0;
|
||||
|
||||
--- a/drivers/net/phy/b53/b53_phy_fixup.c
|
||||
+++ b/drivers/net/phy/b53/b53_phy_fixup.c
|
||||
@@ -28,10 +28,10 @@
|
||||
|
||||
static int b53_phy_fixup(struct phy_device *dev)
|
||||
{
|
||||
- struct mii_bus *bus = dev->mdio.bus;
|
||||
u32 phy_id;
|
||||
+ struct mii_bus *bus = dev->bus;
|
||||
|
||||
- if (dev->mdio.addr != B53_PSEUDO_PHY)
|
||||
+ if (dev->addr != B53_PSEUDO_PHY)
|
||||
return 0;
|
||||
|
||||
/* read the first port's id */
|
@ -1,11 +0,0 @@
|
||||
--- a/drivers/mtd/myloader.c
|
||||
+++ b/drivers/mtd/myloader.c
|
||||
@@ -33,7 +33,7 @@ struct part_data {
|
||||
};
|
||||
|
||||
static int myloader_parse_partitions(struct mtd_info *master,
|
||||
- const struct mtd_partition **pparts,
|
||||
+ struct mtd_partition **pparts,
|
||||
struct mtd_part_parser_data *data)
|
||||
{
|
||||
struct part_data *buf;
|
@ -1,24 +0,0 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Mon, 18 Jan 2016 12:27:49 +0100
|
||||
Subject: [PATCH] Kbuild: don't hardcode path to awk in scripts/ld-version.sh
|
||||
|
||||
On some systems /usr/bin/awk does not exist, or is broken. Find it via
|
||||
$PATH instead.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/scripts/ld-version.sh
|
||||
+++ b/scripts/ld-version.sh
|
||||
@@ -1,8 +1,10 @@
|
||||
-#!/usr/bin/awk -f
|
||||
+#!/bin/sh
|
||||
# extract linker version number from stdin and turn into single number
|
||||
+exec awk '
|
||||
{
|
||||
gsub(".*\\)", "");
|
||||
split($1,a, ".");
|
||||
print a[1]*10000000 + a[2]*100000 + a[3]*10000 + a[4]*100 + a[5];
|
||||
exit
|
||||
}
|
||||
+'
|
@ -1,49 +0,0 @@
|
||||
--- a/drivers/bcma/main.c
|
||||
+++ b/drivers/bcma/main.c
|
||||
@@ -672,11 +672,36 @@ static int bcma_device_uevent(struct dev
|
||||
core->id.rev, core->id.class);
|
||||
}
|
||||
|
||||
-static int __init bcma_modinit(void)
|
||||
+static unsigned int bcma_bus_registered;
|
||||
+
|
||||
+/*
|
||||
+ * If built-in, bus has to be registered early, before any driver calls
|
||||
+ * bcma_driver_register.
|
||||
+ * Otherwise registering driver would trigger BUG in driver_register.
|
||||
+ */
|
||||
+static int __init bcma_init_bus_register(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
+ if (bcma_bus_registered)
|
||||
+ return 0;
|
||||
+
|
||||
err = bus_register(&bcma_bus_type);
|
||||
+ if (!err)
|
||||
+ bcma_bus_registered = 1;
|
||||
+
|
||||
+ return err;
|
||||
+}
|
||||
+#ifndef MODULE
|
||||
+fs_initcall(bcma_init_bus_register);
|
||||
+#endif
|
||||
+
|
||||
+/* Main initialization has to be done with SPI/mtd/NAND/SPROM available */
|
||||
+static int __init bcma_modinit(void)
|
||||
+{
|
||||
+ int err;
|
||||
+
|
||||
+ err = bcma_init_bus_register();
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@@ -695,7 +720,7 @@ static int __init bcma_modinit(void)
|
||||
|
||||
return err;
|
||||
}
|
||||
-fs_initcall(bcma_modinit);
|
||||
+module_init(bcma_modinit);
|
||||
|
||||
static void __exit bcma_modexit(void)
|
||||
{
|
@ -1,761 +0,0 @@
|
||||
--- a/drivers/bcma/driver_chipcommon.c
|
||||
+++ b/drivers/bcma/driver_chipcommon.c
|
||||
@@ -15,6 +15,8 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/bcma/bcma.h>
|
||||
|
||||
+static void bcma_chipco_serial_init(struct bcma_drv_cc *cc);
|
||||
+
|
||||
static inline u32 bcma_cc_write32_masked(struct bcma_drv_cc *cc, u16 offset,
|
||||
u32 mask, u32 value)
|
||||
{
|
||||
@@ -113,8 +115,37 @@ int bcma_chipco_watchdog_register(struct
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static void bcma_core_chipcommon_flash_detect(struct bcma_drv_cc *cc)
|
||||
+{
|
||||
+ struct bcma_bus *bus = cc->core->bus;
|
||||
+
|
||||
+ switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
|
||||
+ case BCMA_CC_FLASHT_STSER:
|
||||
+ case BCMA_CC_FLASHT_ATSER:
|
||||
+ bcma_debug(bus, "Found serial flash\n");
|
||||
+ bcma_sflash_init(cc);
|
||||
+ break;
|
||||
+ case BCMA_CC_FLASHT_PARA:
|
||||
+ bcma_debug(bus, "Found parallel flash\n");
|
||||
+ bcma_pflash_init(cc);
|
||||
+ break;
|
||||
+ default:
|
||||
+ bcma_err(bus, "Flash type not supported\n");
|
||||
+ }
|
||||
+
|
||||
+ if (cc->core->id.rev == 38 ||
|
||||
+ bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) {
|
||||
+ if (cc->capabilities & BCMA_CC_CAP_NFLASH) {
|
||||
+ bcma_debug(bus, "Found NAND flash\n");
|
||||
+ bcma_nflash_init(cc);
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc)
|
||||
{
|
||||
+ struct bcma_bus *bus = cc->core->bus;
|
||||
+
|
||||
if (cc->early_setup_done)
|
||||
return;
|
||||
|
||||
@@ -129,6 +160,12 @@ void bcma_core_chipcommon_early_init(str
|
||||
if (cc->capabilities & BCMA_CC_CAP_PMU)
|
||||
bcma_pmu_early_init(cc);
|
||||
|
||||
+ if (IS_BUILTIN(CONFIG_BCM47XX) && bus->hosttype == BCMA_HOSTTYPE_SOC)
|
||||
+ bcma_chipco_serial_init(cc);
|
||||
+
|
||||
+ if (bus->hosttype == BCMA_HOSTTYPE_SOC)
|
||||
+ bcma_core_chipcommon_flash_detect(cc);
|
||||
+
|
||||
cc->early_setup_done = true;
|
||||
}
|
||||
|
||||
@@ -185,11 +222,12 @@ u32 bcma_chipco_watchdog_timer_set(struc
|
||||
ticks = 2;
|
||||
else if (ticks > maxt)
|
||||
ticks = maxt;
|
||||
- bcma_cc_write32(cc, BCMA_CC_PMU_WATCHDOG, ticks);
|
||||
+ bcma_pmu_write32(cc, BCMA_CC_PMU_WATCHDOG, ticks);
|
||||
} else {
|
||||
struct bcma_bus *bus = cc->core->bus;
|
||||
|
||||
if (bus->chipinfo.id != BCMA_CHIP_ID_BCM4707 &&
|
||||
+ bus->chipinfo.id != BCMA_CHIP_ID_BCM47094 &&
|
||||
bus->chipinfo.id != BCMA_CHIP_ID_BCM53018)
|
||||
bcma_core_set_clockmode(cc->core,
|
||||
ticks ? BCMA_CLKMODE_FAST : BCMA_CLKMODE_DYNAMIC);
|
||||
@@ -314,9 +352,9 @@ u32 bcma_chipco_gpio_pulldown(struct bcm
|
||||
return res;
|
||||
}
|
||||
|
||||
-#ifdef CONFIG_BCMA_DRIVER_MIPS
|
||||
-void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
|
||||
+static void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
|
||||
{
|
||||
+#if IS_BUILTIN(CONFIG_BCM47XX)
|
||||
unsigned int irq;
|
||||
u32 baud_base;
|
||||
u32 i;
|
||||
@@ -358,5 +396,5 @@ void bcma_chipco_serial_init(struct bcma
|
||||
ports[i].baud_base = baud_base;
|
||||
ports[i].reg_shift = 0;
|
||||
}
|
||||
+#endif /* CONFIG_BCM47XX */
|
||||
}
|
||||
-#endif /* CONFIG_BCMA_DRIVER_MIPS */
|
||||
--- a/drivers/bcma/driver_chipcommon_pmu.c
|
||||
+++ b/drivers/bcma/driver_chipcommon_pmu.c
|
||||
@@ -15,44 +15,44 @@
|
||||
|
||||
u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset)
|
||||
{
|
||||
- bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
|
||||
- bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
|
||||
- return bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA);
|
||||
+ bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR, offset);
|
||||
+ bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_ADDR);
|
||||
+ return bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_DATA);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bcma_chipco_pll_read);
|
||||
|
||||
void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset, u32 value)
|
||||
{
|
||||
- bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
|
||||
- bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
|
||||
- bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, value);
|
||||
+ bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR, offset);
|
||||
+ bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_ADDR);
|
||||
+ bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_DATA, value);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bcma_chipco_pll_write);
|
||||
|
||||
void bcma_chipco_pll_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask,
|
||||
u32 set)
|
||||
{
|
||||
- bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
|
||||
- bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
|
||||
- bcma_cc_maskset32(cc, BCMA_CC_PLLCTL_DATA, mask, set);
|
||||
+ bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR, offset);
|
||||
+ bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_ADDR);
|
||||
+ bcma_pmu_maskset32(cc, BCMA_CC_PMU_PLLCTL_DATA, mask, set);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bcma_chipco_pll_maskset);
|
||||
|
||||
void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
|
||||
u32 offset, u32 mask, u32 set)
|
||||
{
|
||||
- bcma_cc_write32(cc, BCMA_CC_CHIPCTL_ADDR, offset);
|
||||
- bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR);
|
||||
- bcma_cc_maskset32(cc, BCMA_CC_CHIPCTL_DATA, mask, set);
|
||||
+ bcma_pmu_write32(cc, BCMA_CC_PMU_CHIPCTL_ADDR, offset);
|
||||
+ bcma_pmu_read32(cc, BCMA_CC_PMU_CHIPCTL_ADDR);
|
||||
+ bcma_pmu_maskset32(cc, BCMA_CC_PMU_CHIPCTL_DATA, mask, set);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bcma_chipco_chipctl_maskset);
|
||||
|
||||
void bcma_chipco_regctl_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask,
|
||||
u32 set)
|
||||
{
|
||||
- bcma_cc_write32(cc, BCMA_CC_REGCTL_ADDR, offset);
|
||||
- bcma_cc_read32(cc, BCMA_CC_REGCTL_ADDR);
|
||||
- bcma_cc_maskset32(cc, BCMA_CC_REGCTL_DATA, mask, set);
|
||||
+ bcma_pmu_write32(cc, BCMA_CC_PMU_REGCTL_ADDR, offset);
|
||||
+ bcma_pmu_read32(cc, BCMA_CC_PMU_REGCTL_ADDR);
|
||||
+ bcma_pmu_maskset32(cc, BCMA_CC_PMU_REGCTL_DATA, mask, set);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bcma_chipco_regctl_maskset);
|
||||
|
||||
@@ -60,18 +60,18 @@ static u32 bcma_pmu_xtalfreq(struct bcma
|
||||
{
|
||||
u32 ilp_ctl, alp_hz;
|
||||
|
||||
- if (!(bcma_cc_read32(cc, BCMA_CC_PMU_STAT) &
|
||||
+ if (!(bcma_pmu_read32(cc, BCMA_CC_PMU_STAT) &
|
||||
BCMA_CC_PMU_STAT_EXT_LPO_AVAIL))
|
||||
return 0;
|
||||
|
||||
- bcma_cc_write32(cc, BCMA_CC_PMU_XTAL_FREQ,
|
||||
- BIT(BCMA_CC_PMU_XTAL_FREQ_MEASURE_SHIFT));
|
||||
+ bcma_pmu_write32(cc, BCMA_CC_PMU_XTAL_FREQ,
|
||||
+ BIT(BCMA_CC_PMU_XTAL_FREQ_MEASURE_SHIFT));
|
||||
usleep_range(1000, 2000);
|
||||
|
||||
- ilp_ctl = bcma_cc_read32(cc, BCMA_CC_PMU_XTAL_FREQ);
|
||||
+ ilp_ctl = bcma_pmu_read32(cc, BCMA_CC_PMU_XTAL_FREQ);
|
||||
ilp_ctl &= BCMA_CC_PMU_XTAL_FREQ_ILPCTL_MASK;
|
||||
|
||||
- bcma_cc_write32(cc, BCMA_CC_PMU_XTAL_FREQ, 0);
|
||||
+ bcma_pmu_write32(cc, BCMA_CC_PMU_XTAL_FREQ, 0);
|
||||
|
||||
alp_hz = ilp_ctl * 32768 / 4;
|
||||
return (alp_hz + 50000) / 100000 * 100;
|
||||
@@ -127,8 +127,8 @@ static void bcma_pmu2_pll_init0(struct b
|
||||
mask = (u32)~(BCMA_RES_4314_HT_AVAIL |
|
||||
BCMA_RES_4314_MACPHY_CLK_AVAIL);
|
||||
|
||||
- bcma_cc_mask32(cc, BCMA_CC_PMU_MINRES_MSK, mask);
|
||||
- bcma_cc_mask32(cc, BCMA_CC_PMU_MAXRES_MSK, mask);
|
||||
+ bcma_pmu_mask32(cc, BCMA_CC_PMU_MINRES_MSK, mask);
|
||||
+ bcma_pmu_mask32(cc, BCMA_CC_PMU_MAXRES_MSK, mask);
|
||||
bcma_wait_value(cc->core, BCMA_CLKCTLST,
|
||||
BCMA_CLKCTLST_HAVEHT, 0, 20000);
|
||||
break;
|
||||
@@ -140,7 +140,7 @@ static void bcma_pmu2_pll_init0(struct b
|
||||
|
||||
/* Flush */
|
||||
if (cc->pmu.rev >= 2)
|
||||
- bcma_cc_set32(cc, BCMA_CC_PMU_CTL, BCMA_CC_PMU_CTL_PLL_UPD);
|
||||
+ bcma_pmu_set32(cc, BCMA_CC_PMU_CTL, BCMA_CC_PMU_CTL_PLL_UPD);
|
||||
|
||||
/* TODO: Do we need to update OTP? */
|
||||
}
|
||||
@@ -195,9 +195,9 @@ static void bcma_pmu_resources_init(stru
|
||||
|
||||
/* Set the resource masks. */
|
||||
if (min_msk)
|
||||
- bcma_cc_write32(cc, BCMA_CC_PMU_MINRES_MSK, min_msk);
|
||||
+ bcma_pmu_write32(cc, BCMA_CC_PMU_MINRES_MSK, min_msk);
|
||||
if (max_msk)
|
||||
- bcma_cc_write32(cc, BCMA_CC_PMU_MAXRES_MSK, max_msk);
|
||||
+ bcma_pmu_write32(cc, BCMA_CC_PMU_MAXRES_MSK, max_msk);
|
||||
|
||||
/*
|
||||
* Add some delay; allow resources to come up and settle.
|
||||
@@ -269,23 +269,33 @@ static void bcma_pmu_workarounds(struct
|
||||
|
||||
void bcma_pmu_early_init(struct bcma_drv_cc *cc)
|
||||
{
|
||||
+ struct bcma_bus *bus = cc->core->bus;
|
||||
u32 pmucap;
|
||||
|
||||
- pmucap = bcma_cc_read32(cc, BCMA_CC_PMU_CAP);
|
||||
+ if (cc->core->id.rev >= 35 &&
|
||||
+ cc->capabilities_ext & BCMA_CC_CAP_EXT_AOB_PRESENT) {
|
||||
+ cc->pmu.core = bcma_find_core(bus, BCMA_CORE_PMU);
|
||||
+ if (!cc->pmu.core)
|
||||
+ bcma_warn(bus, "Couldn't find expected PMU core");
|
||||
+ }
|
||||
+ if (!cc->pmu.core)
|
||||
+ cc->pmu.core = cc->core;
|
||||
+
|
||||
+ pmucap = bcma_pmu_read32(cc, BCMA_CC_PMU_CAP);
|
||||
cc->pmu.rev = (pmucap & BCMA_CC_PMU_CAP_REVISION);
|
||||
|
||||
- bcma_debug(cc->core->bus, "Found rev %u PMU (capabilities 0x%08X)\n",
|
||||
- cc->pmu.rev, pmucap);
|
||||
+ bcma_debug(bus, "Found rev %u PMU (capabilities 0x%08X)\n", cc->pmu.rev,
|
||||
+ pmucap);
|
||||
}
|
||||
|
||||
void bcma_pmu_init(struct bcma_drv_cc *cc)
|
||||
{
|
||||
if (cc->pmu.rev == 1)
|
||||
- bcma_cc_mask32(cc, BCMA_CC_PMU_CTL,
|
||||
- ~BCMA_CC_PMU_CTL_NOILPONW);
|
||||
+ bcma_pmu_mask32(cc, BCMA_CC_PMU_CTL,
|
||||
+ ~BCMA_CC_PMU_CTL_NOILPONW);
|
||||
else
|
||||
- bcma_cc_set32(cc, BCMA_CC_PMU_CTL,
|
||||
- BCMA_CC_PMU_CTL_NOILPONW);
|
||||
+ bcma_pmu_set32(cc, BCMA_CC_PMU_CTL,
|
||||
+ BCMA_CC_PMU_CTL_NOILPONW);
|
||||
|
||||
bcma_pmu_pll_init(cc);
|
||||
bcma_pmu_resources_init(cc);
|
||||
@@ -472,8 +482,8 @@ u32 bcma_pmu_get_cpu_clock(struct bcma_d
|
||||
static void bcma_pmu_spuravoid_pll_write(struct bcma_drv_cc *cc, u32 offset,
|
||||
u32 value)
|
||||
{
|
||||
- bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
|
||||
- bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, value);
|
||||
+ bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR, offset);
|
||||
+ bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_DATA, value);
|
||||
}
|
||||
|
||||
void bcma_pmu_spuravoid_pllupdate(struct bcma_drv_cc *cc, int spuravoid)
|
||||
@@ -497,20 +507,20 @@ void bcma_pmu_spuravoid_pllupdate(struct
|
||||
bus->chipinfo.id == BCMA_CHIP_ID_BCM53572) ? 6 : 0;
|
||||
|
||||
/* RMW only the P1 divider */
|
||||
- bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR,
|
||||
+ bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR,
|
||||
BCMA_CC_PMU_PLL_CTL0 + phypll_offset);
|
||||
- tmp = bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA);
|
||||
+ tmp = bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_DATA);
|
||||
tmp &= (~(BCMA_CC_PMU1_PLL0_PC0_P1DIV_MASK));
|
||||
tmp |= (bcm5357_bcm43236_p1div[spuravoid] << BCMA_CC_PMU1_PLL0_PC0_P1DIV_SHIFT);
|
||||
- bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, tmp);
|
||||
+ bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_DATA, tmp);
|
||||
|
||||
/* RMW only the int feedback divider */
|
||||
- bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR,
|
||||
+ bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR,
|
||||
BCMA_CC_PMU_PLL_CTL2 + phypll_offset);
|
||||
- tmp = bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA);
|
||||
+ tmp = bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_DATA);
|
||||
tmp &= ~(BCMA_CC_PMU1_PLL0_PC2_NDIV_INT_MASK);
|
||||
tmp |= (bcm5357_bcm43236_ndiv[spuravoid]) << BCMA_CC_PMU1_PLL0_PC2_NDIV_INT_SHIFT;
|
||||
- bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, tmp);
|
||||
+ bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_DATA, tmp);
|
||||
|
||||
tmp = BCMA_CC_PMU_CTL_PLL_UPD;
|
||||
break;
|
||||
@@ -646,7 +656,7 @@ void bcma_pmu_spuravoid_pllupdate(struct
|
||||
break;
|
||||
}
|
||||
|
||||
- tmp |= bcma_cc_read32(cc, BCMA_CC_PMU_CTL);
|
||||
- bcma_cc_write32(cc, BCMA_CC_PMU_CTL, tmp);
|
||||
+ tmp |= bcma_pmu_read32(cc, BCMA_CC_PMU_CTL);
|
||||
+ bcma_pmu_write32(cc, BCMA_CC_PMU_CTL, tmp);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bcma_pmu_spuravoid_pllupdate);
|
||||
--- a/drivers/bcma/driver_chipcommon_sflash.c
|
||||
+++ b/drivers/bcma/driver_chipcommon_sflash.c
|
||||
@@ -38,6 +38,7 @@ static const struct bcma_sflash_tbl_e bc
|
||||
{ "M25P32", 0x15, 0x10000, 64, },
|
||||
{ "M25P64", 0x16, 0x10000, 128, },
|
||||
{ "M25FL128", 0x17, 0x10000, 256, },
|
||||
+ { "MX25L25635F", 0x18, 0x10000, 512, },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
--- a/drivers/bcma/scan.c
|
||||
+++ b/drivers/bcma/scan.c
|
||||
@@ -98,6 +98,9 @@ static const struct bcma_device_id_name
|
||||
{ BCMA_CORE_SHIM, "SHIM" },
|
||||
{ BCMA_CORE_PCIE2, "PCIe Gen2" },
|
||||
{ BCMA_CORE_ARM_CR4, "ARM CR4" },
|
||||
+ { BCMA_CORE_GCI, "GCI" },
|
||||
+ { BCMA_CORE_CMEM, "CNDS DDR2/3 memory controller" },
|
||||
+ { BCMA_CORE_ARM_CA7, "ARM CA7" },
|
||||
{ BCMA_CORE_DEFAULT, "Default" },
|
||||
};
|
||||
|
||||
@@ -315,6 +318,8 @@ static int bcma_get_next_core(struct bcm
|
||||
switch (core->id.id) {
|
||||
case BCMA_CORE_4706_MAC_GBIT_COMMON:
|
||||
case BCMA_CORE_NS_CHIPCOMMON_B:
|
||||
+ case BCMA_CORE_PMU:
|
||||
+ case BCMA_CORE_GCI:
|
||||
/* Not used yet: case BCMA_CORE_OOB_ROUTER: */
|
||||
break;
|
||||
default:
|
||||
--- a/drivers/net/wireless/b43/main.c
|
||||
+++ b/drivers/net/wireless/b43/main.c
|
||||
@@ -1215,10 +1215,10 @@ void b43_wireless_core_phy_pll_reset(str
|
||||
case B43_BUS_BCMA:
|
||||
bcma_cc = &dev->dev->bdev->bus->drv_cc;
|
||||
|
||||
- bcma_cc_write32(bcma_cc, BCMA_CC_CHIPCTL_ADDR, 0);
|
||||
- bcma_cc_mask32(bcma_cc, BCMA_CC_CHIPCTL_DATA, ~0x4);
|
||||
- bcma_cc_set32(bcma_cc, BCMA_CC_CHIPCTL_DATA, 0x4);
|
||||
- bcma_cc_mask32(bcma_cc, BCMA_CC_CHIPCTL_DATA, ~0x4);
|
||||
+ bcma_cc_write32(bcma_cc, BCMA_CC_PMU_CHIPCTL_ADDR, 0);
|
||||
+ bcma_cc_mask32(bcma_cc, BCMA_CC_PMU_CHIPCTL_DATA, ~0x4);
|
||||
+ bcma_cc_set32(bcma_cc, BCMA_CC_PMU_CHIPCTL_DATA, 0x4);
|
||||
+ bcma_cc_mask32(bcma_cc, BCMA_CC_PMU_CHIPCTL_DATA, ~0x4);
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_B43_SSB
|
||||
--- a/include/linux/bcma/bcma.h
|
||||
+++ b/include/linux/bcma/bcma.h
|
||||
@@ -151,6 +151,8 @@ struct bcma_host_ops {
|
||||
#define BCMA_CORE_PCIE2 0x83C /* PCI Express Gen2 */
|
||||
#define BCMA_CORE_USB30_DEV 0x83D
|
||||
#define BCMA_CORE_ARM_CR4 0x83E
|
||||
+#define BCMA_CORE_GCI 0x840
|
||||
+#define BCMA_CORE_CMEM 0x846 /* CNDS DDR2/3 memory controller */
|
||||
#define BCMA_CORE_ARM_CA7 0x847
|
||||
#define BCMA_CORE_SYS_MEM 0x849
|
||||
#define BCMA_CORE_DEFAULT 0xFFF
|
||||
@@ -200,6 +202,7 @@ struct bcma_host_ops {
|
||||
#define BCMA_PKG_ID_BCM4707 1
|
||||
#define BCMA_PKG_ID_BCM4708 2
|
||||
#define BCMA_PKG_ID_BCM4709 0
|
||||
+#define BCMA_CHIP_ID_BCM47094 53030
|
||||
#define BCMA_CHIP_ID_BCM53018 53018
|
||||
|
||||
/* Board types (on PCI usually equals to the subsystem dev id) */
|
||||
--- a/include/linux/bcma/bcma_driver_chipcommon.h
|
||||
+++ b/include/linux/bcma/bcma_driver_chipcommon.h
|
||||
@@ -217,6 +217,11 @@
|
||||
#define BCMA_CC_CLKDIV_JTAG_SHIFT 8
|
||||
#define BCMA_CC_CLKDIV_UART 0x000000FF
|
||||
#define BCMA_CC_CAP_EXT 0x00AC /* Capabilities */
|
||||
+#define BCMA_CC_CAP_EXT_SECI_PRESENT 0x00000001
|
||||
+#define BCMA_CC_CAP_EXT_GSIO_PRESENT 0x00000002
|
||||
+#define BCMA_CC_CAP_EXT_GCI_PRESENT 0x00000004
|
||||
+#define BCMA_CC_CAP_EXT_SECI_PUART_PRESENT 0x00000008 /* UART present */
|
||||
+#define BCMA_CC_CAP_EXT_AOB_PRESENT 0x00000040
|
||||
#define BCMA_CC_PLLONDELAY 0x00B0 /* Rev >= 4 only */
|
||||
#define BCMA_CC_FREFSELDELAY 0x00B4 /* Rev >= 4 only */
|
||||
#define BCMA_CC_SLOWCLKCTL 0x00B8 /* 6 <= Rev <= 9 only */
|
||||
@@ -351,12 +356,12 @@
|
||||
#define BCMA_CC_PMU_RES_REQTS 0x0640 /* PMU res req timer sel */
|
||||
#define BCMA_CC_PMU_RES_REQT 0x0644 /* PMU res req timer */
|
||||
#define BCMA_CC_PMU_RES_REQM 0x0648 /* PMU res req mask */
|
||||
-#define BCMA_CC_CHIPCTL_ADDR 0x0650
|
||||
-#define BCMA_CC_CHIPCTL_DATA 0x0654
|
||||
-#define BCMA_CC_REGCTL_ADDR 0x0658
|
||||
-#define BCMA_CC_REGCTL_DATA 0x065C
|
||||
-#define BCMA_CC_PLLCTL_ADDR 0x0660
|
||||
-#define BCMA_CC_PLLCTL_DATA 0x0664
|
||||
+#define BCMA_CC_PMU_CHIPCTL_ADDR 0x0650
|
||||
+#define BCMA_CC_PMU_CHIPCTL_DATA 0x0654
|
||||
+#define BCMA_CC_PMU_REGCTL_ADDR 0x0658
|
||||
+#define BCMA_CC_PMU_REGCTL_DATA 0x065C
|
||||
+#define BCMA_CC_PMU_PLLCTL_ADDR 0x0660
|
||||
+#define BCMA_CC_PMU_PLLCTL_DATA 0x0664
|
||||
#define BCMA_CC_PMU_STRAPOPT 0x0668 /* (corerev >= 28) */
|
||||
#define BCMA_CC_PMU_XTAL_FREQ 0x066C /* (pmurev >= 10) */
|
||||
#define BCMA_CC_PMU_XTAL_FREQ_ILPCTL_MASK 0x00001FFF
|
||||
@@ -566,17 +571,16 @@
|
||||
* Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU)
|
||||
*/
|
||||
struct bcma_chipcommon_pmu {
|
||||
+ struct bcma_device *core; /* Can be separated core or just ChipCommon one */
|
||||
u8 rev; /* PMU revision */
|
||||
u32 crystalfreq; /* The active crystal frequency (in kHz) */
|
||||
};
|
||||
|
||||
-#ifdef CONFIG_BCMA_DRIVER_MIPS
|
||||
+#ifdef CONFIG_BCMA_PFLASH
|
||||
struct bcma_pflash {
|
||||
bool present;
|
||||
- u8 buswidth;
|
||||
- u32 window;
|
||||
- u32 window_size;
|
||||
};
|
||||
+#endif
|
||||
|
||||
#ifdef CONFIG_BCMA_SFLASH
|
||||
struct bcma_sflash {
|
||||
@@ -602,6 +606,7 @@ struct bcma_nflash {
|
||||
};
|
||||
#endif
|
||||
|
||||
+#ifdef CONFIG_BCMA_DRIVER_MIPS
|
||||
struct bcma_serial_port {
|
||||
void *regs;
|
||||
unsigned long clockspeed;
|
||||
@@ -621,8 +626,9 @@ struct bcma_drv_cc {
|
||||
/* Fast Powerup Delay constant */
|
||||
u16 fast_pwrup_delay;
|
||||
struct bcma_chipcommon_pmu pmu;
|
||||
-#ifdef CONFIG_BCMA_DRIVER_MIPS
|
||||
+#ifdef CONFIG_BCMA_PFLASH
|
||||
struct bcma_pflash pflash;
|
||||
+#endif
|
||||
#ifdef CONFIG_BCMA_SFLASH
|
||||
struct bcma_sflash sflash;
|
||||
#endif
|
||||
@@ -630,6 +636,7 @@ struct bcma_drv_cc {
|
||||
struct bcma_nflash nflash;
|
||||
#endif
|
||||
|
||||
+#ifdef CONFIG_BCMA_DRIVER_MIPS
|
||||
int nr_serial_ports;
|
||||
struct bcma_serial_port serial_ports[4];
|
||||
#endif /* CONFIG_BCMA_DRIVER_MIPS */
|
||||
@@ -662,6 +669,19 @@ struct bcma_drv_cc_b {
|
||||
#define bcma_cc_maskset32(cc, offset, mask, set) \
|
||||
bcma_cc_write32(cc, offset, (bcma_cc_read32(cc, offset) & (mask)) | (set))
|
||||
|
||||
+/* PMU registers access */
|
||||
+#define bcma_pmu_read32(cc, offset) \
|
||||
+ bcma_read32((cc)->pmu.core, offset)
|
||||
+#define bcma_pmu_write32(cc, offset, val) \
|
||||
+ bcma_write32((cc)->pmu.core, offset, val)
|
||||
+
|
||||
+#define bcma_pmu_mask32(cc, offset, mask) \
|
||||
+ bcma_pmu_write32(cc, offset, bcma_pmu_read32(cc, offset) & (mask))
|
||||
+#define bcma_pmu_set32(cc, offset, set) \
|
||||
+ bcma_pmu_write32(cc, offset, bcma_pmu_read32(cc, offset) | (set))
|
||||
+#define bcma_pmu_maskset32(cc, offset, mask, set) \
|
||||
+ bcma_pmu_write32(cc, offset, (bcma_pmu_read32(cc, offset) & (mask)) | (set))
|
||||
+
|
||||
extern u32 bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks);
|
||||
|
||||
extern u32 bcma_chipco_get_alp_clock(struct bcma_drv_cc *cc);
|
||||
--- a/drivers/bcma/bcma_private.h
|
||||
+++ b/drivers/bcma/bcma_private.h
|
||||
@@ -45,10 +45,6 @@ int bcma_sprom_get(struct bcma_bus *bus)
|
||||
void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc);
|
||||
void bcma_core_chipcommon_init(struct bcma_drv_cc *cc);
|
||||
void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable);
|
||||
-#ifdef CONFIG_BCMA_DRIVER_MIPS
|
||||
-void bcma_chipco_serial_init(struct bcma_drv_cc *cc);
|
||||
-extern struct platform_device bcma_pflash_dev;
|
||||
-#endif /* CONFIG_BCMA_DRIVER_MIPS */
|
||||
|
||||
/* driver_chipcommon_b.c */
|
||||
int bcma_core_chipcommon_b_init(struct bcma_drv_cc_b *ccb);
|
||||
@@ -60,6 +56,21 @@ void bcma_pmu_init(struct bcma_drv_cc *c
|
||||
u32 bcma_pmu_get_alp_clock(struct bcma_drv_cc *cc);
|
||||
u32 bcma_pmu_get_cpu_clock(struct bcma_drv_cc *cc);
|
||||
|
||||
+/**************************************************
|
||||
+ * driver_chipcommon_sflash.c
|
||||
+ **************************************************/
|
||||
+
|
||||
+#ifdef CONFIG_BCMA_PFLASH
|
||||
+extern struct platform_device bcma_pflash_dev;
|
||||
+int bcma_pflash_init(struct bcma_drv_cc *cc);
|
||||
+#else
|
||||
+static inline int bcma_pflash_init(struct bcma_drv_cc *cc)
|
||||
+{
|
||||
+ bcma_err(cc->core->bus, "Parallel flash not supported\n");
|
||||
+ return 0;
|
||||
+}
|
||||
+#endif /* CONFIG_BCMA_PFLASH */
|
||||
+
|
||||
#ifdef CONFIG_BCMA_SFLASH
|
||||
/* driver_chipcommon_sflash.c */
|
||||
int bcma_sflash_init(struct bcma_drv_cc *cc);
|
||||
--- a/drivers/bcma/driver_gpio.c
|
||||
+++ b/drivers/bcma/driver_gpio.c
|
||||
@@ -197,6 +197,7 @@ int bcma_gpio_init(struct bcma_drv_cc *c
|
||||
case BCMA_CHIP_ID_BCM4707:
|
||||
case BCMA_CHIP_ID_BCM5357:
|
||||
case BCMA_CHIP_ID_BCM53572:
|
||||
+ case BCMA_CHIP_ID_BCM47094:
|
||||
chip->ngpio = 32;
|
||||
break;
|
||||
default:
|
||||
--- a/drivers/bcma/driver_mips.c
|
||||
+++ b/drivers/bcma/driver_mips.c
|
||||
@@ -14,8 +14,6 @@
|
||||
|
||||
#include <linux/bcma/bcma.h>
|
||||
|
||||
-#include <linux/mtd/physmap.h>
|
||||
-#include <linux/platform_device.h>
|
||||
#include <linux/serial.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/serial_reg.h>
|
||||
@@ -32,26 +30,6 @@ enum bcma_boot_dev {
|
||||
BCMA_BOOT_DEV_NAND,
|
||||
};
|
||||
|
||||
-static const char * const part_probes[] = { "bcm47xxpart", NULL };
|
||||
-
|
||||
-static struct physmap_flash_data bcma_pflash_data = {
|
||||
- .part_probe_types = part_probes,
|
||||
-};
|
||||
-
|
||||
-static struct resource bcma_pflash_resource = {
|
||||
- .name = "bcma_pflash",
|
||||
- .flags = IORESOURCE_MEM,
|
||||
-};
|
||||
-
|
||||
-struct platform_device bcma_pflash_dev = {
|
||||
- .name = "physmap-flash",
|
||||
- .dev = {
|
||||
- .platform_data = &bcma_pflash_data,
|
||||
- },
|
||||
- .resource = &bcma_pflash_resource,
|
||||
- .num_resources = 1,
|
||||
-};
|
||||
-
|
||||
/* The 47162a0 hangs when reading MIPS DMP registers registers */
|
||||
static inline bool bcma_core_mips_bcm47162a0_quirk(struct bcma_device *dev)
|
||||
{
|
||||
@@ -272,48 +250,11 @@ static enum bcma_boot_dev bcma_boot_dev(
|
||||
return BCMA_BOOT_DEV_SERIAL;
|
||||
}
|
||||
|
||||
-static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore)
|
||||
+static void bcma_core_mips_nvram_init(struct bcma_drv_mips *mcore)
|
||||
{
|
||||
struct bcma_bus *bus = mcore->core->bus;
|
||||
- struct bcma_drv_cc *cc = &bus->drv_cc;
|
||||
- struct bcma_pflash *pflash = &cc->pflash;
|
||||
enum bcma_boot_dev boot_dev;
|
||||
|
||||
- switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
|
||||
- case BCMA_CC_FLASHT_STSER:
|
||||
- case BCMA_CC_FLASHT_ATSER:
|
||||
- bcma_debug(bus, "Found serial flash\n");
|
||||
- bcma_sflash_init(cc);
|
||||
- break;
|
||||
- case BCMA_CC_FLASHT_PARA:
|
||||
- bcma_debug(bus, "Found parallel flash\n");
|
||||
- pflash->present = true;
|
||||
- pflash->window = BCMA_SOC_FLASH2;
|
||||
- pflash->window_size = BCMA_SOC_FLASH2_SZ;
|
||||
-
|
||||
- if ((bcma_read32(cc->core, BCMA_CC_FLASH_CFG) &
|
||||
- BCMA_CC_FLASH_CFG_DS) == 0)
|
||||
- pflash->buswidth = 1;
|
||||
- else
|
||||
- pflash->buswidth = 2;
|
||||
-
|
||||
- bcma_pflash_data.width = pflash->buswidth;
|
||||
- bcma_pflash_resource.start = pflash->window;
|
||||
- bcma_pflash_resource.end = pflash->window + pflash->window_size;
|
||||
-
|
||||
- break;
|
||||
- default:
|
||||
- bcma_err(bus, "Flash type not supported\n");
|
||||
- }
|
||||
-
|
||||
- if (cc->core->id.rev == 38 ||
|
||||
- bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) {
|
||||
- if (cc->capabilities & BCMA_CC_CAP_NFLASH) {
|
||||
- bcma_debug(bus, "Found NAND flash\n");
|
||||
- bcma_nflash_init(cc);
|
||||
- }
|
||||
- }
|
||||
-
|
||||
/* Determine flash type this SoC boots from */
|
||||
boot_dev = bcma_boot_dev(bus);
|
||||
switch (boot_dev) {
|
||||
@@ -337,13 +278,10 @@ static void bcma_core_mips_flash_detect(
|
||||
|
||||
void bcma_core_mips_early_init(struct bcma_drv_mips *mcore)
|
||||
{
|
||||
- struct bcma_bus *bus = mcore->core->bus;
|
||||
-
|
||||
if (mcore->early_setup_done)
|
||||
return;
|
||||
|
||||
- bcma_chipco_serial_init(&bus->drv_cc);
|
||||
- bcma_core_mips_flash_detect(mcore);
|
||||
+ bcma_core_mips_nvram_init(mcore);
|
||||
|
||||
mcore->early_setup_done = true;
|
||||
}
|
||||
--- a/drivers/bcma/host_pci.c
|
||||
+++ b/drivers/bcma/host_pci.c
|
||||
@@ -294,7 +294,8 @@ static const struct pci_device_id bcma_p
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4358) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4359) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4360) },
|
||||
- { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4365) },
|
||||
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_BROADCOM, 0x4365, PCI_VENDOR_ID_DELL, 0x0016) },
|
||||
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_BROADCOM, 0x4365, PCI_VENDOR_ID_FOXCONN, 0xe092) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43a0) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43a9) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43aa) },
|
||||
--- a/drivers/bcma/Kconfig
|
||||
+++ b/drivers/bcma/Kconfig
|
||||
@@ -70,6 +70,11 @@ config BCMA_DRIVER_MIPS
|
||||
|
||||
If unsure, say N
|
||||
|
||||
+config BCMA_PFLASH
|
||||
+ bool
|
||||
+ depends on BCMA_DRIVER_MIPS
|
||||
+ default y
|
||||
+
|
||||
config BCMA_SFLASH
|
||||
bool
|
||||
depends on BCMA_DRIVER_MIPS
|
||||
--- a/drivers/bcma/Makefile
|
||||
+++ b/drivers/bcma/Makefile
|
||||
@@ -1,6 +1,7 @@
|
||||
bcma-y += main.o scan.o core.o sprom.o
|
||||
bcma-y += driver_chipcommon.o driver_chipcommon_pmu.o
|
||||
bcma-y += driver_chipcommon_b.o
|
||||
+bcma-$(CONFIG_BCMA_PFLASH) += driver_chipcommon_pflash.o
|
||||
bcma-$(CONFIG_BCMA_SFLASH) += driver_chipcommon_sflash.o
|
||||
bcma-$(CONFIG_BCMA_NFLASH) += driver_chipcommon_nflash.o
|
||||
bcma-$(CONFIG_BCMA_DRIVER_PCI) += driver_pci.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/bcma/driver_chipcommon_pflash.c
|
||||
@@ -0,0 +1,49 @@
|
||||
+/*
|
||||
+ * Broadcom specific AMBA
|
||||
+ * ChipCommon parallel flash
|
||||
+ *
|
||||
+ * Licensed under the GNU/GPL. See COPYING for details.
|
||||
+ */
|
||||
+
|
||||
+#include "bcma_private.h"
|
||||
+
|
||||
+#include <linux/bcma/bcma.h>
|
||||
+#include <linux/mtd/physmap.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+
|
||||
+static const char * const part_probes[] = { "bcm47xxpart", NULL };
|
||||
+
|
||||
+static struct physmap_flash_data bcma_pflash_data = {
|
||||
+ .part_probe_types = part_probes,
|
||||
+};
|
||||
+
|
||||
+static struct resource bcma_pflash_resource = {
|
||||
+ .name = "bcma_pflash",
|
||||
+ .flags = IORESOURCE_MEM,
|
||||
+};
|
||||
+
|
||||
+struct platform_device bcma_pflash_dev = {
|
||||
+ .name = "physmap-flash",
|
||||
+ .dev = {
|
||||
+ .platform_data = &bcma_pflash_data,
|
||||
+ },
|
||||
+ .resource = &bcma_pflash_resource,
|
||||
+ .num_resources = 1,
|
||||
+};
|
||||
+
|
||||
+int bcma_pflash_init(struct bcma_drv_cc *cc)
|
||||
+{
|
||||
+ struct bcma_pflash *pflash = &cc->pflash;
|
||||
+
|
||||
+ pflash->present = true;
|
||||
+
|
||||
+ if (!(bcma_read32(cc->core, BCMA_CC_FLASH_CFG) & BCMA_CC_FLASH_CFG_DS))
|
||||
+ bcma_pflash_data.width = 1;
|
||||
+ else
|
||||
+ bcma_pflash_data.width = 2;
|
||||
+
|
||||
+ bcma_pflash_resource.start = BCMA_SOC_FLASH2;
|
||||
+ bcma_pflash_resource.end = BCMA_SOC_FLASH2 + BCMA_SOC_FLASH2_SZ;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
--- a/drivers/bcma/main.c
|
||||
+++ b/drivers/bcma/main.c
|
||||
@@ -136,7 +136,6 @@ static bool bcma_is_core_needed_early(u1
|
||||
return false;
|
||||
}
|
||||
|
||||
-#if defined(CONFIG_OF) && defined(CONFIG_OF_ADDRESS)
|
||||
static struct device_node *bcma_of_find_child_device(struct platform_device *parent,
|
||||
struct bcma_device *core)
|
||||
{
|
||||
@@ -184,7 +183,7 @@ static unsigned int bcma_of_get_irq(stru
|
||||
struct of_phandle_args out_irq;
|
||||
int ret;
|
||||
|
||||
- if (!parent || !parent->dev.of_node)
|
||||
+ if (!IS_ENABLED(CONFIG_OF_IRQ) || !parent || !parent->dev.of_node)
|
||||
return 0;
|
||||
|
||||
ret = bcma_of_irq_parse(parent, core, &out_irq, num);
|
||||
@@ -202,23 +201,15 @@ static void bcma_of_fill_device(struct p
|
||||
{
|
||||
struct device_node *node;
|
||||
|
||||
+ if (!IS_ENABLED(CONFIG_OF_IRQ))
|
||||
+ return;
|
||||
+
|
||||
node = bcma_of_find_child_device(parent, core);
|
||||
if (node)
|
||||
core->dev.of_node = node;
|
||||
|
||||
core->irq = bcma_of_get_irq(parent, core, 0);
|
||||
}
|
||||
-#else
|
||||
-static void bcma_of_fill_device(struct platform_device *parent,
|
||||
- struct bcma_device *core)
|
||||
-{
|
||||
-}
|
||||
-static inline unsigned int bcma_of_get_irq(struct platform_device *parent,
|
||||
- struct bcma_device *core, int num)
|
||||
-{
|
||||
- return 0;
|
||||
-}
|
||||
-#endif /* CONFIG_OF */
|
||||
|
||||
unsigned int bcma_core_irq(struct bcma_device *core, int num)
|
||||
{
|
||||
@@ -350,7 +341,7 @@ static int bcma_register_devices(struct
|
||||
bcma_register_core(bus, core);
|
||||
}
|
||||
|
||||
-#ifdef CONFIG_BCMA_DRIVER_MIPS
|
||||
+#ifdef CONFIG_BCMA_PFLASH
|
||||
if (bus->drv_cc.pflash.present) {
|
||||
err = platform_device_register(&bcma_pflash_dev);
|
||||
if (err)
|
@ -1,52 +0,0 @@
|
||||
--- a/drivers/bcma/Kconfig
|
||||
+++ b/drivers/bcma/Kconfig
|
||||
@@ -76,9 +76,16 @@ config BCMA_PFLASH
|
||||
default y
|
||||
|
||||
config BCMA_SFLASH
|
||||
- bool
|
||||
- depends on BCMA_DRIVER_MIPS
|
||||
+ bool "ChipCommon-attached serial flash support"
|
||||
+ depends on BCMA_HOST_SOC
|
||||
default y
|
||||
+ help
|
||||
+ Some cheap devices have serial flash connected to the ChipCommon
|
||||
+ instead of independent SPI controller. It requires using a separated
|
||||
+ driver that implements ChipCommon specific interface communication.
|
||||
+
|
||||
+ Enabling this symbol will let bcma recognize serial flash and register
|
||||
+ it as platform device.
|
||||
|
||||
config BCMA_NFLASH
|
||||
bool
|
||||
--- a/drivers/bcma/driver_chipcommon_b.c
|
||||
+++ b/drivers/bcma/driver_chipcommon_b.c
|
||||
@@ -33,11 +33,12 @@ static bool bcma_wait_reg(struct bcma_bu
|
||||
void bcma_chipco_b_mii_write(struct bcma_drv_cc_b *ccb, u32 offset, u32 value)
|
||||
{
|
||||
struct bcma_bus *bus = ccb->core->bus;
|
||||
+ void __iomem *mii = ccb->mii;
|
||||
|
||||
- writel(offset, ccb->mii + 0x00);
|
||||
- bcma_wait_reg(bus, ccb->mii + 0x00, 0x0100, 0x0000, 100);
|
||||
- writel(value, ccb->mii + 0x04);
|
||||
- bcma_wait_reg(bus, ccb->mii + 0x00, 0x0100, 0x0000, 100);
|
||||
+ writel(offset, mii + BCMA_CCB_MII_MNG_CTL);
|
||||
+ bcma_wait_reg(bus, mii + BCMA_CCB_MII_MNG_CTL, 0x0100, 0x0000, 100);
|
||||
+ writel(value, mii + BCMA_CCB_MII_MNG_CMD_DATA);
|
||||
+ bcma_wait_reg(bus, mii + BCMA_CCB_MII_MNG_CTL, 0x0100, 0x0000, 100);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bcma_chipco_b_mii_write);
|
||||
|
||||
--- a/include/linux/bcma/bcma_driver_chipcommon.h
|
||||
+++ b/include/linux/bcma/bcma_driver_chipcommon.h
|
||||
@@ -504,6 +504,9 @@
|
||||
#define BCMA_CC_PMU1_PLL0_PC2_NDIV_INT_MASK 0x1ff00000
|
||||
#define BCMA_CC_PMU1_PLL0_PC2_NDIV_INT_SHIFT 20
|
||||
|
||||
+#define BCMA_CCB_MII_MNG_CTL 0x0000
|
||||
+#define BCMA_CCB_MII_MNG_CMD_DATA 0x0004
|
||||
+
|
||||
/* BCM4331 ChipControl numbers. */
|
||||
#define BCMA_CHIPCTL_4331_BT_COEXIST BIT(0) /* 0 disable */
|
||||
#define BCMA_CHIPCTL_4331_SECI BIT(1) /* 0 SECI is disabled (JATG functional) */
|
@ -1,108 +0,0 @@
|
||||
--- a/drivers/bcma/driver_chipcommon.c
|
||||
+++ b/drivers/bcma/driver_chipcommon.c
|
||||
@@ -36,12 +36,31 @@ u32 bcma_chipco_get_alp_clock(struct bcm
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bcma_chipco_get_alp_clock);
|
||||
|
||||
+static bool bcma_core_cc_has_pmu_watchdog(struct bcma_drv_cc *cc)
|
||||
+{
|
||||
+ struct bcma_bus *bus = cc->core->bus;
|
||||
+
|
||||
+ if (cc->capabilities & BCMA_CC_CAP_PMU) {
|
||||
+ if (bus->chipinfo.id == BCMA_CHIP_ID_BCM53573) {
|
||||
+ WARN(bus->chipinfo.rev <= 1, "No watchdog available\n");
|
||||
+ /* 53573B0 and 53573B1 have bugged PMU watchdog. It can
|
||||
+ * be enabled but timer can't be bumped. Use CC one
|
||||
+ * instead.
|
||||
+ */
|
||||
+ return false;
|
||||
+ }
|
||||
+ return true;
|
||||
+ } else {
|
||||
+ return false;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static u32 bcma_chipco_watchdog_get_max_timer(struct bcma_drv_cc *cc)
|
||||
{
|
||||
struct bcma_bus *bus = cc->core->bus;
|
||||
u32 nb;
|
||||
|
||||
- if (cc->capabilities & BCMA_CC_CAP_PMU) {
|
||||
+ if (bcma_core_cc_has_pmu_watchdog(cc)) {
|
||||
if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4706)
|
||||
nb = 32;
|
||||
else if (cc->core->id.rev < 26)
|
||||
@@ -95,9 +114,16 @@ static int bcma_chipco_watchdog_ticks_pe
|
||||
|
||||
int bcma_chipco_watchdog_register(struct bcma_drv_cc *cc)
|
||||
{
|
||||
+ struct bcma_bus *bus = cc->core->bus;
|
||||
struct bcm47xx_wdt wdt = {};
|
||||
struct platform_device *pdev;
|
||||
|
||||
+ if (bus->chipinfo.id == BCMA_CHIP_ID_BCM53573 &&
|
||||
+ bus->chipinfo.rev <= 1) {
|
||||
+ pr_debug("No watchdog on 53573A0 / 53573A1\n");
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
wdt.driver_data = cc;
|
||||
wdt.timer_set = bcma_chipco_watchdog_timer_set_wdt;
|
||||
wdt.timer_set_ms = bcma_chipco_watchdog_timer_set_ms_wdt;
|
||||
@@ -105,7 +131,7 @@ int bcma_chipco_watchdog_register(struct
|
||||
bcma_chipco_watchdog_get_max_timer(cc) / cc->ticks_per_ms;
|
||||
|
||||
pdev = platform_device_register_data(NULL, "bcm47xx-wdt",
|
||||
- cc->core->bus->num, &wdt,
|
||||
+ bus->num, &wdt,
|
||||
sizeof(wdt));
|
||||
if (IS_ERR(pdev))
|
||||
return PTR_ERR(pdev);
|
||||
@@ -217,7 +243,7 @@ u32 bcma_chipco_watchdog_timer_set(struc
|
||||
u32 maxt;
|
||||
|
||||
maxt = bcma_chipco_watchdog_get_max_timer(cc);
|
||||
- if (cc->capabilities & BCMA_CC_CAP_PMU) {
|
||||
+ if (bcma_core_cc_has_pmu_watchdog(cc)) {
|
||||
if (ticks == 1)
|
||||
ticks = 2;
|
||||
else if (ticks > maxt)
|
||||
--- a/include/linux/bcma/bcma.h
|
||||
+++ b/include/linux/bcma/bcma.h
|
||||
@@ -204,6 +204,9 @@ struct bcma_host_ops {
|
||||
#define BCMA_PKG_ID_BCM4709 0
|
||||
#define BCMA_CHIP_ID_BCM47094 53030
|
||||
#define BCMA_CHIP_ID_BCM53018 53018
|
||||
+#define BCMA_CHIP_ID_BCM53573 53573
|
||||
+#define BCMA_PKG_ID_BCM53573 0
|
||||
+#define BCMA_PKG_ID_BCM47189 1
|
||||
|
||||
/* Board types (on PCI usually equals to the subsystem dev id) */
|
||||
/* BCM4313 */
|
||||
--- a/drivers/bcma/main.c
|
||||
+++ b/drivers/bcma/main.c
|
||||
@@ -209,6 +209,8 @@ static void bcma_of_fill_device(struct p
|
||||
core->dev.of_node = node;
|
||||
|
||||
core->irq = bcma_of_get_irq(parent, core, 0);
|
||||
+
|
||||
+ of_dma_configure(&core->dev, node);
|
||||
}
|
||||
|
||||
unsigned int bcma_core_irq(struct bcma_device *core, int num)
|
||||
@@ -248,12 +250,12 @@ void bcma_prepare_core(struct bcma_bus *
|
||||
core->irq = bus->host_pci->irq;
|
||||
break;
|
||||
case BCMA_HOSTTYPE_SOC:
|
||||
- core->dev.dma_mask = &core->dev.coherent_dma_mask;
|
||||
- if (bus->host_pdev) {
|
||||
+ if (IS_ENABLED(CONFIG_OF) && bus->host_pdev) {
|
||||
core->dma_dev = &bus->host_pdev->dev;
|
||||
core->dev.parent = &bus->host_pdev->dev;
|
||||
bcma_of_fill_device(bus->host_pdev, core);
|
||||
} else {
|
||||
+ core->dev.dma_mask = &core->dev.coherent_dma_mask;
|
||||
core->dma_dev = &core->dev;
|
||||
}
|
||||
break;
|
@ -1,85 +0,0 @@
|
||||
--- a/drivers/bcma/main.c
|
||||
+++ b/drivers/bcma/main.c
|
||||
@@ -136,17 +136,17 @@ static bool bcma_is_core_needed_early(u1
|
||||
return false;
|
||||
}
|
||||
|
||||
-static struct device_node *bcma_of_find_child_device(struct platform_device *parent,
|
||||
+static struct device_node *bcma_of_find_child_device(struct device *parent,
|
||||
struct bcma_device *core)
|
||||
{
|
||||
struct device_node *node;
|
||||
u64 size;
|
||||
const __be32 *reg;
|
||||
|
||||
- if (!parent || !parent->dev.of_node)
|
||||
+ if (!parent->of_node)
|
||||
return NULL;
|
||||
|
||||
- for_each_child_of_node(parent->dev.of_node, node) {
|
||||
+ for_each_child_of_node(parent->of_node, node) {
|
||||
reg = of_get_address(node, 0, &size, NULL);
|
||||
if (!reg)
|
||||
continue;
|
||||
@@ -156,7 +156,7 @@ static struct device_node *bcma_of_find_
|
||||
return NULL;
|
||||
}
|
||||
|
||||
-static int bcma_of_irq_parse(struct platform_device *parent,
|
||||
+static int bcma_of_irq_parse(struct device *parent,
|
||||
struct bcma_device *core,
|
||||
struct of_phandle_args *out_irq, int num)
|
||||
{
|
||||
@@ -169,7 +169,7 @@ static int bcma_of_irq_parse(struct plat
|
||||
return rc;
|
||||
}
|
||||
|
||||
- out_irq->np = parent->dev.of_node;
|
||||
+ out_irq->np = parent->of_node;
|
||||
out_irq->args_count = 1;
|
||||
out_irq->args[0] = num;
|
||||
|
||||
@@ -177,13 +177,13 @@ static int bcma_of_irq_parse(struct plat
|
||||
return of_irq_parse_raw(laddr, out_irq);
|
||||
}
|
||||
|
||||
-static unsigned int bcma_of_get_irq(struct platform_device *parent,
|
||||
+static unsigned int bcma_of_get_irq(struct device *parent,
|
||||
struct bcma_device *core, int num)
|
||||
{
|
||||
struct of_phandle_args out_irq;
|
||||
int ret;
|
||||
|
||||
- if (!IS_ENABLED(CONFIG_OF_IRQ) || !parent || !parent->dev.of_node)
|
||||
+ if (!IS_ENABLED(CONFIG_OF_IRQ) || !parent->of_node)
|
||||
return 0;
|
||||
|
||||
ret = bcma_of_irq_parse(parent, core, &out_irq, num);
|
||||
@@ -196,7 +196,7 @@ static unsigned int bcma_of_get_irq(stru
|
||||
return irq_create_of_mapping(&out_irq);
|
||||
}
|
||||
|
||||
-static void bcma_of_fill_device(struct platform_device *parent,
|
||||
+static void bcma_of_fill_device(struct device *parent,
|
||||
struct bcma_device *core)
|
||||
{
|
||||
struct device_node *node;
|
||||
@@ -227,7 +227,7 @@ unsigned int bcma_core_irq(struct bcma_d
|
||||
return mips_irq <= 4 ? mips_irq + 2 : 0;
|
||||
}
|
||||
if (bus->host_pdev)
|
||||
- return bcma_of_get_irq(bus->host_pdev, core, num);
|
||||
+ return bcma_of_get_irq(&bus->host_pdev->dev, core, num);
|
||||
return 0;
|
||||
case BCMA_HOSTTYPE_SDIO:
|
||||
return 0;
|
||||
@@ -253,7 +253,8 @@ void bcma_prepare_core(struct bcma_bus *
|
||||
if (IS_ENABLED(CONFIG_OF) && bus->host_pdev) {
|
||||
core->dma_dev = &bus->host_pdev->dev;
|
||||
core->dev.parent = &bus->host_pdev->dev;
|
||||
- bcma_of_fill_device(bus->host_pdev, core);
|
||||
+ if (core->dev.parent)
|
||||
+ bcma_of_fill_device(core->dev.parent, core);
|
||||
} else {
|
||||
core->dev.dma_mask = &core->dev.coherent_dma_mask;
|
||||
core->dma_dev = &core->dev;
|
@ -1,47 +0,0 @@
|
||||
--- a/drivers/bcma/driver_gpio.c
|
||||
+++ b/drivers/bcma/driver_gpio.c
|
||||
@@ -190,8 +190,7 @@ int bcma_gpio_init(struct bcma_drv_cc *c
|
||||
chip->owner = THIS_MODULE;
|
||||
chip->dev = bcma_bus_get_host_dev(bus);
|
||||
#if IS_BUILTIN(CONFIG_OF)
|
||||
- if (cc->core->bus->hosttype == BCMA_HOSTTYPE_SOC)
|
||||
- chip->of_node = cc->core->dev.of_node;
|
||||
+ chip->of_node = cc->core->dev.of_node;
|
||||
#endif
|
||||
switch (bus->chipinfo.id) {
|
||||
case BCMA_CHIP_ID_BCM4707:
|
||||
--- a/drivers/bcma/main.c
|
||||
+++ b/drivers/bcma/main.c
|
||||
@@ -201,9 +201,6 @@ static void bcma_of_fill_device(struct d
|
||||
{
|
||||
struct device_node *node;
|
||||
|
||||
- if (!IS_ENABLED(CONFIG_OF_IRQ))
|
||||
- return;
|
||||
-
|
||||
node = bcma_of_find_child_device(parent, core);
|
||||
if (node)
|
||||
core->dev.of_node = node;
|
||||
@@ -242,19 +239,18 @@ void bcma_prepare_core(struct bcma_bus *
|
||||
core->dev.release = bcma_release_core_dev;
|
||||
core->dev.bus = &bcma_bus_type;
|
||||
dev_set_name(&core->dev, "bcma%d:%d", bus->num, core->core_index);
|
||||
+ core->dev.parent = bcma_bus_get_host_dev(bus);
|
||||
+ if (core->dev.parent)
|
||||
+ bcma_of_fill_device(core->dev.parent, core);
|
||||
|
||||
switch (bus->hosttype) {
|
||||
case BCMA_HOSTTYPE_PCI:
|
||||
- core->dev.parent = &bus->host_pci->dev;
|
||||
core->dma_dev = &bus->host_pci->dev;
|
||||
core->irq = bus->host_pci->irq;
|
||||
break;
|
||||
case BCMA_HOSTTYPE_SOC:
|
||||
if (IS_ENABLED(CONFIG_OF) && bus->host_pdev) {
|
||||
core->dma_dev = &bus->host_pdev->dev;
|
||||
- core->dev.parent = &bus->host_pdev->dev;
|
||||
- if (core->dev.parent)
|
||||
- bcma_of_fill_device(core->dev.parent, core);
|
||||
} else {
|
||||
core->dev.dma_mask = &core->dev.coherent_dma_mask;
|
||||
core->dma_dev = &core->dev;
|
@ -1,40 +0,0 @@
|
||||
From e9156cd26a495a18706e796f02a81fee41ec14f4 Mon Sep 17 00:00:00 2001
|
||||
From: James Hughes <james.hughes@raspberrypi.org>
|
||||
Date: Wed, 19 Apr 2017 11:13:40 +0100
|
||||
Subject: [PATCH] smsc95xx: Use skb_cow_head to deal with cloned skbs
|
||||
|
||||
The driver was failing to check that the SKB wasn't cloned
|
||||
before adding checksum data.
|
||||
Replace existing handling to extend/copy the header buffer
|
||||
with skb_cow_head.
|
||||
|
||||
Signed-off-by: James Hughes <james.hughes@raspberrypi.org>
|
||||
Acked-by: Eric Dumazet <edumazet@google.com>
|
||||
Acked-by: Woojung Huh <Woojung.Huh@microchip.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/usb/smsc95xx.c | 12 ++++++------
|
||||
1 file changed, 6 insertions(+), 6 deletions(-)
|
||||
|
||||
--- a/drivers/net/usb/smsc95xx.c
|
||||
+++ b/drivers/net/usb/smsc95xx.c
|
||||
@@ -1835,13 +1835,13 @@ static struct sk_buff *smsc95xx_tx_fixup
|
||||
/* We do not advertise SG, so skbs should be already linearized */
|
||||
BUG_ON(skb_shinfo(skb)->nr_frags);
|
||||
|
||||
- if (skb_headroom(skb) < overhead) {
|
||||
- struct sk_buff *skb2 = skb_copy_expand(skb,
|
||||
- overhead, 0, flags);
|
||||
+ /* Make writable and expand header space by overhead if required */
|
||||
+ if (skb_cow_head(skb, overhead)) {
|
||||
+ /* Must deallocate here as returning NULL to indicate error
|
||||
+ * means the skb won't be deallocated in the caller.
|
||||
+ */
|
||||
dev_kfree_skb_any(skb);
|
||||
- skb = skb2;
|
||||
- if (!skb)
|
||||
- return NULL;
|
||||
+ return NULL;
|
||||
}
|
||||
|
||||
if (csum) {
|
@ -1,38 +0,0 @@
|
||||
From 6bc6895bdd6744e0136eaa4a11fbdb20a7db4e40 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Dumazet <edumazet@google.com>
|
||||
Date: Wed, 19 Apr 2017 09:59:25 -0700
|
||||
Subject: [PATCH] ch9200: use skb_cow_head() to deal with cloned skbs
|
||||
|
||||
We need to ensure there is enough headroom to push extra header,
|
||||
but we also need to check if we are allowed to change headers.
|
||||
|
||||
skb_cow_head() is the proper helper to deal with this.
|
||||
|
||||
Fixes: 4a476bd6d1d9 ("usbnet: New driver for QinHeng CH9200 devices")
|
||||
Signed-off-by: Eric Dumazet <edumazet@google.com>
|
||||
Cc: James Hughes <james.hughes@raspberrypi.org>
|
||||
Cc: Matthew Garrett <mjg59@srcf.ucam.org>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/usb/ch9200.c | 9 ++-------
|
||||
1 file changed, 2 insertions(+), 7 deletions(-)
|
||||
|
||||
--- a/drivers/net/usb/ch9200.c
|
||||
+++ b/drivers/net/usb/ch9200.c
|
||||
@@ -255,14 +255,9 @@ static struct sk_buff *ch9200_tx_fixup(s
|
||||
tx_overhead = 0x40;
|
||||
|
||||
len = skb->len;
|
||||
- if (skb_headroom(skb) < tx_overhead) {
|
||||
- struct sk_buff *skb2;
|
||||
-
|
||||
- skb2 = skb_copy_expand(skb, tx_overhead, 0, flags);
|
||||
+ if (skb_cow_head(skb, tx_overhead)) {
|
||||
dev_kfree_skb_any(skb);
|
||||
- skb = skb2;
|
||||
- if (!skb)
|
||||
- return NULL;
|
||||
+ return NULL;
|
||||
}
|
||||
|
||||
__skb_push(skb, tx_overhead);
|
@ -1,43 +0,0 @@
|
||||
From 39fba7835aacda65284a86e611774cbba71dac20 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Dumazet <edumazet@google.com>
|
||||
Date: Wed, 19 Apr 2017 09:59:26 -0700
|
||||
Subject: [PATCH] kaweth: use skb_cow_head() to deal with cloned skbs
|
||||
|
||||
We can use skb_cow_head() to properly deal with clones,
|
||||
especially the ones coming from TCP stack that allow their head being
|
||||
modified. This avoids a copy.
|
||||
|
||||
Signed-off-by: Eric Dumazet <edumazet@google.com>
|
||||
Cc: James Hughes <james.hughes@raspberrypi.org>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/usb/kaweth.c | 18 ++++++------------
|
||||
1 file changed, 6 insertions(+), 12 deletions(-)
|
||||
|
||||
--- a/drivers/net/usb/kaweth.c
|
||||
+++ b/drivers/net/usb/kaweth.c
|
||||
@@ -812,18 +812,12 @@ static netdev_tx_t kaweth_start_xmit(str
|
||||
}
|
||||
|
||||
/* We now decide whether we can put our special header into the sk_buff */
|
||||
- if (skb_cloned(skb) || skb_headroom(skb) < 2) {
|
||||
- /* no such luck - we make our own */
|
||||
- struct sk_buff *copied_skb;
|
||||
- copied_skb = skb_copy_expand(skb, 2, 0, GFP_ATOMIC);
|
||||
- dev_kfree_skb_irq(skb);
|
||||
- skb = copied_skb;
|
||||
- if (!copied_skb) {
|
||||
- kaweth->stats.tx_errors++;
|
||||
- netif_start_queue(net);
|
||||
- spin_unlock_irq(&kaweth->device_lock);
|
||||
- return NETDEV_TX_OK;
|
||||
- }
|
||||
+ if (skb_cow_head(skb, 2)) {
|
||||
+ kaweth->stats.tx_errors++;
|
||||
+ netif_start_queue(net);
|
||||
+ spin_unlock_irq(&kaweth->device_lock);
|
||||
+ dev_kfree_skb_any(skb);
|
||||
+ return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
private_header = (__le16 *)__skb_push(skb, 2);
|
@ -1,189 +0,0 @@
|
||||
From: Eric Dumazet <edumazet@google.com>
|
||||
Date: Sun, 1 May 2016 16:47:26 -0700
|
||||
Subject: [PATCH] fq_codel: add batch ability to fq_codel_drop()
|
||||
|
||||
In presence of inelastic flows and stress, we can call
|
||||
fq_codel_drop() for every packet entering fq_codel qdisc.
|
||||
|
||||
fq_codel_drop() is quite expensive, as it does a linear scan
|
||||
of 4 KB of memory to find a fat flow.
|
||||
Once found, it drops the oldest packet of this flow.
|
||||
|
||||
Instead of dropping a single packet, try to drop 50% of the backlog
|
||||
of this fat flow, with a configurable limit of 64 packets per round.
|
||||
|
||||
TCA_FQ_CODEL_DROP_BATCH_SIZE is the new attribute to make this
|
||||
limit configurable.
|
||||
|
||||
With this strategy the 4 KB search is amortized to a single cache line
|
||||
per drop [1], so fq_codel_drop() no longer appears at the top of kernel
|
||||
profile in presence of few inelastic flows.
|
||||
|
||||
[1] Assuming a 64byte cache line, and 1024 buckets
|
||||
|
||||
Signed-off-by: Eric Dumazet <edumazet@google.com>
|
||||
Reported-by: Dave Taht <dave.taht@gmail.com>
|
||||
Cc: Jonathan Morton <chromatix99@gmail.com>
|
||||
Acked-by: Jesper Dangaard Brouer <brouer@redhat.com>
|
||||
Acked-by: Dave Taht
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
|
||||
--- a/include/uapi/linux/pkt_sched.h
|
||||
+++ b/include/uapi/linux/pkt_sched.h
|
||||
@@ -711,6 +711,7 @@ enum {
|
||||
TCA_FQ_CODEL_FLOWS,
|
||||
TCA_FQ_CODEL_QUANTUM,
|
||||
TCA_FQ_CODEL_CE_THRESHOLD,
|
||||
+ TCA_FQ_CODEL_DROP_BATCH_SIZE,
|
||||
__TCA_FQ_CODEL_MAX
|
||||
};
|
||||
|
||||
--- a/net/sched/sch_fq_codel.c
|
||||
+++ b/net/sched/sch_fq_codel.c
|
||||
@@ -57,6 +57,7 @@ struct fq_codel_sched_data {
|
||||
u32 flows_cnt; /* number of flows */
|
||||
u32 perturbation; /* hash perturbation */
|
||||
u32 quantum; /* psched_mtu(qdisc_dev(sch)); */
|
||||
+ u32 drop_batch_size;
|
||||
struct codel_params cparams;
|
||||
struct codel_stats cstats;
|
||||
u32 drop_overlimit;
|
||||
@@ -133,17 +134,20 @@ static inline void flow_queue_add(struct
|
||||
skb->next = NULL;
|
||||
}
|
||||
|
||||
-static unsigned int fq_codel_drop(struct Qdisc *sch)
|
||||
+static unsigned int fq_codel_drop(struct Qdisc *sch, unsigned int max_packets)
|
||||
{
|
||||
struct fq_codel_sched_data *q = qdisc_priv(sch);
|
||||
struct sk_buff *skb;
|
||||
unsigned int maxbacklog = 0, idx = 0, i, len;
|
||||
struct fq_codel_flow *flow;
|
||||
+ unsigned int threshold;
|
||||
|
||||
- /* Queue is full! Find the fat flow and drop packet from it.
|
||||
+ /* Queue is full! Find the fat flow and drop packet(s) from it.
|
||||
* This might sound expensive, but with 1024 flows, we scan
|
||||
* 4KB of memory, and we dont need to handle a complex tree
|
||||
* in fast path (packet queue/enqueue) with many cache misses.
|
||||
+ * In stress mode, we'll try to drop 64 packets from the flow,
|
||||
+ * amortizing this linear lookup to one cache line per drop.
|
||||
*/
|
||||
for (i = 0; i < q->flows_cnt; i++) {
|
||||
if (q->backlogs[i] > maxbacklog) {
|
||||
@@ -151,15 +155,24 @@ static unsigned int fq_codel_drop(struct
|
||||
idx = i;
|
||||
}
|
||||
}
|
||||
+
|
||||
+ /* Our goal is to drop half of this fat flow backlog */
|
||||
+ threshold = maxbacklog >> 1;
|
||||
+
|
||||
flow = &q->flows[idx];
|
||||
- skb = dequeue_head(flow);
|
||||
- len = qdisc_pkt_len(skb);
|
||||
+ len = 0;
|
||||
+ i = 0;
|
||||
+ do {
|
||||
+ skb = dequeue_head(flow);
|
||||
+ len += qdisc_pkt_len(skb);
|
||||
+ kfree_skb(skb);
|
||||
+ } while (++i < max_packets && len < threshold);
|
||||
+
|
||||
+ flow->dropped += i;
|
||||
q->backlogs[idx] -= len;
|
||||
- sch->q.qlen--;
|
||||
- qdisc_qstats_drop(sch);
|
||||
- qdisc_qstats_backlog_dec(sch, skb);
|
||||
- kfree_skb(skb);
|
||||
- flow->dropped++;
|
||||
+ sch->qstats.drops += i;
|
||||
+ sch->qstats.backlog -= len;
|
||||
+ sch->q.qlen -= i;
|
||||
return idx;
|
||||
}
|
||||
|
||||
@@ -168,14 +181,14 @@ static unsigned int fq_codel_qdisc_drop(
|
||||
unsigned int prev_backlog;
|
||||
|
||||
prev_backlog = sch->qstats.backlog;
|
||||
- fq_codel_drop(sch);
|
||||
+ fq_codel_drop(sch, 1U);
|
||||
return prev_backlog - sch->qstats.backlog;
|
||||
}
|
||||
|
||||
static int fq_codel_enqueue(struct sk_buff *skb, struct Qdisc *sch)
|
||||
{
|
||||
struct fq_codel_sched_data *q = qdisc_priv(sch);
|
||||
- unsigned int idx, prev_backlog;
|
||||
+ unsigned int idx, prev_backlog, prev_qlen;
|
||||
struct fq_codel_flow *flow;
|
||||
int uninitialized_var(ret);
|
||||
|
||||
@@ -204,16 +217,22 @@ static int fq_codel_enqueue(struct sk_bu
|
||||
return NET_XMIT_SUCCESS;
|
||||
|
||||
prev_backlog = sch->qstats.backlog;
|
||||
- q->drop_overlimit++;
|
||||
- /* Return Congestion Notification only if we dropped a packet
|
||||
- * from this flow.
|
||||
+ prev_qlen = sch->q.qlen;
|
||||
+
|
||||
+ /* fq_codel_drop() is quite expensive, as it performs a linear search
|
||||
+ * in q->backlogs[] to find a fat flow.
|
||||
+ * So instead of dropping a single packet, drop half of its backlog
|
||||
+ * with a 64 packets limit to not add a too big cpu spike here.
|
||||
*/
|
||||
- if (fq_codel_drop(sch) == idx)
|
||||
- return NET_XMIT_CN;
|
||||
+ ret = fq_codel_drop(sch, q->drop_batch_size);
|
||||
+
|
||||
+ q->drop_overlimit += prev_qlen - sch->q.qlen;
|
||||
|
||||
- /* As we dropped a packet, better let upper stack know this */
|
||||
- qdisc_tree_reduce_backlog(sch, 1, prev_backlog - sch->qstats.backlog);
|
||||
- return NET_XMIT_SUCCESS;
|
||||
+ /* As we dropped packet(s), better let upper stack know this */
|
||||
+ qdisc_tree_reduce_backlog(sch, prev_qlen - sch->q.qlen,
|
||||
+ prev_backlog - sch->qstats.backlog);
|
||||
+
|
||||
+ return ret == idx ? NET_XMIT_CN : NET_XMIT_SUCCESS;
|
||||
}
|
||||
|
||||
/* This is the specific function called from codel_dequeue()
|
||||
@@ -323,6 +342,7 @@ static const struct nla_policy fq_codel_
|
||||
[TCA_FQ_CODEL_FLOWS] = { .type = NLA_U32 },
|
||||
[TCA_FQ_CODEL_QUANTUM] = { .type = NLA_U32 },
|
||||
[TCA_FQ_CODEL_CE_THRESHOLD] = { .type = NLA_U32 },
|
||||
+ [TCA_FQ_CODEL_DROP_BATCH_SIZE] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
static int fq_codel_change(struct Qdisc *sch, struct nlattr *opt)
|
||||
@@ -374,6 +394,9 @@ static int fq_codel_change(struct Qdisc
|
||||
if (tb[TCA_FQ_CODEL_QUANTUM])
|
||||
q->quantum = max(256U, nla_get_u32(tb[TCA_FQ_CODEL_QUANTUM]));
|
||||
|
||||
+ if (tb[TCA_FQ_CODEL_DROP_BATCH_SIZE])
|
||||
+ q->drop_batch_size = min(1U, nla_get_u32(tb[TCA_FQ_CODEL_DROP_BATCH_SIZE]));
|
||||
+
|
||||
while (sch->q.qlen > sch->limit) {
|
||||
struct sk_buff *skb = fq_codel_dequeue(sch);
|
||||
|
||||
@@ -419,6 +442,7 @@ static int fq_codel_init(struct Qdisc *s
|
||||
|
||||
sch->limit = 10*1024;
|
||||
q->flows_cnt = 1024;
|
||||
+ q->drop_batch_size = 64;
|
||||
q->quantum = psched_mtu(qdisc_dev(sch));
|
||||
q->perturbation = prandom_u32();
|
||||
INIT_LIST_HEAD(&q->new_flows);
|
||||
@@ -476,6 +500,8 @@ static int fq_codel_dump(struct Qdisc *s
|
||||
q->cparams.ecn) ||
|
||||
nla_put_u32(skb, TCA_FQ_CODEL_QUANTUM,
|
||||
q->quantum) ||
|
||||
+ nla_put_u32(skb, TCA_FQ_CODEL_DROP_BATCH_SIZE,
|
||||
+ q->drop_batch_size) ||
|
||||
nla_put_u32(skb, TCA_FQ_CODEL_FLOWS,
|
||||
q->flows_cnt))
|
||||
goto nla_put_failure;
|
@ -1,182 +0,0 @@
|
||||
From: Eric Dumazet <edumazet@google.com>
|
||||
Date: Fri, 6 May 2016 08:55:12 -0700
|
||||
Subject: [PATCH] fq_codel: add memory limitation per queue
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
On small embedded routers, one wants to control maximal amount of
|
||||
memory used by fq_codel, instead of controlling number of packets or
|
||||
bytes, since GRO/TSO make these not practical.
|
||||
|
||||
Assuming skb->truesize is accurate, we have to keep track of
|
||||
skb->truesize sum for skbs in queue.
|
||||
|
||||
This patch adds a new TCA_FQ_CODEL_MEMORY_LIMIT attribute.
|
||||
|
||||
I chose a default value of 32 MBytes, which looks reasonable even
|
||||
for heavy duty usages. (Prior fq_codel users should not be hurt
|
||||
when they upgrade their kernels)
|
||||
|
||||
Two fields are added to tc_fq_codel_qd_stats to report :
|
||||
- Current memory usage
|
||||
- Number of drops caused by memory limits
|
||||
|
||||
# tc qd replace dev eth1 root est 1sec 4sec fq_codel memory_limit 4M
|
||||
..
|
||||
# tc -s -d qd sh dev eth1
|
||||
qdisc fq_codel 8008: root refcnt 257 limit 10240p flows 1024
|
||||
quantum 1514 target 5.0ms interval 100.0ms memory_limit 4Mb ecn
|
||||
Sent 2083566791363 bytes 1376214889 pkt (dropped 4994406, overlimits 0
|
||||
requeues 21705223)
|
||||
rate 9841Mbit 812549pps backlog 3906120b 376p requeues 21705223
|
||||
maxpacket 68130 drop_overlimit 4994406 new_flow_count 28855414
|
||||
ecn_mark 0 memory_used 4190048 drop_overmemory 4994406
|
||||
new_flows_len 1 old_flows_len 177
|
||||
|
||||
Signed-off-by: Eric Dumazet <edumazet@google.com>
|
||||
Cc: Jesper Dangaard Brouer <brouer@redhat.com>
|
||||
Cc: Dave Täht <dave.taht@gmail.com>
|
||||
Cc: Sebastian Möller <moeller0@gmx.de>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
|
||||
--- a/include/uapi/linux/pkt_sched.h
|
||||
+++ b/include/uapi/linux/pkt_sched.h
|
||||
@@ -712,6 +712,7 @@ enum {
|
||||
TCA_FQ_CODEL_QUANTUM,
|
||||
TCA_FQ_CODEL_CE_THRESHOLD,
|
||||
TCA_FQ_CODEL_DROP_BATCH_SIZE,
|
||||
+ TCA_FQ_CODEL_MEMORY_LIMIT,
|
||||
__TCA_FQ_CODEL_MAX
|
||||
};
|
||||
|
||||
@@ -736,6 +737,8 @@ struct tc_fq_codel_qd_stats {
|
||||
__u32 new_flows_len; /* count of flows in new list */
|
||||
__u32 old_flows_len; /* count of flows in old list */
|
||||
__u32 ce_mark; /* packets above ce_threshold */
|
||||
+ __u32 memory_usage; /* in bytes */
|
||||
+ __u32 drop_overmemory;
|
||||
};
|
||||
|
||||
struct tc_fq_codel_cl_stats {
|
||||
--- a/net/sched/sch_fq_codel.c
|
||||
+++ b/net/sched/sch_fq_codel.c
|
||||
@@ -58,8 +58,11 @@ struct fq_codel_sched_data {
|
||||
u32 perturbation; /* hash perturbation */
|
||||
u32 quantum; /* psched_mtu(qdisc_dev(sch)); */
|
||||
u32 drop_batch_size;
|
||||
+ u32 memory_limit;
|
||||
struct codel_params cparams;
|
||||
struct codel_stats cstats;
|
||||
+ u32 memory_usage;
|
||||
+ u32 drop_overmemory;
|
||||
u32 drop_overlimit;
|
||||
u32 new_flow_count;
|
||||
|
||||
@@ -141,6 +144,7 @@ static unsigned int fq_codel_drop(struct
|
||||
unsigned int maxbacklog = 0, idx = 0, i, len;
|
||||
struct fq_codel_flow *flow;
|
||||
unsigned int threshold;
|
||||
+ unsigned int mem = 0;
|
||||
|
||||
/* Queue is full! Find the fat flow and drop packet(s) from it.
|
||||
* This might sound expensive, but with 1024 flows, we scan
|
||||
@@ -165,11 +169,13 @@ static unsigned int fq_codel_drop(struct
|
||||
do {
|
||||
skb = dequeue_head(flow);
|
||||
len += qdisc_pkt_len(skb);
|
||||
+ mem += skb->truesize;
|
||||
kfree_skb(skb);
|
||||
} while (++i < max_packets && len < threshold);
|
||||
|
||||
flow->dropped += i;
|
||||
q->backlogs[idx] -= len;
|
||||
+ q->memory_usage -= mem;
|
||||
sch->qstats.drops += i;
|
||||
sch->qstats.backlog -= len;
|
||||
sch->q.qlen -= i;
|
||||
@@ -191,6 +197,7 @@ static int fq_codel_enqueue(struct sk_bu
|
||||
unsigned int idx, prev_backlog, prev_qlen;
|
||||
struct fq_codel_flow *flow;
|
||||
int uninitialized_var(ret);
|
||||
+ bool memory_limited;
|
||||
|
||||
idx = fq_codel_classify(skb, sch, &ret);
|
||||
if (idx == 0) {
|
||||
@@ -213,7 +220,9 @@ static int fq_codel_enqueue(struct sk_bu
|
||||
flow->deficit = q->quantum;
|
||||
flow->dropped = 0;
|
||||
}
|
||||
- if (++sch->q.qlen <= sch->limit)
|
||||
+ q->memory_usage += skb->truesize;
|
||||
+ memory_limited = q->memory_usage > q->memory_limit;
|
||||
+ if (++sch->q.qlen <= sch->limit && !memory_limited)
|
||||
return NET_XMIT_SUCCESS;
|
||||
|
||||
prev_backlog = sch->qstats.backlog;
|
||||
@@ -227,7 +236,8 @@ static int fq_codel_enqueue(struct sk_bu
|
||||
ret = fq_codel_drop(sch, q->drop_batch_size);
|
||||
|
||||
q->drop_overlimit += prev_qlen - sch->q.qlen;
|
||||
-
|
||||
+ if (memory_limited)
|
||||
+ q->drop_overmemory += prev_qlen - sch->q.qlen;
|
||||
/* As we dropped packet(s), better let upper stack know this */
|
||||
qdisc_tree_reduce_backlog(sch, prev_qlen - sch->q.qlen,
|
||||
prev_backlog - sch->qstats.backlog);
|
||||
@@ -296,6 +306,7 @@ begin:
|
||||
list_del_init(&flow->flowchain);
|
||||
goto begin;
|
||||
}
|
||||
+ q->memory_usage -= skb->truesize;
|
||||
qdisc_bstats_update(sch, skb);
|
||||
flow->deficit -= qdisc_pkt_len(skb);
|
||||
/* We cant call qdisc_tree_reduce_backlog() if our qlen is 0,
|
||||
@@ -343,6 +354,7 @@ static const struct nla_policy fq_codel_
|
||||
[TCA_FQ_CODEL_QUANTUM] = { .type = NLA_U32 },
|
||||
[TCA_FQ_CODEL_CE_THRESHOLD] = { .type = NLA_U32 },
|
||||
[TCA_FQ_CODEL_DROP_BATCH_SIZE] = { .type = NLA_U32 },
|
||||
+ [TCA_FQ_CODEL_MEMORY_LIMIT] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
static int fq_codel_change(struct Qdisc *sch, struct nlattr *opt)
|
||||
@@ -397,7 +409,11 @@ static int fq_codel_change(struct Qdisc
|
||||
if (tb[TCA_FQ_CODEL_DROP_BATCH_SIZE])
|
||||
q->drop_batch_size = min(1U, nla_get_u32(tb[TCA_FQ_CODEL_DROP_BATCH_SIZE]));
|
||||
|
||||
- while (sch->q.qlen > sch->limit) {
|
||||
+ if (tb[TCA_FQ_CODEL_MEMORY_LIMIT])
|
||||
+ q->memory_limit = min(1U << 31, nla_get_u32(tb[TCA_FQ_CODEL_MEMORY_LIMIT]));
|
||||
+
|
||||
+ while (sch->q.qlen > sch->limit ||
|
||||
+ q->memory_usage > q->memory_limit) {
|
||||
struct sk_buff *skb = fq_codel_dequeue(sch);
|
||||
|
||||
q->cstats.drop_len += qdisc_pkt_len(skb);
|
||||
@@ -442,6 +458,7 @@ static int fq_codel_init(struct Qdisc *s
|
||||
|
||||
sch->limit = 10*1024;
|
||||
q->flows_cnt = 1024;
|
||||
+ q->memory_limit = 32 << 20; /* 32 MBytes */
|
||||
q->drop_batch_size = 64;
|
||||
q->quantum = psched_mtu(qdisc_dev(sch));
|
||||
q->perturbation = prandom_u32();
|
||||
@@ -502,6 +519,8 @@ static int fq_codel_dump(struct Qdisc *s
|
||||
q->quantum) ||
|
||||
nla_put_u32(skb, TCA_FQ_CODEL_DROP_BATCH_SIZE,
|
||||
q->drop_batch_size) ||
|
||||
+ nla_put_u32(skb, TCA_FQ_CODEL_MEMORY_LIMIT,
|
||||
+ q->memory_limit) ||
|
||||
nla_put_u32(skb, TCA_FQ_CODEL_FLOWS,
|
||||
q->flows_cnt))
|
||||
goto nla_put_failure;
|
||||
@@ -530,6 +549,8 @@ static int fq_codel_dump_stats(struct Qd
|
||||
st.qdisc_stats.ecn_mark = q->cstats.ecn_mark;
|
||||
st.qdisc_stats.new_flow_count = q->new_flow_count;
|
||||
st.qdisc_stats.ce_mark = q->cstats.ce_mark;
|
||||
+ st.qdisc_stats.memory_usage = q->memory_usage;
|
||||
+ st.qdisc_stats.drop_overmemory = q->drop_overmemory;
|
||||
|
||||
list_for_each(pos, &q->new_flows)
|
||||
st.qdisc_stats.new_flows_len++;
|
@ -1,40 +0,0 @@
|
||||
From: Eric Dumazet <edumazet@google.com>
|
||||
Date: Sun, 15 May 2016 18:16:38 -0700
|
||||
Subject: [PATCH] fq_codel: fix memory limitation drift
|
||||
|
||||
memory_usage must be decreased in dequeue_func(), not in
|
||||
fq_codel_dequeue(), otherwise packets dropped by Codel algo
|
||||
are missing this decrease.
|
||||
|
||||
Also we need to clear memory_usage in fq_codel_reset()
|
||||
|
||||
Fixes: 95b58430abe7 ("fq_codel: add memory limitation per queue")
|
||||
Signed-off-by: Eric Dumazet <edumazet@google.com>
|
||||
---
|
||||
|
||||
--- a/net/sched/sch_fq_codel.c
|
||||
+++ b/net/sched/sch_fq_codel.c
|
||||
@@ -259,6 +259,7 @@ static struct sk_buff *dequeue(struct co
|
||||
if (flow->head) {
|
||||
skb = dequeue_head(flow);
|
||||
q->backlogs[flow - q->flows] -= qdisc_pkt_len(skb);
|
||||
+ q->memory_usage -= skb->truesize;
|
||||
sch->q.qlen--;
|
||||
}
|
||||
return skb;
|
||||
@@ -306,7 +307,6 @@ begin:
|
||||
list_del_init(&flow->flowchain);
|
||||
goto begin;
|
||||
}
|
||||
- q->memory_usage -= skb->truesize;
|
||||
qdisc_bstats_update(sch, skb);
|
||||
flow->deficit -= qdisc_pkt_len(skb);
|
||||
/* We cant call qdisc_tree_reduce_backlog() if our qlen is 0,
|
||||
@@ -343,6 +343,7 @@ static void fq_codel_reset(struct Qdisc
|
||||
}
|
||||
memset(q->backlogs, 0, q->flows_cnt * sizeof(u32));
|
||||
sch->q.qlen = 0;
|
||||
+ q->memory_usage = 0;
|
||||
}
|
||||
|
||||
static const struct nla_policy fq_codel_policy[TCA_FQ_CODEL_MAX + 1] = {
|
@ -1,70 +0,0 @@
|
||||
From: Eric Dumazet <edumazet@google.com>
|
||||
Date: Sat, 4 Jun 2016 12:55:13 -0700
|
||||
Subject: [PATCH] fq_codel: fix NET_XMIT_CN behavior
|
||||
|
||||
My prior attempt to fix the backlogs of parents failed.
|
||||
|
||||
If we return NET_XMIT_CN, our parents wont increase their backlog,
|
||||
so our qdisc_tree_reduce_backlog() should take this into account.
|
||||
|
||||
v2: Florian Westphal pointed out that we could drop the packet,
|
||||
so we need to save qdisc_pkt_len(skb) in a temp variable before
|
||||
calling fq_codel_drop()
|
||||
|
||||
Fixes: 9d18562a2278 ("fq_codel: add batch ability to fq_codel_drop()")
|
||||
Fixes: 2ccccf5fb43f ("net_sched: update hierarchical backlog too")
|
||||
Reported-by: Stas Nichiporovich <stasn77@gmail.com>
|
||||
Signed-off-by: Eric Dumazet <edumazet@google.com>
|
||||
Cc: WANG Cong <xiyou.wangcong@gmail.com>
|
||||
Cc: Jamal Hadi Salim <jhs@mojatatu.com>
|
||||
---
|
||||
|
||||
--- a/net/sched/sch_fq_codel.c
|
||||
+++ b/net/sched/sch_fq_codel.c
|
||||
@@ -197,6 +197,7 @@ static int fq_codel_enqueue(struct sk_bu
|
||||
unsigned int idx, prev_backlog, prev_qlen;
|
||||
struct fq_codel_flow *flow;
|
||||
int uninitialized_var(ret);
|
||||
+ unsigned int pkt_len;
|
||||
bool memory_limited;
|
||||
|
||||
idx = fq_codel_classify(skb, sch, &ret);
|
||||
@@ -228,6 +229,8 @@ static int fq_codel_enqueue(struct sk_bu
|
||||
prev_backlog = sch->qstats.backlog;
|
||||
prev_qlen = sch->q.qlen;
|
||||
|
||||
+ /* save this packet length as it might be dropped by fq_codel_drop() */
|
||||
+ pkt_len = qdisc_pkt_len(skb);
|
||||
/* fq_codel_drop() is quite expensive, as it performs a linear search
|
||||
* in q->backlogs[] to find a fat flow.
|
||||
* So instead of dropping a single packet, drop half of its backlog
|
||||
@@ -235,14 +238,23 @@ static int fq_codel_enqueue(struct sk_bu
|
||||
*/
|
||||
ret = fq_codel_drop(sch, q->drop_batch_size);
|
||||
|
||||
- q->drop_overlimit += prev_qlen - sch->q.qlen;
|
||||
+ prev_qlen -= sch->q.qlen;
|
||||
+ prev_backlog -= sch->qstats.backlog;
|
||||
+ q->drop_overlimit += prev_qlen;
|
||||
if (memory_limited)
|
||||
- q->drop_overmemory += prev_qlen - sch->q.qlen;
|
||||
- /* As we dropped packet(s), better let upper stack know this */
|
||||
- qdisc_tree_reduce_backlog(sch, prev_qlen - sch->q.qlen,
|
||||
- prev_backlog - sch->qstats.backlog);
|
||||
+ q->drop_overmemory += prev_qlen;
|
||||
|
||||
- return ret == idx ? NET_XMIT_CN : NET_XMIT_SUCCESS;
|
||||
+ /* As we dropped packet(s), better let upper stack know this.
|
||||
+ * If we dropped a packet for this flow, return NET_XMIT_CN,
|
||||
+ * but in this case, our parents wont increase their backlogs.
|
||||
+ */
|
||||
+ if (ret == idx) {
|
||||
+ qdisc_tree_reduce_backlog(sch, prev_qlen - 1,
|
||||
+ prev_backlog - pkt_len);
|
||||
+ return NET_XMIT_CN;
|
||||
+ }
|
||||
+ qdisc_tree_reduce_backlog(sch, prev_qlen, prev_backlog);
|
||||
+ return NET_XMIT_SUCCESS;
|
||||
}
|
||||
|
||||
/* This is the specific function called from codel_dequeue()
|
@ -1,39 +0,0 @@
|
||||
From 2c81de771f38e54324ede3f24118f4852570b384 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
|
||||
Date: Thu, 26 Nov 2015 09:05:04 +0100
|
||||
Subject: [PATCH] mtd: spi-nor: include mtd.h header for struct mtd_info
|
||||
definition
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
So far struct spi_nor was using just a pointer to struct mtd_info so it
|
||||
wasn't needed to have it fully defined there. After recent change we
|
||||
embed whole struct so we need to include a proper header.
|
||||
|
||||
Fixes: 1976367173a4 ("mtd: spi-nor: embed struct mtd_info within struct spi_nor")
|
||||
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
|
||||
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
|
||||
---
|
||||
include/linux/mtd/spi-nor.h | 3 +--
|
||||
1 file changed, 1 insertion(+), 2 deletions(-)
|
||||
|
||||
--- a/include/linux/mtd/spi-nor.h
|
||||
+++ b/include/linux/mtd/spi-nor.h
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/mtd/cfi.h>
|
||||
+#include <linux/mtd/mtd.h>
|
||||
|
||||
/*
|
||||
* Manufacturer IDs
|
||||
@@ -117,8 +118,6 @@ enum spi_nor_option_flags {
|
||||
SNOR_F_USE_FSR = BIT(0),
|
||||
};
|
||||
|
||||
-struct mtd_info;
|
||||
-
|
||||
/**
|
||||
* struct spi_nor - Structure for defining a the SPI NOR layer
|
||||
* @mtd: point to a mtd_info structure
|
@ -1,138 +0,0 @@
|
||||
From 5651d6aaf489d1db48c253cf884b40214e91c2c5 Mon Sep 17 00:00:00 2001
|
||||
From: Brian Norris <computersforpeace@gmail.com>
|
||||
Date: Fri, 26 Feb 2016 11:50:28 +0100
|
||||
Subject: [PATCH] mtd: bcm47xxsflash: use ioremap_cache() instead of
|
||||
KSEG0ADDR()
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Using KSEG0ADDR makes code highly MIPS dependent and not portable.
|
||||
Thanks to the fix a68f376 ("MIPS: io.h: Define `ioremap_cache'") we can
|
||||
use ioremap_cache which is generic and supported on MIPS as well now.
|
||||
|
||||
KSEG0ADDR was translating 0x1c000000 into 0x9c000000. With ioremap_cache
|
||||
we use MIPS's __ioremap (and then remap_area_pages). This results in
|
||||
different address (e.g. 0xc0080000) but it still should be cached as
|
||||
expected and it was successfully tested with BCM47186B0.
|
||||
|
||||
Other than that drivers/bcma/driver_chipcommon_sflash.c nicely setups a
|
||||
struct resource for access window, but we wren't using it. Use it now
|
||||
and drop duplicated info.
|
||||
|
||||
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
|
||||
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
|
||||
---
|
||||
|
||||
--- a/drivers/bcma/driver_chipcommon_sflash.c
|
||||
+++ b/drivers/bcma/driver_chipcommon_sflash.c
|
||||
@@ -146,7 +146,6 @@ int bcma_sflash_init(struct bcma_drv_cc
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
- sflash->window = BCMA_SOC_FLASH2;
|
||||
sflash->blocksize = e->blocksize;
|
||||
sflash->numblocks = e->numblocks;
|
||||
sflash->size = sflash->blocksize * sflash->numblocks;
|
||||
--- a/drivers/mtd/devices/bcm47xxsflash.c
|
||||
+++ b/drivers/mtd/devices/bcm47xxsflash.c
|
||||
@@ -2,6 +2,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
+#include <linux/ioport.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/bcma/bcma.h>
|
||||
@@ -109,8 +110,7 @@ static int bcm47xxsflash_read(struct mtd
|
||||
if ((from + len) > mtd->size)
|
||||
return -EINVAL;
|
||||
|
||||
- memcpy_fromio(buf, (void __iomem *)KSEG0ADDR(b47s->window + from),
|
||||
- len);
|
||||
+ memcpy_fromio(buf, b47s->window + from, len);
|
||||
*retlen = len;
|
||||
|
||||
return len;
|
||||
@@ -275,15 +275,33 @@ static void bcm47xxsflash_bcma_cc_write(
|
||||
|
||||
static int bcm47xxsflash_bcma_probe(struct platform_device *pdev)
|
||||
{
|
||||
- struct bcma_sflash *sflash = dev_get_platdata(&pdev->dev);
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ struct bcma_sflash *sflash = dev_get_platdata(dev);
|
||||
struct bcm47xxsflash *b47s;
|
||||
+ struct resource *res;
|
||||
int err;
|
||||
|
||||
- b47s = devm_kzalloc(&pdev->dev, sizeof(*b47s), GFP_KERNEL);
|
||||
+ b47s = devm_kzalloc(dev, sizeof(*b47s), GFP_KERNEL);
|
||||
if (!b47s)
|
||||
return -ENOMEM;
|
||||
sflash->priv = b47s;
|
||||
|
||||
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
+ if (!res) {
|
||||
+ dev_err(dev, "invalid resource\n");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ if (!devm_request_mem_region(dev, res->start, resource_size(res),
|
||||
+ res->name)) {
|
||||
+ dev_err(dev, "can't request region for resource %pR\n", res);
|
||||
+ return -EBUSY;
|
||||
+ }
|
||||
+ b47s->window = ioremap_cache(res->start, resource_size(res));
|
||||
+ if (!b47s->window) {
|
||||
+ dev_err(dev, "ioremap failed for resource %pR\n", res);
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+
|
||||
b47s->bcma_cc = container_of(sflash, struct bcma_drv_cc, sflash);
|
||||
b47s->cc_read = bcm47xxsflash_bcma_cc_read;
|
||||
b47s->cc_write = bcm47xxsflash_bcma_cc_write;
|
||||
@@ -297,7 +315,6 @@ static int bcm47xxsflash_bcma_probe(stru
|
||||
break;
|
||||
}
|
||||
|
||||
- b47s->window = sflash->window;
|
||||
b47s->blocksize = sflash->blocksize;
|
||||
b47s->numblocks = sflash->numblocks;
|
||||
b47s->size = sflash->size;
|
||||
@@ -306,6 +323,7 @@ static int bcm47xxsflash_bcma_probe(stru
|
||||
err = mtd_device_parse_register(&b47s->mtd, probes, NULL, NULL, 0);
|
||||
if (err) {
|
||||
pr_err("Failed to register MTD device: %d\n", err);
|
||||
+ iounmap(b47s->window);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -321,6 +339,7 @@ static int bcm47xxsflash_bcma_remove(str
|
||||
struct bcm47xxsflash *b47s = sflash->priv;
|
||||
|
||||
mtd_device_unregister(&b47s->mtd);
|
||||
+ iounmap(b47s->window);
|
||||
|
||||
return 0;
|
||||
}
|
||||
--- a/drivers/mtd/devices/bcm47xxsflash.h
|
||||
+++ b/drivers/mtd/devices/bcm47xxsflash.h
|
||||
@@ -65,7 +65,8 @@ struct bcm47xxsflash {
|
||||
|
||||
enum bcm47xxsflash_type type;
|
||||
|
||||
- u32 window;
|
||||
+ void __iomem *window;
|
||||
+
|
||||
u32 blocksize;
|
||||
u16 numblocks;
|
||||
u32 size;
|
||||
--- a/include/linux/bcma/bcma_driver_chipcommon.h
|
||||
+++ b/include/linux/bcma/bcma_driver_chipcommon.h
|
||||
@@ -588,7 +588,6 @@ struct bcma_pflash {
|
||||
#ifdef CONFIG_BCMA_SFLASH
|
||||
struct bcma_sflash {
|
||||
bool present;
|
||||
- u32 window;
|
||||
u32 blocksize;
|
||||
u16 numblocks;
|
||||
u32 size;
|
@ -1,41 +0,0 @@
|
||||
From efacc699139e13f9d3ed8b47df92acb88ff8479f Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
|
||||
Date: Tue, 19 Jul 2016 09:08:32 +0200
|
||||
Subject: [PATCH] mtd: add arch dependency for MTD_BCM47XXSFLASH symbol
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
We dropped strict MIPS dependency for bcm47xxsflash driver in:
|
||||
commit 5651d6aaf489 ("mtd: bcm47xxsflash: use ioremap_cache() instead of
|
||||
KSEG0ADDR()") but using ioremap_cache still limits building it to few
|
||||
selected architectures only.
|
||||
|
||||
A recent commit 57d8f7dd2132 ("bcma: allow enabling serial flash support
|
||||
on non-MIPS SoCs") automatically dropped MIPS dependency for
|
||||
MTD_BCM47XXSFLASH which broke building e.g. on powerpc and cris.
|
||||
|
||||
The bcma change is alright as it doesn't break building bcma code in any
|
||||
way. MTD_BCM47XXSFLASH on the other hand should be limited to archs
|
||||
which need it and can build it (by providing ioremap_cache).
|
||||
|
||||
Fixes: 57d8f7dd2132 ("bcma: allow enabling serial flash support on non-MIPS SoCs")
|
||||
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
|
||||
Cc: Brian Norris <computersforpeace@gmail.com>
|
||||
Acked-by: Brian Norris <computersforpeace@gmail.com>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
drivers/mtd/devices/Kconfig | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/mtd/devices/Kconfig
|
||||
+++ b/drivers/mtd/devices/Kconfig
|
||||
@@ -114,7 +114,7 @@ config MTD_SST25L
|
||||
|
||||
config MTD_BCM47XXSFLASH
|
||||
tristate "R/O support for serial flash on BCMA bus"
|
||||
- depends on BCMA_SFLASH
|
||||
+ depends on BCMA_SFLASH && (MIPS || ARM)
|
||||
help
|
||||
BCMA bus can have various flash memories attached, they are
|
||||
registered by bcma as platform devices. This enables driver for
|
@ -1,59 +0,0 @@
|
||||
From 64ad46379fcf14f437553f654d1adcd3d0e0d7f9 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Date: Mon, 15 Aug 2016 14:21:28 +0200
|
||||
Subject: [PATCH] mtd: bcm47xxsflash: use uncached MMIO access for BCM53573
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
BCM53573 is a new series of Broadcom's SoCs. It's based on ARM and uses
|
||||
this old ChipCommon-based flash access. Early tests resulted in flash
|
||||
corruptions that were tracked down to using cached MMIO for flash read
|
||||
access. Switch to ioremap_nocache conditionally to support BCM53573 and
|
||||
don't break performance on old MIPS devices.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
Reviewed-by: Boris Brezillon <boris.brezillon@free-electrons.com>
|
||||
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
|
||||
---
|
||||
drivers/mtd/devices/bcm47xxsflash.c | 24 +++++++++++++++++++-----
|
||||
1 file changed, 19 insertions(+), 5 deletions(-)
|
||||
|
||||
--- a/drivers/mtd/devices/bcm47xxsflash.c
|
||||
+++ b/drivers/mtd/devices/bcm47xxsflash.c
|
||||
@@ -296,16 +296,30 @@ static int bcm47xxsflash_bcma_probe(stru
|
||||
dev_err(dev, "can't request region for resource %pR\n", res);
|
||||
return -EBUSY;
|
||||
}
|
||||
- b47s->window = ioremap_cache(res->start, resource_size(res));
|
||||
- if (!b47s->window) {
|
||||
- dev_err(dev, "ioremap failed for resource %pR\n", res);
|
||||
- return -ENOMEM;
|
||||
- }
|
||||
|
||||
b47s->bcma_cc = container_of(sflash, struct bcma_drv_cc, sflash);
|
||||
b47s->cc_read = bcm47xxsflash_bcma_cc_read;
|
||||
b47s->cc_write = bcm47xxsflash_bcma_cc_write;
|
||||
|
||||
+ /*
|
||||
+ * On old MIPS devices cache was magically invalidated when needed,
|
||||
+ * allowing us to use cached access and gain some performance. Trying
|
||||
+ * the same on ARM based BCM53573 results in flash corruptions, we need
|
||||
+ * to use uncached access for it.
|
||||
+ *
|
||||
+ * It may be arch specific, but right now there is only 1 ARM SoC using
|
||||
+ * this driver, so let's follow Broadcom's reference code and check
|
||||
+ * ChipCommon revision.
|
||||
+ */
|
||||
+ if (b47s->bcma_cc->core->id.rev == 54)
|
||||
+ b47s->window = ioremap_nocache(res->start, resource_size(res));
|
||||
+ else
|
||||
+ b47s->window = ioremap_cache(res->start, resource_size(res));
|
||||
+ if (!b47s->window) {
|
||||
+ dev_err(dev, "ioremap failed for resource %pR\n", res);
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+
|
||||
switch (b47s->bcma_cc->capabilities & BCMA_CC_CAP_FLASHT) {
|
||||
case BCMA_CC_FLASHT_STSER:
|
||||
b47s->type = BCM47XXSFLASH_TYPE_ST;
|
@ -1,63 +0,0 @@
|
||||
From be5e5099183301fb7920f8f6b66bd3ac1f820a97 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Date: Mon, 16 Jan 2017 17:28:18 +0100
|
||||
Subject: [PATCH] mtd: bcm47xxsflash: use platform_(set|get)_drvdata
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
We have generic place & helpers for storing platform driver data so
|
||||
there is no reason for using custom priv pointer.
|
||||
|
||||
This allows cleaning up struct bcma_sflash from unneeded fields.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
Acked-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
Acked-by: Boris Brezillon <boris.brezillon@free-electrons.com>
|
||||
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
|
||||
---
|
||||
drivers/mtd/devices/bcm47xxsflash.c | 6 +++---
|
||||
include/linux/bcma/bcma_driver_chipcommon.h | 3 ---
|
||||
2 files changed, 3 insertions(+), 6 deletions(-)
|
||||
|
||||
--- a/drivers/mtd/devices/bcm47xxsflash.c
|
||||
+++ b/drivers/mtd/devices/bcm47xxsflash.c
|
||||
@@ -284,7 +284,6 @@ static int bcm47xxsflash_bcma_probe(stru
|
||||
b47s = devm_kzalloc(dev, sizeof(*b47s), GFP_KERNEL);
|
||||
if (!b47s)
|
||||
return -ENOMEM;
|
||||
- sflash->priv = b47s;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
@@ -334,6 +333,8 @@ static int bcm47xxsflash_bcma_probe(stru
|
||||
b47s->size = sflash->size;
|
||||
bcm47xxsflash_fill_mtd(b47s, &pdev->dev);
|
||||
|
||||
+ platform_set_drvdata(pdev, b47s);
|
||||
+
|
||||
err = mtd_device_parse_register(&b47s->mtd, probes, NULL, NULL, 0);
|
||||
if (err) {
|
||||
pr_err("Failed to register MTD device: %d\n", err);
|
||||
@@ -349,8 +350,7 @@ static int bcm47xxsflash_bcma_probe(stru
|
||||
|
||||
static int bcm47xxsflash_bcma_remove(struct platform_device *pdev)
|
||||
{
|
||||
- struct bcma_sflash *sflash = dev_get_platdata(&pdev->dev);
|
||||
- struct bcm47xxsflash *b47s = sflash->priv;
|
||||
+ struct bcm47xxsflash *b47s = platform_get_drvdata(pdev);
|
||||
|
||||
mtd_device_unregister(&b47s->mtd);
|
||||
iounmap(b47s->window);
|
||||
--- a/include/linux/bcma/bcma_driver_chipcommon.h
|
||||
+++ b/include/linux/bcma/bcma_driver_chipcommon.h
|
||||
@@ -591,9 +591,6 @@ struct bcma_sflash {
|
||||
u32 blocksize;
|
||||
u16 numblocks;
|
||||
u32 size;
|
||||
-
|
||||
- struct mtd_info *mtd;
|
||||
- void *priv;
|
||||
};
|
||||
#endif
|
||||
|
@ -1,81 +0,0 @@
|
||||
From ccc38234fdc70120be79e7fb2df5c27ca5cd4c8a Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Date: Wed, 8 Feb 2017 23:53:44 +0100
|
||||
Subject: [PATCH] mtd: bcm47xxsflash: support reading flash out of mapping
|
||||
window
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
For reading flash content we use MMIO but it's possible to read only
|
||||
first 16 MiB this way. It's simply an arch design/limitation.
|
||||
To support flash sizes bigger than 16 MiB implement indirect access
|
||||
using ChipCommon registers.
|
||||
This has been tested using MX25L25635F.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
Acked-by: Marek Vasut <marek.vasut@gmail.com>
|
||||
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
|
||||
---
|
||||
drivers/mtd/devices/bcm47xxsflash.c | 24 +++++++++++++++++++++---
|
||||
drivers/mtd/devices/bcm47xxsflash.h | 3 +++
|
||||
2 files changed, 24 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/drivers/mtd/devices/bcm47xxsflash.c
|
||||
+++ b/drivers/mtd/devices/bcm47xxsflash.c
|
||||
@@ -105,15 +105,33 @@ static int bcm47xxsflash_read(struct mtd
|
||||
size_t *retlen, u_char *buf)
|
||||
{
|
||||
struct bcm47xxsflash *b47s = mtd->priv;
|
||||
+ size_t orig_len = len;
|
||||
|
||||
/* Check address range */
|
||||
if ((from + len) > mtd->size)
|
||||
return -EINVAL;
|
||||
|
||||
- memcpy_fromio(buf, b47s->window + from, len);
|
||||
- *retlen = len;
|
||||
+ /* Read as much as possible using fast MMIO window */
|
||||
+ if (from < BCM47XXSFLASH_WINDOW_SZ) {
|
||||
+ size_t memcpy_len;
|
||||
|
||||
- return len;
|
||||
+ memcpy_len = min(len, (size_t)(BCM47XXSFLASH_WINDOW_SZ - from));
|
||||
+ memcpy_fromio(buf, b47s->window + from, memcpy_len);
|
||||
+ from += memcpy_len;
|
||||
+ len -= memcpy_len;
|
||||
+ buf += memcpy_len;
|
||||
+ }
|
||||
+
|
||||
+ /* Use indirect access for content out of the window */
|
||||
+ for (; len; len--) {
|
||||
+ b47s->cc_write(b47s, BCMA_CC_FLASHADDR, from++);
|
||||
+ bcm47xxsflash_cmd(b47s, OPCODE_ST_READ4B);
|
||||
+ *buf++ = b47s->cc_read(b47s, BCMA_CC_FLASHDATA);
|
||||
+ }
|
||||
+
|
||||
+ *retlen = orig_len;
|
||||
+
|
||||
+ return orig_len;
|
||||
}
|
||||
|
||||
static int bcm47xxsflash_write_st(struct mtd_info *mtd, u32 offset, size_t len,
|
||||
--- a/drivers/mtd/devices/bcm47xxsflash.h
|
||||
+++ b/drivers/mtd/devices/bcm47xxsflash.h
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
#include <linux/mtd/mtd.h>
|
||||
|
||||
+#define BCM47XXSFLASH_WINDOW_SZ SZ_16M
|
||||
+
|
||||
/* Used for ST flashes only. */
|
||||
#define OPCODE_ST_WREN 0x0006 /* Write Enable */
|
||||
#define OPCODE_ST_WRDIS 0x0004 /* Write Disable */
|
||||
@@ -16,6 +18,7 @@
|
||||
#define OPCODE_ST_RES 0x03ab /* Read Electronic Signature */
|
||||
#define OPCODE_ST_CSA 0x1000 /* Keep chip select asserted */
|
||||
#define OPCODE_ST_SSE 0x0220 /* Sub-sector Erase */
|
||||
+#define OPCODE_ST_READ4B 0x6313 /* Read Data Bytes in 4Byte addressing mode */
|
||||
|
||||
/* Used for Atmel flashes only. */
|
||||
#define OPCODE_AT_READ 0x07e8
|
@ -1,180 +0,0 @@
|
||||
From b522d7b0ebe3539340c2a6d46d787ae3d33bcb92 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Date: Tue, 10 Jan 2017 23:15:24 +0100
|
||||
Subject: [PATCH] mtd: bcm47xxpart: move TRX parsing code to separated function
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
This change simplifies main parsing loop logic a bit. In future it may
|
||||
be useful for moving TRX support to separated module / parser (if we
|
||||
implement support for them at some point).
|
||||
Finally parsing TRX at the end puts us in a better position as we have
|
||||
better flash layout knowledge. It may be useful e.g. if it appears there
|
||||
is more than 1 TRX partition.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
Acked-by: Marek Vasut <marek.vasut@gmail.com>
|
||||
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
|
||||
---
|
||||
drivers/mtd/bcm47xxpart.c | 121 ++++++++++++++++++++++++++++------------------
|
||||
1 file changed, 74 insertions(+), 47 deletions(-)
|
||||
|
||||
--- a/drivers/mtd/bcm47xxpart.c
|
||||
+++ b/drivers/mtd/bcm47xxpart.c
|
||||
@@ -83,6 +83,67 @@ out_default:
|
||||
return "rootfs";
|
||||
}
|
||||
|
||||
+static int bcm47xxpart_parse_trx(struct mtd_info *master,
|
||||
+ struct mtd_partition *trx,
|
||||
+ struct mtd_partition *parts,
|
||||
+ size_t parts_len)
|
||||
+{
|
||||
+ struct trx_header header;
|
||||
+ size_t bytes_read;
|
||||
+ int curr_part = 0;
|
||||
+ int i, err;
|
||||
+
|
||||
+ if (parts_len < 3) {
|
||||
+ pr_warn("No enough space to add TRX partitions!\n");
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+
|
||||
+ err = mtd_read(master, trx->offset, sizeof(header), &bytes_read,
|
||||
+ (uint8_t *)&header);
|
||||
+ if (err && !mtd_is_bitflip(err)) {
|
||||
+ pr_err("mtd_read error while reading TRX header: %d\n", err);
|
||||
+ return err;
|
||||
+ }
|
||||
+
|
||||
+ i = 0;
|
||||
+
|
||||
+ /* We have LZMA loader if offset[2] points to sth */
|
||||
+ if (header.offset[2]) {
|
||||
+ bcm47xxpart_add_part(&parts[curr_part++], "loader",
|
||||
+ trx->offset + header.offset[i], 0);
|
||||
+ i++;
|
||||
+ }
|
||||
+
|
||||
+ if (header.offset[i]) {
|
||||
+ bcm47xxpart_add_part(&parts[curr_part++], "linux",
|
||||
+ trx->offset + header.offset[i], 0);
|
||||
+ i++;
|
||||
+ }
|
||||
+
|
||||
+ if (header.offset[i]) {
|
||||
+ size_t offset = trx->offset + header.offset[i];
|
||||
+ const char *name = bcm47xxpart_trx_data_part_name(master,
|
||||
+ offset);
|
||||
+
|
||||
+ bcm47xxpart_add_part(&parts[curr_part++], name, offset, 0);
|
||||
+ i++;
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * Assume that every partition ends at the beginning of the one it is
|
||||
+ * followed by.
|
||||
+ */
|
||||
+ for (i = 0; i < curr_part; i++) {
|
||||
+ u64 next_part_offset = (i < curr_part - 1) ?
|
||||
+ parts[i + 1].offset :
|
||||
+ trx->offset + trx->size;
|
||||
+
|
||||
+ parts[i].size = next_part_offset - parts[i].offset;
|
||||
+ }
|
||||
+
|
||||
+ return curr_part;
|
||||
+}
|
||||
+
|
||||
static int bcm47xxpart_parse(struct mtd_info *master,
|
||||
struct mtd_partition **pparts,
|
||||
struct mtd_part_parser_data *data)
|
||||
@@ -93,9 +154,7 @@ static int bcm47xxpart_parse(struct mtd_
|
||||
size_t bytes_read;
|
||||
uint32_t offset;
|
||||
uint32_t blocksize = master->erasesize;
|
||||
- struct trx_header *trx;
|
||||
int trx_part = -1;
|
||||
- int last_trx_part = -1;
|
||||
int possible_nvram_sizes[] = { 0x8000, 0xF000, 0x10000, };
|
||||
int err;
|
||||
|
||||
@@ -182,54 +241,14 @@ static int bcm47xxpart_parse(struct mtd_
|
||||
|
||||
/* TRX */
|
||||
if (buf[0x000 / 4] == TRX_MAGIC) {
|
||||
- if (BCM47XXPART_MAX_PARTS - curr_part < 4) {
|
||||
- pr_warn("Not enough partitions left to register trx, scanning stopped!\n");
|
||||
- break;
|
||||
- }
|
||||
-
|
||||
- trx = (struct trx_header *)buf;
|
||||
+ struct trx_header *trx;
|
||||
|
||||
trx_part = curr_part;
|
||||
bcm47xxpart_add_part(&parts[curr_part++], "firmware",
|
||||
offset, 0);
|
||||
|
||||
- i = 0;
|
||||
- /* We have LZMA loader if offset[2] points to sth */
|
||||
- if (trx->offset[2]) {
|
||||
- bcm47xxpart_add_part(&parts[curr_part++],
|
||||
- "loader",
|
||||
- offset + trx->offset[i],
|
||||
- 0);
|
||||
- i++;
|
||||
- }
|
||||
-
|
||||
- if (trx->offset[i]) {
|
||||
- bcm47xxpart_add_part(&parts[curr_part++],
|
||||
- "linux",
|
||||
- offset + trx->offset[i],
|
||||
- 0);
|
||||
- i++;
|
||||
- }
|
||||
-
|
||||
- /*
|
||||
- * Pure rootfs size is known and can be calculated as:
|
||||
- * trx->length - trx->offset[i]. We don't fill it as
|
||||
- * we want to have jffs2 (overlay) in the same mtd.
|
||||
- */
|
||||
- if (trx->offset[i]) {
|
||||
- const char *name;
|
||||
-
|
||||
- name = bcm47xxpart_trx_data_part_name(master, offset + trx->offset[i]);
|
||||
- bcm47xxpart_add_part(&parts[curr_part++],
|
||||
- name,
|
||||
- offset + trx->offset[i],
|
||||
- 0);
|
||||
- i++;
|
||||
- }
|
||||
-
|
||||
- last_trx_part = curr_part - 1;
|
||||
-
|
||||
/* Jump to the end of TRX */
|
||||
+ trx = (struct trx_header *)buf;
|
||||
offset = roundup(offset + trx->length, blocksize);
|
||||
/* Next loop iteration will increase the offset */
|
||||
offset -= blocksize;
|
||||
@@ -307,9 +326,17 @@ static int bcm47xxpart_parse(struct mtd_
|
||||
parts[i + 1].offset : master->size;
|
||||
|
||||
parts[i].size = next_part_offset - parts[i].offset;
|
||||
- if (i == last_trx_part && trx_part >= 0)
|
||||
- parts[trx_part].size = next_part_offset -
|
||||
- parts[trx_part].offset;
|
||||
+ }
|
||||
+
|
||||
+ /* If there was TRX parse it now */
|
||||
+ if (trx_part >= 0) {
|
||||
+ int num_parts;
|
||||
+
|
||||
+ num_parts = bcm47xxpart_parse_trx(master, &parts[trx_part],
|
||||
+ parts + curr_part,
|
||||
+ BCM47XXPART_MAX_PARTS - curr_part);
|
||||
+ if (num_parts > 0)
|
||||
+ curr_part += num_parts;
|
||||
}
|
||||
|
||||
*pparts = parts;
|
@ -1,112 +0,0 @@
|
||||
From 89a0d9a9f1941a086a82bc7cd73d275cec98ba14 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Date: Tue, 10 Jan 2017 23:15:25 +0100
|
||||
Subject: [PATCH] mtd: bcm47xxpart: support layouts with multiple TRX
|
||||
partitions
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Some devices may have an extra TRX partition used as failsafe one. If
|
||||
we detect such partition we should set a proper name for it and don't
|
||||
parse it.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
Acked-by: Marek Vasut <marek.vasut@gmail.com>
|
||||
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
|
||||
---
|
||||
drivers/mtd/bcm47xxpart.c | 56 ++++++++++++++++++++++++++++++++++++++---------
|
||||
1 file changed, 46 insertions(+), 10 deletions(-)
|
||||
|
||||
--- a/drivers/mtd/bcm47xxpart.c
|
||||
+++ b/drivers/mtd/bcm47xxpart.c
|
||||
@@ -9,6 +9,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
+#include <linux/bcm47xx_nvram.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
@@ -144,6 +145,30 @@ static int bcm47xxpart_parse_trx(struct
|
||||
return curr_part;
|
||||
}
|
||||
|
||||
+/**
|
||||
+ * bcm47xxpart_bootpartition - gets index of TRX partition used by bootloader
|
||||
+ *
|
||||
+ * Some devices may have more than one TRX partition. In such case one of them
|
||||
+ * is the main one and another a failsafe one. Bootloader may fallback to the
|
||||
+ * failsafe firmware if it detects corruption of the main image.
|
||||
+ *
|
||||
+ * This function provides info about currently used TRX partition. It's the one
|
||||
+ * containing kernel started by the bootloader.
|
||||
+ */
|
||||
+static int bcm47xxpart_bootpartition(void)
|
||||
+{
|
||||
+ char buf[4];
|
||||
+ int bootpartition;
|
||||
+
|
||||
+ /* Check CFE environment variable */
|
||||
+ if (bcm47xx_nvram_getenv("bootpartition", buf, sizeof(buf)) > 0) {
|
||||
+ if (!kstrtoint(buf, 0, &bootpartition))
|
||||
+ return bootpartition;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static int bcm47xxpart_parse(struct mtd_info *master,
|
||||
struct mtd_partition **pparts,
|
||||
struct mtd_part_parser_data *data)
|
||||
@@ -154,7 +179,8 @@ static int bcm47xxpart_parse(struct mtd_
|
||||
size_t bytes_read;
|
||||
uint32_t offset;
|
||||
uint32_t blocksize = master->erasesize;
|
||||
- int trx_part = -1;
|
||||
+ int trx_parts[2]; /* Array with indexes of TRX partitions */
|
||||
+ int trx_num = 0; /* Number of found TRX partitions */
|
||||
int possible_nvram_sizes[] = { 0x8000, 0xF000, 0x10000, };
|
||||
int err;
|
||||
|
||||
@@ -243,7 +269,11 @@ static int bcm47xxpart_parse(struct mtd_
|
||||
if (buf[0x000 / 4] == TRX_MAGIC) {
|
||||
struct trx_header *trx;
|
||||
|
||||
- trx_part = curr_part;
|
||||
+ if (trx_num >= ARRAY_SIZE(trx_parts))
|
||||
+ pr_warn("No enough space to store another TRX found at 0x%X\n",
|
||||
+ offset);
|
||||
+ else
|
||||
+ trx_parts[trx_num++] = curr_part;
|
||||
bcm47xxpart_add_part(&parts[curr_part++], "firmware",
|
||||
offset, 0);
|
||||
|
||||
@@ -329,14 +359,20 @@ static int bcm47xxpart_parse(struct mtd_
|
||||
}
|
||||
|
||||
/* If there was TRX parse it now */
|
||||
- if (trx_part >= 0) {
|
||||
- int num_parts;
|
||||
+ for (i = 0; i < trx_num; i++) {
|
||||
+ struct mtd_partition *trx = &parts[trx_parts[i]];
|
||||
|
||||
- num_parts = bcm47xxpart_parse_trx(master, &parts[trx_part],
|
||||
- parts + curr_part,
|
||||
- BCM47XXPART_MAX_PARTS - curr_part);
|
||||
- if (num_parts > 0)
|
||||
- curr_part += num_parts;
|
||||
+ if (i == bcm47xxpart_bootpartition()) {
|
||||
+ int num_parts;
|
||||
+
|
||||
+ num_parts = bcm47xxpart_parse_trx(master, trx,
|
||||
+ parts + curr_part,
|
||||
+ BCM47XXPART_MAX_PARTS - curr_part);
|
||||
+ if (num_parts > 0)
|
||||
+ curr_part += num_parts;
|
||||
+ } else {
|
||||
+ trx->name = "failsafe";
|
||||
+ }
|
||||
}
|
||||
|
||||
*pparts = parts;
|
@ -1,70 +0,0 @@
|
||||
From 237ea0d4762cc14d0fc80e80d61f0f08e1050c7f Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Date: Thu, 12 Apr 2018 07:24:52 +0200
|
||||
Subject: [PATCH] mtd: bcm47xxpart: improve handling TRX partition size
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
When bcm47xxpart finds a TRX partition (container) it's supposed to jump
|
||||
to the end of it and keep looking for more partitions. TRX and its
|
||||
subpartitions are handled by a separate parser.
|
||||
|
||||
The problem with old code was relying on the length specified in a TRX
|
||||
header. That isn't reliable as TRX is commonly modified to have checksum
|
||||
cover only non-changing subpartitions. Otherwise modifying e.g. a rootfs
|
||||
would result in CRC32 mismatch and bootloader refusing to boot a
|
||||
firmware.
|
||||
|
||||
Fix it by trying better to figure out a real TRX size. We can securely
|
||||
assume that TRX has to cover all subpartitions and the last one is at
|
||||
least of a block size in size. Then compare it with a length field.
|
||||
|
||||
This makes code more optimal & reliable thanks to skipping data that
|
||||
shouldn't be parsed.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
|
||||
---
|
||||
drivers/mtd/bcm47xxpart.c | 22 ++++++++++++++++++----
|
||||
1 file changed, 18 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/drivers/mtd/bcm47xxpart.c
|
||||
+++ b/drivers/mtd/bcm47xxpart.c
|
||||
@@ -268,6 +268,8 @@ static int bcm47xxpart_parse(struct mtd_
|
||||
/* TRX */
|
||||
if (buf[0x000 / 4] == TRX_MAGIC) {
|
||||
struct trx_header *trx;
|
||||
+ uint32_t last_subpart;
|
||||
+ uint32_t trx_size;
|
||||
|
||||
if (trx_num >= ARRAY_SIZE(trx_parts))
|
||||
pr_warn("No enough space to store another TRX found at 0x%X\n",
|
||||
@@ -277,11 +279,23 @@ static int bcm47xxpart_parse(struct mtd_
|
||||
bcm47xxpart_add_part(&parts[curr_part++], "firmware",
|
||||
offset, 0);
|
||||
|
||||
- /* Jump to the end of TRX */
|
||||
+ /*
|
||||
+ * Try to find TRX size. The "length" field isn't fully
|
||||
+ * reliable as it could be decreased to make CRC32 cover
|
||||
+ * only part of TRX data. It's commonly used as checksum
|
||||
+ * can't cover e.g. ever-changing rootfs partition.
|
||||
+ * Use offsets as helpers for assuming min TRX size.
|
||||
+ */
|
||||
trx = (struct trx_header *)buf;
|
||||
- offset = roundup(offset + trx->length, blocksize);
|
||||
- /* Next loop iteration will increase the offset */
|
||||
- offset -= blocksize;
|
||||
+ last_subpart = max3(trx->offset[0], trx->offset[1],
|
||||
+ trx->offset[2]);
|
||||
+ trx_size = max(trx->length, last_subpart + blocksize);
|
||||
+
|
||||
+ /*
|
||||
+ * Skip the TRX data. Decrease offset by block size as
|
||||
+ * the next loop iteration will increase it.
|
||||
+ */
|
||||
+ offset += roundup(trx_size, blocksize) - blocksize;
|
||||
continue;
|
||||
}
|
||||
|
@ -1,27 +0,0 @@
|
||||
From 0501f2e5ff28a02295e42fc9e7164a20ef4c30d5 Mon Sep 17 00:00:00 2001
|
||||
From: Andreas Fenkart <afenkart@gmail.com>
|
||||
Date: Thu, 5 Nov 2015 10:04:23 +0100
|
||||
Subject: [PATCH] mtd: spi-nor: mx25l3205d/mx25l6405d: append SECT_4K
|
||||
|
||||
according datasheet both chips can erase 4kByte sectors individually
|
||||
|
||||
Signed-off-by: Andreas Fenkart <andreas.fenkart@dev.digitalstrom.org>
|
||||
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
|
||||
---
|
||||
drivers/mtd/spi-nor/spi-nor.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/mtd/spi-nor/spi-nor.c
|
||||
+++ b/drivers/mtd/spi-nor/spi-nor.c
|
||||
@@ -715,9 +715,9 @@ static const struct flash_info spi_nor_i
|
||||
{ "mx25l4005a", INFO(0xc22013, 0, 64 * 1024, 8, SECT_4K) },
|
||||
{ "mx25l8005", INFO(0xc22014, 0, 64 * 1024, 16, 0) },
|
||||
{ "mx25l1606e", INFO(0xc22015, 0, 64 * 1024, 32, SECT_4K) },
|
||||
- { "mx25l3205d", INFO(0xc22016, 0, 64 * 1024, 64, 0) },
|
||||
+ { "mx25l3205d", INFO(0xc22016, 0, 64 * 1024, 64, SECT_4K) },
|
||||
{ "mx25l3255e", INFO(0xc29e16, 0, 64 * 1024, 64, SECT_4K) },
|
||||
- { "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, 0) },
|
||||
+ { "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, SECT_4K) },
|
||||
{ "mx25u6435f", INFO(0xc22537, 0, 64 * 1024, 128, SECT_4K) },
|
||||
{ "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) },
|
||||
{ "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) },
|
@ -1,46 +0,0 @@
|
||||
From 08922f644878c9163ada8df3ef9def89be1d5e90 Mon Sep 17 00:00:00 2001
|
||||
From: Vignesh R <vigneshr@ti.com>
|
||||
Date: Tue, 29 Mar 2016 11:16:17 +0530
|
||||
Subject: [PATCH] mtd: devices: m25p80: add support for mmap read request
|
||||
|
||||
Certain SPI controllers may provide accelerated hardware interface to
|
||||
read from m25p80 type flash devices in order to provide better read
|
||||
performance. SPI core supports such devices with spi_flash_read() API.
|
||||
Call spi_flash_read(), if supported, to make use of such interface.
|
||||
|
||||
Signed-off-by: Vignesh R <vigneshr@ti.com>
|
||||
[Brian: add memset()]
|
||||
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
|
||||
---
|
||||
|
||||
--- a/drivers/mtd/devices/m25p80.c
|
||||
+++ b/drivers/mtd/devices/m25p80.c
|
||||
@@ -131,6 +131,28 @@ static int m25p80_read(struct spi_nor *n
|
||||
/* convert the dummy cycles to the number of bytes */
|
||||
dummy /= 8;
|
||||
|
||||
+ if (spi_flash_read_supported(spi)) {
|
||||
+ struct spi_flash_read_message msg;
|
||||
+ int ret;
|
||||
+
|
||||
+ memset(&msg, 0, sizeof(msg));
|
||||
+
|
||||
+ msg.buf = buf;
|
||||
+ msg.from = from;
|
||||
+ msg.len = len;
|
||||
+ msg.read_opcode = nor->read_opcode;
|
||||
+ msg.addr_width = nor->addr_width;
|
||||
+ msg.dummy_bytes = dummy;
|
||||
+ /* TODO: Support other combinations */
|
||||
+ msg.opcode_nbits = SPI_NBITS_SINGLE;
|
||||
+ msg.addr_nbits = SPI_NBITS_SINGLE;
|
||||
+ msg.data_nbits = m25p80_rx_nbits(nor);
|
||||
+
|
||||
+ ret = spi_flash_read(spi, &msg);
|
||||
+ *retlen = msg.retlen;
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
spi_message_init(&m);
|
||||
memset(t, 0, (sizeof t));
|
||||
|
@ -1,32 +0,0 @@
|
||||
From 1ae92642e5900316011736072b4fa91710840620 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Sat, 18 Jun 2016 17:53:45 +0200
|
||||
Subject: [PATCH] ubifs: Silence error output if MS_SILENT is set
|
||||
|
||||
This change completes commit
|
||||
90bea5a3f0 ("UBIFS: respect MS_SILENT mount flag")
|
||||
which already implements support for MS_SILENT except for that one
|
||||
error message which is still being displayed despite MS_SILENT being
|
||||
set. Suppress that error message as well in case MS_SILENT is set.
|
||||
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
[rw: massaged commit message]
|
||||
Signed-off-by: Richard Weinberger <richard@nod.at>
|
||||
---
|
||||
fs/ubifs/super.c | 5 +++--
|
||||
1 file changed, 3 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/fs/ubifs/super.c
|
||||
+++ b/fs/ubifs/super.c
|
||||
@@ -2107,8 +2107,9 @@ static struct dentry *ubifs_mount(struct
|
||||
*/
|
||||
ubi = open_ubi(name, UBI_READONLY);
|
||||
if (IS_ERR(ubi)) {
|
||||
- pr_err("UBIFS error (pid: %d): cannot open \"%s\", error %d",
|
||||
- current->pid, name, (int)PTR_ERR(ubi));
|
||||
+ if (!(flags & MS_SILENT))
|
||||
+ pr_err("UBIFS error (pid: %d): cannot open \"%s\", error %d",
|
||||
+ current->pid, name, (int)PTR_ERR(ubi));
|
||||
return ERR_CAST(ubi);
|
||||
}
|
||||
|
@ -1,54 +0,0 @@
|
||||
From dccbc9197d2c3614f2fd6811874e1d982e4415f0 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Tue, 19 Jul 2016 00:26:55 +0200
|
||||
Subject: [PATCH] ubifs: Silence early error messages if MS_SILENT is set
|
||||
|
||||
Probe-mounting a volume too small for UBIFS results in kernel log
|
||||
polution which might irritate users.
|
||||
Address this by silencing errors which may happen during boot if the
|
||||
rootfs is e.g. squashfs (and thus rather small) stored on a UBI volume.
|
||||
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
Signed-off-by: Richard Weinberger <richard@nod.at>
|
||||
---
|
||||
fs/ubifs/super.c | 14 +++++++-------
|
||||
1 file changed, 7 insertions(+), 7 deletions(-)
|
||||
|
||||
--- a/fs/ubifs/super.c
|
||||
+++ b/fs/ubifs/super.c
|
||||
@@ -520,19 +520,19 @@ static int init_constants_early(struct u
|
||||
c->max_write_shift = fls(c->max_write_size) - 1;
|
||||
|
||||
if (c->leb_size < UBIFS_MIN_LEB_SZ) {
|
||||
- ubifs_err(c, "too small LEBs (%d bytes), min. is %d bytes",
|
||||
- c->leb_size, UBIFS_MIN_LEB_SZ);
|
||||
+ ubifs_errc(c, "too small LEBs (%d bytes), min. is %d bytes",
|
||||
+ c->leb_size, UBIFS_MIN_LEB_SZ);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (c->leb_cnt < UBIFS_MIN_LEB_CNT) {
|
||||
- ubifs_err(c, "too few LEBs (%d), min. is %d",
|
||||
- c->leb_cnt, UBIFS_MIN_LEB_CNT);
|
||||
+ ubifs_errc(c, "too few LEBs (%d), min. is %d",
|
||||
+ c->leb_cnt, UBIFS_MIN_LEB_CNT);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!is_power_of_2(c->min_io_size)) {
|
||||
- ubifs_err(c, "bad min. I/O size %d", c->min_io_size);
|
||||
+ ubifs_errc(c, "bad min. I/O size %d", c->min_io_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -543,8 +543,8 @@ static int init_constants_early(struct u
|
||||
if (c->max_write_size < c->min_io_size ||
|
||||
c->max_write_size % c->min_io_size ||
|
||||
!is_power_of_2(c->max_write_size)) {
|
||||
- ubifs_err(c, "bad write buffer size %d for %d min. I/O unit",
|
||||
- c->max_write_size, c->min_io_size);
|
||||
+ ubifs_errc(c, "bad write buffer size %d for %d min. I/O unit",
|
||||
+ c->max_write_size, c->min_io_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -1,47 +0,0 @@
|
||||
From 76a4707de5e18dc32d9cb4e990686140c5664a15 Mon Sep 17 00:00:00 2001
|
||||
From: Brian Norris <computersforpeace@gmail.com>
|
||||
Date: Fri, 29 Jan 2016 11:25:35 -0800
|
||||
Subject: [PATCH] mtd: spi-nor: add SPI_NOR_HAS_LOCK flag
|
||||
|
||||
We can't determine this purely by manufacturer type (see commit
|
||||
67b9bcd36906 ("mtd: spi-nor: fix Spansion regressions (aliased with
|
||||
Winbond)")), and it's not autodetectable by anything like SFDP. So make
|
||||
a new flag for it.
|
||||
|
||||
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
|
||||
Reviewed-by: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
|
||||
Tested-by: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
|
||||
---
|
||||
drivers/mtd/spi-nor/spi-nor.c | 7 +++++--
|
||||
1 file changed, 5 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/mtd/spi-nor/spi-nor.c
|
||||
+++ b/drivers/mtd/spi-nor/spi-nor.c
|
||||
@@ -68,6 +68,7 @@ struct flash_info {
|
||||
#define SPI_NOR_DUAL_READ 0x20 /* Flash supports Dual Read */
|
||||
#define SPI_NOR_QUAD_READ 0x40 /* Flash supports Quad Read */
|
||||
#define USE_FSR 0x80 /* use flag status register */
|
||||
+#define SPI_NOR_HAS_LOCK 0x100 /* Flash supports lock/unlock via SR */
|
||||
};
|
||||
|
||||
#define JEDEC_MFR(info) ((info)->id[0])
|
||||
@@ -1163,7 +1164,8 @@ int spi_nor_scan(struct spi_nor *nor, co
|
||||
|
||||
if (JEDEC_MFR(info) == SNOR_MFR_ATMEL ||
|
||||
JEDEC_MFR(info) == SNOR_MFR_INTEL ||
|
||||
- JEDEC_MFR(info) == SNOR_MFR_SST) {
|
||||
+ JEDEC_MFR(info) == SNOR_MFR_SST ||
|
||||
+ info->flags & SPI_NOR_HAS_LOCK) {
|
||||
write_enable(nor);
|
||||
write_sr(nor, 0);
|
||||
}
|
||||
@@ -1179,7 +1181,8 @@ int spi_nor_scan(struct spi_nor *nor, co
|
||||
mtd->_read = spi_nor_read;
|
||||
|
||||
/* NOR protection support for STmicro/Micron chips and similar */
|
||||
- if (JEDEC_MFR(info) == SNOR_MFR_MICRON) {
|
||||
+ if (JEDEC_MFR(info) == SNOR_MFR_MICRON ||
|
||||
+ info->flags & SPI_NOR_HAS_LOCK) {
|
||||
nor->flash_lock = stm_lock;
|
||||
nor->flash_unlock = stm_unlock;
|
||||
nor->flash_is_locked = stm_is_locked;
|
@ -1,531 +0,0 @@
|
||||
Subject: netfilter: conntrack: cache route for forwarded connections
|
||||
|
||||
... to avoid per-packet FIB lookup if possible.
|
||||
|
||||
The cached dst is re-used provided the input interface
|
||||
is the same as that of the previous packet in the same direction.
|
||||
|
||||
If not, the cached dst is invalidated.
|
||||
|
||||
For ipv6 we also need to store sernum, else dst_check doesn't work,
|
||||
pointed out by Eric Dumazet.
|
||||
|
||||
This should speed up forwarding when conntrack is already in use
|
||||
anyway, especially when using reverse path filtering -- active RPF
|
||||
enforces two FIB lookups for each packet.
|
||||
|
||||
Before the routing cache removal this didn't matter since RPF was performed
|
||||
only when route cache didn't yield a result; but without route cache it
|
||||
comes at higher price.
|
||||
|
||||
Julian Anastasov suggested to add NETDEV_UNREGISTER handler to
|
||||
avoid holding on to dsts of 'frozen' conntracks.
|
||||
|
||||
Signed-off-by: Florian Westphal <fw@strlen.de>
|
||||
|
||||
--- a/include/net/netfilter/nf_conntrack_extend.h
|
||||
+++ b/include/net/netfilter/nf_conntrack_extend.h
|
||||
@@ -30,6 +30,9 @@ enum nf_ct_ext_id {
|
||||
#if IS_ENABLED(CONFIG_NETFILTER_SYNPROXY)
|
||||
NF_CT_EXT_SYNPROXY,
|
||||
#endif
|
||||
+#if IS_ENABLED(CONFIG_NF_CONNTRACK_RTCACHE)
|
||||
+ NF_CT_EXT_RTCACHE,
|
||||
+#endif
|
||||
NF_CT_EXT_NUM,
|
||||
};
|
||||
|
||||
@@ -43,6 +46,7 @@ enum nf_ct_ext_id {
|
||||
#define NF_CT_EXT_TIMEOUT_TYPE struct nf_conn_timeout
|
||||
#define NF_CT_EXT_LABELS_TYPE struct nf_conn_labels
|
||||
#define NF_CT_EXT_SYNPROXY_TYPE struct nf_conn_synproxy
|
||||
+#define NF_CT_EXT_RTCACHE_TYPE struct nf_conn_rtcache
|
||||
|
||||
/* Extensions: optional stuff which isn't permanently in struct. */
|
||||
struct nf_ct_ext {
|
||||
--- /dev/null
|
||||
+++ b/include/net/netfilter/nf_conntrack_rtcache.h
|
||||
@@ -0,0 +1,34 @@
|
||||
+#include <linux/gfp.h>
|
||||
+#include <net/netfilter/nf_conntrack.h>
|
||||
+#include <net/netfilter/nf_conntrack_extend.h>
|
||||
+
|
||||
+struct dst_entry;
|
||||
+
|
||||
+struct nf_conn_dst_cache {
|
||||
+ struct dst_entry *dst;
|
||||
+ int iif;
|
||||
+#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
|
||||
+ u32 cookie;
|
||||
+#endif
|
||||
+
|
||||
+};
|
||||
+
|
||||
+struct nf_conn_rtcache {
|
||||
+ struct nf_conn_dst_cache cached_dst[IP_CT_DIR_MAX];
|
||||
+};
|
||||
+
|
||||
+static inline
|
||||
+struct nf_conn_rtcache *nf_ct_rtcache_find(const struct nf_conn *ct)
|
||||
+{
|
||||
+#if IS_ENABLED(CONFIG_NF_CONNTRACK_RTCACHE)
|
||||
+ return nf_ct_ext_find(ct, NF_CT_EXT_RTCACHE);
|
||||
+#else
|
||||
+ return NULL;
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
+static inline int nf_conn_rtcache_iif_get(const struct nf_conn_rtcache *rtc,
|
||||
+ enum ip_conntrack_dir dir)
|
||||
+{
|
||||
+ return rtc->cached_dst[dir].iif;
|
||||
+}
|
||||
--- a/net/netfilter/Kconfig
|
||||
+++ b/net/netfilter/Kconfig
|
||||
@@ -114,6 +114,18 @@ config NF_CONNTRACK_EVENTS
|
||||
|
||||
If unsure, say `N'.
|
||||
|
||||
+config NF_CONNTRACK_RTCACHE
|
||||
+ tristate "Cache route entries in conntrack objects"
|
||||
+ depends on NETFILTER_ADVANCED
|
||||
+ depends on NF_CONNTRACK
|
||||
+ help
|
||||
+ If this option is enabled, the connection tracking code will
|
||||
+ cache routing information for each connection that is being
|
||||
+ forwarded, at a cost of 32 bytes per conntrack object.
|
||||
+
|
||||
+ To compile it as a module, choose M here. If unsure, say N.
|
||||
+ The module will be called nf_conntrack_rtcache.
|
||||
+
|
||||
config NF_CONNTRACK_TIMEOUT
|
||||
bool 'Connection tracking timeout'
|
||||
depends on NETFILTER_ADVANCED
|
||||
--- a/net/netfilter/Makefile
|
||||
+++ b/net/netfilter/Makefile
|
||||
@@ -16,6 +16,9 @@ obj-$(CONFIG_NETFILTER_NETLINK_LOG) += n
|
||||
# connection tracking
|
||||
obj-$(CONFIG_NF_CONNTRACK) += nf_conntrack.o
|
||||
|
||||
+# optional conntrack route cache extension
|
||||
+obj-$(CONFIG_NF_CONNTRACK_RTCACHE) += nf_conntrack_rtcache.o
|
||||
+
|
||||
# SCTP protocol connection tracking
|
||||
obj-$(CONFIG_NF_CT_PROTO_DCCP) += nf_conntrack_proto_dccp.o
|
||||
obj-$(CONFIG_NF_CT_PROTO_GRE) += nf_conntrack_proto_gre.o
|
||||
--- /dev/null
|
||||
+++ b/net/netfilter/nf_conntrack_rtcache.c
|
||||
@@ -0,0 +1,413 @@
|
||||
+/* route cache for netfilter.
|
||||
+ *
|
||||
+ * (C) 2014 Red Hat GmbH
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify
|
||||
+ * it under the terms of the GNU General Public License version 2 as
|
||||
+ * published by the Free Software Foundation.
|
||||
+ */
|
||||
+
|
||||
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
+
|
||||
+#include <linux/types.h>
|
||||
+#include <linux/netfilter.h>
|
||||
+#include <linux/skbuff.h>
|
||||
+#include <linux/stddef.h>
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/netdevice.h>
|
||||
+#include <linux/export.h>
|
||||
+#include <linux/module.h>
|
||||
+
|
||||
+#include <net/dst.h>
|
||||
+
|
||||
+#include <net/netfilter/nf_conntrack.h>
|
||||
+#include <net/netfilter/nf_conntrack_core.h>
|
||||
+#include <net/netfilter/nf_conntrack_extend.h>
|
||||
+#include <net/netfilter/nf_conntrack_rtcache.h>
|
||||
+
|
||||
+#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
|
||||
+#include <net/ip6_fib.h>
|
||||
+#endif
|
||||
+
|
||||
+static void __nf_conn_rtcache_destroy(struct nf_conn_rtcache *rtc,
|
||||
+ enum ip_conntrack_dir dir)
|
||||
+{
|
||||
+ struct dst_entry *dst = rtc->cached_dst[dir].dst;
|
||||
+
|
||||
+ dst_release(dst);
|
||||
+}
|
||||
+
|
||||
+static void nf_conn_rtcache_destroy(struct nf_conn *ct)
|
||||
+{
|
||||
+ struct nf_conn_rtcache *rtc = nf_ct_rtcache_find(ct);
|
||||
+
|
||||
+ if (!rtc)
|
||||
+ return;
|
||||
+
|
||||
+ __nf_conn_rtcache_destroy(rtc, IP_CT_DIR_ORIGINAL);
|
||||
+ __nf_conn_rtcache_destroy(rtc, IP_CT_DIR_REPLY);
|
||||
+}
|
||||
+
|
||||
+static void nf_ct_rtcache_ext_add(struct nf_conn *ct)
|
||||
+{
|
||||
+ struct nf_conn_rtcache *rtc;
|
||||
+
|
||||
+ rtc = nf_ct_ext_add(ct, NF_CT_EXT_RTCACHE, GFP_ATOMIC);
|
||||
+ if (rtc) {
|
||||
+ rtc->cached_dst[IP_CT_DIR_ORIGINAL].iif = -1;
|
||||
+ rtc->cached_dst[IP_CT_DIR_ORIGINAL].dst = NULL;
|
||||
+ rtc->cached_dst[IP_CT_DIR_REPLY].iif = -1;
|
||||
+ rtc->cached_dst[IP_CT_DIR_REPLY].dst = NULL;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static struct nf_conn_rtcache *nf_ct_rtcache_find_usable(struct nf_conn *ct)
|
||||
+{
|
||||
+ if (nf_ct_is_untracked(ct))
|
||||
+ return NULL;
|
||||
+ return nf_ct_rtcache_find(ct);
|
||||
+}
|
||||
+
|
||||
+static struct dst_entry *
|
||||
+nf_conn_rtcache_dst_get(const struct nf_conn_rtcache *rtc,
|
||||
+ enum ip_conntrack_dir dir)
|
||||
+{
|
||||
+ return rtc->cached_dst[dir].dst;
|
||||
+}
|
||||
+
|
||||
+static u32 nf_rtcache_get_cookie(int pf, const struct dst_entry *dst)
|
||||
+{
|
||||
+#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
|
||||
+ if (pf == NFPROTO_IPV6) {
|
||||
+ const struct rt6_info *rt = (const struct rt6_info *)dst;
|
||||
+
|
||||
+ if (rt->rt6i_node)
|
||||
+ return (u32)rt->rt6i_node->fn_sernum;
|
||||
+ }
|
||||
+#endif
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void nf_conn_rtcache_dst_set(int pf,
|
||||
+ struct nf_conn_rtcache *rtc,
|
||||
+ struct dst_entry *dst,
|
||||
+ enum ip_conntrack_dir dir, int iif)
|
||||
+{
|
||||
+ if (rtc->cached_dst[dir].iif != iif)
|
||||
+ rtc->cached_dst[dir].iif = iif;
|
||||
+
|
||||
+ if (rtc->cached_dst[dir].dst != dst) {
|
||||
+ struct dst_entry *old;
|
||||
+
|
||||
+ dst_hold(dst);
|
||||
+
|
||||
+ old = xchg(&rtc->cached_dst[dir].dst, dst);
|
||||
+ dst_release(old);
|
||||
+
|
||||
+#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
|
||||
+ if (pf == NFPROTO_IPV6)
|
||||
+ rtc->cached_dst[dir].cookie =
|
||||
+ nf_rtcache_get_cookie(pf, dst);
|
||||
+#endif
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void nf_conn_rtcache_dst_obsolete(struct nf_conn_rtcache *rtc,
|
||||
+ enum ip_conntrack_dir dir)
|
||||
+{
|
||||
+ struct dst_entry *old;
|
||||
+
|
||||
+ pr_debug("Invalidate iif %d for dir %d on cache %p\n",
|
||||
+ rtc->cached_dst[dir].iif, dir, rtc);
|
||||
+
|
||||
+ old = xchg(&rtc->cached_dst[dir].dst, NULL);
|
||||
+ dst_release(old);
|
||||
+ rtc->cached_dst[dir].iif = -1;
|
||||
+}
|
||||
+
|
||||
+static unsigned int nf_rtcache_in(u_int8_t pf,
|
||||
+ struct sk_buff *skb,
|
||||
+ const struct nf_hook_state *state)
|
||||
+{
|
||||
+ struct nf_conn_rtcache *rtc;
|
||||
+ enum ip_conntrack_info ctinfo;
|
||||
+ enum ip_conntrack_dir dir;
|
||||
+ struct dst_entry *dst;
|
||||
+ struct nf_conn *ct;
|
||||
+ int iif;
|
||||
+ u32 cookie;
|
||||
+
|
||||
+ if (skb_dst(skb) || skb->sk)
|
||||
+ return NF_ACCEPT;
|
||||
+
|
||||
+ ct = nf_ct_get(skb, &ctinfo);
|
||||
+ if (!ct)
|
||||
+ return NF_ACCEPT;
|
||||
+
|
||||
+ rtc = nf_ct_rtcache_find_usable(ct);
|
||||
+ if (!rtc)
|
||||
+ return NF_ACCEPT;
|
||||
+
|
||||
+ /* if iif changes, don't use cache and let ip stack
|
||||
+ * do route lookup.
|
||||
+ *
|
||||
+ * If rp_filter is enabled it might toss skb, so
|
||||
+ * we don't want to avoid these checks.
|
||||
+ */
|
||||
+ dir = CTINFO2DIR(ctinfo);
|
||||
+ iif = nf_conn_rtcache_iif_get(rtc, dir);
|
||||
+ if (state->in->ifindex != iif) {
|
||||
+ pr_debug("ct %p, iif %d, cached iif %d, skip cached entry\n",
|
||||
+ ct, iif, state->in->ifindex);
|
||||
+ return NF_ACCEPT;
|
||||
+ }
|
||||
+ dst = nf_conn_rtcache_dst_get(rtc, dir);
|
||||
+ if (dst == NULL)
|
||||
+ return NF_ACCEPT;
|
||||
+
|
||||
+ cookie = nf_rtcache_get_cookie(pf, dst);
|
||||
+
|
||||
+ dst = dst_check(dst, cookie);
|
||||
+ pr_debug("obtained dst %p for skb %p, cookie %d\n", dst, skb, cookie);
|
||||
+ if (likely(dst))
|
||||
+ skb_dst_set_noref(skb, dst);
|
||||
+ else
|
||||
+ nf_conn_rtcache_dst_obsolete(rtc, dir);
|
||||
+
|
||||
+ return NF_ACCEPT;
|
||||
+}
|
||||
+
|
||||
+static unsigned int nf_rtcache_forward(u_int8_t pf,
|
||||
+ struct sk_buff *skb,
|
||||
+ const struct nf_hook_state *state)
|
||||
+{
|
||||
+ struct nf_conn_rtcache *rtc;
|
||||
+ enum ip_conntrack_info ctinfo;
|
||||
+ enum ip_conntrack_dir dir;
|
||||
+ struct nf_conn *ct;
|
||||
+ struct dst_entry *dst = skb_dst(skb);
|
||||
+ int iif;
|
||||
+
|
||||
+ ct = nf_ct_get(skb, &ctinfo);
|
||||
+ if (!ct)
|
||||
+ return NF_ACCEPT;
|
||||
+
|
||||
+ if (dst && dst_xfrm(dst))
|
||||
+ return NF_ACCEPT;
|
||||
+
|
||||
+ if (!nf_ct_is_confirmed(ct)) {
|
||||
+ if (WARN_ON(nf_ct_rtcache_find(ct)))
|
||||
+ return NF_ACCEPT;
|
||||
+ nf_ct_rtcache_ext_add(ct);
|
||||
+ return NF_ACCEPT;
|
||||
+ }
|
||||
+
|
||||
+ rtc = nf_ct_rtcache_find_usable(ct);
|
||||
+ if (!rtc)
|
||||
+ return NF_ACCEPT;
|
||||
+
|
||||
+ dir = CTINFO2DIR(ctinfo);
|
||||
+ iif = nf_conn_rtcache_iif_get(rtc, dir);
|
||||
+ pr_debug("ct %p, skb %p, dir %d, iif %d, cached iif %d\n",
|
||||
+ ct, skb, dir, iif, state->in->ifindex);
|
||||
+ if (likely(state->in->ifindex == iif))
|
||||
+ return NF_ACCEPT;
|
||||
+
|
||||
+ nf_conn_rtcache_dst_set(pf, rtc, skb_dst(skb), dir, state->in->ifindex);
|
||||
+ return NF_ACCEPT;
|
||||
+}
|
||||
+
|
||||
+static unsigned int nf_rtcache_in4(void *priv,
|
||||
+ struct sk_buff *skb,
|
||||
+ const struct nf_hook_state *state)
|
||||
+{
|
||||
+ return nf_rtcache_in(NFPROTO_IPV4, skb, state);
|
||||
+}
|
||||
+
|
||||
+static unsigned int nf_rtcache_forward4(void *priv,
|
||||
+ struct sk_buff *skb,
|
||||
+ const struct nf_hook_state *state)
|
||||
+{
|
||||
+ return nf_rtcache_forward(NFPROTO_IPV4, skb, state);
|
||||
+}
|
||||
+
|
||||
+#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
|
||||
+static unsigned int nf_rtcache_in6(void *priv,
|
||||
+ struct sk_buff *skb,
|
||||
+ const struct nf_hook_state *state)
|
||||
+{
|
||||
+ return nf_rtcache_in(NFPROTO_IPV6, skb, state);
|
||||
+}
|
||||
+
|
||||
+static unsigned int nf_rtcache_forward6(void *priv,
|
||||
+ struct sk_buff *skb,
|
||||
+ const struct nf_hook_state *state)
|
||||
+{
|
||||
+ return nf_rtcache_forward(NFPROTO_IPV6, skb, state);
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
+static int nf_rtcache_dst_remove(struct nf_conn *ct, void *data)
|
||||
+{
|
||||
+ struct nf_conn_rtcache *rtc = nf_ct_rtcache_find(ct);
|
||||
+ struct net_device *dev = data;
|
||||
+
|
||||
+ if (!rtc)
|
||||
+ return 0;
|
||||
+
|
||||
+ if (dev->ifindex == rtc->cached_dst[IP_CT_DIR_ORIGINAL].iif ||
|
||||
+ dev->ifindex == rtc->cached_dst[IP_CT_DIR_REPLY].iif) {
|
||||
+ nf_conn_rtcache_dst_obsolete(rtc, IP_CT_DIR_ORIGINAL);
|
||||
+ nf_conn_rtcache_dst_obsolete(rtc, IP_CT_DIR_REPLY);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int nf_rtcache_netdev_event(struct notifier_block *this,
|
||||
+ unsigned long event, void *ptr)
|
||||
+{
|
||||
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
|
||||
+ struct net *net = dev_net(dev);
|
||||
+
|
||||
+ if (event == NETDEV_DOWN)
|
||||
+ nf_ct_iterate_cleanup(net, nf_rtcache_dst_remove, dev, 0, 0);
|
||||
+
|
||||
+ return NOTIFY_DONE;
|
||||
+}
|
||||
+
|
||||
+static struct notifier_block nf_rtcache_notifier = {
|
||||
+ .notifier_call = nf_rtcache_netdev_event,
|
||||
+};
|
||||
+
|
||||
+static struct nf_hook_ops rtcache_ops[] = {
|
||||
+ {
|
||||
+ .hook = nf_rtcache_in4,
|
||||
+ .pf = NFPROTO_IPV4,
|
||||
+ .hooknum = NF_INET_PRE_ROUTING,
|
||||
+ .priority = NF_IP_PRI_LAST,
|
||||
+ },
|
||||
+ {
|
||||
+ .hook = nf_rtcache_forward4,
|
||||
+ .pf = NFPROTO_IPV4,
|
||||
+ .hooknum = NF_INET_FORWARD,
|
||||
+ .priority = NF_IP_PRI_LAST,
|
||||
+ },
|
||||
+#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
|
||||
+ {
|
||||
+ .hook = nf_rtcache_in6,
|
||||
+ .pf = NFPROTO_IPV6,
|
||||
+ .hooknum = NF_INET_PRE_ROUTING,
|
||||
+ .priority = NF_IP_PRI_LAST,
|
||||
+ },
|
||||
+ {
|
||||
+ .hook = nf_rtcache_forward6,
|
||||
+ .pf = NFPROTO_IPV6,
|
||||
+ .hooknum = NF_INET_FORWARD,
|
||||
+ .priority = NF_IP_PRI_LAST,
|
||||
+ },
|
||||
+#endif
|
||||
+};
|
||||
+
|
||||
+static struct nf_ct_ext_type rtcache_extend __read_mostly = {
|
||||
+ .len = sizeof(struct nf_conn_rtcache),
|
||||
+ .align = __alignof__(struct nf_conn_rtcache),
|
||||
+ .id = NF_CT_EXT_RTCACHE,
|
||||
+ .destroy = nf_conn_rtcache_destroy,
|
||||
+};
|
||||
+
|
||||
+static int __init nf_conntrack_rtcache_init(void)
|
||||
+{
|
||||
+ int ret = nf_ct_extend_register(&rtcache_extend);
|
||||
+
|
||||
+ if (ret < 0) {
|
||||
+ pr_err("nf_conntrack_rtcache: Unable to register extension\n");
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ ret = nf_register_hooks(rtcache_ops, ARRAY_SIZE(rtcache_ops));
|
||||
+ if (ret < 0) {
|
||||
+ nf_ct_extend_unregister(&rtcache_extend);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ ret = register_netdevice_notifier(&nf_rtcache_notifier);
|
||||
+ if (ret) {
|
||||
+ nf_unregister_hooks(rtcache_ops, ARRAY_SIZE(rtcache_ops));
|
||||
+ nf_ct_extend_unregister(&rtcache_extend);
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int nf_rtcache_ext_remove(struct nf_conn *ct, void *data)
|
||||
+{
|
||||
+ struct nf_conn_rtcache *rtc = nf_ct_rtcache_find(ct);
|
||||
+
|
||||
+ return rtc != NULL;
|
||||
+}
|
||||
+
|
||||
+static bool __exit nf_conntrack_rtcache_wait_for_dying(struct net *net)
|
||||
+{
|
||||
+ bool wait = false;
|
||||
+ int cpu;
|
||||
+
|
||||
+ for_each_possible_cpu(cpu) {
|
||||
+ struct nf_conntrack_tuple_hash *h;
|
||||
+ struct hlist_nulls_node *n;
|
||||
+ struct nf_conn *ct;
|
||||
+ struct ct_pcpu *pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu);
|
||||
+
|
||||
+ rcu_read_lock();
|
||||
+ spin_lock_bh(&pcpu->lock);
|
||||
+
|
||||
+ hlist_nulls_for_each_entry(h, n, &pcpu->dying, hnnode) {
|
||||
+ ct = nf_ct_tuplehash_to_ctrack(h);
|
||||
+ if (nf_ct_rtcache_find(ct) != NULL) {
|
||||
+ wait = true;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ spin_unlock_bh(&pcpu->lock);
|
||||
+ rcu_read_unlock();
|
||||
+ }
|
||||
+
|
||||
+ return wait;
|
||||
+}
|
||||
+
|
||||
+static void __exit nf_conntrack_rtcache_fini(void)
|
||||
+{
|
||||
+ struct net *net;
|
||||
+ int count = 0;
|
||||
+
|
||||
+ /* remove hooks so no new connections get rtcache extension */
|
||||
+ nf_unregister_hooks(rtcache_ops, ARRAY_SIZE(rtcache_ops));
|
||||
+
|
||||
+ synchronize_net();
|
||||
+
|
||||
+ unregister_netdevice_notifier(&nf_rtcache_notifier);
|
||||
+
|
||||
+ rtnl_lock();
|
||||
+
|
||||
+ /* zap all conntracks with rtcache extension */
|
||||
+ for_each_net(net)
|
||||
+ nf_ct_iterate_cleanup(net, nf_rtcache_ext_remove, NULL, 0, 0);
|
||||
+
|
||||
+ for_each_net(net) {
|
||||
+ /* .. and make sure they're gone from dying list, too */
|
||||
+ while (nf_conntrack_rtcache_wait_for_dying(net)) {
|
||||
+ msleep(200);
|
||||
+ WARN_ONCE(++count > 25, "Waiting for all rtcache conntracks to go away\n");
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ rtnl_unlock();
|
||||
+ synchronize_net();
|
||||
+ nf_ct_extend_unregister(&rtcache_extend);
|
||||
+}
|
||||
+module_init(nf_conntrack_rtcache_init);
|
||||
+module_exit(nf_conntrack_rtcache_fini);
|
||||
+
|
||||
+MODULE_LICENSE("GPL");
|
||||
+MODULE_AUTHOR("Florian Westphal <fw@strlen.de>");
|
||||
+MODULE_DESCRIPTION("Conntrack route cache extension");
|
@ -1,72 +0,0 @@
|
||||
From 56656e960b555cb98bc414382566dcb59aae99a2 Mon Sep 17 00:00:00 2001
|
||||
From: Miklos Szeredi <mszeredi@redhat.com>
|
||||
Date: Mon, 21 Mar 2016 17:31:46 +0100
|
||||
Subject: [PATCH] ovl: rename is_merge to is_lowest
|
||||
|
||||
The 'is_merge' is an historical naming from when only a single lower layer
|
||||
could exist. With the introduction of multiple lower layers the meaning of
|
||||
this flag was changed to mean only the "lowest layer" (while all lower
|
||||
layers were being merged).
|
||||
|
||||
So now 'is_merge' is inaccurate and hence renaming to 'is_lowest'
|
||||
|
||||
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
|
||||
---
|
||||
fs/overlayfs/readdir.c | 16 ++++++++--------
|
||||
1 file changed, 8 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/fs/overlayfs/readdir.c
|
||||
+++ b/fs/overlayfs/readdir.c
|
||||
@@ -36,7 +36,7 @@ struct ovl_dir_cache {
|
||||
|
||||
struct ovl_readdir_data {
|
||||
struct dir_context ctx;
|
||||
- bool is_merge;
|
||||
+ bool is_lowest;
|
||||
struct rb_root root;
|
||||
struct list_head *list;
|
||||
struct list_head middle;
|
||||
@@ -139,9 +139,9 @@ static int ovl_cache_entry_add_rb(struct
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static int ovl_fill_lower(struct ovl_readdir_data *rdd,
|
||||
- const char *name, int namelen,
|
||||
- loff_t offset, u64 ino, unsigned int d_type)
|
||||
+static int ovl_fill_lowest(struct ovl_readdir_data *rdd,
|
||||
+ const char *name, int namelen,
|
||||
+ loff_t offset, u64 ino, unsigned int d_type)
|
||||
{
|
||||
struct ovl_cache_entry *p;
|
||||
|
||||
@@ -193,10 +193,10 @@ static int ovl_fill_merge(struct dir_con
|
||||
container_of(ctx, struct ovl_readdir_data, ctx);
|
||||
|
||||
rdd->count++;
|
||||
- if (!rdd->is_merge)
|
||||
+ if (!rdd->is_lowest)
|
||||
return ovl_cache_entry_add_rb(rdd, name, namelen, ino, d_type);
|
||||
else
|
||||
- return ovl_fill_lower(rdd, name, namelen, offset, ino, d_type);
|
||||
+ return ovl_fill_lowest(rdd, name, namelen, offset, ino, d_type);
|
||||
}
|
||||
|
||||
static int ovl_check_whiteouts(struct dentry *dir, struct ovl_readdir_data *rdd)
|
||||
@@ -289,7 +289,7 @@ static int ovl_dir_read_merged(struct de
|
||||
.ctx.actor = ovl_fill_merge,
|
||||
.list = list,
|
||||
.root = RB_ROOT,
|
||||
- .is_merge = false,
|
||||
+ .is_lowest = false,
|
||||
};
|
||||
int idx, next;
|
||||
|
||||
@@ -306,7 +306,7 @@ static int ovl_dir_read_merged(struct de
|
||||
* allows offsets to be reasonably constant
|
||||
*/
|
||||
list_add(&rdd.middle, rdd.list);
|
||||
- rdd.is_merge = true;
|
||||
+ rdd.is_lowest = true;
|
||||
err = ovl_dir_read(&realpath, &rdd);
|
||||
list_del(&rdd.middle);
|
||||
}
|
@ -1,336 +0,0 @@
|
||||
From 3fe6e52f062643676eb4518d68cee3bc1272091b Mon Sep 17 00:00:00 2001
|
||||
From: Antonio Murdaca <amurdaca@redhat.com>
|
||||
Date: Thu, 7 Apr 2016 15:48:25 +0200
|
||||
Subject: [PATCH] ovl: override creds with the ones from the superblock mounter
|
||||
|
||||
In user namespace the whiteout creation fails with -EPERM because the
|
||||
current process isn't capable(CAP_SYS_ADMIN) when setting xattr.
|
||||
|
||||
A simple reproducer:
|
||||
|
||||
$ mkdir upper lower work merged lower/dir
|
||||
$ sudo mount -t overlay overlay -olowerdir=lower,upperdir=upper,workdir=work merged
|
||||
$ unshare -m -p -f -U -r bash
|
||||
|
||||
Now as root in the user namespace:
|
||||
|
||||
\# touch merged/dir/{1,2,3} # this will force a copy up of lower/dir
|
||||
\# rm -fR merged/*
|
||||
|
||||
This ends up failing with -EPERM after the files in dir has been
|
||||
correctly deleted:
|
||||
|
||||
unlinkat(4, "2", 0) = 0
|
||||
unlinkat(4, "1", 0) = 0
|
||||
unlinkat(4, "3", 0) = 0
|
||||
close(4) = 0
|
||||
unlinkat(AT_FDCWD, "merged/dir", AT_REMOVEDIR) = -1 EPERM (Operation not
|
||||
permitted)
|
||||
|
||||
Interestingly, if you don't place files in merged/dir you can remove it,
|
||||
meaning if upper/dir does not exist, creating the char device file works
|
||||
properly in that same location.
|
||||
|
||||
This patch uses ovl_sb_creator_cred() to get the cred struct from the
|
||||
superblock mounter and override the old cred with these new ones so that
|
||||
the whiteout creation is possible because overlay is wrong in assuming that
|
||||
the creds it will get with prepare_creds will be in the initial user
|
||||
namespace. The old cap_raise game is removed in favor of just overriding
|
||||
the old cred struct.
|
||||
|
||||
This patch also drops from ovl_copy_up_one() the following two lines:
|
||||
|
||||
override_cred->fsuid = stat->uid;
|
||||
override_cred->fsgid = stat->gid;
|
||||
|
||||
This is because the correct uid and gid are taken directly with the stat
|
||||
struct and correctly set with ovl_set_attr().
|
||||
|
||||
Signed-off-by: Antonio Murdaca <runcom@redhat.com>
|
||||
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
|
||||
---
|
||||
fs/overlayfs/copy_up.c | 26 +------------------
|
||||
fs/overlayfs/dir.c | 67 ++++--------------------------------------------
|
||||
fs/overlayfs/overlayfs.h | 1 +
|
||||
fs/overlayfs/readdir.c | 14 +++-------
|
||||
fs/overlayfs/super.c | 18 ++++++++++++-
|
||||
5 files changed, 27 insertions(+), 99 deletions(-)
|
||||
|
||||
--- a/fs/overlayfs/copy_up.c
|
||||
+++ b/fs/overlayfs/copy_up.c
|
||||
@@ -317,7 +317,6 @@ int ovl_copy_up_one(struct dentry *paren
|
||||
struct dentry *upperdir;
|
||||
struct dentry *upperdentry;
|
||||
const struct cred *old_cred;
|
||||
- struct cred *override_cred;
|
||||
char *link = NULL;
|
||||
|
||||
if (WARN_ON(!workdir))
|
||||
@@ -336,28 +335,7 @@ int ovl_copy_up_one(struct dentry *paren
|
||||
return PTR_ERR(link);
|
||||
}
|
||||
|
||||
- err = -ENOMEM;
|
||||
- override_cred = prepare_creds();
|
||||
- if (!override_cred)
|
||||
- goto out_free_link;
|
||||
-
|
||||
- override_cred->fsuid = stat->uid;
|
||||
- override_cred->fsgid = stat->gid;
|
||||
- /*
|
||||
- * CAP_SYS_ADMIN for copying up extended attributes
|
||||
- * CAP_DAC_OVERRIDE for create
|
||||
- * CAP_FOWNER for chmod, timestamp update
|
||||
- * CAP_FSETID for chmod
|
||||
- * CAP_CHOWN for chown
|
||||
- * CAP_MKNOD for mknod
|
||||
- */
|
||||
- cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN);
|
||||
- cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE);
|
||||
- cap_raise(override_cred->cap_effective, CAP_FOWNER);
|
||||
- cap_raise(override_cred->cap_effective, CAP_FSETID);
|
||||
- cap_raise(override_cred->cap_effective, CAP_CHOWN);
|
||||
- cap_raise(override_cred->cap_effective, CAP_MKNOD);
|
||||
- old_cred = override_creds(override_cred);
|
||||
+ old_cred = ovl_override_creds(dentry->d_sb);
|
||||
|
||||
err = -EIO;
|
||||
if (lock_rename(workdir, upperdir) != NULL) {
|
||||
@@ -380,9 +358,7 @@ int ovl_copy_up_one(struct dentry *paren
|
||||
out_unlock:
|
||||
unlock_rename(workdir, upperdir);
|
||||
revert_creds(old_cred);
|
||||
- put_cred(override_cred);
|
||||
|
||||
-out_free_link:
|
||||
if (link)
|
||||
free_page((unsigned long) link);
|
||||
|
||||
--- a/fs/overlayfs/dir.c
|
||||
+++ b/fs/overlayfs/dir.c
|
||||
@@ -408,28 +408,13 @@ static int ovl_create_or_link(struct den
|
||||
err = ovl_create_upper(dentry, inode, &stat, link, hardlink);
|
||||
} else {
|
||||
const struct cred *old_cred;
|
||||
- struct cred *override_cred;
|
||||
|
||||
- err = -ENOMEM;
|
||||
- override_cred = prepare_creds();
|
||||
- if (!override_cred)
|
||||
- goto out_iput;
|
||||
-
|
||||
- /*
|
||||
- * CAP_SYS_ADMIN for setting opaque xattr
|
||||
- * CAP_DAC_OVERRIDE for create in workdir, rename
|
||||
- * CAP_FOWNER for removing whiteout from sticky dir
|
||||
- */
|
||||
- cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN);
|
||||
- cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE);
|
||||
- cap_raise(override_cred->cap_effective, CAP_FOWNER);
|
||||
- old_cred = override_creds(override_cred);
|
||||
+ old_cred = ovl_override_creds(dentry->d_sb);
|
||||
|
||||
err = ovl_create_over_whiteout(dentry, inode, &stat, link,
|
||||
hardlink);
|
||||
|
||||
revert_creds(old_cred);
|
||||
- put_cred(override_cred);
|
||||
}
|
||||
|
||||
if (!err)
|
||||
@@ -659,32 +644,11 @@ static int ovl_do_remove(struct dentry *
|
||||
if (OVL_TYPE_PURE_UPPER(type)) {
|
||||
err = ovl_remove_upper(dentry, is_dir);
|
||||
} else {
|
||||
- const struct cred *old_cred;
|
||||
- struct cred *override_cred;
|
||||
-
|
||||
- err = -ENOMEM;
|
||||
- override_cred = prepare_creds();
|
||||
- if (!override_cred)
|
||||
- goto out_drop_write;
|
||||
-
|
||||
- /*
|
||||
- * CAP_SYS_ADMIN for setting xattr on whiteout, opaque dir
|
||||
- * CAP_DAC_OVERRIDE for create in workdir, rename
|
||||
- * CAP_FOWNER for removing whiteout from sticky dir
|
||||
- * CAP_FSETID for chmod of opaque dir
|
||||
- * CAP_CHOWN for chown of opaque dir
|
||||
- */
|
||||
- cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN);
|
||||
- cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE);
|
||||
- cap_raise(override_cred->cap_effective, CAP_FOWNER);
|
||||
- cap_raise(override_cred->cap_effective, CAP_FSETID);
|
||||
- cap_raise(override_cred->cap_effective, CAP_CHOWN);
|
||||
- old_cred = override_creds(override_cred);
|
||||
+ const struct cred *old_cred = ovl_override_creds(dentry->d_sb);
|
||||
|
||||
err = ovl_remove_and_whiteout(dentry, is_dir);
|
||||
|
||||
revert_creds(old_cred);
|
||||
- put_cred(override_cred);
|
||||
}
|
||||
out_drop_write:
|
||||
ovl_drop_write(dentry);
|
||||
@@ -723,7 +687,6 @@ static int ovl_rename2(struct inode *old
|
||||
bool new_is_dir = false;
|
||||
struct dentry *opaquedir = NULL;
|
||||
const struct cred *old_cred = NULL;
|
||||
- struct cred *override_cred = NULL;
|
||||
|
||||
err = -EINVAL;
|
||||
if (flags & ~(RENAME_EXCHANGE | RENAME_NOREPLACE))
|
||||
@@ -792,26 +755,8 @@ static int ovl_rename2(struct inode *old
|
||||
old_opaque = !OVL_TYPE_PURE_UPPER(old_type);
|
||||
new_opaque = !OVL_TYPE_PURE_UPPER(new_type);
|
||||
|
||||
- if (old_opaque || new_opaque) {
|
||||
- err = -ENOMEM;
|
||||
- override_cred = prepare_creds();
|
||||
- if (!override_cred)
|
||||
- goto out_drop_write;
|
||||
-
|
||||
- /*
|
||||
- * CAP_SYS_ADMIN for setting xattr on whiteout, opaque dir
|
||||
- * CAP_DAC_OVERRIDE for create in workdir
|
||||
- * CAP_FOWNER for removing whiteout from sticky dir
|
||||
- * CAP_FSETID for chmod of opaque dir
|
||||
- * CAP_CHOWN for chown of opaque dir
|
||||
- */
|
||||
- cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN);
|
||||
- cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE);
|
||||
- cap_raise(override_cred->cap_effective, CAP_FOWNER);
|
||||
- cap_raise(override_cred->cap_effective, CAP_FSETID);
|
||||
- cap_raise(override_cred->cap_effective, CAP_CHOWN);
|
||||
- old_cred = override_creds(override_cred);
|
||||
- }
|
||||
+ if (old_opaque || new_opaque)
|
||||
+ old_cred = ovl_override_creds(old->d_sb);
|
||||
|
||||
if (overwrite && OVL_TYPE_MERGE_OR_LOWER(new_type) && new_is_dir) {
|
||||
opaquedir = ovl_check_empty_and_clear(new);
|
||||
@@ -942,10 +887,8 @@ out_dput_old:
|
||||
out_unlock:
|
||||
unlock_rename(new_upperdir, old_upperdir);
|
||||
out_revert_creds:
|
||||
- if (old_opaque || new_opaque) {
|
||||
+ if (old_opaque || new_opaque)
|
||||
revert_creds(old_cred);
|
||||
- put_cred(override_cred);
|
||||
- }
|
||||
out_drop_write:
|
||||
ovl_drop_write(old);
|
||||
out:
|
||||
--- a/fs/overlayfs/overlayfs.h
|
||||
+++ b/fs/overlayfs/overlayfs.h
|
||||
@@ -150,6 +150,7 @@ void ovl_drop_write(struct dentry *dentr
|
||||
bool ovl_dentry_is_opaque(struct dentry *dentry);
|
||||
void ovl_dentry_set_opaque(struct dentry *dentry, bool opaque);
|
||||
bool ovl_is_whiteout(struct dentry *dentry);
|
||||
+const struct cred *ovl_override_creds(struct super_block *sb);
|
||||
void ovl_dentry_update(struct dentry *dentry, struct dentry *upperdentry);
|
||||
struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
|
||||
unsigned int flags);
|
||||
--- a/fs/overlayfs/readdir.c
|
||||
+++ b/fs/overlayfs/readdir.c
|
||||
@@ -36,6 +36,7 @@ struct ovl_dir_cache {
|
||||
|
||||
struct ovl_readdir_data {
|
||||
struct dir_context ctx;
|
||||
+ struct dentry *dentry;
|
||||
bool is_lowest;
|
||||
struct rb_root root;
|
||||
struct list_head *list;
|
||||
@@ -205,17 +206,8 @@ static int ovl_check_whiteouts(struct de
|
||||
struct ovl_cache_entry *p;
|
||||
struct dentry *dentry;
|
||||
const struct cred *old_cred;
|
||||
- struct cred *override_cred;
|
||||
-
|
||||
- override_cred = prepare_creds();
|
||||
- if (!override_cred)
|
||||
- return -ENOMEM;
|
||||
|
||||
- /*
|
||||
- * CAP_DAC_OVERRIDE for lookup
|
||||
- */
|
||||
- cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE);
|
||||
- old_cred = override_creds(override_cred);
|
||||
+ old_cred = ovl_override_creds(rdd->dentry->d_sb);
|
||||
|
||||
err = mutex_lock_killable(&dir->d_inode->i_mutex);
|
||||
if (!err) {
|
||||
@@ -231,7 +223,6 @@ static int ovl_check_whiteouts(struct de
|
||||
mutex_unlock(&dir->d_inode->i_mutex);
|
||||
}
|
||||
revert_creds(old_cred);
|
||||
- put_cred(override_cred);
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -287,6 +278,7 @@ static int ovl_dir_read_merged(struct de
|
||||
struct path realpath;
|
||||
struct ovl_readdir_data rdd = {
|
||||
.ctx.actor = ovl_fill_merge,
|
||||
+ .dentry = dentry,
|
||||
.list = list,
|
||||
.root = RB_ROOT,
|
||||
.is_lowest = false,
|
||||
--- a/fs/overlayfs/super.c
|
||||
+++ b/fs/overlayfs/super.c
|
||||
@@ -42,6 +42,8 @@ struct ovl_fs {
|
||||
long lower_namelen;
|
||||
/* pathnames of lower and upper dirs, for show_options */
|
||||
struct ovl_config config;
|
||||
+ /* creds of process who forced instantiation of super block */
|
||||
+ const struct cred *creator_cred;
|
||||
};
|
||||
|
||||
struct ovl_dir_cache;
|
||||
@@ -246,6 +248,13 @@ bool ovl_is_whiteout(struct dentry *dent
|
||||
return inode && IS_WHITEOUT(inode);
|
||||
}
|
||||
|
||||
+const struct cred *ovl_override_creds(struct super_block *sb)
|
||||
+{
|
||||
+ struct ovl_fs *ofs = sb->s_fs_info;
|
||||
+
|
||||
+ return override_creds(ofs->creator_cred);
|
||||
+}
|
||||
+
|
||||
static bool ovl_is_opaquedir(struct dentry *dentry)
|
||||
{
|
||||
int res;
|
||||
@@ -587,6 +596,7 @@ static void ovl_put_super(struct super_b
|
||||
kfree(ufs->config.lowerdir);
|
||||
kfree(ufs->config.upperdir);
|
||||
kfree(ufs->config.workdir);
|
||||
+ put_cred(ufs->creator_cred);
|
||||
kfree(ufs);
|
||||
}
|
||||
|
||||
@@ -1087,10 +1097,14 @@ static int ovl_fill_super(struct super_b
|
||||
else
|
||||
sb->s_d_op = &ovl_dentry_operations;
|
||||
|
||||
+ ufs->creator_cred = prepare_creds();
|
||||
+ if (!ufs->creator_cred)
|
||||
+ goto out_put_lower_mnt;
|
||||
+
|
||||
err = -ENOMEM;
|
||||
oe = ovl_alloc_entry(numlower);
|
||||
if (!oe)
|
||||
- goto out_put_lower_mnt;
|
||||
+ goto out_put_cred;
|
||||
|
||||
root_dentry = d_make_root(ovl_new_inode(sb, S_IFDIR, oe));
|
||||
if (!root_dentry)
|
||||
@@ -1123,6 +1137,8 @@ static int ovl_fill_super(struct super_b
|
||||
|
||||
out_free_oe:
|
||||
kfree(oe);
|
||||
+out_put_cred:
|
||||
+ put_cred(ufs->creator_cred);
|
||||
out_put_lower_mnt:
|
||||
for (i = 0; i < ufs->numlower; i++)
|
||||
mntput(ufs->lower_mnt[i]);
|
@ -1,131 +0,0 @@
|
||||
From eea2fb4851e9dcbab6b991aaf47e2e024f1f55a0 Mon Sep 17 00:00:00 2001
|
||||
From: Miklos Szeredi <mszeredi@redhat.com>
|
||||
Date: Thu, 1 Sep 2016 11:11:59 +0200
|
||||
Subject: [PATCH] ovl: proper cleanup of workdir
|
||||
|
||||
When mounting overlayfs it needs a clean "work" directory under the
|
||||
supplied workdir.
|
||||
|
||||
Previously the mount code removed this directory if it already existed and
|
||||
created a new one. If the removal failed (e.g. directory was not empty)
|
||||
then it fell back to a read-only mount not using the workdir.
|
||||
|
||||
While this has never been reported, it is possible to get a non-empty
|
||||
"work" dir from a previous mount of overlayfs in case of crash in the
|
||||
middle of an operation using the work directory.
|
||||
|
||||
In this case the left over state should be discarded and the overlay
|
||||
filesystem will be consistent, guaranteed by the atomicity of operations on
|
||||
moving to/from the workdir to the upper layer.
|
||||
|
||||
This patch implements cleaning out any files left in workdir. It is
|
||||
implemented using real recursion for simplicity, but the depth is limited
|
||||
to 2, because the worst case is that of a directory containing whiteouts
|
||||
under "work".
|
||||
|
||||
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
|
||||
Cc: <stable@vger.kernel.org>
|
||||
---
|
||||
fs/overlayfs/overlayfs.h | 2 ++
|
||||
fs/overlayfs/readdir.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++-
|
||||
fs/overlayfs/super.c | 2 +-
|
||||
3 files changed, 65 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/fs/overlayfs/overlayfs.h
|
||||
+++ b/fs/overlayfs/overlayfs.h
|
||||
@@ -164,6 +164,8 @@ extern const struct file_operations ovl_
|
||||
int ovl_check_empty_dir(struct dentry *dentry, struct list_head *list);
|
||||
void ovl_cleanup_whiteouts(struct dentry *upper, struct list_head *list);
|
||||
void ovl_cache_free(struct list_head *list);
|
||||
+void ovl_workdir_cleanup(struct inode *dir, struct vfsmount *mnt,
|
||||
+ struct dentry *dentry, int level);
|
||||
|
||||
/* inode.c */
|
||||
int ovl_setattr(struct dentry *dentry, struct iattr *attr);
|
||||
--- a/fs/overlayfs/readdir.c
|
||||
+++ b/fs/overlayfs/readdir.c
|
||||
@@ -247,7 +247,7 @@ static inline int ovl_dir_read(struct pa
|
||||
err = rdd->err;
|
||||
} while (!err && rdd->count);
|
||||
|
||||
- if (!err && rdd->first_maybe_whiteout)
|
||||
+ if (!err && rdd->first_maybe_whiteout && rdd->dentry)
|
||||
err = ovl_check_whiteouts(realpath->dentry, rdd);
|
||||
|
||||
fput(realfile);
|
||||
@@ -573,3 +573,64 @@ void ovl_cleanup_whiteouts(struct dentry
|
||||
}
|
||||
mutex_unlock(&upper->d_inode->i_mutex);
|
||||
}
|
||||
+
|
||||
+static void ovl_workdir_cleanup_recurse(struct path *path, int level)
|
||||
+{
|
||||
+ int err;
|
||||
+ struct inode *dir = path->dentry->d_inode;
|
||||
+ LIST_HEAD(list);
|
||||
+ struct ovl_cache_entry *p;
|
||||
+ struct ovl_readdir_data rdd = {
|
||||
+ .ctx.actor = ovl_fill_merge,
|
||||
+ .dentry = NULL,
|
||||
+ .list = &list,
|
||||
+ .root = RB_ROOT,
|
||||
+ .is_lowest = false,
|
||||
+ };
|
||||
+
|
||||
+ err = ovl_dir_read(path, &rdd);
|
||||
+ if (err)
|
||||
+ goto out;
|
||||
+
|
||||
+ mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
|
||||
+ list_for_each_entry(p, &list, l_node) {
|
||||
+ struct dentry *dentry;
|
||||
+
|
||||
+ if (p->name[0] == '.') {
|
||||
+ if (p->len == 1)
|
||||
+ continue;
|
||||
+ if (p->len == 2 && p->name[1] == '.')
|
||||
+ continue;
|
||||
+ }
|
||||
+ dentry = lookup_one_len(p->name, path->dentry, p->len);
|
||||
+ if (IS_ERR(dentry))
|
||||
+ continue;
|
||||
+ if (dentry->d_inode)
|
||||
+ ovl_workdir_cleanup(dir, path->mnt, dentry, level);
|
||||
+ dput(dentry);
|
||||
+ }
|
||||
+ mutex_unlock(&dir->i_mutex);
|
||||
+out:
|
||||
+ ovl_cache_free(&list);
|
||||
+}
|
||||
+
|
||||
+void ovl_workdir_cleanup(struct inode *dir, struct vfsmount *mnt,
|
||||
+ struct dentry *dentry, int level)
|
||||
+{
|
||||
+ int err;
|
||||
+
|
||||
+ if (!d_is_dir(dentry) || level > 1) {
|
||||
+ ovl_cleanup(dir, dentry);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ err = ovl_do_rmdir(dir, dentry);
|
||||
+ if (err) {
|
||||
+ struct path path = { .mnt = mnt, .dentry = dentry };
|
||||
+
|
||||
+ mutex_unlock(&dir->i_mutex);
|
||||
+ ovl_workdir_cleanup_recurse(&path, level + 1);
|
||||
+ mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
|
||||
+ ovl_cleanup(dir, dentry);
|
||||
+ }
|
||||
+}
|
||||
--- a/fs/overlayfs/super.c
|
||||
+++ b/fs/overlayfs/super.c
|
||||
@@ -784,7 +784,7 @@ retry:
|
||||
goto out_dput;
|
||||
|
||||
retried = true;
|
||||
- ovl_cleanup(dir, work);
|
||||
+ ovl_workdir_cleanup(dir, mnt, work, 0);
|
||||
dput(work);
|
||||
goto retry;
|
||||
}
|
@ -1,99 +0,0 @@
|
||||
From: Richard Weinberger <richard@nod.at>
|
||||
Date: Tue, 13 Sep 2016 16:18:55 +0200
|
||||
Subject: [PATCH] ubifs: Implement O_TMPFILE
|
||||
|
||||
This patchs adds O_TMPFILE support to UBIFS.
|
||||
A temp file is a reference to an unlinked inode, a user
|
||||
holding the reference can use it. As soon it is being closed
|
||||
all data vanishes.
|
||||
|
||||
Signed-off-by: Richard Weinberger <richard@nod.at>
|
||||
---
|
||||
|
||||
--- a/fs/ubifs/dir.c
|
||||
+++ b/fs/ubifs/dir.c
|
||||
@@ -301,6 +301,76 @@ out_budg:
|
||||
return err;
|
||||
}
|
||||
|
||||
+static int ubifs_tmpfile(struct inode *dir, struct dentry *dentry,
|
||||
+ umode_t mode)
|
||||
+{
|
||||
+ struct inode *inode;
|
||||
+ struct ubifs_info *c = dir->i_sb->s_fs_info;
|
||||
+ struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1};
|
||||
+ struct ubifs_budget_req ino_req = { .dirtied_ino = 1 };
|
||||
+ struct ubifs_inode *ui, *dir_ui = ubifs_inode(dir);
|
||||
+ int err, instantiated = 0;
|
||||
+
|
||||
+ /*
|
||||
+ * Budget request settings: new dirty inode, new direntry,
|
||||
+ * budget for dirtied inode will be released via writeback.
|
||||
+ */
|
||||
+
|
||||
+ dbg_gen("dent '%pd', mode %#hx in dir ino %lu",
|
||||
+ dentry, mode, dir->i_ino);
|
||||
+
|
||||
+ err = ubifs_budget_space(c, &req);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ err = ubifs_budget_space(c, &ino_req);
|
||||
+ if (err) {
|
||||
+ ubifs_release_budget(c, &req);
|
||||
+ return err;
|
||||
+ }
|
||||
+
|
||||
+ inode = ubifs_new_inode(c, dir, mode);
|
||||
+ if (IS_ERR(inode)) {
|
||||
+ err = PTR_ERR(inode);
|
||||
+ goto out_budg;
|
||||
+ }
|
||||
+ ui = ubifs_inode(inode);
|
||||
+
|
||||
+ err = ubifs_init_security(dir, inode, &dentry->d_name);
|
||||
+ if (err)
|
||||
+ goto out_inode;
|
||||
+
|
||||
+ mutex_lock(&ui->ui_mutex);
|
||||
+ insert_inode_hash(inode);
|
||||
+ d_tmpfile(dentry, inode);
|
||||
+ ubifs_assert(ui->dirty);
|
||||
+ instantiated = 1;
|
||||
+ mutex_unlock(&ui->ui_mutex);
|
||||
+
|
||||
+ mutex_lock(&dir_ui->ui_mutex);
|
||||
+ err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 1, 0);
|
||||
+ if (err)
|
||||
+ goto out_cancel;
|
||||
+ mutex_unlock(&dir_ui->ui_mutex);
|
||||
+
|
||||
+ ubifs_release_budget(c, &req);
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+out_cancel:
|
||||
+ mutex_unlock(&dir_ui->ui_mutex);
|
||||
+out_inode:
|
||||
+ make_bad_inode(inode);
|
||||
+ if (!instantiated)
|
||||
+ iput(inode);
|
||||
+out_budg:
|
||||
+ ubifs_release_budget(c, &req);
|
||||
+ if (!instantiated)
|
||||
+ ubifs_release_budget(c, &ino_req);
|
||||
+ ubifs_err(c, "cannot create temporary file, error %d", err);
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* vfs_dent_type - get VFS directory entry type.
|
||||
* @type: UBIFS directory entry type
|
||||
@@ -1195,6 +1265,7 @@ const struct inode_operations ubifs_dir_
|
||||
#ifdef CONFIG_UBIFS_ATIME_SUPPORT
|
||||
.update_time = ubifs_update_time,
|
||||
#endif
|
||||
+ .tmpfile = ubifs_tmpfile,
|
||||
};
|
||||
|
||||
const struct file_operations ubifs_dir_operations = {
|
@ -1,343 +0,0 @@
|
||||
From: Richard Weinberger <richard@nod.at>
|
||||
Date: Tue, 13 Sep 2016 16:18:56 +0200
|
||||
Subject: [PATCH] ubifs: Implement RENAME_WHITEOUT
|
||||
|
||||
Adds RENAME_WHITEOUT support to UBIFS, we implement
|
||||
it in the same way as ext4 and xfs do.
|
||||
For an overview of other ways to implement it please
|
||||
refere to commit 7dcf5c3e4527 ("xfs: add RENAME_WHITEOUT support").
|
||||
|
||||
Signed-off-by: Richard Weinberger <richard@nod.at>
|
||||
---
|
||||
|
||||
--- a/fs/ubifs/dir.c
|
||||
+++ b/fs/ubifs/dir.c
|
||||
@@ -301,8 +301,8 @@ out_budg:
|
||||
return err;
|
||||
}
|
||||
|
||||
-static int ubifs_tmpfile(struct inode *dir, struct dentry *dentry,
|
||||
- umode_t mode)
|
||||
+static int do_tmpfile(struct inode *dir, struct dentry *dentry,
|
||||
+ umode_t mode, struct inode **whiteout)
|
||||
{
|
||||
struct inode *inode;
|
||||
struct ubifs_info *c = dir->i_sb->s_fs_info;
|
||||
@@ -336,14 +336,27 @@ static int ubifs_tmpfile(struct inode *d
|
||||
}
|
||||
ui = ubifs_inode(inode);
|
||||
|
||||
+ if (whiteout) {
|
||||
+ init_special_inode(inode, inode->i_mode, WHITEOUT_DEV);
|
||||
+ ubifs_assert(inode->i_op == &ubifs_file_inode_operations);
|
||||
+ }
|
||||
+
|
||||
err = ubifs_init_security(dir, inode, &dentry->d_name);
|
||||
if (err)
|
||||
goto out_inode;
|
||||
|
||||
mutex_lock(&ui->ui_mutex);
|
||||
insert_inode_hash(inode);
|
||||
- d_tmpfile(dentry, inode);
|
||||
+
|
||||
+ if (whiteout) {
|
||||
+ mark_inode_dirty(inode);
|
||||
+ drop_nlink(inode);
|
||||
+ *whiteout = inode;
|
||||
+ } else {
|
||||
+ d_tmpfile(dentry, inode);
|
||||
+ }
|
||||
ubifs_assert(ui->dirty);
|
||||
+
|
||||
instantiated = 1;
|
||||
mutex_unlock(&ui->ui_mutex);
|
||||
|
||||
@@ -371,6 +384,12 @@ out_budg:
|
||||
return err;
|
||||
}
|
||||
|
||||
+static int ubifs_tmpfile(struct inode *dir, struct dentry *dentry,
|
||||
+ umode_t mode)
|
||||
+{
|
||||
+ return do_tmpfile(dir, dentry, mode, NULL);
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* vfs_dent_type - get VFS directory entry type.
|
||||
* @type: UBIFS directory entry type
|
||||
@@ -1003,37 +1022,43 @@ out_budg:
|
||||
}
|
||||
|
||||
/**
|
||||
- * lock_3_inodes - a wrapper for locking three UBIFS inodes.
|
||||
+ * lock_4_inodes - a wrapper for locking three UBIFS inodes.
|
||||
* @inode1: first inode
|
||||
* @inode2: second inode
|
||||
* @inode3: third inode
|
||||
+ * @inode4: fouth inode
|
||||
*
|
||||
* This function is used for 'ubifs_rename()' and @inode1 may be the same as
|
||||
- * @inode2 whereas @inode3 may be %NULL.
|
||||
+ * @inode2 whereas @inode3 and @inode4 may be %NULL.
|
||||
*
|
||||
* We do not implement any tricks to guarantee strict lock ordering, because
|
||||
* VFS has already done it for us on the @i_mutex. So this is just a simple
|
||||
* wrapper function.
|
||||
*/
|
||||
-static void lock_3_inodes(struct inode *inode1, struct inode *inode2,
|
||||
- struct inode *inode3)
|
||||
+static void lock_4_inodes(struct inode *inode1, struct inode *inode2,
|
||||
+ struct inode *inode3, struct inode *inode4)
|
||||
{
|
||||
mutex_lock_nested(&ubifs_inode(inode1)->ui_mutex, WB_MUTEX_1);
|
||||
if (inode2 != inode1)
|
||||
mutex_lock_nested(&ubifs_inode(inode2)->ui_mutex, WB_MUTEX_2);
|
||||
if (inode3)
|
||||
mutex_lock_nested(&ubifs_inode(inode3)->ui_mutex, WB_MUTEX_3);
|
||||
+ if (inode4)
|
||||
+ mutex_lock_nested(&ubifs_inode(inode4)->ui_mutex, WB_MUTEX_4);
|
||||
}
|
||||
|
||||
/**
|
||||
- * unlock_3_inodes - a wrapper for unlocking three UBIFS inodes for rename.
|
||||
+ * unlock_4_inodes - a wrapper for unlocking three UBIFS inodes for rename.
|
||||
* @inode1: first inode
|
||||
* @inode2: second inode
|
||||
* @inode3: third inode
|
||||
+ * @inode4: fouth inode
|
||||
*/
|
||||
-static void unlock_3_inodes(struct inode *inode1, struct inode *inode2,
|
||||
- struct inode *inode3)
|
||||
+static void unlock_4_inodes(struct inode *inode1, struct inode *inode2,
|
||||
+ struct inode *inode3, struct inode *inode4)
|
||||
{
|
||||
+ if (inode4)
|
||||
+ mutex_unlock(&ubifs_inode(inode4)->ui_mutex);
|
||||
if (inode3)
|
||||
mutex_unlock(&ubifs_inode(inode3)->ui_mutex);
|
||||
if (inode1 != inode2)
|
||||
@@ -1042,12 +1067,15 @@ static void unlock_3_inodes(struct inode
|
||||
}
|
||||
|
||||
static int ubifs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
- struct inode *new_dir, struct dentry *new_dentry)
|
||||
+ struct inode *new_dir, struct dentry *new_dentry,
|
||||
+ unsigned int flags)
|
||||
{
|
||||
struct ubifs_info *c = old_dir->i_sb->s_fs_info;
|
||||
struct inode *old_inode = d_inode(old_dentry);
|
||||
struct inode *new_inode = d_inode(new_dentry);
|
||||
+ struct inode *whiteout = NULL;
|
||||
struct ubifs_inode *old_inode_ui = ubifs_inode(old_inode);
|
||||
+ struct ubifs_inode *whiteout_ui = NULL;
|
||||
int err, release, sync = 0, move = (new_dir != old_dir);
|
||||
int is_dir = S_ISDIR(old_inode->i_mode);
|
||||
int unlink = !!new_inode;
|
||||
@@ -1069,9 +1097,13 @@ static int ubifs_rename(struct inode *ol
|
||||
* separately.
|
||||
*/
|
||||
|
||||
- dbg_gen("dent '%pd' ino %lu in dir ino %lu to dent '%pd' in dir ino %lu",
|
||||
+ dbg_gen("dent '%pd' ino %lu in dir ino %lu to dent '%pd' in dir ino %lu flags 0x%x",
|
||||
old_dentry, old_inode->i_ino, old_dir->i_ino,
|
||||
- new_dentry, new_dir->i_ino);
|
||||
+ new_dentry, new_dir->i_ino, flags);
|
||||
+
|
||||
+ if (flags & ~(RENAME_NOREPLACE | RENAME_WHITEOUT))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
ubifs_assert(mutex_is_locked(&old_dir->i_mutex));
|
||||
ubifs_assert(mutex_is_locked(&new_dir->i_mutex));
|
||||
if (unlink)
|
||||
@@ -1093,7 +1125,32 @@ static int ubifs_rename(struct inode *ol
|
||||
return err;
|
||||
}
|
||||
|
||||
- lock_3_inodes(old_dir, new_dir, new_inode);
|
||||
+ if (flags & RENAME_WHITEOUT) {
|
||||
+ union ubifs_dev_desc *dev = NULL;
|
||||
+
|
||||
+ dev = kmalloc(sizeof(union ubifs_dev_desc), GFP_NOFS);
|
||||
+ if (!dev) {
|
||||
+ ubifs_release_budget(c, &req);
|
||||
+ ubifs_release_budget(c, &ino_req);
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+
|
||||
+ err = do_tmpfile(old_dir, old_dentry, S_IFCHR | WHITEOUT_MODE, &whiteout);
|
||||
+ if (err) {
|
||||
+ ubifs_release_budget(c, &req);
|
||||
+ ubifs_release_budget(c, &ino_req);
|
||||
+ kfree(dev);
|
||||
+ return err;
|
||||
+ }
|
||||
+
|
||||
+ whiteout->i_state |= I_LINKABLE;
|
||||
+ whiteout_ui = ubifs_inode(whiteout);
|
||||
+ whiteout_ui->data = dev;
|
||||
+ whiteout_ui->data_len = ubifs_encode_dev(dev, MKDEV(0, 0));
|
||||
+ ubifs_assert(!whiteout_ui->dirty);
|
||||
+ }
|
||||
+
|
||||
+ lock_4_inodes(old_dir, new_dir, new_inode, whiteout);
|
||||
|
||||
/*
|
||||
* Like most other Unix systems, set the @i_ctime for inodes on a
|
||||
@@ -1163,12 +1220,34 @@ static int ubifs_rename(struct inode *ol
|
||||
if (unlink && IS_SYNC(new_inode))
|
||||
sync = 1;
|
||||
}
|
||||
- err = ubifs_jnl_rename(c, old_dir, old_dentry, new_dir, new_dentry,
|
||||
+
|
||||
+ if (whiteout) {
|
||||
+ struct ubifs_budget_req wht_req = { .dirtied_ino = 1,
|
||||
+ .dirtied_ino_d = \
|
||||
+ ALIGN(ubifs_inode(whiteout)->data_len, 8) };
|
||||
+
|
||||
+ err = ubifs_budget_space(c, &wht_req);
|
||||
+ if (err) {
|
||||
+ ubifs_release_budget(c, &req);
|
||||
+ ubifs_release_budget(c, &ino_req);
|
||||
+ kfree(whiteout_ui->data);
|
||||
+ whiteout_ui->data_len = 0;
|
||||
+ iput(whiteout);
|
||||
+ return err;
|
||||
+ }
|
||||
+
|
||||
+ inc_nlink(whiteout);
|
||||
+ mark_inode_dirty(whiteout);
|
||||
+ whiteout->i_state &= ~I_LINKABLE;
|
||||
+ iput(whiteout);
|
||||
+ }
|
||||
+
|
||||
+ err = ubifs_jnl_rename(c, old_dir, old_dentry, new_dir, new_dentry, whiteout,
|
||||
sync);
|
||||
if (err)
|
||||
goto out_cancel;
|
||||
|
||||
- unlock_3_inodes(old_dir, new_dir, new_inode);
|
||||
+ unlock_4_inodes(old_dir, new_dir, new_inode, whiteout);
|
||||
ubifs_release_budget(c, &req);
|
||||
|
||||
mutex_lock(&old_inode_ui->ui_mutex);
|
||||
@@ -1201,7 +1280,11 @@ out_cancel:
|
||||
inc_nlink(old_dir);
|
||||
}
|
||||
}
|
||||
- unlock_3_inodes(old_dir, new_dir, new_inode);
|
||||
+ if (whiteout) {
|
||||
+ drop_nlink(whiteout);
|
||||
+ iput(whiteout);
|
||||
+ }
|
||||
+ unlock_4_inodes(old_dir, new_dir, new_inode, whiteout);
|
||||
ubifs_release_budget(c, &ino_req);
|
||||
ubifs_release_budget(c, &req);
|
||||
return err;
|
||||
@@ -1255,7 +1338,7 @@ const struct inode_operations ubifs_dir_
|
||||
.mkdir = ubifs_mkdir,
|
||||
.rmdir = ubifs_rmdir,
|
||||
.mknod = ubifs_mknod,
|
||||
- .rename = ubifs_rename,
|
||||
+ .rename2 = ubifs_rename,
|
||||
.setattr = ubifs_setattr,
|
||||
.getattr = ubifs_getattr,
|
||||
.setxattr = ubifs_setxattr,
|
||||
--- a/fs/ubifs/journal.c
|
||||
+++ b/fs/ubifs/journal.c
|
||||
@@ -917,14 +917,15 @@ int ubifs_jnl_delete_inode(struct ubifs_
|
||||
* @sync: non-zero if the write-buffer has to be synchronized
|
||||
*
|
||||
* This function implements the re-name operation which may involve writing up
|
||||
- * to 3 inodes and 2 directory entries. It marks the written inodes as clean
|
||||
+ * to 4 inodes and 2 directory entries. It marks the written inodes as clean
|
||||
* and returns zero on success. In case of failure, a negative error code is
|
||||
* returned.
|
||||
*/
|
||||
int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
|
||||
const struct dentry *old_dentry,
|
||||
const struct inode *new_dir,
|
||||
- const struct dentry *new_dentry, int sync)
|
||||
+ const struct dentry *new_dentry,
|
||||
+ const struct inode *whiteout, int sync)
|
||||
{
|
||||
void *p;
|
||||
union ubifs_key key;
|
||||
@@ -980,13 +981,19 @@ int ubifs_jnl_rename(struct ubifs_info *
|
||||
zero_dent_node_unused(dent);
|
||||
ubifs_prep_grp_node(c, dent, dlen1, 0);
|
||||
|
||||
- /* Make deletion dent */
|
||||
dent2 = (void *)dent + aligned_dlen1;
|
||||
dent2->ch.node_type = UBIFS_DENT_NODE;
|
||||
dent_key_init_flash(c, &dent2->key, old_dir->i_ino,
|
||||
&old_dentry->d_name);
|
||||
- dent2->inum = 0;
|
||||
- dent2->type = DT_UNKNOWN;
|
||||
+
|
||||
+ if (whiteout) {
|
||||
+ dent2->inum = cpu_to_le64(whiteout->i_ino);
|
||||
+ dent2->type = get_dent_type(whiteout->i_mode);
|
||||
+ } else {
|
||||
+ /* Make deletion dent */
|
||||
+ dent2->inum = 0;
|
||||
+ dent2->type = DT_UNKNOWN;
|
||||
+ }
|
||||
dent2->nlen = cpu_to_le16(old_dentry->d_name.len);
|
||||
memcpy(dent2->name, old_dentry->d_name.name, old_dentry->d_name.len);
|
||||
dent2->name[old_dentry->d_name.len] = '\0';
|
||||
@@ -1035,16 +1042,26 @@ int ubifs_jnl_rename(struct ubifs_info *
|
||||
if (err)
|
||||
goto out_ro;
|
||||
|
||||
- err = ubifs_add_dirt(c, lnum, dlen2);
|
||||
- if (err)
|
||||
- goto out_ro;
|
||||
-
|
||||
- dent_key_init(c, &key, old_dir->i_ino, &old_dentry->d_name);
|
||||
- err = ubifs_tnc_remove_nm(c, &key, &old_dentry->d_name);
|
||||
- if (err)
|
||||
- goto out_ro;
|
||||
+ offs += aligned_dlen1;
|
||||
+ if (whiteout) {
|
||||
+ dent_key_init(c, &key, old_dir->i_ino, &old_dentry->d_name);
|
||||
+ err = ubifs_tnc_add_nm(c, &key, lnum, offs, dlen2, &old_dentry->d_name);
|
||||
+ if (err)
|
||||
+ goto out_ro;
|
||||
+
|
||||
+ ubifs_delete_orphan(c, whiteout->i_ino);
|
||||
+ } else {
|
||||
+ err = ubifs_add_dirt(c, lnum, dlen2);
|
||||
+ if (err)
|
||||
+ goto out_ro;
|
||||
+
|
||||
+ dent_key_init(c, &key, old_dir->i_ino, &old_dentry->d_name);
|
||||
+ err = ubifs_tnc_remove_nm(c, &key, &old_dentry->d_name);
|
||||
+ if (err)
|
||||
+ goto out_ro;
|
||||
+ }
|
||||
|
||||
- offs += aligned_dlen1 + aligned_dlen2;
|
||||
+ offs += aligned_dlen2;
|
||||
if (new_inode) {
|
||||
ino_key_init(c, &key, new_inode->i_ino);
|
||||
err = ubifs_tnc_add(c, &key, lnum, offs, ilen);
|
||||
--- a/fs/ubifs/ubifs.h
|
||||
+++ b/fs/ubifs/ubifs.h
|
||||
@@ -180,6 +180,7 @@ enum {
|
||||
WB_MUTEX_1 = 0,
|
||||
WB_MUTEX_2 = 1,
|
||||
WB_MUTEX_3 = 2,
|
||||
+ WB_MUTEX_4 = 3,
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1546,7 +1547,8 @@ int ubifs_jnl_delete_inode(struct ubifs_
|
||||
int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
|
||||
const struct dentry *old_dentry,
|
||||
const struct inode *new_dir,
|
||||
- const struct dentry *new_dentry, int sync);
|
||||
+ const struct dentry *new_dentry,
|
||||
+ const struct inode *whiteout, int sync);
|
||||
int ubifs_jnl_truncate(struct ubifs_info *c, const struct inode *inode,
|
||||
loff_t old_size, loff_t new_size);
|
||||
int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host,
|
@ -1,267 +0,0 @@
|
||||
From: Richard Weinberger <richard@nod.at>
|
||||
Date: Tue, 13 Sep 2016 16:18:57 +0200
|
||||
Subject: [PATCH] ubifs: Implement RENAME_EXCHANGE
|
||||
|
||||
Adds RENAME_EXCHANGE to UBIFS, the operation itself
|
||||
is completely disjunct from a regular rename() that's
|
||||
why we dispatch very early in ubifs_reaname().
|
||||
|
||||
RENAME_EXCHANGE used by the renameat2() system call
|
||||
allows the caller to exchange two paths atomically.
|
||||
Both paths have to exist and have to be on the same
|
||||
filesystem.
|
||||
|
||||
Signed-off-by: Richard Weinberger <richard@nod.at>
|
||||
---
|
||||
|
||||
--- a/fs/ubifs/dir.c
|
||||
+++ b/fs/ubifs/dir.c
|
||||
@@ -1101,11 +1101,6 @@ static int ubifs_rename(struct inode *ol
|
||||
old_dentry, old_inode->i_ino, old_dir->i_ino,
|
||||
new_dentry, new_dir->i_ino, flags);
|
||||
|
||||
- if (flags & ~(RENAME_NOREPLACE | RENAME_WHITEOUT))
|
||||
- return -EINVAL;
|
||||
-
|
||||
- ubifs_assert(mutex_is_locked(&old_dir->i_mutex));
|
||||
- ubifs_assert(mutex_is_locked(&new_dir->i_mutex));
|
||||
if (unlink)
|
||||
ubifs_assert(mutex_is_locked(&new_inode->i_mutex));
|
||||
|
||||
@@ -1290,6 +1285,64 @@ out_cancel:
|
||||
return err;
|
||||
}
|
||||
|
||||
+static int ubifs_xrename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
+ struct inode *new_dir, struct dentry *new_dentry)
|
||||
+{
|
||||
+ struct ubifs_info *c = old_dir->i_sb->s_fs_info;
|
||||
+ struct ubifs_budget_req req = { .new_dent = 1, .mod_dent = 1,
|
||||
+ .dirtied_ino = 2 };
|
||||
+ int sync = IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir);
|
||||
+ struct inode *fst_inode = d_inode(old_dentry);
|
||||
+ struct inode *snd_inode = d_inode(new_dentry);
|
||||
+ struct timespec time;
|
||||
+ int err;
|
||||
+
|
||||
+ ubifs_assert(fst_inode && snd_inode);
|
||||
+
|
||||
+ lock_4_inodes(old_dir, new_dir, NULL, NULL);
|
||||
+
|
||||
+ time = ubifs_current_time(old_dir);
|
||||
+ fst_inode->i_ctime = time;
|
||||
+ snd_inode->i_ctime = time;
|
||||
+ old_dir->i_mtime = old_dir->i_ctime = time;
|
||||
+ new_dir->i_mtime = new_dir->i_ctime = time;
|
||||
+
|
||||
+ if (old_dir != new_dir) {
|
||||
+ if (S_ISDIR(fst_inode->i_mode) && !S_ISDIR(snd_inode->i_mode)) {
|
||||
+ inc_nlink(new_dir);
|
||||
+ drop_nlink(old_dir);
|
||||
+ }
|
||||
+ else if (!S_ISDIR(fst_inode->i_mode) && S_ISDIR(snd_inode->i_mode)) {
|
||||
+ drop_nlink(new_dir);
|
||||
+ inc_nlink(old_dir);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ err = ubifs_jnl_xrename(c, old_dir, old_dentry, new_dir, new_dentry,
|
||||
+ sync);
|
||||
+
|
||||
+ unlock_4_inodes(old_dir, new_dir, NULL, NULL);
|
||||
+ ubifs_release_budget(c, &req);
|
||||
+
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+static int ubifs_rename2(struct inode *old_dir, struct dentry *old_dentry,
|
||||
+ struct inode *new_dir, struct dentry *new_dentry,
|
||||
+ unsigned int flags)
|
||||
+{
|
||||
+ if (flags & ~(RENAME_NOREPLACE | RENAME_WHITEOUT | RENAME_EXCHANGE))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ ubifs_assert(mutex_is_locked(&old_dir->i_mutex));
|
||||
+ ubifs_assert(mutex_is_locked(&new_dir->i_mutex));
|
||||
+
|
||||
+ if (flags & RENAME_EXCHANGE)
|
||||
+ return ubifs_xrename(old_dir, old_dentry, new_dir, new_dentry);
|
||||
+
|
||||
+ return ubifs_rename(old_dir, old_dentry, new_dir, new_dentry, flags);
|
||||
+}
|
||||
+
|
||||
int ubifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
|
||||
struct kstat *stat)
|
||||
{
|
||||
@@ -1338,7 +1391,7 @@ const struct inode_operations ubifs_dir_
|
||||
.mkdir = ubifs_mkdir,
|
||||
.rmdir = ubifs_rmdir,
|
||||
.mknod = ubifs_mknod,
|
||||
- .rename2 = ubifs_rename,
|
||||
+ .rename2 = ubifs_rename2,
|
||||
.setattr = ubifs_setattr,
|
||||
.getattr = ubifs_getattr,
|
||||
.setxattr = ubifs_setxattr,
|
||||
--- a/fs/ubifs/journal.c
|
||||
+++ b/fs/ubifs/journal.c
|
||||
@@ -908,6 +908,147 @@ int ubifs_jnl_delete_inode(struct ubifs_
|
||||
}
|
||||
|
||||
/**
|
||||
+ * ubifs_jnl_xrename - cross rename two directory entries.
|
||||
+ * @c: UBIFS file-system description object
|
||||
+ * @fst_dir: parent inode of 1st directory entry to exchange
|
||||
+ * @fst_dentry: 1st directory entry to exchange
|
||||
+ * @snd_dir: parent inode of 2nd directory entry to exchange
|
||||
+ * @snd_dentry: 2nd directory entry to exchange
|
||||
+ * @sync: non-zero if the write-buffer has to be synchronized
|
||||
+ *
|
||||
+ * This function implements the cross rename operation which may involve
|
||||
+ * writing 2 inodes and 2 directory entries. It marks the written inodes as clean
|
||||
+ * and returns zero on success. In case of failure, a negative error code is
|
||||
+ * returned.
|
||||
+ */
|
||||
+int ubifs_jnl_xrename(struct ubifs_info *c, const struct inode *fst_dir,
|
||||
+ const struct dentry *fst_dentry,
|
||||
+ const struct inode *snd_dir,
|
||||
+ const struct dentry *snd_dentry, int sync)
|
||||
+{
|
||||
+ union ubifs_key key;
|
||||
+ struct ubifs_dent_node *dent1, *dent2;
|
||||
+ int err, dlen1, dlen2, lnum, offs, len, plen = UBIFS_INO_NODE_SZ;
|
||||
+ int aligned_dlen1, aligned_dlen2;
|
||||
+ int twoparents = (fst_dir != snd_dir);
|
||||
+ const struct inode *fst_inode = d_inode(fst_dentry);
|
||||
+ const struct inode *snd_inode = d_inode(snd_dentry);
|
||||
+ void *p;
|
||||
+
|
||||
+ dbg_jnl("dent '%pd' in dir ino %lu between dent '%pd' in dir ino %lu",
|
||||
+ fst_dentry, fst_dir->i_ino, snd_dentry, snd_dir->i_ino);
|
||||
+
|
||||
+ ubifs_assert(ubifs_inode(fst_dir)->data_len == 0);
|
||||
+ ubifs_assert(ubifs_inode(snd_dir)->data_len == 0);
|
||||
+ ubifs_assert(mutex_is_locked(&ubifs_inode(fst_dir)->ui_mutex));
|
||||
+ ubifs_assert(mutex_is_locked(&ubifs_inode(snd_dir)->ui_mutex));
|
||||
+
|
||||
+ dlen1 = UBIFS_DENT_NODE_SZ + snd_dentry->d_name.len + 1;
|
||||
+ dlen2 = UBIFS_DENT_NODE_SZ + fst_dentry->d_name.len + 1;
|
||||
+ aligned_dlen1 = ALIGN(dlen1, 8);
|
||||
+ aligned_dlen2 = ALIGN(dlen2, 8);
|
||||
+
|
||||
+ len = aligned_dlen1 + aligned_dlen2 + ALIGN(plen, 8);
|
||||
+ if (twoparents)
|
||||
+ len += plen;
|
||||
+
|
||||
+ dent1 = kmalloc(len, GFP_NOFS);
|
||||
+ if (!dent1)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ /* Make reservation before allocating sequence numbers */
|
||||
+ err = make_reservation(c, BASEHD, len);
|
||||
+ if (err)
|
||||
+ goto out_free;
|
||||
+
|
||||
+ /* Make new dent for 1st entry */
|
||||
+ dent1->ch.node_type = UBIFS_DENT_NODE;
|
||||
+ dent_key_init_flash(c, &dent1->key, snd_dir->i_ino, &snd_dentry->d_name);
|
||||
+ dent1->inum = cpu_to_le64(fst_inode->i_ino);
|
||||
+ dent1->type = get_dent_type(fst_inode->i_mode);
|
||||
+ dent1->nlen = cpu_to_le16(snd_dentry->d_name.len);
|
||||
+ memcpy(dent1->name, snd_dentry->d_name.name, snd_dentry->d_name.len);
|
||||
+ dent1->name[snd_dentry->d_name.len] = '\0';
|
||||
+ zero_dent_node_unused(dent1);
|
||||
+ ubifs_prep_grp_node(c, dent1, dlen1, 0);
|
||||
+
|
||||
+ /* Make new dent for 2nd entry */
|
||||
+ dent2 = (void *)dent1 + aligned_dlen1;
|
||||
+ dent2->ch.node_type = UBIFS_DENT_NODE;
|
||||
+ dent_key_init_flash(c, &dent2->key, fst_dir->i_ino, &fst_dentry->d_name);
|
||||
+ dent2->inum = cpu_to_le64(snd_inode->i_ino);
|
||||
+ dent2->type = get_dent_type(snd_inode->i_mode);
|
||||
+ dent2->nlen = cpu_to_le16(fst_dentry->d_name.len);
|
||||
+ memcpy(dent2->name, fst_dentry->d_name.name, fst_dentry->d_name.len);
|
||||
+ dent2->name[fst_dentry->d_name.len] = '\0';
|
||||
+ zero_dent_node_unused(dent2);
|
||||
+ ubifs_prep_grp_node(c, dent2, dlen2, 0);
|
||||
+
|
||||
+ p = (void *)dent2 + aligned_dlen2;
|
||||
+ if (!twoparents)
|
||||
+ pack_inode(c, p, fst_dir, 1);
|
||||
+ else {
|
||||
+ pack_inode(c, p, fst_dir, 0);
|
||||
+ p += ALIGN(plen, 8);
|
||||
+ pack_inode(c, p, snd_dir, 1);
|
||||
+ }
|
||||
+
|
||||
+ err = write_head(c, BASEHD, dent1, len, &lnum, &offs, sync);
|
||||
+ if (err)
|
||||
+ goto out_release;
|
||||
+ if (!sync) {
|
||||
+ struct ubifs_wbuf *wbuf = &c->jheads[BASEHD].wbuf;
|
||||
+
|
||||
+ ubifs_wbuf_add_ino_nolock(wbuf, fst_dir->i_ino);
|
||||
+ ubifs_wbuf_add_ino_nolock(wbuf, snd_dir->i_ino);
|
||||
+ }
|
||||
+ release_head(c, BASEHD);
|
||||
+
|
||||
+ dent_key_init(c, &key, snd_dir->i_ino, &snd_dentry->d_name);
|
||||
+ err = ubifs_tnc_add_nm(c, &key, lnum, offs, dlen1, &snd_dentry->d_name);
|
||||
+ if (err)
|
||||
+ goto out_ro;
|
||||
+
|
||||
+ offs += aligned_dlen1;
|
||||
+ dent_key_init(c, &key, fst_dir->i_ino, &fst_dentry->d_name);
|
||||
+ err = ubifs_tnc_add_nm(c, &key, lnum, offs, dlen2, &fst_dentry->d_name);
|
||||
+ if (err)
|
||||
+ goto out_ro;
|
||||
+
|
||||
+ offs += aligned_dlen2;
|
||||
+
|
||||
+ ino_key_init(c, &key, fst_dir->i_ino);
|
||||
+ err = ubifs_tnc_add(c, &key, lnum, offs, plen);
|
||||
+ if (err)
|
||||
+ goto out_ro;
|
||||
+
|
||||
+ if (twoparents) {
|
||||
+ offs += ALIGN(plen, 8);
|
||||
+ ino_key_init(c, &key, snd_dir->i_ino);
|
||||
+ err = ubifs_tnc_add(c, &key, lnum, offs, plen);
|
||||
+ if (err)
|
||||
+ goto out_ro;
|
||||
+ }
|
||||
+
|
||||
+ finish_reservation(c);
|
||||
+
|
||||
+ mark_inode_clean(c, ubifs_inode(fst_dir));
|
||||
+ if (twoparents)
|
||||
+ mark_inode_clean(c, ubifs_inode(snd_dir));
|
||||
+ kfree(dent1);
|
||||
+ return 0;
|
||||
+
|
||||
+out_release:
|
||||
+ release_head(c, BASEHD);
|
||||
+out_ro:
|
||||
+ ubifs_ro_mode(c, err);
|
||||
+ finish_reservation(c);
|
||||
+out_free:
|
||||
+ kfree(dent1);
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
* ubifs_jnl_rename - rename a directory entry.
|
||||
* @c: UBIFS file-system description object
|
||||
* @old_dir: parent inode of directory entry to rename
|
||||
--- a/fs/ubifs/ubifs.h
|
||||
+++ b/fs/ubifs/ubifs.h
|
||||
@@ -1544,6 +1544,10 @@ int ubifs_jnl_write_data(struct ubifs_in
|
||||
const union ubifs_key *key, const void *buf, int len);
|
||||
int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode);
|
||||
int ubifs_jnl_delete_inode(struct ubifs_info *c, const struct inode *inode);
|
||||
+int ubifs_jnl_xrename(struct ubifs_info *c, const struct inode *fst_dir,
|
||||
+ const struct dentry *fst_dentry,
|
||||
+ const struct inode *snd_dir,
|
||||
+ const struct dentry *snd_dentry, int sync);
|
||||
int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
|
||||
const struct dentry *old_dentry,
|
||||
const struct inode *new_dir,
|
@ -1,30 +0,0 @@
|
||||
From: Richard Weinberger <richard@nod.at>
|
||||
Date: Tue, 13 Sep 2016 16:18:58 +0200
|
||||
Subject: [PATCH] ubifs: Use move variable in ubifs_rename()
|
||||
|
||||
...to make the code more consistent since we use
|
||||
move already in other places.
|
||||
|
||||
Signed-off-by: Richard Weinberger <richard@nod.at>
|
||||
---
|
||||
|
||||
--- a/fs/ubifs/journal.c
|
||||
+++ b/fs/ubifs/journal.c
|
||||
@@ -1100,7 +1100,7 @@ int ubifs_jnl_rename(struct ubifs_info *
|
||||
aligned_dlen1 = ALIGN(dlen1, 8);
|
||||
aligned_dlen2 = ALIGN(dlen2, 8);
|
||||
len = aligned_dlen1 + aligned_dlen2 + ALIGN(ilen, 8) + ALIGN(plen, 8);
|
||||
- if (old_dir != new_dir)
|
||||
+ if (move)
|
||||
len += plen;
|
||||
dent = kmalloc(len, GFP_NOFS);
|
||||
if (!dent)
|
||||
@@ -1216,7 +1216,7 @@ int ubifs_jnl_rename(struct ubifs_info *
|
||||
if (err)
|
||||
goto out_ro;
|
||||
|
||||
- if (old_dir != new_dir) {
|
||||
+ if (move) {
|
||||
offs += ALIGN(plen, 8);
|
||||
ino_key_init(c, &key, new_dir->i_ino);
|
||||
err = ubifs_tnc_add(c, &key, lnum, offs, plen);
|
@ -1,82 +0,0 @@
|
||||
From 854826c9d526fd81077742c3b000e3f7fcaef3ce Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Date: Tue, 20 Sep 2016 10:36:14 +0200
|
||||
Subject: [PATCH] ubifs: Drop softlimit and delta fields from struct ubifs_wbuf
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Values of these fields are set during init and never modified. They are
|
||||
used (read) in a single function only. There isn't really any reason to
|
||||
keep them in a struct. It only makes struct just a bit bigger without
|
||||
any visible gain.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
Reviewed-by: Boris Brezillon <boris.brezillon@free-electrons.com>
|
||||
Signed-off-by: Richard Weinberger <richard@nod.at>
|
||||
---
|
||||
fs/ubifs/io.c | 18 ++++++++++--------
|
||||
fs/ubifs/ubifs.h | 5 -----
|
||||
2 files changed, 10 insertions(+), 13 deletions(-)
|
||||
|
||||
--- a/fs/ubifs/io.c
|
||||
+++ b/fs/ubifs/io.c
|
||||
@@ -452,16 +452,22 @@ static enum hrtimer_restart wbuf_timer_c
|
||||
*/
|
||||
static void new_wbuf_timer_nolock(struct ubifs_wbuf *wbuf)
|
||||
{
|
||||
+ ktime_t softlimit = ktime_set(WBUF_TIMEOUT_SOFTLIMIT, 0);
|
||||
+ unsigned long long delta;
|
||||
+
|
||||
+ delta = WBUF_TIMEOUT_HARDLIMIT - WBUF_TIMEOUT_SOFTLIMIT;
|
||||
+ delta *= 1000000000ULL;
|
||||
+
|
||||
ubifs_assert(!hrtimer_active(&wbuf->timer));
|
||||
+ ubifs_assert(delta <= ULONG_MAX);
|
||||
|
||||
if (wbuf->no_timer)
|
||||
return;
|
||||
dbg_io("set timer for jhead %s, %llu-%llu millisecs",
|
||||
dbg_jhead(wbuf->jhead),
|
||||
- div_u64(ktime_to_ns(wbuf->softlimit), USEC_PER_SEC),
|
||||
- div_u64(ktime_to_ns(wbuf->softlimit) + wbuf->delta,
|
||||
- USEC_PER_SEC));
|
||||
- hrtimer_start_range_ns(&wbuf->timer, wbuf->softlimit, wbuf->delta,
|
||||
+ div_u64(ktime_to_ns(softlimit), USEC_PER_SEC),
|
||||
+ div_u64(ktime_to_ns(softlimit) + delta, USEC_PER_SEC));
|
||||
+ hrtimer_start_range_ns(&wbuf->timer, softlimit, delta,
|
||||
HRTIMER_MODE_REL);
|
||||
}
|
||||
|
||||
@@ -1059,10 +1065,6 @@ int ubifs_wbuf_init(struct ubifs_info *c
|
||||
|
||||
hrtimer_init(&wbuf->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
|
||||
wbuf->timer.function = wbuf_timer_callback_nolock;
|
||||
- wbuf->softlimit = ktime_set(WBUF_TIMEOUT_SOFTLIMIT, 0);
|
||||
- wbuf->delta = WBUF_TIMEOUT_HARDLIMIT - WBUF_TIMEOUT_SOFTLIMIT;
|
||||
- wbuf->delta *= 1000000000ULL;
|
||||
- ubifs_assert(wbuf->delta <= ULONG_MAX);
|
||||
return 0;
|
||||
}
|
||||
|
||||
--- a/fs/ubifs/ubifs.h
|
||||
+++ b/fs/ubifs/ubifs.h
|
||||
@@ -668,9 +668,6 @@ typedef int (*ubifs_lpt_scan_callback)(s
|
||||
* @io_mutex: serializes write-buffer I/O
|
||||
* @lock: serializes @buf, @lnum, @offs, @avail, @used, @next_ino and @inodes
|
||||
* fields
|
||||
- * @softlimit: soft write-buffer timeout interval
|
||||
- * @delta: hard and soft timeouts delta (the timer expire interval is @softlimit
|
||||
- * and @softlimit + @delta)
|
||||
* @timer: write-buffer timer
|
||||
* @no_timer: non-zero if this write-buffer does not have a timer
|
||||
* @need_sync: non-zero if the timer expired and the wbuf needs sync'ing
|
||||
@@ -699,8 +696,6 @@ struct ubifs_wbuf {
|
||||
int (*sync_callback)(struct ubifs_info *c, int lnum, int free, int pad);
|
||||
struct mutex io_mutex;
|
||||
spinlock_t lock;
|
||||
- ktime_t softlimit;
|
||||
- unsigned long long delta;
|
||||
struct hrtimer timer;
|
||||
unsigned int no_timer:1;
|
||||
unsigned int need_sync:1;
|
@ -1,66 +0,0 @@
|
||||
From 1b7fc2c0069f3864a3dda15430b7aded31c0bfcc Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Date: Tue, 20 Sep 2016 10:36:15 +0200
|
||||
Subject: [PATCH] ubifs: Use dirty_writeback_interval value for wbuf timer
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Right now wbuf timer has hardcoded timeouts and there is no place for
|
||||
manual adjustments. Some projects / cases many need that though. Few
|
||||
file systems allow doing that by respecting dirty_writeback_interval
|
||||
that can be set using sysctl (dirty_writeback_centisecs).
|
||||
|
||||
Lowering dirty_writeback_interval could be some way of dealing with user
|
||||
space apps lacking proper fsyncs. This is definitely *not* a perfect
|
||||
solution but we don't have ideal (user space) world. There were already
|
||||
advanced discussions on this matter, mostly when ext4 was introduced and
|
||||
it wasn't behaving as ext3. Anyway, the final decision was to add some
|
||||
hacks to the ext4, as trying to fix whole user space or adding new API
|
||||
was pointless.
|
||||
|
||||
We can't (and shouldn't?) just follow ext4. We can't e.g. sync on close
|
||||
as this would cause too many commits and flash wearing. On the other
|
||||
hand we still should allow some trade-off between -o sync and default
|
||||
wbuf timeout. Respecting dirty_writeback_interval should allow some sane
|
||||
cutomizations if used warily.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
Reviewed-by: Boris Brezillon <boris.brezillon@free-electrons.com>
|
||||
Signed-off-by: Richard Weinberger <richard@nod.at>
|
||||
---
|
||||
fs/ubifs/io.c | 8 ++++----
|
||||
fs/ubifs/ubifs.h | 4 ----
|
||||
2 files changed, 4 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/fs/ubifs/io.c
|
||||
+++ b/fs/ubifs/io.c
|
||||
@@ -452,11 +452,11 @@ static enum hrtimer_restart wbuf_timer_c
|
||||
*/
|
||||
static void new_wbuf_timer_nolock(struct ubifs_wbuf *wbuf)
|
||||
{
|
||||
- ktime_t softlimit = ktime_set(WBUF_TIMEOUT_SOFTLIMIT, 0);
|
||||
- unsigned long long delta;
|
||||
+ ktime_t softlimit = ms_to_ktime(dirty_writeback_interval * 10);
|
||||
+ unsigned long long delta = dirty_writeback_interval;
|
||||
|
||||
- delta = WBUF_TIMEOUT_HARDLIMIT - WBUF_TIMEOUT_SOFTLIMIT;
|
||||
- delta *= 1000000000ULL;
|
||||
+ /* centi to milli, milli to nano, then 10% */
|
||||
+ delta *= 10ULL * NSEC_PER_MSEC / 10ULL;
|
||||
|
||||
ubifs_assert(!hrtimer_active(&wbuf->timer));
|
||||
ubifs_assert(delta <= ULONG_MAX);
|
||||
--- a/fs/ubifs/ubifs.h
|
||||
+++ b/fs/ubifs/ubifs.h
|
||||
@@ -106,10 +106,6 @@
|
||||
*/
|
||||
#define BGT_NAME_PATTERN "ubifs_bgt%d_%d"
|
||||
|
||||
-/* Write-buffer synchronization timeout interval in seconds */
|
||||
-#define WBUF_TIMEOUT_SOFTLIMIT 3
|
||||
-#define WBUF_TIMEOUT_HARDLIMIT 5
|
||||
-
|
||||
/* Maximum possible inode number (only 32-bit inodes are supported now) */
|
||||
#define MAX_INUM 0xFFFFFFFF
|
||||
|
@ -1,22 +0,0 @@
|
||||
--- a/arch/mips/boot/compressed/string.c
|
||||
+++ b/arch/mips/boot/compressed/string.c
|
||||
@@ -26,3 +26,19 @@ void *memset(void *s, int c, size_t n)
|
||||
ss[i] = c;
|
||||
return s;
|
||||
}
|
||||
+
|
||||
+void *memmove(void *__dest, __const void *__src, size_t count)
|
||||
+{
|
||||
+ unsigned char *d = __dest;
|
||||
+ const unsigned char *s = __src;
|
||||
+
|
||||
+ if (__dest == __src)
|
||||
+ return __dest;
|
||||
+
|
||||
+ if (__dest < __src)
|
||||
+ return memcpy(__dest, __src, count);
|
||||
+
|
||||
+ while (count--)
|
||||
+ d[count] = s[count];
|
||||
+ return __dest;
|
||||
+}
|
@ -1,83 +0,0 @@
|
||||
From: Eric Dumazet <edumazet@google.com>
|
||||
Date: Wed, 31 Aug 2016 10:42:29 -0700
|
||||
Subject: [PATCH] softirq: let ksoftirqd do its job
|
||||
|
||||
A while back, Paolo and Hannes sent an RFC patch adding threaded-able
|
||||
napi poll loop support : (https://patchwork.ozlabs.org/patch/620657/)
|
||||
|
||||
The problem seems to be that softirqs are very aggressive and are often
|
||||
handled by the current process, even if we are under stress and that
|
||||
ksoftirqd was scheduled, so that innocent threads would have more chance
|
||||
to make progress.
|
||||
|
||||
This patch makes sure that if ksoftirq is running, we let it
|
||||
perform the softirq work.
|
||||
|
||||
Jonathan Corbet summarized the issue in https://lwn.net/Articles/687617/
|
||||
|
||||
Tested:
|
||||
|
||||
- NIC receiving traffic handled by CPU 0
|
||||
- UDP receiver running on CPU 0, using a single UDP socket.
|
||||
- Incoming flood of UDP packets targeting the UDP socket.
|
||||
|
||||
Before the patch, the UDP receiver could almost never get cpu cycles and
|
||||
could only receive ~2,000 packets per second.
|
||||
|
||||
After the patch, cpu cycles are split 50/50 between user application and
|
||||
ksoftirqd/0, and we can effectively read ~900,000 packets per second,
|
||||
a huge improvement in DOS situation. (Note that more packets are now
|
||||
dropped by the NIC itself, since the BH handlers get less cpu cycles to
|
||||
drain RX ring buffer)
|
||||
|
||||
Since the load runs in well identified threads context, an admin can
|
||||
more easily tune process scheduling parameters if needed.
|
||||
|
||||
Reported-by: Paolo Abeni <pabeni@redhat.com>
|
||||
Reported-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
|
||||
Signed-off-by: Eric Dumazet <edumazet@google.com>
|
||||
Cc: David Miller <davem@davemloft.net
|
||||
Cc: Jesper Dangaard Brouer <jbrouer@redhat.com>
|
||||
Cc: Peter Zijlstra <peterz@infradead.org>
|
||||
Cc: Rik van Riel <riel@redhat.com>
|
||||
---
|
||||
|
||||
--- a/kernel/softirq.c
|
||||
+++ b/kernel/softirq.c
|
||||
@@ -78,6 +78,17 @@ static void wakeup_softirqd(void)
|
||||
}
|
||||
|
||||
/*
|
||||
+ * If ksoftirqd is scheduled, we do not want to process pending softirqs
|
||||
+ * right now. Let ksoftirqd handle this at its own rate, to get fairness.
|
||||
+ */
|
||||
+static bool ksoftirqd_running(void)
|
||||
+{
|
||||
+ struct task_struct *tsk = __this_cpu_read(ksoftirqd);
|
||||
+
|
||||
+ return tsk && (tsk->state == TASK_RUNNING);
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
* preempt_count and SOFTIRQ_OFFSET usage:
|
||||
* - preempt_count is changed by SOFTIRQ_OFFSET on entering or leaving
|
||||
* softirq processing.
|
||||
@@ -313,7 +324,7 @@ asmlinkage __visible void do_softirq(voi
|
||||
|
||||
pending = local_softirq_pending();
|
||||
|
||||
- if (pending)
|
||||
+ if (pending && !ksoftirqd_running())
|
||||
do_softirq_own_stack();
|
||||
|
||||
local_irq_restore(flags);
|
||||
@@ -340,6 +351,9 @@ void irq_enter(void)
|
||||
|
||||
static inline void invoke_softirq(void)
|
||||
{
|
||||
+ if (ksoftirqd_running())
|
||||
+ return;
|
||||
+
|
||||
if (!force_irqthreads) {
|
||||
#ifdef CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK
|
||||
/*
|
@ -1,34 +0,0 @@
|
||||
From a4077ce5871304f8a78f80b74b18b6052a410f1a Mon Sep 17 00:00:00 2001
|
||||
From: "Andrey Jr. Melnikov" <temnota.am@gmail.com>
|
||||
Date: Thu, 8 Dec 2016 19:57:08 +0300
|
||||
Subject: [PATCH] mtd: nand: Add Winbond manufacturer id
|
||||
|
||||
Add WINBOND manufacturer id.
|
||||
|
||||
Signed-off-by: Andrey Jr. Melnikov <temnota.am@gmail.com>
|
||||
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
|
||||
---
|
||||
drivers/mtd/nand/nand_ids.c | 1 +
|
||||
include/linux/mtd/nand.h | 1 +
|
||||
2 files changed, 2 insertions(+)
|
||||
|
||||
--- a/drivers/mtd/nand/nand_ids.c
|
||||
+++ b/drivers/mtd/nand/nand_ids.c
|
||||
@@ -181,6 +181,7 @@ struct nand_manufacturers nand_manuf_ids
|
||||
{NAND_MFR_SANDISK, "SanDisk"},
|
||||
{NAND_MFR_INTEL, "Intel"},
|
||||
{NAND_MFR_ATO, "ATO"},
|
||||
+ {NAND_MFR_WINBOND, "Winbond"},
|
||||
{0x0, "Unknown"}
|
||||
};
|
||||
|
||||
--- a/include/linux/mtd/nand.h
|
||||
+++ b/include/linux/mtd/nand.h
|
||||
@@ -736,6 +736,7 @@ struct nand_chip {
|
||||
#define NAND_MFR_SANDISK 0x45
|
||||
#define NAND_MFR_INTEL 0x89
|
||||
#define NAND_MFR_ATO 0x9b
|
||||
+#define NAND_MFR_WINBOND 0xef
|
||||
|
||||
/* The maximum expected count of bytes in the NAND ID sequence */
|
||||
#define NAND_MAX_ID_LEN 8
|
@ -1,46 +0,0 @@
|
||||
From 1f820f538f7396db7fd40684b9c3620816acc5a3 Mon Sep 17 00:00:00 2001
|
||||
From: Arnd Bergmann <arnd@arndb.de>
|
||||
Date: Fri, 29 Jan 2016 12:39:12 +0100
|
||||
Subject: [PATCH] net: bgmac: clarify CONFIG_BCMA dependency
|
||||
|
||||
The bgmac driver depends on BCMA_HOST_SOC, which is only used
|
||||
when CONFIG_BCMA is enabled. However, it is a bool option and can
|
||||
be set when CONFIG_BCMA=m, and then bgmac can be built-in, leading
|
||||
to an obvious link error:
|
||||
|
||||
drivers/built-in.o: In function `bgmac_init':
|
||||
:(.init.text+0x7f2c): undefined reference to `__bcma_driver_register'
|
||||
drivers/built-in.o: In function `bgmac_exit':
|
||||
:(.exit.text+0x110a): undefined reference to `bcma_driver_unregister'
|
||||
|
||||
To avoid this case, we need to depend on both BCMA and BCMA_SOC,
|
||||
as this patch does. I'm also trying to make the dependency more
|
||||
readable by splitting it into three lines, and adding a COMPILE_TEST
|
||||
alternative so we can test-build it in all configurations that
|
||||
support BCMA.
|
||||
|
||||
The added dependency on FIXED_PHY addresses a related issue where
|
||||
we cannot call fixed_phy_register() when CONFIG_FIXED_PHY=m and
|
||||
CONFIG_BGMAC=y.
|
||||
|
||||
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/ethernet/broadcom/Kconfig | 5 ++++-
|
||||
1 file changed, 4 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/net/ethernet/broadcom/Kconfig
|
||||
+++ b/drivers/net/ethernet/broadcom/Kconfig
|
||||
@@ -151,8 +151,11 @@ config BNX2X_VXLAN
|
||||
|
||||
config BGMAC
|
||||
tristate "BCMA bus GBit core support"
|
||||
- depends on BCMA_HOST_SOC && HAS_DMA && (BCM47XX || ARCH_BCM_5301X)
|
||||
+ depends on BCMA && BCMA_HOST_SOC
|
||||
+ depends on HAS_DMA
|
||||
+ depends on BCM47XX || ARCH_BCM_5301X || COMPILE_TEST
|
||||
select PHYLIB
|
||||
+ select FIXED_PHY
|
||||
---help---
|
||||
This driver supports GBit MAC and BCM4706 GBit MAC cores on BCMA bus.
|
||||
They can be found on BCM47xx SoCs and provide gigabit ethernet.
|
@ -1,106 +0,0 @@
|
||||
From 387b75f8b31437792e8334390fdf5cf060d1e3da Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
|
||||
Date: Tue, 2 Feb 2016 07:47:14 +0100
|
||||
Subject: [PATCH] bgmac: add helper checking for BCM4707 / BCM53018 chip id
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Chipsets with BCM4707 / BCM53018 ID require special handling at a few
|
||||
places in the code. It's likely there will be more IDs to check in the
|
||||
future. To simplify it add this trivial helper.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/ethernet/broadcom/bgmac.c | 30 ++++++++++++++++--------------
|
||||
1 file changed, 16 insertions(+), 14 deletions(-)
|
||||
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac.c
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac.c
|
||||
@@ -26,6 +26,17 @@ static const struct bcma_device_id bgmac
|
||||
};
|
||||
MODULE_DEVICE_TABLE(bcma, bgmac_bcma_tbl);
|
||||
|
||||
+static inline bool bgmac_is_bcm4707_family(struct bgmac *bgmac)
|
||||
+{
|
||||
+ switch (bgmac->core->bus->chipinfo.id) {
|
||||
+ case BCMA_CHIP_ID_BCM4707:
|
||||
+ case BCMA_CHIP_ID_BCM53018:
|
||||
+ return true;
|
||||
+ default:
|
||||
+ return false;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static bool bgmac_wait_value(struct bcma_device *core, u16 reg, u32 mask,
|
||||
u32 value, int timeout)
|
||||
{
|
||||
@@ -991,11 +1002,9 @@ static void bgmac_mac_speed(struct bgmac
|
||||
static void bgmac_miiconfig(struct bgmac *bgmac)
|
||||
{
|
||||
struct bcma_device *core = bgmac->core;
|
||||
- struct bcma_chipinfo *ci = &core->bus->chipinfo;
|
||||
u8 imode;
|
||||
|
||||
- if (ci->id == BCMA_CHIP_ID_BCM4707 ||
|
||||
- ci->id == BCMA_CHIP_ID_BCM53018) {
|
||||
+ if (bgmac_is_bcm4707_family(bgmac)) {
|
||||
bcma_awrite32(core, BCMA_IOCTL,
|
||||
bcma_aread32(core, BCMA_IOCTL) | 0x40 |
|
||||
BGMAC_BCMA_IOCTL_SW_CLKEN);
|
||||
@@ -1059,9 +1068,7 @@ static void bgmac_chip_reset(struct bgma
|
||||
}
|
||||
|
||||
/* Request Misc PLL for corerev > 2 */
|
||||
- if (core->id.rev > 2 &&
|
||||
- ci->id != BCMA_CHIP_ID_BCM4707 &&
|
||||
- ci->id != BCMA_CHIP_ID_BCM53018) {
|
||||
+ if (core->id.rev > 2 && !bgmac_is_bcm4707_family(bgmac)) {
|
||||
bgmac_set(bgmac, BCMA_CLKCTLST,
|
||||
BGMAC_BCMA_CLKCTLST_MISC_PLL_REQ);
|
||||
bgmac_wait_value(bgmac->core, BCMA_CLKCTLST,
|
||||
@@ -1197,8 +1204,7 @@ static void bgmac_enable(struct bgmac *b
|
||||
break;
|
||||
}
|
||||
|
||||
- if (ci->id != BCMA_CHIP_ID_BCM4707 &&
|
||||
- ci->id != BCMA_CHIP_ID_BCM53018) {
|
||||
+ if (!bgmac_is_bcm4707_family(bgmac)) {
|
||||
rxq_ctl = bgmac_read(bgmac, BGMAC_RXQ_CTL);
|
||||
rxq_ctl &= ~BGMAC_RXQ_CTL_MDP_MASK;
|
||||
bp_clk = bcma_pmu_get_bus_clock(&bgmac->core->bus->drv_cc) /
|
||||
@@ -1477,14 +1483,12 @@ static int bgmac_fixed_phy_register(stru
|
||||
|
||||
static int bgmac_mii_register(struct bgmac *bgmac)
|
||||
{
|
||||
- struct bcma_chipinfo *ci = &bgmac->core->bus->chipinfo;
|
||||
struct mii_bus *mii_bus;
|
||||
struct phy_device *phy_dev;
|
||||
char bus_id[MII_BUS_ID_SIZE + 3];
|
||||
int i, err = 0;
|
||||
|
||||
- if (ci->id == BCMA_CHIP_ID_BCM4707 ||
|
||||
- ci->id == BCMA_CHIP_ID_BCM53018)
|
||||
+ if (bgmac_is_bcm4707_family(bgmac))
|
||||
return bgmac_fixed_phy_register(bgmac);
|
||||
|
||||
mii_bus = mdiobus_alloc();
|
||||
@@ -1555,7 +1559,6 @@ static void bgmac_mii_unregister(struct
|
||||
/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipattach */
|
||||
static int bgmac_probe(struct bcma_device *core)
|
||||
{
|
||||
- struct bcma_chipinfo *ci = &core->bus->chipinfo;
|
||||
struct net_device *net_dev;
|
||||
struct bgmac *bgmac;
|
||||
struct ssb_sprom *sprom = &core->bus->sprom;
|
||||
@@ -1641,8 +1644,7 @@ static int bgmac_probe(struct bcma_devic
|
||||
bgmac_chip_reset(bgmac);
|
||||
|
||||
/* For Northstar, we have to take all GMAC core out of reset */
|
||||
- if (ci->id == BCMA_CHIP_ID_BCM4707 ||
|
||||
- ci->id == BCMA_CHIP_ID_BCM53018) {
|
||||
+ if (bgmac_is_bcm4707_family(bgmac)) {
|
||||
struct bcma_device *ns_core;
|
||||
int ns_gmac;
|
||||
|
@ -1,39 +0,0 @@
|
||||
From 9e4e6206c67ae11d68fc96882256f37c237087d4 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
|
||||
Date: Mon, 22 Feb 2016 22:51:13 +0100
|
||||
Subject: [PATCH] bgmac: support Ethernet device on BCM47094 SoC
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
It needs very similar workarounds to the one on BCM4707. It was tested
|
||||
on D-Link DIR-885L home router.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/ethernet/broadcom/bgmac.c | 6 ++++--
|
||||
1 file changed, 4 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac.c
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac.c
|
||||
@@ -30,6 +30,7 @@ static inline bool bgmac_is_bcm4707_fami
|
||||
{
|
||||
switch (bgmac->core->bus->chipinfo.id) {
|
||||
case BCMA_CHIP_ID_BCM4707:
|
||||
+ case BCMA_CHIP_ID_BCM47094:
|
||||
case BCMA_CHIP_ID_BCM53018:
|
||||
return true;
|
||||
default:
|
||||
@@ -1056,8 +1057,9 @@ static void bgmac_chip_reset(struct bgma
|
||||
(ci->id == BCMA_CHIP_ID_BCM53572 && ci->pkg == BCMA_PKG_ID_BCM47188))
|
||||
iost &= ~BGMAC_BCMA_IOST_ATTACHED;
|
||||
|
||||
- /* 3GMAC: for BCM4707, only do core reset at bgmac_probe() */
|
||||
- if (ci->id != BCMA_CHIP_ID_BCM4707) {
|
||||
+ /* 3GMAC: for BCM4707 & BCM47094, only do core reset at bgmac_probe() */
|
||||
+ if (ci->id != BCMA_CHIP_ID_BCM4707 &&
|
||||
+ ci->id != BCMA_CHIP_ID_BCM47094) {
|
||||
flags = 0;
|
||||
if (iost & BGMAC_BCMA_IOST_ATTACHED) {
|
||||
flags = BGMAC_BCMA_IOCTL_SW_CLKEN;
|
@ -1,34 +0,0 @@
|
||||
From c02bc350f9dbce7d637c394a6e1c4d29dc5b28b2 Mon Sep 17 00:00:00 2001
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Tue, 12 Apr 2016 18:27:29 +0200
|
||||
Subject: [PATCH] bgmac: fix MAC soft-reset bit for corerev > 4
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Only core revisions older than 4 use BGMAC_CMDCFG_SR_REV0. This mainly
|
||||
fixes support for BCM4708A0KF SoCs with Ethernet core rev 5 (it means
|
||||
only some devices as most of BCM4708A0KF-s got core rev 4).
|
||||
This was tested for regressions on BCM47094 which doesn't seem to care
|
||||
which bit gets used.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac.h
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac.h
|
||||
@@ -199,9 +199,9 @@
|
||||
#define BGMAC_CMDCFG_TAI 0x00000200
|
||||
#define BGMAC_CMDCFG_HD 0x00000400 /* Set if in half duplex mode */
|
||||
#define BGMAC_CMDCFG_HD_SHIFT 10
|
||||
-#define BGMAC_CMDCFG_SR_REV0 0x00000800 /* Set to reset mode, for other revs */
|
||||
-#define BGMAC_CMDCFG_SR_REV4 0x00002000 /* Set to reset mode, only for core rev 4 */
|
||||
-#define BGMAC_CMDCFG_SR(rev) ((rev == 4) ? BGMAC_CMDCFG_SR_REV4 : BGMAC_CMDCFG_SR_REV0)
|
||||
+#define BGMAC_CMDCFG_SR_REV0 0x00000800 /* Set to reset mode, for core rev 0-3 */
|
||||
+#define BGMAC_CMDCFG_SR_REV4 0x00002000 /* Set to reset mode, for core rev >= 4 */
|
||||
+#define BGMAC_CMDCFG_SR(rev) ((rev >= 4) ? BGMAC_CMDCFG_SR_REV4 : BGMAC_CMDCFG_SR_REV0)
|
||||
#define BGMAC_CMDCFG_ML 0x00008000 /* Set to activate mac loopback mode */
|
||||
#define BGMAC_CMDCFG_AE 0x00400000
|
||||
#define BGMAC_CMDCFG_CFE 0x00800000
|
@ -1,25 +0,0 @@
|
||||
From 2022e9d50798aa592887ccb5a7d045e537f3855f Mon Sep 17 00:00:00 2001
|
||||
From: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Date: Tue, 7 Jun 2016 15:06:13 -0700
|
||||
Subject: [PATCH 1/3] bgmac: Bind net_device with backing device structure
|
||||
|
||||
In preparation for allowing different helpers to be utilized against
|
||||
network devices created by the bgmac driver, make sure that we bind the
|
||||
net_device with core->dev.
|
||||
|
||||
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/ethernet/broadcom/bgmac.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac.c
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac.c
|
||||
@@ -1604,6 +1604,7 @@ static int bgmac_probe(struct bcma_devic
|
||||
bgmac->net_dev = net_dev;
|
||||
bgmac->core = core;
|
||||
bcma_set_drvdata(core, bgmac);
|
||||
+ SET_NETDEV_DEV(net_dev, &core->dev);
|
||||
|
||||
/* Defaults */
|
||||
memcpy(bgmac->net_dev->dev_addr, mac, ETH_ALEN);
|
@ -1,175 +0,0 @@
|
||||
From f6613d4fa937fa8388f2c1cb4e69ccc25e9e2336 Mon Sep 17 00:00:00 2001
|
||||
From: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Date: Tue, 7 Jun 2016 15:06:14 -0700
|
||||
Subject: [PATCH 2/3] bgmac: Add support for ethtool statistics
|
||||
|
||||
Read the statistics from the BGMAC's builtin MAC and return them to
|
||||
user-space using the standard ethtool helpers.
|
||||
|
||||
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/ethernet/broadcom/bgmac.c | 124 ++++++++++++++++++++++++++++++++++
|
||||
drivers/net/ethernet/broadcom/bgmac.h | 4 +-
|
||||
2 files changed, 126 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac.c
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac.c
|
||||
@@ -1387,6 +1387,127 @@ static const struct net_device_ops bgmac
|
||||
* ethtool_ops
|
||||
**************************************************/
|
||||
|
||||
+struct bgmac_stat {
|
||||
+ u8 size;
|
||||
+ u32 offset;
|
||||
+ const char *name;
|
||||
+};
|
||||
+
|
||||
+static struct bgmac_stat bgmac_get_strings_stats[] = {
|
||||
+ { 8, BGMAC_TX_GOOD_OCTETS, "tx_good_octets" },
|
||||
+ { 4, BGMAC_TX_GOOD_PKTS, "tx_good" },
|
||||
+ { 8, BGMAC_TX_OCTETS, "tx_octets" },
|
||||
+ { 4, BGMAC_TX_PKTS, "tx_pkts" },
|
||||
+ { 4, BGMAC_TX_BROADCAST_PKTS, "tx_broadcast" },
|
||||
+ { 4, BGMAC_TX_MULTICAST_PKTS, "tx_multicast" },
|
||||
+ { 4, BGMAC_TX_LEN_64, "tx_64" },
|
||||
+ { 4, BGMAC_TX_LEN_65_TO_127, "tx_65_127" },
|
||||
+ { 4, BGMAC_TX_LEN_128_TO_255, "tx_128_255" },
|
||||
+ { 4, BGMAC_TX_LEN_256_TO_511, "tx_256_511" },
|
||||
+ { 4, BGMAC_TX_LEN_512_TO_1023, "tx_512_1023" },
|
||||
+ { 4, BGMAC_TX_LEN_1024_TO_1522, "tx_1024_1522" },
|
||||
+ { 4, BGMAC_TX_LEN_1523_TO_2047, "tx_1523_2047" },
|
||||
+ { 4, BGMAC_TX_LEN_2048_TO_4095, "tx_2048_4095" },
|
||||
+ { 4, BGMAC_TX_LEN_4096_TO_8191, "tx_4096_8191" },
|
||||
+ { 4, BGMAC_TX_LEN_8192_TO_MAX, "tx_8192_max" },
|
||||
+ { 4, BGMAC_TX_JABBER_PKTS, "tx_jabber" },
|
||||
+ { 4, BGMAC_TX_OVERSIZE_PKTS, "tx_oversize" },
|
||||
+ { 4, BGMAC_TX_FRAGMENT_PKTS, "tx_fragment" },
|
||||
+ { 4, BGMAC_TX_UNDERRUNS, "tx_underruns" },
|
||||
+ { 4, BGMAC_TX_TOTAL_COLS, "tx_total_cols" },
|
||||
+ { 4, BGMAC_TX_SINGLE_COLS, "tx_single_cols" },
|
||||
+ { 4, BGMAC_TX_MULTIPLE_COLS, "tx_multiple_cols" },
|
||||
+ { 4, BGMAC_TX_EXCESSIVE_COLS, "tx_excessive_cols" },
|
||||
+ { 4, BGMAC_TX_LATE_COLS, "tx_late_cols" },
|
||||
+ { 4, BGMAC_TX_DEFERED, "tx_defered" },
|
||||
+ { 4, BGMAC_TX_CARRIER_LOST, "tx_carrier_lost" },
|
||||
+ { 4, BGMAC_TX_PAUSE_PKTS, "tx_pause" },
|
||||
+ { 4, BGMAC_TX_UNI_PKTS, "tx_unicast" },
|
||||
+ { 4, BGMAC_TX_Q0_PKTS, "tx_q0" },
|
||||
+ { 8, BGMAC_TX_Q0_OCTETS, "tx_q0_octets" },
|
||||
+ { 4, BGMAC_TX_Q1_PKTS, "tx_q1" },
|
||||
+ { 8, BGMAC_TX_Q1_OCTETS, "tx_q1_octets" },
|
||||
+ { 4, BGMAC_TX_Q2_PKTS, "tx_q2" },
|
||||
+ { 8, BGMAC_TX_Q2_OCTETS, "tx_q2_octets" },
|
||||
+ { 4, BGMAC_TX_Q3_PKTS, "tx_q3" },
|
||||
+ { 8, BGMAC_TX_Q3_OCTETS, "tx_q3_octets" },
|
||||
+ { 8, BGMAC_RX_GOOD_OCTETS, "rx_good_octets" },
|
||||
+ { 4, BGMAC_RX_GOOD_PKTS, "rx_good" },
|
||||
+ { 8, BGMAC_RX_OCTETS, "rx_octets" },
|
||||
+ { 4, BGMAC_RX_PKTS, "rx_pkts" },
|
||||
+ { 4, BGMAC_RX_BROADCAST_PKTS, "rx_broadcast" },
|
||||
+ { 4, BGMAC_RX_MULTICAST_PKTS, "rx_multicast" },
|
||||
+ { 4, BGMAC_RX_LEN_64, "rx_64" },
|
||||
+ { 4, BGMAC_RX_LEN_65_TO_127, "rx_65_127" },
|
||||
+ { 4, BGMAC_RX_LEN_128_TO_255, "rx_128_255" },
|
||||
+ { 4, BGMAC_RX_LEN_256_TO_511, "rx_256_511" },
|
||||
+ { 4, BGMAC_RX_LEN_512_TO_1023, "rx_512_1023" },
|
||||
+ { 4, BGMAC_RX_LEN_1024_TO_1522, "rx_1024_1522" },
|
||||
+ { 4, BGMAC_RX_LEN_1523_TO_2047, "rx_1523_2047" },
|
||||
+ { 4, BGMAC_RX_LEN_2048_TO_4095, "rx_2048_4095" },
|
||||
+ { 4, BGMAC_RX_LEN_4096_TO_8191, "rx_4096_8191" },
|
||||
+ { 4, BGMAC_RX_LEN_8192_TO_MAX, "rx_8192_max" },
|
||||
+ { 4, BGMAC_RX_JABBER_PKTS, "rx_jabber" },
|
||||
+ { 4, BGMAC_RX_OVERSIZE_PKTS, "rx_oversize" },
|
||||
+ { 4, BGMAC_RX_FRAGMENT_PKTS, "rx_fragment" },
|
||||
+ { 4, BGMAC_RX_MISSED_PKTS, "rx_missed" },
|
||||
+ { 4, BGMAC_RX_CRC_ALIGN_ERRS, "rx_crc_align" },
|
||||
+ { 4, BGMAC_RX_UNDERSIZE, "rx_undersize" },
|
||||
+ { 4, BGMAC_RX_CRC_ERRS, "rx_crc" },
|
||||
+ { 4, BGMAC_RX_ALIGN_ERRS, "rx_align" },
|
||||
+ { 4, BGMAC_RX_SYMBOL_ERRS, "rx_symbol" },
|
||||
+ { 4, BGMAC_RX_PAUSE_PKTS, "rx_pause" },
|
||||
+ { 4, BGMAC_RX_NONPAUSE_PKTS, "rx_nonpause" },
|
||||
+ { 4, BGMAC_RX_SACHANGES, "rx_sa_changes" },
|
||||
+ { 4, BGMAC_RX_UNI_PKTS, "rx_unicast" },
|
||||
+};
|
||||
+
|
||||
+#define BGMAC_STATS_LEN ARRAY_SIZE(bgmac_get_strings_stats)
|
||||
+
|
||||
+static int bgmac_get_sset_count(struct net_device *dev, int string_set)
|
||||
+{
|
||||
+ switch (string_set) {
|
||||
+ case ETH_SS_STATS:
|
||||
+ return BGMAC_STATS_LEN;
|
||||
+ }
|
||||
+
|
||||
+ return -EOPNOTSUPP;
|
||||
+}
|
||||
+
|
||||
+static void bgmac_get_strings(struct net_device *dev, u32 stringset,
|
||||
+ u8 *data)
|
||||
+{
|
||||
+ int i;
|
||||
+
|
||||
+ if (stringset != ETH_SS_STATS)
|
||||
+ return;
|
||||
+
|
||||
+ for (i = 0; i < BGMAC_STATS_LEN; i++)
|
||||
+ strlcpy(data + i * ETH_GSTRING_LEN,
|
||||
+ bgmac_get_strings_stats[i].name, ETH_GSTRING_LEN);
|
||||
+}
|
||||
+
|
||||
+static void bgmac_get_ethtool_stats(struct net_device *dev,
|
||||
+ struct ethtool_stats *ss, uint64_t *data)
|
||||
+{
|
||||
+ struct bgmac *bgmac = netdev_priv(dev);
|
||||
+ const struct bgmac_stat *s;
|
||||
+ unsigned int i;
|
||||
+ u64 val;
|
||||
+
|
||||
+ if (!netif_running(dev))
|
||||
+ return;
|
||||
+
|
||||
+ for (i = 0; i < BGMAC_STATS_LEN; i++) {
|
||||
+ s = &bgmac_get_strings_stats[i];
|
||||
+ val = 0;
|
||||
+ if (s->size == 8)
|
||||
+ val = (u64)bgmac_read(bgmac, s->offset + 4) << 32;
|
||||
+ val |= bgmac_read(bgmac, s->offset);
|
||||
+ data[i] = val;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static int bgmac_get_settings(struct net_device *net_dev,
|
||||
struct ethtool_cmd *cmd)
|
||||
{
|
||||
@@ -1411,6 +1532,9 @@ static void bgmac_get_drvinfo(struct net
|
||||
}
|
||||
|
||||
static const struct ethtool_ops bgmac_ethtool_ops = {
|
||||
+ .get_strings = bgmac_get_strings,
|
||||
+ .get_sset_count = bgmac_get_sset_count,
|
||||
+ .get_ethtool_stats = bgmac_get_ethtool_stats,
|
||||
.get_settings = bgmac_get_settings,
|
||||
.set_settings = bgmac_set_settings,
|
||||
.get_drvinfo = bgmac_get_drvinfo,
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac.h
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac.h
|
||||
@@ -123,7 +123,7 @@
|
||||
#define BGMAC_TX_LEN_1024_TO_1522 0x334
|
||||
#define BGMAC_TX_LEN_1523_TO_2047 0x338
|
||||
#define BGMAC_TX_LEN_2048_TO_4095 0x33c
|
||||
-#define BGMAC_TX_LEN_4095_TO_8191 0x340
|
||||
+#define BGMAC_TX_LEN_4096_TO_8191 0x340
|
||||
#define BGMAC_TX_LEN_8192_TO_MAX 0x344
|
||||
#define BGMAC_TX_JABBER_PKTS 0x348 /* Error */
|
||||
#define BGMAC_TX_OVERSIZE_PKTS 0x34c /* Error */
|
||||
@@ -166,7 +166,7 @@
|
||||
#define BGMAC_RX_LEN_1024_TO_1522 0x3e4
|
||||
#define BGMAC_RX_LEN_1523_TO_2047 0x3e8
|
||||
#define BGMAC_RX_LEN_2048_TO_4095 0x3ec
|
||||
-#define BGMAC_RX_LEN_4095_TO_8191 0x3f0
|
||||
+#define BGMAC_RX_LEN_4096_TO_8191 0x3f0
|
||||
#define BGMAC_RX_LEN_8192_TO_MAX 0x3f4
|
||||
#define BGMAC_RX_JABBER_PKTS 0x3f8 /* Error */
|
||||
#define BGMAC_RX_OVERSIZE_PKTS 0x3fc /* Error */
|
@ -1,68 +0,0 @@
|
||||
From 6d490f62a4c7f11c552591bdd08eda3636aa0db9 Mon Sep 17 00:00:00 2001
|
||||
From: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Date: Tue, 7 Jun 2016 15:06:15 -0700
|
||||
Subject: [PATCH 3/3] bgmac: Maintain some netdev statistics
|
||||
|
||||
Add a few netdev statistics to report transmitted and received bytes and
|
||||
packets and a few obvious errors.
|
||||
|
||||
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/ethernet/broadcom/bgmac.c | 10 ++++++++++
|
||||
1 file changed, 10 insertions(+)
|
||||
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac.c
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac.c
|
||||
@@ -246,6 +246,8 @@ err_dma_head:
|
||||
|
||||
err_drop:
|
||||
dev_kfree_skb(skb);
|
||||
+ net_dev->stats.tx_dropped++;
|
||||
+ net_dev->stats.tx_errors++;
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
@@ -285,6 +287,8 @@ static void bgmac_dma_tx_free(struct bgm
|
||||
DMA_TO_DEVICE);
|
||||
|
||||
if (slot->skb) {
|
||||
+ bgmac->net_dev->stats.tx_bytes += slot->skb->len;
|
||||
+ bgmac->net_dev->stats.tx_packets++;
|
||||
bytes_compl += slot->skb->len;
|
||||
pkts_compl++;
|
||||
|
||||
@@ -468,6 +472,7 @@ static int bgmac_dma_rx_read(struct bgma
|
||||
bgmac_err(bgmac, "Found poisoned packet at slot %d, DMA issue!\n",
|
||||
ring->start);
|
||||
put_page(virt_to_head_page(buf));
|
||||
+ bgmac->net_dev->stats.rx_errors++;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -475,6 +480,8 @@ static int bgmac_dma_rx_read(struct bgma
|
||||
bgmac_err(bgmac, "Found oversized packet at slot %d, DMA issue!\n",
|
||||
ring->start);
|
||||
put_page(virt_to_head_page(buf));
|
||||
+ bgmac->net_dev->stats.rx_length_errors++;
|
||||
+ bgmac->net_dev->stats.rx_errors++;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -485,6 +492,7 @@ static int bgmac_dma_rx_read(struct bgma
|
||||
if (unlikely(!skb)) {
|
||||
bgmac_err(bgmac, "build_skb failed\n");
|
||||
put_page(virt_to_head_page(buf));
|
||||
+ bgmac->net_dev->stats.rx_errors++;
|
||||
break;
|
||||
}
|
||||
skb_put(skb, BGMAC_RX_FRAME_OFFSET +
|
||||
@@ -494,6 +502,8 @@ static int bgmac_dma_rx_read(struct bgma
|
||||
|
||||
skb_checksum_none_assert(skb);
|
||||
skb->protocol = eth_type_trans(skb, bgmac->net_dev);
|
||||
+ bgmac->net_dev->stats.rx_bytes += len;
|
||||
+ bgmac->net_dev->stats.rx_packets++;
|
||||
napi_gro_receive(&bgmac->napi, skb);
|
||||
handled++;
|
||||
} while (0);
|
@ -1,105 +0,0 @@
|
||||
From b21fcb259313bcf7d4f73ecd5e44948995c8957c Mon Sep 17 00:00:00 2001
|
||||
From: Philippe Reynes <tremyfr@gmail.com>
|
||||
Date: Sun, 19 Jun 2016 22:37:05 +0200
|
||||
Subject: [PATCH 1/2] net: ethernet: bgmac: use phydev from struct net_device
|
||||
|
||||
The private structure contain a pointer to phydev, but the structure
|
||||
net_device already contain such pointer. So we can remove the pointer
|
||||
phydev in the private structure, and update the driver to use the
|
||||
one contained in struct net_device.
|
||||
|
||||
Signed-off-by: Philippe Reynes <tremyfr@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/ethernet/broadcom/bgmac.c | 17 ++++++-----------
|
||||
drivers/net/ethernet/broadcom/bgmac.h | 1 -
|
||||
2 files changed, 6 insertions(+), 12 deletions(-)
|
||||
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac.c
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac.c
|
||||
@@ -1324,7 +1324,7 @@ static int bgmac_open(struct net_device
|
||||
}
|
||||
napi_enable(&bgmac->napi);
|
||||
|
||||
- phy_start(bgmac->phy_dev);
|
||||
+ phy_start(net_dev->phydev);
|
||||
|
||||
netif_start_queue(net_dev);
|
||||
|
||||
@@ -1337,7 +1337,7 @@ static int bgmac_stop(struct net_device
|
||||
|
||||
netif_carrier_off(net_dev);
|
||||
|
||||
- phy_stop(bgmac->phy_dev);
|
||||
+ phy_stop(net_dev->phydev);
|
||||
|
||||
napi_disable(&bgmac->napi);
|
||||
bgmac_chip_intrs_off(bgmac);
|
||||
@@ -1375,12 +1375,10 @@ static int bgmac_set_mac_address(struct
|
||||
|
||||
static int bgmac_ioctl(struct net_device *net_dev, struct ifreq *ifr, int cmd)
|
||||
{
|
||||
- struct bgmac *bgmac = netdev_priv(net_dev);
|
||||
-
|
||||
if (!netif_running(net_dev))
|
||||
return -EINVAL;
|
||||
|
||||
- return phy_mii_ioctl(bgmac->phy_dev, ifr, cmd);
|
||||
+ return phy_mii_ioctl(net_dev->phydev, ifr, cmd);
|
||||
}
|
||||
|
||||
static const struct net_device_ops bgmac_netdev_ops = {
|
||||
@@ -1523,7 +1521,7 @@ static int bgmac_get_settings(struct net
|
||||
{
|
||||
struct bgmac *bgmac = netdev_priv(net_dev);
|
||||
|
||||
- return phy_ethtool_gset(bgmac->phy_dev, cmd);
|
||||
+ return phy_ethtool_gset(net_dev->phydev, cmd);
|
||||
}
|
||||
|
||||
static int bgmac_set_settings(struct net_device *net_dev,
|
||||
@@ -1531,7 +1529,7 @@ static int bgmac_set_settings(struct net
|
||||
{
|
||||
struct bgmac *bgmac = netdev_priv(net_dev);
|
||||
|
||||
- return phy_ethtool_sset(bgmac->phy_dev, cmd);
|
||||
+ return phy_ethtool_sset(net_dev->phydev, cmd);
|
||||
}
|
||||
|
||||
static void bgmac_get_drvinfo(struct net_device *net_dev,
|
||||
@@ -1568,7 +1566,7 @@ static int bgmac_mii_write(struct mii_bu
|
||||
static void bgmac_adjust_link(struct net_device *net_dev)
|
||||
{
|
||||
struct bgmac *bgmac = netdev_priv(net_dev);
|
||||
- struct phy_device *phy_dev = bgmac->phy_dev;
|
||||
+ struct phy_device *phy_dev = net_dev->phydev;
|
||||
bool update = false;
|
||||
|
||||
if (phy_dev->link) {
|
||||
@@ -1612,8 +1610,6 @@ static int bgmac_fixed_phy_register(stru
|
||||
return err;
|
||||
}
|
||||
|
||||
- bgmac->phy_dev = phy_dev;
|
||||
-
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -1666,7 +1662,6 @@ static int bgmac_mii_register(struct bgm
|
||||
err = PTR_ERR(phy_dev);
|
||||
goto err_unregister_bus;
|
||||
}
|
||||
- bgmac->phy_dev = phy_dev;
|
||||
|
||||
return err;
|
||||
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac.h
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac.h
|
||||
@@ -441,7 +441,6 @@ struct bgmac {
|
||||
struct net_device *net_dev;
|
||||
struct napi_struct napi;
|
||||
struct mii_bus *mii_bus;
|
||||
- struct phy_device *phy_dev;
|
||||
|
||||
/* DMA */
|
||||
struct bgmac_dma_ring tx_ring[BGMAC_MAX_TX_RINGS];
|
@ -1,407 +0,0 @@
|
||||
From d00a8281bcc962027dfe409c2f3e3f0546be9200 Mon Sep 17 00:00:00 2001
|
||||
From: Jon Mason <jon.mason@broadcom.com>
|
||||
Date: Thu, 7 Jul 2016 19:08:53 -0400
|
||||
Subject: [PATCH 1/5] net: ethernet: bgmac: change bgmac_* prints to dev_*
|
||||
prints
|
||||
|
||||
The bgmac_* print wrappers call dev_* prints with the dev pointer from
|
||||
the bcma core. In anticipation of removing the bcma requirement for
|
||||
this driver, these must be changed to not reference that struct. So,
|
||||
simply change all of the bgmac_* prints to their dev_* counterparts. In
|
||||
some cases netdev_* prints are more appropriate, so change those as
|
||||
well.
|
||||
|
||||
Signed-off-by: Jon Mason <jon.mason@broadcom.com>
|
||||
Acked-by: Arnd Bergmann <arnd@arndb.de>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Tested-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/ethernet/broadcom/bgmac.c | 103 +++++++++++++++++-----------------
|
||||
drivers/net/ethernet/broadcom/bgmac.h | 14 +----
|
||||
2 files changed, 55 insertions(+), 62 deletions(-)
|
||||
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac.c
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac.c
|
||||
@@ -50,7 +50,7 @@ static bool bgmac_wait_value(struct bcma
|
||||
return true;
|
||||
udelay(10);
|
||||
}
|
||||
- pr_err("Timeout waiting for reg 0x%X\n", reg);
|
||||
+ dev_err(&core->dev, "Timeout waiting for reg 0x%X\n", reg);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -84,8 +84,8 @@ static void bgmac_dma_tx_reset(struct bg
|
||||
udelay(10);
|
||||
}
|
||||
if (i)
|
||||
- bgmac_err(bgmac, "Timeout suspending DMA TX ring 0x%X (BGMAC_DMA_TX_STAT: 0x%08X)\n",
|
||||
- ring->mmio_base, val);
|
||||
+ dev_err(bgmac->dev, "Timeout suspending DMA TX ring 0x%X (BGMAC_DMA_TX_STAT: 0x%08X)\n",
|
||||
+ ring->mmio_base, val);
|
||||
|
||||
/* Remove SUSPEND bit */
|
||||
bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_CTL, 0);
|
||||
@@ -93,13 +93,13 @@ static void bgmac_dma_tx_reset(struct bg
|
||||
ring->mmio_base + BGMAC_DMA_TX_STATUS,
|
||||
BGMAC_DMA_TX_STAT, BGMAC_DMA_TX_STAT_DISABLED,
|
||||
10000)) {
|
||||
- bgmac_warn(bgmac, "DMA TX ring 0x%X wasn't disabled on time, waiting additional 300us\n",
|
||||
- ring->mmio_base);
|
||||
+ dev_warn(bgmac->dev, "DMA TX ring 0x%X wasn't disabled on time, waiting additional 300us\n",
|
||||
+ ring->mmio_base);
|
||||
udelay(300);
|
||||
val = bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_TX_STATUS);
|
||||
if ((val & BGMAC_DMA_TX_STAT) != BGMAC_DMA_TX_STAT_DISABLED)
|
||||
- bgmac_err(bgmac, "Reset of DMA TX ring 0x%X failed\n",
|
||||
- ring->mmio_base);
|
||||
+ dev_err(bgmac->dev, "Reset of DMA TX ring 0x%X failed\n",
|
||||
+ ring->mmio_base);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,7 +161,7 @@ static netdev_tx_t bgmac_dma_tx_add(stru
|
||||
int i;
|
||||
|
||||
if (skb->len > BGMAC_DESC_CTL1_LEN) {
|
||||
- bgmac_err(bgmac, "Too long skb (%d)\n", skb->len);
|
||||
+ netdev_err(bgmac->net_dev, "Too long skb (%d)\n", skb->len);
|
||||
goto err_drop;
|
||||
}
|
||||
|
||||
@@ -174,7 +174,7 @@ static netdev_tx_t bgmac_dma_tx_add(stru
|
||||
* even when ring->end overflows
|
||||
*/
|
||||
if (ring->end - ring->start + nr_frags + 1 >= BGMAC_TX_RING_SLOTS) {
|
||||
- bgmac_err(bgmac, "TX ring is full, queue should be stopped!\n");
|
||||
+ netdev_err(bgmac->net_dev, "TX ring is full, queue should be stopped!\n");
|
||||
netif_stop_queue(net_dev);
|
||||
return NETDEV_TX_BUSY;
|
||||
}
|
||||
@@ -241,8 +241,8 @@ err_dma:
|
||||
}
|
||||
|
||||
err_dma_head:
|
||||
- bgmac_err(bgmac, "Mapping error of skb on ring 0x%X\n",
|
||||
- ring->mmio_base);
|
||||
+ netdev_err(bgmac->net_dev, "Mapping error of skb on ring 0x%X\n",
|
||||
+ ring->mmio_base);
|
||||
|
||||
err_drop:
|
||||
dev_kfree_skb(skb);
|
||||
@@ -321,8 +321,8 @@ static void bgmac_dma_rx_reset(struct bg
|
||||
ring->mmio_base + BGMAC_DMA_RX_STATUS,
|
||||
BGMAC_DMA_RX_STAT, BGMAC_DMA_RX_STAT_DISABLED,
|
||||
10000))
|
||||
- bgmac_err(bgmac, "Reset of ring 0x%X RX failed\n",
|
||||
- ring->mmio_base);
|
||||
+ dev_err(bgmac->dev, "Reset of ring 0x%X RX failed\n",
|
||||
+ ring->mmio_base);
|
||||
}
|
||||
|
||||
static void bgmac_dma_rx_enable(struct bgmac *bgmac,
|
||||
@@ -374,7 +374,7 @@ static int bgmac_dma_rx_skb_for_slot(str
|
||||
dma_addr = dma_map_single(dma_dev, buf + BGMAC_RX_BUF_OFFSET,
|
||||
BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE);
|
||||
if (dma_mapping_error(dma_dev, dma_addr)) {
|
||||
- bgmac_err(bgmac, "DMA mapping error\n");
|
||||
+ netdev_err(bgmac->net_dev, "DMA mapping error\n");
|
||||
put_page(virt_to_head_page(buf));
|
||||
return -ENOMEM;
|
||||
}
|
||||
@@ -469,16 +469,16 @@ static int bgmac_dma_rx_read(struct bgma
|
||||
|
||||
/* Check for poison and drop or pass the packet */
|
||||
if (len == 0xdead && flags == 0xbeef) {
|
||||
- bgmac_err(bgmac, "Found poisoned packet at slot %d, DMA issue!\n",
|
||||
- ring->start);
|
||||
+ netdev_err(bgmac->net_dev, "Found poisoned packet at slot %d, DMA issue!\n",
|
||||
+ ring->start);
|
||||
put_page(virt_to_head_page(buf));
|
||||
bgmac->net_dev->stats.rx_errors++;
|
||||
break;
|
||||
}
|
||||
|
||||
if (len > BGMAC_RX_ALLOC_SIZE) {
|
||||
- bgmac_err(bgmac, "Found oversized packet at slot %d, DMA issue!\n",
|
||||
- ring->start);
|
||||
+ netdev_err(bgmac->net_dev, "Found oversized packet at slot %d, DMA issue!\n",
|
||||
+ ring->start);
|
||||
put_page(virt_to_head_page(buf));
|
||||
bgmac->net_dev->stats.rx_length_errors++;
|
||||
bgmac->net_dev->stats.rx_errors++;
|
||||
@@ -490,7 +490,7 @@ static int bgmac_dma_rx_read(struct bgma
|
||||
|
||||
skb = build_skb(buf, BGMAC_RX_ALLOC_SIZE);
|
||||
if (unlikely(!skb)) {
|
||||
- bgmac_err(bgmac, "build_skb failed\n");
|
||||
+ netdev_err(bgmac->net_dev, "build_skb failed\n");
|
||||
put_page(virt_to_head_page(buf));
|
||||
bgmac->net_dev->stats.rx_errors++;
|
||||
break;
|
||||
@@ -644,7 +644,7 @@ static int bgmac_dma_alloc(struct bgmac
|
||||
BUILD_BUG_ON(BGMAC_MAX_RX_RINGS > ARRAY_SIZE(ring_base));
|
||||
|
||||
if (!(bcma_aread32(bgmac->core, BCMA_IOST) & BCMA_IOST_DMA64)) {
|
||||
- bgmac_err(bgmac, "Core does not report 64-bit DMA\n");
|
||||
+ dev_err(bgmac->dev, "Core does not report 64-bit DMA\n");
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
@@ -658,8 +658,8 @@ static int bgmac_dma_alloc(struct bgmac
|
||||
&ring->dma_base,
|
||||
GFP_KERNEL);
|
||||
if (!ring->cpu_base) {
|
||||
- bgmac_err(bgmac, "Allocation of TX ring 0x%X failed\n",
|
||||
- ring->mmio_base);
|
||||
+ dev_err(bgmac->dev, "Allocation of TX ring 0x%X failed\n",
|
||||
+ ring->mmio_base);
|
||||
goto err_dma_free;
|
||||
}
|
||||
|
||||
@@ -683,8 +683,8 @@ static int bgmac_dma_alloc(struct bgmac
|
||||
&ring->dma_base,
|
||||
GFP_KERNEL);
|
||||
if (!ring->cpu_base) {
|
||||
- bgmac_err(bgmac, "Allocation of RX ring 0x%X failed\n",
|
||||
- ring->mmio_base);
|
||||
+ dev_err(bgmac->dev, "Allocation of RX ring 0x%X failed\n",
|
||||
+ ring->mmio_base);
|
||||
err = -ENOMEM;
|
||||
goto err_dma_free;
|
||||
}
|
||||
@@ -803,8 +803,8 @@ static u16 bgmac_phy_read(struct bgmac *
|
||||
bcma_write32(core, phy_access_addr, tmp);
|
||||
|
||||
if (!bgmac_wait_value(core, phy_access_addr, BGMAC_PA_START, 0, 1000)) {
|
||||
- bgmac_err(bgmac, "Reading PHY %d register 0x%X failed\n",
|
||||
- phyaddr, reg);
|
||||
+ dev_err(bgmac->dev, "Reading PHY %d register 0x%X failed\n",
|
||||
+ phyaddr, reg);
|
||||
return 0xffff;
|
||||
}
|
||||
|
||||
@@ -836,7 +836,7 @@ static int bgmac_phy_write(struct bgmac
|
||||
|
||||
bgmac_write(bgmac, BGMAC_INT_STATUS, BGMAC_IS_MDIO);
|
||||
if (bgmac_read(bgmac, BGMAC_INT_STATUS) & BGMAC_IS_MDIO)
|
||||
- bgmac_warn(bgmac, "Error setting MDIO int\n");
|
||||
+ dev_warn(bgmac->dev, "Error setting MDIO int\n");
|
||||
|
||||
tmp = BGMAC_PA_START;
|
||||
tmp |= BGMAC_PA_WRITE;
|
||||
@@ -846,8 +846,8 @@ static int bgmac_phy_write(struct bgmac
|
||||
bcma_write32(core, phy_access_addr, tmp);
|
||||
|
||||
if (!bgmac_wait_value(core, phy_access_addr, BGMAC_PA_START, 0, 1000)) {
|
||||
- bgmac_err(bgmac, "Writing to PHY %d register 0x%X failed\n",
|
||||
- phyaddr, reg);
|
||||
+ dev_err(bgmac->dev, "Writing to PHY %d register 0x%X failed\n",
|
||||
+ phyaddr, reg);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
@@ -900,7 +900,7 @@ static void bgmac_phy_reset(struct bgmac
|
||||
bgmac_phy_write(bgmac, bgmac->phyaddr, MII_BMCR, BMCR_RESET);
|
||||
udelay(100);
|
||||
if (bgmac_phy_read(bgmac, bgmac->phyaddr, MII_BMCR) & BMCR_RESET)
|
||||
- bgmac_err(bgmac, "PHY reset failed\n");
|
||||
+ dev_err(bgmac->dev, "PHY reset failed\n");
|
||||
bgmac_phy_init(bgmac);
|
||||
}
|
||||
|
||||
@@ -1001,7 +1001,8 @@ static void bgmac_mac_speed(struct bgmac
|
||||
set |= BGMAC_CMDCFG_ES_2500;
|
||||
break;
|
||||
default:
|
||||
- bgmac_err(bgmac, "Unsupported speed: %d\n", bgmac->mac_speed);
|
||||
+ dev_err(bgmac->dev, "Unsupported speed: %d\n",
|
||||
+ bgmac->mac_speed);
|
||||
}
|
||||
|
||||
if (bgmac->mac_duplex == DUPLEX_HALF)
|
||||
@@ -1100,8 +1101,8 @@ static void bgmac_chip_reset(struct bgma
|
||||
|
||||
if (bcm47xx_nvram_getenv("et_swtype", buf, sizeof(buf)) > 0) {
|
||||
if (kstrtou8(buf, 0, &et_swtype))
|
||||
- bgmac_err(bgmac, "Failed to parse et_swtype (%s)\n",
|
||||
- buf);
|
||||
+ dev_err(bgmac->dev, "Failed to parse et_swtype (%s)\n",
|
||||
+ buf);
|
||||
et_swtype &= 0x0f;
|
||||
et_swtype <<= 4;
|
||||
sw_type = et_swtype;
|
||||
@@ -1264,7 +1265,7 @@ static irqreturn_t bgmac_interrupt(int i
|
||||
|
||||
int_status &= ~(BGMAC_IS_TX0 | BGMAC_IS_RX);
|
||||
if (int_status)
|
||||
- bgmac_err(bgmac, "Unknown IRQs: 0x%08X\n", int_status);
|
||||
+ dev_err(bgmac->dev, "Unknown IRQs: 0x%08X\n", int_status);
|
||||
|
||||
/* Disable new interrupts until handling existing ones */
|
||||
bgmac_chip_intrs_off(bgmac);
|
||||
@@ -1318,7 +1319,7 @@ static int bgmac_open(struct net_device
|
||||
err = request_irq(bgmac->core->irq, bgmac_interrupt, IRQF_SHARED,
|
||||
KBUILD_MODNAME, net_dev);
|
||||
if (err < 0) {
|
||||
- bgmac_err(bgmac, "IRQ request error: %d!\n", err);
|
||||
+ dev_err(bgmac->dev, "IRQ request error: %d!\n", err);
|
||||
bgmac_dma_cleanup(bgmac);
|
||||
return err;
|
||||
}
|
||||
@@ -1599,14 +1600,14 @@ static int bgmac_fixed_phy_register(stru
|
||||
|
||||
phy_dev = fixed_phy_register(PHY_POLL, &fphy_status, -1, NULL);
|
||||
if (!phy_dev || IS_ERR(phy_dev)) {
|
||||
- bgmac_err(bgmac, "Failed to register fixed PHY device\n");
|
||||
+ dev_err(bgmac->dev, "Failed to register fixed PHY device\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
err = phy_connect_direct(bgmac->net_dev, phy_dev, bgmac_adjust_link,
|
||||
PHY_INTERFACE_MODE_MII);
|
||||
if (err) {
|
||||
- bgmac_err(bgmac, "Connecting PHY failed\n");
|
||||
+ dev_err(bgmac->dev, "Connecting PHY failed\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -1646,7 +1647,7 @@ static int bgmac_mii_register(struct bgm
|
||||
|
||||
err = mdiobus_register(mii_bus);
|
||||
if (err) {
|
||||
- bgmac_err(bgmac, "Registration of mii bus failed\n");
|
||||
+ dev_err(bgmac->dev, "Registration of mii bus failed\n");
|
||||
goto err_free_irq;
|
||||
}
|
||||
|
||||
@@ -1658,7 +1659,7 @@ static int bgmac_mii_register(struct bgm
|
||||
phy_dev = phy_connect(bgmac->net_dev, bus_id, &bgmac_adjust_link,
|
||||
PHY_INTERFACE_MODE_MII);
|
||||
if (IS_ERR(phy_dev)) {
|
||||
- bgmac_err(bgmac, "PHY connecton failed\n");
|
||||
+ dev_err(bgmac->dev, "PHY connecton failed\n");
|
||||
err = PTR_ERR(phy_dev);
|
||||
goto err_unregister_bus;
|
||||
}
|
||||
@@ -1707,7 +1708,8 @@ static int bgmac_probe(struct bcma_devic
|
||||
mac = sprom->et2mac;
|
||||
break;
|
||||
default:
|
||||
- pr_err("Unsupported core_unit %d\n", core->core_unit);
|
||||
+ dev_err(&core->dev, "Unsupported core_unit %d\n",
|
||||
+ core->core_unit);
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
@@ -1730,6 +1732,7 @@ static int bgmac_probe(struct bcma_devic
|
||||
net_dev->irq = core->irq;
|
||||
net_dev->ethtool_ops = &bgmac_ethtool_ops;
|
||||
bgmac = netdev_priv(net_dev);
|
||||
+ bgmac->dev = &core->dev;
|
||||
bgmac->net_dev = net_dev;
|
||||
bgmac->core = core;
|
||||
bcma_set_drvdata(core, bgmac);
|
||||
@@ -1741,7 +1744,7 @@ static int bgmac_probe(struct bcma_devic
|
||||
/* On BCM4706 we need common core to access PHY */
|
||||
if (core->id.id == BCMA_CORE_4706_MAC_GBIT &&
|
||||
!core->bus->drv_gmac_cmn.core) {
|
||||
- bgmac_err(bgmac, "GMAC CMN core not found (required for BCM4706)\n");
|
||||
+ dev_err(bgmac->dev, "GMAC CMN core not found (required for BCM4706)\n");
|
||||
err = -ENODEV;
|
||||
goto err_netdev_free;
|
||||
}
|
||||
@@ -1760,15 +1763,15 @@ static int bgmac_probe(struct bcma_devic
|
||||
}
|
||||
bgmac->phyaddr &= BGMAC_PHY_MASK;
|
||||
if (bgmac->phyaddr == BGMAC_PHY_MASK) {
|
||||
- bgmac_err(bgmac, "No PHY found\n");
|
||||
+ dev_err(bgmac->dev, "No PHY found\n");
|
||||
err = -ENODEV;
|
||||
goto err_netdev_free;
|
||||
}
|
||||
- bgmac_info(bgmac, "Found PHY addr: %d%s\n", bgmac->phyaddr,
|
||||
- bgmac->phyaddr == BGMAC_PHY_NOREGS ? " (NOREGS)" : "");
|
||||
+ dev_info(bgmac->dev, "Found PHY addr: %d%s\n", bgmac->phyaddr,
|
||||
+ bgmac->phyaddr == BGMAC_PHY_NOREGS ? " (NOREGS)" : "");
|
||||
|
||||
if (core->bus->hosttype == BCMA_HOSTTYPE_PCI) {
|
||||
- bgmac_err(bgmac, "PCI setup not implemented\n");
|
||||
+ dev_err(bgmac->dev, "PCI setup not implemented\n");
|
||||
err = -ENOTSUPP;
|
||||
goto err_netdev_free;
|
||||
}
|
||||
@@ -1797,7 +1800,7 @@ static int bgmac_probe(struct bcma_devic
|
||||
|
||||
err = bgmac_dma_alloc(bgmac);
|
||||
if (err) {
|
||||
- bgmac_err(bgmac, "Unable to alloc memory for DMA\n");
|
||||
+ dev_err(bgmac->dev, "Unable to alloc memory for DMA\n");
|
||||
goto err_netdev_free;
|
||||
}
|
||||
|
||||
@@ -1811,16 +1814,16 @@ static int bgmac_probe(struct bcma_devic
|
||||
bgmac->has_robosw = !!(core->bus->sprom.boardflags_lo &
|
||||
BGMAC_BFL_ENETROBO);
|
||||
if (bgmac->has_robosw)
|
||||
- bgmac_warn(bgmac, "Support for Roboswitch not implemented\n");
|
||||
+ dev_warn(bgmac->dev, "Support for Roboswitch not implemented\n");
|
||||
|
||||
if (core->bus->sprom.boardflags_lo & BGMAC_BFL_ENETADM)
|
||||
- bgmac_warn(bgmac, "Support for ADMtek ethernet switch not implemented\n");
|
||||
+ dev_warn(bgmac->dev, "Support for ADMtek ethernet switch not implemented\n");
|
||||
|
||||
netif_napi_add(net_dev, &bgmac->napi, bgmac_poll, BGMAC_WEIGHT);
|
||||
|
||||
err = bgmac_mii_register(bgmac);
|
||||
if (err) {
|
||||
- bgmac_err(bgmac, "Cannot register MDIO\n");
|
||||
+ dev_err(bgmac->dev, "Cannot connect to phy\n");
|
||||
goto err_dma_free;
|
||||
}
|
||||
|
||||
@@ -1830,7 +1833,7 @@ static int bgmac_probe(struct bcma_devic
|
||||
|
||||
err = register_netdev(bgmac->net_dev);
|
||||
if (err) {
|
||||
- bgmac_err(bgmac, "Cannot register net device\n");
|
||||
+ dev_err(bgmac->dev, "Cannot register net device\n");
|
||||
goto err_mii_unregister;
|
||||
}
|
||||
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac.h
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac.h
|
||||
@@ -1,17 +1,6 @@
|
||||
#ifndef _BGMAC_H
|
||||
#define _BGMAC_H
|
||||
|
||||
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
-
|
||||
-#define bgmac_err(bgmac, fmt, ...) \
|
||||
- dev_err(&(bgmac)->core->dev, fmt, ##__VA_ARGS__)
|
||||
-#define bgmac_warn(bgmac, fmt, ...) \
|
||||
- dev_warn(&(bgmac)->core->dev, fmt, ##__VA_ARGS__)
|
||||
-#define bgmac_info(bgmac, fmt, ...) \
|
||||
- dev_info(&(bgmac)->core->dev, fmt, ##__VA_ARGS__)
|
||||
-#define bgmac_dbg(bgmac, fmt, ...) \
|
||||
- dev_dbg(&(bgmac)->core->dev, fmt, ##__VA_ARGS__)
|
||||
-
|
||||
#include <linux/bcma/bcma.h>
|
||||
#include <linux/brcmphy.h>
|
||||
#include <linux/netdevice.h>
|
||||
@@ -438,6 +427,8 @@ struct bgmac_rx_header {
|
||||
struct bgmac {
|
||||
struct bcma_device *core;
|
||||
struct bcma_device *cmn; /* Reference to CMN core for BCM4706 */
|
||||
+
|
||||
+ struct device *dev;
|
||||
struct net_device *net_dev;
|
||||
struct napi_struct napi;
|
||||
struct mii_bus *mii_bus;
|
||||
@@ -489,5 +480,4 @@ static inline void bgmac_set(struct bgma
|
||||
{
|
||||
bgmac_maskset(bgmac, offset, ~0, set);
|
||||
}
|
||||
-
|
||||
#endif /* _BGMAC_H */
|
@ -1,112 +0,0 @@
|
||||
From a0b68486f6f680c7c0352a47c60042d7d95ffd87 Mon Sep 17 00:00:00 2001
|
||||
From: Jon Mason <jon.mason@broadcom.com>
|
||||
Date: Thu, 7 Jul 2016 19:08:54 -0400
|
||||
Subject: [PATCH 2/5] net: ethernet: bgmac: add dma_dev pointer
|
||||
|
||||
The dma buffer allocation, etc references a dma_dev device pointer from
|
||||
the bcma core. In anticipation of removing the bcma requirement for
|
||||
this driver, these must be changed to not reference that struct. Add a
|
||||
dma_dev device pointer to the bgmac stuct and reference that instead.
|
||||
|
||||
Signed-off-by: Jon Mason <jon.mason@broadcom.com>
|
||||
Acked-by: Arnd Bergmann <arnd@arndb.de>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Tested-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/ethernet/broadcom/bgmac.c | 17 +++++++++--------
|
||||
drivers/net/ethernet/broadcom/bgmac.h | 1 +
|
||||
2 files changed, 10 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac.c
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac.c
|
||||
@@ -152,7 +152,7 @@ static netdev_tx_t bgmac_dma_tx_add(stru
|
||||
struct bgmac_dma_ring *ring,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
- struct device *dma_dev = bgmac->core->dma_dev;
|
||||
+ struct device *dma_dev = bgmac->dma_dev;
|
||||
struct net_device *net_dev = bgmac->net_dev;
|
||||
int index = ring->end % BGMAC_TX_RING_SLOTS;
|
||||
struct bgmac_slot_info *slot = &ring->slots[index];
|
||||
@@ -254,7 +254,7 @@ err_drop:
|
||||
/* Free transmitted packets */
|
||||
static void bgmac_dma_tx_free(struct bgmac *bgmac, struct bgmac_dma_ring *ring)
|
||||
{
|
||||
- struct device *dma_dev = bgmac->core->dma_dev;
|
||||
+ struct device *dma_dev = bgmac->dma_dev;
|
||||
int empty_slot;
|
||||
bool freed = false;
|
||||
unsigned bytes_compl = 0, pkts_compl = 0;
|
||||
@@ -355,7 +355,7 @@ static void bgmac_dma_rx_enable(struct b
|
||||
static int bgmac_dma_rx_skb_for_slot(struct bgmac *bgmac,
|
||||
struct bgmac_slot_info *slot)
|
||||
{
|
||||
- struct device *dma_dev = bgmac->core->dma_dev;
|
||||
+ struct device *dma_dev = bgmac->dma_dev;
|
||||
dma_addr_t dma_addr;
|
||||
struct bgmac_rx_header *rx;
|
||||
void *buf;
|
||||
@@ -444,7 +444,7 @@ static int bgmac_dma_rx_read(struct bgma
|
||||
end_slot /= sizeof(struct bgmac_dma_desc);
|
||||
|
||||
while (ring->start != end_slot) {
|
||||
- struct device *dma_dev = bgmac->core->dma_dev;
|
||||
+ struct device *dma_dev = bgmac->dma_dev;
|
||||
struct bgmac_slot_info *slot = &ring->slots[ring->start];
|
||||
struct bgmac_rx_header *rx = slot->buf + BGMAC_RX_BUF_OFFSET;
|
||||
struct sk_buff *skb;
|
||||
@@ -547,7 +547,7 @@ static bool bgmac_dma_unaligned(struct b
|
||||
static void bgmac_dma_tx_ring_free(struct bgmac *bgmac,
|
||||
struct bgmac_dma_ring *ring)
|
||||
{
|
||||
- struct device *dma_dev = bgmac->core->dma_dev;
|
||||
+ struct device *dma_dev = bgmac->dma_dev;
|
||||
struct bgmac_dma_desc *dma_desc = ring->cpu_base;
|
||||
struct bgmac_slot_info *slot;
|
||||
int i;
|
||||
@@ -573,7 +573,7 @@ static void bgmac_dma_tx_ring_free(struc
|
||||
static void bgmac_dma_rx_ring_free(struct bgmac *bgmac,
|
||||
struct bgmac_dma_ring *ring)
|
||||
{
|
||||
- struct device *dma_dev = bgmac->core->dma_dev;
|
||||
+ struct device *dma_dev = bgmac->dma_dev;
|
||||
struct bgmac_slot_info *slot;
|
||||
int i;
|
||||
|
||||
@@ -594,7 +594,7 @@ static void bgmac_dma_ring_desc_free(str
|
||||
struct bgmac_dma_ring *ring,
|
||||
int num_slots)
|
||||
{
|
||||
- struct device *dma_dev = bgmac->core->dma_dev;
|
||||
+ struct device *dma_dev = bgmac->dma_dev;
|
||||
int size;
|
||||
|
||||
if (!ring->cpu_base)
|
||||
@@ -632,7 +632,7 @@ static void bgmac_dma_free(struct bgmac
|
||||
|
||||
static int bgmac_dma_alloc(struct bgmac *bgmac)
|
||||
{
|
||||
- struct device *dma_dev = bgmac->core->dma_dev;
|
||||
+ struct device *dma_dev = bgmac->dma_dev;
|
||||
struct bgmac_dma_ring *ring;
|
||||
static const u16 ring_base[] = { BGMAC_DMA_BASE0, BGMAC_DMA_BASE1,
|
||||
BGMAC_DMA_BASE2, BGMAC_DMA_BASE3, };
|
||||
@@ -1733,6 +1733,7 @@ static int bgmac_probe(struct bcma_devic
|
||||
net_dev->ethtool_ops = &bgmac_ethtool_ops;
|
||||
bgmac = netdev_priv(net_dev);
|
||||
bgmac->dev = &core->dev;
|
||||
+ bgmac->dma_dev = core->dma_dev;
|
||||
bgmac->net_dev = net_dev;
|
||||
bgmac->core = core;
|
||||
bcma_set_drvdata(core, bgmac);
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac.h
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac.h
|
||||
@@ -429,6 +429,7 @@ struct bgmac {
|
||||
struct bcma_device *cmn; /* Reference to CMN core for BCM4706 */
|
||||
|
||||
struct device *dev;
|
||||
+ struct device *dma_dev;
|
||||
struct net_device *net_dev;
|
||||
struct napi_struct napi;
|
||||
struct mii_bus *mii_bus;
|
@ -1,676 +0,0 @@
|
||||
From 55954f3bfdacc5908515b0c306cea23e77fab740 Mon Sep 17 00:00:00 2001
|
||||
From: Jon Mason <jon.mason@broadcom.com>
|
||||
Date: Thu, 7 Jul 2016 19:08:55 -0400
|
||||
Subject: [PATCH 3/5] net: ethernet: bgmac: move BCMA MDIO Phy code into a
|
||||
separate file
|
||||
|
||||
Move the BCMA MDIO phy into a separate file, as it is very tightly
|
||||
coupled with the BCMA bus. This will help with the upcoming BCMA
|
||||
removal from the bgmac driver. Optimally, this should be moved into
|
||||
phy drivers, but it is too tightly coupled with the bgmac driver to
|
||||
effectively move it without more changes to the driver.
|
||||
|
||||
Note: the phy_reset was intentionally removed, as the mdio phy subsystem
|
||||
automatically resets the phy if a reset function pointer is present. In
|
||||
addition to the moving of the driver, this reset function is added.
|
||||
|
||||
Signed-off-by: Jon Mason <jon.mason@broadcom.com>
|
||||
Acked-by: Arnd Bergmann <arnd@arndb.de>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Tested-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/ethernet/broadcom/Makefile | 2 +-
|
||||
drivers/net/ethernet/broadcom/bgmac-bcma-mdio.c | 264 ++++++++++++++++++++++++
|
||||
drivers/net/ethernet/broadcom/bgmac.c | 246 +++-------------------
|
||||
drivers/net/ethernet/broadcom/bgmac.h | 3 +
|
||||
4 files changed, 298 insertions(+), 217 deletions(-)
|
||||
create mode 100644 drivers/net/ethernet/broadcom/bgmac-bcma-mdio.c
|
||||
|
||||
--- a/drivers/net/ethernet/broadcom/Makefile
|
||||
+++ b/drivers/net/ethernet/broadcom/Makefile
|
||||
@@ -10,6 +10,6 @@ obj-$(CONFIG_CNIC) += cnic.o
|
||||
obj-$(CONFIG_BNX2X) += bnx2x/
|
||||
obj-$(CONFIG_SB1250_MAC) += sb1250-mac.o
|
||||
obj-$(CONFIG_TIGON3) += tg3.o
|
||||
-obj-$(CONFIG_BGMAC) += bgmac.o
|
||||
+obj-$(CONFIG_BGMAC) += bgmac.o bgmac-bcma-mdio.o
|
||||
obj-$(CONFIG_SYSTEMPORT) += bcmsysport.o
|
||||
obj-$(CONFIG_BNXT) += bnxt/
|
||||
--- /dev/null
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac-bcma-mdio.c
|
||||
@@ -0,0 +1,275 @@
|
||||
+/*
|
||||
+ * Driver for (BCM4706)? GBit MAC core on BCMA bus.
|
||||
+ *
|
||||
+ * Copyright (C) 2012 Rafał Miłecki <zajec5@gmail.com>
|
||||
+ *
|
||||
+ * Licensed under the GNU/GPL. See COPYING for details.
|
||||
+ */
|
||||
+
|
||||
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
+
|
||||
+#include <linux/bcma/bcma.h>
|
||||
+#include <linux/brcmphy.h>
|
||||
+#include "bgmac.h"
|
||||
+
|
||||
+struct bcma_mdio {
|
||||
+ struct bcma_device *core;
|
||||
+ u8 phyaddr;
|
||||
+};
|
||||
+
|
||||
+static bool bcma_mdio_wait_value(struct bcma_device *core, u16 reg, u32 mask,
|
||||
+ u32 value, int timeout)
|
||||
+{
|
||||
+ u32 val;
|
||||
+ int i;
|
||||
+
|
||||
+ for (i = 0; i < timeout / 10; i++) {
|
||||
+ val = bcma_read32(core, reg);
|
||||
+ if ((val & mask) == value)
|
||||
+ return true;
|
||||
+ udelay(10);
|
||||
+ }
|
||||
+ dev_err(&core->dev, "Timeout waiting for reg 0x%X\n", reg);
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
+/**************************************************
|
||||
+ * PHY ops
|
||||
+ **************************************************/
|
||||
+
|
||||
+static u16 bcma_mdio_phy_read(struct bcma_mdio *bcma_mdio, u8 phyaddr, u8 reg)
|
||||
+{
|
||||
+ struct bcma_device *core;
|
||||
+ u16 phy_access_addr;
|
||||
+ u16 phy_ctl_addr;
|
||||
+ u32 tmp;
|
||||
+
|
||||
+ BUILD_BUG_ON(BGMAC_PA_DATA_MASK != BCMA_GMAC_CMN_PA_DATA_MASK);
|
||||
+ BUILD_BUG_ON(BGMAC_PA_ADDR_MASK != BCMA_GMAC_CMN_PA_ADDR_MASK);
|
||||
+ BUILD_BUG_ON(BGMAC_PA_ADDR_SHIFT != BCMA_GMAC_CMN_PA_ADDR_SHIFT);
|
||||
+ BUILD_BUG_ON(BGMAC_PA_REG_MASK != BCMA_GMAC_CMN_PA_REG_MASK);
|
||||
+ BUILD_BUG_ON(BGMAC_PA_REG_SHIFT != BCMA_GMAC_CMN_PA_REG_SHIFT);
|
||||
+ BUILD_BUG_ON(BGMAC_PA_WRITE != BCMA_GMAC_CMN_PA_WRITE);
|
||||
+ BUILD_BUG_ON(BGMAC_PA_START != BCMA_GMAC_CMN_PA_START);
|
||||
+ BUILD_BUG_ON(BGMAC_PC_EPA_MASK != BCMA_GMAC_CMN_PC_EPA_MASK);
|
||||
+ BUILD_BUG_ON(BGMAC_PC_MCT_MASK != BCMA_GMAC_CMN_PC_MCT_MASK);
|
||||
+ BUILD_BUG_ON(BGMAC_PC_MCT_SHIFT != BCMA_GMAC_CMN_PC_MCT_SHIFT);
|
||||
+ BUILD_BUG_ON(BGMAC_PC_MTE != BCMA_GMAC_CMN_PC_MTE);
|
||||
+
|
||||
+ if (bcma_mdio->core->id.id == BCMA_CORE_4706_MAC_GBIT) {
|
||||
+ core = bcma_mdio->core->bus->drv_gmac_cmn.core;
|
||||
+ phy_access_addr = BCMA_GMAC_CMN_PHY_ACCESS;
|
||||
+ phy_ctl_addr = BCMA_GMAC_CMN_PHY_CTL;
|
||||
+ } else {
|
||||
+ core = bcma_mdio->core;
|
||||
+ phy_access_addr = BGMAC_PHY_ACCESS;
|
||||
+ phy_ctl_addr = BGMAC_PHY_CNTL;
|
||||
+ }
|
||||
+
|
||||
+ tmp = bcma_read32(core, phy_ctl_addr);
|
||||
+ tmp &= ~BGMAC_PC_EPA_MASK;
|
||||
+ tmp |= phyaddr;
|
||||
+ bcma_write32(core, phy_ctl_addr, tmp);
|
||||
+
|
||||
+ tmp = BGMAC_PA_START;
|
||||
+ tmp |= phyaddr << BGMAC_PA_ADDR_SHIFT;
|
||||
+ tmp |= reg << BGMAC_PA_REG_SHIFT;
|
||||
+ bcma_write32(core, phy_access_addr, tmp);
|
||||
+
|
||||
+ if (!bcma_mdio_wait_value(core, phy_access_addr, BGMAC_PA_START, 0,
|
||||
+ 1000)) {
|
||||
+ dev_err(&core->dev, "Reading PHY %d register 0x%X failed\n",
|
||||
+ phyaddr, reg);
|
||||
+ return 0xffff;
|
||||
+ }
|
||||
+
|
||||
+ return bcma_read32(core, phy_access_addr) & BGMAC_PA_DATA_MASK;
|
||||
+}
|
||||
+
|
||||
+/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphywr */
|
||||
+static int bcma_mdio_phy_write(struct bcma_mdio *bcma_mdio, u8 phyaddr, u8 reg,
|
||||
+ u16 value)
|
||||
+{
|
||||
+ struct bcma_device *core;
|
||||
+ u16 phy_access_addr;
|
||||
+ u16 phy_ctl_addr;
|
||||
+ u32 tmp;
|
||||
+
|
||||
+ if (bcma_mdio->core->id.id == BCMA_CORE_4706_MAC_GBIT) {
|
||||
+ core = bcma_mdio->core->bus->drv_gmac_cmn.core;
|
||||
+ phy_access_addr = BCMA_GMAC_CMN_PHY_ACCESS;
|
||||
+ phy_ctl_addr = BCMA_GMAC_CMN_PHY_CTL;
|
||||
+ } else {
|
||||
+ core = bcma_mdio->core;
|
||||
+ phy_access_addr = BGMAC_PHY_ACCESS;
|
||||
+ phy_ctl_addr = BGMAC_PHY_CNTL;
|
||||
+ }
|
||||
+
|
||||
+ tmp = bcma_read32(core, phy_ctl_addr);
|
||||
+ tmp &= ~BGMAC_PC_EPA_MASK;
|
||||
+ tmp |= phyaddr;
|
||||
+ bcma_write32(core, phy_ctl_addr, tmp);
|
||||
+
|
||||
+ bcma_write32(bcma_mdio->core, BGMAC_INT_STATUS, BGMAC_IS_MDIO);
|
||||
+ if (bcma_read32(bcma_mdio->core, BGMAC_INT_STATUS) & BGMAC_IS_MDIO)
|
||||
+ dev_warn(&core->dev, "Error setting MDIO int\n");
|
||||
+
|
||||
+ tmp = BGMAC_PA_START;
|
||||
+ tmp |= BGMAC_PA_WRITE;
|
||||
+ tmp |= phyaddr << BGMAC_PA_ADDR_SHIFT;
|
||||
+ tmp |= reg << BGMAC_PA_REG_SHIFT;
|
||||
+ tmp |= value;
|
||||
+ bcma_write32(core, phy_access_addr, tmp);
|
||||
+
|
||||
+ if (!bcma_mdio_wait_value(core, phy_access_addr, BGMAC_PA_START, 0,
|
||||
+ 1000)) {
|
||||
+ dev_err(&core->dev, "Writing to PHY %d register 0x%X failed\n",
|
||||
+ phyaddr, reg);
|
||||
+ return -ETIMEDOUT;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphyinit */
|
||||
+static void bcma_mdio_phy_init(struct bcma_mdio *bcma_mdio)
|
||||
+{
|
||||
+ struct bcma_chipinfo *ci = &bcma_mdio->core->bus->chipinfo;
|
||||
+ u8 i;
|
||||
+
|
||||
+ if (ci->id == BCMA_CHIP_ID_BCM5356) {
|
||||
+ for (i = 0; i < 5; i++) {
|
||||
+ bcma_mdio_phy_write(bcma_mdio, i, 0x1f, 0x008b);
|
||||
+ bcma_mdio_phy_write(bcma_mdio, i, 0x15, 0x0100);
|
||||
+ bcma_mdio_phy_write(bcma_mdio, i, 0x1f, 0x000f);
|
||||
+ bcma_mdio_phy_write(bcma_mdio, i, 0x12, 0x2aaa);
|
||||
+ bcma_mdio_phy_write(bcma_mdio, i, 0x1f, 0x000b);
|
||||
+ }
|
||||
+ }
|
||||
+ if ((ci->id == BCMA_CHIP_ID_BCM5357 && ci->pkg != 10) ||
|
||||
+ (ci->id == BCMA_CHIP_ID_BCM4749 && ci->pkg != 10) ||
|
||||
+ (ci->id == BCMA_CHIP_ID_BCM53572 && ci->pkg != 9)) {
|
||||
+ struct bcma_drv_cc *cc = &bcma_mdio->core->bus->drv_cc;
|
||||
+
|
||||
+ bcma_chipco_chipctl_maskset(cc, 2, ~0xc0000000, 0);
|
||||
+ bcma_chipco_chipctl_maskset(cc, 4, ~0x80000000, 0);
|
||||
+ for (i = 0; i < 5; i++) {
|
||||
+ bcma_mdio_phy_write(bcma_mdio, i, 0x1f, 0x000f);
|
||||
+ bcma_mdio_phy_write(bcma_mdio, i, 0x16, 0x5284);
|
||||
+ bcma_mdio_phy_write(bcma_mdio, i, 0x1f, 0x000b);
|
||||
+ bcma_mdio_phy_write(bcma_mdio, i, 0x17, 0x0010);
|
||||
+ bcma_mdio_phy_write(bcma_mdio, i, 0x1f, 0x000f);
|
||||
+ bcma_mdio_phy_write(bcma_mdio, i, 0x16, 0x5296);
|
||||
+ bcma_mdio_phy_write(bcma_mdio, i, 0x17, 0x1073);
|
||||
+ bcma_mdio_phy_write(bcma_mdio, i, 0x17, 0x9073);
|
||||
+ bcma_mdio_phy_write(bcma_mdio, i, 0x16, 0x52b6);
|
||||
+ bcma_mdio_phy_write(bcma_mdio, i, 0x17, 0x9273);
|
||||
+ bcma_mdio_phy_write(bcma_mdio, i, 0x1f, 0x000b);
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphyreset */
|
||||
+static int bcma_mdio_phy_reset(struct mii_bus *bus)
|
||||
+{
|
||||
+ struct bcma_mdio *bcma_mdio = bus->priv;
|
||||
+ u8 phyaddr = bcma_mdio->phyaddr;
|
||||
+
|
||||
+ if (bcma_mdio->phyaddr == BGMAC_PHY_NOREGS)
|
||||
+ return 0;
|
||||
+
|
||||
+ bcma_mdio_phy_write(bcma_mdio, phyaddr, MII_BMCR, BMCR_RESET);
|
||||
+ udelay(100);
|
||||
+ if (bcma_mdio_phy_read(bcma_mdio, phyaddr, MII_BMCR) & BMCR_RESET)
|
||||
+ dev_err(&bcma_mdio->core->dev, "PHY reset failed\n");
|
||||
+ bcma_mdio_phy_init(bcma_mdio);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/**************************************************
|
||||
+ * MII
|
||||
+ **************************************************/
|
||||
+
|
||||
+static int bcma_mdio_mii_read(struct mii_bus *bus, int mii_id, int regnum)
|
||||
+{
|
||||
+ return bcma_mdio_phy_read(bus->priv, mii_id, regnum);
|
||||
+}
|
||||
+
|
||||
+static int bcma_mdio_mii_write(struct mii_bus *bus, int mii_id, int regnum,
|
||||
+ u16 value)
|
||||
+{
|
||||
+ return bcma_mdio_phy_write(bus->priv, mii_id, regnum, value);
|
||||
+}
|
||||
+
|
||||
+struct mii_bus *bcma_mdio_mii_register(struct bcma_device *core, u8 phyaddr)
|
||||
+{
|
||||
+ struct bcma_mdio *bcma_mdio;
|
||||
+ struct mii_bus *mii_bus;
|
||||
+ int i, err;
|
||||
+
|
||||
+ bcma_mdio = kzalloc(sizeof(*bcma_mdio), GFP_KERNEL);
|
||||
+ if (!bcma_mdio)
|
||||
+ return ERR_PTR(-ENOMEM);
|
||||
+
|
||||
+ mii_bus = mdiobus_alloc();
|
||||
+ if (!mii_bus) {
|
||||
+ err = -ENOMEM;
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
+ mii_bus->name = "bcma_mdio mii bus";
|
||||
+ sprintf(mii_bus->id, "%s-%d-%d", "bcma_mdio", core->bus->num,
|
||||
+ core->core_unit);
|
||||
+ mii_bus->priv = bcma_mdio;
|
||||
+ mii_bus->read = bcma_mdio_mii_read;
|
||||
+ mii_bus->write = bcma_mdio_mii_write;
|
||||
+ mii_bus->reset = bcma_mdio_phy_reset;
|
||||
+ mii_bus->parent = &core->dev;
|
||||
+ mii_bus->phy_mask = ~(1 << phyaddr);
|
||||
+
|
||||
+ mii_bus->irq = kmalloc_array(PHY_MAX_ADDR, sizeof(int), GFP_KERNEL);
|
||||
+ if (!mii_bus->irq) {
|
||||
+ err = -ENOMEM;
|
||||
+ goto err_free_bus;
|
||||
+ }
|
||||
+ for (i = 0; i < PHY_MAX_ADDR; i++)
|
||||
+ mii_bus->irq[i] = PHY_POLL;
|
||||
+
|
||||
+ bcma_mdio->core = core;
|
||||
+ bcma_mdio->phyaddr = phyaddr;
|
||||
+
|
||||
+ err = mdiobus_register(mii_bus);
|
||||
+ if (err) {
|
||||
+ dev_err(&core->dev, "Registration of mii bus failed\n");
|
||||
+ goto err_free_irq;
|
||||
+ }
|
||||
+
|
||||
+ return mii_bus;
|
||||
+
|
||||
+err_free_irq:
|
||||
+ kfree(mii_bus->irq);
|
||||
+err_free_bus:
|
||||
+ mdiobus_free(mii_bus);
|
||||
+err:
|
||||
+ kfree(bcma_mdio);
|
||||
+ return ERR_PTR(err);
|
||||
+}
|
||||
+
|
||||
+void bcma_mdio_mii_unregister(struct mii_bus *mii_bus)
|
||||
+{
|
||||
+ struct bcma_mdio *bcma_mdio;
|
||||
+
|
||||
+ if (!mii_bus)
|
||||
+ return;
|
||||
+
|
||||
+ bcma_mdio = mii_bus->priv;
|
||||
+
|
||||
+ mdiobus_unregister(mii_bus);
|
||||
+ kfree(mii_bus->irq);
|
||||
+ mdiobus_free(mii_bus);
|
||||
+ kfree(bcma_mdio);
|
||||
+}
|
||||
+
|
||||
+MODULE_AUTHOR("Rafał Miłecki");
|
||||
+MODULE_LICENSE("GPL");
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac.c
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac.c
|
||||
@@ -759,150 +759,6 @@ error:
|
||||
return err;
|
||||
}
|
||||
|
||||
-/**************************************************
|
||||
- * PHY ops
|
||||
- **************************************************/
|
||||
-
|
||||
-static u16 bgmac_phy_read(struct bgmac *bgmac, u8 phyaddr, u8 reg)
|
||||
-{
|
||||
- struct bcma_device *core;
|
||||
- u16 phy_access_addr;
|
||||
- u16 phy_ctl_addr;
|
||||
- u32 tmp;
|
||||
-
|
||||
- BUILD_BUG_ON(BGMAC_PA_DATA_MASK != BCMA_GMAC_CMN_PA_DATA_MASK);
|
||||
- BUILD_BUG_ON(BGMAC_PA_ADDR_MASK != BCMA_GMAC_CMN_PA_ADDR_MASK);
|
||||
- BUILD_BUG_ON(BGMAC_PA_ADDR_SHIFT != BCMA_GMAC_CMN_PA_ADDR_SHIFT);
|
||||
- BUILD_BUG_ON(BGMAC_PA_REG_MASK != BCMA_GMAC_CMN_PA_REG_MASK);
|
||||
- BUILD_BUG_ON(BGMAC_PA_REG_SHIFT != BCMA_GMAC_CMN_PA_REG_SHIFT);
|
||||
- BUILD_BUG_ON(BGMAC_PA_WRITE != BCMA_GMAC_CMN_PA_WRITE);
|
||||
- BUILD_BUG_ON(BGMAC_PA_START != BCMA_GMAC_CMN_PA_START);
|
||||
- BUILD_BUG_ON(BGMAC_PC_EPA_MASK != BCMA_GMAC_CMN_PC_EPA_MASK);
|
||||
- BUILD_BUG_ON(BGMAC_PC_MCT_MASK != BCMA_GMAC_CMN_PC_MCT_MASK);
|
||||
- BUILD_BUG_ON(BGMAC_PC_MCT_SHIFT != BCMA_GMAC_CMN_PC_MCT_SHIFT);
|
||||
- BUILD_BUG_ON(BGMAC_PC_MTE != BCMA_GMAC_CMN_PC_MTE);
|
||||
-
|
||||
- if (bgmac->core->id.id == BCMA_CORE_4706_MAC_GBIT) {
|
||||
- core = bgmac->core->bus->drv_gmac_cmn.core;
|
||||
- phy_access_addr = BCMA_GMAC_CMN_PHY_ACCESS;
|
||||
- phy_ctl_addr = BCMA_GMAC_CMN_PHY_CTL;
|
||||
- } else {
|
||||
- core = bgmac->core;
|
||||
- phy_access_addr = BGMAC_PHY_ACCESS;
|
||||
- phy_ctl_addr = BGMAC_PHY_CNTL;
|
||||
- }
|
||||
-
|
||||
- tmp = bcma_read32(core, phy_ctl_addr);
|
||||
- tmp &= ~BGMAC_PC_EPA_MASK;
|
||||
- tmp |= phyaddr;
|
||||
- bcma_write32(core, phy_ctl_addr, tmp);
|
||||
-
|
||||
- tmp = BGMAC_PA_START;
|
||||
- tmp |= phyaddr << BGMAC_PA_ADDR_SHIFT;
|
||||
- tmp |= reg << BGMAC_PA_REG_SHIFT;
|
||||
- bcma_write32(core, phy_access_addr, tmp);
|
||||
-
|
||||
- if (!bgmac_wait_value(core, phy_access_addr, BGMAC_PA_START, 0, 1000)) {
|
||||
- dev_err(bgmac->dev, "Reading PHY %d register 0x%X failed\n",
|
||||
- phyaddr, reg);
|
||||
- return 0xffff;
|
||||
- }
|
||||
-
|
||||
- return bcma_read32(core, phy_access_addr) & BGMAC_PA_DATA_MASK;
|
||||
-}
|
||||
-
|
||||
-/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphywr */
|
||||
-static int bgmac_phy_write(struct bgmac *bgmac, u8 phyaddr, u8 reg, u16 value)
|
||||
-{
|
||||
- struct bcma_device *core;
|
||||
- u16 phy_access_addr;
|
||||
- u16 phy_ctl_addr;
|
||||
- u32 tmp;
|
||||
-
|
||||
- if (bgmac->core->id.id == BCMA_CORE_4706_MAC_GBIT) {
|
||||
- core = bgmac->core->bus->drv_gmac_cmn.core;
|
||||
- phy_access_addr = BCMA_GMAC_CMN_PHY_ACCESS;
|
||||
- phy_ctl_addr = BCMA_GMAC_CMN_PHY_CTL;
|
||||
- } else {
|
||||
- core = bgmac->core;
|
||||
- phy_access_addr = BGMAC_PHY_ACCESS;
|
||||
- phy_ctl_addr = BGMAC_PHY_CNTL;
|
||||
- }
|
||||
-
|
||||
- tmp = bcma_read32(core, phy_ctl_addr);
|
||||
- tmp &= ~BGMAC_PC_EPA_MASK;
|
||||
- tmp |= phyaddr;
|
||||
- bcma_write32(core, phy_ctl_addr, tmp);
|
||||
-
|
||||
- bgmac_write(bgmac, BGMAC_INT_STATUS, BGMAC_IS_MDIO);
|
||||
- if (bgmac_read(bgmac, BGMAC_INT_STATUS) & BGMAC_IS_MDIO)
|
||||
- dev_warn(bgmac->dev, "Error setting MDIO int\n");
|
||||
-
|
||||
- tmp = BGMAC_PA_START;
|
||||
- tmp |= BGMAC_PA_WRITE;
|
||||
- tmp |= phyaddr << BGMAC_PA_ADDR_SHIFT;
|
||||
- tmp |= reg << BGMAC_PA_REG_SHIFT;
|
||||
- tmp |= value;
|
||||
- bcma_write32(core, phy_access_addr, tmp);
|
||||
-
|
||||
- if (!bgmac_wait_value(core, phy_access_addr, BGMAC_PA_START, 0, 1000)) {
|
||||
- dev_err(bgmac->dev, "Writing to PHY %d register 0x%X failed\n",
|
||||
- phyaddr, reg);
|
||||
- return -ETIMEDOUT;
|
||||
- }
|
||||
-
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
-/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphyinit */
|
||||
-static void bgmac_phy_init(struct bgmac *bgmac)
|
||||
-{
|
||||
- struct bcma_chipinfo *ci = &bgmac->core->bus->chipinfo;
|
||||
- struct bcma_drv_cc *cc = &bgmac->core->bus->drv_cc;
|
||||
- u8 i;
|
||||
-
|
||||
- if (ci->id == BCMA_CHIP_ID_BCM5356) {
|
||||
- for (i = 0; i < 5; i++) {
|
||||
- bgmac_phy_write(bgmac, i, 0x1f, 0x008b);
|
||||
- bgmac_phy_write(bgmac, i, 0x15, 0x0100);
|
||||
- bgmac_phy_write(bgmac, i, 0x1f, 0x000f);
|
||||
- bgmac_phy_write(bgmac, i, 0x12, 0x2aaa);
|
||||
- bgmac_phy_write(bgmac, i, 0x1f, 0x000b);
|
||||
- }
|
||||
- }
|
||||
- if ((ci->id == BCMA_CHIP_ID_BCM5357 && ci->pkg != 10) ||
|
||||
- (ci->id == BCMA_CHIP_ID_BCM4749 && ci->pkg != 10) ||
|
||||
- (ci->id == BCMA_CHIP_ID_BCM53572 && ci->pkg != 9)) {
|
||||
- bcma_chipco_chipctl_maskset(cc, 2, ~0xc0000000, 0);
|
||||
- bcma_chipco_chipctl_maskset(cc, 4, ~0x80000000, 0);
|
||||
- for (i = 0; i < 5; i++) {
|
||||
- bgmac_phy_write(bgmac, i, 0x1f, 0x000f);
|
||||
- bgmac_phy_write(bgmac, i, 0x16, 0x5284);
|
||||
- bgmac_phy_write(bgmac, i, 0x1f, 0x000b);
|
||||
- bgmac_phy_write(bgmac, i, 0x17, 0x0010);
|
||||
- bgmac_phy_write(bgmac, i, 0x1f, 0x000f);
|
||||
- bgmac_phy_write(bgmac, i, 0x16, 0x5296);
|
||||
- bgmac_phy_write(bgmac, i, 0x17, 0x1073);
|
||||
- bgmac_phy_write(bgmac, i, 0x17, 0x9073);
|
||||
- bgmac_phy_write(bgmac, i, 0x16, 0x52b6);
|
||||
- bgmac_phy_write(bgmac, i, 0x17, 0x9273);
|
||||
- bgmac_phy_write(bgmac, i, 0x1f, 0x000b);
|
||||
- }
|
||||
- }
|
||||
-}
|
||||
-
|
||||
-/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphyreset */
|
||||
-static void bgmac_phy_reset(struct bgmac *bgmac)
|
||||
-{
|
||||
- if (bgmac->phyaddr == BGMAC_PHY_NOREGS)
|
||||
- return;
|
||||
-
|
||||
- bgmac_phy_write(bgmac, bgmac->phyaddr, MII_BMCR, BMCR_RESET);
|
||||
- udelay(100);
|
||||
- if (bgmac_phy_read(bgmac, bgmac->phyaddr, MII_BMCR) & BMCR_RESET)
|
||||
- dev_err(bgmac->dev, "PHY reset failed\n");
|
||||
- bgmac_phy_init(bgmac);
|
||||
-}
|
||||
|
||||
/**************************************************
|
||||
* Chip ops
|
||||
@@ -1159,7 +1015,8 @@ static void bgmac_chip_reset(struct bgma
|
||||
else
|
||||
bgmac_set(bgmac, BGMAC_PHY_CNTL, BGMAC_PC_MTE);
|
||||
bgmac_miiconfig(bgmac);
|
||||
- bgmac_phy_init(bgmac);
|
||||
+ if (bgmac->mii_bus)
|
||||
+ bgmac->mii_bus->reset(bgmac->mii_bus);
|
||||
|
||||
netdev_reset_queue(bgmac->net_dev);
|
||||
}
|
||||
@@ -1553,17 +1410,6 @@ static const struct ethtool_ops bgmac_et
|
||||
* MII
|
||||
**************************************************/
|
||||
|
||||
-static int bgmac_mii_read(struct mii_bus *bus, int mii_id, int regnum)
|
||||
-{
|
||||
- return bgmac_phy_read(bus->priv, mii_id, regnum);
|
||||
-}
|
||||
-
|
||||
-static int bgmac_mii_write(struct mii_bus *bus, int mii_id, int regnum,
|
||||
- u16 value)
|
||||
-{
|
||||
- return bgmac_phy_write(bus->priv, mii_id, regnum, value);
|
||||
-}
|
||||
-
|
||||
static void bgmac_adjust_link(struct net_device *net_dev)
|
||||
{
|
||||
struct bgmac *bgmac = netdev_priv(net_dev);
|
||||
@@ -1588,7 +1434,7 @@ static void bgmac_adjust_link(struct net
|
||||
}
|
||||
}
|
||||
|
||||
-static int bgmac_fixed_phy_register(struct bgmac *bgmac)
|
||||
+static int bgmac_phy_connect_direct(struct bgmac *bgmac)
|
||||
{
|
||||
struct fixed_phy_status fphy_status = {
|
||||
.link = 1,
|
||||
@@ -1614,81 +1460,24 @@ static int bgmac_fixed_phy_register(stru
|
||||
return err;
|
||||
}
|
||||
|
||||
-static int bgmac_mii_register(struct bgmac *bgmac)
|
||||
+static int bgmac_phy_connect(struct bgmac *bgmac)
|
||||
{
|
||||
- struct mii_bus *mii_bus;
|
||||
struct phy_device *phy_dev;
|
||||
char bus_id[MII_BUS_ID_SIZE + 3];
|
||||
- int i, err = 0;
|
||||
-
|
||||
- if (bgmac_is_bcm4707_family(bgmac))
|
||||
- return bgmac_fixed_phy_register(bgmac);
|
||||
-
|
||||
- mii_bus = mdiobus_alloc();
|
||||
- if (!mii_bus)
|
||||
- return -ENOMEM;
|
||||
-
|
||||
- mii_bus->name = "bgmac mii bus";
|
||||
- sprintf(mii_bus->id, "%s-%d-%d", "bgmac", bgmac->core->bus->num,
|
||||
- bgmac->core->core_unit);
|
||||
- mii_bus->priv = bgmac;
|
||||
- mii_bus->read = bgmac_mii_read;
|
||||
- mii_bus->write = bgmac_mii_write;
|
||||
- mii_bus->parent = &bgmac->core->dev;
|
||||
- mii_bus->phy_mask = ~(1 << bgmac->phyaddr);
|
||||
-
|
||||
- mii_bus->irq = kmalloc_array(PHY_MAX_ADDR, sizeof(int), GFP_KERNEL);
|
||||
- if (!mii_bus->irq) {
|
||||
- err = -ENOMEM;
|
||||
- goto err_free_bus;
|
||||
- }
|
||||
- for (i = 0; i < PHY_MAX_ADDR; i++)
|
||||
- mii_bus->irq[i] = PHY_POLL;
|
||||
-
|
||||
- err = mdiobus_register(mii_bus);
|
||||
- if (err) {
|
||||
- dev_err(bgmac->dev, "Registration of mii bus failed\n");
|
||||
- goto err_free_irq;
|
||||
- }
|
||||
-
|
||||
- bgmac->mii_bus = mii_bus;
|
||||
|
||||
/* Connect to the PHY */
|
||||
- snprintf(bus_id, sizeof(bus_id), PHY_ID_FMT, mii_bus->id,
|
||||
+ snprintf(bus_id, sizeof(bus_id), PHY_ID_FMT, bgmac->mii_bus->id,
|
||||
bgmac->phyaddr);
|
||||
phy_dev = phy_connect(bgmac->net_dev, bus_id, &bgmac_adjust_link,
|
||||
PHY_INTERFACE_MODE_MII);
|
||||
if (IS_ERR(phy_dev)) {
|
||||
dev_err(bgmac->dev, "PHY connecton failed\n");
|
||||
- err = PTR_ERR(phy_dev);
|
||||
- goto err_unregister_bus;
|
||||
+ return PTR_ERR(phy_dev);
|
||||
}
|
||||
|
||||
- return err;
|
||||
-
|
||||
-err_unregister_bus:
|
||||
- mdiobus_unregister(mii_bus);
|
||||
-err_free_irq:
|
||||
- kfree(mii_bus->irq);
|
||||
-err_free_bus:
|
||||
- mdiobus_free(mii_bus);
|
||||
- return err;
|
||||
-}
|
||||
-
|
||||
-static void bgmac_mii_unregister(struct bgmac *bgmac)
|
||||
-{
|
||||
- struct mii_bus *mii_bus = bgmac->mii_bus;
|
||||
-
|
||||
- mdiobus_unregister(mii_bus);
|
||||
- kfree(mii_bus->irq);
|
||||
- mdiobus_free(mii_bus);
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
-/**************************************************
|
||||
- * BCMA bus ops
|
||||
- **************************************************/
|
||||
-
|
||||
-/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipattach */
|
||||
static int bgmac_probe(struct bcma_device *core)
|
||||
{
|
||||
struct net_device *net_dev;
|
||||
@@ -1809,9 +1598,6 @@ static int bgmac_probe(struct bcma_devic
|
||||
if (bcm47xx_nvram_getenv("et0_no_txint", NULL, 0) == 0)
|
||||
bgmac->int_mask &= ~BGMAC_IS_TX_MASK;
|
||||
|
||||
- /* TODO: reset the external phy. Specs are needed */
|
||||
- bgmac_phy_reset(bgmac);
|
||||
-
|
||||
bgmac->has_robosw = !!(core->bus->sprom.boardflags_lo &
|
||||
BGMAC_BFL_ENETROBO);
|
||||
if (bgmac->has_robosw)
|
||||
@@ -1822,10 +1608,25 @@ static int bgmac_probe(struct bcma_devic
|
||||
|
||||
netif_napi_add(net_dev, &bgmac->napi, bgmac_poll, BGMAC_WEIGHT);
|
||||
|
||||
- err = bgmac_mii_register(bgmac);
|
||||
+ if (!bgmac_is_bcm4707_family(bgmac)) {
|
||||
+ struct mii_bus *mii_bus;
|
||||
+
|
||||
+ mii_bus = bcma_mdio_mii_register(core, bgmac->phyaddr);
|
||||
+ if (!IS_ERR(mii_bus)) {
|
||||
+ err = PTR_ERR(mii_bus);
|
||||
+ goto err_dma_free;
|
||||
+ }
|
||||
+
|
||||
+ bgmac->mii_bus = mii_bus;
|
||||
+ }
|
||||
+
|
||||
+ if (!bgmac->mii_bus)
|
||||
+ err = bgmac_phy_connect_direct(bgmac);
|
||||
+ else
|
||||
+ err = bgmac_phy_connect(bgmac);
|
||||
if (err) {
|
||||
dev_err(bgmac->dev, "Cannot connect to phy\n");
|
||||
- goto err_dma_free;
|
||||
+ goto err_mii_unregister;
|
||||
}
|
||||
|
||||
net_dev->features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
|
||||
@@ -1835,18 +1636,19 @@ static int bgmac_probe(struct bcma_devic
|
||||
err = register_netdev(bgmac->net_dev);
|
||||
if (err) {
|
||||
dev_err(bgmac->dev, "Cannot register net device\n");
|
||||
- goto err_mii_unregister;
|
||||
+ goto err_phy_disconnect;
|
||||
}
|
||||
|
||||
netif_carrier_off(net_dev);
|
||||
|
||||
return 0;
|
||||
|
||||
+err_phy_disconnect:
|
||||
+ phy_disconnect(net_dev->phydev);
|
||||
err_mii_unregister:
|
||||
- bgmac_mii_unregister(bgmac);
|
||||
+ bcma_mdio_mii_unregister(bgmac->mii_bus);
|
||||
err_dma_free:
|
||||
bgmac_dma_free(bgmac);
|
||||
-
|
||||
err_netdev_free:
|
||||
bcma_set_drvdata(core, NULL);
|
||||
free_netdev(net_dev);
|
||||
@@ -1859,7 +1661,8 @@ static void bgmac_remove(struct bcma_dev
|
||||
struct bgmac *bgmac = bcma_get_drvdata(core);
|
||||
|
||||
unregister_netdev(bgmac->net_dev);
|
||||
- bgmac_mii_unregister(bgmac);
|
||||
+ phy_disconnect(bgmac->net_dev->phydev);
|
||||
+ bcma_mdio_mii_unregister(bgmac->mii_bus);
|
||||
netif_napi_del(&bgmac->napi);
|
||||
bgmac_dma_free(bgmac);
|
||||
bcma_set_drvdata(core, NULL);
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac.h
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac.h
|
||||
@@ -456,6 +456,9 @@ struct bgmac {
|
||||
bool loopback;
|
||||
};
|
||||
|
||||
+struct mii_bus *bcma_mdio_mii_register(struct bcma_device *core, u8 phyaddr);
|
||||
+void bcma_mdio_mii_unregister(struct mii_bus *mii_bus);
|
||||
+
|
||||
static inline u32 bgmac_read(struct bgmac *bgmac, u16 offset)
|
||||
{
|
||||
return bcma_read32(bgmac->core, offset);
|
@ -1,384 +0,0 @@
|
||||
From db791eb2970bad193b1dc95a4461b222dd22cb64 Mon Sep 17 00:00:00 2001
|
||||
From: Jon Mason <jon.mason@broadcom.com>
|
||||
Date: Thu, 7 Jul 2016 19:08:56 -0400
|
||||
Subject: [PATCH 4/5] net: ethernet: bgmac: convert to feature flags
|
||||
|
||||
The bgmac driver is using the bcma provides device ID and revision, as
|
||||
well as the SoC ID and package, to determine which features are
|
||||
necessary to enable, reset, etc in the driver. In anticipation of
|
||||
removing the bcma requirement for this driver, these must be changed to
|
||||
not reference that struct. In place of that, each "feature" has been
|
||||
given a flag, and the flags are enabled for their respective device and
|
||||
SoC.
|
||||
|
||||
Signed-off-by: Jon Mason <jon.mason@broadcom.com>
|
||||
Acked-by: Arnd Bergmann <arnd@arndb.de>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Tested-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/ethernet/broadcom/bgmac.c | 167 ++++++++++++++++++++++++----------
|
||||
drivers/net/ethernet/broadcom/bgmac.h | 21 ++++-
|
||||
2 files changed, 140 insertions(+), 48 deletions(-)
|
||||
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac.c
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac.c
|
||||
@@ -109,7 +109,7 @@ static void bgmac_dma_tx_enable(struct b
|
||||
u32 ctl;
|
||||
|
||||
ctl = bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_TX_CTL);
|
||||
- if (bgmac->core->id.rev >= 4) {
|
||||
+ if (bgmac->feature_flags & BGMAC_FEAT_TX_MASK_SETUP) {
|
||||
ctl &= ~BGMAC_DMA_TX_BL_MASK;
|
||||
ctl |= BGMAC_DMA_TX_BL_128 << BGMAC_DMA_TX_BL_SHIFT;
|
||||
|
||||
@@ -335,7 +335,7 @@ static void bgmac_dma_rx_enable(struct b
|
||||
/* preserve ONLY bits 16-17 from current hardware value */
|
||||
ctl &= BGMAC_DMA_RX_ADDREXT_MASK;
|
||||
|
||||
- if (bgmac->core->id.rev >= 4) {
|
||||
+ if (bgmac->feature_flags & BGMAC_FEAT_RX_MASK_SETUP) {
|
||||
ctl &= ~BGMAC_DMA_RX_BL_MASK;
|
||||
ctl |= BGMAC_DMA_RX_BL_128 << BGMAC_DMA_RX_BL_SHIFT;
|
||||
|
||||
@@ -772,14 +772,20 @@ static void bgmac_cmdcfg_maskset(struct
|
||||
{
|
||||
u32 cmdcfg = bgmac_read(bgmac, BGMAC_CMDCFG);
|
||||
u32 new_val = (cmdcfg & mask) | set;
|
||||
+ u32 cmdcfg_sr;
|
||||
|
||||
- bgmac_set(bgmac, BGMAC_CMDCFG, BGMAC_CMDCFG_SR(bgmac->core->id.rev));
|
||||
+ if (bgmac->feature_flags & BGMAC_FEAT_CMDCFG_SR_REV4)
|
||||
+ cmdcfg_sr = BGMAC_CMDCFG_SR_REV4;
|
||||
+ else
|
||||
+ cmdcfg_sr = BGMAC_CMDCFG_SR_REV0;
|
||||
+
|
||||
+ bgmac_set(bgmac, BGMAC_CMDCFG, cmdcfg_sr);
|
||||
udelay(2);
|
||||
|
||||
if (new_val != cmdcfg || force)
|
||||
bgmac_write(bgmac, BGMAC_CMDCFG, new_val);
|
||||
|
||||
- bgmac_mask(bgmac, BGMAC_CMDCFG, ~BGMAC_CMDCFG_SR(bgmac->core->id.rev));
|
||||
+ bgmac_mask(bgmac, BGMAC_CMDCFG, ~cmdcfg_sr);
|
||||
udelay(2);
|
||||
}
|
||||
|
||||
@@ -808,7 +814,7 @@ static void bgmac_chip_stats_update(stru
|
||||
{
|
||||
int i;
|
||||
|
||||
- if (bgmac->core->id.id != BCMA_CORE_4706_MAC_GBIT) {
|
||||
+ if (!(bgmac->feature_flags & BGMAC_FEAT_NO_CLR_MIB)) {
|
||||
for (i = 0; i < BGMAC_NUM_MIB_TX_REGS; i++)
|
||||
bgmac->mib_tx_regs[i] =
|
||||
bgmac_read(bgmac,
|
||||
@@ -827,7 +833,7 @@ static void bgmac_clear_mib(struct bgmac
|
||||
{
|
||||
int i;
|
||||
|
||||
- if (bgmac->core->id.id == BCMA_CORE_4706_MAC_GBIT)
|
||||
+ if (bgmac->feature_flags & BGMAC_FEAT_NO_CLR_MIB)
|
||||
return;
|
||||
|
||||
bgmac_set(bgmac, BGMAC_DEV_CTL, BGMAC_DC_MROR);
|
||||
@@ -870,9 +876,8 @@ static void bgmac_mac_speed(struct bgmac
|
||||
static void bgmac_miiconfig(struct bgmac *bgmac)
|
||||
{
|
||||
struct bcma_device *core = bgmac->core;
|
||||
- u8 imode;
|
||||
|
||||
- if (bgmac_is_bcm4707_family(bgmac)) {
|
||||
+ if (bgmac->feature_flags & BGMAC_FEAT_FORCE_SPEED_2500) {
|
||||
bcma_awrite32(core, BCMA_IOCTL,
|
||||
bcma_aread32(core, BCMA_IOCTL) | 0x40 |
|
||||
BGMAC_BCMA_IOCTL_SW_CLKEN);
|
||||
@@ -880,6 +885,8 @@ static void bgmac_miiconfig(struct bgmac
|
||||
bgmac->mac_duplex = DUPLEX_FULL;
|
||||
bgmac_mac_speed(bgmac);
|
||||
} else {
|
||||
+ u8 imode;
|
||||
+
|
||||
imode = (bgmac_read(bgmac, BGMAC_DEV_STATUS) &
|
||||
BGMAC_DS_MM_MASK) >> BGMAC_DS_MM_SHIFT;
|
||||
if (imode == 0 || imode == 1) {
|
||||
@@ -894,9 +901,7 @@ static void bgmac_miiconfig(struct bgmac
|
||||
static void bgmac_chip_reset(struct bgmac *bgmac)
|
||||
{
|
||||
struct bcma_device *core = bgmac->core;
|
||||
- struct bcma_bus *bus = core->bus;
|
||||
- struct bcma_chipinfo *ci = &bus->chipinfo;
|
||||
- u32 flags;
|
||||
+ u32 cmdcfg_sr;
|
||||
u32 iost;
|
||||
int i;
|
||||
|
||||
@@ -919,15 +924,12 @@ static void bgmac_chip_reset(struct bgma
|
||||
}
|
||||
|
||||
iost = bcma_aread32(core, BCMA_IOST);
|
||||
- if ((ci->id == BCMA_CHIP_ID_BCM5357 && ci->pkg == BCMA_PKG_ID_BCM47186) ||
|
||||
- (ci->id == BCMA_CHIP_ID_BCM4749 && ci->pkg == 10) ||
|
||||
- (ci->id == BCMA_CHIP_ID_BCM53572 && ci->pkg == BCMA_PKG_ID_BCM47188))
|
||||
+ if (bgmac->feature_flags & BGMAC_FEAT_IOST_ATTACHED)
|
||||
iost &= ~BGMAC_BCMA_IOST_ATTACHED;
|
||||
|
||||
/* 3GMAC: for BCM4707 & BCM47094, only do core reset at bgmac_probe() */
|
||||
- if (ci->id != BCMA_CHIP_ID_BCM4707 &&
|
||||
- ci->id != BCMA_CHIP_ID_BCM47094) {
|
||||
- flags = 0;
|
||||
+ if (!(bgmac->feature_flags & BGMAC_FEAT_NO_RESET)) {
|
||||
+ u32 flags = 0;
|
||||
if (iost & BGMAC_BCMA_IOST_ATTACHED) {
|
||||
flags = BGMAC_BCMA_IOCTL_SW_CLKEN;
|
||||
if (!bgmac->has_robosw)
|
||||
@@ -937,7 +939,7 @@ static void bgmac_chip_reset(struct bgma
|
||||
}
|
||||
|
||||
/* Request Misc PLL for corerev > 2 */
|
||||
- if (core->id.rev > 2 && !bgmac_is_bcm4707_family(bgmac)) {
|
||||
+ if (bgmac->feature_flags & BGMAC_FEAT_MISC_PLL_REQ) {
|
||||
bgmac_set(bgmac, BCMA_CLKCTLST,
|
||||
BGMAC_BCMA_CLKCTLST_MISC_PLL_REQ);
|
||||
bgmac_wait_value(bgmac->core, BCMA_CLKCTLST,
|
||||
@@ -946,9 +948,7 @@ static void bgmac_chip_reset(struct bgma
|
||||
1000);
|
||||
}
|
||||
|
||||
- if (ci->id == BCMA_CHIP_ID_BCM5357 ||
|
||||
- ci->id == BCMA_CHIP_ID_BCM4749 ||
|
||||
- ci->id == BCMA_CHIP_ID_BCM53572) {
|
||||
+ if (bgmac->feature_flags & BGMAC_FEAT_SW_TYPE_PHY) {
|
||||
struct bcma_drv_cc *cc = &bgmac->core->bus->drv_cc;
|
||||
u8 et_swtype = 0;
|
||||
u8 sw_type = BGMAC_CHIPCTL_1_SW_TYPE_EPHY |
|
||||
@@ -962,11 +962,9 @@ static void bgmac_chip_reset(struct bgma
|
||||
et_swtype &= 0x0f;
|
||||
et_swtype <<= 4;
|
||||
sw_type = et_swtype;
|
||||
- } else if (ci->id == BCMA_CHIP_ID_BCM5357 && ci->pkg == BCMA_PKG_ID_BCM5358) {
|
||||
+ } else if (bgmac->feature_flags & BGMAC_FEAT_SW_TYPE_EPHYRMII) {
|
||||
sw_type = BGMAC_CHIPCTL_1_SW_TYPE_EPHYRMII;
|
||||
- } else if ((ci->id == BCMA_CHIP_ID_BCM5357 && ci->pkg == BCMA_PKG_ID_BCM47186) ||
|
||||
- (ci->id == BCMA_CHIP_ID_BCM4749 && ci->pkg == 10) ||
|
||||
- (ci->id == BCMA_CHIP_ID_BCM53572 && ci->pkg == BCMA_PKG_ID_BCM47188)) {
|
||||
+ } else if (bgmac->feature_flags & BGMAC_FEAT_SW_TYPE_RGMII) {
|
||||
sw_type = BGMAC_CHIPCTL_1_IF_TYPE_RGMII |
|
||||
BGMAC_CHIPCTL_1_SW_TYPE_RGMII;
|
||||
}
|
||||
@@ -986,6 +984,11 @@ static void bgmac_chip_reset(struct bgma
|
||||
* BGMAC_CMDCFG is read _after_ putting chip in a reset. So it has to
|
||||
* be keps until taking MAC out of the reset.
|
||||
*/
|
||||
+ if (bgmac->feature_flags & BGMAC_FEAT_CMDCFG_SR_REV4)
|
||||
+ cmdcfg_sr = BGMAC_CMDCFG_SR_REV4;
|
||||
+ else
|
||||
+ cmdcfg_sr = BGMAC_CMDCFG_SR_REV0;
|
||||
+
|
||||
bgmac_cmdcfg_maskset(bgmac,
|
||||
~(BGMAC_CMDCFG_TE |
|
||||
BGMAC_CMDCFG_RE |
|
||||
@@ -1003,13 +1006,13 @@ static void bgmac_chip_reset(struct bgma
|
||||
BGMAC_CMDCFG_PROM |
|
||||
BGMAC_CMDCFG_NLC |
|
||||
BGMAC_CMDCFG_CFE |
|
||||
- BGMAC_CMDCFG_SR(core->id.rev),
|
||||
+ cmdcfg_sr,
|
||||
false);
|
||||
bgmac->mac_speed = SPEED_UNKNOWN;
|
||||
bgmac->mac_duplex = DUPLEX_UNKNOWN;
|
||||
|
||||
bgmac_clear_mib(bgmac);
|
||||
- if (core->id.id == BCMA_CORE_4706_MAC_GBIT)
|
||||
+ if (bgmac->feature_flags & BGMAC_FEAT_CMN_PHY_CTL)
|
||||
bcma_maskset32(bgmac->cmn, BCMA_GMAC_CMN_PHY_CTL, ~0,
|
||||
BCMA_GMAC_CMN_PC_MTE);
|
||||
else
|
||||
@@ -1035,46 +1038,48 @@ static void bgmac_chip_intrs_off(struct
|
||||
/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/gmac_enable */
|
||||
static void bgmac_enable(struct bgmac *bgmac)
|
||||
{
|
||||
- struct bcma_chipinfo *ci = &bgmac->core->bus->chipinfo;
|
||||
+ u32 cmdcfg_sr;
|
||||
u32 cmdcfg;
|
||||
u32 mode;
|
||||
- u32 rxq_ctl;
|
||||
- u32 fl_ctl;
|
||||
- u16 bp_clk;
|
||||
- u8 mdp;
|
||||
+
|
||||
+ if (bgmac->feature_flags & BGMAC_FEAT_CMDCFG_SR_REV4)
|
||||
+ cmdcfg_sr = BGMAC_CMDCFG_SR_REV4;
|
||||
+ else
|
||||
+ cmdcfg_sr = BGMAC_CMDCFG_SR_REV0;
|
||||
|
||||
cmdcfg = bgmac_read(bgmac, BGMAC_CMDCFG);
|
||||
bgmac_cmdcfg_maskset(bgmac, ~(BGMAC_CMDCFG_TE | BGMAC_CMDCFG_RE),
|
||||
- BGMAC_CMDCFG_SR(bgmac->core->id.rev), true);
|
||||
+ cmdcfg_sr, true);
|
||||
udelay(2);
|
||||
cmdcfg |= BGMAC_CMDCFG_TE | BGMAC_CMDCFG_RE;
|
||||
bgmac_write(bgmac, BGMAC_CMDCFG, cmdcfg);
|
||||
|
||||
mode = (bgmac_read(bgmac, BGMAC_DEV_STATUS) & BGMAC_DS_MM_MASK) >>
|
||||
BGMAC_DS_MM_SHIFT;
|
||||
- if (ci->id != BCMA_CHIP_ID_BCM47162 || mode != 0)
|
||||
+ if (bgmac->feature_flags & BGMAC_FEAT_CLKCTLST || mode != 0)
|
||||
bgmac_set(bgmac, BCMA_CLKCTLST, BCMA_CLKCTLST_FORCEHT);
|
||||
- if (ci->id == BCMA_CHIP_ID_BCM47162 && mode == 2)
|
||||
+ if (bgmac->feature_flags & BGMAC_FEAT_CLKCTLST && mode == 2)
|
||||
bcma_chipco_chipctl_maskset(&bgmac->core->bus->drv_cc, 1, ~0,
|
||||
BGMAC_CHIPCTL_1_RXC_DLL_BYPASS);
|
||||
|
||||
- switch (ci->id) {
|
||||
- case BCMA_CHIP_ID_BCM5357:
|
||||
- case BCMA_CHIP_ID_BCM4749:
|
||||
- case BCMA_CHIP_ID_BCM53572:
|
||||
- case BCMA_CHIP_ID_BCM4716:
|
||||
- case BCMA_CHIP_ID_BCM47162:
|
||||
- fl_ctl = 0x03cb04cb;
|
||||
- if (ci->id == BCMA_CHIP_ID_BCM5357 ||
|
||||
- ci->id == BCMA_CHIP_ID_BCM4749 ||
|
||||
- ci->id == BCMA_CHIP_ID_BCM53572)
|
||||
+ if (bgmac->feature_flags & (BGMAC_FEAT_FLW_CTRL1 |
|
||||
+ BGMAC_FEAT_FLW_CTRL2)) {
|
||||
+ u32 fl_ctl;
|
||||
+
|
||||
+ if (bgmac->feature_flags & BGMAC_FEAT_FLW_CTRL1)
|
||||
fl_ctl = 0x2300e1;
|
||||
+ else
|
||||
+ fl_ctl = 0x03cb04cb;
|
||||
+
|
||||
bgmac_write(bgmac, BGMAC_FLOW_CTL_THRESH, fl_ctl);
|
||||
bgmac_write(bgmac, BGMAC_PAUSE_CTL, 0x27fff);
|
||||
- break;
|
||||
}
|
||||
|
||||
- if (!bgmac_is_bcm4707_family(bgmac)) {
|
||||
+ if (bgmac->feature_flags & BGMAC_FEAT_SET_RXQ_CLK) {
|
||||
+ u32 rxq_ctl;
|
||||
+ u16 bp_clk;
|
||||
+ u8 mdp;
|
||||
+
|
||||
rxq_ctl = bgmac_read(bgmac, BGMAC_RXQ_CTL);
|
||||
rxq_ctl &= ~BGMAC_RXQ_CTL_MDP_MASK;
|
||||
bp_clk = bcma_pmu_get_bus_clock(&bgmac->core->bus->drv_cc) /
|
||||
@@ -1606,6 +1611,74 @@ static int bgmac_probe(struct bcma_devic
|
||||
if (core->bus->sprom.boardflags_lo & BGMAC_BFL_ENETADM)
|
||||
dev_warn(bgmac->dev, "Support for ADMtek ethernet switch not implemented\n");
|
||||
|
||||
+ /* Feature Flags */
|
||||
+ switch (core->bus->chipinfo.id) {
|
||||
+ case BCMA_CHIP_ID_BCM5357:
|
||||
+ bgmac->feature_flags |= BGMAC_FEAT_SET_RXQ_CLK;
|
||||
+ bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
|
||||
+ bgmac->feature_flags |= BGMAC_FEAT_FLW_CTRL1;
|
||||
+ bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_PHY;
|
||||
+ if (core->bus->chipinfo.pkg == BCMA_PKG_ID_BCM47186) {
|
||||
+ bgmac->feature_flags |= BGMAC_FEAT_IOST_ATTACHED;
|
||||
+ bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_RGMII;
|
||||
+ }
|
||||
+ if (core->bus->chipinfo.pkg == BCMA_PKG_ID_BCM5358)
|
||||
+ bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_EPHYRMII;
|
||||
+ break;
|
||||
+ case BCMA_CHIP_ID_BCM53572:
|
||||
+ bgmac->feature_flags |= BGMAC_FEAT_SET_RXQ_CLK;
|
||||
+ bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
|
||||
+ bgmac->feature_flags |= BGMAC_FEAT_FLW_CTRL1;
|
||||
+ bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_PHY;
|
||||
+ if (core->bus->chipinfo.pkg == BCMA_PKG_ID_BCM47188) {
|
||||
+ bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_RGMII;
|
||||
+ bgmac->feature_flags |= BGMAC_FEAT_IOST_ATTACHED;
|
||||
+ }
|
||||
+ break;
|
||||
+ case BCMA_CHIP_ID_BCM4749:
|
||||
+ bgmac->feature_flags |= BGMAC_FEAT_SET_RXQ_CLK;
|
||||
+ bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
|
||||
+ bgmac->feature_flags |= BGMAC_FEAT_FLW_CTRL1;
|
||||
+ bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_PHY;
|
||||
+ if (core->bus->chipinfo.pkg == 10) {
|
||||
+ bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_RGMII;
|
||||
+ bgmac->feature_flags |= BGMAC_FEAT_IOST_ATTACHED;
|
||||
+ }
|
||||
+ break;
|
||||
+ case BCMA_CHIP_ID_BCM4716:
|
||||
+ bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
|
||||
+ /* fallthrough */
|
||||
+ case BCMA_CHIP_ID_BCM47162:
|
||||
+ bgmac->feature_flags |= BGMAC_FEAT_FLW_CTRL2;
|
||||
+ bgmac->feature_flags |= BGMAC_FEAT_SET_RXQ_CLK;
|
||||
+ break;
|
||||
+ /* bcm4707_family */
|
||||
+ case BCMA_CHIP_ID_BCM4707:
|
||||
+ case BCMA_CHIP_ID_BCM47094:
|
||||
+ case BCMA_CHIP_ID_BCM53018:
|
||||
+ bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
|
||||
+ bgmac->feature_flags |= BGMAC_FEAT_NO_RESET;
|
||||
+ bgmac->feature_flags |= BGMAC_FEAT_FORCE_SPEED_2500;
|
||||
+ break;
|
||||
+ default:
|
||||
+ bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
|
||||
+ bgmac->feature_flags |= BGMAC_FEAT_SET_RXQ_CLK;
|
||||
+ }
|
||||
+
|
||||
+ if (!bgmac_is_bcm4707_family(bgmac) && core->id.rev > 2)
|
||||
+ bgmac->feature_flags |= BGMAC_FEAT_MISC_PLL_REQ;
|
||||
+
|
||||
+ if (core->id.id == BCMA_CORE_4706_MAC_GBIT) {
|
||||
+ bgmac->feature_flags |= BGMAC_FEAT_CMN_PHY_CTL;
|
||||
+ bgmac->feature_flags |= BGMAC_FEAT_NO_CLR_MIB;
|
||||
+ }
|
||||
+
|
||||
+ if (core->id.rev >= 4) {
|
||||
+ bgmac->feature_flags |= BGMAC_FEAT_CMDCFG_SR_REV4;
|
||||
+ bgmac->feature_flags |= BGMAC_FEAT_TX_MASK_SETUP;
|
||||
+ bgmac->feature_flags |= BGMAC_FEAT_RX_MASK_SETUP;
|
||||
+ }
|
||||
+
|
||||
netif_napi_add(net_dev, &bgmac->napi, bgmac_poll, BGMAC_WEIGHT);
|
||||
|
||||
if (!bgmac_is_bcm4707_family(bgmac)) {
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac.h
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac.h
|
||||
@@ -190,7 +190,6 @@
|
||||
#define BGMAC_CMDCFG_HD_SHIFT 10
|
||||
#define BGMAC_CMDCFG_SR_REV0 0x00000800 /* Set to reset mode, for core rev 0-3 */
|
||||
#define BGMAC_CMDCFG_SR_REV4 0x00002000 /* Set to reset mode, for core rev >= 4 */
|
||||
-#define BGMAC_CMDCFG_SR(rev) ((rev >= 4) ? BGMAC_CMDCFG_SR_REV4 : BGMAC_CMDCFG_SR_REV0)
|
||||
#define BGMAC_CMDCFG_ML 0x00008000 /* Set to activate mac loopback mode */
|
||||
#define BGMAC_CMDCFG_AE 0x00400000
|
||||
#define BGMAC_CMDCFG_CFE 0x00800000
|
||||
@@ -376,6 +375,24 @@
|
||||
|
||||
#define ETHER_MAX_LEN 1518
|
||||
|
||||
+/* Feature Flags */
|
||||
+#define BGMAC_FEAT_TX_MASK_SETUP BIT(0)
|
||||
+#define BGMAC_FEAT_RX_MASK_SETUP BIT(1)
|
||||
+#define BGMAC_FEAT_IOST_ATTACHED BIT(2)
|
||||
+#define BGMAC_FEAT_NO_RESET BIT(3)
|
||||
+#define BGMAC_FEAT_MISC_PLL_REQ BIT(4)
|
||||
+#define BGMAC_FEAT_SW_TYPE_PHY BIT(5)
|
||||
+#define BGMAC_FEAT_SW_TYPE_EPHYRMII BIT(6)
|
||||
+#define BGMAC_FEAT_SW_TYPE_RGMII BIT(7)
|
||||
+#define BGMAC_FEAT_CMN_PHY_CTL BIT(8)
|
||||
+#define BGMAC_FEAT_FLW_CTRL1 BIT(9)
|
||||
+#define BGMAC_FEAT_FLW_CTRL2 BIT(10)
|
||||
+#define BGMAC_FEAT_SET_RXQ_CLK BIT(11)
|
||||
+#define BGMAC_FEAT_CLKCTLST BIT(12)
|
||||
+#define BGMAC_FEAT_NO_CLR_MIB BIT(13)
|
||||
+#define BGMAC_FEAT_FORCE_SPEED_2500 BIT(14)
|
||||
+#define BGMAC_FEAT_CMDCFG_SR_REV4 BIT(15)
|
||||
+
|
||||
struct bgmac_slot_info {
|
||||
union {
|
||||
struct sk_buff *skb;
|
||||
@@ -430,6 +447,8 @@ struct bgmac {
|
||||
|
||||
struct device *dev;
|
||||
struct device *dma_dev;
|
||||
+ u32 feature_flags;
|
||||
+
|
||||
struct net_device *net_dev;
|
||||
struct napi_struct napi;
|
||||
struct mii_bus *mii_bus;
|
File diff suppressed because it is too large
Load Diff
@ -1,26 +0,0 @@
|
||||
From 12c2e32f14da857b58af281b029d4549d24c3292 Mon Sep 17 00:00:00 2001
|
||||
From: Wei Yongjun <yongjun_wei@trendmicro.com.cn>
|
||||
Date: Tue, 12 Jul 2016 00:17:28 +0000
|
||||
Subject: [PATCH] net: ethernet: bgmac: Fix return value check in bgmac_probe()
|
||||
|
||||
In case of error, the function devm_ioremap_resource() returns ERR_PTR()
|
||||
and never returns NULL. The NULL test in the return value check should be
|
||||
replaced with IS_ERR().
|
||||
|
||||
Signed-off-by: Wei Yongjun <yongjun_wei@trendmicro.com.cn>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/ethernet/broadcom/bgmac-platform.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac-platform.c
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac-platform.c
|
||||
@@ -141,7 +141,7 @@ static int bgmac_probe(struct platform_d
|
||||
}
|
||||
|
||||
bgmac->plat.idm_base = devm_ioremap_resource(&pdev->dev, regs);
|
||||
- if (!bgmac->plat.idm_base) {
|
||||
+ if (IS_ERR(bgmac->plat.idm_base)) {
|
||||
dev_err(&pdev->dev, "Unable to map idm resource\n");
|
||||
return PTR_ERR(bgmac->plat.idm_base);
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
From ce3a380dddd0cb16cb3d8d947b69657d7646c121 Mon Sep 17 00:00:00 2001
|
||||
From: Wei Yongjun <yongjun_wei@trendmicro.com.cn>
|
||||
Date: Wed, 13 Jul 2016 12:46:57 +0000
|
||||
Subject: [PATCH] net: ethernet: bgmac: Remove redundant dev_err call in
|
||||
bgmac_probe()
|
||||
|
||||
There is a error message within devm_ioremap_resource
|
||||
already, so remove the dev_err call to avoid redundant
|
||||
error message.
|
||||
|
||||
Signed-off-by: Wei Yongjun <yongjun_wei@trendmicro.com.cn>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/ethernet/broadcom/bgmac-platform.c | 8 ++------
|
||||
1 file changed, 2 insertions(+), 6 deletions(-)
|
||||
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac-platform.c
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac-platform.c
|
||||
@@ -129,10 +129,8 @@ static int bgmac_probe(struct platform_d
|
||||
}
|
||||
|
||||
bgmac->plat.base = devm_ioremap_resource(&pdev->dev, regs);
|
||||
- if (IS_ERR(bgmac->plat.base)) {
|
||||
- dev_err(&pdev->dev, "Unable to map base resource\n");
|
||||
+ if (IS_ERR(bgmac->plat.base))
|
||||
return PTR_ERR(bgmac->plat.base);
|
||||
- }
|
||||
|
||||
regs = platform_get_resource_byname(pdev, IORESOURCE_MEM, "idm_base");
|
||||
if (!regs) {
|
||||
@@ -141,10 +139,8 @@ static int bgmac_probe(struct platform_d
|
||||
}
|
||||
|
||||
bgmac->plat.idm_base = devm_ioremap_resource(&pdev->dev, regs);
|
||||
- if (IS_ERR(bgmac->plat.idm_base)) {
|
||||
- dev_err(&pdev->dev, "Unable to map idm resource\n");
|
||||
+ if (IS_ERR(bgmac->plat.idm_base))
|
||||
return PTR_ERR(bgmac->plat.idm_base);
|
||||
- }
|
||||
|
||||
bgmac->read = platform_bgmac_read;
|
||||
bgmac->write = platform_bgmac_write;
|
@ -1,28 +0,0 @@
|
||||
From b9f63ae7ba2de2ba19137c5757c0607ce40f3ed5 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Date: Wed, 17 Aug 2016 15:37:14 +0200
|
||||
Subject: [PATCH] net: bgmac: fix reversed check for MII registration error
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
It was failing on successful registration returning meaningless errors.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
Fixes: 55954f3bfdac ("net: ethernet: bgmac: move BCMA MDIO Phy code into a separate file")
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/ethernet/broadcom/bgmac-bcma.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac-bcma.c
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac-bcma.c
|
||||
@@ -159,7 +159,7 @@ static int bgmac_probe(struct bcma_devic
|
||||
|
||||
if (!bgmac_is_bcm4707_family(core)) {
|
||||
mii_bus = bcma_mdio_mii_register(core, bgmac->phyaddr);
|
||||
- if (!IS_ERR(mii_bus)) {
|
||||
+ if (IS_ERR(mii_bus)) {
|
||||
err = PTR_ERR(mii_bus);
|
||||
goto err;
|
||||
}
|
@ -1,161 +0,0 @@
|
||||
From 1cb94db3d1bfe0075bde78fb2989f17e0a8a3936 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Date: Wed, 17 Aug 2016 23:00:30 +0200
|
||||
Subject: [PATCH] net: bgmac: support Ethernet core on BCM53573 SoCs
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
BCM53573 is a new series of Broadcom's SoCs. It's based on ARM and can
|
||||
be found in two packages (versions): BCM53573 and BCM47189. It shares
|
||||
some code with the Northstar family, but also requires some new quirks.
|
||||
|
||||
First of all there can be up to 2 Ethernet cores on this SoC. If that is
|
||||
the case, they are connected to two different switch ports allowing some
|
||||
more complex/optimized setups. It seems the second unit doesn't come
|
||||
fully configured and requires some IRQ quirk.
|
||||
|
||||
Other than that only the first core is connected to the PHY. For the
|
||||
second one we have to register fixed PHY (similarly to the Northstar),
|
||||
otherwise generic PHY driver would get some invalid info.
|
||||
|
||||
This has been successfully tested on Tenda AC9 (BCM47189B0).
|
||||
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/ethernet/broadcom/bgmac-bcma.c | 19 ++++++++++++++++++-
|
||||
drivers/net/ethernet/broadcom/bgmac.c | 25 +++++++++++++++++++++++++
|
||||
drivers/net/ethernet/broadcom/bgmac.h | 19 +++++++++++++++++++
|
||||
include/linux/bcma/bcma.h | 3 +++
|
||||
include/linux/bcma/bcma_regs.h | 1 +
|
||||
5 files changed, 66 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac-bcma.c
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac-bcma.c
|
||||
@@ -92,6 +92,7 @@ MODULE_DEVICE_TABLE(bcma, bgmac_bcma_tbl
|
||||
/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipattach */
|
||||
static int bgmac_probe(struct bcma_device *core)
|
||||
{
|
||||
+ struct bcma_chipinfo *ci = &core->bus->chipinfo;
|
||||
struct ssb_sprom *sprom = &core->bus->sprom;
|
||||
struct mii_bus *mii_bus;
|
||||
struct bgmac *bgmac;
|
||||
@@ -157,7 +158,8 @@ static int bgmac_probe(struct bcma_devic
|
||||
dev_info(bgmac->dev, "Found PHY addr: %d%s\n", bgmac->phyaddr,
|
||||
bgmac->phyaddr == BGMAC_PHY_NOREGS ? " (NOREGS)" : "");
|
||||
|
||||
- if (!bgmac_is_bcm4707_family(core)) {
|
||||
+ if (!bgmac_is_bcm4707_family(core) &&
|
||||
+ !(ci->id == BCMA_CHIP_ID_BCM53573 && core->core_unit == 1)) {
|
||||
mii_bus = bcma_mdio_mii_register(core, bgmac->phyaddr);
|
||||
if (IS_ERR(mii_bus)) {
|
||||
err = PTR_ERR(mii_bus);
|
||||
@@ -230,6 +232,21 @@ static int bgmac_probe(struct bcma_devic
|
||||
bgmac->feature_flags |= BGMAC_FEAT_NO_RESET;
|
||||
bgmac->feature_flags |= BGMAC_FEAT_FORCE_SPEED_2500;
|
||||
break;
|
||||
+ case BCMA_CHIP_ID_BCM53573:
|
||||
+ bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
|
||||
+ bgmac->feature_flags |= BGMAC_FEAT_SET_RXQ_CLK;
|
||||
+ if (ci->pkg == BCMA_PKG_ID_BCM47189)
|
||||
+ bgmac->feature_flags |= BGMAC_FEAT_IOST_ATTACHED;
|
||||
+ if (core->core_unit == 0) {
|
||||
+ bgmac->feature_flags |= BGMAC_FEAT_CC4_IF_SW_TYPE;
|
||||
+ if (ci->pkg == BCMA_PKG_ID_BCM47189)
|
||||
+ bgmac->feature_flags |=
|
||||
+ BGMAC_FEAT_CC4_IF_SW_TYPE_RGMII;
|
||||
+ } else if (core->core_unit == 1) {
|
||||
+ bgmac->feature_flags |= BGMAC_FEAT_IRQ_ID_OOB_6;
|
||||
+ bgmac->feature_flags |= BGMAC_FEAT_CC7_IF_TYPE_RGMII;
|
||||
+ }
|
||||
+ break;
|
||||
default:
|
||||
bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
|
||||
bgmac->feature_flags |= BGMAC_FEAT_SET_RXQ_CLK;
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac.c
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac.c
|
||||
@@ -943,6 +943,27 @@ static void bgmac_chip_reset(struct bgma
|
||||
bgmac_cco_ctl_maskset(bgmac, 1, ~(BGMAC_CHIPCTL_1_IF_TYPE_MASK |
|
||||
BGMAC_CHIPCTL_1_SW_TYPE_MASK),
|
||||
sw_type);
|
||||
+ } else if (bgmac->feature_flags & BGMAC_FEAT_CC4_IF_SW_TYPE) {
|
||||
+ u32 sw_type = BGMAC_CHIPCTL_4_IF_TYPE_MII |
|
||||
+ BGMAC_CHIPCTL_4_SW_TYPE_EPHY;
|
||||
+ u8 et_swtype = 0;
|
||||
+ char buf[4];
|
||||
+
|
||||
+ if (bcm47xx_nvram_getenv("et_swtype", buf, sizeof(buf)) > 0) {
|
||||
+ if (kstrtou8(buf, 0, &et_swtype))
|
||||
+ dev_err(bgmac->dev, "Failed to parse et_swtype (%s)\n",
|
||||
+ buf);
|
||||
+ sw_type = (et_swtype & 0x0f) << 12;
|
||||
+ } else if (bgmac->feature_flags & BGMAC_FEAT_CC4_IF_SW_TYPE_RGMII) {
|
||||
+ sw_type = BGMAC_CHIPCTL_4_IF_TYPE_RGMII |
|
||||
+ BGMAC_CHIPCTL_4_SW_TYPE_RGMII;
|
||||
+ }
|
||||
+ bgmac_cco_ctl_maskset(bgmac, 4, ~(BGMAC_CHIPCTL_4_IF_TYPE_MASK |
|
||||
+ BGMAC_CHIPCTL_4_SW_TYPE_MASK),
|
||||
+ sw_type);
|
||||
+ } else if (bgmac->feature_flags & BGMAC_FEAT_CC7_IF_TYPE_RGMII) {
|
||||
+ bgmac_cco_ctl_maskset(bgmac, 7, ~BGMAC_CHIPCTL_7_IF_TYPE_MASK,
|
||||
+ BGMAC_CHIPCTL_7_IF_TYPE_RGMII);
|
||||
}
|
||||
|
||||
if (iost & BGMAC_BCMA_IOST_ATTACHED && !bgmac->has_robosw)
|
||||
@@ -1486,6 +1507,10 @@ int bgmac_enet_probe(struct bgmac *info)
|
||||
*/
|
||||
bgmac_clk_enable(bgmac, 0);
|
||||
|
||||
+ /* This seems to be fixing IRQ by assigning OOB #6 to the core */
|
||||
+ if (bgmac->feature_flags & BGMAC_FEAT_IRQ_ID_OOB_6)
|
||||
+ bgmac_idm_write(bgmac, BCMA_OOB_SEL_OUT_A30, 0x86);
|
||||
+
|
||||
bgmac_chip_reset(bgmac);
|
||||
|
||||
err = bgmac_dma_alloc(bgmac);
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac.h
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac.h
|
||||
@@ -369,6 +369,21 @@
|
||||
#define BGMAC_CHIPCTL_1_SW_TYPE_RGMII 0x000000C0
|
||||
#define BGMAC_CHIPCTL_1_RXC_DLL_BYPASS 0x00010000
|
||||
|
||||
+#define BGMAC_CHIPCTL_4_IF_TYPE_MASK 0x00003000
|
||||
+#define BGMAC_CHIPCTL_4_IF_TYPE_RMII 0x00000000
|
||||
+#define BGMAC_CHIPCTL_4_IF_TYPE_MII 0x00001000
|
||||
+#define BGMAC_CHIPCTL_4_IF_TYPE_RGMII 0x00002000
|
||||
+#define BGMAC_CHIPCTL_4_SW_TYPE_MASK 0x0000C000
|
||||
+#define BGMAC_CHIPCTL_4_SW_TYPE_EPHY 0x00000000
|
||||
+#define BGMAC_CHIPCTL_4_SW_TYPE_EPHYMII 0x00004000
|
||||
+#define BGMAC_CHIPCTL_4_SW_TYPE_EPHYRMII 0x00008000
|
||||
+#define BGMAC_CHIPCTL_4_SW_TYPE_RGMII 0x0000C000
|
||||
+
|
||||
+#define BGMAC_CHIPCTL_7_IF_TYPE_MASK 0x000000C0
|
||||
+#define BGMAC_CHIPCTL_7_IF_TYPE_RMII 0x00000000
|
||||
+#define BGMAC_CHIPCTL_7_IF_TYPE_MII 0x00000040
|
||||
+#define BGMAC_CHIPCTL_7_IF_TYPE_RGMII 0x00000080
|
||||
+
|
||||
#define BGMAC_WEIGHT 64
|
||||
|
||||
#define ETHER_MAX_LEN 1518
|
||||
@@ -390,6 +405,10 @@
|
||||
#define BGMAC_FEAT_NO_CLR_MIB BIT(13)
|
||||
#define BGMAC_FEAT_FORCE_SPEED_2500 BIT(14)
|
||||
#define BGMAC_FEAT_CMDCFG_SR_REV4 BIT(15)
|
||||
+#define BGMAC_FEAT_IRQ_ID_OOB_6 BIT(16)
|
||||
+#define BGMAC_FEAT_CC4_IF_SW_TYPE BIT(17)
|
||||
+#define BGMAC_FEAT_CC4_IF_SW_TYPE_RGMII BIT(18)
|
||||
+#define BGMAC_FEAT_CC7_IF_TYPE_RGMII BIT(19)
|
||||
|
||||
struct bgmac_slot_info {
|
||||
union {
|
||||
--- a/include/linux/bcma/bcma_regs.h
|
||||
+++ b/include/linux/bcma/bcma_regs.h
|
||||
@@ -23,6 +23,7 @@
|
||||
#define BCMA_CLKCTLST_4328A0_HAVEALP 0x00020000 /* 4328a0 has reversed bits */
|
||||
|
||||
/* Agent registers (common for every core) */
|
||||
+#define BCMA_OOB_SEL_OUT_A30 0x0100
|
||||
#define BCMA_IOCTL 0x0408 /* IO control */
|
||||
#define BCMA_IOCTL_CLK 0x0001
|
||||
#define BCMA_IOCTL_FGC 0x0002
|
@ -1,31 +0,0 @@
|
||||
From e2d8f646c79f26e094bfaf9b21be614d1e148a67 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Date: Wed, 17 Aug 2016 23:11:52 +0200
|
||||
Subject: [PATCH] net: bgmac: make it clear when setting interface type to RMII
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
It doesn't really change anything as BGMAC_CHIPCTL_1_IF_TYPE_RMII is
|
||||
equal to 0. It make code a bit clener, so far when reading it one could
|
||||
think we forgot to set a proper mode. It also keeps this mode code in
|
||||
sync with other ones.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/ethernet/broadcom/bgmac.c | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac.c
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac.c
|
||||
@@ -935,7 +935,8 @@ static void bgmac_chip_reset(struct bgma
|
||||
et_swtype <<= 4;
|
||||
sw_type = et_swtype;
|
||||
} else if (bgmac->feature_flags & BGMAC_FEAT_SW_TYPE_EPHYRMII) {
|
||||
- sw_type = BGMAC_CHIPCTL_1_SW_TYPE_EPHYRMII;
|
||||
+ sw_type = BGMAC_CHIPCTL_1_IF_TYPE_RMII |
|
||||
+ BGMAC_CHIPCTL_1_SW_TYPE_EPHYRMII;
|
||||
} else if (bgmac->feature_flags & BGMAC_FEAT_SW_TYPE_RGMII) {
|
||||
sw_type = BGMAC_CHIPCTL_1_IF_TYPE_RGMII |
|
||||
BGMAC_CHIPCTL_1_SW_TYPE_RGMII;
|
@ -1,33 +0,0 @@
|
||||
From 4af1474e6198b10fee7bb20e81f7e033ad1b586c Mon Sep 17 00:00:00 2001
|
||||
From: Jon Mason <jon.mason@broadcom.com>
|
||||
Date: Wed, 5 Oct 2016 15:36:49 -0400
|
||||
Subject: [PATCH] net: bgmac: Fix errant feature flag check
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
During the conversion to the feature flags, a check against
|
||||
ci->id != BCMA_CHIP_ID_BCM47162
|
||||
became
|
||||
bgmac->feature_flags & BGMAC_FEAT_CLKCTLS
|
||||
instead of
|
||||
!(bgmac->feature_flags & BGMAC_FEAT_CLKCTLS)
|
||||
|
||||
Reported-by: Rafał Miłecki <zajec5@gmail.com>
|
||||
Signed-off-by: Jon Mason <jon.mason@broadcom.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/ethernet/broadcom/bgmac.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac.c
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac.c
|
||||
@@ -1049,7 +1049,7 @@ static void bgmac_enable(struct bgmac *b
|
||||
|
||||
mode = (bgmac_read(bgmac, BGMAC_DEV_STATUS) & BGMAC_DS_MM_MASK) >>
|
||||
BGMAC_DS_MM_SHIFT;
|
||||
- if (bgmac->feature_flags & BGMAC_FEAT_CLKCTLST || mode != 0)
|
||||
+ if (!(bgmac->feature_flags & BGMAC_FEAT_CLKCTLST) || mode != 0)
|
||||
bgmac_set(bgmac, BCMA_CLKCTLST, BCMA_CLKCTLST_FORCEHT);
|
||||
if (bgmac->feature_flags & BGMAC_FEAT_CLKCTLST && mode == 2)
|
||||
bgmac_cco_ctl_maskset(bgmac, 1, ~0,
|
@ -1,25 +0,0 @@
|
||||
From c121f72a66c5f92fbe2fc53baa274eef39875cec Mon Sep 17 00:00:00 2001
|
||||
From: Colin Ian King <colin.king@canonical.com>
|
||||
Date: Mon, 24 Oct 2016 23:46:18 +0100
|
||||
Subject: [PATCH] net: bgmac: fix spelling mistake: "connecton" -> "connection"
|
||||
|
||||
trivial fix to spelling mistake in dev_err message
|
||||
|
||||
Signed-off-by: Colin Ian King <colin.king@canonical.com>
|
||||
Acked-by: Jon Mason <jon.mason@broadcom.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/ethernet/broadcom/bgmac.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac.c
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac.c
|
||||
@@ -1468,7 +1468,7 @@ static int bgmac_phy_connect(struct bgma
|
||||
phy_dev = phy_connect(bgmac->net_dev, bus_id, &bgmac_adjust_link,
|
||||
PHY_INTERFACE_MODE_MII);
|
||||
if (IS_ERR(phy_dev)) {
|
||||
- dev_err(bgmac->dev, "PHY connecton failed\n");
|
||||
+ dev_err(bgmac->dev, "PHY connection failed\n");
|
||||
return PTR_ERR(phy_dev);
|
||||
}
|
||||
|
@ -1,35 +0,0 @@
|
||||
From cdb26d3387f0cdf7b2a2eea581385173547ef21f Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Date: Mon, 7 Nov 2016 13:53:27 +0100
|
||||
Subject: [PATCH] net: bgmac: fix reversed checks for clock control flag
|
||||
|
||||
This fixes regression introduced by patch adding feature flags. It was
|
||||
already reported and patch followed (it got accepted) but it appears it
|
||||
was incorrect. Instead of fixing reversed condition it broke a good one.
|
||||
|
||||
This patch was verified to actually fix SoC hanges caused by bgmac on
|
||||
BCM47186B0.
|
||||
|
||||
Fixes: db791eb2970b ("net: ethernet: bgmac: convert to feature flags")
|
||||
Fixes: 4af1474e6198 ("net: bgmac: Fix errant feature flag check")
|
||||
Cc: Jon Mason <jon.mason@broadcom.com>
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/ethernet/broadcom/bgmac.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac.c
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac.c
|
||||
@@ -1049,9 +1049,9 @@ static void bgmac_enable(struct bgmac *b
|
||||
|
||||
mode = (bgmac_read(bgmac, BGMAC_DEV_STATUS) & BGMAC_DS_MM_MASK) >>
|
||||
BGMAC_DS_MM_SHIFT;
|
||||
- if (!(bgmac->feature_flags & BGMAC_FEAT_CLKCTLST) || mode != 0)
|
||||
+ if (bgmac->feature_flags & BGMAC_FEAT_CLKCTLST || mode != 0)
|
||||
bgmac_set(bgmac, BCMA_CLKCTLST, BCMA_CLKCTLST_FORCEHT);
|
||||
- if (bgmac->feature_flags & BGMAC_FEAT_CLKCTLST && mode == 2)
|
||||
+ if (!(bgmac->feature_flags & BGMAC_FEAT_CLKCTLST) && mode == 2)
|
||||
bgmac_cco_ctl_maskset(bgmac, 1, ~0,
|
||||
BGMAC_CHIPCTL_1_RXC_DLL_BYPASS);
|
||||
|
@ -1,70 +0,0 @@
|
||||
From 40be0dda0725886b623d67868db3219a2e74683b Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Date: Sat, 28 Jan 2017 15:15:42 +0100
|
||||
Subject: [PATCH] net: add devm version of alloc_etherdev_mqs function
|
||||
|
||||
This patch adds devm_alloc_etherdev_mqs function and devm_alloc_etherdev
|
||||
macro. These can be used for simpler netdev allocation without having to
|
||||
care about calling free_netdev.
|
||||
|
||||
Thanks to this change drivers, their error paths and removal paths may
|
||||
get simpler by a bit.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
include/linux/etherdevice.h | 5 +++++
|
||||
net/ethernet/eth.c | 28 ++++++++++++++++++++++++++++
|
||||
2 files changed, 33 insertions(+)
|
||||
|
||||
--- a/include/linux/etherdevice.h
|
||||
+++ b/include/linux/etherdevice.h
|
||||
@@ -51,6 +51,11 @@ struct net_device *alloc_etherdev_mqs(in
|
||||
#define alloc_etherdev(sizeof_priv) alloc_etherdev_mq(sizeof_priv, 1)
|
||||
#define alloc_etherdev_mq(sizeof_priv, count) alloc_etherdev_mqs(sizeof_priv, count, count)
|
||||
|
||||
+struct net_device *devm_alloc_etherdev_mqs(struct device *dev, int sizeof_priv,
|
||||
+ unsigned int txqs,
|
||||
+ unsigned int rxqs);
|
||||
+#define devm_alloc_etherdev(dev, sizeof_priv) devm_alloc_etherdev_mqs(dev, sizeof_priv, 1, 1)
|
||||
+
|
||||
struct sk_buff **eth_gro_receive(struct sk_buff **head,
|
||||
struct sk_buff *skb);
|
||||
int eth_gro_complete(struct sk_buff *skb, int nhoff);
|
||||
--- a/net/ethernet/eth.c
|
||||
+++ b/net/ethernet/eth.c
|
||||
@@ -388,6 +388,34 @@ struct net_device *alloc_etherdev_mqs(in
|
||||
}
|
||||
EXPORT_SYMBOL(alloc_etherdev_mqs);
|
||||
|
||||
+static void devm_free_netdev(struct device *dev, void *res)
|
||||
+{
|
||||
+ free_netdev(*(struct net_device **)res);
|
||||
+}
|
||||
+
|
||||
+struct net_device *devm_alloc_etherdev_mqs(struct device *dev, int sizeof_priv,
|
||||
+ unsigned int txqs, unsigned int rxqs)
|
||||
+{
|
||||
+ struct net_device **dr;
|
||||
+ struct net_device *netdev;
|
||||
+
|
||||
+ dr = devres_alloc(devm_free_netdev, sizeof(*dr), GFP_KERNEL);
|
||||
+ if (!dr)
|
||||
+ return NULL;
|
||||
+
|
||||
+ netdev = alloc_etherdev_mqs(sizeof_priv, txqs, rxqs);
|
||||
+ if (!netdev) {
|
||||
+ devres_free(dr);
|
||||
+ return NULL;
|
||||
+ }
|
||||
+
|
||||
+ *dr = netdev;
|
||||
+ devres_add(dev, dr);
|
||||
+
|
||||
+ return netdev;
|
||||
+}
|
||||
+EXPORT_SYMBOL(devm_alloc_etherdev_mqs);
|
||||
+
|
||||
ssize_t sysfs_format_mac(char *buf, const unsigned char *addr, int len)
|
||||
{
|
||||
return scnprintf(buf, PAGE_SIZE, "%*phC\n", len, addr);
|
@ -1,139 +0,0 @@
|
||||
From 34a5102c3235c470a6c77fba16cb971964d9c136 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Date: Tue, 31 Jan 2017 19:37:54 +0100
|
||||
Subject: [PATCH 1/3] net: bgmac: allocate struct bgmac just once & don't copy
|
||||
it
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
So far were were allocating struct bgmac in 3 places: platform code,
|
||||
bcma code and shared bgmac_enet_probe function. The reason for this was
|
||||
bgmac_enet_probe:
|
||||
1) Requiring early-filled struct bgmac
|
||||
2) Calling alloc_etherdev on its own in order to use netdev_priv later
|
||||
|
||||
This solution got few drawbacks:
|
||||
1) Was duplicating allocating code
|
||||
2) Required copying early-filled struct
|
||||
3) Resulted in platform/bcma code having access only to unused struct
|
||||
|
||||
Solve this situation by simply extracting some probe code into the new
|
||||
bgmac_alloc function.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/ethernet/broadcom/bgmac-bcma.c | 4 +---
|
||||
drivers/net/ethernet/broadcom/bgmac-platform.c | 2 +-
|
||||
drivers/net/ethernet/broadcom/bgmac.c | 25 +++++++++++++++++--------
|
||||
drivers/net/ethernet/broadcom/bgmac.h | 3 ++-
|
||||
4 files changed, 21 insertions(+), 13 deletions(-)
|
||||
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac-bcma.c
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac-bcma.c
|
||||
@@ -99,12 +99,11 @@ static int bgmac_probe(struct bcma_devic
|
||||
u8 *mac;
|
||||
int err;
|
||||
|
||||
- bgmac = kzalloc(sizeof(*bgmac), GFP_KERNEL);
|
||||
+ bgmac = bgmac_alloc(&core->dev);
|
||||
if (!bgmac)
|
||||
return -ENOMEM;
|
||||
|
||||
bgmac->bcma.core = core;
|
||||
- bgmac->dev = &core->dev;
|
||||
bgmac->dma_dev = core->dma_dev;
|
||||
bgmac->irq = core->irq;
|
||||
|
||||
@@ -285,7 +284,6 @@ static int bgmac_probe(struct bcma_devic
|
||||
err1:
|
||||
bcma_mdio_mii_unregister(bgmac->mii_bus);
|
||||
err:
|
||||
- kfree(bgmac);
|
||||
bcma_set_drvdata(core, NULL);
|
||||
|
||||
return err;
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac-platform.c
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac-platform.c
|
||||
@@ -93,7 +93,7 @@ static int bgmac_probe(struct platform_d
|
||||
struct resource *regs;
|
||||
const u8 *mac_addr;
|
||||
|
||||
- bgmac = devm_kzalloc(&pdev->dev, sizeof(*bgmac), GFP_KERNEL);
|
||||
+ bgmac = bgmac_alloc(&pdev->dev);
|
||||
if (!bgmac)
|
||||
return -ENOMEM;
|
||||
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac.c
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac.c
|
||||
@@ -1475,22 +1475,32 @@ static int bgmac_phy_connect(struct bgma
|
||||
return 0;
|
||||
}
|
||||
|
||||
-int bgmac_enet_probe(struct bgmac *info)
|
||||
+struct bgmac *bgmac_alloc(struct device *dev)
|
||||
{
|
||||
struct net_device *net_dev;
|
||||
struct bgmac *bgmac;
|
||||
- int err;
|
||||
|
||||
/* Allocation and references */
|
||||
- net_dev = alloc_etherdev(sizeof(*bgmac));
|
||||
+ net_dev = devm_alloc_etherdev(dev, sizeof(*bgmac));
|
||||
if (!net_dev)
|
||||
- return -ENOMEM;
|
||||
+ return NULL;
|
||||
|
||||
net_dev->netdev_ops = &bgmac_netdev_ops;
|
||||
net_dev->ethtool_ops = &bgmac_ethtool_ops;
|
||||
+
|
||||
bgmac = netdev_priv(net_dev);
|
||||
- memcpy(bgmac, info, sizeof(*bgmac));
|
||||
+ bgmac->dev = dev;
|
||||
bgmac->net_dev = net_dev;
|
||||
+
|
||||
+ return bgmac;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(bgmac_alloc);
|
||||
+
|
||||
+int bgmac_enet_probe(struct bgmac *bgmac)
|
||||
+{
|
||||
+ struct net_device *net_dev = bgmac->net_dev;
|
||||
+ int err;
|
||||
+
|
||||
net_dev->irq = bgmac->irq;
|
||||
SET_NETDEV_DEV(net_dev, bgmac->dev);
|
||||
|
||||
@@ -1517,7 +1527,7 @@ int bgmac_enet_probe(struct bgmac *info)
|
||||
err = bgmac_dma_alloc(bgmac);
|
||||
if (err) {
|
||||
dev_err(bgmac->dev, "Unable to alloc memory for DMA\n");
|
||||
- goto err_netdev_free;
|
||||
+ goto err_out;
|
||||
}
|
||||
|
||||
bgmac->int_mask = BGMAC_IS_ERRMASK | BGMAC_IS_RX | BGMAC_IS_TX_MASK;
|
||||
@@ -1553,8 +1563,7 @@ err_phy_disconnect:
|
||||
phy_disconnect(net_dev->phydev);
|
||||
err_dma_free:
|
||||
bgmac_dma_free(bgmac);
|
||||
-err_netdev_free:
|
||||
- free_netdev(net_dev);
|
||||
+err_out:
|
||||
|
||||
return err;
|
||||
}
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac.h
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac.h
|
||||
@@ -515,7 +515,8 @@ struct bgmac {
|
||||
u32 set);
|
||||
};
|
||||
|
||||
-int bgmac_enet_probe(struct bgmac *info);
|
||||
+struct bgmac *bgmac_alloc(struct device *dev);
|
||||
+int bgmac_enet_probe(struct bgmac *bgmac);
|
||||
void bgmac_enet_remove(struct bgmac *bgmac);
|
||||
|
||||
struct mii_bus *bcma_mdio_mii_register(struct bcma_device *core, u8 phyaddr);
|
@ -1,274 +0,0 @@
|
||||
From aa8863e5d49417094b9457a0d53e8505e95a1863 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Date: Tue, 31 Jan 2017 19:37:55 +0100
|
||||
Subject: [PATCH 2/3] net: bgmac: drop struct bcma_mdio we don't need anymore
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Adding struct bcma_mdio was a workaround for bcma code not having access
|
||||
to the struct bgmac used in the core code. Now we don't duplicate this
|
||||
struct we can just use it internally in bcma code.
|
||||
|
||||
This simplifies code & allows access to all bgmac driver details from
|
||||
all places in bcma code.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/ethernet/broadcom/bgmac-bcma-mdio.c | 98 ++++++++++---------------
|
||||
drivers/net/ethernet/broadcom/bgmac-bcma.c | 2 +-
|
||||
drivers/net/ethernet/broadcom/bgmac.h | 2 +-
|
||||
3 files changed, 42 insertions(+), 60 deletions(-)
|
||||
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac-bcma-mdio.c
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac-bcma-mdio.c
|
||||
@@ -12,11 +12,6 @@
|
||||
#include <linux/brcmphy.h>
|
||||
#include "bgmac.h"
|
||||
|
||||
-struct bcma_mdio {
|
||||
- struct bcma_device *core;
|
||||
- u8 phyaddr;
|
||||
-};
|
||||
-
|
||||
static bool bcma_mdio_wait_value(struct bcma_device *core, u16 reg, u32 mask,
|
||||
u32 value, int timeout)
|
||||
{
|
||||
@@ -37,7 +32,7 @@ static bool bcma_mdio_wait_value(struct
|
||||
* PHY ops
|
||||
**************************************************/
|
||||
|
||||
-static u16 bcma_mdio_phy_read(struct bcma_mdio *bcma_mdio, u8 phyaddr, u8 reg)
|
||||
+static u16 bcma_mdio_phy_read(struct bgmac *bgmac, u8 phyaddr, u8 reg)
|
||||
{
|
||||
struct bcma_device *core;
|
||||
u16 phy_access_addr;
|
||||
@@ -56,12 +51,12 @@ static u16 bcma_mdio_phy_read(struct bcm
|
||||
BUILD_BUG_ON(BGMAC_PC_MCT_SHIFT != BCMA_GMAC_CMN_PC_MCT_SHIFT);
|
||||
BUILD_BUG_ON(BGMAC_PC_MTE != BCMA_GMAC_CMN_PC_MTE);
|
||||
|
||||
- if (bcma_mdio->core->id.id == BCMA_CORE_4706_MAC_GBIT) {
|
||||
- core = bcma_mdio->core->bus->drv_gmac_cmn.core;
|
||||
+ if (bgmac->bcma.core->id.id == BCMA_CORE_4706_MAC_GBIT) {
|
||||
+ core = bgmac->bcma.core->bus->drv_gmac_cmn.core;
|
||||
phy_access_addr = BCMA_GMAC_CMN_PHY_ACCESS;
|
||||
phy_ctl_addr = BCMA_GMAC_CMN_PHY_CTL;
|
||||
} else {
|
||||
- core = bcma_mdio->core;
|
||||
+ core = bgmac->bcma.core;
|
||||
phy_access_addr = BGMAC_PHY_ACCESS;
|
||||
phy_ctl_addr = BGMAC_PHY_CNTL;
|
||||
}
|
||||
@@ -87,7 +82,7 @@ static u16 bcma_mdio_phy_read(struct bcm
|
||||
}
|
||||
|
||||
/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphywr */
|
||||
-static int bcma_mdio_phy_write(struct bcma_mdio *bcma_mdio, u8 phyaddr, u8 reg,
|
||||
+static int bcma_mdio_phy_write(struct bgmac *bgmac, u8 phyaddr, u8 reg,
|
||||
u16 value)
|
||||
{
|
||||
struct bcma_device *core;
|
||||
@@ -95,12 +90,12 @@ static int bcma_mdio_phy_write(struct bc
|
||||
u16 phy_ctl_addr;
|
||||
u32 tmp;
|
||||
|
||||
- if (bcma_mdio->core->id.id == BCMA_CORE_4706_MAC_GBIT) {
|
||||
- core = bcma_mdio->core->bus->drv_gmac_cmn.core;
|
||||
+ if (bgmac->bcma.core->id.id == BCMA_CORE_4706_MAC_GBIT) {
|
||||
+ core = bgmac->bcma.core->bus->drv_gmac_cmn.core;
|
||||
phy_access_addr = BCMA_GMAC_CMN_PHY_ACCESS;
|
||||
phy_ctl_addr = BCMA_GMAC_CMN_PHY_CTL;
|
||||
} else {
|
||||
- core = bcma_mdio->core;
|
||||
+ core = bgmac->bcma.core;
|
||||
phy_access_addr = BGMAC_PHY_ACCESS;
|
||||
phy_ctl_addr = BGMAC_PHY_CNTL;
|
||||
}
|
||||
@@ -110,8 +105,8 @@ static int bcma_mdio_phy_write(struct bc
|
||||
tmp |= phyaddr;
|
||||
bcma_write32(core, phy_ctl_addr, tmp);
|
||||
|
||||
- bcma_write32(bcma_mdio->core, BGMAC_INT_STATUS, BGMAC_IS_MDIO);
|
||||
- if (bcma_read32(bcma_mdio->core, BGMAC_INT_STATUS) & BGMAC_IS_MDIO)
|
||||
+ bcma_write32(bgmac->bcma.core, BGMAC_INT_STATUS, BGMAC_IS_MDIO);
|
||||
+ if (bcma_read32(bgmac->bcma.core, BGMAC_INT_STATUS) & BGMAC_IS_MDIO)
|
||||
dev_warn(&core->dev, "Error setting MDIO int\n");
|
||||
|
||||
tmp = BGMAC_PA_START;
|
||||
@@ -132,39 +127,39 @@ static int bcma_mdio_phy_write(struct bc
|
||||
}
|
||||
|
||||
/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphyinit */
|
||||
-static void bcma_mdio_phy_init(struct bcma_mdio *bcma_mdio)
|
||||
+static void bcma_mdio_phy_init(struct bgmac *bgmac)
|
||||
{
|
||||
- struct bcma_chipinfo *ci = &bcma_mdio->core->bus->chipinfo;
|
||||
+ struct bcma_chipinfo *ci = &bgmac->bcma.core->bus->chipinfo;
|
||||
u8 i;
|
||||
|
||||
if (ci->id == BCMA_CHIP_ID_BCM5356) {
|
||||
for (i = 0; i < 5; i++) {
|
||||
- bcma_mdio_phy_write(bcma_mdio, i, 0x1f, 0x008b);
|
||||
- bcma_mdio_phy_write(bcma_mdio, i, 0x15, 0x0100);
|
||||
- bcma_mdio_phy_write(bcma_mdio, i, 0x1f, 0x000f);
|
||||
- bcma_mdio_phy_write(bcma_mdio, i, 0x12, 0x2aaa);
|
||||
- bcma_mdio_phy_write(bcma_mdio, i, 0x1f, 0x000b);
|
||||
+ bcma_mdio_phy_write(bgmac, i, 0x1f, 0x008b);
|
||||
+ bcma_mdio_phy_write(bgmac, i, 0x15, 0x0100);
|
||||
+ bcma_mdio_phy_write(bgmac, i, 0x1f, 0x000f);
|
||||
+ bcma_mdio_phy_write(bgmac, i, 0x12, 0x2aaa);
|
||||
+ bcma_mdio_phy_write(bgmac, i, 0x1f, 0x000b);
|
||||
}
|
||||
}
|
||||
if ((ci->id == BCMA_CHIP_ID_BCM5357 && ci->pkg != 10) ||
|
||||
(ci->id == BCMA_CHIP_ID_BCM4749 && ci->pkg != 10) ||
|
||||
(ci->id == BCMA_CHIP_ID_BCM53572 && ci->pkg != 9)) {
|
||||
- struct bcma_drv_cc *cc = &bcma_mdio->core->bus->drv_cc;
|
||||
+ struct bcma_drv_cc *cc = &bgmac->bcma.core->bus->drv_cc;
|
||||
|
||||
bcma_chipco_chipctl_maskset(cc, 2, ~0xc0000000, 0);
|
||||
bcma_chipco_chipctl_maskset(cc, 4, ~0x80000000, 0);
|
||||
for (i = 0; i < 5; i++) {
|
||||
- bcma_mdio_phy_write(bcma_mdio, i, 0x1f, 0x000f);
|
||||
- bcma_mdio_phy_write(bcma_mdio, i, 0x16, 0x5284);
|
||||
- bcma_mdio_phy_write(bcma_mdio, i, 0x1f, 0x000b);
|
||||
- bcma_mdio_phy_write(bcma_mdio, i, 0x17, 0x0010);
|
||||
- bcma_mdio_phy_write(bcma_mdio, i, 0x1f, 0x000f);
|
||||
- bcma_mdio_phy_write(bcma_mdio, i, 0x16, 0x5296);
|
||||
- bcma_mdio_phy_write(bcma_mdio, i, 0x17, 0x1073);
|
||||
- bcma_mdio_phy_write(bcma_mdio, i, 0x17, 0x9073);
|
||||
- bcma_mdio_phy_write(bcma_mdio, i, 0x16, 0x52b6);
|
||||
- bcma_mdio_phy_write(bcma_mdio, i, 0x17, 0x9273);
|
||||
- bcma_mdio_phy_write(bcma_mdio, i, 0x1f, 0x000b);
|
||||
+ bcma_mdio_phy_write(bgmac, i, 0x1f, 0x000f);
|
||||
+ bcma_mdio_phy_write(bgmac, i, 0x16, 0x5284);
|
||||
+ bcma_mdio_phy_write(bgmac, i, 0x1f, 0x000b);
|
||||
+ bcma_mdio_phy_write(bgmac, i, 0x17, 0x0010);
|
||||
+ bcma_mdio_phy_write(bgmac, i, 0x1f, 0x000f);
|
||||
+ bcma_mdio_phy_write(bgmac, i, 0x16, 0x5296);
|
||||
+ bcma_mdio_phy_write(bgmac, i, 0x17, 0x1073);
|
||||
+ bcma_mdio_phy_write(bgmac, i, 0x17, 0x9073);
|
||||
+ bcma_mdio_phy_write(bgmac, i, 0x16, 0x52b6);
|
||||
+ bcma_mdio_phy_write(bgmac, i, 0x17, 0x9273);
|
||||
+ bcma_mdio_phy_write(bgmac, i, 0x1f, 0x000b);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -172,17 +167,17 @@ static void bcma_mdio_phy_init(struct bc
|
||||
/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphyreset */
|
||||
static int bcma_mdio_phy_reset(struct mii_bus *bus)
|
||||
{
|
||||
- struct bcma_mdio *bcma_mdio = bus->priv;
|
||||
- u8 phyaddr = bcma_mdio->phyaddr;
|
||||
+ struct bgmac *bgmac = bus->priv;
|
||||
+ u8 phyaddr = bgmac->phyaddr;
|
||||
|
||||
- if (bcma_mdio->phyaddr == BGMAC_PHY_NOREGS)
|
||||
+ if (phyaddr == BGMAC_PHY_NOREGS)
|
||||
return 0;
|
||||
|
||||
- bcma_mdio_phy_write(bcma_mdio, phyaddr, MII_BMCR, BMCR_RESET);
|
||||
+ bcma_mdio_phy_write(bgmac, phyaddr, MII_BMCR, BMCR_RESET);
|
||||
udelay(100);
|
||||
- if (bcma_mdio_phy_read(bcma_mdio, phyaddr, MII_BMCR) & BMCR_RESET)
|
||||
- dev_err(&bcma_mdio->core->dev, "PHY reset failed\n");
|
||||
- bcma_mdio_phy_init(bcma_mdio);
|
||||
+ if (bcma_mdio_phy_read(bgmac, phyaddr, MII_BMCR) & BMCR_RESET)
|
||||
+ dev_err(bgmac->dev, "PHY reset failed\n");
|
||||
+ bcma_mdio_phy_init(bgmac);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -202,16 +197,12 @@ static int bcma_mdio_mii_write(struct mi
|
||||
return bcma_mdio_phy_write(bus->priv, mii_id, regnum, value);
|
||||
}
|
||||
|
||||
-struct mii_bus *bcma_mdio_mii_register(struct bcma_device *core, u8 phyaddr)
|
||||
+struct mii_bus *bcma_mdio_mii_register(struct bgmac *bgmac)
|
||||
{
|
||||
- struct bcma_mdio *bcma_mdio;
|
||||
+ struct bcma_device *core = bgmac->bcma.core;
|
||||
struct mii_bus *mii_bus;
|
||||
int i, err;
|
||||
|
||||
- bcma_mdio = kzalloc(sizeof(*bcma_mdio), GFP_KERNEL);
|
||||
- if (!bcma_mdio)
|
||||
- return ERR_PTR(-ENOMEM);
|
||||
-
|
||||
mii_bus = mdiobus_alloc();
|
||||
if (!mii_bus) {
|
||||
err = -ENOMEM;
|
||||
@@ -221,12 +212,12 @@ struct mii_bus *bcma_mdio_mii_register(s
|
||||
mii_bus->name = "bcma_mdio mii bus";
|
||||
sprintf(mii_bus->id, "%s-%d-%d", "bcma_mdio", core->bus->num,
|
||||
core->core_unit);
|
||||
- mii_bus->priv = bcma_mdio;
|
||||
+ mii_bus->priv = bgmac;
|
||||
mii_bus->read = bcma_mdio_mii_read;
|
||||
mii_bus->write = bcma_mdio_mii_write;
|
||||
mii_bus->reset = bcma_mdio_phy_reset;
|
||||
mii_bus->parent = &core->dev;
|
||||
- mii_bus->phy_mask = ~(1 << phyaddr);
|
||||
+ mii_bus->phy_mask = ~(1 << bgmac->phyaddr);
|
||||
|
||||
mii_bus->irq = kmalloc_array(PHY_MAX_ADDR, sizeof(int), GFP_KERNEL);
|
||||
if (!mii_bus->irq) {
|
||||
@@ -236,9 +227,6 @@ struct mii_bus *bcma_mdio_mii_register(s
|
||||
for (i = 0; i < PHY_MAX_ADDR; i++)
|
||||
mii_bus->irq[i] = PHY_POLL;
|
||||
|
||||
- bcma_mdio->core = core;
|
||||
- bcma_mdio->phyaddr = phyaddr;
|
||||
-
|
||||
err = mdiobus_register(mii_bus);
|
||||
if (err) {
|
||||
dev_err(&core->dev, "Registration of mii bus failed\n");
|
||||
@@ -252,24 +240,18 @@ err_free_irq:
|
||||
err_free_bus:
|
||||
mdiobus_free(mii_bus);
|
||||
err:
|
||||
- kfree(bcma_mdio);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bcma_mdio_mii_register);
|
||||
|
||||
void bcma_mdio_mii_unregister(struct mii_bus *mii_bus)
|
||||
{
|
||||
- struct bcma_mdio *bcma_mdio;
|
||||
-
|
||||
if (!mii_bus)
|
||||
return;
|
||||
|
||||
- bcma_mdio = mii_bus->priv;
|
||||
-
|
||||
mdiobus_unregister(mii_bus);
|
||||
kfree(mii_bus->irq);
|
||||
mdiobus_free(mii_bus);
|
||||
- kfree(bcma_mdio);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bcma_mdio_mii_unregister);
|
||||
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac-bcma.c
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac-bcma.c
|
||||
@@ -159,7 +159,7 @@ static int bgmac_probe(struct bcma_devic
|
||||
|
||||
if (!bgmac_is_bcm4707_family(core) &&
|
||||
!(ci->id == BCMA_CHIP_ID_BCM53573 && core->core_unit == 1)) {
|
||||
- mii_bus = bcma_mdio_mii_register(core, bgmac->phyaddr);
|
||||
+ mii_bus = bcma_mdio_mii_register(bgmac);
|
||||
if (IS_ERR(mii_bus)) {
|
||||
err = PTR_ERR(mii_bus);
|
||||
goto err;
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac.h
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac.h
|
||||
@@ -519,7 +519,7 @@ struct bgmac *bgmac_alloc(struct device
|
||||
int bgmac_enet_probe(struct bgmac *bgmac);
|
||||
void bgmac_enet_remove(struct bgmac *bgmac);
|
||||
|
||||
-struct mii_bus *bcma_mdio_mii_register(struct bcma_device *core, u8 phyaddr);
|
||||
+struct mii_bus *bcma_mdio_mii_register(struct bgmac *bgmac);
|
||||
void bcma_mdio_mii_unregister(struct mii_bus *mii_bus);
|
||||
|
||||
static inline u32 bgmac_read(struct bgmac *bgmac, u16 offset)
|
@ -1,53 +0,0 @@
|
||||
From 8e6f31baba7e2c13ab7e954fe6179420a7545a8b Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Date: Tue, 31 Jan 2017 19:37:56 +0100
|
||||
Subject: [PATCH 3/3] net: bgmac: use PHY subsystem for initializing PHY
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
This adds support for using bgmac with PHYs supported by standalone PHY
|
||||
drivers. Having any PHY initialization in bgmac is hacky and shouldn't
|
||||
be extended but rather removed if anyone has hardware to test it.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/ethernet/broadcom/bgmac-bcma-mdio.c | 10 ++++++++++
|
||||
1 file changed, 10 insertions(+)
|
||||
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac-bcma-mdio.c
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac-bcma-mdio.c
|
||||
@@ -132,6 +132,10 @@ static void bcma_mdio_phy_init(struct bg
|
||||
struct bcma_chipinfo *ci = &bgmac->bcma.core->bus->chipinfo;
|
||||
u8 i;
|
||||
|
||||
+ /* For some legacy hardware we do chipset-based PHY initialization here
|
||||
+ * without even detecting PHY ID. It's hacky and should be cleaned as
|
||||
+ * soon as someone can test it.
|
||||
+ */
|
||||
if (ci->id == BCMA_CHIP_ID_BCM5356) {
|
||||
for (i = 0; i < 5; i++) {
|
||||
bcma_mdio_phy_write(bgmac, i, 0x1f, 0x008b);
|
||||
@@ -140,6 +144,7 @@ static void bcma_mdio_phy_init(struct bg
|
||||
bcma_mdio_phy_write(bgmac, i, 0x12, 0x2aaa);
|
||||
bcma_mdio_phy_write(bgmac, i, 0x1f, 0x000b);
|
||||
}
|
||||
+ return;
|
||||
}
|
||||
if ((ci->id == BCMA_CHIP_ID_BCM5357 && ci->pkg != 10) ||
|
||||
(ci->id == BCMA_CHIP_ID_BCM4749 && ci->pkg != 10) ||
|
||||
@@ -161,7 +166,12 @@ static void bcma_mdio_phy_init(struct bg
|
||||
bcma_mdio_phy_write(bgmac, i, 0x17, 0x9273);
|
||||
bcma_mdio_phy_write(bgmac, i, 0x1f, 0x000b);
|
||||
}
|
||||
+ return;
|
||||
}
|
||||
+
|
||||
+ /* For all other hw do initialization using PHY subsystem. */
|
||||
+ if (bgmac->net_dev && bgmac->net_dev->phydev)
|
||||
+ phy_init_hw(bgmac->net_dev->phydev);
|
||||
}
|
||||
|
||||
/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphyreset */
|
@ -1,50 +0,0 @@
|
||||
From 12acd136913ccdf394eeb2bc8686ff5505368119 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Date: Thu, 12 Oct 2017 10:21:26 +0200
|
||||
Subject: [PATCH] net: bgmac: enable master mode for BCM54210E and B50212E PHYs
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
There are 4 very similar PHYs:
|
||||
0x600d84a1: BCM54210E (rev B0)
|
||||
0x600d84a2: BCM54210E (rev B1)
|
||||
0x600d84a5: B50212E (rev B0)
|
||||
0x600d84a6: B50212E (rev B1)
|
||||
that need setting master mode manually. It's because they run in slave
|
||||
mode by default with Automatic Slave/Master configuration disabled which
|
||||
can lead to unreliable connection with massive ping loss.
|
||||
|
||||
So far it was reported for a board with BCM47189 SoC and B50212E B1 PHY
|
||||
connected to the bgmac supported ethernet device. Telling PHY driver to
|
||||
setup PHY properly solves this issue.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/ethernet/broadcom/bgmac-bcma.c | 8 +++++++-
|
||||
1 file changed, 7 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac-bcma.c
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac-bcma.c
|
||||
@@ -159,13 +159,19 @@ static int bgmac_probe(struct bcma_devic
|
||||
|
||||
if (!bgmac_is_bcm4707_family(core) &&
|
||||
!(ci->id == BCMA_CHIP_ID_BCM53573 && core->core_unit == 1)) {
|
||||
+ struct phy_device *phydev;
|
||||
+
|
||||
mii_bus = bcma_mdio_mii_register(bgmac);
|
||||
if (IS_ERR(mii_bus)) {
|
||||
err = PTR_ERR(mii_bus);
|
||||
goto err;
|
||||
}
|
||||
-
|
||||
bgmac->mii_bus = mii_bus;
|
||||
+
|
||||
+ phydev = bgmac->mii_bus->phy_map[bgmac->phyaddr];
|
||||
+ if (ci->id == BCMA_CHIP_ID_BCM53573 && phydev &&
|
||||
+ (phydev->drv->phy_id & phydev->drv->phy_id_mask) == PHY_ID_BCM54210E)
|
||||
+ phydev->dev_flags |= PHY_BRCM_EN_MASTER_MODE;
|
||||
}
|
||||
|
||||
if (core->bus->hosttype == BCMA_HOSTTYPE_PCI) {
|
@ -1,537 +0,0 @@
|
||||
From 0a63ab263725c427051a8bbaa0732b749627da27 Mon Sep 17 00:00:00 2001
|
||||
From: John Crispin <blogic@openwrt.org>
|
||||
Date: Thu, 7 Aug 2014 18:15:36 +0200
|
||||
Subject: [PATCH 23/36] NET: PHY: adds driver for lantiq PHY11G
|
||||
|
||||
Signed-off-by: John Crispin <blogic@openwrt.org>
|
||||
---
|
||||
drivers/net/phy/Kconfig | 5 +
|
||||
drivers/net/phy/Makefile | 1 +
|
||||
drivers/net/phy/lantiq.c | 231 ++++++++++++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 237 insertions(+)
|
||||
create mode 100644 drivers/net/phy/lantiq.c
|
||||
|
||||
--- a/drivers/net/phy/Kconfig
|
||||
+++ b/drivers/net/phy/Kconfig
|
||||
@@ -156,6 +156,11 @@ config MICROCHIP_PHY
|
||||
help
|
||||
Supports the LAN88XX PHYs.
|
||||
|
||||
+config LANTIQ_PHY
|
||||
+ tristate "Driver for Lantiq PHYs"
|
||||
+ ---help---
|
||||
+ Supports the 11G and 22F PHYs.
|
||||
+
|
||||
config FIXED_PHY
|
||||
tristate "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
|
||||
depends on PHYLIB
|
||||
--- a/drivers/net/phy/Makefile
|
||||
+++ b/drivers/net/phy/Makefile
|
||||
@@ -30,6 +30,7 @@ obj-$(CONFIG_DP83848_PHY) += dp83848.o
|
||||
obj-$(CONFIG_DP83867_PHY) += dp83867.o
|
||||
obj-$(CONFIG_STE10XP) += ste10Xp.o
|
||||
obj-$(CONFIG_MICREL_PHY) += micrel.o
|
||||
+obj-$(CONFIG_LANTIQ_PHY) += lantiq.o
|
||||
obj-$(CONFIG_MDIO_OCTEON) += mdio-octeon.o
|
||||
obj-$(CONFIG_MICREL_KS8995MA) += spi_ks8995.o
|
||||
obj-$(CONFIG_AT803X_PHY) += at803x.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/net/phy/lantiq.c
|
||||
@@ -0,0 +1,278 @@
|
||||
+/*
|
||||
+ * This program is free software; you can redistribute it and/or modify
|
||||
+ * it under the terms of the GNU General Public License as published by
|
||||
+ * the Free Software Foundation; either version 2 of the License, or
|
||||
+ * (at your option) any later version.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful,
|
||||
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
+ * GNU General Public License for more details.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU General Public License
|
||||
+ * along with this program; if not, write to the Free Software
|
||||
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
|
||||
+ *
|
||||
+ * Copyright (C) 2012 Daniel Schwierzeck <daniel.schwierzeck@googlemail.com>
|
||||
+ */
|
||||
+
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/phy.h>
|
||||
+#include <linux/of.h>
|
||||
+
|
||||
+#define MII_MMDCTRL 0x0d
|
||||
+#define MII_MMDDATA 0x0e
|
||||
+
|
||||
+#define MII_VR9_11G_IMASK 0x19 /* interrupt mask */
|
||||
+#define MII_VR9_11G_ISTAT 0x1a /* interrupt status */
|
||||
+
|
||||
+#define INT_VR9_11G_WOL BIT(15) /* Wake-On-LAN */
|
||||
+#define INT_VR9_11G_ANE BIT(11) /* Auto-Neg error */
|
||||
+#define INT_VR9_11G_ANC BIT(10) /* Auto-Neg complete */
|
||||
+#define INT_VR9_11G_ADSC BIT(5) /* Link auto-downspeed detect */
|
||||
+#define INT_VR9_11G_DXMC BIT(2) /* Duplex mode change */
|
||||
+#define INT_VR9_11G_LSPC BIT(1) /* Link speed change */
|
||||
+#define INT_VR9_11G_LSTC BIT(0) /* Link state change */
|
||||
+#define INT_VR9_11G_MASK (INT_VR9_11G_LSTC | INT_VR9_11G_ADSC)
|
||||
+
|
||||
+#define ADVERTISED_MPD BIT(10) /* Multi-port device */
|
||||
+
|
||||
+#define MMD_DEVAD 0x1f
|
||||
+#define MMD_ACTYPE_SHIFT 14
|
||||
+#define MMD_ACTYPE_ADDRESS (0 << MMD_ACTYPE_SHIFT)
|
||||
+#define MMD_ACTYPE_DATA (1 << MMD_ACTYPE_SHIFT)
|
||||
+#define MMD_ACTYPE_DATA_PI (2 << MMD_ACTYPE_SHIFT)
|
||||
+#define MMD_ACTYPE_DATA_PIWR (3 << MMD_ACTYPE_SHIFT)
|
||||
+
|
||||
+static __maybe_unused int vr9_gphy_mmd_read(struct phy_device *phydev,
|
||||
+ u16 regnum)
|
||||
+{
|
||||
+ phy_write(phydev, MII_MMDCTRL, MMD_ACTYPE_ADDRESS | MMD_DEVAD);
|
||||
+ phy_write(phydev, MII_MMDDATA, regnum);
|
||||
+ phy_write(phydev, MII_MMDCTRL, MMD_ACTYPE_DATA | MMD_DEVAD);
|
||||
+
|
||||
+ return phy_read(phydev, MII_MMDDATA);
|
||||
+}
|
||||
+
|
||||
+static __maybe_unused int vr9_gphy_mmd_write(struct phy_device *phydev,
|
||||
+ u16 regnum, u16 val)
|
||||
+{
|
||||
+ phy_write(phydev, MII_MMDCTRL, MMD_ACTYPE_ADDRESS | MMD_DEVAD);
|
||||
+ phy_write(phydev, MII_MMDDATA, regnum);
|
||||
+ phy_write(phydev, MII_MMDCTRL, MMD_ACTYPE_DATA | MMD_DEVAD);
|
||||
+ phy_write(phydev, MII_MMDDATA, val);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#if IS_ENABLED(CONFIG_OF_MDIO)
|
||||
+static int vr9_gphy_of_reg_init(struct phy_device *phydev)
|
||||
+{
|
||||
+ u32 tmp;
|
||||
+
|
||||
+ /* store the led values if one was passed by the devicetree */
|
||||
+ if (!of_property_read_u32(phydev->dev.of_node, "lantiq,ledch", &tmp))
|
||||
+ vr9_gphy_mmd_write(phydev, 0x1e0, tmp);
|
||||
+
|
||||
+ if (!of_property_read_u32(phydev->dev.of_node, "lantiq,ledcl", &tmp))
|
||||
+ vr9_gphy_mmd_write(phydev, 0x1e1, tmp);
|
||||
+
|
||||
+ if (!of_property_read_u32(phydev->dev.of_node, "lantiq,led0h", &tmp))
|
||||
+ vr9_gphy_mmd_write(phydev, 0x1e2, tmp);
|
||||
+
|
||||
+ if (!of_property_read_u32(phydev->dev.of_node, "lantiq,led0l", &tmp))
|
||||
+ vr9_gphy_mmd_write(phydev, 0x1e3, tmp);
|
||||
+
|
||||
+ if (!of_property_read_u32(phydev->dev.of_node, "lantiq,led1h", &tmp))
|
||||
+ vr9_gphy_mmd_write(phydev, 0x1e4, tmp);
|
||||
+
|
||||
+ if (!of_property_read_u32(phydev->dev.of_node, "lantiq,led1l", &tmp))
|
||||
+ vr9_gphy_mmd_write(phydev, 0x1e5, tmp);
|
||||
+ if (!of_property_read_u32(phydev->dev.of_node, "lantiq,led2h", &tmp))
|
||||
+ vr9_gphy_mmd_write(phydev, 0x1e6, tmp);
|
||||
+
|
||||
+ if (!of_property_read_u32(phydev->dev.of_node, "lantiq,led2l", &tmp))
|
||||
+ vr9_gphy_mmd_write(phydev, 0x1e7, tmp);
|
||||
+
|
||||
+ if (!of_property_read_u32(phydev->dev.of_node, "lantiq,led3h", &tmp))
|
||||
+ vr9_gphy_mmd_write(phydev, 0x1e8, tmp);
|
||||
+
|
||||
+ if (!of_property_read_u32(phydev->dev.of_node, "lantiq,led3l", &tmp))
|
||||
+ vr9_gphy_mmd_write(phydev, 0x1e9, tmp);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+#else
|
||||
+static int vr9_gphy_of_reg_init(struct phy_device *phydev)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+#endif /* CONFIG_OF_MDIO */
|
||||
+
|
||||
+static int vr9_gphy_config_init(struct phy_device *phydev)
|
||||
+{
|
||||
+ int err;
|
||||
+
|
||||
+ dev_dbg(&phydev->dev, "%s\n", __func__);
|
||||
+
|
||||
+ /* Mask all interrupts */
|
||||
+ err = phy_write(phydev, MII_VR9_11G_IMASK, 0);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ /* Clear all pending interrupts */
|
||||
+ phy_read(phydev, MII_VR9_11G_ISTAT);
|
||||
+
|
||||
+ vr9_gphy_mmd_write(phydev, 0x1e0, 0xc0);
|
||||
+ vr9_gphy_mmd_write(phydev, 0x1e1, 0x00);
|
||||
+ vr9_gphy_mmd_write(phydev, 0x1e2, 0x70);
|
||||
+ vr9_gphy_mmd_write(phydev, 0x1e3, 0x03);
|
||||
+ vr9_gphy_mmd_write(phydev, 0x1e4, 0x70);
|
||||
+ vr9_gphy_mmd_write(phydev, 0x1e5, 0x03);
|
||||
+ vr9_gphy_mmd_write(phydev, 0x1e6, 0x70);
|
||||
+ vr9_gphy_mmd_write(phydev, 0x1e7, 0x03);
|
||||
+ vr9_gphy_mmd_write(phydev, 0x1e8, 0x70);
|
||||
+ vr9_gphy_mmd_write(phydev, 0x1e9, 0x03);
|
||||
+
|
||||
+ vr9_gphy_of_reg_init(phydev);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int vr9_gphy_config_aneg(struct phy_device *phydev)
|
||||
+{
|
||||
+ int reg, err;
|
||||
+
|
||||
+ /* Advertise as multi-port device */
|
||||
+ reg = phy_read(phydev, MII_CTRL1000);
|
||||
+ reg |= ADVERTISED_MPD;
|
||||
+ err = phy_write(phydev, MII_CTRL1000, reg);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ return genphy_config_aneg(phydev);
|
||||
+}
|
||||
+
|
||||
+static int vr9_gphy_ack_interrupt(struct phy_device *phydev)
|
||||
+{
|
||||
+ int reg;
|
||||
+
|
||||
+ /*
|
||||
+ * Possible IRQ numbers:
|
||||
+ * - IM3_IRL18 for GPHY0
|
||||
+ * - IM3_IRL17 for GPHY1
|
||||
+ *
|
||||
+ * Due to a silicon bug IRQ lines are not really independent from
|
||||
+ * each other. Sometimes the two lines are driven at the same time
|
||||
+ * if only one GPHY core raises the interrupt.
|
||||
+ */
|
||||
+
|
||||
+ reg = phy_read(phydev, MII_VR9_11G_ISTAT);
|
||||
+
|
||||
+ return (reg < 0) ? reg : 0;
|
||||
+}
|
||||
+
|
||||
+static int vr9_gphy_did_interrupt(struct phy_device *phydev)
|
||||
+{
|
||||
+ int reg;
|
||||
+
|
||||
+ reg = phy_read(phydev, MII_VR9_11G_ISTAT);
|
||||
+
|
||||
+ return reg > 0;
|
||||
+}
|
||||
+
|
||||
+static int vr9_gphy_config_intr(struct phy_device *phydev)
|
||||
+{
|
||||
+ int err;
|
||||
+
|
||||
+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
|
||||
+ err = phy_write(phydev, MII_VR9_11G_IMASK, INT_VR9_11G_MASK);
|
||||
+ else
|
||||
+ err = phy_write(phydev, MII_VR9_11G_IMASK, 0);
|
||||
+
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+static struct phy_driver lantiq_phy[] = {
|
||||
+ {
|
||||
+ .phy_id = 0xd565a400,
|
||||
+ .phy_id_mask = 0xfffffff8,
|
||||
+ .name = "Lantiq XWAY PEF7071",
|
||||
+ .features = (PHY_GBIT_FEATURES | SUPPORTED_Pause),
|
||||
+ .flags = 0, /*PHY_HAS_INTERRUPT,*/
|
||||
+ .config_init = vr9_gphy_config_init,
|
||||
+ .config_aneg = vr9_gphy_config_aneg,
|
||||
+ .read_status = genphy_read_status,
|
||||
+ .ack_interrupt = vr9_gphy_ack_interrupt,
|
||||
+ .did_interrupt = vr9_gphy_did_interrupt,
|
||||
+ .config_intr = vr9_gphy_config_intr,
|
||||
+ .driver = { .owner = THIS_MODULE },
|
||||
+ }, {
|
||||
+ .phy_id = 0x030260D0,
|
||||
+ .phy_id_mask = 0xfffffff0,
|
||||
+ .name = "Lantiq XWAY VR9 GPHY 11G v1.3",
|
||||
+ .features = (PHY_GBIT_FEATURES | SUPPORTED_Pause),
|
||||
+ .flags = 0, /*PHY_HAS_INTERRUPT,*/
|
||||
+ .config_init = vr9_gphy_config_init,
|
||||
+ .config_aneg = vr9_gphy_config_aneg,
|
||||
+ .read_status = genphy_read_status,
|
||||
+ .ack_interrupt = vr9_gphy_ack_interrupt,
|
||||
+ .did_interrupt = vr9_gphy_did_interrupt,
|
||||
+ .config_intr = vr9_gphy_config_intr,
|
||||
+ .driver = { .owner = THIS_MODULE },
|
||||
+ }, {
|
||||
+ .phy_id = 0xd565a408,
|
||||
+ .phy_id_mask = 0xfffffff8,
|
||||
+ .name = "Lantiq XWAY VR9 GPHY 11G v1.4",
|
||||
+ .features = (PHY_GBIT_FEATURES | SUPPORTED_Pause),
|
||||
+ .flags = 0, /*PHY_HAS_INTERRUPT,*/
|
||||
+ .config_init = vr9_gphy_config_init,
|
||||
+ .config_aneg = vr9_gphy_config_aneg,
|
||||
+ .read_status = genphy_read_status,
|
||||
+ .ack_interrupt = vr9_gphy_ack_interrupt,
|
||||
+ .did_interrupt = vr9_gphy_did_interrupt,
|
||||
+ .config_intr = vr9_gphy_config_intr,
|
||||
+ .driver = { .owner = THIS_MODULE },
|
||||
+ }, {
|
||||
+ .phy_id = 0xd565a418,
|
||||
+ .phy_id_mask = 0xfffffff8,
|
||||
+ .name = "Lantiq XWAY XRX PHY22F v1.4",
|
||||
+ .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause),
|
||||
+ .flags = 0, /*PHY_HAS_INTERRUPT,*/
|
||||
+ .config_init = vr9_gphy_config_init,
|
||||
+ .config_aneg = vr9_gphy_config_aneg,
|
||||
+ .read_status = genphy_read_status,
|
||||
+ .ack_interrupt = vr9_gphy_ack_interrupt,
|
||||
+ .did_interrupt = vr9_gphy_did_interrupt,
|
||||
+ .config_intr = vr9_gphy_config_intr,
|
||||
+ .driver = { .owner = THIS_MODULE },
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+static int __init ltq_phy_init(void)
|
||||
+{
|
||||
+ int i;
|
||||
+
|
||||
+ for (i = 0; i < ARRAY_SIZE(lantiq_phy); i++) {
|
||||
+ int err = phy_driver_register(&lantiq_phy[i]);
|
||||
+ if (err)
|
||||
+ pr_err("lantiq_phy: failed to load %s\n", lantiq_phy[i].name);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void __exit ltq_phy_exit(void)
|
||||
+{
|
||||
+ int i;
|
||||
+
|
||||
+ for (i = 0; i < ARRAY_SIZE(lantiq_phy); i++)
|
||||
+ phy_driver_unregister(&lantiq_phy[i]);
|
||||
+}
|
||||
+
|
||||
+module_init(ltq_phy_init);
|
||||
+module_exit(ltq_phy_exit);
|
||||
+
|
||||
+MODULE_DESCRIPTION("Lantiq PHY drivers");
|
||||
+MODULE_AUTHOR("Daniel Schwierzeck <daniel.schwierzeck@googlemail.com>");
|
||||
+MODULE_LICENSE("GPL");
|
||||
--- /dev/null
|
||||
+++ b/Documentation/devicetree/bindings/phy/phy-lanitq.txt
|
||||
@@ -0,0 +1,216 @@
|
||||
+Lanitq PHY binding
|
||||
+============================================
|
||||
+
|
||||
+This devicetree binding controls the lantiq ethernet phys led functionality.
|
||||
+
|
||||
+Example:
|
||||
+ mdio@0 {
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
+ compatible = "lantiq,xrx200-mdio";
|
||||
+ phy5: ethernet-phy@5 {
|
||||
+ reg = <0x1>;
|
||||
+ compatible = "lantiq,phy11g", "ethernet-phy-ieee802.3-c22";
|
||||
+ };
|
||||
+ phy11: ethernet-phy@11 {
|
||||
+ reg = <0x11>;
|
||||
+ compatible = "lantiq,phy22f", "ethernet-phy-ieee802.3-c22";
|
||||
+ lantiq,led2h = <0x00>;
|
||||
+ lantiq,led2l = <0x03>;
|
||||
+ };
|
||||
+ phy12: ethernet-phy@12 {
|
||||
+ reg = <0x12>;
|
||||
+ compatible = "lantiq,phy22f", "ethernet-phy-ieee802.3-c22";
|
||||
+ lantiq,led1h = <0x00>;
|
||||
+ lantiq,led1l = <0x03>;
|
||||
+ };
|
||||
+ phy13: ethernet-phy@13 {
|
||||
+ reg = <0x13>;
|
||||
+ compatible = "lantiq,phy22f", "ethernet-phy-ieee802.3-c22";
|
||||
+ lantiq,led2h = <0x00>;
|
||||
+ lantiq,led2l = <0x03>;
|
||||
+ };
|
||||
+ phy14: ethernet-phy@14 {
|
||||
+ reg = <0x14>;
|
||||
+ compatible = "lantiq,phy22f", "ethernet-phy-ieee802.3-c22";
|
||||
+ lantiq,led1h = <0x00>;
|
||||
+ lantiq,led1l = <0x03>;
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
+Register Description
|
||||
+============================================
|
||||
+
|
||||
+LEDCH:
|
||||
+
|
||||
+Name Hardware Reset Value
|
||||
+LEDCH 0x00C5
|
||||
+
|
||||
+| 15 | | | | | | | 8 |
|
||||
+=========================================
|
||||
+| RES |
|
||||
+=========================================
|
||||
+
|
||||
+| 7 | | | | | | | 0 |
|
||||
+=========================================
|
||||
+| FBF | SBF |RES | NACS |
|
||||
+=========================================
|
||||
+
|
||||
+Field Bits Type Description
|
||||
+FBF 7:6 RW Fast Blink Frequency
|
||||
+ ---
|
||||
+ 0x0 (00b) F02HZ 2 Hz blinking frequency
|
||||
+ 0x1 (01b) F04HZ 4 Hz blinking frequency
|
||||
+ 0x2 (10b) F08HZ 8 Hz blinking frequency
|
||||
+ 0x3 (11b) F16HZ 16 Hz blinking frequency
|
||||
+
|
||||
+SBF 5:4 RW Slow Blink Frequency
|
||||
+ ---
|
||||
+ 0x0 (00b) F02HZ 2 Hz blinking frequency
|
||||
+ 0x1 (01b) F04HZ 4 Hz blinking frequency
|
||||
+ 0x2 (10b) F08HZ 8 Hz blinking frequency
|
||||
+ 0x3 (11b) F16HZ 16 Hz blinking frequency
|
||||
+
|
||||
+NACS 2:0 RW Inverse of Scan Function
|
||||
+ ---
|
||||
+ 0x0 (000b) NONE No Function
|
||||
+ 0x1 (001b) LINK Complex function enabled when link is up
|
||||
+ 0x2 (010b) PDOWN Complex function enabled when device is powered-down
|
||||
+ 0x3 (011b) EEE Complex function enabled when device is in EEE mode
|
||||
+ 0x4 (100b) ANEG Complex function enabled when auto-negotiation is running
|
||||
+ 0x5 (101b) ABIST Complex function enabled when analog self-test is running
|
||||
+ 0x6 (110b) CDIAG Complex function enabled when cable diagnostics are running
|
||||
+ 0x7 (111b) TEST Complex function enabled when test mode is running
|
||||
+
|
||||
+LEDCL:
|
||||
+
|
||||
+Name Hardware Reset Value
|
||||
+LEDCL 0x0067
|
||||
+
|
||||
+| 15 | | | | | | | 8 |
|
||||
+=========================================
|
||||
+| RES |
|
||||
+=========================================
|
||||
+
|
||||
+| 7 | | | | | | | 0 |
|
||||
+=========================================
|
||||
+|RES | SCAN |RES | CBLINK |
|
||||
+=========================================
|
||||
+
|
||||
+Field Bits Type Description
|
||||
+SCAN 6:4 RW Complex Scan Configuration
|
||||
+ ---
|
||||
+ 000 B NONE No Function
|
||||
+ 001 B LINK Complex function enabled when link is up
|
||||
+ 010 B PDOWN Complex function enabled when device is powered-down
|
||||
+ 011 B EEE Complex function enabled when device is in EEE mode
|
||||
+ 100 B ANEG Complex function enabled when auto-negotiation is running
|
||||
+ 101 B ABIST Complex function enabled when analog self-test is running
|
||||
+ 110 B CDIAG Complex function enabled when cable diagnostics are running
|
||||
+ 111 B TEST Complex function enabled when test mode is running
|
||||
+
|
||||
+CBLINK 2:0 RW Complex Blinking Configuration
|
||||
+ ---
|
||||
+ 000 B NONE No Function
|
||||
+ 001 B LINK Complex function enabled when link is up
|
||||
+ 010 B PDOWN Complex function enabled when device is powered-down
|
||||
+ 011 B EEE Complex function enabled when device is in EEE mode
|
||||
+ 100 B ANEG Complex function enabled when auto-negotiation is running
|
||||
+ 101 B ABIST Complex function enabled when analog self-test is running
|
||||
+ 110 B CDIAG Complex function enabled when cable diagnostics are running
|
||||
+ 111 B TEST Complex function enabled when test mode is running
|
||||
+
|
||||
+LEDxH:
|
||||
+
|
||||
+Name Hardware Reset Value
|
||||
+LED0H 0x0070
|
||||
+LED1H 0x0020
|
||||
+LED2H 0x0040
|
||||
+LED3H 0x0040
|
||||
+
|
||||
+| 15 | | | | | | | 8 |
|
||||
+=========================================
|
||||
+| RES |
|
||||
+=========================================
|
||||
+
|
||||
+| 7 | | | | | | | 0 |
|
||||
+=========================================
|
||||
+| CON | BLINKF |
|
||||
+=========================================
|
||||
+
|
||||
+Field Bits Type Description
|
||||
+CON 7:4 RW Constant On Configuration
|
||||
+ ---
|
||||
+ 0x0 (0000b) NONE LED does not light up constantly
|
||||
+ 0x1 (0001b) LINK10 LED is on when link is 10 Mbit/s
|
||||
+ 0x2 (0010b) LINK100 LED is on when link is 100 Mbit/s
|
||||
+ 0x3 (0011b) LINK10X LED is on when link is 10/100 Mbit/s
|
||||
+ 0x4 (0100b) LINK1000 LED is on when link is 1000 Mbit/s
|
||||
+ 0x5 (0101b) LINK10_0 LED is on when link is 10/1000 Mbit/s
|
||||
+ 0x6 (0110b) LINK100X LED is on when link is 100/1000 Mbit/s
|
||||
+ 0x7 (0111b) LINK10XX LED is on when link is 10/100/1000 Mbit/s
|
||||
+ 0x8 (1000b) PDOWN LED is on when device is powered-down
|
||||
+ 0x9 (1001b) EEE LED is on when device is in EEE mode
|
||||
+ 0xA (1010b) ANEG LED is on when auto-negotiation is running
|
||||
+ 0xB (1011b) ABIST LED is on when analog self-test is running
|
||||
+ 0xC (1100b) CDIAG LED is on when cable diagnostics are running
|
||||
+
|
||||
+BLINKF 3:0 RW Fast Blinking Configuration
|
||||
+ ---
|
||||
+ 0x0 (0000b) NONE No Blinking
|
||||
+ 0x1 (0001b) LINK10 Blink when link is 10 Mbit/s
|
||||
+ 0x2 (0010b) LINK100 Blink when link is 100 Mbit/s
|
||||
+ 0x3 (0011b) LINK10X Blink when link is 10/100 Mbit/s
|
||||
+ 0x4 (0100b) LINK1000 Blink when link is 1000 Mbit/s
|
||||
+ 0x5 (0101b) LINK10_0 Blink when link is 10/1000 Mbit/s
|
||||
+ 0x6 (0110b) LINK100X Blink when link is 100/1000 Mbit/s
|
||||
+ 0x7 (0111b) LINK10XX Blink when link is 10/100/1000 Mbit/s
|
||||
+ 0x8 (1000b) PDOWN Blink when device is powered-down
|
||||
+ 0x9 (1001b) EEE Blink when device is in EEE mode
|
||||
+ 0xA (1010b) ANEG Blink when auto-negotiation is running
|
||||
+ 0xB (1011b) ABIST Blink when analog self-test is running
|
||||
+ 0xC (1100b) CDIAG Blink when cable diagnostics are running
|
||||
+
|
||||
+LEDxL:
|
||||
+
|
||||
+Name Hardware Reset Value
|
||||
+LED0L 0x0003
|
||||
+LED1L 0x0000
|
||||
+LED2L 0x0000
|
||||
+LED3L 0x0020
|
||||
+
|
||||
+| 15 | | | | | | | 8 |
|
||||
+=========================================
|
||||
+| RES |
|
||||
+=========================================
|
||||
+
|
||||
+| 7 | | | | | | | 0 |
|
||||
+=========================================
|
||||
+| BLINKS | PULSE |
|
||||
+=========================================
|
||||
+
|
||||
+Field Bits Type Description
|
||||
+BLINKS 7:4 RW Slow Blinkin Configuration
|
||||
+ ---
|
||||
+ 0x0 (0000b) NONE No Blinking
|
||||
+ 0x1 (0001b) LINK10 Blink when link is 10 Mbit/s
|
||||
+ 0x2 (0010b) LINK100 Blink when link is 100 Mbit/s
|
||||
+ 0x3 (0011b) LINK10X Blink when link is 10/100 Mbit/s
|
||||
+ 0x4 (0100b) LINK1000 Blink when link is 1000 Mbit/s
|
||||
+ 0x5 (0101b) LINK10_0 Blink when link is 10/1000 Mbit/s
|
||||
+ 0x6 (0110b) LINK100X Blink when link is 100/1000 Mbit/s
|
||||
+ 0x7 (0111b) LINK10XX Blink when link is 10/100/1000 Mbit/s
|
||||
+ 0x8 (1000b) PDOWN Blink when device is powered-down
|
||||
+ 0x9 (1001b) EEE Blink when device is in EEE mode
|
||||
+ 0xA (1010b) ANEG Blink when auto-negotiation is running
|
||||
+ 0xB (1011b) ABIST Blink when analog self-test is running
|
||||
+ 0xC (1100b) CDIAG Blink when cable diagnostics are runningning
|
||||
+
|
||||
+PULSE 3:0 RW Pulsing Configuration
|
||||
+ The pulse field is a mask field by which certain events can be combined
|
||||
+ ---
|
||||
+ 0x0 (0000b) NONE No pulsing
|
||||
+ 0x1 (0001b) TXACT Transmit activity
|
||||
+ 0x2 (0010b) RXACT Receive activity
|
||||
+ 0x4 (0100b) COL Collision
|
||||
+ 0x8 (1000b) RES Reserved
|
@ -1,125 +0,0 @@
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Subject: [PATCH 1/4] net: phy: update Broadcom drivers to v4.5
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
---
|
||||
|
||||
--- a/drivers/net/phy/bcm7xxx.c
|
||||
+++ b/drivers/net/phy/bcm7xxx.c
|
||||
@@ -250,10 +250,6 @@ static int bcm7xxx_config_init(struct ph
|
||||
phy_write(phydev, MII_BCM7XXX_AUX_MODE, MII_BCM7XX_64CLK_MDIO);
|
||||
phy_read(phydev, MII_BCM7XXX_AUX_MODE);
|
||||
|
||||
- /* Workaround only required for 100Mbits/sec capable PHYs */
|
||||
- if (phydev->supported & PHY_GBIT_FEATURES)
|
||||
- return 0;
|
||||
-
|
||||
/* set shadow mode 2 */
|
||||
ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST,
|
||||
MII_BCM7XXX_SHD_MODE_2, MII_BCM7XXX_SHD_MODE_2);
|
||||
@@ -270,7 +266,7 @@ static int bcm7xxx_config_init(struct ph
|
||||
phy_write(phydev, MII_BCM7XXX_100TX_FALSE_CAR, 0x7555);
|
||||
|
||||
/* reset shadow mode 2 */
|
||||
- ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, MII_BCM7XXX_SHD_MODE_2, 0);
|
||||
+ ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, 0, MII_BCM7XXX_SHD_MODE_2);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -307,11 +303,6 @@ static int bcm7xxx_suspend(struct phy_de
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static int bcm7xxx_dummy_config_init(struct phy_device *phydev)
|
||||
-{
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
#define BCM7XXX_28NM_GPHY(_oui, _name) \
|
||||
{ \
|
||||
.phy_id = (_oui), \
|
||||
@@ -338,7 +329,7 @@ static struct phy_driver bcm7xxx_driver[
|
||||
.phy_id = PHY_ID_BCM7425,
|
||||
.phy_id_mask = 0xfffffff0,
|
||||
.name = "Broadcom BCM7425",
|
||||
- .features = PHY_GBIT_FEATURES |
|
||||
+ .features = PHY_BASIC_FEATURES |
|
||||
SUPPORTED_Pause | SUPPORTED_Asym_Pause,
|
||||
.flags = PHY_IS_INTERNAL,
|
||||
.config_init = bcm7xxx_config_init,
|
||||
@@ -351,7 +342,7 @@ static struct phy_driver bcm7xxx_driver[
|
||||
.phy_id = PHY_ID_BCM7429,
|
||||
.phy_id_mask = 0xfffffff0,
|
||||
.name = "Broadcom BCM7429",
|
||||
- .features = PHY_GBIT_FEATURES |
|
||||
+ .features = PHY_BASIC_FEATURES |
|
||||
SUPPORTED_Pause | SUPPORTED_Asym_Pause,
|
||||
.flags = PHY_IS_INTERNAL,
|
||||
.config_init = bcm7xxx_config_init,
|
||||
@@ -361,31 +352,18 @@ static struct phy_driver bcm7xxx_driver[
|
||||
.resume = bcm7xxx_config_init,
|
||||
.driver = { .owner = THIS_MODULE },
|
||||
}, {
|
||||
- .phy_id = PHY_BCM_OUI_4,
|
||||
- .phy_id_mask = 0xffff0000,
|
||||
- .name = "Broadcom BCM7XXX 40nm",
|
||||
- .features = PHY_GBIT_FEATURES |
|
||||
- SUPPORTED_Pause | SUPPORTED_Asym_Pause,
|
||||
- .flags = PHY_IS_INTERNAL,
|
||||
- .config_init = bcm7xxx_config_init,
|
||||
- .config_aneg = genphy_config_aneg,
|
||||
- .read_status = genphy_read_status,
|
||||
- .suspend = bcm7xxx_suspend,
|
||||
- .resume = bcm7xxx_config_init,
|
||||
- .driver = { .owner = THIS_MODULE },
|
||||
-}, {
|
||||
- .phy_id = PHY_BCM_OUI_5,
|
||||
- .phy_id_mask = 0xffffff00,
|
||||
- .name = "Broadcom BCM7XXX 65nm",
|
||||
- .features = PHY_BASIC_FEATURES |
|
||||
+ .phy_id = PHY_ID_BCM7435,
|
||||
+ .phy_id_mask = 0xfffffff0,
|
||||
+ .name = "Broadcom BCM7435",
|
||||
+ .features = PHY_BASIC_FEATURES |
|
||||
SUPPORTED_Pause | SUPPORTED_Asym_Pause,
|
||||
- .flags = PHY_IS_INTERNAL,
|
||||
- .config_init = bcm7xxx_dummy_config_init,
|
||||
- .config_aneg = genphy_config_aneg,
|
||||
- .read_status = genphy_read_status,
|
||||
- .suspend = bcm7xxx_suspend,
|
||||
- .resume = bcm7xxx_config_init,
|
||||
- .driver = { .owner = THIS_MODULE },
|
||||
+ .flags = PHY_IS_INTERNAL,
|
||||
+ .config_init = bcm7xxx_config_init,
|
||||
+ .config_aneg = genphy_config_aneg,
|
||||
+ .read_status = genphy_read_status,
|
||||
+ .suspend = bcm7xxx_suspend,
|
||||
+ .resume = bcm7xxx_config_init,
|
||||
+ .driver = { .owner = THIS_MODULE },
|
||||
} };
|
||||
|
||||
static struct mdio_device_id __maybe_unused bcm7xxx_tbl[] = {
|
||||
@@ -395,9 +373,8 @@ static struct mdio_device_id __maybe_unu
|
||||
{ PHY_ID_BCM7425, 0xfffffff0, },
|
||||
{ PHY_ID_BCM7429, 0xfffffff0, },
|
||||
{ PHY_ID_BCM7439, 0xfffffff0, },
|
||||
+ { PHY_ID_BCM7435, 0xfffffff0, },
|
||||
{ PHY_ID_BCM7445, 0xfffffff0, },
|
||||
- { PHY_BCM_OUI_4, 0xffff0000 },
|
||||
- { PHY_BCM_OUI_5, 0xffffff00 },
|
||||
{ }
|
||||
};
|
||||
|
||||
--- a/include/linux/brcmphy.h
|
||||
+++ b/include/linux/brcmphy.h
|
||||
@@ -26,6 +26,7 @@
|
||||
#define PHY_ID_BCM7366 0x600d8490
|
||||
#define PHY_ID_BCM7425 0x600d86b0
|
||||
#define PHY_ID_BCM7429 0x600d8730
|
||||
+#define PHY_ID_BCM7435 0x600d8750
|
||||
#define PHY_ID_BCM7439 0x600d8480
|
||||
#define PHY_ID_BCM7439_2 0xae025080
|
||||
#define PHY_ID_BCM7445 0x600d8510
|
@ -1,123 +0,0 @@
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Subject: [PATCH 2/4] net: phy: update Broadcom drivers to v4.6
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
---
|
||||
|
||||
--- a/drivers/net/phy/bcm7xxx.c
|
||||
+++ b/drivers/net/phy/bcm7xxx.c
|
||||
@@ -24,7 +24,7 @@
|
||||
#define MII_BCM7XXX_100TX_FALSE_CAR 0x13
|
||||
#define MII_BCM7XXX_100TX_DISC 0x14
|
||||
#define MII_BCM7XXX_AUX_MODE 0x1d
|
||||
-#define MII_BCM7XX_64CLK_MDIO BIT(12)
|
||||
+#define MII_BCM7XXX_64CLK_MDIO BIT(12)
|
||||
#define MII_BCM7XXX_TEST 0x1f
|
||||
#define MII_BCM7XXX_SHD_MODE_2 BIT(2)
|
||||
|
||||
@@ -247,7 +247,7 @@ static int bcm7xxx_config_init(struct ph
|
||||
int ret;
|
||||
|
||||
/* Enable 64 clock MDIO */
|
||||
- phy_write(phydev, MII_BCM7XXX_AUX_MODE, MII_BCM7XX_64CLK_MDIO);
|
||||
+ phy_write(phydev, MII_BCM7XXX_AUX_MODE, MII_BCM7XXX_64CLK_MDIO);
|
||||
phy_read(phydev, MII_BCM7XXX_AUX_MODE);
|
||||
|
||||
/* set shadow mode 2 */
|
||||
@@ -318,6 +318,22 @@ static int bcm7xxx_suspend(struct phy_de
|
||||
.driver = { .owner = THIS_MODULE }, \
|
||||
}
|
||||
|
||||
+#define BCM7XXX_40NM_EPHY(_oui, _name) \
|
||||
+{ \
|
||||
+ .phy_id = (_oui), \
|
||||
+ .phy_id_mask = 0xfffffff0, \
|
||||
+ .name = _name, \
|
||||
+ .features = PHY_BASIC_FEATURES | \
|
||||
+ SUPPORTED_Pause | SUPPORTED_Asym_Pause, \
|
||||
+ .flags = PHY_IS_INTERNAL, \
|
||||
+ .config_init = bcm7xxx_config_init, \
|
||||
+ .config_aneg = genphy_config_aneg, \
|
||||
+ .read_status = genphy_read_status, \
|
||||
+ .suspend = bcm7xxx_suspend, \
|
||||
+ .resume = bcm7xxx_config_init, \
|
||||
+ .driver = { .owner = THIS_MODULE }, \
|
||||
+}
|
||||
+
|
||||
static struct phy_driver bcm7xxx_driver[] = {
|
||||
BCM7XXX_28NM_GPHY(PHY_ID_BCM7250, "Broadcom BCM7250"),
|
||||
BCM7XXX_28NM_GPHY(PHY_ID_BCM7364, "Broadcom BCM7364"),
|
||||
@@ -325,51 +341,19 @@ static struct phy_driver bcm7xxx_driver[
|
||||
BCM7XXX_28NM_GPHY(PHY_ID_BCM7439, "Broadcom BCM7439"),
|
||||
BCM7XXX_28NM_GPHY(PHY_ID_BCM7439_2, "Broadcom BCM7439 (2)"),
|
||||
BCM7XXX_28NM_GPHY(PHY_ID_BCM7445, "Broadcom BCM7445"),
|
||||
-{
|
||||
- .phy_id = PHY_ID_BCM7425,
|
||||
- .phy_id_mask = 0xfffffff0,
|
||||
- .name = "Broadcom BCM7425",
|
||||
- .features = PHY_BASIC_FEATURES |
|
||||
- SUPPORTED_Pause | SUPPORTED_Asym_Pause,
|
||||
- .flags = PHY_IS_INTERNAL,
|
||||
- .config_init = bcm7xxx_config_init,
|
||||
- .config_aneg = genphy_config_aneg,
|
||||
- .read_status = genphy_read_status,
|
||||
- .suspend = bcm7xxx_suspend,
|
||||
- .resume = bcm7xxx_config_init,
|
||||
- .driver = { .owner = THIS_MODULE },
|
||||
-}, {
|
||||
- .phy_id = PHY_ID_BCM7429,
|
||||
- .phy_id_mask = 0xfffffff0,
|
||||
- .name = "Broadcom BCM7429",
|
||||
- .features = PHY_BASIC_FEATURES |
|
||||
- SUPPORTED_Pause | SUPPORTED_Asym_Pause,
|
||||
- .flags = PHY_IS_INTERNAL,
|
||||
- .config_init = bcm7xxx_config_init,
|
||||
- .config_aneg = genphy_config_aneg,
|
||||
- .read_status = genphy_read_status,
|
||||
- .suspend = bcm7xxx_suspend,
|
||||
- .resume = bcm7xxx_config_init,
|
||||
- .driver = { .owner = THIS_MODULE },
|
||||
-}, {
|
||||
- .phy_id = PHY_ID_BCM7435,
|
||||
- .phy_id_mask = 0xfffffff0,
|
||||
- .name = "Broadcom BCM7435",
|
||||
- .features = PHY_BASIC_FEATURES |
|
||||
- SUPPORTED_Pause | SUPPORTED_Asym_Pause,
|
||||
- .flags = PHY_IS_INTERNAL,
|
||||
- .config_init = bcm7xxx_config_init,
|
||||
- .config_aneg = genphy_config_aneg,
|
||||
- .read_status = genphy_read_status,
|
||||
- .suspend = bcm7xxx_suspend,
|
||||
- .resume = bcm7xxx_config_init,
|
||||
- .driver = { .owner = THIS_MODULE },
|
||||
-} };
|
||||
+ BCM7XXX_40NM_EPHY(PHY_ID_BCM7346, "Broadcom BCM7346"),
|
||||
+ BCM7XXX_40NM_EPHY(PHY_ID_BCM7362, "Broadcom BCM7362"),
|
||||
+ BCM7XXX_40NM_EPHY(PHY_ID_BCM7425, "Broadcom BCM7425"),
|
||||
+ BCM7XXX_40NM_EPHY(PHY_ID_BCM7429, "Broadcom BCM7429"),
|
||||
+ BCM7XXX_40NM_EPHY(PHY_ID_BCM7435, "Broadcom BCM7435"),
|
||||
+};
|
||||
|
||||
static struct mdio_device_id __maybe_unused bcm7xxx_tbl[] = {
|
||||
{ PHY_ID_BCM7250, 0xfffffff0, },
|
||||
{ PHY_ID_BCM7364, 0xfffffff0, },
|
||||
{ PHY_ID_BCM7366, 0xfffffff0, },
|
||||
+ { PHY_ID_BCM7346, 0xfffffff0, },
|
||||
+ { PHY_ID_BCM7362, 0xfffffff0, },
|
||||
{ PHY_ID_BCM7425, 0xfffffff0, },
|
||||
{ PHY_ID_BCM7429, 0xfffffff0, },
|
||||
{ PHY_ID_BCM7439, 0xfffffff0, },
|
||||
--- a/include/linux/brcmphy.h
|
||||
+++ b/include/linux/brcmphy.h
|
||||
@@ -24,6 +24,8 @@
|
||||
#define PHY_ID_BCM7250 0xae025280
|
||||
#define PHY_ID_BCM7364 0xae025260
|
||||
#define PHY_ID_BCM7366 0x600d8490
|
||||
+#define PHY_ID_BCM7346 0x600d8650
|
||||
+#define PHY_ID_BCM7362 0x600d84b0
|
||||
#define PHY_ID_BCM7425 0x600d86b0
|
||||
#define PHY_ID_BCM7429 0x600d8730
|
||||
#define PHY_ID_BCM7435 0x600d8750
|
@ -1,315 +0,0 @@
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Subject: [PATCH] net: phy: cherry-pick Broadcom drivers updates from v4.10
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
This includes following upstream commits:
|
||||
5519da874ad0 net: phy: broadcom: Move bcm54xx_auxctl_{read, write} to common library
|
||||
b14995ac2527 net: phy: broadcom: Add BCM54810 PHY entry
|
||||
5b4e29005123 net: phy: broadcom: add bcm54xx_auxctl_read
|
||||
d92ead16be40 net: phy: broadcom: Add support for BCM54612E
|
||||
3cf25904fe46 net: phy: broadcom: Update Auxiliary Control Register macros
|
||||
|
||||
Other commits were skipped as they depend on other changes like
|
||||
ETHTOOL_PHY_DOWNSHIFT & DOWNSHIFT_DEV_DISABLE and new APIs like
|
||||
get_sset_count.
|
||||
|
||||
One exception was picking new regs from commit d06f78c4232d ("net: phy:
|
||||
broadcom: Add support code for downshift/Wirespeed").
|
||||
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
---
|
||||
|
||||
--- a/drivers/net/phy/Kconfig
|
||||
+++ b/drivers/net/phy/Kconfig
|
||||
@@ -77,7 +77,7 @@ config BROADCOM_PHY
|
||||
select BCM_NET_PHYLIB
|
||||
---help---
|
||||
Currently supports the BCM5411, BCM5421, BCM5461, BCM54616S, BCM5464,
|
||||
- BCM5481 and BCM5482 PHYs.
|
||||
+ BCM5481, BCM54810 and BCM5482 PHYs.
|
||||
|
||||
config BCM_CYGNUS_PHY
|
||||
tristate "Drivers for Broadcom Cygnus SoC internal PHY"
|
||||
--- a/drivers/net/phy/bcm-phy-lib.c
|
||||
+++ b/drivers/net/phy/bcm-phy-lib.c
|
||||
@@ -50,6 +50,23 @@ int bcm_phy_read_exp(struct phy_device *
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bcm_phy_read_exp);
|
||||
|
||||
+int bcm54xx_auxctl_read(struct phy_device *phydev, u16 regnum)
|
||||
+{
|
||||
+ /* The register must be written to both the Shadow Register Select and
|
||||
+ * the Shadow Read Register Selector
|
||||
+ */
|
||||
+ phy_write(phydev, MII_BCM54XX_AUX_CTL, regnum |
|
||||
+ regnum << MII_BCM54XX_AUXCTL_SHDWSEL_READ_SHIFT);
|
||||
+ return phy_read(phydev, MII_BCM54XX_AUX_CTL);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(bcm54xx_auxctl_read);
|
||||
+
|
||||
+int bcm54xx_auxctl_write(struct phy_device *phydev, u16 regnum, u16 val)
|
||||
+{
|
||||
+ return phy_write(phydev, MII_BCM54XX_AUX_CTL, regnum | val);
|
||||
+}
|
||||
+EXPORT_SYMBOL(bcm54xx_auxctl_write);
|
||||
+
|
||||
int bcm_phy_write_misc(struct phy_device *phydev,
|
||||
u16 reg, u16 chl, u16 val)
|
||||
{
|
||||
--- a/drivers/net/phy/bcm-phy-lib.h
|
||||
+++ b/drivers/net/phy/bcm-phy-lib.h
|
||||
@@ -19,6 +19,9 @@
|
||||
int bcm_phy_write_exp(struct phy_device *phydev, u16 reg, u16 val);
|
||||
int bcm_phy_read_exp(struct phy_device *phydev, u16 reg);
|
||||
|
||||
+int bcm54xx_auxctl_write(struct phy_device *phydev, u16 regnum, u16 val);
|
||||
+int bcm54xx_auxctl_read(struct phy_device *phydev, u16 regnum);
|
||||
+
|
||||
int bcm_phy_write_misc(struct phy_device *phydev,
|
||||
u16 reg, u16 chl, u16 value);
|
||||
int bcm_phy_read_misc(struct phy_device *phydev,
|
||||
--- a/drivers/net/phy/broadcom.c
|
||||
+++ b/drivers/net/phy/broadcom.c
|
||||
@@ -18,7 +18,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/brcmphy.h>
|
||||
-
|
||||
+#include <linux/of.h>
|
||||
|
||||
#define BRCM_PHY_MODEL(phydev) \
|
||||
((phydev)->drv->phy_id & (phydev)->drv->phy_id_mask)
|
||||
@@ -30,9 +30,32 @@ MODULE_DESCRIPTION("Broadcom PHY driver"
|
||||
MODULE_AUTHOR("Maciej W. Rozycki");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
-static int bcm54xx_auxctl_write(struct phy_device *phydev, u16 regnum, u16 val)
|
||||
+static int bcm54810_config(struct phy_device *phydev)
|
||||
{
|
||||
- return phy_write(phydev, MII_BCM54XX_AUX_CTL, regnum | val);
|
||||
+ int rc, val;
|
||||
+
|
||||
+ val = bcm_phy_read_exp(phydev, BCM54810_EXP_BROADREACH_LRE_MISC_CTL);
|
||||
+ val &= ~BCM54810_EXP_BROADREACH_LRE_MISC_CTL_EN;
|
||||
+ rc = bcm_phy_write_exp(phydev, BCM54810_EXP_BROADREACH_LRE_MISC_CTL,
|
||||
+ val);
|
||||
+ if (rc < 0)
|
||||
+ return rc;
|
||||
+
|
||||
+ val = bcm54xx_auxctl_read(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
|
||||
+ val &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN;
|
||||
+ val |= MII_BCM54XX_AUXCTL_MISC_WREN;
|
||||
+ rc = bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC,
|
||||
+ val);
|
||||
+ if (rc < 0)
|
||||
+ return rc;
|
||||
+
|
||||
+ val = bcm_phy_read_shadow(phydev, BCM54810_SHD_CLK_CTL);
|
||||
+ val &= ~BCM54810_SHD_CLK_CTL_GTXCLK_EN;
|
||||
+ rc = bcm_phy_write_shadow(phydev, BCM54810_SHD_CLK_CTL, val);
|
||||
+ if (rc < 0)
|
||||
+ return rc;
|
||||
+
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
/* Needs SMDSP clock enabled via bcm54xx_phydsp_config() */
|
||||
@@ -207,6 +230,12 @@ static int bcm54xx_config_init(struct ph
|
||||
(phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE))
|
||||
bcm54xx_adjust_rxrefclk(phydev);
|
||||
|
||||
+ if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54810) {
|
||||
+ err = bcm54810_config(phydev);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+ }
|
||||
+
|
||||
bcm54xx_phydsp_config(phydev);
|
||||
|
||||
return 0;
|
||||
@@ -304,6 +333,7 @@ static int bcm5482_read_status(struct ph
|
||||
|
||||
static int bcm5481_config_aneg(struct phy_device *phydev)
|
||||
{
|
||||
+ struct device_node *np = phydev->dev.of_node;
|
||||
int ret;
|
||||
|
||||
/* Aneg firsly. */
|
||||
@@ -334,6 +364,49 @@ static int bcm5481_config_aneg(struct ph
|
||||
phy_write(phydev, 0x18, reg);
|
||||
}
|
||||
|
||||
+ if (of_property_read_bool(np, "enet-phy-lane-swap")) {
|
||||
+ /* Lane Swap - Undocumented register...magic! */
|
||||
+ ret = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_SEL_ER + 0x9,
|
||||
+ 0x11B);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int bcm54612e_config_aneg(struct phy_device *phydev)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ /* First, auto-negotiate. */
|
||||
+ ret = genphy_config_aneg(phydev);
|
||||
+
|
||||
+ /* Clear TX internal delay unless requested. */
|
||||
+ if ((phydev->interface != PHY_INTERFACE_MODE_RGMII_ID) &&
|
||||
+ (phydev->interface != PHY_INTERFACE_MODE_RGMII_TXID)) {
|
||||
+ /* Disable TXD to GTXCLK clock delay (default set) */
|
||||
+ /* Bit 9 is the only field in shadow register 00011 */
|
||||
+ bcm_phy_write_shadow(phydev, 0x03, 0);
|
||||
+ }
|
||||
+
|
||||
+ /* Clear RX internal delay unless requested. */
|
||||
+ if ((phydev->interface != PHY_INTERFACE_MODE_RGMII_ID) &&
|
||||
+ (phydev->interface != PHY_INTERFACE_MODE_RGMII_RXID)) {
|
||||
+ u16 reg;
|
||||
+
|
||||
+ /* Errata: reads require filling in the write selector field */
|
||||
+ bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC,
|
||||
+ MII_BCM54XX_AUXCTL_MISC_RDSEL_MISC);
|
||||
+ reg = phy_read(phydev, MII_BCM54XX_AUX_CTL);
|
||||
+ /* Disable RXD to RXC delay (default set) */
|
||||
+ reg &= ~MII_BCM54XX_AUXCTL_MISC_RXD_RXC_SKEW;
|
||||
+ /* Clear shadow selector field */
|
||||
+ reg &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MASK;
|
||||
+ bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC,
|
||||
+ MII_BCM54XX_AUXCTL_MISC_WREN | reg);
|
||||
+ }
|
||||
+
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -488,6 +561,18 @@ static struct phy_driver broadcom_driver
|
||||
.config_intr = bcm_phy_config_intr,
|
||||
.driver = { .owner = THIS_MODULE },
|
||||
}, {
|
||||
+ .phy_id = PHY_ID_BCM54612E,
|
||||
+ .phy_id_mask = 0xfffffff0,
|
||||
+ .name = "Broadcom BCM54612E",
|
||||
+ .features = PHY_GBIT_FEATURES |
|
||||
+ SUPPORTED_Pause | SUPPORTED_Asym_Pause,
|
||||
+ .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
|
||||
+ .config_init = bcm54xx_config_init,
|
||||
+ .config_aneg = bcm54612e_config_aneg,
|
||||
+ .read_status = genphy_read_status,
|
||||
+ .ack_interrupt = bcm_phy_ack_intr,
|
||||
+ .config_intr = bcm_phy_config_intr,
|
||||
+}, {
|
||||
.phy_id = PHY_ID_BCM54616S,
|
||||
.phy_id_mask = 0xfffffff0,
|
||||
.name = "Broadcom BCM54616S",
|
||||
@@ -527,6 +612,18 @@ static struct phy_driver broadcom_driver
|
||||
.config_intr = bcm_phy_config_intr,
|
||||
.driver = { .owner = THIS_MODULE },
|
||||
}, {
|
||||
+ .phy_id = PHY_ID_BCM54810,
|
||||
+ .phy_id_mask = 0xfffffff0,
|
||||
+ .name = "Broadcom BCM54810",
|
||||
+ .features = PHY_GBIT_FEATURES |
|
||||
+ SUPPORTED_Pause | SUPPORTED_Asym_Pause,
|
||||
+ .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
|
||||
+ .config_init = bcm54xx_config_init,
|
||||
+ .config_aneg = bcm5481_config_aneg,
|
||||
+ .read_status = genphy_read_status,
|
||||
+ .ack_interrupt = bcm_phy_ack_intr,
|
||||
+ .config_intr = bcm_phy_config_intr,
|
||||
+}, {
|
||||
.phy_id = PHY_ID_BCM5482,
|
||||
.phy_id_mask = 0xfffffff0,
|
||||
.name = "Broadcom BCM5482",
|
||||
@@ -612,9 +709,11 @@ static struct mdio_device_id __maybe_unu
|
||||
{ PHY_ID_BCM5411, 0xfffffff0 },
|
||||
{ PHY_ID_BCM5421, 0xfffffff0 },
|
||||
{ PHY_ID_BCM5461, 0xfffffff0 },
|
||||
+ { PHY_ID_BCM54612E, 0xfffffff0 },
|
||||
{ PHY_ID_BCM54616S, 0xfffffff0 },
|
||||
{ PHY_ID_BCM5464, 0xfffffff0 },
|
||||
{ PHY_ID_BCM5481, 0xfffffff0 },
|
||||
+ { PHY_ID_BCM54810, 0xfffffff0 },
|
||||
{ PHY_ID_BCM5482, 0xfffffff0 },
|
||||
{ PHY_ID_BCM50610, 0xfffffff0 },
|
||||
{ PHY_ID_BCM50610M, 0xfffffff0 },
|
||||
--- a/include/linux/brcmphy.h
|
||||
+++ b/include/linux/brcmphy.h
|
||||
@@ -13,11 +13,13 @@
|
||||
#define PHY_ID_BCM5241 0x0143bc30
|
||||
#define PHY_ID_BCMAC131 0x0143bc70
|
||||
#define PHY_ID_BCM5481 0x0143bca0
|
||||
+#define PHY_ID_BCM54810 0x03625d00
|
||||
#define PHY_ID_BCM5482 0x0143bcb0
|
||||
#define PHY_ID_BCM5411 0x00206070
|
||||
#define PHY_ID_BCM5421 0x002060e0
|
||||
#define PHY_ID_BCM5464 0x002060b0
|
||||
#define PHY_ID_BCM5461 0x002060c0
|
||||
+#define PHY_ID_BCM54612E 0x03625e60
|
||||
#define PHY_ID_BCM54616S 0x03625d10
|
||||
#define PHY_ID_BCM57780 0x03625d90
|
||||
|
||||
@@ -55,6 +57,7 @@
|
||||
#define PHY_BRCM_EXT_IBND_TX_ENABLE 0x00002000
|
||||
#define PHY_BRCM_CLEAR_RGMII_MODE 0x00004000
|
||||
#define PHY_BRCM_DIS_TXCRXC_NOENRGY 0x00008000
|
||||
+
|
||||
/* Broadcom BCM7xxx specific workarounds */
|
||||
#define PHY_BRCM_7XXX_REV(x) (((x) >> 8) & 0xff)
|
||||
#define PHY_BRCM_7XXX_PATCH(x) ((x) & 0xff)
|
||||
@@ -105,11 +108,14 @@
|
||||
#define MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA 0x0800
|
||||
|
||||
#define MII_BCM54XX_AUXCTL_MISC_WREN 0x8000
|
||||
+#define MII_BCM54XX_AUXCTL_MISC_RXD_RXC_SKEW 0x0100
|
||||
#define MII_BCM54XX_AUXCTL_MISC_FORCE_AMDIX 0x0200
|
||||
#define MII_BCM54XX_AUXCTL_MISC_RDSEL_MISC 0x7000
|
||||
#define MII_BCM54XX_AUXCTL_SHDWSEL_MISC 0x0007
|
||||
+#define MII_BCM54XX_AUXCTL_SHDWSEL_READ_SHIFT 12
|
||||
+#define MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN (1 << 8)
|
||||
|
||||
-#define MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL 0x0000
|
||||
+#define MII_BCM54XX_AUXCTL_SHDWSEL_MASK 0x0007
|
||||
|
||||
/*
|
||||
* Broadcom LED source encodings. These are used in BCM5461, BCM5481,
|
||||
@@ -124,6 +130,7 @@
|
||||
#define BCM_LED_SRC_INTR 0x6
|
||||
#define BCM_LED_SRC_QUALITY 0x7
|
||||
#define BCM_LED_SRC_RCVLED 0x8
|
||||
+#define BCM_LED_SRC_WIRESPEED 0x9
|
||||
#define BCM_LED_SRC_MULTICOLOR1 0xa
|
||||
#define BCM_LED_SRC_OPENSHORT 0xb
|
||||
#define BCM_LED_SRC_OFF 0xe /* Tied high */
|
||||
@@ -135,6 +142,14 @@
|
||||
* Shadow values go into bits [14:10] of register 0x1c to select a shadow
|
||||
* register to access.
|
||||
*/
|
||||
+
|
||||
+/* 00100: Reserved control register 2 */
|
||||
+#define BCM54XX_SHD_SCR2 0x04
|
||||
+#define BCM54XX_SHD_SCR2_WSPD_RTRY_DIS 0x100
|
||||
+#define BCM54XX_SHD_SCR2_WSPD_RTRY_LMT_SHIFT 2
|
||||
+#define BCM54XX_SHD_SCR2_WSPD_RTRY_LMT_OFFSET 2
|
||||
+#define BCM54XX_SHD_SCR2_WSPD_RTRY_LMT_MASK 0x7
|
||||
+
|
||||
/* 00101: Spare Control Register 3 */
|
||||
#define BCM54XX_SHD_SCR3 0x05
|
||||
#define BCM54XX_SHD_SCR3_DEF_CLK125 0x0001
|
||||
@@ -189,6 +204,12 @@
|
||||
#define BCM5482_SSD_SGMII_SLAVE_EN 0x0002 /* Slave mode enable */
|
||||
#define BCM5482_SSD_SGMII_SLAVE_AD 0x0001 /* Slave auto-detection */
|
||||
|
||||
+/* BCM54810 Registers */
|
||||
+#define BCM54810_EXP_BROADREACH_LRE_MISC_CTL (MII_BCM54XX_EXP_SEL_ER + 0x90)
|
||||
+#define BCM54810_EXP_BROADREACH_LRE_MISC_CTL_EN (1 << 0)
|
||||
+#define BCM54810_SHD_CLK_CTL 0x3
|
||||
+#define BCM54810_SHD_CLK_CTL_GTXCLK_EN (1 << 9)
|
||||
+
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Fast Ethernet Transceiver definitions. */
|
@ -1,283 +0,0 @@
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Subject: [PATCH] net: phy: cherry-pick Broadcom drivers updates from v4.11
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
This includes following upstream commits:
|
||||
62e13097c46c net: phy: broadcom: rehook BCM54612E specific init
|
||||
0fc9ae107669 net: phy: broadcom: add support for BCM54210E
|
||||
5e7bfa6cb0a9 net: phy: bcm-phy-lib: clean up remaining AUXCTL register defines
|
||||
8293c7bcdef1 net: phy: broadcom: drop duplicated define for RGMII SKEW delay
|
||||
85b4685da52f net: phy: broadcom: use auxctl reading helper in BCM54612E code
|
||||
039a7b8592ab net: phy: bcm7xxx: Implement EGPHY workaround for 7278
|
||||
582d0ac397ca net: phy: bcm7xxx: Add entry for BCM7278
|
||||
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
---
|
||||
|
||||
--- a/drivers/net/phy/bcm7xxx.c
|
||||
+++ b/drivers/net/phy/bcm7xxx.c
|
||||
@@ -163,12 +163,43 @@ static int bcm7xxx_28nm_e0_plus_afe_conf
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int bcm7xxx_28nm_a0_patch_afe_config_init(struct phy_device *phydev)
|
||||
+{
|
||||
+ /* +1 RC_CAL codes for RL centering for both LT and HT conditions */
|
||||
+ bcm_phy_write_misc(phydev, AFE_RXCONFIG_2, 0xd003);
|
||||
+
|
||||
+ /* Cut master bias current by 2% to compensate for RC_CAL offset */
|
||||
+ bcm_phy_write_misc(phydev, DSP_TAP10, 0x791b);
|
||||
+
|
||||
+ /* Improve hybrid leakage */
|
||||
+ bcm_phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x10e3);
|
||||
+
|
||||
+ /* Change rx_on_tune 8 to 0xf */
|
||||
+ bcm_phy_write_misc(phydev, 0x21, 0x2, 0x87f6);
|
||||
+
|
||||
+ /* Change 100Tx EEE bandwidth */
|
||||
+ bcm_phy_write_misc(phydev, 0x22, 0x2, 0x017d);
|
||||
+
|
||||
+ /* Enable ffe zero detection for Vitesse interoperability */
|
||||
+ bcm_phy_write_misc(phydev, 0x26, 0x2, 0x0015);
|
||||
+
|
||||
+ r_rc_cal_reset(phydev);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static int bcm7xxx_28nm_config_init(struct phy_device *phydev)
|
||||
{
|
||||
u8 rev = PHY_BRCM_7XXX_REV(phydev->dev_flags);
|
||||
u8 patch = PHY_BRCM_7XXX_PATCH(phydev->dev_flags);
|
||||
int ret = 0;
|
||||
|
||||
+ /* Newer devices have moved the revision information back into a
|
||||
+ * standard location in MII_PHYS_ID[23]
|
||||
+ */
|
||||
+ if (rev == 0)
|
||||
+ rev = phydev->phy_id & ~phydev->drv->phy_id_mask;
|
||||
+
|
||||
pr_info_once("%s: %s PHY revision: 0x%02x, patch: %d\n",
|
||||
dev_name(&phydev->dev), phydev->drv->name, rev, patch);
|
||||
|
||||
@@ -192,6 +223,9 @@ static int bcm7xxx_28nm_config_init(stru
|
||||
case 0x10:
|
||||
ret = bcm7xxx_28nm_e0_plus_afe_config_init(phydev);
|
||||
break;
|
||||
+ case 0x01:
|
||||
+ ret = bcm7xxx_28nm_a0_patch_afe_config_init(phydev);
|
||||
+ break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -336,6 +370,7 @@ static int bcm7xxx_suspend(struct phy_de
|
||||
|
||||
static struct phy_driver bcm7xxx_driver[] = {
|
||||
BCM7XXX_28NM_GPHY(PHY_ID_BCM7250, "Broadcom BCM7250"),
|
||||
+ BCM7XXX_28NM_GPHY(PHY_ID_BCM7278, "Broadcom BCM7278"),
|
||||
BCM7XXX_28NM_GPHY(PHY_ID_BCM7364, "Broadcom BCM7364"),
|
||||
BCM7XXX_28NM_GPHY(PHY_ID_BCM7366, "Broadcom BCM7366"),
|
||||
BCM7XXX_28NM_GPHY(PHY_ID_BCM7439, "Broadcom BCM7439"),
|
||||
@@ -350,6 +385,7 @@ static struct phy_driver bcm7xxx_driver[
|
||||
|
||||
static struct mdio_device_id __maybe_unused bcm7xxx_tbl[] = {
|
||||
{ PHY_ID_BCM7250, 0xfffffff0, },
|
||||
+ { PHY_ID_BCM7278, 0xfffffff0, },
|
||||
{ PHY_ID_BCM7364, 0xfffffff0, },
|
||||
{ PHY_ID_BCM7366, 0xfffffff0, },
|
||||
{ PHY_ID_BCM7346, 0xfffffff0, },
|
||||
--- a/drivers/net/phy/broadcom.c
|
||||
+++ b/drivers/net/phy/broadcom.c
|
||||
@@ -30,6 +30,50 @@ MODULE_DESCRIPTION("Broadcom PHY driver"
|
||||
MODULE_AUTHOR("Maciej W. Rozycki");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
+static int bcm54210e_config_init(struct phy_device *phydev)
|
||||
+{
|
||||
+ int val;
|
||||
+
|
||||
+ val = bcm54xx_auxctl_read(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
|
||||
+ val &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN;
|
||||
+ val |= MII_BCM54XX_AUXCTL_MISC_WREN;
|
||||
+ bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC, val);
|
||||
+
|
||||
+ val = bcm_phy_read_shadow(phydev, BCM54810_SHD_CLK_CTL);
|
||||
+ val &= ~BCM54810_SHD_CLK_CTL_GTXCLK_EN;
|
||||
+ bcm_phy_write_shadow(phydev, BCM54810_SHD_CLK_CTL, val);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int bcm54612e_config_init(struct phy_device *phydev)
|
||||
+{
|
||||
+ /* Clear TX internal delay unless requested. */
|
||||
+ if ((phydev->interface != PHY_INTERFACE_MODE_RGMII_ID) &&
|
||||
+ (phydev->interface != PHY_INTERFACE_MODE_RGMII_TXID)) {
|
||||
+ /* Disable TXD to GTXCLK clock delay (default set) */
|
||||
+ /* Bit 9 is the only field in shadow register 00011 */
|
||||
+ bcm_phy_write_shadow(phydev, 0x03, 0);
|
||||
+ }
|
||||
+
|
||||
+ /* Clear RX internal delay unless requested. */
|
||||
+ if ((phydev->interface != PHY_INTERFACE_MODE_RGMII_ID) &&
|
||||
+ (phydev->interface != PHY_INTERFACE_MODE_RGMII_RXID)) {
|
||||
+ u16 reg;
|
||||
+
|
||||
+ reg = bcm54xx_auxctl_read(phydev,
|
||||
+ MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
|
||||
+ /* Disable RXD to RXC delay (default set) */
|
||||
+ reg &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN;
|
||||
+ /* Clear shadow selector field */
|
||||
+ reg &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MASK;
|
||||
+ bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC,
|
||||
+ MII_BCM54XX_AUXCTL_MISC_WREN | reg);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static int bcm54810_config(struct phy_device *phydev)
|
||||
{
|
||||
int rc, val;
|
||||
@@ -230,7 +274,15 @@ static int bcm54xx_config_init(struct ph
|
||||
(phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE))
|
||||
bcm54xx_adjust_rxrefclk(phydev);
|
||||
|
||||
- if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54810) {
|
||||
+ if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54210E) {
|
||||
+ err = bcm54210e_config_init(phydev);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+ } else if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54612E) {
|
||||
+ err = bcm54612e_config_init(phydev);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+ } else if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54810) {
|
||||
err = bcm54810_config(phydev);
|
||||
if (err)
|
||||
return err;
|
||||
@@ -375,41 +427,6 @@ static int bcm5481_config_aneg(struct ph
|
||||
return ret;
|
||||
}
|
||||
|
||||
-static int bcm54612e_config_aneg(struct phy_device *phydev)
|
||||
-{
|
||||
- int ret;
|
||||
-
|
||||
- /* First, auto-negotiate. */
|
||||
- ret = genphy_config_aneg(phydev);
|
||||
-
|
||||
- /* Clear TX internal delay unless requested. */
|
||||
- if ((phydev->interface != PHY_INTERFACE_MODE_RGMII_ID) &&
|
||||
- (phydev->interface != PHY_INTERFACE_MODE_RGMII_TXID)) {
|
||||
- /* Disable TXD to GTXCLK clock delay (default set) */
|
||||
- /* Bit 9 is the only field in shadow register 00011 */
|
||||
- bcm_phy_write_shadow(phydev, 0x03, 0);
|
||||
- }
|
||||
-
|
||||
- /* Clear RX internal delay unless requested. */
|
||||
- if ((phydev->interface != PHY_INTERFACE_MODE_RGMII_ID) &&
|
||||
- (phydev->interface != PHY_INTERFACE_MODE_RGMII_RXID)) {
|
||||
- u16 reg;
|
||||
-
|
||||
- /* Errata: reads require filling in the write selector field */
|
||||
- bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC,
|
||||
- MII_BCM54XX_AUXCTL_MISC_RDSEL_MISC);
|
||||
- reg = phy_read(phydev, MII_BCM54XX_AUX_CTL);
|
||||
- /* Disable RXD to RXC delay (default set) */
|
||||
- reg &= ~MII_BCM54XX_AUXCTL_MISC_RXD_RXC_SKEW;
|
||||
- /* Clear shadow selector field */
|
||||
- reg &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MASK;
|
||||
- bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC,
|
||||
- MII_BCM54XX_AUXCTL_MISC_WREN | reg);
|
||||
- }
|
||||
-
|
||||
- return ret;
|
||||
-}
|
||||
-
|
||||
static int brcm_phy_setbits(struct phy_device *phydev, int reg, int set)
|
||||
{
|
||||
int val;
|
||||
@@ -548,6 +565,19 @@ static struct phy_driver broadcom_driver
|
||||
.config_intr = bcm_phy_config_intr,
|
||||
.driver = { .owner = THIS_MODULE },
|
||||
}, {
|
||||
+ .phy_id = PHY_ID_BCM54210E,
|
||||
+ .phy_id_mask = 0xfffffff0,
|
||||
+ .name = "Broadcom BCM54210E",
|
||||
+ .features = PHY_GBIT_FEATURES |
|
||||
+ SUPPORTED_Pause | SUPPORTED_Asym_Pause,
|
||||
+ .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
|
||||
+ .config_init = bcm54xx_config_init,
|
||||
+ .config_aneg = genphy_config_aneg,
|
||||
+ .read_status = genphy_read_status,
|
||||
+ .ack_interrupt = bcm_phy_ack_intr,
|
||||
+ .config_intr = bcm_phy_config_intr,
|
||||
+ .driver = { .owner = THIS_MODULE },
|
||||
+}, {
|
||||
.phy_id = PHY_ID_BCM5461,
|
||||
.phy_id_mask = 0xfffffff0,
|
||||
.name = "Broadcom BCM5461",
|
||||
@@ -568,7 +598,7 @@ static struct phy_driver broadcom_driver
|
||||
SUPPORTED_Pause | SUPPORTED_Asym_Pause,
|
||||
.flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
|
||||
.config_init = bcm54xx_config_init,
|
||||
- .config_aneg = bcm54612e_config_aneg,
|
||||
+ .config_aneg = genphy_config_aneg,
|
||||
.read_status = genphy_read_status,
|
||||
.ack_interrupt = bcm_phy_ack_intr,
|
||||
.config_intr = bcm_phy_config_intr,
|
||||
@@ -708,6 +738,7 @@ module_phy_driver(broadcom_drivers);
|
||||
static struct mdio_device_id __maybe_unused broadcom_tbl[] = {
|
||||
{ PHY_ID_BCM5411, 0xfffffff0 },
|
||||
{ PHY_ID_BCM5421, 0xfffffff0 },
|
||||
+ { PHY_ID_BCM54210E, 0xfffffff0 },
|
||||
{ PHY_ID_BCM5461, 0xfffffff0 },
|
||||
{ PHY_ID_BCM54612E, 0xfffffff0 },
|
||||
{ PHY_ID_BCM54616S, 0xfffffff0 },
|
||||
--- a/include/linux/brcmphy.h
|
||||
+++ b/include/linux/brcmphy.h
|
||||
@@ -17,6 +17,7 @@
|
||||
#define PHY_ID_BCM5482 0x0143bcb0
|
||||
#define PHY_ID_BCM5411 0x00206070
|
||||
#define PHY_ID_BCM5421 0x002060e0
|
||||
+#define PHY_ID_BCM54210E 0x600d84a0
|
||||
#define PHY_ID_BCM5464 0x002060b0
|
||||
#define PHY_ID_BCM5461 0x002060c0
|
||||
#define PHY_ID_BCM54612E 0x03625e60
|
||||
@@ -24,6 +25,7 @@
|
||||
#define PHY_ID_BCM57780 0x03625d90
|
||||
|
||||
#define PHY_ID_BCM7250 0xae025280
|
||||
+#define PHY_ID_BCM7278 0xae0251a0
|
||||
#define PHY_ID_BCM7364 0xae025260
|
||||
#define PHY_ID_BCM7366 0x600d8490
|
||||
#define PHY_ID_BCM7346 0x600d8650
|
||||
@@ -103,18 +105,17 @@
|
||||
/*
|
||||
* AUXILIARY CONTROL SHADOW ACCESS REGISTERS. (PHY REG 0x18)
|
||||
*/
|
||||
-#define MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL 0x0000
|
||||
+#define MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL 0x00
|
||||
#define MII_BCM54XX_AUXCTL_ACTL_TX_6DB 0x0400
|
||||
#define MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA 0x0800
|
||||
|
||||
-#define MII_BCM54XX_AUXCTL_MISC_WREN 0x8000
|
||||
-#define MII_BCM54XX_AUXCTL_MISC_RXD_RXC_SKEW 0x0100
|
||||
-#define MII_BCM54XX_AUXCTL_MISC_FORCE_AMDIX 0x0200
|
||||
-#define MII_BCM54XX_AUXCTL_MISC_RDSEL_MISC 0x7000
|
||||
-#define MII_BCM54XX_AUXCTL_SHDWSEL_MISC 0x0007
|
||||
-#define MII_BCM54XX_AUXCTL_SHDWSEL_READ_SHIFT 12
|
||||
-#define MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN (1 << 8)
|
||||
+#define MII_BCM54XX_AUXCTL_SHDWSEL_MISC 0x07
|
||||
+#define MII_BCM54XX_AUXCTL_SHDWSEL_MISC_WIRESPEED_EN 0x0010
|
||||
+#define MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN 0x0100
|
||||
+#define MII_BCM54XX_AUXCTL_MISC_FORCE_AMDIX 0x0200
|
||||
+#define MII_BCM54XX_AUXCTL_MISC_WREN 0x8000
|
||||
|
||||
+#define MII_BCM54XX_AUXCTL_SHDWSEL_READ_SHIFT 12
|
||||
#define MII_BCM54XX_AUXCTL_SHDWSEL_MASK 0x0007
|
||||
|
||||
/*
|
@ -1,37 +0,0 @@
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Subject: [PATCH] net: phy: cherry-pick Broadcom drivers updates from v4.15
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
This includes following upstream commits:
|
||||
2355a6546a05 net: phy: broadcom: support new device flag for setting master mode
|
||||
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
---
|
||||
|
||||
--- a/drivers/net/phy/broadcom.c
|
||||
+++ b/drivers/net/phy/broadcom.c
|
||||
@@ -43,6 +43,12 @@ static int bcm54210e_config_init(struct
|
||||
val &= ~BCM54810_SHD_CLK_CTL_GTXCLK_EN;
|
||||
bcm_phy_write_shadow(phydev, BCM54810_SHD_CLK_CTL, val);
|
||||
|
||||
+ if (phydev->dev_flags & PHY_BRCM_EN_MASTER_MODE) {
|
||||
+ val = phy_read(phydev, MII_CTRL1000);
|
||||
+ val |= CTL1000_AS_MASTER | CTL1000_ENABLE_MASTER;
|
||||
+ phy_write(phydev, MII_CTRL1000, val);
|
||||
+ }
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
--- a/include/linux/brcmphy.h
|
||||
+++ b/include/linux/brcmphy.h
|
||||
@@ -59,6 +59,7 @@
|
||||
#define PHY_BRCM_EXT_IBND_TX_ENABLE 0x00002000
|
||||
#define PHY_BRCM_CLEAR_RGMII_MODE 0x00004000
|
||||
#define PHY_BRCM_DIS_TXCRXC_NOENRGY 0x00008000
|
||||
+#define PHY_BRCM_EN_MASTER_MODE 0x00010000
|
||||
|
||||
/* Broadcom BCM7xxx specific workarounds */
|
||||
#define PHY_BRCM_7XXX_REV(x) (((x) >> 8) & 0xff)
|
@ -1,179 +0,0 @@
|
||||
From 556351f14e74db4cd3ddde386457edce7bf0b27f Mon Sep 17 00:00:00 2001
|
||||
From: Vignesh R <vigneshr@ti.com>
|
||||
Date: Fri, 11 Dec 2015 09:39:56 +0530
|
||||
Subject: [PATCH] spi: introduce accelerated read support for spi flash devices
|
||||
|
||||
In addition to providing direct access to SPI bus, some spi controller
|
||||
hardwares (like ti-qspi) provide special port (like memory mapped port)
|
||||
that are optimized to improve SPI flash read performance.
|
||||
This means the controller can automatically send the SPI signals
|
||||
required to read data from the SPI flash device.
|
||||
For this, SPI controller needs to know flash specific information like
|
||||
read command to use, dummy bytes and address width.
|
||||
|
||||
Introduce spi_flash_read() interface to support accelerated read
|
||||
over SPI flash devices. SPI master drivers can implement this callback to
|
||||
support interfaces such as memory mapped read etc. m25p80 flash driver
|
||||
and other flash drivers can call this make use of such interfaces. The
|
||||
interface should only be used with SPI flashes and cannot be used with
|
||||
other SPI devices.
|
||||
|
||||
Signed-off-by: Vignesh R <vigneshr@ti.com>
|
||||
Signed-off-by: Mark Brown <broonie@kernel.org>
|
||||
---
|
||||
|
||||
--- a/drivers/spi/spi.c
|
||||
+++ b/drivers/spi/spi.c
|
||||
@@ -1135,6 +1135,7 @@ static void __spi_pump_messages(struct s
|
||||
}
|
||||
}
|
||||
|
||||
+ mutex_lock(&master->bus_lock_mutex);
|
||||
trace_spi_message_start(master->cur_msg);
|
||||
|
||||
if (master->prepare_message) {
|
||||
@@ -1144,6 +1145,7 @@ static void __spi_pump_messages(struct s
|
||||
"failed to prepare message: %d\n", ret);
|
||||
master->cur_msg->status = ret;
|
||||
spi_finalize_current_message(master);
|
||||
+ mutex_unlock(&master->bus_lock_mutex);
|
||||
return;
|
||||
}
|
||||
master->cur_msg_prepared = true;
|
||||
@@ -1153,6 +1155,7 @@ static void __spi_pump_messages(struct s
|
||||
if (ret) {
|
||||
master->cur_msg->status = ret;
|
||||
spi_finalize_current_message(master);
|
||||
+ mutex_unlock(&master->bus_lock_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1160,8 +1163,10 @@ static void __spi_pump_messages(struct s
|
||||
if (ret) {
|
||||
dev_err(&master->dev,
|
||||
"failed to transfer one message from queue\n");
|
||||
+ mutex_unlock(&master->bus_lock_mutex);
|
||||
return;
|
||||
}
|
||||
+ mutex_unlock(&master->bus_lock_mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2329,6 +2334,46 @@ int spi_async_locked(struct spi_device *
|
||||
EXPORT_SYMBOL_GPL(spi_async_locked);
|
||||
|
||||
|
||||
+int spi_flash_read(struct spi_device *spi,
|
||||
+ struct spi_flash_read_message *msg)
|
||||
+
|
||||
+{
|
||||
+ struct spi_master *master = spi->master;
|
||||
+ int ret;
|
||||
+
|
||||
+ if ((msg->opcode_nbits == SPI_NBITS_DUAL ||
|
||||
+ msg->addr_nbits == SPI_NBITS_DUAL) &&
|
||||
+ !(spi->mode & (SPI_TX_DUAL | SPI_TX_QUAD)))
|
||||
+ return -EINVAL;
|
||||
+ if ((msg->opcode_nbits == SPI_NBITS_QUAD ||
|
||||
+ msg->addr_nbits == SPI_NBITS_QUAD) &&
|
||||
+ !(spi->mode & SPI_TX_QUAD))
|
||||
+ return -EINVAL;
|
||||
+ if (msg->data_nbits == SPI_NBITS_DUAL &&
|
||||
+ !(spi->mode & (SPI_RX_DUAL | SPI_RX_QUAD)))
|
||||
+ return -EINVAL;
|
||||
+ if (msg->data_nbits == SPI_NBITS_QUAD &&
|
||||
+ !(spi->mode & SPI_RX_QUAD))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (master->auto_runtime_pm) {
|
||||
+ ret = pm_runtime_get_sync(master->dev.parent);
|
||||
+ if (ret < 0) {
|
||||
+ dev_err(&master->dev, "Failed to power device: %d\n",
|
||||
+ ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+ }
|
||||
+ mutex_lock(&master->bus_lock_mutex);
|
||||
+ ret = master->spi_flash_read(spi, msg);
|
||||
+ mutex_unlock(&master->bus_lock_mutex);
|
||||
+ if (master->auto_runtime_pm)
|
||||
+ pm_runtime_put(master->dev.parent);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(spi_flash_read);
|
||||
+
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* Utility methods for SPI master protocol drivers, layered on
|
||||
--- a/include/linux/spi/spi.h
|
||||
+++ b/include/linux/spi/spi.h
|
||||
@@ -25,6 +25,7 @@
|
||||
struct dma_chan;
|
||||
struct spi_master;
|
||||
struct spi_transfer;
|
||||
+struct spi_flash_read_message;
|
||||
|
||||
/*
|
||||
* INTERFACES between SPI master-side drivers and SPI infrastructure.
|
||||
@@ -361,6 +362,8 @@ static inline void spi_unregister_driver
|
||||
* @handle_err: the subsystem calls the driver to handle an error that occurs
|
||||
* in the generic implementation of transfer_one_message().
|
||||
* @unprepare_message: undo any work done by prepare_message().
|
||||
+ * @spi_flash_read: to support spi-controller hardwares that provide
|
||||
+ * accelerated interface to read from flash devices.
|
||||
* @cs_gpios: Array of GPIOs to use as chip select lines; one per CS
|
||||
* number. Any individual value may be -ENOENT for CS lines that
|
||||
* are not GPIOs (driven by the SPI controller itself).
|
||||
@@ -507,6 +510,8 @@ struct spi_master {
|
||||
struct spi_message *message);
|
||||
int (*unprepare_message)(struct spi_master *master,
|
||||
struct spi_message *message);
|
||||
+ int (*spi_flash_read)(struct spi_device *spi,
|
||||
+ struct spi_flash_read_message *msg);
|
||||
|
||||
/*
|
||||
* These hooks are for drivers that use a generic implementation
|
||||
@@ -999,6 +1004,42 @@ static inline ssize_t spi_w8r16be(struct
|
||||
return be16_to_cpu(result);
|
||||
}
|
||||
|
||||
+/**
|
||||
+ * struct spi_flash_read_message - flash specific information for
|
||||
+ * spi-masters that provide accelerated flash read interfaces
|
||||
+ * @buf: buffer to read data
|
||||
+ * @from: offset within the flash from where data is to be read
|
||||
+ * @len: length of data to be read
|
||||
+ * @retlen: actual length of data read
|
||||
+ * @read_opcode: read_opcode to be used to communicate with flash
|
||||
+ * @addr_width: number of address bytes
|
||||
+ * @dummy_bytes: number of dummy bytes
|
||||
+ * @opcode_nbits: number of lines to send opcode
|
||||
+ * @addr_nbits: number of lines to send address
|
||||
+ * @data_nbits: number of lines for data
|
||||
+ */
|
||||
+struct spi_flash_read_message {
|
||||
+ void *buf;
|
||||
+ loff_t from;
|
||||
+ size_t len;
|
||||
+ size_t retlen;
|
||||
+ u8 read_opcode;
|
||||
+ u8 addr_width;
|
||||
+ u8 dummy_bytes;
|
||||
+ u8 opcode_nbits;
|
||||
+ u8 addr_nbits;
|
||||
+ u8 data_nbits;
|
||||
+};
|
||||
+
|
||||
+/* SPI core interface for flash read support */
|
||||
+static inline bool spi_flash_read_supported(struct spi_device *spi)
|
||||
+{
|
||||
+ return spi->master->spi_flash_read ? true : false;
|
||||
+}
|
||||
+
|
||||
+int spi_flash_read(struct spi_device *spi,
|
||||
+ struct spi_flash_read_message *msg);
|
||||
+
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
@ -1,157 +0,0 @@
|
||||
From a7b221d8f0d75511c5f959584712a5dd35f88a86 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
|
||||
Date: Mon, 18 Apr 2016 14:39:30 +0200
|
||||
Subject: [PATCH] spi: bcm53xx: add spi_flash_read callback for MMIO-based
|
||||
reads
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
This implements more efficient reads of SPI-attached flash content.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
|
||||
Signed-off-by: Mark Brown <broonie@kernel.org>
|
||||
---
|
||||
|
||||
--- a/drivers/spi/spi-bcm53xx.c
|
||||
+++ b/drivers/spi/spi-bcm53xx.c
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "spi-bcm53xx.h"
|
||||
|
||||
#define BCM53XXSPI_MAX_SPI_BAUD 13500000 /* 216 MHz? */
|
||||
+#define BCM53XXSPI_FLASH_WINDOW SZ_32M
|
||||
|
||||
/* The longest observed required wait was 19 ms */
|
||||
#define BCM53XXSPI_SPE_TIMEOUT_MS 80
|
||||
@@ -17,8 +18,10 @@
|
||||
struct bcm53xxspi {
|
||||
struct bcma_device *core;
|
||||
struct spi_master *master;
|
||||
+ void __iomem *mmio_base;
|
||||
|
||||
size_t read_offset;
|
||||
+ bool bspi; /* Boot SPI mode with memory mapping */
|
||||
};
|
||||
|
||||
static inline u32 bcm53xxspi_read(struct bcm53xxspi *b53spi, u16 offset)
|
||||
@@ -32,6 +35,50 @@ static inline void bcm53xxspi_write(stru
|
||||
bcma_write32(b53spi->core, offset, value);
|
||||
}
|
||||
|
||||
+static void bcm53xxspi_disable_bspi(struct bcm53xxspi *b53spi)
|
||||
+{
|
||||
+ struct device *dev = &b53spi->core->dev;
|
||||
+ unsigned long deadline;
|
||||
+ u32 tmp;
|
||||
+
|
||||
+ if (!b53spi->bspi)
|
||||
+ return;
|
||||
+
|
||||
+ tmp = bcm53xxspi_read(b53spi, B53SPI_BSPI_MAST_N_BOOT_CTRL);
|
||||
+ if (tmp & 0x1)
|
||||
+ return;
|
||||
+
|
||||
+ deadline = jiffies + usecs_to_jiffies(200);
|
||||
+ do {
|
||||
+ tmp = bcm53xxspi_read(b53spi, B53SPI_BSPI_BUSY_STATUS);
|
||||
+ if (!(tmp & 0x1)) {
|
||||
+ bcm53xxspi_write(b53spi, B53SPI_BSPI_MAST_N_BOOT_CTRL,
|
||||
+ 0x1);
|
||||
+ ndelay(200);
|
||||
+ b53spi->bspi = false;
|
||||
+ return;
|
||||
+ }
|
||||
+ udelay(1);
|
||||
+ } while (!time_after_eq(jiffies, deadline));
|
||||
+
|
||||
+ dev_warn(dev, "Timeout disabling BSPI\n");
|
||||
+}
|
||||
+
|
||||
+static void bcm53xxspi_enable_bspi(struct bcm53xxspi *b53spi)
|
||||
+{
|
||||
+ u32 tmp;
|
||||
+
|
||||
+ if (b53spi->bspi)
|
||||
+ return;
|
||||
+
|
||||
+ tmp = bcm53xxspi_read(b53spi, B53SPI_BSPI_MAST_N_BOOT_CTRL);
|
||||
+ if (!(tmp & 0x1))
|
||||
+ return;
|
||||
+
|
||||
+ bcm53xxspi_write(b53spi, B53SPI_BSPI_MAST_N_BOOT_CTRL, 0x0);
|
||||
+ b53spi->bspi = true;
|
||||
+}
|
||||
+
|
||||
static inline unsigned int bcm53xxspi_calc_timeout(size_t len)
|
||||
{
|
||||
/* Do some magic calculation based on length and buad. Add 10% and 1. */
|
||||
@@ -176,6 +223,8 @@ static int bcm53xxspi_transfer_one(struc
|
||||
u8 *buf;
|
||||
size_t left;
|
||||
|
||||
+ bcm53xxspi_disable_bspi(b53spi);
|
||||
+
|
||||
if (t->tx_buf) {
|
||||
buf = (u8 *)t->tx_buf;
|
||||
left = t->len;
|
||||
@@ -206,6 +255,22 @@ static int bcm53xxspi_transfer_one(struc
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int bcm53xxspi_flash_read(struct spi_device *spi,
|
||||
+ struct spi_flash_read_message *msg)
|
||||
+{
|
||||
+ struct bcm53xxspi *b53spi = spi_master_get_devdata(spi->master);
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ if (msg->from + msg->len > BCM53XXSPI_FLASH_WINDOW)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ bcm53xxspi_enable_bspi(b53spi);
|
||||
+ memcpy_fromio(msg->buf, b53spi->mmio_base + msg->from, msg->len);
|
||||
+ msg->retlen = msg->len;
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
/**************************************************
|
||||
* BCMA
|
||||
**************************************************/
|
||||
@@ -222,6 +287,7 @@ MODULE_DEVICE_TABLE(bcma, bcm53xxspi_bcm
|
||||
|
||||
static int bcm53xxspi_bcma_probe(struct bcma_device *core)
|
||||
{
|
||||
+ struct device *dev = &core->dev;
|
||||
struct bcm53xxspi *b53spi;
|
||||
struct spi_master *master;
|
||||
int err;
|
||||
@@ -231,7 +297,7 @@ static int bcm53xxspi_bcma_probe(struct
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
- master = spi_alloc_master(&core->dev, sizeof(*b53spi));
|
||||
+ master = spi_alloc_master(dev, sizeof(*b53spi));
|
||||
if (!master)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -239,11 +305,19 @@ static int bcm53xxspi_bcma_probe(struct
|
||||
b53spi->master = master;
|
||||
b53spi->core = core;
|
||||
|
||||
+ if (core->addr_s[0])
|
||||
+ b53spi->mmio_base = devm_ioremap(dev, core->addr_s[0],
|
||||
+ BCM53XXSPI_FLASH_WINDOW);
|
||||
+ b53spi->bspi = true;
|
||||
+ bcm53xxspi_disable_bspi(b53spi);
|
||||
+
|
||||
master->transfer_one = bcm53xxspi_transfer_one;
|
||||
+ if (b53spi->mmio_base)
|
||||
+ master->spi_flash_read = bcm53xxspi_flash_read;
|
||||
|
||||
bcma_set_drvdata(core, b53spi);
|
||||
|
||||
- err = devm_spi_register_master(&core->dev, master);
|
||||
+ err = devm_spi_register_master(dev, master);
|
||||
if (err) {
|
||||
spi_master_put(master);
|
||||
bcma_set_drvdata(core, NULL);
|
@ -1,179 +0,0 @@
|
||||
From 69bec725985324e79b1c47ea287815ac4ddb0521 Mon Sep 17 00:00:00 2001
|
||||
From: Peter Chen <peter.chen@freescale.com>
|
||||
Date: Fri, 19 Feb 2016 17:26:15 +0800
|
||||
Subject: [PATCH] USB: core: let USB device know device node
|
||||
|
||||
Although most of USB devices are hot-plug's, there are still some devices
|
||||
are hard wired on the board, eg, for HSIC and SSIC interface USB devices.
|
||||
If these kinds of USB devices are multiple functions, and they can supply
|
||||
other interfaces like i2c, gpios for other devices, we may need to
|
||||
describe these at device tree.
|
||||
|
||||
In this commit, it uses "reg" in dts as physical port number to match
|
||||
the phyiscal port number decided by USB core, if they are the same,
|
||||
then the device node is for the device we are creating for USB core.
|
||||
|
||||
Signed-off-by: Peter Chen <peter.chen@freescale.com>
|
||||
Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
|
||||
Acked-by: Alan Stern <stern@rowland.harvard.edu>
|
||||
Acked-by: Rob Herring <robh@kernel.org>
|
||||
Acked-by: Arnd Bergmann <arnd@arndb.de>
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||
---
|
||||
.../devicetree/bindings/usb/usb-device.txt | 28 +++++++++++++
|
||||
drivers/usb/core/Makefile | 2 +-
|
||||
drivers/usb/core/of.c | 47 ++++++++++++++++++++++
|
||||
drivers/usb/core/usb.c | 10 +++++
|
||||
include/linux/usb/of.h | 7 ++++
|
||||
5 files changed, 93 insertions(+), 1 deletion(-)
|
||||
create mode 100644 Documentation/devicetree/bindings/usb/usb-device.txt
|
||||
create mode 100644 drivers/usb/core/of.c
|
||||
|
||||
--- /dev/null
|
||||
+++ b/Documentation/devicetree/bindings/usb/usb-device.txt
|
||||
@@ -0,0 +1,28 @@
|
||||
+Generic USB Device Properties
|
||||
+
|
||||
+Usually, we only use device tree for hard wired USB device.
|
||||
+The reference binding doc is from:
|
||||
+http://www.firmware.org/1275/bindings/usb/usb-1_0.ps
|
||||
+
|
||||
+Required properties:
|
||||
+- compatible: usbVID,PID. The textual representation of VID, PID shall
|
||||
+ be in lower case hexadecimal with leading zeroes suppressed. The
|
||||
+ other compatible strings from the above standard binding could also
|
||||
+ be used, but a device adhering to this binding may leave out all except
|
||||
+ for usbVID,PID.
|
||||
+- reg: the port number which this device is connecting to, the range
|
||||
+ is 1-31.
|
||||
+
|
||||
+Example:
|
||||
+
|
||||
+&usb1 {
|
||||
+ status = "okay";
|
||||
+
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
+
|
||||
+ hub: genesys@1 {
|
||||
+ compatible = "usb5e3,608";
|
||||
+ reg = <1>;
|
||||
+ };
|
||||
+}
|
||||
--- a/drivers/usb/core/Makefile
|
||||
+++ b/drivers/usb/core/Makefile
|
||||
@@ -5,7 +5,7 @@
|
||||
usbcore-y := usb.o hub.o hcd.o urb.o message.o driver.o
|
||||
usbcore-y += config.o file.o buffer.o sysfs.o endpoint.o
|
||||
usbcore-y += devio.o notify.o generic.o quirks.o devices.o
|
||||
-usbcore-y += port.o
|
||||
+usbcore-y += port.o of.o
|
||||
|
||||
usbcore-$(CONFIG_PCI) += hcd-pci.o
|
||||
usbcore-$(CONFIG_ACPI) += usb-acpi.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/usb/core/of.c
|
||||
@@ -0,0 +1,47 @@
|
||||
+/*
|
||||
+ * of.c The helpers for hcd device tree support
|
||||
+ *
|
||||
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
|
||||
+ * Author: Peter Chen <peter.chen@freescale.com>
|
||||
+ *
|
||||
+ * This program is free software: you can redistribute it and/or modify
|
||||
+ * it under the terms of the GNU General Public License version 2 of
|
||||
+ * the License as published by the Free Software Foundation.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful,
|
||||
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
+ * GNU General Public License for more details.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU General Public License
|
||||
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/of.h>
|
||||
+
|
||||
+/**
|
||||
+ * usb_of_get_child_node - Find the device node match port number
|
||||
+ * @parent: the parent device node
|
||||
+ * @portnum: the port number which device is connecting
|
||||
+ *
|
||||
+ * Find the node from device tree according to its port number.
|
||||
+ *
|
||||
+ * Return: On success, a pointer to the device node, %NULL on failure.
|
||||
+ */
|
||||
+struct device_node *usb_of_get_child_node(struct device_node *parent,
|
||||
+ int portnum)
|
||||
+{
|
||||
+ struct device_node *node;
|
||||
+ u32 port;
|
||||
+
|
||||
+ for_each_child_of_node(parent, node) {
|
||||
+ if (!of_property_read_u32(node, "reg", &port)) {
|
||||
+ if (port == portnum)
|
||||
+ return node;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(usb_of_get_child_node);
|
||||
+
|
||||
--- a/drivers/usb/core/usb.c
|
||||
+++ b/drivers/usb/core/usb.c
|
||||
@@ -36,6 +36,7 @@
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/debugfs.h>
|
||||
+#include <linux/usb/of.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <linux/scatterlist.h>
|
||||
@@ -469,6 +470,7 @@ struct usb_device *usb_alloc_dev(struct
|
||||
dev->route = 0;
|
||||
|
||||
dev->dev.parent = bus->controller;
|
||||
+ dev->dev.of_node = bus->controller->of_node;
|
||||
dev_set_name(&dev->dev, "usb%d", bus->busnum);
|
||||
root_hub = 1;
|
||||
} else {
|
||||
@@ -493,6 +495,14 @@ struct usb_device *usb_alloc_dev(struct
|
||||
dev->dev.parent = &parent->dev;
|
||||
dev_set_name(&dev->dev, "%d-%s", bus->busnum, dev->devpath);
|
||||
|
||||
+ if (!parent->parent) {
|
||||
+ /* device under root hub's port */
|
||||
+ port1 = usb_hcd_find_raw_port_number(usb_hcd,
|
||||
+ port1);
|
||||
+ }
|
||||
+ dev->dev.of_node = usb_of_get_child_node(parent->dev.of_node,
|
||||
+ port1);
|
||||
+
|
||||
/* hub driver sets up TT records */
|
||||
}
|
||||
|
||||
--- a/include/linux/usb/of.h
|
||||
+++ b/include/linux/usb/of.h
|
||||
@@ -15,6 +15,8 @@
|
||||
bool of_usb_host_tpl_support(struct device_node *np);
|
||||
int of_usb_update_otg_caps(struct device_node *np,
|
||||
struct usb_otg_caps *otg_caps);
|
||||
+struct device_node *usb_of_get_child_node(struct device_node *parent,
|
||||
+ int portnum);
|
||||
#else
|
||||
static inline bool of_usb_host_tpl_support(struct device_node *np)
|
||||
{
|
||||
@@ -25,6 +27,11 @@ static inline int of_usb_update_otg_caps
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
+static inline struct device_node *usb_of_get_child_node
|
||||
+ (struct device_node *parent, int portnum)
|
||||
+{
|
||||
+ return NULL;
|
||||
+}
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_USB_SUPPORT)
|
@ -1,108 +0,0 @@
|
||||
From 7222c832254a75dcd67d683df75753d4a4e125bb Mon Sep 17 00:00:00 2001
|
||||
From: Nicolai Stange <nicstange@gmail.com>
|
||||
Date: Thu, 17 Mar 2016 23:53:02 +0100
|
||||
Subject: [PATCH] usb/core: usb_alloc_dev(): fix setting of ->portnum
|
||||
|
||||
With commit 69bec7259853 ("USB: core: let USB device know device node"),
|
||||
the port1 argument of usb_alloc_dev() gets overwritten as follows:
|
||||
|
||||
... usb_alloc_dev(..., unsigned port1)
|
||||
{
|
||||
...
|
||||
if (!parent->parent) {
|
||||
port1 = usb_hcd_find_raw_port_number(..., port1);
|
||||
}
|
||||
...
|
||||
}
|
||||
|
||||
Later on, this now overwritten port1 gets assigned to ->portnum:
|
||||
|
||||
dev->portnum = port1;
|
||||
|
||||
However, since xhci_find_raw_port_number() isn't idempotent, the
|
||||
aforementioned commit causes a number of KASAN splats like the following:
|
||||
|
||||
BUG: KASAN: slab-out-of-bounds in xhci_find_raw_port_number+0x98/0x170
|
||||
at addr ffff8801d9311670
|
||||
Read of size 8 by task kworker/2:1/87
|
||||
[...]
|
||||
Workqueue: usb_hub_wq hub_event
|
||||
0000000000000188 000000005814b877 ffff8800cba17588 ffffffff8191447e
|
||||
0000000041b58ab3 ffffffff82a03209 ffffffff819143a2 ffffffff82a252f4
|
||||
ffff8801d93115e0 0000000000000188 ffff8801d9311628 ffff8800cba17588
|
||||
Call Trace:
|
||||
[<ffffffff8191447e>] dump_stack+0xdc/0x15e
|
||||
[<ffffffff819143a2>] ? _atomic_dec_and_lock+0xa2/0xa2
|
||||
[<ffffffff814e2cd1>] ? print_section+0x61/0xb0
|
||||
[<ffffffff814e4939>] print_trailer+0x179/0x2c0
|
||||
[<ffffffff814f0d84>] object_err+0x34/0x40
|
||||
[<ffffffff814f4388>] kasan_report_error+0x2f8/0x8b0
|
||||
[<ffffffff814eb91e>] ? __slab_alloc+0x5e/0x90
|
||||
[<ffffffff812178c0>] ? __lock_is_held+0x90/0x130
|
||||
[<ffffffff814f5091>] kasan_report+0x71/0xa0
|
||||
[<ffffffff814ec082>] ? kmem_cache_alloc_trace+0x212/0x560
|
||||
[<ffffffff81d99468>] ? xhci_find_raw_port_number+0x98/0x170
|
||||
[<ffffffff814f33d4>] __asan_load8+0x64/0x70
|
||||
[<ffffffff81d99468>] xhci_find_raw_port_number+0x98/0x170
|
||||
[<ffffffff81db0105>] xhci_setup_addressable_virt_dev+0x235/0xa10
|
||||
[<ffffffff81d9ea51>] xhci_setup_device+0x3c1/0x1430
|
||||
[<ffffffff8121cddd>] ? trace_hardirqs_on+0xd/0x10
|
||||
[<ffffffff81d9fac0>] ? xhci_setup_device+0x1430/0x1430
|
||||
[<ffffffff81d9fad3>] xhci_address_device+0x13/0x20
|
||||
[<ffffffff81d2081a>] hub_port_init+0x55a/0x1550
|
||||
[<ffffffff81d28705>] hub_event+0xef5/0x24d0
|
||||
[<ffffffff81d27810>] ? hub_port_debounce+0x2f0/0x2f0
|
||||
[<ffffffff8195e1ee>] ? debug_object_deactivate+0x1be/0x270
|
||||
[<ffffffff81210203>] ? print_rt_rq+0x53/0x2d0
|
||||
[<ffffffff8121657d>] ? trace_hardirqs_off+0xd/0x10
|
||||
[<ffffffff8226acfb>] ? _raw_spin_unlock_irqrestore+0x5b/0x60
|
||||
[<ffffffff81250000>] ? irq_domain_set_hwirq_and_chip+0x30/0xb0
|
||||
[<ffffffff81256339>] ? debug_lockdep_rcu_enabled+0x39/0x40
|
||||
[<ffffffff812178c0>] ? __lock_is_held+0x90/0x130
|
||||
[<ffffffff81196877>] process_one_work+0x567/0xec0
|
||||
[...]
|
||||
|
||||
Afterwards, xhci reports some functional errors:
|
||||
|
||||
xhci_hcd 0000:00:14.0: ERROR: unexpected setup address command completion
|
||||
code 0x11.
|
||||
xhci_hcd 0000:00:14.0: ERROR: unexpected setup address command completion
|
||||
code 0x11.
|
||||
usb 4-3: device not accepting address 2, error -22
|
||||
|
||||
Fix this by not overwriting the port1 argument in usb_alloc_dev(), but
|
||||
storing the raw port number as required by OF in an additional variable,
|
||||
raw_port.
|
||||
|
||||
Fixes: 69bec7259853 ("USB: core: let USB device know device node")
|
||||
Signed-off-by: Nicolai Stange <nicstange@gmail.com>
|
||||
Acked-by: Alan Stern <stern@rowland.harvard.edu>
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||
---
|
||||
drivers/usb/core/usb.c | 5 +++--
|
||||
1 file changed, 3 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/usb/core/usb.c
|
||||
+++ b/drivers/usb/core/usb.c
|
||||
@@ -423,6 +423,7 @@ struct usb_device *usb_alloc_dev(struct
|
||||
struct usb_device *dev;
|
||||
struct usb_hcd *usb_hcd = bus_to_hcd(bus);
|
||||
unsigned root_hub = 0;
|
||||
+ unsigned raw_port = port1;
|
||||
|
||||
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
|
||||
if (!dev)
|
||||
@@ -497,11 +498,11 @@ struct usb_device *usb_alloc_dev(struct
|
||||
|
||||
if (!parent->parent) {
|
||||
/* device under root hub's port */
|
||||
- port1 = usb_hcd_find_raw_port_number(usb_hcd,
|
||||
+ raw_port = usb_hcd_find_raw_port_number(usb_hcd,
|
||||
port1);
|
||||
}
|
||||
dev->dev.of_node = usb_of_get_child_node(parent->dev.of_node,
|
||||
- port1);
|
||||
+ raw_port);
|
||||
|
||||
/* hub driver sets up TT records */
|
||||
}
|
@ -1,182 +0,0 @@
|
||||
From 4143804c4fdef40358c654d1fb2271a1a0f1fedf Mon Sep 17 00:00:00 2001
|
||||
From: Stephen Boyd <sboyd@codeaurora.org>
|
||||
Date: Fri, 5 Feb 2016 17:02:52 -0800
|
||||
Subject: [PATCH] clk: Add {devm_}clk_hw_{register,unregister}() APIs
|
||||
|
||||
We've largely split the clk consumer and provider APIs along
|
||||
struct clk and struct clk_hw, but clk_register() still returns a
|
||||
struct clk pointer for each struct clk_hw that's registered.
|
||||
Eventually we'd like to only allocate struct clks when there's a
|
||||
user, because struct clk is per-user now, so clk_register() needs
|
||||
to change.
|
||||
|
||||
Let's add new APIs to register struct clk_hws, but this time
|
||||
we'll hide the struct clk from the caller by returning an int
|
||||
error code. Also add an unregistration API that takes the clk_hw
|
||||
structure that was passed to the registration API. This way
|
||||
provider drivers never have to deal with a struct clk pointer
|
||||
unless they're using the clk consumer APIs.
|
||||
|
||||
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
|
||||
---
|
||||
Documentation/driver-model/devres.txt | 1 +
|
||||
drivers/clk/clk.c | 86 +++++++++++++++++++++++++++++++++++
|
||||
include/linux/clk-provider.h | 6 +++
|
||||
3 files changed, 93 insertions(+)
|
||||
|
||||
--- a/Documentation/driver-model/devres.txt
|
||||
+++ b/Documentation/driver-model/devres.txt
|
||||
@@ -236,6 +236,7 @@ certainly invest a bit more effort into
|
||||
CLOCK
|
||||
devm_clk_get()
|
||||
devm_clk_put()
|
||||
+ devm_clk_hw_register()
|
||||
|
||||
DMA
|
||||
dmam_alloc_coherent()
|
||||
--- a/drivers/clk/clk.c
|
||||
+++ b/drivers/clk/clk.c
|
||||
@@ -2595,6 +2595,22 @@ fail_out:
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_register);
|
||||
|
||||
+/**
|
||||
+ * clk_hw_register - register a clk_hw and return an error code
|
||||
+ * @dev: device that is registering this clock
|
||||
+ * @hw: link to hardware-specific clock data
|
||||
+ *
|
||||
+ * clk_hw_register is the primary interface for populating the clock tree with
|
||||
+ * new clock nodes. It returns an integer equal to zero indicating success or
|
||||
+ * less than zero indicating failure. Drivers must test for an error code after
|
||||
+ * calling clk_hw_register().
|
||||
+ */
|
||||
+int clk_hw_register(struct device *dev, struct clk_hw *hw)
|
||||
+{
|
||||
+ return PTR_ERR_OR_ZERO(clk_register(dev, hw));
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(clk_hw_register);
|
||||
+
|
||||
/* Free memory allocated for a clock. */
|
||||
static void __clk_release(struct kref *ref)
|
||||
{
|
||||
@@ -2696,11 +2712,26 @@ void clk_unregister(struct clk *clk)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_unregister);
|
||||
|
||||
+/**
|
||||
+ * clk_hw_unregister - unregister a currently registered clk_hw
|
||||
+ * @hw: hardware-specific clock data to unregister
|
||||
+ */
|
||||
+void clk_hw_unregister(struct clk_hw *hw)
|
||||
+{
|
||||
+ clk_unregister(hw->clk);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(clk_hw_unregister);
|
||||
+
|
||||
static void devm_clk_release(struct device *dev, void *res)
|
||||
{
|
||||
clk_unregister(*(struct clk **)res);
|
||||
}
|
||||
|
||||
+static void devm_clk_hw_release(struct device *dev, void *res)
|
||||
+{
|
||||
+ clk_hw_unregister(*(struct clk_hw **)res);
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* devm_clk_register - resource managed clk_register()
|
||||
* @dev: device that is registering this clock
|
||||
@@ -2731,6 +2762,36 @@ struct clk *devm_clk_register(struct dev
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_clk_register);
|
||||
|
||||
+/**
|
||||
+ * devm_clk_hw_register - resource managed clk_hw_register()
|
||||
+ * @dev: device that is registering this clock
|
||||
+ * @hw: link to hardware-specific clock data
|
||||
+ *
|
||||
+ * Managed clk_hw_register(). Clocks returned from this function are
|
||||
+ * automatically clk_hw_unregister()ed on driver detach. See clk_hw_register()
|
||||
+ * for more information.
|
||||
+ */
|
||||
+int devm_clk_hw_register(struct device *dev, struct clk_hw *hw)
|
||||
+{
|
||||
+ struct clk_hw **hwp;
|
||||
+ int ret;
|
||||
+
|
||||
+ hwp = devres_alloc(devm_clk_hw_release, sizeof(*hwp), GFP_KERNEL);
|
||||
+ if (!hwp)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ ret = clk_hw_register(dev, hw);
|
||||
+ if (!ret) {
|
||||
+ *hwp = hw;
|
||||
+ devres_add(dev, hwp);
|
||||
+ } else {
|
||||
+ devres_free(hwp);
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(devm_clk_hw_register);
|
||||
+
|
||||
static int devm_clk_match(struct device *dev, void *res, void *data)
|
||||
{
|
||||
struct clk *c = res;
|
||||
@@ -2739,6 +2800,15 @@ static int devm_clk_match(struct device
|
||||
return c == data;
|
||||
}
|
||||
|
||||
+static int devm_clk_hw_match(struct device *dev, void *res, void *data)
|
||||
+{
|
||||
+ struct clk_hw *hw = res;
|
||||
+
|
||||
+ if (WARN_ON(!hw))
|
||||
+ return 0;
|
||||
+ return hw == data;
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* devm_clk_unregister - resource managed clk_unregister()
|
||||
* @clk: clock to unregister
|
||||
@@ -2753,6 +2823,22 @@ void devm_clk_unregister(struct device *
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_clk_unregister);
|
||||
|
||||
+/**
|
||||
+ * devm_clk_hw_unregister - resource managed clk_hw_unregister()
|
||||
+ * @dev: device that is unregistering the hardware-specific clock data
|
||||
+ * @hw: link to hardware-specific clock data
|
||||
+ *
|
||||
+ * Unregister a clk_hw registered with devm_clk_hw_register(). Normally
|
||||
+ * this function will not need to be called and the resource management
|
||||
+ * code will ensure that the resource is freed.
|
||||
+ */
|
||||
+void devm_clk_hw_unregister(struct device *dev, struct clk_hw *hw)
|
||||
+{
|
||||
+ WARN_ON(devres_release(dev, devm_clk_hw_release, devm_clk_hw_match,
|
||||
+ hw));
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(devm_clk_hw_unregister);
|
||||
+
|
||||
/*
|
||||
* clkdev helpers
|
||||
*/
|
||||
--- a/include/linux/clk-provider.h
|
||||
+++ b/include/linux/clk-provider.h
|
||||
@@ -639,9 +639,15 @@ void of_gpio_mux_clk_setup(struct device
|
||||
struct clk *clk_register(struct device *dev, struct clk_hw *hw);
|
||||
struct clk *devm_clk_register(struct device *dev, struct clk_hw *hw);
|
||||
|
||||
+int __must_check clk_hw_register(struct device *dev, struct clk_hw *hw);
|
||||
+int __must_check devm_clk_hw_register(struct device *dev, struct clk_hw *hw);
|
||||
+
|
||||
void clk_unregister(struct clk *clk);
|
||||
void devm_clk_unregister(struct device *dev, struct clk *clk);
|
||||
|
||||
+void clk_hw_unregister(struct clk_hw *hw);
|
||||
+void devm_clk_hw_unregister(struct device *dev, struct clk_hw *hw);
|
||||
+
|
||||
/* helper functions */
|
||||
const char *__clk_get_name(const struct clk *clk);
|
||||
const char *clk_hw_get_name(const struct clk_hw *hw);
|
@ -1,234 +0,0 @@
|
||||
From 0861e5b8cf80038e91942f1005c8dfce79d18c38 Mon Sep 17 00:00:00 2001
|
||||
From: Stephen Boyd <sboyd@codeaurora.org>
|
||||
Date: Fri, 5 Feb 2016 17:38:26 -0800
|
||||
Subject: [PATCH] clk: Add clk_hw OF clk providers
|
||||
|
||||
Now that we have a clk registration API that doesn't return
|
||||
struct clks, we need to have some way to hand out struct clks via
|
||||
the clk_get() APIs that doesn't involve associating struct clk
|
||||
pointers with an OF node. Currently we ask the OF provider to
|
||||
give us a struct clk pointer for some clkspec, turn that struct
|
||||
clk into a struct clk_hw and then allocate a new struct clk to
|
||||
return to the caller.
|
||||
|
||||
Let's add a clk_hw based OF provider hook that returns a struct
|
||||
clk_hw directly, so that we skip the intermediate step of
|
||||
converting from struct clk to struct clk_hw. Eventually when
|
||||
we've converted all OF clk providers to struct clk_hw based APIs
|
||||
we can remove the struct clk based ones.
|
||||
|
||||
It should also be noted that we change the onecell provider to
|
||||
have a flex array instead of a pointer for the array of clk_hw
|
||||
pointers. This allows providers to allocate one structure of the
|
||||
correct length in one step instead of two.
|
||||
|
||||
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
|
||||
---
|
||||
drivers/clk/clk.c | 85 +++++++++++++++++++++++++++++++++++++++++---
|
||||
include/linux/clk-provider.h | 30 ++++++++++++++++
|
||||
2 files changed, 111 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/drivers/clk/clk.c
|
||||
+++ b/drivers/clk/clk.c
|
||||
@@ -3001,6 +3001,7 @@ struct of_clk_provider {
|
||||
|
||||
struct device_node *node;
|
||||
struct clk *(*get)(struct of_phandle_args *clkspec, void *data);
|
||||
+ struct clk_hw *(*get_hw)(struct of_phandle_args *clkspec, void *data);
|
||||
void *data;
|
||||
};
|
||||
|
||||
@@ -3017,6 +3018,12 @@ struct clk *of_clk_src_simple_get(struct
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_clk_src_simple_get);
|
||||
|
||||
+struct clk_hw *of_clk_hw_simple_get(struct of_phandle_args *clkspec, void *data)
|
||||
+{
|
||||
+ return data;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(of_clk_hw_simple_get);
|
||||
+
|
||||
struct clk *of_clk_src_onecell_get(struct of_phandle_args *clkspec, void *data)
|
||||
{
|
||||
struct clk_onecell_data *clk_data = data;
|
||||
@@ -3031,6 +3038,21 @@ struct clk *of_clk_src_onecell_get(struc
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_clk_src_onecell_get);
|
||||
|
||||
+struct clk_hw *
|
||||
+of_clk_hw_onecell_get(struct of_phandle_args *clkspec, void *data)
|
||||
+{
|
||||
+ struct clk_hw_onecell_data *hw_data = data;
|
||||
+ unsigned int idx = clkspec->args[0];
|
||||
+
|
||||
+ if (idx >= hw_data->num) {
|
||||
+ pr_err("%s: invalid index %u\n", __func__, idx);
|
||||
+ return ERR_PTR(-EINVAL);
|
||||
+ }
|
||||
+
|
||||
+ return hw_data->hws[idx];
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(of_clk_hw_onecell_get);
|
||||
+
|
||||
/**
|
||||
* of_clk_add_provider() - Register a clock provider for a node
|
||||
* @np: Device node pointer associated with clock provider
|
||||
@@ -3067,6 +3089,41 @@ int of_clk_add_provider(struct device_no
|
||||
EXPORT_SYMBOL_GPL(of_clk_add_provider);
|
||||
|
||||
/**
|
||||
+ * of_clk_add_hw_provider() - Register a clock provider for a node
|
||||
+ * @np: Device node pointer associated with clock provider
|
||||
+ * @get: callback for decoding clk_hw
|
||||
+ * @data: context pointer for @get callback.
|
||||
+ */
|
||||
+int of_clk_add_hw_provider(struct device_node *np,
|
||||
+ struct clk_hw *(*get)(struct of_phandle_args *clkspec,
|
||||
+ void *data),
|
||||
+ void *data)
|
||||
+{
|
||||
+ struct of_clk_provider *cp;
|
||||
+ int ret;
|
||||
+
|
||||
+ cp = kzalloc(sizeof(*cp), GFP_KERNEL);
|
||||
+ if (!cp)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ cp->node = of_node_get(np);
|
||||
+ cp->data = data;
|
||||
+ cp->get_hw = get;
|
||||
+
|
||||
+ mutex_lock(&of_clk_mutex);
|
||||
+ list_add(&cp->link, &of_clk_providers);
|
||||
+ mutex_unlock(&of_clk_mutex);
|
||||
+ pr_debug("Added clk_hw provider from %s\n", np->full_name);
|
||||
+
|
||||
+ ret = of_clk_set_defaults(np, true);
|
||||
+ if (ret < 0)
|
||||
+ of_clk_del_provider(np);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(of_clk_add_hw_provider);
|
||||
+
|
||||
+/**
|
||||
* of_clk_del_provider() - Remove a previously registered clock provider
|
||||
* @np: Device node pointer associated with clock provider
|
||||
*/
|
||||
@@ -3087,11 +3144,32 @@ void of_clk_del_provider(struct device_n
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_clk_del_provider);
|
||||
|
||||
+static struct clk_hw *
|
||||
+__of_clk_get_hw_from_provider(struct of_clk_provider *provider,
|
||||
+ struct of_phandle_args *clkspec)
|
||||
+{
|
||||
+ struct clk *clk;
|
||||
+ struct clk_hw *hw = ERR_PTR(-EPROBE_DEFER);
|
||||
+
|
||||
+ if (provider->get_hw) {
|
||||
+ hw = provider->get_hw(clkspec, provider->data);
|
||||
+ } else if (provider->get) {
|
||||
+ clk = provider->get(clkspec, provider->data);
|
||||
+ if (!IS_ERR(clk))
|
||||
+ hw = __clk_get_hw(clk);
|
||||
+ else
|
||||
+ hw = ERR_CAST(clk);
|
||||
+ }
|
||||
+
|
||||
+ return hw;
|
||||
+}
|
||||
+
|
||||
struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec,
|
||||
const char *dev_id, const char *con_id)
|
||||
{
|
||||
struct of_clk_provider *provider;
|
||||
struct clk *clk = ERR_PTR(-EPROBE_DEFER);
|
||||
+ struct clk_hw *hw = ERR_PTR(-EPROBE_DEFER);
|
||||
|
||||
if (!clkspec)
|
||||
return ERR_PTR(-EINVAL);
|
||||
@@ -3100,10 +3178,9 @@ struct clk *__of_clk_get_from_provider(s
|
||||
mutex_lock(&of_clk_mutex);
|
||||
list_for_each_entry(provider, &of_clk_providers, link) {
|
||||
if (provider->node == clkspec->np)
|
||||
- clk = provider->get(clkspec, provider->data);
|
||||
- if (!IS_ERR(clk)) {
|
||||
- clk = __clk_create_clk(__clk_get_hw(clk), dev_id,
|
||||
- con_id);
|
||||
+ hw = __of_clk_get_hw_from_provider(provider, clkspec);
|
||||
+ if (!IS_ERR(hw)) {
|
||||
+ clk = __clk_create_clk(hw, dev_id, con_id);
|
||||
|
||||
if (!IS_ERR(clk) && !__clk_get(clk)) {
|
||||
__clk_free_clk(clk);
|
||||
--- a/include/linux/clk-provider.h
|
||||
+++ b/include/linux/clk-provider.h
|
||||
@@ -693,6 +693,11 @@ struct clk_onecell_data {
|
||||
unsigned int clk_num;
|
||||
};
|
||||
|
||||
+struct clk_hw_onecell_data {
|
||||
+ size_t num;
|
||||
+ struct clk_hw *hws[];
|
||||
+};
|
||||
+
|
||||
extern struct of_device_id __clk_of_table;
|
||||
|
||||
#define CLK_OF_DECLARE(name, compat, fn) OF_DECLARE_1(clk, name, compat, fn)
|
||||
@@ -702,10 +707,19 @@ int of_clk_add_provider(struct device_no
|
||||
struct clk *(*clk_src_get)(struct of_phandle_args *args,
|
||||
void *data),
|
||||
void *data);
|
||||
+int of_clk_add_hw_provider(struct device_node *np,
|
||||
+ struct clk_hw *(*get)(struct of_phandle_args *clkspec,
|
||||
+ void *data),
|
||||
+ void *data);
|
||||
void of_clk_del_provider(struct device_node *np);
|
||||
struct clk *of_clk_src_simple_get(struct of_phandle_args *clkspec,
|
||||
void *data);
|
||||
+
|
||||
+struct clk_hw *of_clk_hw_simple_get(struct of_phandle_args *clkspec,
|
||||
+ void *data);
|
||||
struct clk *of_clk_src_onecell_get(struct of_phandle_args *clkspec, void *data);
|
||||
+struct clk_hw *of_clk_hw_onecell_get(struct of_phandle_args *clkspec,
|
||||
+ void *data);
|
||||
int of_clk_get_parent_count(struct device_node *np);
|
||||
int of_clk_parent_fill(struct device_node *np, const char **parents,
|
||||
unsigned int size);
|
||||
@@ -722,6 +736,13 @@ static inline int of_clk_add_provider(st
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
+static inline int of_clk_add_hw_provider(struct device_node *np,
|
||||
+ struct clk_hw *(*get)(struct of_phandle_args *clkspec,
|
||||
+ void *data),
|
||||
+ void *data)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
#define of_clk_del_provider(np) \
|
||||
{ while (0); }
|
||||
static inline struct clk *of_clk_src_simple_get(
|
||||
@@ -729,11 +750,21 @@ static inline struct clk *of_clk_src_sim
|
||||
{
|
||||
return ERR_PTR(-ENOENT);
|
||||
}
|
||||
+static inline struct clk_hw *
|
||||
+of_clk_hw_simple_get(struct of_phandle_args *clkspec, void *data)
|
||||
+{
|
||||
+ return ERR_PTR(-ENOENT);
|
||||
+}
|
||||
static inline struct clk *of_clk_src_onecell_get(
|
||||
struct of_phandle_args *clkspec, void *data)
|
||||
{
|
||||
return ERR_PTR(-ENOENT);
|
||||
}
|
||||
+static inline struct clk_hw *
|
||||
+of_clk_hw_onecell_get(struct of_phandle_args *clkspec, void *data)
|
||||
+{
|
||||
+ return ERR_PTR(-ENOENT);
|
||||
+}
|
||||
static inline int of_clk_get_parent_count(struct device_node *np)
|
||||
{
|
||||
return 0;
|
@ -1,465 +0,0 @@
|
||||
From 0f247626cbbfa2010d2b86fdee652605e084e248 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Date: Fri, 16 Sep 2016 16:13:48 +0200
|
||||
Subject: [PATCH] usb: core: Introduce a USB port LED trigger
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
This commit adds a new trigger responsible for turning on LED when USB
|
||||
device gets connected to the selected USB port. This can can useful for
|
||||
various home routers that have USB port(s) and a proper LED telling user
|
||||
a device is connected.
|
||||
|
||||
The trigger gets its documentation file but basically it just requires
|
||||
enabling it and selecting USB ports (e.g. echo 1 > ports/usb1-1).
|
||||
|
||||
There was a long discussion on design of this driver. Its current state
|
||||
is a result of picking them most adjustable solution as others couldn't
|
||||
handle all cases.
|
||||
|
||||
1) It wasn't possible for the driver to register separated trigger for
|
||||
each USB port. Some physical USB ports are handled by more than one
|
||||
controller and so by more than one USB port. E.g. USB 2.0 physical
|
||||
port may be handled by OHCI's port and EHCI's port.
|
||||
It's also not possible to assign more than 1 trigger to a single LED
|
||||
and implementing such feature would be tricky due to syncing triggers
|
||||
and sysfs conflicts with old triggers.
|
||||
|
||||
2) Another idea was to register trigger per USB hub. This wouldn't allow
|
||||
handling devices with multiple USB LEDs and controllers (hubs)
|
||||
controlling more than 1 physical port. It's common for hubs to have
|
||||
few ports and each may have its own LED.
|
||||
|
||||
This final trigger is highly flexible. It allows selecting any USB ports
|
||||
for any LED. It was also modified (comparing to the initial version) to
|
||||
allow choosing ports rather than having user /guess/ proper names. It
|
||||
was successfully tested on SmartRG SR400ac which has 3 USB LEDs,
|
||||
2 physical ports and 3 controllers.
|
||||
|
||||
It was noted USB subsystem already has usb-gadget and usb-host triggers
|
||||
but they are pretty trivial ones. They indicate activity only and can't
|
||||
have ports specified.
|
||||
|
||||
In future it may be good idea to consider adding activity support to
|
||||
usbport as well. This should allow switching to this more generic driver
|
||||
and maybe marking old ones as obsolete.
|
||||
This can be implemented with another sysfs file for setting mode. The
|
||||
default mode wouldn't change so there won't be ABI breakage and so such
|
||||
feature can be safely implemented later.
|
||||
|
||||
There was also an idea of supporting other devices (PCI, SDIO, etc.) but
|
||||
as this driver already contains some USB specific code (and will get
|
||||
more) these should be probably separated drivers (triggers).
|
||||
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||
---
|
||||
.../ABI/testing/sysfs-class-led-trigger-usbport | 12 +
|
||||
Documentation/leds/ledtrig-usbport.txt | 41 +++
|
||||
drivers/usb/core/Kconfig | 8 +
|
||||
drivers/usb/core/Makefile | 2 +
|
||||
drivers/usb/core/ledtrig-usbport.c | 314 +++++++++++++++++++++
|
||||
5 files changed, 377 insertions(+)
|
||||
create mode 100644 Documentation/ABI/testing/sysfs-class-led-trigger-usbport
|
||||
create mode 100644 Documentation/leds/ledtrig-usbport.txt
|
||||
create mode 100644 drivers/usb/core/ledtrig-usbport.c
|
||||
|
||||
--- /dev/null
|
||||
+++ b/Documentation/ABI/testing/sysfs-class-led-trigger-usbport
|
||||
@@ -0,0 +1,12 @@
|
||||
+What: /sys/class/leds/<led>/ports/<port>
|
||||
+Date: September 2016
|
||||
+KernelVersion: 4.9
|
||||
+Contact: linux-leds@vger.kernel.org
|
||||
+ linux-usb@vger.kernel.org
|
||||
+Description:
|
||||
+ Every dir entry represents a single USB port that can be
|
||||
+ selected for the USB port trigger. Selecting ports makes trigger
|
||||
+ observing them for any connected devices and lighting on LED if
|
||||
+ there are any.
|
||||
+ Echoing "1" value selects USB port. Echoing "0" unselects it.
|
||||
+ Current state can be also read.
|
||||
--- /dev/null
|
||||
+++ b/Documentation/leds/ledtrig-usbport.txt
|
||||
@@ -0,0 +1,41 @@
|
||||
+USB port LED trigger
|
||||
+====================
|
||||
+
|
||||
+This LED trigger can be used for signalling to the user a presence of USB device
|
||||
+in a given port. It simply turns on LED when device appears and turns it off
|
||||
+when it disappears.
|
||||
+
|
||||
+It requires selecting USB ports that should be observed. All available ones are
|
||||
+listed as separated entries in a "ports" subdirectory. Selecting is handled by
|
||||
+echoing "1" to a chosen port.
|
||||
+
|
||||
+Please note that this trigger allows selecting multiple USB ports for a single
|
||||
+LED. This can be useful in two cases:
|
||||
+
|
||||
+1) Device with single USB LED and few physical ports
|
||||
+
|
||||
+In such a case LED will be turned on as long as there is at least one connected
|
||||
+USB device.
|
||||
+
|
||||
+2) Device with a physical port handled by few controllers
|
||||
+
|
||||
+Some devices may have one controller per PHY standard. E.g. USB 3.0 physical
|
||||
+port may be handled by ohci-platform, ehci-platform and xhci-hcd. If there is
|
||||
+only one LED user will most likely want to assign ports from all 3 hubs.
|
||||
+
|
||||
+
|
||||
+This trigger can be activated from user space on led class devices as shown
|
||||
+below:
|
||||
+
|
||||
+ echo usbport > trigger
|
||||
+
|
||||
+This adds sysfs attributes to the LED that are documented in:
|
||||
+Documentation/ABI/testing/sysfs-class-led-trigger-usbport
|
||||
+
|
||||
+Example use-case:
|
||||
+
|
||||
+ echo usbport > trigger
|
||||
+ echo 1 > ports/usb1-port1
|
||||
+ echo 1 > ports/usb2-port1
|
||||
+ cat ports/usb1-port1
|
||||
+ echo 0 > ports/usb1-port1
|
||||
--- a/drivers/usb/core/Kconfig
|
||||
+++ b/drivers/usb/core/Kconfig
|
||||
@@ -103,3 +103,11 @@ config USB_ULPI_BUS
|
||||
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called ulpi.
|
||||
+
|
||||
+config USB_LEDS_TRIGGER_USBPORT
|
||||
+ tristate "USB port LED trigger"
|
||||
+ depends on USB && LEDS_TRIGGERS
|
||||
+ help
|
||||
+ This driver allows LEDs to be controlled by USB events. Enabling this
|
||||
+ trigger allows specifying list of USB ports that should turn on LED
|
||||
+ when some USB device gets connected.
|
||||
--- a/drivers/usb/core/Makefile
|
||||
+++ b/drivers/usb/core/Makefile
|
||||
@@ -11,3 +11,5 @@ usbcore-$(CONFIG_PCI) += hcd-pci.o
|
||||
usbcore-$(CONFIG_ACPI) += usb-acpi.o
|
||||
|
||||
obj-$(CONFIG_USB) += usbcore.o
|
||||
+
|
||||
+obj-$(CONFIG_USB_LEDS_TRIGGER_USBPORT) += ledtrig-usbport.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/usb/core/ledtrig-usbport.c
|
||||
@@ -0,0 +1,314 @@
|
||||
+/*
|
||||
+ * USB port LED trigger
|
||||
+ *
|
||||
+ * Copyright (C) 2016 Rafał Miłecki <rafal@milecki.pl>
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify
|
||||
+ * it under the terms of the GNU General Public License version 2 as
|
||||
+ * published by the Free Software Foundation.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/device.h>
|
||||
+#include <linux/leds.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/slab.h>
|
||||
+#include <linux/usb.h>
|
||||
+
|
||||
+struct usbport_trig_data {
|
||||
+ struct led_classdev *led_cdev;
|
||||
+ struct list_head ports;
|
||||
+ struct notifier_block nb;
|
||||
+ int count; /* Amount of connected matching devices */
|
||||
+};
|
||||
+
|
||||
+struct usbport_trig_port {
|
||||
+ struct usbport_trig_data *data;
|
||||
+ struct usb_device *hub;
|
||||
+ int portnum;
|
||||
+ char *port_name;
|
||||
+ bool observed;
|
||||
+ struct device_attribute attr;
|
||||
+ struct list_head list;
|
||||
+};
|
||||
+
|
||||
+/***************************************
|
||||
+ * Helpers
|
||||
+ ***************************************/
|
||||
+
|
||||
+/**
|
||||
+ * usbport_trig_usb_dev_observed - Check if dev is connected to observed port
|
||||
+ */
|
||||
+static bool usbport_trig_usb_dev_observed(struct usbport_trig_data *usbport_data,
|
||||
+ struct usb_device *usb_dev)
|
||||
+{
|
||||
+ struct usbport_trig_port *port;
|
||||
+
|
||||
+ if (!usb_dev->parent)
|
||||
+ return false;
|
||||
+
|
||||
+ list_for_each_entry(port, &usbport_data->ports, list) {
|
||||
+ if (usb_dev->parent == port->hub &&
|
||||
+ usb_dev->portnum == port->portnum)
|
||||
+ return port->observed;
|
||||
+ }
|
||||
+
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
+static int usbport_trig_usb_dev_check(struct usb_device *usb_dev, void *data)
|
||||
+{
|
||||
+ struct usbport_trig_data *usbport_data = data;
|
||||
+
|
||||
+ if (usbport_trig_usb_dev_observed(usbport_data, usb_dev))
|
||||
+ usbport_data->count++;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * usbport_trig_update_count - Recalculate amount of connected matching devices
|
||||
+ */
|
||||
+static void usbport_trig_update_count(struct usbport_trig_data *usbport_data)
|
||||
+{
|
||||
+ struct led_classdev *led_cdev = usbport_data->led_cdev;
|
||||
+
|
||||
+ usbport_data->count = 0;
|
||||
+ usb_for_each_dev(usbport_data, usbport_trig_usb_dev_check);
|
||||
+ led_cdev->brightness_set(led_cdev,
|
||||
+ usbport_data->count ? LED_FULL : LED_OFF);
|
||||
+}
|
||||
+
|
||||
+/***************************************
|
||||
+ * Device attr
|
||||
+ ***************************************/
|
||||
+
|
||||
+static ssize_t usbport_trig_port_show(struct device *dev,
|
||||
+ struct device_attribute *attr, char *buf)
|
||||
+{
|
||||
+ struct usbport_trig_port *port = container_of(attr,
|
||||
+ struct usbport_trig_port,
|
||||
+ attr);
|
||||
+
|
||||
+ return sprintf(buf, "%d\n", port->observed) + 1;
|
||||
+}
|
||||
+
|
||||
+static ssize_t usbport_trig_port_store(struct device *dev,
|
||||
+ struct device_attribute *attr,
|
||||
+ const char *buf, size_t size)
|
||||
+{
|
||||
+ struct usbport_trig_port *port = container_of(attr,
|
||||
+ struct usbport_trig_port,
|
||||
+ attr);
|
||||
+
|
||||
+ if (!strcmp(buf, "0") || !strcmp(buf, "0\n"))
|
||||
+ port->observed = 0;
|
||||
+ else if (!strcmp(buf, "1") || !strcmp(buf, "1\n"))
|
||||
+ port->observed = 1;
|
||||
+ else
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ usbport_trig_update_count(port->data);
|
||||
+
|
||||
+ return size;
|
||||
+}
|
||||
+
|
||||
+static struct attribute *ports_attrs[] = {
|
||||
+ NULL,
|
||||
+};
|
||||
+static const struct attribute_group ports_group = {
|
||||
+ .name = "ports",
|
||||
+ .attrs = ports_attrs,
|
||||
+};
|
||||
+
|
||||
+/***************************************
|
||||
+ * Adding & removing ports
|
||||
+ ***************************************/
|
||||
+
|
||||
+static int usbport_trig_add_port(struct usbport_trig_data *usbport_data,
|
||||
+ struct usb_device *usb_dev,
|
||||
+ const char *hub_name, int portnum)
|
||||
+{
|
||||
+ struct led_classdev *led_cdev = usbport_data->led_cdev;
|
||||
+ struct usbport_trig_port *port;
|
||||
+ size_t len;
|
||||
+ int err;
|
||||
+
|
||||
+ port = kzalloc(sizeof(*port), GFP_KERNEL);
|
||||
+ if (!port) {
|
||||
+ err = -ENOMEM;
|
||||
+ goto err_out;
|
||||
+ }
|
||||
+
|
||||
+ port->data = usbport_data;
|
||||
+ port->hub = usb_dev;
|
||||
+ port->portnum = portnum;
|
||||
+
|
||||
+ len = strlen(hub_name) + 8;
|
||||
+ port->port_name = kzalloc(len, GFP_KERNEL);
|
||||
+ if (!port->port_name) {
|
||||
+ err = -ENOMEM;
|
||||
+ goto err_free_port;
|
||||
+ }
|
||||
+ snprintf(port->port_name, len, "%s-port%d", hub_name, portnum);
|
||||
+
|
||||
+ port->attr.attr.name = port->port_name;
|
||||
+ port->attr.attr.mode = S_IRUSR | S_IWUSR;
|
||||
+ port->attr.show = usbport_trig_port_show;
|
||||
+ port->attr.store = usbport_trig_port_store;
|
||||
+
|
||||
+ err = sysfs_add_file_to_group(&led_cdev->dev->kobj, &port->attr.attr,
|
||||
+ ports_group.name);
|
||||
+ if (err)
|
||||
+ goto err_free_port_name;
|
||||
+
|
||||
+ list_add_tail(&port->list, &usbport_data->ports);
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+err_free_port_name:
|
||||
+ kfree(port->port_name);
|
||||
+err_free_port:
|
||||
+ kfree(port);
|
||||
+err_out:
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+static int usbport_trig_add_usb_dev_ports(struct usb_device *usb_dev,
|
||||
+ void *data)
|
||||
+{
|
||||
+ struct usbport_trig_data *usbport_data = data;
|
||||
+ int i;
|
||||
+
|
||||
+ for (i = 1; i <= usb_dev->maxchild; i++)
|
||||
+ usbport_trig_add_port(usbport_data, usb_dev,
|
||||
+ dev_name(&usb_dev->dev), i);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void usbport_trig_remove_port(struct usbport_trig_data *usbport_data,
|
||||
+ struct usbport_trig_port *port)
|
||||
+{
|
||||
+ struct led_classdev *led_cdev = usbport_data->led_cdev;
|
||||
+
|
||||
+ list_del(&port->list);
|
||||
+ sysfs_remove_file_from_group(&led_cdev->dev->kobj, &port->attr.attr,
|
||||
+ ports_group.name);
|
||||
+ kfree(port->port_name);
|
||||
+ kfree(port);
|
||||
+}
|
||||
+
|
||||
+static void usbport_trig_remove_usb_dev_ports(struct usbport_trig_data *usbport_data,
|
||||
+ struct usb_device *usb_dev)
|
||||
+{
|
||||
+ struct usbport_trig_port *port, *tmp;
|
||||
+
|
||||
+ list_for_each_entry_safe(port, tmp, &usbport_data->ports, list) {
|
||||
+ if (port->hub == usb_dev)
|
||||
+ usbport_trig_remove_port(usbport_data, port);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/***************************************
|
||||
+ * Init, exit, etc.
|
||||
+ ***************************************/
|
||||
+
|
||||
+static int usbport_trig_notify(struct notifier_block *nb, unsigned long action,
|
||||
+ void *data)
|
||||
+{
|
||||
+ struct usbport_trig_data *usbport_data =
|
||||
+ container_of(nb, struct usbport_trig_data, nb);
|
||||
+ struct led_classdev *led_cdev = usbport_data->led_cdev;
|
||||
+ struct usb_device *usb_dev = data;
|
||||
+ bool observed;
|
||||
+
|
||||
+ observed = usbport_trig_usb_dev_observed(usbport_data, usb_dev);
|
||||
+
|
||||
+ switch (action) {
|
||||
+ case USB_DEVICE_ADD:
|
||||
+ usbport_trig_add_usb_dev_ports(usb_dev, usbport_data);
|
||||
+ if (observed && usbport_data->count++ == 0)
|
||||
+ led_cdev->brightness_set(led_cdev, LED_FULL);
|
||||
+ return NOTIFY_OK;
|
||||
+ case USB_DEVICE_REMOVE:
|
||||
+ usbport_trig_remove_usb_dev_ports(usbport_data, usb_dev);
|
||||
+ if (observed && --usbport_data->count == 0)
|
||||
+ led_cdev->brightness_set(led_cdev, LED_OFF);
|
||||
+ return NOTIFY_OK;
|
||||
+ }
|
||||
+
|
||||
+ return NOTIFY_DONE;
|
||||
+}
|
||||
+
|
||||
+static void usbport_trig_activate(struct led_classdev *led_cdev)
|
||||
+{
|
||||
+ struct usbport_trig_data *usbport_data;
|
||||
+ int err;
|
||||
+
|
||||
+ usbport_data = kzalloc(sizeof(*usbport_data), GFP_KERNEL);
|
||||
+ if (!usbport_data)
|
||||
+ return;
|
||||
+ usbport_data->led_cdev = led_cdev;
|
||||
+
|
||||
+ /* List of ports */
|
||||
+ INIT_LIST_HEAD(&usbport_data->ports);
|
||||
+ err = sysfs_create_group(&led_cdev->dev->kobj, &ports_group);
|
||||
+ if (err)
|
||||
+ goto err_free;
|
||||
+ usb_for_each_dev(usbport_data, usbport_trig_add_usb_dev_ports);
|
||||
+
|
||||
+ /* Notifications */
|
||||
+ usbport_data->nb.notifier_call = usbport_trig_notify,
|
||||
+ led_cdev->trigger_data = usbport_data;
|
||||
+ usb_register_notify(&usbport_data->nb);
|
||||
+
|
||||
+ led_cdev->activated = true;
|
||||
+ return;
|
||||
+
|
||||
+err_free:
|
||||
+ kfree(usbport_data);
|
||||
+}
|
||||
+
|
||||
+static void usbport_trig_deactivate(struct led_classdev *led_cdev)
|
||||
+{
|
||||
+ struct usbport_trig_data *usbport_data = led_cdev->trigger_data;
|
||||
+ struct usbport_trig_port *port, *tmp;
|
||||
+
|
||||
+ if (!led_cdev->activated)
|
||||
+ return;
|
||||
+
|
||||
+ list_for_each_entry_safe(port, tmp, &usbport_data->ports, list) {
|
||||
+ usbport_trig_remove_port(usbport_data, port);
|
||||
+ }
|
||||
+
|
||||
+ usb_unregister_notify(&usbport_data->nb);
|
||||
+
|
||||
+ sysfs_remove_group(&led_cdev->dev->kobj, &ports_group);
|
||||
+
|
||||
+ kfree(usbport_data);
|
||||
+
|
||||
+ led_cdev->activated = false;
|
||||
+}
|
||||
+
|
||||
+static struct led_trigger usbport_led_trigger = {
|
||||
+ .name = "usbport",
|
||||
+ .activate = usbport_trig_activate,
|
||||
+ .deactivate = usbport_trig_deactivate,
|
||||
+};
|
||||
+
|
||||
+static int __init usbport_trig_init(void)
|
||||
+{
|
||||
+ return led_trigger_register(&usbport_led_trigger);
|
||||
+}
|
||||
+
|
||||
+static void __exit usbport_trig_exit(void)
|
||||
+{
|
||||
+ led_trigger_unregister(&usbport_led_trigger);
|
||||
+}
|
||||
+
|
||||
+module_init(usbport_trig_init);
|
||||
+module_exit(usbport_trig_exit);
|
||||
+
|
||||
+MODULE_AUTHOR("Rafał Miłecki <rafal@milecki.pl>");
|
||||
+MODULE_DESCRIPTION("USB port trigger");
|
||||
+MODULE_LICENSE("GPL v2");
|
@ -1,70 +0,0 @@
|
||||
From 89778ba335e302a450932ce5b703c1ee6216e949 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Date: Tue, 6 Dec 2016 00:39:33 +0100
|
||||
Subject: [PATCH] usb: core: usbport: Use proper LED API to fix potential crash
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Calling brightness_set manually isn't safe as some LED drivers don't
|
||||
implement this callback. The best idea is to just use a proper helper
|
||||
which will fallback to the brightness_set_blocking callback if needed.
|
||||
|
||||
This fixes:
|
||||
[ 1461.761528] Unable to handle kernel NULL pointer dereference at virtual address 00000000
|
||||
(...)
|
||||
[ 1462.117049] Backtrace:
|
||||
[ 1462.119521] [<bf228164>] (usbport_trig_port_store [ledtrig_usbport]) from [<c023f758>] (dev_attr_store+0x20/0x2c)
|
||||
[ 1462.129826] r7:dcabc7c0 r6:dee0ff80 r5:00000002 r4:bf228164
|
||||
[ 1462.135511] [<c023f738>] (dev_attr_store) from [<c0169310>] (sysfs_kf_write+0x48/0x4c)
|
||||
[ 1462.143459] r5:00000002 r4:c023f738
|
||||
[ 1462.147049] [<c01692c8>] (sysfs_kf_write) from [<c0168ab8>] (kernfs_fop_write+0xf8/0x1f8)
|
||||
[ 1462.155258] r5:00000002 r4:df4a1000
|
||||
[ 1462.158850] [<c01689c0>] (kernfs_fop_write) from [<c0100c78>] (__vfs_write+0x34/0x120)
|
||||
[ 1462.166800] r10:00000000 r9:dee0e000 r8:c000fc24 r7:00000002 r6:dee0ff80 r5:c01689c0
|
||||
[ 1462.174660] r4:df727a80
|
||||
[ 1462.177204] [<c0100c44>] (__vfs_write) from [<c0101ae4>] (vfs_write+0xac/0x170)
|
||||
[ 1462.184543] r9:dee0e000 r8:c000fc24 r7:dee0ff80 r6:b6f092d0 r5:df727a80 r4:00000002
|
||||
[ 1462.192319] [<c0101a38>] (vfs_write) from [<c01028dc>] (SyS_write+0x4c/0xa8)
|
||||
[ 1462.199396] r9:dee0e000 r8:c000fc24 r7:00000002 r6:b6f092d0 r5:df727a80 r4:df727a80
|
||||
[ 1462.207174] [<c0102890>] (SyS_write) from [<c000fa60>] (ret_fast_syscall+0x0/0x3c)
|
||||
[ 1462.214774] r7:00000004 r6:ffffffff r5:00000000 r4:00000000
|
||||
[ 1462.220456] Code: bad PC value
|
||||
[ 1462.223560] ---[ end trace 676638a3a12c7a56 ]---
|
||||
|
||||
Reported-by: Ralph Sennhauser <ralph.sennhauser@gmail.com>
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
Fixes: 0f247626cbb ("usb: core: Introduce a USB port LED trigger")
|
||||
Cc: stable@vger.kernel.org # 4.9+
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||
---
|
||||
drivers/usb/core/ledtrig-usbport.c | 7 +++----
|
||||
1 file changed, 3 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/drivers/usb/core/ledtrig-usbport.c
|
||||
+++ b/drivers/usb/core/ledtrig-usbport.c
|
||||
@@ -74,8 +74,7 @@ static void usbport_trig_update_count(st
|
||||
|
||||
usbport_data->count = 0;
|
||||
usb_for_each_dev(usbport_data, usbport_trig_usb_dev_check);
|
||||
- led_cdev->brightness_set(led_cdev,
|
||||
- usbport_data->count ? LED_FULL : LED_OFF);
|
||||
+ led_set_brightness(led_cdev, usbport_data->count ? LED_FULL : LED_OFF);
|
||||
}
|
||||
|
||||
/***************************************
|
||||
@@ -228,12 +227,12 @@ static int usbport_trig_notify(struct no
|
||||
case USB_DEVICE_ADD:
|
||||
usbport_trig_add_usb_dev_ports(usb_dev, usbport_data);
|
||||
if (observed && usbport_data->count++ == 0)
|
||||
- led_cdev->brightness_set(led_cdev, LED_FULL);
|
||||
+ led_set_brightness(led_cdev, LED_FULL);
|
||||
return NOTIFY_OK;
|
||||
case USB_DEVICE_REMOVE:
|
||||
usbport_trig_remove_usb_dev_ports(usbport_data, usb_dev);
|
||||
if (observed && --usbport_data->count == 0)
|
||||
- led_cdev->brightness_set(led_cdev, LED_OFF);
|
||||
+ led_set_brightness(led_cdev, LED_OFF);
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
@ -1,106 +0,0 @@
|
||||
From 4f04c210d031667e503d6538a72345a36f3b5d71 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Date: Thu, 8 Jun 2017 18:08:32 +0200
|
||||
Subject: [PATCH] usb: core: read USB ports from DT in the usbport LED trigger
|
||||
driver
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
This uses DT info to read relation description of LEDs and USB ports. If
|
||||
DT has properly described LEDs, trigger will know when to turn them on.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||
---
|
||||
drivers/usb/core/ledtrig-usbport.c | 56 ++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 56 insertions(+)
|
||||
|
||||
--- a/drivers/usb/core/ledtrig-usbport.c
|
||||
+++ b/drivers/usb/core/ledtrig-usbport.c
|
||||
@@ -11,8 +11,10 @@
|
||||
#include <linux/device.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/module.h>
|
||||
+#include <linux/of.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/usb.h>
|
||||
+#include <linux/usb/of.h>
|
||||
|
||||
struct usbport_trig_data {
|
||||
struct led_classdev *led_cdev;
|
||||
@@ -123,6 +125,57 @@ static const struct attribute_group port
|
||||
* Adding & removing ports
|
||||
***************************************/
|
||||
|
||||
+/**
|
||||
+ * usbport_trig_port_observed - Check if port should be observed
|
||||
+ */
|
||||
+static bool usbport_trig_port_observed(struct usbport_trig_data *usbport_data,
|
||||
+ struct usb_device *usb_dev, int port1)
|
||||
+{
|
||||
+ struct device *dev = usbport_data->led_cdev->dev;
|
||||
+ struct device_node *led_np = dev->of_node;
|
||||
+ struct of_phandle_args args;
|
||||
+ struct device_node *port_np;
|
||||
+ int count, i;
|
||||
+
|
||||
+ if (!led_np)
|
||||
+ return false;
|
||||
+
|
||||
+ /* Get node of port being added */
|
||||
+ port_np = usb_of_get_child_node(usb_dev->dev.of_node, port1);
|
||||
+ if (!port_np)
|
||||
+ return false;
|
||||
+
|
||||
+ /* Amount of trigger sources for this LED */
|
||||
+ count = of_count_phandle_with_args(led_np, "trigger-sources",
|
||||
+ "#trigger-source-cells");
|
||||
+ if (count < 0) {
|
||||
+ dev_warn(dev, "Failed to get trigger sources for %s\n",
|
||||
+ led_np->full_name);
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ /* Check list of sources for this specific port */
|
||||
+ for (i = 0; i < count; i++) {
|
||||
+ int err;
|
||||
+
|
||||
+ err = of_parse_phandle_with_args(led_np, "trigger-sources",
|
||||
+ "#trigger-source-cells", i,
|
||||
+ &args);
|
||||
+ if (err) {
|
||||
+ dev_err(dev, "Failed to get trigger source phandle at index %d: %d\n",
|
||||
+ i, err);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ of_node_put(args.np);
|
||||
+
|
||||
+ if (args.np == port_np)
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
static int usbport_trig_add_port(struct usbport_trig_data *usbport_data,
|
||||
struct usb_device *usb_dev,
|
||||
const char *hub_name, int portnum)
|
||||
@@ -141,6 +194,8 @@ static int usbport_trig_add_port(struct
|
||||
port->data = usbport_data;
|
||||
port->hub = usb_dev;
|
||||
port->portnum = portnum;
|
||||
+ port->observed = usbport_trig_port_observed(usbport_data, usb_dev,
|
||||
+ portnum);
|
||||
|
||||
len = strlen(hub_name) + 8;
|
||||
port->port_name = kzalloc(len, GFP_KERNEL);
|
||||
@@ -255,6 +310,7 @@ static void usbport_trig_activate(struct
|
||||
if (err)
|
||||
goto err_free;
|
||||
usb_for_each_dev(usbport_data, usbport_trig_add_usb_dev_ports);
|
||||
+ usbport_trig_update_count(usbport_data);
|
||||
|
||||
/* Notifications */
|
||||
usbport_data->nb.notifier_call = usbport_trig_notify,
|
@ -1,53 +0,0 @@
|
||||
From bff23714bc36a1322d0f14519022df0d1a4b21f3 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
|
||||
Date: Fri, 8 Jul 2016 14:53:38 +0200
|
||||
Subject: [PATCH] leds: leds-gpio: Set of_node for created LED devices
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
When working with Device Tree we iterate over children of "gpio-leds"
|
||||
compatible node and create LED device for each of them. We take care of
|
||||
all common DT properties (label, default trigger, state, etc.), however
|
||||
some triggers may want to support more of them.
|
||||
|
||||
It could be useful for timer trigger to support setting delay on/off
|
||||
values with Device Tree property. Or for transient trigger to support
|
||||
e.g. duration property.
|
||||
|
||||
We obviously should handle such properties in triggers, not in generic
|
||||
code. To let trigger drivers read properties from DT node we need to set
|
||||
of_node to point the relevant node. This change allows using all kind of
|
||||
of helpers in e.g. "activate" callbacks.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
|
||||
Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
|
||||
---
|
||||
drivers/leds/leds-gpio.c | 5 +++--
|
||||
1 file changed, 3 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/leds/leds-gpio.c
|
||||
+++ b/drivers/leds/leds-gpio.c
|
||||
@@ -182,6 +182,7 @@ static struct gpio_leds_priv *gpio_leds_
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
device_for_each_child_node(dev, child) {
|
||||
+ struct gpio_led_data *led_dat = &priv->leds[priv->num_leds];
|
||||
struct gpio_led led = {};
|
||||
const char *state = NULL;
|
||||
|
||||
@@ -220,12 +221,12 @@ static struct gpio_leds_priv *gpio_leds_
|
||||
if (fwnode_property_present(child, "retain-state-suspended"))
|
||||
led.retain_state_suspended = 1;
|
||||
|
||||
- ret = create_gpio_led(&led, &priv->leds[priv->num_leds],
|
||||
- dev, NULL);
|
||||
+ ret = create_gpio_led(&led, led_dat, dev, NULL);
|
||||
if (ret < 0) {
|
||||
fwnode_handle_put(child);
|
||||
goto err;
|
||||
}
|
||||
+ led_dat->cdev.dev->of_node = np;
|
||||
priv->num_leds++;
|
||||
}
|
||||
|
@ -1,61 +0,0 @@
|
||||
From 68620e594c250ba8c43a78e77f5296cb9952582e Mon Sep 17 00:00:00 2001
|
||||
From: Heiner Kallweit <hkallweit1@gmail.com>
|
||||
Date: Wed, 14 Sep 2016 20:54:12 +0200
|
||||
Subject: [PATCH] leds: gpio: introduce gpio_blink_set_t
|
||||
|
||||
Introduce a typedef gpio_blink_set_t to improve readability of the code.
|
||||
|
||||
Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
|
||||
Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
|
||||
---
|
||||
drivers/leds/leds-gpio.c | 6 ++----
|
||||
include/linux/leds.h | 9 ++++++---
|
||||
2 files changed, 8 insertions(+), 7 deletions(-)
|
||||
|
||||
--- a/drivers/leds/leds-gpio.c
|
||||
+++ b/drivers/leds/leds-gpio.c
|
||||
@@ -29,8 +29,7 @@ struct gpio_led_data {
|
||||
u8 new_level;
|
||||
u8 can_sleep;
|
||||
u8 blinking;
|
||||
- int (*platform_gpio_blink_set)(struct gpio_desc *desc, int state,
|
||||
- unsigned long *delay_on, unsigned long *delay_off);
|
||||
+ gpio_blink_set_t platform_gpio_blink_set;
|
||||
};
|
||||
|
||||
static void gpio_led_work(struct work_struct *work)
|
||||
@@ -88,8 +87,7 @@ static int gpio_blink_set(struct led_cla
|
||||
|
||||
static int create_gpio_led(const struct gpio_led *template,
|
||||
struct gpio_led_data *led_dat, struct device *parent,
|
||||
- int (*blink_set)(struct gpio_desc *, int, unsigned long *,
|
||||
- unsigned long *))
|
||||
+ gpio_blink_set_t blink_set)
|
||||
{
|
||||
int ret, state;
|
||||
|
||||
--- a/include/linux/leds.h
|
||||
+++ b/include/linux/leds.h
|
||||
@@ -330,6 +330,11 @@ struct led_platform_data {
|
||||
struct led_info *leds;
|
||||
};
|
||||
|
||||
+struct gpio_desc;
|
||||
+typedef int (*gpio_blink_set_t)(struct gpio_desc *desc, int state,
|
||||
+ unsigned long *delay_on,
|
||||
+ unsigned long *delay_off);
|
||||
+
|
||||
/* For the leds-gpio driver */
|
||||
struct gpio_led {
|
||||
const char *name;
|
||||
@@ -352,9 +357,7 @@ struct gpio_led_platform_data {
|
||||
#define GPIO_LED_NO_BLINK_LOW 0 /* No blink GPIO state low */
|
||||
#define GPIO_LED_NO_BLINK_HIGH 1 /* No blink GPIO state high */
|
||||
#define GPIO_LED_BLINK 2 /* Please, blink */
|
||||
- int (*gpio_blink_set)(struct gpio_desc *desc, int state,
|
||||
- unsigned long *delay_on,
|
||||
- unsigned long *delay_off);
|
||||
+ gpio_blink_set_t gpio_blink_set;
|
||||
};
|
||||
|
||||
struct platform_device *gpio_led_register_device(
|
@ -1,75 +0,0 @@
|
||||
From bc2c0dd85a0a31505ca2f92bef891ddac9126725 Mon Sep 17 00:00:00 2001
|
||||
From: Heiner Kallweit <hkallweit1@gmail.com>
|
||||
Date: Wed, 14 Sep 2016 20:55:27 +0200
|
||||
Subject: [PATCH] leds: gpio: switch to managed version of
|
||||
led_classdev_register
|
||||
|
||||
Using the managed version of led_classdev_register allows to
|
||||
significantly simplify the code.
|
||||
|
||||
Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
|
||||
Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
|
||||
---
|
||||
drivers/leds/leds-gpio.c | 23 ++---------------------
|
||||
1 file changed, 2 insertions(+), 21 deletions(-)
|
||||
|
||||
--- a/drivers/leds/leds-gpio.c
|
||||
+++ b/drivers/leds/leds-gpio.c
|
||||
@@ -143,7 +143,7 @@ static int create_gpio_led(const struct
|
||||
|
||||
INIT_WORK(&led_dat->work, gpio_led_work);
|
||||
|
||||
- return led_classdev_register(parent, &led_dat->cdev);
|
||||
+ return devm_led_classdev_register(parent, &led_dat->cdev);
|
||||
}
|
||||
|
||||
static void delete_gpio_led(struct gpio_led_data *led)
|
||||
@@ -231,8 +231,6 @@ static struct gpio_leds_priv *gpio_leds_
|
||||
return priv;
|
||||
|
||||
err:
|
||||
- for (count = priv->num_leds - 1; count >= 0; count--)
|
||||
- delete_gpio_led(&priv->leds[count]);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
@@ -261,12 +259,8 @@ static int gpio_led_probe(struct platfor
|
||||
ret = create_gpio_led(&pdata->leds[i],
|
||||
&priv->leds[i],
|
||||
&pdev->dev, pdata->gpio_blink_set);
|
||||
- if (ret < 0) {
|
||||
- /* On failure: unwind the led creations */
|
||||
- for (i = i - 1; i >= 0; i--)
|
||||
- delete_gpio_led(&priv->leds[i]);
|
||||
+ if (ret < 0)
|
||||
return ret;
|
||||
- }
|
||||
}
|
||||
} else {
|
||||
priv = gpio_leds_create(pdev);
|
||||
@@ -279,17 +273,6 @@ static int gpio_led_probe(struct platfor
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static int gpio_led_remove(struct platform_device *pdev)
|
||||
-{
|
||||
- struct gpio_leds_priv *priv = platform_get_drvdata(pdev);
|
||||
- int i;
|
||||
-
|
||||
- for (i = 0; i < priv->num_leds; i++)
|
||||
- delete_gpio_led(&priv->leds[i]);
|
||||
-
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
static void gpio_led_shutdown(struct platform_device *pdev)
|
||||
{
|
||||
struct gpio_leds_priv *priv = platform_get_drvdata(pdev);
|
||||
@@ -304,7 +287,6 @@ static void gpio_led_shutdown(struct pla
|
||||
|
||||
static struct platform_driver gpio_led_driver = {
|
||||
.probe = gpio_led_probe,
|
||||
- .remove = gpio_led_remove,
|
||||
.shutdown = gpio_led_shutdown,
|
||||
.driver = {
|
||||
.name = "leds-gpio",
|
@ -1,120 +0,0 @@
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Date: Mon, 6 Mar 2017 06:19:44 +0100
|
||||
Subject: [PATCH] leds: core: add OF variants of LED registering functions
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
These new functions allow passing an additional device_node argument
|
||||
that will be internally set for created LED device. Thanks to this LED
|
||||
core code and triggers will be able to access DT node for reading extra
|
||||
info.
|
||||
|
||||
The easiest solution for achieving this was reworking old functions to
|
||||
more generic ones & adding simple defines for API compatibility.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
Acked-by: Pavel Machek <pavel@ucw.cz>
|
||||
Signed-off-by: Jacek Anaszewski <jacek.anaszewski@gmail.com>
|
||||
---
|
||||
drivers/leds/led-class.c | 26 ++++++++++++++++----------
|
||||
include/linux/leds.h | 14 ++++++++++----
|
||||
2 files changed, 26 insertions(+), 14 deletions(-)
|
||||
|
||||
--- a/drivers/leds/led-class.c
|
||||
+++ b/drivers/leds/led-class.c
|
||||
@@ -181,11 +181,14 @@ static int led_classdev_next_name(const
|
||||
}
|
||||
|
||||
/**
|
||||
- * led_classdev_register - register a new object of led_classdev class.
|
||||
- * @parent: The device to register.
|
||||
+ * of_led_classdev_register - register a new object of led_classdev class.
|
||||
+ *
|
||||
+ * @parent: parent of LED device
|
||||
* @led_cdev: the led_classdev structure for this device.
|
||||
+ * @np: DT node describing this LED
|
||||
*/
|
||||
-int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
|
||||
+int of_led_classdev_register(struct device *parent, struct device_node *np,
|
||||
+ struct led_classdev *led_cdev)
|
||||
{
|
||||
char name[64];
|
||||
int ret;
|
||||
@@ -198,6 +201,7 @@ int led_classdev_register(struct device
|
||||
led_cdev, led_cdev->groups, "%s", name);
|
||||
if (IS_ERR(led_cdev->dev))
|
||||
return PTR_ERR(led_cdev->dev);
|
||||
+ led_cdev->dev->of_node = np;
|
||||
|
||||
if (ret)
|
||||
dev_warn(parent, "Led %s renamed to %s due to name collision",
|
||||
@@ -230,7 +234,7 @@ int led_classdev_register(struct device
|
||||
|
||||
return 0;
|
||||
}
|
||||
-EXPORT_SYMBOL_GPL(led_classdev_register);
|
||||
+EXPORT_SYMBOL_GPL(of_led_classdev_register);
|
||||
|
||||
/**
|
||||
* led_classdev_unregister - unregisters a object of led_properties class.
|
||||
@@ -269,12 +273,14 @@ static void devm_led_classdev_release(st
|
||||
}
|
||||
|
||||
/**
|
||||
- * devm_led_classdev_register - resource managed led_classdev_register()
|
||||
- * @parent: The device to register.
|
||||
+ * devm_of_led_classdev_register - resource managed led_classdev_register()
|
||||
+ *
|
||||
+ * @parent: parent of LED device
|
||||
* @led_cdev: the led_classdev structure for this device.
|
||||
*/
|
||||
-int devm_led_classdev_register(struct device *parent,
|
||||
- struct led_classdev *led_cdev)
|
||||
+int devm_of_led_classdev_register(struct device *parent,
|
||||
+ struct device_node *np,
|
||||
+ struct led_classdev *led_cdev)
|
||||
{
|
||||
struct led_classdev **dr;
|
||||
int rc;
|
||||
@@ -283,7 +289,7 @@ int devm_led_classdev_register(struct de
|
||||
if (!dr)
|
||||
return -ENOMEM;
|
||||
|
||||
- rc = led_classdev_register(parent, led_cdev);
|
||||
+ rc = of_led_classdev_register(parent, np, led_cdev);
|
||||
if (rc) {
|
||||
devres_free(dr);
|
||||
return rc;
|
||||
@@ -294,7 +300,7 @@ int devm_led_classdev_register(struct de
|
||||
|
||||
return 0;
|
||||
}
|
||||
-EXPORT_SYMBOL_GPL(devm_led_classdev_register);
|
||||
+EXPORT_SYMBOL_GPL(devm_of_led_classdev_register);
|
||||
|
||||
static int devm_led_classdev_match(struct device *dev, void *res, void *data)
|
||||
{
|
||||
--- a/include/linux/leds.h
|
||||
+++ b/include/linux/leds.h
|
||||
@@ -103,10 +103,16 @@ struct led_classdev {
|
||||
struct mutex led_access;
|
||||
};
|
||||
|
||||
-extern int led_classdev_register(struct device *parent,
|
||||
- struct led_classdev *led_cdev);
|
||||
-extern int devm_led_classdev_register(struct device *parent,
|
||||
- struct led_classdev *led_cdev);
|
||||
+extern int of_led_classdev_register(struct device *parent,
|
||||
+ struct device_node *np,
|
||||
+ struct led_classdev *led_cdev);
|
||||
+#define led_classdev_register(parent, led_cdev) \
|
||||
+ of_led_classdev_register(parent, NULL, led_cdev)
|
||||
+extern int devm_of_led_classdev_register(struct device *parent,
|
||||
+ struct device_node *np,
|
||||
+ struct led_classdev *led_cdev);
|
||||
+#define devm_led_classdev_register(parent, led_cdev) \
|
||||
+ devm_of_led_classdev_register(parent, NULL, led_cdev)
|
||||
extern void led_classdev_unregister(struct led_classdev *led_cdev);
|
||||
extern void devm_led_classdev_unregister(struct device *parent,
|
||||
struct led_classdev *led_cdev);
|
@ -1,60 +0,0 @@
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Date: Mon, 6 Mar 2017 06:19:45 +0100
|
||||
Subject: [PATCH] leds: gpio: use OF variant of LED registering function
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
In leds-gpio we support LEDs specified in DT so we should use
|
||||
(devm_)of_led_classdev_register. This allows passing DT node as argument
|
||||
for use by the LED subsystem.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
Acked-by: Pavel Machek <pavel@ucw.cz>
|
||||
Signed-off-by: Jacek Anaszewski <jacek.anaszewski@gmail.com>
|
||||
---
|
||||
drivers/leds/leds-gpio.c | 12 ++++++------
|
||||
1 file changed, 6 insertions(+), 6 deletions(-)
|
||||
|
||||
--- a/drivers/leds/leds-gpio.c
|
||||
+++ b/drivers/leds/leds-gpio.c
|
||||
@@ -87,7 +87,7 @@ static int gpio_blink_set(struct led_cla
|
||||
|
||||
static int create_gpio_led(const struct gpio_led *template,
|
||||
struct gpio_led_data *led_dat, struct device *parent,
|
||||
- gpio_blink_set_t blink_set)
|
||||
+ struct device_node *np, gpio_blink_set_t blink_set)
|
||||
{
|
||||
int ret, state;
|
||||
|
||||
@@ -143,7 +143,7 @@ static int create_gpio_led(const struct
|
||||
|
||||
INIT_WORK(&led_dat->work, gpio_led_work);
|
||||
|
||||
- return devm_led_classdev_register(parent, &led_dat->cdev);
|
||||
+ return devm_of_led_classdev_register(parent, np, &led_dat->cdev);
|
||||
}
|
||||
|
||||
static void delete_gpio_led(struct gpio_led_data *led)
|
||||
@@ -219,7 +219,7 @@ static struct gpio_leds_priv *gpio_leds_
|
||||
if (fwnode_property_present(child, "retain-state-suspended"))
|
||||
led.retain_state_suspended = 1;
|
||||
|
||||
- ret = create_gpio_led(&led, led_dat, dev, NULL);
|
||||
+ ret = create_gpio_led(&led, led_dat, dev, np, NULL);
|
||||
if (ret < 0) {
|
||||
fwnode_handle_put(child);
|
||||
goto err;
|
||||
@@ -256,9 +256,9 @@ static int gpio_led_probe(struct platfor
|
||||
|
||||
priv->num_leds = pdata->num_leds;
|
||||
for (i = 0; i < priv->num_leds; i++) {
|
||||
- ret = create_gpio_led(&pdata->leds[i],
|
||||
- &priv->leds[i],
|
||||
- &pdev->dev, pdata->gpio_blink_set);
|
||||
+ ret = create_gpio_led(&pdata->leds[i], &priv->leds[i],
|
||||
+ &pdev->dev, NULL,
|
||||
+ pdata->gpio_blink_set);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
@ -1,143 +0,0 @@
|
||||
From e498b4984db82b4ba3ceea7dba813222a31e9c2e Mon Sep 17 00:00:00 2001
|
||||
From: Laxman Dewangan <ldewangan@nvidia.com>
|
||||
Date: Wed, 9 Mar 2016 18:40:06 +0530
|
||||
Subject: [PATCH] thermal: of-thermal: Add devm version of
|
||||
thermal_zone_of_sensor_register
|
||||
|
||||
Add resource managed version of thermal_zone_of_sensor_register() and
|
||||
thermal_zone_of_sensor_unregister().
|
||||
|
||||
This helps in reducing the code size in error path, remove of
|
||||
driver remove callbacks and making proper sequence for deallocations.
|
||||
|
||||
Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
|
||||
Signed-off-by: Eduardo Valentin <edubezval@gmail.com>
|
||||
---
|
||||
drivers/thermal/of-thermal.c | 81 ++++++++++++++++++++++++++++++++++++++++++++
|
||||
include/linux/thermal.h | 18 ++++++++++
|
||||
2 files changed, 99 insertions(+)
|
||||
|
||||
--- a/drivers/thermal/of-thermal.c
|
||||
+++ b/drivers/thermal/of-thermal.c
|
||||
@@ -559,6 +559,87 @@ void thermal_zone_of_sensor_unregister(s
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(thermal_zone_of_sensor_unregister);
|
||||
|
||||
+static void devm_thermal_zone_of_sensor_release(struct device *dev, void *res)
|
||||
+{
|
||||
+ thermal_zone_of_sensor_unregister(dev,
|
||||
+ *(struct thermal_zone_device **)res);
|
||||
+}
|
||||
+
|
||||
+static int devm_thermal_zone_of_sensor_match(struct device *dev, void *res,
|
||||
+ void *data)
|
||||
+{
|
||||
+ struct thermal_zone_device **r = res;
|
||||
+
|
||||
+ if (WARN_ON(!r || !*r))
|
||||
+ return 0;
|
||||
+
|
||||
+ return *r == data;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * devm_thermal_zone_of_sensor_register - Resource managed version of
|
||||
+ * thermal_zone_of_sensor_register()
|
||||
+ * @dev: a valid struct device pointer of a sensor device. Must contain
|
||||
+ * a valid .of_node, for the sensor node.
|
||||
+ * @sensor_id: a sensor identifier, in case the sensor IP has more
|
||||
+ * than one sensors
|
||||
+ * @data: a private pointer (owned by the caller) that will be passed
|
||||
+ * back, when a temperature reading is needed.
|
||||
+ * @ops: struct thermal_zone_of_device_ops *. Must contain at least .get_temp.
|
||||
+ *
|
||||
+ * Refer thermal_zone_of_sensor_register() for more details.
|
||||
+ *
|
||||
+ * Return: On success returns a valid struct thermal_zone_device,
|
||||
+ * otherwise, it returns a corresponding ERR_PTR(). Caller must
|
||||
+ * check the return value with help of IS_ERR() helper.
|
||||
+ * Registered hermal_zone_device device will automatically be
|
||||
+ * released when device is unbounded.
|
||||
+ */
|
||||
+struct thermal_zone_device *devm_thermal_zone_of_sensor_register(
|
||||
+ struct device *dev, int sensor_id,
|
||||
+ void *data, const struct thermal_zone_of_device_ops *ops)
|
||||
+{
|
||||
+ struct thermal_zone_device **ptr, *tzd;
|
||||
+
|
||||
+ ptr = devres_alloc(devm_thermal_zone_of_sensor_release, sizeof(*ptr),
|
||||
+ GFP_KERNEL);
|
||||
+ if (!ptr)
|
||||
+ return ERR_PTR(-ENOMEM);
|
||||
+
|
||||
+ tzd = thermal_zone_of_sensor_register(dev, sensor_id, data, ops);
|
||||
+ if (IS_ERR(tzd)) {
|
||||
+ devres_free(ptr);
|
||||
+ return tzd;
|
||||
+ }
|
||||
+
|
||||
+ *ptr = tzd;
|
||||
+ devres_add(dev, ptr);
|
||||
+
|
||||
+ return tzd;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(devm_thermal_zone_of_sensor_register);
|
||||
+
|
||||
+/**
|
||||
+ * devm_thermal_zone_of_sensor_unregister - Resource managed version of
|
||||
+ * thermal_zone_of_sensor_unregister().
|
||||
+ * @dev: Device for which which resource was allocated.
|
||||
+ * @tzd: a pointer to struct thermal_zone_device where the sensor is registered.
|
||||
+ *
|
||||
+ * This function removes the sensor callbacks and private data from the
|
||||
+ * thermal zone device registered with devm_thermal_zone_of_sensor_register()
|
||||
+ * API. It will also silent the zone by remove the .get_temp() and .get_trend()
|
||||
+ * thermal zone device callbacks.
|
||||
+ * Normally this function will not need to be called and the resource
|
||||
+ * management code will ensure that the resource is freed.
|
||||
+ */
|
||||
+void devm_thermal_zone_of_sensor_unregister(struct device *dev,
|
||||
+ struct thermal_zone_device *tzd)
|
||||
+{
|
||||
+ WARN_ON(devres_release(dev, devm_thermal_zone_of_sensor_release,
|
||||
+ devm_thermal_zone_of_sensor_match, tzd));
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(devm_thermal_zone_of_sensor_unregister);
|
||||
+
|
||||
/*** functions parsing device tree nodes ***/
|
||||
|
||||
/**
|
||||
--- a/include/linux/thermal.h
|
||||
+++ b/include/linux/thermal.h
|
||||
@@ -364,6 +364,11 @@ thermal_zone_of_sensor_register(struct d
|
||||
const struct thermal_zone_of_device_ops *ops);
|
||||
void thermal_zone_of_sensor_unregister(struct device *dev,
|
||||
struct thermal_zone_device *tz);
|
||||
+struct thermal_zone_device *devm_thermal_zone_of_sensor_register(
|
||||
+ struct device *dev, int id, void *data,
|
||||
+ const struct thermal_zone_of_device_ops *ops);
|
||||
+void devm_thermal_zone_of_sensor_unregister(struct device *dev,
|
||||
+ struct thermal_zone_device *tz);
|
||||
#else
|
||||
static inline struct thermal_zone_device *
|
||||
thermal_zone_of_sensor_register(struct device *dev, int id, void *data,
|
||||
@@ -378,6 +383,19 @@ void thermal_zone_of_sensor_unregister(s
|
||||
{
|
||||
}
|
||||
|
||||
+static inline struct thermal_zone_device *devm_thermal_zone_of_sensor_register(
|
||||
+ struct device *dev, int id, void *data,
|
||||
+ const struct thermal_zone_of_device_ops *ops)
|
||||
+{
|
||||
+ return ERR_PTR(-ENODEV);
|
||||
+}
|
||||
+
|
||||
+static inline
|
||||
+void devm_thermal_zone_of_sensor_unregister(struct device *dev,
|
||||
+ struct thermal_zone_device *tz)
|
||||
+{
|
||||
+}
|
||||
+
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_THERMAL)
|
@ -1,101 +0,0 @@
|
||||
From 4a7069a32c99a81950de035535b0a064dcceaeba Mon Sep 17 00:00:00 2001
|
||||
From: Rajendra Nayak <rnayak@codeaurora.org>
|
||||
Date: Thu, 5 May 2016 14:21:42 +0530
|
||||
Subject: [PATCH] thermal: core: export apis to get slope and offset
|
||||
|
||||
Add apis for platform thermal drivers to query for slope and offset
|
||||
attributes, which might be needed for temperature calculations.
|
||||
|
||||
Signed-off-by: Rajendra Nayak <rnayak@codeaurora.org>
|
||||
Signed-off-by: Eduardo Valentin <edubezval@gmail.com>
|
||||
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
|
||||
---
|
||||
Documentation/thermal/sysfs-api.txt | 12 ++++++++++++
|
||||
drivers/thermal/thermal_core.c | 30 ++++++++++++++++++++++++++++++
|
||||
include/linux/thermal.h | 8 ++++++++
|
||||
3 files changed, 50 insertions(+)
|
||||
|
||||
--- a/Documentation/thermal/sysfs-api.txt
|
||||
+++ b/Documentation/thermal/sysfs-api.txt
|
||||
@@ -72,6 +72,18 @@ temperature) and throttle appropriate de
|
||||
It deletes the corresponding entry form /sys/class/thermal folder and
|
||||
unbind all the thermal cooling devices it uses.
|
||||
|
||||
+1.1.7 int thermal_zone_get_slope(struct thermal_zone_device *tz)
|
||||
+
|
||||
+ This interface is used to read the slope attribute value
|
||||
+ for the thermal zone device, which might be useful for platform
|
||||
+ drivers for temperature calculations.
|
||||
+
|
||||
+1.1.8 int thermal_zone_get_offset(struct thermal_zone_device *tz)
|
||||
+
|
||||
+ This interface is used to read the offset attribute value
|
||||
+ for the thermal zone device, which might be useful for platform
|
||||
+ drivers for temperature calculations.
|
||||
+
|
||||
1.2 thermal cooling device interface
|
||||
1.2.1 struct thermal_cooling_device *thermal_cooling_device_register(char *name,
|
||||
void *devdata, struct thermal_cooling_device_ops *)
|
||||
--- a/drivers/thermal/thermal_core.c
|
||||
+++ b/drivers/thermal/thermal_core.c
|
||||
@@ -2061,6 +2061,36 @@ exit:
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(thermal_zone_get_zone_by_name);
|
||||
|
||||
+/**
|
||||
+ * thermal_zone_get_slope - return the slope attribute of the thermal zone
|
||||
+ * @tz: thermal zone device with the slope attribute
|
||||
+ *
|
||||
+ * Return: If the thermal zone device has a slope attribute, return it, else
|
||||
+ * return 1.
|
||||
+ */
|
||||
+int thermal_zone_get_slope(struct thermal_zone_device *tz)
|
||||
+{
|
||||
+ if (tz && tz->tzp)
|
||||
+ return tz->tzp->slope;
|
||||
+ return 1;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(thermal_zone_get_slope);
|
||||
+
|
||||
+/**
|
||||
+ * thermal_zone_get_offset - return the offset attribute of the thermal zone
|
||||
+ * @tz: thermal zone device with the offset attribute
|
||||
+ *
|
||||
+ * Return: If the thermal zone device has a offset attribute, return it, else
|
||||
+ * return 0.
|
||||
+ */
|
||||
+int thermal_zone_get_offset(struct thermal_zone_device *tz)
|
||||
+{
|
||||
+ if (tz && tz->tzp)
|
||||
+ return tz->tzp->offset;
|
||||
+ return 0;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(thermal_zone_get_offset);
|
||||
+
|
||||
#ifdef CONFIG_NET
|
||||
static const struct genl_multicast_group thermal_event_mcgrps[] = {
|
||||
{ .name = THERMAL_GENL_MCAST_GROUP_NAME, },
|
||||
--- a/include/linux/thermal.h
|
||||
+++ b/include/linux/thermal.h
|
||||
@@ -432,6 +432,8 @@ thermal_of_cooling_device_register(struc
|
||||
void thermal_cooling_device_unregister(struct thermal_cooling_device *);
|
||||
struct thermal_zone_device *thermal_zone_get_zone_by_name(const char *name);
|
||||
int thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp);
|
||||
+int thermal_zone_get_slope(struct thermal_zone_device *tz);
|
||||
+int thermal_zone_get_offset(struct thermal_zone_device *tz);
|
||||
|
||||
int get_tz_trend(struct thermal_zone_device *, int);
|
||||
struct thermal_instance *get_thermal_instance(struct thermal_zone_device *,
|
||||
@@ -489,6 +491,12 @@ static inline struct thermal_zone_device
|
||||
static inline int thermal_zone_get_temp(
|
||||
struct thermal_zone_device *tz, int *temp)
|
||||
{ return -ENODEV; }
|
||||
+static inline int thermal_zone_get_slope(
|
||||
+ struct thermal_zone_device *tz)
|
||||
+{ return -ENODEV; }
|
||||
+static inline int thermal_zone_get_offset(
|
||||
+ struct thermal_zone_device *tz)
|
||||
+{ return -ENODEV; }
|
||||
static inline int get_tz_trend(struct thermal_zone_device *tz, int trip)
|
||||
{ return -ENODEV; }
|
||||
static inline struct thermal_instance *
|
@ -1,365 +0,0 @@
|
||||
From bcb7dd9ef206f7d646ed8dac6fe7772083714253 Mon Sep 17 00:00:00 2001
|
||||
From: Stefan Wahren <stefan.wahren@i2se.com>
|
||||
Date: Fri, 31 Mar 2017 20:03:06 +0000
|
||||
Subject: [PATCH] thermal: bcm2835: add thermal driver for bcm2835 SoC
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Add basic thermal driver for bcm2835 SoC.
|
||||
|
||||
This driver currently make sure that tsense HW block is set up
|
||||
correctly.
|
||||
|
||||
Tested-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
Signed-off-by: Martin Sperl <kernel@martin.sperl.org>
|
||||
Signed-off-by: Stefan Wahren <stefan.wahren@i2se.com>
|
||||
Acked-by: Eric Anholt <eric@anholt.net>
|
||||
Acked-by: Eduardo Valentin <edubezval@gmail.com>
|
||||
Signed-off-by: Eduardo Valentin <edubezval@gmail.com>
|
||||
---
|
||||
drivers/thermal/Kconfig | 8 +
|
||||
drivers/thermal/Makefile | 1 +
|
||||
drivers/thermal/bcm2835_thermal.c | 314 ++++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 323 insertions(+)
|
||||
create mode 100644 drivers/thermal/bcm2835_thermal.c
|
||||
|
||||
--- a/drivers/thermal/Kconfig
|
||||
+++ b/drivers/thermal/Kconfig
|
||||
@@ -391,4 +391,12 @@ config QCOM_SPMI_TEMP_ALARM
|
||||
real time die temperature if an ADC is present or an estimate of the
|
||||
temperature based upon the over temperature stage value.
|
||||
|
||||
+config BCM2835_THERMAL
|
||||
+ tristate "Thermal sensors on bcm2835 SoC"
|
||||
+ depends on ARCH_BCM2835 || COMPILE_TEST
|
||||
+ depends on HAS_IOMEM
|
||||
+ depends on THERMAL_OF
|
||||
+ help
|
||||
+ Support for thermal sensors on Broadcom bcm2835 SoCs.
|
||||
+
|
||||
endif
|
||||
--- a/drivers/thermal/Makefile
|
||||
+++ b/drivers/thermal/Makefile
|
||||
@@ -48,3 +48,4 @@ obj-$(CONFIG_INTEL_PCH_THERMAL) += intel
|
||||
obj-$(CONFIG_ST_THERMAL) += st/
|
||||
obj-$(CONFIG_TEGRA_SOCTHERM) += tegra_soctherm.o
|
||||
obj-$(CONFIG_HISI_THERMAL) += hisi_thermal.o
|
||||
+obj-$(CONFIG_BCM2835_THERMAL) += bcm2835_thermal.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/thermal/bcm2835_thermal.c
|
||||
@@ -0,0 +1,314 @@
|
||||
+/*
|
||||
+ * Driver for Broadcom BCM2835 SoC temperature sensor
|
||||
+ *
|
||||
+ * Copyright (C) 2016 Martin Sperl
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify
|
||||
+ * it under the terms of the GNU General Public License as published by
|
||||
+ * the Free Software Foundation; either version 2 of the License, or
|
||||
+ * (at your option) any later version.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful,
|
||||
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
+ * GNU General Public License for more details.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/clk.h>
|
||||
+#include <linux/debugfs.h>
|
||||
+#include <linux/device.h>
|
||||
+#include <linux/err.h>
|
||||
+#include <linux/io.h>
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/of_address.h>
|
||||
+#include <linux/of_device.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/thermal.h>
|
||||
+
|
||||
+#define BCM2835_TS_TSENSCTL 0x00
|
||||
+#define BCM2835_TS_TSENSSTAT 0x04
|
||||
+
|
||||
+#define BCM2835_TS_TSENSCTL_PRWDW BIT(0)
|
||||
+#define BCM2835_TS_TSENSCTL_RSTB BIT(1)
|
||||
+
|
||||
+/*
|
||||
+ * bandgap reference voltage in 6 mV increments
|
||||
+ * 000b = 1178 mV, 001b = 1184 mV, ... 111b = 1220 mV
|
||||
+ */
|
||||
+#define BCM2835_TS_TSENSCTL_CTRL_BITS 3
|
||||
+#define BCM2835_TS_TSENSCTL_CTRL_SHIFT 2
|
||||
+#define BCM2835_TS_TSENSCTL_CTRL_MASK \
|
||||
+ GENMASK(BCM2835_TS_TSENSCTL_CTRL_BITS + \
|
||||
+ BCM2835_TS_TSENSCTL_CTRL_SHIFT - 1, \
|
||||
+ BCM2835_TS_TSENSCTL_CTRL_SHIFT)
|
||||
+#define BCM2835_TS_TSENSCTL_CTRL_DEFAULT 1
|
||||
+#define BCM2835_TS_TSENSCTL_EN_INT BIT(5)
|
||||
+#define BCM2835_TS_TSENSCTL_DIRECT BIT(6)
|
||||
+#define BCM2835_TS_TSENSCTL_CLR_INT BIT(7)
|
||||
+#define BCM2835_TS_TSENSCTL_THOLD_SHIFT 8
|
||||
+#define BCM2835_TS_TSENSCTL_THOLD_BITS 10
|
||||
+#define BCM2835_TS_TSENSCTL_THOLD_MASK \
|
||||
+ GENMASK(BCM2835_TS_TSENSCTL_THOLD_BITS + \
|
||||
+ BCM2835_TS_TSENSCTL_THOLD_SHIFT - 1, \
|
||||
+ BCM2835_TS_TSENSCTL_THOLD_SHIFT)
|
||||
+/*
|
||||
+ * time how long the block to be asserted in reset
|
||||
+ * which based on a clock counter (TSENS clock assumed)
|
||||
+ */
|
||||
+#define BCM2835_TS_TSENSCTL_RSTDELAY_SHIFT 18
|
||||
+#define BCM2835_TS_TSENSCTL_RSTDELAY_BITS 8
|
||||
+#define BCM2835_TS_TSENSCTL_REGULEN BIT(26)
|
||||
+
|
||||
+#define BCM2835_TS_TSENSSTAT_DATA_BITS 10
|
||||
+#define BCM2835_TS_TSENSSTAT_DATA_SHIFT 0
|
||||
+#define BCM2835_TS_TSENSSTAT_DATA_MASK \
|
||||
+ GENMASK(BCM2835_TS_TSENSSTAT_DATA_BITS + \
|
||||
+ BCM2835_TS_TSENSSTAT_DATA_SHIFT - 1, \
|
||||
+ BCM2835_TS_TSENSSTAT_DATA_SHIFT)
|
||||
+#define BCM2835_TS_TSENSSTAT_VALID BIT(10)
|
||||
+#define BCM2835_TS_TSENSSTAT_INTERRUPT BIT(11)
|
||||
+
|
||||
+struct bcm2835_thermal_data {
|
||||
+ struct thermal_zone_device *tz;
|
||||
+ void __iomem *regs;
|
||||
+ struct clk *clk;
|
||||
+ struct dentry *debugfsdir;
|
||||
+};
|
||||
+
|
||||
+static int bcm2835_thermal_adc2temp(u32 adc, int offset, int slope)
|
||||
+{
|
||||
+ return offset + slope * adc;
|
||||
+}
|
||||
+
|
||||
+static int bcm2835_thermal_temp2adc(int temp, int offset, int slope)
|
||||
+{
|
||||
+ temp -= offset;
|
||||
+ temp /= slope;
|
||||
+
|
||||
+ if (temp < 0)
|
||||
+ temp = 0;
|
||||
+ if (temp >= BIT(BCM2835_TS_TSENSSTAT_DATA_BITS))
|
||||
+ temp = BIT(BCM2835_TS_TSENSSTAT_DATA_BITS) - 1;
|
||||
+
|
||||
+ return temp;
|
||||
+}
|
||||
+
|
||||
+static int bcm2835_thermal_get_temp(void *d, int *temp)
|
||||
+{
|
||||
+ struct bcm2835_thermal_data *data = d;
|
||||
+ u32 val = readl(data->regs + BCM2835_TS_TSENSSTAT);
|
||||
+
|
||||
+ if (!(val & BCM2835_TS_TSENSSTAT_VALID))
|
||||
+ return -EIO;
|
||||
+
|
||||
+ val &= BCM2835_TS_TSENSSTAT_DATA_MASK;
|
||||
+
|
||||
+ *temp = bcm2835_thermal_adc2temp(
|
||||
+ val,
|
||||
+ thermal_zone_get_offset(data->tz),
|
||||
+ thermal_zone_get_slope(data->tz));
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct debugfs_reg32 bcm2835_thermal_regs[] = {
|
||||
+ {
|
||||
+ .name = "ctl",
|
||||
+ .offset = 0
|
||||
+ },
|
||||
+ {
|
||||
+ .name = "stat",
|
||||
+ .offset = 4
|
||||
+ }
|
||||
+};
|
||||
+
|
||||
+static void bcm2835_thermal_debugfs(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct thermal_zone_device *tz = platform_get_drvdata(pdev);
|
||||
+ struct bcm2835_thermal_data *data = tz->devdata;
|
||||
+ struct debugfs_regset32 *regset;
|
||||
+
|
||||
+ data->debugfsdir = debugfs_create_dir("bcm2835_thermal", NULL);
|
||||
+ if (!data->debugfsdir)
|
||||
+ return;
|
||||
+
|
||||
+ regset = devm_kzalloc(&pdev->dev, sizeof(*regset), GFP_KERNEL);
|
||||
+ if (!regset)
|
||||
+ return;
|
||||
+
|
||||
+ regset->regs = bcm2835_thermal_regs;
|
||||
+ regset->nregs = ARRAY_SIZE(bcm2835_thermal_regs);
|
||||
+ regset->base = data->regs;
|
||||
+
|
||||
+ debugfs_create_regset32("regset", 0444, data->debugfsdir, regset);
|
||||
+}
|
||||
+
|
||||
+static struct thermal_zone_of_device_ops bcm2835_thermal_ops = {
|
||||
+ .get_temp = bcm2835_thermal_get_temp,
|
||||
+};
|
||||
+
|
||||
+/*
|
||||
+ * Note: as per Raspberry Foundation FAQ
|
||||
+ * (https://www.raspberrypi.org/help/faqs/#performanceOperatingTemperature)
|
||||
+ * the recommended temperature range for the SoC -40C to +85C
|
||||
+ * so the trip limit is set to 80C.
|
||||
+ * this applies to all the BCM283X SoC
|
||||
+ */
|
||||
+
|
||||
+static const struct of_device_id bcm2835_thermal_of_match_table[] = {
|
||||
+ {
|
||||
+ .compatible = "brcm,bcm2835-thermal",
|
||||
+ },
|
||||
+ {
|
||||
+ .compatible = "brcm,bcm2836-thermal",
|
||||
+ },
|
||||
+ {
|
||||
+ .compatible = "brcm,bcm2837-thermal",
|
||||
+ },
|
||||
+ {},
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, bcm2835_thermal_of_match_table);
|
||||
+
|
||||
+static int bcm2835_thermal_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ const struct of_device_id *match;
|
||||
+ struct thermal_zone_device *tz;
|
||||
+ struct bcm2835_thermal_data *data;
|
||||
+ struct resource *res;
|
||||
+ int err = 0;
|
||||
+ u32 val;
|
||||
+ unsigned long rate;
|
||||
+
|
||||
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
|
||||
+ if (!data)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ match = of_match_device(bcm2835_thermal_of_match_table,
|
||||
+ &pdev->dev);
|
||||
+ if (!match)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
+ data->regs = devm_ioremap_resource(&pdev->dev, res);
|
||||
+ if (IS_ERR(data->regs)) {
|
||||
+ err = PTR_ERR(data->regs);
|
||||
+ dev_err(&pdev->dev, "Could not get registers: %d\n", err);
|
||||
+ return err;
|
||||
+ }
|
||||
+
|
||||
+ data->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
+ if (IS_ERR(data->clk)) {
|
||||
+ err = PTR_ERR(data->clk);
|
||||
+ if (err != -EPROBE_DEFER)
|
||||
+ dev_err(&pdev->dev, "Could not get clk: %d\n", err);
|
||||
+ return err;
|
||||
+ }
|
||||
+
|
||||
+ err = clk_prepare_enable(data->clk);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ rate = clk_get_rate(data->clk);
|
||||
+ if ((rate < 1920000) || (rate > 5000000))
|
||||
+ dev_warn(&pdev->dev,
|
||||
+ "Clock %pCn running at %pCr Hz is outside of the recommended range: 1.92 to 5MHz\n",
|
||||
+ data->clk, data->clk);
|
||||
+
|
||||
+ /* register of thermal sensor and get info from DT */
|
||||
+ tz = thermal_zone_of_sensor_register(&pdev->dev, 0, data,
|
||||
+ &bcm2835_thermal_ops);
|
||||
+ if (IS_ERR(tz)) {
|
||||
+ err = PTR_ERR(tz);
|
||||
+ dev_err(&pdev->dev,
|
||||
+ "Failed to register the thermal device: %d\n",
|
||||
+ err);
|
||||
+ goto err_clk;
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * right now the FW does set up the HW-block, so we are not
|
||||
+ * touching the configuration registers.
|
||||
+ * But if the HW is not enabled, then set it up
|
||||
+ * using "sane" values used by the firmware right now.
|
||||
+ */
|
||||
+ val = readl(data->regs + BCM2835_TS_TSENSCTL);
|
||||
+ if (!(val & BCM2835_TS_TSENSCTL_RSTB)) {
|
||||
+ int trip_temp, offset, slope;
|
||||
+
|
||||
+ slope = thermal_zone_get_slope(tz);
|
||||
+ offset = thermal_zone_get_offset(tz);
|
||||
+ /*
|
||||
+ * For now we deal only with critical, otherwise
|
||||
+ * would need to iterate
|
||||
+ */
|
||||
+ err = tz->ops->get_trip_temp(tz, 0, &trip_temp);
|
||||
+ if (err < 0) {
|
||||
+ err = PTR_ERR(tz);
|
||||
+ dev_err(&pdev->dev,
|
||||
+ "Not able to read trip_temp: %d\n",
|
||||
+ err);
|
||||
+ goto err_tz;
|
||||
+ }
|
||||
+
|
||||
+ /* set bandgap reference voltage and enable voltage regulator */
|
||||
+ val = (BCM2835_TS_TSENSCTL_CTRL_DEFAULT <<
|
||||
+ BCM2835_TS_TSENSCTL_CTRL_SHIFT) |
|
||||
+ BCM2835_TS_TSENSCTL_REGULEN;
|
||||
+
|
||||
+ /* use the recommended reset duration */
|
||||
+ val |= (0xFE << BCM2835_TS_TSENSCTL_RSTDELAY_SHIFT);
|
||||
+
|
||||
+ /* trip_adc value from info */
|
||||
+ val |= bcm2835_thermal_temp2adc(trip_temp,
|
||||
+ offset,
|
||||
+ slope)
|
||||
+ << BCM2835_TS_TSENSCTL_THOLD_SHIFT;
|
||||
+
|
||||
+ /* write the value back to the register as 2 steps */
|
||||
+ writel(val, data->regs + BCM2835_TS_TSENSCTL);
|
||||
+ val |= BCM2835_TS_TSENSCTL_RSTB;
|
||||
+ writel(val, data->regs + BCM2835_TS_TSENSCTL);
|
||||
+ }
|
||||
+
|
||||
+ data->tz = tz;
|
||||
+
|
||||
+ platform_set_drvdata(pdev, tz);
|
||||
+
|
||||
+ bcm2835_thermal_debugfs(pdev);
|
||||
+
|
||||
+ return 0;
|
||||
+err_tz:
|
||||
+ thermal_zone_of_sensor_unregister(&pdev->dev, tz);
|
||||
+err_clk:
|
||||
+ clk_disable_unprepare(data->clk);
|
||||
+
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+static int bcm2835_thermal_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct thermal_zone_device *tz = platform_get_drvdata(pdev);
|
||||
+ struct bcm2835_thermal_data *data = tz->devdata;
|
||||
+
|
||||
+ debugfs_remove_recursive(data->debugfsdir);
|
||||
+ thermal_zone_of_sensor_unregister(&pdev->dev, tz);
|
||||
+ clk_disable_unprepare(data->clk);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static struct platform_driver bcm2835_thermal_driver = {
|
||||
+ .probe = bcm2835_thermal_probe,
|
||||
+ .remove = bcm2835_thermal_remove,
|
||||
+ .driver = {
|
||||
+ .name = "bcm2835_thermal",
|
||||
+ .of_match_table = bcm2835_thermal_of_match_table,
|
||||
+ },
|
||||
+};
|
||||
+module_platform_driver(bcm2835_thermal_driver);
|
||||
+
|
||||
+MODULE_AUTHOR("Martin Sperl");
|
||||
+MODULE_DESCRIPTION("Thermal driver for bcm2835 chip");
|
||||
+MODULE_LICENSE("GPL");
|
@ -1,173 +0,0 @@
|
||||
From a94cb7eeecc4104a6874339f90c5d0647359c102 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Date: Mon, 3 Apr 2017 17:48:29 +0200
|
||||
Subject: [PATCH] thermal: broadcom: add Northstar thermal driver
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Northstar is a SoC family commonly used in home routers. This commit
|
||||
adds a driver for checking CPU temperature. As Northstar Plus seems to
|
||||
also have this IP block this new symbol gets ARCH_BCM_IPROC dependency.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
Signed-off-by: Jon Mason <jon.mason@broadcom.com>
|
||||
Signed-off-by: Eduardo Valentin <edubezval@gmail.com>
|
||||
---
|
||||
drivers/thermal/Kconfig | 5 ++
|
||||
drivers/thermal/Makefile | 1 +
|
||||
drivers/thermal/broadcom/Kconfig | 8 +++
|
||||
drivers/thermal/broadcom/Makefile | 1 +
|
||||
drivers/thermal/broadcom/ns-thermal.c | 105 ++++++++++++++++++++++++++++++++++
|
||||
5 files changed, 120 insertions(+)
|
||||
create mode 100644 drivers/thermal/broadcom/Kconfig
|
||||
create mode 100644 drivers/thermal/broadcom/Makefile
|
||||
create mode 100644 drivers/thermal/broadcom/ns-thermal.c
|
||||
|
||||
--- a/drivers/thermal/Kconfig
|
||||
+++ b/drivers/thermal/Kconfig
|
||||
@@ -365,6 +365,11 @@ config INTEL_PCH_THERMAL
|
||||
Thermal reporting device will provide temperature reading,
|
||||
programmable trip points and other information.
|
||||
|
||||
+menu "Broadcom thermal drivers"
|
||||
+depends on ARCH_BCM || COMPILE_TEST
|
||||
+source "drivers/thermal/broadcom/Kconfig"
|
||||
+endmenu
|
||||
+
|
||||
menu "Texas Instruments thermal drivers"
|
||||
depends on ARCH_HAS_BANDGAP || COMPILE_TEST
|
||||
source "drivers/thermal/ti-soc-thermal/Kconfig"
|
||||
--- a/drivers/thermal/Makefile
|
||||
+++ b/drivers/thermal/Makefile
|
||||
@@ -26,6 +26,7 @@ thermal_sys-$(CONFIG_CLOCK_THERMAL) += c
|
||||
thermal_sys-$(CONFIG_DEVFREQ_THERMAL) += devfreq_cooling.o
|
||||
|
||||
# platform thermal drivers
|
||||
+obj-y += broadcom/
|
||||
obj-$(CONFIG_QCOM_SPMI_TEMP_ALARM) += qcom-spmi-temp-alarm.o
|
||||
obj-$(CONFIG_SPEAR_THERMAL) += spear_thermal.o
|
||||
obj-$(CONFIG_ROCKCHIP_THERMAL) += rockchip_thermal.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/thermal/broadcom/Kconfig
|
||||
@@ -0,0 +1,8 @@
|
||||
+config BCM_NS_THERMAL
|
||||
+ tristate "Northstar thermal driver"
|
||||
+ depends on ARCH_BCM_IPROC || COMPILE_TEST
|
||||
+ help
|
||||
+ Northstar is a family of SoCs that includes e.g. BCM4708, BCM47081,
|
||||
+ BCM4709 and BCM47094. It contains DMU (Device Management Unit) block
|
||||
+ with a thermal sensor that allows checking CPU temperature. This
|
||||
+ driver provides support for it.
|
||||
--- /dev/null
|
||||
+++ b/drivers/thermal/broadcom/Makefile
|
||||
@@ -0,0 +1 @@
|
||||
+obj-$(CONFIG_BCM_NS_THERMAL) += ns-thermal.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/thermal/broadcom/ns-thermal.c
|
||||
@@ -0,0 +1,105 @@
|
||||
+/*
|
||||
+ * Copyright (C) 2017 Rafał Miłecki <rafal@milecki.pl>
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify
|
||||
+ * it under the terms of the GNU General Public License version 2 as
|
||||
+ * published by the Free Software Foundation.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/of_address.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/thermal.h>
|
||||
+
|
||||
+#define PVTMON_CONTROL0 0x00
|
||||
+#define PVTMON_CONTROL0_SEL_MASK 0x0000000e
|
||||
+#define PVTMON_CONTROL0_SEL_TEMP_MONITOR 0x00000000
|
||||
+#define PVTMON_CONTROL0_SEL_TEST_MODE 0x0000000e
|
||||
+#define PVTMON_STATUS 0x08
|
||||
+
|
||||
+struct ns_thermal {
|
||||
+ struct thermal_zone_device *tz;
|
||||
+ void __iomem *pvtmon;
|
||||
+};
|
||||
+
|
||||
+static int ns_thermal_get_temp(void *data, int *temp)
|
||||
+{
|
||||
+ struct ns_thermal *ns_thermal = data;
|
||||
+ int offset = thermal_zone_get_offset(ns_thermal->tz);
|
||||
+ int slope = thermal_zone_get_slope(ns_thermal->tz);
|
||||
+ u32 val;
|
||||
+
|
||||
+ val = readl(ns_thermal->pvtmon + PVTMON_CONTROL0);
|
||||
+ if ((val & PVTMON_CONTROL0_SEL_MASK) != PVTMON_CONTROL0_SEL_TEMP_MONITOR) {
|
||||
+ /* Clear current mode selection */
|
||||
+ val &= ~PVTMON_CONTROL0_SEL_MASK;
|
||||
+
|
||||
+ /* Set temp monitor mode (it's the default actually) */
|
||||
+ val |= PVTMON_CONTROL0_SEL_TEMP_MONITOR;
|
||||
+
|
||||
+ writel(val, ns_thermal->pvtmon + PVTMON_CONTROL0);
|
||||
+ }
|
||||
+
|
||||
+ val = readl(ns_thermal->pvtmon + PVTMON_STATUS);
|
||||
+ *temp = slope * val + offset;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct thermal_zone_of_device_ops ns_thermal_ops = {
|
||||
+ .get_temp = ns_thermal_get_temp,
|
||||
+};
|
||||
+
|
||||
+static int ns_thermal_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ struct ns_thermal *ns_thermal;
|
||||
+
|
||||
+ ns_thermal = devm_kzalloc(dev, sizeof(*ns_thermal), GFP_KERNEL);
|
||||
+ if (!ns_thermal)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ ns_thermal->pvtmon = of_iomap(dev_of_node(dev), 0);
|
||||
+ if (WARN_ON(!ns_thermal->pvtmon))
|
||||
+ return -ENOENT;
|
||||
+
|
||||
+ ns_thermal->tz = devm_thermal_zone_of_sensor_register(dev, 0,
|
||||
+ ns_thermal,
|
||||
+ &ns_thermal_ops);
|
||||
+ if (IS_ERR(ns_thermal->tz)) {
|
||||
+ iounmap(ns_thermal->pvtmon);
|
||||
+ return PTR_ERR(ns_thermal->tz);
|
||||
+ }
|
||||
+
|
||||
+ platform_set_drvdata(pdev, ns_thermal);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int ns_thermal_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct ns_thermal *ns_thermal = platform_get_drvdata(pdev);
|
||||
+
|
||||
+ iounmap(ns_thermal->pvtmon);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id ns_thermal_of_match[] = {
|
||||
+ { .compatible = "brcm,ns-thermal", },
|
||||
+ {},
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, ns_thermal_of_match);
|
||||
+
|
||||
+static struct platform_driver ns_thermal_driver = {
|
||||
+ .probe = ns_thermal_probe,
|
||||
+ .remove = ns_thermal_remove,
|
||||
+ .driver = {
|
||||
+ .name = "ns-thermal",
|
||||
+ .of_match_table = ns_thermal_of_match,
|
||||
+ },
|
||||
+};
|
||||
+module_platform_driver(ns_thermal_driver);
|
||||
+
|
||||
+MODULE_DESCRIPTION("Northstar thermal driver");
|
||||
+MODULE_LICENSE("GPL v2");
|
@ -1,19 +0,0 @@
|
||||
From d44264c8735f79da3253520024841311c555ca31 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Date: Fri, 14 Apr 2017 22:25:12 +0200
|
||||
Subject: [PATCH] thermal: broadcom: fix compilation of Northstar driver
|
||||
|
||||
---
|
||||
drivers/thermal/broadcom/ns-thermal.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
--- a/drivers/thermal/broadcom/ns-thermal.c
|
||||
+++ b/drivers/thermal/broadcom/ns-thermal.c
|
||||
@@ -6,6 +6,7 @@
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
+#include <asm/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/platform_device.h>
|
@ -1,69 +0,0 @@
|
||||
From de88e9b0354c2e3ff8eae3f97afe43a34f5ed239 Mon Sep 17 00:00:00 2001
|
||||
From: Jonas Gorski <jonas.gorski@gmail.com>
|
||||
Date: Sat, 13 May 2017 13:03:21 +0200
|
||||
Subject: [PATCH] regmap: make LZO cache optional
|
||||
|
||||
Commit 2cbbb579bcbe3 ("regmap: Add the LZO cache support") added support
|
||||
for LZO compression in regcache, but there were never any users added
|
||||
afterwards. Since LZO support itself has its own size, it currently is
|
||||
rather a deoptimization.
|
||||
|
||||
So make it optional by introducing a symbol that can be selected by
|
||||
drivers wanting to make use of it.
|
||||
|
||||
Saves e.g. ~46 kB on MIPS (size of LZO support + regcache LZO code).
|
||||
|
||||
Signed-off-by: Jonas Gorski <jonas.gorski@gmail.com>
|
||||
---
|
||||
I tried using google to find any users (even out-of-tree ones), but at
|
||||
best I found a single driver submission that was switched to RBTREE in
|
||||
subsequent resubmissions (MFD_SMSC).
|
||||
|
||||
One could maybe also just drop the code because of no users for 5 years,
|
||||
but that would be up to the maintainer(s) to decide.
|
||||
|
||||
drivers/base/regmap/Kconfig | 5 ++++-
|
||||
drivers/base/regmap/Makefile | 3 ++-
|
||||
drivers/base/regmap/regcache.c | 2 ++
|
||||
3 files changed, 8 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/base/regmap/Kconfig
|
||||
+++ b/drivers/base/regmap/Kconfig
|
||||
@@ -4,9 +4,12 @@
|
||||
|
||||
config REGMAP
|
||||
default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ)
|
||||
+ select IRQ_DOMAIN if REGMAP_IRQ
|
||||
+ bool
|
||||
+
|
||||
+config REGCACHE_COMPRESSED
|
||||
select LZO_COMPRESS
|
||||
select LZO_DECOMPRESS
|
||||
- select IRQ_DOMAIN if REGMAP_IRQ
|
||||
bool
|
||||
|
||||
config REGMAP_AC97
|
||||
--- a/drivers/base/regmap/Makefile
|
||||
+++ b/drivers/base/regmap/Makefile
|
||||
@@ -2,7 +2,8 @@
|
||||
CFLAGS_regmap.o := -I$(src)
|
||||
|
||||
obj-$(CONFIG_REGMAP) += regmap.o regcache.o
|
||||
-obj-$(CONFIG_REGMAP) += regcache-rbtree.o regcache-lzo.o regcache-flat.o
|
||||
+obj-$(CONFIG_REGMAP) += regcache-rbtree.o regcache-flat.o
|
||||
+obj-$(CONFIG_REGCACHE_COMPRESSED) += regcache-lzo.o
|
||||
obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o
|
||||
obj-$(CONFIG_REGMAP_AC97) += regmap-ac97.o
|
||||
obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o
|
||||
--- a/drivers/base/regmap/regcache.c
|
||||
+++ b/drivers/base/regmap/regcache.c
|
||||
@@ -21,7 +21,9 @@
|
||||
|
||||
static const struct regcache_ops *cache_types[] = {
|
||||
®cache_rbtree_ops,
|
||||
+#if IS_ENABLED(CONFIG_REGCACHE_COMPRESSED)
|
||||
®cache_lzo_ops,
|
||||
+#endif
|
||||
®cache_flat_ops,
|
||||
};
|
||||
|
@ -1,317 +0,0 @@
|
||||
From: James Hogan <james.hogan@imgtec.com>
|
||||
Date: Mon, 25 Jan 2016 21:30:00 +0000
|
||||
Subject: [PATCH] MIPS: c-r4k: Use IPI calls for CM indexed cache ops
|
||||
|
||||
The Coherence Manager (CM) can propagate address-based ("hit") cache
|
||||
operations to other cores in the coherent system, alleviating software
|
||||
of the need to use IPI calls, however indexed cache operations are not
|
||||
propagated since doing so makes no sense for separate caches.
|
||||
|
||||
r4k_on_each_cpu() previously had a special case for CONFIG_MIPS_MT_SMP,
|
||||
intended to avoid the IPIs when the only other CPUs in the system were
|
||||
other VPEs in the same core, and hence sharing the same caches. This was
|
||||
changed by commit cccf34e9411c ("MIPS: c-r4k: Fix cache flushing for MT
|
||||
cores") to apparently handle multi-core multi-VPE systems, but it
|
||||
focussed mainly on hit cache ops, so the IPI calls were still disabled
|
||||
entirely for CM systems.
|
||||
|
||||
This doesn't normally cause problems, but tests can be written to hit
|
||||
these corner cases by using multiple threads, or changing task
|
||||
affinities to force the process to migrate cores. For example the
|
||||
failure of mprotect RW->RX to globally sync icaches (via
|
||||
flush_cache_range) can be detected by modifying and mprotecting a code
|
||||
page on one core, and migrating to a different core to execute from it.
|
||||
|
||||
Most of the functions called by r4k_on_each_cpu() perform cache
|
||||
operations exclusively with a single addressing-type (virtual address vs
|
||||
indexed), so add a type argument and modify the callers to pass in
|
||||
R4K_USER (user virtual addressing), R4K_KERN (global kernel virtual
|
||||
addressing) or R4K_INDEX (index into cache).
|
||||
|
||||
local_r4k_flush_icache_range() is split up, to allow it to be called
|
||||
from the rest of the kernel, or from r4k_flush_icache_range() where it
|
||||
will choose either indexed or hit cache operations based on the size of
|
||||
the range and the cache sizes.
|
||||
|
||||
local_r4k_flush_kernel_vmap_range() is split into two functions, each of
|
||||
which uses cache operations with a single addressing-type, with
|
||||
r4k_flush_kernel_vmap_range() making the decision whether to use indexed
|
||||
cache ops or not.
|
||||
|
||||
Signed-off-by: James Hogan <james.hogan@imgtec.com>
|
||||
Cc: Ralf Baechle <ralf@linux-mips.org>
|
||||
Cc: Paul Burton <paul.burton@imgtec.com>
|
||||
Cc: Leonid Yegoshin <leonid.yegoshin@imgtec.com>
|
||||
Cc: linux-mips@linux-mips.org
|
||||
---
|
||||
|
||||
--- a/arch/mips/mm/c-r4k.c
|
||||
+++ b/arch/mips/mm/c-r4k.c
|
||||
@@ -40,6 +40,50 @@
|
||||
#include <asm/mips-cm.h>
|
||||
|
||||
/*
|
||||
+ * Bits describing what cache ops an IPI callback function may perform.
|
||||
+ *
|
||||
+ * R4K_USER - Virtual user address based cache operations.
|
||||
+ * Ineffective on other CPUs.
|
||||
+ * R4K_KERN - Virtual kernel address based cache operations (including kmap).
|
||||
+ * Effective on other CPUs.
|
||||
+ * R4K_INDEX - Index based cache operations.
|
||||
+ * Effective on other CPUs.
|
||||
+ */
|
||||
+
|
||||
+#define R4K_USER BIT(0)
|
||||
+#define R4K_KERN BIT(1)
|
||||
+#define R4K_INDEX BIT(2)
|
||||
+
|
||||
+#ifdef CONFIG_SMP
|
||||
+/* The Coherence manager propagates address-based cache ops to other cores */
|
||||
+#define r4k_hit_globalized mips_cm_present()
|
||||
+#define r4k_index_globalized 0
|
||||
+#else
|
||||
+/* If there's only 1 CPU, then all cache ops are globalized to that 1 CPU */
|
||||
+#define r4k_hit_globalized 1
|
||||
+#define r4k_index_globalized 1
|
||||
+#endif
|
||||
+
|
||||
+/**
|
||||
+ * r4k_op_needs_ipi() - Decide if a cache op needs to be done on every core.
|
||||
+ * @type: Type of cache operations (R4K_USER, R4K_KERN or R4K_INDEX).
|
||||
+ *
|
||||
+ * Returns: 1 if the cache operation @type should be done on every core in
|
||||
+ * the system.
|
||||
+ * 0 if the cache operation @type is globalized and only needs to
|
||||
+ * be performed on a simple CPU.
|
||||
+ */
|
||||
+static inline bool r4k_op_needs_ipi(unsigned int type)
|
||||
+{
|
||||
+ /*
|
||||
+ * If hardware doesn't globalize the required cache ops we must use IPIs
|
||||
+ * to do so.
|
||||
+ */
|
||||
+ return (type & R4K_KERN && !r4k_hit_globalized) ||
|
||||
+ (type & R4K_INDEX && !r4k_index_globalized);
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
* Special Variant of smp_call_function for use by cache functions:
|
||||
*
|
||||
* o No return value
|
||||
@@ -48,19 +92,11 @@
|
||||
* primary cache.
|
||||
* o doesn't disable interrupts on the local CPU
|
||||
*/
|
||||
-static inline void r4k_on_each_cpu(void (*func) (void *info), void *info)
|
||||
+static inline void r4k_on_each_cpu(unsigned int type,
|
||||
+ void (*func) (void *info), void *info)
|
||||
{
|
||||
preempt_disable();
|
||||
-
|
||||
- /*
|
||||
- * The Coherent Manager propagates address-based cache ops to other
|
||||
- * cores but not index-based ops. However, r4k_on_each_cpu is used
|
||||
- * in both cases so there is no easy way to tell what kind of op is
|
||||
- * executed to the other cores. The best we can probably do is
|
||||
- * to restrict that call when a CM is not present because both
|
||||
- * CM-based SMP protocols (CMP & CPS) restrict index-based cache ops.
|
||||
- */
|
||||
- if (!mips_cm_present())
|
||||
+ if (r4k_op_needs_ipi(type))
|
||||
smp_call_function_many(&cpu_foreign_map, func, info, 1);
|
||||
func(info);
|
||||
preempt_enable();
|
||||
@@ -456,7 +492,7 @@ static inline void local_r4k___flush_cac
|
||||
|
||||
static void r4k___flush_cache_all(void)
|
||||
{
|
||||
- r4k_on_each_cpu(local_r4k___flush_cache_all, NULL);
|
||||
+ r4k_on_each_cpu(R4K_INDEX, local_r4k___flush_cache_all, NULL);
|
||||
}
|
||||
|
||||
static inline int has_valid_asid(const struct mm_struct *mm)
|
||||
@@ -503,7 +539,7 @@ static void r4k_flush_cache_range(struct
|
||||
int exec = vma->vm_flags & VM_EXEC;
|
||||
|
||||
if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc))
|
||||
- r4k_on_each_cpu(local_r4k_flush_cache_range, vma);
|
||||
+ r4k_on_each_cpu(R4K_INDEX, local_r4k_flush_cache_range, vma);
|
||||
}
|
||||
|
||||
static inline void local_r4k_flush_cache_mm(void * args)
|
||||
@@ -535,7 +571,7 @@ static void r4k_flush_cache_mm(struct mm
|
||||
if (!cpu_has_dc_aliases)
|
||||
return;
|
||||
|
||||
- r4k_on_each_cpu(local_r4k_flush_cache_mm, mm);
|
||||
+ r4k_on_each_cpu(R4K_INDEX, local_r4k_flush_cache_mm, mm);
|
||||
}
|
||||
|
||||
struct flush_cache_page_args {
|
||||
@@ -629,7 +665,7 @@ static void r4k_flush_cache_page(struct
|
||||
args.addr = addr;
|
||||
args.pfn = pfn;
|
||||
|
||||
- r4k_on_each_cpu(local_r4k_flush_cache_page, &args);
|
||||
+ r4k_on_each_cpu(R4K_KERN, local_r4k_flush_cache_page, &args);
|
||||
}
|
||||
|
||||
static inline void local_r4k_flush_data_cache_page(void * addr)
|
||||
@@ -642,18 +678,23 @@ static void r4k_flush_data_cache_page(un
|
||||
if (in_atomic())
|
||||
local_r4k_flush_data_cache_page((void *)addr);
|
||||
else
|
||||
- r4k_on_each_cpu(local_r4k_flush_data_cache_page, (void *) addr);
|
||||
+ r4k_on_each_cpu(R4K_KERN, local_r4k_flush_data_cache_page,
|
||||
+ (void *) addr);
|
||||
}
|
||||
|
||||
struct flush_icache_range_args {
|
||||
unsigned long start;
|
||||
unsigned long end;
|
||||
+ unsigned int type;
|
||||
};
|
||||
|
||||
-static inline void local_r4k_flush_icache_range(unsigned long start, unsigned long end)
|
||||
+static inline void __local_r4k_flush_icache_range(unsigned long start,
|
||||
+ unsigned long end,
|
||||
+ unsigned int type)
|
||||
{
|
||||
if (!cpu_has_ic_fills_f_dc) {
|
||||
- if (end - start >= dcache_size) {
|
||||
+ if (type == R4K_INDEX ||
|
||||
+ (type & R4K_INDEX && end - start >= dcache_size)) {
|
||||
r4k_blast_dcache();
|
||||
} else {
|
||||
R4600_HIT_CACHEOP_WAR_IMPL;
|
||||
@@ -661,7 +702,8 @@ static inline void local_r4k_flush_icach
|
||||
}
|
||||
}
|
||||
|
||||
- if (end - start > icache_size)
|
||||
+ if (type == R4K_INDEX ||
|
||||
+ (type & R4K_INDEX && end - start > icache_size))
|
||||
r4k_blast_icache();
|
||||
else {
|
||||
switch (boot_cpu_type()) {
|
||||
@@ -687,23 +729,59 @@ static inline void local_r4k_flush_icach
|
||||
#endif
|
||||
}
|
||||
|
||||
+static inline void local_r4k_flush_icache_range(unsigned long start,
|
||||
+ unsigned long end)
|
||||
+{
|
||||
+ __local_r4k_flush_icache_range(start, end, R4K_KERN | R4K_INDEX);
|
||||
+}
|
||||
+
|
||||
static inline void local_r4k_flush_icache_range_ipi(void *args)
|
||||
{
|
||||
struct flush_icache_range_args *fir_args = args;
|
||||
unsigned long start = fir_args->start;
|
||||
unsigned long end = fir_args->end;
|
||||
+ unsigned int type = fir_args->type;
|
||||
|
||||
- local_r4k_flush_icache_range(start, end);
|
||||
+ __local_r4k_flush_icache_range(start, end, type);
|
||||
}
|
||||
|
||||
static void r4k_flush_icache_range(unsigned long start, unsigned long end)
|
||||
{
|
||||
struct flush_icache_range_args args;
|
||||
+ unsigned long size, cache_size;
|
||||
|
||||
args.start = start;
|
||||
args.end = end;
|
||||
+ args.type = R4K_KERN | R4K_INDEX;
|
||||
|
||||
- r4k_on_each_cpu(local_r4k_flush_icache_range_ipi, &args);
|
||||
+ if (in_atomic()) {
|
||||
+ /*
|
||||
+ * We can't do blocking IPI calls from atomic context, so fall
|
||||
+ * back to pure address-based cache ops if they globalize.
|
||||
+ */
|
||||
+ if (!r4k_index_globalized && r4k_hit_globalized) {
|
||||
+ args.type &= ~R4K_INDEX;
|
||||
+ } else {
|
||||
+ /* Just do it locally instead. */
|
||||
+ local_r4k_flush_icache_range(start, end);
|
||||
+ instruction_hazard();
|
||||
+ return;
|
||||
+ }
|
||||
+ } else if (!r4k_index_globalized && r4k_hit_globalized) {
|
||||
+ /*
|
||||
+ * If address-based cache ops are globalized, then we may be
|
||||
+ * able to avoid the IPI for small flushes.
|
||||
+ */
|
||||
+ size = start - end;
|
||||
+ cache_size = icache_size;
|
||||
+ if (!cpu_has_ic_fills_f_dc) {
|
||||
+ size *= 2;
|
||||
+ cache_size += dcache_size;
|
||||
+ }
|
||||
+ if (size <= cache_size)
|
||||
+ args.type &= ~R4K_INDEX;
|
||||
+ }
|
||||
+ r4k_on_each_cpu(args.type, local_r4k_flush_icache_range_ipi, &args);
|
||||
instruction_hazard();
|
||||
}
|
||||
|
||||
@@ -823,7 +901,12 @@ static void local_r4k_flush_cache_sigtra
|
||||
|
||||
static void r4k_flush_cache_sigtramp(unsigned long addr)
|
||||
{
|
||||
- r4k_on_each_cpu(local_r4k_flush_cache_sigtramp, (void *) addr);
|
||||
+ /*
|
||||
+ * FIXME this is a bit broken when !r4k_hit_globalized, since the user
|
||||
+ * code probably won't be mapped on other CPUs, so if the process is
|
||||
+ * migrated, it could end up hitting stale icache lines.
|
||||
+ */
|
||||
+ r4k_on_each_cpu(R4K_USER, local_r4k_flush_cache_sigtramp, (void *)addr);
|
||||
}
|
||||
|
||||
static void r4k_flush_icache_all(void)
|
||||
@@ -837,6 +920,15 @@ struct flush_kernel_vmap_range_args {
|
||||
int size;
|
||||
};
|
||||
|
||||
+static inline void local_r4k_flush_kernel_vmap_range_index(void *args)
|
||||
+{
|
||||
+ /*
|
||||
+ * Aliases only affect the primary caches so don't bother with
|
||||
+ * S-caches or T-caches.
|
||||
+ */
|
||||
+ r4k_blast_dcache();
|
||||
+}
|
||||
+
|
||||
static inline void local_r4k_flush_kernel_vmap_range(void *args)
|
||||
{
|
||||
struct flush_kernel_vmap_range_args *vmra = args;
|
||||
@@ -847,12 +939,8 @@ static inline void local_r4k_flush_kerne
|
||||
* Aliases only affect the primary caches so don't bother with
|
||||
* S-caches or T-caches.
|
||||
*/
|
||||
- if (cpu_has_safe_index_cacheops && size >= dcache_size)
|
||||
- r4k_blast_dcache();
|
||||
- else {
|
||||
- R4600_HIT_CACHEOP_WAR_IMPL;
|
||||
- blast_dcache_range(vaddr, vaddr + size);
|
||||
- }
|
||||
+ R4600_HIT_CACHEOP_WAR_IMPL;
|
||||
+ blast_dcache_range(vaddr, vaddr + size);
|
||||
}
|
||||
|
||||
static void r4k_flush_kernel_vmap_range(unsigned long vaddr, int size)
|
||||
@@ -862,7 +950,12 @@ static void r4k_flush_kernel_vmap_range(
|
||||
args.vaddr = (unsigned long) vaddr;
|
||||
args.size = size;
|
||||
|
||||
- r4k_on_each_cpu(local_r4k_flush_kernel_vmap_range, &args);
|
||||
+ if (cpu_has_safe_index_cacheops && size >= dcache_size)
|
||||
+ r4k_on_each_cpu(R4K_INDEX,
|
||||
+ local_r4k_flush_kernel_vmap_range_index, NULL);
|
||||
+ else
|
||||
+ r4k_on_each_cpu(R4K_KERN, local_r4k_flush_kernel_vmap_range,
|
||||
+ &args);
|
||||
}
|
||||
|
||||
static inline void rm7k_erratum31(void)
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user