Re: [PATCH v3 5/5] mmc: add support for HS400 mode of eMMC5.0

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 3 April 2014 13:53, Seungwon Jeon <tgih.jun@xxxxxxxxxxx> wrote:
> On Wed, April 02, 2014, Ulf Hansson wrote:
>> On 2 April 2014 03:15, Seungwon Jeon <tgih.jun@xxxxxxxxxxx> wrote:
>> > On Fri, March 28, 2014, Ulf Hansson wrote:
>> >> On 28 March 2014 13:18, Seungwon Jeon <tgih.jun@xxxxxxxxxxx> wrote:
>> >> > On Fri, March 28, 2014, Ulf Hansson wrote:
>> >> >> On 25 March 2014 10:23, Seungwon Jeon <tgih.jun@xxxxxxxxxxx> wrote:
>> >> >> > Hi Ulf,
>> >> >> >
>> >> >> > On Tue, March 25, 2014, Ulf Hansson wrote:
>> >> >> >> On 14 March 2014 13:16, Seungwon Jeon <tgih.jun@xxxxxxxxxxx> wrote:
>> >> >> >> > This patch adds HS400 mode support for eMMC5.0 device.
>> >> >> >> > HS400 mode is high speed DDR interface timing from HS200.
>> >> >> >> > Clock frequency is up to 200MHz and only 8-bit bus width is
>> >> >> >> > supported. In addition, tuning process of HS200 is required
>> >> >> >> > to synchronize the command response on the CMD line because
>> >> >> >> > CMD input timing for HS400 mode is the same as HS200 mode.
>> >> >> >> >
>> >> >> >> > Signed-off-by: Seungwon Jeon <tgih.jun@xxxxxxxxxxx>
>> >> >> >> > Reviewed-by: Jackey Shen <jackey.shen@xxxxxxx>
>> >> >> >> > Tested-by: Jaehoon Chung <jh80.chung@xxxxxxxxxxx>
>> >> >> >> > Acked-by: Jaehoon Chung <jh80.chung@xxxxxxxxxxx>
>> >> >> >> > ---
>> >> >> >> >  drivers/mmc/core/bus.c     |    1 +
>> >> >> >> >  drivers/mmc/core/debugfs.c |    3 +
>> >> >> >> >  drivers/mmc/core/mmc.c     |  115 +++++++++++++++++++++++++++++++++++++++++--
>> >> >> >> >  include/linux/mmc/card.h   |    1 +
>> >> >> >> >  include/linux/mmc/host.h   |   15 +++++-
>> >> >> >> >  include/linux/mmc/mmc.h    |    7 ++-
>> >> >> >> >  6 files changed, 134 insertions(+), 8 deletions(-)
>> >> >> >> >
>> >> >> >> > diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
>> >> >> >> > index f37e9d6..d2dbf02 100644
>> >> >> >> > --- a/drivers/mmc/core/bus.c
>> >> >> >> > +++ b/drivers/mmc/core/bus.c
>> >> >> >> > @@ -349,6 +349,7 @@ int mmc_add_card(struct mmc_card *card)
>> >> >> >> >                         mmc_hostname(card->host),
>> >> >> >> >                         mmc_card_uhs(card) ? "ultra high speed " :
>> >> >> >> >                         (mmc_card_hs(card) ? "high speed " : ""),
>> >> >> >> > +                       mmc_card_hs400(card) ? "HS400 " :
>> >> >> >> >                         (mmc_card_hs200(card) ? "HS200 " : ""),
>> >> >> >> >                         mmc_card_ddr52(card) ? "DDR " : "",
>> >> >> >> >                         uhs_bus_speed_mode, type, card->rca);
>> >> >> >> > diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
>> >> >> >> > index 1f730db..91eb162 100644
>> >> >> >> > --- a/drivers/mmc/core/debugfs.c
>> >> >> >> > +++ b/drivers/mmc/core/debugfs.c
>> >> >> >> > @@ -141,6 +141,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
>> >> >> >> >         case MMC_TIMING_MMC_HS200:
>> >> >> >> >                 str = "mmc HS200";
>> >> >> >> >                 break;
>> >> >> >> > +       case MMC_TIMING_MMC_HS400:
>> >> >> >> > +               str = "mmc HS400";
>> >> >> >> > +               break;
>> >> >> >> >         default:
>> >> >> >> >                 str = "invalid";
>> >> >> >> >                 break;
>> >> >> >> > diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
>> >> >> >> > index 6dd68e6..969d595 100644
>> >> >> >> > --- a/drivers/mmc/core/mmc.c
>> >> >> >> > +++ b/drivers/mmc/core/mmc.c
>> >> >> >> > @@ -240,7 +240,7 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
>> >> >> >> >  static void mmc_select_card_type(struct mmc_card *card)
>> >> >> >> >  {
>> >> >> >> >         struct mmc_host *host = card->host;
>> >> >> >> > -       u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
>> >> >> >> > +       u8 card_type = card->ext_csd.raw_card_type;
>> >> >> >> >         u32 caps = host->caps, caps2 = host->caps2;
>> >> >> >> >         unsigned int hs_max_dtr = 0, hs200_max_dtr = 0;
>> >> >> >> >         unsigned int avail_type = 0;
>> >> >> >> > @@ -281,6 +281,18 @@ static void mmc_select_card_type(struct mmc_card *card)
>> >> >> >> >                 avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
>> >> >> >> >         }
>> >> >> >> >
>> >> >> >> > +       if (caps2 & MMC_CAP2_HS400_1_8V &&
>> >> >> >> > +           card_type & EXT_CSD_CARD_TYPE_HS400_1_8V) {
>> >> >> >> > +               hs200_max_dtr = MMC_HS200_MAX_DTR;
>> >> >> >> > +               avail_type |= EXT_CSD_CARD_TYPE_HS400_1_8V;
>> >> >> >> > +       }
>> >> >> >> > +
>> >> >> >> > +       if (caps2 & MMC_CAP2_HS400_1_2V &&
>> >> >> >> > +           card_type & EXT_CSD_CARD_TYPE_HS400_1_2V) {
>> >> >> >> > +               hs200_max_dtr = MMC_HS200_MAX_DTR;
>> >> >> >> > +               avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
>> >> >> >> > +       }
>> >> >> >> > +
>> >> >> >> >         card->ext_csd.hs_max_dtr = hs_max_dtr;
>> >> >> >> >         card->ext_csd.hs200_max_dtr = hs200_max_dtr;
>> >> >> >> >         card->mmc_avail_type = avail_type;
>> >> >> >> > @@ -499,6 +511,8 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
>> >> >> >> >                         ext_csd[EXT_CSD_PWR_CL_DDR_52_195];
>> >> >> >> >                 card->ext_csd.raw_pwr_cl_ddr_52_360 =
>> >> >> >> >                         ext_csd[EXT_CSD_PWR_CL_DDR_52_360];
>> >> >> >> > +               card->ext_csd.raw_pwr_cl_ddr_200_360 =
>> >> >> >> > +                       ext_csd[EXT_CSD_PWR_CL_DDR_200_360];
>> >> >> >> >         }
>> >> >> >> >
>> >> >> >> >         if (card->ext_csd.rev >= 5) {
>> >> >> >> > @@ -665,7 +679,10 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned
>> bus_width)
>> >> >> >> >                 (card->ext_csd.raw_pwr_cl_ddr_52_195 ==
>> >> >> >> >                         bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_195]) &&
>> >> >> >> >                 (card->ext_csd.raw_pwr_cl_ddr_52_360 ==
>> >> >> >> > -                       bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]));
>> >> >> >> > +                       bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]) &&
>> >> >> >> > +               (card->ext_csd.raw_pwr_cl_ddr_200_360 ==
>> >> >> >> > +                       bw_ext_csd[EXT_CSD_PWR_CL_DDR_200_360]));
>> >> >> >> > +
>> >> >> >> >         if (err)
>> >> >> >> >                 err = -EINVAL;
>> >> >> >> >
>> >> >> >> > @@ -776,7 +793,9 @@ static int __mmc_select_powerclass(struct mmc_card *card,
>> >> >> >> >                                 ext_csd->raw_pwr_cl_52_360 :
>> >> >> >> >                                 ext_csd->raw_pwr_cl_ddr_52_360;
>> >> >> >> >                 else if (host->ios.clock <= MMC_HS200_MAX_DTR)
>> >> >> >> > -                       pwrclass_val = ext_csd->raw_pwr_cl_200_360;
>> >> >> >> > +                       pwrclass_val = (bus_width == EXT_CSD_DDR_BUS_WIDTH_8) ?
>> >> >> >> > +                               ext_csd->raw_pwr_cl_ddr_200_360 :
>> >> >> >> > +                               ext_csd->raw_pwr_cl_200_360;
>> >> >> >> >                 break;
>> >> >> >> >         default:
>> >> >> >> >                 pr_warning("%s: Voltage range not supported "
>> >> >> >> > @@ -840,7 +859,8 @@ static void mmc_set_bus_speed(struct mmc_card *card)
>> >> >> >> >  {
>> >> >> >> >         unsigned int max_dtr = (unsigned int)-1;
>> >> >> >> >
>> >> >> >> > -       if (mmc_card_hs200(card) && max_dtr > card->ext_csd.hs200_max_dtr)
>> >> >> >> > +       if ((mmc_card_hs200(card) || mmc_card_hs400(card)) &&
>> >> >> >> > +            max_dtr > card->ext_csd.hs200_max_dtr)
>> >> >> >> >                 max_dtr = card->ext_csd.hs200_max_dtr;
>> >> >> >> >         else if (mmc_card_hs(card) && max_dtr > card->ext_csd.hs_max_dtr)
>> >> >> >> >                 max_dtr = card->ext_csd.hs_max_dtr;
>> >> >> >> > @@ -939,6 +959,28 @@ static int mmc_select_hs(struct mmc_card *card)
>> >> >> >> >  }
>> >> >> >> >
>> >> >> >> >  /*
>> >> >> >> > + * Revert to the high-speed mode from above speed
>> >> >> >> > + */
>> >> >> >> > +static int mmc_revert_to_hs(struct mmc_card *card)
>> >> >> >> > +{
>> >> >> >> > +       /*
>> >> >> >> > +        * CMD13, which is used to confirm the completion of timing
>> >> >> >> > +        * change, will be issued at higher speed timing condtion
>> >> >> >> > +        * rather than high-speed. If device has completed the change
>> >> >> >> > +        * to high-speed mode, it may not be proper timing to issue
>> >> >> >> > +        * command. Low speed supplies better timing margin than high
>> >> >> >> > +        * speed. Accordingly clock rate & timging should be chagned
>> >> >> >> > +        * ahead before actual switch.
>> >> >> >>
>> >> >> >> I have some problem to understand this comment. I guess you are trying
>> >> >> >> to provide the arguments to why it makes sense to perform the revert
>> >> >> >> to lower speed mode!?
>> >> >> >>
>> >> >> >> This makes me wonder if this is not part of the spec? Could you try to clarify?
>> >> >> > But specification says that "HS_TIMING must be set to "0x1" before setting BUS_WIDTH for dual
>> >> data
>> >> >> rate operation".
>> >> >> > I think this sequence is not graceful.
>> >> >> > I also commented why speed mode should be changed to high-speed mode from HS200 mode in the
>> >> >> function-called part.
>> >> >> > Because it is not possible to set 8-bit data bus for dual rate on HS200 mode, revert to high-
>> >> speed
>> >> >> from HS200 is needed.
>> >> >> > If the above-commented point makes it confused, it could be removed.
>> >> >> > Please let me know your opinion.
>> >> >> >
>> >> >> >>
>> >> >> >> > +        */
>> >> >> >> > +       mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
>> >> >> >> > +       mmc_set_bus_speed(card);
>> >> >> >> > +
>> >> >> >> > +       return mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> >> >> >> > +                         EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
>> >> >> >> > +                         card->ext_csd.generic_cmd6_time);
>> >> >> >> > +}
>> >> >> >> > +
>> >> >> >> > +/*
>> >> >> >> >   * Activate wide bus and DDR if supported.
>> >> >> >> >   */
>> >> >> >> >  static int mmc_select_hs_ddr(struct mmc_card *card)
>> >> >> >> > @@ -993,6 +1035,54 @@ static int mmc_select_hs_ddr(struct mmc_card *card)
>> >> >> >> >         return err;
>> >> >> >> >  }
>> >> >> >> >
>> >> >> >> > +static int mmc_select_hs400(struct mmc_card *card)
>> >> >> >> > +{
>> >> >> >> > +       struct mmc_host *host = card->host;
>> >> >> >> > +       int err = 0;
>> >> >> >> > +
>> >> >> >> > +       /*
>> >> >> >> > +        * The bus width is set to only 8 DDR in HS400 mode
>> >> >> >>
>> >> >> >> Please rephrase the comment to something like:
>> >> >> >> "HS400 mode requires 8-bit bus width."
>> >> >> > As it is, it was from spec's description.
>> >> >> > But I think yours would be more clearable.
>> >> >> >
>> >> >> >>
>> >> >> >> > +        */
>> >> >> >> > +       if (!(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400 &&
>> >> >> >> > +             host->ios.bus_width == MMC_BUS_WIDTH_8))
>> >> >> >> > +               return 0;
>> >> >> >> > +
>> >> >> >> > +       /*
>> >> >> >> > +        * Before setting BUS_WIDTH for dual data rate operation,
>> >> >> >> > +        * HS_TIMING must be set to High Speed(0x1)
>> >> >> >> > +        */
>> >> >> >>
>> >> >> >> Please rephrase comment:
>> >> >> >>
>> >> >> >> "Before switching to dual data rate operation for HS400, we need
>> >> >> >> revert from HS200 timing to regular HS timing."
>> >> >> > Ok.
>> >> >> >
>> >> >> >>
>> >> >> >> > +       err = mmc_revert_to_hs(card);
>> >> >> >>
>> >> >> >> I don't think we need a separate function to handle the revert.
>> >> >> >> Please, just add the code here instead. While you do that, I suppose
>> >> >> >> we should combine the comment in that function into one comment here.
>> >> >> > OK, I don't oppose that.
>> >> >> >
>> >> >> >>
>> >> >> >> > +       if (err) {
>> >> >> >> > +               pr_warn("%s: switch to high-speed from hs200 failed, err:%d\n",
>> >> >> >> > +                       mmc_hostname(host), err);
>> >> >> >> > +               return err;
>> >> >> >> > +       }
>> >> >> >> > +
>> >> >> >> > +       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> >> >> >> > +                        EXT_CSD_BUS_WIDTH,
>> >> >> >> > +                        EXT_CSD_DDR_BUS_WIDTH_8,
>> >> >> >> > +                        card->ext_csd.generic_cmd6_time);
>> >> >> >> > +       if (err) {
>> >> >> >> > +               pr_warn("%s: switch to bus width for hs400 failed, err:%d\n",
>> >> >> >> > +                       mmc_hostname(host), err);
>> >> >> >> > +               return err;
>> >> >> >> > +       }
>> >> >> >> > +
>> >> >> >> > +       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> >> >> >> > +                        EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400,
>> >> >> >> > +                        card->ext_csd.generic_cmd6_time);
>> >> >> >> > +       if (err) {
>> >> >> >> > +               pr_warn("%s: switch to hs400 failed, err:%d\n",
>> >> >> >> > +                        mmc_hostname(host), err);
>> >> >> >> > +               return err;
>> >> >> >> > +       }
>> >> >> >> > +
>> >> >> >> > +       mmc_set_timing(host, MMC_TIMING_MMC_HS400);
>> >> >> >> > +       mmc_set_bus_speed(card);
>> >> >> >> > +
>> >> >> >> > +       return 0;
>> >> >> >> > +}
>> >> >> >> > +
>> >> >> >> >  /*
>> >> >> >> >   * For device supporting HS200 mode, the following sequence
>> >> >> >> >   * should be done before executing the tuning process.
>> >> >> >> > @@ -1025,7 +1115,16 @@ static int mmc_select_hs200(struct mmc_card *card)
>> >> >> >> >                                    EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200,
>> >> >> >> >                                    card->ext_csd.generic_cmd6_time,
>> >> >> >> >                                    true, true, true);
>> >> >> >> > -               if (!err)
>> >> >> >> > +               if (err)
>> >> >> >> > +                       goto err;
>> >> >> >> > +
>> >> >> >> > +               if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400)
>> >> >> >> > +                       /*
>> >> >> >> > +                        * Timing should be adjusted to the HS400 target
>> >> >> >> > +                        * operation frequency for tuning process
>> >> >> >> > +                        */
>> >> >> >> > +                       mmc_set_timing(host, MMC_TIMING_MMC_HS400_TUNING);
>> >> >> >>
>> >> >> >> This seems strange. Do we really need a separate
>> >> >> >> MMC_TIMING_MMC_HS400_TUNING value?
>> >> >> > Spec. describes the HS400 selection sequence like below.
>> >> >> > <Quot>
>> >> >> > ...
>> >> >> > 6) Perform the Tuning Process at the HS400 target operating frequency
>> >> >> > (Note: tuning process in HS200 mode is required to synchronize the command response on the CMD
>> >> line
>> >> >> to CLK for HS400 operation).
>> >> >> > ...
>> >> >> > </Quot>
>> >> >> > That means target clock rate for tuning sequence can be different with HS200.
>> >> >> > Considering for that, it needs to distinguish.
>> >> >>
>> >> >> I understand the spec now, thanks.
>> >> >>
>> >> >> Still, I am not convinced we should handle this through the
>> >> >> MMC_TIMING* field. That will leave host drivers to do some magic clock
>> >> >> frequency calculation from their ->set_ios callbacks, just depending
>> >> >> on the MMC_TIMING_MMC_HS400_TUNING value.
>> >> >>
>> >> >> I am also a bit concerned how MMC_TIMING_MMC_HS400_TUNING, would work
>> >> >> if/when we implement periodic re-tuning - triggered from the mmc core
>> >> >> layer.
>> >> >>
>> >> >> What we really want to do, is to pretend we were to operate in
>> >> >> MMC_TIMING_MMC_HS400 and ask the host driver what the target frequency
>> >> >> would be in this case. Then set this frequency through
>> >> >> mmc_set_clock().
>> >> >>
>> >> >> Then how do we ask the host driver about this frequency? Let's add a
>> >> >> new host_ops callback. We want it to be generic, so provide the
>> >> >> MMC_TIMING bit as a parameter. Additionally we want it to be optional
>> >> >> to implement, thus for those host drivers that supports the same
>> >> >> target frequency for HS200 as for HS400, they don't need to implement
>> >> >> it.
>> >> >>
>> >> >> Would this be a way forward?
>> >> >
>> >> > Thanks for your opinion.
>> >> >
>> >> > IMO, in this case additional callback handling seems to cause the complication in host side.
>> >> > I think we don't need to ask host driver about target frequency for HS400 in order to set
>> specific
>> >> frequency through
>> >> > mmc_set_clock().
>> >> > Target frequency which core layer requires for HS400 will be 200MHz and it is also mentioned in
>> >> specification.
>> >> > Host driver including actual controller just will effort to make DDR rate with 200MHz.
>> >>
>> >> What the mmc_set_clock() request is not the same as what the frequency
>> >> actually will be set to. That depends on the host controller/driver.
>> >>
>> >> If for some reason the host controller/driver are not able to use the
>> >> same frequency for HS200 as for HS400, this should be possible to be
>> >> addressed in the way I suggested.
>> > I checked your sequence, but I'm not sure whether your suggestion is suitable for this.
>> > As we know, in case of DDR52 clock rate requested by mmc_set_clock() is not different from High
>> speed; Actually same 52Mhz is
>> > requested.
>> > It will be same in HS400 mode. Clock rate for mmc_set_clock() will be 200MHz in both HS200 and HS400.
>> > Instead, host driver may control specific register for DDR rate output.
>> > This is why core layer don't need call extra mmc_set_clock().
>> > That means it doesn't need to ask host driver about frequency with using additional callback.
>> > What core layer should do is to gives host driver timing information such as
>> MMC_TIMING_MMC_HS400_TUNING.
>> > Then, host can prepare specific timing setting for HS400 tuning.
>> > As you mentioned, it depends on the host controller/driver.
>>
>> The reason why I suggested to add a new host_ops callback and to use
>> the mmc_set_clock() method was to address what's mentioned in the
>> spec, which you pointed me to.
>>
>> So, now you are saying we don't need to consider this scenario,
>> because very likely we will be using the same frequency as for HS200.
> I didn't mean actual output clock frequency.
> Just mentioned required clock rate through mmc_set_clock() in core layer.
>
> I think clock generation depends on host controller.
> For higher speed, some programmable setting will be needed.
> Hopefully, you could find the following patch to check how HS400 is handled in host driver.
> Exynos host changes internal clock rate for HS400 mode.
> "[PATCH v2 5/7] mmc: dw_mmc: exynos: support eMMC's HS400 mode"
>
>>
>> Okay - let's leave this to be implemented if/when we see there is a need for it.
>>
>> >
>> >>
>> >> > MMC_TIMING_MMC_HS400_TUNING may be used as notification for host to prepare HS400 tuning sequence.
>> >>
>> >> So, are you saying that your controller are have different tuning
>> >> methods for HS200 vs HS400? That's a different requirement, which of
>> >> course we need to handle.
>> > NO, tuning method is equal. I meant that host's setting for IO timing would be different.
>>
>> I suppose this means the host don't need to bother about HS400 (at
>> all) during tuning sequence and thus we don't need the
>> MMC_TIMING_MMC_HS400_TUNING timing? Or am I missing your point?
> Please check the patch I mentioned above.

In the patch you refer to above, your ->set_ios callback takes
specific actions while "MMC_TIMING_MMC_HS400_TUNING".

Like this:
+       case MMC_TIMING_MMC_HS400_TUNING:
+               clksel = priv->hs400_timing;
+               wanted <<= 1;
+               break;

I don't think inventing MMC_TIMING_MMC_HS400_TUNING is the correct
approach to solve this. Instead, I believe we have these two options:

1. Let the host_ops->execute_tuning callback, notify the host about
HS400 tuning. Currently the "opcode" parameter is directly related to
the actual MMC command, but we could change that to have a different
meaning. Obviously you need to convert those host drivers implementing
the callback, but that should be quite simply I think.

2. Invent a new host_ops callback, like host_ops->execute_hs400_tuning.

>
>>
>> While we are discussion this, what about re-tuning? Is that also
>> supposed to be done in HS200 mode?
> I guess re-tuning is not related to this patch.
> OK, Can you say in more detail?
> I didn't get your meaning.

Currently sdhci performs re-tuning while a timer has elapsed, locally
implemented in the sdhci host.

Instead, I would like the re-tuning to be triggered from the mmc core
layer - thus all host drivers can benefit. Potentially the mmc core
would invoke the host_ops->execute_tuning callback to perform the
re-tuning. I just wanted you to keep this in mind, while implementing
1) or 2), sorry if it was too unclear.

Kind regards
Ulf Hansson

>
> Thanks,
> Seungwon Jeon
>
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux