summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2019-09-01 15:16:38 -0400
committerDavid S. Miller <davem@davemloft.net>2019-09-01 15:16:38 -0400
commit4bc61b0b16955322576265724ab0a0075a30dc84 (patch)
tree4ed06a60199887ca6303fe3acd5d0fcf76af5bde
parentb943e03341e69cfd384ceabbb4efc28a82f69e0c (diff)
parent45de77ff8286156f78ac2beef03f6088bb3e451b (diff)
Merge branch 'net-dsa-mv88e6xxx-centralize-SERDES-IRQ-handling'
Vivien Didelot says: ==================== net: dsa: mv88e6xxx: centralize SERDES IRQ handling Following Marek's work on the abstraction of the SERDES lanes mapping, this series trades the .serdes_irq_setup and .serdes_irq_free callbacks for new .serdes_irq_mapping, .serdes_irq_enable and .serdes_irq_status operations. This has the benefit to limit the various SERDES implementations to simple register accesses only; centralize the IRQ handling and mutex locking logic; as well as reducing boilerplate in the driver. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/dsa/mv88e6xxx/chip.c141
-rw-r--r--drivers/net/dsa/mv88e6xxx/chip.h15
-rw-r--r--drivers/net/dsa/mv88e6xxx/port.c21
-rw-r--r--drivers/net/dsa/mv88e6xxx/serdes.c382
-rw-r--r--drivers/net/dsa/mv88e6xxx/serdes.h107
5 files changed, 315 insertions, 351 deletions
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index c648f9fbfa59..30365a54c31b 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -2054,27 +2054,93 @@ static int mv88e6xxx_setup_egress_floods(struct mv88e6xxx_chip *chip, int port)
2054 return 0; 2054 return 0;
2055} 2055}
2056 2056
2057static irqreturn_t mv88e6xxx_serdes_irq_thread_fn(int irq, void *dev_id)
2058{
2059 struct mv88e6xxx_port *mvp = dev_id;
2060 struct mv88e6xxx_chip *chip = mvp->chip;
2061 irqreturn_t ret = IRQ_NONE;
2062 int port = mvp->port;
2063 u8 lane;
2064
2065 mv88e6xxx_reg_lock(chip);
2066 lane = mv88e6xxx_serdes_get_lane(chip, port);
2067 if (lane)
2068 ret = mv88e6xxx_serdes_irq_status(chip, port, lane);
2069 mv88e6xxx_reg_unlock(chip);
2070
2071 return ret;
2072}
2073
2074static int mv88e6xxx_serdes_irq_request(struct mv88e6xxx_chip *chip, int port,
2075 u8 lane)
2076{
2077 struct mv88e6xxx_port *dev_id = &chip->ports[port];
2078 unsigned int irq;
2079 int err;
2080
2081 /* Nothing to request if this SERDES port has no IRQ */
2082 irq = mv88e6xxx_serdes_irq_mapping(chip, port);
2083 if (!irq)
2084 return 0;
2085
2086 /* Requesting the IRQ will trigger IRQ callbacks, so release the lock */
2087 mv88e6xxx_reg_unlock(chip);
2088 err = request_threaded_irq(irq, NULL, mv88e6xxx_serdes_irq_thread_fn,
2089 IRQF_ONESHOT, "mv88e6xxx-serdes", dev_id);
2090 mv88e6xxx_reg_lock(chip);
2091 if (err)
2092 return err;
2093
2094 dev_id->serdes_irq = irq;
2095
2096 return mv88e6xxx_serdes_irq_enable(chip, port, lane);
2097}
2098
2099static int mv88e6xxx_serdes_irq_free(struct mv88e6xxx_chip *chip, int port,
2100 u8 lane)
2101{
2102 struct mv88e6xxx_port *dev_id = &chip->ports[port];
2103 unsigned int irq = dev_id->serdes_irq;
2104 int err;
2105
2106 /* Nothing to free if no IRQ has been requested */
2107 if (!irq)
2108 return 0;
2109
2110 err = mv88e6xxx_serdes_irq_disable(chip, port, lane);
2111
2112 /* Freeing the IRQ will trigger IRQ callbacks, so release the lock */
2113 mv88e6xxx_reg_unlock(chip);
2114 free_irq(irq, dev_id);
2115 mv88e6xxx_reg_lock(chip);
2116
2117 dev_id->serdes_irq = 0;
2118
2119 return err;
2120}
2121
2057static int mv88e6xxx_serdes_power(struct mv88e6xxx_chip *chip, int port, 2122static int mv88e6xxx_serdes_power(struct mv88e6xxx_chip *chip, int port,
2058 bool on) 2123 bool on)
2059{ 2124{
2125 u8 lane;
2060 int err; 2126 int err;
2061 2127
2062 if (!chip->info->ops->serdes_power) 2128 lane = mv88e6xxx_serdes_get_lane(chip, port);
2129 if (!lane)
2063 return 0; 2130 return 0;
2064 2131
2065 if (on) { 2132 if (on) {
2066 err = chip->info->ops->serdes_power(chip, port, true); 2133 err = mv88e6xxx_serdes_power_up(chip, port, lane);
2067 if (err) 2134 if (err)
2068 return err; 2135 return err;
2069 2136
2070 if (chip->info->ops->serdes_irq_setup) 2137 err = mv88e6xxx_serdes_irq_request(chip, port, lane);
2071 err = chip->info->ops->serdes_irq_setup(chip, port);
2072 } else { 2138 } else {
2073 if (chip->info->ops->serdes_irq_free && 2139 err = mv88e6xxx_serdes_irq_free(chip, port, lane);
2074 chip->ports[port].serdes_irq) 2140 if (err)
2075 chip->info->ops->serdes_irq_free(chip, port); 2141 return err;
2076 2142
2077 err = chip->info->ops->serdes_power(chip, port, false); 2143 err = mv88e6xxx_serdes_power_down(chip, port, lane);
2078 } 2144 }
2079 2145
2080 return err; 2146 return err;
@@ -2931,8 +2997,9 @@ static const struct mv88e6xxx_ops mv88e6141_ops = {
2931 .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 2997 .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
2932 .serdes_power = mv88e6390_serdes_power, 2998 .serdes_power = mv88e6390_serdes_power,
2933 .serdes_get_lane = mv88e6341_serdes_get_lane, 2999 .serdes_get_lane = mv88e6341_serdes_get_lane,
2934 .serdes_irq_setup = mv88e6390_serdes_irq_setup, 3000 .serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
2935 .serdes_irq_free = mv88e6390_serdes_irq_free, 3001 .serdes_irq_enable = mv88e6390_serdes_irq_enable,
3002 .serdes_irq_status = mv88e6390_serdes_irq_status,
2936 .gpio_ops = &mv88e6352_gpio_ops, 3003 .gpio_ops = &mv88e6352_gpio_ops,
2937 .phylink_validate = mv88e6341_phylink_validate, 3004 .phylink_validate = mv88e6341_phylink_validate,
2938}; 3005};
@@ -3092,6 +3159,7 @@ static const struct mv88e6xxx_ops mv88e6172_ops = {
3092 .rmu_disable = mv88e6352_g1_rmu_disable, 3159 .rmu_disable = mv88e6352_g1_rmu_disable,
3093 .vtu_getnext = mv88e6352_g1_vtu_getnext, 3160 .vtu_getnext = mv88e6352_g1_vtu_getnext,
3094 .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 3161 .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
3162 .serdes_get_lane = mv88e6352_serdes_get_lane,
3095 .serdes_power = mv88e6352_serdes_power, 3163 .serdes_power = mv88e6352_serdes_power,
3096 .gpio_ops = &mv88e6352_gpio_ops, 3164 .gpio_ops = &mv88e6352_gpio_ops,
3097 .phylink_validate = mv88e6352_phylink_validate, 3165 .phylink_validate = mv88e6352_phylink_validate,
@@ -3177,9 +3245,11 @@ static const struct mv88e6xxx_ops mv88e6176_ops = {
3177 .rmu_disable = mv88e6352_g1_rmu_disable, 3245 .rmu_disable = mv88e6352_g1_rmu_disable,
3178 .vtu_getnext = mv88e6352_g1_vtu_getnext, 3246 .vtu_getnext = mv88e6352_g1_vtu_getnext,
3179 .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 3247 .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
3248 .serdes_get_lane = mv88e6352_serdes_get_lane,
3180 .serdes_power = mv88e6352_serdes_power, 3249 .serdes_power = mv88e6352_serdes_power,
3181 .serdes_irq_setup = mv88e6352_serdes_irq_setup, 3250 .serdes_irq_mapping = mv88e6352_serdes_irq_mapping,
3182 .serdes_irq_free = mv88e6352_serdes_irq_free, 3251 .serdes_irq_enable = mv88e6352_serdes_irq_enable,
3252 .serdes_irq_status = mv88e6352_serdes_irq_status,
3183 .gpio_ops = &mv88e6352_gpio_ops, 3253 .gpio_ops = &mv88e6352_gpio_ops,
3184 .phylink_validate = mv88e6352_phylink_validate, 3254 .phylink_validate = mv88e6352_phylink_validate,
3185}; 3255};
@@ -3261,8 +3331,9 @@ static const struct mv88e6xxx_ops mv88e6190_ops = {
3261 .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 3331 .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
3262 .serdes_power = mv88e6390_serdes_power, 3332 .serdes_power = mv88e6390_serdes_power,
3263 .serdes_get_lane = mv88e6390_serdes_get_lane, 3333 .serdes_get_lane = mv88e6390_serdes_get_lane,
3264 .serdes_irq_setup = mv88e6390_serdes_irq_setup, 3334 .serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
3265 .serdes_irq_free = mv88e6390_serdes_irq_free, 3335 .serdes_irq_enable = mv88e6390_serdes_irq_enable,
3336 .serdes_irq_status = mv88e6390_serdes_irq_status,
3266 .gpio_ops = &mv88e6352_gpio_ops, 3337 .gpio_ops = &mv88e6352_gpio_ops,
3267 .phylink_validate = mv88e6390_phylink_validate, 3338 .phylink_validate = mv88e6390_phylink_validate,
3268}; 3339};
@@ -3308,8 +3379,9 @@ static const struct mv88e6xxx_ops mv88e6190x_ops = {
3308 .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 3379 .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
3309 .serdes_power = mv88e6390_serdes_power, 3380 .serdes_power = mv88e6390_serdes_power,
3310 .serdes_get_lane = mv88e6390x_serdes_get_lane, 3381 .serdes_get_lane = mv88e6390x_serdes_get_lane,
3311 .serdes_irq_setup = mv88e6390_serdes_irq_setup, 3382 .serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
3312 .serdes_irq_free = mv88e6390_serdes_irq_free, 3383 .serdes_irq_enable = mv88e6390_serdes_irq_enable,
3384 .serdes_irq_status = mv88e6390_serdes_irq_status,
3313 .gpio_ops = &mv88e6352_gpio_ops, 3385 .gpio_ops = &mv88e6352_gpio_ops,
3314 .phylink_validate = mv88e6390x_phylink_validate, 3386 .phylink_validate = mv88e6390x_phylink_validate,
3315}; 3387};
@@ -3355,8 +3427,9 @@ static const struct mv88e6xxx_ops mv88e6191_ops = {
3355 .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 3427 .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
3356 .serdes_power = mv88e6390_serdes_power, 3428 .serdes_power = mv88e6390_serdes_power,
3357 .serdes_get_lane = mv88e6390_serdes_get_lane, 3429 .serdes_get_lane = mv88e6390_serdes_get_lane,
3358 .serdes_irq_setup = mv88e6390_serdes_irq_setup, 3430 .serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
3359 .serdes_irq_free = mv88e6390_serdes_irq_free, 3431 .serdes_irq_enable = mv88e6390_serdes_irq_enable,
3432 .serdes_irq_status = mv88e6390_serdes_irq_status,
3360 .avb_ops = &mv88e6390_avb_ops, 3433 .avb_ops = &mv88e6390_avb_ops,
3361 .ptp_ops = &mv88e6352_ptp_ops, 3434 .ptp_ops = &mv88e6352_ptp_ops,
3362 .phylink_validate = mv88e6390_phylink_validate, 3435 .phylink_validate = mv88e6390_phylink_validate,
@@ -3402,9 +3475,11 @@ static const struct mv88e6xxx_ops mv88e6240_ops = {
3402 .rmu_disable = mv88e6352_g1_rmu_disable, 3475 .rmu_disable = mv88e6352_g1_rmu_disable,
3403 .vtu_getnext = mv88e6352_g1_vtu_getnext, 3476 .vtu_getnext = mv88e6352_g1_vtu_getnext,
3404 .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 3477 .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
3478 .serdes_get_lane = mv88e6352_serdes_get_lane,
3405 .serdes_power = mv88e6352_serdes_power, 3479 .serdes_power = mv88e6352_serdes_power,
3406 .serdes_irq_setup = mv88e6352_serdes_irq_setup, 3480 .serdes_irq_mapping = mv88e6352_serdes_irq_mapping,
3407 .serdes_irq_free = mv88e6352_serdes_irq_free, 3481 .serdes_irq_enable = mv88e6352_serdes_irq_enable,
3482 .serdes_irq_status = mv88e6352_serdes_irq_status,
3408 .gpio_ops = &mv88e6352_gpio_ops, 3483 .gpio_ops = &mv88e6352_gpio_ops,
3409 .avb_ops = &mv88e6352_avb_ops, 3484 .avb_ops = &mv88e6352_avb_ops,
3410 .ptp_ops = &mv88e6352_ptp_ops, 3485 .ptp_ops = &mv88e6352_ptp_ops,
@@ -3492,8 +3567,9 @@ static const struct mv88e6xxx_ops mv88e6290_ops = {
3492 .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 3567 .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
3493 .serdes_power = mv88e6390_serdes_power, 3568 .serdes_power = mv88e6390_serdes_power,
3494 .serdes_get_lane = mv88e6390_serdes_get_lane, 3569 .serdes_get_lane = mv88e6390_serdes_get_lane,
3495 .serdes_irq_setup = mv88e6390_serdes_irq_setup, 3570 .serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
3496 .serdes_irq_free = mv88e6390_serdes_irq_free, 3571 .serdes_irq_enable = mv88e6390_serdes_irq_enable,
3572 .serdes_irq_status = mv88e6390_serdes_irq_status,
3497 .gpio_ops = &mv88e6352_gpio_ops, 3573 .gpio_ops = &mv88e6352_gpio_ops,
3498 .avb_ops = &mv88e6390_avb_ops, 3574 .avb_ops = &mv88e6390_avb_ops,
3499 .ptp_ops = &mv88e6352_ptp_ops, 3575 .ptp_ops = &mv88e6352_ptp_ops,
@@ -3629,8 +3705,9 @@ static const struct mv88e6xxx_ops mv88e6341_ops = {
3629 .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 3705 .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
3630 .serdes_power = mv88e6390_serdes_power, 3706 .serdes_power = mv88e6390_serdes_power,
3631 .serdes_get_lane = mv88e6341_serdes_get_lane, 3707 .serdes_get_lane = mv88e6341_serdes_get_lane,
3632 .serdes_irq_setup = mv88e6390_serdes_irq_setup, 3708 .serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
3633 .serdes_irq_free = mv88e6390_serdes_irq_free, 3709 .serdes_irq_enable = mv88e6390_serdes_irq_enable,
3710 .serdes_irq_status = mv88e6390_serdes_irq_status,
3634 .gpio_ops = &mv88e6352_gpio_ops, 3711 .gpio_ops = &mv88e6352_gpio_ops,
3635 .avb_ops = &mv88e6390_avb_ops, 3712 .avb_ops = &mv88e6390_avb_ops,
3636 .ptp_ops = &mv88e6352_ptp_ops, 3713 .ptp_ops = &mv88e6352_ptp_ops,
@@ -3759,9 +3836,11 @@ static const struct mv88e6xxx_ops mv88e6352_ops = {
3759 .rmu_disable = mv88e6352_g1_rmu_disable, 3836 .rmu_disable = mv88e6352_g1_rmu_disable,
3760 .vtu_getnext = mv88e6352_g1_vtu_getnext, 3837 .vtu_getnext = mv88e6352_g1_vtu_getnext,
3761 .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, 3838 .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
3839 .serdes_get_lane = mv88e6352_serdes_get_lane,
3762 .serdes_power = mv88e6352_serdes_power, 3840 .serdes_power = mv88e6352_serdes_power,
3763 .serdes_irq_setup = mv88e6352_serdes_irq_setup, 3841 .serdes_irq_mapping = mv88e6352_serdes_irq_mapping,
3764 .serdes_irq_free = mv88e6352_serdes_irq_free, 3842 .serdes_irq_enable = mv88e6352_serdes_irq_enable,
3843 .serdes_irq_status = mv88e6352_serdes_irq_status,
3765 .gpio_ops = &mv88e6352_gpio_ops, 3844 .gpio_ops = &mv88e6352_gpio_ops,
3766 .avb_ops = &mv88e6352_avb_ops, 3845 .avb_ops = &mv88e6352_avb_ops,
3767 .ptp_ops = &mv88e6352_ptp_ops, 3846 .ptp_ops = &mv88e6352_ptp_ops,
@@ -3814,8 +3893,9 @@ static const struct mv88e6xxx_ops mv88e6390_ops = {
3814 .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 3893 .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
3815 .serdes_power = mv88e6390_serdes_power, 3894 .serdes_power = mv88e6390_serdes_power,
3816 .serdes_get_lane = mv88e6390_serdes_get_lane, 3895 .serdes_get_lane = mv88e6390_serdes_get_lane,
3817 .serdes_irq_setup = mv88e6390_serdes_irq_setup, 3896 .serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
3818 .serdes_irq_free = mv88e6390_serdes_irq_free, 3897 .serdes_irq_enable = mv88e6390_serdes_irq_enable,
3898 .serdes_irq_status = mv88e6390_serdes_irq_status,
3819 .gpio_ops = &mv88e6352_gpio_ops, 3899 .gpio_ops = &mv88e6352_gpio_ops,
3820 .avb_ops = &mv88e6390_avb_ops, 3900 .avb_ops = &mv88e6390_avb_ops,
3821 .ptp_ops = &mv88e6352_ptp_ops, 3901 .ptp_ops = &mv88e6352_ptp_ops,
@@ -3865,8 +3945,9 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = {
3865 .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, 3945 .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
3866 .serdes_power = mv88e6390_serdes_power, 3946 .serdes_power = mv88e6390_serdes_power,
3867 .serdes_get_lane = mv88e6390x_serdes_get_lane, 3947 .serdes_get_lane = mv88e6390x_serdes_get_lane,
3868 .serdes_irq_setup = mv88e6390_serdes_irq_setup, 3948 .serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
3869 .serdes_irq_free = mv88e6390_serdes_irq_free, 3949 .serdes_irq_enable = mv88e6390_serdes_irq_enable,
3950 .serdes_irq_status = mv88e6390_serdes_irq_status,
3870 .gpio_ops = &mv88e6352_gpio_ops, 3951 .gpio_ops = &mv88e6352_gpio_ops,
3871 .avb_ops = &mv88e6390_avb_ops, 3952 .avb_ops = &mv88e6390_avb_ops,
3872 .ptp_ops = &mv88e6352_ptp_ops, 3953 .ptp_ops = &mv88e6352_ptp_ops,
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index 421e8b84bec3..6bc0a4e4fe7b 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -199,7 +199,7 @@ struct mv88e6xxx_port {
199 u64 vtu_member_violation; 199 u64 vtu_member_violation;
200 u64 vtu_miss_violation; 200 u64 vtu_miss_violation;
201 u8 cmode; 201 u8 cmode;
202 int serdes_irq; 202 unsigned int serdes_irq;
203}; 203};
204 204
205struct mv88e6xxx_chip { 205struct mv88e6xxx_chip {
@@ -441,14 +441,19 @@ struct mv88e6xxx_ops {
441 int (*mgmt_rsvd2cpu)(struct mv88e6xxx_chip *chip); 441 int (*mgmt_rsvd2cpu)(struct mv88e6xxx_chip *chip);
442 442
443 /* Power on/off a SERDES interface */ 443 /* Power on/off a SERDES interface */
444 int (*serdes_power)(struct mv88e6xxx_chip *chip, int port, bool on); 444 int (*serdes_power)(struct mv88e6xxx_chip *chip, int port, u8 lane,
445 bool up);
445 446
446 /* SERDES lane mapping */ 447 /* SERDES lane mapping */
447 int (*serdes_get_lane)(struct mv88e6xxx_chip *chip, int port, u8 *lane); 448 u8 (*serdes_get_lane)(struct mv88e6xxx_chip *chip, int port);
448 449
449 /* SERDES interrupt handling */ 450 /* SERDES interrupt handling */
450 int (*serdes_irq_setup)(struct mv88e6xxx_chip *chip, int port); 451 unsigned int (*serdes_irq_mapping)(struct mv88e6xxx_chip *chip,
451 void (*serdes_irq_free)(struct mv88e6xxx_chip *chip, int port); 452 int port);
453 int (*serdes_irq_enable)(struct mv88e6xxx_chip *chip, int port, u8 lane,
454 bool enable);
455 irqreturn_t (*serdes_irq_status)(struct mv88e6xxx_chip *chip, int port,
456 u8 lane);
452 457
453 /* Statistics from the SERDES interface */ 458 /* Statistics from the SERDES interface */
454 int (*serdes_get_sset_count)(struct mv88e6xxx_chip *chip, int port); 459 int (*serdes_get_sset_count)(struct mv88e6xxx_chip *chip, int port);
diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c
index 4f841335ea32..04006344adb2 100644
--- a/drivers/net/dsa/mv88e6xxx/port.c
+++ b/drivers/net/dsa/mv88e6xxx/port.c
@@ -431,18 +431,15 @@ static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
431 if (cmode == chip->ports[port].cmode) 431 if (cmode == chip->ports[port].cmode)
432 return 0; 432 return 0;
433 433
434 err = mv88e6xxx_serdes_get_lane(chip, port, &lane); 434 lane = mv88e6xxx_serdes_get_lane(chip, port);
435 if (err && err != -ENODEV) 435 if (lane) {
436 return err;
437
438 if (err != -ENODEV) {
439 if (chip->ports[port].serdes_irq) { 436 if (chip->ports[port].serdes_irq) {
440 err = mv88e6390_serdes_irq_disable(chip, port, lane); 437 err = mv88e6xxx_serdes_irq_disable(chip, port, lane);
441 if (err) 438 if (err)
442 return err; 439 return err;
443 } 440 }
444 441
445 err = mv88e6390_serdes_power(chip, port, false); 442 err = mv88e6xxx_serdes_power_down(chip, port, lane);
446 if (err) 443 if (err)
447 return err; 444 return err;
448 } 445 }
@@ -463,16 +460,16 @@ static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
463 460
464 chip->ports[port].cmode = cmode; 461 chip->ports[port].cmode = cmode;
465 462
466 err = mv88e6xxx_serdes_get_lane(chip, port, &lane); 463 lane = mv88e6xxx_serdes_get_lane(chip, port);
467 if (err) 464 if (!lane)
468 return err; 465 return -ENODEV;
469 466
470 err = mv88e6390_serdes_power(chip, port, true); 467 err = mv88e6xxx_serdes_power_up(chip, port, lane);
471 if (err) 468 if (err)
472 return err; 469 return err;
473 470
474 if (chip->ports[port].serdes_irq) { 471 if (chip->ports[port].serdes_irq) {
475 err = mv88e6390_serdes_irq_enable(chip, port, lane); 472 err = mv88e6xxx_serdes_irq_enable(chip, port, lane);
476 if (err) 473 if (err)
477 return err; 474 return err;
478 } 475 }
diff --git a/drivers/net/dsa/mv88e6xxx/serdes.c b/drivers/net/dsa/mv88e6xxx/serdes.c
index 38c0da2492c0..902feb398746 100644
--- a/drivers/net/dsa/mv88e6xxx/serdes.c
+++ b/drivers/net/dsa/mv88e6xxx/serdes.c
@@ -49,7 +49,8 @@ static int mv88e6390_serdes_write(struct mv88e6xxx_chip *chip,
49 return mv88e6xxx_phy_write(chip, lane, reg_c45, val); 49 return mv88e6xxx_phy_write(chip, lane, reg_c45, val);
50} 50}
51 51
52static int mv88e6352_serdes_power_set(struct mv88e6xxx_chip *chip, bool on) 52int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, u8 lane,
53 bool up)
53{ 54{
54 u16 val, new_val; 55 u16 val, new_val;
55 int err; 56 int err;
@@ -58,7 +59,7 @@ static int mv88e6352_serdes_power_set(struct mv88e6xxx_chip *chip, bool on)
58 if (err) 59 if (err)
59 return err; 60 return err;
60 61
61 if (on) 62 if (up)
62 new_val = val & ~BMCR_PDOWN; 63 new_val = val & ~BMCR_PDOWN;
63 else 64 else
64 new_val = val | BMCR_PDOWN; 65 new_val = val | BMCR_PDOWN;
@@ -69,29 +70,25 @@ static int mv88e6352_serdes_power_set(struct mv88e6xxx_chip *chip, bool on)
69 return err; 70 return err;
70} 71}
71 72
72static bool mv88e6352_port_has_serdes(struct mv88e6xxx_chip *chip, int port) 73u8 mv88e6352_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
73{ 74{
74 u8 cmode = chip->ports[port].cmode; 75 u8 cmode = chip->ports[port].cmode;
76 u8 lane = 0;
75 77
76 if ((cmode == MV88E6XXX_PORT_STS_CMODE_100BASEX) || 78 if ((cmode == MV88E6XXX_PORT_STS_CMODE_100BASEX) ||
77 (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX) || 79 (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX) ||
78 (cmode == MV88E6XXX_PORT_STS_CMODE_SGMII)) 80 (cmode == MV88E6XXX_PORT_STS_CMODE_SGMII))
79 return true; 81 lane = 0xff; /* Unused */
80 82
81 return false; 83 return lane;
82} 84}
83 85
84int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on) 86static bool mv88e6352_port_has_serdes(struct mv88e6xxx_chip *chip, int port)
85{ 87{
86 int err; 88 if (mv88e6xxx_serdes_get_lane(chip, port))
87 89 return true;
88 if (mv88e6352_port_has_serdes(chip, port)) {
89 err = mv88e6352_serdes_power_set(chip, on);
90 if (err < 0)
91 return err;
92 }
93 90
94 return 0; 91 return false;
95} 92}
96 93
97struct mv88e6352_serdes_hw_stat { 94struct mv88e6352_serdes_hw_stat {
@@ -186,254 +183,178 @@ static void mv88e6352_serdes_irq_link(struct mv88e6xxx_chip *chip, int port)
186 struct dsa_switch *ds = chip->ds; 183 struct dsa_switch *ds = chip->ds;
187 u16 status; 184 u16 status;
188 bool up; 185 bool up;
186 int err;
189 187
190 mv88e6352_serdes_read(chip, MII_BMSR, &status); 188 err = mv88e6352_serdes_read(chip, MII_BMSR, &status);
189 if (err)
190 return;
191 191
192 /* Status must be read twice in order to give the current link 192 /* Status must be read twice in order to give the current link
193 * status. Otherwise the change in link status since the last 193 * status. Otherwise the change in link status since the last
194 * read of the register is returned. 194 * read of the register is returned.
195 */ 195 */
196 mv88e6352_serdes_read(chip, MII_BMSR, &status); 196 err = mv88e6352_serdes_read(chip, MII_BMSR, &status);
197 if (err)
198 return;
197 199
198 up = status & BMSR_LSTATUS; 200 up = status & BMSR_LSTATUS;
199 201
200 dsa_port_phylink_mac_change(ds, port, up); 202 dsa_port_phylink_mac_change(ds, port, up);
201} 203}
202 204
203static irqreturn_t mv88e6352_serdes_thread_fn(int irq, void *dev_id) 205irqreturn_t mv88e6352_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
206 u8 lane)
204{ 207{
205 struct mv88e6xxx_port *port = dev_id;
206 struct mv88e6xxx_chip *chip = port->chip;
207 irqreturn_t ret = IRQ_NONE; 208 irqreturn_t ret = IRQ_NONE;
208 u16 status; 209 u16 status;
209 int err; 210 int err;
210 211
211 mv88e6xxx_reg_lock(chip);
212
213 err = mv88e6352_serdes_read(chip, MV88E6352_SERDES_INT_STATUS, &status); 212 err = mv88e6352_serdes_read(chip, MV88E6352_SERDES_INT_STATUS, &status);
214 if (err) 213 if (err)
215 goto out; 214 return ret;
216 215
217 if (status & MV88E6352_SERDES_INT_LINK_CHANGE) { 216 if (status & MV88E6352_SERDES_INT_LINK_CHANGE) {
218 ret = IRQ_HANDLED; 217 ret = IRQ_HANDLED;
219 mv88e6352_serdes_irq_link(chip, port->port); 218 mv88e6352_serdes_irq_link(chip, port);
220 } 219 }
221out:
222 mv88e6xxx_reg_unlock(chip);
223 220
224 return ret; 221 return ret;
225} 222}
226 223
227static int mv88e6352_serdes_irq_enable(struct mv88e6xxx_chip *chip) 224int mv88e6352_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, u8 lane,
228{ 225 bool enable)
229 return mv88e6352_serdes_write(chip, MV88E6352_SERDES_INT_ENABLE,
230 MV88E6352_SERDES_INT_LINK_CHANGE);
231}
232
233static int mv88e6352_serdes_irq_disable(struct mv88e6xxx_chip *chip)
234{ 226{
235 return mv88e6352_serdes_write(chip, MV88E6352_SERDES_INT_ENABLE, 0); 227 u16 val = 0;
236}
237
238int mv88e6352_serdes_irq_setup(struct mv88e6xxx_chip *chip, int port)
239{
240 int err;
241
242 if (!mv88e6352_port_has_serdes(chip, port))
243 return 0;
244
245 chip->ports[port].serdes_irq = irq_find_mapping(chip->g2_irq.domain,
246 MV88E6352_SERDES_IRQ);
247 if (chip->ports[port].serdes_irq < 0) {
248 dev_err(chip->dev, "Unable to map SERDES irq: %d\n",
249 chip->ports[port].serdes_irq);
250 return chip->ports[port].serdes_irq;
251 }
252
253 /* Requesting the IRQ will trigger irq callbacks. So we cannot
254 * hold the reg_lock.
255 */
256 mv88e6xxx_reg_unlock(chip);
257 err = request_threaded_irq(chip->ports[port].serdes_irq, NULL,
258 mv88e6352_serdes_thread_fn,
259 IRQF_ONESHOT, "mv88e6xxx-serdes",
260 &chip->ports[port]);
261 mv88e6xxx_reg_lock(chip);
262 228
263 if (err) { 229 if (enable)
264 dev_err(chip->dev, "Unable to request SERDES interrupt: %d\n", 230 val |= MV88E6352_SERDES_INT_LINK_CHANGE;
265 err);
266 return err;
267 }
268 231
269 return mv88e6352_serdes_irq_enable(chip); 232 return mv88e6352_serdes_write(chip, MV88E6352_SERDES_INT_ENABLE, val);
270} 233}
271 234
272void mv88e6352_serdes_irq_free(struct mv88e6xxx_chip *chip, int port) 235unsigned int mv88e6352_serdes_irq_mapping(struct mv88e6xxx_chip *chip, int port)
273{ 236{
274 if (!mv88e6352_port_has_serdes(chip, port)) 237 return irq_find_mapping(chip->g2_irq.domain, MV88E6352_SERDES_IRQ);
275 return;
276
277 mv88e6352_serdes_irq_disable(chip);
278
279 /* Freeing the IRQ will trigger irq callbacks. So we cannot
280 * hold the reg_lock.
281 */
282 mv88e6xxx_reg_unlock(chip);
283 free_irq(chip->ports[port].serdes_irq, &chip->ports[port]);
284 mv88e6xxx_reg_lock(chip);
285
286 chip->ports[port].serdes_irq = 0;
287} 238}
288 239
289int mv88e6341_serdes_get_lane(struct mv88e6xxx_chip *chip, int port, u8 *lane) 240u8 mv88e6341_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
290{ 241{
291 u8 cmode = chip->ports[port].cmode; 242 u8 cmode = chip->ports[port].cmode;
243 u8 lane = 0;
292 244
293 if (port != 5) 245 switch (port) {
294 return -ENODEV; 246 case 5:
295 247 if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
296 if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX || 248 cmode == MV88E6XXX_PORT_STS_CMODE_SGMII ||
297 cmode == MV88E6XXX_PORT_STS_CMODE_SGMII || 249 cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
298 cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX) { 250 lane = MV88E6341_PORT5_LANE;
299 *lane = MV88E6341_PORT5_LANE; 251 break;
300 return 0;
301 } 252 }
302 253
303 return -ENODEV; 254 return lane;
304} 255}
305 256
306int mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port, u8 *lane) 257u8 mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
307{ 258{
308 u8 cmode = chip->ports[port].cmode; 259 u8 cmode = chip->ports[port].cmode;
260 u8 lane = 0;
309 261
310 switch (port) { 262 switch (port) {
311 case 9: 263 case 9:
312 if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX || 264 if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
313 cmode == MV88E6XXX_PORT_STS_CMODE_SGMII || 265 cmode == MV88E6XXX_PORT_STS_CMODE_SGMII ||
314 cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX) { 266 cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
315 *lane = MV88E6390_PORT9_LANE0; 267 lane = MV88E6390_PORT9_LANE0;
316 return 0;
317 }
318 break; 268 break;
319 case 10: 269 case 10:
320 if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX || 270 if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
321 cmode == MV88E6XXX_PORT_STS_CMODE_SGMII || 271 cmode == MV88E6XXX_PORT_STS_CMODE_SGMII ||
322 cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX) { 272 cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
323 *lane = MV88E6390_PORT10_LANE0; 273 lane = MV88E6390_PORT10_LANE0;
324 return 0;
325 }
326 break;
327 default:
328 break; 274 break;
329 } 275 }
330 276
331 return -ENODEV; 277 return lane;
332} 278}
333 279
334int mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port, u8 *lane) 280u8 mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
335{ 281{
336 u8 cmode_port9, cmode_port10, cmode_port; 282 u8 cmode_port = chip->ports[port].cmode;
337 283 u8 cmode_port10 = chip->ports[10].cmode;
338 cmode_port9 = chip->ports[9].cmode; 284 u8 cmode_port9 = chip->ports[9].cmode;
339 cmode_port10 = chip->ports[10].cmode; 285 u8 lane = 0;
340 cmode_port = chip->ports[port].cmode;
341 286
342 switch (port) { 287 switch (port) {
343 case 2: 288 case 2:
344 if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX || 289 if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
345 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII || 290 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
346 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX) { 291 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
347 if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX) { 292 if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX)
348 *lane = MV88E6390_PORT9_LANE1; 293 lane = MV88E6390_PORT9_LANE1;
349 return 0;
350 }
351 }
352 break; 294 break;
353 case 3: 295 case 3:
354 if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX || 296 if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
355 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII || 297 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
356 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX || 298 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
357 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI) { 299 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
358 if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX) { 300 if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX)
359 *lane = MV88E6390_PORT9_LANE2; 301 lane = MV88E6390_PORT9_LANE2;
360 return 0;
361 }
362 }
363 break; 302 break;
364 case 4: 303 case 4:
365 if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX || 304 if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
366 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII || 305 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
367 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX || 306 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
368 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI) { 307 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
369 if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX) { 308 if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX)
370 *lane = MV88E6390_PORT9_LANE3; 309 lane = MV88E6390_PORT9_LANE3;
371 return 0;
372 }
373 }
374 break; 310 break;
375 case 5: 311 case 5:
376 if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX || 312 if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
377 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII || 313 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
378 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX) { 314 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
379 if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX) { 315 if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX)
380 *lane = MV88E6390_PORT10_LANE1; 316 lane = MV88E6390_PORT10_LANE1;
381 return 0;
382 }
383 }
384 break; 317 break;
385 case 6: 318 case 6:
386 if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX || 319 if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
387 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII || 320 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
388 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX || 321 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
389 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI) { 322 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
390 if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX) { 323 if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX)
391 *lane = MV88E6390_PORT10_LANE2; 324 lane = MV88E6390_PORT10_LANE2;
392 return 0;
393 }
394 }
395 break; 325 break;
396 case 7: 326 case 7:
397 if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX || 327 if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
398 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII || 328 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
399 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX || 329 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
400 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI) { 330 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
401 if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX) { 331 if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX)
402 *lane = MV88E6390_PORT10_LANE3; 332 lane = MV88E6390_PORT10_LANE3;
403 return 0;
404 }
405 }
406 break; 333 break;
407 case 9: 334 case 9:
408 if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX || 335 if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
409 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII || 336 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
410 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX || 337 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
411 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_XAUI || 338 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_XAUI ||
412 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI) { 339 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
413 *lane = MV88E6390_PORT9_LANE0; 340 lane = MV88E6390_PORT9_LANE0;
414 return 0;
415 }
416 break; 341 break;
417 case 10: 342 case 10:
418 if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX || 343 if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
419 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII || 344 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
420 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX || 345 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
421 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_XAUI || 346 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_XAUI ||
422 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI) { 347 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
423 *lane = MV88E6390_PORT10_LANE0; 348 lane = MV88E6390_PORT10_LANE0;
424 return 0;
425 }
426 break;
427 default:
428 break; 349 break;
429 } 350 }
430 351
431 return -ENODEV; 352 return lane;
432} 353}
433 354
434/* Set the power on/off for 10GBASE-R and 10GBASE-X4/X2 */ 355/* Set power up/down for 10GBASE-R and 10GBASE-X4/X2 */
435static int mv88e6390_serdes_power_10g(struct mv88e6xxx_chip *chip, u8 lane, 356static int mv88e6390_serdes_power_10g(struct mv88e6xxx_chip *chip, u8 lane,
436 bool on) 357 bool up)
437{ 358{
438 u16 val, new_val; 359 u16 val, new_val;
439 int err; 360 int err;
@@ -444,7 +365,7 @@ static int mv88e6390_serdes_power_10g(struct mv88e6xxx_chip *chip, u8 lane,
444 if (err) 365 if (err)
445 return err; 366 return err;
446 367
447 if (on) 368 if (up)
448 new_val = val & ~(MV88E6390_PCS_CONTROL_1_RESET | 369 new_val = val & ~(MV88E6390_PCS_CONTROL_1_RESET |
449 MV88E6390_PCS_CONTROL_1_LOOPBACK | 370 MV88E6390_PCS_CONTROL_1_LOOPBACK |
450 MV88E6390_PCS_CONTROL_1_PDOWN); 371 MV88E6390_PCS_CONTROL_1_PDOWN);
@@ -458,9 +379,9 @@ static int mv88e6390_serdes_power_10g(struct mv88e6xxx_chip *chip, u8 lane,
458 return err; 379 return err;
459} 380}
460 381
461/* Set the power on/off for SGMII and 1000Base-X */ 382/* Set power up/down for SGMII and 1000Base-X */
462static int mv88e6390_serdes_power_sgmii(struct mv88e6xxx_chip *chip, u8 lane, 383static int mv88e6390_serdes_power_sgmii(struct mv88e6xxx_chip *chip, u8 lane,
463 bool on) 384 bool up)
464{ 385{
465 u16 val, new_val; 386 u16 val, new_val;
466 int err; 387 int err;
@@ -470,7 +391,7 @@ static int mv88e6390_serdes_power_sgmii(struct mv88e6xxx_chip *chip, u8 lane,
470 if (err) 391 if (err)
471 return err; 392 return err;
472 393
473 if (on) 394 if (up)
474 new_val = val & ~(MV88E6390_SGMII_CONTROL_RESET | 395 new_val = val & ~(MV88E6390_SGMII_CONTROL_RESET |
475 MV88E6390_SGMII_CONTROL_LOOPBACK | 396 MV88E6390_SGMII_CONTROL_LOOPBACK |
476 MV88E6390_SGMII_CONTROL_PDOWN); 397 MV88E6390_SGMII_CONTROL_PDOWN);
@@ -484,27 +405,19 @@ static int mv88e6390_serdes_power_sgmii(struct mv88e6xxx_chip *chip, u8 lane,
484 return err; 405 return err;
485} 406}
486 407
487int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on) 408int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, u8 lane,
409 bool up)
488{ 410{
489 u8 cmode = chip->ports[port].cmode; 411 u8 cmode = chip->ports[port].cmode;
490 u8 lane;
491 int err;
492
493 err = mv88e6xxx_serdes_get_lane(chip, port, &lane);
494 if (err) {
495 if (err == -ENODEV)
496 err = 0;
497 return err;
498 }
499 412
500 switch (cmode) { 413 switch (cmode) {
501 case MV88E6XXX_PORT_STS_CMODE_SGMII: 414 case MV88E6XXX_PORT_STS_CMODE_SGMII:
502 case MV88E6XXX_PORT_STS_CMODE_1000BASEX: 415 case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
503 case MV88E6XXX_PORT_STS_CMODE_2500BASEX: 416 case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
504 return mv88e6390_serdes_power_sgmii(chip, lane, on); 417 return mv88e6390_serdes_power_sgmii(chip, lane, up);
505 case MV88E6XXX_PORT_STS_CMODE_XAUI: 418 case MV88E6XXX_PORT_STS_CMODE_XAUI:
506 case MV88E6XXX_PORT_STS_CMODE_RXAUI: 419 case MV88E6XXX_PORT_STS_CMODE_RXAUI:
507 return mv88e6390_serdes_power_10g(chip, lane, on); 420 return mv88e6390_serdes_power_10g(chip, lane, up);
508 } 421 }
509 422
510 return 0; 423 return 0;
@@ -578,51 +491,31 @@ static void mv88e6390_serdes_irq_link_sgmii(struct mv88e6xxx_chip *chip,
578} 491}
579 492
580static int mv88e6390_serdes_irq_enable_sgmii(struct mv88e6xxx_chip *chip, 493static int mv88e6390_serdes_irq_enable_sgmii(struct mv88e6xxx_chip *chip,
581 u8 lane) 494 u8 lane, bool enable)
582{
583 return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
584 MV88E6390_SGMII_INT_ENABLE,
585 MV88E6390_SGMII_INT_LINK_DOWN |
586 MV88E6390_SGMII_INT_LINK_UP);
587}
588
589static int mv88e6390_serdes_irq_disable_sgmii(struct mv88e6xxx_chip *chip,
590 u8 lane)
591{ 495{
592 return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS, 496 u16 val = 0;
593 MV88E6390_SGMII_INT_ENABLE, 0);
594}
595 497
596int mv88e6390_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, 498 if (enable)
597 u8 lane) 499 val |= MV88E6390_SGMII_INT_LINK_DOWN |
598{ 500 MV88E6390_SGMII_INT_LINK_UP;
599 u8 cmode = chip->ports[port].cmode;
600 int err = 0;
601 501
602 switch (cmode) { 502 return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
603 case MV88E6XXX_PORT_STS_CMODE_SGMII: 503 MV88E6390_SGMII_INT_ENABLE, val);
604 case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
605 case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
606 err = mv88e6390_serdes_irq_enable_sgmii(chip, lane);
607 }
608
609 return err;
610} 504}
611 505
612int mv88e6390_serdes_irq_disable(struct mv88e6xxx_chip *chip, int port, 506int mv88e6390_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, u8 lane,
613 u8 lane) 507 bool enable)
614{ 508{
615 u8 cmode = chip->ports[port].cmode; 509 u8 cmode = chip->ports[port].cmode;
616 int err = 0;
617 510
618 switch (cmode) { 511 switch (cmode) {
619 case MV88E6XXX_PORT_STS_CMODE_SGMII: 512 case MV88E6XXX_PORT_STS_CMODE_SGMII:
620 case MV88E6XXX_PORT_STS_CMODE_1000BASEX: 513 case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
621 case MV88E6XXX_PORT_STS_CMODE_2500BASEX: 514 case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
622 err = mv88e6390_serdes_irq_disable_sgmii(chip, lane); 515 return mv88e6390_serdes_irq_enable_sgmii(chip, lane, enable);
623 } 516 }
624 517
625 return err; 518 return 0;
626} 519}
627 520
628static int mv88e6390_serdes_irq_status_sgmii(struct mv88e6xxx_chip *chip, 521static int mv88e6390_serdes_irq_status_sgmii(struct mv88e6xxx_chip *chip,
@@ -636,21 +529,13 @@ static int mv88e6390_serdes_irq_status_sgmii(struct mv88e6xxx_chip *chip,
636 return err; 529 return err;
637} 530}
638 531
639static irqreturn_t mv88e6390_serdes_thread_fn(int irq, void *dev_id) 532irqreturn_t mv88e6390_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
533 u8 lane)
640{ 534{
641 struct mv88e6xxx_port *port = dev_id; 535 u8 cmode = chip->ports[port].cmode;
642 struct mv88e6xxx_chip *chip = port->chip;
643 irqreturn_t ret = IRQ_NONE; 536 irqreturn_t ret = IRQ_NONE;
644 u8 cmode = port->cmode;
645 u16 status; 537 u16 status;
646 int err; 538 int err;
647 u8 lane;
648
649 mv88e6xxx_reg_lock(chip);
650
651 err = mv88e6xxx_serdes_get_lane(chip, port->port, &lane);
652 if (err)
653 goto out;
654 539
655 switch (cmode) { 540 switch (cmode) {
656 case MV88E6XXX_PORT_STS_CMODE_SGMII: 541 case MV88E6XXX_PORT_STS_CMODE_SGMII:
@@ -658,79 +543,18 @@ static irqreturn_t mv88e6390_serdes_thread_fn(int irq, void *dev_id)
658 case MV88E6XXX_PORT_STS_CMODE_2500BASEX: 543 case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
659 err = mv88e6390_serdes_irq_status_sgmii(chip, lane, &status); 544 err = mv88e6390_serdes_irq_status_sgmii(chip, lane, &status);
660 if (err) 545 if (err)
661 goto out; 546 return ret;
662 if (status & (MV88E6390_SGMII_INT_LINK_DOWN | 547 if (status & (MV88E6390_SGMII_INT_LINK_DOWN |
663 MV88E6390_SGMII_INT_LINK_UP)) { 548 MV88E6390_SGMII_INT_LINK_UP)) {
664 ret = IRQ_HANDLED; 549 ret = IRQ_HANDLED;
665 mv88e6390_serdes_irq_link_sgmii(chip, port->port, lane); 550 mv88e6390_serdes_irq_link_sgmii(chip, port, lane);
666 } 551 }
667 } 552 }
668out:
669 mv88e6xxx_reg_unlock(chip);
670 553
671 return ret; 554 return ret;
672} 555}
673 556
674int mv88e6390_serdes_irq_setup(struct mv88e6xxx_chip *chip, int port) 557unsigned int mv88e6390_serdes_irq_mapping(struct mv88e6xxx_chip *chip, int port)
675{
676 int err;
677 u8 lane;
678
679 err = mv88e6xxx_serdes_get_lane(chip, port, &lane);
680 if (err) {
681 if (err == -ENODEV)
682 err = 0;
683 return err;
684 }
685
686 chip->ports[port].serdes_irq = irq_find_mapping(chip->g2_irq.domain,
687 port);
688 if (chip->ports[port].serdes_irq < 0) {
689 dev_err(chip->dev, "Unable to map SERDES irq: %d\n",
690 chip->ports[port].serdes_irq);
691 return chip->ports[port].serdes_irq;
692 }
693
694 /* Requesting the IRQ will trigger irq callbacks. So we cannot
695 * hold the reg_lock.
696 */
697 mv88e6xxx_reg_unlock(chip);
698 err = request_threaded_irq(chip->ports[port].serdes_irq, NULL,
699 mv88e6390_serdes_thread_fn,
700 IRQF_ONESHOT, "mv88e6xxx-serdes",
701 &chip->ports[port]);
702 mv88e6xxx_reg_lock(chip);
703
704 if (err) {
705 dev_err(chip->dev, "Unable to request SERDES interrupt: %d\n",
706 err);
707 return err;
708 }
709
710 return mv88e6390_serdes_irq_enable(chip, port, lane);
711}
712
713void mv88e6390_serdes_irq_free(struct mv88e6xxx_chip *chip, int port)
714{ 558{
715 int err; 559 return irq_find_mapping(chip->g2_irq.domain, port);
716 u8 lane;
717
718 err = mv88e6xxx_serdes_get_lane(chip, port, &lane);
719 if (err) {
720 if (err != -ENODEV)
721 dev_err(chip->dev, "Unable to free SERDES irq: %d\n",
722 err);
723 return;
724 }
725
726 mv88e6390_serdes_irq_disable(chip, port, lane);
727
728 /* Freeing the IRQ will trigger irq callbacks. So we cannot
729 * hold the reg_lock.
730 */
731 mv88e6xxx_reg_unlock(chip);
732 free_irq(chip->ports[port].serdes_irq, &chip->ports[port]);
733 mv88e6xxx_reg_lock(chip);
734
735 chip->ports[port].serdes_irq = 0;
736} 560}
diff --git a/drivers/net/dsa/mv88e6xxx/serdes.h b/drivers/net/dsa/mv88e6xxx/serdes.h
index c2e6fc3ddf8b..bd8df36ab537 100644
--- a/drivers/net/dsa/mv88e6xxx/serdes.h
+++ b/drivers/net/dsa/mv88e6xxx/serdes.h
@@ -74,37 +74,94 @@
74#define MV88E6390_SGMII_PHY_STATUS_SPD_DPL_VALID BIT(11) 74#define MV88E6390_SGMII_PHY_STATUS_SPD_DPL_VALID BIT(11)
75#define MV88E6390_SGMII_PHY_STATUS_LINK BIT(10) 75#define MV88E6390_SGMII_PHY_STATUS_LINK BIT(10)
76 76
77/* Put the SERDES lane address a port is using into *lane. If a port has 77u8 mv88e6341_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
78 * multiple lanes, should put the first lane the port is using. If a port does 78u8 mv88e6352_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
79 * not have a lane, return -ENODEV. 79u8 mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
80 */ 80u8 mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
81static inline int mv88e6xxx_serdes_get_lane(struct mv88e6xxx_chip *chip, 81unsigned int mv88e6352_serdes_irq_mapping(struct mv88e6xxx_chip *chip,
82 int port, u8 *lane) 82 int port);
83unsigned int mv88e6390_serdes_irq_mapping(struct mv88e6xxx_chip *chip,
84 int port);
85int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, u8 lane,
86 bool on);
87int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, u8 lane,
88 bool on);
89int mv88e6352_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, u8 lane,
90 bool enable);
91int mv88e6390_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, u8 lane,
92 bool enable);
93irqreturn_t mv88e6352_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
94 u8 lane);
95irqreturn_t mv88e6390_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
96 u8 lane);
97int mv88e6352_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port);
98int mv88e6352_serdes_get_strings(struct mv88e6xxx_chip *chip,
99 int port, uint8_t *data);
100int mv88e6352_serdes_get_stats(struct mv88e6xxx_chip *chip, int port,
101 uint64_t *data);
102
103/* Return the (first) SERDES lane address a port is using, 0 otherwise. */
104static inline u8 mv88e6xxx_serdes_get_lane(struct mv88e6xxx_chip *chip,
105 int port)
83{ 106{
84 if (!chip->info->ops->serdes_get_lane) 107 if (!chip->info->ops->serdes_get_lane)
108 return 0;
109
110 return chip->info->ops->serdes_get_lane(chip, port);
111}
112
113static inline int mv88e6xxx_serdes_power_up(struct mv88e6xxx_chip *chip,
114 int port, u8 lane)
115{
116 if (!chip->info->ops->serdes_power)
85 return -EOPNOTSUPP; 117 return -EOPNOTSUPP;
86 118
87 return chip->info->ops->serdes_get_lane(chip, port, lane); 119 return chip->info->ops->serdes_power(chip, port, lane, true);
88} 120}
89 121
90int mv88e6341_serdes_get_lane(struct mv88e6xxx_chip *chip, int port, u8 *lane); 122static inline int mv88e6xxx_serdes_power_down(struct mv88e6xxx_chip *chip,
91int mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port, u8 *lane); 123 int port, u8 lane)
92int mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port, u8 *lane); 124{
93int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on); 125 if (!chip->info->ops->serdes_power)
94int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on); 126 return -EOPNOTSUPP;
95int mv88e6390_serdes_irq_setup(struct mv88e6xxx_chip *chip, int port);
96void mv88e6390_serdes_irq_free(struct mv88e6xxx_chip *chip, int port);
97int mv88e6352_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port);
98int mv88e6352_serdes_get_strings(struct mv88e6xxx_chip *chip,
99 int port, uint8_t *data);
100int mv88e6352_serdes_get_stats(struct mv88e6xxx_chip *chip, int port,
101 uint64_t *data);
102int mv88e6390_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port,
103 u8 lane);
104int mv88e6390_serdes_irq_disable(struct mv88e6xxx_chip *chip, int port,
105 u8 lane);
106int mv88e6352_serdes_irq_setup(struct mv88e6xxx_chip *chip, int port);
107void mv88e6352_serdes_irq_free(struct mv88e6xxx_chip *chip, int port);
108 127
128 return chip->info->ops->serdes_power(chip, port, lane, false);
129}
130
131static inline unsigned int
132mv88e6xxx_serdes_irq_mapping(struct mv88e6xxx_chip *chip, int port)
133{
134 if (!chip->info->ops->serdes_irq_mapping)
135 return 0;
136
137 return chip->info->ops->serdes_irq_mapping(chip, port);
138}
139
140static inline int mv88e6xxx_serdes_irq_enable(struct mv88e6xxx_chip *chip,
141 int port, u8 lane)
142{
143 if (!chip->info->ops->serdes_irq_enable)
144 return -EOPNOTSUPP;
145
146 return chip->info->ops->serdes_irq_enable(chip, port, lane, true);
147}
148
149static inline int mv88e6xxx_serdes_irq_disable(struct mv88e6xxx_chip *chip,
150 int port, u8 lane)
151{
152 if (!chip->info->ops->serdes_irq_enable)
153 return -EOPNOTSUPP;
154
155 return chip->info->ops->serdes_irq_enable(chip, port, lane, false);
156}
157
158static inline irqreturn_t
159mv88e6xxx_serdes_irq_status(struct mv88e6xxx_chip *chip, int port, u8 lane)
160{
161 if (!chip->info->ops->serdes_irq_status)
162 return IRQ_NONE;
163
164 return chip->info->ops->serdes_irq_status(chip, port, lane);
165}
109 166
110#endif 167#endif