Bjorn, Do you have anything to say based on the notes below? -Sergey On Wed, Jun 22, 2022 at 08:04:37PM +0300, Serge Semin wrote: > On Tue, Jun 21, 2022 at 01:29:41PM -0500, Bjorn Helgaas wrote: > > On Mon, Jun 20, 2022 at 08:13:47PM +0300, Serge Semin wrote: > > > On Wed, Jun 15, 2022 at 11:48:48AM -0500, Bjorn Helgaas wrote: > > > > On Fri, Jun 10, 2022 at 11:57:05AM +0300, Serge Semin wrote: > > > > > Baikal-T1 SoC is equipped with DWC PCIe v4.60a host controller. It can be > > > > > trained to work up to Gen.3 speed over up to x4 lanes. The host controller > > > > > is attached to the DW PCIe 3.0 PCS via the PIPE-4 interface, which in its > > > > > turn is connected to the DWC 10G PHY. The whole system is supposed to be > > > > > fed up with four clock sources: DBI peripheral clock, AXI application > > > > > clocks and external PHY/core reference clock generating the 100MHz signal. > > > > > In addition to that the platform provide a way to reset each part of the > > > > > controller: sticky/non-sticky bits, host controller core, PIPE interface, > > > > > PCS/PHY and Hot/Power reset signal. The driver also provides a way to > > > > > handle the GPIO-based PERST# signal. > > > > > > > > > > Note due to the Baikal-T1 MMIO peculiarity we have to implement the DBI > > > > > interface accessors which make sure the IO operations are dword-aligned. > > > > > > > +struct dw_pcie_ops bt1_pcie_dw_ops = { > > > > > + .read_dbi = bt1_pcie_read_dbi, > > > > > + .write_dbi = bt1_pcie_write_dbi, > > > > > + .write_dbi2 = bt1_pcie_write_dbi2, > > > > > + .start_link = bt1_pcie_start_ltssm, > > > > > + .stop_link = bt1_pcie_stop_ltssm, > > > > > +}; > > > > > > Please rename to "dw_pcie_ops" as most > > > > drivers use. > > > > > > IMO matching the structure and its instance names is not a good idea. > > > Other than confusing objects nature, at the very least it forces you to > > > violate the local namespace convention. Thus in the line of the > > > dw_pcie->ops initialization it looks like you use some generic > > > operations while in fact you just refer to the locally defined > > > DW PCIe ops instance with the generic variable name. Moreover AFAICS > > > the latest platform drivers mainly use the vendor-specific prefix in > > > the dw_pcie_ops structure instance including the ones acked by you, > > > Lorenzo and Gustavo. What makes my code any different from them? > > > > > That's fair. I suggest "bt1_pcie_ops" or "bt1_dw_pcie_ops" to match > > the other drivers that include the driver name: > > > > intel_pcie_ops > > keembay_pcie_ops > > kirin_dw_pcie_ops > > tegra_dw_pcie_ops > > + ks_pcie_dw_pcie_ops > > which is even further from the suggested names.) > > > > > They're not 100% consistent, but hopefully we can at least not make > > things *less* consistent. > > I don't think we can make something less consistent if there is no real > consistency.) There are at most five ops descriptors can be defined in > the DW PCIe platform drivers: > > 1. struct dw_pcie_ops - DW PCIe DBI interface accessors, > +-> dw_pcie_ops > +-> <vendor>_pcie_ops > +-> <vendor>_dw_pcie_ops > > 2. struct pci_ops - own or child PCIe config space accessors, > +-> dw_pcie_ops !!! in the driver core. > +-> <vendor>_pci_ops > +-> <vendor>_pcie_ops > +-> dw_child_pcie_ops > +-> <vendor>_child_pcie_ops > +-> <vendor>_child_pci_ops > > 3. struct dw_pcie_host_ops - DW PCIe Root Port init/de-init operations > +-> <vendor>_pcie_host_ops > +-> <vendor>_pcie_dw_host_ops > > 4. struct dw_pcie_ep_ops - DW PCIe Endpoint init/de-init operations > +-> pcie_ep_ops > +-> pci_ep_ops > +-> <vendor>_pcie_ep_ops > > As you can see each can have different naming approaches used in the > DW PCIe platform drivers here and there. Some of them have been utilized > more frequently, some of them - less. As for me what is really consistent > across all the DW PCIe platform drivers is the local namespace prefix > of the form "<vendor>_pcie". It is used in all the locally defined > functions names and more-or-less mainly in the local instances of the > operation descriptors. So if you want we can pick some approach and > make sure it is used in all the driver from now on. For instance, > > struct dw_pcie_ops <vendor>_pcie_ops > struct dw_pcie_host_ops <vendor>_pcie_host_ops > struct dw_pcie_ep_ops <vendor>_pcie_ep_ops > struct pci_ops <vendor>_pci_ops // Can be confused with the struct > // dw_pcie_ops instance, but this what > // is mainly used in the available drivers. > struct pci_ops <vendor>_child_pci_ops // less frequent naming > // approach, but it looks more > // like the own CFG-space IOs. > > Note the later two cases will violate the local namespace naming > convention of having "<vendor>_pcie" prefix. > > In my case the names would look like: > struct dw_pcie_ops bt1_pcie_ops // What you suggest in the comment above > struct dw_pcie_host_ops bt1_pcie_host_ops > struct pci_ops bt1_pci_ops // It may look ambiguous with bt1_pcie_ops. > > What do you think? > > > > > > > > +static int bt1_pcie_get_res(struct bt1_pcie *btpci) > > > > > > > Can you name this something similar to what other drivers use? There > > > > are a couple *_pcie_get_resources() functions (normally called from > > > > *_pcie_probe()), but no *_get_res() yet. > > > > > > Earlier in this patchset I've introduced a new method to get > > > the CSRs ranges, PCIe speed, NoF lanes, etc resources. See the patch: > > > [PATCH v3 14/17] PCI: dwc: Introduce generic resources getter > > > The method has been named as "dw_pcie_get_res()". So the locally > > > defined function has been named to refer to that method. If you think > > > that using the "_resources" suffix is better (IMO there is no > > > significant difference) then we'll need to change the name there too. > > > Do you? > > > > > Yes. I don't think there's value in names being gratuitously > > different. > > Ok. > > > > > > > > + /* AXI-interface is configured with 64-bit address bus width */ > > > > > + ret = dma_coerce_mask_and_coherent(&btpci->dw.pp.bridge->dev, > > > > > + DMA_BIT_MASK(64)); > > > > > > > Just to double-check since this is the first instance of > > > > dma_coerce_mask_and_coherent() in drivers/pci -- I guess Baikal-T1 is > > > > unique in needing this? > > > > > > To be honest I've set it here just in case, seeing the dma_mask and > > > coherent_dma_mask are left uninitialized in the Host bridge device > > > instance, while it's still participate in the PCI devices hierarchy: > > > > > > 1. platform_device.dev; > > > | (<= devm_pci_alloc_host_bridge(dev)) > > > +---+ > > > &v > > > 2. pci_host_bridge.dev.parent > > > | (<= pci_register_host_bridge(bridge) or) > > > | (<= pci_alloc_child_bus() ) > > > &v > > > pci_bus.bridge > > > +-------------------+ > > > | | (<= pci_setup_device()) > > > v v > > > 3. pci_bus.dev.parent pci_dev.dev.parent > > > pci_dev.dma_mask = 0xffffffff; > > > | (<= pci_device_add()) > > > +----+ > > > &v > > > pci_dev->dev.dma_mask > > > pci_dev->dev.coherent_dma_mask = 0xffffffffull; > > > > > > So each device detected on the very first PCIe bus gets to have the > > > PCI host bridge device as a parent. But AFAICS the PCI subsystem core > > > code doesn't use the PCI host bridge DMA-mask and by default the > > > dma_mask/coherent_dma_mask fields of each PCIe peripheral device are > > > unconditionally initialized with DMA_BIT_MASK(32) (they are supposed > > > to be overridden by the device-driver anyway). So to speak we can > > > freely drop the dma_coerce_mask_and_coherent() method invocation from > > > my driver if you say it is required and the PCI host bridge DMA parameter > > > will never be used. What do you think? > > > > > I'd like the usage across drivers to be consistent unless there's a > > hardware difference that requires something different. So if you can > > point to something different in bt1, great. If not, do it the same as > > the other drivers. > > Ok. I'll drop it from the driver then. > > > > > > > > +static void bt1_pcie_full_stop_bus(struct bt1_pcie *btpci, bool init) > > > > > > > > Can you name this something similar to what other drivers use? > > > > > > For instance? (Please note, the link_stop/link_start callbacks are > > > defined as separate methods above.) The current names correctly describe > > > the methods logic. So I wouldn't want to fully change their names. > > > > > Do any other drivers contain similar logic? If so, please use a > > similar name. > > host_init content is very platform-specific. So each driver has its own > callback implementation and logical sub-methods split up. My case > isn't an exception. > > > > > > > > + * Application reset controls are trigger-based so de-assert the core > > > > > + * resets only. > > > > > + */ > > > > > + ret = reset_control_bulk_assert(DW_PCIE_NUM_CORE_RSTS, pci->core_rsts); > > > > > BTW, the comment says "de-assert" but the code looks like "assert". > > Right. It is supposed to be "assert" in accordance with what is > actually done. > > > > > > > > + /* Make sure the reset is settled */ > > > > > + usleep_range(1, 10); > > > > > > > Is this duration related to something in the PCIe spec? Or the DWC > > > > spec? > > > > > > No. These durations are the chip-specific. Partly due to them being > > > specific for each SoC we can't implement a generic bus reset > > > procedure. > > > > > > > I'd really like to use named constants when possible, although > > > > we have a ton of bare magic numbers currently. > > > > > > > > Similar for the poll timeouts and the "state settled" sleep below. > > > > > > I don't really see much need in this parametrization since these > > > numbers are used only once in the platform driver and their > > > application is easily inferable from the code context. > > > > > Even if they are used only once, it's helpful when constants like this > > can be connected to the spec or other justification for the specific > > values. > > Ok. I'll replace the literals with the macros. > > > > > > > > +static struct bt1_pcie *bt1_pcie_create_data(struct platform_device *pdev) > > > > > +{ > > > > > + struct bt1_pcie *btpci; > > > > > + > > > > > + btpci = devm_kzalloc(&pdev->dev, sizeof(*btpci), GFP_KERNEL); > > > > > + if (!btpci) > > > > > + return ERR_PTR(-ENOMEM); > > > > > + > > > > > + btpci->pdev = pdev; > > > > > + > > > > > + platform_set_drvdata(pdev, btpci); > > > > > + > > > > > + return btpci; > > > > > > > I don't think it's worth splitting this into a separate function. I > > > > think it would be better to use the same structure as other dwc-based > > > > drivers and keep this in bt1_pcie_probe(). > > > > > > Sorry, I disagree in this matter. Generally I don't like the most of > > > the probe methods designed in the kernel well because after evolving > > > in time they get to be a mess if incoherent initializations, > > > allocations, requests, etc. Splitting it up into a set of smaller > > > coherent methods makes the code much clearer. > > > > > There's definitely some tension between making one driver better and > > making it different from all the others. I'm all in favor of making > > all the drivers better and more consistent. I'm less in favor of > > one-off improvements because consistency is extremely important for > > maintenance. > > Well, if there were a consistency in the probe method design it would > have been another story, but in case of the DW PCIe there is none. > Some DW PCIe platform drivers perform all the probe actions right in > the probe method forming a long list of the weakly coherent things, > some of them have a few sub-functions called but still look the same, > some of them are mainly split up in the sub-methods, but still perform > some initialization right in the probe method. So in general there is > no unification and well defined convention in that regard. > > My approach on the contrary makes the probe method code well unified. > Should any new additional step is required, the new method can be > added together with the cleanup antagonist. Similarly the > sub-methods update patches is easier to review than reading the > all-in-one probe code update. Moreover such design approach I've > been using in all the drivers submitted by me to the kernel and no > questions have been raised so far. Finally the driver is supposed to > be maintained by its author at the very least. So I definitely won't > have any problem with it especially after using the same design > pattern in all my drivers. > > > > > > > > +static int bt1_pcie_add_dw_port(struct bt1_pcie *btpci) > > > > > > > All other dwc-based drivers call dw_pcie_host_init() from either > > > > *_pcie_probe() or *_add_pcie_port(). Please use a similar convention. > > > > > > Not entirely. Tegra is an exception. So as before I don't think there > > > is a real convention. Most likely it's a result of a lucky coincident. > > > Moreover I don't really like such naming. Something like > > > VENDOR_pcie_add_root_port() would be much better. > > > > > I stand corrected. Of the 21 dw_pcie_host_init() calls, 13 are from > > *_pcie_probe(), 7 are from *_add_pcie_port(), and tegra is from > > tegra_pcie_init_controller(). I think the *_add_pcie_port() structure > > is better because it makes room to support multiple root ports. > > See the last comment. It concerns the same methods, but you suggest to > use the names "*_add_port()" there. > > > > > > > > + ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); > > > > > > > > Why do you need this when no other dwc-based drivers do? Is Baikal-T1 > > > > different in this respect? > > > > > > It's because eDMA engine embedded into the DW PCIe root port. > > > > > Let's add a comment about the fact that this is needed because of the > > eDMA engine. > > Ok. > > > > > > > > +static void bt1_pcie_del_dw_port(struct bt1_pcie *btpci) > > > > > > > Can you call dw_pcie_host_deinit() from the same place as other > > > > drivers? > > > > > > > > $ git grep -p dw_pcie_host_deinit drivers/pci/controller/dwc > > > > > > Sorry I'd rather leave it as is. There are only four drivers using > > > it and one of them don't follow what seems like a convention. I'd > > > rather have my driver code coherent: > > > bt1_pcie_add_pcie_port() is used to add the DW PCIe Root Port. > > > and > > > bt1_pcie_del_pcie_port() is used to remove the DW PCIe Root Port > > > > I agree with your rationale. Intel and kirin do: > > > > *_pcie_probe > > dw_pcie_host_init > > > > *_pcie_remove > > dw_pcie_host_deinit > > > > and tegra is similar but from tegra_pcie_init_controller() and > > tegra_pcie_deinit_controller(). Exynos is the odd one out and calls > > dw_pcie_host_init() from exynos_add_pcie_port() but > > dw_pcie_host_deinit() from exynos_pcie_remove(). > > > > Your model is better since it removes the "single root port" > > assumption. I would like the "bt1_pcie_add_port()" and > > "bt1_pcie_del_port()" (or "bt1_pcie_remove_port()", which would be > > slightly more parallel with "add") names to align with other drivers. > > Ok. I'll use bt1_pcie_add_port() and bt1_pcie_del_port() names then. > * Note the DW PCIe platform drivers mainly use the _pcie_port() suffix > * in the add-method. > > -Sergey > > > > > Bjorn