lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <CAGCDX1nLbVKRYp-LQXv0DiYng2P1C8i_xBY+kdAemoKhyWe7Fw@mail.gmail.com>
Date:	Tue, 24 Jul 2012 09:58:53 +0800
From:	Jason Lin <kernel.jason@...il.com>
To:	Andy Fleming <afleming@...il.com>
Cc:	Florian Fainelli <florian@...nwrt.org>, netdev@...r.kernel.org
Subject: Re: [RFC] net:phy:phylib: phy shares the same interrupt with mac

Any comments will be appreciated.
Thanks.

2012/7/13 Jason Lin <kernel.jason@...il.com>:
> Dear:
> But I think there have some performance issues.
> Because the phy should execute its own ISR only when the interrupt is
> issued by phy.
> This will cause some unnecessary MDIO access.
>
> By the way, PHY_DUMMY_IRQ is defined in the platform definition file.
> One should get PHY_DUMMY_IRQ by platform_get_irq function.
> So the driver will look like this:
>
> /*** platform related file ***************/
> static struct resource mac_0_resources[] = {
>     {
>         .start  = MAC_PA_BASE,
>         .end    = MAC_PA_BASE + SZ_4K - 1,
>         .flags  = IORESOURCE_MEM,
>     }, {
>         .start  = IRQ_MAC,
>         .flags  = IORESOURCE_IRQ,
>     }, {
>         .start  = IRQ_PHY,
>         .flags  = IORESOURCE_IRQ,
>     },
> };
>
>
> /*** driver file ***************/
> mydriver_probe(struct platform_device *pdev)
> {
>     int mac_irq, phy_irq, i;
>
>     mac_irq = platform_get_irq(pdev, 0);
>     if (mac_irq < 0)
>         return mac_irq;
>
>     phy_irq = platform_get_irq(pdev, 1);
>     if (phy_irq < 0)
>         phy_irq = PHY_POLL;
>
>     for (i = 0; i < PHY_MAX_ADDR; i++)
>         priv->mii_bus->irq[i] = phy_irq;
> }
>
> mydriver_napi_poll(struct napi_struct *napi, int budget)
> {
>     struct mydriver_priv *priv = = container_of(napi, struct
> mydriver_priv, napi);
>     struct phy_device *phydev = priv->phydev;
>     unsigned int status = get_int_status();
>
> #ifdef CONFIG_MAC_CONTROL_PHY_INT
>     if (status & PHY_INT) {
>         tasklet_schedule(&phydev->phy_task);
>     }
> #endif
>
> }
>
> /**** phy lib modification ***************/
> diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
> index 3cbda08..482f7e5 100644
> --- a/drivers/net/phy/phy.c
> +++ b/drivers/net/phy/phy.c
> @@ -416,7 +416,7 @@ out_unlock:
>  }
>  EXPORT_SYMBOL(phy_start_aneg);
>
> -
> +static void phy_tasklet(unsigned long data);
>  static void phy_change(struct work_struct *work);
>
>  /**
> @@ -523,10 +523,12 @@ static irqreturn_t phy_interrupt(int irq, void *phy_dat)
>      * context, so we need to disable the irq here.  A work
>      * queue will write the PHY to disable and clear the
>      * interrupt, and then reenable the irq line. */
> -   disable_irq_nosync(irq);
> +/* disable_irq_nosync(irq);
>     atomic_inc(&phydev->irq_disable);
>
> -   schedule_work(&phydev->phy_queue);
> +   schedule_work(&phydev->phy_queue);*/
> +
> +   tasklet_schedule(&phydev->phy_task);
>
>     return IRQ_HANDLED;
>  }
> @@ -591,6 +593,7 @@ int phy_start_interrupts(struct phy_device *phydev)
>  {
>     int err = 0;
>
> +   tasklet_init(&phydev->phy_task, phy_tasklet, (unsigned long)phydev);
>     INIT_WORK(&phydev->phy_queue, phy_change);
>
>     atomic_set(&phydev->irq_disable, 0);
> @@ -633,6 +636,7 @@ int phy_stop_interrupts(struct phy_device *phydev)
>      * possibly pending and take care of the matter below.
>      */
>     cancel_work_sync(&phydev->phy_queue);
> +   tasklet_kill(&phydev->phy_task);
>     /*
>      * If work indeed has been cancelled, disable_irq() will have
>      * been left unbalanced from phy_interrupt() and enable_irq()
> @@ -645,7 +649,13 @@ int phy_stop_interrupts(struct phy_device *phydev)
>  }
>  EXPORT_SYMBOL(phy_stop_interrupts);
>
>
> -
> +static void phy_tasklet(unsigned long data)
> +{
> +   struct phy_device *phydev = (struct phy_device *)data;
> +   disable_irq_nosync(phydev->irq);
> +   atomic_inc(&phydev->irq_disable);
> +   schedule_work(&phydev->phy_queue);
> +}
>  /**
>   * phy_change - Scheduled by the phy_interrupt/timer to handle PHY changes
>   * @work: work_struct that describes the work to be done
> diff --git a/include/linux/phy.h b/include/linux/phy.h
> index c599f7e..04203a7 100644
> --- a/include/linux/phy.h
> +++ b/include/linux/phy.h
> @@ -330,6 +330,7 @@ struct phy_device {
>     /* Interrupt and Polling infrastructure */
>     struct work_struct phy_queue;
>     struct delayed_work state_queue;
> +   struct tasklet_struct phy_task;
>     atomic_t irq_disable;
>
>     struct mutex lock;
>
> /*** end modification **********************************/
>
> how about this modification?
> F.Y.I.
> Thanks.
>
> 2012/7/13 Jason Lin <kernel.jason@...il.com>:
>> Thank for your reply.
>> My case is the second one.
>> change request_irq with IRQF_SHARED, and assign the same MAC irq number to phy
>> (mii_bus->irq[i] = mac_irq)
>> This way can fix my issue.
>>
>> Thanks again.
>>
>> 2012/7/13 Andy Fleming <afleming@...il.com>:
>>> On Tue, Jul 10, 2012 at 8:32 PM, Jason Lin <kernel.jason@...il.com> wrote:
>>>> Dear :
>>>> I describe my situation again.
>>>> In my hardware design, the interrupt (INT) pin of phy is connected to
>>>> the INT input pin of MAC.
>>>> In other words, one of triggering interrupt condition of MAC is
>>>> related to phy's interrupt.
>>>> So the phy will share the same "IRQ pin" with MAC.
>>>> As described above, the best solution is the INT pin of phy is
>>>> connected to architecture independently.
>>>> But, the hardware architecture cannot modify easily.
>>>> So I think
>>>> 1. We can assign dummy IRQ number (which is a empty IRQ number but
>>>> large than zero) to phy.
>>>> phydev->irq = PHY_DUMMY_IRQ (this value is depend on architecture)
>>>> 2. Change to do the soft IRQ in phy's ISR.
>>>>     To schedule workqueue in this soft IRQ.
>>>> In this way, the MAC can schedule phy's soft IRQ to do phy's work
>>>> queue (to do ack phy's interrupt ... etc).
>>>>
>>>> Dose it make sense?
>>>>
>>>
>>> If PHY_IGNORE_INTERRUPT doesn't currently work to allow a MAC's driver
>>> to manage PHY interrupts, then we need to fix PHY Lib to support this
>>> correctly. PHY_IGNORE_INTERRUPT was meant for this purpose. We don't
>>> want to start defining interrupt numbers which may conflict with real
>>> numbers, and have to be constantly re-defined by various systems to
>>> avoid that.
>>>
>>> Your notion of making the phy_enable_interrupts() and
>>> phy_disable_interrupts() code available to the MAC drivers sounds like
>>> the right approach to me. But you might want to implement your own
>>> version. The biggest problem with PHY interrupts is that masking them
>>> requires an MDIO transaction, which is *slow*. If you can mask the
>>> interrupt by writing a bit in a memory-mapped register, it's far
>>> better to do it that way, at interrupt time, and *then* schedule the
>>> PHY code to be run from a work queue. However, your driver probably
>>> already *does* have a workqueue of some sort. If so, what you should
>>> probably do is implement a new version of phy_change(), that doesn't
>>> have to deal with the weird PHY interrupt masking issues. Something
>>> like this:
>>>
>>> mydriver_phy_change(struct mydriver_priv *priv)
>>> {
>>>         int err;
>>>         struct phy_device *phydev = priv->phydev;
>>>
>>>         if (phydev->drv->did_interrupt &&
>>>             !phydev->drv->did_interrupt(phydev))
>>>                 goto ignore;
>>>
>>>         err = phy_disable_interrupts(phydev);
>>>
>>>         if (err)
>>>                 goto phy_err;
>>>
>>>         mutex_lock(&phydev->lock);
>>>         if ((PHY_RUNNING == phydev->state) || (PHY_NOLINK == phydev->state))
>>>                 phydev->state = PHY_CHANGELINK;
>>>         mutex_unlock(&phydev->lock);
>>>
>>>         /* Reenable interrupts */
>>>         if (PHY_HALTED != phydev->state)
>>>                 err = phy_config_interrupt(phydev, PHY_INTERRUPT_ENABLED);
>>>
>>>         if (err)
>>>                 goto irq_enable_err;
>>>
>>>         /* reschedule state queue work to run as soon as possible */
>>>         cancel_delayed_work_sync(&phydev->state_queue);
>>>         schedule_delayed_work(&phydev->state_queue, 0);
>>>
>>>         return;
>>>
>>> ignore:
>>>         return;
>>>
>>> irq_enable_err:
>>> phy_err:
>>>         phy_error(phydev);
>>> }
>>>
>>>
>>> Of course, now I re-read your question, and I'm not sure I've
>>> interpreted it correctly. Are you saying your MAC has control of the
>>> PHY interrupt (ie - the interrupt sets a bit in some event register in
>>> your MAC, and you can MASK/ACK it from your driver), or that the PHY
>>> shares the same interrupt pin?
>>>
>>> If it's the second one, you don't need to do anything, but allow your
>>> MAC driver to register its interrupt as a shared interrupt, and allow
>>> the PHY to manage its own interrupts, as usual.
>>>
>>> Andy
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ