Commit 6e0cca6b authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge branch 'net-stmmac-mdio-cleanups'



Russell King says:

====================
net: stmmac: mdio cleanups

Clean up the stmmac MDIO code:
- provide an address register formatter to avoid repeated code
- provide a common function to wait for the busy bit to clear
- pre-compute the CR field (mdio clock divider)
- move address formatter into read/write functions
- combine the read/write functions into a common accessor function
- move runtime PM handling into common accessor function
- rename register constants to better reflect manufacturer names
- move stmmac_clk_csr_set() into stmmac_mdio
- make stmmac_clk_csr_set() return the CR field value and remove
  priv->clk_csr
- clean up if() range tests in stmmac_clk_csr_set()
- use STMMAC_CSR_xxx definitions in initialisers

For Qualcomm QCS9100 Ride R3 board with the AQR115C PHY:

Tested-by: default avatarMohd Ayaan Anwar <quic_mohdayaa@quicinc.com>
====================

Link: https://patch.msgid.link/aLmBwsMdW__XBv7g@shell.armlinux.org.uk


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 144d0b1c fc8f62c8
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -563,7 +563,8 @@ static int intel_mac_finish(struct net_device *ndev,

static void common_default_data(struct plat_stmmacenet_data *plat)
{
	plat->clk_csr = 2;	/* clk_csr_i = 20-35MHz & MDC = clk_csr_i/16 */
	/* clk_csr_i = 20-35MHz & MDC = clk_csr_i/16 */
	plat->clk_csr = STMMAC_CSR_20_35M;
	plat->has_gmac = 1;
	plat->force_sf_dma_mode = 1;

@@ -610,7 +611,7 @@ static int intel_mgbe_common_data(struct pci_dev *pdev,

	plat->pdev = pdev;
	plat->phy_addr = -1;
	plat->clk_csr = 5;
	plat->clk_csr = STMMAC_CSR_250_300M;
	plat->has_gmac = 0;
	plat->has_gmac4 = 1;
	plat->force_sf_dma_mode = 0;
+2 −1
Original line number Diff line number Diff line
@@ -90,7 +90,8 @@ static void loongson_default_data(struct pci_dev *pdev,
	/* Get bus_id, this can be overwritten later */
	plat->bus_id = pci_dev_id(pdev);

	plat->clk_csr = 2;	/* clk_csr_i = 20-35MHz & MDC = clk_csr_i/16 */
	/* clk_csr_i = 20-35MHz & MDC = clk_csr_i/16 */
	plat->clk_csr = STMMAC_CSR_20_35M;
	plat->has_gmac = 1;
	plat->force_sf_dma_mode = 1;

+1 −1
Original line number Diff line number Diff line
@@ -289,7 +289,7 @@ struct stmmac_priv {
	u32 msg_enable;
	int wolopts;
	int wol_irq;
	int clk_csr;
	u32 gmii_address_bus_config;
	struct timer_list eee_ctrl_timer;
	int lpi_irq;
	u32 tx_lpi_timer;
+0 −82
Original line number Diff line number Diff line
@@ -314,77 +314,6 @@ static void stmmac_global_err(struct stmmac_priv *priv)
	stmmac_service_event_schedule(priv);
}

/**
 * stmmac_clk_csr_set - dynamically set the MDC clock
 * @priv: driver private structure
 * Description: this is to dynamically set the MDC clock according to the csr
 * clock input.
 * Note:
 *	If a specific clk_csr value is passed from the platform
 *	this means that the CSR Clock Range selection cannot be
 *	changed at run-time and it is fixed (as reported in the driver
 *	documentation). Viceversa the driver will try to set the MDC
 *	clock dynamically according to the actual clock input.
 */
static void stmmac_clk_csr_set(struct stmmac_priv *priv)
{
	unsigned long clk_rate;

	clk_rate = clk_get_rate(priv->plat->stmmac_clk);

	/* Platform provided default clk_csr would be assumed valid
	 * for all other cases except for the below mentioned ones.
	 * For values higher than the IEEE 802.3 specified frequency
	 * we can not estimate the proper divider as it is not known
	 * the frequency of clk_csr_i. So we do not change the default
	 * divider.
	 */
	if (!(priv->clk_csr & MAC_CSR_H_FRQ_MASK)) {
		if (clk_rate < CSR_F_35M)
			priv->clk_csr = STMMAC_CSR_20_35M;
		else if ((clk_rate >= CSR_F_35M) && (clk_rate < CSR_F_60M))
			priv->clk_csr = STMMAC_CSR_35_60M;
		else if ((clk_rate >= CSR_F_60M) && (clk_rate < CSR_F_100M))
			priv->clk_csr = STMMAC_CSR_60_100M;
		else if ((clk_rate >= CSR_F_100M) && (clk_rate < CSR_F_150M))
			priv->clk_csr = STMMAC_CSR_100_150M;
		else if ((clk_rate >= CSR_F_150M) && (clk_rate < CSR_F_250M))
			priv->clk_csr = STMMAC_CSR_150_250M;
		else if ((clk_rate >= CSR_F_250M) && (clk_rate <= CSR_F_300M))
			priv->clk_csr = STMMAC_CSR_250_300M;
		else if ((clk_rate >= CSR_F_300M) && (clk_rate < CSR_F_500M))
			priv->clk_csr = STMMAC_CSR_300_500M;
		else if ((clk_rate >= CSR_F_500M) && (clk_rate < CSR_F_800M))
			priv->clk_csr = STMMAC_CSR_500_800M;
	}

	if (priv->plat->flags & STMMAC_FLAG_HAS_SUN8I) {
		if (clk_rate > 160000000)
			priv->clk_csr = 0x03;
		else if (clk_rate > 80000000)
			priv->clk_csr = 0x02;
		else if (clk_rate > 40000000)
			priv->clk_csr = 0x01;
		else
			priv->clk_csr = 0;
	}

	if (priv->plat->has_xgmac) {
		if (clk_rate > 400000000)
			priv->clk_csr = 0x5;
		else if (clk_rate > 350000000)
			priv->clk_csr = 0x4;
		else if (clk_rate > 300000000)
			priv->clk_csr = 0x3;
		else if (clk_rate > 250000000)
			priv->clk_csr = 0x2;
		else if (clk_rate > 150000000)
			priv->clk_csr = 0x1;
		else
			priv->clk_csr = 0x0;
	}
}

static void print_pkt(unsigned char *buf, int len)
{
	pr_debug("len = %d byte, buf addr: 0x%p\n", len, buf);
@@ -7718,17 +7647,6 @@ int stmmac_dvr_probe(struct device *device,

	stmmac_fpe_init(priv);

	/* If a specific clk_csr value is passed from the platform
	 * this means that the CSR Clock Range selection cannot be
	 * changed at run-time and it is fixed. Viceversa the driver'll try to
	 * set the MDC clock dynamically according to the csr actual
	 * clock input.
	 */
	if (priv->plat->clk_csr >= 0)
		priv->clk_csr = priv->plat->clk_csr;
	else
		stmmac_clk_csr_set(priv);

	stmmac_check_pcs_mode(priv);

	pm_runtime_get_noresume(device);
+198 −147
Original line number Diff line number Diff line
@@ -23,9 +23,9 @@
#include "dwxgmac2.h"
#include "stmmac.h"

#define MII_BUSY 0x00000001
#define MII_WRITE 0x00000002
#define MII_DATA_MASK GENMASK(15, 0)
#define MII_ADDR_GBUSY			BIT(0)
#define MII_ADDR_GWRITE			BIT(1)
#define MII_DATA_GD_MASK		GENMASK(15, 0)

/* GMAC4 defines */
#define MII_GMAC4_GOC_SHIFT		2
@@ -45,6 +45,16 @@
#define MII_XGMAC_PA_SHIFT		16
#define MII_XGMAC_DA_SHIFT		21

static int stmmac_mdio_wait(void __iomem *reg, u32 mask)
{
	u32 v;

	if (readl_poll_timeout(reg, v, !(v & mask), 100, 10000))
		return -EBUSY;

	return 0;
}

static void stmmac_xgmac2_c45_format(struct stmmac_priv *priv, int phyaddr,
				     int devad, int phyreg, u32 *hw_addr)
{
@@ -83,7 +93,6 @@ static int stmmac_xgmac2_mdio_read(struct stmmac_priv *priv, u32 addr,
{
	unsigned int mii_address = priv->hw->mii.addr;
	unsigned int mii_data = priv->hw->mii.data;
	u32 tmp;
	int ret;

	ret = pm_runtime_resume_and_get(priv->device);
@@ -91,33 +100,25 @@ static int stmmac_xgmac2_mdio_read(struct stmmac_priv *priv, u32 addr,
		return ret;

	/* Wait until any existing MII operation is complete */
	if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
			       !(tmp & MII_XGMAC_BUSY), 100, 10000)) {
		ret = -EBUSY;
	ret = stmmac_mdio_wait(priv->ioaddr + mii_data, MII_XGMAC_BUSY);
	if (ret)
		goto err_disable_clks;
	}

	value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
		& priv->hw->mii.clk_csr_mask;
	value |= MII_XGMAC_READ;
	value |= priv->gmii_address_bus_config | MII_XGMAC_READ;

	/* Wait until any existing MII operation is complete */
	if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
			       !(tmp & MII_XGMAC_BUSY), 100, 10000)) {
		ret = -EBUSY;
	ret = stmmac_mdio_wait(priv->ioaddr + mii_data, MII_XGMAC_BUSY);
	if (ret)
		goto err_disable_clks;
	}

	/* Set the MII address register to read */
	writel(addr, priv->ioaddr + mii_address);
	writel(value, priv->ioaddr + mii_data);

	/* Wait until any existing MII operation is complete */
	if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
			       !(tmp & MII_XGMAC_BUSY), 100, 10000)) {
		ret = -EBUSY;
	ret = stmmac_mdio_wait(priv->ioaddr + mii_data, MII_XGMAC_BUSY);
	if (ret)
		goto err_disable_clks;
	}

	/* Read the data from the MII data register */
	ret = (int)readl(priv->ioaddr + mii_data) & GENMASK(15, 0);
@@ -160,7 +161,6 @@ static int stmmac_xgmac2_mdio_write(struct stmmac_priv *priv, u32 addr,
{
	unsigned int mii_address = priv->hw->mii.addr;
	unsigned int mii_data = priv->hw->mii.data;
	u32 tmp;
	int ret;

	ret = pm_runtime_resume_and_get(priv->device);
@@ -168,31 +168,23 @@ static int stmmac_xgmac2_mdio_write(struct stmmac_priv *priv, u32 addr,
		return ret;

	/* Wait until any existing MII operation is complete */
	if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
			       !(tmp & MII_XGMAC_BUSY), 100, 10000)) {
		ret = -EBUSY;
	ret = stmmac_mdio_wait(priv->ioaddr + mii_data, MII_XGMAC_BUSY);
	if (ret)
		goto err_disable_clks;
	}

	value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
		& priv->hw->mii.clk_csr_mask;
	value |= phydata;
	value |= MII_XGMAC_WRITE;
	value |= priv->gmii_address_bus_config | phydata | MII_XGMAC_WRITE;

	/* Wait until any existing MII operation is complete */
	if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
			       !(tmp & MII_XGMAC_BUSY), 100, 10000)) {
		ret = -EBUSY;
	ret = stmmac_mdio_wait(priv->ioaddr + mii_data, MII_XGMAC_BUSY);
	if (ret)
		goto err_disable_clks;
	}

	/* Set the MII address register to write */
	writel(addr, priv->ioaddr + mii_address);
	writel(value, priv->ioaddr + mii_data);

	/* Wait until any existing MII operation is complete */
	ret = readl_poll_timeout(priv->ioaddr + mii_data, tmp,
				 !(tmp & MII_XGMAC_BUSY), 100, 10000);
	ret = stmmac_mdio_wait(priv->ioaddr + mii_data, MII_XGMAC_BUSY);

err_disable_clks:
	pm_runtime_put(priv->device);
@@ -229,25 +221,69 @@ static int stmmac_xgmac2_mdio_write_c45(struct mii_bus *bus, int phyaddr,
					phydata);
}

static int stmmac_mdio_read(struct stmmac_priv *priv, int data, u32 value)
/**
 * stmmac_mdio_format_addr() - format the address register
 * @priv: struct stmmac_priv pointer
 * @pa: 5-bit MDIO package address
 * @gr: 5-bit MDIO register address (C22) or MDIO device address (C45)
 *
 * Return: formatted address register
 */
static u32 stmmac_mdio_format_addr(struct stmmac_priv *priv,
				   unsigned int pa, unsigned int gr)
{
	unsigned int mii_address = priv->hw->mii.addr;
	unsigned int mii_data = priv->hw->mii.data;
	u32 v;
	const struct mii_regs *mii_regs = &priv->hw->mii;

	if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
			       100, 10000))
		return -EBUSY;
	return ((pa << mii_regs->addr_shift) & mii_regs->addr_mask) |
	       ((gr << mii_regs->reg_shift) & mii_regs->reg_mask) |
	       priv->gmii_address_bus_config |
	       MII_ADDR_GBUSY;
}

	writel(data, priv->ioaddr + mii_data);
	writel(value, priv->ioaddr + mii_address);
static int stmmac_mdio_access(struct stmmac_priv *priv, unsigned int pa,
			      unsigned int gr, u32 cmd, u32 data, bool read)
{
	void __iomem *mii_address = priv->ioaddr + priv->hw->mii.addr;
	void __iomem *mii_data = priv->ioaddr + priv->hw->mii.data;
	u32 addr;
	int ret;

	if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
			       100, 10000))
		return -EBUSY;
	ret = pm_runtime_resume_and_get(priv->device);
	if (ret < 0)
		return ret;

	/* Read the data from the MII data register */
	return readl(priv->ioaddr + mii_data) & MII_DATA_MASK;
	ret = stmmac_mdio_wait(mii_address, MII_ADDR_GBUSY);
	if (ret)
		goto out;

	addr = stmmac_mdio_format_addr(priv, pa, gr) | cmd;

	writel(data, mii_data);
	writel(addr, mii_address);

	ret = stmmac_mdio_wait(mii_address, MII_ADDR_GBUSY);
	if (ret)
		goto out;

	/* Read the data from the MII data register if in read mode */
	ret = read ? readl(mii_data) & MII_DATA_GD_MASK : 0;

out:
	pm_runtime_put(priv->device);

	return ret;
}

static int stmmac_mdio_read(struct stmmac_priv *priv, unsigned int pa,
			    unsigned int gr, u32 cmd, int data)
{
	return stmmac_mdio_access(priv, pa, gr, cmd, data, true);
}

static int stmmac_mdio_write(struct stmmac_priv *priv, unsigned int pa,
			     unsigned int gr, u32 cmd, int data)
{
	return stmmac_mdio_access(priv, pa, gr, cmd, data, false);
}

/**
@@ -263,26 +299,14 @@ static int stmmac_mdio_read(struct stmmac_priv *priv, int data, u32 value)
static int stmmac_mdio_read_c22(struct mii_bus *bus, int phyaddr, int phyreg)
{
	struct stmmac_priv *priv = netdev_priv(bus->priv);
	u32 value = MII_BUSY;
	int data = 0;

	data = pm_runtime_resume_and_get(priv->device);
	if (data < 0)
		return data;

	value |= (phyaddr << priv->hw->mii.addr_shift)
		& priv->hw->mii.addr_mask;
	value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
	value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
		& priv->hw->mii.clk_csr_mask;
	if (priv->plat->has_gmac4)
		value |= MII_GMAC4_READ;
	u32 cmd;

	data = stmmac_mdio_read(priv, data, value);

	pm_runtime_put(priv->device);
	if (priv->plat->has_gmac4)
		cmd = MII_GMAC4_READ;
	else
		cmd = 0;

	return data;
	return stmmac_mdio_read(priv, phyaddr, phyreg, cmd, 0);
}

/**
@@ -300,48 +324,10 @@ static int stmmac_mdio_read_c45(struct mii_bus *bus, int phyaddr, int devad,
				int phyreg)
{
	struct stmmac_priv *priv = netdev_priv(bus->priv);
	u32 value = MII_BUSY;
	int data = 0;

	data = pm_runtime_resume_and_get(priv->device);
	if (data < 0)
		return data;

	value |= (phyaddr << priv->hw->mii.addr_shift)
		& priv->hw->mii.addr_mask;
	value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
		& priv->hw->mii.clk_csr_mask;
	value |= MII_GMAC4_READ;
	value |= MII_GMAC4_C45E;
	value |= (devad << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;

	data |= phyreg << MII_GMAC4_REG_ADDR_SHIFT;

	data = stmmac_mdio_read(priv, data, value);
	int data = phyreg << MII_GMAC4_REG_ADDR_SHIFT;
	u32 cmd = MII_GMAC4_READ | MII_GMAC4_C45E;

	pm_runtime_put(priv->device);

	return data;
}

static int stmmac_mdio_write(struct stmmac_priv *priv, int data, u32 value)
{
	unsigned int mii_address = priv->hw->mii.addr;
	unsigned int mii_data = priv->hw->mii.data;
	u32 v;

	/* Wait until any existing MII operation is complete */
	if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
			       100, 10000))
		return -EBUSY;

	/* Set the MII address register to write */
	writel(data, priv->ioaddr + mii_data);
	writel(value, priv->ioaddr + mii_address);

	/* Wait until any existing MII operation is complete */
	return readl_poll_timeout(priv->ioaddr + mii_address, v,
				  !(v & MII_BUSY), 100, 10000);
	return stmmac_mdio_read(priv, phyaddr, devad, cmd, data);
}

/**
@@ -356,29 +342,14 @@ static int stmmac_mdio_write_c22(struct mii_bus *bus, int phyaddr, int phyreg,
				 u16 phydata)
{
	struct stmmac_priv *priv = netdev_priv(bus->priv);
	int ret, data = phydata;
	u32 value = MII_BUSY;
	u32 cmd;

	ret = pm_runtime_resume_and_get(priv->device);
	if (ret < 0)
		return ret;

	value |= (phyaddr << priv->hw->mii.addr_shift)
		& priv->hw->mii.addr_mask;
	value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;

	value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
		& priv->hw->mii.clk_csr_mask;
	if (priv->plat->has_gmac4)
		value |= MII_GMAC4_WRITE;
		cmd = MII_GMAC4_WRITE;
	else
		value |= MII_WRITE;

	ret = stmmac_mdio_write(priv, data, value);

	pm_runtime_put(priv->device);
		cmd = MII_ADDR_GWRITE;

	return ret;
	return stmmac_mdio_write(priv, phyaddr, phyreg, cmd, phydata);
}

/**
@@ -394,30 +365,12 @@ static int stmmac_mdio_write_c45(struct mii_bus *bus, int phyaddr,
				 int devad, int phyreg, u16 phydata)
{
	struct stmmac_priv *priv = netdev_priv(bus->priv);
	int ret, data = phydata;
	u32 value = MII_BUSY;

	ret = pm_runtime_resume_and_get(priv->device);
	if (ret < 0)
		return ret;

	value |= (phyaddr << priv->hw->mii.addr_shift)
		& priv->hw->mii.addr_mask;

	value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
		& priv->hw->mii.clk_csr_mask;

	value |= MII_GMAC4_WRITE;
	value |= MII_GMAC4_C45E;
	value |= (devad << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
	u32 cmd = MII_GMAC4_WRITE | MII_GMAC4_C45E;
	int data = phydata;

	data |= phyreg << MII_GMAC4_REG_ADDR_SHIFT;

	ret = stmmac_mdio_write(priv, data, value);

	pm_runtime_put(priv->device);

	return ret;
	return stmmac_mdio_write(priv, phyaddr, devad, cmd, data);
}

/**
@@ -520,6 +473,102 @@ void stmmac_pcs_clean(struct net_device *ndev)
	priv->hw->xpcs = NULL;
}

/**
 * stmmac_clk_csr_set - dynamically set the MDC clock
 * @priv: driver private structure
 * Description: this is to dynamically set the MDC clock according to the csr
 * clock input.
 * Return: MII register CR field value
 * Note:
 *	If a specific clk_csr value is passed from the platform
 *	this means that the CSR Clock Range selection cannot be
 *	changed at run-time and it is fixed (as reported in the driver
 *	documentation). Viceversa the driver will try to set the MDC
 *	clock dynamically according to the actual clock input.
 */
static u32 stmmac_clk_csr_set(struct stmmac_priv *priv)
{
	unsigned long clk_rate;
	u32 value = ~0;

	clk_rate = clk_get_rate(priv->plat->stmmac_clk);

	/* Platform provided default clk_csr would be assumed valid
	 * for all other cases except for the below mentioned ones.
	 * For values higher than the IEEE 802.3 specified frequency
	 * we can not estimate the proper divider as it is not known
	 * the frequency of clk_csr_i. So we do not change the default
	 * divider.
	 */
	if (clk_rate < CSR_F_35M)
		value = STMMAC_CSR_20_35M;
	else if (clk_rate < CSR_F_60M)
		value = STMMAC_CSR_35_60M;
	else if (clk_rate < CSR_F_100M)
		value = STMMAC_CSR_60_100M;
	else if (clk_rate < CSR_F_150M)
		value = STMMAC_CSR_100_150M;
	else if (clk_rate < CSR_F_250M)
		value = STMMAC_CSR_150_250M;
	else if (clk_rate <= CSR_F_300M)
		value = STMMAC_CSR_250_300M;
	else if (clk_rate < CSR_F_500M)
		value = STMMAC_CSR_300_500M;
	else if (clk_rate < CSR_F_800M)
		value = STMMAC_CSR_500_800M;

	if (priv->plat->flags & STMMAC_FLAG_HAS_SUN8I) {
		if (clk_rate > 160000000)
			value = 0x03;
		else if (clk_rate > 80000000)
			value = 0x02;
		else if (clk_rate > 40000000)
			value = 0x01;
		else
			value = 0;
	}

	if (priv->plat->has_xgmac) {
		if (clk_rate > 400000000)
			value = 0x5;
		else if (clk_rate > 350000000)
			value = 0x4;
		else if (clk_rate > 300000000)
			value = 0x3;
		else if (clk_rate > 250000000)
			value = 0x2;
		else if (clk_rate > 150000000)
			value = 0x1;
		else
			value = 0x0;
	}

	return value;
}

static void stmmac_mdio_bus_config(struct stmmac_priv *priv)
{
	u32 value;

	/* If a specific clk_csr value is passed from the platform, this means
	 * that the CSR Clock Range value should not be computed from the CSR
	 * clock.
	 */
	if (priv->plat->clk_csr >= 0)
		value = priv->plat->clk_csr;
	else
		value = stmmac_clk_csr_set(priv);

	value <<= priv->hw->mii.clk_csr_shift;

	if (value & ~priv->hw->mii.clk_csr_mask)
		dev_warn(priv->device,
			 "clk_csr value out of range (0x%08x exceeds mask 0x%08x), truncating\n",
			 value, priv->hw->mii.clk_csr_mask);

	priv->gmii_address_bus_config = value & priv->hw->mii.clk_csr_mask;
}

/**
 * stmmac_mdio_register
 * @ndev: net device structure
@@ -540,6 +589,8 @@ int stmmac_mdio_register(struct net_device *ndev)
	if (!mdio_bus_data)
		return 0;

	stmmac_mdio_bus_config(priv);

	new_bus = mdiobus_alloc();
	if (!new_bus)
		return -ENOMEM;
Loading