diff options
Diffstat (limited to 'drivers/net/phy/dp83640.c')
| -rw-r--r-- | drivers/net/phy/dp83640.c | 268 |
1 files changed, 117 insertions, 151 deletions
diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c index ecbd5e0d685c..b950acc9c49b 100644 --- a/drivers/net/phy/dp83640.c +++ b/drivers/net/phy/dp83640.c @@ -50,6 +50,14 @@ #define MII_DP83640_MISR_LINK_INT_EN 0x20 #define MII_DP83640_MISR_ED_INT_EN 0x40 #define MII_DP83640_MISR_LQ_INT_EN 0x80 +#define MII_DP83640_MISR_ANC_INT 0x400 +#define MII_DP83640_MISR_DUP_INT 0x800 +#define MII_DP83640_MISR_SPD_INT 0x1000 +#define MII_DP83640_MISR_LINK_INT 0x2000 +#define MII_DP83640_MISR_INT_MASK (MII_DP83640_MISR_ANC_INT |\ + MII_DP83640_MISR_DUP_INT |\ + MII_DP83640_MISR_SPD_INT |\ + MII_DP83640_MISR_LINK_INT) /* phyter seems to miss the mark by 16 ns */ #define ADJTIME_FIX 16 @@ -162,9 +170,9 @@ static ushort gpio_tab[GPIO_TABLE_SIZE] = { module_param(chosen_phy, int, 0444); module_param_array(gpio_tab, ushort, NULL, 0444); -MODULE_PARM_DESC(chosen_phy, \ +MODULE_PARM_DESC(chosen_phy, "The address of the PHY to use for the ancillary clock features"); -MODULE_PARM_DESC(gpio_tab, \ +MODULE_PARM_DESC(gpio_tab, "Which GPIO line to use for which purpose: cal,perout,extts1,...,extts6"); static void dp83640_gpio_defaults(struct ptp_pin_desc *pd) @@ -470,13 +478,6 @@ static int ptp_dp83640_enable(struct ptp_clock_info *ptp, switch (rq->type) { case PTP_CLK_REQ_EXTTS: - /* Reject requests with unsupported flags */ - if (rq->extts.flags & ~(PTP_ENABLE_FEATURE | - PTP_RISING_EDGE | - PTP_FALLING_EDGE | - PTP_STRICT_FLAGS)) - return -EOPNOTSUPP; - /* Reject requests to enable time stamping on both edges. */ if ((rq->extts.flags & PTP_STRICT_FLAGS) && (rq->extts.flags & PTP_ENABLE_FEATURE) && @@ -505,9 +506,6 @@ static int ptp_dp83640_enable(struct ptp_clock_info *ptp, return 0; case PTP_CLK_REQ_PEROUT: - /* Reject requests with unsupported flags */ - if (rq->perout.flags) - return -EOPNOTSUPP; if (rq->perout.index >= N_PER_OUT) return -EINVAL; return periodic_output(clock, rq, on, rq->perout.index); @@ -607,6 +605,7 @@ static void prune_rx_ts(struct dp83640_private *dp83640) static void enable_broadcast(struct phy_device *phydev, int init_page, int on) { int val; + phy_write(phydev, PAGESEL, 0); val = phy_read(phydev, PHYCR2); if (on) @@ -622,7 +621,6 @@ static void recalibrate(struct dp83640_clock *clock) s64 now, diff; struct phy_txts event_ts; struct timespec64 ts; - struct list_head *this; struct dp83640_private *tmp; struct phy_device *master = clock->chosen->phydev; u16 cal_gpio, cfg0, evnt, ptp_trig, trigger, val; @@ -639,8 +637,7 @@ static void recalibrate(struct dp83640_clock *clock) /* * enable broadcast, disable status frames, enable ptp clock */ - list_for_each(this, &clock->phylist) { - tmp = list_entry(this, struct dp83640_private, list); + list_for_each_entry(tmp, &clock->phylist, list) { enable_broadcast(tmp->phydev, clock->page, 1); tmp->cfg0 = ext_read(tmp->phydev, PAGE5, PSF_CFG0); ext_write(0, tmp->phydev, PAGE5, PSF_CFG0, 0); @@ -658,10 +655,8 @@ static void recalibrate(struct dp83640_clock *clock) evnt |= (CAL_EVENT & EVNT_SEL_MASK) << EVNT_SEL_SHIFT; evnt |= (cal_gpio & EVNT_GPIO_MASK) << EVNT_GPIO_SHIFT; - list_for_each(this, &clock->phylist) { - tmp = list_entry(this, struct dp83640_private, list); + list_for_each_entry(tmp, &clock->phylist, list) ext_write(0, tmp->phydev, PAGE5, PTP_EVNT, evnt); - } ext_write(0, master, PAGE5, PTP_EVNT, evnt); /* @@ -700,8 +695,7 @@ static void recalibrate(struct dp83640_clock *clock) event_ts.sec_hi = ext_read(master, PAGE4, PTP_EDATA); now = phy2txts(&event_ts); - list_for_each(this, &clock->phylist) { - tmp = list_entry(this, struct dp83640_private, list); + list_for_each_entry(tmp, &clock->phylist, list) { val = ext_read(tmp->phydev, PAGE4, PTP_STS); phydev_info(tmp->phydev, "slave PTP_STS 0x%04hx\n", val); val = ext_read(tmp->phydev, PAGE4, PTP_ESTS); @@ -721,10 +715,8 @@ static void recalibrate(struct dp83640_clock *clock) /* * restore status frames */ - list_for_each(this, &clock->phylist) { - tmp = list_entry(this, struct dp83640_private, list); + list_for_each_entry(tmp, &clock->phylist, list) ext_write(0, tmp->phydev, PAGE5, PSF_CFG0, tmp->cfg0); - } ext_write(0, master, PAGE5, PSF_CFG0, cfg0); mutex_unlock(&clock->extreg_lock); @@ -766,13 +758,13 @@ static int decode_evnt(struct dp83640_private *dp83640, switch (words) { case 3: dp83640->edata.sec_hi = phy_txts->sec_hi; - /* fall through */ + fallthrough; case 2: dp83640->edata.sec_lo = phy_txts->sec_lo; - /* fall through */ + fallthrough; case 1: dp83640->edata.ns_hi = phy_txts->ns_hi; - /* fall through */ + fallthrough; case 0: dp83640->edata.ns_lo = phy_txts->ns_lo; } @@ -798,50 +790,32 @@ static int decode_evnt(struct dp83640_private *dp83640, return parsed; } -#define DP83640_PACKET_HASH_OFFSET 20 #define DP83640_PACKET_HASH_LEN 10 static int match(struct sk_buff *skb, unsigned int type, struct rxts *rxts) { - u16 *seqid, hash; - unsigned int offset = 0; - u8 *msgtype, *data = skb_mac_header(skb); + struct ptp_header *hdr; + u8 msgtype; + u16 seqid; + u16 hash; /* check sequenceID, messageType, 12 bit hash of offset 20-29 */ - if (type & PTP_CLASS_VLAN) - offset += VLAN_HLEN; - - switch (type & PTP_CLASS_PMASK) { - case PTP_CLASS_IPV4: - offset += ETH_HLEN + IPV4_HLEN(data + offset) + UDP_HLEN; - break; - case PTP_CLASS_IPV6: - offset += ETH_HLEN + IP6_HLEN + UDP_HLEN; - break; - case PTP_CLASS_L2: - offset += ETH_HLEN; - break; - default: + hdr = ptp_parse_header(skb, type); + if (!hdr) return 0; - } - if (skb->len + ETH_HLEN < offset + OFF_PTP_SEQUENCE_ID + sizeof(*seqid)) - return 0; + msgtype = ptp_get_msgtype(hdr, type); - if (unlikely(type & PTP_CLASS_V1)) - msgtype = data + offset + OFF_PTP_CONTROL; - else - msgtype = data + offset; - if (rxts->msgtype != (*msgtype & 0xf)) + if (rxts->msgtype != (msgtype & 0xf)) return 0; - seqid = (u16 *)(data + offset + OFF_PTP_SEQUENCE_ID); - if (rxts->seqid != ntohs(*seqid)) + seqid = be16_to_cpu(hdr->sequence_id); + if (rxts->seqid != seqid) return 0; hash = ether_crc(DP83640_PACKET_HASH_LEN, - data + offset + DP83640_PACKET_HASH_OFFSET) >> 20; + (unsigned char *)&hdr->source_port_identity) >> 20; if (rxts->hash != hash) return 0; @@ -895,7 +869,7 @@ out: spin_unlock_irqrestore(&dp83640->rx_lock, flags); if (shhwtstamps) - netif_rx_ni(skb); + netif_rx(skb); } static void decode_txts(struct dp83640_private *dp83640, @@ -979,63 +953,6 @@ static void decode_status_frame(struct dp83640_private *dp83640, } } -static int is_sync(struct sk_buff *skb, int type) -{ - u8 *data = skb->data, *msgtype; - unsigned int offset = 0; - - if (type & PTP_CLASS_VLAN) - offset += VLAN_HLEN; - - switch (type & PTP_CLASS_PMASK) { - case PTP_CLASS_IPV4: - offset += ETH_HLEN + IPV4_HLEN(data + offset) + UDP_HLEN; - break; - case PTP_CLASS_IPV6: - offset += ETH_HLEN + IP6_HLEN + UDP_HLEN; - break; - case PTP_CLASS_L2: - offset += ETH_HLEN; - break; - default: - return 0; - } - - if (type & PTP_CLASS_V1) - offset += OFF_PTP_CONTROL; - - if (skb->len < offset + 1) - return 0; - - msgtype = data + offset; - - return (*msgtype & 0xf) == 0; -} - -static void dp83640_free_clocks(void) -{ - struct dp83640_clock *clock; - struct list_head *this, *next; - - mutex_lock(&phyter_clocks_lock); - - list_for_each_safe(this, next, &phyter_clocks) { - clock = list_entry(this, struct dp83640_clock, list); - if (!list_empty(&clock->phylist)) { - pr_warn("phy list non-empty while unloading\n"); - BUG(); - } - list_del(&clock->list); - mutex_destroy(&clock->extreg_lock); - mutex_destroy(&clock->clock_lock); - put_device(&clock->bus->dev); - kfree(clock->caps.pin_config); - kfree(clock); - } - - mutex_unlock(&phyter_clocks_lock); -} - static void dp83640_clock_init(struct dp83640_clock *clock, struct mii_bus *bus) { INIT_LIST_HEAD(&clock->list); @@ -1051,6 +968,9 @@ static void dp83640_clock_init(struct dp83640_clock *clock, struct mii_bus *bus) clock->caps.n_per_out = N_PER_OUT; clock->caps.n_pins = DP83640_N_PINS; clock->caps.pps = 0; + clock->caps.supported_extts_flags = PTP_RISING_EDGE | + PTP_FALLING_EDGE | + PTP_STRICT_FLAGS; clock->caps.adjfine = ptp_dp83640_adjfine; clock->caps.adjtime = ptp_dp83640_adjtime; clock->caps.gettime64 = ptp_dp83640_gettime; @@ -1188,6 +1108,10 @@ static int dp83640_config_intr(struct phy_device *phydev) int err; if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { + err = dp83640_ack_interrupt(phydev); + if (err) + return err; + misr = phy_read(phydev, MII_DP83640_MISR); if (misr < 0) return misr; @@ -1226,29 +1150,58 @@ static int dp83640_config_intr(struct phy_device *phydev) MII_DP83640_MISR_DUP_INT_EN | MII_DP83640_MISR_SPD_INT_EN | MII_DP83640_MISR_LINK_INT_EN); - return phy_write(phydev, MII_DP83640_MISR, misr); + err = phy_write(phydev, MII_DP83640_MISR, misr); + if (err) + return err; + + return dp83640_ack_interrupt(phydev); } } -static int dp83640_hwtstamp(struct mii_timestamper *mii_ts, struct ifreq *ifr) +static irqreturn_t dp83640_handle_interrupt(struct phy_device *phydev) +{ + int irq_status; + + irq_status = phy_read(phydev, MII_DP83640_MISR); + if (irq_status < 0) { + phy_error(phydev); + return IRQ_NONE; + } + + if (!(irq_status & MII_DP83640_MISR_INT_MASK)) + return IRQ_NONE; + + phy_trigger_machine(phydev); + + return IRQ_HANDLED; +} + +static int dp83640_hwtstamp_get(struct mii_timestamper *mii_ts, + struct kernel_hwtstamp_config *cfg) { struct dp83640_private *dp83640 = container_of(mii_ts, struct dp83640_private, mii_ts); - struct hwtstamp_config cfg; - u16 txcfg0, rxcfg0; - if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg))) - return -EFAULT; + cfg->rx_filter = dp83640->hwts_rx_en; + cfg->tx_type = dp83640->hwts_tx_en; - if (cfg.flags) /* reserved for future extensions */ - return -EINVAL; + return 0; +} - if (cfg.tx_type < 0 || cfg.tx_type > HWTSTAMP_TX_ONESTEP_SYNC) +static int dp83640_hwtstamp_set(struct mii_timestamper *mii_ts, + struct kernel_hwtstamp_config *cfg, + struct netlink_ext_ack *extack) +{ + struct dp83640_private *dp83640 = + container_of(mii_ts, struct dp83640_private, mii_ts); + u16 txcfg0, rxcfg0; + + if (cfg->tx_type < 0 || cfg->tx_type > HWTSTAMP_TX_ONESTEP_SYNC) return -ERANGE; - dp83640->hwts_tx_en = cfg.tx_type; + dp83640->hwts_tx_en = cfg->tx_type; - switch (cfg.rx_filter) { + switch (cfg->rx_filter) { case HWTSTAMP_FILTER_NONE: dp83640->hwts_rx_en = 0; dp83640->layer = 0; @@ -1257,30 +1210,34 @@ static int dp83640_hwtstamp(struct mii_timestamper *mii_ts, struct ifreq *ifr) case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: - dp83640->hwts_rx_en = 1; + dp83640->hwts_rx_en = HWTSTAMP_FILTER_PTP_V1_L4_EVENT; dp83640->layer = PTP_CLASS_L4; dp83640->version = PTP_CLASS_V1; + cfg->rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT; break; case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: - dp83640->hwts_rx_en = 1; + dp83640->hwts_rx_en = HWTSTAMP_FILTER_PTP_V2_L4_EVENT; dp83640->layer = PTP_CLASS_L4; dp83640->version = PTP_CLASS_V2; + cfg->rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT; break; case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: - dp83640->hwts_rx_en = 1; + dp83640->hwts_rx_en = HWTSTAMP_FILTER_PTP_V2_L2_EVENT; dp83640->layer = PTP_CLASS_L2; dp83640->version = PTP_CLASS_V2; + cfg->rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT; break; case HWTSTAMP_FILTER_PTP_V2_EVENT: case HWTSTAMP_FILTER_PTP_V2_SYNC: case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: - dp83640->hwts_rx_en = 1; + dp83640->hwts_rx_en = HWTSTAMP_FILTER_PTP_V2_EVENT; dp83640->layer = PTP_CLASS_L4 | PTP_CLASS_L2; dp83640->version = PTP_CLASS_V2; + cfg->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; break; default: return -ERANGE; @@ -1314,7 +1271,7 @@ static int dp83640_hwtstamp(struct mii_timestamper *mii_ts, struct ifreq *ifr) mutex_unlock(&dp83640->clock->extreg_lock); - return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0; + return 0; } static void rx_timestamp_work(struct work_struct *work) @@ -1333,7 +1290,7 @@ static void rx_timestamp_work(struct work_struct *work) break; } - netif_rx_ni(skb); + netif_rx(skb); } if (!skb_queue_empty(&dp83640->rx_queue)) @@ -1384,7 +1341,7 @@ static bool dp83640_rxtstamp(struct mii_timestamper *mii_ts, skb_queue_tail(&dp83640->rx_queue, skb); schedule_delayed_work(&dp83640->ts_work, SKB_TIMESTAMP_TIMEOUT); } else { - netif_rx_ni(skb); + netif_rx(skb); } return true; @@ -1400,11 +1357,11 @@ static void dp83640_txtstamp(struct mii_timestamper *mii_ts, switch (dp83640->hwts_tx_en) { case HWTSTAMP_TX_ONESTEP_SYNC: - if (is_sync(skb, type)) { + if (ptp_msg_is_sync(skb, type)) { kfree_skb(skb); return; } - /* fall through */ + fallthrough; case HWTSTAMP_TX_ON: skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; skb_info->tmo = jiffies + SKB_TIMESTAMP_TIMEOUT; @@ -1419,7 +1376,7 @@ static void dp83640_txtstamp(struct mii_timestamper *mii_ts, } static int dp83640_ts_info(struct mii_timestamper *mii_ts, - struct ethtool_ts_info *info) + struct kernel_ethtool_ts_info *info) { struct dp83640_private *dp83640 = container_of(mii_ts, struct dp83640_private, mii_ts); @@ -1462,7 +1419,8 @@ static int dp83640_probe(struct phy_device *phydev) dp83640->phydev = phydev; dp83640->mii_ts.rxtstamp = dp83640_rxtstamp; dp83640->mii_ts.txtstamp = dp83640_txtstamp; - dp83640->mii_ts.hwtstamp = dp83640_hwtstamp; + dp83640->mii_ts.hwtstamp_set = dp83640_hwtstamp_set; + dp83640->mii_ts.hwtstamp_get = dp83640_hwtstamp_get; dp83640->mii_ts.ts_info = dp83640_ts_info; INIT_DELAYED_WORK(&dp83640->ts_work, rx_timestamp_work); @@ -1471,6 +1429,8 @@ static int dp83640_probe(struct phy_device *phydev) for (i = 0; i < MAX_RXTS; i++) list_add(&dp83640->rx_pool_data[i].list, &dp83640->rxpool); + /* Timestamp selected by default to keep legacy API */ + phydev->default_timestamp = true; phydev->mii_ts = &dp83640->mii_ts; phydev->priv = dp83640; @@ -1508,6 +1468,7 @@ static void dp83640_remove(struct phy_device *phydev) struct dp83640_clock *clock; struct list_head *this, *next; struct dp83640_private *tmp, *dp83640 = phydev->priv; + bool remove_clock = false; if (phydev->mdio.addr == BROADCAST_ADDR) return; @@ -1535,11 +1496,27 @@ static void dp83640_remove(struct phy_device *phydev) } } + if (!clock->chosen && list_empty(&clock->phylist)) + remove_clock = true; + dp83640_clock_put(clock); kfree(dp83640); + + if (remove_clock) { + mutex_lock(&phyter_clocks_lock); + list_del(&clock->list); + mutex_unlock(&phyter_clocks_lock); + + mutex_destroy(&clock->extreg_lock); + mutex_destroy(&clock->clock_lock); + put_device(&clock->bus->dev); + kfree(clock->caps.pin_config); + kfree(clock); + } } -static struct phy_driver dp83640_driver = { +static struct phy_driver dp83640_driver[] = { +{ .phy_id = DP83640_PHY_ID, .phy_id_mask = 0xfffffff0, .name = "NatSemi DP83640", @@ -1548,29 +1525,18 @@ static struct phy_driver dp83640_driver = { .remove = dp83640_remove, .soft_reset = dp83640_soft_reset, .config_init = dp83640_config_init, - .ack_interrupt = dp83640_ack_interrupt, .config_intr = dp83640_config_intr, + .handle_interrupt = dp83640_handle_interrupt, +}, }; -static int __init dp83640_init(void) -{ - return phy_driver_register(&dp83640_driver, THIS_MODULE); -} - -static void __exit dp83640_exit(void) -{ - dp83640_free_clocks(); - phy_driver_unregister(&dp83640_driver); -} +module_phy_driver(dp83640_driver); MODULE_DESCRIPTION("National Semiconductor DP83640 PHY driver"); MODULE_AUTHOR("Richard Cochran <richardcochran@gmail.com>"); MODULE_LICENSE("GPL"); -module_init(dp83640_init); -module_exit(dp83640_exit); - -static struct mdio_device_id __maybe_unused dp83640_tbl[] = { +static const struct mdio_device_id __maybe_unused dp83640_tbl[] = { { DP83640_PHY_ID, 0xfffffff0 }, { } }; |
