[PATCH net-next v3 01/10] net: wwan: tmi: Add PCIe core

Yanchao Yang (杨彦超) Yanchao.Yang at mediatek.com
Thu Feb 16 04:50:44 PST 2023


Hi Jakub,

On Tue, 2023-02-14 at 20:22 -0800, Jakub Kicinski wrote:
> On Sat, 11 Feb 2023 16:37:23 +0800 Yanchao Yang wrote:
> > +ccflags-y += -I$(srctree)/$(src)/
> > +ccflags-y += -I$(srctree)/$(src)/pcie/
> 
> Do you really need these flags?
We will check and update if it's really redundant soon.
> 
> > +#ifndef _MTK_COMMON_H
> > +#define _MTK_COMMON_H
> > +
> > +#include <linux/device.h>
> > +
> > +#define MTK_UEVENT_INFO_LEN 128
> > +
> > +/* MTK uevent */
> > +enum mtk_uevent_id {
> > +	MTK_UEVENT_FSM = 1,
> > +	MTK_UEVENT_MAX
> > +};
> > +
> > +static inline void mtk_uevent_notify(struct device *dev, enum
> > mtk_uevent_id id, const char *info)
> > +{
> > +	char buf[MTK_UEVENT_INFO_LEN];
> > +	char *ext[2] = {NULL, NULL};
> > +
> > +	snprintf(buf, MTK_UEVENT_INFO_LEN, "%s:event_id=%d, info=%s",
> > +		 dev->kobj.name, id, info);
> > +	ext[0] = buf;
> > +	kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, ext);
> > +}
> 
> What is this for? It's not used in this patch.
Ok, remove it from patch1 and add it back to patch5.
> 
> > +static int mtk_mhccif_register_evt(struct mtk_md_dev *mdev, u32
> > chs,
> > +				   int (*evt_cb)(u32 status, void
> > *data), void *data)
> > +{
> > +	struct mtk_pci_priv *priv = mdev->hw_priv;
> > +	struct mtk_mhccif_cb *cb;
> > +	unsigned long flag;
> > +	int ret = 0;
> > +
> > +	if (!chs || !evt_cb)
> > +		return -EINVAL;
> 
> avoid defensive programming
Ok, remove it.
> 
> > +	spin_lock_irqsave(&priv->mhccif_lock, flag);
> > +	list_for_each_entry(cb, &priv->mhccif_cb_list, entry) {
> > +		if (cb->chs & chs) {
> > +			ret = -EFAULT;
> > +			dev_err(mdev->dev,
> > +				"Unable to register evt,
> > chs=0x%08X&0x%08X registered_cb=%ps\n",
> > +				chs, cb->chs, cb->evt_cb);
> > +			goto err;
> > +		}
> > +	}
> > +	cb = devm_kzalloc(mdev->dev, sizeof(*cb), GFP_ATOMIC);
> > +	if (!cb) {
> > +		ret = -ENOMEM;
> > +		goto err;
> > +	}
> > +	cb->evt_cb = evt_cb;
> > +	cb->data = data;
> > +	cb->chs = chs;
> > +	list_add_tail(&cb->entry, &priv->mhccif_cb_list);
> > +
> > +err:
> > +	spin_unlock_irqrestore(&priv->mhccif_lock, flag);
> > +
> > +	return ret;
> > +}
> > +
> > +static int mtk_mhccif_unregister_evt(struct mtk_md_dev *mdev, u32
> > chs)
> > +{
> > +	struct mtk_pci_priv *priv = mdev->hw_priv;
> > +	struct mtk_mhccif_cb *cb, *next;
> > +	unsigned long flag;
> > +	int ret = 0;
> > +
> > +	if (!chs)
> > +		return -EINVAL;
> 
> avoid defensive programming
Ok, remove it.
> 
> > +	spin_lock_irqsave(&priv->mhccif_lock, flag);
> > +	list_for_each_entry_safe(cb, next, &priv->mhccif_cb_list,
> > entry) {
> > +		if (cb->chs == chs) {
> > +			list_del(&cb->entry);
> > +			devm_kfree(mdev->dev, cb);
> > +			goto out;
> > +		}
> > +	}
> > +	ret = -EFAULT;
> > +	dev_warn(mdev->dev, "Unable to unregister evt, no chs=0x%08X
> > has been registered.\n", chs);
> > +out:
> > +	spin_unlock_irqrestore(&priv->mhccif_lock, flag);
> > +
> > +	return ret;
> > +}
> > +static void mtk_mhccif_clear_evt(struct mtk_md_dev *mdev, u32 chs)
> > +{
> > +	struct mtk_pci_priv *priv = mdev->hw_priv;
> > +
> > +	mtk_pci_write32(mdev, priv->cfg->mhccif_rc_base_addr
> > +		+ MHCCIF_EP2RC_SW_INT_ACK, chs);
> 
> + goes at the end of the previous line, and the continuation line
> should be aligned to (
> Please fix everywhere.
Ok, modify as shown below:
> +	mtk_pci_write32(mdev, priv->cfg-
>mhccif_rc_base_addr +
> +		               MHCCIF_EP2RC_SW_INT_ACK,
chs);
> 
> > +}
> > +
> > +static int mtk_mhccif_send_evt(struct mtk_md_dev *mdev, u32 ch)
> > +{
> > +	struct mtk_pci_priv *priv = mdev->hw_priv;
> > +	u32 rc_base;
> > +
> > +	rc_base = priv->cfg->mhccif_rc_base_addr;
> > +	/* Only allow one ch to be triggered at a time */
> > +	if ((ch & (ch - 1)) || !ch) {
> 
> is_power_of_2() ?
Ok, use kernel API instead
> +	/* Only allow one ch to be triggered at a
time */
> +	if (!is_power_of_2(ch)) {
> 
> > +		dev_err(mdev->dev, "Unsupported ext evt ch=0x%08X\n",
> > ch);
> > +		return -EINVAL;
> > +	}
> > +
> > +	mtk_pci_write32(mdev, rc_base + MHCCIF_RC2EP_SW_BSY, ch);
> > +	mtk_pci_write32(mdev, rc_base + MHCCIF_RC2EP_SW_TCHNUM, ffs(ch)
> > - 1);
> > +
> > +	return 0;
> > +}
> > +
> > +static u32 mtk_mhccif_get_evt_status(struct mtk_md_dev *mdev)
> > +{
> > +	struct mtk_pci_priv *priv = mdev->hw_priv;
> > +
> > +	return mtk_pci_read32(mdev, priv->cfg->mhccif_rc_base_addr +
> > MHCCIF_EP2RC_SW_INT_STS);
> > +}
> > +
> > +static int mtk_pci_acpi_reset(struct mtk_md_dev *mdev, char
> > *fn_name)
> > +{
> > +#ifdef CONFIG_ACPI
> > +	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
> > +	acpi_status acpi_ret;
> > +	acpi_handle handle;
> > +	int ret = 0;
> > +
> > +	handle = ACPI_HANDLE(mdev->dev);
> > +	if (!handle) {
> > +		dev_err(mdev->dev, "Unsupported, acpi handle isn't
> > found\n");
> > +		ret = -ENODEV;
> > +		goto err;
> > +	}
> > +	if (!acpi_has_method(handle, fn_name)) {
> > +		dev_err(mdev->dev, "Unsupported, _RST method isn't
> > found\n");
> > +		ret = -ENODEV;
> > +		goto err;
> > +	}
> > +	acpi_ret = acpi_evaluate_object(handle, fn_name, NULL,
> > &buffer);
> > +	if (ACPI_FAILURE(acpi_ret)) {
> > +		dev_err(mdev->dev, "Failed to execute %s method: %s\n",
> > +			fn_name,
> > +			acpi_format_exception(acpi_ret));
> > +		ret = -EFAULT;
> > +		goto err;
> > +	}
> > +	dev_info(mdev->dev, "FLDR execute successfully\n");
> > +	acpi_os_free(buffer.pointer);
> > +err:
> > +	return ret;
> > +#else
> > +	dev_err(mdev->dev, "Unsupported, CONFIG ACPI hasn't been set to
> > 'y'\n");
> > +	return -ENODEV;
> 
> If driver needs ACPI it should be a dependency in Kconfig.
Ok, add the dependency in Kconfig.
> 
> > +#endif
> > +}
> > +static irqreturn_t mtk_pci_irq_msix(int irq, void *data)
> > +{
> > +	struct mtk_pci_irq_desc *irq_desc = data;
> > +	struct mtk_md_dev *mdev = irq_desc->mdev;
> > +	struct mtk_pci_priv *priv;
> > +	u32 irq_state, irq_enable;
> > +
> > +	priv = mdev->hw_priv;
> > +	irq_state = mtk_pci_mac_read32(priv,
> > REG_MSIX_ISTATUS_HOST_GRP0_0);
> > +	irq_enable = mtk_pci_mac_read32(priv,
> > REG_IMASK_HOST_MSIX_GRP0_0);
> > +	dev_dbg(mdev->dev, "irq_state=0x%08X, irq_enable=0x%08X,
> > msix_bits=0x%08X\n",
> > +		irq_state, irq_enable, irq_desc->msix_bits);
> > +	irq_state &= irq_enable;
> > +
> > +	if (unlikely(!irq_state) ||
> > +	    unlikely(!((irq_state % GENMASK(priv->irq_cnt - 1, 0)) &
> > irq_desc->msix_bits)))
> 
> Are you sure the modulo is correct here?
Yes, sure. We have tested it and confirm related test cases pass.
> 
> > +		return IRQ_NONE;
> > +
> > +	/* Mask the bit and user needs to unmask by itself */
> > +	mtk_pci_mac_write32(priv, REG_IMASK_HOST_MSIX_CLR_GRP0_0,
> > irq_state & (~BIT(30)));
> mtk_cldma.c
> parenthesis unnecessary
Ok, modify as shown below:
> +	mtk_pci_mac_write32(priv,
REG_IMASK_HOST_MSIX_CLR_GRP0_0, irq_state & ~BIT(30));
> 
> > +
> > +	return mtk_pci_irq_handler(mdev, irq_state);
> > +}
> > +
> > +static int mtk_pci_request_irq_msix(struct mtk_md_dev *mdev, int
> > irq_cnt_allocated)
> > +{
> > +	struct mtk_pci_priv *priv = mdev->hw_priv;
> > +	struct mtk_pci_irq_desc *irq_desc;
> > +	struct pci_dev *pdev;
> > +	int irq_cnt;
> > +	int ret, i;
> > +
> > +	/* calculate the nearest 2's power number */
> > +	irq_cnt = BIT(fls(irq_cnt_allocated) - 1);
> > +	pdev = to_pci_dev(mdev->dev);
> > +	irq_desc = priv->irq_desc;
> > +	for (i = 0; i < irq_cnt; i++) {
> > +		irq_desc[i].mdev = mdev;
> > +		irq_desc[i].msix_bits = BIT(i);
> > +		snprintf(irq_desc[i].name, MTK_IRQ_NAME_LEN, "msix%d-
> > %s", i, mdev->dev_str);
> 
> please use pci_name() instead of your custom format stored in
> dev_str.
Ok, modify as shown below:
snprintf(irq_desc[i].name, MTK_IRQ_NAME_LEN,
"msix%d-%s", i, pci_name(to_pci_dev(mdev->dev));
> 
> > +		ret = pci_request_irq(pdev, i, mtk_pci_irq_msix, NULL,
> > +				      &irq_desc[i], irq_desc[i].name);
> > +		if (ret) {
> > +			dev_err(mdev->dev, "Failed to request %s:
> > ret=%d\n", irq_desc[i].name, ret);
> > +			for (i--; i >= 0; i--)mtk_cldma.c
> > +				pci_free_irq(pdev, i, &irq_desc[i]);
> > +			return ret;
> > +		}
> > +	}
> > +	priv->irq_cnt = irq_cnt;
> > +	priv->irq_type = PCI_IRQ_MSIX;
> > +
> > +	if (irq_cnt != MTK_IRQ_CNT_MAX)
> > +		mtk_pci_set_msix_merged(priv, irq_cnt);
> > +
> > +	return 0;
> > +}
> > +
> > +static int mtk_pci_request_irq(struct mtk_md_dev *mdev, int
> > max_irq_cnt, int irq_type)
> 
> irq_type is always PCI_IRQ_MSIX in this series
> and max_irq_cnt is MTK_IRQ_CNT_MAX. Use those directly.
Ok, will modify this part as shown below:
static int
mtk_pci_request_irq(struct mtk_md_dev *mdev)

in mtk_pci_probe()
ret =
mtk_pci_request_irq(mdev);
if (ret)
	goto err_request_irq;
> 
> > +{
> > +	struct pci_dev *pdev = to_pci_dev(mdev->dev);
> > +	int irq_cnt;
> > +
> > +	irq_cnt = pci_alloc_irq_vectors(pdev, MTK_IRQ_CNT_MIN,
> > max_irq_cnt, irq_type);
> > +	mdev->msi_nvecs = irq_cnt;
> > +
> > +	if (irq_cnt < MTK_IRQ_CNT_MIN) {
> > +		dev_err(mdev->dev,
> > +			"Unable to alloc pci irq vectors. ret=%d
> > maxirqcnt=%d irqtype=0x%x\n",
> > +			irq_cnt, max_irq_cnt, irq_type);
> > +		return -EFAULT;
> > +	}
> > +
> > +	return mtk_pci_request_irq_msix(mdev, irq_cnt);
> > +}
> > +
> > +static void mtk_pci_free_irq(struct mtk_md_dev *mdev)
> > +{
> > +	struct pci_dev *pdev = to_pci_dev(mdev->dev);
> > +	struct mtk_pci_priv *priv = mdev->hw_priv;
> > +	int i;
> > +
> > +	for (i = 0; i < priv->irq_cnt; i++)
> > +		pci_free_irq(pdev, i, &priv->irq_desc[i]);
> > +
> > +	pci_free_irq_vectors(pdev);
> > +}
> > +
> > +static void mtk_pci_save_state(struct mtk_md_dev *mdev)
> > +{
> > +	struct pci_dev *pdev = to_pci_dev(mdev->dev);
> > +	struct mtk_pci_priv *priv = mdev->hw_priv;
> > +	int ltr, l1ss;
> > +
> > +	pci_save_state(pdev);
> > +	/* save ltr */
> > +	ltr = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_LTR);
> > +	if (ltr) {
> > +		pci_read_config_word(pdev, ltr + PCI_LTR_MAX_SNOOP_LAT,
> > +				     &priv->ltr_max_snoop_lat);
> > +		pci_read_config_word(pdev, ltr +
> > PCI_LTR_MAX_NOSNOOP_LAT,
> > +				     &priv->ltr_max_nosnoop_lat);
> > +	}
> > +	/* save l1ss */
> > +	l1ss = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_L1SS);
> > +	if (l1ss) {
> > +		pci_read_config_dword(pdev, l1ss + PCI_L1SS_CTL1,
> > &priv->l1ss_ctl1);
> > +		pci_read_config_dword(pdev, l1ss + PCI_L1SS_CTL2,
> > &priv->l1ss_ctl2);
> > +	}
> > +}
> > +	dev_info(mdev->dev, "Probe done hw_ver=0x%x\n", mdev->hw_ver);
> > +	return 0;
> > +
> > +err_save_state:
> 
> Labels should be named after action they perform, not where they jump
> from. Please fix this everywhere.
We can found similar samples in kernel codes, naming the label per
where jump from…
ex. pci-sysfs.c
shall we apply this rule to our driver?
I
t's mandatory or nice to have.
> 
> > +	pci_disable_pcie_error_reporting(pdev);
> > +	pci_clear_master(pdev);mtk_cldma.c
> > +	mtk_pci_free_irq(mdev);
> > +err_request_irq:
> > +	mtk_mhccif_exit(mdev);
> > +err_mhccif_init:
> > +err_atr_init:
> > +	mtk_pci_bar_exit(mdev);
> > +err_bar_init:
> > +err_set_dma_mask:
> > +	pci_disable_device(pdev);
> > +err_enable_pdev:
> > +	devm_kfree(dev, priv);
> > +err_alloc_priv:
> > +	devm_kfree(dev, mdev);
> > +err_alloc_mdev:
> > +	dev_err(dev, "Failed to probe device, ret=%d\n", ret);
> 
> I believe core already prints this sort of a message. 
> Please double check.
Ok, remove the redundant warning trace.
> 
> > +	return ret;
> > +}
> > +
> > +static void mtk_pci_remove(struct pci_dev *pdev)
> > +{
> > +	struct mtk_md_dev *mdev = pci_get_drvdata(pdev);
> > +	struct mtk_pci_priv *priv = mdev->hw_priv;
> > +	struct device *dev = &pdev->dev;
> > +	int ret;
> > +
> > +	mtk_pci_mask_irq(mdev, priv->mhccif_irq_id);
> > +	pci_disable_pcie_error_reporting(pdev);
> 
> The explicit error reporting calls should be removed, please 
> see f26e58bf6f54
Ok, remove it ”pci_disable_pcie_error_reporting(pdev);“.
> 
> > +	ret = mtk_pci_fldr(mdev);
> > +	if (ret)
> > +		mtk_mhccif_send_evt(mdev, EXT_EVT_H2D_DEVICE_RESET);
> > +
> > +	pci_clear_master(pdev);
> > +	mtk_mhccif_exit(mdev);
> > +	mtk_pci_free_irq(mdev);
> > +	mtk_pci_bar_exit(mdev);
> > +	pci_disable_device(pdev);
> > +	pci_load_and_free_saved_state(pdev, &priv->saved_state);
> > +	devm_kfree(dev, priv);
> > +	devm_kfree(dev, mdev);
> 
> Why are you using devm_ if you call kfree explicitly anyway?
> You can save some memory by using kfree() directly.
devm_kzalloc(), devm_ioremap_resource(), devm_request_irq(),
devm_gpio_request(), devm_clk_get()…..
They will be freed automatically
when corresponding device is freed, so you don’t have to free them
explicitly. This also make probe error easier to handle. Is it ok?
> 
> > +	u16 ltr_max_snoop_lat;
> > +	u16 ltr_max_nosnoop_lat;
> > +	u32 l1ss_ctl1;
> > +	u32 l1ss_ctl2;
> 
> These 4 registers seem to be saved but never used.
Ok, remove it from patch1.

Many thanks.
yanchao.yang


More information about the Linux-mediatek mailing list